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