Browse Source

Started added poll_cq() verb.

Started reworking MLX_EXTRACT(), MLX_POPULATE() etc. to automatically
determine type information.
tags/v0.9.3
Michael Brown 16 years ago
parent
commit
a3a91fedc1
3 changed files with 240 additions and 84 deletions
  1. 97
    68
      src/drivers/net/mlx_ipoib/bit_ops.h
  2. 92
    11
      src/drivers/net/mlx_ipoib/mt25218.c
  3. 51
    5
      src/include/gpxe/infiniband.h

+ 97
- 68
src/drivers/net/mlx_ipoib/bit_ops.h View File

@@ -137,112 +137,139 @@ struct addr_64_st {
137 137
 
138 138
 /* Remaining code Copyright Fen Systems Ltd. 2007 */
139 139
 
140
+/**
141
+ * Wrapper structure for pseudo_bit_t structures
142
+ *
143
+ * This structure provides a wrapper around the autogenerated
144
+ * pseudo_bit_t structures.  It has the correct size, and also
145
+ * encapsulates type information about the underlying pseudo_bit_t
146
+ * structure, which allows the MLX_POPULATE etc. macros to work
147
+ * without requiring explicit type information.
148
+ */
149
+#define MLX_DECLARE_STRUCT( _structure )				     \
150
+	_structure {							     \
151
+	    union {							     \
152
+		uint8_t bytes[ sizeof ( struct _structure ## _st ) / 8 ];    \
153
+		uint32_t dwords[ sizeof ( struct _structure ## _st ) / 32 ]; \
154
+		struct _structure ## _st *dummy[0];			     \
155
+	    } u;							     \
156
+	}
157
+
158
+/** Get pseudo_bit_t structure type from wrapper structure pointer */
159
+#define MLX_PSEUDO_STRUCT( _ptr )					     \
160
+	typeof ( *((_ptr)->u.dummy[0]) )
161
+
140 162
 /** Bit offset of a field within a pseudo_bit_t structure */
141
-#define MLX_BIT_OFFSET( _structure, _field )				   \
142
-	offsetof ( struct _structure, _field )
163
+#define MLX_BIT_OFFSET( _structure_st, _field )				     \
164
+	offsetof ( _structure_st, _field )
143 165
 
144 166
 /** Dword offset of a field within a pseudo_bit_t structure */
145
-#define MLX_DWORD_OFFSET( _structure, _field )				   \
146
-	( MLX_BIT_OFFSET ( _structure, _field ) / 32 )
167
+#define MLX_DWORD_OFFSET( _structure_st, _field )			     \
168
+	( MLX_BIT_OFFSET ( _structure_st, _field ) / 32 )
147 169
 
148 170
 /** Dword bit offset of a field within a pseudo_bit_t structure
149 171
  *
150 172
  * Yes, using mod-32 would work, but would lose the check for the
151 173
  * error of specifying a mismatched field name and dword index.
152 174
  */
153
-#define MLX_DWORD_BIT_OFFSET( _structure, _index, _field )		   \
154
-	( MLX_BIT_OFFSET ( _structure, _field ) - ( 32 * (_index) ) )
175
+#define MLX_DWORD_BIT_OFFSET( _structure_st, _index, _field )		     \
176
+	( MLX_BIT_OFFSET ( _structure_st, _field ) - ( 32 * (_index) ) )
155 177
 
156 178
 /** Bit width of a field within a pseudo_bit_t structure */
157
-#define MLX_BIT_WIDTH( _structure, _field )				   \
158
-	sizeof ( ( ( struct _structure * ) NULL )->_field )
179
+#define MLX_BIT_WIDTH( _structure_st, _field )				     \
180
+	sizeof ( ( ( _structure_st * ) NULL )->_field )
159 181
 
160 182
 /** Bit mask for a field within a pseudo_bit_t structure */
161
-#define MLX_BIT_MASK( _structure, _field )				   \
162
-	( ( 1 << MLX_BIT_WIDTH ( _structure, _field ) ) - 1 )
183
+#define MLX_BIT_MASK( _structure_st, _field )				     \
184
+	( ( 1 << MLX_BIT_WIDTH ( _structure_st, _field ) ) - 1 )
163 185
 
164 186
 /*
165 187
  * Assemble native-endian dword from named fields and values
166 188
  *
167 189
  */
168 190
 
169
-#define MLX_ASSEMBLE_1( _structure, _index, _field, _value )		   \
170
-	( (_value) << MLX_DWORD_BIT_OFFSET ( _structure, _index, _field ) )
191
+#define MLX_ASSEMBLE_1( _structure_st, _index, _field, _value )		     \
192
+	( (_value) << MLX_DWORD_BIT_OFFSET ( _structure_st, _index, _field ) )
171 193
 
172
-#define MLX_ASSEMBLE_2( _structure, _index, _field, _value, ... )	   \
173
-	( MLX_ASSEMBLE_1 ( _structure, _index, _field, _value ) |	   \
174
-	  MLX_ASSEMBLE_1 ( _structure, _index, __VA_ARGS__ ) )
194
+#define MLX_ASSEMBLE_2( _structure_st, _index, _field, _value, ... )	     \
195
+	( MLX_ASSEMBLE_1 ( _structure_st, _index, _field, _value ) |	     \
196
+	  MLX_ASSEMBLE_1 ( _structure_st, _index, __VA_ARGS__ ) )
175 197
 
176
-#define MLX_ASSEMBLE_3( _structure, _index, _field, _value, ... )	   \
177
-	( MLX_ASSEMBLE_1 ( _structure, _index, _field, _value ) |	   \
178
-	  MLX_ASSEMBLE_2 ( _structure, _index, __VA_ARGS__ ) )
198
+#define MLX_ASSEMBLE_3( _structure_st, _index, _field, _value, ... )	     \
199
+	( MLX_ASSEMBLE_1 ( _structure_st, _index, _field, _value ) |	     \
200
+	  MLX_ASSEMBLE_2 ( _structure_st, _index, __VA_ARGS__ ) )
179 201
 
180
-#define MLX_ASSEMBLE_4( _structure, _index, _field, _value, ... )	   \
181
-	( MLX_ASSEMBLE_1 ( _structure, _index, _field, _value ) |	   \
182
-	  MLX_ASSEMBLE_3 ( _structure, _index, __VA_ARGS__ ) )
202
+#define MLX_ASSEMBLE_4( _structure_st, _index, _field, _value, ... )	     \
203
+	( MLX_ASSEMBLE_1 ( _structure_st, _index, _field, _value ) |	     \
204
+	  MLX_ASSEMBLE_3 ( _structure_st, _index, __VA_ARGS__ ) )
183 205
 
184 206
 /*
185 207
  * Build native-endian (positive) dword bitmasks from named fields
186 208
  *
187 209
  */
188 210
 
189
-#define MLX_MASK_1( _structure, _index, _field )			   \
190
-	( MLX_BIT_MASK ( _structure, _field ) <<			   \
191
-	  MLX_DWORD_BIT_OFFSET ( _structure, _index, _field ) )
211
+#define MLX_MASK_1( _structure_st, _index, _field )			     \
212
+	( MLX_BIT_MASK ( _structure_st, _field ) <<			     \
213
+	  MLX_DWORD_BIT_OFFSET ( _structure_st, _index, _field ) )
192 214
 
193
-#define MLX_MASK_2( _structure, _index, _field, ... )			   \
194
-	( MLX_MASK_1 ( _structure, _index, _field ) |			   \
195
-	  MLX_MASK_1 ( _structure, _index, __VA_ARGS__ ) )
215
+#define MLX_MASK_2( _structure_st, _index, _field, ... )		     \
216
+	( MLX_MASK_1 ( _structure_st, _index, _field ) |		     \
217
+	  MLX_MASK_1 ( _structure_st, _index, __VA_ARGS__ ) )
196 218
 
197
-#define MLX_MASK_3( _structure, _index, _field, ... )			   \
198
-	( MLX_MASK_1 ( _structure, _index, _field ) |			   \
199
-	  MLX_MASK_2 ( _structure, _index, __VA_ARGS__ ) )
219
+#define MLX_MASK_3( _structure_st, _index, _field, ... )		     \
220
+	( MLX_MASK_1 ( _structure_st, _index, _field ) |		     \
221
+	  MLX_MASK_2 ( _structure_st, _index, __VA_ARGS__ ) )
200 222
 
201
-#define MLX_MASK_4( _structure, _index, _field, ... )			   \
202
-	( MLX_MASK_1 ( _structure, _index, _field ) |			   \
203
-	  MLX_MASK_3 ( _structure, _index, __VA_ARGS__ ) )
223
+#define MLX_MASK_4( _structure_st, _index, _field, ... )		     \
224
+	( MLX_MASK_1 ( _structure_st, _index, _field ) |		     \
225
+	  MLX_MASK_3 ( _structure_st, _index, __VA_ARGS__ ) )
204 226
 
205 227
 /*
206 228
  * Populate big-endian dwords from named fields and values
207 229
  *
208 230
  */
209 231
 
210
-#define MLX_POPULATE( _base, _index, _assembled )			   \
211
-	do {								   \
212
-		uint32_t *__ptr = ( ( (uint32_t *) (_base) ) + (_index) ); \
213
-		uint32_t __assembled = (_assembled);			   \
214
-		*__ptr = cpu_to_be32 ( __assembled );			   \
232
+#define MLX_POPULATE( _ptr, _index, _assembled )			     \
233
+	do {								     \
234
+		uint32_t *__ptr = &(_ptr)->u.dwords[(_index)];		     \
235
+		uint32_t __assembled = (_assembled);			     \
236
+		*__ptr = cpu_to_be32 ( __assembled );			     \
215 237
 	} while ( 0 )
216 238
 
217
-#define MLX_POPULATE_1( _base, _structure, _index, ... )		   \
218
-	MLX_POPULATE ( _base, _index,					   \
219
-		       MLX_ASSEMBLE_1 ( _structure, _index, __VA_ARGS__ ) )
239
+#define MLX_POPULATE_1( _ptr, _index, ... )				     \
240
+	MLX_POPULATE ( _ptr, _index,					     \
241
+		       MLX_ASSEMBLE_1 ( MLX_PSEUDO_STRUCT ( _ptr ),	     \
242
+					_index, __VA_ARGS__ ) )
220 243
 
221
-#define MLX_POPULATE_2( _base, _structure, _index, ... )		   \
222
-	MLX_POPULATE ( _base, _index,					   \
223
-		       MLX_ASSEMBLE_2 ( _structure, _index, __VA_ARGS__ ) )
244
+#define MLX_POPULATE_2( _ptr, _index, ... )				     \
245
+	MLX_POPULATE ( _ptr, _index,					     \
246
+		       MLX_ASSEMBLE_2 ( MLX_PSEUDO_STRUCT ( _ptr ),	     \
247
+					_index, __VA_ARGS__ ) )
224 248
 
225
-#define MLX_POPULATE_3( _base, _structure, _index, ... )		   \
226
-	MLX_POPULATE ( _base, _index,					   \
227
-		       MLX_ASSEMBLE_3 ( _structure, _index, __VA_ARGS__ ) )
249
+#define MLX_POPULATE_3( _ptr, _index, ... )				     \
250
+	MLX_POPULATE ( _ptr, _index,					     \
251
+		       MLX_ASSEMBLE_3 ( MLX_PSEUDO_STRUCT ( _ptr ),	     \
252
+					_index, __VA_ARGS__ ) )
228 253
 
229
-#define MLX_POPULATE_4( _base, _structure, _index, ... )		   \
230
-	MLX_POPULATE ( _base, _index,					   \
231
-		       MLX_ASSEMBLE_4 ( _structure, _index, __VA_ARGS__ ) )
254
+#define MLX_POPULATE_4( _ptr, _index, ... )				     \
255
+	MLX_POPULATE ( _ptr, _index,					     \
256
+		       MLX_ASSEMBLE_4 ( MLX_PSEUDO_STRUCT ( _ptr ),	     \
257
+					_index, __VA_ARGS__ ) )
232 258
 
233 259
 /*
234 260
  * Modify big-endian dword using named field and value
235 261
  *
236 262
  */
237 263
 
238
-#define MLX_MODIFY( _base, _structure, _index, _field, _value )		   \
239
-	do {								   \
240
-		uint32_t *__ptr = ( ( (uint32_t *) (_base) ) + (_index) ); \
241
-		uint32_t __value = be32_to_cpu ( *__ptr );		   \
242
-		__value &= ~( MLX_MASK_1 ( _structure, _index, _field ) ); \
243
-		__value |= MLX_ASSEMBLE_1 ( _structure, _index,		   \
244
-					    _field, _value );		   \
245
-		*__ptr = cpu_to_be32 ( __value );			   \
264
+#define MLX_MODIFY( _ptr, _index, _field, _value )			     \
265
+	do {								     \
266
+		uint32_t *__ptr = &(_ptr)->u.dwords[(_index)];		     \
267
+		uint32_t __value = be32_to_cpu ( *__ptr );		     \
268
+		__value &= ~( MLX_MASK_1 ( MLX_PSEUDO_STRUCT ( _ptr ),	     \
269
+					   _index, _field ) );		     \
270
+		__value |= MLX_ASSEMBLE_1 ( MLX_PSEUDO_STRUCT ( _ptr ),	     \
271
+					    _index, _field, _value );	     \
272
+		*__ptr = cpu_to_be32 ( __value );			     \
246 273
 	} while ( 0 )
247 274
 
248 275
 /*
@@ -250,16 +277,18 @@ struct addr_64_st {
250 277
  *
251 278
  */
252 279
 
253
-#define MLX_EXTRACT( _base, _structure, _field )			   \
254
-	( {								   \
255
-		unsigned int __index = 					   \
256
-			MLX_DWORD_OFFSET ( _structure, _field );	   \
257
-		uint32_t *__ptr = ( ( (uint32_t *) (_base) ) + __index );  \
258
-		uint32_t __value = be32_to_cpu ( *__ptr );		   \
259
-		__value >>= MLX_DWORD_BIT_OFFSET ( _structure, __index,	   \
260
-						   _field );		   \
261
-		__value &= MLX_BIT_MASK ( _structure, _field );		   \
262
-		__value;						   \
280
+#define MLX_EXTRACT( _ptr, _field )					     \
281
+	( {								     \
282
+		unsigned int __index = 					     \
283
+		    MLX_DWORD_OFFSET ( MLX_PSEUDO_STRUCT ( _ptr ), _field ); \
284
+		uint32_t *__ptr = &(_ptr)->u.dwords[__index];		     \
285
+		uint32_t __value = be32_to_cpu ( *__ptr );		     \
286
+		__value >>=						     \
287
+		    MLX_DWORD_BIT_OFFSET ( MLX_PSEUDO_STRUCT ( _ptr ),	     \
288
+					    __index, _field );		     \
289
+		__value &=						     \
290
+		    MLX_BIT_MASK ( MLX_PSEUDO_STRUCT ( _ptr ), _field );     \
291
+		__value;						     \
263 292
 	} )
264 293
 
265 294
 #endif				/* __bit_ops_h__ */

+ 92
- 11
src/drivers/net/mlx_ipoib/mt25218.c View File

@@ -23,14 +23,23 @@ Skeleton NIC driver for Etherboot
23 23
 
24 24
 #include "mt25218_imp.c"
25 25
 
26
+#include "arbel.h"
27
+
26 28
 struct arbel_send_work_queue {
27
-	/** Doorbell number */
29
+	/** Doorbell record number */
28 30
 	unsigned int doorbell_idx;
29 31
 	/** Work queue entries */
30 32
 	//	struct ud_send_wqe_st *wqe;
31 33
 	union ud_send_wqe_u *wqe_u;
32 34
 };
33 35
 
36
+struct arbel_completion_queue {
37
+	/** Doorbell record number */
38
+	unsigned int doorbell_idx;
39
+	/** Completion queue entries */
40
+	union cqe_st *cqe;
41
+};
42
+
34 43
 struct arbel {
35 44
 	/** User Access Region */
36 45
 	void *uar;
@@ -143,13 +152,14 @@ static int mlx_transmit_direct ( struct net_device *netdev,
143 152
 		},
144 153
 	};
145 154
 	struct ud_av_st *bcast_av = mlx->bcast_av;
146
-	struct address_vector_st *bav = &bcast_av->av;
155
+	struct arbelprm_ud_address_vector *bav =
156
+		( struct arbelprm_ud_address_vector * ) &bcast_av->av;
147 157
 	struct ib_address_vector av = {
148 158
 		.dest_qp = bcast_av->dest_qp,
149 159
 		.qkey = bcast_av->qkey,
150
-		.dlid = MLX_EXTRACT ( bav, arbelprm_ud_address_vector_st, rlid ),
151
-		.rate = ( MLX_EXTRACT ( bav, arbelprm_ud_address_vector_st, max_stat_rate ) ? 1 : 4 ),
152
-		.sl = MLX_EXTRACT ( bav, arbelprm_ud_address_vector_st, sl ),
160
+		.dlid = MLX_EXTRACT ( bav, rlid ),
161
+		.rate = ( MLX_EXTRACT ( bav, max_stat_rate ) ? 1 : 4 ),
162
+		.sl = MLX_EXTRACT ( bav, sl ),
153 163
 		.gid_present = 1,
154 164
 	};
155 165
 	memcpy ( &av.gid, ( ( void * ) bav ) + 16, 16 );
@@ -301,6 +311,13 @@ static struct ib_gid arbel_no_gid = {
301 311
 	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2 }
302 312
 };
303 313
 
314
+/**
315
+ * Ring doorbell register in UAR
316
+ *
317
+ * @v arbel		Arbel device
318
+ * @v db_reg		Doorbell register structure
319
+ * @v offset		Address of doorbell
320
+ */
304 321
 static void arbel_ring_doorbell ( struct arbel *arbel, void *db_reg,
305 322
 				  unsigned int offset ) {
306 323
 	uint32_t *db_reg_dword = db_reg;
@@ -315,6 +332,15 @@ static void arbel_ring_doorbell ( struct arbel *arbel, void *db_reg,
315 332
 	writel ( db_reg_dword[1], ( arbel->uar + offset + 4 ) );
316 333
 }
317 334
 
335
+/**
336
+ * Post send work queue entry
337
+ *
338
+ * @v ibdev		Infiniband device
339
+ * @v iobuf		I/O buffer
340
+ * @v av		Address vector
341
+ * @v qp		Queue pair
342
+ * @ret rc		Return status code
343
+ */
318 344
 static int arbel_post_send ( struct ib_device *ibdev, struct io_buffer *iobuf,
319 345
 			     struct ib_address_vector *av,
320 346
 			     struct ib_queue_pair *qp ) {
@@ -365,14 +391,8 @@ static int arbel_post_send ( struct ib_device *ibdev, struct io_buffer *iobuf,
365 391
 			 destination_qp, av->dest_qp );
366 392
 	MLX_POPULATE_1 ( &wqe->udseg, arbelprm_wqe_segment_ud_st, 9,
367 393
 			 q_key, av->qkey );
368
-
369 394
 	wqe->mpointer[0].local_addr_l =
370 395
 		cpu_to_be32 ( virt_to_bus ( iobuf->data ) );
371
-
372
-	//	memcpy ( bus_to_virt ( be32_to_cpu ( wqe->mpointer[0].local_addr_l ) ),
373
-	//		 iobuf->data, iob_len ( iobuf ) );
374
-
375
-
376 396
 	wqe->mpointer[0].byte_count = cpu_to_be32 ( iob_len ( iobuf ) );
377 397
 
378 398
 	DBG ( "Work queue entry:\n" );
@@ -416,8 +436,69 @@ static int arbel_post_send ( struct ib_device *ibdev, struct io_buffer *iobuf,
416 436
 	return 0;
417 437
 }
418 438
 
439
+static void arbel_parse_completion ( struct arbel *arbel,
440
+				     union cqe_st *cqe,
441
+				     struct ib_completion *completion ) {
442
+	memset ( completion, 0, sizeof ( *completion ) );
443
+	is_send = MLX_EXTRACT ( cqe, arbelprm_completion_queue_entry_st, s );					
444
+	completion->len =
445
+		MLX_EXTRACT ( cqe, arbelprm_completion_queue_entry_st,
446
+			      byte_cnt );}
447
+
448
+/**
449
+ * Poll completion queue
450
+ *
451
+ * @v ibdev		Infiniband device
452
+ * @v cq		Completion queue
453
+ * @v complete		Completion handler
454
+ */
455
+static void arbel_poll_cq ( struct ib_device *ibdev,
456
+			    struct ib_completion_queue *cq,
457
+			    ib_completer_t complete_send,
458
+			    ib_completer_t complete_recv ) {
459
+	struct arbel *arbel = ibdev->priv;
460
+	struct arbel_completion_queue *arbel_cq = cq->priv;
461
+	unsigned int cqe_idx_mask = ( cq->num_cqes - 1 );
462
+	union db_record_st *db_rec = &arbel->db_rec[arbel_cq->doorbell_idx];
463
+	union cqe_st *cqe;
464
+	struct ib_completion completion;
465
+	struct io_buffer *iobuf;
466
+	int is_send;
467
+
468
+	while ( 1 ) {
469
+		/* Look for completion entry */
470
+		cqe = &arbel_cq->cqe[cq->next_idx & cqe_idx_mask];
471
+		if ( MLX_EXTRACT ( cqe, arbelprm_completion_queue_entry_st,
472
+				   owner ) != 0 ) {
473
+			/* Entry still owned by hardware; end of poll */
474
+			break;
475
+		}
476
+
477
+		/* Parse completion */
478
+
479
+		
480
+		
481
+		/* Handle completion */
482
+		( is_send ? complete_send : complete_recv ) ( ibdev,
483
+							      &completion,
484
+							      iobuf );
485
+
486
+		/* Return ownership to hardware */
487
+		MLX_POPULATE_1 ( cqe, arbelprm_completion_queue_entry_st, 7,
488
+				 owner, 1 );
489
+		barrier();
490
+		/* Update completion queue's index */
491
+		cq->next_idx++;
492
+		/* Update doorbell record */
493
+		MLX_POPULATE_1 ( db_rec, arbelprm_cq_ci_db_record_st, 0,
494
+				 counter, ( cq->next_idx & 0xffffffffUL ) );
495
+	}
496
+}
497
+
498
+/** Arbel Infiniband operations */
419 499
 static struct ib_device_operations arbel_ib_operations = {
420 500
 	.post_send	= arbel_post_send,
501
+	.poll_cq	= arbel_poll_cq,
421 502
 };
422 503
 
423 504
 /**

+ 51
- 5
src/include/gpxe/infiniband.h View File

@@ -63,6 +63,7 @@ struct ibhdr {
63 63
 
64 64
 
65 65
 
66
+struct ib_device;
66 67
 
67 68
 /** An Infiniband Work Queue */
68 69
 struct ib_work_queue {
@@ -71,9 +72,11 @@ struct ib_work_queue {
71 72
 	/** Next work queue entry index
72 73
 	 *
73 74
 	 * This is the index of the next entry to be filled (i.e. the
74
-	 * first empty entry).
75
+	 * first empty entry).  This value is not bounded by num_wqes;
76
+	 * users must logical-AND with (num_wqes-1) to generate an
77
+	 * array index.
75 78
 	 */
76
-	unsigned int next_idx;
79
+	unsigned long next_idx;
77 80
 	/** I/O buffers assigned to work queue */
78 81
 	struct io_buffer **iobufs;
79 82
 	/** Driver private data */
@@ -92,6 +95,38 @@ struct ib_queue_pair {
92 95
 	void *priv;
93 96
 };
94 97
 
98
+/** An Infiniband Completion Queue */
99
+struct ib_completion_queue {
100
+	/** Number of completion queue entries */
101
+	unsigned int num_cqes;
102
+	/** Next completion queue entry index
103
+	 *
104
+	 * This is the index of the next entry to be filled (i.e. the
105
+	 * first empty entry).  This value is not bounded by num_wqes;
106
+	 * users must logical-AND with (num_wqes-1) to generate an
107
+	 * array index.
108
+	 */
109
+	unsigned long next_idx;
110
+	/** Driver private data */
111
+	void *priv;
112
+};
113
+
114
+/** An Infiniband completion */
115
+struct ib_completion {
116
+	/** Length */
117
+	size_t len;
118
+};
119
+
120
+/** An Infiniband completion handler
121
+ *
122
+ * @v ibdev		Infiniband device
123
+ * @v completion	Completion
124
+ * @v iobuf		I/O buffer
125
+ */
126
+typedef void ( * ib_completer_t ) ( struct ib_device *ibdev,
127
+				    struct ib_completion *completion,
128
+				    struct io_buffer *iobuf );
129
+
95 130
 /** An Infiniband Address Vector */
96 131
 struct ib_address_vector {
97 132
 	/** Destination Queue Pair */
@@ -110,15 +145,13 @@ struct ib_address_vector {
110 145
 	struct ib_gid gid;
111 146
 };
112 147
 
113
-struct ib_device;
114
-
115 148
 /**
116 149
  * Infiniband device operations
117 150
  *
118 151
  * These represent a subset of the Infiniband Verbs.
119 152
  */
120 153
 struct ib_device_operations {
121
-	/** Post Send work queue entry
154
+	/** Post send work queue entry
122 155
 	 *
123 156
 	 * @v ibdev		Infiniband device
124 157
 	 * @v iobuf		I/O buffer
@@ -135,6 +168,19 @@ struct ib_device_operations {
135 168
 			      struct io_buffer *iobuf,
136 169
 			      struct ib_address_vector *av,
137 170
 			      struct ib_queue_pair *qp );
171
+	/** Poll completion queue
172
+	 *
173
+	 * @v ibdev		Infiniband device
174
+	 * @v cq		Completion queue
175
+	 * @v complete_send	Send completion handler
176
+	 * @v complete_recv	Receive completion handler
177
+	 *
178
+	 * The completion handler takes ownership of the I/O buffer.
179
+	 */
180
+	void ( * poll_cq ) ( struct ib_device *ibdev,
181
+			     struct ib_completion_queue *cq,
182
+			     ib_completer_t complete_send,
183
+			     ib_completer_t complete_recv );
138 184
 };
139 185
 
140 186
 /** An Infiniband device */

Loading…
Cancel
Save