root/sys/dev/pms/freebsd/driver/common/lxutil.c
/******************************************************************************
*Copyright (c) 2014 PMC-Sierra, Inc.  All rights reserved. 
*
*Redistribution and use in source and binary forms, with or without modification, are permitted provided 
*that the following conditions are met: 
*1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
*following disclaimer. 
*2. Redistributions in binary form must reproduce the above copyright notice, 
*this list of conditions and the following disclaimer in the documentation and/or other materials provided
*with the distribution. 
*
*THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED 
*WARRANTIES,INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
*FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
*FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 
*NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 
*BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
*LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
*SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE

******************************************************************************/
/******************************************************************************
This program is part of PMC-Sierra initiator/target device driver. 
The functions here are commonly used by different type of drivers that support
PMC-Sierra storage network initiator hardware. 
******************************************************************************/


MALLOC_DEFINE( M_PMC_MMAL, "agtiapi_MemAlloc malloc",
               "allocated from agtiapi_MemAlloc as simple malloc case" );


/*****************************************************************************
agtiapi_DelayMSec()

Purpose:
  Busy wait for number of mili-seconds
Parameters:
  U32 MiliSeconds (IN)  Number of mili-seconds to delay
Return:
Note:
*****************************************************************************/
STATIC void agtiapi_DelayMSec( U32 MiliSeconds )
{
  DELAY(MiliSeconds * 1000);  // DELAY takes in usecs
}

/******************************************************************************
agtiapi_typhAlloc()
Purpose:
  Preallocation handling
  Allocate DMA memory which will be divided among proper pointers in
   agtiapi_MemAlloc() later
Parameters:
  ag_card_info_t *thisCardInst (IN)
Return:
  AGTIAPI_SUCCESS - success
  AGTIAPI_FAIL    - fail
******************************************************************************/
STATIC agBOOLEAN agtiapi_typhAlloc( ag_card_info_t *thisCardInst )
{
  struct agtiapi_softc *pmsc = thisCardInst->pCard;
  int wait = 0;

  if( bus_dma_tag_create( bus_get_dma_tag(pmsc->my_dev), // parent
                          32,                          // alignment
                          0,                           // boundary
                          BUS_SPACE_MAXADDR,           // lowaddr
                          BUS_SPACE_MAXADDR,           // highaddr
                          NULL,                        // filter
                          NULL,                        // filterarg
                          pmsc->typhn,                 // maxsize (size)
                          1,                           // number of segments
                          pmsc->typhn,                 // maxsegsize
                          0,                           // flags
                          NULL,                        // lockfunc
                          NULL,                        // lockarg
                          &pmsc->typh_dmat ) ) {
    printf( "agtiapi_typhAlloc: Can't create no-cache mem tag\n" );
    return AGTIAPI_FAIL;
  }

  if( bus_dmamem_alloc( pmsc->typh_dmat,
                        &pmsc->typh_mem,
                        BUS_DMA_WAITOK | BUS_DMA_ZERO | BUS_DMA_NOCACHE,
                        &pmsc->typh_mapp ) ) {
    printf( "agtiapi_typhAlloc: Cannot allocate cache mem %d\n",
            pmsc->typhn );
    return AGTIAPI_FAIL;
  }

  if ( bus_dmamap_load( pmsc->typh_dmat,
                        pmsc->typh_mapp,
                        pmsc->typh_mem,
                        pmsc->typhn,
                        agtiapi_MemoryCB, // try reuse of CB for same goal
                        &pmsc->typh_busaddr,
                        0 ) || !pmsc->typh_busaddr ) {
    for( ; wait < 20; wait++ ) {
      if( pmsc->typh_busaddr ) break;
      DELAY( 50000 );
    }

    if( ! pmsc->typh_busaddr ) {
      printf( "agtiapi_typhAlloc: cache mem won't load %d\n",
              pmsc->typhn );
      return AGTIAPI_FAIL;
    }
  }

  pmsc->typhIdx = 0;
  pmsc->tyPhsIx = 0;

  return AGTIAPI_SUCCESS;
}


