-PCI scanning
[pintos-anon] / src / devices / pci.c
index 1fac33c9b6733dae12a2722e9f4f066ea32f36c4..066588470dae91759e4cb16349c6873b46df7f9f 100755 (executable)
@@ -1,8 +1,14 @@
 #include <debug.h>
+#include <list.h>
 #include <stdbool.h>
 #include <stdio.h>
-#include "threads/io.h"
 #include "devices/pci.h"
+#include "threads/io.h"
+#include "threads/malloc.h"
+
+struct list pci_dev_list;
+
+static void scan_bus(uint8_t bus);
 
 static uint32_t
 pci_read_config (unsigned bus, unsigned dev, unsigned func, unsigned reg) 
@@ -17,56 +23,115 @@ pci_read_config (unsigned bus, unsigned dev, unsigned func, unsigned reg)
   return inl (0xcfc);
 }
 
+static void
+pci_dump_dev (struct pci_dev *dev) 
+{
+  printf ("%04x:%02x:%02x.%x PCI device %04x:%04x\n", 
+         0, dev->bus_id, dev->devfn >> 4, dev->devfn & 0xf, 
+         dev->ven_id, dev->dev_id);
+  printf ("Class: %02x:%02x:%02x\n", 
+         dev->base_class, dev->sub_class, dev->interface);
+}
+
 static bool
-scan_device (int bus, int dev, int func) 
+scan_device (uint8_t bus, uint8_t dev, uint8_t func) 
 {
   uint32_t cfg[16];
+  uint8_t *byte_cfg;
   int dev_id, vendor_id;
   int line;
   int reg;
+  struct pci_dev *new_pci_dev;
 
+  byte_cfg = (uint8_t *) cfg;
+
+  /* Read configuration space header */
   for (reg = 0; reg < 16; reg++)
     cfg[reg] = pci_read_config (bus, dev, func, reg);
+  
+  /* Get vendor and device ID */
   dev_id = cfg[0] >> 16;
   vendor_id = cfg[0] & 0xffff;
 
-  if (dev_id == 0 || dev_id == 0xffff
-      || vendor_id == 0 || vendor_id == 0xffff)
+  if (dev_id == 0 || dev_id == PCI_BAD_DEVICE || 
+      vendor_id == 0 || vendor_id == PCI_BAD_DEVICE)
     return 0;
 
-  printf ("%04x:%02x:%02x.%x PCI device %04x:%04x\n",
-          0, bus, dev, func, vendor_id, dev_id);
-  for (line = 0; line < 4; line++) 
+  /* We have a valid PCI device, set it up */
+  new_pci_dev = malloc (sizeof *new_pci_dev);
+  if (!new_pci_dev)
+    PANIC ("couldn't allocate memory for PCI device");
+
+  new_pci_dev->bus_id = bus;
+  new_pci_dev->devfn = (dev << 4) | func;
+  new_pci_dev->ven_id = vendor_id;
+  new_pci_dev->dev_id = dev_id;
+  new_pci_dev->base_class = byte_cfg[PCI_REG_CLASS_BASE];
+  new_pci_dev->sub_class = byte_cfg[PCI_REG_CLASS_SUB];
+  new_pci_dev->interface = byte_cfg[PCI_REG_CLASS_INTERFACE];
+  list_push_front (&pci_dev_list, &new_pci_dev->elem);
+  
+  /* Debugging output */
+  pci_dump_dev(new_pci_dev);
+  for (line = 0; line < 16; line++) 
     {
       int byte;
-
-      printf ("%02x:", line * 16);
-      for (byte = 0; byte < 16; byte++)
-        printf (" %02x", ((uint8_t *) cfg)[line * 16 + byte]);
+      
+      printf ("%02x:", line * 4);
+      for (byte = 3; byte >= 0; byte--)
+       printf (" %02x", byte_cfg[line * 4 + byte]);
       printf ("\n");
     }
   printf ("\n");
-
-  return cfg[3] & 0x00800000;
+  
+  /* If device is PCI-to-PCI bridge, scan the bus behind it */
+  if (new_pci_dev->base_class == PCI_BRIDGE_BASE_CLASS &&
+      new_pci_dev->sub_class == PCI_BRIDGE_SUB_CLASS &&
+      (byte_cfg[PCI_REG_HEADER_TYPE] & 0x3f) == PCI_BRIDGE_HEADER_TYPE)
+    scan_bus(byte_cfg[PCI_BRIDGE_REG_SBUS]);
+  
+  return byte_cfg[PCI_REG_HEADER_TYPE] & 0x80;
 }
 
-void
-pci_scan (void) 
+static void
+scan_bus(uint8_t bus)
 {
-  int dev;
+  uint8_t dev;
+
+  printf ("PCI: Scanning bus (%u)\n", bus);
 
-  printf ("PCI BUS: Scanning \n");
-  
   for (dev = 0; dev < 32; dev++) 
     {
-      if (scan_device (0, dev, 0)) 
+      /* Returns true if device is multi-function */
+      if (scan_device (bus, dev, 0)) 
         {
           int func;
 
           for (func = 1; func < 8; func++)
-            scan_device (0, dev, func);
+            scan_device (bus, dev, func);
         }
     }
+  printf ("PCI: Done (%u)\n", bus);
+}
+
+void
+pci_init (void) 
+{
+  printf ("PCI: Initializating\n");
+  list_init (&pci_dev_list);
+  scan_bus(0);  
+  printf ("PCI: Initialization done\n");
+}
 
-  printf ("PCI BUS: Done \n");
+void
+pci_dump (void)
+{
+  struct list_elem *e;
+
+  for (e = list_begin (&pci_dev_list); e != list_end (&pci_dev_list);
+       e = list_next (e))
+    {
+      struct pci_dev *dev = list_entry (e, struct pci_dev, elem);
+      pci_dump_dev(dev);
+    }
 }