1 |
/* |
---|
2 |
* Isochronous Cycle Timer register test |
---|
3 |
* |
---|
4 |
* Copyright 2010 Stefan Richter <stefanr@s5r6.in-berlin.de> |
---|
5 |
* You may freely use, modify, and/or redistribute this program. |
---|
6 |
* |
---|
7 |
* Version imported into FFADO: v20100125, from |
---|
8 |
* http://user.in-berlin.de/~s5r6/linux1394/utils/ |
---|
9 |
* |
---|
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. |
---|
14 |
* |
---|
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. |
---|
19 |
* |
---|
20 |
* Usage: |
---|
21 |
* |
---|
22 |
* - Compile with "gcc test_cycle_time_v20100125.c". |
---|
23 |
* |
---|
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. |
---|
27 |
* |
---|
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 |
---|
32 |
* bug. |
---|
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. |
---|
36 |
* |
---|
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". |
---|
41 |
* |
---|
42 |
* Remark: |
---|
43 |
* |
---|
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. |
---|
54 |
*/ |
---|
55 |
|
---|
56 |
#include <fcntl.h> |
---|
57 |
#include <stdio.h> |
---|
58 |
#include <stdlib.h> |
---|
59 |
#include <sys/ioctl.h> |
---|
60 |
#include <sys/stat.h> |
---|
61 |
#include <sys/types.h> |
---|
62 |
#include <unistd.h> |
---|
63 |
|
---|
64 |
#include <linux/firewire-cdev.h> |
---|
65 |
|
---|
66 |
#define TEST_DURATION 60 /* seconds */ |
---|
67 |
|
---|
68 |
static void cooked_ioctl(int fd, int req, void *arg, const char *name) |
---|
69 |
{ |
---|
70 |
if (ioctl(fd, req, arg) < 0) { |
---|
71 |
fprintf(stderr, "Failed %s ioctl: %m\n", name); |
---|
72 |
exit(1); |
---|
73 |
} |
---|
74 |
} |
---|
75 |
|
---|
76 |
static int rolled_over(__u32 c0, __u32 c1) |
---|
77 |
{ |
---|
78 |
return (c0 >> 25) == 127 && |
---|
79 |
(c1 >> 25) == 0 && |
---|
80 |
(c0 >> 12 & 0x1fff) > 8000 - 3 && |
---|
81 |
(c1 >> 12 & 0x1fff) < 0000 + 3; |
---|
82 |
} |
---|
83 |
|
---|
84 |
static void print_ct(__u32 c, __u64 l) |
---|
85 |
{ |
---|
86 |
printf("%03d %04d %04d - %lld.%06lld\n", |
---|
87 |
c >> 25, c >> 12 & 0x1fff, c & 0xfff, |
---|
88 |
l / 1000000, l % 1000000); |
---|
89 |
} |
---|
90 |
|
---|
91 |
int main(int argc, char **argv) |
---|
92 |
{ |
---|
93 |
if (argc != 2) { |
---|
94 |
fprintf(stderr, "Usage: %s /dev/fw[0-n]*\n", argv[0]); |
---|
95 |
return -1; |
---|
96 |
} |
---|
97 |
|
---|
98 |
int fd = open(argv[1], O_RDWR); |
---|
99 |
if (fd < 0) { |
---|
100 |
fprintf(stderr, "Failed to open %s: %m\n", argv[0]); |
---|
101 |
return -1; |
---|
102 |
} |
---|
103 |
|
---|
104 |
__u32 rom[4]; |
---|
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, |
---|
110 |
}; |
---|
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"); |
---|
114 |
return -1; |
---|
115 |
} |
---|
116 |
|
---|
117 |
struct fw_cdev_get_cycle_timer ct; |
---|
118 |
__u32 c0, c1; |
---|
119 |
__u64 l0, l1, end_time; |
---|
120 |
int i, j1, j2, j3; |
---|
121 |
cooked_ioctl(fd, FW_CDEV_IOC_GET_CYCLE_TIMER, &ct, "cycle timer"); |
---|
122 |
c1 = ct.cycle_timer; |
---|
123 |
l1 = ct.local_time; |
---|
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"); |
---|
127 |
c0 = c1; |
---|
128 |
l0 = l1; |
---|
129 |
c1 = ct.cycle_timer; |
---|
130 |
l1 = ct.local_time; |
---|
131 |
|
---|
132 |
if (c1 <= c0 && !rolled_over(c0, c1)) { |
---|
133 |
print_ct(c0, l0); |
---|
134 |
print_ct(c1, l1); |
---|
135 |
printf("\n"); |
---|
136 |
j1++; |
---|
137 |
if ((c1 & 0xfffff000) < (c0 & 0xfffff000)) |
---|
138 |
j2++; |
---|
139 |
if ((c1 & 0xfe000000) < (c0 & 0xfe000000)) |
---|
140 |
j3++; |
---|
141 |
} |
---|
142 |
} |
---|
143 |
|
---|
144 |
printf("--------------------------------------------------------\n\n"); |
---|
145 |
fflush(stdout); |
---|
146 |
|
---|
147 |
char buf[200]; |
---|
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); |
---|
151 |
|
---|
152 |
printf("\n%d cycleOffset backwards out of %d samples (%.2e)\n", |
---|
153 |
j1, i, (double)j1 / (double)i); |
---|
154 |
|
---|
155 |
printf("%d cycleCount backwards (%.2e)\n", |
---|
156 |
j2, (double)j2 / (double)i); |
---|
157 |
|
---|
158 |
printf("%d cycleSeconds backwards (%.2e)\n", |
---|
159 |
j3, (double)j3 / (double)i); |
---|
160 |
|
---|
161 |
return 0; |
---|
162 |
} |
---|