diff options
Diffstat (limited to 'drivers/staging/ath6kl/bmi')
| -rw-r--r-- | drivers/staging/ath6kl/bmi/include/bmi_internal.h | 54 | ||||
| -rw-r--r-- | drivers/staging/ath6kl/bmi/src/bmi.c | 1010 |
2 files changed, 1064 insertions, 0 deletions
diff --git a/drivers/staging/ath6kl/bmi/include/bmi_internal.h b/drivers/staging/ath6kl/bmi/include/bmi_internal.h new file mode 100644 index 00000000000..8e2577074d6 --- /dev/null +++ b/drivers/staging/ath6kl/bmi/include/bmi_internal.h | |||
| @@ -0,0 +1,54 @@ | |||
| 1 | //------------------------------------------------------------------------------ | ||
| 2 | // Copyright (c) 2004-2010 Atheros Communications Inc. | ||
| 3 | // All rights reserved. | ||
| 4 | // | ||
| 5 | // | ||
| 6 | // Permission to use, copy, modify, and/or distribute this software for any | ||
| 7 | // purpose with or without fee is hereby granted, provided that the above | ||
| 8 | // copyright notice and this permission notice appear in all copies. | ||
| 9 | // | ||
| 10 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
| 11 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
| 12 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
| 13 | // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
| 14 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
| 15 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
| 16 | // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
| 17 | // | ||
| 18 | // | ||
| 19 | //------------------------------------------------------------------------------ | ||
| 20 | //============================================================================== | ||
| 21 | // | ||
| 22 | // Author(s): ="Atheros" | ||
| 23 | //============================================================================== | ||
| 24 | #ifndef BMI_INTERNAL_H | ||
| 25 | #define BMI_INTERNAL_H | ||
| 26 | |||
| 27 | #include "a_config.h" | ||
| 28 | #include "athdefs.h" | ||
| 29 | #include "a_osapi.h" | ||
| 30 | #define ATH_MODULE_NAME bmi | ||
| 31 | #include "a_debug.h" | ||
| 32 | #include "hw/mbox_host_reg.h" | ||
| 33 | #include "bmi_msg.h" | ||
| 34 | |||
| 35 | #define ATH_DEBUG_BMI ATH_DEBUG_MAKE_MODULE_MASK(0) | ||
| 36 | |||
| 37 | |||
| 38 | #define BMI_COMMUNICATION_TIMEOUT 100000 | ||
| 39 | |||
| 40 | /* ------ Global Variable Declarations ------- */ | ||
| 41 | static bool bmiDone; | ||
| 42 | |||
| 43 | int | ||
| 44 | bmiBufferSend(struct hif_device *device, | ||
| 45 | u8 *buffer, | ||
| 46 | u32 length); | ||
| 47 | |||
| 48 | int | ||
| 49 | bmiBufferReceive(struct hif_device *device, | ||
| 50 | u8 *buffer, | ||
| 51 | u32 length, | ||
| 52 | bool want_timeout); | ||
| 53 | |||
| 54 | #endif | ||
diff --git a/drivers/staging/ath6kl/bmi/src/bmi.c b/drivers/staging/ath6kl/bmi/src/bmi.c new file mode 100644 index 00000000000..f1f085eba9c --- /dev/null +++ b/drivers/staging/ath6kl/bmi/src/bmi.c | |||
| @@ -0,0 +1,1010 @@ | |||
| 1 | //------------------------------------------------------------------------------ | ||
| 2 | // <copyright file="bmi.c" company="Atheros"> | ||
| 3 | // Copyright (c) 2004-2010 Atheros Corporation. All rights reserved. | ||
| 4 | // | ||
| 5 | // | ||
| 6 | // Permission to use, copy, modify, and/or distribute this software for any | ||
| 7 | // purpose with or without fee is hereby granted, provided that the above | ||
| 8 | // copyright notice and this permission notice appear in all copies. | ||
| 9 | // | ||
| 10 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
| 11 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
| 12 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
| 13 | // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
| 14 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
| 15 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
| 16 | // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
| 17 | // | ||
| 18 | // | ||
| 19 | //------------------------------------------------------------------------------ | ||
| 20 | //============================================================================== | ||
| 21 | // | ||
| 22 | // Author(s): ="Atheros" | ||
| 23 | //============================================================================== | ||
| 24 | |||
| 25 | |||
| 26 | #ifdef THREAD_X | ||
| 27 | #include <string.h> | ||
| 28 | #endif | ||
| 29 | |||
| 30 | #include "hif.h" | ||
| 31 | #include "bmi.h" | ||
| 32 | #include "htc_api.h" | ||
| 33 | #include "bmi_internal.h" | ||
| 34 | |||
| 35 | #ifdef ATH_DEBUG_MODULE | ||
| 36 | static struct ath_debug_mask_description bmi_debug_desc[] = { | ||
| 37 | { ATH_DEBUG_BMI , "BMI Tracing"}, | ||
| 38 | }; | ||
| 39 | |||
| 40 | ATH_DEBUG_INSTANTIATE_MODULE_VAR(bmi, | ||
| 41 | "bmi", | ||
| 42 | "Boot Manager Interface", | ||
| 43 | ATH_DEBUG_MASK_DEFAULTS, | ||
| 44 | ATH_DEBUG_DESCRIPTION_COUNT(bmi_debug_desc), | ||
| 45 | bmi_debug_desc); | ||
| 46 | |||
| 47 | #endif | ||
| 48 | |||
| 49 | /* | ||
| 50 | Although we had envisioned BMI to run on top of HTC, this is not how the | ||
| 51 | final implementation ended up. On the Target side, BMI is a part of the BSP | ||
| 52 | and does not use the HTC protocol nor even DMA -- it is intentionally kept | ||
| 53 | very simple. | ||
| 54 | */ | ||
| 55 | |||
| 56 | static bool pendingEventsFuncCheck = false; | ||
| 57 | static u32 *pBMICmdCredits; | ||
| 58 | static u8 *pBMICmdBuf; | ||
| 59 | #define MAX_BMI_CMDBUF_SZ (BMI_DATASZ_MAX + \ | ||
| 60 | sizeof(u32) /* cmd */ + \ | ||
| 61 | sizeof(u32) /* addr */ + \ | ||
| 62 | sizeof(u32))/* length */ | ||
| 63 | #define BMI_COMMAND_FITS(sz) ((sz) <= MAX_BMI_CMDBUF_SZ) | ||
| 64 | |||
| 65 | /* APIs visible to the driver */ | ||
| 66 | void | ||
| 67 | BMIInit(void) | ||
| 68 | { | ||
| 69 | bmiDone = false; | ||
| 70 | pendingEventsFuncCheck = false; | ||
| 71 | |||
| 72 | /* | ||
| 73 | * On some platforms, it's not possible to DMA to a static variable | ||
| 74 | * in a device driver (e.g. Linux loadable driver module). | ||
| 75 | * So we need to A_MALLOC space for "command credits" and for commands. | ||
| 76 | * | ||
| 77 | * Note: implicitly relies on A_MALLOC to provide a buffer that is | ||
| 78 | * suitable for DMA (or PIO). This buffer will be passed down the | ||
| 79 | * bus stack. | ||
| 80 | */ | ||
| 81 | if (!pBMICmdCredits) { | ||
| 82 | pBMICmdCredits = (u32 *)A_MALLOC_NOWAIT(4); | ||
| 83 | A_ASSERT(pBMICmdCredits); | ||
| 84 | } | ||
| 85 | |||
| 86 | if (!pBMICmdBuf) { | ||
| 87 | pBMICmdBuf = (u8 *)A_MALLOC_NOWAIT(MAX_BMI_CMDBUF_SZ); | ||
| 88 | A_ASSERT(pBMICmdBuf); | ||
| 89 | } | ||
| 90 | |||
| 91 | A_REGISTER_MODULE_DEBUG_INFO(bmi); | ||
| 92 | } | ||
| 93 | |||
| 94 | void | ||
| 95 | BMICleanup(void) | ||
| 96 | { | ||
| 97 | if (pBMICmdCredits) { | ||
| 98 | kfree(pBMICmdCredits); | ||
| 99 | pBMICmdCredits = NULL; | ||
| 100 | } | ||
| 101 | |||
| 102 | if (pBMICmdBuf) { | ||
| 103 | kfree(pBMICmdBuf); | ||
| 104 | pBMICmdBuf = NULL; | ||
| 105 | } | ||
| 106 | } | ||
| 107 | |||
| 108 | int | ||
| 109 | BMIDone(struct hif_device *device) | ||
| 110 | { | ||
| 111 | int status; | ||
| 112 | u32 cid; | ||
| 113 | |||
| 114 | if (bmiDone) { | ||
| 115 | AR_DEBUG_PRINTF (ATH_DEBUG_BMI, ("BMIDone skipped\n")); | ||
| 116 | return 0; | ||
| 117 | } | ||
| 118 | |||
| 119 | AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI Done: Enter (device: 0x%p)\n", device)); | ||
| 120 | bmiDone = true; | ||
| 121 | cid = BMI_DONE; | ||
| 122 | |||
| 123 | status = bmiBufferSend(device, (u8 *)&cid, sizeof(cid)); | ||
| 124 | if (status) { | ||
| 125 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to write to the device\n")); | ||
| 126 | return A_ERROR; | ||
| 127 | } | ||
| 128 | |||
| 129 | if (pBMICmdCredits) { | ||
| 130 | kfree(pBMICmdCredits); | ||
| 131 | pBMICmdCredits = NULL; | ||
| 132 | } | ||
| 133 | |||
| 134 | if (pBMICmdBuf) { | ||
| 135 | kfree(pBMICmdBuf); | ||
| 136 | pBMICmdBuf = NULL; | ||
| 137 | } | ||
| 138 | |||
| 139 | AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI Done: Exit\n")); | ||
| 140 | |||
| 141 | return 0; | ||
| 142 | } | ||
| 143 | |||
| 144 | int | ||
| 145 | BMIGetTargetInfo(struct hif_device *device, struct bmi_target_info *targ_info) | ||
| 146 | { | ||
| 147 | int status; | ||
| 148 | u32 cid; | ||
| 149 | |||
| 150 | if (bmiDone) { | ||
| 151 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Command disallowed\n")); | ||
| 152 | return A_ERROR; | ||
| 153 | } | ||
| 154 | |||
| 155 | AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI Get Target Info: Enter (device: 0x%p)\n", device)); | ||
| 156 | cid = BMI_GET_TARGET_INFO; | ||
| 157 | |||
| 158 | status = bmiBufferSend(device, (u8 *)&cid, sizeof(cid)); | ||
| 159 | if (status) { | ||
| 160 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to write to the device\n")); | ||
| 161 | return A_ERROR; | ||
| 162 | } | ||
| 163 | |||
| 164 | status = bmiBufferReceive(device, (u8 *)&targ_info->target_ver, | ||
| 165 | sizeof(targ_info->target_ver), true); | ||
| 166 | if (status) { | ||
| 167 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to read Target Version from the device\n")); | ||
| 168 | return A_ERROR; | ||
| 169 | } | ||
| 170 | |||
| 171 | if (targ_info->target_ver == TARGET_VERSION_SENTINAL) { | ||
| 172 | /* Determine how many bytes are in the Target's targ_info */ | ||
| 173 | status = bmiBufferReceive(device, (u8 *)&targ_info->target_info_byte_count, | ||
| 174 | sizeof(targ_info->target_info_byte_count), true); | ||
| 175 | if (status) { | ||
| 176 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to read Target Info Byte Count from the device\n")); | ||
| 177 | return A_ERROR; | ||
| 178 | } | ||
| 179 | |||
| 180 | /* | ||
| 181 | * The Target's targ_info doesn't match the Host's targ_info. | ||
| 182 | * We need to do some backwards compatibility work to make this OK. | ||
| 183 | */ | ||
| 184 | A_ASSERT(targ_info->target_info_byte_count == sizeof(*targ_info)); | ||
| 185 | |||
| 186 | /* Read the remainder of the targ_info */ | ||
| 187 | status = bmiBufferReceive(device, | ||
| 188 | ((u8 *)targ_info)+sizeof(targ_info->target_info_byte_count), | ||
| 189 | sizeof(*targ_info)-sizeof(targ_info->target_info_byte_count), true); | ||
| 190 | if (status) { | ||
| 191 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to read Target Info (%d bytes) from the device\n", | ||
| 192 | targ_info->target_info_byte_count)); | ||
| 193 | return A_ERROR; | ||
| 194 | } | ||
| 195 | } | ||
| 196 | |||
| 197 | AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI Get Target Info: Exit (ver: 0x%x type: 0x%x)\n", | ||
| 198 | targ_info->target_ver, targ_info->target_type)); | ||
| 199 | |||
| 200 | return 0; | ||
| 201 | } | ||
| 202 | |||
| 203 | int | ||
| 204 | BMIReadMemory(struct hif_device *device, | ||
| 205 | u32 address, | ||
| 206 | u8 *buffer, | ||
| 207 | u32 length) | ||
| 208 | { | ||
| 209 | u32 cid; | ||
| 210 | int status; | ||
| 211 | u32 offset; | ||
| 212 | u32 remaining, rxlen; | ||
| 213 | |||
| 214 | A_ASSERT(BMI_COMMAND_FITS(BMI_DATASZ_MAX + sizeof(cid) + sizeof(address) + sizeof(length))); | ||
| 215 | memset (pBMICmdBuf, 0, BMI_DATASZ_MAX + sizeof(cid) + sizeof(address) + sizeof(length)); | ||
| 216 | |||
| 217 | if (bmiDone) { | ||
| 218 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Command disallowed\n")); | ||
| 219 | return A_ERROR; | ||
| 220 | } | ||
| 221 | |||
| 222 | AR_DEBUG_PRINTF(ATH_DEBUG_BMI, | ||
| 223 | ("BMI Read Memory: Enter (device: 0x%p, address: 0x%x, length: %d)\n", | ||
| 224 | device, address, length)); | ||
| 225 | |||
| 226 | cid = BMI_READ_MEMORY; | ||
| 227 | |||
| 228 | remaining = length; | ||
| 229 | |||
| 230 | while (remaining) | ||
| 231 | { | ||
| 232 | rxlen = (remaining < BMI_DATASZ_MAX) ? remaining : BMI_DATASZ_MAX; | ||
| 233 | offset = 0; | ||
| 234 | memcpy(&(pBMICmdBuf[offset]), &cid, sizeof(cid)); | ||
| 235 | offset += sizeof(cid); | ||
| 236 | memcpy(&(pBMICmdBuf[offset]), &address, sizeof(address)); | ||
| 237 | offset += sizeof(address); | ||
| 238 | memcpy(&(pBMICmdBuf[offset]), &rxlen, sizeof(rxlen)); | ||
| 239 | offset += sizeof(length); | ||
| 240 | |||
| 241 | status = bmiBufferSend(device, pBMICmdBuf, offset); | ||
| 242 | if (status) { | ||
| 243 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to write to the device\n")); | ||
| 244 | return A_ERROR; | ||
| 245 | } | ||
| 246 | status = bmiBufferReceive(device, pBMICmdBuf, rxlen, true); | ||
| 247 | if (status) { | ||
| 248 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to read from the device\n")); | ||
| 249 | return A_ERROR; | ||
| 250 | } | ||
| 251 | memcpy(&buffer[length - remaining], pBMICmdBuf, rxlen); | ||
| 252 | remaining -= rxlen; address += rxlen; | ||
| 253 | } | ||
| 254 | |||
| 255 | AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI Read Memory: Exit\n")); | ||
| 256 | return 0; | ||
| 257 | } | ||
| 258 | |||
| 259 | int | ||
| 260 | BMIWriteMemory(struct hif_device *device, | ||
| 261 | u32 address, | ||
| 262 | u8 *buffer, | ||
| 263 | u32 length) | ||
| 264 | { | ||
| 265 | u32 cid; | ||
| 266 | int status; | ||
| 267 | u32 offset; | ||
| 268 | u32 remaining, txlen; | ||
| 269 | const u32 header = sizeof(cid) + sizeof(address) + sizeof(length); | ||
| 270 | u8 alignedBuffer[BMI_DATASZ_MAX]; | ||
| 271 | u8 *src; | ||
| 272 | |||
| 273 | A_ASSERT(BMI_COMMAND_FITS(BMI_DATASZ_MAX + header)); | ||
| 274 | memset (pBMICmdBuf, 0, BMI_DATASZ_MAX + header); | ||
| 275 | |||
| 276 | if (bmiDone) { | ||
| 277 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Command disallowed\n")); | ||
| 278 | return A_ERROR; | ||
| 279 | } | ||
| 280 | |||
| 281 | AR_DEBUG_PRINTF(ATH_DEBUG_BMI, | ||
| 282 | ("BMI Write Memory: Enter (device: 0x%p, address: 0x%x, length: %d)\n", | ||
| 283 | device, address, length)); | ||
| 284 | |||
| 285 | cid = BMI_WRITE_MEMORY; | ||
| 286 | |||
| 287 | remaining = length; | ||
| 288 | while (remaining) | ||
| 289 | { | ||
| 290 | src = &buffer[length - remaining]; | ||
| 291 | if (remaining < (BMI_DATASZ_MAX - header)) { | ||
| 292 | if (remaining & 3) { | ||
| 293 | /* align it with 4 bytes */ | ||
| 294 | remaining = remaining + (4 - (remaining & 3)); | ||
| 295 | memcpy(alignedBuffer, src, remaining); | ||
| 296 | src = alignedBuffer; | ||
| 297 | } | ||
| 298 | txlen = remaining; | ||
| 299 | } else { | ||
| 300 | txlen = (BMI_DATASZ_MAX - header); | ||
| 301 | } | ||
| 302 | offset = 0; | ||
| 303 | memcpy(&(pBMICmdBuf[offset]), &cid, sizeof(cid)); | ||
| 304 | offset += sizeof(cid); | ||
| 305 | memcpy(&(pBMICmdBuf[offset]), &address, sizeof(address)); | ||
| 306 | offset += sizeof(address); | ||
| 307 | memcpy(&(pBMICmdBuf[offset]), &txlen, sizeof(txlen)); | ||
| 308 | offset += sizeof(txlen); | ||
| 309 | memcpy(&(pBMICmdBuf[offset]), src, txlen); | ||
| 310 | offset += txlen; | ||
| 311 | status = bmiBufferSend(device, pBMICmdBuf, offset); | ||
| 312 | if (status) { | ||
| 313 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to write to the device\n")); | ||
| 314 | return A_ERROR; | ||
| 315 | } | ||
| 316 | remaining -= txlen; address += txlen; | ||
| 317 | } | ||
| 318 | |||
| 319 | AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI Write Memory: Exit\n")); | ||
| 320 | |||
| 321 | return 0; | ||
| 322 | } | ||
| 323 | |||
| 324 | int | ||
| 325 | BMIExecute(struct hif_device *device, | ||
| 326 | u32 address, | ||
| 327 | u32 *param) | ||
| 328 | { | ||
| 329 | u32 cid; | ||
| 330 | int status; | ||
| 331 | u32 offset; | ||
| 332 | |||
| 333 | A_ASSERT(BMI_COMMAND_FITS(sizeof(cid) + sizeof(address) + sizeof(param))); | ||
| 334 | memset (pBMICmdBuf, 0, sizeof(cid) + sizeof(address) + sizeof(param)); | ||
| 335 | |||
| 336 | if (bmiDone) { | ||
| 337 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Command disallowed\n")); | ||
| 338 | return A_ERROR; | ||
| 339 | } | ||
| 340 | |||
| 341 | AR_DEBUG_PRINTF(ATH_DEBUG_BMI, | ||
| 342 | ("BMI Execute: Enter (device: 0x%p, address: 0x%x, param: %d)\n", | ||
| 343 | device, address, *param)); | ||
| 344 | |||
| 345 | cid = BMI_EXECUTE; | ||
| 346 | |||
| 347 | offset = 0; | ||
| 348 | memcpy(&(pBMICmdBuf[offset]), &cid, sizeof(cid)); | ||
| 349 | offset += sizeof(cid); | ||
| 350 | memcpy(&(pBMICmdBuf[offset]), &address, sizeof(address)); | ||
| 351 | offset += sizeof(address); | ||
| 352 | memcpy(&(pBMICmdBuf[offset]), param, sizeof(*param)); | ||
| 353 | offset += sizeof(*param); | ||
| 354 | status = bmiBufferSend(device, pBMICmdBuf, offset); | ||
| 355 | if (status) { | ||
| 356 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to write to the device\n")); | ||
| 357 | return A_ERROR; | ||
| 358 | } | ||
| 359 | |||
| 360 | status = bmiBufferReceive(device, pBMICmdBuf, sizeof(*param), false); | ||
| 361 | if (status) { | ||
| 362 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to read from the device\n")); | ||
| 363 | return A_ERROR; | ||
| 364 | } | ||
| 365 | |||
| 366 | memcpy(param, pBMICmdBuf, sizeof(*param)); | ||
| 367 | |||
| 368 | AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI Execute: Exit (param: %d)\n", *param)); | ||
| 369 | return 0; | ||
| 370 | } | ||
| 371 | |||
| 372 | int | ||
| 373 | BMISetAppStart(struct hif_device *device, | ||
| 374 | u32 address) | ||
| 375 | { | ||
| 376 | u32 cid; | ||
| 377 | int status; | ||
| 378 | u32 offset; | ||
| 379 | |||
| 380 | A_ASSERT(BMI_COMMAND_FITS(sizeof(cid) + sizeof(address))); | ||
| 381 | memset (pBMICmdBuf, 0, sizeof(cid) + sizeof(address)); | ||
| 382 | |||
| 383 | if (bmiDone) { | ||
| 384 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Command disallowed\n")); | ||
| 385 | return A_ERROR; | ||
| 386 | } | ||
| 387 | |||
| 388 | AR_DEBUG_PRINTF(ATH_DEBUG_BMI, | ||
| 389 | ("BMI Set App Start: Enter (device: 0x%p, address: 0x%x)\n", | ||
| 390 | device, address)); | ||
| 391 | |||
| 392 | cid = BMI_SET_APP_START; | ||
| 393 | |||
| 394 | offset = 0; | ||
| 395 | memcpy(&(pBMICmdBuf[offset]), &cid, sizeof(cid)); | ||
| 396 | offset += sizeof(cid); | ||
| 397 | memcpy(&(pBMICmdBuf[offset]), &address, sizeof(address)); | ||
| 398 | offset += sizeof(address); | ||
| 399 | status = bmiBufferSend(device, pBMICmdBuf, offset); | ||
| 400 | if (status) { | ||
| 401 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to write to the device\n")); | ||
| 402 | return A_ERROR; | ||
| 403 | } | ||
| 404 | |||
| 405 | AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI Set App Start: Exit\n")); | ||
| 406 | return 0; | ||
| 407 | } | ||
| 408 | |||
| 409 | int | ||
| 410 | BMIReadSOCRegister(struct hif_device *device, | ||
| 411 | u32 address, | ||
| 412 | u32 *param) | ||
| 413 | { | ||
| 414 | u32 cid; | ||
| 415 | int status; | ||
| 416 | u32 offset; | ||
| 417 | |||
| 418 | A_ASSERT(BMI_COMMAND_FITS(sizeof(cid) + sizeof(address))); | ||
| 419 | memset (pBMICmdBuf, 0, sizeof(cid) + sizeof(address)); | ||
| 420 | |||
| 421 | if (bmiDone) { | ||
| 422 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Command disallowed\n")); | ||
| 423 | return A_ERROR; | ||
| 424 | } | ||
| 425 | |||
| 426 | AR_DEBUG_PRINTF(ATH_DEBUG_BMI, | ||
| 427 | ("BMI Read SOC Register: Enter (device: 0x%p, address: 0x%x)\n", | ||
| 428 | device, address)); | ||
| 429 | |||
| 430 | cid = BMI_READ_SOC_REGISTER; | ||
| 431 | |||
| 432 | offset = 0; | ||
| 433 | memcpy(&(pBMICmdBuf[offset]), &cid, sizeof(cid)); | ||
| 434 | offset += sizeof(cid); | ||
| 435 | memcpy(&(pBMICmdBuf[offset]), &address, sizeof(address)); | ||
| 436 | offset += sizeof(address); | ||
| 437 | |||
| 438 | status = bmiBufferSend(device, pBMICmdBuf, offset); | ||
| 439 | if (status) { | ||
| 440 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to write to the device\n")); | ||
| 441 | return A_ERROR; | ||
| 442 | } | ||
| 443 | |||
| 444 | status = bmiBufferReceive(device, pBMICmdBuf, sizeof(*param), true); | ||
| 445 | if (status) { | ||
| 446 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to read from the device\n")); | ||
| 447 | return A_ERROR; | ||
| 448 | } | ||
| 449 | memcpy(param, pBMICmdBuf, sizeof(*param)); | ||
| 450 | |||
| 451 | AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI Read SOC Register: Exit (value: %d)\n", *param)); | ||
| 452 | return 0; | ||
| 453 | } | ||
| 454 | |||
| 455 | int | ||
| 456 | BMIWriteSOCRegister(struct hif_device *device, | ||
| 457 | u32 address, | ||
| 458 | u32 param) | ||
| 459 | { | ||
| 460 | u32 cid; | ||
| 461 | int status; | ||
| 462 | u32 offset; | ||
| 463 | |||
| 464 | A_ASSERT(BMI_COMMAND_FITS(sizeof(cid) + sizeof(address) + sizeof(param))); | ||
| 465 | memset (pBMICmdBuf, 0, sizeof(cid) + sizeof(address) + sizeof(param)); | ||
| 466 | |||
| 467 | if (bmiDone) { | ||
| 468 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Command disallowed\n")); | ||
| 469 | return A_ERROR; | ||
| 470 | } | ||
| 471 | |||
| 472 | AR_DEBUG_PRINTF(ATH_DEBUG_BMI, | ||
| 473 | ("BMI Write SOC Register: Enter (device: 0x%p, address: 0x%x, param: %d)\n", | ||
| 474 | device, address, param)); | ||
| 475 | |||
| 476 | cid = BMI_WRITE_SOC_REGISTER; | ||
| 477 | |||
| 478 | offset = 0; | ||
| 479 | memcpy(&(pBMICmdBuf[offset]), &cid, sizeof(cid)); | ||
| 480 | offset += sizeof(cid); | ||
| 481 | memcpy(&(pBMICmdBuf[offset]), &address, sizeof(address)); | ||
| 482 | offset += sizeof(address); | ||
| 483 | memcpy(&(pBMICmdBuf[offset]), ¶m, sizeof(param)); | ||
| 484 | offset += sizeof(param); | ||
| 485 | status = bmiBufferSend(device, pBMICmdBuf, offset); | ||
| 486 | if (status) { | ||
| 487 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to write to the device\n")); | ||
| 488 | return A_ERROR; | ||
| 489 | } | ||
| 490 | |||
| 491 | AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI Read SOC Register: Exit\n")); | ||
| 492 | return 0; | ||
| 493 | } | ||
| 494 | |||
| 495 | int | ||
| 496 | BMIrompatchInstall(struct hif_device *device, | ||
| 497 | u32 ROM_addr, | ||
| 498 | u32 RAM_addr, | ||
| 499 | u32 nbytes, | ||
| 500 | u32 do_activate, | ||
| 501 | u32 *rompatch_id) | ||
| 502 | { | ||
| 503 | u32 cid; | ||
| 504 | int status; | ||
| 505 | u32 offset; | ||
| 506 | |||
| 507 | A_ASSERT(BMI_COMMAND_FITS(sizeof(cid) + sizeof(ROM_addr) + sizeof(RAM_addr) + | ||
| 508 | sizeof(nbytes) + sizeof(do_activate))); | ||
| 509 | memset(pBMICmdBuf, 0, sizeof(cid) + sizeof(ROM_addr) + sizeof(RAM_addr) + | ||
| 510 | sizeof(nbytes) + sizeof(do_activate)); | ||
| 511 | |||
| 512 | if (bmiDone) { | ||
| 513 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Command disallowed\n")); | ||
| 514 | return A_ERROR; | ||
| 515 | } | ||
| 516 | |||
| 517 | AR_DEBUG_PRINTF(ATH_DEBUG_BMI, | ||
| 518 | ("BMI rompatch Install: Enter (device: 0x%p, ROMaddr: 0x%x, RAMaddr: 0x%x length: %d activate: %d)\n", | ||
| 519 | device, ROM_addr, RAM_addr, nbytes, do_activate)); | ||
| 520 | |||
| 521 | cid = BMI_ROMPATCH_INSTALL; | ||
| 522 | |||
| 523 | offset = 0; | ||
| 524 | memcpy(&(pBMICmdBuf[offset]), &cid, sizeof(cid)); | ||
| 525 | offset += sizeof(cid); | ||
| 526 | memcpy(&(pBMICmdBuf[offset]), &ROM_addr, sizeof(ROM_addr)); | ||
| 527 | offset += sizeof(ROM_addr); | ||
| 528 | memcpy(&(pBMICmdBuf[offset]), &RAM_addr, sizeof(RAM_addr)); | ||
| 529 | offset += sizeof(RAM_addr); | ||
| 530 | memcpy(&(pBMICmdBuf[offset]), &nbytes, sizeof(nbytes)); | ||
| 531 | offset += sizeof(nbytes); | ||
| 532 | memcpy(&(pBMICmdBuf[offset]), &do_activate, sizeof(do_activate)); | ||
| 533 | offset += sizeof(do_activate); | ||
| 534 | status = bmiBufferSend(device, pBMICmdBuf, offset); | ||
| 535 | if (status) { | ||
| 536 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to write to the device\n")); | ||
| 537 | return A_ERROR; | ||
| 538 | } | ||
| 539 | |||
| 540 | status = bmiBufferReceive(device, pBMICmdBuf, sizeof(*rompatch_id), true); | ||
| 541 | if (status) { | ||
| 542 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to read from the device\n")); | ||
| 543 | return A_ERROR; | ||
| 544 | } | ||
| 545 | memcpy(rompatch_id, pBMICmdBuf, sizeof(*rompatch_id)); | ||
| 546 | |||
| 547 | AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI rompatch Install: (rompatch_id=%d)\n", *rompatch_id)); | ||
| 548 | return 0; | ||
| 549 | } | ||
| 550 | |||
| 551 | int | ||
| 552 | BMIrompatchUninstall(struct hif_device *device, | ||
| 553 | u32 rompatch_id) | ||
| 554 | { | ||
| 555 | u32 cid; | ||
| 556 | int status; | ||
| 557 | u32 offset; | ||
| 558 | |||
| 559 | A_ASSERT(BMI_COMMAND_FITS(sizeof(cid) + sizeof(rompatch_id))); | ||
| 560 | memset (pBMICmdBuf, 0, sizeof(cid) + sizeof(rompatch_id)); | ||
| 561 | |||
| 562 | if (bmiDone) { | ||
| 563 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Command disallowed\n")); | ||
| 564 | return A_ERROR; | ||
| 565 | } | ||
| 566 | |||
| 567 | AR_DEBUG_PRINTF(ATH_DEBUG_BMI, | ||
| 568 | ("BMI rompatch Uninstall: Enter (device: 0x%p, rompatch_id: %d)\n", | ||
| 569 | device, rompatch_id)); | ||
| 570 | |||
| 571 | cid = BMI_ROMPATCH_UNINSTALL; | ||
| 572 | |||
| 573 | offset = 0; | ||
| 574 | memcpy(&(pBMICmdBuf[offset]), &cid, sizeof(cid)); | ||
| 575 | offset += sizeof(cid); | ||
| 576 | memcpy(&(pBMICmdBuf[offset]), &rompatch_id, sizeof(rompatch_id)); | ||
| 577 | offset += sizeof(rompatch_id); | ||
| 578 | status = bmiBufferSend(device, pBMICmdBuf, offset); | ||
| 579 | if (status) { | ||
| 580 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to write to the device\n")); | ||
| 581 | return A_ERROR; | ||
| 582 | } | ||
| 583 | |||
| 584 | AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI rompatch UNinstall: (rompatch_id=0x%x)\n", rompatch_id)); | ||
| 585 | return 0; | ||
| 586 | } | ||
| 587 | |||
| 588 | static int | ||
| 589 | _BMIrompatchChangeActivation(struct hif_device *device, | ||
| 590 | u32 rompatch_count, | ||
| 591 | u32 *rompatch_list, | ||
| 592 | u32 do_activate) | ||
| 593 | { | ||
| 594 | u32 cid; | ||
| 595 | int status; | ||
| 596 | u32 offset; | ||
| 597 | u32 length; | ||
| 598 | |||
| 599 | A_ASSERT(BMI_COMMAND_FITS(BMI_DATASZ_MAX + sizeof(cid) + sizeof(rompatch_count))); | ||
| 600 | memset(pBMICmdBuf, 0, BMI_DATASZ_MAX + sizeof(cid) + sizeof(rompatch_count)); | ||
| 601 | |||
| 602 | if (bmiDone) { | ||
| 603 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Command disallowed\n")); | ||
| 604 | return A_ERROR; | ||
| 605 | } | ||
| 606 | |||
| 607 | AR_DEBUG_PRINTF(ATH_DEBUG_BMI, | ||
| 608 | ("BMI Change rompatch Activation: Enter (device: 0x%p, count: %d)\n", | ||
| 609 | device, rompatch_count)); | ||
| 610 | |||
| 611 | cid = do_activate ? BMI_ROMPATCH_ACTIVATE : BMI_ROMPATCH_DEACTIVATE; | ||
| 612 | |||
| 613 | offset = 0; | ||
| 614 | memcpy(&(pBMICmdBuf[offset]), &cid, sizeof(cid)); | ||
| 615 | offset += sizeof(cid); | ||
| 616 | memcpy(&(pBMICmdBuf[offset]), &rompatch_count, sizeof(rompatch_count)); | ||
| 617 | offset += sizeof(rompatch_count); | ||
| 618 | length = rompatch_count * sizeof(*rompatch_list); | ||
| 619 | memcpy(&(pBMICmdBuf[offset]), rompatch_list, length); | ||
| 620 | offset += length; | ||
| 621 | status = bmiBufferSend(device, pBMICmdBuf, offset); | ||
| 622 | if (status) { | ||
| 623 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to write to the device\n")); | ||
| 624 | return A_ERROR; | ||
| 625 | } | ||
| 626 | |||
| 627 | AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI Change rompatch Activation: Exit\n")); | ||
| 628 | |||
| 629 | return 0; | ||
| 630 | } | ||
| 631 | |||
| 632 | int | ||
| 633 | BMIrompatchActivate(struct hif_device *device, | ||
| 634 | u32 rompatch_count, | ||
| 635 | u32 *rompatch_list) | ||
| 636 | { | ||
| 637 | return _BMIrompatchChangeActivation(device, rompatch_count, rompatch_list, 1); | ||
| 638 | } | ||
| 639 | |||
| 640 | int | ||
| 641 | BMIrompatchDeactivate(struct hif_device *device, | ||
| 642 | u32 rompatch_count, | ||
| 643 | u32 *rompatch_list) | ||
| 644 | { | ||
| 645 | return _BMIrompatchChangeActivation(device, rompatch_count, rompatch_list, 0); | ||
| 646 | } | ||
| 647 | |||
| 648 | int | ||
| 649 | BMILZData(struct hif_device *device, | ||
| 650 | u8 *buffer, | ||
| 651 | u32 length) | ||
| 652 | { | ||
| 653 | u32 cid; | ||
| 654 | int status; | ||
| 655 | u32 offset; | ||
| 656 | u32 remaining, txlen; | ||
| 657 | const u32 header = sizeof(cid) + sizeof(length); | ||
| 658 | |||
| 659 | A_ASSERT(BMI_COMMAND_FITS(BMI_DATASZ_MAX+header)); | ||
| 660 | memset (pBMICmdBuf, 0, BMI_DATASZ_MAX+header); | ||
| 661 | |||
| 662 | if (bmiDone) { | ||
| 663 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Command disallowed\n")); | ||
| 664 | return A_ERROR; | ||
| 665 | } | ||
| 666 | |||
| 667 | AR_DEBUG_PRINTF(ATH_DEBUG_BMI, | ||
| 668 | ("BMI Send LZ Data: Enter (device: 0x%p, length: %d)\n", | ||
| 669 | device, length)); | ||
| 670 | |||
| 671 | cid = BMI_LZ_DATA; | ||
| 672 | |||
| 673 | remaining = length; | ||
| 674 | while (remaining) | ||
| 675 | { | ||
| 676 | txlen = (remaining < (BMI_DATASZ_MAX - header)) ? | ||
| 677 | remaining : (BMI_DATASZ_MAX - header); | ||
| 678 | offset = 0; | ||
| 679 | memcpy(&(pBMICmdBuf[offset]), &cid, sizeof(cid)); | ||
| 680 | offset += sizeof(cid); | ||
| 681 | memcpy(&(pBMICmdBuf[offset]), &txlen, sizeof(txlen)); | ||
| 682 | offset += sizeof(txlen); | ||
| 683 | memcpy(&(pBMICmdBuf[offset]), &buffer[length - remaining], txlen); | ||
| 684 | offset += txlen; | ||
| 685 | status = bmiBufferSend(device, pBMICmdBuf, offset); | ||
| 686 | if (status) { | ||
| 687 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to write to the device\n")); | ||
| 688 | return A_ERROR; | ||
| 689 | } | ||
| 690 | remaining -= txlen; | ||
| 691 | } | ||
| 692 | |||
| 693 | AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI LZ Data: Exit\n")); | ||
| 694 | |||
| 695 | return 0; | ||
| 696 | } | ||
| 697 | |||
| 698 | int | ||
| 699 | BMILZStreamStart(struct hif_device *device, | ||
| 700 | u32 address) | ||
| 701 | { | ||
| 702 | u32 cid; | ||
| 703 | int status; | ||
| 704 | u32 offset; | ||
| 705 | |||
| 706 | A_ASSERT(BMI_COMMAND_FITS(sizeof(cid) + sizeof(address))); | ||
| 707 | memset (pBMICmdBuf, 0, sizeof(cid) + sizeof(address)); | ||
| 708 | |||
| 709 | if (bmiDone) { | ||
| 710 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Command disallowed\n")); | ||
| 711 | return A_ERROR; | ||
| 712 | } | ||
| 713 | |||
| 714 | AR_DEBUG_PRINTF(ATH_DEBUG_BMI, | ||
| 715 | ("BMI LZ Stream Start: Enter (device: 0x%p, address: 0x%x)\n", | ||
| 716 | device, address)); | ||
| 717 | |||
| 718 | cid = BMI_LZ_STREAM_START; | ||
| 719 | offset = 0; | ||
| 720 | memcpy(&(pBMICmdBuf[offset]), &cid, sizeof(cid)); | ||
| 721 | offset += sizeof(cid); | ||
| 722 | memcpy(&(pBMICmdBuf[offset]), &address, sizeof(address)); | ||
| 723 | offset += sizeof(address); | ||
| 724 | status = bmiBufferSend(device, pBMICmdBuf, offset); | ||
| 725 | if (status) { | ||
| 726 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to Start LZ Stream to the device\n")); | ||
| 727 | return A_ERROR; | ||
| 728 | } | ||
| 729 | |||
| 730 | AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI LZ Stream Start: Exit\n")); | ||
| 731 | |||
| 732 | return 0; | ||
| 733 | } | ||
| 734 | |||
| 735 | /* BMI Access routines */ | ||
| 736 | int | ||
| 737 | bmiBufferSend(struct hif_device *device, | ||
| 738 | u8 *buffer, | ||
| 739 | u32 length) | ||
| 740 | { | ||
| 741 | int status; | ||
| 742 | u32 timeout; | ||
| 743 | u32 address; | ||
| 744 | u32 mboxAddress[HTC_MAILBOX_NUM_MAX]; | ||
| 745 | |||
| 746 | HIFConfigureDevice(device, HIF_DEVICE_GET_MBOX_ADDR, | ||
| 747 | &mboxAddress[0], sizeof(mboxAddress)); | ||
| 748 | |||
| 749 | *pBMICmdCredits = 0; | ||
| 750 | timeout = BMI_COMMUNICATION_TIMEOUT; | ||
| 751 | |||
| 752 | while(timeout-- && !(*pBMICmdCredits)) { | ||
| 753 | /* Read the counter register to get the command credits */ | ||
| 754 | address = COUNT_DEC_ADDRESS + (HTC_MAILBOX_NUM_MAX + ENDPOINT1) * 4; | ||
| 755 | /* hit the credit counter with a 4-byte access, the first byte read will hit the counter and cause | ||
| 756 | * a decrement, while the remaining 3 bytes has no effect. The rationale behind this is to | ||
| 757 | * make all HIF accesses 4-byte aligned */ | ||
| 758 | status = HIFReadWrite(device, address, (u8 *)pBMICmdCredits, 4, | ||
| 759 | HIF_RD_SYNC_BYTE_INC, NULL); | ||
| 760 | if (status) { | ||
| 761 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to decrement the command credit count register\n")); | ||
| 762 | return A_ERROR; | ||
| 763 | } | ||
| 764 | /* the counter is only 8=bits, ignore anything in the upper 3 bytes */ | ||
| 765 | (*pBMICmdCredits) &= 0xFF; | ||
| 766 | } | ||
| 767 | |||
| 768 | if (*pBMICmdCredits) { | ||
| 769 | address = mboxAddress[ENDPOINT1]; | ||
| 770 | status = HIFReadWrite(device, address, buffer, length, | ||
| 771 | HIF_WR_SYNC_BYTE_INC, NULL); | ||
| 772 | if (status) { | ||
| 773 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to send the BMI data to the device\n")); | ||
| 774 | return A_ERROR; | ||
| 775 | } | ||
| 776 | } else { | ||
| 777 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("BMI Communication timeout - bmiBufferSend\n")); | ||
| 778 | return A_ERROR; | ||
| 779 | } | ||
| 780 | |||
| 781 | return status; | ||
| 782 | } | ||
| 783 | |||
| 784 | int | ||
| 785 | bmiBufferReceive(struct hif_device *device, | ||
| 786 | u8 *buffer, | ||
| 787 | u32 length, | ||
| 788 | bool want_timeout) | ||
| 789 | { | ||
| 790 | int status; | ||
| 791 | u32 address; | ||
| 792 | u32 mboxAddress[HTC_MAILBOX_NUM_MAX]; | ||
| 793 | struct hif_pending_events_info hifPendingEvents; | ||
| 794 | static HIF_PENDING_EVENTS_FUNC getPendingEventsFunc = NULL; | ||
| 795 | |||
| 796 | if (!pendingEventsFuncCheck) { | ||
| 797 | /* see if the HIF layer implements an alternative function to get pending events | ||
| 798 | * do this only once! */ | ||
| 799 | HIFConfigureDevice(device, | ||
| 800 | HIF_DEVICE_GET_PENDING_EVENTS_FUNC, | ||
| 801 | &getPendingEventsFunc, | ||
| 802 | sizeof(getPendingEventsFunc)); | ||
| 803 | pendingEventsFuncCheck = true; | ||
| 804 | } | ||
| 805 | |||
| 806 | HIFConfigureDevice(device, HIF_DEVICE_GET_MBOX_ADDR, | ||
| 807 | &mboxAddress[0], sizeof(mboxAddress)); | ||
| 808 | |||
| 809 | /* | ||
| 810 | * During normal bootup, small reads may be required. | ||
| 811 | * Rather than issue an HIF Read and then wait as the Target | ||
| 812 | * adds successive bytes to the FIFO, we wait here until | ||
| 813 | * we know that response data is available. | ||
| 814 | * | ||
| 815 | * This allows us to cleanly timeout on an unexpected | ||
| 816 | * Target failure rather than risk problems at the HIF level. In | ||
| 817 | * particular, this avoids SDIO timeouts and possibly garbage | ||
| 818 | * data on some host controllers. And on an interconnect | ||
| 819 | * such as Compact Flash (as well as some SDIO masters) which | ||
| 820 | * does not provide any indication on data timeout, it avoids | ||
| 821 | * a potential hang or garbage response. | ||
| 822 | * | ||
| 823 | * Synchronization is more difficult for reads larger than the | ||
| 824 | * size of the MBOX FIFO (128B), because the Target is unable | ||
| 825 | * to push the 129th byte of data until AFTER the Host posts an | ||
| 826 | * HIF Read and removes some FIFO data. So for large reads the | ||
| 827 | * Host proceeds to post an HIF Read BEFORE all the data is | ||
| 828 | * actually available to read. Fortunately, large BMI reads do | ||
| 829 | * not occur in practice -- they're supported for debug/development. | ||
| 830 | * | ||
| 831 | * So Host/Target BMI synchronization is divided into these cases: | ||
| 832 | * CASE 1: length < 4 | ||
| 833 | * Should not happen | ||
| 834 | * | ||
| 835 | * CASE 2: 4 <= length <= 128 | ||
| 836 | * Wait for first 4 bytes to be in FIFO | ||
| 837 | * If CONSERVATIVE_BMI_READ is enabled, also wait for | ||
| 838 | * a BMI command credit, which indicates that the ENTIRE | ||
| 839 | * response is available in the the FIFO | ||
| 840 | * | ||
| 841 | * CASE 3: length > 128 | ||
| 842 | * Wait for the first 4 bytes to be in FIFO | ||
| 843 | * | ||
| 844 | * For most uses, a small timeout should be sufficient and we will | ||
| 845 | * usually see a response quickly; but there may be some unusual | ||
| 846 | * (debug) cases of BMI_EXECUTE where we want an larger timeout. | ||
| 847 | * For now, we use an unbounded busy loop while waiting for | ||
| 848 | * BMI_EXECUTE. | ||
| 849 | * | ||
| 850 | * If BMI_EXECUTE ever needs to support longer-latency execution, | ||
| 851 | * especially in production, this code needs to be enhanced to sleep | ||
| 852 | * and yield. Also note that BMI_COMMUNICATION_TIMEOUT is currently | ||
| 853 | * a function of Host processor speed. | ||
| 854 | */ | ||
| 855 | if (length >= 4) { /* NB: Currently, always true */ | ||
| 856 | /* | ||
| 857 | * NB: word_available is declared static for esoteric reasons | ||
| 858 | * having to do with protection on some OSes. | ||
| 859 | */ | ||
| 860 | static u32 word_available; | ||
| 861 | u32 timeout; | ||
| 862 | |||
| 863 | word_available = 0; | ||
| 864 | timeout = BMI_COMMUNICATION_TIMEOUT; | ||
| 865 | while((!want_timeout || timeout--) && !word_available) { | ||
| 866 | |||
| 867 | if (getPendingEventsFunc != NULL) { | ||
| 868 | status = getPendingEventsFunc(device, | ||
| 869 | &hifPendingEvents, | ||
| 870 | NULL); | ||
| 871 | if (status) { | ||
| 872 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("BMI: Failed to get pending events \n")); | ||
| 873 | break; | ||
| 874 | } | ||
| 875 | |||
| 876 | if (hifPendingEvents.AvailableRecvBytes >= sizeof(u32)) { | ||
| 877 | word_available = 1; | ||
| 878 | } | ||
| 879 | continue; | ||
| 880 | } | ||
| 881 | |||
| 882 | status = HIFReadWrite(device, RX_LOOKAHEAD_VALID_ADDRESS, (u8 *)&word_available, | ||
| 883 | sizeof(word_available), HIF_RD_SYNC_BYTE_INC, NULL); | ||
| 884 | if (status) { | ||
| 885 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to read RX_LOOKAHEAD_VALID register\n")); | ||
| 886 | return A_ERROR; | ||
| 887 | } | ||
| 888 | /* We did a 4-byte read to the same register; all we really want is one bit */ | ||
| 889 | word_available &= (1 << ENDPOINT1); | ||
| 890 | } | ||
| 891 | |||
| 892 | if (!word_available) { | ||
| 893 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("BMI Communication timeout - bmiBufferReceive FIFO empty\n")); | ||
| 894 | return A_ERROR; | ||
| 895 | } | ||
| 896 | } | ||
| 897 | |||
| 898 | #define CONSERVATIVE_BMI_READ 0 | ||
| 899 | #if CONSERVATIVE_BMI_READ | ||
| 900 | /* | ||
| 901 | * This is an extra-conservative CREDIT check. It guarantees | ||
| 902 | * that ALL data is available in the FIFO before we start to | ||
| 903 | * read from the interconnect. | ||
| 904 | * | ||
| 905 | * This credit check is useless when firmware chooses to | ||
| 906 | * allow multiple outstanding BMI Command Credits, since the next | ||
| 907 | * credit will already be present. To restrict the Target to one | ||
| 908 | * BMI Command Credit, see HI_OPTION_BMI_CRED_LIMIT. | ||
| 909 | * | ||
| 910 | * And for large reads (when HI_OPTION_BMI_CRED_LIMIT is set) | ||
| 911 | * we cannot wait for the next credit because the Target's FIFO | ||
| 912 | * will not hold the entire response. So we need the Host to | ||
| 913 | * start to empty the FIFO sooner. (And again, large reads are | ||
| 914 | * not used in practice; they are for debug/development only.) | ||
| 915 | * | ||
| 916 | * For a more conservative Host implementation (which would be | ||
| 917 | * safer for a Compact Flash interconnect): | ||
| 918 | * Set CONSERVATIVE_BMI_READ (above) to 1 | ||
| 919 | * Set HI_OPTION_BMI_CRED_LIMIT and | ||
| 920 | * reduce BMI_DATASZ_MAX to 32 or 64 | ||
| 921 | */ | ||
| 922 | if ((length > 4) && (length < 128)) { /* check against MBOX FIFO size */ | ||
| 923 | u32 timeout; | ||
| 924 | |||
| 925 | *pBMICmdCredits = 0; | ||
| 926 | timeout = BMI_COMMUNICATION_TIMEOUT; | ||
| 927 | while((!want_timeout || timeout--) && !(*pBMICmdCredits) { | ||
| 928 | /* Read the counter register to get the command credits */ | ||
| 929 | address = COUNT_ADDRESS + (HTC_MAILBOX_NUM_MAX + ENDPOINT1) * 1; | ||
| 930 | /* read the counter using a 4-byte read. Since the counter is NOT auto-decrementing, | ||
| 931 | * we can read this counter multiple times using a non-incrementing address mode. | ||
| 932 | * The rationale here is to make all HIF accesses a multiple of 4 bytes */ | ||
| 933 | status = HIFReadWrite(device, address, (u8 *)pBMICmdCredits, sizeof(*pBMICmdCredits), | ||
| 934 | HIF_RD_SYNC_BYTE_FIX, NULL); | ||
| 935 | if (status) { | ||
| 936 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to read the command credit count register\n")); | ||
| 937 | return A_ERROR; | ||
| 938 | } | ||
| 939 | /* we did a 4-byte read to the same count register so mask off upper bytes */ | ||
| 940 | (*pBMICmdCredits) &= 0xFF; | ||
| 941 | } | ||
| 942 | |||
| 943 | if (!(*pBMICmdCredits)) { | ||
| 944 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("BMI Communication timeout- bmiBufferReceive no credit\n")); | ||
| 945 | return A_ERROR; | ||
| 946 | } | ||
| 947 | } | ||
| 948 | #endif | ||
| 949 | |||
| 950 | address = mboxAddress[ENDPOINT1]; | ||
| 951 | status = HIFReadWrite(device, address, buffer, length, HIF_RD_SYNC_BYTE_INC, NULL); | ||
| 952 | if (status) { | ||
| 953 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to read the BMI data from the device\n")); | ||
| 954 | return A_ERROR; | ||
| 955 | } | ||
| 956 | |||
| 957 | return 0; | ||
| 958 | } | ||
| 959 | |||
| 960 | int | ||
| 961 | BMIFastDownload(struct hif_device *device, u32 address, u8 *buffer, u32 length) | ||
| 962 | { | ||
| 963 | int status = A_ERROR; | ||
| 964 | u32 lastWord = 0; | ||
| 965 | u32 lastWordOffset = length & ~0x3; | ||
| 966 | u32 unalignedBytes = length & 0x3; | ||
| 967 | |||
| 968 | status = BMILZStreamStart (device, address); | ||
| 969 | if (status) { | ||
| 970 | return A_ERROR; | ||
| 971 | } | ||
| 972 | |||
| 973 | if (unalignedBytes) { | ||
| 974 | /* copy the last word into a zero padded buffer */ | ||
| 975 | memcpy(&lastWord, &buffer[lastWordOffset], unalignedBytes); | ||
| 976 | } | ||
| 977 | |||
| 978 | status = BMILZData(device, buffer, lastWordOffset); | ||
| 979 | |||
| 980 | if (status) { | ||
| 981 | return A_ERROR; | ||
| 982 | } | ||
| 983 | |||
| 984 | if (unalignedBytes) { | ||
| 985 | status = BMILZData(device, (u8 *)&lastWord, 4); | ||
| 986 | } | ||
| 987 | |||
| 988 | if (!status) { | ||
| 989 | // | ||
| 990 | // Close compressed stream and open a new (fake) one. This serves mainly to flush Target caches. | ||
| 991 | // | ||
| 992 | status = BMILZStreamStart (device, 0x00); | ||
| 993 | if (status) { | ||
| 994 | return A_ERROR; | ||
| 995 | } | ||
| 996 | } | ||
| 997 | return status; | ||
| 998 | } | ||
| 999 | |||
| 1000 | int | ||
| 1001 | BMIRawWrite(struct hif_device *device, u8 *buffer, u32 length) | ||
| 1002 | { | ||
| 1003 | return bmiBufferSend(device, buffer, length); | ||
| 1004 | } | ||
| 1005 | |||
| 1006 | int | ||
| 1007 | BMIRawRead(struct hif_device *device, u8 *buffer, u32 length, bool want_timeout) | ||
| 1008 | { | ||
| 1009 | return bmiBufferReceive(device, buffer, length, want_timeout); | ||
| 1010 | } | ||
