Browse Source

[infiniband] Add raw packet parser and constructor

This can be used with cards that require the driver to construct and
parse packet headers manually.  Headers are optionally handled
out-of-line from the packet payload, since some such cards will split
received headers into a separate ring buffer.
tags/v0.9.6
Michael Brown 16 years ago
parent
commit
9e5fd8ec59

+ 234
- 0
src/drivers/infiniband/ib_packet.c View File

@@ -0,0 +1,234 @@
1
+/*
2
+ * Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>.
3
+ *
4
+ * This program is free software; you can redistribute it and/or
5
+ * modify it under the terms of the GNU General Public License as
6
+ * published by the Free Software Foundation; either version 2 of the
7
+ * License, or any later version.
8
+ *
9
+ * This program is distributed in the hope that it will be useful, but
10
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
+ * General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License
15
+ * along with this program; if not, write to the Free Software
16
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
+ */
18
+
19
+#include <stdint.h>
20
+#include <stdlib.h>
21
+#include <string.h>
22
+#include <errno.h>
23
+#include <byteswap.h>
24
+#include <gpxe/iobuf.h>
25
+#include <gpxe/infiniband.h>
26
+#include <gpxe/ib_packet.h>
27
+
28
+/**
29
+ * @file
30
+ *
31
+ * Infiniband Packet Formats
32
+ *
33
+ */
34
+
35
+/**
36
+ * Add IB headers
37
+ *
38
+ * @v ibdev		Infiniband device
39
+ * @v iobuf		I/O buffer to contain headers
40
+ * @v qp		Queue pair
41
+ * @v payload_len	Payload length
42
+ * @v av		Address vector
43
+ */
44
+int ib_push ( struct ib_device *ibdev, struct io_buffer *iobuf,
45
+	      struct ib_queue_pair *qp, size_t payload_len,
46
+	      const struct ib_address_vector *av ) {
47
+	struct ib_local_route_header *lrh;
48
+	struct ib_global_route_header *grh;
49
+	struct ib_base_transport_header *bth;
50
+	struct ib_datagram_extended_transport_header *deth;
51
+	size_t orig_iob_len = iob_len ( iobuf );
52
+	size_t pad_len;
53
+	size_t lrh_len;
54
+	size_t grh_len;
55
+	unsigned int vl;
56
+	unsigned int lnh;
57
+
58
+	DBGC2 ( ibdev, "IBDEV %p TX %04x:%08lx => %04x:%08lx (key %08lx)\n",
59
+		ibdev, ibdev->lid, qp->qpn, av->lid, av->qpn, av->qkey );
60
+
61
+	/* Calculate packet length */
62
+	pad_len = ( (-payload_len) & 0x3 );
63
+	payload_len += pad_len;
64
+	payload_len += 4; /* ICRC */
65
+
66
+	/* Reserve space for headers */
67
+	orig_iob_len = iob_len ( iobuf );
68
+	deth = iob_push ( iobuf, sizeof ( *deth ) );
69
+	bth = iob_push ( iobuf, sizeof ( *bth ) );
70
+	grh_len = ( payload_len + iob_len ( iobuf ) - orig_iob_len );
71
+	grh = ( av->gid_present ?
72
+		iob_push ( iobuf, sizeof ( *grh ) ) : NULL );
73
+	lrh = iob_push ( iobuf, sizeof ( *lrh ) );
74
+	lrh_len = ( payload_len + iob_len ( iobuf ) - orig_iob_len );
75
+
76
+	/* Construct LRH */
77
+	vl = ( ( av->qpn == IB_QPN_SMP ) ? IB_VL_SMP : IB_VL_DEFAULT );
78
+	lrh->vl__lver = ( vl << 4 );
79
+	lnh = ( grh ? IB_LNH_GRH : IB_LNH_BTH );
80
+	lrh->sl__lnh = ( ( av->sl << 4 ) | lnh );
81
+	lrh->dlid = htons ( av->lid );
82
+	lrh->length = htons ( lrh_len >> 2 );
83
+	lrh->slid = htons ( ibdev->lid );
84
+
85
+	/* Construct GRH, if required */
86
+	if ( grh ) {
87
+		grh->ipver__tclass__flowlabel =
88
+			htonl ( IB_GRH_IPVER_IPv6 << 28 );
89
+		grh->paylen = htons ( grh_len );
90
+		grh->nxthdr = IB_GRH_NXTHDR_IBA;
91
+		grh->hoplmt = 0;
92
+		memcpy ( &grh->sgid, &ibdev->gid, sizeof ( grh->sgid ) );
93
+		memcpy ( &grh->dgid, &av->gid, sizeof ( grh->dgid ) );
94
+	}
95
+
96
+	/* Construct BTH */
97
+	bth->opcode = BTH_OPCODE_UD_SEND;
98
+	bth->se__m__padcnt__tver = ( pad_len << 4 );
99
+	bth->pkey = htons ( ibdev->pkey );
100
+	bth->dest_qp = htonl ( av->qpn );
101
+	bth->ack__psn = htonl ( ( ibdev->psn++ ) & 0xffffffUL );
102
+
103
+	/* Construct DETH */
104
+	deth->qkey = htonl ( av->qkey );
105
+	deth->src_qp = htonl ( qp->qpn );
106
+
107
+	DBGCP_HDA ( ibdev, 0, iobuf->data,
108
+		    ( iob_len ( iobuf ) - orig_iob_len ) );
109
+
110
+	return 0;
111
+}
112
+
113
+/**
114
+ * Remove IB headers
115
+ *
116
+ * @v ibdev		Infiniband device
117
+ * @v iobuf		I/O buffer containing headers
118
+ * @v qp		Queue pair to fill in, or NULL
119
+ * @v payload_len	Payload length to fill in, or NULL
120
+ * @v av		Address vector to fill in
121
+ */
122
+int ib_pull ( struct ib_device *ibdev, struct io_buffer *iobuf,
123
+	      struct ib_queue_pair **qp, size_t *payload_len,
124
+	      struct ib_address_vector *av ) {
125
+	struct ib_local_route_header *lrh;
126
+	struct ib_global_route_header *grh;
127
+	struct ib_base_transport_header *bth;
128
+	struct ib_datagram_extended_transport_header *deth;
129
+	size_t orig_iob_len = iob_len ( iobuf );
130
+	unsigned int lnh;
131
+	size_t pad_len;
132
+	unsigned long qpn;
133
+	unsigned int lid;
134
+
135
+	/* Clear return values */
136
+	if ( qp )
137
+		*qp = NULL;
138
+	if ( payload_len )
139
+		*payload_len = 0;
140
+	memset ( av, 0, sizeof ( *av ) );
141
+
142
+	/* Extract LRH */
143
+	if ( iob_len ( iobuf ) < sizeof ( *lrh ) ) {
144
+		DBGC ( ibdev, "IBDEV %p RX too short (%zd bytes) for LRH\n",
145
+		       ibdev, iob_len ( iobuf ) );
146
+		return -EINVAL;
147
+	}
148
+	lrh = iobuf->data;
149
+	iob_pull ( iobuf, sizeof ( *lrh ) );
150
+	av->lid = ntohs ( lrh->slid );
151
+	av->sl = ( lrh->sl__lnh >> 4 );
152
+	lnh = ( lrh->sl__lnh & 0x3 );
153
+	lid = ntohs ( lrh->dlid );
154
+
155
+	/* Reject unsupported packets */
156
+	if ( ! ( ( lnh == IB_LNH_BTH ) || ( lnh == IB_LNH_GRH ) ) ) {
157
+		DBGC ( ibdev, "IBDEV %p RX unsupported LNH %x\n",
158
+		       ibdev, lnh );
159
+		return -ENOTSUP;
160
+	}
161
+
162
+	/* Extract GRH, if present */
163
+	if ( lnh == IB_LNH_GRH ) {
164
+		if ( iob_len ( iobuf ) < sizeof ( *grh ) ) {
165
+			DBGC ( ibdev, "IBDEV %p RX too short (%zd bytes) "
166
+			       "for GRH\n", ibdev, iob_len ( iobuf ) );
167
+			return -EINVAL;
168
+		}
169
+		grh = iobuf->data;
170
+		iob_pull ( iobuf, sizeof ( *grh ) );
171
+		av->gid_present = 1;
172
+		memcpy ( &av->gid, &grh->sgid, sizeof ( av->gid ) );
173
+	} else {
174
+		grh = NULL;
175
+	}
176
+
177
+	/* Extract BTH */
178
+	if ( iob_len ( iobuf ) < sizeof ( *bth ) ) {
179
+		DBGC ( ibdev, "IBDEV %p RX too short (%zd bytes) for BTH\n",
180
+		       ibdev, iob_len ( iobuf ) );
181
+		return -EINVAL;
182
+	}
183
+	bth = iobuf->data;
184
+	iob_pull ( iobuf, sizeof ( *bth ) );
185
+	if ( bth->opcode != BTH_OPCODE_UD_SEND ) {
186
+		DBGC ( ibdev, "IBDEV %p unsupported BTH opcode %x\n",
187
+		       ibdev, bth->opcode );
188
+		return -ENOTSUP;
189
+	}
190
+	qpn = ntohl ( bth->dest_qp );
191
+
192
+	/* Extract DETH */
193
+	if ( iob_len ( iobuf ) < sizeof ( *deth ) ) {
194
+		DBGC ( ibdev, "IBDEV %p RX too short (%zd bytes) for DETH\n",
195
+		       ibdev, iob_len ( iobuf ) );
196
+		return -EINVAL;
197
+	}
198
+	deth = iobuf->data;
199
+	iob_pull ( iobuf, sizeof ( *deth ) );
200
+	av->qpn = ntohl ( deth->src_qp );
201
+	av->qkey = ntohl ( deth->qkey );
202
+
203
+	/* Calculate payload length, if applicable */
204
+	if ( payload_len ) {
205
+		pad_len = ( ( bth->se__m__padcnt__tver >> 4 ) & 0x3 );
206
+		*payload_len = ( ( ntohs ( lrh->length ) << 2 )
207
+				 - ( orig_iob_len - iob_len ( iobuf ) )
208
+				 - pad_len - 4 /* ICRC */ );
209
+	}
210
+
211
+	/* Determine destination QP, if applicable */
212
+	if ( qp ) {
213
+		if ( IB_LID_MULTICAST ( lid ) && grh ) {
214
+			*qp = ib_find_qp_mgid ( ibdev, &grh->dgid );
215
+		} else {
216
+			*qp = ib_find_qp_qpn ( ibdev, qpn );
217
+		}
218
+		if ( ! *qp ) {
219
+			DBGC ( ibdev, "IBDEV %p RX for nonexistent QP\n",
220
+			       ibdev );
221
+			return -ENODEV;
222
+		}
223
+	}
224
+
225
+	DBGC2 ( ibdev, "IBDEV %p RX %04x:%08lx <= %04x:%08lx (key %08lx)\n",
226
+		ibdev, lid,
227
+		( IB_LID_MULTICAST( lid ) ? ( qp ? (*qp)->qpn : -1UL ) : qpn ),
228
+		av->lid, av->qpn, ntohl ( deth->qkey ) );
229
+	DBGCP_HDA ( ibdev, 0,
230
+		    ( iobuf->data - ( orig_iob_len - iob_len ( iobuf ) ) ),
231
+		    ( orig_iob_len - iob_len ( iobuf ) ) );
232
+
233
+	return 0;
234
+}

