diff --git a/src/add-ons/kernel/bus_managers/pci/arch/x86/pci_arch_info.cpp b/src/add-ons/kernel/bus_managers/pci/arch/x86/pci_arch_info.cpp index 3071c12245..38f18df191 100644 --- a/src/add-ons/kernel/bus_managers/pci/arch/x86/pci_arch_info.cpp +++ b/src/add-ons/kernel/bus_managers/pci/arch/x86/pci_arch_info.cpp @@ -10,4 +10,5 @@ pci_read_arch_info(PCIDev *dev) { pci_read_msi_info(dev); pci_read_msix_info(dev); + pci_read_ht_mapping_info(dev); } diff --git a/src/add-ons/kernel/bus_managers/pci/arch/x86/pci_arch_info.h b/src/add-ons/kernel/bus_managers/pci/arch/x86/pci_arch_info.h index 4822dbe007..7e36c7bf4b 100644 --- a/src/add-ons/kernel/bus_managers/pci/arch/x86/pci_arch_info.h +++ b/src/add-ons/kernel/bus_managers/pci/arch/x86/pci_arch_info.h @@ -10,6 +10,7 @@ typedef struct pci_arch_info { msi_info msi; msix_info msix; + ht_mapping_info ht_mapping; } pci_arch_info; diff --git a/src/add-ons/kernel/bus_managers/pci/arch/x86/pci_msi.cpp b/src/add-ons/kernel/bus_managers/pci/arch/x86/pci_msi.cpp index 590551bff3..e87e852270 100644 --- a/src/add-ons/kernel/bus_managers/pci/arch/x86/pci_msi.cpp +++ b/src/add-ons/kernel/bus_managers/pci/arch/x86/pci_msi.cpp @@ -15,6 +15,60 @@ extern PCI *gPCI; +static void +pci_ht_msi_map(PCIDev *device, uint64 address) +{ + ht_mapping_info *info = &device->arch_info.ht_mapping; + if (!info->ht_mapping_capable) + return; + + bool enabled = (info->control_value & PCI_ht_command_msi_enable) != 0; + if ((address != 0) != enabled) { + if (enabled) { + info->control_value &= ~PCI_ht_command_msi_enable; + } else { + if ((address >> 20) != (info->address_value >> 20)) + return; + dprintf("ht msi mapping enabled\n"); + info->control_value |= PCI_ht_command_msi_enable; + } + gPCI->WriteConfig(device, info->capability_offset + PCI_ht_command, + info->control_value, 2); + } +} + + +void +pci_read_ht_mapping_info(PCIDev *device) +{ + if (!msi_supported()) + return; + + ht_mapping_info *info = &device->arch_info.ht_mapping; + info->ht_mapping_capable = false; + + uint8 offset = 0; + if (gPCI->FindHTCapability(device, PCI_ht_command_cap_msi_mapping, + &offset) == B_OK) { + info->control_value = gPCI->ReadConfig(device, offset + PCI_ht_command, + 2); + info->capability_offset = offset; + info->ht_mapping_capable = true; + if ((info->control_value & PCI_ht_command_msi_fixed) != 0) + info->address_value = MSI_ADDRESS_BASE; + else { + info->address_value = gPCI->ReadConfig(device, offset + + PCI_ht_msi_address_high, 4); + info->address_value <<= 32; + info->address_value |= gPCI->ReadConfig(device, offset + + PCI_ht_msi_address_low, 4); + } + dprintf("found an ht msi mapping at %#" B_PRIx64 "\n", + info->address_value); + } +} + + uint8 pci_get_msi_count(uint8 virtualBus, uint8 _device, uint8 function) { @@ -164,6 +218,9 @@ pci_enable_msi(uint8 virtualBus, uint8 _device, uint8 function) gPCI->WriteConfig(device, info->capability_offset + PCI_msi_control, 2, info->control_value); + // enable HT msi mapping (if applicable) + pci_ht_msi_map(device, info->address_value); + dprintf("msi enabled: 0x%04" B_PRIx32 "\n", gPCI->ReadConfig(device, info->capability_offset + PCI_msi_control, 2)); return B_OK; @@ -193,6 +250,9 @@ pci_disable_msi(uint8 virtualBus, uint8 _device, uint8 function) if (info->configured_count == 0) return B_NO_INIT; + // disable HT msi mapping (if applicable) + pci_ht_msi_map(device, 0); + // disable msi generation info->control_value &= ~PCI_msi_control_enable; gPCI->WriteConfig(device, info->capability_offset + PCI_msi_control, 2, @@ -423,6 +483,9 @@ pci_enable_msix(uint8 virtualBus, uint8 _device, uint8 function) gPCI->WriteConfig(device, info->capability_offset + PCI_msix_control, 2, info->control_value); + // enable HT msi mapping (if applicable) + pci_ht_msi_map(device, info->address_value); + dprintf("msi-x enabled: 0x%04" B_PRIx32 "\n", gPCI->ReadConfig(device, info->capability_offset + PCI_msix_control, 2)); return B_OK; @@ -452,6 +515,9 @@ pci_disable_msix(uint8 virtualBus, uint8 _device, uint8 function) if (info->configured_count == 0) return B_NO_INIT; + // disable HT msi mapping (if applicable) + pci_ht_msi_map(device, 0); + // disable msi-x generation info->control_value &= ~PCI_msix_control_enable; gPCI->WriteConfig(device, info->capability_offset + PCI_msix_control, 2, diff --git a/src/add-ons/kernel/bus_managers/pci/arch/x86/pci_msi.h b/src/add-ons/kernel/bus_managers/pci/arch/x86/pci_msi.h index 286d030f1a..52fa47a67d 100644 --- a/src/add-ons/kernel/bus_managers/pci/arch/x86/pci_msi.h +++ b/src/add-ons/kernel/bus_managers/pci/arch/x86/pci_msi.h @@ -10,9 +10,12 @@ #include +// Message Signaled Interrupts + + class PCIDev; -// Message Signaled Interrupts +// MSI typedef struct msi_info { bool msi_capable; uint8 capability_offset; @@ -34,7 +37,7 @@ status_t pci_disable_msi(uint8 virtualBus, uint8 device, uint8 function); void pci_read_msi_info(PCIDev *device); -// Message Signaled Interrupts +// MSI-X typedef struct msix_info { bool msix_capable; uint8 capability_offset; @@ -63,4 +66,16 @@ status_t pci_enable_msix(uint8 virtualBus, uint8 _device, uint8 function); status_t pci_disable_msix(uint8 virtualBus, uint8 _device, uint8 function); void pci_read_msix_info(PCIDev *device); +// HyperTransport MSI mapping +typedef struct ht_mapping_info { + bool ht_mapping_capable; + uint8 capability_offset; + uint16 control_value; + uint64 address_value; +} ht_mapping_info; + + +void pci_read_ht_mapping_info(PCIDev *device); + + #endif // _PCI_x86_MSI_H