Commit b677532b authored by Clemens Ladisch's avatar Clemens Ladisch Committed by Stefan Richter

firewire: ohci: work around cycle timer bugs on VIA controllers

VIA controllers sometimes return an inconsistent value when reading the
isochronous cycle timer register.  To work around this, read the
register multiple times and add consistency checks.
Signed-off-by: default avatarClemens Ladisch <clemens@ladisch.de>
Reported-by: default avatarPieter Palmers <pieterp@joow.be>
Reported-by: default avatarHåkan Johansson <f96hajo@chalmers.se>
Signed-off-by: default avatarStefan Richter <stefanr@s5r6.in-berlin.de>
parent a67483d2
...@@ -192,6 +192,7 @@ struct fw_ohci { ...@@ -192,6 +192,7 @@ struct fw_ohci {
bool use_dualbuffer; bool use_dualbuffer;
bool old_uninorth; bool old_uninorth;
bool bus_reset_packet_quirk; bool bus_reset_packet_quirk;
bool iso_cycle_timer_quirk;
/* /*
* Spinlock for accessing fw_ohci data. Never call out of * Spinlock for accessing fw_ohci data. Never call out of
...@@ -1794,14 +1795,57 @@ static int ohci_enable_phys_dma(struct fw_card *card, ...@@ -1794,14 +1795,57 @@ static int ohci_enable_phys_dma(struct fw_card *card,
#endif /* CONFIG_FIREWIRE_OHCI_REMOTE_DMA */ #endif /* CONFIG_FIREWIRE_OHCI_REMOTE_DMA */
} }
static inline u32 cycle_timer_ticks(u32 cycle_timer)
{
u32 ticks;
ticks = cycle_timer & 0xfff;
ticks += 3072 * ((cycle_timer >> 12) & 0x1fff);
ticks += (3072 * 8000) * (cycle_timer >> 25);
return ticks;
}
static u64 ohci_get_bus_time(struct fw_card *card) static u64 ohci_get_bus_time(struct fw_card *card)
{ {
struct fw_ohci *ohci = fw_ohci(card); struct fw_ohci *ohci = fw_ohci(card);
u32 cycle_time; u32 c0, c1, c2;
u32 t0, t1, t2;
s32 diff01, diff12;
u64 bus_time; u64 bus_time;
cycle_time = reg_read(ohci, OHCI1394_IsochronousCycleTimer); if (!ohci->iso_cycle_timer_quirk) {
bus_time = ((u64)atomic_read(&ohci->bus_seconds) << 32) | cycle_time; c2 = reg_read(ohci, OHCI1394_IsochronousCycleTimer);
} else {
/*
* VIA controllers have two bugs when updating the iso cycle
* timer register:
* 1) When the lowest six bits are wrapping around to zero,
* a read that happens at the same time will return garbage
* in the lowest ten bits.
* 2) When the cycleOffset field wraps around to zero, the
* cycleCount field is not incremented for about 60 ns.
*
* To catch these, we read the register three times and ensure
* that the difference between each two consecutive reads is
* approximately the same, i.e., less than twice the other.
* Furthermore, any negative difference indicates an error.
* (A PCI read should take at least 20 ticks of the 24.576 MHz
* timer to execute, so we have enough precision to compute the
* ratio of the differences.)
*/
do {
c0 = reg_read(ohci, OHCI1394_IsochronousCycleTimer);
c1 = reg_read(ohci, OHCI1394_IsochronousCycleTimer);
c2 = reg_read(ohci, OHCI1394_IsochronousCycleTimer);
t0 = cycle_timer_ticks(c0);
t1 = cycle_timer_ticks(c1);
t2 = cycle_timer_ticks(c2);
diff01 = t1 - t0;
diff12 = t2 - t1;
} while (diff01 <= 0 || diff12 <= 0 ||
diff01 / diff12 >= 2 || diff12 / diff01 >= 2);
}
bus_time = ((u64)atomic_read(&ohci->bus_seconds) << 32) | c2;
return bus_time; return bus_time;
} }
...@@ -2498,6 +2542,8 @@ static int __devinit pci_probe(struct pci_dev *dev, ...@@ -2498,6 +2542,8 @@ static int __devinit pci_probe(struct pci_dev *dev,
#endif #endif
ohci->bus_reset_packet_quirk = dev->vendor == PCI_VENDOR_ID_TI; ohci->bus_reset_packet_quirk = dev->vendor == PCI_VENDOR_ID_TI;
ohci->iso_cycle_timer_quirk = dev->vendor == PCI_VENDOR_ID_VIA;
ar_context_init(&ohci->ar_request_ctx, ohci, ar_context_init(&ohci->ar_request_ctx, ohci,
OHCI1394_AsReqRcvContextControlSet); OHCI1394_AsReqRcvContextControlSet);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment