summaryrefslogtreecommitdiff
path: root/usr/src/uts/common/sys/ib/adapters/hermon/hermon_qp.h
blob: 0086ee93a031f0b215d21f32135c870f2ca9f153 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */

/*
 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
 */

#ifndef	_SYS_IB_ADAPTERS_HERMON_QP_H
#define	_SYS_IB_ADAPTERS_HERMON_QP_H

/*
 * hermon_qp.h
 *    Contains all of the prototypes, #defines, and structures necessary
 *    for all of the Queue Pair Processing routines.
 *    Specifically it contains the various flags, structures used for managing
 *    Hermon queue pairs, and prototypes for many of the functions consumed by
 *    other parts of the Hermon driver (including those routines directly
 *    exposed through the IBTF CI interface).
 *
 *    Most of the values defined below establish default values which,
 *    where indicated, can be controlled via their related patchable values,
 *    if 'hermon_alt_config_enable' is set.
 */

#include <sys/types.h>
#include <sys/conf.h>
#include <sys/ddi.h>
#include <sys/sunddi.h>

#ifdef __cplusplus
extern "C" {
#endif

/*
 * The following defines the default number of Queue Pairs. This value is
 * controlled via the "hermon_log_num_qp" configuration variables.
 * We also have a define for the minimum size of a QP.  QPs allocated
 * with size 0, 1, 2, or 3 will always get back a QP of size 4.
 *
 * Note: Increasing #QPs from 64K to 256K for reserved ranges for FCoIB.
 */
#define	HERMON_NUM_QP_SHIFT		0x12
#define	HERMON_NUM_QPS			(1 << HERMON_NUM_QP_SHIFT) /* 256K */
#define	HERMON_QP_MIN_SIZE		0xf

/*
 * The following defines the default number of Hermon RDMA Remote read
 * database (RDB) entries per QP.  This value is controllable through the
 * "hermon_log_num_rdb_per_qp" configuration variable.
 */
#define	HERMON_LOG_NUM_RDB_PER_QP	0x4

/*
 * This defines the maximum number of SGLs per WQE.  This value is
 * controllable through the "hermon_wqe_max_sgl" configuration variable
 * (but should not be set larger than this value).
 */
#define	HERMON_NUM_SGL_PER_WQE		0x10

/*
 * Maximum QP number mask (QP number is 24 bits).
 * We reserve the most significant bit to indicate an "XRC" QP
 * as recommended by the PRM.  All XRC QPs will have this bit set.
 */
#define	HERMON_QP_MAXNUMBER_MSK		0x7FFFFF
#define	HERMON_QP_XRC_MSK		0x800000

/*
 * This define and the following macro are used to find a schedule queue for
 * a new QP based on its queue pair number.  Note:  This is a rather simple
 * method that we use today.  We simply choose from the schedule queue based
 * on the 4 least significant bits of the QP number.
 */

/*
 * The following defines are used to indicate whether a QP is special or
 * not (and what type it is).  They are used in the "qp_is_special" field
 * below in qp_state.  If "qp_is_special" == 0 then an ordinary data qp.
 */

/*
 * The sl is selected based on the qpnum as it was for Tavor/Arbel, except for
 * QP0, which is defined as being 0xF
 */

#define	HERMON_QP_SMI			0x1
#define	HERMON_QP_GSI			0x2

#define	HERMON_DEF_SCHED_POLICY		0x03
#define	HERMON_DEF_SCHED_SELECTION	0x0F

#define	HERMON_QP_SCHEDQ_GET(port, sl, issmi)   \
	(HERMON_DEF_SCHED_POLICY 		\
	| (issmi == HERMON_QP_SMI ? (HERMON_DEF_SCHED_SELECTION << 2) : \
	((issmi == HERMON_QP_GSI ? 0 : (sl & 0XF)) << 2)) \
	| ((port & 0x01) << 6) \
	| ((issmi == HERMON_QP_SMI ? 0 : 1) << 7))


/*
 * This define determines the frequency with which the AckReq bit will be
 * set in outgoing RC packets.  By default it is set to five (5) or 2^5 = 32.
 * So AckReq will be set once every 32 packets sent.  This value is
 * controllable through the "hermon_qp_ackreq_freq" configuration variable.
 */
#define	HERMON_QP_ACKREQ_FREQ		0x5

/*
 * Define the maximum message size (log 2).  Note: This value corresponds
 * to the maximum allowable message sized as defined by the IBA spec.
 */
#define	HERMON_QP_LOG_MAX_MSGSZ		0x1F

/*
 * This macro is used to determine if the hermon QP type (qp_serv) is the
 * same as the caller passed in IBT type (qp_trans).  This is used in QP modify
 * to ensure the types match.
 */
#define	HERMON_QP_TYPE_VALID(qp_trans, qp_serv)				\
	((qp_trans == IBT_RC_SRV && qp_serv == HERMON_QP_RC) ||		\
	(qp_trans == IBT_UD_SRV && (qp_serv == HERMON_QP_UD ||		\
	qp_serv == HERMON_QP_RFCI || qp_serv == HERMON_QP_FCMND ||	\
	qp_serv == HERMON_QP_FEXCH)) ||					\
	(qp_trans == IBT_UC_SRV && qp_serv == HERMON_QP_UC))

/*
 * The following enumerated type is used to capture all the various types
 * of Hermon work queue types. It is specifically used as an argument to the
 * to the hermon_qp_sgl_to_logwqesz() routine to determine the amount of
 * overhead (in WQE header size) consumed by each of the types. This
 * information is used to round the WQE size to the next largest power-of-2
 * (and to determine the number of SGLs that are supported for the given WQE
 * type).  There is also a define below used to specify the minimum size for a
 * WQE.  The minimum size is set to 64 bytes (a single cacheline).
 */

typedef enum {
	HERMON_QP_WQ_TYPE_SENDQ_UD,
	HERMON_QP_WQ_TYPE_SENDQ_CONN,
	HERMON_QP_WQ_TYPE_RECVQ,
	HERMON_QP_WQ_TYPE_SENDMLX_QP0,
	HERMON_QP_WQ_TYPE_SENDMLX_QP1
} hermon_qp_wq_type_t;
#define	HERMON_QP_WQE_MLX_SND_HDRS	0x40
#define	HERMON_QP_WQE_MLX_RCV_HDRS	0x00
#define	HERMON_QP_WQE_MLX_SRQ_HDRS	0x10
#define	HERMON_QP_WQE_MLX_QP0_HDRS	0x40
#define	HERMON_QP_WQE_MLX_QP1_HDRS	0x70
#define	HERMON_QP_WQE_LOG_MINIMUM	0x6


/*
 * The hermon_qp_range_t is used to manage a qp_range for RSS and FEXCH.
 * It has a reference count.  When the reference count goes to 0,
 * the qpc resource can be freed.
 */
typedef struct hermon_qp_range_s {
	kmutex_t	hqpr_lock;
	hermon_rsrc_t	*hqpr_qpcrsrc;
	uint_t		hqpr_refcnt;
} hermon_qp_range_t;

/*
 * The hermon_qp_info_t structure is used internally by the Hermon driver to
 * pass information to and from the hermon_qp_alloc() and
 * hermon_special_qp_alloc() routines.  It contains placeholders for all of the
 * potential inputs and outputs that either routine can take.
 */
typedef struct hermon_qp_info_s {
	ibt_qp_alloc_attr_t	*qpi_attrp;
	uint_t			qpi_type;
	uint_t			qpi_port;
	ibtl_qp_hdl_t		qpi_ibt_qphdl;
	ibt_chan_sizes_t	*qpi_queueszp;
	ib_qpn_t		*qpi_qpn;
	hermon_qphdl_t		qpi_qphdl;
} hermon_qp_info_t;

/*
 * The QPN entry which is stored in the AVL tree
 */
typedef struct hermon_qpn_entry_s {
	avl_node_t		qpn_avlnode;
	uint_t			qpn_refcnt;
	uint_t			qpn_counter;
	uint_t			qpn_indx;
	hermon_rsrc_t		*qpn_qpc;
} hermon_qpn_entry_t;
#define	HERMON_QPN_NOFLAG		0x0
#define	HERMON_QPN_RELEASE		0x1
#define	HERMON_QPN_FREE_ONLY		0x2

#define	HERMON_QP_OH_SIZE		0x0800
/*
 * 2KB, fixed per Mnox PRM 0.35c & conversation w/Mnox technical Sep 5, 2007
 */

/*
 * The hermon_sw_qp_s structure is also referred to using the "hermon_qphdl_t"
 * typedef (see hermon_typedef.h).  It encodes all the information necessary
 * to track the various resources needed to allocate, query, modify, and
 * (later) free both normal QP and special QP.
 *
 * Specifically, it has a lock to ensure single threaded access to the QP.
 * It has QP state, type, and number, pointers to the PD, MR, and CQ handles
 * associated with the QP, and pointers to the buffer where the work queues
 * come from.
 *
 * It has two pointers (one per work queue) to the workQ headers for the WRID
 * list, as well as pointers to the last WQE on each chain (used when
 * connecting a new chain of WQEs to a previously executing chain - see
 * hermon_wr.c).  It's also got the real WQE size, real number of SGL per WQE,
 * and the size of each of the work queues (in number of WQEs).
 *
 * Additionally, it has pointers to the resources associated with the QP,
 * including the obligatory backpointer to the resource for the QP handle
 * itself.  But it also has some flags, like "qp_forward_sqd_event" and
 * "qp_sqd_still_draining" (which are used to indicate whether a Send Queue
 * Drained Event should be forwarded to the IBTF) or "qp_is_special",
 * "qp_portnum", and "qp_pkeyindx" (which are used by special QP to store
 * necessary information about the type of the QP, which port it's connected
 * to, and what its current PKey index is set to).
 */
struct hermon_sw_qp_s {
	kmutex_t		qp_lock;
	uint_t			qp_state;
	uint32_t		qp_qpnum;
	hermon_pdhdl_t		qp_pdhdl;
	uint_t			qp_serv_type;
	ibt_qp_type_t		qp_type;
	uint_t			qp_sl;		/* service level */
	hermon_mrhdl_t		qp_mrhdl;
	uint_t			qp_sq_sigtype;
	uint_t			qp_is_special;
	ibt_qp_alloc_flags_t	qp_alloc_flags;
	uint32_t		qp_uarpg;
	devmap_cookie_t		qp_umap_dhp;
	uint_t			qp_portnum;	/* port 0/1 for HCA */
	uint_t			qp_portnum_alt;	/* port 0/1 for HCA */
	uint_t			qp_pkeyindx;
	uint_t			qp_no_prefetch;
				/* prefetch == 0, none == 1, for headroom */
	uint_t			qp_rlky;	/* using reserved lkey */

	/* Send Work Queue */
	kmutex_t		qp_sq_lock;
	hermon_cqhdl_t		qp_sq_cqhdl;
	hermon_workq_avl_t	qp_sq_wqavl;
	hermon_workq_hdr_t	*qp_sq_wqhdr;
	uint32_t		*qp_sq_buf;
	uint32_t		qp_sq_bufsz;
	uint32_t		qp_sq_logqsz;	/* used to check owner valid */
	uint32_t		qp_sq_log_wqesz;
	uint32_t		qp_sq_headroom; /* #bytes needed for headroom */
	uint32_t		qp_sq_hdrmwqes;	/* # wqes needed for headroom */
	uint32_t		qp_sq_baseaddr;
	uint32_t		qp_sq_sgl;
	uint_t			qp_uses_lso;
	uint32_t		qp_ring;
	uint_t			qp_state_for_post_send; /* copy of qp_state */

	/* Receive Work Queue - not used when SRQ is used */
	hermon_cqhdl_t		qp_rq_cqhdl;
	hermon_workq_avl_t	qp_rq_wqavl;	/* needed for srq */
	hermon_workq_hdr_t	*qp_rq_wqhdr;
	uint32_t		*qp_rq_buf;
	uint32_t		qp_rq_bufsz;
	uint32_t		qp_rq_logqsz;	/* used to check owner valid */
	uint32_t		qp_rq_log_wqesz;
	uint32_t		qp_rq_wqecntr;
	uint32_t		qp_rq_baseaddr;
	uint32_t		qp_rq_sgl;

	/* DoorBell Record information */
	ddi_acc_handle_t	qp_rq_dbr_acchdl;
	hermon_dbr_t		*qp_rq_vdbr;
	uint64_t		qp_rq_pdbr;
	uint64_t		qp_rdbr_mapoffset;	/* user mode access */

	uint64_t		qp_desc_off;

	hermon_rsrc_t		*qp_qpcrsrcp;
	hermon_rsrc_t		*qp_rsrcp;
	void			*qp_hdlrarg;
	uint_t			qp_forward_sqd_event;
	uint_t			qp_sqd_still_draining;

	/* Shared Receive Queue */
	hermon_srqhdl_t		qp_srqhdl;

	/* Refcnt of QP belongs to an MCG */
	uint_t			qp_mcg_refcnt;

	/* save the mtu from init2rtr for future use */
	uint_t			qp_save_mtu;
	hermon_qpn_entry_t	*qp_qpn_hdl;

	struct hermon_qalloc_info_s qp_wqinfo;

	ibt_fc_attr_t		qp_fc_attr;

	struct hermon_qp_range_s *qp_rangep;

	/* Beware: 8-byte alignment needed here */

	struct hermon_hw_qpc_s qpc;
};
_NOTE(READ_ONLY_DATA(hermon_sw_qp_s::qp_qpnum
    hermon_sw_qp_s::qp_sq_buf
    hermon_sw_qp_s::qp_sq_log_wqesz
    hermon_sw_qp_s::qp_sq_bufsz
    hermon_sw_qp_s::qp_sq_sgl
    hermon_sw_qp_s::qp_rq_buf
    hermon_sw_qp_s::qp_rq_log_wqesz
    hermon_sw_qp_s::qp_rq_bufsz
    hermon_sw_qp_s::qp_rq_sgl
    hermon_sw_qp_s::qp_desc_off
    hermon_sw_qp_s::qp_mrhdl
    hermon_sw_qp_s::qp_wqinfo
    hermon_sw_qp_s::qp_qpcrsrcp
    hermon_sw_qp_s::qp_rsrcp
    hermon_sw_qp_s::qp_hdlrarg
    hermon_sw_qp_s::qp_pdhdl
    hermon_sw_qp_s::qp_sq_cqhdl
    hermon_sw_qp_s::qp_rq_cqhdl
    hermon_sw_qp_s::qp_sq_sigtype
    hermon_sw_qp_s::qp_serv_type
    hermon_sw_qp_s::qp_is_special
    hermon_sw_qp_s::qp_alloc_flags
    hermon_sw_qp_s::qp_uarpg
    hermon_sw_qp_s::qp_sq_wqhdr
    hermon_sw_qp_s::qp_rq_wqhdr
    hermon_sw_qp_s::qp_qpn_hdl))
_NOTE(MUTEX_PROTECTS_DATA(hermon_sw_qp_s::qp_lock,
    hermon_sw_qp_s::qp_state
    hermon_sw_qp_s::qpc
    hermon_sw_qp_s::qp_forward_sqd_event
    hermon_sw_qp_s::qp_sqd_still_draining
    hermon_sw_qp_s::qp_mcg_refcnt
    hermon_sw_qp_s::qp_save_mtu
    hermon_sw_qp_s::qp_umap_dhp))
_NOTE(SCHEME_PROTECTS_DATA("safe sharing",
    hermon_sw_qp_s::qp_pkeyindx
    hermon_sw_qp_s::qp_portnum))

#define	HERMON_SET_QP_POST_SEND_STATE(qp, state)			\
	mutex_enter(&qp->qp_sq_lock);					\
	qp->qp_state_for_post_send = state;				\
	mutex_exit(&qp->qp_sq_lock)

/* Defined in hermon_qp.c */
int hermon_qp_alloc(hermon_state_t *state, hermon_qp_info_t *qpinfo,
    uint_t sleepflag);
int hermon_special_qp_alloc(hermon_state_t *state, hermon_qp_info_t *qpinfo,
    uint_t sleepflag);
int hermon_qp_alloc_range(hermon_state_t *state, uint_t log2,
    hermon_qp_info_t *qpinfo, ibtl_qp_hdl_t *ibtl_qp_p, ibc_cq_hdl_t *send_cq_p,
    ibc_cq_hdl_t *recv_cq_p, hermon_qphdl_t *qp_p, uint_t sleepflag);
int hermon_qp_free(hermon_state_t *state, hermon_qphdl_t *qphdl,
    ibc_free_qp_flags_t free_qp_flags, ibc_qpn_hdl_t *qpnh, uint_t sleepflag);
int hermon_qp_query(hermon_state_t *state, hermon_qphdl_t qphdl,
    ibt_qp_query_attr_t *attr_p);
hermon_qphdl_t hermon_qphdl_from_qpnum(hermon_state_t *state, uint_t qpnum);
void hermon_qp_release_qpn(hermon_state_t *state, hermon_qpn_entry_t *entry,
    int flags);
void hermon_qpn_avl_init(hermon_state_t *state);
void hermon_qpn_avl_fini(hermon_state_t *state);

/* Defined in hermon_qpmod.c */
int hermon_qp_modify(hermon_state_t *state, hermon_qphdl_t qp,
    ibt_cep_modify_flags_t flags, ibt_qp_info_t *info_p,
    ibt_queue_sizes_t *actual_sz);
int hermon_qp_to_reset(hermon_state_t *state, hermon_qphdl_t qp);

#ifdef __cplusplus
}
#endif

#endif	/* _SYS_IB_ADAPTERS_HERMON_QP_H */