diff mbox series

[RFC,3/4] pdbg: add timeer facility TB error injections.

Message ID 158918649880.16822.9214964387579789187.stgit@jupiter
State New
Headers show
Series [RFC,1/4] pdbg: Add support for error injection framework. | expand

Checks

Context Check Description
snowpatch_ozlabs/apply_patch success Successfully applied on branch master (6c10b68bf774a9fe21affd5ef0b40084cd49800d)
snowpatch_ozlabs/build-multiarch fail Test build-multiarch on branch master

Commit Message

Mahesh J Salgaonkar May 11, 2020, 8:41 a.m. UTC
# ./pdbg -p0 -c3 -t3 inject
Usage: pdbg inject <component> <error>
 <component>:
    ?          Show component list
    tb
# ./pdbg -p0 -c3 -t3 inject tb ?
Usage: pdbg inject tb <error>:
 <error>:
    ?               Show error list
    tfmr_parity     TFMR parity error
    hdec_parity     HDEC parity error
    tb_residue      TB parity/residue error
    purr_parity     PURR parity error
    spurr_parity    SPURR parity error
    dec_parity      DEC parity error

# ./pdbg -p0 -c1 -t3  inject tb dec_parity
p0:c1:t3: 0x20010a84 = 0x001e000000000000
#
# ./pdbg -p0 -c1,2  inject tb hdec_parity
p0:c1: 0x20010a84 = 0x0002000000000000
p0:c2: 0x20010a84 = 0x0002000000000000
#

Signed-off-by: Mahesh Salgaonkar <mahesh@linux.ibm.com>
---
 Makefile.am         |    3 +
 src/err_inject.c    |   46 +++++++++++++++++++++
 src/err_inject.h    |   43 +++++++++++++++++++
 src/timefac_error.c |  114 +++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 205 insertions(+), 1 deletion(-)
 create mode 100644 src/timefac_error.c

Comments

Nicholas Piggin May 13, 2020, 5:04 a.m. UTC | #1
Hey Mahesh,

Very nice, I'm assuming adding various MCE injection should be quite 
easy when the framework is in place.

I'm handwaving a bit here because I haven't looked at pdbg's targeting 
for so long maybe it doesn't quite work so well, but what I had hoped is 
that targets would implement an ->inject_error and ->inject_error_list
that core code knows nothing about but calls directly.

Then the targets would be able to advertise exactly what they implement
and common code doesn't have these target specifics.

Thanks,
Nick

