#include <sys/types.h>
#include <sys/conf.h>
#include <sys/ddi.h>
#include <sys/sunddi.h>
#include <sys/modctl.h>
#include <sys/file.h>
#include <sys/avl.h>
#include <sys/sysmacros.h>
#include <sys/ib/adapters/tavor/tavor.h>
extern void *tavor_statep;
extern tavor_umap_db_t tavor_userland_rsrc_db;
static int tavor_umap_uarpg(tavor_state_t *state, devmap_cookie_t dhp,
tavor_rsrc_t *rsrcp, size_t *maplen, int *err);
static int tavor_umap_cqmem(tavor_state_t *state, devmap_cookie_t dhp,
tavor_rsrc_t *rsrcp, offset_t off, size_t *maplen, int *err);
static int tavor_umap_qpmem(tavor_state_t *state, devmap_cookie_t dhp,
tavor_rsrc_t *rsrcp, offset_t off, size_t *maplen, int *err);
static int tavor_umap_srqmem(tavor_state_t *state, devmap_cookie_t dhp,
tavor_rsrc_t *rsrcp, offset_t off, size_t *maplen, int *err);
static int tavor_devmap_umem_map(devmap_cookie_t dhp, dev_t dev, uint_t flags,
offset_t off, size_t len, void **pvtp);
static int tavor_devmap_umem_dup(devmap_cookie_t dhp, void *pvtp,
devmap_cookie_t new_dhp, void **new_pvtp);
static void tavor_devmap_umem_unmap(devmap_cookie_t dhp, void *pvtp,
offset_t off, size_t len, devmap_cookie_t new_dhp1, void **pvtp1,
devmap_cookie_t new_dhp2, void **pvtp2);
static int tavor_devmap_devmem_map(devmap_cookie_t dhp, dev_t dev, uint_t flags,
offset_t off, size_t len, void **pvtp);
static int tavor_devmap_devmem_dup(devmap_cookie_t dhp, void *pvtp,
devmap_cookie_t new_dhp, void **new_pvtp);
static void tavor_devmap_devmem_unmap(devmap_cookie_t dhp, void *pvtp,
offset_t off, size_t len, devmap_cookie_t new_dhp1, void **pvtp1,
devmap_cookie_t new_dhp2, void **pvtp2);
static ibt_status_t tavor_umap_mr_data_in(tavor_mrhdl_t mr,
ibt_mr_data_in_t *data, size_t data_sz);
static ibt_status_t tavor_umap_cq_data_out(tavor_cqhdl_t cq,
mlnx_umap_cq_data_out_t *data, size_t data_sz);
static ibt_status_t tavor_umap_qp_data_out(tavor_qphdl_t qp,
mlnx_umap_qp_data_out_t *data, size_t data_sz);
static ibt_status_t tavor_umap_srq_data_out(tavor_srqhdl_t srq,
mlnx_umap_srq_data_out_t *data, size_t data_sz);
static int tavor_umap_db_compare(const void *query, const void *entry);
static ibt_status_t tavor_umap_pd_data_out(tavor_pdhdl_t pd,
mlnx_umap_pd_data_out_t *data, size_t data_sz);
static struct devmap_callback_ctl tavor_devmap_umem_cbops = {
DEVMAP_OPS_REV,
tavor_devmap_umem_map,
NULL,
tavor_devmap_umem_dup,
tavor_devmap_umem_unmap
};
static struct devmap_callback_ctl tavor_devmap_devmem_cbops = {
DEVMAP_OPS_REV,
tavor_devmap_devmem_map,
NULL,
tavor_devmap_devmem_dup,
tavor_devmap_devmem_unmap
};
int
tavor_devmap(dev_t dev, devmap_cookie_t dhp, offset_t off, size_t len,
size_t *maplen, uint_t model)
{
tavor_state_t *state;
tavor_rsrc_t *rsrcp;
minor_t instance;
uint64_t key, value;
uint_t type;
int err, status;
instance = TAVOR_DEV_INSTANCE(dev);
state = ddi_get_soft_state(tavor_statep, instance);
if (state == NULL) {
return (ENXIO);
}
if (state->ts_operational_mode == TAVOR_MAINTENANCE_MODE) {
return (EFAULT);
}
key = off >> PAGESHIFT;
type = key & MLNX_UMAP_RSRC_TYPE_MASK;
key = key >> MLNX_UMAP_RSRC_TYPE_SHIFT;
status = tavor_umap_db_find(instance, key, type, &value, 0, NULL);
if (status == DDI_SUCCESS) {
rsrcp = (tavor_rsrc_t *)(uintptr_t)value;
switch (type) {
case MLNX_UMAP_UARPG_RSRC:
if (key != ddi_get_pid()) {
return (EINVAL);
}
status = tavor_umap_uarpg(state, dhp, rsrcp, maplen,
&err);
if (status != DDI_SUCCESS) {
return (err);
}
break;
case MLNX_UMAP_CQMEM_RSRC:
status = tavor_umap_cqmem(state, dhp, rsrcp, off,
maplen, &err);
if (status != DDI_SUCCESS) {
return (err);
}
break;
case MLNX_UMAP_QPMEM_RSRC:
status = tavor_umap_qpmem(state, dhp, rsrcp, off,
maplen, &err);
if (status != DDI_SUCCESS) {
return (err);
}
break;
case MLNX_UMAP_SRQMEM_RSRC:
status = tavor_umap_srqmem(state, dhp, rsrcp, off,
maplen, &err);
if (status != DDI_SUCCESS) {
return (err);
}
break;
default:
TAVOR_WARNING(state, "unexpected rsrc type in devmap");
return (EINVAL);
}
} else {
return (EINVAL);
}
return (0);
}
static int
tavor_umap_uarpg(tavor_state_t *state, devmap_cookie_t dhp,
tavor_rsrc_t *rsrcp, size_t *maplen, int *err)
{
int status;
uint_t maxprot;
maxprot = (PROT_READ | PROT_WRITE | PROT_USER);
status = devmap_devmem_setup(dhp, state->ts_dip,
&tavor_devmap_devmem_cbops, TAVOR_UAR_BAR, (rsrcp->tr_indx <<
PAGESHIFT), PAGESIZE, maxprot, DEVMAP_ALLOW_REMAP,
&state->ts_reg_accattr);
if (status < 0) {
*err = status;
return (DDI_FAILURE);
}
*maplen = PAGESIZE;
return (DDI_SUCCESS);
}
static int
tavor_umap_cqmem(tavor_state_t *state, devmap_cookie_t dhp,
tavor_rsrc_t *rsrcp, offset_t off, size_t *maplen, int *err)
{
tavor_cqhdl_t cq;
size_t size;
uint_t maxprot;
int status;
cq = (tavor_cqhdl_t)rsrcp->tr_addr;
size = ptob(btopr(cq->cq_cqinfo.qa_size));
maxprot = (PROT_READ | PROT_WRITE | PROT_USER);
status = devmap_umem_setup(dhp, state->ts_dip,
&tavor_devmap_umem_cbops, cq->cq_cqinfo.qa_umemcookie, 0, size,
maxprot, (DEVMAP_ALLOW_REMAP | DEVMAP_DEFAULTS), NULL);
if (status < 0) {
*err = status;
return (DDI_FAILURE);
}
*maplen = size;
return (DDI_SUCCESS);
}
static int
tavor_umap_qpmem(tavor_state_t *state, devmap_cookie_t dhp,
tavor_rsrc_t *rsrcp, offset_t off, size_t *maplen, int *err)
{
tavor_qphdl_t qp;
offset_t offset;
size_t size;
uint_t maxprot;
int status;
qp = (tavor_qphdl_t)rsrcp->tr_addr;
offset = (offset_t)((uintptr_t)qp->qp_wqinfo.qa_buf_aligned -
(uintptr_t)qp->qp_wqinfo.qa_buf_real);
size = ptob(btopr(qp->qp_wqinfo.qa_size));
maxprot = (PROT_READ | PROT_WRITE | PROT_USER);
status = devmap_umem_setup(dhp, state->ts_dip,
&tavor_devmap_umem_cbops, qp->qp_wqinfo.qa_umemcookie, offset,
size, maxprot, (DEVMAP_ALLOW_REMAP | DEVMAP_DEFAULTS), NULL);
if (status < 0) {
*err = status;
return (DDI_FAILURE);
}
*maplen = size;
return (DDI_SUCCESS);
}
static int
tavor_umap_srqmem(tavor_state_t *state, devmap_cookie_t dhp,
tavor_rsrc_t *rsrcp, offset_t off, size_t *maplen, int *err)
{
tavor_srqhdl_t srq;
offset_t offset;
size_t size;
uint_t maxprot;
int status;
srq = (tavor_srqhdl_t)rsrcp->tr_addr;
offset = (offset_t)((uintptr_t)srq->srq_wqinfo.qa_buf_aligned -
(uintptr_t)srq->srq_wqinfo.qa_buf_real);
size = ptob(btopr(srq->srq_wqinfo.qa_size));
maxprot = (PROT_READ | PROT_WRITE | PROT_USER);
status = devmap_umem_setup(dhp, state->ts_dip,
&tavor_devmap_umem_cbops, srq->srq_wqinfo.qa_umemcookie, offset,
size, maxprot, (DEVMAP_ALLOW_REMAP | DEVMAP_DEFAULTS), NULL);
if (status < 0) {
*err = status;
return (DDI_FAILURE);
}
*maplen = size;
return (DDI_SUCCESS);
}
static int
tavor_devmap_umem_map(devmap_cookie_t dhp, dev_t dev, uint_t flags,
offset_t off, size_t len, void **pvtp)
{
tavor_state_t *state;
tavor_devmap_track_t *dvm_track;
tavor_cqhdl_t cq;
tavor_qphdl_t qp;
tavor_srqhdl_t srq;
minor_t instance;
uint64_t key;
uint_t type;
instance = TAVOR_DEV_INSTANCE(dev);
state = ddi_get_soft_state(tavor_statep, instance);
if (state == NULL) {
return (ENXIO);
}
key = off >> PAGESHIFT;
type = key & MLNX_UMAP_RSRC_TYPE_MASK;
key = key >> MLNX_UMAP_RSRC_TYPE_SHIFT;
dvm_track = (tavor_devmap_track_t *)kmem_zalloc(
sizeof (tavor_devmap_track_t), KM_SLEEP);
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*dvm_track))
dvm_track->tdt_offset = off;
dvm_track->tdt_state = state;
dvm_track->tdt_refcnt = 1;
mutex_init(&dvm_track->tdt_lock, NULL, MUTEX_DRIVER,
DDI_INTR_PRI(state->ts_intrmsi_pri));
if (type == MLNX_UMAP_CQMEM_RSRC) {
cq = tavor_cqhdl_from_cqnum(state, key);
mutex_enter(&cq->cq_lock);
if (cq->cq_umap_dhp == NULL) {
cq->cq_umap_dhp = dhp;
dvm_track->tdt_size = cq->cq_cqinfo.qa_size;
mutex_exit(&cq->cq_lock);
} else {
mutex_exit(&cq->cq_lock);
goto umem_map_fail;
}
} else if (type == MLNX_UMAP_QPMEM_RSRC) {
qp = tavor_qphdl_from_qpnum(state, key);
mutex_enter(&qp->qp_lock);
if (qp->qp_umap_dhp == NULL) {
qp->qp_umap_dhp = dhp;
dvm_track->tdt_size = qp->qp_wqinfo.qa_size;
mutex_exit(&qp->qp_lock);
} else {
mutex_exit(&qp->qp_lock);
goto umem_map_fail;
}
} else if (type == MLNX_UMAP_SRQMEM_RSRC) {
srq = tavor_srqhdl_from_srqnum(state, key);
mutex_enter(&srq->srq_lock);
if (srq->srq_umap_dhp == NULL) {
srq->srq_umap_dhp = dhp;
dvm_track->tdt_size = srq->srq_wqinfo.qa_size;
mutex_exit(&srq->srq_lock);
} else {
mutex_exit(&srq->srq_lock);
goto umem_map_fail;
}
}
*pvtp = dvm_track;
return (DDI_SUCCESS);
umem_map_fail:
mutex_destroy(&dvm_track->tdt_lock);
kmem_free(dvm_track, sizeof (tavor_devmap_track_t));
return (DDI_FAILURE);
}
static int
tavor_devmap_umem_dup(devmap_cookie_t dhp, void *pvtp, devmap_cookie_t new_dhp,
void **new_pvtp)
{
tavor_state_t *state;
tavor_devmap_track_t *dvm_track, *new_dvm_track;
uint_t maxprot;
int status;
dvm_track = (tavor_devmap_track_t *)pvtp;
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*dvm_track))
state = dvm_track->tdt_state;
maxprot = (PROT_READ | PROT_WRITE | PROT_USER);
status = devmap_devmem_remap(new_dhp, state->ts_dip, 0, 0,
dvm_track->tdt_size, maxprot, DEVMAP_MAPPING_INVALID, NULL);
if (status != DDI_SUCCESS) {
TAVOR_WARNING(state, "failed in tavor_devmap_umem_dup()");
return (status);
}
new_dvm_track = (tavor_devmap_track_t *)kmem_zalloc(
sizeof (tavor_devmap_track_t), KM_SLEEP);
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*new_dvm_track))
new_dvm_track->tdt_offset = 0;
new_dvm_track->tdt_state = state;
new_dvm_track->tdt_refcnt = 1;
new_dvm_track->tdt_size = 0;
mutex_init(&new_dvm_track->tdt_lock, NULL, MUTEX_DRIVER,
DDI_INTR_PRI(state->ts_intrmsi_pri));
*new_pvtp = new_dvm_track;
return (DDI_SUCCESS);
}
static void
tavor_devmap_umem_unmap(devmap_cookie_t dhp, void *pvtp, offset_t off,
size_t len, devmap_cookie_t new_dhp1, void **pvtp1,
devmap_cookie_t new_dhp2, void **pvtp2)
{
tavor_state_t *state;
tavor_rsrc_t *rsrcp;
tavor_devmap_track_t *dvm_track;
tavor_cqhdl_t cq;
tavor_qphdl_t qp;
tavor_srqhdl_t srq;
uint64_t key, value;
uint_t type;
uint_t size;
int status;
dvm_track = (tavor_devmap_track_t *)pvtp;
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*dvm_track))
state = dvm_track->tdt_state;
key = dvm_track->tdt_offset >> PAGESHIFT;
type = key & MLNX_UMAP_RSRC_TYPE_MASK;
key = key >> MLNX_UMAP_RSRC_TYPE_SHIFT;
size = dvm_track->tdt_size;
mutex_enter(&dvm_track->tdt_lock);
if ((new_dhp1 == NULL) && (new_dhp2 == NULL)) {
dvm_track->tdt_refcnt--;
} else if ((new_dhp1 != NULL) && (new_dhp2 != NULL)) {
dvm_track->tdt_refcnt++;
}
mutex_exit(&dvm_track->tdt_lock);
if (new_dhp1 != NULL) {
*pvtp1 = pvtp;
}
if (new_dhp2 != NULL) {
*pvtp2 = pvtp;
}
if (dvm_track->tdt_refcnt == 0) {
mutex_destroy(&dvm_track->tdt_lock);
kmem_free(dvm_track, sizeof (tavor_devmap_track_t));
if (size == 0) {
return;
}
} else {
return;
}
status = tavor_umap_db_find(state->ts_instance, key, type, &value,
0, NULL);
if (status == DDI_SUCCESS) {
if (type == MLNX_UMAP_CQMEM_RSRC) {
rsrcp = (tavor_rsrc_t *)(uintptr_t)value;
cq = (tavor_cqhdl_t)rsrcp->tr_addr;
mutex_enter(&cq->cq_lock);
if (cq->cq_umap_dhp == dhp) {
cq->cq_umap_dhp = (devmap_cookie_t)NULL;
}
mutex_exit(&cq->cq_lock);
} else if (type == MLNX_UMAP_QPMEM_RSRC) {
rsrcp = (tavor_rsrc_t *)(uintptr_t)value;
qp = (tavor_qphdl_t)rsrcp->tr_addr;
mutex_enter(&qp->qp_lock);
if (qp->qp_umap_dhp == dhp) {
qp->qp_umap_dhp = (devmap_cookie_t)NULL;
}
mutex_exit(&qp->qp_lock);
} else if (type == MLNX_UMAP_SRQMEM_RSRC) {
rsrcp = (tavor_rsrc_t *)(uintptr_t)value;
srq = (tavor_srqhdl_t)rsrcp->tr_addr;
mutex_enter(&srq->srq_lock);
if (srq->srq_umap_dhp == dhp) {
srq->srq_umap_dhp = (devmap_cookie_t)NULL;
}
mutex_exit(&srq->srq_lock);
}
}
}
static int
tavor_devmap_devmem_map(devmap_cookie_t dhp, dev_t dev, uint_t flags,
offset_t off, size_t len, void **pvtp)
{
tavor_state_t *state;
tavor_devmap_track_t *dvm_track;
minor_t instance;
instance = TAVOR_DEV_INSTANCE(dev);
state = ddi_get_soft_state(tavor_statep, instance);
if (state == NULL) {
return (ENXIO);
}
dvm_track = (tavor_devmap_track_t *)kmem_zalloc(
sizeof (tavor_devmap_track_t), KM_SLEEP);
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*dvm_track))
dvm_track->tdt_state = state;
dvm_track->tdt_size = PAGESIZE;
*pvtp = dvm_track;
return (DDI_SUCCESS);
}
static int
tavor_devmap_devmem_dup(devmap_cookie_t dhp, void *pvtp,
devmap_cookie_t new_dhp, void **new_pvtp)
{
tavor_state_t *state;
tavor_devmap_track_t *dvm_track;
uint_t maxprot;
int status;
dvm_track = (tavor_devmap_track_t *)pvtp;
if (dvm_track == NULL) {
*new_pvtp = NULL;
return (DDI_SUCCESS);
}
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*dvm_track))
state = dvm_track->tdt_state;
maxprot = (PROT_READ | PROT_WRITE | PROT_USER);
status = devmap_devmem_remap(new_dhp, state->ts_dip, 0, 0,
dvm_track->tdt_size, maxprot, DEVMAP_MAPPING_INVALID, NULL);
if (status != DDI_SUCCESS) {
TAVOR_WARNING(state, "failed in tavor_devmap_devmem_dup()");
return (status);
}
*new_pvtp = NULL;
return (DDI_SUCCESS);
}
static void
tavor_devmap_devmem_unmap(devmap_cookie_t dhp, void *pvtp, offset_t off,
size_t len, devmap_cookie_t new_dhp1, void **pvtp1,
devmap_cookie_t new_dhp2, void **pvtp2)
{
tavor_devmap_track_t *dvm_track;
dvm_track = (tavor_devmap_track_t *)pvtp;
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*dvm_track))
if (dvm_track == NULL) {
return;
}
kmem_free(dvm_track, sizeof (tavor_devmap_track_t));
}
ibt_status_t
tavor_umap_ci_data_in(tavor_state_t *state, ibt_ci_data_flags_t flags,
ibt_object_type_t object, void *hdl, void *data_p, size_t data_sz)
{
int status;
switch (object) {
case IBT_HDL_MR:
status = tavor_umap_mr_data_in((tavor_mrhdl_t)hdl,
(ibt_mr_data_in_t *)data_p, data_sz);
if (status != DDI_SUCCESS) {
return (status);
}
break;
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);
default:
return (IBT_INVALID_PARAM);
}
return (DDI_SUCCESS);
}
static ibt_status_t
tavor_umap_mr_data_in(tavor_mrhdl_t mr, ibt_mr_data_in_t *data,
size_t data_sz)
{
if (data->mr_rev != IBT_MR_DATA_IN_IF_VERSION) {
return (IBT_NOT_SUPPORTED);
}
if (mr == NULL) {
return (IBT_MR_HDL_INVALID);
}
if (data_sz < sizeof (ibt_mr_data_in_t)) {
return (IBT_INSUFF_RESOURCE);
}
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*data))
mutex_enter(&mr->mr_lock);
if ((mr->mr_is_umem == 0) || (mr->mr_umemcookie == NULL)) {
mutex_exit(&mr->mr_lock);
return (IBT_MR_HDL_INVALID);
}
mr->mr_umem_cbfunc = data->mr_func;
mr->mr_umem_cbarg1 = data->mr_arg1;
mr->mr_umem_cbarg2 = data->mr_arg2;
mutex_exit(&mr->mr_lock);
return (DDI_SUCCESS);
}
ibt_status_t
tavor_umap_ci_data_out(tavor_state_t *state, ibt_ci_data_flags_t flags,
ibt_object_type_t object, void *hdl, void *data_p, size_t data_sz)
{
int status;
switch (object) {
case IBT_HDL_CQ:
status = tavor_umap_cq_data_out((tavor_cqhdl_t)hdl,
(mlnx_umap_cq_data_out_t *)data_p, data_sz);
if (status != DDI_SUCCESS) {
return (status);
}
break;
case IBT_HDL_QP:
status = tavor_umap_qp_data_out((tavor_qphdl_t)hdl,
(mlnx_umap_qp_data_out_t *)data_p, data_sz);
if (status != DDI_SUCCESS) {
return (status);
}
break;
case IBT_HDL_SRQ:
status = tavor_umap_srq_data_out((tavor_srqhdl_t)hdl,
(mlnx_umap_srq_data_out_t *)data_p, data_sz);
if (status != DDI_SUCCESS) {
return (status);
}
break;
case IBT_HDL_PD:
status = tavor_umap_pd_data_out((tavor_pdhdl_t)hdl,
(mlnx_umap_pd_data_out_t *)data_p, data_sz);
if (status != DDI_SUCCESS) {
return (status);
}
break;
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);
default:
return (IBT_INVALID_PARAM);
}
return (DDI_SUCCESS);
}
static ibt_status_t
tavor_umap_cq_data_out(tavor_cqhdl_t cq, mlnx_umap_cq_data_out_t *data,
size_t data_sz)
{
if (cq == NULL) {
return (IBT_CQ_HDL_INVALID);
}
if (data_sz < sizeof (mlnx_umap_cq_data_out_t)) {
return (IBT_INSUFF_RESOURCE);
}
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*data))
data->mcq_rev = MLNX_UMAP_IF_VERSION;
data->mcq_mapoffset = ((((uint64_t)cq->cq_cqnum <<
MLNX_UMAP_RSRC_TYPE_SHIFT) | MLNX_UMAP_CQMEM_RSRC) << PAGESHIFT);
data->mcq_maplen = cq->cq_cqinfo.qa_size;
data->mcq_cqnum = cq->cq_cqnum;
data->mcq_numcqe = cq->cq_bufsz;
data->mcq_cqesz = sizeof (tavor_hw_cqe_t);
return (DDI_SUCCESS);
}
static ibt_status_t
tavor_umap_qp_data_out(tavor_qphdl_t qp, mlnx_umap_qp_data_out_t *data,
size_t data_sz)
{
if (qp == NULL) {
return (IBT_QP_HDL_INVALID);
}
if (data_sz < sizeof (mlnx_umap_qp_data_out_t)) {
return (IBT_INSUFF_RESOURCE);
}
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*data))
data->mqp_rev = MLNX_UMAP_IF_VERSION;
data->mqp_mapoffset = ((((uint64_t)qp->qp_qpnum <<
MLNX_UMAP_RSRC_TYPE_SHIFT) | MLNX_UMAP_QPMEM_RSRC) << PAGESHIFT);
data->mqp_maplen = qp->qp_wqinfo.qa_size;
data->mqp_qpnum = qp->qp_qpnum;
if (qp->qp_srq_en == TAVOR_QP_SRQ_ENABLED) {
data->mqp_rq_off = (uint32_t)qp->qp_wqinfo.qa_size;
data->mqp_rq_desc_addr = (uint32_t)qp->qp_wqinfo.qa_size;
data->mqp_rq_numwqe = 0;
data->mqp_rq_wqesz = 0;
} else {
data->mqp_rq_off = (uintptr_t)qp->qp_rq_buf -
(uintptr_t)qp->qp_wqinfo.qa_buf_aligned;
data->mqp_rq_desc_addr = (uint32_t)((uintptr_t)qp->qp_rq_buf -
qp->qp_desc_off);
data->mqp_rq_numwqe = qp->qp_rq_bufsz;
data->mqp_rq_wqesz = (1 << qp->qp_rq_log_wqesz);
}
data->mqp_sq_off = (uintptr_t)qp->qp_sq_buf -
(uintptr_t)qp->qp_wqinfo.qa_buf_aligned;
data->mqp_sq_desc_addr = (uint32_t)((uintptr_t)qp->qp_sq_buf -
qp->qp_desc_off);
data->mqp_sq_numwqe = qp->qp_sq_bufsz;
data->mqp_sq_wqesz = (1 << qp->qp_sq_log_wqesz);
return (DDI_SUCCESS);
}
static ibt_status_t
tavor_umap_srq_data_out(tavor_srqhdl_t srq, mlnx_umap_srq_data_out_t *data,
size_t data_sz)
{
if (srq == NULL) {
return (IBT_SRQ_HDL_INVALID);
}
if (data_sz < sizeof (mlnx_umap_srq_data_out_t)) {
return (IBT_INSUFF_RESOURCE);
}
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*data))
data->msrq_rev = MLNX_UMAP_IF_VERSION;
data->msrq_mapoffset = ((((uint64_t)srq->srq_srqnum <<
MLNX_UMAP_RSRC_TYPE_SHIFT) | MLNX_UMAP_SRQMEM_RSRC) << PAGESHIFT);
data->msrq_maplen = srq->srq_wqinfo.qa_size;
data->msrq_srqnum = srq->srq_srqnum;
data->msrq_desc_addr = (uint32_t)((uintptr_t)srq->srq_wq_buf -
srq->srq_desc_off);
data->msrq_numwqe = srq->srq_wq_bufsz;
data->msrq_wqesz = (1 << srq->srq_wq_log_wqesz);
return (DDI_SUCCESS);
}
static ibt_status_t
tavor_umap_pd_data_out(tavor_pdhdl_t pd, mlnx_umap_pd_data_out_t *data,
size_t data_sz)
{
if (pd == NULL) {
return (IBT_PD_HDL_INVALID);
}
if (data_sz < sizeof (mlnx_umap_pd_data_out_t)) {
return (IBT_INSUFF_RESOURCE);
}
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*data))
data->mpd_rev = MLNX_UMAP_IF_VERSION;
data->mpd_pdnum = pd->pd_pdnum;
return (DDI_SUCCESS);
}
void
tavor_umap_db_init(void)
{
mutex_init(&tavor_userland_rsrc_db.tdl_umapdb_lock, NULL,
MUTEX_DRIVER, NULL);
avl_create(&tavor_userland_rsrc_db.tdl_umapdb_avl,
tavor_umap_db_compare, sizeof (tavor_umap_db_entry_t),
offsetof(tavor_umap_db_entry_t, tdbe_avlnode));
}
void
tavor_umap_db_fini(void)
{
avl_destroy(&tavor_userland_rsrc_db.tdl_umapdb_avl);
mutex_destroy(&tavor_userland_rsrc_db.tdl_umapdb_lock);
}
tavor_umap_db_entry_t *
tavor_umap_db_alloc(uint_t instance, uint64_t key, uint_t type, uint64_t value)
{
tavor_umap_db_entry_t *umapdb;
umapdb = kmem_zalloc(sizeof (tavor_umap_db_entry_t), KM_NOSLEEP);
if (umapdb == NULL) {
return (NULL);
}
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*umapdb))
umapdb->tdbe_common.tdb_instance = instance;
umapdb->tdbe_common.tdb_type = type;
umapdb->tdbe_common.tdb_key = key;
umapdb->tdbe_common.tdb_value = value;
return (umapdb);
}
void
tavor_umap_db_free(tavor_umap_db_entry_t *umapdb)
{
kmem_free(umapdb, sizeof (tavor_umap_db_entry_t));
}
void
tavor_umap_db_add(tavor_umap_db_entry_t *umapdb)
{
mutex_enter(&tavor_userland_rsrc_db.tdl_umapdb_lock);
tavor_umap_db_add_nolock(umapdb);
mutex_exit(&tavor_userland_rsrc_db.tdl_umapdb_lock);
}
void
tavor_umap_db_add_nolock(tavor_umap_db_entry_t *umapdb)
{
tavor_umap_db_query_t query;
avl_index_t where;
ASSERT(MUTEX_HELD(&tavor_userland_rsrc_db.tdl_umapdb_lock));
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*umapdb))
query.tqdb_common = umapdb->tdbe_common;
query.tqdb_flags = 0;
(void) avl_find(&tavor_userland_rsrc_db.tdl_umapdb_avl, &query,
&where);
avl_insert(&tavor_userland_rsrc_db.tdl_umapdb_avl, umapdb,
where);
}
int
tavor_umap_db_find(uint_t instance, uint64_t key, uint_t type,
uint64_t *value, uint_t flag, tavor_umap_db_entry_t **umapdb)
{
int status;
mutex_enter(&tavor_userland_rsrc_db.tdl_umapdb_lock);
status = tavor_umap_db_find_nolock(instance, key, type, value, flag,
umapdb);
mutex_exit(&tavor_userland_rsrc_db.tdl_umapdb_lock);
return (status);
}
int
tavor_umap_db_find_nolock(uint_t instance, uint64_t key, uint_t type,
uint64_t *value, uint_t flags, tavor_umap_db_entry_t **umapdb)
{
tavor_umap_db_query_t query;
tavor_umap_db_entry_t *entry;
avl_index_t where;
ASSERT(MUTEX_HELD(&tavor_userland_rsrc_db.tdl_umapdb_lock));
query.tqdb_flags = flags;
query.tqdb_common.tdb_key = key;
query.tqdb_common.tdb_type = type;
query.tqdb_common.tdb_instance = instance;
entry = (tavor_umap_db_entry_t *)avl_find(
&tavor_userland_rsrc_db.tdl_umapdb_avl, &query, &where);
if (entry == NULL) {
return (DDI_FAILURE);
}
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*entry))
if (flags & TAVOR_UMAP_DB_REMOVE) {
avl_remove(&tavor_userland_rsrc_db.tdl_umapdb_avl, entry);
ASSERT(umapdb != NULL);
}
if (umapdb != NULL) {
*umapdb = entry;
}
*value = entry->tdbe_common.tdb_value;
return (DDI_SUCCESS);
}
void
tavor_umap_umemlock_cb(ddi_umem_cookie_t *umem_cookie)
{
tavor_umap_db_entry_t *umapdb;
tavor_state_t *state;
tavor_rsrc_t *rsrcp;
tavor_mrhdl_t mr;
uint64_t value;
uint_t instance;
int status;
void (*mr_callback)(void *, void *);
void *mr_cbarg1, *mr_cbarg2;
status = tavor_umap_db_find(0, (uint64_t)(uintptr_t)umem_cookie,
MLNX_UMAP_MRMEM_RSRC, &value, (TAVOR_UMAP_DB_REMOVE |
TAVOR_UMAP_DB_IGNORE_INSTANCE), &umapdb);
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*umapdb))
if (status == DDI_SUCCESS) {
instance = umapdb->tdbe_common.tdb_instance;
state = ddi_get_soft_state(tavor_statep, instance);
if (state == NULL) {
cmn_err(CE_WARN, "Unable to match Tavor instance\n");
return;
}
tavor_umap_db_free(umapdb);
rsrcp = (tavor_rsrc_t *)(uintptr_t)value;
mr = (tavor_mrhdl_t)rsrcp->tr_addr;
mutex_enter(&mr->mr_lock);
mr_callback = mr->mr_umem_cbfunc;
mr_cbarg1 = mr->mr_umem_cbarg1;
mr_cbarg2 = mr->mr_umem_cbarg2;
mutex_exit(&mr->mr_lock);
if (mr_callback != NULL) {
mr_callback(mr_cbarg1, mr_cbarg2);
}
status = tavor_mr_deregister(state, &mr, TAVOR_MR_DEREG_ALL,
TAVOR_SLEEP);
if (status != DDI_SUCCESS) {
TAVOR_WARNING(state, "Unexpected failure in "
"deregister from callback\n");
}
}
}
static int
tavor_umap_db_compare(const void *q, const void *e)
{
tavor_umap_db_common_t *entry_common, *query_common;
uint_t query_flags;
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*((tavor_umap_db_query_t *)q)))
entry_common = &((tavor_umap_db_entry_t *)e)->tdbe_common;
query_common = &((tavor_umap_db_query_t *)q)->tqdb_common;
query_flags = ((tavor_umap_db_query_t *)q)->tqdb_flags;
if (query_common->tdb_key < entry_common->tdb_key) {
return (-1);
} else if (query_common->tdb_key > entry_common->tdb_key) {
return (+1);
}
if (query_common->tdb_type < entry_common->tdb_type) {
return (-1);
} else if (query_common->tdb_type > entry_common->tdb_type) {
return (+1);
}
if (query_flags & TAVOR_UMAP_DB_IGNORE_INSTANCE) {
return (0);
}
if (query_common->tdb_instance < entry_common->tdb_instance) {
return (-1);
} else if (query_common->tdb_instance > entry_common->tdb_instance) {
return (+1);
}
return (0);
}
int
tavor_umap_db_set_onclose_cb(dev_t dev, uint64_t flag,
void (*callback)(void *), void *arg)
{
tavor_umap_db_priv_t *priv;
tavor_umap_db_entry_t *umapdb;
minor_t instance;
uint64_t value;
int status;
instance = TAVOR_DEV_INSTANCE(dev);
if (instance == -1) {
return (DDI_FAILURE);
}
if (flag != TAVOR_ONCLOSE_FLASH_INPROGRESS) {
return (DDI_FAILURE);
}
mutex_enter(&tavor_userland_rsrc_db.tdl_umapdb_lock);
status = tavor_umap_db_find_nolock(instance, dev,
MLNX_UMAP_PID_RSRC, &value, 0, &umapdb);
if (status != DDI_SUCCESS) {
mutex_exit(&tavor_userland_rsrc_db.tdl_umapdb_lock);
return (DDI_FAILURE);
}
priv = (tavor_umap_db_priv_t *)umapdb->tdbe_common.tdb_priv;
if (priv == NULL) {
priv = (tavor_umap_db_priv_t *)kmem_zalloc(
sizeof (tavor_umap_db_priv_t), KM_NOSLEEP);
if (priv == NULL) {
mutex_exit(&tavor_userland_rsrc_db.tdl_umapdb_lock);
return (DDI_FAILURE);
}
}
priv->tdp_cb = callback;
priv->tdp_arg = arg;
umapdb->tdbe_common.tdb_priv = (void *)priv;
mutex_exit(&tavor_userland_rsrc_db.tdl_umapdb_lock);
return (DDI_SUCCESS);
}
int
tavor_umap_db_clear_onclose_cb(dev_t dev, uint64_t flag)
{
tavor_umap_db_priv_t *priv;
tavor_umap_db_entry_t *umapdb;
minor_t instance;
uint64_t value;
int status;
instance = TAVOR_DEV_INSTANCE(dev);
if (instance == -1) {
return (DDI_FAILURE);
}
if (flag != TAVOR_ONCLOSE_FLASH_INPROGRESS) {
return (DDI_FAILURE);
}
mutex_enter(&tavor_userland_rsrc_db.tdl_umapdb_lock);
status = tavor_umap_db_find_nolock(instance, dev,
MLNX_UMAP_PID_RSRC, &value, 0, &umapdb);
if (status != DDI_SUCCESS) {
mutex_exit(&tavor_userland_rsrc_db.tdl_umapdb_lock);
return (DDI_FAILURE);
}
priv = (tavor_umap_db_priv_t *)umapdb->tdbe_common.tdb_priv;
if (priv != NULL) {
kmem_free(priv, sizeof (tavor_umap_db_priv_t));
priv = NULL;
}
umapdb->tdbe_common.tdb_priv = (void *)priv;
mutex_exit(&tavor_userland_rsrc_db.tdl_umapdb_lock);
return (DDI_SUCCESS);
}
void
tavor_umap_db_handle_onclose_cb(tavor_umap_db_priv_t *priv)
{
void (*callback)(void *);
ASSERT(MUTEX_HELD(&tavor_userland_rsrc_db.tdl_umapdb_lock));
callback = priv->tdp_cb;
callback(priv->tdp_arg);
}