pci: generic MSI interrupts support

Change-Id: Ib4fd23f6bca867a2b428bf2651234d719ee08672
Reviewed-on: https://review.haiku-os.org/c/haiku/+/6221
Reviewed-by: waddlesplash <[email protected]>
Reviewed-by: Adrien Destugues <[email protected]>
This commit is contained in:
X512
2023-04-25 15:54:32 +00:00
committed by waddlesplash
parent 26704b5974
commit e942269a1f
19 changed files with 256 additions and 198 deletions
@@ -12,6 +12,7 @@ KernelAddon pci :
pci_module.cpp
pci_root.cpp
pci_device.cpp
pci_msi.cpp
: pci_arch_bus_manager.a
;
@@ -75,20 +75,29 @@ PCIFU740::InitMSI(int32 msiIrq)
return result;
}
msi_set_interface(static_cast<MSIInterface*>(this));
dprintf(" fMsiStartIrq: %ld\n", fMsiStartIrq);
return B_OK;
}
int32
PCIFU740::AllocateMSIIrq()
status_t
PCIFU740::AllocateVectors(uint8 count, uint8& startVector, uint64& address, uint16& data)
{
if (count != 1)
return B_ERROR;
for (int i = 0; i < 32; i++) {
if (((1 << i) & fAllocatedMsiIrqs[0]) == 0) {
fAllocatedMsiIrqs[0] |= (1 << i);
GetDbuRegs()->msiIntr[0].mask &= ~(1 << i);
return i;
startVector = fMsiStartIrq + i;
address = fMsiPhysAddr;
data = i;
return B_OK;
}
}
return B_ERROR;
@@ -96,11 +105,16 @@ PCIFU740::AllocateMSIIrq()
void
PCIFU740::FreeMSIIrq(int32 irq)
PCIFU740::FreeVectors(uint8 count, uint8 startVector)
{
if (irq >= 0 && irq < 32 && ((1 << irq) & fAllocatedMsiIrqs[0]) != 0) {
GetDbuRegs()->msiIntr[0].mask |= (1 << (uint32)irq);
fAllocatedMsiIrqs[0] &= ~(1 << (uint32)irq);
int32 irq = (int32)startVector - fMsiStartIrq;
while (count > 0) {
if (irq >= 0 && irq < 32 && ((1 << irq) & fAllocatedMsiIrqs[0]) != 0) {
GetDbuRegs()->msiIntr[0].mask |= (1 << (uint32)irq);
fAllocatedMsiIrqs[0] &= ~(1 << (uint32)irq);
}
irq++;
count--;
}
}
@@ -400,68 +414,3 @@ PCIFU740::ConfigAddress(uint8 bus, uint8 device, uint8 function, uint16 offset)
return fConfigBase + offset;
}
void
PCIFU740::InitDeviceMSI(uint8 bus, uint8 device, uint8 function)
{
uint32 status;
uint32 capPtr;
uint32 capId;
ReadConfig(NULL, bus, device, function, PCI_status, 2, &status);
if ((status & PCI_status_capabilities) == 0)
return;
uint32 headerType;
ReadConfig(NULL, bus, device, function, PCI_header_type, 1, &headerType);
switch (headerType & PCI_header_type_mask) {
case PCI_header_type_generic:
case PCI_header_type_PCI_to_PCI_bridge:
ReadConfig(NULL, bus, device, function, PCI_capabilities_ptr, 1, &capPtr);
break;
case PCI_header_type_cardbus:
ReadConfig(NULL, bus, device, function, PCI_capabilities_ptr_2, 1, &capPtr);
break;
default:
return;
}
capPtr &= ~3;
if (capPtr == 0)
return;
for (int i = 0; i < 48; i++) {
ReadConfig(NULL, bus, device, function, capPtr + 0, 1, &capId);
if (capId == PCI_cap_id_msi)
break;
ReadConfig(NULL, bus, device, function, capPtr + 1, 1, &capPtr);
capPtr &= ~3;
if (capPtr == 0)
return;
}
dprintf(" MSI offset: %#x\n", capPtr);
int32 msiIrq = AllocateMSIIrq();
dprintf(" msiIrq: %" B_PRId32 "\n", msiIrq);
uint32 control;
ReadConfig(NULL, bus, device, function, capPtr + PCI_msi_control, 2, &control);
WriteConfig(NULL, bus, device, function, capPtr + PCI_msi_address, 4, (uint32)fMsiPhysAddr);
if ((control & PCI_msi_control_64bit) != 0) {
WriteConfig(NULL, bus, device, function, capPtr + PCI_msi_address_high, 4, (uint32)(fMsiPhysAddr >> 32));
WriteConfig(NULL, bus, device, function, capPtr + PCI_msi_data_64bit, 2, msiIrq);
} else
WriteConfig(NULL, bus, device, function, capPtr + PCI_msi_data, 2, msiIrq);
control &= ~PCI_msi_control_mme_mask;
control |= (ffs(1) - 1) << 4;
control |= PCI_msi_control_enable;
WriteConfig(NULL, bus, device, function, capPtr + PCI_msi_control, 2, control);
WriteConfig(NULL, bus, device, function, PCI_interrupt_line, 1, fMsiStartIrq + msiIrq);
}
@@ -5,6 +5,7 @@
#include "arch_pci_controller.h"
#include <arch/generic/msi.h>
enum {
@@ -39,22 +40,82 @@ struct PciAtuRegs {
};
class PCIFU740 : public ArchPCIController {
struct PciDbiRegs {
uint8 unknown0[0x700];
uint32 unknown1[3];
uint32 portAfr;
uint32 linkControl;
uint32 unknown2[5];
uint32 portDebug0;
uint32 portDebug1;
uint32 unknown3[55];
uint32 linkWidthSpeedControl;
uint32 unknown4[4];
uint32 msiAddrLo;
uint32 msiAddrHi;
struct {
uint32 enable;
uint32 mask;
uint32 status;
} msiIntr[8];
uint32 unknown5[13];
uint32 miscControl1Off;
uint32 miscPortMultiLaneCtrl;
uint32 unknown6[15];
uint32 atuViewport;
uint32 atuCr1;
uint32 atuCr2;
uint32 atuBaseLo;
uint32 atuBaseHi;
uint32 atuLimit;
uint32 atuTargetLo;
uint32 atuTargetHi;
uint32 unknown7;
uint32 atuLimitHi;
uint32 unknown8[8];
uint32 msixDoorbell;
uint32 unknown9[117];
uint32 plChkRegControlStatus;
uint32 unknown10;
uint32 plChkRegErrAddr;
uint32 unknown11[309];
};
class PCIFU740 : public ArchPCIController, public MSIInterface {
status_t Init(device_node* pciRootNode);
status_t InitMSI(int32 irq);
int32 AllocateMSIIrq();
void FreeMSIIrq(int32 irq);
int32 HandleMSIIrq(void* arg);
PciDbiRegs volatile* GetDbuRegs() {return (PciDbiRegs volatile*)fDbiBase;}
status_t InitMSI(int32 irq);
status_t AllocateVectors(uint8 count, uint8& startVector, uint64& address,
uint16& data) final;
void FreeVectors(uint8 count, uint8 startVector) final;
static int32 HandleMSIIrq(void* arg);
inline int32 HandleMSIIrqInt();
void EnableIoInterrupt(int irq) final;
void DisableIoInterrupt(int irq) final;
void ConfigureIoInterrupt(int irq, uint32 config) final;
int32 AssignToCpu(int32 irq, int32 cpu) final;
addr_t ConfigAddress(uint8 bus, uint8 device, uint8 function, uint16 offset);
void InitDeviceMSI(uint8 bus, uint8 device, uint8 function);
bool AllocateBar() { return false; }
private:
status_t AtuMap(uint32 index, uint32 direction, uint32 type,
uint64 parentAdr, uint64 childAdr, uint32 size);
void AtuDump();
private:
AreaDeleter fDbiArea;
addr_t fDbiPhysBase{};
addr_t fDbiBase{};
size_t fDbiSize{};
};
@@ -11,11 +11,8 @@ SubDirHdrs $(HAIKU_TOP) src add-ons kernel bus_managers acpi arch $(TARGET_KERNE
KernelStaticLibrary pci_arch_bus_manager :
pci_acpi.cpp
pci_arch_info.cpp
pci_arch_module.cpp
pci_bios.cpp
pci_controller.cpp
pci_io.cpp
pci_irq.cpp
pci_msi.cpp
;
@@ -1,14 +0,0 @@
/*
* Copyright 2010, Michael Lotz, [email protected]. All Rights Reserved.
* Distributed under the terms of the MIT License.
*/
#include "pci_arch_info.h"
void
pci_read_arch_info(PCIDev *dev)
{
pci_read_msi_info(dev);
pci_read_msix_info(dev);
pci_read_ht_mapping_info(dev);
}
@@ -1,19 +0,0 @@
/*
* Copyright 2010, Michael Lotz, [email protected]. All Rights Reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef _PCI_ARCH_INFO_H
#define _PCI_ARCH_INFO_H
#include "pci_msi.h"
typedef struct pci_arch_info {
msi_info msi;
msix_info msix;
ht_mapping_info ht_mapping;
} pci_arch_info;
void pci_read_arch_info(PCIDev *device);
#endif // _PCI_ARCH_INFO_H
@@ -1,49 +0,0 @@
/*
* Copyright 2010, Michael Lotz, [email protected]. All Rights Reserved.
* Distributed under the terms of the MIT License.
*/
#include <PCI.h>
#include <PCI_x86.h>
#include "pci_msi.h"
static int32
pci_arch_module_std_ops(int32 op, ...)
{
switch (op) {
case B_MODULE_INIT:
{
module_info *dummy;
status_t result = get_module(B_PCI_MODULE_NAME, &dummy);
if (result != B_OK)
return result;
return B_OK;
}
case B_MODULE_UNINIT:
put_module(B_PCI_MODULE_NAME);
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,
&pci_get_msix_count,
&pci_configure_msix,
&pci_enable_msix
};
+3 -3
View File
@@ -1551,9 +1551,9 @@ PCI::_RefreshDeviceInfo(PCIBus *bus)
for (PCIDev *dev = bus->child; dev; dev = dev->next) {
_ReadBasicInfo(dev);
_ReadHeaderInfo(dev);
#if defined(__i386__) || defined(__x86_64__)
pci_read_arch_info(dev);
#endif
pci_read_msi_info(dev);
pci_read_msix_info(dev);
pci_read_ht_mapping_info(dev);
if (dev->child)
_RefreshDeviceInfo(dev->child);
}
+6 -7
View File
@@ -14,10 +14,8 @@
#endif
#include "pci_controller.h"
#include "pci_msi.h"
#if defined(__i386__) || defined(__x86_64__)
#include "pci_arch_info.h"
#endif
#define TRACE_PCI
#ifndef TRACE_PCI
@@ -47,9 +45,10 @@ struct PCIDev {
uint8 device;
uint8 function;
pci_info info;
#if defined(__i386__) || defined(__x86_64__)
pci_arch_info arch_info;
#endif
msi_info msi;
msix_info msix;
ht_mapping_info ht_mapping;
};
@@ -105,7 +104,7 @@ public:
uint8 *offset);
status_t FindHTCapability(PCIDev *device,
uint16 capID, uint8 *offset = NULL);
status_t ResolveVirtualBus(uint8 virtualBus, uint8 *domain,
uint8 *bus);
@@ -7,6 +7,8 @@
#include <PCI.h>
#include <PCI_x86.h>
#include "pci_msi.h"
#include "pci_private.h"
#include "pci_info.h"
@@ -14,7 +16,6 @@
device_manager_info *gDeviceManager;
extern struct pci_arch_module gPCIArchModule;
static int32
pci_old_module_std_ops(int32 op, ...)
@@ -45,6 +46,29 @@ pci_old_module_std_ops(int32 op, ...)
}
static int32
pci_arch_module_std_ops(int32 op, ...)
{
switch (op) {
case B_MODULE_INIT:
{
module_info *dummy;
status_t result = get_module(B_PCI_MODULE_NAME, &dummy);
if (result != B_OK)
return result;
return B_OK;
}
case B_MODULE_UNINIT:
put_module(B_PCI_MODULE_NAME);
return B_OK;
}
return B_BAD_VALUE;
}
static struct pci_module_info sOldPCIModule = {
{
{
@@ -73,6 +97,25 @@ static struct pci_module_info sOldPCIModule = {
&pci_set_powerstate
};
static pci_x86_module_info sPCIArchModule = {
{
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,
&pci_get_msix_count,
&pci_configure_msix,
&pci_enable_msix
};
module_dependency module_dependencies[] = {
{B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&gDeviceManager},
{}
@@ -92,9 +135,6 @@ module_info *modules[] = {
(module_info *)&gPCIRootModule,
(module_info *)&gPCIDeviceModule,
(module_info *)&gPCILegacyDriverModule,
#if defined(__i386__) || defined(__x86_64__)
// add platforms when they provide an arch specific module
(module_info *)&gPCIArchModule,
#endif
(module_info *)&sPCIArchModule,
NULL
};
@@ -5,7 +5,6 @@
*/
#include "pci_msi.h"
#include "pci_arch_info.h"
#include "pci.h"
#include "pci_private.h"
@@ -24,7 +23,7 @@ static status_t pci_disable_msix(PCIDev *device);
static void
pci_ht_msi_map(PCIDev *device, uint64 address)
{
ht_mapping_info *info = &device->arch_info.ht_mapping;
ht_mapping_info *info = &device->ht_mapping;
if (!info->ht_mapping_capable)
return;
@@ -50,7 +49,7 @@ pci_read_ht_mapping_info(PCIDev *device)
if (!msi_supported())
return;
ht_mapping_info *info = &device->arch_info.ht_mapping;
ht_mapping_info *info = &device->ht_mapping;
info->ht_mapping_capable = false;
uint8 offset = 0;
@@ -90,7 +89,7 @@ pci_get_msi_count(uint8 virtualBus, uint8 _device, uint8 function)
if (device == NULL)
return 0;
msi_info *info = &device->arch_info.msi;
msi_info *info = &device->msi;
if (!info->msi_capable)
return 0;
@@ -118,7 +117,7 @@ pci_configure_msi(uint8 virtualBus, uint8 _device, uint8 function,
if (device == NULL)
return B_ERROR;
msi_info *info = &device->arch_info.msi;
msi_info *info = &device->msi;
if (!info->msi_capable)
return B_UNSUPPORTED;
@@ -177,7 +176,7 @@ pci_unconfigure_msi(uint8 virtualBus, uint8 _device, uint8 function)
if (result != B_UNSUPPORTED && result != B_NO_INIT)
return result;
msi_info *info = &device->arch_info.msi;
msi_info *info = &device->msi;
if (!info->msi_capable)
return B_UNSUPPORTED;
@@ -213,7 +212,7 @@ pci_enable_msi(uint8 virtualBus, uint8 _device, uint8 function)
if (device == NULL)
return B_ERROR;
msi_info *info = &device->arch_info.msi;
msi_info *info = &device->msi;
if (!info->msi_capable)
return B_UNSUPPORTED;
@@ -259,7 +258,7 @@ pci_disable_msi(uint8 virtualBus, uint8 _device, uint8 function)
if (result != B_UNSUPPORTED && result != B_NO_INIT)
return result;
msi_info *info = &device->arch_info.msi;
msi_info *info = &device->msi;
if (!info->msi_capable)
return B_UNSUPPORTED;
@@ -284,7 +283,7 @@ pci_read_msi_info(PCIDev *device)
if (!msi_supported())
return;
msi_info *info = &device->arch_info.msi;
msi_info *info = &device->msi;
info->msi_capable = false;
status_t result = gPCI->FindCapability(device->domain, device->bus,
device->device, device->function, PCI_cap_id_msi,
@@ -319,7 +318,7 @@ pci_get_msix_count(uint8 virtualBus, uint8 _device, uint8 function)
if (device == NULL)
return 0;
msix_info *info = &device->arch_info.msix;
msix_info *info = &device->msix;
if (!info->msix_capable)
return 0;
@@ -347,7 +346,7 @@ pci_configure_msix(uint8 virtualBus, uint8 _device, uint8 function,
if (device == NULL)
return B_ERROR;
msix_info *info = &device->arch_info.msix;
msix_info *info = &device->msix;
if (!info->msix_capable)
return B_UNSUPPORTED;
@@ -432,7 +431,7 @@ pci_configure_msix(uint8 virtualBus, uint8 _device, uint8 function,
static status_t
pci_unconfigure_msix(PCIDev *device)
{
msix_info *info = &device->arch_info.msix;
msix_info *info = &device->msix;
if (!info->msix_capable)
return B_UNSUPPORTED;
@@ -481,7 +480,7 @@ pci_enable_msix(uint8 virtualBus, uint8 _device, uint8 function)
if (device == NULL)
return B_ERROR;
msix_info *info = &device->arch_info.msix;
msix_info *info = &device->msix;
if (!info->msix_capable)
return B_UNSUPPORTED;
@@ -509,7 +508,7 @@ pci_enable_msix(uint8 virtualBus, uint8 _device, uint8 function)
status_t
pci_disable_msix(PCIDev *device)
{
msix_info *info = &device->arch_info.msix;
msix_info *info = &device->msix;
if (!info->msix_capable)
return B_UNSUPPORTED;
@@ -534,7 +533,7 @@ pci_read_msix_info(PCIDev *device)
if (!msi_supported())
return;
msix_info *info = &device->arch_info.msix;
msix_info *info = &device->msix;
info->msix_capable = false;
status_t result = gPCI->FindCapability(device->domain, device->bus,
device->device, device->function, PCI_cap_id_msix,
+2
View File
@@ -28,6 +28,8 @@ KernelMergeObject kernel_arch_arm.o :
arch_vm_translation_map.cpp
arch_asm.S
generic_msi.cpp
# Serial UART and drivers
debug_uart.cpp
debug_uart_8250.cpp
+2
View File
@@ -31,6 +31,8 @@ KernelMergeObject kernel_arch_arm64.o :
VMSAv8TranslationMap.cpp
PMAPPhysicalPageMapper.cpp
generic_msi.cpp
# Serial UART and drivers
debug_uart.cpp
debug_uart_8250.cpp
@@ -0,0 +1,39 @@
/*
* Copyright 2022, Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#include <arch/generic/msi.h>
MSIInterface* sMSIInterface;
void
msi_set_interface(MSIInterface* interface)
{
sMSIInterface = interface;
}
bool
msi_supported()
{
return sMSIInterface != NULL;
}
status_t
msi_allocate_vectors(uint8 count, uint8 *startVector, uint64 *address, uint16 *data)
{
return sMSIInterface->AllocateVectors(count, *startVector, *address, *data);
}
void
msi_free_vectors(uint8 count, uint8 startVector)
{
sMSIInterface->FreeVectors(count, startVector);
}
+2
View File
@@ -27,6 +27,8 @@ KernelMergeObject kernel_arch_riscv64.o :
Htif.cpp
sbi_syscalls.S
generic_msi.cpp
# Serial UART drivers
debug_uart.cpp
debug_uart_8250.cpp