Excerpts from Mahesh Salgaonkar's message of May 11, 2020 6:41 pm:
> # ./pdbg -p0 -c3 -t3 inject
> Usage: pdbg inject <component> <error>
>  <component>:
>     ?          Show component list
>     tb
> # ./pdbg -p0 -c3 -t3 inject tb ?
> Usage: pdbg inject tb <error>:
>  <error>:
>     ?               Show error list
>     tfmr_parity     TFMR parity error
>     hdec_parity     HDEC parity error
>     tb_residue      TB parity/residue error
>     purr_parity     PURR parity error
>     spurr_parity    SPURR parity error
>     dec_parity      DEC parity error
> 
> # ./pdbg -p0 -c1 -t3  inject tb dec_parity
> p0:c1:t3: 0x20010a84 = 0x001e000000000000
> #
> # ./pdbg -p0 -c1,2  inject tb hdec_parity
> p0:c1: 0x20010a84 = 0x0002000000000000
> p0:c2: 0x20010a84 = 0x0002000000000000
> #
> 
> Signed-off-by: Mahesh Salgaonkar <mahesh@linux.ibm.com>
> ---
>  Makefile.am         |    3 +
>  src/err_inject.c    |   46 +++++++++++++++++++++
>  src/err_inject.h    |   43 +++++++++++++++++++
>  src/timefac_error.c |  114 +++++++++++++++++++++++++++++++++++++++++++++++++++
>  4 files changed, 205 insertions(+), 1 deletion(-)
>  create mode 100644 src/timefac_error.c
> 
> diff --git a/Makefile.am b/Makefile.am
> index 05522cf..ed97505 100644
> --- a/Makefile.am
> +++ b/Makefile.am
> @@ -122,7 +122,8 @@ pdbg_SOURCES = \
>  	src/util.c \
>  	src/util.h \
>  	src/err_inject.c \
> -	src/err_inject.h
> +	src/err_inject.h \
> +	src/timefac_error.c
>  
>  pdbg_CFLAGS = -I$(top_srcdir)/libpdbg -Wall -Werror -DGIT_SHA1=\"${GIT_SHA1}\" \
>  	      $(ARCH_FLAGS)
> diff --git a/src/err_inject.c b/src/err_inject.c
> index ef6bc97..c059ef8 100644
> --- a/src/err_inject.c
> +++ b/src/err_inject.c
> @@ -22,6 +22,7 @@
>  
>  #include <libpdbg.h>
>  #include <ccan/list/list.h>
> +#include <bitutils.h>
>  
>  #include "main.h"
>  #include "optcmd.h"
> @@ -162,9 +163,54 @@ static void inject_errors(char *component, char *error)
>  	}
>  }
>  
> +static char *target_short_path(struct pdbg_target *target)
> +{
> +	char result[255];
> +	char *bufp = result;
> +	int proc_index = -1, chip_index = -1, thread_index = -1;
> +	int n = 0;
> +
> +	if (get_target_type(target) == TARGET_TYPE_THREAD) {
> +		thread_index = pdbg_target_index(target);
> +		target = pdbg_target_parent("core", target);
> +	}
> +	if (get_target_type(target) == TARGET_TYPE_CORE) {
> +		chip_index = pdbg_target_index(target);
> +		target = pdbg_target_parent("pib", target);
> +	}
> +	if (get_target_type(target) == TARGET_TYPE_PROC)
> +		proc_index = pdbg_target_index(target);
> +
> +	if (proc_index >= 0)
> +		n += sprintf(bufp + n, "p%d:", proc_index);
> +	if (chip_index >= 0)
> +		n += sprintf(bufp + n, "c%d:", chip_index);
> +	if (thread_index >= 0)
> +		n += sprintf(bufp + n, "t%d:", thread_index);
> +
> +	return strdup(result);
> +}
> +
> +int target_inject_error(struct pdbg_target *target, uint32_t scom_addr,
> +							uint64_t val)
> +{
> +	char *short_path;
> +	int rc;
> +
> +	rc = pib_write(target, scom_addr, val);
> +	if (rc)
> +		return rc;
> +
> +	short_path = target_short_path(target);
> +	printf("%s 0x%x = 0x%016llx\n", short_path, scom_addr, val);
> +	free(short_path);
> +	return 0;
> +}
> +
>  static void error_inject_init(void)
>  {
>  	/* Call error inject init routines. */
> +	timefac_err_init();
>  }
>  
>  static int inject(char *component, char *error)
> diff --git a/src/err_inject.h b/src/err_inject.h
> index 76acee7..d295470 100644
> --- a/src/err_inject.h
> +++ b/src/err_inject.h
> @@ -3,6 +3,12 @@
>  
>  #include <stdint.h>
>  #include <stdbool.h>
> +#include <libpdbg.h>
> +
> +/* Target types */
> +#define TARGET_TYPE_PROC	1
> +#define TARGET_TYPE_CORE	2
> +#define TARGET_TYPE_THREAD	3
>  
>  typedef int (*inject_error_t)(struct pdbg_target *target, void *data);
>  
> @@ -17,4 +23,41 @@ typedef int (*inject_error_t)(struct pdbg_target *target, void *data);
>   */
>  extern int register_error_inject(char *component, char *error,
>  			char *error_desc, inject_error_t func, void *data);
> +
> +/* Get target type */
> +static inline int get_target_type(struct pdbg_target *target)
> +{
> +	const char *classname;
> +
> +	classname = pdbg_target_class_name(target);
> +	if (!strcmp(classname, "pib"))
> +		return TARGET_TYPE_PROC;
> +
> +	if (!strcmp(classname, "core"))
> +		return TARGET_TYPE_CORE;
> +
> +	if (!strcmp(classname, "thread"))
> +		return TARGET_TYPE_THREAD;
> +
> +	return 0;
> +}
> +
> +/**
> + * @brief Inject an error on specified target using scom addr/value.
> + * @param[in] target     pdbg target where error to be injected.
> + * @param[in] scom_adddr SCOM address to use.
> + * @param[in] val        Value to set for a given scom address.
> + *
> + * This function uses pib_write() to write to scom address and on
> + * successfull injection it prints out target short path along with
> + * scom address and data written.
> + * e.g.
> + *	p0:c1:t3: 0x20010a84 = 0x001e000000000000
> + */
> +int target_inject_error(struct pdbg_target *target, uint32_t scom_addr,
> +							uint64_t val);
> +
> +/* Error inject init functions */
> +extern void timefac_err_init(void);
> +
>  #endif
> diff --git a/src/timefac_error.c b/src/timefac_error.c
> new file mode 100644
> index 0000000..cb6c9ac
> --- /dev/null
> +++ b/src/timefac_error.c
> @@ -0,0 +1,114 @@
> +/* Copyright 2020 IBM Corp.
> + *
> + * Licensed under the Apache License, Version 2.0 (the "License");
> + * you may not use this file except in compliance with the License.
> + * You may obtain a copy of the License at
> + *
> + *	http://www.apache.org/licenses/LICENSE-2.0
> + *
> + * Unless required by applicable law or agreed to in writing, software
> + * distributed under the License is distributed on an "AS IS" BASIS,
> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
> + * implied.
> + * See the License for the specific language governing permissions and
> + * limitations under the License.
> + */
> +#include <errno.h>
> +#include <inttypes.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <assert.h>
> +
> +#include <libpdbg.h>
> +#include <ccan/list/list.h>
> +#include <ccan/array_size/array_size.h>
> +#include <bitutils.h>
> +
> +#include "main.h"
> +#include "optcmd.h"
> +#include "path.h"
> +#include "err_inject.h"
> +
> +/* SPR_MODE scom address */
> +#define P9_SCOM_SPR_MODE	0x20010A84
> +
> +/* TB Errors */
> +#define TB_ERROR_MASK		PPC_BITMASK(10, 15)
> +/* Core level TB errors */
> +#define TB_ERROR_TFMR_PARITY	0x1
> +#define TB_ERROR_HDEC_PARITY	0x2
> +#define TB_ERROR_TB_PARITY	0x3
> +/* Thread level TB errors */
> +#define TB_ERROR_PURR_PARITY	0x4
> +#define TB_ERROR_SPURR_PARITY	0x5
> +#define TB_ERROR_DEC_PARITY	0x6
> +
> +typedef struct error_type {
> +	char *name;
> +	char *desc;
> +	uint64_t error;
> +} error_type_t;
> +
> +static error_type_t tb_error_type[] = {
> +	{ "tfmr_parity", "TFMR parity error", TB_ERROR_TFMR_PARITY },
> +	{ "hdec_parity", "HDEC parity error", TB_ERROR_HDEC_PARITY },
> +	{ "tb_residue", "TB parity/residue error", TB_ERROR_TB_PARITY },
> +	{ "purr_parity", "PURR parity error", TB_ERROR_PURR_PARITY },
> +	{ "spurr_parity", "SPURR parity error", TB_ERROR_SPURR_PARITY },
> +	{ "dec_parity", "DEC parity error", TB_ERROR_DEC_PARITY },
> +};
> +
> +static int timefac_inject_tb_error(struct pdbg_target *target, void *data)
> +{
> +	int target_type = 0;
> +	uint64_t err_type;
> +	uint64_t val;
> +	uint64_t tindex;
> +	int rc;
> +
> +	err_type = *((uint64_t *)data);
> +	if (err_type < TB_ERROR_PURR_PARITY)
> +		target_type = TARGET_TYPE_CORE;
> +	else
> +		target_type = TARGET_TYPE_THREAD;
> +
> +	if (target_type != get_target_type(target))
> +		return -EINVAL;
> +
> +	/*
> +	 * TODO: Add a check for proc type p8/p9/p10 and then use scom
> +	 *       address appropriately.
> +	 */
> +	rc = pib_read(target, P9_SCOM_SPR_MODE, &val);
> +	if (rc) {
> +		/* just print the error message and continue. */
> +		printf("Failed to read scom addr: %x\n", P9_SCOM_SPR_MODE);
> +		val = 0;
> +	}
> +
> +	/* set the error type and thread index where error to be injected */
> +	if (target_type == TARGET_TYPE_THREAD) {
> +		tindex = pdbg_target_index(target);
> +		err_type |= (tindex << 3);
> +	}
> +	val = SETFIELD(TB_ERROR_MASK, val, err_type);
> +
> +	rc = target_inject_error(target, P9_SCOM_SPR_MODE, val);
> +	if (rc) {
> +		printf("Failed to inject\n");
> +	}
> +	return rc;
> +}
> +
> +void timefac_err_init(void)
> +{
> +	int i;
> +
> +	/* Register Tb error injects. */
> +	for (i = 0; i < ARRAY_SIZE(tb_error_type); i++)
> +		register_error_inject("tb", tb_error_type[i].name,
> +				tb_error_type[i].desc, timefac_inject_tb_error,
> +				&tb_error_type[i].error);
> +
> +}
> 
>
Mahesh J Salgaonkar May 26, 2020, 6:18 a.m. UTC | #2
On 2020-05-13 15:04:31 Wed, Nicholas Piggin wrote:
> Hey Mahesh,
> 
> Very nice, I'm assuming adding various MCE injection should be quite 
> easy when the framework is in place.
> 
> I'm handwaving a bit here because I haven't looked at pdbg's targeting 
> for so long maybe it doesn't quite work so well, but what I had hoped is 
> that targets would implement an ->inject_error and ->inject_error_list
> that core code knows nothing about but calls directly.

I followed the getscom/putscom way.. Let me see if I can hook this up
into target itself.

Thanks,
-Mahesh.