+ 1
- 0
src/include/gpxe/errfile.h View File

@@ -136,6 +136,7 @@
136 136
 #define ERRFILE_dhcppkt			( ERRFILE_NET | 0x00150000 )
137 137
 #define ERRFILE_slam			( ERRFILE_NET | 0x00160000 )
138 138
 #define ERRFILE_ib_sma			( ERRFILE_NET | 0x00170000 )
139
+#define ERRFILE_ib_packet		( ERRFILE_NET | 0x00180000 )
139 140
 
140 141
 #define ERRFILE_image		      ( ERRFILE_IMAGE | 0x00000000 )
141 142
 #define ERRFILE_elf		      ( ERRFILE_IMAGE | 0x00010000 )

+ 34
- 1
src/include/gpxe/ib_packet.h View File

@@ -7,6 +7,11 @@
7 7
  *
8 8
  */
9 9
 
10
+struct ib_device;
11
+struct ib_queue_pair;
12
+struct ib_address_vector;
13
+struct io_buffer;
14
+
10 15
 /** Half of an Infiniband Global Identifier */
11 16
 struct ib_gid_half {
12 17
 	uint8_t bytes[8];
@@ -53,6 +58,9 @@ enum ib_lnh {
53 58
 /** Default Infiniband LID */
54 59
 #define IB_LID_NONE 0xffff
55 60
 
61
+/** Test for multicast LID */
62
+#define IB_LID_MULTICAST( lid ) ( ( (lid) >= 0xc000 ) && ( (lid) <= 0xfffe ) )
63
+
56 64
 /** An Infiniband Global Route Header */
57 65
 struct ib_global_route_header {
58 66
 	/** IP version, traffic class, and flow label
@@ -76,7 +84,6 @@ struct ib_global_route_header {
76 84
 
77 85
 #define IB_GRH_IPVER_IPv6 0x06
78 86
 #define IB_GRH_NXTHDR_IBA 0x1b
79
-#define IB_GRH_HOPLMT_MAX 0xff
80 87
 
81 88
 /** An Infiniband Base Transport Header */
82 89
 struct ib_base_transport_header {
@@ -111,4 +118,30 @@ struct ib_datagram_extended_transport_header {
111 118
 	uint32_t src_qp;
112 119
 } __attribute__ (( packed ));
113 120
 
121
+/** All known IB header formats */
122
+union ib_headers {
123
+	struct ib_local_route_header lrh;
124
+	struct {
125
+		struct ib_local_route_header lrh;
126
+		struct ib_global_route_header grh;
127
+		struct ib_base_transport_header bth;
128
+		struct ib_datagram_extended_transport_header deth;
129
+	} __attribute__ (( packed )) lrh__grh__bth__deth;
130
+	struct {
131
+		struct ib_local_route_header lrh;
132
+		struct ib_base_transport_header bth;
133
+		struct ib_datagram_extended_transport_header deth;
134
+	} __attribute__ (( packed )) lrh__bth__deth;
135
+} __attribute__ (( packed ));
136
+
137
+/** Maximum size required for IB headers */
138
+#define IB_MAX_HEADER_SIZE sizeof ( union ib_headers )
139
+
140
+extern int ib_push ( struct ib_device *ibdev, struct io_buffer *iobuf,
141
+		     struct ib_queue_pair *qp, size_t payload_len,
142
+		     const struct ib_address_vector *av );
143
+extern int ib_pull ( struct ib_device *ibdev, struct io_buffer *iobuf,
144
+		     struct ib_queue_pair **qp, size_t *payload_len,
145
+		     struct ib_address_vector *av );
146
+
114 147
 #endif /* _GPXE_IB_PACKET_H */

+ 27
- 27
src/include/gpxe/infiniband.h View File

@@ -55,8 +55,20 @@ struct ib_work_queue {
55 55
 	void *drv_priv;
56 56
 };
57 57
 
58
+/** An Infiniband multicast GID */
59
+struct ib_multicast_gid {
60
+	/** List of multicast GIDs on this QP */
61
+	struct list_head list;
62
+	/** Multicast GID */
63
+	struct ib_gid gid;
64
+};
65
+
58 66
 /** An Infiniband Queue Pair */
59 67
 struct ib_queue_pair {
68
+	/** Containing Infiniband device */
69
+	struct ib_device *ibdev;
70
+	/** List of queue pairs on this Infiniband device */
71
+	struct list_head list;
60 72
 	/** Queue Pair Number */
61 73
 	unsigned long qpn;
62 74
 	/** Queue key */
@@ -65,6 +77,8 @@ struct ib_queue_pair {
65 77
 	struct ib_work_queue send;
66 78
 	/** Receive queue */
67 79
 	struct ib_work_queue recv;
80
+	/** List of multicast GIDs */
81
+	struct list_head mgids;
68 82
 	/** Driver private data */
69 83
 	void *drv_priv;
70 84
 	/** Queue owner private data */
@@ -286,6 +300,8 @@ struct ib_device {
286 300
 	struct list_head list;
287 301
 	/** Underlying device */
288 302
 	struct device *dev;
303
+	/** List of queue pairs */
304
+	struct list_head qps;
289 305
 	/** Infiniband operations */
290 306
 	struct ib_device_operations *op;
291 307
 	/** Port number */
@@ -308,6 +324,9 @@ struct ib_device {
308 324
 	/** Partition key */
309 325
 	uint16_t pkey;
310 326
 
327
+	/** Outbound packet sequence number */
328
+	uint32_t psn;
329
+
311 330
 	/** Driver private data */
312 331
 	void *drv_priv;
313 332
 	/** Owner private data */
@@ -327,6 +346,10 @@ extern int ib_modify_qp ( struct ib_device *ibdev, struct ib_queue_pair *qp,
327 346
 			  unsigned long mod_list, unsigned long qkey );
328 347
 extern void ib_destroy_qp ( struct ib_device *ibdev,
329 348
 			    struct ib_queue_pair *qp );
349
+extern struct ib_queue_pair * ib_find_qp_qpn ( struct ib_device *ibdev,
350
+					       unsigned long qpn );
351
+extern struct ib_queue_pair * ib_find_qp_mgid ( struct ib_device *ibdev,
352
+						struct ib_gid *gid );
330 353
 extern struct ib_work_queue * ib_find_wq ( struct ib_completion_queue *cq,
331 354
 					   unsigned long qpn, int is_send );
332 355
 extern int ib_post_send ( struct ib_device *ibdev, struct ib_queue_pair *qp,
@@ -341,6 +364,10 @@ extern void ib_complete_recv ( struct ib_device *ibdev,
341 364
 			       struct ib_queue_pair *qp,
342 365
 			       struct ib_address_vector *av,
343 366
 			       struct io_buffer *iobuf, int rc );
367
+extern int ib_mcast_attach ( struct ib_device *ibdev, struct ib_queue_pair *qp,
368
+			     struct ib_gid *gid );
369
+extern void ib_mcast_detach ( struct ib_device *ibdev,
370
+			      struct ib_queue_pair *qp, struct ib_gid *gid );
344 371
 extern struct ib_device * alloc_ibdev ( size_t priv_size );
345 372
 extern int register_ibdev ( struct ib_device *ibdev );
346 373
 extern void unregister_ibdev ( struct ib_device *ibdev );
@@ -394,33 +421,6 @@ ib_link_ok ( struct ib_device *ibdev ) {
394 421
 	return ( ibdev->port_state == IB_PORT_STATE_ACTIVE );
395 422
 }
396 423
 
397
-/**
398
- * Attach to multicast group
399
- *
400
- * @v ibdev		Infiniband device
401
- * @v qp		Queue pair
402
- * @v gid		Multicast GID
403
- * @ret rc		Return status code
404
- */
405
-static inline __always_inline int
406
-ib_mcast_attach ( struct ib_device *ibdev, struct ib_queue_pair *qp,
407
-		  struct ib_gid *gid ) {
408
-	return ibdev->op->mcast_attach ( ibdev, qp, gid );
409
-}
410
-
411
-/**
412
- * Detach from multicast group
413
- *
414
- * @v ibdev		Infiniband device
415
- * @v qp		Queue pair
416
- * @v gid		Multicast GID
417
- */
418
-static inline __always_inline void
419
-ib_mcast_detach ( struct ib_device *ibdev, struct ib_queue_pair *qp,
420
-		  struct ib_gid *gid ) {
421
-	ibdev->op->mcast_detach ( ibdev, qp, gid );
422
-}
423
-
424 424
 /**
425 425
  * Get reference to Infiniband device
426 426
  *

+ 127
- 8
src/net/infiniband.c View File

@@ -60,7 +60,7 @@ ib_create_cq ( struct ib_device *ibdev, unsigned int num_cqes,
60 60
 	/* Allocate and initialise data structure */
61 61
 	cq = zalloc ( sizeof ( *cq ) );
62 62
 	if ( ! cq )
63
-		return NULL;
63
+		goto err_alloc_cq;
64 64
 	cq->num_cqes = num_cqes;
65 65
 	INIT_LIST_HEAD ( &cq->work_queues );
66 66
 	cq->op = op;
@@ -69,14 +69,19 @@ ib_create_cq ( struct ib_device *ibdev, unsigned int num_cqes,
69 69
 	if ( ( rc = ibdev->op->create_cq ( ibdev, cq ) ) != 0 ) {
70 70
 		DBGC ( ibdev, "IBDEV %p could not initialise completion "
71 71
 		       "queue: %s\n", ibdev, strerror ( rc ) );
72
-		free ( cq );
73
-		return NULL;
72
+		goto err_dev_create_cq;
74 73
 	}
75 74
 
76 75
 	DBGC ( ibdev, "IBDEV %p created %d-entry completion queue %p (%p) "
77 76
 	       "with CQN %#lx\n", ibdev, num_cqes, cq,
78 77
 	       ib_cq_get_drvdata ( cq ), cq->cqn );
79 78
 	return cq;
79
+
80
+	ibdev->op->destroy_cq ( ibdev, cq );
81
+ err_dev_create_cq:
82
+	free ( cq );
83
+ err_alloc_cq:
84
+	return NULL;
80 85
 }
81 86
 
82 87
 /**
@@ -123,7 +128,9 @@ struct ib_queue_pair * ib_create_qp ( struct ib_device *ibdev,
123 128
 		       ( num_recv_wqes * sizeof ( qp->recv.iobufs[0] ) ) );
124 129
 	qp = zalloc ( total_size );
125 130
 	if ( ! qp )
126
-		return NULL;
131
+		goto err_alloc_qp;
132
+	qp->ibdev = ibdev;
133
+	list_add ( &qp->list, &ibdev->qps );
127 134
 	qp->qkey = qkey;
128 135
 	qp->send.qp = qp;
129 136
 	qp->send.is_send = 1;
@@ -137,15 +144,13 @@ struct ib_queue_pair * ib_create_qp ( struct ib_device *ibdev,
137 144
 	qp->recv.num_wqes = num_recv_wqes;
138 145
 	qp->recv.iobufs = ( ( ( void * ) qp ) + sizeof ( *qp ) +
139 146
 			    ( num_send_wqes * sizeof ( qp->send.iobufs[0] ) ));
147
+	INIT_LIST_HEAD ( &qp->mgids );
140 148
 
141 149
 	/* Perform device-specific initialisation and get QPN */
142 150
 	if ( ( rc = ibdev->op->create_qp ( ibdev, qp ) ) != 0 ) {
143 151
 		DBGC ( ibdev, "IBDEV %p could not initialise queue pair: "
144 152
 		       "%s\n", ibdev, strerror ( rc ) );
145
-		list_del ( &qp->send.list );
146
-		list_del ( &qp->recv.list );
147
-		free ( qp );
148
-		return NULL;
153
+		goto err_dev_create_qp;
149 154
 	}
150 155
 
151 156
 	DBGC ( ibdev, "IBDEV %p created queue pair %p (%p) with QPN %#lx\n",
@@ -157,6 +162,15 @@ struct ib_queue_pair * ib_create_qp ( struct ib_device *ibdev,
157 162
 	       ibdev, qp->qpn, num_recv_wqes, qp->recv.iobufs,
158 163
 	       ( ( ( void * ) qp ) + total_size ) );
159 164
 	return qp;
165
+
166
+	ibdev->op->destroy_qp ( ibdev, qp );
167
+ err_dev_create_qp:
168
+	list_del ( &qp->send.list );
169
+	list_del ( &qp->recv.list );
170
+	list_del ( &qp->list );
171
+	free ( qp );
172
+ err_alloc_qp:
173
+	return NULL;
160 174
 }
161 175
 
162 176
 /**
@@ -199,6 +213,8 @@ void ib_destroy_qp ( struct ib_device *ibdev, struct ib_queue_pair *qp ) {
199 213
 	DBGC ( ibdev, "IBDEV %p destroying QPN %#lx\n",
200 214
 	       ibdev, qp->qpn );
201 215
 
216
+	assert ( list_empty ( &qp->mgids ) );
217
+
202 218
 	/* Perform device-specific destruction */
203 219
 	ibdev->op->destroy_qp ( ibdev, qp );
204 220
 
@@ -219,9 +235,51 @@ void ib_destroy_qp ( struct ib_device *ibdev, struct ib_queue_pair *qp ) {
219 235
 	list_del ( &qp->recv.list );
220 236
 
221 237
 	/* Free QP */
238
+	list_del ( &qp->list );
222 239
 	free ( qp );
223 240
 }
224 241
 
242
+/**
243
+ * Find queue pair by QPN
244
+ *
245
+ * @v ibdev		Infiniband device
246
+ * @v qpn		Queue pair number
247
+ * @ret qp		Queue pair, or NULL
248
+ */
249
+struct ib_queue_pair * ib_find_qp_qpn ( struct ib_device *ibdev,
250
+					unsigned long qpn ) {
251
+	struct ib_queue_pair *qp;
252
+
253
+	list_for_each_entry ( qp, &ibdev->qps, list ) {
254
+		if ( qp->qpn == qpn )
255
+			return qp;
256
+	}
257
+	return NULL;
258
+}
259
+
260
+/**
261
+ * Find queue pair by multicast GID
262
+ *
263
+ * @v ibdev		Infiniband device
264
+ * @v gid		Multicast GID
265
+ * @ret qp		Queue pair, or NULL
266
+ */
267
+struct ib_queue_pair * ib_find_qp_mgid ( struct ib_device *ibdev,
268
+					 struct ib_gid *gid ) {
269
+	struct ib_queue_pair *qp;
270
+	struct ib_multicast_gid *mgid;
271
+
272
+	list_for_each_entry ( qp, &ibdev->qps, list ) {
273
+		list_for_each_entry ( mgid, &qp->mgids, list ) {
274
+			if ( memcmp ( &mgid->gid, gid,
275
+				      sizeof ( mgid->gid ) ) == 0 ) {
276
+				return qp;
277
+			}
278
+		}
279
+	}
280
+	return NULL;
281
+}
282
+
225 283
 /**
226 284
  * Find work queue belonging to completion queue
227 285
  *
@@ -333,6 +391,66 @@ void ib_complete_recv ( struct ib_device *ibdev, struct ib_queue_pair *qp,
333 391
 	qp->recv.fill--;
334 392
 }
335 393
 
394
+/**
395
+ * Attach to multicast group
396
+ *
397
+ * @v ibdev		Infiniband device
398
+ * @v qp		Queue pair
399
+ * @v gid		Multicast GID
400
+ * @ret rc		Return status code
401
+ */
402
+int ib_mcast_attach ( struct ib_device *ibdev, struct ib_queue_pair *qp,
403
+		      struct ib_gid *gid ) {
404
+	struct ib_multicast_gid *mgid;
405
+	int rc;
406
+
407
+	/* Add to software multicast GID list */
408
+	mgid = zalloc ( sizeof ( *mgid ) );
409
+	if ( ! mgid ) {
410
+		rc = -ENOMEM;
411
+		goto err_alloc_mgid;
412
+	}
413
+	memcpy ( &mgid->gid, gid, sizeof ( mgid->gid ) );
414
+	list_add ( &mgid->list, &qp->mgids );
415
+
416
+	/* Add to hardware multicast GID list */
417
+	if ( ( rc = ibdev->op->mcast_attach ( ibdev, qp, gid ) ) != 0 )
418
+		goto err_dev_mcast_attach;
419
+
420
+	return 0;
421
+
422
+ err_dev_mcast_attach:
423
+	list_del ( &mgid->list );
424
+	free ( mgid );
425
+ err_alloc_mgid:
426
+	return rc;
427
+}
428
+
429
+/**
430
+ * Detach from multicast group
431
+ *
432
+ * @v ibdev		Infiniband device
433
+ * @v qp		Queue pair
434
+ * @v gid		Multicast GID
435
+ */
436
+void ib_mcast_detach ( struct ib_device *ibdev, struct ib_queue_pair *qp,
437
+		       struct ib_gid *gid ) {
438
+	struct ib_multicast_gid *mgid;
439
+
440
+	/* Remove from hardware multicast GID list */
441
+	ibdev->op->mcast_detach ( ibdev, qp, gid );
442
+
443
+	/* Remove from software multicast GID list */
444
+	list_for_each_entry ( mgid, &qp->mgids, list ) {
445
+		if ( memcmp ( &mgid->gid, gid, sizeof ( mgid->gid ) ) == 0 ) {
446
+			list_del ( &mgid->list );
447
+			free ( mgid );
448
+			break;
449
+		}
450
+	}
451
+}
452
+
453
+
336 454
 /***************************************************************************
337 455
  *
338 456
  * Event queues
@@ -392,6 +510,7 @@ struct ib_device * alloc_ibdev ( size_t priv_size ) {
392 510
 	if ( ibdev ) {
393 511
 		drv_priv = ( ( ( void * ) ibdev ) + sizeof ( *ibdev ) );
394 512
 		ib_set_drvdata ( ibdev, drv_priv );
513
+		INIT_LIST_HEAD ( &ibdev->qps );
395 514
 		ibdev->lid = IB_LID_NONE;
396 515
 		ibdev->pkey = IB_PKEY_NONE;
397 516
 	}

Loading…
Cancel
Save