2 * Copyright (c) 2017 Apple Inc. All rights reserved.
10 #include <IOKit/IOService.h>
11 #include <stdatomic.h>
12 #include <kern/bits.h>
17 kIOPerfControlClientWorkUntracked
= 0,
21 * @class IOPerfControlClient : public OSObject
22 * @abstract Class which implements an interface allowing device drivers to participate in performance control.
25 class IOPerfControlClient final
: public OSObject
27 OSDeclareDefaultStructors(IOPerfControlClient
);
30 virtual bool init(IOService
*driver
, uint64_t maxWorkCapacity
);
34 * @function copyClient
35 * @abstract Return a retained reference to a client object, to be released by the driver. It may be
36 * shared with other drivers in the system.
37 * @param driver The device driver that will be using this interface.
38 * @param maxWorkCapacity The maximum number of concurrent work items supported by the device driver.
39 * @returns An instance of IOPerfControlClient.
41 static IOPerfControlClient
*copyClient(IOService
*driver
, uint64_t maxWorkCapacity
);
44 * @function registerDevice
45 * @abstract Inform the system that work will be dispatched to a device in the future.
46 * @discussion The system will do some one-time setup work associated with the device, and may block the
47 * current thread during the setup. Devices should not be passed to work workSubmit, workSubmitAndBegin,
48 * workBegin, or workEnd until they have been successfully registered. The unregistration process happens
49 * automatically when the device object is deallocated.
50 * @param device The device object. Some platforms require device to be a specific subclass of IOService.
51 * @returns kIOReturnSuccess or an IOReturn error code
53 virtual IOReturn
registerDevice(IOService
*driver
, IOService
*device
);
56 * @function unregisterDevice
57 * @abstract Inform the system that work will be no longer be dispatched to a device in the future.
58 * @discussion This call is optional as the unregistration process happens automatically when the device
59 * object is deallocated. This call may block the current thread and/or acquire locks. It should not be
60 * called until after all submitted work has been ended using workEnd.
61 * @param device The device object. Some platforms require device to be a specific subclass of IOService.
63 virtual void unregisterDevice(IOService
*driver
, IOService
*device
);
66 * @struct WorkSubmitArgs
67 * @discussion Drivers may submit additional device-specific arguments related to the submission of a work item
68 * by passing a struct with WorkSubmitArgs as its first member. Note: Drivers are responsible for publishing
69 * a header file describing these arguments.
71 struct WorkSubmitArgs
{
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.
89 virtual uint64_t workSubmit(IOService
*device
, WorkSubmitArgs
*args
= nullptr);
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.
97 struct WorkBeginArgs
{
101 uint64_t reserved
[4];
106 * @function workSubmitAndBegin
107 * @abstract Tell the performance controller that work was submitted and immediately began executing.
108 * @param device The device that is executing the work. Some platforms require device to be a
109 * specific subclass of IOService.
110 * @param submitArgs Optional device-specific arguments related to the submission of this work item.
111 * @param beginArgs Optional device-specific arguments related to the start of this work item.
112 * @returns A token representing this work item, which must be passed to workEnd when the work is finished
113 * unless the token equals kIOPerfControlClientWorkUntracked. Failure to do this will result in memory leaks
114 * and a degradation of system performance.
116 virtual uint64_t workSubmitAndBegin(IOService
*device
, WorkSubmitArgs
*submitArgs
= nullptr,
117 WorkBeginArgs
*beginArgs
= nullptr);
120 * @function workBegin
121 * @abstract Tell the performance controller that previously submitted work began executing.
122 * @param device The device that is executing the work. Some platforms require device to be a
123 * specific subclass of IOService.
124 * @param args Optional device-specific arguments related to the start of this work item.
126 virtual void workBegin(IOService
*device
, uint64_t token
, WorkBeginArgs
*args
= nullptr);
129 * @struct WorkEndArgs
130 * @discussion Drivers may submit additional device-specific arguments related to the end of a work item
131 * by passing a struct with WorkEndArgs as its first member. Note: Drivers are responsible for publishing
132 * a header file describing these arguments.
138 uint64_t reserved
[4];
144 * @abstract Tell the performance controller that previously started work finished executing.
145 * @param device The device that executed the work. Some platforms require device to be a
146 * specific subclass of IOService.
147 * @param args Optional device-specific arguments related to the end of this work item.
148 * @param done Optional Set to false if the work has not yet completed. Drivers are then responsible for
149 * calling workBegin when the work resumes and workEnd with done set to True when it has completed.
151 virtual void workEnd(IOService
*device
, uint64_t token
, WorkEndArgs
*args
= nullptr, bool done
= true);
154 * @struct PerfControllerInterface
155 * @discussion Function pointers necessary to register a performance controller. Not for general driver use.
157 struct PerfControllerInterface
{
159 uint64_t thread_group_id
;
160 void *thread_group_data
;
162 uint32_t work_data_size
;
165 using RegisterDeviceFunction
= IOReturn (*)(IOService
*);
166 using WorkCanSubmitFunction
= bool (*)(IOService
*, WorkState
*, WorkSubmitArgs
*);
167 using WorkSubmitFunction
= void (*)(IOService
*, uint64_t, WorkState
*, WorkSubmitArgs
*);
168 using WorkBeginFunction
= void (*)(IOService
*, uint64_t, WorkState
*, WorkBeginArgs
*);
169 using WorkEndFunction
= void (*)(IOService
*, uint64_t, WorkState
*, WorkEndArgs
*, bool);
172 RegisterDeviceFunction registerDevice
;
173 RegisterDeviceFunction unregisterDevice
;
174 WorkCanSubmitFunction workCanSubmit
;
175 WorkSubmitFunction workSubmit
;
176 WorkBeginFunction workBegin
;
177 WorkEndFunction workEnd
;
180 struct IOPerfControlClientShared
{
181 atomic_uint_fast8_t maxDriverIndex
;
182 PerfControllerInterface interface
;
183 IOLock
*interfaceLock
;
184 OSSet
*deviceRegistrationList
;
188 * @function registerPerformanceController
189 * @abstract Register a performance controller to receive callbacks. Not for general driver use.
190 * @param interface Struct containing callback functions implemented by the performance controller.
191 * @returns kIOReturnSuccess or kIOReturnError if the interface was already registered.
193 virtual IOReturn
registerPerformanceController(PerfControllerInterface interface
);
196 struct WorkTableEntry
{
197 struct thread_group
*thread_group
;
199 uint8_t perfcontrol_data
[32];
202 static constexpr size_t kMaxWorkTableNumEntries
= 1024;
203 static constexpr size_t kWorkTableIndexBits
= 24;
204 static constexpr size_t kWorkTableMaxSize
= (1 << kWorkTableIndexBits
) - 1; // - 1 since
205 // kIOPerfControlClientWorkUntracked takes number 0
206 static constexpr size_t kWorkTableIndexMask
= mask(kWorkTableIndexBits
);
208 uint64_t allocateToken(thread_group
*thread_group
);
209 void deallocateToken(uint64_t token
);
210 bool getEntryForToken(uint64_t token
, WorkTableEntry
&entry
);
211 void markEntryStarted(uint64_t token
, bool started
);
212 inline uint64_t tokenToGlobalUniqueToken(uint64_t token
);
215 IOPerfControlClientShared
*shared
;
216 WorkTableEntry
*workTable
;
217 size_t workTableLength
;
218 size_t workTableNextIndex
;
219 IOSimpleLock
*workTableLock
;
222 #endif /* __cplusplus */
223 #endif /* KERNEL_PRIVATE */