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(kernel_args *args);
|
||||||
status_t arch_int_init_post_vm(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);
|
void arch_int_enable_interrupts(void);
|
||||||
int arch_int_disable_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(struct kernel_args *args);
|
||||||
status_t int_init_post_vm(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);
|
int int_io_interrupt_handler(int vector);
|
||||||
|
|
||||||
bool interrupts_enabled(void);
|
bool interrupts_enabled(void);
|
||||||
|
@ -12,13 +12,16 @@
|
|||||||
|
|
||||||
#include <int.h>
|
#include <int.h>
|
||||||
|
|
||||||
#include <boot/kernel_args.h>
|
|
||||||
|
|
||||||
#include <arch/smp.h>
|
#include <arch/smp.h>
|
||||||
|
#include <boot/kernel_args.h>
|
||||||
|
#include <device_manager.h>
|
||||||
#include <kscheduler.h>
|
#include <kscheduler.h>
|
||||||
|
#include <interrupt_controller.h>
|
||||||
#include <smp.h>
|
#include <smp.h>
|
||||||
#include <thread.h>
|
#include <thread.h>
|
||||||
#include <timer.h>
|
#include <timer.h>
|
||||||
|
#include <util/DoublyLinkedList.h>
|
||||||
|
#include <util/kernel_cpp.h>
|
||||||
#include <vm.h>
|
#include <vm.h>
|
||||||
#include <vm_address_space.h>
|
#include <vm_address_space.h>
|
||||||
#include <vm_priv.h>
|
#include <vm_priv.h>
|
||||||
@ -40,18 +43,30 @@ static ppc_cpu_exception_context sCPUExceptionContexts[SMP_MAX_CPUS];
|
|||||||
// threads yet.
|
// threads yet.
|
||||||
struct iframe_stack gBootFrameStack;
|
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
|
void
|
||||||
arch_int_enable_io_interrupt(int irq)
|
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
|
void
|
||||||
arch_int_disable_io_interrupt(int irq)
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0x500: // external interrupt
|
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;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case 0x600: // alignment exception
|
case 0x600: // alignment exception
|
||||||
panic("alignment exception: unimplemented\n");
|
panic("alignment exception: unimplemented\n");
|
||||||
break;
|
break;
|
||||||
@ -177,7 +207,7 @@ ppc_exception_entry(int vector, struct iframe *iframe)
|
|||||||
case 0xf00: // performance monitor exception
|
case 0xf00: // performance monitor exception
|
||||||
panic("performance monitor exception: unimplemented\n");
|
panic("performance monitor exception: unimplemented\n");
|
||||||
break;
|
break;
|
||||||
case 0xf20: // alitivec unavailable exception
|
case 0xf20: // altivec unavailable exception
|
||||||
panic("alitivec unavailable exception: unimplemented\n");
|
panic("alitivec unavailable exception: unimplemented\n");
|
||||||
break;
|
break;
|
||||||
case 0x1000:
|
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 -
|
// #pragma mark -
|
||||||
|
|
||||||
struct ppc_cpu_exception_context *
|
struct ppc_cpu_exception_context *
|
||||||
|
@ -618,3 +618,10 @@ arch_int_init_post_vm(kernel_args *args)
|
|||||||
|
|
||||||
return area >= B_OK ? B_OK : area;
|
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
|
/** Install a handler to be called when an interrupt is triggered
|
||||||
* for the given interrupt number with \a data as the argument.
|
* 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,
|
// ToDo: device manager starts here, bus_init()/dev_init() won't be necessary anymore,
|
||||||
// but instead, the hardware and drivers are rescanned then.
|
// but instead, the hardware and drivers are rescanned then.
|
||||||
|
|
||||||
|
int_init_post_device_manager(&sKernelArgs);
|
||||||
|
|
||||||
TRACE(("Mount boot file system\n"));
|
TRACE(("Mount boot file system\n"));
|
||||||
vfs_mount_boot_file_system(&sKernelArgs);
|
vfs_mount_boot_file_system(&sKernelArgs);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user