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

« back to all changes in this revision

Viewing changes to roms/ipxe/src/drivers/infiniband/mlx_nodnic/src/mlx_port.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 "../include/mlx_port.h"
 
23
#include "../include/mlx_cmd.h"
 
24
#include "../../mlx_utils/include/public/mlx_memory.h"
 
25
#include "../../mlx_utils/include/public/mlx_pci.h"
 
26
#include "../../mlx_utils/include/public/mlx_bail.h"
 
27
 
 
28
#define PortDataEntry( _option, _offset, _align, _mask) { \
 
29
  .option = _option,                     \
 
30
  .offset = _offset,                   \
 
31
  .align = _align,                  \
 
32
  .mask = _mask,                    \
 
33
  }
 
34
 
 
35
#define QpDataEntry( _type, _send_offset, _recv_offset) { \
 
36
  .type = _type,                     \
 
37
  .send_offset = _send_offset,                   \
 
38
  .recv_offset = _recv_offset,                  \
 
39
  }
 
40
 
 
41
 
 
42
struct nodnic_port_data_entry nodnic_port_data_table[] = {
 
43
                PortDataEntry(nodnic_port_option_link_type, 0x0, 4, 0x1),
 
44
                PortDataEntry(nodnic_port_option_mac_low, 0xc, 0, 0xFFFFFFFF),
 
45
                PortDataEntry(nodnic_port_option_mac_high, 0x8, 0, 0xFFFF),
 
46
                PortDataEntry(nodnic_port_option_log_cq_size, 0x6c, 0, 0x3F),
 
47
                PortDataEntry(nodnic_port_option_reset_needed, 0x0, 31, 0x1),
 
48
                PortDataEntry(nodnic_port_option_mac_filters_en, 0x4, 0, 0x1F),
 
49
                PortDataEntry(nodnic_port_option_port_state, 0x0, 0, 0xF),
 
50
                PortDataEntry(nodnic_port_option_network_en, 0x4, 31, 0x1),
 
51
                PortDataEntry(nodnic_port_option_dma_en, 0x4, 30, 0x1),
 
52
                PortDataEntry(nodnic_port_option_eq_addr_low, 0x74, 0, 0xFFFFFFFF),
 
53
                PortDataEntry(nodnic_port_option_eq_addr_high, 0x70, 0, 0xFFFFFFFF),
 
54
                PortDataEntry(nodnic_port_option_cq_addr_low, 0x6c, 12, 0xFFFFF),
 
55
                PortDataEntry(nodnic_port_option_cq_addr_high, 0x68, 0, 0xFFFFFFFF),
 
56
                PortDataEntry(nodnic_port_option_port_management_change_event, 0x0, 30, 0x1),
 
57
                PortDataEntry(nodnic_port_option_port_promisc_en, 0x4, 29, 0x1),
 
58
                PortDataEntry(nodnic_port_option_arm_cq, 0x78, 8, 0xffff),
 
59
                PortDataEntry(nodnic_port_option_port_promisc_multicast_en, 0x4, 28, 0x1),
 
60
#ifdef DEVICE_CX3
 
61
                PortDataEntry(nodnic_port_option_crspace_en, 0x4, 27, 0x1),
 
62
#endif
 
63
};
 
64
 
 
65
#define MAX_QP_DATA_ENTRIES 5
 
66
struct nodnic_qp_data_entry nodnic_qp_data_teable[MAX_QP_DATA_ENTRIES] = {
 
67
                QpDataEntry(NODNIC_QPT_SMI, 0, 0),
 
68
                QpDataEntry(NODNIC_QPT_GSI, 0, 0),
 
69
                QpDataEntry(NODNIC_QPT_UD, 0, 0),
 
70
                QpDataEntry(NODNIC_QPT_RC, 0, 0),
 
71
                QpDataEntry(NODNIC_QPT_ETH, 0x80, 0xC0),
 
72
};
 
73
 
 
74
#define MAX_NODNIC_PORTS 2
 
75
int nodnic_port_offset_table[MAX_NODNIC_PORTS] = {
 
76
        0x100, //port 1 offset
 
77
        0x280, //port 1 offset
 
78
};
 
79
 
 
80
mlx_status
 
81
nodnic_port_get_state(
 
82
                                        IN  nodnic_port_priv    *port_priv,
 
83
                                        OUT nodnic_port_state                   *state
 
84
                                        )
 
85
{
 
86
        mlx_status status = MLX_SUCCESS;
 
87
        mlx_uint32 out = 0;
 
88
 
 
89
        status = nodnic_port_query(port_priv,
 
90
                        nodnic_port_option_port_state, &out);
 
91
        MLX_CHECK_STATUS(port_priv->device, status, query_err,
 
92
                        "nodnic_port_query failed");
 
93
        *state = (nodnic_port_state)out;
 
94
query_err:
 
95
        return status;
 
96
}
 
97
mlx_status
 
98
nodnic_port_get_type(
 
99
                                        IN  nodnic_port_priv    *port_priv,
 
100
                                        OUT nodnic_port_type    *type
 
101
                                        )
 
102
{
 
103
        mlx_status status = MLX_SUCCESS;
 
104
        mlx_uint32 out = 0;
 
105
 
 
106
        if ( port_priv->port_type == NODNIC_PORT_TYPE_UNKNOWN){
 
107
                status = nodnic_port_query(port_priv,
 
108
                                nodnic_port_option_link_type, &out);
 
109
                MLX_FATAL_CHECK_STATUS(status, query_err,
 
110
                                "nodnic_port_query failed");
 
111
                port_priv->port_type = (nodnic_port_type)out;
 
112
        }
 
113
        *type = port_priv->port_type;
 
114
query_err:
 
115
        return status;
 
116
}
 
117
 
 
118
mlx_status
 
119
nodnic_port_query(
 
120
                                        IN  nodnic_port_priv    *port_priv,
 
121
                                        IN  nodnic_port_option          option,
 
122
                                        OUT     mlx_uint32                              *out
 
123
                                        )
 
