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