[Pdbg] [PATCH 03/10] libpdbg/target: add a release operation
Nicholas Piggin
npiggin at gmail.com
Thu May 3 16:26:55 AEST 2018
This will be used to release special wakeup, other things later.
Signed-off-by: Nicholas Piggin <npiggin at gmail.com>
---
libpdbg/libpdbg.h | 11 +++++++++--
libpdbg/target.c | 42 ++++++++++++++++++++++++++++++++++++++++++
libpdbg/target.h | 6 ++++++
3 files changed, 57 insertions(+), 2 deletions(-)
diff --git a/libpdbg/libpdbg.h b/libpdbg/libpdbg.h
index f2b5de7..50baacc 100644
--- a/libpdbg/libpdbg.h
+++ b/libpdbg/libpdbg.h
@@ -13,7 +13,8 @@ struct pdbg_target *__pdbg_next_child_target(struct pdbg_target *parent, struct
/*
* Each target has a status associated with it. This is what each status means:
*
- * enabled - the target exists and has been probed.
+ * enabled - the target exists and has been probed, will be released by
+ * the release call.
*
* disabled - the target has not been probed and will never be probed. Target
* selection code may use this to prevent probing of certain
@@ -28,6 +29,10 @@ struct pdbg_target *__pdbg_next_child_target(struct pdbg_target *parent, struct
* it does not exist as it is required for correct operation.
* Selection code may set this.
*
+ * released - the target was enabled and has now been released.
+ * pending release - the target was released but some children still enabled
+ * so the ->release method hasn't been called yet.
+ *
* Initially these properties are read from the device tree. This allows the
* client application to select which targets it does not care about to avoid
* unneccessary probing by marking them disabled. If no status property exists
@@ -35,7 +40,8 @@ struct pdbg_target *__pdbg_next_child_target(struct pdbg_target *parent, struct
*/
enum pdbg_target_status {PDBG_TARGET_UNKNOWN = 0, PDBG_TARGET_ENABLED,
PDBG_TARGET_DISABLED, PDBG_TARGET_MUSTEXIST,
- PDBG_TARGET_NONEXISTENT};
+ PDBG_TARGET_NONEXISTENT, PDBG_TARGET_RELEASED,
+ PDBG_TARGET_PENDING_RELEASE };
#define pdbg_for_each_target(class, parent, target) \
for (target = __pdbg_next_target(class, parent, NULL); \
@@ -63,6 +69,7 @@ uint64_t pdbg_get_address(struct pdbg_target *target, uint64_t *size);
/* Misc. */
void pdbg_targets_init(void *fdt);
enum pdbg_target_status pdbg_target_probe(struct pdbg_target *target);
+void pdbg_target_release(struct pdbg_target *target);
enum pdbg_target_status pdbg_target_status(struct pdbg_target *target);
void pdbg_target_status_set(struct pdbg_target *target, enum pdbg_target_status status);
uint32_t pdbg_target_index(struct pdbg_target *target);
diff --git a/libpdbg/target.c b/libpdbg/target.c
index 704d7d5..bf5fb08 100644
--- a/libpdbg/target.c
+++ b/libpdbg/target.c
@@ -285,6 +285,9 @@ enum pdbg_target_status pdbg_target_probe(struct pdbg_target *target)
assert(target);
status = pdbg_target_status(target);
+ assert(status != PDBG_TARGET_RELEASED);
+ assert(status != PDBG_TARGET_PENDING_RELEASE);
+
if (status == PDBG_TARGET_DISABLED || status == PDBG_TARGET_NONEXISTENT
|| status == PDBG_TARGET_ENABLED)
/* We've already tried probing this target and by assumption
@@ -311,6 +314,8 @@ enum pdbg_target_status pdbg_target_probe(struct pdbg_target *target)
assert(pdbg_target_status(target) != PDBG_TARGET_MUSTEXIST);
return pdbg_target_status(target);
+ case PDBG_TARGET_RELEASED:
+ case PDBG_TARGET_PENDING_RELEASE:
case PDBG_TARGET_MUSTEXIST:
case PDBG_TARGET_UNKNOWN:
/* We must know by now if the parent exists or not */
@@ -334,6 +339,43 @@ enum pdbg_target_status pdbg_target_probe(struct pdbg_target *target)
return PDBG_TARGET_ENABLED;
}
+/*
+ * Walk back up, releasing.
+ */
+void pdbg_target_release(struct pdbg_target *target)
+{
+ struct pdbg_target *parent;
+ struct pdbg_target *child;
+
+ assert(target);
+
+ /* If it's not enabled, the parent wasn't enabled. */
+ if ((pdbg_target_status(target) != PDBG_TARGET_ENABLED) &&
+ (pdbg_target_status(target) != PDBG_TARGET_PENDING_RELEASE))
+ return;
+
+ target->status = PDBG_TARGET_PENDING_RELEASE;
+
+ pdbg_for_each_child_target(target, child) {
+ /* Not all children released yet, stop here. */
+ if (pdbg_target_status(child) == PDBG_TARGET_ENABLED)
+ return;
+ if (pdbg_target_status(child) == PDBG_TARGET_PENDING_RELEASE)
+ return;
+ }
+
+ /* At this point any parents must exist and have already been probed */
+ if (target->release)
+ target->release(target);
+ target->status = PDBG_TARGET_RELEASED;
+
+ parent = target->parent;
+ if (parent) {
+ /* Recurse up the tree to release parents */
+ pdbg_target_release(parent);
+ }
+}
+
bool pdbg_target_is_class(struct pdbg_target *target, const char *class)
{
if (!target || !target->class || !class)
diff --git a/libpdbg/target.h b/libpdbg/target.h
index eba26cb..a33e089 100644
--- a/libpdbg/target.h
+++ b/libpdbg/target.h
@@ -44,6 +44,7 @@ struct pdbg_target {
char *compatible;
char *class;
int (*probe)(struct pdbg_target *target);
+ void (*release)(struct pdbg_target *target);
int index;
enum pdbg_target_status status;
const char *dn_name;
@@ -64,9 +65,14 @@ struct pdbg_target_class *get_target_class(const char *name);
bool pdbg_target_is_class(struct pdbg_target *target, const char *class);
extern struct list_head empty_list;
+extern struct list_head target_classes;
+
#define for_each_class_target(class_name, target) \
list_for_each((find_target_class(class_name) ? &require_target_class(class_name)->targets : &empty_list), target, class_link)
+#define for_each_target_class(target_class) \
+ list_for_each(&target_classes, target_class, class_head_link)
+
struct hw_unit_info {
void *hw_unit;
size_t size;
--
2.17.0
More information about the Pdbg
mailing list