4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
26 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
27 * Use is subject to license terms.
30 #ifndef _COMPAT_OPENSOLARIS_SYS_CYCLIC_IMPL_H_
31 #define _COMPAT_OPENSOLARIS_SYS_CYCLIC_IMPL_H_
33 #include <sys/cyclic.h>
36 * Cyclic Subsystem Backend-supplied Interfaces
37 * --------------------------------------------
41 * The design, implementation and interfaces of the cyclic subsystem are
42 * covered in detail in block comments in the implementation. This
43 * comment covers the interface from the cyclic subsystem into the cyclic
44 * backend. The backend is specified by a structure of function pointers
49 * cyb_configure() <-- Configures the backend on the specified CPU
50 * cyb_unconfigure() <-- Unconfigures the backend
51 * cyb_enable() <-- Enables the CY_HIGH_LEVEL interrupt source
52 * cyb_disable() <-- Disables the CY_HIGH_LEVEL interrupt source
53 * cyb_reprogram() <-- Reprograms the CY_HIGH_LEVEL interrupt source
54 * cyb_xcall() <-- Cross calls to the specified CPU
56 * 2 cyb_arg_t cyb_configure(cpu_t *)
60 * cyb_configure() should configure the specified CPU for cyclic operation.
62 * 2.2 Arguments and notes
64 * cyb_configure() should initialize any backend-specific per-CPU
65 * structures for the specified CPU. cyb_configure() will be called for
66 * each CPU (including the boot CPU) during boot. If the platform
67 * supports dynamic reconfiguration, cyb_configure() will be called for
68 * new CPUs as they are configured into the system.
72 * cyb_configure() is expected to return a cookie (a cyb_arg_t, which is
73 * of type void *) which will be used as the first argument for all future
74 * cyclic calls into the backend on the specified CPU.
76 * 2.4 Caller's context
78 * cpu_lock will be held. The caller's CPU is unspecified, and may or
79 * may not be the CPU specified to cyb_configure().
81 * 3 void cyb_unconfigure(cyb_arg_t arg)
85 * cyb_unconfigure() should unconfigure the specified backend.
87 * 3.2 Arguments and notes
89 * The only argument to cyb_unconfigure() is a cookie as returned from
92 * cyb_unconfigure() should free any backend-specific per-CPU structures
93 * for the specified backend. cyb_unconfigure() will _only_ be called on
94 * platforms which support dynamic reconfiguration. If the platform does
95 * not support dynamic reconfiguration, cyb_unconfigure() may panic.
97 * After cyb_unconfigure() returns, the backend must not call cyclic_fire()
98 * on the corresponding CPU; doing so will result in a bad trap.
104 * 3.4 Caller's context
106 * cpu_lock will be held. The caller's CPU is unspecified, and may or
107 * may not be the CPU specified to cyb_unconfigure(). The specified
108 * CPU is guaranteed to exist at the time cyb_unconfigure() is called.
109 * The cyclic subsystem is guaranteed to be suspended when cyb_unconfigure()
110 * is called, and interrupts are guaranteed to be disabled.
112 * 4 void cyb_enable(cyb_arg_t arg)
116 * cyb_enable() should enable the CY_HIGH_LEVEL interrupt source on
117 * the specified backend.
119 * 4.2 Arguments and notes
121 * The only argument to cyb_enable() is a backend cookie as returned from
124 * cyb_enable() will only be called if a) the specified backend has never
125 * been enabled or b) the specified backend has been explicitly disabled with
126 * cyb_disable(). In either case, cyb_enable() will only be called if
127 * the cyclic subsystem wishes to add a cyclic to the CPU corresponding
128 * to the specified backend. cyb_enable() will be called before
129 * cyb_reprogram() for a given backend.
131 * cyclic_fire() should not be called on a CPU which has not had its backend
132 * explicitly cyb_enable()'d, but to do so does not constitute fatal error.
138 * 4.4 Caller's context
140 * cyb_enable() will only be called from CY_HIGH_LEVEL context on the CPU
141 * corresponding to the specified backend.
143 * 5 void cyb_disable(cyb_arg_t arg)
147 * cyb_disable() should disable the CY_HIGH_LEVEL interrupt source on
148 * the specified backend.
150 * 5.2 Arguments and notes
152 * The only argument to cyb_disable() is a backend cookie as returned from
155 * cyb_disable() will only be called on backends which have been previously
156 * been cyb_enable()'d. cyb_disable() will be called when all cyclics have
157 * been juggled away or removed from a cyb_enable()'d CPU.
159 * cyclic_fire() should not be called on a CPU which has had its backend
160 * explicitly cyb_disable()'d, but to do so does not constitute fatal
161 * error. cyb_disable() is thus not required to check for a pending
162 * CY_HIGH_LEVEL interrupt.
168 * 5.4 Caller's context
170 * cyb_disable() will only be called from CY_HIGH_LEVEL context on the CPU
171 * corresponding to the specified backend.
173 * 6 void cyb_reprogram(cyb_arg_t arg, hrtime_t time)
177 * cyb_reprogram() should reprogram the CY_HIGH_LEVEL interrupt source
178 * to fire at the absolute time specified.
180 * 6.2 Arguments and notes
182 * The first argument to cyb_reprogram() is a backend cookie as returned from
185 * The second argument is an absolute time at which the CY_HIGH_LEVEL
186 * interrupt should fire. The specified time _may_ be in the past (albeit
187 * the very recent past). If this is the case, the backend should generate
188 * a CY_HIGH_LEVEL interrupt as soon as possible.
190 * The platform should not assume that cyb_reprogram() will be called with
191 * monotonically increasing values.
193 * If the platform does not allow for interrupts at arbitrary times in the
194 * future, cyb_reprogram() may do nothing -- as long as cyclic_fire() is
195 * called periodically at CY_HIGH_LEVEL. While this is clearly suboptimal
196 * (cyclic granularity will be bounded by the length of the period between
197 * cyclic_fire()'s), it allows the cyclic subsystem to be implemented on
204 * 6.4 Caller's context
206 * cyb_reprogram() will only be called from CY_HIGH_LEVEL context on the CPU
207 * corresponding to the specified backend.
209 * 10 cyb_xcall(cyb_arg_t arg, cpu_t *, void(*func)(void *), void *farg)
213 * cyb_xcall() should execute the specified function on the specified CPU.
215 * 10.2 Arguments and notes
217 * The first argument to cyb_restore_level() is a backend cookie as returned
218 * from cyb_configure(). The second argument is a CPU on which the third
219 * argument, a function pointer, should be executed. The fourth argument,
220 * a void *, should be passed as the argument to the specified function.
222 * cyb_xcall() must provide exactly-once semantics. If the specified
223 * function is called more than once, or not at all, the cyclic subsystem
224 * will become internally inconsistent. The specified function must be
225 * be executed on the specified CPU, but may be executed in any context
226 * (any interrupt context or kernel context).
228 * cyb_xcall() cannot block. Any resources which cyb_xcall() needs to
229 * acquire must thus be protected by synchronization primitives which
230 * never require the caller to block.
236 * 10.4 Caller's context
238 * cpu_lock will be held and kernel preemption may be disabled. The caller
239 * may be unable to block, giving rise to the constraint outlined in
243 typedef struct cyc_backend {
244 cyb_arg_t (*cyb_configure)(cpu_t *);
245 void (*cyb_unconfigure)(cyb_arg_t);
246 void (*cyb_enable)(cyb_arg_t);
247 void (*cyb_disable)(cyb_arg_t);
248 void (*cyb_reprogram)(cyb_arg_t, hrtime_t);
249 void (*cyb_xcall)(cyb_arg_t, cpu_t *, cyc_func_t, void *);
253 #define CYF_FREE 0x0001
255 typedef struct cyclic {
257 hrtime_t cy_interval;
258 void (*cy_handler)(void *);
263 typedef struct cyc_cpu {
265 cyc_index_t *cyp_heap;
266 cyclic_t *cyp_cyclics;
267 cyc_index_t cyp_nelems;
268 cyc_index_t cyp_size;
269 cyc_backend_t *cyp_backend;
273 typedef struct cyc_omni_cpu {
277 struct cyc_omni_cpu *cyo_next;
280 typedef struct cyc_id {
283 struct cyc_id *cyi_prev;
284 struct cyc_id *cyi_next;
285 cyc_omni_handler_t cyi_omni_hdlr;
286 cyc_omni_cpu_t *cyi_omni_list;
289 typedef struct cyc_xcallarg {
294 #define CY_DEFAULT_PERCPU 1
295 #define CY_PASSIVE_LEVEL -1
300 #define CYC_HEAP_PARENT(ndx) (((ndx) - 1) >> 1)
301 #define CYC_HEAP_RIGHT(ndx) (((ndx) + 1) << 1)
302 #define CYC_HEAP_LEFT(ndx) ((((ndx) + 1) << 1) - 1)