124
{
 
125
        mlx_status                              status = MLX_SUCCESS;
 
126
        nodnic_device_priv              *device_priv = NULL;
 
127
        struct nodnic_port_data_entry *data_entry;
 
128
        mlx_uint32                              buffer = 0;
 
129
        if( port_priv == NULL || out == NULL){
 
130
                status = MLX_INVALID_PARAMETER;
 
131
                goto invalid_parm;
 
132
        }
 
133
        device_priv = port_priv->device;
 
134
 
 
135
        data_entry = &nodnic_port_data_table[option];
 
136
 
 
137
        status = nodnic_cmd_read(device_priv,
 
138
                        port_priv->port_offset + data_entry->offset , &buffer);
 
139
        MLX_CHECK_STATUS(device_priv, status, read_err,
 
140
                        "nodnic_cmd_read failed");
 
141
        *out = (buffer >> data_entry->align) & data_entry->mask;
 
142
read_err:
 
143
invalid_parm:
 
144
        return status;
 
145
}
 
146
 
 
147
mlx_status
 
148
nodnic_port_set(
 
149
                                        IN  nodnic_port_priv    *port_priv,
 
150
                                        IN  nodnic_port_option          option,
 
151
                                        IN      mlx_uint32                              in
 
152
                                        )
 
153
{
 
154
        mlx_status                              status = MLX_SUCCESS;
 
155
        nodnic_device_priv              *device_priv = NULL;
 
156
        struct nodnic_port_data_entry *data_entry;
 
157
        mlx_uint32                              buffer = 0;
 
158
 
 
159
        if( port_priv == NULL ){
 
160
                MLX_DEBUG_FATAL_ERROR("port_priv is NULL\n");
 
161
                status = MLX_INVALID_PARAMETER;
 
162
                goto invalid_parm;
 
163
        }
 
164
        device_priv = port_priv->device;
 
165
        data_entry = &nodnic_port_data_table[option];
 
166
 
 
167
        if( in > data_entry->mask ){
 
168
                MLX_DEBUG_FATAL_ERROR("in > data_entry->mask (%d > %d)\n",
 
169
                                in, data_entry->mask);
 
170
                status = MLX_INVALID_PARAMETER;
 
171
                goto invalid_parm;
 
172
        }
 
173
        status = nodnic_cmd_read(device_priv,
 
174
                        port_priv->port_offset + data_entry->offset, &buffer);
 
175
        MLX_FATAL_CHECK_STATUS(status, read_err,
 
176
                        "nodnic_cmd_read failed");
 
177
        buffer = buffer & ~(data_entry->mask << data_entry->align);
 
178
        buffer = buffer | (in << data_entry->align);
 
179
        status = nodnic_cmd_write(device_priv,
 
180
                        port_priv->port_offset + data_entry->offset, buffer);
 
181
        MLX_FATAL_CHECK_STATUS(status, write_err,
 
182
                        "nodnic_cmd_write failed");
 
183
write_err:
 
184
read_err:
 
185
invalid_parm:
 
186
        return status;
 
187
}
 
188
 
 
189
mlx_status
 
190
nodnic_port_read_reset_needed(
 
191
                                                IN nodnic_port_priv             *port_priv,
 
192
                                                OUT mlx_boolean                 *reset_needed
 
193
                                                )
 
194
{
 
195
        mlx_status status = MLX_SUCCESS;
 
196
        mlx_uint32 out = 0;
 
197
        status = nodnic_port_query(port_priv,
 
198
                        nodnic_port_option_reset_needed, &out);
 
199
        MLX_CHECK_STATUS(port_priv->device, status, query_err,
 
200
                        "nodnic_port_query failed");
 
201
        *reset_needed = (mlx_boolean)out;
 
202
query_err:
 
203
        return status;
 
204
}
 
205
 
 
206
mlx_status
 
207
nodnic_port_read_port_management_change_event(
 
208
                                                IN nodnic_port_priv             *port_priv,
 
209
                                                OUT mlx_boolean                 *change_event
 
210
                                                )
 
211
{
 
212
        mlx_status status = MLX_SUCCESS;
 
213
        mlx_uint32 out = 0;
 
214
        status = nodnic_port_query(port_priv,
 
215
                        nodnic_port_option_port_management_change_event, &out);
 
216
        MLX_CHECK_STATUS(port_priv->device, status, query_err,
 
217
                        "nodnic_port_query failed");
 
218
        *change_event = (mlx_boolean)out;
 
219
query_err:
 
220
        return status;
 
221
}
 
222
 
 
223
mlx_status
 
224
nodnic_port_create_cq(
 
225
                                        IN nodnic_port_priv     *port_priv,
 
226
                                        IN mlx_size     cq_size,
 
227
                                        OUT nodnic_cq   **cq
 
228
                                        )
 
229
{
 
230
        mlx_status status = MLX_SUCCESS;
 
231
        nodnic_device_priv *device_priv = NULL;
 
232
        mlx_uint64 address = 0;
 
233
        if( port_priv == NULL || cq == NULL){
 
234
                status = MLX_INVALID_PARAMETER;
 
235
                goto invalid_parm;
 
236
        }
 
237
 
 
238
        device_priv =  port_priv->device;
 
239
 
 
240
        status = mlx_memory_zalloc(device_priv->utils,
 
241
                                sizeof(nodnic_cq),(mlx_void **)cq);
 
242
        MLX_FATAL_CHECK_STATUS(status, alloc_err,
 
243
                        "cq priv allocation error");
 
244
 
 
245
        (*cq)->cq_size = cq_size;
 
246
        status = mlx_memory_alloc_dma(device_priv->utils,
 
247
                        (*cq)->cq_size, NODNIC_MEMORY_ALIGN,
 
248
                                &(*cq)->cq_virt);
 
249
        MLX_FATAL_CHECK_STATUS(status, dma_alloc_err,
 
250
                                "cq allocation error");
 
251
 
 
252
        status = mlx_memory_map_dma(device_priv->utils,
 
253
                                                (*cq)->cq_virt,
 
254
                                                (*cq)->cq_size,
 
255
                                                &(*cq)->cq_physical,
 
256
                                                &(*cq)->map);
 
257
        MLX_FATAL_CHECK_STATUS(status, cq_map_err,
 
258
                                "cq map error");
 
259
 
 
260
        /* update cq address */
 
261
#define NODIC_CQ_ADDR_HIGH 0x68
 
262
#define NODIC_CQ_ADDR_LOW 0x6c
 
263
        address = (mlx_uint64)(*cq)->cq_physical;
 
264
        nodnic_port_set(port_priv, nodnic_port_option_cq_addr_low,
 
265
                        (mlx_uint32)(address >> 12));
 
266
        address = address >> 32;
 
267
        nodnic_port_set(port_priv, nodnic_port_option_cq_addr_high,
 
268
                                (mlx_uint32)address);
 
269
 
 
270
        return status;
 
271
        mlx_memory_ummap_dma(device_priv->utils, (*cq)->map);
 
272
cq_map_err:
 
273
        mlx_memory_free_dma(device_priv->utils, (*cq)->cq_size,
 
274
                        (void **)&((*cq)->cq_virt));
 
275
dma_alloc_err:
 
276
        mlx_memory_free(device_priv->utils, (void **)cq);
 
277
alloc_err:
 
278
invalid_parm:
 
279
        return status;
 
280
}
 
