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