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