4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
26 #include <sys/types.h>
30 #include <sys/sunddi.h>
31 #include <sys/ksynch.h>
33 #include <sys/ib/clients/eoib/eib_impl.h>
41 * Allocate a eib_chan_t to store stuff about admin qp and
42 * initialize some basic stuff
44 chan
= kmem_zalloc(sizeof (eib_chan_t
), KM_SLEEP
);
46 mutex_init(&chan
->ch_pkey_lock
, NULL
, MUTEX_DRIVER
, NULL
);
47 mutex_init(&chan
->ch_cep_lock
, NULL
, MUTEX_DRIVER
, NULL
);
48 mutex_init(&chan
->ch_tx_lock
, NULL
, MUTEX_DRIVER
, NULL
);
49 mutex_init(&chan
->ch_rx_lock
, NULL
, MUTEX_DRIVER
, NULL
);
50 mutex_init(&chan
->ch_vhub_lock
, NULL
, MUTEX_DRIVER
, NULL
);
52 cv_init(&chan
->ch_cep_cv
, NULL
, CV_DEFAULT
, NULL
);
53 cv_init(&chan
->ch_tx_cv
, NULL
, CV_DEFAULT
, NULL
);
54 cv_init(&chan
->ch_rx_cv
, NULL
, CV_DEFAULT
, NULL
);
60 eib_chan_fini(eib_chan_t
*chan
)
63 cv_destroy(&chan
->ch_rx_cv
);
64 cv_destroy(&chan
->ch_tx_cv
);
65 cv_destroy(&chan
->ch_cep_cv
);
67 mutex_destroy(&chan
->ch_vhub_lock
);
68 mutex_destroy(&chan
->ch_rx_lock
);
69 mutex_destroy(&chan
->ch_tx_lock
);
70 mutex_destroy(&chan
->ch_cep_lock
);
71 mutex_destroy(&chan
->ch_pkey_lock
);
73 kmem_free(chan
, sizeof (eib_chan_t
));
78 eib_chan_post_rx(eib_t
*ss
, eib_chan_t
*chan
, uint_t
*n_posted
)
80 eib_wqe_t
*rwqes
[EIB_RWR_CHUNK_SZ
];
91 * We don't want to post beyond the maximum rwqe size for this channel
93 room
= chan
->ch_max_rwqes
- chan
->ch_rx_posted
;
94 limit
= (room
> chan
->ch_rwqe_bktsz
) ? chan
->ch_rwqe_bktsz
: room
;
96 for (wndx
= 0; wndx
< limit
; wndx
+= chunk_sz
) {
98 * Grab a chunk of rwqes
100 chunk_sz
= ((limit
- wndx
) < EIB_RWR_CHUNK_SZ
) ?
101 (limit
- wndx
) : EIB_RWR_CHUNK_SZ
;
104 * When eib_chan_post_rx() is called to post a bunch of rwqes,
105 * it is either during the vnic setup or when we're refilling
106 * the data channel. Neither situation is important enough for
107 * us to grab the wqes reserved for sending keepalives of
108 * previously established vnics.
110 ret
= eib_rsrc_grab_rwqes(ss
, rwqes
, chunk_sz
, &n_got
,
112 if (ret
!= EIB_E_SUCCESS
)
116 * Post work requests from the rwqes we just grabbed
118 for (i
= 0; i
< n_got
; i
++) {
119 eib_wqe_t
*rwqe
= rwqes
[i
];
121 ret
= eib_chan_post_recv(ss
, chan
, rwqe
);
122 if (ret
== EIB_E_SUCCESS
) {
124 } else if (rwqe
->qe_mp
) {
125 freemsg(rwqe
->qe_mp
);
127 eib_rsrc_return_rwqe(ss
, rwqe
, NULL
);
132 * If we got less rwqes than we asked for during the grab
133 * earlier, we'll stop asking for more and quit now.
135 if (n_got
< chunk_sz
)
140 * If we posted absolutely nothing, we return failure; otherwise
144 return (EIB_E_FAILURE
);
149 return (EIB_E_SUCCESS
);
154 eib_chan_post_recv(eib_t
*ss
, eib_chan_t
*chan
, eib_wqe_t
*rwqe
)
160 rwqe
->qe_sgl
.ds_va
= (ib_vaddr_t
)(uintptr_t)rwqe
->qe_cpbuf
;
161 rwqe
->qe_sgl
.ds_len
= rwqe
->qe_bufsz
;
164 * If this channel has receive buffer alignment restrictions, make
165 * sure the requirements are met
167 if (chan
->ch_ip_hdr_align
) {
168 rwqe
->qe_sgl
.ds_va
+= chan
->ch_ip_hdr_align
;
169 rwqe
->qe_sgl
.ds_len
-= chan
->ch_ip_hdr_align
;
173 * If the receive buffer for this channel needs to have an mblk
176 if (chan
->ch_alloc_mp
) {
177 mp_base
= (uint8_t *)(uintptr_t)(rwqe
->qe_sgl
.ds_va
);
178 mp_len
= rwqe
->qe_sgl
.ds_len
;
180 rwqe
->qe_mp
= desballoc(mp_base
, mp_len
, 0, &rwqe
->qe_frp
);
181 if (rwqe
->qe_mp
== NULL
) {
182 EIB_DPRINTF_ERR(ss
->ei_instance
, "eib_chan_post_recv: "
183 "desballoc(base=0x%llx, len=0x%llx) failed",
185 return (EIB_E_FAILURE
);
190 * Check if the recv queue is already full or if we can post one more
192 mutex_enter(&chan
->ch_rx_lock
);
193 if (chan
->ch_rx_posted
> (chan
->ch_max_rwqes
- 1)) {
194 EIB_DPRINTF_ERR(ss
->ei_instance
, "eib_chan_post_recv: "
195 "too many rwqes posted already, posted=0x%lx, max=0x%lx",
196 chan
->ch_rx_posted
, chan
->ch_max_rwqes
);
197 mutex_exit(&chan
->ch_rx_lock
);
198 return (EIB_E_FAILURE
);
201 rwqe
->qe_vnic_inst
= chan
->ch_vnic_inst
;
202 rwqe
->qe_chan
= chan
;
203 rwqe
->qe_info
|= EIB_WQE_FLG_POSTED_TO_HCA
;
205 ret
= ibt_post_recv(chan
->ch_chan
, &(rwqe
->qe_wr
.recv
), 1, NULL
);
206 if (ret
!= IBT_SUCCESS
) {
207 EIB_DPRINTF_ERR(ss
->ei_instance
, "eib_chan_post_recv: "
208 "ibt_post_recv() failed, ret=%d", ret
);
209 mutex_exit(&chan
->ch_rx_lock
);
210 return (EIB_E_FAILURE
);
212 chan
->ch_rx_posted
++;
213 mutex_exit(&chan
->ch_rx_lock
);
215 return (EIB_E_SUCCESS
);