> 
> Then the targets would be able to advertise exactly what they implement
> and common code doesn't have these target specifics.
> 
> Thanks,
> Nick
> 
> Excerpts from Mahesh Salgaonkar's message of May 11, 2020 6:41 pm:
> > # ./pdbg -p0 -c3 -t3 inject
> > Usage: pdbg inject <component> <error>
> >  <component>:
> >     ?          Show component list
> >     tb
> > # ./pdbg -p0 -c3 -t3 inject tb ?
> > Usage: pdbg inject tb <error>:
> >  <error>:
> >     ?               Show error list
> >     tfmr_parity     TFMR parity error
> >     hdec_parity     HDEC parity error
> >     tb_residue      TB parity/residue error
> >     purr_parity     PURR parity error
> >     spurr_parity    SPURR parity error
> >     dec_parity      DEC parity error
> > 
> > # ./pdbg -p0 -c1 -t3  inject tb dec_parity
> > p0:c1:t3: 0x20010a84 = 0x001e000000000000
> > #
> > # ./pdbg -p0 -c1,2  inject tb hdec_parity
> > p0:c1: 0x20010a84 = 0x0002000000000000
> > p0:c2: 0x20010a84 = 0x0002000000000000
> > #
> > 
> > Signed-off-by: Mahesh Salgaonkar <mahesh@linux.ibm.com>
> > ---
> >  Makefile.am         |    3 +
> >  src/err_inject.c    |   46 +++++++++++++++++++++
> >  src/err_inject.h    |   43 +++++++++++++++++++
> >  src/timefac_error.c |  114 +++++++++++++++++++++++++++++++++++++++++++++++++++
> >  4 files changed, 205 insertions(+), 1 deletion(-)
> >  create mode 100644 src/timefac_error.c
> > 
> > diff --git a/Makefile.am b/Makefile.am
> > index 05522cf..ed97505 100644
> > --- a/Makefile.am
> > +++ b/Makefile.am
> > @@ -122,7 +122,8 @@ pdbg_SOURCES = \
> >  	src/util.c \
> >  	src/util.h \
> >  	src/err_inject.c \
> > -	src/err_inject.h
> > +	src/err_inject.h \
> > +	src/timefac_error.c
> >  
> >  pdbg_CFLAGS = -I$(top_srcdir)/libpdbg -Wall -Werror -DGIT_SHA1=\"${GIT_SHA1}\" \
> >  	      $(ARCH_FLAGS)
> > diff --git a/src/err_inject.c b/src/err_inject.c
> > index ef6bc97..c059ef8 100644
> > --- a/src/err_inject.c
> > +++ b/src/err_inject.c
> > @@ -22,6 +22,7 @@
> >  
> >  #include <libpdbg.h>
> >  #include <ccan/list/list.h>
> > +#include <bitutils.h>
> >  
> >  #include "main.h"
> >  #include "optcmd.h"
> > @@ -162,9 +163,54 @@ static void inject_errors(char *component, char *error)
> >  	}
> >  }
> >  
> > +static char *target_short_path(struct pdbg_target *target)
> > +{
> > +	char result[255];
> > +	char *bufp = result;
> > +	int proc_index = -1, chip_index = -1, thread_index = -1;
> > +	int n = 0;
> > +
> > +	if (get_target_type(target) == TARGET_TYPE_THREAD) {
> > +		thread_index = pdbg_target_index(target);
> > +		target = pdbg_target_parent("core", target);
> > +	}
> > +	if (get_target_type(target) == TARGET_TYPE_CORE) {
> > +		chip_index = pdbg_target_index(target);
> > +		target = pdbg_target_parent("pib", target);
> > +	}
> > +	if (get_target_type(target) == TARGET_TYPE_PROC)
> > +		proc_index = pdbg_target_index(target);
> > +
> > +	if (proc_index >= 0)
> > +		n += sprintf(bufp + n, "p%d:", proc_index);
> > +	if (chip_index >= 0)
> > +		n += sprintf(bufp + n, "c%d:", chip_index);
> > +	if (thread_index >= 0)
> > +		n += sprintf(bufp + n, "t%d:", thread_index);
> > +
> > +	return strdup(result);
> > +}
> > +
> > +int target_inject_error(struct pdbg_target *target, uint32_t scom_addr,
> > +							uint64_t val)
> > +{
> > +	char *short_path;
> > +	int rc;
> > +
> > +	rc = pib_write(target, scom_addr, val);
> > +	if (rc)
> > +		return rc;
> > +
> > +	short_path = target_short_path(target);
> > +	printf("%s 0x%x = 0x%016llx\n", short_path, scom_addr, val);
> > +	free(short_path);
> > +	return 0;
> > +}
> > +
> >  static void error_inject_init(void)
> >  {
> >  	/* Call error inject init routines. */
> > +	timefac_err_init();
> >  }
> >  
> >  static int inject(char *component, char *error)
> > diff --git a/src/err_inject.h b/src/err_inject.h
> > index 76acee7..d295470 100644
> > --- a/src/err_inject.h
> > +++ b/src/err_inject.h
> > @@ -3,6 +3,12 @@
> >  
> >  #include <stdint.h>
> >  #include <stdbool.h>
> > +#include <libpdbg.h>
> > +
> > +/* Target types */
> > +#define TARGET_TYPE_PROC	1
> > +#define TARGET_TYPE_CORE	2
> > +#define TARGET_TYPE_THREAD	3
> >  
> >  typedef int (*inject_error_t)(struct pdbg_target *target, void *data);
> >  
> > @@ -17,4 +23,41 @@ typedef int (*inject_error_t)(struct pdbg_target *target, void *data);
> >   */
> >  extern int register_error_inject(char *component, char *error,
> >  			char *error_desc, inject_error_t func, void *data);
> > +
> > +/* Get target type */
> > +static inline int get_target_type(struct pdbg_target *target)
> > +{
> > +	const char *classname;
> > +
> > +	classname = pdbg_target_class_name(target);
> > +	if (!strcmp(classname, "pib"))
> > +		return TARGET_TYPE_PROC;
> > +
> > +	if (!strcmp(classname, "core"))
> > +		return TARGET_TYPE_CORE;
> > +
> > +	if (!strcmp(classname, "thread"))
> > +		return TARGET_TYPE_THREAD;
> > +
> > +	return 0;
> > +}
> > +
> > +/**
> > + * @brief Inject an error on specified target using scom addr/value.
> > + * @param[in] target     pdbg target where error to be injected.
> > + * @param[in] scom_adddr SCOM address to use.
> > + * @param[in] val        Value to set for a given scom address.
> > + *
> > + * This function uses pib_write() to write to scom address and on
> > + * successfull injection it prints out target short path along with
> > + * scom address and data written.
> > + * e.g.
> > + *	p0:c1:t3: 0x20010a84 = 0x001e000000000000
> > + */
> > +int target_inject_error(struct pdbg_target *target, uint32_t scom_addr,
> > +							uint64_t val);
> > +
> > +/* Error inject init functions */
> > +extern void timefac_err_init(void);
> > +
> >  #endif
> > diff --git a/src/timefac_error.c b/src/timefac_error.c
> > new file mode 100644
> > index 0000000..cb6c9ac
> > --- /dev/null
> > +++ b/src/timefac_error.c
> > @@ -0,0 +1,114 @@
> > +/* Copyright 2020 IBM Corp.
> > + *
> > + * Licensed under the Apache License, Version 2.0 (the "License");
> > + * you may not use this file except in compliance with the License.
> > + * You may obtain a copy of the License at
> > + *
> > + *	http://www.apache.org/licenses/LICENSE-2.0
> > + *
> > + * Unless required by applicable law or agreed to in writing, software
> > + * distributed under the License is distributed on an "AS IS" BASIS,
> > + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
> > + * implied.
> > + * See the License for the specific language governing permissions and
> > + * limitations under the License.
> > + */
> > +#include <errno.h>
> > +#include <inttypes.h>
> > +#include <stdio.h>
> > +#include <stdlib.h>
> > +#include <string.h>
> > +#include <assert.h>
> > +
> > +#include <libpdbg.h>
> > +#include <ccan/list/list.h>
> > +#include <ccan/array_size/array_size.h>
> > +#include <bitutils.h>
> > +
> > +#include "main.h"
> > +#include "optcmd.h"
> > +#include "path.h"
> > +#include "err_inject.h"
> > +
> > +/* SPR_MODE scom address */
> > +#define P9_SCOM_SPR_MODE	0x20010A84
> > +
> > +/* TB Errors */
> > +#define TB_ERROR_MASK		PPC_BITMASK(10, 15)
> > +/* Core level TB errors */
> > +#define TB_ERROR_TFMR_PARITY	0x1
> > +#define TB_ERROR_HDEC_PARITY	0x2
> > +#define TB_ERROR_TB_PARITY	0x3
> > +/* Thread level TB errors */
> > +#define TB_ERROR_PURR_PARITY	0x4
> > +#define TB_ERROR_SPURR_PARITY	0x5
> > +#define TB_ERROR_DEC_PARITY	0x6
> > +
> > +typedef struct error_type {
> > +	char *name;
> > +	char *desc;
> > +	uint64_t error;
> > +} error_type_t;
> > +
> > +static error_type_t tb_error_type[] = {
> > +	{ "tfmr_parity", "TFMR parity error", TB_ERROR_TFMR_PARITY },
> > +	{ "hdec_parity", "HDEC parity error", TB_ERROR_HDEC_PARITY },
> > +	{ "tb_residue", "TB parity/residue error", TB_ERROR_TB_PARITY },
> > +	{ "purr_parity", "PURR parity error", TB_ERROR_PURR_PARITY },
> > +	{ "spurr_parity", "SPURR parity error", TB_ERROR_SPURR_PARITY },
> > +	{ "dec_parity", "DEC parity error", TB_ERROR_DEC_PARITY },
> > +};
> > +
> > +static int timefac_inject_tb_error(struct pdbg_target *target, void *data)
> > +{
> > +	int target_type = 0;
> > +	uint64_t err_type;
> > +	uint64_t val;
> > +	uint64_t tindex;
> > +	int rc;
> > +
> > +	err_type = *((uint64_t *)data);
> > +	if (err_type < TB_ERROR_PURR_PARITY)
> > +		target_type = TARGET_TYPE_CORE;
> > +	else
> > +		target_type = TARGET_TYPE_THREAD;
> > +
> > +	if (target_type != get_target_type(target))
> > +		return -EINVAL;
> > +
> > +	/*
> > +	 * TODO: Add a check for proc type p8/p9/p10 and then use scom
> > +	 *       address appropriately.
> > +	 */
> > +	rc = pib_read(target, P9_SCOM_SPR_MODE, &val);
> > +	if (rc) {
> > +		/* just print the error message and continue. */
> > +		printf("Failed to read scom addr: %x\n", P9_SCOM_SPR_MODE);
> > +		val = 0;
> > +	}
> > +
> > +	/* set the error type and thread index where error to be injected */
> > +	if (target_type == TARGET_TYPE_THREAD) {
> > +		tindex = pdbg_target_index(target);
> > +		err_type |= (tindex << 3);
> > +	}
> > +	val = SETFIELD(TB_ERROR_MASK, val, err_type);
> > +
> > +	rc = target_inject_error(target, P9_SCOM_SPR_MODE, val);
> > +	if (rc) {
> > +		printf("Failed to inject\n");
> > +	}
> > +	return rc;
> > +}
> > +
> > +void timefac_err_init(void)
> > +{
> > +	int i;
> > +
> > +	/* Register Tb error injects. */
> > +	for (i = 0; i < ARRAY_SIZE(tb_error_type); i++)
> > +		register_error_inject("tb", tb_error_type[i].name,
> > +				tb_error_type[i].desc, timefac_inject_tb_error,
> > +				&tb_error_type[i].error);
> > +
> > +}
> > 
> >
Alistair Popple May 26, 2020, 6:21 a.m. UTC | #3
Sorry, I meant to get to this earlier but Nick's idea seems worth 
investigating. We could add ->inject_error and ->inject_error_list to the 
struct pdbg_target which would allow us to add recipes for injecting errors on 
any target that supports them which would be nice.

