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