Browse Source

IRQ stuff

K. Lange 2 years ago
parent
commit
095d087e1d
13 changed files with 115 additions and 26 deletions
  1. 1 1
      base/usr/include/kernel/system.h
  2. 9 1
      kernel/cpu/irq.c
  3. 1 1
      kernel/devices/timer.c
  4. 1 1
      modules/ac97.c
  5. 2 2
      modules/ata.c
  6. 55 12
      modules/e1000.c
  7. 1 1
      modules/pcnet.c
  8. 29 0
      modules/procfs.c
  9. 1 1
      modules/ps2kbd.c
  10. 1 1
      modules/ps2mouse.c
  11. 2 2
      modules/rtl.c
  12. 11 2
      modules/serial.c
  13. 1 1
      modules/vbox.c

+ 1 - 1
base/usr/include/kernel/system.h

@@ -110,7 +110,7 @@ extern void isrs_uninstall_handler(size_t isrs);
 
 /* Interrupt Handlers */
 extern void irq_install(void);
-extern void irq_install_handler(size_t irq, irq_handler_chain_t);
+extern void irq_install_handler(size_t irq, irq_handler_chain_t, char * desc);
 extern void irq_uninstall_handler(size_t irq);
 extern int irq_is_handler_free(size_t irq);
 extern void irq_gates(void);

+ 9 - 1
kernel/cpu/irq.c

