adiv6: use struct adiv5_ap->ap_num to contain the AP base address

ADIv5 DAP can only have 256 AP, while ADIv6 can provide till
2**40 (1,099,511,627,776) AP per DAP.

Reuse the field ap_num in struct adiv5_ap, currently used on ADIv5
to hold the ADIv5 AP number (apsel), to contain the ADIv6 AP base
address.

Convert struct adiv5_ap->ap_num to 64 bit and initialize it to
DP_APSEL_INVALID for unused AP.
Restrict dap_find_get_ap() to ADIv5 only. To be enhanced.
On ADIv6, let dap_get_ap() return an already allocated AP, or
allocate and return an unused AP.
Add function is_ap_num_valid() and use it.

Change-Id: Ib2fe8c7ec0d08393cd91c29fdac5d632dfc1e438
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: https://review.openocd.org/c/openocd/+/6461
Reviewed-by: Daniel Goehring <dgoehrin@os.amperecomputing.com>
Tested-by: jenkins
This commit is contained in:
Antonio Borneo
2021-08-14 23:56:12 +02:00
parent 72fb88613f
commit 3f4bc6ce7f
9 changed files with 156 additions and 73 deletions

View File

@@ -966,16 +966,45 @@ static const char *ap_type_to_description(enum ap_type type)
return "Unknown";
}
bool is_ap_num_valid(struct adiv5_dap *dap, uint64_t ap_num)
{
if (!dap)
return false;
/* no autodetection, by now, so uninitialized is equivalent to ADIv5 for
* backward compatibility */
if (!is_adiv6(dap)) {
if (ap_num > DP_APSEL_MAX)
return false;
return true;
}
if (is_adiv6(dap)) {
if (ap_num & 0x0fffULL)
return false;
if (dap->asize != 0)
if (ap_num & ((~0ULL) << dap->asize))
return false;
return true;
}
return false;
}
/*
* This function checks the ID for each access port to find the requested Access Port type
* It also calls dap_get_ap() to increment the AP refcount
*/
int dap_find_get_ap(struct adiv5_dap *dap, enum ap_type type_to_find, struct adiv5_ap **ap_out)
{
int ap_num;
if (is_adiv6(dap)) {
/* TODO: scan the ROM table and detect the AP available */
LOG_DEBUG("On ADIv6 we cannot scan all the possible AP");
return ERROR_FAIL;
}
/* Maximum AP number is 255 since the SELECT register is 8 bits */
for (ap_num = 0; ap_num <= DP_APSEL_MAX; ap_num++) {
for (unsigned int ap_num = 0; ap_num <= DP_APSEL_MAX; ap_num++) {
struct adiv5_ap *ap = dap_get_ap(dap, ap_num);
if (!ap)
continue;
@@ -1014,33 +1043,55 @@ static inline bool is_ap_in_use(struct adiv5_ap *ap)
return ap->refcount > 0 || ap->config_ap_never_release;
}
static struct adiv5_ap *_dap_get_ap(struct adiv5_dap *dap, unsigned int ap_num)
static struct adiv5_ap *_dap_get_ap(struct adiv5_dap *dap, uint64_t ap_num)
{
if (ap_num > DP_APSEL_MAX) {
LOG_ERROR("Invalid AP#%u", ap_num);
if (!is_ap_num_valid(dap, ap_num)) {
LOG_ERROR("Invalid AP#0x%" PRIx64, ap_num);
return NULL;
}
if (is_adiv6(dap)) {
for (unsigned int i = 0; i <= DP_APSEL_MAX; i++) {
struct adiv5_ap *ap = &dap->ap[i];
if (is_ap_in_use(ap) && ap->ap_num == ap_num) {
++ap->refcount;
return ap;
}
}
for (unsigned int i = 0; i <= DP_APSEL_MAX; i++) {
struct adiv5_ap *ap = &dap->ap[i];
if (!is_ap_in_use(ap)) {
ap->ap_num = ap_num;
++ap->refcount;
return ap;
}
}
LOG_ERROR("No more AP available!");
return NULL;
}
/* ADIv5 */
struct adiv5_ap *ap = &dap->ap[ap_num];
ap->ap_num = ap_num;
++ap->refcount;
return ap;
}
/* Return AP with specified ap_num. Increment AP refcount */
struct adiv5_ap *dap_get_ap(struct adiv5_dap *dap, unsigned int ap_num)
struct adiv5_ap *dap_get_ap(struct adiv5_dap *dap, uint64_t ap_num)
{
struct adiv5_ap *ap = _dap_get_ap(dap, ap_num);
if (ap)
LOG_DEBUG("refcount AP#%u get %u", ap_num, ap->refcount);
LOG_DEBUG("refcount AP#0x%" PRIx64 " get %u", ap_num, ap->refcount);
return ap;
}
/* Return AP with specified ap_num. Increment AP refcount and keep it non-zero */
struct adiv5_ap *dap_get_config_ap(struct adiv5_dap *dap, unsigned int ap_num)
struct adiv5_ap *dap_get_config_ap(struct adiv5_dap *dap, uint64_t ap_num)
{
struct adiv5_ap *ap = _dap_get_ap(dap, ap_num);
if (ap) {
ap->config_ap_never_release = true;
LOG_DEBUG("refcount AP#%u get_config %u", ap_num, ap->refcount);
LOG_DEBUG("refcount AP#0x%" PRIx64 " get_config %u", ap_num, ap->refcount);
}
return ap;
}
@@ -1049,15 +1100,16 @@ struct adiv5_ap *dap_get_config_ap(struct adiv5_dap *dap, unsigned int ap_num)
int dap_put_ap(struct adiv5_ap *ap)
{
if (ap->refcount == 0) {
LOG_ERROR("BUG: refcount AP#%" PRIu8 " put underflow", ap->ap_num);
LOG_ERROR("BUG: refcount AP#0x%" PRIx64 " put underflow", ap->ap_num);
return ERROR_FAIL;
}
--ap->refcount;
LOG_DEBUG("refcount AP#%" PRIu8 " put %u", ap->ap_num, ap->refcount);
LOG_DEBUG("refcount AP#0x%" PRIx64 " put %u", ap->ap_num, ap->refcount);
if (!is_ap_in_use(ap)) {
/* defaults from dap_instance_init() */
ap->ap_num = DP_APSEL_INVALID;
ap->memaccess_tck = 255;
ap->tar_autoincr_block = (1 << 10);
ap->csw_default = CSW_AHB_DEFAULT;
@@ -1756,7 +1808,7 @@ static int dap_info_mem_ap_header(int retval, struct adiv5_ap *ap,
command_print(cmd, "AP ID register 0x%8.8" PRIx32, apid);
if (apid == 0) {
command_print(cmd, "No AP found at this ap 0x%x", ap->ap_num);
command_print(cmd, "No AP found at this AP#0x%" PRIx64, ap->ap_num);
return ERROR_FAIL;
}
@@ -2000,7 +2052,7 @@ static const struct jim_nvp nvp_config_opts[] = {
};
static int adiv5_jim_spot_configure(struct jim_getopt_info *goi,
struct adiv5_dap **dap_p, int *ap_num_p, uint32_t *base_p)
struct adiv5_dap **dap_p, uint64_t *ap_num_p, uint32_t *base_p)
{
assert(dap_p && ap_num_p);
@@ -2055,11 +2107,13 @@ static int adiv5_jim_spot_configure(struct jim_getopt_info *goi,
case CFG_AP_NUM:
if (goi->isconfigure) {
/* jim_wide is a signed 64 bits int, ap_num is unsigned with max 52 bits */
jim_wide ap_num;
e = jim_getopt_wide(goi, &ap_num);
if (e != JIM_OK)
return e;
if (ap_num < 0 || ap_num > DP_APSEL_MAX) {
/* we still don't know dap->adi_version */
if (ap_num < 0 || (ap_num > DP_APSEL_MAX && (ap_num & 0xfff))) {
Jim_SetResultString(goi->interp, "Invalid AP number!", -1);
return JIM_ERR;
}
@@ -2164,15 +2218,15 @@ int adiv5_mem_ap_spot_init(struct adiv5_mem_ap_spot *p)
COMMAND_HANDLER(handle_dap_info_command)
{
struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA);
uint32_t apsel;
uint64_t apsel;
switch (CMD_ARGC) {
case 0:
apsel = dap->apsel;
break;
case 1:
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], apsel);
if (apsel > DP_APSEL_MAX) {
COMMAND_PARSE_NUMBER(u64, CMD_ARGV[0], apsel);
if (!is_ap_num_valid(dap, apsel)) {
command_print(CMD, "Invalid AP number");
return ERROR_COMMAND_ARGUMENT_INVALID;
}
@@ -2195,7 +2249,8 @@ COMMAND_HANDLER(handle_dap_info_command)
COMMAND_HANDLER(dap_baseaddr_command)
{
struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA);
uint32_t apsel, baseaddr_lower, baseaddr_upper;
uint64_t apsel;
uint32_t baseaddr_lower, baseaddr_upper;
struct adiv5_ap *ap;
target_addr_t baseaddr;
int retval;
@@ -2207,9 +2262,8 @@ COMMAND_HANDLER(dap_baseaddr_command)
apsel = dap->apsel;
break;
case 1:
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], apsel);
/* AP address is in bits 31:24 of DP_SELECT */
if (apsel > DP_APSEL_MAX) {
COMMAND_PARSE_NUMBER(u64, CMD_ARGV[0], apsel);
if (!is_ap_num_valid(dap, apsel)) {
command_print(CMD, "Invalid AP number");
return ERROR_COMMAND_ARGUMENT_INVALID;
}
@@ -2294,16 +2348,15 @@ COMMAND_HANDLER(dap_memaccess_command)
COMMAND_HANDLER(dap_apsel_command)
{
struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA);
uint32_t apsel;
uint64_t apsel;
switch (CMD_ARGC) {
case 0:
command_print(CMD, "%" PRIu32, dap->apsel);
command_print(CMD, "0x%" PRIx64, dap->apsel);
return ERROR_OK;
case 1:
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], apsel);
/* AP address is in bits 31:24 of DP_SELECT */
if (apsel > DP_APSEL_MAX) {
COMMAND_PARSE_NUMBER(u64, CMD_ARGV[0], apsel);
if (!is_ap_num_valid(dap, apsel)) {
command_print(CMD, "Invalid AP number");
return ERROR_COMMAND_ARGUMENT_INVALID;
}
@@ -2329,7 +2382,7 @@ COMMAND_HANDLER(dap_apcsw_command)
command_print(CMD, "Cannot get AP");
return ERROR_FAIL;
}
command_print(CMD, "ap %" PRIu32 " selected, csw 0x%8.8" PRIx32,
command_print(CMD, "AP#0x%" PRIx64 " selected, csw 0x%8.8" PRIx32,
dap->apsel, ap->csw_default);
break;
case 1:
@@ -2376,7 +2429,8 @@ COMMAND_HANDLER(dap_apcsw_command)
COMMAND_HANDLER(dap_apid_command)
{
struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA);
uint32_t apsel, apid;
uint64_t apsel;
uint32_t apid;
int retval;
switch (CMD_ARGC) {
@@ -2384,9 +2438,8 @@ COMMAND_HANDLER(dap_apid_command)
apsel = dap->apsel;
break;
case 1:
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], apsel);
/* AP address is in bits 31:24 of DP_SELECT */
if (apsel > DP_APSEL_MAX) {
COMMAND_PARSE_NUMBER(u64, CMD_ARGV[0], apsel);
if (!is_ap_num_valid(dap, apsel)) {
command_print(CMD, "Invalid AP number");
return ERROR_COMMAND_ARGUMENT_INVALID;
}
@@ -2418,23 +2471,30 @@ COMMAND_HANDLER(dap_apid_command)
COMMAND_HANDLER(dap_apreg_command)
{
struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA);
uint32_t apsel, reg, value;
uint64_t apsel;
uint32_t reg, value;
int retval;
if (CMD_ARGC < 2 || CMD_ARGC > 3)
return ERROR_COMMAND_SYNTAX_ERROR;
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], apsel);
/* AP address is in bits 31:24 of DP_SELECT */
if (apsel > DP_APSEL_MAX) {
COMMAND_PARSE_NUMBER(u64, CMD_ARGV[0], apsel);
if (!is_ap_num_valid(dap, apsel)) {
command_print(CMD, "Invalid AP number");
return ERROR_COMMAND_ARGUMENT_INVALID;
}
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], reg);
if (reg >= 256 || (reg & 3)) {
command_print(CMD, "Invalid reg value (should be less than 256 and 4 bytes aligned)");
return ERROR_COMMAND_ARGUMENT_INVALID;
if (is_adiv6(dap)) {
if (reg >= 4096 || (reg & 3)) {
command_print(CMD, "Invalid reg value (should be less than 4096 and 4 bytes aligned)");
return ERROR_COMMAND_ARGUMENT_INVALID;
}
} else { /* ADI version 5 */
if (reg >= 256 || (reg & 3)) {
command_print(CMD, "Invalid reg value (should be less than 256 and 4 bytes aligned)");
return ERROR_COMMAND_ARGUMENT_INVALID;
}
}
struct adiv5_ap *ap = dap_get_ap(dap, apsel);