281
 
 
282
mlx_status
 
283
nodnic_port_destroy_cq(
 
284
                                        IN nodnic_port_priv     *port_priv,
 
285
                                        IN nodnic_cq    *cq
 
286
                                        )
 
287
{
 
288
        mlx_status status = MLX_SUCCESS;
 
289
        nodnic_device_priv *device_priv = NULL;
 
290
 
 
291
        if( port_priv == NULL || cq == NULL){
 
292
                status = MLX_INVALID_PARAMETER;
 
293
                goto invalid_parm;
 
294
        }
 
295
        device_priv =  port_priv->device;
 
296
 
 
297
        mlx_memory_ummap_dma(device_priv->utils, cq->map);
 
298
 
 
299
        mlx_memory_free_dma(device_priv->utils, cq->cq_size,
 
300
                        (void **)&(cq->cq_virt));
 
301
 
 
302
        mlx_memory_free(device_priv->utils, (void **)&cq);
 
303
invalid_parm:
 
304
        return status;
 
305
}
 
306
mlx_status
 
307
nodnic_port_create_qp(
 
308
                                        IN nodnic_port_priv     *port_priv,
 
309
                                        IN nodnic_queue_pair_type       type,
 
310
                                        IN mlx_size     send_wq_size,
 
311
                                        IN mlx_uint32 send_wqe_num,
 
312
                                        IN mlx_size     receive_wq_size,
 
313
                                        IN mlx_uint32 recv_wqe_num,
 
314
                                        OUT nodnic_qp   **qp
 
315
                                        )
 
