]> git.saurik.com Git - apple/xnu.git/blob - iokit/IOKit/perfcontrol/IOPerfControl.h
xnu-4903.221.2.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
12 struct thread_group;
13
14 enum
15 {
16 kIOPerfControlClientWorkUntracked = 0,
17 };
18
19 /*!
20 * @class IOPerfControlClient : public OSObject
21 * @abstract Class which implements an interface allowing device drivers to participate in performance control.
22 * @discussion TODO
23 */
24 class IOPerfControlClient final : public OSObject
25 {
26 OSDeclareDefaultStructors(IOPerfControlClient);
27
28 protected:
29 virtual bool init(IOService *driver, uint64_t maxWorkCapacity);
30
31 public:
32 /*!
33 * @function copyClient
34 * @abstract Return a retained reference to a client object, to be released by the driver. It may be
35 * shared with other drivers in the system.
36 * @param driver The device driver that will be using this interface.
37 * @param maxWorkCapacity The maximum number of concurrent work items supported by the device driver.
38 * @returns An instance of IOPerfControlClient.
39 */
40 static IOPerfControlClient *copyClient(IOService *driver, uint64_t maxWorkCapacity);
41
42 /*!
43 * @function registerDevice
44 * @abstract Inform the system that work will be dispatched to a device in the future.
45 * @discussion The system will do some one-time setup work associated with the device, and may block the
46 * current thread during the setup. Devices should not be passed to work workSubmit, workSubmitAndBegin,
47 * workBegin, or workEnd until they have been successfully registered. The unregistration process happens
48 * automatically when the device object is deallocated.
49 * @param device The device object. Some platforms require device to be a specific subclass of IOService.
50 * @returns kIOReturnSuccess or an IOReturn error code
51 */
52 virtual IOReturn registerDevice(IOService *driver, IOService *device);
53
54 /*!
55 * @function unregisterDevice
56 * @abstract Inform the system that work will be no longer be dispatched to a device in the future.
57 * @discussion This call is optional as the unregistration process happens automatically when the device
58 * object is deallocated. This call may block the current thread and/or acquire locks. It should not be
59 * called until after all submitted work has been ended using workEnd.
60 * @param device The device object. Some platforms require device to be a specific subclass of IOService.
61 */
62 virtual void unregisterDevice(IOService *driver, IOService *device);
63
64 /*!
65 * @struct WorkSubmitArgs
66 * @discussion Drivers may submit additional device-specific arguments related to the submission of a work item
67 * by passing a struct with WorkSubmitArgs as its first member. Note: Drivers are responsible for publishing
68 * a header file describing these arguments.
69 */
70 struct WorkSubmitArgs
71 {
72 uint32_t version;
73 uint32_t size;
74 uint64_t submit_time;
75 uint64_t reserved[4];
76 void *driver_data;
77 };
78
79 /*!
80 * @function workSubmit
81 * @abstract Tell the performance controller that work was submitted.
82 * @param device The device that will execute the work. Some platforms require device to be a
83 * specific subclass of IOService.
84 * @param args Optional device-specific arguments related to the submission of this work item.
85 * @returns A token representing this work item, which must be passed to workEnd when the work is finished
86 * unless the token equals kIOPerfControlClientWorkUntracked. Failure to do this will result in memory leaks
87 * and a degradation of system performance.
88 */
89 virtual uint64_t workSubmit(IOService *device, WorkSubmitArgs *args = nullptr);
90
91 /*!
92 * @struct WorkBeginArgs
93 * @discussion Drivers may submit additional device-specific arguments related to the start of a work item
94 * by passing a struct with WorkBeginArgs as its first member. Note: Drivers are responsible for publishing
95 * a header file describing these arguments.
96 */
97 struct WorkBeginArgs
98 {
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 {
137 uint32_t version;
138 uint32_t size;
139 uint64_t end_time;
140 uint64_t reserved[4];
141 void *driver_data;
142 };
143
144 /*!
145 * @function workEnd
146 * @abstract Tell the performance controller that previously started work finished executing.
147 * @param device The device that executed the work. Some platforms require device to be a
148 * specific subclass of IOService.
149 * @param args Optional device-specific arguments related to the end of this work item.
150 * @param done Optional Set to false if the work has not yet completed. Drivers are then responsible for
151 * calling workBegin when the work resumes and workEnd with done set to True when it has completed.
152 */
153 virtual void workEnd(IOService *device, uint64_t token, WorkEndArgs *args = nullptr, bool done = true);
154
155 /*!
156 * @struct PerfControllerInterface
157 * @discussion Function pointers necessary to register a performance controller. Not for general driver use.
158 */
159 struct PerfControllerInterface
160 {
161 struct WorkState {
162 uint64_t thread_group_id;
163 void *thread_group_data;
164 void *work_data;
165 uint32_t work_data_size;
166 };
167
168 using RegisterDeviceFunction = IOReturn (*)(IOService *);
169 using WorkCanSubmitFunction = bool (*)(IOService *, WorkState *, WorkSubmitArgs *);
170 using WorkSubmitFunction = void (*)(IOService *, uint64_t, WorkState *, WorkSubmitArgs *);
171 using WorkBeginFunction = void (*)(IOService *, uint64_t, WorkState *, WorkBeginArgs *);
172 using WorkEndFunction = void (*)(IOService *, uint64_t, WorkState *, WorkEndArgs *, bool);
173
174 uint64_t version;
175 RegisterDeviceFunction registerDevice;
176 RegisterDeviceFunction unregisterDevice;
177 WorkCanSubmitFunction workCanSubmit;
178 WorkSubmitFunction workSubmit;
179 WorkBeginFunction workBegin;
180 WorkEndFunction workEnd;
181 };
182
183 /*!
184 * @function registerPerformanceController
185 * @abstract Register a performance controller to receive callbacks. Not for general driver use.
186 * @param interface Struct containing callback functions implemented by the performance controller.
187 * @returns kIOReturnSuccess or kIOReturnError if the interface was already registered.
188 */
189 virtual IOReturn registerPerformanceController(PerfControllerInterface interface);
190
191 private:
192 struct WorkTableEntry
193 {
194 struct thread_group *thread_group;
195 bool started;
196 uint8_t perfcontrol_data[32];
197 };
198
199 // TODO: size of table should match sum(maxWorkCapacity) of all users
200 static constexpr size_t kWorkTableNumEntries = 1024;
201
202 uint64_t allocateToken(thread_group *thread_group);
203 void deallocateToken(uint64_t token);
204 bool getEntryForToken(uint64_t token, WorkTableEntry &entry);
205 void markEntryStarted(uint64_t token, bool started);
206
207 PerfControllerInterface interface;
208 IOLock *interfaceLock;
209 OSSet *deviceRegistrationList;
210
211 // TODO: replace with ltable or pool of objects
212 WorkTableEntry workTable[kWorkTableNumEntries];
213 size_t workTableNextIndex;
214 IOSimpleLock *workTableLock;
215 };
216
217 #endif /* __cplusplus */
218 #endif /* KERNEL_PRIVATE */