Commit | Line | Data |
---|---|---|
800f879a AT |
1 | /* |
2 | * Copyright 2010-2017 Intel Corporation. | |
3 | * | |
4 | * This program is free software; you can redistribute it and/or modify | |
5 | * it under the terms of the GNU General Public License, version 2, | |
6 | * as published by the Free Software Foundation. | |
7 | * | |
8 | * This program is distributed in the hope that it will be useful, | |
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
11 | * General Public License for more details. | |
12 | * | |
13 | * Disclaimer: The codes contained in these modules may be specific to | |
14 | * the Intel Software Development Platform codenamed Knights Ferry, | |
15 | * and the Intel product codenamed Knights Corner, and are not backward | |
16 | * compatible with other Intel products. Additionally, Intel will NOT | |
17 | * support the codes or instruction set in future products. | |
18 | * | |
19 | * Intel offers no warranty of any kind regarding the code. This code is | |
20 | * licensed on an "AS IS" basis and Intel is not obligated to provide | |
21 | * any support, assistance, installation, training, or other services | |
22 | * of any kind. Intel is also not obligated to provide any updates, | |
23 | * enhancements or extensions. Intel specifically disclaims any warranty | |
24 | * of merchantability, non-infringement, fitness for any particular | |
25 | * purpose, and any other warranty. | |
26 | * | |
27 | * Further, Intel disclaims all liability of any kind, including but | |
28 | * not limited to liability for infringement of any proprietary rights, | |
29 | * relating to the use of the code, even if Intel is notified of the | |
30 | * possibility of such liability. Except as expressly stated in an Intel | |
31 | * license agreement provided with this code and agreed upon with Intel, | |
32 | * no license, express or implied, by estoppel or otherwise, to any | |
33 | * intellectual property rights is granted herein. | |
34 | */ | |
35 | ||
36 | #include <stdio.h> | |
37 | #include <stdlib.h> | |
38 | #include <stdint.h> | |
39 | #include <unistd.h> | |
40 | #include <fcntl.h> | |
41 | #include <sys/ioctl.h> | |
42 | #include "../include/scif.h" | |
43 | #include "trace_capture.h" | |
44 | ||
45 | #define BARRIER(epd, string) { \ | |
46 | printf("%s\n", string); \ | |
47 | if ((err = scif_send(epd, &control_msg, sizeof(control_msg), 1)) <= 0) { \ | |
48 | printf("scif_send failed with err %d\n", errno); \ | |
49 | fflush(stdout); \ | |
50 | goto close; \ | |
51 | } \ | |
52 | if ((err = scif_recv(epd, &control_msg, sizeof(control_msg), 1)) <= 0) { \ | |
53 | printf("scif_recv failed with err %d\n", errno); \ | |
54 | fflush(stdout); \ | |
55 | goto close; \ | |
56 | } \ | |
57 | } | |
58 | ||
59 | #if 0 | |
60 | // These are common to the Host App | |
61 | // and the MIC driver Trace Capture Feature | |
62 | // COMMON DEFINES START HERE | |
63 | enum TRACE_COMMAND { | |
64 | TRACE_NOP = 100, | |
65 | TRACE_DATA, | |
66 | TRACE_HOST_READY, | |
67 | TRACE_DONE, | |
68 | TRACE_ERROR, | |
69 | TRACE_PRINT, | |
70 | TRACE_GET_FILE, | |
71 | TRACE_PAGE_READY, | |
72 | TRACE_REG_COMPLETE, | |
73 | TRACE_MEM_COMPLETE, | |
74 | TRACE_COMPLETE | |
75 | }; | |
76 | ||
77 | #define TRACE_STATUS_OFFSET 8 | |
78 | #define TRACE_SIZE_OFFSET 12 | |
79 | ||
80 | // Enable/Disable Memory Test. | |
81 | // This MUST be enabled simultaneously on Host App as well. | |
82 | #define MIC_TRACE_CAPTURE_MEMORY_TEST 0 | |
83 | ||
84 | #if MIC_TRACE_CAPTURE_MEMORY_TEST | |
85 | #define TRACE_CHECKSUM_OFFSET 16 | |
86 | #endif | |
87 | ||
88 | #define TRACE_TRIGGER_OFFSET 20 | |
89 | #define TRACE_DATA_OFFSET 4096 | |
90 | ||
91 | // Types of Triggers - Refer to uOS Trace Capture Wiki for Usage | |
92 | // Generic counter | |
93 | #define TRACE_HOST_GENERIC_COUNTER 0x1 | |
94 | // Async Flip counter | |
95 | #define TRACE_HOST_FRAME_COUNTER 0x2 | |
96 | // COMMON DEFINES END HERE | |
97 | #endif | |
98 | ||
99 | // End points for SCIF | |
100 | //static scif_epd_t mictc_epd_cmd; | |
101 | static scif_epd_t mictc_epd_data; | |
102 | ||
103 | // SCIF ports - temp hack; move to scif.h | |
104 | #define MICTC_SCIF_PORT_DATA 300 | |
105 | ||
106 | static volatile uint64_t *g_traceBufferStatusOffset = NULL; | |
107 | static volatile uint64_t *g_traceBufferSizeOffset = NULL; | |
108 | static volatile uint32_t *g_traceBufferDataOffset = NULL; | |
109 | static volatile uint32_t *g_traceBufferTriggerOffset = NULL; | |
110 | ||
111 | // This is an array of trigger numbers. The value TRACE_EOL is ignored. | |
112 | static uint32_t g_traceTriggers[TRACE_TRIGGER_MAX]; | |
113 | ||
114 | static struct scif_portID portID_data; | |
115 | static scif_epd_t mictc_newepd; | |
116 | ||
117 | static void *g_mictc_buffer_base; | |
118 | static void *g_mictc_buffer_offset_xml; | |
119 | static off_t g_mictc_buffer_offset_mem; | |
120 | ||
121 | FILE *fp; | |
122 | ||
123 | static | |
124 | int open_scif_channels(void) | |
125 | { | |
126 | int err; | |
127 | struct pollfd spollfd; | |
128 | int control_msg = 0; | |
129 | long scif_offset_dst; | |
130 | int timeout = 0; | |
131 | int page_count = 0; | |
132 | int i; | |
133 | ||
134 | if ((err = posix_memalign(&g_mictc_buffer_base, 0x1000, MICTC_MEM_BUFFER_SIZE))) { | |
135 | fprintf(stderr, "posix_memalign failed failed with %d\n", err); | |
136 | return 0; | |
137 | } | |
138 | // Data channel | |
139 | if ((mictc_epd_data = scif_open()) == SCIF_OPEN_FAILED) { | |
140 | fprintf(stderr, "scif_open failed with ENOMEM\n", errno); | |
141 | return 0; | |
142 | } | |
143 | ||
144 | if (scif_bind(mictc_epd_data, MICTC_SCIF_PORT_DATA) == -1) { | |
145 | fprintf(stderr, "scif_bind failed with error %d\n", errno); | |
146 | return 0; | |
147 | } | |
148 | ||
149 | portID_data.node = 1; | |
150 | portID_data.port = MICTC_SCIF_PORT_DATA; | |
151 | ||
152 | if (scif_listen(mictc_epd_data, 1) == -1) { | |
153 | fprintf(stderr, "scif_listen failed with error %d\n", errno); | |
154 | return 0; | |
155 | } | |
156 | ||
157 | while (1) { | |
158 | printf("scif_accept in poll mode until a connect request is found\n"); | |
159 | err = 1; | |
160 | while (err) { | |
161 | spollfd.fd = scif_get_fd(mictc_epd_data); | |
162 | spollfd.events = POLLIN; | |
163 | spollfd.revents = 0; | |
164 | if ((err = poll(&spollfd, 1, -1)) < 0) { | |
165 | printf("poll failed with err %d\n", errno); | |
166 | } | |
167 | if (((err = scif_accept(mictc_epd_data, &portID_data, &mictc_newepd, 0)) < 0) && (errno != EAGAIN)) { | |
168 | printf("scif_accept failed with err %d\n", errno); | |
169 | return 0; | |
170 | } | |
171 | } | |
172 | ||
173 | printf("scif_accept from port %d complete\n", portID_data.port); | |
174 | ||
175 | if ((g_mictc_buffer_offset_mem = scif_register(mictc_newepd, g_mictc_buffer_base, MICTC_MEM_BUFFER_SIZE, 0, // suggested_offset, | |
176 | SCIF_PROT_READ | SCIF_PROT_WRITE, 0)) < 0) { | |
177 | fprintf(stderr, "scif_register failed with err %d\n", errno); | |
178 | return 0; | |
179 | } | |
180 | ||
181 | printf("After scif_register, g_mictc_buffer_offset_mem = %llx\n", | |
182 | (unsigned long long)g_mictc_buffer_offset_mem); | |
183 | fflush(stdout); | |
184 | ||
185 | // printf("Before scif_send\n"); | |
186 | // fflush(stdout); | |
187 | ||
188 | BARRIER(mictc_newepd, "before barrier"); | |
189 | ||
190 | if ((err = | |
191 | scif_send(mictc_newepd, &g_mictc_buffer_offset_mem, sizeof(g_mictc_buffer_offset_mem), | |
192 | SCIF_SEND_BLOCK)) <= 0) { | |
193 | printf("scif_send failed with err %d\n", errno); | |
194 | fflush(stdout); | |
195 | goto close; | |
196 | } | |
197 | // BARRIER(mictc_newepd, "scif_send"); | |
198 | ||
199 | // printf("scif_offset = %lx\n", scif_offset); | |
200 | // fflush(stdout); | |
201 | ||
202 | printf("Before scif_recv\n"); | |
203 | fflush(stdout); | |
204 | ||
205 | if ((err = scif_recv(mictc_newepd, &scif_offset_dst, sizeof(scif_offset_dst), SCIF_RECV_BLOCK)) <= 0) { | |
206 | printf("scif_recv failed with err %d\n", errno); | |
207 | fflush(stdout); | |
208 | goto close; | |
209 | } | |
210 | printf("scif_offset_dst = %lx\n", scif_offset_dst); | |
211 | ||
212 | printf("Before scif_mmap\n"); | |
213 | ||
214 | if ((g_mictc_buffer_offset_xml = scif_mmap(0, // physical address | |
215 | MICTC_XML_BUFFER_SIZE, // length | |
216 | SCIF_PROT_READ | SCIF_PROT_WRITE, // protection | |
217 | 0, // flags | |
218 | mictc_newepd, // endpoint | |
219 | scif_offset_dst) // offset | |
220 | ) == (void *)-1) { | |
221 | fprintf(stderr, "scif_mmap failed with err %d\n", errno); | |
222 | return 0; | |
223 | } | |
224 | ||
225 | g_traceBufferStatusOffset = (uint64_t *) (g_mictc_buffer_offset_xml + TRACE_STATUS_OFFSET); | |
226 | g_traceBufferSizeOffset = (uint64_t *) (g_mictc_buffer_offset_xml + TRACE_SIZE_OFFSET); | |
227 | g_traceBufferDataOffset = (uint32_t *) (g_mictc_buffer_offset_xml + TRACE_DATA_OFFSET); | |
228 | g_traceBufferTriggerOffset = (uint32_t *) (g_mictc_buffer_offset_xml + TRACE_TRIGGER_OFFSET); | |
229 | ||
230 | for (i = 0; i < TRACE_TRIGGER_MAX; i++) { | |
231 | *g_traceBufferTriggerOffset = g_traceTriggers[i]; | |
232 | g_traceBufferTriggerOffset++; | |
233 | } | |
234 | ||
235 | *g_traceBufferStatusOffset = TRACE_HOST_READY; | |
236 | ||
237 | printf("Before fopen\n"); | |
238 | ||
239 | if ((fp = fopen("cpu.xml", "w")) == NULL) { | |
240 | fprintf(stderr, "Cannot open file cpu.xml.\n"); | |
241 | } | |
242 | ||
243 | printf("Waiting for TRACE_REG_COMPLETE or TRACE_ABORTED"); | |
244 | fflush(stdout); | |
245 | ||
246 | while (*g_traceBufferStatusOffset != TRACE_REG_COMPLETE) { | |
247 | printf("."); | |
248 | fflush(stdout); | |
249 | sleep(1); | |
250 | if (timeout++ >= 200) { | |
251 | // Hmmm, something is hung up. Save everything in the buffer ignoring length. | |
252 | printf("Punt!\n"); | |
253 | fprintf(fp, "%s\n", (char *)g_traceBufferDataOffset); | |
254 | *g_traceBufferStatusOffset = TRACE_GET_FILE; | |
255 | fclose(fp); | |
256 | sleep(5); | |
257 | goto close; // and quit | |
258 | } | |
259 | // If this happens the current trigger was not one we want -- reset and wait. | |
260 | if (*g_traceBufferStatusOffset == TRACE_ABORTED) { | |
261 | printf("\nAborted trace\n"); | |
262 | fflush(stdout); | |
263 | goto close2; | |
264 | } | |
265 | } | |
266 | printf("\n"); | |
267 | ||
268 | { | |
269 | int j; | |
270 | ||
271 | asm volatile ("lfence" ::: "memory"); | |
272 | j = *g_traceBufferSizeOffset; | |
273 | fprintf(fp, "%*s\n", j, (char *)g_traceBufferDataOffset); | |
274 | } | |
275 | *g_traceBufferStatusOffset = TRACE_GET_FILE; | |
276 | fclose(fp); | |
277 | sleep(5); | |
278 | ||
279 | // Memory dump | |
280 | ||
281 | if ((fp = fopen("mem.dat", "w")) == NULL) { | |
282 | fprintf(stderr, "Cannot open file mem.dat.\n"); | |
283 | } | |
284 | ||
285 | printf("Waiting for memory pages\n"); | |
286 | fflush(stdout); | |
287 | ||
288 | timeout = 0; | |
289 | ||
290 | { | |
291 | long i = 0; | |
292 | ||
293 | while (*g_traceBufferStatusOffset != TRACE_MEM_COMPLETE) { | |
294 | //printf("status %d\n", *g_traceBufferStatusOffset); | |
295 | ||
296 | if (*g_traceBufferStatusOffset == TRACE_PAGE_READY) { | |
297 | printf(" %ld", i++); | |
298 | fflush(stdout); | |
299 | asm volatile ("lfence" ::: "memory"); | |
300 | ||
301 | if (fwrite(g_mictc_buffer_base, *g_traceBufferSizeOffset, 1, fp) != 1) { | |
302 | fprintf(stderr, "\nCannot write file mem.dat. error = %d\n", ferror(fp)); | |
303 | return 0; | |
304 | } | |
305 | *g_traceBufferStatusOffset = TRACE_HOST_READY; // Get next page | |
306 | timeout = 0; | |
307 | } else { | |
308 | // printf("."); | |
309 | // fflush(stdout); | |
310 | usleep(10000); | |
311 | ||
312 | if (timeout++ >= 2000) { | |
313 | // Hmmm, something is hung up. Just close and quit. | |
314 | printf("Punt!\n"); | |
315 | fclose(fp); | |
316 | sleep(5); | |
317 | goto close; // and quit | |
318 | } | |
319 | } | |
320 | } | |
321 | } | |
322 | close1: | |
323 | printf("\nClosing memory dump file.\n"); | |
324 | fflush(stdout); | |
325 | fclose(fp); | |
326 | *g_traceBufferStatusOffset = TRACE_COMPLETE; // File is closed; tell driver we are done. | |
327 | printf("Done.\n"); | |
328 | fflush(stdout); | |
329 | close2: | |
330 | sleep(2); | |
331 | scif_munmap(g_mictc_buffer_offset_xml, MICTC_XML_BUFFER_SIZE); | |
332 | scif_unregister(mictc_newepd, (off_t) g_mictc_buffer_base, MICTC_MEM_BUFFER_SIZE); | |
333 | scif_close(mictc_newepd); | |
334 | } // while (1) | |
335 | close: | |
336 | scif_munmap(g_mictc_buffer_offset_xml, MICTC_XML_BUFFER_SIZE); | |
337 | scif_close(mictc_newepd); | |
338 | scif_close(mictc_epd_data); | |
339 | free(g_mictc_buffer_base); | |
340 | return 1; | |
341 | } | |
342 | ||
343 | int main(int argc, char *argv[]) | |
344 | { | |
345 | int i; | |
346 | ||
347 | for (i = 0; i < TRACE_TRIGGER_MAX; i++) { | |
348 | g_traceTriggers[i] = TRACE_EOL; | |
349 | } | |
350 | ||
351 | if (argc >= 2) { | |
352 | for (i = 1; i < argc; i++) { | |
353 | if (i > TRACE_TRIGGER_MAX) break; | |
354 | ||
355 | g_traceTriggers[i - 1] = atoi(argv[i]); | |
356 | printf("Trigger %d\n", g_traceTriggers[i - 1]); | |
357 | } | |
358 | } else { | |
359 | printf("No triggers -- accept everything\n"); | |
360 | } | |
361 | ||
362 | if (!open_scif_channels()) | |
363 | exit(1); | |
364 | ||
365 | exit(0); | |
366 | } |