]>
Commit | Line | Data |
---|---|---|
6f231dda DW |
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 | #include "isci.h" | |
57 | #include "timers.h" | |
ce2b3261 | 58 | #include "host.h" |
6f231dda | 59 | |
6f231dda DW |
60 | /** |
61 | * isci_timer_list_construct() - This method contrucst the SCI Timer List | |
62 | * object used by the SCI Module class. The construction process involves | |
63 | * creating isci_timer objects and adding them to the SCI Timer List | |
64 | * object's list member. The number of isci_timer objects is determined by | |
65 | * the timer_list_size parameter. | |
7c40a803 | 66 | * @ihost: container of the timer list |
6f231dda DW |
67 | * |
68 | * This method returns an error code indicating sucess or failure. The user | |
69 | * should check for possible memory allocation error return otherwise, a zero | |
70 | * indicates success. | |
71 | */ | |
7c40a803 | 72 | int isci_timer_list_construct(struct isci_host *ihost) |
6f231dda | 73 | { |
7c40a803 DW |
74 | struct isci_timer *itimer; |
75 | int i, err = 0; | |
6f231dda | 76 | |
7c40a803 DW |
77 | INIT_LIST_HEAD(&ihost->timers); |
78 | for (i = 0; i < SCI_MAX_TIMER_COUNT; i++) { | |
79 | itimer = devm_kzalloc(&ihost->pdev->dev, sizeof(*itimer), GFP_KERNEL); | |
6f231dda | 80 | |
7c40a803 | 81 | if (!itimer) { |
6f231dda DW |
82 | err = -ENOMEM; |
83 | break; | |
84 | } | |
7c40a803 DW |
85 | init_timer(&itimer->timer); |
86 | itimer->used = 0; | |
87 | itimer->stopped = 1; | |
88 | list_add(&itimer->node, &ihost->timers); | |
6f231dda DW |
89 | } |
90 | ||
7c40a803 | 91 | return err; |
6f231dda DW |
92 | } |
93 | ||
6f231dda DW |
94 | /** |
95 | * isci_timer_list_destroy() - This method destroys the SCI Timer List object | |
96 | * used by the SCI Module class. The destruction process involves freeing | |
97 | * memory allocated for isci_timer objects on the SCI Timer List object's | |
98 | * timers list_head member. If any isci_timer objects are mark as "in use", | |
99 | * they are not freed and the function returns an error code of -EBUSY. | |
7c40a803 | 100 | * @ihost: container of the list to be destroyed |
6f231dda | 101 | */ |
7c40a803 | 102 | void isci_timer_list_destroy(struct isci_host *ihost) |
6f231dda | 103 | { |
7c40a803 DW |
104 | struct isci_timer *timer; |
105 | LIST_HEAD(list); | |
6f231dda | 106 | |
7c40a803 DW |
107 | spin_lock_irq(&ihost->scic_lock); |
108 | list_splice_init(&ihost->timers, &list); | |
109 | spin_unlock_irq(&ihost->scic_lock); | |
6f231dda | 110 | |
7c40a803 DW |
111 | list_for_each_entry(timer, &list, node) |
112 | del_timer_sync(&timer->timer); | |
6f231dda DW |
113 | } |
114 | ||
115 | /** | |
116 | * This method pulls an isci_timer object off of the list for the SCI Timer | |
117 | * List object specified, marks the isci_timer as "in use" and initializes | |
118 | * it with user callback function and cookie data. The timer is not start at | |
119 | * this time, just reserved for the user. | |
120 | * @isci_timer_list: This parameter points to the SCI Timer List from which the | |
121 | * timer is reserved. | |
122 | * @cookie: This parameter specifies a piece of information that the user must | |
123 | * retain. This cookie is to be supplied by the user anytime a timeout | |
124 | * occurs for the created timer. | |
125 | * @timer_callback: This parameter specifies the callback method to be invoked | |
126 | * whenever the timer expires. | |
127 | * | |
128 | * This method returns a pointer to an isci_timer object reserved from the SCI | |
129 | * Timer List. The pointer will be utilized for all further interactions | |
130 | * relating to this timer. | |
131 | */ | |
132 | ||
133 | static void timer_function(unsigned long data) | |
134 | { | |
135 | ||
7c40a803 | 136 | struct isci_timer *timer = (struct isci_timer *)data; |
6f231dda DW |
137 | struct isci_host *isci_host = timer->isci_host; |
138 | unsigned long flags; | |
139 | ||
140 | dev_dbg(&isci_host->pdev->dev, | |
141 | "%s: isci_timer = %p\n", __func__, timer); | |
142 | ||
143 | if (isci_stopped == isci_host_get_state(isci_host)) { | |
144 | timer->stopped = 1; | |
145 | return; | |
146 | } | |
147 | ||
148 | spin_lock_irqsave(&isci_host->scic_lock, flags); | |
149 | ||
150 | if (!timer->stopped) { | |
151 | timer->stopped = 1; | |
7c40a803 | 152 | timer->timer_callback(timer->cb_param); |
6f231dda DW |
153 | } |
154 | ||
155 | spin_unlock_irqrestore(&isci_host->scic_lock, flags); | |
156 | } | |
157 | ||
158 | ||
7c40a803 DW |
159 | struct isci_timer *isci_timer_create(struct isci_host *ihost, void *cb_param, |
160 | void (*timer_callback)(void *)) | |
6f231dda | 161 | { |
6f231dda DW |
162 | struct timer_list *timer; |
163 | struct isci_timer *isci_timer; | |
7c40a803 | 164 | struct list_head *list = &ihost->timers; |
6f231dda | 165 | |
7c40a803 DW |
166 | WARN_ONCE(!spin_is_locked(&ihost->scic_lock), |
167 | "%s: unlocked!\n", __func__); | |
6f231dda | 168 | |
7c40a803 | 169 | if (WARN_ONCE(list_empty(list), "%s: timer pool empty\n", __func__)) |
6f231dda | 170 | return NULL; |
6f231dda | 171 | |
7c40a803 | 172 | isci_timer = list_entry(list->next, struct isci_timer, node); |
6f231dda | 173 | |
6f231dda DW |
174 | isci_timer->used = 1; |
175 | isci_timer->stopped = 1; | |
7c40a803 DW |
176 | /* FIXME: what!? we recycle the timer, rather than take it off |
177 | * the free list? | |
178 | */ | |
179 | list_move_tail(&isci_timer->node, list); | |
6f231dda DW |
180 | |
181 | timer = &isci_timer->timer; | |
182 | timer->data = (unsigned long)isci_timer; | |
183 | timer->function = timer_function; | |
7c40a803 | 184 | isci_timer->cb_param = cb_param; |
6f231dda | 185 | isci_timer->timer_callback = timer_callback; |
7c40a803 | 186 | isci_timer->isci_host = ihost; |
6f231dda | 187 | |
7c40a803 | 188 | dev_dbg(&ihost->pdev->dev, |
6f231dda DW |
189 | "%s: isci_timer = %p\n", __func__, isci_timer); |
190 | ||
191 | return isci_timer; | |
192 | } | |
193 | ||
7c40a803 | 194 | /* isci_del_timer() - This method frees the isci_timer, marking it "free to |
6f231dda DW |
195 | * use", then places its back at the head of the timers list for the SCI |
196 | * Timer List object specified. | |
6f231dda | 197 | */ |
7c40a803 | 198 | void isci_del_timer(struct isci_host *ihost, struct isci_timer *isci_timer) |
6f231dda | 199 | { |
7c40a803 DW |
200 | struct list_head *list = &ihost->timers; |
201 | ||
202 | WARN_ONCE(!spin_is_locked(&ihost->scic_lock), | |
203 | "%s unlocked!\n", __func__); | |
6f231dda DW |
204 | |
205 | dev_dbg(&isci_timer->isci_host->pdev->dev, | |
206 | "%s: isci_timer = %p\n", __func__, isci_timer); | |
207 | ||
6f231dda | 208 | isci_timer->used = 0; |
7c40a803 DW |
209 | list_move(&isci_timer->node, list); |
210 | del_timer(&isci_timer->timer); | |
211 | isci_timer->stopped = 1; | |
6f231dda DW |
212 | } |
213 | ||
214 | /** | |
215 | * isci_timer_start() - This method starts the specified isci_timer, with the | |
216 | * specified timeout value. | |
217 | * @isci_timer: This parameter specifies the timer to be started. | |
218 | * @timeout: This parameter specifies the timeout, in milliseconds, after which | |
219 | * the associated callback function will be called. | |
220 | * | |
221 | */ | |
7c40a803 | 222 | void isci_timer_start(struct isci_timer *isci_timer, unsigned long tmo) |
6f231dda DW |
223 | { |
224 | struct timer_list *timer = &isci_timer->timer; | |
225 | ||
226 | dev_dbg(&isci_timer->isci_host->pdev->dev, | |
227 | "%s: isci_timer = %p\n", __func__, isci_timer); | |
228 | ||
6f231dda | 229 | isci_timer->stopped = 0; |
7c40a803 | 230 | mod_timer(timer, jiffies + msecs_to_jiffies(tmo)); |
6f231dda DW |
231 | } |
232 | ||
233 | /** | |
234 | * isci_timer_stop() - This method stops the supplied isci_timer. | |
235 | * @isci_timer: This parameter specifies the isci_timer to be stopped. | |
236 | * | |
237 | */ | |
238 | void isci_timer_stop(struct isci_timer *isci_timer) | |
239 | { | |
240 | dev_dbg(&isci_timer->isci_host->pdev->dev, | |
241 | "%s: isci_timer = %p\n", __func__, isci_timer); | |
242 | ||
6f231dda | 243 | isci_timer->stopped = 1; |
6f231dda DW |
244 | del_timer(&isci_timer->timer); |
245 | } |