From 48377a24b085ccb3731b9d39879cf8a8be848873 Mon Sep 17 00:00:00 2001 From: David Reid Date: Fri, 19 Jul 2002 16:07:36 +0000 Subject: [PATCH] Few changes... - catch up with the changes to the interrupt functions - change the way we handle the list of handlers to use a standard function rather than a home spun one :) - don't add every function on a pci device as a seperate device - add more info to the pci_info structure - when FULL_MONTY turned on show more information git-svn-id: file:///srv/svn/repos/haiku/trunk/current@340 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../core/addons/bus_managers/config_manager.c | 21 ++- src/kernel/core/addons/bus_managers/pci/pci.c | 61 ++++++-- src/kernel/core/faults.c | 6 +- src/kernel/core/int.c | 141 ++++++++++-------- src/kernel/core/sem.c | 4 +- src/kernel/core/smp.c | 4 +- src/kernel/core/syscalls.c | 2 +- src/kernel/core/thread.c | 2 +- src/kernel/core/timer.c | 7 +- 9 files changed, 165 insertions(+), 83 deletions(-) diff --git a/src/kernel/core/addons/bus_managers/config_manager.c b/src/kernel/core/addons/bus_managers/config_manager.c index df38f07541..15aff78e9c 100644 --- a/src/kernel/core/addons/bus_managers/config_manager.c +++ b/src/kernel/core/addons/bus_managers/config_manager.c @@ -89,7 +89,7 @@ static char *decode_device(uint16 dev) } } -static void show_pci_details(struct pci_info *p) +static void show_pci_details(struct pci_info *p, pci_module_info *pcim) { dprintf("PCI device found:\n"); dprintf("\tvendor id : %02x [%s]\n", p->vendor_id, decode_vendor(p->vendor_id)); @@ -103,12 +103,19 @@ static void show_pci_details(struct pci_info *p) dprintf("\tclass_api : %02x\n", p->class_api); dprintf("\tclass_sub : %02x\n", p->class_sub); #endif - dprintf("\tclass_base : %02x [%s]\n", p->class_base, decode_class_base(p->class_base)); #if THE_FULL_MONTY + dprintf("\tstatus : %04x\n", + pcim->read_pci_config(p->bus, p->device, p->function, PCI_status, 2)); + dprintf("\tcommand : %04x\n", + pcim->read_pci_config(p->bus, p->device, p->function, PCI_command, 2)); + dprintf("\tbase address: %08lx\n", + pcim->read_pci_config(p->bus, p->device, p->function, PCI_base_registers, 4)); + dprintf("\tline_size : %02x\n", p->line_size); dprintf("\theader_type : %02x\n", p->header_type); + dprintf("\tbist : %02x\n", p->bist); if (p->header_type == 0) { dprintf("Header Type 0\n"); @@ -117,9 +124,17 @@ static void show_pci_details(struct pci_info *p) dprintf("\tsubsystem_vendor_id : %04x [%s]\n", p->u.h0.subsystem_vendor_id, decode_vendor(p->u.h0.subsystem_vendor_id)); dprintf("\trom_base_pci : %08lx\n", p->u.h0.rom_base_pci); + dprintf("\tinterrupt_line : %02x\n", p->u.h0.interrupt_line); + dprintf("\tinterrupt_pin : %02x\n", p->u.h0.interrupt_pin); + } else if (p->header_type == 1) { dprintf("Header Type 1 (PCI-PCI bridge)\n"); dprintf("\trom_base_pci : %08lx\n", p->u.h1.rom_base_pci); + dprintf("\tinterrupt_line : %02x\n", p->u.h1.interrupt_line); + dprintf("\tinterrupt_pin : %02x\n", p->u.h1.interrupt_pin); + dprintf("\t2ndry status : %04x\n", p->u.h1.secondary_status); + dprintf("\tmemory_base : %04x\n", p->u.h1.memory_base); + dprintf("\tbridge control : %02x\n", p->u.h1.bridge_control); } #endif } @@ -136,7 +151,7 @@ static status_t test_me(void) } while (pcim->get_nth_pci_info(index++, &apci) == 0) { - show_pci_details(&apci); + show_pci_details(&apci, pcim); } put_module(B_PCI_MODULE_NAME); diff --git a/src/kernel/core/addons/bus_managers/pci/pci.c b/src/kernel/core/addons/bus_managers/pci/pci.c index ba71c37b3a..479a48a2d6 100755 --- a/src/kernel/core/addons/bus_managers/pci/pci.c +++ b/src/kernel/core/addons/bus_managers/pci/pci.c @@ -228,20 +228,39 @@ static void scan_pci(void) /* We can have up to 255 busses */ for(bus = 0; bus < 255; bus++) { - /* Each bus can have up to 32 devices on it */ - for(dev = 0; dev < bus_max_devices; dev++) { + /* Each bus can have up to 'bus_max_devices' devices on it */ + for(dev = 0; dev <= bus_max_devices; dev++) { /* Each device can have up to 8 functions */ + uint16 sv_vendor_id = 0, sv_device_id = 0; + for (func = 0; func < 8; func++) { pci_info *pcii = NULL; struct found_pci_device *npcid = NULL; - uint16 val = read_pci_config(bus, dev, func, 0, 2); - /* If we get 0xffff then there is noe device here. As there can't + uint16 vendor_id = read_pci_config(bus, dev, func, 0, 2); + uint16 device_id; + uint8 int_line = 0, int_pin = 0; + /* If we get 0xffff then there is no device here. As there can't * be any gaps in function allocation this tells us that we * can move onto the next device/bus */ - if (val == 0xffff) + if (vendor_id == 0xffff) break; + device_id = read_pci_config(bus, dev, func, PCI_device_id, 2); + + /* Is this a new device? As we're scanning the functions here, many devices + * will supply identical information for all 8 accesses! Try to catch this and + * simply move past duplicates. We need to continue scanning in case we miss + * a different device at the end. + * XXX - is this correct???? + */ + if (vendor_id == sv_vendor_id && sv_device_id == device_id) { + /* It's a duplicate */ + continue; + } + sv_vendor_id = vendor_id; + sv_device_id = device_id; + /* At present we will add a device to our list if we get here, * but we may want to review if we need to add 8 version of the * same device if only the functions differ? @@ -256,8 +275,9 @@ static void scan_pci(void) return; } - pcii->vendor_id = val; - pcii->device_id = read_pci_config(bus, dev, func, PCI_device_id, 2); + /* basic header */ + pcii->vendor_id = vendor_id; + pcii->device_id = device_id; pcii->bus = bus; pcii->device = dev; pcii->function = func; @@ -268,17 +288,38 @@ static void scan_pci(void) pcii->line_size = read_pci_config(bus, dev, func, PCI_line_size, 1); pcii->latency = read_pci_config(bus, dev, func, PCI_latency, 1); pcii->header_type = read_pci_config(bus, dev, func, PCI_header_type, 1); - + pcii->bist = read_pci_config(bus, dev, func, PCI_bist, 1); + + int_line = read_pci_config(bus, dev, func, PCI_interrupt_line, 1); + int_pin = read_pci_config(bus, dev, func, PCI_interrupt_pin, 1); + + /* device type specific headers based on header_type declared */ if (pcii->header_type == 0) { /* header type 0 */ pcii->u.h0.cardbus_cis = read_pci_config(bus, dev, func, PCI_cardbus_cis, 4); pcii->u.h0.subsystem_id = read_pci_config(bus, dev, func, PCI_subsystem_id, 2); pcii->u.h0.subsystem_vendor_id = read_pci_config(bus, dev, func, PCI_subsystem_vendor_id, 2); pcii->u.h0.rom_base_pci = read_pci_config(bus, dev, func, PCI_rom_base, 4); + pcii->u.h0.interrupt_line = int_line; + pcii->u.h0.interrupt_pin = int_pin; } else if (pcii->header_type == 1) { /* header_type 1 */ - /* bridge */ + /* PCI-PCI bridge - may be used for AGP */ pcii->u.h1.rom_base_pci = read_pci_config(bus, dev, func, PCI_bridge_rom_base, 4); + pcii->u.h1.primary_bus = read_pci_config(bus, dev, func, PCI_primary_bus, 1); + pcii->u.h1.secondary_bus = read_pci_config(bus, dev, func, PCI_secondary_bus, 1); + pcii->u.h1.secondary_latency = read_pci_config(bus, dev, func, PCI_secondary_latency, 1); + pcii->u.h1.secondary_status = read_pci_config(bus, dev, func, PCI_secondary_status, 2); + pcii->u.h1.subordinate_bus = read_pci_config(bus, dev, func, PCI_subordinate_bus, 1); + pcii->u.h1.io_base = read_pci_config(bus, dev, func, PCI_io_base, 1); + pcii->u.h1.io_limit = read_pci_config(bus, dev, func, PCI_io_limit, 1); + pcii->u.h1.memory_base = read_pci_config(bus, dev, func, PCI_memory_base, 2); + pcii->u.h1.memory_limit = read_pci_config(bus, dev, func, PCI_memory_limit, 2); + pcii->u.h1.prefetchable_memory_base = read_pci_config(bus, dev, func, PCI_prefetchable_memory_base, 2); + pcii->u.h1.prefetchable_memory_limit = read_pci_config(bus, dev, func, PCI_prefetchable_memory_limit, 2); + pcii->u.h1.bridge_control = read_pci_config(bus, dev, func, PCI_bridge_control, 1); + pcii->u.h1.interrupt_line = int_line; + pcii->u.h1.interrupt_pin = int_pin; } else if (pcii->header_type == 0x80) { /* ??? */ } @@ -287,7 +328,9 @@ static void scan_pci(void) /* Add the device to the list */ insque(npcid, &pci_dev_list); } + /* next device */ } + /* next bus */ } } diff --git a/src/kernel/core/faults.c b/src/kernel/core/faults.c index 6bcbb4b435..cdf53003b1 100644 --- a/src/kernel/core/faults.c +++ b/src/kernel/core/faults.c @@ -26,7 +26,7 @@ int general_protection_fault(int errorcode) { panic("GENERAL PROTECTION FAULT: errcode 0x%x. Killing system.\n", errorcode); - return INT_NO_RESCHEDULE; + return B_HANDLED_INTERRUPT; } static const char *fpu_fault_to_str(enum fpu_faults fpu_fault) @@ -52,13 +52,13 @@ int fpu_fault(int fpu_fault) { panic("FPU FAULT: errcode 0x%x (%s), Killing system.\n", fpu_fault, fpu_fault_to_str(fpu_fault)); - return INT_NO_RESCHEDULE; + return B_HANDLED_INTERRUPT; } int fpu_disable_fault(void) { panic("FPU DISABLE FAULT: Killing system.\n"); - return INT_NO_RESCHEDULE; + return B_HANDLED_INTERRUPT; } diff --git a/src/kernel/core/int.c b/src/kernel/core/int.c index 037f8ba56b..3fd17dcfab 100644 --- a/src/kernel/core/int.c +++ b/src/kernel/core/int.c @@ -17,18 +17,18 @@ #define NUM_IO_VECTORS 256 struct io_handler { - struct io_handler *next; - int (*func)(void*); + struct io_handler *next; + struct io_handler *prev; + interrupt_handler func; void* data; }; struct io_vector { - struct io_handler *handler_list; - spinlock_t vector_lock; + struct io_handler handler_list; + spinlock_t vector_lock; }; -static struct io_vector *io_vectors = NULL; - +static struct io_vector *io_vectors = NULL; int int_init(kernel_args *ka) @@ -52,75 +52,90 @@ int_init2(kernel_args *ka) } -int -int_set_io_interrupt_handler(int vector, int (*func)(void*), void* data) +/* install_io_interrupt_handler + * install a handler to be called when an interrupt is triggered + * for the given irq with data as the argument + */ +long install_io_interrupt_handler(long irq, interrupt_handler handler, + void* data, ulong flags) { - struct io_handler *io; + struct io_handler *io = NULL; int state; - // insert this io handler in the chain of interrupt - // handlers registered for this io interrupt - + /* find the chain of handlers for this irq. + * NB there can be multiple handlers for the same IRQ, especially for + * PCI drivers. Where we have multiple handlers we will call each in turn + * until one returns a value other than B_UNHANDLED_INTERRUPT. + */ io = (struct io_handler *)kmalloc(sizeof(struct io_handler)); if (io == NULL) return ENOMEM; - io->func = func; + io->func = handler; io->data = data; - state = int_disable_interrupts(); - acquire_spinlock(&io_vectors[vector].vector_lock); - io->next = io_vectors[vector].handler_list; - io_vectors[vector].handler_list = io; - release_spinlock(&io_vectors[vector].vector_lock); + /* Make sure our list is init'd or bad things will happen */ + if (io_vectors[irq].handler_list.next == NULL) { + io_vectors[irq].handler_list.next = &io_vectors[irq].handler_list; + io_vectors[irq].handler_list.prev = &io_vectors[irq].handler_list; + } + + /* Disable the interrupts, get the spinlock for this irq only + * and then insert the handler */ + state = int_disable_interrupts(); + acquire_spinlock(&io_vectors[irq].vector_lock); + insque(io, &io_vectors[irq].handler_list); + release_spinlock(&io_vectors[irq].vector_lock); int_restore_interrupts(state); - arch_int_enable_io_interrupt(vector); + /* If we were passed the bit-flag B_NO_ENABLE_COUNTER then + * we're being asked to not alter whether the interrupt is set + * regardless of setting. + */ + if ((flags & B_NO_ENABLE_COUNTER) == 0) + arch_int_enable_io_interrupt(irq); return 0; } - -int -int_remove_io_interrupt_handler(int vector, int (*func)(void*), void* data) +/* remove_io_interrupt_handler + * remove an interrupt handler previously inserted + */ +long remove_io_interrupt_handler(long irq, interrupt_handler handler, + void* data) { - struct io_handler *io, *prev = NULL; + struct io_handler *io = NULL; int state; // lock the structures down so it is not modified while we search state = int_disable_interrupts(); - acquire_spinlock(&io_vectors[vector].vector_lock); + acquire_spinlock(&io_vectors[irq].vector_lock); - // start at the beginning - io = io_vectors[vector].handler_list; - - // while not at end - while (io != NULL) { - // see if we match both the function & data - if (io->func == func && io->data == data) + /* loop through the available handlers and try to find a match. + * We go forward through the list but this means we start with the + * most recently added handlers. + */ + io = io_vectors[irq].handler_list.next; + while (io != &io_vectors[irq].handler_list) { + /* we have to match both function and data */ + if (io->func == handler && io->data == data) break; - - // Store our backlink and move to next - prev = io; io = io->next; } - // If we found it - if (io != NULL) { - // unlink it, taking care of the change it was the first in line - if (prev != NULL) - prev->next = io->next; - else - io_vectors[vector].handler_list = io->next; - } - + if (io) + remque(io); + // release our lock as we're done with the vector - release_spinlock(&io_vectors[vector].vector_lock); + release_spinlock(&io_vectors[irq].vector_lock); int_restore_interrupts(state); // and disable the IRQ if nothing left if (io != NULL) { - if (prev == NULL && io->next == NULL) - arch_int_disable_io_interrupt(vector); + /* we still have handlers left if the next handler doesn't point back + * to the head of the list. + */ + if (io_vectors[irq].handler_list.next != &io_vectors[irq].handler_list) + arch_int_disable_io_interrupt(irq); kfree(io); } @@ -128,26 +143,34 @@ int_remove_io_interrupt_handler(int vector, int (*func)(void*), void* data) return (io != NULL) ? 0 : EINVAL; } - -int -int_io_interrupt_handler(int vector) +/* int_io_interrupt_handler + * actually process an interrupt via the handlers registered for that + * vector (irq) + */ +int int_io_interrupt_handler(int vector) { - int ret = INT_NO_RESCHEDULE; + int ret = B_UNHANDLED_INTERRUPT; acquire_spinlock(&io_vectors[vector].vector_lock); - if (io_vectors[vector].handler_list == NULL) { + if (io_vectors[vector].handler_list.next == &io_vectors[vector].handler_list) { dprintf("unhandled io interrupt %d\n", vector); } else { struct io_handler *io; - int temp_ret; - - io = io_vectors[vector].handler_list; - while (io != NULL) { - temp_ret = io->func(io->data); - if (temp_ret == INT_RESCHEDULE) - ret = INT_RESCHEDULE; - io = io->next; + /* Loop through the list of handlers. + * each handler returns as follows... + * - B_UNHANDLED_INTERRUPT, the interrupt wasn't processed by the + * fucntion, so try the next available. + * - B_HANDLED_INTERRUPT, the interrupt has been handled and no further + * attention is required + * - B_INVOKE_SCHEDULER, the interrupt has been handled, but the function wants + * the scheduler to be invoked + */ + for (io = io_vectors[vector].handler_list.next; + io != &io_vectors[vector].handler_list; + io = io->next) { + if ((ret = io->func(io->data)) != B_UNHANDLED_INTERRUPT) + break; } } diff --git a/src/kernel/core/sem.c b/src/kernel/core/sem.c index e9f7352cba..822e5a5501 100644 --- a/src/kernel/core/sem.c +++ b/src/kernel/core/sem.c @@ -291,7 +291,7 @@ static int sem_timeout(void *data) t = thread_get_thread_struct(args->blocked_thread); if(t == NULL) - return INT_NO_RESCHEDULE; + return B_HANDLED_INTERRUPT; slot = args->blocked_sem_id % MAX_SEMS; state = int_disable_interrupts(); @@ -319,7 +319,7 @@ static int sem_timeout(void *data) int_restore_interrupts(state); - return INT_RESCHEDULE; + return B_INVOKE_SCHEDULER; } diff --git a/src/kernel/core/smp.c b/src/kernel/core/smp.c index 53df25acd5..ee38e13b94 100644 --- a/src/kernel/core/smp.c +++ b/src/kernel/core/smp.c @@ -243,7 +243,7 @@ static int smp_process_pending_ici(int curr_cpu) struct smp_msg *msg; bool halt = false; int source_mailbox = 0; - int retval = INT_NO_RESCHEDULE; + int retval = B_HANDLED_INTERRUPT; msg = smp_check_for_message(curr_cpu, &source_mailbox); if(msg == NULL) @@ -261,7 +261,7 @@ static int smp_process_pending_ici(int curr_cpu) arch_cpu_global_TLB_invalidate(); break; case SMP_MSG_RESCHEDULE: - retval = INT_RESCHEDULE; + retval = B_INVOKE_SCHEDULER; break; case SMP_MSG_CPU_HALT: halt = true; diff --git a/src/kernel/core/syscalls.c b/src/kernel/core/syscalls.c index f8b5ddafea..719328843c 100644 --- a/src/kernel/core/syscalls.c +++ b/src/kernel/core/syscalls.c @@ -313,5 +313,5 @@ int syscall_dispatcher(unsigned long call_num, void *arg_buffer, uint64 *call_re // dprintf("syscall_dispatcher: done with syscall 0x%x\n", call_num); - return INT_RESCHEDULE; + return B_INVOKE_SCHEDULER; } diff --git a/src/kernel/core/thread.c b/src/kernel/core/thread.c index 62ba121164..a10bd8b4d5 100644 --- a/src/kernel/core/thread.c +++ b/src/kernel/core/thread.c @@ -1480,7 +1480,7 @@ static int reschedule_event(void *unused) // this function is called as a result of the timer event set by the scheduler // returning this causes a reschedule on the timer event thread_get_current_thread()->cpu->info.preempted= 1; - return INT_RESCHEDULE; + return B_INVOKE_SCHEDULER; } // NOTE: expects thread_spinlock to be held diff --git a/src/kernel/core/timer.c b/src/kernel/core/timer.c index e99dcd57ad..0c8e7e99e0 100644 --- a/src/kernel/core/timer.c +++ b/src/kernel/core/timer.c @@ -57,7 +57,7 @@ int timer_interrupt() struct timer_event *event; spinlock_t *spinlock; int curr_cpu = smp_get_current_cpu(); - int rc = INT_NO_RESCHEDULE; + int rc = B_HANDLED_INTERRUPT; // dprintf("timer_interrupt: time 0x%x 0x%x, cpu %d\n", system_time(), smp_get_current_cpu()); @@ -80,8 +80,9 @@ restart_scan: // note: if the event is not periodic, it is ok // to delete the event structure inside the callback if(event->func != NULL) { - if(event->func(event->data) == INT_RESCHEDULE) - rc = INT_RESCHEDULE; + rc = event->func(event->data); +// if (event->func(event->data) == INT_RESCHEDULE) +// rc = INT_RESCHEDULE; } acquire_spinlock(spinlock);