* Add the framework for adding an arch specific module to the PCI bus_manager.

* Implement such a module for x86 which currently exports only an MSI API.
* Implement the PCI part for configuring and enabling MSIs.
* Some automatic whitespace cleanup.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@36223 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Michael Lotz
2010-04-13 15:18:46 +00:00
parent bafcab9265
commit 2548ea219a
12 changed files with 493 additions and 19 deletions
+35 -7
View File
@@ -83,7 +83,7 @@ typedef struct pci_info {
ulong rom_base_pci; /* rom base addr, viewed from pci */
uchar interrupt_line; /* interrupt line */
uchar interrupt_pin; /* interrupt pin */
ushort bridge_control;
ushort bridge_control;
ushort subsystem_id; /* subsystem (add-in card) id */
ushort subsystem_vendor_id; /* subsystem (add-in card) vendor id */
} h1;
@@ -109,7 +109,7 @@ typedef struct pci_info {
ushort secondary_status;
ushort bridge_control;
#endif /* __HAIKU_PCI_BUS_MANAGER_TESTING */
} h2;
} h2;
} u;
} pci_info;
@@ -221,7 +221,7 @@ struct pci_module_info {
#define PCI_primary_bus 0x18 /* (1 byte) */
#define PCI_secondary_bus 0x19 /* (1 byte) */
#define PCI_subordinate_bus 0x1A /* (1 byte) */
#define PCI_secondary_latency 0x1B /* (1 byte) latency of secondary bus */
#define PCI_secondary_latency 0x1B /* (1 byte) latency of secondary bus */
#define PCI_io_base 0x1C /* (1 byte) io base address register for 2ndry bus*/
#define PCI_io_limit 0x1D /* (1 byte) */
#define PCI_secondary_status 0x1E /* (2 bytes) */
@@ -236,7 +236,7 @@ struct pci_module_info {
#define PCI_sub_vendor_id_1 0x34 /* (2 bytes) */
#define PCI_sub_device_id_1 0x36 /* (2 bytes) */
#define PCI_bridge_rom_base 0x38
#define PCI_bridge_control 0x3E /* (2 bytes) */
#define PCI_bridge_control 0x3E /* (2 bytes) */
/* PCI type 2 header offsets */
@@ -245,7 +245,7 @@ struct pci_module_info {
#define PCI_primary_bus_2 0x18 /* (1 byte) */
#define PCI_secondary_bus_2 0x19 /* (1 byte) */
#define PCI_subordinate_bus_2 0x1A /* (1 byte) */
#define PCI_secondary_latency_2 0x1B /* (1 byte) latency of secondary bus */
#define PCI_secondary_latency_2 0x1B /* (1 byte) latency of secondary bus */
#define PCI_memory_base0_2 0x1C /* (4 bytes) */
#define PCI_memory_limit0_2 0x20 /* (4 bytes) */
#define PCI_memory_base1_2 0x24 /* (4 bytes) */
@@ -588,8 +588,8 @@ struct pci_module_info {
/** types of PCI header */
#define PCI_header_type_generic 0x00
#define PCI_header_type_PCI_to_PCI_bridge 0x01
#define PCI_header_type_generic 0x00
#define PCI_header_type_PCI_to_PCI_bridge 0x01
#define PCI_header_type_cardbus 0x02
@@ -677,6 +677,34 @@ struct pci_module_info {
#define PCI_pm_state_d2 0x02
#define PCI_pm_state_d3 0x03
/** MSI registers **/
#define PCI_msi_control 0x02
#define PCI_msi_address 0x04
#define PCI_msi_address_high 0x08
#define PCI_msi_data 0x08
#define PCI_msi_data_64bit 0x0c
#define PCI_msi_mask 0x10
#define PCI_msi_pending 0x14
/** MSI control register values **/
#define PCI_msi_control_enable 0x0001
#define PCI_msi_control_vector 0x0100
#define PCI_msi_control_64bit 0x0080
#define PCI_msi_control_mme_mask 0x0070
#define PCI_msi_control_mme_1 0x0000
#define PCI_msi_control_mme_2 0x0010
#define PCI_msi_control_mme_4 0x0020
#define PCI_msi_control_mme_8 0x0030
#define PCI_msi_control_mme_16 0x0040
#define PCI_msi_control_mme_32 0x0050
#define PCI_msi_control_mmc_mask 0x000e
#define PCI_msi_control_mmc_1 0x0000
#define PCI_msi_control_mmc_2 0x0002
#define PCI_msi_control_mmc_4 0x0004
#define PCI_msi_control_mmc_8 0x0006
#define PCI_msi_control_mmc_16 0x0008
#define PCI_msi_control_mmc_32 0x000a
#ifdef __cplusplus
}
#endif
+38
View File
@@ -0,0 +1,38 @@
#ifndef PCI_X86_H
#define PCI_X86_H
#include <SupportDefs.h>
#include <module.h>
typedef struct pci_x86_module_info {
module_info info;
uint8 (*get_msi_count)(
uint8 bus, /* bus number */
uint8 device, /* device # on bus */
uint8 function); /* function # in device */
status_t (*configure_msi)(
uint8 bus, /* bus number */
uint8 device, /* device # on bus */
uint8 function, /* function # in device */
uint8 count, /* count of vectors desired */
uint8 *startVector); /* first configured vector */
status_t (*unconfigure_msi)(
uint8 bus, /* bus number */
uint8 device, /* device # on bus */
uint8 function); /* function # in device */
status_t (*enable_msi)(
uint8 bus, /* bus number */
uint8 device, /* device # on bus */
uint8 function); /* function # in device */
status_t (*disable_msi)(
uint8 bus, /* bus number */
uint8 device, /* device # on bus */
uint8 function); /* function # in device */
} pci_x86_module_info;
#define B_PCI_X86_MODULE_NAME "bus_managers/pci/x86/v1"
#endif // PCI_X86_H
+2 -1
View File
@@ -3,12 +3,13 @@ SubDir HAIKU_TOP src add-ons kernel bus_managers pci ;
UsePrivateKernelHeaders ;
UsePrivateHeaders shared ;
UsePrivateHeaders [ FDirName kernel util ] ;
UseHeaders [ FDirName $(SUBDIR) arch $(TARGET_ARCH) ] ;
KernelAddon pci :
pci.cpp
pci_fixup.cpp
pci_info.cpp
pci_module.c
pci_module.cpp
pci_root.cpp
pci_device.cpp
: pci_arch_bus_manager.a
@@ -2,12 +2,14 @@ SubDir HAIKU_TOP src add-ons kernel bus_managers pci arch x86 ;
SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) $(DOTDOT) ] ;
UsePrivateHeaders kernel [ FDirName kernel arch x86 ] ;
UsePrivateHeaders kernel [ FDirName kernel arch x86 ] [ FDirName kernel util ] ;
KernelStaticLibrary pci_arch_bus_manager :
KernelStaticLibrary pci_arch_bus_manager :
pci_arch_info.cpp
pci_arch_module.cpp
pci_bios.c
pci_controller.c
pci_io.c
pci_irq.c
pci_msi.cpp
;
@@ -0,0 +1,7 @@
#include "pci_arch_info.h"
void
pci_read_arch_info(PCIDev *dev)
{
pci_read_msi_info(dev);
}
@@ -0,0 +1,13 @@
#ifndef _PCI_ARCH_INFO_H
#define _PCI_ARCH_INFO_H
#include "pci_msi.h"
typedef struct pci_arch_info {
msi_info msi;
} pci_arch_info;
void pci_read_arch_info(PCIDev *device);
#endif // _PCI_ARCH_INFO_H
@@ -0,0 +1,30 @@
#include <PCI_x86.h>
#include "pci_msi.h"
static int32
pci_arch_module_std_ops(int32 op, ...)
{
switch (op) {
case B_MODULE_INIT:
case B_MODULE_UNINIT:
return B_OK;
}
return B_BAD_VALUE;
}
pci_x86_module_info gPCIArchModule = {
{
B_PCI_X86_MODULE_NAME,
0,
pci_arch_module_std_ops
},
&pci_get_msi_count,
&pci_configure_msi,
&pci_unconfigure_msi,
&pci_enable_msi,
&pci_disable_msi
};
@@ -0,0 +1,222 @@
#include "pci_msi.h"
#include "pci_arch_info.h"
#include "pci.h"
#include "pci_private.h"
#include <arch/x86/msi.h>
#include <debug.h>
extern PCI *gPCI;
uint8
pci_get_msi_count(uint8 virtualBus, uint8 _device, uint8 function)
{
if (!msi_supported())
return 0;
uint8 bus;
int domain;
if (gPCI->ResolveVirtualBus(virtualBus, &domain, &bus) != B_OK)
return 0;
PCIDev *device = gPCI->FindDevice(domain, bus, _device, function);
if (device == NULL)
return 0;
msi_info *info = &device->arch_info.msi;
if (!info->msi_capable)
return 0;
return info->message_count;
}
status_t
pci_configure_msi(uint8 virtualBus, uint8 _device, uint8 function,
uint8 count, uint8 *startVector)
{
if (!msi_supported())
return B_UNSUPPORTED;
if (count == 0 || startVector == NULL)
return B_BAD_VALUE;
uint8 bus;
int domain;
status_t result = gPCI->ResolveVirtualBus(virtualBus, &domain, &bus);
if (result != B_OK)
return result;
PCIDev *device = gPCI->FindDevice(domain, bus, _device, function);
if (device == NULL)
return B_ERROR;
msi_info *info = &device->arch_info.msi;
if (!info->msi_capable)
return B_UNSUPPORTED;
if (count > 32 || count > info->message_count
|| ((count - 1) & count) != 0 /* needs to be a power of 2 */) {
return B_BAD_VALUE;
}
if (info->configured_count != 0)
return B_BUSY;
result = msi_allocate_vectors(count, &info->start_vector,
&info->address_value, &info->data_value);
if (result != B_OK)
return result;
uint8 offset = info->capability_offset;
gPCI->WriteConfig(device, offset + PCI_msi_address, 4,
info->address_value & 0xffffffff);
if (info->control_value & PCI_msi_control_64bit) {
gPCI->WriteConfig(device, offset + PCI_msi_address_high, 4,
info->address_value >> 32);
gPCI->WriteConfig(device, offset + PCI_msi_data_64bit, 2,
info->data_value);
} else
gPCI->WriteConfig(device, offset + PCI_msi_data, 2, info->data_value);
info->control_value &= ~PCI_msi_control_mme_mask;
info->control_value |= (ffs(count) - 1) << 4;
gPCI->WriteConfig(device, offset + PCI_msi_control, 2, info->control_value);
info->configured_count = count;
*startVector = info->start_vector;
return B_OK;
}
status_t
pci_unconfigure_msi(uint8 virtualBus, uint8 _device, uint8 function)
{
if (!msi_supported())
return B_UNSUPPORTED;
uint8 bus;
int domain;
status_t result = gPCI->ResolveVirtualBus(virtualBus, &domain, &bus);
if (result != B_OK)
return result;
PCIDev *device = gPCI->FindDevice(domain, bus, _device, function);
if (device == NULL)
return B_ERROR;
msi_info *info = &device->arch_info.msi;
if (!info->msi_capable)
return B_UNSUPPORTED;
if (info->configured_count == 0)
return B_NO_INIT;
msi_free_vectors(info->configured_count, info->start_vector);
info->control_value &= ~PCI_msi_control_mme_mask;
gPCI->WriteConfig(device, info->capability_offset + PCI_msi_control, 2,
info->control_value);
info->configured_count = 0;
info->address_value = 0;
info->data_value = 0;
return B_OK;
}
status_t
pci_enable_msi(uint8 virtualBus, uint8 _device, uint8 function)
{
if (!msi_supported())
return B_UNSUPPORTED;
uint8 bus;
int domain;
status_t result = gPCI->ResolveVirtualBus(virtualBus, &domain, &bus);
if (result != B_OK)
return result;
PCIDev *device = gPCI->FindDevice(domain, bus, _device, function);
if (device == NULL)
return B_ERROR;
msi_info *info = &device->arch_info.msi;
if (!info->msi_capable)
return B_UNSUPPORTED;
if (info->configured_count == 0)
return B_NO_INIT;
// ensure the pinned interrupt is disabled
gPCI->WriteConfig(device, PCI_command, 2,
gPCI->ReadConfig(device, PCI_command, 2) | PCI_command_int_disable);
// enable msi generation
info->control_value |= PCI_msi_control_enable;
gPCI->WriteConfig(device, info->capability_offset + PCI_msi_control, 2,
info->control_value);
dprintf("msi enabled: 0x%04lx\n",
gPCI->ReadConfig(device, info->capability_offset + PCI_msi_control, 2));
return B_OK;
}
status_t
pci_disable_msi(uint8 virtualBus, uint8 _device, uint8 function)
{
if (!msi_supported())
return B_UNSUPPORTED;
uint8 bus;
int domain;
status_t result = gPCI->ResolveVirtualBus(virtualBus, &domain, &bus);
if (result != B_OK)
return result;
PCIDev *device = gPCI->FindDevice(domain, bus, _device, function);
if (device == NULL)
return B_ERROR;
msi_info *info = &device->arch_info.msi;
if (!info->msi_capable)
return B_UNSUPPORTED;
if (info->configured_count == 0)
return B_NO_INIT;
// disable msi generation
info->control_value &= ~PCI_msi_control_enable;
gPCI->WriteConfig(device, info->capability_offset + PCI_msi_control, 2,
info->control_value);
return B_OK;
}
void
pci_read_msi_info(PCIDev *device)
{
if (!msi_supported())
return;
msi_info *info = &device->arch_info.msi;
info->msi_capable = false;
status_t result = gPCI->FindCapability(device->domain, device->bus,
device->device, device->function, PCI_cap_id_msi,
&info->capability_offset);
if (result != B_OK)
return;
info->msi_capable = true;
info->control_value = gPCI->ReadConfig(device->domain, device->bus,
device->device, device->function,
info->capability_offset + PCI_msi_control, 2);
info->message_count
= 1 << ((info->control_value & PCI_msi_control_mmc_mask) >> 1);
info->configured_count = 0;
info->data_value = 0;
info->address_value = 0;
}
@@ -0,0 +1,29 @@
#ifndef _PCI_x86_MSI_H
#define _PCI_x86_MSI_H
#include <SupportDefs.h>
class PCIDev;
// Message Signaled Interrupts
typedef struct msi_info {
bool msi_capable;
uint8 capability_offset;
uint8 message_count;
uint8 configured_count;
uint8 start_vector;
uint16 control_value;
uint16 data_value;
uint64 address_value;
} msi_info;
uint8 pci_get_msi_count(uint8 virtualBus, uint8 _device, uint8 function);
status_t pci_configure_msi(uint8 virtualBus, uint8 _device, uint8 function,
uint8 count, uint8 *startVector);
status_t pci_unconfigure_msi(uint8 virtualBus, uint8 device, uint8 function);
status_t pci_enable_msi(uint8 virtualBus, uint8 device, uint8 function);
status_t pci_disable_msi(uint8 virtualBus, uint8 device, uint8 function);
void pci_read_msi_info(PCIDev *device);
#endif // _PCI_x86_MSI_H
+10 -7
View File
@@ -103,7 +103,7 @@ pci_reserve_device(uchar virtualBus, uchar device, uchar function,
if (gPCI->ResolveVirtualBus(virtualBus, &domain, &bus) != B_OK)
return B_ERROR;
//TRACE(("%s(%d [%d:%d], %d, %d, %s, %p)\n", __FUNCTION__, virtualBus,
//TRACE(("%s(%d [%d:%d], %d, %d, %s, %p)\n", __FUNCTION__, virtualBus,
// domain, bus, device, function, driverName, nodeCookie));
device_attr matchPCIRoot[] = {
@@ -140,7 +140,7 @@ pci_reserve_device(uchar virtualBus, uchar device, uchar function,
root = gDeviceManager->get_root_node();
if (!root)
return status;
pci = NULL;
if (gDeviceManager->get_next_child_node(root, matchPCIRoot, &pci) < B_OK)
goto err0;
@@ -148,16 +148,16 @@ pci_reserve_device(uchar virtualBus, uchar device, uchar function,
node = NULL;
if (gDeviceManager->get_next_child_node(pci, matchThis, &node) < B_OK)
goto err1;
// common API for all legacy modules ?
//status = legacy_driver_register(node, driverName, nodeCookie, PCI_LEGACY_DRIVER_MODULE_NAME);
status = gDeviceManager->register_node(node, PCI_LEGACY_DRIVER_MODULE_NAME,
status = gDeviceManager->register_node(node, PCI_LEGACY_DRIVER_MODULE_NAME,
legacyAttrs, NULL, &legacy);
if (status < B_OK)
goto err2;
status = gDeviceManager->register_node(legacy, PCI_LEGACY_DRIVER_MODULE_NAME,
status = gDeviceManager->register_node(legacy, PCI_LEGACY_DRIVER_MODULE_NAME,
drvAttrs, NULL, NULL);
if (status < B_OK)
goto err3;
@@ -192,7 +192,7 @@ pci_unreserve_device(uchar virtualBus, uchar device, uchar function,
if (gPCI->ResolveVirtualBus(virtualBus, &domain, &bus) != B_OK)
return B_ERROR;
//TRACE(("%s(%d [%d:%d], %d, %d, %s, %p)\n", __FUNCTION__, virtualBus,
//TRACE(("%s(%d [%d:%d], %d, %d, %s, %p)\n", __FUNCTION__, virtualBus,
// domain, bus, device, function, driverName, nodeCookie));
device_attr matchPCIRoot[] = {
@@ -237,7 +237,7 @@ pci_unreserve_device(uchar virtualBus, uchar device, uchar function,
node = NULL;
if (gDeviceManager->get_next_child_node(pci, matchThis, &node) < B_OK)
goto err1;
// common API for all legacy modules ?
//status = legacy_driver_unregister(node, driverName, nodeCookie);
@@ -1325,6 +1325,9 @@ PCI::_RefreshDeviceInfo(PCIBus *bus)
for (PCIDev *dev = bus->child; dev; dev = dev->next) {
_ReadBasicInfo(dev);
_ReadHeaderInfo(dev);
#ifdef __INTEL__
pci_read_arch_info(dev);
#endif
if (dev->child)
_RefreshDeviceInfo(dev->child);
}
+6 -1
View File
@@ -15,6 +15,9 @@
#include "pci_controller.h"
#ifdef __INTEL__
#include "pci_arch_info.h"
#endif
#define TRACE_PCI
#ifndef TRACE_PCI
@@ -23,7 +26,6 @@
# define TRACE(x) dprintf x
#endif
#ifdef __cplusplus
struct PCIDev;
@@ -45,6 +47,9 @@ struct PCIDev {
uint8 device;
uint8 function;
pci_info info;
#ifdef __INTEL__
pci_arch_info arch_info;
#endif
};
@@ -0,0 +1,96 @@
/*
* Copyright 2005-2008, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
* Copyright 2003, Marcus Overhagen. All rights reserved.
*
* Distributed under the terms of the MIT License.
*/
#include <PCI.h>
#include "pci_private.h"
#include "pci_info.h"
#include "pci.h"
device_manager_info *gDeviceManager;
extern struct pci_arch_module gPCIArchModule;
static int32
pci_old_module_std_ops(int32 op, ...)
{
switch (op) {
case B_MODULE_INIT:
{
status_t status;
TRACE(("PCI: pci_module_init\n"));
status = pci_init();
if (status < B_OK)
return status;
pci_print_info();
return B_OK;
}
case B_MODULE_UNINIT:
TRACE(("PCI: pci_module_uninit\n"));
pci_uninit();
return B_OK;
}
return B_BAD_VALUE;
}
static struct pci_module_info sOldPCIModule = {
{
{
B_PCI_MODULE_NAME,
B_KEEP_LOADED,
pci_old_module_std_ops
},
NULL
},
&pci_read_io_8,
&pci_write_io_8,
&pci_read_io_16,
&pci_write_io_16,
&pci_read_io_32,
&pci_write_io_32,
&pci_get_nth_pci_info,
&pci_read_config,
&pci_write_config,
&pci_ram_address,
&pci_find_capability,
&pci_reserve_device,
&pci_unreserve_device
};
module_dependency module_dependencies[] = {
{B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&gDeviceManager},
{}
};
driver_module_info gPCILegacyDriverModule = {
{
PCI_LEGACY_DRIVER_MODULE_NAME,
0,
NULL,
},
NULL
};
module_info *modules[] = {
(module_info *)&sOldPCIModule,
(module_info *)&gPCIRootModule,
(module_info *)&gPCIDeviceModule,
(module_info *)&gPCILegacyDriverModule,
#ifdef __INTEL__
// add platforms when they provide an arch specific module
(module_info *)&gPCIArchModule,
#endif
NULL
};