Blame view

drivers/scsi/isci/unsolicited_frame_control.c 7.73 KB
6f231dda6   Dan Williams   isci: Intel(R) C6...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
  /*
   * This file is provided under a dual BSD/GPLv2 license.  When using or
   * redistributing this file, you may do so under either license.
   *
   * GPL LICENSE SUMMARY
   *
   * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of version 2 of the GNU General Public License as
   * published by the Free Software Foundation.
   *
   * This program is distributed in the hope that it will be useful, but
   * WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   * General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write to the Free Software
   * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
   * The full GNU General Public License is included in this distribution
   * in the file called LICENSE.GPL.
   *
   * BSD LICENSE
   *
   * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
   * All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   *   * Redistributions of source code must retain the above copyright
   *     notice, this list of conditions and the following disclaimer.
   *   * Redistributions in binary form must reproduce the above copyright
   *     notice, this list of conditions and the following disclaimer in
   *     the documentation and/or other materials provided with the
   *     distribution.
   *   * Neither the name of Intel Corporation nor the names of its
   *     contributors may be used to endorse or promote products derived
   *     from this software without specific prior written permission.
   *
   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
   * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
   * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
   * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   */
cc9203bf3   Dan Williams   isci: move core/c...
55
  #include "host.h"
63a3a15fb   Dan Williams   isci: uplevel reg...
56
57
  #include "unsolicited_frame_control.h"
  #include "registers.h"
6f231dda6   Dan Williams   isci: Intel(R) C6...
58

89a7301f2   Dan Williams   isci: retire scic...
59
  int sci_unsolicited_frame_control_construct(struct isci_host *ihost)
