The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/smartpqi/smartpqi_sis.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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 }

Cache object: cc79a8a819d29f55a914d23fe01fcd8b


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.