1 /******************************************************************************* 2 ** 3 *Copyright (c) 2014 PMC-Sierra, Inc. All rights reserved. 4 * 5 *Redistribution and use in source and binary forms, with or without modification, are permitted provided 6 *that the following conditions are met: 7 *1. Redistributions of source code must retain the above copyright notice, this list of conditions and the 8 *following disclaimer. 9 *2. Redistributions in binary form must reproduce the above copyright notice, 10 *this list of conditions and the following disclaimer in the documentation and/or other materials provided 11 *with the distribution. 12 * 13 *THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED 14 *WARRANTIES,INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 15 *FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 16 *FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 17 *NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 18 *BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 19 *LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 20 *SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE 21 22 ********************************************************************************/ 23 24 /*******************************************************************************/ 25 /*! \file mpi.c 26 * \brief The file is a MPI Libraries to implement the MPI functions 27 * 28 * The file implements the MPI Library functions. 29 * 30 */ 31 /*******************************************************************************/ 32 #include <sys/cdefs.h> 33 #include <dev/pms/config.h> 34 35 #include <dev/pms/RefTisa/sallsdk/spc/saglobal.h> 36 37 #ifdef SA_ENABLE_TRACE_FUNCTIONS 38 #ifdef siTraceFileID 39 #undef siTraceFileID 40 #endif 41 #define siTraceFileID 'A' 42 #endif 43 44 #ifdef LOOPBACK_MPI 45 extern int loopback; 46 #endif 47 /*******************************************************************************/ 48 49 /*******************************************************************************/ 50 /*******************************************************************************/ 51 /* FUNCTIONS */ 52 /*******************************************************************************/ 53 /*******************************************************************************/ 54 /** \fn void mpiRequirementsGet(mpiConfig_t* config, mpiMemReq_t* memoryRequirement) 55 * \brief Retrieves the MPI layer resource requirements 56 * \param config MPI configuration for the Host MPI Message Unit 57 * \param memoryRequirement Returned data structure as defined by mpiMemReq_t 58 * that holds the different chunks of memory that are required 59 * 60 * The mpiRequirementsGet() function is used to determine the resource requirements 61 * for the SPC device interface 62 * 63 * Return: None 64 */ 65 /*******************************************************************************/ 66 void mpiRequirementsGet(mpiConfig_t* config, mpiMemReq_t* memoryRequirement) 67 { 68 bit32 qIdx, numq; 69 mpiMemReq_t* memoryMap; 70 SA_DBG2(("Entering function:mpiRequirementsGet\n")); 71 SA_ASSERT((NULL != config), "config argument cannot be null"); 72 73 memoryMap = memoryRequirement; 74 memoryMap->count = 0; 75 76 /* MPI Memory region 0 for MSGU(AAP1) Event Log for fw */ 77 memoryMap->region[memoryMap->count].numElements = 1; 78 memoryMap->region[memoryMap->count].elementSize = sizeof(bit8) * config->mainConfig.eventLogSize; 79 memoryMap->region[memoryMap->count].totalLength = sizeof(bit8) * config->mainConfig.eventLogSize; 80 memoryMap->region[memoryMap->count].alignment = 32; 81 memoryMap->region[memoryMap->count].type = AGSA_DMA_MEM; 82 SA_DBG2(("mpiRequirementsGet:eventLogSize region[%d] 0x%X\n",memoryMap->count,memoryMap->region[memoryMap->count].totalLength )); 83 memoryMap->count++; 84 85 SA_DBG2(("mpiRequirementsGet:eventLogSize region[%d] 0x%X\n",memoryMap->count,memoryMap->region[memoryMap->count].totalLength )); 86 /* MPI Memory region 1 for IOP Event Log for fw */ 87 memoryMap->region[memoryMap->count].numElements = 1; 88 memoryMap->region[memoryMap->count].elementSize = sizeof(bit8) * config->mainConfig.IOPeventLogSize; 89 memoryMap->region[memoryMap->count].totalLength = sizeof(bit8) * config->mainConfig.IOPeventLogSize; 90 memoryMap->region[memoryMap->count].alignment = 32; 91 memoryMap->region[memoryMap->count].type = AGSA_DMA_MEM; 92 SA_DBG2(("mpiRequirementsGet:IOPeventLogSize region[%d] 0x%X\n",memoryMap->count,memoryMap->region[memoryMap->count].totalLength )); 93 memoryMap->count++; 94 95 /* MPI Memory region 2 for consumer Index of inbound queues */ 96 memoryMap->region[memoryMap->count].numElements = 1; 97 memoryMap->region[memoryMap->count].elementSize = sizeof(bit32) * config->numInboundQueues; 98 memoryMap->region[memoryMap->count].totalLength = sizeof(bit32) * config->numInboundQueues; 99 memoryMap->region[memoryMap->count].alignment = 4; 100 memoryMap->region[memoryMap->count].type = AGSA_DMA_MEM; 101 SA_DBG2(("mpiRequirementsGet:numInboundQueues region[%d] 0x%X\n",memoryMap->count,memoryMap->region[memoryMap->count].totalLength )); 102 memoryMap->count++; 103 104 /* MPI Memory region 3 for producer Index of outbound queues */ 105 memoryMap->region[memoryMap->count].numElements = 1; 106 memoryMap->region[memoryMap->count].elementSize = sizeof(bit32) * config->numOutboundQueues; 107 memoryMap->region[memoryMap->count].totalLength = sizeof(bit32) * config->numOutboundQueues; 108 memoryMap->region[memoryMap->count].alignment = 4; 109 memoryMap->region[memoryMap->count].type = AGSA_DMA_MEM; 110 SA_DBG2(("mpiRequirementsGet:numOutboundQueues region[%d] 0x%X\n",memoryMap->count,memoryMap->region[memoryMap->count].totalLength )); 111 memoryMap->count++; 112 113 /* MPI Memory regions 4, ... for the inbound queues - depends on configuration */ 114 numq = 0; 115 for(qIdx = 0; qIdx < config->numInboundQueues; qIdx++) 116 { 117 if(0 != config->inboundQueues[qIdx].numElements) 118 { 119 bit32 memSize = config->inboundQueues[qIdx].numElements * config->inboundQueues[qIdx].elementSize; 120 bit32 remainder = memSize & 127; 121 122 /* Calculate the size of this queue padded to 128 bytes */ 123 if (remainder > 0) 124 { 125 memSize += (128 - remainder); 126 } 127 128 if (numq == 0) 129 { 130 memoryMap->region[memoryMap->count].numElements = 1; 131 memoryMap->region[memoryMap->count].elementSize = memSize; 132 memoryMap->region[memoryMap->count].totalLength = memSize; 133 memoryMap->region[memoryMap->count].alignment = 128; 134 memoryMap->region[memoryMap->count].type = AGSA_CACHED_DMA_MEM; 135 } 136 else 137 { 138 memoryMap->region[memoryMap->count].elementSize += memSize; 139 memoryMap->region[memoryMap->count].totalLength += memSize; 140 } 141 142 numq++; 143 144 if ((0 == ((qIdx + 1) % MAX_QUEUE_EACH_MEM)) || 145 (qIdx == (bit32)(config->numInboundQueues - 1))) 146 { 147 SA_DBG2(("mpiRequirementsGet: (inboundQueues) memoryMap->region[%d].elementSize = %d\n", 148 memoryMap->count, memoryMap->region[memoryMap->count].elementSize)); 149 SA_DBG2(("mpiRequirementsGet: (inboundQueues) memoryMap->region[%d].numElements = %d\n", 150 memoryMap->count, memoryMap->region[memoryMap->count].numElements)); 151 152 memoryMap->count++; 153 numq = 0; 154 } 155 } 156 } 157 158 /* MPI Memory regions for the outbound queues - depends on configuration */ 159 numq = 0; 160 for(qIdx = 0; qIdx < config->numOutboundQueues; qIdx++) 161 { 162 if(0 != config->outboundQueues[qIdx].numElements) 163 { 164 bit32 memSize = config->outboundQueues[qIdx].numElements * config->outboundQueues[qIdx].elementSize; 165 bit32 remainder = memSize & 127; 166 167 /* Calculate the size of this queue padded to 128 bytes */ 168 if (remainder > 0) 169 { 170 memSize += (128 - remainder); 171 } 172 173 if (numq == 0) 174 { 175 memoryMap->region[memoryMap->count].numElements = 1; 176 memoryMap->region[memoryMap->count].elementSize = memSize; 177 memoryMap->region[memoryMap->count].totalLength = memSize; 178 memoryMap->region[memoryMap->count].alignment = 128; 179 memoryMap->region[memoryMap->count].type = AGSA_CACHED_DMA_MEM; 180 } 181 else 182 { 183 memoryMap->region[memoryMap->count].elementSize += memSize; 184 memoryMap->region[memoryMap->count].totalLength += memSize; 185 } 186 187 numq++; 188 189 if ((0 == ((qIdx + 1) % MAX_QUEUE_EACH_MEM)) || 190 (qIdx == (bit32)(config->numOutboundQueues - 1))) 191 { 192 SA_DBG2(("mpiRequirementsGet: (outboundQueues) memoryMap->region[%d].elementSize = %d\n", 193 memoryMap->count, memoryMap->region[memoryMap->count].elementSize)); 194 SA_DBG2(("mpiRequirementsGet: (outboundQueues) memoryMap->region[%d].numElements = %d\n", 195 memoryMap->count, memoryMap->region[memoryMap->count].numElements)); 196 197 198 memoryMap->count++; 199 numq = 0; 200 } 201 } 202 } 203 204 } 205 206 /*******************************************************************************/ 207 /** \fn mpiMsgFreeGet(mpiICQueue_t *circularQ, bit16 messageSize, void** messagePtr) 208 * \brief Retrieves a free message buffer from an inbound queue 209 * \param circularQ Pointer to an inbound circular queue 210 * \param messageSize Requested message size in bytes - only support 64 bytes/element 211 * \param messagePtr Pointer to the free message buffer payload (not including message header) or NULL if no free message buffers are available 212 * 213 * This function is used to retrieve a free message buffer for the given inbound queue of at least 214 * messageSize bytes. 215 * The caller can use the returned buffer to construct the message and then call mpiMsgProduce() 216 * to deliver the message to the device message unit or mpiMsgInvalidate() if the message buffer 217 * is not going to be used 218 * 219 * Return: 220 * AGSA_RC_SUCCESS if messagePtr contains a valid message buffer pointer 221 * AGSA_RC_FAILURE if messageSize larger than the elementSize of queue 222 * AGSA_RC_BUSY if there are not free message buffers (Queue full) 223 */ 224 /*******************************************************************************/ 225 GLOBAL FORCEINLINE 226 bit32 227 mpiMsgFreeGet( 228 mpiICQueue_t *circularQ, 229 bit16 messageSize, 230 void** messagePtr 231 ) 232 { 233 bit32 offset; 234 agsaRoot_t *agRoot=circularQ->agRoot; 235 mpiMsgHeader_t *msgHeader; 236 bit8 bcCount = 1; /* only support single buffer */ 237 238 SA_DBG4(("Entering function:mpiMsgFreeGet\n")); 239 SA_ASSERT(NULL != circularQ, "circularQ cannot be null"); 240 SA_ASSERT(NULL != messagePtr, "messagePtr argument cannot be null"); 241 SA_ASSERT(0 != circularQ->numElements, "The number of elements in this queue is 0"); 242 243 /* Checks is the requested message size can be allocated in this queue */ 244 if(messageSize > circularQ->elementSize) 245 { 246 SA_DBG1(("mpiMsgFreeGet: Message Size (%d) is larger than Q element size (%d)\n",messageSize,circularQ->elementSize)); 247 return AGSA_RC_FAILURE; 248 } 249 250 /* Stores the new consumer index */ 251 OSSA_READ_LE_32(circularQ->agRoot, &circularQ->consumerIdx, circularQ->ciPointer, 0); 252 /* if inbound queue is full, return busy */ 253 /* This queue full logic may only works for bc == 1 ( == ) */ 254 /* ( pi + bc ) % size > ci not fully works for bc > 1 */ 255 /* To do - support bc > 1 case and wrap around case */ 256 if (((circularQ->producerIdx + bcCount) % circularQ->numElements) == circularQ->consumerIdx) 257 { 258 *messagePtr = NULL; 259 smTrace(hpDBG_VERY_LOUD,"Za", (((circularQ->producerIdx & 0xFFF) << 16) | (circularQ->consumerIdx & 0xFFF) )); 260 /* TP:Za IQ PI CI */ 261 ossaHwRegRead(agRoot, MSGU_HOST_SCRATCH_PAD_0); 262 SA_DBG1(("mpiMsgFreeGet: %d + %d == %d AGSA_RC_BUSY\n",circularQ->producerIdx,bcCount,circularQ->consumerIdx)); 263 264 return AGSA_RC_BUSY; 265 } 266 267 smTrace(hpDBG_VERY_LOUD,"Zb", (((circularQ->producerIdx & 0xFFF) << 16) | (circularQ->consumerIdx & 0xFFF) )); 268 /* TP:Zb IQ PI CI */ 269 270 271 /* get memory IOMB buffer address */ 272 offset = circularQ->producerIdx * circularQ->elementSize; 273 /* increment to next bcCount element */ 274 circularQ->producerIdx = (circularQ->producerIdx + bcCount) % circularQ->numElements; 275 276 /* Adds that distance to the base of the region virtual address plus the message header size*/ 277 msgHeader = (mpiMsgHeader_t*) (((bit8 *)(circularQ->memoryRegion.virtPtr)) + offset); 278 279 SA_DBG3(("mpiMsgFreeGet: msgHeader = %p Offset = 0x%x\n", (void *)msgHeader, offset)); 280 281 /* Sets the message buffer in "allocated" state */ 282 /* bc always is 1 for inbound queue */ 283 /* temporarily store it in the native endian format, when the rest of the */ 284 /* header is filled, this would be converted to Little Endian */ 285 msgHeader->Header = (1<<24); 286 *messagePtr = ((bit8*)msgHeader) + sizeof(mpiMsgHeader_t); 287 288 return AGSA_RC_SUCCESS; 289 } 290 291 #ifdef LOOPBACK_MPI 292 GLOBAL bit32 mpiMsgFreeGetOQ(mpiOCQueue_t *circularQ, bit16 messageSize, void** messagePtr) 293 { 294 bit32 offset; 295 mpiMsgHeader_t *msgHeader; 296 bit8 bcCount = 1; /* only support single buffer */ 297 298 SA_DBG4(("Entering function:mpiMsgFreeGet\n")); 299 SA_ASSERT(NULL != circularQ, "circularQ cannot be null"); 300 SA_ASSERT(NULL != messagePtr, "messagePtr argument cannot be null"); 301 SA_ASSERT(0 != circularQ->numElements, "The number of elements in this queue is 0"); 302 303 /* Checks is the requested message size can be allocated in this queue */ 304 if(messageSize > circularQ->elementSize) 305 { 306 SA_DBG1(("mpiMsgFreeGet: Message Size is not fit in\n")); 307 return AGSA_RC_FAILURE; 308 } 309 310 /* Stores the new consumer index */ 311 //OSSA_READ_LE_32(circularQ->agRoot, &circularQ->consumerIdx, circularQ->ciPointer, 0); 312 /* if inbound queue is full, return busy */ 313 /* This queue full logic may only works for bc == 1 ( == ) */ 314 /* ( pi + bc ) % size > ci not fully works for bc > 1 */ 315 /* To do - support bc > 1 case and wrap around case */ 316 if (((circularQ->producerIdx + bcCount) % circularQ->numElements) == circularQ->consumerIdx) 317 { 318 *messagePtr = NULL; 319 return AGSA_RC_BUSY; 320 } 321 322 /* get memory IOMB buffer address */ 323 offset = circularQ->producerIdx * circularQ->elementSize; 324 /* increment to next bcCount element */ 325 circularQ->producerIdx = (circularQ->producerIdx + bcCount) % circularQ->numElements; 326 327 /* Adds that distance to the base of the region virtual address plus the message header size*/ 328 msgHeader = (mpiMsgHeader_t*) (((bit8 *)(circularQ->memoryRegion.virtPtr)) + offset); 329 330 SA_DBG3(("mpiMsgFreeGet: msgHeader = %p Offset = 0x%x\n", (void *)msgHeader, offset)); 331 332 /* Sets the message buffer in "allocated" state */ 333 /* bc always is 1 for inbound queue */ 334 /* temporarily store it in the native endian format, when the rest of the */ 335 /* header is filled, this would be converted to Little Endian */ 336 msgHeader->Header = (1<<24); 337 *messagePtr = ((bit8*)msgHeader) + sizeof(mpiMsgHeader_t); 338 339 return AGSA_RC_SUCCESS; 340 } 341 #endif 342 343 /*******************************************************************************/ 344 /** \fn mpiMsgProduce(mpiICQueue_t *circularQ, void *messagePtr, mpiMsgCategory_t category, bit16 opCode, bit8 responseQueue) 345 * \brief Add a header of IOMB then send to a inbound queue and update the Producer index 346 * \param circularQ Pointer to an inbound queue 347 * \param messagePtr Pointer to the message buffer payload (not including message header)) 348 * \param category Message category (ETHERNET, FC, SAS-SATA, SCSI) 349 * \param opCode Message operation code 350 * \param responseQueue If the message requires response, this paramater indicates the outbound queue for the response 351 * 352 * This function is used to sumit a message buffer, previously obtained from mpiMsgFreeGet() 353 * function call, to the given Inbound queue 354 * 355 * Return: 356 * AGSA_RC_SUCCESS if the message has been posted succesfully 357 */ 358 /*******************************************************************************/ 359 #ifdef FAST_IO_TEST 360 GLOBAL bit32 mpiMsgPrepare( 361 mpiICQueue_t *circularQ, 362 void *messagePtr, 363 mpiMsgCategory_t category, 364 bit16 opCode, 365 bit8 responseQueue, 366 bit8 hiPriority 367 ) 368 { 369 mpiMsgHeader_t *msgHeader; 370 bit32 bc; 371 bit32 Header = 0; 372 bit32 hpriority = 0; 373 374 SA_DBG4(("Entering function:mpiMsgProduce\n")); 375 SA_ASSERT(NULL != circularQ, "circularQ argument cannot be null"); 376 SA_ASSERT(NULL != messagePtr, "messagePtr argument cannot be null"); 377 SA_ASSERT(0 != circularQ->numElements, "The number of elements in this queue" 378 " is 0"); 379 SA_ASSERT(MPI_MAX_OUTBOUND_QUEUES > responseQueue, "oQueue ID is wrong"); 380 381 /* Obtains the address of the entire message buffer, including the header */ 382 msgHeader = (mpiMsgHeader_t*)(((bit8*)messagePtr) - sizeof(mpiMsgHeader_t)); 383 /* Read the BC from header, its stored in native endian format when message 384 was allocated */ 385 /* intially */ 386 bc = (((msgHeader->Header) >> SHIFT24) & BC_MASK); 387 SA_DBG6(("mpiMsgProduce: msgHeader bc %d\n", bc)); 388 if (circularQ->priority) 389 hpriority = 1; 390 391 /* Checks the message is in "allocated" state */ 392 SA_ASSERT(0 != bc, "The message buffer is not in \"allocated\" state " 393 "(bc == 0)"); 394 395 Header = ((V_BIT << SHIFT31) | (hpriority << SHIFT30) | 396 ((bc & BC_MASK) << SHIFT24) | 397 ((responseQueue & OBID_MASK) << SHIFT16) | 398 ((category & CAT_MASK) << SHIFT12 ) | (opCode & OPCODE_MASK)); 399 400 /* pre flush the IOMB cache line */ 401 ossaCachePreFlush(circularQ->agRoot, 402 (void *)circularQ->memoryRegion.appHandle, 403 (void *)msgHeader, circularQ->elementSize * bc); 404 OSSA_WRITE_LE_32(circularQ->agRoot, msgHeader, OSSA_OFFSET_OF(mpiMsgHeader_t, 405 Header), Header); 406 /* flush the IOMB cache line */ 407 ossaCacheFlush(circularQ->agRoot, (void *)circularQ->memoryRegion.appHandle, 408 (void *)msgHeader, circularQ->elementSize * bc); 409 410 MPI_DEBUG_TRACE( circularQ->qNumber, 411 ((circularQ->producerIdx << 16 ) | circularQ->consumerIdx), 412 MPI_DEBUG_TRACE_IBQ, 413 (void *)msgHeader, 414 circularQ->elementSize); 415 416 ossaLogIomb(circularQ->agRoot, 417 circularQ->qNumber, 418 TRUE, 419 (void *)msgHeader, 420 circularQ->elementSize); 421 422 return AGSA_RC_SUCCESS; 423 } /* mpiMsgPrepare */ 424 425 GLOBAL bit32 mpiMsgProduce( 426 mpiICQueue_t *circularQ, 427 void *messagePtr, 428 mpiMsgCategory_t category, 429 bit16 opCode, 430 bit8 responseQueue, 431 bit8 hiPriority 432 ) 433 { 434 bit32 ret; 435 436 ret = mpiMsgPrepare(circularQ, messagePtr, category, opCode, responseQueue, 437 hiPriority); 438 if (ret == AGSA_RC_SUCCESS) 439 { 440 /* update PI of inbound queue */ 441 ossaHwRegWriteExt(circularQ->agRoot, 442 circularQ->PIPCIBar, 443 circularQ->PIPCIOffset, 444 circularQ->producerIdx); 445 } 446 return ret; 447 } 448 449 GLOBAL void mpiIBQMsgSend(mpiICQueue_t *circularQ) 450 { 451 ossaHwRegWriteExt(circularQ->agRoot, 452 circularQ->PIPCIBar, 453 circularQ->PIPCIOffset, 454 circularQ->producerIdx); 455 } 456 #else /* FAST_IO_TEST */ 457 458 GLOBAL FORCEINLINE 459 bit32 460 mpiMsgProduce( 461 mpiICQueue_t *circularQ, 462 void *messagePtr, 463 mpiMsgCategory_t category, 464 bit16 opCode, 465 bit8 responseQueue, 466 bit8 hiPriority 467 ) 468 { 469 mpiMsgHeader_t *msgHeader; 470 bit32 bc; 471 bit32 Header = 0; 472 bit32 hpriority = 0; 473 474 #ifdef SA_FW_TEST_BUNCH_STARTS 475 #define Need_agRootDefined 1 476 #endif /* SA_FW_TEST_BUNCH_STARTS */ 477 478 #ifdef SA_ENABLE_TRACE_FUNCTIONS 479 bit32 i; 480 #define Need_agRootDefined 1 481 #endif /* SA_ENABLE_TRACE_FUNCTIONS */ 482 483 #ifdef MPI_DEBUG_TRACE_ENABLE 484 #define Need_agRootDefined 1 485 #endif /* MPI_DEBUG_TRACE_ENABLE */ 486 487 #ifdef Need_agRootDefined 488 agsaRoot_t *agRoot=circularQ->agRoot; 489 #ifdef SA_FW_TEST_BUNCH_STARTS 490 agsaLLRoot_t *saRoot = agNULL; 491 saRoot = agRoot->sdkData; 492 #endif /* SA_FW_TEST_BUNCH_STARTS */ 493 494 #undef Need_agRootDefined 495 #endif /* Need_agRootDefined */ 496 497 SA_DBG4(("Entering function:mpiMsgProduce\n")); 498 SA_ASSERT(NULL != circularQ, "circularQ argument cannot be null"); 499 SA_ASSERT(NULL != messagePtr, "messagePtr argument cannot be null"); 500 SA_ASSERT(0 != circularQ->numElements, "The number of elements in this queue is 0"); 501 SA_ASSERT(MPI_MAX_OUTBOUND_QUEUES > responseQueue, "oQueue ID is wrong"); 502 503 /* REB Start extra trace */ 504 smTraceFuncEnter(hpDBG_VERY_LOUD,"22"); 505 /* REB End extra trace */ 506 507 /* Obtains the address of the entire message buffer, including the header */ 508 msgHeader = (mpiMsgHeader_t*)(((bit8*)messagePtr) - sizeof(mpiMsgHeader_t)); 509 /* Read the BC from header, its stored in native endian format when message was allocated */ 510 /* intially */ 511 bc = (((msgHeader->Header) >> SHIFT24) & BC_MASK); 512 SA_DBG6(("mpiMsgProduce: msgHeader bc %d\n", bc)); 513 if (circularQ->priority) 514 { 515 hpriority = 1; 516 } 517 518 /* Checks the message is in "allocated" state */ 519 SA_ASSERT(0 != bc, "The message buffer is not in \"allocated\" state (bc == 0)"); 520 521 Header = ((V_BIT << SHIFT31) | 522 (hpriority << SHIFT30) | 523 ((bc & BC_MASK) << SHIFT24) | 524 ((responseQueue & OBID_MASK) << SHIFT16) | 525 ((category & CAT_MASK) << SHIFT12 ) | 526 (opCode & OPCODE_MASK)); 527 528 /* pre flush the cache line */ 529 ossaCachePreFlush(circularQ->agRoot, (void *)circularQ->memoryRegion.appHandle, (void *)msgHeader, circularQ->elementSize * bc); 530 OSSA_WRITE_LE_32(circularQ->agRoot, msgHeader, OSSA_OFFSET_OF(mpiMsgHeader_t, Header), Header); 531 /* flush the cache line for IOMB */ 532 ossaCacheFlush(circularQ->agRoot, (void *)circularQ->memoryRegion.appHandle, (void *)msgHeader, circularQ->elementSize * bc); 533 534 MPI_DEBUG_TRACE( circularQ->qNumber, 535 ((circularQ->producerIdx << 16 ) | circularQ->consumerIdx), 536 MPI_DEBUG_TRACE_IBQ, 537 (void *)msgHeader, 538 circularQ->elementSize); 539 540 ossaLogIomb(circularQ->agRoot, 541 circularQ->qNumber, 542 TRUE, 543 (void *)msgHeader, 544 circularQ->elementSize); 545 546 #if defined(SALLSDK_DEBUG) 547 MPI_IBQ_IOMB_LOG(circularQ->qNumber, (void *)msgHeader, circularQ->elementSize); 548 #endif /* SALLSDK_DEBUG */ 549 /* REB Start extra trace */ 550 #ifdef SA_ENABLE_TRACE_FUNCTIONS 551 smTrace(hpDBG_IOMB,"M1",circularQ->qNumber); 552 /* TP:M1 circularQ->qNumber */ 553 for (i=0; i<((bit32)bc*(circularQ->elementSize/4)); i++) 554 { 555 /* The -sizeof(mpiMsgHeader_t) is to account for mpiMsgProduce adding the header to the pMessage pointer */ 556 smTrace(hpDBG_IOMB,"MD",*( ((bit32 *)((bit8 *)messagePtr - sizeof(mpiMsgHeader_t))) + i)); 557 /* TP:MD Inbound IOMB Dword */ 558 } 559 #endif /* SA_ENABLE_TRACE_FUNCTIONS */ 560 561 /* update PI of inbound queue */ 562 563 #ifdef SA_FW_TEST_BUNCH_STARTS 564 if(saRoot->BunchStarts_Enable) 565 { 566 if (circularQ->BunchStarts_QPending == 0) 567 { 568 // store tick value for 1st deferred IO only 569 circularQ->BunchStarts_QPendingTick = saRoot->timeTick; 570 } 571 // update queue's pending count 572 circularQ->BunchStarts_QPending++; 573 574 // update global pending count 575 saRoot->BunchStarts_Pending++; 576 577 SA_DBG1(("mpiMsgProduce: BunchStarts - Global Pending %d\n", saRoot->BunchStarts_Pending)); 578 SA_DBG1(("mpiMsgProduce: BunchStarts - QPending %d, Q-%d\n", circularQ->BunchStarts_QPending, circularQ->qNumber)); 579 smTraceFuncExit(hpDBG_VERY_LOUD, 'a', "22"); 580 581 return AGSA_RC_SUCCESS; 582 } 583 584 saRoot->BunchStarts_Pending = 0; 585 circularQ->BunchStarts_QPending = 0; 586 #endif /* SA_FW_TEST_BUNCH_STARTS */ 587 ossaHwRegWriteExt(circularQ->agRoot, 588 circularQ->PIPCIBar, 589 circularQ->PIPCIOffset, 590 circularQ->producerIdx); 591 592 smTraceFuncExit(hpDBG_VERY_LOUD, 'b', "22"); 593 594 return AGSA_RC_SUCCESS; 595 } /* mpiMsgProduce */ 596 #endif /* FAST_IO_TEST */ 597 598 #ifdef SA_FW_TEST_BUNCH_STARTS 599 600 void mpiMsgProduceBunch( agsaLLRoot_t *saRoot) 601 { 602 mpiICQueue_t *circularQ; 603 bit32 inq; 604 605 for(inq=0; ((inq < saRoot->QueueConfig.numInboundQueues) && saRoot->BunchStarts_Pending); inq++) 606 { 607 circularQ= &saRoot->inboundQueue[inq]; 608 /* If any pending IOs present then either process if BunchStarts_Threshold 609 * IO limit reached or if the timer has popped 610 */ 611 if (circularQ->BunchStarts_QPending && 612 ((circularQ->BunchStarts_QPending >= saRoot->BunchStarts_Threshold) || 613 ((saRoot->timeTick - circularQ->BunchStarts_QPendingTick) >= saRoot->BunchStarts_TimeoutTicks)) 614 ) 615 { 616 if(circularQ->qNumber != inq) 617 { 618 SA_DBG1(("mpiMsgProduceBunch:circularQ->qNumber(%d) != inq(%d)\n",circularQ->qNumber, inq)); 619 } 620 621 SA_DBG1(("mpiMsgProduceBunch: IQ=%d, PI=%d\n", inq, circularQ->producerIdx)); 622 SA_DBG1(("mpiMsgProduceBunch: Qpending=%d, TotPending=%d\n", circularQ->BunchStarts_QPending, saRoot->BunchStarts_Pending)); 623 624 ossaHwRegWriteExt(circularQ->agRoot, 625 circularQ->PIPCIBar, 626 circularQ->PIPCIOffset, 627 circularQ->producerIdx); 628 629 // update global pending count 630 saRoot->BunchStarts_Pending -= circularQ->BunchStarts_QPending; 631 632 // clear current queue's pending count after processing 633 circularQ->BunchStarts_QPending = 0; 634 circularQ->BunchStarts_QPendingTick = saRoot->timeTick; 635 } 636 } 637 } 638 #endif /* SA_FW_TEST_BUNCH_STARTS */ 639 640 /*******************************************************************************/ 641 /** \fn mpiMsgConsume(mpiOCQueue_t *circularQ, void *messagePtr1, 642 * mpiMsgCategory_t * pCategory, bit16 * pOpCode, bit8 * pBC) 643 * \brief Get a received message 644 * \param circularQ Pointer to a outbound queue 645 * \param messagePtr1 Pointer to the returned message buffer or NULL if no valid message 646 * \param pCategory Pointer to Message category (ETHERNET, FC, SAS-SATA, SCSI) 647 * \param pOpCode Pointer to Message operation code 648 * \param pBC Pointer to buffer count 649 * 650 * Consume a receive message in the specified outbound queue 651 * 652 * Return: 653 * AGSA_RC_SUCCESS if the message has been retrieved succesfully 654 * AGSA_RC_BUSY if the circular is empty 655 */ 656 /*******************************************************************************/ 657 GLOBAL FORCEINLINE 658 bit32 659 mpiMsgConsume( 660 mpiOCQueue_t *circularQ, 661 void ** messagePtr1, 662 mpiMsgCategory_t *pCategory, 663 bit16 *pOpCode, 664 bit8 *pBC 665 ) 666 { 667 mpiMsgHeader_t *msgHeader; 668 bit32 msgHeader_tmp; 669 670 SA_ASSERT(NULL != circularQ, "circularQ argument cannot be null"); 671 SA_ASSERT(NULL != messagePtr1, "messagePtr1 argument cannot be null"); 672 SA_ASSERT(NULL != pCategory, "pCategory argument cannot be null"); 673 SA_ASSERT(NULL != pOpCode, "pOpCode argument cannot be null"); 674 SA_ASSERT(NULL != pBC, "pBC argument cannot be null"); 675 SA_ASSERT(0 != circularQ->numElements, "The number of elements in this queue is 0"); 676 677 do 678 { 679 /* If there are not-yet-delivered messages ... */ 680 if(circularQ->producerIdx != circularQ->consumerIdx) 681 { 682 /* Get the pointer to the circular queue buffer element */ 683 msgHeader = (mpiMsgHeader_t*) ((bit8 *)(circularQ->memoryRegion.virtPtr) + circularQ->consumerIdx * circularQ->elementSize); 684 685 #ifdef LOOPBACK_MPI 686 if (!loopback) 687 #endif 688 /* invalidate the cache line of IOMB */ 689 ossaCacheInvalidate(circularQ->agRoot, (void *)circularQ->memoryRegion.appHandle, (void *)msgHeader, circularQ->elementSize); 690 691 692 /* read header */ 693 OSSA_READ_LE_32(circularQ->agRoot, &msgHeader_tmp, msgHeader, 0); 694 695 SA_DBG4(("mpiMsgConsume: process an IOMB, header=0x%x\n", msgHeader_tmp)); 696 697 SA_ASSERT(0 != (msgHeader_tmp & HEADER_BC_MASK), "The bc field in the header is 0"); 698 #ifdef TEST 699 /* for debugging */ 700 if (0 == (msgHeader_tmp & HEADER_BC_MASK)) 701 { 702 SA_DBG1(("mpiMsgConsume: CI=%d PI=%d msgHeader=%p\n", circularQ->consumerIdx, circularQ->producerIdx, (void *)msgHeader)); 703 circularQ->consumerIdx = (circularQ->consumerIdx + 1) % circularQ->numElements; 704 /* update the CI of outbound queue - skip this blank IOMB, for test only */ 705 ossaHwRegWriteExt(circularQ->agRoot, 706 circularQ->CIPCIBar, 707 circularQ->CIPCIOffset, 708 circularQ->consumerIdx); 709 return AGSA_RC_FAILURE; 710 } 711 #endif 712 /* get message pointer of valid entry */ 713 if (0 != (msgHeader_tmp & HEADER_V_MASK)) 714 { 715 SA_ASSERT(circularQ->consumerIdx <= circularQ->numElements, "Multi-buffer messages cannot wrap around"); 716 717 if (OPC_OUB_SKIP_ENTRY != (msgHeader_tmp & OPCODE_MASK)) 718 { 719 /* ... return the message payload */ 720 *messagePtr1 = ((bit8*)msgHeader) + sizeof(mpiMsgHeader_t); 721 *pCategory = (mpiMsgCategory_t)(msgHeader_tmp >> SHIFT12) & CAT_MASK; 722 *pOpCode = (bit16)(msgHeader_tmp & OPCODE_MASK); 723 *pBC = (bit8)((msgHeader_tmp >> SHIFT24) & BC_MASK); 724 725 /* invalidate the cache line for IOMB */ 726 #ifdef LOOPBACK_MPI 727 if (!loopback) 728 #endif 729 ossaCacheInvalidate(circularQ->agRoot, (void *)circularQ->memoryRegion.appHandle, (void *)msgHeader, (*pBC - 1) * circularQ->elementSize); 730 731 #if defined(SALLSDK_DEBUG) 732 SA_DBG3(("mpiMsgConsume: CI=%d PI=%d msgHeader=%p\n", circularQ->consumerIdx, circularQ->producerIdx, (void *)msgHeader)); 733 MPI_OBQ_IOMB_LOG(circularQ->qNumber, (void *)msgHeader, circularQ->elementSize); 734 #endif 735 return AGSA_RC_SUCCESS; 736 } 737 else 738 { 739 SA_DBG3(("mpiMsgConsume: SKIP_ENTRIES_IOMB BC=%d\n", (msgHeader_tmp >> SHIFT24) & BC_MASK)); 740 /* Updated comsumerIdx and skip it */ 741 circularQ->consumerIdx = (circularQ->consumerIdx + ((msgHeader_tmp >> SHIFT24) & BC_MASK)) % circularQ->numElements; 742 /* clean header to 0 */ 743 msgHeader_tmp = 0; 744 /*ossaSingleThreadedEnter(agRoot, LL_IOREQ_OBQ_LOCK);*/ 745 746 OSSA_WRITE_LE_32(circularQ->agRoot, msgHeader, OSSA_OFFSET_OF(mpiMsgHeader_t, Header), msgHeader_tmp); 747 748 /* update the CI of outbound queue */ 749 ossaHwRegWriteExt(circularQ->agRoot, 750 circularQ->CIPCIBar, 751 circularQ->CIPCIOffset, 752 circularQ->consumerIdx); 753 /* Update the producer index */ 754 OSSA_READ_LE_32(circularQ->agRoot, &circularQ->producerIdx, circularQ->piPointer, 0); 755 /*ossaSingleThreadedLeave(agRoot, LL_IOREQ_OBQ_LOCK); */ 756 } 757 } 758 else 759 { 760 /* V bit is not set */ 761 #if defined(SALLSDK_DEBUG) 762 agsaRoot_t *agRoot=circularQ->agRoot; 763 SA_DBG1(("mpiMsgConsume: V bit not set, PI=%d CI=%d msgHeader=%p\n", circularQ->producerIdx, circularQ->consumerIdx,(void *)msgHeader)); 764 SA_DBG1(("mpiMsgConsume: V bit not set, 0x%08X Q=%d \n", msgHeader_tmp, circularQ->qNumber)); 765 766 MPI_DEBUG_TRACE(MPI_DEBUG_TRACE_QNUM_ERROR + circularQ->qNumber, 767 ((circularQ->producerIdx << 16 ) | circularQ->consumerIdx), 768 MPI_DEBUG_TRACE_OBQ, 769 (void *)(((bit8*)msgHeader) - sizeof(mpiMsgHeader_t)), 770 circularQ->elementSize); 771 772 circularQ->consumerIdx = circularQ->consumerIdx % circularQ->numElements; 773 circularQ->consumerIdx ++; 774 OSSA_WRITE_LE_32(circularQ->agRoot, msgHeader, OSSA_OFFSET_OF(mpiMsgHeader_t, Header), msgHeader_tmp); 775 ossaHwRegWriteExt(agRoot, 776 circularQ->CIPCIBar, 777 circularQ->CIPCIOffset, 778 circularQ->consumerIdx); 779 MPI_OBQ_IOMB_LOG(circularQ->qNumber, (void *)msgHeader, circularQ->elementSize); 780 #endif 781 SA_DBG1(("mpiMsgConsume: V bit is not set!!!!! HW CI=%d\n", ossaHwRegReadExt(circularQ->agRoot, circularQ->CIPCIBar, circularQ->CIPCIOffset) )); 782 SA_ASSERT(0, "V bit is not set"); 783 return AGSA_RC_FAILURE; 784 } 785 } 786 else 787 { 788 /* Update the producer index from SPC */ 789 OSSA_READ_LE_32(circularQ->agRoot, &circularQ->producerIdx, circularQ->piPointer, 0); 790 } 791 } while(circularQ->producerIdx != circularQ->consumerIdx); /* while we don't have any more not-yet-delivered message */ 792 793 #ifdef TEST 794 SA_DBG4(("mpiMsgConsume: Outbound queue is empty.\n")); 795 #endif 796 797 /* report empty */ 798 return AGSA_RC_BUSY; 799 } 800 801 /*******************************************************************************/ 802 /** \fn mpiMsgFreeSet(mpiOCQueue_t *circularQ, void *messagePtr) 803 * \brief Returns a received message to the outbound queue 804 * \param circularQ Pointer to an outbound queue 805 * \param messagePtr1 Pointer to the returned message buffer to free 806 * \param messagePtr2 Pointer to the returned message buffer to free if bc > 1 807 * 808 * Returns consumed and processed message to the specified outbounf queue 809 * 810 * Return: 811 * AGSA_RC_SUCCESS if the message has been returned succesfully 812 */ 813 /*******************************************************************************/ 814 GLOBAL FORCEINLINE 815 bit32 816 mpiMsgFreeSet( 817 mpiOCQueue_t *circularQ, 818 void *messagePtr1, 819 bit8 bc 820 ) 821 { 822 mpiMsgHeader_t *msgHeader; 823 824 SA_DBG4(("Entering function:mpiMsgFreeSet\n")); 825 SA_ASSERT(NULL != circularQ, "circularQ argument cannot be null"); 826 SA_ASSERT(NULL != messagePtr1, "messagePtr1 argument cannot be null"); 827 SA_ASSERT(0 != circularQ->numElements, "The number of elements in this queue is 0"); 828 829 /* Obtains the address of the entire message buffer, including the header */ 830 msgHeader = (mpiMsgHeader_t*)(((bit8*)messagePtr1) - sizeof(mpiMsgHeader_t)); 831 832 if ( ((mpiMsgHeader_t*)((bit8*)circularQ->memoryRegion.virtPtr + circularQ->consumerIdx * circularQ->elementSize)) != msgHeader) 833 { 834 /* IOMB of CI points mismatch with Message Header - should never happened */ 835 SA_DBG1(("mpiMsgFreeSet: Wrong CI, Q %d ConsumeIdx = %d msgHeader 0x%08x\n",circularQ->qNumber, circularQ->consumerIdx ,msgHeader->Header)); 836 SA_DBG1(("mpiMsgFreeSet: msgHeader %p != %p\n", msgHeader,((mpiMsgHeader_t*)((bit8*)circularQ->memoryRegion.virtPtr + circularQ->consumerIdx * circularQ->elementSize)))); 837 838 #ifdef LOOPBACK_MPI 839 if (!loopback) 840 #endif 841 /* Update the producer index from SPC */ 842 OSSA_READ_LE_32(circularQ->agRoot, &circularQ->producerIdx, circularQ->piPointer, 0); 843 #if defined(SALLSDK_DEBUG) 844 SA_DBG3(("mpiMsgFreeSet: ProducerIdx = %d\n", circularQ->producerIdx)); 845 #endif 846 return AGSA_RC_SUCCESS; 847 } 848 849 /* ... free the circular queue buffer elements associated with the message ... */ 850 /*... by incrementing the consumer index (with wrap arround) */ 851 circularQ->consumerIdx = (circularQ->consumerIdx + bc) % circularQ->numElements; 852 853 /* Invalidates this circular queue buffer element */ 854 855 msgHeader->Header &= ~HEADER_V_MASK; /* Clear Valid bit to indicate IOMB consumed by host */ 856 SA_ASSERT(circularQ->consumerIdx <= circularQ->numElements, "Multi-buffer messages cannot wrap arround"); 857 858 /* update the CI of outbound queue */ 859 #ifdef LOOPBACK_MPI 860 if (!loopback) 861 #endif 862 { 863 ossaHwRegWriteExt(circularQ->agRoot, 864 circularQ->CIPCIBar, 865 circularQ->CIPCIOffset, 866 circularQ->consumerIdx); 867 868 /* Update the producer index from SPC */ 869 OSSA_READ_LE_32(circularQ->agRoot, &circularQ->producerIdx, circularQ->piPointer, 0); 870 } 871 #if defined(SALLSDK_DEBUG) 872 SA_DBG5(("mpiMsgFreeSet: CI=%d PI=%d\n", circularQ->consumerIdx, circularQ->producerIdx)); 873 #endif 874 return AGSA_RC_SUCCESS; 875 } 876 877 #ifdef TEST 878 GLOBAL bit32 mpiRotateQnumber(agsaRoot_t *agRoot) 879 { 880 agsaLLRoot_t *saRoot = (agsaLLRoot_t *) (agRoot->sdkData); 881 bit32 denom; 882 bit32 ret = 0; 883 884 /* inbound queue number */ 885 saRoot->IBQnumber++; 886 denom = saRoot->QueueConfig.numInboundQueues; 887 if (saRoot->IBQnumber % denom == 0) /* % Qnumber*/ 888 { 889 saRoot->IBQnumber = 0; 890 } 891 SA_DBG3(("mpiRotateQnumber: IBQnumber %d\n", saRoot->IBQnumber)); 892 893 /* outbound queue number */ 894 saRoot->OBQnumber++; 895 denom = saRoot->QueueConfig.numOutboundQueues; 896 if (saRoot->OBQnumber % denom == 0) /* % Qnumber*/ 897 { 898 saRoot->OBQnumber = 0; 899 } 900 SA_DBG3(("mpiRotateQnumber: OBQnumber %d\n", saRoot->OBQnumber)); 901 902 ret = (saRoot->OBQnumber << SHIFT16) | saRoot->IBQnumber; 903 return ret; 904 } 905 #endif 906 907 #ifdef LOOPBACK_MPI 908 GLOBAL bit32 mpiMsgProduceOQ( 909 mpiOCQueue_t *circularQ, 910 void *messagePtr, 911 mpiMsgCategory_t category, 912 bit16 opCode, 913 bit8 responseQueue, 914 bit8 hiPriority 915 ) 916 { 917 mpiMsgHeader_t *msgHeader; 918 bit32 bc; 919 bit32 Header = 0; 920 bit32 hpriority = 0; 921 922 SA_DBG4(("Entering function:mpiMsgProduceOQ\n")); 923 SA_ASSERT(NULL != circularQ, "circularQ argument cannot be null"); 924 SA_ASSERT(NULL != messagePtr, "messagePtr argument cannot be null"); 925 SA_ASSERT(0 != circularQ->numElements, "The number of elements in this queue" 926 " is 0"); 927 SA_ASSERT(MPI_MAX_OUTBOUND_QUEUES > responseQueue, "oQueue ID is wrong"); 928 929 /* REB Start extra trace */ 930 smTraceFuncEnter(hpDBG_VERY_LOUD, "2I"); 931 /* REB End extra trace */ 932 933 /* Obtains the address of the entire message buffer, including the header */ 934 msgHeader = (mpiMsgHeader_t*)(((bit8*)messagePtr) - sizeof(mpiMsgHeader_t)); 935 /* Read the BC from header, its stored in native endian format when message 936 was allocated */ 937 /* intially */ 938 SA_DBG4(("mpiMsgProduceOQ: msgHeader %p opcode %d pi/ci %d / %d\n", msgHeader, opCode, circularQ->producerIdx, circularQ->consumerIdx)); 939 bc = (((msgHeader->Header) >> SHIFT24) & BC_MASK); 940 SA_DBG6(("mpiMsgProduceOQ: msgHeader bc %d\n", bc)); 941 if (circularQ->priority) 942 hpriority = 1; 943 944 /* Checks the message is in "allocated" state */ 945 SA_ASSERT(0 != bc, "The message buffer is not in \"allocated\" state " 946 "(bc == 0)"); 947 948 Header = ((V_BIT << SHIFT31) | (hpriority << SHIFT30) | 949 ((bc & BC_MASK) << SHIFT24) | 950 ((responseQueue & OBID_MASK) << SHIFT16) | 951 ((category & CAT_MASK) << SHIFT12 ) | (opCode & OPCODE_MASK)); 952 /* pre flush the IOMB cache line */ 953 //ossaCachePreFlush(circularQ->agRoot, 954 // (void *)circularQ->memoryRegion.appHandle, 955 // (void *)msgHeader, circularQ->elementSize * bc); 956 OSSA_WRITE_LE_32(circularQ->agRoot, msgHeader, OSSA_OFFSET_OF(mpiMsgHeader_t, 957 Header), Header); 958 959 /* flush the IOMB cache line */ 960 //ossaCacheFlush(circularQ->agRoot, (void *)circularQ->memoryRegion.appHandle, 961 // (void *)msgHeader, circularQ->elementSize * bc); 962 963 MPI_DEBUG_TRACE( circularQ->qNumber, 964 ((circularQ->producerIdx << 16 ) | circularQ->consumerIdx), 965 MPI_DEBUG_TRACE_OBQ, 966 (void *)msgHeader, 967 circularQ->elementSize); 968 969 ossaLogIomb(circularQ->agRoot, 970 circularQ->qNumber, 971 TRUE, 972 (void *)msgHeader, 973 circularQ->elementSize); 974 975 smTraceFuncExit(hpDBG_VERY_LOUD, 'a', "2I"); 976 return AGSA_RC_SUCCESS; 977 } /* mpiMsgProduceOQ */ 978 #endif 979 980