xref: /freebsd/sys/dev/smartpqi/smartpqi_sis.c (revision 7ef62cebc2f965b0f640263e179276928885e33d)
1 /*-
2  * Copyright 2016-2021 Microchip Technology, Inc. and/or its subsidiaries.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23  * SUCH DAMAGE.
24  */
25 
26 /* $FreeBSD$ */
27 
28 #include "smartpqi_includes.h"
29 
30 /* Function for disabling msix interrupots */
31 void
32 sis_disable_msix(pqisrc_softstate_t *softs)
33 {
34 	uint32_t db_reg;
35 
36 	DBG_FUNC("IN\n");
37 
38 	db_reg = PCI_MEM_GET32(softs, &softs->ioa_reg->host_to_ioa_db,
39 			LEGACY_SIS_IDBR);
40 	db_reg &= ~SIS_ENABLE_MSIX;
41 	PCI_MEM_PUT32(softs, &softs->ioa_reg->host_to_ioa_db,
42 			LEGACY_SIS_IDBR, db_reg);
43 
44 	DBG_FUNC("OUT\n");
45 }
46 
47 void
48 sis_enable_intx(pqisrc_softstate_t *softs)
49 {
50 	uint32_t db_reg;
51 
52 	DBG_FUNC("IN\n");
53 
54 	db_reg = PCI_MEM_GET32(softs, &softs->ioa_reg->host_to_ioa_db,
55 		LEGACY_SIS_IDBR);
56 	db_reg |= SIS_ENABLE_INTX;
57 	PCI_MEM_PUT32(softs, &softs->ioa_reg->host_to_ioa_db,
58 			LEGACY_SIS_IDBR, db_reg);
59 	if (pqisrc_sis_wait_for_db_bit_to_clear(softs,SIS_ENABLE_INTX)
60 		!= PQI_STATUS_SUCCESS) {
61 		DBG_ERR("Failed to wait for enable intx db bit to clear\n");
62 	}
63 	DBG_FUNC("OUT\n");
64 }
65 
66 void
67 sis_disable_intx(pqisrc_softstate_t *softs)
68 {
69 	uint32_t db_reg;
70 
71 	DBG_FUNC("IN\n");
72 
73 	db_reg = PCI_MEM_GET32(softs, &softs->ioa_reg->host_to_ioa_db,
74 			LEGACY_SIS_IDBR);
75 	db_reg &= ~SIS_ENABLE_INTX;
76 	PCI_MEM_PUT32(softs, &softs->ioa_reg->host_to_ioa_db,
77 			LEGACY_SIS_IDBR, db_reg);
78 
79 	DBG_FUNC("OUT\n");
80 }
81 
82 void
83 sis_disable_interrupt(pqisrc_softstate_t *softs)
84 {
85 	DBG_FUNC("IN");
86 
87 	switch(softs->intr_type) {
88 		case INTR_TYPE_FIXED:
89 			pqisrc_configure_legacy_intx(softs,false);
90 			sis_disable_intx(softs);
91 			break;
92 		case INTR_TYPE_MSI:
93 		case INTR_TYPE_MSIX:
94 			sis_disable_msix(softs);
95 			break;
96 		default:
97 			DBG_ERR("Inerrupt mode none!\n");
98 			break;
99 	}
100 
101 	DBG_FUNC("OUT");
102 }
103 
104 
105 /* Trigger a NMI as part of taking controller offline procedure */
106 void
107 pqisrc_trigger_nmi_sis(pqisrc_softstate_t *softs)
108 {
109 
110 	DBG_FUNC("IN\n");
111 
112 	PCI_MEM_PUT32(softs,  &softs->ioa_reg->host_to_ioa_db,
113 			LEGACY_SIS_IDBR, LE_32(TRIGGER_NMI_SIS));
114 	DBG_FUNC("OUT\n");
115 }
116 
117 /* Switch the adapter back to SIS mode during uninitialization */
118 int
119 pqisrc_reenable_sis(pqisrc_softstate_t *softs)
120 {
121 	int ret = PQI_STATUS_SUCCESS;
122 	uint32_t timeout = SIS_ENABLE_TIMEOUT;
123 
124 	DBG_FUNC("IN\n");
125 
126 	PCI_MEM_PUT32(softs, &softs->ioa_reg->host_to_ioa_db,
127         LEGACY_SIS_IDBR, LE_32(REENABLE_SIS));
128 
129 	COND_WAIT(((PCI_MEM_GET32(softs, &softs->ioa_reg->ioa_to_host_db, LEGACY_SIS_ODBR_R) &
130 				REENABLE_SIS) == 0), timeout)
131 	if (!timeout) {
132 		DBG_WARN(" [ %s ] failed to re enable sis\n",__func__);
133 		ret = PQI_STATUS_TIMEOUT;
134 	}
135 
136 	DBG_FUNC("OUT\n");
137 	return ret;
138 }
139 
140 /* Validate the FW status PQI_CTRL_KERNEL_UP_AND_RUNNING */
141 int
142 pqisrc_check_fw_status(pqisrc_softstate_t *softs)
143 {
144 	int ret = PQI_STATUS_SUCCESS;
145 	uint32_t timeout = SIS_STATUS_OK_TIMEOUT;
146 
147 	DBG_FUNC("IN\n");
148 
149 	OS_SLEEP(1000000);
150 	COND_WAIT((GET_FW_STATUS(softs) &
151 		PQI_CTRL_KERNEL_UP_AND_RUNNING), timeout);
152 	if (!timeout) {
153 		DBG_ERR("FW check status timedout\n");
154 		ret = PQI_STATUS_TIMEOUT;
155 	}
156 
157 	DBG_FUNC("OUT\n");
158 	return ret;
159 }
160 
161 /* Function used to submit a SIS command to the adapter */
162 static int
163 pqisrc_send_sis_cmd(pqisrc_softstate_t *softs, uint32_t *mb)
164 {
165 	int ret = PQI_STATUS_SUCCESS;
166 	int i = 0;
167 	uint32_t timeout = SIS_CMD_COMPLETE_TIMEOUT;
168 
169 	int val;
170 
171 	DBG_FUNC("IN\n");
172 
173 
174 	/* Copy Command to mailbox */
175 	for (i = 0; i < 6; i++)
176 		PCI_MEM_PUT32(softs, &softs->ioa_reg->mb[i],
177             LEGACY_SIS_SRCV_MAILBOX+i*4, LE_32(mb[i]));
178 
179 	/* TODO : Switch to INTX Mode ?*/
180 	PCI_MEM_PUT32(softs, &softs->ioa_reg->ioa_to_host_db_clr,
181 		LEGACY_SIS_ODBR_R, LE_32(0x1000));
182 
183 	/* Submit the command */
184 	PCI_MEM_PUT32(softs, &softs->ioa_reg->host_to_ioa_db,
185 		LEGACY_SIS_IDBR, LE_32(SIS_CMD_SUBMIT));
186 
187 #ifdef SIS_POLL_WAIT
188 	/* Wait for 20  milli sec to poll */
189 	OS_BUSYWAIT(SIS_POLL_START_WAIT_TIME);
190 #endif
191 
192 	val = PCI_MEM_GET32(softs, &softs->ioa_reg->ioa_to_host_db, LEGACY_SIS_ODBR_R);
193 
194 	DBG_FUNC("val : %x\n",val);
195 	/* Spin waiting for the command to complete */
196 	COND_WAIT((PCI_MEM_GET32(softs, &softs->ioa_reg->ioa_to_host_db, LEGACY_SIS_ODBR_R) &
197 		SIS_CMD_COMPLETE), timeout);
198 	if (!timeout) {
199 		DBG_ERR("Sync command %x, timedout\n", mb[0]);
200 		ret = PQI_STATUS_TIMEOUT;
201 		goto err_out;
202 	}
203 	/* Check command status */
204 	mb[0] = LE_32(PCI_MEM_GET32(softs, &softs->ioa_reg->mb[0], LEGACY_SIS_SRCV_MAILBOX));
205 
206 	if (mb[0] != SIS_CMD_STATUS_SUCCESS) {
207 		DBG_ERR("SIS cmd failed with status = 0x%x\n",
208 			mb[0]);
209 		ret = PQI_STATUS_FAILURE;
210 		goto err_out;
211 	}
212 
213 	/* Copy the mailbox back  */
214 	for (i = 1; i < 6; i++)
215 		mb[i] =	LE_32(PCI_MEM_GET32(softs, &softs->ioa_reg->mb[i], LEGACY_SIS_SRCV_MAILBOX+i*4));
216 
217 	DBG_FUNC("OUT\n");
218 	return ret;
219 
220 err_out:
221 	DBG_FUNC("OUT failed\n");
222 	return ret;
223 }
224 
225 /* First SIS command for the adapter to check PQI support */
226 int
227 pqisrc_get_adapter_properties(pqisrc_softstate_t *softs,
228 				uint32_t *prop, uint32_t *ext_prop)
229 {
230 	int ret = PQI_STATUS_SUCCESS;
231 	uint32_t mb[6] = {0};
232 
233 	DBG_FUNC("IN\n");
234 
235 	mb[0] = SIS_CMD_GET_ADAPTER_PROPERTIES;
236 	ret = pqisrc_send_sis_cmd(softs, mb);
237 	if (!ret) {
238 		DBG_INIT("GET_PROPERTIES prop = %x, ext_prop = %x\n",
239 					mb[1], mb[4]);
240 		*prop = mb[1];
241 		*ext_prop = mb[4];
242 	}
243 
244 	DBG_FUNC("OUT\n");
245 	return ret;
246 }
247 
248 /* Second SIS command to the adapter GET_COMM_PREFERRED_SETTINGS */
249 int
250 pqisrc_get_preferred_settings(pqisrc_softstate_t *softs)
251 {
252 	int ret = PQI_STATUS_SUCCESS;
253 	uint32_t mb[6] = {0};
254 
255 	DBG_FUNC("IN\n");
256 
257 	mb[0] = SIS_CMD_GET_COMM_PREFERRED_SETTINGS;
258 	ret = pqisrc_send_sis_cmd(softs, mb);
259 	if (!ret) {
260 		/* 31:16 maximum command size in KB */
261 		softs->pref_settings.max_cmd_size = mb[1] >> 16;
262 		/* 15:00: Maximum FIB size in bytes */
263 		softs->pref_settings.max_fib_size = mb[1] & 0x0000FFFF;
264 		DBG_INIT("cmd size = %x, fib size = %x\n",
265 			softs->pref_settings.max_cmd_size,
266 			softs->pref_settings.max_fib_size);
267 	}
268 
269 	DBG_FUNC("OUT\n");
270 	return ret;
271 }
272 
273 /* Get supported PQI capabilities from the adapter */
274 int
275 pqisrc_get_sis_pqi_cap(pqisrc_softstate_t *softs)
276 {
277 	int ret = PQI_STATUS_SUCCESS;
278 	uint32_t mb[6] = {0};
279 
280 	DBG_FUNC("IN\n");
281 
282 	mb[0] = SIS_CMD_GET_PQI_CAPABILITIES;
283 	ret = pqisrc_send_sis_cmd(softs,  mb);
284 	if (!ret) {
285 		softs->pqi_cap.max_sg_elem = mb[1];
286 		softs->pqi_cap.max_transfer_size = mb[2];
287 		softs->pqi_cap.max_outstanding_io = mb[3];
288 		softs->pqi_cap.conf_tab_off = mb[4];
289 		softs->pqi_cap.conf_tab_sz =  mb[5];
290 
291 		os_update_dma_attributes(softs);
292 
293 		DBG_INIT("max_sg_elem = %x\n",
294 					softs->pqi_cap.max_sg_elem);
295 		DBG_INIT("max_transfer_size = %x\n",
296 					softs->pqi_cap.max_transfer_size);
297 		DBG_INIT("max_outstanding_io = %x\n",
298 					softs->pqi_cap.max_outstanding_io);
299 	}
300 
301 	DBG_FUNC("OUT\n");
302 	return ret;
303 }
304 
305 /* Send INIT STRUCT BASE ADDR - one of the SIS command */
306 int
307 pqisrc_init_struct_base(pqisrc_softstate_t *softs)
308 {
309 	int ret = PQI_STATUS_SUCCESS;
310 	uint32_t elem_size = 0;
311 	uint32_t num_elem = 0;
312 	struct dma_mem init_struct_mem = {0};
313 	struct init_base_struct *init_struct = NULL;
314 	uint32_t mb[6] = {0};
315 
316 	DBG_FUNC("IN\n");
317 
318 	/* Allocate init struct */
319 	memset(&init_struct_mem, 0, sizeof(struct dma_mem));
320 	init_struct_mem.size = sizeof(struct init_base_struct);
321 	init_struct_mem.align = PQISRC_INIT_STRUCT_DMA_ALIGN;
322 	init_struct_mem.tag = "init_struct";
323 	ret = os_dma_mem_alloc(softs, &init_struct_mem);
324 	if (ret) {
325 		DBG_ERR("Failed to Allocate error buffer ret : %d\n",
326 			ret);
327 		goto err_out;
328 	}
329 
330 	/* Calculate error buffer size */
331 	/* The valid tag values are from 1, 2, ..., softs->max_outstanding_io
332 	 * The rcb and error buffer will be accessed by using the tag as index
333 	 * As 0 tag  index is not used, we need to allocate one extra.
334 	 */
335 	num_elem = softs->pqi_cap.max_outstanding_io + 1;
336 	elem_size = PQISRC_ERR_BUF_ELEM_SIZE;
337 	softs->err_buf_dma_mem.size = num_elem * elem_size;
338 
339 	/* Allocate error buffer */
340 	softs->err_buf_dma_mem.align = PQISRC_ERR_BUF_DMA_ALIGN;
341 	softs->err_buf_dma_mem.tag = "error_buffer";
342 	ret = os_dma_mem_alloc(softs, &softs->err_buf_dma_mem);
343 	if (ret) {
344 		DBG_ERR("Failed to Allocate error buffer ret : %d\n",
345 			ret);
346 		goto err_error_buf_alloc;
347 	}
348 
349 	/* Fill init struct */
350 	init_struct = (struct init_base_struct *)DMA_TO_VIRT(&init_struct_mem);
351 	init_struct->revision = PQISRC_INIT_STRUCT_REVISION;
352 	init_struct->flags    = 0;
353 	init_struct->err_buf_paddr_l = DMA_PHYS_LOW(&softs->err_buf_dma_mem);
354 	init_struct->err_buf_paddr_h = DMA_PHYS_HIGH(&softs->err_buf_dma_mem);
355 	init_struct->err_buf_elem_len = elem_size;
356 	init_struct->err_buf_num_elem = num_elem;
357 
358 	mb[0] = SIS_CMD_INIT_BASE_STRUCT_ADDRESS;
359 	mb[1] = DMA_PHYS_LOW(&init_struct_mem);
360 	mb[2] = DMA_PHYS_HIGH(&init_struct_mem);
361 	mb[3] = init_struct_mem.size;
362 
363 	ret = pqisrc_send_sis_cmd(softs, mb);
364 	if (ret)
365 		goto err_sis_cmd;
366 
367 	DBG_FUNC("OUT\n");
368 	os_dma_mem_free(softs, &init_struct_mem);
369 	return ret;
370 
371 err_sis_cmd:
372 	os_dma_mem_free(softs, &softs->err_buf_dma_mem);
373 err_error_buf_alloc:
374 	os_dma_mem_free(softs, &init_struct_mem);
375 err_out:
376 	DBG_FUNC("OUT failed %d\n", ret);
377 	return PQI_STATUS_FAILURE;
378 }
379 
380 /*
381  * SIS initialization of the adapter in a sequence of
382  * - GET_ADAPTER_PROPERTIES
383  * - GET_COMM_PREFERRED_SETTINGS
384  * - GET_PQI_CAPABILITIES
385  * - INIT_STRUCT_BASE ADDR
386  */
387 int
388 pqisrc_sis_init(pqisrc_softstate_t *softs)
389 {
390 	int ret = PQI_STATUS_SUCCESS;
391 	uint32_t prop = 0;
392 	uint32_t ext_prop = 0;
393 
394 	DBG_FUNC("IN\n");
395 
396 	ret = pqisrc_force_sis(softs);
397 	if (ret) {
398 		DBG_ERR("Failed to switch back the adapter to SIS mode!\n");
399 		goto err_out;
400 	}
401 
402 	/* Check FW status ready	*/
403 	ret = pqisrc_check_fw_status(softs);
404 	if (ret) {
405 		DBG_ERR("PQI Controller is not ready !!!\n");
406 		goto err_out;
407 	}
408 
409 	/* Check For PQI support(19h) */
410 	ret = pqisrc_get_adapter_properties(softs, &prop, &ext_prop);
411 	if (ret) {
412 		DBG_ERR("Failed to get adapter properties\n");
413 		goto err_out;
414 	}
415 	if (!((prop & SIS_SUPPORT_EXT_OPT) &&
416 		(ext_prop & SIS_SUPPORT_PQI))) {
417 		DBG_ERR("PQI Mode Not Supported\n");
418 		ret = PQI_STATUS_FAILURE;
419 		goto err_out;
420 	}
421 
422 	softs->pqi_reset_quiesce_allowed = false;
423 	if (ext_prop & SIS_SUPPORT_PQI_RESET_QUIESCE)
424 		softs->pqi_reset_quiesce_allowed = true;
425 
426 	/* Send GET_COMM_PREFERRED_SETTINGS (26h)  */
427 	ret = pqisrc_get_preferred_settings(softs);
428 	if (ret) {
429 		DBG_ERR("Failed to get adapter pref settings\n");
430 		goto err_out;
431 	}
432 
433 	/* Get PQI settings , 3000h*/
434 	ret = pqisrc_get_sis_pqi_cap(softs);
435 	if (ret) {
436 		DBG_ERR("Failed to get PQI Capabilities\n");
437 		goto err_out;
438 	}
439 
440 	/* We need to allocate DMA memory here ,
441 	 * Do any os specific DMA setup.
442 	 */
443 	ret = os_dma_setup(softs);
444 	if (ret) {
445 		DBG_ERR("Failed to Setup DMA\n");
446 		goto err_out;
447 	}
448 
449 	/* Init struct base addr */
450 	ret = pqisrc_init_struct_base(softs);
451 	if (ret) {
452 		DBG_ERR("Failed to set init struct base addr\n");
453 		goto err_dma;
454 	}
455 
456 
457 	DBG_FUNC("OUT\n");
458 	return ret;
459 
460 err_dma:
461 	os_dma_destroy(softs);
462 err_out:
463 	DBG_FUNC("OUT failed\n");
464 	return ret;
465 }
466 
467 /* Deallocate the resources used during SIS initialization */
468 void
469 pqisrc_sis_uninit(pqisrc_softstate_t *softs)
470 {
471 	DBG_FUNC("IN\n");
472 
473 	os_dma_mem_free(softs, &softs->err_buf_dma_mem);
474 
475 	os_dma_destroy(softs);
476 	os_resource_free(softs);
477 	pqi_reset(softs);
478 
479 
480 	DBG_FUNC("OUT\n");
481 }
482 
483 int
484 pqisrc_sis_wait_for_db_bit_to_clear(pqisrc_softstate_t *softs, uint32_t bit)
485 {
486 	int rcode = PQI_STATUS_SUCCESS;
487 	uint32_t db_reg;
488 	uint32_t loop_cnt = 0;
489 
490 	DBG_FUNC("IN\n");
491 
492 	while (1) {
493 		db_reg = PCI_MEM_GET32(softs, &softs->ioa_reg->host_to_ioa_db,
494 				LEGACY_SIS_IDBR);
495 		if ((db_reg & bit) == 0)
496 			break;
497 		if (GET_FW_STATUS(softs) & PQI_CTRL_KERNEL_PANIC) {
498 			DBG_ERR("controller kernel panic\n");
499 			rcode = PQI_STATUS_FAILURE;
500 			break;
501 		}
502 		if (loop_cnt++ == SIS_DB_BIT_CLEAR_TIMEOUT_CNT) {
503 			DBG_ERR("door-bell reg bit 0x%x not cleared\n", bit);
504 			rcode = PQI_STATUS_TIMEOUT;
505 			break;
506 		}
507 		OS_SLEEP(500);
508 	}
509 
510 	DBG_FUNC("OUT\n");
511 
512 	return rcode;
513 }
514