~pmdj/ubuntu/trusty/qemu/2.9+applesmc+fadtv3

« back to all changes in this revision

Viewing changes to roms/ipxe/src/drivers/infiniband/flexboot_nodnic.c

  • Committer: Phil Dennis-Jordan
  • Date: 2017-07-21 08:03:43 UTC
  • mfrom: (1.1.1)
  • Revision ID: phil@philjordan.eu-20170721080343-2yr2vdj7713czahv
New upstream release 2.9.0.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
}