Dan Williams | 6f231dd | 2011-07-02 22:56:22 -0700 | [diff] [blame] | 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 | * * Neither the name of Intel Corporation nor the names of its |
| 40 | * contributors may be used to endorse or promote products derived |
| 41 | * from this software without specific prior written permission. |
| 42 | * |
| 43 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 44 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 45 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 46 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 47 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 48 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 49 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 50 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 51 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 52 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 53 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 54 | */ |
| 55 | |
Dan Williams | cc9203b | 2011-05-08 17:34:44 -0700 | [diff] [blame] | 56 | #include "host.h" |
Dan Williams | 63a3a15 | 2011-05-08 21:36:46 -0700 | [diff] [blame] | 57 | #include "unsolicited_frame_control.h" |
| 58 | #include "registers.h" |
Dan Williams | 6f231dd | 2011-07-02 22:56:22 -0700 | [diff] [blame] | 59 | |
Dan Williams | abec912 | 2012-02-15 13:58:42 -0800 | [diff] [blame] | 60 | void sci_unsolicited_frame_control_construct(struct isci_host *ihost) |
Dan Williams | 6f231dd | 2011-07-02 22:56:22 -0700 | [diff] [blame] | 61 | { |
Dan Williams | 89a7301 | 2011-06-30 19:14:33 -0700 | [diff] [blame] | 62 | struct sci_unsolicited_frame_control *uf_control = &ihost->uf_control; |
| 63 | struct sci_unsolicited_frame *uf; |
Dan Williams | abec912 | 2012-02-15 13:58:42 -0800 | [diff] [blame] | 64 | dma_addr_t dma = ihost->ufi_dma; |
| 65 | void *virt = ihost->ufi_buf; |
| 66 | int i; |
Christoph Hellwig | bc5c967 | 2011-04-02 08:15:04 -0400 | [diff] [blame] | 67 | |
Dan Williams | 6f231dd | 2011-07-02 22:56:22 -0700 | [diff] [blame] | 68 | /* |
| 69 | * The Unsolicited Frame buffers are set at the start of the UF |
Dave Jiang | f7885c8 | 2011-02-22 16:39:32 -0700 | [diff] [blame] | 70 | * memory descriptor entry. The headers and address table will be |
| 71 | * placed after the buffers. |
| 72 | */ |
Dan Williams | 6f231dd | 2011-07-02 22:56:22 -0700 | [diff] [blame] | 73 | |
| 74 | /* |
| 75 | * Program the location of the UF header table into the SCU. |
| 76 | * Notes: |
| 77 | * - The address must align on a 64-byte boundary. Guaranteed to be |
| 78 | * on 64-byte boundary already 1KB boundary for unsolicited frames. |
| 79 | * - Program unused header entries to overlap with the last |
| 80 | * unsolicited frame. The silicon will never DMA to these unused |
| 81 | * headers, since we program the UF address table pointers to |
Dave Jiang | f7885c8 | 2011-02-22 16:39:32 -0700 | [diff] [blame] | 82 | * NULL. |
| 83 | */ |
Dan Williams | abec912 | 2012-02-15 13:58:42 -0800 | [diff] [blame] | 84 | uf_control->headers.physical_address = dma + SCI_UFI_BUF_SIZE; |
| 85 | uf_control->headers.array = virt + SCI_UFI_BUF_SIZE; |
Dan Williams | 6f231dd | 2011-07-02 22:56:22 -0700 | [diff] [blame] | 86 | |
| 87 | /* |
| 88 | * Program the location of the UF address table into the SCU. |
| 89 | * Notes: |
| 90 | * - The address must align on a 64-bit boundary. Guaranteed to be on 64 |
| 91 | * byte boundary already due to above programming headers being on a |
Dave Jiang | f7885c8 | 2011-02-22 16:39:32 -0700 | [diff] [blame] | 92 | * 64-bit boundary and headers are on a 64-bytes in size. |
| 93 | */ |
Dan Williams | abec912 | 2012-02-15 13:58:42 -0800 | [diff] [blame] | 94 | uf_control->address_table.physical_address = dma + SCI_UFI_BUF_SIZE + SCI_UFI_HDR_SIZE; |
| 95 | uf_control->address_table.array = virt + SCI_UFI_BUF_SIZE + SCI_UFI_HDR_SIZE; |
Dan Williams | 6f231dd | 2011-07-02 22:56:22 -0700 | [diff] [blame] | 96 | uf_control->get = 0; |
| 97 | |
| 98 | /* |
| 99 | * UF buffer requirements are: |
| 100 | * - The last entry in the UF queue is not NULL. |
| 101 | * - There is a power of 2 number of entries (NULL or not-NULL) |
| 102 | * programmed into the queue. |
| 103 | * - Aligned on a 1KB boundary. */ |
| 104 | |
| 105 | /* |
Dan Williams | 7c78da3 | 2011-06-01 16:00:01 -0700 | [diff] [blame] | 106 | * Program the actual used UF buffers into the UF address table and |
| 107 | * the controller's array of UFs. |
| 108 | */ |
| 109 | for (i = 0; i < SCU_MAX_UNSOLICITED_FRAMES; i++) { |
| 110 | uf = &uf_control->buffers.array[i]; |
| 111 | |
| 112 | uf_control->address_table.array[i] = dma; |
| 113 | |
| 114 | uf->buffer = virt; |
| 115 | uf->header = &uf_control->headers.array[i]; |
| 116 | uf->state = UNSOLICITED_FRAME_EMPTY; |
| 117 | |
| 118 | /* |
| 119 | * Increment the address of the physical and virtual memory |
| 120 | * pointers. Everything is aligned on 1k boundary with an |
| 121 | * increment of 1k. |
| 122 | */ |
| 123 | virt += SCU_UNSOLICITED_FRAME_BUFFER_SIZE; |
| 124 | dma += SCU_UNSOLICITED_FRAME_BUFFER_SIZE; |
| 125 | } |
Dan Williams | 6f231dd | 2011-07-02 22:56:22 -0700 | [diff] [blame] | 126 | } |
| 127 | |
Dan Williams | 89a7301 | 2011-06-30 19:14:33 -0700 | [diff] [blame] | 128 | enum sci_status sci_unsolicited_frame_control_get_header(struct sci_unsolicited_frame_control *uf_control, |
| 129 | u32 frame_index, |
| 130 | void **frame_header) |
Dan Williams | 6f231dd | 2011-07-02 22:56:22 -0700 | [diff] [blame] | 131 | { |
Dan Williams | 7c78da3 | 2011-06-01 16:00:01 -0700 | [diff] [blame] | 132 | if (frame_index < SCU_MAX_UNSOLICITED_FRAMES) { |
Dan Williams | 89a7301 | 2011-06-30 19:14:33 -0700 | [diff] [blame] | 133 | /* Skip the first word in the frame since this is a controll word used |
| 134 | * by the hardware. |
| 135 | */ |
Dan Williams | 6f231dd | 2011-07-02 22:56:22 -0700 | [diff] [blame] | 136 | *frame_header = &uf_control->buffers.array[frame_index].header->data; |
| 137 | |
| 138 | return SCI_SUCCESS; |
| 139 | } |
| 140 | |
| 141 | return SCI_FAILURE_INVALID_PARAMETER_VALUE; |
| 142 | } |
| 143 | |
Dan Williams | 89a7301 | 2011-06-30 19:14:33 -0700 | [diff] [blame] | 144 | enum sci_status sci_unsolicited_frame_control_get_buffer(struct sci_unsolicited_frame_control *uf_control, |
| 145 | u32 frame_index, |
| 146 | void **frame_buffer) |
Dan Williams | 6f231dd | 2011-07-02 22:56:22 -0700 | [diff] [blame] | 147 | { |
Dan Williams | 7c78da3 | 2011-06-01 16:00:01 -0700 | [diff] [blame] | 148 | if (frame_index < SCU_MAX_UNSOLICITED_FRAMES) { |
Dan Williams | 6f231dd | 2011-07-02 22:56:22 -0700 | [diff] [blame] | 149 | *frame_buffer = uf_control->buffers.array[frame_index].buffer; |
| 150 | |
| 151 | return SCI_SUCCESS; |
| 152 | } |
| 153 | |
| 154 | return SCI_FAILURE_INVALID_PARAMETER_VALUE; |
| 155 | } |
| 156 | |
Dan Williams | 89a7301 | 2011-06-30 19:14:33 -0700 | [diff] [blame] | 157 | bool sci_unsolicited_frame_control_release_frame(struct sci_unsolicited_frame_control *uf_control, |
| 158 | u32 frame_index) |
Dan Williams | 6f231dd | 2011-07-02 22:56:22 -0700 | [diff] [blame] | 159 | { |
| 160 | u32 frame_get; |
| 161 | u32 frame_cycle; |
| 162 | |
Dan Williams | 7c78da3 | 2011-06-01 16:00:01 -0700 | [diff] [blame] | 163 | frame_get = uf_control->get & (SCU_MAX_UNSOLICITED_FRAMES - 1); |
| 164 | frame_cycle = uf_control->get & SCU_MAX_UNSOLICITED_FRAMES; |
Dan Williams | 6f231dd | 2011-07-02 22:56:22 -0700 | [diff] [blame] | 165 | |
| 166 | /* |
| 167 | * In the event there are NULL entries in the UF table, we need to |
| 168 | * advance the get pointer in order to find out if this frame should |
Dan Williams | 994a930 | 2011-06-09 16:04:28 -0700 | [diff] [blame] | 169 | * be released (i.e. update the get pointer) |
| 170 | */ |
Dan Williams | 7c78da3 | 2011-06-01 16:00:01 -0700 | [diff] [blame] | 171 | while (lower_32_bits(uf_control->address_table.array[frame_get]) == 0 && |
| 172 | upper_32_bits(uf_control->address_table.array[frame_get]) == 0 && |
| 173 | frame_get < SCU_MAX_UNSOLICITED_FRAMES) |
Dan Williams | 6f231dd | 2011-07-02 22:56:22 -0700 | [diff] [blame] | 174 | frame_get++; |
| 175 | |
| 176 | /* |
| 177 | * The table has a NULL entry as it's last element. This is |
Dan Williams | 994a930 | 2011-06-09 16:04:28 -0700 | [diff] [blame] | 178 | * illegal. |
| 179 | */ |
Dan Williams | 7c78da3 | 2011-06-01 16:00:01 -0700 | [diff] [blame] | 180 | BUG_ON(frame_get >= SCU_MAX_UNSOLICITED_FRAMES); |
Dan Williams | 994a930 | 2011-06-09 16:04:28 -0700 | [diff] [blame] | 181 | if (frame_index >= SCU_MAX_UNSOLICITED_FRAMES) |
| 182 | return false; |
Dan Williams | 6f231dd | 2011-07-02 22:56:22 -0700 | [diff] [blame] | 183 | |
Dan Williams | 994a930 | 2011-06-09 16:04:28 -0700 | [diff] [blame] | 184 | uf_control->buffers.array[frame_index].state = UNSOLICITED_FRAME_RELEASED; |
Dan Williams | 6f231dd | 2011-07-02 22:56:22 -0700 | [diff] [blame] | 185 | |
Dan Williams | 994a930 | 2011-06-09 16:04:28 -0700 | [diff] [blame] | 186 | if (frame_get != frame_index) { |
Dan Williams | 6f231dd | 2011-07-02 22:56:22 -0700 | [diff] [blame] | 187 | /* |
Dan Williams | 994a930 | 2011-06-09 16:04:28 -0700 | [diff] [blame] | 188 | * Frames remain in use until we advance the get pointer |
| 189 | * so there is nothing we can do here |
| 190 | */ |
| 191 | return false; |
Dan Williams | 6f231dd | 2011-07-02 22:56:22 -0700 | [diff] [blame] | 192 | } |
| 193 | |
Dan Williams | 994a930 | 2011-06-09 16:04:28 -0700 | [diff] [blame] | 194 | /* |
| 195 | * The frame index is equal to the current get pointer so we |
| 196 | * can now free up all of the frame entries that |
| 197 | */ |
| 198 | while (uf_control->buffers.array[frame_get].state == UNSOLICITED_FRAME_RELEASED) { |
| 199 | uf_control->buffers.array[frame_get].state = UNSOLICITED_FRAME_EMPTY; |
Dan Williams | 6f231dd | 2011-07-02 22:56:22 -0700 | [diff] [blame] | 200 | |
Dan Williams | 994a930 | 2011-06-09 16:04:28 -0700 | [diff] [blame] | 201 | if (frame_get+1 == SCU_MAX_UNSOLICITED_FRAMES-1) { |
| 202 | frame_cycle ^= SCU_MAX_UNSOLICITED_FRAMES; |
| 203 | frame_get = 0; |
| 204 | } else |
| 205 | frame_get++; |
| 206 | } |
| 207 | |
| 208 | uf_control->get = SCU_UFQGP_GEN_BIT(ENABLE_BIT) | frame_cycle | frame_get; |
| 209 | |
| 210 | return true; |
| 211 | } |