From: Joshua Wise <joshua@rebirth.joshuawise.com>
Date: Fri, 26 Sep 2008 03:16:58 +0000 (-0400)
Subject: Add PCI bus probe and enumeration routines.
X-Git-Url: http://git.joshuawise.com/netwatch.git/commitdiff_plain/83a025567a37236fd819b30d12e32828d8fd2dc4

Add PCI bus probe and enumeration routines.
---

diff --git a/grubload/Makefile b/grubload/Makefile
index 0ff596a..3c7e395 100644
--- a/grubload/Makefile
+++ b/grubload/Makefile
@@ -1,4 +1,4 @@
-OBJS=multiboot_c.o multiboot_asm.o realmode.o loader.o ../pci/pci-raw.o ../lib/minilib.o ../lib/console.o ../ich2/smram-ich2.o ../ich2/smi.o output.o ../lib/sprintf.o ../lib/doprnt.o
+OBJS=multiboot_c.o multiboot_asm.o realmode.o loader.o ../pci/pci-raw.o ../lib/minilib.o ../lib/console.o ../ich2/smram-ich2.o ../ich2/smi.o output.o ../lib/sprintf.o ../lib/doprnt.o ../pci/pci.o
 CC=gcc
 CFLAGS=-nostdlib -I../include -I../include/raw -I. -D__RAW__ -fno-builtin -nostdinc -Wall -Werror -pedantic -std=gnu99
 
diff --git a/grubload/multiboot_c.c b/grubload/multiboot_c.c
index 17c1542..372363c 100644
--- a/grubload/multiboot_c.c
+++ b/grubload/multiboot_c.c
@@ -54,7 +54,6 @@ void c_start(unsigned int magic, struct mb_info *mbinfo)
 	outputf("Current USB state is: %04x %04x", pci_read16(0, 31, 2, 0xC0), pci_read16(0, 31, 4, 0xC0));
 	outputf("Current SMI state is: %08x", inl(0x830));
 	
-	
 	smi_disable();
 	
 	/* Try really hard to shut up USB_LEGKEY. */
@@ -62,6 +61,8 @@ void c_start(unsigned int magic, struct mb_info *mbinfo)
 	pci_write16(0, 31, 2, 0xC0, 0);
 	pci_write16(0, 31, 4, 0xC0, pci_read16(0, 31, 4, 0xC0));
 	pci_write16(0, 31, 4, 0xC0, 0);
+	
+	pci_bus_enum();
 
 	/* Open the SMRAM aperture and load our ELF. */
 	old_smramc = smram_save_state();
diff --git a/include/pci.h b/include/pci.h
index 60b665f..313b3e0 100644
--- a/include/pci.h
+++ b/include/pci.h
@@ -16,4 +16,29 @@ uint32_t pci_read32(int bus, int slot, int fn, int addr);
 uint16_t pci_read16(int bus, int slot, int fn, int addr);
 uint8_t pci_read8(int bus, int slot, int fn, int addr);
 
+/* Hardware-agnostic functions implemented by pci.c */
+typedef enum {
+	PCI_BAR_NONE = 0,
+	PCI_BAR_MEMORY32,
+	PCI_BAR_MEMORY64,
+	PCI_BAR_IO
+} pci_bar_type_t;
+
+typedef struct pci_bar {
+	pci_bar_type_t type;
+	unsigned char prefetchable;
+	unsigned long addr;
+} pci_bar_t;
+
+typedef struct pci_dev {
+	unsigned short vid, did;
+	int bus, dev, fn;
+	pci_bar_t bars[6];
+} pci_dev_t;
+
+typedef int (*pci_probe_fn_t)(pci_dev_t *);
+
+void pci_bus_enum();
+int pci_probe(pci_probe_fn_t probe);
+
 #endif
diff --git a/pci/pci.c b/pci/pci.c
new file mode 100644
index 0000000..e5ab816
--- /dev/null
+++ b/pci/pci.c
@@ -0,0 +1,100 @@
+#include <pci.h>
+#include <output.h>
+
+int pci_probe(pci_probe_fn_t probe)
+{
+	int devsfound = 0;
+	pci_dev_t pdev;
+	unsigned int bus;
+	unsigned int dev;
+	unsigned int fn;
+	
+	for (bus = 0; bus < 0x100; bus++)
+		for (dev = 0; dev < 0x20; dev++)
+			if (pci_read32(bus, dev, 0, 0) != 0xFFFFFFFF)
+				for (fn = 0; fn < 8; fn++)
+				{
+					int bar;
+					
+					if (pci_read32(bus, dev, fn, 0) == 0xFFFFFFFF)
+						continue;
+					
+					if ((fn != 0) && !(pci_read8(bus, dev, 0, 0x0E) & 0x80))
+						continue;
+					
+					pdev.bus = bus;
+					pdev.dev = dev;
+					pdev.fn = fn;
+					pdev.vid = pci_read16(bus, dev, fn, 0);
+					pdev.did = pci_read16(bus, dev, fn, 2);
+					
+					for (bar = 0; bar < 6; bar++)
+					{
+						unsigned long bardat = pci_read32(bus, dev, fn, 0x10 + bar*4);
+						if (bardat == 0)
+						{
+							pdev.bars[bar].type = PCI_BAR_NONE;
+							continue;
+						}
+						if (bardat & 1)
+						{
+							pdev.bars[bar].type = PCI_BAR_IO;
+							pdev.bars[bar].addr = bardat & ~0x3;
+						} else {
+							pdev.bars[bar].prefetchable = (bardat >> 3) & 1;
+							switch ((bardat >> 1) & 0x3)
+							{
+							case 0:
+								pdev.bars[bar].type = PCI_BAR_MEMORY32;
+								pdev.bars[bar].addr = bardat & ~0xF;
+								break;
+							case 2:
+								pdev.bars[bar].type = PCI_BAR_MEMORY64;
+								bar++;
+								pdev.bars[bar].type = PCI_BAR_NONE;
+								break;
+							default:
+								pdev.bars[bar].type = PCI_BAR_NONE;
+								continue;
+							}
+						}
+					}
+					
+					devsfound += probe(&pdev);
+				}
+	
+	return devsfound;
+}
+
+static int _enumfn(pci_dev_t *pdev)
+{
+	int bar;
+	
+	outputf("Found device: %02x:%02x.%1x: %04X:%04X",
+		pdev->bus, pdev->dev, pdev->fn,
+		pdev->vid, pdev->did);
+	for (bar = 0; bar < 6; bar++)
+	{
+		switch (pdev->bars[bar].type)
+		{
+		case PCI_BAR_IO:
+			outputf("  BAR %d: I/O, Addr %04x", bar, pdev->bars[bar].addr);
+			break;
+		case PCI_BAR_MEMORY32:
+			outputf("  BAR %d: Mem32, Addr %04x", bar, pdev->bars[bar].addr);
+			break;
+		case PCI_BAR_MEMORY64:
+			outputf("  BAR %d: Mem64, Addr %04x", bar, pdev->bars[bar].addr);
+			break;
+		default:
+			break;
+		}
+	}
+	return 0;
+}
+
+void pci_bus_enum()
+{
+	pci_probe(_enumfn);
+}
+