[golan] Add Connect-IB, ConnectX-4 and ConnectX-4 Lx (Infiniband) support
[ipxe.git] / src / drivers / infiniband / mlx_nodnic / src / mlx_port.c
1 /*
2 * Copyright (C) 2015 Mellanox Technologies Ltd.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 * 02110-1301, USA.
18 */
19
20 FILE_LICENCE ( GPL2_OR_LATER );
21
22 #include "../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 }