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
);
15 bool IOPerfControlClient::init(IOService
*driver
, uint64_t maxWorkCapacity
)
20 interface
= PerfControllerInterface
{
23 [](IOService
*device
) {
24 return kIOReturnSuccess
;
27 [](IOService
*device
) {
28 return kIOReturnSuccess
;
31 [](IOService
*device
, PerfControllerInterface::WorkState
*state
, WorkSubmitArgs
*args
) {
35 [](IOService
*device
, uint64_t token
, PerfControllerInterface::WorkState
*state
, WorkSubmitArgs
*args
) {
38 [](IOService
*device
, uint64_t token
, PerfControllerInterface::WorkState
*state
, WorkBeginArgs
*args
) {
41 [](IOService
*device
, uint64_t token
, PerfControllerInterface::WorkState
*state
, WorkEndArgs
*args
, bool done
) {
45 interfaceLock
= IOLockAlloc();
49 deviceRegistrationList
= OSSet::withCapacity(4);
50 if (!deviceRegistrationList
)
53 bzero(workTable
, sizeof(workTable
));
54 memset(&workTable
[kIOPerfControlClientWorkUntracked
], ~0, sizeof(WorkTableEntry
));
55 workTableNextIndex
= kIOPerfControlClientWorkUntracked
+ 1;
57 workTableLock
= IOSimpleLockAlloc();
61 // TODO: check sum(maxWorkCapacities) < table size
67 IOLockFree(interfaceLock
);
68 if (deviceRegistrationList
)
69 deviceRegistrationList
->release();
71 IOSimpleLockFree(workTableLock
);
75 IOPerfControlClient
*_Atomic gSharedClient
= nullptr;
77 IOPerfControlClient
*IOPerfControlClient::copyClient(IOService
*driver
, uint64_t maxWorkCapacity
)
79 IOPerfControlClient
*client
= atomic_load_explicit(&gSharedClient
, memory_order_acquire
);
80 if (client
== nullptr) {
81 IOPerfControlClient
*expected
= client
;
82 client
= new IOPerfControlClient
;
83 if (!client
|| !client
->init(driver
, maxWorkCapacity
))
84 panic("could not create IOPerfControlClient");
85 if (!atomic_compare_exchange_strong_explicit(&gSharedClient
, &expected
, client
, memory_order_acq_rel
,
86 memory_order_acquire
)) {
91 // TODO: add maxWorkCapacity to existing client
96 uint64_t IOPerfControlClient::allocateToken(thread_group
*thread_group
)
98 uint64_t token
= kIOPerfControlClientWorkUntracked
;
104 void IOPerfControlClient::deallocateToken(uint64_t token
)
108 bool IOPerfControlClient::getEntryForToken(uint64_t token
, IOPerfControlClient::WorkTableEntry
&entry
)
110 if (token
== kIOPerfControlClientWorkUntracked
)
113 if (token
>= kWorkTableNumEntries
)
114 panic("Invalid work token (%llu): index out of bounds.", token
);
116 entry
= workTable
[token
];
117 auto *thread_group
= entry
.thread_group
;
118 assertf(thread_group
, "Invalid work token: %llu", token
);
119 return thread_group
!= nullptr;
122 void IOPerfControlClient::markEntryStarted(uint64_t token
, bool started
)
124 if (token
== kIOPerfControlClientWorkUntracked
)
127 if (token
>= kWorkTableNumEntries
)
128 panic("Invalid work token (%llu): index out of bounds.", token
);
130 workTable
[token
].started
= started
;
133 IOReturn
IOPerfControlClient::registerDevice(__unused IOService
*driver
, IOService
*device
)
135 IOReturn ret
= kIOReturnSuccess
;
137 IOLockLock(interfaceLock
);
139 if (interface
.version
> 0)
140 ret
= interface
.registerDevice(device
);
142 deviceRegistrationList
->setObject(device
);
144 IOLockUnlock(interfaceLock
);
149 void IOPerfControlClient::unregisterDevice(__unused IOService
*driver
, IOService
*device
)
151 IOLockLock(interfaceLock
);
153 if (interface
.version
> 0)
154 interface
.unregisterDevice(device
);
156 deviceRegistrationList
->removeObject(device
);
158 IOLockUnlock(interfaceLock
);
161 uint64_t IOPerfControlClient::workSubmit(IOService
*device
, WorkSubmitArgs
*args
)
163 return kIOPerfControlClientWorkUntracked
;
166 uint64_t IOPerfControlClient::workSubmitAndBegin(IOService
*device
, WorkSubmitArgs
*submitArgs
, WorkBeginArgs
*beginArgs
)
168 return kIOPerfControlClientWorkUntracked
;
171 void IOPerfControlClient::workBegin(IOService
*device
, uint64_t token
, WorkBeginArgs
*args
)
175 void IOPerfControlClient::workEnd(IOService
*device
, uint64_t token
, WorkEndArgs
*args
, bool done
)
179 IOReturn
IOPerfControlClient::registerPerformanceController(PerfControllerInterface pci
)
181 IOReturn result
= kIOReturnError
;
183 IOLockLock(interfaceLock
);
185 if (interface
.version
== 0 && pci
.version
> 0) {
186 assert(pci
.registerDevice
&& pci
.unregisterDevice
&& pci
.workCanSubmit
&& pci
.workSubmit
&& pci
.workBegin
&& pci
.workEnd
);
187 result
= kIOReturnSuccess
;
190 while ((obj
= deviceRegistrationList
->getAnyObject())) {
191 IOService
*device
= OSDynamicCast(IOService
, obj
);
193 pci
.registerDevice(device
);
194 deviceRegistrationList
->removeObject(obj
);
200 IOLockUnlock(interfaceLock
);