6f231dda6   Dan Williams   isci: Intel(R) C6...
60
  {
89a7301f2   Dan Williams   isci: retire scic...
61
62
  	struct sci_unsolicited_frame_control *uf_control = &ihost->uf_control;
  	struct sci_unsolicited_frame *uf;
7c78da317   Dan Williams   isci: remove 'min...
63
64
  	u32 buf_len, header_len, i;
  	dma_addr_t dma;
bc5c96748   Christoph Hellwig   isci: simplify dm...
65
  	size_t size;
7c78da317   Dan Williams   isci: remove 'min...
66
  	void *virt;
6f231dda6   Dan Williams   isci: Intel(R) C6...
67
68
69
  
  	/*
  	 * Prepare all of the memory sizes for the UF headers, UF address
bc5c96748   Christoph Hellwig   isci: simplify dm...
70
71
  	 * table, and UF buffers themselves.
  	 */
7c78da317   Dan Williams   isci: remove 'min...
72
73
  	buf_len = SCU_MAX_UNSOLICITED_FRAMES * SCU_UNSOLICITED_FRAME_BUFFER_SIZE;
  	header_len = SCU_MAX_UNSOLICITED_FRAMES * sizeof(struct scu_unsolicited_frame_header);
ee33e2b77   Dan Williams   [SCSI] isci: fix ...
74
  	size = buf_len + header_len + SCU_MAX_UNSOLICITED_FRAMES * sizeof(uf_control->address_table.array[0]);
bc5c96748   Christoph Hellwig   isci: simplify dm...
75

6f231dda6   Dan Williams   isci: Intel(R) C6...
76
77
  	/*
  	 * The Unsolicited Frame buffers are set at the start of the UF
f7885c849   Dave Jiang   isci: Removed spe...
78
79
80
  	 * memory descriptor entry. The headers and address table will be
  	 * placed after the buffers.
  	 */
d9dcb4ba7   Dan Williams   isci: unify isci_...
81
  	virt = dmam_alloc_coherent(&ihost->pdev->dev, size, &dma, GFP_KERNEL);
7c78da317   Dan Williams   isci: remove 'min...
82
  	if (!virt)
bc5c96748   Christoph Hellwig   isci: simplify dm...
83
  		return -ENOMEM;
6f231dda6   Dan Williams   isci: Intel(R) C6...
84
85
86
87
88
89
90
91
92
  
  	/*
  	 * Program the location of the UF header table into the SCU.
  	 * Notes:
  	 * - The address must align on a 64-byte boundary. Guaranteed to be
  	 *   on 64-byte boundary already 1KB boundary for unsolicited frames.
  	 * - Program unused header entries to overlap with the last
  	 *   unsolicited frame.  The silicon will never DMA to these unused
  	 *   headers, since we program the UF address table pointers to
f7885c849   Dave Jiang   isci: Removed spe...
93
94
  	 *   NULL.
  	 */
7c78da317   Dan Williams   isci: remove 'min...
95
96
  	uf_control->headers.physical_address = dma + buf_len;
  	uf_control->headers.array = virt + buf_len;
6f231dda6   Dan Williams   isci: Intel(R) C6...
97
98
99
100
101
102
  
  	/*
  	 * Program the location of the UF address table into the SCU.
  	 * Notes:
  	 * - The address must align on a 64-bit boundary. Guaranteed to be on 64
  	 *   byte boundary already due to above programming headers being on a
f7885c849   Dave Jiang   isci: Removed spe...
103
104
  	 *   64-bit boundary and headers are on a 64-bytes in size.
  	 */
7c78da317   Dan Williams   isci: remove 'min...
105
106
  	uf_control->address_table.physical_address = dma + buf_len + header_len;
  	uf_control->address_table.array = virt + buf_len + header_len;
6f231dda6   Dan Williams   isci: Intel(R) C6...
107
108
109
110
111
112
113
114
115
116
  	uf_control->get = 0;
  
  	/*
  	 * UF buffer requirements are:
  	 * - The last entry in the UF queue is not NULL.
  	 * - There is a power of 2 number of entries (NULL or not-NULL)
  	 *   programmed into the queue.
  	 * - Aligned on a 1KB boundary. */
  
  	/*
7c78da317   Dan Williams   isci: remove 'min...
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
  	 * Program the actual used UF buffers into the UF address table and
  	 * the controller's array of UFs.
  	 */
  	for (i = 0; i < SCU_MAX_UNSOLICITED_FRAMES; i++) {
  		uf = &uf_control->buffers.array[i];
  
  		uf_control->address_table.array[i] = dma;
  
  		uf->buffer = virt;
  		uf->header = &uf_control->headers.array[i];
  		uf->state  = UNSOLICITED_FRAME_EMPTY;
  
  		/*
  		 * Increment the address of the physical and virtual memory
  		 * pointers. Everything is aligned on 1k boundary with an
  		 * increment of 1k.
  		 */
  		virt += SCU_UNSOLICITED_FRAME_BUFFER_SIZE;
  		dma += SCU_UNSOLICITED_FRAME_BUFFER_SIZE;
  	}
bc5c96748   Christoph Hellwig   isci: simplify dm...
137
138
  
  	return 0;
6f231dda6   Dan Williams   isci: Intel(R) C6...
139
  }
89a7301f2   Dan Williams   isci: retire scic...
140
141
142
  enum sci_status sci_unsolicited_frame_control_get_header(struct sci_unsolicited_frame_control *uf_control,
  							 u32 frame_index,
  							 void **frame_header)
6f231dda6   Dan Williams   isci: Intel(R) C6...
143
  {
7c78da317   Dan Williams   isci: remove 'min...
144
  	if (frame_index < SCU_MAX_UNSOLICITED_FRAMES) {
89a7301f2   Dan Williams   isci: retire scic...
145
146
147
  		/* Skip the first word in the frame since this is a controll word used
  		 * by the hardware.
  		 */
6f231dda6   Dan Williams   isci: Intel(R) C6...
148
149
150
151
152
153
154
  		*frame_header = &uf_control->buffers.array[frame_index].header->data;
  
  		return SCI_SUCCESS;
  	}
  
  	return SCI_FAILURE_INVALID_PARAMETER_VALUE;
  }
89a7301f2   Dan Williams   isci: retire scic...
155
156
157
  enum sci_status sci_unsolicited_frame_control_get_buffer(struct sci_unsolicited_frame_control *uf_control,
  							 u32 frame_index,
  							 void **frame_buffer)
