diff mbox series

[2/3] libpdbg/p10chip: add basic thread direct controls

Message ID 20201221101733.912938-2-npiggin@gmail.com
State Accepted
Headers show
Series [1/3] libpdbg/p10chip: remove delay from special wakeup clearing | expand

Commit Message

Nicholas Piggin Dec. 21, 2020, 10:17 a.m. UTC
This adds support for stop, start, sreset.

Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
 libpdbg/p10_fapi_targets.c |  20 --------
 libpdbg/p10chip.c          | 101 +++++++++++++++++++++++++++++++++++++
 2 files changed, 101 insertions(+), 20 deletions(-)

Comments

Joel Stanley Jan. 11, 2021, 4:56 a.m. UTC | #1
On Mon, 21 Dec 2020 at 10:18, Nicholas Piggin <npiggin@gmail.com> wrote:
>
> This adds support for stop, start, sreset.
>
> Signed-off-by: Nicholas Piggin <npiggin@gmail.com>

Reviewed-by: Joel Stanley <joel@jms.id.au>

> ---
>  libpdbg/p10_fapi_targets.c |  20 --------
>  libpdbg/p10chip.c          | 101 +++++++++++++++++++++++++++++++++++++
>  2 files changed, 101 insertions(+), 20 deletions(-)
>
> diff --git a/libpdbg/p10_fapi_targets.c b/libpdbg/p10_fapi_targets.c
> index 6023389..0f16735 100644
> --- a/libpdbg/p10_fapi_targets.c
> +++ b/libpdbg/p10_fapi_targets.c
> @@ -488,25 +488,6 @@ static struct chiplet p10_chiplet = {
>  };
>  DECLARE_HW_UNIT(p10_chiplet);
>
> -static int p10_thread_probe(struct pdbg_target *target)
> -{
> -       struct thread *thread = target_to_thread(target);
> -
> -       thread->id = pdbg_target_index(target);
> -
> -       return 0;
> -}
> -
> -static struct thread p10_thread = {
> -       .target = {
> -               .name = "POWER10 Thread",
> -               .compatible = "ibm,power10-thread",
> -               .class = "thread",
> -               .probe = p10_thread_probe,
> -       },
> -};
> -DECLARE_HW_UNIT(p10_thread);
> -
>  static uint64_t no_translate(struct pdbg_target *target, uint64_t addr)
>  {
>         /*  No translation performed */
> @@ -540,6 +521,5 @@ static void register_p10_fapi_targets(void)
>         pdbg_hwunit_register(PDBG_DEFAULT_BACKEND, &p10_pauc_hw_unit);
>         pdbg_hwunit_register(PDBG_DEFAULT_BACKEND, &p10_pau_hw_unit);
>         pdbg_hwunit_register(PDBG_DEFAULT_BACKEND, &p10_chiplet_hw_unit);
> -       pdbg_hwunit_register(PDBG_DEFAULT_BACKEND, &p10_thread_hw_unit);
>         pdbg_hwunit_register(PDBG_DEFAULT_BACKEND, &p10_fc_hw_unit);
>  }
> diff --git a/libpdbg/p10chip.c b/libpdbg/p10chip.c
> index f26e4ca..87d34e5 100644
> --- a/libpdbg/p10chip.c
> +++ b/libpdbg/p10chip.c
> @@ -22,8 +22,16 @@
>  #include "chip.h"
>  #include "debug.h"
>
> +/*
> + * NOTE!
> + * All timeouts and scom procedures in general through the file should be kept
> + * in synch with skiboot (e.g., core/direct-controls.c) as far as possible.
> + * If you fix a bug here, fix it in skiboot, and vice versa.
> + */
> +
>  #define P10_CORE_THREAD_STATE  0x28412
>  #define P10_THREAD_INFO                0x28413
> +#define P10_DIRECT_CONTROL     0x28449
>  #define P10_RAS_STATUS         0x28454
>
>  /* PCB Slave registers */
> @@ -31,6 +39,7 @@
>  #define  SPECIAL_WKUP_DONE     PPC_BIT(1)
>  #define QME_SPWU_FSP           0xE8834
>
> +#define RAS_STATUS_TIMEOUT     100 /* 100ms */
>  #define SPECIAL_WKUP_TIMEOUT   100 /* 100ms */
>
>  static int thread_read(struct thread *thread, uint64_t addr, uint64_t *data)
> @@ -40,6 +49,13 @@ static int thread_read(struct thread *thread, uint64_t addr, uint64_t *data)
>         return pib_read(core, addr, data);
>  }
>
> +static uint64_t thread_write(struct thread *thread, uint64_t addr, uint64_t data)
> +{
> +       struct pdbg_target *chip = pdbg_target_require_parent("core", &thread->target);
> +
> +       return pib_write(chip, addr, data);
> +}
> +
>  struct thread_state p10_thread_state(struct thread *thread)
>  {
>         struct thread_state thread_state;
> @@ -89,6 +105,90 @@ struct thread_state p10_thread_state(struct thread *thread)
>         return thread_state;
>  }
>
> +static int p10_thread_probe(struct pdbg_target *target)
> +{
> +       struct thread *thread = target_to_thread(target);
> +
> +       thread->id = pdbg_target_index(target);
> +       thread->status = thread->state(thread);
> +
> +       return 0;
> +}
> +
> +static void p10_thread_release(struct pdbg_target *target)
> +{
> +       struct core *core = target_to_core(pdbg_target_require_parent("core", target));
> +       struct thread *thread = target_to_thread(target);
> +
> +       if (thread->status.quiesced)
> +               /* This thread is still quiesced so don't release spwkup */
> +               core->release_spwkup = false;
> +}
> +
> +static int p10_thread_start(struct thread *thread)
> +{
> +       if (!(thread->status.quiesced))
> +               return 1;
> +
> +       if ((!(thread->status.active)) ||
> +           (thread->status.sleep_state == PDBG_THREAD_STATE_STOP)) {
> +               /* Inactive or active and stopped: Clear Maint */
> +               thread_write(thread, P10_DIRECT_CONTROL, PPC_BIT(3 + 8*thread->id));
> +       } else {
> +               /* Active and not stopped: Start */
> +               thread_write(thread, P10_DIRECT_CONTROL, PPC_BIT(6 + 8*thread->id));
> +       }
> +
> +       thread->status = thread->state(thread);
> +
> +       return 0;
> +}
> +
> +static int p10_thread_stop(struct thread *thread)
> +{
> +       int i = 0;
> +
> +       thread_write(thread, P10_DIRECT_CONTROL, PPC_BIT(7 + 8*thread->id));
> +       while (!(thread->state(thread).quiesced)) {
> +               usleep(1000);
> +               if (i++ > RAS_STATUS_TIMEOUT) {
> +                       PR_ERROR("Unable to quiesce thread\n");
> +                       break;
> +               }
> +       }
> +       thread->status = thread->state(thread);
> +
> +       return 0;
> +}
> +
> +static int p10_thread_sreset(struct thread *thread)
> +{
> +       /* Can only sreset if a thread is quiesced */
> +       if (!(thread->status.quiesced))
> +               return 1;
> +
> +       thread_write(thread, P10_DIRECT_CONTROL, PPC_BIT(4 + 8*thread->id));
> +
> +       thread->status = thread->state(thread);
> +
> +       return 0;
> +}
> +
> +static struct thread p10_thread = {
> +       .target = {
> +               .name = "POWER10 Thread",
> +               .compatible = "ibm,power10-thread",
> +               .class = "thread",
> +               .probe = p10_thread_probe,
> +               .release = p10_thread_release,
> +       },
> +       .state = p10_thread_state,
> +       .start = p10_thread_start,
> +       .stop = p10_thread_stop,
> +       .sreset = p10_thread_sreset,
> +};
> +DECLARE_HW_UNIT(p10_thread);
> +
>  static int p10_core_probe(struct pdbg_target *target)
>  {
>         struct core *core = target_to_core(target);
> @@ -190,5 +290,6 @@ DECLARE_HW_UNIT(p10_core);
>  __attribute__((constructor))
>  static void register_p10chip(void)
>  {
> +       pdbg_hwunit_register(PDBG_DEFAULT_BACKEND, &p10_thread_hw_unit);
>         pdbg_hwunit_register(PDBG_DEFAULT_BACKEND, &p10_core_hw_unit);
>  }
> --
> 2.23.0
>
> --
> Pdbg mailing list
> Pdbg@lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/pdbg
diff mbox series

Patch

diff --git a/libpdbg/p10_fapi_targets.c b/libpdbg/p10_fapi_targets.c
index 6023389..0f16735 100644
--- a/libpdbg/p10_fapi_targets.c
+++ b/libpdbg/p10_fapi_targets.c
@@ -488,25 +488,6 @@  static struct chiplet p10_chiplet = {
 };
 DECLARE_HW_UNIT(p10_chiplet);
 
-static int p10_thread_probe(struct pdbg_target *target)
-{
-	struct thread *thread = target_to_thread(target);
-
-	thread->id = pdbg_target_index(target);
-
-	return 0;
-}
-
-static struct thread p10_thread = {
-	.target = {
-		.name = "POWER10 Thread",
-		.compatible = "ibm,power10-thread",
-		.class = "thread",
-		.probe = p10_thread_probe,
-	},
-};
-DECLARE_HW_UNIT(p10_thread);
-
 static uint64_t no_translate(struct pdbg_target *target, uint64_t addr)
 {
 	/*  No translation performed */
@@ -540,6 +521,5 @@  static void register_p10_fapi_targets(void)
 	pdbg_hwunit_register(PDBG_DEFAULT_BACKEND, &p10_pauc_hw_unit);
 	pdbg_hwunit_register(PDBG_DEFAULT_BACKEND, &p10_pau_hw_unit);
 	pdbg_hwunit_register(PDBG_DEFAULT_BACKEND, &p10_chiplet_hw_unit);
-	pdbg_hwunit_register(PDBG_DEFAULT_BACKEND, &p10_thread_hw_unit);
 	pdbg_hwunit_register(PDBG_DEFAULT_BACKEND, &p10_fc_hw_unit);
 }
diff --git a/libpdbg/p10chip.c b/libpdbg/p10chip.c
index f26e4ca..87d34e5 100644
--- a/libpdbg/p10chip.c
+++ b/libpdbg/p10chip.c
@@ -22,8 +22,16 @@ 
 #include "chip.h"
 #include "debug.h"
 
+/*
+ * NOTE!
+ * All timeouts and scom procedures in general through the file should be kept
+ * in synch with skiboot (e.g., core/direct-controls.c) as far as possible.
+ * If you fix a bug here, fix it in skiboot, and vice versa.
+ */
+
 #define P10_CORE_THREAD_STATE	0x28412
 #define P10_THREAD_INFO		0x28413
+#define P10_DIRECT_CONTROL	0x28449
 #define P10_RAS_STATUS		0x28454
 
 /* PCB Slave registers */
@@ -31,6 +39,7 @@ 
 #define  SPECIAL_WKUP_DONE	PPC_BIT(1)
 #define QME_SPWU_FSP		0xE8834
 
+#define RAS_STATUS_TIMEOUT	100 /* 100ms */
 #define SPECIAL_WKUP_TIMEOUT	100 /* 100ms */
 
 static int thread_read(struct thread *thread, uint64_t addr, uint64_t *data)
@@ -40,6 +49,13 @@  static int thread_read(struct thread *thread, uint64_t addr, uint64_t *data)
 	return pib_read(core, addr, data);
 }
 
