1 /*
2  * Copyright (c) 2017-2018 Cavium, Inc.
3  * All rights reserved.
4  *
5  *  Redistribution and use in source and binary forms, with or without
6  *  modification, are permitted provided that the following conditions
7  *  are met:
8  *
9  *  1. Redistributions of source code must retain the above copyright
10  *     notice, this list of conditions and the following disclaimer.
11  *  2. Redistributions in binary form must reproduce the above copyright
12  *     notice, this list of conditions and the following disclaimer in the
13  *     documentation and/or other materials provided with the distribution.
14  *
15  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
19  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25  *  POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 
29 /*
30  * File: qlnx_ioctl.c
31  * Author : David C Somayajulu, Qlogic Corporation, Aliso Viejo, CA 92656.
32  */
33 
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD: stable/10/sys/dev/qlnx/qlnxe/qlnx_ioctl.c 337519 2018-08-09 01:39:47Z davidcs $");
36 
37 #include "qlnx_os.h"
38 #include "bcm_osal.h"
39 
40 #include "reg_addr.h"
41 #include "ecore_gtt_reg_addr.h"
42 #include "ecore.h"
43 #include "ecore_chain.h"
44 #include "ecore_status.h"
45 #include "ecore_hw.h"
46 #include "ecore_rt_defs.h"
47 #include "ecore_init_ops.h"
48 #include "ecore_int.h"
49 #include "ecore_cxt.h"
50 #include "ecore_spq.h"
51 #include "ecore_init_fw_funcs.h"
52 #include "ecore_sp_commands.h"
53 #include "ecore_dev_api.h"
54 #include "ecore_l2_api.h"
55 #include "ecore_mcp.h"
56 #include "ecore_hw_defs.h"
57 #include "mcp_public.h"
58 #include "ecore_iro.h"
59 #include "nvm_cfg.h"
60 #include "ecore_dev_api.h"
61 #include "ecore_dbg_fw_funcs.h"
62 #include "ecore_dcbx_api.h"
63 
64 #include "qlnx_ioctl.h"
65 #include "qlnx_def.h"
66 #include "qlnx_ver.h"
67 #include <sys/smp.h>
68 
69 
70 static int qlnx_eioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
71                 struct thread *td);
72 
73 static struct cdevsw qlnx_cdevsw = {
74         .d_version = D_VERSION,
75         .d_ioctl = qlnx_eioctl,
76         .d_name = "qlnxioctl",
77 };
78 
79 int
qlnx_make_cdev(qlnx_host_t * ha)80 qlnx_make_cdev(qlnx_host_t *ha)
81 {
82 	ha->ioctl_dev = make_dev(&qlnx_cdevsw,
83 				ha->ifp->if_dunit,
84 				UID_ROOT,
85 				GID_WHEEL,
86 				0600,
87 				"%s",
88 				if_name(ha->ifp));
89 
90 	if (ha->ioctl_dev == NULL)
91 		return (-1);
92 
93 	ha->ioctl_dev->si_drv1 = ha;
94 
95 	return (0);
96 }
97 
98 void
qlnx_del_cdev(qlnx_host_t * ha)99 qlnx_del_cdev(qlnx_host_t *ha)
100 {
101 	if (ha->ioctl_dev != NULL)
102 		destroy_dev(ha->ioctl_dev);
103 	return;
104 }
105 
106 int
qlnx_grc_dump(qlnx_host_t * ha,uint32_t * num_dumped_dwords,int hwfn_index)107 qlnx_grc_dump(qlnx_host_t *ha, uint32_t *num_dumped_dwords, int hwfn_index)
108 {
109 	int rval = EINVAL;
110 	struct ecore_hwfn *p_hwfn;
111 	struct ecore_ptt *p_ptt;
112 
113 	if (ha->grcdump_dwords[hwfn_index]) {
114 		/* the grcdump is already available */
115 		*num_dumped_dwords = ha->grcdump_dwords[hwfn_index];
116 		return (0);
117 	}
118 
119 	ecore_dbg_set_app_ver(ecore_dbg_get_fw_func_ver());
120 
121 	p_hwfn = &ha->cdev.hwfns[hwfn_index];
122 	p_ptt = ecore_ptt_acquire(p_hwfn);
123 
124 	if (!p_ptt) {
125 		QL_DPRINT1(ha,"ecore_ptt_acquire failed\n");
126 		return (rval);
127 	}
128 
129 	if ((rval = ecore_dbg_grc_dump(p_hwfn, p_ptt,
130 			ha->grcdump[hwfn_index],
131 			(ha->grcdump_size[hwfn_index] >> 2),
132 			num_dumped_dwords)) == DBG_STATUS_OK) {
133 	 	rval = 0;
134 		ha->grcdump_taken = 1;
135 	} else
136 		QL_DPRINT1(ha,"ecore_dbg_grc_dump failed [%d, 0x%x]\n",
137 			   hwfn_index, rval);
138 
139 	ecore_ptt_release(p_hwfn, p_ptt);
140 
141 	return (rval);
142 }
143 
144 static void
qlnx_get_grc_dump_size(qlnx_host_t * ha,qlnx_grcdump_t * grcdump)145 qlnx_get_grc_dump_size(qlnx_host_t *ha, qlnx_grcdump_t *grcdump)
146 {
147 	int i;
148 
149 	grcdump->pci_func = ha->pci_func;
150 
151 	for (i = 0; i < ha->cdev.num_hwfns; i++)
152 		grcdump->grcdump_size[i] = ha->grcdump_size[i];
153 
154 	return;
155 }
156 
157 static int
qlnx_get_grc_dump(qlnx_host_t * ha,qlnx_grcdump_t * grcdump)158 qlnx_get_grc_dump(qlnx_host_t *ha, qlnx_grcdump_t *grcdump)
159 {
160 	int		i;
161 	int		rval = 0;
162 	uint32_t	dwords = 0;
163 
164 	grcdump->pci_func = ha->pci_func;
165 
166 	for (i = 0; i < ha->cdev.num_hwfns; i++) {
167 
168 		if ((ha->grcdump[i] == NULL) || (grcdump->grcdump[i] == NULL) ||
169 			(grcdump->grcdump_size[i] < ha->grcdump_size[i]))
170 			return (EINVAL);
171 
172 		rval = qlnx_grc_dump(ha, &dwords, i);
173 
174 		if (rval)
175 			break;
176 
177 		grcdump->grcdump_dwords[i] = dwords;
178 
179 		QL_DPRINT1(ha,"grcdump_dwords[%d] = 0x%x\n", i, dwords);
180 
181 		rval = copyout(ha->grcdump[i], grcdump->grcdump[i],
182 				ha->grcdump_size[i]);
183 
184 		if (rval)
185 			break;
186 
187 		ha->grcdump_dwords[i] = 0;
188 	}
189 
190 	ha->grcdump_taken = 0;
191 
192 	return (rval);
193 }
194 
195 int
qlnx_idle_chk(qlnx_host_t * ha,uint32_t * num_dumped_dwords,int hwfn_index)196 qlnx_idle_chk(qlnx_host_t *ha, uint32_t *num_dumped_dwords, int hwfn_index)
197 {
198 	int rval = EINVAL;
199 	struct ecore_hwfn *p_hwfn;
200 	struct ecore_ptt *p_ptt;
201 
202 	if (ha->idle_chk_dwords[hwfn_index]) {
203 		/* the idle check is already available */
204 		*num_dumped_dwords = ha->idle_chk_dwords[hwfn_index];
205 		return (0);
206 	}
207 
208 	ecore_dbg_set_app_ver(ecore_dbg_get_fw_func_ver());
209 
210 	p_hwfn = &ha->cdev.hwfns[hwfn_index];
211 	p_ptt = ecore_ptt_acquire(p_hwfn);
212 
213 	if (!p_ptt) {
214 		QL_DPRINT1(ha,"ecore_ptt_acquire failed\n");
215 		return (rval);
216 	}
217 
218 	if ((rval = ecore_dbg_idle_chk_dump(p_hwfn, p_ptt,
219 			ha->idle_chk[hwfn_index],
220 			(ha->idle_chk_size[hwfn_index] >> 2),
221 			num_dumped_dwords)) == DBG_STATUS_OK) {
222 	 	rval = 0;
223 		ha->idle_chk_taken = 1;
224 	} else
225 		QL_DPRINT1(ha,"ecore_dbg_idle_chk_dump failed [%d, 0x%x]\n",
226 			   hwfn_index, rval);
227 
228 	ecore_ptt_release(p_hwfn, p_ptt);
229 
230 	return (rval);
231 }
232 
233 static void
qlnx_get_idle_chk_size(qlnx_host_t * ha,qlnx_idle_chk_t * idle_chk)234 qlnx_get_idle_chk_size(qlnx_host_t *ha, qlnx_idle_chk_t *idle_chk)
235 {
236 	int i;
237 
238 	idle_chk->pci_func = ha->pci_func;
239 
240 	for (i = 0; i < ha->cdev.num_hwfns; i++)
241 		idle_chk->idle_chk_size[i] = ha->idle_chk_size[i];
242 
243 	return;
244 }
245 
246 static int
qlnx_get_idle_chk(qlnx_host_t * ha,qlnx_idle_chk_t * idle_chk)247 qlnx_get_idle_chk(qlnx_host_t *ha, qlnx_idle_chk_t *idle_chk)
248 {
249 	int		i;
250 	int		rval = 0;
251 	uint32_t	dwords = 0;
252 
253 	idle_chk->pci_func = ha->pci_func;
254 
255 	for (i = 0; i < ha->cdev.num_hwfns; i++) {
256 
257 		if ((ha->idle_chk[i] == NULL) ||
258 				(idle_chk->idle_chk[i] == NULL) ||
259 				(idle_chk->idle_chk_size[i] <
260 					ha->idle_chk_size[i]))
261 			return (EINVAL);
262 
263 		rval = qlnx_idle_chk(ha, &dwords, i);
264 
265 		if (rval)
266 			break;
267 
268 		idle_chk->idle_chk_dwords[i] = dwords;
269 
270 		QL_DPRINT1(ha,"idle_chk_dwords[%d] = 0x%x\n", i, dwords);
271 
272                	rval = copyout(ha->idle_chk[i], idle_chk->idle_chk[i],
273 				ha->idle_chk_size[i]);
274 
275 		if (rval)
276 			break;
277 
278 		ha->idle_chk_dwords[i] = 0;
279 	}
280 	ha->idle_chk_taken = 0;
281 
282 	return (rval);
283 }
284 
285 static uint32_t
qlnx_get_trace_cmd_size(qlnx_host_t * ha,int hwfn_index,uint16_t cmd)286 qlnx_get_trace_cmd_size(qlnx_host_t *ha, int hwfn_index, uint16_t cmd)
287 {
288         int rval = -1;
289         struct ecore_hwfn *p_hwfn;
290         struct ecore_ptt *p_ptt;
291 	uint32_t num_dwords = 0;
292 
293         p_hwfn = &ha->cdev.hwfns[hwfn_index];
294         p_ptt = ecore_ptt_acquire(p_hwfn);
295 
296         if (!p_ptt) {
297                 QL_DPRINT1(ha, "ecore_ptt_acquire [%d, 0x%x]failed\n",
298                            hwfn_index, cmd);
299                 return (0);
300         }
301 
302 	switch (cmd) {
303 
304 	case QLNX_MCP_TRACE:
305         	rval = ecore_dbg_mcp_trace_get_dump_buf_size(p_hwfn,
306 				p_ptt, &num_dwords);
307 		break;
308 
309 	case QLNX_REG_FIFO:
310         	rval = ecore_dbg_reg_fifo_get_dump_buf_size(p_hwfn,
311 				p_ptt, &num_dwords);
312 		break;
313 
314 	case QLNX_IGU_FIFO:
315         	rval = ecore_dbg_igu_fifo_get_dump_buf_size(p_hwfn,
316 				p_ptt, &num_dwords);
317 		break;
318 
319 	case QLNX_PROTECTION_OVERRIDE:
320         	rval = ecore_dbg_protection_override_get_dump_buf_size(p_hwfn,
321 				p_ptt, &num_dwords);
322 		break;
323 
324 	case QLNX_FW_ASSERTS:
325         	rval = ecore_dbg_fw_asserts_get_dump_buf_size(p_hwfn,
326 				p_ptt, &num_dwords);
327 		break;
328 	}
329 
330         if (rval != DBG_STATUS_OK) {
331                 QL_DPRINT1(ha,"cmd = 0x%x failed [0x%x]\n", cmd, rval);
332 		num_dwords = 0;
333         }
334 
335         ecore_ptt_release(p_hwfn, p_ptt);
336 
337         return ((num_dwords * sizeof (uint32_t)));
338 }
339 
340 static void
qlnx_get_trace_size(qlnx_host_t * ha,qlnx_trace_t * trace)341 qlnx_get_trace_size(qlnx_host_t *ha, qlnx_trace_t *trace)
342 {
343 	int i;
344 
345 	trace->pci_func = ha->pci_func;
346 
347 	for (i = 0; i < ha->cdev.num_hwfns; i++) {
348 		trace->size[i] = qlnx_get_trace_cmd_size(ha, i, trace->cmd);
349 	}
350 
351 	return;
352 }
353 
354 static int
qlnx_get_trace(qlnx_host_t * ha,int hwfn_index,qlnx_trace_t * trace)355 qlnx_get_trace(qlnx_host_t *ha, int hwfn_index, qlnx_trace_t *trace)
356 {
357         int rval = -1;
358         struct ecore_hwfn *p_hwfn;
359         struct ecore_ptt *p_ptt;
360 	uint32_t num_dwords = 0;
361 	void *buffer;
362 
363 	buffer = qlnx_zalloc(trace->size[hwfn_index]);
364 	if (buffer == NULL) {
365                 QL_DPRINT1(ha,"qlnx_zalloc [%d, 0x%x]failed\n",
366                            hwfn_index, trace->cmd);
367                 return (ENXIO);
368 	}
369 	ecore_dbg_set_app_ver(ecore_dbg_get_fw_func_ver());
370 
371         p_hwfn = &ha->cdev.hwfns[hwfn_index];
372         p_ptt = ecore_ptt_acquire(p_hwfn);
373 
374         if (!p_ptt) {
375                 QL_DPRINT1(ha, "ecore_ptt_acquire [%d, 0x%x]failed\n",
376                            hwfn_index, trace->cmd);
377                 return (ENXIO);
378         }
379 
380 	switch (trace->cmd) {
381 
382 	case QLNX_MCP_TRACE:
383         	rval = ecore_dbg_mcp_trace_dump(p_hwfn, p_ptt,
384 				buffer, (trace->size[hwfn_index] >> 2),
385 				&num_dwords);
386 		break;
387 
388 	case QLNX_REG_FIFO:
389         	rval = ecore_dbg_reg_fifo_dump(p_hwfn, p_ptt,
390 				buffer, (trace->size[hwfn_index] >> 2),
391 				&num_dwords);
392 		break;
393 
394 	case QLNX_IGU_FIFO:
395         	rval = ecore_dbg_igu_fifo_dump(p_hwfn, p_ptt,
396 				buffer, (trace->size[hwfn_index] >> 2),
397 				&num_dwords);
398 		break;
399 
400 	case QLNX_PROTECTION_OVERRIDE:
401         	rval = ecore_dbg_protection_override_dump(p_hwfn, p_ptt,
402 				buffer, (trace->size[hwfn_index] >> 2),
403 				&num_dwords);
404 		break;
405 
406 	case QLNX_FW_ASSERTS:
407         	rval = ecore_dbg_fw_asserts_dump(p_hwfn, p_ptt,
408 				buffer, (trace->size[hwfn_index] >> 2),
409 				&num_dwords);
410 		break;
411 	}
412 
413         if (rval != DBG_STATUS_OK) {
414                 QL_DPRINT1(ha,"cmd = 0x%x failed [0x%x]\n", trace->cmd, rval);
415 		num_dwords = 0;
416         }
417 
418         ecore_ptt_release(p_hwfn, p_ptt);
419 
420 	trace->dwords[hwfn_index] = num_dwords;
421 
422 	if (num_dwords) {
423                	rval = copyout(buffer, trace->buffer[hwfn_index],
424 				(num_dwords << 2));
425 	}
426 
427         return (rval);
428 }
429 
430 static int
qlnx_reg_rd_wr(qlnx_host_t * ha,qlnx_reg_rd_wr_t * reg_rd_wr)431 qlnx_reg_rd_wr(qlnx_host_t *ha, qlnx_reg_rd_wr_t *reg_rd_wr)
432 {
433 	int			rval = 0;
434 	struct ecore_hwfn	*p_hwfn;
435 
436 	if (reg_rd_wr->hwfn_index >= QLNX_MAX_HW_FUNCS) {
437 		return (EINVAL);
438 	}
439 
440 	p_hwfn = &ha->cdev.hwfns[reg_rd_wr->hwfn_index];
441 
442 	switch (reg_rd_wr->cmd) {
443 
444 		case QLNX_REG_READ_CMD:
445 			if (reg_rd_wr->access_type == QLNX_REG_ACCESS_DIRECT) {
446 				reg_rd_wr->val = qlnx_reg_rd32(p_hwfn,
447 							reg_rd_wr->addr);
448 			}
449 			break;
450 
451 		case QLNX_REG_WRITE_CMD:
452 			if (reg_rd_wr->access_type == QLNX_REG_ACCESS_DIRECT) {
453 				qlnx_reg_wr32(p_hwfn, reg_rd_wr->addr,
454 					reg_rd_wr->val);
455 			}
456 			break;
457 
458 		default:
459 			rval = EINVAL;
460 			break;
461 	}
462 
463 	return (rval);
464 }
465 
466 static int
qlnx_rd_wr_pci_config(qlnx_host_t * ha,qlnx_pcicfg_rd_wr_t * pci_cfg_rd_wr)467 qlnx_rd_wr_pci_config(qlnx_host_t *ha, qlnx_pcicfg_rd_wr_t *pci_cfg_rd_wr)
468 {
469 	int rval = 0;
470 
471 	switch (pci_cfg_rd_wr->cmd) {
472 
473 		case QLNX_PCICFG_READ:
474 			pci_cfg_rd_wr->val = pci_read_config(ha->pci_dev,
475 						pci_cfg_rd_wr->reg,
476 						pci_cfg_rd_wr->width);
477 			break;
478 
479 		case QLNX_PCICFG_WRITE:
480 			pci_write_config(ha->pci_dev, pci_cfg_rd_wr->reg,
481 				pci_cfg_rd_wr->val, pci_cfg_rd_wr->width);
482 			break;
483 
484 		default:
485 			rval = EINVAL;
486 			break;
487 	}
488 
489 	return (rval);
490 }
491 
492 static void
qlnx_mac_addr(qlnx_host_t * ha,qlnx_perm_mac_addr_t * mac_addr)493 qlnx_mac_addr(qlnx_host_t *ha, qlnx_perm_mac_addr_t *mac_addr)
494 {
495 	bzero(mac_addr->addr, sizeof(mac_addr->addr));
496 	snprintf(mac_addr->addr, sizeof(mac_addr->addr),
497 		"%02x:%02x:%02x:%02x:%02x:%02x",
498 		ha->primary_mac[0], ha->primary_mac[1], ha->primary_mac[2],
499 		ha->primary_mac[3], ha->primary_mac[4], ha->primary_mac[5]);
500 
501 	return;
502 }
503 
504 static int
qlnx_get_regs(qlnx_host_t * ha,qlnx_get_regs_t * regs)505 qlnx_get_regs(qlnx_host_t *ha, qlnx_get_regs_t *regs)
506 {
507 	int		i;
508 	int		rval = 0;
509 	uint32_t	dwords = 0;
510 	uint8_t		*outb;
511 
512 	regs->reg_buf_len = 0;
513 	outb = regs->reg_buf;
514 
515 	for (i = 0; i < ha->cdev.num_hwfns; i++) {
516 
517 		rval = qlnx_grc_dump(ha, &dwords, i);
518 
519 		if (rval)
520 			break;
521 
522 		regs->reg_buf_len += (dwords << 2);
523 
524 		rval = copyout(ha->grcdump[i], outb, ha->grcdump_size[i]);
525 
526 		if (rval)
527 			break;
528 
529 		ha->grcdump_dwords[i] = 0;
530 		outb += regs->reg_buf_len;
531 	}
532 
533 	ha->grcdump_taken = 0;
534 
535 	return (rval);
536 }
537 
538 static int
qlnx_drv_info(qlnx_host_t * ha,qlnx_drvinfo_t * drv_info)539 qlnx_drv_info(qlnx_host_t *ha, qlnx_drvinfo_t *drv_info)
540 {
541 	int i;
542 	extern char qlnx_name_str[];
543 	extern char qlnx_ver_str[];
544 
545 	bzero(drv_info, sizeof(qlnx_drvinfo_t));
546 
547 	snprintf(drv_info->drv_name, sizeof(drv_info->drv_name), "%s",
548 		qlnx_name_str);
549 	snprintf(drv_info->drv_version, sizeof(drv_info->drv_version), "%s",
550 		qlnx_ver_str);
551 	snprintf(drv_info->mfw_version, sizeof(drv_info->mfw_version), "%s",
552 		ha->mfw_ver);
553 	snprintf(drv_info->stormfw_version, sizeof(drv_info->stormfw_version),
554 		"%s", ha->stormfw_ver);
555 
556 	drv_info->eeprom_dump_len = ha->flash_size;
557 
558 	for (i = 0; i < ha->cdev.num_hwfns; i++) {
559 		drv_info->reg_dump_len += ha->grcdump_size[i];
560 	}
561 
562 	snprintf(drv_info->bus_info, sizeof(drv_info->bus_info),
563 		"%d:%d:%d", pci_get_bus(ha->pci_dev),
564 		pci_get_slot(ha->pci_dev), ha->pci_func);
565 
566 	return (0);
567 }
568 
569 static int
qlnx_dev_settings(qlnx_host_t * ha,qlnx_dev_setting_t * dev_info)570 qlnx_dev_settings(qlnx_host_t *ha, qlnx_dev_setting_t *dev_info)
571 {
572 	struct ecore_hwfn *p_hwfn;
573 	struct qlnx_link_output if_link;
574 
575 	p_hwfn = &ha->cdev.hwfns[0];
576 
577 	qlnx_fill_link(ha, p_hwfn, &if_link);
578 
579 	dev_info->supported = if_link.supported_caps;
580 	dev_info->advertising = if_link.advertised_caps;
581 	dev_info->speed = if_link.speed;
582 	dev_info->duplex = if_link.duplex;
583 	dev_info->port = ha->pci_func & 0x1;
584 	dev_info->autoneg = if_link.autoneg;
585 
586 	return (0);
587 }
588 
589 static int
qlnx_write_nvram(qlnx_host_t * ha,qlnx_nvram_t * nvram,uint32_t cmd)590 qlnx_write_nvram(qlnx_host_t *ha, qlnx_nvram_t *nvram, uint32_t cmd)
591 {
592 	uint8_t *buf;
593 	int ret = 0;
594 
595 	if ((nvram->data == NULL) || (nvram->data_len == 0))
596 		return (EINVAL);
597 
598 	buf = qlnx_zalloc(nvram->data_len);
599 
600 	ret = copyin(nvram->data, buf, nvram->data_len);
601 
602 	QL_DPRINT9(ha, "issue cmd = 0x%x data = %p \
603 		 data_len = 0x%x ret = 0x%x exit\n",
604 		cmd, nvram->data, nvram->data_len, ret);
605 
606 	if (ret == 0) {
607 		ret = ecore_mcp_nvm_write(&ha->cdev, cmd,
608 			nvram->offset, buf, nvram->data_len);
609 	}
610 
611 	QL_DPRINT9(ha, "cmd = 0x%x data = %p \
612 		 data_len = 0x%x resp = 0x%x ret = 0x%x exit\n",
613 		cmd, nvram->data, nvram->data_len, ha->cdev.mcp_nvm_resp, ret);
614 
615 	free(buf, M_QLNXBUF);
616 
617 	return (ret);
618 }
619 
620 static int
qlnx_read_nvram(qlnx_host_t * ha,qlnx_nvram_t * nvram)621 qlnx_read_nvram(qlnx_host_t *ha, qlnx_nvram_t *nvram)
622 {
623 	uint8_t *buf;
624 	int ret = 0;
625 
626 	if ((nvram->data == NULL) || (nvram->data_len == 0))
627 		return (EINVAL);
628 
629 	buf = qlnx_zalloc(nvram->data_len);
630 
631 	ret = ecore_mcp_nvm_read(&ha->cdev, nvram->offset, buf,
632 		nvram->data_len);
633 
634 	QL_DPRINT9(ha, " data = %p data_len = 0x%x \
635 		 resp = 0x%x ret = 0x%x exit\n",
636 		nvram->data, nvram->data_len, ha->cdev.mcp_nvm_resp, ret);
637 
638 	if (ret == 0) {
639 		ret = copyout(buf, nvram->data, nvram->data_len);
640 	}
641 
642 	free(buf, M_QLNXBUF);
643 
644 	return (ret);
645 }
646 
647 static int
qlnx_get_nvram_resp(qlnx_host_t * ha,qlnx_nvram_t * nvram)648 qlnx_get_nvram_resp(qlnx_host_t *ha, qlnx_nvram_t *nvram)
649 {
650 	uint8_t *buf;
651 	int ret = 0;
652 
653 	if ((nvram->data == NULL) || (nvram->data_len == 0))
654 		return (EINVAL);
655 
656 	buf = qlnx_zalloc(nvram->data_len);
657 
658 
659 	ret = ecore_mcp_nvm_resp(&ha->cdev, buf);
660 
661 	QL_DPRINT9(ha, "data = %p data_len = 0x%x \
662 		 resp = 0x%x ret = 0x%x exit\n",
663 		nvram->data, nvram->data_len, ha->cdev.mcp_nvm_resp, ret);
664 
665 	if (ret == 0) {
666 		ret = copyout(buf, nvram->data, nvram->data_len);
667 	}
668 
669 	free(buf, M_QLNXBUF);
670 
671 	return (ret);
672 }
673 
674 static int
qlnx_nvram(qlnx_host_t * ha,qlnx_nvram_t * nvram)675 qlnx_nvram(qlnx_host_t *ha, qlnx_nvram_t *nvram)
676 {
677 	int ret = 0;
678 
679 	switch (nvram->cmd) {
680 
681 	case QLNX_NVRAM_CMD_WRITE_NVRAM:
682 		ret = qlnx_write_nvram(ha, nvram, ECORE_NVM_WRITE_NVRAM);
683 		break;
684 
685 	case QLNX_NVRAM_CMD_PUT_FILE_DATA:
686 		ret = qlnx_write_nvram(ha, nvram, ECORE_PUT_FILE_DATA);
687 		break;
688 
689 	case QLNX_NVRAM_CMD_READ_NVRAM:
690 		ret = qlnx_read_nvram(ha, nvram);
691 		break;
692 
693 	case QLNX_NVRAM_CMD_SET_SECURE_MODE:
694 		ret = ecore_mcp_nvm_set_secure_mode(&ha->cdev, nvram->offset);
695 
696 		QL_DPRINT9(ha, "QLNX_NVRAM_CMD_SET_SECURE_MODE \
697 			 resp = 0x%x ret = 0x%x exit\n",
698 			 ha->cdev.mcp_nvm_resp, ret);
699 		break;
700 
701 	case QLNX_NVRAM_CMD_DEL_FILE:
702 		ret = ecore_mcp_nvm_del_file(&ha->cdev, nvram->offset);
703 
704 		QL_DPRINT9(ha, "QLNX_NVRAM_CMD_DEL_FILE \
705 			 resp = 0x%x ret = 0x%x exit\n",
706 			ha->cdev.mcp_nvm_resp, ret);
707 		break;
708 
709 	case QLNX_NVRAM_CMD_PUT_FILE_BEGIN:
710 		ret = ecore_mcp_nvm_put_file_begin(&ha->cdev, nvram->offset);
711 
712 		QL_DPRINT9(ha, "QLNX_NVRAM_CMD_PUT_FILE_BEGIN \
713 			 resp = 0x%x ret = 0x%x exit\n",
714 			ha->cdev.mcp_nvm_resp, ret);
715 		break;
716 
717 	case QLNX_NVRAM_CMD_GET_NVRAM_RESP:
718 		ret = qlnx_get_nvram_resp(ha, nvram);
719 		break;
720 
721 	default:
722 		ret = EINVAL;
723 		break;
724 	}
725 
726 	return (ret);
727 }
728 
729 static void
qlnx_storm_stats(qlnx_host_t * ha,qlnx_storm_stats_dump_t * s_stats)730 qlnx_storm_stats(qlnx_host_t *ha, qlnx_storm_stats_dump_t *s_stats)
731 {
732 	int i;
733 	int index;
734 	int ret;
735 	int stats_copied = 0;
736 
737 	s_stats->num_hwfns = ha->cdev.num_hwfns;
738 
739 //	if (ha->storm_stats_index < QLNX_STORM_STATS_SAMPLES_PER_HWFN)
740 //		return;
741 
742 	s_stats->num_samples = ha->storm_stats_index;
743 
744 	for (i = 0; i < ha->cdev.num_hwfns; i++) {
745 
746 		index = (QLNX_STORM_STATS_SAMPLES_PER_HWFN * i);
747 
748 		if (s_stats->buffer[i]) {
749 
750 			ret = copyout(&ha->storm_stats[index],
751 					s_stats->buffer[i],
752 					QLNX_STORM_STATS_BYTES_PER_HWFN);
753 			if (ret) {
754 				printf("%s [%d]: failed\n", __func__, i);
755 			}
756 
757 			if (s_stats->num_samples ==
758 				QLNX_STORM_STATS_SAMPLES_PER_HWFN) {
759 
760 				bzero((void *)&ha->storm_stats[i],
761 					QLNX_STORM_STATS_BYTES_PER_HWFN);
762 
763 				stats_copied = 1;
764 			}
765 		}
766 	}
767 
768 	if (stats_copied)
769 		ha->storm_stats_index = 0;
770 
771 	return;
772 }
773 
774 #ifdef QLNX_USER_LLDP
775 
776 static int
qlnx_lldp_configure(qlnx_host_t * ha,struct ecore_hwfn * p_hwfn,struct ecore_ptt * p_ptt,uint32_t enable)777 qlnx_lldp_configure(qlnx_host_t *ha, struct ecore_hwfn *p_hwfn,
778 	struct ecore_ptt *p_ptt, uint32_t enable)
779 {
780 	int ret = 0;
781 	uint8_t lldp_mac[6] = {0};
782 	struct ecore_lldp_config_params lldp_params;
783 	struct ecore_lldp_sys_tlvs tlv_params;
784 
785 	ret = ecore_mcp_get_lldp_mac(p_hwfn, p_ptt, lldp_mac);
786 
787 	if (ret != ECORE_SUCCESS) {
788                 device_printf(ha->pci_dev,
789 			"%s: ecore_mcp_get_lldp_mac failed\n", __func__);
790                 return (-1);
791 	}
792 
793 	bzero(&lldp_params, sizeof(struct ecore_lldp_config_params));
794 	bzero(&tlv_params, sizeof(struct ecore_lldp_sys_tlvs));
795 
796 	lldp_params.agent = ECORE_LLDP_NEAREST_BRIDGE;
797 	lldp_params.tx_interval = 30; //Default value used as suggested by MFW
798 	lldp_params.tx_hold = 4; //Default value used as suggested by MFW
799 	lldp_params.tx_credit = 5; //Default value used as suggested by MFW
800 	lldp_params.rx_enable = enable ? 1 : 0;
801 	lldp_params.tx_enable = enable ? 1 : 0;
802 
803 	lldp_params.chassis_id_tlv[0] = 0;
804 	lldp_params.chassis_id_tlv[0] |= (QLNX_LLDP_TYPE_CHASSIS_ID << 1);
805 	lldp_params.chassis_id_tlv[0] |=
806 		((QLNX_LLDP_CHASSIS_ID_SUBTYPE_OCTETS +
807 			QLNX_LLDP_CHASSIS_ID_MAC_ADDR_LEN) << 8);
808 	lldp_params.chassis_id_tlv[0] |= (QLNX_LLDP_CHASSIS_ID_SUBTYPE_MAC << 16);
809 	lldp_params.chassis_id_tlv[0] |= lldp_mac[0] << 24;
810 	lldp_params.chassis_id_tlv[1] = lldp_mac[1] | (lldp_mac[2] << 8) |
811 		 (lldp_mac[3] << 16) | (lldp_mac[4] << 24);
812 	lldp_params.chassis_id_tlv[2] = lldp_mac[5];
813 
814 
815 	lldp_params.port_id_tlv[0] = 0;
816 	lldp_params.port_id_tlv[0] |= (QLNX_LLDP_TYPE_PORT_ID << 1);
817 	lldp_params.port_id_tlv[0] |=
818 		((QLNX_LLDP_PORT_ID_SUBTYPE_OCTETS +
819 			QLNX_LLDP_PORT_ID_MAC_ADDR_LEN) << 8);
820 	lldp_params.port_id_tlv[0] |= (QLNX_LLDP_PORT_ID_SUBTYPE_MAC << 16);
821 	lldp_params.port_id_tlv[0] |= lldp_mac[0] << 24;
822 	lldp_params.port_id_tlv[1] = lldp_mac[1] | (lldp_mac[2] << 8) |
823 		 (lldp_mac[3] << 16) | (lldp_mac[4] << 24);
824 	lldp_params.port_id_tlv[2] = lldp_mac[5];
825 
826 	ret = ecore_lldp_set_params(p_hwfn, p_ptt, &lldp_params);
827 
828 	if (ret != ECORE_SUCCESS) {
829                 device_printf(ha->pci_dev,
830 			"%s: ecore_lldp_set_params failed\n", __func__);
831                 return (-1);
832 	}
833 
834 	//If LLDP is disable then disable discard_mandatory_tlv flag
835 	if (!enable) {
836 		tlv_params.discard_mandatory_tlv = false;
837 		tlv_params.buf_size = 0;
838 		ret = ecore_lldp_set_system_tlvs(p_hwfn, p_ptt, &tlv_params);
839     	}
840 
841 	if (ret != ECORE_SUCCESS) {
842                 device_printf(ha->pci_dev,
843 			"%s: ecore_lldp_set_system_tlvs failed\n", __func__);
844 	}
845 
846 	return (ret);
847 }
848 
849 static int
qlnx_register_default_lldp_tlvs(qlnx_host_t * ha,struct ecore_hwfn * p_hwfn,struct ecore_ptt * p_ptt)850 qlnx_register_default_lldp_tlvs(qlnx_host_t *ha, struct ecore_hwfn *p_hwfn,
851 	struct ecore_ptt *p_ptt)
852 {
853 	int ret = 0;
854 
855 	ret = ecore_lldp_register_tlv(p_hwfn, p_ptt,
856 			ECORE_LLDP_NEAREST_BRIDGE, QLNX_LLDP_TYPE_CHASSIS_ID);
857 	if (ret != ECORE_SUCCESS) {
858                 device_printf(ha->pci_dev,
859 			"%s: QLNX_LLDP_TYPE_CHASSIS_ID failed\n", __func__);
860 		goto qlnx_register_default_lldp_tlvs_exit;
861 	}
862 
863 	//register Port ID TLV
864 	ret = ecore_lldp_register_tlv(p_hwfn, p_ptt,
865 			ECORE_LLDP_NEAREST_BRIDGE, QLNX_LLDP_TYPE_PORT_ID);
866 	if (ret != ECORE_SUCCESS) {
867                 device_printf(ha->pci_dev,
868 			"%s: QLNX_LLDP_TYPE_PORT_ID failed\n", __func__);
869 		goto qlnx_register_default_lldp_tlvs_exit;
870 	}
871 
872 	//register TTL TLV
873 	ret = ecore_lldp_register_tlv(p_hwfn, p_ptt,
874 			ECORE_LLDP_NEAREST_BRIDGE, QLNX_LLDP_TYPE_TTL);
875 	if (ret != ECORE_SUCCESS) {
876                 device_printf(ha->pci_dev,
877 			"%s: QLNX_LLDP_TYPE_TTL failed\n", __func__);
878 		goto qlnx_register_default_lldp_tlvs_exit;
879 	}
880 
881 	//register Port Description TLV
882 	ret = ecore_lldp_register_tlv(p_hwfn, p_ptt,
883 			ECORE_LLDP_NEAREST_BRIDGE, QLNX_LLDP_TYPE_PORT_DESC);
884 	if (ret != ECORE_SUCCESS) {
885                 device_printf(ha->pci_dev,
886 			"%s: QLNX_LLDP_TYPE_PORT_DESC failed\n", __func__);
887 		goto qlnx_register_default_lldp_tlvs_exit;
888 	}
889 
890 	//register System Name TLV
891 	ret = ecore_lldp_register_tlv(p_hwfn, p_ptt,
892 			ECORE_LLDP_NEAREST_BRIDGE, QLNX_LLDP_TYPE_SYS_NAME);
893 	if (ret != ECORE_SUCCESS) {
894                 device_printf(ha->pci_dev,
895 			"%s: QLNX_LLDP_TYPE_SYS_NAME failed\n", __func__);
896 		goto qlnx_register_default_lldp_tlvs_exit;
897 	}
898 
899 	//register System Description TLV
900 	ret = ecore_lldp_register_tlv(p_hwfn, p_ptt,
901 			ECORE_LLDP_NEAREST_BRIDGE, QLNX_LLDP_TYPE_SYS_DESC);
902 	if (ret != ECORE_SUCCESS) {
903                 device_printf(ha->pci_dev,
904 			"%s: QLNX_LLDP_TYPE_SYS_DESC failed\n", __func__);
905 		goto qlnx_register_default_lldp_tlvs_exit;
906 	}
907 
908 	//register System Capabilities TLV
909 	ret = ecore_lldp_register_tlv(p_hwfn, p_ptt,
910 			ECORE_LLDP_NEAREST_BRIDGE, QLNX_LLDP_TYPE_SYS_CAPS);
911 	if (ret != ECORE_SUCCESS) {
912                 device_printf(ha->pci_dev,
913 			"%s: QLNX_LLDP_TYPE_SYS_CAPS failed\n", __func__);
914 		goto qlnx_register_default_lldp_tlvs_exit;
915 	}
916 
917 	//register Management Address TLV
918 	ret = ecore_lldp_register_tlv(p_hwfn, p_ptt,
919 			ECORE_LLDP_NEAREST_BRIDGE, QLNX_LLDP_TYPE_MGMT_ADDR);
920 	if (ret != ECORE_SUCCESS) {
921                 device_printf(ha->pci_dev,
922 			"%s: QLNX_LLDP_TYPE_MGMT_ADDR failed\n", __func__);
923 		goto qlnx_register_default_lldp_tlvs_exit;
924 	}
925 
926 	//register Organizationally Specific TLVs
927 	ret = ecore_lldp_register_tlv(p_hwfn, p_ptt,
928 			ECORE_LLDP_NEAREST_BRIDGE, QLNX_LLDP_TYPE_ORG_SPECIFIC);
929 	if (ret != ECORE_SUCCESS) {
930                 device_printf(ha->pci_dev,
931 			"%s: QLNX_LLDP_TYPE_ORG_SPECIFIC failed\n", __func__);
932 	}
933 
934 qlnx_register_default_lldp_tlvs_exit:
935 	return (ret);
936 }
937 
938 int
qlnx_set_lldp_tlvx(qlnx_host_t * ha,qlnx_lldp_sys_tlvs_t * lldp_tlvs)939 qlnx_set_lldp_tlvx(qlnx_host_t *ha, qlnx_lldp_sys_tlvs_t *lldp_tlvs)
940 {
941 	int ret = 0;
942 	struct ecore_hwfn *p_hwfn;
943 	struct ecore_ptt *p_ptt;
944 	struct ecore_lldp_sys_tlvs tlv_params;
945 
946 	p_hwfn = &ha->cdev.hwfns[0];
947 	p_ptt = ecore_ptt_acquire(p_hwfn);
948 
949         if (!p_ptt) {
950                 device_printf(ha->pci_dev,
951 			"%s: ecore_ptt_acquire failed\n", __func__);
952                 return (ENXIO);
953         }
954 
955 	ret = qlnx_lldp_configure(ha, p_hwfn, p_ptt, 0);
956 
957 	if (ret) {
958                 device_printf(ha->pci_dev,
959 			"%s: qlnx_lldp_configure disable failed\n", __func__);
960 		goto qlnx_set_lldp_tlvx_exit;
961 	}
962 
963 	ret = qlnx_register_default_lldp_tlvs(ha, p_hwfn, p_ptt);
964 
965 	if (ret) {
966                 device_printf(ha->pci_dev,
967 			"%s: qlnx_register_default_lldp_tlvs failed\n",
968 			__func__);
969 		goto qlnx_set_lldp_tlvx_exit;
970 	}
971 
972 	ret = qlnx_lldp_configure(ha, p_hwfn, p_ptt, 1);
973 
974 	if (ret) {
975                 device_printf(ha->pci_dev,
976 			"%s: qlnx_lldp_configure enable failed\n", __func__);
977 		goto qlnx_set_lldp_tlvx_exit;
978 	}
979 
980 	if (lldp_tlvs != NULL) {
981 		bzero(&tlv_params, sizeof(struct ecore_lldp_sys_tlvs));
982 
983 		tlv_params.discard_mandatory_tlv =
984 			(lldp_tlvs->discard_mandatory_tlv ? true: false);
985 		tlv_params.buf_size = lldp_tlvs->buf_size;
986 		memcpy(tlv_params.buf, lldp_tlvs->buf, lldp_tlvs->buf_size);
987 
988 		ret = ecore_lldp_set_system_tlvs(p_hwfn, p_ptt, &tlv_params);
989 
990 		if (ret) {
991 			device_printf(ha->pci_dev,
992 				"%s: ecore_lldp_set_system_tlvs failed\n",
993 				__func__);
994 		}
995 	}
996 qlnx_set_lldp_tlvx_exit:
997 
998 	ecore_ptt_release(p_hwfn, p_ptt);
999 	return (ret);
1000 }
1001 
1002 #endif /* #ifdef QLNX_USER_LLDP */
1003 
1004 static int
qlnx_eioctl(struct cdev * dev,u_long cmd,caddr_t data,int fflag,struct thread * td)1005 qlnx_eioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
1006 	struct thread *td)
1007 {
1008 	qlnx_host_t	*ha;
1009 	int		rval = 0;
1010 	struct ifnet	*ifp;
1011 	qlnx_trace_t	*trace;
1012 	int		i;
1013 
1014 	if ((ha = (qlnx_host_t *)dev->si_drv1) == NULL)
1015 		return ENXIO;
1016 
1017 	ifp = ha->ifp;
1018 
1019 	switch (cmd) {
1020 
1021 	case QLNX_GRC_DUMP_SIZE:
1022 		qlnx_get_grc_dump_size(ha, (qlnx_grcdump_t *)data);
1023 		break;
1024 
1025 	case QLNX_GRC_DUMP:
1026 		rval = qlnx_get_grc_dump(ha, (qlnx_grcdump_t *)data);
1027 		break;
1028 
1029 	case QLNX_IDLE_CHK_SIZE:
1030 		qlnx_get_idle_chk_size(ha, (qlnx_idle_chk_t *)data);
1031 		break;
1032 
1033 	case QLNX_IDLE_CHK:
1034 		rval = qlnx_get_idle_chk(ha, (qlnx_idle_chk_t *)data);
1035 		break;
1036 
1037 	case QLNX_DRV_INFO:
1038 		rval = qlnx_drv_info(ha, (qlnx_drvinfo_t *)data);
1039 		break;
1040 
1041 	case QLNX_DEV_SETTING:
1042 		rval = qlnx_dev_settings(ha, (qlnx_dev_setting_t *)data);
1043 		break;
1044 
1045 	case QLNX_GET_REGS:
1046 		rval = qlnx_get_regs(ha, (qlnx_get_regs_t *)data);
1047 		break;
1048 
1049 	case QLNX_NVRAM:
1050 		rval = qlnx_nvram(ha, (qlnx_nvram_t *)data);
1051 		break;
1052 
1053 	case QLNX_RD_WR_REG:
1054 		rval = qlnx_reg_rd_wr(ha, (qlnx_reg_rd_wr_t *)data);
1055 		break;
1056 
1057 	case QLNX_RD_WR_PCICFG:
1058 		rval = qlnx_rd_wr_pci_config(ha, (qlnx_pcicfg_rd_wr_t *)data);
1059 		break;
1060 
1061 	case QLNX_MAC_ADDR:
1062 		qlnx_mac_addr(ha, (qlnx_perm_mac_addr_t *)data);
1063 		break;
1064 
1065 	case QLNX_STORM_STATS:
1066 		qlnx_storm_stats(ha, (qlnx_storm_stats_dump_t *)data);
1067 		break;
1068 
1069 	case QLNX_TRACE_SIZE:
1070 		qlnx_get_trace_size(ha, (qlnx_trace_t *)data);
1071 		break;
1072 
1073 	case QLNX_TRACE:
1074 		trace = (qlnx_trace_t *)data;
1075 
1076 		for (i = 0; i < ha->cdev.num_hwfns; i++) {
1077 
1078 			if (trace->size[i] && trace->cmd && trace->buffer[i])
1079 				rval = qlnx_get_trace(ha, i, trace);
1080 
1081 			if (rval)
1082 				break;
1083 		}
1084 		break;
1085 
1086 #ifdef QLNX_USER_LLDP
1087 	case QLNX_SET_LLDP_TLVS:
1088 		rval = qlnx_set_lldp_tlvx(ha, (qlnx_lldp_sys_tlvs_t *)data);
1089 		break;
1090 #endif /* #ifdef QLNX_USER_LLDP */
1091 
1092 	default:
1093 		rval = EINVAL;
1094 		break;
1095 	}
1096 
1097 	return (rval);
1098 }
1099 
1100