/******************************************************************************
agtiapi_InitResource()
Purpose:
  Mapping PCI memory space
  Allocate and initialize per card based resource
Parameters: 
  ag_card_info_t *pCardInfo (IN)  
Return:
  AGTIAPI_SUCCESS - success
  AGTIAPI_FAIL    - fail
Note:    
******************************************************************************/
STATIC agBOOLEAN agtiapi_InitResource( ag_card_info_t *thisCardInst )
{
  struct agtiapi_softc *pmsc = thisCardInst->pCard;
  device_t devx = thisCardInst->pPCIDev;

  //AGTIAPI_PRINTK( "agtiapi_InitResource: begin; pointer values %p / %p \n",
  //        devx, thisCardInst );
  // no IO mapped card implementation, we'll implement memory mapping

  if( agtiapi_typhAlloc( thisCardInst ) == AGTIAPI_FAIL ) {
    printf( "agtiapi_InitResource: failed call to agtiapi_typhAlloc \n" );
    return AGTIAPI_FAIL;
  }

  AGTIAPI_PRINTK( "agtiapi_InitResource: dma alloc MemSpan %p -- %p\n",
                  (void*) pmsc->typh_busaddr,
                  (void*) ( (U32_64)pmsc->typh_busaddr + pmsc->typhn ) );

  //  logical BARs for SPC:
  //    bar 0 and 1 - logical BAR0
  //    bar 2 and 3 - logical BAR1
  //    bar4 - logical BAR2
  //    bar5 - logical BAR3
  //    Skiping the assignments for bar 1 and bar 3 (making bar 0, 2 64-bit):
  U32 bar;
  U32 lBar = 0; // logicalBar
  for (bar = 0; bar < PCI_NUMBER_BARS; bar++) {
    if ((bar==1) || (bar==3))
      continue;
    thisCardInst->pciMemBaseRIDSpc[lBar] = PCIR_BAR(bar);
    thisCardInst->pciMemBaseRscSpc[lBar] =
      bus_alloc_resource_any( devx,
                              SYS_RES_MEMORY,
                              &(thisCardInst->pciMemBaseRIDSpc[lBar]),
                              RF_ACTIVE );
    AGTIAPI_PRINTK( "agtiapi_InitResource: bus_alloc_resource_any rtn %p \n",
                    thisCardInst->pciMemBaseRscSpc[lBar] );
    if ( thisCardInst->pciMemBaseRscSpc[lBar] != NULL ) {
      thisCardInst->pciMemVirtAddrSpc[lBar] =
        (caddr_t)rman_get_virtual(
          thisCardInst->pciMemBaseRscSpc[lBar] );
      thisCardInst->pciMemBaseSpc[lBar]  =
        bus_get_resource_start( devx, SYS_RES_MEMORY,
                                thisCardInst->pciMemBaseRIDSpc[lBar]);
      thisCardInst->pciMemSizeSpc[lBar]  =
        bus_get_resource_count( devx, SYS_RES_MEMORY,
                                thisCardInst->pciMemBaseRIDSpc[lBar] );
      AGTIAPI_PRINTK( "agtiapi_InitResource: PCI: bar %d, lBar %d "
                      "VirtAddr=%lx, len=%d\n", bar, lBar,
                      (long unsigned int)thisCardInst->pciMemVirtAddrSpc[lBar],
                      thisCardInst->pciMemSizeSpc[lBar] );
    }
    else {
      thisCardInst->pciMemVirtAddrSpc[lBar] = 0;
      thisCardInst->pciMemBaseSpc[lBar]  = 0;
      thisCardInst->pciMemSizeSpc[lBar]  = 0;
    }
    lBar++;
  }
  thisCardInst->pciMemVirtAddr = thisCardInst->pciMemVirtAddrSpc[0];
  thisCardInst->pciMemSize = thisCardInst->pciMemSizeSpc[0];
  thisCardInst->pciMemBase = thisCardInst->pciMemBaseSpc[0];

  // Allocate all TI data structure required resources.
  // tiLoLevelResource
  U32 numVal;
  ag_resource_info_t *pRscInfo;
  pRscInfo = &thisCardInst->tiRscInfo;
  pRscInfo->tiLoLevelResource.loLevelOption.pciFunctionNumber =
    pci_get_function( devx );

  struct timeval tv;
  tv.tv_sec  = 1;
  tv.tv_usec = 0;
  int ticksPerSec;
  ticksPerSec = tvtohz( &tv );
  int uSecPerTick = 1000000/USEC_PER_TICK;

  if (pRscInfo->tiLoLevelResource.loLevelMem.count != 0) {
    //AGTIAPI_INIT("agtiapi_InitResource: loLevelMem count = %d\n",
    // pRscInfo->tiLoLevelResource.loLevelMem.count);

    // adjust tick value to meet Linux requirement
    pRscInfo->tiLoLevelResource.loLevelOption.usecsPerTick = uSecPerTick;
    AGTIAPI_PRINTK( "agtiapi_InitResource: "
                    "pRscInfo->tiLoLevelResource.loLevelOption.usecsPerTick"
                    " 0x%x\n",
                    pRscInfo->tiLoLevelResource.loLevelOption.usecsPerTick );
    for( numVal = 0; numVal < pRscInfo->tiLoLevelResource.loLevelMem.count;
         numVal++ ) {
      if( pRscInfo->tiLoLevelResource.loLevelMem.mem[numVal].totalLength ==
          0 ) {
        AGTIAPI_PRINTK("agtiapi_InitResource: skip ZERO %d\n", numVal);
        continue;
      }

      // check for 64 bit alignment
      if ( pRscInfo->tiLoLevelResource.loLevelMem.mem[numVal].alignment <
           AGTIAPI_64BIT_ALIGN ) {
        AGTIAPI_PRINTK("agtiapi_InitResource: set ALIGN %d\n", numVal);
        pRscInfo->tiLoLevelResource.loLevelMem.mem[numVal].alignment =
          AGTIAPI_64BIT_ALIGN;
      }
      if( ((pRscInfo->tiLoLevelResource.loLevelMem.mem[numVal].type
            & (BIT(0) | BIT(1))) == TI_DMA_MEM)  ||
          ((pRscInfo->tiLoLevelResource.loLevelMem.mem[numVal].type
            & (BIT(0) | BIT(1))) == TI_CACHED_DMA_MEM)) {
        if ( thisCardInst->dmaIndex >=
             sizeof(thisCardInst->tiDmaMem) /
             sizeof(thisCardInst->tiDmaMem[0]) ) {
          AGTIAPI_PRINTK( "Invalid dmaIndex %d ERROR\n",
                          thisCardInst->dmaIndex );
          return AGTIAPI_FAIL;
        }
        thisCardInst->tiDmaMem[thisCardInst->dmaIndex].type =
#ifdef CACHED_DMA
          pRscInfo->tiLoLevelResource.loLevelMem.mem[numVal].type
          & (BIT(0) | BIT(1));
#else
        TI_DMA_MEM;
#endif
        if( agtiapi_MemAlloc( thisCardInst,
              &thisCardInst->tiDmaMem[thisCardInst->dmaIndex].dmaVirtAddr,
              &thisCardInst->tiDmaMem[thisCardInst->dmaIndex].dmaPhysAddr,
              &pRscInfo->tiLoLevelResource.loLevelMem.mem[numVal].virtPtr,
              &pRscInfo->tiLoLevelResource.loLevelMem.mem[numVal].
              physAddrUpper,
              &pRscInfo->tiLoLevelResource.loLevelMem.mem[numVal].
              physAddrLower,
              pRscInfo->tiLoLevelResource.loLevelMem.mem[numVal].totalLength,
              thisCardInst->tiDmaMem[thisCardInst->dmaIndex].type,
              pRscInfo->tiLoLevelResource.loLevelMem.mem[numVal].alignment)
            != AGTIAPI_SUCCESS ) {
          return AGTIAPI_FAIL;
        }
        thisCardInst->tiDmaMem[thisCardInst->dmaIndex].memSize =
          pRscInfo->tiLoLevelResource.loLevelMem.mem[numVal].totalLength;
        //AGTIAPI_INIT("agtiapi_InitResource: LoMem %d dmaIndex=%d  DMA virt"
        //             " %p, phys 0x%x, length %d align %d\n",
        //       numVal, pCardInfo->dmaIndex,
        //     pRscInfo->tiLoLevelResource.loLevelMem.mem[numVal].virtPtr,
        //   pRscInfo->tiLoLevelResource.loLevelMem.mem[numVal].physAddrLower,
        //     pRscInfo->tiLoLevelResource.loLevelMem.mem[numVal].totalLength,
        //     pRscInfo->tiLoLevelResource.loLevelMem.mem[numVal].alignment);
        thisCardInst->dmaIndex++;
      }
      else if ( (pRscInfo->tiLoLevelResource.loLevelMem.mem[numVal].type &
                 (BIT(0) | BIT(1))) == TI_CACHED_MEM) {
        if (thisCardInst->cacheIndex >=
            sizeof(thisCardInst->tiCachedMem) /
            sizeof(thisCardInst->tiCachedMem[0])) {
          AGTIAPI_PRINTK( "Invalid cacheIndex %d ERROR\n",
                  thisCardInst->cacheIndex );
          return AGTIAPI_FAIL;
        }
        if ( agtiapi_MemAlloc( thisCardInst,
               &thisCardInst->tiCachedMem[thisCardInst->cacheIndex],
               (vm_paddr_t *)agNULL,
               &pRscInfo->tiLoLevelResource.loLevelMem.mem[numVal].virtPtr,
               (U32 *)agNULL,
               (U32 *)agNULL,
               pRscInfo->tiLoLevelResource.loLevelMem.mem[numVal].totalLength,
               TI_CACHED_MEM,
               pRscInfo->tiLoLevelResource.loLevelMem.mem[numVal].alignment)
             != AGTIAPI_SUCCESS ) {
          return AGTIAPI_FAIL;
        }

        //AGTIAPI_INIT("agtiapi_InitResource: LoMem %d cacheIndex=%d CACHED "
        //      "vaddr %p / %p, length %d align %d\n",
        //      numVal, pCardInfo->cacheIndex,
        //      pCardInfo->tiCachedMem[pCardInfo->cacheIndex],
        //      pRscInfo->tiLoLevelResource.loLevelMem.mem[numVal].virtPtr,
        //      pRscInfo->tiLoLevelResource.loLevelMem.mem[numVal].totalLength,
        //      pRscInfo->tiLoLevelResource.loLevelMem.mem[numVal].alignment);

        thisCardInst->cacheIndex++;
      }
      else if ( ((pRscInfo->tiLoLevelResource.loLevelMem.mem[numVal].type
                  & (BIT(0) | BIT(1))) == TI_DMA_MEM_CHIP)) {
        // not expecting this case, print warning that should get attention
        printf( "RED ALARM: we need a BAR for TI_DMA_MEM_CHIP, ignoring!" );
      }
      else {
        printf( "agtiapi_InitResource: Unknown required memory type %d "
                "ERROR!\n",
                pRscInfo->tiLoLevelResource.loLevelMem.mem[numVal].type);
        return AGTIAPI_FAIL;
      }
    }
  }
  // end: TI data structure resources ...

  // begin: tiInitiatorResource
  if ( pmsc->flags & AGTIAPI_INITIATOR ) {
    if ( pRscInfo->tiInitiatorResource.initiatorMem.count != 0 ) {
      //AGTIAPI_INIT("agtiapi_InitResource: initiatorMem count = %d\n",
      //         pRscInfo->tiInitiatorResource.initiatorMem.count);
      numVal =
        (U32)( pRscInfo->tiInitiatorResource.initiatorOption.usecsPerTick
               / uSecPerTick );
      if( pRscInfo->tiInitiatorResource.initiatorOption.usecsPerTick
          % uSecPerTick > 0 )
        pRscInfo->tiInitiatorResource.initiatorOption.usecsPerTick =
          (numVal + 1) * uSecPerTick;
      else
        pRscInfo->tiInitiatorResource.initiatorOption.usecsPerTick =
          numVal * uSecPerTick;
      for ( numVal = 0;
            numVal < pRscInfo->tiInitiatorResource.initiatorMem.count;
            numVal++ ) {
        // check for 64 bit alignment
        if( pRscInfo->tiInitiatorResource.initiatorMem.tdCachedMem[numVal].
            alignment < AGTIAPI_64BIT_ALIGN ) {
          pRscInfo->tiInitiatorResource.initiatorMem.tdCachedMem[numVal].
            alignment = AGTIAPI_64BIT_ALIGN;
        }
        if( thisCardInst->cacheIndex >=
            sizeof( thisCardInst->tiCachedMem) /
            sizeof( thisCardInst->tiCachedMem[0])) {
          AGTIAPI_PRINTK( "Invalid cacheIndex %d ERROR\n",
                  thisCardInst->cacheIndex );
          return AGTIAPI_FAIL;
        }
        // initiator memory is cached, no check is needed
        if( agtiapi_MemAlloc( thisCardInst,
              (void *)&thisCardInst->tiCachedMem[thisCardInst->cacheIndex],
              (vm_paddr_t *)agNULL,
              &pRscInfo->tiInitiatorResource.initiatorMem.
              tdCachedMem[numVal].virtPtr,
              (U32 *)agNULL,
              (U32 *)agNULL,
              pRscInfo->tiInitiatorResource.initiatorMem.tdCachedMem[numVal].
              totalLength,
              TI_CACHED_MEM,
              pRscInfo->tiInitiatorResource.initiatorMem.tdCachedMem[numVal].
              alignment)
            != AGTIAPI_SUCCESS) {
          return AGTIAPI_FAIL;
        }
        // AGTIAPI_INIT("agtiapi_InitResource: IniMem %d cacheIndex=%d CACHED "
        //      "vaddr %p / %p, length %d align 0x%x\n",
        //      numVal,
        //      pCardInfo->cacheIndex,
        //      pCardInfo->tiCachedMem[pCardInfo->cacheIndex],
        //      pRscInfo->tiInitiatorResource.initiatorMem.tdCachedMem[numVal].
        //       virtPtr,
        //pRscInfo->tiInitiatorResource.initiatorMem.tdCachedMem[numVal].
        //       totalLength,
        // pRscInfo->tiInitiatorResource.initiatorMem.tdCachedMem[numVal].
        //       alignment);
        thisCardInst->cacheIndex++;
      }
    }
  }
  // end: tiInitiatorResource   

  // begin: tiTdSharedMem
  if (pRscInfo->tiSharedMem.tdSharedCachedMem1.totalLength != 0) {
    // check for 64 bit alignment
    if( pRscInfo->tiSharedMem.tdSharedCachedMem1.alignment < 
        AGTIAPI_64BIT_ALIGN ) {
      pRscInfo->tiSharedMem.tdSharedCachedMem1.alignment = AGTIAPI_64BIT_ALIGN;
    }
    if( (pRscInfo->tiSharedMem.tdSharedCachedMem1.type & (BIT(0) | BIT(1))) 
        == TI_DMA_MEM ) { 
      if( thisCardInst->dmaIndex >=
          sizeof(thisCardInst->tiDmaMem) / sizeof(thisCardInst->tiDmaMem[0]) ) {
        AGTIAPI_PRINTK( "Invalid dmaIndex %d ERROR\n", thisCardInst->dmaIndex);
        return AGTIAPI_FAIL;
      }
      if( agtiapi_MemAlloc( thisCardInst, (void *)&thisCardInst->
                            tiDmaMem[thisCardInst->dmaIndex].dmaVirtAddr,
                            &thisCardInst->tiDmaMem[thisCardInst->dmaIndex].
                            dmaPhysAddr,
                            &pRscInfo->tiSharedMem.tdSharedCachedMem1.virtPtr, 
                            &pRscInfo->tiSharedMem.tdSharedCachedMem1.
                            physAddrUpper, 
                            &pRscInfo->tiSharedMem.tdSharedCachedMem1.
                            physAddrLower, 
                            pRscInfo->tiSharedMem.tdSharedCachedMem1.
                            totalLength, 
                            TI_DMA_MEM,
                            pRscInfo->tiSharedMem.tdSharedCachedMem1.alignment)
          != AGTIAPI_SUCCESS )
        return AGTIAPI_FAIL;

      thisCardInst->tiDmaMem[thisCardInst->dmaIndex].memSize = 
        pRscInfo->tiSharedMem.tdSharedCachedMem1.totalLength + 
        pRscInfo->tiSharedMem.tdSharedCachedMem1.alignment;
      //    printf( "agtiapi_InitResource: SharedMem DmaIndex=%d DMA "
      //            "virt %p / %p, phys 0x%x, align %d\n", 
      //            thisCardInst->dmaIndex,
      //            thisCardInst->tiDmaMem[thisCardInst->dmaIndex].dmaVirtAddr,
      //            pRscInfo->tiSharedMem.tdSharedCachedMem1.virtPtr, 
      //            pRscInfo->tiSharedMem.tdSharedCachedMem1.physAddrLower, 
      //            pRscInfo->tiSharedMem.tdSharedCachedMem1.alignment);
      thisCardInst->dmaIndex++;
    }
    else if( (pRscInfo->tiSharedMem.tdSharedCachedMem1.type &
              (BIT(0) | BIT(1)))
             == TI_CACHED_MEM ) {
      if( thisCardInst->cacheIndex >=
          sizeof(thisCardInst->tiCachedMem) /
          sizeof(thisCardInst->tiCachedMem[0]) ) {
        AGTIAPI_PRINTK( "Invalid cacheIndex %d ERROR\n", thisCardInst->cacheIndex);
        return AGTIAPI_FAIL;
      }
      if( agtiapi_MemAlloc( thisCardInst, (void *)&thisCardInst->
                            tiCachedMem[thisCardInst->cacheIndex],
                            (vm_paddr_t *)agNULL,
                            &pRscInfo->tiSharedMem.tdSharedCachedMem1.virtPtr, 
                            (U32 *)agNULL,
                            (U32 *)agNULL,
                            pRscInfo->
                            tiSharedMem.tdSharedCachedMem1.totalLength, 
                            TI_CACHED_MEM,
                            pRscInfo->tiSharedMem.tdSharedCachedMem1.alignment)
          != AGTIAPI_SUCCESS )
        return AGTIAPI_FAIL;
      //    printf( "agtiapi_InitResource: SharedMem cacheIndex=%d CACHED "
      //                 "vaddr %p / %p, length %d align 0x%x\n",
      //                 thisCardInst->cacheIndex,
      //                 thisCardInst->tiCachedMem[thisCardInst->cacheIndex],
      //                 pRscInfo->tiSharedMem.tdSharedCachedMem1.virtPtr,
      //                 pRscInfo->tiSharedMem.tdSharedCachedMem1.totalLength,
      //                 pRscInfo->tiSharedMem.tdSharedCachedMem1.alignment);
      AGTIAPI_PRINTK( "agtiapi_InitResource: SharedMem cacheIndex=%d CACHED "
                      "vaddr %p / %p, length %d align 0x%x\n",
                      thisCardInst->cacheIndex,
                      thisCardInst->tiCachedMem[thisCardInst->cacheIndex],
                      pRscInfo->tiSharedMem.tdSharedCachedMem1.virtPtr,
                      pRscInfo->tiSharedMem.tdSharedCachedMem1.totalLength,
                      pRscInfo->tiSharedMem.tdSharedCachedMem1.alignment );
      thisCardInst->cacheIndex++;
    }
    else {
      AGTIAPI_PRINTK( "agtiapi_InitResource: "
                      "Unknown required memory type ERROR!\n" );
      return AGTIAPI_FAIL;
    }
  }
  // end: tiTdSharedMem
  DELAY( 200000 ); // or use AGTIAPI_INIT_MDELAY(200);
  return AGTIAPI_SUCCESS;
} // agtiapi_InitResource() ends here

