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