riscv: Retry failed memory reads

This commit is contained in:
Megan Wachs 2017-03-22 17:51:46 -07:00
parent 98420e377a
commit c61b3efe9a
1 changed files with 72 additions and 62 deletions

View File

@ -1830,72 +1830,82 @@ static int read_memory(struct target *target, uint32_t address,
{ {
select_dmi(target); select_dmi(target);
abstract_write_register(target, S0, xlen(target), address); while (1) {
abstract_write_register(target, S0, xlen(target), address);
program_t *program = program_new(); program_t *program = program_new();
switch (size) { switch (size) {
case 1: case 1:
program_add32(program, lb(S1, S0, 0)); program_add32(program, lb(S1, S0, 0));
break; break;
case 2: case 2:
program_add32(program, lh(S1, S0, 0)); program_add32(program, lh(S1, S0, 0));
break; break;
case 4: case 4:
program_add32(program, lw(S1, S0, 0)); program_add32(program, lw(S1, S0, 0));
break; break;
default: default:
LOG_ERROR("Unsupported size: %d", size); LOG_ERROR("Unsupported size: %d", size);
return ERROR_FAIL; return ERROR_FAIL;
} }
program_add32(program, addi(S0, S0, size)); program_add32(program, addi(S0, S0, size));
program_add32(program, ebreak()); program_add32(program, ebreak());
write_program(target, program); write_program(target, program);
program_delete(program); program_delete(program);
if (execute_abstract_command(target, if (execute_abstract_command(target,
AC_ACCESS_REGISTER_PREEXEC | AC_ACCESS_REGISTER_PREEXEC |
abstract_register_size(xlen(target)) | reg_number_to_no(S1)) != ERROR_OK) { abstract_register_size(xlen(target)) | reg_number_to_no(S1)) != ERROR_OK) {
return ERROR_FAIL; return ERROR_FAIL;
} }
dmi_write(target, DMI_ABSTRACTCS, DMI_ABSTRACTCS_CMDERR); dmi_write(target, DMI_ABSTRACTCS, DMI_ABSTRACTCS_CMDERR);
dmi_write(target, DMI_ABSTRACTAUTO, 0x1 << DMI_ABSTRACTAUTO_AUTOEXECDATA_OFFSET); dmi_write(target, DMI_ABSTRACTAUTO, 0x1 << DMI_ABSTRACTAUTO_AUTOEXECDATA_OFFSET);
uint32_t abstractcs; uint32_t abstractcs;
for (uint32_t i = 0; i < count; i++) { for (uint32_t i = 0; i < count; i++) {
uint32_t value = dmi_read(target, DMI_DATA0); uint32_t value = dmi_read(target, DMI_DATA0);
switch (size) { switch (size) {
case 1: case 1:
buffer[i] = value; buffer[i] = value;
break; break;
case 2: case 2:
buffer[2*i] = value; buffer[2*i] = value;
buffer[2*i+1] = value >> 8; buffer[2*i+1] = value >> 8;
break; break;
case 4: case 4:
buffer[4*i] = value; buffer[4*i] = value;
buffer[4*i+1] = value >> 8; buffer[4*i+1] = value >> 8;
buffer[4*i+2] = value >> 16; buffer[4*i+2] = value >> 16;
buffer[4*i+3] = value >> 24; buffer[4*i+3] = value >> 24;
break; break;
default: default:
return ERROR_FAIL; return ERROR_FAIL;
} }
// The above dmi_read started an abstract command. If we just // The above dmi_read started an abstract command. If we just
// immediately read here, we'll probably get a busy error. Wait for idle first, // immediately read here, we'll probably get a busy error. Wait for idle first,
// or otherwise take ac_command_busy into account (this defeats the purpose // or otherwise take ac_command_busy into account (this defeats the purpose
// of autoexec, this whole code needs optimization). // of autoexec, this whole code needs optimization).
if (wait_for_idle(target, &abstractcs) != ERROR_OK) { if (wait_for_idle(target, &abstractcs) != ERROR_OK) {
return ERROR_FAIL; return ERROR_FAIL;
} }
}
dmi_write(target, DMI_ABSTRACTAUTO, 0);
dmi_write(target, DMI_ABSTRACTCS, DMI_ABSTRACTCS_CMDERR);
abstractcs = dmi_read(target, DMI_ABSTRACTCS);
unsigned cmderr = get_field(abstractcs, DMI_ABSTRACTCS_CMDERR);
if (cmderr == CMDERR_BUSY) {
dmi_write(target, DMI_ABSTRACTCS, 0);
increase_ac_busy_delay(target);
} else if (cmderr) {
LOG_ERROR("cmderr=%d", get_field(abstractcs, DMI_ABSTRACTCS_CMDERR));
return ERROR_FAIL;
} else {
return ERROR_OK;
}
} }
dmi_write(target, DMI_ABSTRACTCS, DMI_ABSTRACTCS_CMDERR); // Should not get here.
abstractcs = dmi_read(target, DMI_ABSTRACTCS); assert(0);
if (get_field(abstractcs, DMI_ABSTRACTCS_CMDERR)) { return ERROR_OK;
// TODO: retry with more delay?
return ERROR_FAIL;
}
return ERROR_OK;
} }
/** /**