PCI cleanup
authorBarret Rhoden <brho@cs.berkeley.edu>
Sun, 21 Nov 2010 22:03:18 +0000 (14:03 -0800)
committerKevin Klues <klueska@cs.berkeley.edu>
Thu, 3 Nov 2011 00:35:57 +0000 (17:35 -0700)
Shame on Paul, there was some really ghetto shit in there.  The IOAPIC
stuff might still work, though it'll need sorted a bit when we get the
ACPI stuff working.

Also required a rewrite of how the NICs config themselves.  Note, you
probably shouldn't have device drivers accessing PCI config space...

kern/arch/i686/e1000.c
kern/arch/i686/ioapic.c
kern/arch/i686/ne2k.c
kern/arch/i686/ne2k.h
kern/arch/i686/pci.c
kern/arch/i686/pci.h
kern/arch/i686/rl8168.c

index bf3ff96..ad50e16 100644 (file)
@@ -138,103 +138,73 @@ void e1000_init() {
 }
 
 int e1000_scan_pci() {
-       
-       extern pci_dev_entry_t pci_dev_map[PCI_MAX_BUS][PCI_MAX_DEV][PCI_MAX_FUNC];
-       extern uint16_t pci_irq_map[PCI_MAX_BUS][PCI_MAX_DEV][PCI_MAX_FUNC];
-
+       struct pci_device *pcidev;
+       uint32_t result;
+       unsigned int once = 0;
        printk("Searching for Intel E1000 Network device...");
-
-       for (int i = 0; i < PCI_MAX_BUS; i++) {
-               for (int j = 0; j < PCI_MAX_DEV; j++) {
-                       for (int k = 0; k < PCI_MAX_FUNC; k++) {
-                               uint32_t address;
-                               uint32_t bus = i;
-                               uint32_t dev = j;
-                               uint32_t func = k;
-                               uint32_t reg = 0; 
-                               uint32_t result  = 0;
-       
-                               uint16_t curr_dev_id = pci_dev_map[i][j][k].dev_id;
-                               uint16_t curr_ven_id = pci_dev_map[i][j][k].ven_id;
-
-                               // Vender DNE
-                               if (curr_ven_id == INVALID_VENDOR_ID) 
-                                       continue;
-
-                               // Ignore non Intel E1000 Devices
-                               if (curr_ven_id != INTEL_VENDOR_ID)
-                                       continue;
-
-                               // Ignore non E1000 devices
-                               if ((curr_dev_id != INTEL_DEV_ID0) && 
-                                   (curr_dev_id != INTEL_DEV_ID1) &&
-                                   (curr_dev_id != INTEL_DEV_ID2))
-                                       continue;
-                               printk(" found on BUS %x DEV %x FUNC %x\n", i, j, k);
-                               
-                               // Skip the management nic on the 16 core box
-                               if ((curr_dev_id == INTEL_DEV_ID1) && (k == 0)) 
-                                       continue;
-
-                               device_id = curr_dev_id;
-
-                               // Find the IRQ
-                               e1000_irq = pci_irq_map[i][j][k];
-                               e1000_debug("-->IRQ: %u\n", e1000_irq);
-
-                               // Loop over the BARs
-                               for (int k = 0; k <= 5; k++) {
-                                       reg = 4 + k;
-                                       address = MK_CONFIG_ADDR(bus, dev, func, reg << 2);     
-                                       outl(PCI_CONFIG_ADDR, address);
+       STAILQ_FOREACH(pcidev, &pci_devices, all_dev) {
+               /* Ignore non Intel Devices */
+               if (pcidev->ven_id != INTEL_VENDOR_ID)
+                       continue;
+               /* Ignore non E1000 devices */
+               if ((pcidev->dev_id != INTEL_DEV_ID0) && 
+                   (pcidev->dev_id != INTEL_DEV_ID1) &&
+                   (pcidev->dev_id != INTEL_DEV_ID2))
+                       continue;
+               printk(" found on BUS %x DEV %x FUNC %x\n", pcidev->bus, pcidev->dev,
+                      pcidev->func);
+               /* TODO: (ghetto) Skip the management nic on the 16 core box.  It is
+                * probably the first one found (check this) */
+               if ((pcidev->dev_id == INTEL_DEV_ID1) && (once++ == 0)) 
+                       continue;
+               /* Find the IRQ */
+               e1000_irq = pcidev->irqline;
+               e1000_debug("-->IRQ: %u\n", e1000_irq);
+               /* Loop over the BARs */
+               for (int k = 0; k <= 5; k++) {
+                       int reg = 4 + k;
+               result = pcidev_read32(pcidev, reg << 2);       // SHAME!
+                       if (result == 0) // (0 denotes no valid data)
+                               continue;
+                       // Read the bottom bit of the BAR. 
+                       if (result & PCI_BAR_IO_MASK) {
+                               result = result & PCI_IO_MASK;
+                               e1000_debug("-->BAR%u: %s --> %x\n", k, "IO", result);
+                       } else {
+                               result = result & PCI_MEM_MASK;
+                               e1000_debug("-->BAR%u: %s --> %x\n", k, "MEM", result);
+                       }
+                       if (k == 0) { // BAR0 denotes the IO Addr for the device
+                               if (result & PCI_BAR_IO_MASK) {
+                                       e1000_debug("-->IO PORT MODE\n");
+                                       panic("IO PORT MODE NOT SUPPORTED\n");
+                               } else {
+                                       e1000_debug("-->MMIO Mode\n");
+                                       e1000_mmio_base_addr = result;
+                                       // Now we do magic to find the size
+                                       // The first non zero bit after we
+                                       // write all 1's denotes the size
+                                       outl(PCI_CONFIG_DATA, 0xFFFFFFFF);
                                        result = inl(PCI_CONFIG_DATA);
-
-                                       if (result == 0) // (0 denotes no valid data)
-                                               continue;
-
-                                       // Read the bottom bit of the BAR. 
-                                       if (result & PCI_BAR_IO_MASK) {
-                                               result = result & PCI_IO_MASK;
-                                               e1000_debug("-->BAR%u: %s --> %x\n", k, "IO", result);
-                                       } else {
-                                               result = result & PCI_MEM_MASK;
-                                               e1000_debug("-->BAR%u: %s --> %x\n", k, "MEM", result);
-                                       }
-                       
-                                       if (k == 0) { // BAR0 denotes the IO Addr for the device
-                                               if (result & PCI_BAR_IO_MASK) {
-                                                       e1000_debug("-->IO PORT MODE\n");
-                                                       panic("IO PORT MODE NOT SUPPORTED\n");
-                                               } else {
-                                                       e1000_debug("-->MMIO Mode\n");
-                                                       e1000_mmio_base_addr = result;
-                                                       // Now we do magic to find the size
-                                                       // The first non zero bit after we
-                                                       // write all 1's denotes the size
-                                                       outl(PCI_CONFIG_DATA, 0xFFFFFFFF);
-                                                       result = inl(PCI_CONFIG_DATA);
-                                                       result = result & PCI_MEM_MASK;
-                                                       result = (result ^ 0xFFFFFFFF) + 1;
-                                                       e1000_addr_size = result;
-                                                        e1000_debug("-->MMIO Size %x\n", e1000_addr_size);
-                                                       outl(PCI_CONFIG_DATA, e1000_mmio_base_addr);
-                               
-#ifdef __CONFIG_E1000_MMIO_HACK__
-                                                       // Map the page in.
-                                                       printd("HACK FOR BROKEN MMIO\n");
-                                                       e1000_mmio_base_addr = E1000_MMIO_ADDR;
-                                                       outl(PCI_CONFIG_DATA, e1000_mmio_base_addr);
-                                                       e1000_mmio_base_addr = 0xfee00000 + 0x1000;
-#endif
-                                               }
-                                       }                                               
+                                       result = result & PCI_MEM_MASK;
+                                       result = (result ^ 0xFFFFFFFF) + 1;
+                                       e1000_addr_size = result;
+                    e1000_debug("-->MMIO Size %x\n", e1000_addr_size);
+                                       outl(PCI_CONFIG_DATA, e1000_mmio_base_addr);
+               
+                                       #ifdef __CONFIG_E1000_MMIO_HACK__
+                                       // Map the page in.
+                                       printd("HACK FOR BROKEN MMIO\n");
+                                       e1000_mmio_base_addr = E1000_MMIO_ADDR;
+                                       outl(PCI_CONFIG_DATA, e1000_mmio_base_addr);
+                                       e1000_mmio_base_addr = 0xfee00000 + 0x1000;
+                                       #endif
                                }
-                               return 0;
-                       }
+                       }                                               
                }
+               return 0;
        }
-       cprintf(" not found. No device configured.\n");
-       
+       printk(" not found. No device configured.\n");
        return -1;
 }
 
index 2e437e6..d07142e 100644 (file)
@@ -51,7 +51,6 @@ void ioapic_init() {
                                                                                                //  mptables and the pci bus.
        
        // Pull in all the stuff we need from mptables and the pci parsing. These are all stack allocated (cant be null)
-       extern pci_irq_entry_t irq_pci_map[NUM_IRQS];
        extern pci_int_device_t pci_int_devices[PCI_MAX_BUS][PCI_MAX_DEV];
        extern ioapic_entry_t ioapic_entries[IOAPIC_MAX_ID];
        extern isa_int_entry_t isa_int_entries[NUM_IRQS];
@@ -60,14 +59,15 @@ void ioapic_init() {
        for (int i = 0; i < NUM_IRQS; i++) {
                // Bus is 16 bits as we use a sential BUS value (INVALID_BUS) to denote an invalid bus
                //  and this valid is out of the range 0->2^8-1
-               uint16_t bus = irq_pci_map[i].bus;
-               uint8_t dev = irq_pci_map[i].dev;
-               uint8_t line = irq_pci_map[i].line;
+               uint16_t bus = irq_pci_map[i]->bus;
+               uint8_t dev = irq_pci_map[i]->dev;
+               uint8_t line = irq_pci_map[i]->irqpin;  // Paul's line, not the irqline
                
                if (bus == INVALID_BUS)
                        continue;
 
                // We do the same trick with the dest apic ID as we do with the PCI Bus, so its wider.
+               /* might be issues with the 'line' for INTA being 0x01 now */
                uint16_t dst_apic_id = pci_int_devices[bus][dev].line[line].dst_apic_id;
                uint8_t dst_apic_int = pci_int_devices[bus][dev].line[line].dst_apic_int;
                
@@ -109,7 +109,8 @@ void ioapic_init() {
                }
                
                // Code to check if this isa irq entry claims to be pci
-               uint16_t pci_bus = irq_pci_map[i].bus;
+               uint16_t pci_bus = irq_pci_map[i]->bus;
+               /* TODO: this stuff probably doesn't work right anymore */
                if (pci_bus != INVALID_BUS) {
                        // PCI bus had an entry for this irq, but we didn't set it during our pci run
                        //  This means it is likely a broken mptable implimentation. this happens on bochs and kvm
index 5576550..8217313 100644 (file)
@@ -100,66 +100,39 @@ void ne2k_init() {
 
 
 int ne2k_scan_pci() {
-       
-       extern pci_dev_entry_t pci_dev_map[PCI_MAX_BUS][PCI_MAX_DEV][PCI_MAX_FUNC];
-       extern uint16_t pci_irq_map[PCI_MAX_BUS][PCI_MAX_DEV][PCI_MAX_FUNC];
-
-       cprintf("Searching for NE2000 Network device...");
-
-       for (int i = 0; i < PCI_MAX_BUS; i++)
-               for (int j = 0; j < PCI_MAX_DEV; j++)
-                       for (int k = 0; k < PCI_MAX_FUNC; k++) {
-                               uint32_t address;
-                               uint32_t lbus = i;
-                               uint32_t ldev = j;
-                               uint32_t lfunc = k;
-                               uint32_t lreg = 0; 
-                               uint32_t result  = 0;
-       
-                               uint16_t dev_id = pci_dev_map[i][j][k].dev_id;
-                               uint16_t ven_id = pci_dev_map[i][j][k].ven_id;
-
-                               // Vender DNE
-                               if (ven_id == INVALID_VENDOR_ID) 
-                                       continue;
-
-                               // Ignore non RealTek 8168 Devices
-                               if (ven_id != NE2K_VENDOR_ID || dev_id != NE2K_DEV_ID)
-                                       continue;
-                               cprintf(" found on BUS %x DEV %x\n", i, j);
-
-                               // Find the IRQ
-                               ne2k_irq = pci_irq_map[i][j][k];
-                               ne2k_debug("-->IRQ: %u\n", ne2k_irq);
-
-                               // Loop over the BARs
-                               for (int k = 0; k <= 5; k++) {
-                                       lreg = 4 + k;
-                                       address = MK_CONFIG_ADDR(lbus, ldev, lfunc, lreg << 2); 
-                               outl(PCI_CONFIG_ADDR, address);
-                               result = inl(PCI_CONFIG_DATA);
-                                       
-                                       if (result == 0) // (0 denotes no valid data)
-                                               continue;
-
-                                       // Read the bottom bit of the BAR. 
-                                       if (result & PCI_BAR_IO_MASK) {
-                                               result = result & PCI_IO_MASK;
-                                               ne2k_debug("-->BAR%u: %s --> %x\n", k, "IO", result);
-                                       } else {
-                                               result = result & PCI_MEM_MASK;
-                                               ne2k_debug("-->BAR%u: %s --> %x\n", k, "MEM", result);
-                                       }
-                       
-                                       // TODO Switch to memory mapped instead of IO?
-                                       if (k == 0) // BAR0 denotes the IO Addr for the device
-                                               ne2k_io_base_addr = result;                                             
-                               }
-                               
+       struct pci_device *pcidev;
+       uint32_t result;
+       printk("Searching for NE2000 Network device...");
+       STAILQ_FOREACH(pcidev, &pci_devices, all_dev) {
+               /* Ignore non NE2K Devices */
+               if ((pcidev->ven_id != NE2K_VENDOR_ID) ||
+                  (pcidev->dev_id != NE2K_DEV_ID))
+                       continue;
+               printk(" found on BUS %x DEV %x\n", pcidev->bus, pcidev->dev);
+               /* Find the IRQ */
+               ne2k_irq = pcidev->irqline;
+               ne2k_debug("-->IRQ: %u\n", ne2k_irq);
+               /* Loop over the BARs */
+               for (int k = 0; k <= 5; k++) {
+                       int reg = 4 + k;
+               result = pcidev_read32(pcidev, reg << 2);       // SHAME!
+                       if (result == 0) // (0 denotes no valid data)
+                               continue;
+                       // Read the bottom bit of the BAR. 
+                       if (result & PCI_BAR_IO_MASK) {
+                               result = result & PCI_IO_MASK;
+                               ne2k_debug("-->BAR%u: %s --> %x\n", k, "IO", result);
+                       } else {
+                               result = result & PCI_MEM_MASK;
+                               ne2k_debug("-->BAR%u: %s --> %x\n", k, "MEM", result);
+                       }
+                       // TODO Switch to memory mapped instead of IO?
+                       if (k == 0) // BAR0 denotes the IO Addr for the device
+                               ne2k_io_base_addr = result;                                             
+               }
                return 0;
        }
-       cprintf(" not found. No device configured.\n");
-       
+       printk(" not found. No device configured.\n");
        return -1;
 }
 
index 54f94bb..07e2b0f 100644 (file)
@@ -4,6 +4,7 @@
 #include <ros/common.h>
 #include <trap.h>
 #include <pmap.h>
+#include <arch/pci.h>
 #include <arch/nic_common.h>
 
 #define ne2k_debug(...)  //cprintf(__VA_ARGS__)  
 
 #define NIC_IRQ_CPU                    5
 
-// Macro for formatting PCI Configuration Address queries
-#define MK_CONFIG_ADDR(BUS, DEV, FUNC, REG) (unsigned long)( (BUS << 16) | (DEV << 11) | \
-                                                             (FUNC << 8) | REG  | \
-                                                             ((uint32_t)0x80000000))
 #define NE2K_VENDOR_ID 0x10EC
 #define NE2K_DEV_ID 0x8029
 
index 7276444..766cf32 100644 (file)
-/*
- * Copyright (c) 2009 The Regents of the University of California
+/* Copyright (c) 2009, 2010 The Regents of the University of California
  * See LICENSE for details.
- */
-
-#ifdef __SHARC__
-#pragma nosharc
-#endif
-// Not currently sharc complient. 
-
-/** @file
- * @brief Basic PCI Driver.
- *
- * This file is responsible for the scanning the PCI bus and recording
- * all the information needed for ouR OS to function. 
- *
- * No PCI Specifications (or even consulted) were harmed in the making of this file.
- *
- * @author Paul Pearce <pearce@eecs.berkeley.edu>
- *
- * @todo Build an entire useful PCI subsystem, not this hack with a few data structures laying around
  *
- */
+ * Barret Rhoden <brho@cs.berkeley.edu>
+ * Original by Paul Pearce <pearce@eecs.berkeley.edu> */
 
 #include <arch/x86.h>
+#include <arch/pci.h>
 #include <stdio.h>
 #include <string.h>
-#include <arch/pci.h>
-
-// A value of INVALID_IRQ (something 256 or larger) means invalid
-uint16_t pci_irq_map[PCI_MAX_BUS][PCI_MAX_DEV][PCI_MAX_FUNC];
-
-pci_dev_entry_t pci_dev_map[PCI_MAX_BUS][PCI_MAX_DEV][PCI_MAX_FUNC];
-
-// NOTE: If we care about ALL devices associated with an IRQ, not just the last device, this needs to be some sort of linked structure
-pci_irq_entry_t irq_pci_map[NUM_IRQS];
-
-/**
- * @brief Perform the actual PCI bus parsing
- *
- * See file description.
- * 
- * This function must be called during bootup, before ioapic_init().
- */
-void pci_init() {
-       
-       // Initalize the irq->pci table (pci->irq below)
-       // Setting all 1's forces an invalid entry, as bus = INVALID_BUS = 0xFFFF.
-       memset(irq_pci_map, 0xFF, sizeof(irq_pci_map));
-       
-       uint32_t address;
-       uint32_t bus = 0;
-       uint32_t dev = 0;
-       uint32_t func = 0;
-       uint32_t reg = 0; 
-       uint32_t result  = 0;
-       pci_debug("Scanning PCI Bus....\n");
-
+#include <assert.h>
+#include <kmalloc.h>
+
+/* Which pci devices hang off of which irqs */
+/* TODO: make this an array of SLISTs (pain from ioapic.c, etc...) */
+struct pci_device *irq_pci_map[NUM_IRQS] = {0};
+
+/* List of all discovered devices */
+struct pcidev_stailq pci_devices = STAILQ_HEAD_INITIALIZER(pci_devices);
+
+/* Scans the PCI bus.  Won't actually work for anything other than bus 0, til we
+ * sort out how to handle bridge devices. */
+void pci_init(void) {
+       uint32_t result = 0;
+       uint16_t dev_id, ven_id;
+       struct pci_device *pcidev;
        for (int i = 0; i < PCI_MAX_BUS; i++)
                for (int j = 0; j < PCI_MAX_DEV; j++)
                        for (int k = 0; k < PCI_MAX_FUNC; k++) {
-
-                               bus = i;
-                               dev = j;
-                               func = k;
-                               reg = 0; // PCI REGISTER 0
-                               
-                               // Set the fields invalid.
-                               pci_irq_map[i][j][k] = INVALID_IRQ;
-                               pci_dev_map[i][j][k].dev_id = INVALID_VENDOR_ID;
-
-                               address = MK_CONFIG_ADDR(bus, dev, func, reg); 
-
-                               // Probe current bus/dev
-                               outl(PCI_CONFIG_ADDR, address);
-                               result = inl(PCI_CONFIG_DATA);
-       
-                               uint16_t dev_id = result >> PCI_DEVICE_OFFSET;
-                               uint16_t ven_id = result & PCI_VENDOR_MASK;
-
-                               // Vender DNE
+                               result = pci_read32(i, j, k, PCI_DEV_VEND_REG);
+                               dev_id = result >> PCI_DEVICE_OFFSET;
+                               ven_id = result & PCI_VENDOR_MASK;
+                               /* Skip invalid IDs (not a device) */
                                if (ven_id == INVALID_VENDOR_ID) 
                                        continue;
-
-                               pci_debug("Found device on BUS %x DEV %x FUNC %x: DEV_ID: %x VEN_ID: %x\n", i, j, k, dev_id, ven_id);
-
-                               // Find the IRQ
-                               address = MK_CONFIG_ADDR(bus, dev, func, PCI_IRQ_REG);
-                               outl(PCI_CONFIG_ADDR, address);
-                               uint16_t irq = inl(PCI_CONFIG_DATA) & PCI_IRQ_MASK;
-                               pci_debug("-->IRQ: %u\n", irq);
-                               
-                               // Find the line (a-d)
-                               address = MK_CONFIG_ADDR(bus, dev, func, PCI_IRQ_REG);
-                               outl(PCI_CONFIG_ADDR, address);
-                               uint8_t line = (inl(PCI_CONFIG_DATA) & PCI_LINE_MASK) >> PCI_LINE_SHFT;
-                               
-                               // If intn == 0, no interrupts used.
-                               if (line != INVALID_LINE) {
-                                       
-                                       // Now shift A to 0, B to 1, etc.
-                                       // This starts off as A 1, B 2 (grr)
-                                       line--;
-                               
-                                       pci_irq_map[i][j][k] = irq;
-                                       pci_dev_map[i][j][k].dev_id = dev_id;
-                                       pci_dev_map[i][j][k].ven_id = ven_id;
-                                       irq_pci_map[irq].bus = i;
-                                       irq_pci_map[irq].dev = j;
-                                       irq_pci_map[irq].func = k;
-                                       irq_pci_map[irq].line = line;
-                                       
-                                       // @todo We may want to perform some check to make sure we arent overwriting some current irq entry and maintain that info
+                               pcidev = kmalloc(sizeof(struct pci_device), 0);
+                               pcidev->bus = i;
+                               pcidev->dev = j;
+                               pcidev->func = k;
+                               pcidev->dev_id = dev_id;
+                               pcidev->ven_id = ven_id;
+                               /* Get the Class/subclass */
+                               result = pcidev_read32(pcidev, PCI_CLASS_REG);
+                               pcidev->class = result >> 24;
+                               pcidev->subclass = (result >> 16) & 0xff;
+                               /* All device types (0, 1, 2) have the IRQ in the same place */
+                               result = pcidev_read32(pcidev, PCI_IRQ_STD);
+                               /* This is the PIC IRQ the device is wired to */
+                               pcidev->irqline = result & PCI_IRQLINE_MASK;
+                               /* This is the interrupt pin the device uses (INTA# - INTD#) */
+                               pcidev->irqpin = (result & PCI_IRQPIN_MASK) >> PCI_IRQPIN_SHFT;
+                               printk("PCI: %d:%d:%d Vend/Dev: %04p/%04p Class/Sub: %02p/%02p "
+                                      "IRQ: %d Pin: %p\n", pcidev->bus, pcidev->dev,
+                                      pcidev->func, pcidev->ven_id, pcidev->dev_id,
+                                      pcidev->class, pcidev->subclass, pcidev->irqline,
+                                      pcidev->irqpin);
+                               if (pcidev->irqpin != PCI_NOINT) {
+                                       /* TODO: use a list (check for collisions for now) */
+                                       assert(!irq_pci_map[pcidev->irqline]);
+                                       irq_pci_map[pcidev->irqline] = pcidev;
                                }
-                               
-
-                               /* Loop over the BARs
-                                * Right now we don't do anything useful with this data. 
-                                * This is legacy code in which I pulled data from the BARS during NIC development
-                                * At some point we will have to use this, so the code is still here.
-                                */
+                               /* Loop over the BARs Right now we don't do anything useful with
+                                * this data.  This is legacy code in which I pulled data from
+                                * the BARS during NIC development At some point we will have to
+                                * use this, so the code is still here. */
                                
                                // Note: These magic numbers are from the PCI spec (according to OSDev).
+                               #if 0
                                #ifdef CHECK_BARS
                                for (int k = 0; k <= 5; k++) {
                                        reg = 4 + k;
@@ -142,7 +86,84 @@ void pci_init() {
                                        }                                       
                                }
                                #endif
+                               #endif
                                
-                               pci_debug("\n");
-                       }               
+                               STAILQ_INSERT_TAIL(&pci_devices, pcidev, all_dev);
+                       }
+}
+
+/* Helper to read 32 bits from the config space of B:D:F.  'Offset' is how far
+ * into the config space we offset before reading, aka: where we are reading. */
+uint32_t pci_read32(unsigned short bus, unsigned short dev, unsigned short func,
+                    unsigned short offset)
+{
+       /* Send type 1 requests for everything beyond bus 0.  Note this does nothing
+        * until we configure the PCI bridges (which we don't do yet). */
+       if (bus !=  0)
+               offset |= 0x1;
+       outl(PCI_CONFIG_ADDR, MK_CONFIG_ADDR(bus, dev, func, offset));
+       return inl(PCI_CONFIG_DATA);
+}
+
+/* Same, but writes (doing 32bit at a time).  Never actually tested (not sure if
+ * PCI lets you write back). */
+void pci_write32(unsigned short bus, unsigned short dev, unsigned short func,
+                    unsigned short offset, uint32_t value)
+{
+       outl(PCI_CONFIG_ADDR, MK_CONFIG_ADDR(bus, dev, func, offset));
+       outl(PCI_CONFIG_DATA, value);
+}
+
+/* Helper to read from a specific device's config space. */
+uint32_t pcidev_read32(struct pci_device *pcidev, unsigned short offset)
+{
+       return pci_read32(pcidev->bus, pcidev->dev, pcidev->func, offset);
 }
+
+/* Helper to write to a specific device */
+void pcidev_write32(struct pci_device *pcidev, unsigned short offset,
+                    uint32_t value)
+{
+       pci_write32(pcidev->bus, pcidev->dev, pcidev->func, offset, value);
+}
+
+/* Gets any old raw bar. */
+uint32_t pci_getbar(struct pci_device *pcidev, unsigned int bar)
+{
+       uint32_t value, type;
+       if (bar > 5)
+               panic("Nonexistant bar requested!");
+       value = pcidev_read32(pcidev, PCI_HEADER_REG);
+       type = (value >> 16) & 0xff;
+       /* Only types 0 and 1 have BARS */
+       if ((type != 0x00) && (type != 0x01))
+               return 0;
+       /* Only type 0 has BAR2 - BAR5 */
+       if ((bar > 1) && (type != 0x00))
+               return 0;
+       return pcidev_read32(pcidev, PCI_BAR0_STD + bar * PCI_BAR_OFF);
+}
+
+/* Determines if a given bar is IO (o/w, it's mem) */
+bool pci_is_iobar(uint32_t bar)
+{
+       return bar & PCI_BAR_IO;
+}
+
+/* Helper to get the address from a membar.  Check the type beforehand */
+uint32_t pci_getmembar32(uint32_t bar)
+{
+       uint8_t type = bar & PCI_MEMBAR_TYPE;
+       if (type != PCI_MEMBAR_32BIT) {
+               warn("Unhandled PCI membar type: %02p\n", type >> 1);
+               return 0;
+       }
+       return bar & 0xfffffff0;
+}
+
+/* Helper to get the address from an IObar.  Check the type beforehand */
+uint32_t pci_getiobar32(uint32_t bar)
+{
+       return bar & 0xfffffffc;
+}
+
index ce35923..be07b98 100644 (file)
-/*
- * Copyright (c) 2009 The Regents of the University of California
+/* Copyright (c) 2009, 2010 The Regents of the University of California
  * See LICENSE for details.
- */
+ *
+ * Barret Rhoden <brho@cs.berkeley.edu>
+ * Original by Paul Pearce <pearce@eecs.berkeley.edu> */
 
-#ifndef ROS_INC_PCI_H
-#define ROS_INC_PCI_H
+#ifndef ROS_ARCH_PCI_H
+#define ROS_ARCH_PCI_H
 
-#define pci_debug(...) // printk(__VA_ARGS__)  
+#include <ros/common.h>
+#include <sys/queue.h>
+
+#define pci_debug(...)  printk(__VA_ARGS__)  
 
 // Macro for creating the address fed to the PCI config register 
-// Several generations away from OSDev inline code.
-#define MK_CONFIG_ADDR(BUS, DEV, FUNC, REG) (unsigned long)( (BUS << 16) | (DEV << 11) | \
-                                                             (FUNC << 8) | REG  | \
-                                                             ((uint32_t)0x80000000))
+// TODO: get rid of this, in favor of the helpers
+#define MK_CONFIG_ADDR(BUS, DEV, FUNC, REG) (unsigned long)(((BUS) << 16)   |  \
+                                                            ((DEV) << 11)   |  \
+                                                            ((FUNC) << 8)   |  \
+                                                            ((REG) & 0xfc)  |  \
+                                                            (0x80000000))
 
-// General PCI Magic numbers yanked from OSDev / BSD. Yay magic!
 #define PCI_CONFIG_ADDR     0xCF8
 #define PCI_CONFIG_DATA     0xCFC
 #define INVALID_VENDOR_ID   0xFFFF
 
-#define INVALID_IRQ                    0xFFFF
+/* TODO: gut this (when the IOAPIC is fixed) */
 #define INVALID_BUS                    0xFFFF
-#define INVALID_LINE           0x0000
-
-#define PCI_IO_MASK         0xFFF8
-#define PCI_MEM_MASK        0xFFFFFFF0
-#define PCI_IRQ_MASK           0xFF
-#define PCI_LINE_MASK          0xFF00
-#define PCI_LINE_SHFT          0x8
-#define PCI_VENDOR_MASK                0xFFFF
+
+#define PCI_IO_MASK                    0xfff8
+#define PCI_MEM_MASK           0xfffffff0
+#define PCI_IRQLINE_MASK       0x000000ff
+#define PCI_IRQPIN_MASK                0x0000ff00
+#define PCI_IRQPIN_SHFT                8
+#define PCI_VENDOR_MASK                0xffff
 #define PCI_DEVICE_OFFSET      0x10
-#define PCI_IRQ_REG                    0x3c
+
+#define PCI_NOINT                      0x00
+#define PCI_INTA                       0x01
+#define PCI_INTB                       0x02
+#define PCI_INTC                       0x03
+#define PCI_INTD                       0x04
+
+/* PCI Register Config Space */
+#define PCI_DEV_VEND_REG       0x00
+#define PCI_STAT_CMD_REG       0x04
+#define PCI_CLASS_REG          0x08
+#define PCI_HEADER_REG         0x0c
+/* Config space for header type 0x00  (Standard) */
+#define PCI_BAR0_STD           0x10
+#define PCI_BAR1_STD           0x14
+#define PCI_BAR2_STD           0x18
+#define PCI_BAR3_STD           0x1c
+#define PCI_BAR4_STD           0x20
+#define PCI_BAR5_STD           0x24
+#define PCI_BAR_OFF                    0x04
+#define PCI_CARDBUS_STD                0x28
+#define PCI_SUBSYSTEM_STD      0x2C
+#define PCI_EXPROM_STD         0x30
+#define PCI_CAPAB_STD          0x34
+#define PCI_IRQ_STD                    0x3c
+/* Config space for header type 0x01 (PCI-PCI bridge) */
+#define PCI_BAR0_BR                    0x10
+#define PCI_BAR1_BR                    0x14
+#define PCI_BUSINFO_BR         0x18
+#define PCI_IOINFO_BR          0x1c
+#define PCI_MEM_BR                     0x20
+#define PCI_MEM_PRFC_BR                0x24
+#define PCI_PRFC_BASE_BR       0x28
+#define PCI_PRFC_LIM_BR                0x2C
+#define PCI_IO_LIM_BR          0x30
+#define PCI_CAPAB_BR           0x34
+#define PCI_IRQ_BDG_BR         0x3c
+/* Config space for header type 0x02 (PCI-Cardbus bridge) */
+#define PCI_SOC_BASE_CB                0x10
+#define PCI_SEC_STAT_CB                0x14
+#define PCI_BUS_INFO_CB                0x18
+#define PCI_MEM_BASE0_CB       0x1c
+#define PCI_MEM_LIMIT0_CB      0x20
+#define PCI_MEM_BASE1_CB       0x24
+#define PCI_MEM_LIMIT1_CB      0x28
+#define PCI_IO_BASE0_CB                0x2c
+#define PCI_IO_LIMIT0_CB       0x30
+#define PCI_IO_BASE1_CB                0x34
+#define PCI_IO_LIMIT1_CB       0x38
+#define PCI_IRQ_CB                     0x3c
+#define PCI_SUBSYS_CB          0x40
+#define PCI_16BIT_CB           0x44
+
+/* Legacy Paul-mapping */
+#define PCI_IRQ_REG                    PCI_IRQ_STD
+
+/* Command Register Flags */
+#define PCI_CMD_IO_SPC         (1 << 0)
+#define PCI_CMD_MEM_SPC                (1 << 1)
+#define PCI_CMD_BUS_MAS                (1 << 2)
+#define PCI_CMD_SPC_CYC                (1 << 3)
+#define PCI_CMD_WR_EN          (1 << 4)
+#define PCI_CMD_VGA                    (1 << 5)
+#define PCI_CMD_PAR_ERR                (1 << 6)
+/* #define PCI_CMD_XXX         (1 << 7) Reserved */
+#define PCI_CMD_SERR           (1 << 8)
+#define PCI_CMD_FAST_EN                (1 << 9)
+#define PCI_CMD_IRQ_DIS                (1 << 10)
+
+/* Status Register Flags (Bits 9 and 10 are one field) */
+/* Bits 0, 1, and 2 are reserved */
+#define PCI_ST_IRQ_STAT                (1 << 3)
+#define PCI_ST_CAP_LIST                (1 << 4)
+#define PCI_ST_66MHZ           (1 << 5)
+/* #define PCI_CMD_XXX         (1 << 6)  Reserved */
+#define PCI_ST_FAST_CAP                (1 << 7)
+#define PCI_ST_MASPAR_ERR      (1 << 8)
+#define PCI_ST_DEVSEL_TIM      (3 << 9)        /* 2 bits */
+#define PCI_ST_SIG_TAR_ABRT    (1 << 11)
+#define PCI_ST_REC_TAR_ABRT    (1 << 12)
+#define PCI_ST_REC_MAS_ABRT    (1 << 13)
+#define PCI_ST_SIG_SYS_ERR     (1 << 14)
+#define PCI_ST_PAR_ERR         (1 << 15)
+
+/* BARS: Base Address Registers */
+#define PCI_BAR_IO_MASK                0x1
+#define PCI_BAR_IO PCI_BAR_IO_MASK
+#define PCI_MEMBAR_TYPE        (3 << 1)
+#define PCI_MEMBAR_32BIT       0x0
+#define PCI_MEMBAR_RESV        0x2                     /* type 0x1 shifted to MEMBAR_TYPE */
+#define PCI_MEMBAR_64BIT       0x4                     /* type 0x2 shifted to MEMBAR_TYPE */
 
 #define PCI_MAX_BUS                    256
 #define PCI_MAX_DEV                    32
 #define PCI_MAX_FUNC           8
-#define PCI_BAR_IO_MASK                0x1
 #define NUM_IRQS                       256
 
 // Offset used for indexing IRQs. Why isnt this defined elsewhere?
 // Run the PCI Code to loop over the PCI BARs. For now we don't use the BARs, dont check em.
 #define CHECK_BARS                     0
 
-typedef struct PCIIRQENTRY {
-       uint16_t bus; // Bus larger than 255 denotes invalid entry.
-                                 // This is why bus is 16 bits not 8.
-       uint8_t dev;
-       uint8_t func;
-       uint8_t line;
-} pci_irq_entry_t;
+/* Struct for some meager contents of a PCI device */
+struct pci_device {
+       STAILQ_ENTRY(pci_device)        all_dev;        /* list of all devices */
+       SLIST_ENTRY(pci_device)         irq_dev;        /* list of all devs off an irq */
+       uint8_t                                         bus;
+       uint8_t                                         dev;
+       uint8_t                                         func;
+       uint16_t                                        dev_id;
+       uint16_t                                        ven_id;
+       uint8_t                                         irqline;
+       uint8_t                                         irqpin;
+       uint16_t                                        class;
+       uint16_t                                        subclass;
+};
+
+/* List of all discovered devices */
+STAILQ_HEAD(pcidev_stailq, pci_device);
+SLIST_HEAD(pcidev_slist, pci_device);
+extern struct pcidev_stailq pci_devices;
+/* Mapping of irq -> PCI device (TODO: make this PCI-agnostic) */
+extern struct pci_device *irq_pci_map[NUM_IRQS];
 
-typedef struct PCIDEVENTRY {
-       uint16_t dev_id; 
-       uint16_t ven_id;
-} pci_dev_entry_t;
+void pci_init(void);
 
-void pci_init();
+/* Read and write helpers (Eventually, we should have these be statics, since no
+ * device should touch PCI config space). */
+uint32_t pci_read32(unsigned short bus, unsigned short dev, unsigned short func,
+                    unsigned short offset);
+void pci_write32(unsigned short bus, unsigned short dev, unsigned short func,
+                    unsigned short offset, uint32_t value);
+uint32_t pcidev_read32(struct pci_device *pcidev, unsigned short offset);
+void pcidev_write32(struct pci_device *pcidev, unsigned short offset,
+                    uint32_t value);
+uint32_t pci_getbar(struct pci_device *pcidev, unsigned int bar);
+bool pci_is_iobar(uint32_t bar);
+uint32_t pci_getmembar32(uint32_t bar);
+uint32_t pci_getiobar32(uint32_t bar);
 
-#endif /* !ROS_INC_PCI_H */
+#endif /* ROS_ARCH_PCI_H */
index b2f1910..d12b163 100644 (file)
@@ -121,68 +121,41 @@ void rl8168_init() {
 
 
 int rl8168_scan_pci() {
-       
-       extern pci_dev_entry_t pci_dev_map[PCI_MAX_BUS][PCI_MAX_DEV][PCI_MAX_FUNC];
-       extern uint16_t pci_irq_map[PCI_MAX_BUS][PCI_MAX_DEV][PCI_MAX_FUNC];
-
-       cprintf("Searching for RealTek 8168 Network device...");
-
-       for (int i = 0; i < PCI_MAX_BUS; i++)
-               for (int j = 0; j < PCI_MAX_DEV; j++)
-                       for (int k = 0; k < PCI_MAX_FUNC; k++) {
-                               uint32_t address;
-                               uint32_t bus = i;
-                               uint32_t dev = j;
-                               uint32_t func = k;
-                               uint32_t reg = 0; 
-                               uint32_t result  = 0;
-       
-                               uint16_t dev_id = pci_dev_map[i][j][k].dev_id;
-                               uint16_t ven_id = pci_dev_map[i][j][k].ven_id;
-
-                               // Vender DNE
-                               if (ven_id == INVALID_VENDOR_ID) 
-                                       continue;
-
-                               // Ignore non RealTek 8168 Devices
-                               if (ven_id != REALTEK_VENDOR_ID || dev_id != REALTEK_DEV_ID)
-                                       continue;
-                               cprintf(" found on BUS %x DEV %x\n", i, j);
-
-                               // Find the IRQ
-                               rl8168_irq = pci_irq_map[i][j][k];
-                               rl8168_debug("-->IRQ: %u\n", rl8168_irq);
-
-                               // Loop over the BARs
-                               for (int k = 0; k <= 5; k++) {
-                                       reg = 4 + k;
-                                       address = MK_CONFIG_ADDR(bus, dev, func, reg << 2);     
-                               outl(PCI_CONFIG_ADDR, address);
-                               result = inl(PCI_CONFIG_DATA);
-                                       
-                                       if (result == 0) // (0 denotes no valid data)
-                                               continue;
-
-                                       // Read the bottom bit of the BAR. 
-                                       if (result & PCI_BAR_IO_MASK) {
-                                               result = result & PCI_IO_MASK;
-                                               rl8168_debug("-->BAR%u: %s --> %x\n", k, "IO", result);
-                                       } else {
-                                               result = result & PCI_MEM_MASK;
-                                               rl8168_debug("-->BAR%u: %s --> %x\n", k, "MEM", result);
-                                       }
-                       
-                                       // TODO Switch to memory mapped instead of IO?
-                                       if (k == 0) // BAR0 denotes the IO Addr for the device
-                                               rl8168_io_base_addr = result;                                           
-                               }
-               
-               rl8168_debug("-->hwrev: %x\n", inl(rl8168_io_base_addr + RL_HWREV_REG) & RL_HWREV_MASK);
-               
+       struct pci_device *pcidev;
+       uint32_t result;
+       printk("Searching for RealTek 8168 Network device...");
+       STAILQ_FOREACH(pcidev, &pci_devices, all_dev) {
+               /* Ignore non RealTek 8168 Devices */
+               if ((pcidev->ven_id != REALTEK_VENDOR_ID) ||
+                  (pcidev->dev_id != REALTEK_DEV_ID))
+                       continue;
+               printk(" found on BUS %x DEV %x\n", pcidev->bus, pcidev->dev);
+               /* Find the IRQ */
+               rl8168_irq = pcidev->irqline;
+               rl8168_debug("-->IRQ: %u\n", rl8168_irq);
+               /* Loop over the BARs */
+               for (int k = 0; k <= 5; k++) {
+                       int reg = 4 + k;
+               result = pcidev_read32(pcidev, reg << 2);       // SHAME!
+                       if (result == 0) // (0 denotes no valid data)
+                               continue;
+                       // Read the bottom bit of the BAR. 
+                       if (result & PCI_BAR_IO_MASK) {
+                               result = result & PCI_IO_MASK;
+                               rl8168_debug("-->BAR%u: %s --> %x\n", k, "IO", result);
+                       } else {
+                               result = result & PCI_MEM_MASK;
+                               rl8168_debug("-->BAR%u: %s --> %x\n", k, "MEM", result);
+                       }
+                       // TODO Switch to memory mapped instead of IO?
+                       if (k == 0) // BAR0 denotes the IO Addr for the device
+                               rl8168_io_base_addr = result;                                           
+               }
+               rl8168_debug("-->hwrev: %x\n",
+                            inl(rl8168_io_base_addr + RL_HWREV_REG) & RL_HWREV_MASK);
                return 0;
        }
-       cprintf(" not found. No device configured.\n");
-       
+       printk(" not found. No device configured.\n");
        return -1;
 }