Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / hypervisor / src / common / src / cyclic.s
CommitLineData
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 */