[haiku-commits] haiku: hrev45777 - src/add-ons/kernel/bus_managers/pci/arch/x86 src/add-ons/kernel/bus_managers/pci headers/os/drivers src/add-ons/kernel/bus_managers/pci/arch/ppc/openfirmware src/add-ons/kernel/bus_managers/pci/arch/m68k/atari

  • From: korli@xxxxxxxxxxxxxxxx
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Sat, 22 Jun 2013 19:50:31 +0200 (CEST)

hrev45777 adds 3 changesets to branch 'master'
old head: bc7a518375cc478c3630ad875fc23cbae51e8db0
new head: 26a4510e591b2d12b5191918ca4e92a5f94b2bd5
overview: http://cgit.haiku-os.org/haiku/log/?qt=range&q=26a4510+%5Ebc7a518

----------------------------------------------------------------------------

ce353e5: pci: added pcie mechanism for config space access.
  
  * pci-acpi.cpp is based on the bootloader bios_ia32/acpi.cpp. The ACPI module
  has already a dependency on the PCI module. Using pci-acpi.cpp eases the 
simple
  task of finding the PCIe base address to map the config space.
  * pci_read_config and pci_write_config in pci_controller.h were using an uint8
  for offsets in the config space. Switched to uint16 to enable access to the 
extended
  config space (0x100 and upper). Added a check for these offsets in
  pci_mech[1|2]_[read|write]_config() for x86 and other platforms as these 
mechanisms
  don't support a priori the extended config space.

e1c4476: pci: switched PCI::[Read|Write]Config to type uint16 for the offset.

26a4510: pci: added pci_find_extended_capability().
  
  * added PCI Extended Capabilities definitions.
  * pci_find_capability() parameter offset is now optional.

                                   [ Jérôme Duval <jerome.duval@xxxxxxxxx> ]

----------------------------------------------------------------------------

14 files changed, 592 insertions(+), 53 deletions(-)
headers/os/drivers/PCI.h                         |  36 +++
.../pci/arch/m68k/atari/pci_atari.cpp            |   8 +-
.../pci/arch/ppc/openfirmware/grackle.cpp        |  10 +-
.../pci/arch/ppc/openfirmware/uninorth.cpp       |  14 +-
.../kernel/bus_managers/pci/arch/x86/Jamfile     |   5 +
.../bus_managers/pci/arch/x86/pci_acpi.cpp       | 270 +++++++++++++++++++
.../kernel/bus_managers/pci/arch/x86/pci_acpi.h  |  27 ++
.../bus_managers/pci/arch/x86/pci_bios.cpp       |   4 +-
.../kernel/bus_managers/pci/arch/x86/pci_bios.h  |   4 +-
.../bus_managers/pci/arch/x86/pci_controller.cpp | 142 +++++++++-
src/add-ons/kernel/bus_managers/pci/pci.cpp      |  97 +++++--
src/add-ons/kernel/bus_managers/pci/pci.h        |  19 +-
.../kernel/bus_managers/pci/pci_controller.h     |   4 +-
.../kernel/bus_managers/pci/pci_private.h        |   5 +-

############################################################################

Commit:      ce353e5d6e65080fe81c58aa5c61abef824ad00e
URL:         http://cgit.haiku-os.org/haiku/commit/?id=ce353e5
Author:      Jérôme Duval <jerome.duval@xxxxxxxxx>
Date:        Sat Jun 22 17:13:39 2013 UTC

pci: added pcie mechanism for config space access.

* pci-acpi.cpp is based on the bootloader bios_ia32/acpi.cpp. The ACPI module
has already a dependency on the PCI module. Using pci-acpi.cpp eases the simple
task of finding the PCIe base address to map the config space.
* pci_read_config and pci_write_config in pci_controller.h were using an uint8
for offsets in the config space. Switched to uint16 to enable access to the 
extended
config space (0x100 and upper). Added a check for these offsets in
pci_mech[1|2]_[read|write]_config() for x86 and other platforms as these 
mechanisms
don't support a priori the extended config space.

----------------------------------------------------------------------------

