|
|
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_* ! 12: #include "pci_regs.h" // PCI_VENDOR_ID ! 13: #include "pci_ids.h" // PCI_CLASS_DISPLAY_VGA ! 14: ! 15: void pci_config_writel(u16 bdf, u32 addr, u32 val) ! 16: { ! 17: outl(0x80000000 | (bdf << 8) | (addr & 0xfc), PORT_PCI_CMD); ! 18: outl(val, PORT_PCI_DATA); ! 19: } ! 20: ! 21: void pci_config_writew(u16 bdf, u32 addr, u16 val) ! 22: { ! 23: outl(0x80000000 | (bdf << 8) | (addr & 0xfc), PORT_PCI_CMD); ! 24: outw(val, PORT_PCI_DATA + (addr & 2)); ! 25: } ! 26: ! 27: void pci_config_writeb(u16 bdf, u32 addr, u8 val) ! 28: { ! 29: outl(0x80000000 | (bdf << 8) | (addr & 0xfc), PORT_PCI_CMD); ! 30: outb(val, PORT_PCI_DATA + (addr & 3)); ! 31: } ! 32: ! 33: u32 pci_config_readl(u16 bdf, u32 addr) ! 34: { ! 35: outl(0x80000000 | (bdf << 8) | (addr & 0xfc), PORT_PCI_CMD); ! 36: return inl(PORT_PCI_DATA); ! 37: } ! 38: ! 39: u16 pci_config_readw(u16 bdf, u32 addr) ! 40: { ! 41: outl(0x80000000 | (bdf << 8) | (addr & 0xfc), PORT_PCI_CMD); ! 42: return inw(PORT_PCI_DATA + (addr & 2)); ! 43: } ! 44: ! 45: u8 pci_config_readb(u16 bdf, u32 addr) ! 46: { ! 47: outl(0x80000000 | (bdf << 8) | (addr & 0xfc), PORT_PCI_CMD); ! 48: return inb(PORT_PCI_DATA + (addr & 3)); ! 49: } ! 50: ! 51: void ! 52: pci_config_maskw(u16 bdf, u32 addr, u16 off, u16 on) ! 53: { ! 54: u16 val = pci_config_readw(bdf, addr); ! 55: val = (val & ~off) | on; ! 56: pci_config_writew(bdf, addr, val); ! 57: } ! 58: ! 59: // Helper function for foreachpci() macro - return next device ! 60: int ! 61: pci_next(int bdf, int *pmax) ! 62: { ! 63: if (pci_bdf_to_fn(bdf) == 1 ! 64: && (pci_config_readb(bdf-1, PCI_HEADER_TYPE) & 0x80) == 0) ! 65: // Last found device wasn't a multi-function device - skip to ! 66: // the next device. ! 67: bdf += 7; ! 68: ! 69: int max = *pmax; ! 70: for (;;) { ! 71: if (bdf >= max) { ! 72: if (CONFIG_PCI_ROOT1 && bdf <= (CONFIG_PCI_ROOT1 << 8)) ! 73: bdf = CONFIG_PCI_ROOT1 << 8; ! 74: else if (CONFIG_PCI_ROOT2 && bdf <= (CONFIG_PCI_ROOT2 << 8)) ! 75: bdf = CONFIG_PCI_ROOT2 << 8; ! 76: else ! 77: return -1; ! 78: *pmax = max = bdf + 0x0100; ! 79: } ! 80: ! 81: u16 v = pci_config_readw(bdf, PCI_VENDOR_ID); ! 82: if (v != 0x0000 && v != 0xffff) ! 83: // Device is present. ! 84: break; ! 85: ! 86: if (pci_bdf_to_fn(bdf) == 0) ! 87: bdf += 8; ! 88: else ! 89: bdf += 1; ! 90: } ! 91: ! 92: // Check if found device is a bridge. ! 93: u32 v = pci_config_readb(bdf, PCI_HEADER_TYPE); ! 94: v &= 0x7f; ! 95: if (v == PCI_HEADER_TYPE_BRIDGE || v == PCI_HEADER_TYPE_CARDBUS) { ! 96: v = pci_config_readl(bdf, PCI_PRIMARY_BUS); ! 97: int newmax = (v & 0xff00) + 0x0100; ! 98: if (newmax > max) ! 99: *pmax = newmax; ! 100: } ! 101: ! 102: return bdf; ! 103: } ! 104: ! 105: // Find a vga device with legacy address decoding enabled. ! 106: int ! 107: pci_find_vga() ! 108: { ! 109: int bdf = 0x0000, max = 0x0100; ! 110: for (;;) { ! 111: if (bdf >= max) { ! 112: if (CONFIG_PCI_ROOT1 && bdf <= (CONFIG_PCI_ROOT1 << 8)) ! 113: bdf = CONFIG_PCI_ROOT1 << 8; ! 114: else if (CONFIG_PCI_ROOT2 && bdf <= (CONFIG_PCI_ROOT2 << 8)) ! 115: bdf = CONFIG_PCI_ROOT2 << 8; ! 116: else ! 117: return -1; ! 118: max = bdf + 0x0100; ! 119: } ! 120: ! 121: u16 cls = pci_config_readw(bdf, PCI_CLASS_DEVICE); ! 122: if (cls == 0x0000 || cls == 0xffff) { ! 123: // Device not present. ! 124: if (pci_bdf_to_fn(bdf) == 0) ! 125: bdf += 8; ! 126: else ! 127: bdf += 1; ! 128: continue; ! 129: } ! 130: if (cls == PCI_CLASS_DISPLAY_VGA) { ! 131: u16 cmd = pci_config_readw(bdf, PCI_COMMAND); ! 132: if (cmd & PCI_COMMAND_IO && cmd & PCI_COMMAND_MEMORY) ! 133: // Found active vga card ! 134: return bdf; ! 135: } ! 136: ! 137: // Check if device is a bridge. ! 138: u8 hdr = pci_config_readb(bdf, PCI_HEADER_TYPE); ! 139: u8 ht = hdr & 0x7f; ! 140: if (ht == PCI_HEADER_TYPE_BRIDGE || ht == PCI_HEADER_TYPE_CARDBUS) { ! 141: u32 ctrl = pci_config_readb(bdf, PCI_BRIDGE_CONTROL); ! 142: if (ctrl & PCI_BRIDGE_CTL_VGA) { ! 143: // Found a VGA enabled bridge. ! 144: u32 pbus = pci_config_readl(bdf, PCI_PRIMARY_BUS); ! 145: bdf = (pbus & 0xff00); ! 146: max = bdf + 0x100; ! 147: continue; ! 148: } ! 149: } ! 150: ! 151: if (pci_bdf_to_fn(bdf) == 0 && (hdr & 0x80) == 0) ! 152: // Last found device wasn't a multi-function device - skip to ! 153: // the next device. ! 154: bdf += 8; ! 155: else ! 156: bdf += 1; ! 157: } ! 158: } ! 159: ! 160: // Search for a device with the specified vendor and device ids. ! 161: int ! 162: pci_find_device(u16 vendid, u16 devid) ! 163: { ! 164: u32 id = (devid << 16) | vendid; ! 165: int bdf, max; ! 166: foreachpci(bdf, max) { ! 167: u32 v = pci_config_readl(bdf, PCI_VENDOR_ID); ! 168: if (v == id) ! 169: return bdf; ! 170: } ! 171: return -1; ! 172: } ! 173: ! 174: // Search for a device with the specified class id. ! 175: int ! 176: pci_find_class(u16 classid) ! 177: { ! 178: int bdf, max; ! 179: foreachpci(bdf, max) { ! 180: u16 v = pci_config_readw(bdf, PCI_CLASS_DEVICE); ! 181: if (v == classid) ! 182: return bdf; ! 183: } ! 184: return -1; ! 185: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.