0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018 #include "core.h"
0019 #include "hif-ops.h"
0020 #include "target.h"
0021 #include "debug.h"
0022
0023 int ath6kl_bmi_done(struct ath6kl *ar)
0024 {
0025 int ret;
0026 u32 cid = BMI_DONE;
0027
0028 if (ar->bmi.done_sent) {
0029 ath6kl_dbg(ATH6KL_DBG_BMI, "bmi done skipped\n");
0030 return 0;
0031 }
0032
0033 ar->bmi.done_sent = true;
0034
0035 ret = ath6kl_hif_bmi_write(ar, (u8 *)&cid, sizeof(cid));
0036 if (ret) {
0037 ath6kl_err("Unable to send bmi done: %d\n", ret);
0038 return ret;
0039 }
0040
0041 return 0;
0042 }
0043
0044 int ath6kl_bmi_get_target_info(struct ath6kl *ar,
0045 struct ath6kl_bmi_target_info *targ_info)
0046 {
0047 int ret;
0048 u32 cid = BMI_GET_TARGET_INFO;
0049
0050 if (ar->bmi.done_sent) {
0051 ath6kl_err("bmi done sent already, cmd %d disallowed\n", cid);
0052 return -EACCES;
0053 }
0054
0055 ret = ath6kl_hif_bmi_write(ar, (u8 *)&cid, sizeof(cid));
0056 if (ret) {
0057 ath6kl_err("Unable to send get target info: %d\n", ret);
0058 return ret;
0059 }
0060
0061 if (ar->hif_type == ATH6KL_HIF_TYPE_USB) {
0062 ret = ath6kl_hif_bmi_read(ar, (u8 *)targ_info,
0063 sizeof(*targ_info));
0064 } else {
0065 ret = ath6kl_hif_bmi_read(ar, (u8 *)&targ_info->version,
0066 sizeof(targ_info->version));
0067 }
0068
0069 if (ret) {
0070 ath6kl_err("Unable to recv target info: %d\n", ret);
0071 return ret;
0072 }
0073
0074 if (le32_to_cpu(targ_info->version) == TARGET_VERSION_SENTINAL) {
0075
0076 ret = ath6kl_hif_bmi_read(ar,
0077 (u8 *)&targ_info->byte_count,
0078 sizeof(targ_info->byte_count));
0079 if (ret) {
0080 ath6kl_err("unable to read target info byte count: %d\n",
0081 ret);
0082 return ret;
0083 }
0084
0085
0086
0087
0088
0089 if (le32_to_cpu(targ_info->byte_count) != sizeof(*targ_info)) {
0090 WARN_ON(1);
0091 return -EINVAL;
0092 }
0093
0094
0095 ret = ath6kl_hif_bmi_read(ar,
0096 ((u8 *)targ_info) +
0097 sizeof(targ_info->byte_count),
0098 sizeof(*targ_info) -
0099 sizeof(targ_info->byte_count));
0100
0101 if (ret) {
0102 ath6kl_err("Unable to read target info (%d bytes): %d\n",
0103 targ_info->byte_count, ret);
0104 return ret;
0105 }
0106 }
0107
0108 ath6kl_dbg(ATH6KL_DBG_BMI, "target info (ver: 0x%x type: 0x%x)\n",
0109 targ_info->version, targ_info->type);
0110
0111 return 0;
0112 }
0113
0114 int ath6kl_bmi_read(struct ath6kl *ar, u32 addr, u8 *buf, u32 len)
0115 {
0116 u32 cid = BMI_READ_MEMORY;
0117 int ret;
0118 u32 offset;
0119 u32 len_remain, rx_len;
0120 u16 size;
0121
0122 if (ar->bmi.done_sent) {
0123 ath6kl_err("bmi done sent already, cmd %d disallowed\n", cid);
0124 return -EACCES;
0125 }
0126
0127 size = ar->bmi.max_data_size + sizeof(cid) + sizeof(addr) + sizeof(len);
0128 if (size > ar->bmi.max_cmd_size) {
0129 WARN_ON(1);
0130 return -EINVAL;
0131 }
0132 memset(ar->bmi.cmd_buf, 0, size);
0133
0134 ath6kl_dbg(ATH6KL_DBG_BMI,
0135 "bmi read memory: device: addr: 0x%x, len: %d\n",
0136 addr, len);
0137
0138 len_remain = len;
0139
0140 while (len_remain) {
0141 rx_len = (len_remain < ar->bmi.max_data_size) ?
0142 len_remain : ar->bmi.max_data_size;
0143 offset = 0;
0144 memcpy(&(ar->bmi.cmd_buf[offset]), &cid, sizeof(cid));
0145 offset += sizeof(cid);
0146 memcpy(&(ar->bmi.cmd_buf[offset]), &addr, sizeof(addr));
0147 offset += sizeof(addr);
0148 memcpy(&(ar->bmi.cmd_buf[offset]), &rx_len, sizeof(rx_len));
0149 offset += sizeof(len);
0150
0151 ret = ath6kl_hif_bmi_write(ar, ar->bmi.cmd_buf, offset);
0152 if (ret) {
0153 ath6kl_err("Unable to write to the device: %d\n",
0154 ret);
0155 return ret;
0156 }
0157 ret = ath6kl_hif_bmi_read(ar, ar->bmi.cmd_buf, rx_len);
0158 if (ret) {
0159 ath6kl_err("Unable to read from the device: %d\n",
0160 ret);
0161 return ret;
0162 }
0163 memcpy(&buf[len - len_remain], ar->bmi.cmd_buf, rx_len);
0164 len_remain -= rx_len; addr += rx_len;
0165 }
0166
0167 return 0;
0168 }
0169
0170 int ath6kl_bmi_write(struct ath6kl *ar, u32 addr, u8 *buf, u32 len)
0171 {
0172 u32 cid = BMI_WRITE_MEMORY;
0173 int ret;
0174 u32 offset;
0175 u32 len_remain, tx_len;
0176 const u32 header = sizeof(cid) + sizeof(addr) + sizeof(len);
0177 u8 aligned_buf[400];
0178 u8 *src;
0179
0180 if (ar->bmi.done_sent) {
0181 ath6kl_err("bmi done sent already, cmd %d disallowed\n", cid);
0182 return -EACCES;
0183 }
0184
0185 if ((ar->bmi.max_data_size + header) > ar->bmi.max_cmd_size) {
0186 WARN_ON(1);
0187 return -EINVAL;
0188 }
0189
0190 if (WARN_ON(ar->bmi.max_data_size > sizeof(aligned_buf)))
0191 return -E2BIG;
0192
0193 memset(ar->bmi.cmd_buf, 0, ar->bmi.max_data_size + header);
0194
0195 ath6kl_dbg(ATH6KL_DBG_BMI,
0196 "bmi write memory: addr: 0x%x, len: %d\n", addr, len);
0197
0198 len_remain = len;
0199 while (len_remain) {
0200 src = &buf[len - len_remain];
0201
0202 if (len_remain < (ar->bmi.max_data_size - header)) {
0203 if (len_remain & 3) {
0204
0205 len_remain = len_remain +
0206 (4 - (len_remain & 3));
0207 memcpy(aligned_buf, src, len_remain);
0208 src = aligned_buf;
0209 }
0210 tx_len = len_remain;
0211 } else {
0212 tx_len = (ar->bmi.max_data_size - header);
0213 }
0214
0215 offset = 0;
0216 memcpy(&(ar->bmi.cmd_buf[offset]), &cid, sizeof(cid));
0217 offset += sizeof(cid);
0218 memcpy(&(ar->bmi.cmd_buf[offset]), &addr, sizeof(addr));
0219 offset += sizeof(addr);
0220 memcpy(&(ar->bmi.cmd_buf[offset]), &tx_len, sizeof(tx_len));
0221 offset += sizeof(tx_len);
0222 memcpy(&(ar->bmi.cmd_buf[offset]), src, tx_len);
0223 offset += tx_len;
0224
0225 ret = ath6kl_hif_bmi_write(ar, ar->bmi.cmd_buf, offset);
0226 if (ret) {
0227 ath6kl_err("Unable to write to the device: %d\n",
0228 ret);
0229 return ret;
0230 }
0231 len_remain -= tx_len; addr += tx_len;
0232 }
0233
0234 return 0;
0235 }
0236
0237 int ath6kl_bmi_execute(struct ath6kl *ar, u32 addr, u32 *param)
0238 {
0239 u32 cid = BMI_EXECUTE;
0240 int ret;
0241 u32 offset;
0242 u16 size;
0243
0244 if (ar->bmi.done_sent) {
0245 ath6kl_err("bmi done sent already, cmd %d disallowed\n", cid);
0246 return -EACCES;
0247 }
0248
0249 size = sizeof(cid) + sizeof(addr) + sizeof(param);
0250 if (size > ar->bmi.max_cmd_size) {
0251 WARN_ON(1);
0252 return -EINVAL;
0253 }
0254 memset(ar->bmi.cmd_buf, 0, size);
0255
0256 ath6kl_dbg(ATH6KL_DBG_BMI, "bmi execute: addr: 0x%x, param: %d)\n",
0257 addr, *param);
0258
0259 offset = 0;
0260 memcpy(&(ar->bmi.cmd_buf[offset]), &cid, sizeof(cid));
0261 offset += sizeof(cid);
0262 memcpy(&(ar->bmi.cmd_buf[offset]), &addr, sizeof(addr));
0263 offset += sizeof(addr);
0264 memcpy(&(ar->bmi.cmd_buf[offset]), param, sizeof(*param));
0265 offset += sizeof(*param);
0266
0267 ret = ath6kl_hif_bmi_write(ar, ar->bmi.cmd_buf, offset);
0268 if (ret) {
0269 ath6kl_err("Unable to write to the device: %d\n", ret);
0270 return ret;
0271 }
0272
0273 ret = ath6kl_hif_bmi_read(ar, ar->bmi.cmd_buf, sizeof(*param));
0274 if (ret) {
0275 ath6kl_err("Unable to read from the device: %d\n", ret);
0276 return ret;
0277 }
0278
0279 memcpy(param, ar->bmi.cmd_buf, sizeof(*param));
0280
0281 return 0;
0282 }
0283
0284 int ath6kl_bmi_set_app_start(struct ath6kl *ar, u32 addr)
0285 {
0286 u32 cid = BMI_SET_APP_START;
0287 int ret;
0288 u32 offset;
0289 u16 size;
0290
0291 if (ar->bmi.done_sent) {
0292 ath6kl_err("bmi done sent already, cmd %d disallowed\n", cid);
0293 return -EACCES;
0294 }
0295
0296 size = sizeof(cid) + sizeof(addr);
0297 if (size > ar->bmi.max_cmd_size) {
0298 WARN_ON(1);
0299 return -EINVAL;
0300 }
0301 memset(ar->bmi.cmd_buf, 0, size);
0302
0303 ath6kl_dbg(ATH6KL_DBG_BMI, "bmi set app start: addr: 0x%x\n", addr);
0304
0305 offset = 0;
0306 memcpy(&(ar->bmi.cmd_buf[offset]), &cid, sizeof(cid));
0307 offset += sizeof(cid);
0308 memcpy(&(ar->bmi.cmd_buf[offset]), &addr, sizeof(addr));
0309 offset += sizeof(addr);
0310
0311 ret = ath6kl_hif_bmi_write(ar, ar->bmi.cmd_buf, offset);
0312 if (ret) {
0313 ath6kl_err("Unable to write to the device: %d\n", ret);
0314 return ret;
0315 }
0316
0317 return 0;
0318 }
0319
0320 int ath6kl_bmi_reg_read(struct ath6kl *ar, u32 addr, u32 *param)
0321 {
0322 u32 cid = BMI_READ_SOC_REGISTER;
0323 int ret;
0324 u32 offset;
0325 u16 size;
0326
0327 if (ar->bmi.done_sent) {
0328 ath6kl_err("bmi done sent already, cmd %d disallowed\n", cid);
0329 return -EACCES;
0330 }
0331
0332 size = sizeof(cid) + sizeof(addr);
0333 if (size > ar->bmi.max_cmd_size) {
0334 WARN_ON(1);
0335 return -EINVAL;
0336 }
0337 memset(ar->bmi.cmd_buf, 0, size);
0338
0339 ath6kl_dbg(ATH6KL_DBG_BMI, "bmi read SOC reg: addr: 0x%x\n", addr);
0340
0341 offset = 0;
0342 memcpy(&(ar->bmi.cmd_buf[offset]), &cid, sizeof(cid));
0343 offset += sizeof(cid);
0344 memcpy(&(ar->bmi.cmd_buf[offset]), &addr, sizeof(addr));
0345 offset += sizeof(addr);
0346
0347 ret = ath6kl_hif_bmi_write(ar, ar->bmi.cmd_buf, offset);
0348 if (ret) {
0349 ath6kl_err("Unable to write to the device: %d\n", ret);
0350 return ret;
0351 }
0352
0353 ret = ath6kl_hif_bmi_read(ar, ar->bmi.cmd_buf, sizeof(*param));
0354 if (ret) {
0355 ath6kl_err("Unable to read from the device: %d\n", ret);
0356 return ret;
0357 }
0358 memcpy(param, ar->bmi.cmd_buf, sizeof(*param));
0359
0360 return 0;
0361 }
0362
0363 int ath6kl_bmi_reg_write(struct ath6kl *ar, u32 addr, u32 param)
0364 {
0365 u32 cid = BMI_WRITE_SOC_REGISTER;
0366 int ret;
0367 u32 offset;
0368 u16 size;
0369
0370 if (ar->bmi.done_sent) {
0371 ath6kl_err("bmi done sent already, cmd %d disallowed\n", cid);
0372 return -EACCES;
0373 }
0374
0375 size = sizeof(cid) + sizeof(addr) + sizeof(param);
0376 if (size > ar->bmi.max_cmd_size) {
0377 WARN_ON(1);
0378 return -EINVAL;
0379 }
0380 memset(ar->bmi.cmd_buf, 0, size);
0381
0382 ath6kl_dbg(ATH6KL_DBG_BMI,
0383 "bmi write SOC reg: addr: 0x%x, param: %d\n",
0384 addr, param);
0385
0386 offset = 0;
0387 memcpy(&(ar->bmi.cmd_buf[offset]), &cid, sizeof(cid));
0388 offset += sizeof(cid);
0389 memcpy(&(ar->bmi.cmd_buf[offset]), &addr, sizeof(addr));
0390 offset += sizeof(addr);
0391 memcpy(&(ar->bmi.cmd_buf[offset]), ¶m, sizeof(param));
0392 offset += sizeof(param);
0393
0394 ret = ath6kl_hif_bmi_write(ar, ar->bmi.cmd_buf, offset);
0395 if (ret) {
0396 ath6kl_err("Unable to write to the device: %d\n", ret);
0397 return ret;
0398 }
0399
0400 return 0;
0401 }
0402
0403 int ath6kl_bmi_lz_data(struct ath6kl *ar, u8 *buf, u32 len)
0404 {
0405 u32 cid = BMI_LZ_DATA;
0406 int ret;
0407 u32 offset;
0408 u32 len_remain, tx_len;
0409 const u32 header = sizeof(cid) + sizeof(len);
0410 u16 size;
0411
0412 if (ar->bmi.done_sent) {
0413 ath6kl_err("bmi done sent already, cmd %d disallowed\n", cid);
0414 return -EACCES;
0415 }
0416
0417 size = ar->bmi.max_data_size + header;
0418 if (size > ar->bmi.max_cmd_size) {
0419 WARN_ON(1);
0420 return -EINVAL;
0421 }
0422 memset(ar->bmi.cmd_buf, 0, size);
0423
0424 ath6kl_dbg(ATH6KL_DBG_BMI, "bmi send LZ data: len: %d)\n",
0425 len);
0426
0427 len_remain = len;
0428 while (len_remain) {
0429 tx_len = (len_remain < (ar->bmi.max_data_size - header)) ?
0430 len_remain : (ar->bmi.max_data_size - header);
0431
0432 offset = 0;
0433 memcpy(&(ar->bmi.cmd_buf[offset]), &cid, sizeof(cid));
0434 offset += sizeof(cid);
0435 memcpy(&(ar->bmi.cmd_buf[offset]), &tx_len, sizeof(tx_len));
0436 offset += sizeof(tx_len);
0437 memcpy(&(ar->bmi.cmd_buf[offset]), &buf[len - len_remain],
0438 tx_len);
0439 offset += tx_len;
0440
0441 ret = ath6kl_hif_bmi_write(ar, ar->bmi.cmd_buf, offset);
0442 if (ret) {
0443 ath6kl_err("Unable to write to the device: %d\n",
0444 ret);
0445 return ret;
0446 }
0447
0448 len_remain -= tx_len;
0449 }
0450
0451 return 0;
0452 }
0453
0454 int ath6kl_bmi_lz_stream_start(struct ath6kl *ar, u32 addr)
0455 {
0456 u32 cid = BMI_LZ_STREAM_START;
0457 int ret;
0458 u32 offset;
0459 u16 size;
0460
0461 if (ar->bmi.done_sent) {
0462 ath6kl_err("bmi done sent already, cmd %d disallowed\n", cid);
0463 return -EACCES;
0464 }
0465
0466 size = sizeof(cid) + sizeof(addr);
0467 if (size > ar->bmi.max_cmd_size) {
0468 WARN_ON(1);
0469 return -EINVAL;
0470 }
0471 memset(ar->bmi.cmd_buf, 0, size);
0472
0473 ath6kl_dbg(ATH6KL_DBG_BMI,
0474 "bmi LZ stream start: addr: 0x%x)\n",
0475 addr);
0476
0477 offset = 0;
0478 memcpy(&(ar->bmi.cmd_buf[offset]), &cid, sizeof(cid));
0479 offset += sizeof(cid);
0480 memcpy(&(ar->bmi.cmd_buf[offset]), &addr, sizeof(addr));
0481 offset += sizeof(addr);
0482
0483 ret = ath6kl_hif_bmi_write(ar, ar->bmi.cmd_buf, offset);
0484 if (ret) {
0485 ath6kl_err("Unable to start LZ stream to the device: %d\n",
0486 ret);
0487 return ret;
0488 }
0489
0490 return 0;
0491 }
0492
0493 int ath6kl_bmi_fast_download(struct ath6kl *ar, u32 addr, u8 *buf, u32 len)
0494 {
0495 int ret;
0496 u32 last_word = 0;
0497 u32 last_word_offset = len & ~0x3;
0498 u32 unaligned_bytes = len & 0x3;
0499
0500 ret = ath6kl_bmi_lz_stream_start(ar, addr);
0501 if (ret)
0502 return ret;
0503
0504 if (unaligned_bytes) {
0505
0506 memcpy(&last_word, &buf[last_word_offset], unaligned_bytes);
0507 }
0508
0509 ret = ath6kl_bmi_lz_data(ar, buf, last_word_offset);
0510 if (ret)
0511 return ret;
0512
0513 if (unaligned_bytes)
0514 ret = ath6kl_bmi_lz_data(ar, (u8 *)&last_word, 4);
0515
0516 if (!ret) {
0517
0518
0519 ret = ath6kl_bmi_lz_stream_start(ar, 0x00);
0520 }
0521 return ret;
0522 }
0523
0524 void ath6kl_bmi_reset(struct ath6kl *ar)
0525 {
0526 ar->bmi.done_sent = false;
0527 }
0528
0529 int ath6kl_bmi_init(struct ath6kl *ar)
0530 {
0531 if (WARN_ON(ar->bmi.max_data_size == 0))
0532 return -EINVAL;
0533
0534
0535 ar->bmi.max_cmd_size = ar->bmi.max_data_size + (sizeof(u32) * 3);
0536
0537 ar->bmi.cmd_buf = kzalloc(ar->bmi.max_cmd_size, GFP_KERNEL);
0538 if (!ar->bmi.cmd_buf)
0539 return -ENOMEM;
0540
0541 return 0;
0542 }
0543
0544 void ath6kl_bmi_cleanup(struct ath6kl *ar)
0545 {
0546 kfree(ar->bmi.cmd_buf);
0547 ar->bmi.cmd_buf = NULL;
0548 }