1/*
2 * Copyright (c) 1999-2000 Apple Computer, Inc.  All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28/*
29 * Copyright (c) 1999-2000 Apple Computer, Inc.  All rights reserved.
30 *
31 *  DRI: Josh de Cesare
32 *
33 */
34
35extern "C" {
36#include <machine/machine_routines.h>
37#include <pexpert/pexpert.h>
38}
39
40#include <machine/machine_routines.h>
41
42#include <IOKit/IOLib.h>
43#include <IOKit/IOPlatformExpert.h>
44#include <IOKit/pwr_mgt/RootDomain.h>
45#include <IOKit/IOUserClient.h>
46#include <IOKit/IOKitKeysPrivate.h>
47#include <IOKit/IOCPU.h>
48
49/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
50#include <kern/queue.h>
51
52typedef kern_return_t (*iocpu_platform_action_t)(void * refcon0, void * refcon1, uint32_t priority,
53						 void * param1, void * param2, void * param3);
54
55struct iocpu_platform_action_entry
56{
57    queue_chain_t                     link;
58    iocpu_platform_action_t           action;
59    int32_t	                      priority;
60    void *	                      refcon0;
61    void *			      refcon1;
62    struct iocpu_platform_action_entry * alloc_list;
63};
64typedef struct iocpu_platform_action_entry iocpu_platform_action_entry_t;
65
66queue_head_t *
67iocpu_get_platform_quiesce_queue(void);
68
69queue_head_t *
70iocpu_get_platform_active_queue(void);
71
72void
73iocpu_platform_cpu_action_init(queue_head_t * quiesce_queue, queue_head_t * init_queue);
74
75void
76iocpu_add_platform_action(queue_head_t * queue, iocpu_platform_action_entry_t * entry);
77
78void
79iocpu_remove_platform_action(iocpu_platform_action_entry_t * entry);
80
81kern_return_t
82iocpu_run_platform_actions(queue_head_t * queue, uint32_t first_priority, uint32_t last_priority,
83					void * param1, void * param2, void * param3);
84
85/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
86
87#define kBootCPUNumber  0
88
89static iocpu_platform_action_entry_t * gIOAllActionsQueue;
90static queue_head_t gIOSleepActionQueue;
91static queue_head_t gIOWakeActionQueue;
92
93static queue_head_t iocpu_quiesce_queue;
94static queue_head_t iocpu_active_queue;
95
96/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
97
98void
99iocpu_platform_cpu_action_init(queue_head_t * quiesce_queue, __unused queue_head_t * init_queue)
100{
101#if 0
102    enum { kNumQuiesceActions = 2 };
103    static iocpu_platform_action_entry_t quiesce_actions[kNumQuiesceActions] =
104    {
105	{ { NULL, NULL }, (iocpu_platform_action_t) &clean_mmu_dcache, 97000, 0, 0, NULL },
106	{ { NULL, NULL }, (iocpu_platform_action_t) &arm_sleep, 99000, 0, 0, NULL },
107    };
108    unsigned int idx;
109
110    for (idx = 0; idx < kNumQuiesceActions; idx++)
111	iocpu_add_platform_action(quiesce_queue, &quiesce_actions[idx]);
112#endif
113}
114
115queue_head_t * iocpu_get_platform_quiesce_queue(void)
116{
117    if (!iocpu_quiesce_queue.next)
118    {
119	queue_init(&iocpu_quiesce_queue);
120	queue_init(&iocpu_active_queue);
121	iocpu_platform_cpu_action_init(&iocpu_quiesce_queue, &iocpu_active_queue);
122    }
123    return (&iocpu_quiesce_queue);
124}
125
126queue_head_t * iocpu_get_platform_active_queue(void)
127{
128    return (&iocpu_active_queue);
129}
130
131void iocpu_add_platform_action(queue_head_t * queue, iocpu_platform_action_entry_t * entry)
132{
133    iocpu_platform_action_entry_t * next;
134
135    queue_iterate(queue, next, iocpu_platform_action_entry_t *, link)
136    {
137	if (next->priority > entry->priority)
138	{
139	    queue_insert_before(queue, entry, next, iocpu_platform_action_entry_t *, link);
140	    return;
141	}
142    }
143    queue_enter(queue, entry, iocpu_platform_action_entry_t *, link);	// at tail
144}
145
146void iocpu_remove_platform_action(iocpu_platform_action_entry_t * entry)
147{
148    remque(&entry->link);
149}
150
151kern_return_t
152iocpu_run_platform_actions(queue_head_t * queue, uint32_t first_priority, uint32_t last_priority,
153					void * param1, void * param2, void * param3)
154{
155    kern_return_t                ret = KERN_SUCCESS;
156    kern_return_t                result = KERN_SUCCESS;
157    iocpu_platform_action_entry_t * next;
158
159    queue_iterate(queue, next, iocpu_platform_action_entry_t *, link)
160    {
161	uint32_t pri = (next->priority < 0) ? -next->priority : next->priority;
162	if ((pri >= first_priority) && (pri <= last_priority))
163	{
164	    //kprintf("[%p]", next->action);
165	    ret = (*next->action)(next->refcon0, next->refcon1, pri, param1, param2, param3);
166	}
167	if (KERN_SUCCESS == result)
168	    result = ret;
169    }
170    return (result);
171}
172
173/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
174
175extern "C" kern_return_t
176IOCPURunPlatformQuiesceActions(void)
177{
178    return (iocpu_run_platform_actions(iocpu_get_platform_quiesce_queue(), 0, 0UL-1,
179				    NULL, NULL, NULL));
180}
181
182extern "C" kern_return_t
183IOCPURunPlatformActiveActions(void)
184{
185    return (iocpu_run_platform_actions(iocpu_get_platform_active_queue(), 0, 0UL-1,
186				    NULL, NULL, NULL));
187}
188
189static kern_return_t
190IOServicePlatformAction(void * refcon0, void * refcon1, uint32_t priority,
191			  void * param1, void * param2, void * param3)
192{
193    IOReturn	     ret;
194    IOService *      service  = (IOService *)      refcon0;
195    const OSSymbol * function = (const OSSymbol *) refcon1;
196
197    kprintf("%s -> %s\n", function->getCStringNoCopy(), service->getName());
198
199    ret = service->callPlatformFunction(function, false,
200					 (void *) priority, param1, param2, param3);
201
202    return (ret);
203}
204
205static void
206IOInstallServicePlatformAction(IOService * service,
207				const OSSymbol * key, queue_head_t * queue,
208				bool reverse)
209{
210    OSNumber * num;
211    iocpu_platform_action_entry_t * entry;
212    uint32_t priority;
213
214    num = OSDynamicCast(OSNumber, service->getProperty(key));
215    if (!num)
216	return;
217
218    entry = IONew(iocpu_platform_action_entry_t, 1);
219    entry->action = &IOServicePlatformAction;
220    priority = num->unsigned32BitValue();
221    if (reverse)
222	entry->priority = -priority;
223    else
224	entry->priority = priority;
225    entry->refcon0 = service;
226    entry->refcon1 = (void *) key;
227
228    iocpu_add_platform_action(queue, entry);
229    entry->alloc_list = gIOAllActionsQueue;
230    gIOAllActionsQueue = entry;
231}
232
233/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
234
235kern_return_t PE_cpu_start(cpu_id_t target,
236			   vm_offset_t start_paddr, vm_offset_t arg_paddr)
237{
238  IOCPU *targetCPU = OSDynamicCast(IOCPU, (OSObject *)target);
239
240  if (targetCPU == 0) return KERN_FAILURE;
241  return targetCPU->startCPU(start_paddr, arg_paddr);
242}
243
244void PE_cpu_halt(cpu_id_t target)
245{
246  IOCPU *targetCPU = OSDynamicCast(IOCPU, (OSObject *)target);
247
248  if (targetCPU) targetCPU->haltCPU();
249}
250
251void PE_cpu_signal(cpu_id_t source, cpu_id_t target)
252{
253  IOCPU *sourceCPU = OSDynamicCast(IOCPU, (OSObject *)source);
254  IOCPU *targetCPU = OSDynamicCast(IOCPU, (OSObject *)target);
255
256  if (sourceCPU && targetCPU) sourceCPU->signalCPU(targetCPU);
257}
258
259void PE_cpu_machine_init(cpu_id_t target, boolean_t bootb)
260{
261  IOCPU *targetCPU = OSDynamicCast(IOCPU, (OSObject *)target);
262
263  if (targetCPU) targetCPU->initCPU(bootb);
264}
265
266void PE_cpu_machine_quiesce(cpu_id_t target)
267{
268  IOCPU *targetCPU = OSDynamicCast(IOCPU, (OSObject *)target);
269
270  if (targetCPU) targetCPU->quiesceCPU();
271}
272
273
274/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
275
276#define super IOService
277
278OSDefineMetaClassAndAbstractStructors(IOCPU, IOService);
279OSMetaClassDefineReservedUnused(IOCPU, 0);
280OSMetaClassDefineReservedUnused(IOCPU, 1);
281OSMetaClassDefineReservedUnused(IOCPU, 2);
282OSMetaClassDefineReservedUnused(IOCPU, 3);
283OSMetaClassDefineReservedUnused(IOCPU, 4);
284OSMetaClassDefineReservedUnused(IOCPU, 5);
285OSMetaClassDefineReservedUnused(IOCPU, 6);
286OSMetaClassDefineReservedUnused(IOCPU, 7);
287
288/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
289
290static OSArray *gIOCPUs;
291static const OSSymbol *gIOCPUStateKey;
292static OSString *gIOCPUStateNames[kIOCPUStateCount];
293
294void IOCPUSleepKernel(void)
295{
296    long cnt, numCPUs;
297    IOCPU *target;
298    IOCPU *bootCPU = NULL;
299
300    kprintf("IOCPUSleepKernel\n");
301
302    OSIterator * iter;
303    IOService *  service;
304
305    queue_init(&gIOSleepActionQueue);
306    queue_init(&gIOWakeActionQueue);
307
308    iter = IORegistryIterator::iterateOver( gIOServicePlane,
309					    kIORegistryIterateRecursively );
310    if( iter)
311    {
312	do
313	{
314	    iter->reset();
315	    while((service = (IOService *) iter->getNextObject()))
316	    {
317		IOInstallServicePlatformAction(service, gIOPlatformSleepActionKey,   &gIOSleepActionQueue,		 false);
318		IOInstallServicePlatformAction(service, gIOPlatformWakeActionKey,    &gIOWakeActionQueue,		 true);
319		IOInstallServicePlatformAction(service, gIOPlatformQuiesceActionKey, iocpu_get_platform_quiesce_queue(), false);
320		IOInstallServicePlatformAction(service, gIOPlatformActiveActionKey,  iocpu_get_platform_active_queue(),  true);
321	    }
322	}
323	while( !service && !iter->isValid());
324	iter->release();
325    }
326
327    iocpu_run_platform_actions(&gIOSleepActionQueue, 0, 0UL-1,
328				NULL, NULL, NULL);
329
330    numCPUs = gIOCPUs->getCount();
331    // Sleep the CPUs.
332    cnt = numCPUs;
333    while (cnt--)
334    {
335        target = OSDynamicCast(IOCPU, gIOCPUs->getObject(cnt));
336
337        // We make certain that the bootCPU is the last to sleep
338        // We'll skip it for now, and halt it after finishing the
339        // non-boot CPU's.
340        if (target->getCPUNumber() == kBootCPUNumber)
341        {
342            bootCPU = target;
343        } else if (target->getCPUState() == kIOCPUStateRunning)
344        {
345            target->haltCPU();
346        }
347    }
348
349    // Now sleep the boot CPU.
350    if (bootCPU)
351        bootCPU->haltCPU();
352
353    iocpu_run_platform_actions(&gIOWakeActionQueue, 0, 0UL-1,
354				    NULL, NULL, NULL);
355
356    iocpu_platform_action_entry_t * entry;
357    while ((entry = gIOAllActionsQueue))
358    {
359	gIOAllActionsQueue = entry->alloc_list;
360	iocpu_remove_platform_action(entry);
361	IODelete(entry, iocpu_platform_action_entry_t, 1);
362    }
363
364    if (!queue_empty(&gIOSleepActionQueue))
365	IOPanic("gIOSleepActionQueue");
366    if (!queue_empty(&gIOWakeActionQueue))
367	IOPanic("gIOWakeActionQueue");
368
369    // Wake the other CPUs.
370    for (cnt = 0; cnt < numCPUs; cnt++)
371    {
372        target = OSDynamicCast(IOCPU, gIOCPUs->getObject(cnt));
373
374        // Skip the already-woken boot CPU.
375        if ((target->getCPUNumber() != kBootCPUNumber)
376            && (target->getCPUState() == kIOCPUStateStopped))
377        {
378            processor_start(target->getMachProcessor());
379        }
380    }
381}
382
383void IOCPU::initCPUs(void)
384{
385  if (gIOCPUs == 0) {
386    gIOCPUs = OSArray::withCapacity(1);
387
388    gIOCPUStateKey = OSSymbol::withCStringNoCopy("IOCPUState");
389
390    gIOCPUStateNames[kIOCPUStateUnregistered] =
391      OSString::withCStringNoCopy("Unregistered");
392    gIOCPUStateNames[kIOCPUStateUninitalized] =
393      OSString::withCStringNoCopy("Uninitalized");
394    gIOCPUStateNames[kIOCPUStateStopped] =
395      OSString::withCStringNoCopy("Stopped");
396    gIOCPUStateNames[kIOCPUStateRunning] =
397      OSString::withCStringNoCopy("Running");
398  }
399}
400
401bool IOCPU::start(IOService *provider)
402{
403  OSData *busFrequency, *cpuFrequency, *timebaseFrequency;
404
405  if (!super::start(provider)) return false;
406
407  initCPUs();
408
409  _cpuGroup = gIOCPUs;
410  cpuNub = provider;
411
412  gIOCPUs->setObject(this);
413
414  // Correct the bus, cpu and timebase frequencies in the device tree.
415  if (gPEClockFrequencyInfo.bus_frequency_hz < 0x100000000ULL) {
416    busFrequency = OSData::withBytesNoCopy((void *)&gPEClockFrequencyInfo.bus_clock_rate_hz, 4);
417  } else {
418    busFrequency = OSData::withBytesNoCopy((void *)&gPEClockFrequencyInfo.bus_frequency_hz, 8);
419  }
420  provider->setProperty("bus-frequency", busFrequency);
421  busFrequency->release();
422
423  if (gPEClockFrequencyInfo.cpu_frequency_hz < 0x100000000ULL) {
424    cpuFrequency = OSData::withBytesNoCopy((void *)&gPEClockFrequencyInfo.cpu_clock_rate_hz, 4);
425  } else {
426    cpuFrequency = OSData::withBytesNoCopy((void *)&gPEClockFrequencyInfo.cpu_frequency_hz, 8);
427  }
428  provider->setProperty("clock-frequency", cpuFrequency);
429  cpuFrequency->release();
430
431  timebaseFrequency = OSData::withBytesNoCopy((void *)&gPEClockFrequencyInfo.timebase_frequency_hz, 4);
432  provider->setProperty("timebase-frequency", timebaseFrequency);
433  timebaseFrequency->release();
434
435  super::setProperty("IOCPUID", (UInt32)this, 32);
436
437  setCPUNumber(0);
438  setCPUState(kIOCPUStateUnregistered);
439
440  return true;
441}
442
443OSObject *IOCPU::getProperty(const OSSymbol *aKey) const
444{
445  if (aKey == gIOCPUStateKey) return gIOCPUStateNames[_cpuState];
446
447  return super::getProperty(aKey);
448}
449
450bool IOCPU::setProperty(const OSSymbol *aKey, OSObject *anObject)
451{
452  OSString *stateStr;
453
454  if (aKey == gIOCPUStateKey) {
455    stateStr = OSDynamicCast(OSString, anObject);
456    if (stateStr == 0) return false;
457
458    if (_cpuNumber == 0) return false;
459
460    if (stateStr->isEqualTo("running")) {
461      if (_cpuState == kIOCPUStateStopped) {
462	processor_start(machProcessor);
463      } else if (_cpuState != kIOCPUStateRunning) {
464	return false;
465      }
466    } else if (stateStr->isEqualTo("stopped")) {
467      if (_cpuState == kIOCPUStateRunning) {
468        haltCPU();
469      } else if (_cpuState != kIOCPUStateStopped) {
470        return false;
471      }
472    } else return false;
473
474    return true;
475  }
476
477  return super::setProperty(aKey, anObject);
478}
479
480bool IOCPU::serializeProperties(OSSerialize *serialize) const
481{
482	bool result;
483	OSDictionary *dict = dictionaryWithProperties();
484	dict->setObject(gIOCPUStateKey, gIOCPUStateNames[_cpuState]);
485	result = dict->serialize(serialize);
486	dict->release();
487	return result;
488}
489
490IOReturn IOCPU::setProperties(OSObject *properties)
491{
492  OSDictionary *dict = OSDynamicCast(OSDictionary, properties);
493  OSString     *stateStr;
494  IOReturn     result;
495
496  if (dict == 0) return kIOReturnUnsupported;
497
498  stateStr = OSDynamicCast(OSString, dict->getObject(gIOCPUStateKey));
499  if (stateStr != 0) {
500    result = IOUserClient::clientHasPrivilege(current_task(), kIOClientPrivilegeAdministrator);
501    if (result != kIOReturnSuccess) return result;
502
503    if (setProperty(gIOCPUStateKey, stateStr)) return kIOReturnSuccess;
504
505    return kIOReturnUnsupported;
506  }
507
508  return kIOReturnUnsupported;
509}
510
511void IOCPU::signalCPU(IOCPU */*target*/)
512{
513}
514
515void IOCPU::enableCPUTimeBase(bool /*enable*/)
516{
517}
518
519UInt32 IOCPU::getCPUNumber(void)
520{
521  return _cpuNumber;
522}
523
524void IOCPU::setCPUNumber(UInt32 cpuNumber)
525{
526  _cpuNumber = cpuNumber;
527  super::setProperty("IOCPUNumber", _cpuNumber, 32);
528}
529
530UInt32 IOCPU::getCPUState(void)
531{
532  return _cpuState;
533}
534
535void IOCPU::setCPUState(UInt32 cpuState)
536{
537  if (cpuState < kIOCPUStateCount) {
538    _cpuState = cpuState;
539  }
540}
541
542OSArray *IOCPU::getCPUGroup(void)
543{
544  return _cpuGroup;
545}
546
547UInt32 IOCPU::getCPUGroupSize(void)
548{
549  return _cpuGroup->getCount();
550}
551
552processor_t IOCPU::getMachProcessor(void)
553{
554  return machProcessor;
555}
556
557
558/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
559
560#undef super
561#define super IOInterruptController
562
563OSDefineMetaClassAndStructors(IOCPUInterruptController, IOInterruptController);
564
565OSMetaClassDefineReservedUnused(IOCPUInterruptController, 0);
566OSMetaClassDefineReservedUnused(IOCPUInterruptController, 1);
567OSMetaClassDefineReservedUnused(IOCPUInterruptController, 2);
568OSMetaClassDefineReservedUnused(IOCPUInterruptController, 3);
569OSMetaClassDefineReservedUnused(IOCPUInterruptController, 4);
570OSMetaClassDefineReservedUnused(IOCPUInterruptController, 5);
571
572
573
574/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
575
576
577IOReturn IOCPUInterruptController::initCPUInterruptController(int sources)
578{
579  int cnt;
580
581  if (!super::init()) return kIOReturnInvalid;
582
583  numCPUs = sources;
584
585  cpus = (IOCPU **)IOMalloc(numCPUs * sizeof(IOCPU *));
586  if (cpus == 0) return kIOReturnNoMemory;
587  bzero(cpus, numCPUs * sizeof(IOCPU *));
588
589  vectors = (IOInterruptVector *)IOMalloc(numCPUs * sizeof(IOInterruptVector));
590  if (vectors == 0) return kIOReturnNoMemory;
591  bzero(vectors, numCPUs * sizeof(IOInterruptVector));
592
593  // Allocate locks for the
594  for (cnt = 0; cnt < numCPUs; cnt++) {
595    vectors[cnt].interruptLock = IOLockAlloc();
596    if (vectors[cnt].interruptLock == NULL) {
597      for (cnt = 0; cnt < numCPUs; cnt++) {
598	if (vectors[cnt].interruptLock != NULL)
599	  IOLockFree(vectors[cnt].interruptLock);
600      }
601      return kIOReturnNoResources;
602    }
603  }
604
605  ml_init_max_cpus(numCPUs);
606
607  return kIOReturnSuccess;
608}
609
610void IOCPUInterruptController::registerCPUInterruptController(void)
611{
612  registerService();
613
614  getPlatform()->registerInterruptController(gPlatformInterruptControllerName,
615					     this);
616}
617
618void IOCPUInterruptController::setCPUInterruptProperties(IOService *service)
619{
620  int          cnt;
621  OSArray      *controller;
622  OSArray      *specifier;
623  OSData       *tmpData;
624  long         tmpLong;
625
626  if ((service->getProperty(gIOInterruptControllersKey) != 0) &&
627      (service->getProperty(gIOInterruptSpecifiersKey) != 0))
628    return;
629
630  // Create the interrupt specifer array.
631  specifier = OSArray::withCapacity(numCPUs);
632  for (cnt = 0; cnt < numCPUs; cnt++) {
633    tmpLong = cnt;
634    tmpData = OSData::withBytes(&tmpLong, sizeof(tmpLong));
635    specifier->setObject(tmpData);
636    tmpData->release();
637  };
638
639  // Create the interrupt controller array.
640  controller = OSArray::withCapacity(numCPUs);
641  for (cnt = 0; cnt < numCPUs; cnt++) {
642    controller->setObject(gPlatformInterruptControllerName);
643  }
644
645  // Put the two arrays into the property table.
646  service->setProperty(gIOInterruptControllersKey, controller);
647  service->setProperty(gIOInterruptSpecifiersKey, specifier);
648  controller->release();
649  specifier->release();
650}
651
652void IOCPUInterruptController::enableCPUInterrupt(IOCPU *cpu)
653{
654	IOInterruptHandler handler = OSMemberFunctionCast(
655		IOInterruptHandler, this, &IOCPUInterruptController::handleInterrupt);
656
657	ml_install_interrupt_handler(cpu, cpu->getCPUNumber(), this, handler, 0);
658
659	enabledCPUs++;
660
661  if (enabledCPUs == numCPUs) thread_wakeup(this);
662}
663
664IOReturn IOCPUInterruptController::registerInterrupt(IOService *nub,
665						     int source,
666						     void *target,
667						     IOInterruptHandler handler,
668						     void *refCon)
669{
670  IOInterruptVector *vector;
671
672  if (source >= numCPUs) return kIOReturnNoResources;
673
674  vector = &vectors[source];
675
676  // Get the lock for this vector.
677  IOTakeLock(vector->interruptLock);
678
679  // Make sure the vector is not in use.
680  if (vector->interruptRegistered) {
681    IOUnlock(vector->interruptLock);
682    return kIOReturnNoResources;
683  }
684
685  // Fill in vector with the client's info.
686  vector->handler = handler;
687  vector->nub     = nub;
688  vector->source  = source;
689  vector->target  = target;
690  vector->refCon  = refCon;
691
692  // Get the vector ready.  It starts hard disabled.
693  vector->interruptDisabledHard = 1;
694  vector->interruptDisabledSoft = 1;
695  vector->interruptRegistered   = 1;
696
697  IOUnlock(vector->interruptLock);
698
699  if (enabledCPUs != numCPUs) {
700    assert_wait(this, THREAD_UNINT);
701    thread_block(THREAD_CONTINUE_NULL);
702  }
703
704  return kIOReturnSuccess;
705}
706
707IOReturn IOCPUInterruptController::getInterruptType(IOService */*nub*/,
708						    int /*source*/,
709						    int *interruptType)
710{
711  if (interruptType == 0) return kIOReturnBadArgument;
712
713  *interruptType = kIOInterruptTypeLevel;
714
715  return kIOReturnSuccess;
716}
717
718IOReturn IOCPUInterruptController::enableInterrupt(IOService */*nub*/,
719						   int /*source*/)
720{
721//  ml_set_interrupts_enabled(true);
722  return kIOReturnSuccess;
723}
724
725IOReturn IOCPUInterruptController::disableInterrupt(IOService */*nub*/,
726						    int /*source*/)
727{
728//  ml_set_interrupts_enabled(false);
729  return kIOReturnSuccess;
730}
731
732IOReturn IOCPUInterruptController::causeInterrupt(IOService */*nub*/,
733						  int /*source*/)
734{
735  ml_cause_interrupt();
736  return kIOReturnSuccess;
737}
738
739IOReturn IOCPUInterruptController::handleInterrupt(void */*refCon*/,
740						   IOService */*nub*/,
741						   int source)
742{
743  IOInterruptVector *vector;
744
745  vector = &vectors[source];
746
747  if (!vector->interruptRegistered) return kIOReturnInvalid;
748
749  vector->handler(vector->target, vector->refCon,
750		  vector->nub, vector->source);
751
752  return kIOReturnSuccess;
753}
754
755/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
756