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