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

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

unix.superglobalmegacorp.com

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