From c19086408321f47e3778755934d9ca862cd27e28 Mon Sep 17 00:00:00 2001 From: Augustin Cavalier Date: Wed, 1 May 2019 15:43:27 -0400 Subject: [PATCH] bus_managers/pci: Properly handle 64-bit BAR addresses. We need to call pci_ram_address() on the whole address, not just the lower 32 bits, and then store both components inside the PCI info (previously we were leaving the high bits unset.) Very few drivers bother to check if the address is 64-bit or not, and for the most part they don't need to care, since the PCI bus is at 0x0 physically and will pretty much never get anywhere near 4GB in size. But the XHCI driver read these, and so would get bogus values for the high 32 bits, as we were never setting those. Probably fixes #15040. --- src/add-ons/kernel/bus_managers/pci/pci.cpp | 31 ++++++++++++++++----- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/src/add-ons/kernel/bus_managers/pci/pci.cpp b/src/add-ons/kernel/bus_managers/pci/pci.cpp index a31c6cc18e..04f0ac4012 100644 --- a/src/add-ons/kernel/bus_managers/pci/pci.cpp +++ b/src/add-ons/kernel/bus_managers/pci/pci.cpp @@ -1301,8 +1301,17 @@ PCI::_ReadHeaderInfo(PCIDev *dev) &dev->info.u.h0.base_register_sizes[i], &dev->info.u.h0.base_register_flags[i], i < 5 ? &dev->info.u.h0.base_registers_pci[i + 1] : NULL); - dev->info.u.h0.base_registers[i] = (uint32)pci_ram_address( - dev->info.u.h0.base_registers_pci[i]); + + phys_addr_t addr = dev->info.u.h0.base_registers_pci[i]; + if (barSize == 2) { + addr += ((phys_addr_t)dev->info.u.h0.base_registers_pci[i + 1]) + << 32; + } + addr = pci_ram_address(addr); + dev->info.u.h0.base_registers[i] = (uint32)addr; + if (barSize == 2) + dev->info.u.h0.base_registers[i + 1] = (uint32)(addr >> 32); + i += barSize; } @@ -1346,9 +1355,17 @@ PCI::_ReadHeaderInfo(PCIDev *dev) &dev->info.u.h1.base_registers_pci[i], &dev->info.u.h1.base_register_sizes[i], &dev->info.u.h1.base_register_flags[i], - i < 5 ? &dev->info.u.h1.base_registers_pci[i + 1] : NULL); - dev->info.u.h1.base_registers[i] = (uint32)pci_ram_address( - dev->info.u.h1.base_registers_pci[i]); + i < 2 ? &dev->info.u.h1.base_registers_pci[i + 1] : NULL); + + phys_addr_t addr = dev->info.u.h1.base_registers_pci[i]; + if (barSize == 2) { + addr += ((phys_addr_t)dev->info.u.h0.base_registers_pci[i + 1]) + << 32; + } + addr = pci_ram_address(addr); + dev->info.u.h1.base_registers[i] = (uint32)addr; + if (barSize == 2) + dev->info.u.h1.base_registers[i + 1] = (uint32)(addr >> 32); i += barSize; } @@ -1597,7 +1614,7 @@ PCI::FindCapability(uint8 domain, uint8 bus, uint8 device, uint8 function, for (int i = 0; i < 48; i++) { if (ReadConfig(domain, bus, device, function, capPointer, 1) == capID) { - if (offset != NULL) + if (offset != NULL) *offset = capPointer; return B_OK; } @@ -1684,7 +1701,7 @@ PCI::FindHTCapability(uint8 domain, uint8 bus, uint8 device, "not supported\n", bus, device, function, capID); return B_NAME_NOT_FOUND; } - + uint16 mask = PCI_ht_command_cap_mask_5_bits; if (capID == PCI_ht_command_cap_slave || capID == PCI_ht_command_cap_host) mask = PCI_ht_command_cap_mask_3_bits;