aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ieee1394/ohci1394.c
diff options
context:
space:
mode:
authorPieter Palmers <pieterp@joow.be>2008-03-19 17:10:59 -0400
committerStefan Richter <stefanr@s5r6.in-berlin.de>2008-04-25 12:15:45 -0400
commitcc9429bcb6e36e9f2c51e4e47b95740e472c4c2d (patch)
treefecf2d6e8fdbe6f0dd5ee74e4b3cbe945d473c3d /drivers/ieee1394/ohci1394.c
parentdb8be076cad4b843aa743ef462c75022cddd9c63 (diff)
ieee1394: rawiso: requeue packet for transmission after skipped cycle
As it seems, some host controllers have issues that can cause them to skip cycles now and then when using large packets. I suspect that this is due to DMA not succeeding in time. If the transmit fifo can't contain more than one packet (big packets), the DMA should provide a new packet each cycle (125us). I am under the impression that my current PCI express test system can't guarantee this. In any case, the patch tries to provide a workaround as follows: The DMA program descriptors are modified such that when an error occurs, the DMA engine retries the descriptor the next cycle instead of stalling. This way no data is lost. The side effect of this is that packets are sent with one cycle delay. This however might not be that much of a problem for certain protocols (e.g. AM824). If they use padding packets for e.g. rate matching they can drop one of those to resync the streams. The amount of skips between two userspace wakeups is counted. This number is then propagated to userspace through the upper 16 bits of the 'dropped' parameter. This allows unmodified userspace applications due to the following: 1) libraw simply passes this dropped parameter to the user application 2) the meaning of the dropped parameter is: if it's nonzero, something bad has happened. The actual value of the parameter at this moment does not have a specific meaning. A libraw client can then retrieve the number of skipped cycles and account for them if needed. Signed-off-by: Pieter Palmers <pieterp@joow.be> Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
Diffstat (limited to 'drivers/ieee1394/ohci1394.c')
-rw-r--r--drivers/ieee1394/ohci1394.c34
1 files changed, 34 insertions, 0 deletions
diff --git a/drivers/ieee1394/ohci1394.c b/drivers/ieee1394/ohci1394.c
index 0690469fcecf..e509e13cb7a7 100644
--- a/drivers/ieee1394/ohci1394.c
+++ b/drivers/ieee1394/ohci1394.c
@@ -1723,6 +1723,8 @@ struct ohci_iso_xmit {
1723 struct dma_prog_region prog; 1723 struct dma_prog_region prog;
1724 struct ohci1394_iso_tasklet task; 1724 struct ohci1394_iso_tasklet task;
1725 int task_active; 1725 int task_active;
1726 int last_cycle;
1727 atomic_t skips;
1726 1728
1727 u32 ContextControlSet; 1729 u32 ContextControlSet;
1728 u32 ContextControlClear; 1730 u32 ContextControlClear;
@@ -1759,6 +1761,8 @@ static int ohci_iso_xmit_init(struct hpsb_iso *iso)
1759 iso->hostdata = xmit; 1761 iso->hostdata = xmit;
1760 xmit->ohci = iso->host->hostdata; 1762 xmit->ohci = iso->host->hostdata;
1761 xmit->task_active = 0; 1763 xmit->task_active = 0;
1764 xmit->last_cycle = -1;
1765 atomic_set(&iso->skips, 0);
1762 1766
1763 dma_prog_region_init(&xmit->prog); 1767 dma_prog_region_init(&xmit->prog);
1764 1768
@@ -1856,6 +1860,26 @@ static void ohci_iso_xmit_task(unsigned long data)
1856 /* parse cycle */ 1860 /* parse cycle */
1857 cycle = le32_to_cpu(cmd->output_last.status) & 0x1FFF; 1861 cycle = le32_to_cpu(cmd->output_last.status) & 0x1FFF;
1858 1862
1863 if (xmit->last_cycle > -1) {
1864 int cycle_diff = cycle - xmit->last_cycle;
1865 int skip;
1866
1867 /* unwrap */
1868 if (cycle_diff < 0) {
1869 cycle_diff += 8000;
1870 if (cycle_diff < 0)
1871 PRINT(KERN_ERR, "bogus cycle diff %d\n",
1872 cycle_diff);
1873 }
1874
1875 skip = cycle_diff - 1;
1876 if (skip > 0) {
1877 DBGMSG("skipped %d cycles without packet loss", skip);
1878 atomic_add(skip, &iso->skips);
1879 }
1880 }
1881 xmit->last_cycle = cycle;
1882
1859 /* tell the subsystem the packet has gone out */ 1883 /* tell the subsystem the packet has gone out */
1860 hpsb_iso_packet_sent(iso, cycle, event != 0x11); 1884 hpsb_iso_packet_sent(iso, cycle, event != 0x11);
1861 1885
@@ -1943,6 +1967,16 @@ static int ohci_iso_xmit_queue(struct hpsb_iso *iso, struct hpsb_iso_packet_info
1943 prev->output_last.branchAddress = cpu_to_le32( 1967 prev->output_last.branchAddress = cpu_to_le32(
1944 dma_prog_region_offset_to_bus(&xmit->prog, sizeof(struct iso_xmit_cmd) * next_i) | 3); 1968 dma_prog_region_offset_to_bus(&xmit->prog, sizeof(struct iso_xmit_cmd) * next_i) | 3);
1945 1969
1970 /*
1971 * Link the skip address to this descriptor itself. This causes a
1972 * context to skip a cycle whenever lost cycles or FIFO overruns occur,
1973 * without dropping the data at that point the application should then
1974 * decide whether this is an error condition or not. Some protocols
1975 * can deal with this by dropping some rate-matching padding packets.
1976 */
1977 next->output_more_immediate.branchAddress =
1978 prev->output_last.branchAddress;
1979
1946 /* disable interrupt, unless required by the IRQ interval */ 1980 /* disable interrupt, unless required by the IRQ interval */
1947 if (prev_i % iso->irq_interval) { 1981 if (prev_i % iso->irq_interval) {
1948 prev->output_last.control &= cpu_to_le32(~(3 << 20)); /* no interrupt */ 1982 prev->output_last.control &= cpu_to_le32(~(3 << 20)); /* no interrupt */