diff mbox

[1/2] intel_reg_dumper: Add a single register decode mode

Message ID 1346420719-5532-1-git-send-email-damien.lespiau@gmail.com (mailing list archive)
State Superseded
Headers show

Commit Message

Damien Lespiau Aug. 31, 2012, 1:45 p.m. UTC
From: Damien Lespiau <damien.lespiau@intel.com>

From time to time, one would like to decode a register value that have
been captured at a certain point in time (and say printed out with a
printk). intel_reg_dumper has all the knowledge to do that and this
patch adds a way to ask it to decode a value.

Example usage:

$ ./tools/intel_reg_dumper PCH_PP_CONTROL 0xabcd0002
       PCH_PP_CONTROL: 0xabcd0002 (blacklight disabled, power...

v2: friendlier invocation (Chris Wilson)

Signed-off-by: Damien Lespiau <damien.lespiau@intel.com>
---
 tools/intel_reg_dumper.c | 99 +++++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 86 insertions(+), 13 deletions(-)

Comments

Ben Widawsky Sept. 2, 2012, 1:48 a.m. UTC | #1
On 2012-08-31 06:45, Damien Lespiau wrote:
> From: Damien Lespiau <damien.lespiau@intel.com>
>
> From time to time, one would like to decode a register value that 
> have
> been captured at a certain point in time (and say printed out with a
> printk). intel_reg_dumper has all the knowledge to do that and this
> patch adds a way to ask it to decode a value.
>
> Example usage:
>
> $ ./tools/intel_reg_dumper PCH_PP_CONTROL 0xabcd0002
>        PCH_PP_CONTROL: 0xabcd0002 (blacklight disabled, power...
>
> v2: friendlier invocation (Chris Wilson)
>
> Signed-off-by: Damien Lespiau <damien.lespiau@intel.com>

Back to my earlier complaint from the other patch... If the names don't 
match the docs then you forced to memorize our historically awful naming 
scheme. More useful to me would be to decode a register at an offset for 
a given generation.

> ---
>  tools/intel_reg_dumper.c | 99
> +++++++++++++++++++++++++++++++++++++++++-------
>  1 file changed, 86 insertions(+), 13 deletions(-)
>
> diff --git a/tools/intel_reg_dumper.c b/tools/intel_reg_dumper.c
> index b49d967..098affa 100644
> --- a/tools/intel_reg_dumper.c
> +++ b/tools/intel_reg_dumper.c
> @@ -1911,26 +1911,33 @@ static struct reg_debug i945gm_mi_regs[] = {
>  	DEFINEREG(ECOSKPD),
>  };
>
> +static void
> +_intel_dump_reg(struct reg_debug *reg, uint32_t val)
> +{
> +	char debug[1024];
> +
> +	if (reg->debug_output != NULL) {
> +		reg->debug_output(debug, sizeof(debug), reg->reg, val);
> +		printf("%30.30s: 0x%08x (%s)\n",
> +		       reg->name,
> +		       (unsigned int)val, debug);
> +	} else {
> +		printf("%30.30s: 0x%08x\n", reg->name,
> +		       (unsigned int)val);
> +	}
> +}
> +
>  #define intel_dump_regs(regs) _intel_dump_regs(regs, 
> ARRAY_SIZE(regs))
>
>  static void
>  _intel_dump_regs(struct reg_debug *regs, int count)
>  {
> -	char debug[1024];
>  	int i;
>
>  	for (i = 0; i < count; i++) {
>  		uint32_t val = INREG(regs[i].reg);
>
> -		if (regs[i].debug_output != NULL) {
> -			regs[i].debug_output(debug, sizeof(debug), regs[i].reg, val);
> -			printf("%30.30s: 0x%08x (%s)\n",
> -			       regs[i].name,
> -			       (unsigned int)val, debug);
> -		} else {
> -			printf("%30.30s: 0x%08x\n", regs[i].name,
> -			       (unsigned int)val);
> -		}
> +		_intel_dump_reg(&regs[i], val);
>  	}
>  }
>
> @@ -1964,6 +1971,54 @@ static struct reg_debug gen6_rp_debug_regs[] = 
> {
>  	DEFINEREG(GEN6_PMINTRMSK),
>  };
>
> +#define DECLARE_REGS(r)	{ .regs = r, .count = ARRAY_SIZE(r) }
> +static struct {
> +	struct reg_debug *regs;
> +	int count;
> +} known_registers[] = {
> +	DECLARE_REGS(ironlake_debug_regs),
> +	DECLARE_REGS(i945gm_mi_regs),
> +	DECLARE_REGS(intel_debug_regs),
> +	DECLARE_REGS(gen6_rp_debug_regs),
> +	DECLARE_REGS(haswell_debug_regs)
> +};
> +#undef DECLARE_REGS
> +
> +static struct reg_debug *
> +find_register_by_name(struct reg_debug *regs, int count,
> +		      const char *name)
> +{
> +	int i;
> +
> +	for (i = 0; i < count; i++)
> +		if (strcmp(name, regs[i].name) == 0)
> +			return &regs[i];
> +
> +	return NULL;
> +}
> +
> +static void
> +decode_register(const char *name, uint32_t val)
> +{
> +	int i;
> +	struct reg_debug *reg = NULL;
> +
> +	for (i = 0; i < ARRAY_SIZE(known_registers); i++) {
> +		reg = find_register_by_name(known_registers[i].regs,
> +					    known_registers[i].count,
> +					    name);
> +		if (reg)
> +			break;
> +	}
> +
> +	if (!reg) {
> +		fprintf(stderr, "Unknown register: %s\n", name);
> +		return;
> +	}
> +
> +	_intel_dump_reg(reg, val);
> +}
> +
>  static void
>  intel_dump_other_regs(void)
>  {
> @@ -2172,6 +2227,7 @@ intel_dump_other_regs(void)
>  static void print_usage(void)
>  {
>  	printf("Usage: intel_reg_dumper [options] [file]\n"
> +	       "       intel_reg_dumper [options] register value\n"
>  	       "Options:\n"
>  	       "  -d id   when a dump file is used, use 'id' as device id 
> (in "
>  	       "hex)\n"
> @@ -2181,8 +2237,9 @@ static void print_usage(void)
>  int main(int argc, char** argv)
>  {
>  	struct pci_device *pci_dev;
> -	int opt;
> -	char *file = NULL;
> +	int opt, n_args;
> +	char *file = NULL, *reg_name = NULL;
> +	uint32_t reg_val;
>
>  	while ((opt = getopt(argc, argv, "d:h")) != -1) {
>  		switch (opt) {
> @@ -2197,8 +2254,24 @@ int main(int argc, char** argv)
>  			return 1;
>  		}
>  	}
> -	if (optind < argc)
> +
> +	n_args = argc - optind;
> +	if (n_args == 1) {
>  		file = argv[optind];
> +	} else if (n_args == 2) {
> +		reg_name = argv[optind];
> +		reg_val = strtoul(argv[optind + 1], NULL, 0);
> +	} else if (n_args) {
> +		print_usage();
> +		return 1;
> +	}
> +
> +	/* the tool operates in "single" mode, decode a single register 
> given
> +	 * on the command line: intel_reg_dumper PCH_PP_CONTROL 0xabcd0002 
> */
> +	if (reg_name) {
> +		decode_register(reg_name, reg_val);
> +		return 0;
> +	}
>
>  	if (file) {
>  		intel_map_file(file);
Jani Nikula Sept. 3, 2012, 7:06 a.m. UTC | #2
On Sun, 02 Sep 2012, Ben Widawsky <ben@bwidawsk.net> wrote:
> On 2012-08-31 06:45, Damien Lespiau wrote:
>> From: Damien Lespiau <damien.lespiau@intel.com>
>>
>> From time to time, one would like to decode a register value that 
>> have
>> been captured at a certain point in time (and say printed out with a
>> printk). intel_reg_dumper has all the knowledge to do that and this
>> patch adds a way to ask it to decode a value.
>>
>> Example usage:
>>
>> $ ./tools/intel_reg_dumper PCH_PP_CONTROL 0xabcd0002
>>        PCH_PP_CONTROL: 0xabcd0002 (blacklight disabled, power...
>>
>> v2: friendlier invocation (Chris Wilson)
>>
>> Signed-off-by: Damien Lespiau <damien.lespiau@intel.com>
>
> Back to my earlier complaint from the other patch... If the names don't 
> match the docs then you forced to memorize our historically awful naming 
> scheme. More useful to me would be to decode a register at an offset for 
> a given generation.

I think both would be useful. So how about supporting both? Concrete
suggestion:

1) If strtoul eats whole of register name, it's register offset. Print
*all* matches across *all* generations.

2) If it's a register name, print *all* partial matches (from beginning
of string) across *all* generations.

3) Include generation and register offset in the output:
   Gen5: PCH_PP_CONTROL (0xc7204): 0xabcd0002 (blacklight disabled, power...

This would help in cross checking historically awful naming against
register offsets, and help in checking for differences between registers
and their values across generations.

These patches could also go in first, and the above added later.


BR,
Jani.
Jani Nikula Sept. 3, 2012, 7:10 a.m. UTC | #3
On Fri, 31 Aug 2012, Damien Lespiau <damien.lespiau@gmail.com> wrote:
> From: Damien Lespiau <damien.lespiau@intel.com>
>
> From time to time, one would like to decode a register value that have
> been captured at a certain point in time (and say printed out with a
> printk). intel_reg_dumper has all the knowledge to do that and this
> patch adds a way to ask it to decode a value.
>
> Example usage:
>
> $ ./tools/intel_reg_dumper PCH_PP_CONTROL 0xabcd0002
>        PCH_PP_CONTROL: 0xabcd0002 (blacklight disabled, power...
>
> v2: friendlier invocation (Chris Wilson)
>
> Signed-off-by: Damien Lespiau <damien.lespiau@intel.com>
> ---
>  tools/intel_reg_dumper.c | 99 +++++++++++++++++++++++++++++++++++++++++-------
>  1 file changed, 86 insertions(+), 13 deletions(-)
>
> diff --git a/tools/intel_reg_dumper.c b/tools/intel_reg_dumper.c
> index b49d967..098affa 100644
> --- a/tools/intel_reg_dumper.c
> +++ b/tools/intel_reg_dumper.c
> @@ -1911,26 +1911,33 @@ static struct reg_debug i945gm_mi_regs[] = {
>  	DEFINEREG(ECOSKPD),
>  };
>  
> +static void
> +_intel_dump_reg(struct reg_debug *reg, uint32_t val)
> +{
> +	char debug[1024];
> +
> +	if (reg->debug_output != NULL) {
> +		reg->debug_output(debug, sizeof(debug), reg->reg, val);
> +		printf("%30.30s: 0x%08x (%s)\n",
> +		       reg->name,
> +		       (unsigned int)val, debug);

Is the cast really required? val is already unsigned. Ditto below in a
few places.

> +	} else {
> +		printf("%30.30s: 0x%08x\n", reg->name,
> +		       (unsigned int)val);
> +	}
> +}
> +
>  #define intel_dump_regs(regs) _intel_dump_regs(regs, ARRAY_SIZE(regs))
>  
>  static void
>  _intel_dump_regs(struct reg_debug *regs, int count)
>  {
> -	char debug[1024];
>  	int i;
>  
>  	for (i = 0; i < count; i++) {
>  		uint32_t val = INREG(regs[i].reg);
>  
> -		if (regs[i].debug_output != NULL) {
> -			regs[i].debug_output(debug, sizeof(debug), regs[i].reg, val);
> -			printf("%30.30s: 0x%08x (%s)\n",
> -			       regs[i].name,
> -			       (unsigned int)val, debug);
> -		} else {
> -			printf("%30.30s: 0x%08x\n", regs[i].name,
> -			       (unsigned int)val);
> -		}
> +		_intel_dump_reg(&regs[i], val);
>  	}
>  }
>  
> @@ -1964,6 +1971,54 @@ static struct reg_debug gen6_rp_debug_regs[] = {
>  	DEFINEREG(GEN6_PMINTRMSK),
>  };
>  
> +#define DECLARE_REGS(r)	{ .regs = r, .count = ARRAY_SIZE(r) }
> +static struct {
> +	struct reg_debug *regs;
> +	int count;
> +} known_registers[] = {
> +	DECLARE_REGS(ironlake_debug_regs),
> +	DECLARE_REGS(i945gm_mi_regs),
> +	DECLARE_REGS(intel_debug_regs),
> +	DECLARE_REGS(gen6_rp_debug_regs),
> +	DECLARE_REGS(haswell_debug_regs)
> +};
> +#undef DECLARE_REGS
> +
> +static struct reg_debug *
> +find_register_by_name(struct reg_debug *regs, int count,
> +		      const char *name)
> +{
> +	int i;
> +
> +	for (i = 0; i < count; i++)
> +		if (strcmp(name, regs[i].name) == 0)
> +			return &regs[i];

strcasecmp for ease of use?

BR,
Jani.

> +
> +	return NULL;
> +}
> +
> +static void
> +decode_register(const char *name, uint32_t val)
> +{
> +	int i;
> +	struct reg_debug *reg = NULL;
> +
> +	for (i = 0; i < ARRAY_SIZE(known_registers); i++) {
> +		reg = find_register_by_name(known_registers[i].regs,
> +					    known_registers[i].count,
> +					    name);
> +		if (reg)
> +			break;
> +	}
> +
> +	if (!reg) {
> +		fprintf(stderr, "Unknown register: %s\n", name);
> +		return;
> +	}
> +
> +	_intel_dump_reg(reg, val);
> +}
> +
>  static void
>  intel_dump_other_regs(void)
>  {
> @@ -2172,6 +2227,7 @@ intel_dump_other_regs(void)
>  static void print_usage(void)
>  {
>  	printf("Usage: intel_reg_dumper [options] [file]\n"
> +	       "       intel_reg_dumper [options] register value\n"
>  	       "Options:\n"
>  	       "  -d id   when a dump file is used, use 'id' as device id (in "
>  	       "hex)\n"
> @@ -2181,8 +2237,9 @@ static void print_usage(void)
>  int main(int argc, char** argv)
>  {
>  	struct pci_device *pci_dev;
> -	int opt;
> -	char *file = NULL;
> +	int opt, n_args;
> +	char *file = NULL, *reg_name = NULL;
> +	uint32_t reg_val;
>  
>  	while ((opt = getopt(argc, argv, "d:h")) != -1) {
>  		switch (opt) {
> @@ -2197,8 +2254,24 @@ int main(int argc, char** argv)
>  			return 1;
>  		}
>  	}
> -	if (optind < argc)
> +
> +	n_args = argc - optind;
> +	if (n_args == 1) {
>  		file = argv[optind];
> +	} else if (n_args == 2) {
> +		reg_name = argv[optind];
> +		reg_val = strtoul(argv[optind + 1], NULL, 0);
> +	} else if (n_args) {
> +		print_usage();
> +		return 1;
> +	}
> +
> +	/* the tool operates in "single" mode, decode a single register given
> +	 * on the command line: intel_reg_dumper PCH_PP_CONTROL 0xabcd0002 */
> +	if (reg_name) {
> +		decode_register(reg_name, reg_val);
> +		return 0;
> +	}
>  
>  	if (file) {
>  		intel_map_file(file);
> -- 
> 1.7.11.4
>
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx
Lespiau, Damien Sept. 3, 2012, 3:35 p.m. UTC | #4
On Sun, Sep 2, 2012 at 2:48 AM, Ben Widawsky <ben@bwidawsk.net> wrote:
> On 2012-08-31 06:45, Damien Lespiau wrote:
> Back to my earlier complaint from the other patch... If the names don't
> match the docs then you forced to memorize our historically awful naming
> scheme. More useful to me would be to decode a register at an offset for a
> given generation.

Well, renaming the registers sounds a bit tedious and will break the
diffs between two dumps across the change (don't know if it's a big
deal). Hopefully the new little features suggested by Jani make the
single register decode more useful for you.
diff mbox

Patch

diff --git a/tools/intel_reg_dumper.c b/tools/intel_reg_dumper.c
index b49d967..098affa 100644
--- a/tools/intel_reg_dumper.c
+++ b/tools/intel_reg_dumper.c
@@ -1911,26 +1911,33 @@  static struct reg_debug i945gm_mi_regs[] = {
 	DEFINEREG(ECOSKPD),
 };
 
+static void
+_intel_dump_reg(struct reg_debug *reg, uint32_t val)
+{
+	char debug[1024];
+
+	if (reg->debug_output != NULL) {
+		reg->debug_output(debug, sizeof(debug), reg->reg, val);
+		printf("%30.30s: 0x%08x (%s)\n",
+		       reg->name,
+		       (unsigned int)val, debug);
+	} else {
+		printf("%30.30s: 0x%08x\n", reg->name,
+		       (unsigned int)val);
+	}
+}
+
 #define intel_dump_regs(regs) _intel_dump_regs(regs, ARRAY_SIZE(regs))
 
 static void
 _intel_dump_regs(struct reg_debug *regs, int count)
 {
-	char debug[1024];
 	int i;
 
 	for (i = 0; i < count; i++) {
 		uint32_t val = INREG(regs[i].reg);
 
-		if (regs[i].debug_output != NULL) {
-			regs[i].debug_output(debug, sizeof(debug), regs[i].reg, val);
-			printf("%30.30s: 0x%08x (%s)\n",
-			       regs[i].name,
-			       (unsigned int)val, debug);
-		} else {
-			printf("%30.30s: 0x%08x\n", regs[i].name,
-			       (unsigned int)val);
-		}
+		_intel_dump_reg(&regs[i], val);
 	}
 }
 
@@ -1964,6 +1971,54 @@  static struct reg_debug gen6_rp_debug_regs[] = {
 	DEFINEREG(GEN6_PMINTRMSK),
 };
 
+#define DECLARE_REGS(r)	{ .regs = r, .count = ARRAY_SIZE(r) }
+static struct {
+	struct reg_debug *regs;
+	int count;
+} known_registers[] = {
+	DECLARE_REGS(ironlake_debug_regs),
+	DECLARE_REGS(i945gm_mi_regs),
+	DECLARE_REGS(intel_debug_regs),
+	DECLARE_REGS(gen6_rp_debug_regs),
+	DECLARE_REGS(haswell_debug_regs)
+};
+#undef DECLARE_REGS
+
+static struct reg_debug *
+find_register_by_name(struct reg_debug *regs, int count,
+		      const char *name)
+{
+	int i;
+
+	for (i = 0; i < count; i++)
+		if (strcmp(name, regs[i].name) == 0)
+			return &regs[i];
+
+	return NULL;
+}
+
+static void
+decode_register(const char *name, uint32_t val)
+{
+	int i;
+	struct reg_debug *reg = NULL;
+
+	for (i = 0; i < ARRAY_SIZE(known_registers); i++) {
+		reg = find_register_by_name(known_registers[i].regs,
+					    known_registers[i].count,
+					    name);
+		if (reg)
+			break;
+	}
+
+	if (!reg) {
+		fprintf(stderr, "Unknown register: %s\n", name);
+		return;
+	}
+
+	_intel_dump_reg(reg, val);
+}
+
 static void
 intel_dump_other_regs(void)
 {
@@ -2172,6 +2227,7 @@  intel_dump_other_regs(void)
 static void print_usage(void)
 {
 	printf("Usage: intel_reg_dumper [options] [file]\n"
+	       "       intel_reg_dumper [options] register value\n"
 	       "Options:\n"
 	       "  -d id   when a dump file is used, use 'id' as device id (in "
 	       "hex)\n"
@@ -2181,8 +2237,9 @@  static void print_usage(void)
 int main(int argc, char** argv)
 {
 	struct pci_device *pci_dev;
-	int opt;
-	char *file = NULL;
+	int opt, n_args;
+	char *file = NULL, *reg_name = NULL;
+	uint32_t reg_val;
 
 	while ((opt = getopt(argc, argv, "d:h")) != -1) {
 		switch (opt) {
@@ -2197,8 +2254,24 @@  int main(int argc, char** argv)
 			return 1;
 		}
 	}
-	if (optind < argc)
+
+	n_args = argc - optind;
+	if (n_args == 1) {
 		file = argv[optind];
+	} else if (n_args == 2) {
+		reg_name = argv[optind];
+		reg_val = strtoul(argv[optind + 1], NULL, 0);
+	} else if (n_args) {
+		print_usage();
+		return 1;
+	}
+
+	/* the tool operates in "single" mode, decode a single register given
+	 * on the command line: intel_reg_dumper PCH_PP_CONTROL 0xabcd0002 */
+	if (reg_name) {
+		decode_register(reg_name, reg_val);
+		return 0;
+	}
 
 	if (file) {
 		intel_map_file(file);