From patchwork Thu Mar 28 04:38:51 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andre Marin X-Patchwork-Id: 1067761 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 44VC7Z3R2Pz9sQx for ; Thu, 28 Mar 2019 15:48:58 +1100 (AEDT) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=alexamarin.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=alexamarin-com.20150623.gappssmtp.com header.i=@alexamarin-com.20150623.gappssmtp.com header.b="Oj+iwxlx"; dkim-atps=neutral Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 44VC7Y6pWGzDqQ6 for ; Thu, 28 Mar 2019 15:48:57 +1100 (AEDT) X-Original-To: pdbg@lists.ozlabs.org Delivered-To: pdbg@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; spf=none (mailfrom) smtp.mailfrom=alexamarin.com (client-ip=2607:f8b0:4864:20::841; helo=mail-qt1-x841.google.com; envelope-from=andre@alexamarin.com; receiver=) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=alexamarin.com Authentication-Results: lists.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=alexamarin-com.20150623.gappssmtp.com header.i=@alexamarin-com.20150623.gappssmtp.com header.b="Oj+iwxlx"; dkim-atps=neutral Received: from mail-qt1-x841.google.com (mail-qt1-x841.google.com [IPv6:2607:f8b0:4864:20::841]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 44VByB0f7dzDqLj for ; Thu, 28 Mar 2019 15:40:49 +1100 (AEDT) Received: by mail-qt1-x841.google.com with SMTP id h39so21666837qte.2 for ; Wed, 27 Mar 2019 21:40:49 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=alexamarin-com.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=+6ohBEcpP/XwLNgV7qb8GWxKKvFwgy1Aq1E0uPcOioU=; b=Oj+iwxlxZqvpoRE2bh3HnSDYIz33vxSUYK5sqfyncRkpiDq59Eq5pTp8cfFuIO+NzJ 1NEOBGgVBbvOCboNyXTT++oPBRj8r8CM9xeIseS8GUFUOHadhZkRMiG5ue3Vwl5/F6d1 bv7SSvxk/5E8l/LMhKjMq/CwaPTkgG3JoFgNEPZEfpofIgKijd8goA6xq0HjEE+F7Caz JDmy3fSvU3KHdjkQQ9EUzC8lDFqmuI5Kle6ZzZ6vlueh9ABZvMWq8aS4VPtA2fOo6NOm 8Jk9h6M2qPuL1ag9h4hxhoXuWUgsRIJrMcsYZmT6rrGAs43X6XPRYlV11wL4JdXCacVR 0+Vw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=+6ohBEcpP/XwLNgV7qb8GWxKKvFwgy1Aq1E0uPcOioU=; b=SYGzoKsgA+oHVqURTZF8IHUzJgYOJh9vqqUHteXQ/eEx1o7yzWThN3oSCHAMxJ+6yc xQKWvapMVB7KnB37+W4MbxViq/K+kSiWbCymNaeMnnu5fG9pGDxXXlwIR1qN95ZnG3x+ A+Y3OnTKFp3hGrcBHOFGLxAHP+Q/WqjHDQ/6r36vw86mRq8GY+uQhV5KqxTZxgkOVIjm L8WJ4UNw5ehWhALFYoXXgR/QR1+bMyzJReH/+pg/us7r4OfQF+7gWSKuWoj9au65KQJH CSFUvGQvVz21sGmeOj59KI0B5JA+ogY2Zt9fnvFZ+NX+Jm7oersU4fkik+LJ64aR2GRW 7mjQ== X-Gm-Message-State: APjAAAWrDY+/8zonGqsSSB8ameo27/CyDzJFEmKndgd3CKTSGhJzSdCu 1YsFTYeaZeQl/2D4GFFhjZK9phBpis2yGg== X-Google-Smtp-Source: APXvYqzM7NGiU/sbKRd+lcXNrVikh2fooUTD4514wDyos2hQvFzyfpxWn5261FsLUC+xlQ6g/w1G2g== X-Received: by 2002:ac8:f6e:: with SMTP id l43mr34386413qtk.322.1553748046621; Wed, 27 Mar 2019 21:40:46 -0700 (PDT) Received: from bml86.aus.stglabs.ibm.com ([32.97.110.52]) by smtp.gmail.com with ESMTPSA id q51sm16629951qte.29.2019.03.27.21.40.44 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 27 Mar 2019 21:40:45 -0700 (PDT) From: Andre Marin To: pdbg@lists.ozlabs.org Date: Wed, 27 Mar 2019 23:38:51 -0500 Message-Id: <20190328043851.5831-2-andre@alexamarin.com> X-Mailer: git-send-email 2.14.1 In-Reply-To: <20190328043851.5831-1-andre@alexamarin.com> References: <20190328043851.5831-1-andre@alexamarin.com> X-Mailman-Approved-At: Thu, 28 Mar 2019 15:48:49 +1100 Subject: [Pdbg] [PATCH 1/1] Adding initial doxgyen to several files in libpdbg X-BeenThere: pdbg@lists.ozlabs.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "mailing list for https://github.com/open-power/pdbg development" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Andre Marin MIME-Version: 1.0 Errors-To: pdbg-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Pdbg" From: Andre Marin --- libfdt/fdt.h | 9 +- libpdbg/device.c | 29 +++++- libpdbg/libpdbg.c | 97 ++++++++++++++++--- libpdbg/libpdbg.h | 277 ++++++++++++++++++++++++++++++++++++++++++++++++++---- libpdbg/target.c | 171 ++++++++++++++++++++++++++++++--- libpdbg/target.h | 238 ++++++++++++++++++++++++++++++++++++++++++++-- 6 files changed, 766 insertions(+), 55 deletions(-) diff --git a/libfdt/fdt.h b/libfdt/fdt.h index 526aedb..a8cc756 100644 --- a/libfdt/fdt.h +++ b/libfdt/fdt.h @@ -54,7 +54,10 @@ #ifndef __ASSEMBLY__ +/* The layout of the header for the devicetree */ struct fdt_header { + /* header fields are stored in big-endian format */ + fdt32_t magic; /* magic word FDT_MAGIC */ fdt32_t totalsize; /* total size of DT block */ fdt32_t off_dt_struct; /* offset to structure */ @@ -73,9 +76,11 @@ struct fdt_header { fdt32_t size_dt_struct; /* size of the structure block */ }; +/* memory reservation block : + not used for general memory allocation*/ struct fdt_reserve_entry { - fdt64_t address; - fdt64_t size; + fdt64_t address; /* physical address*/ + fdt64_t size; /* size in bytes*/ }; struct fdt_node_header { diff --git a/libpdbg/device.c b/libpdbg/device.c index 3dc301f..c395e4c 100644 --- a/libpdbg/device.c +++ b/libpdbg/device.c @@ -392,6 +392,13 @@ void pdbg_target_set_property(struct pdbg_target *target, const char *name, cons } } +/** + * @brief Get the given property and return the size + * @param[in] target the pdbg_target + * @param[in] name the given class name + * @param[out] size the property size + * @return NULL + */ void *pdbg_target_property(struct pdbg_target *target, const char *name, size_t *size) { struct dt_property *p; @@ -465,6 +472,12 @@ static const struct dt_property *dt_require_property(const struct pdbg_target *n return p; } +/** + * @brief Check to see if a given compatible matches that of a pdbg_target + * @param[in] target the pdbg_target + * @param[in] compatible the compatible string we want to match against + * @return bool true if pdbg_target is found given compatible + */ bool pdbg_target_compatible(struct pdbg_target *target, const char *compatible) { char *c, *end; @@ -620,7 +633,13 @@ static u32 dt_n_size_cells(const struct pdbg_target *node) return dt_prop_get_u32_def(node->parent, "#size-cells", 1); } -uint64_t pdbg_target_address(struct pdbg_target *target, uint64_t *out_size) +/** + * @brief Get the address for a pdbg_target + * @param[in] target the pdbg_target + * @param[out] val pointer to return value, modified only if no error. + * @return int 0 iff successful, otherwise -1 + */ +uint64_t pdbg_target_address(struct pdbg_target *target, uint64_t *size) { const struct dt_property *p; u32 na = dt_n_address_cells(target); @@ -630,8 +649,8 @@ uint64_t pdbg_target_address(struct pdbg_target *target, uint64_t *out_size) p = dt_require_property(target, "reg", -1); n = (na + ns) * sizeof(u32); assert(n <= p->len); - if (out_size) - *out_size = dt_get_number(p->prop + na * sizeof(u32), ns); + if (size) + *size = dt_get_number(p->prop + na * sizeof(u32), ns); return dt_get_number(p->prop, na); } @@ -654,6 +673,10 @@ struct pdbg_target *pdbg_target_from_path(struct pdbg_target *target, const char return dt_find_by_path(target, path); } +/** + * @brief Gets the head pdbg_target (root node) + * @return pdbg_target the root target + */ struct pdbg_target *pdbg_target_root(void) { return pdbg_dt_root; diff --git a/libpdbg/libpdbg.c b/libpdbg/libpdbg.c index c549497..aeb8839 100644 --- a/libpdbg/libpdbg.c +++ b/libpdbg/libpdbg.c @@ -6,6 +6,13 @@ static pdbg_progress_tick_t progress_tick; +/** + * @brief Find the next pdbg_target* given a class + * @param[in] class the class of interest + * @param[in] parent the head pdbg_target + * @param[in] last the last pdbg_target in the class + * @return the next pdbg_target* iff successful, otherwise NULL + */ struct pdbg_target *__pdbg_next_target(const char *class, struct pdbg_target *parent, struct pdbg_target *last) { struct pdbg_target *next, *tmp; @@ -43,6 +50,12 @@ retry: } } +/** + * @brief Find the next child pdbg_target* given a parent target + * @param[in] parent the head pdbg_target + * @param[in] last the last pdbg_target in the class + * @return the next pdbg_target* iff successful, otherwise NULL + */ struct pdbg_target *__pdbg_next_child_target(struct pdbg_target *parent, struct pdbg_target *last) { if (!parent || list_empty(&parent->children)) @@ -57,11 +70,22 @@ struct pdbg_target *__pdbg_next_child_target(struct pdbg_target *parent, struct return list_entry(last->list.next, struct pdbg_target, list); } +/** + * @brief Get the pdbg_target status + * @param[in] target the pdbg_target + * @return pdbg_target_status the next pdbg_target status + */ enum pdbg_target_status pdbg_target_status(struct pdbg_target *target) { return target->status; } +/** + * @brief Set the pdbg_target status + * @param[in] target pdbg_target + * @param[in] status the status to set + * @return void + */ void pdbg_target_status_set(struct pdbg_target *target, enum pdbg_target_status status) { /* It's a programming error for user code to attempt anything else so @@ -71,7 +95,11 @@ void pdbg_target_status_set(struct pdbg_target *target, enum pdbg_target_status target->status = status; } -/* Searches up the tree and returns the first valid index found */ +/** + * @brief Searches up the tree and returns the first valid index found + * @param[in] target the pdbg_target + * @return uint32_t the target index + */ uint32_t pdbg_target_index(struct pdbg_target *target) { struct pdbg_target *dn; @@ -84,7 +112,12 @@ uint32_t pdbg_target_index(struct pdbg_target *target) return dn->index; } -/* Find a target parent from the given class */ +/** + * @brief Find a target parent from the given class + * @param[in] class the given class + * @param[in] target the pdbg_target + * @return struct pdbg_target* the first parent target of the given class, otherwise NULL + */ struct pdbg_target *pdbg_target_parent(const char *class, struct pdbg_target *target) { struct pdbg_target *parent; @@ -100,6 +133,13 @@ struct pdbg_target *pdbg_target_parent(const char *class, struct pdbg_target *ta return NULL; } +/** + * @brief Find a target parent from the given class + * @param[in] class the given class + * @param[in] target the pdbg_target + * @return struct pdbg_target* the first parent target of the given class, otherwise assert out + * @note Same as above but instead of returning NULL causes an assert failure + */ struct pdbg_target *pdbg_target_require_parent(const char *class, struct pdbg_target *target) { struct pdbg_target *parent = pdbg_target_parent(class, target); @@ -108,7 +148,12 @@ struct pdbg_target *pdbg_target_require_parent(const char *class, struct pdbg_ta return parent; } -/* Searched up the tree for the first target of the right class and returns its index */ +/** + * @brief Searched up the tree for the first target of the right class and returns its index + * @param[in] target the pdbg_target + * @param[in] class the given class + * @return uint32_t target parent index, otherwise -1 if there's an error + */ uint32_t pdbg_parent_index(struct pdbg_target *target, char *class) { struct pdbg_target *parent; @@ -120,21 +165,43 @@ uint32_t pdbg_parent_index(struct pdbg_target *target, char *class) return -1; } +/** + * @brief Get the target class name + * @param[in] target the pdbg_target + * @return char* the class name + */ char *pdbg_target_class_name(struct pdbg_target *target) { return target->class; } +/** + * @brief Get the target name + * @param[in] target the pdbg_target + * @return char* the target name + */ char *pdbg_target_name(struct pdbg_target *target) { return target->name; } +/** + * @brief Get the dn name + * @param[in] target the pdbg_target + * @return char* the dn name + */ const char *pdbg_target_dn_name(struct pdbg_target *target) { return target->dn_name; } +/** + * @brief Get the given property value + * @param[in] target the pdbg_target + * @param[in] name the given class name + * @param[out] val the property value (uint32_t*) + * @return 0 iff successful, -1 otherwise + */ int pdbg_target_u32_property(struct pdbg_target *target, const char *name, uint32_t *val) { uint32_t *p; @@ -150,23 +217,31 @@ int pdbg_target_u32_property(struct pdbg_target *target, const char *name, uint3 return 0; } +/** + * @brief Searched up the tree for the first target of the right class and returns its index + * @param[in] target the pdbg_target + * @param[in] name the given class name + * @param[in] index of the u32 in the list of values + * @param[out] val pointer to return value, modified only if no error. + * @return int 0 iff successful, otherwise -1 + */ int pdbg_target_u32_index(struct pdbg_target *target, const char *name, int index, uint32_t *val) { - size_t len; + size_t len; uint32_t *p; - p = pdbg_get_target_property(target, name, &len); - if (!p) - return -1; + p = pdbg_get_target_property(target, name, &len); + if (!p) + return -1; - assert(len >= (index+1)*sizeof(uint32_t)); + assert(len >= (index+1)*sizeof(uint32_t)); /* FDT pointers should be aligned, but best to check */ assert(!((uintptr_t) p & 0x3)); - /* Always aligned, so this works. */ - *val = be32toh(p[index]); - return 0; + /* Always aligned, so this works. */ + *val = be32toh(p[index]); + return 0; } void pdbg_progress_tick(uint64_t cur, uint64_t end) diff --git a/libpdbg/libpdbg.h b/libpdbg/libpdbg.h index 301c2c8..db19e14 100644 --- a/libpdbg/libpdbg.h +++ b/libpdbg/libpdbg.h @@ -6,22 +6,52 @@ #include #include -#include - #include +/** + * @struct pdbg_target + * @brief PowerPC FSI Debugger target + */ struct pdbg_target; + +/** + * @struct pdbg_target_class + * @brief PowerPC FSI Debugger target class + */ struct pdbg_target_class; /* loops/iterators */ + +/** + * @brief Find the next compatible target given @compat compat + * @param[in] parent the head pdbg_target + * @param[in] prev the last pdbg_target in the class + * @return the next compatible pdbg_target* + */ struct pdbg_target *__pdbg_next_compatible_node(struct pdbg_target *root, struct pdbg_target *prev, const char *compat); + +/** + * @brief Find the next pdbg_target* given a class + * @param[in] klass the klass of interest + * @param[in] parent the head pdbg_target + * @param[in] last the last pdbg_target in the klass + * @return the next pdbg_target* iff successful, otherwise NULL + */ struct pdbg_target *__pdbg_next_target(const char *klass, struct pdbg_target *parent, struct pdbg_target *last); + +/** + * @brief Find the next child pdbg_target* given a parent target + * @param[in] parent the head pdbg_target + * @param[in] last the last pdbg_target in the class + * @return the next pdbg_target* iff successful, otherwise NULL + */ struct pdbg_target *__pdbg_next_child_target(struct pdbg_target *parent, struct pdbg_target *last); -/* - * Each target has a status associated with it. This is what each status means: +/** + * @brief the pdbg_target states + * @note Each target has a status associated with it. This is what each status means: * * enabled - the target exists and has been probed, will be released by * the release call. @@ -46,43 +76,116 @@ struct pdbg_target *__pdbg_next_child_target(struct pdbg_target *parent, struct * unneccessary probing by marking them disabled. If no status property exists * it defaults to "unknown". */ -enum pdbg_target_status {PDBG_TARGET_UNKNOWN = 0, PDBG_TARGET_ENABLED, - PDBG_TARGET_DISABLED, PDBG_TARGET_MUSTEXIST, - PDBG_TARGET_NONEXISTENT, PDBG_TARGET_RELEASED}; +enum pdbg_target_status { + PDBG_TARGET_UNKNOWN = 0, /**< UNKNOWN STATE */ + PDBG_TARGET_ENABLED, /**< ENABLED STATE */ + PDBG_TARGET_DISABLED, /**< DISABLED STATE */ + PDBG_TARGET_MUSTEXIST, /**< MUSTEXIST STATE */ + PDBG_TARGET_NONEXISTENT, /**< NONEXISTENT STATE */ + PDBG_TARGET_RELEASED, /**< RELEASED STATE */ +}; + +/** + * @brief For each loop accross compatible targets + * @param[in] target the current pdbg_target + * @param[out] compat comptabile key to match against + */ #define pdbg_for_each_compatible(parent, target, compat) \ for (target = NULL; \ (target = __pdbg_next_compatible_node(parent, target, compat)) != NULL;) +/** + * @brief For each loop accross targets in the class (list) + * @param[in] parent the root pdbg_target + * @param[in] target the current pdbg_target + */ #define pdbg_for_each_target(class, parent, target) \ for (target = __pdbg_next_target(class, parent, NULL); \ target; \ target = __pdbg_next_target(class, parent, target)) +/** + * @brief For each loop accross class_targets (list) + * @param[in] class the class_target + * @param[in] target the current pdbg_target + */ #define pdbg_for_each_class_target(class, target) \ for (target = __pdbg_next_target(class, NULL, NULL); \ target; \ target = __pdbg_next_target(class, NULL, target)) +/** + * @brief For each loop accross class_targets (list) + * @param[in] parent the head pdbg_target + * @param[in] target the current pdbg_target + */ #define pdbg_for_each_child_target(parent, target) \ for (target = __pdbg_next_child_target(parent, NULL); \ target; \ target = __pdbg_next_child_target(parent, target)) -/* Return the first parent target of the given class, or NULL if the given - * target does not have a parent of the given class. */ +/** + * @brief Find a target parent from the given class + * @param[in] klass the given class + * @param[in] target the pdbg_target + * @return struct pdbg_target* the first parent target of the given class, otherwise NULL + */ struct pdbg_target *pdbg_target_parent(const char *klass, struct pdbg_target *target); -/* Same as above but instead of returning NULL causes an assert failure. */ +/** + * @brief Find a target parent from the given class + * @param[in] klass the given class + * @param[in] target the pdbg_target + * @return struct pdbg_target* the first parent target of the given class, otherwise assert out + * @note Same as above but instead of returning NULL causes an assert failure + */ struct pdbg_target *pdbg_target_require_parent(const char *klass, struct pdbg_target *target); -/* Set the given property. Will automatically add one if one doesn't exist */ +/** + * @brief Set the given property. Will automatically add one if one doesn't exist + * @param[in] name the given class name + * @param[in] target the pdbg_target + * @param[in] val the property to set + * @param[in] size the size + * @return void + */ void pdbg_target_set_property(struct pdbg_target *target, const char *name, const void *val, size_t size); -/* Get the given property and return the size */ +/** + * @brief Get the given property and return the size + * @param[in] target the pdbg_target + * @param[in] name the given class name + * @param[out] size the property size + * @return void* the pdbg_target property + */ void *pdbg_target_property(struct pdbg_target *target, const char *name, size_t *size); + +/** + * @brief Get the given property value + * @param[in] target the pdbg_target + * @param[in] name the given class name + * @param[out] val the property value (uint32_t*) + * @return 0 iff successful, -1 otherwise + */ int pdbg_target_u32_property(struct pdbg_target *target, const char *name, uint32_t *val); + +/** + * @brief Searched up the tree for the first target of the right class and returns its index + * @param[in] target the pdbg_target + * @param[in] name the given class name + * @param[in] index of the u32 in the list of values + * @param[out] val pointer to return value, modified only if no error. + * @return int 0 iff successful, otherwise -1 + */ int pdbg_target_u32_index(struct pdbg_target *target, const char *name, int index, uint32_t *val); + +/** + * @brief Get the address for a pdbg_target + * @param[in] target the pdbg_target + * @param[out] val pointer to return value, modified only if no error. + * @return int 0 iff successful, otherwise -1 + */ uint64_t pdbg_target_address(struct pdbg_target *target, uint64_t *size); /* Old deprecated for names for the above. Do not use for new projects @@ -99,32 +202,150 @@ void pdbg_targets_init(void *fdt); void pdbg_target_probe_all(struct pdbg_target *parent); enum pdbg_target_status pdbg_target_probe(struct pdbg_target *target); void pdbg_target_release(struct pdbg_target *target); + +/** + * @brief Get the pdbg_target status + * @param[in] target the pdbg_target + * @return pdbg_target_status the next pdbg_target status + */ enum pdbg_target_status pdbg_target_status(struct pdbg_target *target); + +/** + * @brief Set the pdbg_target status + * @param[in] target pdbg_target + * @param[in] status the status to set + * @return void + */ void pdbg_target_status_set(struct pdbg_target *target, enum pdbg_target_status status); + +/** + * @brief Searches up the tree and returns the first valid index found + * @param[in] target the pdbg_target + * @return uint32_t the target index + */ uint32_t pdbg_target_index(struct pdbg_target *target); char *pdbg_target_path(const struct pdbg_target *target); struct pdbg_target *pdbg_target_from_path(struct pdbg_target *target, const char *path); + +/** + * @brief Searched up the tree for the first target of the right class and returns its index + * @param[in] target the pdbg_target + * @param[in] class the given class + * @return uint32_t target parent index, otherwise -1 if there's an error + */ uint32_t pdbg_parent_index(struct pdbg_target *target, char *klass); + +/** + * @brief Get the target class name + * @param[in] target the pdbg_target + * @return char* the class name + */ char *pdbg_target_class_name(struct pdbg_target *target); + +/** + * @brief Get the target name + * @param[in] target the pdbg_target + * @return char* the target name + */ char *pdbg_target_name(struct pdbg_target *target); + +/** + * @brief Get the dn name + * @param[in] target the pdbg_target + * @return char* the dn name + */ const char *pdbg_target_dn_name(struct pdbg_target *target); + +/** + * @brief Gets the priv member of pdbg_target + * @param[in] target the pdbg_target + * @return void* to priv + */ void *pdbg_target_priv(struct pdbg_target *target); + +/** + * @brief Sets the priv member of pdbg_target + * @param[in,out] target the pdbg_target + * @param[in] void* priv member to set + * @return void + */ void pdbg_target_priv_set(struct pdbg_target *target, void *priv); + +/** + * @brief Gets the head pdbg_target (root node) + * @return pdbg_target the root target + */ struct pdbg_target *pdbg_target_root(void); + +/** + * @brief Check to see if a given compatible matches that of a pdbg_target + * @param[in] target the pdbg_target + * @param[in] compatible the compatible string we want to match against + * @return bool true if pdbg_target is found given compatible + */ bool pdbg_target_compatible(struct pdbg_target *target, const char *compatible); -/* Translate an address offset for a target to absolute address in address - * space of a "base" target. */ + +/** + * @brief Translate an address offset for a target to absolute address in address space of a "base" target + * @param[in] target the current pdbg_target + * @param[out] attr the target address offset + * @return struct pdbg_target* the current target + */ struct pdbg_target *pdbg_address_absolute(struct pdbg_target *target, uint64_t *addr); /* Procedures */ + +/** + * @brief FSI read + * @param[in] fsi_dt the pdbg_target + * @param[in] addr the address + * @param[out] data the read data + * @return int 0 if successful, -1 otherwise + */ int fsi_read(struct pdbg_target *target, uint32_t addr, uint32_t *val); + +/** + * @brief FSI write + * @param[in] fsi_dt the pdbg_target + * @param[in] addr the address + * @param[out] data the write data + * @return int 0 if successful, -1 otherwise + */ int fsi_write(struct pdbg_target *target, uint32_t addr, uint32_t val); +/** + * @brief PIB read + * @param[in] pib_dt the pdbg_target + * @param[in] addr the address + * @param[out] data the read data + * @return int 0 if successful, -1 otherwise + */ int pib_read(struct pdbg_target *target, uint64_t addr, uint64_t *val); + +/** + * @brief PIB write + * @param[in] pib_dt the pdbg_target + * @param[in] addr the address + * @param[out] data the write data + * @return int 0 if successful, -1 otherwise + */ int pib_write(struct pdbg_target *target, uint64_t addr, uint64_t val); + +/** + * @brief Wait for a SCOM register addr to match value & mask == data + * @param[in] pib_dt the pdbg_target + * @param[in] addr the address + * @param[in] mask the mask + * @param[in] data the data we want to match against + * @return int 0 if successful, -1 otherwise + */ int pib_wait(struct pdbg_target *pib_dt, uint64_t addr, uint64_t mask, uint64_t data); +/** + * @struct thread_regs + * @brief CPU thread registers + */ struct thread_regs { uint64_t nia; uint64_t msr; @@ -185,12 +406,32 @@ int ram_getxer(struct pdbg_target *thread, uint64_t *value); int ram_putxer(struct pdbg_target *thread, uint64_t value); int getring(struct pdbg_target *chiplet_target, uint64_t ring_addr, uint64_t ring_len, uint32_t result[]); -enum pdbg_sleep_state {PDBG_THREAD_STATE_RUN, PDBG_THREAD_STATE_DOZE, - PDBG_THREAD_STATE_NAP, PDBG_THREAD_STATE_SLEEP, - PDBG_THREAD_STATE_STOP}; +/** + * @brief the pdbg thread states + */ +enum pdbg_sleep_state { + PDBG_THREAD_STATE_RUN, /**< RUN STATE */ + PDBG_THREAD_STATE_DOZE, /**< DOZE STATE */ + PDBG_THREAD_STATE_NAP, /**< NAP STATE */ + PDBG_THREAD_STATE_SLEEP, /**< SLEEP STATE */ + PDBG_THREAD_STATE_STOP, /**< STOP STATE */ +}; -enum pdbg_smt_state {PDBG_SMT_UNKNOWN, PDBG_SMT_1, PDBG_SMT_2, PDBG_SMT_4, PDBG_SMT_8}; +/** + * @brief the pdbg_smt states + */ +enum pdbg_smt_state { + PDBG_SMT_UNKNOWN, /**< UNKNOWN STATE */ + PDBG_SMT_1, /**< SMT_1 STATE */ + PDBG_SMT_2, /**< SMT_2 STATE */ + PDBG_SMT_4, /**< SMT_4 STATE */ + PDBG_SMT_8, /**< SMT_8 STATE */ +}; +/** + * @struct thread_state + * @brief Container of thread states + */ struct thread_state { bool active; bool quiesced; diff --git a/libpdbg/target.c b/libpdbg/target.c index 37d3f54..eb97dbc 100644 --- a/libpdbg/target.c +++ b/libpdbg/target.c @@ -10,11 +10,27 @@ #include "operations.h" #include "debug.h" -struct list_head empty_list = LIST_HEAD_INIT(empty_list); -struct list_head target_classes = LIST_HEAD_INIT(target_classes); +/** + * @struct empty_list + * @brief Defines and initializes a list_head named empty_list + * @note this is a special node that refers to the linked list, without being a list node + */ +LIST_HEAD(empty_list); -/* Work out the address to access based on the current target and - * final class name */ +/** + * @struct target_classes + * @brief Defines and initializes a list_head named target_classes + * @note this is a special node that refers to the linked list, without being a list node + */ +LIST_HEAD(target_classes); + +/** + * @brief Work out the address to access + * @param[in] target the current target + * @param[in] name final class name + * @param[out] addr the address to access + * @return pdbg_target* the current target + */ static struct pdbg_target *get_class_target_addr(struct pdbg_target *target, const char *name, uint64_t *addr) { /* Check class */ @@ -36,6 +52,12 @@ static struct pdbg_target *get_class_target_addr(struct pdbg_target *target, con return target; } +/** + * @brief Translate an address offset for a target to absolute address in address space of a "base" target + * @param[in] target the current pdbg_target + * @param[out] attr the target address offset + * @return struct pdbg_target* the current target + */ struct pdbg_target *pdbg_address_absolute(struct pdbg_target *target, uint64_t *addr) { return get_class_target_addr(target, "pib", addr); @@ -51,6 +73,13 @@ struct pdbg_target *pdbg_address_absolute(struct pdbg_target *target, uint64_t * #define PIB_DATA_IND_ERR PPC_BITMASK(33, 35) #define PIB_DATA_IND_DATA PPC_BITMASK(48, 63) +/** + * @brief PIB indirect read + * @param[in] pib the pib target + * @param[in] addr the address + * @param[out] data the read data + * @return int 0 if successful, -1 otherwise + */ static int pib_indirect_read(struct pib *pib, uint64_t addr, uint64_t *data) { uint64_t indirect_addr; @@ -85,6 +114,13 @@ static int pib_indirect_read(struct pib *pib, uint64_t addr, uint64_t *data) return 0; } +/** + * @brief PIB indirect write + * @param[in] pib the pib target + * @param[in] addr the address + * @param[out] data the write data + * @return int 0 if successful, -1 otherwise + */ static int pib_indirect_write(struct pib *pib, uint64_t addr, uint64_t data) { uint64_t indirect_addr; @@ -118,6 +154,13 @@ static int pib_indirect_write(struct pib *pib, uint64_t addr, uint64_t data) return 0; } +/** + * @brief PIB read + * @param[in] pib_dt the pdbg_target + * @param[in] addr the address + * @param[out] data the read data + * @return int 0 if successful, -1 otherwise + */ int pib_read(struct pdbg_target *pib_dt, uint64_t addr, uint64_t *data) { struct pib *pib; @@ -135,6 +178,13 @@ int pib_read(struct pdbg_target *pib_dt, uint64_t addr, uint64_t *data) return rc; } +/** + * @brief PIB write + * @param[in] pib_dt the pdbg_target + * @param[in] addr the address + * @param[out] data the write data + * @return int 0 if successful, -1 otherwise + */ int pib_write(struct pdbg_target *pib_dt, uint64_t addr, uint64_t data) { struct pib *pib; @@ -152,7 +202,14 @@ int pib_write(struct pdbg_target *pib_dt, uint64_t addr, uint64_t data) return rc; } -/* Wait for a SCOM register addr to match value & mask == data */ +/** + * @brief Wait for a SCOM register addr to match value & mask == data + * @param[in] pib_dt the pdbg_target + * @param[in] addr the address + * @param[in] mask the mask + * @param[in] data the data we want to match against + * @return int 0 if successful, -1 otherwise + */ int pib_wait(struct pdbg_target *pib_dt, uint64_t addr, uint64_t mask, uint64_t data) { struct pib *pib; @@ -174,6 +231,13 @@ int pib_wait(struct pdbg_target *pib_dt, uint64_t addr, uint64_t mask, uint64_t return 0; } +/** + * @brief OPB read + * @param[in] opb_dt the pdbg_target + * @param[in] addr the address + * @param[out] data the read data + * @return int 0 if successful, -1 otherwise + */ int opb_read(struct pdbg_target *opb_dt, uint32_t addr, uint32_t *data) { struct opb *opb; @@ -184,6 +248,13 @@ int opb_read(struct pdbg_target *opb_dt, uint32_t addr, uint32_t *data) return opb->read(opb, addr64, data); } +/** + * @brief OPB write + * @param[in] opb_dt the pdbg_target + * @param[in] addr the address + * @param[out] data the write data + * @return int 0 if successful, -1 otherwise + */ int opb_write(struct pdbg_target *opb_dt, uint32_t addr, uint32_t data) { struct opb *opb; @@ -195,6 +266,13 @@ int opb_write(struct pdbg_target *opb_dt, uint32_t addr, uint32_t data) return opb->write(opb, addr64, data); } +/** + * @brief FSI read + * @param[in] fsi_dt the pdbg_target + * @param[in] addr the address + * @param[out] data the read data + * @return int 0 if successful, -1 otherwise + */ int fsi_read(struct pdbg_target *fsi_dt, uint32_t addr, uint32_t *data) { struct fsi *fsi; @@ -205,6 +283,13 @@ int fsi_read(struct pdbg_target *fsi_dt, uint32_t addr, uint32_t *data) return fsi->read(fsi, addr64, data); } +/** + * @brief FSI write + * @param[in] fsi_dt the pdbg_target + * @param[in] addr the address + * @param[out] data the write data + * @return int 0 if successful, -1 otherwise + */ int fsi_write(struct pdbg_target *fsi_dt, uint32_t addr, uint32_t data) { struct fsi *fsi; @@ -216,13 +301,23 @@ int fsi_write(struct pdbg_target *fsi_dt, uint32_t addr, uint32_t data) return fsi->write(fsi, addr64, data); } +/** + * @brief Checks that a pdbg_target has a parent target + * @param[in] target A PowerPC FSI Debugger target + * @return struct pdbg_target* the input's parent target + * @note we assert out if the input is the list head + */ struct pdbg_target *require_target_parent(struct pdbg_target *target) { assert(target->parent); return target->parent; } -/* Finds the given class. Returns NULL if not found. */ +/** + * @brief Finds the target class given a name + * @param name the name of the class we want + * @return the found pdbg_target_class, otherwise NULL + */ struct pdbg_target_class *find_target_class(const char *name) { struct pdbg_target_class *target_class; @@ -234,8 +329,12 @@ struct pdbg_target_class *find_target_class(const char *name) return NULL; } -/* Same as above but dies with an assert if the target class doesn't - * exist */ +/** + * @brief Finds the target class given a name + * @param name the name of the class we want + * @return the found pdbg_target_class, otherwise assert out + * @note same as find_target_class but asserts out if the target class doesn't exist + */ struct pdbg_target_class *require_target_class(const char *name) { struct pdbg_target_class *target_class; @@ -248,7 +347,11 @@ struct pdbg_target_class *require_target_class(const char *name) return target_class; } -/* Returns the existing class or allocates space for a new one */ +/** + * @brief Returns the existing class or allocates space for a new one + * @param name the name of the class we want + * @return the found or new pdbg_target_class + */ struct pdbg_target_class *get_target_class(const char *name) { struct pdbg_target_class *target_class; @@ -266,8 +369,22 @@ struct pdbg_target_class *get_target_class(const char *name) return target_class; } +/** + * @struct __start_hw_units + * @brief declaration of __start_hw_units + */ extern struct hw_unit_info *__start_hw_units; + +/** + * @struct __stop_hw_units + * @brief declaration of __stop_hw_units + */ extern struct hw_init_info *__stop_hw_units; + +/** + * @brief Find a target given @compat a compatibility member + * @param[in] compat the given compatibility + */ struct hw_unit_info *find_compatible_target(const char *compat) { struct hw_unit_info **p; @@ -282,8 +399,11 @@ struct hw_unit_info *find_compatible_target(const char *compat) return NULL; } -/* We walk the tree root down disabling targets which might/should - * exist but don't */ +/** + * @brief We walk the tree root down disabling targets which might/should exist but don't + * @param[in] target the pdbg_target + * @return pdbg_target_status + */ enum pdbg_target_status pdbg_target_probe(struct pdbg_target *target) { struct pdbg_target *parent; @@ -344,7 +464,11 @@ enum pdbg_target_status pdbg_target_probe(struct pdbg_target *target) return PDBG_TARGET_ENABLED; } -/* Releases a target by first recursively releasing all its children */ +/** + * @brief Releases a target by first recursively releasing all its children + * @param[in,out] target the pdbg_target + * @return void + */ void pdbg_target_release(struct pdbg_target *target) { struct pdbg_target *child; @@ -361,8 +485,10 @@ void pdbg_target_release(struct pdbg_target *target) target->status = PDBG_TARGET_RELEASED; } -/* - * Probe all targets in the device tree. +/** + * @brief Probe all targets in the device tree. + * @param[in,out] target the pdbg_target + * @return void */ void pdbg_target_probe_all(struct pdbg_target *parent) { @@ -377,6 +503,12 @@ void pdbg_target_probe_all(struct pdbg_target *parent) } } +/** + * @brief Checks if the target is the given class + * @param[in] target the pdbg_target + * @param class the class name + * @return true if the pdbg_target is the class, otherwise false + */ bool pdbg_target_is_class(struct pdbg_target *target, const char *class) { if (!target || !target->class || !class) @@ -384,11 +516,22 @@ bool pdbg_target_is_class(struct pdbg_target *target, const char *class) return strcmp(target->class, class) == 0; } +/** + * @brief Gets the priv member of pdbg_target + * @param[in] target the pdbg_target + * @return void* to priv + */ void *pdbg_target_priv(struct pdbg_target *target) { return target->priv; } +/** + * @brief Sets the priv member of pdbg_target + * @param[in,out] target the pdbg_target + * @param[in] void* priv member to set + * @return void + */ void pdbg_target_priv_set(struct pdbg_target *target, void *priv) { target->priv = priv; diff --git a/libpdbg/target.h b/libpdbg/target.h index 729b122..0c4413b 100644 --- a/libpdbg/target.h +++ b/libpdbg/target.h @@ -23,14 +23,32 @@ #include "compiler.h" #include "libpdbg.h" -enum chip_type {CHIP_UNKNOWN, CHIP_P8, CHIP_P8NV, CHIP_P9}; +/** @file target.h */ +/** A chip type +* A list of currently supported processor chip types +*/ +enum chip_type { + CHIP_UNKNOWN, /**< Unknown */ + CHIP_P8, /**< P8 */ + CHIP_P8NV, /**< P8 Prime */ + CHIP_P9, /**< P9 */ +}; + +/** + * @struct pdbg_target_class + * @brief A container as a doubly linked list + */ struct pdbg_target_class { char *name; struct list_head targets; struct list_node class_head_link; }; +/** + * @struct pdbg_target + * @brief The PowerPC FSI Debugger target + */ struct pdbg_target { char *name; char *compatible; @@ -51,42 +69,108 @@ struct pdbg_target { void *priv; }; +/** + * @brief Checks that a pdbg_target has a parent target + * @param[in] target A PowerPC FSI Debugger target + * @return struct pdbg_target* the input's parent target + * @note we assert out if the input is the list head + */ struct pdbg_target *require_target_parent(struct pdbg_target *target); + +/** + * @brief Finds the given class + * @param name the name of the class we want + * @return the found pdbg_target_class, otherwise NULL + */ struct pdbg_target_class *find_target_class(const char *name); + +/** + * @brief Finds the target class given a name + * @param name the name of the class we want + * @return the found pdbg_target_class, otherwise assert out + * @note same as find_target_class but asserts out if the target class doesn't exist + */ struct pdbg_target_class *require_target_class(const char *name); + +/** + * @brief Returns the existing class or allocates space for a new one + * @param name the name of the class we want + * @return the found or new pdbg_target_class + */ struct pdbg_target_class *get_target_class(const char *name); + +/** + * @brief Checks if the target is the given class + * @param[in] target the pdbg_target + * @param class the class name + * @return true if the pdbg_target is the class, otherwise false + */ bool pdbg_target_is_class(struct pdbg_target *target, const char *class); -/* This works and should be safe because struct pdbg_target is guaranteed to be +/** + * @brief A macro that casts @x x as a translate function pointer + * @param[in] x + * @note This works and should be safe because struct pdbg_target is guaranteed to be * the first member of the specialised type (see the DECLARE_HW_UNIT definition * below). I'm not sure how sane it is though. Probably not very but it does - * remove a bunch of tedious container_of() typing */ + * remove a bunch of tedious container_of() typing + */ #define translate_cast(x) (uint64_t (*)(struct pdbg_target *, uint64_t)) (x) +/** + * @struct empty_list + * @brief Declares a list_head named empty_list + * @note this is a special node that refers to the linked list, without being a list node + */ extern struct list_head empty_list; + +/** + * @struct target_classes + * @brief Declares list_head named target_classes + * @note this is a special node that refers to the linked list, without being a list node + */ extern struct list_head target_classes; +/** + * @brief A macro that iterates through a target_class (list) for a given class name + * @param[in] class_name the class name + * @param[in] target the target list + */ #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) +/** + * @brief A macro that iterates through a list @target_class target classes + * @param[in] target_class the target class + */ #define for_each_target_class(target_class) \ list_for_each(&target_classes, target_class, class_head_link) +/** + * @struct hw_unit_info + * @brief Declares HW unit information + */ struct hw_unit_info { void *hw_unit; size_t size; }; + +/** + * @brief Find a target given @compat a compatibility member + * @param[in] compat the given compatibility + */ struct hw_unit_info *find_compatible_target(const char *compat); -/* We can't pack the structs themselves directly into a special +/** + * @brief A macro that packs pointers name into a special section + * @note We can't pack the structs themselves directly into a special * section because there doesn't seem to be any standard way of doing * that due to alignment rules. So instead we pack pointers into a * special section. - * * If this macro fails to compile for you, you've probably not * declared the struct pdbg_target as the first member of the * container struct. Not doing so will break other assumptions. - * */ + */ #define DECLARE_HW_UNIT(name) \ static inline void name ##_hw_unit_check(void) { \ ((void)sizeof(char[1 - 2 * (container_off(typeof(name), target) != 0)])); \ @@ -95,6 +179,10 @@ struct hw_unit_info *find_compatible_target(const char *compat); { .hw_unit = &name, .size = sizeof(name) }; \ const struct hw_unit_info __used __section("hw_units") *name ##_hw_unit_p = &name ##_hw_unit +/** + * @struct htm + * @brief Defines a HTM target + */ struct htm { struct pdbg_target target; int (*start)(struct htm *); @@ -103,44 +191,104 @@ struct htm { int (*dump)(struct htm *, char *); int (*record)(struct htm *, char *); }; + +/** + * @brief A macro that retrieves the struct given a pointer 'target' member + * @param[in] x A pointer to the 'target' field in htm + * @return struct htm* + */ #define target_to_htm(x) container_of(x, struct htm, target) +/** + * @struct adu + * @brief Defines a ADU target + */ struct adu { struct pdbg_target target; int (*getmem)(struct adu *, uint64_t, uint64_t *, int); int (*putmem)(struct adu *, uint64_t, uint64_t, int, int); }; + +/** + * @brief A macro that retrieves the struct given a pointer 'target' member + * @param[in] x A pointer to the 'target' field in adu + * @return struct adu* + */ #define target_to_adu(x) container_of(x, struct adu, target) +/** + * @struct pib + * @brief Defines a PIB target + */ struct pib { struct pdbg_target target; int (*read)(struct pib *, uint64_t, uint64_t *); int (*write)(struct pib *, uint64_t, uint64_t); void *priv; }; + +/** + * @brief A macro that retrieves the struct given a pointer 'target' member + * @param[in] x A pointer to the 'target' field in pib + * @return struct pib* + */ #define target_to_pib(x) container_of(x, struct pib, target) +/** + * @struct opb + * @brief Defines a OPB target + */ struct opb { struct pdbg_target target; int (*read)(struct opb *, uint32_t, uint32_t *); int (*write)(struct opb *, uint32_t, uint32_t); }; + +/** + * @brief A macro that retrieves the struct given a pointer 'target' member + * @param[in] x A pointer to the 'target' field in opb + * @return struct opb* + */ #define target_to_opb(x) container_of(x, struct opb, target) +/** + * @struct fsi + * @brief Defines a FSI target + */ struct fsi { struct pdbg_target target; int (*read)(struct fsi *, uint32_t, uint32_t *); int (*write)(struct fsi *, uint32_t, uint32_t); enum chip_type chip_type; }; + +/** + * @brief A macro that retrieves the struct given a pointer 'target' member + * @param[in] x A pointer to the 'target' field in fsi + * @return struct fsi* + */ #define target_to_fsi(x) container_of(x, struct fsi, target) +/** + * @struct core + * @brief Defines a CORE target + */ struct core { struct pdbg_target target; bool release_spwkup; }; + +/** + * @brief A macro that retrieves the struct given a pointer 'target' member + * @param[in] x A pointer to the 'target' field in core + * @return struct core* + */ #define target_to_core(x) container_of(x, struct core, target) +/** + * @struct thread + * @brief Refers to CPU threads on the host + */ struct thread { struct pdbg_target target; struct thread_state status; @@ -163,46 +311,122 @@ struct thread { int (*ram_putxer)(struct pdbg_target *, uint64_t value); int (*enable_attn)(struct pdbg_target *); }; + +/** + * @brief A macro that retrieves the struct given a pointer 'target' member + * @param[in] x A pointer to the 'target' field in thread + * @return struct thread* + */ #define target_to_thread(x) container_of(x, struct thread, target) -/* Place holder for chiplets which we just want translation for */ +/** + * @struct chiplet + * @brief Defines a CHIPLET target + * @note Place holder for chiplets which we just want translation for + */ struct chiplet { struct pdbg_target target; int (*getring)(struct chiplet *, uint64_t, int64_t, uint32_t[]); }; + +/** + * @brief A macro that retrieves the struct given a pointer 'target' member + * @param[in] x A pointer to the 'target' field in chiplet + * @return struct chiplet* + */ #define target_to_chiplet(x) container_of(x, struct chiplet, target) +/** + * @struct xbus + * @brief Defines a XBUS target + */ struct xbus { struct pdbg_target target; uint32_t ring_id; }; + +/** + * @brief A macro that retrieves the struct given a pointer 'target' member + * @param[in] x A pointer to the 'target' field in xbus + * @return struct xbus* + */ #define target_to_xbus(x) container_of(x, struct xbus, target) +/** + * @struct mcs + * @brief Defines a MCS target + */ struct mcs { struct pdbg_target target; uint32_t chip_unit; }; + +/** + * @brief A macro that retrieves the struct given a pointer 'target' member + * @param[in] x A pointer to the 'target' field in mcs + * @return struct mcs* + */ #define target_to_mcs(x) container_of(x, struct mcs, target) +/** + * @struct pec + * @brief Defines a PEC target + */ struct pec { struct pdbg_target target; uint32_t chip_unit; }; + +/** + * @brief A macro that retrieves the struct given a pointer 'target' member + * @param[in] x A pointer to the 'target' field in pec + * @return struct pec* + */ #define target_to_pec(x) container_of(x, struct pec, target) +/** + * @struct eq + * @brief Defines a EQ target + */ struct eq { struct pdbg_target target; }; + +/** + * @brief A macro that retrieves the struct given a pointer 'target' member + * @param[in] x A pointer to the 'target' field in eq + * @return struct eq* + */ #define target_to_eq(x) container_of(x, struct eq, target); +/** + * @struct ex + * @brief Defines a EX target + */ struct ex { struct pdbg_target target; }; + +/** + * @brief A macro that retrieves the struct given a pointer 'target' member + * @param[in] x A pointer to the 'target' field in ex + * @return struct ex* + */ #define target_to_ex(x) container_of(x, struct ex, target) +/** + * @struct ec + * @brief Defines a EC target + */ struct ec { struct pdbg_target target; }; + +/** + * @brief A macro that retrieves the struct given a pointer 'target' member + * @param[in] x A pointer to the 'target' field in ec + * @return struct ec* + */ #define target_to_ec(x) container_of(x, struct ec, target) #endif