2 * Isochronous Cycle Timer register test
4 * Copyright 2010 Stefan Richter <stefanr@s5r6.in-berlin.de>
5 * You may freely use, modify, and/or redistribute this program.
7 * Version imported into FFADO: v20100125, from
8 * http://user.in-berlin.de/~s5r6/linux1394/utils/
10 * This is a tool to test the reliability of one particular hardware feature
11 * of OHCI-1394 (FireWire) controllers: The isochronous cycle timer register.
12 * Some controllers do not access this register atomically, resulting in the
13 * cycle time seemingly jumping backwards occasionally.
15 * The firewire-ohci driver contains a workaround for unreliable isochronous
16 * cycle timer hardware, but this workaround is only activated for known bad
17 * hardware. You can use this tool to check whether you have an affected
18 * controller and firewire-ohci misses the necessary quirks entry.
22 * - Compile with "gcc test_cycle_time_v20100125.c".
24 * - Run with "sudo ./a.out /dev/fw0". Use a different /dev/fw* file if you
25 * have multiple controllers in your machine and want to test the second
26 * or following controller. Be patient, the test runs for 60 seconds.
28 * - If the very last lines of the resulting output contains only
29 * "0 cycleOffset backwards", "0 cycleCount backwards", "0 cycleSeconds
30 * backwards", then either the hardware works correctly or the driver
31 * already uses the workaround to compensate for a cycle timer hardware
33 * But if the last lines of the output show one or more of the three cycle
34 * timer components having gone backwards, then the hardware is buggy and
35 * the driver does not yet contain the necessary quirks entry.
37 * In the latter case, please report your findings at
38 * <linux1394-devel@lists.sourceforge.net>. This mailinglist is open for
39 * posting without prior subscription. Please include the type and identifiers
40 * of your FireWire controller(s) in your posting, as obtained by "lspci -nn".
44 * This program optionally accesses /usr/share/misc/oui.db to translate the
45 * Globally Unique Identifier of the device that is associated with the chosen
46 * /dev/fw* to the company name of the device manufacturer. The oui.db file
47 * is not necessary for this program to work though. If you want you can
48 * generate oui.db this way:
49 * wget -O - http://standards.ieee.org/regauth/oui/oui.txt |
50 * grep -E '(base 16).*\w+.*$' |
51 * sed -e 's/\s*(base 16)\s*'/' /' > oui.db
52 * sudo mv oui.db /usr/share/misc/
53 * which will download ~2 MB data and result in a ~0.4 MB large oui.db.
59 #include <sys/ioctl.h>
61 #include <sys/types.h>
64 #include <linux/firewire-cdev.h>
66 #define TEST_DURATION 60 /* seconds */
68 static void cooked_ioctl(int fd
, int req
, void *arg
, const char *name
)
70 if (ioctl(fd
, req
, arg
) < 0) {
71 fprintf(stderr
, "Failed %s ioctl: %m\n", name
);
76 static int rolled_over(__u32 c0
, __u32 c1
)
78 return (c0
>> 25) == 127 &&
80 (c0
>> 12 & 0x1fff) > 8000 - 3 &&
81 (c1
>> 12 & 0x1fff) < 0000 + 3;
84 static void print_ct(__u32 c
, __u64 l
)
86 printf("%03d %04d %04d - %lld.%06lld\n",
87 c
>> 25, c
>> 12 & 0x1fff, c
& 0xfff,
88 l
/ 1000000, l
% 1000000);
91 int main(int argc
, char **argv
)
94 fprintf(stderr
, "Usage: %s /dev/fw[0-n]*\n", argv
[0]);
98 int fd
= open(argv
[1], O_RDWR
);
100 fprintf(stderr
, "Failed to open %s: %m\n", argv
[0]);
105 struct fw_cdev_event_bus_reset reset
;
106 struct fw_cdev_get_info info
= {
107 .rom
= (unsigned long)rom
,
108 .rom_length
= sizeof(rom
),
109 .bus_reset
= (unsigned long)&reset
,
111 cooked_ioctl(fd
, FW_CDEV_IOC_GET_INFO
, &info
, "info");
112 if (reset
.node_id
!= reset
.local_node_id
) {
113 fprintf(stderr
, "Not a local node\n");
117 struct fw_cdev_get_cycle_timer ct
;
119 __u64 l0
, l1
, end_time
;
121 cooked_ioctl(fd
, FW_CDEV_IOC_GET_CYCLE_TIMER
, &ct
, "cycle timer");
124 end_time
= l1
+ TEST_DURATION
* 1000000ULL;
125 for (i
= j1
= j2
= j3
= 0; l1
< end_time
; i
++) {
126 cooked_ioctl(fd
, FW_CDEV_IOC_GET_CYCLE_TIMER
, &ct
, "cycle timer");
132 if (c1
<= c0
&& !rolled_over(c0
, c1
)) {
137 if ((c1
& 0xfffff000) < (c0
& 0xfffff000))
139 if ((c1
& 0xfe000000) < (c0
& 0xfe000000))
144 printf("--------------------------------------------------------\n\n");
148 sprintf(buf
, "grep %06X /usr/share/misc/oui.db", rom
[3] >> 8);
149 if (system(buf
) != 0)
150 printf("%06X (unknown Vendor OUI)\n", rom
[3] >> 8);
152 printf("\n%d cycleOffset backwards out of %d samples (%.2e)\n",
153 j1
, i
, (double)j1
/ (double)i
);
155 printf("%d cycleCount backwards (%.2e)\n",
156 j2
, (double)j2
/ (double)i
);
158 printf("%d cycleSeconds backwards (%.2e)\n",
159 j3
, (double)j3
/ (double)i
);