1433d6423SLionel Sambuc /*
2433d6423SLionel Sambuc pci.c
3433d6423SLionel Sambuc
4433d6423SLionel Sambuc Configure devices on the PCI bus
5433d6423SLionel Sambuc
6433d6423SLionel Sambuc Created: Jan 2000 by Philip Homburg <philip@cs.vu.nl>
7433d6423SLionel Sambuc */
86e7bb628SLionel Sambuc #include <minix/acpi.h>
95d831176SLionel Sambuc #include <minix/chardriver.h>
105d831176SLionel Sambuc #include <minix/driver.h>
115d831176SLionel Sambuc #include <minix/param.h>
126e7bb628SLionel Sambuc #include <minix/rs.h>
136e7bb628SLionel Sambuc
146e7bb628SLionel Sambuc #include <machine/pci.h>
15433d6423SLionel Sambuc #include <machine/pci_amd.h>
16433d6423SLionel Sambuc #include <machine/pci_intel.h>
17433d6423SLionel Sambuc #include <machine/pci_sis.h>
18433d6423SLionel Sambuc #include <machine/pci_via.h>
196e7bb628SLionel Sambuc #include <machine/vmparam.h>
20433d6423SLionel Sambuc
210a6a1f1dSLionel Sambuc #include <dev/pci/pci_verbose.h>
220a6a1f1dSLionel Sambuc
233641562fSLionel Sambuc #include <pci.h>
24433d6423SLionel Sambuc #include <stdlib.h>
25433d6423SLionel Sambuc #include <stdio.h>
266e7bb628SLionel Sambuc
276e7bb628SLionel Sambuc #include "pci.h"
286e7bb628SLionel Sambuc
290a6a1f1dSLionel Sambuc #define PCI_VENDORSTR_LEN 64
300a6a1f1dSLionel Sambuc #define PCI_PRODUCTSTR_LEN 64
310a6a1f1dSLionel Sambuc
326e7bb628SLionel Sambuc #define irq_mode_pci(irq) ((void)0)
33433d6423SLionel Sambuc
34433d6423SLionel Sambuc #define PBT_INTEL_HOST 1
35433d6423SLionel Sambuc #define PBT_PCIBRIDGE 2
36433d6423SLionel Sambuc #define PBT_CARDBUS 3
37433d6423SLionel Sambuc
38433d6423SLionel Sambuc #define BAM_NR 6 /* Number of base-address registers */
39433d6423SLionel Sambuc
406e7bb628SLionel Sambuc struct pci_acl pci_acl[NR_DRIVERS];
41433d6423SLionel Sambuc
42433d6423SLionel Sambuc static struct pcibus
43433d6423SLionel Sambuc {
44433d6423SLionel Sambuc int pb_type;
45433d6423SLionel Sambuc int pb_needinit;
46433d6423SLionel Sambuc int pb_isabridge_dev;
47433d6423SLionel Sambuc int pb_isabridge_type;
48433d6423SLionel Sambuc
49433d6423SLionel Sambuc int pb_devind;
50433d6423SLionel Sambuc int pb_busnr;
51433d6423SLionel Sambuc u8_t (*pb_rreg8)(int busind, int devind, int port);
52433d6423SLionel Sambuc u16_t (*pb_rreg16)(int busind, int devind, int port);
53433d6423SLionel Sambuc u32_t (*pb_rreg32)(int busind, int devind, int port);
54433d6423SLionel Sambuc void (*pb_wreg8)(int busind, int devind, int port, u8_t value);
55433d6423SLionel Sambuc void (*pb_wreg16)(int busind, int devind, int port, u16_t value);
56433d6423SLionel Sambuc void (*pb_wreg32)(int busind, int devind, int port, u32_t value);
57433d6423SLionel Sambuc u16_t (*pb_rsts)(int busind);
58433d6423SLionel Sambuc void (*pb_wsts)(int busind, u16_t value);
59433d6423SLionel Sambuc } pcibus[NR_PCIBUS];
60433d6423SLionel Sambuc static int nr_pcibus= 0;
61433d6423SLionel Sambuc
62433d6423SLionel Sambuc static struct pcidev
63433d6423SLionel Sambuc {
64433d6423SLionel Sambuc u8_t pd_busnr;
65433d6423SLionel Sambuc u8_t pd_dev;
66433d6423SLionel Sambuc u8_t pd_func;
67433d6423SLionel Sambuc u8_t pd_baseclass;
68433d6423SLionel Sambuc u8_t pd_subclass;
69433d6423SLionel Sambuc u8_t pd_infclass;
70433d6423SLionel Sambuc u16_t pd_vid;
71433d6423SLionel Sambuc u16_t pd_did;
72433d6423SLionel Sambuc u16_t pd_sub_vid;
73433d6423SLionel Sambuc u16_t pd_sub_did;
74433d6423SLionel Sambuc u8_t pd_ilr;
75433d6423SLionel Sambuc
76433d6423SLionel Sambuc u8_t pd_inuse;
77433d6423SLionel Sambuc endpoint_t pd_proc;
78433d6423SLionel Sambuc
79433d6423SLionel Sambuc struct bar
80433d6423SLionel Sambuc {
81433d6423SLionel Sambuc int pb_flags;
82433d6423SLionel Sambuc int pb_nr;
83433d6423SLionel Sambuc u32_t pb_base;
84433d6423SLionel Sambuc u32_t pb_size;
85433d6423SLionel Sambuc } pd_bar[BAM_NR];
86433d6423SLionel Sambuc int pd_bar_nr;
87433d6423SLionel Sambuc } pcidev[NR_PCIDEV];
88433d6423SLionel Sambuc
89433d6423SLionel Sambuc /* pb_flags */
90433d6423SLionel Sambuc #define PBF_IO 1 /* I/O else memory */
91433d6423SLionel Sambuc #define PBF_INCOMPLETE 2 /* not allocated */
92433d6423SLionel Sambuc
93433d6423SLionel Sambuc static int nr_pcidev= 0;
94433d6423SLionel Sambuc
95433d6423SLionel Sambuc static struct machine machine;
96433d6423SLionel Sambuc
97433d6423SLionel Sambuc /*===========================================================================*
98433d6423SLionel Sambuc * helper functions for I/O *
99433d6423SLionel Sambuc *===========================================================================*/
1006e7bb628SLionel Sambuc static unsigned
pci_inb(u16_t port)1016e7bb628SLionel Sambuc pci_inb(u16_t port) {
102433d6423SLionel Sambuc u32_t value;
103433d6423SLionel Sambuc int s;
104433d6423SLionel Sambuc if ((s=sys_inb(port, &value)) !=OK)
105433d6423SLionel Sambuc printf("PCI: warning, sys_inb failed: %d\n", s);
106433d6423SLionel Sambuc return value;
107433d6423SLionel Sambuc }
1086e7bb628SLionel Sambuc
1096e7bb628SLionel Sambuc static unsigned
pci_inw(u16_t port)1106e7bb628SLionel Sambuc pci_inw(u16_t port) {
111433d6423SLionel Sambuc u32_t value;
112433d6423SLionel Sambuc int s;
113433d6423SLionel Sambuc if ((s=sys_inw(port, &value)) !=OK)
114433d6423SLionel Sambuc printf("PCI: warning, sys_inw failed: %d\n", s);
115433d6423SLionel Sambuc return value;
116433d6423SLionel Sambuc }
1176e7bb628SLionel Sambuc
1186e7bb628SLionel Sambuc static unsigned
pci_inl(u16_t port)1196e7bb628SLionel Sambuc pci_inl(u16_t port) {
120433d6423SLionel Sambuc u32_t value;
121433d6423SLionel Sambuc int s;
122433d6423SLionel Sambuc if ((s=sys_inl(port, &value)) !=OK)
123433d6423SLionel Sambuc printf("PCI: warning, sys_inl failed: %d\n", s);
124433d6423SLionel Sambuc return value;
125433d6423SLionel Sambuc }
1266e7bb628SLionel Sambuc
1276e7bb628SLionel Sambuc static void
pci_outb(u16_t port,u8_t value)1286e7bb628SLionel Sambuc pci_outb(u16_t port, u8_t value) {
129433d6423SLionel Sambuc int s;
130433d6423SLionel Sambuc if ((s=sys_outb(port, value)) !=OK)
131433d6423SLionel Sambuc printf("PCI: warning, sys_outb failed: %d\n", s);
132433d6423SLionel Sambuc }
1336e7bb628SLionel Sambuc
1346e7bb628SLionel Sambuc static void
pci_outw(u16_t port,u16_t value)1356e7bb628SLionel Sambuc pci_outw(u16_t port, u16_t value) {
136433d6423SLionel Sambuc int s;
137433d6423SLionel Sambuc if ((s=sys_outw(port, value)) !=OK)
138433d6423SLionel Sambuc printf("PCI: warning, sys_outw failed: %d\n", s);
139433d6423SLionel Sambuc }
1406e7bb628SLionel Sambuc
1416e7bb628SLionel Sambuc static void
pci_outl(u16_t port,u32_t value)1426e7bb628SLionel Sambuc pci_outl(u16_t port, u32_t value) {
143433d6423SLionel Sambuc int s;
144433d6423SLionel Sambuc if ((s=sys_outl(port, value)) !=OK)
145433d6423SLionel Sambuc printf("PCI: warning, sys_outl failed: %d\n", s);
146433d6423SLionel Sambuc }
147433d6423SLionel Sambuc
1486e7bb628SLionel Sambuc static u8_t
pcii_rreg8(int busind,int devind,int port)1496e7bb628SLionel Sambuc pcii_rreg8(int busind, int devind, int port)
150433d6423SLionel Sambuc {
1516e7bb628SLionel Sambuc u8_t v;
1526e7bb628SLionel Sambuc int s;
153433d6423SLionel Sambuc
1546e7bb628SLionel Sambuc v= PCII_RREG8_(pcibus[busind].pb_busnr,
1556e7bb628SLionel Sambuc pcidev[devind].pd_dev, pcidev[devind].pd_func,
1566e7bb628SLionel Sambuc port);
1576e7bb628SLionel Sambuc if (OK != (s=sys_outl(PCII_CONFADD, PCII_UNSEL)))
1586e7bb628SLionel Sambuc printf("PCI: warning, sys_outl failed: %d\n", s);
159433d6423SLionel Sambuc #if 0
1606e7bb628SLionel Sambuc printf("pcii_rreg8(%d, %d, 0x%X): %d.%d.%d= 0x%X\n",
1616e7bb628SLionel Sambuc busind, devind, port,
1626e7bb628SLionel Sambuc pcibus[busind].pb_bus, pcidev[devind].pd_dev,
1636e7bb628SLionel Sambuc pcidev[devind].pd_func, v);
164433d6423SLionel Sambuc #endif
1656e7bb628SLionel Sambuc return v;
166433d6423SLionel Sambuc }
167433d6423SLionel Sambuc
1686e7bb628SLionel Sambuc static u16_t
pcii_rreg16(int busind,int devind,int port)1696e7bb628SLionel Sambuc pcii_rreg16(int busind, int devind, int port)
170433d6423SLionel Sambuc {
1716e7bb628SLionel Sambuc u16_t v;
1726e7bb628SLionel Sambuc int s;
173433d6423SLionel Sambuc
1746e7bb628SLionel Sambuc v= PCII_RREG16_(pcibus[busind].pb_busnr,
1756e7bb628SLionel Sambuc pcidev[devind].pd_dev, pcidev[devind].pd_func,
1766e7bb628SLionel Sambuc port);
1776e7bb628SLionel Sambuc if (OK != (s=sys_outl(PCII_CONFADD, PCII_UNSEL)))
1786e7bb628SLionel Sambuc printf("PCI: warning, sys_outl failed: %d\n", s);
179433d6423SLionel Sambuc #if 0
1806e7bb628SLionel Sambuc printf("pcii_rreg16(%d, %d, 0x%X): %d.%d.%d= 0x%X\n",
1816e7bb628SLionel Sambuc busind, devind, port,
1826e7bb628SLionel Sambuc pcibus[busind].pb_bus, pcidev[devind].pd_dev,
1836e7bb628SLionel Sambuc pcidev[devind].pd_func, v);
184433d6423SLionel Sambuc #endif
1856e7bb628SLionel Sambuc return v;
186433d6423SLionel Sambuc }
187433d6423SLionel Sambuc
1886e7bb628SLionel Sambuc static u32_t
pcii_rreg32(int busind,int devind,int port)1896e7bb628SLionel Sambuc pcii_rreg32(int busind, int devind, int port)
190433d6423SLionel Sambuc {
1916e7bb628SLionel Sambuc u32_t v;
1926e7bb628SLionel Sambuc int s;
193433d6423SLionel Sambuc
1946e7bb628SLionel Sambuc v= PCII_RREG32_(pcibus[busind].pb_busnr,
1956e7bb628SLionel Sambuc pcidev[devind].pd_dev, pcidev[devind].pd_func,
1966e7bb628SLionel Sambuc port);
1976e7bb628SLionel Sambuc if (OK != (s=sys_outl(PCII_CONFADD, PCII_UNSEL)))
1986e7bb628SLionel Sambuc printf("PCI: warning, sys_outl failed: %d\n", s);
199433d6423SLionel Sambuc #if 0
2006e7bb628SLionel Sambuc printf("pcii_rreg32(%d, %d, 0x%X): %d.%d.%d= 0x%X\n",
2016e7bb628SLionel Sambuc busind, devind, port,
2026e7bb628SLionel Sambuc pcibus[busind].pb_bus, pcidev[devind].pd_dev,
2036e7bb628SLionel Sambuc pcidev[devind].pd_func, v);
204433d6423SLionel Sambuc #endif
2056e7bb628SLionel Sambuc return v;
206433d6423SLionel Sambuc }
2076e7bb628SLionel Sambuc
2086e7bb628SLionel Sambuc static void
pcii_wreg8(int busind,int devind,int port,u8_t value)2096e7bb628SLionel Sambuc pcii_wreg8(int busind, int devind, int port, u8_t value)
2106e7bb628SLionel Sambuc {
2116e7bb628SLionel Sambuc int s;
2126e7bb628SLionel Sambuc #if 0
2136e7bb628SLionel Sambuc printf("pcii_wreg8(%d, %d, 0x%X, 0x%X): %d.%d.%d\n",
2146e7bb628SLionel Sambuc busind, devind, port, value,
2156e7bb628SLionel Sambuc pcibus[busind].pb_bus, pcidev[devind].pd_dev,
2166e7bb628SLionel Sambuc pcidev[devind].pd_func);
2176e7bb628SLionel Sambuc #endif
2186e7bb628SLionel Sambuc PCII_WREG8_(pcibus[busind].pb_busnr,
2196e7bb628SLionel Sambuc pcidev[devind].pd_dev, pcidev[devind].pd_func,
2206e7bb628SLionel Sambuc port, value);
2216e7bb628SLionel Sambuc if (OK != (s=sys_outl(PCII_CONFADD, PCII_UNSEL)))
2226e7bb628SLionel Sambuc printf("PCI: warning, sys_outl failed: %d\n", s);
2236e7bb628SLionel Sambuc }
2246e7bb628SLionel Sambuc
2256e7bb628SLionel Sambuc static void
pcii_wreg16(int busind,int devind,int port,u16_t value)2266e7bb628SLionel Sambuc pcii_wreg16(int busind, int devind, int port, u16_t value)
2276e7bb628SLionel Sambuc {
2286e7bb628SLionel Sambuc int s;
2296e7bb628SLionel Sambuc #if 0
2306e7bb628SLionel Sambuc printf("pcii_wreg16(%d, %d, 0x%X, 0x%X): %d.%d.%d\n",
2316e7bb628SLionel Sambuc busind, devind, port, value,
2326e7bb628SLionel Sambuc pcibus[busind].pb_bus, pcidev[devind].pd_dev,
2336e7bb628SLionel Sambuc pcidev[devind].pd_func);
2346e7bb628SLionel Sambuc #endif
2356e7bb628SLionel Sambuc PCII_WREG16_(pcibus[busind].pb_busnr,
2366e7bb628SLionel Sambuc pcidev[devind].pd_dev, pcidev[devind].pd_func,
2376e7bb628SLionel Sambuc port, value);
2386e7bb628SLionel Sambuc if (OK != (s=sys_outl(PCII_CONFADD, PCII_UNSEL)))
2396e7bb628SLionel Sambuc printf("PCI: warning, sys_outl failed: %d\n", s);
2406e7bb628SLionel Sambuc }
2416e7bb628SLionel Sambuc
2426e7bb628SLionel Sambuc static void
pcii_wreg32(int busind,int devind,int port,u32_t value)2436e7bb628SLionel Sambuc pcii_wreg32(int busind, int devind, int port, u32_t value)
2446e7bb628SLionel Sambuc {
2456e7bb628SLionel Sambuc int s;
2466e7bb628SLionel Sambuc #if 0
2476e7bb628SLionel Sambuc printf("pcii_wreg32(%d, %d, 0x%X, 0x%X): %d.%d.%d\n",
2486e7bb628SLionel Sambuc busind, devind, port, value,
2496e7bb628SLionel Sambuc pcibus[busind].pb_busnr, pcidev[devind].pd_dev,
2506e7bb628SLionel Sambuc pcidev[devind].pd_func);
2516e7bb628SLionel Sambuc #endif
2526e7bb628SLionel Sambuc PCII_WREG32_(pcibus[busind].pb_busnr,
2536e7bb628SLionel Sambuc pcidev[devind].pd_dev, pcidev[devind].pd_func,
2546e7bb628SLionel Sambuc port, value);
2556e7bb628SLionel Sambuc if (OK != (s=sys_outl(PCII_CONFADD, PCII_UNSEL)))
2566e7bb628SLionel Sambuc printf("PCI: warning, sys_outl failed: %d\n",s);
257433d6423SLionel Sambuc }
258433d6423SLionel Sambuc
259433d6423SLionel Sambuc /*===========================================================================*
2606e7bb628SLionel Sambuc * ntostr *
261433d6423SLionel Sambuc *===========================================================================*/
2626e7bb628SLionel Sambuc static void
ntostr(unsigned int n,char ** str,const char * end)2636e7bb628SLionel Sambuc ntostr(unsigned int n, char **str, const char *end)
264433d6423SLionel Sambuc {
2656e7bb628SLionel Sambuc char tmpstr[20];
2666e7bb628SLionel Sambuc int i;
267433d6423SLionel Sambuc
2686e7bb628SLionel Sambuc if (n == 0)
269433d6423SLionel Sambuc {
2706e7bb628SLionel Sambuc tmpstr[0]= '0';
2716e7bb628SLionel Sambuc i= 1;
272433d6423SLionel Sambuc }
273433d6423SLionel Sambuc else
274433d6423SLionel Sambuc {
2756e7bb628SLionel Sambuc for (i= 0; n; i++)
276433d6423SLionel Sambuc {
2776e7bb628SLionel Sambuc tmpstr[i]= '0' + (n%10);
2786e7bb628SLionel Sambuc n /= 10;
279433d6423SLionel Sambuc }
280433d6423SLionel Sambuc }
2816e7bb628SLionel Sambuc for (; i>0; i--)
282433d6423SLionel Sambuc {
2836e7bb628SLionel Sambuc if (*str == end)
284433d6423SLionel Sambuc {
2856e7bb628SLionel Sambuc break;
286433d6423SLionel Sambuc }
2876e7bb628SLionel Sambuc **str= tmpstr[i-1];
2886e7bb628SLionel Sambuc (*str)++;
289433d6423SLionel Sambuc }
2906e7bb628SLionel Sambuc if (*str == end)
2916e7bb628SLionel Sambuc (*str)[-1]= '\0';
2926e7bb628SLionel Sambuc else
2936e7bb628SLionel Sambuc **str= '\0';
294433d6423SLionel Sambuc }
295433d6423SLionel Sambuc
296433d6423SLionel Sambuc /*===========================================================================*
2976e7bb628SLionel Sambuc * get_busind *
298433d6423SLionel Sambuc *===========================================================================*/
2996e7bb628SLionel Sambuc static int
get_busind(int busnr)3006e7bb628SLionel Sambuc get_busind(int busnr)
301433d6423SLionel Sambuc {
302433d6423SLionel Sambuc int i;
303433d6423SLionel Sambuc
3046e7bb628SLionel Sambuc for (i= 0; i<nr_pcibus; i++)
305433d6423SLionel Sambuc {
3066e7bb628SLionel Sambuc if (pcibus[i].pb_busnr == busnr)
3076e7bb628SLionel Sambuc return i;
308433d6423SLionel Sambuc }
3096e7bb628SLionel Sambuc panic("get_busind: can't find bus: %d", busnr);
310433d6423SLionel Sambuc }
311433d6423SLionel Sambuc
312433d6423SLionel Sambuc /*===========================================================================*
3136e7bb628SLionel Sambuc * Unprotected helper functions *
314433d6423SLionel Sambuc *===========================================================================*/
3156e7bb628SLionel Sambuc static u8_t
__pci_attr_r8(int devind,int port)3166e7bb628SLionel Sambuc __pci_attr_r8(int devind, int port)
317433d6423SLionel Sambuc {
318433d6423SLionel Sambuc int busnr, busind;
319433d6423SLionel Sambuc
320433d6423SLionel Sambuc busnr= pcidev[devind].pd_busnr;
321433d6423SLionel Sambuc busind= get_busind(busnr);
322433d6423SLionel Sambuc return pcibus[busind].pb_rreg8(busind, devind, port);
323433d6423SLionel Sambuc }
324433d6423SLionel Sambuc
3256e7bb628SLionel Sambuc static u16_t
__pci_attr_r16(int devind,int port)3266e7bb628SLionel Sambuc __pci_attr_r16(int devind, int port)
327433d6423SLionel Sambuc {
328433d6423SLionel Sambuc int busnr, busind;
329433d6423SLionel Sambuc
330433d6423SLionel Sambuc busnr= pcidev[devind].pd_busnr;
331433d6423SLionel Sambuc busind= get_busind(busnr);
332433d6423SLionel Sambuc return pcibus[busind].pb_rreg16(busind, devind, port);
333433d6423SLionel Sambuc }
334433d6423SLionel Sambuc
3356e7bb628SLionel Sambuc static u32_t
__pci_attr_r32(int devind,int port)3366e7bb628SLionel Sambuc __pci_attr_r32(int devind, int port)
337433d6423SLionel Sambuc {
338433d6423SLionel Sambuc int busnr, busind;
339433d6423SLionel Sambuc
340433d6423SLionel Sambuc busnr= pcidev[devind].pd_busnr;
341433d6423SLionel Sambuc busind= get_busind(busnr);
342433d6423SLionel Sambuc return pcibus[busind].pb_rreg32(busind, devind, port);
343433d6423SLionel Sambuc }
344433d6423SLionel Sambuc
3456e7bb628SLionel Sambuc static void
__pci_attr_w8(int devind,int port,u8_t value)3466e7bb628SLionel Sambuc __pci_attr_w8(int devind, int port, u8_t value)
347433d6423SLionel Sambuc {
348433d6423SLionel Sambuc int busnr, busind;
349433d6423SLionel Sambuc
350433d6423SLionel Sambuc busnr= pcidev[devind].pd_busnr;
351433d6423SLionel Sambuc busind= get_busind(busnr);
352433d6423SLionel Sambuc pcibus[busind].pb_wreg8(busind, devind, port, value);
353433d6423SLionel Sambuc }
354433d6423SLionel Sambuc
3556e7bb628SLionel Sambuc static void
__pci_attr_w16(int devind,int port,u16_t value)3566e7bb628SLionel Sambuc __pci_attr_w16(int devind, int port, u16_t value)
357433d6423SLionel Sambuc {
358433d6423SLionel Sambuc int busnr, busind;
359433d6423SLionel Sambuc
360433d6423SLionel Sambuc busnr= pcidev[devind].pd_busnr;
361433d6423SLionel Sambuc busind= get_busind(busnr);
362433d6423SLionel Sambuc pcibus[busind].pb_wreg16(busind, devind, port, value);
363433d6423SLionel Sambuc }
364433d6423SLionel Sambuc
3656e7bb628SLionel Sambuc static void
__pci_attr_w32(int devind,int port,u32_t value)3666e7bb628SLionel Sambuc __pci_attr_w32(int devind, int port, u32_t value)
367433d6423SLionel Sambuc {
368433d6423SLionel Sambuc int busnr, busind;
369433d6423SLionel Sambuc
370433d6423SLionel Sambuc busnr= pcidev[devind].pd_busnr;
371433d6423SLionel Sambuc busind= get_busind(busnr);
372433d6423SLionel Sambuc pcibus[busind].pb_wreg32(busind, devind, port, value);
373433d6423SLionel Sambuc }
374433d6423SLionel Sambuc
375433d6423SLionel Sambuc /*===========================================================================*
3766e7bb628SLionel Sambuc * helpers *
377433d6423SLionel Sambuc *===========================================================================*/
3786e7bb628SLionel Sambuc static u16_t
pci_attr_rsts(int devind)3796e7bb628SLionel Sambuc pci_attr_rsts(int devind)
380433d6423SLionel Sambuc {
3816e7bb628SLionel Sambuc int busnr, busind;
382433d6423SLionel Sambuc
3836e7bb628SLionel Sambuc busnr= pcidev[devind].pd_busnr;
3846e7bb628SLionel Sambuc busind= get_busind(busnr);
3856e7bb628SLionel Sambuc return pcibus[busind].pb_rsts(busind);
3866e7bb628SLionel Sambuc }
387433d6423SLionel Sambuc
3886e7bb628SLionel Sambuc static void
pci_attr_wsts(int devind,u16_t value)3896e7bb628SLionel Sambuc pci_attr_wsts(int devind, u16_t value)
3906e7bb628SLionel Sambuc {
3916e7bb628SLionel Sambuc int busnr, busind;
3926e7bb628SLionel Sambuc
3936e7bb628SLionel Sambuc busnr= pcidev[devind].pd_busnr;
3946e7bb628SLionel Sambuc busind= get_busind(busnr);
3956e7bb628SLionel Sambuc pcibus[busind].pb_wsts(busind, value);
3966e7bb628SLionel Sambuc }
3976e7bb628SLionel Sambuc
3986e7bb628SLionel Sambuc static u16_t
pcii_rsts(int busind)3996e7bb628SLionel Sambuc pcii_rsts(int busind)
4006e7bb628SLionel Sambuc {
4016e7bb628SLionel Sambuc u16_t v;
4026e7bb628SLionel Sambuc int s;
4036e7bb628SLionel Sambuc
4046e7bb628SLionel Sambuc v= PCII_RREG16_(pcibus[busind].pb_busnr, 0, 0, PCI_SR);
405433d6423SLionel Sambuc if (OK != (s=sys_outl(PCII_CONFADD, PCII_UNSEL)))
406433d6423SLionel Sambuc printf("PCI: warning, sys_outl failed: %d\n", s);
4076e7bb628SLionel Sambuc return v;
4086e7bb628SLionel Sambuc }
409433d6423SLionel Sambuc
4106e7bb628SLionel Sambuc static void
pcii_wsts(int busind,u16_t value)4116e7bb628SLionel Sambuc pcii_wsts(int busind, u16_t value)
412433d6423SLionel Sambuc {
4136e7bb628SLionel Sambuc int s;
4146e7bb628SLionel Sambuc PCII_WREG16_(pcibus[busind].pb_busnr, 0, 0, PCI_SR, value);
4156e7bb628SLionel Sambuc if (OK != (s=sys_outl(PCII_CONFADD, PCII_UNSEL)))
4166e7bb628SLionel Sambuc printf("PCI: warning, sys_outl failed: %d\n", s);
417433d6423SLionel Sambuc }
418433d6423SLionel Sambuc
4196e7bb628SLionel Sambuc static int
is_duplicate(u8_t busnr,u8_t dev,u8_t func)4206e7bb628SLionel Sambuc is_duplicate(u8_t busnr, u8_t dev, u8_t func)
421433d6423SLionel Sambuc {
422433d6423SLionel Sambuc int i;
423433d6423SLionel Sambuc
424433d6423SLionel Sambuc for (i= 0; i<nr_pcidev; i++)
425433d6423SLionel Sambuc {
426433d6423SLionel Sambuc if (pcidev[i].pd_busnr == busnr &&
427433d6423SLionel Sambuc pcidev[i].pd_dev == dev &&
428433d6423SLionel Sambuc pcidev[i].pd_func == func)
429433d6423SLionel Sambuc {
430433d6423SLionel Sambuc return 1;
431433d6423SLionel Sambuc }
432433d6423SLionel Sambuc }
433433d6423SLionel Sambuc return 0;
434433d6423SLionel Sambuc }
435433d6423SLionel Sambuc
4366e7bb628SLionel Sambuc static int
get_freebus(void)4376e7bb628SLionel Sambuc get_freebus(void)
4386e7bb628SLionel Sambuc {
4396e7bb628SLionel Sambuc int i, freebus;
4406e7bb628SLionel Sambuc
4416e7bb628SLionel Sambuc freebus= 1;
4426e7bb628SLionel Sambuc for (i= 0; i<nr_pcibus; i++)
4436e7bb628SLionel Sambuc {
4446e7bb628SLionel Sambuc if (pcibus[i].pb_needinit)
4456e7bb628SLionel Sambuc continue;
4466e7bb628SLionel Sambuc if (pcibus[i].pb_type == PBT_INTEL_HOST)
4476e7bb628SLionel Sambuc continue;
4486e7bb628SLionel Sambuc if (pcibus[i].pb_busnr <= freebus)
4496e7bb628SLionel Sambuc freebus= pcibus[i].pb_busnr+1;
4506e7bb628SLionel Sambuc printf("get_freebus: should check suboridinate bus number\n");
4516e7bb628SLionel Sambuc }
4526e7bb628SLionel Sambuc return freebus;
4536e7bb628SLionel Sambuc }
4546e7bb628SLionel Sambuc
4556e7bb628SLionel Sambuc static const char *
pci_vid_name(u16_t vid)4566e7bb628SLionel Sambuc pci_vid_name(u16_t vid)
4576e7bb628SLionel Sambuc {
4580a6a1f1dSLionel Sambuc static char vendor[PCI_VENDORSTR_LEN];
4590a6a1f1dSLionel Sambuc pci_findvendor(vendor, sizeof(vendor), vid);
4600a6a1f1dSLionel Sambuc
4610a6a1f1dSLionel Sambuc return vendor;
4626e7bb628SLionel Sambuc }
4636e7bb628SLionel Sambuc
4646e7bb628SLionel Sambuc
4656e7bb628SLionel Sambuc static void
print_hyper_cap(int devind,u8_t capptr)4666e7bb628SLionel Sambuc print_hyper_cap(int devind, u8_t capptr)
4676e7bb628SLionel Sambuc {
4686e7bb628SLionel Sambuc u32_t v;
4696e7bb628SLionel Sambuc u16_t cmd;
4706e7bb628SLionel Sambuc int type0, type1;
4716e7bb628SLionel Sambuc
4726e7bb628SLionel Sambuc printf("\n");
4736e7bb628SLionel Sambuc v= __pci_attr_r32(devind, capptr);
4746e7bb628SLionel Sambuc printf("print_hyper_cap: @0x%x, off 0 (cap):", capptr);
4756e7bb628SLionel Sambuc cmd= (v >> 16) & 0xffff;
4766e7bb628SLionel Sambuc #if 0
4776e7bb628SLionel Sambuc if (v & 0x10000)
4786e7bb628SLionel Sambuc {
4796e7bb628SLionel Sambuc printf(" WarmReset");
4806e7bb628SLionel Sambuc v &= ~0x10000;
4816e7bb628SLionel Sambuc }
4826e7bb628SLionel Sambuc if (v & 0x20000)
4836e7bb628SLionel Sambuc {
4846e7bb628SLionel Sambuc printf(" DblEnded");
4856e7bb628SLionel Sambuc v &= ~0x20000;
4866e7bb628SLionel Sambuc }
4876e7bb628SLionel Sambuc printf(" DevNum %d", (v & 0x7C0000) >> 18);
4886e7bb628SLionel Sambuc v &= ~0x7C0000;
4896e7bb628SLionel Sambuc #endif
4906e7bb628SLionel Sambuc type0= (cmd & 0xE000) >> 13;
4916e7bb628SLionel Sambuc type1= (cmd & 0xF800) >> 11;
4926e7bb628SLionel Sambuc if (type0 == 0 || type0 == 1)
4936e7bb628SLionel Sambuc {
4946e7bb628SLionel Sambuc printf("Capability Type: %s\n",
4956e7bb628SLionel Sambuc type0 == 0 ? "Slave or Primary Interface" :
4966e7bb628SLionel Sambuc "Host or Secondary Interface");
4976e7bb628SLionel Sambuc cmd &= ~0xE000;
4986e7bb628SLionel Sambuc }
4996e7bb628SLionel Sambuc else
5006e7bb628SLionel Sambuc {
5016e7bb628SLionel Sambuc printf(" Capability Type 0x%x", type1);
5026e7bb628SLionel Sambuc cmd &= ~0xF800;
5036e7bb628SLionel Sambuc }
5046e7bb628SLionel Sambuc if (cmd)
5056e7bb628SLionel Sambuc printf(" undecoded 0x%x\n", cmd);
5066e7bb628SLionel Sambuc
5076e7bb628SLionel Sambuc #if 0
5086e7bb628SLionel Sambuc printf("print_hyper_cap: off 4 (ctl): 0x%x\n",
5096e7bb628SLionel Sambuc __pci_attr_r32(devind, capptr+4));
5106e7bb628SLionel Sambuc printf("print_hyper_cap: off 8 (freq/rev): 0x%x\n",
5116e7bb628SLionel Sambuc __pci_attr_r32(devind, capptr+8));
5126e7bb628SLionel Sambuc printf("print_hyper_cap: off 12 (cap): 0x%x\n",
5136e7bb628SLionel Sambuc __pci_attr_r32(devind, capptr+12));
5146e7bb628SLionel Sambuc printf("print_hyper_cap: off 16 (buf count): 0x%x\n",
5156e7bb628SLionel Sambuc __pci_attr_r32(devind, capptr+16));
5166e7bb628SLionel Sambuc v= __pci_attr_r32(devind, capptr+20);
5176e7bb628SLionel Sambuc printf("print_hyper_cap: @0x%x, off 20 (bus nr): ",
5186e7bb628SLionel Sambuc capptr+20);
5196e7bb628SLionel Sambuc printf("prim %d", v & 0xff);
5206e7bb628SLionel Sambuc printf(", sec %d", (v >> 8) & 0xff);
5216e7bb628SLionel Sambuc printf(", sub %d", (v >> 16) & 0xff);
5226e7bb628SLionel Sambuc if (v >> 24)
5236e7bb628SLionel Sambuc printf(", reserved %d", (v >> 24) & 0xff);
5246e7bb628SLionel Sambuc printf("\n");
5256e7bb628SLionel Sambuc printf("print_hyper_cap: off 24 (type): 0x%x\n",
5266e7bb628SLionel Sambuc __pci_attr_r32(devind, capptr+24));
5276e7bb628SLionel Sambuc #endif
5286e7bb628SLionel Sambuc }
5296e7bb628SLionel Sambuc
5306e7bb628SLionel Sambuc static void
print_capabilities(int devind)5316e7bb628SLionel Sambuc print_capabilities(int devind)
5326e7bb628SLionel Sambuc {
5336e7bb628SLionel Sambuc u8_t status, capptr, type, next, subtype;
5346e7bb628SLionel Sambuc const char *str;
5356e7bb628SLionel Sambuc
5366e7bb628SLionel Sambuc /* Check capabilities bit in the device status register */
5376e7bb628SLionel Sambuc status= __pci_attr_r16(devind, PCI_SR);
5386e7bb628SLionel Sambuc if (!(status & PSR_CAPPTR))
5396e7bb628SLionel Sambuc return;
5406e7bb628SLionel Sambuc
5416e7bb628SLionel Sambuc capptr= (__pci_attr_r8(devind, PCI_CAPPTR) & PCI_CP_MASK);
5426e7bb628SLionel Sambuc while (capptr != 0)
5436e7bb628SLionel Sambuc {
5446e7bb628SLionel Sambuc type = __pci_attr_r8(devind, capptr+CAP_TYPE);
5456e7bb628SLionel Sambuc next= (__pci_attr_r8(devind, capptr+CAP_NEXT) & PCI_CP_MASK);
5466e7bb628SLionel Sambuc switch(type)
5476e7bb628SLionel Sambuc {
5486e7bb628SLionel Sambuc case 1: str= "PCI Power Management"; break;
5496e7bb628SLionel Sambuc case 2: str= "AGP"; break;
5506e7bb628SLionel Sambuc case 3: str= "Vital Product Data"; break;
5516e7bb628SLionel Sambuc case 4: str= "Slot Identification"; break;
5526e7bb628SLionel Sambuc case 5: str= "Message Signaled Interrupts"; break;
5536e7bb628SLionel Sambuc case 6: str= "CompactPCI Hot Swap"; break;
5546e7bb628SLionel Sambuc case 8: str= "AMD HyperTransport"; break;
5556e7bb628SLionel Sambuc case 0xf: str= "Secure Device"; break;
5566e7bb628SLionel Sambuc default: str= "(unknown type)"; break;
5576e7bb628SLionel Sambuc }
5586e7bb628SLionel Sambuc
5596e7bb628SLionel Sambuc printf(" @0x%x (0x%08x): capability type 0x%x: %s",
5606e7bb628SLionel Sambuc capptr, __pci_attr_r32(devind, capptr), type, str);
5616e7bb628SLionel Sambuc if (type == 0x08)
5626e7bb628SLionel Sambuc print_hyper_cap(devind, capptr);
5636e7bb628SLionel Sambuc else if (type == 0x0f)
5646e7bb628SLionel Sambuc {
5656e7bb628SLionel Sambuc subtype= (__pci_attr_r8(devind, capptr+2) & 0x07);
5666e7bb628SLionel Sambuc switch(subtype)
5676e7bb628SLionel Sambuc {
5686e7bb628SLionel Sambuc case 0: str= "Device Exclusion Vector"; break;
5696e7bb628SLionel Sambuc case 3: str= "IOMMU"; break;
5706e7bb628SLionel Sambuc default: str= "(unknown type)"; break;
5716e7bb628SLionel Sambuc }
5726e7bb628SLionel Sambuc printf(", sub type 0%o: %s", subtype, str);
5736e7bb628SLionel Sambuc }
5746e7bb628SLionel Sambuc printf("\n");
5756e7bb628SLionel Sambuc capptr= next;
5766e7bb628SLionel Sambuc }
5776e7bb628SLionel Sambuc }
5786e7bb628SLionel Sambuc
5796e7bb628SLionel Sambuc /*===========================================================================*
5806e7bb628SLionel Sambuc * ISA Bridge Helpers *
5816e7bb628SLionel Sambuc *===========================================================================*/
5826e7bb628SLionel Sambuc static void
update_bridge4dev_io(int devind,u32_t io_base,u32_t io_size)5836e7bb628SLionel Sambuc update_bridge4dev_io(int devind, u32_t io_base, u32_t io_size)
5846e7bb628SLionel Sambuc {
5856e7bb628SLionel Sambuc int busnr, busind, type, br_devind;
5866e7bb628SLionel Sambuc u16_t v16;
5876e7bb628SLionel Sambuc
5886e7bb628SLionel Sambuc busnr= pcidev[devind].pd_busnr;
5896e7bb628SLionel Sambuc busind= get_busind(busnr);
5906e7bb628SLionel Sambuc type= pcibus[busind].pb_type;
5916e7bb628SLionel Sambuc if (type == PBT_INTEL_HOST)
5926e7bb628SLionel Sambuc return; /* Nothing to do for host controller */
5936e7bb628SLionel Sambuc if (type == PBT_PCIBRIDGE)
5946e7bb628SLionel Sambuc {
5956e7bb628SLionel Sambuc printf(
5966e7bb628SLionel Sambuc "update_bridge4dev_io: not implemented for PCI bridges\n");
5976e7bb628SLionel Sambuc return;
5986e7bb628SLionel Sambuc }
5996e7bb628SLionel Sambuc if (type != PBT_CARDBUS)
6006e7bb628SLionel Sambuc panic("update_bridge4dev_io: strange bus type: %d", type);
6016e7bb628SLionel Sambuc
6026e7bb628SLionel Sambuc if (debug)
6036e7bb628SLionel Sambuc {
6046e7bb628SLionel Sambuc printf("update_bridge4dev_io: adding 0x%x at 0x%x\n",
6056e7bb628SLionel Sambuc io_size, io_base);
6066e7bb628SLionel Sambuc }
6076e7bb628SLionel Sambuc br_devind= pcibus[busind].pb_devind;
6086e7bb628SLionel Sambuc __pci_attr_w32(br_devind, CBB_IOLIMIT_0, io_base+io_size-1);
6096e7bb628SLionel Sambuc __pci_attr_w32(br_devind, CBB_IOBASE_0, io_base);
6106e7bb628SLionel Sambuc
6116e7bb628SLionel Sambuc /* Enable I/O access. Enable busmaster access as well. */
6126e7bb628SLionel Sambuc v16= __pci_attr_r16(devind, PCI_CR);
6136e7bb628SLionel Sambuc __pci_attr_w16(devind, PCI_CR, v16 | PCI_CR_IO_EN | PCI_CR_MAST_EN);
6146e7bb628SLionel Sambuc }
6156e7bb628SLionel Sambuc
6166e7bb628SLionel Sambuc static int
do_piix(int devind)6176e7bb628SLionel Sambuc do_piix(int devind)
6186e7bb628SLionel Sambuc {
6196e7bb628SLionel Sambuc int i, s, irqrc, irq;
6206e7bb628SLionel Sambuc u32_t elcr1, elcr2, elcr;
6216e7bb628SLionel Sambuc
6226e7bb628SLionel Sambuc #if DEBUG
6236e7bb628SLionel Sambuc printf("in piix\n");
6246e7bb628SLionel Sambuc #endif
6256e7bb628SLionel Sambuc if (OK != (s=sys_inb(PIIX_ELCR1, &elcr1)))
6266e7bb628SLionel Sambuc printf("Warning, sys_inb failed: %d\n", s);
6276e7bb628SLionel Sambuc if (OK != (s=sys_inb(PIIX_ELCR2, &elcr2)))
6286e7bb628SLionel Sambuc printf("Warning, sys_inb failed: %d\n", s);
6296e7bb628SLionel Sambuc elcr= elcr1 | (elcr2 << 8);
6306e7bb628SLionel Sambuc for (i= 0; i<4; i++)
6316e7bb628SLionel Sambuc {
6326e7bb628SLionel Sambuc irqrc= __pci_attr_r8(devind, PIIX_PIRQRCA+i);
6336e7bb628SLionel Sambuc if (irqrc & PIIX_IRQ_DI)
6346e7bb628SLionel Sambuc {
6356e7bb628SLionel Sambuc if (debug)
6366e7bb628SLionel Sambuc printf("INT%c: disabled\n", 'A'+i);
6376e7bb628SLionel Sambuc }
6386e7bb628SLionel Sambuc else
6396e7bb628SLionel Sambuc {
6406e7bb628SLionel Sambuc irq= irqrc & PIIX_IRQ_MASK;
6416e7bb628SLionel Sambuc if (debug)
6426e7bb628SLionel Sambuc printf("INT%c: %d\n", 'A'+i, irq);
6436e7bb628SLionel Sambuc if (!(elcr & (1 << irq)))
6446e7bb628SLionel Sambuc {
6456e7bb628SLionel Sambuc if (debug)
6466e7bb628SLionel Sambuc {
6476e7bb628SLionel Sambuc printf(
6486e7bb628SLionel Sambuc "(warning) IRQ %d is not level triggered\n",
6496e7bb628SLionel Sambuc irq);
6506e7bb628SLionel Sambuc }
6516e7bb628SLionel Sambuc }
6526e7bb628SLionel Sambuc irq_mode_pci(irq);
6536e7bb628SLionel Sambuc }
6546e7bb628SLionel Sambuc }
6556e7bb628SLionel Sambuc return 0;
6566e7bb628SLionel Sambuc }
6576e7bb628SLionel Sambuc
6586e7bb628SLionel Sambuc static int
do_amd_isabr(int devind)6596e7bb628SLionel Sambuc do_amd_isabr(int devind)
6606e7bb628SLionel Sambuc {
6616e7bb628SLionel Sambuc int i, busnr, dev, func, xdevind, irq, edge;
6626e7bb628SLionel Sambuc u8_t levmask;
6636e7bb628SLionel Sambuc u16_t pciirq;
6646e7bb628SLionel Sambuc
6656e7bb628SLionel Sambuc /* Find required function */
6666e7bb628SLionel Sambuc func= AMD_ISABR_FUNC;
6676e7bb628SLionel Sambuc busnr= pcidev[devind].pd_busnr;
6686e7bb628SLionel Sambuc dev= pcidev[devind].pd_dev;
6696e7bb628SLionel Sambuc
6706e7bb628SLionel Sambuc /* Fake a device with the required function */
6716e7bb628SLionel Sambuc if (nr_pcidev >= NR_PCIDEV)
6726e7bb628SLionel Sambuc panic("too many PCI devices: %d", nr_pcidev);
6736e7bb628SLionel Sambuc xdevind= nr_pcidev;
6746e7bb628SLionel Sambuc pcidev[xdevind].pd_busnr= busnr;
6756e7bb628SLionel Sambuc pcidev[xdevind].pd_dev= dev;
6766e7bb628SLionel Sambuc pcidev[xdevind].pd_func= func;
6776e7bb628SLionel Sambuc pcidev[xdevind].pd_inuse= 1;
6786e7bb628SLionel Sambuc nr_pcidev++;
6796e7bb628SLionel Sambuc
6806e7bb628SLionel Sambuc levmask= __pci_attr_r8(xdevind, AMD_ISABR_PCIIRQ_LEV);
6816e7bb628SLionel Sambuc pciirq= __pci_attr_r16(xdevind, AMD_ISABR_PCIIRQ_ROUTE);
6826e7bb628SLionel Sambuc for (i= 0; i<4; i++)
6836e7bb628SLionel Sambuc {
6846e7bb628SLionel Sambuc edge= (levmask >> i) & 1;
6856e7bb628SLionel Sambuc irq= (pciirq >> (4*i)) & 0xf;
6866e7bb628SLionel Sambuc if (!irq)
6876e7bb628SLionel Sambuc {
6886e7bb628SLionel Sambuc if (debug)
6896e7bb628SLionel Sambuc printf("INT%c: disabled\n", 'A'+i);
6906e7bb628SLionel Sambuc }
6916e7bb628SLionel Sambuc else
6926e7bb628SLionel Sambuc {
6936e7bb628SLionel Sambuc if (debug)
6946e7bb628SLionel Sambuc printf("INT%c: %d\n", 'A'+i, irq);
6956e7bb628SLionel Sambuc if (edge && debug)
6966e7bb628SLionel Sambuc {
6976e7bb628SLionel Sambuc printf(
6986e7bb628SLionel Sambuc "(warning) IRQ %d is not level triggered\n",
6996e7bb628SLionel Sambuc irq);
7006e7bb628SLionel Sambuc }
7016e7bb628SLionel Sambuc irq_mode_pci(irq);
7026e7bb628SLionel Sambuc }
7036e7bb628SLionel Sambuc }
7046e7bb628SLionel Sambuc nr_pcidev--;
7056e7bb628SLionel Sambuc return 0;
7066e7bb628SLionel Sambuc }
7076e7bb628SLionel Sambuc
7086e7bb628SLionel Sambuc static int
do_sis_isabr(int devind)7096e7bb628SLionel Sambuc do_sis_isabr(int devind)
7106e7bb628SLionel Sambuc {
7116e7bb628SLionel Sambuc int i, irq;
7126e7bb628SLionel Sambuc
7136e7bb628SLionel Sambuc irq= 0; /* lint */
7146e7bb628SLionel Sambuc for (i= 0; i<4; i++)
7156e7bb628SLionel Sambuc {
7166e7bb628SLionel Sambuc irq= __pci_attr_r8(devind, SIS_ISABR_IRQ_A+i);
7176e7bb628SLionel Sambuc if (irq & SIS_IRQ_DISABLED)
7186e7bb628SLionel Sambuc {
7196e7bb628SLionel Sambuc if (debug)
7206e7bb628SLionel Sambuc printf("INT%c: disabled\n", 'A'+i);
7216e7bb628SLionel Sambuc }
7226e7bb628SLionel Sambuc else
7236e7bb628SLionel Sambuc {
7246e7bb628SLionel Sambuc irq &= SIS_IRQ_MASK;
7256e7bb628SLionel Sambuc if (debug)
7266e7bb628SLionel Sambuc printf("INT%c: %d\n", 'A'+i, irq);
7276e7bb628SLionel Sambuc irq_mode_pci(irq);
7286e7bb628SLionel Sambuc }
7296e7bb628SLionel Sambuc }
7306e7bb628SLionel Sambuc return 0;
7316e7bb628SLionel Sambuc }
7326e7bb628SLionel Sambuc
7336e7bb628SLionel Sambuc static int
do_via_isabr(int devind)7346e7bb628SLionel Sambuc do_via_isabr(int devind)
7356e7bb628SLionel Sambuc {
7366e7bb628SLionel Sambuc int i, irq, edge;
7376e7bb628SLionel Sambuc u8_t levmask;
7386e7bb628SLionel Sambuc
7396e7bb628SLionel Sambuc levmask= __pci_attr_r8(devind, VIA_ISABR_EL);
7406e7bb628SLionel Sambuc irq= 0; /* lint */
7416e7bb628SLionel Sambuc edge= 0; /* lint */
7426e7bb628SLionel Sambuc for (i= 0; i<4; i++)
7436e7bb628SLionel Sambuc {
7446e7bb628SLionel Sambuc switch(i)
7456e7bb628SLionel Sambuc {
7466e7bb628SLionel Sambuc case 0:
7476e7bb628SLionel Sambuc edge= (levmask & VIA_ISABR_EL_INTA);
7486e7bb628SLionel Sambuc irq= __pci_attr_r8(devind, VIA_ISABR_IRQ_R2) >> 4;
7496e7bb628SLionel Sambuc break;
7506e7bb628SLionel Sambuc case 1:
7516e7bb628SLionel Sambuc edge= (levmask & VIA_ISABR_EL_INTB);
7526e7bb628SLionel Sambuc irq= __pci_attr_r8(devind, VIA_ISABR_IRQ_R2);
7536e7bb628SLionel Sambuc break;
7546e7bb628SLionel Sambuc case 2:
7556e7bb628SLionel Sambuc edge= (levmask & VIA_ISABR_EL_INTC);
7566e7bb628SLionel Sambuc irq= __pci_attr_r8(devind, VIA_ISABR_IRQ_R3) >> 4;
7576e7bb628SLionel Sambuc break;
7586e7bb628SLionel Sambuc case 3:
7596e7bb628SLionel Sambuc edge= (levmask & VIA_ISABR_EL_INTD);
7606e7bb628SLionel Sambuc irq= __pci_attr_r8(devind, VIA_ISABR_IRQ_R1) >> 4;
7616e7bb628SLionel Sambuc break;
7626e7bb628SLionel Sambuc default:
7636e7bb628SLionel Sambuc panic("PCI: VIA ISA Bridge IRQ Detection Failed");
7646e7bb628SLionel Sambuc }
7656e7bb628SLionel Sambuc irq &= 0xf;
7666e7bb628SLionel Sambuc if (!irq)
7676e7bb628SLionel Sambuc {
7686e7bb628SLionel Sambuc if (debug)
7696e7bb628SLionel Sambuc printf("INT%c: disabled\n", 'A'+i);
7706e7bb628SLionel Sambuc }
7716e7bb628SLionel Sambuc else
7726e7bb628SLionel Sambuc {
7736e7bb628SLionel Sambuc if (debug)
7746e7bb628SLionel Sambuc printf("INT%c: %d\n", 'A'+i, irq);
7756e7bb628SLionel Sambuc if (edge && debug)
7766e7bb628SLionel Sambuc {
7776e7bb628SLionel Sambuc printf(
7786e7bb628SLionel Sambuc "(warning) IRQ %d is not level triggered\n",
7796e7bb628SLionel Sambuc irq);
7806e7bb628SLionel Sambuc }
7816e7bb628SLionel Sambuc irq_mode_pci(irq);
7826e7bb628SLionel Sambuc }
7836e7bb628SLionel Sambuc }
7846e7bb628SLionel Sambuc return 0;
7856e7bb628SLionel Sambuc }
7866e7bb628SLionel Sambuc
7876e7bb628SLionel Sambuc static int
do_isabridge(int busind)7886e7bb628SLionel Sambuc do_isabridge(int busind)
7896e7bb628SLionel Sambuc {
7906e7bb628SLionel Sambuc int i, j, r, type, busnr, unknown_bridge, bridge_dev;
7916e7bb628SLionel Sambuc u16_t vid, did;
7926e7bb628SLionel Sambuc u32_t t3;
7936e7bb628SLionel Sambuc const char *dstr;
7946e7bb628SLionel Sambuc
7956e7bb628SLionel Sambuc unknown_bridge= -1;
7966e7bb628SLionel Sambuc bridge_dev= -1;
7976e7bb628SLionel Sambuc j= 0; /* lint */
7986e7bb628SLionel Sambuc vid= did= 0; /* lint */
7996e7bb628SLionel Sambuc busnr= pcibus[busind].pb_busnr;
8006e7bb628SLionel Sambuc for (i= 0; i< nr_pcidev; i++)
8016e7bb628SLionel Sambuc {
8026e7bb628SLionel Sambuc if (pcidev[i].pd_busnr != busnr)
8036e7bb628SLionel Sambuc continue;
8046e7bb628SLionel Sambuc t3= ((pcidev[i].pd_baseclass << 16) |
8056e7bb628SLionel Sambuc (pcidev[i].pd_subclass << 8) | pcidev[i].pd_infclass);
8066e7bb628SLionel Sambuc if (t3 == PCI_T3_ISA)
8076e7bb628SLionel Sambuc {
8086e7bb628SLionel Sambuc /* ISA bridge. Report if no supported bridge is
8096e7bb628SLionel Sambuc * found.
8106e7bb628SLionel Sambuc */
8116e7bb628SLionel Sambuc unknown_bridge= i;
8126e7bb628SLionel Sambuc }
8136e7bb628SLionel Sambuc
8146e7bb628SLionel Sambuc vid= pcidev[i].pd_vid;
8156e7bb628SLionel Sambuc did= pcidev[i].pd_did;
8166e7bb628SLionel Sambuc for (j= 0; pci_isabridge[j].vid != 0; j++)
8176e7bb628SLionel Sambuc {
8186e7bb628SLionel Sambuc if (pci_isabridge[j].vid != vid)
8196e7bb628SLionel Sambuc continue;
8206e7bb628SLionel Sambuc if (pci_isabridge[j].did != did)
8216e7bb628SLionel Sambuc continue;
8226e7bb628SLionel Sambuc if (pci_isabridge[j].checkclass &&
8236e7bb628SLionel Sambuc unknown_bridge != i)
8246e7bb628SLionel Sambuc {
8256e7bb628SLionel Sambuc /* This part of multifunction device is
8266e7bb628SLionel Sambuc * not the bridge.
8276e7bb628SLionel Sambuc */
8286e7bb628SLionel Sambuc continue;
8296e7bb628SLionel Sambuc }
8306e7bb628SLionel Sambuc break;
8316e7bb628SLionel Sambuc }
8326e7bb628SLionel Sambuc if (pci_isabridge[j].vid)
8336e7bb628SLionel Sambuc {
8346e7bb628SLionel Sambuc bridge_dev= i;
8356e7bb628SLionel Sambuc break;
8366e7bb628SLionel Sambuc }
8376e7bb628SLionel Sambuc }
8386e7bb628SLionel Sambuc
8396e7bb628SLionel Sambuc if (bridge_dev != -1)
8406e7bb628SLionel Sambuc {
8416e7bb628SLionel Sambuc dstr= _pci_dev_name(vid, did);
8426e7bb628SLionel Sambuc if (!dstr)
8436e7bb628SLionel Sambuc dstr= "unknown device";
8446e7bb628SLionel Sambuc if (debug)
8456e7bb628SLionel Sambuc {
8466e7bb628SLionel Sambuc printf("found ISA bridge (%04X:%04X) %s\n",
8476e7bb628SLionel Sambuc vid, did, dstr);
8486e7bb628SLionel Sambuc }
8496e7bb628SLionel Sambuc pcibus[busind].pb_isabridge_dev= bridge_dev;
8506e7bb628SLionel Sambuc type= pci_isabridge[j].type;
8516e7bb628SLionel Sambuc pcibus[busind].pb_isabridge_type= type;
8526e7bb628SLionel Sambuc switch(type)
8536e7bb628SLionel Sambuc {
8546e7bb628SLionel Sambuc case PCI_IB_PIIX:
8556e7bb628SLionel Sambuc r= do_piix(bridge_dev);
8566e7bb628SLionel Sambuc break;
8576e7bb628SLionel Sambuc case PCI_IB_VIA:
8586e7bb628SLionel Sambuc r= do_via_isabr(bridge_dev);
8596e7bb628SLionel Sambuc break;
8606e7bb628SLionel Sambuc case PCI_IB_AMD:
8616e7bb628SLionel Sambuc r= do_amd_isabr(bridge_dev);
8626e7bb628SLionel Sambuc break;
8636e7bb628SLionel Sambuc case PCI_IB_SIS:
8646e7bb628SLionel Sambuc r= do_sis_isabr(bridge_dev);
8656e7bb628SLionel Sambuc break;
8666e7bb628SLionel Sambuc default:
8676e7bb628SLionel Sambuc panic("unknown ISA bridge type: %d", type);
8686e7bb628SLionel Sambuc }
8696e7bb628SLionel Sambuc return r;
8706e7bb628SLionel Sambuc }
8716e7bb628SLionel Sambuc
8726e7bb628SLionel Sambuc if (unknown_bridge == -1)
8736e7bb628SLionel Sambuc {
8746e7bb628SLionel Sambuc if (debug)
8756e7bb628SLionel Sambuc {
8766e7bb628SLionel Sambuc printf("(warning) no ISA bridge found on bus %d\n",
8776e7bb628SLionel Sambuc busind);
8786e7bb628SLionel Sambuc }
8796e7bb628SLionel Sambuc return 0;
8806e7bb628SLionel Sambuc }
8816e7bb628SLionel Sambuc if (debug)
8826e7bb628SLionel Sambuc {
8836e7bb628SLionel Sambuc printf(
8846e7bb628SLionel Sambuc "(warning) unsupported ISA bridge %04X:%04X for bus %d\n",
8856e7bb628SLionel Sambuc pcidev[unknown_bridge].pd_vid,
8866e7bb628SLionel Sambuc pcidev[unknown_bridge].pd_did, busind);
8876e7bb628SLionel Sambuc }
8886e7bb628SLionel Sambuc return 0;
8896e7bb628SLionel Sambuc }
8906e7bb628SLionel Sambuc
8916e7bb628SLionel Sambuc static int
derive_irq(struct pcidev * dev,int pin)8926e7bb628SLionel Sambuc derive_irq(struct pcidev * dev, int pin)
893433d6423SLionel Sambuc {
894433d6423SLionel Sambuc struct pcidev * parent_bridge;
895433d6423SLionel Sambuc int slot;
896433d6423SLionel Sambuc
897433d6423SLionel Sambuc parent_bridge = &pcidev[pcibus[get_busind(dev->pd_busnr)].pb_devind];
898433d6423SLionel Sambuc
899433d6423SLionel Sambuc /*
900433d6423SLionel Sambuc * We don't support PCI-Express, no ARI, decode the slot of the device
901433d6423SLionel Sambuc * and mangle the pin as the device is behind a bridge
902433d6423SLionel Sambuc */
903433d6423SLionel Sambuc slot = ((dev->pd_func) >> 3) & 0x1f;
904433d6423SLionel Sambuc
905433d6423SLionel Sambuc return acpi_get_irq(parent_bridge->pd_busnr,
906433d6423SLionel Sambuc parent_bridge->pd_dev, (pin + slot) % 4);
907433d6423SLionel Sambuc }
908433d6423SLionel Sambuc
9096e7bb628SLionel Sambuc static void
record_irq(int devind)9106e7bb628SLionel Sambuc record_irq(int devind)
911433d6423SLionel Sambuc {
912433d6423SLionel Sambuc int ilr, ipr, busnr, busind, cb_devind;
913433d6423SLionel Sambuc
9146e7bb628SLionel Sambuc ilr= __pci_attr_r8(devind, PCI_ILR);
9156e7bb628SLionel Sambuc ipr= __pci_attr_r8(devind, PCI_IPR);
916433d6423SLionel Sambuc
917433d6423SLionel Sambuc if (ipr && machine.apic_enabled) {
918433d6423SLionel Sambuc int irq;
919433d6423SLionel Sambuc
920433d6423SLionel Sambuc irq = acpi_get_irq(pcidev[devind].pd_busnr,
921433d6423SLionel Sambuc pcidev[devind].pd_dev, ipr - 1);
922433d6423SLionel Sambuc
923433d6423SLionel Sambuc if (irq < 0)
924433d6423SLionel Sambuc irq = derive_irq(&pcidev[devind], ipr - 1);
925433d6423SLionel Sambuc
926433d6423SLionel Sambuc if (irq >= 0) {
927433d6423SLionel Sambuc ilr = irq;
9286e7bb628SLionel Sambuc __pci_attr_w8(devind, PCI_ILR, ilr);
929433d6423SLionel Sambuc if (debug)
930433d6423SLionel Sambuc printf("PCI: ACPI IRQ %d for "
931433d6423SLionel Sambuc "device %d.%d.%d INT%c\n",
932433d6423SLionel Sambuc irq,
933433d6423SLionel Sambuc pcidev[devind].pd_busnr,
934433d6423SLionel Sambuc pcidev[devind].pd_dev,
935433d6423SLionel Sambuc pcidev[devind].pd_func,
936433d6423SLionel Sambuc 'A' + ipr-1);
937433d6423SLionel Sambuc }
938433d6423SLionel Sambuc else if (debug) {
939433d6423SLionel Sambuc printf("PCI: no ACPI IRQ routing for "
940433d6423SLionel Sambuc "device %d.%d.%d INT%c\n",
941433d6423SLionel Sambuc pcidev[devind].pd_busnr,
942433d6423SLionel Sambuc pcidev[devind].pd_dev,
943433d6423SLionel Sambuc pcidev[devind].pd_func,
944433d6423SLionel Sambuc 'A' + ipr-1);
945433d6423SLionel Sambuc }
946433d6423SLionel Sambuc }
947433d6423SLionel Sambuc
948433d6423SLionel Sambuc if (ilr == 0)
949433d6423SLionel Sambuc {
950433d6423SLionel Sambuc static int first= 1;
951433d6423SLionel Sambuc if (ipr && first && debug)
952433d6423SLionel Sambuc {
953433d6423SLionel Sambuc first= 0;
954433d6423SLionel Sambuc printf("PCI: strange, BIOS assigned IRQ0\n");
955433d6423SLionel Sambuc }
956433d6423SLionel Sambuc ilr= PCI_ILR_UNKNOWN;
957433d6423SLionel Sambuc }
958433d6423SLionel Sambuc pcidev[devind].pd_ilr= ilr;
959433d6423SLionel Sambuc if (ilr == PCI_ILR_UNKNOWN && !ipr)
960433d6423SLionel Sambuc {
961433d6423SLionel Sambuc }
962433d6423SLionel Sambuc else if (ilr != PCI_ILR_UNKNOWN && ipr)
963433d6423SLionel Sambuc {
964433d6423SLionel Sambuc if (debug)
965433d6423SLionel Sambuc printf("\tIRQ %d for INT%c\n", ilr, 'A' + ipr-1);
966433d6423SLionel Sambuc }
967433d6423SLionel Sambuc else if (ilr != PCI_ILR_UNKNOWN)
968433d6423SLionel Sambuc {
969433d6423SLionel Sambuc printf(
970433d6423SLionel Sambuc "PCI: IRQ %d is assigned, but device %d.%d.%d does not need it\n",
971433d6423SLionel Sambuc ilr, pcidev[devind].pd_busnr, pcidev[devind].pd_dev,
972433d6423SLionel Sambuc pcidev[devind].pd_func);
973433d6423SLionel Sambuc }
974433d6423SLionel Sambuc else
975433d6423SLionel Sambuc {
976433d6423SLionel Sambuc /* Check for cardbus devices */
977433d6423SLionel Sambuc busnr= pcidev[devind].pd_busnr;
978433d6423SLionel Sambuc busind= get_busind(busnr);
979433d6423SLionel Sambuc if (pcibus[busind].pb_type == PBT_CARDBUS)
980433d6423SLionel Sambuc {
981433d6423SLionel Sambuc cb_devind= pcibus[busind].pb_devind;
982433d6423SLionel Sambuc ilr= pcidev[cb_devind].pd_ilr;
983433d6423SLionel Sambuc if (ilr != PCI_ILR_UNKNOWN)
984433d6423SLionel Sambuc {
985433d6423SLionel Sambuc if (debug)
986433d6423SLionel Sambuc {
987433d6423SLionel Sambuc printf(
988433d6423SLionel Sambuc "assigning IRQ %d to Cardbus device\n",
989433d6423SLionel Sambuc ilr);
990433d6423SLionel Sambuc }
9916e7bb628SLionel Sambuc __pci_attr_w8(devind, PCI_ILR, ilr);
992433d6423SLionel Sambuc pcidev[devind].pd_ilr= ilr;
993433d6423SLionel Sambuc return;
994433d6423SLionel Sambuc }
995433d6423SLionel Sambuc }
996433d6423SLionel Sambuc if(debug) {
997433d6423SLionel Sambuc printf(
998433d6423SLionel Sambuc "PCI: device %d.%d.%d uses INT%c but is not assigned any IRQ\n",
999433d6423SLionel Sambuc pcidev[devind].pd_busnr, pcidev[devind].pd_dev,
1000433d6423SLionel Sambuc pcidev[devind].pd_func, 'A' + ipr-1);
1001433d6423SLionel Sambuc }
1002433d6423SLionel Sambuc }
1003433d6423SLionel Sambuc }
1004433d6423SLionel Sambuc
1005433d6423SLionel Sambuc /*===========================================================================*
10066e7bb628SLionel Sambuc * BAR helpers *
1007433d6423SLionel Sambuc *===========================================================================*/
10086e7bb628SLionel Sambuc static int
record_bar(int devind,int bar_nr,int last)10096e7bb628SLionel Sambuc record_bar(int devind, int bar_nr, int last)
10106e7bb628SLionel Sambuc {
10116e7bb628SLionel Sambuc int reg, prefetch, type, dev_bar_nr, width;
10126e7bb628SLionel Sambuc u32_t bar, bar2;
10136e7bb628SLionel Sambuc u16_t cmd;
10146e7bb628SLionel Sambuc
10156e7bb628SLionel Sambuc /* Start by assuming that this is a 32-bit bar, taking up one DWORD. */
10166e7bb628SLionel Sambuc width = 1;
10176e7bb628SLionel Sambuc
10186e7bb628SLionel Sambuc reg= PCI_BAR+4*bar_nr;
10196e7bb628SLionel Sambuc
10206e7bb628SLionel Sambuc bar= __pci_attr_r32(devind, reg);
10216e7bb628SLionel Sambuc if (bar & PCI_BAR_IO)
10226e7bb628SLionel Sambuc {
10236e7bb628SLionel Sambuc /* Disable I/O access before probing for BAR's size */
10246e7bb628SLionel Sambuc cmd = __pci_attr_r16(devind, PCI_CR);
10256e7bb628SLionel Sambuc __pci_attr_w16(devind, PCI_CR, cmd & ~PCI_CR_IO_EN);
10266e7bb628SLionel Sambuc
10276e7bb628SLionel Sambuc /* Probe BAR's size */
10286e7bb628SLionel Sambuc __pci_attr_w32(devind, reg, 0xffffffff);
10296e7bb628SLionel Sambuc bar2= __pci_attr_r32(devind, reg);
10306e7bb628SLionel Sambuc
10316e7bb628SLionel Sambuc /* Restore original state */
10326e7bb628SLionel Sambuc __pci_attr_w32(devind, reg, bar);
10336e7bb628SLionel Sambuc __pci_attr_w16(devind, PCI_CR, cmd);
10346e7bb628SLionel Sambuc
10356e7bb628SLionel Sambuc bar &= PCI_BAR_IO_MASK; /* Clear non-address bits */
10366e7bb628SLionel Sambuc bar2 &= PCI_BAR_IO_MASK;
10376e7bb628SLionel Sambuc bar2= (~bar2 & 0xffff)+1;
10386e7bb628SLionel Sambuc if (debug)
10396e7bb628SLionel Sambuc {
10406e7bb628SLionel Sambuc printf("\tbar_%d: %d bytes at 0x%x I/O\n",
10416e7bb628SLionel Sambuc bar_nr, bar2, bar);
10426e7bb628SLionel Sambuc }
10436e7bb628SLionel Sambuc
10446e7bb628SLionel Sambuc dev_bar_nr= pcidev[devind].pd_bar_nr++;
10456e7bb628SLionel Sambuc pcidev[devind].pd_bar[dev_bar_nr].pb_flags= PBF_IO;
10466e7bb628SLionel Sambuc pcidev[devind].pd_bar[dev_bar_nr].pb_base= bar;
10476e7bb628SLionel Sambuc pcidev[devind].pd_bar[dev_bar_nr].pb_size= bar2;
10486e7bb628SLionel Sambuc pcidev[devind].pd_bar[dev_bar_nr].pb_nr= bar_nr;
10496e7bb628SLionel Sambuc if (bar == 0)
10506e7bb628SLionel Sambuc {
10516e7bb628SLionel Sambuc pcidev[devind].pd_bar[dev_bar_nr].pb_flags |=
10526e7bb628SLionel Sambuc PBF_INCOMPLETE;
10536e7bb628SLionel Sambuc }
10546e7bb628SLionel Sambuc }
10556e7bb628SLionel Sambuc else
10566e7bb628SLionel Sambuc {
10576e7bb628SLionel Sambuc type= (bar & PCI_BAR_TYPE);
10586e7bb628SLionel Sambuc
10596e7bb628SLionel Sambuc switch(type) {
10606e7bb628SLionel Sambuc case PCI_TYPE_32:
10616e7bb628SLionel Sambuc case PCI_TYPE_32_1M:
10626e7bb628SLionel Sambuc break;
10636e7bb628SLionel Sambuc
10646e7bb628SLionel Sambuc case PCI_TYPE_64:
10656e7bb628SLionel Sambuc /* A 64-bit BAR takes up two consecutive DWORDs. */
10666e7bb628SLionel Sambuc if (last)
10676e7bb628SLionel Sambuc {
10686e7bb628SLionel Sambuc printf("PCI: device %d.%d.%d BAR %d extends"
10696e7bb628SLionel Sambuc " beyond designated area\n",
10706e7bb628SLionel Sambuc pcidev[devind].pd_busnr,
10716e7bb628SLionel Sambuc pcidev[devind].pd_dev,
10726e7bb628SLionel Sambuc pcidev[devind].pd_func, bar_nr);
10736e7bb628SLionel Sambuc
10746e7bb628SLionel Sambuc return width;
10756e7bb628SLionel Sambuc }
10766e7bb628SLionel Sambuc width++;
10776e7bb628SLionel Sambuc
10786e7bb628SLionel Sambuc bar2= __pci_attr_r32(devind, reg+4);
10796e7bb628SLionel Sambuc
10806e7bb628SLionel Sambuc /* If the upper 32 bits of the BAR are not zero, the
10816e7bb628SLionel Sambuc * memory is inaccessible to us; ignore the BAR.
10826e7bb628SLionel Sambuc */
10836e7bb628SLionel Sambuc if (bar2 != 0)
10846e7bb628SLionel Sambuc {
10856e7bb628SLionel Sambuc if (debug)
10866e7bb628SLionel Sambuc {
10876e7bb628SLionel Sambuc printf("\tbar_%d: (64-bit BAR with"
10886e7bb628SLionel Sambuc " high bits set)\n", bar_nr);
10896e7bb628SLionel Sambuc }
10906e7bb628SLionel Sambuc
10916e7bb628SLionel Sambuc return width;
10926e7bb628SLionel Sambuc }
10936e7bb628SLionel Sambuc
10946e7bb628SLionel Sambuc break;
10956e7bb628SLionel Sambuc
10966e7bb628SLionel Sambuc default:
10976e7bb628SLionel Sambuc /* Ignore the BAR. */
10986e7bb628SLionel Sambuc if (debug)
10996e7bb628SLionel Sambuc {
11006e7bb628SLionel Sambuc printf("\tbar_%d: (unknown type %x)\n",
11016e7bb628SLionel Sambuc bar_nr, type);
11026e7bb628SLionel Sambuc }
11036e7bb628SLionel Sambuc
11046e7bb628SLionel Sambuc return width;
11056e7bb628SLionel Sambuc }
11066e7bb628SLionel Sambuc
11076e7bb628SLionel Sambuc /* Disable mem access before probing for BAR's size */
11086e7bb628SLionel Sambuc cmd = __pci_attr_r16(devind, PCI_CR);
11096e7bb628SLionel Sambuc __pci_attr_w16(devind, PCI_CR, cmd & ~PCI_CR_MEM_EN);
11106e7bb628SLionel Sambuc
11116e7bb628SLionel Sambuc /* Probe BAR's size */
11126e7bb628SLionel Sambuc __pci_attr_w32(devind, reg, 0xffffffff);
11136e7bb628SLionel Sambuc bar2= __pci_attr_r32(devind, reg);
11146e7bb628SLionel Sambuc
11156e7bb628SLionel Sambuc /* Restore original values */
11166e7bb628SLionel Sambuc __pci_attr_w32(devind, reg, bar);
11176e7bb628SLionel Sambuc __pci_attr_w16(devind, PCI_CR, cmd);
11186e7bb628SLionel Sambuc
11196e7bb628SLionel Sambuc if (bar2 == 0)
11206e7bb628SLionel Sambuc return width; /* Reg. is not implemented */
11216e7bb628SLionel Sambuc
11226e7bb628SLionel Sambuc prefetch= !!(bar & PCI_BAR_PREFETCH);
11236e7bb628SLionel Sambuc bar &= PCI_BAR_MEM_MASK; /* Clear non-address bits */
11246e7bb628SLionel Sambuc bar2 &= PCI_BAR_MEM_MASK;
11256e7bb628SLionel Sambuc bar2= (~bar2)+1;
11266e7bb628SLionel Sambuc if (debug)
11276e7bb628SLionel Sambuc {
11286e7bb628SLionel Sambuc printf("\tbar_%d: 0x%x bytes at 0x%x%s memory%s\n",
11296e7bb628SLionel Sambuc bar_nr, bar2, bar,
11306e7bb628SLionel Sambuc prefetch ? " prefetchable" : "",
11316e7bb628SLionel Sambuc type == PCI_TYPE_64 ? ", 64-bit" : "");
11326e7bb628SLionel Sambuc }
11336e7bb628SLionel Sambuc
11346e7bb628SLionel Sambuc dev_bar_nr= pcidev[devind].pd_bar_nr++;
11356e7bb628SLionel Sambuc pcidev[devind].pd_bar[dev_bar_nr].pb_flags= 0;
11366e7bb628SLionel Sambuc pcidev[devind].pd_bar[dev_bar_nr].pb_base= bar;
11376e7bb628SLionel Sambuc pcidev[devind].pd_bar[dev_bar_nr].pb_size= bar2;
11386e7bb628SLionel Sambuc pcidev[devind].pd_bar[dev_bar_nr].pb_nr= bar_nr;
11396e7bb628SLionel Sambuc if (bar == 0)
11406e7bb628SLionel Sambuc {
11416e7bb628SLionel Sambuc pcidev[devind].pd_bar[dev_bar_nr].pb_flags |=
11426e7bb628SLionel Sambuc PBF_INCOMPLETE;
11436e7bb628SLionel Sambuc }
11446e7bb628SLionel Sambuc }
11456e7bb628SLionel Sambuc
11466e7bb628SLionel Sambuc return width;
11476e7bb628SLionel Sambuc }
11486e7bb628SLionel Sambuc
11496e7bb628SLionel Sambuc static void
record_bars(int devind,int last_reg)11506e7bb628SLionel Sambuc record_bars(int devind, int last_reg)
11516e7bb628SLionel Sambuc {
11526e7bb628SLionel Sambuc int i, reg, width;
11536e7bb628SLionel Sambuc
11546e7bb628SLionel Sambuc for (i= 0, reg= PCI_BAR; reg <= last_reg; i += width, reg += 4 * width)
11556e7bb628SLionel Sambuc {
11566e7bb628SLionel Sambuc width = record_bar(devind, i, reg == last_reg);
11576e7bb628SLionel Sambuc }
11586e7bb628SLionel Sambuc }
11596e7bb628SLionel Sambuc
11606e7bb628SLionel Sambuc static void
record_bars_normal(int devind)11616e7bb628SLionel Sambuc record_bars_normal(int devind)
1162433d6423SLionel Sambuc {
1163433d6423SLionel Sambuc int i, j, clear_01, clear_23, pb_nr;
1164433d6423SLionel Sambuc
1165433d6423SLionel Sambuc /* The BAR area of normal devices is six DWORDs in size. */
1166433d6423SLionel Sambuc record_bars(devind, PCI_BAR_6);
1167433d6423SLionel Sambuc
1168433d6423SLionel Sambuc /* Special case code for IDE controllers in compatibility mode */
1169433d6423SLionel Sambuc if (pcidev[devind].pd_baseclass == PCI_BCR_MASS_STORAGE &&
1170433d6423SLionel Sambuc pcidev[devind].pd_subclass == PCI_MS_IDE)
1171433d6423SLionel Sambuc {
1172433d6423SLionel Sambuc /* IDE device */
1173433d6423SLionel Sambuc clear_01= 0;
1174433d6423SLionel Sambuc clear_23= 0;
1175433d6423SLionel Sambuc if (!(pcidev[devind].pd_infclass & PCI_IDE_PRI_NATIVE))
1176433d6423SLionel Sambuc {
1177433d6423SLionel Sambuc if (debug)
1178433d6423SLionel Sambuc {
1179433d6423SLionel Sambuc printf(
1180433d6423SLionel Sambuc "primary channel is not in native mode, clearing BARs 0 and 1\n");
1181433d6423SLionel Sambuc }
1182433d6423SLionel Sambuc clear_01= 1;
1183433d6423SLionel Sambuc }
1184433d6423SLionel Sambuc if (!(pcidev[devind].pd_infclass & PCI_IDE_SEC_NATIVE))
1185433d6423SLionel Sambuc {
1186433d6423SLionel Sambuc if (debug)
1187433d6423SLionel Sambuc {
1188433d6423SLionel Sambuc printf(
1189433d6423SLionel Sambuc "secondary channel is not in native mode, clearing BARs 2 and 3\n");
1190433d6423SLionel Sambuc }
1191433d6423SLionel Sambuc clear_23= 1;
1192433d6423SLionel Sambuc }
1193433d6423SLionel Sambuc
1194433d6423SLionel Sambuc j= 0;
1195433d6423SLionel Sambuc for (i= 0; i<pcidev[devind].pd_bar_nr; i++)
1196433d6423SLionel Sambuc {
1197433d6423SLionel Sambuc pb_nr= pcidev[devind].pd_bar[i].pb_nr;
1198433d6423SLionel Sambuc if ((pb_nr == 0 || pb_nr == 1) && clear_01)
1199433d6423SLionel Sambuc {
1200433d6423SLionel Sambuc if (debug) printf("skipping bar %d\n", pb_nr);
1201433d6423SLionel Sambuc continue; /* Skip */
1202433d6423SLionel Sambuc }
1203433d6423SLionel Sambuc if ((pb_nr == 2 || pb_nr == 3) && clear_23)
1204433d6423SLionel Sambuc {
1205433d6423SLionel Sambuc if (debug) printf("skipping bar %d\n", pb_nr);
1206433d6423SLionel Sambuc continue; /* Skip */
1207433d6423SLionel Sambuc }
1208433d6423SLionel Sambuc if (i == j)
1209433d6423SLionel Sambuc {
1210433d6423SLionel Sambuc j++;
1211433d6423SLionel Sambuc continue; /* No need to copy */
1212433d6423SLionel Sambuc }
1213433d6423SLionel Sambuc pcidev[devind].pd_bar[j]=
1214433d6423SLionel Sambuc pcidev[devind].pd_bar[i];
1215433d6423SLionel Sambuc j++;
1216433d6423SLionel Sambuc }
1217433d6423SLionel Sambuc pcidev[devind].pd_bar_nr= j;
1218433d6423SLionel Sambuc }
1219433d6423SLionel Sambuc }
1220433d6423SLionel Sambuc
12216e7bb628SLionel Sambuc static void
record_bars_bridge(int devind)12226e7bb628SLionel Sambuc record_bars_bridge(int devind)
1223433d6423SLionel Sambuc {
1224433d6423SLionel Sambuc u32_t base, limit, size;
1225433d6423SLionel Sambuc
1226433d6423SLionel Sambuc /* The generic BAR area of PCI-to-PCI bridges is two DWORDs in size.
1227433d6423SLionel Sambuc * It may contain up to two 32-bit BARs, or one 64-bit BAR.
1228433d6423SLionel Sambuc */
1229433d6423SLionel Sambuc record_bars(devind, PCI_BAR_2);
1230433d6423SLionel Sambuc
12316e7bb628SLionel Sambuc base= ((__pci_attr_r8(devind, PPB_IOBASE) & PPB_IOB_MASK) << 8) |
12326e7bb628SLionel Sambuc (__pci_attr_r16(devind, PPB_IOBASEU16) << 16);
1233433d6423SLionel Sambuc limit= 0xff |
12346e7bb628SLionel Sambuc ((__pci_attr_r8(devind, PPB_IOLIMIT) & PPB_IOL_MASK) << 8) |
1235433d6423SLionel Sambuc ((~PPB_IOL_MASK & 0xff) << 8) |
12366e7bb628SLionel Sambuc (__pci_attr_r16(devind, PPB_IOLIMITU16) << 16);
1237433d6423SLionel Sambuc size= limit-base + 1;
1238433d6423SLionel Sambuc if (debug)
1239433d6423SLionel Sambuc {
1240433d6423SLionel Sambuc printf("\tI/O window: base 0x%x, limit 0x%x, size %d\n",
1241433d6423SLionel Sambuc base, limit, size);
1242433d6423SLionel Sambuc }
1243433d6423SLionel Sambuc
12446e7bb628SLionel Sambuc base= ((__pci_attr_r16(devind, PPB_MEMBASE) & PPB_MEMB_MASK) << 16);
1245433d6423SLionel Sambuc limit= 0xffff |
12466e7bb628SLionel Sambuc ((__pci_attr_r16(devind, PPB_MEMLIMIT) & PPB_MEML_MASK) << 16) |
1247433d6423SLionel Sambuc ((~PPB_MEML_MASK & 0xffff) << 16);
1248433d6423SLionel Sambuc size= limit-base + 1;
1249433d6423SLionel Sambuc if (debug)
1250433d6423SLionel Sambuc {
1251433d6423SLionel Sambuc printf("\tMemory window: base 0x%x, limit 0x%x, size 0x%x\n",
1252433d6423SLionel Sambuc base, limit, size);
1253433d6423SLionel Sambuc }
1254433d6423SLionel Sambuc
1255433d6423SLionel Sambuc /* Ignore the upper 32 bits */
12566e7bb628SLionel Sambuc base= ((__pci_attr_r16(devind, PPB_PFMEMBASE) & PPB_PFMEMB_MASK) << 16);
1257433d6423SLionel Sambuc limit= 0xffff |
12586e7bb628SLionel Sambuc ((__pci_attr_r16(devind, PPB_PFMEMLIMIT) &
1259433d6423SLionel Sambuc PPB_PFMEML_MASK) << 16) |
1260433d6423SLionel Sambuc ((~PPB_PFMEML_MASK & 0xffff) << 16);
1261433d6423SLionel Sambuc size= limit-base + 1;
1262433d6423SLionel Sambuc if (debug)
1263433d6423SLionel Sambuc {
1264433d6423SLionel Sambuc printf(
1265433d6423SLionel Sambuc "\tPrefetchable memory window: base 0x%x, limit 0x%x, size 0x%x\n",
1266433d6423SLionel Sambuc base, limit, size);
1267433d6423SLionel Sambuc }
1268433d6423SLionel Sambuc }
1269433d6423SLionel Sambuc
12706e7bb628SLionel Sambuc static void
record_bars_cardbus(int devind)12716e7bb628SLionel Sambuc record_bars_cardbus(int devind)
1272433d6423SLionel Sambuc {
1273433d6423SLionel Sambuc u32_t base, limit, size;
1274433d6423SLionel Sambuc
1275433d6423SLionel Sambuc /* The generic BAR area of CardBus devices is one DWORD in size. */
1276433d6423SLionel Sambuc record_bars(devind, PCI_BAR);
1277433d6423SLionel Sambuc
12786e7bb628SLionel Sambuc base= __pci_attr_r32(devind, CBB_MEMBASE_0);
12796e7bb628SLionel Sambuc limit= __pci_attr_r32(devind, CBB_MEMLIMIT_0) |
1280433d6423SLionel Sambuc (~CBB_MEML_MASK & 0xffffffff);
1281433d6423SLionel Sambuc size= limit-base + 1;
1282433d6423SLionel Sambuc if (debug)
1283433d6423SLionel Sambuc {
1284433d6423SLionel Sambuc printf("\tMemory window 0: base 0x%x, limit 0x%x, size %d\n",
1285433d6423SLionel Sambuc base, limit, size);
1286433d6423SLionel Sambuc }
1287433d6423SLionel Sambuc
12886e7bb628SLionel Sambuc base= __pci_attr_r32(devind, CBB_MEMBASE_1);
12896e7bb628SLionel Sambuc limit= __pci_attr_r32(devind, CBB_MEMLIMIT_1) |
1290433d6423SLionel Sambuc (~CBB_MEML_MASK & 0xffffffff);
1291433d6423SLionel Sambuc size= limit-base + 1;
1292433d6423SLionel Sambuc if (debug)
1293433d6423SLionel Sambuc {
1294433d6423SLionel Sambuc printf("\tMemory window 1: base 0x%x, limit 0x%x, size %d\n",
1295433d6423SLionel Sambuc base, limit, size);
1296433d6423SLionel Sambuc }
1297433d6423SLionel Sambuc
12986e7bb628SLionel Sambuc base= __pci_attr_r32(devind, CBB_IOBASE_0);
12996e7bb628SLionel Sambuc limit= __pci_attr_r32(devind, CBB_IOLIMIT_0) |
1300433d6423SLionel Sambuc (~CBB_IOL_MASK & 0xffffffff);
1301433d6423SLionel Sambuc size= limit-base + 1;
1302433d6423SLionel Sambuc if (debug)
1303433d6423SLionel Sambuc {
1304433d6423SLionel Sambuc printf("\tI/O window 0: base 0x%x, limit 0x%x, size %d\n",
1305433d6423SLionel Sambuc base, limit, size);
1306433d6423SLionel Sambuc }
1307433d6423SLionel Sambuc
13086e7bb628SLionel Sambuc base= __pci_attr_r32(devind, CBB_IOBASE_1);
13096e7bb628SLionel Sambuc limit= __pci_attr_r32(devind, CBB_IOLIMIT_1) |
1310433d6423SLionel Sambuc (~CBB_IOL_MASK & 0xffffffff);
1311433d6423SLionel Sambuc size= limit-base + 1;
1312433d6423SLionel Sambuc if (debug)
1313433d6423SLionel Sambuc {
1314433d6423SLionel Sambuc printf("\tI/O window 1: base 0x%x, limit 0x%x, size %d\n",
1315433d6423SLionel Sambuc base, limit, size);
1316433d6423SLionel Sambuc }
1317433d6423SLionel Sambuc }
1318433d6423SLionel Sambuc
13196e7bb628SLionel Sambuc static void
complete_bars(void)13206e7bb628SLionel Sambuc complete_bars(void)
1321433d6423SLionel Sambuc {
1322433d6423SLionel Sambuc int i, j, bar_nr, reg;
1323433d6423SLionel Sambuc u32_t memgap_low, memgap_high, iogap_low, iogap_high, io_high,
1324433d6423SLionel Sambuc base, size, v32, diff1, diff2;
1325433d6423SLionel Sambuc kinfo_t kinfo;
1326433d6423SLionel Sambuc
1327433d6423SLionel Sambuc if(OK != sys_getkinfo(&kinfo))
1328433d6423SLionel Sambuc panic("can't get kinfo");
1329433d6423SLionel Sambuc
1330433d6423SLionel Sambuc /* Set memgap_low to just above physical memory */
1331433d6423SLionel Sambuc memgap_low= kinfo.mem_high_phys;
1332433d6423SLionel Sambuc memgap_high= 0xfe000000; /* Leave space for the CPU (APIC) */
1333433d6423SLionel Sambuc
1334433d6423SLionel Sambuc if (debug)
1335433d6423SLionel Sambuc {
1336433d6423SLionel Sambuc printf("complete_bars: initial gap: [0x%x .. 0x%x>\n",
1337433d6423SLionel Sambuc memgap_low, memgap_high);
1338433d6423SLionel Sambuc }
1339433d6423SLionel Sambuc
1340433d6423SLionel Sambuc /* Find the lowest memory base */
1341433d6423SLionel Sambuc for (i= 0; i<nr_pcidev; i++)
1342433d6423SLionel Sambuc {
1343433d6423SLionel Sambuc for (j= 0; j<pcidev[i].pd_bar_nr; j++)
1344433d6423SLionel Sambuc {
1345433d6423SLionel Sambuc if (pcidev[i].pd_bar[j].pb_flags & PBF_IO)
1346433d6423SLionel Sambuc continue;
1347433d6423SLionel Sambuc if (pcidev[i].pd_bar[j].pb_flags & PBF_INCOMPLETE)
1348433d6423SLionel Sambuc continue;
1349433d6423SLionel Sambuc base= pcidev[i].pd_bar[j].pb_base;
1350433d6423SLionel Sambuc size= pcidev[i].pd_bar[j].pb_size;
1351433d6423SLionel Sambuc
1352433d6423SLionel Sambuc if (base >= memgap_high)
1353433d6423SLionel Sambuc continue; /* Not in the gap */
1354433d6423SLionel Sambuc if (base+size <= memgap_low)
1355433d6423SLionel Sambuc continue; /* Not in the gap */
1356433d6423SLionel Sambuc
1357433d6423SLionel Sambuc /* Reduce the gap by the smallest amount */
1358433d6423SLionel Sambuc diff1= base+size-memgap_low;
1359433d6423SLionel Sambuc diff2= memgap_high-base;
1360433d6423SLionel Sambuc
1361433d6423SLionel Sambuc if (diff1 < diff2)
1362433d6423SLionel Sambuc memgap_low= base+size;
1363433d6423SLionel Sambuc else
1364433d6423SLionel Sambuc memgap_high= base;
1365433d6423SLionel Sambuc }
1366433d6423SLionel Sambuc }
1367433d6423SLionel Sambuc
1368433d6423SLionel Sambuc if (debug)
1369433d6423SLionel Sambuc {
1370433d6423SLionel Sambuc printf("complete_bars: intermediate gap: [0x%x .. 0x%x>\n",
1371433d6423SLionel Sambuc memgap_low, memgap_high);
1372433d6423SLionel Sambuc }
1373433d6423SLionel Sambuc
1374433d6423SLionel Sambuc /* Should check main memory size */
1375433d6423SLionel Sambuc if (memgap_high < memgap_low)
1376433d6423SLionel Sambuc {
1377433d6423SLionel Sambuc printf("PCI: bad memory gap: [0x%x .. 0x%x>\n",
1378433d6423SLionel Sambuc memgap_low, memgap_high);
1379433d6423SLionel Sambuc panic(NULL);
1380433d6423SLionel Sambuc }
1381433d6423SLionel Sambuc
1382433d6423SLionel Sambuc iogap_high= 0x10000;
1383433d6423SLionel Sambuc iogap_low= 0x400;
1384433d6423SLionel Sambuc
1385433d6423SLionel Sambuc /* Find the free I/O space */
1386433d6423SLionel Sambuc for (i= 0; i<nr_pcidev; i++)
1387433d6423SLionel Sambuc {
1388433d6423SLionel Sambuc for (j= 0; j<pcidev[i].pd_bar_nr; j++)
1389433d6423SLionel Sambuc {
1390433d6423SLionel Sambuc if (!(pcidev[i].pd_bar[j].pb_flags & PBF_IO))
1391433d6423SLionel Sambuc continue;
1392433d6423SLionel Sambuc if (pcidev[i].pd_bar[j].pb_flags & PBF_INCOMPLETE)
1393433d6423SLionel Sambuc continue;
1394433d6423SLionel Sambuc base= pcidev[i].pd_bar[j].pb_base;
1395433d6423SLionel Sambuc size= pcidev[i].pd_bar[j].pb_size;
1396433d6423SLionel Sambuc if (base >= iogap_high)
1397433d6423SLionel Sambuc continue;
1398433d6423SLionel Sambuc if (base+size <= iogap_low)
1399433d6423SLionel Sambuc continue;
1400433d6423SLionel Sambuc #if 0
1401433d6423SLionel Sambuc if (debug)
1402433d6423SLionel Sambuc {
1403433d6423SLionel Sambuc printf(
1404433d6423SLionel Sambuc "pci device %d (%04x:%04x), bar %d: base 0x%x, size 0x%x\n",
1405433d6423SLionel Sambuc i, pcidev[i].pd_vid, pcidev[i].pd_did,
1406433d6423SLionel Sambuc j, base, size);
1407433d6423SLionel Sambuc }
1408433d6423SLionel Sambuc #endif
1409433d6423SLionel Sambuc if (base+size-iogap_low < iogap_high-base)
1410433d6423SLionel Sambuc iogap_low= base+size;
1411433d6423SLionel Sambuc else
1412433d6423SLionel Sambuc iogap_high= base;
1413433d6423SLionel Sambuc }
1414433d6423SLionel Sambuc }
1415433d6423SLionel Sambuc
1416433d6423SLionel Sambuc if (iogap_high < iogap_low)
1417433d6423SLionel Sambuc {
1418433d6423SLionel Sambuc if (debug)
1419433d6423SLionel Sambuc {
1420433d6423SLionel Sambuc printf("iogap_high too low, should panic\n");
1421433d6423SLionel Sambuc }
1422433d6423SLionel Sambuc else
1423433d6423SLionel Sambuc panic("iogap_high too low: %d", iogap_high);
1424433d6423SLionel Sambuc }
1425433d6423SLionel Sambuc if (debug)
1426433d6423SLionel Sambuc printf("I/O range = [0x%x..0x%x>\n", iogap_low, iogap_high);
1427433d6423SLionel Sambuc
1428433d6423SLionel Sambuc for (i= 0; i<nr_pcidev; i++)
1429433d6423SLionel Sambuc {
1430433d6423SLionel Sambuc for (j= 0; j<pcidev[i].pd_bar_nr; j++)
1431433d6423SLionel Sambuc {
1432433d6423SLionel Sambuc if (pcidev[i].pd_bar[j].pb_flags & PBF_IO)
1433433d6423SLionel Sambuc continue;
1434433d6423SLionel Sambuc if (!(pcidev[i].pd_bar[j].pb_flags & PBF_INCOMPLETE))
1435433d6423SLionel Sambuc continue;
1436433d6423SLionel Sambuc size= pcidev[i].pd_bar[j].pb_size;
1437433d6423SLionel Sambuc if (size < PAGE_SIZE)
1438433d6423SLionel Sambuc size= PAGE_SIZE;
1439433d6423SLionel Sambuc base= memgap_high-size;
1440433d6423SLionel Sambuc base &= ~(u32_t)(size-1);
1441433d6423SLionel Sambuc if (base < memgap_low)
1442433d6423SLionel Sambuc panic("memory base too low: %d", base);
1443433d6423SLionel Sambuc memgap_high= base;
1444433d6423SLionel Sambuc bar_nr= pcidev[i].pd_bar[j].pb_nr;
1445433d6423SLionel Sambuc reg= PCI_BAR + 4*bar_nr;
14466e7bb628SLionel Sambuc v32= __pci_attr_r32(i, reg);
14476e7bb628SLionel Sambuc __pci_attr_w32(i, reg, v32 | base);
1448433d6423SLionel Sambuc if (debug)
1449433d6423SLionel Sambuc {
1450433d6423SLionel Sambuc printf(
1451433d6423SLionel Sambuc "complete_bars: allocated 0x%x size %d to %d.%d.%d, bar_%d\n",
1452433d6423SLionel Sambuc base, size, pcidev[i].pd_busnr,
1453433d6423SLionel Sambuc pcidev[i].pd_dev, pcidev[i].pd_func,
1454433d6423SLionel Sambuc bar_nr);
1455433d6423SLionel Sambuc }
1456433d6423SLionel Sambuc pcidev[i].pd_bar[j].pb_base= base;
1457433d6423SLionel Sambuc pcidev[i].pd_bar[j].pb_flags &= ~PBF_INCOMPLETE;
1458433d6423SLionel Sambuc }
1459433d6423SLionel Sambuc
1460433d6423SLionel Sambuc io_high= iogap_high;
1461433d6423SLionel Sambuc for (j= 0; j<pcidev[i].pd_bar_nr; j++)
1462433d6423SLionel Sambuc {
1463433d6423SLionel Sambuc if (!(pcidev[i].pd_bar[j].pb_flags & PBF_IO))
1464433d6423SLionel Sambuc continue;
1465433d6423SLionel Sambuc if (!(pcidev[i].pd_bar[j].pb_flags & PBF_INCOMPLETE))
1466433d6423SLionel Sambuc continue;
1467433d6423SLionel Sambuc size= pcidev[i].pd_bar[j].pb_size;
1468433d6423SLionel Sambuc base= iogap_high-size;
1469433d6423SLionel Sambuc base &= ~(u32_t)(size-1);
1470433d6423SLionel Sambuc
1471433d6423SLionel Sambuc /* Assume that ISA compatibility is required. Only
1472433d6423SLionel Sambuc * use the lowest 256 bytes out of every 1024 bytes.
1473433d6423SLionel Sambuc */
1474433d6423SLionel Sambuc base &= 0xfcff;
1475433d6423SLionel Sambuc
1476433d6423SLionel Sambuc if (base < iogap_low)
14777171c232Srlfnb printf("I/O base too low: %d", base);
1478433d6423SLionel Sambuc
1479433d6423SLionel Sambuc iogap_high= base;
1480433d6423SLionel Sambuc bar_nr= pcidev[i].pd_bar[j].pb_nr;
1481433d6423SLionel Sambuc reg= PCI_BAR + 4*bar_nr;
14826e7bb628SLionel Sambuc v32= __pci_attr_r32(i, reg);
14836e7bb628SLionel Sambuc __pci_attr_w32(i, reg, v32 | base);
1484433d6423SLionel Sambuc if (debug)
1485433d6423SLionel Sambuc {
1486433d6423SLionel Sambuc printf(
1487433d6423SLionel Sambuc "complete_bars: allocated 0x%x size %d to %d.%d.%d, bar_%d\n",
1488433d6423SLionel Sambuc base, size, pcidev[i].pd_busnr,
1489433d6423SLionel Sambuc pcidev[i].pd_dev, pcidev[i].pd_func,
1490433d6423SLionel Sambuc bar_nr);
1491433d6423SLionel Sambuc }
1492433d6423SLionel Sambuc pcidev[i].pd_bar[j].pb_base= base;
1493433d6423SLionel Sambuc pcidev[i].pd_bar[j].pb_flags &= ~PBF_INCOMPLETE;
1494433d6423SLionel Sambuc
1495433d6423SLionel Sambuc }
1496433d6423SLionel Sambuc if (iogap_high != io_high)
1497433d6423SLionel Sambuc {
1498433d6423SLionel Sambuc update_bridge4dev_io(i, iogap_high,
1499433d6423SLionel Sambuc io_high-iogap_high);
1500433d6423SLionel Sambuc }
1501433d6423SLionel Sambuc }
1502433d6423SLionel Sambuc
1503433d6423SLionel Sambuc for (i= 0; i<nr_pcidev; i++)
1504433d6423SLionel Sambuc {
1505433d6423SLionel Sambuc for (j= 0; j<pcidev[i].pd_bar_nr; j++)
1506433d6423SLionel Sambuc {
1507433d6423SLionel Sambuc if (!(pcidev[i].pd_bar[j].pb_flags & PBF_INCOMPLETE))
1508433d6423SLionel Sambuc continue;
1509433d6423SLionel Sambuc printf("should allocate resources for device %d\n", i);
1510433d6423SLionel Sambuc }
1511433d6423SLionel Sambuc }
1512433d6423SLionel Sambuc return;
1513433d6423SLionel Sambuc }
1514433d6423SLionel Sambuc
1515433d6423SLionel Sambuc /*===========================================================================*
15166e7bb628SLionel Sambuc * PCI Bridge Helpers *
1517433d6423SLionel Sambuc *===========================================================================*/
15186e7bb628SLionel Sambuc static void
probe_bus(int busind)15196e7bb628SLionel Sambuc probe_bus(int busind)
1520433d6423SLionel Sambuc {
15210a6a1f1dSLionel Sambuc uint32_t dev, func;
15220a6a1f1dSLionel Sambuc #if 0
15230a6a1f1dSLionel Sambuc uint32_t t3;
15240a6a1f1dSLionel Sambuc #endif
15256e7bb628SLionel Sambuc u16_t vid, did, sts, sub_vid, sub_did;
15266e7bb628SLionel Sambuc u8_t headt;
15276e7bb628SLionel Sambuc u8_t baseclass, subclass, infclass;
15286e7bb628SLionel Sambuc int devind, busnr;
15296e7bb628SLionel Sambuc const char *s, *dstr;
1530433d6423SLionel Sambuc
15316e7bb628SLionel Sambuc if (debug)
15326e7bb628SLionel Sambuc printf("probe_bus(%d)\n", busind);
15336e7bb628SLionel Sambuc if (nr_pcidev >= NR_PCIDEV)
15346e7bb628SLionel Sambuc panic("too many PCI devices: %d", nr_pcidev);
15356e7bb628SLionel Sambuc devind= nr_pcidev;
15366e7bb628SLionel Sambuc
15376e7bb628SLionel Sambuc busnr= pcibus[busind].pb_busnr;
15386e7bb628SLionel Sambuc for (dev= 0; dev<32; dev++)
15396e7bb628SLionel Sambuc {
15406e7bb628SLionel Sambuc
15416e7bb628SLionel Sambuc for (func= 0; func < 8; func++)
15426e7bb628SLionel Sambuc {
15436e7bb628SLionel Sambuc pcidev[devind].pd_busnr= busnr;
15446e7bb628SLionel Sambuc pcidev[devind].pd_dev= dev;
15456e7bb628SLionel Sambuc pcidev[devind].pd_func= func;
15466e7bb628SLionel Sambuc
15476e7bb628SLionel Sambuc pci_attr_wsts(devind,
15486e7bb628SLionel Sambuc PSR_SSE|PSR_RMAS|PSR_RTAS);
15496e7bb628SLionel Sambuc vid= __pci_attr_r16(devind, PCI_VID);
15506e7bb628SLionel Sambuc did= __pci_attr_r16(devind, PCI_DID);
15516e7bb628SLionel Sambuc headt= __pci_attr_r8(devind, PCI_HEADT);
15526e7bb628SLionel Sambuc sts= pci_attr_rsts(devind);
15536e7bb628SLionel Sambuc
15546e7bb628SLionel Sambuc #if 0
15556e7bb628SLionel Sambuc printf("vid 0x%x, did 0x%x, headt 0x%x, sts 0x%x\n",
15566e7bb628SLionel Sambuc vid, did, headt, sts);
15576e7bb628SLionel Sambuc #endif
15586e7bb628SLionel Sambuc
15596e7bb628SLionel Sambuc if (vid == NO_VID && did == NO_VID)
15606e7bb628SLionel Sambuc {
15616e7bb628SLionel Sambuc if (func == 0)
15626e7bb628SLionel Sambuc break; /* Nothing here */
15636e7bb628SLionel Sambuc
15646e7bb628SLionel Sambuc /* Scan all functions of a multifunction
15656e7bb628SLionel Sambuc * device.
15666e7bb628SLionel Sambuc */
15676e7bb628SLionel Sambuc continue;
15686e7bb628SLionel Sambuc }
15696e7bb628SLionel Sambuc
15706e7bb628SLionel Sambuc if (sts & (PSR_SSE|PSR_RMAS|PSR_RTAS))
15716e7bb628SLionel Sambuc {
15726e7bb628SLionel Sambuc static int warned = 0;
15736e7bb628SLionel Sambuc
15746e7bb628SLionel Sambuc if(!warned) {
15756e7bb628SLionel Sambuc printf(
15766e7bb628SLionel Sambuc "PCI: ignoring bad value 0x%x in sts for QEMU\n",
15776e7bb628SLionel Sambuc sts & (PSR_SSE|PSR_RMAS|PSR_RTAS));
15786e7bb628SLionel Sambuc warned = 1;
15796e7bb628SLionel Sambuc }
15806e7bb628SLionel Sambuc }
15816e7bb628SLionel Sambuc
15826e7bb628SLionel Sambuc sub_vid= __pci_attr_r16(devind, PCI_SUBVID);
15836e7bb628SLionel Sambuc sub_did= __pci_attr_r16(devind, PCI_SUBDID);
15846e7bb628SLionel Sambuc
15856e7bb628SLionel Sambuc dstr= _pci_dev_name(vid, did);
15866e7bb628SLionel Sambuc if (debug)
15876e7bb628SLionel Sambuc {
15886e7bb628SLionel Sambuc if (dstr)
15896e7bb628SLionel Sambuc {
15906e7bb628SLionel Sambuc printf("%d.%lu.%lu: %s (%04X:%04X)\n",
15916e7bb628SLionel Sambuc busnr, (unsigned long)dev,
15926e7bb628SLionel Sambuc (unsigned long)func, dstr,
15936e7bb628SLionel Sambuc vid, did);
15946e7bb628SLionel Sambuc }
15956e7bb628SLionel Sambuc else
1596433d6423SLionel Sambuc {
1597433d6423SLionel Sambuc printf(
15986e7bb628SLionel Sambuc "%d.%lu.%lu: Unknown device, vendor %04X (%s), device %04X\n",
15996e7bb628SLionel Sambuc busnr, (unsigned long)dev,
16006e7bb628SLionel Sambuc (unsigned long)func, vid,
16016e7bb628SLionel Sambuc pci_vid_name(vid), did);
1602433d6423SLionel Sambuc }
16036e7bb628SLionel Sambuc printf("Device index: %d\n", devind);
16046e7bb628SLionel Sambuc printf("Subsystem: Vid 0x%x, did 0x%x\n",
16056e7bb628SLionel Sambuc sub_vid, sub_did);
16066e7bb628SLionel Sambuc }
1607433d6423SLionel Sambuc
16086e7bb628SLionel Sambuc baseclass= __pci_attr_r8(devind, PCI_BCR);
16096e7bb628SLionel Sambuc subclass= __pci_attr_r8(devind, PCI_SCR);
16106e7bb628SLionel Sambuc infclass= __pci_attr_r8(devind, PCI_PIFR);
16113641562fSLionel Sambuc s= pci_subclass_name(baseclass << 24 | subclass << 16);
16126e7bb628SLionel Sambuc if (!s)
16133641562fSLionel Sambuc s= pci_baseclass_name(baseclass << 24);
16146e7bb628SLionel Sambuc {
16156e7bb628SLionel Sambuc if (!s)
16166e7bb628SLionel Sambuc s= "(unknown class)";
16176e7bb628SLionel Sambuc }
1618433d6423SLionel Sambuc if (debug)
1619433d6423SLionel Sambuc {
16206e7bb628SLionel Sambuc printf("\tclass %s (%X/%X/%X)\n", s,
16216e7bb628SLionel Sambuc baseclass, subclass, infclass);
1622433d6423SLionel Sambuc }
1623433d6423SLionel Sambuc
16246e7bb628SLionel Sambuc if (is_duplicate(busnr, dev, func))
1625433d6423SLionel Sambuc {
16266e7bb628SLionel Sambuc printf("\tduplicate!\n");
16276e7bb628SLionel Sambuc if (func == 0 && !(headt & PHT_MULTIFUNC))
1628433d6423SLionel Sambuc break;
16296e7bb628SLionel Sambuc continue;
1630433d6423SLionel Sambuc }
1631433d6423SLionel Sambuc
16326e7bb628SLionel Sambuc devind= nr_pcidev;
16336e7bb628SLionel Sambuc nr_pcidev++;
16346e7bb628SLionel Sambuc pcidev[devind].pd_baseclass= baseclass;
16356e7bb628SLionel Sambuc pcidev[devind].pd_subclass= subclass;
16366e7bb628SLionel Sambuc pcidev[devind].pd_infclass= infclass;
16376e7bb628SLionel Sambuc pcidev[devind].pd_vid= vid;
16386e7bb628SLionel Sambuc pcidev[devind].pd_did= did;
16396e7bb628SLionel Sambuc pcidev[devind].pd_sub_vid= sub_vid;
16406e7bb628SLionel Sambuc pcidev[devind].pd_sub_did= sub_did;
16416e7bb628SLionel Sambuc pcidev[devind].pd_inuse= 0;
16426e7bb628SLionel Sambuc pcidev[devind].pd_bar_nr= 0;
16436e7bb628SLionel Sambuc record_irq(devind);
16446e7bb628SLionel Sambuc switch(headt & PHT_MASK)
1645433d6423SLionel Sambuc {
16466e7bb628SLionel Sambuc case PHT_NORMAL:
16476e7bb628SLionel Sambuc record_bars_normal(devind);
1648433d6423SLionel Sambuc break;
16496e7bb628SLionel Sambuc case PHT_BRIDGE:
16506e7bb628SLionel Sambuc record_bars_bridge(devind);
1651433d6423SLionel Sambuc break;
16526e7bb628SLionel Sambuc case PHT_CARDBUS:
16536e7bb628SLionel Sambuc record_bars_cardbus(devind);
1654433d6423SLionel Sambuc break;
1655433d6423SLionel Sambuc default:
16566e7bb628SLionel Sambuc printf("\t%d.%d.%d: unknown header type %d\n",
16576e7bb628SLionel Sambuc busind, dev, func,
16586e7bb628SLionel Sambuc headt & PHT_MASK);
16596e7bb628SLionel Sambuc break;
1660433d6423SLionel Sambuc }
16616e7bb628SLionel Sambuc if (debug)
16626e7bb628SLionel Sambuc print_capabilities(devind);
16636e7bb628SLionel Sambuc
16646e7bb628SLionel Sambuc #if 0
16650a6a1f1dSLionel Sambuc t3= ((baseclass << 16) | (subclass << 8) | infclass);
16666e7bb628SLionel Sambuc if (t3 == PCI_T3_VGA || t3 == PCI_T3_VGA_OLD)
16676e7bb628SLionel Sambuc report_vga(devind);
16686e7bb628SLionel Sambuc #endif
16696e7bb628SLionel Sambuc
16706e7bb628SLionel Sambuc if (nr_pcidev >= NR_PCIDEV)
16716e7bb628SLionel Sambuc panic("too many PCI devices: %d", nr_pcidev);
16726e7bb628SLionel Sambuc devind= nr_pcidev;
16736e7bb628SLionel Sambuc
16746e7bb628SLionel Sambuc if (func == 0 && !(headt & PHT_MULTIFUNC))
16756e7bb628SLionel Sambuc break;
16766e7bb628SLionel Sambuc }
16776e7bb628SLionel Sambuc }
1678433d6423SLionel Sambuc }
1679433d6423SLionel Sambuc
16806e7bb628SLionel Sambuc
16816e7bb628SLionel Sambuc static u16_t
pcibr_std_rsts(int busind)16826e7bb628SLionel Sambuc pcibr_std_rsts(int busind)
1683433d6423SLionel Sambuc {
16846e7bb628SLionel Sambuc int devind;
16856e7bb628SLionel Sambuc
16866e7bb628SLionel Sambuc devind= pcibus[busind].pb_devind;
16876e7bb628SLionel Sambuc return __pci_attr_r16(devind, PPB_SSTS);
1688433d6423SLionel Sambuc }
16896e7bb628SLionel Sambuc
16906e7bb628SLionel Sambuc static void
pcibr_std_wsts(int busind,u16_t value)16916e7bb628SLionel Sambuc pcibr_std_wsts(int busind, u16_t value)
16926e7bb628SLionel Sambuc {
16936e7bb628SLionel Sambuc int devind;
16946e7bb628SLionel Sambuc devind= pcibus[busind].pb_devind;
16956e7bb628SLionel Sambuc
16966e7bb628SLionel Sambuc #if 0
16976e7bb628SLionel Sambuc printf("pcibr_std_wsts(%d, 0x%X), devind= %d\n",
16986e7bb628SLionel Sambuc busind, value, devind);
16996e7bb628SLionel Sambuc #endif
17006e7bb628SLionel Sambuc __pci_attr_w16(devind, PPB_SSTS, value);
17016e7bb628SLionel Sambuc }
17026e7bb628SLionel Sambuc
17036e7bb628SLionel Sambuc static u16_t
pcibr_cb_rsts(int busind)17046e7bb628SLionel Sambuc pcibr_cb_rsts(int busind)
17056e7bb628SLionel Sambuc {
17066e7bb628SLionel Sambuc int devind;
17076e7bb628SLionel Sambuc devind= pcibus[busind].pb_devind;
17086e7bb628SLionel Sambuc
17096e7bb628SLionel Sambuc return __pci_attr_r16(devind, CBB_SSTS);
17106e7bb628SLionel Sambuc }
17116e7bb628SLionel Sambuc
17126e7bb628SLionel Sambuc static void
pcibr_cb_wsts(int busind,u16_t value)17136e7bb628SLionel Sambuc pcibr_cb_wsts(int busind, u16_t value)
17146e7bb628SLionel Sambuc {
17156e7bb628SLionel Sambuc int devind;
17166e7bb628SLionel Sambuc devind= pcibus[busind].pb_devind;
17176e7bb628SLionel Sambuc
17186e7bb628SLionel Sambuc #if 0
17196e7bb628SLionel Sambuc printf("pcibr_cb_wsts(%d, 0x%X), devind= %d\n",
17206e7bb628SLionel Sambuc busind, value, devind);
17216e7bb628SLionel Sambuc #endif
17226e7bb628SLionel Sambuc __pci_attr_w16(devind, CBB_SSTS, value);
17236e7bb628SLionel Sambuc }
17246e7bb628SLionel Sambuc
17256e7bb628SLionel Sambuc static u16_t
pcibr_via_rsts(int busind)17266e7bb628SLionel Sambuc pcibr_via_rsts(int busind)
17276e7bb628SLionel Sambuc {
1728433d6423SLionel Sambuc return 0;
1729433d6423SLionel Sambuc }
17306e7bb628SLionel Sambuc
17316e7bb628SLionel Sambuc static void
pcibr_via_wsts(int busind,u16_t value)17326e7bb628SLionel Sambuc pcibr_via_wsts(int busind, u16_t value)
17336e7bb628SLionel Sambuc {
17340a6a1f1dSLionel Sambuc #if 0
17356e7bb628SLionel Sambuc int devind;
17366e7bb628SLionel Sambuc devind= pcibus[busind].pb_devind;
17376e7bb628SLionel Sambuc
17386e7bb628SLionel Sambuc printf("pcibr_via_wsts(%d, 0x%X), devind= %d (not implemented)\n",
17396e7bb628SLionel Sambuc busind, value, devind);
17406e7bb628SLionel Sambuc #endif
17416e7bb628SLionel Sambuc }
17426e7bb628SLionel Sambuc
17436e7bb628SLionel Sambuc static void
complete_bridges(void)17446e7bb628SLionel Sambuc complete_bridges(void)
17456e7bb628SLionel Sambuc {
17466e7bb628SLionel Sambuc int i, freebus, devind, prim_busnr;
17476e7bb628SLionel Sambuc
17486e7bb628SLionel Sambuc for (i= 0; i<nr_pcibus; i++)
17496e7bb628SLionel Sambuc {
17506e7bb628SLionel Sambuc if (!pcibus[i].pb_needinit)
17516e7bb628SLionel Sambuc continue;
17526e7bb628SLionel Sambuc printf("should allocate bus number for bus %d\n", i);
17536e7bb628SLionel Sambuc freebus= get_freebus();
17546e7bb628SLionel Sambuc printf("got bus number %d\n", freebus);
17556e7bb628SLionel Sambuc
17566e7bb628SLionel Sambuc devind= pcibus[i].pb_devind;
17576e7bb628SLionel Sambuc
17586e7bb628SLionel Sambuc prim_busnr= pcidev[devind].pd_busnr;
17596e7bb628SLionel Sambuc if (prim_busnr != 0)
1760433d6423SLionel Sambuc {
1761433d6423SLionel Sambuc printf(
17626e7bb628SLionel Sambuc "complete_bridge: updating subordinate bus number not implemented\n");
1763433d6423SLionel Sambuc }
17646e7bb628SLionel Sambuc
17656e7bb628SLionel Sambuc pcibus[i].pb_needinit= 0;
17666e7bb628SLionel Sambuc pcibus[i].pb_busnr= freebus;
17676e7bb628SLionel Sambuc
17686e7bb628SLionel Sambuc printf("devind = %d\n", devind);
17696e7bb628SLionel Sambuc printf("prim_busnr= %d\n", prim_busnr);
17706e7bb628SLionel Sambuc
17716e7bb628SLionel Sambuc __pci_attr_w8(devind, PPB_PRIMBN, prim_busnr);
17726e7bb628SLionel Sambuc __pci_attr_w8(devind, PPB_SECBN, freebus);
17736e7bb628SLionel Sambuc __pci_attr_w8(devind, PPB_SUBORDBN, freebus);
17746e7bb628SLionel Sambuc
17756e7bb628SLionel Sambuc printf("CR = 0x%x\n", __pci_attr_r16(devind, PCI_CR));
17766e7bb628SLionel Sambuc printf("SECBLT = 0x%x\n", __pci_attr_r8(devind, PPB_SECBLT));
17776e7bb628SLionel Sambuc printf("BRIDGECTRL = 0x%x\n",
17786e7bb628SLionel Sambuc __pci_attr_r16(devind, PPB_BRIDGECTRL));
17796e7bb628SLionel Sambuc }
1780433d6423SLionel Sambuc }
1781433d6423SLionel Sambuc
17826e7bb628SLionel Sambuc static void
do_pcibridge(int busind)17836e7bb628SLionel Sambuc do_pcibridge(int busind)
1784433d6423SLionel Sambuc {
17853641562fSLionel Sambuc int devind, busnr;
1786433d6423SLionel Sambuc int ind, type;
1787433d6423SLionel Sambuc u16_t vid, did;
1788433d6423SLionel Sambuc u8_t sbusn, baseclass, subclass, infclass, headt;
1789433d6423SLionel Sambuc u32_t t3;
1790433d6423SLionel Sambuc
1791433d6423SLionel Sambuc vid= did= 0; /* lint */
1792433d6423SLionel Sambuc busnr= pcibus[busind].pb_busnr;
1793433d6423SLionel Sambuc for (devind= 0; devind< nr_pcidev; devind++)
1794433d6423SLionel Sambuc {
1795433d6423SLionel Sambuc if (pcidev[devind].pd_busnr != busnr)
1796433d6423SLionel Sambuc {
1797433d6423SLionel Sambuc #if 0
1798433d6423SLionel Sambuc printf("wrong bus\n");
1799433d6423SLionel Sambuc #endif
1800433d6423SLionel Sambuc continue;
1801433d6423SLionel Sambuc }
1802433d6423SLionel Sambuc
1803433d6423SLionel Sambuc vid= pcidev[devind].pd_vid;
1804433d6423SLionel Sambuc did= pcidev[devind].pd_did;
18053641562fSLionel Sambuc /* LSC: The table is empty, so always true...
18063641562fSLionel Sambuc if (pci_pcibridge[i].vid == 0) */
1807433d6423SLionel Sambuc {
18086e7bb628SLionel Sambuc headt= __pci_attr_r8(devind, PCI_HEADT);
1809433d6423SLionel Sambuc type= 0;
1810433d6423SLionel Sambuc if ((headt & PHT_MASK) == PHT_BRIDGE)
1811433d6423SLionel Sambuc type= PCI_PPB_STD;
1812433d6423SLionel Sambuc else if ((headt & PHT_MASK) == PHT_CARDBUS)
1813433d6423SLionel Sambuc type= PCI_PPB_CB;
1814433d6423SLionel Sambuc else
1815433d6423SLionel Sambuc {
1816433d6423SLionel Sambuc #if 0
1817433d6423SLionel Sambuc printf("not a bridge\n");
1818433d6423SLionel Sambuc #endif
1819433d6423SLionel Sambuc continue; /* Not a bridge */
1820433d6423SLionel Sambuc }
1821433d6423SLionel Sambuc
18226e7bb628SLionel Sambuc baseclass= __pci_attr_r8(devind, PCI_BCR);
18236e7bb628SLionel Sambuc subclass= __pci_attr_r8(devind, PCI_SCR);
18246e7bb628SLionel Sambuc infclass= __pci_attr_r8(devind, PCI_PIFR);
1825433d6423SLionel Sambuc t3= ((baseclass << 16) | (subclass << 8) | infclass);
1826433d6423SLionel Sambuc if (type == PCI_PPB_STD &&
1827433d6423SLionel Sambuc t3 != PCI_T3_PCI2PCI &&
1828433d6423SLionel Sambuc t3 != PCI_T3_PCI2PCI_SUBTR)
1829433d6423SLionel Sambuc {
1830433d6423SLionel Sambuc printf(
1831433d6423SLionel Sambuc "Unknown PCI class %02x/%02x/%02x for PCI-to-PCI bridge, device %04X:%04X\n",
1832433d6423SLionel Sambuc baseclass, subclass, infclass,
1833433d6423SLionel Sambuc vid, did);
1834433d6423SLionel Sambuc continue;
1835433d6423SLionel Sambuc }
1836433d6423SLionel Sambuc if (type == PCI_PPB_CB &&
1837433d6423SLionel Sambuc t3 != PCI_T3_CARDBUS)
1838433d6423SLionel Sambuc {
1839433d6423SLionel Sambuc printf(
1840433d6423SLionel Sambuc "Unknown PCI class %02x/%02x/%02x for Cardbus bridge, device %04X:%04X\n",
1841433d6423SLionel Sambuc baseclass, subclass, infclass,
1842433d6423SLionel Sambuc vid, did);
1843433d6423SLionel Sambuc continue;
1844433d6423SLionel Sambuc }
1845433d6423SLionel Sambuc }
1846433d6423SLionel Sambuc
1847433d6423SLionel Sambuc if (debug)
1848433d6423SLionel Sambuc {
1849433d6423SLionel Sambuc printf("%u.%u.%u: PCI-to-PCI bridge: %04X:%04X\n",
1850433d6423SLionel Sambuc pcidev[devind].pd_busnr,
1851433d6423SLionel Sambuc pcidev[devind].pd_dev,
1852433d6423SLionel Sambuc pcidev[devind].pd_func, vid, did);
1853433d6423SLionel Sambuc }
1854433d6423SLionel Sambuc
1855433d6423SLionel Sambuc /* Assume that the BIOS initialized the secondary bus
1856433d6423SLionel Sambuc * number.
1857433d6423SLionel Sambuc */
18586e7bb628SLionel Sambuc sbusn= __pci_attr_r8(devind, PPB_SECBN);
1859433d6423SLionel Sambuc
1860433d6423SLionel Sambuc if (nr_pcibus >= NR_PCIBUS)
1861433d6423SLionel Sambuc panic("too many PCI busses: %d", nr_pcibus);
1862433d6423SLionel Sambuc ind= nr_pcibus;
1863433d6423SLionel Sambuc nr_pcibus++;
1864433d6423SLionel Sambuc pcibus[ind].pb_type= PBT_PCIBRIDGE;
1865433d6423SLionel Sambuc pcibus[ind].pb_needinit= 1;
1866433d6423SLionel Sambuc pcibus[ind].pb_isabridge_dev= -1;
1867433d6423SLionel Sambuc pcibus[ind].pb_isabridge_type= 0;
1868433d6423SLionel Sambuc pcibus[ind].pb_devind= devind;
1869433d6423SLionel Sambuc pcibus[ind].pb_busnr= sbusn;
1870433d6423SLionel Sambuc pcibus[ind].pb_rreg8= pcibus[busind].pb_rreg8;
1871433d6423SLionel Sambuc pcibus[ind].pb_rreg16= pcibus[busind].pb_rreg16;
1872433d6423SLionel Sambuc pcibus[ind].pb_rreg32= pcibus[busind].pb_rreg32;
1873433d6423SLionel Sambuc pcibus[ind].pb_wreg8= pcibus[busind].pb_wreg8;
1874433d6423SLionel Sambuc pcibus[ind].pb_wreg16= pcibus[busind].pb_wreg16;
1875433d6423SLionel Sambuc pcibus[ind].pb_wreg32= pcibus[busind].pb_wreg32;
1876433d6423SLionel Sambuc switch(type)
1877433d6423SLionel Sambuc {
1878433d6423SLionel Sambuc case PCI_PPB_STD:
1879433d6423SLionel Sambuc pcibus[ind].pb_rsts= pcibr_std_rsts;
1880433d6423SLionel Sambuc pcibus[ind].pb_wsts= pcibr_std_wsts;
1881433d6423SLionel Sambuc break;
1882433d6423SLionel Sambuc case PCI_PPB_CB:
1883433d6423SLionel Sambuc pcibus[ind].pb_type= PBT_CARDBUS;
1884433d6423SLionel Sambuc pcibus[ind].pb_rsts= pcibr_cb_rsts;
1885433d6423SLionel Sambuc pcibus[ind].pb_wsts= pcibr_cb_wsts;
1886433d6423SLionel Sambuc break;
1887433d6423SLionel Sambuc case PCI_AGPB_VIA:
1888433d6423SLionel Sambuc pcibus[ind].pb_rsts= pcibr_via_rsts;
1889433d6423SLionel Sambuc pcibus[ind].pb_wsts= pcibr_via_wsts;
1890433d6423SLionel Sambuc break;
1891433d6423SLionel Sambuc default:
1892433d6423SLionel Sambuc panic("unknown PCI-PCI bridge type: %d", type);
1893433d6423SLionel Sambuc }
1894433d6423SLionel Sambuc
1895433d6423SLionel Sambuc if (machine.apic_enabled)
1896433d6423SLionel Sambuc acpi_map_bridge(pcidev[devind].pd_busnr,
1897433d6423SLionel Sambuc pcidev[devind].pd_dev, sbusn);
1898433d6423SLionel Sambuc
1899433d6423SLionel Sambuc if (debug)
1900433d6423SLionel Sambuc {
1901433d6423SLionel Sambuc printf(
1902433d6423SLionel Sambuc "bus(table) = %d, bus(sec) = %d, bus(subord) = %d\n",
19036e7bb628SLionel Sambuc ind, sbusn, __pci_attr_r8(devind, PPB_SUBORDBN));
1904433d6423SLionel Sambuc }
1905433d6423SLionel Sambuc if (sbusn == 0)
1906433d6423SLionel Sambuc {
1907433d6423SLionel Sambuc printf("Secondary bus number not initialized\n");
1908433d6423SLionel Sambuc continue;
1909433d6423SLionel Sambuc }
1910433d6423SLionel Sambuc pcibus[ind].pb_needinit= 0;
1911433d6423SLionel Sambuc
1912433d6423SLionel Sambuc probe_bus(ind);
1913433d6423SLionel Sambuc
1914433d6423SLionel Sambuc /* Look for PCI bridges */
1915433d6423SLionel Sambuc do_pcibridge(ind);
1916433d6423SLionel Sambuc }
1917433d6423SLionel Sambuc }
1918433d6423SLionel Sambuc
1919433d6423SLionel Sambuc /*===========================================================================*
19206e7bb628SLionel Sambuc * pci_intel_init *
1921433d6423SLionel Sambuc *===========================================================================*/
19226e7bb628SLionel Sambuc static void
pci_intel_init(void)19230a6a1f1dSLionel Sambuc pci_intel_init(void)
1924433d6423SLionel Sambuc {
19256e7bb628SLionel Sambuc /* Try to detect a know PCI controller. Read the Vendor ID and
19266e7bb628SLionel Sambuc * the Device ID for function 0 of device 0.
19276e7bb628SLionel Sambuc * Two times the value 0xffff suggests a system without a (compatible)
19286e7bb628SLionel Sambuc * PCI controller.
19296e7bb628SLionel Sambuc */
19306e7bb628SLionel Sambuc u32_t bus, dev, func;
19316e7bb628SLionel Sambuc u16_t vid, did;
19326e7bb628SLionel Sambuc int s, i, r, busind, busnr;
19336e7bb628SLionel Sambuc const char *dstr;
1934433d6423SLionel Sambuc
19356e7bb628SLionel Sambuc bus= 0;
19366e7bb628SLionel Sambuc dev= 0;
19376e7bb628SLionel Sambuc func= 0;
19386e7bb628SLionel Sambuc
19396e7bb628SLionel Sambuc vid= PCII_RREG16_(bus, dev, func, PCI_VID);
19406e7bb628SLionel Sambuc did= PCII_RREG16_(bus, dev, func, PCI_DID);
19416e7bb628SLionel Sambuc if (OK != (s=sys_outl(PCII_CONFADD, PCII_UNSEL)))
19426e7bb628SLionel Sambuc printf("PCI: warning, sys_outl failed: %d\n", s);
19436e7bb628SLionel Sambuc
19446e7bb628SLionel Sambuc if (nr_pcibus >= NR_PCIBUS)
19456e7bb628SLionel Sambuc panic("too many PCI busses: %d", nr_pcibus);
19466e7bb628SLionel Sambuc busind= nr_pcibus;
19476e7bb628SLionel Sambuc nr_pcibus++;
19486e7bb628SLionel Sambuc pcibus[busind].pb_type= PBT_INTEL_HOST;
19496e7bb628SLionel Sambuc pcibus[busind].pb_needinit= 0;
19506e7bb628SLionel Sambuc pcibus[busind].pb_isabridge_dev= -1;
19516e7bb628SLionel Sambuc pcibus[busind].pb_isabridge_type= 0;
19526e7bb628SLionel Sambuc pcibus[busind].pb_devind= -1;
19536e7bb628SLionel Sambuc pcibus[busind].pb_busnr= 0;
19546e7bb628SLionel Sambuc pcibus[busind].pb_rreg8= pcii_rreg8;
19556e7bb628SLionel Sambuc pcibus[busind].pb_rreg16= pcii_rreg16;
19566e7bb628SLionel Sambuc pcibus[busind].pb_rreg32= pcii_rreg32;
19576e7bb628SLionel Sambuc pcibus[busind].pb_wreg8= pcii_wreg8;
19586e7bb628SLionel Sambuc pcibus[busind].pb_wreg16= pcii_wreg16;
19596e7bb628SLionel Sambuc pcibus[busind].pb_wreg32= pcii_wreg32;
19606e7bb628SLionel Sambuc pcibus[busind].pb_rsts= pcii_rsts;
19616e7bb628SLionel Sambuc pcibus[busind].pb_wsts= pcii_wsts;
19626e7bb628SLionel Sambuc
19636e7bb628SLionel Sambuc dstr= _pci_dev_name(vid, did);
19646e7bb628SLionel Sambuc if (!dstr)
19656e7bb628SLionel Sambuc dstr= "unknown device";
1966433d6423SLionel Sambuc if (debug)
1967433d6423SLionel Sambuc {
19686e7bb628SLionel Sambuc printf("pci_intel_init: %s (%04X:%04X)\n",
19696e7bb628SLionel Sambuc dstr, vid, did);
1970433d6423SLionel Sambuc }
1971433d6423SLionel Sambuc
19726e7bb628SLionel Sambuc probe_bus(busind);
1973433d6423SLionel Sambuc
19746e7bb628SLionel Sambuc r= do_isabridge(busind);
19756e7bb628SLionel Sambuc if (r != OK)
19766e7bb628SLionel Sambuc {
19776e7bb628SLionel Sambuc busnr= pcibus[busind].pb_busnr;
1978433d6423SLionel Sambuc
19796e7bb628SLionel Sambuc /* Disable all devices for this bus */
19806e7bb628SLionel Sambuc for (i= 0; i<nr_pcidev; i++)
1981433d6423SLionel Sambuc {
19826e7bb628SLionel Sambuc if (pcidev[i].pd_busnr != busnr)
19836e7bb628SLionel Sambuc continue;
19846e7bb628SLionel Sambuc pcidev[i].pd_inuse= 1;
1985433d6423SLionel Sambuc }
19866e7bb628SLionel Sambuc return;
1987433d6423SLionel Sambuc }
1988433d6423SLionel Sambuc
19896e7bb628SLionel Sambuc /* Look for PCI bridges */
19906e7bb628SLionel Sambuc do_pcibridge(busind);
1991433d6423SLionel Sambuc
19926e7bb628SLionel Sambuc /* Allocate bus numbers for uninitialized bridges */
19936e7bb628SLionel Sambuc complete_bridges();
1994433d6423SLionel Sambuc
19956e7bb628SLionel Sambuc /* Allocate I/O and memory resources for uninitialized devices */
19966e7bb628SLionel Sambuc complete_bars();
1997433d6423SLionel Sambuc }
1998433d6423SLionel Sambuc
1999433d6423SLionel Sambuc #if 0
2000433d6423SLionel Sambuc /*===========================================================================*
2001433d6423SLionel Sambuc * report_vga *
2002433d6423SLionel Sambuc *===========================================================================*/
20036e7bb628SLionel Sambuc static void
20046e7bb628SLionel Sambuc report_vga(int devind)
2005433d6423SLionel Sambuc {
2006433d6423SLionel Sambuc /* Report the amount of video memory. This is needed by the X11R6
2007433d6423SLionel Sambuc * postinstall script to chmem the X server. Hopefully this can be
2008433d6423SLionel Sambuc * removed when we get virtual memory.
2009433d6423SLionel Sambuc */
2010433d6423SLionel Sambuc size_t amount, size;
2011433d6423SLionel Sambuc int i;
2012433d6423SLionel Sambuc
2013433d6423SLionel Sambuc amount= 0;
2014433d6423SLionel Sambuc for (i= 0; i<pcidev[devind].pd_bar_nr; i++)
2015433d6423SLionel Sambuc {
2016433d6423SLionel Sambuc if (pcidev[devind].pd_bar[i].pb_flags & PBF_IO)
2017433d6423SLionel Sambuc continue;
2018433d6423SLionel Sambuc size= pcidev[devind].pd_bar[i].pb_size;
2019433d6423SLionel Sambuc if (size < amount)
2020433d6423SLionel Sambuc continue;
2021433d6423SLionel Sambuc amount= size;
2022433d6423SLionel Sambuc }
2023433d6423SLionel Sambuc if (size != 0)
2024433d6423SLionel Sambuc {
2025433d6423SLionel Sambuc printf("PCI: video memory for device at %d.%d.%d: %d bytes\n",
2026433d6423SLionel Sambuc pcidev[devind].pd_busnr,
2027433d6423SLionel Sambuc pcidev[devind].pd_dev,
2028433d6423SLionel Sambuc pcidev[devind].pd_func,
2029433d6423SLionel Sambuc amount);
2030433d6423SLionel Sambuc }
2031433d6423SLionel Sambuc }
2032433d6423SLionel Sambuc #endif
2033433d6423SLionel Sambuc
2034433d6423SLionel Sambuc
2035433d6423SLionel Sambuc /*===========================================================================*
2036433d6423SLionel Sambuc * visible *
2037433d6423SLionel Sambuc *===========================================================================*/
20386e7bb628SLionel Sambuc static int
visible(struct rs_pci * aclp,int devind)20396e7bb628SLionel Sambuc visible(struct rs_pci *aclp, int devind)
2040433d6423SLionel Sambuc {
2041433d6423SLionel Sambuc u16_t acl_sub_vid, acl_sub_did;
2042433d6423SLionel Sambuc int i;
2043433d6423SLionel Sambuc u32_t class_id;
2044433d6423SLionel Sambuc
2045433d6423SLionel Sambuc if (!aclp)
2046433d6423SLionel Sambuc return TRUE; /* Should be changed when ACLs become
2047433d6423SLionel Sambuc * mandatory. Do note that procfs relies
2048433d6423SLionel Sambuc * on being able to see all devices.
2049433d6423SLionel Sambuc */
2050433d6423SLionel Sambuc /* Check whether the caller is allowed to get this device. */
2051433d6423SLionel Sambuc for (i= 0; i<aclp->rsp_nr_device; i++)
2052433d6423SLionel Sambuc {
2053433d6423SLionel Sambuc acl_sub_vid = aclp->rsp_device[i].sub_vid;
2054433d6423SLionel Sambuc acl_sub_did = aclp->rsp_device[i].sub_did;
2055433d6423SLionel Sambuc if (aclp->rsp_device[i].vid == pcidev[devind].pd_vid &&
2056433d6423SLionel Sambuc aclp->rsp_device[i].did == pcidev[devind].pd_did &&
2057433d6423SLionel Sambuc (acl_sub_vid == NO_SUB_VID ||
2058433d6423SLionel Sambuc acl_sub_vid == pcidev[devind].pd_sub_vid) &&
2059433d6423SLionel Sambuc (acl_sub_did == NO_SUB_DID ||
2060433d6423SLionel Sambuc acl_sub_did == pcidev[devind].pd_sub_did))
2061433d6423SLionel Sambuc {
2062433d6423SLionel Sambuc return TRUE;
2063433d6423SLionel Sambuc }
2064433d6423SLionel Sambuc }
2065433d6423SLionel Sambuc if (!aclp->rsp_nr_class)
2066433d6423SLionel Sambuc return FALSE;
2067433d6423SLionel Sambuc
2068433d6423SLionel Sambuc class_id= (pcidev[devind].pd_baseclass << 16) |
2069433d6423SLionel Sambuc (pcidev[devind].pd_subclass << 8) |
2070433d6423SLionel Sambuc pcidev[devind].pd_infclass;
2071433d6423SLionel Sambuc for (i= 0; i<aclp->rsp_nr_class; i++)
2072433d6423SLionel Sambuc {
2073433d6423SLionel Sambuc if (aclp->rsp_class[i].pciclass ==
2074433d6423SLionel Sambuc (class_id & aclp->rsp_class[i].mask))
2075433d6423SLionel Sambuc {
2076433d6423SLionel Sambuc return TRUE;
2077433d6423SLionel Sambuc }
2078433d6423SLionel Sambuc }
2079433d6423SLionel Sambuc
2080433d6423SLionel Sambuc return FALSE;
2081433d6423SLionel Sambuc }
2082433d6423SLionel Sambuc
2083433d6423SLionel Sambuc /*===========================================================================*
20846e7bb628SLionel Sambuc * sef_cb_init_fresh *
2085433d6423SLionel Sambuc *===========================================================================*/
20866e7bb628SLionel Sambuc int
sef_cb_init(int type,sef_init_info_t * info)20875d831176SLionel Sambuc sef_cb_init(int type, sef_init_info_t *info)
2088433d6423SLionel Sambuc {
20895d831176SLionel Sambuc /* Initialize the driver. */
20905d831176SLionel Sambuc int do_announce_driver = -1;
20915d831176SLionel Sambuc
20926e7bb628SLionel Sambuc long v;
20936e7bb628SLionel Sambuc int i, r;
20946e7bb628SLionel Sambuc struct rprocpub rprocpub[NR_BOOT_PROCS];
2095433d6423SLionel Sambuc
20966e7bb628SLionel Sambuc v= 0;
20976e7bb628SLionel Sambuc env_parse("pci_debug", "d", 0, &v, 0, 1);
20986e7bb628SLionel Sambuc debug= v;
20996e7bb628SLionel Sambuc
21006e7bb628SLionel Sambuc if (sys_getmachine(&machine)) {
21016e7bb628SLionel Sambuc printf("PCI: no machine\n");
21026e7bb628SLionel Sambuc return ENODEV;
21036e7bb628SLionel Sambuc }
21046e7bb628SLionel Sambuc if (machine.apic_enabled &&
2105*fee60e45Srlfnb acpi_init() != OK) {
21066e7bb628SLionel Sambuc panic("PCI: Cannot use APIC mode without ACPI!\n");
21076e7bb628SLionel Sambuc }
21086e7bb628SLionel Sambuc
21096e7bb628SLionel Sambuc /* Only Intel (compatible) PCI controllers are supported at the
21106e7bb628SLionel Sambuc * moment.
21116e7bb628SLionel Sambuc */
21126e7bb628SLionel Sambuc pci_intel_init();
21136e7bb628SLionel Sambuc
21146e7bb628SLionel Sambuc /* Map all the services in the boot image. */
21156e7bb628SLionel Sambuc if ((r = sys_safecopyfrom(RS_PROC_NR, info->rproctab_gid, 0,
21166e7bb628SLionel Sambuc (vir_bytes) rprocpub, sizeof(rprocpub))) != OK) {
21176e7bb628SLionel Sambuc panic("sys_safecopyfrom failed: %d", r);
21186e7bb628SLionel Sambuc }
21196e7bb628SLionel Sambuc for(i=0;i < NR_BOOT_PROCS;i++) {
21206e7bb628SLionel Sambuc if (rprocpub[i].in_use) {
21216e7bb628SLionel Sambuc if ((r = map_service(&rprocpub[i])) != OK) {
21226e7bb628SLionel Sambuc panic("unable to map service: %d", r);
21236e7bb628SLionel Sambuc }
21246e7bb628SLionel Sambuc }
21256e7bb628SLionel Sambuc }
21266e7bb628SLionel Sambuc
21275d831176SLionel Sambuc switch(type) {
21285d831176SLionel Sambuc case SEF_INIT_FRESH:
21295d831176SLionel Sambuc case SEF_INIT_RESTART:
21305d831176SLionel Sambuc do_announce_driver = TRUE;
21315d831176SLionel Sambuc break;
21325d831176SLionel Sambuc case SEF_INIT_LU:
21335d831176SLionel Sambuc do_announce_driver = FALSE;
21345d831176SLionel Sambuc break;
21355d831176SLionel Sambuc default:
21365d831176SLionel Sambuc panic("Unknown type of restart");
21375d831176SLionel Sambuc break;
21385d831176SLionel Sambuc }
21395d831176SLionel Sambuc
21405d831176SLionel Sambuc /* Announce we are up when necessary. */
21415d831176SLionel Sambuc if (TRUE == do_announce_driver) {
21425d831176SLionel Sambuc chardriver_announce();
21435d831176SLionel Sambuc }
21445d831176SLionel Sambuc
21455d831176SLionel Sambuc /* Initialization completed successfully. */
21465d831176SLionel Sambuc return OK;
21476e7bb628SLionel Sambuc }
21486e7bb628SLionel Sambuc
21496e7bb628SLionel Sambuc /*===========================================================================*
21506e7bb628SLionel Sambuc * map_service *
21516e7bb628SLionel Sambuc *===========================================================================*/
21526e7bb628SLionel Sambuc int
map_service(struct rprocpub * rpub)21536e7bb628SLionel Sambuc map_service(struct rprocpub *rpub)
21546e7bb628SLionel Sambuc {
21556e7bb628SLionel Sambuc /* Map a new service by registering a new acl entry if required. */
21566e7bb628SLionel Sambuc int i;
21576e7bb628SLionel Sambuc
21586e7bb628SLionel Sambuc /* Stop right now if no pci device or class is found. */
21596e7bb628SLionel Sambuc if(rpub->pci_acl.rsp_nr_device == 0
21606e7bb628SLionel Sambuc && rpub->pci_acl.rsp_nr_class == 0) {
21616e7bb628SLionel Sambuc return(OK);
21626e7bb628SLionel Sambuc }
21636e7bb628SLionel Sambuc
21646e7bb628SLionel Sambuc /* Find a free acl slot. */
21656e7bb628SLionel Sambuc for (i= 0; i<NR_DRIVERS; i++)
21666e7bb628SLionel Sambuc {
21676e7bb628SLionel Sambuc if (!pci_acl[i].inuse)
21686e7bb628SLionel Sambuc break;
21696e7bb628SLionel Sambuc }
21706e7bb628SLionel Sambuc if (i >= NR_DRIVERS)
21716e7bb628SLionel Sambuc {
21726e7bb628SLionel Sambuc printf("PCI: map_service: table is full\n");
21736e7bb628SLionel Sambuc return ENOMEM;
21746e7bb628SLionel Sambuc }
21756e7bb628SLionel Sambuc
21766e7bb628SLionel Sambuc /* Initialize acl slot. */
21776e7bb628SLionel Sambuc pci_acl[i].inuse = 1;
21786e7bb628SLionel Sambuc pci_acl[i].acl = rpub->pci_acl;
21796e7bb628SLionel Sambuc
21805d831176SLionel Sambuc return OK;
21816e7bb628SLionel Sambuc }
21826e7bb628SLionel Sambuc
21836e7bb628SLionel Sambuc /*===========================================================================*
21846e7bb628SLionel Sambuc * _pci_find_dev *
21856e7bb628SLionel Sambuc *===========================================================================*/
21866e7bb628SLionel Sambuc int
_pci_find_dev(u8_t bus,u8_t dev,u8_t func,int * devindp)21876e7bb628SLionel Sambuc _pci_find_dev(u8_t bus, u8_t dev, u8_t func, int *devindp)
21886e7bb628SLionel Sambuc {
21896e7bb628SLionel Sambuc int devind;
21906e7bb628SLionel Sambuc
21916e7bb628SLionel Sambuc for (devind= 0; devind < nr_pcidev; devind++)
21926e7bb628SLionel Sambuc {
21936e7bb628SLionel Sambuc if (pcidev[devind].pd_busnr == bus &&
21946e7bb628SLionel Sambuc pcidev[devind].pd_dev == dev &&
21956e7bb628SLionel Sambuc pcidev[devind].pd_func == func)
21966e7bb628SLionel Sambuc {
21976e7bb628SLionel Sambuc break;
21986e7bb628SLionel Sambuc }
21996e7bb628SLionel Sambuc }
22005d831176SLionel Sambuc
22016e7bb628SLionel Sambuc if (devind >= nr_pcidev)
22026e7bb628SLionel Sambuc return 0;
22035d831176SLionel Sambuc
22046e7bb628SLionel Sambuc *devindp= devind;
22055d831176SLionel Sambuc
22066e7bb628SLionel Sambuc return 1;
22076e7bb628SLionel Sambuc }
22086e7bb628SLionel Sambuc
22096e7bb628SLionel Sambuc /*===========================================================================*
22106e7bb628SLionel Sambuc * _pci_first_dev *
22116e7bb628SLionel Sambuc *===========================================================================*/
22126e7bb628SLionel Sambuc int
_pci_first_dev(struct rs_pci * aclp,int * devindp,u16_t * vidp,u16_t * didp)22136e7bb628SLionel Sambuc _pci_first_dev(struct rs_pci *aclp, int *devindp, u16_t *vidp,
22146e7bb628SLionel Sambuc u16_t *didp)
2215433d6423SLionel Sambuc {
22166e7bb628SLionel Sambuc int devind;
22176e7bb628SLionel Sambuc
22186e7bb628SLionel Sambuc for (devind= 0; devind < nr_pcidev; devind++)
22196e7bb628SLionel Sambuc {
22206e7bb628SLionel Sambuc if (!visible(aclp, devind))
22216e7bb628SLionel Sambuc continue;
22226e7bb628SLionel Sambuc break;
22236e7bb628SLionel Sambuc }
22246e7bb628SLionel Sambuc if (devind >= nr_pcidev)
22256e7bb628SLionel Sambuc return 0;
22266e7bb628SLionel Sambuc *devindp= devind;
22276e7bb628SLionel Sambuc *vidp= pcidev[devind].pd_vid;
22286e7bb628SLionel Sambuc *didp= pcidev[devind].pd_did;
22296e7bb628SLionel Sambuc return 1;
22306e7bb628SLionel Sambuc }
22316e7bb628SLionel Sambuc
22326e7bb628SLionel Sambuc /*===========================================================================*
22336e7bb628SLionel Sambuc * _pci_next_dev *
22346e7bb628SLionel Sambuc *===========================================================================*/
22356e7bb628SLionel Sambuc int
_pci_next_dev(struct rs_pci * aclp,int * devindp,u16_t * vidp,u16_t * didp)22366e7bb628SLionel Sambuc _pci_next_dev(struct rs_pci *aclp, int *devindp, u16_t *vidp, u16_t *didp)
22376e7bb628SLionel Sambuc {
22386e7bb628SLionel Sambuc int devind;
22396e7bb628SLionel Sambuc
22406e7bb628SLionel Sambuc for (devind= *devindp+1; devind < nr_pcidev; devind++)
22416e7bb628SLionel Sambuc {
22426e7bb628SLionel Sambuc if (!visible(aclp, devind))
22436e7bb628SLionel Sambuc continue;
22446e7bb628SLionel Sambuc break;
22456e7bb628SLionel Sambuc }
22466e7bb628SLionel Sambuc if (devind >= nr_pcidev)
22476e7bb628SLionel Sambuc return 0;
22486e7bb628SLionel Sambuc *devindp= devind;
22496e7bb628SLionel Sambuc *vidp= pcidev[devind].pd_vid;
22506e7bb628SLionel Sambuc *didp= pcidev[devind].pd_did;
22516e7bb628SLionel Sambuc return 1;
22526e7bb628SLionel Sambuc }
22536e7bb628SLionel Sambuc
22546e7bb628SLionel Sambuc /*===========================================================================*
22555d831176SLionel Sambuc * _pci_grant_access *
22566e7bb628SLionel Sambuc *===========================================================================*/
22576e7bb628SLionel Sambuc int
_pci_grant_access(int devind,endpoint_t proc)22585d831176SLionel Sambuc _pci_grant_access(int devind, endpoint_t proc)
22596e7bb628SLionel Sambuc {
22605d831176SLionel Sambuc int i, ilr;
22615d831176SLionel Sambuc int r = OK;
22626e7bb628SLionel Sambuc struct io_range ior;
22636e7bb628SLionel Sambuc struct minix_mem_range mr;
22646e7bb628SLionel Sambuc
22656e7bb628SLionel Sambuc for (i= 0; i<pcidev[devind].pd_bar_nr; i++)
22666e7bb628SLionel Sambuc {
22676e7bb628SLionel Sambuc if (pcidev[devind].pd_bar[i].pb_flags & PBF_INCOMPLETE)
22686e7bb628SLionel Sambuc {
22696e7bb628SLionel Sambuc printf("pci_reserve_a: BAR %d is incomplete\n", i);
22706e7bb628SLionel Sambuc continue;
22716e7bb628SLionel Sambuc }
22726e7bb628SLionel Sambuc if (pcidev[devind].pd_bar[i].pb_flags & PBF_IO)
22736e7bb628SLionel Sambuc {
22746e7bb628SLionel Sambuc ior.ior_base= pcidev[devind].pd_bar[i].pb_base;
22756e7bb628SLionel Sambuc ior.ior_limit= ior.ior_base +
22766e7bb628SLionel Sambuc pcidev[devind].pd_bar[i].pb_size-1;
22776e7bb628SLionel Sambuc
22786e7bb628SLionel Sambuc if(debug) {
22796e7bb628SLionel Sambuc printf(
22806e7bb628SLionel Sambuc "pci_reserve_a: for proc %d, adding I/O range [0x%x..0x%x]\n",
22816e7bb628SLionel Sambuc proc, ior.ior_base, ior.ior_limit);
22826e7bb628SLionel Sambuc }
22836e7bb628SLionel Sambuc r= sys_privctl(proc, SYS_PRIV_ADD_IO, &ior);
22846e7bb628SLionel Sambuc if (r != OK)
22856e7bb628SLionel Sambuc {
22866e7bb628SLionel Sambuc printf("sys_privctl failed for proc %d: %d\n",
22876e7bb628SLionel Sambuc proc, r);
22886e7bb628SLionel Sambuc }
2289433d6423SLionel Sambuc }
2290433d6423SLionel Sambuc else
2291433d6423SLionel Sambuc {
22926e7bb628SLionel Sambuc mr.mr_base= pcidev[devind].pd_bar[i].pb_base;
22936e7bb628SLionel Sambuc mr.mr_limit= mr.mr_base +
22946e7bb628SLionel Sambuc pcidev[devind].pd_bar[i].pb_size-1;
2295433d6423SLionel Sambuc
22966e7bb628SLionel Sambuc r= sys_privctl(proc, SYS_PRIV_ADD_MEM, &mr);
22976e7bb628SLionel Sambuc if (r != OK)
22986e7bb628SLionel Sambuc {
22996e7bb628SLionel Sambuc printf("sys_privctl failed for proc %d: %d\n",
23006e7bb628SLionel Sambuc proc, r);
23016e7bb628SLionel Sambuc }
23026e7bb628SLionel Sambuc }
23036e7bb628SLionel Sambuc }
23046e7bb628SLionel Sambuc ilr= pcidev[devind].pd_ilr;
23056e7bb628SLionel Sambuc if (ilr != PCI_ILR_UNKNOWN)
23066e7bb628SLionel Sambuc {
23076e7bb628SLionel Sambuc if(debug) printf("pci_reserve_a: adding IRQ %d\n", ilr);
23086e7bb628SLionel Sambuc r= sys_privctl(proc, SYS_PRIV_ADD_IRQ, &ilr);
23096e7bb628SLionel Sambuc if (r != OK)
23106e7bb628SLionel Sambuc {
23116e7bb628SLionel Sambuc printf("sys_privctl failed for proc %d: %d\n",
23126e7bb628SLionel Sambuc proc, r);
23136e7bb628SLionel Sambuc }
2314433d6423SLionel Sambuc }
2315433d6423SLionel Sambuc
23165d831176SLionel Sambuc return r;
23175d831176SLionel Sambuc }
23185d831176SLionel Sambuc
23195d831176SLionel Sambuc /*===========================================================================*
23205d831176SLionel Sambuc * _pci_reserve *
23215d831176SLionel Sambuc *===========================================================================*/
23225d831176SLionel Sambuc int
_pci_reserve(int devind,endpoint_t proc,struct rs_pci * aclp)23235d831176SLionel Sambuc _pci_reserve(int devind, endpoint_t proc, struct rs_pci *aclp)
23245d831176SLionel Sambuc {
23255d831176SLionel Sambuc if (devind < 0 || devind >= nr_pcidev)
23265d831176SLionel Sambuc {
23275d831176SLionel Sambuc printf("pci_reserve_a: bad devind: %d\n", devind);
23285d831176SLionel Sambuc return EINVAL;
23295d831176SLionel Sambuc }
23305d831176SLionel Sambuc if (!visible(aclp, devind))
23315d831176SLionel Sambuc {
23325d831176SLionel Sambuc printf("pci_reserve_a: %u is not allowed to reserve %d\n",
23335d831176SLionel Sambuc proc, devind);
23345d831176SLionel Sambuc return EPERM;
23355d831176SLionel Sambuc }
23365d831176SLionel Sambuc
23375d831176SLionel Sambuc if(pcidev[devind].pd_inuse && pcidev[devind].pd_proc != proc)
23385d831176SLionel Sambuc return EBUSY;
23395d831176SLionel Sambuc
23405d831176SLionel Sambuc pcidev[devind].pd_inuse= 1;
23415d831176SLionel Sambuc pcidev[devind].pd_proc= proc;
23425d831176SLionel Sambuc
23435d831176SLionel Sambuc return _pci_grant_access(devind, proc);
23446e7bb628SLionel Sambuc }
23456e7bb628SLionel Sambuc
23466e7bb628SLionel Sambuc /*===========================================================================*
23476e7bb628SLionel Sambuc * _pci_release *
23486e7bb628SLionel Sambuc *===========================================================================*/
23496e7bb628SLionel Sambuc void
_pci_release(endpoint_t proc)23506e7bb628SLionel Sambuc _pci_release(endpoint_t proc)
23516e7bb628SLionel Sambuc {
23526e7bb628SLionel Sambuc int i;
23536e7bb628SLionel Sambuc
23546e7bb628SLionel Sambuc for (i= 0; i<nr_pcidev; i++)
23556e7bb628SLionel Sambuc {
23566e7bb628SLionel Sambuc if (!pcidev[i].pd_inuse)
23576e7bb628SLionel Sambuc continue;
23586e7bb628SLionel Sambuc if (pcidev[i].pd_proc != proc)
23596e7bb628SLionel Sambuc continue;
23606e7bb628SLionel Sambuc pcidev[i].pd_inuse= 0;
23616e7bb628SLionel Sambuc }
23626e7bb628SLionel Sambuc }
23636e7bb628SLionel Sambuc
23646e7bb628SLionel Sambuc /*===========================================================================*
23656e7bb628SLionel Sambuc * _pci_ids *
23666e7bb628SLionel Sambuc *===========================================================================*/
23676e7bb628SLionel Sambuc int
_pci_ids(int devind,u16_t * vidp,u16_t * didp)23686e7bb628SLionel Sambuc _pci_ids(int devind, u16_t *vidp, u16_t *didp)
23696e7bb628SLionel Sambuc {
23706e7bb628SLionel Sambuc if (devind < 0 || devind >= nr_pcidev)
23716e7bb628SLionel Sambuc return EINVAL;
23726e7bb628SLionel Sambuc
23736e7bb628SLionel Sambuc *vidp= pcidev[devind].pd_vid;
23746e7bb628SLionel Sambuc *didp= pcidev[devind].pd_did;
23756e7bb628SLionel Sambuc return OK;
23766e7bb628SLionel Sambuc }
23776e7bb628SLionel Sambuc
23786e7bb628SLionel Sambuc /*===========================================================================*
23796e7bb628SLionel Sambuc * _pci_rescan_bus *
23806e7bb628SLionel Sambuc *===========================================================================*/
23816e7bb628SLionel Sambuc void
_pci_rescan_bus(u8_t busnr)23826e7bb628SLionel Sambuc _pci_rescan_bus(u8_t busnr)
23836e7bb628SLionel Sambuc {
23846e7bb628SLionel Sambuc int busind;
23856e7bb628SLionel Sambuc
23866e7bb628SLionel Sambuc busind= get_busind(busnr);
23876e7bb628SLionel Sambuc probe_bus(busind);
23886e7bb628SLionel Sambuc
23896e7bb628SLionel Sambuc /* Allocate bus numbers for uninitialized bridges */
23906e7bb628SLionel Sambuc complete_bridges();
23916e7bb628SLionel Sambuc
23926e7bb628SLionel Sambuc /* Allocate I/O and memory resources for uninitialized devices */
23936e7bb628SLionel Sambuc complete_bars();
23946e7bb628SLionel Sambuc }
23956e7bb628SLionel Sambuc
23966e7bb628SLionel Sambuc /*===========================================================================*
23976e7bb628SLionel Sambuc * _pci_slot_name *
23986e7bb628SLionel Sambuc *===========================================================================*/
23996e7bb628SLionel Sambuc int
_pci_slot_name(int devind,char ** cpp)24006e7bb628SLionel Sambuc _pci_slot_name(int devind, char **cpp)
24016e7bb628SLionel Sambuc {
24026e7bb628SLionel Sambuc static char label[]= "ddd.ddd.ddd.ddd";
24036e7bb628SLionel Sambuc char *end;
24046e7bb628SLionel Sambuc char *p;
24056e7bb628SLionel Sambuc
24066e7bb628SLionel Sambuc if (devind < 0 || devind >= nr_pcidev)
24076e7bb628SLionel Sambuc return EINVAL;
24086e7bb628SLionel Sambuc
24096e7bb628SLionel Sambuc p= label;
24106e7bb628SLionel Sambuc end= label+sizeof(label);
24116e7bb628SLionel Sambuc
24126e7bb628SLionel Sambuc /* FIXME: domain nb is always 0 on 32bit system, but we should
24136e7bb628SLionel Sambuc * retrieve it properly, somehow. */
24146e7bb628SLionel Sambuc ntostr(0, &p, end);
24156e7bb628SLionel Sambuc *p++= '.';
24166e7bb628SLionel Sambuc
24176e7bb628SLionel Sambuc ntostr(pcidev[devind].pd_busnr, &p, end);
24186e7bb628SLionel Sambuc *p++= '.';
24196e7bb628SLionel Sambuc
24206e7bb628SLionel Sambuc ntostr(pcidev[devind].pd_dev, &p, end);
24216e7bb628SLionel Sambuc *p++= '.';
24226e7bb628SLionel Sambuc
24236e7bb628SLionel Sambuc ntostr(pcidev[devind].pd_func, &p, end);
24246e7bb628SLionel Sambuc
24256e7bb628SLionel Sambuc *cpp= label;
24266e7bb628SLionel Sambuc return OK;
24276e7bb628SLionel Sambuc }
24286e7bb628SLionel Sambuc
24296e7bb628SLionel Sambuc /*===========================================================================*
24306e7bb628SLionel Sambuc * _pci_dev_name *
24316e7bb628SLionel Sambuc *===========================================================================*/
24326e7bb628SLionel Sambuc const char *
_pci_dev_name(u16_t vid,u16_t did)24336e7bb628SLionel Sambuc _pci_dev_name(u16_t vid, u16_t did)
24346e7bb628SLionel Sambuc {
24350a6a1f1dSLionel Sambuc static char product[PCI_PRODUCTSTR_LEN];
24360a6a1f1dSLionel Sambuc pci_findproduct(product, sizeof(product), vid, did);
24370a6a1f1dSLionel Sambuc return product;
24386e7bb628SLionel Sambuc }
24396e7bb628SLionel Sambuc
24406e7bb628SLionel Sambuc /*===========================================================================*
24416e7bb628SLionel Sambuc * _pci_get_bar *
24426e7bb628SLionel Sambuc *===========================================================================*/
24436e7bb628SLionel Sambuc int
_pci_get_bar(int devind,int port,u32_t * base,u32_t * size,int * ioflag)24446e7bb628SLionel Sambuc _pci_get_bar(int devind, int port, u32_t *base, u32_t *size,
24456e7bb628SLionel Sambuc int *ioflag)
24466e7bb628SLionel Sambuc {
24476e7bb628SLionel Sambuc int i, reg;
24486e7bb628SLionel Sambuc
24496e7bb628SLionel Sambuc if (devind < 0 || devind >= nr_pcidev)
24506e7bb628SLionel Sambuc return EINVAL;
24516e7bb628SLionel Sambuc
24526e7bb628SLionel Sambuc for (i= 0; i < pcidev[devind].pd_bar_nr; i++)
24536e7bb628SLionel Sambuc {
24546e7bb628SLionel Sambuc reg= PCI_BAR+4*pcidev[devind].pd_bar[i].pb_nr;
24556e7bb628SLionel Sambuc
24566e7bb628SLionel Sambuc if (reg == port)
24576e7bb628SLionel Sambuc {
24586e7bb628SLionel Sambuc if (pcidev[devind].pd_bar[i].pb_flags & PBF_INCOMPLETE)
24596e7bb628SLionel Sambuc return EINVAL;
24606e7bb628SLionel Sambuc
24616e7bb628SLionel Sambuc *base= pcidev[devind].pd_bar[i].pb_base;
24626e7bb628SLionel Sambuc *size= pcidev[devind].pd_bar[i].pb_size;
24636e7bb628SLionel Sambuc *ioflag=
24646e7bb628SLionel Sambuc !!(pcidev[devind].pd_bar[i].pb_flags & PBF_IO);
24656e7bb628SLionel Sambuc return OK;
24666e7bb628SLionel Sambuc }
24676e7bb628SLionel Sambuc }
24686e7bb628SLionel Sambuc return EINVAL;
24696e7bb628SLionel Sambuc }
24706e7bb628SLionel Sambuc
24716e7bb628SLionel Sambuc /*===========================================================================*
24726e7bb628SLionel Sambuc * _pci_attr_r8 *
24736e7bb628SLionel Sambuc *===========================================================================*/
24746e7bb628SLionel Sambuc int
_pci_attr_r8(int devind,int port,u8_t * vp)24756e7bb628SLionel Sambuc _pci_attr_r8(int devind, int port, u8_t *vp)
24766e7bb628SLionel Sambuc {
24776e7bb628SLionel Sambuc if (devind < 0 || devind >= nr_pcidev)
24786e7bb628SLionel Sambuc return EINVAL;
24796e7bb628SLionel Sambuc if (port < 0 || port > 256-1)
24806e7bb628SLionel Sambuc return EINVAL;
24816e7bb628SLionel Sambuc
24826e7bb628SLionel Sambuc *vp= __pci_attr_r8(devind, port);
24836e7bb628SLionel Sambuc return OK;
24846e7bb628SLionel Sambuc }
24856e7bb628SLionel Sambuc
24866e7bb628SLionel Sambuc /*===========================================================================*
24876e7bb628SLionel Sambuc * _pci_attr_r16 *
24886e7bb628SLionel Sambuc *===========================================================================*/
24896e7bb628SLionel Sambuc int
_pci_attr_r16(int devind,int port,u16_t * vp)24906e7bb628SLionel Sambuc _pci_attr_r16(int devind, int port, u16_t *vp)
24916e7bb628SLionel Sambuc {
24926e7bb628SLionel Sambuc if (devind < 0 || devind >= nr_pcidev)
24936e7bb628SLionel Sambuc return EINVAL;
24946e7bb628SLionel Sambuc if (port < 0 || port > 256-2)
24956e7bb628SLionel Sambuc return EINVAL;
24966e7bb628SLionel Sambuc
24976e7bb628SLionel Sambuc *vp= __pci_attr_r16(devind, port);
24986e7bb628SLionel Sambuc return OK;
24996e7bb628SLionel Sambuc }
25006e7bb628SLionel Sambuc
25016e7bb628SLionel Sambuc /*===========================================================================*
25026e7bb628SLionel Sambuc * _pci_attr_r32 *
25036e7bb628SLionel Sambuc *===========================================================================*/
25046e7bb628SLionel Sambuc int
_pci_attr_r32(int devind,int port,u32_t * vp)25056e7bb628SLionel Sambuc _pci_attr_r32(int devind, int port, u32_t *vp)
25066e7bb628SLionel Sambuc {
25076e7bb628SLionel Sambuc if (devind < 0 || devind >= nr_pcidev)
25086e7bb628SLionel Sambuc return EINVAL;
25096e7bb628SLionel Sambuc if (port < 0 || port > 256-4)
25106e7bb628SLionel Sambuc return EINVAL;
25116e7bb628SLionel Sambuc
25126e7bb628SLionel Sambuc *vp= __pci_attr_r32(devind, port);
25136e7bb628SLionel Sambuc return OK;
25146e7bb628SLionel Sambuc }
25156e7bb628SLionel Sambuc
25166e7bb628SLionel Sambuc /*===========================================================================*
25176e7bb628SLionel Sambuc * _pci_attr_w8 *
25186e7bb628SLionel Sambuc *===========================================================================*/
25196e7bb628SLionel Sambuc int
_pci_attr_w8(int devind,int port,u8_t value)25206e7bb628SLionel Sambuc _pci_attr_w8(int devind, int port, u8_t value)
25216e7bb628SLionel Sambuc {
25226e7bb628SLionel Sambuc if (devind < 0 || devind >= nr_pcidev)
25236e7bb628SLionel Sambuc return EINVAL;
25246e7bb628SLionel Sambuc if (port < 0 || port > 256-1)
25256e7bb628SLionel Sambuc return EINVAL;
25266e7bb628SLionel Sambuc
25276e7bb628SLionel Sambuc __pci_attr_w8(devind, port, value);
25286e7bb628SLionel Sambuc return OK;
25296e7bb628SLionel Sambuc }
25306e7bb628SLionel Sambuc
25316e7bb628SLionel Sambuc /*===========================================================================*
25326e7bb628SLionel Sambuc * _pci_attr_w16 *
25336e7bb628SLionel Sambuc *===========================================================================*/
25346e7bb628SLionel Sambuc int
_pci_attr_w16(int devind,int port,u16_t value)25356e7bb628SLionel Sambuc _pci_attr_w16(int devind, int port, u16_t value)
25366e7bb628SLionel Sambuc {
25376e7bb628SLionel Sambuc if (devind < 0 || devind >= nr_pcidev)
25386e7bb628SLionel Sambuc return EINVAL;
25396e7bb628SLionel Sambuc if (port < 0 || port > 256-2)
25406e7bb628SLionel Sambuc return EINVAL;
25416e7bb628SLionel Sambuc
25426e7bb628SLionel Sambuc __pci_attr_w16(devind, port, value);
25436e7bb628SLionel Sambuc return OK;
25446e7bb628SLionel Sambuc }
25456e7bb628SLionel Sambuc
25466e7bb628SLionel Sambuc /*===========================================================================*
25476e7bb628SLionel Sambuc * _pci_attr_w32 *
25486e7bb628SLionel Sambuc *===========================================================================*/
25496e7bb628SLionel Sambuc int
_pci_attr_w32(int devind,int port,u32_t value)25506e7bb628SLionel Sambuc _pci_attr_w32(int devind, int port, u32_t value)
25516e7bb628SLionel Sambuc {
25526e7bb628SLionel Sambuc if (devind < 0 || devind >= nr_pcidev)
25536e7bb628SLionel Sambuc return EINVAL;
25546e7bb628SLionel Sambuc if (port < 0 || port > 256-4)
25556e7bb628SLionel Sambuc return EINVAL;
25566e7bb628SLionel Sambuc
25576e7bb628SLionel Sambuc __pci_attr_w32(devind, port, value);
25586e7bb628SLionel Sambuc return OK;
25596e7bb628SLionel Sambuc }
2560