17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*87a18d3fSMadhavan Venkataraman * Common Development and Distribution License (the "License"). 6*87a18d3fSMadhavan Venkataraman * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22*87a18d3fSMadhavan Venkataraman * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #ifndef _SYS_CYCLIC_IMPL_H 277c478bd9Sstevel@tonic-gate #define _SYS_CYCLIC_IMPL_H 287c478bd9Sstevel@tonic-gate 297c478bd9Sstevel@tonic-gate #ifdef __cplusplus 307c478bd9Sstevel@tonic-gate extern "C" { 317c478bd9Sstevel@tonic-gate #endif 327c478bd9Sstevel@tonic-gate 337c478bd9Sstevel@tonic-gate #include <sys/cyclic.h> 34*87a18d3fSMadhavan Venkataraman #include <sys/rwlock.h> 357c478bd9Sstevel@tonic-gate 367c478bd9Sstevel@tonic-gate /* 377c478bd9Sstevel@tonic-gate * Cyclic Subsystem Backend-supplied Interfaces 387c478bd9Sstevel@tonic-gate * -------------------------------------------- 397c478bd9Sstevel@tonic-gate * 407c478bd9Sstevel@tonic-gate * 0 Background 417c478bd9Sstevel@tonic-gate * 427c478bd9Sstevel@tonic-gate * The design, implementation and interfaces of the cyclic subsystem are 437c478bd9Sstevel@tonic-gate * covered in detail in block comments in the implementation. This 447c478bd9Sstevel@tonic-gate * comment covers the interface from the cyclic subsystem into the cyclic 457c478bd9Sstevel@tonic-gate * backend. The backend is specified by a structure of function pointers 467c478bd9Sstevel@tonic-gate * defined below. 477c478bd9Sstevel@tonic-gate * 487c478bd9Sstevel@tonic-gate * 1 Overview 497c478bd9Sstevel@tonic-gate * 507c478bd9Sstevel@tonic-gate * cyb_configure() <-- Configures the backend on the specified CPU 517c478bd9Sstevel@tonic-gate * cyb_unconfigure() <-- Unconfigures the backend 527c478bd9Sstevel@tonic-gate * cyb_enable() <-- Enables the CY_HIGH_LEVEL interrupt source 537c478bd9Sstevel@tonic-gate * cyb_disable() <-- Disables the CY_HIGH_LEVEL interrupt source 547c478bd9Sstevel@tonic-gate * cyb_reprogram() <-- Reprograms the CY_HIGH_LEVEL interrupt source 557c478bd9Sstevel@tonic-gate * cyb_softint() <-- Generates a soft interrupt 567c478bd9Sstevel@tonic-gate * cyb_set_level() <-- Sets the programmable interrupt level 577c478bd9Sstevel@tonic-gate * cyb_restore_level() <-- Restores the programmable interrupt level 587c478bd9Sstevel@tonic-gate * cyb_xcall() <-- Cross calls to the specified CPU 597c478bd9Sstevel@tonic-gate * cyb_suspend() <-- Suspends the backend 607c478bd9Sstevel@tonic-gate * cyb_resume() <-- Resumes the backend 617c478bd9Sstevel@tonic-gate * 627c478bd9Sstevel@tonic-gate * 2 cyb_arg_t cyb_configure(cpu_t *) 637c478bd9Sstevel@tonic-gate * 647c478bd9Sstevel@tonic-gate * 2.1 Overview 657c478bd9Sstevel@tonic-gate * 667c478bd9Sstevel@tonic-gate * cyb_configure() should configure the specified CPU for cyclic operation. 677c478bd9Sstevel@tonic-gate * 687c478bd9Sstevel@tonic-gate * 2.2 Arguments and notes 697c478bd9Sstevel@tonic-gate * 707c478bd9Sstevel@tonic-gate * cyb_configure() should initialize any backend-specific per-CPU 717c478bd9Sstevel@tonic-gate * structures for the specified CPU. cyb_configure() will be called for 727c478bd9Sstevel@tonic-gate * each CPU (including the boot CPU) during boot. If the platform 737c478bd9Sstevel@tonic-gate * supports dynamic reconfiguration, cyb_configure() will be called for 747c478bd9Sstevel@tonic-gate * new CPUs as they are configured into the system. 757c478bd9Sstevel@tonic-gate * 767c478bd9Sstevel@tonic-gate * 2.3 Return value 777c478bd9Sstevel@tonic-gate * 787c478bd9Sstevel@tonic-gate * cyb_configure() is expected to return a cookie (a cyb_arg_t, which is 797c478bd9Sstevel@tonic-gate * of type void *) which will be used as the first argument for all future 807c478bd9Sstevel@tonic-gate * cyclic calls into the backend on the specified CPU. 817c478bd9Sstevel@tonic-gate * 827c478bd9Sstevel@tonic-gate * 2.4 Caller's context 837c478bd9Sstevel@tonic-gate * 847c478bd9Sstevel@tonic-gate * cpu_lock will be held. The caller's CPU is unspecified, and may or 857c478bd9Sstevel@tonic-gate * may not be the CPU specified to cyb_configure(). 867c478bd9Sstevel@tonic-gate * 877c478bd9Sstevel@tonic-gate * 3 void cyb_unconfigure(cyb_arg_t arg) 887c478bd9Sstevel@tonic-gate * 897c478bd9Sstevel@tonic-gate * 3.1 Overview 907c478bd9Sstevel@tonic-gate * 917c478bd9Sstevel@tonic-gate * cyb_unconfigure() should unconfigure the specified backend. 927c478bd9Sstevel@tonic-gate * 937c478bd9Sstevel@tonic-gate * 3.2 Arguments and notes 947c478bd9Sstevel@tonic-gate * 957c478bd9Sstevel@tonic-gate * The only argument to cyb_unconfigure() is a cookie as returned from 967c478bd9Sstevel@tonic-gate * cyb_configure(). 977c478bd9Sstevel@tonic-gate * 987c478bd9Sstevel@tonic-gate * cyb_unconfigure() should free any backend-specific per-CPU structures 997c478bd9Sstevel@tonic-gate * for the specified backend. cyb_unconfigure() will _only_ be called on 1007c478bd9Sstevel@tonic-gate * platforms which support dynamic reconfiguration. If the platform does 1017c478bd9Sstevel@tonic-gate * not support dynamic reconfiguration, cyb_unconfigure() may panic. 1027c478bd9Sstevel@tonic-gate * 1037c478bd9Sstevel@tonic-gate * After cyb_unconfigure() returns, the backend must not call cyclic_fire() 1047c478bd9Sstevel@tonic-gate * on the corresponding CPU; doing so will result in a bad trap. 1057c478bd9Sstevel@tonic-gate * 1067c478bd9Sstevel@tonic-gate * 3.3 Return value 1077c478bd9Sstevel@tonic-gate * 1087c478bd9Sstevel@tonic-gate * None. 1097c478bd9Sstevel@tonic-gate * 1107c478bd9Sstevel@tonic-gate * 3.4 Caller's context 1117c478bd9Sstevel@tonic-gate * 1127c478bd9Sstevel@tonic-gate * cpu_lock will be held. The caller's CPU is unspecified, and may or 1137c478bd9Sstevel@tonic-gate * may not be the CPU specified to cyb_unconfigure(). The specified 1147c478bd9Sstevel@tonic-gate * CPU is guaranteed to exist at the time cyb_unconfigure() is called. 1157c478bd9Sstevel@tonic-gate * The cyclic subsystem is guaranteed to be suspended when cyb_unconfigure() 1167c478bd9Sstevel@tonic-gate * is called, and interrupts are guaranteed to be disabled. 1177c478bd9Sstevel@tonic-gate * 1187c478bd9Sstevel@tonic-gate * 4 void cyb_enable(cyb_arg_t arg) 1197c478bd9Sstevel@tonic-gate * 1207c478bd9Sstevel@tonic-gate * 4.1 Overview 1217c478bd9Sstevel@tonic-gate * 1227c478bd9Sstevel@tonic-gate * cyb_enable() should enable the CY_HIGH_LEVEL interrupt source on 1237c478bd9Sstevel@tonic-gate * the specified backend. 1247c478bd9Sstevel@tonic-gate * 1257c478bd9Sstevel@tonic-gate * 4.2 Arguments and notes 1267c478bd9Sstevel@tonic-gate * 1277c478bd9Sstevel@tonic-gate * The only argument to cyb_enable() is a backend cookie as returned from 1287c478bd9Sstevel@tonic-gate * cyb_configure(). 1297c478bd9Sstevel@tonic-gate * 1307c478bd9Sstevel@tonic-gate * cyb_enable() will only be called if a) the specified backend has never 1317c478bd9Sstevel@tonic-gate * been enabled or b) the specified backend has been explicitly disabled with 1327c478bd9Sstevel@tonic-gate * cyb_disable(). In either case, cyb_enable() will only be called if 1337c478bd9Sstevel@tonic-gate * the cyclic subsystem wishes to add a cyclic to the CPU corresponding 1347c478bd9Sstevel@tonic-gate * to the specified backend. cyb_enable() will be called before 1357c478bd9Sstevel@tonic-gate * cyb_reprogram() for a given backend. 1367c478bd9Sstevel@tonic-gate * 1377c478bd9Sstevel@tonic-gate * cyclic_fire() should not be called on a CPU which has not had its backend 1387c478bd9Sstevel@tonic-gate * explicitly cyb_enable()'d, but to do so does not constitute fatal error. 1397c478bd9Sstevel@tonic-gate * 1407c478bd9Sstevel@tonic-gate * 4.3 Return value 1417c478bd9Sstevel@tonic-gate * 1427c478bd9Sstevel@tonic-gate * None. 1437c478bd9Sstevel@tonic-gate * 1447c478bd9Sstevel@tonic-gate * 4.4 Caller's context 1457c478bd9Sstevel@tonic-gate * 1467c478bd9Sstevel@tonic-gate * cyb_enable() will only be called from CY_HIGH_LEVEL context on the CPU 1477c478bd9Sstevel@tonic-gate * corresponding to the specified backend. 1487c478bd9Sstevel@tonic-gate * 1497c478bd9Sstevel@tonic-gate * 5 void cyb_disable(cyb_arg_t arg) 1507c478bd9Sstevel@tonic-gate * 1517c478bd9Sstevel@tonic-gate * 5.1 Overview 1527c478bd9Sstevel@tonic-gate * 1537c478bd9Sstevel@tonic-gate * cyb_disable() should disable the CY_HIGH_LEVEL interrupt source on 1547c478bd9Sstevel@tonic-gate * the specified backend. 1557c478bd9Sstevel@tonic-gate * 1567c478bd9Sstevel@tonic-gate * 5.2 Arguments and notes 1577c478bd9Sstevel@tonic-gate * 1587c478bd9Sstevel@tonic-gate * The only argument to cyb_disable() is a backend cookie as returned from 1597c478bd9Sstevel@tonic-gate * cyb_configure(). 1607c478bd9Sstevel@tonic-gate * 1617c478bd9Sstevel@tonic-gate * cyb_disable() will only be called on backends which have been previously 1627c478bd9Sstevel@tonic-gate * been cyb_enable()'d. cyb_disable() will be called when all cyclics have 1637c478bd9Sstevel@tonic-gate * been juggled away or removed from a cyb_enable()'d CPU. 1647c478bd9Sstevel@tonic-gate * 1657c478bd9Sstevel@tonic-gate * cyclic_fire() should not be called on a CPU which has had its backend 1667c478bd9Sstevel@tonic-gate * explicitly cyb_disable()'d, but to do so does not constitute fatal 1677c478bd9Sstevel@tonic-gate * error. cyb_disable() is thus not required to check for a pending 1687c478bd9Sstevel@tonic-gate * CY_HIGH_LEVEL interrupt. 1697c478bd9Sstevel@tonic-gate * 1707c478bd9Sstevel@tonic-gate * 5.3 Return value 1717c478bd9Sstevel@tonic-gate * 1727c478bd9Sstevel@tonic-gate * None. 1737c478bd9Sstevel@tonic-gate * 1747c478bd9Sstevel@tonic-gate * 5.4 Caller's context 1757c478bd9Sstevel@tonic-gate * 1767c478bd9Sstevel@tonic-gate * cyb_disable() will only be called from CY_HIGH_LEVEL context on the CPU 1777c478bd9Sstevel@tonic-gate * corresponding to the specified backend. 1787c478bd9Sstevel@tonic-gate * 1797c478bd9Sstevel@tonic-gate * 6 void cyb_reprogram(cyb_arg_t arg, hrtime_t time) 1807c478bd9Sstevel@tonic-gate * 1817c478bd9Sstevel@tonic-gate * 6.1 Overview 1827c478bd9Sstevel@tonic-gate * 1837c478bd9Sstevel@tonic-gate * cyb_reprogram() should reprogram the CY_HIGH_LEVEL interrupt source 1847c478bd9Sstevel@tonic-gate * to fire at the absolute time specified. 1857c478bd9Sstevel@tonic-gate * 1867c478bd9Sstevel@tonic-gate * 6.2 Arguments and notes 1877c478bd9Sstevel@tonic-gate * 1887c478bd9Sstevel@tonic-gate * The first argument to cyb_reprogram() is a backend cookie as returned from 1897c478bd9Sstevel@tonic-gate * cyb_configure(). 1907c478bd9Sstevel@tonic-gate * 1917c478bd9Sstevel@tonic-gate * The second argument is an absolute time at which the CY_HIGH_LEVEL 1927c478bd9Sstevel@tonic-gate * interrupt should fire. The specified time _may_ be in the past (albeit 1937c478bd9Sstevel@tonic-gate * the very recent past). If this is the case, the backend should generate 1947c478bd9Sstevel@tonic-gate * a CY_HIGH_LEVEL interrupt as soon as possible. 1957c478bd9Sstevel@tonic-gate * 1967c478bd9Sstevel@tonic-gate * The platform should not assume that cyb_reprogram() will be called with 1977c478bd9Sstevel@tonic-gate * monotonically increasing values. 1987c478bd9Sstevel@tonic-gate * 1997c478bd9Sstevel@tonic-gate * If the platform does not allow for interrupts at arbitrary times in the 2007c478bd9Sstevel@tonic-gate * future, cyb_reprogram() may do nothing -- as long as cyclic_fire() is 2017c478bd9Sstevel@tonic-gate * called periodically at CY_HIGH_LEVEL. While this is clearly suboptimal 2027c478bd9Sstevel@tonic-gate * (cyclic granularity will be bounded by the length of the period between 2037c478bd9Sstevel@tonic-gate * cyclic_fire()'s), it allows the cyclic subsystem to be implemented on 2047c478bd9Sstevel@tonic-gate * inferior hardware. 2057c478bd9Sstevel@tonic-gate * 2067c478bd9Sstevel@tonic-gate * 6.3 Return value 2077c478bd9Sstevel@tonic-gate * 2087c478bd9Sstevel@tonic-gate * None. 2097c478bd9Sstevel@tonic-gate * 2107c478bd9Sstevel@tonic-gate * 6.4 Caller's context 2117c478bd9Sstevel@tonic-gate * 2127c478bd9Sstevel@tonic-gate * cyb_reprogram() will only be called from CY_HIGH_LEVEL context on the CPU 2137c478bd9Sstevel@tonic-gate * corresponding to the specified backend. 2147c478bd9Sstevel@tonic-gate * 2157c478bd9Sstevel@tonic-gate * 7 void cyb_softint(cyb_arg_t arg, cyc_level_t level) 2167c478bd9Sstevel@tonic-gate * 2177c478bd9Sstevel@tonic-gate * 7.1 Overview 2187c478bd9Sstevel@tonic-gate * 2197c478bd9Sstevel@tonic-gate * cyb_softint() should generate a software interrupt on the specified 2207c478bd9Sstevel@tonic-gate * backend at the specified level. 2217c478bd9Sstevel@tonic-gate * 2227c478bd9Sstevel@tonic-gate * 7.2 Arguments and notes 2237c478bd9Sstevel@tonic-gate * 2247c478bd9Sstevel@tonic-gate * The first argument to cyb_softint() is a backend cookie as returned from 2257c478bd9Sstevel@tonic-gate * cyb_configure(). The second argument is the interrupt level at which 2267c478bd9Sstevel@tonic-gate * the software interrupt should be generated; it will be either 2277c478bd9Sstevel@tonic-gate * CY_LOCK_LEVEL or CY_LOW_LEVEL. 2287c478bd9Sstevel@tonic-gate * 2297c478bd9Sstevel@tonic-gate * The software interrupt _must_ be generated on the CPU corresponding 2307c478bd9Sstevel@tonic-gate * to the specified backend; platforms are _required_ to have a per-CPU 2317c478bd9Sstevel@tonic-gate * notion of a software interrupt. 2327c478bd9Sstevel@tonic-gate * 2337c478bd9Sstevel@tonic-gate * Unless a software interrupt is already pending at the specified level, 2347c478bd9Sstevel@tonic-gate * the software interrupt _must_ be generated. Once cyclic_softint() 2357c478bd9Sstevel@tonic-gate * has been called at a given level, the software interrupt at that level 2367c478bd9Sstevel@tonic-gate * should no longer be considered pending; an intervening CY_HIGH_LEVEL 2377c478bd9Sstevel@tonic-gate * interrupt and subsequent cyb_softint() must generate another software 2387c478bd9Sstevel@tonic-gate * interrupt. 2397c478bd9Sstevel@tonic-gate * 2407c478bd9Sstevel@tonic-gate * 7.3 Return value 2417c478bd9Sstevel@tonic-gate * 2427c478bd9Sstevel@tonic-gate * None. 2437c478bd9Sstevel@tonic-gate * 2447c478bd9Sstevel@tonic-gate * 7.4 Caller's context 2457c478bd9Sstevel@tonic-gate * 2467c478bd9Sstevel@tonic-gate * cyb_softint() will only be called at a level higher than the one 2477c478bd9Sstevel@tonic-gate * specified: if CY_LOCK_LEVEL is specified, the caller will be at 2487c478bd9Sstevel@tonic-gate * CY_HIGH_LEVEL; if CY_LOW_LEVEL is specified, the caller will be at 2497c478bd9Sstevel@tonic-gate * either CY_HIGH_LEVEL or CY_LOCK_LEVEL. cyb_softint() will only be 2507c478bd9Sstevel@tonic-gate * called on the CPU corresponding to the specified backend. 2517c478bd9Sstevel@tonic-gate * 2527c478bd9Sstevel@tonic-gate * 8 cyb_set_level(cyb_arg_t arg, cyc_level_t level) 2537c478bd9Sstevel@tonic-gate * 2547c478bd9Sstevel@tonic-gate * 8.1 Overview 2557c478bd9Sstevel@tonic-gate * 2567c478bd9Sstevel@tonic-gate * cyb_set_level() should set the programmable interrupt level to the 2577c478bd9Sstevel@tonic-gate * level specified. 2587c478bd9Sstevel@tonic-gate * 2597c478bd9Sstevel@tonic-gate * 8.2 Arguments and notes 2607c478bd9Sstevel@tonic-gate * 2617c478bd9Sstevel@tonic-gate * The first argument to cyb_set_level() is a backend cookie as returned 2627c478bd9Sstevel@tonic-gate * from cyb_configure(). The second argument is the level to which 2637c478bd9Sstevel@tonic-gate * the programmable interrupt level should be set; it will be one of 2647c478bd9Sstevel@tonic-gate * CY_HIGH_LEVEL, CY_LOCK_LEVEL or CY_LOW_LEVEL. 2657c478bd9Sstevel@tonic-gate * 2667c478bd9Sstevel@tonic-gate * After cyb_set_level() returns, the CPU associated with the specified 2677c478bd9Sstevel@tonic-gate * backend should accept no interrupt at a level greater than or equal to 2687c478bd9Sstevel@tonic-gate * the specified level. This will generally be a wrapper around splx(). 2697c478bd9Sstevel@tonic-gate * 2707c478bd9Sstevel@tonic-gate * The cyclic subsystem will never call cyb_set_level() twice consecutively 2717c478bd9Sstevel@tonic-gate * on the same backend; there will always be an intervening 2727c478bd9Sstevel@tonic-gate * cyb_restore_level(); 2737c478bd9Sstevel@tonic-gate * 2747c478bd9Sstevel@tonic-gate * 8.3 Return value 2757c478bd9Sstevel@tonic-gate * 2767c478bd9Sstevel@tonic-gate * cyb_set_level() should return a cookie to be passed back to 2777c478bd9Sstevel@tonic-gate * cyb_restore_level(). On most implementations, this cookie will be 2787c478bd9Sstevel@tonic-gate * the spl at the time of cyb_set_level(). 2797c478bd9Sstevel@tonic-gate * 2807c478bd9Sstevel@tonic-gate * 8.4 Caller's context 2817c478bd9Sstevel@tonic-gate * 2827c478bd9Sstevel@tonic-gate * cyb_set_level() is unique in that it is the only backend-provided 2837c478bd9Sstevel@tonic-gate * interface which may be called in cross call context (see cyb_xcall(), 2847c478bd9Sstevel@tonic-gate * below). cyb_set_level() may also be called from any of the cyclic 2857c478bd9Sstevel@tonic-gate * 2867c478bd9Sstevel@tonic-gate * 9 cyb_restore_level(cyb_arg_t arg, cyc_cookie_t cookie) 2877c478bd9Sstevel@tonic-gate * 2887c478bd9Sstevel@tonic-gate * 9.1 Overview 2897c478bd9Sstevel@tonic-gate * 2907c478bd9Sstevel@tonic-gate * cyb_restore_level() should restore the programmable interrupt level 2917c478bd9Sstevel@tonic-gate * based upon the specified cookie. 2927c478bd9Sstevel@tonic-gate * 2937c478bd9Sstevel@tonic-gate * 9.2 Arguments and notes 2947c478bd9Sstevel@tonic-gate * 2957c478bd9Sstevel@tonic-gate * The first argument to cyb_restore_level() is a backend cookie as returned 2967c478bd9Sstevel@tonic-gate * from cyb_configure(). The second argument is a cookie as returned from 2977c478bd9Sstevel@tonic-gate * cyb_set_level(). 2987c478bd9Sstevel@tonic-gate * 2997c478bd9Sstevel@tonic-gate * cyb_restore_level() should restore the programmable interrupt level 3007c478bd9Sstevel@tonic-gate * to its value when cyb_set_level() was called; the cookie is used 3017c478bd9Sstevel@tonic-gate * to provide a hint to the backend. cyb_restore_level() will not be 3027c478bd9Sstevel@tonic-gate * called without a proceeding call to cyb_set_level(), and 3037c478bd9Sstevel@tonic-gate * cyb_restore_level() will never be called twice consecutively on the 3047c478bd9Sstevel@tonic-gate * same backend. 3057c478bd9Sstevel@tonic-gate * 3067c478bd9Sstevel@tonic-gate * 9.3 Return value 3077c478bd9Sstevel@tonic-gate * 3087c478bd9Sstevel@tonic-gate * None. 3097c478bd9Sstevel@tonic-gate * 3107c478bd9Sstevel@tonic-gate * 9.4 Caller's context 3117c478bd9Sstevel@tonic-gate * 3127c478bd9Sstevel@tonic-gate * The constraints outlined in 5.9.2 imply that cyb_restore_level() can 3137c478bd9Sstevel@tonic-gate * only be called from CY_HIGH_LEVEL, CY_LOCK_LEVEL or CY_LOW_LEVEL context. 3147c478bd9Sstevel@tonic-gate * cyb_restore_level() is always called on the CPU associated with the 3157c478bd9Sstevel@tonic-gate * specified backend. 3167c478bd9Sstevel@tonic-gate * 3177c478bd9Sstevel@tonic-gate * 10 cyb_xcall(cyb_arg_t arg, cpu_t *, void(*func)(void *), void *farg) 3187c478bd9Sstevel@tonic-gate * 3197c478bd9Sstevel@tonic-gate * 10.1 Overview 3207c478bd9Sstevel@tonic-gate * 3217c478bd9Sstevel@tonic-gate * cyb_xcall() should execute the specified function on the specified CPU. 3227c478bd9Sstevel@tonic-gate * 3237c478bd9Sstevel@tonic-gate * 10.2 Arguments and notes 3247c478bd9Sstevel@tonic-gate * 3257c478bd9Sstevel@tonic-gate * The first argument to cyb_restore_level() is a backend cookie as returned 3267c478bd9Sstevel@tonic-gate * from cyb_configure(). The second argument is a CPU on which the third 3277c478bd9Sstevel@tonic-gate * argument, a function pointer, should be executed. The fourth argument, 3287c478bd9Sstevel@tonic-gate * a void *, should be passed as the argument to the specified function. 3297c478bd9Sstevel@tonic-gate * 3307c478bd9Sstevel@tonic-gate * cyb_xcall() must provide exactly-once semantics. If the specified 3317c478bd9Sstevel@tonic-gate * function is called more than once, or not at all, the cyclic subsystem 3327c478bd9Sstevel@tonic-gate * will become internally inconsistent. The specified function must be 3337c478bd9Sstevel@tonic-gate * be executed on the specified CPU, but may be executed in any context 3347c478bd9Sstevel@tonic-gate * (any interrupt context or kernel context). 3357c478bd9Sstevel@tonic-gate * 3367c478bd9Sstevel@tonic-gate * cyb_xcall() cannot block. Any resources which cyb_xcall() needs to 3377c478bd9Sstevel@tonic-gate * acquire must thus be protected by synchronization primitives which 3387c478bd9Sstevel@tonic-gate * never require the caller to block. 3397c478bd9Sstevel@tonic-gate * 3407c478bd9Sstevel@tonic-gate * 10.3 Return value 3417c478bd9Sstevel@tonic-gate * 3427c478bd9Sstevel@tonic-gate * None. 3437c478bd9Sstevel@tonic-gate * 3447c478bd9Sstevel@tonic-gate * 10.4 Caller's context 3457c478bd9Sstevel@tonic-gate * 3467c478bd9Sstevel@tonic-gate * cpu_lock will be held and kernel preemption may be disabled. The caller 3477c478bd9Sstevel@tonic-gate * may be unable to block, giving rise to the constraint outlined in 3487c478bd9Sstevel@tonic-gate * 10.2, above. 3497c478bd9Sstevel@tonic-gate * 3507c478bd9Sstevel@tonic-gate * 11 cyb_suspend(cyb_arg_t arg) 3517c478bd9Sstevel@tonic-gate * 3527c478bd9Sstevel@tonic-gate * 11.1 Overview 3537c478bd9Sstevel@tonic-gate * 3547c478bd9Sstevel@tonic-gate * cyb_suspend() should suspend the specified backend. 3557c478bd9Sstevel@tonic-gate * 3567c478bd9Sstevel@tonic-gate * 11.2 Arguments and notes 3577c478bd9Sstevel@tonic-gate * 3587c478bd9Sstevel@tonic-gate * The only argument to cyb_suspend() is a backend cookie as returned from 3597c478bd9Sstevel@tonic-gate * cyb_configure(). 3607c478bd9Sstevel@tonic-gate * 3617c478bd9Sstevel@tonic-gate * cyb_suspend() will never be called on enabled backends. The backend 3627c478bd9Sstevel@tonic-gate * should assume that the machine may be subsequently powered off; any 3637c478bd9Sstevel@tonic-gate * volatile hardware state should be preserved and restored in cyb_resume(). 3647c478bd9Sstevel@tonic-gate * However, the backend should not _assume_ that the machine will be 3657c478bd9Sstevel@tonic-gate * powered off; cyb_suspend() may also be called as part of dynamic 3667c478bd9Sstevel@tonic-gate * reconfiguration. 3677c478bd9Sstevel@tonic-gate * 3687c478bd9Sstevel@tonic-gate * cyb_suspend() will be called on the corresponding backend of each 3697c478bd9Sstevel@tonic-gate * CPU in the system in succession, regardless of CPU state (P_ONLINE, 3707c478bd9Sstevel@tonic-gate * P_OFFLINE, P_NOINTR). The cyclic subsystem will not suspend only a 3717c478bd9Sstevel@tonic-gate * fraction of the CPUs. 3727c478bd9Sstevel@tonic-gate * 3737c478bd9Sstevel@tonic-gate * 11.3 Return value 3747c478bd9Sstevel@tonic-gate * 3757c478bd9Sstevel@tonic-gate * None. 3767c478bd9Sstevel@tonic-gate * 3777c478bd9Sstevel@tonic-gate * 11.4 Caller's context 3787c478bd9Sstevel@tonic-gate * 3797c478bd9Sstevel@tonic-gate * cyb_suspend() will be called in cross call context on the CPU associated 3807c478bd9Sstevel@tonic-gate * with the specified backend. 3817c478bd9Sstevel@tonic-gate * 3827c478bd9Sstevel@tonic-gate * 12 cyb_resume(cyb_arg_t arg) 3837c478bd9Sstevel@tonic-gate * 3847c478bd9Sstevel@tonic-gate * 12.1 Overview 3857c478bd9Sstevel@tonic-gate * 3867c478bd9Sstevel@tonic-gate * cyb_resume() should resume the specified backend. 3877c478bd9Sstevel@tonic-gate * 3887c478bd9Sstevel@tonic-gate * 12.2 Arguments and notes 3897c478bd9Sstevel@tonic-gate * 3907c478bd9Sstevel@tonic-gate * The only argument to cyb_resume() is a backend cookie as returned from 3917c478bd9Sstevel@tonic-gate * cyb_resume(). 3927c478bd9Sstevel@tonic-gate * 3937c478bd9Sstevel@tonic-gate * Calls to cyb_resume() will always have been proceeded by corresponding 3947c478bd9Sstevel@tonic-gate * calls to cyb_suspend(). The machine may have been powered off between 3957c478bd9Sstevel@tonic-gate * cyb_suspend() and the call to cyb_resume(). cyb_resume() may decide 3967c478bd9Sstevel@tonic-gate * to restore hardware to its state at the time cyb_suspend() was called. 3977c478bd9Sstevel@tonic-gate * 3987c478bd9Sstevel@tonic-gate * The cyclic subsystem will make no calls into the backend between 3997c478bd9Sstevel@tonic-gate * cyb_suspend() and cyb_resume(). 4007c478bd9Sstevel@tonic-gate * 4017c478bd9Sstevel@tonic-gate * 12.3 Return value 4027c478bd9Sstevel@tonic-gate * 4037c478bd9Sstevel@tonic-gate * None. 4047c478bd9Sstevel@tonic-gate * 4057c478bd9Sstevel@tonic-gate * 12.4 Caller's context 4067c478bd9Sstevel@tonic-gate * 4077c478bd9Sstevel@tonic-gate * cyb_resume() will be called in cross call context on the CPU associated 4087c478bd9Sstevel@tonic-gate * with the specified backend. 4097c478bd9Sstevel@tonic-gate */ 4107c478bd9Sstevel@tonic-gate typedef struct cyc_backend { 4117c478bd9Sstevel@tonic-gate cyb_arg_t (*cyb_configure)(cpu_t *); 4127c478bd9Sstevel@tonic-gate void (*cyb_unconfigure)(cyb_arg_t); 4137c478bd9Sstevel@tonic-gate void (*cyb_enable)(cyb_arg_t); 4147c478bd9Sstevel@tonic-gate void (*cyb_disable)(cyb_arg_t); 4157c478bd9Sstevel@tonic-gate void (*cyb_reprogram)(cyb_arg_t, hrtime_t); 4167c478bd9Sstevel@tonic-gate void (*cyb_softint)(cyb_arg_t, cyc_level_t); 4177c478bd9Sstevel@tonic-gate cyc_cookie_t (*cyb_set_level)(cyb_arg_t, cyc_level_t); 4187c478bd9Sstevel@tonic-gate void (*cyb_restore_level)(cyb_arg_t, cyc_cookie_t); 4197c478bd9Sstevel@tonic-gate void (*cyb_xcall)(cyb_arg_t, cpu_t *, cyc_func_t, void *); 4207c478bd9Sstevel@tonic-gate void (*cyb_suspend)(cyb_arg_t); 4217c478bd9Sstevel@tonic-gate void (*cyb_resume)(cyb_arg_t); 4227c478bd9Sstevel@tonic-gate cyb_arg_t cyb_arg; 4237c478bd9Sstevel@tonic-gate } cyc_backend_t; 4247c478bd9Sstevel@tonic-gate 4257c478bd9Sstevel@tonic-gate extern void cyclic_init(cyc_backend_t *be, hrtime_t resolution); 4267c478bd9Sstevel@tonic-gate extern void cyclic_mp_init(); 4277c478bd9Sstevel@tonic-gate 4287c478bd9Sstevel@tonic-gate #ifdef DEBUG 4297c478bd9Sstevel@tonic-gate #define CYCLIC_TRACE 4307c478bd9Sstevel@tonic-gate #endif 4317c478bd9Sstevel@tonic-gate 4327c478bd9Sstevel@tonic-gate typedef enum { 4337c478bd9Sstevel@tonic-gate CYS_ONLINE, 4347c478bd9Sstevel@tonic-gate CYS_OFFLINE, 4357c478bd9Sstevel@tonic-gate CYS_EXPANDING, 4367c478bd9Sstevel@tonic-gate CYS_REMOVING, 4377c478bd9Sstevel@tonic-gate CYS_SUSPENDED 4387c478bd9Sstevel@tonic-gate } cyc_state_t; 4397c478bd9Sstevel@tonic-gate 4407c478bd9Sstevel@tonic-gate #define CYF_FREE 0x0001 4417c478bd9Sstevel@tonic-gate #define CYF_CPU_BOUND 0x0002 4427c478bd9Sstevel@tonic-gate #define CYF_PART_BOUND 0x0004 4437c478bd9Sstevel@tonic-gate 4447c478bd9Sstevel@tonic-gate typedef struct cyclic { 4457c478bd9Sstevel@tonic-gate hrtime_t cy_expire; 4467c478bd9Sstevel@tonic-gate hrtime_t cy_interval; 4477c478bd9Sstevel@tonic-gate void (*cy_handler)(void *); 4487c478bd9Sstevel@tonic-gate void *cy_arg; 4497c478bd9Sstevel@tonic-gate uint32_t cy_pend; 4507c478bd9Sstevel@tonic-gate uint16_t cy_flags; 4517c478bd9Sstevel@tonic-gate cyc_level_t cy_level; 4527c478bd9Sstevel@tonic-gate } cyclic_t; 4537c478bd9Sstevel@tonic-gate 4547c478bd9Sstevel@tonic-gate typedef struct cyc_pcbuffer { 4557c478bd9Sstevel@tonic-gate cyc_index_t *cypc_buf; 4567c478bd9Sstevel@tonic-gate int cypc_prodndx; 4577c478bd9Sstevel@tonic-gate int cypc_consndx; 4587c478bd9Sstevel@tonic-gate int cypc_sizemask; 4597c478bd9Sstevel@tonic-gate } cyc_pcbuffer_t; 4607c478bd9Sstevel@tonic-gate 4617c478bd9Sstevel@tonic-gate typedef struct cyc_softbuf { 4627c478bd9Sstevel@tonic-gate uchar_t cys_hard; /* Can only be zero or one */ 4637c478bd9Sstevel@tonic-gate uchar_t cys_soft; /* Can only be zero or one */ 4647c478bd9Sstevel@tonic-gate cyc_pcbuffer_t cys_buf[2]; 4657c478bd9Sstevel@tonic-gate } cyc_softbuf_t; 4667c478bd9Sstevel@tonic-gate 4677c478bd9Sstevel@tonic-gate #define CY_NTRACEREC 512 4687c478bd9Sstevel@tonic-gate 4697c478bd9Sstevel@tonic-gate typedef struct cyc_tracerec { 4707c478bd9Sstevel@tonic-gate hrtime_t cyt_tstamp; 4717c478bd9Sstevel@tonic-gate char *cyt_why; 4727c478bd9Sstevel@tonic-gate uint64_t cyt_arg0; 4737c478bd9Sstevel@tonic-gate uint64_t cyt_arg1; 4747c478bd9Sstevel@tonic-gate } cyc_tracerec_t; 4757c478bd9Sstevel@tonic-gate 4767c478bd9Sstevel@tonic-gate typedef struct cyc_tracebuf { 4777c478bd9Sstevel@tonic-gate int cyt_ndx; 4787c478bd9Sstevel@tonic-gate cyc_tracerec_t cyt_buf[CY_NTRACEREC]; 4797c478bd9Sstevel@tonic-gate } cyc_tracebuf_t; 4807c478bd9Sstevel@tonic-gate 4817c478bd9Sstevel@tonic-gate #define CY_NCOVERAGE 127 4827c478bd9Sstevel@tonic-gate 4837c478bd9Sstevel@tonic-gate typedef struct cyc_coverage { 4847c478bd9Sstevel@tonic-gate char *cyv_why; 4857c478bd9Sstevel@tonic-gate int cyv_passive_count; 4867c478bd9Sstevel@tonic-gate int cyv_count[CY_LEVELS]; 4877c478bd9Sstevel@tonic-gate uint64_t cyv_arg0; 4887c478bd9Sstevel@tonic-gate uint64_t cyv_arg1; 4897c478bd9Sstevel@tonic-gate } cyc_coverage_t; 4907c478bd9Sstevel@tonic-gate 4917c478bd9Sstevel@tonic-gate typedef struct cyc_cpu { 4927c478bd9Sstevel@tonic-gate cpu_t *cyp_cpu; 4937c478bd9Sstevel@tonic-gate cyc_index_t *cyp_heap; 4947c478bd9Sstevel@tonic-gate cyclic_t *cyp_cyclics; 4957c478bd9Sstevel@tonic-gate cyc_index_t cyp_nelems; 4967c478bd9Sstevel@tonic-gate cyc_index_t cyp_size; 4977c478bd9Sstevel@tonic-gate cyc_state_t cyp_state; 4987c478bd9Sstevel@tonic-gate cyc_softbuf_t cyp_softbuf[CY_SOFT_LEVELS]; 4997c478bd9Sstevel@tonic-gate cyc_backend_t *cyp_backend; 5007c478bd9Sstevel@tonic-gate ksema_t cyp_modify_wait; 5017c478bd9Sstevel@tonic-gate uint32_t cyp_modify_levels; 5027c478bd9Sstevel@tonic-gate uint32_t cyp_rpend; 5037c478bd9Sstevel@tonic-gate #ifdef CYCLIC_TRACE 5047c478bd9Sstevel@tonic-gate cyc_tracebuf_t cyp_trace[CY_LEVELS]; 5057c478bd9Sstevel@tonic-gate #endif 5067c478bd9Sstevel@tonic-gate } cyc_cpu_t; 5077c478bd9Sstevel@tonic-gate 5087c478bd9Sstevel@tonic-gate typedef struct cyc_omni_cpu { 5097c478bd9Sstevel@tonic-gate cyc_cpu_t *cyo_cpu; 5107c478bd9Sstevel@tonic-gate cyc_index_t cyo_ndx; 5117c478bd9Sstevel@tonic-gate void *cyo_arg; 5127c478bd9Sstevel@tonic-gate struct cyc_omni_cpu *cyo_next; 5137c478bd9Sstevel@tonic-gate } cyc_omni_cpu_t; 5147c478bd9Sstevel@tonic-gate 5157c478bd9Sstevel@tonic-gate typedef struct cyc_id { 516*87a18d3fSMadhavan Venkataraman krwlock_t cyi_lock; 5177c478bd9Sstevel@tonic-gate cyc_cpu_t *cyi_cpu; 5187c478bd9Sstevel@tonic-gate cyc_index_t cyi_ndx; 5197c478bd9Sstevel@tonic-gate struct cyc_id *cyi_prev; 5207c478bd9Sstevel@tonic-gate struct cyc_id *cyi_next; 5217c478bd9Sstevel@tonic-gate cyc_omni_handler_t cyi_omni_hdlr; 5227c478bd9Sstevel@tonic-gate cyc_omni_cpu_t *cyi_omni_list; 5237c478bd9Sstevel@tonic-gate } cyc_id_t; 5247c478bd9Sstevel@tonic-gate 5257c478bd9Sstevel@tonic-gate typedef struct cyc_xcallarg { 5267c478bd9Sstevel@tonic-gate cyc_cpu_t *cyx_cpu; 5277c478bd9Sstevel@tonic-gate cyc_handler_t *cyx_hdlr; 5287c478bd9Sstevel@tonic-gate cyc_time_t *cyx_when; 5297c478bd9Sstevel@tonic-gate cyc_index_t cyx_ndx; 5307c478bd9Sstevel@tonic-gate cyc_index_t *cyx_heap; 5317c478bd9Sstevel@tonic-gate cyclic_t *cyx_cyclics; 5327c478bd9Sstevel@tonic-gate cyc_index_t cyx_size; 5337c478bd9Sstevel@tonic-gate uint16_t cyx_flags; 5347c478bd9Sstevel@tonic-gate int cyx_wait; 5357c478bd9Sstevel@tonic-gate } cyc_xcallarg_t; 5367c478bd9Sstevel@tonic-gate 5377c478bd9Sstevel@tonic-gate #define CY_DEFAULT_PERCPU 1 5387c478bd9Sstevel@tonic-gate #define CY_PASSIVE_LEVEL -1 5397c478bd9Sstevel@tonic-gate 5407c478bd9Sstevel@tonic-gate #define CY_WAIT 0 5417c478bd9Sstevel@tonic-gate #define CY_NOWAIT 1 5427c478bd9Sstevel@tonic-gate 5437c478bd9Sstevel@tonic-gate #define CYC_HEAP_PARENT(ndx) (((ndx) - 1) >> 1) 5447c478bd9Sstevel@tonic-gate #define CYC_HEAP_RIGHT(ndx) (((ndx) + 1) << 1) 5457c478bd9Sstevel@tonic-gate #define CYC_HEAP_LEFT(ndx) ((((ndx) + 1) << 1) - 1) 5467c478bd9Sstevel@tonic-gate 5477c478bd9Sstevel@tonic-gate #ifdef __cplusplus 5487c478bd9Sstevel@tonic-gate } 5497c478bd9Sstevel@tonic-gate #endif 5507c478bd9Sstevel@tonic-gate 5517c478bd9Sstevel@tonic-gate #endif /* _SYS_CYCLIC_IMPL_H */ 552