Find all pci devices at startup and cache them for future use.
[seabios.git] / src / pci.c
1 // PCI config space access functions.
2 //
3 // Copyright (C) 2008  Kevin O'Connor <kevin@koconnor.net>
4 // Copyright (C) 2002  MandrakeSoft S.A.
5 //
6 // This file may be distributed under the terms of the GNU LGPLv3 license.
7
8 #include "pci.h" // pci_config_writel
9 #include "ioport.h" // outl
10 #include "util.h" // dprintf
11 #include "config.h" // CONFIG_*
12 #include "farptr.h" // CONFIG_*
13 #include "pci_regs.h" // PCI_VENDOR_ID
14 #include "pci_ids.h" // PCI_CLASS_DISPLAY_VGA
15
16 void pci_config_writel(u16 bdf, u32 addr, u32 val)
17 {
18     outl(0x80000000 | (bdf << 8) | (addr & 0xfc), PORT_PCI_CMD);
19     outl(val, PORT_PCI_DATA);
20 }
21
22 void pci_config_writew(u16 bdf, u32 addr, u16 val)
23 {
24     outl(0x80000000 | (bdf << 8) | (addr & 0xfc), PORT_PCI_CMD);
25     outw(val, PORT_PCI_DATA + (addr & 2));
26 }
27
28 void pci_config_writeb(u16 bdf, u32 addr, u8 val)
29 {
30     outl(0x80000000 | (bdf << 8) | (addr & 0xfc), PORT_PCI_CMD);
31     outb(val, PORT_PCI_DATA + (addr & 3));
32 }
33
34 u32 pci_config_readl(u16 bdf, u32 addr)
35 {
36     outl(0x80000000 | (bdf << 8) | (addr & 0xfc), PORT_PCI_CMD);
37     return inl(PORT_PCI_DATA);
38 }
39
40 u16 pci_config_readw(u16 bdf, u32 addr)
41 {
42     outl(0x80000000 | (bdf << 8) | (addr & 0xfc), PORT_PCI_CMD);
43     return inw(PORT_PCI_DATA + (addr & 2));
44 }
45
46 u8 pci_config_readb(u16 bdf, u32 addr)
47 {
48     outl(0x80000000 | (bdf << 8) | (addr & 0xfc), PORT_PCI_CMD);
49     return inb(PORT_PCI_DATA + (addr & 3));
50 }
51
52 void
53 pci_config_maskw(u16 bdf, u32 addr, u16 off, u16 on)
54 {
55     u16 val = pci_config_readw(bdf, addr);
56     val = (val & ~off) | on;
57     pci_config_writew(bdf, addr, val);
58 }
59
60 // Helper function for foreachbdf() macro - return next device
61 int
62 pci_next(int bdf, int *pmax)
63 {
64     if (pci_bdf_to_fn(bdf) == 1
65         && (pci_config_readb(bdf-1, PCI_HEADER_TYPE) & 0x80) == 0)
66         // Last found device wasn't a multi-function device - skip to
67         // the next device.
68         bdf += 7;
69
70     int max = *pmax;
71     for (;;) {
72         if (bdf >= max) {
73             if (CONFIG_PCI_ROOT1 && bdf <= (CONFIG_PCI_ROOT1 << 8))
74                 bdf = CONFIG_PCI_ROOT1 << 8;
75             else if (CONFIG_PCI_ROOT2 && bdf <= (CONFIG_PCI_ROOT2 << 8))
76                 bdf = CONFIG_PCI_ROOT2 << 8;
77             else
78                 return -1;
79             *pmax = max = bdf + 0x0100;
80         }
81
82         u16 v = pci_config_readw(bdf, PCI_VENDOR_ID);
83         if (v != 0x0000 && v != 0xffff)
84             // Device is present.
85             break;
86
87         if (pci_bdf_to_fn(bdf) == 0)
88             bdf += 8;
89         else
90             bdf += 1;
91     }
92
93     // Check if found device is a bridge.
94     u32 v = pci_config_readb(bdf, PCI_HEADER_TYPE);
95     v &= 0x7f;
96     if (v == PCI_HEADER_TYPE_BRIDGE || v == PCI_HEADER_TYPE_CARDBUS) {
97         v = pci_config_readl(bdf, PCI_PRIMARY_BUS);
98         int newmax = (v & 0xff00) + 0x0100;
99         if (newmax > max)
100             *pmax = newmax;
101     }
102
103     return bdf;
104 }
105
106 struct pci_device *PCIDevices;
107 int MaxPCIBus;
108
109 void
110 pci_probe(void)
111 {
112     int rootbuses = 0;
113     struct pci_device *busdevs[256];
114     memset(busdevs, 0, sizeof(busdevs));
115
116     struct pci_device **pprev = &PCIDevices;
117     u8 lastbus = 0;
118     int bdf, max;
119     foreachbdf(bdf, max) {
120         // Create new pci_device struct and add to list.
121         struct pci_device *dev = malloc_tmp(sizeof(*dev));
122         if (!dev) {
123             warn_noalloc();
124             return;
125         }
126         memset(dev, 0, sizeof(*dev));
127         *pprev = dev;
128         pprev = &dev->next;
129
130         // Find parent device.
131         u8 bus = pci_bdf_to_bus(bdf), rootbus;
132         struct pci_device *parent = busdevs[bus];
133         if (!parent) {
134             if (bus != lastbus)
135                 rootbuses++;
136             lastbus = bus;
137             rootbus = rootbuses;
138         } else {
139             rootbus = parent->rootbus;
140         }
141         if (bus > MaxPCIBus)
142             MaxPCIBus = bus;
143
144         // Populate pci_device info.
145         dev->bdf = bdf;
146         dev->parent = parent;
147         dev->rootbus = rootbus;
148         u32 vendev = pci_config_readl(bdf, PCI_VENDOR_ID);
149         dev->vendor = vendev & 0xffff;
150         dev->device = vendev >> 16;
151         u32 classrev = pci_config_readl(bdf, PCI_CLASS_REVISION);
152         dev->class = classrev >> 16;
153         dev->prog_if = classrev >> 8;
154         dev->revision = classrev & 0xff;
155         dev->header_type = pci_config_readb(bdf, PCI_HEADER_TYPE);
156         u8 v = dev->header_type & 0x7f;
157         if (v == PCI_HEADER_TYPE_BRIDGE || v == PCI_HEADER_TYPE_CARDBUS) {
158             u8 secbus = pci_config_readb(bdf, PCI_SECONDARY_BUS);
159             dev->secondary_bus = secbus;
160             if (secbus > bus && !busdevs[secbus])
161                 busdevs[secbus] = dev;
162         }
163     }
164 }
165
166 // Find a vga device with legacy address decoding enabled.
167 int
168 pci_find_vga(void)
169 {
170     int bdf = 0x0000, max = 0x0100;
171     for (;;) {
172         if (bdf >= max) {
173             if (CONFIG_PCI_ROOT1 && bdf <= (CONFIG_PCI_ROOT1 << 8))
174                 bdf = CONFIG_PCI_ROOT1 << 8;
175             else if (CONFIG_PCI_ROOT2 && bdf <= (CONFIG_PCI_ROOT2 << 8))
176                 bdf = CONFIG_PCI_ROOT2 << 8;
177             else
178                 return -1;
179             max = bdf + 0x0100;
180         }
181
182         u16 cls = pci_config_readw(bdf, PCI_CLASS_DEVICE);
183         if (cls == 0x0000 || cls == 0xffff) {
184             // Device not present.
185             if (pci_bdf_to_fn(bdf) == 0)
186                 bdf += 8;
187             else
188                 bdf += 1;
189             continue;
190         }
191         if (cls == PCI_CLASS_DISPLAY_VGA) {
192             u16 cmd = pci_config_readw(bdf, PCI_COMMAND);
193             if (cmd & PCI_COMMAND_IO && cmd & PCI_COMMAND_MEMORY)
194                 // Found active vga card
195                 return bdf;
196         }
197
198         // Check if device is a bridge.
199         u8 hdr = pci_config_readb(bdf, PCI_HEADER_TYPE);
200         u8 ht = hdr & 0x7f;
201         if (ht == PCI_HEADER_TYPE_BRIDGE || ht == PCI_HEADER_TYPE_CARDBUS) {
202             u32 ctrl = pci_config_readb(bdf, PCI_BRIDGE_CONTROL);
203             if (ctrl & PCI_BRIDGE_CTL_VGA) {
204                 // Found a VGA enabled bridge.
205                 u32 pbus = pci_config_readl(bdf, PCI_PRIMARY_BUS);
206                 bdf = (pbus & 0xff00);
207                 max = bdf + 0x100;
208                 continue;
209             }
210         }
211
212         if (pci_bdf_to_fn(bdf) == 0 && (hdr & 0x80) == 0)
213             // Last found device wasn't a multi-function device - skip to
214             // the next device.
215             bdf += 8;
216         else
217             bdf += 1;
218     }
219 }
220
221 // Search for a device with the specified vendor and device ids.
222 int
223 pci_find_device(u16 vendid, u16 devid)
224 {
225     u32 id = (devid << 16) | vendid;
226     int bdf, max;
227     foreachbdf(bdf, max) {
228         u32 v = pci_config_readl(bdf, PCI_VENDOR_ID);
229         if (v == id)
230             return bdf;
231     }
232     return -1;
233 }
234
235 // Search for a device with the specified class id.
236 int
237 pci_find_class(u16 classid)
238 {
239     int bdf, max;
240     foreachbdf(bdf, max) {
241         u16 v = pci_config_readw(bdf, PCI_CLASS_DEVICE);
242         if (v == classid)
243             return bdf;
244     }
245     return -1;
246 }
247
248 int *PCIpaths;
249
250 // Build the PCI path designations.
251 void
252 pci_path_setup(void)
253 {
254     PCIpaths = malloc_tmp(sizeof(*PCIpaths) * 256);
255     if (!PCIpaths)
256         return;
257     memset(PCIpaths, 0, sizeof(*PCIpaths) * 256);
258
259     int roots = 0;
260     int bdf, max;
261     foreachbdf(bdf, max) {
262         int bus = pci_bdf_to_bus(bdf);
263         if (! PCIpaths[bus])
264             PCIpaths[bus] = (roots++) | PP_ROOT;
265
266         // Check if found device is a bridge.
267         u32 v = pci_config_readb(bdf, PCI_HEADER_TYPE);
268         v &= 0x7f;
269         if (v == PCI_HEADER_TYPE_BRIDGE || v == PCI_HEADER_TYPE_CARDBUS) {
270             v = pci_config_readl(bdf, PCI_PRIMARY_BUS);
271             int childbus = (v >> 8) & 0xff;
272             if (childbus > bus)
273                 PCIpaths[childbus] = bdf | PP_PCIBRIDGE;
274         }
275     }
276 }
277
278 int pci_init_device(const struct pci_device_id *ids, u16 bdf, void *arg)
279 {
280     u16 vendor_id = pci_config_readw(bdf, PCI_VENDOR_ID);
281     u16 device_id = pci_config_readw(bdf, PCI_DEVICE_ID);
282     u16 class = pci_config_readw(bdf, PCI_CLASS_DEVICE);
283
284     while (ids->vendid || ids->class_mask) {
285         if ((ids->vendid == PCI_ANY_ID || ids->vendid == vendor_id) &&
286             (ids->devid == PCI_ANY_ID || ids->devid == device_id) &&
287             !((ids->class ^ class) & ids->class_mask)) {
288             if (ids->func) {
289                 ids->func(bdf, arg);
290             }
291             return 0;
292         }
293         ids++;
294     }
295     return -1;
296 }
297
298 int pci_find_init_device(const struct pci_device_id *ids, void *arg)
299 {
300     int bdf, max;
301
302     foreachbdf(bdf, max) {
303         if (pci_init_device(ids, bdf, arg) == 0) {
304             return bdf;
305         }
306     }
307     return -1;
308 }
309
310 void
311 pci_reboot(void)
312 {
313     u8 v = inb(PORT_PCI_REBOOT) & ~6;
314     outb(v|2, PORT_PCI_REBOOT); /* Request hard reset */
315     udelay(50);
316     outb(v|6, PORT_PCI_REBOOT); /* Actually do the reset */
317     udelay(50);
318 }
319
320 // helper functions to access pci mmio bars from real mode
321
322 u32 VISIBLE32FLAT
323 pci_readl_32(u32 addr)
324 {
325     dprintf(3, "32: pci read : %x\n", addr);
326     return readl((void*)addr);
327 }
328
329 u32 pci_readl(u32 addr)
330 {
331     if (MODESEGMENT) {
332         dprintf(3, "16: pci read : %x\n", addr);
333         extern void _cfunc32flat_pci_readl_32(u32 addr);
334         return call32(_cfunc32flat_pci_readl_32, addr, -1);
335     } else {
336         return pci_readl_32(addr);
337     }
338 }
339
340 struct reg32 {
341     u32 addr;
342     u32 data;
343 };
344
345 void VISIBLE32FLAT
346 pci_writel_32(struct reg32 *reg32)
347 {
348     dprintf(3, "32: pci write: %x, %x (%p)\n", reg32->addr, reg32->data, reg32);
349     writel((void*)(reg32->addr), reg32->data);
350 }
351
352 void pci_writel(u32 addr, u32 val)
353 {
354     struct reg32 reg32 = { .addr = addr, .data = val };
355     if (MODESEGMENT) {
356         dprintf(3, "16: pci write: %x, %x (%x:%p)\n",
357                 reg32.addr, reg32.data, GET_SEG(SS), &reg32);
358         void *flatptr = MAKE_FLATPTR(GET_SEG(SS), &reg32);
359         extern void _cfunc32flat_pci_writel_32(struct reg32 *reg32);
360         call32(_cfunc32flat_pci_writel_32, (u32)flatptr, -1);
361     } else {
362         pci_writel_32(&reg32);
363     }
364 }