xref: /onnv-gate/usr/src/uts/common/sys/cyclic_impl.h (revision 8048:4b8c6e469829)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*8048SMadhavan.Venkataraman@Sun.COM  * Common Development and Distribution License (the "License").
6*8048SMadhavan.Venkataraman@Sun.COM  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*8048SMadhavan.Venkataraman@Sun.COM  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #ifndef _SYS_CYCLIC_IMPL_H
270Sstevel@tonic-gate #define	_SYS_CYCLIC_IMPL_H
280Sstevel@tonic-gate 
290Sstevel@tonic-gate #ifdef	__cplusplus
300Sstevel@tonic-gate extern "C" {
310Sstevel@tonic-gate #endif
320Sstevel@tonic-gate 
330Sstevel@tonic-gate #include <sys/cyclic.h>
34*8048SMadhavan.Venkataraman@Sun.COM #include <sys/rwlock.h>
350Sstevel@tonic-gate 
360Sstevel@tonic-gate /*
370Sstevel@tonic-gate  *  Cyclic Subsystem Backend-supplied Interfaces
380Sstevel@tonic-gate  *  --------------------------------------------
390Sstevel@tonic-gate  *
400Sstevel@tonic-gate  *  0  Background
410Sstevel@tonic-gate  *
420Sstevel@tonic-gate  *    The design, implementation and interfaces of the cyclic subsystem are
430Sstevel@tonic-gate  *    covered in detail in block comments in the implementation.  This
440Sstevel@tonic-gate  *    comment covers the interface from the cyclic subsystem into the cyclic
450Sstevel@tonic-gate  *    backend.  The backend is specified by a structure of function pointers
460Sstevel@tonic-gate  *    defined below.
470Sstevel@tonic-gate  *
480Sstevel@tonic-gate  *  1  Overview
490Sstevel@tonic-gate  *
500Sstevel@tonic-gate  *      cyb_configure()      <-- Configures the backend on the specified CPU
510Sstevel@tonic-gate  *      cyb_unconfigure()    <-- Unconfigures the backend
520Sstevel@tonic-gate  *      cyb_enable()         <-- Enables the CY_HIGH_LEVEL interrupt source
530Sstevel@tonic-gate  *      cyb_disable()        <-- Disables the CY_HIGH_LEVEL interrupt source
540Sstevel@tonic-gate  *      cyb_reprogram()      <-- Reprograms the CY_HIGH_LEVEL interrupt source
550Sstevel@tonic-gate  *      cyb_softint()        <-- Generates a soft interrupt
560Sstevel@tonic-gate  *      cyb_set_level()      <-- Sets the programmable interrupt level
570Sstevel@tonic-gate  *      cyb_restore_level()  <-- Restores the programmable interrupt level
580Sstevel@tonic-gate  *      cyb_xcall()          <-- Cross calls to the specified CPU
590Sstevel@tonic-gate  *      cyb_suspend()        <-- Suspends the backend
600Sstevel@tonic-gate  *      cyb_resume()         <-- Resumes the backend
610Sstevel@tonic-gate  *
620Sstevel@tonic-gate  *  2  cyb_arg_t cyb_configure(cpu_t *)
630Sstevel@tonic-gate  *
640Sstevel@tonic-gate  *  2.1  Overview
650Sstevel@tonic-gate  *
660Sstevel@tonic-gate  *    cyb_configure() should configure the specified CPU for cyclic operation.
670Sstevel@tonic-gate  *
680Sstevel@tonic-gate  *  2.2  Arguments and notes
690Sstevel@tonic-gate  *
700Sstevel@tonic-gate  *    cyb_configure() should initialize any backend-specific per-CPU
710Sstevel@tonic-gate  *    structures for the specified CPU.  cyb_configure() will be called for
720Sstevel@tonic-gate  *    each CPU (including the boot CPU) during boot.  If the platform
730Sstevel@tonic-gate  *    supports dynamic reconfiguration, cyb_configure() will be called for
740Sstevel@tonic-gate  *    new CPUs as they are configured into the system.
750Sstevel@tonic-gate  *
760Sstevel@tonic-gate  *  2.3  Return value
770Sstevel@tonic-gate  *
780Sstevel@tonic-gate  *    cyb_configure() is expected to return a cookie (a cyb_arg_t, which is
790Sstevel@tonic-gate  *    of type void *) which will be used as the first argument for all future
800Sstevel@tonic-gate  *    cyclic calls into the backend on the specified CPU.
810Sstevel@tonic-gate  *
820Sstevel@tonic-gate  *  2.4  Caller's context
830Sstevel@tonic-gate  *
840Sstevel@tonic-gate  *    cpu_lock will be held.  The caller's CPU is unspecified, and may or
850Sstevel@tonic-gate  *    may not be the CPU specified to cyb_configure().
860Sstevel@tonic-gate  *
870Sstevel@tonic-gate  *  3  void cyb_unconfigure(cyb_arg_t arg)
880Sstevel@tonic-gate  *
890Sstevel@tonic-gate  *  3.1  Overview
900Sstevel@tonic-gate  *
910Sstevel@tonic-gate  *    cyb_unconfigure() should unconfigure the specified backend.
920Sstevel@tonic-gate  *
930Sstevel@tonic-gate  *  3.2  Arguments and notes
940Sstevel@tonic-gate  *
950Sstevel@tonic-gate  *    The only argument to cyb_unconfigure() is a cookie as returned from
960Sstevel@tonic-gate  *    cyb_configure().
970Sstevel@tonic-gate  *
980Sstevel@tonic-gate  *    cyb_unconfigure() should free any backend-specific per-CPU structures
990Sstevel@tonic-gate  *    for the specified backend.  cyb_unconfigure() will _only_ be called on
1000Sstevel@tonic-gate  *    platforms which support dynamic reconfiguration.  If the platform does
1010Sstevel@tonic-gate  *    not support dynamic reconfiguration, cyb_unconfigure() may panic.
1020Sstevel@tonic-gate  *
1030Sstevel@tonic-gate  *    After cyb_unconfigure() returns, the backend must not call cyclic_fire()
1040Sstevel@tonic-gate  *    on the corresponding CPU; doing so will result in a bad trap.
1050Sstevel@tonic-gate  *
1060Sstevel@tonic-gate  *  3.3  Return value
1070Sstevel@tonic-gate  *
1080Sstevel@tonic-gate  *    None.
1090Sstevel@tonic-gate  *
1100Sstevel@tonic-gate  *  3.4  Caller's context
1110Sstevel@tonic-gate  *
1120Sstevel@tonic-gate  *    cpu_lock will be held.  The caller's CPU is unspecified, and may or
1130Sstevel@tonic-gate  *    may not be the CPU specified to cyb_unconfigure().  The specified
1140Sstevel@tonic-gate  *    CPU is guaranteed to exist at the time cyb_unconfigure() is called.
1150Sstevel@tonic-gate  *    The cyclic subsystem is guaranteed to be suspended when cyb_unconfigure()
1160Sstevel@tonic-gate  *    is called, and interrupts are guaranteed to be disabled.
1170Sstevel@tonic-gate  *
1180Sstevel@tonic-gate  *  4  void cyb_enable(cyb_arg_t arg)
1190Sstevel@tonic-gate  *
1200Sstevel@tonic-gate  *  4.1  Overview
1210Sstevel@tonic-gate  *
1220Sstevel@tonic-gate  *    cyb_enable() should enable the CY_HIGH_LEVEL interrupt source on
1230Sstevel@tonic-gate  *    the specified backend.
1240Sstevel@tonic-gate  *
1250Sstevel@tonic-gate  *  4.2  Arguments and notes
1260Sstevel@tonic-gate  *
1270Sstevel@tonic-gate  *    The only argument to cyb_enable() is a backend cookie as returned from
1280Sstevel@tonic-gate  *    cyb_configure().
1290Sstevel@tonic-gate  *
1300Sstevel@tonic-gate  *    cyb_enable() will only be called if a) the specified backend has never
1310Sstevel@tonic-gate  *    been enabled or b) the specified backend has been explicitly disabled with
1320Sstevel@tonic-gate  *    cyb_disable().  In either case, cyb_enable() will only be called if
1330Sstevel@tonic-gate  *    the cyclic subsystem wishes to add a cyclic to the CPU corresponding
1340Sstevel@tonic-gate  *    to the specified backend.  cyb_enable() will be called before
1350Sstevel@tonic-gate  *    cyb_reprogram() for a given backend.
1360Sstevel@tonic-gate  *
1370Sstevel@tonic-gate  *    cyclic_fire() should not be called on a CPU which has not had its backend
1380Sstevel@tonic-gate  *    explicitly cyb_enable()'d, but to do so does not constitute fatal error.
1390Sstevel@tonic-gate  *
1400Sstevel@tonic-gate  *  4.3  Return value
1410Sstevel@tonic-gate  *
1420Sstevel@tonic-gate  *    None.
1430Sstevel@tonic-gate  *
1440Sstevel@tonic-gate  *  4.4  Caller's context
1450Sstevel@tonic-gate  *
1460Sstevel@tonic-gate  *    cyb_enable() will only be called from CY_HIGH_LEVEL context on the CPU
1470Sstevel@tonic-gate  *    corresponding to the specified backend.
1480Sstevel@tonic-gate  *
1490Sstevel@tonic-gate  *  5  void cyb_disable(cyb_arg_t arg)
1500Sstevel@tonic-gate  *
1510Sstevel@tonic-gate  *  5.1  Overview
1520Sstevel@tonic-gate  *
1530Sstevel@tonic-gate  *    cyb_disable() should disable the CY_HIGH_LEVEL interrupt source on
1540Sstevel@tonic-gate  *    the specified backend.
1550Sstevel@tonic-gate  *
1560Sstevel@tonic-gate  *  5.2  Arguments and notes
1570Sstevel@tonic-gate  *
1580Sstevel@tonic-gate  *    The only argument to cyb_disable() is a backend cookie as returned from
1590Sstevel@tonic-gate  *    cyb_configure().
1600Sstevel@tonic-gate  *
1610Sstevel@tonic-gate  *    cyb_disable() will only be called on backends which have been previously
1620Sstevel@tonic-gate  *    been cyb_enable()'d.  cyb_disable() will be called when all cyclics have
1630Sstevel@tonic-gate  *    been juggled away or removed from a cyb_enable()'d CPU.
1640Sstevel@tonic-gate  *
1650Sstevel@tonic-gate  *    cyclic_fire() should not be called on a CPU which has had its backend
1660Sstevel@tonic-gate  *    explicitly cyb_disable()'d, but to do so does not constitute fatal
1670Sstevel@tonic-gate  *    error.  cyb_disable() is thus not required to check for a pending
1680Sstevel@tonic-gate  *    CY_HIGH_LEVEL interrupt.
1690Sstevel@tonic-gate  *
1700Sstevel@tonic-gate  *  5.3  Return value
1710Sstevel@tonic-gate  *
1720Sstevel@tonic-gate  *    None.
1730Sstevel@tonic-gate  *
1740Sstevel@tonic-gate  *  5.4  Caller's context
1750Sstevel@tonic-gate  *
1760Sstevel@tonic-gate  *    cyb_disable() will only be called from CY_HIGH_LEVEL context on the CPU
1770Sstevel@tonic-gate  *    corresponding to the specified backend.
1780Sstevel@tonic-gate  *
1790Sstevel@tonic-gate  *  6  void cyb_reprogram(cyb_arg_t arg, hrtime_t time)
1800Sstevel@tonic-gate  *
1810Sstevel@tonic-gate  *  6.1  Overview
1820Sstevel@tonic-gate  *
1830Sstevel@tonic-gate  *    cyb_reprogram() should reprogram the CY_HIGH_LEVEL interrupt source
1840Sstevel@tonic-gate  *    to fire at the absolute time specified.
1850Sstevel@tonic-gate  *
1860Sstevel@tonic-gate  *  6.2  Arguments and notes
1870Sstevel@tonic-gate  *
1880Sstevel@tonic-gate  *    The first argument to cyb_reprogram() is a backend cookie as returned from
1890Sstevel@tonic-gate  *    cyb_configure().
1900Sstevel@tonic-gate  *
1910Sstevel@tonic-gate  *    The second argument is an absolute time at which the CY_HIGH_LEVEL
1920Sstevel@tonic-gate  *    interrupt should fire.  The specified time _may_ be in the past (albeit
1930Sstevel@tonic-gate  *    the very recent past).  If this is the case, the backend should generate
1940Sstevel@tonic-gate  *    a CY_HIGH_LEVEL interrupt as soon as possible.
1950Sstevel@tonic-gate  *
1960Sstevel@tonic-gate  *    The platform should not assume that cyb_reprogram() will be called with
1970Sstevel@tonic-gate  *    monotonically increasing values.
1980Sstevel@tonic-gate  *
1990Sstevel@tonic-gate  *    If the platform does not allow for interrupts at arbitrary times in the
2000Sstevel@tonic-gate  *    future, cyb_reprogram() may do nothing -- as long as cyclic_fire() is
2010Sstevel@tonic-gate  *    called periodically at CY_HIGH_LEVEL.  While this is clearly suboptimal
2020Sstevel@tonic-gate  *    (cyclic granularity will be bounded by the length of the period between
2030Sstevel@tonic-gate  *    cyclic_fire()'s), it allows the cyclic subsystem to be implemented on
2040Sstevel@tonic-gate  *    inferior hardware.
2050Sstevel@tonic-gate  *
2060Sstevel@tonic-gate  *  6.3  Return value
2070Sstevel@tonic-gate  *
2080Sstevel@tonic-gate  *     None.
2090Sstevel@tonic-gate  *
2100Sstevel@tonic-gate  *  6.4  Caller's context
2110Sstevel@tonic-gate  *
2120Sstevel@tonic-gate  *    cyb_reprogram() will only be called from CY_HIGH_LEVEL context on the CPU
2130Sstevel@tonic-gate  *    corresponding to the specified backend.
2140Sstevel@tonic-gate  *
2150Sstevel@tonic-gate  *  7  void cyb_softint(cyb_arg_t arg, cyc_level_t level)
2160Sstevel@tonic-gate  *
2170Sstevel@tonic-gate  *  7.1  Overview
2180Sstevel@tonic-gate  *
2190Sstevel@tonic-gate  *    cyb_softint() should generate a software interrupt on the specified
2200Sstevel@tonic-gate  *    backend at the specified level.
2210Sstevel@tonic-gate  *
2220Sstevel@tonic-gate  *  7.2  Arguments and notes
2230Sstevel@tonic-gate  *
2240Sstevel@tonic-gate  *    The first argument to cyb_softint() is a backend cookie as returned from
2250Sstevel@tonic-gate  *    cyb_configure().  The second argument is the interrupt level at which
2260Sstevel@tonic-gate  *    the software interrupt should be generated; it will be either
2270Sstevel@tonic-gate  *    CY_LOCK_LEVEL or CY_LOW_LEVEL.
2280Sstevel@tonic-gate  *
2290Sstevel@tonic-gate  *    The software interrupt _must_ be generated on the CPU corresponding
2300Sstevel@tonic-gate  *    to the specified backend; platforms are _required_ to have a per-CPU
2310Sstevel@tonic-gate  *    notion of a software interrupt.
2320Sstevel@tonic-gate  *
2330Sstevel@tonic-gate  *    Unless a software interrupt is already pending at the specified level,
2340Sstevel@tonic-gate  *    the software interrupt _must_ be generated.  Once cyclic_softint()
2350Sstevel@tonic-gate  *    has been called at a given level, the software interrupt at that level
2360Sstevel@tonic-gate  *    should no longer be considered pending; an intervening CY_HIGH_LEVEL
2370Sstevel@tonic-gate  *    interrupt and subsequent cyb_softint() must generate another software
2380Sstevel@tonic-gate  *    interrupt.
2390Sstevel@tonic-gate  *
2400Sstevel@tonic-gate  *  7.3  Return value
2410Sstevel@tonic-gate  *
2420Sstevel@tonic-gate  *    None.
2430Sstevel@tonic-gate  *
2440Sstevel@tonic-gate  *  7.4  Caller's context
2450Sstevel@tonic-gate  *
2460Sstevel@tonic-gate  *    cyb_softint() will only be called at a level higher than the one
2470Sstevel@tonic-gate  *    specified:  if CY_LOCK_LEVEL is specified, the caller will be at
2480Sstevel@tonic-gate  *    CY_HIGH_LEVEL; if CY_LOW_LEVEL is specified, the caller will be at
2490Sstevel@tonic-gate  *    either CY_HIGH_LEVEL or CY_LOCK_LEVEL.  cyb_softint() will only be
2500Sstevel@tonic-gate  *    called on the CPU corresponding to the specified backend.
2510Sstevel@tonic-gate  *
2520Sstevel@tonic-gate  *  8  cyb_set_level(cyb_arg_t arg, cyc_level_t level)
2530Sstevel@tonic-gate  *
2540Sstevel@tonic-gate  *  8.1  Overview
2550Sstevel@tonic-gate  *
2560Sstevel@tonic-gate  *    cyb_set_level() should set the programmable interrupt level to the
2570Sstevel@tonic-gate  *    level specified.
2580Sstevel@tonic-gate  *
2590Sstevel@tonic-gate  *  8.2  Arguments and notes
2600Sstevel@tonic-gate  *
2610Sstevel@tonic-gate  *    The first argument to cyb_set_level() is a backend cookie as returned
2620Sstevel@tonic-gate  *    from cyb_configure().  The second argument is the level to which
2630Sstevel@tonic-gate  *    the programmable interrupt level should be set; it will be one of
2640Sstevel@tonic-gate  *    CY_HIGH_LEVEL, CY_LOCK_LEVEL or CY_LOW_LEVEL.
2650Sstevel@tonic-gate  *
2660Sstevel@tonic-gate  *    After cyb_set_level() returns, the CPU associated with the specified
2670Sstevel@tonic-gate  *    backend should accept no interrupt at a level greater than or equal to
2680Sstevel@tonic-gate  *    the specified level.  This will generally be a wrapper around splx().
2690Sstevel@tonic-gate  *
2700Sstevel@tonic-gate  *    The cyclic subsystem will never call cyb_set_level() twice consecutively
2710Sstevel@tonic-gate  *    on the same backend; there will always be an intervening
2720Sstevel@tonic-gate  *    cyb_restore_level();
2730Sstevel@tonic-gate  *
2740Sstevel@tonic-gate  *  8.3  Return value
2750Sstevel@tonic-gate  *
2760Sstevel@tonic-gate  *    cyb_set_level() should return a cookie to be passed back to
2770Sstevel@tonic-gate  *    cyb_restore_level().  On most implementations, this cookie will be
2780Sstevel@tonic-gate  *    the spl at the time of cyb_set_level().
2790Sstevel@tonic-gate  *
2800Sstevel@tonic-gate  *  8.4  Caller's context
2810Sstevel@tonic-gate  *
2820Sstevel@tonic-gate  *    cyb_set_level() is unique in that it is the only backend-provided
2830Sstevel@tonic-gate  *    interface which may be called in cross call context (see cyb_xcall(),
2840Sstevel@tonic-gate  *    below).  cyb_set_level() may also be called from any of the cyclic
2850Sstevel@tonic-gate  *
2860Sstevel@tonic-gate  *  9  cyb_restore_level(cyb_arg_t arg, cyc_cookie_t cookie)
2870Sstevel@tonic-gate  *
2880Sstevel@tonic-gate  *  9.1  Overview
2890Sstevel@tonic-gate  *
2900Sstevel@tonic-gate  *    cyb_restore_level() should restore the programmable interrupt level
2910Sstevel@tonic-gate  *    based upon the specified cookie.
2920Sstevel@tonic-gate  *
2930Sstevel@tonic-gate  *  9.2  Arguments and notes
2940Sstevel@tonic-gate  *
2950Sstevel@tonic-gate  *    The first argument to cyb_restore_level() is a backend cookie as returned
2960Sstevel@tonic-gate  *    from cyb_configure().  The second argument is a cookie as returned from
2970Sstevel@tonic-gate  *    cyb_set_level().
2980Sstevel@tonic-gate  *
2990Sstevel@tonic-gate  *    cyb_restore_level() should restore the programmable interrupt level
3000Sstevel@tonic-gate  *    to its value when cyb_set_level() was called; the cookie is used
3010Sstevel@tonic-gate  *    to provide a hint to the backend.  cyb_restore_level() will not be
3020Sstevel@tonic-gate  *    called without a proceeding call to cyb_set_level(), and
3030Sstevel@tonic-gate  *    cyb_restore_level() will never be called twice consecutively on the
3040Sstevel@tonic-gate  *    same backend.
3050Sstevel@tonic-gate  *
3060Sstevel@tonic-gate  *  9.3  Return value
3070Sstevel@tonic-gate  *
3080Sstevel@tonic-gate  *    None.
3090Sstevel@tonic-gate  *
3100Sstevel@tonic-gate  *  9.4  Caller's context
3110Sstevel@tonic-gate  *
3120Sstevel@tonic-gate  *    The constraints outlined in 5.9.2 imply that cyb_restore_level() can
3130Sstevel@tonic-gate  *    only be called from CY_HIGH_LEVEL, CY_LOCK_LEVEL or CY_LOW_LEVEL context.
3140Sstevel@tonic-gate  *    cyb_restore_level() is always called on the CPU associated with the
3150Sstevel@tonic-gate  *    specified backend.
3160Sstevel@tonic-gate  *
3170Sstevel@tonic-gate  *  10  cyb_xcall(cyb_arg_t arg, cpu_t *, void(*func)(void *), void *farg)
3180Sstevel@tonic-gate  *
3190Sstevel@tonic-gate  *  10.1  Overview
3200Sstevel@tonic-gate  *
3210Sstevel@tonic-gate  *    cyb_xcall() should execute the specified function on the specified CPU.
3220Sstevel@tonic-gate  *
3230Sstevel@tonic-gate  *  10.2  Arguments and notes
3240Sstevel@tonic-gate  *
3250Sstevel@tonic-gate  *    The first argument to cyb_restore_level() is a backend cookie as returned
3260Sstevel@tonic-gate  *    from cyb_configure().  The second argument is a CPU on which the third
3270Sstevel@tonic-gate  *    argument, a function pointer, should be executed.  The fourth argument,
3280Sstevel@tonic-gate  *    a void *, should be passed as the argument to the specified function.
3290Sstevel@tonic-gate  *
3300Sstevel@tonic-gate  *    cyb_xcall() must provide exactly-once semantics.  If the specified
3310Sstevel@tonic-gate  *    function is called more than once, or not at all, the cyclic subsystem
3320Sstevel@tonic-gate  *    will become internally inconsistent.  The specified function must be
3330Sstevel@tonic-gate  *    be executed on the specified CPU, but may be executed in any context
3340Sstevel@tonic-gate  *    (any interrupt context or kernel context).
3350Sstevel@tonic-gate  *
3360Sstevel@tonic-gate  *    cyb_xcall() cannot block.  Any resources which cyb_xcall() needs to
3370Sstevel@tonic-gate  *    acquire must thus be protected by synchronization primitives which
3380Sstevel@tonic-gate  *    never require the caller to block.
3390Sstevel@tonic-gate  *
3400Sstevel@tonic-gate  *  10.3  Return value
3410Sstevel@tonic-gate  *
3420Sstevel@tonic-gate  *    None.
3430Sstevel@tonic-gate  *
3440Sstevel@tonic-gate  *  10.4  Caller's context
3450Sstevel@tonic-gate  *
3460Sstevel@tonic-gate  *    cpu_lock will be held and kernel preemption may be disabled.  The caller
3470Sstevel@tonic-gate  *    may be unable to block, giving rise to the constraint outlined in
3480Sstevel@tonic-gate  *    10.2, above.
3490Sstevel@tonic-gate  *
3500Sstevel@tonic-gate  *  11  cyb_suspend(cyb_arg_t arg)
3510Sstevel@tonic-gate  *
3520Sstevel@tonic-gate  *  11.1  Overview
3530Sstevel@tonic-gate  *
3540Sstevel@tonic-gate  *    cyb_suspend() should suspend the specified backend.
3550Sstevel@tonic-gate  *
3560Sstevel@tonic-gate  *  11.2  Arguments and notes
3570Sstevel@tonic-gate  *
3580Sstevel@tonic-gate  *    The only argument to cyb_suspend() is a backend cookie as returned from
3590Sstevel@tonic-gate  *    cyb_configure().
3600Sstevel@tonic-gate  *
3610Sstevel@tonic-gate  *    cyb_suspend() will never be called on enabled backends.  The backend
3620Sstevel@tonic-gate  *    should assume that the machine may be subsequently powered off; any
3630Sstevel@tonic-gate  *    volatile hardware state should be preserved and restored in cyb_resume().
3640Sstevel@tonic-gate  *    However, the backend should not _assume_ that the machine will be
3650Sstevel@tonic-gate  *    powered off; cyb_suspend() may also be called as part of dynamic
3660Sstevel@tonic-gate  *    reconfiguration.
3670Sstevel@tonic-gate  *
3680Sstevel@tonic-gate  *    cyb_suspend() will be called on the corresponding backend of each
3690Sstevel@tonic-gate  *    CPU in the system in succession, regardless of CPU state (P_ONLINE,
3700Sstevel@tonic-gate  *    P_OFFLINE, P_NOINTR).  The cyclic subsystem will not suspend only a
3710Sstevel@tonic-gate  *    fraction of the CPUs.
3720Sstevel@tonic-gate  *
3730Sstevel@tonic-gate  *  11.3  Return value
3740Sstevel@tonic-gate  *
3750Sstevel@tonic-gate  *    None.
3760Sstevel@tonic-gate  *
3770Sstevel@tonic-gate  *  11.4  Caller's context
3780Sstevel@tonic-gate  *
3790Sstevel@tonic-gate  *    cyb_suspend() will be called in cross call context on the CPU associated
3800Sstevel@tonic-gate  *    with the specified backend.
3810Sstevel@tonic-gate  *
3820Sstevel@tonic-gate  *  12  cyb_resume(cyb_arg_t arg)
3830Sstevel@tonic-gate  *
3840Sstevel@tonic-gate  *  12.1  Overview
3850Sstevel@tonic-gate  *
3860Sstevel@tonic-gate  *    cyb_resume() should resume the specified backend.
3870Sstevel@tonic-gate  *
3880Sstevel@tonic-gate  *  12.2  Arguments and notes
3890Sstevel@tonic-gate  *
3900Sstevel@tonic-gate  *    The only argument to cyb_resume() is a backend cookie as returned from
3910Sstevel@tonic-gate  *    cyb_resume().
3920Sstevel@tonic-gate  *
3930Sstevel@tonic-gate  *    Calls to cyb_resume() will always have been proceeded by corresponding
3940Sstevel@tonic-gate  *    calls to cyb_suspend().  The machine may have been powered off between
3950Sstevel@tonic-gate  *    cyb_suspend() and the call to cyb_resume().  cyb_resume() may decide
3960Sstevel@tonic-gate  *    to restore hardware to its state at the time cyb_suspend() was called.
3970Sstevel@tonic-gate  *
3980Sstevel@tonic-gate  *    The cyclic subsystem will make no calls into the backend between
3990Sstevel@tonic-gate  *    cyb_suspend() and cyb_resume().
4000Sstevel@tonic-gate  *
4010Sstevel@tonic-gate  *  12.3  Return value
4020Sstevel@tonic-gate  *
4030Sstevel@tonic-gate  *    None.
4040Sstevel@tonic-gate  *
4050Sstevel@tonic-gate  *  12.4  Caller's context
4060Sstevel@tonic-gate  *
4070Sstevel@tonic-gate  *    cyb_resume() will be called in cross call context on the CPU associated
4080Sstevel@tonic-gate  *    with the specified backend.
4090Sstevel@tonic-gate  */
4100Sstevel@tonic-gate typedef struct cyc_backend {
4110Sstevel@tonic-gate 	cyb_arg_t (*cyb_configure)(cpu_t *);
4120Sstevel@tonic-gate 	void (*cyb_unconfigure)(cyb_arg_t);
4130Sstevel@tonic-gate 	void (*cyb_enable)(cyb_arg_t);
4140Sstevel@tonic-gate 	void (*cyb_disable)(cyb_arg_t);
4150Sstevel@tonic-gate 	void (*cyb_reprogram)(cyb_arg_t, hrtime_t);
4160Sstevel@tonic-gate 	void (*cyb_softint)(cyb_arg_t, cyc_level_t);
4170Sstevel@tonic-gate 	cyc_cookie_t (*cyb_set_level)(cyb_arg_t, cyc_level_t);
4180Sstevel@tonic-gate 	void (*cyb_restore_level)(cyb_arg_t, cyc_cookie_t);
4190Sstevel@tonic-gate 	void (*cyb_xcall)(cyb_arg_t, cpu_t *, cyc_func_t, void *);
4200Sstevel@tonic-gate 	void (*cyb_suspend)(cyb_arg_t);
4210Sstevel@tonic-gate 	void (*cyb_resume)(cyb_arg_t);
4220Sstevel@tonic-gate 	cyb_arg_t cyb_arg;
4230Sstevel@tonic-gate } cyc_backend_t;
4240Sstevel@tonic-gate 
4250Sstevel@tonic-gate extern void cyclic_init(cyc_backend_t *be, hrtime_t resolution);
4260Sstevel@tonic-gate extern void cyclic_mp_init();
4270Sstevel@tonic-gate 
4280Sstevel@tonic-gate #ifdef DEBUG
4290Sstevel@tonic-gate #define	CYCLIC_TRACE
4300Sstevel@tonic-gate #endif
4310Sstevel@tonic-gate 
4320Sstevel@tonic-gate typedef enum {
4330Sstevel@tonic-gate 	CYS_ONLINE,
4340Sstevel@tonic-gate 	CYS_OFFLINE,
4350Sstevel@tonic-gate 	CYS_EXPANDING,
4360Sstevel@tonic-gate 	CYS_REMOVING,
4370Sstevel@tonic-gate 	CYS_SUSPENDED
4380Sstevel@tonic-gate } cyc_state_t;
4390Sstevel@tonic-gate 
4400Sstevel@tonic-gate #define	CYF_FREE		0x0001
4410Sstevel@tonic-gate #define	CYF_CPU_BOUND		0x0002
4420Sstevel@tonic-gate #define	CYF_PART_BOUND		0x0004
4430Sstevel@tonic-gate 
4440Sstevel@tonic-gate typedef struct cyclic {
4450Sstevel@tonic-gate 	hrtime_t cy_expire;
4460Sstevel@tonic-gate 	hrtime_t cy_interval;
4470Sstevel@tonic-gate 	void (*cy_handler)(void *);
4480Sstevel@tonic-gate 	void *cy_arg;
4490Sstevel@tonic-gate 	uint32_t cy_pend;
4500Sstevel@tonic-gate 	uint16_t cy_flags;
4510Sstevel@tonic-gate 	cyc_level_t cy_level;
4520Sstevel@tonic-gate } cyclic_t;
4530Sstevel@tonic-gate 
4540Sstevel@tonic-gate typedef struct cyc_pcbuffer {
4550Sstevel@tonic-gate 	cyc_index_t *cypc_buf;
4560Sstevel@tonic-gate 	int cypc_prodndx;
4570Sstevel@tonic-gate 	int cypc_consndx;
4580Sstevel@tonic-gate 	int cypc_sizemask;
4590Sstevel@tonic-gate } cyc_pcbuffer_t;
4600Sstevel@tonic-gate 
4610Sstevel@tonic-gate typedef struct cyc_softbuf {
4620Sstevel@tonic-gate 	uchar_t cys_hard;		/* Can only be zero or one */
4630Sstevel@tonic-gate 	uchar_t cys_soft;		/* Can only be zero or one */
4640Sstevel@tonic-gate 	cyc_pcbuffer_t cys_buf[2];
4650Sstevel@tonic-gate } cyc_softbuf_t;
4660Sstevel@tonic-gate 
4670Sstevel@tonic-gate #define	CY_NTRACEREC		512
4680Sstevel@tonic-gate 
4690Sstevel@tonic-gate typedef struct cyc_tracerec {
4700Sstevel@tonic-gate 	hrtime_t cyt_tstamp;
4710Sstevel@tonic-gate 	char *cyt_why;
4720Sstevel@tonic-gate 	uint64_t cyt_arg0;
4730Sstevel@tonic-gate 	uint64_t cyt_arg1;
4740Sstevel@tonic-gate } cyc_tracerec_t;
4750Sstevel@tonic-gate 
4760Sstevel@tonic-gate typedef struct cyc_tracebuf {
4770Sstevel@tonic-gate 	int cyt_ndx;
4780Sstevel@tonic-gate 	cyc_tracerec_t cyt_buf[CY_NTRACEREC];
4790Sstevel@tonic-gate } cyc_tracebuf_t;
4800Sstevel@tonic-gate 
4810Sstevel@tonic-gate #define	CY_NCOVERAGE	127
4820Sstevel@tonic-gate 
4830Sstevel@tonic-gate typedef struct cyc_coverage {
4840Sstevel@tonic-gate 	char *cyv_why;
4850Sstevel@tonic-gate 	int cyv_passive_count;
4860Sstevel@tonic-gate 	int cyv_count[CY_LEVELS];
4870Sstevel@tonic-gate 	uint64_t cyv_arg0;
4880Sstevel@tonic-gate 	uint64_t cyv_arg1;
4890Sstevel@tonic-gate } cyc_coverage_t;
4900Sstevel@tonic-gate 
4910Sstevel@tonic-gate typedef struct cyc_cpu {
4920Sstevel@tonic-gate 	cpu_t *cyp_cpu;
4930Sstevel@tonic-gate 	cyc_index_t *cyp_heap;
4940Sstevel@tonic-gate 	cyclic_t *cyp_cyclics;
4950Sstevel@tonic-gate 	cyc_index_t cyp_nelems;
4960Sstevel@tonic-gate 	cyc_index_t cyp_size;
4970Sstevel@tonic-gate 	cyc_state_t cyp_state;
4980Sstevel@tonic-gate 	cyc_softbuf_t cyp_softbuf[CY_SOFT_LEVELS];
4990Sstevel@tonic-gate 	cyc_backend_t *cyp_backend;
5000Sstevel@tonic-gate 	ksema_t cyp_modify_wait;
5010Sstevel@tonic-gate 	uint32_t cyp_modify_levels;
5020Sstevel@tonic-gate 	uint32_t cyp_rpend;
5030Sstevel@tonic-gate #ifdef CYCLIC_TRACE
5040Sstevel@tonic-gate 	cyc_tracebuf_t cyp_trace[CY_LEVELS];
5050Sstevel@tonic-gate #endif
5060Sstevel@tonic-gate } cyc_cpu_t;
5070Sstevel@tonic-gate 
5080Sstevel@tonic-gate typedef struct cyc_omni_cpu {
5090Sstevel@tonic-gate 	cyc_cpu_t *cyo_cpu;
5100Sstevel@tonic-gate 	cyc_index_t cyo_ndx;
5110Sstevel@tonic-gate 	void *cyo_arg;
5120Sstevel@tonic-gate 	struct cyc_omni_cpu *cyo_next;
5130Sstevel@tonic-gate } cyc_omni_cpu_t;
5140Sstevel@tonic-gate 
5150Sstevel@tonic-gate typedef struct cyc_id {
516*8048SMadhavan.Venkataraman@Sun.COM 	krwlock_t cyi_lock;
5170Sstevel@tonic-gate 	cyc_cpu_t *cyi_cpu;
5180Sstevel@tonic-gate 	cyc_index_t cyi_ndx;
5190Sstevel@tonic-gate 	struct cyc_id *cyi_prev;
5200Sstevel@tonic-gate 	struct cyc_id *cyi_next;
5210Sstevel@tonic-gate 	cyc_omni_handler_t cyi_omni_hdlr;
5220Sstevel@tonic-gate 	cyc_omni_cpu_t *cyi_omni_list;
5230Sstevel@tonic-gate } cyc_id_t;
5240Sstevel@tonic-gate 
5250Sstevel@tonic-gate typedef struct cyc_xcallarg {
5260Sstevel@tonic-gate 	cyc_cpu_t *cyx_cpu;
5270Sstevel@tonic-gate 	cyc_handler_t *cyx_hdlr;
5280Sstevel@tonic-gate 	cyc_time_t *cyx_when;
5290Sstevel@tonic-gate 	cyc_index_t cyx_ndx;
5300Sstevel@tonic-gate 	cyc_index_t *cyx_heap;
5310Sstevel@tonic-gate 	cyclic_t *cyx_cyclics;
5320Sstevel@tonic-gate 	cyc_index_t cyx_size;
5330Sstevel@tonic-gate 	uint16_t cyx_flags;
5340Sstevel@tonic-gate 	int cyx_wait;
5350Sstevel@tonic-gate } cyc_xcallarg_t;
5360Sstevel@tonic-gate 
5370Sstevel@tonic-gate #define	CY_DEFAULT_PERCPU	1
5380Sstevel@tonic-gate #define	CY_PASSIVE_LEVEL	-1
5390Sstevel@tonic-gate 
5400Sstevel@tonic-gate #define	CY_WAIT			0
5410Sstevel@tonic-gate #define	CY_NOWAIT		1
5420Sstevel@tonic-gate 
5430Sstevel@tonic-gate #define	CYC_HEAP_PARENT(ndx)		(((ndx) - 1) >> 1)
5440Sstevel@tonic-gate #define	CYC_HEAP_RIGHT(ndx)		(((ndx) + 1) << 1)
5450Sstevel@tonic-gate #define	CYC_HEAP_LEFT(ndx)		((((ndx) + 1) << 1) - 1)
5460Sstevel@tonic-gate 
5470Sstevel@tonic-gate #ifdef	__cplusplus
5480Sstevel@tonic-gate }
5490Sstevel@tonic-gate #endif
5500Sstevel@tonic-gate 
5510Sstevel@tonic-gate #endif /* _SYS_CYCLIC_IMPL_H */
552