Browse Source

PIIX PIRQ handling?

K. Lange 2 years ago
parent
commit
f10a54dd2b
9 changed files with 71 additions and 26 deletions
  1. 2 1
      base/usr/include/kernel/pci.h
  2. 43 0
      kernel/devices/pci.c
  3. 2 0
      kernel/main.c
  4. 1 1
      modules/ac97.c
  5. 19 0
      modules/debug_sh.c
  6. 1 17
      modules/e1000.c
  7. 1 1
      modules/pcnet.c
  8. 1 1
      modules/rtl.c
  9. 1 5
      modules/vbox.c

+ 2 - 1
base/usr/include/kernel/pci.h

@@ -66,4 +66,5 @@ void pci_scan_func(pci_func_t f, int type, int bus, int slot, int func, void * e
 void pci_scan_slot(pci_func_t f, int type, int bus, int slot, void * extra);
 void pci_scan_bus(pci_func_t f, int type, int bus, void * extra);
 void pci_scan(pci_func_t f, int type, void * extra);
-
+void pci_remap(void);
+int pci_get_interrupt(uint32_t device);

+ 43 - 0
kernel/devices/pci.c

@@ -8,6 +8,7 @@
 
 #include <kernel/system.h>
 #include <kernel/pci.h>
+#include <kernel/logging.h>
 
 void pci_write_field(uint32_t device, int field, int size, uint32_t value) {
 	outportl(PCI_ADDRESS_PORT, pci_get_addr(device, field));
@@ -151,3 +152,45 @@ void pci_scan(pci_func_t f, int type, void * extra) {
 	}
 }
 
+static void find_isa_bridge(uint32_t device, uint16_t vendorid, uint16_t deviceid, void * extra) {
+	if (vendorid == 0x8086 && (deviceid == 0x7000 || deviceid == 0x7110)) {
+		*((uint32_t *)extra) = device;
+	}
+}
+static uint32_t pci_isa = 0;
+static uint8_t pci_remaps[4] = {0};
+void pci_remap(void) {
+	pci_scan(&find_isa_bridge, -1, &pci_isa);
+	if (pci_isa) {
+		for (int i = 0; i < 4; ++i) {
+			pci_remaps[i] = pci_read_field(pci_isa, 0x60+i, 1);
+			if (pci_remaps[i] == 0x80) {
+				pci_remaps[i] = 0x0a; /* fallback */
+			}
+		}
+		uint32_t out = 0;
+		memcpy(&out, &pci_remaps, 4);
+		pci_write_field(pci_isa, 0x60, 4, out);
+	}
+}
+
+int pci_get_interrupt(uint32_t device) {
+
+	if (pci_isa) {
+		uint32_t irq_pin = pci_read_field(device, 0x3D, 1);
+		if (irq_pin == 0) {
+			/* ??? */
+			debug_print(ERROR, "PCI device does not specific interrupt line");
+			return pci_read_field(device, PCI_INTERRUPT_LINE, 1);
+		}
+		int pirq = (irq_pin + pci_extract_slot(device) - 2) % 4;
+		debug_print(ERROR, "slot is %d, irq pin is %d, so pirq is %d and that maps to %d?", pci_extract_slot(device), irq_pin, pirq, pci_remaps[pirq]);
+		if (pci_remaps[pirq] == 0x80) {
+			debug_print(ERROR, "not mapped, falling back?\n");
+			return pci_read_field(device, PCI_INTERRUPT_LINE, 1);
+		}
+		return pci_remaps[pirq];
+	} else {
+		return pci_read_field(device, PCI_INTERRUPT_LINE, 1);
+	}
+}

+ 2 - 0
kernel/main.c

@@ -48,6 +48,7 @@
 #include <kernel/shm.h>
 #include <kernel/args.h>
 #include <kernel/module.h>
+#include <kernel/pci.h>
 
 uintptr_t initial_esp = 0;
 
@@ -174,6 +175,7 @@ int kmain(struct multiboot *mboot, uint32_t mboot_mag, uintptr_t esp) {
 	syscalls_install(); /* Install the system calls */
 	shm_install();      /* Install shared memory */
 	modules_install();  /* Modules! */
+	pci_remap();
 
 	DISABLE_EARLY_BOOT_LOG();
 

+ 1 - 1
modules/ac97.c

@@ -237,7 +237,7 @@ static int init(void) {
 	}
 	_device.nabmbar = pci_read_field(_device.pci_device, AC97_NABMBAR, 2) & ((uint32_t) -1) << 1;
 	_device.nambar = pci_read_field(_device.pci_device, PCI_BAR0, 4) & ((uint32_t) -1) << 1;
-	_device.irq = pci_read_field(_device.pci_device, PCI_INTERRUPT_LINE, 1);
+	_device.irq = pci_get_interrupt(_device.pci_device);
 	irq_install_handler(_device.irq, irq_handler, "ac97");
 	/* Enable all matter of interrupts */
 	outportb(_device.nabmbar + AC97_PO_CR, AC97_X_CR_FEIE | AC97_X_CR_IOCE);

+ 19 - 0
modules/debug_sh.c

@@ -325,6 +325,23 @@ static int shell_pci(fs_node_t * tty, int argc, char * argv[]) {
 	return 0;
 }
 
+static void find_isa_bridge(uint32_t device, uint16_t vendorid, uint16_t deviceid, void * extra) {
+	if (vendorid == 0x8086 && (deviceid == 0x7000 || deviceid == 0x7110)) {
+		*((uint32_t *)extra) = device;
+	}
+}
+static int shell_frob_piix(fs_node_t * tty, int argc, char * argv[]) {
+	uint32_t pci_isa = 0;
+	pci_scan(&find_isa_bridge, -1, &pci_isa);
+	if (pci_isa) {
+		fprintf(tty, "Found it.\n");
+		for (int i = 0; i < 16; ++i) {
+			fprintf(tty, "%d: 0x%2x\n", i, pci_read_field(pci_isa, 0x60+i, 1));
+		}
+	}
+	return 0;
+}
+
 static int shell_uid(fs_node_t * tty, int argc, char * argv[]) {
 	if (argc < 2) {
 		fprintf(tty, "uid=%d\n", current_process->user);
@@ -658,6 +675,8 @@ static struct shell_command shell_commands[] = {
 		"Disable VGA text mode cursor."},
 	{"exit", &shell_exit,
 		"Quit the shell."},
+	{"piix", &shell_frob_piix,
+		"frob piix"},
 	{NULL, NULL, NULL}
 };
 

+ 1 - 17
modules/e1000.c

@@ -208,8 +208,6 @@ static void read_mac(void) {
 
 static int irq_handler(struct regs *r) {
 
-	debug_print(E1000_LOG_LEVEL, "RECEIVED INTERRUPT FROM E1000");
-
 	uint32_t status = read_command(0xc0);
 
 	irq_ack(e1000_irq);
@@ -377,21 +375,7 @@ static void e1000_init(void * data, char * name) {
 	net_queue = list_create();
 	rx_wait = list_create();
 
-	uint32_t irq_pin = pci_read_field(e1000_device_pci, 0x3D, 1);
-	debug_print(E1000_LOG_LEVEL, "IRQ pin is 0x%2x", irq_pin);
-	e1000_irq = pci_read_field(e1000_device_pci, PCI_INTERRUPT_LINE, 1);
-
-#define REQ_IRQ 11
-	if (e1000_irq == 255) {
-		debug_print(E1000_LOG_LEVEL, "IRQ line is not set for E1000, trying 11");
-		/* Bad interrupt, need to select one */
-		e1000_irq = REQ_IRQ; /* seems to work okay */
-		pci_write_field(e1000_device_pci, PCI_INTERRUPT_LINE, 1, e1000_irq);
-		e1000_irq = pci_read_field(e1000_device_pci, PCI_INTERRUPT_LINE, 1);
-		if (e1000_irq != REQ_IRQ) {
-			debug_print(E1000_LOG_LEVEL, "irq 10 was rejected?");
-		}
-	}
+	e1000_irq = pci_get_interrupt(e1000_device_pci);
 
 	irq_install_handler(e1000_irq, irq_handler, "e1000");
 

+ 1 - 1
modules/pcnet.c

@@ -209,7 +209,7 @@ static void pcnet_init(void * data, char * name) {
 	pcnet_io_base  = pci_read_field(pcnet_device_pci, PCI_BAR0, 4) & 0xFFFFFFF0;
 	pcnet_mem_base = pci_read_field(pcnet_device_pci, PCI_BAR1, 4) & 0xFFFFFFF0;
 
-	pcnet_irq = pci_read_field(pcnet_device_pci, PCI_INTERRUPT_LINE, 1);
+	pcnet_irq = pci_get_interrupt(pcnet_device_pci);
 	irq_install_handler(pcnet_irq, pcnet_irq_handler, "pcnet");
 
 	debug_print(NOTICE, "irq line: %d", pcnet_irq);

+ 1 - 1
modules/rtl.c

@@ -302,7 +302,7 @@ int init_rtl(void) {
 			debug_print(NOTICE, "COMMAND register after:  0x%4x\n", command_reg);
 		}
 
-		rtl_irq = pci_read_field(rtl_device_pci, PCI_INTERRUPT_LINE, 1);
+		rtl_irq = pci_get_interrupt(rtl_device_pci);
 		debug_print(NOTICE, "Interrupt Line: %x\n", rtl_irq);
 		irq_install_handler(rtl_irq, rtl_irq_handler, "rtl8139");
 

+ 1 - 5
modules/vbox.c

@@ -203,11 +203,7 @@ static int vbox_check(void) {
 
 		vfs_mount("/dev/absmouse", mouse_pipe);
 
-		vbox_irq = pci_read_field(vbox_device, PCI_INTERRUPT_LINE, 1);
-		if (vbox_irq == 255) {
-			vbox_irq = 10; /* seems to work okay */
-			pci_write_field(vbox_device, PCI_INTERRUPT_LINE, 1, vbox_irq);
-		}
+		vbox_irq = pci_get_interrupt(vbox_device);
 		debug_print(WARNING, "(vbox) device IRQ is set to %d", vbox_irq);
 		fprintf(&vb, "irq line is %d\n", vbox_irq);
 		irq_install_handler(vbox_irq, vbox_irq_handler, "vbox");