aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/firewire
diff options
context:
space:
mode:
authorClemens Ladisch <clemens@ladisch.de>2010-01-20 03:58:02 -0500
committerStefan Richter <stefanr@s5r6.in-berlin.de>2010-02-19 14:51:10 -0500
commitb677532b971276f48e82578b4d829fb4382e7b41 (patch)
tree5f773a4d65614872c619109595c09b8f9c93bda1 /drivers/firewire
parenta67483d2be12dfc5563c09e6169bec9a88f434b0 (diff)
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: Clemens Ladisch <clemens@ladisch.de> Reported-by: Pieter Palmers <pieterp@joow.be> Reported-by: HÃ¥kan Johansson <f96hajo@chalmers.se> Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
Diffstat (limited to 'drivers/firewire')
-rw-r--r--drivers/firewire/ohci.c52
1 files changed, 49 insertions, 3 deletions
diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c
index 6610d2d38802..d6ba897b2197 100644
--- a/drivers/firewire/ohci.c
+++ b/drivers/firewire/ohci.c
@@ -192,6 +192,7 @@ struct fw_ohci {
192 bool use_dualbuffer; 192 bool use_dualbuffer;
193 bool old_uninorth; 193 bool old_uninorth;
194 bool bus_reset_packet_quirk; 194 bool bus_reset_packet_quirk;
195 bool iso_cycle_timer_quirk;
195 196
196 /* 197 /*
197 * Spinlock for accessing fw_ohci data. Never call out of 198 * 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#endif /* CONFIG_FIREWIRE_OHCI_REMOTE_DMA */ 1795#endif /* CONFIG_FIREWIRE_OHCI_REMOTE_DMA */
1795} 1796}
1796 1797
1798static inline u32 cycle_timer_ticks(u32 cycle_timer)
1799{
1800 u32 ticks;
1801
1802 ticks = cycle_timer & 0xfff;
1803 ticks += 3072 * ((cycle_timer >> 12) & 0x1fff);
1804 ticks += (3072 * 8000) * (cycle_timer >> 25);
1805 return ticks;
1806}
1807
1797static u64 ohci_get_bus_time(struct fw_card *card) 1808static u64 ohci_get_bus_time(struct fw_card *card)
1798{ 1809{
1799 struct fw_ohci *ohci = fw_ohci(card); 1810 struct fw_ohci *ohci = fw_ohci(card);
1800 u32 cycle_time; 1811 u32 c0, c1, c2;
1812 u32 t0, t1, t2;
1813 s32 diff01, diff12;
1801 u64 bus_time; 1814 u64 bus_time;
1802 1815
1803 cycle_time = reg_read(ohci, OHCI1394_IsochronousCycleTimer); 1816 if (!ohci->iso_cycle_timer_quirk) {
1804 bus_time = ((u64)atomic_read(&ohci->bus_seconds) << 32) | cycle_time; 1817 c2 = reg_read(ohci, OHCI1394_IsochronousCycleTimer);
1818 } else {
1819 /*
1820 * VIA controllers have two bugs when updating the iso cycle
1821 * timer register:
1822 * 1) When the lowest six bits are wrapping around to zero,
1823 * a read that happens at the same time will return garbage
1824 * in the lowest ten bits.
1825 * 2) When the cycleOffset field wraps around to zero, the
1826 * cycleCount field is not incremented for about 60 ns.
1827 *
1828 * To catch these, we read the register three times and ensure
1829 * that the difference between each two consecutive reads is
1830 * approximately the same, i.e., less than twice the other.
1831 * Furthermore, any negative difference indicates an error.
1832 * (A PCI read should take at least 20 ticks of the 24.576 MHz
1833 * timer to execute, so we have enough precision to compute the
1834 * ratio of the differences.)
1835 */
1836 do {
1837 c0 = reg_read(ohci, OHCI1394_IsochronousCycleTimer);
1838 c1 = reg_read(ohci, OHCI1394_IsochronousCycleTimer);
1839 c2 = reg_read(ohci, OHCI1394_IsochronousCycleTimer);
1840 t0 = cycle_timer_ticks(c0);
1841 t1 = cycle_timer_ticks(c1);
1842 t2 = cycle_timer_ticks(c2);
1843 diff01 = t1 - t0;
1844 diff12 = t2 - t1;
1845 } while (diff01 <= 0 || diff12 <= 0 ||
1846 diff01 / diff12 >= 2 || diff12 / diff01 >= 2);
1847 }
1848 bus_time = ((u64)atomic_read(&ohci->bus_seconds) << 32) | c2;
1805 1849
1806 return bus_time; 1850 return bus_time;
1807} 1851}
@@ -2498,6 +2542,8 @@ static int __devinit pci_probe(struct pci_dev *dev,
2498#endif 2542#endif
2499 ohci->bus_reset_packet_quirk = dev->vendor == PCI_VENDOR_ID_TI; 2543 ohci->bus_reset_packet_quirk = dev->vendor == PCI_VENDOR_ID_TI;
2500 2544
2545 ohci->iso_cycle_timer_quirk = dev->vendor == PCI_VENDOR_ID_VIA;
2546
2501 ar_context_init(&ohci->ar_request_ctx, ohci, 2547 ar_context_init(&ohci->ar_request_ctx, ohci,
2502 OHCI1394_AsReqRcvContextControlSet); 2548 OHCI1394_AsReqRcvContextControlSet);
2503 2549