|
|
1.1 root 1: // PCI config space access functions.
2: //
3: // Copyright (C) 2008 Kevin O'Connor <[email protected]>
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
1.1.1.6 ! root 11: #include "paravirt.h" // romfile_loadint
! 12: #include "farptr.h" // MAKE_FLATPTR
1.1 root 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:
1.1.1.6 ! root 60: // Helper function for foreachbdf() macro - return next device
1.1 root 61: int
1.1.1.6 ! root 62: pci_next(int bdf, int bus)
1.1 root 63: {
1.1.1.6 ! root 64: if (pci_bdf_to_fn(bdf) == 0
! 65: && (pci_config_readb(bdf, PCI_HEADER_TYPE) & 0x80) == 0)
1.1 root 66: // Last found device wasn't a multi-function device - skip to
67: // the next device.
1.1.1.6 ! root 68: bdf += 8;
! 69: else
! 70: bdf += 1;
1.1 root 71:
72: for (;;) {
1.1.1.6 ! root 73: if (pci_bdf_to_bus(bdf) != bus)
! 74: return -1;
1.1 root 75:
76: u16 v = pci_config_readw(bdf, PCI_VENDOR_ID);
77: if (v != 0x0000 && v != 0xffff)
78: // Device is present.
1.1.1.6 ! root 79: return bdf;
1.1 root 80:
81: if (pci_bdf_to_fn(bdf) == 0)
82: bdf += 8;
83: else
84: bdf += 1;
85: }
86: }
87:
1.1.1.6 ! root 88: struct pci_device *PCIDevices;
! 89: int MaxPCIBus VAR16VISIBLE;
1.1 root 90:
1.1.1.6 ! root 91: // Find all PCI devices and populate PCIDevices linked list.
! 92: void
! 93: pci_probe(void)
! 94: {
! 95: dprintf(3, "PCI probe\n");
! 96: struct pci_device *busdevs[256];
! 97: memset(busdevs, 0, sizeof(busdevs));
! 98: struct pci_device **pprev = &PCIDevices;
! 99: int extraroots = romfile_loadint("etc/extra-pci-roots", 0);
! 100: int bus = -1, lastbus = 0, rootbuses = 0, count=0;
! 101: while (bus < 0xff && (bus < MaxPCIBus || rootbuses < extraroots)) {
! 102: bus++;
! 103: int bdf;
! 104: foreachbdf(bdf, bus) {
! 105: // Create new pci_device struct and add to list.
! 106: struct pci_device *dev = malloc_tmp(sizeof(*dev));
! 107: if (!dev) {
! 108: warn_noalloc();
! 109: return;
! 110: }
! 111: memset(dev, 0, sizeof(*dev));
! 112: *pprev = dev;
! 113: pprev = &dev->next;
! 114: count++;
! 115:
! 116: // Find parent device.
! 117: int rootbus;
! 118: struct pci_device *parent = busdevs[bus];
! 119: if (!parent) {
! 120: if (bus != lastbus)
! 121: rootbuses++;
! 122: lastbus = bus;
! 123: rootbus = rootbuses;
! 124: if (bus > MaxPCIBus)
! 125: MaxPCIBus = bus;
! 126: } else {
! 127: rootbus = parent->rootbus;
! 128: }
1.1 root 129:
1.1.1.6 ! root 130: // Populate pci_device info.
! 131: dev->bdf = bdf;
! 132: dev->parent = parent;
! 133: dev->rootbus = rootbus;
! 134: u32 vendev = pci_config_readl(bdf, PCI_VENDOR_ID);
! 135: dev->vendor = vendev & 0xffff;
! 136: dev->device = vendev >> 16;
! 137: u32 classrev = pci_config_readl(bdf, PCI_CLASS_REVISION);
! 138: dev->class = classrev >> 16;
! 139: dev->prog_if = classrev >> 8;
! 140: dev->revision = classrev & 0xff;
! 141: dev->header_type = pci_config_readb(bdf, PCI_HEADER_TYPE);
! 142: u8 v = dev->header_type & 0x7f;
! 143: if (v == PCI_HEADER_TYPE_BRIDGE || v == PCI_HEADER_TYPE_CARDBUS) {
! 144: u8 secbus = pci_config_readb(bdf, PCI_SECONDARY_BUS);
! 145: dev->secondary_bus = secbus;
! 146: if (secbus > bus && !busdevs[secbus])
! 147: busdevs[secbus] = dev;
! 148: if (secbus > MaxPCIBus)
! 149: MaxPCIBus = secbus;
1.1 root 150: }
1.1.1.6 ! root 151: dprintf(4, "PCI device %02x:%02x.%x (vd=%04x:%04x c=%04x)\n"
! 152: , pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf)
! 153: , pci_bdf_to_fn(bdf)
! 154: , dev->vendor, dev->device, dev->class);
1.1 root 155: }
156: }
1.1.1.6 ! root 157: dprintf(1, "Found %d PCI devices (max PCI bus is %02x)\n", count, MaxPCIBus);
1.1 root 158: }
159:
160: // Search for a device with the specified vendor and device ids.
1.1.1.6 ! root 161: struct pci_device *
1.1 root 162: pci_find_device(u16 vendid, u16 devid)
163: {
1.1.1.6 ! root 164: struct pci_device *pci;
! 165: foreachpci(pci) {
! 166: if (pci->vendor == vendid && pci->device == devid)
! 167: return pci;
1.1 root 168: }
1.1.1.6 ! root 169: return NULL;
1.1 root 170: }
171:
172: // Search for a device with the specified class id.
1.1.1.6 ! root 173: struct pci_device *
1.1 root 174: pci_find_class(u16 classid)
175: {
1.1.1.6 ! root 176: struct pci_device *pci;
! 177: foreachpci(pci) {
! 178: if (pci->class == classid)
! 179: return pci;
1.1 root 180: }
1.1.1.6 ! root 181: return NULL;
1.1 root 182: }
1.1.1.3 root 183:
1.1.1.6 ! root 184: int pci_init_device(const struct pci_device_id *ids
! 185: , struct pci_device *pci, void *arg)
1.1.1.5 root 186: {
1.1.1.3 root 187: while (ids->vendid || ids->class_mask) {
1.1.1.6 ! root 188: if ((ids->vendid == PCI_ANY_ID || ids->vendid == pci->vendor) &&
! 189: (ids->devid == PCI_ANY_ID || ids->devid == pci->device) &&
! 190: !((ids->class ^ pci->class) & ids->class_mask)) {
! 191: if (ids->func)
! 192: ids->func(pci, arg);
1.1.1.3 root 193: return 0;
194: }
195: ids++;
196: }
197: return -1;
198: }
1.1.1.4 root 199:
1.1.1.6 ! root 200: struct pci_device *
! 201: pci_find_init_device(const struct pci_device_id *ids, void *arg)
1.1.1.4 root 202: {
1.1.1.6 ! root 203: struct pci_device *pci;
! 204: foreachpci(pci) {
! 205: if (pci_init_device(ids, pci, arg) == 0)
! 206: return pci;
1.1.1.4 root 207: }
1.1.1.6 ! root 208: return NULL;
1.1.1.4 root 209: }
1.1.1.5 root 210:
211: void
212: pci_reboot(void)
213: {
214: u8 v = inb(PORT_PCI_REBOOT) & ~6;
215: outb(v|2, PORT_PCI_REBOOT); /* Request hard reset */
216: udelay(50);
217: outb(v|6, PORT_PCI_REBOOT); /* Actually do the reset */
218: udelay(50);
219: }
220:
221: // helper functions to access pci mmio bars from real mode
222:
223: u32 VISIBLE32FLAT
224: pci_readl_32(u32 addr)
225: {
226: dprintf(3, "32: pci read : %x\n", addr);
227: return readl((void*)addr);
228: }
229:
230: u32 pci_readl(u32 addr)
231: {
232: if (MODESEGMENT) {
233: dprintf(3, "16: pci read : %x\n", addr);
234: extern void _cfunc32flat_pci_readl_32(u32 addr);
235: return call32(_cfunc32flat_pci_readl_32, addr, -1);
236: } else {
237: return pci_readl_32(addr);
238: }
239: }
240:
241: struct reg32 {
242: u32 addr;
243: u32 data;
244: };
245:
246: void VISIBLE32FLAT
247: pci_writel_32(struct reg32 *reg32)
248: {
249: dprintf(3, "32: pci write: %x, %x (%p)\n", reg32->addr, reg32->data, reg32);
250: writel((void*)(reg32->addr), reg32->data);
251: }
252:
253: void pci_writel(u32 addr, u32 val)
254: {
255: struct reg32 reg32 = { .addr = addr, .data = val };
256: if (MODESEGMENT) {
257: dprintf(3, "16: pci write: %x, %x (%x:%p)\n",
258: reg32.addr, reg32.data, GET_SEG(SS), ®32);
259: void *flatptr = MAKE_FLATPTR(GET_SEG(SS), ®32);
260: extern void _cfunc32flat_pci_writel_32(struct reg32 *reg32);
261: call32(_cfunc32flat_pci_writel_32, (u32)flatptr, -1);
262: } else {
263: pci_writel_32(®32);
264: }
265: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.