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