Introduce workaround for the (documented) bug with ATI/AMD SB600 and early SB700

periodic list cache. This workaround is based on similar patches in NetBSD and
Linux and disables the (Advanced) Periodic List Cache on the affected devices
using ATI/AMD specifc registers (as documented in the corresponding AMD
register reference guide).
Also remove a ton of stray whitespace introduced by the isochronous patches.
Please take more care the next time.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@41512 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Michael Lotz 2011-05-15 14:36:19 +00:00
parent 84464c202e
commit 3bb5704280
2 changed files with 81 additions and 31 deletions

View File

@ -141,6 +141,48 @@ EHCI::EHCI(pci_info *info, Stack *stack)
TRACE("constructing new EHCI host controller driver\n");
fInitOK = false;
// ATI/AMD SB600/SB700 periodic list cache workaround
// Logic kindly borrowed from NetBSD PR 40056
if (fPCIInfo->vendor_id == AMD_SBX00_VENDOR) {
bool applyWorkaround = false;
if (fPCIInfo->device_id == AMD_SB600_EHCI_CONTROLLER) {
// always apply on SB600
applyWorkaround = true;
} else if (fPCIInfo->device_id == AMD_SB700_SB800_EHCI_CONTROLLER) {
// only apply on certain chipsets, determined by SMBus revision
pci_info smbus;
int32 index = 0;
while (sPCIModule->get_nth_pci_info(index++, &smbus) >= B_OK) {
if (smbus.vendor_id == AMD_SBX00_VENDOR
&& smbus.device_id == AMD_SBX00_SMBUS_CONTROLLER) {
// Only applies to chipsets < SB710 (rev A14)
if (smbus.revision == 0x3a || smbus.revision == 0x3b)
applyWorkaround = true;
break;
}
}
}
if (applyWorkaround) {
// According to AMD errata of SB700 and SB600 register documentation
// this disables the Periodic List Cache on SB600 and the Advanced
// Periodic List Cache on early SB700. Both the BSDs and Linux use
// this workaround.
TRACE_ALWAYS("disabling SB600/SB700 periodic list cache\n");
uint32 workaround = sPCIModule->read_pci_config(fPCIInfo->bus,
fPCIInfo->device, fPCIInfo->function,
AMD_SBX00_EHCI_MISC_REGISTER, 4);
sPCIModule->write_pci_config(fPCIInfo->bus, fPCIInfo->device,
fPCIInfo->function, AMD_SBX00_EHCI_MISC_REGISTER, 4,
workaround | AMD_SBX00_EHCI_MISC_DISABLE_PERIODIC_LIST_CACHE);
}
}
// enable busmaster and memory mapped access
uint16 command = sPCIModule->read_pci_config(fPCIInfo->bus,
fPCIInfo->device, fPCIInfo->function, PCI_command, 2);
@ -1657,7 +1699,6 @@ EHCI::FinishIsochronousTransfers()
// Make sure to reset the frame bandwidth
fFrameBandwidth[currentFrame] = MAX_AVAILABLE_BANDWIDTH;
currentFrame = (currentFrame + 1) % EHCI_VFRAMELIST_ENTRIES_COUNT;
}
}
}

View File

@ -335,4 +335,13 @@ typedef struct {
// ToDo: Periodic Frame Span Traversal Node (FSTN, EHCI Spec 3.7)
// Quirk registers and values
#define AMD_SBX00_VENDOR 0x1002
#define AMD_SBX00_SMBUS_CONTROLLER 0x4385
#define AMD_SB600_EHCI_CONTROLLER 0x4386
#define AMD_SB700_SB800_EHCI_CONTROLLER 0x4396
#define AMD_SBX00_EHCI_MISC_REGISTER 0x50 // Advanced config register
#define AMD_SBX00_EHCI_MISC_DISABLE_PERIODIC_LIST_CACHE (1 << 27)
#endif // !EHCI_HARDWARE_H