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: stable/9/sys/cddl/compat/opensolaris/sys/cyclic_impl.h 216254 2010-12-07 12:25:26Z avg $ 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 312