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 }
Cache object: cc79a8a819d29f55a914d23fe01fcd8b
|