/*
* 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 Userland Mapping Routines
*
* Implements all the routines necessary for enabling direct userland
* access to the Hermon hardware. This includes all routines necessary for
* maintaining the "userland resources database" and all the support routines
* for the devmap calls.
*/
#include <sys/sysmacros.h>
/* Hermon HCA state pointer (extern) */
extern void *hermon_statep;
/* Hermon HCA Userland Resource Database (extern) */
/*
* These callbacks are passed to devmap_umem_setup() and devmap_devmem_setup(),
* respectively. They are used to handle (among other things) partial
* unmappings and to provide a method for invalidating mappings inherited
* as a result of a fork(2) system call.
*/
NULL,
};
NULL,
};
NULL,
};
/*
* hermon_devmap()
* Context: Can be called from user context.
*/
/* ARGSUSED */
int
{
/* Get Hermon softstate structure from instance */
return (ENXIO);
}
/*
* Access to Hermon devmap interface is not allowed in
* "maintenance mode".
*/
return (EFAULT);
}
/*
* The bottom bits of "offset" are undefined (number depends on
* system PAGESIZE). Shifting these off leaves us with a "key".
* The "key" is actually a combination of both a real key value
* (for the purpose of database lookup) and a "type" value. We
* extract this information before doing the database lookup.
*/
if (type == MLNX_UMAP_BLUEFLAMEPG_RSRC) {
return (EFAULT);
}
}
if (status == DDI_SUCCESS) {
switch (type) {
case MLNX_UMAP_UARPG_RSRC:
/*
* Double check that process who open()'d Hermon is
* same process attempting to mmap() UAR page.
*/
if (key != ddi_get_pid()) {
return (EINVAL);
}
/* Map the UAR page out for userland access */
if (status != DDI_SUCCESS) {
return (err);
}
break;
case MLNX_UMAP_CQMEM_RSRC:
/* Map the CQ memory out for userland access */
if (status != DDI_SUCCESS) {
return (err);
}
break;
case MLNX_UMAP_QPMEM_RSRC:
/* Map the QP memory out for userland access */
if (status != DDI_SUCCESS) {
return (err);
}
break;
case MLNX_UMAP_SRQMEM_RSRC:
/* Map the SRQ memory out for userland access */
if (status != DDI_SUCCESS) {
return (err);
}
break;
case MLNX_UMAP_DBRMEM_RSRC:
/*
* Map the doorbell record memory out for
* userland access
*/
if (status != DDI_SUCCESS) {
return (err);
}
break;
default:
return (EINVAL);
}
} else {
return (EINVAL);
}
return (0);
}
/*
* hermon_umap_uarpg()
* Context: Can be called from user context.
*/
static int
{
int status;
if (offset != 0) { /* Hermon Blueflame */
/* Try to use write coalescing data ordering */
}
/* Map out the UAR page (doorbell page) */
accattrp);
if (status < 0) {
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
/*
* hermon_umap_cqmem()
* Context: Can be called from user context.
*/
/* ARGSUSED */
static int
{
int status;
/* Extract the Hermon CQ handle pointer from the hermon_rsrc_t */
/* Round-up the CQ size to system page size */
/* Map out the CQ memory - use resize_hdl if non-NULL */
if (status < 0) {
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
/*
* hermon_umap_qpmem()
* Context: Can be called from user context.
*/
/* ARGSUSED */
static int
{
int status;
/* Extract the Hermon QP handle pointer from the hermon_rsrc_t */
/*
* Calculate the offset of the first work queue (send or recv) into
* the memory (ddi_umem_alloc()) allocated previously for the QP.
*/
/* Round-up the QP work queue sizes to system page size */
/* Map out the QP memory */
if (status < 0) {
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
/*
* hermon_umap_srqmem()
* Context: Can be called from user context.
*/
/* ARGSUSED */
static int
{
int status;
/* Extract the Hermon SRQ handle pointer from the hermon_rsrc_t */
/*
* Calculate the offset of the first shared recv queue into the memory
* (ddi_umem_alloc()) allocated previously for the SRQ.
*/
/* Round-up the SRQ work queue sizes to system page size */
/* Map out the SRQ memory */
if (status < 0) {
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
/*
* hermon_devmap_dbrecmem()
* Context: Can be called from user context.
*/
/* ARGSUSED */
static int
{
int status;
/* We stored the udbr_page pointer, and not a hermon_rsrc_t */
/*
* Calculate the offset of the doorbell records into the memory
* (ddi_umem_alloc()) allocated previously for them.
*/
offset = 0;
/* Round-up the doorbell page to system page size */
/* Map out the Doorbell Record memory */
if (status < 0) {
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
/*
* hermon_devmap_umem_map()
* Context: Can be called from kernel context.
*/
/* ARGSUSED */
static int
{
/* Get Hermon softstate structure from instance */
return (ENXIO);
}
/*
* The bottom bits of "offset" are undefined (number depends on
* system PAGESIZE). Shifting these off leaves us with a "key".
* The "key" is actually a combination of both a real key value
* (for the purpose of database lookup) and a "type" value. Although
* we are not going to do any database lookup per se, we do want
* to extract the "key" and the "type" (to enable faster lookup of
* the appropriate CQ or QP handle).
*/
/*
* Allocate an entry to track the mapping and unmapping (specifically,
* partial unmapping) of this resource.
*/
sizeof (hermon_devmap_track_t), KM_SLEEP);
/*
* Depending of the type of resource that has been mapped out, we
* need to update the QP or CQ handle to reflect that it has, in
* fact, been mapped. This allows the driver code which frees a QP
* or a CQ to know whether it is appropriate to do a
* devmap_devmem_remap() to invalidate the userland mapping for the
* corresponding queue's memory.
*/
if (type == MLNX_UMAP_CQMEM_RSRC) {
/* Use "key" (CQ number) to do fast lookup of CQ handle */
/*
* Update the handle to the userland mapping. Note: If
* the CQ already has a valid userland mapping, then stop
* and return failure.
*/
} else if (cq->cq_resize_hdl &&
} else {
goto umem_map_fail;
}
} else if (type == MLNX_UMAP_QPMEM_RSRC) {
/* Use "key" (QP number) to do fast lookup of QP handle */
/*
* Update the handle to the userland mapping. Note: If
* the CQ already has a valid userland mapping, then stop
* and return failure.
*/
} else {
goto umem_map_fail;
}
} else if (type == MLNX_UMAP_SRQMEM_RSRC) {
/* Use "key" (SRQ number) to do fast lookup on SRQ handle */
/*
* Update the handle to the userland mapping. Note: If the
* SRQ already has a valid userland mapping, then stop and
* return failure.
*/
} else {
goto umem_map_fail;
}
}
/*
* Pass the private "Hermon devmap tracking structure" back. This
* pointer will be returned in subsequent "unmap" callbacks.
*/
return (DDI_SUCCESS);
return (DDI_FAILURE);
}
/*
* hermon_devmap_umem_dup()
* Context: Can be called from kernel context.
*/
/* ARGSUSED */
static int
void **new_pvtp)
{
int status;
/*
* Extract the Hermon softstate pointer from "Hermon devmap tracking
* structure" (in "pvtp").
*/
/*
* Since this devmap_dup() entry point is generally called
* when a process does fork(2), it is incumbent upon the driver
* to insure that the child does not inherit a valid copy of
* the parent's QP or CQ resource. This is accomplished by using
* devmap_devmem_remap() to invalidate the child's mapping to the
* kernel memory.
*/
if (status != DDI_SUCCESS) {
return (status);
}
/*
* Allocate a new entry to track the subsequent unmapping
* (specifically, all partial unmappings) of the child's newly
* invalidated resource. Note: Setting the "hdt_size" field to
* zero here is an indication to the devmap_unmap() entry point
* that this mapping is invalid, and that its subsequent unmapping
* should not affect any of the parent's CQ or QP resources.
*/
sizeof (hermon_devmap_track_t), KM_SLEEP);
new_dvm_track->hdt_offset = 0;
new_dvm_track->hdt_size = 0;
return (DDI_SUCCESS);
}
/*
* hermon_devmap_umem_unmap()
* Context: Can be called from kernel context.
*/
/* ARGSUSED */
static void
{
int status;
/*
* Extract the Hermon softstate pointer from "Hermon devmap tracking
* structure" (in "pvtp").
*/
/*
* Extract the "offset" from the "Hermon devmap tracking structure".
* Note: The input argument "off" is ignored here because the
* Hermon mapping interfaces define a very specific meaning to
* each "logical offset". Also extract the "key" and "type" encoded
* in the logical offset.
*/
/*
* Extract the "size" of the mapping. If this size is determined
* to be zero, then it is an indication of a previously invalidated
* mapping, and no CQ or QP resources should be affected.
*/
/*
* If only the "middle portion of a given mapping is being unmapped,
* then we are effectively creating one new piece of mapped memory.
* (Original region is divided into three pieces of which the middle
* piece is being removed. This leaves two pieces. Since we started
* with one piece and now have two pieces, we need to increment the
* counter in the "Hermon devmap tracking structure".
*
* If, however, the whole mapped region is being unmapped, then we
* have started with one region which we are completely removing.
* In this case, we need to decrement the counter in the "Hermon
* devmap tracking structure".
*
* In each of the remaining cases, we will have started with one
* mapped region and ended with one (different) region. So no counter
* modification is necessary.
*/
dvm_track->hdt_refcnt--;
dvm_track->hdt_refcnt++;
}
/*
* For each of the cases where the region is being divided, then we
* need to pass back the "Hermon devmap tracking structure". This way
* we get it back when each of the remaining pieces is subsequently
* unmapped.
*/
}
}
/*
* If the "Hermon devmap tracking structure" is no longer being
* referenced, then free it up. Otherwise, return.
*/
if (dvm_track->hdt_refcnt == 0) {
/*
* If the mapping was invalid (see explanation above), then
* no further processing is necessary.
*/
if (size == 0) {
return;
}
} else {
return;
}
/*
* Now that we can guarantee that the user memory is fully unmapped,
* we can use the "key" and "type" values to try to find the entry
* in the "userland resources database". If it's found, then it
* indicates that the queue memory (CQ or QP) has not yet been freed.
* In this case, we update the corresponding CQ or QP handle to
* indicate that the "devmap_devmem_remap()" call will be unnecessary.
* If it's _not_ found, then it indicates that the CQ or QP memory
* was, in fact, freed before it was unmapped (thus requiring a
* previous invalidation by remapping - which will already have
* been done in the free routine).
*/
0, NULL);
if (status == DDI_SUCCESS) {
/*
* Depending on the type of the mapped resource (CQ or QP),
* update handle to indicate that no invalidation remapping
* will be necessary.
*/
if (type == MLNX_UMAP_CQMEM_RSRC) {
/* Use "value" to convert to CQ handle */
/*
* Invalidate the handle to the userland mapping.
* Note: We must ensure that the mapping being
* unmapped here is the current one for the CQ. It
* is possible that it might not be if this CQ has
* been resized and the previous CQ memory has not
* yet been unmapped. But in that case, because of
* the devmap_devmem_remap(), there is no longer any
* association between the mapping and the real CQ
* kernel memory.
*/
if (cq->cq_resize_hdl) {
/* resize is DONE, switch queues */
}
} else {
if (cq->cq_resize_hdl &&
/*
* Unexpected case. munmap of the
* cq_resize buf, and not the
* original buf.
*/
}
}
} else if (type == MLNX_UMAP_QPMEM_RSRC) {
/* Use "value" to convert to QP handle */
/*
* Invalidate the handle to the userland mapping.
* Note: we ensure that the mapping being unmapped
* here is the current one for the QP. This is
* more of a sanity check here since, unlike CQs
* (above) we do not support resize of QPs.
*/
}
} else if (type == MLNX_UMAP_SRQMEM_RSRC) {
/* Use "value" to convert to SRQ handle */
/*
* Invalidate the handle to the userland mapping.
* Note: we ensure that the mapping being unmapped
* here is the current one for the QP. This is
* more of a sanity check here since, unlike CQs
* (above) we do not support resize of QPs.
*/
}
}
}
}
/*
* hermon_devmap_devmem_map()
* Context: Can be called from kernel context.
*/
/* ARGSUSED */
static int
{
/* Get Hermon softstate structure from instance */
return (ENXIO);
}
/*
* The bottom bits of "offset" are undefined (number depends on
* system PAGESIZE). Shifting these off leaves us with a "key".
* The "key" is actually a combination of both a real key value
* (for the purpose of database lookup) and a "type" value. Although
* we are not going to do any database lookup per se, we do want
* to extract the "key" and the "type" (to enable faster lookup of
* the appropriate CQ or QP handle).
*/
/*
* Allocate an entry to track the mapping and unmapping (specifically,
* partial unmapping) of this resource.
*/
sizeof (hermon_devmap_track_t), KM_SLEEP);
/*
* Depending of the type of resource that has been mapped out, we
* need to update the QP or CQ handle to reflect that it has, in
* fact, been mapped. This allows the driver code which frees a QP
* or a CQ to know whether it is appropriate to do a
* devmap_devmem_remap() to invalidate the userland mapping for the
* corresponding queue's memory.
*/
if (type == MLNX_UMAP_CQMEM_RSRC) {
/* Use "key" (CQ number) to do fast lookup of CQ handle */
/*
* Update the handle to the userland mapping. Note: If
* the CQ already has a valid userland mapping, then stop
* and return failure.
*/
} else {
goto umem_map_fail;
}
} else if (type == MLNX_UMAP_QPMEM_RSRC) {
/* Use "key" (QP number) to do fast lookup of QP handle */
/*
* Update the handle to the userland mapping. Note: If
* the CQ already has a valid userland mapping, then stop
* and return failure.
*/
} else {
goto umem_map_fail;
}
} else if (type == MLNX_UMAP_SRQMEM_RSRC) {
/* Use "key" (SRQ number) to do fast lookup on SRQ handle */
/*
* Update the handle to the userland mapping. Note: If the
* SRQ already has a valid userland mapping, then stop and
* return failure.
*/
} else {
goto umem_map_fail;
}
}
/*
* Pass the private "Hermon devmap tracking structure" back. This
* pointer will be returned in subsequent "unmap" callbacks.
*/
return (DDI_SUCCESS);
return (DDI_FAILURE);
}
/*
* hermon_devmap_dbrecmem_dup()
* Context: Can be called from kernel context.
*/
/* ARGSUSED */
static int
{
int status;
/*
* Extract the Hermon softstate pointer from "Hermon devmap tracking
* structure" (in "pvtp").
*/
/*
* Since this devmap_dup() entry point is generally called
* when a process does fork(2), it is incumbent upon the driver
* to insure that the child does not inherit a valid copy of
* the parent's QP or CQ resource. This is accomplished by using
* devmap_devmem_remap() to invalidate the child's mapping to the
* kernel memory.
*/
if (status != DDI_SUCCESS) {
return (status);
}
/*
* Allocate a new entry to track the subsequent unmapping
* (specifically, all partial unmappings) of the child's newly
* invalidated resource. Note: Setting the "hdt_size" field to
* zero here is an indication to the devmap_unmap() entry point
* that this mapping is invalid, and that its subsequent unmapping
* should not affect any of the parent's CQ or QP resources.
*/
sizeof (hermon_devmap_track_t), KM_SLEEP);
new_dvm_track->hdt_offset = 0;
new_dvm_track->hdt_size = 0;
return (DDI_SUCCESS);
}
/*
* hermon_devmap_dbrecmem_unmap()
* Context: Can be called from kernel context.
*/
/* ARGSUSED */
static void
{
int status;
/*
* Extract the Hermon softstate pointer from "Hermon devmap tracking
* structure" (in "pvtp").
*/
/*
* Extract the "offset" from the "Hermon devmap tracking structure".
* Note: The input argument "off" is ignored here because the
* Hermon mapping interfaces define a very specific meaning to
* each "logical offset". Also extract the "key" and "type" encoded
* in the logical offset.
*/
/*
* Extract the "size" of the mapping. If this size is determined
* to be zero, then it is an indication of a previously invalidated
* mapping, and no CQ or QP resources should be affected.
*/
/*
* If only the "middle portion of a given mapping is being unmapped,
* then we are effectively creating one new piece of mapped memory.
* (Original region is divided into three pieces of which the middle
* piece is being removed. This leaves two pieces. Since we started
* with one piece and now have two pieces, we need to increment the
* counter in the "Hermon devmap tracking structure".
*
* If, however, the whole mapped region is being unmapped, then we
* have started with one region which we are completely removing.
* In this case, we need to decrement the counter in the "Hermon
* devmap tracking structure".
*
* In each of the remaining cases, we will have started with one
* mapped region and ended with one (different) region. So no counter
* modification is necessary.
*/
dvm_track->hdt_refcnt--;
dvm_track->hdt_refcnt++;
}
/*
* For each of the cases where the region is being divided, then we
* need to pass back the "Hermon devmap tracking structure". This way
* we get it back when each of the remaining pieces is subsequently
* unmapped.
*/
}
}
/*
* If the "Hermon devmap tracking structure" is no longer being
* referenced, then free it up. Otherwise, return.
*/
if (dvm_track->hdt_refcnt == 0) {
/*
* If the mapping was invalid (see explanation above), then
* no further processing is necessary.
*/
if (size == 0) {
return;
}
} else {
return;
}
/*
* Now that we can guarantee that the user memory is fully unmapped,
* we can use the "key" and "type" values to try to find the entry
* in the "userland resources database". If it's found, then it
* indicates that the queue memory (CQ or QP) has not yet been freed.
* In this case, we update the corresponding CQ or QP handle to
* indicate that the "devmap_devmem_remap()" call will be unnecessary.
* If it's _not_ found, then it indicates that the CQ or QP memory
* was, in fact, freed before it was unmapped (thus requiring a
* previous invalidation by remapping - which will already have
* been done in the free routine).
*/
0, NULL);
if (status == DDI_SUCCESS) {
/*
* Depending on the type of the mapped resource (CQ or QP),
* update handle to indicate that no invalidation remapping
* will be necessary.
*/
if (type == MLNX_UMAP_CQMEM_RSRC) {
/* Use "value" to convert to CQ handle */
/*
* Invalidate the handle to the userland mapping.
* Note: We must ensure that the mapping being
* unmapped here is the current one for the CQ. It
* is possible that it might not be if this CQ has
* been resized and the previous CQ memory has not
* yet been unmapped. But in that case, because of
* the devmap_devmem_remap(), there is no longer any
* association between the mapping and the real CQ
* kernel memory.
*/
}
} else if (type == MLNX_UMAP_QPMEM_RSRC) {
/* Use "value" to convert to QP handle */
/*
* Invalidate the handle to the userland mapping.
* Note: we ensure that the mapping being unmapped
* here is the current one for the QP. This is
* more of a sanity check here since, unlike CQs
* (above) we do not support resize of QPs.
*/
}
} else if (type == MLNX_UMAP_SRQMEM_RSRC) {
/* Use "value" to convert to SRQ handle */
/*
* Invalidate the handle to the userland mapping.
* Note: we ensure that the mapping being unmapped
* here is the current one for the QP. This is
* more of a sanity check here since, unlike CQs
* (above) we do not support resize of QPs.
*/
}
}
}
}
/*
* hermon_devmap_devmem_map()
* Context: Can be called from kernel context.
*/
/* ARGSUSED */
static int
{
/* Get Hermon softstate structure from instance */
return (ENXIO);
}
/*
* Allocate an entry to track the mapping and unmapping of this
* resource. Note: We don't need to initialize the "refcnt" or
* "offset" fields here, nor do we need to initialize the mutex
* used with the "refcnt". Since UAR pages are single pages, they
* are not subject to "partial" unmappings. This makes these other
* fields unnecessary.
*/
sizeof (hermon_devmap_track_t), KM_SLEEP);
/*
* Pass the private "Hermon devmap tracking structure" back. This
* pointer will be returned in a subsequent "unmap" callback.
*/
return (DDI_SUCCESS);
}
/*
* hermon_devmap_devmem_dup()
* Context: Can be called from kernel context.
*/
/* ARGSUSED */
static int
{
int status;
/*
* Extract the Hermon softstate pointer from "Hermon devmap tracking
* structure" (in "pvtp"). Note: If the tracking structure is NULL
* here, it means that the mapping corresponds to an invalid mapping.
* In this case, it can be safely ignored ("new_pvtp" set to NULL).
*/
return (DDI_SUCCESS);
}
/*
* Since this devmap_dup() entry point is generally called
* when a process does fork(2), it is incumbent upon the driver
* to insure that the child does not inherit a valid copy of
* the parent's resource. This is accomplished by using
* devmap_devmem_remap() to invalidate the child's mapping to the
* kernel memory.
*/
if (status != DDI_SUCCESS) {
return (status);
}
/*
* Since the region is invalid, there is no need for us to
* allocate and continue to track an additional "Hermon devmap
* tracking structure". Instead we return NULL here, which is an
* indication to the devmap_unmap() entry point that this entry
* can be safely ignored.
*/
return (DDI_SUCCESS);
}
/*
* hermon_devmap_devmem_unmap()
* Context: Can be called from kernel context.
*/
/* ARGSUSED */
static void
{
/*
* Free up the "Hermon devmap tracking structure" (in "pvtp").
* There cannot be "partial" unmappings here because all UAR pages
* are single pages. Note: If the tracking structure is NULL here,
* it means that the mapping corresponds to an invalid mapping. In
* this case, it can be safely ignored.
*/
return;
}
}
/*
* hermon_umap_ci_data_in()
* Context: Can be called from user or kernel context.
*/
/* ARGSUSED */
{
int status;
/*
* Depending on the type of object about which additional information
* is being provided (currently only MR is supported), we call the
* appropriate resource-specific function.
*/
switch (object) {
case IBT_HDL_MR:
if (status != DDI_SUCCESS) {
return (status);
}
break;
/*
* For other possible valid IBT types, we return IBT_NOT_SUPPORTED,
* since the Hermon driver does not support these.
*/
case IBT_HDL_HCA:
case IBT_HDL_QP:
case IBT_HDL_CQ:
case IBT_HDL_PD:
case IBT_HDL_MW:
case IBT_HDL_AH:
case IBT_HDL_SCHED:
case IBT_HDL_EEC:
case IBT_HDL_RDD:
case IBT_HDL_SRQ:
return (IBT_NOT_SUPPORTED);
/*
* Any other types are invalid.
*/
default:
return (IBT_INVALID_PARAM);
}
return (DDI_SUCCESS);
}
/*
* hermon_umap_mr_data_in()
* Context: Can be called from user or kernel context.
*/
static ibt_status_t
{
return (IBT_NOT_SUPPORTED);
}
/* Check for valid MR handle pointer */
return (IBT_MR_HDL_INVALID);
}
/* Check for valid MR input structure size */
if (data_sz < sizeof (ibt_mr_data_in_t)) {
return (IBT_INSUFF_RESOURCE);
}
/*
* Ensure that the MR corresponds to userland memory and that it is
* a currently valid memory region as well.
*/
return (IBT_MR_HDL_INVALID);
}
/*
* If it has passed all the above checks, then extract the callback
* function and argument from the input structure. Copy them into
* the MR handle. This function will be called only if the memory
* corresponding to the MR handle gets a umem_lockmemory() callback.
*/
return (DDI_SUCCESS);
}
/*
* hermon_umap_ci_data_out()
* Context: Can be called from user or kernel context.
*/
/* ARGSUSED */
{
int status;
/*
* Depending on the type of object about which additional information
* is being requested (CQ or QP), we call the appropriate resource-
* specific mapping function.
*/
switch (object) {
case IBT_HDL_CQ:
if (status != DDI_SUCCESS) {
return (status);
}
break;
case IBT_HDL_QP:
if (status != DDI_SUCCESS) {
return (status);
}
break;
case IBT_HDL_SRQ:
if (status != DDI_SUCCESS) {
return (status);
}
break;
case IBT_HDL_PD:
if (status != DDI_SUCCESS) {
return (status);
}
break;
/*
* For other possible valid IBT types, we return IBT_NOT_SUPPORTED,
* since the Hermon driver does not support these.
*/
case IBT_HDL_HCA:
case IBT_HDL_MR:
case IBT_HDL_MW:
case IBT_HDL_AH:
case IBT_HDL_SCHED:
case IBT_HDL_EEC:
case IBT_HDL_RDD:
return (IBT_NOT_SUPPORTED);
/*
* Any other types are invalid.
*/
default:
return (IBT_INVALID_PARAM);
}
return (DDI_SUCCESS);
}
/*
* hermon_umap_cq_data_out()
* Context: Can be called from user or kernel context.
*/
static ibt_status_t
{
/* Check for valid CQ handle pointer */
return (IBT_CQ_HDL_INVALID);
}
/* Check for valid CQ mapping structure size */
if (data_sz < sizeof (mlnx_umap_cq_data_out_t)) {
return (IBT_INSUFF_RESOURCE);
}
/* deal with cq_alloc() verses cq_resize() */
if (cq->cq_resize_hdl) {
} else {
}
/*
* If it has passed all the above checks, then fill in all the useful
* mapping information (including the mapping offset that will be
* passed back to the devmap() interface during a subsequent mmap()
* call.
*
* The "offset" for CQ mmap()'s looks like this:
* +----------------------------------------+--------+--------------+
* | CQ Number | 0x33 | Reserved (0) |
* +----------------------------------------+--------+--------------+
* (64 - 8 - PAGESHIFT) bits 8 bits PAGESHIFT bits
*
* This returns information about the mapping offset, the length of
* the CQ memory, the CQ number (for use in later CQ doorbells), the
* number of CQEs the CQ memory can hold, and the size of each CQE.
*/
/* doorbell record fields */
return (DDI_SUCCESS);
}
/*
* hermon_umap_qp_data_out()
* Context: Can be called from user or kernel context.
*/
static ibt_status_t
{
/* Check for valid QP handle pointer */
return (IBT_QP_HDL_INVALID);
}
/* Check for valid QP mapping structure size */
if (data_sz < sizeof (mlnx_umap_qp_data_out_t)) {
return (IBT_INSUFF_RESOURCE);
}
/*
* If it has passed all the checks, then fill in all the useful
* mapping information (including the mapping offset that will be
* passed back to the devmap() interface during a subsequent mmap()
* call.
*
* The "offset" for QP mmap()'s looks like this:
* +----------------------------------------+--------+--------------+
* | QP Number | 0x44 | Reserved (0) |
* +----------------------------------------+--------+--------------+
* (64 - 8 - PAGESHIFT) bits 8 bits PAGESHIFT bits
*
* This returns information about the mapping offset, the length of
* the QP memory, and the QP number (for use in later send and recv
* doorbells). It also returns the following information for both
* the receive work queue and the send work queue, respectively: the
* offset (from the base mapped address) of the start of the given
* work queue, the 64-bit IB virtual address that corresponds to
* the base mapped address (needed for posting WQEs though the
* QP doorbells), the number of WQEs the given work queue can hold,
* and the size of each WQE for the given work queue.
*/
/*
* If this QP is associated with a shared receive queue (SRQ),
* then return invalid RecvQ parameters. Otherwise, return
* the proper parameter values.
*/
data->mqp_rq_numwqe = 0;
data->mqp_rq_wqesz = 0;
data->mqp_rdbr_mapoffset = 0;
data->mqp_rdbr_maplen = 0;
data->mqp_rdbr_offset = 0;
} else {
qp->qp_desc_off);
/* doorbell record fields */
}
qp->qp_desc_off);
/* doorbell record fields */
data->mqp_sdbr_mapoffset = 0;
data->mqp_sdbr_maplen = 0;
data->mqp_sdbr_offset = 0;
return (DDI_SUCCESS);
}
/*
* hermon_umap_srq_data_out()
* Context: Can be called from user or kernel context.
*/
static ibt_status_t
{
/* Check for valid SRQ handle pointer */
return (IBT_SRQ_HDL_INVALID);
}
/* Check for valid SRQ mapping structure size */
if (data_sz < sizeof (mlnx_umap_srq_data_out_t)) {
return (IBT_INSUFF_RESOURCE);
}
/*
* If it has passed all the checks, then fill in all the useful
* mapping information (including the mapping offset that will be
* passed back to the devmap() interface during a subsequent mmap()
* call.
*
* The "offset" for SRQ mmap()'s looks like this:
* +----------------------------------------+--------+--------------+
* | SRQ Number | 0x66 | Reserved (0) |
* +----------------------------------------+--------+--------------+
* (64 - 8 - PAGESHIFT) bits 8 bits PAGESHIFT bits
*
* This returns information about the mapping offset, the length of the
* SRQ memory, and the SRQ number (for use in later send and recv
* doorbells). It also returns the following information for the
* shared receive queue: the offset (from the base mapped address) of
* the start of the given work queue, the 64-bit IB virtual address
* that corresponds to the base mapped address (needed for posting WQEs
* though the QP doorbells), the number of WQEs the given work queue
* can hold, and the size of each WQE for the given work queue.
*/
srq->srq_desc_off);
/* doorbell record fields */
return (DDI_SUCCESS);
}
/*
* hermon_umap_pd_data_out()
* Context: Can be called from user or kernel context.
*/
static ibt_status_t
{
/* Check for valid PD handle pointer */
return (IBT_PD_HDL_INVALID);
}
/* Check for valid PD mapping structure size */
if (data_sz < sizeof (mlnx_umap_pd_data_out_t)) {
return (IBT_INSUFF_RESOURCE);
}
/*
* If it has passed all the checks, then fill the PD table index
* (the PD table allocated index for the PD pd_pdnum).
*/
return (DDI_SUCCESS);
}
/*
* hermon_umap_db_init()
* Context: Only called from attach() path context
*/
void
hermon_umap_db_init(void)
{
/*
* Initialize the lock used by the Hermon "userland resources database"
* This is used to ensure atomic access to add, remove, and find
* entries in the database.
*/
MUTEX_DRIVER, NULL);
/*
* Initialize the AVL tree used for the "userland resources
* database". Using an AVL tree here provides the ability to
* scale the database size to large numbers of resources. The
* entries in the tree are "hermon_umap_db_entry_t" (see
* hermon_umap.h). The tree is searched with the help of the
* hermon_umap_db_compare() routine.
*/
hermon_umap_db_compare, sizeof (hermon_umap_db_entry_t),
}
/*
* hermon_umap_db_fini()
*/
void
hermon_umap_db_fini(void)
{
/* Destroy the AVL tree for the "userland resources database" */
/* Destroy the lock for the "userland resources database" */
}
/*
* hermon_umap_db_alloc()
* Context: Can be called from user or kernel context.
*/
{
/* Allocate an entry to add to the "userland resources database" */
return (NULL);
}
/* Fill in the fields in the database entry */
return (umapdb);
}
/*
* hermon_umap_db_free()
* Context: Can be called from user or kernel context.
*/
void
{
/* Free the database entry */
}
/*
* hermon_umap_db_add()
* Context: Can be called from user or kernel context.
*/
void
{
}
/*
* hermon_umap_db_add_nolock()
* Context: Can be called from user or kernel context.
*/
void
{
/*
* Copy the common portion of the "to-be-added" database entry
* into the "hermon_umap_db_query_t" structure. We use this structure
* (with no flags set) to find the appropriate location in the
* "userland resources database" for the new entry to be added.
*
* Note: we expect that this entry should not be found in the
* database (unless something bad has happened).
*/
query.hqdb_flags = 0;
&where);
/*
* Now, using the "where" field from the avl_find() operation
* above, we will insert the new database entry ("umapdb").
*/
where);
}
/*
* hermon_umap_db_find()
* Context: Can be called from user or kernel context.
*/
int
{
int status;
umapdb);
return (status);
}
/*
* hermon_umap_db_find_nolock()
* Context: Can be called from user or kernel context.
*/
int
{
/*
* Fill in key, type, instance, and flags values of the
* hermon_umap_db_query_t in preparation for the database
* lookup.
*/
/*
* Perform the database query. If no entry is found, then
* return failure, else continue.
*/
return (DDI_FAILURE);
}
/*
* If the flags argument specifies that the entry should
* be removed if found, then call avl_remove() to remove
* the entry from the database.
*/
if (flags & HERMON_UMAP_DB_REMOVE) {
/*
* The database entry is returned with the expectation
* that the caller will use hermon_umap_db_free() to
* free the entry's memory. ASSERT that this is non-NULL.
* NULL pointer should never be passed for the
* HERMON_UMAP_DB_REMOVE case.
*/
}
/*
* If the caller would like visibility to the database entry
* (indicated through the use of a non-NULL "umapdb" argument),
* then fill it in.
*/
}
/* Extract value field from database entry and return success */
return (DDI_SUCCESS);
}
/*
* hermon_umap_umemlock_cb()
* Context: Can be called from callback context.
*/
void
{
int status;
void (*mr_callback)(void *, void *);
/*
* If this was userland memory, then we need to remove its entry
* from the "userland resources database". Note: We use the
* HERMON_UMAP_DB_IGNORE_INSTANCE flag here because we don't know
* which instance was used when the entry was added (but we want
* to know after the entry is found using the other search criteria).
*/
if (status == DDI_SUCCESS) {
return;
}
/* Free the database entry */
/* Use "value" to convert to an MR handle */
/*
* If a callback has been provided, call it first. This
* callback is expected to do any cleanup necessary to
* guarantee that the subsequent MR deregister (below)
* will succeed. Specifically, this means freeing up memory
* windows which might have been associated with the MR.
*/
if (mr_callback != NULL) {
}
/*
* Then call hermon_mr_deregister() to release the resources
* associated with the MR handle. Note: Because this routine
* will also check for whether the ddi_umem_cookie_t is in the
* database, it will take responsibility for disabling the
* memory region and calling ddi_umem_unlock().
*/
if (status != DDI_SUCCESS) {
"deregister from callback\n");
}
}
}
/*
* hermon_umap_db_compare()
* Context: Can be called from user or kernel context.
*/
static int
hermon_umap_db_compare(const void *q, const void *e)
{
/*
* The first comparison is done on the "key" value in "query"
* and "entry". If they are not equal, then the appropriate
* search direction is returned. Else, we continue by
* comparing "type".
*/
return (-1);
return (+1);
}
/*
* If the search reaches this point, then "query" and "entry"
* have equal key values. So we continue be comparing their
* "type" values. Again, if they are not equal, then the
* appropriate search direction is returned. Else, we continue
* by comparing "instance".
*/
return (-1);
return (+1);
}
/*
* If the search reaches this point, then "query" and "entry"
* have exactly the same key and type values. Now we consult
* the "flags" field in the query to determine whether the
* "instance" is relevant to the search. If the
* HERMON_UMAP_DB_IGNORE_INSTANCE flags is set, then return
* success (0) here. Otherwise, continue the search by comparing
* instance values and returning the appropriate search direction.
*/
return (0);
}
/*
* If the search has reached this point, then "query" and "entry"
* can only be differentiated by their instance values. If these
* are not equal, then return the appropriate search direction.
* Else, we return success (0).
*/
return (-1);
return (+1);
}
/* Everything matches... so return success */
return (0);
}
/*
* hermon_umap_db_set_onclose_cb()
* Context: Can be called from user or kernel context.
*/
int
{
int status;
return (DDI_FAILURE);
}
if (flag != HERMON_ONCLOSE_FLASH_INPROGRESS) {
return (DDI_FAILURE);
}
/*
* Grab the lock for the "userland resources database" and find
* the entry corresponding to this minor number. Once it's found,
* allocate (if necessary) and add an entry (in the "hdb_priv"
* field) to indicate that further processing may be needed during
* Hermon's close() handling.
*/
if (status != DDI_SUCCESS) {
return (DDI_FAILURE);
}
sizeof (hermon_umap_db_priv_t), KM_NOSLEEP);
return (DDI_FAILURE);
}
}
/*
* Save away the callback and argument to be used during Hermon's
* close() processing.
*/
return (DDI_SUCCESS);
}
/*
* hermon_umap_db_clear_onclose_cb()
* Context: Can be called from user or kernel context.
*/
int
{
int status;
return (DDI_FAILURE);
}
if (flag != HERMON_ONCLOSE_FLASH_INPROGRESS) {
return (DDI_FAILURE);
}
/*
* Grab the lock for the "userland resources database" and find
* the entry corresponding to this minor number. Once it's found,
* remove the entry (in the "hdb_priv" field) that indicated the
* need for further processing during Hermon's close(). Free the
* entry, if appropriate.
*/
if (status != DDI_SUCCESS) {
return (DDI_FAILURE);
}
}
return (DDI_SUCCESS);
}
/*
* hermon_umap_db_clear_onclose_cb()
* Context: Can be called from user or kernel context.
*/
int
{
int (*callback)(void *);
/*
* Call the callback.
* Note: Currently there is only one callback (in "hdp_cb"), but
* in the future there may be more, depending on what other types
* of interaction there are between userland processes and the
* driver.
*/
}