2 * Copyright (c) 2017 Apple Inc. All rights reserved.
5 #include <IOKit/perfcontrol/IOPerfControl.h>
9 #include <kern/thread_group.h>
12 #define super OSObject
13 OSDefineMetaClassAndStructors(IOPerfControlClient
, OSObject
);
16 IOPerfControlClient::init(IOService
*driver
, uint64_t maxWorkCapacity
)
22 interface
= PerfControllerInterface
{
25 [](IOService
*device
) {
26 return kIOReturnSuccess
;
29 [](IOService
*device
) {
30 return kIOReturnSuccess
;
33 [](IOService
*device
, PerfControllerInterface::WorkState
*state
, WorkSubmitArgs
*args
) {
37 [](IOService
*device
, uint64_t token
, PerfControllerInterface::WorkState
*state
, WorkSubmitArgs
*args
) {
40 [](IOService
*device
, uint64_t token
, PerfControllerInterface::WorkState
*state
, WorkBeginArgs
*args
) {
43 [](IOService
*device
, uint64_t token
, PerfControllerInterface::WorkState
*state
, WorkEndArgs
*args
, bool done
) {
47 interfaceLock
= IOLockAlloc();
52 deviceRegistrationList
= OSSet::withCapacity(4);
53 if (!deviceRegistrationList
) {
57 bzero(workTable
, sizeof(workTable
));
58 memset(&workTable
[kIOPerfControlClientWorkUntracked
], ~0, sizeof(WorkTableEntry
));
59 workTableNextIndex
= kIOPerfControlClientWorkUntracked
+ 1;
61 workTableLock
= IOSimpleLockAlloc();
66 // TODO: check sum(maxWorkCapacities) < table size
72 IOLockFree(interfaceLock
);
74 if (deviceRegistrationList
) {
75 deviceRegistrationList
->release();
78 IOSimpleLockFree(workTableLock
);
83 IOPerfControlClient
*_Atomic gSharedClient
= nullptr;
86 IOPerfControlClient::copyClient(IOService
*driver
, uint64_t maxWorkCapacity
)
88 IOPerfControlClient
*client
= atomic_load_explicit(&gSharedClient
, memory_order_acquire
);
89 if (client
== nullptr) {
90 IOPerfControlClient
*expected
= client
;
91 client
= new IOPerfControlClient
;
92 if (!client
|| !client
->init(driver
, maxWorkCapacity
)) {
93 panic("could not create IOPerfControlClient");
95 if (!atomic_compare_exchange_strong_explicit(&gSharedClient
, &expected
, client
, memory_order_acq_rel
,
96 memory_order_acquire
)) {
101 // TODO: add maxWorkCapacity to existing client
107 IOPerfControlClient::allocateToken(thread_group
*thread_group
)
109 uint64_t token
= kIOPerfControlClientWorkUntracked
;
116 IOPerfControlClient::deallocateToken(uint64_t token
)
121 IOPerfControlClient::getEntryForToken(uint64_t token
, IOPerfControlClient::WorkTableEntry
&entry
)
123 if (token
== kIOPerfControlClientWorkUntracked
) {
127 if (token
>= kWorkTableNumEntries
) {
128 panic("Invalid work token (%llu): index out of bounds.", token
);
131 entry
= workTable
[token
];
132 auto *thread_group
= entry
.thread_group
;
133 assertf(thread_group
, "Invalid work token: %llu", token
);
134 return thread_group
!= nullptr;
138 IOPerfControlClient::markEntryStarted(uint64_t token
, bool started
)
140 if (token
== kIOPerfControlClientWorkUntracked
) {
144 if (token
>= kWorkTableNumEntries
) {
145 panic("Invalid work token (%llu): index out of bounds.", token
);
148 workTable
[token
].started
= started
;
152 IOPerfControlClient::registerDevice(__unused IOService
*driver
, IOService
*device
)
154 IOReturn ret
= kIOReturnSuccess
;
156 IOLockLock(interfaceLock
);
158 if (interface
.version
> 0) {
159 ret
= interface
.registerDevice(device
);
161 deviceRegistrationList
->setObject(device
);
164 IOLockUnlock(interfaceLock
);
170 IOPerfControlClient::unregisterDevice(__unused IOService
*driver
, IOService
*device
)
172 IOLockLock(interfaceLock
);
174 if (interface
.version
> 0) {
175 interface
.unregisterDevice(device
);
177 deviceRegistrationList
->removeObject(device
);
180 IOLockUnlock(interfaceLock
);
184 IOPerfControlClient::workSubmit(IOService
*device
, WorkSubmitArgs
*args
)
186 return kIOPerfControlClientWorkUntracked
;
190 IOPerfControlClient::workSubmitAndBegin(IOService
*device
, WorkSubmitArgs
*submitArgs
, WorkBeginArgs
*beginArgs
)
192 return kIOPerfControlClientWorkUntracked
;
196 IOPerfControlClient::workBegin(IOService
*device
, uint64_t token
, WorkBeginArgs
*args
)
201 IOPerfControlClient::workEnd(IOService
*device
, uint64_t token
, WorkEndArgs
*args
, bool done
)
206 IOPerfControlClient::registerPerformanceController(PerfControllerInterface pci
)
208 IOReturn result
= kIOReturnError
;
210 IOLockLock(interfaceLock
);
212 if (interface
.version
== 0 && pci
.version
> 0) {
213 assert(pci
.registerDevice
&& pci
.unregisterDevice
&& pci
.workCanSubmit
&& pci
.workSubmit
&& pci
.workBegin
&& pci
.workEnd
);
214 result
= kIOReturnSuccess
;
217 while ((obj
= deviceRegistrationList
->getAnyObject())) {
218 IOService
*device
= OSDynamicCast(IOService
, obj
);
220 pci
.registerDevice(device
);
222 deviceRegistrationList
->removeObject(obj
);
228 IOLockUnlock(interfaceLock
);