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