]> git.saurik.com Git - apple/xnu.git/blob - iokit/IOKit/perfcontrol/IOPerfControl.h
xnu-7195.101.1.tar.gz
[apple/xnu.git] / iokit / IOKit / perfcontrol / IOPerfControl.h
1 /*
2 * Copyright (c) 2017 Apple Inc. All rights reserved.
3 */
4
5 #pragma once
6
7 #ifdef KERNEL_PRIVATE
8 #ifdef __cplusplus
9
10 #include <IOKit/IOService.h>
11 #include <stdatomic.h>
12 #include <kern/bits.h>
13 #include <libkern/c++/OSPtr.h>
14
15 struct thread_group;
16
17 enum{
18 kIOPerfControlClientWorkUntracked = 0,
19 };
20
21 /*!
22 * @class IOPerfControlClient : public OSObject
23 * @abstract Class which implements an interface allowing device drivers to participate in performance control.
24 * @discussion TODO
25 */
26 class IOPerfControlClient final : public OSObject
27 {
28 OSDeclareDefaultStructors(IOPerfControlClient);
29
30 protected:
31 virtual bool init(IOService *driver, uint64_t maxWorkCapacity);
32
33 public:
34 /*!
35 * @function copyClient
36 * @abstract Return a retained reference to a client object, to be released by the driver. It may be
37 * shared with other drivers in the system.
38 * @param driver The device driver that will be using this interface.
39 * @param maxWorkCapacity The maximum number of concurrent work items supported by the device driver.
40 * @returns An instance of IOPerfControlClient.
41 */
42 static IOPerfControlClient *copyClient(IOService *driver, uint64_t maxWorkCapacity);
43
44 /*!
45 * @function registerDevice
46 * @abstract Inform the system that work will be dispatched to a device in the future.
47 * @discussion The system will do some one-time setup work associated with the device, and may block the
48 * current thread during the setup. Devices should not be passed to work workSubmit, workSubmitAndBegin,
49 * workBegin, or workEnd until they have been successfully registered. The unregistration process happens
50 * automatically when the device object is deallocated.
51 * @param device The device object. Some platforms require device to be a specific subclass of IOService.
52 * @returns kIOReturnSuccess or an IOReturn error code
53 */
54 virtual IOReturn registerDevice(IOService *driver, IOService *device);
55
56 /*!
57 * @function unregisterDevice
58 * @abstract Inform the system that work will be no longer be dispatched to a device in the future.
59 * @discussion This call is optional as the unregistration process happens automatically when the device
60 * object is deallocated. This call may block the current thread and/or acquire locks. It should not be
61 * called until after all submitted work has been ended using workEnd.
62 * @param device The device object. Some platforms require device to be a specific subclass of IOService.
63 */
64 virtual void unregisterDevice(IOService *driver, IOService *device);
65
66 /*!
67 * @struct WorkSubmitArgs
68 * @discussion Drivers may submit additional device-specific arguments related to the submission of a work item
69 * by passing a struct with WorkSubmitArgs as its first member. Note: Drivers are responsible for publishing
70 * a header file describing these arguments.
71 */
72 struct WorkSubmitArgs {
73 uint32_t version;
74 uint32_t size;
75 uint64_t submit_time;
76 uint64_t reserved[4];
77 void *driver_data;
78 };
79
80 /*!
81 * @function workSubmit
82 * @abstract Tell the performance controller that work was submitted.
83 * @param device The device that will execute the work. Some platforms require device to be a
84 * specific subclass of IOService.
85 * @param args Optional device-specific arguments related to the submission of this work item.
86 * @returns A token representing this work item, which must be passed to workEnd when the work is finished
87 * unless the token equals kIOPerfControlClientWorkUntracked. Failure to do this will result in memory leaks
88 * and a degradation of system performance.
89 */
90 virtual uint64_t workSubmit(IOService *device, WorkSubmitArgs *args = nullptr);
91
92 /*!
93 * @struct WorkBeginArgs
94 * @discussion Drivers may submit additional device-specific arguments related to the start of a work item
95 * by passing a struct with WorkBeginArgs as its first member. Note: Drivers are responsible for publishing
96 * a header file describing these arguments.
97 */
98 struct WorkBeginArgs {
99 uint32_t version;
100 uint32_t size;
101 uint64_t begin_time;
102 uint64_t reserved[4];
103 void *driver_data;
104 };
105
106 /*!
107 * @function workSubmitAndBegin
108 * @abstract Tell the performance controller that work was submitted and immediately began executing.
109 * @param device The device that is executing the work. Some platforms require device to be a
110 * specific subclass of IOService.
111 * @param submitArgs Optional device-specific arguments related to the submission of this work item.
112 * @param beginArgs Optional device-specific arguments related to the start of this work item.
113 * @returns A token representing this work item, which must be passed to workEnd when the work is finished
114 * unless the token equals kIOPerfControlClientWorkUntracked. Failure to do this will result in memory leaks
115 * and a degradation of system performance.
116 */
117 virtual uint64_t workSubmitAndBegin(IOService *device, WorkSubmitArgs *submitArgs = nullptr,
118 WorkBeginArgs *beginArgs = nullptr);
119
120 /*!
121 * @function workBegin
122 * @abstract Tell the performance controller that previously submitted work began executing.
123 * @param device The device that is executing the work. Some platforms require device to be a
124 * specific subclass of IOService.
125 * @param args Optional device-specific arguments related to the start of this work item.
126 */
127 virtual void workBegin(IOService *device, uint64_t token, WorkBeginArgs *args = nullptr);
128
129 /*!
130 * @struct WorkEndArgs
131 * @discussion Drivers may submit additional device-specific arguments related to the end of a work item
132 * by passing a struct with WorkEndArgs as its first member. Note: Drivers are responsible for publishing
133 * a header file describing these arguments.
134 */
135 struct WorkEndArgs {
136 uint32_t version;
137 uint32_t size;
138 uint64_t end_time;
139 uint64_t reserved[4];
140 void *driver_data;
141 };
142
143 /*!
144 * @function workEnd
145 * @abstract Tell the performance controller that previously started work finished executing.
146 * @param device The device that executed the work. Some platforms require device to be a
147 * specific subclass of IOService.
148 * @param args Optional device-specific arguments related to the end of this work item.
149 * @param done Optional Set to false if the work has not yet completed. Drivers are then responsible for
150 * calling workBegin when the work resumes and workEnd with done set to True when it has completed. A workEnd() call
151 * without a corresponding workBegin() call is a way to cancel a work item and return token to IOPerfControl.
152 */
153 virtual void workEnd(IOService *device, uint64_t token, WorkEndArgs *args = nullptr, bool done = true);
154
155 /*!
156 * @function copyWorkContext
157 * @abstract Return a retained reference to an opaque OSObject, to be released by the driver. This object can
158 * be used by IOPerfControl to track a work item. This may perform dynamic memory allocation.
159 * @returns A pointer to an OSObject
160 */
161 OSPtr<OSObject> copyWorkContext();
162
163 /*!
164 * @function workSubmitAndBeginWithContext
165 * @abstract Tell the performance controller that work was submitted and immediately began executing
166 * @param device The device that is executing the work. Some platforms require device to be a
167 * specific subclass of IOService.
168 * @param context An OSObject returned by copyWorkContext(). The context object will be used by IOPerfControl to track
169 * this work item.
170 * @param submitArgs Optional device-specific arguments related to the submission of this work item.
171 * @param beginArgs Optional device-specific arguments related to the start of this work item.
172 * @returns true if IOPerfControl is tracking this work item, else false.
173 * @note The workEndWithContext() call is optional if the corresponding workSubmitWithContext() call returned false.
174 */
175 bool workSubmitAndBeginWithContext(IOService *device, OSObject *context, WorkSubmitArgs *submitArgs = nullptr,
176 WorkBeginArgs *beginArgs = nullptr);
177
178 /*!
179 * @function workSubmitWithContext
180 * @abstract Tell the performance controller that work was submitted.
181 * @param device The device that will execute the work. Some platforms require device to be a
182 * specific subclass of IOService.
183 * @param context An OSObject returned by copyWorkContext(). The context object will be used by IOPerfControl to track
184 * this work item.
185 * @param args Optional device-specific arguments related to the submission of this work item.
186 * @returns true if IOPerfControl is tracking this work item, else false.
187 */
188 bool workSubmitWithContext(IOService *device, OSObject *context, WorkSubmitArgs *args = nullptr);
189
190 /*!
191 * @function workBeginWithContext
192 * @abstract Tell the performance controller that previously submitted work began executing.
193 * @param device The device that is executing the work. Some platforms require device to be a
194 * specific subclass of IOService.
195 * @param context An OSObject returned by copyWorkContext() and provided to the previous call to workSubmitWithContext().
196 * @param args Optional device-specific arguments related to the start of this work item.
197 * @note The workBeginWithContext() and workEndWithContext() calls are optional if the corresponding workSubmitWithContext() call returned false.
198 */
199 void workBeginWithContext(IOService *device, OSObject *context, WorkBeginArgs *args = nullptr);
200
201 /*!
202 * @function workEndWithContext
203 * @abstract Tell the performance controller that previously started work finished executing.
204 * @param device The device that executed the work. Some platforms require device to be a
205 * specific subclass of IOService.
206 * @param context An OSObject returned by copyWorkContext() and provided to the previous call to workSubmitWithContext().
207 * @param args Optional device-specific arguments related to the end of this work item.
208 * @param done Optional Set to false if the work has not yet completed. Drivers are then responsible for
209 * calling workBegin when the work resumes and workEnd with done set to True when it has completed.
210 * @note The workEndWithContext() call is optional if the corresponding workSubmitWithContext() call returned false. A workEndWithContext()
211 * call without a corresponding workBeginWithContext() call is a way to cancel a work item.
212 */
213 void workEndWithContext(IOService *device, OSObject *context, WorkEndArgs *args = nullptr, bool done = true);
214
215 /*!
216 * @struct PerfControllerInterface
217 * @discussion Function pointers necessary to register a performance controller. Not for general driver use.
218 */
219 struct PerfControllerInterface {
220 struct WorkState {
221 uint64_t thread_group_id;
222 void *thread_group_data;
223 void *work_data;
224 uint32_t work_data_size;
225 uint32_t started : 1;
226 uint32_t reserved : 31;
227 };
228
229 using RegisterDeviceFunction = IOReturn (*)(IOService *);
230 using WorkCanSubmitFunction = bool (*)(IOService *, WorkState *, WorkSubmitArgs *);
231 using WorkSubmitFunction = void (*)(IOService *, uint64_t, WorkState *, WorkSubmitArgs *);
232 using WorkBeginFunction = void (*)(IOService *, uint64_t, WorkState *, WorkBeginArgs *);
233 using WorkEndFunction = void (*)(IOService *, uint64_t, WorkState *, WorkEndArgs *, bool);
234
235 uint64_t version;
236 RegisterDeviceFunction registerDevice;
237 RegisterDeviceFunction unregisterDevice;
238 WorkCanSubmitFunction workCanSubmit;
239 WorkSubmitFunction workSubmit;
240 WorkBeginFunction workBegin;
241 WorkEndFunction workEnd;
242 };
243
244 struct IOPerfControlClientShared {
245 atomic_uint_fast8_t maxDriverIndex;
246 PerfControllerInterface interface;
247 IOLock *interfaceLock;
248 OSSet *deviceRegistrationList;
249 };
250
251 /*!
252 * @function registerPerformanceController
253 * @abstract Register a performance controller to receive callbacks. Not for general driver use.
254 * @param interface Struct containing callback functions implemented by the performance controller.
255 * @returns kIOReturnSuccess or kIOReturnError if the interface was already registered.
256 */
257 virtual IOReturn registerPerformanceController(PerfControllerInterface interface);
258
259 private:
260 struct WorkTableEntry {
261 struct thread_group *thread_group;
262 bool started;
263 uint8_t perfcontrol_data[32];
264 };
265
266 static constexpr size_t kMaxWorkTableNumEntries = 1024;
267 static constexpr size_t kWorkTableIndexBits = 24;
268 static constexpr size_t kWorkTableMaxSize = (1 << kWorkTableIndexBits) - 1; // - 1 since
269 // kIOPerfControlClientWorkUntracked takes number 0
270 static constexpr size_t kWorkTableIndexMask = (const size_t)mask(kWorkTableIndexBits);
271
272 uint64_t allocateToken(thread_group *thread_group);
273 void deallocateToken(uint64_t token);
274 WorkTableEntry *getEntryForToken(uint64_t token);
275 void markEntryStarted(uint64_t token, bool started);
276 inline uint64_t tokenToGlobalUniqueToken(uint64_t token);
277
278 uint8_t driverIndex;
279 IOPerfControlClientShared *shared;
280 WorkTableEntry *workTable;
281 size_t workTableLength;
282 size_t workTableNextIndex;
283 IOSimpleLock *workTableLock;
284 };
285
286 #endif /* __cplusplus */
287 #endif /* KERNEL_PRIVATE */