|
@@ -26,6 +26,7 @@ Skeleton NIC driver for Etherboot
|
26
|
26
|
#include "arbel.h"
|
27
|
27
|
|
28
|
28
|
|
|
29
|
+#define MLX_RX_MAX_FILL NUM_IPOIB_RCV_WQES
|
29
|
30
|
|
30
|
31
|
struct mlx_nic {
|
31
|
32
|
/** Queue pair handle */
|
|
@@ -36,35 +37,65 @@ struct mlx_nic {
|
36
|
37
|
cq_t snd_cqh;
|
37
|
38
|
/** Receive completion queue */
|
38
|
39
|
cq_t rcv_cqh;
|
|
40
|
+
|
|
41
|
+ /** RX fill level */
|
|
42
|
+ unsigned int rx_fill;
|
39
|
43
|
};
|
40
|
44
|
|
41
|
45
|
|
42
|
46
|
static struct io_buffer *static_ipoib_tx_ring[NUM_IPOIB_SND_WQES];
|
|
47
|
+static struct io_buffer *static_ipoib_rx_ring[NUM_IPOIB_RCV_WQES];
|
43
|
48
|
|
44
|
49
|
static struct arbel static_arbel;
|
45
|
50
|
static struct arbel_send_work_queue static_arbel_ipoib_send_wq = {
|
46
|
51
|
.doorbell_idx = IPOIB_SND_QP_DB_IDX,
|
47
|
52
|
};
|
|
53
|
+static struct arbel_send_work_queue static_arbel_ipoib_recv_wq = {
|
|
54
|
+ .doorbell_idx = IPOIB_RCV_QP_DB_IDX,
|
|
55
|
+};
|
48
|
56
|
static struct arbel_completion_queue static_arbel_ipoib_send_cq = {
|
49
|
57
|
.doorbell_idx = IPOIB_SND_CQ_CI_DB_IDX,
|
50
|
58
|
};
|
|
59
|
+static struct arbel_completion_queue static_arbel_ipoib_recv_cq = {
|
|
60
|
+ .doorbell_idx = IPOIB_RCV_CQ_CI_DB_IDX,
|
|
61
|
+};
|
51
|
62
|
|
|
63
|
+static struct ib_completion_queue static_ipoib_send_cq;
|
|
64
|
+static struct ib_completion_queue static_ipoib_recv_cq;
|
52
|
65
|
static struct ib_device static_ibdev = {
|
53
|
66
|
.dev_priv = &static_arbel,
|
54
|
67
|
};
|
55
|
68
|
static struct ib_queue_pair static_ipoib_qp = {
|
56
|
69
|
.send = {
|
|
70
|
+ .qp = &static_ipoib_qp,
|
|
71
|
+ .is_send = 1,
|
|
72
|
+ .cq = &static_ipoib_send_cq,
|
57
|
73
|
.num_wqes = NUM_IPOIB_SND_WQES,
|
58
|
74
|
.iobufs = static_ipoib_tx_ring,
|
59
|
75
|
.dev_priv = &static_arbel_ipoib_send_wq,
|
|
76
|
+ .list = LIST_HEAD_INIT ( static_ipoib_qp.send.list ),
|
|
77
|
+ },
|
|
78
|
+ .recv = {
|
|
79
|
+ .qp = &static_ipoib_qp,
|
|
80
|
+ .is_send = 0,
|
|
81
|
+ .cq = &static_ipoib_recv_cq,
|
|
82
|
+ .num_wqes = NUM_IPOIB_RCV_WQES,
|
|
83
|
+ .iobufs = static_ipoib_rx_ring,
|
|
84
|
+ .dev_priv = &static_arbel_ipoib_recv_wq,
|
|
85
|
+ .list = LIST_HEAD_INIT ( static_ipoib_qp.recv.list ),
|
60
|
86
|
},
|
61
|
|
- .list = LIST_HEAD_INIT ( static_ipoib_qp.list ),
|
62
|
87
|
};
|
63
|
88
|
static struct ib_completion_queue static_ipoib_send_cq = {
|
64
|
89
|
.cqn = 1234, /* Only used for debug messages */
|
65
|
90
|
.num_cqes = NUM_IPOIB_SND_CQES,
|
66
|
91
|
.dev_priv = &static_arbel_ipoib_send_cq,
|
67
|
|
- .queue_pairs = LIST_HEAD_INIT ( static_ipoib_send_cq.queue_pairs ),
|
|
92
|
+ .work_queues = LIST_HEAD_INIT ( static_ipoib_send_cq.work_queues ),
|
|
93
|
+};
|
|
94
|
+static struct ib_completion_queue static_ipoib_recv_cq = {
|
|
95
|
+ .cqn = 2345, /* Only used for debug messages */
|
|
96
|
+ .num_cqes = NUM_IPOIB_RCV_CQES,
|
|
97
|
+ .dev_priv = &static_arbel_ipoib_recv_cq,
|
|
98
|
+ .work_queues = LIST_HEAD_INIT ( static_ipoib_recv_cq.work_queues ),
|
68
|
99
|
};
|
69
|
100
|
|
70
|
101
|
|
|
@@ -157,36 +188,6 @@ static int mlx_transmit_direct ( struct net_device *netdev,
|
157
|
188
|
}
|
158
|
189
|
|
159
|
190
|
|
160
|
|
-static void arbel_poll_cq ( struct ib_device *ibdev,
|
161
|
|
- struct ib_completion_queue *cq,
|
162
|
|
- ib_completer_t complete_send,
|
163
|
|
- ib_completer_t complete_recv );
|
164
|
|
-
|
165
|
|
-static void temp_complete_send ( struct ib_device *ibdev __unused,
|
166
|
|
- struct ib_queue_pair *qp,
|
167
|
|
- struct ib_completion *completion,
|
168
|
|
- struct io_buffer *iobuf ) {
|
169
|
|
- struct net_device *netdev = qp->priv;
|
170
|
|
-
|
171
|
|
- DBG ( "Wahey! TX completion\n" );
|
172
|
|
- netdev_tx_complete_err ( netdev, iobuf,
|
173
|
|
- ( completion->syndrome ? -EIO : 0 ) );
|
174
|
|
-}
|
175
|
|
-
|
176
|
|
-static void temp_complete_recv ( struct ib_device *ibdev __unused,
|
177
|
|
- struct ib_queue_pair *qp __unused,
|
178
|
|
- struct ib_completion *completion __unused,
|
179
|
|
- struct io_buffer *iobuf __unused ) {
|
180
|
|
- DBG ( "AARGH! recv completion\n" );
|
181
|
|
-}
|
182
|
|
-
|
183
|
|
-static void mlx_poll_cq_direct ( struct net_device *netdev ) {
|
184
|
|
- struct mlx_nic *mlx = netdev->priv;
|
185
|
|
-
|
186
|
|
- arbel_poll_cq ( &static_ibdev, &static_ipoib_send_cq,
|
187
|
|
- temp_complete_send, temp_complete_recv );
|
188
|
|
-}
|
189
|
|
-
|
190
|
191
|
/**
|
191
|
192
|
* Handle TX completion
|
192
|
193
|
*
|
|
@@ -233,6 +234,44 @@ static void mlx_rx_complete ( struct net_device *netdev,
|
233
|
234
|
netdev_rx ( netdev, iobuf );
|
234
|
235
|
}
|
235
|
236
|
|
|
237
|
+static void arbel_poll_cq ( struct ib_device *ibdev,
|
|
238
|
+ struct ib_completion_queue *cq,
|
|
239
|
+ ib_completer_t complete_send,
|
|
240
|
+ ib_completer_t complete_recv );
|
|
241
|
+
|
|
242
|
+static void temp_complete_send ( struct ib_device *ibdev __unused,
|
|
243
|
+ struct ib_queue_pair *qp,
|
|
244
|
+ struct ib_completion *completion,
|
|
245
|
+ struct io_buffer *iobuf ) {
|
|
246
|
+ struct net_device *netdev = qp->priv;
|
|
247
|
+
|
|
248
|
+ DBG ( "Wahey! TX completion\n" );
|
|
249
|
+ netdev_tx_complete_err ( netdev, iobuf,
|
|
250
|
+ ( completion->syndrome ? -EIO : 0 ) );
|
|
251
|
+}
|
|
252
|
+
|
|
253
|
+static void temp_complete_recv ( struct ib_device *ibdev __unused,
|
|
254
|
+ struct ib_queue_pair *qp,
|
|
255
|
+ struct ib_completion *completion,
|
|
256
|
+ struct io_buffer *iobuf ) {
|
|
257
|
+ struct net_device *netdev = qp->priv;
|
|
258
|
+ struct mlx_nic *mlx = netdev->priv;
|
|
259
|
+
|
|
260
|
+ DBG ( "Yay! RX completion on %p len %zx:\n", iobuf, completion->len );
|
|
261
|
+ // DBG_HD ( iobuf, sizeof ( *iobuf ) );
|
|
262
|
+ // DBG_HD ( iobuf->data, 256 );
|
|
263
|
+ if ( completion->syndrome ) {
|
|
264
|
+ netdev_rx_err ( netdev, iobuf, -EIO );
|
|
265
|
+ } else {
|
|
266
|
+ iob_put ( iobuf, completion->len );
|
|
267
|
+ iob_pull ( iobuf, sizeof ( struct ib_global_route_header ) );
|
|
268
|
+ netdev_rx ( netdev, iobuf );
|
|
269
|
+ }
|
|
270
|
+
|
|
271
|
+ mlx->rx_fill--;
|
|
272
|
+}
|
|
273
|
+
|
|
274
|
+#if 0
|
236
|
275
|
/**
|
237
|
276
|
* Poll completion queue
|
238
|
277
|
*
|
|
@@ -267,6 +306,32 @@ static void mlx_poll_cq ( struct net_device *netdev, cq_t cq,
|
267
|
306
|
free_wqe ( ib_cqe.wqe );
|
268
|
307
|
}
|
269
|
308
|
}
|
|
309
|
+#endif
|
|
310
|
+
|
|
311
|
+static int arbel_post_recv ( struct ib_device *ibdev,
|
|
312
|
+ struct ib_queue_pair *qp,
|
|
313
|
+ struct io_buffer *iobuf );
|
|
314
|
+
|
|
315
|
+static void mlx_refill_rx ( struct net_device *netdev ) {
|
|
316
|
+ struct mlx_nic *mlx = netdev->priv;
|
|
317
|
+ struct io_buffer *iobuf;
|
|
318
|
+ int rc;
|
|
319
|
+
|
|
320
|
+ while ( mlx->rx_fill < MLX_RX_MAX_FILL ) {
|
|
321
|
+ iobuf = alloc_iob ( 2048 );
|
|
322
|
+ if ( ! iobuf )
|
|
323
|
+ break;
|
|
324
|
+ DBG ( "Posting RX buffer %p:\n", iobuf );
|
|
325
|
+ // memset ( iobuf->data, 0xaa, 256 );
|
|
326
|
+ // DBG_HD ( iobuf, sizeof ( *iobuf ) );
|
|
327
|
+ if ( ( rc = arbel_post_recv ( &static_ibdev, &static_ipoib_qp,
|
|
328
|
+ iobuf ) ) != 0 ) {
|
|
329
|
+ free_iob ( iobuf );
|
|
330
|
+ break;
|
|
331
|
+ }
|
|
332
|
+ mlx->rx_fill++;
|
|
333
|
+ }
|
|
334
|
+}
|
270
|
335
|
|
271
|
336
|
/**
|
272
|
337
|
* Poll for completed and received packets
|
|
@@ -291,8 +356,13 @@ static void mlx_poll ( struct net_device *netdev ) {
|
291
|
356
|
}
|
292
|
357
|
|
293
|
358
|
/* Poll completion queues */
|
294
|
|
- mlx_poll_cq_direct ( netdev );
|
295
|
|
- mlx_poll_cq ( netdev, mlx->rcv_cqh, mlx_rx_complete );
|
|
359
|
+ arbel_poll_cq ( &static_ibdev, &static_ipoib_send_cq,
|
|
360
|
+ temp_complete_send, temp_complete_recv );
|
|
361
|
+ arbel_poll_cq ( &static_ibdev, &static_ipoib_recv_cq,
|
|
362
|
+ temp_complete_send, temp_complete_recv );
|
|
363
|
+ // mlx_poll_cq ( netdev, mlx->rcv_cqh, mlx_rx_complete );
|
|
364
|
+
|
|
365
|
+ mlx_refill_rx ( netdev );
|
296
|
366
|
}
|
297
|
367
|
|
298
|
368
|
/**
|
|
@@ -397,12 +467,9 @@ static int arbel_post_send ( struct ib_device *ibdev,
|
397
|
467
|
memcpy ( &wqe->ud.u.dwords[4], gid, sizeof ( *gid ) );
|
398
|
468
|
MLX_FILL_1 ( &wqe->ud, 8, destination_qp, av->dest_qp );
|
399
|
469
|
MLX_FILL_1 ( &wqe->ud, 9, q_key, av->qkey );
|
|
470
|
+ MLX_FILL_1 ( &wqe->data[0], 0, byte_count, iob_len ( iobuf ) );
|
400
|
471
|
MLX_FILL_1 ( &wqe->data[0], 3,
|
401
|
472
|
local_address_l, virt_to_bus ( iobuf->data ) );
|
402
|
|
- MLX_FILL_1 ( &wqe->data[0], 0, byte_count, iob_len ( iobuf ) );
|
403
|
|
-
|
404
|
|
- DBG ( "Work queue entry:\n" );
|
405
|
|
- DBG_HD ( wqe, sizeof ( *wqe ) );
|
406
|
473
|
|
407
|
474
|
/* Update previous work queue entry's "next" field */
|
408
|
475
|
nds = ( ( offsetof ( typeof ( *wqe ), data ) +
|
|
@@ -413,16 +480,11 @@ static int arbel_post_send ( struct ib_device *ibdev,
|
413
|
480
|
f, 1,
|
414
|
481
|
always1, 1 );
|
415
|
482
|
|
416
|
|
- DBG ( "Previous work queue entry's next field:\n" );
|
417
|
|
- DBG_HD ( &prev_wqe->next, sizeof ( prev_wqe->next ) );
|
418
|
|
-
|
419
|
483
|
/* Update doorbell record */
|
|
484
|
+ barrier();
|
420
|
485
|
db_rec = &arbel->db_rec[arbel_send_wq->doorbell_idx];
|
421
|
486
|
MLX_FILL_1 ( &db_rec->qp, 0,
|
422
|
487
|
counter, ( ( wq->next_idx + 1 ) & 0xffff ) );
|
423
|
|
- barrier();
|
424
|
|
- DBG ( "Doorbell record:\n" );
|
425
|
|
- DBG_HD ( db_rec, 8 );
|
426
|
488
|
|
427
|
489
|
/* Ring doorbell register */
|
428
|
490
|
MLX_FILL_4 ( &db_reg.send, 0,
|
|
@@ -441,6 +503,51 @@ static int arbel_post_send ( struct ib_device *ibdev,
|
441
|
503
|
return 0;
|
442
|
504
|
}
|
443
|
505
|
|
|
506
|
+/**
|
|
507
|
+ * Post receive work queue entry
|
|
508
|
+ *
|
|
509
|
+ * @v ibdev Infiniband device
|
|
510
|
+ * @v qp Queue pair
|
|
511
|
+ * @v iobuf I/O buffer
|
|
512
|
+ * @ret rc Return status code
|
|
513
|
+ */
|
|
514
|
+static int arbel_post_recv ( struct ib_device *ibdev,
|
|
515
|
+ struct ib_queue_pair *qp,
|
|
516
|
+ struct io_buffer *iobuf ) {
|
|
517
|
+ struct arbel *arbel = ibdev->dev_priv;
|
|
518
|
+ struct ib_work_queue *wq = &qp->recv;
|
|
519
|
+ struct arbel_recv_work_queue *arbel_recv_wq = wq->dev_priv;
|
|
520
|
+ struct arbelprm_recv_wqe *wqe;
|
|
521
|
+ union arbelprm_doorbell_record *db_rec;
|
|
522
|
+ unsigned int wqe_idx_mask;
|
|
523
|
+
|
|
524
|
+ /* Allocate work queue entry */
|
|
525
|
+ wqe_idx_mask = ( wq->num_wqes - 1 );
|
|
526
|
+ if ( wq->iobufs[wq->next_idx & wqe_idx_mask] ) {
|
|
527
|
+ DBGC ( arbel, "Arbel %p receive queue full", arbel );
|
|
528
|
+ return -ENOBUFS;
|
|
529
|
+ }
|
|
530
|
+ wq->iobufs[wq->next_idx & wqe_idx_mask] = iobuf;
|
|
531
|
+ wqe = &arbel_recv_wq->wqe[wq->next_idx & wqe_idx_mask].recv;
|
|
532
|
+
|
|
533
|
+ /* Construct work queue entry */
|
|
534
|
+ MLX_FILL_1 ( &wqe->data[0], 0, byte_count, iob_tailroom ( iobuf ) );
|
|
535
|
+ MLX_FILL_1 ( &wqe->data[0], 1, l_key, arbel->reserved_lkey );
|
|
536
|
+ MLX_FILL_1 ( &wqe->data[0], 3,
|
|
537
|
+ local_address_l, virt_to_bus ( iobuf->data ) );
|
|
538
|
+
|
|
539
|
+ /* Update doorbell record */
|
|
540
|
+ barrier();
|
|
541
|
+ db_rec = &arbel->db_rec[arbel_recv_wq->doorbell_idx];
|
|
542
|
+ MLX_FILL_1 ( &db_rec->qp, 0,
|
|
543
|
+ counter, ( ( wq->next_idx + 1 ) & 0xffff ) );
|
|
544
|
+
|
|
545
|
+ /* Update work queue's index */
|
|
546
|
+ wq->next_idx++;
|
|
547
|
+
|
|
548
|
+ return 0;
|
|
549
|
+}
|
|
550
|
+
|
444
|
551
|
/**
|
445
|
552
|
* Handle completion
|
446
|
553
|
*
|
|
@@ -458,7 +565,6 @@ static int arbel_complete ( struct ib_device *ibdev,
|
458
|
565
|
ib_completer_t complete_recv ) {
|
459
|
566
|
struct arbel *arbel = ibdev->dev_priv;
|
460
|
567
|
struct ib_completion completion;
|
461
|
|
- struct ib_queue_pair *qp;
|
462
|
568
|
struct ib_work_queue *wq;
|
463
|
569
|
struct io_buffer *iobuf;
|
464
|
570
|
struct arbel_send_work_queue *arbel_send_wq;
|
|
@@ -466,7 +572,7 @@ static int arbel_complete ( struct ib_device *ibdev,
|
466
|
572
|
ib_completer_t complete;
|
467
|
573
|
unsigned int opcode;
|
468
|
574
|
unsigned long qpn;
|
469
|
|
- unsigned int is_send;
|
|
575
|
+ int is_send;
|
470
|
576
|
unsigned long wqe_adr;
|
471
|
577
|
unsigned int wqe_idx;
|
472
|
578
|
int rc = 0;
|
|
@@ -489,22 +595,20 @@ static int arbel_complete ( struct ib_device *ibdev,
|
489
|
595
|
/* Don't return immediately; propagate error to completer */
|
490
|
596
|
}
|
491
|
597
|
|
492
|
|
- /* Identify queue pair */
|
493
|
|
- qp = ib_find_qp ( &cq->queue_pairs, qpn );
|
494
|
|
- if ( ! qp ) {
|
495
|
|
- DBGC ( arbel, "Arbel %p CQN %lx unknown QPN %lx\n",
|
496
|
|
- arbel, cq->cqn, qpn );
|
|
598
|
+ /* Identify work queue */
|
|
599
|
+ wq = ib_find_wq ( cq, qpn, is_send );
|
|
600
|
+ if ( ! wq ) {
|
|
601
|
+ DBGC ( arbel, "Arbel %p CQN %lx unknown %s QPN %lx\n",
|
|
602
|
+ arbel, cq->cqn, ( is_send ? "send" : "recv" ), qpn );
|
497
|
603
|
return -EIO;
|
498
|
604
|
}
|
499
|
605
|
|
500
|
606
|
/* Identify work queue entry index */
|
501
|
607
|
if ( is_send ) {
|
502
|
|
- wq = &qp->send;
|
503
|
608
|
arbel_send_wq = wq->dev_priv;
|
504
|
609
|
wqe_idx = ( ( wqe_adr - virt_to_bus ( arbel_send_wq->wqe ) ) /
|
505
|
610
|
sizeof ( arbel_send_wq->wqe[0] ) );
|
506
|
611
|
} else {
|
507
|
|
- wq = &qp->recv;
|
508
|
612
|
arbel_recv_wq = wq->dev_priv;
|
509
|
613
|
wqe_idx = ( ( wqe_adr - virt_to_bus ( arbel_recv_wq->wqe ) ) /
|
510
|
614
|
sizeof ( arbel_recv_wq->wqe[0] ) );
|
|
@@ -521,7 +625,7 @@ static int arbel_complete ( struct ib_device *ibdev,
|
521
|
625
|
|
522
|
626
|
/* Pass off to caller's completion handler */
|
523
|
627
|
complete = ( is_send ? complete_send : complete_recv );
|
524
|
|
- complete ( ibdev, qp, &completion, iobuf );
|
|
628
|
+ complete ( ibdev, wq->qp, &completion, iobuf );
|
525
|
629
|
|
526
|
630
|
return rc;
|
527
|
631
|
}
|
|
@@ -577,6 +681,7 @@ static void arbel_poll_cq ( struct ib_device *ibdev,
|
577
|
681
|
/** Arbel Infiniband operations */
|
578
|
682
|
static struct ib_device_operations arbel_ib_operations = {
|
579
|
683
|
.post_send = arbel_post_send,
|
|
684
|
+ .post_recv = arbel_post_recv,
|
580
|
685
|
.poll_cq = arbel_poll_cq,
|
581
|
686
|
};
|
582
|
687
|
|
|
@@ -636,14 +741,21 @@ static int arbel_probe ( struct pci_device *pci,
|
636
|
741
|
/* Hack up IB structures */
|
637
|
742
|
static_arbel.uar = memfree_pci_dev.uar;
|
638
|
743
|
static_arbel.db_rec = dev_ib_data.uar_context_base;
|
|
744
|
+ static_arbel.reserved_lkey = dev_ib_data.mkey;
|
639
|
745
|
static_arbel_ipoib_send_wq.wqe =
|
640
|
746
|
( ( struct udqp_st * ) qph )->snd_wq;
|
|
747
|
+ static_arbel_ipoib_recv_wq.wqe =
|
|
748
|
+ ( ( struct udqp_st * ) qph )->rcv_wq;
|
641
|
749
|
static_arbel_ipoib_send_cq.cqe =
|
642
|
750
|
( ( struct cq_st * ) ib_data.ipoib_snd_cq )->cq_buf;
|
|
751
|
+ static_arbel_ipoib_recv_cq.cqe =
|
|
752
|
+ ( ( struct cq_st * ) ib_data.ipoib_rcv_cq )->cq_buf;
|
643
|
753
|
static_ipoib_qp.qpn = ib_get_qpn ( qph );
|
644
|
754
|
static_ipoib_qp.priv = netdev;
|
645
|
|
- list_add ( &static_ipoib_qp.list,
|
646
|
|
- &static_ipoib_send_cq.queue_pairs );
|
|
755
|
+ list_add ( &static_ipoib_qp.send.list,
|
|
756
|
+ &static_ipoib_send_cq.work_queues );
|
|
757
|
+ list_add ( &static_ipoib_qp.recv.list,
|
|
758
|
+ &static_ipoib_recv_cq.work_queues );
|
647
|
759
|
|
648
|
760
|
/* Register network device */
|
649
|
761
|
if ( ( rc = register_netdev ( netdev ) ) != 0 )
|