|
|
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
11: #include "config.h" // CONFIG_*
1.1.1.5 ! root 12: #include "farptr.h" // CONFIG_*
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:
60: // Helper function for foreachpci() 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: // Find a vga device with legacy address decoding enabled.
107: int
1.1.1.2 root 108: pci_find_vga(void)
1.1 root 109: {
110: int bdf = 0x0000, max = 0x0100;
111: for (;;) {
112: if (bdf >= max) {
113: if (CONFIG_PCI_ROOT1 && bdf <= (CONFIG_PCI_ROOT1 << 8))
114: bdf = CONFIG_PCI_ROOT1 << 8;
115: else if (CONFIG_PCI_ROOT2 && bdf <= (CONFIG_PCI_ROOT2 << 8))
116: bdf = CONFIG_PCI_ROOT2 << 8;
117: else
118: return -1;
119: max = bdf + 0x0100;
120: }
121:
122: u16 cls = pci_config_readw(bdf, PCI_CLASS_DEVICE);
123: if (cls == 0x0000 || cls == 0xffff) {
124: // Device not present.
125: if (pci_bdf_to_fn(bdf) == 0)
126: bdf += 8;
127: else
128: bdf += 1;
129: continue;
130: }
131: if (cls == PCI_CLASS_DISPLAY_VGA) {
132: u16 cmd = pci_config_readw(bdf, PCI_COMMAND);
133: if (cmd & PCI_COMMAND_IO && cmd & PCI_COMMAND_MEMORY)
134: // Found active vga card
135: return bdf;
136: }
137:
138: // Check if device is a bridge.
139: u8 hdr = pci_config_readb(bdf, PCI_HEADER_TYPE);
140: u8 ht = hdr & 0x7f;
141: if (ht == PCI_HEADER_TYPE_BRIDGE || ht == PCI_HEADER_TYPE_CARDBUS) {
142: u32 ctrl = pci_config_readb(bdf, PCI_BRIDGE_CONTROL);
143: if (ctrl & PCI_BRIDGE_CTL_VGA) {
144: // Found a VGA enabled bridge.
145: u32 pbus = pci_config_readl(bdf, PCI_PRIMARY_BUS);
146: bdf = (pbus & 0xff00);
147: max = bdf + 0x100;
148: continue;
149: }
150: }
151:
152: if (pci_bdf_to_fn(bdf) == 0 && (hdr & 0x80) == 0)
153: // Last found device wasn't a multi-function device - skip to
154: // the next device.
155: bdf += 8;
156: else
157: bdf += 1;
158: }
159: }
160:
161: // Search for a device with the specified vendor and device ids.
162: int
163: pci_find_device(u16 vendid, u16 devid)
164: {
165: u32 id = (devid << 16) | vendid;
166: int bdf, max;
167: foreachpci(bdf, max) {
168: u32 v = pci_config_readl(bdf, PCI_VENDOR_ID);
169: if (v == id)
170: return bdf;
171: }
172: return -1;
173: }
174:
175: // Search for a device with the specified class id.
176: int
177: pci_find_class(u16 classid)
178: {
179: int bdf, max;
180: foreachpci(bdf, max) {
181: u16 v = pci_config_readw(bdf, PCI_CLASS_DEVICE);
182: if (v == classid)
183: return bdf;
184: }
185: return -1;
186: }
1.1.1.3 root 187:
1.1.1.5 ! root 188: int *PCIpaths;
! 189:
! 190: // Build the PCI path designations.
! 191: void
! 192: pci_path_setup(void)
! 193: {
! 194: PCIpaths = malloc_tmp(sizeof(*PCIpaths) * 256);
! 195: if (!PCIpaths)
! 196: return;
! 197: memset(PCIpaths, 0, sizeof(*PCIpaths) * 256);
! 198:
! 199: int roots = 0;
! 200: int bdf, max;
! 201: foreachpci(bdf, max) {
! 202: int bus = pci_bdf_to_bus(bdf);
! 203: if (! PCIpaths[bus])
! 204: PCIpaths[bus] = (roots++) | PP_ROOT;
! 205:
! 206: // Check if found device is a bridge.
! 207: u32 v = pci_config_readb(bdf, PCI_HEADER_TYPE);
! 208: v &= 0x7f;
! 209: if (v == PCI_HEADER_TYPE_BRIDGE || v == PCI_HEADER_TYPE_CARDBUS) {
! 210: v = pci_config_readl(bdf, PCI_PRIMARY_BUS);
! 211: int childbus = (v >> 8) & 0xff;
! 212: if (childbus > bus)
! 213: PCIpaths[childbus] = bdf | PP_PCIBRIDGE;
! 214: }
! 215: }
! 216: }
! 217:
1.1.1.3 root 218: int pci_init_device(const struct pci_device_id *ids, u16 bdf, void *arg)
219: {
220: u16 vendor_id = pci_config_readw(bdf, PCI_VENDOR_ID);
221: u16 device_id = pci_config_readw(bdf, PCI_DEVICE_ID);
222: u16 class = pci_config_readw(bdf, PCI_CLASS_DEVICE);
223:
224: while (ids->vendid || ids->class_mask) {
225: if ((ids->vendid == PCI_ANY_ID || ids->vendid == vendor_id) &&
226: (ids->devid == PCI_ANY_ID || ids->devid == device_id) &&
227: !((ids->class ^ class) & ids->class_mask)) {
228: if (ids->func) {
229: ids->func(bdf, arg);
230: }
231: return 0;
232: }
233: ids++;
234: }
235: return -1;
236: }
1.1.1.4 root 237:
238: int pci_find_init_device(const struct pci_device_id *ids, void *arg)
239: {
240: int bdf, max;
241:
242: foreachpci(bdf, max) {
243: if (pci_init_device(ids, bdf, arg) == 0) {
244: return bdf;
245: }
246: }
247: return -1;
248: }
1.1.1.5 ! root 249:
! 250: void
! 251: pci_reboot(void)
! 252: {
! 253: u8 v = inb(PORT_PCI_REBOOT) & ~6;
! 254: outb(v|2, PORT_PCI_REBOOT); /* Request hard reset */
! 255: udelay(50);
! 256: outb(v|6, PORT_PCI_REBOOT); /* Actually do the reset */
! 257: udelay(50);
! 258: }
! 259:
! 260: // helper functions to access pci mmio bars from real mode
! 261:
! 262: u32 VISIBLE32FLAT
! 263: pci_readl_32(u32 addr)
! 264: {
! 265: dprintf(3, "32: pci read : %x\n", addr);
! 266: return readl((void*)addr);
! 267: }
! 268:
! 269: u32 pci_readl(u32 addr)
! 270: {
! 271: if (MODESEGMENT) {
! 272: dprintf(3, "16: pci read : %x\n", addr);
! 273: extern void _cfunc32flat_pci_readl_32(u32 addr);
! 274: return call32(_cfunc32flat_pci_readl_32, addr, -1);
! 275: } else {
! 276: return pci_readl_32(addr);
! 277: }
! 278: }
! 279:
! 280: struct reg32 {
! 281: u32 addr;
! 282: u32 data;
! 283: };
! 284:
! 285: void VISIBLE32FLAT
! 286: pci_writel_32(struct reg32 *reg32)
! 287: {
! 288: dprintf(3, "32: pci write: %x, %x (%p)\n", reg32->addr, reg32->data, reg32);
! 289: writel((void*)(reg32->addr), reg32->data);
! 290: }
! 291:
! 292: void pci_writel(u32 addr, u32 val)
! 293: {
! 294: struct reg32 reg32 = { .addr = addr, .data = val };
! 295: if (MODESEGMENT) {
! 296: dprintf(3, "16: pci write: %x, %x (%x:%p)\n",
! 297: reg32.addr, reg32.data, GET_SEG(SS), ®32);
! 298: void *flatptr = MAKE_FLATPTR(GET_SEG(SS), ®32);
! 299: extern void _cfunc32flat_pci_writel_32(struct reg32 *reg32);
! 300: call32(_cfunc32flat_pci_writel_32, (u32)flatptr, -1);
! 301: } else {
! 302: pci_writel_32(®32);
! 303: }
! 304: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.