6f231dda6   Dan Williams   isci: Intel(R) C6...
158
  {
7c78da317   Dan Williams   isci: remove 'min...
159
  	if (frame_index < SCU_MAX_UNSOLICITED_FRAMES) {
6f231dda6   Dan Williams   isci: Intel(R) C6...
160
161
162
163
164
165
166
  		*frame_buffer = uf_control->buffers.array[frame_index].buffer;
  
  		return SCI_SUCCESS;
  	}
  
  	return SCI_FAILURE_INVALID_PARAMETER_VALUE;
  }
89a7301f2   Dan Williams   isci: retire scic...
167
168
  bool sci_unsolicited_frame_control_release_frame(struct sci_unsolicited_frame_control *uf_control,
  						 u32 frame_index)
6f231dda6   Dan Williams   isci: Intel(R) C6...
169
170
171
  {
  	u32 frame_get;
  	u32 frame_cycle;
7c78da317   Dan Williams   isci: remove 'min...
172
173
  	frame_get   = uf_control->get & (SCU_MAX_UNSOLICITED_FRAMES - 1);
  	frame_cycle = uf_control->get & SCU_MAX_UNSOLICITED_FRAMES;
6f231dda6   Dan Williams   isci: Intel(R) C6...
174
175
176
177
  
  	/*
  	 * In the event there are NULL entries in the UF table, we need to
  	 * advance the get pointer in order to find out if this frame should
994a9303d   Dan Williams   isci: cleanup/opt...
178
179
  	 * be released (i.e. update the get pointer)
  	 */
7c78da317   Dan Williams   isci: remove 'min...
180
181
182
  	while (lower_32_bits(uf_control->address_table.array[frame_get]) == 0 &&
  	       upper_32_bits(uf_control->address_table.array[frame_get]) == 0 &&
  	       frame_get < SCU_MAX_UNSOLICITED_FRAMES)
6f231dda6   Dan Williams   isci: Intel(R) C6...
183
184
185
186
  		frame_get++;
  
  	/*
  	 * The table has a NULL entry as it's last element.  This is
994a9303d   Dan Williams   isci: cleanup/opt...
187
188
  	 * illegal.
  	 */
7c78da317   Dan Williams   isci: remove 'min...
189
  	BUG_ON(frame_get >= SCU_MAX_UNSOLICITED_FRAMES);
994a9303d   Dan Williams   isci: cleanup/opt...
190
191
  	if (frame_index >= SCU_MAX_UNSOLICITED_FRAMES)
  		return false;
6f231dda6   Dan Williams   isci: Intel(R) C6...
192

994a9303d   Dan Williams   isci: cleanup/opt...
193
  	uf_control->buffers.array[frame_index].state = UNSOLICITED_FRAME_RELEASED;
6f231dda6   Dan Williams   isci: Intel(R) C6...
194

994a9303d   Dan Williams   isci: cleanup/opt...
195
  	if (frame_get != frame_index) {
6f231dda6   Dan Williams   isci: Intel(R) C6...
196
  		/*
994a9303d   Dan Williams   isci: cleanup/opt...
197
198
199
200
201
  		 * Frames remain in use until we advance the get pointer
  		 * so there is nothing we can do here
  		 */
  		return false;
  	}
6f231dda6   Dan Williams   isci: Intel(R) C6...
202

994a9303d   Dan Williams   isci: cleanup/opt...
203
204
205
206
207
208
209
210
211
212
213
214
  	/*
  	 * The frame index is equal to the current get pointer so we
  	 * can now free up all of the frame entries that
  	 */
  	while (uf_control->buffers.array[frame_get].state == UNSOLICITED_FRAME_RELEASED) {
  		uf_control->buffers.array[frame_get].state = UNSOLICITED_FRAME_EMPTY;
  
  		if (frame_get+1 == SCU_MAX_UNSOLICITED_FRAMES-1) {
  			frame_cycle ^= SCU_MAX_UNSOLICITED_FRAMES;
  			frame_get = 0;
  		} else
  			frame_get++;
6f231dda6   Dan Williams   isci: Intel(R) C6...
215
  	}
994a9303d   Dan Williams   isci: cleanup/opt...
216
  	uf_control->get = SCU_UFQGP_GEN_BIT(ENABLE_BIT) | frame_cycle | frame_get;
6f231dda6   Dan Williams   isci: Intel(R) C6...
217

994a9303d   Dan Williams   isci: cleanup/opt...
218
219
  	return true;
  }