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 // private kernel header to get B_NO_HANDLED_INFO
#include <int.h> #include <int.h>
#include <PCI_x86.h>
//#define DEBUG_BUS_SPACE_RW //#define DEBUG_BUS_SPACE_RW
#ifdef DEBUG_BUS_SPACE_RW #ifdef DEBUG_BUS_SPACE_RW
@@ -48,6 +50,7 @@ struct internal_intr {
void *arg; void *arg;
int irq; int irq;
uint32 flags; uint32 flags;
bool is_msi;
thread_id thread; thread_id thread;
sem_id sem; sem_id sem;
@@ -138,9 +141,21 @@ bus_alloc_resource(device_t dev, int type, int *rid, unsigned long start,
if (res == NULL) if (res == NULL)
return NULL; return NULL;
if (type == SYS_RES_IRQ) if (type == SYS_RES_IRQ) {
result = bus_alloc_irq_resource(dev, res); if (*rid == 0) {
else if (type == SYS_RES_MEMORY) // 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); result = bus_alloc_mem_resource(dev, res, *rid);
else if (type == SYS_RES_IOPORT) else if (type == SYS_RES_IOPORT)
result = bus_alloc_ioport_resource(dev, res, *rid); 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->arg = arg;
intr->irq = res->r_bushandle; intr->irq = res->r_bushandle;
intr->flags = flags; intr->flags = flags;
intr->is_msi = false;
intr->sem = -1; intr->sem = -1;
intr->thread = -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); 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) { if (status < B_OK) {
free_internal_intr(intr); free_internal_intr(intr);
return status; return status;
@@ -358,6 +388,13 @@ bus_teardown_intr(device_t dev, struct resource *res, void *arg)
{ {
struct internal_intr *intr = 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) { if (intr->filter != NULL) {
remove_io_interrupt_handler(intr->irq, (interrupt_handler)intr->filter, remove_io_interrupt_handler(intr->irq, (interrupt_handler)intr->filter,
intr->arg); intr->arg);
@@ -659,21 +696,45 @@ pci_find_extcap(device_t child, int capability, int *_capabilityRegister)
int int
pci_msi_count(device_t dev) 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 int
pci_alloc_msi(device_t dev, int *count) 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 int
pci_release_msi(device_t dev) 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; struct net_stack_module_info *gStack;
pci_module_info *gPci; pci_module_info *gPci;
struct pci_x86_module_info *gPCIx86;
static struct list sRootDevices; static struct list sRootDevices;
static int sNextUnit; static int sNextUnit;
+1
View File
@@ -43,6 +43,7 @@ enum {
extern struct net_stack_module_info *gStack; extern struct net_stack_module_info *gStack;
extern pci_module_info *gPci; extern pci_module_info *gPci;
extern struct pci_x86_module_info *gPCIx86;
static inline void static inline void
+10
View File
@@ -19,6 +19,7 @@
#include <Drivers.h> #include <Drivers.h>
#include <ether_driver.h> #include <ether_driver.h>
#include <PCI_x86.h>
#include <compat/sys/haiku-module.h> #include <compat/sys/haiku-module.h>
@@ -149,6 +150,10 @@ _fbsd_init_driver(driver_t *driver)
if (status < B_OK) if (status < B_OK)
return status; 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(); status = init_hard_clock();
if (status < B_OK) if (status < B_OK)
goto err1; goto err1;
@@ -220,6 +225,9 @@ err2:
uninit_hard_clock(); uninit_hard_clock();
err1: err1:
put_module(B_PCI_MODULE_NAME); put_module(B_PCI_MODULE_NAME);
if (gPCIx86 != NULL)
put_module(B_PCI_X86_MODULE_NAME);
return status; return status;
} }
@@ -243,4 +251,6 @@ _fbsd_uninit_driver(driver_t *driver)
uninit_mutexes(); uninit_mutexes();
put_module(B_PCI_MODULE_NAME); put_module(B_PCI_MODULE_NAME);
if (gPCIx86 != NULL)
put_module(B_PCI_X86_MODULE_NAME);
} }