316
{
 
317
        mlx_status status = MLX_SUCCESS;
 
318
        nodnic_device_priv *device_priv = NULL;
 
319
        mlx_uint32 max_ring_size = 0;
 
320
        mlx_uint64 address = 0;
 
321
        mlx_uint32 log_size = 0;
 
322
        if( port_priv == NULL || qp == NULL){
 
323
                status = MLX_INVALID_PARAMETER;
 
324
                goto invalid_parm;
 
325
        }
 
326
 
 
327
        device_priv =  port_priv->device;
 
328
        max_ring_size = (1 << device_priv->device_cap.log_max_ring_size);
 
329
        if( send_wq_size > max_ring_size ||
 
330
                        receive_wq_size > max_ring_size ){
 
331
                status = MLX_INVALID_PARAMETER;
 
332
                goto invalid_parm;
 
333
        }
 
334
 
 
335
        status = mlx_memory_zalloc(device_priv->utils,
 
336
                        sizeof(nodnic_qp),(mlx_void **)qp);
 
337
        MLX_FATAL_CHECK_STATUS(status, alloc_err,
 
338
                        "qp allocation error");
 
339
 
 
340
        if( nodnic_qp_data_teable[type].send_offset == 0 ||
 
341
                        nodnic_qp_data_teable[type].recv_offset == 0){
 
342
                status = MLX_INVALID_PARAMETER;
 
343
                goto invalid_type;
 
344
        }
 
345
 
 
346
        (*qp)->send.nodnic_ring.offset = port_priv->port_offset +
 
347
                                nodnic_qp_data_teable[type].send_offset;
 
348
        (*qp)->receive.nodnic_ring.offset = port_priv->port_offset +
 
349
                        nodnic_qp_data_teable[type].recv_offset;
 
350
 
 
351
        status = mlx_memory_alloc_dma(device_priv->utils,
 
352
                        send_wq_size, NODNIC_MEMORY_ALIGN,
 
353
                        (void*)&(*qp)->send.wqe_virt);
 
354
        MLX_FATAL_CHECK_STATUS(status, send_alloc_err,
 
355
                                "send wq allocation error");
 
356
 
 
357
        status = mlx_memory_alloc_dma(device_priv->utils,
 
358
                                receive_wq_size, NODNIC_MEMORY_ALIGN,
 
359
                                &(*qp)->receive.wqe_virt);
 
360
        MLX_FATAL_CHECK_STATUS(status, receive_alloc_err,
 
361
                                "receive wq allocation error");
 
362
 
 
363
        status = mlx_memory_map_dma(device_priv->utils,
 
364
                                                (*qp)->send.wqe_virt,
 
365
                                                send_wq_size,
 
366
                                                &(*qp)->send.nodnic_ring.wqe_physical,
 
367
                                                &(*qp)->send.nodnic_ring.map);
 
368
        MLX_FATAL_CHECK_STATUS(status, send_map_err,
 
369
                                "send wq map error");
 
370
 
 
371
        status = mlx_memory_map_dma(device_priv->utils,
 
372
                                                (*qp)->receive.wqe_virt,
 
373
                                                receive_wq_size,
 
374
                                                &(*qp)->receive.nodnic_ring.wqe_physical,
 
375
                                                &(*qp)->receive.nodnic_ring.map);
 
376
        MLX_FATAL_CHECK_STATUS(status, receive_map_err,
 
377
                                "receive wq map error");
 
378
 
 
379
        (*qp)->send.nodnic_ring.wq_size = send_wq_size;
 
380
        (*qp)->send.nodnic_ring.num_wqes = send_wqe_num;
 
381
        (*qp)->receive.nodnic_ring.wq_size = receive_wq_size;
 
382
        (*qp)->receive.nodnic_ring.num_wqes = recv_wqe_num;
 
383
 
 
384
        /* Set Ownership bit in Send/receive queue (0 - recv ; 1 - send) */
 
385
        mlx_memory_set(device_priv->utils, (*qp)->send.wqe_virt, 0xff, send_wq_size );
 
386
        mlx_memory_set(device_priv->utils, (*qp)->receive.wqe_virt, 0, recv_wqe_num );
 
387
 
 
388
        /* update send ring */
 
389
#define NODIC_RING_QP_ADDR_HIGH 0x0
 
390
#define NODIC_RING_QP_ADDR_LOW 0x4
 
391
        address = (mlx_uint64)(*qp)->send.nodnic_ring.wqe_physical;
 
392
        status = nodnic_cmd_write(device_priv, (*qp)->send.nodnic_ring.offset +
 
393
                        NODIC_RING_QP_ADDR_HIGH,
 
394
                        (mlx_uint32)(address >> 32));
 
395
        MLX_FATAL_CHECK_STATUS(status, write_send_addr_err,
 
396
                                        "send address write error 1");
 
397
        mlx_utils_ilog2((*qp)->send.nodnic_ring.wq_size, &log_size);
 
398
        address = address | log_size;
 
399
        status = nodnic_cmd_write(device_priv, (*qp)->send.nodnic_ring.offset +
 
400
                        NODIC_RING_QP_ADDR_LOW,
 
401
                                (mlx_uint32)address);
 
402
        MLX_FATAL_CHECK_STATUS(status, write_send_addr_err,
 
403
                                                "send address write error 2");
 
404
        /* update receive ring */
 
405
        address = (mlx_uint64)(*qp)->receive.nodnic_ring.wqe_physical;
 
406
        status = nodnic_cmd_write(device_priv, (*qp)->receive.nodnic_ring.offset +
 
407
                        NODIC_RING_QP_ADDR_HIGH,
 
408
                        (mlx_uint32)(address >> 32));
 
409
        MLX_FATAL_CHECK_STATUS(status, write_recv_addr_err,
 
410
                                                "receive address write error 1");
 
411
        mlx_utils_ilog2((*qp)->receive.nodnic_ring.wq_size, &log_size);
 
412
        address = address | log_size;
 
413
        status = nodnic_cmd_write(device_priv, (*qp)->receive.nodnic_ring.offset +
 
414
                        NODIC_RING_QP_ADDR_LOW,
 
415
                                (mlx_uint32)address);
 
416
        MLX_FATAL_CHECK_STATUS(status, write_recv_addr_err,
 
417
                                                "receive address write error 2");
 
418
 
 
419
        return status;
 
420
write_recv_addr_err:
 
421
write_send_addr_err:
 
422
        mlx_memory_ummap_dma(device_priv->utils, (*qp)->receive.nodnic_ring.map);
 
423
receive_map_err:
 
424
        mlx_memory_ummap_dma(device_priv->utils, (*qp)->send.nodnic_ring.map);
 
425
send_map_err:
 
426
        mlx_memory_free_dma(device_priv->utils, receive_wq_size,
 
427
                        &((*qp)->receive.wqe_virt));
 
428
receive_alloc_err:
 
429
        mlx_memory_free_dma(device_priv->utils, send_wq_size,
 
430
                        (void **)&((*qp)->send.wqe_virt));
 
431
send_alloc_err:
 
432
invalid_type:
 
433
        mlx_memory_free(device_priv->utils, (void **)qp);
 
434
alloc_err:
 
435
invalid_parm:
 
436
        return status;
 
437
}
 
438
 
 
439
mlx_status
 
440
nodnic_port_destroy_qp(
 
441
                                        IN nodnic_port_priv     *port_priv,
 
442
                                        IN nodnic_queue_pair_type       type __attribute__((unused)),
 
443
                                        IN nodnic_qp    *qp
 
444
                                        )
 
445
{
 
446
        mlx_status status = MLX_SUCCESS;
 
447
        nodnic_device_priv *device_priv = port_priv->device;
 
448
 
 
449
        status = mlx_memory_ummap_dma(device_priv->utils,
 
450
                        qp->receive.nodnic_ring.map);
 
451
        if( status != MLX_SUCCESS){
 
452
                MLX_DEBUG_ERROR(device_priv, "mlx_memory_ummap_dma failed (Status = %d)\n", status);
 
453
        }
 
454
 
 
455
        status = mlx_memory_ummap_dma(device_priv->utils, qp->send.nodnic_ring.map);
 
456
        if( status != MLX_SUCCESS){
 
457
                MLX_DEBUG_ERROR(device_priv, "mlx_memory_ummap_dma failed (Status = %d)\n", status);
 
458
        }
 
459
 
 
460
        status = mlx_memory_free_dma(device_priv->utils,
 
461
                        qp->receive.nodnic_ring.wq_size,
 
462
                        (void **)&(qp->receive.wqe_virt));
 
463
        if( status != MLX_SUCCESS){
 
464
                MLX_DEBUG_ERROR(device_priv, "mlx_memory_free_dma failed (Status = %d)\n", status);
 
465
        }
 
466
        status = mlx_memory_free_dma(device_priv->utils,
 
467
                        qp->send.nodnic_ring.wq_size,
 
468
                        (void **)&(qp->send.wqe_virt));
 
469
        if( status != MLX_SUCCESS){
 
470
                MLX_DEBUG_ERROR(device_priv, "mlx_memory_free_dma failed (Status = %d)\n", status);
 
471
        }
 
472
        status = mlx_memory_free(device_priv->utils, (void **)&qp);
 
473
        if( status != MLX_SUCCESS){
 
474
                MLX_DEBUG_ERROR(device_priv, "mlx_memory_free failed (Status = %d)\n", status);
 
475
        }
 
476
        return status;
 
477
}
 
