void find_ptimer_b12(int cnum) { uint8_t signals_ref_timer[0x100 * 8]; uint8_t signals_tmp[0x100 * 8]; struct signals_comparaison diffs; int i; uint32_t r_9210, r_9400; printf("<PTIMER_B12>\n"); r_9210 = nva_rd32(cnum, 0x9210); r_9400 = nva_rd32(cnum, 0x9400); /* stop the time */ nva_wr32(cnum, 0x9210, 0); nva_wr32(cnum, 0x9400, 0); poll_signals(cnum, signals_ref_timer); nva_wr32(cnum, 0x9400, 0x20000); poll_signals(cnum, signals_tmp); /* restore ptimer */ nva_wr32(cnum, 0x9400, r_9400); nva_wr32(cnum, 0x9210, r_9210); diffs = signals_compare(signals_ref_timer, signals_tmp); if (diffs.diff_count >= 1) { for (i = 0; i < diffs.diff_count; i++) { uint8_t set, signal; set = diffs.differences[i].set; signal = diffs.differences[i].signal; if (diffs.differences[i].set == 0) { if (diffs.differences[i].change == ZERO_TO_ONE) printf("PTIMER_B12: Set %u, signal 0x%.2x\n", set, signal); } else { printf("Unexpected difference: "); print_difference(diffs.differences[i]); } } } else printf("Not found.\n"); signals_comparaison_free(diffs); printf("</PTIMER_B12>\n\n"); }
void find_ctxCtlFlags(int cnum) { uint8_t signals_ref_ctx[0x100 * 8]; uint8_t signals_tmp[0x100 * 8]; struct signals_comparaison diffs; int bit, i; uint32_t r_400824 = nva_rd32(cnum, 0x400824); printf("<CTXCTL FLAGS>\n"); nva_mask(cnum, 0x400824, 0xf0000000, 0); poll_signals(cnum, signals_ref_ctx); for (bit = 28; bit < 32; bit++) { nva_mask(cnum, 0x400824, 0xf0000000, 1 << bit); poll_signals(cnum, signals_tmp); diffs = signals_compare(signals_ref_ctx, signals_tmp); if (diffs.diff_count >= 1) { for (i = 0; i < diffs.diff_count; i++) { uint8_t set, signal; set = diffs.differences[i].set; signal = diffs.differences[i].signal; if (diffs.differences[i].set == 1) { if (diffs.differences[i].change == ZERO_TO_ONE) printf("CTXCTL flag 0x%.2x: Set %u, signal 0x%.2x\n", bit, set, signal); } else { printf("Unexpected difference: "); print_difference(diffs.differences[i]); } } } else printf("Not found. Please re-run when the GPU is idle.\n"); signals_comparaison_free(diffs); } nva_wr32(cnum, 0x400824, r_400824); printf("</CTXCTL FLAGS>\n\n"); }
int main(int argc, char **argv) { int c, cnum = 0; if (nva_init()) { fprintf (stderr, "PCI init failure!\n"); return 1; } /* Arguments parsing */ while ((c = getopt (argc, argv, "c:")) != -1) switch (c) { case 'c': sscanf(optarg, "%d", &cnum); break; } if (cnum >= nva_cardsnum) { if (nva_cardsnum) fprintf (stderr, "No such card.\n"); else fprintf (stderr, "No cards found.\n"); return 1; } if (nva_cards[cnum].chipset < 0x10 || nva_cards[cnum].chipset >= 0xc0) { fprintf(stderr, "The chipset nv%x isn't currently supported\n", nva_cards[cnum].chipset); return 1; } /* Init */ nva_wr32(cnum, 0x200, 0xffffffff); printf("Chipset nv%x:\n\n", nva_cards[cnum].chipset); poll_signals(cnum, signals_ref); find_counter_noise(cnum); find_ptimer_b12(cnum); find_host_mem_read_write(cnum); find_mmio_read_write(cnum, 0x200, "MMIO"); find_mmio_read_write(cnum, 0x2210, "MMIO_PFIFO"); find_mmio_read_write(cnum, 0x610384, "MMIO_PDISPLAY"); find_mmio_read_write(cnum, 0x6666, "MMIO_INVALID"); find_pgraphIdle_and_interrupt(cnum); find_ctxCtlFlags(cnum); return 0; }
void poll_loop(void) { SIG_ENTITY *sig; fd_set perm,set; int fds,ret; FD_ZERO(&perm); FD_SET(kernel,&perm); fds = kernel+1; for (sig = entities; sig; sig = sig->next) { FD_SET(sig->signaling,&perm); if (fds <= sig->signaling) fds = sig->signaling+1; } gettimeofday(&now,NULL); while (!stop) { set = perm; poll_signals(); /* * Here we have a small race condition: if a signal is delivered after * poll_signals tests for it but before select sleeps, we miss that * signal. If it is sent again, we're of course likely to get it. This * isn't worth fixing, because those signals are only used for * debugging anyway. */ ret = select(fds,&set,NULL,NULL,next_timer()); if (ret < 0) { if (errno != EINTR) perror("select"); } else { diag(COMPONENT,DIAG_DEBUG,"----------"); gettimeofday(&now,NULL); if (FD_ISSET(kernel,&set)) recv_kernel(); for (sig = entities; sig; sig = sig->next) if (FD_ISSET(sig->signaling,&set)) recv_signaling(sig); expire_timers(); /* expire timers after handling messges to make sure we don't time out unnecessarily because of scheduling delays */ } } }
void find_pgraphIdle_and_interrupt(int cnum) { unsigned char signals_idle[0x100 * 8]; struct signals_comparaison diffs; int i; uint32_t r_400500, r_400808, r_40013c; printf("<PGRAPH_IDLE/INTERRUPT> /!\\ no drivers should be loaded!\n"); /* safety check: */ if (nva_rd32(cnum, 0x140) == 1) { printf("You shouldn't run this tool while a driver is running\n"); goto error; } /* reboot PGRAPH */ nva_mask(cnum, 0x200, 0x00201000, 0x00000000); nva_mask(cnum, 0x200, 0x00201000, 0x00201000); r_400500 = nva_rd32(cnum, 0x400500); r_400808 = nva_rd32(cnum, 0x400808); r_40013c = nva_rd32(cnum, 0x40013c); /* generate an illegal method IRQ * that will pull the PGRAP_IDLE signal down and the PGRAPH_INTERRUPT up * * neither nouveau or nvidia should be loaded as they would ack the interrupt * straight away. */ nva_wr32(cnum, 0x400500, 0x10001); nva_wr32(cnum, 0x400808, 0xa00000fc); nva_wr32(cnum, 0x40013c, 0xffffffff); poll_signals(cnum, signals_idle); diffs = signals_compare(signals_ref, signals_idle); if (diffs.diff_count >= 1) { for (i = 0; i < diffs.diff_count; i++) { uint8_t set, signal; set = diffs.differences[i].set; signal = diffs.differences[i].signal; if (diffs.differences[i].set == 1) { if (diffs.differences[i].change == ONE_TO_ZERO) printf("PGRAPH_IDLE: Set %u, signal 0x%.2x\n", set, signal); else if (diffs.differences[i].change == ZERO_TO_ONE) printf("PGRAPH_INTERRUPT: Set %u, signal 0x%.2x\n", set, signal); } else { printf("Unexpected difference: "); print_difference(diffs.differences[i]); } } signals_comparaison_free(diffs); } else printf("Not found. Please re-run when the GPU is idle.\n"); /* restore our mess */ nva_wr32(cnum, 0x400500, r_400500); nva_wr32(cnum, 0x400808, r_400808); nva_wr32(cnum, 0x40013c, r_40013c); /* ACK all PGRAPH's interrupts */ nva_wr32(cnum, 0x400100, 0xffffffff); error: printf("</PGRAPH_IDLE/INTERRUPT>\n\n"); }