Back to home page

Quest Cross Reference

 
 

    


Warning, cross-references for /kernel/drivers/pci/pci.c need to be fixed.

0001 /*                    The Quest Operating System
0002  *  Copyright (C) 2005-2010  Richard West, Boston University
0003  *
0004  *  This program is free software: you can redistribute it and/or modify
0005  *  it under the terms of the GNU General Public License as published by
0006  *  the Free Software Foundation, either version 3 of the License, or
0007  *  (at your option) any later version.
0008  *
0009  *  This program is distributed in the hope that it will be useful,
0010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
0011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0012  *  GNU General Public License for more details.
0013  *
0014  *  You should have received a copy of the GNU General Public License
0015  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
0016  */
0017 
0018 #include "drivers/pci/pci.h"
0019 #include "drivers/pci/pcidb.h"
0020 #include "arch/i386.h"
0021 #include "util/printf.h"
0022 #include "smp/smp.h"
0023 #include "smp/apic.h"
0024 #include "kernel.h"
0025 
0026 #define DEBUG_PCI
0027 
0028 #ifdef DEBUG_PCI
0029 #define DLOG(fmt,...) DLOG_PREFIX("PCI",fmt,##__VA_ARGS__)
0030 #else
0031 #define DLOG(fmt,...) ;
0032 #endif
0033 
0034 
0035 #define READ(bus, slot, func, reg, type) \
0036   pci_read_##type (pci_addr (bus, slot, func, reg))
0037 #define WRITE(bus, slot, func, reg, type, val) \
0038   pci_write_##type (pci_addr (bus, slot, func, reg), val)
0039 
0040 
0041 bool
0042 pci_search_ven_table (uint32 vendor, PCI_VENTABLE* e)
0043 {
0044   uint32 i;
0045   for (i=0; i<PCI_VENTABLE_LEN; i++)
0046     if (PciVenTable[i].VenId == vendor) {
0047       *e = PciVenTable[i];
0048       return TRUE;
0049     }
0050   return FALSE;
0051 }
0052 
0053 bool
0054 pci_search_dev_table (uint32 vendor, uint32 dev, PCI_DEVTABLE* e)
0055 {
0056   uint32 i;
0057   for (i=0; i<PCI_DEVTABLE_LEN; i++)
0058     if (PciDevTable[i].VenId == vendor && PciDevTable[i].DevId == dev) {
0059       *e = PciDevTable[i];
0060       return TRUE;
0061     }
0062   return FALSE;
0063 }
0064 
0065 bool
0066 pci_search_class_code_table (uint32 base, uint32 sub, uint32 prog,
0067                              PCI_CLASSCODETABLE* e)
0068 {
0069   uint32 i;
0070   for (i=0; i<PCI_CLASSCODETABLE_LEN; i++)
0071     if (PciClassCodeTable[i].BaseClass == base &&
0072         PciClassCodeTable[i].SubClass == sub &&
0073         PciClassCodeTable[i].ProgIf == prog) {
0074       *e = PciClassCodeTable[i];
0075       return TRUE;
0076     }
0077   return FALSE;
0078 }
0079 
0080 
0081 /* store table of PCI devices */
0082 static pci_device devices[PCI_MAX_DEVICES];
0083 static uint32 num_devices = 0;
0084 
0085 
0086 static void
0087 probe (void)
0088 {
0089   uint32 bus, slot, func, i;
0090 #ifdef DEBUG_PCI
0091   PCI_VENTABLE ven;
0092   PCI_DEVTABLE dev;
0093   PCI_CLASSCODETABLE cc;
0094 #endif
0095 
0096   for (bus=0; bus <= PCI_MAX_BUS_NUM; bus++)
0097     for (slot=0; slot <= PCI_MAX_DEV_NUM; slot++)
0098       for (func=0; func <= PCI_MAX_FUNC_NUM; func++)
0099         if (READ (bus, slot, func, 0x00, dword) != 0xFFFFFFFF) {
0100 
0101           uint16 vendorID = READ (bus, slot, func, 0x00, word);
0102           uint16 deviceID = READ (bus, slot, func, 0x02, word);
0103           uint8 classID   = READ (bus, slot, func, 0x0B, byte);
0104           uint8 subclID   = READ (bus, slot, func, 0x0A, byte);
0105           uint8 prgIFID   = READ (bus, slot, func, 0x09, byte);
0106           uint8 header    = READ (bus, slot, func, 0x0E, byte);
0107 
0108           for (i=0; i<0x10; i++)
0109             devices[num_devices].data[i] =
0110               /* BTW, misaligned read from PCI config space causes
0111                * VMware to crash. :) */
0112               READ (bus, slot, func, i<<2, dword);
0113 
0114 #ifdef DEBUG_PCI
0115           DLOG ("%.02x:%.02x.%x", bus, slot, func);
0116           DLOG ("  %.08x %.08x %.08x %.08x",
0117                 devices[num_devices].data[0],
0118                 devices[num_devices].data[1],
0119                 devices[num_devices].data[2],
0120                 devices[num_devices].data[3]);
0121           DLOG ("  %.08x %.08x %.08x %.08x",
0122                 devices[num_devices].data[4],
0123                 devices[num_devices].data[5],
0124                 devices[num_devices].data[6],
0125                 devices[num_devices].data[7]);
0126           DLOG ("  %.08x %.08x %.08x %.08x",
0127                 devices[num_devices].data[8],
0128                 devices[num_devices].data[9],
0129                 devices[num_devices].data[10],
0130                 devices[num_devices].data[11]);
0131           DLOG ("  %.08x %.08x %.08x %.08x",
0132                 devices[num_devices].data[12],
0133                 devices[num_devices].data[13],
0134                 devices[num_devices].data[14],
0135                 devices[num_devices].data[15]);
0136 #endif
0137 
0138 #ifdef DEBUG_PCI
0139           if (classID == 0x02 && subclID == 0)
0140             printf ("PCI ethernet: %x %x\n", vendorID, deviceID);
0141           if (classID == 0x0C && subclID == 0x03)
0142             printf ("USB host controller: %x %x\n", vendorID, deviceID);
0143           if (pci_search_ven_table (vendorID, &ven))
0144             DLOG ("  %s (0x%x)", ven.VenFull, vendorID);
0145           else
0146             DLOG ("  0x%x", vendorID);
0147           if (pci_search_dev_table (vendorID, deviceID, &dev))
0148             DLOG ("  %s (0x%x)", dev.ChipDesc, deviceID);
0149           else
0150             DLOG ("  0x%x", deviceID);
0151           if (pci_search_class_code_table (classID, subclID, prgIFID, &cc))
0152             DLOG ("  %s (%x) %s (%x) %s (%x)",
0153                   cc.BaseDesc, classID,
0154                   cc.SubDesc, subclID,
0155                   cc.ProgDesc, prgIFID);
0156 #endif
0157 
0158           devices[num_devices].vendor = vendorID;
0159           devices[num_devices].device = deviceID;
0160           devices[num_devices].bus = bus;
0161           devices[num_devices].slot = slot;
0162           devices[num_devices].func = func;
0163           devices[num_devices].classcode = classID;
0164           devices[num_devices].subclass = subclID;
0165           devices[num_devices].progIF = prgIFID;
0166           devices[num_devices].headerType = header;
0167           devices[num_devices].index = num_devices;
0168 
0169           if ((header & 0x7F) == 0) {
0170             /* 6 BARs */
0171             for (i=0; i<6; i++) {
0172               devices[num_devices].bar[i].raw = devices[num_devices].data[4+i];
0173               if (devices[num_devices].bar[i].raw != 0) {
0174                 /* Save raw data */
0175                 uint32 raw = devices[num_devices].bar[i].raw;
0176 #ifdef DEBUG_PCI
0177                 DLOG ("  BAR%d raw: %p", i, devices[num_devices].bar[i].raw);
0178 #endif
0179                 /* Fill with 1s */
0180                 WRITE (bus, slot, func, 0x10 + i*4, dword, ~0);
0181                 /* Read back mask */
0182                 uint32 mask = READ (bus, slot, func, 0x10 + i*4, dword);
0183 #ifdef DEBUG_PCI
0184                 DLOG ("  BAR%d mask: %p", i, mask);
0185 #endif
0186                 devices[num_devices].bar[i].mask = mask;
0187                 /* Restore raw data */
0188                 WRITE (bus, slot, func, 0x10 + i*4, dword, raw);
0189               }
0190             }
0191           }
0192           num_devices++;
0193           if (num_devices >= PCI_MAX_DEVICES) /* reached our limit */
0194             return;
0195         }
0196 
0197 }
0198 
0199 bool
0200 pci_init (void)
0201 {
0202   DLOG("init");
0203   probe ();
0204   return TRUE;
0205 }
0206 
0207 bool
0208 pci_get_device (uint n, pci_device *dev)
0209 {
0210   if (n < num_devices) {
0211     memcpy (dev, &devices[n], sizeof (pci_device));
0212     return TRUE;
0213   }
0214   return FALSE;
0215 }
0216 
0217 bool
0218 pci_find_device (uint16 vendor, uint16 device,
0219                  uint8 classcode, uint8 subclass,
0220                  uint start_index,
0221                  uint* index)
0222 {
0223 #ifdef DEBUG_PCI
0224   DLOG ("find_device (%p,%p,%p,%p,%p) num_devices=%d",
0225         vendor, device, classcode, subclass, start_index, num_devices);
0226 #endif
0227   uint i;
0228   for (i=start_index; i<num_devices; i++) {
0229     if ((vendor == 0xFFFF    || vendor == devices[i].vendor) &&
0230         (device == 0xFFFF    || device == devices[i].device) &&
0231         (classcode == 0xFF   || classcode == devices[i].classcode) &&
0232         (subclass == 0xFF    || subclass == devices[i].subclass)) {
0233       *index = i;
0234       return TRUE;
0235     }
0236   }
0237   return FALSE;
0238 }
0239 
0240 bool
0241 pci_decode_bar (uint index, uint bar_index,
0242                 uint* mem_addr, uint* io_addr, uint* mask)
0243 {
0244   pci_device *dev;
0245   pci_bar *bar;
0246 
0247   if (index >= num_devices) return FALSE;
0248 
0249   dev = &devices[index];
0250 
0251   if ((dev->headerType & 0x7F) == 0) {
0252     /* there are 6 BARs */
0253     if (bar_index >= 6) return FALSE;
0254 
0255     bar = &dev->bar[bar_index];
0256 
0257     DLOG ("pci_decode_bar (%d, %d) bar->raw=%p", index, bar_index, bar->raw);
0258     if (bar->raw & 0x1) {
0259       /* IO port */
0260       if (io_addr)
0261         *io_addr = bar->ioBAR.ioPort << 2;
0262       if (mem_addr)
0263         *mem_addr = 0;
0264       if (mask)
0265         *mask = bar->mask;
0266     } else {
0267       /* Memory-mapped */
0268       if (io_addr)
0269         *io_addr = 0;
0270       if (mem_addr)
0271         *mem_addr = bar->memBAR.baseAddr << 4;
0272       if (mask)
0273         *mask = bar->mask;
0274     }
0275 
0276     return TRUE;
0277   }
0278 
0279   return FALSE;
0280 }
0281 
0282 bool
0283 pci_get_interrupt (uint index, uint* line, uint* pin)
0284 {
0285   if (index >= num_devices) return FALSE;
0286 
0287   *line = devices[index].data[0xF] & 0xFF;
0288   *pin = (devices[index].data[0xF] >> 8) & 0xFF;
0289   return TRUE;
0290 }
0291 
0292 #include "module/header.h"
0293 
0294 static const struct module_ops mod_ops = {
0295   .init = pci_init
0296 };
0297 
0298 DEF_MODULE (pci, "PCI bus driver", &mod_ops, {});
0299 
0300 /*
0301  * Local Variables:
0302  * indent-tabs-mode: nil
0303  * mode: C
0304  * c-file-style: "gnu"
0305  * c-basic-offset: 2
0306  * End:
0307  */
0308 
0309 /* vi: set et sw=2 sts=2: */