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