/******************************************************************************
agtiapi_ScopeDMARes()
Purpose:
  Determine the amount of DMA (non-cache) memory resources which will be
  required for a card ( and necessarily allocated in agtiapi_InitResource() )
Parameters: 
  ag_card_info_t *thisCardInst (IN)  
Return:
  size of DMA memory which call to agtiapi_InitResource() will consume  
Note:
  this funcion mirrors the flow of agtiapi_InitResource()
  results are stored in agtiapi_softc fields
******************************************************************************/
STATIC int agtiapi_ScopeDMARes( ag_card_info_t *thisCardInst )
{
  struct agtiapi_softc *pmsc = thisCardInst->pCard;
  U32 lAllMem = 0; // total memory count; typhn
  U32 lTmpAlign, lTmpType, lTmpLen;

  // tiLoLevelResource
  U32 numVal;
  ag_resource_info_t *pRscInfo;
  pRscInfo = &thisCardInst->tiRscInfo;

  if (pRscInfo->tiLoLevelResource.loLevelMem.count != 0) {
    for( numVal = 0; numVal < pRscInfo->tiLoLevelResource.loLevelMem.count;
         numVal++ ) {
      if( pRscInfo->tiLoLevelResource.loLevelMem.mem[numVal].totalLength ==
          0 ) {
        printf( "agtiapi_ScopeDMARes: skip ZERO %d\n", numVal );
        continue;
      }
      // check for 64 bit alignment
      lTmpAlign = pRscInfo->tiLoLevelResource.loLevelMem.mem[numVal].alignment;
      if( lTmpAlign < AGTIAPI_64BIT_ALIGN ) {
        AGTIAPI_PRINTK("agtiapi_ScopeDMARes: set ALIGN %d\n", numVal);
        //pRscInfo->tiLoLevelResource.loLevelMem.mem[numVal].alignment =
        lTmpAlign = AGTIAPI_64BIT_ALIGN;
      }
      if( ((pRscInfo->tiLoLevelResource.loLevelMem.mem[numVal].type
            & (BIT(0) | BIT(1))) == TI_DMA_MEM)  ||
          ((pRscInfo->tiLoLevelResource.loLevelMem.mem[numVal].type
            & (BIT(0) | BIT(1))) == TI_CACHED_DMA_MEM)) {
        //thisCardInst->tiDmaMem[thisCardInst->dmaIndex].type =
        lTmpType =
#ifdef CACHED_DMA
          pRscInfo->tiLoLevelResource.loLevelMem.mem[numVal].type
          & (BIT(0) | BIT(1));
#else
        TI_DMA_MEM;
#endif
        if( lTmpType == TI_DMA_MEM ) {
          lTmpLen =
            pRscInfo->tiLoLevelResource.loLevelMem.mem[numVal].totalLength; 
          lAllMem += lTmpLen + lTmpAlign;
        }
        //printf( "agtiapi_ScopeDMARes: call 1 0x%x\n", lAllMem );
      }
      else if ( ( pRscInfo->tiLoLevelResource.loLevelMem.mem[numVal].type &
                  (BIT(0) | BIT(1)) ) == TI_CACHED_MEM ) {
        // these are not the droids we're looking for
        if( thisCardInst->cacheIndex >=
            sizeof(thisCardInst->tiCachedMem) /
            sizeof(thisCardInst->tiCachedMem[0]) ) {
          AGTIAPI_PRINTK( "agtiapi_ScopeDMARes: Invalid cacheIndex %d ERROR\n",
                          thisCardInst->cacheIndex );
          return lAllMem;
        }
      }
      else {
        printf( "agtiapi_ScopeDMARes: Unknown required memory type %d "
                "ERROR!\n",
                pRscInfo->tiLoLevelResource.loLevelMem.mem[numVal].type );
        return lAllMem;
      }
    }
  }
  // end: TI data structure resources ...

  // nothing for tiInitiatorResource

  // begin: tiTdSharedMem
  if (pRscInfo->tiSharedMem.tdSharedCachedMem1.totalLength != 0) {
    // check for 64 bit alignment
    lTmpAlign = pRscInfo->tiSharedMem.tdSharedCachedMem1.alignment;
    if( lTmpAlign < AGTIAPI_64BIT_ALIGN ) {
      //pRscInfo->tiSharedMem.tdSharedCachedMem1.alignment=AGTIAPI_64BIT_ALIGN;
       lTmpAlign = AGTIAPI_64BIT_ALIGN;
    }
    if( (pRscInfo->tiSharedMem.tdSharedCachedMem1.type & (BIT(0) | BIT(1))) 
        == TI_DMA_MEM ) { 
      lTmpLen = pRscInfo->tiSharedMem.tdSharedCachedMem1.totalLength;
      lAllMem += lTmpLen + lTmpAlign;
      // printf( "agtiapi_ScopeDMARes: call 4D 0x%x\n", lAllMem );
    }
    else if( (pRscInfo->tiSharedMem.tdSharedCachedMem1.type &
              (BIT(0) | BIT(1)))
             != TI_CACHED_MEM ) {
      printf( "agtiapi_ScopeDMARes: Unknown required memory type ERROR!\n" );
    }
  }
  // end: tiTdSharedMem

  pmsc->typhn = lAllMem;
  return lAllMem;

} // agtiapi_ScopeDMARes() ends here