+static uint64_t thread_write(struct thread *thread, uint64_t addr, uint64_t data)
+{
+	struct pdbg_target *chip = pdbg_target_require_parent("core", &thread->target);
+
+	return pib_write(chip, addr, data);
+}
+
 struct thread_state p10_thread_state(struct thread *thread)
 {
 	struct thread_state thread_state;
@@ -89,6 +105,90 @@  struct thread_state p10_thread_state(struct thread *thread)
 	return thread_state;
 }
 
+static int p10_thread_probe(struct pdbg_target *target)
+{
+	struct thread *thread = target_to_thread(target);
+
+	thread->id = pdbg_target_index(target);
+	thread->status = thread->state(thread);
+
+	return 0;
+}
+
+static void p10_thread_release(struct pdbg_target *target)
+{
+	struct core *core = target_to_core(pdbg_target_require_parent("core", target));
+	struct thread *thread = target_to_thread(target);
+
+	if (thread->status.quiesced)
+		/* This thread is still quiesced so don't release spwkup */
+		core->release_spwkup = false;
+}
+
+static int p10_thread_start(struct thread *thread)
+{
+	if (!(thread->status.quiesced))
+		return 1;
+
+	if ((!(thread->status.active)) ||
+	    (thread->status.sleep_state == PDBG_THREAD_STATE_STOP)) {
+		/* Inactive or active and stopped: Clear Maint */
+		thread_write(thread, P10_DIRECT_CONTROL, PPC_BIT(3 + 8*thread->id));
+	} else {
+		/* Active and not stopped: Start */
+		thread_write(thread, P10_DIRECT_CONTROL, PPC_BIT(6 + 8*thread->id));
+	}
+
+	thread->status = thread->state(thread);
+
+	return 0;
+}
+
+static int p10_thread_stop(struct thread *thread)
+{
+	int i = 0;
+
+	thread_write(thread, P10_DIRECT_CONTROL, PPC_BIT(7 + 8*thread->id));
+	while (!(thread->state(thread).quiesced)) {
+		usleep(1000);
+		if (i++ > RAS_STATUS_TIMEOUT) {
+			PR_ERROR("Unable to quiesce thread\n");
+			break;
+		}
+	}
+	thread->status = thread->state(thread);
+
+	return 0;
+}
+
+static int p10_thread_sreset(struct thread *thread)
+{
+	/* Can only sreset if a thread is quiesced */
+	if (!(thread->status.quiesced))
+		return 1;
+
+	thread_write(thread, P10_DIRECT_CONTROL, PPC_BIT(4 + 8*thread->id));
+
+	thread->status = thread->state(thread);
+
+	return 0;
+}
+
+static struct thread p10_thread = {
+	.target = {
+		.name = "POWER10 Thread",
+		.compatible = "ibm,power10-thread",
+		.class = "thread",
+		.probe = p10_thread_probe,
+		.release = p10_thread_release,
+	},
+	.state = p10_thread_state,
+	.start = p10_thread_start,
+	.stop = p10_thread_stop,
+	.sreset = p10_thread_sreset,
+};
+DECLARE_HW_UNIT(p10_thread);
+
 static int p10_core_probe(struct pdbg_target *target)
 {
 	struct core *core = target_to_core(target);
@@ -190,5 +290,6 @@  DECLARE_HW_UNIT(p10_core);
 __attribute__((constructor))
 static void register_p10chip(void)
 {
+	pdbg_hwunit_register(PDBG_DEFAULT_BACKEND, &p10_thread_hw_unit);
 	pdbg_hwunit_register(PDBG_DEFAULT_BACKEND, &p10_core_hw_unit);
 }