xref: /plan9-contrib/sys/src/9k/k10/ioapic.c (revision 099a302f446d4403b6040f6424f6808f43846106)
19ef1f84bSDavid du Colombier #include "u.h"
29ef1f84bSDavid du Colombier #include "../port/lib.h"
39ef1f84bSDavid du Colombier #include "mem.h"
49ef1f84bSDavid du Colombier #include "dat.h"
59ef1f84bSDavid du Colombier #include "fns.h"
69ef1f84bSDavid du Colombier 
79ef1f84bSDavid du Colombier #include "apic.h"
89ef1f84bSDavid du Colombier #include "io.h"
99ef1f84bSDavid du Colombier 
10bbf74bb6SDavid du Colombier typedef struct Rbus Rbus;
119ef1f84bSDavid du Colombier typedef struct Rdt Rdt;
12bbf74bb6SDavid du Colombier 
13bbf74bb6SDavid du Colombier struct Rbus {
14bbf74bb6SDavid du Colombier 	Rbus	*next;
15ffa640cdSDavid du Colombier 	int	bustype;
169ef1f84bSDavid du Colombier 	int	devno;
17bbf74bb6SDavid du Colombier 	Rdt	*rdt;
18bbf74bb6SDavid du Colombier };
19bbf74bb6SDavid du Colombier 
20bbf74bb6SDavid du Colombier struct Rdt {
21bbf74bb6SDavid du Colombier 	Apic*	apic;
229ef1f84bSDavid du Colombier 	int	intin;
239ef1f84bSDavid du Colombier 	u32int	lo;
249ef1f84bSDavid du Colombier 
25bbf74bb6SDavid du Colombier 	int	ref;				/* could map to multiple busses */
26bbf74bb6SDavid du Colombier 	int	enabled;			/* times enabled */
27bbf74bb6SDavid du Colombier };
289ef1f84bSDavid du Colombier 
299ef1f84bSDavid du Colombier enum {						/* IOAPIC registers */
309ef1f84bSDavid du Colombier 	Ioregsel	= 0x00,			/* indirect register address */
319ef1f84bSDavid du Colombier 	Iowin		= 0x04,			/* indirect register data */
329ef1f84bSDavid du Colombier 	Ioipa		= 0x08,			/* IRQ Pin Assertion */
339ef1f84bSDavid du Colombier 	Ioeoi		= 0x10,			/* EOI */
349ef1f84bSDavid du Colombier 
359ef1f84bSDavid du Colombier 	Ioapicid	= 0x00,			/* Identification */
369ef1f84bSDavid du Colombier 	Ioapicver	= 0x01,			/* Version */
379ef1f84bSDavid du Colombier 	Ioapicarb	= 0x02,			/* Arbitration */
389ef1f84bSDavid du Colombier 	Ioabcfg		= 0x03,			/* Boot Coniguration */
399ef1f84bSDavid du Colombier 	Ioredtbl	= 0x10,			/* Redirection Table */
409ef1f84bSDavid du Colombier };
419ef1f84bSDavid du Colombier 
429ef1f84bSDavid du Colombier static Rdt rdtarray[Nrdt];
439ef1f84bSDavid du Colombier static int nrdtarray;
449ef1f84bSDavid du Colombier static int gsib;
45bbf74bb6SDavid du Colombier static Rbus* rdtbus[Nbus];
469ef1f84bSDavid du Colombier static Rdt* rdtvecno[IdtMAX+1];
479ef1f84bSDavid du Colombier 
489ef1f84bSDavid du Colombier static Lock idtnolock;
499ef1f84bSDavid du Colombier static int idtno = IdtIOAPIC;
509ef1f84bSDavid du Colombier 
519ef1f84bSDavid du Colombier static void
rtblget(Apic * apic,int sel,u32int * hi,u32int * lo)529ef1f84bSDavid du Colombier rtblget(Apic* apic, int sel, u32int* hi, u32int* lo)
539ef1f84bSDavid du Colombier {
549ef1f84bSDavid du Colombier 	u32int r;
559ef1f84bSDavid du Colombier 
569ef1f84bSDavid du Colombier 	sel = Ioredtbl + 2*sel;
579ef1f84bSDavid du Colombier 
589ef1f84bSDavid du Colombier 	*(apic->addr+Ioregsel) = sel+1;
599ef1f84bSDavid du Colombier 	r = *(apic->addr+Iowin);
609ef1f84bSDavid du Colombier 	if(hi)
619ef1f84bSDavid du Colombier 		*hi = r;
629ef1f84bSDavid du Colombier 	*(apic->addr+Ioregsel) = sel;
639ef1f84bSDavid du Colombier 	r = *(apic->addr+Iowin);
649ef1f84bSDavid du Colombier 	if(lo)
659ef1f84bSDavid du Colombier 		*lo = r;
669ef1f84bSDavid du Colombier }
679ef1f84bSDavid du Colombier 
689ef1f84bSDavid du Colombier static void
rtblput(Apic * apic,int sel,u32int hi,u32int lo)699ef1f84bSDavid du Colombier rtblput(Apic* apic, int sel, u32int hi, u32int lo)
709ef1f84bSDavid du Colombier {
719ef1f84bSDavid du Colombier 	sel = Ioredtbl + 2*sel;
729ef1f84bSDavid du Colombier 
739ef1f84bSDavid du Colombier 	*(apic->addr+Ioregsel) = sel+1;
749ef1f84bSDavid du Colombier 	*(apic->addr+Iowin) = hi;
759ef1f84bSDavid du Colombier 	*(apic->addr+Ioregsel) = sel;
769ef1f84bSDavid du Colombier 	*(apic->addr+Iowin) = lo;
779ef1f84bSDavid du Colombier }
789ef1f84bSDavid du Colombier 
79bbf74bb6SDavid du Colombier Rdt*
rdtlookup(Apic * apic,int intin)80bbf74bb6SDavid du Colombier rdtlookup(Apic *apic, int intin)
81bbf74bb6SDavid du Colombier {
82bbf74bb6SDavid du Colombier 	int i;
83bbf74bb6SDavid du Colombier 	Rdt *r;
84bbf74bb6SDavid du Colombier 
85bbf74bb6SDavid du Colombier 	for(i = 0; i < nrdtarray; i++){
86bbf74bb6SDavid du Colombier 		r = rdtarray + i;
87bbf74bb6SDavid du Colombier 		if(apic == r->apic && intin == r->intin)
88bbf74bb6SDavid du Colombier 			return r;
89bbf74bb6SDavid du Colombier 	}
90bbf74bb6SDavid du Colombier 	return nil;
91bbf74bb6SDavid du Colombier }
92bbf74bb6SDavid du Colombier 
939ef1f84bSDavid du Colombier void
ioapicintrinit(int bustype,int busno,int apicno,int intin,int devno,u32int lo)94ffa640cdSDavid du Colombier ioapicintrinit(int bustype, int busno, int apicno, int intin, int devno, u32int lo)
959ef1f84bSDavid du Colombier {
96bbf74bb6SDavid du Colombier 	Rbus *rbus;
979ef1f84bSDavid du Colombier 	Rdt *rdt;
989ef1f84bSDavid du Colombier 	Apic *apic;
999ef1f84bSDavid du Colombier 
1009ef1f84bSDavid du Colombier 	if(busno >= Nbus || apicno >= Napic || nrdtarray >= Nrdt)
1019ef1f84bSDavid du Colombier 		return;
1029ef1f84bSDavid du Colombier 	apic = &ioapic[apicno];
1039ef1f84bSDavid du Colombier 	if(!apic->useable || intin >= apic->nrdt)
1049ef1f84bSDavid du Colombier 		return;
1059ef1f84bSDavid du Colombier 
106bbf74bb6SDavid du Colombier 	rdt = rdtlookup(apic, intin);
107bbf74bb6SDavid du Colombier 	if(rdt == nil){
108bbf74bb6SDavid du Colombier 		if(nrdtarray == nelem(rdtarray)){
109bbf74bb6SDavid du Colombier 			print("ioapic: intrinit: rdtarray too small\n");
110bbf74bb6SDavid du Colombier 			return;
111bbf74bb6SDavid du Colombier 		}
1129ef1f84bSDavid du Colombier 		rdt = &rdtarray[nrdtarray++];
1139ef1f84bSDavid du Colombier 		rdt->apic = apic;
1149ef1f84bSDavid du Colombier 		rdt->intin = intin;
1159ef1f84bSDavid du Colombier 		rdt->lo = lo;
116bbf74bb6SDavid du Colombier 	}else{
117bbf74bb6SDavid du Colombier 		if(lo != rdt->lo){
118ffa640cdSDavid du Colombier 			if(bustype == BusISA && intin < 16 && lo == (Im|IPhigh|TMedge)){
119ffa640cdSDavid du Colombier 				DBG("override: isa %d %.8ux\n", intin, rdt->lo);
120ffa640cdSDavid du Colombier 				return;	/* expected; default was overridden*/
121ffa640cdSDavid du Colombier 			}
122ffa640cdSDavid du Colombier 			print("multiple irq botch type %d bus %d %d/%d/%d lo %.8ux vs %.8ux\n",
123ffa640cdSDavid du Colombier 				bustype, busno, apicno, intin, devno, lo, rdt->lo);
124bbf74bb6SDavid du Colombier 			return;
125bbf74bb6SDavid du Colombier 		}
126bbf74bb6SDavid du Colombier 		DBG("dup rdt %d %d %d %d %.8ux\n", busno, apicno, intin, devno, lo);
127bbf74bb6SDavid du Colombier 	}
128bbf74bb6SDavid du Colombier 	rdt->ref++;
129bbf74bb6SDavid du Colombier 	rbus = malloc(sizeof(*rbus));
130bbf74bb6SDavid du Colombier 	rbus->rdt = rdt;
131ffa640cdSDavid du Colombier 	rbus->bustype = bustype;
132bbf74bb6SDavid du Colombier 	rbus->devno = devno;
133bbf74bb6SDavid du Colombier 	rbus->next = rdtbus[busno];
134bbf74bb6SDavid du Colombier 	rdtbus[busno] = rbus;
1359ef1f84bSDavid du Colombier }
1369ef1f84bSDavid du Colombier 
1379ef1f84bSDavid du Colombier void
ioapicinit(int id,uintmem pa)1389ef1f84bSDavid du Colombier ioapicinit(int id, uintmem pa)
1399ef1f84bSDavid du Colombier {
1409ef1f84bSDavid du Colombier 	Apic *apic;
1419ef1f84bSDavid du Colombier 
1429ef1f84bSDavid du Colombier 	/*
1439ef1f84bSDavid du Colombier 	 * Mark the IOAPIC useable if it has a good ID
1449ef1f84bSDavid du Colombier 	 * and the registers can be mapped.
1459ef1f84bSDavid du Colombier 	 */
1469ef1f84bSDavid du Colombier 	if(id >= Napic)
1479ef1f84bSDavid du Colombier 		return;
1489ef1f84bSDavid du Colombier 
1499ef1f84bSDavid du Colombier 	apic = &ioapic[id];
1509ef1f84bSDavid du Colombier 	if(apic->useable || (apic->addr = vmap(pa, 1024)) == nil)
1519ef1f84bSDavid du Colombier 		return;
1529ef1f84bSDavid du Colombier 	apic->useable = 1;
1539ef1f84bSDavid du Colombier 
1549ef1f84bSDavid du Colombier 	/*
1559ef1f84bSDavid du Colombier 	 * Initialise the IOAPIC.
1569ef1f84bSDavid du Colombier 	 * The MultiProcessor Specification says it is the
1579ef1f84bSDavid du Colombier 	 * responsibility of the O/S to set the APIC ID.
1589ef1f84bSDavid du Colombier 	 */
1599ef1f84bSDavid du Colombier 	lock(apic);
1609ef1f84bSDavid du Colombier 	*(apic->addr+Ioregsel) = Ioapicver;
1619ef1f84bSDavid du Colombier 	apic->nrdt = ((*(apic->addr+Iowin)>>16) & 0xff) + 1;
1629ef1f84bSDavid du Colombier 	apic->gsib = gsib;
1639ef1f84bSDavid du Colombier 	gsib += apic->nrdt;
1649ef1f84bSDavid du Colombier 
1659ef1f84bSDavid du Colombier 	*(apic->addr+Ioregsel) = Ioapicid;
1669ef1f84bSDavid du Colombier 	*(apic->addr+Iowin) = id<<24;
1679ef1f84bSDavid du Colombier 	unlock(apic);
1689ef1f84bSDavid du Colombier }
1699ef1f84bSDavid du Colombier 
1709ef1f84bSDavid du Colombier void
ioapicdump(void)1719ef1f84bSDavid du Colombier ioapicdump(void)
1729ef1f84bSDavid du Colombier {
1739ef1f84bSDavid du Colombier 	int i, n;
174bbf74bb6SDavid du Colombier 	Rbus *rbus;
1759ef1f84bSDavid du Colombier 	Rdt *rdt;
1769ef1f84bSDavid du Colombier 	Apic *apic;
1779ef1f84bSDavid du Colombier 	u32int hi, lo;
1789ef1f84bSDavid du Colombier 
1799ef1f84bSDavid du Colombier 	if(!DBGFLG)
1809ef1f84bSDavid du Colombier 		return;
1819ef1f84bSDavid du Colombier 
1829ef1f84bSDavid du Colombier 	for(i = 0; i < Napic; i++){
1839ef1f84bSDavid du Colombier 		apic = &ioapic[i];
1849ef1f84bSDavid du Colombier 		if(!apic->useable || apic->addr == 0)
1859ef1f84bSDavid du Colombier 			continue;
1869ef1f84bSDavid du Colombier 		DBG("ioapic %d addr %#p nrdt %d gsib %d\n",
1879ef1f84bSDavid du Colombier 			i, apic->addr, apic->nrdt, apic->gsib);
1889ef1f84bSDavid du Colombier 		for(n = 0; n < apic->nrdt; n++){
1899ef1f84bSDavid du Colombier 			lock(apic);
1909ef1f84bSDavid du Colombier 			rtblget(apic, n, &hi, &lo);
1919ef1f84bSDavid du Colombier 			unlock(apic);
1929ef1f84bSDavid du Colombier 			DBG(" rdt %2.2d %#8.8ux %#8.8ux\n", n, hi, lo);
1939ef1f84bSDavid du Colombier 		}
1949ef1f84bSDavid du Colombier 	}
1959ef1f84bSDavid du Colombier 	for(i = 0; i < Nbus; i++){
196bbf74bb6SDavid du Colombier 		if((rbus = rdtbus[i]) == nil)
1979ef1f84bSDavid du Colombier 			continue;
1989ef1f84bSDavid du Colombier 		DBG("iointr bus %d:\n", i);
199bbf74bb6SDavid du Colombier 		while(rbus != nil){
200bbf74bb6SDavid du Colombier 			rdt = rbus->rdt;
201bbf74bb6SDavid du Colombier 			DBG(" apic %ld devno %#ux (%d %d) intin %d lo %#ux ref %d\n",
202bbf74bb6SDavid du Colombier 				rdt->apic-ioapic, rbus->devno, rbus->devno>>2,
203bbf74bb6SDavid du Colombier 				rbus->devno & 0x03, rdt->intin, rdt->lo, rdt->ref);
204bbf74bb6SDavid du Colombier 			rbus = rbus->next;
2059ef1f84bSDavid du Colombier 		}
2069ef1f84bSDavid du Colombier 	}
2079ef1f84bSDavid du Colombier }
2089ef1f84bSDavid du Colombier 
2099ef1f84bSDavid du Colombier void
ioapiconline(void)2109ef1f84bSDavid du Colombier ioapiconline(void)
2119ef1f84bSDavid du Colombier {
2129ef1f84bSDavid du Colombier 	int i;
2139ef1f84bSDavid du Colombier 	Apic *apic;
2149ef1f84bSDavid du Colombier 
2159ef1f84bSDavid du Colombier 	for(apic = ioapic; apic < &ioapic[Napic]; apic++){
2169ef1f84bSDavid du Colombier 		if(!apic->useable || apic->addr == nil)
2179ef1f84bSDavid du Colombier 			continue;
2189ef1f84bSDavid du Colombier 		for(i = 0; i < apic->nrdt; i++){
2199ef1f84bSDavid du Colombier 			lock(apic);
2209ef1f84bSDavid du Colombier 			rtblput(apic, i, 0, Im);
2219ef1f84bSDavid du Colombier 			unlock(apic);
2229ef1f84bSDavid du Colombier 		}
2239ef1f84bSDavid du Colombier 	}
2249ef1f84bSDavid du Colombier 	if(DBGFLG)
2259ef1f84bSDavid du Colombier 		ioapicdump();
2269ef1f84bSDavid du Colombier }
2279ef1f84bSDavid du Colombier 
2289ef1f84bSDavid du Colombier static int dfpolicy = 0;
2299ef1f84bSDavid du Colombier 
2309ef1f84bSDavid du Colombier static void
ioapicintrdd(u32int * hi,u32int * lo)2319ef1f84bSDavid du Colombier ioapicintrdd(u32int* hi, u32int* lo)
2329ef1f84bSDavid du Colombier {
2339ef1f84bSDavid du Colombier 	int i;
2349ef1f84bSDavid du Colombier 	static int df;
2359ef1f84bSDavid du Colombier 	static Lock dflock;
2369ef1f84bSDavid du Colombier 
2379ef1f84bSDavid du Colombier 	/*
2389ef1f84bSDavid du Colombier 	 * Set delivery mode (lo) and destination field (hi),
2399ef1f84bSDavid du Colombier 	 * according to interrupt routing policy.
2409ef1f84bSDavid du Colombier 	 */
2419ef1f84bSDavid du Colombier 	/*
2429ef1f84bSDavid du Colombier 	 * The bulk of this code was written ~1995, when there was
2439ef1f84bSDavid du Colombier 	 * one architecture and one generation of hardware, the number
2449ef1f84bSDavid du Colombier 	 * of CPUs was up to 4(8) and the choices for interrupt routing
2459ef1f84bSDavid du Colombier 	 * were physical, or flat logical (optionally with lowest
2469ef1f84bSDavid du Colombier 	 * priority interrupt). Logical mode hasn't scaled well with
2479ef1f84bSDavid du Colombier 	 * the increasing number of packages/cores/threads, so the
2489ef1f84bSDavid du Colombier 	 * fall-back is to physical mode, which works across all processor
2499ef1f84bSDavid du Colombier 	 * generations, both AMD and Intel, using the APIC and xAPIC.
2509ef1f84bSDavid du Colombier 	 *
2519ef1f84bSDavid du Colombier 	 * Interrupt routing policy can be set here.
2529ef1f84bSDavid du Colombier 	 */
2539ef1f84bSDavid du Colombier 	switch(dfpolicy){
2549ef1f84bSDavid du Colombier 	default:				/* noise core 0 */
2559ef1f84bSDavid du Colombier 		*hi = sys->machptr[0]->apicno<<24;
2569ef1f84bSDavid du Colombier 		break;
2579ef1f84bSDavid du Colombier 	case 1:					/* round-robin */
2589ef1f84bSDavid du Colombier 		/*
2599ef1f84bSDavid du Colombier 		 * Assign each interrupt to a different CPU on a round-robin
2609ef1f84bSDavid du Colombier 		 * Some idea of the packages/cores/thread topology would be
2619ef1f84bSDavid du Colombier 		 * useful here, e.g. to not assign interrupts to more than one
2629ef1f84bSDavid du Colombier 		 * thread in a core. But, as usual, Intel make that an onerous
2639ef1f84bSDavid du Colombier 		 * task.
2649ef1f84bSDavid du Colombier 		 */
2659ef1f84bSDavid du Colombier 		lock(&dflock);
2669ef1f84bSDavid du Colombier 		for(;;){
2679ef1f84bSDavid du Colombier 			i = df++;
2689ef1f84bSDavid du Colombier 			if(df >= MACHMAX+1)
2699ef1f84bSDavid du Colombier 				df = 0;
2709ef1f84bSDavid du Colombier 			if(sys->machptr[i] == nil || !sys->machptr[i]->online)
2719ef1f84bSDavid du Colombier 				continue;
2729ef1f84bSDavid du Colombier 			i = sys->machptr[i]->apicno;
2739ef1f84bSDavid du Colombier 			if(xapic[i].useable && xapic[i].addr == 0)
2749ef1f84bSDavid du Colombier 				break;
2759ef1f84bSDavid du Colombier 		}
2769ef1f84bSDavid du Colombier 		unlock(&dflock);
2779ef1f84bSDavid du Colombier 
2789ef1f84bSDavid du Colombier 		*hi = i<<24;
2799ef1f84bSDavid du Colombier 		break;
2809ef1f84bSDavid du Colombier 	}
2819ef1f84bSDavid du Colombier 	*lo |= Pm|MTf;
2829ef1f84bSDavid du Colombier }
2839ef1f84bSDavid du Colombier 
2849ef1f84bSDavid du Colombier int
ioapicintrenable(Vctl * v)2859ef1f84bSDavid du Colombier ioapicintrenable(Vctl* v)
2869ef1f84bSDavid du Colombier {
287bbf74bb6SDavid du Colombier 	Rbus *rbus;
2889ef1f84bSDavid du Colombier 	Rdt *rdt;
2899ef1f84bSDavid du Colombier 	u32int hi, lo;
290ffa640cdSDavid du Colombier 	int bustype, busno, devno, vecno;
2919ef1f84bSDavid du Colombier 
2929ef1f84bSDavid du Colombier 	/*
2939ef1f84bSDavid du Colombier 	 * Bridge between old and unspecified new scheme,
2949ef1f84bSDavid du Colombier 	 * the work in progress...
2959ef1f84bSDavid du Colombier 	 */
2969ef1f84bSDavid du Colombier 	if(v->tbdf == BUSUNKNOWN){
2979ef1f84bSDavid du Colombier 		if(v->irq >= IdtLINT0 && v->irq <= IdtSPURIOUS){
2989ef1f84bSDavid du Colombier 			if(v->irq != IdtSPURIOUS)
2999ef1f84bSDavid du Colombier 				v->isr = apiceoi;
300*099a302fSDavid du Colombier 			v->type = "lapic";
3019ef1f84bSDavid du Colombier 			return v->irq;
3029ef1f84bSDavid du Colombier 		}
3039ef1f84bSDavid du Colombier 		else{
3049ef1f84bSDavid du Colombier 			/*
3059ef1f84bSDavid du Colombier 			 * Legacy ISA.
3069ef1f84bSDavid du Colombier 			 * Make a busno and devno using the
3079ef1f84bSDavid du Colombier 			 * ISA bus number and the irq.
3089ef1f84bSDavid du Colombier 			 */
3099ef1f84bSDavid du Colombier 			extern int mpisabusno;
3109ef1f84bSDavid du Colombier 
3119ef1f84bSDavid du Colombier 			if(mpisabusno == -1)
3129ef1f84bSDavid du Colombier 				panic("no ISA bus allocated");
3139ef1f84bSDavid du Colombier 			busno = mpisabusno;
314ffa640cdSDavid du Colombier 			devno = v->irq;
315ffa640cdSDavid du Colombier 			bustype = BusISA;
3169ef1f84bSDavid du Colombier 		}
3179ef1f84bSDavid du Colombier 	}
318ffa640cdSDavid du Colombier 	else if((bustype = BUSTYPE(v->tbdf)) == BusPCI){
3199ef1f84bSDavid du Colombier 		/*
3209ef1f84bSDavid du Colombier 		 * PCI.
3219ef1f84bSDavid du Colombier 		 * Make a devno from BUSDNO(tbdf) and pcidev->intp.
3229ef1f84bSDavid du Colombier 		 */
3239ef1f84bSDavid du Colombier 		Pcidev *pcidev;
3249ef1f84bSDavid du Colombier 
3259ef1f84bSDavid du Colombier 		busno = BUSBNO(v->tbdf);
3269ef1f84bSDavid du Colombier 		if((pcidev = pcimatchtbdf(v->tbdf)) == nil)
3279ef1f84bSDavid du Colombier 			panic("no PCI dev for tbdf %#8.8ux\n", v->tbdf);
3289ef1f84bSDavid du Colombier 		if((devno = pcicfgr8(pcidev, PciINTP)) == 0)
3299ef1f84bSDavid du Colombier 			panic("no INTP for tbdf %#8.8ux\n", v->tbdf);
3309ef1f84bSDavid du Colombier 		devno = BUSDNO(v->tbdf)<<2|(devno-1);
3319ef1f84bSDavid du Colombier 		DBG("ioapicintrenable: tbdf %#8.8ux busno %d devno %d\n",
3329ef1f84bSDavid du Colombier 			v->tbdf, busno, devno);
3339ef1f84bSDavid du Colombier 	}
3349ef1f84bSDavid du Colombier 	else{
3359ef1f84bSDavid du Colombier 		SET(busno, devno);
3369ef1f84bSDavid du Colombier 		panic("unknown tbdf %#8.8ux\n", v->tbdf);
3379ef1f84bSDavid du Colombier 	}
3389ef1f84bSDavid du Colombier 
339bbf74bb6SDavid du Colombier 	rdt = nil;
340bbf74bb6SDavid du Colombier 	for(rbus = rdtbus[busno]; rbus != nil; rbus = rbus->next)
341ffa640cdSDavid du Colombier 		if(rbus->devno == devno && rbus->bustype == bustype){
342bbf74bb6SDavid du Colombier 			rdt = rbus->rdt;
3439ef1f84bSDavid du Colombier 			break;
3449ef1f84bSDavid du Colombier 		}
3459ef1f84bSDavid du Colombier 	if(rdt == nil){
3469ef1f84bSDavid du Colombier 		extern int mpisabusno;
3479ef1f84bSDavid du Colombier 
3489ef1f84bSDavid du Colombier 		/*
3499ef1f84bSDavid du Colombier 		 * First crack in the smooth exterior of the new code:
3509ef1f84bSDavid du Colombier 		 * some BIOS make an MPS table where the PCI devices are
3519ef1f84bSDavid du Colombier 		 * just defaulted to ISA.
3529ef1f84bSDavid du Colombier 		 * Rewrite this to be cleaner.
3539ef1f84bSDavid du Colombier 		 */
3549ef1f84bSDavid du Colombier 		if((busno = mpisabusno) == -1)
3559ef1f84bSDavid du Colombier 			return -1;
3569ef1f84bSDavid du Colombier 		devno = v->irq<<2;
357bbf74bb6SDavid du Colombier 		for(rbus = rdtbus[busno]; rbus != nil; rbus = rbus->next){
358bbf74bb6SDavid du Colombier 			if(rbus->devno == devno){
359bbf74bb6SDavid du Colombier 				rdt = rbus->rdt;
3609ef1f84bSDavid du Colombier 				break;
3619ef1f84bSDavid du Colombier 			}
362bbf74bb6SDavid du Colombier 		}
3639ef1f84bSDavid du Colombier 		DBG("isa: tbdf %#8.8ux busno %d devno %d %#p\n",
3649ef1f84bSDavid du Colombier 			v->tbdf, busno, devno, rdt);
3659ef1f84bSDavid du Colombier 	}
3669ef1f84bSDavid du Colombier 	if(rdt == nil)
3679ef1f84bSDavid du Colombier 		return -1;
3689ef1f84bSDavid du Colombier 
3699ef1f84bSDavid du Colombier 	/*
3709ef1f84bSDavid du Colombier 	 * Second crack:
3719ef1f84bSDavid du Colombier 	 * what to do about devices that intrenable/intrdisable frequently?
3729ef1f84bSDavid du Colombier 	 * 1) there is no ioapicdisable yet;
3739ef1f84bSDavid du Colombier 	 * 2) it would be good to reuse freed vectors.
3749ef1f84bSDavid du Colombier 	 * Oh bugger.
3759ef1f84bSDavid du Colombier 	 */
3769ef1f84bSDavid du Colombier 	/*
3779ef1f84bSDavid du Colombier 	 * This is a low-frequency event so just lock
3789ef1f84bSDavid du Colombier 	 * the whole IOAPIC to initialise the RDT entry
3799ef1f84bSDavid du Colombier 	 * rather than putting a Lock in each entry.
3809ef1f84bSDavid du Colombier 	 */
3819ef1f84bSDavid du Colombier 	lock(rdt->apic);
3829ef1f84bSDavid du Colombier 	if((rdt->lo & 0xff) == 0){
3839ef1f84bSDavid du Colombier 		lock(&idtnolock);
3849ef1f84bSDavid du Colombier 		vecno = idtno;
3859ef1f84bSDavid du Colombier 		idtno = (idtno+8) % IdtMAX;
3869ef1f84bSDavid du Colombier 		if(idtno < IdtIOAPIC)
3879ef1f84bSDavid du Colombier 			idtno += IdtIOAPIC;
3889ef1f84bSDavid du Colombier 		unlock(&idtnolock);
3899ef1f84bSDavid du Colombier 
3909ef1f84bSDavid du Colombier 		rdt->lo |= vecno;
3919ef1f84bSDavid du Colombier 		rdtvecno[vecno] = rdt;
3929ef1f84bSDavid du Colombier 	}
3939ef1f84bSDavid du Colombier 
394bbf74bb6SDavid du Colombier 	rdt->enabled++;
3959ef1f84bSDavid du Colombier 	lo = (rdt->lo & ~Im);
3969ef1f84bSDavid du Colombier 	ioapicintrdd(&hi, &lo);
3979ef1f84bSDavid du Colombier 	rtblput(rdt->apic, rdt->intin, hi, lo);
3989ef1f84bSDavid du Colombier 	vecno = lo & 0xff;
3999ef1f84bSDavid du Colombier 	unlock(rdt->apic);
4009ef1f84bSDavid du Colombier 
4019ef1f84bSDavid du Colombier 	DBG("busno %d devno %d hi %#8.8ux lo %#8.8ux vecno %d\n",
4029ef1f84bSDavid du Colombier 		busno, devno, hi, lo, vecno);
4039ef1f84bSDavid du Colombier 	v->isr = apicisr;
4049ef1f84bSDavid du Colombier 	v->eoi = apiceoi;
4059ef1f84bSDavid du Colombier 	v->vno = vecno;
406*099a302fSDavid du Colombier 	v->type = "ioapic";
4079ef1f84bSDavid du Colombier 
4089ef1f84bSDavid du Colombier 	return vecno;
4099ef1f84bSDavid du Colombier }
4109ef1f84bSDavid du Colombier 
4119ef1f84bSDavid du Colombier int
ioapicintrdisable(int vecno)4129ef1f84bSDavid du Colombier ioapicintrdisable(int vecno)
4139ef1f84bSDavid du Colombier {
4149ef1f84bSDavid du Colombier 	Rdt *rdt;
4159ef1f84bSDavid du Colombier 
4169ef1f84bSDavid du Colombier 	/*
4179ef1f84bSDavid du Colombier 	 * FOV. Oh dear. This isn't very good.
4189ef1f84bSDavid du Colombier 	 * Fortunately rdtvecno[vecno] is static
4199ef1f84bSDavid du Colombier 	 * once assigned.
4209ef1f84bSDavid du Colombier 	 * Must do better.
4219ef1f84bSDavid du Colombier 	 *
4229ef1f84bSDavid du Colombier 	 * What about any pending interrupts?
4239ef1f84bSDavid du Colombier 	 */
4249ef1f84bSDavid du Colombier 	if(vecno < 0 || vecno > IdtMAX){
4259ef1f84bSDavid du Colombier 		panic("ioapicintrdisable: vecno %d out of range", vecno);
4269ef1f84bSDavid du Colombier 		return -1;
4279ef1f84bSDavid du Colombier 	}
4289ef1f84bSDavid du Colombier 	if((rdt = rdtvecno[vecno]) == nil){
4299ef1f84bSDavid du Colombier 		panic("ioapicintrdisable: vecno %d has no rdt", vecno);
4309ef1f84bSDavid du Colombier 		return -1;
4319ef1f84bSDavid du Colombier 	}
4329ef1f84bSDavid du Colombier 
4339ef1f84bSDavid du Colombier 	lock(rdt->apic);
434bbf74bb6SDavid du Colombier 	rdt->enabled--;
435bbf74bb6SDavid du Colombier 	if(rdt->enabled == 0)
4369ef1f84bSDavid du Colombier 		rtblput(rdt->apic, rdt->intin, 0, rdt->lo);
4379ef1f84bSDavid du Colombier 	unlock(rdt->apic);
4389ef1f84bSDavid du Colombier 
4399ef1f84bSDavid du Colombier 	return 0;
4409ef1f84bSDavid du Colombier }
441