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