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