pci_cfgreg.c revision 69783
1/*
2 * Copyright (c) 1997, Stefan Esser <se@freebsd.org>
3 * Copyright (c) 2000, Michael Smith <msmith@freebsd.org>
4 * Copyright (c) 2000, BSDi
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice unmodified, this list of conditions, and the following
12 *    disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * $FreeBSD: head/sys/amd64/pci/pci_cfgreg.c 69783 2000-12-08 22:11:23Z msmith $
29 *
30 */
31
32#include <sys/param.h>		/* XXX trim includes */
33#include <sys/systm.h>
34#include <sys/bus.h>
35#include <sys/kernel.h>
36#include <sys/module.h>
37#include <sys/malloc.h>
38#include <vm/vm.h>
39#include <vm/pmap.h>
40#include <machine/md_var.h>
41#include <pci/pcivar.h>
42#include <pci/pcireg.h>
43#include <isa/isavar.h>
44#include <machine/nexusvar.h>
45#include <machine/pci_cfgreg.h>
46#include <machine/segments.h>
47#include <machine/pc/bios.h>
48
49#ifdef APIC_IO
50#include <machine/smp.h>
51#endif /* APIC_IO */
52
53#include "pcib_if.h"
54
55static int cfgmech;
56static int devmax;
57static int usebios;
58
59static int	pci_cfgintr_unique(struct PIR_entry *pe, int pin);
60static int	pci_cfgintr_linked(struct PIR_entry *pe, int pin);
61static int	pci_cfgintr_search(struct PIR_entry *pe, int bus, int device, int matchpin, int pin);
62static int	pci_cfgintr_virgin(struct PIR_entry *pe, int pin);
63
64static int	pcibios_cfgread(int bus, int slot, int func, int reg, int bytes);
65static void	pcibios_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes);
66static int	pcibios_cfgopen(void);
67static int	pcireg_cfgread(int bus, int slot, int func, int reg, int bytes);
68static void	pcireg_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes);
69static int	pcireg_cfgopen(void);
70
71static struct PIR_table	*pci_route_table;
72static int		pci_route_count;
73
74/*
75 * Initialise access to PCI configuration space
76 */
77int
78pci_cfgregopen(void)
79{
80    static int			opened = 0;
81    u_long			sigaddr;
82    static struct PIR_table	*pt;
83    u_int8_t			ck, *cv;
84    int				i;
85
86    if (opened)
87	return(1);
88
89    if (pcibios_cfgopen() != 0) {
90	usebios = 1;
91    } else if (pcireg_cfgopen() != 0) {
92	usebios = 0;
93    } else {
94	return(0);
95    }
96
97    /*
98     * Look for the interrupt routing table.
99     */
100    /* XXX use PCI BIOS if it's available */
101
102    if ((pt == NULL) && ((sigaddr = bios_sigsearch(0, "$PIR", 4, 16, 0)) != 0)) {
103	pt = (struct PIR_table *)(uintptr_t)BIOS_PADDRTOVADDR(sigaddr);
104	for (cv = (u_int8_t *)pt, ck = 0, i = 0; i < (pt->pt_header.ph_length); i++) {
105	    ck += cv[i];
106	}
107	if (ck == 0) {
108	    pci_route_table = pt;
109	    pci_route_count = (pt->pt_header.ph_length - sizeof(struct PIR_header)) / sizeof(struct PIR_entry);
110	    printf("Using $PIR table, %d entries at %p\n", pci_route_count, pci_route_table);
111	}
112    }
113
114    opened = 1;
115    return(1);
116}
117
118/*
119 * Read configuration space register
120 */
121u_int32_t
122pci_do_cfgregread(int bus, int slot, int func, int reg, int bytes)
123{
124    return(usebios ?
125	   pcibios_cfgread(bus, slot, func, reg, bytes) :
126	   pcireg_cfgread(bus, slot, func, reg, bytes));
127}
128
129u_int32_t
130pci_cfgregread(int bus, int slot, int func, int reg, int bytes)
131{
132#ifdef APIC_IO
133    /*
134     * If we are using the APIC, the contents of the intline register will probably
135     * be wrong (since they are set up for use with the PIC.
136     * Rather than rewrite these registers (maybe that would be smarter) we trap
137     * attempts to read them and translate to our private vector numbers.
138     */
139    if ((reg == PCIR_INTLINE) && (bytes == 1)) {
140	int	pin, line, airq;
141
142	pin = pci_do_cfgregread(bus, slot, func, PCIR_INTPIN, 1);
143	line = pci_do_cfgregread(bus, slot, func, PCIR_INTLINE, 1);
144
145	if (pin != 0) {
146	    int airq;
147
148	    airq = pci_apic_irq(bus, slot, pin);
149	    if (airq >= 0) {
150		/* PCI specific entry found in MP table */
151		if (airq != line)
152		    undirect_pci_irq(line);
153		return(airq);
154	    } else {
155		/*
156		 * PCI interrupts might be redirected to the
157		 * ISA bus according to some MP tables. Use the
158		 * same methods as used by the ISA devices
159		 * devices to find the proper IOAPIC int pin.
160		 */
161		airq = isa_apic_irq(line);
162		if ((airq >= 0) && (airq != line)) {
163		    /* XXX: undirect_pci_irq() ? */
164		    undirect_isa_irq(line);
165		    return(airq);
166		}
167	    }
168	}
169	return(line);
170    }
171#endif /* APIC_IO */
172    return(pci_do_cfgregread(bus, slot, func, reg, bytes));
173}
174
175/*
176 * Write configuration space register
177 */
178void
179pci_cfgregwrite(int bus, int slot, int func, int reg, u_int32_t data, int bytes)
180{
181    return(usebios ?
182	   pcibios_cfgwrite(bus, slot, func, reg, data, bytes) :
183	   pcireg_cfgwrite(bus, slot, func, reg, data, bytes));
184}
185
186/*
187 * Route a PCI interrupt
188 *
189 * XXX we don't do anything "right" with the function number in the PIR table
190 *     (because the consumer isn't currently passing it in).  We don't care
191 *     anyway, due to the way PCI interrupts are assigned.
192 */
193int
194pci_cfgintr(int bus, int device, int pin)
195{
196    struct PIR_entry	*pe;
197    int			i, irq;
198    struct bios_regs	args;
199
200    if ((bus < 0) || (bus > 255) || (device < 0) || (device > 255) ||
201      (pin < 1) || (pin > 4))
202	return(255);
203
204    /*
205     * Scan the entry table for a contender
206     */
207    for (i = 0, pe = &pci_route_table->pt_entry[0]; i < pci_route_count; i++, pe++) {
208	if ((bus != pe->pe_bus) || (device != pe->pe_device))
209	    continue;
210
211	irq = pci_cfgintr_unique(pe, pin);
212	if (irq == 255)
213	    irq = pci_cfgintr_linked(pe, pin);
214	if (irq == 255)
215	    irq = pci_cfgintr_virgin(pe, pin);
216
217	if (irq == 255)
218	    break;
219
220
221	/*
222	 * Ask the BIOS to route the interrupt
223	 */
224	args.eax = PCIBIOS_ROUTE_INTERRUPT;
225	args.ebx = (bus << 8) | (device << 3);
226	args.ecx = (irq << 8) | (0xa + pin - 1);	/* pin value is 0xa - 0xd */
227	bios32(&args, PCIbios.ventry, GSEL(GCODE_SEL, SEL_KPL));
228
229	/*
230	 * XXX if it fails, we should try to smack the router hardware directly
231	 */
232
233	printf("pci_cfgintr: %d:%d INT%c routed to irq %d\n",
234	       bus, device, 'A' + pin - 1, irq);
235	return(irq);
236    }
237
238    printf("pci_cfgintr: can't route an interrupt to %d:%d INT%c\n", bus, device, 'A' + pin - 1);
239    return(255);
240}
241
242/*
243 * Look to see if the routing table claims this pin is uniquely routed.
244 */
245static int
246pci_cfgintr_unique(struct PIR_entry *pe, int pin)
247{
248    int		irq;
249
250    if (powerof2(pe->pe_intpin[pin - 1].irqs)) {
251	irq = ffs(pe->pe_intpin[pin - 1].irqs) - 1;
252	printf("pci_cfgintr_unique: hard-routed to irq %d\n", irq);
253	return(irq);
254    }
255    return(255);
256}
257
258/*
259 * Look for another device which shares the same link byte and
260 * already has a unique IRQ, or which has had one routed already.
261 */
262static int
263pci_cfgintr_linked(struct PIR_entry *pe, int pin)
264{
265    struct PIR_entry	*oe;
266    struct PIR_intpin	*pi;
267    int			i, j, irq;
268
269    /*
270     * Scan table slots.
271     */
272    for (i = 0, oe = &pci_route_table->pt_entry[0]; i < pci_route_count; i++, oe++) {
273
274	/* scan interrupt pins */
275	for (j = 0, pi = &oe->pe_intpin[0]; j < 4; j++, pi++) {
276
277	    /* don't look at the entry we're trying to match with */
278	    if ((pe == oe) && (i == (pin - 1)))
279		continue;
280
281	    /* compare link bytes */
282	    if (pi->link != pe->pe_intpin[pin - 1].link)
283		continue;
284
285	    /* link destination mapped to a unique interrupt? */
286	    if (powerof2(pi->irqs)) {
287		irq = ffs(pi->irqs) - 1;
288		printf("pci_cfgintr_linked: linked (%x) to hard-routed irq %d\n",
289		       pi->link, irq);
290		return(irq);
291	    }
292
293	    /* look for the real PCI device that matches this table entry */
294	    if ((irq = pci_cfgintr_search(pe, oe->pe_bus, oe->pe_device, j, pin)) != 255)
295		return(irq);
296	}
297    }
298    return(255);
299}
300
301/*
302 * Scan for the real PCI device at (bus)/(device) using intpin (matchpin) and
303 * see if it has already been assigned an interrupt.
304 */
305static int
306pci_cfgintr_search(struct PIR_entry *pe, int bus, int device, int matchpin, int pin)
307{
308    devclass_t		pci_devclass;
309    device_t		*pci_devices;
310    int			pci_count;
311    device_t		*pci_children;
312    int			pci_childcount;
313    device_t		*busp, *childp;
314    int			i, j, irq;
315
316    /*
317     * Find all the PCI busses.
318     */
319    pci_count = 0;
320    if ((pci_devclass = devclass_find("pci")) != NULL)
321	devclass_get_devices(pci_devclass, &pci_devices, &pci_count);
322
323    /*
324     * Scan all the PCI busses/devices looking for this one.
325     */
326    for (i = 0, busp = pci_devices; i < pci_count; i++, busp++) {
327	pci_childcount = 0;
328	device_get_children(*busp, &pci_children, &pci_childcount);
329
330	for (j = 0, childp = pci_children; j < pci_childcount; j++, childp++) {
331	    if ((pci_get_bus(*childp) == bus) &&
332		(pci_get_slot(*childp) == device) &&
333		(pci_get_intpin(*childp) == matchpin) &&
334		((irq = pci_get_irq(*childp)) != 255)) {
335		printf("pci_cfgintr_search: linked (%x) to configured irq %d at %d:%d:%d\n",
336		       irq, pe->pe_intpin[pin - 1].link,
337		       pci_get_bus(*childp), pci_get_slot(*childp), pci_get_function(*childp));
338		return(irq);
339	    }
340	}
341    }
342    return(255);
343}
344
345/*
346 * Pick a suitable IRQ from those listed as routable to this device.
347 */
348static int
349pci_cfgintr_virgin(struct PIR_entry *pe, int pin)
350{
351    int		irq, ibit;
352
353    /* first scan the set of PCI-only interrupts and see if any of these are routable */
354    for (irq = 0; irq < 16; irq++) {
355	ibit = (1 << irq);
356
357	/* can we use this interrupt? */
358	if ((pci_route_table->pt_header.ph_pci_irqs & ibit) &&
359	    (pe->pe_intpin[pin - 1].irqs & ibit)) {
360	    printf("pci_cfgintr_virgin: using routable PCI-only interrupt %d\n", irq);
361	    return(irq);
362	}
363    }
364
365    /* life is tough, so just pick an interrupt */
366    for (irq = 0; irq < 16; irq++) {
367	ibit = (1 << irq);
368
369	if (pe->pe_intpin[pin - 1].irqs & ibit) {
370	    printf("pci_cfgintr_virgin: using routable interrupt %d\n", irq);
371	    return(irq);
372	}
373    }
374    return(255);
375}
376
377
378/*
379 * Config space access using BIOS functions
380 */
381static int
382pcibios_cfgread(int bus, int slot, int func, int reg, int bytes)
383{
384    struct bios_regs args;
385    u_int mask;
386
387    switch(bytes) {
388    case 1:
389	args.eax = PCIBIOS_READ_CONFIG_BYTE;
390	mask = 0xff;
391	break;
392    case 2:
393	args.eax = PCIBIOS_READ_CONFIG_WORD;
394	mask = 0xffff;
395	break;
396    case 4:
397	args.eax = PCIBIOS_READ_CONFIG_DWORD;
398	mask = 0xffffffff;
399	break;
400    default:
401	return(-1);
402    }
403    args.ebx = (bus << 8) | (slot << 3) | func;
404    args.edi = reg;
405    bios32(&args, PCIbios.ventry, GSEL(GCODE_SEL, SEL_KPL));
406    /* check call results? */
407    return(args.ecx & mask);
408}
409
410static void
411pcibios_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes)
412{
413    struct bios_regs args;
414
415    switch(bytes) {
416    case 1:
417	args.eax = PCIBIOS_WRITE_CONFIG_BYTE;
418	break;
419    case 2:
420	args.eax = PCIBIOS_WRITE_CONFIG_WORD;
421	break;
422    case 4:
423	args.eax = PCIBIOS_WRITE_CONFIG_DWORD;
424	break;
425    default:
426	return;
427    }
428    args.ebx = (bus << 8) | (slot << 3) | func;
429    args.ecx = data;
430    args.edi = reg;
431    bios32(&args, PCIbios.ventry, GSEL(GCODE_SEL, SEL_KPL));
432}
433
434/*
435 * Determine whether there is a PCI BIOS present
436 */
437static int
438pcibios_cfgopen(void)
439{
440    /* check for a found entrypoint */
441    return(PCIbios.entry != 0);
442}
443
444/*
445 * Configuration space access using direct register operations
446 */
447
448/* enable configuration space accesses and return data port address */
449static int
450pci_cfgenable(unsigned bus, unsigned slot, unsigned func, int reg, int bytes)
451{
452    int dataport = 0;
453
454    if (bus <= PCI_BUSMAX
455	&& slot < devmax
456	&& func <= PCI_FUNCMAX
457	&& reg <= PCI_REGMAX
458	&& bytes != 3
459	&& (unsigned) bytes <= 4
460	&& (reg & (bytes -1)) == 0) {
461	switch (cfgmech) {
462	case 1:
463	    outl(CONF1_ADDR_PORT, (1 << 31)
464		 | (bus << 16) | (slot << 11)
465		 | (func << 8) | (reg & ~0x03));
466	    dataport = CONF1_DATA_PORT + (reg & 0x03);
467	    break;
468	case 2:
469	    outb(CONF2_ENABLE_PORT, 0xf0 | (func << 1));
470	    outb(CONF2_FORWARD_PORT, bus);
471	    dataport = 0xc000 | (slot << 8) | reg;
472	    break;
473	}
474    }
475    return (dataport);
476}
477
478/* disable configuration space accesses */
479static void
480pci_cfgdisable(void)
481{
482    switch (cfgmech) {
483    case 1:
484	outl(CONF1_ADDR_PORT, 0);
485	break;
486    case 2:
487	outb(CONF2_ENABLE_PORT, 0);
488	outb(CONF2_FORWARD_PORT, 0);
489	break;
490    }
491}
492
493static int
494pcireg_cfgread(int bus, int slot, int func, int reg, int bytes)
495{
496    int data = -1;
497    int port;
498
499    port = pci_cfgenable(bus, slot, func, reg, bytes);
500
501    if (port != 0) {
502	switch (bytes) {
503	case 1:
504	    data = inb(port);
505	    break;
506	case 2:
507	    data = inw(port);
508	    break;
509	case 4:
510	    data = inl(port);
511	    break;
512	}
513	pci_cfgdisable();
514    }
515    return (data);
516}
517
518static void
519pcireg_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes)
520{
521    int port;
522
523    port = pci_cfgenable(bus, slot, func, reg, bytes);
524    if (port != 0) {
525	switch (bytes) {
526	case 1:
527	    outb(port, data);
528	    break;
529	case 2:
530	    outw(port, data);
531	    break;
532	case 4:
533	    outl(port, data);
534	    break;
535	}
536	pci_cfgdisable();
537    }
538}
539
540/* check whether the configuration mechanism has been correctly identified */
541static int
542pci_cfgcheck(int maxdev)
543{
544    u_char device;
545
546    if (bootverbose)
547	printf("pci_cfgcheck:\tdevice ");
548
549    for (device = 0; device < maxdev; device++) {
550	unsigned id, class, header;
551	if (bootverbose)
552	    printf("%d ", device);
553
554	id = inl(pci_cfgenable(0, device, 0, 0, 4));
555	if (id == 0 || id == -1)
556	    continue;
557
558	class = inl(pci_cfgenable(0, device, 0, 8, 4)) >> 8;
559	if (bootverbose)
560	    printf("[class=%06x] ", class);
561	if (class == 0 || (class & 0xf870ff) != 0)
562	    continue;
563
564	header = inb(pci_cfgenable(0, device, 0, 14, 1));
565	if (bootverbose)
566	    printf("[hdr=%02x] ", header);
567	if ((header & 0x7e) != 0)
568	    continue;
569
570	if (bootverbose)
571	    printf("is there (id=%08x)\n", id);
572
573	pci_cfgdisable();
574	return (1);
575    }
576    if (bootverbose)
577	printf("-- nothing found\n");
578
579    pci_cfgdisable();
580    return (0);
581}
582
583static int
584pcireg_cfgopen(void)
585{
586    unsigned long mode1res,oldval1;
587    unsigned char mode2res,oldval2;
588
589    oldval1 = inl(CONF1_ADDR_PORT);
590
591    if (bootverbose) {
592	printf("pci_open(1):\tmode 1 addr port (0x0cf8) is 0x%08lx\n",
593	       oldval1);
594    }
595
596    if ((oldval1 & CONF1_ENABLE_MSK) == 0) {
597
598	cfgmech = 1;
599	devmax = 32;
600
601	outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK);
602	outb(CONF1_ADDR_PORT +3, 0);
603	mode1res = inl(CONF1_ADDR_PORT);
604	outl(CONF1_ADDR_PORT, oldval1);
605
606	if (bootverbose)
607	    printf("pci_open(1a):\tmode1res=0x%08lx (0x%08lx)\n",
608		   mode1res, CONF1_ENABLE_CHK);
609
610	if (mode1res) {
611	    if (pci_cfgcheck(32))
612		return (cfgmech);
613	}
614
615	outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK1);
616	mode1res = inl(CONF1_ADDR_PORT);
617	outl(CONF1_ADDR_PORT, oldval1);
618
619	if (bootverbose)
620	    printf("pci_open(1b):\tmode1res=0x%08lx (0x%08lx)\n",
621		   mode1res, CONF1_ENABLE_CHK1);
622
623	if ((mode1res & CONF1_ENABLE_MSK1) == CONF1_ENABLE_RES1) {
624	    if (pci_cfgcheck(32))
625		return (cfgmech);
626	}
627    }
628
629    oldval2 = inb(CONF2_ENABLE_PORT);
630
631    if (bootverbose) {
632	printf("pci_open(2):\tmode 2 enable port (0x0cf8) is 0x%02x\n",
633	       oldval2);
634    }
635
636    if ((oldval2 & 0xf0) == 0) {
637
638	cfgmech = 2;
639	devmax = 16;
640
641	outb(CONF2_ENABLE_PORT, CONF2_ENABLE_CHK);
642	mode2res = inb(CONF2_ENABLE_PORT);
643	outb(CONF2_ENABLE_PORT, oldval2);
644
645	if (bootverbose)
646	    printf("pci_open(2a):\tmode2res=0x%02x (0x%02x)\n",
647		   mode2res, CONF2_ENABLE_CHK);
648
649	if (mode2res == CONF2_ENABLE_RES) {
650	    if (bootverbose)
651		printf("pci_open(2a):\tnow trying mechanism 2\n");
652
653	    if (pci_cfgcheck(16))
654		return (cfgmech);
655	}
656    }
657
658    cfgmech = 0;
659    devmax = 0;
660    return (cfgmech);
661}
662
663