/* * Copyright © 2014 Intel Corporation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include #include #include "i915_reg.h" #include "main.h" int process_regread(char *cmdhdr,unsigned int reg) { uint32_t value=INREG(linear_mmio,reg); printf("read register 0x%x,value is 0x%08x\n",reg,value); print_bin_fmt(value,15); return 0; } int process_regwrite(char *cmdhdr,unsigned int reg, unsigned int value) { printf("Write register 0x%x with value 0x%x\n",reg,value); OUTREG(linear_mmio,reg,value); return 0; } static uint64_t now_us() { struct timeval tv; if (gettimeofday(&tv, NULL)) return 0; return tv.tv_usec + tv.tv_sec*1000*1000; } static int current_render(uint32_t delta_ms, uint32_t delta_us); static int current_video(uint32_t delta_ms, uint32_t delta_us); #define I915_GEM_HWS_INDEX 0x20 /* Linux kernle file i915_irq.c */ #define GEN8_GT_IIR(which) (0x44308 + (0x10 * (which))) #define GEN8_BCS_IRQ_SHIFT 16 #define GEN8_RCS_IRQ_SHIFT 0 #define GEN8_VCS2_IRQ_SHIFT 16 #define GEN8_VCS1_IRQ_SHIFT 0 #define GEN8_VECS_IRQ_SHIFT 0 #define GEN8_OACS_IRQ_SHIFT 19 int process_irq(char *cmdhdr,unsigned int seconds) { uint64_t start = now_us(); uint64_t expected_end = start + 1000 * 1000 * seconds; unsigned int render_iir=0, video_iir=0; uint32_t *render_seqno, *video_seqno, last_render_seqno=0, last_video_seqno=0; uint32_t *blit_seqno, *video2_seqno, last_blit_seqno=0, last_video2_seqno=0; uint32_t render_hws, video_hws, blit_hws, video2_hws; if (is_gen7) { printf("IRQ sample tbd on GEN7\n"); return 0; } render_hws = INREG(linear_mmio, 0x2080); video_hws = INREG(linear_mmio, 0x12080); blit_hws = INREG(linear_mmio, 0x1a080); video2_hws = INREG(linear_mmio, 0x1c080); printf("Sample IRQ for %d seconds....It is not accurate, just rough view\n", seconds); printf("Render HWS_PGA=0x%08x, Video HWS_PGA=0x%08x\n", render_hws, video_hws); render_seqno = (uint32_t *)((unsigned char *)linear_fb + render_hws) + I915_GEM_HWS_INDEX; video_seqno = (uint32_t *)((unsigned char *)linear_fb + video_hws) + I915_GEM_HWS_INDEX; blit_seqno = (uint32_t *)((unsigned char *)linear_fb + blit_hws) + I915_GEM_HWS_INDEX; video2_seqno = (uint32_t *)((unsigned char *)linear_fb + video2_hws) + I915_GEM_HWS_INDEX; while (1) { uint64_t now = now_us(); int64_t test = now - expected_end; //printf("now=%u, expected end=%u, test = %d\n", now, expected_end, test); if (test > 0) break; uint64_t delta = now - start; uint32_t delta_ms = (uint32_t)(delta/1000); uint32_t delta_us = (uint32_t)(delta%1000); uint32_t tmp = INREG(linear_mmio, GEN8_GT_IIR(0)); uint32_t tmp1 = INREG(linear_mmio, GEN8_GT_IIR(1)); while (render_iir != tmp) { uint32_t rcs = tmp >> GEN8_RCS_IRQ_SHIFT; uint32_t bcs = tmp >> GEN8_BCS_IRQ_SHIFT; int has_irq; render_iir = tmp; has_irq = (rcs|bcs) & (GT_RENDER_USER_INTERRUPT|GT_CONTEXT_SWITCH_INTERRUPT); if (has_irq) { printf("T%d.%03d:iir=0x%08x\n", delta_ms, delta_us, tmp); //print_bin_fmt(tmp, 8); } else break; if ((rcs & GT_RENDER_USER_INTERRUPT) && (last_render_seqno != *render_seqno)) { printf("\tRCS:GT_USER_INTERRUPT (seqno=0x%08x)\n", *render_seqno); last_render_seqno = *render_seqno; } if (rcs & GT_CONTEXT_SWITCH_INTERRUPT) { printf("\tRCS:GT_CONTEXT_SWITCH_INTERRUPT (seqno=0x%08x)\n", *render_seqno); if (verbose) current_render(delta_ms, delta_us); } if ((bcs & GT_RENDER_USER_INTERRUPT) && (last_blit_seqno != *blit_seqno)) { last_blit_seqno = *blit_seqno; printf("\tBCS:GT_USER_INTERRUPT (seqno=0x%08x)\n", *blit_seqno); } if (bcs & GT_CONTEXT_SWITCH_INTERRUPT) printf("\tBCS:GT_CONTEXT_SWITCH_INTERRUPT (seqno=0x%08x)\n", *render_seqno); break; } while (video_iir != tmp1) { /* video engine */ uint32_t vcs = tmp1 >> GEN8_VCS1_IRQ_SHIFT; uint32_t vcs2 = tmp1 >> GEN8_VCS2_IRQ_SHIFT; int has_irq; video_iir = tmp1; has_irq = (vcs|vcs2) & (GT_RENDER_USER_INTERRUPT|GT_CONTEXT_SWITCH_INTERRUPT); if (has_irq) { printf("T%d.%03d:iir=0x%08x\n", delta_ms, delta_us, tmp1); //print_bin_fmt(tmp, 8); } else break; if ((vcs & GT_RENDER_USER_INTERRUPT) && (last_video_seqno != *video_seqno)) { last_video_seqno = *video_seqno; printf("\tVCS:GT_USER_INTERRUPT (seqno=0x%08x)\n", *video_seqno); } if (vcs & GT_CONTEXT_SWITCH_INTERRUPT) { printf("\tVCS:GT_CONTEXT_SWITCH_INTERRUPT (seqno=0x%08x)\n", *video_seqno); if (verbose) current_video(delta_ms, delta_us); } if ((vcs2 & GT_RENDER_USER_INTERRUPT) && (last_video2_seqno != *video2_seqno)) { last_video2_seqno = *video2_seqno; printf("\tVCS2:GT_USER_INTERRUPT (seqno=0x%08x)\n", *video2_seqno); } if (vcs2 & GT_CONTEXT_SWITCH_INTERRUPT) printf("\tVCS2:GT_CONTEXT_SWITCH_INTERRUPT (seqno=0x%08x)\n", *video_seqno); break; } } return 0; } static void print_estatus(uint32_t estatus) { uint32_t tmp; printf("\tExeclist 0 Active = %d\n", (estatus>>18) & 0x1); printf("\tExeclist 1 Active = %d\n", (estatus>>18) & 0x1); tmp = (estatus>>14) & 0x2; printf("\tCurrent Active Element Status = %d", tmp); if (tmp == 0) printf("(No Active Element being executed)\n"); else if (tmp == 1) printf("(Element0 of current execlist being executed)\n"); else if (tmp == 2) printf("(Element1 of current execlist being executed)\n"); tmp = (estatus>>5) & 0x1ff; printf("\tLast Context Switch Reason = 0x%x\n", tmp); if (tmp & 1) printf("\t\tIDLE to ACTIVE\n"); if (tmp & 2) printf("\t\tPreempted\n"); if (tmp & 4) printf("\t\tElement Switch: from element0 to element1 in the current execlist\n"); if (tmp & 8) printf("\t\tACTIVE to IDLE\n"); if (tmp & 0x10) printf("\t\tContext Complete:Element is completely processed\n"); if (tmp & 0x1e0) printf("\t\tWait on display\n"); printf("\tExeclist 0 Valid = %d\n", (estatus>>4) & 0x1); printf("\tExeclist 1 Valid = %d\n", (estatus>>3) & 0x1); } int process_estatus(char *cmdhdr,unsigned int seconds) { uint64_t start = now_us(); uint64_t expected_end = start + 1000 * 1000 * seconds; uint32_t previous_r_eid = 0, previous_r_estatus = 0; uint32_t previous_v_eid = 0, previous_v_estatus = 0; if (is_gen7) { printf("Execlist is not supported on GEN7\n"); return 0; } printf("Sample ExecList Status for %d seconds....\n", seconds); printf("It is not accurate, just for a rough view\n"); while (1) { uint64_t now = now_us(); int64_t test = now - expected_end; if (test > 0) break; uint64_t delta = now - start; uint32_t delta_ms = (uint32_t)(delta/1000); uint32_t delta_us = (uint32_t)(delta%1000); uint32_t r_estatus = INREG(linear_mmio, 0x2234); uint32_t r_eid = INREG(linear_mmio, 0x2238); uint32_t v_estatus = INREG(linear_mmio, 0x12234); uint32_t v_eid = INREG(linear_mmio, 0x12238); if ((r_eid !=0) && (r_estatus != 0) && ((previous_r_eid != r_eid) || (previous_r_estatus!= r_estatus))) { printf("----------------------------------Render---------------------------------\n"); printf("T%d.%03d:context id=0x%08x, status=0x%08x\n", delta_ms, delta_us, r_eid, r_estatus); print_estatus(r_estatus); previous_r_eid = r_eid; previous_r_estatus = r_estatus; } if ((v_eid !=0) && (v_estatus != 0) && ((previous_v_eid != v_eid) || (previous_v_estatus!= v_estatus))) { printf("----------------------------------Video---------------------------------\n"); printf("T%d.%03d:context id=0x%08x, status=0x%08x\n", delta_ms, delta_us, v_eid, v_estatus); print_estatus(v_estatus); previous_v_eid = v_eid; previous_v_estatus = v_estatus; } } return 0; } static void print_cstatus(uint32_t ldw, uint32_t udw) { uint32_t tmp; printf("\tContext id=0x%08x\n", udw); printf("\tContext status = 0x%08x\n", ldw); printf("\t\tWait display plane = 0x%04x\n", (ldw>>16) & 0xf); printf("\t\tLite restore = %d\n", (ldw>>15)&1); printf("\t\tWait display plane = 0x%03x\n", (ldw>>12) & 0x3); printf("\t\tSemaphore wait mode = %d\n", (ldw>>11)&1); tmp = ldw & 0x1ff; printf("\t\tLast Context Switch Reason = 0x%x\n", tmp); if (tmp & 1) printf("\t\t\tIDLE to ACTIVE\n"); if (tmp & 2) printf("\t\t\tPreempted\n"); if (tmp & 4) printf("\t\t\tElement Switch: from element0 to element1 in the current execlist\n"); if (tmp & 8) printf("\t\t\tACTIVE to IDLE\n"); if (tmp & 0x10) printf("\t\t\tContext Complete:Element is completely processed\n"); if (tmp & 0x1e0) printf("\t\t\tWait on display\n"); } static struct context_status_t { uint32_t udw; uint32_t ldw; } render[6], video[6]; static int render_wp, video_wp, last_render_wp, last_video_wp; static int current_render(uint32_t delta_ms, uint32_t delta_us) { uint32_t mmio_addr; render_wp = INREG(linear_mmio, 0x23a0) % 6; if (render_wp == last_render_wp) return 0; last_render_wp = render_wp; if (render_wp == 0) render_wp = 5; else render_wp--; mmio_addr = 0x2370; render[render_wp].ldw = INREG(linear_mmio, mmio_addr + render_wp*8); render[render_wp].udw = INREG(linear_mmio, mmio_addr + render_wp*8 + 4); if (render[render_wp].udw != 0) { printf("-----------------------------------------------\n"); printf("T%d.%03d:Render Context Info(write ponter = %d)\n", delta_ms, delta_us, render_wp); print_cstatus(render[render_wp].ldw, render[render_wp].udw); printf("-----------------------------------------------\n"); } return 0; } static int current_video(uint32_t delta_ms, uint32_t delta_us) { uint32_t mmio_addr; video_wp = INREG(linear_mmio, 0x123a0) % 6; if (video_wp == last_video_wp) return 0; last_video_wp = video_wp; if (video_wp == 0) video_wp = 5; else video_wp--; mmio_addr = 0x12370; video[video_wp].ldw = INREG(linear_mmio, mmio_addr + video_wp*8); video[video_wp].udw = INREG(linear_mmio, mmio_addr + video_wp*8 + 4); if (video[video_wp].udw != 0) { printf("-----------------------------------------------\n"); printf("T%d.%03d:Video Context Info (write ponter = %d)\n", delta_ms, delta_us, video_wp); print_cstatus(video[video_wp].ldw, video[video_wp].udw); printf("-----------------------------------------------\n"); } return 0; } int process_cstatus(char *cmdhdr,unsigned int seconds) { uint64_t start = now_us(); uint64_t expected_end = start + 1000 * 1000 * seconds; if (is_gen7) { printf("Execlist is not supported on GEN7\n"); return 0; } printf("Sample Context Status for %d seconds....\n", seconds); printf("It is not accurate, just for rough view\n"); while (1) { uint64_t now = now_us(); int64_t test = now - expected_end; if (test > 0) break; uint64_t delta = now - start; uint32_t delta_ms = (uint32_t)(delta/1000); uint32_t delta_us = (uint32_t)(delta%1000); current_render(delta_ms, delta_us); current_video(delta_ms, delta_us); } return 0; } int process_msgread(char *cmdhdr,unsigned int port,unsigned int reg) { unsigned int value = 0; //value = MSG_READ32(port, reg) printf("read MSG port 0x%x, reg 0x%x, value=0x%08x\n",port, reg, value); print_bin_fmt(value,15); return 0; } int process_msgwrite(char *cmdhdr,unsigned int port, unsigned int reg, unsigned int new_value) { unsigned int value = 0; //value = MSG_READ32(port, reg); printf("Read MSG port 0x%x, reg 0x%x, value 0x%08x,try to write 0x%08x\n",port, reg, value, new_value); //MSG_WRITE32(port,reg,new_value); //value = MSG_READ32(port, reg); printf("After write, MSG port 0x%x, reg 0x%x, new value=0x%08x\n",port, reg, value); return 0; }