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:
@@ -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);
|
||||
|
||||
@@ -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 */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
+82
-59
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user