Implement MSI support using the x86 specific PCI module in the FreeBSD

compatibility layer. This should make some network and wireless hardware use
MSIs and therefore solve issues related to interrupt sharing and wrongly
advertised interrupt lines.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@36225 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Michael Lotz
2010-04-13 15:24:18 +00:00
parent be982b9cd5
commit 2b5b2e045a
4 changed files with 79 additions and 6 deletions
+67 -6
View File
@@ -22,6 +22,8 @@
// private kernel header to get B_NO_HANDLED_INFO
#include <int.h>
#include <PCI_x86.h>
//#define DEBUG_BUS_SPACE_RW
#ifdef DEBUG_BUS_SPACE_RW
@@ -48,6 +50,7 @@ struct internal_intr {
void *arg;
int irq;
uint32 flags;
bool is_msi;
thread_id thread;
sem_id sem;
@@ -138,9 +141,21 @@ bus_alloc_resource(device_t dev, int type, int *rid, unsigned long start,
if (res == NULL)
return NULL;
if (type == SYS_RES_IRQ)
result = bus_alloc_irq_resource(dev, res);
else if (type == SYS_RES_MEMORY)
if (type == SYS_RES_IRQ) {
if (*rid == 0) {
// pinned interrupt
result = bus_alloc_irq_resource(dev, res);
} else {
// msi or msi-x interrupt at index *rid - 1
pci_info *info;
info = &((struct root_device_softc *)dev->root->softc)->pci_info;
res->r_bustag = 1;
res->r_bushandle = info->u.h0.interrupt_line + *rid - 1;
result = 0;
// TODO: msi-x interrupts
}
} else if (type == SYS_RES_MEMORY)
result = bus_alloc_mem_resource(dev, res, *rid);
else if (type == SYS_RES_IOPORT)
result = bus_alloc_ioport_resource(dev, res, *rid);
@@ -309,6 +324,7 @@ bus_setup_intr(device_t dev, struct resource *res, int flags,
intr->arg = arg;
intr->irq = res->r_bushandle;
intr->flags = flags;
intr->is_msi = false;
intr->sem = -1;
intr->thread = -1;
@@ -341,6 +357,20 @@ bus_setup_intr(device_t dev, struct resource *res, int flags,
intr_wrapper, intr, B_NO_HANDLED_INFO);
}
if (status == B_OK && res->r_bustag == 1 && gPCIx86 != NULL) {
// this is an msi, enable it
pci_info *info
= &((struct root_device_softc *)dev->root->softc)->pci_info;
if (gPCIx86->enable_msi(info->bus, info->device,
info->function) != B_OK) {
device_printf(dev, "enabling msi failed\n");
bus_teardown_intr(dev, res, intr);
return ENODEV;
}
intr->is_msi = true;
}
if (status < B_OK) {
free_internal_intr(intr);
return status;
@@ -358,6 +388,13 @@ bus_teardown_intr(device_t dev, struct resource *res, void *arg)
{
struct internal_intr *intr = arg;
if (intr->is_msi && gPCIx86 != NULL) {
// disable msi generation
pci_info *info
= &((struct root_device_softc *)dev->root->softc)->pci_info;
gPCIx86->disable_msi(info->bus, info->device, info->function);
}
if (intr->filter != NULL) {
remove_io_interrupt_handler(intr->irq, (interrupt_handler)intr->filter,
intr->arg);
@@ -659,21 +696,45 @@ pci_find_extcap(device_t child, int capability, int *_capabilityRegister)
int
pci_msi_count(device_t dev)
{
return 0;
pci_info *info;
if (gPCIx86 == NULL)
return 0;
info = &((struct root_device_softc *)dev->root->softc)->pci_info;
return gPCIx86->get_msi_count(info->bus, info->device, info->function);
}
int
pci_alloc_msi(device_t dev, int *count)
{
return ENODEV;
pci_info *info;
uint8 startVector = 0;
if (gPCIx86 == NULL)
return ENODEV;
info = &((struct root_device_softc *)dev->root->softc)->pci_info;
if (gPCIx86->configure_msi(info->bus, info->device, info->function, *count,
&startVector) != B_OK) {
return ENODEV;
}
info->u.h0.interrupt_line = startVector;
return EOK;
}
int
pci_release_msi(device_t dev)
{
return ENODEV;
pci_info *info;
if (gPCIx86 == NULL)
return ENODEV;
info = &((struct root_device_softc *)dev->root->softc)->pci_info;
gPCIx86->unconfigure_msi(info->bus, info->device, info->function);
return EOK;
}
+1
View File
@@ -27,6 +27,7 @@ spinlock __haiku_intr_spinlock;
struct net_stack_module_info *gStack;
pci_module_info *gPci;
struct pci_x86_module_info *gPCIx86;
static struct list sRootDevices;
static int sNextUnit;
+1
View File
@@ -43,6 +43,7 @@ enum {
extern struct net_stack_module_info *gStack;
extern pci_module_info *gPci;
extern struct pci_x86_module_info *gPCIx86;
static inline void
+10
View File
@@ -19,6 +19,7 @@
#include <Drivers.h>
#include <ether_driver.h>
#include <PCI_x86.h>
#include <compat/sys/haiku-module.h>
@@ -149,6 +150,10 @@ _fbsd_init_driver(driver_t *driver)
if (status < B_OK)
return status;
// if it fails we just don't support x86 specific features (like MSIs)
if (get_module(B_PCI_X86_MODULE_NAME, (module_info **)&gPCIx86) != B_OK)
gPCIx86 = NULL;
status = init_hard_clock();
if (status < B_OK)
goto err1;
@@ -220,6 +225,9 @@ err2:
uninit_hard_clock();
err1:
put_module(B_PCI_MODULE_NAME);
if (gPCIx86 != NULL)
put_module(B_PCI_X86_MODULE_NAME);
return status;
}
@@ -243,4 +251,6 @@ _fbsd_uninit_driver(driver_t *driver)
uninit_mutexes();
put_module(B_PCI_MODULE_NAME);
if (gPCIx86 != NULL)
put_module(B_PCI_X86_MODULE_NAME);
}