478
 
 
479
mlx_status
 
480
nodnic_port_get_qpn(
 
481
                        IN nodnic_port_priv     *port_priv,
 
482
                        IN struct nodnic_ring  *ring,
 
483
                        OUT mlx_uint32 *qpn
 
484
                        )
 
485
{
 
486
        mlx_status status = MLX_SUCCESS;
 
487
        mlx_uint32 buffer = 0;
 
488
        if( ring == NULL || qpn == NULL){
 
489
                status = MLX_INVALID_PARAMETER;
 
490
                goto bad_param;
 
491
        }
 
492
        if( ring->qpn != 0 ){
 
493
                *qpn = ring->qpn;
 
494
                goto success;
 
495
        }
 
496
#define NODNIC_RING_QPN_OFFSET 0xc
 
497
#define NODNIC_RING_QPN_MASK 0xFFFFFF
 
498
        status = nodnic_cmd_read(port_priv->device,
 
499
                        ring->offset + NODNIC_RING_QPN_OFFSET,
 
500
                        &buffer);
 
501
        MLX_FATAL_CHECK_STATUS(status, read_err,
 
502
                        "nodnic_cmd_read failed");
 
503
        ring->qpn = buffer & NODNIC_RING_QPN_MASK;
 
504
        *qpn = ring->qpn;
 
505
read_err:
 
506
success:
 
507
bad_param:
 
508
        return status;
 
509
}
 
510
 
 
511
#ifdef DEVICE_CX3
 
512
static
 
513
mlx_status
 
514
nodnic_port_send_db_connectx3(
 
515
                IN nodnic_port_priv     *port_priv,
 
516
                IN struct nodnic_ring *ring __attribute__((unused)),
 
517
                IN mlx_uint16 index
 
518
                )
 
519
{
 
520
        nodnic_port_data_flow_gw *ptr = port_priv->data_flow_gw;
 
521
        mlx_uint32 index32 = index;
 
522
        mlx_pci_mem_write(port_priv->device->utils, MlxPciWidthUint32, 0,
 
523
                        (mlx_uint64)&(ptr->send_doorbell), 1, &index32);
 
524
        return MLX_SUCCESS;
 
525
}
 
526
 
 
527
static
 
528
mlx_status
 
529
nodnic_port_recv_db_connectx3(
 
530
                IN nodnic_port_priv     *port_priv,
 
531
                IN struct nodnic_ring *ring __attribute__((unused)),
 
532
                IN mlx_uint16 index
 
533
                )
 
534
{
 
535
        nodnic_port_data_flow_gw *ptr = port_priv->data_flow_gw;
 
536
        mlx_uint32 index32 = index;
 
537
        mlx_pci_mem_write(port_priv->device->utils, MlxPciWidthUint32, 0,
 
538
                        (mlx_uint64)&(ptr->recv_doorbell), 1, &index32);
 
539
        return MLX_SUCCESS;
 
540
}
 
541
#endif
 
542
 
 
543
mlx_status
 
544
nodnic_port_update_ring_doorbell(
 
545
                                        IN nodnic_port_priv     *port_priv,
 
546
                                        IN struct nodnic_ring *ring,
 
547
                                        IN mlx_uint16 index
 
548
                                        )
 
549
{
 
550
        mlx_status status = MLX_SUCCESS;
 
551
        mlx_uint32 buffer = 0;
 
552
        if( ring == NULL ){
 
553
                status = MLX_INVALID_PARAMETER;
 
554
                goto bad_param;
 
555
        }
 
556
#define NODNIC_RING_RING_OFFSET 0x8
 
557
        buffer = (mlx_uint32)((index & 0xFFFF)<< 8);
 
558
        status = nodnic_cmd_write(port_priv->device,
 
559
                                ring->offset + NODNIC_RING_RING_OFFSET,
 
560
                                buffer);
 
561
        MLX_CHECK_STATUS(port_priv->device, status, write_err,
 
562
                                "nodnic_cmd_write failed");
 
563
write_err:
 
564
bad_param:
 
565
        return status;
 
566
}
 
567
 
 
568
mlx_status
 
569
nodnic_port_get_cq_size(
 
570
                IN nodnic_port_priv     *port_priv,
 
571
                OUT mlx_uint64 *cq_size
 
572
                )
 
573
{
 
574
        mlx_status status = MLX_SUCCESS;
 
575
        mlx_uint32 out = 0;
 
576
        status = nodnic_port_query(port_priv, nodnic_port_option_log_cq_size, &out);
 
577
        MLX_FATAL_CHECK_STATUS(status, query_err,
 
578
                        "nodnic_port_query failed");
 
579
        *cq_size = 1 << out;
 
580
query_err:
 
581
        return status;
 
582
}
 
583
 
 
584
mlx_status
 
585
nodnic_port_allocate_eq(
 
586
                                        IN  nodnic_port_priv    *port_priv,
 
587
                                        IN  mlx_uint8                   log_eq_size
 
588
                                        )
 
