Vipin Mehta | 30295c8 | 2010-09-01 12:06:33 -0700 | [diff] [blame] | 1 | //------------------------------------------------------------------------------ |
| 2 | // <copyright file="htc.c" company="Atheros"> |
| 3 | // Copyright (c) 2007-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 | // Author(s): ="Atheros" |
| 22 | //============================================================================== |
| 23 | #include "htc_internal.h" |
| 24 | |
| 25 | #ifdef ATH_DEBUG_MODULE |
| 26 | static ATH_DEBUG_MASK_DESCRIPTION g_HTCDebugDescription[] = { |
| 27 | { ATH_DEBUG_SEND , "Send"}, |
| 28 | { ATH_DEBUG_RECV , "Recv"}, |
| 29 | { ATH_DEBUG_SYNC , "Sync"}, |
| 30 | { ATH_DEBUG_DUMP , "Dump Data (RX or TX)"}, |
| 31 | { ATH_DEBUG_IRQ , "Interrupt Processing"} |
| 32 | }; |
| 33 | |
| 34 | ATH_DEBUG_INSTANTIATE_MODULE_VAR(htc, |
| 35 | "htc", |
| 36 | "Host Target Communications", |
| 37 | ATH_DEBUG_MASK_DEFAULTS, |
| 38 | ATH_DEBUG_DESCRIPTION_COUNT(g_HTCDebugDescription), |
| 39 | g_HTCDebugDescription); |
| 40 | |
| 41 | #endif |
| 42 | |
| 43 | static void HTCReportFailure(void *Context); |
| 44 | static void ResetEndpointStates(HTC_TARGET *target); |
| 45 | |
| 46 | void HTCFreeControlBuffer(HTC_TARGET *target, HTC_PACKET *pPacket, HTC_PACKET_QUEUE *pList) |
| 47 | { |
| 48 | LOCK_HTC(target); |
| 49 | HTC_PACKET_ENQUEUE(pList,pPacket); |
| 50 | UNLOCK_HTC(target); |
| 51 | } |
| 52 | |
| 53 | HTC_PACKET *HTCAllocControlBuffer(HTC_TARGET *target, HTC_PACKET_QUEUE *pList) |
| 54 | { |
| 55 | HTC_PACKET *pPacket; |
| 56 | |
| 57 | LOCK_HTC(target); |
| 58 | pPacket = HTC_PACKET_DEQUEUE(pList); |
| 59 | UNLOCK_HTC(target); |
| 60 | |
| 61 | return pPacket; |
| 62 | } |
| 63 | |
| 64 | /* cleanup the HTC instance */ |
| 65 | static void HTCCleanup(HTC_TARGET *target) |
| 66 | { |
Joe Perches | f68057e | 2011-02-02 14:05:55 -0800 | [diff] [blame] | 67 | s32 i; |
Vipin Mehta | 30295c8 | 2010-09-01 12:06:33 -0700 | [diff] [blame] | 68 | |
| 69 | DevCleanup(&target->Device); |
| 70 | |
| 71 | for (i = 0;i < NUM_CONTROL_BUFFERS;i++) { |
| 72 | if (target->HTCControlBuffers[i].Buffer) { |
| 73 | A_FREE(target->HTCControlBuffers[i].Buffer); |
| 74 | } |
| 75 | } |
| 76 | |
| 77 | if (A_IS_MUTEX_VALID(&target->HTCLock)) { |
| 78 | A_MUTEX_DELETE(&target->HTCLock); |
| 79 | } |
| 80 | |
| 81 | if (A_IS_MUTEX_VALID(&target->HTCRxLock)) { |
| 82 | A_MUTEX_DELETE(&target->HTCRxLock); |
| 83 | } |
| 84 | |
| 85 | if (A_IS_MUTEX_VALID(&target->HTCTxLock)) { |
| 86 | A_MUTEX_DELETE(&target->HTCTxLock); |
| 87 | } |
| 88 | /* free our instance */ |
| 89 | A_FREE(target); |
| 90 | } |
| 91 | |
| 92 | /* registered target arrival callback from the HIF layer */ |
| 93 | HTC_HANDLE HTCCreate(void *hif_handle, HTC_INIT_INFO *pInfo) |
| 94 | { |
| 95 | HTC_TARGET *target = NULL; |
Joe Perches | 1f4c34b | 2011-01-27 20:04:19 -0800 | [diff] [blame] | 96 | int status = A_OK; |
Vipin Mehta | 30295c8 | 2010-09-01 12:06:33 -0700 | [diff] [blame] | 97 | int i; |
Joe Perches | e1ce2a3 | 2011-02-02 14:05:51 -0800 | [diff] [blame] | 98 | u32 ctrl_bufsz; |
| 99 | u32 blocksizes[HTC_MAILBOX_NUM_MAX]; |
Vipin Mehta | 30295c8 | 2010-09-01 12:06:33 -0700 | [diff] [blame] | 100 | |
| 101 | AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HTCCreate - Enter\n")); |
| 102 | |
| 103 | A_REGISTER_MODULE_DEBUG_INFO(htc); |
| 104 | |
| 105 | do { |
| 106 | |
| 107 | /* allocate target memory */ |
| 108 | if ((target = (HTC_TARGET *)A_MALLOC(sizeof(HTC_TARGET))) == NULL) { |
| 109 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to allocate memory\n")); |
| 110 | status = A_ERROR; |
| 111 | break; |
| 112 | } |
| 113 | |
| 114 | A_MEMZERO(target, sizeof(HTC_TARGET)); |
| 115 | A_MUTEX_INIT(&target->HTCLock); |
| 116 | A_MUTEX_INIT(&target->HTCRxLock); |
| 117 | A_MUTEX_INIT(&target->HTCTxLock); |
| 118 | INIT_HTC_PACKET_QUEUE(&target->ControlBufferTXFreeList); |
| 119 | INIT_HTC_PACKET_QUEUE(&target->ControlBufferRXFreeList); |
| 120 | |
| 121 | /* give device layer the hif device handle */ |
| 122 | target->Device.HIFDevice = hif_handle; |
| 123 | /* give the device layer our context (for event processing) |
| 124 | * the device layer will register it's own context with HIF |
| 125 | * so we need to set this so we can fetch it in the target remove handler */ |
| 126 | target->Device.HTCContext = target; |
| 127 | /* set device layer target failure callback */ |
| 128 | target->Device.TargetFailureCallback = HTCReportFailure; |
| 129 | /* set device layer recv message pending callback */ |
| 130 | target->Device.MessagePendingCallback = HTCRecvMessagePendingHandler; |
| 131 | target->EpWaitingForBuffers = ENDPOINT_MAX; |
| 132 | |
| 133 | A_MEMCPY(&target->HTCInitInfo,pInfo,sizeof(HTC_INIT_INFO)); |
| 134 | |
| 135 | ResetEndpointStates(target); |
| 136 | |
| 137 | /* setup device layer */ |
| 138 | status = DevSetup(&target->Device); |
| 139 | |
Joe Perches | 391bb21 | 2011-01-27 20:04:21 -0800 | [diff] [blame] | 140 | if (status) { |
Vipin Mehta | 30295c8 | 2010-09-01 12:06:33 -0700 | [diff] [blame] | 141 | break; |
| 142 | } |
| 143 | |
| 144 | |
| 145 | /* get the block sizes */ |
| 146 | status = HIFConfigureDevice(hif_handle, HIF_DEVICE_GET_MBOX_BLOCK_SIZE, |
| 147 | blocksizes, sizeof(blocksizes)); |
Joe Perches | 391bb21 | 2011-01-27 20:04:21 -0800 | [diff] [blame] | 148 | if (status) { |
Vipin Mehta | 30295c8 | 2010-09-01 12:06:33 -0700 | [diff] [blame] | 149 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Failed to get block size info from HIF layer...\n")); |
| 150 | break; |
| 151 | } |
| 152 | |
| 153 | /* Set the control buffer size based on the block size */ |
| 154 | if (blocksizes[1] > HTC_MAX_CONTROL_MESSAGE_LENGTH) { |
| 155 | ctrl_bufsz = blocksizes[1] + HTC_HDR_LENGTH; |
| 156 | } else { |
| 157 | ctrl_bufsz = HTC_MAX_CONTROL_MESSAGE_LENGTH + HTC_HDR_LENGTH; |
| 158 | } |
| 159 | for (i = 0;i < NUM_CONTROL_BUFFERS;i++) { |
| 160 | target->HTCControlBuffers[i].Buffer = A_MALLOC(ctrl_bufsz); |
| 161 | if (target->HTCControlBuffers[i].Buffer == NULL) { |
| 162 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to allocate memory\n")); |
| 163 | status = A_ERROR; |
| 164 | break; |
| 165 | } |
| 166 | } |
| 167 | |
Joe Perches | 391bb21 | 2011-01-27 20:04:21 -0800 | [diff] [blame] | 168 | if (status) { |
Vipin Mehta | 30295c8 | 2010-09-01 12:06:33 -0700 | [diff] [blame] | 169 | break; |
| 170 | } |
| 171 | |
| 172 | /* carve up buffers/packets for control messages */ |
| 173 | for (i = 0; i < NUM_CONTROL_RX_BUFFERS; i++) { |
| 174 | HTC_PACKET *pControlPacket; |
| 175 | pControlPacket = &target->HTCControlBuffers[i].HtcPacket; |
| 176 | SET_HTC_PACKET_INFO_RX_REFILL(pControlPacket, |
| 177 | target, |
| 178 | target->HTCControlBuffers[i].Buffer, |
| 179 | ctrl_bufsz, |
| 180 | ENDPOINT_0); |
| 181 | HTC_FREE_CONTROL_RX(target,pControlPacket); |
| 182 | } |
| 183 | |
| 184 | for (;i < NUM_CONTROL_BUFFERS;i++) { |
| 185 | HTC_PACKET *pControlPacket; |
| 186 | pControlPacket = &target->HTCControlBuffers[i].HtcPacket; |
| 187 | INIT_HTC_PACKET_INFO(pControlPacket, |
| 188 | target->HTCControlBuffers[i].Buffer, |
| 189 | ctrl_bufsz); |
| 190 | HTC_FREE_CONTROL_TX(target,pControlPacket); |
| 191 | } |
| 192 | |
Joe Perches | 1071a13 | 2011-02-02 14:05:47 -0800 | [diff] [blame] | 193 | } while (false); |
Vipin Mehta | 30295c8 | 2010-09-01 12:06:33 -0700 | [diff] [blame] | 194 | |
Joe Perches | 391bb21 | 2011-01-27 20:04:21 -0800 | [diff] [blame] | 195 | if (status) { |
Vipin Mehta | 30295c8 | 2010-09-01 12:06:33 -0700 | [diff] [blame] | 196 | if (target != NULL) { |
| 197 | HTCCleanup(target); |
| 198 | target = NULL; |
| 199 | } |
| 200 | } |
| 201 | |
| 202 | AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HTCCreate - Exit\n")); |
| 203 | |
| 204 | return target; |
| 205 | } |
| 206 | |
| 207 | void HTCDestroy(HTC_HANDLE HTCHandle) |
| 208 | { |
| 209 | HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); |
| 210 | AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("+HTCDestroy .. Destroying :0x%lX \n",(unsigned long)target)); |
| 211 | HTCCleanup(target); |
| 212 | AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("-HTCDestroy \n")); |
| 213 | } |
| 214 | |
| 215 | /* get the low level HIF device for the caller , the caller may wish to do low level |
| 216 | * HIF requests */ |
| 217 | void *HTCGetHifDevice(HTC_HANDLE HTCHandle) |
| 218 | { |
| 219 | HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); |
| 220 | return target->Device.HIFDevice; |
| 221 | } |
| 222 | |
| 223 | /* wait for the target to arrive (sends HTC Ready message) |
| 224 | * this operation is fully synchronous and the message is polled for */ |
Joe Perches | 1f4c34b | 2011-01-27 20:04:19 -0800 | [diff] [blame] | 225 | int HTCWaitTarget(HTC_HANDLE HTCHandle) |
Vipin Mehta | 30295c8 | 2010-09-01 12:06:33 -0700 | [diff] [blame] | 226 | { |
| 227 | HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); |
Joe Perches | 1f4c34b | 2011-01-27 20:04:19 -0800 | [diff] [blame] | 228 | int status; |
Vipin Mehta | 30295c8 | 2010-09-01 12:06:33 -0700 | [diff] [blame] | 229 | HTC_PACKET *pPacket = NULL; |
| 230 | HTC_READY_EX_MSG *pRdyMsg; |
| 231 | |
| 232 | HTC_SERVICE_CONNECT_REQ connect; |
| 233 | HTC_SERVICE_CONNECT_RESP resp; |
| 234 | |
| 235 | AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HTCWaitTarget - Enter (target:0x%lX) \n", (unsigned long)target)); |
| 236 | |
| 237 | do { |
| 238 | |
| 239 | #ifdef MBOXHW_UNIT_TEST |
| 240 | |
| 241 | status = DoMboxHWTest(&target->Device); |
| 242 | |
Joe Perches | a1d4652 | 2011-02-02 14:05:56 -0800 | [diff] [blame^] | 243 | if (status) { |
Vipin Mehta | 30295c8 | 2010-09-01 12:06:33 -0700 | [diff] [blame] | 244 | break; |
| 245 | } |
| 246 | |
| 247 | #endif |
| 248 | |
| 249 | /* we should be getting 1 control message that the target is ready */ |
| 250 | status = HTCWaitforControlMessage(target, &pPacket); |
| 251 | |
Joe Perches | 391bb21 | 2011-01-27 20:04:21 -0800 | [diff] [blame] | 252 | if (status) { |
Vipin Mehta | 30295c8 | 2010-09-01 12:06:33 -0700 | [diff] [blame] | 253 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, (" Target Not Available!!\n")); |
| 254 | break; |
| 255 | } |
| 256 | |
| 257 | /* we controlled the buffer creation so it has to be properly aligned */ |
| 258 | pRdyMsg = (HTC_READY_EX_MSG *)pPacket->pBuffer; |
| 259 | |
| 260 | if ((pRdyMsg->Version2_0_Info.MessageID != HTC_MSG_READY_ID) || |
| 261 | (pPacket->ActualLength < sizeof(HTC_READY_MSG))) { |
| 262 | /* this message is not valid */ |
Joe Perches | 1071a13 | 2011-02-02 14:05:47 -0800 | [diff] [blame] | 263 | AR_DEBUG_ASSERT(false); |
Vipin Mehta | 30295c8 | 2010-09-01 12:06:33 -0700 | [diff] [blame] | 264 | status = A_EPROTO; |
| 265 | break; |
| 266 | } |
| 267 | |
| 268 | |
| 269 | if (pRdyMsg->Version2_0_Info.CreditCount == 0 || pRdyMsg->Version2_0_Info.CreditSize == 0) { |
| 270 | /* this message is not valid */ |
Joe Perches | 1071a13 | 2011-02-02 14:05:47 -0800 | [diff] [blame] | 271 | AR_DEBUG_ASSERT(false); |
Vipin Mehta | 30295c8 | 2010-09-01 12:06:33 -0700 | [diff] [blame] | 272 | status = A_EPROTO; |
| 273 | break; |
| 274 | } |
| 275 | |
| 276 | target->TargetCredits = pRdyMsg->Version2_0_Info.CreditCount; |
| 277 | target->TargetCreditSize = pRdyMsg->Version2_0_Info.CreditSize; |
| 278 | |
| 279 | AR_DEBUG_PRINTF(ATH_DEBUG_WARN, (" Target Ready: credits: %d credit size: %d\n", |
| 280 | target->TargetCredits, target->TargetCreditSize)); |
| 281 | |
| 282 | /* check if this is an extended ready message */ |
| 283 | if (pPacket->ActualLength >= sizeof(HTC_READY_EX_MSG)) { |
| 284 | /* this is an extended message */ |
| 285 | target->HTCTargetVersion = pRdyMsg->HTCVersion; |
| 286 | target->MaxMsgPerBundle = pRdyMsg->MaxMsgsPerHTCBundle; |
| 287 | } else { |
| 288 | /* legacy */ |
| 289 | target->HTCTargetVersion = HTC_VERSION_2P0; |
| 290 | target->MaxMsgPerBundle = 0; |
| 291 | } |
| 292 | |
| 293 | #ifdef HTC_FORCE_LEGACY_2P0 |
| 294 | /* for testing and comparison...*/ |
| 295 | target->HTCTargetVersion = HTC_VERSION_2P0; |
| 296 | target->MaxMsgPerBundle = 0; |
| 297 | #endif |
| 298 | |
| 299 | AR_DEBUG_PRINTF(ATH_DEBUG_TRC, |
| 300 | ("Using HTC Protocol Version : %s (%d)\n ", |
| 301 | (target->HTCTargetVersion == HTC_VERSION_2P0) ? "2.0" : ">= 2.1", |
| 302 | target->HTCTargetVersion)); |
| 303 | |
| 304 | if (target->MaxMsgPerBundle > 0) { |
| 305 | /* limit what HTC can handle */ |
| 306 | target->MaxMsgPerBundle = min(HTC_HOST_MAX_MSG_PER_BUNDLE, target->MaxMsgPerBundle); |
| 307 | /* target supports message bundling, setup device layer */ |
Joe Perches | 391bb21 | 2011-01-27 20:04:21 -0800 | [diff] [blame] | 308 | if (DevSetupMsgBundling(&target->Device,target->MaxMsgPerBundle)) { |
Vipin Mehta | 30295c8 | 2010-09-01 12:06:33 -0700 | [diff] [blame] | 309 | /* device layer can't handle bundling */ |
| 310 | target->MaxMsgPerBundle = 0; |
| 311 | } else { |
| 312 | /* limit bundle what the device layer can handle */ |
| 313 | target->MaxMsgPerBundle = min(DEV_GET_MAX_MSG_PER_BUNDLE(&target->Device), |
| 314 | target->MaxMsgPerBundle); |
| 315 | } |
| 316 | } |
| 317 | |
| 318 | if (target->MaxMsgPerBundle > 0) { |
| 319 | AR_DEBUG_PRINTF(ATH_DEBUG_TRC, |
| 320 | (" HTC bundling allowed. Max Msg Per HTC Bundle: %d\n", target->MaxMsgPerBundle)); |
| 321 | |
| 322 | if (DEV_GET_MAX_BUNDLE_SEND_LENGTH(&target->Device) != 0) { |
Joe Perches | 1071a13 | 2011-02-02 14:05:47 -0800 | [diff] [blame] | 323 | target->SendBundlingEnabled = true; |
Vipin Mehta | 30295c8 | 2010-09-01 12:06:33 -0700 | [diff] [blame] | 324 | } |
| 325 | if (DEV_GET_MAX_BUNDLE_RECV_LENGTH(&target->Device) != 0) { |
Joe Perches | 1071a13 | 2011-02-02 14:05:47 -0800 | [diff] [blame] | 326 | target->RecvBundlingEnabled = true; |
Vipin Mehta | 30295c8 | 2010-09-01 12:06:33 -0700 | [diff] [blame] | 327 | } |
| 328 | |
| 329 | if (!DEV_IS_LEN_BLOCK_ALIGNED(&target->Device,target->TargetCreditSize)) { |
| 330 | AR_DEBUG_PRINTF(ATH_DEBUG_WARN, ("*** Credit size: %d is not block aligned! Disabling send bundling \n", |
| 331 | target->TargetCreditSize)); |
| 332 | /* disallow send bundling since the credit size is not aligned to a block size |
| 333 | * the I/O block padding will spill into the next credit buffer which is fatal */ |
Joe Perches | 1071a13 | 2011-02-02 14:05:47 -0800 | [diff] [blame] | 334 | target->SendBundlingEnabled = false; |
Vipin Mehta | 30295c8 | 2010-09-01 12:06:33 -0700 | [diff] [blame] | 335 | } |
| 336 | } |
| 337 | |
| 338 | /* setup our pseudo HTC control endpoint connection */ |
| 339 | A_MEMZERO(&connect,sizeof(connect)); |
| 340 | A_MEMZERO(&resp,sizeof(resp)); |
| 341 | connect.EpCallbacks.pContext = target; |
| 342 | connect.EpCallbacks.EpTxComplete = HTCControlTxComplete; |
| 343 | connect.EpCallbacks.EpRecv = HTCControlRecv; |
| 344 | connect.EpCallbacks.EpRecvRefill = NULL; /* not needed */ |
| 345 | connect.EpCallbacks.EpSendFull = NULL; /* not nedded */ |
| 346 | connect.MaxSendQueueDepth = NUM_CONTROL_BUFFERS; |
| 347 | connect.ServiceID = HTC_CTRL_RSVD_SVC; |
| 348 | |
| 349 | /* connect fake service */ |
| 350 | status = HTCConnectService((HTC_HANDLE)target, |
| 351 | &connect, |
| 352 | &resp); |
| 353 | |
Joe Perches | 391bb21 | 2011-01-27 20:04:21 -0800 | [diff] [blame] | 354 | if (!status) { |
Vipin Mehta | 30295c8 | 2010-09-01 12:06:33 -0700 | [diff] [blame] | 355 | break; |
| 356 | } |
| 357 | |
Joe Perches | 1071a13 | 2011-02-02 14:05:47 -0800 | [diff] [blame] | 358 | } while (false); |
Vipin Mehta | 30295c8 | 2010-09-01 12:06:33 -0700 | [diff] [blame] | 359 | |
| 360 | if (pPacket != NULL) { |
| 361 | HTC_FREE_CONTROL_RX(target,pPacket); |
| 362 | } |
| 363 | |
| 364 | AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HTCWaitTarget - Exit\n")); |
| 365 | |
| 366 | return status; |
| 367 | } |
| 368 | |
| 369 | |
| 370 | |
| 371 | /* Start HTC, enable interrupts and let the target know host has finished setup */ |
Joe Perches | 1f4c34b | 2011-01-27 20:04:19 -0800 | [diff] [blame] | 372 | int HTCStart(HTC_HANDLE HTCHandle) |
Vipin Mehta | 30295c8 | 2010-09-01 12:06:33 -0700 | [diff] [blame] | 373 | { |
| 374 | HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); |
| 375 | HTC_PACKET *pPacket; |
Joe Perches | 1f4c34b | 2011-01-27 20:04:19 -0800 | [diff] [blame] | 376 | int status; |
Vipin Mehta | 30295c8 | 2010-09-01 12:06:33 -0700 | [diff] [blame] | 377 | |
| 378 | AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HTCStart Enter\n")); |
| 379 | |
| 380 | /* make sure interrupts are disabled at the chip level, |
| 381 | * this function can be called again from a reboot of the target without shutting down HTC */ |
| 382 | DevDisableInterrupts(&target->Device); |
| 383 | /* make sure state is cleared again */ |
| 384 | target->OpStateFlags = 0; |
| 385 | target->RecvStateFlags = 0; |
| 386 | |
| 387 | /* now that we are starting, push control receive buffers into the |
| 388 | * HTC control endpoint */ |
| 389 | |
| 390 | while (1) { |
| 391 | pPacket = HTC_ALLOC_CONTROL_RX(target); |
| 392 | if (NULL == pPacket) { |
| 393 | break; |
| 394 | } |
| 395 | HTCAddReceivePkt((HTC_HANDLE)target,pPacket); |
| 396 | } |
| 397 | |
| 398 | do { |
| 399 | |
| 400 | AR_DEBUG_ASSERT(target->InitCredits != NULL); |
| 401 | AR_DEBUG_ASSERT(target->EpCreditDistributionListHead != NULL); |
| 402 | AR_DEBUG_ASSERT(target->EpCreditDistributionListHead->pNext != NULL); |
| 403 | |
| 404 | /* call init credits callback to do the distribution , |
| 405 | * NOTE: the first entry in the distribution list is ENDPOINT_0, so |
| 406 | * we pass the start of the list after this one. */ |
| 407 | target->InitCredits(target->pCredDistContext, |
| 408 | target->EpCreditDistributionListHead->pNext, |
| 409 | target->TargetCredits); |
| 410 | |
| 411 | #ifdef ATH_DEBUG_MODULE |
| 412 | |
| 413 | if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_TRC)) { |
| 414 | DumpCreditDistStates(target); |
| 415 | } |
| 416 | #endif |
| 417 | |
| 418 | /* the caller is done connecting to services, so we can indicate to the |
| 419 | * target that the setup phase is complete */ |
| 420 | status = HTCSendSetupComplete(target); |
| 421 | |
Joe Perches | 391bb21 | 2011-01-27 20:04:21 -0800 | [diff] [blame] | 422 | if (status) { |
Vipin Mehta | 30295c8 | 2010-09-01 12:06:33 -0700 | [diff] [blame] | 423 | break; |
| 424 | } |
| 425 | |
| 426 | /* unmask interrupts */ |
| 427 | status = DevUnmaskInterrupts(&target->Device); |
| 428 | |
Joe Perches | 391bb21 | 2011-01-27 20:04:21 -0800 | [diff] [blame] | 429 | if (status) { |
Vipin Mehta | 30295c8 | 2010-09-01 12:06:33 -0700 | [diff] [blame] | 430 | HTCStop(target); |
| 431 | } |
| 432 | |
Joe Perches | 1071a13 | 2011-02-02 14:05:47 -0800 | [diff] [blame] | 433 | } while (false); |
Vipin Mehta | 30295c8 | 2010-09-01 12:06:33 -0700 | [diff] [blame] | 434 | |
| 435 | AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HTCStart Exit\n")); |
| 436 | return status; |
| 437 | } |
| 438 | |
| 439 | static void ResetEndpointStates(HTC_TARGET *target) |
| 440 | { |
| 441 | HTC_ENDPOINT *pEndpoint; |
| 442 | int i; |
| 443 | |
| 444 | for (i = ENDPOINT_0; i < ENDPOINT_MAX; i++) { |
| 445 | pEndpoint = &target->EndPoint[i]; |
| 446 | |
| 447 | A_MEMZERO(&pEndpoint->CreditDist, sizeof(pEndpoint->CreditDist)); |
| 448 | pEndpoint->ServiceID = 0; |
| 449 | pEndpoint->MaxMsgLength = 0; |
| 450 | pEndpoint->MaxTxQueueDepth = 0; |
| 451 | #ifdef HTC_EP_STAT_PROFILING |
| 452 | A_MEMZERO(&pEndpoint->EndPointStats,sizeof(pEndpoint->EndPointStats)); |
| 453 | #endif |
| 454 | INIT_HTC_PACKET_QUEUE(&pEndpoint->RxBuffers); |
| 455 | INIT_HTC_PACKET_QUEUE(&pEndpoint->TxQueue); |
| 456 | INIT_HTC_PACKET_QUEUE(&pEndpoint->RecvIndicationQueue); |
| 457 | pEndpoint->target = target; |
| 458 | } |
| 459 | /* reset distribution list */ |
| 460 | target->EpCreditDistributionListHead = NULL; |
| 461 | } |
| 462 | |
| 463 | /* stop HTC communications, i.e. stop interrupt reception, and flush all queued buffers */ |
| 464 | void HTCStop(HTC_HANDLE HTCHandle) |
| 465 | { |
| 466 | HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); |
| 467 | AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("+HTCStop \n")); |
| 468 | |
| 469 | LOCK_HTC(target); |
| 470 | /* mark that we are shutting down .. */ |
| 471 | target->OpStateFlags |= HTC_OP_STATE_STOPPING; |
| 472 | UNLOCK_HTC(target); |
| 473 | |
| 474 | /* Masking interrupts is a synchronous operation, when this function returns |
| 475 | * all pending HIF I/O has completed, we can safely flush the queues */ |
| 476 | DevMaskInterrupts(&target->Device); |
| 477 | |
| 478 | #ifdef THREAD_X |
| 479 | // |
| 480 | // Is this delay required |
| 481 | // |
| 482 | A_MDELAY(200); // wait for IRQ process done |
| 483 | #endif |
| 484 | /* flush all send packets */ |
| 485 | HTCFlushSendPkts(target); |
| 486 | /* flush all recv buffers */ |
| 487 | HTCFlushRecvBuffers(target); |
| 488 | |
| 489 | ResetEndpointStates(target); |
| 490 | |
| 491 | AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("-HTCStop \n")); |
| 492 | } |
| 493 | |
| 494 | #ifdef ATH_DEBUG_MODULE |
| 495 | void HTCDumpCreditStates(HTC_HANDLE HTCHandle) |
| 496 | { |
| 497 | HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); |
| 498 | |
| 499 | LOCK_HTC_TX(target); |
| 500 | |
| 501 | DumpCreditDistStates(target); |
| 502 | |
| 503 | UNLOCK_HTC_TX(target); |
| 504 | |
| 505 | DumpAR6KDevState(&target->Device); |
| 506 | } |
| 507 | #endif |
| 508 | /* report a target failure from the device, this is a callback from the device layer |
| 509 | * which uses a mechanism to report errors from the target (i.e. special interrupts) */ |
| 510 | static void HTCReportFailure(void *Context) |
| 511 | { |
| 512 | HTC_TARGET *target = (HTC_TARGET *)Context; |
| 513 | |
Joe Perches | 1071a13 | 2011-02-02 14:05:47 -0800 | [diff] [blame] | 514 | target->TargetFailure = true; |
Vipin Mehta | 30295c8 | 2010-09-01 12:06:33 -0700 | [diff] [blame] | 515 | |
| 516 | if (target->HTCInitInfo.TargetFailure != NULL) { |
| 517 | /* let upper layer know, it needs to call HTCStop() */ |
| 518 | target->HTCInitInfo.TargetFailure(target->HTCInitInfo.pContext, A_ERROR); |
| 519 | } |
| 520 | } |
| 521 | |
Joe Perches | 1071a13 | 2011-02-02 14:05:47 -0800 | [diff] [blame] | 522 | bool HTCGetEndpointStatistics(HTC_HANDLE HTCHandle, |
Vipin Mehta | 30295c8 | 2010-09-01 12:06:33 -0700 | [diff] [blame] | 523 | HTC_ENDPOINT_ID Endpoint, |
| 524 | HTC_ENDPOINT_STAT_ACTION Action, |
| 525 | HTC_ENDPOINT_STATS *pStats) |
| 526 | { |
| 527 | |
| 528 | #ifdef HTC_EP_STAT_PROFILING |
| 529 | HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); |
Joe Perches | 1071a13 | 2011-02-02 14:05:47 -0800 | [diff] [blame] | 530 | bool clearStats = false; |
| 531 | bool sample = false; |
Vipin Mehta | 30295c8 | 2010-09-01 12:06:33 -0700 | [diff] [blame] | 532 | |
| 533 | switch (Action) { |
| 534 | case HTC_EP_STAT_SAMPLE : |
Joe Perches | 1071a13 | 2011-02-02 14:05:47 -0800 | [diff] [blame] | 535 | sample = true; |
Vipin Mehta | 30295c8 | 2010-09-01 12:06:33 -0700 | [diff] [blame] | 536 | break; |
| 537 | case HTC_EP_STAT_SAMPLE_AND_CLEAR : |
Joe Perches | 1071a13 | 2011-02-02 14:05:47 -0800 | [diff] [blame] | 538 | sample = true; |
| 539 | clearStats = true; |
Vipin Mehta | 30295c8 | 2010-09-01 12:06:33 -0700 | [diff] [blame] | 540 | break; |
| 541 | case HTC_EP_STAT_CLEAR : |
Joe Perches | 1071a13 | 2011-02-02 14:05:47 -0800 | [diff] [blame] | 542 | clearStats = true; |
Vipin Mehta | 30295c8 | 2010-09-01 12:06:33 -0700 | [diff] [blame] | 543 | break; |
| 544 | default: |
| 545 | break; |
| 546 | } |
| 547 | |
| 548 | A_ASSERT(Endpoint < ENDPOINT_MAX); |
| 549 | |
| 550 | /* lock out TX and RX while we sample and/or clear */ |
| 551 | LOCK_HTC_TX(target); |
| 552 | LOCK_HTC_RX(target); |
| 553 | |
| 554 | if (sample) { |
| 555 | A_ASSERT(pStats != NULL); |
| 556 | /* return the stats to the caller */ |
| 557 | A_MEMCPY(pStats, &target->EndPoint[Endpoint].EndPointStats, sizeof(HTC_ENDPOINT_STATS)); |
| 558 | } |
| 559 | |
| 560 | if (clearStats) { |
| 561 | /* reset stats */ |
| 562 | A_MEMZERO(&target->EndPoint[Endpoint].EndPointStats, sizeof(HTC_ENDPOINT_STATS)); |
| 563 | } |
| 564 | |
| 565 | UNLOCK_HTC_RX(target); |
| 566 | UNLOCK_HTC_TX(target); |
| 567 | |
Joe Perches | 1071a13 | 2011-02-02 14:05:47 -0800 | [diff] [blame] | 568 | return true; |
Vipin Mehta | 30295c8 | 2010-09-01 12:06:33 -0700 | [diff] [blame] | 569 | #else |
Joe Perches | 1071a13 | 2011-02-02 14:05:47 -0800 | [diff] [blame] | 570 | return false; |
Vipin Mehta | 30295c8 | 2010-09-01 12:06:33 -0700 | [diff] [blame] | 571 | #endif |
| 572 | } |
| 573 | |
| 574 | AR6K_DEVICE *HTCGetAR6KDevice(void *HTCHandle) |
| 575 | { |
| 576 | HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); |
| 577 | return &target->Device; |
| 578 | } |
| 579 | |