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 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #ifndef _SYS_CYCLIC_IMPL_H 28 #define _SYS_CYCLIC_IMPL_H 29 30 #pragma ident "%Z%%M% %I% %E% SMI" 31 32 #ifdef __cplusplus 33 extern "C" { 34 #endif 35 36 #include <sys/cyclic.h> 37 38 /* 39 * Cyclic Subsystem Backend-supplied Interfaces 40 * -------------------------------------------- 41 * 42 * 0 Background 43 * 44 * The design, implementation and interfaces of the cyclic subsystem are 45 * covered in detail in block comments in the implementation. This 46 * comment covers the interface from the cyclic subsystem into the cyclic 47 * backend. The backend is specified by a structure of function pointers 48 * defined below. 49 * 50 * 1 Overview 51 * 52 * cyb_configure() <-- Configures the backend on the specified CPU 53 * cyb_unconfigure() <-- Unconfigures the backend 54 * cyb_enable() <-- Enables the CY_HIGH_LEVEL interrupt source 55 * cyb_disable() <-- Disables the CY_HIGH_LEVEL interrupt source 56 * cyb_reprogram() <-- Reprograms the CY_HIGH_LEVEL interrupt source 57 * cyb_softint() <-- Generates a soft interrupt 58 * cyb_set_level() <-- Sets the programmable interrupt level 59 * cyb_restore_level() <-- Restores the programmable interrupt level 60 * cyb_xcall() <-- Cross calls to the specified CPU 61 * cyb_suspend() <-- Suspends the backend 62 * cyb_resume() <-- Resumes the backend 63 * 64 * 2 cyb_arg_t cyb_configure(cpu_t *) 65 * 66 * 2.1 Overview 67 * 68 * cyb_configure() should configure the specified CPU for cyclic operation. 69 * 70 * 2.2 Arguments and notes 71 * 72 * cyb_configure() should initialize any backend-specific per-CPU 73 * structures for the specified CPU. cyb_configure() will be called for 74 * each CPU (including the boot CPU) during boot. If the platform 75 * supports dynamic reconfiguration, cyb_configure() will be called for 76 * new CPUs as they are configured into the system. 77 * 78 * 2.3 Return value 79 * 80 * cyb_configure() is expected to return a cookie (a cyb_arg_t, which is 81 * of type void *) which will be used as the first argument for all future 82 * cyclic calls into the backend on the specified CPU. 83 * 84 * 2.4 Caller's context 85 * 86 * cpu_lock will be held. The caller's CPU is unspecified, and may or 87 * may not be the CPU specified to cyb_configure(). 88 * 89 * 3 void cyb_unconfigure(cyb_arg_t arg) 90 * 91 * 3.1 Overview 92 * 93 * cyb_unconfigure() should unconfigure the specified backend. 94 * 95 * 3.2 Arguments and notes 96 * 97 * The only argument to cyb_unconfigure() is a cookie as returned from 98 * cyb_configure(). 99 * 100 * cyb_unconfigure() should free any backend-specific per-CPU structures 101 * for the specified backend. cyb_unconfigure() will _only_ be called on 102 * platforms which support dynamic reconfiguration. If the platform does 103 * not support dynamic reconfiguration, cyb_unconfigure() may panic. 104 * 105 * After cyb_unconfigure() returns, the backend must not call cyclic_fire() 106 * on the corresponding CPU; doing so will result in a bad trap. 107 * 108 * 3.3 Return value 109 * 110 * None. 111 * 112 * 3.4 Caller's context 113 * 114 * cpu_lock will be held. The caller's CPU is unspecified, and may or 115 * may not be the CPU specified to cyb_unconfigure(). The specified 116 * CPU is guaranteed to exist at the time cyb_unconfigure() is called. 117 * The cyclic subsystem is guaranteed to be suspended when cyb_unconfigure() 118 * is called, and interrupts are guaranteed to be disabled. 119 * 120 * 4 void cyb_enable(cyb_arg_t arg) 121 * 122 * 4.1 Overview 123 * 124 * cyb_enable() should enable the CY_HIGH_LEVEL interrupt source on 125 * the specified backend. 126 * 127 * 4.2 Arguments and notes 128 * 129 * The only argument to cyb_enable() is a backend cookie as returned from 130 * cyb_configure(). 131 * 132 * cyb_enable() will only be called if a) the specified backend has never 133 * been enabled or b) the specified backend has been explicitly disabled with 134 * cyb_disable(). In either case, cyb_enable() will only be called if 135 * the cyclic subsystem wishes to add a cyclic to the CPU corresponding 136 * to the specified backend. cyb_enable() will be called before 137 * cyb_reprogram() for a given backend. 138 * 139 * cyclic_fire() should not be called on a CPU which has not had its backend 140 * explicitly cyb_enable()'d, but to do so does not constitute fatal error. 141 * 142 * 4.3 Return value 143 * 144 * None. 145 * 146 * 4.4 Caller's context 147 * 148 * cyb_enable() will only be called from CY_HIGH_LEVEL context on the CPU 149 * corresponding to the specified backend. 150 * 151 * 5 void cyb_disable(cyb_arg_t arg) 152 * 153 * 5.1 Overview 154 * 155 * cyb_disable() should disable the CY_HIGH_LEVEL interrupt source on 156 * the specified backend. 157 * 158 * 5.2 Arguments and notes 159 * 160 * The only argument to cyb_disable() is a backend cookie as returned from 161 * cyb_configure(). 162 * 163 * cyb_disable() will only be called on backends which have been previously 164 * been cyb_enable()'d. cyb_disable() will be called when all cyclics have 165 * been juggled away or removed from a cyb_enable()'d CPU. 166 * 167 * cyclic_fire() should not be called on a CPU which has had its backend 168 * explicitly cyb_disable()'d, but to do so does not constitute fatal 169 * error. cyb_disable() is thus not required to check for a pending 170 * CY_HIGH_LEVEL interrupt. 171 * 172 * 5.3 Return value 173 * 174 * None. 175 * 176 * 5.4 Caller's context 177 * 178 * cyb_disable() will only be called from CY_HIGH_LEVEL context on the CPU 179 * corresponding to the specified backend. 180 * 181 * 6 void cyb_reprogram(cyb_arg_t arg, hrtime_t time) 182 * 183 * 6.1 Overview 184 * 185 * cyb_reprogram() should reprogram the CY_HIGH_LEVEL interrupt source 186 * to fire at the absolute time specified. 187 * 188 * 6.2 Arguments and notes 189 * 190 * The first argument to cyb_reprogram() is a backend cookie as returned from 191 * cyb_configure(). 192 * 193 * The second argument is an absolute time at which the CY_HIGH_LEVEL 194 * interrupt should fire. The specified time _may_ be in the past (albeit 195 * the very recent past). If this is the case, the backend should generate 196 * a CY_HIGH_LEVEL interrupt as soon as possible. 197 * 198 * The platform should not assume that cyb_reprogram() will be called with 199 * monotonically increasing values. 200 * 201 * If the platform does not allow for interrupts at arbitrary times in the 202 * future, cyb_reprogram() may do nothing -- as long as cyclic_fire() is 203 * called periodically at CY_HIGH_LEVEL. While this is clearly suboptimal 204 * (cyclic granularity will be bounded by the length of the period between 205 * cyclic_fire()'s), it allows the cyclic subsystem to be implemented on 206 * inferior hardware. 207 * 208 * 6.3 Return value 209 * 210 * None. 211 * 212 * 6.4 Caller's context 213 * 214 * cyb_reprogram() will only be called from CY_HIGH_LEVEL context on the CPU 215 * corresponding to the specified backend. 216 * 217 * 7 void cyb_softint(cyb_arg_t arg, cyc_level_t level) 218 * 219 * 7.1 Overview 220 * 221 * cyb_softint() should generate a software interrupt on the specified 222 * backend at the specified level. 223 * 224 * 7.2 Arguments and notes 225 * 226 * The first argument to cyb_softint() is a backend cookie as returned from 227 * cyb_configure(). The second argument is the interrupt level at which 228 * the software interrupt should be generated; it will be either 229 * CY_LOCK_LEVEL or CY_LOW_LEVEL. 230 * 231 * The software interrupt _must_ be generated on the CPU corresponding 232 * to the specified backend; platforms are _required_ to have a per-CPU 233 * notion of a software interrupt. 234 * 235 * Unless a software interrupt is already pending at the specified level, 236 * the software interrupt _must_ be generated. Once cyclic_softint() 237 * has been called at a given level, the software interrupt at that level 238 * should no longer be considered pending; an intervening CY_HIGH_LEVEL 239 * interrupt and subsequent cyb_softint() must generate another software 240 * interrupt. 241 * 242 * 7.3 Return value 243 * 244 * None. 245 * 246 * 7.4 Caller's context 247 * 248 * cyb_softint() will only be called at a level higher than the one 249 * specified: if CY_LOCK_LEVEL is specified, the caller will be at 250 * CY_HIGH_LEVEL; if CY_LOW_LEVEL is specified, the caller will be at 251 * either CY_HIGH_LEVEL or CY_LOCK_LEVEL. cyb_softint() will only be 252 * called on the CPU corresponding to the specified backend. 253 * 254 * 8 cyb_set_level(cyb_arg_t arg, cyc_level_t level) 255 * 256 * 8.1 Overview 257 * 258 * cyb_set_level() should set the programmable interrupt level to the 259 * level specified. 260 * 261 * 8.2 Arguments and notes 262 * 263 * The first argument to cyb_set_level() is a backend cookie as returned 264 * from cyb_configure(). The second argument is the level to which 265 * the programmable interrupt level should be set; it will be one of 266 * CY_HIGH_LEVEL, CY_LOCK_LEVEL or CY_LOW_LEVEL. 267 * 268 * After cyb_set_level() returns, the CPU associated with the specified 269 * backend should accept no interrupt at a level greater than or equal to 270 * the specified level. This will generally be a wrapper around splx(). 271 * 272 * The cyclic subsystem will never call cyb_set_level() twice consecutively 273 * on the same backend; there will always be an intervening 274 * cyb_restore_level(); 275 * 276 * 8.3 Return value 277 * 278 * cyb_set_level() should return a cookie to be passed back to 279 * cyb_restore_level(). On most implementations, this cookie will be 280 * the spl at the time of cyb_set_level(). 281 * 282 * 8.4 Caller's context 283 * 284 * cyb_set_level() is unique in that it is the only backend-provided 285 * interface which may be called in cross call context (see cyb_xcall(), 286 * below). cyb_set_level() may also be called from any of the cyclic 287 * 288 * 9 cyb_restore_level(cyb_arg_t arg, cyc_cookie_t cookie) 289 * 290 * 9.1 Overview 291 * 292 * cyb_restore_level() should restore the programmable interrupt level 293 * based upon the specified cookie. 294 * 295 * 9.2 Arguments and notes 296 * 297 * The first argument to cyb_restore_level() is a backend cookie as returned 298 * from cyb_configure(). The second argument is a cookie as returned from 299 * cyb_set_level(). 300 * 301 * cyb_restore_level() should restore the programmable interrupt level 302 * to its value when cyb_set_level() was called; the cookie is used 303 * to provide a hint to the backend. cyb_restore_level() will not be 304 * called without a proceeding call to cyb_set_level(), and 305 * cyb_restore_level() will never be called twice consecutively on the 306 * same backend. 307 * 308 * 9.3 Return value 309 * 310 * None. 311 * 312 * 9.4 Caller's context 313 * 314 * The constraints outlined in 5.9.2 imply that cyb_restore_level() can 315 * only be called from CY_HIGH_LEVEL, CY_LOCK_LEVEL or CY_LOW_LEVEL context. 316 * cyb_restore_level() is always called on the CPU associated with the 317 * specified backend. 318 * 319 * 10 cyb_xcall(cyb_arg_t arg, cpu_t *, void(*func)(void *), void *farg) 320 * 321 * 10.1 Overview 322 * 323 * cyb_xcall() should execute the specified function on the specified CPU. 324 * 325 * 10.2 Arguments and notes 326 * 327 * The first argument to cyb_restore_level() is a backend cookie as returned 328 * from cyb_configure(). The second argument is a CPU on which the third 329 * argument, a function pointer, should be executed. The fourth argument, 330 * a void *, should be passed as the argument to the specified function. 331 * 332 * cyb_xcall() must provide exactly-once semantics. If the specified 333 * function is called more than once, or not at all, the cyclic subsystem 334 * will become internally inconsistent. The specified function must be 335 * be executed on the specified CPU, but may be executed in any context 336 * (any interrupt context or kernel context). 337 * 338 * cyb_xcall() cannot block. Any resources which cyb_xcall() needs to 339 * acquire must thus be protected by synchronization primitives which 340 * never require the caller to block. 341 * 342 * 10.3 Return value 343 * 344 * None. 345 * 346 * 10.4 Caller's context 347 * 348 * cpu_lock will be held and kernel preemption may be disabled. The caller 349 * may be unable to block, giving rise to the constraint outlined in 350 * 10.2, above. 351 * 352 * 11 cyb_suspend(cyb_arg_t arg) 353 * 354 * 11.1 Overview 355 * 356 * cyb_suspend() should suspend the specified backend. 357 * 358 * 11.2 Arguments and notes 359 * 360 * The only argument to cyb_suspend() is a backend cookie as returned from 361 * cyb_configure(). 362 * 363 * cyb_suspend() will never be called on enabled backends. The backend 364 * should assume that the machine may be subsequently powered off; any 365 * volatile hardware state should be preserved and restored in cyb_resume(). 366 * However, the backend should not _assume_ that the machine will be 367 * powered off; cyb_suspend() may also be called as part of dynamic 368 * reconfiguration. 369 * 370 * cyb_suspend() will be called on the corresponding backend of each 371 * CPU in the system in succession, regardless of CPU state (P_ONLINE, 372 * P_OFFLINE, P_NOINTR). The cyclic subsystem will not suspend only a 373 * fraction of the CPUs. 374 * 375 * 11.3 Return value 376 * 377 * None. 378 * 379 * 11.4 Caller's context 380 * 381 * cyb_suspend() will be called in cross call context on the CPU associated 382 * with the specified backend. 383 * 384 * 12 cyb_resume(cyb_arg_t arg) 385 * 386 * 12.1 Overview 387 * 388 * cyb_resume() should resume the specified backend. 389 * 390 * 12.2 Arguments and notes 391 * 392 * The only argument to cyb_resume() is a backend cookie as returned from 393 * cyb_resume(). 394 * 395 * Calls to cyb_resume() will always have been proceeded by corresponding 396 * calls to cyb_suspend(). The machine may have been powered off between 397 * cyb_suspend() and the call to cyb_resume(). cyb_resume() may decide 398 * to restore hardware to its state at the time cyb_suspend() was called. 399 * 400 * The cyclic subsystem will make no calls into the backend between 401 * cyb_suspend() and cyb_resume(). 402 * 403 * 12.3 Return value 404 * 405 * None. 406 * 407 * 12.4 Caller's context 408 * 409 * cyb_resume() will be called in cross call context on the CPU associated 410 * with the specified backend. 411 */ 412 typedef struct cyc_backend { 413 cyb_arg_t (*cyb_configure)(cpu_t *); 414 void (*cyb_unconfigure)(cyb_arg_t); 415 void (*cyb_enable)(cyb_arg_t); 416 void (*cyb_disable)(cyb_arg_t); 417 void (*cyb_reprogram)(cyb_arg_t, hrtime_t); 418 void (*cyb_softint)(cyb_arg_t, cyc_level_t); 419 cyc_cookie_t (*cyb_set_level)(cyb_arg_t, cyc_level_t); 420 void (*cyb_restore_level)(cyb_arg_t, cyc_cookie_t); 421 void (*cyb_xcall)(cyb_arg_t, cpu_t *, cyc_func_t, void *); 422 void (*cyb_suspend)(cyb_arg_t); 423 void (*cyb_resume)(cyb_arg_t); 424 cyb_arg_t cyb_arg; 425 } cyc_backend_t; 426 427 extern void cyclic_init(cyc_backend_t *be, hrtime_t resolution); 428 extern void cyclic_mp_init(); 429 430 #ifdef DEBUG 431 #define CYCLIC_TRACE 432 #endif 433 434 typedef enum { 435 CYS_ONLINE, 436 CYS_OFFLINE, 437 CYS_EXPANDING, 438 CYS_REMOVING, 439 CYS_SUSPENDED 440 } cyc_state_t; 441 442 #define CYF_FREE 0x0001 443 #define CYF_CPU_BOUND 0x0002 444 #define CYF_PART_BOUND 0x0004 445 446 typedef struct cyclic { 447 hrtime_t cy_expire; 448 hrtime_t cy_interval; 449 void (*cy_handler)(void *); 450 void *cy_arg; 451 uint32_t cy_pend; 452 uint16_t cy_flags; 453 cyc_level_t cy_level; 454 } cyclic_t; 455 456 typedef struct cyc_pcbuffer { 457 cyc_index_t *cypc_buf; 458 int cypc_prodndx; 459 int cypc_consndx; 460 int cypc_sizemask; 461 } cyc_pcbuffer_t; 462 463 typedef struct cyc_softbuf { 464 uchar_t cys_hard; /* Can only be zero or one */ 465 uchar_t cys_soft; /* Can only be zero or one */ 466 cyc_pcbuffer_t cys_buf[2]; 467 } cyc_softbuf_t; 468 469 #define CY_NTRACEREC 512 470 471 typedef struct cyc_tracerec { 472 hrtime_t cyt_tstamp; 473 char *cyt_why; 474 uint64_t cyt_arg0; 475 uint64_t cyt_arg1; 476 } cyc_tracerec_t; 477 478 typedef struct cyc_tracebuf { 479 int cyt_ndx; 480 cyc_tracerec_t cyt_buf[CY_NTRACEREC]; 481 } cyc_tracebuf_t; 482 483 #define CY_NCOVERAGE 127 484 485 typedef struct cyc_coverage { 486 char *cyv_why; 487 int cyv_passive_count; 488 int cyv_count[CY_LEVELS]; 489 uint64_t cyv_arg0; 490 uint64_t cyv_arg1; 491 } cyc_coverage_t; 492 493 typedef struct cyc_cpu { 494 cpu_t *cyp_cpu; 495 cyc_index_t *cyp_heap; 496 cyclic_t *cyp_cyclics; 497 cyc_index_t cyp_nelems; 498 cyc_index_t cyp_size; 499 cyc_state_t cyp_state; 500 cyc_softbuf_t cyp_softbuf[CY_SOFT_LEVELS]; 501 cyc_backend_t *cyp_backend; 502 ksema_t cyp_modify_wait; 503 uint32_t cyp_modify_levels; 504 uint32_t cyp_rpend; 505 #ifdef CYCLIC_TRACE 506 cyc_tracebuf_t cyp_trace[CY_LEVELS]; 507 #endif 508 } cyc_cpu_t; 509 510 typedef struct cyc_omni_cpu { 511 cyc_cpu_t *cyo_cpu; 512 cyc_index_t cyo_ndx; 513 void *cyo_arg; 514 struct cyc_omni_cpu *cyo_next; 515 } cyc_omni_cpu_t; 516 517 typedef struct cyc_id { 518 cyc_cpu_t *cyi_cpu; 519 cyc_index_t cyi_ndx; 520 struct cyc_id *cyi_prev; 521 struct cyc_id *cyi_next; 522 cyc_omni_handler_t cyi_omni_hdlr; 523 cyc_omni_cpu_t *cyi_omni_list; 524 } cyc_id_t; 525 526 typedef struct cyc_xcallarg { 527 cyc_cpu_t *cyx_cpu; 528 cyc_handler_t *cyx_hdlr; 529 cyc_time_t *cyx_when; 530 cyc_index_t cyx_ndx; 531 cyc_index_t *cyx_heap; 532 cyclic_t *cyx_cyclics; 533 cyc_index_t cyx_size; 534 uint16_t cyx_flags; 535 int cyx_wait; 536 } cyc_xcallarg_t; 537 538 #define CY_DEFAULT_PERCPU 1 539 #define CY_PASSIVE_LEVEL -1 540 541 #define CY_WAIT 0 542 #define CY_NOWAIT 1 543 544 #define CYC_HEAP_PARENT(ndx) (((ndx) - 1) >> 1) 545 #define CYC_HEAP_RIGHT(ndx) (((ndx) + 1) << 1) 546 #define CYC_HEAP_LEFT(ndx) ((((ndx) + 1) << 1) - 1) 547 548 #ifdef __cplusplus 549 } 550 #endif 551 552 #endif /* _SYS_CYCLIC_IMPL_H */ 553