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 15 years ago
parent
commit
9e5fd8ec59

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

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
 #define ERRFILE_dhcppkt			( ERRFILE_NET | 0x00150000 )
136
 #define ERRFILE_dhcppkt			( ERRFILE_NET | 0x00150000 )
137
 #define ERRFILE_slam			( ERRFILE_NET | 0x00160000 )
137
 #define ERRFILE_slam			( ERRFILE_NET | 0x00160000 )
138
 #define ERRFILE_ib_sma			( ERRFILE_NET | 0x00170000 )
138
 #define ERRFILE_ib_sma			( ERRFILE_NET | 0x00170000 )
139
+#define ERRFILE_ib_packet		( ERRFILE_NET | 0x00180000 )
139
 
140
 
140
 #define ERRFILE_image		      ( ERRFILE_IMAGE | 0x00000000 )
141
 #define ERRFILE_image		      ( ERRFILE_IMAGE | 0x00000000 )
141
 #define ERRFILE_elf		      ( ERRFILE_IMAGE | 0x00010000 )
142
 #define ERRFILE_elf		      ( ERRFILE_IMAGE | 0x00010000 )

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

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
 /** Half of an Infiniband Global Identifier */
15
 /** Half of an Infiniband Global Identifier */
11
 struct ib_gid_half {
16
 struct ib_gid_half {
12
 	uint8_t bytes[8];
17
 	uint8_t bytes[8];
53
 /** Default Infiniband LID */
58
 /** Default Infiniband LID */
54
 #define IB_LID_NONE 0xffff
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
 /** An Infiniband Global Route Header */
64
 /** An Infiniband Global Route Header */
57
 struct ib_global_route_header {
65
 struct ib_global_route_header {
58
 	/** IP version, traffic class, and flow label
66
 	/** IP version, traffic class, and flow label
76
 
84
 
77
 #define IB_GRH_IPVER_IPv6 0x06
85
 #define IB_GRH_IPVER_IPv6 0x06
78
 #define IB_GRH_NXTHDR_IBA 0x1b
86
 #define IB_GRH_NXTHDR_IBA 0x1b
79
-#define IB_GRH_HOPLMT_MAX 0xff
80
 
87
 
81
 /** An Infiniband Base Transport Header */
88
 /** An Infiniband Base Transport Header */
82
 struct ib_base_transport_header {
89
 struct ib_base_transport_header {
111
 	uint32_t src_qp;
118
 	uint32_t src_qp;
112
 } __attribute__ (( packed ));
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
 #endif /* _GPXE_IB_PACKET_H */
147
 #endif /* _GPXE_IB_PACKET_H */

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

55
 	void *drv_priv;
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
 /** An Infiniband Queue Pair */
66
 /** An Infiniband Queue Pair */
59
 struct ib_queue_pair {
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
 	/** Queue Pair Number */
72
 	/** Queue Pair Number */
61
 	unsigned long qpn;
73
 	unsigned long qpn;
62
 	/** Queue key */
74
 	/** Queue key */
65
 	struct ib_work_queue send;
77
 	struct ib_work_queue send;
66
 	/** Receive queue */
78
 	/** Receive queue */
67
 	struct ib_work_queue recv;
79
 	struct ib_work_queue recv;
80
+	/** List of multicast GIDs */
81
+	struct list_head mgids;
68
 	/** Driver private data */
82
 	/** Driver private data */
69
 	void *drv_priv;
83
 	void *drv_priv;
70
 	/** Queue owner private data */
84
 	/** Queue owner private data */
286
 	struct list_head list;
300
 	struct list_head list;
287
 	/** Underlying device */
301
 	/** Underlying device */
288
 	struct device *dev;
302
 	struct device *dev;
303
+	/** List of queue pairs */
304
+	struct list_head qps;
289
 	/** Infiniband operations */
305
 	/** Infiniband operations */
290
 	struct ib_device_operations *op;
306
 	struct ib_device_operations *op;
291
 	/** Port number */
307
 	/** Port number */
308
 	/** Partition key */
324
 	/** Partition key */
309
 	uint16_t pkey;
325
 	uint16_t pkey;
310
 
326
 
327
+	/** Outbound packet sequence number */
328
+	uint32_t psn;
329
+
311
 	/** Driver private data */
330
 	/** Driver private data */
312
 	void *drv_priv;
331
 	void *drv_priv;
313
 	/** Owner private data */
332
 	/** Owner private data */
327
 			  unsigned long mod_list, unsigned long qkey );
346
 			  unsigned long mod_list, unsigned long qkey );
328
 extern void ib_destroy_qp ( struct ib_device *ibdev,
347
 extern void ib_destroy_qp ( struct ib_device *ibdev,
329
 			    struct ib_queue_pair *qp );
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
 extern struct ib_work_queue * ib_find_wq ( struct ib_completion_queue *cq,
353
 extern struct ib_work_queue * ib_find_wq ( struct ib_completion_queue *cq,
331
 					   unsigned long qpn, int is_send );
354
 					   unsigned long qpn, int is_send );
332
 extern int ib_post_send ( struct ib_device *ibdev, struct ib_queue_pair *qp,
355
 extern int ib_post_send ( struct ib_device *ibdev, struct ib_queue_pair *qp,
341
 			       struct ib_queue_pair *qp,
364
 			       struct ib_queue_pair *qp,
342
 			       struct ib_address_vector *av,
365
 			       struct ib_address_vector *av,
343
 			       struct io_buffer *iobuf, int rc );
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
 extern struct ib_device * alloc_ibdev ( size_t priv_size );
371
 extern struct ib_device * alloc_ibdev ( size_t priv_size );
345
 extern int register_ibdev ( struct ib_device *ibdev );
372
 extern int register_ibdev ( struct ib_device *ibdev );
346
 extern void unregister_ibdev ( struct ib_device *ibdev );
373
 extern void unregister_ibdev ( struct ib_device *ibdev );
394
 	return ( ibdev->port_state == IB_PORT_STATE_ACTIVE );
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
  * Get reference to Infiniband device
425
  * Get reference to Infiniband device
426
  *
426
  *

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

60
 	/* Allocate and initialise data structure */
60
 	/* Allocate and initialise data structure */
61
 	cq = zalloc ( sizeof ( *cq ) );
61
 	cq = zalloc ( sizeof ( *cq ) );
62
 	if ( ! cq )
62
 	if ( ! cq )
63
-		return NULL;
63
+		goto err_alloc_cq;
64
 	cq->num_cqes = num_cqes;
64
 	cq->num_cqes = num_cqes;
65
 	INIT_LIST_HEAD ( &cq->work_queues );
65
 	INIT_LIST_HEAD ( &cq->work_queues );
66
 	cq->op = op;
66
 	cq->op = op;
69
 	if ( ( rc = ibdev->op->create_cq ( ibdev, cq ) ) != 0 ) {
69
 	if ( ( rc = ibdev->op->create_cq ( ibdev, cq ) ) != 0 ) {
70
 		DBGC ( ibdev, "IBDEV %p could not initialise completion "
70
 		DBGC ( ibdev, "IBDEV %p could not initialise completion "
71
 		       "queue: %s\n", ibdev, strerror ( rc ) );
71
 		       "queue: %s\n", ibdev, strerror ( rc ) );
72
-		free ( cq );
73
-		return NULL;
72
+		goto err_dev_create_cq;
74
 	}
73
 	}
75
 
74
 
76
 	DBGC ( ibdev, "IBDEV %p created %d-entry completion queue %p (%p) "
75
 	DBGC ( ibdev, "IBDEV %p created %d-entry completion queue %p (%p) "
77
 	       "with CQN %#lx\n", ibdev, num_cqes, cq,
76
 	       "with CQN %#lx\n", ibdev, num_cqes, cq,
78
 	       ib_cq_get_drvdata ( cq ), cq->cqn );
77
 	       ib_cq_get_drvdata ( cq ), cq->cqn );
79
 	return cq;
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
 		       ( num_recv_wqes * sizeof ( qp->recv.iobufs[0] ) ) );
128
 		       ( num_recv_wqes * sizeof ( qp->recv.iobufs[0] ) ) );
124
 	qp = zalloc ( total_size );
129
 	qp = zalloc ( total_size );
125
 	if ( ! qp )
130
 	if ( ! qp )
126
-		return NULL;
131
+		goto err_alloc_qp;
132
+	qp->ibdev = ibdev;
133
+	list_add ( &qp->list, &ibdev->qps );
127
 	qp->qkey = qkey;
134
 	qp->qkey = qkey;
128
 	qp->send.qp = qp;
135
 	qp->send.qp = qp;
129
 	qp->send.is_send = 1;
136
 	qp->send.is_send = 1;
137
 	qp->recv.num_wqes = num_recv_wqes;
144
 	qp->recv.num_wqes = num_recv_wqes;
138
 	qp->recv.iobufs = ( ( ( void * ) qp ) + sizeof ( *qp ) +
145
 	qp->recv.iobufs = ( ( ( void * ) qp ) + sizeof ( *qp ) +
139
 			    ( num_send_wqes * sizeof ( qp->send.iobufs[0] ) ));
146
 			    ( num_send_wqes * sizeof ( qp->send.iobufs[0] ) ));
147
+	INIT_LIST_HEAD ( &qp->mgids );
140
 
148
 
141
 	/* Perform device-specific initialisation and get QPN */
149
 	/* Perform device-specific initialisation and get QPN */
142
 	if ( ( rc = ibdev->op->create_qp ( ibdev, qp ) ) != 0 ) {
150
 	if ( ( rc = ibdev->op->create_qp ( ibdev, qp ) ) != 0 ) {
143
 		DBGC ( ibdev, "IBDEV %p could not initialise queue pair: "
151
 		DBGC ( ibdev, "IBDEV %p could not initialise queue pair: "
144
 		       "%s\n", ibdev, strerror ( rc ) );
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
 	DBGC ( ibdev, "IBDEV %p created queue pair %p (%p) with QPN %#lx\n",
156
 	DBGC ( ibdev, "IBDEV %p created queue pair %p (%p) with QPN %#lx\n",
157
 	       ibdev, qp->qpn, num_recv_wqes, qp->recv.iobufs,
162
 	       ibdev, qp->qpn, num_recv_wqes, qp->recv.iobufs,
158
 	       ( ( ( void * ) qp ) + total_size ) );
163
 	       ( ( ( void * ) qp ) + total_size ) );
159
 	return qp;
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
 	DBGC ( ibdev, "IBDEV %p destroying QPN %#lx\n",
213
 	DBGC ( ibdev, "IBDEV %p destroying QPN %#lx\n",
200
 	       ibdev, qp->qpn );
214
 	       ibdev, qp->qpn );
201
 
215
 
216
+	assert ( list_empty ( &qp->mgids ) );
217
+
202
 	/* Perform device-specific destruction */
218
 	/* Perform device-specific destruction */
203
 	ibdev->op->destroy_qp ( ibdev, qp );
219
 	ibdev->op->destroy_qp ( ibdev, qp );
204
 
220
 
219
 	list_del ( &qp->recv.list );
235
 	list_del ( &qp->recv.list );
220
 
236
 
221
 	/* Free QP */
237
 	/* Free QP */
238
+	list_del ( &qp->list );
222
 	free ( qp );
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
  * Find work queue belonging to completion queue
284
  * Find work queue belonging to completion queue
227
  *
285
  *
333
 	qp->recv.fill--;
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
  * Event queues
456
  * Event queues
392
 	if ( ibdev ) {
510
 	if ( ibdev ) {
393
 		drv_priv = ( ( ( void * ) ibdev ) + sizeof ( *ibdev ) );
511
 		drv_priv = ( ( ( void * ) ibdev ) + sizeof ( *ibdev ) );
394
 		ib_set_drvdata ( ibdev, drv_priv );
512
 		ib_set_drvdata ( ibdev, drv_priv );
513
+		INIT_LIST_HEAD ( &ibdev->qps );
395
 		ibdev->lid = IB_LID_NONE;
514
 		ibdev->lid = IB_LID_NONE;
396
 		ibdev->pkey = IB_PKEY_NONE;
515
 		ibdev->pkey = IB_PKEY_NONE;
397
 	}
516
 	}

Loading…
Cancel
Save