This should have been a part of r2210.
[ffado.git] / libffado / tests / test-cycle-time.c
blob43fcbe85a7bc01eb1aeb1d988c4f7924bbea96c5
1 /*
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.
20 * Usage:
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
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.
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".
42 * Remark:
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.
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>
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);
72 exit(1);
76 static int rolled_over(__u32 c0, __u32 c1)
78 return (c0 >> 25) == 127 &&
79 (c1 >> 25) == 0 &&
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)
93 if (argc != 2) {
94 fprintf(stderr, "Usage: %s /dev/fw[0-n]*\n", argv[0]);
95 return -1;
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;
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,
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;
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;
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++;
144 printf("--------------------------------------------------------\n\n");
145 fflush(stdout);
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);
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);
161 return 0;