diff --git a/src/add-ons/kernel/bus_managers/pci/arch/m68k/atari/pci_atari.cpp 
b/src/add-ons/kernel/bus_managers/pci/arch/m68k/atari/pci_atari.cpp
index d29f51c..c81474a 100644
--- a/src/add-ons/kernel/bus_managers/pci/arch/m68k/atari/pci_atari.cpp
+++ b/src/add-ons/kernel/bus_managers/pci/arch/m68k/atari/pci_atari.cpp
@@ -82,9 +82,9 @@ static int            m68k_atari_enable_config(struct 
m68k_atari_fake_host_bridge *bridge,
                                        uint8 bus, uint8 slot, uint8 function, 
uint8 offset);
 
 static status_t        m68k_atari_read_pci_config(void *cookie, uint8 bus, 
uint8 device,
-                                       uint8 function, uint8 offset, uint8 
size, uint32 *value);
+                                       uint8 function, uint16 offset, uint8 
size, uint32 *value);
 static status_t        m68k_atari_write_pci_config(void *cookie, uint8 bus,
-                                       uint8 device, uint8 function, uint8 
offset, uint8 size,
+                                       uint8 device, uint8 function, uint16 
offset, uint8 size,
                                        uint32 value);
 static status_t        m68k_atari_get_max_bus_devices(void *cookie, int32 
*count);
 static status_t        m68k_atari_read_pci_irq(void *cookie, uint8 bus, uint8 
device,
@@ -103,7 +103,7 @@ static pci_controller sM68kAtariPCIController = {
 
 static status_t
 m68k_atari_read_pci_config(void *cookie, uint8 bus, uint8 device, uint8 
function,
-       uint8 offset, uint8 size, uint32 *value)
+       uint16 offset, uint8 size, uint32 *value)
 {
        struct fake_pci_device *devices = (struct fake_pci_device *)cookie;
        struct fake_pci_device *dev;
@@ -183,7 +183,7 @@ m68k_atari_read_pci_config(void *cookie, uint8 bus, uint8 
device, uint8 function
 
 static status_t
 m68k_atari_write_pci_config(void *cookie, uint8 bus, uint8 device,
-       uint8 function, uint8 offset, uint8 size, uint32 value)
+       uint8 function, uint16 offset, uint8 size, uint32 value)
 {
 #if 0
        if (m68k_atari_enable_config(bridge, bus, device, function, offset)) {
diff --git 
a/src/add-ons/kernel/bus_managers/pci/arch/ppc/openfirmware/grackle.cpp 
b/src/add-ons/kernel/bus_managers/pci/arch/ppc/openfirmware/grackle.cpp
index 7a67ca0..b0a98f1 100644
--- a/src/add-ons/kernel/bus_managers/pci/arch/ppc/openfirmware/grackle.cpp
+++ b/src/add-ons/kernel/bus_managers/pci/arch/ppc/openfirmware/grackle.cpp
@@ -80,13 +80,16 @@ struct grackle_host_bridge {
 
 static status_t
 grackle_read_pci_config(void *cookie, uint8 bus, uint8 device, uint8 function,
-       uint8 offset, uint8 size, uint32 *value)
+       uint16 offset, uint8 size, uint32 *value)
 {
        grackle_host_bridge *bridge = (grackle_host_bridge*)cookie;
        TRACE("grackle_read_pci_config(bus=%u, dev=%u, func=%u, offset=%u, "
                "size=%u)\n", (int)bus, (int)device, (int)function, (int)offset,
                (int)size);
 
+       if (offset > 0xff)
+               return B_BAD_VALUE;
+
        out32rb(bridge->address_registers, (1 << 31)
                | (bus << 16) | ((device & 0x1f) << 11) | ((function & 0x7) << 
8)
                | (offset & 0xfc));
@@ -115,13 +118,16 @@ grackle_read_pci_config(void *cookie, uint8 bus, uint8 
device, uint8 function,
 
 static status_t
 grackle_write_pci_config(void *cookie, uint8 bus, uint8 device, uint8 function,
-       uint8 offset, uint8 size, uint32 value)
+       uint16 offset, uint8 size, uint32 value)
 {
        grackle_host_bridge *bridge = (grackle_host_bridge*)cookie;
        TRACE("grackle_write_pci_config(bus=%u, dev=%u, func=%u, offset=%u, "
                "size=%u, value=%lu)\n", (int)bus, (int)device, (int)function,
                (int)offset, (int)size, value);
 
+       if (offset > 0xff)
+               return B_BAD_VALUE;
+
        out32rb(bridge->address_registers, (1 << 31)
                | (bus << 16) | ((device & 0x1f) << 11) | ((function & 0x7) << 
8)
                | (offset & 0xfc));
diff --git 
a/src/add-ons/kernel/bus_managers/pci/arch/ppc/openfirmware/uninorth.cpp 
b/src/add-ons/kernel/bus_managers/pci/arch/ppc/openfirmware/uninorth.cpp
index d7a1f4c..7997129 100644
--- a/src/add-ons/kernel/bus_managers/pci/arch/ppc/openfirmware/uninorth.cpp
+++ b/src/add-ons/kernel/bus_managers/pci/arch/ppc/openfirmware/uninorth.cpp
@@ -74,9 +74,9 @@ static int            uninorth_enable_config(struct 
uninorth_host_bridge *bridge,
                                        uint8 bus, uint8 slot, uint8 function, 
uint8 offset);
 
 static status_t        uninorth_read_pci_config(void *cookie, uint8 bus, uint8 
device,
-                                       uint8 function, uint8 offset, uint8 
size, uint32 *value);
+                                       uint8 function, uint16 offset, uint8 
size, uint32 *value);
 static status_t        uninorth_write_pci_config(void *cookie, uint8 bus,
-                                       uint8 device, uint8 function, uint8 
offset, uint8 size,
+                                       uint8 device, uint8 function, uint16 
offset, uint8 size,
                                        uint32 value);
 static status_t        uninorth_get_max_bus_devices(void *cookie, int32 
*count);
 static status_t        uninorth_read_pci_irq(void *cookie, uint8 bus, uint8 
device,
@@ -95,10 +95,13 @@ static pci_controller sUniNorthPCIController = {
 
 static status_t
 uninorth_read_pci_config(void *cookie, uint8 bus, uint8 device, uint8 function,
-       uint8 offset, uint8 size, uint32 *value)
+       uint16 offset, uint8 size, uint32 *value)
 {
        uninorth_host_bridge *bridge = (uninorth_host_bridge*)cookie;
 
+       if (offset > 0xff)
+               return B_BAD_VALUE;
+
        addr_t caoff = bridge->data_registers + (offset & 0x07);
 
        if (uninorth_enable_config(bridge, bus, device, function, offset) != 0) 
{
@@ -124,10 +127,13 @@ uninorth_read_pci_config(void *cookie, uint8 bus, uint8 
device, uint8 function,
 
 
 static status_t uninorth_write_pci_config(void *cookie, uint8 bus, uint8 
device,
-       uint8 function, uint8 offset, uint8 size, uint32 value)
+       uint8 function, uint16 offset, uint8 size, uint32 value)
 {
        uninorth_host_bridge *bridge = (uninorth_host_bridge*)cookie;
 
+       if (offset > 0xff)
+               return B_BAD_VALUE;
+
        addr_t caoff = bridge->data_registers + (offset & 0x07);
 
        if (uninorth_enable_config(bridge, bus, device, function, offset)) {
diff --git a/src/add-ons/kernel/bus_managers/pci/arch/x86/Jamfile 
b/src/add-ons/kernel/bus_managers/pci/arch/x86/Jamfile
index f03f6c7..980b450 100644
--- a/src/add-ons/kernel/bus_managers/pci/arch/x86/Jamfile
+++ b/src/add-ons/kernel/bus_managers/pci/arch/x86/Jamfile
@@ -4,7 +4,12 @@ SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) $(DOTDOT) ] ;
 
 UsePrivateHeaders kernel [ FDirName kernel arch x86 ] [ FDirName kernel util ] 
;
 
+SubDirHdrs $(HAIKU_TOP) src add-ons kernel bus_managers acpi acpica include ;
+SubDirHdrs $(HAIKU_TOP) src add-ons kernel bus_managers acpi acpica include
+       platform ;
+
 KernelStaticLibrary pci_arch_bus_manager :
+       pci_acpi.cpp
        pci_arch_info.cpp
        pci_arch_module.cpp
        pci_bios.cpp
diff --git a/src/add-ons/kernel/bus_managers/pci/arch/x86/pci_acpi.cpp 
b/src/add-ons/kernel/bus_managers/pci/arch/x86/pci_acpi.cpp
new file mode 100644
index 0000000..f1fb0fa
--- /dev/null
+++ b/src/add-ons/kernel/bus_managers/pci/arch/x86/pci_acpi.cpp
@@ -0,0 +1,270 @@
+/*
+ * Copyright 2011, Rene Gollent, rene@xxxxxxxxxxx.
+ * Copyright 2008, Dustin Howett, dustin.howett@xxxxxxxxx. All rights reserved.
+ * Copyright 2007, Michael Lotz, mmlr@xxxxxxxx
+ * Copyright 2004-2005, Axel Dörfler, axeld@xxxxxxxxxxxxxxxx.
+ * Distributed under the terms of the MIT License.
+ *
+ * Copyright 2001, Travis Geiselbrecht. All rights reserved.
+ * Distributed under the terms of the NewOS License.
+*/
+
+
+#include "pci_acpi.h"
+
+#include <string.h>
+
+#include <KernelExport.h>
+
+#include <arch/x86/arch_acpi.h>
+
+
+//#define TRACE_ACPI
+#ifdef TRACE_ACPI
+#      define TRACE(x) dprintf x
+#else
+#      define TRACE(x) ;
+#endif
+
+static struct scan_spots_struct acpi_scan_spots[] = {
+       { 0x0, 0x1000, 0x1000 },
+       { 0x9f000, 0x10000, 0x1000 },
+       { 0xe0000, 0x110000, 0x20000 },
+       { 0xfd000, 0xfe000, 0x1000},
+       { 0, 0, 0 }
+};
+
+static acpi_descriptor_header* sAcpiRsdt; // System Description Table
+static acpi_descriptor_header* sAcpiXsdt; // Extended System Description Table
+static int32 sNumEntries = -1;
+
+
+static status_t
+acpi_validate_rsdp(acpi_rsdp* rsdp)
+{
+       const char* data = (const char*)rsdp;
+       unsigned char checksum = 0;
+       for (uint32 i = 0; i < sizeof(acpi_rsdp_legacy); i++)
+               checksum += data[i];
+
+       if ((checksum & 0xff) != 0) {
+               TRACE(("acpi: rsdp failed basic checksum\n"));
+               return B_BAD_DATA;
+       }
+
+       // for ACPI 2.0+ we need to also validate the extended checksum
+       if (rsdp->revision > 0) {
+               for (uint32 i = sizeof(acpi_rsdp_legacy);
+                       i < sizeof(acpi_rsdp_extended); i++) {
+                               checksum += data[i];
+               }
+
+               if ((checksum & 0xff) != 0) {
+                       TRACE(("acpi: rsdp failed extended checksum\n"));
+                       return B_BAD_DATA;
+               }
+       }
+
+       return B_OK;
+}
+
+
+static status_t
+acpi_validate_rsdt(acpi_descriptor_header* rsdt)
+{
+       const char* data = (const char*)rsdt;
+       unsigned char checksum = 0;
+       for (uint32 i = 0; i < rsdt->length; i++)
+               checksum += data[i];
+
+       return checksum == 0 ? B_OK : B_BAD_DATA;
+}
+
+
+static status_t
+acpi_check_rsdt(acpi_rsdp* rsdp)
+{
+       if (acpi_validate_rsdp(rsdp) != B_OK)
+               return B_BAD_DATA;
+
+       bool usingXsdt = false;
+
+       TRACE(("acpi: found rsdp at %p oem id: %.6s, rev %d\n",
+               rsdp, rsdp->oem_id, rsdp->revision));
+       TRACE(("acpi: rsdp points to rsdt at 0x%lx\n", rsdp->rsdt_address));
+
+       uint32 length = 0;
+       acpi_descriptor_header* rsdt = NULL;
+       area_id rsdtArea = -1;
+       if (rsdp->revision > 0) {
+               length = rsdp->xsdt_length;
+               rsdtArea = map_physical_memory("rsdt acpi",
+                       (uint32)rsdp->xsdt_address, rsdp->xsdt_length, 
B_ANY_KERNEL_ADDRESS, 
+                       B_KERNEL_READ_AREA, (void **)&rsdt);
+               if (rsdt != NULL
+                       && strncmp(rsdt->signature, ACPI_XSDT_SIGNATURE, 4) != 
0) {
+                       delete_area(rsdtArea);
+                       rsdt = NULL;
+                       TRACE(("acpi: invalid extended system description 
table\n"));
+               } else
+                       usingXsdt = true;
+       }
+
+       // if we're ACPI v1 or we fail to map the XSDT for some reason,
+       // attempt to use the RSDT instead.
+       if (rsdt == NULL) {
+               // map and validate the root system description table
+               rsdtArea = map_physical_memory("rsdt acpi",
+                       rsdp->rsdt_address, sizeof(acpi_descriptor_header),
+                       B_ANY_KERNEL_ADDRESS, B_KERNEL_READ_AREA, (void 
**)&rsdt);
+               if (rsdt != NULL
+                       && strncmp(rsdt->signature, ACPI_RSDT_SIGNATURE, 4) != 
0) {
+                       delete_area(rsdtArea);
+                       rsdt = NULL;
+                       TRACE(("acpi: invalid root system description 
table\n"));
+                       return B_ERROR;
+               }
+
+               length = rsdt->length;
+               // Map the whole table, not just the header
+               TRACE(("acpi: rsdt length: %lu\n", length));
+               delete_area(rsdtArea);
+               rsdtArea = map_physical_memory("rsdt acpi",
+                       rsdp->rsdt_address, length, B_ANY_KERNEL_ADDRESS, 
+                       B_KERNEL_READ_AREA, (void **)&rsdt);
+       }
+
+       if (rsdt != NULL) {
+               if (acpi_validate_rsdt(rsdt) != B_OK) {
+                       TRACE(("acpi: rsdt failed checksum validation\n"));
+                       delete_area(rsdtArea);
+                       return B_ERROR;
+               } else {
+                       if (usingXsdt)
+                               sAcpiXsdt = rsdt;
+                       else
+                               sAcpiRsdt = rsdt;
+                       TRACE(("acpi: found valid %s at %p\n",
+                               usingXsdt ? ACPI_XSDT_SIGNATURE : 
ACPI_RSDT_SIGNATURE,
+                               rsdt));
+               }
+       } else
+               return B_ERROR;
+
+       return B_OK;
+}
+
+
+template<typename PointerType>
+acpi_descriptor_header*
+acpi_find_table_generic(const char* signature, acpi_descriptor_header* acpiSdt)
+{
+       if (acpiSdt == NULL)
+               return NULL;
+
+       if (sNumEntries == -1) {
+               // if using the xsdt, our entries are 64 bits wide.
+               sNumEntries = (acpiSdt->length
+                       - sizeof(acpi_descriptor_header))
+                               / sizeof(PointerType);
+       }
+
+       if (sNumEntries <= 0) {
+               TRACE(("acpi: root system description table is empty\n"));
+               return NULL;
+       }
+
+       TRACE(("acpi: searching %ld entries for table '%.4s'\n", sNumEntries,
+               signature));
+
+       PointerType* pointer = (PointerType*)((uint8*)acpiSdt
+               + sizeof(acpi_descriptor_header));
+
+       acpi_descriptor_header* header = NULL;
+       area_id headerArea = -1;
+       for (int32 j = 0; j < sNumEntries; j++, pointer++) {
+               headerArea = map_physical_memory("acpi header", 
(uint32)*pointer,
+                               sizeof(acpi_descriptor_header), 
B_ANY_KERNEL_ADDRESS, 
+                       B_KERNEL_READ_AREA, (void **)&header);
+
+               if (header == NULL
+                       || strncmp(header->signature, signature, 4) != 0) {
+                       // not interesting for us
+                       TRACE(("acpi: Looking for '%.4s'. Skipping '%.4s'\n",
+                               signature, header != NULL ? header->signature : 
"null"));
+
+                       if (header != NULL) {
+                               delete_area(headerArea);
+                               header = NULL;
+                       }
+
+                       continue;
+               }
+
+               TRACE(("acpi: Found '%.4s' @ %p\n", signature, pointer));
+               break;
+       }
+
+
+       if (header == NULL)
+               return NULL;
+
+       // Map the whole table, not just the header
+       uint32 length = header->length;
+       delete_area(headerArea);
+
+       headerArea = map_physical_memory("acpi table",
+               (uint32)*pointer, length, B_ANY_KERNEL_ADDRESS, 
+                       B_KERNEL_READ_AREA, (void **)&header);
+       return header;
+}
+
+
+void*
+acpi_find_table(const char* signature)
+{
+       if (sAcpiRsdt != NULL)
+               return acpi_find_table_generic<uint32>(signature, sAcpiRsdt);
+       else if (sAcpiXsdt != NULL)
+               return acpi_find_table_generic<uint64>(signature, sAcpiXsdt);
+
+       return NULL;
+}
+
+
+void
+acpi_init()
+{
+       // Try to find the ACPI RSDP.
+       for (int32 i = 0; acpi_scan_spots[i].length > 0; i++) {
+               acpi_rsdp* rsdp = NULL;
+
+               TRACE(("acpi_init: entry base 0x%lx, limit 0x%lx\n",
+                       acpi_scan_spots[i].start, acpi_scan_spots[i].stop));
+
+               char* start = NULL;
+               area_id rsdpArea = map_physical_memory("acpi rsdp",
+                       acpi_scan_spots[i].start, acpi_scan_spots[i].length,
+                       B_ANY_KERNEL_ADDRESS, B_KERNEL_READ_AREA, (void 
**)&start);
+               if (rsdpArea < B_OK) {
+                       TRACE(("acpi_init: couldn't map %s\n", 
strerror(rsdpArea)));
+                       break;
+               }
+               for (char *pointer = start;
+                       (addr_t)pointer < (addr_t)start + 
acpi_scan_spots[i].length;
+                       pointer += 16) {
+                       if (strncmp(pointer, ACPI_RSDP_SIGNATURE, 8) == 0) {
+                               TRACE(("acpi_init: found ACPI RSDP signature at 
%p\n",
+                                       pointer));
+                               rsdp = (acpi_rsdp*)pointer;
+                       }
+               }
+               
+               if (rsdp != NULL && acpi_check_rsdt(rsdp) == B_OK) {
+                       delete_area(rsdpArea);
+                       break;
+               }
+               delete_area(rsdpArea);
+       }
+
+}
diff --git a/src/add-ons/kernel/bus_managers/pci/arch/x86/pci_acpi.h 
b/src/add-ons/kernel/bus_managers/pci/arch/x86/pci_acpi.h
new file mode 100644
index 0000000..8be3856
--- /dev/null
+++ b/src/add-ons/kernel/bus_managers/pci/arch/x86/pci_acpi.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2005, Axel Dörfler, axeld@xxxxxxxxxxxxxxxx. All rights reserved.
+ * Distributed under the terms of the MIT License.
+ */
+#ifndef PCI_ACPI_H
+#define PCI_ACPI_H
+
+#include <SupportDefs.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct scan_spots_struct {
+       uint32 start;
+       uint32 stop;
+       uint32 length;
+};
+
+void *acpi_find_table(const char *signature);
+void acpi_init(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PCI_ACPI_H */
diff --git a/src/add-ons/kernel/bus_managers/pci/arch/x86/pci_bios.cpp 
b/src/add-ons/kernel/bus_managers/pci/arch/x86/pci_bios.cpp
index 1852f70..ef34b2b 100644
--- a/src/add-ons/kernel/bus_managers/pci/arch/x86/pci_bios.cpp
+++ b/src/add-ons/kernel/bus_managers/pci/arch/x86/pci_bios.cpp
@@ -17,7 +17,7 @@ pci_bios_init(void)
 
 status_t
 pci_bios_read_config(void *cookie, uint8 bus, uint8 device, uint8 function,
-       uint8 offset, uint8 size, uint32 *value)
+       uint16 offset, uint8 size, uint32 *value)
 {
        return B_ERROR;
 }
@@ -25,7 +25,7 @@ pci_bios_read_config(void *cookie, uint8 bus, uint8 device, 
uint8 function,
 
 status_t
 pci_bios_write_config(void *cookie, uint8 bus, uint8 device, uint8 function,
-       uint8 offset, uint8 size, uint32 value)
+       uint16 offset, uint8 size, uint32 value)
 {
        return B_ERROR;
 }
diff --git a/src/add-ons/kernel/bus_managers/pci/arch/x86/pci_bios.h 
b/src/add-ons/kernel/bus_managers/pci/arch/x86/pci_bios.h
index 89807f1..64d05b6 100644
--- a/src/add-ons/kernel/bus_managers/pci/arch/x86/pci_bios.h
+++ b/src/add-ons/kernel/bus_managers/pci/arch/x86/pci_bios.h
@@ -7,11 +7,11 @@ status_t pci_bios_init(void);
 
 status_t pci_bios_read_config(void *cookie, 
                                                          uint8 bus, uint8 
device, uint8 function,
-                                                         uint8 offset, uint8 
size, uint32 *value);
+                                                         uint16 offset, uint8 
size, uint32 *value);
 
 status_t pci_bios_write_config(void *cookie, 
                                                           uint8 bus, uint8 
device, uint8 function,
-                                                          uint8 offset, uint8 
size, uint32 value);
+                                                          uint16 offset, uint8 
size, uint32 value);
 
 status_t pci_bios_get_max_bus_devices(void *cookie, int32 *count);
 
diff --git a/src/add-ons/kernel/bus_managers/pci/arch/x86/pci_controller.cpp 
b/src/add-ons/kernel/bus_managers/pci/arch/x86/pci_controller.cpp
index 4a0fd7f..e702ca7 100644
--- a/src/add-ons/kernel/bus_managers/pci/arch/x86/pci_controller.cpp
+++ b/src/add-ons/kernel/bus_managers/pci/arch/x86/pci_controller.cpp
@@ -3,14 +3,20 @@
  * Distributed under the terms of the MIT License.
  */
 
+
 #include <KernelExport.h>
 #include <driver_settings.h>
 #include <string.h>
-#include "pci_irq.h"
+
+#include "pci_acpi.h"
+#include "arch_cpu.h"
 #include "pci_bios.h"
-#include "pci_private.h"
 #include "pci_controller.h"
-#include "arch_cpu.h"
+#include "pci_irq.h"
+#include "pci_private.h"
+
+#include "acpi.h"
+
 
 #define PCI_MECH1_REQ_PORT                             0xCF8
 #define PCI_MECH1_DATA_PORT                    0xCFC
@@ -38,11 +44,14 @@ spinlock sConfigLock = B_SPINLOCK_INITIALIZER;
 
 static status_t
 pci_mech1_read_config(void *cookie, uint8 bus, uint8 device, uint8 function,
-                                         uint8 offset, uint8 size, uint32 
*value)
+                                         uint16 offset, uint8 size, uint32 
*value)
 {
        cpu_status cpu;
        status_t status = B_OK;
 
+       if (offset > 0xff)
+               return B_BAD_VALUE;
+
        PCI_LOCK_CONFIG(cpu);
        out32(PCI_MECH1_REQ_DATA(bus, device, function, offset), 
PCI_MECH1_REQ_PORT);
        switch (size) {
@@ -67,11 +76,14 @@ pci_mech1_read_config(void *cookie, uint8 bus, uint8 
device, uint8 function,
 
 static status_t
 pci_mech1_write_config(void *cookie, uint8 bus, uint8 device, uint8 function,
-                                          uint8 offset, uint8 size, uint32 
value)
+                                          uint16 offset, uint8 size, uint32 
value)
 {
        cpu_status cpu;
        status_t status = B_OK;
 
+       if (offset > 0xff)
+               return B_BAD_VALUE;
+
        PCI_LOCK_CONFIG(cpu);
        out32(PCI_MECH1_REQ_DATA(bus, device, function, offset), 
PCI_MECH1_REQ_PORT);
        switch (size) {
@@ -104,11 +116,14 @@ pci_mech1_get_max_bus_devices(void *cookie, int32 *count)
 
 static status_t
 pci_mech2_read_config(void *cookie, uint8 bus, uint8 device, uint8 function,
-                                         uint8 offset, uint8 size, uint32 
*value)
+                                         uint16 offset, uint8 size, uint32 
*value)
 {
        cpu_status cpu;
        status_t status = B_OK;
 
+       if (offset > 0xff)
+               return B_BAD_VALUE;
+
        PCI_LOCK_CONFIG(cpu);
        out8((uint8)(0xf0 | (function << 1)), PCI_MECH2_ENABLE_PORT);
        out8(bus, PCI_MECH2_FORWARD_PORT);
@@ -135,11 +150,14 @@ pci_mech2_read_config(void *cookie, uint8 bus, uint8 
device, uint8 function,
 
 static status_t
 pci_mech2_write_config(void *cookie, uint8 bus, uint8 device, uint8 function,
-                                          uint8 offset, uint8 size, uint32 
value)
+                                          uint16 offset, uint8 size, uint32 
value)
 {
        cpu_status cpu;
        status_t status = B_OK;
 
+       if (offset > 0xff)
+               return B_BAD_VALUE;
+
        PCI_LOCK_CONFIG(cpu);
        out8((uint8)(0xf0 | (function << 1)), PCI_MECH2_ENABLE_PORT);
        out8(bus, PCI_MECH2_FORWARD_PORT);
@@ -172,6 +190,71 @@ pci_mech2_get_max_bus_devices(void *cookie, int32 *count)
 }
 
 
+addr_t sPCIeBase = 0;
+#define PCIE_VADDR(base, bus, slot, func, reg)  ((base) + \
+       ((((bus) & 0xff) << 20) | (((slot) & 0x1f) << 15) |   \
+    (((func) & 0x7) << 12) | ((reg) & 0xfff)))
+
+static status_t
+pci_mechpcie_read_config(void *cookie, uint8 bus, uint8 device, uint8 function,
+                                         uint16 offset, uint8 size, uint32 
*value)
+{
+       status_t status = B_OK;
+
+       addr_t address = PCIE_VADDR(sPCIeBase, bus, device, function, offset);
+
+       switch (size) {
+               case 1:
+                       *value = *(uint8*)address;
+                       break;
+               case 2:
+                       *value = *(uint16*)address;
+                       break;
+               case 4:
+                       *value = *(uint32*)address;
+                       break;
+               default:
+                       status = B_ERROR;
+                       break;
+       }
+       return status;
+}
+
+
+static status_t
+pci_mechpcie_write_config(void *cookie, uint8 bus, uint8 device, uint8 
function,
+                                          uint16 offset, uint8 size, uint32 
value)
+{
+       status_t status = B_OK;
+
+       addr_t address = PCIE_VADDR(sPCIeBase, bus, device, function, offset);
+       switch (size) {
+               case 1:
+                       *(uint8*)address = value;
+                       break;
+               case 2:
+                       *(uint16*)address = value;
+                       break;
+               case 4:
+                       *(uint32*)address = value;
+                       break;
+               default:
+                       status = B_ERROR;
+                       break;
+       }
+
+       return status;
+}
+
+
+static status_t
+pci_mechpcie_get_max_bus_devices(void *cookie, int32 *count)
+{
+       *count = 32;
+       return B_OK;
+}
+
+
 void *
 pci_ram_address(const void *physical_address_in_system_memory)
 {
@@ -197,6 +280,15 @@ pci_controller pci_controller_x86_mech2 =
        pci_x86_irq_write,
 };
 
+pci_controller pci_controller_x86_mechpcie =
+{
+       pci_mechpcie_read_config,
+       pci_mechpcie_write_config,
+       pci_mechpcie_get_max_bus_devices,
+       pci_x86_irq_read,
+       pci_x86_irq_write,
+};
+
 pci_controller pci_controller_x86_bios =
 {
        pci_bios_read_config,
@@ -212,6 +304,7 @@ pci_controller_init(void)
 {
        bool search_mech1 = true;
        bool search_mech2 = true;
+       bool search_mechpcie = true;
        bool search_bios = true;
        void *config = NULL;
        status_t status;
@@ -225,11 +318,13 @@ pci_controller_init(void)
                const char *mech = get_driver_parameter(config, "mechanism",
                        NULL, NULL);
                if (mech) {
-                       search_mech1 = search_mech2 = search_bios = false;
+                       search_mech1 = search_mech2 = search_mechpcie = 
search_bios = false;
                        if (strcmp(mech, "1") == 0)
                                search_mech1 = true;
                        else if (strcmp(mech, "2") == 0)
                                search_mech2 = true;
+                       else if (strcmp(mech, "pcie") == 0)
+                               search_mechpcie = true;
                        else if (strcmp(mech, "bios") == 0)
                                search_bios = true;
                        else
@@ -240,10 +335,39 @@ pci_controller_init(void)
 
        // TODO: check safemode "don't call the BIOS" setting and unset 
search_bios!
 
-       // PCI configuration mechanism 1 is the preferred one.
+       // PCI configuration mechanism PCIe is the preferred one.
+       // If it doesn't work, try mechanism 1.
        // If it doesn't work, try mechanism 2.
        // Finally, try to fallback to PCI BIOS
 
+       if (search_mechpcie) {
+               acpi_init();
+               struct acpi_table_mcfg* mcfg =
+                       (struct acpi_table_mcfg*)acpi_find_table("MCFG");
+               if (mcfg != NULL) {
+                       struct acpi_mcfg_allocation* end = (struct 
acpi_mcfg_allocation*)
+                               ((char*)mcfg + mcfg->Header.Length);
+                       struct acpi_mcfg_allocation* alloc = (struct 
acpi_mcfg_allocation*)
+                               (mcfg + 1);
+                       for (; alloc < end; alloc++) {
+                               dprintf("PCI: mechanism addr: %" B_PRIx64 ", 
seg: %x, start: "
+                                       "%x, end: %x\n", alloc->Address, 
alloc->PciSegment,
+                                       alloc->StartBusNumber, 
alloc->EndBusNumber);
+                               if (alloc->PciSegment == 0) {
+                                       area_id mcfgArea = 
map_physical_memory("acpi mcfg",
+                                               alloc->Address, 
(alloc->EndBusNumber + 1) << 20,
+                                               B_ANY_KERNEL_ADDRESS, 
B_KERNEL_READ_AREA
+                                                       | B_KERNEL_WRITE_AREA, 
(void **)&sPCIeBase);
+                                       if (mcfgArea < 0)
+                                               break;
+                                       dprintf("PCI: mechanism pcie controller 
found\n");
+                                       return 
pci_controller_add(&pci_controller_x86_mechpcie,
+                                               NULL);
+                               }
+                       }
+               }
+       }
+
        if (search_mech1) {
                // check for mechanism 1
                out32(0x80000000, PCI_MECH1_REQ_PORT);
diff --git a/src/add-ons/kernel/bus_managers/pci/pci_controller.h 
b/src/add-ons/kernel/bus_managers/pci/pci_controller.h
index 0c39c35..3a37e80 100644
--- a/src/add-ons/kernel/bus_managers/pci/pci_controller.h
+++ b/src/add-ons/kernel/bus_managers/pci/pci_controller.h
@@ -13,12 +13,12 @@ typedef struct pci_controller
        // read PCI config space
        status_t        (*read_pci_config)(void *cookie, 
                                uint8 bus, uint8 device, uint8 function,
-                               uint8 offset, uint8 size, uint32 *value);
+                               uint16 offset, uint8 size, uint32 *value);
 
        // write PCI config space
        status_t        (*write_pci_config)(void *cookie, 
                                uint8 bus, uint8 device, uint8 function,
-                               uint8 offset, uint8 size, uint32 value);
+                               uint16 offset, uint8 size, uint32 value);
                                
        status_t        (*get_max_bus_devices)(void *cookie, int32 *count);
        

############################################################################

Commit:      e1c44764ef30ce2fd53219561bd3c2d582334882
URL:         http://cgit.haiku-os.org/haiku/commit/?id=e1c4476
Author:      Jérôme Duval <jerome.duval@xxxxxxxxx>
Date:        Sat Jun 22 17:35:43 2013 UTC

pci: switched PCI::[Read|Write]Config to type uint16 for the offset.

----------------------------------------------------------------------------

diff --git a/src/add-ons/kernel/bus_managers/pci/pci.cpp 
b/src/add-ons/kernel/bus_managers/pci/pci.cpp
index 67f0585..fc3f5dc 100644
--- a/src/add-ons/kernel/bus_managers/pci/pci.cpp
+++ b/src/add-ons/kernel/bus_managers/pci/pci.cpp
@@ -1467,7 +1467,7 @@ PCI::_RefreshDeviceInfo(PCIBus *bus)
 
 status_t
 PCI::ReadConfig(uint8 domain, uint8 bus, uint8 device, uint8 function,
-       uint8 offset, uint8 size, uint32 *value)
+       uint16 offset, uint8 size, uint32 *value)
 {
        domain_data *info = _GetDomainData(domain);
        if (!info)
@@ -1490,7 +1490,7 @@ PCI::ReadConfig(uint8 domain, uint8 bus, uint8 device, 
uint8 function,
 
 uint32
 PCI::ReadConfig(uint8 domain, uint8 bus, uint8 device, uint8 function,
-       uint8 offset, uint8 size)
+       uint16 offset, uint8 size)
 {
        uint32 value;
        if (ReadConfig(domain, bus, device, function, offset, size, &value)
@@ -1502,7 +1502,7 @@ PCI::ReadConfig(uint8 domain, uint8 bus, uint8 device, 
uint8 function,
 
 
 uint32
-PCI::ReadConfig(PCIDev *device, uint8 offset, uint8 size)
+PCI::ReadConfig(PCIDev *device, uint16 offset, uint8 size)
 {
        uint32 value;
        if (ReadConfig(device->domain, device->bus, device->device,
@@ -1515,7 +1515,7 @@ PCI::ReadConfig(PCIDev *device, uint8 offset, uint8 size)
 
 status_t
 PCI::WriteConfig(uint8 domain, uint8 bus, uint8 device, uint8 function,
-       uint8 offset, uint8 size, uint32 value)
+       uint16 offset, uint8 size, uint32 value)
 {
        domain_data *info = _GetDomainData(domain);
        if (!info)
@@ -1537,7 +1537,7 @@ PCI::WriteConfig(uint8 domain, uint8 bus, uint8 device, 
uint8 function,
 
 
 status_t
-PCI::WriteConfig(PCIDev *device, uint8 offset, uint8 size, uint32 value)
+PCI::WriteConfig(PCIDev *device, uint16 offset, uint8 size, uint32 value)
 {
        return WriteConfig(device->domain, device->bus, device->device,
                device->function, offset, size, value);
diff --git a/src/add-ons/kernel/bus_managers/pci/pci.h 
b/src/add-ons/kernel/bus_managers/pci/pci.h
index c86676f..bb7f9dc 100644
--- a/src/add-ons/kernel/bus_managers/pci/pci.h
+++ b/src/add-ons/kernel/bus_managers/pci/pci.h
@@ -77,17 +77,17 @@ public:
                        status_t                GetNthInfo(long index, pci_info 
*outInfo);
 
                        status_t                ReadConfig(uint8 domain, uint8 
bus, uint8 device,
-                                                               uint8 function, 
uint8 offset, uint8 size,
+                                                               uint8 function, 
uint16 offset, uint8 size,
                                                                uint32 *value);
                        uint32                  ReadConfig(uint8 domain, uint8 
bus, uint8 device,
-                                                               uint8 function, 
uint8 offset, uint8 size);
-                       uint32                  ReadConfig(PCIDev *device, 
uint8 offset,
+                                                               uint8 function, 
uint16 offset, uint8 size);
+                       uint32                  ReadConfig(PCIDev *device, 
uint16 offset,
                                                                uint8 size);
 
                        status_t                WriteConfig(uint8 domain, uint8 
bus, uint8 device,
-                                                               uint8 function, 
uint8 offset, uint8 size,
+                                                               uint8 function, 
uint16 offset, uint8 size,
                                                                uint32 value);
-                       status_t                WriteConfig(PCIDev *device, 
uint8 offset,
+                       status_t                WriteConfig(PCIDev *device, 
uint16 offset,
                                                                uint8 size, 
uint32 value);
 
                        status_t                FindCapability(uint8 domain, 
uint8 bus,

############################################################################

Revision:    hrev45777
Commit:      26a4510e591b2d12b5191918ca4e92a5f94b2bd5
URL:         http://cgit.haiku-os.org/haiku/commit/?id=26a4510
Author:      Jérôme Duval <jerome.duval@xxxxxxxxx>
Date:        Sat Jun 22 17:43:00 2013 UTC

pci: added pci_find_extended_capability().

* added PCI Extended Capabilities definitions.
* pci_find_capability() parameter offset is now optional.

----------------------------------------------------------------------------

diff --git a/headers/os/drivers/PCI.h b/headers/os/drivers/PCI.h
index ef0b506..bff025f 100644
--- a/headers/os/drivers/PCI.h
+++ b/headers/os/drivers/PCI.h
@@ -196,6 +196,7 @@ struct pci_module_info {
 #define PCI_header_type                        0x0e            /* (1 byte) 
header type */
 #define PCI_bist                               0x0f            /* (1 byte) 
built-in self-test */
 
+#define PCI_extended_capability 0x100          /* (4 bytes) extended 
capability */
 
 
 /* ---
@@ -690,6 +691,41 @@ struct pci_module_info {
 #define PCI_cap_id_sata                0x12    /* Serial ATA Capability */
 #define PCI_cap_id_pciaf       0x13    /* PCI Advanced Features */
 
+/** PCI Extended Capabilities */
+#define PCI_extcap_id(x)               (x & 0x0000ffff)
+#define PCI_extcap_version(x)  ((x & 0x000f0000) >> 16)
+#define PCI_extcap_next_ptr(x) ((x & 0xfff00000) >> 20)
+
+#define PCI_extcap_id_aer                      0x0001  /* Advanced Error 
Reporting */
+#define PCI_extcap_id_vc                       0x0002  /* Virtual Channel */
+#define PCI_extcap_id_serial           0x0003  /* Serial Number */
+#define PCI_extcap_id_power_budget     0x0004  /* Power Budgeting */
+#define PCI_extcap_id_rcl_decl         0x0005  /* Root Complex Link 
Declaration */
+#define PCI_extcap_id_rcil_ctl         0x0006  /* Root Complex Internal Link 
Control */
+#define PCI_extcap_id_rcec_assoc       0x0007  /* Root Complex Event Collector 
Association */
+#define PCI_extcap_id_mfvc                     0x0008  /* MultiFunction 
Virtual Channel */
+#define PCI_extcap_id_vc2                      0x0009  /* Virtual Channel 2 */
+#define PCI_extcap_id_rcrb_header      0x000a  /* RCRB Header */
+#define PCI_extcap_id_vendor           0x000b  /* Vendor Unique */
+#define PCI_extcap_id_acs                      0x000d  /* Access Control 
Services */
+#define PCI_extcap_id_ari                      0x000e  /* Alternative Routing 
Id Interpretation */
+#define PCI_extcap_id_ats                      0x000f  /* Address Translation 
Services */
+#define PCI_extcap_id_srio_virtual     0x0010  /* Single Root I/O 
Virtualization */
+#define PCI_extcap_id_mrio_virtual     0x0011  /* Multiple Root I/O Virtual */
+#define PCI_extcap_id_multicast                0x0012  /* Multicast */
+#define PCI_extcap_id_page_request     0x0013  /* Page Request */
+#define PCI_extcap_id_amd                      0x0014  /* AMD Reserved */
+#define PCI_extcap_id_resizable_bar    0x0015  /* Resizable Bar */
+#define PCI_extcap_id_dyn_power_alloc  0x0016  /* Dynamic Power Allocation */
+#define PCI_extcap_id_tph_requester    0x0017  /* TPH Requester */
+#define PCI_extcap_id_latency_tolerance        0x0018  /* Latency Tolerance 
Reporting */
+#define PCI_extcap_id_2ndpcie          0x0019  /* Secondary PCIe */
+#define PCI_extcap_id_pmux                     0x001a  /* Protocol 
Multiplexing */
+#define PCI_extcap_id_pasid                    0x001b  /* Process Address 
Space Id */
+#define PCI_extcap_id_ln_requester     0x001c  /* LN Requester */
+#define PCI_extcap_id_dpc                      0x001d  /* Downstream Porto 
Containment */
+#define PCI_extcap_id_l1pm                     0x001e  /* L1 Power Management 
Substates */
+
 /** Power Management Control Status Register settings */
 #define PCI_pm_mask             0x03
 #define PCI_pm_ctrl             0x02
diff --git a/src/add-ons/kernel/bus_managers/pci/pci.cpp 
b/src/add-ons/kernel/bus_managers/pci/pci.cpp
index fc3f5dc..1b8a1c0 100644
--- a/src/add-ons/kernel/bus_managers/pci/pci.cpp
+++ b/src/add-ons/kernel/bus_managers/pci/pci.cpp
@@ -75,8 +75,8 @@ pci_write_config(uint8 virtualBus, uint8 device, uint8 
function, uint8 offset,
 
 
 status_t
-pci_find_capability(uchar virtualBus, uchar device, uchar function,
-       uchar capID, uchar *offset)
+pci_find_capability(uint8 virtualBus, uint8 device, uint8 function,
+       uint8 capID, uint8 *offset)
 {
        uint8 bus;
        uint8 domain;
@@ -88,6 +88,20 @@ pci_find_capability(uchar virtualBus, uchar device, uchar 
function,
 
 
 status_t
+pci_find_extended_capability(uint8 virtualBus, uint8 device, uint8 function,
+       uint16 capID, uint16 *offset)
+{
+       uint8 bus;
+       uint8 domain;
+       if (gPCI->ResolveVirtualBus(virtualBus, &domain, &bus) != B_OK)
+               return B_ERROR;
+
+       return gPCI->FindExtendedCapability(domain, bus, device, function, 
capID,
+               offset);
+}
+
+
+status_t
 pci_reserve_device(uchar virtualBus, uchar device, uchar function,
        const char *driverName, void *nodeCookie)
 {
@@ -1548,14 +1562,10 @@ status_t
 PCI::FindCapability(uint8 domain, uint8 bus, uint8 device, uint8 function,
        uint8 capID, uint8 *offset)
 {
-       if (offset == NULL) {
-               TRACE_CAP("PCI: FindCapability() ERROR %u:%u:%u capability 
%#02x offset NULL pointer\n", bus, device, function, capID);
-               return B_BAD_VALUE;
-       }
-
        uint16 status = ReadConfig(domain, bus, device, function, PCI_status, 
2);
        if (!(status & PCI_status_capabilities)) {
-               TRACE_CAP("PCI: find_pci_capability ERROR %u:%u:%u capability 
%#02x not supported\n", bus, device, function, capID);
+               FLOW("PCI: find_pci_capability ERROR %u:%u:%u capability %#02x "
+                       "not supported\n", bus, device, function, capID);
                return B_ERROR;
        }
 
@@ -1566,27 +1576,29 @@ PCI::FindCapability(uint8 domain, uint8 bus, uint8 
device, uint8 function,
        switch (headerType & PCI_header_type_mask) {
                case PCI_header_type_generic:
                case PCI_header_type_PCI_to_PCI_bridge:
-                       capPointer = ReadConfig(domain, bus, device, function,
-                               PCI_capabilities_ptr, 1);
+                       capPointer = PCI_capabilities_ptr;
                        break;
                case PCI_header_type_cardbus:
-                       capPointer = ReadConfig(domain, bus, device, function,
-                               PCI_capabilities_ptr_2, 1);
+                       capPointer = PCI_capabilities_ptr_2;
                        break;
                default:
-                       TRACE_CAP("PCI: find_pci_capability ERROR %u:%u:%u 
capability %#02x unknown header type\n", bus, device, function, capID);
+                       TRACE_CAP("PCI: find_pci_capability ERROR %u:%u:%u 
capability "
+                               "%#02x unknown header type\n", bus, device, 
function, capID);
                        return B_ERROR;
        }
 
+       capPointer = ReadConfig(domain, bus, device, function, capPointer, 1);
        capPointer &= ~3;
        if (capPointer == 0) {
-               TRACE_CAP("PCI: find_pci_capability ERROR %u:%u:%u capability 
%#02x empty list\n", bus, device, function, capID);
+               TRACE_CAP("PCI: find_pci_capability ERROR %u:%u:%u capability 
%#02x "
+                       "empty list\n", bus, device, function, capID);
                return B_NAME_NOT_FOUND;
        }
 
        for (int i = 0; i < 48; i++) {
                if (ReadConfig(domain, bus, device, function, capPointer, 1) == 
capID) {
-                       *offset = capPointer;
+                       if (offset != NULL)                     
+                               *offset = capPointer;
                        return B_OK;
                }
 
@@ -1611,6 +1623,51 @@ PCI::FindCapability(PCIDev *device, uint8 capID, uint8 
*offset)
 }
 
 
+status_t
+PCI::FindExtendedCapability(uint8 domain, uint8 bus, uint8 device,
+       uint8 function, uint16 capID, uint16 *offset)
+{
+       if (FindCapability(domain, bus, device, function, PCI_cap_id_pcie)
+               != B_OK) {
+               FLOW("PCI:FindExtendedCapability ERROR %u:%u:%u capability 
%#02x "
+                       "not supported\n", bus, device, function, capID);
+               return B_ERROR;
+       }
+       uint16 capPointer = PCI_extended_capability;
+       uint32 capability = ReadConfig(domain, bus, device, function,
+               capPointer, 4);
+
+       if (capability == 0 || capability == 0xffffffff)
+                       return B_NAME_NOT_FOUND;
+
+       for (int i = 0; i < 48; i++) {
+               if (PCI_extcap_id(capability) == capID) {
+                       if (offset != NULL)
+                               *offset = capPointer;
+                       return B_OK;
+               }
+
+               capPointer = PCI_extcap_next_ptr(capability) & ~3;
+               if (capPointer < PCI_extended_capability)
+                       return B_NAME_NOT_FOUND;
+               capability = ReadConfig(domain, bus, device, function,
+                       capPointer, 4);
+       }
+
+       TRACE_CAP("PCI:FindExtendedCapability ERROR %u:%u:%u capability %#04x "
+               "circular list\n", bus, device, function, capID);
+       return B_ERROR;
+}
+
+
+status_t
+PCI::FindExtendedCapability(PCIDev *device, uint16 capID, uint16 *offset)
+{
+       return FindExtendedCapability(device->domain, device->bus, 
device->device,
+               device->function, capID, offset);
+}
+
+
 PCIDev *
 PCI::FindDevice(uint8 domain, uint8 bus, uint8 device, uint8 function)
 {
diff --git a/src/add-ons/kernel/bus_managers/pci/pci.h 
b/src/add-ons/kernel/bus_managers/pci/pci.h
index bb7f9dc..5ec5da5 100644
--- a/src/add-ons/kernel/bus_managers/pci/pci.h
+++ b/src/add-ons/kernel/bus_managers/pci/pci.h
@@ -92,9 +92,14 @@ public:
 
                        status_t                FindCapability(uint8 domain, 
uint8 bus,
                                                                uint8 device, 
uint8 function, uint8 capID,
-                                                               uint8 *offset);
+                                                               uint8 *offset = 
NULL);
                        status_t                FindCapability(PCIDev *device, 
uint8 capID,
-                                                               uint8 *offset);
+                                                               uint8 *offset = 
NULL);
+                       status_t                FindExtendedCapability(uint8 
domain, uint8 bus,
+                                                               uint8 device, 
uint8 function, uint16 capID,
+                                                               uint16 *offset 
= NULL);
+                       status_t                FindExtendedCapability(PCIDev 
*device,
+                                                               uint16 capID, 
uint16 *offset = NULL);
 
                        status_t                ResolveVirtualBus(uint8 
virtualBus, uint8 *domain,
                                                                uint8 *bus);
diff --git a/src/add-ons/kernel/bus_managers/pci/pci_private.h 
b/src/add-ons/kernel/bus_managers/pci/pci_private.h
index 973dc41..a58220e 100644
--- a/src/add-ons/kernel/bus_managers/pci/pci_private.h
+++ b/src/add-ons/kernel/bus_managers/pci/pci_private.h
@@ -46,7 +46,10 @@ extern "C" {
 
 void *         pci_ram_address(const void *physical_address_in_system_memory);
 
-status_t       pci_find_capability(uchar bus, uchar device, uchar function, 
uchar cap_id, uchar *offset);
+status_t       pci_find_capability(uint8 bus, uint8 device, uint8 function,
+       uint8 cap_id, uint8 *offset = NULL);
+status_t       pci_find_extended_capability(uint8 bus, uint8 device, uint8 
function, 
+       uint16 cap_id, uint16 *offset = NULL);
 
 status_t       pci_reserve_device(uchar virtualBus, uchar device, uchar 
function,
                        const char *driverName, void *nodeCookie);


Other related posts: