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