arm_adi_v5: add ap refcount and add get/put around ap use

While an ADIv5 DAP can only have 256 AP, ADIv6 can provide till
2**40 (1,099,511,627,776) AP per DAP.
The actual trivial code implementation for ADIv5 (that uses an
array of 256 ap in the struct adiv5_dap) cannot be extended as-is
to handle ADIv6.

The simple array of 256 AP can be reused as a dynamic storage for
ADIv6 ap:
- the ADIv5 AP number is replaced by the ADIv6 base address;
- the index of the array (equal to ADIv5 AP number) has no link to
  any ADIv6 property;
- the ADIv6 base_address has to be searched in the array of AP.

The 256 elements in the AP array should be enough for any device
available today. In future it can be easily increased, if needed.

To efficiently use the 256 elements in the AP array, the code
should associate one element of the array to an ADIv6 AP (through
the AP base address), then cancel the association when the AP is
not anymore needed. This is important to avoid saturating the AP
array while exploring the device through 'dap apreg' commands.

Add a reference counter in the struct adiv5_ap to track how many
times the struct has been associated with the same base address.
Introduce the function dap_get_ap() to associate and return the
struct, and dap_put_ap() to release the struct. For the moment the
code covers ADIv5 only, so the association is through the index.
Use the two functions above and dap_find_get_ap() throughout the
code.
Check the return value of dap_get_ap(). It is always not NULL in
the current ADIv5-only implementation, but can be NULL for ADIv6
when there are no more available AP in the array.
Instrument dap_queue_ap_read() and dap_queue_ap_write() to log an
error message if the AP has reference counter zero, meaning that
the AP has not been 'get' yet. This helps identifying AP used
without get/put, e.g. code missed by this patch, or merged later.
Instrument dap_cleanup_all() to log an error message if an AP has
reference counter not zero at openocd exit, meaning that the AP
has not been 'put' yet.

Change-Id: I98316eb42b9f3d9c9bbbb6c73b1091b53f629092
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: https://review.openocd.org/c/openocd/+/6455
Reviewed-by: Daniel Goehring <dgoehrin@os.amperecomputing.com>
Tested-by: jenkins
This commit is contained in:
Antonio Borneo
2021-08-04 23:07:57 +02:00
parent 480d4e1772
commit 35a503b08d
12 changed files with 330 additions and 69 deletions

View File

@@ -90,6 +90,7 @@ struct arm_tpiu_swo_event_action {
struct arm_tpiu_swo_object {
struct list_head lh;
struct adiv5_mem_ap_spot spot;
struct adiv5_ap *ap;
char *name;
struct arm_tpiu_swo_event_action *event_action;
/* record enable before init */
@@ -233,6 +234,9 @@ int arm_tpiu_swo_cleanup_all(void)
ea = next;
}
if (obj->ap)
dap_put_ap(obj->ap);
free(obj->name);
free(obj->out_filename);
free(obj);
@@ -596,7 +600,6 @@ static int jim_arm_tpiu_swo_enable(Jim_Interp *interp, int argc, Jim_Obj *const
struct command *c = jim_to_command(interp);
struct arm_tpiu_swo_object *obj = c->jim_handler_data;
struct command_context *cmd_ctx = current_command_context(interp);
struct adiv5_ap *tpiu_ap = dap_ap(obj->spot.dap, obj->spot.ap_num);
uint32_t value;
int retval;
@@ -644,7 +647,6 @@ static int jim_arm_tpiu_swo_enable(Jim_Interp *interp, int argc, Jim_Obj *const
struct cortex_m_common *cm = target_to_cm(target);
obj->recheck_ap_cur_target = false;
obj->spot.ap_num = cm->armv7m.debug_ap->ap_num;
tpiu_ap = dap_ap(obj->spot.dap, obj->spot.ap_num);
if (obj->spot.ap_num == 0)
LOG_INFO(MSG "Confirmed TPIU %s is on AP 0", obj->name);
else
@@ -655,10 +657,18 @@ static int jim_arm_tpiu_swo_enable(Jim_Interp *interp, int argc, Jim_Obj *const
}
/* END_DEPRECATED_TPIU */
if (!obj->ap) {
obj->ap = dap_get_ap(obj->spot.dap, obj->spot.ap_num);
if (!obj->ap) {
LOG_ERROR("Cannot get AP");
return JIM_ERR;
}
}
/* trigger the event before any attempt to R/W in the TPIU/SWO */
arm_tpiu_swo_handle_event(obj, TPIU_SWO_EVENT_PRE_ENABLE);
retval = wrap_read_u32(target, tpiu_ap, obj->spot.base + TPIU_DEVID_OFFSET, &value);
retval = wrap_read_u32(target, obj->ap, obj->spot.base + TPIU_DEVID_OFFSET, &value);
if (retval != ERROR_OK) {
LOG_ERROR("Unable to read %s", obj->name);
return JIM_ERR;
@@ -684,7 +694,7 @@ static int jim_arm_tpiu_swo_enable(Jim_Interp *interp, int argc, Jim_Obj *const
}
if (obj->pin_protocol == TPIU_SPPR_PROTOCOL_SYNC) {
retval = wrap_read_u32(target, tpiu_ap, obj->spot.base + TPIU_SSPSR_OFFSET, &value);
retval = wrap_read_u32(target, obj->ap, obj->spot.base + TPIU_SSPSR_OFFSET, &value);
if (retval != ERROR_OK) {
LOG_ERROR("Cannot read TPIU register SSPSR");
return JIM_ERR;
@@ -759,26 +769,26 @@ static int jim_arm_tpiu_swo_enable(Jim_Interp *interp, int argc, Jim_Obj *const
obj->swo_pin_freq = swo_pin_freq;
}
retval = wrap_write_u32(target, tpiu_ap, obj->spot.base + TPIU_CSPSR_OFFSET, BIT(obj->port_width - 1));
retval = wrap_write_u32(target, obj->ap, obj->spot.base + TPIU_CSPSR_OFFSET, BIT(obj->port_width - 1));
if (retval != ERROR_OK)
goto error_exit;
retval = wrap_write_u32(target, tpiu_ap, obj->spot.base + TPIU_ACPR_OFFSET, prescaler - 1);
retval = wrap_write_u32(target, obj->ap, obj->spot.base + TPIU_ACPR_OFFSET, prescaler - 1);
if (retval != ERROR_OK)
goto error_exit;
retval = wrap_write_u32(target, tpiu_ap, obj->spot.base + TPIU_SPPR_OFFSET, obj->pin_protocol);
retval = wrap_write_u32(target, obj->ap, obj->spot.base + TPIU_SPPR_OFFSET, obj->pin_protocol);
if (retval != ERROR_OK)
goto error_exit;
retval = wrap_read_u32(target, tpiu_ap, obj->spot.base + TPIU_FFCR_OFFSET, &value);
retval = wrap_read_u32(target, obj->ap, obj->spot.base + TPIU_FFCR_OFFSET, &value);
if (retval != ERROR_OK)
goto error_exit;
if (obj->en_formatter)
value |= BIT(1);
else
value &= ~BIT(1);
retval = wrap_write_u32(target, tpiu_ap, obj->spot.base + TPIU_FFCR_OFFSET, value);
retval = wrap_write_u32(target, obj->ap, obj->spot.base + TPIU_FFCR_OFFSET, value);
if (retval != ERROR_OK)
goto error_exit;