/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
*/
/*
* Hermon Resource Management Routines
*
* Implements all the routines necessary for setup, teardown, and
* by Hermon hardware or which live in Hermon's direct attached DDR memory.
*/
#include <sys/sysmacros.h>
int hermon_rsrc_verbose = 0;
/*
* The following routines are used for initializing and destroying
* the resource pools used by the Hermon resource allocation routines.
* They consist of four classes of object:
*
* Mailboxes: The "In" and "Out" mailbox types are used by the Hermon
* command interface routines. Mailboxes are used to pass information
* back and forth to the Hermon firmware. Either type of mailbox may
* be allocated from Hermon's direct attached DDR memory or from system
* memory (although currently all "In" mailboxes are in DDR and all "out"
* mailboxes come from system memory.
*
* HW entry objects: These objects represent resources required by the Hermon
* hardware. These objects include things like Queue Pair contexts (QPC),
* Completion Queue contexts (CQC), Event Queue contexts (EQC), RDB (for
* Protection Table entries (MPT), Memory Translation Table entries (MTT).
*
* What these objects all have in common is that they are each required
* to come from ICM memory, they are always allocated from tables, and
* they are not to be directly accessed (read or written) by driver
* software (Mellanox FMR access to MPT is an exception).
* The other notable exceptions are the UAR pages (UAR_PG) which are
* allocated from the UAR address space rather than DDR, and the UD
* address vectors (UDAV) which are similar to the common object types
* with the major difference being that UDAVs _are_ directly read and
* written by driver software.
*
* SW handle objects: These objects represent resources required by Hermon
* driver software. They are primarily software tracking structures,
* which are allocated from system memory (using kmem_cache). Several of
* the objects have both a "constructor" and "destructor" method
* associated with them (see below).
*
* Protection Domain (PD) handle objects: These objects are very much like
* a SW handle object with the notable difference that all PD handle
* objects have an actual Protection Domain number (PD) associated with
* vmem_arena specifically set aside for this purpose.
*/
/*
* The following routines are used for allocating and freeing the specific
* types of objects described above from their associated resource pools.
*/
hermon_rsrc_t *hdl);
hermon_rsrc_t *hdl);
hermon_rsrc_t *hdl);
/*
* The following routines are the constructors and destructors for several
* of the SW handle type objects. For certain types of SW handles objects
* (all of which are implemented using kmem_cache), we need to do some
* special field initialization (specifically, mutex_init/destroy). These
* routines enable that init and teardown.
*/
/*
* Special routine to calculate and return the size of a MCG object based
* on current driver configuration (specifically, the number of QP per MCG
* that has been configured.
*/
/*
* hermon_rsrc_alloc()
*
* Context: Can be called from interrupt or base context.
* The "sleepflag" parameter is used by all object allocators to
* determine whether to SLEEP for resources or not.
*/
int
{
/*
* Allocate space for the object used to track the resource handle
*/
if (tmp_rsrc_hdl == NULL) {
return (DDI_FAILURE);
}
/*
* Set rsrc_hdl type. This is later used by the hermon_rsrc_free call
* to know what type of resource is being freed.
*/
/*
* Depending on resource type, call the appropriate alloc routine
*/
switch (rsrc) {
case HERMON_IN_MBOX:
case HERMON_OUT_MBOX:
case HERMON_INTR_IN_MBOX:
case HERMON_INTR_OUT_MBOX:
break;
case HERMON_DMPT:
/* Allocate "num" (contiguous/aligned for FEXCH) DMPTs */
case HERMON_QPC:
/* Allocate "num" (contiguous/aligned for RSS) QPCs */
break;
case HERMON_QPC_FEXCH_PORT1:
case HERMON_QPC_FEXCH_PORT2:
/* Allocate "num" contiguous/aligned QPCs for FEXCH */
break;
case HERMON_QPC_RFCI_PORT1:
case HERMON_QPC_RFCI_PORT2:
/* Allocate "num" contiguous/aligned QPCs for RFCI */
break;
case HERMON_MTT:
case HERMON_CQC:
case HERMON_SRQC:
case HERMON_EQC:
case HERMON_MCG:
case HERMON_UARPG:
/* Allocate "num" unaligned resources */
break;
case HERMON_MRHDL:
case HERMON_EQHDL:
case HERMON_CQHDL:
case HERMON_SRQHDL:
case HERMON_AHHDL:
case HERMON_QPHDL:
case HERMON_REFCNT:
break;
case HERMON_PDHDL:
break;
case HERMON_RDB: /* handled during HERMON_QPC */
case HERMON_ALTC: /* handled during HERMON_QPC */
case HERMON_AUXC: /* handled during HERMON_QPC */
case HERMON_CMPT_QPC: /* handled during HERMON_QPC */
case HERMON_CMPT_SRQC: /* handled during HERMON_SRQC */
case HERMON_CMPT_CQC: /* handled during HERMON_CPC */
case HERMON_CMPT_EQC: /* handled during HERMON_EPC */
default:
break;
}
/*
* If the resource allocation failed, then free the special resource
* tracking structure and return failure. Otherwise return the
* handle for the resource tracking structure.
*/
if (status != DDI_SUCCESS) {
return (DDI_FAILURE);
} else {
*hdl = tmp_rsrc_hdl;
return (DDI_SUCCESS);
}
}
/*
* hermon_rsrc_reserve()
*
* Context: Can only be called from attach.
* The "sleepflag" parameter is used by all object allocators to
* determine whether to SLEEP for resources or not.
*/
int
{
/*
* Allocate space for the object used to track the resource handle
*/
if (tmp_rsrc_hdl == NULL) {
return (DDI_FAILURE);
}
/*
* Set rsrc_hdl type. This is later used by the hermon_rsrc_free call
* to know what type of resource is being freed.
*/
switch (rsrc) {
case HERMON_QPC:
case HERMON_DMPT:
case HERMON_MTT:
/*
* Reserve num resources, naturally aligned (N * num).
*/
break;
default:
break;
}
/*
* If the resource allocation failed, then free the special resource
* tracking structure and return failure. Otherwise return the
* handle for the resource tracking structure.
*/
if (status != DDI_SUCCESS) {
return (DDI_FAILURE);
} else {
*hdl = tmp_rsrc_hdl;
return (DDI_SUCCESS);
}
}
/*
* hermon_rsrc_fexch_alloc()
*
* Context: Can only be called from base context.
* The "sleepflag" parameter is used by all object allocators to
* determine whether to SLEEP for resources or not.
*/
static int
{
void *addr;
return (DDI_FAILURE);
/* Allocate from the FEXCH QP range */
return (DDI_FAILURE);
}
/* ICM confirm for the FEXCH QP range */
if (status != DDI_SUCCESS) {
return (DDI_FAILURE);
}
/* ICM confirm for the Primary MKEYs (client side only) */
if (status != DDI_SUCCESS) {
return (DDI_FAILURE);
}
/* ICM confirm for the MTTs of the Primary MKEYs (client side only) */
if (status != DDI_SUCCESS) {
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
static void
{
}
/*
* hermon_rsrc_rfci_alloc()
*
* Context: Can only be called from base context.
* The "sleepflag" parameter is used by all object allocators to
* determine whether to SLEEP for resources or not.
*/
static int
{
void *addr;
return (DDI_FAILURE);
/* Allocate from the RFCI QP range */
return (DDI_FAILURE);
}
/* ICM confirm for the RFCI QP */
if (status != DDI_SUCCESS) {
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
static void
{
}
/*
* hermon_rsrc_free()
* Context: Can be called from interrupt or base context.
*/
void
{
/*
* Depending on resource type, call the appropriate free routine
*/
case HERMON_IN_MBOX:
case HERMON_OUT_MBOX:
case HERMON_INTR_IN_MBOX:
case HERMON_INTR_OUT_MBOX:
break;
case HERMON_QPC_FEXCH_PORT1:
case HERMON_QPC_FEXCH_PORT2:
break;
case HERMON_QPC_RFCI_PORT1:
case HERMON_QPC_RFCI_PORT2:
break;
case HERMON_QPC:
case HERMON_CQC:
case HERMON_SRQC:
case HERMON_EQC:
case HERMON_DMPT:
case HERMON_MCG:
case HERMON_MTT:
case HERMON_UARPG:
break;
case HERMON_MRHDL:
case HERMON_EQHDL:
case HERMON_CQHDL:
case HERMON_SRQHDL:
case HERMON_AHHDL:
case HERMON_QPHDL:
case HERMON_REFCNT:
break;
case HERMON_PDHDL:
break;
case HERMON_RDB:
case HERMON_ALTC:
case HERMON_AUXC:
case HERMON_CMPT_QPC:
case HERMON_CMPT_SRQC:
case HERMON_CMPT_CQC:
case HERMON_CMPT_EQC:
default:
break;
}
/*
* Free the special resource tracking structure, set the handle to
* NULL, and return.
*/
}
/*
* hermon_rsrc_init_phase1()
*
* Completes the first phase of Hermon resource/configuration init.
* This involves creating the kmem_cache for the "hermon_rsrc_t"
* structs, allocating the space for the resource pool handles,
* and setting up the "Out" mailboxes.
*
* When this function completes, the Hermon driver is ready to
* post the following commands which return information only in the
* "Out" mailbox: QUERY_DDR, QUERY_FW, QUERY_DEV_LIM, and QUERY_ADAPTER
* If any of these commands are to be posted at this time, they must be
* done so only when "spinning" (as the outstanding command list and
* EQ setup code has not yet run)
*
* Context: Only called from attach() path context
*/
int
{
int status;
char *rsrc_name;
/* This is where Phase 1 of resource initialization begins */
/* Build kmem cache name from Hermon instance */
/*
* Create the kmem_cache for "hermon_rsrc_t" structures
* (kmem_cache_create will SLEEP until successful)
*/
/*
* Allocate an array of hermon_rsrc_pool_info_t's (used in all
* subsequent resource allocations)
*/
sizeof (hermon_rsrc_pool_info_t), KM_SLEEP);
/* Pull in the configuration profile */
/* Initialize the resource pool for "out" mailboxes */
if (status != DDI_SUCCESS) {
goto rsrcinitp1_fail;
}
/* Initialize the mailbox list */
if (status != DDI_SUCCESS) {
goto rsrcinitp1_fail;
}
/* Initialize the resource pool for "interrupt out" mailboxes */
if (status != DDI_SUCCESS) {
goto rsrcinitp1_fail;
}
/* Initialize the mailbox list */
if (status != DDI_SUCCESS) {
goto rsrcinitp1_fail;
}
/* Initialize the resource pool for "in" mailboxes */
if (status != DDI_SUCCESS) {
goto rsrcinitp1_fail;
}
/* Initialize the mailbox list */
if (status != DDI_SUCCESS) {
goto rsrcinitp1_fail;
}
/* Initialize the resource pool for "interrupt in" mailboxes */
if (status != DDI_SUCCESS) {
goto rsrcinitp1_fail;
}
/* Initialize the mailbox list */
if (status != DDI_SUCCESS) {
goto rsrcinitp1_fail;
}
return (DDI_SUCCESS);
return (status);
}
/*
* hermon_rsrc_init_phase2()
* Context: Only called from attach() path context
*/
int
{
int i, status;
char *rsrc_name;
/* Phase 2 initialization begins where Phase 1 left off */
/* Allocate the ICM resource name space */
/* Build the ICM vmem arena names from Hermon instance */
/*
* Initialize the resource pools for all objects that exist in
* context memory (ICM). The ICM consists of context tables, each
* type of resource (QP, CQ, EQ, etc) having it's own context table
* (QPC, CQC, EQC, etc...).
*/
/*
* Initialize the resource pools for each of the driver resources.
* With a few exceptions, these resources fall into the two cateogories
* of either hw_entries or sw_entries.
*/
/*
* Initialize the resource pools for ICM (hardware) types first.
* These resources are managed through vmem arenas, which are
* created via the rsrc pool initialization routine. Note that,
* due to further calculations, the MCG resource pool is
* initialized seperately.
*/
for (i = 0; i < HERMON_NUM_ICM_RESOURCES; i++) {
/* Set the resource-specific attributes */
switch (i) {
case HERMON_MTT:
break;
case HERMON_DMPT:
break;
case HERMON_QPC:
break;
case HERMON_CQC:
break;
case HERMON_SRQC:
break;
case HERMON_EQC:
break;
case HERMON_MCG: /* handled below */
case HERMON_AUXC:
case HERMON_ALTC:
case HERMON_RDB:
case HERMON_CMPT_QPC:
case HERMON_CMPT_SRQC:
case HERMON_CMPT_CQC:
case HERMON_CMPT_EQC:
default:
/* We don't need to initialize this rsrc here. */
continue;
}
/* Set the common values for all resource pools */
/* Now, initialize the entry_info and call the init routine */
if (status != DDI_SUCCESS) {
goto rsrcinitp2_fail;
}
}
/*
* Initialize the Multicast Group (MCG) entries. First, calculate
* (and validate) the size of the MCGs.
*/
if (status != DDI_SUCCESS) {
goto rsrcinitp2_fail;
}
/*
* Initialize the resource pool for the MCG table entries. Notice
* that the number of MCGs is configurable. Note also that a certain
* number of MCGs must be set aside for Hermon firmware use (they
* correspond to the number of MCGs used by the internal hash
* function).
*/
if (status != DDI_SUCCESS) {
goto rsrcinitp2_fail;
}
/*
* Initialize the full range of ICM for the AUXC resource.
* This is done because its size is so small, about 1 byte per QP.
*/
/*
* Initialize the Hermon command handling interfaces. This step
* sets up the outstanding command tracking mechanism for easy access
* and fast allocation (see hermon_cmd.c for more details).
*/
if (status != DDI_SUCCESS) {
goto rsrcinitp2_fail;
}
/* Initialize the resource pool and vmem arena for the PD handles */
if (status != DDI_SUCCESS) {
goto rsrcinitp2_fail;
}
/*
* Initialize the resource pools for the rest of the software handles.
* This includes MR handles, EQ handles, QP handles, etc. These
* objects are almost entirely managed using kmem_cache routines,
* and do not utilize a vmem arena.
*/
for (i = HERMON_NUM_ICM_RESOURCES; i < HERMON_NUM_RESOURCES; i++) {
/* Set the resource-specific attributes */
switch (i) {
case HERMON_MRHDL:
sizeof (struct hermon_sw_mr_s);
break;
case HERMON_EQHDL:
sizeof (struct hermon_sw_eq_s);
break;
case HERMON_CQHDL:
sizeof (struct hermon_sw_cq_s);
break;
case HERMON_SRQHDL:
sizeof (struct hermon_sw_srq_s);
break;
case HERMON_AHHDL:
sizeof (struct hermon_sw_ah_s);
break;
case HERMON_QPHDL:
sizeof (struct hermon_sw_qp_s);
break;
case HERMON_REFCNT:
break;
default:
continue;
}
/* Set the common values and call the init routine */
if (status != DDI_SUCCESS) {
goto rsrcinitp2_fail;
}
}
/*
* Initialize a resource pool for the MCG handles. Notice that for
* these MCG handles, we are allocating a table of structures (used to
* keep track of the MCG entries that are being written to hardware
*/
if (status != DDI_SUCCESS) {
goto rsrcinitp2_fail;
}
/*
* Last, initialize the resource pool for the UAR pages, which contain
* the hardware's doorbell registers. Each process supported in User
* Mode is assigned a UAR page. Also coming from this pool are the
* kernel-assigned UAR page, and any hardware-reserved pages. Note
* that the number of UAR pages is configurable, the value must be less
* than the maximum value (obtained from the QUERY_DEV_LIM command) or
* the initialization will fail. Note also that we assign the base
* address of the UAR BAR to the rsrc_start parameter.
*/
if (status != DDI_SUCCESS) {
goto rsrcinitp2_fail;
}
return (DDI_SUCCESS);
return (status);
}
/*
* hermon_rsrc_fini()
*/
void
{
/*
* If init code above is shortened up (see comments), then we
* need to establish how to safely and simply clean up from any
* given failure point. Flags, maybe...
*/
switch (clean) {
/*
* If we add more resources that need to be cleaned up here, we should
* ensure that HERMON_RSRC_CLEANUP_ALL is still the first entry (i.e.
* corresponds to the last resource allocated).
*/
case HERMON_RSRC_CLEANUP_ALL:
/* Cleanup the UAR page resource pool, first the dbr pages */
if (state->hs_kern_dbr) {
}
/* NS then, the pool itself */
/* FALLTHROUGH */
/* Cleanup the central MCG handle pointers list */
/* FALLTHROUGH */
/* Cleanup the reference count resource pool */
/* FALLTHROUGH */
/* Cleanup the QP handle resource pool */
/* FALLTHROUGH */
/* Cleanup the address handle resrouce pool */
/* FALLTHROUGH */
/* Cleanup the SRQ handle resource pool. */
/* FALLTHROUGH */
/* Cleanup the CQ handle resource pool */
/* FALLTHROUGH */
/* Cleanup the EQ handle resource pool */
/* FALLTHROUGH */
/* Cleanup the MR handle resource pool */
/* FALLTHROUGH */
/* Cleanup the PD handle resource pool */
/* FALLTHROUGH */
/* Currently unused - FALLTHROUGH */
/* Cleanup the outstanding command list */
/* FALLTHROUGH */
/* Cleanup the EQC table resource pool */
/* FALLTHROUGH */
/* Cleanup the MCG table resource pool */
/* FALLTHROUGH */
/* Currently Unused - fallthrough */
/* Cleanup the SRQC table resource pool */
/* FALLTHROUGH */
/* Cleanup the AUXC table resource pool */
/* FALLTHROUGH */
/* Cleanup the ALTCF table resource pool */
/* FALLTHROUGH */
/* Cleanup the CQC table resource pool */
/* FALLTHROUGH */
/* Cleanup the RDB table resource pool */
/* FALLTHROUGH */
/* Cleanup the QPC table resource pool */
/* FALLTHROUGH */
/* Cleanup the cMPTs for the EQs, CQs, SRQs, and QPs */
/* FALLTHROUGH */
/* Cleanup the cMPTs for the EQs, CQs, SRQs, and QPs */
/* FALLTHROUGH */
/* Cleanup the cMPTs for the EQs, CQs, SRQs, and QPs */
/* FALLTHROUGH */
/* Cleanup the cMPTs for the EQs, CQs, SRQs, and QPs */
/* FALLTHROUGH */
/* Cleanup the dMPT table resource pool */
/* FALLTHROUGH */
/* Cleanup the MTT table resource pool */
break;
/*
* The cleanup below comes from the "Phase 1" initialization step.
* (see hermon_rsrc_init_phase1() above)
*/
/* Cleanup the "In" mailbox list */
/* FALLTHROUGH */
/* Cleanup the interrupt "In" mailbox resource pool */
/* FALLTHROUGH */
/* Cleanup the "In" mailbox list */
/* FALLTHROUGH */
/* Cleanup the "In" mailbox resource pool */
/* FALLTHROUGH */
/* Cleanup the interrupt "Out" mailbox list */
/* FALLTHROUGH */
/* Cleanup the "Out" mailbox resource pool */
/* FALLTHROUGH */
/* Cleanup the "Out" mailbox list */
/* FALLTHROUGH */
/* Cleanup the "Out" mailbox resource pool */
/* FALLTHROUGH */
/* Free the array of hermon_rsrc_pool_info_t's */
sizeof (hermon_rsrc_pool_info_t));
break;
default:
break;
}
}
/*
* hermon_rsrc_mbox_init()
* Context: Only called from attach() path context
*/
static int
{
/* Allocate and initialize mailbox private structure */
/*
* Initialize many of the default DMA attributes. Then set alignment
* and scatter-gather restrictions specific for mailbox memory.
*/
return (DDI_SUCCESS);
}
/*
* hermon_rsrc_mbox_fini()
*/
/* ARGSUSED */
static void
{
/* Free up the private struct */
}
/*
* hermon_rsrc_hw_entries_init()
* Context: Only called from attach() path context
*/
int
{
int status;
if (hermon_rsrc_verbose) {
"rsrc_type (0x%x) num (%llx) max (0x%llx) prealloc "
}
/* Make sure number of HW entries makes sense */
if (num_hwentry > max_hwentry) {
return (DDI_FAILURE);
}
/* Set this pool's rsrc_start from the initial ICM allocation */
if (rsrc_pool->rsrc_start == 0) {
/* use a ROUND value that works on both 32 and 64-bit kernels */
if (hermon_rsrc_verbose) {
" rsrc_type (0x%x) rsrc_start set (0x%lx)",
}
}
/*
* Create new vmem arena for the HW entries table if rsrc_quantum
* is non-zero. Otherwise if rsrc_quantum is zero, then these HW
* entries are not going to be dynamically allocatable (i.e. they
* won't be allocated/freed through hermon_rsrc_alloc/free). This
* latter option is used for both ALTC and CMPT resources which
* are managed by hardware.
*/
if (rsrc_pool->rsrc_quantum != 0) {
/* failed to create vmem arena */
return (DDI_FAILURE);
}
if (hermon_rsrc_verbose) {
" rsrc_type (0x%x) created vmem arena for rsrc",
}
} else {
/* we do not require a vmem arena */
if (hermon_rsrc_verbose) {
" rsrc_type (0x%x) vmem arena not required",
}
}
/* Allocate hardware reserved resources, if any */
if (num_prealloc != 0) {
if (status != DDI_SUCCESS) {
/* unable to preallocate the reserved entries */
}
return (DDI_FAILURE);
}
}
return (DDI_SUCCESS);
}
/*
* hermon_rsrc_hw_entries_fini()
*/
void
{
/* Free up any "reserved" (i.e. preallocated) HW entries */
}
/*
* If we've actually setup a vmem arena for the HW entries, then
* destroy it now
*/
}
}
/*
* hermon_rsrc_sw_handles_init()
* Context: Only called from attach() path context
*/
/* ARGSUSED */
static int
{
/* Make sure number of SW handles makes sense */
return (DDI_FAILURE);
}
/*
* Depending on the flags parameter, create a kmem_cache for some
* number of software handle structures. Note: kmem_cache_create()
* will SLEEP until successful.
*/
}
/* Allocate the central list of SW handle pointers */
KM_SLEEP);
}
return (DDI_SUCCESS);
}
/*
* hermon_rsrc_sw_handles_fini()
*/
/* ARGSUSED */
static void
{
/*
* If a "software handle" kmem_cache exists for this resource, then
* destroy it now
*/
}
/* Free up this central list of SW handle pointers */
}
}
/*
* hermon_rsrc_pd_handles_init()
* Context: Only called from attach() path context
*/
static int
{
int status;
/* Initialize the resource pool for software handle table */
if (status != DDI_SUCCESS) {
return (DDI_FAILURE);
}
/* Build vmem arena name from Hermon instance */
/* Create new vmem arena for PD numbers */
/* Unable to create vmem arena */
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
/*
* hermon_rsrc_pd_handles_fini()
*/
static void
{
/* Destroy the specially created UAR scratch table vmem arena */
/* Destroy the "hermon_sw_pd_t" kmem_cache */
}
/*
* hermon_rsrc_mbox_alloc()
* Context: Only called from attach() path context
*/
static int
{
int status;
/* Get the private pointer for the mailboxes */
/* Allocate a DMA handle for the mailbox */
if (status != DDI_SUCCESS) {
return (DDI_FAILURE);
}
/* Allocate memory for the mailbox */
if (status != DDI_SUCCESS) {
/* No more memory available for mailbox entries */
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
/*
* hermon_rsrc_mbox_free()
* Context: Can be called from interrupt or base context.
*/
static void
{
/* Use ddi_dma_mem_free() to free up sys memory for mailbox */
/* Free the DMA handle for the mailbox */
}
/*
* hermon_rsrc_hw_entry_alloc()
* Context: Can be called from interrupt or base context.
*/
static int
{
void *addr;
int status;
int flag;
/*
* Use vmem_xalloc() to get a properly aligned pointer (based on
* the number requested) to the HW entry(ies). This handles the
* cases (for special QPCs and for RDB entries) where we need more
* than one and need to ensure that they are properly aligned.
*/
/* No more HW entries available */
return (DDI_FAILURE);
}
/* Calculate vaddr and HW table index */
int num_to_hdl;
/* confirm ICM is mapped, and allocate if necessary */
if (status != DDI_SUCCESS) {
return (DDI_FAILURE);
}
}
return (DDI_SUCCESS);
}
/*
* hermon_rsrc_hw_entry_reserve()
* Context: Can be called from interrupt or base context.
*/
int
{
void *addr;
int flag;
/*
* Use vmem_xalloc() to get a properly aligned pointer (based on
* the number requested) to the HW entry(ies). This handles the
* cases (for special QPCs and for RDB entries) where we need more
* than one and need to ensure that they are properly aligned.
*/
/* No more HW entries available */
return (DDI_FAILURE);
}
/* Calculate vaddr and HW table index */
/* ICM will be allocated and mapped if and when it gets used */
return (DDI_SUCCESS);
}
/*
* hermon_rsrc_hw_entry_free()
* Context: Can be called from interrupt or base context.
*/
static void
{
void *addr;
int status;
/* Calculate the allocated address */
/* Use vmem_xfree() to free up the HW table entry */
int num_to_hdl;
/* free ICM references, and free ICM if required */
if (status != DDI_SUCCESS)
"failure in hw_entry_free");
}
}
/*
* hermon_rsrc_hw_entry_icm_confirm()
* Context: Can be called from interrupt or base context.
*/
static int
{
int num_backed;
int status;
/*
* Utility routine responsible for ensuring that there is memory
* backing the ICM resources allocated via hermon_rsrc_hw_entry_alloc().
* Confirm existing ICM mapping(s) or allocate ICM memory for the
* given hardware resources being allocated, and increment the
* ICM DMA structure(s) reference count.
*
* We may be allocating more objects than can fit in a single span,
* or more than will fit in the remaining contiguous memory (from
* the offset indicated by hdl->ar_indx) in the span in question.
* In either of these cases, we'll be breaking up our allocation
* into multiple spans.
*/
if (hermon_rsrc_verbose) {
"type (0x%x) num (0x%x) length (0x%x) index (0x%x, 0x%x): ",
}
while (num) {
#ifndef __lock_lint
}
#endif
/* Allocate ICM for this span */
if (status != DDI_SUCCESS) {
goto fail_alloc;
}
if (hermon_rsrc_verbose) {
"hw_entry_icm_confirm: ALLOCATED ICM: "
"type (0x%x) index (0x%x, 0x%x)",
}
}
/*
* We need to increment the refcnt of this span by the
* number of objects in this resource allocation that are
* backed by this span. Given that the rsrc allocation is
* contiguous, this value will be the number of objects in
* the span from 'span_offset' onward, either up to a max
* of the total number of objects, or the end of the span.
* So, determine the number of objects that can be backed
* by this span ('span_avail'), then determine the number
* of backed resources.
*/
if (num > span_avail) {
} else {
num_backed = num;
}
/*
* Now that we know 'num_backed', increment the refcnt,
* decrement the total number, and set 'span_offset' to
* 0 in case we roll over into the next span.
*/
rindx += num_backed;
num -= num_backed;
if (hermon_rsrc_verbose) {
"(0x%x, 0x%x) num_backed (0x%x)",
"(0x%x) num_remaining (0x%x)", type,
}
if (num == 0)
break;
}
return (DDI_SUCCESS);
/* JBDB */
if (hermon_rsrc_verbose) {
"hw_entry_icm_confirm: FAILED ICM ALLOC: "
"type (0x%x) num remaind (0x%x) index (0x%x, 0x%x)"
}
"unimplemented fail code in hermon_rsrc_hw_entry_icm_alloc\n");
#if needs_work
/* free refcnt's and any spans we've allocated */
/*
* JBDB - This is a bit tricky. We need to
* free refcnt's on any spans that we've
* incremented them on, and completely free
* spans that we've allocated. How do we do
* this here? Does it need to be as involved
* as the core of icm_free() below, or can
* we leverage breadcrumbs somehow?
*/
"UNIMPLEMENTED HANDLING!!");
}
#else
"unimplemented fail code in hermon_rsrc_hw_entry_icm_alloc\n");
#endif
return (DDI_FAILURE);
}
/*
* hermon_rsrc_hw_entry_icm_free()
* Context: Can be called from interrupt or base context.
*/
static int
{
int num_freed;
int num;
/*
* Utility routine responsible for freeing references to ICM
* DMA spans, and freeing the ICM memory if necessary.
*
* We may have allocated objects in a single contiguous resource
* allocation that reside in a number of spans, at any given
* starting offset within a span. We therefore must determine
* where this allocation starts, and then determine if we need
* to free objects in more than one span.
*/
/* determine the number of ICM objects in this allocation */
if (hermon_rsrc_verbose) {
"type (0x%x) num (0x%x) length (0x%x) index (0x%x, 0x%x)",
}
while (num) {
/*
* As with the ICM confirm code above, we need to
* decrement the ICM span(s) by the number of
* resources being freed. So, determine the number
* of objects that are backed in this span from
* 'span_offset' onward, and set 'num_freed' to
* the smaller of either that number ('span_remain'),
* or the total number of objects being freed.
*/
if (num > span_remain) {
} else {
}
/*
* Now that we know 'num_freed', decrement the refcnt,
* decrement the total number, and set 'span_offset' to
* 0 in case we roll over into the next span.
*/
if (hermon_rsrc_verbose) {
"(0x%x, 0x%x) num_freed (0x%x)", type,
"(0x%x) num remaining (0x%x)", type,
}
/* If we've freed the last object in this span, free it */
if (hermon_rsrc_verbose) {
"_icm_free: freeing ICM type (0x%x) index"
}
}
#endif
if (num == 0)
break;
}
return (DDI_SUCCESS);
}
/*
* hermon_rsrc_swhdl_alloc()
* Context: Can be called from interrupt or base context.
*/
static int
{
void *addr;
int flag;
/* Allocate the software handle structure */
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
/*
* hermon_rsrc_swhdl_free()
* Context: Can be called from interrupt or base context.
*/
static void
{
/* Free the software handle structure */
}
/*
* hermon_rsrc_pdhdl_alloc()
* Context: Can be called from interrupt or base context.
*/
static int
{
void *tmpaddr;
/* Allocate the software handle */
if (status != DDI_SUCCESS) {
return (DDI_FAILURE);
}
/* Allocate a PD number for the handle */
/* No more PD number entries available */
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
/*
* hermon_rsrc_pdhdl_free()
* Context: Can be called from interrupt or base context.
*/
static void
{
/* Use vmem_free() to free up the PD number */
/* Free the software handle structure */
}
/*
* hermon_rsrc_pdhdl_constructor()
* Context: Can be called from interrupt or base context.
*/
/* ARGSUSED */
static int
{
return (DDI_SUCCESS);
}
/*
* hermon_rsrc_pdhdl_destructor()
* Context: Can be called from interrupt or base context.
*/
/* ARGSUSED */
static void
{
}
/*
* hermon_rsrc_cqhdl_constructor()
* Context: Can be called from interrupt or base context.
*/
/* ARGSUSED */
static int
{
return (DDI_SUCCESS);
}
/*
* hermon_rsrc_cqhdl_destructor()
* Context: Can be called from interrupt or base context.
*/
/* ARGSUSED */
static void
{
}
/*
* hermon_rsrc_qphdl_constructor()
* Context: Can be called from interrupt or base context.
*/
/* ARGSUSED */
static int
{
return (DDI_SUCCESS);
}
/*
* hermon_rsrc_qphdl_destructor()
* Context: Can be called from interrupt or base context.
*/
/* ARGSUSED */
static void
{
}
/*
* hermon_rsrc_srqhdl_constructor()
* Context: Can be called from interrupt or base context.
*/
/* ARGSUSED */
static int
{
return (DDI_SUCCESS);
}
/*
* hermon_rsrc_srqhdl_destructor()
* Context: Can be called from interrupt or base context.
*/
/* ARGSUSED */
static void
{
}
/*
* hermon_rsrc_refcnt_constructor()
* Context: Can be called from interrupt or base context.
*/
/* ARGSUSED */
static int
{
return (DDI_SUCCESS);
}
/*
* hermon_rsrc_refcnt_destructor()
* Context: Can be called from interrupt or base context.
*/
/* ARGSUSED */
static void
{
}
/*
* hermon_rsrc_ahhdl_constructor()
* Context: Can be called from interrupt or base context.
*/
/* ARGSUSED */
static int
{
return (DDI_SUCCESS);
}
/*
* hermon_rsrc_ahhdl_destructor()
* Context: Can be called from interrupt or base context.
*/
/* ARGSUSED */
static void
{
}
/*
* hermon_rsrc_mrhdl_constructor()
* Context: Can be called from interrupt or base context.
*/
/* ARGSUSED */
static int
{
return (DDI_SUCCESS);
}
/*
* hermon_rsrc_mrhdl_destructor()
* Context: Can be called from interrupt or base context.
*/
/* ARGSUSED */
static void
{
}
/*
* hermon_rsrc_mcg_entry_get_size()
*/
static int
{
/*
* Round the configured number of QP per MCG to next larger
* power-of-2 size and update.
*/
if (ISP2(num_qp_per_mcg)) {
}
/* Now make sure number of QP per MCG makes sense */
if (num_qp_per_mcg > max_qp_per_mcg) {
return (DDI_FAILURE);
}
/* Return the (shift) size of an individual MCG HW entry */
return (DDI_SUCCESS);
}