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

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), &reg32);
                    271:         void *flatptr = MAKE_FLATPTR(GET_SEG(SS), &reg32);
                    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(&reg32);
                    276:     }
                    277: }

unix.superglobalmegacorp.com

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