1 /*
2  * SPDX-FileCopyrightText: Copyright (c) 2016 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3  * SPDX-License-Identifier: MIT
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  */
23 
24 #ifndef __NV_KTHREAD_QUEUE_H__
25 #define __NV_KTHREAD_QUEUE_H__
26 
27 struct nv_kthread_q;
28 struct nv_kthread_q_item;
29 typedef struct nv_kthread_q nv_kthread_q_t;
30 typedef struct nv_kthread_q_item nv_kthread_q_item_t;
31 
32 typedef void (*nv_q_func_t)(void *args);
33 
34 #include "nv-kthread-q-os.h"
35 
36 ////////////////////////////////////////////////////////////////////////////////
37 // nv_kthread_q:
38 //
39 // 1. API and overview
40 //
41 //    This "nv_kthread_q" system implements a simple queuing system for deferred
42 //    work. The nv_kthread_q system has goals and use cases that are similar to
43 //    the named workqueues in the Linux kernel, but nv_kthread_q is much (10x or
44 //    so) smaller, simpler--and correspondingly less general. Deferred work
45 //    items are put into a queue, and run within the context of a dedicated set
46 //    of kernel threads (kthread).
47 //
48 //    In order to avoid confusion with the Linux workqueue system, I have
49 //    avoided using the term "work", and instead refer to "queues" (also called
50 //    "q's") and "queue items" (also called "q_items"), in both variable names
51 //    and comments.
52 //
53 //    This module depends only upon the Linux kernel.
54 //
55 //    Queue items that are submitted to separate nv_kthread_q instances are
56 //    guaranteed to be run in different kthreads.
57 //
58 //    Queue items that are submitted to the same nv_kthread_q are not guaranteed
59 //    to be serialized, nor are they guaranteed to run concurrently.
60 //
61 // 2. Allocations
62 //
63 //    The caller allocates queues and queue items. The nv_kthread_q APIs do
64 //    the initialization (zeroing and setup) of queues and queue items.
65 //    Allocation is handled that way, because one of the first use cases is a
66 //    bottom half interrupt handler, and for that, queue items should be
67 //    pre-allocated (for example, one per GPU), so that no allocation is
68 //    required in the top-half interrupt handler. Relevant API calls:
69 //
70 // 3. Queue initialization
71 //
72 //    nv_kthread_q_init() initializes a queue on the current NUMA node.
73 //
74 //    or
75 //
76 //    nv_kthread_q_init_on_node() initializes a queue on a specific NUMA node.
77 //
78 // 3. Scheduling things for the queue to run
79 //
80 //    The nv_kthread_q_schedule_q_item() routine will schedule a q_item to run.
81 //
82 // 4. Stopping the queue(s)
83 //
84 //    The nv_kthread_q_stop() routine will flush the queue, and safely stop
85 //    the kthread, before returning.
86 //
87 ////////////////////////////////////////////////////////////////////////////////
88 
89 //
90 // The queue must not be used before calling this routine.
91 //
92 // The caller allocates an nv_kthread_q_t item. This routine initializes
93 // the queue, and starts up a kernel thread ("kthread") to service the queue.
94 // The queue will initially be empty; there is intentionally no way to
95 // pre-initialize the queue with items to run.
96 //
97 // In order to avoid external dependencies (specifically, NV_STATUS codes), this
98 // returns a Linux kernel (negative) errno on failure, and zero on success. It
99 // is safe to call nv_kthread_q_stop() on a queue that nv_kthread_q_init()
100 // failed for.
101 //
102 // A short prefix of the qname arg will show up in []'s, via the ps(1) utility.
103 //
104 // The kernel thread stack is preferably allocated on the specified NUMA node,
105 // but fallback to another node is possible because kernel allocators do not
106 // guarantee affinity. Note that NUMA-affinity applies only to
107 // the kthread stack. This API does not do anything about limiting the CPU
108 // affinity of the kthread. That is left to the caller.
109 //
110 // Reusing a queue: once a queue is initialized, it must be safely shut down
111 // (see "Stopping the queue(s)", below), before it can be reused. So, for
112 // a simple queue use case, the following will work:
113 //
114 //     nv_kthread_q_init_on_node(&some_q, "display_name", preferred_node);
115 //     nv_kthread_q_stop(&some_q);
116 //     nv_kthread_q_init_on_node(&some_q, "reincarnated", preferred_node);
117 //     nv_kthread_q_stop(&some_q);
118 //
119 int nv_kthread_q_init_on_node(nv_kthread_q_t *q,
120                               const char *qname,
121                               int preferred_node);
122 
123 //
124 // This routine is the same as nv_kthread_q_init_on_node() with the exception
125 // that the queue stack will be allocated on the NUMA node of the caller.
126 //
127 int nv_kthread_q_init(nv_kthread_q_t *q, const char *qname);
128 
129 //
130 // The caller is responsible for stopping all queues, by calling this routine
131 // before, for example, kernel module unloading. This nv_kthread_q_stop()
132 // routine will flush the queue, and safely stop the kthread, before returning.
133 //
134 // You may ONLY call nv_kthread_q_stop() once, unless you reinitialize the
135 // queue in between, as shown in the nv_kthread_q_init() documentation, above.
136 //
137 // Do not add any more items to the queue after calling nv_kthread_q_stop.
138 //
139 // Calling nv_kthread_q_stop() on a queue which has been zero-initialized or
140 // for which nv_kthread_q_init() failed, is a no-op.
141 //
142 void nv_kthread_q_stop(nv_kthread_q_t *q);
143 
144 //
145 // All items that were in the queue before nv_kthread_q_flush was called, and
146 // all items scheduled by those items, will get run before this function
147 // returns.
148 //
149 // You may NOT call nv_kthread_q_flush() after having called nv_kthread_q_stop.
150 //
151 // This actually flushes the queue twice. That ensures that the queue is fully
152 // flushed, for an important use case: rescheduling from within one's own
153 // callback. In order to do that safely, you need to:
154 //
155 //     -- set a flag that tells the callback to stop rescheduling itself.
156 //
157 //     -- call either nv_kthread_q_flush or nv_kthread_q_stop (which internally
158 //        calls nv_kthread_q_flush). The nv_kthread_q_flush, in turn, actually
159 //        flushes the queue *twice*. The first flush waits for any callbacks
160 //        to finish, that missed seeing the "stop_rescheduling" flag. The
161 //        second flush waits for callbacks that were already scheduled when the
162 //        first flush finished.
163 //
164 void nv_kthread_q_flush(nv_kthread_q_t *q);
165 
166 // Assigns function_to_run and function_args to the q_item.
167 //
168 // This must be called before calling nv_kthread_q_schedule_q_item.
169 void nv_kthread_q_item_init(nv_kthread_q_item_t *q_item,
170                             nv_q_func_t function_to_run,
171                             void *function_args);
172 
173 //
174 // The caller must have already set up the queue, via nv_kthread_q_init().
175 // The caller owns the lifetime of the q_item. The nv_kthread_q system runs
176 // q_items, and adds or removes them from the queue. However, due to the first
177 // law of q-dynamics, it neither creates nor destroys q_items.
178 //
179 // When the callback (the function_to_run argument) is actually run, it is OK
180 // to free the q_item from within that routine. The nv_kthread_q system
181 // promises to be done with the q_item before that point.
182 //
183 // nv_kthread_q_schedule_q_item may be called from multiple threads at once,
184 // without danger of corrupting anything. This routine may also be safely
185 // called from interrupt context, including top-half ISRs.
186 //
187 // It is OK to reschedule the same q_item from within its own callback function.
188 //
189 // It is also OK to attempt to reschedule the same q_item, if that q_item is
190 // already pending in the queue. The q_item will not be rescheduled if it is
191 // already pending.
192 //
193 // Returns true (non-zero) if the item was actually scheduled. Returns false if
194 // the item was not scheduled, which can happen if:
195 //
196 //     -- The q_item was already pending in a queue, or
197 //     -- The queue is shutting down (or not yet started up).
198 //
199 int nv_kthread_q_schedule_q_item(nv_kthread_q_t *q,
200                                  nv_kthread_q_item_t *q_item);
201 
202 // Built-in test. Returns -1 if any subtest failed, or 0 upon success.
203 int nv_kthread_q_run_self_test(void);
204 
205 #endif // __NV_KTHREAD_QUEUE_H__
206