Commit | Line | Data |
---|---|---|
920dae64 AT |
1 | /* |
2 | * ========== Copyright Header Begin ========================================== | |
3 | * | |
4 | * Hypervisor Software File: cyclic.s | |
5 | * | |
6 | * Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved. | |
7 | * | |
8 | * - Do no alter or remove copyright notices | |
9 | * | |
10 | * - Redistribution and use of this software in source and binary forms, with | |
11 | * or without modification, are permitted provided that the following | |
12 | * conditions are met: | |
13 | * | |
14 | * - Redistribution of source code must retain the above copyright notice, | |
15 | * this list of conditions and the following disclaimer. | |
16 | * | |
17 | * - Redistribution in binary form must reproduce the above copyright notice, | |
18 | * this list of conditions and the following disclaimer in the | |
19 | * documentation and/or other materials provided with the distribution. | |
20 | * | |
21 | * Neither the name of Sun Microsystems, Inc. or the names of contributors | |
22 | * may be used to endorse or promote products derived from this software | |
23 | * without specific prior written permission. | |
24 | * | |
25 | * This software is provided "AS IS," without a warranty of any kind. | |
26 | * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, | |
27 | * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A | |
28 | * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN | |
29 | * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR | |
30 | * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR | |
31 | * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN | |
32 | * OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR | |
33 | * FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE | |
34 | * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, | |
35 | * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF | |
36 | * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. | |
37 | * | |
38 | * You acknowledge that this software is not designed, licensed or | |
39 | * intended for use in the design, construction, operation or maintenance of | |
40 | * any nuclear facility. | |
41 | * | |
42 | * ========== Copyright Header End ============================================ | |
43 | */ | |
44 | /* | |
45 | * Copyright 2006 Sun Microsystems, Inc. All rights reserved. | |
46 | * Use is subject to license terms. | |
47 | */ | |
48 | ||
49 | .ident "@(#)cyclic.s 1.9 07/03/23 SMI" | |
50 | ||
51 | .file "cyclic.s" | |
52 | ||
53 | #include <sys/asm_linkage.h> | |
54 | #include <sys/htypes.h> | |
55 | #include <asi.h> | |
56 | #include <hprivregs.h> | |
57 | #include <sun4v/asi.h> | |
58 | #include <offsets.h> | |
59 | #include <cyclic.h> | |
60 | #include <util.h> | |
61 | ||
62 | ||
63 | /* | |
64 | * Function: cyclic_add_rel & cyclic_add_abs | |
65 | * | |
66 | * These functions register a handler to be called at a time | |
67 | * specified by relative or absolute ticks. | |
68 | * | |
69 | * The maximum real time for the counter depends on the core frequency. | |
70 | * Assuming a 1.0 GHz tick, the rollover will occur in ~292 yrs. | |
71 | * Since this opens the door for unrealistic timeout values, we shall, | |
72 | * by default, limit the input delta to a more realistic value. This | |
73 | * value, in days, is set by default to one year plus one day (367). | |
74 | * It is then converted to system ticks in the function start_master. | |
75 | * | |
76 | * A handler is automatically removed from the queue when the | |
77 | * interrupt is serviced. | |
78 | * | |
79 | * Input Arguments: | |
80 | * %g1: tick time (relative or absolute) | |
81 | * %g2: handler address | |
82 | * %g3: handler arg0 | |
83 | * %g4: handler arg1 | |
84 | * %g5: scratch | |
85 | * | |
86 | * Return: | |
87 | * %g1: status (0=success, 1=full) | |
88 | * | |
89 | * Function: cyclic_add_rel | |
90 | * | |
91 | * This entry registers a handler to be called after a delay | |
92 | * specified in ticks. | |
93 | */ | |
94 | ENTRY_NP(cyclic_add_rel) | |
95 | rd STICK, %g5 ! current time | |
96 | add %g1, %g5, %g1 ! + delta = abs time | |
97 | /* Fall thru into cyclic_add_abs() */ | |
98 | ||
99 | ||
100 | /* | |
101 | * Function: cyclic_add_abs | |
102 | * | |
103 | * This entry registers a handler to be called at a time | |
104 | * specified in ticks. | |
105 | */ | |
106 | ENTRY_NP(cyclic_add_abs) | |
107 | /* Fall thru into cyclic_add() core function*/ | |
108 | ||
109 | ||
110 | /* This is the core function cyclic_add() */ | |
111 | STRAND_STRUCT(%g6) | |
112 | stx %g2, [%g6 + STRAND_CY_HANDLER] ! save handler address | |
113 | stx %g3, [%g6 + STRAND_CY_ARG0] ! save handler args | |
114 | stx %g4, [%g6 + STRAND_CY_ARG1] ! save handler args | |
115 | ||
116 | /* | |
117 | * Check if array full: | |
118 | */ | |
119 | ldx [%g6 + STRAND_CY_CB_LAST_TICK], %g2 | |
120 | brnz,a %g2, .cya_ret ! full: return error | |
121 | mov 1, %g1 ! status = 1 | |
122 | ||
123 | STRAND2CONFIG_STRUCT(%g6, %g5) ! ->config | |
124 | ldx [%g6 + STRAND_CY_CB_TICK], %g2 ! first tick | |
125 | brnz,pt %g2, .cya_1 ! not empty: continue | |
126 | rd STICK, %g3 ! get current time | |
127 | stx %g3, [%g6 + STRAND_CY_T0] ! empty: set t0 | |
128 | .cya_1: | |
129 | wrhpr %g0, -1, %hstick_cmpr ! inhibit the compare interrupt | |
130 | ||
131 | ldx [%g5 + CONFIG_CYCLIC_MAXD], %g5 ! max delta | |
132 | subcc %g1, %g5, %g2 ! delta | |
133 | bleu %xcc, .cya_3 ! in the past, let t0 check fix | |
134 | cmp %g2, %g5 ! input within range? | |
135 | bgu,a %xcc, .cya_3 ! yes: anul next | |
136 | add %g3, %g5, %g1 ! no: use max value! | |
137 | .cya_3: | |
138 | /* g1=abs_tick */ | |
139 | ldx [%g6 + STRAND_CY_T0], %g4 ! normalize input to T0 | |
140 | subcc %g1, %g4, %g1 ! .. | |
141 | movlu %xcc, %g0, %g1 ! reverse - set to minimum | |
142 | /* g1=delta_tick */ | |
143 | add %g6, STRAND_CY_CB, %g4 ! ->cb[0] | |
144 | add %g4, CB_LAST, %g5 ! ->cb[last] | |
145 | dec CB_SIZE, %g4 ! annul next inc | |
146 | .cya_4: | |
147 | inc CB_SIZE, %g4 ! next | |
148 | ldx [%g4 + CB_HANDLER], %g3 ! cb[i].handler | |
149 | ldx [%g4 + CB_TICK], %g2 ! cb[i].tick | |
150 | brz,pn %g3, .cya_7 ! empty: store here | |
151 | cmp %g1, %g2 ! input less than delta? | |
152 | bge,a %xcc, .cya_4 ! no: check next | |
153 | sub %g1, %g2, %g1 ! adjust input | |
154 | /* | |
155 | * Insert at %g4: | |
156 | */ | |
157 | sub %g2, %g1, %g2 ! adjust current for insert | |
158 | stx %g2, [%g4 + CB_TICK] ! store | |
159 | .cya_5: ! shift remaining up | |
160 | ldx [%g5 + CB_HANDLER], %g2 ! next handler | |
161 | brz,a,pt %g2, .cya_6 ! open slot: skip | |
162 | cmp %g4, %g5 ! (at cb[i]?) | |
163 | ! move this one up: | |
164 | ldx [%g5 + CB_TICK], %g3 ! tick | |
165 | stx %g2, [%g5 + CB_SIZE + CB_HANDLER] | |
166 | ldx [%g5 + CB_ARG0], %g2 ! arg0 | |
167 | stx %g3, [%g5 + CB_SIZE + CB_TICK] | |
168 | ldx [%g5 + CB_ARG1], %g3 ! arg1 | |
169 | stx %g2, [%g5 + CB_SIZE + CB_ARG0] | |
170 | stx %g3, [%g5 + CB_SIZE + CB_ARG1] ! .. | |
171 | cmp %g4, %g5 ! at cb[i]? | |
172 | .cya_6: | |
173 | bnz,a,pt %xcc, .cya_5 ! no | |
174 | dec CB_SIZE, %g5 ! check next | |
175 | ||
176 | /* | |
177 | * Store new entry at %g4: | |
178 | */ | |
179 | .cya_7: | |
180 | stx %g1, [%g4 + CB_TICK] ! store tick | |
181 | ldx [%g6 + STRAND_CY_HANDLER],%g2 ! saved handler | |
182 | stx %g2, [%g4 + CB_HANDLER] ! store | |
183 | ldx [%g6 + STRAND_CY_ARG0], %g2 ! saved arg0 | |
184 | stx %g2, [%g4 + CB_ARG0] ! store | |
185 | ldx [%g6 + STRAND_CY_ARG1], %g2 ! saved arg1 | |
186 | stx %g2, [%g4 + CB_ARG1] ! store | |
187 | /* | |
188 | * Setup new timer interrupt: | |
189 | */ | |
190 | ldx [%g6 + STRAND_CY_T0], %g1 ! T0 (abs base for cyclic[].tick) | |
191 | ldx [%g6 + STRAND_CY_CB_TICK], %g2 ! Td (next delta time) | |
192 | add %g1, %g2, %g4 ! Tn = T0 + Td (next int time) | |
193 | ||
194 | set EXIT_NTICK, %g5 ! #tick needed to exit | |
195 | rd STICK, %g3 ! current time | |
196 | add %g3, %g5, %g3 ! Tm (minimum int time) | |
197 | ||
198 | cmp %g3, %g4 ! Tn = max(Tn, Tm) | |
199 | movgu %xcc, %g3, %g4 | |
200 | ||
201 | wrhpr %g4, %hstick_cmpr ! start the clock running | |
202 | ||
203 | clr %g1 ! return status = success | |
204 | .cya_ret: | |
205 | HVRET | |
206 | SET_SIZE(cyclic_add_abs) | |
207 | SET_SIZE(cyclic_add_rel) | |
208 | ||
209 | ||
210 | /* | |
211 | * Function: cyclic_remove | |
212 | * | |
213 | * This function removes an entry from the cyclic timer | |
214 | * queue. | |
215 | * | |
216 | * input: %g2 = handler address, if zero - remove head entry | |
217 | * | |
218 | * scratch: %g3-4 | |
219 | * | |
220 | * ToDo: ???? if first entry: disable int | |
221 | */ | |
222 | ENTRY_NP(cyclic_remove) | |
223 | STRAND_STRUCT(%g4) | |
224 | add %g4, STRAND_CY_CB, %g4 ! ->cb[0] | |
225 | brz,pt %g2, .cyr_2 ! input == 0: do head | |
226 | .cyr_1: | |
227 | ldx [%g4 + CB_HANDLER], %g3 ! address | |
228 | brz %g3, .cyr_9 ! null: input not found! | |
229 | cmp %g2, %g3 ! match input? | |
230 | bnz,a %xcc, .cyr_1 ! no: keep looking | |
231 | inc CB_SIZE, %g4 ! => next entry | |
232 | ldx [%g4 + CB_TICK], %g3 ! Td of entry removed | |
233 | ldx [%g4 + CB_SIZE + CB_TICK], %g2 ! Td of next entry | |
234 | add %g3, %g2, %g3 ! adjust next time | |
235 | stx %g3, [%g4 + CB_SIZE + CB_TICK] ! .. | |
236 | .cyr_2: ! | |
237 | ldx [%g4 + CB_SIZE + CB_HANDLER], %g2 ! shift remainder down | |
238 | ldx [%g4 + CB_SIZE + CB_TICK], %g3 ! .. | |
239 | stx %g2, [%g4 + CB_HANDLER] ! .. | |
240 | brz,a,pn %g2, .cyr_8 ! (done: addr==0, tick=0) | |
241 | stx %g0, [%g4 + CB_TICK] ! .. | |
242 | ldx [%g4 + CB_SIZE + CB_ARG0], %g2 ! .. | |
243 | stx %g3, [%g4 + CB_TICK] ! .. | |
244 | ldx [%g4 + CB_SIZE + CB_ARG1], %g3 ! .. | |
245 | stx %g2, [%g4 + CB_ARG0] ! .. | |
246 | stx %g3, [%g4 + CB_ARG1] ! .. | |
247 | ba .cyr_2 ! do next | |
248 | inc CB_SIZE, %g4 | |
249 | .cyr_8: | |
250 | stx %g0, [%g4 + CB_ARG0] ! zero arg0 | |
251 | stx %g0, [%g4 + CB_ARG1] ! zero arg1 | |
252 | .cyr_9: | |
253 | HVRET | |
254 | SET_SIZE(cyclic_remove) | |
255 | ||
256 | ||
257 | /* | |
258 | * Function: cyclic_handler_pop | |
259 | * | |
260 | * This function pops first element off the queue. It uses the | |
261 | * handler address as a valid flag. Time Zero (T0) is updated | |
262 | * to the next time base (T0 + cyclic_tick[0]). | |
263 | * | |
264 | * return: | |
265 | * g1 arg0 | |
266 | * g2 arg1 | |
267 | * g3 t0 | |
268 | * g4 handler address | |
269 | * g5-6 clobbered | |
270 | */ | |
271 | ENTRY_NP(cyclic_handler_pop) | |
272 | ||
273 | STRAND_STRUCT(%g6) ! ->strand | |
274 | add %g6, STRAND_CY_CB, %g5 ! ->cb[0] | |
275 | ||
276 | ldx [%g5 + CB_HANDLER], %g4 ! cb[0].handler | |
277 | brz,a,pn %g4, .cyp_9 ! null: return g4=null | |
278 | clrx [%g6 + STRAND_CY_T0] ! reset time basis | |
279 | /* | |
280 | * Update time basis: | |
281 | */ | |
282 | ldx [%g6 + STRAND_CY_T0], %g3 ! T0 | |
283 | ldx [%g5 + CB_TICK], %g2 ! cb[0].tick | |
284 | add %g3, %g2, %g3 ! next T0 | |
285 | stx %g3, [%g6 + STRAND_CY_T0] | |
286 | ||
287 | ldx [%g5 + CB_ARG0], %g1 ! cb[0].arg0 | |
288 | ldx [%g5 + CB_ARG1], %g2 ! cb[0].arg1 | |
289 | .cyp_2: | |
290 | ldx [%g5 + CB_SIZE + CB_HANDLER], %g6 ! shift rest down | |
291 | stx %g6, [%g5 + CB_HANDLER] ! .. | |
292 | brz,a %g6, .cyp_8 ! done: addr, tick = 0 | |
293 | clrx [%g5 + CB_TICK] ! .. | |
294 | ldx [%g5 + CB_SIZE + CB_TICK], %g6 ! .. | |
295 | stx %g6, [%g5 + CB_TICK] ! .. | |
296 | ldx [%g5 + CB_SIZE + CB_ARG0], %g6 ! .. | |
297 | stx %g6, [%g5 + CB_ARG0] ! .. | |
298 | ldx [%g5 + CB_SIZE + CB_ARG1], %g6 ! .. | |
299 | stx %g6, [%g5 + CB_ARG1] ! .. | |
300 | ba .cyp_2 ! do next | |
301 | inc CB_SIZE, %g5 | |
302 | .cyp_8: | |
303 | clrx [%g5 + CB_ARG0] ! zero arg0 | |
304 | clrx [%g5 + CB_ARG1] ! zero arg1 | |
305 | .cyp_9: | |
306 | HVRET | |
307 | SET_SIZE(cyclic_handler_pop) | |
308 | ||
309 | ||
310 | /* | |
311 | * hstick_intr | |
312 | * | |
313 | * Hstick interrupt service routine. | |
314 | * This function is called when the compare interrupt fires. | |
315 | * | |
316 | * Note that %hstick_cmpr has been disabled in the trap handler. | |
317 | */ | |
318 | ENTRY_NP(hstick_intr) | |
319 | ||
320 | HVCALL(cyclic_handler_pop) ! %g1-4: arg0, arg1, t0, handler | |
321 | ! %g5-6: clobbered | |
322 | brz,a,pn %g4, .hsi_8 ! no cyclic: return | |
323 | nop | |
324 | ||
325 | jmp %g4 ! call handler(arg0, arg1, t0) | |
326 | rd %pc, %g7 ! assume all regs are clobbered!! | |
327 | ||
328 | /* | |
329 | * This test should (must) fail, if not there is a logic error. | |
330 | * It is here as a fail-safe - add 'warning' code later | |
331 | */ | |
332 | rdhpr %hstick_cmpr, %g1 ! did callback re-enable? | |
333 | brgez %g1, .hsi_8 ! yes: clear int & return | |
334 | nop | |
335 | STRAND_STRUCT(%g6) ! ->strand | |
336 | ldx [%g6 + STRAND_CY_CB_HANDLER], %g2 ! first handler | |
337 | brz,a %g2, .hsi_8 ! empty: clear int & return | |
338 | nop | |
339 | ldx [%g6 + STRAND_CY_CB_TICK], %g2 ! Td (next delta time) | |
340 | ldx [%g6 + STRAND_CY_T0], %g4 ! T0 (abs base for cyclic[].tick) | |
341 | ||
342 | rd STICK, %g3 ! Tc = current time | |
343 | mov HSTICK_RET, %g1 ! Tr = #tick needed to Retry | |
344 | add %g3, %g1, %g3 ! Tint_min = Tc + Tr | |
345 | ||
346 | add %g4, %g2, %g4 ! Tint_next = T0 + Td | |
347 | ||
348 | cmp %g3, %g4 ! is Tint_min > Tint_next ? | |
349 | movgu %xcc, %g3, %g4 ! yes: Tn = Tint_min | |
350 | wrhpr %g4, %hstick_cmpr ! set the clock | |
351 | ||
352 | .hsi_8: | |
353 | /* | |
354 | * Reenable our interrupt. Clear hintp:HSP | |
355 | */ | |
356 | wrhpr %g0, %hintp | |
357 | ||
358 | retry | |
359 | SET_SIZE(hstick_intr) | |
360 | ||
361 | ||
362 | #if 0 | |
363 | /* | |
364 | * cyclic_callback_template | |
365 | * | |
366 | * Hstick interrupt callback function template: | |
367 | * | |
368 | * Called to get actual handler callback address (avoid relocation problems) | |
369 | * | |
370 | * Entry Data: | |
371 | * none | |
372 | * | |
373 | * Return Data: | |
374 | * %g2: handler address | |
375 | * | |
376 | * Registers modified: | |
377 | * %g2 | |
378 | */ | |
379 | ENTRY_NP(cyclic_callback_template) | |
380 | RETURN_HANDLER_ADDRESS(%g2) ! in %g2 | |
381 | ||
382 | /* | |
383 | * Callback from interrupt: | |
384 | * | |
385 | * Entry Data: | |
386 | * %g1: arg0 | |
387 | * %g2: arg1 | |
388 | * %g3: t0 - interrupt tick time | |
389 | * | |
390 | * Return Data: | |
391 | * none | |
392 | * | |
393 | * Registers modified: | |
394 | * %g1-6 | |
395 | */ | |
396 | .callback_entry: /* This is the actual function entry */ | |
397 | nop ! insert code here. | |
398 | ||
399 | HVRET | |
400 | SET_SIZE(cyclic_callback_template) | |
401 | #endif /* 0/1 */ |