1/* 2 * 3 * Copyright (c) 2007 Atheros Communications Inc. 4 * All rights reserved. 5 * 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License version 2 as 9 * published by the Free Software Foundation; 10 * 11 * Software distributed under the License is distributed on an "AS 12 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or 13 * implied. See the License for the specific language governing 14 * rights and limitations under the License. 15 * 16 * 17 * 18 */ 19 20#include "htc_internal.h" 21 22 23static HTC_INIT_INFO HTCInitInfo = {NULL,NULL,NULL}; 24static A_BOOL HTCInitialized = FALSE; 25 26static A_STATUS HTCTargetInsertedHandler(void *hif_handle); 27static A_STATUS HTCTargetRemovedHandler(void *handle, A_STATUS status); 28static void HTCReportFailure(void *Context); 29 30/* Initializes the HTC layer */ 31A_STATUS HTCInit(HTC_INIT_INFO *pInitInfo) 32{ 33 HTC_CALLBACKS htcCallbacks; 34 35 AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HTCInit: Enter\n")); 36 if (HTCInitialized) { 37 AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HTCInit: Exit\n")); 38 return A_OK; 39 } 40 41 A_MEMCPY(&HTCInitInfo,pInitInfo,sizeof(HTC_INIT_INFO)); 42 43 A_MEMZERO(&htcCallbacks, sizeof(HTC_CALLBACKS)); 44 45 /* setup HIF layer callbacks */ 46 htcCallbacks.deviceInsertedHandler = HTCTargetInsertedHandler; 47 htcCallbacks.deviceRemovedHandler = HTCTargetRemovedHandler; 48 /* the device layer handles these */ 49 htcCallbacks.rwCompletionHandler = DevRWCompletionHandler; 50 htcCallbacks.dsrHandler = DevDsrHandler; 51 HIFInit(&htcCallbacks); 52 HTCInitialized = TRUE; 53 54 AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HTCInit: Exit\n")); 55 return A_OK; 56} 57 58void HTCFreeControlBuffer(HTC_TARGET *target, HTC_PACKET *pPacket, HTC_PACKET_QUEUE *pList) 59{ 60 LOCK_HTC(target); 61 HTC_PACKET_ENQUEUE(pList,pPacket); 62 UNLOCK_HTC(target); 63} 64 65HTC_PACKET *HTCAllocControlBuffer(HTC_TARGET *target, HTC_PACKET_QUEUE *pList) 66{ 67 HTC_PACKET *pPacket; 68 69 LOCK_HTC(target); 70 pPacket = HTC_PACKET_DEQUEUE(pList); 71 UNLOCK_HTC(target); 72 73 return pPacket; 74} 75 76/* cleanup the HTC instance */ 77static void HTCCleanup(HTC_TARGET *target) 78{ 79 if (A_IS_MUTEX_VALID(&target->HTCLock)) { 80 A_MUTEX_DELETE(&target->HTCLock); 81 } 82 83 if (A_IS_MUTEX_VALID(&target->HTCRxLock)) { 84 A_MUTEX_DELETE(&target->HTCRxLock); 85 } 86 87 if (A_IS_MUTEX_VALID(&target->HTCTxLock)) { 88 A_MUTEX_DELETE(&target->HTCTxLock); 89 } 90 /* free our instance */ 91 A_FREE(target); 92} 93 94/* registered target arrival callback from the HIF layer */ 95static A_STATUS HTCTargetInsertedHandler(void *hif_handle) 96{ 97 HTC_TARGET *target = NULL; 98 A_STATUS status; 99 int i; 100 101 AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("htcTargetInserted - Enter\n")); 102 103 do { 104 105 /* allocate target memory */ 106 if ((target = (HTC_TARGET *)A_MALLOC(sizeof(HTC_TARGET))) == NULL) { 107 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to allocate memory\n")); 108 status = A_ERROR; 109 break; 110 } 111 112 A_MEMZERO(target, sizeof(HTC_TARGET)); 113 A_MUTEX_INIT(&target->HTCLock); 114 A_MUTEX_INIT(&target->HTCRxLock); 115 A_MUTEX_INIT(&target->HTCTxLock); 116 INIT_HTC_PACKET_QUEUE(&target->ControlBufferTXFreeList); 117 INIT_HTC_PACKET_QUEUE(&target->ControlBufferRXFreeList); 118 119 /* give device layer the hif device handle */ 120 target->Device.HIFDevice = hif_handle; 121 /* give the device layer our context (for event processing) 122 * the device layer will register it's own context with HIF 123 * so we need to set this so we can fetch it in the target remove handler */ 124 target->Device.HTCContext = target; 125 /* set device layer target failure callback */ 126 target->Device.TargetFailureCallback = HTCReportFailure; 127 /* set device layer recv message pending callback */ 128 target->Device.MessagePendingCallback = HTCRecvMessagePendingHandler; 129 target->EpWaitingForBuffers = ENDPOINT_MAX; 130 131 /* setup device layer */ 132 status = DevSetup(&target->Device); 133 134 if (A_FAILED(status)) { 135 break; 136 } 137 138 /* carve up buffers/packets for control messages */ 139 for (i = 0; i < NUM_CONTROL_RX_BUFFERS; i++) { 140 HTC_PACKET *pControlPacket; 141 pControlPacket = &target->HTCControlBuffers[i].HtcPacket; 142 SET_HTC_PACKET_INFO_RX_REFILL(pControlPacket, 143 target, 144 target->HTCControlBuffers[i].Buffer, 145 HTC_CONTROL_BUFFER_SIZE, 146 ENDPOINT_0); 147 HTC_FREE_CONTROL_RX(target,pControlPacket); 148 } 149 150 for (;i < NUM_CONTROL_BUFFERS;i++) { 151 HTC_PACKET *pControlPacket; 152 pControlPacket = &target->HTCControlBuffers[i].HtcPacket; 153 INIT_HTC_PACKET_INFO(pControlPacket, 154 target->HTCControlBuffers[i].Buffer, 155 HTC_CONTROL_BUFFER_SIZE); 156 HTC_FREE_CONTROL_TX(target,pControlPacket); 157 } 158 159 } while (FALSE); 160 161 if (A_SUCCESS(status)) { 162 AR_DEBUG_PRINTF(ATH_DEBUG_TRC, (" calling AddInstance callback \n")); 163 /* announce ourselves */ 164 HTCInitInfo.AddInstance((HTC_HANDLE)target); 165 } else { 166 if (target != NULL) { 167 HTCCleanup(target); 168 } 169 } 170 171 AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("htcTargetInserted - Exit\n")); 172 173 return status; 174} 175 176/* registered removal callback from the HIF layer */ 177static A_STATUS HTCTargetRemovedHandler(void *handle, A_STATUS status) 178{ 179 HTC_TARGET *target; 180 181 AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("+HTCTargetRemovedHandler handle:0x%X \n",(A_UINT32)handle)); 182 183 if (NULL == handle) { 184 /* this could be NULL in the event that target initialization failed */ 185 return A_OK; 186 } 187 188 target = ((AR6K_DEVICE *)handle)->HTCContext; 189 190 AR_DEBUG_PRINTF(ATH_DEBUG_TRC, (" removing target:0x%X instance:0x%X ... \n", 191 (A_UINT32)target, (A_UINT32)target->pInstanceContext)); 192 193 if (target->pInstanceContext != NULL) { 194 /* let upper layer know, it needs to call HTCStop() */ 195 HTCInitInfo.DeleteInstance(target->pInstanceContext); 196 } 197 198 HIFShutDownDevice(target->Device.HIFDevice); 199 200 HTCCleanup(target); 201 AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("-HTCTargetRemovedHandler \n")); 202 return A_OK; 203} 204 205/* get the low level HIF device for the caller , the caller may wish to do low level 206 * HIF requests */ 207void *HTCGetHifDevice(HTC_HANDLE HTCHandle) 208{ 209 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); 210 return target->Device.HIFDevice; 211} 212 213/* set the instance block for this HTC handle, so that on removal, the blob can be 214 * returned to the caller */ 215void HTCSetInstance(HTC_HANDLE HTCHandle, void *Instance) 216{ 217 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); 218 219 target->pInstanceContext = Instance; 220} 221 222/* wait for the target to arrive (sends HTC Ready message) 223 * this operation is fully synchronous and the message is polled for */ 224A_STATUS HTCWaitTarget(HTC_HANDLE HTCHandle) 225{ 226 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); 227 A_STATUS status; 228 HTC_PACKET *pPacket = NULL; 229 HTC_READY_MSG *pRdyMsg; 230 HTC_SERVICE_CONNECT_REQ connect; 231 HTC_SERVICE_CONNECT_RESP resp; 232 233 AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HTCWaitTarget - Enter (target:0x%X) \n", (A_UINT32)target)); 234 235 do { 236 237#ifdef MBOXHW_UNIT_TEST 238 239 status = DoMboxHWTest(&target->Device); 240 241 if (status != A_OK) { 242 break; 243 } 244 245#endif 246 247 /* we should be getting 1 control message that the target is ready */ 248 status = HTCWaitforControlMessage(target, &pPacket); 249 250 if (A_FAILED(status)) { 251 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, (" Target Not Available!!\n")); 252 break; 253 } 254 255 /* we controlled the buffer creation so it has to be properly aligned */ 256 pRdyMsg = (HTC_READY_MSG *)pPacket->pBuffer; 257 258 if ((pRdyMsg->MessageID != HTC_MSG_READY_ID) || 259 (pPacket->ActualLength < sizeof(HTC_READY_MSG))) { 260 /* this message is not valid */ 261 AR_DEBUG_ASSERT(FALSE); 262 status = A_EPROTO; 263 break; 264 } 265 266 if (pRdyMsg->CreditCount == 0 || pRdyMsg->CreditSize == 0) { 267 /* this message is not valid */ 268 AR_DEBUG_ASSERT(FALSE); 269 status = A_EPROTO; 270 break; 271 } 272 273 target->TargetCredits = pRdyMsg->CreditCount; 274 target->TargetCreditSize = pRdyMsg->CreditSize; 275 276 AR_DEBUG_PRINTF(ATH_DEBUG_TRC, (" Target Ready: credits: %d credit size: %d\n", 277 target->TargetCredits, target->TargetCreditSize)); 278 279 /* setup our pseudo HTC control endpoint connection */ 280 A_MEMZERO(&connect,sizeof(connect)); 281 A_MEMZERO(&resp,sizeof(resp)); 282 connect.EpCallbacks.pContext = target; 283 connect.EpCallbacks.EpTxComplete = HTCControlTxComplete; 284 connect.EpCallbacks.EpRecv = HTCControlRecv; 285 connect.EpCallbacks.EpRecvRefill = NULL; /* not needed */ 286 connect.EpCallbacks.EpSendFull = NULL; /* not needed */ 287 connect.EpCallbacks.EpSendAvail = NULL; /* not needed */ 288 connect.MaxSendQueueDepth = NUM_CONTROL_BUFFERS; 289 connect.ServiceID = HTC_CTRL_RSVD_SVC; 290 291 /* connect fake service */ 292 status = HTCConnectService((HTC_HANDLE)target, 293 &connect, 294 &resp); 295 296 if (!A_FAILED(status)) { 297 break; 298 } 299 300 } while (FALSE); 301 302 if (pPacket != NULL) { 303 HTC_FREE_CONTROL_RX(target,pPacket); 304 } 305 306 AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HTCWaitTarget - Exit\n")); 307 308 return status; 309} 310 311 312 313/* Start HTC, enable interrupts and let the target know host has finished setup */ 314A_STATUS HTCStart(HTC_HANDLE HTCHandle) 315{ 316 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); 317 HTC_PACKET *pPacket; 318 A_STATUS status; 319 320 AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HTCStart Enter\n")); 321 322 /* now that we are starting, push control receive buffers into the 323 * HTC control endpoint */ 324 325 while (1) { 326 pPacket = HTC_ALLOC_CONTROL_RX(target); 327 if (NULL == pPacket) { 328 break; 329 } 330 HTCAddReceivePkt((HTC_HANDLE)target,pPacket); 331 } 332 333 do { 334 335 AR_DEBUG_ASSERT(target->InitCredits != NULL); 336 AR_DEBUG_ASSERT(target->EpCreditDistributionListHead != NULL); 337 AR_DEBUG_ASSERT(target->EpCreditDistributionListHead->pNext != NULL); 338 339 /* call init credits callback to do the distribution , 340 * NOTE: the first entry in the distribution list is ENDPOINT_0, so 341 * we pass the start of the list after this one. */ 342 target->InitCredits(target->pCredDistContext, 343 target->EpCreditDistributionListHead->pNext, 344 target->TargetCredits); 345 346 if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_TRC)) { 347 DumpCreditDistStates(target); 348 } 349 350 /* the caller is done connecting to services, so we can indicate to the 351 * target that the setup phase is complete */ 352 status = HTCSendSetupComplete(target); 353 354 if (A_FAILED(status)) { 355 break; 356 } 357 358 /* unmask interrupts */ 359 status = DevUnmaskInterrupts(&target->Device); 360 361 if (A_FAILED(status)) { 362 HTCStop(target); 363 } 364 365 } while (FALSE); 366 367 AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HTCStart Exit\n")); 368 return status; 369} 370 371 372/* stop HTC communications, i.e. stop interrupt reception, and flush all queued buffers */ 373void HTCStop(HTC_HANDLE HTCHandle) 374{ 375 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); 376 AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("+HTCStop \n")); 377 378 /* mark that we are shutting down .. */ 379 target->HTCStateFlags |= HTC_STATE_STOPPING; 380 381 /* Masking interrupts is a synchronous operation, when this function returns 382 * all pending HIF I/O has completed, we can safely flush the queues */ 383 DevMaskInterrupts(&target->Device); 384 385 /* flush all send packets */ 386 HTCFlushSendPkts(target); 387 /* flush all recv buffers */ 388 HTCFlushRecvBuffers(target); 389 390 AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("-HTCStop \n")); 391} 392 393/* undo what was done in HTCInit() */ 394void HTCShutDown(void) 395{ 396 AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("+HTCShutDown: \n")); 397 HTCInitialized = FALSE; 398 /* undo HTCInit */ 399 HIFShutDownDevice(NULL); 400 AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("-HTCShutDown: \n")); 401} 402 403void HTCDumpCreditStates(HTC_HANDLE HTCHandle) 404{ 405 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); 406 407 LOCK_HTC_TX(target); 408 409 DumpCreditDistStates(target); 410 411 UNLOCK_HTC_TX(target); 412} 413 414/* report a target failure from the device, this is a callback from the device layer 415 * which uses a mechanism to report errors from the target (i.e. special interrupts) */ 416static void HTCReportFailure(void *Context) 417{ 418 HTC_TARGET *target = (HTC_TARGET *)Context; 419 420 target->TargetFailure = TRUE; 421 422 if ((target->pInstanceContext != NULL) && (HTCInitInfo.TargetFailure != NULL)) { 423 /* let upper layer know, it needs to call HTCStop() */ 424 HTCInitInfo.TargetFailure(target->pInstanceContext, A_ERROR); 425 } 426} 427 428void DebugDumpBytes(A_UCHAR *buffer, A_UINT16 length, char *pDescription) 429{ 430 A_CHAR stream[60]; 431 A_UINT32 i; 432 A_UINT16 offset, count; 433 434 AR_DEBUG_PRINTF(ATH_DEBUG_ANY, ("<---------Dumping %d Bytes : %s ------>\n", length, pDescription)); 435 436 count = 0; 437 offset = 0; 438 for(i = 0; i < length; i++) { 439 sprintf(stream + offset, "%2.2X ", buffer[i]); 440 count ++; 441 offset += 3; 442 443 if(count == 16) { 444 count = 0; 445 offset = 0; 446 AR_DEBUG_PRINTF(ATH_DEBUG_ANY, ("[H]: %s\n", stream)); 447 A_MEMZERO(stream, 60); 448 } 449 } 450 451 if(offset != 0) { 452 AR_DEBUG_PRINTF(ATH_DEBUG_ANY, ("[H]: %s\n", stream)); 453 } 454 455 AR_DEBUG_PRINTF(ATH_DEBUG_ANY, ("<------------------------------------------------->\n")); 456} 457 458A_BOOL HTCGetEndpointStatistics(HTC_HANDLE HTCHandle, 459 HTC_ENDPOINT_ID Endpoint, 460 HTC_ENDPOINT_STAT_ACTION Action, 461 HTC_ENDPOINT_STATS *pStats) 462{ 463 464#ifdef HTC_EP_STAT_PROFILING 465 HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); 466 A_BOOL clearStats = FALSE; 467 A_BOOL sample = FALSE; 468 469 switch (Action) { 470 case HTC_EP_STAT_SAMPLE : 471 sample = TRUE; 472 break; 473 case HTC_EP_STAT_SAMPLE_AND_CLEAR : 474 sample = TRUE; 475 clearStats = TRUE; 476 break; 477 case HTC_EP_STAT_CLEAR : 478 clearStats = TRUE; 479 break; 480 default: 481 break; 482 } 483 484 A_ASSERT(Endpoint < ENDPOINT_MAX); 485 486 /* lock out TX and RX while we sample and/or clear */ 487 LOCK_HTC_TX(target); 488 LOCK_HTC_RX(target); 489 490 if (sample) { 491 A_ASSERT(pStats != NULL); 492 /* return the stats to the caller */ 493 A_MEMCPY(pStats, &target->EndPoint[Endpoint].EndPointStats, sizeof(HTC_ENDPOINT_STATS)); 494 } 495 496 if (clearStats) { 497 /* reset stats */ 498 A_MEMZERO(&target->EndPoint[Endpoint].EndPointStats, sizeof(HTC_ENDPOINT_STATS)); 499 } 500 501 UNLOCK_HTC_RX(target); 502 UNLOCK_HTC_TX(target); 503 504 return TRUE; 505#else 506 return FALSE; 507#endif 508} 509