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
This commit is contained in:
David Reid
2002-07-19 16:07:36 +00:00
parent 9adc7af78a
commit 48377a24b0
9 changed files with 165 additions and 83 deletions
@@ -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);
+51 -8
View File
@@ -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 */
}
}
+3 -3
View File
@@ -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;
}
+78 -55
View File
@@ -18,18 +18,18 @@
struct io_handler {
struct io_handler *next;
int (*func)(void*);
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;
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;
/* 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[vector].vector_lock);
io->next = io_vectors[vector].handler_list;
io_vectors[vector].handler_list = io;
release_spinlock(&io_vectors[vector].vector_lock);
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;
}
}
+2 -2
View File
@@ -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;
}
+2 -2
View File
@@ -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;
+1 -1
View File
@@ -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;
}
+1 -1
View File
@@ -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
+4 -3
View File
@@ -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);