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