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 167 /* Copy Command to mailbox */ 168 for (i = 0; i < 6; i++) 169 PCI_MEM_PUT32(softs, &softs->ioa_reg->mb[i], 170 LEGACY_SIS_SRCV_MAILBOX+i*4, LE_32(mb[i])); 171 172 PCI_MEM_PUT32(softs, &softs->ioa_reg->ioa_to_host_db_clr, 173 LEGACY_SIS_ODBR_R, LE_32(0x1000)); 174 175 /* Submit the command */ 176 PCI_MEM_PUT32(softs, &softs->ioa_reg->host_to_ioa_db, 177 LEGACY_SIS_IDBR, LE_32(SIS_CMD_SUBMIT)); 178 179 #ifdef SIS_POLL_WAIT 180 /* Wait for 20 milli sec to poll */ 181 OS_BUSYWAIT(SIS_POLL_START_WAIT_TIME); 182 #endif 183 184 val = PCI_MEM_GET32(softs, &softs->ioa_reg->ioa_to_host_db, LEGACY_SIS_ODBR_R); 185 186 DBG_FUNC("val : %x\n",val); 187 /* Spin waiting for the command to complete */ 188 COND_WAIT((PCI_MEM_GET32(softs, &softs->ioa_reg->ioa_to_host_db, LEGACY_SIS_ODBR_R) & 189 SIS_CMD_COMPLETE), timeout); 190 if (!timeout) { 191 DBG_ERR("Sync command %x, timedout\n", mb[0]); 192 ret = PQI_STATUS_TIMEOUT; 193 goto err_out; 194 } 195 /* Check command status */ 196 mb[0] = LE_32(PCI_MEM_GET32(softs, &softs->ioa_reg->mb[0], LEGACY_SIS_SRCV_MAILBOX)); 197 198 if (mb[0] != SIS_CMD_STATUS_SUCCESS) { 199 DBG_ERR("SIS cmd failed with status = 0x%x\n", 200 mb[0]); 201 ret = PQI_STATUS_FAILURE; 202 goto err_out; 203 } 204 205 /* Copy the mailbox back */ 206 for (i = 1; i < 6; i++) 207 mb[i] = LE_32(PCI_MEM_GET32(softs, &softs->ioa_reg->mb[i], LEGACY_SIS_SRCV_MAILBOX+i*4)); 208 209 DBG_FUNC("OUT\n"); 210 return ret; 211 212 err_out: 213 DBG_FUNC("OUT failed\n"); 214 return ret; 215 } 216 217 /* First SIS command for the adapter to check PQI support */ 218 int pqisrc_get_adapter_properties(pqisrc_softstate_t *softs, 219 uint32_t *prop, uint32_t *ext_prop) 220 { 221 int ret = PQI_STATUS_SUCCESS; 222 uint32_t mb[6] = {0}; 223 224 DBG_FUNC("IN\n"); 225 226 mb[0] = SIS_CMD_GET_ADAPTER_PROPERTIES; 227 ret = pqisrc_send_sis_cmd(softs, mb); 228 if (!ret) { 229 DBG_INIT("GET_PROPERTIES prop = %x, ext_prop = %x\n", 230 mb[1], mb[4]); 231 *prop = mb[1]; 232 *ext_prop = mb[4]; 233 } 234 235 DBG_FUNC("OUT\n"); 236 return ret; 237 } 238 239 /* Second SIS command to the adapter GET_COMM_PREFERRED_SETTINGS */ 240 int pqisrc_get_preferred_settings(pqisrc_softstate_t *softs) 241 { 242 int ret = PQI_STATUS_SUCCESS; 243 uint32_t mb[6] = {0}; 244 245 DBG_FUNC("IN\n"); 246 247 mb[0] = SIS_CMD_GET_COMM_PREFERRED_SETTINGS; 248 ret = pqisrc_send_sis_cmd(softs, mb); 249 if (!ret) { 250 /* 31:16 maximum command size in KB */ 251 softs->pref_settings.max_cmd_size = mb[1] >> 16; 252 /* 15:00: Maximum FIB size in bytes */ 253 softs->pref_settings.max_fib_size = mb[1] & 0x0000FFFF; 254 DBG_INIT("cmd size = %x, fib size = %x\n", 255 softs->pref_settings.max_cmd_size, 256 softs->pref_settings.max_fib_size); 257 } 258 259 DBG_FUNC("OUT\n"); 260 return ret; 261 } 262 263 /* Get supported PQI capabilities from the adapter */ 264 int pqisrc_get_sis_pqi_cap(pqisrc_softstate_t *softs) 265 { 266 int ret = PQI_STATUS_SUCCESS; 267 uint32_t mb[6] = {0}; 268 269 DBG_FUNC("IN\n"); 270 271 mb[0] = SIS_CMD_GET_PQI_CAPABILITIES; 272 ret = pqisrc_send_sis_cmd(softs, mb); 273 if (!ret) { 274 softs->pqi_cap.max_sg_elem = mb[1]; 275 softs->pqi_cap.max_transfer_size = mb[2]; 276 softs->pqi_cap.max_outstanding_io = mb[3]; 277 softs->pqi_cap.conf_tab_off = mb[4]; 278 softs->pqi_cap.conf_tab_sz = mb[5]; 279 280 DBG_INIT("max_sg_elem = %x\n", 281 softs->pqi_cap.max_sg_elem); 282 DBG_INIT("max_transfer_size = %x\n", 283 softs->pqi_cap.max_transfer_size); 284 DBG_INIT("max_outstanding_io = %x\n", 285 softs->pqi_cap.max_outstanding_io); 286 } 287 288 DBG_FUNC("OUT\n"); 289 return ret; 290 } 291 292 /* Send INIT STRUCT BASE ADDR - one of the SIS command */ 293 int pqisrc_init_struct_base(pqisrc_softstate_t *softs) 294 { 295 int ret = PQI_STATUS_SUCCESS; 296 uint32_t elem_size = 0; 297 uint32_t num_elem = 0; 298 struct dma_mem init_struct_mem = {0}; 299 struct init_base_struct *init_struct = NULL; 300 uint32_t mb[6] = {0}; 301 302 DBG_FUNC("IN\n"); 303 304 /* Allocate init struct */ 305 memset(&init_struct_mem, 0, sizeof(struct dma_mem)); 306 init_struct_mem.size = sizeof(struct init_base_struct); 307 init_struct_mem.align = PQISRC_INIT_STRUCT_DMA_ALIGN; 308 init_struct_mem.tag = "init_struct"; 309 ret = os_dma_mem_alloc(softs, &init_struct_mem); 310 if (ret) { 311 DBG_ERR("Failed to Allocate error buffer ret : %d\n", 312 ret); 313 goto err_out; 314 } 315 316 /* Calculate error buffer size */ 317 /* The valid tag values are from 1, 2, ..., softs->max_outstanding_io 318 * The rcb and error buffer will be accessed by using the tag as index 319 * As 0 tag index is not used, we need to allocate one extra. 320 */ 321 num_elem = softs->pqi_cap.max_outstanding_io + 1; 322 elem_size = PQISRC_ERR_BUF_ELEM_SIZE; 323 softs->err_buf_dma_mem.size = num_elem * elem_size; 324 325 /* Allocate error buffer */ 326 softs->err_buf_dma_mem.align = PQISRC_ERR_BUF_DMA_ALIGN; 327 softs->err_buf_dma_mem.tag = "error_buffer"; 328 ret = os_dma_mem_alloc(softs, &softs->err_buf_dma_mem); 329 if (ret) { 330 DBG_ERR("Failed to Allocate error buffer ret : %d\n", 331 ret); 332 goto err_error_buf_alloc; 333 } 334 335 /* Fill init struct */ 336 init_struct = (struct init_base_struct *)DMA_TO_VIRT(&init_struct_mem); 337 init_struct->revision = PQISRC_INIT_STRUCT_REVISION; 338 init_struct->flags = 0; 339 init_struct->err_buf_paddr_l = DMA_PHYS_LOW(&softs->err_buf_dma_mem); 340 init_struct->err_buf_paddr_h = DMA_PHYS_HIGH(&softs->err_buf_dma_mem); 341 init_struct->err_buf_elem_len = elem_size; 342 init_struct->err_buf_num_elem = num_elem; 343 344 mb[0] = SIS_CMD_INIT_BASE_STRUCT_ADDRESS; 345 mb[1] = DMA_PHYS_LOW(&init_struct_mem); 346 mb[2] = DMA_PHYS_HIGH(&init_struct_mem); 347 mb[3] = init_struct_mem.size; 348 349 ret = pqisrc_send_sis_cmd(softs, mb); 350 if (ret) 351 goto err_sis_cmd; 352 353 DBG_FUNC("OUT\n"); 354 os_dma_mem_free(softs, &init_struct_mem); 355 return ret; 356 357 err_sis_cmd: 358 os_dma_mem_free(softs, &softs->err_buf_dma_mem); 359 err_error_buf_alloc: 360 os_dma_mem_free(softs, &init_struct_mem); 361 err_out: 362 DBG_FUNC("OUT failed %d\n", ret); 363 return PQI_STATUS_FAILURE; 364 } 365 366 /* 367 * SIS initialization of the adapter in a sequence of 368 * - GET_ADAPTER_PROPERTIES 369 * - GET_COMM_PREFERRED_SETTINGS 370 * - GET_PQI_CAPABILITIES 371 * - INIT_STRUCT_BASE ADDR 372 */ 373 int pqisrc_sis_init(pqisrc_softstate_t *softs) 374 { 375 int ret = PQI_STATUS_SUCCESS; 376 uint32_t prop = 0; 377 uint32_t ext_prop = 0; 378 379 DBG_FUNC("IN\n"); 380 381 ret = pqisrc_force_sis(softs); 382 if (ret) { 383 DBG_ERR("Failed to switch back the adapter to SIS mode!\n"); 384 goto err_out; 385 } 386 387 /* Check FW status ready */ 388 ret = pqisrc_check_fw_status(softs); 389 if (ret) { 390 DBG_ERR("PQI Controller is not ready !!!\n"); 391 goto err_out; 392 } 393 394 /* Check For PQI support(19h) */ 395 ret = pqisrc_get_adapter_properties(softs, &prop, &ext_prop); 396 if (ret) { 397 DBG_ERR("Failed to get adapter properties\n"); 398 goto err_out; 399 } 400 if (!((prop & SIS_SUPPORT_EXT_OPT) && 401 (ext_prop & SIS_SUPPORT_PQI))) { 402 DBG_ERR("PQI Mode Not Supported\n"); 403 ret = PQI_STATUS_FAILURE; 404 goto err_out; 405 } 406 407 softs->pqi_reset_quiesce_allowed = false; 408 if (ext_prop & SIS_SUPPORT_PQI_RESET_QUIESCE) 409 softs->pqi_reset_quiesce_allowed = true; 410 411 /* Send GET_COMM_PREFERRED_SETTINGS (26h) */ 412 ret = pqisrc_get_preferred_settings(softs); 413 if (ret) { 414 DBG_ERR("Failed to get adapter pref settings\n"); 415 goto err_out; 416 } 417 418 /* Get PQI settings , 3000h*/ 419 ret = pqisrc_get_sis_pqi_cap(softs); 420 if (ret) { 421 DBG_ERR("Failed to get PQI Capabilities\n"); 422 goto err_out; 423 } 424 425 /* Init struct base addr */ 426 ret = pqisrc_init_struct_base(softs); 427 if (ret) { 428 DBG_ERR("Failed to set init struct base addr\n"); 429 goto err_out; 430 } 431 432 DBG_FUNC("OUT\n"); 433 return ret; 434 435 err_out: 436 DBG_FUNC("OUT failed\n"); 437 return ret; 438 } 439 440 /* Deallocate the resources used during SIS initialization */ 441 void pqisrc_sis_uninit(pqisrc_softstate_t *softs) 442 { 443 DBG_FUNC("IN\n"); 444 445 os_dma_mem_free(softs, &softs->err_buf_dma_mem); 446 os_resource_free(softs); 447 pqi_reset(softs); 448 449 DBG_FUNC("OUT\n"); 450 } 451 452 int pqisrc_sis_wait_for_db_bit_to_clear(pqisrc_softstate_t *softs, uint32_t bit) 453 { 454 int rcode = PQI_STATUS_SUCCESS; 455 uint32_t db_reg; 456 uint32_t loop_cnt = 0; 457 458 DBG_FUNC("IN\n"); 459 460 while (1) { 461 db_reg = PCI_MEM_GET32(softs, &softs->ioa_reg->host_to_ioa_db, 462 LEGACY_SIS_IDBR); 463 if ((db_reg & bit) == 0) 464 break; 465 if (GET_FW_STATUS(softs) & PQI_CTRL_KERNEL_PANIC) { 466 DBG_ERR("controller kernel panic\n"); 467 rcode = PQI_STATUS_FAILURE; 468 break; 469 } 470 if (loop_cnt++ == SIS_DB_BIT_CLEAR_TIMEOUT_CNT) { 471 DBG_ERR("door-bell reg bit 0x%x not cleared\n", bit); 472 rcode = PQI_STATUS_TIMEOUT; 473 break; 474 } 475 OS_SLEEP(500); 476 } 477 478 DBG_FUNC("OUT\n"); 479 480 return rcode; 481 } 482