[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