xref: /illumos-gate/usr/src/uts/common/io/ib/ibtl/ibtl_cq.c (revision f7327bbd956f5bf6b97f9b90e0c81e8344d8835f)
1 /*
2  * CDDL HEADER START
3  *
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.
7  *
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.
12  *
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]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
23  */
24 
25 #include <sys/ib/ibtl/impl/ibtl.h>
26 
27 /*
28  * ibtl_cq.c
29  *	These routines implement (most of) the verbs related to
30  *	Completion Queues.
31  */
32 
33 /*
34  * Globals
35  */
36 
37 static char ibtf_cq[] = "ibtl_cq";
38 
39 /*
40  * This file contains code for the  TI CQ calls
41  */
42 
43 /*
44  * ibt_alloc_cq_sched() - Reserve CQ scheduling class resources
45  *
46  *	chan	    - IBT Channel Handle.
47  *	load	    - Expected CQ load in class, 0 = unspecified
48  *      sched_hdl_p - Returned scheduling handle.
49  */
50 ibt_status_t
51 ibt_alloc_cq_sched(ibt_hca_hdl_t hca_hdl, ibt_cq_sched_attr_t *attr,
52     ibt_sched_hdl_t *sched_hdl_p)
53 {
54 	ibc_cq_handler_attr_t	handler_attrs;
55 	ibt_cq_priority_t	priority;
56 
57 	IBTF_DPRINTF_L3(ibtf_cq, "ibt_alloc_cq_sched(%p, %p, %p)",
58 	    hca_hdl, attr, sched_hdl_p);
59 
60 	/* Validate and Convert the IBT CQ priority */
61 	priority = attr->cqs_priority;
62 
63 	if ((priority < IBT_CQ_DEFAULT) || (priority > IBT_CQ_PRI_16)) {
64 		return (IBT_CQ_INVALID_PRIORITY);
65 	}
66 
67 
68 	/*
69 	 * Do we need to check for valid range for load ? What's the valid
70 	 * range?
71 	 */
72 	*sched_hdl_p = NULL;	/* Function not implemented fully yet */
73 
74 	return (IBTL_HCA2CIHCAOPS_P(hca_hdl)->ibc_alloc_cq_sched(
75 	    IBTL_HCA2CIHCA(hca_hdl), attr->cqs_flags, &handler_attrs));
76 }
77 
78 
79 /*
80  * ibt_free_cq_sched() - Free CQ scheduling class resources
81  *
82  *	chan	  - IBT Channel Handle.
83  *      sched_hdl - Scheduling handle returned from ibt_alloc_cq_sched.
84  *	load	  - CQ load being removed.
85  */
86 ibt_status_t
87 ibt_free_cq_sched(ibt_hca_hdl_t hca_hdl, ibt_sched_hdl_t sched_hdl,
88     uint_t load)
89 {
90 	ibt_cq_handler_id_t	handler_id = 0;
91 
92 	IBTF_DPRINTF_L3(ibtf_cq, "ibt_free_cq_sched(%p, %d, %p)",
93 	    hca_hdl, sched_hdl, load);
94 
95 	/*
96 	 * Function not fully implemented should get handler ID from
97 	 * sched_hdl.
98 	 */
99 	return (IBTL_HCA2CIHCAOPS_P(hca_hdl)->ibc_free_cq_sched(
100 	    IBTL_HCA2CIHCA(hca_hdl), handler_id));
101 }
102 
103 
104 /*
105  *
106  * ibt_alloc_cq() - Allocate a completion queue
107  */
108 ibt_status_t
109 ibt_alloc_cq(ibt_hca_hdl_t hca_hdl, ibt_cq_attr_t *cq_attr,
110     ibt_cq_hdl_t *ibt_cq_p, uint32_t *real_size)
111 {
112 	ibt_status_t 		status;
113 	ibt_cq_hdl_t		ibt_cq;
114 
115 	IBTF_DPRINTF_L3(ibtf_cq, "ibt_alloc_cq(%p, %p)",
116 	    hca_hdl, cq_attr);
117 
118 
119 	ibt_cq = kmem_zalloc(sizeof (struct ibtl_cq_s), KM_SLEEP);
120 	*ibt_cq_p = ibt_cq;
121 
122 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(ibt_cq->cq_in_thread))
123 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(ibt_cq->cq_ibc_cq_hdl))
124 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(ibt_cq->cq_hca))
125 	/*
126 	 * Set the following values before creating CI CQ, to avoid race
127 	 * conditions on async callback.
128 	 */
129 	ibt_cq->cq_hca = hca_hdl;
130 
131 	ibtl_qp_flow_control_enter();
132 	status = IBTL_HCA2CIHCAOPS_P(hca_hdl)->ibc_alloc_cq(
133 	    IBTL_HCA2CIHCA(hca_hdl), ibt_cq, cq_attr, &ibt_cq->cq_ibc_cq_hdl,
134 	    real_size);
135 	ibtl_qp_flow_control_exit();
136 
137 	if (status != IBT_SUCCESS) {
138 		IBTF_DPRINTF_L2(ibtf_cq, "ibt_alloc_cq: "
139 		    "CI CQ handle allocation failed: status = %d", status);
140 		kmem_free(ibt_cq, sizeof (struct ibtl_cq_s));
141 		*ibt_cq_p = NULL;
142 		return (status);
143 	}
144 
145 	if (cq_attr->cq_flags & IBT_CQ_HANDLER_IN_THREAD) {
146 		ibt_cq->cq_in_thread = 1;
147 		/* We may want additional CQ threads now. */
148 		ibtl_another_cq_handler_in_thread();
149 	}
150 	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(ibt_cq->cq_in_thread))
151 	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(ibt_cq->cq_ibc_cq_hdl))
152 	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(ibt_cq->cq_hca))
153 
154 	mutex_init(&ibt_cq->cq_mutex, NULL, MUTEX_DEFAULT, NULL);
155 
156 	/* Update the cq resource count */
157 	atomic_inc_32(&hca_hdl->ha_cq_cnt);
158 
159 	return (IBT_SUCCESS);
160 }
161 
162 
163 /*
164  * ibt_free_cq() - Free a completion queue
165  *
166  */
167 ibt_status_t
168 ibt_free_cq(ibt_cq_hdl_t ibt_cq)
169 {
170 	ibt_status_t	status;
171 	ibtl_hca_t	*ibt_hca = ibt_cq->cq_hca;
172 
173 	IBTF_DPRINTF_L3(ibtf_cq, "ibt_free_cq(%p)", ibt_cq);
174 
175 	ibtl_free_cq_check(ibt_cq);
176 
177 	status = ((IBTL_CQ2CIHCAOPS_P(ibt_cq))->ibc_free_cq)
178 	    (IBTL_CQ2CIHCA(ibt_cq), ibt_cq->cq_ibc_cq_hdl);
179 
180 	if (status != IBT_SUCCESS) {
181 		IBTF_DPRINTF_L2(ibtf_cq, "ibt_free_cq: "
182 		    "CI CQ handle de-allocation failed: status = %d", status);
183 		return (status);
184 	}
185 
186 	/* mutex_destroy(&ibt_cq->cq_mutex); */
187 	ibtl_free_cq_async_check(ibt_cq);
188 
189 	/* Update the cq resource count */
190 	atomic_dec_32(&ibt_hca->ha_cq_cnt);
191 
192 	return (status);
193 }
194 
195 
196 /*
197  * ibt_query_cq() - Returns the size of the cq
198  */
199 ibt_status_t
200 ibt_query_cq(ibt_cq_hdl_t ibt_cq, uint32_t *entries_p, uint_t *count_p,
201     uint_t *usec_p, ibt_cq_handler_id_t *hid_p)
202 {
203 	IBTF_DPRINTF_L3(ibtf_cq, "ibt_query_cq(%p)", ibt_cq);
204 
205 	return (IBTL_CQ2CIHCAOPS_P(ibt_cq)->ibc_query_cq(IBTL_CQ2CIHCA(ibt_cq),
206 	    ibt_cq->cq_ibc_cq_hdl, entries_p, count_p, usec_p, hid_p));
207 }
208 
209 
210 /*
211  *  ibt_resize_cq() - Change the size of a cq.
212  */
213 ibt_status_t
214 ibt_resize_cq(ibt_cq_hdl_t ibt_cq, uint32_t new_sz, uint32_t *real_sz)
215 {
216 	IBTF_DPRINTF_L3(ibtf_cq, "ibt_resize_cq(%p, %d)", ibt_cq, new_sz);
217 
218 	return (IBTL_CQ2CIHCAOPS_P(ibt_cq)->ibc_resize_cq(IBTL_CQ2CIHCA(ibt_cq),
219 	    ibt_cq->cq_ibc_cq_hdl, new_sz, real_sz));
220 }
221 
222 ibt_status_t
223 ibt_modify_cq(ibt_cq_hdl_t ibt_cq, uint_t count, uint_t usec,
224     ibt_cq_handler_id_t hid)
225 {
226 	IBTF_DPRINTF_L3(ibtf_cq, "ibt_modify_cq(%p, %d, %d, %d)", ibt_cq, count,
227 	    usec, hid);
228 
229 	return (IBTL_CQ2CIHCAOPS_P(ibt_cq)->ibc_modify_cq(IBTL_CQ2CIHCA(ibt_cq),
230 	    ibt_cq->cq_ibc_cq_hdl, count, usec, hid));
231 }
232 
233 
234 /*
235  * ibt_poll_cq()
236  *      Poll the specified CQ for a work request (WR) completion. If a CQ
237  *      contains a completed WR, the completed WR at the head of the CQ is
238  *      returned.
239  *
240  *      ibt_cq                  The CQ handle.
241  *
242  *      work_completions        An array of work completions.
243  *
244  *      num_wc                  Size of the Work completion array. The
245  *                              requested number of completions.
246  *
247  *      num_polled              The actual number of completions returned.
248  *
249  */
250 ibt_status_t
251 ibt_poll_cq(ibt_cq_hdl_t ibt_cq, ibt_wc_t *work_completions, uint_t num_wc,
252     uint_t *num_polled)
253 {
254 	IBTF_DPRINTF_L4(ibtf_cq, "ibt_poll_cq(%p)", ibt_cq);
255 
256 	return (IBTL_CQ2CIHCAOPS_P(ibt_cq)->ibc_poll_cq(IBTL_CQ2CIHCA(ibt_cq),
257 	    ibt_cq->cq_ibc_cq_hdl, work_completions, num_wc, num_polled));
258 }
259 
260 _NOTE(SCHEME_PROTECTS_DATA("client managed", ibtl_cq_s::cq_clnt_private))
261 
262 /*
263  * ibt_set_cq_private - Sets the private data on a given CQ
264  *
265  *      ibt_cq          The ibt_cq_hdl_t of the allocated CQ.
266  *      clnt_private    The client private data.
267  */
268 void
269 ibt_set_cq_private(ibt_cq_hdl_t ibt_cq, void *clnt_private)
270 {
271 	ibt_cq->cq_clnt_private = clnt_private;
272 }
273 
274 
275 /*
276  * ibt_get_cq_private - Retrieves the private data for a given CQ
277  *
278  *      ibt_cq          The ibt_cq_hdl_t of the allocated CQ.
279  */
280 void *
281 ibt_get_cq_private(ibt_cq_hdl_t ibt_cq)
282 {
283 	return (ibt_cq->cq_clnt_private);
284 }
285