#include <sys/types.h>
#include <sys/kmem.h>
#include <sys/conf.h>
#include <sys/ddi.h>
#include <sys/sunddi.h>
#include <sys/ksynch.h>
#include <sys/ib/clients/eoib/eib_impl.h>
eib_chan_t *
eib_chan_init(void)
{
eib_chan_t *chan;
chan = kmem_zalloc(sizeof (eib_chan_t), KM_SLEEP);
mutex_init(&chan->ch_pkey_lock, NULL, MUTEX_DRIVER, NULL);
mutex_init(&chan->ch_cep_lock, NULL, MUTEX_DRIVER, NULL);
mutex_init(&chan->ch_tx_lock, NULL, MUTEX_DRIVER, NULL);
mutex_init(&chan->ch_rx_lock, NULL, MUTEX_DRIVER, NULL);
mutex_init(&chan->ch_vhub_lock, NULL, MUTEX_DRIVER, NULL);
cv_init(&chan->ch_cep_cv, NULL, CV_DEFAULT, NULL);
cv_init(&chan->ch_tx_cv, NULL, CV_DEFAULT, NULL);
cv_init(&chan->ch_rx_cv, NULL, CV_DEFAULT, NULL);
return (chan);
}
void
eib_chan_fini(eib_chan_t *chan)
{
if (chan) {
cv_destroy(&chan->ch_rx_cv);
cv_destroy(&chan->ch_tx_cv);
cv_destroy(&chan->ch_cep_cv);
mutex_destroy(&chan->ch_vhub_lock);
mutex_destroy(&chan->ch_rx_lock);
mutex_destroy(&chan->ch_tx_lock);
mutex_destroy(&chan->ch_cep_lock);
mutex_destroy(&chan->ch_pkey_lock);
kmem_free(chan, sizeof (eib_chan_t));
}
}
int
eib_chan_post_rx(eib_t *ss, eib_chan_t *chan, uint_t *n_posted)
{
eib_wqe_t *rwqes[EIB_RWR_CHUNK_SZ];
ibt_status_t ret;
uint_t n_got = 0;
uint_t n_good = 0;
uint_t limit = 0;
uint_t room = 0;
uint_t chunk_sz;
int wndx;
int i;
room = chan->ch_max_rwqes - chan->ch_rx_posted;
limit = (room > chan->ch_rwqe_bktsz) ? chan->ch_rwqe_bktsz : room;
for (wndx = 0; wndx < limit; wndx += chunk_sz) {
chunk_sz = ((limit - wndx) < EIB_RWR_CHUNK_SZ) ?
(limit - wndx) : EIB_RWR_CHUNK_SZ;
ret = eib_rsrc_grab_rwqes(ss, rwqes, chunk_sz, &n_got,
EIB_WPRI_LO);
if (ret != EIB_E_SUCCESS)
break;
for (i = 0; i < n_got; i++) {
eib_wqe_t *rwqe = rwqes[i];
ret = eib_chan_post_recv(ss, chan, rwqe);
if (ret == EIB_E_SUCCESS) {
n_good++;
} else if (rwqe->qe_mp) {
freemsg(rwqe->qe_mp);
} else {
eib_rsrc_return_rwqe(ss, rwqe, NULL);
}
}
if (n_got < chunk_sz)
break;
}
if (n_good == 0)
return (EIB_E_FAILURE);
if (n_posted)
*n_posted = n_good;
return (EIB_E_SUCCESS);
}
int
eib_chan_post_recv(eib_t *ss, eib_chan_t *chan, eib_wqe_t *rwqe)
{
ibt_status_t ret;
uint8_t *mp_base;
size_t mp_len;
rwqe->qe_sgl.ds_va = (ib_vaddr_t)(uintptr_t)rwqe->qe_cpbuf;
rwqe->qe_sgl.ds_len = rwqe->qe_bufsz;
if (chan->ch_ip_hdr_align) {
rwqe->qe_sgl.ds_va += chan->ch_ip_hdr_align;
rwqe->qe_sgl.ds_len -= chan->ch_ip_hdr_align;
}
if (chan->ch_alloc_mp) {
mp_base = (uint8_t *)(uintptr_t)(rwqe->qe_sgl.ds_va);
mp_len = rwqe->qe_sgl.ds_len;
rwqe->qe_mp = desballoc(mp_base, mp_len, 0, &rwqe->qe_frp);
if (rwqe->qe_mp == NULL) {
EIB_DPRINTF_ERR(ss->ei_instance, "eib_chan_post_recv: "
"desballoc(base=0x%llx, len=0x%llx) failed",
mp_base, mp_len);
return (EIB_E_FAILURE);
}
}
mutex_enter(&chan->ch_rx_lock);
if (chan->ch_rx_posted > (chan->ch_max_rwqes - 1)) {
EIB_DPRINTF_ERR(ss->ei_instance, "eib_chan_post_recv: "
"too many rwqes posted already, posted=0x%lx, max=0x%lx",
chan->ch_rx_posted, chan->ch_max_rwqes);
mutex_exit(&chan->ch_rx_lock);
return (EIB_E_FAILURE);
}
rwqe->qe_vnic_inst = chan->ch_vnic_inst;
rwqe->qe_chan = chan;
rwqe->qe_info |= EIB_WQE_FLG_POSTED_TO_HCA;
ret = ibt_post_recv(chan->ch_chan, &(rwqe->qe_wr.recv), 1, NULL);
if (ret != IBT_SUCCESS) {
EIB_DPRINTF_ERR(ss->ei_instance, "eib_chan_post_recv: "
"ibt_post_recv() failed, ret=%d", ret);
mutex_exit(&chan->ch_rx_lock);
return (EIB_E_FAILURE);
}
chan->ch_rx_posted++;
mutex_exit(&chan->ch_rx_lock);
return (EIB_E_SUCCESS);
}