@@ -85,14 +85,22 @@ void int_enable(void) {
 
 static void (*irqs[IRQ_CHAIN_SIZE])(void);
 static irq_handler_chain_t irq_routines[IRQ_CHAIN_SIZE * IRQ_CHAIN_DEPTH] = { NULL };
+static char * _irq_handler_descriptions[IRQ_CHAIN_SIZE * IRQ_CHAIN_DEPTH] = { NULL };
 
-void irq_install_handler(size_t irq, irq_handler_chain_t handler) {
+char * get_irq_handler(int irq, int chain) {
+	if (irq >= IRQ_CHAIN_SIZE) return NULL;
+	if (chain >= IRQ_CHAIN_DEPTH) return NULL;
+	return _irq_handler_descriptions[IRQ_CHAIN_SIZE * chain + irq];
+}
+
+void irq_install_handler(size_t irq, irq_handler_chain_t handler, char * desc) {
 	/* Disable interrupts when changing handlers */
 	SYNC_CLI();
 	for (size_t i = 0; i < IRQ_CHAIN_DEPTH; i++) {
 		if (irq_routines[i * IRQ_CHAIN_SIZE + irq])
 			continue;
 		irq_routines[i * IRQ_CHAIN_SIZE + irq] = handler;
+		_irq_handler_descriptions[i * IRQ_CHAIN_SIZE + irq ] = desc;
 		break;
 	}
 	SYNC_STI();

+ 1 - 1
kernel/devices/timer.c

@@ -84,7 +84,7 @@ void relative_time(unsigned long seconds, unsigned long subseconds, unsigned lon
 void timer_install(void) {
 	debug_print(NOTICE,"Initializing interval timer");
 	boot_time = read_cmos();
-	irq_install_handler(TIMER_IRQ, timer_handler);
+	irq_install_handler(TIMER_IRQ, timer_handler, "pit timer");
 	timer_phase(SUBTICKS_PER_TICK); /* 100Hz */
 }
 

+ 1 - 1
modules/ac97.c

@@ -238,7 +238,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);
-	irq_install_handler(_device.irq, irq_handler);
+	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);
 

+ 2 - 2
modules/ata.c

@@ -820,8 +820,8 @@ static int ata_initialize(void) {
 	/* Locate ATA device via PCI */
 	pci_scan(&find_ata_pci, -1, &ata_pci);
 
-	irq_install_handler(14, ata_irq_handler);
-	irq_install_handler(15, ata_irq_handler_s);
+	irq_install_handler(14, ata_irq_handler, "ide master");
+	irq_install_handler(15, ata_irq_handler_s, "ide slave");
 
 	atapi_waiter = list_create();
 

+ 55 - 12
modules/e1000.c

@@ -14,6 +14,8 @@
 
 #include <toaru/list.h>
 
+#define E1000_LOG_LEVEL NOTICE
+
 static uint32_t e1000_device_pci = 0x00000000;
 static int e1000_irq = 0;
 static uintptr_t mem_base = 0;
@@ -206,6 +208,8 @@ 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);
@@ -216,7 +220,7 @@ static int irq_handler(struct regs *r) {
 
 	if (status & 0x04) {
 		/* Start link */
-		debug_print(NOTICE, "start link");
+		debug_print(E1000_LOG_LEVEL, "start link");
 	} else if (status & 0x10) {
 		/* ?? */
 	} else if (status & ((1 << 6) | (1 << 7))) {
@@ -249,7 +253,7 @@ static int irq_handler(struct regs *r) {
 
 static void send_packet(uint8_t* payload, size_t payload_size) {
 	tx_index = read_command(E1000_REG_TXDESCTAIL);
-	debug_print(NOTICE,"sending packet 0x%x, %d desc[%d]", payload, payload_size, tx_index);
+	debug_print(E1000_LOG_LEVEL,"sending packet 0x%x, %d desc[%d]", payload, payload_size, tx_index);
 
 	memcpy(tx_virt[tx_index], payload, payload_size);
 	tx[tx_index].length = payload_size;
@@ -300,28 +304,52 @@ static void init_tx(void) {
 
 static void e1000_init(void * data, char * name) {
 
+	debug_print(E1000_LOG_LEVEL, "enabling bus mastering");
 	uint16_t command_reg = pci_read_field(e1000_device_pci, PCI_COMMAND, 2);
 	command_reg |= (1 << 2);
 	command_reg |= (1 << 0);
 	pci_write_field(e1000_device_pci, PCI_COMMAND, 2, command_reg);
 
-	debug_print(NOTICE, "mem base: 0x%x", mem_base);
+	debug_print(E1000_LOG_LEVEL, "mem base: 0x%x", mem_base);
 
 	eeprom_detect();
-	debug_print(NOTICE, "has_eeprom = %d", has_eeprom);
+	debug_print(E1000_LOG_LEVEL, "has_eeprom = %d", has_eeprom);
 	read_mac();
 
-	debug_print(NOTICE, "device mac %2x:%2x:%2x:%2x:%2x:%2x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+	debug_print(E1000_LOG_LEVEL, "device mac %2x:%2x:%2x:%2x:%2x:%2x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+	unsigned long s, ss;
+
+	uint32_t ctrl = read_command(E1000_REG_CTRL);
+	/* reset phy */
+	write_command(E1000_REG_CTRL, ctrl | (0x80000000));
+	read_command(E1000_REG_STATUS);
+	relative_time(0, 10, &s, &ss);
+	sleep_until((process_t *)current_process, s, ss);
+	switch_task(0);
+
+	/* reset mac */
+	write_command(E1000_REG_CTRL, ctrl | (0x04000000));
+	read_command(E1000_REG_STATUS);
+	relative_time(0, 10, &s, &ss);
+	sleep_until((process_t *)current_process, s, ss);
+	switch_task(0);
+
+	/* Reload EEPROM */
+	write_command(E1000_REG_CTRL, ctrl | (0x00002000));
+	read_command(E1000_REG_STATUS);
+	relative_time(0, 20, &s, &ss);
+	sleep_until((process_t *)current_process, s, ss);
+	switch_task(0);
+
 
 	/* initialize */
-	write_command(E1000_REG_CTRL, (1 << 26));
+	write_command(E1000_REG_CTRL, ctrl | (1 << 26));
 
 	/* wait */
-	unsigned long s, ss;
 	relative_time(0, 10, &s, &ss);
 	sleep_until((process_t *)current_process, s, ss);
 	switch_task(0);
-	debug_print(NOTICE, "back from sleep");
+	debug_print(E1000_LOG_LEVEL, "back from sleep");
 
 	uint32_t status = read_command(E1000_REG_CTRL);
 	status |= (1 << 5);   /* set auto speed detection */
@@ -349,10 +377,25 @@ 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);
-	irq_install_handler(e1000_irq, irq_handler);
 
-	debug_print(NOTICE, "Binding interrupt %d", e1000_irq);
+#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?");
+		}
+	}
+
+	irq_install_handler(e1000_irq, irq_handler, "e1000");
+
+	debug_print(E1000_LOG_LEVEL, "Binding interrupt %d", e1000_irq);
 
 	for (int i = 0; i < 128; ++i) {
 		write_command(0x5200 + i * 4, 0);
@@ -409,7 +452,7 @@ static int init(void) {
 
 	for (int i = 0; i < E1000_NUM_RX_DESC; ++i) {
 		rx_virt[i] = (void*)kvmalloc_p(8192 + 16, (uint32_t *)&rx[i].addr);
-		debug_print(INFO, "rx[%d] 0x%x → 0x%x", i, rx_virt[i], (uint32_t)rx[i].addr);
+		debug_print(E1000_LOG_LEVEL, "rx[%d] 0x%x → 0x%x", i, rx_virt[i], (uint32_t)rx[i].addr);
 		rx[i].status = 0;
 	}
 
@@ -417,7 +460,7 @@ static int init(void) {
 
 	for (int i = 0; i < E1000_NUM_TX_DESC; ++i) {
 		tx_virt[i] = (void*)kvmalloc_p(8192+16, (uint32_t *)&tx[i].addr);
-		debug_print(INFO, "tx[%d] 0x%x → 0x%x", i, tx_virt[i], (uint32_t)tx[i].addr);
+		debug_print(E1000_LOG_LEVEL, "tx[%d] 0x%x → 0x%x", i, tx_virt[i], (uint32_t)tx[i].addr);
 		tx[i].status = 0;
 		tx[i].cmd = (1 << 0);
 	}

+ 1 - 1
modules/pcnet.c

@@ -210,7 +210,7 @@ static void pcnet_init(void * data, char * name) {
 	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);
-	irq_install_handler(pcnet_irq, pcnet_irq_handler);
+	irq_install_handler(pcnet_irq, pcnet_irq_handler, "pcnet");
 
 	debug_print(NOTICE, "irq line: %d", pcnet_irq);
 	debug_print(NOTICE, "io base: 0x%x", pcnet_io_base);

+ 29 - 0
modules/procfs.c

@@ -532,6 +532,34 @@ static uint32_t loader_func(fs_node_t *node, uint32_t offset, uint32_t size, uin
 	return size;
 }
 
+extern char * get_irq_handler(int irq, int chain);
+
+static uint32_t irq_func(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) {
+	char * buf = malloc(4096);
+	unsigned int soffset = 0;
+
+	for (int i = 0; i < 16; ++i) {
+		soffset += sprintf(&buf[soffset], "irq %d: ", i);
+		for (int j = 0; j < 4; ++j) {
+			char * t = get_irq_handler(i, j);
+			if (!t) break;
+			soffset += sprintf(&buf[soffset], "%s%s", j ? "," : "", t);
+		}
+		soffset += sprintf(&buf[soffset], "\n");
+	}
+
+	size_t _bsize = strlen(buf);
+	if (offset > _bsize) {
+		free(buf);
+		return 0;
+	}
+	if (size > _bsize - offset) size = _bsize - offset;
+
+	memcpy(buffer, buf, size);
+	free(buf);
+	return size;
+}
+
 static struct procfs_entry std_entries[] = {
 	{-1, "cpuinfo",  cpuinfo_func},
 	{-2, "meminfo",  meminfo_func},
@@ -544,6 +572,7 @@ static struct procfs_entry std_entries[] = {
 	{-9, "modules",  modules_func},
 	{-10,"filesystems", filesystems_func},
 	{-11,"loader",   loader_func},
+	{-12,"irq",      irq_func},
 };
 
 static struct dirent * readdir_procfs_root(fs_node_t *node, uint32_t index) {

+ 1 - 1
modules/ps2kbd.c

@@ -61,7 +61,7 @@ static int keyboard_install(void) {
 	vfs_mount("/dev/kbd", keyboard_pipe);
 
 	/* Install the interrupt handler */
-	irq_install_handler(KEY_IRQ, keyboard_handler);
+	irq_install_handler(KEY_IRQ, keyboard_handler, "ps2 kbd");
 
 	return 0;
 }

+ 1 - 1
modules/ps2mouse.c

@@ -223,7 +223,7 @@ static int mouse_install(void) {
 	mouse_wait(1);
 	mouse_read();
 
-	irq_install_handler(MOUSE_IRQ, mouse_handler);
+	irq_install_handler(MOUSE_IRQ, mouse_handler, "ps2 mouse");
 	IRQ_RES;
 
 	uint8_t tmp = inportb(0x61);

+ 2 - 2
modules/rtl.c

@@ -304,7 +304,7 @@ int init_rtl(void) {
 
 		rtl_irq = pci_read_field(rtl_device_pci, PCI_INTERRUPT_LINE, 1);
 		debug_print(NOTICE, "Interrupt Line: %x\n", rtl_irq);
-		irq_install_handler(rtl_irq, rtl_irq_handler);
+		irq_install_handler(rtl_irq, rtl_irq_handler, "rtl8139");
 
 		uint32_t rtl_bar0 = pci_read_field(rtl_device_pci, PCI_BAR0, 4);
 		uint32_t rtl_bar1 = pci_read_field(rtl_device_pci, PCI_BAR1, 4);
@@ -406,7 +406,7 @@ int init_rtl(void) {
 static int init(void) {
 	pci_scan(&find_rtl, -1, &rtl_device_pci);
 	if (!rtl_device_pci) {
-		debug_print(ERROR, "No RTL 8139 found?");
+		debug_print(NOTICE, "No RTL 8139 found");
 		return 1;
 	}
 	init_rtl();

+ 11 - 2
modules/serial.c

@@ -149,6 +149,9 @@ static int check_serial(fs_node_t * node) {
 	return selectcheck_fs(*pipe_for_port((int)node->device));
 }
 
+static int have_installed_ac = 0;
+static int have_installed_bd = 0;
+
 static fs_node_t * serial_device_create(int device) {
 	fs_node_t * fnode = malloc(sizeof(fs_node_t));
 	memset(fnode, 0x00, sizeof(fs_node_t));
@@ -176,9 +179,15 @@ static fs_node_t * serial_device_create(int device) {
 	serial_enable(device);
 
 	if (device == SERIAL_PORT_A || device == SERIAL_PORT_C) {
-		irq_install_handler(SERIAL_IRQ_AC, serial_handler_ac);
+		if (!have_installed_ac) {
+			irq_install_handler(SERIAL_IRQ_AC, serial_handler_ac, "serial ac");
+			have_installed_ac = 1;
+		}
 	} else {
-		irq_install_handler(SERIAL_IRQ_BD, serial_handler_bd);
+		if (!have_installed_bd) {
+			irq_install_handler(SERIAL_IRQ_BD, serial_handler_bd, "serial bd");
+			have_installed_bd = 1;
+		}
 	}
 
 	*pipe_for_port(device) = make_pipe(128);

+ 1 - 1
modules/vbox.c

@@ -210,7 +210,7 @@ static int vbox_check(void) {
 		}
 		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);
+		irq_install_handler(vbox_irq, vbox_irq_handler, "vbox");
 
 		uint32_t vbox_phys = 0;
 		struct vbox_guest_info * packet = (void*)kvmalloc_p(0x1000, &vbox_phys);