[golan] Add Connect-IB, ConnectX-4 and ConnectX-4 Lx (Infiniband) support
[ipxe.git] / src / drivers / infiniband / flexboot_nodnic.c
1 /*
2 * Copyright (C) 2015 Mellanox Technologies Ltd.
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., 51 Franklin Street, Fifth Floor, Boston, MA
17 * 02110-1301, USA.
18 */
19
20 FILE_LICENCE ( GPL2_OR_LATER );
21
22 #include <stdio.h>
23 #include <unistd.h>
24 #include <errno.h>
25 #include <byteswap.h>
26 #include <ipxe/pci.h>
27 #include <ipxe/malloc.h>
28 #include <ipxe/umalloc.h>
29 #include <ipxe/if_ether.h>
30 #include <ipxe/ethernet.h>
31 #include <ipxe/vlan.h>
32 #include <ipxe/io.h>
33 #include "flexboot_nodnic.h"
34 #include "mlx_utils/mlx_lib/mlx_nvconfig/mlx_nvconfig.h"
35 #include "mlx_utils/mlx_lib/mlx_nvconfig/mlx_nvconfig_defaults.h"
36 #include "mlx_utils/include/public/mlx_pci_gw.h"
37 #include "mlx_utils/mlx_lib/mlx_vmac/mlx_vmac.h"
38 #include "mlx_utils/include/public/mlx_types.h"
39 #include "mlx_utils/include/public/mlx_utils.h"
40 #include "mlx_utils/include/public/mlx_bail.h"
41 #include "mlx_nodnic/include/mlx_cmd.h"
42 #include "mlx_utils/include/public/mlx_memory.h"
43 #include "mlx_utils/include/public/mlx_pci.h"
44 #include "mlx_nodnic/include/mlx_device.h"
45 #include "mlx_nodnic/include/mlx_port.h"
46
47 /***************************************************************************
48 *
49 * Completion queue operations
50 *
51 ***************************************************************************
52 */
53 static int flexboot_nodnic_arm_cq ( struct flexboot_nodnic_port *port ) {
54 #ifndef DEVICE_CX3
55 mlx_uint32 val = ( port->eth_cq->next_idx & 0xffff );
56 if ( nodnic_port_set ( & port->port_priv, nodnic_port_option_arm_cq, val ) ) {
57 MLX_DEBUG_ERROR( port->port_priv.device, "Failed to arm the CQ\n" );
58 return MLX_FAILED;
59 }
60 #else
61 mlx_utils *utils = port->port_priv.device->utils;
62 nodnic_port_data_flow_gw *ptr = port->port_priv.data_flow_gw;
63 mlx_uint32 data = 0;
64 mlx_uint32 val = 0;
65
66 if ( port->port_priv.device->device_cap.crspace_doorbells == 0 ) {
67 val = ( port->eth_cq->next_idx & 0xffff );
68 if ( nodnic_port_set ( & port->port_priv, nodnic_port_option_arm_cq, val ) ) {
69 MLX_DEBUG_ERROR( port->port_priv.device, "Failed to arm the CQ\n" );
70 return MLX_FAILED;
71 }
72 } else {
73 /* Arming the CQ with CQ CI should be with this format -
74 * 16 bit - CQ CI - same endianness as the FW (don't swap bytes)
75 * 15 bit - reserved
76 * 1 bit - arm CQ - must correct the endianness with the reserved above */
77 data = ( ( ( port->eth_cq->next_idx & 0xffff ) << 16 ) | 0x0080 );
78 /* Write the new index and update FW that new data was submitted */
79 mlx_pci_mem_write ( utils, MlxPciWidthUint32, 0,
80 ( mlx_uint64 ) & ( ptr->armcq_cq_ci_dword ), 1, &data );
81 }
82 #endif
83 return 0;
84 }
85
86 /**
87 * Create completion queue
88 *
89 * @v ibdev Infiniband device
90 * @v cq Completion queue
91 * @ret rc Return status code
92 */
93 static int flexboot_nodnic_create_cq ( struct ib_device *ibdev ,
94 struct ib_completion_queue *cq ) {
95 struct flexboot_nodnic *flexboot_nodnic = ib_get_drvdata ( ibdev );
96 struct flexboot_nodnic_port *port = &flexboot_nodnic->port[ibdev->port - 1];
97 struct flexboot_nodnic_completion_queue *flexboot_nodnic_cq;
98 mlx_status status = MLX_SUCCESS;
99
100 flexboot_nodnic_cq = (struct flexboot_nodnic_completion_queue *)
101 zalloc(sizeof(*flexboot_nodnic_cq));
102 if ( flexboot_nodnic_cq == NULL ) {
103 status = MLX_OUT_OF_RESOURCES;
104 goto qp_alloc_err;
105 }
106
107 status = nodnic_port_create_cq(&port->port_priv,
108 cq->num_cqes *
109 flexboot_nodnic->callbacks->get_cqe_size(),
110 &flexboot_nodnic_cq->nodnic_completion_queue
111 );
112 MLX_FATAL_CHECK_STATUS(status, create_err,
113 "nodnic_port_create_cq failed");
114 flexboot_nodnic->callbacks->cqe_set_owner(
115 flexboot_nodnic_cq->nodnic_completion_queue->cq_virt,
116 cq->num_cqes);
117
118
119 ib_cq_set_drvdata ( cq, flexboot_nodnic_cq );
120 return status;
121 create_err:
122 free(flexboot_nodnic_cq);
123 qp_alloc_err:
124 return status;
125 }
126
127 /**
128 * Destroy completion queue
129 *
130 * @v ibdev Infiniband device
131 * @v cq Completion queue
132 */
133 static void flexboot_nodnic_destroy_cq ( struct ib_device *ibdev ,
134 struct ib_completion_queue *cq ) {
135 struct flexboot_nodnic *flexboot_nodnic = ib_get_drvdata ( ibdev );
136 struct flexboot_nodnic_port *port = &flexboot_nodnic->port[ibdev->port - 1];
137 struct flexboot_nodnic_completion_queue *flexboot_nodnic_cq = ib_cq_get_drvdata ( cq );
138
139 nodnic_port_destroy_cq(&port->port_priv,
140 flexboot_nodnic_cq->nodnic_completion_queue);
141
142 free(flexboot_nodnic_cq);
143 }
144
145 static
146 struct ib_work_queue * flexboot_nodnic_find_wq ( struct ib_device *ibdev ,
147 struct ib_completion_queue *cq,
148 unsigned long qpn, int is_send ) {
149 struct ib_work_queue *wq;
150 struct flexboot_nodnic_queue_pair *flexboot_nodnic_qp;
151 struct flexboot_nodnic *flexboot_nodnic = ib_get_drvdata ( ibdev );
152 struct flexboot_nodnic_port *port = &flexboot_nodnic->port[ibdev->port - 1];
153 struct nodnic_ring *ring;
154 mlx_uint32 out_qpn;
155 list_for_each_entry ( wq, &cq->work_queues, list ) {
156 flexboot_nodnic_qp = ib_qp_get_drvdata ( wq->qp );
157 if( wq->is_send == is_send && wq->is_send == TRUE ) {
158 ring = &flexboot_nodnic_qp->nodnic_queue_pair->send.nodnic_ring;
159 } else if( wq->is_send == is_send && wq->is_send == FALSE ) {
160 ring = &flexboot_nodnic_qp->nodnic_queue_pair->receive.nodnic_ring;
161 } else {
162 continue;
163 }
164 nodnic_port_get_qpn(&port->port_priv, ring, &out_qpn);
165 if ( out_qpn == qpn )
166 return wq;
167 }
168 return NULL;
169 }
170
171 /**
172 * Handle completion
173 *
174 * @v ibdev Infiniband device
175 * @v cq Completion queue
176 * @v cqe Hardware completion queue entry
177 * @ret rc Return status code
178 */
179 static int flexboot_nodnic_complete ( struct ib_device *ibdev,
180 struct ib_completion_queue *cq,
181 struct cqe_data *cqe_data ) {
182 struct flexboot_nodnic *flexboot_nodnic = ib_get_drvdata ( ibdev );
183 struct ib_work_queue *wq;
184 struct ib_queue_pair *qp;
185 struct io_buffer *iobuf;
186 struct ib_address_vector recv_dest;
187 struct ib_address_vector recv_source;
188 unsigned long qpn;
189 unsigned long wqe_idx;
190 unsigned long wqe_idx_mask;
191 size_t len;
192 int rc = 0;
193
194 /* Parse completion */
195 qpn = cqe_data->qpn;
196
197 if ( cqe_data->is_error == TRUE ) {
198 DBGC ( flexboot_nodnic, "flexboot_nodnic %p CQN %#lx syndrome %x vendor %x\n",
199 flexboot_nodnic, cq->cqn, cqe_data->syndrome,
200 cqe_data->vendor_err_syndrome );
201 rc = -EIO;
202 /* Don't return immediately; propagate error to completer */
203 }
204
205 /* Identify work queue */
206 wq = flexboot_nodnic_find_wq( ibdev, cq, qpn, cqe_data->is_send );
207 if ( wq == NULL ) {
208 DBGC ( flexboot_nodnic,
209 "flexboot_nodnic %p CQN %#lx unknown %s QPN %#lx\n",
210 flexboot_nodnic, cq->cqn,
211 ( cqe_data->is_send ? "send" : "recv" ), qpn );
212 return -EIO;
213 }
214 qp = wq->qp;
215
216 /* Identify work queue entry */
217 wqe_idx = cqe_data->wqe_counter;
218 wqe_idx_mask = ( wq->num_wqes - 1 );
219 DBGCP ( flexboot_nodnic,
220 "NODNIC %p CQN %#lx QPN %#lx %s WQE %#lx completed:\n",
221 flexboot_nodnic, cq->cqn, qp->qpn,
222 ( cqe_data->is_send ? "send" : "recv" ),
223 wqe_idx );
224
225 /* Identify I/O buffer */
226 iobuf = wq->iobufs[wqe_idx & wqe_idx_mask];
227 if ( iobuf == NULL ) {
228 DBGC ( flexboot_nodnic,
229 "NODNIC %p CQN %#lx QPN %#lx empty %s WQE %#lx\n",
230 flexboot_nodnic, cq->cqn, qp->qpn,
231 ( cqe_data->is_send ? "send" : "recv" ), wqe_idx );
232 return -EIO;
233 }
234 wq->iobufs[wqe_idx & wqe_idx_mask] = NULL;
235
236 if ( cqe_data->is_send == TRUE ) {
237 /* Hand off to completion handler */
238 ib_complete_send ( ibdev, qp, iobuf, rc );
239 } else if ( rc != 0 ) {
240 /* Propagate error to receive completion handler */
241 ib_complete_recv ( ibdev, qp, NULL, NULL, iobuf, rc );
242 } else {
243 /* Set received length */
244 len = cqe_data->byte_cnt;
245 assert ( len <= iob_tailroom ( iobuf ) );
246 iob_put ( iobuf, len );
247 memset ( &recv_dest, 0, sizeof ( recv_dest ) );
248 recv_dest.qpn = qpn;
249 memset ( &recv_source, 0, sizeof ( recv_source ) );
250 switch ( qp->type ) {
251 case IB_QPT_SMI:
252 case IB_QPT_GSI:
253 case IB_QPT_UD:
254 case IB_QPT_RC:
255 break;
256 case IB_QPT_ETH:
257 break;
258 default:
259 assert ( 0 );
260 return -EINVAL;
261 }
262 /* Hand off to completion handler */
263 ib_complete_recv ( ibdev, qp, &recv_dest,
264 &recv_source, iobuf, rc );
265 }
266
267 return rc;
268 }
269 /**
270 * Poll completion queue
271 *
272 * @v ibdev Infiniband device
273 * @v cq Completion queues
274 */
275 static void flexboot_nodnic_poll_cq ( struct ib_device *ibdev,
276 struct ib_completion_queue *cq) {
277 struct flexboot_nodnic *flexboot_nodnic = ib_get_drvdata ( ibdev );
278 struct flexboot_nodnic_completion_queue *flexboot_nodnic_cq = ib_cq_get_drvdata ( cq );
279 void *cqe;
280 mlx_size cqe_size;
281 struct cqe_data cqe_data;
282 unsigned int cqe_idx_mask;
283 int rc;
284
285 cqe_size = flexboot_nodnic->callbacks->get_cqe_size();
286 while ( TRUE ) {
287 /* Look for completion entry */
288 cqe_idx_mask = ( cq->num_cqes - 1 );
289 cqe = ((uint8_t *)flexboot_nodnic_cq->nodnic_completion_queue->cq_virt) +
290 cqe_size * (cq->next_idx & cqe_idx_mask);
291
292 /* TODO: check fill_completion */
293 flexboot_nodnic->callbacks->fill_completion(cqe, &cqe_data);
294 if ( cqe_data.owner ^
295 ( ( cq->next_idx & cq->num_cqes ) ? 1 : 0 ) ) {
296 /* Entry still owned by hardware; end of poll */
297 break;
298 }
299 /* Handle completion */
300 rc = flexboot_nodnic_complete ( ibdev, cq, &cqe_data );
301 if ( rc != 0 ) {
302 DBGC ( flexboot_nodnic, "flexboot_nodnic %p CQN %#lx failed to complete: %s\n",
303 flexboot_nodnic, cq->cqn, strerror ( rc ) );
304 DBGC_HDA ( flexboot_nodnic, virt_to_phys ( cqe ),
305 cqe, sizeof ( *cqe ) );
306 }
307
308 /* Update completion queue's index */
309 cq->next_idx++;
310 }
311 }
312 /***************************************************************************
313 *
314 * Queue pair operations
315 *
316 ***************************************************************************
317 */
318
319
320 /**
321 * Create queue pair
322 *
323 * @v ibdev Infiniband device
324 * @v qp Queue pair
325 * @ret rc Return status code
326 */
327 static int flexboot_nodnic_create_qp ( struct ib_device *ibdev,
328 struct ib_queue_pair *qp ) {
329 struct flexboot_nodnic *flexboot_nodnic = ib_get_drvdata ( ibdev );
330 struct flexboot_nodnic_port *port = &flexboot_nodnic->port[ibdev->port - 1];
331 struct flexboot_nodnic_queue_pair *flexboot_nodnic_qp;
332 mlx_status status = MLX_SUCCESS;
333
334 flexboot_nodnic_qp = (struct flexboot_nodnic_queue_pair *)zalloc(sizeof(*flexboot_nodnic_qp));
335 if ( flexboot_nodnic_qp == NULL ) {
336 status = MLX_OUT_OF_RESOURCES;
337 goto qp_alloc_err;
338 }
339
340 status = nodnic_port_create_qp(&port->port_priv, qp->type,
341 qp->send.num_wqes * sizeof(struct nodnic_send_wqbb),
342 qp->send.num_wqes,
343 qp->recv.num_wqes * sizeof(struct nodnic_recv_wqe),
344 qp->recv.num_wqes,
345 &flexboot_nodnic_qp->nodnic_queue_pair);
346 MLX_FATAL_CHECK_STATUS(status, create_err,
347 "nodnic_port_create_qp failed");
348 ib_qp_set_drvdata ( qp, flexboot_nodnic_qp );
349 return status;
350 create_err:
351 free(flexboot_nodnic_qp);
352 qp_alloc_err:
353 return status;
354 }
355
356 /**
357 * Modify queue pair
358 *
359 * @v ibdev Infiniband device
360 * @v qp Queue pair
361 * @ret rc Return status code
362 */
363 static int flexboot_nodnic_modify_qp ( struct ib_device *ibdev __unused,
364 struct ib_queue_pair *qp __unused) {
365 /*not needed*/
366 return 0;
367 }
368
369 /**
370 * Destroy queue pair
371 *
372 * @v ibdev Infiniband device
373 * @v qp Queue pair
374 */
375 static void flexboot_nodnic_destroy_qp ( struct ib_device *ibdev,
376 struct ib_queue_pair *qp ) {
377 struct flexboot_nodnic *flexboot_nodnic = ib_get_drvdata ( ibdev );
378 struct flexboot_nodnic_port *port = &flexboot_nodnic->port[ibdev->port - 1];
379 struct flexboot_nodnic_queue_pair *flexboot_nodnic_qp = ib_qp_get_drvdata ( qp );
380
381 nodnic_port_destroy_qp(&port->port_priv, qp->type,
382 flexboot_nodnic_qp->nodnic_queue_pair);
383
384 free(flexboot_nodnic_qp);
385 }
386
387 /***************************************************************************
388 *
389 * Work request operations
390 *
391 ***************************************************************************
392 */
393
394 /**
395 * Post send work queue entry
396 *
397 * @v ibdev Infiniband device
398 * @v qp Queue pair
399 * @v av Address vector
400 * @v iobuf I/O buffer
401 * @ret rc Return status code
402 */
403 static int flexboot_nodnic_post_send ( struct ib_device *ibdev,
404 struct ib_queue_pair *qp,
405 struct ib_address_vector *av,
406 struct io_buffer *iobuf) {
407
408 struct flexboot_nodnic *flexboot_nodnic = ib_get_drvdata ( ibdev );
409 struct flexboot_nodnic_queue_pair *flexboot_nodnic_qp = ib_qp_get_drvdata ( qp );
410 struct flexboot_nodnic_port *port = &flexboot_nodnic->port[ibdev->port - 1];
411 struct ib_work_queue *wq = &qp->send;
412 struct nodnic_send_wqbb *wqbb;
413 nodnic_qp *nodnic_qp = flexboot_nodnic_qp->nodnic_queue_pair;
414 struct nodnic_send_ring *send_ring = &nodnic_qp->send;
415 mlx_status status = MLX_SUCCESS;
416 unsigned int wqe_idx_mask;
417 unsigned long wqe_idx;
418
419 if ( ( port->port_priv.dma_state == FALSE ) ||
420 ( port->port_priv.port_state & NODNIC_PORT_DISABLING_DMA ) ) {
421 DBGC ( flexboot_nodnic, "flexboot_nodnic DMA disabled\n");
422 status = -ENETDOWN;
423 goto post_send_done;
424 }
425
426 /* Allocate work queue entry */
427 wqe_idx = wq->next_idx;
428 wqe_idx_mask = ( wq->num_wqes - 1 );
429 if ( wq->iobufs[wqe_idx & wqe_idx_mask] ) {
430 DBGC ( flexboot_nodnic, "flexboot_nodnic %p QPN %#lx send queue full\n",
431 flexboot_nodnic, qp->qpn );
432 status = -ENOBUFS;
433 goto post_send_done;
434 }
435 wqbb = &send_ring->wqe_virt[wqe_idx & wqe_idx_mask];
436 wq->iobufs[wqe_idx & wqe_idx_mask] = iobuf;
437
438 assert ( flexboot_nodnic->callbacks->
439 fill_send_wqe[qp->type] != NULL );
440 status = flexboot_nodnic->callbacks->
441 fill_send_wqe[qp->type] ( ibdev, qp, av, iobuf,
442 wqbb, wqe_idx );
443 if ( status != 0 ) {
444 DBGC ( flexboot_nodnic, "flexboot_nodnic %p QPN %#lx fill send wqe failed\n",
445 flexboot_nodnic, qp->qpn );
446 goto post_send_done;
447 }
448
449 wq->next_idx++;
450
451 status = port->port_priv.send_doorbell ( &port->port_priv,
452 &send_ring->nodnic_ring, ( mlx_uint16 ) wq->next_idx );
453 if ( status != 0 ) {
454 DBGC ( flexboot_nodnic, "flexboot_nodnic %p ring send doorbell failed\n", flexboot_nodnic );
455 }
456
457 post_send_done:
458 return status;
459 }
460
461 /**
462 * Post receive work queue entry
463 *
464 * @v ibdev Infiniband device
465 * @v qp Queue pair
466 * @v iobuf I/O buffer
467 * @ret rc Return status code
468 */
469 static int flexboot_nodnic_post_recv ( struct ib_device *ibdev,
470 struct ib_queue_pair *qp,
471 struct io_buffer *iobuf ) {
472 struct flexboot_nodnic *flexboot_nodnic = ib_get_drvdata ( ibdev );
473 struct flexboot_nodnic_queue_pair *flexboot_nodnic_qp = ib_qp_get_drvdata ( qp );
474 struct flexboot_nodnic_port *port = &flexboot_nodnic->port[ibdev->port - 1];
475 struct ib_work_queue *wq = &qp->recv;
476 nodnic_qp *nodnic_qp = flexboot_nodnic_qp->nodnic_queue_pair;
477 struct nodnic_recv_ring *recv_ring = &nodnic_qp->receive;
478 struct nodnic_recv_wqe *wqe;
479 unsigned int wqe_idx_mask;
480 mlx_status status = MLX_SUCCESS;
481
482 /* Allocate work queue entry */
483 wqe_idx_mask = ( wq->num_wqes - 1 );
484 if ( wq->iobufs[wq->next_idx & wqe_idx_mask] ) {
485 DBGC ( flexboot_nodnic,
486 "flexboot_nodnic %p QPN %#lx receive queue full\n",
487 flexboot_nodnic, qp->qpn );
488 status = -ENOBUFS;
489 goto post_recv_done;
490 }
491 wq->iobufs[wq->next_idx & wqe_idx_mask] = iobuf;
492 wqe = &((struct nodnic_recv_wqe*)recv_ring->wqe_virt)[wq->next_idx & wqe_idx_mask];
493
494 MLX_FILL_1 ( &wqe->data[0], 0, byte_count, iob_tailroom ( iobuf ) );
495 MLX_FILL_1 ( &wqe->data[0], 1, l_key, flexboot_nodnic->device_priv.lkey );
496 MLX_FILL_H ( &wqe->data[0], 2,
497 local_address_h, virt_to_bus ( iobuf->data ) );
498 MLX_FILL_1 ( &wqe->data[0], 3,
499 local_address_l, virt_to_bus ( iobuf->data ) );
500
501 wq->next_idx++;
502
503 status = port->port_priv.recv_doorbell ( &port->port_priv,
504 &recv_ring->nodnic_ring, ( mlx_uint16 ) wq->next_idx );
505 if ( status != 0 ) {
506 DBGC ( flexboot_nodnic, "flexboot_nodnic %p ring receive doorbell failed\n", flexboot_nodnic );
507 }
508 post_recv_done:
509 return status;
510 }
511
512 /***************************************************************************
513 *
514 * Event queues
515 *
516 ***************************************************************************
517 */
518
519 static void flexboot_nodnic_poll_eq ( struct ib_device *ibdev ) {
520 struct flexboot_nodnic *flexboot_nodnic;
521 struct flexboot_nodnic_port *port;
522 struct net_device *netdev;
523 nodnic_port_state state = 0;
524 mlx_status status;
525
526 if ( ! ibdev ) {
527 DBG ( "%s: ibdev = NULL!!!\n", __FUNCTION__ );
528 return;
529 }
530
531 flexboot_nodnic = ib_get_drvdata ( ibdev );
532 port = &flexboot_nodnic->port[ibdev->port - 1];
533 netdev = port->netdev;
534
535 if ( ! netdev_is_open ( netdev ) ) {
536 DBG2( "%s: port %d is closed\n", __FUNCTION__, port->ibdev->port );
537 return;
538 }
539
540 /* we don't poll EQ. Just poll link status if it's not active */
541 if ( ! netdev_link_ok ( netdev ) ) {
542 status = nodnic_port_get_state ( &port->port_priv, &state );
543 MLX_FATAL_CHECK_STATUS(status, state_err, "nodnic_port_get_state failed");
544
545 if ( state == nodnic_port_state_active ) {
546 DBG( "%s: port %d physical link is up\n", __FUNCTION__,
547 port->ibdev->port );
548 port->type->state_change ( flexboot_nodnic, port, 1 );
549 }
550 }
551 state_err:
552 return;
553 }
554
555 /***************************************************************************
556 *
557 * Multicast group operations
558 *
559 ***************************************************************************
560 */
561 static int flexboot_nodnic_mcast_attach ( struct ib_device *ibdev,
562 struct ib_queue_pair *qp,
563 union ib_gid *gid) {
564 struct flexboot_nodnic *flexboot_nodnic = ib_get_drvdata ( ibdev );
565 struct flexboot_nodnic_port *port = &flexboot_nodnic->port[ibdev->port - 1];
566 mlx_mac_address mac;
567 mlx_status status = MLX_SUCCESS;
568
569 switch (qp->type) {
570 case IB_QPT_ETH:
571 memcpy(&mac, &gid, sizeof(mac));
572 status = nodnic_port_add_mac_filter(&port->port_priv, mac);
573 MLX_CHECK_STATUS(flexboot_nodnic->device_priv, status, mac_err,
574 "nodnic_port_add_mac_filter failed");
575 break;
576 default:
577 break;
578 }
579 mac_err:
580 return status;
581 }
582 static void flexboot_nodnic_mcast_detach ( struct ib_device *ibdev,
583 struct ib_queue_pair *qp,
584 union ib_gid *gid ) {
585 struct flexboot_nodnic *flexboot_nodnic = ib_get_drvdata ( ibdev );
586 struct flexboot_nodnic_port *port = &flexboot_nodnic->port[ibdev->port - 1];
587 mlx_mac_address mac;
588 mlx_status status = MLX_SUCCESS;
589
590 switch (qp->type) {
591 case IB_QPT_ETH:
592 memcpy(&mac, &gid, sizeof(mac));
593 status = nodnic_port_remove_mac_filter(&port->port_priv, mac);
594 MLX_CHECK_STATUS(flexboot_nodnic->device_priv, status, mac_err,
595 "nodnic_port_remove_mac_filter failed");
596 break;
597 default:
598 break;
599 }
600 mac_err:
601 return;
602 }
603 /***************************************************************************
604 *
605 * Infiniband link-layer operations
606 *
607 ***************************************************************************
608 */
609
610 /**
611 * Initialise Infiniband link
612 *
613 * @v ibdev Infiniband device
614 * @ret rc Return status code
615 */
616 static int flexboot_nodnic_ib_open ( struct ib_device *ibdev __unused) {
617 int rc = 0;
618
619 /*TODO: add implementation*/
620 return rc;
621 }
622
623 /**
624 * Close Infiniband link
625 *
626 * @v ibdev Infiniband device
627 */
628 static void flexboot_nodnic_ib_close ( struct ib_device *ibdev __unused) {
629 /*TODO: add implementation*/
630 }
631
632 /**
633 * Inform embedded subnet management agent of a received MAD
634 *
635 * @v ibdev Infiniband device
636 * @v mad MAD
637 * @ret rc Return status code
638 */
639 static int flexboot_nodnic_inform_sma ( struct ib_device *ibdev __unused,
640 union ib_mad *mad __unused) {
641 /*TODO: add implementation*/
642 return 0;
643 }
644
645 /** flexboot_nodnic Infiniband operations */
646 static struct ib_device_operations flexboot_nodnic_ib_operations = {
647 .create_cq = flexboot_nodnic_create_cq,
648 .destroy_cq = flexboot_nodnic_destroy_cq,
649 .create_qp = flexboot_nodnic_create_qp,
650 .modify_qp = flexboot_nodnic_modify_qp,
651 .destroy_qp = flexboot_nodnic_destroy_qp,
652 .post_send = flexboot_nodnic_post_send,
653 .post_recv = flexboot_nodnic_post_recv,
654 .poll_cq = flexboot_nodnic_poll_cq,
655 .poll_eq = flexboot_nodnic_poll_eq,
656 .open = flexboot_nodnic_ib_open,
657 .close = flexboot_nodnic_ib_close,
658 .mcast_attach = flexboot_nodnic_mcast_attach,
659 .mcast_detach = flexboot_nodnic_mcast_detach,
660 .set_port_info = flexboot_nodnic_inform_sma,
661 .set_pkey_table = flexboot_nodnic_inform_sma,
662 };
663 /***************************************************************************
664 *
665 *
666 *
667 ***************************************************************************
668 */
669
670 #define FLEX_NODNIC_TX_POLL_TOUT 500000
671 #define FLEX_NODNIC_TX_POLL_USLEEP 10
672
673 static void flexboot_nodnic_complete_all_tx ( struct flexboot_nodnic_port *port ) {
674 struct ib_device *ibdev = port->ibdev;
675 struct ib_completion_queue *cq;
676 struct ib_work_queue *wq;
677 int keep_polling = 0;
678 int timeout = FLEX_NODNIC_TX_POLL_TOUT;
679
680 list_for_each_entry ( cq, &ibdev->cqs, list ) {
681 do {
682 ib_poll_cq ( ibdev, cq );
683 keep_polling = 0;
684 list_for_each_entry ( wq, &cq->work_queues, list ) {
685 if ( wq->is_send )
686 keep_polling += ( wq->fill > 0 );
687 }
688 udelay ( FLEX_NODNIC_TX_POLL_USLEEP );
689 } while ( keep_polling && ( timeout-- > 0 ) );
690 }
691 }
692
693 static void flexboot_nodnic_port_disable_dma ( struct flexboot_nodnic_port *port ) {
694 nodnic_port_priv *port_priv = & ( port->port_priv );
695 mlx_status status;
696
697 if ( ! ( port_priv->port_state & NODNIC_PORT_OPENED ) )
698 return;
699
700 port_priv->port_state |= NODNIC_PORT_DISABLING_DMA;
701 flexboot_nodnic_complete_all_tx ( port );
702 if ( ( status = nodnic_port_disable_dma ( port_priv ) ) ) {
703 MLX_DEBUG_WARN ( port, "Failed to disable DMA %d\n", status );
704 }
705
706 port_priv->port_state &= ~NODNIC_PORT_DISABLING_DMA;
707 }
708
709 /***************************************************************************
710 *
711 * Ethernet operation
712 *
713 ***************************************************************************
714 */
715
716 /** Number of flexboot_nodnic Ethernet send work queue entries */
717 #define FLEXBOOT_NODNIC_ETH_NUM_SEND_WQES 64
718
719 /** Number of flexboot_nodnic Ethernet receive work queue entries */
720 #define FLEXBOOT_NODNIC_ETH_NUM_RECV_WQES 64
721 /** flexboot nodnic Ethernet queue pair operations */
722 static struct ib_queue_pair_operations flexboot_nodnic_eth_qp_op = {
723 .alloc_iob = alloc_iob,
724 };
725
726 /**
727 * Transmit packet via flexboot_nodnic Ethernet device
728 *
729 * @v netdev Network device
730 * @v iobuf I/O buffer
731 * @ret rc Return status code
732 */
733 static int flexboot_nodnic_eth_transmit ( struct net_device *netdev,
734 struct io_buffer *iobuf) {
735 struct flexboot_nodnic_port *port = netdev->priv;
736 struct ib_device *ibdev = port->ibdev;
737 struct flexboot_nodnic *flexboot_nodnic = ib_get_drvdata ( ibdev );
738 int rc;
739
740 rc = ib_post_send ( ibdev, port->eth_qp, NULL, iobuf);
741 /* Transmit packet */
742 if ( rc != 0) {
743 DBGC ( flexboot_nodnic, "NODNIC %p port %d could not transmit: %s\n",
744 flexboot_nodnic, ibdev->port, strerror ( rc ) );
745 return rc;
746 }
747
748 return 0;
749 }
750
751 /**
752 * Handle flexboot_nodnic Ethernet device send completion
753 *
754 * @v ibdev Infiniband device
755 * @v qp Queue pair
756 * @v iobuf I/O buffer
757 * @v rc Completion status code
758 */
759 static void flexboot_nodnic_eth_complete_send ( struct ib_device *ibdev __unused,
760 struct ib_queue_pair *qp,
761 struct io_buffer *iobuf,
762 int rc) {
763 struct net_device *netdev = ib_qp_get_ownerdata ( qp );
764
765 netdev_tx_complete_err ( netdev, iobuf, rc );
766 }
767
768 /**
769 * Handle flexboot_nodnic Ethernet device receive completion
770 *
771 * @v ibdev Infiniband device
772 * @v qp Queue pair
773 * @v av Address vector, or NULL
774 * @v iobuf I/O buffer
775 * @v rc Completion status code
776 */
777 static void flexboot_nodnic_eth_complete_recv ( struct ib_device *ibdev __unused,
778 struct ib_queue_pair *qp,
779 struct ib_address_vector *dest __unused,
780 struct ib_address_vector *source,
781 struct io_buffer *iobuf,
782 int rc) {
783 struct net_device *netdev = ib_qp_get_ownerdata ( qp );
784
785 if ( rc != 0 ) {
786 DBG ( "Received packet with error\n" );
787 netdev_rx_err ( netdev, iobuf, rc );
788 return;
789 }
790
791 if ( source == NULL ) {
792 DBG ( "Received packet without address vector\n" );
793 netdev_rx_err ( netdev, iobuf, -ENOTTY );
794 return;
795 }
796 netdev_rx ( netdev, iobuf );
797 }
798
799 /** flexboot_nodnic Ethernet device completion operations */
800 static struct ib_completion_queue_operations flexboot_nodnic_eth_cq_op = {
801 .complete_send = flexboot_nodnic_eth_complete_send,
802 .complete_recv = flexboot_nodnic_eth_complete_recv,
803 };
804
805 /**
806 * Poll flexboot_nodnic Ethernet device
807 *
808 * @v netdev Network device
809 */
810 static void flexboot_nodnic_eth_poll ( struct net_device *netdev) {
811 struct flexboot_nodnic_port *port = netdev->priv;
812 struct ib_device *ibdev = port->ibdev;
813
814 ib_poll_eq ( ibdev );
815 }
816
817 /**
818 * Open flexboot_nodnic Ethernet device
819 *
820 * @v netdev Network device
821 * @ret rc Return status code
822 */
823 static int flexboot_nodnic_eth_open ( struct net_device *netdev ) {
824 struct flexboot_nodnic_port *port = netdev->priv;
825 struct ib_device *ibdev = port->ibdev;
826 struct flexboot_nodnic *flexboot_nodnic = ib_get_drvdata ( ibdev );
827 mlx_status status = MLX_SUCCESS;
828 struct ib_completion_queue *dummy_cq = NULL;
829 struct flexboot_nodnic_queue_pair *flexboot_nodnic_qp = NULL;
830 mlx_uint64 cq_size = 0;
831 mlx_uint32 qpn = 0;
832 nodnic_port_state state = nodnic_port_state_down;
833
834 if ( port->port_priv.port_state & NODNIC_PORT_OPENED ) {
835 DBGC ( flexboot_nodnic, "%s: port %d is already opened\n",
836 __FUNCTION__, port->ibdev->port );
837 return 0;
838 }
839
840 port->port_priv.port_state |= NODNIC_PORT_OPENED;
841
842 dummy_cq = zalloc ( sizeof ( struct ib_completion_queue ) );
843 if ( dummy_cq == NULL ) {
844 DBGC ( flexboot_nodnic, "%s: Failed to allocate dummy CQ\n", __FUNCTION__ );
845 status = MLX_OUT_OF_RESOURCES;
846 goto err_create_dummy_cq;
847 }
848 INIT_LIST_HEAD ( &dummy_cq->work_queues );
849
850 port->eth_qp = ib_create_qp ( ibdev, IB_QPT_ETH,
851 FLEXBOOT_NODNIC_ETH_NUM_SEND_WQES, dummy_cq,
852 FLEXBOOT_NODNIC_ETH_NUM_RECV_WQES, dummy_cq,
853 &flexboot_nodnic_eth_qp_op, netdev->name );
854 if ( !port->eth_qp ) {
855 DBGC ( flexboot_nodnic, "flexboot_nodnic %p port %d could not create queue pair\n",
856 flexboot_nodnic, ibdev->port );
857 status = MLX_OUT_OF_RESOURCES;
858 goto err_create_qp;
859 }
860
861 ib_qp_set_ownerdata ( port->eth_qp, netdev );
862
863 status = nodnic_port_get_cq_size(&port->port_priv, &cq_size);
864 MLX_FATAL_CHECK_STATUS(status, get_cq_size_err,
865 "nodnic_port_get_cq_size failed");
866
867 port->eth_cq = ib_create_cq ( ibdev, cq_size,
868 &flexboot_nodnic_eth_cq_op );
869 if ( !port->eth_cq ) {
870 DBGC ( flexboot_nodnic,
871 "flexboot_nodnic %p port %d could not create completion queue\n",
872 flexboot_nodnic, ibdev->port );
873 status = MLX_OUT_OF_RESOURCES;
874 goto err_create_cq;
875 }
876 port->eth_qp->send.cq = port->eth_cq;
877 list_del(&port->eth_qp->send.list);
878 list_add ( &port->eth_qp->send.list, &port->eth_cq->work_queues );
879 port->eth_qp->recv.cq = port->eth_cq;
880 list_del(&port->eth_qp->recv.list);
881 list_add ( &port->eth_qp->recv.list, &port->eth_cq->work_queues );
882
883 status = nodnic_port_allocate_eq(&port->port_priv,
884 flexboot_nodnic->device_priv.device_cap.log_working_buffer_size);
885 MLX_FATAL_CHECK_STATUS(status, eq_alloc_err,
886 "nodnic_port_allocate_eq failed");
887
888 status = nodnic_port_init(&port->port_priv);
889 MLX_FATAL_CHECK_STATUS(status, init_err,
890 "nodnic_port_init failed");
891
892 /* update qp - qpn */
893 flexboot_nodnic_qp = ib_qp_get_drvdata ( port->eth_qp );
894 status = nodnic_port_get_qpn(&port->port_priv,
895 &flexboot_nodnic_qp->nodnic_queue_pair->send.nodnic_ring,
896 &qpn);
897 MLX_FATAL_CHECK_STATUS(status, qpn_err,
898 "nodnic_port_get_qpn failed");
899 port->eth_qp->qpn = qpn;
900
901 /* Fill receive rings */
902 ib_refill_recv ( ibdev, port->eth_qp );
903
904 status = nodnic_port_enable_dma(&port->port_priv);
905 MLX_FATAL_CHECK_STATUS(status, dma_err,
906 "nodnic_port_enable_dma failed");
907
908 if (flexboot_nodnic->device_priv.device_cap.support_promisc_filter) {
909 status = nodnic_port_set_promisc(&port->port_priv, TRUE);
910 MLX_FATAL_CHECK_STATUS(status, promisc_err,
911 "nodnic_port_set_promisc failed");
912 }
913
914 status = nodnic_port_get_state(&port->port_priv, &state);
915 MLX_FATAL_CHECK_STATUS(status, state_err,
916 "nodnic_port_get_state failed");
917
918 port->type->state_change (
919 flexboot_nodnic, port, state == nodnic_port_state_active );
920
921 DBGC ( flexboot_nodnic, "%s: port %d opened (link is %s)\n",
922 __FUNCTION__, port->ibdev->port,
923 ( ( state == nodnic_port_state_active ) ? "Up" : "Down" ) );
924
925 free(dummy_cq);
926 return 0;
927 state_err:
928 promisc_err:
929 dma_err:
930 qpn_err:
931 nodnic_port_close(&port->port_priv);
932 init_err:
933 nodnic_port_free_eq(&port->port_priv);
934 eq_alloc_err:
935 err_create_cq:
936 get_cq_size_err:
937 ib_destroy_qp(ibdev, port->eth_qp );
938 err_create_qp:
939 free(dummy_cq);
940 err_create_dummy_cq:
941 port->port_priv.port_state &= ~NODNIC_PORT_OPENED;
942 return status;
943 }
944
945 /**
946 * Close flexboot_nodnic Ethernet device
947 *
948 * @v netdev Network device
949 */
950 static void flexboot_nodnic_eth_close ( struct net_device *netdev) {
951 struct flexboot_nodnic_port *port = netdev->priv;
952 struct ib_device *ibdev = port->ibdev;
953 struct flexboot_nodnic *flexboot_nodnic = ib_get_drvdata ( ibdev );
954 mlx_status status = MLX_SUCCESS;
955
956 if ( ! ( port->port_priv.port_state & NODNIC_PORT_OPENED ) ) {
957 DBGC ( flexboot_nodnic, "%s: port %d is already closed\n",
958 __FUNCTION__, port->ibdev->port );
959 return;
960 }
961
962 if (flexboot_nodnic->device_priv.device_cap.support_promisc_filter) {
963 if ( ( status = nodnic_port_set_promisc( &port->port_priv, FALSE ) ) ) {
964 DBGC ( flexboot_nodnic,
965 "nodnic_port_set_promisc failed (status = %d)\n", status );
966 }
967 }
968
969 flexboot_nodnic_port_disable_dma ( port );
970
971 port->port_priv.port_state &= ~NODNIC_PORT_OPENED;
972
973 port->type->state_change ( flexboot_nodnic, port, FALSE );
974
975 /* Close port */
976 status = nodnic_port_close(&port->port_priv);
977 if ( status != MLX_SUCCESS ) {
978 DBGC ( flexboot_nodnic, "flexboot_nodnic %p port %d could not close port: %s\n",
979 flexboot_nodnic, ibdev->port, strerror ( status ) );
980 /* Nothing we can do about this */
981 }
982
983 ib_destroy_qp ( ibdev, port->eth_qp );
984 port->eth_qp = NULL;
985 ib_destroy_cq ( ibdev, port->eth_cq );
986 port->eth_cq = NULL;
987
988 nodnic_port_free_eq(&port->port_priv);
989
990 DBGC ( flexboot_nodnic, "%s: port %d closed\n", __FUNCTION__, port->ibdev->port );
991 }
992
993 void flexboot_nodnic_eth_irq ( struct net_device *netdev, int enable ) {
994 struct flexboot_nodnic_port *port = netdev->priv;
995
996 if ( enable ) {
997 if ( ( port->port_priv.port_state & NODNIC_PORT_OPENED ) &&
998 ! ( port->port_priv.port_state & NODNIC_PORT_DISABLING_DMA ) ) {
999 flexboot_nodnic_arm_cq ( port );
1000 } else {
1001 /* do nothing */
1002 }
1003 } else {
1004 nodnic_device_clear_int( port->port_priv.device );
1005 }
1006 }
1007
1008 /** flexboot_nodnic Ethernet network device operations */
1009 static struct net_device_operations flexboot_nodnic_eth_operations = {
1010 .open = flexboot_nodnic_eth_open,
1011 .close = flexboot_nodnic_eth_close,
1012 .transmit = flexboot_nodnic_eth_transmit,
1013 .poll = flexboot_nodnic_eth_poll,
1014 };
1015
1016 /**
1017 * Register flexboot_nodnic Ethernet device
1018 */
1019 static int flexboot_nodnic_register_netdev ( struct flexboot_nodnic *flexboot_nodnic,
1020 struct flexboot_nodnic_port *port) {
1021 mlx_status status = MLX_SUCCESS;
1022 struct net_device *netdev;
1023 struct ib_device *ibdev = port->ibdev;
1024 union {
1025 uint8_t bytes[8];
1026 uint32_t dwords[2];
1027 } mac;
1028
1029 /* Allocate network devices */
1030 netdev = alloc_etherdev ( 0 );
1031 if ( netdev == NULL ) {
1032 DBGC ( flexboot_nodnic, "flexboot_nodnic %p port %d could not allocate net device\n",
1033 flexboot_nodnic, ibdev->port );
1034 status = MLX_OUT_OF_RESOURCES;
1035 goto alloc_err;
1036 }
1037 port->netdev = netdev;
1038 netdev_init ( netdev, &flexboot_nodnic_eth_operations );
1039 netdev->dev = ibdev->dev;
1040 netdev->priv = port;
1041
1042 status = nodnic_port_query(&port->port_priv,
1043 nodnic_port_option_mac_high,
1044 &mac.dwords[0]);
1045 MLX_FATAL_CHECK_STATUS(status, mac_err,
1046 "failed to query mac high");
1047 status = nodnic_port_query(&port->port_priv,
1048 nodnic_port_option_mac_low,
1049 &mac.dwords[1]);
1050 MLX_FATAL_CHECK_STATUS(status, mac_err,
1051 "failed to query mac low");
1052 mac.dwords[0] = htonl(mac.dwords[0]);
1053 mac.dwords[1] = htonl(mac.dwords[1]);
1054 memcpy ( netdev->hw_addr,
1055 &mac.bytes[2], ETH_ALEN);
1056 /* Register network device */
1057 status = register_netdev ( netdev );
1058 if ( status != MLX_SUCCESS ) {
1059 DBGC ( flexboot_nodnic,
1060 "flexboot_nodnic %p port %d could not register network device: %s\n",
1061 flexboot_nodnic, ibdev->port, strerror ( status ) );
1062 goto reg_err;
1063 }
1064 return status;
1065 reg_err:
1066 mac_err:
1067 netdev_put ( netdev );
1068 alloc_err:
1069 return status;
1070 }
1071
1072 /**
1073 * Handle flexboot_nodnic Ethernet device port state change
1074 */
1075 static void flexboot_nodnic_state_change_netdev ( struct flexboot_nodnic *flexboot_nodnic __unused,
1076 struct flexboot_nodnic_port *port,
1077 int link_up ) {
1078 struct net_device *netdev = port->netdev;
1079
1080 if ( link_up )
1081 netdev_link_up ( netdev );
1082 else
1083 netdev_link_down ( netdev );
1084
1085 }
1086
1087 /**
1088 * Unregister flexboot_nodnic Ethernet device
1089 */
1090 static void flexboot_nodnic_unregister_netdev ( struct flexboot_nodnic *flexboot_nodnic __unused,
1091 struct flexboot_nodnic_port *port ) {
1092 struct net_device *netdev = port->netdev;
1093 unregister_netdev ( netdev );
1094 netdev_nullify ( netdev );
1095 netdev_put ( netdev );
1096 }
1097
1098 /** flexboot_nodnic Ethernet port type */
1099 static struct flexboot_nodnic_port_type flexboot_nodnic_port_type_eth = {
1100 .register_dev = flexboot_nodnic_register_netdev,
1101 .state_change = flexboot_nodnic_state_change_netdev,
1102 .unregister_dev = flexboot_nodnic_unregister_netdev,
1103 };
1104
1105 /***************************************************************************
1106 *
1107 * PCI interface helper functions
1108 *
1109 ***************************************************************************
1110 */
1111 static
1112 mlx_status
1113 flexboot_nodnic_allocate_infiniband_devices( struct flexboot_nodnic *flexboot_nodnic_priv ) {
1114 mlx_status status = MLX_SUCCESS;
1115 nodnic_device_priv *device_priv = &flexboot_nodnic_priv->device_priv;
1116 struct pci_device *pci = flexboot_nodnic_priv->pci;
1117 struct ib_device *ibdev = NULL;
1118 unsigned int i = 0;
1119
1120 /* Allocate Infiniband devices */
1121 for (; i < device_priv->device_cap.num_ports; i++) {
1122 if ( ! ( flexboot_nodnic_priv->port_mask & ( i + 1 ) ) )
1123 continue;
1124 ibdev = alloc_ibdev(0);
1125 if (ibdev == NULL) {
1126 status = MLX_OUT_OF_RESOURCES;
1127 goto err_alloc_ibdev;
1128 }
1129 flexboot_nodnic_priv->port[i].ibdev = ibdev;
1130 ibdev->op = &flexboot_nodnic_ib_operations;
1131 ibdev->dev = &pci->dev;
1132 ibdev->port = ( FLEXBOOT_NODNIC_PORT_BASE + i);
1133 ib_set_drvdata(ibdev, flexboot_nodnic_priv);
1134 }
1135 return status;
1136 err_alloc_ibdev:
1137 for ( i-- ; ( signed int ) i >= 0 ; i-- )
1138 ibdev_put ( flexboot_nodnic_priv->port[i].ibdev );
1139 return status;
1140 }
1141
1142 static
1143 mlx_status
1144 flexboot_nodnic_thin_init_ports( struct flexboot_nodnic *flexboot_nodnic_priv ) {
1145 mlx_status status = MLX_SUCCESS;
1146 nodnic_device_priv *device_priv = &flexboot_nodnic_priv->device_priv;
1147 nodnic_port_priv *port_priv = NULL;
1148 unsigned int i = 0;
1149
1150 for ( i = 0; i < device_priv->device_cap.num_ports; i++ ) {
1151 if ( ! ( flexboot_nodnic_priv->port_mask & ( i + 1 ) ) )
1152 continue;
1153 port_priv = &flexboot_nodnic_priv->port[i].port_priv;
1154 status = nodnic_port_thin_init( device_priv, port_priv, i );
1155 MLX_FATAL_CHECK_STATUS(status, thin_init_err,
1156 "flexboot_nodnic_thin_init_ports failed");
1157 }
1158 thin_init_err:
1159 return status;
1160 }
1161
1162
1163 static
1164 mlx_status
1165 flexboot_nodnic_set_ports_type ( struct flexboot_nodnic *flexboot_nodnic_priv ) {
1166 mlx_status status = MLX_SUCCESS;
1167 nodnic_device_priv *device_priv = &flexboot_nodnic_priv->device_priv;
1168 nodnic_port_priv *port_priv = NULL;
1169 nodnic_port_type type = NODNIC_PORT_TYPE_UNKNOWN;
1170 unsigned int i = 0;
1171
1172 for ( i = 0 ; i < device_priv->device_cap.num_ports ; i++ ) {
1173 if ( ! ( flexboot_nodnic_priv->port_mask & ( i + 1 ) ) )
1174 continue;
1175 port_priv = &flexboot_nodnic_priv->port[i].port_priv;
1176 status = nodnic_port_get_type(port_priv, &type);
1177 MLX_FATAL_CHECK_STATUS(status, type_err,
1178 "nodnic_port_get_type failed");
1179 switch ( type ) {
1180 case NODNIC_PORT_TYPE_ETH:
1181 DBGC ( flexboot_nodnic_priv, "Port %d type is Ethernet\n", i );
1182 flexboot_nodnic_priv->port[i].type = &flexboot_nodnic_port_type_eth;
1183 break;
1184 case NODNIC_PORT_TYPE_IB:
1185 DBGC ( flexboot_nodnic_priv, "Port %d type is Infiniband\n", i );
1186 status = MLX_UNSUPPORTED;
1187 goto type_err;
1188 default:
1189 DBGC ( flexboot_nodnic_priv, "Port %d type is unknown\n", i );
1190 status = MLX_UNSUPPORTED;
1191 goto type_err;
1192 }
1193 }
1194 type_err:
1195 return status;
1196 }
1197
1198 static
1199 mlx_status
1200 flexboot_nodnic_ports_register_dev( struct flexboot_nodnic *flexboot_nodnic_priv ) {
1201 mlx_status status = MLX_SUCCESS;
1202 nodnic_device_priv *device_priv = &flexboot_nodnic_priv->device_priv;
1203 struct flexboot_nodnic_port *port = NULL;
1204 unsigned int i = 0;
1205
1206 for (; i < device_priv->device_cap.num_ports; i++) {
1207 if ( ! ( flexboot_nodnic_priv->port_mask & ( i + 1 ) ) )
1208 continue;
1209 port = &flexboot_nodnic_priv->port[i];
1210 status = port->type->register_dev ( flexboot_nodnic_priv, port );
1211 MLX_FATAL_CHECK_STATUS(status, reg_err,
1212 "port register_dev failed");
1213 }
1214 reg_err:
1215 return status;
1216 }
1217
1218 static
1219 mlx_status
1220 flexboot_nodnic_ports_unregister_dev ( struct flexboot_nodnic *flexboot_nodnic_priv ) {
1221 struct flexboot_nodnic_port *port;
1222 nodnic_device_priv *device_priv = &flexboot_nodnic_priv->device_priv;
1223 int i = (device_priv->device_cap.num_ports - 1);
1224
1225 for (; i >= 0; i--) {
1226 if ( ! ( flexboot_nodnic_priv->port_mask & ( i + 1 ) ) )
1227 continue;
1228 port = &flexboot_nodnic_priv->port[i];
1229 port->type->unregister_dev(flexboot_nodnic_priv, port);
1230 ibdev_put(flexboot_nodnic_priv->port[i].ibdev);
1231 }
1232 return MLX_SUCCESS;
1233 }
1234
1235 /***************************************************************************
1236 *
1237 * flexboot nodnic interface
1238 *
1239 ***************************************************************************
1240 */
1241 __unused static void flexboot_nodnic_enable_dma ( struct flexboot_nodnic *nodnic ) {
1242 nodnic_port_priv *port_priv;
1243 mlx_status status;
1244 int i;
1245
1246 for ( i = 0; i < nodnic->device_priv.device_cap.num_ports; i++ ) {
1247 if ( ! ( nodnic->port_mask & ( i + 1 ) ) )
1248 continue;
1249 port_priv = & ( nodnic->port[i].port_priv );
1250 if ( ! ( port_priv->port_state & NODNIC_PORT_OPENED ) )
1251 continue;
1252
1253 if ( ( status = nodnic_port_enable_dma ( port_priv ) ) ) {
1254 MLX_DEBUG_WARN ( nodnic, "Failed to enable DMA %d\n", status );
1255 }
1256 }
1257 }
1258
1259 __unused static void flexboot_nodnic_disable_dma ( struct flexboot_nodnic *nodnic ) {
1260 int i;
1261
1262 for ( i = 0; i < nodnic->device_priv.device_cap.num_ports; i++ ) {
1263 if ( ! ( nodnic->port_mask & ( i + 1 ) ) )
1264 continue;
1265 flexboot_nodnic_port_disable_dma ( & ( nodnic->port[i] ) );
1266 }
1267 }
1268
1269 int flexboot_nodnic_is_supported ( struct pci_device *pci ) {
1270 mlx_utils utils;
1271 mlx_pci_gw_buffer buffer;
1272 mlx_status status;
1273 int is_supported = 0;
1274
1275 DBG ( "%s: start\n", __FUNCTION__ );
1276
1277 memset ( &utils, 0, sizeof ( utils ) );
1278
1279 status = mlx_utils_init ( &utils, pci );
1280 MLX_CHECK_STATUS ( pci, status, utils_init_err, "mlx_utils_init failed" );
1281
1282 status = mlx_pci_gw_init ( &utils );
1283 MLX_CHECK_STATUS ( pci, status, pci_gw_init_err, "mlx_pci_gw_init failed" );
1284
1285 status = mlx_pci_gw_read ( &utils, PCI_GW_SPACE_NODNIC,
1286 NODNIC_NIC_INTERFACE_SUPPORTED_OFFSET, &buffer );
1287
1288 if ( status == MLX_SUCCESS ) {
1289 buffer >>= NODNIC_NIC_INTERFACE_SUPPORTED_BIT;
1290 is_supported = ( buffer & 0x1 );
1291 }
1292
1293 mlx_pci_gw_teardown( &utils );
1294
1295 pci_gw_init_err:
1296 utils_init_err:
1297 DBG ( "%s: NODNIC is %s supported (status = %d)\n",
1298 __FUNCTION__, ( is_supported ? "": "not" ), status );
1299 return is_supported;
1300 }
1301
1302 void flexboot_nodnic_copy_mac ( uint8_t mac_addr[], uint32_t low_byte,
1303 uint16_t high_byte ) {
1304 union mac_addr {
1305 struct {
1306 uint32_t low_byte;
1307 uint16_t high_byte;
1308 };
1309 uint8_t mac_addr[ETH_ALEN];
1310 } mac_addr_aux;
1311
1312 mac_addr_aux.high_byte = high_byte;
1313 mac_addr_aux.low_byte = low_byte;
1314
1315 mac_addr[0] = mac_addr_aux.mac_addr[5];
1316 mac_addr[1] = mac_addr_aux.mac_addr[4];
1317 mac_addr[2] = mac_addr_aux.mac_addr[3];
1318 mac_addr[3] = mac_addr_aux.mac_addr[2];
1319 mac_addr[4] = mac_addr_aux.mac_addr[1];
1320 mac_addr[5] = mac_addr_aux.mac_addr[0];
1321 }
1322
1323 static mlx_status flexboot_nodnic_get_factory_mac (
1324 struct flexboot_nodnic *flexboot_nodnic_priv, uint8_t port __unused ) {
1325 struct mlx_vmac_query_virt_mac virt_mac;
1326 mlx_status status;
1327
1328 memset ( & virt_mac, 0, sizeof ( virt_mac ) );
1329 status = mlx_vmac_query_virt_mac ( flexboot_nodnic_priv->device_priv.utils,
1330 &virt_mac );
1331 if ( ! status ) {
1332 DBGC ( flexboot_nodnic_priv, "NODNIC %p Failed to set the virtual MAC\n",
1333 flexboot_nodnic_priv );
1334 }
1335
1336 return status;
1337 }
1338
1339 /**
1340 * Set port masking
1341 *
1342 * @v flexboot_nodnic nodnic device
1343 * @ret rc Return status code
1344 */
1345 static int flexboot_nodnic_set_port_masking ( struct flexboot_nodnic *flexboot_nodnic ) {
1346 unsigned int i;
1347 nodnic_device_priv *device_priv = &flexboot_nodnic->device_priv;
1348
1349 flexboot_nodnic->port_mask = 0;
1350 for ( i = 0; i < device_priv->device_cap.num_ports; i++ ) {
1351 flexboot_nodnic->port_mask |= (i + 1);
1352 }
1353
1354 if ( ! flexboot_nodnic->port_mask ) {
1355 /* No port was enabled */
1356 DBGC ( flexboot_nodnic, "NODNIC %p No port was enabled for "
1357 "booting\n", flexboot_nodnic );
1358 return -ENETUNREACH;
1359 }
1360
1361 return 0;
1362 }
1363
1364 int flexboot_nodnic_probe ( struct pci_device *pci,
1365 struct flexboot_nodnic_callbacks *callbacks,
1366 void *drv_priv __unused ) {
1367 mlx_status status = MLX_SUCCESS;
1368 struct flexboot_nodnic *flexboot_nodnic_priv = NULL;
1369 nodnic_device_priv *device_priv = NULL;
1370 int i = 0;
1371
1372 if ( ( pci == NULL ) || ( callbacks == NULL ) ) {
1373 DBGC ( flexboot_nodnic_priv, "%s: Bad Parameter\n", __FUNCTION__ );
1374 return -EINVAL;
1375 }
1376
1377 flexboot_nodnic_priv = zalloc( sizeof ( *flexboot_nodnic_priv ) );
1378 if ( flexboot_nodnic_priv == NULL ) {
1379 DBGC ( flexboot_nodnic_priv, "%s: Failed to allocate priv data\n", __FUNCTION__ );
1380 status = MLX_OUT_OF_RESOURCES;
1381 goto device_err_alloc;
1382 }
1383
1384 /* Register settings
1385 * Note that pci->priv will be the device private data */
1386 flexboot_nodnic_priv->pci = pci;
1387 flexboot_nodnic_priv->callbacks = callbacks;
1388 pci_set_drvdata ( pci, flexboot_nodnic_priv );
1389
1390 device_priv = &flexboot_nodnic_priv->device_priv;
1391 device_priv->utils = (mlx_utils *)zalloc( sizeof ( mlx_utils ) );
1392 if ( device_priv->utils == NULL ) {
1393 DBGC ( flexboot_nodnic_priv, "%s: Failed to allocate utils\n", __FUNCTION__ );
1394 status = MLX_OUT_OF_RESOURCES;
1395 goto utils_err_alloc;
1396 }
1397
1398 status = mlx_utils_init( device_priv->utils, pci );
1399 MLX_FATAL_CHECK_STATUS(status, utils_init_err,
1400 "mlx_utils_init failed");
1401
1402 /* nodnic init*/
1403 status = mlx_pci_gw_init( device_priv->utils );
1404 MLX_FATAL_CHECK_STATUS(status, cmd_init_err,
1405 "mlx_pci_gw_init failed");
1406
1407 /* init device */
1408 status = nodnic_device_init( device_priv );
1409 MLX_FATAL_CHECK_STATUS(status, device_init_err,
1410 "nodnic_device_init failed");
1411
1412 status = nodnic_device_get_cap( device_priv );
1413 MLX_FATAL_CHECK_STATUS(status, get_cap_err,
1414 "nodnic_device_get_cap failed");
1415
1416 status = flexboot_nodnic_set_port_masking ( flexboot_nodnic_priv );
1417 MLX_FATAL_CHECK_STATUS(status, err_set_masking,
1418 "flexboot_nodnic_set_port_masking failed");
1419
1420 status = flexboot_nodnic_allocate_infiniband_devices( flexboot_nodnic_priv );
1421 MLX_FATAL_CHECK_STATUS(status, err_alloc_ibdev,
1422 "flexboot_nodnic_allocate_infiniband_devices failed");
1423
1424 /* port init */
1425 status = flexboot_nodnic_thin_init_ports( flexboot_nodnic_priv );
1426 MLX_FATAL_CHECK_STATUS(status, err_thin_init_ports,
1427 "flexboot_nodnic_thin_init_ports failed");
1428
1429 /* device reg */
1430 status = flexboot_nodnic_set_ports_type( flexboot_nodnic_priv );
1431 MLX_CHECK_STATUS( flexboot_nodnic_priv, status, err_set_ports_types,
1432 "flexboot_nodnic_set_ports_type failed");
1433
1434 status = flexboot_nodnic_ports_register_dev( flexboot_nodnic_priv );
1435 MLX_FATAL_CHECK_STATUS(status, reg_err,
1436 "flexboot_nodnic_ports_register_dev failed");
1437
1438 for ( i = 0; i < device_priv->device_cap.num_ports; i++ ) {
1439 if ( ! ( flexboot_nodnic_priv->port_mask & ( i + 1 ) ) )
1440 continue;
1441 flexboot_nodnic_get_factory_mac ( flexboot_nodnic_priv, i );
1442 }
1443
1444 /* Update ETH operations with IRQ function if supported */
1445 DBGC ( flexboot_nodnic_priv, "%s: %s IRQ function\n",
1446 __FUNCTION__, ( callbacks->irq ? "Valid" : "No" ) );
1447 flexboot_nodnic_eth_operations.irq = callbacks->irq;
1448 return 0;
1449
1450 flexboot_nodnic_ports_unregister_dev ( flexboot_nodnic_priv );
1451 reg_err:
1452 err_set_ports_types:
1453 err_thin_init_ports:
1454 err_alloc_ibdev:
1455 err_set_masking:
1456 get_cap_err:
1457 nodnic_device_teardown ( device_priv );
1458 device_init_err:
1459 mlx_pci_gw_teardown ( device_priv->utils );
1460 cmd_init_err:
1461 utils_init_err:
1462 free ( device_priv->utils );
1463 utils_err_alloc:
1464 free ( flexboot_nodnic_priv );
1465 device_err_alloc:
1466 return status;
1467 }
1468
1469 void flexboot_nodnic_remove ( struct pci_device *pci )
1470 {
1471 struct flexboot_nodnic *flexboot_nodnic_priv = pci_get_drvdata ( pci );
1472 nodnic_device_priv *device_priv = & ( flexboot_nodnic_priv->device_priv );
1473
1474 flexboot_nodnic_ports_unregister_dev ( flexboot_nodnic_priv );
1475 nodnic_device_teardown( device_priv );
1476 mlx_pci_gw_teardown( device_priv->utils );
1477 free( device_priv->utils );
1478 free( flexboot_nodnic_priv );
1479 }