Home | History | Annotate | Line # | Download | only in sys
      1 /*	$NetBSD: cyclic_impl.h,v 1.5 2018/05/28 21:05:10 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: head/sys/cddl/compat/opensolaris/sys/cyclic_impl.h 216254 2010-12-07 12:25:26Z avg $
     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