589
{
 
590
        mlx_status status = MLX_SUCCESS;
 
591
        nodnic_device_priv *device_priv = NULL;
 
592
        mlx_uint64 address = 0;
 
593
 
 
594
        if( port_priv == NULL ){
 
595
                status = MLX_INVALID_PARAMETER;
 
596
                goto bad_param;
 
597
        }
 
598
 
 
599
        device_priv = port_priv->device;
 
600
        port_priv->eq.eq_size = ( ( 1 << log_eq_size ) * 1024 ); /* Size is in KB */
 
601
        status = mlx_memory_alloc_dma(device_priv->utils,
 
602
                                                                port_priv->eq.eq_size,
 
603
                                                                NODNIC_MEMORY_ALIGN,
 
604
                                                                &port_priv->eq.eq_virt);
 
605
        MLX_FATAL_CHECK_STATUS(status, alloc_err,
 
606
                                                        "eq allocation error");
 
607
 
 
608
        status = mlx_memory_map_dma(device_priv->utils,
 
609
                                                        port_priv->eq.eq_virt,
 
610
                                                        port_priv->eq.eq_size,
 
611
                                                        &port_priv->eq.eq_physical,
 
612
                                                        &port_priv->eq.map);
 
613
        MLX_FATAL_CHECK_STATUS(status, map_err,
 
614
                                                                "eq map error");
 
615
 
 
616
        address = port_priv->eq.eq_physical;
 
617
        status = nodnic_port_set(port_priv, nodnic_port_option_eq_addr_low,
 
618
                                                (mlx_uint32)address);
 
619
        MLX_FATAL_CHECK_STATUS(status, set_err,
 
620
                        "failed to set eq addr low");
 
621
        address = (address >> 32);
 
622
        status = nodnic_port_set(port_priv, nodnic_port_option_eq_addr_high,
 
623
                                                (mlx_uint32)address);
 
624
        MLX_FATAL_CHECK_STATUS(status, set_err,
 
625
                                "failed to set eq addr high");
 
626
        return status;
 
627
set_err:
 
628
        mlx_memory_ummap_dma(device_priv->utils, port_priv->eq.map);
 
629
map_err:
 
630
        mlx_memory_free_dma(device_priv->utils,
 
631
                        port_priv->eq.eq_size,
 
632
                        (void **)&(port_priv->eq.eq_virt));
 
633
alloc_err:
 
634
bad_param:
 
635
        return status;
 
636
}
 
637
mlx_status
 
638
nodnic_port_free_eq(
 
639
                                        IN  nodnic_port_priv    *port_priv
 
640
                                        )
 
641
{
 
642
        mlx_status status = MLX_SUCCESS;
 
643
        nodnic_device_priv *device_priv = NULL;
 
644
 
 
645
        if( port_priv == NULL ){
 
646
                status = MLX_INVALID_PARAMETER;
 
647
                goto bad_param;
 
648
        }
 
649
 
 
650
        device_priv = port_priv->device;
 
651
        mlx_memory_ummap_dma(device_priv->utils, port_priv->eq.map);
 
652
 
 
653
        mlx_memory_free_dma(device_priv->utils,
 
654
                        port_priv->eq.eq_size,
 
655
                        (void **)&(port_priv->eq.eq_virt));
 
656
 
 
657
bad_param:
 
658
        return status;
 
659
}
 
660
 
 
661
mlx_status
 
662
nodnic_port_add_mac_filter(
 
663
                                        IN  nodnic_port_priv    *port_priv,
 
664
                                        IN  mlx_mac_address     mac
 
665
                                        )
 
666
{
 
667
        mlx_status status = MLX_SUCCESS;
 
668
        nodnic_device_priv *device= NULL;;
 
669
        mlx_uint8 index = 0;
 
670
        mlx_uint32 out = 0;
 
671
        mlx_uint32 mac_filters_en = 0;
 
672
        mlx_uint32 address = 0;
 
673
        mlx_mac_address zero_mac;
 
674
        mlx_utils *utils = NULL;
 
675
 
 
676
        if( port_priv == NULL){
 
677
                status = MLX_INVALID_PARAMETER;
 
678
                goto bad_param;
 
679
        }
 
680
 
 
681
        memset(&zero_mac, 0, sizeof(zero_mac));
 
682
 
 
683
        device = port_priv->device;
 
684
        utils = device->utils;
 
685
 
 
686
        /* check if mac already exists */
 
687
        for( ; index < NODNIC_MAX_MAC_FILTERS ; index ++) {
 
688
                mlx_memory_cmp(utils, &port_priv->mac_filters[index], &mac,
 
689
                                sizeof(mac), &out);
 
690
                if ( out == 0 ){
 
691
                        status = MLX_FAILED;
 
692
                        goto already_exists;
 
693
                }
 
694
        }
 
695
 
 
696
        /* serch for available mac filter slot */
 
697
        for (index = 0 ; index < NODNIC_MAX_MAC_FILTERS ; index ++) {
 
698
                mlx_memory_cmp(utils, &port_priv->mac_filters[index], &zero_mac,
 
699
                                sizeof(zero_mac), &out);
 
700
                if ( out == 0 ){
 
701
                        break;
 
702
                }
 
703
        }
 
704
        if ( index >= NODNIC_MAX_MAC_FILTERS ){
 
705
                status = MLX_FAILED;
 
706
                goto mac_list_full;
 
707
        }
 
708
 
 
709
        status = nodnic_port_query(port_priv, nodnic_port_option_mac_filters_en,
 
710
                        &mac_filters_en);
 
711
        MLX_CHECK_STATUS(device, status , query_err,
 
712
                        "nodnic_port_query failed");
 
713
        if(mac_filters_en & (1 << index)){
 
714
                status = MLX_FAILED;
 
715
                goto mac_list_full;
 
716
        }
 
717
        port_priv->mac_filters[index] = mac;
 
718
 
 
719
        // set mac filter
 
720
        address = port_priv->port_offset + NODNIC_PORT_MAC_FILTERS_OFFSET +
 
721
                                (0x8 * index);
 
722
 
 
723
        status = nodnic_cmd_write(device, address, mac.high );
 
724
        MLX_CHECK_STATUS(device, status, write_err,     "set mac high failed");
 
725
        status = nodnic_cmd_write(device, address + 0x4, mac.low );
 
726
        MLX_CHECK_STATUS(device, status, write_err, "set mac low failed");
 
727
 
 
728
        // enable mac filter
 
729
        mac_filters_en = mac_filters_en | (1 << index);
 
730
        status = nodnic_port_set(port_priv, nodnic_port_option_mac_filters_en,
 
731
                                mac_filters_en);
 
732
        MLX_CHECK_STATUS(device, status , set_err,
 
733
                        "nodnic_port_set failed");
 
734
set_err:
 
735
write_err:
 
736
query_err:
 
737
mac_list_full:
 
738
already_exists:
 
739
bad_param:
 
740
        return status;
 
741
}
 
742
 
 
743
mlx_status
 