STATIC void agtiapi_ReleasePCIMem( ag_card_info_t *pCardInfo ) {
  U32 bar = 0;
  int tmpRid = 0;
  struct resource *tmpRsc = NULL; 
  device_t dev;
  dev = pCardInfo->pPCIDev;

  for (bar=0; bar  < PCI_NUMBER_BARS; bar++) {  // clean up PCI resource
    tmpRid = pCardInfo->pciMemBaseRIDSpc[bar];
    tmpRsc = pCardInfo->pciMemBaseRscSpc[bar];
    if (tmpRsc != NULL) {   // Release PCI resources
      bus_release_resource( dev, SYS_RES_MEMORY, tmpRid, tmpRsc );
    }
  }
  return;
}


/******************************************************************************
agtiapi_MemAlloc()
Purpose:
  Handle various memory allocation requests.
Parameters: 
  ag_card_info_t *pCardInfo (IN)  Pointer to card info structure
  void **VirtAlloc (OUT)          Allocated memory virtual address  
  dma_addr_t *pDmaAddr (OUT)      Allocated dma memory physical address  
  void **VirtAddr (OUT)           Aligned memory virtual address  
  U32 *pPhysAddrUp (OUT)          Allocated memory physical upper 32 bits  
  U32 *pPhysAddrLow (OUT)         Allocated memory physical lower 32 bits  
  U32 MemSize (IN)                Allocated memory size
  U32 Type (IN)                   Type of memory required
  U32 Align (IN)                  Required memory alignment
Return:
  AGTIAPI_SUCCESS - success
  AGTIAPI_FAIL    - fail
******************************************************************************/
STATIC agBOOLEAN agtiapi_MemAlloc( ag_card_info_t *thisCardInst,
                                   void       **VirtAlloc,
                                   vm_paddr_t  *pDmaAddr,
                                   void       **VirtAddr,
                                   U32         *pPhysAddrUp,
                                   U32         *pPhysAddrLow,
                                   U32          MemSize,
                                   U32          Type,
                                   U32          Align )
{
  U32_64  alignOffset = 0;
  if( Align )
    alignOffset = Align - 1;

// printf( "agtiapi_MemAlloc: debug find mem TYPE, %d vs. CACHE %d, DMA %d \n",
//          ( Type & ( BIT(0) | BIT(1) ) ), TI_CACHED_MEM, TI_DMA_MEM );

  if ((Type & (BIT(0) | BIT(1))) == TI_CACHED_MEM) {
    *VirtAlloc = malloc( MemSize + Align, M_PMC_MMAL, M_ZERO | M_NOWAIT );
    *VirtAddr  = (void *)(((U32_64)*VirtAlloc + alignOffset) & ~alignOffset);
  }
  else {
    struct agtiapi_softc *pmsc = thisCardInst->pCard; // get card reference
    U32 residAlign = 0;
    // find virt index value
    *VirtAlloc = (void*)( (U64)pmsc->typh_mem + pmsc->typhIdx );
    *VirtAddr = (void *)( ( (U32_64)*VirtAlloc + alignOffset) & ~alignOffset );
    if( *VirtAddr != *VirtAlloc )
      residAlign = (U64)*VirtAddr - (U64)*VirtAlloc; // find alignment needed
    pmsc->typhIdx += residAlign + MemSize; // update index
    residAlign = 0; // reset variable for reuse
    // find phys index val
    pDmaAddr = (vm_paddr_t*)( (U64)pmsc->typh_busaddr + pmsc->tyPhsIx );
    vm_paddr_t *lPhysAligned =
      (vm_paddr_t*)( ( (U64)pDmaAddr + alignOffset ) & ~alignOffset );
    if( lPhysAligned != pDmaAddr )
      residAlign = (U64)lPhysAligned - (U64)pDmaAddr; // find alignment needed
    pmsc->tyPhsIx += residAlign + MemSize;  // update index
    *pPhysAddrUp  = HIGH_32_BITS( (U64)lPhysAligned );
    *pPhysAddrLow = LOW_32_BITS( (U64)lPhysAligned );
    //printf( "agtiapi_MemAlloc: physIx 0x%x size 0x%x resid:0x%x "
    //        "addr:0x%p addrAligned:0x%p Align:0x%x\n",
    //        pmsc->tyPhsIx, MemSize, residAlign, pDmaAddr, lPhysAligned,
    //        Align );
  }
  if ( !*VirtAlloc ) {
    AGTIAPI_PRINTK( "agtiapi_MemAlloc memory allocation ERROR x%x\n",
                    Type & (U32)(BIT(0) | BIT(1)));
    return AGTIAPI_FAIL;
  }
  return AGTIAPI_SUCCESS;
}


