From 095d087e1da70118208eb138e7cf375ba9459b46 Mon Sep 17 00:00:00 2001 From: "K. Lange" Date: Sat, 21 Jul 2018 16:02:39 +0900 Subject: [PATCH] IRQ stuff --- base/usr/include/kernel/system.h | 2 +- kernel/cpu/irq.c | 10 ++++- kernel/devices/timer.c | 2 +- modules/ac97.c | 2 +- modules/ata.c | 4 +- modules/e1000.c | 73 +++++++++++++++++++++++++------- modules/pcnet.c | 2 +- modules/procfs.c | 29 +++++++++++++ modules/ps2kbd.c | 2 +- modules/ps2mouse.c | 2 +- modules/rtl.c | 4 +- modules/serial.c | 13 +++++- modules/vbox.c | 2 +- 13 files changed, 118 insertions(+), 29 deletions(-) diff --git a/base/usr/include/kernel/system.h b/base/usr/include/kernel/system.h index a5eb7086..4fdc4323 100644 --- a/base/usr/include/kernel/system.h +++ b/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); diff --git a/kernel/cpu/irq.c b/kernel/cpu/irq.c index 8a4a4c4e..bbb06db4 100644 --- a/kernel/cpu/irq.c +++ b/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(); diff --git a/kernel/devices/timer.c b/kernel/devices/timer.c index 0fe3b60e..59775260 100644 --- a/kernel/devices/timer.c +++ b/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 */ } diff --git a/modules/ac97.c b/modules/ac97.c index f730ef6b..c3900e80 100644 --- a/modules/ac97.c +++ b/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); diff --git a/modules/ata.c b/modules/ata.c index b8ed3a1f..f959788e 100644 --- a/modules/ata.c +++ b/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(); diff --git a/modules/e1000.c b/modules/e1000.c index 0805a7c4..ace17d25 100644 --- a/modules/e1000.c +++ b/modules/e1000.c @@ -14,6 +14,8 @@ #include +#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]); - - /* initialize */ - write_command(E1000_REG_CTRL, (1 << 26)); - - /* wait */ + 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); - debug_print(NOTICE, "back from sleep"); + + /* 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, ctrl | (1 << 26)); + + /* wait */ + relative_time(0, 10, &s, &ss); + sleep_until((process_t *)current_process, s, ss); + switch_task(0); + 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); } diff --git a/modules/pcnet.c b/modules/pcnet.c index 5f81f9b0..45343910 100644 --- a/modules/pcnet.c +++ b/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); diff --git a/modules/procfs.c b/modules/procfs.c index e60594fa..c48861bb 100644 --- a/modules/procfs.c +++ b/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) { diff --git a/modules/ps2kbd.c b/modules/ps2kbd.c index c57e7dbf..6814f7c4 100644 --- a/modules/ps2kbd.c +++ b/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; } diff --git a/modules/ps2mouse.c b/modules/ps2mouse.c index 00f9f6e4..7d7aed75 100644 --- a/modules/ps2mouse.c +++ b/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); diff --git a/modules/rtl.c b/modules/rtl.c index 3ec57d20..d28e6682 100644 --- a/modules/rtl.c +++ b/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(); diff --git a/modules/serial.c b/modules/serial.c index 0e963ce5..6772169e 100644 --- a/modules/serial.c +++ b/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); diff --git a/modules/vbox.c b/modules/vbox.c index 30a3ad30..2cffe647 100644 --- a/modules/vbox.c +++ b/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);