1*33de042dSApple OSS Distributions /*
2*33de042dSApple OSS Distributions * Copyright (c) 2017 Apple Inc. All rights reserved.
3*33de042dSApple OSS Distributions */
4*33de042dSApple OSS Distributions
5*33de042dSApple OSS Distributions #include <IOKit/perfcontrol/IOPerfControl.h>
6*33de042dSApple OSS Distributions
7*33de042dSApple OSS Distributions #include <stdatomic.h>
8*33de042dSApple OSS Distributions
9*33de042dSApple OSS Distributions #include <kern/thread_group.h>
10*33de042dSApple OSS Distributions #include <kern/task.h>
11*33de042dSApple OSS Distributions #include <sys/coalition.h>
12*33de042dSApple OSS Distributions #include <kern/coalition.h>
13*33de042dSApple OSS Distributions
14*33de042dSApple OSS Distributions #undef super
15*33de042dSApple OSS Distributions #define super OSObject
16*33de042dSApple OSS Distributions OSDefineMetaClassAndStructors(IOPerfControlClient, OSObject);
17*33de042dSApple OSS Distributions
18*33de042dSApple OSS Distributions static IOPerfControlClient::IOPerfControlClientShared *_Atomic gIOPerfControlClientShared;
19*33de042dSApple OSS Distributions
20*33de042dSApple OSS Distributions bool
init(IOService * driver,uint64_t maxWorkCapacity)21*33de042dSApple OSS Distributions IOPerfControlClient::init(IOService *driver, uint64_t maxWorkCapacity)
22*33de042dSApple OSS Distributions {
23*33de042dSApple OSS Distributions // TODO: Remove this limit and implement dynamic table growth if workloads are found that exceed this
24*33de042dSApple OSS Distributions if (maxWorkCapacity > kMaxWorkTableNumEntries) {
25*33de042dSApple OSS Distributions maxWorkCapacity = kMaxWorkTableNumEntries;
26*33de042dSApple OSS Distributions }
27*33de042dSApple OSS Distributions
28*33de042dSApple OSS Distributions if (!super::init()) {
29*33de042dSApple OSS Distributions return false;
30*33de042dSApple OSS Distributions }
31*33de042dSApple OSS Distributions
32*33de042dSApple OSS Distributions shared = atomic_load_explicit(&gIOPerfControlClientShared, memory_order_acquire);
33*33de042dSApple OSS Distributions if (shared == nullptr) {
34*33de042dSApple OSS Distributions IOPerfControlClient::IOPerfControlClientShared *expected = shared;
35*33de042dSApple OSS Distributions shared = kalloc_type(IOPerfControlClientShared, Z_WAITOK);
36*33de042dSApple OSS Distributions if (!shared) {
37*33de042dSApple OSS Distributions return false;
38*33de042dSApple OSS Distributions }
39*33de042dSApple OSS Distributions
40*33de042dSApple OSS Distributions atomic_init(&shared->maxDriverIndex, 0);
41*33de042dSApple OSS Distributions
42*33de042dSApple OSS Distributions shared->interface = PerfControllerInterface{
43*33de042dSApple OSS Distributions .version = PERFCONTROL_INTERFACE_VERSION_NONE,
44*33de042dSApple OSS Distributions .registerDevice =
45*33de042dSApple OSS Distributions [](IOService *device) {
46*33de042dSApple OSS Distributions return kIOReturnSuccess;
47*33de042dSApple OSS Distributions },
48*33de042dSApple OSS Distributions .unregisterDevice =
49*33de042dSApple OSS Distributions [](IOService *device) {
50*33de042dSApple OSS Distributions return kIOReturnSuccess;
51*33de042dSApple OSS Distributions },
52*33de042dSApple OSS Distributions .workCanSubmit =
53*33de042dSApple OSS Distributions [](IOService *device, PerfControllerInterface::WorkState *state, WorkSubmitArgs *args) {
54*33de042dSApple OSS Distributions return false;
55*33de042dSApple OSS Distributions },
56*33de042dSApple OSS Distributions .workSubmit =
57*33de042dSApple OSS Distributions [](IOService *device, uint64_t token, PerfControllerInterface::WorkState *state, WorkSubmitArgs *args) {
58*33de042dSApple OSS Distributions },
59*33de042dSApple OSS Distributions .workBegin =
60*33de042dSApple OSS Distributions [](IOService *device, uint64_t token, PerfControllerInterface::WorkState *state, WorkBeginArgs *args) {
61*33de042dSApple OSS Distributions },
62*33de042dSApple OSS Distributions .workEnd =
63*33de042dSApple OSS Distributions [](IOService *device, uint64_t token, PerfControllerInterface::WorkState *state, WorkEndArgs *args, bool done) {
64*33de042dSApple OSS Distributions },
65*33de042dSApple OSS Distributions .workUpdate =
66*33de042dSApple OSS Distributions [](IOService *device, uint64_t token, PerfControllerInterface::WorkState *state, WorkUpdateArgs *args) {
67*33de042dSApple OSS Distributions },
68*33de042dSApple OSS Distributions };
69*33de042dSApple OSS Distributions
70*33de042dSApple OSS Distributions shared->interfaceLock = IOLockAlloc();
71*33de042dSApple OSS Distributions if (!shared->interfaceLock) {
72*33de042dSApple OSS Distributions goto shared_init_error;
73*33de042dSApple OSS Distributions }
74*33de042dSApple OSS Distributions
75*33de042dSApple OSS Distributions shared->deviceRegistrationList = OSSet::withCapacity(4);
76*33de042dSApple OSS Distributions if (!shared->deviceRegistrationList) {
77*33de042dSApple OSS Distributions goto shared_init_error;
78*33de042dSApple OSS Distributions }
79*33de042dSApple OSS Distributions
80*33de042dSApple OSS Distributions if (!atomic_compare_exchange_strong_explicit(&gIOPerfControlClientShared, &expected, shared, memory_order_acq_rel,
81*33de042dSApple OSS Distributions memory_order_acquire)) {
82*33de042dSApple OSS Distributions IOLockFree(shared->interfaceLock);
83*33de042dSApple OSS Distributions shared->deviceRegistrationList->release();
84*33de042dSApple OSS Distributions kfree_type(IOPerfControlClientShared, shared);
85*33de042dSApple OSS Distributions shared = expected;
86*33de042dSApple OSS Distributions }
87*33de042dSApple OSS Distributions }
88*33de042dSApple OSS Distributions workTable = NULL;
89*33de042dSApple OSS Distributions workTableLock = NULL;
90*33de042dSApple OSS Distributions
91*33de042dSApple OSS Distributions // Note: driverIndex is not guaranteed to be unique if maxDriverIndex wraps around. It is intended for debugging only.
92*33de042dSApple OSS Distributions driverIndex = atomic_fetch_add_explicit(&shared->maxDriverIndex, 1, memory_order_relaxed) + 1;
93*33de042dSApple OSS Distributions
94*33de042dSApple OSS Distributions // + 1 since index 0 is unused for kIOPerfControlClientWorkUntracked
95*33de042dSApple OSS Distributions workTableLength = maxWorkCapacity + 1;
96*33de042dSApple OSS Distributions assertf(workTableLength <= kWorkTableMaxSize, "%zu exceeds max allowed capacity of %zu", workTableLength, kWorkTableMaxSize);
97*33de042dSApple OSS Distributions if (maxWorkCapacity > 0) {
98*33de042dSApple OSS Distributions workTable = kalloc_type(WorkTableEntry, workTableLength, Z_WAITOK_ZERO);
99*33de042dSApple OSS Distributions if (!workTable) {
100*33de042dSApple OSS Distributions goto error;
101*33de042dSApple OSS Distributions }
102*33de042dSApple OSS Distributions workTableNextIndex = 1;
103*33de042dSApple OSS Distributions
104*33de042dSApple OSS Distributions workTableLock = IOSimpleLockAlloc();
105*33de042dSApple OSS Distributions if (!workTableLock) {
106*33de042dSApple OSS Distributions goto error;
107*33de042dSApple OSS Distributions }
108*33de042dSApple OSS Distributions }
109*33de042dSApple OSS Distributions
110*33de042dSApple OSS Distributions bzero(&clientData, sizeof(clientData));
111*33de042dSApple OSS Distributions
112*33de042dSApple OSS Distributions return true;
113*33de042dSApple OSS Distributions
114*33de042dSApple OSS Distributions error:
115*33de042dSApple OSS Distributions if (workTable) {
116*33de042dSApple OSS Distributions kfree_type(WorkTableEntry, workTableLength, workTable);
117*33de042dSApple OSS Distributions workTable = NULL;
118*33de042dSApple OSS Distributions }
119*33de042dSApple OSS Distributions if (workTableLock) {
120*33de042dSApple OSS Distributions IOSimpleLockFree(workTableLock);
121*33de042dSApple OSS Distributions workTableLock = NULL;
122*33de042dSApple OSS Distributions }
123*33de042dSApple OSS Distributions return false;
124*33de042dSApple OSS Distributions shared_init_error:
125*33de042dSApple OSS Distributions if (shared) {
126*33de042dSApple OSS Distributions if (shared->interfaceLock) {
127*33de042dSApple OSS Distributions IOLockFree(shared->interfaceLock);
128*33de042dSApple OSS Distributions }
129*33de042dSApple OSS Distributions if (shared->deviceRegistrationList) {
130*33de042dSApple OSS Distributions shared->deviceRegistrationList->release();
131*33de042dSApple OSS Distributions }
132*33de042dSApple OSS Distributions kfree_type(IOPerfControlClientShared, shared);
133*33de042dSApple OSS Distributions shared = nullptr;
134*33de042dSApple OSS Distributions }
135*33de042dSApple OSS Distributions return false;
136*33de042dSApple OSS Distributions }
137*33de042dSApple OSS Distributions
138*33de042dSApple OSS Distributions void
free()139*33de042dSApple OSS Distributions IOPerfControlClient::free()
140*33de042dSApple OSS Distributions {
141*33de042dSApple OSS Distributions if (workTable) {
142*33de042dSApple OSS Distributions kfree_type(WorkTableEntry, workTableLength, workTable);
143*33de042dSApple OSS Distributions }
144*33de042dSApple OSS Distributions if (workTableLock) {
145*33de042dSApple OSS Distributions IOSimpleLockFree(workTableLock);
146*33de042dSApple OSS Distributions }
147*33de042dSApple OSS Distributions super::free();
148*33de042dSApple OSS Distributions }
149*33de042dSApple OSS Distributions
150*33de042dSApple OSS Distributions IOPerfControlClient *
copyClient(IOService * driver,uint64_t maxWorkCapacity)151*33de042dSApple OSS Distributions IOPerfControlClient::copyClient(IOService *driver, uint64_t maxWorkCapacity)
152*33de042dSApple OSS Distributions {
153*33de042dSApple OSS Distributions IOPerfControlClient *client = new IOPerfControlClient;
154*33de042dSApple OSS Distributions if (!client || !client->init(driver, maxWorkCapacity)) {
155*33de042dSApple OSS Distributions panic("could not create IOPerfControlClient");
156*33de042dSApple OSS Distributions }
157*33de042dSApple OSS Distributions return client;
158*33de042dSApple OSS Distributions }
159*33de042dSApple OSS Distributions
160*33de042dSApple OSS Distributions /* Convert the per driver token into a globally unique token for the performance
161*33de042dSApple OSS Distributions * controller's consumption. This is achieved by setting the driver's unique
162*33de042dSApple OSS Distributions * index onto the high order bits. The performance controller is shared between
163*33de042dSApple OSS Distributions * all drivers and must track all instances separately, while each driver has
164*33de042dSApple OSS Distributions * its own token table, so this step is needed to avoid token collisions between
165*33de042dSApple OSS Distributions * drivers.
166*33de042dSApple OSS Distributions */
167*33de042dSApple OSS Distributions inline uint64_t
tokenToGlobalUniqueToken(uint64_t token)168*33de042dSApple OSS Distributions IOPerfControlClient::tokenToGlobalUniqueToken(uint64_t token)
169*33de042dSApple OSS Distributions {
170*33de042dSApple OSS Distributions return token | (static_cast<uint64_t>(driverIndex) << kWorkTableIndexBits);
171*33de042dSApple OSS Distributions }
172*33de042dSApple OSS Distributions
173*33de042dSApple OSS Distributions /* Accounting resources used in a work item to the containing coalition.
174*33de042dSApple OSS Distributions * Contigent upon the PerfController signaling that it wants resource accounting
175*33de042dSApple OSS Distributions * in the registerDevice()/registerDriverDevice calls. More device types can
176*33de042dSApple OSS Distributions * be added here in the future.
177*33de042dSApple OSS Distributions */
178*33de042dSApple OSS Distributions void
accountResources(coalition_t coal,PerfControllerInterface::PerfDeviceID device_type,PerfControllerInterface::ResourceAccounting * resources)179*33de042dSApple OSS Distributions IOPerfControlClient::accountResources(coalition_t coal, PerfControllerInterface::PerfDeviceID device_type, PerfControllerInterface::ResourceAccounting *resources)
180*33de042dSApple OSS Distributions {
181*33de042dSApple OSS Distributions switch (device_type) {
182*33de042dSApple OSS Distributions case PerfControllerInterface::PerfDeviceID::kANE:
183*33de042dSApple OSS Distributions if (coal != nullptr) {
184*33de042dSApple OSS Distributions coalition_update_ane_stats(coal, resources->mach_time_delta, resources->energy_nj_delta);
185*33de042dSApple OSS Distributions }
186*33de042dSApple OSS Distributions break;
187*33de042dSApple OSS Distributions
188*33de042dSApple OSS Distributions default:
189*33de042dSApple OSS Distributions assertf(false, "Unexpected device type for IOPerfControlClient::accountResources: %llu", static_cast<uint64_t>(device_type));
190*33de042dSApple OSS Distributions }
191*33de042dSApple OSS Distributions }
192*33de042dSApple OSS Distributions
193*33de042dSApple OSS Distributions /* With this implementation, tokens returned to the driver differ from tokens
194*33de042dSApple OSS Distributions * passed to the performance controller. This implementation has the nice
195*33de042dSApple OSS Distributions * property that tokens returns to the driver will aways be between 1 and
196*33de042dSApple OSS Distributions * the value of maxWorkCapacity passed by the driver to copyClient. The tokens
197*33de042dSApple OSS Distributions * the performance controller sees will match on the lower order bits and have
198*33de042dSApple OSS Distributions * the driver index set on the high order bits.
199*33de042dSApple OSS Distributions */
200*33de042dSApple OSS Distributions uint64_t
allocateToken(thread_group * thread_group)201*33de042dSApple OSS Distributions IOPerfControlClient::allocateToken(thread_group *thread_group)
202*33de042dSApple OSS Distributions {
203*33de042dSApple OSS Distributions uint64_t token = kIOPerfControlClientWorkUntracked;
204*33de042dSApple OSS Distributions
205*33de042dSApple OSS Distributions #if CONFIG_THREAD_GROUPS
206*33de042dSApple OSS Distributions auto s = IOSimpleLockLockDisableInterrupt(workTableLock);
207*33de042dSApple OSS Distributions
208*33de042dSApple OSS Distributions uint64_t num_tries = 0;
209*33de042dSApple OSS Distributions size_t index = workTableNextIndex;
210*33de042dSApple OSS Distributions // - 1 since entry 0 is for kIOPerfControlClientWorkUntracked
211*33de042dSApple OSS Distributions while (num_tries < workTableLength - 1) {
212*33de042dSApple OSS Distributions if (workTable[index].thread_group == nullptr) {
213*33de042dSApple OSS Distributions thread_group_retain(thread_group);
214*33de042dSApple OSS Distributions workTable[index].thread_group = thread_group;
215*33de042dSApple OSS Distributions if (clientData.driverState.resource_accounting) {
216*33de042dSApple OSS Distributions auto *coalition = task_get_coalition(current_task(), COALITION_TYPE_RESOURCE);
217*33de042dSApple OSS Distributions assert(coalition != nullptr);
218*33de042dSApple OSS Distributions coalition_retain(coalition);
219*33de042dSApple OSS Distributions workTable[index].coal = coalition;
220*33de042dSApple OSS Distributions }
221*33de042dSApple OSS Distributions token = index;
222*33de042dSApple OSS Distributions // next integer between 1 and workTableLength - 1
223*33de042dSApple OSS Distributions workTableNextIndex = (index % (workTableLength - 1)) + 1;
224*33de042dSApple OSS Distributions break;
225*33de042dSApple OSS Distributions }
226*33de042dSApple OSS Distributions // next integer between 1 and workTableLength - 1
227*33de042dSApple OSS Distributions index = (index % (workTableLength - 1)) + 1;
228*33de042dSApple OSS Distributions num_tries += 1;
229*33de042dSApple OSS Distributions }
230*33de042dSApple OSS Distributions #if (DEVELOPMENT || DEBUG)
231*33de042dSApple OSS Distributions if (token == kIOPerfControlClientWorkUntracked) {
232*33de042dSApple OSS Distributions /* When investigating a panic here, first check that the driver is not leaking tokens.
233*33de042dSApple OSS Distributions * If the driver is not leaking tokens and maximum is less than kMaxWorkTableNumEntries,
234*33de042dSApple OSS Distributions * the driver should be modified to pass a larger value to copyClient.
235*33de042dSApple OSS Distributions * If the driver is not leaking tokens and maximum is equal to kMaxWorkTableNumEntries,
236*33de042dSApple OSS Distributions * this code will have to be modified to support dynamic table growth to support larger
237*33de042dSApple OSS Distributions * numbers of tokens.
238*33de042dSApple OSS Distributions */
239*33de042dSApple OSS Distributions panic("Tokens allocated for this device exceeded maximum of %zu.",
240*33de042dSApple OSS Distributions workTableLength - 1); // - 1 since entry 0 is for kIOPerfControlClientWorkUntracked
241*33de042dSApple OSS Distributions }
242*33de042dSApple OSS Distributions #endif
243*33de042dSApple OSS Distributions
244*33de042dSApple OSS Distributions IOSimpleLockUnlockEnableInterrupt(workTableLock, s);
245*33de042dSApple OSS Distributions #endif
246*33de042dSApple OSS Distributions
247*33de042dSApple OSS Distributions return token;
248*33de042dSApple OSS Distributions }
249*33de042dSApple OSS Distributions
250*33de042dSApple OSS Distributions void
deallocateToken(uint64_t token)251*33de042dSApple OSS Distributions IOPerfControlClient::deallocateToken(uint64_t token)
252*33de042dSApple OSS Distributions {
253*33de042dSApple OSS Distributions #if CONFIG_THREAD_GROUPS
254*33de042dSApple OSS Distributions assertf(token != kIOPerfControlClientWorkUntracked, "Attempt to deallocate token kIOPerfControlClientWorkUntracked\n");
255*33de042dSApple OSS Distributions assertf(token <= workTableLength, "Attempt to deallocate token %llu which is greater than the table size of %zu\n", token, workTableLength);
256*33de042dSApple OSS Distributions auto s = IOSimpleLockLockDisableInterrupt(workTableLock);
257*33de042dSApple OSS Distributions
258*33de042dSApple OSS Distributions auto &entry = workTable[token];
259*33de042dSApple OSS Distributions auto *thread_group = entry.thread_group;
260*33de042dSApple OSS Distributions auto *coal = entry.coal;
261*33de042dSApple OSS Distributions bzero(&entry, sizeof(entry));
262*33de042dSApple OSS Distributions workTableNextIndex = token;
263*33de042dSApple OSS Distributions
264*33de042dSApple OSS Distributions IOSimpleLockUnlockEnableInterrupt(workTableLock, s);
265*33de042dSApple OSS Distributions
266*33de042dSApple OSS Distributions // This can call into the performance controller if the last reference is dropped here. Are we sure
267*33de042dSApple OSS Distributions // the driver isn't holding any locks? If not, we may want to async this to another context.
268*33de042dSApple OSS Distributions thread_group_release(thread_group);
269*33de042dSApple OSS Distributions if (coal != nullptr) {
270*33de042dSApple OSS Distributions coalition_release(coal);
271*33de042dSApple OSS Distributions }
272*33de042dSApple OSS Distributions #endif
273*33de042dSApple OSS Distributions }
274*33de042dSApple OSS Distributions
275*33de042dSApple OSS Distributions IOPerfControlClient::WorkTableEntry *
getEntryForToken(uint64_t token)276*33de042dSApple OSS Distributions IOPerfControlClient::getEntryForToken(uint64_t token)
277*33de042dSApple OSS Distributions {
278*33de042dSApple OSS Distributions if (token == kIOPerfControlClientWorkUntracked) {
279*33de042dSApple OSS Distributions return nullptr;
280*33de042dSApple OSS Distributions }
281*33de042dSApple OSS Distributions
282*33de042dSApple OSS Distributions if (token >= workTableLength) {
283*33de042dSApple OSS Distributions panic("Invalid work token (%llu): index out of bounds.", token);
284*33de042dSApple OSS Distributions }
285*33de042dSApple OSS Distributions
286*33de042dSApple OSS Distributions WorkTableEntry *entry = &workTable[token];
287*33de042dSApple OSS Distributions assertf(entry->thread_group, "Invalid work token: %llu", token);
288*33de042dSApple OSS Distributions return entry;
289*33de042dSApple OSS Distributions }
290*33de042dSApple OSS Distributions
291*33de042dSApple OSS Distributions void
markEntryStarted(uint64_t token,bool started)292*33de042dSApple OSS Distributions IOPerfControlClient::markEntryStarted(uint64_t token, bool started)
293*33de042dSApple OSS Distributions {
294*33de042dSApple OSS Distributions if (token == kIOPerfControlClientWorkUntracked) {
295*33de042dSApple OSS Distributions return;
296*33de042dSApple OSS Distributions }
297*33de042dSApple OSS Distributions
298*33de042dSApple OSS Distributions if (token >= workTableLength) {
299*33de042dSApple OSS Distributions panic("Invalid work token (%llu): index out of bounds.", token);
300*33de042dSApple OSS Distributions }
301*33de042dSApple OSS Distributions
302*33de042dSApple OSS Distributions workTable[token].started = started;
303*33de042dSApple OSS Distributions }
304*33de042dSApple OSS Distributions
305*33de042dSApple OSS Distributions #if CONFIG_THREAD_GROUPS
306*33de042dSApple OSS Distributions
307*33de042dSApple OSS Distributions static struct thread_group *
threadGroupForDextService(IOService * device)308*33de042dSApple OSS Distributions threadGroupForDextService(IOService *device)
309*33de042dSApple OSS Distributions {
310*33de042dSApple OSS Distributions assert(device);
311*33de042dSApple OSS Distributions
312*33de042dSApple OSS Distributions if (!device->hasUserServer()) {
313*33de042dSApple OSS Distributions return NULL;
314*33de042dSApple OSS Distributions }
315*33de042dSApple OSS Distributions
316*33de042dSApple OSS Distributions // Devices associated with a dext driver, must be called from dext
317*33de042dSApple OSS Distributions // context to ensure that thread_group reference is valid.
318*33de042dSApple OSS Distributions thread_t thread = current_thread();
319*33de042dSApple OSS Distributions assert(get_threadtask(thread) != kernel_task);
320*33de042dSApple OSS Distributions struct thread_group * thread_group = thread_group_get(thread);
321*33de042dSApple OSS Distributions assert(thread_group != nullptr);
322*33de042dSApple OSS Distributions return thread_group;
323*33de042dSApple OSS Distributions }
324*33de042dSApple OSS Distributions
325*33de042dSApple OSS Distributions #endif /* CONFIG_THREAD_GROUPS */
326*33de042dSApple OSS Distributions
327*33de042dSApple OSS Distributions IOReturn
registerDevice(IOService * driver,IOService * device)328*33de042dSApple OSS Distributions IOPerfControlClient::registerDevice(IOService *driver, IOService *device)
329*33de042dSApple OSS Distributions {
330*33de042dSApple OSS Distributions IOReturn ret = kIOReturnSuccess;
331*33de042dSApple OSS Distributions #if CONFIG_THREAD_GROUPS
332*33de042dSApple OSS Distributions IOLockLock(shared->interfaceLock);
333*33de042dSApple OSS Distributions
334*33de042dSApple OSS Distributions clientData.device = device;
335*33de042dSApple OSS Distributions
336*33de042dSApple OSS Distributions if (device) {
337*33de042dSApple OSS Distributions struct thread_group *dext_thread_group = threadGroupForDextService(device);
338*33de042dSApple OSS Distributions if (dext_thread_group) {
339*33de042dSApple OSS Distributions if (clientData.driverState.has_target_thread_group) {
340*33de042dSApple OSS Distributions panic("driverState has already been initialized");
341*33de042dSApple OSS Distributions }
342*33de042dSApple OSS Distributions clientData.driverState.has_target_thread_group = true;
343*33de042dSApple OSS Distributions clientData.driverState.target_thread_group_id = thread_group_get_id(dext_thread_group);
344*33de042dSApple OSS Distributions clientData.driverState.target_thread_group_data = thread_group_get_machine_data(dext_thread_group);
345*33de042dSApple OSS Distributions
346*33de042dSApple OSS Distributions clientData.target_thread_group = dext_thread_group;
347*33de042dSApple OSS Distributions thread_group_retain(dext_thread_group);
348*33de042dSApple OSS Distributions }
349*33de042dSApple OSS Distributions }
350*33de042dSApple OSS Distributions
351*33de042dSApple OSS Distributions if (shared->interface.version >= PERFCONTROL_INTERFACE_VERSION_3) {
352*33de042dSApple OSS Distributions ret = shared->interface.registerDriverDevice(driver, device, &clientData.driverState);
353*33de042dSApple OSS Distributions } else if (shared->interface.version >= PERFCONTROL_INTERFACE_VERSION_1) {
354*33de042dSApple OSS Distributions ret = shared->interface.registerDevice(device);
355*33de042dSApple OSS Distributions } else {
356*33de042dSApple OSS Distributions shared->deviceRegistrationList->setObject(this);
357*33de042dSApple OSS Distributions }
358*33de042dSApple OSS Distributions
359*33de042dSApple OSS Distributions IOLockUnlock(shared->interfaceLock);
360*33de042dSApple OSS Distributions #endif
361*33de042dSApple OSS Distributions return ret;
362*33de042dSApple OSS Distributions }
363*33de042dSApple OSS Distributions
364*33de042dSApple OSS Distributions void
unregisterDevice(IOService * driver,IOService * device)365*33de042dSApple OSS Distributions IOPerfControlClient::unregisterDevice(IOService *driver, IOService *device)
366*33de042dSApple OSS Distributions {
367*33de042dSApple OSS Distributions #if CONFIG_THREAD_GROUPS
368*33de042dSApple OSS Distributions IOLockLock(shared->interfaceLock);
369*33de042dSApple OSS Distributions
370*33de042dSApple OSS Distributions if (shared->interface.version >= PERFCONTROL_INTERFACE_VERSION_3) {
371*33de042dSApple OSS Distributions shared->interface.unregisterDriverDevice(driver, device, &clientData.driverState);
372*33de042dSApple OSS Distributions } else if (shared->interface.version >= PERFCONTROL_INTERFACE_VERSION_1) {
373*33de042dSApple OSS Distributions shared->interface.unregisterDevice(device);
374*33de042dSApple OSS Distributions } else {
375*33de042dSApple OSS Distributions shared->deviceRegistrationList->removeObject(this);
376*33de042dSApple OSS Distributions }
377*33de042dSApple OSS Distributions
378*33de042dSApple OSS Distributions if (clientData.driverState.has_target_thread_group) {
379*33de042dSApple OSS Distributions thread_group_release(clientData.target_thread_group);
380*33de042dSApple OSS Distributions clientData.target_thread_group = nullptr;
381*33de042dSApple OSS Distributions
382*33de042dSApple OSS Distributions clientData.driverState.has_target_thread_group = false;
383*33de042dSApple OSS Distributions clientData.driverState.target_thread_group_id = ~0ull;
384*33de042dSApple OSS Distributions clientData.driverState.target_thread_group_data = nullptr;
385*33de042dSApple OSS Distributions }
386*33de042dSApple OSS Distributions
387*33de042dSApple OSS Distributions clientData.device = nullptr;
388*33de042dSApple OSS Distributions
389*33de042dSApple OSS Distributions IOLockUnlock(shared->interfaceLock);
390*33de042dSApple OSS Distributions #endif
391*33de042dSApple OSS Distributions }
392*33de042dSApple OSS Distributions
393*33de042dSApple OSS Distributions uint64_t
workSubmit(IOService * device,WorkSubmitArgs * args)394*33de042dSApple OSS Distributions IOPerfControlClient::workSubmit(IOService *device, WorkSubmitArgs *args)
395*33de042dSApple OSS Distributions {
396*33de042dSApple OSS Distributions #if CONFIG_THREAD_GROUPS
397*33de042dSApple OSS Distributions auto *thread_group = thread_group_get(current_thread());
398*33de042dSApple OSS Distributions if (!thread_group) {
399*33de042dSApple OSS Distributions return kIOPerfControlClientWorkUntracked;
400*33de042dSApple OSS Distributions }
401*33de042dSApple OSS Distributions
402*33de042dSApple OSS Distributions PerfControllerInterface::WorkState state{
403*33de042dSApple OSS Distributions .thread_group_id = thread_group_get_id(thread_group),
404*33de042dSApple OSS Distributions .thread_group_data = thread_group_get_machine_data(thread_group),
405*33de042dSApple OSS Distributions .work_data = nullptr,
406*33de042dSApple OSS Distributions .work_data_size = 0,
407*33de042dSApple OSS Distributions .started = false,
408*33de042dSApple OSS Distributions .driver_state = &clientData.driverState
409*33de042dSApple OSS Distributions };
410*33de042dSApple OSS Distributions if (!shared->interface.workCanSubmit(device, &state, args)) {
411*33de042dSApple OSS Distributions return kIOPerfControlClientWorkUntracked;
412*33de042dSApple OSS Distributions }
413*33de042dSApple OSS Distributions
414*33de042dSApple OSS Distributions uint64_t token = allocateToken(thread_group);
415*33de042dSApple OSS Distributions if (token != kIOPerfControlClientWorkUntracked) {
416*33de042dSApple OSS Distributions state.work_data = &workTable[token].perfcontrol_data;
417*33de042dSApple OSS Distributions state.work_data_size = sizeof(workTable[token].perfcontrol_data);
418*33de042dSApple OSS Distributions shared->interface.workSubmit(device, tokenToGlobalUniqueToken(token), &state, args);
419*33de042dSApple OSS Distributions }
420*33de042dSApple OSS Distributions return token;
421*33de042dSApple OSS Distributions #else
422*33de042dSApple OSS Distributions return kIOPerfControlClientWorkUntracked;
423*33de042dSApple OSS Distributions #endif
424*33de042dSApple OSS Distributions }
425*33de042dSApple OSS Distributions
426*33de042dSApple OSS Distributions uint64_t
workSubmitAndBegin(IOService * device,WorkSubmitArgs * submitArgs,WorkBeginArgs * beginArgs)427*33de042dSApple OSS Distributions IOPerfControlClient::workSubmitAndBegin(IOService *device, WorkSubmitArgs *submitArgs, WorkBeginArgs *beginArgs)
428*33de042dSApple OSS Distributions {
429*33de042dSApple OSS Distributions #if CONFIG_THREAD_GROUPS
430*33de042dSApple OSS Distributions auto *thread_group = thread_group_get(current_thread());
431*33de042dSApple OSS Distributions if (!thread_group) {
432*33de042dSApple OSS Distributions return kIOPerfControlClientWorkUntracked;
433*33de042dSApple OSS Distributions }
434*33de042dSApple OSS Distributions
435*33de042dSApple OSS Distributions PerfControllerInterface::WorkState state{
436*33de042dSApple OSS Distributions .thread_group_id = thread_group_get_id(thread_group),
437*33de042dSApple OSS Distributions .thread_group_data = thread_group_get_machine_data(thread_group),
438*33de042dSApple OSS Distributions .work_data = nullptr,
439*33de042dSApple OSS Distributions .work_data_size = 0,
440*33de042dSApple OSS Distributions .started = false,
441*33de042dSApple OSS Distributions .driver_state = &clientData.driverState
442*33de042dSApple OSS Distributions };
443*33de042dSApple OSS Distributions if (!shared->interface.workCanSubmit(device, &state, submitArgs)) {
444*33de042dSApple OSS Distributions return kIOPerfControlClientWorkUntracked;
445*33de042dSApple OSS Distributions }
446*33de042dSApple OSS Distributions
447*33de042dSApple OSS Distributions uint64_t token = allocateToken(thread_group);
448*33de042dSApple OSS Distributions if (token != kIOPerfControlClientWorkUntracked) {
449*33de042dSApple OSS Distributions auto &entry = workTable[token];
450*33de042dSApple OSS Distributions state.work_data = &entry.perfcontrol_data;
451*33de042dSApple OSS Distributions state.work_data_size = sizeof(workTable[token].perfcontrol_data);
452*33de042dSApple OSS Distributions shared->interface.workSubmit(device, tokenToGlobalUniqueToken(token), &state, submitArgs);
453*33de042dSApple OSS Distributions state.started = true;
454*33de042dSApple OSS Distributions shared->interface.workBegin(device, tokenToGlobalUniqueToken(token), &state, beginArgs);
455*33de042dSApple OSS Distributions markEntryStarted(token, true);
456*33de042dSApple OSS Distributions }
457*33de042dSApple OSS Distributions return token;
458*33de042dSApple OSS Distributions #else
459*33de042dSApple OSS Distributions return kIOPerfControlClientWorkUntracked;
460*33de042dSApple OSS Distributions #endif
461*33de042dSApple OSS Distributions }
462*33de042dSApple OSS Distributions
463*33de042dSApple OSS Distributions void
workBegin(IOService * device,uint64_t token,WorkBeginArgs * args)464*33de042dSApple OSS Distributions IOPerfControlClient::workBegin(IOService *device, uint64_t token, WorkBeginArgs *args)
465*33de042dSApple OSS Distributions {
466*33de042dSApple OSS Distributions #if CONFIG_THREAD_GROUPS
467*33de042dSApple OSS Distributions WorkTableEntry *entry = getEntryForToken(token);
468*33de042dSApple OSS Distributions if (entry == nullptr) {
469*33de042dSApple OSS Distributions return;
470*33de042dSApple OSS Distributions }
471*33de042dSApple OSS Distributions
472*33de042dSApple OSS Distributions assertf(!entry->started, "Work for token %llu was already started", token);
473*33de042dSApple OSS Distributions
474*33de042dSApple OSS Distributions PerfControllerInterface::WorkState state{
475*33de042dSApple OSS Distributions .thread_group_id = thread_group_get_id(entry->thread_group),
476*33de042dSApple OSS Distributions .thread_group_data = thread_group_get_machine_data(entry->thread_group),
477*33de042dSApple OSS Distributions .work_data = &entry->perfcontrol_data,
478*33de042dSApple OSS Distributions .work_data_size = sizeof(entry->perfcontrol_data),
479*33de042dSApple OSS Distributions .started = true,
480*33de042dSApple OSS Distributions .driver_state = &clientData.driverState
481*33de042dSApple OSS Distributions };
482*33de042dSApple OSS Distributions shared->interface.workBegin(device, tokenToGlobalUniqueToken(token), &state, args);
483*33de042dSApple OSS Distributions markEntryStarted(token, true);
484*33de042dSApple OSS Distributions #endif
485*33de042dSApple OSS Distributions }
486*33de042dSApple OSS Distributions
487*33de042dSApple OSS Distributions void
workEnd(IOService * device,uint64_t token,WorkEndArgs * args,bool done)488*33de042dSApple OSS Distributions IOPerfControlClient::workEnd(IOService *device, uint64_t token, WorkEndArgs *args, bool done)
489*33de042dSApple OSS Distributions {
490*33de042dSApple OSS Distributions #if CONFIG_THREAD_GROUPS
491*33de042dSApple OSS Distributions WorkTableEntry *entry = getEntryForToken(token);
492*33de042dSApple OSS Distributions if (entry == nullptr) {
493*33de042dSApple OSS Distributions return;
494*33de042dSApple OSS Distributions }
495*33de042dSApple OSS Distributions
496*33de042dSApple OSS Distributions PerfControllerInterface::WorkState state{
497*33de042dSApple OSS Distributions .thread_group_id = thread_group_get_id(entry->thread_group),
498*33de042dSApple OSS Distributions .thread_group_data = thread_group_get_machine_data(entry->thread_group),
499*33de042dSApple OSS Distributions .work_data = &entry->perfcontrol_data,
500*33de042dSApple OSS Distributions .work_data_size = sizeof(entry->perfcontrol_data),
501*33de042dSApple OSS Distributions .started = entry->started,
502*33de042dSApple OSS Distributions .driver_state = &clientData.driverState
503*33de042dSApple OSS Distributions };
504*33de042dSApple OSS Distributions
505*33de042dSApple OSS Distributions if (shared->interface.version >= PERFCONTROL_INTERFACE_VERSION_4) {
506*33de042dSApple OSS Distributions PerfControllerInterface::ResourceAccounting resources;
507*33de042dSApple OSS Distributions shared->interface.workEndWithResources(device, tokenToGlobalUniqueToken(token), &state, args, &resources, done);
508*33de042dSApple OSS Distributions if (clientData.driverState.resource_accounting) {
509*33de042dSApple OSS Distributions accountResources(workTable[token].coal, clientData.driverState.device_type, &resources);
510*33de042dSApple OSS Distributions }
511*33de042dSApple OSS Distributions } else {
512*33de042dSApple OSS Distributions shared->interface.workEnd(device, tokenToGlobalUniqueToken(token), &state, args, done);
513*33de042dSApple OSS Distributions }
514*33de042dSApple OSS Distributions
515*33de042dSApple OSS Distributions if (done) {
516*33de042dSApple OSS Distributions deallocateToken(token);
517*33de042dSApple OSS Distributions } else {
518*33de042dSApple OSS Distributions markEntryStarted(token, false);
519*33de042dSApple OSS Distributions }
520*33de042dSApple OSS Distributions #endif
521*33de042dSApple OSS Distributions }
522*33de042dSApple OSS Distributions
523*33de042dSApple OSS Distributions static _Atomic uint64_t unique_work_context_id = 1ull;
524*33de042dSApple OSS Distributions
525*33de042dSApple OSS Distributions class IOPerfControlWorkContext : public OSObject
526*33de042dSApple OSS Distributions {
527*33de042dSApple OSS Distributions OSDeclareDefaultStructors(IOPerfControlWorkContext);
528*33de042dSApple OSS Distributions
529*33de042dSApple OSS Distributions public:
530*33de042dSApple OSS Distributions uint64_t id;
531*33de042dSApple OSS Distributions struct thread_group *thread_group;
532*33de042dSApple OSS Distributions coalition_t coal;
533*33de042dSApple OSS Distributions bool started;
534*33de042dSApple OSS Distributions uint8_t perfcontrol_data[32];
535*33de042dSApple OSS Distributions
536*33de042dSApple OSS Distributions bool init() override;
537*33de042dSApple OSS Distributions void reset();
538*33de042dSApple OSS Distributions void free() override;
539*33de042dSApple OSS Distributions };
540*33de042dSApple OSS Distributions
541*33de042dSApple OSS Distributions OSDefineMetaClassAndStructors(IOPerfControlWorkContext, OSObject);
542*33de042dSApple OSS Distributions
543*33de042dSApple OSS Distributions bool
init()544*33de042dSApple OSS Distributions IOPerfControlWorkContext::init()
545*33de042dSApple OSS Distributions {
546*33de042dSApple OSS Distributions if (!super::init()) {
547*33de042dSApple OSS Distributions return false;
548*33de042dSApple OSS Distributions }
549*33de042dSApple OSS Distributions id = atomic_fetch_add_explicit(&unique_work_context_id, 1, memory_order_relaxed) + 1;
550*33de042dSApple OSS Distributions reset();
551*33de042dSApple OSS Distributions return true;
552*33de042dSApple OSS Distributions }
553*33de042dSApple OSS Distributions
554*33de042dSApple OSS Distributions void
reset()555*33de042dSApple OSS Distributions IOPerfControlWorkContext::reset()
556*33de042dSApple OSS Distributions {
557*33de042dSApple OSS Distributions thread_group = nullptr;
558*33de042dSApple OSS Distributions coal = nullptr;
559*33de042dSApple OSS Distributions started = false;
560*33de042dSApple OSS Distributions bzero(perfcontrol_data, sizeof(perfcontrol_data));
561*33de042dSApple OSS Distributions }
562*33de042dSApple OSS Distributions
563*33de042dSApple OSS Distributions void
free()564*33de042dSApple OSS Distributions IOPerfControlWorkContext::free()
565*33de042dSApple OSS Distributions {
566*33de042dSApple OSS Distributions assertf(thread_group == nullptr, "IOPerfControlWorkContext ID %llu being released without calling workEnd!\n", id);
567*33de042dSApple OSS Distributions assertf(coal == nullptr, "IOPerfControlWorkContext ID %llu being released without calling workEnd!\n", id);
568*33de042dSApple OSS Distributions super::free();
569*33de042dSApple OSS Distributions }
570*33de042dSApple OSS Distributions
571*33de042dSApple OSS Distributions OSObject *
copyWorkContext()572*33de042dSApple OSS Distributions IOPerfControlClient::copyWorkContext()
573*33de042dSApple OSS Distributions {
574*33de042dSApple OSS Distributions IOPerfControlWorkContext *context = new IOPerfControlWorkContext;
575*33de042dSApple OSS Distributions
576*33de042dSApple OSS Distributions if (context == nullptr) {
577*33de042dSApple OSS Distributions return nullptr;
578*33de042dSApple OSS Distributions }
579*33de042dSApple OSS Distributions
580*33de042dSApple OSS Distributions if (!context->init()) {
581*33de042dSApple OSS Distributions context->free();
582*33de042dSApple OSS Distributions return nullptr;
583*33de042dSApple OSS Distributions }
584*33de042dSApple OSS Distributions
585*33de042dSApple OSS Distributions return context;
586*33de042dSApple OSS Distributions }
587*33de042dSApple OSS Distributions
588*33de042dSApple OSS Distributions bool
workSubmitAndBeginWithContext(IOService * device,OSObject * context,WorkSubmitArgs * submitArgs,WorkBeginArgs * beginArgs)589*33de042dSApple OSS Distributions IOPerfControlClient::workSubmitAndBeginWithContext(IOService *device, OSObject *context, WorkSubmitArgs *submitArgs, WorkBeginArgs *beginArgs)
590*33de042dSApple OSS Distributions {
591*33de042dSApple OSS Distributions #if CONFIG_THREAD_GROUPS
592*33de042dSApple OSS Distributions
593*33de042dSApple OSS Distributions if (workSubmitWithContext(device, context, submitArgs) == false) {
594*33de042dSApple OSS Distributions return false;
595*33de042dSApple OSS Distributions }
596*33de042dSApple OSS Distributions
597*33de042dSApple OSS Distributions IOPerfControlWorkContext *work_context = OSDynamicCast(IOPerfControlWorkContext, context);
598*33de042dSApple OSS Distributions
599*33de042dSApple OSS Distributions PerfControllerInterface::WorkState state{
600*33de042dSApple OSS Distributions .thread_group_id = thread_group_get_id(work_context->thread_group),
601*33de042dSApple OSS Distributions .thread_group_data = thread_group_get_machine_data(work_context->thread_group),
602*33de042dSApple OSS Distributions .work_data = &work_context->perfcontrol_data,
603*33de042dSApple OSS Distributions .work_data_size = sizeof(work_context->perfcontrol_data),
604*33de042dSApple OSS Distributions .started = true,
605*33de042dSApple OSS Distributions .driver_state = &clientData.driverState
606*33de042dSApple OSS Distributions };
607*33de042dSApple OSS Distributions
608*33de042dSApple OSS Distributions shared->interface.workBegin(device, work_context->id, &state, beginArgs);
609*33de042dSApple OSS Distributions
610*33de042dSApple OSS Distributions work_context->started = true;
611*33de042dSApple OSS Distributions
612*33de042dSApple OSS Distributions return true;
613*33de042dSApple OSS Distributions #else
614*33de042dSApple OSS Distributions return false;
615*33de042dSApple OSS Distributions #endif
616*33de042dSApple OSS Distributions }
617*33de042dSApple OSS Distributions
618*33de042dSApple OSS Distributions bool
workSubmitWithContext(IOService * device,OSObject * context,WorkSubmitArgs * args)619*33de042dSApple OSS Distributions IOPerfControlClient::workSubmitWithContext(IOService *device, OSObject *context, WorkSubmitArgs *args)
620*33de042dSApple OSS Distributions {
621*33de042dSApple OSS Distributions #if CONFIG_THREAD_GROUPS
622*33de042dSApple OSS Distributions IOPerfControlWorkContext *work_context = OSDynamicCast(IOPerfControlWorkContext, context);
623*33de042dSApple OSS Distributions
624*33de042dSApple OSS Distributions if (work_context == nullptr) {
625*33de042dSApple OSS Distributions return false;
626*33de042dSApple OSS Distributions }
627*33de042dSApple OSS Distributions
628*33de042dSApple OSS Distributions auto *thread_group = thread_group_get(current_thread());
629*33de042dSApple OSS Distributions assert(thread_group != nullptr);
630*33de042dSApple OSS Distributions
631*33de042dSApple OSS Distributions assertf(!work_context->started, "IOPerfControlWorkContext ID %llu was already started", work_context->id);
632*33de042dSApple OSS Distributions assertf(work_context->thread_group == nullptr, "IOPerfControlWorkContext ID %llu has already taken a refcount on TG 0x%p \n", work_context->id, (void *)(work_context->thread_group));
633*33de042dSApple OSS Distributions
634*33de042dSApple OSS Distributions PerfControllerInterface::WorkState state{
635*33de042dSApple OSS Distributions .thread_group_id = thread_group_get_id(thread_group),
636*33de042dSApple OSS Distributions .thread_group_data = thread_group_get_machine_data(thread_group),
637*33de042dSApple OSS Distributions .work_data = nullptr,
638*33de042dSApple OSS Distributions .work_data_size = 0,
639*33de042dSApple OSS Distributions .started = false,
640*33de042dSApple OSS Distributions .driver_state = &clientData.driverState
641*33de042dSApple OSS Distributions };
642*33de042dSApple OSS Distributions if (!shared->interface.workCanSubmit(device, &state, args)) {
643*33de042dSApple OSS Distributions return false;
644*33de042dSApple OSS Distributions }
645*33de042dSApple OSS Distributions
646*33de042dSApple OSS Distributions work_context->thread_group = thread_group_retain(thread_group);
647*33de042dSApple OSS Distributions if (clientData.driverState.resource_accounting) {
648*33de042dSApple OSS Distributions auto *coalition = task_get_coalition(current_task(), COALITION_TYPE_RESOURCE);
649*33de042dSApple OSS Distributions assert(coalition != nullptr);
650*33de042dSApple OSS Distributions work_context->coal = coalition;
651*33de042dSApple OSS Distributions coalition_retain(coalition);
652*33de042dSApple OSS Distributions }
653*33de042dSApple OSS Distributions
654*33de042dSApple OSS Distributions state.work_data = &work_context->perfcontrol_data;
655*33de042dSApple OSS Distributions state.work_data_size = sizeof(work_context->perfcontrol_data);
656*33de042dSApple OSS Distributions
657*33de042dSApple OSS Distributions shared->interface.workSubmit(device, work_context->id, &state, args);
658*33de042dSApple OSS Distributions
659*33de042dSApple OSS Distributions return true;
660*33de042dSApple OSS Distributions #else
661*33de042dSApple OSS Distributions return false;
662*33de042dSApple OSS Distributions #endif
663*33de042dSApple OSS Distributions }
664*33de042dSApple OSS Distributions
665*33de042dSApple OSS Distributions void
workUpdateWithContext(IOService * device,OSObject * context,WorkUpdateArgs * args)666*33de042dSApple OSS Distributions IOPerfControlClient::workUpdateWithContext(IOService *device, OSObject *context, WorkUpdateArgs *args)
667*33de042dSApple OSS Distributions {
668*33de042dSApple OSS Distributions #if CONFIG_THREAD_GROUPS
669*33de042dSApple OSS Distributions IOPerfControlWorkContext *work_context = OSDynamicCast(IOPerfControlWorkContext, context);
670*33de042dSApple OSS Distributions
671*33de042dSApple OSS Distributions if (work_context == nullptr) {
672*33de042dSApple OSS Distributions return;
673*33de042dSApple OSS Distributions }
674*33de042dSApple OSS Distributions
675*33de042dSApple OSS Distributions if (work_context->thread_group == nullptr) {
676*33de042dSApple OSS Distributions // This Work Context has not taken a refcount on a TG
677*33de042dSApple OSS Distributions return;
678*33de042dSApple OSS Distributions }
679*33de042dSApple OSS Distributions
680*33de042dSApple OSS Distributions PerfControllerInterface::WorkState state{
681*33de042dSApple OSS Distributions .thread_group_id = thread_group_get_id(work_context->thread_group),
682*33de042dSApple OSS Distributions .thread_group_data = thread_group_get_machine_data(work_context->thread_group),
683*33de042dSApple OSS Distributions .work_data = &work_context->perfcontrol_data,
684*33de042dSApple OSS Distributions .work_data_size = sizeof(work_context->perfcontrol_data),
685*33de042dSApple OSS Distributions .driver_state = &clientData.driverState
686*33de042dSApple OSS Distributions };
687*33de042dSApple OSS Distributions shared->interface.workUpdate(device, work_context->id, &state, args);
688*33de042dSApple OSS Distributions #endif
689*33de042dSApple OSS Distributions }
690*33de042dSApple OSS Distributions
691*33de042dSApple OSS Distributions void
workBeginWithContext(IOService * device,OSObject * context,WorkBeginArgs * args)692*33de042dSApple OSS Distributions IOPerfControlClient::workBeginWithContext(IOService *device, OSObject *context, WorkBeginArgs *args)
693*33de042dSApple OSS Distributions {
694*33de042dSApple OSS Distributions #if CONFIG_THREAD_GROUPS
695*33de042dSApple OSS Distributions IOPerfControlWorkContext *work_context = OSDynamicCast(IOPerfControlWorkContext, context);
696*33de042dSApple OSS Distributions
697*33de042dSApple OSS Distributions if (work_context == nullptr) {
698*33de042dSApple OSS Distributions return;
699*33de042dSApple OSS Distributions }
700*33de042dSApple OSS Distributions
701*33de042dSApple OSS Distributions if (work_context->thread_group == nullptr) {
702*33de042dSApple OSS Distributions // This Work Context has not taken a refcount on a TG
703*33de042dSApple OSS Distributions return;
704*33de042dSApple OSS Distributions }
705*33de042dSApple OSS Distributions
706*33de042dSApple OSS Distributions assertf(!work_context->started, "IOPerfControlWorkContext %llu was already started", work_context->id);
707*33de042dSApple OSS Distributions
708*33de042dSApple OSS Distributions PerfControllerInterface::WorkState state{
709*33de042dSApple OSS Distributions .thread_group_id = thread_group_get_id(work_context->thread_group),
710*33de042dSApple OSS Distributions .thread_group_data = thread_group_get_machine_data(work_context->thread_group),
711*33de042dSApple OSS Distributions .work_data = &work_context->perfcontrol_data,
712*33de042dSApple OSS Distributions .work_data_size = sizeof(work_context->perfcontrol_data),
713*33de042dSApple OSS Distributions .started = true,
714*33de042dSApple OSS Distributions .driver_state = &clientData.driverState
715*33de042dSApple OSS Distributions };
716*33de042dSApple OSS Distributions shared->interface.workBegin(device, work_context->id, &state, args);
717*33de042dSApple OSS Distributions
718*33de042dSApple OSS Distributions work_context->started = true;
719*33de042dSApple OSS Distributions #endif
720*33de042dSApple OSS Distributions }
721*33de042dSApple OSS Distributions
722*33de042dSApple OSS Distributions void
workEndWithContext(IOService * device,OSObject * context,WorkEndArgs * args,bool done)723*33de042dSApple OSS Distributions IOPerfControlClient::workEndWithContext(IOService *device, OSObject *context, WorkEndArgs *args, bool done)
724*33de042dSApple OSS Distributions {
725*33de042dSApple OSS Distributions #if CONFIG_THREAD_GROUPS
726*33de042dSApple OSS Distributions IOPerfControlWorkContext *work_context = OSDynamicCast(IOPerfControlWorkContext, context);
727*33de042dSApple OSS Distributions
728*33de042dSApple OSS Distributions if (work_context == nullptr) {
729*33de042dSApple OSS Distributions return;
730*33de042dSApple OSS Distributions }
731*33de042dSApple OSS Distributions
732*33de042dSApple OSS Distributions if (work_context->thread_group == nullptr) {
733*33de042dSApple OSS Distributions return;
734*33de042dSApple OSS Distributions }
735*33de042dSApple OSS Distributions
736*33de042dSApple OSS Distributions PerfControllerInterface::WorkState state{
737*33de042dSApple OSS Distributions .thread_group_id = thread_group_get_id(work_context->thread_group),
738*33de042dSApple OSS Distributions .thread_group_data = thread_group_get_machine_data(work_context->thread_group),
739*33de042dSApple OSS Distributions .work_data = &work_context->perfcontrol_data,
740*33de042dSApple OSS Distributions .work_data_size = sizeof(work_context->perfcontrol_data),
741*33de042dSApple OSS Distributions .started = work_context->started,
742*33de042dSApple OSS Distributions .driver_state = &clientData.driverState
743*33de042dSApple OSS Distributions };
744*33de042dSApple OSS Distributions
745*33de042dSApple OSS Distributions if (shared->interface.version >= PERFCONTROL_INTERFACE_VERSION_4) {
746*33de042dSApple OSS Distributions PerfControllerInterface::ResourceAccounting resources;
747*33de042dSApple OSS Distributions shared->interface.workEndWithResources(device, work_context->id, &state, args, &resources, done);
748*33de042dSApple OSS Distributions if (clientData.driverState.resource_accounting) {
749*33de042dSApple OSS Distributions accountResources(work_context->coal, clientData.driverState.device_type, &resources);
750*33de042dSApple OSS Distributions }
751*33de042dSApple OSS Distributions } else {
752*33de042dSApple OSS Distributions shared->interface.workEnd(device, work_context->id, &state, args, done);
753*33de042dSApple OSS Distributions }
754*33de042dSApple OSS Distributions
755*33de042dSApple OSS Distributions if (done) {
756*33de042dSApple OSS Distributions thread_group_release(work_context->thread_group);
757*33de042dSApple OSS Distributions if (work_context->coal != nullptr) {
758*33de042dSApple OSS Distributions coalition_release(work_context->coal);
759*33de042dSApple OSS Distributions }
760*33de042dSApple OSS Distributions work_context->reset();
761*33de042dSApple OSS Distributions } else {
762*33de042dSApple OSS Distributions work_context->started = false;
763*33de042dSApple OSS Distributions }
764*33de042dSApple OSS Distributions
765*33de042dSApple OSS Distributions return;
766*33de042dSApple OSS Distributions #else
767*33de042dSApple OSS Distributions return;
768*33de042dSApple OSS Distributions #endif
769*33de042dSApple OSS Distributions }
770*33de042dSApple OSS Distributions
771*33de042dSApple OSS Distributions IOReturn
registerPerformanceController(PerfControllerInterface * pci)772*33de042dSApple OSS Distributions IOPerfControlClient::registerPerformanceController(PerfControllerInterface *pci)
773*33de042dSApple OSS Distributions {
774*33de042dSApple OSS Distributions IOReturn result = kIOReturnError;
775*33de042dSApple OSS Distributions
776*33de042dSApple OSS Distributions IOLockLock(shared->interfaceLock);
777*33de042dSApple OSS Distributions
778*33de042dSApple OSS Distributions if (shared->interface.version == PERFCONTROL_INTERFACE_VERSION_NONE) {
779*33de042dSApple OSS Distributions shared->interface.version = pci->version;
780*33de042dSApple OSS Distributions
781*33de042dSApple OSS Distributions if (pci->version >= PERFCONTROL_INTERFACE_VERSION_1) {
782*33de042dSApple OSS Distributions assert(pci->registerDevice && pci->unregisterDevice && pci->workCanSubmit && pci->workSubmit && pci->workBegin && pci->workEnd);
783*33de042dSApple OSS Distributions shared->interface.registerDevice = pci->registerDevice;
784*33de042dSApple OSS Distributions shared->interface.unregisterDevice = pci->unregisterDevice;
785*33de042dSApple OSS Distributions shared->interface.workCanSubmit = pci->workCanSubmit;
786*33de042dSApple OSS Distributions shared->interface.workSubmit = pci->workSubmit;
787*33de042dSApple OSS Distributions shared->interface.workBegin = pci->workBegin;
788*33de042dSApple OSS Distributions shared->interface.workEnd = pci->workEnd;
789*33de042dSApple OSS Distributions }
790*33de042dSApple OSS Distributions
791*33de042dSApple OSS Distributions if (pci->version >= PERFCONTROL_INTERFACE_VERSION_2) {
792*33de042dSApple OSS Distributions if (pci->workUpdate != nullptr) {
793*33de042dSApple OSS Distributions shared->interface.workUpdate = pci->workUpdate;
794*33de042dSApple OSS Distributions }
795*33de042dSApple OSS Distributions }
796*33de042dSApple OSS Distributions
797*33de042dSApple OSS Distributions if (pci->version >= PERFCONTROL_INTERFACE_VERSION_3) {
798*33de042dSApple OSS Distributions assert(pci->registerDriverDevice && pci->unregisterDriverDevice);
799*33de042dSApple OSS Distributions shared->interface.registerDriverDevice = pci->registerDriverDevice;
800*33de042dSApple OSS Distributions shared->interface.unregisterDriverDevice = pci->unregisterDriverDevice;
801*33de042dSApple OSS Distributions }
802*33de042dSApple OSS Distributions
803*33de042dSApple OSS Distributions if (pci->version >= PERFCONTROL_INTERFACE_VERSION_4) {
804*33de042dSApple OSS Distributions assert(pci->workEndWithResources);
805*33de042dSApple OSS Distributions shared->interface.workEndWithResources = pci->workEndWithResources;
806*33de042dSApple OSS Distributions }
807*33de042dSApple OSS Distributions
808*33de042dSApple OSS Distributions result = kIOReturnSuccess;
809*33de042dSApple OSS Distributions
810*33de042dSApple OSS Distributions OSObject *obj;
811*33de042dSApple OSS Distributions while ((obj = shared->deviceRegistrationList->getAnyObject())) {
812*33de042dSApple OSS Distributions IOPerfControlClient *client = OSDynamicCast(IOPerfControlClient, obj);
813*33de042dSApple OSS Distributions IOPerfControlClientData *clientData = client->getClientData();
814*33de042dSApple OSS Distributions if (clientData && clientData->device) {
815*33de042dSApple OSS Distributions if (pci->version >= PERFCONTROL_INTERFACE_VERSION_3) {
816*33de042dSApple OSS Distributions pci->registerDriverDevice(clientData->device->getProvider(), clientData->device, &(clientData->driverState));
817*33de042dSApple OSS Distributions } else if (pci->version >= PERFCONTROL_INTERFACE_VERSION_1) {
818*33de042dSApple OSS Distributions pci->registerDevice(clientData->device);
819*33de042dSApple OSS Distributions }
820*33de042dSApple OSS Distributions }
821*33de042dSApple OSS Distributions shared->deviceRegistrationList->removeObject(obj);
822*33de042dSApple OSS Distributions }
823*33de042dSApple OSS Distributions }
824*33de042dSApple OSS Distributions
825*33de042dSApple OSS Distributions IOLockUnlock(shared->interfaceLock);
826*33de042dSApple OSS Distributions
827*33de042dSApple OSS Distributions return result;
828*33de042dSApple OSS Distributions }
829