- Alistair

On Tuesday, 26 May 2020 4:18:21 PM AEST Mahesh J Salgaonkar wrote:
> On 2020-05-13 15:04:31 Wed, Nicholas Piggin wrote:
> > Hey Mahesh,
> > 
> > Very nice, I'm assuming adding various MCE injection should be quite
> > easy when the framework is in place.
> > 
> > I'm handwaving a bit here because I haven't looked at pdbg's targeting
> > for so long maybe it doesn't quite work so well, but what I had hoped is
> > that targets would implement an ->inject_error and ->inject_error_list
> > that core code knows nothing about but calls directly.
> 
> I followed the getscom/putscom way.. Let me see if I can hook this up
> into target itself.
> 
> Thanks,
> -Mahesh.
> 
> > Then the targets would be able to advertise exactly what they implement
> > and common code doesn't have these target specifics.
> > 
> > Thanks,
> > Nick
> > 
> > Excerpts from Mahesh Salgaonkar's message of May 11, 2020 6:41 pm:
> > > # ./pdbg -p0 -c3 -t3 inject
> > > Usage: pdbg inject <component> <error>
> > > 
> > >  <component>:
> > >     ?          Show component list
> > >     tb
> > > 
> > > # ./pdbg -p0 -c3 -t3 inject tb ?
> > > 
> > > Usage: pdbg inject tb <error>:
> > >  <error>:
> > >     ?               Show error list
> > >     tfmr_parity     TFMR parity error
> > >     hdec_parity     HDEC parity error
> > >     tb_residue      TB parity/residue error
> > >     purr_parity     PURR parity error
> > >     spurr_parity    SPURR parity error
> > >     dec_parity      DEC parity error
> > > 
> > > # ./pdbg -p0 -c1 -t3  inject tb dec_parity
> > > p0:c1:t3: 0x20010a84 = 0x001e000000000000
> > > #
> > > # ./pdbg -p0 -c1,2  inject tb hdec_parity
> > > p0:c1: 0x20010a84 = 0x0002000000000000
> > > p0:c2: 0x20010a84 = 0x0002000000000000
> > > #
> > > 
> > > Signed-off-by: Mahesh Salgaonkar <mahesh@linux.ibm.com>
> > > ---
> > > 
> > >  Makefile.am         |    3 +
> > >  src/err_inject.c    |   46 +++++++++++++++++++++
> > >  src/err_inject.h    |   43 +++++++++++++++++++
> > >  src/timefac_error.c |  114
> > >  +++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed,
> > >  205 insertions(+), 1 deletion(-)
> > >  create mode 100644 src/timefac_error.c
> > > 
> > > diff --git a/Makefile.am b/Makefile.am
> > > index 05522cf..ed97505 100644
> > > --- a/Makefile.am
> > > +++ b/Makefile.am
> > > @@ -122,7 +122,8 @@ pdbg_SOURCES = \
> > > 
> > >  	src/util.c \
> > >  	src/util.h \
> > >  	src/err_inject.c \
> > > 
> > > -	src/err_inject.h
> > > +	src/err_inject.h \
> > > +	src/timefac_error.c
> > > 
> > >  pdbg_CFLAGS = -I$(top_srcdir)/libpdbg -Wall -Werror
> > >  -DGIT_SHA1=\"${GIT_SHA1}\" \> >  
> > >  	      $(ARCH_FLAGS)
> > > 
> > > diff --git a/src/err_inject.c b/src/err_inject.c
> > > index ef6bc97..c059ef8 100644
> > > --- a/src/err_inject.c
> > > +++ b/src/err_inject.c
> > > @@ -22,6 +22,7 @@
> > > 
> > >  #include <libpdbg.h>
> > >  #include <ccan/list/list.h>
> > > 
> > > +#include <bitutils.h>
> > > 
> > >  #include "main.h"
> > >  #include "optcmd.h"
> > > 
> > > @@ -162,9 +163,54 @@ static void inject_errors(char *component, char
> > > *error)> > 
> > >  	}
> > >  
> > >  }
> > > 
> > > +static char *target_short_path(struct pdbg_target *target)
> > > +{
> > > +	char result[255];
> > > +	char *bufp = result;
> > > +	int proc_index = -1, chip_index = -1, thread_index = -1;
> > > +	int n = 0;
> > > +
> > > +	if (get_target_type(target) == TARGET_TYPE_THREAD) {
> > > +		thread_index = pdbg_target_index(target);
> > > +		target = pdbg_target_parent("core", target);
> > > +	}
> > > +	if (get_target_type(target) == TARGET_TYPE_CORE) {
> > > +		chip_index = pdbg_target_index(target);
> > > +		target = pdbg_target_parent("pib", target);
> > > +	}
> > > +	if (get_target_type(target) == TARGET_TYPE_PROC)
> > > +		proc_index = pdbg_target_index(target);
> > > +
> > > +	if (proc_index >= 0)
> > > +		n += sprintf(bufp + n, "p%d:", proc_index);
> > > +	if (chip_index >= 0)
> > > +		n += sprintf(bufp + n, "c%d:", chip_index);
> > > +	if (thread_index >= 0)
> > > +		n += sprintf(bufp + n, "t%d:", thread_index);
> > > +
> > > +	return strdup(result);
> > > +}
> > > +
> > > +int target_inject_error(struct pdbg_target *target, uint32_t scom_addr,
> > > +							uint64_t val)
> > > +{
> > > +	char *short_path;
> > > +	int rc;
> > > +
> > > +	rc = pib_write(target, scom_addr, val);
> > > +	if (rc)
> > > +		return rc;
> > > +
> > > +	short_path = target_short_path(target);
> > > +	printf("%s 0x%x = 0x%016llx\n", short_path, scom_addr, val);
> > > +	free(short_path);
> > > +	return 0;
> > > +}
> > > +
> > > 
> > >  static void error_inject_init(void)
> > >  {
> > >  
> > >  	/* Call error inject init routines. */
> > > 
> > > +	timefac_err_init();
> > > 
> > >  }
> > >  
> > >  static int inject(char *component, char *error)
> > > 
> > > diff --git a/src/err_inject.h b/src/err_inject.h
> > > index 76acee7..d295470 100644
> > > --- a/src/err_inject.h
> > > +++ b/src/err_inject.h
> > > @@ -3,6 +3,12 @@
> > > 
> > >  #include <stdint.h>
> > >  #include <stdbool.h>
> > > 
> > > +#include <libpdbg.h>
> > > +
> > > +/* Target types */
> > > +#define TARGET_TYPE_PROC	1
> > > +#define TARGET_TYPE_CORE	2
> > > +#define TARGET_TYPE_THREAD	3
> > > 
> > >  typedef int (*inject_error_t)(struct pdbg_target *target, void *data);
> > > 
> > > @@ -17,4 +23,41 @@ typedef int (*inject_error_t)(struct pdbg_target
> > > *target, void *data);> > 
> > >   */
> > >  
> > >  extern int register_error_inject(char *component, char *error,
> > >  
> > >  			char *error_desc, inject_error_t func, void *data);
> > > 
> > > +
> > > +/* Get target type */
> > > +static inline int get_target_type(struct pdbg_target *target)
> > > +{
> > > +	const char *classname;
> > > +
> > > +	classname = pdbg_target_class_name(target);
> > > +	if (!strcmp(classname, "pib"))
> > > +		return TARGET_TYPE_PROC;
> > > +
> > > +	if (!strcmp(classname, "core"))
> > > +		return TARGET_TYPE_CORE;
> > > +
> > > +	if (!strcmp(classname, "thread"))
> > > +		return TARGET_TYPE_THREAD;
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +/**
> > > + * @brief Inject an error on specified target using scom addr/value.
> > > + * @param[in] target     pdbg target where error to be injected.
> > > + * @param[in] scom_adddr SCOM address to use.
> > > + * @param[in] val        Value to set for a given scom address.
> > > + *
> > > + * This function uses pib_write() to write to scom address and on
> > > + * successfull injection it prints out target short path along with
> > > + * scom address and data written.
> > > + * e.g.
> > > + *	p0:c1:t3: 0x20010a84 = 0x001e000000000000
> > > + */
> > > +int target_inject_error(struct pdbg_target *target, uint32_t scom_addr,
> > > +							uint64_t val);
> > > +
> > > +/* Error inject init functions */
> > > +extern void timefac_err_init(void);
> > > +
> > > 
> > >  #endif
> > > 
> > > diff --git a/src/timefac_error.c b/src/timefac_error.c
> > > new file mode 100644
> > > index 0000000..cb6c9ac
> > > --- /dev/null
> > > +++ b/src/timefac_error.c
> > > @@ -0,0 +1,114 @@
> > > +/* Copyright 2020 IBM Corp.
> > > + *
> > > + * Licensed under the Apache License, Version 2.0 (the "License");
> > > + * you may not use this file except in compliance with the License.
> > > + * You may obtain a copy of the License at
> > > + *
> > > + *	http://www.apache.org/licenses/LICENSE-2.0
> > > + *
> > > + * Unless required by applicable law or agreed to in writing, software
> > > + * distributed under the License is distributed on an "AS IS" BASIS,
> > > + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
> > > + * implied.
> > > + * See the License for the specific language governing permissions and
> > > + * limitations under the License.
> > > + */
> > > +#include <errno.h>
> > > +#include <inttypes.h>
> > > +#include <stdio.h>
> > > +#include <stdlib.h>
> > > +#include <string.h>
> > > +#include <assert.h>
> > > +
> > > +#include <libpdbg.h>
> > > +#include <ccan/list/list.h>
> > > +#include <ccan/array_size/array_size.h>
> > > +#include <bitutils.h>
> > > +
> > > +#include "main.h"
> > > +#include "optcmd.h"
> > > +#include "path.h"
> > > +#include "err_inject.h"
> > > +
> > > +/* SPR_MODE scom address */
> > > +#define P9_SCOM_SPR_MODE	0x20010A84
> > > +
> > > +/* TB Errors */
> > > +#define TB_ERROR_MASK		PPC_BITMASK(10, 15)
> > > +/* Core level TB errors */
> > > +#define TB_ERROR_TFMR_PARITY	0x1
> > > +#define TB_ERROR_HDEC_PARITY	0x2
> > > +#define TB_ERROR_TB_PARITY	0x3
> > > +/* Thread level TB errors */
> > > +#define TB_ERROR_PURR_PARITY	0x4
> > > +#define TB_ERROR_SPURR_PARITY	0x5
> > > +#define TB_ERROR_DEC_PARITY	0x6
> > > +
> > > +typedef struct error_type {
> > > +	char *name;
> > > +	char *desc;
> > > +	uint64_t error;
> > > +} error_type_t;
> > > +
> > > +static error_type_t tb_error_type[] = {
> > > +	{ "tfmr_parity", "TFMR parity error", TB_ERROR_TFMR_PARITY },
> > > +	{ "hdec_parity", "HDEC parity error", TB_ERROR_HDEC_PARITY },
> > > +	{ "tb_residue", "TB parity/residue error", TB_ERROR_TB_PARITY },
> > > +	{ "purr_parity", "PURR parity error", TB_ERROR_PURR_PARITY },
> > > +	{ "spurr_parity", "SPURR parity error", TB_ERROR_SPURR_PARITY },
> > > +	{ "dec_parity", "DEC parity error", TB_ERROR_DEC_PARITY },
> > > +};
> > > +
> > > +static int timefac_inject_tb_error(struct pdbg_target *target, void
> > > *data)
> > > +{
> > > +	int target_type = 0;
> > > +	uint64_t err_type;
> > > +	uint64_t val;
> > > +	uint64_t tindex;
> > > +	int rc;
> > > +
> > > +	err_type = *((uint64_t *)data);
> > > +	if (err_type < TB_ERROR_PURR_PARITY)
> > > +		target_type = TARGET_TYPE_CORE;
> > > +	else
> > > +		target_type = TARGET_TYPE_THREAD;
> > > +
> > > +	if (target_type != get_target_type(target))
> > > +		return -EINVAL;
> > > +
> > > +	/*
> > > +	 * TODO: Add a check for proc type p8/p9/p10 and then use scom
> > > +	 *       address appropriately.
> > > +	 */
> > > +	rc = pib_read(target, P9_SCOM_SPR_MODE, &val);
> > > +	if (rc) {
> > > +		/* just print the error message and continue. */
> > > +		printf("Failed to read scom addr: %x\n", P9_SCOM_SPR_MODE);
> > > +		val = 0;
> > > +	}
> > > +
> > > +	/* set the error type and thread index where error to be injected */
> > > +	if (target_type == TARGET_TYPE_THREAD) {
> > > +		tindex = pdbg_target_index(target);
> > > +		err_type |= (tindex << 3);
> > > +	}
> > > +	val = SETFIELD(TB_ERROR_MASK, val, err_type);
> > > +
> > > +	rc = target_inject_error(target, P9_SCOM_SPR_MODE, val);
> > > +	if (rc) {
> > > +		printf("Failed to inject\n");
> > > +	}
> > > +	return rc;
> > > +}
> > > +
> > > +void timefac_err_init(void)
> > > +{
> > > +	int i;
> > > +
> > > +	/* Register Tb error injects. */
> > > +	for (i = 0; i < ARRAY_SIZE(tb_error_type); i++)
> > > +		register_error_inject("tb", tb_error_type[i].name,
> > > +				tb_error_type[i].desc, timefac_inject_tb_error,
> > > +				&tb_error_type[i].error);
> > > +
> > > +}
Mahesh J Salgaonkar May 26, 2020, 6:30 a.m. UTC | #4
On 2020-05-26 16:21:44 Tue, Alistair Popple wrote:
> Sorry, I meant to get to this earlier but Nick's idea seems worth 
> investigating. We could add ->inject_error and ->inject_error_list to the 
> struct pdbg_target which would allow us to add recipes for injecting errors on 
> any target that supports them which would be nice.

Yup I agree. I was on leave last week. I will take look and try to hook
this into target (struct pdbg_target ) itself.

Thanks,
-Mahesh.

> 
> - Alistair
> 
> On Tuesday, 26 May 2020 4:18:21 PM AEST Mahesh J Salgaonkar wrote:
> > On 2020-05-13 15:04:31 Wed, Nicholas Piggin wrote:
> > > Hey Mahesh,
> > > 
> > > Very nice, I'm assuming adding various MCE injection should be quite
> > > easy when the framework is in place.
> > > 
> > > I'm handwaving a bit here because I haven't looked at pdbg's targeting
> > > for so long maybe it doesn't quite work so well, but what I had hoped is
> > > that targets would implement an ->inject_error and ->inject_error_list
> > > that core code knows nothing about but calls directly.
> > 
> > I followed the getscom/putscom way.. Let me see if I can hook this up
> > into target itself.
> > 
> > Thanks,
> > -Mahesh.
> > 
> > > Then the targets would be able to advertise exactly what they implement
> > > and common code doesn't have these target specifics.
> > > 
> > > Thanks,
> > > Nick
> > > 
> > > Excerpts from Mahesh Salgaonkar's message of May 11, 2020 6:41 pm:
> > > > # ./pdbg -p0 -c3 -t3 inject
> > > > Usage: pdbg inject <component> <error>
> > > > 
> > > >  <component>:
> > > >     ?          Show component list
> > > >     tb
> > > > 
> > > > # ./pdbg -p0 -c3 -t3 inject tb ?
> > > > 
> > > > Usage: pdbg inject tb <error>:
> > > >  <error>:
> > > >     ?               Show error list
> > > >     tfmr_parity     TFMR parity error
> > > >     hdec_parity     HDEC parity error
> > > >     tb_residue      TB parity/residue error
> > > >     purr_parity     PURR parity error
> > > >     spurr_parity    SPURR parity error
> > > >     dec_parity      DEC parity error
> > > > 
> > > > # ./pdbg -p0 -c1 -t3  inject tb dec_parity
> > > > p0:c1:t3: 0x20010a84 = 0x001e000000000000
> > > > #
> > > > # ./pdbg -p0 -c1,2  inject tb hdec_parity
> > > > p0:c1: 0x20010a84 = 0x0002000000000000
> > > > p0:c2: 0x20010a84 = 0x0002000000000000
> > > > #
> > > > 
> > > > Signed-off-by: Mahesh Salgaonkar <mahesh@linux.ibm.com>
> > > > ---
> > > > 
> > > >  Makefile.am         |    3 +
> > > >  src/err_inject.c    |   46 +++++++++++++++++++++
> > > >  src/err_inject.h    |   43 +++++++++++++++++++
> > > >  src/timefac_error.c |  114
> > > >  +++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed,
> > > >  205 insertions(+), 1 deletion(-)
> > > >  create mode 100644 src/timefac_error.c
> > > > 
> > > > diff --git a/Makefile.am b/Makefile.am
> > > > index 05522cf..ed97505 100644
> > > > --- a/Makefile.am
> > > > +++ b/Makefile.am
> > > > @@ -122,7 +122,8 @@ pdbg_SOURCES = \
> > > > 
> > > >  	src/util.c \
> > > >  	src/util.h \
> > > >  	src/err_inject.c \
> > > > 
> > > > -	src/err_inject.h
> > > > +	src/err_inject.h \
> > > > +	src/timefac_error.c
> > > > 
> > > >  pdbg_CFLAGS = -I$(top_srcdir)/libpdbg -Wall -Werror
> > > >  -DGIT_SHA1=\"${GIT_SHA1}\" \> >  
> > > >  	      $(ARCH_FLAGS)
> > > > 
> > > > diff --git a/src/err_inject.c b/src/err_inject.c
> > > > index ef6bc97..c059ef8 100644
> > > > --- a/src/err_inject.c
> > > > +++ b/src/err_inject.c
> > > > @@ -22,6 +22,7 @@
> > > > 
> > > >  #include <libpdbg.h>
> > > >  #include <ccan/list/list.h>
> > > > 
> > > > +#include <bitutils.h>
> > > > 
> > > >  #include "main.h"
> > > >  #include "optcmd.h"
> > > > 
> > > > @@ -162,9 +163,54 @@ static void inject_errors(char *component, char
> > > > *error)> > 
> > > >  	}
> > > >  
> > > >  }
> > > > 
> > > > +static char *target_short_path(struct pdbg_target *target)
> > > > +{
> > > > +	char result[255];
> > > > +	char *bufp = result;
> > > > +	int proc_index = -1, chip_index = -1, thread_index = -1;
> > > > +	int n = 0;
> > > > +
> > > > +	if (get_target_type(target) == TARGET_TYPE_THREAD) {
> > > > +		thread_index = pdbg_target_index(target);
> > > > +		target = pdbg_target_parent("core", target);
> > > > +	}
> > > > +	if (get_target_type(target) == TARGET_TYPE_CORE) {
> > > > +		chip_index = pdbg_target_index(target);
> > > > +		target = pdbg_target_parent("pib", target);
> > > > +	}
> > > > +	if (get_target_type(target) == TARGET_TYPE_PROC)
> > > > +		proc_index = pdbg_target_index(target);
> > > > +
> > > > +	if (proc_index >= 0)
> > > > +		n += sprintf(bufp + n, "p%d:", proc_index);
> > > > +	if (chip_index >= 0)
> > > > +		n += sprintf(bufp + n, "c%d:", chip_index);
> > > > +	if (thread_index >= 0)
> > > > +		n += sprintf(bufp + n, "t%d:", thread_index);
> > > > +
> > > > +	return strdup(result);
> > > > +}
> > > > +
> > > > +int target_inject_error(struct pdbg_target *target, uint32_t scom_addr,
> > > > +							uint64_t val)
> > > > +{
> > > > +	char *short_path;
> > > > +	int rc;
> > > > +
> > > > +	rc = pib_write(target, scom_addr, val);
> > > > +	if (rc)
> > > > +		return rc;
> > > > +
> > > > +	short_path = target_short_path(target);
> > > > +	printf("%s 0x%x = 0x%016llx\n", short_path, scom_addr, val);
> > > > +	free(short_path);
> > > > +	return 0;
> > > > +}
> > > > +
> > > > 
> > > >  static void error_inject_init(void)
> > > >  {
> > > >  
> > > >  	/* Call error inject init routines. */
> > > > 
> > > > +	timefac_err_init();
> > > > 
> > > >  }
> > > >  
> > > >  static int inject(char *component, char *error)
> > > > 
> > > > diff --git a/src/err_inject.h b/src/err_inject.h
> > > > index 76acee7..d295470 100644
> > > > --- a/src/err_inject.h
> > > > +++ b/src/err_inject.h
> > > > @@ -3,6 +3,12 @@
> > > > 
> > > >  #include <stdint.h>
> > > >  #include <stdbool.h>
> > > > 
> > > > +#include <libpdbg.h>
> > > > +
> > > > +/* Target types */
> > > > +#define TARGET_TYPE_PROC	1
> > > > +#define TARGET_TYPE_CORE	2
> > > > +#define TARGET_TYPE_THREAD	3
> > > > 
> > > >  typedef int (*inject_error_t)(struct pdbg_target *target, void *data);
> > > > 
> > > > @@ -17,4 +23,41 @@ typedef int (*inject_error_t)(struct pdbg_target
> > > > *target, void *data);> > 
> > > >   */
> > > >  
> > > >  extern int register_error_inject(char *component, char *error,
> > > >  
> > > >  			char *error_desc, inject_error_t func, void *data);
> > > > 
> > > > +
> > > > +/* Get target type */
> > > > +static inline int get_target_type(struct pdbg_target *target)
> > > > +{
> > > > +	const char *classname;
> > > > +
> > > > +	classname = pdbg_target_class_name(target);
> > > > +	if (!strcmp(classname, "pib"))
> > > > +		return TARGET_TYPE_PROC;
> > > > +
> > > > +	if (!strcmp(classname, "core"))
> > > > +		return TARGET_TYPE_CORE;
> > > > +
> > > > +	if (!strcmp(classname, "thread"))
> > > > +		return TARGET_TYPE_THREAD;
> > > > +
> > > > +	return 0;
> > > > +}
> > > > +
> > > > +/**
> > > > + * @brief Inject an error on specified target using scom addr/value.
> > > > + * @param[in] target     pdbg target where error to be injected.
> > > > + * @param[in] scom_adddr SCOM address to use.
> > > > + * @param[in] val        Value to set for a given scom address.
> > > > + *
> > > > + * This function uses pib_write() to write to scom address and on
> > > > + * successfull injection it prints out target short path along with
> > > > + * scom address and data written.
> > > > + * e.g.
> > > > + *	p0:c1:t3: 0x20010a84 = 0x001e000000000000
> > > > + */
> > > > +int target_inject_error(struct pdbg_target *target, uint32_t scom_addr,
> > > > +							uint64_t val);
> > > > +
> > > > +/* Error inject init functions */
> > > > +extern void timefac_err_init(void);
> > > > +
> > > > 
> > > >  #endif
> > > > 
> > > > diff --git a/src/timefac_error.c b/src/timefac_error.c
> > > > new file mode 100644
> > > > index 0000000..cb6c9ac
> > > > --- /dev/null
> > > > +++ b/src/timefac_error.c
> > > > @@ -0,0 +1,114 @@
> > > > +/* Copyright 2020 IBM Corp.
> > > > + *
> > > > + * Licensed under the Apache License, Version 2.0 (the "License");
> > > > + * you may not use this file except in compliance with the License.
> > > > + * You may obtain a copy of the License at
> > > > + *
> > > > + *	http://www.apache.org/licenses/LICENSE-2.0
> > > > + *
> > > > + * Unless required by applicable law or agreed to in writing, software
> > > > + * distributed under the License is distributed on an "AS IS" BASIS,
> > > > + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
> > > > + * implied.
> > > > + * See the License for the specific language governing permissions and
> > > > + * limitations under the License.
> > > > + */
> > > > +#include <errno.h>
> > > > +#include <inttypes.h>
> > > > +#include <stdio.h>
> > > > +#include <stdlib.h>
> > > > +#include <string.h>
> > > > +#include <assert.h>
> > > > +
> > > > +#include <libpdbg.h>
> > > > +#include <ccan/list/list.h>
> > > > +#include <ccan/array_size/array_size.h>
> > > > +#include <bitutils.h>
> > > > +
> > > > +#include "main.h"
> > > > +#include "optcmd.h"
> > > > +#include "path.h"
> > > > +#include "err_inject.h"
> > > > +
> > > > +/* SPR_MODE scom address */
> > > > +#define P9_SCOM_SPR_MODE	0x20010A84
> > > > +
> > > > +/* TB Errors */
> > > > +#define TB_ERROR_MASK		PPC_BITMASK(10, 15)
> > > > +/* Core level TB errors */
> > > > +#define TB_ERROR_TFMR_PARITY	0x1
> > > > +#define TB_ERROR_HDEC_PARITY	0x2
> > > > +#define TB_ERROR_TB_PARITY	0x3
> > > > +/* Thread level TB errors */
> > > > +#define TB_ERROR_PURR_PARITY	0x4
> > > > +#define TB_ERROR_SPURR_PARITY	0x5
> > > > +#define TB_ERROR_DEC_PARITY	0x6
> > > > +
> > > > +typedef struct error_type {
> > > > +	char *name;
> > > > +	char *desc;
> > > > +	uint64_t error;
> > > > +} error_type_t;
> > > > +
> > > > +static error_type_t tb_error_type[] = {
> > > > +	{ "tfmr_parity", "TFMR parity error", TB_ERROR_TFMR_PARITY },
> > > > +	{ "hdec_parity", "HDEC parity error", TB_ERROR_HDEC_PARITY },
> > > > +	{ "tb_residue", "TB parity/residue error", TB_ERROR_TB_PARITY },
> > > > +	{ "purr_parity", "PURR parity error", TB_ERROR_PURR_PARITY },
> > > > +	{ "spurr_parity", "SPURR parity error", TB_ERROR_SPURR_PARITY },
> > > > +	{ "dec_parity", "DEC parity error", TB_ERROR_DEC_PARITY },
> > > > +};
> > > > +
> > > > +static int timefac_inject_tb_error(struct pdbg_target *target, void
> > > > *data)
> > > > +{
> > > > +	int target_type = 0;
> > > > +	uint64_t err_type;
> > > > +	uint64_t val;
> > > > +	uint64_t tindex;
> > > > +	int rc;
> > > > +
> > > > +	err_type = *((uint64_t *)data);
> > > > +	if (err_type < TB_ERROR_PURR_PARITY)
> > > > +		target_type = TARGET_TYPE_CORE;
> > > > +	else
> > > > +		target_type = TARGET_TYPE_THREAD;
> > > > +
> > > > +	if (target_type != get_target_type(target))
> > > > +		return -EINVAL;
> > > > +
> > > > +	/*
> > > > +	 * TODO: Add a check for proc type p8/p9/p10 and then use scom
> > > > +	 *       address appropriately.
> > > > +	 */
> > > > +	rc = pib_read(target, P9_SCOM_SPR_MODE, &val);
> > > > +	if (rc) {
> > > > +		/* just print the error message and continue. */
> > > > +		printf("Failed to read scom addr: %x\n", P9_SCOM_SPR_MODE);
> > > > +		val = 0;
> > > > +	}
> > > > +
> > > > +	/* set the error type and thread index where error to be injected */
> > > > +	if (target_type == TARGET_TYPE_THREAD) {
> > > > +		tindex = pdbg_target_index(target);
> > > > +		err_type |= (tindex << 3);
> > > > +	}
> > > > +	val = SETFIELD(TB_ERROR_MASK, val, err_type);
> > > > +
> > > > +	rc = target_inject_error(target, P9_SCOM_SPR_MODE, val);
> > > > +	if (rc) {
> > > > +		printf("Failed to inject\n");
> > > > +	}
> > > > +	return rc;
> > > > +}
> > > > +
> > > > +void timefac_err_init(void)
> > > > +{
> > > > +	int i;
> > > > +
> > > > +	/* Register Tb error injects. */
> > > > +	for (i = 0; i < ARRAY_SIZE(tb_error_type); i++)
> > > > +		register_error_inject("tb", tb_error_type[i].name,
> > > > +				tb_error_type[i].desc, timefac_inject_tb_error,
> > > > +				&tb_error_type[i].error);
> > > > +
> > > > +}
> 
> 
> 
>
diff mbox series

