1230557Sjimharris/*-
2230557Sjimharris * This file is provided under a dual BSD/GPLv2 license.  When using or
3230557Sjimharris * redistributing this file, you may do so under either license.
4230557Sjimharris *
5230557Sjimharris * GPL LICENSE SUMMARY
6230557Sjimharris *
7230557Sjimharris * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
8230557Sjimharris *
9230557Sjimharris * This program is free software; you can redistribute it and/or modify
10230557Sjimharris * it under the terms of version 2 of the GNU General Public License as
11230557Sjimharris * published by the Free Software Foundation.
12230557Sjimharris *
13230557Sjimharris * This program is distributed in the hope that it will be useful, but
14230557Sjimharris * WITHOUT ANY WARRANTY; without even the implied warranty of
15230557Sjimharris * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16230557Sjimharris * General Public License for more details.
17230557Sjimharris *
18230557Sjimharris * You should have received a copy of the GNU General Public License
19230557Sjimharris * along with this program; if not, write to the Free Software
20230557Sjimharris * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
21230557Sjimharris * The full GNU General Public License is included in this distribution
22230557Sjimharris * in the file called LICENSE.GPL.
23230557Sjimharris *
24230557Sjimharris * BSD LICENSE
25230557Sjimharris *
26230557Sjimharris * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
27230557Sjimharris * All rights reserved.
28230557Sjimharris *
29230557Sjimharris * Redistribution and use in source and binary forms, with or without
30230557Sjimharris * modification, are permitted provided that the following conditions
31230557Sjimharris * are met:
32230557Sjimharris *
33230557Sjimharris *   * Redistributions of source code must retain the above copyright
34230557Sjimharris *     notice, this list of conditions and the following disclaimer.
35230557Sjimharris *   * Redistributions in binary form must reproduce the above copyright
36230557Sjimharris *     notice, this list of conditions and the following disclaimer in
37230557Sjimharris *     the documentation and/or other materials provided with the
38230557Sjimharris *     distribution.
39230557Sjimharris *
40230557Sjimharris * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
41230557Sjimharris * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
42230557Sjimharris * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
43230557Sjimharris * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
44230557Sjimharris * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
45230557Sjimharris * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
46230557Sjimharris * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
47230557Sjimharris * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
48230557Sjimharris * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
49230557Sjimharris * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
50230557Sjimharris * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
51230557Sjimharris */
52230557Sjimharris
53230557Sjimharris#include <sys/cdefs.h>
54230557Sjimharris__FBSDID("$FreeBSD$");
55230557Sjimharris
56230557Sjimharris/**
57230557Sjimharris * @file
58230557Sjimharris *
59230557Sjimharris * @brief This file contains the implementation of the
60230557Sjimharris *        SCIC_SDS_UNSOLICITED_FRAME_CONTROL object and it's public,
61230557Sjimharris *        protected, and private methods.
62230557Sjimharris */
63230557Sjimharris
64230557Sjimharris#include <dev/isci/scil/scic_sds_unsolicited_frame_control.h>
65230557Sjimharris#include <dev/isci/scil/scu_registers.h>
66230557Sjimharris#include <dev/isci/scil/scic_sds_controller.h>
67230557Sjimharris#include <dev/isci/scil/scic_user_callback.h>
68230557Sjimharris#include <dev/isci/scil/sci_util.h>
69230557Sjimharris
70230557Sjimharris/**
71230557Sjimharris * @brief The UF buffer address table size must be programmed to a power
72230557Sjimharris *        of 2.  Find the first power of 2 that is equal to or greater then
73230557Sjimharris *        the number of unsolicited frame buffers to be utilized.
74230557Sjimharris *
75230557Sjimharris * @param[in,out] uf_control This parameter specifies the UF control
76230557Sjimharris *                object for which to update the address table count.
77230557Sjimharris *
78230557Sjimharris * @return none
79230557Sjimharris */
80230557Sjimharrisvoid scic_sds_unsolicited_frame_control_set_address_table_count(
81230557Sjimharris   SCIC_SDS_UNSOLICITED_FRAME_CONTROL_T *uf_control
82230557Sjimharris)
83230557Sjimharris{
84230557Sjimharris   uf_control->address_table.count = SCU_MIN_UF_TABLE_ENTRIES;
85230557Sjimharris   while (
86230557Sjimharris            (uf_control->address_table.count < uf_control->buffers.count)
87230557Sjimharris         && (uf_control->address_table.count < SCU_ABSOLUTE_MAX_UNSOLICITED_FRAMES)
88230557Sjimharris         )
89230557Sjimharris   {
90230557Sjimharris      uf_control->address_table.count <<= 1;
91230557Sjimharris   }
92230557Sjimharris}
93230557Sjimharris
94230557Sjimharris/**
95230557Sjimharris * @brief This method will program the unsolicited frames (UFs) into
96230557Sjimharris *        the UF address table and construct the UF frame structure
97230557Sjimharris *        being modeled in the core.  It will handle the case where
98230557Sjimharris *        some of the UFs are not being used and thus should have
99230557Sjimharris *        entries programmed to zero in the address table.
100230557Sjimharris *
101230557Sjimharris * @param[in,out] uf_control This parameter specifies the unsolicted
102230557Sjimharris *                frame control object for which to construct the
103230557Sjimharris *                unsolicited frames objects.
104230557Sjimharris * @param[in]     uf_buffer_phys_address This parameter specifies the
105230557Sjimharris *                physical address for the first unsolicited frame
106230557Sjimharris *                buffer.
107230557Sjimharris * @param[in]     uf_buffer_virt_address This parameter specifies the
108230557Sjimharris *                virtual address for the first unsolicited frame
109230557Sjimharris *                buffer.
110230557Sjimharris * @param[in]     unused_uf_header_entries This parameter specifies
111230557Sjimharris *                the number of unused UF headers.  This value can
112230557Sjimharris *                be non-zero when there are a non-power of 2 number
113230557Sjimharris *                of unsolicited frames being supported.
114230557Sjimharris * @param[in]     used_uf_header_entries This parameter specifies
115230557Sjimharris *                the number of actually utilized UF headers.
116230557Sjimharris *
117230557Sjimharris * @return none
118230557Sjimharris */
119230557Sjimharrisstatic
120230557Sjimharrisvoid scic_sds_unsolicited_frame_control_construct_frames(
121230557Sjimharris   SCIC_SDS_UNSOLICITED_FRAME_CONTROL_T *uf_control,
122230557Sjimharris   SCI_PHYSICAL_ADDRESS                  uf_buffer_phys_address,
123230557Sjimharris   POINTER_UINT                          uf_buffer_virt_address,
124230557Sjimharris   U32                                   unused_uf_header_entries,
125230557Sjimharris   U32                                   used_uf_header_entries
126230557Sjimharris)
127230557Sjimharris{
128230557Sjimharris   U32                           index;
129230557Sjimharris   SCIC_SDS_UNSOLICITED_FRAME_T *uf;
130230557Sjimharris
131230557Sjimharris   // Program the unused buffers into the UF address table and the
132230557Sjimharris   // controller's array of UFs.
133230557Sjimharris   for (index = 0; index < unused_uf_header_entries; index++)
134230557Sjimharris   {
135230557Sjimharris      uf = &uf_control->buffers.array[index];
136230557Sjimharris
137230557Sjimharris      sci_cb_make_physical_address(
138230557Sjimharris         uf_control->address_table.array[index], 0, 0
139230557Sjimharris      );
140230557Sjimharris      uf->buffer = NULL;
141230557Sjimharris      uf->header = &uf_control->headers.array[index];
142230557Sjimharris      uf->state  = UNSOLICITED_FRAME_EMPTY;
143230557Sjimharris   }
144230557Sjimharris
145230557Sjimharris   // Program the actual used UF buffers into the UF address table and
146230557Sjimharris   // the controller's array of UFs.
147230557Sjimharris   for (index = unused_uf_header_entries;
148230557Sjimharris        index < unused_uf_header_entries + used_uf_header_entries;
149230557Sjimharris        index++)
150230557Sjimharris   {
151230557Sjimharris      uf = &uf_control->buffers.array[index];
152230557Sjimharris
153230557Sjimharris      uf_control->address_table.array[index] = uf_buffer_phys_address;
154230557Sjimharris
155230557Sjimharris      uf->buffer = (void*) uf_buffer_virt_address;
156230557Sjimharris      uf->header = &uf_control->headers.array[index];
157230557Sjimharris      uf->state  = UNSOLICITED_FRAME_EMPTY;
158230557Sjimharris
159230557Sjimharris      // Increment the address of the physical and virtual memory pointers
160230557Sjimharris      // Everything is aligned on 1k boundary with an increment of 1k
161230557Sjimharris      uf_buffer_virt_address += SCU_UNSOLICITED_FRAME_BUFFER_SIZE;
162230557Sjimharris      sci_physical_address_add(
163230557Sjimharris         uf_buffer_phys_address, SCU_UNSOLICITED_FRAME_BUFFER_SIZE
164230557Sjimharris      );
165230557Sjimharris   }
166230557Sjimharris}
167230557Sjimharris
168230557Sjimharris/**
169230557Sjimharris * @brief This method constructs the various members of the unsolicted
170230557Sjimharris *        frame control object (buffers, headers, address, table, etc).
171230557Sjimharris *
172230557Sjimharris * @param[in,out] uf_control This parameter specifies the unsolicited
173230557Sjimharris *                frame control object to construct.
174230557Sjimharris * @param[in]     mde This parameter specifies the memory descriptor
175230557Sjimharris *                from which to derive all of the address information
176230557Sjimharris *                needed to get the unsolicited frame functionality
177230557Sjimharris *                working.
178230557Sjimharris * @param[in]     controller This parameter specifies the controller
179230557Sjimharris *                object associated with the uf_control being constructed.
180230557Sjimharris *
181230557Sjimharris * @return none
182230557Sjimharris */
183230557Sjimharrisvoid scic_sds_unsolicited_frame_control_construct(
184230557Sjimharris   SCIC_SDS_UNSOLICITED_FRAME_CONTROL_T *uf_control,
185230557Sjimharris   SCI_PHYSICAL_MEMORY_DESCRIPTOR_T     *mde,
186230557Sjimharris   SCIC_SDS_CONTROLLER_T                *controller
187230557Sjimharris)
188230557Sjimharris{
189230557Sjimharris   U32  unused_uf_header_entries;
190230557Sjimharris   U32  used_uf_header_entries;
191230557Sjimharris   U32  used_uf_buffer_bytes;
192230557Sjimharris   U32  unused_uf_header_bytes;
193230557Sjimharris   U32  used_uf_header_bytes;
194230557Sjimharris   SCI_PHYSICAL_ADDRESS  uf_buffer_phys_address;
195230557Sjimharris
196230557Sjimharris   // Prepare all of the memory sizes for the UF headers, UF address
197230557Sjimharris   // table, and UF buffers themselves.
198230557Sjimharris   used_uf_buffer_bytes     = uf_control->buffers.count
199230557Sjimharris                              * SCU_UNSOLICITED_FRAME_BUFFER_SIZE;
200230557Sjimharris   unused_uf_header_entries = uf_control->address_table.count
201230557Sjimharris                              - uf_control->buffers.count;
202230557Sjimharris   used_uf_header_entries   = uf_control->buffers.count;
203230557Sjimharris   unused_uf_header_bytes   = unused_uf_header_entries
204230557Sjimharris                              * sizeof(SCU_UNSOLICITED_FRAME_HEADER_T);
205230557Sjimharris   used_uf_header_bytes     = used_uf_header_entries
206230557Sjimharris                              * sizeof(SCU_UNSOLICITED_FRAME_HEADER_T);
207230557Sjimharris
208230557Sjimharris   // The Unsolicited Frame buffers are set at the start of the UF
209230557Sjimharris   // memory descriptor entry.  The headers and address table will be
210230557Sjimharris   // placed after the buffers.
211230557Sjimharris   uf_buffer_phys_address = mde->physical_address;
212230557Sjimharris
213230557Sjimharris   // Program the location of the UF header table into the SCU.
214230557Sjimharris   // Notes:
215230557Sjimharris   // - The address must align on a 64-byte boundary. Guaranteed to be
216230557Sjimharris   //   on 64-byte boundary already 1KB boundary for unsolicited frames.
217230557Sjimharris   // - Program unused header entries to overlap with the last
218230557Sjimharris   //   unsolicited frame.  The silicon will never DMA to these unused
219230557Sjimharris   //   headers, since we program the UF address table pointers to
220230557Sjimharris   //   NULL.
221230557Sjimharris   uf_control->headers.physical_address = uf_buffer_phys_address;
222230557Sjimharris   sci_physical_address_add(
223230557Sjimharris      uf_control->headers.physical_address, used_uf_buffer_bytes);
224230557Sjimharris   sci_physical_address_subtract(
225230557Sjimharris      uf_control->headers.physical_address, unused_uf_header_bytes);
226230557Sjimharris
227230557Sjimharris   uf_control->headers.array = (SCU_UNSOLICITED_FRAME_HEADER_T*)
228230557Sjimharris      ((U8 *)mde->virtual_address + used_uf_buffer_bytes - unused_uf_header_bytes);
229230557Sjimharris
230230557Sjimharris   // Program the location of the UF address table into the SCU.
231230557Sjimharris   // Notes:
232230557Sjimharris   // - The address must align on a 64-bit boundary. Guaranteed to be on 64
233230557Sjimharris   //   byte boundary already due to above programming headers being on a
234230557Sjimharris   //   64-bit boundary and headers are on a 64-bytes in size.
235230557Sjimharris   uf_control->address_table.physical_address = uf_buffer_phys_address;
236230557Sjimharris   sci_physical_address_add(
237230557Sjimharris      uf_control->address_table.physical_address, used_uf_buffer_bytes);
238230557Sjimharris   sci_physical_address_add(
239230557Sjimharris      uf_control->address_table.physical_address, used_uf_header_bytes);
240230557Sjimharris
241230557Sjimharris   uf_control->address_table.array = (SCI_PHYSICAL_ADDRESS*)
242230557Sjimharris      ((U8 *)mde->virtual_address + used_uf_buffer_bytes + used_uf_header_bytes);
243230557Sjimharris
244230557Sjimharris   uf_control->get = 0;
245230557Sjimharris
246230557Sjimharris   // UF buffer requirements are:
247230557Sjimharris   // - The last entry in the UF queue is not NULL.
248230557Sjimharris   // - There is a power of 2 number of entries (NULL or not-NULL)
249230557Sjimharris   //   programmed into the queue.
250230557Sjimharris   // - Aligned on a 1KB boundary.
251230557Sjimharris
252230557Sjimharris   // If the user provided less then the maximum amount of memory,
253230557Sjimharris   // then be sure that we programm the first entries in the UF
254230557Sjimharris   // address table to NULL.
255230557Sjimharris   scic_sds_unsolicited_frame_control_construct_frames(
256230557Sjimharris      uf_control,
257230557Sjimharris      uf_buffer_phys_address,
258230557Sjimharris      (POINTER_UINT) mde->virtual_address,
259230557Sjimharris      unused_uf_header_entries,
260230557Sjimharris      used_uf_header_entries
261230557Sjimharris   );
262230557Sjimharris}
263230557Sjimharris
264230557Sjimharris/**
265230557Sjimharris * @brief This method returns the frame header for the specified frame
266230557Sjimharris *        index.
267230557Sjimharris *
268230557Sjimharris * @param[in] uf_control
269230557Sjimharris * @param[in] frame_index
270230557Sjimharris * @param[out] frame_header
271230557Sjimharris *
272230557Sjimharris * @return SCI_STATUS
273230557Sjimharris */
274230557SjimharrisSCI_STATUS scic_sds_unsolicited_frame_control_get_header(
275230557Sjimharris   SCIC_SDS_UNSOLICITED_FRAME_CONTROL_T *uf_control,
276230557Sjimharris   U32                                   frame_index,
277230557Sjimharris   void                                **frame_header
278230557Sjimharris)
279230557Sjimharris{
280230557Sjimharris   if (frame_index < uf_control->address_table.count)
281230557Sjimharris   {
282230557Sjimharris      // Skip the first word in the frame since this is a controll word used
283230557Sjimharris      // by the hardware.
284230557Sjimharris      *frame_header = &uf_control->buffers.array[frame_index].header->data;
285230557Sjimharris
286230557Sjimharris      return SCI_SUCCESS;
287230557Sjimharris   }
288230557Sjimharris
289230557Sjimharris   return SCI_FAILURE_INVALID_PARAMETER_VALUE;
290230557Sjimharris}
291230557Sjimharris
292230557Sjimharris/**
293230557Sjimharris * @brief This method returns the frame buffer for the specified frame
294230557Sjimharris *        index.
295230557Sjimharris *
296230557Sjimharris * @param[in] uf_control
297230557Sjimharris * @param[in] frame_index
298230557Sjimharris * @param[out] frame_buffer
299230557Sjimharris *
300230557Sjimharris * @return SCI_STATUS
301230557Sjimharris */
302230557SjimharrisSCI_STATUS scic_sds_unsolicited_frame_control_get_buffer(
303230557Sjimharris   SCIC_SDS_UNSOLICITED_FRAME_CONTROL_T *uf_control,
304230557Sjimharris   U32                                   frame_index,
305230557Sjimharris   void                                **frame_buffer
306230557Sjimharris)
307230557Sjimharris{
308230557Sjimharris   if (frame_index < uf_control->address_table.count)
309230557Sjimharris   {
310230557Sjimharris      *frame_buffer = uf_control->buffers.array[frame_index].buffer;
311230557Sjimharris
312230557Sjimharris      return SCI_SUCCESS;
313230557Sjimharris   }
314230557Sjimharris
315230557Sjimharris   return SCI_FAILURE_INVALID_PARAMETER_VALUE;
316230557Sjimharris}
317230557Sjimharris
318230557Sjimharris/**
319230557Sjimharris * @brief This method releases the frame once this is done the frame is
320230557Sjimharris *        available for re-use by the hardware.  The data contained in the
321230557Sjimharris *        frame header and frame buffer is no longer valid.
322230557Sjimharris *
323230557Sjimharris * @param[in] uf_control This parameter specifies the UF control object
324230557Sjimharris * @param[in] frame_index This parameter specifies the frame index to
325230557Sjimharris *            attempt to release.
326230557Sjimharris *
327230557Sjimharris * @return This method returns an indication to the caller as to whether
328230557Sjimharris *         the unsolicited frame get pointer should be updated.
329230557Sjimharris * @retval TRUE This value indicates the unsolicited frame get pointer
330230557Sjimharris *         should be updated (i.e. write SCU_UFQGP_WRITE).
331230557Sjimharris * @retval FALSE This value indicates the get pointer should not be
332230557Sjimharris *         updated.
333230557Sjimharris */
334230557SjimharrisBOOL scic_sds_unsolicited_frame_control_release_frame(
335230557Sjimharris   SCIC_SDS_UNSOLICITED_FRAME_CONTROL_T *uf_control,
336230557Sjimharris   U32                                   frame_index
337230557Sjimharris)
338230557Sjimharris{
339230557Sjimharris   U32 frame_get;
340230557Sjimharris   U32 frame_cycle;
341230557Sjimharris
342230557Sjimharris   frame_get   = uf_control->get & (uf_control->address_table.count - 1);
343230557Sjimharris   frame_cycle = uf_control->get & uf_control->address_table.count;
344230557Sjimharris
345230557Sjimharris   // In the event there are NULL entries in the UF table, we need to
346230557Sjimharris   // advance the get pointer in order to find out if this frame should
347230557Sjimharris   // be released (i.e. update the get pointer).
348230557Sjimharris   while (
349230557Sjimharris            (
350230557Sjimharris               (sci_cb_physical_address_lower(
351230557Sjimharris                   uf_control->address_table.array[frame_get]) == 0)
352230557Sjimharris            && (sci_cb_physical_address_upper(
353230557Sjimharris                   uf_control->address_table.array[frame_get]) == 0)
354230557Sjimharris            )
355230557Sjimharris         && (frame_get < uf_control->address_table.count)
356230557Sjimharris         )
357230557Sjimharris   {
358230557Sjimharris      frame_get++;
359230557Sjimharris   }
360230557Sjimharris
361230557Sjimharris   // The table has a NULL entry as it's last element.  This is
362230557Sjimharris   // illegal.
363230557Sjimharris   ASSERT(frame_get < uf_control->address_table.count);
364230557Sjimharris
365230557Sjimharris   if (frame_index < uf_control->address_table.count)
366230557Sjimharris   {
367230557Sjimharris      uf_control->buffers.array[frame_index].state = UNSOLICITED_FRAME_RELEASED;
368230557Sjimharris
369230557Sjimharris      // The frame index is equal to the current get pointer so we
370230557Sjimharris      // can now free up all of the frame entries that
371230557Sjimharris      if (frame_get == frame_index)
372230557Sjimharris      {
373230557Sjimharris         while (
374230557Sjimharris                  uf_control->buffers.array[frame_get].state
375230557Sjimharris               == UNSOLICITED_FRAME_RELEASED
376230557Sjimharris               )
377230557Sjimharris         {
378230557Sjimharris            uf_control->buffers.array[frame_get].state = UNSOLICITED_FRAME_EMPTY;
379230557Sjimharris
380230557Sjimharris            INCREMENT_QUEUE_GET(
381230557Sjimharris               frame_get,
382230557Sjimharris               frame_cycle,
383230557Sjimharris               uf_control->address_table.count - 1,
384230557Sjimharris               uf_control->address_table.count
385230557Sjimharris            );
386230557Sjimharris         }
387230557Sjimharris
388230557Sjimharris         uf_control->get =
389230557Sjimharris                  (SCU_UFQGP_GEN_BIT(ENABLE_BIT) | frame_cycle | frame_get);
390230557Sjimharris
391230557Sjimharris         return TRUE;
392230557Sjimharris      }
393230557Sjimharris      else
394230557Sjimharris      {
395230557Sjimharris         // Frames remain in use until we advance the get pointer
396230557Sjimharris         // so there is nothing we can do here
397230557Sjimharris      }
398230557Sjimharris   }
399230557Sjimharris
400230557Sjimharris   return FALSE;
401230557Sjimharris}
402230557Sjimharris
403