From 65621982c96e3b6f3fddb26ab2776fa75ce0535b Mon Sep 17 00:00:00 2001 From: Marcus Overhagen Date: Sat, 10 Nov 2007 15:51:40 +0000 Subject: [PATCH] New PCI quirk/fixup support. The Jmicron AHCI controller has a mode that combines IDE and AHCI functionality into a single PCI device at function 0. This happens when the controller is set in the BIOS to "basic" or "IDE" mode (but not in "RAID" or "AHCI" mode). To avoid needing two drivers to handle a single PCI device, we switch to the multifunction (split device) AHCI mode. This will set PCI device at function 0 to AHCI, and PCI device at function 1 to IDE controller. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@22868 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/add-ons/kernel/bus_managers/pci/Jamfile | 1 + src/add-ons/kernel/bus_managers/pci/pci.cpp | 11 ++- .../kernel/bus_managers/pci/pci_fixup.cpp | 70 +++++++++++++++++++ .../kernel/bus_managers/pci/pci_fixup.h | 14 ++++ 4 files changed, 90 insertions(+), 6 deletions(-) create mode 100644 src/add-ons/kernel/bus_managers/pci/pci_fixup.cpp create mode 100644 src/add-ons/kernel/bus_managers/pci/pci_fixup.h diff --git a/src/add-ons/kernel/bus_managers/pci/Jamfile b/src/add-ons/kernel/bus_managers/pci/Jamfile index 61ecde0063..971d7235fd 100644 --- a/src/add-ons/kernel/bus_managers/pci/Jamfile +++ b/src/add-ons/kernel/bus_managers/pci/Jamfile @@ -5,6 +5,7 @@ UsePrivateHeaders [ FDirName kernel util ] ; KernelAddon pci : pci.cpp + pci_fixup.cpp pci_info.cpp pci_module.c pci_device.c diff --git a/src/add-ons/kernel/bus_managers/pci/pci.cpp b/src/add-ons/kernel/bus_managers/pci/pci.cpp index 7a3b467860..6f5ccc9ba4 100644 --- a/src/add-ons/kernel/bus_managers/pci/pci.cpp +++ b/src/add-ons/kernel/bus_managers/pci/pci.cpp @@ -13,6 +13,7 @@ #include #include "util/kernel_cpp.h" +#include "pci_fixup.h" #include "pci_priv.h" #include "pci.h" @@ -328,12 +329,8 @@ PCI::InitBus() ppnext = &bus->next; } - bool bus_enumeration = true; - - if (bus_enumeration) { - for (int i = 0; i < fDomainCount; i++) { - EnumerateBus(i, 0); - } + for (int i = 0; i < fDomainCount; i++) { + EnumerateBus(i, 0); } if (fRootBus) { @@ -511,6 +508,8 @@ PCI::EnumerateBus(int domain, uint8 bus, uint8 *subordinate_bus) if (device_id == 0xffff) continue; + pci_fixup_device(this, domain, bus, dev, func); + uint8 base_class = ReadPciConfig(domain, bus, dev, func, PCI_class_base, 1); uint8 sub_class = ReadPciConfig(domain, bus, dev, func, PCI_class_sub, 1); if (base_class != PCI_bridge || sub_class != PCI_pci) diff --git a/src/add-ons/kernel/bus_managers/pci/pci_fixup.cpp b/src/add-ons/kernel/bus_managers/pci/pci_fixup.cpp new file mode 100644 index 0000000000..a943174286 --- /dev/null +++ b/src/add-ons/kernel/bus_managers/pci/pci_fixup.cpp @@ -0,0 +1,70 @@ +/* + * Copyright 2007, Marcus Overhagen. All rights reserved. + * + * Distributed under the terms of the MIT License. + */ + +#include "pci.h" +#include "pci_fixup.h" + +#include + +/* The Jmicron AHCI controller has a mode that combines IDE and AHCI functionality + * into a single PCI device at function 0. This happens when the controller is set + * in the BIOS to "basic" or "IDE" mode (but not in "RAID" or "AHCI" mode). + * To avoid needing two drivers to handle a single PCI device, we switch to the + * multifunction (split device) AHCI mode. This will set PCI device at function 0 + * to AHCI, and PCI device at function 1 to IDE controller. + */ +static void +jmicron_fixup_ahci(PCI *pci, int domain, uint8 bus, uint8 device, uint8 function, uint16 deviceId) +{ + if (deviceId != 0x2360 && deviceId != 0x2361 && deviceId != 0x2362 && deviceId != 0x2363 && deviceId != 0x2366) + return; + + dprintf("jmicron_fixup_ahci: domain %u, bus %u, device %u, function %u, deviceId 0x%04x\n", + domain, bus, device, function, deviceId); + + if (function == 0) { + dprintf("0x40: 0x%08lx\n", pci->ReadPciConfig(domain, bus, device, function, 0x40, 4)); + dprintf("0xdc: 0x%08lx\n", pci->ReadPciConfig(domain, bus, device, function, 0xdc, 4)); + uint32 val = pci->ReadPciConfig(domain, bus, device, function, 0xdc, 4); + if (!(val & (1 << 30))) { + dprintf("jmicron_fixup_ahci: enabling split device mode\n"); + val &= ~(1 << 24); + val |= (1 << 25) | (1 << 30); + pci->WritePciConfig(domain, bus, device, function, 0xdc, 4, val); + val = pci->ReadPciConfig(domain, bus, device, function, 0x40, 4); + val &= ~(1 << 16); + val |= (1 << 1) | (1 << 17) | (1 << 22); + pci->WritePciConfig(domain, bus, device, function, 0x40, 4, val); + } + dprintf("0x40: 0x%08lx\n", pci->ReadPciConfig(domain, bus, device, function, 0x40, 4)); + dprintf("0xdc: 0x%08lx\n", pci->ReadPciConfig(domain, bus, device, function, 0xdc, 4)); + } +} + + +static void +intel_fixup_ahci(PCI *pci, int domain, uint8 bus, uint8 device, uint8 function, uint16 deviceId) +{ +} + + +void +pci_fixup_device(PCI *pci, int domain, uint8 bus, uint8 device, uint8 function) +{ + uint16 vendorId = pci->ReadPciConfig(domain, bus, device, function, PCI_vendor_id, 2); + uint16 deviceId = pci->ReadPciConfig(domain, bus, device, function, PCI_device_id, 2); + + switch (vendorId) { + case 0x197b: + jmicron_fixup_ahci(pci, domain, bus, device, function, deviceId); + break; + + case 0x8086: + intel_fixup_ahci(pci, domain, bus, device, function, deviceId); + break; + } +} + diff --git a/src/add-ons/kernel/bus_managers/pci/pci_fixup.h b/src/add-ons/kernel/bus_managers/pci/pci_fixup.h new file mode 100644 index 0000000000..9b6d1fb122 --- /dev/null +++ b/src/add-ons/kernel/bus_managers/pci/pci_fixup.h @@ -0,0 +1,14 @@ +/* + * Copyright 2007, Marcus Overhagen. All rights reserved. + * + * Distributed under the terms of the MIT License. + */ +#ifndef _PCI_FIXUP_H +#define _PCI_FIXUP_H + +class PCI; + +void +pci_fixup_device(PCI *pci, int domain, uint8 bus, uint8 device, uint8 function); + +#endif