/******************************************************************************
agtiapi_MemFree()

Purpose:
  Free agtiapi_MemAlloc() allocated memory
Parameters: 
  ag_card_info_t *pCardInfo (IN)  Pointer to card info structure
Return: none
******************************************************************************/
STATIC void agtiapi_MemFree( ag_card_info_t *pCardInfo )
{
  U32 idx;

  // release memory vs. alloc in agtiapi_MemAlloc; cached case
  for( idx = 0; idx < pCardInfo->cacheIndex; idx++ ) {
    if( pCardInfo->tiCachedMem[idx] ) {
      free( pCardInfo->tiCachedMem[idx], M_PMC_MMAL );
      AGTIAPI_PRINTK( "agtiapi_MemFree: TI_CACHED_MEM Mem[%d] %p\n",
              idx, pCardInfo->tiCachedMem[idx] );
    }
  }

  // release memory vs. alloc in agtiapi_typhAlloc; used in agtiapi_MemAlloc
  struct agtiapi_softc *pmsc = pCardInfo->pCard; // get card reference
  if( pmsc->typh_busaddr != 0 ) {
    bus_dmamap_unload( pmsc->typh_dmat, pmsc->typh_mapp );
  }
  if( pmsc->typh_mem != NULL )  {
    bus_dmamem_free( pmsc->typh_dmat, pmsc->typh_mem, pmsc->typh_mapp );
  }
  if( pmsc->typh_dmat != NULL ) {
    bus_dma_tag_destroy( pmsc->typh_dmat );
  }
//reference values:
//  pCardInfo->dmaIndex
//  pCardInfo->tiDmaMem[idx].dmaVirtAddr
//  pCardInfo->tiDmaMem[idx].memSize
//  pCardInfo->tiDmaMem[idx].type == TI_CACHED_DMA_MEM
//  pCardInfo->tiDmaMem[idx].type == TI_DMA_MEM

/* This code is redundant.  Commenting out for now to maintain a placekeeper.
   Free actually takes place in agtiapi_ReleaseHBA as calls on osti_dmat. dm
  // release possible lower layer dynamic memory
  for( idx = 0; idx < AGTIAPI_DYNAMIC_MAX; idx++ ) {
    if( pCardInfo->dynamicMem[idx].dmaVirtAddr != NULL ) {
      printf( "agtiapi_MemFree: dynMem[%d] virtAddr"
                    " %p / %lx size: %d\n",
              idx, pCardInfo->dynamicMem[idx].dmaVirtAddr,
              (long unsigned int)pCardInfo->dynamicMem[idx].dmaPhysAddr,
              pCardInfo->dynamicMem[idx].memSize );
      if( pCardInfo->dynamicMem[idx].dmaPhysAddr )
              some form of free call would go here  (
                    pCardInfo->dynamicMem[idx].dmaVirtAddr,
                    pCardInfo->dynamicMem[idx].memSize, ... );
      else
        free case for cacheable memory would go here
    }
  }
*/
  return;
}

