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