Patch

diff --git a/Makefile.am b/Makefile.am
index 05522cf..ed97505 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -122,7 +122,8 @@  pdbg_SOURCES = \
 	src/util.c \
 	src/util.h \
 	src/err_inject.c \
-	src/err_inject.h
+	src/err_inject.h \
+	src/timefac_error.c
 
 pdbg_CFLAGS = -I$(top_srcdir)/libpdbg -Wall -Werror -DGIT_SHA1=\"${GIT_SHA1}\" \
 	      $(ARCH_FLAGS)
diff --git a/src/err_inject.c b/src/err_inject.c
index ef6bc97..c059ef8 100644
--- a/src/err_inject.c
+++ b/src/err_inject.c
@@ -22,6 +22,7 @@ 
 
 #include <libpdbg.h>
 #include <ccan/list/list.h>
+#include <bitutils.h>
 
 #include "main.h"
 #include "optcmd.h"
@@ -162,9 +163,54 @@  static void inject_errors(char *component, char *error)
 	}
 }
 
+static char *target_short_path(struct pdbg_target *target)
+{
+	char result[255];
+	char *bufp = result;
+	int proc_index = -1, chip_index = -1, thread_index = -1;
+	int n = 0;
+
+	if (get_target_type(target) == TARGET_TYPE_THREAD) {
+		thread_index = pdbg_target_index(target);
+		target = pdbg_target_parent("core", target);
+	}
+	if (get_target_type(target) == TARGET_TYPE_CORE) {
+		chip_index = pdbg_target_index(target);
+		target = pdbg_target_parent("pib", target);
+	}
+	if (get_target_type(target) == TARGET_TYPE_PROC)
+		proc_index = pdbg_target_index(target);
+
+	if (proc_index >= 0)
+		n += sprintf(bufp + n, "p%d:", proc_index);
+	if (chip_index >= 0)
+		n += sprintf(bufp + n, "c%d:", chip_index);
+	if (thread_index >= 0)
+		n += sprintf(bufp + n, "t%d:", thread_index);
+
+	return strdup(result);
+}
+
+int target_inject_error(struct pdbg_target *target, uint32_t scom_addr,
+							uint64_t val)
+{
+	char *short_path;
+	int rc;
+
+	rc = pib_write(target, scom_addr, val);
+	if (rc)
+		return rc;
+
+	short_path = target_short_path(target);
+	printf("%s 0x%x = 0x%016llx\n", short_path, scom_addr, val);
+	free(short_path);
+	return 0;
+}
+
 static void error_inject_init(void)
 {
 	/* Call error inject init routines. */
+	timefac_err_init();
 }
 
 static int inject(char *component, char *error)
