1 | /* |
2 | * Copyright (c) 2007-2012 Apple Inc. All rights reserved. |
3 | * Copyright (c) 1998-2006 Apple Computer, Inc. All rights reserved. |
4 | * |
5 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ |
6 | * |
7 | * This file contains Original Code and/or Modifications of Original Code |
8 | * as defined in and that are subject to the Apple Public Source License |
9 | * Version 2.0 (the 'License'). You may not use this file except in |
10 | * compliance with the License. The rights granted to you under the License |
11 | * may not be used to create, or enable the creation or redistribution of, |
12 | * unlawful or unlicensed copies of an Apple operating system, or to |
13 | * circumvent, violate, or enable the circumvention or violation of, any |
14 | * terms of an Apple operating system software license agreement. |
15 | * |
16 | * Please obtain a copy of the License at |
17 | * http://www.opensource.apple.com/apsl/ and read it before using this file. |
18 | * |
19 | * The Original Code and all software distributed under the License are |
20 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER |
21 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
22 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, |
23 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. |
24 | * Please see the License for the specific language governing rights and |
25 | * limitations under the License. |
26 | * |
27 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ |
28 | */ |
29 | |
30 | #include <IOKit/IOLib.h> |
31 | #include <IOKit/IOService.h> |
32 | #include <IOKit/IOPlatformExpert.h> |
33 | #include <IOKit/IODeviceTreeSupport.h> |
34 | #include <IOKit/IOInterrupts.h> |
35 | #include <IOKit/IOInterruptController.h> |
36 | #include <IOKit/IOKitDebug.h> |
37 | #include <IOKit/IOTimeStamp.h> |
38 | |
39 | |
40 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
41 | |
42 | #define super IOService |
43 | |
44 | OSDefineMetaClassAndAbstractStructors(IOInterruptController, IOService); |
45 | |
46 | OSMetaClassDefineReservedUsedX86(IOInterruptController, 0); |
47 | OSMetaClassDefineReservedUsedX86(IOInterruptController, 1); |
48 | OSMetaClassDefineReservedUsedX86(IOInterruptController, 2); |
49 | OSMetaClassDefineReservedUnused(IOInterruptController, 3); |
50 | OSMetaClassDefineReservedUnused(IOInterruptController, 4); |
51 | OSMetaClassDefineReservedUnused(IOInterruptController, 5); |
52 | |
53 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
54 | |
55 | IOReturn |
56 | IOInterruptController::registerInterrupt(IOService *nub, int source, |
57 | void *target, |
58 | IOInterruptHandler handler, |
59 | void *refCon) |
60 | { |
61 | IOInterruptSource *interruptSources; |
62 | IOInterruptVectorNumber vectorNumber; |
63 | IOInterruptVector *vector; |
64 | int wasDisabledSoft; |
65 | IOReturn error; |
66 | OSData *vectorData; |
67 | IOOptionBits options; |
68 | bool canBeShared, shouldBeShared, wasAlreadyRegisterd; |
69 | |
70 | IOService *originalNub = NULL;// Protected by wasAlreadyRegisterd |
71 | int originalSource = 0;// Protected by wasAlreadyRegisterd |
72 | |
73 | |
74 | interruptSources = nub->_interruptSources; |
75 | vectorData = interruptSources[source].vectorData; |
76 | vectorNumber = *(IOInterruptVectorNumber *)vectorData->getBytesNoCopy(); |
77 | vector = &vectors[vectorNumber]; |
78 | |
79 | // Get the lock for this vector. |
80 | IOLockLock(vector->interruptLock); |
81 | |
82 | // Check if the interrupt source can/should be shared. |
83 | canBeShared = vectorCanBeShared(vectorNumber, vector); |
84 | IODTGetInterruptOptions(regEntry: nub, source, options: &options); |
85 | #if defined(__i386__) || defined(__x86_64__) |
86 | int interruptType; |
87 | if (OSDynamicCast(IOPlatformDevice, getProvider()) && |
88 | (getInterruptType(nub, source, &interruptType) == kIOReturnSuccess) && |
89 | (kIOInterruptTypeLevel & interruptType)) { |
90 | options |= kIODTInterruptShared; |
91 | } |
92 | #endif |
93 | shouldBeShared = canBeShared && (options & kIODTInterruptShared); |
94 | wasAlreadyRegisterd = vector->interruptRegistered; |
95 | |
96 | // If the vector is registered and can not be shared return error. |
97 | if (wasAlreadyRegisterd && !canBeShared) { |
98 | IOLockUnlock(vector->interruptLock); |
99 | return kIOReturnNoResources; |
100 | } |
101 | |
102 | // If this vector is already in use, and can be shared (implied), |
103 | // or it is not registered and should be shared, |
104 | // register as a shared interrupt. |
105 | if (wasAlreadyRegisterd || shouldBeShared) { |
106 | // If this vector is not already shared, break it out. |
107 | if (vector->sharedController == NULL) { |
108 | // Make the IOShareInterruptController instance |
109 | vector->sharedController = new IOSharedInterruptController; |
110 | if (vector->sharedController == NULL) { |
111 | IOLockUnlock(vector->interruptLock); |
112 | return kIOReturnNoMemory; |
113 | } |
114 | |
115 | if (wasAlreadyRegisterd) { |
116 | // Save the nub and source for the original consumer. |
117 | originalNub = vector->nub; |
118 | originalSource = vector->source; |
119 | |
120 | // Physically disable the interrupt, but mark it as being enabled in the hardware. |
121 | // The interruptDisabledSoft now indicates the driver's request for enablement. |
122 | disableVectorHard(vectorNumber, vector); |
123 | vector->interruptDisabledHard = 0; |
124 | } |
125 | |
126 | // Initialize the new shared interrupt controller. |
127 | error = vector->sharedController->initInterruptController(parentController: this, parentSource: vectorData); |
128 | // If the IOSharedInterruptController could not be initalized, |
129 | // if needed, put the original consumer's interrupt back to normal and |
130 | // get rid of whats left of the shared controller. |
131 | if (error != kIOReturnSuccess) { |
132 | if (wasAlreadyRegisterd) { |
133 | enableInterrupt(nub: originalNub, source: originalSource); |
134 | } |
135 | vector->sharedController->release(); |
136 | vector->sharedController = NULL; |
137 | IOLockUnlock(vector->interruptLock); |
138 | return error; |
139 | } |
140 | |
141 | // If there was an original consumer try to register it on the shared controller. |
142 | if (wasAlreadyRegisterd) { |
143 | error = vector->sharedController->registerInterrupt(nub: originalNub, |
144 | source: originalSource, |
145 | target: vector->target, |
146 | handler: vector->handler, |
147 | refCon: vector->refCon); |
148 | // If the original consumer could not be moved to the shared controller, |
149 | // put the original consumor's interrupt back to normal and |
150 | // get rid of whats left of the shared controller. |
151 | if (error != kIOReturnSuccess) { |
152 | // Save the driver's interrupt enablement state. |
153 | wasDisabledSoft = vector->interruptDisabledSoft; |
154 | |
155 | // Make the interrupt really hard disabled. |
156 | vector->interruptDisabledSoft = 1; |
157 | vector->interruptDisabledHard = 1; |
158 | |
159 | // Enable the original consumer's interrupt if needed. |
160 | if (!wasDisabledSoft) { |
161 | originalNub->enableInterrupt(source: originalSource); |
162 | } |
163 | enableInterrupt(nub: originalNub, source: originalSource); |
164 | |
165 | vector->sharedController->release(); |
166 | vector->sharedController = NULL; |
167 | IOLockUnlock(vector->interruptLock); |
168 | return error; |
169 | } |
170 | } |
171 | |
172 | // Fill in vector with the shared controller's info. |
173 | vector->handler = (IOInterruptHandler)vector->sharedController->getInterruptHandlerAddress(); |
174 | vector->nub = vector->sharedController; |
175 | vector->source = 0; |
176 | vector->target = vector->sharedController; |
177 | vector->refCon = NULL; |
178 | |
179 | // If the interrupt was already registered, |
180 | // save the driver's interrupt enablement state. |
181 | if (wasAlreadyRegisterd) { |
182 | wasDisabledSoft = vector->interruptDisabledSoft; |
183 | } else { |
184 | wasDisabledSoft = true; |
185 | } |
186 | |
187 | // Do any specific initalization for this vector if it has not yet been used. |
188 | if (!wasAlreadyRegisterd) { |
189 | initVector(vectorNumber, vector); |
190 | } |
191 | |
192 | // Make the interrupt really hard disabled. |
193 | vector->interruptDisabledSoft = 1; |
194 | vector->interruptDisabledHard = 1; |
195 | vector->interruptRegistered = 1; |
196 | |
197 | // Enable the original consumer's interrupt if needed. |
198 | // originalNub is protected by wasAlreadyRegisterd here (see line 184). |
199 | if (!wasDisabledSoft) { |
200 | originalNub->enableInterrupt(source: originalSource); |
201 | } |
202 | } |
203 | |
204 | error = vector->sharedController->registerInterrupt(nub, source, target, |
205 | handler, refCon); |
206 | IOLockUnlock(vector->interruptLock); |
207 | return error; |
208 | } |
209 | |
210 | // Fill in vector with the client's info. |
211 | vector->handler = handler; |
212 | vector->nub = nub; |
213 | vector->source = source; |
214 | vector->target = target; |
215 | vector->refCon = refCon; |
216 | |
217 | // Do any specific initalization for this vector. |
218 | initVector(vectorNumber, vector); |
219 | |
220 | // Get the vector ready. It starts hard disabled. |
221 | vector->interruptDisabledHard = 1; |
222 | vector->interruptDisabledSoft = 1; |
223 | vector->interruptRegistered = 1; |
224 | |
225 | IOLockUnlock(vector->interruptLock); |
226 | return kIOReturnSuccess; |
227 | } |
228 | |
229 | IOReturn |
230 | IOInterruptController::unregisterInterrupt(IOService *nub, int source) |
231 | { |
232 | IOInterruptSource *interruptSources; |
233 | IOInterruptVectorNumber vectorNumber; |
234 | IOInterruptVector *vector; |
235 | OSData *vectorData; |
236 | |
237 | interruptSources = nub->_interruptSources; |
238 | vectorData = interruptSources[source].vectorData; |
239 | vectorNumber = *(IOInterruptVectorNumber *)vectorData->getBytesNoCopy(); |
240 | vector = &vectors[vectorNumber]; |
241 | |
242 | // Get the lock for this vector. |
243 | IOLockLock(vector->interruptLock); |
244 | |
245 | // Return success if it is not already registered |
246 | if (!vector->interruptRegistered) { |
247 | IOLockUnlock(vector->interruptLock); |
248 | return kIOReturnSuccess; |
249 | } |
250 | |
251 | // Soft disable the source. |
252 | disableInterrupt(nub, source); |
253 | |
254 | // Turn the source off at hardware. |
255 | disableVectorHard(vectorNumber, vector); |
256 | |
257 | // Clear all the storage for the vector except for interruptLock. |
258 | vector->interruptActive = 0; |
259 | vector->interruptDisabledSoft = 0; |
260 | vector->interruptDisabledHard = 0; |
261 | vector->interruptRegistered = 0; |
262 | vector->nub = NULL; |
263 | vector->source = 0; |
264 | vector->handler = NULL; |
265 | vector->target = NULL; |
266 | vector->refCon = NULL; |
267 | |
268 | IOLockUnlock(vector->interruptLock); |
269 | return kIOReturnSuccess; |
270 | } |
271 | |
272 | IOReturn |
273 | IOInterruptController::getInterruptType(IOService *nub, int source, |
274 | int *interruptType) |
275 | { |
276 | IOInterruptSource *interruptSources; |
277 | IOInterruptVectorNumber vectorNumber; |
278 | IOInterruptVector *vector; |
279 | OSData *vectorData; |
280 | |
281 | if (interruptType == NULL) { |
282 | return kIOReturnBadArgument; |
283 | } |
284 | |
285 | interruptSources = nub->_interruptSources; |
286 | vectorData = interruptSources[source].vectorData; |
287 | vectorNumber = *(IOInterruptVectorNumber *)vectorData->getBytesNoCopy(); |
288 | vector = &vectors[vectorNumber]; |
289 | |
290 | *interruptType = getVectorType(vectorNumber, vector); |
291 | |
292 | return kIOReturnSuccess; |
293 | } |
294 | |
295 | IOReturn |
296 | IOInterruptController::enableInterrupt(IOService *nub, int source) |
297 | { |
298 | IOInterruptSource *interruptSources; |
299 | IOInterruptVectorNumber vectorNumber; |
300 | IOInterruptVector *vector; |
301 | OSData *vectorData; |
302 | |
303 | interruptSources = nub->_interruptSources; |
304 | vectorData = interruptSources[source].vectorData; |
305 | vectorNumber = *(IOInterruptVectorNumber *)vectorData->getBytesNoCopy(); |
306 | vector = &vectors[vectorNumber]; |
307 | |
308 | if (vector->interruptDisabledSoft) { |
309 | vector->interruptDisabledSoft = 0; |
310 | #if !defined(__i386__) && !defined(__x86_64__) |
311 | OSMemoryBarrier(); |
312 | #endif |
313 | |
314 | if (!getPlatform()->atInterruptLevel()) { |
315 | while (vector->interruptActive) { |
316 | } |
317 | } |
318 | if (vector->interruptDisabledHard) { |
319 | vector->interruptDisabledHard = 0; |
320 | |
321 | // A DSB ISH on ARM is needed to make sure the vector data are |
322 | // properly initialized before the MMIO enabling the interrupts |
323 | // in hardware. OSMemoryBarrier(), which maps to DMB, is not |
324 | // sufficient here as the CPUs are not consumers of the device |
325 | // write. Hence, the DMB does not guarantee the CPUs won't see an |
326 | // interrupt before it initalizes the vector data properly. |
327 | OSSynchronizeIO(); |
328 | |
329 | enableVector(vectorNumber, vector); |
330 | } |
331 | } |
332 | |
333 | return kIOReturnSuccess; |
334 | } |
335 | |
336 | IOReturn |
337 | IOInterruptController::disableInterrupt(IOService *nub, int source) |
338 | { |
339 | IOInterruptSource *interruptSources; |
340 | IOInterruptVectorNumber vectorNumber; |
341 | IOInterruptVector *vector; |
342 | OSData *vectorData; |
343 | |
344 | interruptSources = nub->_interruptSources; |
345 | vectorData = interruptSources[source].vectorData; |
346 | vectorNumber = *(IOInterruptVectorNumber *)vectorData->getBytesNoCopy(); |
347 | vector = &vectors[vectorNumber]; |
348 | |
349 | vector->interruptDisabledSoft = 1; |
350 | #if !defined(__i386__) && !defined(__x86_64__) |
351 | OSMemoryBarrier(); |
352 | #endif |
353 | |
354 | if (!getPlatform()->atInterruptLevel()) { |
355 | while (vector->interruptActive) { |
356 | } |
357 | } |
358 | |
359 | return kIOReturnSuccess; |
360 | } |
361 | |
362 | IOReturn |
363 | IOInterruptController::causeInterrupt(IOService *nub, int source) |
364 | { |
365 | IOInterruptSource *interruptSources; |
366 | IOInterruptVectorNumber vectorNumber; |
367 | IOInterruptVector *vector; |
368 | OSData *vectorData; |
369 | |
370 | interruptSources = nub->_interruptSources; |
371 | vectorData = interruptSources[source].vectorData; |
372 | vectorNumber = *(IOInterruptVectorNumber *)vectorData->getBytesNoCopy(); |
373 | vector = &vectors[vectorNumber]; |
374 | |
375 | causeVector(vectorNumber, vector); |
376 | |
377 | return kIOReturnSuccess; |
378 | } |
379 | |
380 | IOInterruptAction |
381 | IOInterruptController::getInterruptHandlerAddress(void) |
382 | { |
383 | return NULL; |
384 | } |
385 | |
386 | IOReturn |
387 | IOInterruptController::handleInterrupt(void *refCon, IOService *nub, |
388 | int source) |
389 | { |
390 | return kIOReturnInvalid; |
391 | } |
392 | |
393 | |
394 | // Methods to be overridden for simplifed interrupt controller subclasses. |
395 | |
396 | bool |
397 | IOInterruptController::vectorCanBeShared(IOInterruptVectorNumber /*vectorNumber*/, |
398 | IOInterruptVector */*vector*/) |
399 | { |
400 | return false; |
401 | } |
402 | |
403 | void |
404 | IOInterruptController::initVector(IOInterruptVectorNumber /*vectorNumber*/, |
405 | IOInterruptVector */*vector*/) |
406 | { |
407 | } |
408 | |
409 | int |
410 | IOInterruptController::getVectorType(IOInterruptVectorNumber /*vectorNumber*/, |
411 | IOInterruptVector */*vector*/) |
412 | { |
413 | return kIOInterruptTypeEdge; |
414 | } |
415 | |
416 | void |
417 | IOInterruptController::disableVectorHard(IOInterruptVectorNumber /*vectorNumber*/, |
418 | IOInterruptVector */*vector*/) |
419 | { |
420 | } |
421 | |
422 | void |
423 | IOInterruptController::enableVector(IOInterruptVectorNumber /*vectorNumber*/, |
424 | IOInterruptVector */*vector*/) |
425 | { |
426 | } |
427 | |
428 | void |
429 | IOInterruptController::causeVector(IOInterruptVectorNumber /*vectorNumber*/, |
430 | IOInterruptVector */*vector*/) |
431 | { |
432 | } |
433 | |
434 | void |
435 | IOInterruptController::setCPUInterruptProperties(IOService */*service*/) |
436 | { |
437 | } |
438 | |
439 | void |
440 | IOInterruptController::sendIPI(unsigned int /*cpu_id*/, bool /*deferred*/) |
441 | { |
442 | } |
443 | |
444 | void |
445 | IOInterruptController::cancelDeferredIPI(unsigned int /*cpu_id*/) |
446 | { |
447 | } |
448 | |
449 | void |
450 | IOInterruptController::timeStampSpuriousInterrupt(void) |
451 | { |
452 | uint64_t providerID = 0; |
453 | IOService * provider = getProvider(); |
454 | |
455 | if (provider) { |
456 | providerID = provider->getRegistryEntryID(); |
457 | } |
458 | |
459 | IOTimeStampConstant(IODBG_INTC(IOINTC_SPURIOUS), a: providerID); |
460 | } |
461 | |
462 | void |
463 | IOInterruptController::timeStampInterruptHandlerInternal(bool isStart, IOInterruptVectorNumber vectorNumber, IOInterruptVector *vector) |
464 | { |
465 | uint64_t providerID = 0; |
466 | vm_offset_t unslidHandler = 0; |
467 | vm_offset_t unslidTarget = 0; |
468 | |
469 | IOService * provider = getProvider(); |
470 | |
471 | if (provider) { |
472 | providerID = provider->getRegistryEntryID(); |
473 | } |
474 | |
475 | if (vector) { |
476 | unslidHandler = VM_KERNEL_UNSLIDE((vm_offset_t)vector->handler); |
477 | unslidTarget = VM_KERNEL_UNSLIDE_OR_PERM((vm_offset_t)vector->target); |
478 | } |
479 | |
480 | |
481 | if (isStart) { |
482 | #if SCHED_HYGIENE_DEBUG |
483 | ml_irq_debug_start((uintptr_t)vector->handler, (uintptr_t)vector); |
484 | #endif |
485 | IOTimeStampStartConstant(IODBG_INTC(IOINTC_HANDLER), a: (uintptr_t)vectorNumber, b: (uintptr_t)unslidHandler, |
486 | c: (uintptr_t)unslidTarget, d: (uintptr_t)providerID); |
487 | } else { |
488 | IOTimeStampEndConstant(IODBG_INTC(IOINTC_HANDLER), a: (uintptr_t)vectorNumber, b: (uintptr_t)unslidHandler, |
489 | c: (uintptr_t)unslidTarget, d: (uintptr_t)providerID); |
490 | #if SCHED_HYGIENE_DEBUG |
491 | ml_irq_debug_end(); |
492 | #endif |
493 | } |
494 | } |
495 | |
496 | void |
497 | IOInterruptController::timeStampInterruptHandlerStart(IOInterruptVectorNumber vectorNumber, IOInterruptVector *vector) |
498 | { |
499 | timeStampInterruptHandlerInternal(isStart: true, vectorNumber, vector); |
500 | } |
501 | |
502 | void |
503 | IOInterruptController::timeStampInterruptHandlerEnd(IOInterruptVectorNumber vectorNumber, IOInterruptVector *vector) |
504 | { |
505 | timeStampInterruptHandlerInternal(isStart: false, vectorNumber, vector); |
506 | } |
507 | |
508 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
509 | |
510 | #undef super |
511 | #define super IOInterruptController |
512 | |
513 | OSDefineMetaClassAndStructors(IOSharedInterruptController, IOInterruptController); |
514 | |
515 | OSMetaClassDefineReservedUnused(IOSharedInterruptController, 0); |
516 | OSMetaClassDefineReservedUnused(IOSharedInterruptController, 1); |
517 | OSMetaClassDefineReservedUnused(IOSharedInterruptController, 2); |
518 | OSMetaClassDefineReservedUnused(IOSharedInterruptController, 3); |
519 | |
520 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
521 | |
522 | #define kIOSharedInterruptControllerDefaultVectors (128) |
523 | |
524 | IOReturn |
525 | IOSharedInterruptController::initInterruptController(IOInterruptController *parentController, OSData *parentSource) |
526 | { |
527 | int cnt, interruptType; |
528 | IOReturn error; |
529 | |
530 | if (!super::init()) { |
531 | return kIOReturnNoResources; |
532 | } |
533 | |
534 | // Set provider to this so enable/disable nub stuff works. |
535 | provider = this; |
536 | |
537 | // Allocate the IOInterruptSource so this can act like a nub. |
538 | _interruptSources = IONew(IOInterruptSource, 1); |
539 | if (_interruptSources == NULL) { |
540 | return kIOReturnNoMemory; |
541 | } |
542 | _numInterruptSources = 1; |
543 | |
544 | // Set up the IOInterruptSource to point at this. |
545 | parentController->retain(); |
546 | parentSource->retain(); |
547 | _interruptSources[0].interruptController = parentController; |
548 | _interruptSources[0].vectorData = parentSource; |
549 | |
550 | sourceIsLevel = false; |
551 | error = provider->getInterruptType(source: 0, interruptType: &interruptType); |
552 | if (error == kIOReturnSuccess) { |
553 | if (interruptType & kIOInterruptTypeLevel) { |
554 | sourceIsLevel = true; |
555 | } |
556 | } |
557 | |
558 | // Allocate the memory for the vectors |
559 | numVectors = kIOSharedInterruptControllerDefaultVectors; // For now a constant number. |
560 | vectors = IONewZero(IOInterruptVector, numVectors); |
561 | if (vectors == NULL) { |
562 | IODelete(_interruptSources, IOInterruptSource, 1); |
563 | return kIOReturnNoMemory; |
564 | } |
565 | |
566 | // Allocate the lock for the controller. |
567 | controllerLock = IOSimpleLockAlloc(); |
568 | if (controllerLock == NULL) { |
569 | return kIOReturnNoResources; |
570 | } |
571 | |
572 | // Allocate locks for the vectors. |
573 | for (cnt = 0; cnt < numVectors; cnt++) { |
574 | vectors[cnt].interruptLock = IOLockAlloc(); |
575 | if (vectors[cnt].interruptLock == NULL) { |
576 | for (cnt = 0; cnt < numVectors; cnt++) { |
577 | if (vectors[cnt].interruptLock != NULL) { |
578 | IOLockFree(lock: vectors[cnt].interruptLock); |
579 | } |
580 | } |
581 | return kIOReturnNoResources; |
582 | } |
583 | } |
584 | |
585 | numVectors = 0; // reset the high water mark for used vectors |
586 | vectorsRegistered = 0; |
587 | vectorsEnabled = 0; |
588 | controllerDisabled = 1; |
589 | |
590 | return kIOReturnSuccess; |
591 | } |
592 | |
593 | IOReturn |
594 | IOSharedInterruptController::registerInterrupt(IOService *nub, |
595 | int source, |
596 | void *target, |
597 | IOInterruptHandler handler, |
598 | void *refCon) |
599 | { |
600 | IOInterruptSource *interruptSources; |
601 | IOInterruptVectorNumber vectorNumber; |
602 | IOInterruptVector *vector = NULL; |
603 | OSData *vectorData; |
604 | IOInterruptState interruptState; |
605 | |
606 | interruptSources = nub->_interruptSources; |
607 | |
608 | // Find a free vector. |
609 | vectorNumber = kIOSharedInterruptControllerDefaultVectors; |
610 | while (vectorsRegistered != kIOSharedInterruptControllerDefaultVectors) { |
611 | for (vectorNumber = 0; vectorNumber < kIOSharedInterruptControllerDefaultVectors; vectorNumber++) { |
612 | vector = &vectors[vectorNumber]; |
613 | |
614 | // Get the lock for this vector. |
615 | IOLockLock(vector->interruptLock); |
616 | |
617 | // Is it unregistered? |
618 | if (!vector->interruptRegistered) { |
619 | break; |
620 | } |
621 | |
622 | // Move along to the next one. |
623 | IOLockUnlock(vector->interruptLock); |
624 | } |
625 | |
626 | if (vectorNumber != kIOSharedInterruptControllerDefaultVectors) { |
627 | break; |
628 | } |
629 | } |
630 | |
631 | // Could not find a free one, so give up. |
632 | if (vectorNumber == kIOSharedInterruptControllerDefaultVectors) { |
633 | return kIOReturnNoResources; |
634 | } |
635 | |
636 | // Create the vectorData for the IOInterruptSource. |
637 | vectorData = OSData::withValue(value: vectorNumber); |
638 | if (vectorData == NULL) { |
639 | IOLockUnlock(vector->interruptLock); |
640 | return kIOReturnNoMemory; |
641 | } |
642 | |
643 | // Fill in the IOInterruptSource with the controller's info. |
644 | interruptSources[source].interruptController = this; |
645 | interruptSources[source].vectorData = vectorData; |
646 | |
647 | // Fill in vector with the client's info. |
648 | vector->handler = handler; |
649 | vector->nub = nub; |
650 | vector->source = source; |
651 | vector->target = target; |
652 | vector->refCon = refCon; |
653 | |
654 | // Get the vector ready. It starts off soft disabled. |
655 | vector->interruptDisabledSoft = 1; |
656 | vector->interruptRegistered = 1; |
657 | |
658 | interruptState = IOSimpleLockLockDisableInterrupt(lock: controllerLock); |
659 | // Move the high water mark if needed |
660 | if (++vectorsRegistered > numVectors) { |
661 | numVectors = vectorsRegistered; |
662 | } |
663 | IOSimpleLockUnlockEnableInterrupt(lock: controllerLock, state: interruptState); |
664 | |
665 | IOLockUnlock(vector->interruptLock); |
666 | return kIOReturnSuccess; |
667 | } |
668 | |
669 | IOReturn |
670 | IOSharedInterruptController::unregisterInterrupt(IOService *nub, |
671 | int source) |
672 | { |
673 | IOInterruptVectorNumber vectorNumber; |
674 | IOInterruptVector *vector; |
675 | IOInterruptState interruptState; |
676 | |
677 | for (vectorNumber = 0; vectorNumber < kIOSharedInterruptControllerDefaultVectors; vectorNumber++) { |
678 | vector = &vectors[vectorNumber]; |
679 | |
680 | // Get the lock for this vector. |
681 | IOLockLock(vector->interruptLock); |
682 | |
683 | // Return success if it is not already registered |
684 | if (!vector->interruptRegistered |
685 | || (vector->nub != nub) || (vector->source != source)) { |
686 | IOLockUnlock(vector->interruptLock); |
687 | continue; |
688 | } |
689 | |
690 | // Soft disable the source and the controller too. |
691 | disableInterrupt(nub, source); |
692 | |
693 | // Free vectorData |
694 | IOInterruptSource *interruptSources = nub->_interruptSources; |
695 | OSSafeReleaseNULL(interruptSources[source].vectorData); |
696 | |
697 | // Clear all the storage for the vector except for interruptLock. |
698 | vector->interruptActive = 0; |
699 | vector->interruptDisabledSoft = 0; |
700 | vector->interruptDisabledHard = 0; |
701 | vector->interruptRegistered = 0; |
702 | vector->nub = NULL; |
703 | vector->source = 0; |
704 | vector->handler = NULL; |
705 | vector->target = NULL; |
706 | vector->refCon = NULL; |
707 | |
708 | interruptState = IOSimpleLockLockDisableInterrupt(lock: controllerLock); |
709 | vectorsRegistered--; |
710 | IOSimpleLockUnlockEnableInterrupt(lock: controllerLock, state: interruptState); |
711 | |
712 | // Move along to the next one. |
713 | IOLockUnlock(vector->interruptLock); |
714 | } |
715 | |
716 | // Re-enable the controller if all vectors are enabled. |
717 | if (vectorsEnabled == vectorsRegistered) { |
718 | controllerDisabled = 0; |
719 | provider->enableInterrupt(source: 0); |
720 | } |
721 | |
722 | return kIOReturnSuccess; |
723 | } |
724 | |
725 | IOReturn |
726 | IOSharedInterruptController::getInterruptType(IOService */*nub*/, |
727 | int /*source*/, |
728 | int *interruptType) |
729 | { |
730 | return provider->getInterruptType(source: 0, interruptType); |
731 | } |
732 | |
733 | IOReturn |
734 | IOSharedInterruptController::enableInterrupt(IOService *nub, |
735 | int source) |
736 | { |
737 | IOInterruptSource *interruptSources; |
738 | IOInterruptVectorNumber vectorNumber; |
739 | IOInterruptVector *vector; |
740 | OSData *vectorData; |
741 | IOInterruptState interruptState; |
742 | |
743 | interruptSources = nub->_interruptSources; |
744 | vectorData = interruptSources[source].vectorData; |
745 | vectorNumber = *(IOInterruptVectorNumber *)vectorData->getBytesNoCopy(); |
746 | vector = &vectors[vectorNumber]; |
747 | |
748 | interruptState = IOSimpleLockLockDisableInterrupt(lock: controllerLock); |
749 | if (!vector->interruptDisabledSoft) { |
750 | IOSimpleLockUnlockEnableInterrupt(lock: controllerLock, state: interruptState); |
751 | return kIOReturnSuccess; |
752 | } |
753 | |
754 | vector->interruptDisabledSoft = 0; |
755 | vectorsEnabled++; |
756 | IOSimpleLockUnlockEnableInterrupt(lock: controllerLock, state: interruptState); |
757 | |
758 | if (controllerDisabled && (vectorsEnabled == vectorsRegistered)) { |
759 | controllerDisabled = 0; |
760 | provider->enableInterrupt(source: 0); |
761 | } |
762 | |
763 | return kIOReturnSuccess; |
764 | } |
765 | |
766 | IOReturn |
767 | IOSharedInterruptController::disableInterrupt(IOService *nub, |
768 | int source) |
769 | { |
770 | IOInterruptSource *interruptSources; |
771 | IOInterruptVectorNumber vectorNumber; |
772 | IOInterruptVector *vector; |
773 | OSData *vectorData; |
774 | IOInterruptState interruptState; |
775 | |
776 | interruptSources = nub->_interruptSources; |
777 | vectorData = interruptSources[source].vectorData; |
778 | vectorNumber = *(IOInterruptVectorNumber *)vectorData->getBytesNoCopy(); |
779 | vector = &vectors[vectorNumber]; |
780 | |
781 | interruptState = IOSimpleLockLockDisableInterrupt(lock: controllerLock); |
782 | if (!vector->interruptDisabledSoft) { |
783 | vector->interruptDisabledSoft = 1; |
784 | #if !defined(__i386__) && !defined(__x86_64__) |
785 | OSMemoryBarrier(); |
786 | #endif |
787 | |
788 | vectorsEnabled--; |
789 | } |
790 | IOSimpleLockUnlockEnableInterrupt(lock: controllerLock, state: interruptState); |
791 | |
792 | if (!getPlatform()->atInterruptLevel()) { |
793 | while (vector->interruptActive) { |
794 | } |
795 | } |
796 | |
797 | return kIOReturnSuccess; |
798 | } |
799 | |
800 | IOInterruptAction |
801 | IOSharedInterruptController::getInterruptHandlerAddress(void) |
802 | { |
803 | return OSMemberFunctionCast(IOInterruptAction, |
804 | this, &IOSharedInterruptController::handleInterrupt); |
805 | } |
806 | |
807 | IOReturn |
808 | IOSharedInterruptController::handleInterrupt(void * /*refCon*/, |
809 | IOService * nub, |
810 | int /*source*/) |
811 | { |
812 | IOInterruptVectorNumber vectorNumber; |
813 | IOInterruptVector *vector; |
814 | |
815 | for (vectorNumber = 0; vectorNumber < numVectors; vectorNumber++) { |
816 | vector = &vectors[vectorNumber]; |
817 | |
818 | vector->interruptActive = 1; |
819 | #if !defined(__i386__) && !defined(__x86_64__) |
820 | OSMemoryBarrier(); |
821 | #endif |
822 | |
823 | if (!vector->interruptDisabledSoft) { |
824 | // Call the handler if it exists. |
825 | if (vector->interruptRegistered) { |
826 | bool trace = (gIOKitTrace & kIOTraceInterrupts) ? true : false; |
827 | |
828 | if (trace) { |
829 | timeStampInterruptHandlerStart(vectorNumber, vector); |
830 | } |
831 | |
832 | // Call handler. |
833 | vector->handler(vector->target, vector->refCon, vector->nub, vector->source); |
834 | |
835 | if (trace) { |
836 | timeStampInterruptHandlerEnd(vectorNumber, vector); |
837 | } |
838 | } |
839 | } |
840 | |
841 | vector->interruptActive = 0; |
842 | } |
843 | |
844 | // if any of the vectors are dissabled, then dissable this controller. |
845 | IOSimpleLockLock(controllerLock); |
846 | if (vectorsEnabled != vectorsRegistered) { |
847 | nub->disableInterrupt(source: 0); |
848 | controllerDisabled = 1; |
849 | } |
850 | IOSimpleLockUnlock(controllerLock); |
851 | |
852 | return kIOReturnSuccess; |
853 | } |
854 | |