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