blob: 04e8401fcbede045c7ba2383c0563829ad495a78 [file] [log] [blame]
Kalle Valo2f01a1f2009-04-29 23:33:31 +03001#include "cmd.h"
2
3#include <linux/module.h>
4#include <linux/crc7.h>
5#include <linux/spi/spi.h>
6
7#include "wl12xx.h"
8#include "wl12xx_80211.h"
9#include "reg.h"
10#include "spi.h"
11#include "ps.h"
Kalle Valoff258392009-06-12 14:14:19 +030012#include "acx.h"
Kalle Valo2f01a1f2009-04-29 23:33:31 +030013
Kalle Valoff258392009-06-12 14:14:19 +030014/**
15 * send command to firmware
16 *
17 * @wl: wl struct
18 * @id: command id
19 * @buf: buffer containing the command, must work with dma
20 * @len: length of the buffer
21 */
22int wl12xx_cmd_send(struct wl12xx *wl, u16 id, void *buf, size_t len)
Kalle Valo2f01a1f2009-04-29 23:33:31 +030023{
Kalle Valoff258392009-06-12 14:14:19 +030024 struct wl12xx_cmd_header *cmd;
Kalle Valo2f01a1f2009-04-29 23:33:31 +030025 unsigned long timeout;
Kalle Valo2f01a1f2009-04-29 23:33:31 +030026 u32 intr;
27 int ret = 0;
28
Kalle Valoff258392009-06-12 14:14:19 +030029 cmd = buf;
30 cmd->id = id;
31 cmd->status = 0;
32
33 WARN_ON(len % 4 != 0);
Kalle Valo2f01a1f2009-04-29 23:33:31 +030034
35 wl12xx_ps_elp_wakeup(wl);
36
Kalle Valoff258392009-06-12 14:14:19 +030037 wl12xx_spi_mem_write(wl, wl->cmd_box_addr, buf, len);
Kalle Valo2f01a1f2009-04-29 23:33:31 +030038
39 wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_CMD);
40
41 timeout = jiffies + msecs_to_jiffies(WL12XX_COMMAND_TIMEOUT);
42
43 intr = wl12xx_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
44 while (!(intr & wl->chip.intr_cmd_complete)) {
45 if (time_after(jiffies, timeout)) {
46 wl12xx_error("command complete timeout");
47 ret = -ETIMEDOUT;
48 goto out;
49 }
50
51 msleep(1);
52
53 intr = wl12xx_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
54 }
55
56 wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_ACK,
57 wl->chip.intr_cmd_complete);
58
59out:
60 wl12xx_ps_elp_sleep(wl);
61
62 return ret;
63}
64
Kalle Valoff258392009-06-12 14:14:19 +030065/**
66 * send test command to firmware
67 *
68 * @wl: wl struct
Ari Kauppi6021b282009-06-12 14:16:13 +030069 * @buf: buffer containing the command, with all headers, must work with dma
Kalle Valoff258392009-06-12 14:14:19 +030070 * @len: length of the buffer
71 * @answer: is answer needed
Kalle Valoff258392009-06-12 14:14:19 +030072 */
Kalle Valo2f01a1f2009-04-29 23:33:31 +030073int wl12xx_cmd_test(struct wl12xx *wl, void *buf, size_t buf_len, u8 answer)
74{
75 int ret;
76
77 wl12xx_debug(DEBUG_CMD, "cmd test");
78
Ari Kauppi6021b282009-06-12 14:16:13 +030079 ret = wl12xx_cmd_send(wl, CMD_TEST, buf, buf_len);
Kalle Valoff258392009-06-12 14:14:19 +030080
Kalle Valo2f01a1f2009-04-29 23:33:31 +030081 if (ret < 0) {
82 wl12xx_warning("TEST command failed");
Ari Kauppi6021b282009-06-12 14:16:13 +030083 return ret;
Kalle Valo2f01a1f2009-04-29 23:33:31 +030084 }
85
86 if (answer) {
Ari Kauppi6021b282009-06-12 14:16:13 +030087 struct wl12xx_command *cmd_answer;
88
Kalle Valo2f01a1f2009-04-29 23:33:31 +030089 /*
90 * The test command got in, we can read the answer.
91 * The answer would be a wl12xx_command, where the
92 * parameter array contains the actual answer.
93 */
94
95 wl12xx_ps_elp_wakeup(wl);
96
Ari Kauppi6021b282009-06-12 14:16:13 +030097 wl12xx_spi_mem_read(wl, wl->cmd_box_addr, buf, buf_len);
Kalle Valo2f01a1f2009-04-29 23:33:31 +030098
99 wl12xx_ps_elp_sleep(wl);
100
Ari Kauppi6021b282009-06-12 14:16:13 +0300101 cmd_answer = buf;
102
103 if (cmd_answer->header.status != CMD_STATUS_SUCCESS)
Kalle Valo2f01a1f2009-04-29 23:33:31 +0300104 wl12xx_error("TEST command answer error: %d",
Ari Kauppi6021b282009-06-12 14:16:13 +0300105 cmd_answer->header.status);
Kalle Valo2f01a1f2009-04-29 23:33:31 +0300106 }
107
Ari Kauppi6021b282009-06-12 14:16:13 +0300108 return 0;
Kalle Valo2f01a1f2009-04-29 23:33:31 +0300109}
110
Kalle Valoff258392009-06-12 14:14:19 +0300111/**
112 * read acx from firmware
113 *
114 * @wl: wl struct
115 * @id: acx id
116 * @buf: buffer for the response, including all headers, must work with dma
117 * @len: lenght of buf
118 */
119int wl12xx_cmd_interrogate(struct wl12xx *wl, u16 id, void *buf, size_t len)
Kalle Valo2f01a1f2009-04-29 23:33:31 +0300120{
Kalle Valoff258392009-06-12 14:14:19 +0300121 struct acx_header *acx = buf;
Kalle Valo2f01a1f2009-04-29 23:33:31 +0300122 int ret;
123
124 wl12xx_debug(DEBUG_CMD, "cmd interrogate");
125
Kalle Valoff258392009-06-12 14:14:19 +0300126 acx->id = id;
Kalle Valo2f01a1f2009-04-29 23:33:31 +0300127
Kalle Valoff258392009-06-12 14:14:19 +0300128 /* payload length, does not include any headers */
129 acx->len = len - sizeof(*acx);
130
131 ret = wl12xx_cmd_send(wl, CMD_INTERROGATE, acx, sizeof(*acx));
Kalle Valo2f01a1f2009-04-29 23:33:31 +0300132 if (ret < 0) {
133 wl12xx_error("INTERROGATE command failed");
Kalle Valoff258392009-06-12 14:14:19 +0300134 goto out;
Kalle Valo2f01a1f2009-04-29 23:33:31 +0300135 }
136
137 wl12xx_ps_elp_wakeup(wl);
138
139 /* the interrogate command got in, we can read the answer */
Kalle Valoff258392009-06-12 14:14:19 +0300140 wl12xx_spi_mem_read(wl, wl->cmd_box_addr, buf, len);
Kalle Valo2f01a1f2009-04-29 23:33:31 +0300141
142 wl12xx_ps_elp_sleep(wl);
143
Kalle Valoff258392009-06-12 14:14:19 +0300144 acx = buf;
145 if (acx->cmd.status != CMD_STATUS_SUCCESS)
Kalle Valo2f01a1f2009-04-29 23:33:31 +0300146 wl12xx_error("INTERROGATE command error: %d",
Kalle Valoff258392009-06-12 14:14:19 +0300147 acx->cmd.status);
Kalle Valo2f01a1f2009-04-29 23:33:31 +0300148
Kalle Valoff258392009-06-12 14:14:19 +0300149out:
150 return ret;
Kalle Valo2f01a1f2009-04-29 23:33:31 +0300151}
152
Kalle Valoff258392009-06-12 14:14:19 +0300153/**
154 * write acx value to firmware
155 *
156 * @wl: wl struct
157 * @id: acx id
158 * @buf: buffer containing acx, including all headers, must work with dma
159 * @len: length of buf
160 */
161int wl12xx_cmd_configure(struct wl12xx *wl, u16 id, void *buf, size_t len)
Kalle Valo2f01a1f2009-04-29 23:33:31 +0300162{
Kalle Valoff258392009-06-12 14:14:19 +0300163 struct acx_header *acx = buf;
Kalle Valo2f01a1f2009-04-29 23:33:31 +0300164 int ret;
165
166 wl12xx_debug(DEBUG_CMD, "cmd configure");
167
Kalle Valoff258392009-06-12 14:14:19 +0300168 acx->id = id;
169
170 /* payload length, does not include any headers */
171 acx->len = len - sizeof(*acx);
172
173 ret = wl12xx_cmd_send(wl, CMD_CONFIGURE, acx, len);
Kalle Valo2f01a1f2009-04-29 23:33:31 +0300174 if (ret < 0) {
175 wl12xx_warning("CONFIGURE command NOK");
176 return ret;
177 }
178
179 return 0;
Kalle Valo2f01a1f2009-04-29 23:33:31 +0300180}
181
182int wl12xx_cmd_vbm(struct wl12xx *wl, u8 identity,
183 void *bitmap, u16 bitmap_len, u8 bitmap_control)
184{
Kalle Valoff258392009-06-12 14:14:19 +0300185 struct wl12xx_cmd_vbm_update *vbm;
Kalle Valo2f01a1f2009-04-29 23:33:31 +0300186 int ret;
187
188 wl12xx_debug(DEBUG_CMD, "cmd vbm");
189
Kalle Valoff258392009-06-12 14:14:19 +0300190 vbm = kzalloc(sizeof(*vbm), GFP_KERNEL);
191 if (!vbm) {
192 ret = -ENOMEM;
193 goto out;
194 }
195
Kalle Valo2f01a1f2009-04-29 23:33:31 +0300196 /* Count and period will be filled by the target */
Kalle Valoff258392009-06-12 14:14:19 +0300197 vbm->tim.bitmap_ctrl = bitmap_control;
Kalle Valo2f01a1f2009-04-29 23:33:31 +0300198 if (bitmap_len > PARTIAL_VBM_MAX) {
199 wl12xx_warning("cmd vbm len is %d B, truncating to %d",
200 bitmap_len, PARTIAL_VBM_MAX);
201 bitmap_len = PARTIAL_VBM_MAX;
202 }
Kalle Valoff258392009-06-12 14:14:19 +0300203 memcpy(vbm->tim.pvb_field, bitmap, bitmap_len);
204 vbm->tim.identity = identity;
205 vbm->tim.length = bitmap_len + 3;
Kalle Valo2f01a1f2009-04-29 23:33:31 +0300206
Kalle Valoff258392009-06-12 14:14:19 +0300207 vbm->len = cpu_to_le16(bitmap_len + 5);
Kalle Valo2f01a1f2009-04-29 23:33:31 +0300208
Kalle Valoff258392009-06-12 14:14:19 +0300209 ret = wl12xx_cmd_send(wl, CMD_VBM, vbm, sizeof(*vbm));
Kalle Valo2f01a1f2009-04-29 23:33:31 +0300210 if (ret < 0) {
211 wl12xx_error("VBM command failed");
Kalle Valoff258392009-06-12 14:14:19 +0300212 goto out;
Kalle Valo2f01a1f2009-04-29 23:33:31 +0300213 }
214
Kalle Valoff258392009-06-12 14:14:19 +0300215out:
216 kfree(vbm);
Kalle Valo2f01a1f2009-04-29 23:33:31 +0300217 return 0;
218}
219
Kalle Valoff258392009-06-12 14:14:19 +0300220int wl12xx_cmd_data_path(struct wl12xx *wl, u8 channel, bool enable)
Kalle Valo2f01a1f2009-04-29 23:33:31 +0300221{
Kalle Valoff258392009-06-12 14:14:19 +0300222 struct cmd_enabledisable_path *cmd;
Kalle Valo2f01a1f2009-04-29 23:33:31 +0300223 int ret;
224 u16 cmd_rx, cmd_tx;
225
226 wl12xx_debug(DEBUG_CMD, "cmd data path");
227
Kalle Valoff258392009-06-12 14:14:19 +0300228 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
229 if (!cmd) {
230 ret = -ENOMEM;
231 goto out;
232 }
233
234 cmd->channel = channel;
235
Kalle Valo2f01a1f2009-04-29 23:33:31 +0300236 if (enable) {
237 cmd_rx = CMD_ENABLE_RX;
238 cmd_tx = CMD_ENABLE_TX;
239 } else {
240 cmd_rx = CMD_DISABLE_RX;
241 cmd_tx = CMD_DISABLE_TX;
242 }
243
Kalle Valoff258392009-06-12 14:14:19 +0300244 ret = wl12xx_cmd_send(wl, cmd_rx, cmd, sizeof(*cmd));
Kalle Valo2f01a1f2009-04-29 23:33:31 +0300245 if (ret < 0) {
246 wl12xx_error("rx %s cmd for channel %d failed",
247 enable ? "start" : "stop", channel);
Kalle Valoff258392009-06-12 14:14:19 +0300248 goto out;
Kalle Valo2f01a1f2009-04-29 23:33:31 +0300249 }
250
251 wl12xx_debug(DEBUG_BOOT, "rx %s cmd channel %d",
252 enable ? "start" : "stop", channel);
253
Kalle Valoff258392009-06-12 14:14:19 +0300254 ret = wl12xx_cmd_send(wl, cmd_tx, cmd, sizeof(*cmd));
Kalle Valo2f01a1f2009-04-29 23:33:31 +0300255 if (ret < 0) {
256 wl12xx_error("tx %s cmd for channel %d failed",
257 enable ? "start" : "stop", channel);
258 return ret;
259 }
260
261 wl12xx_debug(DEBUG_BOOT, "tx %s cmd channel %d",
262 enable ? "start" : "stop", channel);
263
Kalle Valoff258392009-06-12 14:14:19 +0300264out:
265 kfree(cmd);
266 return ret;
Kalle Valo2f01a1f2009-04-29 23:33:31 +0300267}
268
269int wl12xx_cmd_join(struct wl12xx *wl, u8 bss_type, u8 dtim_interval,
270 u16 beacon_interval, u8 wait)
271{
272 unsigned long timeout;
Kalle Valoff258392009-06-12 14:14:19 +0300273 struct cmd_join *join;
Kalle Valo2f01a1f2009-04-29 23:33:31 +0300274 int ret, i;
275 u8 *bssid;
276
Kalle Valoff258392009-06-12 14:14:19 +0300277 join = kzalloc(sizeof(*join), GFP_KERNEL);
278 if (!join) {
279 ret = -ENOMEM;
280 goto out;
281 }
282
Kalle Valo2f01a1f2009-04-29 23:33:31 +0300283 /* FIXME: this should be in main.c */
284 ret = wl12xx_acx_frame_rates(wl, DEFAULT_HW_GEN_TX_RATE,
285 DEFAULT_HW_GEN_MODULATION_TYPE,
286 wl->tx_mgmt_frm_rate,
287 wl->tx_mgmt_frm_mod);
288 if (ret < 0)
Kalle Valoff258392009-06-12 14:14:19 +0300289 goto out;
Kalle Valo2f01a1f2009-04-29 23:33:31 +0300290
291 wl12xx_debug(DEBUG_CMD, "cmd join");
292
293 /* Reverse order BSSID */
Kalle Valoff258392009-06-12 14:14:19 +0300294 bssid = (u8 *) &join->bssid_lsb;
Kalle Valo2f01a1f2009-04-29 23:33:31 +0300295 for (i = 0; i < ETH_ALEN; i++)
296 bssid[i] = wl->bssid[ETH_ALEN - i - 1];
297
Kalle Valoff258392009-06-12 14:14:19 +0300298 join->rx_config_options = wl->rx_config;
299 join->rx_filter_options = wl->rx_filter;
Kalle Valo2f01a1f2009-04-29 23:33:31 +0300300
Kalle Valoff258392009-06-12 14:14:19 +0300301 join->basic_rate_set = RATE_MASK_1MBPS | RATE_MASK_2MBPS |
Kalle Valo2f01a1f2009-04-29 23:33:31 +0300302 RATE_MASK_5_5MBPS | RATE_MASK_11MBPS;
303
Kalle Valoff258392009-06-12 14:14:19 +0300304 join->beacon_interval = beacon_interval;
305 join->dtim_interval = dtim_interval;
306 join->bss_type = bss_type;
307 join->channel = wl->channel;
308 join->ctrl = JOIN_CMD_CTRL_TX_FLUSH;
Kalle Valo2f01a1f2009-04-29 23:33:31 +0300309
Kalle Valoff258392009-06-12 14:14:19 +0300310 ret = wl12xx_cmd_send(wl, CMD_START_JOIN, join, sizeof(*join));
Kalle Valo2f01a1f2009-04-29 23:33:31 +0300311 if (ret < 0) {
312 wl12xx_error("failed to initiate cmd join");
Kalle Valoff258392009-06-12 14:14:19 +0300313 goto out;
Kalle Valo2f01a1f2009-04-29 23:33:31 +0300314 }
315
316 timeout = msecs_to_jiffies(JOIN_TIMEOUT);
317
318 /*
319 * ugly hack: we should wait for JOIN_EVENT_COMPLETE_ID but to
320 * simplify locking we just sleep instead, for now
321 */
322 if (wait)
323 msleep(10);
324
Kalle Valoff258392009-06-12 14:14:19 +0300325out:
326 kfree(join);
327 return ret;
Kalle Valo2f01a1f2009-04-29 23:33:31 +0300328}
329
330int wl12xx_cmd_ps_mode(struct wl12xx *wl, u8 ps_mode)
331{
Kalle Valoff258392009-06-12 14:14:19 +0300332 struct wl12xx_cmd_ps_params *ps_params = NULL;
333 int ret = 0;
Kalle Valo2f01a1f2009-04-29 23:33:31 +0300334
335 /* FIXME: this should be in ps.c */
Luciano Coelho9f483dc2009-06-12 14:15:46 +0300336 ret = wl12xx_acx_wake_up_conditions(wl, WAKE_UP_EVENT_DTIM_BITMAP,
337 wl->listen_int);
Kalle Valo2f01a1f2009-04-29 23:33:31 +0300338 if (ret < 0) {
Kalle Valoff258392009-06-12 14:14:19 +0300339 wl12xx_error("couldn't set wake up conditions");
340 goto out;
Kalle Valo2f01a1f2009-04-29 23:33:31 +0300341 }
342
343 wl12xx_debug(DEBUG_CMD, "cmd set ps mode");
344
Kalle Valoff258392009-06-12 14:14:19 +0300345 ps_params = kzalloc(sizeof(*ps_params), GFP_KERNEL);
346 if (!ps_params) {
347 ret = -ENOMEM;
348 goto out;
Kalle Valo2f01a1f2009-04-29 23:33:31 +0300349 }
350
Kalle Valoff258392009-06-12 14:14:19 +0300351 ps_params->ps_mode = ps_mode;
352 ps_params->send_null_data = 1;
353 ps_params->retries = 5;
354 ps_params->hang_over_period = 128;
355 ps_params->null_data_rate = 1; /* 1 Mbps */
356
357 ret = wl12xx_cmd_send(wl, CMD_SET_PS_MODE, ps_params,
358 sizeof(*ps_params));
359 if (ret < 0) {
360 wl12xx_error("cmd set_ps_mode failed");
361 goto out;
362 }
363
364out:
365 kfree(ps_params);
366 return ret;
Kalle Valo2f01a1f2009-04-29 23:33:31 +0300367}
368
Kalle Valoff258392009-06-12 14:14:19 +0300369int wl12xx_cmd_read_memory(struct wl12xx *wl, u32 addr, void *answer,
370 size_t len)
Kalle Valo2f01a1f2009-04-29 23:33:31 +0300371{
Kalle Valoff258392009-06-12 14:14:19 +0300372 struct cmd_read_write_memory *cmd;
373 int ret = 0;
Kalle Valo2f01a1f2009-04-29 23:33:31 +0300374
375 wl12xx_debug(DEBUG_CMD, "cmd read memory");
376
Kalle Valoff258392009-06-12 14:14:19 +0300377 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
378 if (!cmd) {
379 ret = -ENOMEM;
380 goto out;
381 }
Kalle Valo2f01a1f2009-04-29 23:33:31 +0300382
Kalle Valoff258392009-06-12 14:14:19 +0300383 WARN_ON(len > MAX_READ_SIZE);
384 len = min_t(size_t, len, MAX_READ_SIZE);
385
386 cmd->addr = addr;
387 cmd->size = len;
388
389 ret = wl12xx_cmd_send(wl, CMD_READ_MEMORY, cmd, sizeof(*cmd));
Kalle Valo2f01a1f2009-04-29 23:33:31 +0300390 if (ret < 0) {
391 wl12xx_error("read memory command failed: %d", ret);
Kalle Valoff258392009-06-12 14:14:19 +0300392 goto out;
Kalle Valo2f01a1f2009-04-29 23:33:31 +0300393 }
394
395 /* the read command got in, we can now read the answer */
Kalle Valoff258392009-06-12 14:14:19 +0300396 wl12xx_spi_mem_read(wl, wl->cmd_box_addr, cmd, sizeof(*cmd));
Kalle Valo2f01a1f2009-04-29 23:33:31 +0300397
Kalle Valoff258392009-06-12 14:14:19 +0300398 if (cmd->header.status != CMD_STATUS_SUCCESS)
399 wl12xx_error("error in read command result: %d",
400 cmd->header.status);
Kalle Valo2f01a1f2009-04-29 23:33:31 +0300401
Kalle Valoff258392009-06-12 14:14:19 +0300402 memcpy(answer, cmd->value, len);
Kalle Valo2f01a1f2009-04-29 23:33:31 +0300403
Kalle Valoff258392009-06-12 14:14:19 +0300404out:
405 kfree(cmd);
406 return ret;
Kalle Valo2f01a1f2009-04-29 23:33:31 +0300407}
408
409int wl12xx_cmd_template_set(struct wl12xx *wl, u16 cmd_id,
410 void *buf, size_t buf_len)
411{
Kalle Valoff258392009-06-12 14:14:19 +0300412 struct wl12xx_cmd_packet_template *cmd;
413 size_t cmd_len;
414 int ret = 0;
Kalle Valo2f01a1f2009-04-29 23:33:31 +0300415
416 wl12xx_debug(DEBUG_CMD, "cmd template %d", cmd_id);
417
Kalle Valo2f01a1f2009-04-29 23:33:31 +0300418 WARN_ON(buf_len > WL12XX_MAX_TEMPLATE_SIZE);
419 buf_len = min_t(size_t, buf_len, WL12XX_MAX_TEMPLATE_SIZE);
Kalle Valoff258392009-06-12 14:14:19 +0300420 cmd_len = ALIGN(sizeof(*cmd) + buf_len, 4);
Kalle Valo2f01a1f2009-04-29 23:33:31 +0300421
Kalle Valoff258392009-06-12 14:14:19 +0300422 cmd = kzalloc(cmd_len, GFP_KERNEL);
423 if (!cmd) {
424 ret = -ENOMEM;
425 goto out;
Kalle Valo2f01a1f2009-04-29 23:33:31 +0300426 }
427
Kalle Valoff258392009-06-12 14:14:19 +0300428 cmd->size = cpu_to_le16(buf_len);
429
430 if (buf)
431 memcpy(cmd->data, buf, buf_len);
432
433 ret = wl12xx_cmd_send(wl, cmd_id, cmd, cmd_len);
434 if (ret < 0) {
435 wl12xx_warning("cmd set_template failed: %d", ret);
436 goto out;
437 }
438
439out:
440 kfree(cmd);
441 return ret;
Kalle Valo2f01a1f2009-04-29 23:33:31 +0300442}