diff options
author | Dan Williams <dan.j.williams@intel.com> | 2011-06-07 21:50:55 -0400 |
---|---|---|
committer | Dan Williams <dan.j.williams@intel.com> | 2011-07-03 07:04:51 -0400 |
commit | ac668c69709c7d927015c5cf3d9e87bf4eaaf57d (patch) | |
tree | 16a42117d260a86b8217d266ab65b25438c48e06 | |
parent | 9b917987fd16d0687afe550a02f68099419f5d43 (diff) |
isci: cleanup/optimize pool implementation
The circ_buf macros are ~6% faster, as measured by perf, because they take
advantage of power-of-two math assumptions i.e. no test and branch for
rollover. Their semantics are clearer than the hidden side effects in pool.h
(like sci_pool_get() which hides an assignment).
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
-rw-r--r-- | drivers/scsi/isci/host.c | 75 | ||||
-rw-r--r-- | drivers/scsi/isci/host.h | 12 | ||||
-rw-r--r-- | drivers/scsi/isci/isci.h | 1 | ||||
-rw-r--r-- | drivers/scsi/isci/pool.h | 199 |
4 files changed, 56 insertions, 231 deletions
diff --git a/drivers/scsi/isci/host.c b/drivers/scsi/isci/host.c index 41a7c5099dea..343655bd1a6a 100644 --- a/drivers/scsi/isci/host.c +++ b/drivers/scsi/isci/host.c | |||
@@ -52,6 +52,7 @@ | |||
52 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 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. | 53 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
54 | */ | 54 | */ |
55 | #include <linux/circ_buf.h> | ||
55 | #include <linux/device.h> | 56 | #include <linux/device.h> |
56 | #include <scsi/sas.h> | 57 | #include <scsi/sas.h> |
57 | #include "host.h" | 58 | #include "host.h" |
@@ -1054,6 +1055,33 @@ done: | |||
1054 | spin_unlock_irqrestore(&ihost->scic_lock, flags); | 1055 | spin_unlock_irqrestore(&ihost->scic_lock, flags); |
1055 | } | 1056 | } |
1056 | 1057 | ||
1058 | static void isci_tci_free(struct isci_host *ihost, u16 tci) | ||
1059 | { | ||
1060 | u16 tail = ihost->tci_tail & (SCI_MAX_IO_REQUESTS-1); | ||
1061 | |||
1062 | ihost->tci_pool[tail] = tci; | ||
1063 | ihost->tci_tail = tail + 1; | ||
1064 | } | ||
1065 | |||
1066 | static u16 isci_tci_alloc(struct isci_host *ihost) | ||
1067 | { | ||
1068 | u16 head = ihost->tci_head & (SCI_MAX_IO_REQUESTS-1); | ||
1069 | u16 tci = ihost->tci_pool[head]; | ||
1070 | |||
1071 | ihost->tci_head = head + 1; | ||
1072 | return tci; | ||
1073 | } | ||
1074 | |||
1075 | static u16 isci_tci_active(struct isci_host *ihost) | ||
1076 | { | ||
1077 | return CIRC_CNT(ihost->tci_head, ihost->tci_tail, SCI_MAX_IO_REQUESTS); | ||
1078 | } | ||
1079 | |||
1080 | static u16 isci_tci_space(struct isci_host *ihost) | ||
1081 | { | ||
1082 | return CIRC_SPACE(ihost->tci_head, ihost->tci_tail, SCI_MAX_IO_REQUESTS); | ||
1083 | } | ||
1084 | |||
1057 | static enum sci_status scic_controller_start(struct scic_sds_controller *scic, | 1085 | static enum sci_status scic_controller_start(struct scic_sds_controller *scic, |
1058 | u32 timeout) | 1086 | u32 timeout) |
1059 | { | 1087 | { |
@@ -1069,9 +1097,11 @@ static enum sci_status scic_controller_start(struct scic_sds_controller *scic, | |||
1069 | } | 1097 | } |
1070 | 1098 | ||
1071 | /* Build the TCi free pool */ | 1099 | /* Build the TCi free pool */ |
1072 | sci_pool_initialize(scic->tci_pool); | 1100 | BUILD_BUG_ON(SCI_MAX_IO_REQUESTS > 1 << sizeof(ihost->tci_pool[0]) * 8); |
1101 | ihost->tci_head = 0; | ||
1102 | ihost->tci_tail = 0; | ||
1073 | for (index = 0; index < scic->task_context_entries; index++) | 1103 | for (index = 0; index < scic->task_context_entries; index++) |
1074 | sci_pool_put(scic->tci_pool, index); | 1104 | isci_tci_free(ihost, index); |
1075 | 1105 | ||
1076 | /* Build the RNi free pool */ | 1106 | /* Build the RNi free pool */ |
1077 | scic_sds_remote_node_table_initialize( | 1107 | scic_sds_remote_node_table_initialize( |
@@ -3063,18 +3093,17 @@ enum sci_task_status scic_controller_start_task( | |||
3063 | * currently available tags to be allocated. All return other values indicate a | 3093 | * currently available tags to be allocated. All return other values indicate a |
3064 | * legitimate tag. | 3094 | * legitimate tag. |
3065 | */ | 3095 | */ |
3066 | u16 scic_controller_allocate_io_tag( | 3096 | u16 scic_controller_allocate_io_tag(struct scic_sds_controller *scic) |
3067 | struct scic_sds_controller *scic) | ||
3068 | { | 3097 | { |
3069 | u16 task_context; | 3098 | struct isci_host *ihost = scic_to_ihost(scic); |
3070 | u16 sequence_count; | 3099 | u16 tci; |
3071 | 3100 | u16 seq; | |
3072 | if (!sci_pool_empty(scic->tci_pool)) { | ||
3073 | sci_pool_get(scic->tci_pool, task_context); | ||
3074 | 3101 | ||
3075 | sequence_count = scic->io_request_sequence[task_context]; | 3102 | if (isci_tci_space(ihost)) { |
3103 | tci = isci_tci_alloc(ihost); | ||
3104 | seq = scic->io_request_sequence[tci]; | ||
3076 | 3105 | ||
3077 | return scic_sds_io_tag_construct(sequence_count, task_context); | 3106 | return scic_sds_io_tag_construct(seq, tci); |
3078 | } | 3107 | } |
3079 | 3108 | ||
3080 | return SCI_CONTROLLER_INVALID_IO_TAG; | 3109 | return SCI_CONTROLLER_INVALID_IO_TAG; |
@@ -3105,10 +3134,10 @@ u16 scic_controller_allocate_io_tag( | |||
3105 | * tags. SCI_FAILURE_INVALID_IO_TAG This value is returned if the supplied tag | 3134 | * tags. SCI_FAILURE_INVALID_IO_TAG This value is returned if the supplied tag |
3106 | * is not a valid IO tag value. | 3135 | * is not a valid IO tag value. |
3107 | */ | 3136 | */ |
3108 | enum sci_status scic_controller_free_io_tag( | 3137 | enum sci_status scic_controller_free_io_tag(struct scic_sds_controller *scic, |
3109 | struct scic_sds_controller *scic, | 3138 | u16 io_tag) |
3110 | u16 io_tag) | ||
3111 | { | 3139 | { |
3140 | struct isci_host *ihost = scic_to_ihost(scic); | ||
3112 | u16 sequence; | 3141 | u16 sequence; |
3113 | u16 index; | 3142 | u16 index; |
3114 | 3143 | ||
@@ -3117,18 +3146,16 @@ enum sci_status scic_controller_free_io_tag( | |||
3117 | sequence = scic_sds_io_tag_get_sequence(io_tag); | 3146 | sequence = scic_sds_io_tag_get_sequence(io_tag); |
3118 | index = scic_sds_io_tag_get_index(io_tag); | 3147 | index = scic_sds_io_tag_get_index(io_tag); |
3119 | 3148 | ||
3120 | if (!sci_pool_full(scic->tci_pool)) { | 3149 | /* prevent tail from passing head */ |
3121 | if (sequence == scic->io_request_sequence[index]) { | 3150 | if (isci_tci_active(ihost) == 0) |
3122 | scic_sds_io_sequence_increment( | 3151 | return SCI_FAILURE_INVALID_IO_TAG; |
3123 | scic->io_request_sequence[index]); | ||
3124 | 3152 | ||
3125 | sci_pool_put(scic->tci_pool, index); | 3153 | if (sequence == scic->io_request_sequence[index]) { |
3154 | scic_sds_io_sequence_increment(scic->io_request_sequence[index]); | ||
3126 | 3155 | ||
3127 | return SCI_SUCCESS; | 3156 | isci_tci_free(ihost, index); |
3128 | } | ||
3129 | } | ||
3130 | 3157 | ||
3158 | return SCI_SUCCESS; | ||
3159 | } | ||
3131 | return SCI_FAILURE_INVALID_IO_TAG; | 3160 | return SCI_FAILURE_INVALID_IO_TAG; |
3132 | } | 3161 | } |
3133 | |||
3134 | |||
diff --git a/drivers/scsi/isci/host.h b/drivers/scsi/isci/host.h index 740350043d89..c61a9fa130b7 100644 --- a/drivers/scsi/isci/host.h +++ b/drivers/scsi/isci/host.h | |||
@@ -57,7 +57,6 @@ | |||
57 | 57 | ||
58 | #include "remote_device.h" | 58 | #include "remote_device.h" |
59 | #include "phy.h" | 59 | #include "phy.h" |
60 | #include "pool.h" | ||
61 | #include "isci.h" | 60 | #include "isci.h" |
62 | #include "remote_node_table.h" | 61 | #include "remote_node_table.h" |
63 | #include "registers.h" | 62 | #include "registers.h" |
@@ -180,11 +179,6 @@ struct scic_sds_controller { | |||
180 | struct scic_remote_node_table available_remote_nodes; | 179 | struct scic_remote_node_table available_remote_nodes; |
181 | 180 | ||
182 | /** | 181 | /** |
183 | * This field is the TCi pool used to manage the task context index. | ||
184 | */ | ||
185 | SCI_POOL_CREATE(tci_pool, u16, SCI_MAX_IO_REQUESTS); | ||
186 | |||
187 | /** | ||
188 | * This filed is the struct scic_power_control data used to controll when direct | 182 | * This filed is the struct scic_power_control data used to controll when direct |
189 | * attached devices can consume power. | 183 | * attached devices can consume power. |
190 | */ | 184 | */ |
@@ -310,6 +304,10 @@ struct scic_sds_controller { | |||
310 | 304 | ||
311 | struct isci_host { | 305 | struct isci_host { |
312 | struct scic_sds_controller sci; | 306 | struct scic_sds_controller sci; |
307 | u16 tci_head; | ||
308 | u16 tci_tail; | ||
309 | u16 tci_pool[SCI_MAX_IO_REQUESTS]; | ||
310 | |||
313 | union scic_oem_parameters oem_parameters; | 311 | union scic_oem_parameters oem_parameters; |
314 | 312 | ||
315 | int id; /* unique within a given pci device */ | 313 | int id; /* unique within a given pci device */ |
@@ -423,8 +421,6 @@ enum scic_sds_controller_states { | |||
423 | SCIC_FAILED, | 421 | SCIC_FAILED, |
424 | }; | 422 | }; |
425 | 423 | ||
426 | |||
427 | |||
428 | /** | 424 | /** |
429 | * struct isci_pci_info - This class represents the pci function containing the | 425 | * struct isci_pci_info - This class represents the pci function containing the |
430 | * controllers. Depending on PCI SKU, there could be up to 2 controllers in | 426 | * controllers. Depending on PCI SKU, there could be up to 2 controllers in |
diff --git a/drivers/scsi/isci/isci.h b/drivers/scsi/isci/isci.h index 714ed926171b..84ba533ca51e 100644 --- a/drivers/scsi/isci/isci.h +++ b/drivers/scsi/isci/isci.h | |||
@@ -112,6 +112,7 @@ static inline void check_sizes(void) | |||
112 | BUILD_BUG_ON_NOT_POWER_OF_2(SCU_MAX_UNSOLICITED_FRAMES); | 112 | BUILD_BUG_ON_NOT_POWER_OF_2(SCU_MAX_UNSOLICITED_FRAMES); |
113 | BUILD_BUG_ON_NOT_POWER_OF_2(SCU_MAX_COMPLETION_QUEUE_ENTRIES); | 113 | BUILD_BUG_ON_NOT_POWER_OF_2(SCU_MAX_COMPLETION_QUEUE_ENTRIES); |
114 | BUILD_BUG_ON(SCU_MAX_UNSOLICITED_FRAMES > SCU_ABSOLUTE_MAX_UNSOLICITED_FRAMES); | 114 | BUILD_BUG_ON(SCU_MAX_UNSOLICITED_FRAMES > SCU_ABSOLUTE_MAX_UNSOLICITED_FRAMES); |
115 | BUILD_BUG_ON_NOT_POWER_OF_2(SCI_MAX_IO_REQUESTS); | ||
115 | } | 116 | } |
116 | 117 | ||
117 | /** | 118 | /** |
diff --git a/drivers/scsi/isci/pool.h b/drivers/scsi/isci/pool.h deleted file mode 100644 index 016ec832f74f..000000000000 --- a/drivers/scsi/isci/pool.h +++ /dev/null | |||
@@ -1,199 +0,0 @@ | |||
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 | |||
56 | /** | ||
57 | * This file contains the interface to the pool class. This class allows two | ||
58 | * different two different priority tasks to insert and remove items from | ||
59 | * the free pool. The user of the pool is expected to evaluate the pool | ||
60 | * condition empty before a get operation and pool condition full before a | ||
61 | * put operation. Methods Provided: - sci_pool_create() - | ||
62 | * sci_pool_initialize() - sci_pool_empty() - sci_pool_full() - | ||
63 | * sci_pool_get() - sci_pool_put() | ||
64 | * | ||
65 | * | ||
66 | */ | ||
67 | |||
68 | #ifndef _SCI_POOL_H_ | ||
69 | #define _SCI_POOL_H_ | ||
70 | |||
71 | /** | ||
72 | * SCI_POOL_INCREMENT() - | ||
73 | * | ||
74 | * Private operation for the pool | ||
75 | */ | ||
76 | #define SCI_POOL_INCREMENT(pool, index) \ | ||
77 | (((index) + 1) == (pool).size ? 0 : (index) + 1) | ||
78 | |||
79 | /** | ||
80 | * SCI_POOL_CREATE() - | ||
81 | * | ||
82 | * This creates a pool structure of pool_name. The members in the pool are of | ||
83 | * type with number of elements equal to size. | ||
84 | */ | ||
85 | #define SCI_POOL_CREATE(pool_name, type, pool_size) \ | ||
86 | struct \ | ||
87 | { \ | ||
88 | u32 size; \ | ||
89 | u32 get; \ | ||
90 | u32 put; \ | ||
91 | type array[(pool_size) + 1]; \ | ||
92 | } pool_name | ||
93 | |||
94 | |||
95 | /** | ||
96 | * sci_pool_empty() - | ||
97 | * | ||
98 | * This macro evaluates the pool and returns true if the pool is empty. If the | ||
99 | * pool is empty the user should not perform any get operation on the pool. | ||
100 | */ | ||
101 | #define sci_pool_empty(pool) \ | ||
102 | ((pool).get == (pool).put) | ||
103 | |||
104 | /** | ||
105 | * sci_pool_full() - | ||
106 | * | ||
107 | * This macro evaluates the pool and returns true if the pool is full. If the | ||
108 | * pool is full the user should not perform any put operation. | ||
109 | */ | ||
110 | #define sci_pool_full(pool) \ | ||
111 | (SCI_POOL_INCREMENT(pool, (pool).put) == (pool).get) | ||
112 | |||
113 | /** | ||
114 | * sci_pool_size() - | ||
115 | * | ||
116 | * This macro returns the size of the pool created. The internal size of the | ||
117 | * pool is actually 1 larger then necessary in order to ensure get and put | ||
118 | * pointers can be written simultaneously by different users. As a result, | ||
119 | * this macro subtracts 1 from the internal size | ||
120 | */ | ||
121 | #define sci_pool_size(pool) \ | ||
122 | ((pool).size - 1) | ||
123 | |||
124 | /** | ||
125 | * sci_pool_count() - | ||
126 | * | ||
127 | * This macro indicates the number of elements currently contained in the pool. | ||
128 | */ | ||
129 | #define sci_pool_count(pool) \ | ||
130 | (\ | ||
131 | sci_pool_empty((pool)) \ | ||
132 | ? 0 \ | ||
133 | : (\ | ||
134 | sci_pool_full((pool)) \ | ||
135 | ? sci_pool_size((pool)) \ | ||
136 | : (\ | ||
137 | (pool).get > (pool).put \ | ||
138 | ? ((pool).size - (pool).get + (pool).put) \ | ||
139 | : ((pool).put - (pool).get) \ | ||
140 | ) \ | ||
141 | ) \ | ||
142 | ) | ||
143 | |||
144 | /** | ||
145 | * sci_pool_initialize() - | ||
146 | * | ||
147 | * This macro initializes the pool to an empty condition. | ||
148 | */ | ||
149 | #define sci_pool_initialize(pool) \ | ||
150 | { \ | ||
151 | (pool).size = (sizeof((pool).array) / sizeof((pool).array[0])); \ | ||
152 | (pool).get = 0; \ | ||
153 | (pool).put = 0; \ | ||
154 | } | ||
155 | |||
156 | /** | ||
157 | * sci_pool_get() - | ||
158 | * | ||
159 | * This macro will get the next free element from the pool. This should only be | ||
160 | * called if the pool is not empty. | ||
161 | */ | ||
162 | #define sci_pool_get(pool, my_value) \ | ||
163 | { \ | ||
164 | (my_value) = (pool).array[(pool).get]; \ | ||
165 | (pool).get = SCI_POOL_INCREMENT((pool), (pool).get); \ | ||
166 | } | ||
167 | |||
168 | /** | ||
169 | * sci_pool_put() - | ||
170 | * | ||
171 | * This macro will put the value into the pool. This should only be called if | ||
172 | * the pool is not full. | ||
173 | */ | ||
174 | #define sci_pool_put(pool, value) \ | ||
175 | { \ | ||
176 | (pool).array[(pool).put] = (value); \ | ||
177 | (pool).put = SCI_POOL_INCREMENT((pool), (pool).put); \ | ||
178 | } | ||
179 | |||
180 | /** | ||
181 | * sci_pool_erase() - | ||
182 | * | ||
183 | * This macro will search the pool and remove any elements in the pool matching | ||
184 | * the supplied value. This method can only be utilized on pools | ||
185 | */ | ||
186 | #define sci_pool_erase(pool, type, value) \ | ||
187 | { \ | ||
188 | type tmp_value; \ | ||
189 | u32 index; \ | ||
190 | u32 element_count = sci_pool_count((pool)); \ | ||
191 | \ | ||
192 | for (index = 0; index < element_count; index++) { \ | ||
193 | sci_pool_get((pool), tmp_value); \ | ||
194 | if (tmp_value != (value)) \ | ||
195 | sci_pool_put((pool), tmp_value); \ | ||
196 | } \ | ||
197 | } | ||
198 | |||
199 | #endif /* _SCI_POOL_H_ */ | ||