1/*
2 * Copyright (c) 1998-2006 Apple Computer, Inc. All rights reserved.
3 * Copyright (c) 2007-2021 Apple Inc. All rights reserved.
4 *
5 * @APPLE_LICENSE_HEADER_START@
6 *
7 * The contents of this file constitute Original Code as defined in and
8 * are subject to the Apple Public Source License Version 1.1 (the
9 * "License").  You may not use this file except in compliance with the
10 * License.  Please obtain a copy of the License at
11 * http://www.apple.com/publicsource and read it before using this file.
12 *
13 * This Original Code and all software distributed under the License are
14 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
18 * License for the specific language governing rights and limitations
19 * under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24
25/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
26
27#include <IOKit/pci/IOPCIPrivate.h>
28#include <IOKit/system.h>
29#include <IOKit/IODeviceTreeSupport.h>
30#include <IOKit/IOPlatformExpert.h>
31#include <IOKit/IOLib.h>
32
33#define kMSIFreeCountKey    "MSIFree"
34
35#ifndef kBaseVectorNumberKey
36#define kBaseVectorNumberKey          "Base Vector Number"
37#endif
38
39#ifndef kVectorCountKey
40#define kVectorCountKey               "Vector Count"
41#endif
42
43#ifndef kInterruptControllerNameKey
44#define kInterruptControllerNameKey   "InterruptControllerName"
45#endif
46
47extern uint32_t gIOPCIFlags;
48
49#undef  super
50#define super IOInterruptController
51
52OSDefineMetaClassAndStructors(IOPCIMessagedInterruptController, IOInterruptController)
53
54/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
55
56#define API_ENTRY()																	\
57	IOInterruptSource     * interruptSources;										\
58	IOInterruptVector     * vector;													\
59	IOInterruptVector     * subVectors;												\
60	OSData                * vectorData;												\
61	IOInterruptVectorNumber vectorNumber;											\
62																					\
63	interruptSources = nub->_interruptSources;										\
64	vectorData = interruptSources[source].vectorData;								\
65	vectorNumber = *(IOInterruptVectorNumber *)vectorData->getBytesNoCopy();		\
66	vector = &vectors[vectorNumber];												\
67	if ((subVectors = (typeof(subVectors)) vector->sharedController)) 				\
68	{																				\
69		vectorNumber = source - vector->source;				/* now msi index */	    \
70		vector       = subVectors + vectorNumber;									\
71	}
72
73/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
74
75IOReturn IOPCIMessagedInterruptController::registerInterrupt(IOService *nub, int source,
76						  void *target,
77						  IOInterruptHandler handler,
78						  void *refCon)
79{
80	API_ENTRY();
81
82	// Get the lock for this vector.
83	IOLockLock(vector->interruptLock);
84
85	if (vector->interruptRegistered)
86	{
87		IOLockUnlock(vector->interruptLock);
88		return (kIOReturnNoResources);
89	}
90
91	// Fill in vector with the client's info.
92	vector->handler = handler;
93	vector->nub     = nub;
94	vector->source  = source;
95	vector->target  = target;
96	vector->refCon  = refCon;
97
98	// Do any specific initalization for this vector.
99	initVector(vectorNumber, vector);
100
101	// Get the vector ready.  It starts hard disabled.
102	vector->interruptDisabledHard = 1;
103	vector->interruptDisabledSoft = 1;
104	vector->interruptRegistered   = 1;
105
106	IOLockUnlock(vector->interruptLock);
107
108    IOPCIDevice * device = OSDynamicCast(IOPCIDevice, nub);
109	enableDeviceMSI(device);
110
111	return (kIOReturnSuccess);
112}
113
114IOReturn IOPCIMessagedInterruptController::unregisterInterrupt(IOService *nub, int source)
115{
116	API_ENTRY();
117
118	// Get the lock for this vector.
119	IOLockLock(vector->interruptLock);
120
121	// Return success if it is not already registered
122	if (!vector->interruptRegistered)
123	{
124		IOLockUnlock(vector->interruptLock);
125		return (kIOReturnSuccess);
126	}
127
128	// Soft disable the source.
129	disableInterrupt(nub, source);
130
131	// Turn the source off at hardware.
132	disableVectorHard(vectorNumber, vector);
133
134	// Clear all the storage for the vector except for interruptLock.
135	vector->interruptActive = 0;
136	vector->interruptDisabledSoft = 0;
137	vector->interruptDisabledHard = 0;
138	vector->interruptRegistered = 0;
139	vector->nub = 0;
140	vector->source = 0;
141	vector->handler = 0;
142	vector->target = 0;
143	vector->refCon = 0;
144
145	IOLockUnlock(vector->interruptLock);
146
147	IOPCIDevice * device = OSDynamicCast(IOPCIDevice, nub);
148	disableDeviceMSI(device);
149
150	return (kIOReturnSuccess);
151}
152
153IOReturn IOPCIMessagedInterruptController::getInterruptType(IOService *nub, int source,
154						 int *interruptType)
155{
156	if (interruptType == 0) return (kIOReturnBadArgument);
157
158	API_ENTRY();
159
160	*interruptType = getVectorType(vectorNumber, vector);
161
162	return (kIOReturnSuccess);
163}
164
165IOReturn IOPCIMessagedInterruptController::enableInterrupt(IOService *nub, int source)
166{
167	API_ENTRY();
168
169	if (vector->interruptDisabledSoft)
170	{
171		vector->interruptDisabledSoft = 0;
172#if !defined(__i386__) && !defined(__x86_64__)
173		OSMemoryBarrier();
174#endif
175		if (!getPlatform()->atInterruptLevel())
176		{
177			while (vector->interruptActive) {}
178		}
179		if (vector->interruptDisabledHard)
180		{
181			vector->interruptDisabledHard = 0;
182			enableVector(vectorNumber, vector);
183		}
184	}
185
186	return (kIOReturnSuccess);
187}
188
189IOReturn IOPCIMessagedInterruptController::disableInterrupt(IOService *nub, int source)
190{
191	API_ENTRY();
192
193	vector->interruptDisabledSoft = 1;
194#if !defined(__i386__) && !defined(__x86_64__)
195	OSMemoryBarrier();
196#endif
197
198	if (!getPlatform()->atInterruptLevel())
199	{
200		while (vector->interruptActive)	{}
201	}
202
203	return (kIOReturnSuccess);
204}
205
206/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
207
208IOInterruptVector * IOPCIMessagedInterruptController::allocVectors(uint32_t count)
209{
210    IOInterruptVector * vectors;
211
212    vectors = IONew(IOInterruptVector, count);
213    if (!vectors) return (0);
214    bzero(vectors, sizeof(IOInterruptVector) * count);
215
216    // Allocate locks for the vectors.
217    for (uint32_t i = 0; i < count; i++)
218    {
219        vectors[i].interruptLock = IOLockAlloc();
220        if (!vectors[i].interruptLock) return (0);
221    }
222
223    return (vectors);
224}
225
226bool IOPCIMessagedInterruptController::init(UInt32 numVectors, UInt32 baseVector)
227{
228    OSNumber * num;
229    const OSSymbol * sym = 0;
230
231    if (!super::init())
232        return (false);
233
234    _vectorCount = numVectors;
235    setProperty(kVectorCountKey, _vectorCount, 32);
236	if (-1 != baseVector) setProperty(kBaseVectorNumberKey, baseVector, 32);
237
238    // Allocate the memory for the vectors shared with the superclass.
239	vectors = allocVectors(_vectorCount);
240    if (!vectors) return (false);
241
242    attach(getPlatform());
243    sym = copyName();
244    setProperty(kInterruptControllerNameKey, (OSObject *) sym);
245    getPlatform()->registerInterruptController( (OSSymbol *) sym, this );
246    sym->release();
247
248    num = OSDynamicCast(OSNumber, getProperty(kBaseVectorNumberKey));
249    if (num) _vectorBase = num->unsigned32BitValue();
250
251    _messagedInterruptsAllocator = IORangeAllocator::withRange(0, 0, 4, IORangeAllocator::kLocking);
252    _messagedInterruptsAllocator->deallocate(0, _vectorCount);
253    setProperty(kMSIFreeCountKey, _messagedInterruptsAllocator->getFreeCount(), 32);
254
255    registerService();
256
257    return (true);
258}
259
260bool IOPCIMessagedInterruptController::init(UInt32 numVectors)
261{
262    return (init(numVectors, -1));
263}
264
265bool IOPCIMessagedInterruptController::addDeviceInterruptProperties(
266                                IORegistryEntry * device,
267                                UInt32            controllerIndex,
268                                UInt32            interruptFlags,
269                                SInt32 *          deviceIndex)
270{
271    OSArray *        controllers;
272    OSArray *        specifiers;
273    OSArray *        liveCtrls;
274    OSArray *        liveSpecs;
275    const OSSymbol * symName;
276    OSData *         specData;
277    bool             success = false;
278
279    if (!device) return false;
280
281    liveCtrls = OSDynamicCast(OSArray,
282        device->getProperty(gIOInterruptControllersKey));
283
284    liveSpecs = OSDynamicCast(OSArray,
285        device->getProperty(gIOInterruptSpecifiersKey));
286
287    if (liveCtrls && liveSpecs)
288    {
289        // reserve space for new interrupt vector
290        controllers = OSArray::withArray(liveCtrls, liveCtrls->getCount() + 1);
291        specifiers  = OSArray::withArray(liveSpecs, liveSpecs->getCount() + 1);
292    }
293    else
294    {
295        controllers = OSArray::withCapacity(1);
296        specifiers  = OSArray::withCapacity(1);
297    }
298
299    specData = OSData::withCapacity(2 * sizeof(UInt32));
300    symName = copyName();
301
302    if (!controllers || !specifiers || !specData || !symName) 			return (false);
303
304    // Specifier data will be 64-bits long, containing:
305    //    data[0] = interrupt number
306    //    data[1] = interrupt flags
307    // This must agree with interrupt controller drivers.
308    //
309    // << Warning >>
310    // IOInterruptController::registerInterrupt() assumes that
311    // the vectorNumber is the first long in the specifier.
312
313    specData->appendBytes(&controllerIndex, sizeof(controllerIndex));
314    specData->appendBytes(&interruptFlags,  sizeof(interruptFlags));
315
316    if (deviceIndex)
317        *deviceIndex = specifiers->getCount() - 1;
318
319    success = specifiers->setObject(specData)
320                && controllers->setObject(symName);
321
322    if (success)
323    {
324        device->setProperty(gIOInterruptControllersKey, controllers);
325        device->setProperty(gIOInterruptSpecifiersKey, specifiers);
326    }
327
328    specifiers->release();
329    controllers->release();
330    symName->release();
331    specData->release();
332
333    return (success);
334}
335
336IOReturn IOPCIMessagedInterruptController::allocateDeviceInterrupts(
337                                IOService * entry, uint32_t numVectors, uint32_t msiCapability,
338                                uint64_t * msiAddress, uint32_t * msiData)
339{
340    IOReturn      ret;
341    IOPCIDevice * device;
342    uint32_t      vector, firstVector = _vectorBase;
343    IORangeScalar rangeStart;
344    uint32_t      message[3];
345    uint32_t      msiPhysVectors;
346    uint16_t      control = 0;
347    bool          allocated;
348
349    device = OSDynamicCast(IOPCIDevice, entry);
350    if (!device) msiCapability = 0;
351    msiPhysVectors = 0;
352
353    if (msiCapability)
354    {
355        uint32_t    vendorProd;
356        uint32_t    revIDClass;
357
358        msiCapability  = device->reserved->msiCapability;
359        control    = device->configRead16(msiCapability + 2);
360        if (kMSIX & device->reserved->msiMode)
361            msiPhysVectors = 1 + (0x7ff & control);
362        else
363            msiPhysVectors = 1 << (0x7 & (control >> 1));
364
365	    numVectors = msiPhysVectors;
366        vendorProd = device->savedConfig[kIOPCIConfigVendorID >> 2];
367        revIDClass = device->savedConfig[kIOPCIConfigRevisionID >> 2];
368
369        // pci2pci bridges get none or one for hotplug
370        if (0x0604 == (revIDClass >> 16))
371        {
372            bool tunnelLink = (0 != device->getProperty(kIOPCITunnelLinkChangeKey));
373            if (tunnelLink
374                || device->getProperty(kIOPCIHotPlugKey)
375                || device->getProperty(kIOPCILinkChangeKey))
376            {
377                // hot plug bridge, but use legacy if avail
378                uint8_t line = device->configRead8(kIOPCIConfigInterruptLine);
379                if (tunnelLink)
380                {
381                    tunnelLink = (0x15138086 != vendorProd)
382                              && (0x151a8086 != vendorProd)
383                              && (0x151b8086 != vendorProd)
384                              && (0x15498086 != vendorProd)
385                              && ((0x15478086 != vendorProd) || ((revIDClass & 0xff) > 1));
386                }
387                if (tunnelLink || (line == 0) || (line == 0xFF))
388                {
389                    // no legacy ints, need one MSI
390                    numVectors = 1;
391                }
392                else numVectors = 0;
393            }
394            else
395            {
396                // no hot plug
397                numVectors = 0;
398            }
399        }
400#if !defined(SUPPORT_MULTIPLE_MSI)
401        else if (numVectors)
402        {
403            // max per function is one
404            numVectors = 1;
405        }
406#endif
407    }
408
409    allocated  = false;
410    rangeStart = 0;
411    while (!allocated && numVectors > 0)
412    {
413        allocated = allocateInterruptVectors(entry, numVectors, &rangeStart);
414        if (!allocated) numVectors >>= 1;
415    }
416    if (!allocated) return (kIOReturnNoSpace);
417
418    firstVector = rangeStart;
419    ret = entry->callPlatformFunction(gIOPlatformGetMessagedInterruptAddressKey,
420            /* waitForFunction */ false,
421            /* nub             */ entry,
422            /* options         */ (void *) 0,
423            /* vector          */ (void *) (uintptr_t) (firstVector + _vectorBase),
424            /* message         */ (void *) &message[0]);
425
426    if (kIOReturnSuccess == ret)
427    {
428        if (msiAddress) *msiAddress = message[0] | (((uint64_t)message[1]) << 32);
429        if (msiData)    *msiData    = message[2];
430
431        if (msiCapability)
432        {
433			IOPCIConfigShadow * shadow;
434
435			shadow = configShadow(device);
436			if ((kMSIX & device->reserved->msiMode)
437			  && (numVectors < msiPhysVectors))
438			{
439				device->reserved->msiVectors = allocVectors(msiPhysVectors);
440				IOInterruptVector * ivector = &vectors[firstVector];
441				// Fill in vector with the IOPCIMessagedInterruptController info
442				ivector->handler = OSMemberFunctionCast(IOInterruptHandler,
443						this, &IOPCIMessagedInterruptController::handleInterrupt);
444				ivector->nub     = device;
445				ivector->target  = this;
446				ivector->refCon  = 0;
447				initVector(firstVector, ivector);
448				ivector->interruptDisabledSoft = 0;
449				ivector->interruptDisabledHard = 0;
450				ivector->interruptRegistered   = msiPhysVectors;
451				ivector->sharedController = (IOSharedInterruptController *) device->reserved->msiVectors;
452
453				for (vector = 0; vector < msiPhysVectors; vector++)
454				{
455					SInt32 deviceIndex;
456					addDeviceInterruptProperties(entry, firstVector,
457							kIOInterruptTypeEdge | kIOInterruptTypePCIMessaged, &deviceIndex);
458					if (!vector) ivector->source = deviceIndex;
459				}
460			}
461			else
462			{
463				device->reserved->msiVectors = &vectors[firstVector];
464				for (vector = firstVector; vector < (firstVector + numVectors); vector++)
465				{
466					addDeviceInterruptProperties(entry, vector,
467							kIOInterruptTypeEdge | kIOInterruptTypePCIMessaged, NULL);
468				}
469			}
470
471			shadow->savedMSIAddress0 = message[0];
472			shadow->savedMSIAddress1 = message[1];
473			shadow->savedMSIData     = message[2];
474			device->reserved->msiPhysVectorCount = msiPhysVectors;
475			device->reserved->msiVectorCount     = numVectors;
476
477            if (kMSIX & device->reserved->msiMode)
478            {
479                IOMemoryMap * map;
480                uint32_t      table;
481                uint8_t       bar;
482
483                table = device->configRead32(msiCapability + 8);
484                bar = kIOPCIConfigBaseAddress0 + ((table & 7) << 2);
485                table &= ~7;
486                map = device->mapDeviceMemoryWithRegister(bar);
487                if (map) device->reserved->msiPBA = map->getAddress() + table;
488
489                table  = device->configRead32(msiCapability + 4);
490                bar    = (kIOPCIConfigBaseAddress0 + ((table & 7) << 2));
491                table &= ~7;
492                map = device->mapDeviceMemoryWithRegister(bar);
493                if (map) device->reserved->msiTable = map->getAddress() + table;
494            }
495            else
496            {
497				if (numVectors) numVectors = (31 - __builtin_clz(numVectors)); // log2
498				control |= (numVectors << 4);
499			}
500			control &= ~((1 << 15) | 1); 			// disabled
501			device->reserved->msiControl = control;
502			initDevice(device, shadow);
503        }
504    }
505
506    return (ret);
507}
508
509void IOPCIMessagedInterruptController::initDevice(IOPCIDevice * device, IOPCIConfigShadow * shadow)
510{
511    IOInterruptVector * vectors;
512	uint32_t            numVectors, msiPhysVectors, vector, data;
513	uint16_t            control, msiCapability, cmd;
514
515	msiCapability  = device->reserved->msiCapability;
516	control        = device->reserved->msiControl;
517	numVectors     = device->reserved->msiVectorCount;
518	msiPhysVectors = device->reserved->msiPhysVectorCount;
519
520	if (kMSIX & device->reserved->msiMode)
521	{
522		if (device->reserved->msiTable)
523		{
524			vectors = device->reserved->msiVectors;
525			cmd = device->configRead16(kIOPCIConfigCommand);
526			device->configWrite16(kIOPCIConfigCommand, cmd | kIOPCICommandMemorySpace);
527			for (vector = 0; vector < msiPhysVectors; vector++)
528			{
529				data = shadow->savedMSIData;
530				if (vector < numVectors) data += vector;
531				((uint32_t *) device->reserved->msiTable)[vector*4 + 0] = shadow->savedMSIAddress0;
532				((uint32_t *) device->reserved->msiTable)[vector*4 + 1] = shadow->savedMSIAddress1;
533				((uint32_t *) device->reserved->msiTable)[vector*4 + 2] = data;
534				((uint32_t *) device->reserved->msiTable)[vector*4 + 3] = vectors[vector].interruptDisabledHard;
535			}
536			device->configWrite16(kIOPCIConfigCommand, cmd);
537		}
538	}
539	else
540	{
541		device->configWrite32(msiCapability + 4, shadow->savedMSIAddress0);
542		if (0x0080 & control)
543		{
544			// 64b
545			device->configWrite32(msiCapability + 8,  shadow->savedMSIAddress1);
546			device->configWrite16(msiCapability + 12, shadow->savedMSIData);
547		}
548		else
549		{
550			device->configWrite16(msiCapability + 8,  shadow->savedMSIData);
551		}
552//		if (0x0100 & control) msiBlockSize += 2;
553	}
554	device->configWrite16(msiCapability + 2, control);
555}
556
557void IOPCIMessagedInterruptController::enableDeviceMSI(IOPCIDevice *device)
558{
559    if (device && device->reserved && !device->isInactive())
560    {
561        if (!device->reserved->msiEnable)
562        {
563            IOByteCount msi = device->reserved->msiCapability;
564            uint16_t control;
565
566            control = device->reserved->msiControl;
567            if (kMSIX & device->reserved->msiMode)
568            {
569                control |= (1 << 15);
570            }
571            else
572            {
573                control |= 1;
574            }
575			device->reserved->msiControl = control;
576            device->configWrite16(msi + 2, control);
577
578            control = device->configRead16(kIOPCIConfigCommand);
579            control |= kIOPCICommandInterruptDisable | kIOPCICommandBusMaster;
580            device->configWrite16(kIOPCIConfigCommand, control);
581            device->setProperty("IOPCIMSIMode", kOSBooleanTrue);
582        }
583        device->reserved->msiEnable++;
584    }
585}
586
587void IOPCIMessagedInterruptController::disableDeviceMSI(IOPCIDevice *device)
588{
589    if (device && device->reserved
590        && device->reserved->msiEnable
591        && !(--device->reserved->msiEnable)
592        && !device->isInactive())
593    {
594        IOByteCount msi = device->reserved->msiCapability;
595        uint16_t control;
596
597        control = device->reserved->msiControl;
598        control &= ~((1 << 15) | 1);
599		device->reserved->msiControl = control;
600        device->configWrite16(msi + 2, control);
601
602		control = device->configRead16(kIOPCIConfigCommand);
603		control &= ~kIOPCICommandInterruptDisable;
604        device->configWrite16(kIOPCIConfigCommand, control);
605
606        device->removeProperty("IOPCIMSIMode");
607    }
608}
609
610void IOPCIMessagedInterruptController::saveDeviceState(IOPCIDevice * device, IOPCIConfigShadow * shadow)
611{
612    if (!device->reserved->msiCapability) return;
613}
614
615void IOPCIMessagedInterruptController::restoreDeviceState(IOPCIDevice * device, IOPCIConfigShadow * shadow)
616{
617    if (!device->reserved->msiCapability) return;
618    initDevice(device, shadow);
619}
620
621bool IOPCIMessagedInterruptController::reserveVectors(UInt32 vector, UInt32 count)
622{
623    bool result;
624
625    result = _messagedInterruptsAllocator->allocateRange(vector, count);
626    if (result) setProperty(kMSIFreeCountKey, _messagedInterruptsAllocator->getFreeCount(), 32);
627
628    return (result);
629}
630
631bool IOPCIMessagedInterruptController::allocateInterruptVectors( IOService *device,
632                                                                 uint32_t numVectors,
633                                                                 IORangeScalar *rangeStartOut)
634{
635    bool result;
636
637    result = _messagedInterruptsAllocator->allocate(numVectors, rangeStartOut, numVectors);
638    if (result) setProperty(kMSIFreeCountKey, _messagedInterruptsAllocator->getFreeCount(), 32);
639
640    return (result);
641}
642
643IOReturn IOPCIMessagedInterruptController::deallocateDeviceInterrupts(IOService * device)
644{
645    const OSSymbol * myName;
646    OSArray *        controllers;
647    OSObject *       controller;
648    OSArray *        specs;
649    OSData *         spec;
650    uint32_t         index = 0;
651    uint32_t         firstVector;
652
653    myName = copyName();
654
655    controllers = OSDynamicCast(OSArray, device->getProperty(gIOInterruptControllersKey));
656    specs = OSDynamicCast(OSArray, device->getProperty(gIOInterruptSpecifiersKey));
657
658    if (!myName || !controllers || !specs) return (kIOReturnBadArgument);
659
660	for (firstVector = -1U;
661        (spec = OSDynamicCast(OSData, specs->getObject(index)))
662		  && (controller = controllers->getObject(index));
663		index++)
664    {
665        if (!controller->isEqualTo(myName)) continue;
666
667		uint32_t vector = *((uint32_t *) spec->getBytesNoCopy());
668		if (vector == firstVector) continue;
669		if (-1U == firstVector)    firstVector = vector;
670		deallocateInterrupt(vector);
671    }
672    myName->release();
673
674    return (kIOReturnSuccess);
675}
676
677void IOPCIMessagedInterruptController::deallocateInterrupt(UInt32 vector)
678{
679    IOInterruptVector * subVectors;
680    IORangeScalar       rangeStart;
681    uint32_t            count;
682
683	if ((subVectors = (IOInterruptVector *) vectors[vector].sharedController))
684	{
685		count = vectors[vector].interruptRegistered;
686		vectors[vector].sharedController = 0;
687	    IODelete(subVectors, IOInterruptVector, count);
688	}
689
690	rangeStart = vector;
691    _messagedInterruptsAllocator->deallocate(rangeStart, 1);
692    setProperty(kMSIFreeCountKey, _messagedInterruptsAllocator->getFreeCount(), 32);
693}
694
695IOReturn
696IOPCIMessagedInterruptController::handleInterrupt( void *      state,
697                                                   IOService * nub,
698                                                   int         source)
699{
700    IOInterruptVector * vector;
701	IOInterruptVector * subVectors;
702	IOPCIDevice       * device;
703	uint64_t            bits;
704	uint32_t            count, bit;
705
706    source -= _vectorBase;
707    if ((source < 0) || (source > (int) _vectorCount)) return (kIOReturnSuccess);
708
709    vector = &vectors[source];
710	if ((subVectors = (IOInterruptVector *) vector->sharedController))
711	{
712		device = (IOPCIDevice *) vector->nub;
713//      if (!(kIOPCICommandMemorySpace & device->configRead16(kIOPCIConfigCommand))) return (kIOReturnSuccess);
714
715		count = vector->interruptRegistered;
716		bits = 0;
717		for (source = 0; source < count; source++)
718		{
719			bit = (source & 63);
720			if (!bit) bits = ((uint64_t *) device->reserved->msiPBA)[source >> 6];
721			if (!(bits & (1ULL << bit))) continue;
722
723			vector = &subVectors[source];
724//		    if (!vector->interruptRegistered && source) vector = &vectors[0];
725			vector->interruptActive = 1;
726			if (vector->interruptRegistered)
727			{
728				if (vector->interruptDisabledHard) vector->interruptRegistered = 3;
729				else
730				{
731					vector->handler(vector->target, vector->refCon, vector->nub, vector->source);
732				}
733			}
734			vector->interruptActive = 0;
735		}
736	}
737	else
738    {
739		vector->interruptActive = 1;
740		if (vector->interruptRegistered)
741		{
742			if (vector->interruptDisabledHard) vector->interruptRegistered = 3;
743			else
744			{
745				vector->handler(vector->target, vector->refCon, vector->nub, vector->source);
746			}
747		}
748		vector->interruptActive = 0;
749    }
750
751    return (kIOReturnSuccess);
752}
753
754bool IOPCIMessagedInterruptController::vectorCanBeShared(IOInterruptVectorNumber vectorNumber,
755                                       					 IOInterruptVector * vector)
756{
757    return (false);
758}
759
760void IOPCIMessagedInterruptController::initVector(IOInterruptVectorNumber vectorNumber,
761                                       			  IOInterruptVector * vector)
762{
763}
764
765int IOPCIMessagedInterruptController::getVectorType(IOInterruptVectorNumber vectorNumber,
766                                       				IOInterruptVector * vector)
767{
768    return (kIOInterruptTypeEdge | kIOInterruptTypePCIMessaged);
769}
770
771void IOPCIMessagedInterruptController::disableVectorHard(IOInterruptVectorNumber vectorNumber,
772                                       					 IOInterruptVector * vector)
773{
774	IOPCIDevice * device;
775	device = (IOPCIDevice *) vector->nub;
776
777	if (device->reserved->msiTable)
778	{
779		// masked
780		((uint32_t *) device->reserved->msiTable)[vectorNumber * 4 + 3] = 1;
781	}
782}
783
784void IOPCIMessagedInterruptController::enableVector(IOInterruptVectorNumber vectorNumber,
785                                       				IOInterruptVector * vector)
786{
787	IOPCIDevice * device;
788	device = (IOPCIDevice *) vector->nub;
789
790    if (3 == vector->interruptRegistered)
791    {
792        vector->interruptRegistered = 1;
793        vector->handler(vector->target, vector->refCon,
794                        vector->nub, vector->source);
795    }
796	if (device->reserved->msiTable)
797	{
798		// enabled
799		((uint32_t *) device->reserved->msiTable)[vectorNumber * 4 + 3] = 0;
800	}
801}
802