744
nodnic_port_remove_mac_filter(
 
745
                                        IN  nodnic_port_priv    *port_priv,
 
746
                                        IN  mlx_mac_address     mac
 
747
                                        )
 
748
{
 
749
        mlx_status status = MLX_SUCCESS;
 
750
        nodnic_device_priv *device= NULL;;
 
751
        mlx_uint8 index = 0;
 
752
        mlx_uint32 out = 0;
 
753
        mlx_uint32 mac_filters_en = 0;
 
754
        mlx_mac_address zero_mac;
 
755
        mlx_utils *utils = NULL;
 
756
 
 
757
        if( port_priv == NULL){
 
758
                status = MLX_INVALID_PARAMETER;
 
759
                goto bad_param;
 
760
        }
 
761
 
 
762
        memset(&zero_mac, 0, sizeof(zero_mac));
 
763
 
 
764
        device = port_priv->device;
 
765
        utils = device->utils;
 
766
 
 
767
        /* serch for mac filter */
 
768
        for( ; index < NODNIC_MAX_MAC_FILTERS ; index ++) {
 
769
                mlx_memory_cmp(utils, &port_priv->mac_filters[index], &mac,
 
770
                                sizeof(mac), &out);
 
771
                if ( out == 0 ){
 
772
                        break;
 
773
                }
 
774
        }
 
775
        if ( index == NODNIC_MAX_MAC_FILTERS ){
 
776
                status = MLX_FAILED;
 
777
                goto mac_not_found;
 
778
        }
 
779
 
 
780
        status = nodnic_port_query(port_priv, nodnic_port_option_mac_filters_en,
 
781
                        &mac_filters_en);
 
782
        MLX_CHECK_STATUS(device, status , query_err,
 
783
                        "nodnic_port_query failed");
 
784
        if((mac_filters_en & (1 << index)) == 0){
 
785
                status = MLX_FAILED;
 
786
                goto mac_not_en;
 
787
        }
 
788
        port_priv->mac_filters[index] = zero_mac;
 
789
 
 
790
        // disable mac filter
 
791
        mac_filters_en = mac_filters_en & ~(1 << index);
 
792
        status = nodnic_port_set(port_priv, nodnic_port_option_mac_filters_en,
 
793
                                mac_filters_en);
 
794
        MLX_CHECK_STATUS(device, status , set_err,
 
795
                        "nodnic_port_set failed");
 
796
set_err:
 
797
query_err:
 
798
mac_not_en:
 
799
mac_not_found:
 
800
bad_param:
 
801
        return status;
 
802
}
 
803
 
 
804
static
 
805
mlx_status
 
806
nodnic_port_set_network(
 
807
                IN nodnic_port_priv             *port_priv,
 
808
                IN mlx_boolean                  value
 
809
                )
 
810
{
 
811
        mlx_status status = MLX_SUCCESS;
 
812
        /*mlx_uint32 network_valid = 0;
 
813
        mlx_uint8 try = 0;*/
 
814
 
 
815
        status = nodnic_port_set(port_priv, nodnic_port_option_network_en, value);
 
816
        MLX_CHECK_STATUS(port_priv->device, status, set_err,
 
817
                        "nodnic_port_set failed");
 
818
        port_priv->network_state = value;
 
819
set_err:
 
820
        return status;
 
821
}
 
822
 
 
823
#ifdef DEVICE_CX3
 
824
static
 
825
mlx_status
 
826
nodnic_port_set_dma_connectx3(
 
827
                IN nodnic_port_priv             *port_priv,
 
828
                IN mlx_boolean                  value
 
829
                )
 
830
{
 
831
        mlx_utils *utils = port_priv->device->utils;
 
832
        nodnic_port_data_flow_gw *ptr = port_priv->data_flow_gw;
 
833
        mlx_uint32 data = (value ? 0xffffffff : 0x0);
 
834
        mlx_pci_mem_write(utils, MlxPciWidthUint32, 0,
 
835
                        (mlx_uint64)&(ptr->dma_en), 1, &data);
 
836
        return MLX_SUCCESS;
 
837
}
 
838
#endif
 
839
 
 
840
static
 
841
mlx_status
 
842
nodnic_port_set_dma(
 
843
                IN nodnic_port_priv             *port_priv,
 
844
                IN mlx_boolean                  value
 
845
                )
 
846
{
 
847
        return nodnic_port_set(port_priv, nodnic_port_option_dma_en, value);
 
848
}
 
849
 
 
850
static
 
851
mlx_status
 
852
nodnic_port_check_and_set_dma(
 
853
                IN nodnic_port_priv             *port_priv,
 
854
                IN mlx_boolean                  value
 
855
                )
 
856
{
 
857
        mlx_status status = MLX_SUCCESS;
 
858
        if ( port_priv->dma_state == value ) {
 
859
                MLX_DEBUG_WARN(port_priv->device,
 
860
                                "nodnic_port_check_and_set_dma: already %s\n",
 
861
                                (value ? "enabled" : "disabled"));
 
862
                status = MLX_SUCCESS;
 
863
                goto set_out;
 
864
        }
 
865
 
 
866
        status = port_priv->set_dma(port_priv, value);
 
867
        MLX_CHECK_STATUS(port_priv->device, status, set_err,
 
868
                        "nodnic_port_set failed");
 
869
        port_priv->dma_state = value;
 
870
set_err:
 
871
set_out:
 
872
        return status;
 
873
}
 
874
 
 
875
 
 
876
mlx_status
 
877
nodnic_port_set_promisc(
 
878
                IN nodnic_port_priv             *port_priv,
 
879
                IN mlx_boolean                  value
 
880
                ){
 
881
        mlx_status status = MLX_SUCCESS;
 
882
        mlx_uint32      buffer = value;
 
883
 
 
884
        status = nodnic_port_set(port_priv, nodnic_port_option_port_promisc_en, buffer);
 
885
        MLX_CHECK_STATUS(port_priv->device, status, set_err,
 
886
                        "nodnic_port_set failed");
 
887
set_err:
 
888
        return status;
 
889
}
 
890
 
 
891
mlx_status
 
