Commit | Line | Data |
---|---|---|
bdcd8170 KV |
1 | /* |
2 | * Copyright (c) 2004-2011 Atheros Communications Inc. | |
1b2df407 | 3 | * Copyright (c) 2011-2012 Qualcomm Atheros, Inc. |
bdcd8170 KV |
4 | * |
5 | * Permission to use, copy, modify, and/or distribute this software for any | |
6 | * purpose with or without fee is hereby granted, provided that the above | |
7 | * copyright notice and this permission notice appear in all copies. | |
8 | * | |
9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
10 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
11 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
12 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
13 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
14 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
15 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
16 | */ | |
17 | ||
18 | #include "core.h" | |
19 | #include "hif-ops.h" | |
20 | #include "target.h" | |
21 | #include "debug.h" | |
22 | ||
bdcd8170 KV |
23 | int ath6kl_bmi_done(struct ath6kl *ar) |
24 | { | |
25 | int ret; | |
26 | u32 cid = BMI_DONE; | |
27 | ||
28 | if (ar->bmi.done_sent) { | |
29 | ath6kl_dbg(ATH6KL_DBG_BMI, "bmi done skipped\n"); | |
30 | return 0; | |
31 | } | |
32 | ||
33 | ar->bmi.done_sent = true; | |
34 | ||
66b693c3 | 35 | ret = ath6kl_hif_bmi_write(ar, (u8 *)&cid, sizeof(cid)); |
bdcd8170 KV |
36 | if (ret) { |
37 | ath6kl_err("Unable to send bmi done: %d\n", ret); | |
38 | return ret; | |
39 | } | |
40 | ||
bdcd8170 KV |
41 | return 0; |
42 | } | |
43 | ||
44 | int ath6kl_bmi_get_target_info(struct ath6kl *ar, | |
45 | struct ath6kl_bmi_target_info *targ_info) | |
46 | { | |
47 | int ret; | |
48 | u32 cid = BMI_GET_TARGET_INFO; | |
49 | ||
50 | if (ar->bmi.done_sent) { | |
51 | ath6kl_err("bmi done sent already, cmd %d disallowed\n", cid); | |
52 | return -EACCES; | |
53 | } | |
54 | ||
66b693c3 | 55 | ret = ath6kl_hif_bmi_write(ar, (u8 *)&cid, sizeof(cid)); |
bdcd8170 KV |
56 | if (ret) { |
57 | ath6kl_err("Unable to send get target info: %d\n", ret); | |
58 | return ret; | |
59 | } | |
60 | ||
241b128b KV |
61 | if (ar->hif_type == ATH6KL_HIF_TYPE_USB) { |
62 | ret = ath6kl_hif_bmi_read(ar, (u8 *)targ_info, | |
63 | sizeof(*targ_info)); | |
64 | } else { | |
65 | ret = ath6kl_hif_bmi_read(ar, (u8 *)&targ_info->version, | |
66 | sizeof(targ_info->version)); | |
67 | } | |
68 | ||
bdcd8170 KV |
69 | if (ret) { |
70 | ath6kl_err("Unable to recv target info: %d\n", ret); | |
71 | return ret; | |
72 | } | |
73 | ||
74 | if (le32_to_cpu(targ_info->version) == TARGET_VERSION_SENTINAL) { | |
75 | /* Determine how many bytes are in the Target's targ_info */ | |
66b693c3 | 76 | ret = ath6kl_hif_bmi_read(ar, |
bdcd8170 | 77 | (u8 *)&targ_info->byte_count, |
cfc301ed | 78 | sizeof(targ_info->byte_count)); |
bdcd8170 KV |
79 | if (ret) { |
80 | ath6kl_err("unable to read target info byte count: %d\n", | |
81 | ret); | |
82 | return ret; | |
83 | } | |
84 | ||
85 | /* | |
86 | * The target's targ_info doesn't match the host's targ_info. | |
87 | * We need to do some backwards compatibility to make this work. | |
88 | */ | |
89 | if (le32_to_cpu(targ_info->byte_count) != sizeof(*targ_info)) { | |
90 | WARN_ON(1); | |
91 | return -EINVAL; | |
92 | } | |
93 | ||
94 | /* Read the remainder of the targ_info */ | |
66b693c3 | 95 | ret = ath6kl_hif_bmi_read(ar, |
bdcd8170 KV |
96 | ((u8 *)targ_info) + |
97 | sizeof(targ_info->byte_count), | |
98 | sizeof(*targ_info) - | |
cfc301ed | 99 | sizeof(targ_info->byte_count)); |
bdcd8170 KV |
100 | |
101 | if (ret) { | |
102 | ath6kl_err("Unable to read target info (%d bytes): %d\n", | |
103 | targ_info->byte_count, ret); | |
104 | return ret; | |
105 | } | |
106 | } | |
107 | ||
108 | ath6kl_dbg(ATH6KL_DBG_BMI, "target info (ver: 0x%x type: 0x%x)\n", | |
109 | targ_info->version, targ_info->type); | |
110 | ||
111 | return 0; | |
112 | } | |
113 | ||
114 | int ath6kl_bmi_read(struct ath6kl *ar, u32 addr, u8 *buf, u32 len) | |
115 | { | |
116 | u32 cid = BMI_READ_MEMORY; | |
117 | int ret; | |
118 | u32 offset; | |
119 | u32 len_remain, rx_len; | |
120 | u16 size; | |
121 | ||
122 | if (ar->bmi.done_sent) { | |
123 | ath6kl_err("bmi done sent already, cmd %d disallowed\n", cid); | |
124 | return -EACCES; | |
125 | } | |
126 | ||
1f4c894d KV |
127 | size = ar->bmi.max_data_size + sizeof(cid) + sizeof(addr) + sizeof(len); |
128 | if (size > ar->bmi.max_cmd_size) { | |
bdcd8170 KV |
129 | WARN_ON(1); |
130 | return -EINVAL; | |
131 | } | |
132 | memset(ar->bmi.cmd_buf, 0, size); | |
133 | ||
134 | ath6kl_dbg(ATH6KL_DBG_BMI, | |
135 | "bmi read memory: device: addr: 0x%x, len: %d\n", | |
136 | addr, len); | |
137 | ||
138 | len_remain = len; | |
139 | ||
140 | while (len_remain) { | |
1f4c894d KV |
141 | rx_len = (len_remain < ar->bmi.max_data_size) ? |
142 | len_remain : ar->bmi.max_data_size; | |
bdcd8170 KV |
143 | offset = 0; |
144 | memcpy(&(ar->bmi.cmd_buf[offset]), &cid, sizeof(cid)); | |
145 | offset += sizeof(cid); | |
146 | memcpy(&(ar->bmi.cmd_buf[offset]), &addr, sizeof(addr)); | |
147 | offset += sizeof(addr); | |
148 | memcpy(&(ar->bmi.cmd_buf[offset]), &rx_len, sizeof(rx_len)); | |
149 | offset += sizeof(len); | |
150 | ||
66b693c3 | 151 | ret = ath6kl_hif_bmi_write(ar, ar->bmi.cmd_buf, offset); |
bdcd8170 KV |
152 | if (ret) { |
153 | ath6kl_err("Unable to write to the device: %d\n", | |
154 | ret); | |
155 | return ret; | |
156 | } | |
66b693c3 | 157 | ret = ath6kl_hif_bmi_read(ar, ar->bmi.cmd_buf, rx_len); |
bdcd8170 KV |
158 | if (ret) { |
159 | ath6kl_err("Unable to read from the device: %d\n", | |
160 | ret); | |
161 | return ret; | |
162 | } | |
163 | memcpy(&buf[len - len_remain], ar->bmi.cmd_buf, rx_len); | |
164 | len_remain -= rx_len; addr += rx_len; | |
165 | } | |
166 | ||
167 | return 0; | |
168 | } | |
169 | ||
170 | int ath6kl_bmi_write(struct ath6kl *ar, u32 addr, u8 *buf, u32 len) | |
171 | { | |
172 | u32 cid = BMI_WRITE_MEMORY; | |
173 | int ret; | |
174 | u32 offset; | |
175 | u32 len_remain, tx_len; | |
176 | const u32 header = sizeof(cid) + sizeof(addr) + sizeof(len); | |
1f4c894d | 177 | u8 aligned_buf[400]; |
bdcd8170 KV |
178 | u8 *src; |
179 | ||
180 | if (ar->bmi.done_sent) { | |
181 | ath6kl_err("bmi done sent already, cmd %d disallowed\n", cid); | |
182 | return -EACCES; | |
183 | } | |
184 | ||
1f4c894d | 185 | if ((ar->bmi.max_data_size + header) > ar->bmi.max_cmd_size) { |
bdcd8170 KV |
186 | WARN_ON(1); |
187 | return -EINVAL; | |
188 | } | |
189 | ||
1f4c894d KV |
190 | if (WARN_ON(ar->bmi.max_data_size > sizeof(aligned_buf))) |
191 | return -E2BIG; | |
192 | ||
193 | memset(ar->bmi.cmd_buf, 0, ar->bmi.max_data_size + header); | |
bdcd8170 KV |
194 | |
195 | ath6kl_dbg(ATH6KL_DBG_BMI, | |
196 | "bmi write memory: addr: 0x%x, len: %d\n", addr, len); | |
197 | ||
198 | len_remain = len; | |
199 | while (len_remain) { | |
200 | src = &buf[len - len_remain]; | |
201 | ||
1f4c894d | 202 | if (len_remain < (ar->bmi.max_data_size - header)) { |
bdcd8170 KV |
203 | if (len_remain & 3) { |
204 | /* align it with 4 bytes */ | |
205 | len_remain = len_remain + | |
206 | (4 - (len_remain & 3)); | |
207 | memcpy(aligned_buf, src, len_remain); | |
208 | src = aligned_buf; | |
209 | } | |
210 | tx_len = len_remain; | |
211 | } else { | |
1f4c894d | 212 | tx_len = (ar->bmi.max_data_size - header); |
bdcd8170 KV |
213 | } |
214 | ||
215 | offset = 0; | |
216 | memcpy(&(ar->bmi.cmd_buf[offset]), &cid, sizeof(cid)); | |
217 | offset += sizeof(cid); | |
218 | memcpy(&(ar->bmi.cmd_buf[offset]), &addr, sizeof(addr)); | |
219 | offset += sizeof(addr); | |
220 | memcpy(&(ar->bmi.cmd_buf[offset]), &tx_len, sizeof(tx_len)); | |
221 | offset += sizeof(tx_len); | |
222 | memcpy(&(ar->bmi.cmd_buf[offset]), src, tx_len); | |
223 | offset += tx_len; | |
224 | ||
66b693c3 | 225 | ret = ath6kl_hif_bmi_write(ar, ar->bmi.cmd_buf, offset); |
bdcd8170 KV |
226 | if (ret) { |
227 | ath6kl_err("Unable to write to the device: %d\n", | |
228 | ret); | |
229 | return ret; | |
230 | } | |
231 | len_remain -= tx_len; addr += tx_len; | |
232 | } | |
233 | ||
234 | return 0; | |
235 | } | |
236 | ||
237 | int ath6kl_bmi_execute(struct ath6kl *ar, u32 addr, u32 *param) | |
238 | { | |
239 | u32 cid = BMI_EXECUTE; | |
240 | int ret; | |
241 | u32 offset; | |
242 | u16 size; | |
243 | ||
244 | if (ar->bmi.done_sent) { | |
245 | ath6kl_err("bmi done sent already, cmd %d disallowed\n", cid); | |
246 | return -EACCES; | |
247 | } | |
248 | ||
249 | size = sizeof(cid) + sizeof(addr) + sizeof(param); | |
1f4c894d | 250 | if (size > ar->bmi.max_cmd_size) { |
bdcd8170 KV |
251 | WARN_ON(1); |
252 | return -EINVAL; | |
253 | } | |
254 | memset(ar->bmi.cmd_buf, 0, size); | |
255 | ||
256 | ath6kl_dbg(ATH6KL_DBG_BMI, "bmi execute: addr: 0x%x, param: %d)\n", | |
257 | addr, *param); | |
258 | ||
259 | offset = 0; | |
260 | memcpy(&(ar->bmi.cmd_buf[offset]), &cid, sizeof(cid)); | |
261 | offset += sizeof(cid); | |
262 | memcpy(&(ar->bmi.cmd_buf[offset]), &addr, sizeof(addr)); | |
263 | offset += sizeof(addr); | |
264 | memcpy(&(ar->bmi.cmd_buf[offset]), param, sizeof(*param)); | |
265 | offset += sizeof(*param); | |
266 | ||
66b693c3 | 267 | ret = ath6kl_hif_bmi_write(ar, ar->bmi.cmd_buf, offset); |
bdcd8170 KV |
268 | if (ret) { |
269 | ath6kl_err("Unable to write to the device: %d\n", ret); | |
270 | return ret; | |
271 | } | |
272 | ||
66b693c3 | 273 | ret = ath6kl_hif_bmi_read(ar, ar->bmi.cmd_buf, sizeof(*param)); |
bdcd8170 KV |
274 | if (ret) { |
275 | ath6kl_err("Unable to read from the device: %d\n", ret); | |
276 | return ret; | |
277 | } | |
278 | ||
279 | memcpy(param, ar->bmi.cmd_buf, sizeof(*param)); | |
280 | ||
281 | return 0; | |
282 | } | |
283 | ||
284 | int ath6kl_bmi_set_app_start(struct ath6kl *ar, u32 addr) | |
285 | { | |
286 | u32 cid = BMI_SET_APP_START; | |
287 | int ret; | |
288 | u32 offset; | |
289 | u16 size; | |
290 | ||
291 | if (ar->bmi.done_sent) { | |
292 | ath6kl_err("bmi done sent already, cmd %d disallowed\n", cid); | |
293 | return -EACCES; | |
294 | } | |
295 | ||
296 | size = sizeof(cid) + sizeof(addr); | |
1f4c894d | 297 | if (size > ar->bmi.max_cmd_size) { |
bdcd8170 KV |
298 | WARN_ON(1); |
299 | return -EINVAL; | |
300 | } | |
301 | memset(ar->bmi.cmd_buf, 0, size); | |
302 | ||
303 | ath6kl_dbg(ATH6KL_DBG_BMI, "bmi set app start: addr: 0x%x\n", addr); | |
304 | ||
305 | offset = 0; | |
306 | memcpy(&(ar->bmi.cmd_buf[offset]), &cid, sizeof(cid)); | |
307 | offset += sizeof(cid); | |
308 | memcpy(&(ar->bmi.cmd_buf[offset]), &addr, sizeof(addr)); | |
309 | offset += sizeof(addr); | |
310 | ||
66b693c3 | 311 | ret = ath6kl_hif_bmi_write(ar, ar->bmi.cmd_buf, offset); |
bdcd8170 KV |
312 | if (ret) { |
313 | ath6kl_err("Unable to write to the device: %d\n", ret); | |
314 | return ret; | |
315 | } | |
316 | ||
317 | return 0; | |
318 | } | |
319 | ||
320 | int ath6kl_bmi_reg_read(struct ath6kl *ar, u32 addr, u32 *param) | |
321 | { | |
322 | u32 cid = BMI_READ_SOC_REGISTER; | |
323 | int ret; | |
324 | u32 offset; | |
325 | u16 size; | |
326 | ||
327 | if (ar->bmi.done_sent) { | |
328 | ath6kl_err("bmi done sent already, cmd %d disallowed\n", cid); | |
329 | return -EACCES; | |
330 | } | |
331 | ||
332 | size = sizeof(cid) + sizeof(addr); | |
1f4c894d | 333 | if (size > ar->bmi.max_cmd_size) { |
bdcd8170 KV |
334 | WARN_ON(1); |
335 | return -EINVAL; | |
336 | } | |
337 | memset(ar->bmi.cmd_buf, 0, size); | |
338 | ||
339 | ath6kl_dbg(ATH6KL_DBG_BMI, "bmi read SOC reg: addr: 0x%x\n", addr); | |
340 | ||
341 | offset = 0; | |
342 | memcpy(&(ar->bmi.cmd_buf[offset]), &cid, sizeof(cid)); | |
343 | offset += sizeof(cid); | |
344 | memcpy(&(ar->bmi.cmd_buf[offset]), &addr, sizeof(addr)); | |
345 | offset += sizeof(addr); | |
346 | ||
66b693c3 | 347 | ret = ath6kl_hif_bmi_write(ar, ar->bmi.cmd_buf, offset); |
bdcd8170 KV |
348 | if (ret) { |
349 | ath6kl_err("Unable to write to the device: %d\n", ret); | |
350 | return ret; | |
351 | } | |
352 | ||
66b693c3 | 353 | ret = ath6kl_hif_bmi_read(ar, ar->bmi.cmd_buf, sizeof(*param)); |
bdcd8170 KV |
354 | if (ret) { |
355 | ath6kl_err("Unable to read from the device: %d\n", ret); | |
356 | return ret; | |
357 | } | |
358 | memcpy(param, ar->bmi.cmd_buf, sizeof(*param)); | |
359 | ||
360 | return 0; | |
361 | } | |
362 | ||
363 | int ath6kl_bmi_reg_write(struct ath6kl *ar, u32 addr, u32 param) | |
364 | { | |
365 | u32 cid = BMI_WRITE_SOC_REGISTER; | |
366 | int ret; | |
367 | u32 offset; | |
368 | u16 size; | |
369 | ||
370 | if (ar->bmi.done_sent) { | |
371 | ath6kl_err("bmi done sent already, cmd %d disallowed\n", cid); | |
372 | return -EACCES; | |
373 | } | |
374 | ||
375 | size = sizeof(cid) + sizeof(addr) + sizeof(param); | |
1f4c894d | 376 | if (size > ar->bmi.max_cmd_size) { |
bdcd8170 KV |
377 | WARN_ON(1); |
378 | return -EINVAL; | |
379 | } | |
380 | memset(ar->bmi.cmd_buf, 0, size); | |
381 | ||
382 | ath6kl_dbg(ATH6KL_DBG_BMI, | |
383 | "bmi write SOC reg: addr: 0x%x, param: %d\n", | |
384 | addr, param); | |
385 | ||
386 | offset = 0; | |
387 | memcpy(&(ar->bmi.cmd_buf[offset]), &cid, sizeof(cid)); | |
388 | offset += sizeof(cid); | |
389 | memcpy(&(ar->bmi.cmd_buf[offset]), &addr, sizeof(addr)); | |
390 | offset += sizeof(addr); | |
391 | memcpy(&(ar->bmi.cmd_buf[offset]), ¶m, sizeof(param)); | |
392 | offset += sizeof(param); | |
393 | ||
66b693c3 | 394 | ret = ath6kl_hif_bmi_write(ar, ar->bmi.cmd_buf, offset); |
bdcd8170 KV |
395 | if (ret) { |
396 | ath6kl_err("Unable to write to the device: %d\n", ret); | |
397 | return ret; | |
398 | } | |
399 | ||
400 | return 0; | |
401 | } | |
402 | ||
403 | int ath6kl_bmi_lz_data(struct ath6kl *ar, u8 *buf, u32 len) | |
404 | { | |
405 | u32 cid = BMI_LZ_DATA; | |
406 | int ret; | |
407 | u32 offset; | |
408 | u32 len_remain, tx_len; | |
409 | const u32 header = sizeof(cid) + sizeof(len); | |
410 | u16 size; | |
411 | ||
412 | if (ar->bmi.done_sent) { | |
413 | ath6kl_err("bmi done sent already, cmd %d disallowed\n", cid); | |
414 | return -EACCES; | |
415 | } | |
416 | ||
1f4c894d KV |
417 | size = ar->bmi.max_data_size + header; |
418 | if (size > ar->bmi.max_cmd_size) { | |
bdcd8170 KV |
419 | WARN_ON(1); |
420 | return -EINVAL; | |
421 | } | |
422 | memset(ar->bmi.cmd_buf, 0, size); | |
423 | ||
424 | ath6kl_dbg(ATH6KL_DBG_BMI, "bmi send LZ data: len: %d)\n", | |
425 | len); | |
426 | ||
427 | len_remain = len; | |
428 | while (len_remain) { | |
1f4c894d KV |
429 | tx_len = (len_remain < (ar->bmi.max_data_size - header)) ? |
430 | len_remain : (ar->bmi.max_data_size - header); | |
bdcd8170 KV |
431 | |
432 | offset = 0; | |
433 | memcpy(&(ar->bmi.cmd_buf[offset]), &cid, sizeof(cid)); | |
434 | offset += sizeof(cid); | |
435 | memcpy(&(ar->bmi.cmd_buf[offset]), &tx_len, sizeof(tx_len)); | |
436 | offset += sizeof(tx_len); | |
437 | memcpy(&(ar->bmi.cmd_buf[offset]), &buf[len - len_remain], | |
438 | tx_len); | |
439 | offset += tx_len; | |
440 | ||
66b693c3 | 441 | ret = ath6kl_hif_bmi_write(ar, ar->bmi.cmd_buf, offset); |
bdcd8170 KV |
442 | if (ret) { |
443 | ath6kl_err("Unable to write to the device: %d\n", | |
444 | ret); | |
445 | return ret; | |
446 | } | |
447 | ||
448 | len_remain -= tx_len; | |
449 | } | |
450 | ||
451 | return 0; | |
452 | } | |
453 | ||
454 | int ath6kl_bmi_lz_stream_start(struct ath6kl *ar, u32 addr) | |
455 | { | |
456 | u32 cid = BMI_LZ_STREAM_START; | |
457 | int ret; | |
458 | u32 offset; | |
459 | u16 size; | |
460 | ||
461 | if (ar->bmi.done_sent) { | |
462 | ath6kl_err("bmi done sent already, cmd %d disallowed\n", cid); | |
463 | return -EACCES; | |
464 | } | |
465 | ||
466 | size = sizeof(cid) + sizeof(addr); | |
1f4c894d | 467 | if (size > ar->bmi.max_cmd_size) { |
bdcd8170 KV |
468 | WARN_ON(1); |
469 | return -EINVAL; | |
470 | } | |
471 | memset(ar->bmi.cmd_buf, 0, size); | |
472 | ||
473 | ath6kl_dbg(ATH6KL_DBG_BMI, | |
474 | "bmi LZ stream start: addr: 0x%x)\n", | |
475 | addr); | |
476 | ||
477 | offset = 0; | |
478 | memcpy(&(ar->bmi.cmd_buf[offset]), &cid, sizeof(cid)); | |
479 | offset += sizeof(cid); | |
480 | memcpy(&(ar->bmi.cmd_buf[offset]), &addr, sizeof(addr)); | |
481 | offset += sizeof(addr); | |
482 | ||
66b693c3 | 483 | ret = ath6kl_hif_bmi_write(ar, ar->bmi.cmd_buf, offset); |
bdcd8170 KV |
484 | if (ret) { |
485 | ath6kl_err("Unable to start LZ stream to the device: %d\n", | |
486 | ret); | |
487 | return ret; | |
488 | } | |
489 | ||
490 | return 0; | |
491 | } | |
492 | ||
493 | int ath6kl_bmi_fast_download(struct ath6kl *ar, u32 addr, u8 *buf, u32 len) | |
494 | { | |
495 | int ret; | |
496 | u32 last_word = 0; | |
497 | u32 last_word_offset = len & ~0x3; | |
498 | u32 unaligned_bytes = len & 0x3; | |
499 | ||
500 | ret = ath6kl_bmi_lz_stream_start(ar, addr); | |
501 | if (ret) | |
502 | return ret; | |
503 | ||
504 | if (unaligned_bytes) { | |
505 | /* copy the last word into a zero padded buffer */ | |
506 | memcpy(&last_word, &buf[last_word_offset], unaligned_bytes); | |
507 | } | |
508 | ||
509 | ret = ath6kl_bmi_lz_data(ar, buf, last_word_offset); | |
510 | if (ret) | |
511 | return ret; | |
512 | ||
513 | if (unaligned_bytes) | |
514 | ret = ath6kl_bmi_lz_data(ar, (u8 *)&last_word, 4); | |
515 | ||
516 | if (!ret) { | |
517 | /* Close compressed stream and open a new (fake) one. | |
518 | * This serves mainly to flush Target caches. */ | |
519 | ret = ath6kl_bmi_lz_stream_start(ar, 0x00); | |
520 | } | |
521 | return ret; | |
522 | } | |
523 | ||
5fe4dffb KV |
524 | void ath6kl_bmi_reset(struct ath6kl *ar) |
525 | { | |
526 | ar->bmi.done_sent = false; | |
527 | } | |
528 | ||
bdcd8170 KV |
529 | int ath6kl_bmi_init(struct ath6kl *ar) |
530 | { | |
1f4c894d KV |
531 | if (WARN_ON(ar->bmi.max_data_size == 0)) |
532 | return -EINVAL; | |
533 | ||
534 | /* cmd + addr + len + data_size */ | |
535 | ar->bmi.max_cmd_size = ar->bmi.max_data_size + (sizeof(u32) * 3); | |
bdcd8170 | 536 | |
1f4c894d | 537 | ar->bmi.cmd_buf = kzalloc(ar->bmi.max_cmd_size, GFP_ATOMIC); |
bdcd8170 KV |
538 | if (!ar->bmi.cmd_buf) |
539 | return -ENOMEM; | |
540 | ||
541 | return 0; | |
542 | } | |
543 | ||
544 | void ath6kl_bmi_cleanup(struct ath6kl *ar) | |
545 | { | |
546 | kfree(ar->bmi.cmd_buf); | |
547 | ar->bmi.cmd_buf = NULL; | |
548 | } |