Annotation of qemu/roms/seabios/src/pci.c, revision 1.1.1.5

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), &reg32);
        !           298:         void *flatptr = MAKE_FLATPTR(GET_SEG(SS), &reg32);
        !           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(&reg32);
        !           303:     }
        !           304: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.