892
nodnic_port_set_promisc_multicast(
 
893
                IN nodnic_port_priv             *port_priv,
 
894
                IN mlx_boolean                  value
 
895
                ){
 
896
        mlx_status status = MLX_SUCCESS;
 
897
        mlx_uint32      buffer = value;
 
898
 
 
899
        status = nodnic_port_set(port_priv, nodnic_port_option_port_promisc_multicast_en, buffer);
 
900
        MLX_CHECK_STATUS(port_priv->device, status, set_err,
 
901
                        "nodnic_port_set failed");
 
902
set_err:
 
903
        return status;
 
904
}
 
905
 
 
906
mlx_status
 
907
nodnic_port_init(
 
908
                IN nodnic_port_priv             *port_priv
 
909
                )
 
910
{
 
911
        mlx_status status = MLX_SUCCESS;
 
912
 
 
913
        if( port_priv == NULL ){
 
914
                status = MLX_INVALID_PARAMETER;
 
915
                goto bad_param;
 
916
        }
 
917
 
 
918
        status = nodnic_port_set_network(port_priv, TRUE);
 
919
        MLX_FATAL_CHECK_STATUS(status, set_err,
 
920
                                        "nodnic_port_set_network failed");
 
921
set_err:
 
922
bad_param:
 
923
        return status;
 
924
}
 
925
 
 
926
mlx_status
 
927
nodnic_port_close(
 
928
                IN nodnic_port_priv             *port_priv
 
929
                )
 
930
{
 
931
        mlx_status status = MLX_SUCCESS;
 
932
 
 
933
        if( port_priv == NULL ){
 
934
                status = MLX_INVALID_PARAMETER;
 
935
                goto bad_param;
 
936
        }
 
937
 
 
938
        status = nodnic_port_set_network(port_priv, FALSE);
 
939
        MLX_FATAL_CHECK_STATUS(status, set_err,
 
940
                                        "nodnic_port_set_network failed");
 
941
set_err:
 
942
bad_param:
 
943
        return status;
 
944
}
 
945
 
 
946
mlx_status
 
947
nodnic_port_enable_dma(
 
948
                IN nodnic_port_priv             *port_priv
 
949
                )
 
950
{
 
951
        mlx_status status = MLX_SUCCESS;
 
952
 
 
953
        if( port_priv == NULL ){
 
954
                status = MLX_INVALID_PARAMETER;
 
955
                goto bad_param;
 
956
        }
 
957
 
 
958
        status = nodnic_port_check_and_set_dma(port_priv, TRUE);
 
959
        MLX_CHECK_STATUS(port_priv->device, status, set_err,
 
960
                                        "nodnic_port_check_and_set_dma failed");
 
961
set_err:
 
962
bad_param:
 
963
        return status;
 
964
}
 
965
 
 
966
mlx_status
 
967
nodnic_port_disable_dma(
 
968
                IN nodnic_port_priv             *port_priv
 
969
                )
 
970
{
 
971
        mlx_status status = MLX_SUCCESS;
 
972
 
 
973
        if( port_priv == NULL ){
 
974
                status = MLX_INVALID_PARAMETER;
 
975
                goto bad_param;
 
976
        }
 
977
 
 
978
        status = nodnic_port_check_and_set_dma(port_priv, FALSE);
 
979
        MLX_CHECK_STATUS(port_priv->device, status, set_err,
 
980
                                        "nodnic_port_check_and_set_dma failed");
 
981
set_err:
 
982
bad_param:
 
983
        return status;
 
984
}
 
985
 
 
986
mlx_status
 
987
nodnic_port_thin_init(
 
988
                IN nodnic_device_priv   *device_priv,
 
989
                IN nodnic_port_priv             *port_priv,
 
990
                IN mlx_uint8                    port_index
 
991
                )
 
992
{
 
993
        mlx_status status = MLX_SUCCESS;
 
994
        mlx_boolean     reset_needed = 0;
 
995
#ifdef DEVICE_CX3
 
996
        mlx_uint32 offset;
 
997
#endif
 
998
 
 
999
        if( device_priv == NULL || port_priv == NULL || port_index > 1){
 
1000
                status = MLX_INVALID_PARAMETER;
 
1001
                goto invalid_parm;
 
1002
        }
 
1003
 
 
1004
        port_priv->device = device_priv;
 
1005
 
 
1006
        port_priv->port_offset = device_priv->device_offset +
 
1007
                        nodnic_port_offset_table[port_index];
 
1008
 
 
1009
        port_priv->port_num = port_index + 1;
 
1010
 
 
1011
        port_priv->send_doorbell = nodnic_port_update_ring_doorbell;
 
1012
        port_priv->recv_doorbell = nodnic_port_update_ring_doorbell;
 
1013
        port_priv->set_dma = nodnic_port_set_dma;
 
1014
#ifdef DEVICE_CX3
 
1015
        if (device_priv->device_cap.crspace_doorbells) {
 
1016
                status = nodnic_cmd_read(device_priv, (port_priv->port_offset + 0x100),
 
1017
                                &offset);
 
1018
                if (status != MLX_SUCCESS) {
 
1019
                        return status;
 
1020
                } else {
 
1021
                        port_priv->data_flow_gw = (nodnic_port_data_flow_gw *)
 
1022
                                        (device_priv->utils->config + offset);
 
1023
                }
 
1024
                if ( nodnic_port_set ( port_priv, nodnic_port_option_crspace_en, 1 ) ) {
 
1025
                        return MLX_FAILED;
 
1026
                }
 
1027
                port_priv->send_doorbell = nodnic_port_send_db_connectx3;
 
1028
                port_priv->recv_doorbell = nodnic_port_recv_db_connectx3;
 
1029
                port_priv->set_dma = nodnic_port_set_dma_connectx3;
 
1030
        }
 
1031
#endif
 
1032
        /* clear reset_needed */
 
1033
        nodnic_port_read_reset_needed(port_priv, &reset_needed);
 
1034
 
 
1035
        port_priv->port_type = NODNIC_PORT_TYPE_UNKNOWN;
 
1036
invalid_parm:
 
1037
        return status;
 
1038
}