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 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #ifndef _SYS_IB_ADAPTERS_TAVOR_WR_H
28 #define _SYS_IB_ADAPTERS_TAVOR_WR_H
32 * Contains all of the prototypes, #defines, and structures necessary
33 * for the Tavor Work Request Processing Routines
34 * Specifically it contains #defines, macros, and prototypes for each of
35 * building each of the various types of WQE and for managing the WRID
36 * tracking mechanisms.
39 #include <sys/types.h>
42 #include <sys/sunddi.h>
49 * The following macro is used to convert WQE address and size into the
50 * "wqeaddrsz" value needed in the tavor_wrid_entry_t (see below).
52 #define TAVOR_QP_WQEADDRSZ(addr, size) \
53 ((((uintptr_t)(addr)) & ~TAVOR_WQE_NDS_MASK) | \
54 ((size) & TAVOR_WQE_NDS_MASK))
57 * The following macros are used to calculate pointers to the Send or Receive
58 * (or SRQ) WQEs on a given QP, respectively
60 #define TAVOR_QP_SQ_ENTRY(qp, tail) \
61 ((uint64_t *)((uintptr_t)((qp)->qp_sq_buf) + \
62 ((tail) << (qp)->qp_sq_log_wqesz)))
63 #define TAVOR_QP_RQ_ENTRY(qp, tail) \
64 ((uint64_t *)((uintptr_t)((qp)->qp_rq_buf) + \
65 ((tail) << (qp)->qp_rq_log_wqesz)))
66 #define TAVOR_SRQ_WQ_ENTRY(srq, tail) \
67 ((uint64_t *)((uintptr_t)((srq)->srq_wq_buf) + \
68 ((tail) << (srq)->srq_wq_log_wqesz)))
71 * The following macro is used to calculate the 'wqe_index' field during SRQ
72 * operation. This returns the index based on the WQE size, that can be used
73 * to reference WQEs in an SRQ.
75 #define TAVOR_SRQ_WQE_INDEX(srq_base_addr, wqe_addr, log_wqesz) \
76 (((uint32_t)(uintptr_t)wqe_addr - \
77 (uint32_t)(uintptr_t)srq_base_addr) >> log_wqesz)
79 #define TAVOR_SRQ_WQE_ADDR(srq, wqe_index) \
80 ((uint64_t *)((uintptr_t)srq->srq_wq_buf + \
81 (wqe_index << srq->srq_wq_log_wqesz)))
84 * The following macros are used to access specific fields in Directed Route
85 * MAD packets. We can extract the MgmtClass, "hop pointer", and "hop count".
86 * We can also update the "hop pointer" as appropriate. Note: Again, because
87 * of the limited amount of direct handling the Tavor hardware does on special
88 * QP request (specifically on Directed Route MADs), the driver needs to
89 * update (as necessary) the "hop pointer" value depending on whether a MAD
90 * is outbound or inbound (i.e. depending on the relationship between "hop
91 * pointer" and "hop count" in the given MAD)
93 #define TAVOR_SPECIAL_QP_DRMAD_GET_MGMTCLASS(mgmtclass, offset, va, len) \
94 if (((mgmtclass) == NULL) && ((offset) + (len) > 1)) { \
95 (mgmtclass) = &((uint8_t *)(uintptr_t)(va))[1 - (offset)]; \
97 #define TAVOR_SPECIAL_QP_DRMAD_GET_HOPPOINTER(hp, offset, va, len) \
98 if (((hp) == NULL) && \
99 ((offset) + (len) > 6)) { \
100 (hp) = &((uint8_t *)(uintptr_t)(va))[6 - (offset)]; \
102 #define TAVOR_SPECIAL_QP_DRMAD_GET_HOPCOUNT(hc, offset, va, len) \
103 if (((hc) == NULL) && \
104 ((offset) + (len) > 7)) { \
105 (hc) = &((uint8_t *)(uintptr_t)(va))[7 - (offset)]; \
107 #define TAVOR_SPECIAL_QP_DRMAD_DO_HOPPOINTER_MODIFY(mgmtclass, hp, hc) \
108 if ((mgmtclass) == 0x81) { \
111 } else if ((hp) > (hc)) { \
118 * The tavor_wrid_entry_s structure is used internally by the Tavor
119 * driver to contain all the information necessary for tracking WRIDs.
120 * Specifically, this structure contains the 64-bit WRID, the 32-bit quantity
121 * called "wr_wqeaddrsz" (which can also be found in every CQE), and the
122 * "wr_signaled_dbd" information which indicates whether a given entry was
123 * signaled or not and whether a doorbell was subsequently rung for this
124 * particular work request. Note: the latter piece of information is
125 * particularly useful during completion processing on errored CQEs.
127 struct tavor_wrid_entry_s
{
129 uint32_t wr_wqeaddrsz
;
130 uint32_t wr_signaled_dbd
;
132 #define TAVOR_WRID_ENTRY_SIGNALED (1 << 0)
133 #define TAVOR_WRID_ENTRY_DOORBELLED (1 << 1)
136 * The tavor_sw_wqe_dbinfo_t structure is used internally by the Tavor
137 * driver to return information (from the tavor_wqe_mlx_build_nextctl() and
138 * tavor_wqe_send_build_nextctl() routines) regarding the type of Tavor
139 * doorbell necessary.
141 typedef struct tavor_sw_wqe_dbinfo_s
{
144 } tavor_sw_wqe_dbinfo_t
;
147 * The Work Queue Lock (WQL) structure. Each WQHDR (tavor_workq_hdr_t defined
148 * below) must lock access to the wridlist during any wridlist manipulation.
149 * Also, any Shared Receive Queue (SRQ) must also be able to lock the wridlist
150 * since it maintains wridlist's differently than normal QPs. This
151 * 'tavor_wq_lock_t' structure is shared and accessible through the WQ or the
152 * SRQ, and refcnt is maintained. The last entity to decrement use of the
153 * lock, also will free up the memory.
155 struct tavor_wq_lock_s
{
161 * The tavor_wrid_list_hdr_s structure is used internally by the Tavor driver
162 * to track all the information necessary to manage a queue of WRID entries
163 * (the tavor_wrid_entry_s struct above).
164 * It contains some information regarding the status of a given WRID list
165 * (e.g. head index, tail index, queue full condition, etc.). Note: Although
166 * some of this information is also kept by the tavor_workq_hdr_s below, what
167 * is kept here may, in fact, represent the state of an old WRID list. It
168 * could be different from what is kept in the tavor_workq_hdr_s because this
169 * WRID list may no longer be the active WRID list. If it is an active list,
170 * however, then both sets of information should be up-to-date and consistent.
171 * Several of these structures are chained together on each work queue header
172 * to form a linked list (using the "wl_next" and "wl_prev"). These structs,
173 * in turn, each have a pointer to a queue of WRID entries. They also each
174 * have a pointer to the next "reapable" entry ("wl_reap_next") which is only
175 * used when a WRID list has been retired and is ready to be freed up.
176 * Lastly, it has a backpointer to the work queue header to which the WRID
177 * list belongs (this is for proper handling on removal).
179 struct tavor_wrid_list_hdr_s
{
180 tavor_wrid_list_hdr_t
*wl_next
;
181 tavor_wrid_list_hdr_t
*wl_prev
;
182 tavor_wrid_list_hdr_t
*wl_reap_next
;
183 tavor_workq_hdr_t
*wl_wqhdr
;
185 tavor_wrid_entry_t
*wl_wre
;
186 tavor_wrid_entry_t
*wl_wre_old_tail
;
194 int wl_free_list_indx
;
195 ddi_acc_handle_t wl_acchdl
;
196 uint32_t *wl_srq_wq_buf
;
197 uint32_t wl_srq_wq_bufsz
;
198 uint64_t wl_srq_desc_off
;
199 uint32_t wl_srq_log_wqesz
;
201 _NOTE(MUTEX_PROTECTS_DATA(tavor_sw_cq_s::cq_wrid_wqhdr_lock
,
202 tavor_wrid_list_hdr_s::wl_next
203 tavor_wrid_list_hdr_s::wl_prev
204 tavor_wrid_list_hdr_s::wl_wqhdr
))
205 _NOTE(MUTEX_PROTECTS_DATA(tavor_wq_lock_s::wql_lock
,
206 tavor_wrid_list_hdr_s::wl_wre
207 tavor_wrid_list_hdr_s::wl_wre_old_tail
208 tavor_wrid_list_hdr_s::wl_size
209 tavor_wrid_list_hdr_s::wl_full
210 tavor_wrid_list_hdr_s::wl_head
211 tavor_wrid_list_hdr_s::wl_tail
212 tavor_wrid_list_hdr_s::wl_srq_en
213 tavor_wrid_list_hdr_s::wl_free_list_indx
214 tavor_wrid_list_hdr_s::wl_acchdl
215 tavor_wrid_list_hdr_s::wl_srq_wq_buf
216 tavor_wrid_list_hdr_s::wl_srq_desc_off
217 tavor_wrid_list_hdr_s::wl_srq_log_wqesz
))
220 * The tavor_workq_hdr_s structure is used internally by the Tavor driver to
221 * track all the information necessary to manage the work queues associated
222 * with a given completion queue. It contains much of the information
223 * regarding the status of a given work queue (e.g. head index, tail index,
224 * queue full condition, etc.). Note: This information is kept here (i.e.
225 * associated with a completion queue) rather than as part of the QP because
226 * the queue pair may potentially be destroyed while outstanding CQEs still
228 * Several of these structures are chained together on each CQ to form a
229 * linked list (using the "wq_next" and "wq_prev"). These headers, in turn,
230 * link to the containers for the individual WRID entries (managed with the
231 * tavor_wrid_list_hdr_s structs above). Note: We keep a list of these
232 * tavor_wrid_list_hdr_s because a given QP may be used, destroyed (or
233 * transition to "Reset"), and then reused. The list helps us track where
234 * to put new WRID entries and where to pull old entries from.
235 * The "wq_qpn" (QP number) and "wq_send_or_recv" (TAVOR_WR_SEND or
236 * TAVOR_WR_RECV) are used to uniquely identify the given work queue.
237 * Lookups into the work queue list (to find a given work queue) will use
238 * these two fields as identifiers.
240 struct tavor_workq_hdr_s
{
241 avl_node_t wq_avl_link
;
245 tavor_wq_lock_t
*wq_wrid_wql
;
251 tavor_wrid_list_hdr_t
*wq_wrid_poll
;
252 tavor_wrid_list_hdr_t
*wq_wrid_post
;
254 _NOTE(MUTEX_PROTECTS_DATA(tavor_sw_cq_s::cq_wrid_wqhdr_lock
,
255 tavor_workq_hdr_s::wq_avl_link
256 tavor_workq_hdr_s::wq_qpn
257 tavor_workq_hdr_s::wq_type
258 tavor_sw_cq_s::cq_wrid_reap_head
259 tavor_sw_cq_s::cq_wrid_reap_tail
))
260 _NOTE(MUTEX_PROTECTS_DATA(tavor_wq_lock_s::wql_lock
,
261 tavor_workq_hdr_s::wq_size
262 tavor_workq_hdr_s::wq_head
263 tavor_workq_hdr_s::wq_tail
264 tavor_workq_hdr_s::wq_full
265 tavor_workq_hdr_s::wq_wrid_poll
266 tavor_workq_hdr_s::wq_wrid_post
267 tavor_wrid_list_hdr_s::wl_wre
268 tavor_wrid_list_hdr_s::wl_wre_old_tail
269 tavor_wrid_list_hdr_s::wl_size
270 tavor_wrid_list_hdr_s::wl_full
271 tavor_wrid_list_hdr_s::wl_head
272 tavor_wrid_list_hdr_s::wl_tail
))
273 _NOTE(MUTEX_PROTECTS_DATA(tavor_sw_cq_s::cq_wrid_wqhdr_lock
,
274 tavor_wrid_list_hdr_s::wl_reap_next
))
275 _NOTE(LOCK_ORDER(tavor_sw_cq_s::cq_lock
276 tavor_sw_cq_s::cq_wrid_wqhdr_lock
277 tavor_wq_lock_s::wql_lock
))
278 #define TAVOR_WR_RECV 0x0
279 #define TAVOR_WR_SEND 0x1
280 #define TAVOR_WR_SRQ 0x2
282 extern int tavor_wrid_wqhdr_compare(const void *p1
, const void *p2
);
283 typedef struct tavor_workq_compare_s
{
286 } tavor_workq_compare_t
;
288 /* For Work Request posting */
289 int tavor_post_send(tavor_state_t
*state
, tavor_qphdl_t qphdl
,
290 ibt_send_wr_t
*wr_p
, uint_t num_wr
, uint_t
*num_posted
);
291 int tavor_post_recv(tavor_state_t
*state
, tavor_qphdl_t qphdl
,
292 ibt_recv_wr_t
*wr_p
, uint_t num_wr
, uint_t
*num_posted
);
293 int tavor_post_srq(tavor_state_t
*state
, tavor_srqhdl_t srqhdl
,
294 ibt_recv_wr_t
*wr_p
, uint_t num_wr
, uint_t
*num_posted
);
296 /* For WRID handling */
297 int tavor_wrid_from_reset_handling(tavor_state_t
*state
, tavor_qphdl_t qp
);
298 void tavor_wrid_to_reset_handling(tavor_state_t
*state
, tavor_qphdl_t qp
);
299 void tavor_wrid_add_entry(tavor_workq_hdr_t
*wq
, uint64_t wrid
,
300 uint32_t wqeaddr_sz
, uint_t signaled_dbd
);
301 void tavor_wrid_add_entry_srq(tavor_srqhdl_t srq
, uint64_t wrid
,
302 uint_t signaled_dbd
);
303 uint64_t tavor_wrid_get_entry(tavor_cqhdl_t cqhdl
, tavor_hw_cqe_t
*cqe
,
304 tavor_wrid_entry_t
*wre
);
305 tavor_wq_lock_t
*tavor_wrid_wql_create(tavor_state_t
*state
);
306 tavor_wrid_list_hdr_t
*tavor_wrid_get_list(uint32_t size
);
307 void tavor_wrid_list_srq_init(tavor_wrid_list_hdr_t
*r_wridlist
,
308 tavor_srqhdl_t srq
, uint_t wq_start
);
309 void tavor_wrid_cq_reap(tavor_cqhdl_t cq
);
310 void tavor_wrid_cq_force_reap(tavor_cqhdl_t cq
);
311 void tavor_wql_refcnt_dec(tavor_wq_lock_t
*wq_lock
);
312 void tavor_wql_refcnt_inc(tavor_wq_lock_t
*wq_lock
);
313 tavor_wrid_entry_t
*tavor_wrid_find_match_srq(tavor_wrid_list_hdr_t
*wq
,
314 tavor_cqhdl_t cq
, tavor_hw_cqe_t
*cqe
);
320 #endif /* _SYS_IB_ADAPTERS_TAVOR_WR_H */