diff --git a/src/err_inject.h b/src/err_inject.h
index 76acee7..d295470 100644
--- a/src/err_inject.h
+++ b/src/err_inject.h
@@ -3,6 +3,12 @@ 
 
 #include <stdint.h>
 #include <stdbool.h>
+#include <libpdbg.h>
+
+/* Target types */
+#define TARGET_TYPE_PROC	1
+#define TARGET_TYPE_CORE	2
+#define TARGET_TYPE_THREAD	3
 
 typedef int (*inject_error_t)(struct pdbg_target *target, void *data);
 
@@ -17,4 +23,41 @@  typedef int (*inject_error_t)(struct pdbg_target *target, void *data);
  */
 extern int register_error_inject(char *component, char *error,
 			char *error_desc, inject_error_t func, void *data);
+
+/* Get target type */
+static inline int get_target_type(struct pdbg_target *target)
+{
+	const char *classname;
+
+	classname = pdbg_target_class_name(target);
+	if (!strcmp(classname, "pib"))
+		return TARGET_TYPE_PROC;
+
+	if (!strcmp(classname, "core"))
+		return TARGET_TYPE_CORE;
+
+	if (!strcmp(classname, "thread"))
+		return TARGET_TYPE_THREAD;
+
+	return 0;
+}
+
+/**
+ * @brief Inject an error on specified target using scom addr/value.
+ * @param[in] target     pdbg target where error to be injected.
+ * @param[in] scom_adddr SCOM address to use.
+ * @param[in] val        Value to set for a given scom address.
+ *
+ * This function uses pib_write() to write to scom address and on
+ * successfull injection it prints out target short path along with
+ * scom address and data written.
+ * e.g.
+ *	p0:c1:t3: 0x20010a84 = 0x001e000000000000
+ */
+int target_inject_error(struct pdbg_target *target, uint32_t scom_addr,
+							uint64_t val);
+
+/* Error inject init functions */
+extern void timefac_err_init(void);
+
 #endif