/******************************************************************************
agtiapi_ProbeCard()
Purpose:
  sets thisCardInst->cardIdIndex to structure variant consistent with card.
  ag_card_type[idx].vendorId we already determined is PCI_VENDOR_ID_PMC_SIERRA.
Parameters:
  device_t dev,
  ag_card_info_t *thisCardInst,
  int thisCard
Return:
  0 - success
  other values are not as good
Note:
 This implementation is tailored to FreeBSD in alignment with the probe
 functionality of the FreeBSD environment.
******************************************************************************/
STATIC int agtiapi_ProbeCard( device_t dev,
                              ag_card_info_t *thisCardInst,
                              int thisCard )
{
  int idx;
  u_int16_t agtiapi_vendor; // PCI vendor ID
  u_int16_t agtiapi_dev; // PCI device ID
  AGTIAPI_PRINTK("agtiapi_ProbeCard: start\n");

  agtiapi_vendor = pci_get_vendor( dev ); // get PCI vendor ID
  agtiapi_dev = pci_get_device( dev ); // get PCI device ID
  for( idx = 0; idx < COUNT(ag_card_type); idx++ ) 
  {
    if ( ag_card_type[idx].deviceId == agtiapi_dev &&
          ag_card_type[idx].vendorId == agtiapi_vendor) 
    { // device ID match
      memset( (void *)&agCardInfoList[ thisCard ], 0,
              sizeof(ag_card_info_t) );
      thisCardInst->cardIdIndex = idx;
      thisCardInst->pPCIDev = dev;
      thisCardInst->cardNameIndex = ag_card_type[idx].cardNameIndex;
      thisCardInst->cardID =
        pci_read_config( dev, ag_card_type[idx].membar, 4 ); // memAddr
      AGTIAPI_PRINTK("agtiapi_ProbeCard: We've got PMC SAS, probe successful %p / %p\n",
              thisCardInst->pPCIDev, thisCardInst );
      device_set_desc( dev, ag_card_names[ag_card_type[idx].cardNameIndex] );
      return 0;
    }
  }
  return 1;
}