]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - sys/cddl/compat/opensolaris/sys/cyclic_impl.h
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / sys / cddl / compat / opensolaris / sys / cyclic_impl.h
1 /*
2  * CDDL HEADER START
3  *
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
7  * with the License.
8  *
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.
13  *
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]
19  *
20  * CDDL HEADER END
21  *
22  * $FreeBSD$
23  *
24  */
25 /*
26  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
27  * Use is subject to license terms.
28  */
29
30 #ifndef _COMPAT_OPENSOLARIS_SYS_CYCLIC_IMPL_H_
31 #define _COMPAT_OPENSOLARIS_SYS_CYCLIC_IMPL_H_
32
33 #include <sys/cyclic.h>
34
35 /*
36  *  Cyclic Subsystem Backend-supplied Interfaces
37  *  --------------------------------------------
38  *
39  *  0  Background
40  *
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
45  *    defined below.
46  *
47  *  1  Overview
48  *
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
55  *
56  *  2  cyb_arg_t cyb_configure(cpu_t *)
57  *
58  *  2.1  Overview
59  *
60  *    cyb_configure() should configure the specified CPU for cyclic operation.
61  *
62  *  2.2  Arguments and notes
63  *
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.
69  *
70  *  2.3  Return value
71  *
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.
75  *
76  *  2.4  Caller's context
77  *
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().
80  *
81  *  3  void cyb_unconfigure(cyb_arg_t arg)
82  *
83  *  3.1  Overview
84  *
85  *    cyb_unconfigure() should unconfigure the specified backend.
86  *
87  *  3.2  Arguments and notes
88  *
89  *    The only argument to cyb_unconfigure() is a cookie as returned from
90  *    cyb_configure().
91  *
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.
96  *
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.
99  *
100  *  3.3  Return value
101  *
102  *    None.
103  *
104  *  3.4  Caller's context
105  *
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.
111  *
112  *  4  void cyb_enable(cyb_arg_t arg)
113  *
114  *  4.1  Overview
115  *
116  *    cyb_enable() should enable the CY_HIGH_LEVEL interrupt source on
117  *    the specified backend.
118  *
119  *  4.2  Arguments and notes
120  *
121  *    The only argument to cyb_enable() is a backend cookie as returned from
122  *    cyb_configure().
123  *
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.
130  *
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.
133  *
134  *  4.3  Return value
135  *
136  *    None.
137  *
138  *  4.4  Caller's context
139  *
140  *    cyb_enable() will only be called from CY_HIGH_LEVEL context on the CPU
141  *    corresponding to the specified backend.
142  *
143  *  5  void cyb_disable(cyb_arg_t arg)
144  *
145  *  5.1  Overview
146  *
147  *    cyb_disable() should disable the CY_HIGH_LEVEL interrupt source on
148  *    the specified backend.
149  *
150  *  5.2  Arguments and notes
151  *
152  *    The only argument to cyb_disable() is a backend cookie as returned from
153  *    cyb_configure().
154  *
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.
158  *
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.
163  *
164  *  5.3  Return value
165  *
166  *    None.
167  *
168  *  5.4  Caller's context
169  *
170  *    cyb_disable() will only be called from CY_HIGH_LEVEL context on the CPU
171  *    corresponding to the specified backend.
172  *
173  *  6  void cyb_reprogram(cyb_arg_t arg, hrtime_t time)
174  *
175  *  6.1  Overview
176  *
177  *    cyb_reprogram() should reprogram the CY_HIGH_LEVEL interrupt source
178  *    to fire at the absolute time specified.
179  *
180  *  6.2  Arguments and notes
181  *
182  *    The first argument to cyb_reprogram() is a backend cookie as returned from
183  *    cyb_configure().
184  *
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.
189  *
190  *    The platform should not assume that cyb_reprogram() will be called with
191  *    monotonically increasing values.
192  *
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
198  *    inferior hardware.
199  *
200  *  6.3  Return value
201  *
202  *     None.
203  *
204  *  6.4  Caller's context
205  *
206  *    cyb_reprogram() will only be called from CY_HIGH_LEVEL context on the CPU
207  *    corresponding to the specified backend.
208  *
209  *  10  cyb_xcall(cyb_arg_t arg, cpu_t *, void(*func)(void *), void *farg)
210  *
211  *  10.1  Overview
212  *
213  *    cyb_xcall() should execute the specified function on the specified CPU.
214  *
215  *  10.2  Arguments and notes
216  *
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.
221  *
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).
227  *
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.
231  *
232  *  10.3  Return value
233  *
234  *    None.
235  *
236  *  10.4  Caller's context
237  *
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
240  *    10.2, above.
241  *
242  */
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 *);
250         cyb_arg_t cyb_arg;
251 } cyc_backend_t;
252
253 #define CYF_FREE                0x0001
254
255 typedef struct cyclic {
256         hrtime_t cy_expire;
257         hrtime_t cy_interval;
258         void (*cy_handler)(void *);
259         void *cy_arg;
260         uint16_t cy_flags;
261 } cyclic_t;
262
263 typedef struct cyc_cpu {
264         cpu_t *cyp_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;
270         struct mtx cyp_mtx;
271 } cyc_cpu_t;
272
273 typedef struct cyc_omni_cpu {
274         cyc_cpu_t *cyo_cpu;
275         cyc_index_t cyo_ndx;
276         void *cyo_arg;
277         struct cyc_omni_cpu *cyo_next;
278 } cyc_omni_cpu_t;
279
280 typedef struct cyc_id {
281         cyc_cpu_t *cyi_cpu;
282         cyc_index_t cyi_ndx;
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;
287 } cyc_id_t;
288
289 typedef struct cyc_xcallarg {
290         cyc_cpu_t *cyx_cpu;
291         cyc_handler_t *cyx_hdlr;
292         cyc_time_t *cyx_when;
293         cyc_index_t cyx_ndx;
294         cyc_index_t *cyx_heap;
295         cyclic_t *cyx_cyclics;
296         cyc_index_t cyx_size;
297         uint16_t cyx_flags;
298         int cyx_wait;
299 } cyc_xcallarg_t;
300
301 #define CY_DEFAULT_PERCPU       1
302 #define CY_PASSIVE_LEVEL        -1
303
304 #define CY_WAIT                 0
305 #define CY_NOWAIT               1
306
307 #define CYC_HEAP_PARENT(ndx)            (((ndx) - 1) >> 1)
308 #define CYC_HEAP_RIGHT(ndx)             (((ndx) + 1) << 1)
309 #define CYC_HEAP_LEFT(ndx)              ((((ndx) + 1) << 1) - 1)
310
311 #endif