diff options
author | Kalle Valo <kalle.valo@nokia.com> | 2009-08-12 07:42:51 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-08-14 09:14:05 -0400 |
commit | 11aa6e2398f54712b1e1bdeb9d8bf3b452c5a5d5 (patch) | |
tree | 48b0d733572cb54f0a9ddd76ea5df35ebdfeffa5 /drivers | |
parent | aae79e648d93bc9d6b3581ab4eb88e2ac44f5c46 (diff) |
wl1251: remove wl1251_ops.c
Commit "wl1251: remove wl1251_ops" originally removed file wl1251_ops.c,
but while I rebased the patch the removal got lost. Now remote the file
for real.
Signed-off-by: Kalle Valo <kalle.valo@nokia.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1251_ops.c | 729 |
1 files changed, 0 insertions, 729 deletions
diff --git a/drivers/net/wireless/wl12xx/wl1251_ops.c b/drivers/net/wireless/wl12xx/wl1251_ops.c deleted file mode 100644 index 758280af10d4..000000000000 --- a/drivers/net/wireless/wl12xx/wl1251_ops.c +++ /dev/null | |||
@@ -1,729 +0,0 @@ | |||
1 | /* | ||
2 | * This file is part of wl1251 | ||
3 | * | ||
4 | * Copyright (C) 2008-2009 Nokia Corporation | ||
5 | * | ||
6 | * Contact: Kalle Valo <kalle.valo@nokia.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * version 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
20 | * 02110-1301 USA | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #include <linux/kernel.h> | ||
25 | #include <linux/module.h> | ||
26 | |||
27 | #include "wl1251_ops.h" | ||
28 | #include "reg.h" | ||
29 | #include "wl1251_io.h" | ||
30 | #include "wl1251_spi.h" | ||
31 | #include "wl1251_boot.h" | ||
32 | #include "wl1251_event.h" | ||
33 | #include "wl1251_acx.h" | ||
34 | #include "wl1251_tx.h" | ||
35 | #include "wl1251_rx.h" | ||
36 | #include "wl1251_ps.h" | ||
37 | #include "wl1251_init.h" | ||
38 | |||
39 | static struct wl1251_partition_set wl1251_part_table[PART_TABLE_LEN] = { | ||
40 | [PART_DOWN] = { | ||
41 | .mem = { | ||
42 | .start = 0x00000000, | ||
43 | .size = 0x00016800 | ||
44 | }, | ||
45 | .reg = { | ||
46 | .start = REGISTERS_BASE, | ||
47 | .size = REGISTERS_DOWN_SIZE | ||
48 | }, | ||
49 | }, | ||
50 | |||
51 | [PART_WORK] = { | ||
52 | .mem = { | ||
53 | .start = 0x00028000, | ||
54 | .size = 0x00014000 | ||
55 | }, | ||
56 | .reg = { | ||
57 | .start = REGISTERS_BASE, | ||
58 | .size = REGISTERS_WORK_SIZE | ||
59 | }, | ||
60 | }, | ||
61 | |||
62 | /* WL1251 doesn't use the DRPW partition, so we don't set it here */ | ||
63 | }; | ||
64 | |||
65 | static enum wl12xx_acx_int_reg wl1251_acx_reg_table[ACX_REG_TABLE_LEN] = { | ||
66 | [ACX_REG_INTERRUPT_TRIG] = (REGISTERS_BASE + 0x0474), | ||
67 | [ACX_REG_INTERRUPT_TRIG_H] = (REGISTERS_BASE + 0x0478), | ||
68 | [ACX_REG_INTERRUPT_MASK] = (REGISTERS_BASE + 0x0494), | ||
69 | [ACX_REG_HINT_MASK_SET] = (REGISTERS_BASE + 0x0498), | ||
70 | [ACX_REG_HINT_MASK_CLR] = (REGISTERS_BASE + 0x049C), | ||
71 | [ACX_REG_INTERRUPT_NO_CLEAR] = (REGISTERS_BASE + 0x04B0), | ||
72 | [ACX_REG_INTERRUPT_CLEAR] = (REGISTERS_BASE + 0x04A4), | ||
73 | [ACX_REG_INTERRUPT_ACK] = (REGISTERS_BASE + 0x04A8), | ||
74 | [ACX_REG_SLV_SOFT_RESET] = (REGISTERS_BASE + 0x0000), | ||
75 | [ACX_REG_EE_START] = (REGISTERS_BASE + 0x080C), | ||
76 | [ACX_REG_ECPU_CONTROL] = (REGISTERS_BASE + 0x0804) | ||
77 | }; | ||
78 | |||
79 | static int wl1251_upload_firmware(struct wl1251 *wl) | ||
80 | { | ||
81 | struct wl1251_partition_set *p_table = wl->chip.p_table; | ||
82 | int addr, chunk_num, partition_limit; | ||
83 | size_t fw_data_len; | ||
84 | u8 *p; | ||
85 | |||
86 | /* whal_FwCtrl_LoadFwImageSm() */ | ||
87 | |||
88 | wl1251_debug(DEBUG_BOOT, "chip id before fw upload: 0x%x", | ||
89 | wl1251_reg_read32(wl, CHIP_ID_B)); | ||
90 | |||
91 | /* 10.0 check firmware length and set partition */ | ||
92 | fw_data_len = (wl->fw[4] << 24) | (wl->fw[5] << 16) | | ||
93 | (wl->fw[6] << 8) | (wl->fw[7]); | ||
94 | |||
95 | wl1251_debug(DEBUG_BOOT, "fw_data_len %zu chunk_size %d", fw_data_len, | ||
96 | CHUNK_SIZE); | ||
97 | |||
98 | if ((fw_data_len % 4) != 0) { | ||
99 | wl1251_error("firmware length not multiple of four"); | ||
100 | return -EIO; | ||
101 | } | ||
102 | |||
103 | wl1251_set_partition(wl, | ||
104 | p_table[PART_DOWN].mem.start, | ||
105 | p_table[PART_DOWN].mem.size, | ||
106 | p_table[PART_DOWN].reg.start, | ||
107 | p_table[PART_DOWN].reg.size); | ||
108 | |||
109 | /* 10.1 set partition limit and chunk num */ | ||
110 | chunk_num = 0; | ||
111 | partition_limit = p_table[PART_DOWN].mem.size; | ||
112 | |||
113 | while (chunk_num < fw_data_len / CHUNK_SIZE) { | ||
114 | /* 10.2 update partition, if needed */ | ||
115 | addr = p_table[PART_DOWN].mem.start + | ||
116 | (chunk_num + 2) * CHUNK_SIZE; | ||
117 | if (addr > partition_limit) { | ||
118 | addr = p_table[PART_DOWN].mem.start + | ||
119 | chunk_num * CHUNK_SIZE; | ||
120 | partition_limit = chunk_num * CHUNK_SIZE + | ||
121 | p_table[PART_DOWN].mem.size; | ||
122 | wl1251_set_partition(wl, | ||
123 | addr, | ||
124 | p_table[PART_DOWN].mem.size, | ||
125 | p_table[PART_DOWN].reg.start, | ||
126 | p_table[PART_DOWN].reg.size); | ||
127 | } | ||
128 | |||
129 | /* 10.3 upload the chunk */ | ||
130 | addr = p_table[PART_DOWN].mem.start + chunk_num * CHUNK_SIZE; | ||
131 | p = wl->fw + FW_HDR_SIZE + chunk_num * CHUNK_SIZE; | ||
132 | wl1251_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x", | ||
133 | p, addr); | ||
134 | wl1251_mem_write(wl, addr, p, CHUNK_SIZE); | ||
135 | |||
136 | chunk_num++; | ||
137 | } | ||
138 | |||
139 | /* 10.4 upload the last chunk */ | ||
140 | addr = p_table[PART_DOWN].mem.start + chunk_num * CHUNK_SIZE; | ||
141 | p = wl->fw + FW_HDR_SIZE + chunk_num * CHUNK_SIZE; | ||
142 | wl1251_debug(DEBUG_BOOT, "uploading fw last chunk (%zu B) 0x%p to 0x%x", | ||
143 | fw_data_len % CHUNK_SIZE, p, addr); | ||
144 | wl1251_mem_write(wl, addr, p, fw_data_len % CHUNK_SIZE); | ||
145 | |||
146 | return 0; | ||
147 | } | ||
148 | |||
149 | static int wl1251_upload_nvs(struct wl1251 *wl) | ||
150 | { | ||
151 | size_t nvs_len, nvs_bytes_written, burst_len; | ||
152 | int nvs_start, i; | ||
153 | u32 dest_addr, val; | ||
154 | u8 *nvs_ptr, *nvs; | ||
155 | |||
156 | nvs = wl->nvs; | ||
157 | if (nvs == NULL) | ||
158 | return -ENODEV; | ||
159 | |||
160 | nvs_ptr = nvs; | ||
161 | |||
162 | nvs_len = wl->nvs_len; | ||
163 | nvs_start = wl->fw_len; | ||
164 | |||
165 | /* | ||
166 | * Layout before the actual NVS tables: | ||
167 | * 1 byte : burst length. | ||
168 | * 2 bytes: destination address. | ||
169 | * n bytes: data to burst copy. | ||
170 | * | ||
171 | * This is ended by a 0 length, then the NVS tables. | ||
172 | */ | ||
173 | |||
174 | while (nvs_ptr[0]) { | ||
175 | burst_len = nvs_ptr[0]; | ||
176 | dest_addr = (nvs_ptr[1] & 0xfe) | ((u32)(nvs_ptr[2] << 8)); | ||
177 | |||
178 | /* We move our pointer to the data */ | ||
179 | nvs_ptr += 3; | ||
180 | |||
181 | for (i = 0; i < burst_len; i++) { | ||
182 | val = (nvs_ptr[0] | (nvs_ptr[1] << 8) | ||
183 | | (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24)); | ||
184 | |||
185 | wl1251_debug(DEBUG_BOOT, | ||
186 | "nvs burst write 0x%x: 0x%x", | ||
187 | dest_addr, val); | ||
188 | wl1251_mem_write32(wl, dest_addr, val); | ||
189 | |||
190 | nvs_ptr += 4; | ||
191 | dest_addr += 4; | ||
192 | } | ||
193 | } | ||
194 | |||
195 | /* | ||
196 | * We've reached the first zero length, the first NVS table | ||
197 | * is 7 bytes further. | ||
198 | */ | ||
199 | nvs_ptr += 7; | ||
200 | nvs_len -= nvs_ptr - nvs; | ||
201 | nvs_len = ALIGN(nvs_len, 4); | ||
202 | |||
203 | /* Now we must set the partition correctly */ | ||
204 | wl1251_set_partition(wl, nvs_start, | ||
205 | wl->chip.p_table[PART_DOWN].mem.size, | ||
206 | wl->chip.p_table[PART_DOWN].reg.start, | ||
207 | wl->chip.p_table[PART_DOWN].reg.size); | ||
208 | |||
209 | /* And finally we upload the NVS tables */ | ||
210 | nvs_bytes_written = 0; | ||
211 | while (nvs_bytes_written < nvs_len) { | ||
212 | val = (nvs_ptr[0] | (nvs_ptr[1] << 8) | ||
213 | | (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24)); | ||
214 | |||
215 | val = cpu_to_le32(val); | ||
216 | |||
217 | wl1251_debug(DEBUG_BOOT, | ||
218 | "nvs write table 0x%x: 0x%x", | ||
219 | nvs_start, val); | ||
220 | wl1251_mem_write32(wl, nvs_start, val); | ||
221 | |||
222 | nvs_ptr += 4; | ||
223 | nvs_bytes_written += 4; | ||
224 | nvs_start += 4; | ||
225 | } | ||
226 | |||
227 | return 0; | ||
228 | } | ||
229 | |||
230 | static int wl1251_boot(struct wl1251 *wl) | ||
231 | { | ||
232 | int ret = 0, minor_minor_e2_ver; | ||
233 | u32 tmp, boot_data; | ||
234 | |||
235 | ret = wl1251_boot_soft_reset(wl); | ||
236 | if (ret < 0) | ||
237 | goto out; | ||
238 | |||
239 | /* 2. start processing NVS file */ | ||
240 | ret = wl->chip.op_upload_nvs(wl); | ||
241 | if (ret < 0) | ||
242 | goto out; | ||
243 | |||
244 | /* write firmware's last address (ie. it's length) to | ||
245 | * ACX_EEPROMLESS_IND_REG */ | ||
246 | wl1251_reg_write32(wl, ACX_EEPROMLESS_IND_REG, wl->fw_len); | ||
247 | |||
248 | /* 6. read the EEPROM parameters */ | ||
249 | tmp = wl1251_reg_read32(wl, SCR_PAD2); | ||
250 | |||
251 | /* 7. read bootdata */ | ||
252 | wl->boot_attr.radio_type = (tmp & 0x0000FF00) >> 8; | ||
253 | wl->boot_attr.major = (tmp & 0x00FF0000) >> 16; | ||
254 | tmp = wl1251_reg_read32(wl, SCR_PAD3); | ||
255 | |||
256 | /* 8. check bootdata and call restart sequence */ | ||
257 | wl->boot_attr.minor = (tmp & 0x00FF0000) >> 16; | ||
258 | minor_minor_e2_ver = (tmp & 0xFF000000) >> 24; | ||
259 | |||
260 | wl1251_debug(DEBUG_BOOT, "radioType 0x%x majorE2Ver 0x%x " | ||
261 | "minorE2Ver 0x%x minor_minor_e2_ver 0x%x", | ||
262 | wl->boot_attr.radio_type, wl->boot_attr.major, | ||
263 | wl->boot_attr.minor, minor_minor_e2_ver); | ||
264 | |||
265 | ret = wl1251_boot_init_seq(wl); | ||
266 | if (ret < 0) | ||
267 | goto out; | ||
268 | |||
269 | /* 9. NVS processing done */ | ||
270 | boot_data = wl1251_reg_read32(wl, ACX_REG_ECPU_CONTROL); | ||
271 | |||
272 | wl1251_debug(DEBUG_BOOT, "halt boot_data 0x%x", boot_data); | ||
273 | |||
274 | /* 10. check that ECPU_CONTROL_HALT bits are set in | ||
275 | * pWhalBus->uBootData and start uploading firmware | ||
276 | */ | ||
277 | if ((boot_data & ECPU_CONTROL_HALT) == 0) { | ||
278 | wl1251_error("boot failed, ECPU_CONTROL_HALT not set"); | ||
279 | ret = -EIO; | ||
280 | goto out; | ||
281 | } | ||
282 | |||
283 | ret = wl->chip.op_upload_fw(wl); | ||
284 | if (ret < 0) | ||
285 | goto out; | ||
286 | |||
287 | /* 10.5 start firmware */ | ||
288 | ret = wl1251_boot_run_firmware(wl); | ||
289 | if (ret < 0) | ||
290 | goto out; | ||
291 | |||
292 | out: | ||
293 | return ret; | ||
294 | } | ||
295 | |||
296 | static int wl1251_mem_cfg(struct wl1251 *wl) | ||
297 | { | ||
298 | struct wl1251_acx_config_memory *mem_conf; | ||
299 | int ret, i; | ||
300 | |||
301 | wl1251_debug(DEBUG_ACX, "wl1251 mem cfg"); | ||
302 | |||
303 | mem_conf = kzalloc(sizeof(*mem_conf), GFP_KERNEL); | ||
304 | if (!mem_conf) { | ||
305 | ret = -ENOMEM; | ||
306 | goto out; | ||
307 | } | ||
308 | |||
309 | /* memory config */ | ||
310 | mem_conf->mem_config.num_stations = cpu_to_le16(DEFAULT_NUM_STATIONS); | ||
311 | mem_conf->mem_config.rx_mem_block_num = 35; | ||
312 | mem_conf->mem_config.tx_min_mem_block_num = 64; | ||
313 | mem_conf->mem_config.num_tx_queues = MAX_TX_QUEUES; | ||
314 | mem_conf->mem_config.host_if_options = HOSTIF_PKT_RING; | ||
315 | mem_conf->mem_config.num_ssid_profiles = 1; | ||
316 | mem_conf->mem_config.debug_buffer_size = | ||
317 | cpu_to_le16(TRACE_BUFFER_MAX_SIZE); | ||
318 | |||
319 | /* RX queue config */ | ||
320 | mem_conf->rx_queue_config.dma_address = 0; | ||
321 | mem_conf->rx_queue_config.num_descs = ACX_RX_DESC_DEF; | ||
322 | mem_conf->rx_queue_config.priority = DEFAULT_RXQ_PRIORITY; | ||
323 | mem_conf->rx_queue_config.type = DEFAULT_RXQ_TYPE; | ||
324 | |||
325 | /* TX queue config */ | ||
326 | for (i = 0; i < MAX_TX_QUEUES; i++) { | ||
327 | mem_conf->tx_queue_config[i].num_descs = ACX_TX_DESC_DEF; | ||
328 | mem_conf->tx_queue_config[i].attributes = i; | ||
329 | } | ||
330 | |||
331 | ret = wl1251_cmd_configure(wl, ACX_MEM_CFG, mem_conf, | ||
332 | sizeof(*mem_conf)); | ||
333 | if (ret < 0) { | ||
334 | wl1251_warning("wl1251 mem config failed: %d", ret); | ||
335 | goto out; | ||
336 | } | ||
337 | |||
338 | out: | ||
339 | kfree(mem_conf); | ||
340 | return ret; | ||
341 | } | ||
342 | |||
343 | static int wl1251_hw_init_mem_config(struct wl1251 *wl) | ||
344 | { | ||
345 | int ret; | ||
346 | |||
347 | ret = wl1251_mem_cfg(wl); | ||
348 | if (ret < 0) | ||
349 | return ret; | ||
350 | |||
351 | wl->target_mem_map = kzalloc(sizeof(struct wl1251_acx_mem_map), | ||
352 | GFP_KERNEL); | ||
353 | if (!wl->target_mem_map) { | ||
354 | wl1251_error("couldn't allocate target memory map"); | ||
355 | return -ENOMEM; | ||
356 | } | ||
357 | |||
358 | /* we now ask for the firmware built memory map */ | ||
359 | ret = wl1251_acx_mem_map(wl, wl->target_mem_map, | ||
360 | sizeof(struct wl1251_acx_mem_map)); | ||
361 | if (ret < 0) { | ||
362 | wl1251_error("couldn't retrieve firmware memory map"); | ||
363 | kfree(wl->target_mem_map); | ||
364 | wl->target_mem_map = NULL; | ||
365 | return ret; | ||
366 | } | ||
367 | |||
368 | return 0; | ||
369 | } | ||
370 | |||
371 | static void wl1251_set_ecpu_ctrl(struct wl1251 *wl, u32 flag) | ||
372 | { | ||
373 | u32 cpu_ctrl; | ||
374 | |||
375 | /* 10.5.0 run the firmware (I) */ | ||
376 | cpu_ctrl = wl1251_reg_read32(wl, ACX_REG_ECPU_CONTROL); | ||
377 | |||
378 | /* 10.5.1 run the firmware (II) */ | ||
379 | cpu_ctrl &= ~flag; | ||
380 | wl1251_reg_write32(wl, ACX_REG_ECPU_CONTROL, cpu_ctrl); | ||
381 | } | ||
382 | |||
383 | static void wl1251_target_enable_interrupts(struct wl1251 *wl) | ||
384 | { | ||
385 | /* Enable target's interrupts */ | ||
386 | wl->intr_mask = WL1251_ACX_INTR_RX0_DATA | | ||
387 | WL1251_ACX_INTR_RX1_DATA | | ||
388 | WL1251_ACX_INTR_TX_RESULT | | ||
389 | WL1251_ACX_INTR_EVENT_A | | ||
390 | WL1251_ACX_INTR_EVENT_B | | ||
391 | WL1251_ACX_INTR_INIT_COMPLETE; | ||
392 | wl1251_boot_target_enable_interrupts(wl); | ||
393 | } | ||
394 | |||
395 | static void wl1251_fw_version(struct wl1251 *wl) | ||
396 | { | ||
397 | wl1251_acx_fw_version(wl, wl->chip.fw_ver, sizeof(wl->chip.fw_ver)); | ||
398 | } | ||
399 | |||
400 | static void wl1251_irq_work(struct work_struct *work) | ||
401 | { | ||
402 | u32 intr; | ||
403 | struct wl1251 *wl = | ||
404 | container_of(work, struct wl1251, irq_work); | ||
405 | int ret; | ||
406 | |||
407 | mutex_lock(&wl->mutex); | ||
408 | |||
409 | wl1251_debug(DEBUG_IRQ, "IRQ work"); | ||
410 | |||
411 | if (wl->state == WL1251_STATE_OFF) | ||
412 | goto out; | ||
413 | |||
414 | ret = wl1251_ps_elp_wakeup(wl); | ||
415 | if (ret < 0) | ||
416 | goto out; | ||
417 | |||
418 | wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, WL1251_ACX_INTR_ALL); | ||
419 | |||
420 | intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_CLEAR); | ||
421 | wl1251_debug(DEBUG_IRQ, "intr: 0x%x", intr); | ||
422 | |||
423 | if (wl->data_path) { | ||
424 | wl->rx_counter = | ||
425 | wl1251_mem_read32(wl, wl->data_path->rx_control_addr); | ||
426 | |||
427 | /* We handle a firmware bug here */ | ||
428 | switch ((wl->rx_counter - wl->rx_handled) & 0xf) { | ||
429 | case 0: | ||
430 | wl1251_debug(DEBUG_IRQ, "RX: FW and host in sync"); | ||
431 | intr &= ~WL1251_ACX_INTR_RX0_DATA; | ||
432 | intr &= ~WL1251_ACX_INTR_RX1_DATA; | ||
433 | break; | ||
434 | case 1: | ||
435 | wl1251_debug(DEBUG_IRQ, "RX: FW +1"); | ||
436 | intr |= WL1251_ACX_INTR_RX0_DATA; | ||
437 | intr &= ~WL1251_ACX_INTR_RX1_DATA; | ||
438 | break; | ||
439 | case 2: | ||
440 | wl1251_debug(DEBUG_IRQ, "RX: FW +2"); | ||
441 | intr |= WL1251_ACX_INTR_RX0_DATA; | ||
442 | intr |= WL1251_ACX_INTR_RX1_DATA; | ||
443 | break; | ||
444 | default: | ||
445 | wl1251_warning("RX: FW and host out of sync: %d", | ||
446 | wl->rx_counter - wl->rx_handled); | ||
447 | break; | ||
448 | } | ||
449 | |||
450 | wl->rx_handled = wl->rx_counter; | ||
451 | |||
452 | |||
453 | wl1251_debug(DEBUG_IRQ, "RX counter: %d", wl->rx_counter); | ||
454 | } | ||
455 | |||
456 | intr &= wl->intr_mask; | ||
457 | |||
458 | if (intr == 0) { | ||
459 | wl1251_debug(DEBUG_IRQ, "INTR is 0"); | ||
460 | wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, | ||
461 | ~(wl->intr_mask)); | ||
462 | |||
463 | goto out_sleep; | ||
464 | } | ||
465 | |||
466 | if (intr & WL1251_ACX_INTR_RX0_DATA) { | ||
467 | wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX0_DATA"); | ||
468 | wl1251_rx(wl); | ||
469 | } | ||
470 | |||
471 | if (intr & WL1251_ACX_INTR_RX1_DATA) { | ||
472 | wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX1_DATA"); | ||
473 | wl1251_rx(wl); | ||
474 | } | ||
475 | |||
476 | if (intr & WL1251_ACX_INTR_TX_RESULT) { | ||
477 | wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_TX_RESULT"); | ||
478 | wl1251_tx_complete(wl); | ||
479 | } | ||
480 | |||
481 | if (intr & (WL1251_ACX_INTR_EVENT_A | WL1251_ACX_INTR_EVENT_B)) { | ||
482 | wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_EVENT (0x%x)", intr); | ||
483 | if (intr & WL1251_ACX_INTR_EVENT_A) | ||
484 | wl1251_event_handle(wl, 0); | ||
485 | else | ||
486 | wl1251_event_handle(wl, 1); | ||
487 | } | ||
488 | |||
489 | if (intr & WL1251_ACX_INTR_INIT_COMPLETE) | ||
490 | wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_INIT_COMPLETE"); | ||
491 | |||
492 | wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask)); | ||
493 | |||
494 | out_sleep: | ||
495 | wl1251_ps_elp_sleep(wl); | ||
496 | |||
497 | out: | ||
498 | mutex_unlock(&wl->mutex); | ||
499 | } | ||
500 | |||
501 | static int wl1251_hw_init_txq_fill(u8 qid, | ||
502 | struct acx_tx_queue_qos_config *config, | ||
503 | u32 num_blocks) | ||
504 | { | ||
505 | config->qid = qid; | ||
506 | |||
507 | switch (qid) { | ||
508 | case QOS_AC_BE: | ||
509 | config->high_threshold = | ||
510 | (QOS_TX_HIGH_BE_DEF * num_blocks) / 100; | ||
511 | config->low_threshold = | ||
512 | (QOS_TX_LOW_BE_DEF * num_blocks) / 100; | ||
513 | break; | ||
514 | case QOS_AC_BK: | ||
515 | config->high_threshold = | ||
516 | (QOS_TX_HIGH_BK_DEF * num_blocks) / 100; | ||
517 | config->low_threshold = | ||
518 | (QOS_TX_LOW_BK_DEF * num_blocks) / 100; | ||
519 | break; | ||
520 | case QOS_AC_VI: | ||
521 | config->high_threshold = | ||
522 | (QOS_TX_HIGH_VI_DEF * num_blocks) / 100; | ||
523 | config->low_threshold = | ||
524 | (QOS_TX_LOW_VI_DEF * num_blocks) / 100; | ||
525 | break; | ||
526 | case QOS_AC_VO: | ||
527 | config->high_threshold = | ||
528 | (QOS_TX_HIGH_VO_DEF * num_blocks) / 100; | ||
529 | config->low_threshold = | ||
530 | (QOS_TX_LOW_VO_DEF * num_blocks) / 100; | ||
531 | break; | ||
532 | default: | ||
533 | wl1251_error("Invalid TX queue id: %d", qid); | ||
534 | return -EINVAL; | ||
535 | } | ||
536 | |||
537 | return 0; | ||
538 | } | ||
539 | |||
540 | static int wl1251_hw_init_tx_queue_config(struct wl1251 *wl) | ||
541 | { | ||
542 | struct acx_tx_queue_qos_config *config; | ||
543 | struct wl1251_acx_mem_map *wl_mem_map = wl->target_mem_map; | ||
544 | int ret, i; | ||
545 | |||
546 | wl1251_debug(DEBUG_ACX, "acx tx queue config"); | ||
547 | |||
548 | config = kzalloc(sizeof(*config), GFP_KERNEL); | ||
549 | if (!config) { | ||
550 | ret = -ENOMEM; | ||
551 | goto out; | ||
552 | } | ||
553 | |||
554 | for (i = 0; i < MAX_NUM_OF_AC; i++) { | ||
555 | ret = wl1251_hw_init_txq_fill(i, config, | ||
556 | wl_mem_map->num_tx_mem_blocks); | ||
557 | if (ret < 0) | ||
558 | goto out; | ||
559 | |||
560 | ret = wl1251_cmd_configure(wl, ACX_TX_QUEUE_CFG, | ||
561 | config, sizeof(*config)); | ||
562 | if (ret < 0) | ||
563 | goto out; | ||
564 | } | ||
565 | |||
566 | out: | ||
567 | kfree(config); | ||
568 | return ret; | ||
569 | } | ||
570 | |||
571 | static int wl1251_hw_init_data_path_config(struct wl1251 *wl) | ||
572 | { | ||
573 | int ret; | ||
574 | |||
575 | /* asking for the data path parameters */ | ||
576 | wl->data_path = kzalloc(sizeof(struct acx_data_path_params_resp), | ||
577 | GFP_KERNEL); | ||
578 | if (!wl->data_path) { | ||
579 | wl1251_error("Couldn't allocate data path parameters"); | ||
580 | return -ENOMEM; | ||
581 | } | ||
582 | |||
583 | ret = wl1251_acx_data_path_params(wl, wl->data_path); | ||
584 | if (ret < 0) { | ||
585 | kfree(wl->data_path); | ||
586 | wl->data_path = NULL; | ||
587 | return ret; | ||
588 | } | ||
589 | |||
590 | return 0; | ||
591 | } | ||
592 | |||
593 | static int wl1251_hw_init(struct wl1251 *wl) | ||
594 | { | ||
595 | struct wl1251_acx_mem_map *wl_mem_map; | ||
596 | int ret; | ||
597 | |||
598 | ret = wl1251_hw_init_hwenc_config(wl); | ||
599 | if (ret < 0) | ||
600 | return ret; | ||
601 | |||
602 | /* Template settings */ | ||
603 | ret = wl1251_hw_init_templates_config(wl); | ||
604 | if (ret < 0) | ||
605 | return ret; | ||
606 | |||
607 | /* Default memory configuration */ | ||
608 | ret = wl1251_hw_init_mem_config(wl); | ||
609 | if (ret < 0) | ||
610 | return ret; | ||
611 | |||
612 | /* Default data path configuration */ | ||
613 | ret = wl1251_hw_init_data_path_config(wl); | ||
614 | if (ret < 0) | ||
615 | goto out_free_memmap; | ||
616 | |||
617 | /* RX config */ | ||
618 | ret = wl1251_hw_init_rx_config(wl, | ||
619 | RX_CFG_PROMISCUOUS | RX_CFG_TSF, | ||
620 | RX_FILTER_OPTION_DEF); | ||
621 | /* RX_CONFIG_OPTION_ANY_DST_ANY_BSS, | ||
622 | RX_FILTER_OPTION_FILTER_ALL); */ | ||
623 | if (ret < 0) | ||
624 | goto out_free_data_path; | ||
625 | |||
626 | /* TX queues config */ | ||
627 | ret = wl1251_hw_init_tx_queue_config(wl); | ||
628 | if (ret < 0) | ||
629 | goto out_free_data_path; | ||
630 | |||
631 | /* PHY layer config */ | ||
632 | ret = wl1251_hw_init_phy_config(wl); | ||
633 | if (ret < 0) | ||
634 | goto out_free_data_path; | ||
635 | |||
636 | /* Beacon filtering */ | ||
637 | ret = wl1251_hw_init_beacon_filter(wl); | ||
638 | if (ret < 0) | ||
639 | goto out_free_data_path; | ||
640 | |||
641 | /* Bluetooth WLAN coexistence */ | ||
642 | ret = wl1251_hw_init_pta(wl); | ||
643 | if (ret < 0) | ||
644 | goto out_free_data_path; | ||
645 | |||
646 | /* Energy detection */ | ||
647 | ret = wl1251_hw_init_energy_detection(wl); | ||
648 | if (ret < 0) | ||
649 | goto out_free_data_path; | ||
650 | |||
651 | /* Beacons and boradcast settings */ | ||
652 | ret = wl1251_hw_init_beacon_broadcast(wl); | ||
653 | if (ret < 0) | ||
654 | goto out_free_data_path; | ||
655 | |||
656 | /* Enable data path */ | ||
657 | ret = wl1251_cmd_data_path(wl, wl->channel, 1); | ||
658 | if (ret < 0) | ||
659 | goto out_free_data_path; | ||
660 | |||
661 | /* Default power state */ | ||
662 | ret = wl1251_hw_init_power_auth(wl); | ||
663 | if (ret < 0) | ||
664 | goto out_free_data_path; | ||
665 | |||
666 | wl_mem_map = wl->target_mem_map; | ||
667 | wl1251_info("%d tx blocks at 0x%x, %d rx blocks at 0x%x", | ||
668 | wl_mem_map->num_tx_mem_blocks, | ||
669 | wl->data_path->tx_control_addr, | ||
670 | wl_mem_map->num_rx_mem_blocks, | ||
671 | wl->data_path->rx_control_addr); | ||
672 | |||
673 | return 0; | ||
674 | |||
675 | out_free_data_path: | ||
676 | kfree(wl->data_path); | ||
677 | |||
678 | out_free_memmap: | ||
679 | kfree(wl->target_mem_map); | ||
680 | |||
681 | return ret; | ||
682 | } | ||
683 | |||
684 | static int wl1251_plt_init(struct wl1251 *wl) | ||
685 | { | ||
686 | int ret; | ||
687 | |||
688 | ret = wl1251_hw_init_mem_config(wl); | ||
689 | if (ret < 0) | ||
690 | return ret; | ||
691 | |||
692 | ret = wl1251_cmd_data_path(wl, wl->channel, 1); | ||
693 | if (ret < 0) | ||
694 | return ret; | ||
695 | |||
696 | return 0; | ||
697 | } | ||
698 | |||
699 | void wl1251_setup(struct wl1251 *wl) | ||
700 | { | ||
701 | /* FIXME: Is it better to use strncpy here or is this ok? */ | ||
702 | wl->chip.fw_filename = WL1251_FW_NAME; | ||
703 | wl->chip.nvs_filename = WL1251_NVS_NAME; | ||
704 | |||
705 | /* Now we know what chip we're using, so adjust the power on sleep | ||
706 | * time accordingly */ | ||
707 | wl->chip.power_on_sleep = WL1251_POWER_ON_SLEEP; | ||
708 | |||
709 | wl->chip.intr_cmd_complete = WL1251_ACX_INTR_CMD_COMPLETE; | ||
710 | wl->chip.intr_init_complete = WL1251_ACX_INTR_INIT_COMPLETE; | ||
711 | |||
712 | wl->chip.op_upload_nvs = wl1251_upload_nvs; | ||
713 | wl->chip.op_upload_fw = wl1251_upload_firmware; | ||
714 | wl->chip.op_boot = wl1251_boot; | ||
715 | wl->chip.op_set_ecpu_ctrl = wl1251_set_ecpu_ctrl; | ||
716 | wl->chip.op_target_enable_interrupts = wl1251_target_enable_interrupts; | ||
717 | wl->chip.op_hw_init = wl1251_hw_init; | ||
718 | wl->chip.op_plt_init = wl1251_plt_init; | ||
719 | wl->chip.op_fw_version = wl1251_fw_version; | ||
720 | wl->chip.op_tx_flush = wl1251_tx_flush; | ||
721 | wl->chip.op_cmd_join = wl1251_cmd_join; | ||
722 | |||
723 | wl->chip.p_table = wl1251_part_table; | ||
724 | wl->chip.acx_reg_table = wl1251_acx_reg_table; | ||
725 | |||
726 | INIT_WORK(&wl->irq_work, wl1251_irq_work); | ||
727 | INIT_WORK(&wl->tx_work, wl1251_tx_work); | ||
728 | |||
729 | } | ||