xref: /onnv-gate/usr/src/uts/common/sys/cyclic_impl.h (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #ifndef _SYS_CYCLIC_IMPL_H
28*0Sstevel@tonic-gate #define	_SYS_CYCLIC_IMPL_H
29*0Sstevel@tonic-gate 
30*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
31*0Sstevel@tonic-gate 
32*0Sstevel@tonic-gate #ifdef	__cplusplus
33*0Sstevel@tonic-gate extern "C" {
34*0Sstevel@tonic-gate #endif
35*0Sstevel@tonic-gate 
36*0Sstevel@tonic-gate #include <sys/cyclic.h>
37*0Sstevel@tonic-gate 
38*0Sstevel@tonic-gate /*
39*0Sstevel@tonic-gate  *  Cyclic Subsystem Backend-supplied Interfaces
40*0Sstevel@tonic-gate  *  --------------------------------------------
41*0Sstevel@tonic-gate  *
42*0Sstevel@tonic-gate  *  0  Background
43*0Sstevel@tonic-gate  *
44*0Sstevel@tonic-gate  *    The design, implementation and interfaces of the cyclic subsystem are
45*0Sstevel@tonic-gate  *    covered in detail in block comments in the implementation.  This
46*0Sstevel@tonic-gate  *    comment covers the interface from the cyclic subsystem into the cyclic
47*0Sstevel@tonic-gate  *    backend.  The backend is specified by a structure of function pointers
48*0Sstevel@tonic-gate  *    defined below.
49*0Sstevel@tonic-gate  *
50*0Sstevel@tonic-gate  *  1  Overview
51*0Sstevel@tonic-gate  *
52*0Sstevel@tonic-gate  *      cyb_configure()      <-- Configures the backend on the specified CPU
53*0Sstevel@tonic-gate  *      cyb_unconfigure()    <-- Unconfigures the backend
54*0Sstevel@tonic-gate  *      cyb_enable()         <-- Enables the CY_HIGH_LEVEL interrupt source
55*0Sstevel@tonic-gate  *      cyb_disable()        <-- Disables the CY_HIGH_LEVEL interrupt source
56*0Sstevel@tonic-gate  *      cyb_reprogram()      <-- Reprograms the CY_HIGH_LEVEL interrupt source
57*0Sstevel@tonic-gate  *      cyb_softint()        <-- Generates a soft interrupt
58*0Sstevel@tonic-gate  *      cyb_set_level()      <-- Sets the programmable interrupt level
59*0Sstevel@tonic-gate  *      cyb_restore_level()  <-- Restores the programmable interrupt level
60*0Sstevel@tonic-gate  *      cyb_xcall()          <-- Cross calls to the specified CPU
61*0Sstevel@tonic-gate  *      cyb_suspend()        <-- Suspends the backend
62*0Sstevel@tonic-gate  *      cyb_resume()         <-- Resumes the backend
63*0Sstevel@tonic-gate  *
64*0Sstevel@tonic-gate  *  2  cyb_arg_t cyb_configure(cpu_t *)
65*0Sstevel@tonic-gate  *
66*0Sstevel@tonic-gate  *  2.1  Overview
67*0Sstevel@tonic-gate  *
68*0Sstevel@tonic-gate  *    cyb_configure() should configure the specified CPU for cyclic operation.
69*0Sstevel@tonic-gate  *
70*0Sstevel@tonic-gate  *  2.2  Arguments and notes
71*0Sstevel@tonic-gate  *
72*0Sstevel@tonic-gate  *    cyb_configure() should initialize any backend-specific per-CPU
73*0Sstevel@tonic-gate  *    structures for the specified CPU.  cyb_configure() will be called for
74*0Sstevel@tonic-gate  *    each CPU (including the boot CPU) during boot.  If the platform
75*0Sstevel@tonic-gate  *    supports dynamic reconfiguration, cyb_configure() will be called for
76*0Sstevel@tonic-gate  *    new CPUs as they are configured into the system.
77*0Sstevel@tonic-gate  *
78*0Sstevel@tonic-gate  *  2.3  Return value
79*0Sstevel@tonic-gate  *
80*0Sstevel@tonic-gate  *    cyb_configure() is expected to return a cookie (a cyb_arg_t, which is
81*0Sstevel@tonic-gate  *    of type void *) which will be used as the first argument for all future
82*0Sstevel@tonic-gate  *    cyclic calls into the backend on the specified CPU.
83*0Sstevel@tonic-gate  *
84*0Sstevel@tonic-gate  *  2.4  Caller's context
85*0Sstevel@tonic-gate  *
86*0Sstevel@tonic-gate  *    cpu_lock will be held.  The caller's CPU is unspecified, and may or
87*0Sstevel@tonic-gate  *    may not be the CPU specified to cyb_configure().
88*0Sstevel@tonic-gate  *
89*0Sstevel@tonic-gate  *  3  void cyb_unconfigure(cyb_arg_t arg)
90*0Sstevel@tonic-gate  *
91*0Sstevel@tonic-gate  *  3.1  Overview
92*0Sstevel@tonic-gate  *
93*0Sstevel@tonic-gate  *    cyb_unconfigure() should unconfigure the specified backend.
94*0Sstevel@tonic-gate  *
95*0Sstevel@tonic-gate  *  3.2  Arguments and notes
96*0Sstevel@tonic-gate  *
97*0Sstevel@tonic-gate  *    The only argument to cyb_unconfigure() is a cookie as returned from
98*0Sstevel@tonic-gate  *    cyb_configure().
99*0Sstevel@tonic-gate  *
100*0Sstevel@tonic-gate  *    cyb_unconfigure() should free any backend-specific per-CPU structures
101*0Sstevel@tonic-gate  *    for the specified backend.  cyb_unconfigure() will _only_ be called on
102*0Sstevel@tonic-gate  *    platforms which support dynamic reconfiguration.  If the platform does
103*0Sstevel@tonic-gate  *    not support dynamic reconfiguration, cyb_unconfigure() may panic.
104*0Sstevel@tonic-gate  *
105*0Sstevel@tonic-gate  *    After cyb_unconfigure() returns, the backend must not call cyclic_fire()
106*0Sstevel@tonic-gate  *    on the corresponding CPU; doing so will result in a bad trap.
107*0Sstevel@tonic-gate  *
108*0Sstevel@tonic-gate  *  3.3  Return value
109*0Sstevel@tonic-gate  *
110*0Sstevel@tonic-gate  *    None.
111*0Sstevel@tonic-gate  *
112*0Sstevel@tonic-gate  *  3.4  Caller's context
113*0Sstevel@tonic-gate  *
114*0Sstevel@tonic-gate  *    cpu_lock will be held.  The caller's CPU is unspecified, and may or
115*0Sstevel@tonic-gate  *    may not be the CPU specified to cyb_unconfigure().  The specified
116*0Sstevel@tonic-gate  *    CPU is guaranteed to exist at the time cyb_unconfigure() is called.
117*0Sstevel@tonic-gate  *    The cyclic subsystem is guaranteed to be suspended when cyb_unconfigure()
118*0Sstevel@tonic-gate  *    is called, and interrupts are guaranteed to be disabled.
119*0Sstevel@tonic-gate  *
120*0Sstevel@tonic-gate  *  4  void cyb_enable(cyb_arg_t arg)
121*0Sstevel@tonic-gate  *
122*0Sstevel@tonic-gate  *  4.1  Overview
123*0Sstevel@tonic-gate  *
124*0Sstevel@tonic-gate  *    cyb_enable() should enable the CY_HIGH_LEVEL interrupt source on
125*0Sstevel@tonic-gate  *    the specified backend.
126*0Sstevel@tonic-gate  *
127*0Sstevel@tonic-gate  *  4.2  Arguments and notes
128*0Sstevel@tonic-gate  *
129*0Sstevel@tonic-gate  *    The only argument to cyb_enable() is a backend cookie as returned from
130*0Sstevel@tonic-gate  *    cyb_configure().
131*0Sstevel@tonic-gate  *
132*0Sstevel@tonic-gate  *    cyb_enable() will only be called if a) the specified backend has never
133*0Sstevel@tonic-gate  *    been enabled or b) the specified backend has been explicitly disabled with
134*0Sstevel@tonic-gate  *    cyb_disable().  In either case, cyb_enable() will only be called if
135*0Sstevel@tonic-gate  *    the cyclic subsystem wishes to add a cyclic to the CPU corresponding
136*0Sstevel@tonic-gate  *    to the specified backend.  cyb_enable() will be called before
137*0Sstevel@tonic-gate  *    cyb_reprogram() for a given backend.
138*0Sstevel@tonic-gate  *
139*0Sstevel@tonic-gate  *    cyclic_fire() should not be called on a CPU which has not had its backend
140*0Sstevel@tonic-gate  *    explicitly cyb_enable()'d, but to do so does not constitute fatal error.
141*0Sstevel@tonic-gate  *
142*0Sstevel@tonic-gate  *  4.3  Return value
143*0Sstevel@tonic-gate  *
144*0Sstevel@tonic-gate  *    None.
145*0Sstevel@tonic-gate  *
146*0Sstevel@tonic-gate  *  4.4  Caller's context
147*0Sstevel@tonic-gate  *
148*0Sstevel@tonic-gate  *    cyb_enable() will only be called from CY_HIGH_LEVEL context on the CPU
149*0Sstevel@tonic-gate  *    corresponding to the specified backend.
150*0Sstevel@tonic-gate  *
151*0Sstevel@tonic-gate  *  5  void cyb_disable(cyb_arg_t arg)
152*0Sstevel@tonic-gate  *
153*0Sstevel@tonic-gate  *  5.1  Overview
154*0Sstevel@tonic-gate  *
155*0Sstevel@tonic-gate  *    cyb_disable() should disable the CY_HIGH_LEVEL interrupt source on
156*0Sstevel@tonic-gate  *    the specified backend.
157*0Sstevel@tonic-gate  *
158*0Sstevel@tonic-gate  *  5.2  Arguments and notes
159*0Sstevel@tonic-gate  *
160*0Sstevel@tonic-gate  *    The only argument to cyb_disable() is a backend cookie as returned from
161*0Sstevel@tonic-gate  *    cyb_configure().
162*0Sstevel@tonic-gate  *
163*0Sstevel@tonic-gate  *    cyb_disable() will only be called on backends which have been previously
164*0Sstevel@tonic-gate  *    been cyb_enable()'d.  cyb_disable() will be called when all cyclics have
165*0Sstevel@tonic-gate  *    been juggled away or removed from a cyb_enable()'d CPU.
166*0Sstevel@tonic-gate  *
167*0Sstevel@tonic-gate  *    cyclic_fire() should not be called on a CPU which has had its backend
168*0Sstevel@tonic-gate  *    explicitly cyb_disable()'d, but to do so does not constitute fatal
169*0Sstevel@tonic-gate  *    error.  cyb_disable() is thus not required to check for a pending
170*0Sstevel@tonic-gate  *    CY_HIGH_LEVEL interrupt.
171*0Sstevel@tonic-gate  *
172*0Sstevel@tonic-gate  *  5.3  Return value
173*0Sstevel@tonic-gate  *
174*0Sstevel@tonic-gate  *    None.
175*0Sstevel@tonic-gate  *
176*0Sstevel@tonic-gate  *  5.4  Caller's context
177*0Sstevel@tonic-gate  *
178*0Sstevel@tonic-gate  *    cyb_disable() will only be called from CY_HIGH_LEVEL context on the CPU
179*0Sstevel@tonic-gate  *    corresponding to the specified backend.
180*0Sstevel@tonic-gate  *
181*0Sstevel@tonic-gate  *  6  void cyb_reprogram(cyb_arg_t arg, hrtime_t time)
182*0Sstevel@tonic-gate  *
183*0Sstevel@tonic-gate  *  6.1  Overview
184*0Sstevel@tonic-gate  *
185*0Sstevel@tonic-gate  *    cyb_reprogram() should reprogram the CY_HIGH_LEVEL interrupt source
186*0Sstevel@tonic-gate  *    to fire at the absolute time specified.
187*0Sstevel@tonic-gate  *
188*0Sstevel@tonic-gate  *  6.2  Arguments and notes
189*0Sstevel@tonic-gate  *
190*0Sstevel@tonic-gate  *    The first argument to cyb_reprogram() is a backend cookie as returned from
191*0Sstevel@tonic-gate  *    cyb_configure().
192*0Sstevel@tonic-gate  *
193*0Sstevel@tonic-gate  *    The second argument is an absolute time at which the CY_HIGH_LEVEL
194*0Sstevel@tonic-gate  *    interrupt should fire.  The specified time _may_ be in the past (albeit
195*0Sstevel@tonic-gate  *    the very recent past).  If this is the case, the backend should generate
196*0Sstevel@tonic-gate  *    a CY_HIGH_LEVEL interrupt as soon as possible.
197*0Sstevel@tonic-gate  *
198*0Sstevel@tonic-gate  *    The platform should not assume that cyb_reprogram() will be called with
199*0Sstevel@tonic-gate  *    monotonically increasing values.
200*0Sstevel@tonic-gate  *
201*0Sstevel@tonic-gate  *    If the platform does not allow for interrupts at arbitrary times in the
202*0Sstevel@tonic-gate  *    future, cyb_reprogram() may do nothing -- as long as cyclic_fire() is
203*0Sstevel@tonic-gate  *    called periodically at CY_HIGH_LEVEL.  While this is clearly suboptimal
204*0Sstevel@tonic-gate  *    (cyclic granularity will be bounded by the length of the period between
205*0Sstevel@tonic-gate  *    cyclic_fire()'s), it allows the cyclic subsystem to be implemented on
206*0Sstevel@tonic-gate  *    inferior hardware.
207*0Sstevel@tonic-gate  *
208*0Sstevel@tonic-gate  *  6.3  Return value
209*0Sstevel@tonic-gate  *
210*0Sstevel@tonic-gate  *     None.
211*0Sstevel@tonic-gate  *
212*0Sstevel@tonic-gate  *  6.4  Caller's context
213*0Sstevel@tonic-gate  *
214*0Sstevel@tonic-gate  *    cyb_reprogram() will only be called from CY_HIGH_LEVEL context on the CPU
215*0Sstevel@tonic-gate  *    corresponding to the specified backend.
216*0Sstevel@tonic-gate  *
217*0Sstevel@tonic-gate  *  7  void cyb_softint(cyb_arg_t arg, cyc_level_t level)
218*0Sstevel@tonic-gate  *
219*0Sstevel@tonic-gate  *  7.1  Overview
220*0Sstevel@tonic-gate  *
221*0Sstevel@tonic-gate  *    cyb_softint() should generate a software interrupt on the specified
222*0Sstevel@tonic-gate  *    backend at the specified level.
223*0Sstevel@tonic-gate  *
224*0Sstevel@tonic-gate  *  7.2  Arguments and notes
225*0Sstevel@tonic-gate  *
226*0Sstevel@tonic-gate  *    The first argument to cyb_softint() is a backend cookie as returned from
227*0Sstevel@tonic-gate  *    cyb_configure().  The second argument is the interrupt level at which
228*0Sstevel@tonic-gate  *    the software interrupt should be generated; it will be either
229*0Sstevel@tonic-gate  *    CY_LOCK_LEVEL or CY_LOW_LEVEL.
230*0Sstevel@tonic-gate  *
231*0Sstevel@tonic-gate  *    The software interrupt _must_ be generated on the CPU corresponding
232*0Sstevel@tonic-gate  *    to the specified backend; platforms are _required_ to have a per-CPU
233*0Sstevel@tonic-gate  *    notion of a software interrupt.
234*0Sstevel@tonic-gate  *
235*0Sstevel@tonic-gate  *    Unless a software interrupt is already pending at the specified level,
236*0Sstevel@tonic-gate  *    the software interrupt _must_ be generated.  Once cyclic_softint()
237*0Sstevel@tonic-gate  *    has been called at a given level, the software interrupt at that level
238*0Sstevel@tonic-gate  *    should no longer be considered pending; an intervening CY_HIGH_LEVEL
239*0Sstevel@tonic-gate  *    interrupt and subsequent cyb_softint() must generate another software
240*0Sstevel@tonic-gate  *    interrupt.
241*0Sstevel@tonic-gate  *
242*0Sstevel@tonic-gate  *  7.3  Return value
243*0Sstevel@tonic-gate  *
244*0Sstevel@tonic-gate  *    None.
245*0Sstevel@tonic-gate  *
246*0Sstevel@tonic-gate  *  7.4  Caller's context
247*0Sstevel@tonic-gate  *
248*0Sstevel@tonic-gate  *    cyb_softint() will only be called at a level higher than the one
249*0Sstevel@tonic-gate  *    specified:  if CY_LOCK_LEVEL is specified, the caller will be at
250*0Sstevel@tonic-gate  *    CY_HIGH_LEVEL; if CY_LOW_LEVEL is specified, the caller will be at
251*0Sstevel@tonic-gate  *    either CY_HIGH_LEVEL or CY_LOCK_LEVEL.  cyb_softint() will only be
252*0Sstevel@tonic-gate  *    called on the CPU corresponding to the specified backend.
253*0Sstevel@tonic-gate  *
254*0Sstevel@tonic-gate  *  8  cyb_set_level(cyb_arg_t arg, cyc_level_t level)
255*0Sstevel@tonic-gate  *
256*0Sstevel@tonic-gate  *  8.1  Overview
257*0Sstevel@tonic-gate  *
258*0Sstevel@tonic-gate  *    cyb_set_level() should set the programmable interrupt level to the
259*0Sstevel@tonic-gate  *    level specified.
260*0Sstevel@tonic-gate  *
261*0Sstevel@tonic-gate  *  8.2  Arguments and notes
262*0Sstevel@tonic-gate  *
263*0Sstevel@tonic-gate  *    The first argument to cyb_set_level() is a backend cookie as returned
264*0Sstevel@tonic-gate  *    from cyb_configure().  The second argument is the level to which
265*0Sstevel@tonic-gate  *    the programmable interrupt level should be set; it will be one of
266*0Sstevel@tonic-gate  *    CY_HIGH_LEVEL, CY_LOCK_LEVEL or CY_LOW_LEVEL.
267*0Sstevel@tonic-gate  *
268*0Sstevel@tonic-gate  *    After cyb_set_level() returns, the CPU associated with the specified
269*0Sstevel@tonic-gate  *    backend should accept no interrupt at a level greater than or equal to
270*0Sstevel@tonic-gate  *    the specified level.  This will generally be a wrapper around splx().
271*0Sstevel@tonic-gate  *
272*0Sstevel@tonic-gate  *    The cyclic subsystem will never call cyb_set_level() twice consecutively
273*0Sstevel@tonic-gate  *    on the same backend; there will always be an intervening
274*0Sstevel@tonic-gate  *    cyb_restore_level();
275*0Sstevel@tonic-gate  *
276*0Sstevel@tonic-gate  *  8.3  Return value
277*0Sstevel@tonic-gate  *
278*0Sstevel@tonic-gate  *    cyb_set_level() should return a cookie to be passed back to
279*0Sstevel@tonic-gate  *    cyb_restore_level().  On most implementations, this cookie will be
280*0Sstevel@tonic-gate  *    the spl at the time of cyb_set_level().
281*0Sstevel@tonic-gate  *
282*0Sstevel@tonic-gate  *  8.4  Caller's context
283*0Sstevel@tonic-gate  *
284*0Sstevel@tonic-gate  *    cyb_set_level() is unique in that it is the only backend-provided
285*0Sstevel@tonic-gate  *    interface which may be called in cross call context (see cyb_xcall(),
286*0Sstevel@tonic-gate  *    below).  cyb_set_level() may also be called from any of the cyclic
287*0Sstevel@tonic-gate  *
288*0Sstevel@tonic-gate  *  9  cyb_restore_level(cyb_arg_t arg, cyc_cookie_t cookie)
289*0Sstevel@tonic-gate  *
290*0Sstevel@tonic-gate  *  9.1  Overview
291*0Sstevel@tonic-gate  *
292*0Sstevel@tonic-gate  *    cyb_restore_level() should restore the programmable interrupt level
293*0Sstevel@tonic-gate  *    based upon the specified cookie.
294*0Sstevel@tonic-gate  *
295*0Sstevel@tonic-gate  *  9.2  Arguments and notes
296*0Sstevel@tonic-gate  *
297*0Sstevel@tonic-gate  *    The first argument to cyb_restore_level() is a backend cookie as returned
298*0Sstevel@tonic-gate  *    from cyb_configure().  The second argument is a cookie as returned from
299*0Sstevel@tonic-gate  *    cyb_set_level().
300*0Sstevel@tonic-gate  *
301*0Sstevel@tonic-gate  *    cyb_restore_level() should restore the programmable interrupt level
302*0Sstevel@tonic-gate  *    to its value when cyb_set_level() was called; the cookie is used
303*0Sstevel@tonic-gate  *    to provide a hint to the backend.  cyb_restore_level() will not be
304*0Sstevel@tonic-gate  *    called without a proceeding call to cyb_set_level(), and
305*0Sstevel@tonic-gate  *    cyb_restore_level() will never be called twice consecutively on the
306*0Sstevel@tonic-gate  *    same backend.
307*0Sstevel@tonic-gate  *
308*0Sstevel@tonic-gate  *  9.3  Return value
309*0Sstevel@tonic-gate  *
310*0Sstevel@tonic-gate  *    None.
311*0Sstevel@tonic-gate  *
312*0Sstevel@tonic-gate  *  9.4  Caller's context
313*0Sstevel@tonic-gate  *
314*0Sstevel@tonic-gate  *    The constraints outlined in 5.9.2 imply that cyb_restore_level() can
315*0Sstevel@tonic-gate  *    only be called from CY_HIGH_LEVEL, CY_LOCK_LEVEL or CY_LOW_LEVEL context.
316*0Sstevel@tonic-gate  *    cyb_restore_level() is always called on the CPU associated with the
317*0Sstevel@tonic-gate  *    specified backend.
318*0Sstevel@tonic-gate  *
319*0Sstevel@tonic-gate  *  10  cyb_xcall(cyb_arg_t arg, cpu_t *, void(*func)(void *), void *farg)
320*0Sstevel@tonic-gate  *
321*0Sstevel@tonic-gate  *  10.1  Overview
322*0Sstevel@tonic-gate  *
323*0Sstevel@tonic-gate  *    cyb_xcall() should execute the specified function on the specified CPU.
324*0Sstevel@tonic-gate  *
325*0Sstevel@tonic-gate  *  10.2  Arguments and notes
326*0Sstevel@tonic-gate  *
327*0Sstevel@tonic-gate  *    The first argument to cyb_restore_level() is a backend cookie as returned
328*0Sstevel@tonic-gate  *    from cyb_configure().  The second argument is a CPU on which the third
329*0Sstevel@tonic-gate  *    argument, a function pointer, should be executed.  The fourth argument,
330*0Sstevel@tonic-gate  *    a void *, should be passed as the argument to the specified function.
331*0Sstevel@tonic-gate  *
332*0Sstevel@tonic-gate  *    cyb_xcall() must provide exactly-once semantics.  If the specified
333*0Sstevel@tonic-gate  *    function is called more than once, or not at all, the cyclic subsystem
334*0Sstevel@tonic-gate  *    will become internally inconsistent.  The specified function must be
335*0Sstevel@tonic-gate  *    be executed on the specified CPU, but may be executed in any context
336*0Sstevel@tonic-gate  *    (any interrupt context or kernel context).
337*0Sstevel@tonic-gate  *
338*0Sstevel@tonic-gate  *    cyb_xcall() cannot block.  Any resources which cyb_xcall() needs to
339*0Sstevel@tonic-gate  *    acquire must thus be protected by synchronization primitives which
340*0Sstevel@tonic-gate  *    never require the caller to block.
341*0Sstevel@tonic-gate  *
342*0Sstevel@tonic-gate  *  10.3  Return value
343*0Sstevel@tonic-gate  *
344*0Sstevel@tonic-gate  *    None.
345*0Sstevel@tonic-gate  *
346*0Sstevel@tonic-gate  *  10.4  Caller's context
347*0Sstevel@tonic-gate  *
348*0Sstevel@tonic-gate  *    cpu_lock will be held and kernel preemption may be disabled.  The caller
349*0Sstevel@tonic-gate  *    may be unable to block, giving rise to the constraint outlined in
350*0Sstevel@tonic-gate  *    10.2, above.
351*0Sstevel@tonic-gate  *
352*0Sstevel@tonic-gate  *  11  cyb_suspend(cyb_arg_t arg)
353*0Sstevel@tonic-gate  *
354*0Sstevel@tonic-gate  *  11.1  Overview
355*0Sstevel@tonic-gate  *
356*0Sstevel@tonic-gate  *    cyb_suspend() should suspend the specified backend.
357*0Sstevel@tonic-gate  *
358*0Sstevel@tonic-gate  *  11.2  Arguments and notes
359*0Sstevel@tonic-gate  *
360*0Sstevel@tonic-gate  *    The only argument to cyb_suspend() is a backend cookie as returned from
361*0Sstevel@tonic-gate  *    cyb_configure().
362*0Sstevel@tonic-gate  *
363*0Sstevel@tonic-gate  *    cyb_suspend() will never be called on enabled backends.  The backend
364*0Sstevel@tonic-gate  *    should assume that the machine may be subsequently powered off; any
365*0Sstevel@tonic-gate  *    volatile hardware state should be preserved and restored in cyb_resume().
366*0Sstevel@tonic-gate  *    However, the backend should not _assume_ that the machine will be
367*0Sstevel@tonic-gate  *    powered off; cyb_suspend() may also be called as part of dynamic
368*0Sstevel@tonic-gate  *    reconfiguration.
369*0Sstevel@tonic-gate  *
370*0Sstevel@tonic-gate  *    cyb_suspend() will be called on the corresponding backend of each
371*0Sstevel@tonic-gate  *    CPU in the system in succession, regardless of CPU state (P_ONLINE,
372*0Sstevel@tonic-gate  *    P_OFFLINE, P_NOINTR).  The cyclic subsystem will not suspend only a
373*0Sstevel@tonic-gate  *    fraction of the CPUs.
374*0Sstevel@tonic-gate  *
375*0Sstevel@tonic-gate  *  11.3  Return value
376*0Sstevel@tonic-gate  *
377*0Sstevel@tonic-gate  *    None.
378*0Sstevel@tonic-gate  *
379*0Sstevel@tonic-gate  *  11.4  Caller's context
380*0Sstevel@tonic-gate  *
381*0Sstevel@tonic-gate  *    cyb_suspend() will be called in cross call context on the CPU associated
382*0Sstevel@tonic-gate  *    with the specified backend.
383*0Sstevel@tonic-gate  *
384*0Sstevel@tonic-gate  *  12  cyb_resume(cyb_arg_t arg)
385*0Sstevel@tonic-gate  *
386*0Sstevel@tonic-gate  *  12.1  Overview
387*0Sstevel@tonic-gate  *
388*0Sstevel@tonic-gate  *    cyb_resume() should resume the specified backend.
389*0Sstevel@tonic-gate  *
390*0Sstevel@tonic-gate  *  12.2  Arguments and notes
391*0Sstevel@tonic-gate  *
392*0Sstevel@tonic-gate  *    The only argument to cyb_resume() is a backend cookie as returned from
393*0Sstevel@tonic-gate  *    cyb_resume().
394*0Sstevel@tonic-gate  *
395*0Sstevel@tonic-gate  *    Calls to cyb_resume() will always have been proceeded by corresponding
396*0Sstevel@tonic-gate  *    calls to cyb_suspend().  The machine may have been powered off between
397*0Sstevel@tonic-gate  *    cyb_suspend() and the call to cyb_resume().  cyb_resume() may decide
398*0Sstevel@tonic-gate  *    to restore hardware to its state at the time cyb_suspend() was called.
399*0Sstevel@tonic-gate  *
400*0Sstevel@tonic-gate  *    The cyclic subsystem will make no calls into the backend between
401*0Sstevel@tonic-gate  *    cyb_suspend() and cyb_resume().
402*0Sstevel@tonic-gate  *
403*0Sstevel@tonic-gate  *  12.3  Return value
404*0Sstevel@tonic-gate  *
405*0Sstevel@tonic-gate  *    None.
406*0Sstevel@tonic-gate  *
407*0Sstevel@tonic-gate  *  12.4  Caller's context
408*0Sstevel@tonic-gate  *
409*0Sstevel@tonic-gate  *    cyb_resume() will be called in cross call context on the CPU associated
410*0Sstevel@tonic-gate  *    with the specified backend.
411*0Sstevel@tonic-gate  */
412*0Sstevel@tonic-gate typedef struct cyc_backend {
413*0Sstevel@tonic-gate 	cyb_arg_t (*cyb_configure)(cpu_t *);
414*0Sstevel@tonic-gate 	void (*cyb_unconfigure)(cyb_arg_t);
415*0Sstevel@tonic-gate 	void (*cyb_enable)(cyb_arg_t);
416*0Sstevel@tonic-gate 	void (*cyb_disable)(cyb_arg_t);
417*0Sstevel@tonic-gate 	void (*cyb_reprogram)(cyb_arg_t, hrtime_t);
418*0Sstevel@tonic-gate 	void (*cyb_softint)(cyb_arg_t, cyc_level_t);
419*0Sstevel@tonic-gate 	cyc_cookie_t (*cyb_set_level)(cyb_arg_t, cyc_level_t);
420*0Sstevel@tonic-gate 	void (*cyb_restore_level)(cyb_arg_t, cyc_cookie_t);
421*0Sstevel@tonic-gate 	void (*cyb_xcall)(cyb_arg_t, cpu_t *, cyc_func_t, void *);
422*0Sstevel@tonic-gate 	void (*cyb_suspend)(cyb_arg_t);
423*0Sstevel@tonic-gate 	void (*cyb_resume)(cyb_arg_t);
424*0Sstevel@tonic-gate 	cyb_arg_t cyb_arg;
425*0Sstevel@tonic-gate } cyc_backend_t;
426*0Sstevel@tonic-gate 
427*0Sstevel@tonic-gate extern void cyclic_init(cyc_backend_t *be, hrtime_t resolution);
428*0Sstevel@tonic-gate extern void cyclic_mp_init();
429*0Sstevel@tonic-gate 
430*0Sstevel@tonic-gate #ifdef DEBUG
431*0Sstevel@tonic-gate #define	CYCLIC_TRACE
432*0Sstevel@tonic-gate #endif
433*0Sstevel@tonic-gate 
434*0Sstevel@tonic-gate typedef enum {
435*0Sstevel@tonic-gate 	CYS_ONLINE,
436*0Sstevel@tonic-gate 	CYS_OFFLINE,
437*0Sstevel@tonic-gate 	CYS_EXPANDING,
438*0Sstevel@tonic-gate 	CYS_REMOVING,
439*0Sstevel@tonic-gate 	CYS_SUSPENDED
440*0Sstevel@tonic-gate } cyc_state_t;
441*0Sstevel@tonic-gate 
442*0Sstevel@tonic-gate #define	CYF_FREE		0x0001
443*0Sstevel@tonic-gate #define	CYF_CPU_BOUND		0x0002
444*0Sstevel@tonic-gate #define	CYF_PART_BOUND		0x0004
445*0Sstevel@tonic-gate 
446*0Sstevel@tonic-gate typedef struct cyclic {
447*0Sstevel@tonic-gate 	hrtime_t cy_expire;
448*0Sstevel@tonic-gate 	hrtime_t cy_interval;
449*0Sstevel@tonic-gate 	void (*cy_handler)(void *);
450*0Sstevel@tonic-gate 	void *cy_arg;
451*0Sstevel@tonic-gate 	uint32_t cy_pend;
452*0Sstevel@tonic-gate 	uint16_t cy_flags;
453*0Sstevel@tonic-gate 	cyc_level_t cy_level;
454*0Sstevel@tonic-gate } cyclic_t;
455*0Sstevel@tonic-gate 
456*0Sstevel@tonic-gate typedef struct cyc_pcbuffer {
457*0Sstevel@tonic-gate 	cyc_index_t *cypc_buf;
458*0Sstevel@tonic-gate 	int cypc_prodndx;
459*0Sstevel@tonic-gate 	int cypc_consndx;
460*0Sstevel@tonic-gate 	int cypc_sizemask;
461*0Sstevel@tonic-gate } cyc_pcbuffer_t;
462*0Sstevel@tonic-gate 
463*0Sstevel@tonic-gate typedef struct cyc_softbuf {
464*0Sstevel@tonic-gate 	uchar_t cys_hard;		/* Can only be zero or one */
465*0Sstevel@tonic-gate 	uchar_t cys_soft;		/* Can only be zero or one */
466*0Sstevel@tonic-gate 	cyc_pcbuffer_t cys_buf[2];
467*0Sstevel@tonic-gate } cyc_softbuf_t;
468*0Sstevel@tonic-gate 
469*0Sstevel@tonic-gate #define	CY_NTRACEREC		512
470*0Sstevel@tonic-gate 
471*0Sstevel@tonic-gate typedef struct cyc_tracerec {
472*0Sstevel@tonic-gate 	hrtime_t cyt_tstamp;
473*0Sstevel@tonic-gate 	char *cyt_why;
474*0Sstevel@tonic-gate 	uint64_t cyt_arg0;
475*0Sstevel@tonic-gate 	uint64_t cyt_arg1;
476*0Sstevel@tonic-gate } cyc_tracerec_t;
477*0Sstevel@tonic-gate 
478*0Sstevel@tonic-gate typedef struct cyc_tracebuf {
479*0Sstevel@tonic-gate 	int cyt_ndx;
480*0Sstevel@tonic-gate 	cyc_tracerec_t cyt_buf[CY_NTRACEREC];
481*0Sstevel@tonic-gate } cyc_tracebuf_t;
482*0Sstevel@tonic-gate 
483*0Sstevel@tonic-gate #define	CY_NCOVERAGE	127
484*0Sstevel@tonic-gate 
485*0Sstevel@tonic-gate typedef struct cyc_coverage {
486*0Sstevel@tonic-gate 	char *cyv_why;
487*0Sstevel@tonic-gate 	int cyv_passive_count;
488*0Sstevel@tonic-gate 	int cyv_count[CY_LEVELS];
489*0Sstevel@tonic-gate 	uint64_t cyv_arg0;
490*0Sstevel@tonic-gate 	uint64_t cyv_arg1;
491*0Sstevel@tonic-gate } cyc_coverage_t;
492*0Sstevel@tonic-gate 
493*0Sstevel@tonic-gate typedef struct cyc_cpu {
494*0Sstevel@tonic-gate 	cpu_t *cyp_cpu;
495*0Sstevel@tonic-gate 	cyc_index_t *cyp_heap;
496*0Sstevel@tonic-gate 	cyclic_t *cyp_cyclics;
497*0Sstevel@tonic-gate 	cyc_index_t cyp_nelems;
498*0Sstevel@tonic-gate 	cyc_index_t cyp_size;
499*0Sstevel@tonic-gate 	cyc_state_t cyp_state;
500*0Sstevel@tonic-gate 	cyc_softbuf_t cyp_softbuf[CY_SOFT_LEVELS];
501*0Sstevel@tonic-gate 	cyc_backend_t *cyp_backend;
502*0Sstevel@tonic-gate 	ksema_t cyp_modify_wait;
503*0Sstevel@tonic-gate 	uint32_t cyp_modify_levels;
504*0Sstevel@tonic-gate 	uint32_t cyp_rpend;
505*0Sstevel@tonic-gate #ifdef CYCLIC_TRACE
506*0Sstevel@tonic-gate 	cyc_tracebuf_t cyp_trace[CY_LEVELS];
507*0Sstevel@tonic-gate #endif
508*0Sstevel@tonic-gate } cyc_cpu_t;
509*0Sstevel@tonic-gate 
510*0Sstevel@tonic-gate typedef struct cyc_omni_cpu {
511*0Sstevel@tonic-gate 	cyc_cpu_t *cyo_cpu;
512*0Sstevel@tonic-gate 	cyc_index_t cyo_ndx;
513*0Sstevel@tonic-gate 	void *cyo_arg;
514*0Sstevel@tonic-gate 	struct cyc_omni_cpu *cyo_next;
515*0Sstevel@tonic-gate } cyc_omni_cpu_t;
516*0Sstevel@tonic-gate 
517*0Sstevel@tonic-gate typedef struct cyc_id {
518*0Sstevel@tonic-gate 	cyc_cpu_t *cyi_cpu;
519*0Sstevel@tonic-gate 	cyc_index_t cyi_ndx;
520*0Sstevel@tonic-gate 	struct cyc_id *cyi_prev;
521*0Sstevel@tonic-gate 	struct cyc_id *cyi_next;
522*0Sstevel@tonic-gate 	cyc_omni_handler_t cyi_omni_hdlr;
523*0Sstevel@tonic-gate 	cyc_omni_cpu_t *cyi_omni_list;
524*0Sstevel@tonic-gate } cyc_id_t;
525*0Sstevel@tonic-gate 
526*0Sstevel@tonic-gate typedef struct cyc_xcallarg {
527*0Sstevel@tonic-gate 	cyc_cpu_t *cyx_cpu;
528*0Sstevel@tonic-gate 	cyc_handler_t *cyx_hdlr;
529*0Sstevel@tonic-gate 	cyc_time_t *cyx_when;
530*0Sstevel@tonic-gate 	cyc_index_t cyx_ndx;
531*0Sstevel@tonic-gate 	cyc_index_t *cyx_heap;
532*0Sstevel@tonic-gate 	cyclic_t *cyx_cyclics;
533*0Sstevel@tonic-gate 	cyc_index_t cyx_size;
534*0Sstevel@tonic-gate 	uint16_t cyx_flags;
535*0Sstevel@tonic-gate 	int cyx_wait;
536*0Sstevel@tonic-gate } cyc_xcallarg_t;
537*0Sstevel@tonic-gate 
538*0Sstevel@tonic-gate #define	CY_DEFAULT_PERCPU	1
539*0Sstevel@tonic-gate #define	CY_PASSIVE_LEVEL	-1
540*0Sstevel@tonic-gate 
541*0Sstevel@tonic-gate #define	CY_WAIT			0
542*0Sstevel@tonic-gate #define	CY_NOWAIT		1
543*0Sstevel@tonic-gate 
544*0Sstevel@tonic-gate #define	CYC_HEAP_PARENT(ndx)		(((ndx) - 1) >> 1)
545*0Sstevel@tonic-gate #define	CYC_HEAP_RIGHT(ndx)		(((ndx) + 1) << 1)
546*0Sstevel@tonic-gate #define	CYC_HEAP_LEFT(ndx)		((((ndx) + 1) << 1) - 1)
547*0Sstevel@tonic-gate 
548*0Sstevel@tonic-gate #ifdef	__cplusplus
549*0Sstevel@tonic-gate }
550*0Sstevel@tonic-gate #endif
551*0Sstevel@tonic-gate 
552*0Sstevel@tonic-gate #endif /* _SYS_CYCLIC_IMPL_H */
553