1 /*	$NetBSD: cyclic_impl.h,v 1.4 2012/12/02 01:05:16 chs Exp $	*/
2 
3 /*
4  * CDDL HEADER START
5  *
6  * The contents of this file are subject to the terms of the
7  * Common Development and Distribution License, Version 1.0 only
8  * (the "License").  You may not use this file except in compliance
9  * with the License.
10  *
11  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
12  * or http://www.opensolaris.org/os/licensing.
13  * See the License for the specific language governing permissions
14  * and limitations under the License.
15  *
16  * When distributing Covered Code, include this CDDL HEADER in each
17  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
18  * If applicable, add the following below this CDDL HEADER, with the
19  * fields enclosed by brackets "[]" replaced with your own identifying
20  * information: Portions Copyright [yyyy] [name of copyright owner]
21  *
22  * CDDL HEADER END
23  *
24  * $FreeBSD$
25  *
26  */
27 /*
28  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
29  * Use is subject to license terms.
30  */
31 
32 #ifndef _COMPAT_OPENSOLARIS_SYS_CYCLIC_IMPL_H_
33 #define _COMPAT_OPENSOLARIS_SYS_CYCLIC_IMPL_H_
34 
35 #include <sys/cyclic.h>
36 
37 /*
38  *  Cyclic Subsystem Backend-supplied Interfaces
39  *  --------------------------------------------
40  *
41  *  0  Background
42  *
43  *    The design, implementation and interfaces of the cyclic subsystem are
44  *    covered in detail in block comments in the implementation.  This
45  *    comment covers the interface from the cyclic subsystem into the cyclic
46  *    backend.  The backend is specified by a structure of function pointers
47  *    defined below.
48  *
49  *  1  Overview
50  *
51  *      cyb_configure()      <-- Configures the backend on the specified CPU
52  *      cyb_unconfigure()    <-- Unconfigures the backend
53  *      cyb_enable()         <-- Enables the CY_HIGH_LEVEL interrupt source
54  *      cyb_disable()        <-- Disables the CY_HIGH_LEVEL interrupt source
55  *      cyb_reprogram()      <-- Reprograms the CY_HIGH_LEVEL interrupt source
56  *      cyb_xcall()          <-- Cross calls to the specified CPU
57  *
58  *  2  cyb_arg_t cyb_configure(cpu_t *)
59  *
60  *  2.1  Overview
61  *
62  *    cyb_configure() should configure the specified CPU for cyclic operation.
63  *
64  *  2.2  Arguments and notes
65  *
66  *    cyb_configure() should initialize any backend-specific per-CPU
67  *    structures for the specified CPU.  cyb_configure() will be called for
68  *    each CPU (including the boot CPU) during boot.  If the platform
69  *    supports dynamic reconfiguration, cyb_configure() will be called for
70  *    new CPUs as they are configured into the system.
71  *
72  *  2.3  Return value
73  *
74  *    cyb_configure() is expected to return a cookie (a cyb_arg_t, which is
75  *    of type void *) which will be used as the first argument for all future
76  *    cyclic calls into the backend on the specified CPU.
77  *
78  *  2.4  Caller's context
79  *
80  *    cpu_lock will be held.  The caller's CPU is unspecified, and may or
81  *    may not be the CPU specified to cyb_configure().
82  *
83  *  3  void cyb_unconfigure(cyb_arg_t arg)
84  *
85  *  3.1  Overview
86  *
87  *    cyb_unconfigure() should unconfigure the specified backend.
88  *
89  *  3.2  Arguments and notes
90  *
91  *    The only argument to cyb_unconfigure() is a cookie as returned from
92  *    cyb_configure().
93  *
94  *    cyb_unconfigure() should free any backend-specific per-CPU structures
95  *    for the specified backend.  cyb_unconfigure() will _only_ be called on
96  *    platforms which support dynamic reconfiguration.  If the platform does
97  *    not support dynamic reconfiguration, cyb_unconfigure() may panic.
98  *
99  *    After cyb_unconfigure() returns, the backend must not call cyclic_fire()
100  *    on the corresponding CPU; doing so will result in a bad trap.
101  *
102  *  3.3  Return value
103  *
104  *    None.
105  *
106  *  3.4  Caller's context
107  *
108  *    cpu_lock will be held.  The caller's CPU is unspecified, and may or
109  *    may not be the CPU specified to cyb_unconfigure().  The specified
110  *    CPU is guaranteed to exist at the time cyb_unconfigure() is called.
111  *    The cyclic subsystem is guaranteed to be suspended when cyb_unconfigure()
112  *    is called, and interrupts are guaranteed to be disabled.
113  *
114  *  4  void cyb_enable(cyb_arg_t arg)
115  *
116  *  4.1  Overview
117  *
118  *    cyb_enable() should enable the CY_HIGH_LEVEL interrupt source on
119  *    the specified backend.
120  *
121  *  4.2  Arguments and notes
122  *
123  *    The only argument to cyb_enable() is a backend cookie as returned from
124  *    cyb_configure().
125  *
126  *    cyb_enable() will only be called if a) the specified backend has never
127  *    been enabled or b) the specified backend has been explicitly disabled with
128  *    cyb_disable().  In either case, cyb_enable() will only be called if
129  *    the cyclic subsystem wishes to add a cyclic to the CPU corresponding
130  *    to the specified backend.  cyb_enable() will be called before
131  *    cyb_reprogram() for a given backend.
132  *
133  *    cyclic_fire() should not be called on a CPU which has not had its backend
134  *    explicitly cyb_enable()'d, but to do so does not constitute fatal error.
135  *
136  *  4.3  Return value
137  *
138  *    None.
139  *
140  *  4.4  Caller's context
141  *
142  *    cyb_enable() will only be called from CY_HIGH_LEVEL context on the CPU
143  *    corresponding to the specified backend.
144  *
145  *  5  void cyb_disable(cyb_arg_t arg)
146  *
147  *  5.1  Overview
148  *
149  *    cyb_disable() should disable the CY_HIGH_LEVEL interrupt source on
150  *    the specified backend.
151  *
152  *  5.2  Arguments and notes
153  *
154  *    The only argument to cyb_disable() is a backend cookie as returned from
155  *    cyb_configure().
156  *
157  *    cyb_disable() will only be called on backends which have been previously
158  *    been cyb_enable()'d.  cyb_disable() will be called when all cyclics have
159  *    been juggled away or removed from a cyb_enable()'d CPU.
160  *
161  *    cyclic_fire() should not be called on a CPU which has had its backend
162  *    explicitly cyb_disable()'d, but to do so does not constitute fatal
163  *    error.  cyb_disable() is thus not required to check for a pending
164  *    CY_HIGH_LEVEL interrupt.
165  *
166  *  5.3  Return value
167  *
168  *    None.
169  *
170  *  5.4  Caller's context
171  *
172  *    cyb_disable() will only be called from CY_HIGH_LEVEL context on the CPU
173  *    corresponding to the specified backend.
174  *
175  *  6  void cyb_reprogram(cyb_arg_t arg, hrtime_t time)
176  *
177  *  6.1  Overview
178  *
179  *    cyb_reprogram() should reprogram the CY_HIGH_LEVEL interrupt source
180  *    to fire at the absolute time specified.
181  *
182  *  6.2  Arguments and notes
183  *
184  *    The first argument to cyb_reprogram() is a backend cookie as returned from
185  *    cyb_configure().
186  *
187  *    The second argument is an absolute time at which the CY_HIGH_LEVEL
188  *    interrupt should fire.  The specified time _may_ be in the past (albeit
189  *    the very recent past).  If this is the case, the backend should generate
190  *    a CY_HIGH_LEVEL interrupt as soon as possible.
191  *
192  *    The platform should not assume that cyb_reprogram() will be called with
193  *    monotonically increasing values.
194  *
195  *    If the platform does not allow for interrupts at arbitrary times in the
196  *    future, cyb_reprogram() may do nothing -- as long as cyclic_fire() is
197  *    called periodically at CY_HIGH_LEVEL.  While this is clearly suboptimal
198  *    (cyclic granularity will be bounded by the length of the period between
199  *    cyclic_fire()'s), it allows the cyclic subsystem to be implemented on
200  *    inferior hardware.
201  *
202  *  6.3  Return value
203  *
204  *     None.
205  *
206  *  6.4  Caller's context
207  *
208  *    cyb_reprogram() will only be called from CY_HIGH_LEVEL context on the CPU
209  *    corresponding to the specified backend.
210  *
211  *  10  cyb_xcall(cyb_arg_t arg, cpu_t *, void(*func)(void *), void *farg)
212  *
213  *  10.1  Overview
214  *
215  *    cyb_xcall() should execute the specified function on the specified CPU.
216  *
217  *  10.2  Arguments and notes
218  *
219  *    The first argument to cyb_restore_level() is a backend cookie as returned
220  *    from cyb_configure().  The second argument is a CPU on which the third
221  *    argument, a function pointer, should be executed.  The fourth argument,
222  *    a void *, should be passed as the argument to the specified function.
223  *
224  *    cyb_xcall() must provide exactly-once semantics.  If the specified
225  *    function is called more than once, or not at all, the cyclic subsystem
226  *    will become internally inconsistent.  The specified function must be
227  *    be executed on the specified CPU, but may be executed in any context
228  *    (any interrupt context or kernel context).
229  *
230  *    cyb_xcall() cannot block.  Any resources which cyb_xcall() needs to
231  *    acquire must thus be protected by synchronization primitives which
232  *    never require the caller to block.
233  *
234  *  10.3  Return value
235  *
236  *    None.
237  *
238  *  10.4  Caller's context
239  *
240  *    cpu_lock will be held and kernel preemption may be disabled.  The caller
241  *    may be unable to block, giving rise to the constraint outlined in
242  *    10.2, above.
243  *
244  */
245 typedef struct cyc_backend {
246 	cyb_arg_t (*cyb_configure)(cpu_t *);
247 	void (*cyb_unconfigure)(cyb_arg_t);
248 	void (*cyb_enable)(cyb_arg_t);
249 	void (*cyb_disable)(cyb_arg_t);
250 	void (*cyb_reprogram)(cyb_arg_t, hrtime_t);
251 	void (*cyb_xcall)(cyb_arg_t, cpu_t *, cyc_func_t, void *);
252 	cyb_arg_t cyb_arg;
253 } cyc_backend_t;
254 
255 #define	CYF_FREE		0x0001
256 
257 typedef struct cyclic {
258 	hrtime_t cy_expire;
259 	hrtime_t cy_interval;
260 	void (*cy_handler)(void *);
261 	void *cy_arg;
262 	uint16_t cy_flags;
263 } cyclic_t;
264 
265 typedef struct cyc_cpu {
266 	cpu_t *cyp_cpu;
267 	cyc_index_t *cyp_heap;
268 	cyclic_t *cyp_cyclics;
269 	cyc_index_t cyp_nelems;
270 	cyc_index_t cyp_size;
271 	cyc_backend_t *cyp_backend;
272 	kmutex_t cyp_mtx;
273 } cyc_cpu_t;
274 
275 typedef struct cyc_omni_cpu {
276 	cyc_cpu_t *cyo_cpu;
277 	cyc_index_t cyo_ndx;
278 	void *cyo_arg;
279 	struct cyc_omni_cpu *cyo_next;
280 } cyc_omni_cpu_t;
281 
282 typedef struct cyc_id {
283 	cyc_cpu_t *cyi_cpu;
284 	cyc_index_t cyi_ndx;
285 	struct cyc_id *cyi_prev;
286 	struct cyc_id *cyi_next;
287 	cyc_omni_handler_t cyi_omni_hdlr;
288 	cyc_omni_cpu_t *cyi_omni_list;
289 } cyc_id_t;
290 
291 typedef struct cyc_xcallarg {
292 	cyc_cpu_t *cyx_cpu;
293 	cyc_handler_t *cyx_hdlr;
294 	cyc_time_t *cyx_when;
295 	cyc_index_t cyx_ndx;
296 	cyc_index_t *cyx_heap;
297 	cyclic_t *cyx_cyclics;
298 	cyc_index_t cyx_size;
299 	uint16_t cyx_flags;
300 	int cyx_wait;
301 } cyc_xcallarg_t;
302 
303 #define	CY_DEFAULT_PERCPU	1
304 #define	CY_PASSIVE_LEVEL	-1
305 
306 #define	CY_WAIT			0
307 #define	CY_NOWAIT		1
308 
309 #define	CYC_HEAP_PARENT(ndx)		(((ndx) - 1) >> 1)
310 #define	CYC_HEAP_RIGHT(ndx)		(((ndx) + 1) << 1)
311 #define	CYC_HEAP_LEFT(ndx)		((((ndx) + 1) << 1) - 1)
312 
313 #endif
314