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/isci/scil/scic_sds_unsolicited_frame_control.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  * SPDX-License-Identifier: BSD-2-Clause OR GPL-2.0
    3  *
    4  * This file is provided under a dual BSD/GPLv2 license.  When using or
    5  * redistributing this file, you may do so under either license.
    6  *
    7  * GPL LICENSE SUMMARY
    8  *
    9  * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
   10  *
   11  * This program is free software; you can redistribute it and/or modify
   12  * it under the terms of version 2 of the GNU General Public License as
   13  * published by the Free Software Foundation.
   14  *
   15  * This program is distributed in the hope that it will be useful, but
   16  * WITHOUT ANY WARRANTY; without even the implied warranty of
   17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   18  * General Public License for more details.
   19  *
   20  * You should have received a copy of the GNU General Public License
   21  * along with this program; if not, write to the Free Software
   22  * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
   23  * The full GNU General Public License is included in this distribution
   24  * in the file called LICENSE.GPL.
   25  *
   26  * BSD LICENSE
   27  *
   28  * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
   29  * All rights reserved.
   30  *
   31  * Redistribution and use in source and binary forms, with or without
   32  * modification, are permitted provided that the following conditions
   33  * are met:
   34  *
   35  *   * Redistributions of source code must retain the above copyright
   36  *     notice, this list of conditions and the following disclaimer.
   37  *   * Redistributions in binary form must reproduce the above copyright
   38  *     notice, this list of conditions and the following disclaimer in
   39  *     the documentation and/or other materials provided with the
   40  *     distribution.
   41  *
   42  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   43  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   44  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
   45  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
   46  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   47  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   48  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   49  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   50  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   51  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
   52  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   53  */
   54 
   55 #include <sys/cdefs.h>
   56 __FBSDID("$FreeBSD$");
   57 
   58 /**
   59  * @file
   60  *
   61  * @brief This file contains the implementation of the
   62  *        SCIC_SDS_UNSOLICITED_FRAME_CONTROL object and it's public,
   63  *        protected, and private methods.
   64  */
   65 
   66 #include <dev/isci/scil/scic_sds_unsolicited_frame_control.h>
   67 #include <dev/isci/scil/scu_registers.h>
   68 #include <dev/isci/scil/scic_sds_controller.h>
   69 #include <dev/isci/scil/scic_user_callback.h>
   70 #include <dev/isci/scil/sci_util.h>
   71 
   72 /**
   73  * @brief The UF buffer address table size must be programmed to a power
   74  *        of 2.  Find the first power of 2 that is equal to or greater then
   75  *        the number of unsolicited frame buffers to be utilized.
   76  *
   77  * @param[in,out] uf_control This parameter specifies the UF control
   78  *                object for which to update the address table count.
   79  *
   80  * @return none
   81  */
   82 void scic_sds_unsolicited_frame_control_set_address_table_count(
   83    SCIC_SDS_UNSOLICITED_FRAME_CONTROL_T *uf_control
   84 )
   85 {
   86    uf_control->address_table.count = SCU_MIN_UF_TABLE_ENTRIES;
   87    while (
   88             (uf_control->address_table.count < uf_control->buffers.count)
   89          && (uf_control->address_table.count < SCU_ABSOLUTE_MAX_UNSOLICITED_FRAMES)
   90          )
   91    {
   92       uf_control->address_table.count <<= 1;
   93    }
   94 }
   95 
   96 /**
   97  * @brief This method will program the unsolicited frames (UFs) into
   98  *        the UF address table and construct the UF frame structure
   99  *        being modeled in the core.  It will handle the case where
  100  *        some of the UFs are not being used and thus should have
  101  *        entries programmed to zero in the address table.
  102  *
  103  * @param[in,out] uf_control This parameter specifies the unsolicted
  104  *                frame control object for which to construct the
  105  *                unsolicited frames objects.
  106  * @param[in]     uf_buffer_phys_address This parameter specifies the
  107  *                physical address for the first unsolicited frame
  108  *                buffer.
  109  * @param[in]     uf_buffer_virt_address This parameter specifies the
  110  *                virtual address for the first unsolicited frame
  111  *                buffer.
  112  * @param[in]     unused_uf_header_entries This parameter specifies
  113  *                the number of unused UF headers.  This value can
  114  *                be non-zero when there are a non-power of 2 number
  115  *                of unsolicited frames being supported.
  116  * @param[in]     used_uf_header_entries This parameter specifies
  117  *                the number of actually utilized UF headers.
  118  *
  119  * @return none
  120  */
  121 static
  122 void scic_sds_unsolicited_frame_control_construct_frames(
  123    SCIC_SDS_UNSOLICITED_FRAME_CONTROL_T *uf_control,
  124    SCI_PHYSICAL_ADDRESS                  uf_buffer_phys_address,
  125    POINTER_UINT                          uf_buffer_virt_address,
  126    U32                                   unused_uf_header_entries,
  127    U32                                   used_uf_header_entries
  128 )
  129 {
  130    U32                           index;
  131    SCIC_SDS_UNSOLICITED_FRAME_T *uf;
  132 
  133    // Program the unused buffers into the UF address table and the
  134    // controller's array of UFs.
  135    for (index = 0; index < unused_uf_header_entries; index++)
  136    {
  137       uf = &uf_control->buffers.array[index];
  138 
  139       sci_cb_make_physical_address(
  140          uf_control->address_table.array[index], 0, 0
  141       );
  142       uf->buffer = NULL;
  143       uf->header = &uf_control->headers.array[index];
  144       uf->state  = UNSOLICITED_FRAME_EMPTY;
  145    }
  146 
  147    // Program the actual used UF buffers into the UF address table and
  148    // the controller's array of UFs.
  149    for (index = unused_uf_header_entries;
  150         index < unused_uf_header_entries + used_uf_header_entries;
  151         index++)
  152    {
  153       uf = &uf_control->buffers.array[index];
  154 
  155       uf_control->address_table.array[index] = uf_buffer_phys_address;
  156 
  157       uf->buffer = (void*) uf_buffer_virt_address;
  158       uf->header = &uf_control->headers.array[index];
  159       uf->state  = UNSOLICITED_FRAME_EMPTY;
  160 
  161       // Increment the address of the physical and virtual memory pointers
  162       // Everything is aligned on 1k boundary with an increment of 1k
  163       uf_buffer_virt_address += SCU_UNSOLICITED_FRAME_BUFFER_SIZE;
  164       sci_physical_address_add(
  165          uf_buffer_phys_address, SCU_UNSOLICITED_FRAME_BUFFER_SIZE
  166       );
  167    }
  168 }
  169 
  170 /**
  171  * @brief This method constructs the various members of the unsolicted
  172  *        frame control object (buffers, headers, address, table, etc).
  173  *
  174  * @param[in,out] uf_control This parameter specifies the unsolicited
  175  *                frame control object to construct.
  176  * @param[in]     mde This parameter specifies the memory descriptor
  177  *                from which to derive all of the address information
  178  *                needed to get the unsolicited frame functionality
  179  *                working.
  180  * @param[in]     controller This parameter specifies the controller
  181  *                object associated with the uf_control being constructed.
  182  *
  183  * @return none
  184  */
  185 void scic_sds_unsolicited_frame_control_construct(
  186    SCIC_SDS_UNSOLICITED_FRAME_CONTROL_T *uf_control,
  187    SCI_PHYSICAL_MEMORY_DESCRIPTOR_T     *mde,
  188    SCIC_SDS_CONTROLLER_T                *controller
  189 )
  190 {
  191    U32  unused_uf_header_entries;
  192    U32  used_uf_header_entries;
  193    U32  used_uf_buffer_bytes;
  194    U32  unused_uf_header_bytes;
  195    U32  used_uf_header_bytes;
  196    SCI_PHYSICAL_ADDRESS  uf_buffer_phys_address;
  197 
  198    // Prepare all of the memory sizes for the UF headers, UF address
  199    // table, and UF buffers themselves.
  200    used_uf_buffer_bytes     = uf_control->buffers.count
  201                               * SCU_UNSOLICITED_FRAME_BUFFER_SIZE;
  202    unused_uf_header_entries = uf_control->address_table.count
  203                               - uf_control->buffers.count;
  204    used_uf_header_entries   = uf_control->buffers.count;
  205    unused_uf_header_bytes   = unused_uf_header_entries
  206                               * sizeof(SCU_UNSOLICITED_FRAME_HEADER_T);
  207    used_uf_header_bytes     = used_uf_header_entries
  208                               * sizeof(SCU_UNSOLICITED_FRAME_HEADER_T);
  209 
  210    // The Unsolicited Frame buffers are set at the start of the UF
  211    // memory descriptor entry.  The headers and address table will be
  212    // placed after the buffers.
  213    uf_buffer_phys_address = mde->physical_address;
  214 
  215    // Program the location of the UF header table into the SCU.
  216    // Notes:
  217    // - The address must align on a 64-byte boundary. Guaranteed to be
  218    //   on 64-byte boundary already 1KB boundary for unsolicited frames.
  219    // - Program unused header entries to overlap with the last
  220    //   unsolicited frame.  The silicon will never DMA to these unused
  221    //   headers, since we program the UF address table pointers to
  222    //   NULL.
  223    uf_control->headers.physical_address = uf_buffer_phys_address;
  224    sci_physical_address_add(
  225       uf_control->headers.physical_address, used_uf_buffer_bytes);
  226    sci_physical_address_subtract(
  227       uf_control->headers.physical_address, unused_uf_header_bytes);
  228 
  229    uf_control->headers.array = (SCU_UNSOLICITED_FRAME_HEADER_T*)
  230       ((U8 *)mde->virtual_address + used_uf_buffer_bytes - unused_uf_header_bytes);
  231 
  232    // Program the location of the UF address table into the SCU.
  233    // Notes:
  234    // - The address must align on a 64-bit boundary. Guaranteed to be on 64
  235    //   byte boundary already due to above programming headers being on a
  236    //   64-bit boundary and headers are on a 64-bytes in size.
  237    uf_control->address_table.physical_address = uf_buffer_phys_address;
  238    sci_physical_address_add(
  239       uf_control->address_table.physical_address, used_uf_buffer_bytes);
  240    sci_physical_address_add(
  241       uf_control->address_table.physical_address, used_uf_header_bytes);
  242 
  243    uf_control->address_table.array = (SCI_PHYSICAL_ADDRESS*)
  244       ((U8 *)mde->virtual_address + used_uf_buffer_bytes + used_uf_header_bytes);
  245 
  246    uf_control->get = 0;
  247 
  248    // UF buffer requirements are:
  249    // - The last entry in the UF queue is not NULL.
  250    // - There is a power of 2 number of entries (NULL or not-NULL)
  251    //   programmed into the queue.
  252    // - Aligned on a 1KB boundary.
  253 
  254    // If the user provided less then the maximum amount of memory,
  255    // then be sure that we programm the first entries in the UF
  256    // address table to NULL.
  257    scic_sds_unsolicited_frame_control_construct_frames(
  258       uf_control,
  259       uf_buffer_phys_address,
  260       (POINTER_UINT) mde->virtual_address,
  261       unused_uf_header_entries,
  262       used_uf_header_entries
  263    );
  264 }
  265 
  266 /**
  267  * @brief This method returns the frame header for the specified frame
  268  *        index.
  269  *
  270  * @param[in] uf_control
  271  * @param[in] frame_index
  272  * @param[out] frame_header
  273  *
  274  * @return SCI_STATUS
  275  */
  276 SCI_STATUS scic_sds_unsolicited_frame_control_get_header(
  277    SCIC_SDS_UNSOLICITED_FRAME_CONTROL_T *uf_control,
  278    U32                                   frame_index,
  279    void                                **frame_header
  280 )
  281 {
  282    if (frame_index < uf_control->address_table.count)
  283    {
  284       // Skip the first word in the frame since this is a control word used
  285       // by the hardware.
  286       *frame_header = &uf_control->buffers.array[frame_index].header->data;
  287 
  288       return SCI_SUCCESS;
  289    }
  290 
  291    return SCI_FAILURE_INVALID_PARAMETER_VALUE;
  292 }
  293 
  294 /**
  295  * @brief This method returns the frame buffer for the specified frame
  296  *        index.
  297  *
  298  * @param[in] uf_control
  299  * @param[in] frame_index
  300  * @param[out] frame_buffer
  301  *
  302  * @return SCI_STATUS
  303  */
  304 SCI_STATUS scic_sds_unsolicited_frame_control_get_buffer(
  305    SCIC_SDS_UNSOLICITED_FRAME_CONTROL_T *uf_control,
  306    U32                                   frame_index,
  307    void                                **frame_buffer
  308 )
  309 {
  310    if (frame_index < uf_control->address_table.count)
  311    {
  312       *frame_buffer = uf_control->buffers.array[frame_index].buffer;
  313 
  314       return SCI_SUCCESS;
  315    }
  316 
  317    return SCI_FAILURE_INVALID_PARAMETER_VALUE;
  318 }
  319 
  320 /**
  321  * @brief This method releases the frame once this is done the frame is
  322  *        available for re-use by the hardware.  The data contained in the
  323  *        frame header and frame buffer is no longer valid.
  324  *
  325  * @param[in] uf_control This parameter specifies the UF control object
  326  * @param[in] frame_index This parameter specifies the frame index to
  327  *            attempt to release.
  328  *
  329  * @return This method returns an indication to the caller as to whether
  330  *         the unsolicited frame get pointer should be updated.
  331  * @retval TRUE This value indicates the unsolicited frame get pointer
  332  *         should be updated (i.e. write SCU_UFQGP_WRITE).
  333  * @retval FALSE This value indicates the get pointer should not be
  334  *         updated.
  335  */
  336 BOOL scic_sds_unsolicited_frame_control_release_frame(
  337    SCIC_SDS_UNSOLICITED_FRAME_CONTROL_T *uf_control,
  338    U32                                   frame_index
  339 )
  340 {
  341    U32 frame_get;
  342    U32 frame_cycle;
  343 
  344    frame_get   = uf_control->get & (uf_control->address_table.count - 1);
  345    frame_cycle = uf_control->get & uf_control->address_table.count;
  346 
  347    // In the event there are NULL entries in the UF table, we need to
  348    // advance the get pointer in order to find out if this frame should
  349    // be released (i.e. update the get pointer).
  350    while (
  351             (
  352                (sci_cb_physical_address_lower(
  353                    uf_control->address_table.array[frame_get]) == 0)
  354             && (sci_cb_physical_address_upper(
  355                    uf_control->address_table.array[frame_get]) == 0)
  356             )
  357          && (frame_get < uf_control->address_table.count)
  358          )
  359    {
  360       frame_get++;
  361    }
  362 
  363    // The table has a NULL entry as it's last element.  This is
  364    // illegal.
  365    ASSERT(frame_get < uf_control->address_table.count);
  366 
  367    if (frame_index < uf_control->address_table.count)
  368    {
  369       uf_control->buffers.array[frame_index].state = UNSOLICITED_FRAME_RELEASED;
  370 
  371       // The frame index is equal to the current get pointer so we
  372       // can now free up all of the frame entries that
  373       if (frame_get == frame_index)
  374       {
  375          while (
  376                   uf_control->buffers.array[frame_get].state
  377                == UNSOLICITED_FRAME_RELEASED
  378                )
  379          {
  380             uf_control->buffers.array[frame_get].state = UNSOLICITED_FRAME_EMPTY;
  381 
  382             INCREMENT_QUEUE_GET(
  383                frame_get,
  384                frame_cycle,
  385                uf_control->address_table.count - 1,
  386                uf_control->address_table.count
  387             );
  388          }
  389 
  390          uf_control->get =
  391                   (SCU_UFQGP_GEN_BIT(ENABLE_BIT) | frame_cycle | frame_get);
  392 
  393          return TRUE;
  394       }
  395       else
  396       {
  397          // Frames remain in use until we advance the get pointer
  398          // so there is nothing we can do here
  399       }
  400    }
  401 
  402    return FALSE;
  403 }
  404 

Cache object: 06fdb916e4ce48e6c61e0fa3a24a7824


[ 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.