root/trunk/libffado/tests/test-cycle-time.c

Revision 2101, 5.0 kB (checked in by jwoithe, 12 years ago)

Take 2: this time make sure test-cycle-time.c has been added to version control.

Line 
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 }
Note: See TracBrowser for help on using the browser.