diff --git a/src/timefac_error.c b/src/timefac_error.c
new file mode 100644
index 0000000..cb6c9ac
--- /dev/null
+++ b/src/timefac_error.c
@@ -0,0 +1,114 @@ 
+/* Copyright 2020 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *	http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <errno.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include <libpdbg.h>
+#include <ccan/list/list.h>
+#include <ccan/array_size/array_size.h>
+#include <bitutils.h>
+
+#include "main.h"
+#include "optcmd.h"
+#include "path.h"
+#include "err_inject.h"
+
+/* SPR_MODE scom address */
+#define P9_SCOM_SPR_MODE	0x20010A84
+
+/* TB Errors */
+#define TB_ERROR_MASK		PPC_BITMASK(10, 15)
+/* Core level TB errors */
+#define TB_ERROR_TFMR_PARITY	0x1
+#define TB_ERROR_HDEC_PARITY	0x2
+#define TB_ERROR_TB_PARITY	0x3
+/* Thread level TB errors */
+#define TB_ERROR_PURR_PARITY	0x4
+#define TB_ERROR_SPURR_PARITY	0x5
+#define TB_ERROR_DEC_PARITY	0x6
+
+typedef struct error_type {
+	char *name;
+	char *desc;
+	uint64_t error;
+} error_type_t;
+
+static error_type_t tb_error_type[] = {
+	{ "tfmr_parity", "TFMR parity error", TB_ERROR_TFMR_PARITY },
+	{ "hdec_parity", "HDEC parity error", TB_ERROR_HDEC_PARITY },
+	{ "tb_residue", "TB parity/residue error", TB_ERROR_TB_PARITY },
+	{ "purr_parity", "PURR parity error", TB_ERROR_PURR_PARITY },
+	{ "spurr_parity", "SPURR parity error", TB_ERROR_SPURR_PARITY },
+	{ "dec_parity", "DEC parity error", TB_ERROR_DEC_PARITY },
+};
+
+static int timefac_inject_tb_error(struct pdbg_target *target, void *data)
+{
+	int target_type = 0;
+	uint64_t err_type;
+	uint64_t val;
+	uint64_t tindex;
+	int rc;
+
+	err_type = *((uint64_t *)data);
+	if (err_type < TB_ERROR_PURR_PARITY)
+		target_type = TARGET_TYPE_CORE;
+	else
+		target_type = TARGET_TYPE_THREAD;
+
+	if (target_type != get_target_type(target))
+		return -EINVAL;
+
+	/*
+	 * TODO: Add a check for proc type p8/p9/p10 and then use scom
+	 *       address appropriately.
+	 */
+	rc = pib_read(target, P9_SCOM_SPR_MODE, &val);
+	if (rc) {
+		/* just print the error message and continue. */
+		printf("Failed to read scom addr: %x\n", P9_SCOM_SPR_MODE);
+		val = 0;
+	}
+
+	/* set the error type and thread index where error to be injected */
+	if (target_type == TARGET_TYPE_THREAD) {
+		tindex = pdbg_target_index(target);
+		err_type |= (tindex << 3);
+	}
+	val = SETFIELD(TB_ERROR_MASK, val, err_type);
+
+	rc = target_inject_error(target, P9_SCOM_SPR_MODE, val);
+	if (rc) {
+		printf("Failed to inject\n");
+	}
+	return rc;
+}
+
+void timefac_err_init(void)
+{
+	int i;
+
+	/* Register Tb error injects. */
+	for (i = 0; i < ARRAY_SIZE(tb_error_type); i++)
+		register_error_inject("tb", tb_error_type[i].name,
+				tb_error_type[i].desc, timefac_inject_tb_error,
+				&tb_error_type[i].error);
+
+}