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 #ifndef DEVICE_CX3
59 		PortDataEntry(nodnic_port_option_arm_cq, 0x78, 8, 0xffffff),
60 #else
61 		PortDataEntry(nodnic_port_option_arm_cq, 0x78, 8, 0xffff),
62 #endif
63 		PortDataEntry(nodnic_port_option_port_promisc_multicast_en, 0x4, 28, 0x1),
64 #ifdef DEVICE_CX3
65 		PortDataEntry(nodnic_port_option_crspace_en, 0x4, 27, 0x1),
66 #endif
67 		PortDataEntry(nodnic_port_option_send_ring0_uar_index, 0x108, 0, 0xFFFFFFFF),
68 		PortDataEntry(nodnic_port_option_send_ring1_uar_index, 0x10c, 0, 0xFFFFFFFF),
69 		PortDataEntry(nodnic_port_option_cq_n_index, 0x118, 0, 0xFFFFFF),
70 };
71 
72 #define MAX_QP_DATA_ENTRIES 5
73 struct nodnic_qp_data_entry nodnic_qp_data_teable[MAX_QP_DATA_ENTRIES] = {
74 		QpDataEntry(NODNIC_QPT_SMI, 0, 0),
75 		QpDataEntry(NODNIC_QPT_GSI, 0, 0),
76 		QpDataEntry(NODNIC_QPT_UD, 0, 0),
77 		QpDataEntry(NODNIC_QPT_RC, 0, 0),
78 		QpDataEntry(NODNIC_QPT_ETH, 0x80, 0xC0),
79 };
80 
81 #define MAX_NODNIC_PORTS 2
82 int nodnic_port_offset_table[MAX_NODNIC_PORTS] = {
83 	0x100, //port 1 offset
84 	0x280, //port 1 offset
85 };
86 
87 mlx_status
nodnic_port_get_state(IN nodnic_port_priv * port_priv,OUT nodnic_port_state * state)88 nodnic_port_get_state(
89 					IN  nodnic_port_priv	*port_priv,
90 					OUT nodnic_port_state			*state
91 					)
92 {
93 	mlx_status status = MLX_SUCCESS;
94 	mlx_uint32 out = 0;
95 
96 	status = nodnic_port_query(port_priv,
97 			nodnic_port_option_port_state, &out);
98 	MLX_CHECK_STATUS(port_priv->device, status, query_err,
99 			"nodnic_port_query failed");
100 	*state = (nodnic_port_state)out;
101 query_err:
102 	return status;
103 }
104 mlx_status
nodnic_port_get_type(IN nodnic_port_priv * port_priv,OUT nodnic_port_type * type)105 nodnic_port_get_type(
106 					IN  nodnic_port_priv	*port_priv,
107 					OUT nodnic_port_type	*type
108 					)
109 {
110 	mlx_status status = MLX_SUCCESS;
111 	mlx_uint32 out = 0;
112 
113 	if ( port_priv->port_type == NODNIC_PORT_TYPE_UNKNOWN){
114 		status = nodnic_port_query(port_priv,
115 				nodnic_port_option_link_type, &out);
116 		MLX_FATAL_CHECK_STATUS(status, query_err,
117 				"nodnic_port_query failed");
118 		port_priv->port_type = (nodnic_port_type)out;
119 	}
120 	*type = port_priv->port_type;
121 query_err:
122 	return status;
123 }
124 
125 mlx_status
nodnic_port_query(IN nodnic_port_priv * port_priv,IN nodnic_port_option option,OUT mlx_uint32 * out)126 nodnic_port_query(
127 					IN  nodnic_port_priv	*port_priv,
128 					IN  nodnic_port_option		option,
129 					OUT	mlx_uint32				*out
130 					)
131 {
132 	mlx_status 				status = MLX_SUCCESS;
133 	nodnic_device_priv		*device_priv = NULL;
134 	struct nodnic_port_data_entry *data_entry;
135 	mlx_uint32				buffer = 0;
136 	if( port_priv == NULL || out == NULL){
137 		status = MLX_INVALID_PARAMETER;
138 		goto invalid_parm;
139 	}
140 	device_priv = port_priv->device;
141 
142 	data_entry = &nodnic_port_data_table[option];
143 
144 	status = nodnic_cmd_read(device_priv,
145 			port_priv->port_offset + data_entry->offset , &buffer);
146 	MLX_CHECK_STATUS(device_priv, status, read_err,
147 			"nodnic_cmd_read failed");
148 	*out = (buffer >> data_entry->align) & data_entry->mask;
149 read_err:
150 invalid_parm:
151 	return status;
152 }
153 
154 mlx_status
nodnic_port_set(IN nodnic_port_priv * port_priv,IN nodnic_port_option option,IN mlx_uint32 in)155 nodnic_port_set(
156 					IN  nodnic_port_priv	*port_priv,
157 					IN  nodnic_port_option		option,
158 					IN	mlx_uint32				in
159 					)
160 {
161 	mlx_status 				status = MLX_SUCCESS;
162 	nodnic_device_priv		*device_priv = NULL;
163 	struct nodnic_port_data_entry *data_entry;
164 	mlx_uint32				buffer = 0;
165 
166 	if( port_priv == NULL ){
167 		MLX_DEBUG_FATAL_ERROR("port_priv is NULL\n");
168 		status = MLX_INVALID_PARAMETER;
169 		goto invalid_parm;
170 	}
171 	device_priv = port_priv->device;
172 	data_entry = &nodnic_port_data_table[option];
173 
174 	if( in > data_entry->mask ){
175 		MLX_DEBUG_FATAL_ERROR("in > data_entry->mask (%d > %d)\n",
176 				in, data_entry->mask);
177 		status = MLX_INVALID_PARAMETER;
178 		goto invalid_parm;
179 	}
180 	status = nodnic_cmd_read(device_priv,
181 			port_priv->port_offset + data_entry->offset, &buffer);
182 	MLX_FATAL_CHECK_STATUS(status, read_err,
183 			"nodnic_cmd_read failed");
184 	buffer = buffer & ~(data_entry->mask << data_entry->align);
185 	buffer = buffer | (in << data_entry->align);
186 	status = nodnic_cmd_write(device_priv,
187 			port_priv->port_offset + data_entry->offset, buffer);
188 	MLX_FATAL_CHECK_STATUS(status, write_err,
189 			"nodnic_cmd_write failed");
190 write_err:
191 read_err:
192 invalid_parm:
193 	return status;
194 }
195 
196 mlx_status
nodnic_port_set_send_uar_offset(IN nodnic_port_priv * port_priv)197 nodnic_port_set_send_uar_offset(
198 		IN  nodnic_port_priv	*port_priv
199 		)
200 {
201 	mlx_status status = MLX_SUCCESS;
202 	mlx_uint32 out = 0;
203 
204 	if  ( ! port_priv->device->device_cap.support_uar_tx_db ) {
205 		MLX_DEBUG_INFO1 ( port_priv, "nodnic_port_set_send_uar_offset: tx db using uar is not supported \n");
206 		status = MLX_UNSUPPORTED;
207 		goto uar_not_supported;
208    }
209 
210 	status = nodnic_port_query(port_priv,
211 			nodnic_port_option_send_ring0_uar_index, &out);
212 	MLX_CHECK_STATUS(port_priv->device, status, query_err,
213 			"nodnic_port_query failed");
214 	port_priv->device->uar.offset = out << port_priv->device->device_cap.log_uar_page_size;
215 uar_not_supported:
216 query_err:
217 	return status;
218 }
219 
220 mlx_status
nodnic_port_read_reset_needed(IN nodnic_port_priv * port_priv,OUT mlx_boolean * reset_needed)221 nodnic_port_read_reset_needed(
222 						IN nodnic_port_priv		*port_priv,
223 						OUT mlx_boolean			*reset_needed
224 						)
225 {
226 	mlx_status status = MLX_SUCCESS;
227 	mlx_uint32 out = 0;
228 	status = nodnic_port_query(port_priv,
229 			nodnic_port_option_reset_needed, &out);
230 	MLX_CHECK_STATUS(port_priv->device, status, query_err,
231 			"nodnic_port_query failed");
232 	*reset_needed = (mlx_boolean)out;
233 query_err:
234 	return status;
235 }
236 
237 mlx_status
nodnic_port_read_port_management_change_event(IN nodnic_port_priv * port_priv,OUT mlx_boolean * change_event)238 nodnic_port_read_port_management_change_event(
239 						IN nodnic_port_priv		*port_priv,
240 						OUT mlx_boolean			*change_event
241 						)
242 {
243 	mlx_status status = MLX_SUCCESS;
244 	mlx_uint32 out = 0;
245 	status = nodnic_port_query(port_priv,
246 			nodnic_port_option_port_management_change_event, &out);
247 	MLX_CHECK_STATUS(port_priv->device, status, query_err,
248 			"nodnic_port_query failed");
249 	*change_event = (mlx_boolean)out;
250 query_err:
251 	return status;
252 }
253 
254 static
255 mlx_status
nodnic_port_allocate_dbr_dma(IN nodnic_port_priv * port_priv,IN struct nodnic_doorbell * nodnic_db,IN mlx_uint32 dbr_addr_low_ofst,IN mlx_uint32 dbr_addr_high_ofst,IN void ** dbr_addr,IN mlx_size size,IN void ** map)256 nodnic_port_allocate_dbr_dma (
257 		IN nodnic_port_priv	*port_priv,
258 		IN struct nodnic_doorbell	*nodnic_db,
259 		IN mlx_uint32	dbr_addr_low_ofst,
260 		IN mlx_uint32	dbr_addr_high_ofst,
261 		IN void	**dbr_addr,
262 		IN mlx_size	size,
263 		IN void	**map
264 		)
265 {
266 	mlx_status status = MLX_SUCCESS;
267 	mlx_uint64 address = 0;
268 	nodnic_device_priv *device_priv = NULL;
269 
270 	if( port_priv == NULL || nodnic_db == NULL ){
271 			status = MLX_INVALID_PARAMETER;
272 			goto invalid_parm;
273 	}
274 
275 	device_priv = port_priv->device;
276 	status = mlx_memory_alloc_dma(device_priv->utils,
277 					size,
278 					NODNIC_MEMORY_ALIGN,
279 					(void **)dbr_addr
280 					);
281 	MLX_FATAL_CHECK_STATUS(status, alloc_db_record_err,
282 				"doorbell record dma allocation error");
283 
284 	status = mlx_memory_map_dma(device_priv->utils,
285 					(void *)(*dbr_addr),
286 					size,
287 					&nodnic_db->doorbell_physical,
288 					map//nodnic_ring->map
289 					);
290 	MLX_FATAL_CHECK_STATUS(status, map_db_record_err,
291 				"doorbell record map dma error");
292 
293 	address = (mlx_uint64)nodnic_db->doorbell_physical;
294 	status = nodnic_cmd_write(device_priv,
295 				dbr_addr_low_ofst,
296 				(mlx_uint32)address);
297 	MLX_FATAL_CHECK_STATUS(status, set_err,
298 			"failed to set doorbell addr low");
299 
300 	address = address >> 32;
301 	status = nodnic_cmd_write(device_priv,
302 				dbr_addr_high_ofst,
303 				(mlx_uint32)address);
304 	MLX_FATAL_CHECK_STATUS(status, set_err,
305 			"failed to set doorbell addr high");
306 
307 	return status;
308 
309 set_err:
310 	mlx_memory_ummap_dma(device_priv->utils, *map);
311 map_db_record_err:
312 	mlx_memory_free_dma(device_priv->utils, size,
313 		(void **)dbr_addr);
314 alloc_db_record_err:
315 invalid_parm:
316 	return status;
317 }
318 
319 static
320 mlx_status
nodnic_port_cq_dbr_dma_init(IN nodnic_port_priv * port_priv,OUT nodnic_cq ** cq)321 nodnic_port_cq_dbr_dma_init(
322 		IN nodnic_port_priv	*port_priv,
323 		OUT nodnic_cq	**cq
324 		)
325 {
326 	mlx_status status = MLX_SUCCESS;
327 	nodnic_device_priv *device_priv = NULL;
328 
329 	if( port_priv == NULL ){
330 		status = MLX_INVALID_PARAMETER;
331 		goto invalid_parm;
332 	}
333 
334 	device_priv =  port_priv->device;
335 	if ( ! device_priv->device_cap.support_bar_cq_ctrl ) {
336 		status = MLX_UNSUPPORTED;
337 		goto uar_arm_cq_db_unsupported;
338 	}
339 
340 #define NODNIC_PORT_ARM_CQ_DBR_ADDR_LOW_OFFSET 0x114
341 #define NODNIC_PORT_ARM_CQ_DBR_ADDR_HIGH_OFFSET 0x110
342 
343 	status = nodnic_port_allocate_dbr_dma ( port_priv,&(*cq)->arm_cq_doorbell,
344 			port_priv->port_offset + NODNIC_PORT_ARM_CQ_DBR_ADDR_LOW_OFFSET,
345 			port_priv->port_offset + NODNIC_PORT_ARM_CQ_DBR_ADDR_HIGH_OFFSET,
346 			(void **)&port_priv->arm_cq_doorbell_record ,
347 			sizeof(nodnic_arm_cq_db),
348 			(void **)&((*cq)->arm_cq_doorbell.map));
349 	MLX_FATAL_CHECK_STATUS(status, alloc_dbr_dma_err,
350 				"failed to allocate doorbell record dma");
351 	return status;
352 
353 alloc_dbr_dma_err:
354 uar_arm_cq_db_unsupported:
355 invalid_parm:
356 	return status;
357 }
358 
359 mlx_status
nodnic_port_create_cq(IN nodnic_port_priv * port_priv,IN mlx_size cq_size,OUT nodnic_cq ** cq)360 nodnic_port_create_cq(
361 					IN nodnic_port_priv	*port_priv,
362 					IN mlx_size	cq_size,
363 					OUT nodnic_cq	**cq
364 					)
365 {
366 	mlx_status status = MLX_SUCCESS;
367 	nodnic_device_priv *device_priv = NULL;
368 	mlx_uint64 address = 0;
369 	if( port_priv == NULL || cq == NULL){
370 		status = MLX_INVALID_PARAMETER;
371 		goto invalid_parm;
372 	}
373 
374 	device_priv =  port_priv->device;
375 
376 	status = mlx_memory_zalloc(device_priv->utils,
377 				sizeof(nodnic_cq),(mlx_void **)cq);
378 	MLX_FATAL_CHECK_STATUS(status, alloc_err,
379 			"cq priv allocation error");
380 
381 	(*cq)->cq_size = cq_size;
382 	status = mlx_memory_alloc_dma(device_priv->utils,
383 			(*cq)->cq_size, NODNIC_MEMORY_ALIGN,
384 				&(*cq)->cq_virt);
385 	MLX_FATAL_CHECK_STATUS(status, dma_alloc_err,
386 				"cq allocation error");
387 
388 	status = mlx_memory_map_dma(device_priv->utils,
389 						(*cq)->cq_virt,
390 						(*cq)->cq_size,
391 						&(*cq)->cq_physical,
392 						&(*cq)->map);
393 	MLX_FATAL_CHECK_STATUS(status, cq_map_err,
394 				"cq map error");
395 
396 	status = nodnic_port_cq_dbr_dma_init(port_priv,cq);
397 
398 	/* update cq address */
399 #define NODIC_CQ_ADDR_HIGH 0x68
400 #define NODIC_CQ_ADDR_LOW 0x6c
401 	address = (mlx_uint64)(*cq)->cq_physical;
402 	status = nodnic_port_set(port_priv, nodnic_port_option_cq_addr_low,
403 			(mlx_uint32)(address) >> 12);
404 	MLX_FATAL_CHECK_STATUS(status, dma_set_addr_low_err,
405 					"cq set addr low error");
406 	address = address >> 32;
407 	status = nodnic_port_set(port_priv, nodnic_port_option_cq_addr_high,
408 				(mlx_uint32)address);
409 	MLX_FATAL_CHECK_STATUS(status, dma_set_addr_high_err,
410 						"cq set addr high error");
411 	return status;
412 dma_set_addr_high_err:
413 dma_set_addr_low_err:
414 	mlx_memory_ummap_dma(device_priv->utils, (*cq)->map);
415 cq_map_err:
416 	mlx_memory_free_dma(device_priv->utils, (*cq)->cq_size,
417 			(void **)&((*cq)->cq_virt));
418 dma_alloc_err:
419 	mlx_memory_free(device_priv->utils, (void **)cq);
420 alloc_err:
421 invalid_parm:
422 	return status;
423 }
424 
425 mlx_status
nodnic_port_destroy_cq(IN nodnic_port_priv * port_priv,IN nodnic_cq * cq)426 nodnic_port_destroy_cq(
427 					IN nodnic_port_priv	*port_priv,
428 					IN nodnic_cq	*cq
429 					)
430 {
431 	mlx_status status = MLX_SUCCESS;
432 	nodnic_device_priv *device_priv = NULL;
433 
434 	if( port_priv == NULL || cq == NULL){
435 		status = MLX_INVALID_PARAMETER;
436 		goto invalid_parm;
437 	}
438 	device_priv =  port_priv->device;
439 
440 	if ( device_priv->device_cap.support_bar_cq_ctrl ){
441 			status = mlx_memory_ummap_dma(device_priv->utils,
442 					cq->arm_cq_doorbell.map);
443 			if( status != MLX_SUCCESS){
444 				MLX_DEBUG_ERROR(device_priv, "mlx_memory_ummap_dma failed (Status = %d)\n", status);
445 			}
446 
447 			status = mlx_memory_free_dma(device_priv->utils,
448 					sizeof(nodnic_arm_cq_db),
449 					(void **)&(port_priv->arm_cq_doorbell_record));
450 			if( status != MLX_SUCCESS){
451 				MLX_DEBUG_ERROR(device_priv, "mlx_memory_free_dma failed (Status = %d)\n", status);
452 			}
453 		}
454 
455 	mlx_memory_ummap_dma(device_priv->utils, cq->map);
456 
457 	mlx_memory_free_dma(device_priv->utils, cq->cq_size,
458 			(void **)&(cq->cq_virt));
459 
460 	mlx_memory_free(device_priv->utils, (void **)&cq);
461 invalid_parm:
462 	return status;
463 }
464 
465 static
466 mlx_status
nodnic_port_allocate_ring_db_dma(IN nodnic_port_priv * port_priv,IN struct nodnic_ring * nodnic_ring,IN struct nodnic_doorbell * nodnic_db)467 nodnic_port_allocate_ring_db_dma (
468 		IN nodnic_port_priv	*port_priv,
469 		IN struct nodnic_ring *nodnic_ring,
470 		IN struct nodnic_doorbell *nodnic_db
471 		)
472 {
473 	mlx_status status = MLX_SUCCESS;
474 
475 	if( port_priv == NULL || nodnic_ring == NULL || nodnic_db == NULL ){
476 			status = MLX_INVALID_PARAMETER;
477 			goto invalid_parm;
478 	}
479 #define NODNIC_RING_DBR_ADDR_LOW_OFFSET 0x1C
480 #define NODNIC_RING_DBR_ADDR_HIGH_OFFSET 0x18
481 	status = nodnic_port_allocate_dbr_dma ( port_priv,nodnic_db,
482 			nodnic_ring->offset + NODNIC_RING_DBR_ADDR_LOW_OFFSET,
483 			nodnic_ring->offset + NODNIC_RING_DBR_ADDR_HIGH_OFFSET,
484 			(void **)&nodnic_db->qp_doorbell_record,
485 			sizeof(nodnic_qp_db),
486 			(void **)&nodnic_ring->map );
487 	MLX_FATAL_CHECK_STATUS(status, alloc_dbr_dma_err,
488 			"failed to allocate doorbell record dma");
489 
490 	return status;
491 alloc_dbr_dma_err:
492 invalid_parm:
493 	return status;
494 }
495 
496 static
497 mlx_status
nodnic_port_rx_pi_dma_alloc(IN nodnic_port_priv * port_priv,OUT nodnic_qp ** qp)498 nodnic_port_rx_pi_dma_alloc(
499 		IN nodnic_port_priv	*port_priv,
500 		OUT nodnic_qp	**qp
501 		)
502 {
503 	mlx_status status = MLX_SUCCESS;
504 	nodnic_device_priv *device_priv = NULL;
505 
506 	if( port_priv == NULL || qp == NULL){
507 		status = MLX_INVALID_PARAMETER;
508 		goto invalid_parm;
509 	}
510 
511 	device_priv =  port_priv->device;
512 
513 	if ( ! device_priv->device_cap.support_rx_pi_dma ) {
514 		goto rx_pi_dma_unsupported;
515 	}
516 
517 	if ( device_priv->device_cap.support_rx_pi_dma ) {
518 		status = nodnic_port_allocate_ring_db_dma(port_priv,
519 				&(*qp)->receive.nodnic_ring,&(*qp)->receive.nodnic_ring.recv_doorbell);
520 		MLX_FATAL_CHECK_STATUS(status, dma_alloc_err,
521 				"rx doorbell dma allocation error");
522 	}
523 
524 	return status;
525 
526 dma_alloc_err:
527 rx_pi_dma_unsupported:
528 invalid_parm:
529 	return status;
530 }
531 
532 static
533 mlx_status
nodnic_port_send_db_dma(IN nodnic_port_priv * port_priv,IN struct nodnic_ring * ring,IN mlx_uint16 index)534 nodnic_port_send_db_dma(
535 		IN nodnic_port_priv	*port_priv,
536 		IN struct nodnic_ring *ring,
537 		IN mlx_uint16 index
538 		)
539 {
540 	mlx_uint32 swapped = 0;
541 	mlx_uint32 index32 = index;
542 	mlx_memory_cpu_to_be32(port_priv->device->utils, index32, &swapped);
543 	ring->send_doorbell.qp_doorbell_record->send_db =  swapped;
544 
545 	return MLX_SUCCESS;
546 }
547 
548 static
549 mlx_status
nodnic_port_tx_dbr_dma_init(IN nodnic_port_priv * port_priv,OUT nodnic_qp ** qp)550 nodnic_port_tx_dbr_dma_init(
551 		IN nodnic_port_priv	*port_priv,
552 		OUT nodnic_qp	**qp
553 		)
554 {
555 	mlx_status status = MLX_SUCCESS;
556 	nodnic_device_priv *device_priv = NULL;
557 
558 	if( port_priv == NULL || qp == NULL){
559 		status = MLX_INVALID_PARAMETER;
560 		goto invalid_parm;
561 	}
562 
563 	device_priv =  port_priv->device;
564 
565 	if ( ! device_priv->device_cap.support_uar_tx_db || ! device_priv->uar.offset ) {
566 		status = MLX_UNSUPPORTED;
567 		goto uar_tx_db_unsupported;
568 	}
569 	status = nodnic_port_allocate_ring_db_dma(port_priv,
570 			&(*qp)->send.nodnic_ring,&(*qp)->send.nodnic_ring.send_doorbell);
571 	MLX_FATAL_CHECK_STATUS(status, dma_alloc_err,
572 			"tx doorbell dma allocation error");
573 	port_priv->send_doorbell = nodnic_port_send_db_dma;
574 
575 	return status;
576 
577 dma_alloc_err:
578 uar_tx_db_unsupported:
579 invalid_parm:
580 
581 	return status;
582 }
583 
584 mlx_status
nodnic_port_create_qp(IN nodnic_port_priv * port_priv,IN nodnic_queue_pair_type type,IN mlx_size send_wq_size,IN mlx_uint32 send_wqe_num,IN mlx_size receive_wq_size,IN mlx_uint32 recv_wqe_num,OUT nodnic_qp ** qp)585 nodnic_port_create_qp(
586 					IN nodnic_port_priv	*port_priv,
587 					IN nodnic_queue_pair_type	type,
588 					IN mlx_size	send_wq_size,
589 					IN mlx_uint32 send_wqe_num,
590 					IN mlx_size	receive_wq_size,
591 					IN mlx_uint32 recv_wqe_num,
592 					OUT nodnic_qp	**qp
593 					)
594 {
595 	mlx_status status = MLX_SUCCESS;
596 	nodnic_device_priv *device_priv = NULL;
597 	mlx_uint32 max_ring_size = 0;
598 	mlx_uint64 address = 0;
599 	mlx_uint32 log_size = 0;
600 	if( port_priv == NULL || qp == NULL){
601 		status = MLX_INVALID_PARAMETER;
602 		goto invalid_parm;
603 	}
604 
605 	device_priv =  port_priv->device;
606 	max_ring_size = (1 << device_priv->device_cap.log_max_ring_size);
607 	if( send_wq_size > max_ring_size ||
608 			receive_wq_size > max_ring_size ){
609 		status = MLX_INVALID_PARAMETER;
610 		goto invalid_parm;
611 	}
612 
613 	status = mlx_memory_zalloc(device_priv->utils,
614 			sizeof(nodnic_qp),(mlx_void **)qp);
615 	MLX_FATAL_CHECK_STATUS(status, alloc_err,
616 			"qp allocation error");
617 
618 	if( nodnic_qp_data_teable[type].send_offset == 0 ||
619 			nodnic_qp_data_teable[type].recv_offset == 0){
620 		status = MLX_INVALID_PARAMETER;
621 		goto invalid_type;
622 	}
623 
624 	(*qp)->send.nodnic_ring.offset = port_priv->port_offset +
625 				nodnic_qp_data_teable[type].send_offset;
626 	(*qp)->receive.nodnic_ring.offset = port_priv->port_offset +
627 			nodnic_qp_data_teable[type].recv_offset;
628 
629 	status = mlx_memory_alloc_dma(device_priv->utils,
630 			send_wq_size, NODNIC_MEMORY_ALIGN,
631 			(void*)&(*qp)->send.wqe_virt);
632 	MLX_FATAL_CHECK_STATUS(status, send_alloc_err,
633 				"send wq allocation error");
634 
635 	status = mlx_memory_alloc_dma(device_priv->utils,
636 				receive_wq_size, NODNIC_MEMORY_ALIGN,
637 				&(*qp)->receive.wqe_virt);
638 	MLX_FATAL_CHECK_STATUS(status, receive_alloc_err,
639 				"receive wq allocation error");
640 
641 	status = mlx_memory_map_dma(device_priv->utils,
642 						(*qp)->send.wqe_virt,
643 						send_wq_size,
644 						&(*qp)->send.nodnic_ring.wqe_physical,
645 						&(*qp)->send.nodnic_ring.map);
646 	MLX_FATAL_CHECK_STATUS(status, send_map_err,
647 				"send wq map error");
648 
649 	status = mlx_memory_map_dma(device_priv->utils,
650 						(*qp)->receive.wqe_virt,
651 						receive_wq_size,
652 						&(*qp)->receive.nodnic_ring.wqe_physical,
653 						&(*qp)->receive.nodnic_ring.map);
654 	MLX_FATAL_CHECK_STATUS(status, receive_map_err,
655 				"receive wq map error");
656 
657 	status = nodnic_port_rx_pi_dma_alloc(port_priv,qp);
658 	MLX_FATAL_CHECK_STATUS(status, rx_pi_dma_alloc_err,
659 				"receive db dma error");
660 
661 	status = nodnic_port_tx_dbr_dma_init(port_priv,qp);
662 
663 
664 	(*qp)->send.nodnic_ring.wq_size = send_wq_size;
665 	(*qp)->send.nodnic_ring.num_wqes = send_wqe_num;
666 	(*qp)->receive.nodnic_ring.wq_size = receive_wq_size;
667 	(*qp)->receive.nodnic_ring.num_wqes = recv_wqe_num;
668 
669 	/* Set Ownership bit in Send/receive queue (0 - recv ; 1 - send) */
670 	mlx_memory_set(device_priv->utils, (*qp)->send.wqe_virt, 0xff, send_wq_size );
671 	mlx_memory_set(device_priv->utils, (*qp)->receive.wqe_virt, 0, recv_wqe_num );
672 
673 	/* update send ring */
674 #define NODIC_RING_QP_ADDR_HIGH 0x0
675 #define NODIC_RING_QP_ADDR_LOW 0x4
676 	address = (mlx_uint64)(*qp)->send.nodnic_ring.wqe_physical;
677 	status = nodnic_cmd_write(device_priv, (*qp)->send.nodnic_ring.offset +
678 			NODIC_RING_QP_ADDR_HIGH,
679 			(mlx_uint32)(address >> 32));
680 	MLX_FATAL_CHECK_STATUS(status, write_send_addr_err,
681 					"send address write error 1");
682 	mlx_utils_ilog2((*qp)->send.nodnic_ring.wq_size, &log_size);
683 	address = address | log_size;
684 	status = nodnic_cmd_write(device_priv, (*qp)->send.nodnic_ring.offset +
685 			NODIC_RING_QP_ADDR_LOW,
686 				(mlx_uint32)address);
687 	MLX_FATAL_CHECK_STATUS(status, write_send_addr_err,
688 						"send address write error 2");
689 	/* update receive ring */
690 	address = (mlx_uint64)(*qp)->receive.nodnic_ring.wqe_physical;
691 	status = nodnic_cmd_write(device_priv, (*qp)->receive.nodnic_ring.offset +
692 			NODIC_RING_QP_ADDR_HIGH,
693 			(mlx_uint32)(address >> 32));
694 	MLX_FATAL_CHECK_STATUS(status, write_recv_addr_err,
695 						"receive address write error 1");
696 	mlx_utils_ilog2((*qp)->receive.nodnic_ring.wq_size, &log_size);
697 	address = address | log_size;
698 	status = nodnic_cmd_write(device_priv, (*qp)->receive.nodnic_ring.offset +
699 			NODIC_RING_QP_ADDR_LOW,
700 				(mlx_uint32)address);
701 	MLX_FATAL_CHECK_STATUS(status, write_recv_addr_err,
702 						"receive address write error 2");
703 
704 	return status;
705 write_recv_addr_err:
706 write_send_addr_err:
707 	mlx_memory_ummap_dma(device_priv->utils, (*qp)->receive.nodnic_ring.map);
708 rx_pi_dma_alloc_err:
709 receive_map_err:
710 	mlx_memory_ummap_dma(device_priv->utils, (*qp)->send.nodnic_ring.map);
711 send_map_err:
712 	mlx_memory_free_dma(device_priv->utils, receive_wq_size,
713 			&((*qp)->receive.wqe_virt));
714 receive_alloc_err:
715 	mlx_memory_free_dma(device_priv->utils, send_wq_size,
716 			(void **)&((*qp)->send.wqe_virt));
717 send_alloc_err:
718 invalid_type:
719 	mlx_memory_free(device_priv->utils, (void **)qp);
720 alloc_err:
721 invalid_parm:
722 	return status;
723 }
724 
725 mlx_status
nodnic_port_destroy_qp(IN nodnic_port_priv * port_priv,IN nodnic_queue_pair_type type,IN nodnic_qp * qp)726 nodnic_port_destroy_qp(
727 					IN nodnic_port_priv	*port_priv,
728 					IN nodnic_queue_pair_type	type __attribute__((unused)),
729 					IN nodnic_qp	*qp
730 					)
731 {
732 	mlx_status status = MLX_SUCCESS;
733 	nodnic_device_priv *device_priv = port_priv->device;
734 
735 	status = mlx_memory_ummap_dma(device_priv->utils,
736 			qp->receive.nodnic_ring.map);
737 	if( status != MLX_SUCCESS){
738 		MLX_DEBUG_ERROR(device_priv, "mlx_memory_ummap_dma failed (Status = %d)\n", status);
739 	}
740 
741 	status = mlx_memory_ummap_dma(device_priv->utils, qp->send.nodnic_ring.map);
742 	if( status != MLX_SUCCESS){
743 		MLX_DEBUG_ERROR(device_priv, "mlx_memory_ummap_dma failed (Status = %d)\n", status);
744 	}
745 
746 	if ( device_priv->device_cap.support_rx_pi_dma ){
747 		status = mlx_memory_ummap_dma(device_priv->utils,
748 					qp->receive.nodnic_ring.recv_doorbell.map);
749 		if( status != MLX_SUCCESS){
750 			MLX_DEBUG_ERROR(device_priv, "mlx_memory_ummap_dma failed (Status = %d)\n", status);
751 		}
752 
753 		status = mlx_memory_free_dma(device_priv->utils,
754 				sizeof(nodnic_qp_db),
755 				(void **)&(qp->receive.nodnic_ring.recv_doorbell.qp_doorbell_record));
756 		if( status != MLX_SUCCESS){
757 			MLX_DEBUG_ERROR(device_priv, "mlx_memory_free_dma failed (Status = %d)\n", status);
758 		}
759 	}
760 
761 	if ( device_priv->device_cap.support_uar_tx_db || ! device_priv->uar.offset){
762 		status = mlx_memory_ummap_dma(device_priv->utils,
763 					qp->send.nodnic_ring.send_doorbell.map);
764 		if( status != MLX_SUCCESS){
765 			MLX_DEBUG_ERROR(device_priv, "mlx_memory_ummap_dma failed (Status = %d)\n", status);
766 		}
767 
768 		status = mlx_memory_free_dma(device_priv->utils,
769 				sizeof(nodnic_qp_db),
770 				(void **)&(qp->send.nodnic_ring.send_doorbell.qp_doorbell_record));
771 		if( status != MLX_SUCCESS){
772 			MLX_DEBUG_ERROR(device_priv, "mlx_memory_free_dma failed (Status = %d)\n", status);
773 		}
774 	}
775 
776 	status = mlx_memory_free_dma(device_priv->utils,
777 			qp->receive.nodnic_ring.wq_size,
778 			(void **)&(qp->receive.wqe_virt));
779 	if( status != MLX_SUCCESS){
780 		MLX_DEBUG_ERROR(device_priv, "mlx_memory_free_dma failed (Status = %d)\n", status);
781 	}
782 	status = mlx_memory_free_dma(device_priv->utils,
783 			qp->send.nodnic_ring.wq_size,
784 			(void **)&(qp->send.wqe_virt));
785 	if( status != MLX_SUCCESS){
786 		MLX_DEBUG_ERROR(device_priv, "mlx_memory_free_dma failed (Status = %d)\n", status);
787 	}
788 	status = mlx_memory_free(device_priv->utils, (void **)&qp);
789 	if( status != MLX_SUCCESS){
790 		MLX_DEBUG_ERROR(device_priv, "mlx_memory_free failed (Status = %d)\n", status);
791 	}
792 	return status;
793 }
794 
795 mlx_status
nodnic_port_get_qpn(IN nodnic_port_priv * port_priv,IN struct nodnic_ring * ring,OUT mlx_uint32 * qpn)796 nodnic_port_get_qpn(
797 			IN nodnic_port_priv	*port_priv,
798 			IN struct nodnic_ring  *ring,
799 			OUT mlx_uint32 *qpn
800 			)
801 {
802 	mlx_status status = MLX_SUCCESS;
803 	mlx_uint32 buffer = 0;
804 	if( ring == NULL || qpn == NULL){
805 		status = MLX_INVALID_PARAMETER;
806 		goto bad_param;
807 	}
808 	if( ring->qpn != 0 ){
809 		*qpn = ring->qpn;
810 		goto success;
811 	}
812 #define NODNIC_RING_QPN_OFFSET 0xc
813 #define NODNIC_RING_QPN_MASK 0xFFFFFF
814 	status = nodnic_cmd_read(port_priv->device,
815 			ring->offset + NODNIC_RING_QPN_OFFSET,
816 			&buffer);
817 	MLX_FATAL_CHECK_STATUS(status, read_err,
818 			"nodnic_cmd_read failed");
819 	ring->qpn = buffer & NODNIC_RING_QPN_MASK;
820 	*qpn = ring->qpn;
821 read_err:
822 success:
823 bad_param:
824 	return status;
825 }
826 
827 #ifdef DEVICE_CX3
828 static
829 mlx_status
nodnic_port_send_db_connectx3(IN nodnic_port_priv * port_priv,IN struct nodnic_ring * ring,IN mlx_uint16 index)830 nodnic_port_send_db_connectx3(
831 		IN nodnic_port_priv	*port_priv,
832 		IN struct nodnic_ring *ring __attribute__((unused)),
833 		IN mlx_uint16 index
834 		)
835 {
836 	nodnic_port_data_flow_gw *ptr = port_priv->data_flow_gw;
837 	mlx_uint32 index32 = index;
838 	mlx_pci_mem_write(port_priv->device->utils, MlxPciWidthUint32, 0,
839 			(mlx_uintn)&(ptr->send_doorbell), 1, &index32);
840 	return MLX_SUCCESS;
841 }
842 
843 static
844 mlx_status
nodnic_port_recv_db_connectx3(IN nodnic_port_priv * port_priv,IN struct nodnic_ring * ring,IN mlx_uint16 index)845 nodnic_port_recv_db_connectx3(
846 		IN nodnic_port_priv	*port_priv,
847 		IN struct nodnic_ring *ring __attribute__((unused)),
848 		IN mlx_uint16 index
849 		)
850 {
851 	nodnic_port_data_flow_gw *ptr = port_priv->data_flow_gw;
852 	mlx_uint32 index32 = index;
853 	mlx_pci_mem_write(port_priv->device->utils, MlxPciWidthUint32, 0,
854 			(mlx_uintn)&(ptr->recv_doorbell), 1, &index32);
855 	return MLX_SUCCESS;
856 }
857 #endif
858 static
859 mlx_status
nodnic_port_recv_db_dma(IN nodnic_port_priv * port_priv,IN struct nodnic_ring * ring,IN mlx_uint16 index)860 nodnic_port_recv_db_dma(
861 		IN nodnic_port_priv	*port_priv __attribute__((unused)),
862 		IN struct nodnic_ring *ring,
863 		IN mlx_uint16 index
864 		)
865 {
866 	mlx_uint32 swapped = 0;
867 	mlx_uint32 index32 = index;
868 	mlx_memory_cpu_to_be32(port_priv->device->utils, index32, &swapped);
869 	ring->recv_doorbell.qp_doorbell_record->recv_db =  swapped;
870 	return MLX_SUCCESS;
871 }
872 
873 mlx_status
nodnic_port_update_ring_doorbell(IN nodnic_port_priv * port_priv,IN struct nodnic_ring * ring,IN mlx_uint16 index)874 nodnic_port_update_ring_doorbell(
875 					IN nodnic_port_priv	*port_priv,
876 					IN struct nodnic_ring *ring,
877 					IN mlx_uint16 index
878 					)
879 {
880 	mlx_status status = MLX_SUCCESS;
881 	mlx_uint32 buffer = 0;
882 	if( ring == NULL ){
883 		status = MLX_INVALID_PARAMETER;
884 		goto bad_param;
885 	}
886 #define NODNIC_RING_RING_OFFSET 0x8
887 	buffer = (mlx_uint32)((index & 0xFFFF)<< 8);
888 	status = nodnic_cmd_write(port_priv->device,
889 				ring->offset + NODNIC_RING_RING_OFFSET,
890 				buffer);
891 	MLX_CHECK_STATUS(port_priv->device, status, write_err,
892 				"nodnic_cmd_write failed");
893 write_err:
894 bad_param:
895 	return status;
896 }
897 
898 mlx_status
nodnic_port_get_cq_size(IN nodnic_port_priv * port_priv,OUT mlx_uint64 * cq_size)899 nodnic_port_get_cq_size(
900 		IN nodnic_port_priv	*port_priv,
901 		OUT mlx_uint64 *cq_size
902 		)
903 {
904 	mlx_status status = MLX_SUCCESS;
905 	mlx_uint32 out = 0;
906 	status = nodnic_port_query(port_priv, nodnic_port_option_log_cq_size, &out);
907 	MLX_FATAL_CHECK_STATUS(status, query_err,
908 			"nodnic_port_query failed");
909 	*cq_size = 1 << out;
910 query_err:
911 	return status;
912 }
913 
914 mlx_status
nodnic_port_allocate_eq(IN nodnic_port_priv * port_priv,IN mlx_uint8 log_eq_size)915 nodnic_port_allocate_eq(
916 					IN  nodnic_port_priv	*port_priv,
917 					IN  mlx_uint8			log_eq_size
918 					)
919 {
920 	mlx_status status = MLX_SUCCESS;
921 	nodnic_device_priv *device_priv = NULL;
922 	mlx_uint64 address = 0;
923 
924 	if( port_priv == NULL ){
925 		status = MLX_INVALID_PARAMETER;
926 		goto bad_param;
927 	}
928 
929 	device_priv = port_priv->device;
930 	port_priv->eq.eq_size = ( ( 1 << log_eq_size ) * 1024 ); /* Size is in KB */
931 	status = mlx_memory_alloc_dma(device_priv->utils,
932 								port_priv->eq.eq_size,
933 								NODNIC_MEMORY_ALIGN,
934 								&port_priv->eq.eq_virt);
935 	MLX_FATAL_CHECK_STATUS(status, alloc_err,
936 							"eq allocation error");
937 
938 	status = mlx_memory_map_dma(device_priv->utils,
939 							port_priv->eq.eq_virt,
940 							port_priv->eq.eq_size,
941 							&port_priv->eq.eq_physical,
942 							&port_priv->eq.map);
943 	MLX_FATAL_CHECK_STATUS(status, map_err,
944 								"eq map error");
945 
946 	address = port_priv->eq.eq_physical;
947 	status = nodnic_port_set(port_priv, nodnic_port_option_eq_addr_low,
948 						(mlx_uint32)address);
949 	MLX_FATAL_CHECK_STATUS(status, set_err,
950 			"failed to set eq addr low");
951 	address = (address >> 32);
952 	status = nodnic_port_set(port_priv, nodnic_port_option_eq_addr_high,
953 						(mlx_uint32)address);
954 	MLX_FATAL_CHECK_STATUS(status, set_err,
955 				"failed to set eq addr high");
956 	return status;
957 set_err:
958 	mlx_memory_ummap_dma(device_priv->utils, port_priv->eq.map);
959 map_err:
960 	mlx_memory_free_dma(device_priv->utils,
961 			port_priv->eq.eq_size,
962 			(void **)&(port_priv->eq.eq_virt));
963 alloc_err:
964 bad_param:
965 	return status;
966 }
967 mlx_status
nodnic_port_free_eq(IN nodnic_port_priv * port_priv)968 nodnic_port_free_eq(
969 					IN  nodnic_port_priv	*port_priv
970 					)
971 {
972 	mlx_status status = MLX_SUCCESS;
973 	nodnic_device_priv *device_priv = NULL;
974 
975 	if( port_priv == NULL ){
976 		status = MLX_INVALID_PARAMETER;
977 		goto bad_param;
978 	}
979 
980 	device_priv = port_priv->device;
981 	mlx_memory_ummap_dma(device_priv->utils, port_priv->eq.map);
982 
983 	mlx_memory_free_dma(device_priv->utils,
984 			port_priv->eq.eq_size,
985 			(void **)&(port_priv->eq.eq_virt));
986 
987 bad_param:
988 	return status;
989 }
990 
991 mlx_status
nodnic_port_add_mac_filter(IN nodnic_port_priv * port_priv,IN mlx_mac_address mac)992 nodnic_port_add_mac_filter(
993 					IN  nodnic_port_priv	*port_priv,
994 					IN  mlx_mac_address 	mac
995 					)
996 {
997 	mlx_status status = MLX_SUCCESS;
998 	nodnic_device_priv *device= NULL;;
999 	mlx_uint8 index = 0;
1000 	mlx_uint32 out = 0;
1001 	mlx_uint32 mac_filters_en = 0;
1002 	mlx_uint32 address = 0;
1003 	mlx_mac_address zero_mac;
1004 	mlx_utils *utils = NULL;
1005 
1006 	if( port_priv == NULL){
1007 		status = MLX_INVALID_PARAMETER;
1008 		goto bad_param;
1009 	}
1010 
1011 	device = port_priv->device;
1012 	utils = device->utils;
1013 
1014 	mlx_memory_set(utils, &zero_mac, 0, sizeof(zero_mac));
1015 	/* check if mac already exists */
1016 	for( ; index < NODNIC_MAX_MAC_FILTERS ; index ++) {
1017 		mlx_memory_cmp(utils, &port_priv->mac_filters[index], &mac,
1018 				sizeof(mac), &out);
1019 		if ( out == 0 ){
1020 			status = MLX_FAILED;
1021 			goto already_exists;
1022 		}
1023 	}
1024 
1025 	/* serch for available mac filter slot */
1026 	for (index = 0 ; index < NODNIC_MAX_MAC_FILTERS ; index ++) {
1027 		mlx_memory_cmp(utils, &port_priv->mac_filters[index], &zero_mac,
1028 				sizeof(zero_mac), &out);
1029 		if ( out == 0 ){
1030 			break;
1031 		}
1032 	}
1033 	if ( index >= NODNIC_MAX_MAC_FILTERS ){
1034 		status = MLX_FAILED;
1035 		goto mac_list_full;
1036 	}
1037 
1038 	status = nodnic_port_query(port_priv, nodnic_port_option_mac_filters_en,
1039 			&mac_filters_en);
1040 	MLX_CHECK_STATUS(device, status , query_err,
1041 			"nodnic_port_query failed");
1042 	if(mac_filters_en & (1 << index)){
1043 		status = MLX_FAILED;
1044 		goto mac_list_full;
1045 	}
1046 	port_priv->mac_filters[index] = mac;
1047 
1048 	// set mac filter
1049 	address = port_priv->port_offset + NODNIC_PORT_MAC_FILTERS_OFFSET +
1050 				(0x8 * index);
1051 
1052 	status = nodnic_cmd_write(device, address, mac.high );
1053 	MLX_CHECK_STATUS(device, status, write_err,	"set mac high failed");
1054 	status = nodnic_cmd_write(device, address + 0x4, mac.low );
1055 	MLX_CHECK_STATUS(device, status, write_err, "set mac low failed");
1056 
1057 	// enable mac filter
1058 	mac_filters_en = mac_filters_en | (1 << index);
1059 	status = nodnic_port_set(port_priv, nodnic_port_option_mac_filters_en,
1060 				mac_filters_en);
1061 	MLX_CHECK_STATUS(device, status , set_err,
1062 			"nodnic_port_set failed");
1063 set_err:
1064 write_err:
1065 query_err:
1066 mac_list_full:
1067 already_exists:
1068 bad_param:
1069 	return status;
1070 }
1071 
1072 mlx_status
nodnic_port_remove_mac_filter(IN nodnic_port_priv * port_priv,IN mlx_mac_address mac)1073 nodnic_port_remove_mac_filter(
1074 					IN  nodnic_port_priv	*port_priv,
1075 					IN  mlx_mac_address 	mac
1076 					)
1077 {
1078 	mlx_status status = MLX_SUCCESS;
1079 	nodnic_device_priv *device= NULL;;
1080 	mlx_uint8 index = 0;
1081 	mlx_uint32 out = 0;
1082 	mlx_uint32 mac_filters_en = 0;
1083 	mlx_mac_address zero_mac;
1084 	mlx_utils *utils = NULL;
1085 
1086 	if( port_priv == NULL){
1087 		status = MLX_INVALID_PARAMETER;
1088 		goto bad_param;
1089 	}
1090 
1091 	device = port_priv->device;
1092 	utils = device->utils;
1093 
1094 	mlx_memory_set(utils, &zero_mac, 0, sizeof(zero_mac));
1095 	/* serch for mac filter */
1096 	for( ; index < NODNIC_MAX_MAC_FILTERS ; index ++) {
1097 		mlx_memory_cmp(utils, &port_priv->mac_filters[index], &mac,
1098 				sizeof(mac), &out);
1099 		if ( out == 0 ){
1100 			break;
1101 		}
1102 	}
1103 	if ( index == NODNIC_MAX_MAC_FILTERS ){
1104 		status = MLX_FAILED;
1105 		goto mac_not_found;
1106 	}
1107 
1108 	status = nodnic_port_query(port_priv, nodnic_port_option_mac_filters_en,
1109 			&mac_filters_en);
1110 	MLX_CHECK_STATUS(device, status , query_err,
1111 			"nodnic_port_query failed");
1112 	if((mac_filters_en & (1 << index)) == 0){
1113 		status = MLX_FAILED;
1114 		goto mac_not_en;
1115 	}
1116 	port_priv->mac_filters[index] = zero_mac;
1117 
1118 	// disable mac filter
1119 	mac_filters_en = mac_filters_en & ~(1 << index);
1120 	status = nodnic_port_set(port_priv, nodnic_port_option_mac_filters_en,
1121 				mac_filters_en);
1122 	MLX_CHECK_STATUS(device, status , set_err,
1123 			"nodnic_port_set failed");
1124 set_err:
1125 query_err:
1126 mac_not_en:
1127 mac_not_found:
1128 bad_param:
1129 	return status;
1130 }
1131 
1132 static
1133 mlx_status
nodnic_port_set_network(IN nodnic_port_priv * port_priv,IN mlx_boolean value)1134 nodnic_port_set_network(
1135 		IN nodnic_port_priv		*port_priv,
1136 		IN mlx_boolean			value
1137 		)
1138 {
1139 	mlx_status status = MLX_SUCCESS;
1140 	/*mlx_uint32 network_valid = 0;
1141 	mlx_uint8 try = 0;*/
1142 
1143 	status = nodnic_port_set(port_priv, nodnic_port_option_network_en, value);
1144 	MLX_CHECK_STATUS(port_priv->device, status, set_err,
1145 			"nodnic_port_set failed");
1146 	port_priv->network_state = value;
1147 set_err:
1148 	return status;
1149 }
1150 
1151 #ifdef DEVICE_CX3
1152 static
1153 mlx_status
nodnic_port_set_dma_connectx3(IN nodnic_port_priv * port_priv,IN mlx_boolean value)1154 nodnic_port_set_dma_connectx3(
1155 		IN nodnic_port_priv		*port_priv,
1156 		IN mlx_boolean			value
1157 		)
1158 {
1159 	mlx_utils *utils = port_priv->device->utils;
1160 	nodnic_port_data_flow_gw *ptr = port_priv->data_flow_gw;
1161 	mlx_uint32 data = (value ? 0xffffffff : 0x0);
1162 	mlx_pci_mem_write(utils, MlxPciWidthUint32, 0,
1163 			(mlx_uintn)&(ptr->dma_en), 1, &data);
1164 	return MLX_SUCCESS;
1165 }
1166 #endif
1167 
1168 static
1169 mlx_status
nodnic_port_set_dma(IN nodnic_port_priv * port_priv,IN mlx_boolean value)1170 nodnic_port_set_dma(
1171 		IN nodnic_port_priv		*port_priv,
1172 		IN mlx_boolean			value
1173 		)
1174 {
1175 	return nodnic_port_set(port_priv, nodnic_port_option_dma_en, value);
1176 }
1177 
1178 static
1179 mlx_status
nodnic_port_check_and_set_dma(IN nodnic_port_priv * port_priv,IN mlx_boolean value)1180 nodnic_port_check_and_set_dma(
1181 		IN nodnic_port_priv		*port_priv,
1182 		IN mlx_boolean			value
1183 		)
1184 {
1185 	mlx_status status = MLX_SUCCESS;
1186 	if ( port_priv->dma_state == value ) {
1187 		MLX_DEBUG_WARN(port_priv->device,
1188 				"nodnic_port_check_and_set_dma: already %s\n",
1189 				(value ? "enabled" : "disabled"));
1190 		status = MLX_SUCCESS;
1191 		goto set_out;
1192 	}
1193 
1194 	status = port_priv->set_dma(port_priv, value);
1195 	MLX_CHECK_STATUS(port_priv->device, status, set_err,
1196 			"nodnic_port_set failed");
1197 	port_priv->dma_state = value;
1198 set_err:
1199 set_out:
1200 	return status;
1201 }
1202 
1203 
1204 mlx_status
nodnic_port_set_promisc(IN nodnic_port_priv * port_priv,IN mlx_boolean value)1205 nodnic_port_set_promisc(
1206 		IN nodnic_port_priv		*port_priv,
1207 		IN mlx_boolean			value
1208 		){
1209 	mlx_status status = MLX_SUCCESS;
1210 	mlx_uint32	buffer = value;
1211 
1212 	status = nodnic_port_set(port_priv, nodnic_port_option_port_promisc_en, buffer);
1213 	MLX_CHECK_STATUS(port_priv->device, status, set_err,
1214 			"nodnic_port_set failed");
1215 set_err:
1216 	return status;
1217 }
1218 
1219 mlx_status
nodnic_port_set_promisc_multicast(IN nodnic_port_priv * port_priv,IN mlx_boolean value)1220 nodnic_port_set_promisc_multicast(
1221 		IN nodnic_port_priv		*port_priv,
1222 		IN mlx_boolean			value
1223 		){
1224 	mlx_status status = MLX_SUCCESS;
1225 	mlx_uint32	buffer = value;
1226 
1227 	status = nodnic_port_set(port_priv, nodnic_port_option_port_promisc_multicast_en, buffer);
1228 	MLX_CHECK_STATUS(port_priv->device, status, set_err,
1229 			"nodnic_port_set failed");
1230 set_err:
1231 	return status;
1232 }
1233 
1234 mlx_status
nodnic_port_init(IN nodnic_port_priv * port_priv)1235 nodnic_port_init(
1236 		IN nodnic_port_priv		*port_priv
1237 		)
1238 {
1239 	mlx_status status = MLX_SUCCESS;
1240 
1241 	if( port_priv == NULL ){
1242 		status = MLX_INVALID_PARAMETER;
1243 		goto bad_param;
1244 	}
1245 
1246 	status = nodnic_port_set_network(port_priv, TRUE);
1247 	MLX_FATAL_CHECK_STATUS(status, set_err,
1248 					"nodnic_port_set_network failed");
1249 set_err:
1250 bad_param:
1251 	return status;
1252 }
1253 
1254 mlx_status
nodnic_port_close(IN nodnic_port_priv * port_priv)1255 nodnic_port_close(
1256 		IN nodnic_port_priv		*port_priv
1257 		)
1258 {
1259 	mlx_status status = MLX_SUCCESS;
1260 
1261 	if( port_priv == NULL ){
1262 		status = MLX_INVALID_PARAMETER;
1263 		goto bad_param;
1264 	}
1265 
1266 	status = nodnic_port_set_network(port_priv, FALSE);
1267 	MLX_FATAL_CHECK_STATUS(status, set_err,
1268 					"nodnic_port_set_network failed");
1269 set_err:
1270 bad_param:
1271 	return status;
1272 }
1273 
1274 mlx_status
nodnic_port_enable_dma(IN nodnic_port_priv * port_priv)1275 nodnic_port_enable_dma(
1276 		IN nodnic_port_priv		*port_priv
1277 		)
1278 {
1279 	mlx_status status = MLX_SUCCESS;
1280 
1281 	if( port_priv == NULL ){
1282 		status = MLX_INVALID_PARAMETER;
1283 		goto bad_param;
1284 	}
1285 
1286 	status = nodnic_port_check_and_set_dma(port_priv, TRUE);
1287 	MLX_CHECK_STATUS(port_priv->device, status, set_err,
1288 					"nodnic_port_check_and_set_dma failed");
1289 set_err:
1290 bad_param:
1291 	return status;
1292 }
1293 
1294 mlx_status
nodnic_port_disable_dma(IN nodnic_port_priv * port_priv)1295 nodnic_port_disable_dma(
1296 		IN nodnic_port_priv		*port_priv
1297 		)
1298 {
1299 	mlx_status status = MLX_SUCCESS;
1300 
1301 	if( port_priv == NULL ){
1302 		status = MLX_INVALID_PARAMETER;
1303 		goto bad_param;
1304 	}
1305 
1306 	status = nodnic_port_check_and_set_dma(port_priv, FALSE);
1307 	MLX_CHECK_STATUS(port_priv->device, status, set_err,
1308 					"nodnic_port_check_and_set_dma failed");
1309 set_err:
1310 bad_param:
1311 	return status;
1312 }
1313 
1314 mlx_status
nodnic_port_thin_init(IN nodnic_device_priv * device_priv,IN nodnic_port_priv * port_priv,IN mlx_uint8 port_index)1315 nodnic_port_thin_init(
1316 		IN nodnic_device_priv	*device_priv,
1317 		IN nodnic_port_priv		*port_priv,
1318 		IN mlx_uint8			port_index
1319 		)
1320 {
1321 	mlx_status status = MLX_SUCCESS;
1322 	mlx_boolean	reset_needed = 0;
1323 #ifdef DEVICE_CX3
1324 	mlx_uint32 offset;
1325 #endif
1326 
1327 	if( device_priv == NULL || port_priv == NULL || port_index > 1){
1328 		status = MLX_INVALID_PARAMETER;
1329 		goto invalid_parm;
1330 	}
1331 
1332 	port_priv->device = device_priv;
1333 
1334 	port_priv->port_offset = device_priv->device_offset +
1335 			nodnic_port_offset_table[port_index];
1336 
1337 	port_priv->port_num = port_index + 1;
1338 
1339 	port_priv->send_doorbell = nodnic_port_update_ring_doorbell;
1340 	port_priv->recv_doorbell = nodnic_port_update_ring_doorbell;
1341 	port_priv->set_dma = nodnic_port_set_dma;
1342 #ifdef DEVICE_CX3
1343 	if (device_priv->device_cap.crspace_doorbells) {
1344 		status = nodnic_cmd_read(device_priv, (port_priv->port_offset + 0x100),
1345 				&offset);
1346 		if (status != MLX_SUCCESS) {
1347 			return status;
1348 		} else {
1349 			port_priv->data_flow_gw = (nodnic_port_data_flow_gw *)
1350 					(device_priv->utils->config + offset);
1351 		}
1352 		if ( nodnic_port_set ( port_priv, nodnic_port_option_crspace_en, 1 ) ) {
1353 			return MLX_FAILED;
1354 		}
1355 		port_priv->send_doorbell = nodnic_port_send_db_connectx3;
1356 		port_priv->recv_doorbell = nodnic_port_recv_db_connectx3;
1357 		port_priv->set_dma = nodnic_port_set_dma_connectx3;
1358 	}
1359 #endif
1360 	if ( device_priv->device_cap.support_rx_pi_dma ) {
1361 		port_priv->recv_doorbell = nodnic_port_recv_db_dma;
1362 	}
1363 
1364 	/* clear reset_needed */
1365 	nodnic_port_read_reset_needed(port_priv, &reset_needed);
1366 
1367 	port_priv->port_type = NODNIC_PORT_TYPE_UNKNOWN;
1368 invalid_parm:
1369 	return status;
1370 }
1371