Added [arch_]int_post_device_manager() which is invoked after
the device manager is initialized. For x86 it does nothing, but for PPC it searches for a supported interrupt controller and remembers it for later use. arch_int_{enable,disable}_io_interrupt() are implemented as well as handling of external exceptions (aka as I/O interrupts). We'll see later how well that works. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@16271 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
a8193053ec
commit
f4b0f67cf6
@ -19,6 +19,7 @@ extern "C" {
|
||||
|
||||
status_t arch_int_init(kernel_args *args);
|
||||
status_t arch_int_init_post_vm(kernel_args *args);
|
||||
status_t arch_int_init_post_device_manager(struct kernel_args *args);
|
||||
|
||||
void arch_int_enable_interrupts(void);
|
||||
int arch_int_disable_interrupts(void);
|
||||
|
@ -21,6 +21,7 @@ extern "C" {
|
||||
|
||||
status_t int_init(struct kernel_args *args);
|
||||
status_t int_init_post_vm(struct kernel_args *args);
|
||||
status_t int_init_post_device_manager(struct kernel_args *args);
|
||||
int int_io_interrupt_handler(int vector);
|
||||
|
||||
bool interrupts_enabled(void);
|
||||
|
@ -12,13 +12,16 @@
|
||||
|
||||
#include <int.h>
|
||||
|
||||
#include <boot/kernel_args.h>
|
||||
|
||||
#include <arch/smp.h>
|
||||
#include <boot/kernel_args.h>
|
||||
#include <device_manager.h>
|
||||
#include <kscheduler.h>
|
||||
#include <interrupt_controller.h>
|
||||
#include <smp.h>
|
||||
#include <thread.h>
|
||||
#include <timer.h>
|
||||
#include <util/DoublyLinkedList.h>
|
||||
#include <util/kernel_cpp.h>
|
||||
#include <vm.h>
|
||||
#include <vm_address_space.h>
|
||||
#include <vm_priv.h>
|
||||
@ -40,18 +43,30 @@ static ppc_cpu_exception_context sCPUExceptionContexts[SMP_MAX_CPUS];
|
||||
// threads yet.
|
||||
struct iframe_stack gBootFrameStack;
|
||||
|
||||
// interrupt controller interface (initialized
|
||||
// in arch_int_init_post_device_manager())
|
||||
static struct interrupt_controller_module_info *sPIC;
|
||||
static void *sPICCookie;
|
||||
|
||||
|
||||
void
|
||||
arch_int_enable_io_interrupt(int irq)
|
||||
{
|
||||
return;
|
||||
if (!sPIC)
|
||||
return;
|
||||
|
||||
// TODO: I have no idea, what IRQ type is appropriate.
|
||||
sPIC->enable_io_interrupt(sPICCookie, irq, IRQ_TYPE_LEVEL);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
arch_int_disable_io_interrupt(int irq)
|
||||
{
|
||||
return;
|
||||
if (!sPIC)
|
||||
return;
|
||||
|
||||
sPIC->disable_io_interrupt(sPICCookie, irq);
|
||||
}
|
||||
|
||||
|
||||
@ -150,9 +165,24 @@ ppc_exception_entry(int vector, struct iframe *iframe)
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x500: // external interrupt
|
||||
panic("external interrrupt exception: unimplemented\n");
|
||||
{
|
||||
if (!sPIC) {
|
||||
panic("ppc_exception_entry(): external interrupt although we "
|
||||
"don't have a PIC driver!");
|
||||
ret = B_HANDLED_INTERRUPT;
|
||||
break;
|
||||
}
|
||||
|
||||
dprintf("handling I/O interrupts...\n");
|
||||
int irq;
|
||||
while ((irq = sPIC->acknowledge_io_interrupt(sPICCookie)) >= 0)
|
||||
ret = int_io_interrupt_handler(irq);
|
||||
dprintf("handling I/O interrupts done\n");
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x600: // alignment exception
|
||||
panic("alignment exception: unimplemented\n");
|
||||
break;
|
||||
@ -177,7 +207,7 @@ ppc_exception_entry(int vector, struct iframe *iframe)
|
||||
case 0xf00: // performance monitor exception
|
||||
panic("performance monitor exception: unimplemented\n");
|
||||
break;
|
||||
case 0xf20: // alitivec unavailable exception
|
||||
case 0xf20: // altivec unavailable exception
|
||||
panic("alitivec unavailable exception: unimplemented\n");
|
||||
break;
|
||||
case 0x1000:
|
||||
@ -275,6 +305,217 @@ arch_int_init_post_vm(kernel_args *args)
|
||||
}
|
||||
|
||||
|
||||
template<typename ModuleInfo>
|
||||
struct Module : DoublyLinkedListLinkImpl<Module<ModuleInfo> > {
|
||||
Module(ModuleInfo *module)
|
||||
: module(module)
|
||||
{
|
||||
}
|
||||
|
||||
~Module()
|
||||
{
|
||||
if (module)
|
||||
put_module(((module_info*)module)->name);
|
||||
}
|
||||
|
||||
ModuleInfo *module;
|
||||
};
|
||||
|
||||
typedef Module<interrupt_controller_module_info> PICModule;
|
||||
|
||||
struct PICModuleList : DoublyLinkedList<PICModule> {
|
||||
~PICModuleList()
|
||||
{
|
||||
while (PICModule *module = First()) {
|
||||
Remove(module);
|
||||
delete module;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class DeviceTreeIterator {
|
||||
public:
|
||||
DeviceTreeIterator(device_manager_info *deviceManager)
|
||||
: fDeviceManager(deviceManager),
|
||||
fNode(NULL),
|
||||
fParent(NULL)
|
||||
{
|
||||
Rewind();
|
||||
}
|
||||
|
||||
~DeviceTreeIterator()
|
||||
{
|
||||
if (fParent != NULL)
|
||||
fDeviceManager->put_device_node(fParent);
|
||||
if (fNode != NULL)
|
||||
fDeviceManager->put_device_node(fNode);
|
||||
}
|
||||
|
||||
void Rewind()
|
||||
{
|
||||
fNode = fDeviceManager->get_root();
|
||||
}
|
||||
|
||||
bool HasNext() const
|
||||
{
|
||||
return (fNode != NULL);
|
||||
}
|
||||
|
||||
device_node_handle Next()
|
||||
{
|
||||
if (fNode == NULL)
|
||||
return NULL;
|
||||
|
||||
device_node_handle foundNode = fNode;
|
||||
|
||||
// get first child
|
||||
device_node_handle child = NULL;
|
||||
if (fDeviceManager->get_next_child_device(fNode, &child, NULL)
|
||||
== B_OK) {
|
||||
// move to the child node
|
||||
if (fParent != NULL)
|
||||
fDeviceManager->put_device_node(fParent);
|
||||
fParent = fNode;
|
||||
fNode = child;
|
||||
|
||||
// no more children; backtrack to find the next sibling
|
||||
} else {
|
||||
while (fParent != NULL) {
|
||||
if (fDeviceManager->get_next_child_device(fParent, &fNode, NULL)
|
||||
== B_OK) {
|
||||
// get_next_child_device() always puts the node
|
||||
break;
|
||||
}
|
||||
fNode = fParent;
|
||||
fParent = fDeviceManager->get_parent(fNode);
|
||||
}
|
||||
|
||||
// if we hit the root node again, we're done
|
||||
if (fParent == NULL) {
|
||||
fDeviceManager->put_device_node(fNode);
|
||||
fNode = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return foundNode;
|
||||
}
|
||||
|
||||
private:
|
||||
device_manager_info *fDeviceManager;
|
||||
device_node_handle fNode;
|
||||
device_node_handle fParent;
|
||||
};
|
||||
|
||||
|
||||
static void
|
||||
get_interrupt_controller_modules(PICModuleList &list)
|
||||
{
|
||||
const char *namePrefix = "interrupt_controllers/";
|
||||
size_t namePrefixLen = strlen(namePrefix);
|
||||
|
||||
char name[B_PATH_NAME_LENGTH];
|
||||
size_t length;
|
||||
uint32 cookie = 0;
|
||||
while (get_next_loaded_module_name(&cookie, name, &(length = sizeof(name)))
|
||||
== B_OK) {
|
||||
// an interrupt controller module?
|
||||
if (length <= namePrefixLen
|
||||
|| strncmp(name, namePrefix, namePrefixLen) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// get the module
|
||||
interrupt_controller_module_info *moduleInfo;
|
||||
if (get_module(name, (module_info**)&moduleInfo) != B_OK)
|
||||
continue;
|
||||
|
||||
// add it to the list
|
||||
PICModule *module = new(nothrow) PICModule(moduleInfo);
|
||||
if (!module) {
|
||||
put_module(((module_info*)moduleInfo)->name);
|
||||
continue;
|
||||
}
|
||||
list.Add(module);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static bool
|
||||
probe_pic_device(device_node_handle node, PICModuleList &picModules)
|
||||
{
|
||||
for (PICModule *module = picModules.Head();
|
||||
module;
|
||||
module = picModules.GetNext(module)) {
|
||||
bool noConnection;
|
||||
if (module->module->info.supports_device(node, &noConnection) > 0) {
|
||||
if (module->module->info.register_device(node) == B_OK)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
arch_int_init_post_device_manager(struct kernel_args *args)
|
||||
{
|
||||
// get the interrupt controller driver modules
|
||||
PICModuleList picModules;
|
||||
get_interrupt_controller_modules(picModules);
|
||||
if (picModules.IsEmpty()) {
|
||||
panic("arch_int_init_post_device_manager(): Found no PIC modules!");
|
||||
return B_ENTRY_NOT_FOUND;
|
||||
}
|
||||
|
||||
// get the device manager module
|
||||
device_manager_info *deviceManager;
|
||||
status_t error = get_module(B_DEVICE_MANAGER_MODULE_NAME,
|
||||
(module_info**)&deviceManager);
|
||||
if (error != B_OK) {
|
||||
panic("arch_int_init_post_device_manager(): Failed to get device "
|
||||
"manager: %s", strerror(error));
|
||||
return error;
|
||||
}
|
||||
Module<device_manager_info> _deviceManager(deviceManager); // auto put
|
||||
|
||||
// iterate through the device tree and probe the interrupt controllers
|
||||
DeviceTreeIterator iterator(deviceManager);
|
||||
while (device_node_handle node = iterator.Next())
|
||||
probe_pic_device(node, picModules);
|
||||
|
||||
// iterate through the tree again and get an interrupt controller node
|
||||
iterator.Rewind();
|
||||
while (device_node_handle node = iterator.Next()) {
|
||||
char *deviceType;
|
||||
if (deviceManager->get_attr_string(node, B_DRIVER_DEVICE_TYPE,
|
||||
&deviceType, false) == B_OK) {
|
||||
bool isPIC
|
||||
= (strcmp(deviceType, B_INTERRUPT_CONTROLLER_DRIVER_TYPE) == 0);
|
||||
free(deviceType);
|
||||
|
||||
if (isPIC) {
|
||||
driver_module_info *driver;
|
||||
void *driverCookie;
|
||||
error = deviceManager->init_driver(node, NULL, &driver,
|
||||
&driverCookie);
|
||||
if (error == B_OK) {
|
||||
sPIC = (interrupt_controller_module_info *)driver;
|
||||
sPICCookie = driverCookie;
|
||||
return B_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// no PIC found
|
||||
panic("arch_int_init_post_device_manager(): Found no supported PIC!");
|
||||
|
||||
return B_ENTRY_NOT_FOUND;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
struct ppc_cpu_exception_context *
|
||||
|
@ -618,3 +618,10 @@ arch_int_init_post_vm(kernel_args *args)
|
||||
|
||||
return area >= B_OK ? B_OK : area;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
arch_int_init_post_device_manager(struct kernel_args *args)
|
||||
{
|
||||
return B_OK;
|
||||
}
|
||||
|
@ -126,6 +126,13 @@ int_init_post_vm(kernel_args *args)
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
int_init_post_device_manager(kernel_args *args)
|
||||
{
|
||||
return arch_int_init_post_device_manager(args);
|
||||
}
|
||||
|
||||
|
||||
/** Install a handler to be called when an interrupt is triggered
|
||||
* for the given interrupt number with \a data as the argument.
|
||||
*/
|
||||
|
@ -218,6 +218,8 @@ main2(void *unused)
|
||||
// ToDo: device manager starts here, bus_init()/dev_init() won't be necessary anymore,
|
||||
// but instead, the hardware and drivers are rescanned then.
|
||||
|
||||
int_init_post_device_manager(&sKernelArgs);
|
||||
|
||||
TRACE(("Mount boot file system\n"));
|
||||
vfs_mount_boot_file_system(&sKernelArgs);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user