[Crash-utility] Cell/B.E. SPU commands extension

Dave Anderson anderson at redhat.com
Tue May 22 20:20:25 UTC 2007


Lucio Correia wrote:
> Hi,
> 
> I've developed this crash extension to analyze SPU specific data for
> Cell/B.E. processor. This extension makes use of some important data
> saved by this kernel patch (that is not mainline yet)
> http://ozlabs.org/pipermail/cbe-oss-dev/2007-May/001848.html during the
> crash dump.
> 
> I would like to check if there is any issue with the code.
> 

Functionally it looks fine.

I changed the _init() function to just do an error(INFO, ...)
so I could load the extensions, and the only suggestion
I can make is purely aesthetic, which would be to make
the "help" messages 80 characters or less like the regular
commands are.  In other words, the "DESCRIPTION" section
outputs, and the sentences in in the "spuctx" EXAMPLE
section are kind of ugly the way that they run on with
no linefeeds.

But like I said before, I don't see any issues/problems
with the code -- pretty nifty extension...

Dave



> 
> Thanks in advance,
> 
> 
> ------------------------------------------------------------------------
> 
> /* spu.c - commands for viewing Cell/B.E. SPUs data
>  *
>  * (C) Copyright 2007 IBM Corp.
>  *
>  * Author: Lucio Correia <luciojhc at br.ibm.com>
>  *
>  * This program is free software; you can redistribute it and/or modify
>  * it under the terms of the GNU General Public License as published by
>  * the Free Software Foundation; either version 2 of the License, or
>  * (at your option) any later version.
>  *
>  * This program is distributed in the hope that it will be useful,
>  * but WITHOUT ANY WARRANTY; without even the implied warranty of
>  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>  * GNU General Public License for more details.
>  */
> 
> #include "defs.h"
> 
> #define NR_SPUS			 (16)	/* Enough for current hardware */
> #define MAX_PRIO		(140)
> #define MAX_CTXS		 (50)
> 
> #define STR_SPU_INVALID		(0x0)
> #define STR_SPU_ID		(0x1)
> #define STR_SPU_PID		(0x2)
> #define STR_SPU_ADDR		(0x4)
> #define STR_SPU_CTX_ADDR	(0x8)
> 
> #define SPUCTX_CMD_NAME "spuctx"
> #define SPUS_CMD_NAME "spus"
> #define SPURQ_CMD_NAME "spurq"
> 
> 
> ulong get_debug_field(ulong spu, char *field);
> ulong get_spu_field(ulong spu, char *field);
> 
> void cmd_spus(void);
> void cmd_spurq(void);
> void cmd_spuctx(void);
> char *help_spus[];
> char *help_spurq[];
> void show_spu_state(ulong spu);
> void dump_spu_runq(ulong k_prio_array);
> char *help_spuctx[];
> void show_ctx_info(ulong ctx_addr);
> void print_ctx_info(char *ctx_data, char *spu_data, int info);
> void show_ctx_info_all(void);
> 
> 
> static struct command_table_entry command_table[] = {
> 	SPUCTX_CMD_NAME, cmd_spuctx, help_spuctx, 0,
> 	SPUS_CMD_NAME, cmd_spus, help_spus, 0,
> 	SPURQ_CMD_NAME, cmd_spurq, help_spurq, 0,
> 	NULL
> };
> 
> ulong spu[NR_SPUS];
> 
> /*****************************************************************************
>  * INIT FUNCTIONS
>  */
> 
> /*
>  * Read kernel virtual addresses of debug_spu_info data stored by kdump
>  */
> int get_debug_spu_info(void)
> {
> 	int i;
> 	ulong addr;
> 	long offset;
> 
> 	if (symbol_exists("debug_spu_info")) {
> 		addr = symbol_value("debug_spu_info");
> 		offset = STRUCT_SIZE("debug_spu_info");
> 		if (offset == -1)
> 			error(FATAL, "Couldn't get debug_spu_info size.\n");
> 	}
> 	else
> 		return FALSE;
> 
> 	for (i = 0; i < NR_SPUS; i++)
> 		spu[i] = addr + (i * offset);
> 
> 	return TRUE;
> }
> 
> _init()
> {
> 	int i, n_registered;
> 	struct command_table_entry *cte;
> 
> 	for (i = 0; i < NR_SPUS; i++)
> 		spu[i] = 0;
> 
> 	register_extension(command_table);
> 
> 	if (!get_debug_spu_info())
> 		error(FATAL, "Couldn't get spu_debug_info data.\n");
> }
> 
> 
> _fini() { }
> 
> 
> 
> /*****************************************************************************
>  * BASIC FUNCTIONS
>  */
> 
> 
> /*
>  * Returns a pointer to the requested debug field
>  */
> ulong get_debug_field(ulong spu_info, char *field)
> {
> 	ulong offset;
> 
> 	offset = MEMBER_OFFSET("debug_spu_info", field);
> 	if (offset == -1)
> 		error(FATAL, "Couldn't get debug_spu_info.%s offset.\n", field);
> 
> 	return spu_info + offset;
> }
> 
> /*
>  * Returns a pointer to the requested SPU field 
>  */
> ulong get_spu_field(ulong spu_info, char* field)
> {
> 	ulong offset, spu_addr;
> 
> 	offset = MEMBER_OFFSET("debug_spu_info", "spu");
> 	if (offset == -1)
> 		error(FATAL, "Couldn't get debug_spu_info.spu offset.\n");
> 
> 	readmem(spu_info + offset, KVADDR, &spu_addr, sizeof(spu_addr), 
> 					"get_spu_field", FAULT_ON_ERROR);
> 
> 	offset = field ? MEMBER_OFFSET("spu", field) : 0;
> 	if (offset == -1)
> 		error(FATAL, "Couldn't get spu.%s offset.\n", field);
> 
> 	return spu_addr + offset;
> }
> 
> 
> /*****************************************************************************
>  * SPUCTX COMMAND
>  */
> 
> #define DUMP_WIDTH	23
> #define DUMP_SPU_FIELD(format, field, cast)				\
> do {									\
> 	offset = MEMBER_OFFSET("spu", field);				\
> 	if (offset == -1)						\
> 		error(FATAL, "Couldn't get offset for %s.\n", field);	\
> 									\
> 	printf("  %-*s = "format"\n", DUMP_WIDTH, field,		\
> 					cast(spu_data + offset));	\
> } while(0)
> 
> #define DUMP_CTX_FIELD(format, field, cast)				\
> do {									\
> 	offset = MEMBER_OFFSET("spu_context", field);			\
> 	if (offset == -1)						\
> 		error(FATAL, "Couldn't get offset for %s.\n", field);	\
> 									\
> 	printf("  %-*s = "format"\n", DUMP_WIDTH, field,		\
> 					cast(ctx_data + offset));	\
> } while(0)
> 
> #define DUMP_DBG_FIELD(format, field, cast)				\
> do {									\
> 	offset = MEMBER_OFFSET("debug_spu_info", field);		\
> 	if (offset == -1)						\
> 		error(FATAL, "Couldn't get offset for %s.\n", field);	\
> 									\
> 	printf("  %-*s = "format"\n", DUMP_WIDTH, field,		\
> 					cast(debug_data + offset));	\
> } while(0)
> 
> /* 
>  * Print the spu and spu_context structs fields. Some SPU memory-mapped IO 
>  * registers are taken directly from debug_spu_info.
>  */
> void print_ctx_info(char *ctx_data, char *spu_data, int info)
> {
> 	long offset, size;
> 	char *debug_data;
> 
> 	DUMP_CTX_FIELD("%d", "state", *(int *));
> 	DUMP_CTX_FIELD("%d", "prio", *(int *));
> 	DUMP_CTX_FIELD("%p", "local_store", *(ulong *));
> 	DUMP_CTX_FIELD("%p", "rq", *(ulong *));
> 
> 	if (spu_data) {
> 		DUMP_SPU_FIELD("%d", "node", *(int *));
> 		DUMP_SPU_FIELD("%d", "number", *(int *));
> 		DUMP_SPU_FIELD("%d", "pid", *(int *));
> 		DUMP_SPU_FIELD("%s", "name", (char *));
> 		DUMP_SPU_FIELD("%x", "slb_replace", *(unsigned int *));
> 		DUMP_SPU_FIELD("%p", "mm", *(ulong *));
> 		DUMP_SPU_FIELD("%p", "timestamp", *(long long *));
> 		DUMP_SPU_FIELD("%d", "class_0_pending", *(int *));
> 		DUMP_SPU_FIELD("%p", "problem", *(ulong *));
> 		DUMP_SPU_FIELD("%p", "priv2", *(ulong *));
> 		DUMP_SPU_FIELD("%lu", "flags", *(ulong *));
> 
> 		size = STRUCT_SIZE("debug_spu_info");
> 		if (size == -1)
> 			error(FATAL, "Couldn't get debug_spu_info size.\n");
> 
> 		debug_data = (char *)GETBUF(size);
> 		readmem(spu[info], KVADDR, debug_data, size, "debug_data",
> 								FAULT_ON_ERROR);
> 
> 		DUMP_DBG_FIELD("%lu", "saved_mfc_sr1_RW", *(ulong *));
> 		DUMP_DBG_FIELD("%lu", "saved_mfc_dar", *(ulong *));
> 		DUMP_DBG_FIELD("%lu", "saved_mfc_dsisr", *(ulong *));
> 		DUMP_DBG_FIELD("%u", "saved_spu_runcntl_RW", *(uint *));
> 		DUMP_DBG_FIELD("%u", "saved_spu_status_R", *(uint *));
> 		DUMP_DBG_FIELD("%u", "saved_spu_npc_RW", *(uint *));
> 
> 		FREEBUF(debug_data);
> 	}
> }
> 
> 
> /*
>  * Pass ctx and respective spu data to print_ctx_info for the contexts in
>  * ctx_addr list (chosen contexts).
>  */
> void show_ctx_info(ulong ctx_addr)
> {
> 	int number, info, i;
> 	char *ctx_data, *spu_data;
> 	long size, offset;
> 	ulong spu_addr, addr;
> 
> 	spu_data = NULL;
> 	info = 0;
> 
> 	size = STRUCT_SIZE("spu_context");
> 	if (size == -1)
> 		error(FATAL, "Couldn't get spu_context size.\n");
> 
> 	ctx_data = GETBUF(size);
> 	if (!ctx_data)
> 		error(FATAL, "Couldn't allocate memory for ctx.\n");
> 	readmem(ctx_addr, KVADDR, ctx_data, size, "show_ctx_info ctx", 
> 								FAULT_ON_ERROR);
> 
> 	offset = MEMBER_OFFSET("spu_context", "spu");
> 	if (offset == -1)
> 		error(FATAL, "Couldn't get spu_context_spu offset.\n");
> 	spu_addr = *(ulong *)(ctx_data + offset);
> 
> 	if (spu_addr) {
> 		size = STRUCT_SIZE("spu");
> 		if (size == -1)
> 			error(FATAL, "Couldn't get spu size.\n");
> 
> 		spu_data = GETBUF(size);
> 		if (!spu_data)
> 			error(FATAL, "Couldn't allocate memory for spu.\n");
> 		readmem(spu_addr, KVADDR, spu_data, size, "show_ctx_info spu",
> 								FAULT_ON_ERROR);
> 
> 		for (i = 0; i < NR_SPUS; i++) {
> 			readmem(spu[i], KVADDR, &addr, sizeof(addr), "spu addr",
> 								FAULT_ON_ERROR);
> 			if (addr == spu_addr)
> 				info = i;
> 		}
> 	}
> 
> 	printf("Dumping context fields for spu_context %lx:\n", ctx_addr);
> 	print_ctx_info(ctx_data, spu_data, info);
> 
> 	FREEBUF(ctx_data);
> 	if (spu_addr)
> 		FREEBUF(spu_data);
> }
> 
> /*
>  * Pass ctx and respective spu data to print_ctx_info for all the contexts
>  * running and on the runqueue.
>  */
> void show_ctx_info_all(void)
> {
> 	int i, j, cnt;
> 	long prio_size, prio_runq_off, ctx_rq_off, jump, offset, ctxs_size;
> 	char *u_spu_prio;
> 	ulong spu_prio_addr, k_spu_prio, kvaddr, uvaddr, addr, ctx;
> 	ulong *ctxs;
> 	ulong list_head[2];
> 	struct list_data list_data, *ld;
> 
> 	/* Walking SPUs */
> 	for (i = 0; i < NR_SPUS; i++) {
> 		addr = (ulong)get_spu_field(spu[i], "ctx");
> 		readmem(addr, KVADDR, &ctx, sizeof(ctx), "show_ctx_info_all",
> 								FAULT_ON_ERROR);
> 		show_ctx_info(ctx);
> 	}
> 
> 	/* Walking SPU runqueue */
> 	if (symbol_exists("spu_prio")) {
> 		spu_prio_addr = symbol_value("spu_prio");
> 		readmem(spu_prio_addr, KVADDR, &k_spu_prio, sizeof(k_spu_prio),
> 						"runq_array", FAULT_ON_ERROR);
> 	}
> 	else
> 		error(FATAL, "Could not get SPU run queue data.\n");
> 
> 	jump = STRUCT_SIZE("list_head");
> 	if (jump == -1)
> 		error(FATAL, "Couldn't get list_head size.\n");
> 
> 	prio_runq_off =  MEMBER_OFFSET("spu_prio_array", "runq");
> 	if (prio_runq_off == -1)
> 		error(FATAL, "Couldn't get runq offset.\n");
> 
> 	ctx_rq_off =  MEMBER_OFFSET("spu_context", "rq");
> 	if (ctx_rq_off == -1)
> 		error(FATAL, "Couldn't get rq offset.\n");
> 
> 	prio_size = STRUCT_SIZE("spu_prio_array");
> 	if (prio_size == -1)
> 		error(FATAL, "Couldn't get list_head size.\n");
> 
> 	u_spu_prio = (char *)GETBUF(prio_size);
> 	readmem(k_spu_prio, KVADDR, u_spu_prio, prio_size, "get_runq_ctxs", 
> 								FAULT_ON_ERROR);
> 
> 	ctxs_size = MAX_CTXS * sizeof(ulong);
> 	ctxs = (ulong *)GETBUF(ctxs_size);
> 
> 	for (i = 0; i < MAX_PRIO; i++) {
> 		offset = prio_runq_off + i * jump;
> 		kvaddr = k_spu_prio + offset;
> 		uvaddr = (ulong)u_spu_prio + offset;
> 
> 		BCOPY((char *)uvaddr, (char *)&list_head[0], sizeof(ulong)*2);
> 
> 		if ((list_head[0] == kvaddr) && (list_head[1] == kvaddr))
> 			continue;
> 
> 		ld = &list_data;
> 
> 		BZERO(ld, sizeof(struct list_data));
> 		ld->start = list_head[0];
> 		ld->list_head_offset = ctx_rq_off;
> 		ld->flags |= RETURN_ON_LIST_ERROR;
> 		ld->end = kvaddr;
> 
> 		hq_open();
> 		cnt = do_list(ld);
> 		if (cnt == -1) {
> 			hq_close();
> 			FREEBUF(u_spu_prio);
> 			FREEBUF(ctxs);
> 			error(FATAL, "Couldn't walk the list.\n");
> 		}
> 
> 		BZERO(ctxs, ctxs_size);
> 		cnt = retrieve_list(ctxs, cnt);
> 		hq_close();
> 
> 		for (j = 0; j < cnt; j++)
> 			if (j < MAX_CTXS)
> 				show_ctx_info(ctxs[j]);
> 	}
> 
> 	FREEBUF(u_spu_prio);
> 	FREEBUF(ctxs);
> }
> 
> /*
>  * Tries to discover the meaning of string and to find the referred context
>  */
> int str_to_spuctx(char *string, ulong *value, ulong *spu_ctx)
> {
> 	char *s, *u_spu_prio;
> 	ulong dvalue, hvalue, addr, spu_addr, ctx;
> 	ulong k_spu_prio, spu_prio_addr, kvaddr, uvaddr;
> 	int type, pid, i, j, cnt;
> 	long prio_size, prio_runq_off, ctx_rq_off, jump, offset, ctxs_size;
> 	ulong *ctxs;
> 	ulong list_head[2];
> 	struct list_data list_data, *ld;
> 
> 	if (string == NULL) {
> 		error(INFO, "%s: received NULL string.\n", __FUNCTION__);
> 		return STR_SPU_INVALID;
> 	}
> 
> 	s = string;
> 	dvalue = hvalue = BADADDR;
> 
> 	if (decimal(s, 0))
> 		dvalue = dtol(s, RETURN_ON_ERROR, NULL);
> 
> 	if (hexadecimal(s, 0)) {
> 		if (STRNEQ(s, "0x") || STRNEQ(s, "0X"))
> 			s += 2;
> 		if (strlen(s) <= MAX_HEXADDR_STRLEN)
> 			hvalue = htol(s, RETURN_ON_ERROR, NULL);
> 	}
> 
> 	type = STR_SPU_INVALID;
> 
> 	if (dvalue != BADADDR) {
> 		/* Testing for SPU ID */
> 		if ((dvalue >= 0) && (dvalue < NR_SPUS)) {
> 			addr = get_spu_field(spu[dvalue], "ctx");
> 			readmem(addr, KVADDR, &ctx, sizeof(ctx), 
> 					"str_to_spuctx ID", FAULT_ON_ERROR);
> 
> 			type = STR_SPU_ID;
> 			*value = dvalue;
> 			*spu_ctx = ctx;
> 			return type;
> 		}
> 		else {
> 			/* Testing for PID */
> 			for (i = 0; i < NR_SPUS; i++) {
> 				addr = get_spu_field(spu[i], "pid");
> 				readmem(addr, KVADDR, &pid, sizeof(pid), 
> 					"str_to_spuctx PID", FAULT_ON_ERROR);
> 
> 				if (dvalue == pid) {
> 					addr = get_spu_field(spu[i], "ctx");
> 					readmem(addr, KVADDR, &ctx, sizeof(ctx),
> 						"str_to_spuctx PID ctx",
> 						FAULT_ON_ERROR);
> 
> 					type = STR_SPU_PID;
> 					*value = dvalue;
> 					*spu_ctx = ctx;
> 					return type;
> 				}
> 			}
> 		}
> 	}
> 
> 	if (hvalue != BADADDR) {
> 		/* Testing for spuctx address on SPUs */
> 		for (i = 0; i < NR_SPUS; i++) {
> 			addr = get_spu_field(spu[i], "ctx");
> 			readmem(addr, KVADDR, &ctx, sizeof(ctx), 
> 					"str_to_spuctx CTX", FAULT_ON_ERROR);
> 
> 			if (hvalue == ctx) {
> 				type = STR_SPU_CTX_ADDR;
> 				*value = hvalue;
> 				*spu_ctx = ctx;
> 				return type;
> 			}
> 		}
> 
> 		/* Testing for spuctx address on SPU runqueue */
> 		if (symbol_exists("spu_prio")) {
> 			spu_prio_addr = symbol_value("spu_prio");
> 			readmem(spu_prio_addr, KVADDR, &k_spu_prio, 
> 			      sizeof(k_spu_prio), "runq_array", FAULT_ON_ERROR);
> 		}
> 		else
> 			error(FATAL, "Could not get SPU run queue data.\n");
> 
> 		jump = STRUCT_SIZE("list_head");
> 		if (jump == -1)
> 			error(FATAL, "Couldn't get list_head size.\n");
> 
> 		prio_runq_off = MEMBER_OFFSET("spu_prio_array", "runq");
> 		if (prio_runq_off == -1)
> 			error(FATAL, "Couldn't get runq offset.\n");
> 
> 		ctx_rq_off = MEMBER_OFFSET("spu_context", "rq");
> 		if (ctx_rq_off == -1)
> 			error(FATAL, "Couldn't get rq offset.\n");
> 
> 		prio_size = STRUCT_SIZE("spu_prio_array");
> 		if (prio_size == -1)
> 			error(FATAL, "Couldn't get list_head size.\n");
> 
> 		u_spu_prio = (char *)GETBUF(prio_size);
> 		readmem(k_spu_prio, KVADDR, u_spu_prio, prio_size, 
> 					"get_runq_ctxs", FAULT_ON_ERROR);
> 
> 		ctxs_size = MAX_CTXS * sizeof(ulong);
> 		ctxs = (ulong *)GETBUF(ctxs_size);
> 
> 		for (i = 0; i < MAX_PRIO; i++) {
> 			offset = prio_runq_off + i * jump;
> 			kvaddr = k_spu_prio + offset;
> 			uvaddr = (ulong)u_spu_prio + offset;
> 
> 			BCOPY((char *)uvaddr, (char *)&list_head[0], sizeof(ulong)*2);
> 
> 			if ((list_head[0] == kvaddr) && (list_head[1] == kvaddr))
> 				continue;
> 
> 			ld = &list_data;
> 
> 			BZERO(ld, sizeof(struct list_data));
> 			ld->start = list_head[0];
> 			ld->list_head_offset = ctx_rq_off;
> 			ld->flags |= RETURN_ON_LIST_ERROR;
> 			ld->end = kvaddr;
> 
> 			hq_open();
> 			cnt = do_list(ld);
> 			if (cnt == -1) {
> 				hq_close();
> 				FREEBUF(u_spu_prio);
> 				FREEBUF(ctxs);
> 				error(FATAL, "Couldn't walk the list.\n");
> 			}
> 
> 			BZERO(ctxs, ctxs_size);
> 			cnt = retrieve_list(ctxs, cnt);
> 			hq_close();
> 
> 			for (j = 0; j < cnt; j++)
> 				if ((j < MAX_CTXS) && (hvalue == ctxs[j])) {
> 					type = STR_SPU_CTX_ADDR;
> 					*value = hvalue;
> 					*spu_ctx = ctxs[j];
> 					FREEBUF(u_spu_prio);
> 					FREEBUF(ctxs);
> 					return type;
> 				}
> 		}
> 
> 		FREEBUF(u_spu_prio);
> 		FREEBUF(ctxs);
> 
> 		/* Testing for spu address */
> 		for (i = 0; i < NR_SPUS; i++) {
> 			addr = get_debug_field(spu[i], "spu");
> 			readmem(addr, KVADDR, &spu_addr, sizeof(spu_addr),
> 					"str_to_spuctx SPU", FAULT_ON_ERROR);
> 
> 			if (hvalue == spu_addr) {
> 				addr = get_spu_field(spu[i], "ctx");
> 				readmem(addr, KVADDR, &ctx, sizeof(ctx),
> 				       "str_to_spuctx SPU ctx", FAULT_ON_ERROR);
> 
> 				type = STR_SPU_ADDR;
> 				*value = hvalue;
> 				*spu_ctx = ctx;
> 				return type;
> 			}
> 		}
> 	}
> 
> 	return type;
> }
> 
> /* 
>  * spuctx command stands for "spu context" and shows the context fields 
>  * for the spu or respective struct address passed as an argument
>  */
> void cmd_spuctx()
> {
> 	int i, c, cnt;
> 	ulong value, ctx;
> 	ulong *ctxlist;
> 
> 	while ((c = getopt(argcnt, args, "")) != EOF) {
> 		switch(c) 
> 		{
> 		default:
> 			argerrs++;
> 			break;
> 		}
> 	}
> 
> 	if (argerrs)
> 		cmd_usage(pc->curcmd, SYNOPSIS);
> 
> 	if (!args[optind]) {
> 		show_ctx_info_all();
> 		return;
> 	}
> 
> 	cnt = 0;
> 	ctxlist = (ulong *)GETBUF((MAXARGS+NR_CPUS)*sizeof(ctx));
> 
> 	while (args[optind]) {
> 		if (IS_A_NUMBER(args[optind])) {
> 			switch (str_to_spuctx(args[optind], &value, &ctx)) 
> 			{
> 			case STR_SPU_ADDR:
> 			case STR_SPU_CTX_ADDR:
> 			case STR_SPU_ID:
> 			case STR_SPU_PID:
> 				ctxlist[cnt++] = ctx;
> 				break;
> 
> 			case STR_SPU_INVALID:
> 				error(INFO, "Invalid SPU context or PID: %s\n",
> 								args[optind]);
> 				break;
> 			}
> 		}
> 		else
> 			error(INFO, "Invalid SPU context or PID: %s\n", 
> 							args[optind]);
> 		optind++;
> 	}
> 
> 	if (cnt == 0)
> 		error(INFO, "No valid ID, PID or address for a SPU.\n");
> 	else
> 		for (i = 0; i < cnt; i++)
> 			show_ctx_info(ctxlist[i]);
> 
> 	FREEBUF(ctxlist);
> }
> 
> 
> /*****************************************************************************
>  * SPUS COMMAND
>  */
> 
> void print_spu_header(ulong spu_info)
> {
> 	int id, pid, size;
> 	ulong ctx_addr, spu_addr;
> 	char *spu_data;
> 
> 	if (spu_info) {
> 		size = STRUCT_SIZE("spu");
> 		spu_data = GETBUF(size);
> 		spu_addr = get_spu_field(spu_info, NULL);
> 		readmem(spu_addr, KVADDR, spu_data, size, "SPU struct", 
> 								FAULT_ON_ERROR);
> 
> 		id = *(int *)(spu_data + MEMBER_OFFSET("spu", "number"));
> 		ctx_addr = *(ulong *)(spu_data + MEMBER_OFFSET("spu", "ctx"));
> 		pid = *(int *)(spu_data + MEMBER_OFFSET("spu", "pid"));
> 
> 		fprintf(fp, "%2d\t%16lx\t%16lx\t%s\t%5d\n", id, spu_addr, 
> 			ctx_addr, ctx_addr ? "LOADED" : " IDLE ", pid);
> 
> 		FREEBUF(spu_data);
> 	}
> }
> 
> void print_node_header(int node)
> {
> 	fprintf(fp, "\n");
> 	fprintf(fp, "NODE %i:\n", node);
> 	fprintf(fp, "ID\t     SPUADDR    \t     CTXADDR    \t STATE\t PID\n");
> }
> 
> void show_spus()
> {
> 	int i, j, nr_cpus, show_header, node;
> 	ulong spu_addr, addr;
> 	long offset;
> 
> 	nr_cpus = kt->kernel_NR_CPUS ? kt->kernel_NR_CPUS : NR_CPUS;
> 
> 	for (i = 0; i < nr_cpus; i++) {
> 		show_header = TRUE;
> 
> 		for (j = 0; j < NR_SPUS; j++) {
> 			addr = get_debug_field(spu[j], "spu");
> 			readmem(addr, KVADDR, &spu_addr, sizeof(spu_addr),
> 					"show_spus spu_addr", FAULT_ON_ERROR);
> 
> 			offset = MEMBER_OFFSET("spu", "node");
> 			if (offset == -1)
> 				error(FATAL, "Couldn't get spu.node offset.\n");
> 
> 			spu_addr += offset;
> 			readmem(spu_addr, KVADDR, &node, sizeof(node),
> 					"show_spus node", FAULT_ON_ERROR);
> 
> 			if (node == i) {
> 				if (show_header) {
> 					print_node_header(node);
> 					show_header = FALSE;
> 				}
> 
> 				print_spu_header(spu[j]);
> 			}
> 		}
> 	}
> }
> 
> /*
>  * spus stands for "spu state" and shows what contexts are running in what 
>  * SPU.
>  */
> void cmd_spus()
> {
> 	int c;
> 
> 	while ((c = getopt(argcnt, args, "")) != EOF) {
> 		switch(c)
> 		{
> 		default:
> 			argerrs++;
> 			break;
> 		}
> 	}
> 
> 	if (argerrs || args[optind])
> 		cmd_usage(pc->curcmd, SYNOPSIS);
> 	else
> 		show_spus();
> }
> 
> 
> /*****************************************************************************
>  * SPURQ COMMAND
>  */
> 
> /*
>  * Prints the addresses of SPU contexts on the SPU runqueue.
>  */
> void dump_spu_runq(ulong k_spu_prio)
> {
> 	int i, cnt;
> 	long prio_size, prio_runq_off, ctx_rq_off, jump, offset;
> 	char *u_spu_prio;
> 	ulong kvaddr, uvaddr;
> 	ulong list_head[2];
> 	struct list_data list_data, *ld;
> 
> 	prio_runq_off = MEMBER_OFFSET("spu_prio_array", "runq");
> 	if (prio_runq_off == -1)
> 		error(FATAL, "Couldn't get runq offset.\n");
> 
> 	jump = STRUCT_SIZE("list_head");
> 	if (jump == -1)
> 		error(FATAL, "Couldn't get list_head size.\n");
> 
> 	ctx_rq_off = MEMBER_OFFSET("spu_context", "rq");
> 	if (ctx_rq_off == -1)
> 		error(FATAL, "Couldn't get rq offset.\n");
> 
> 	prio_size = STRUCT_SIZE("spu_prio_array");
> 	if (prio_size == -1)
> 		error(FATAL, "Couldn't get list_head size.\n");
> 
> 	u_spu_prio = (char *)GETBUF(prio_size);
> 	readmem(k_spu_prio, KVADDR, u_spu_prio, prio_size, "get_runq_ctxs", 
> 								FAULT_ON_ERROR);
> 
> 	for (i = 0; i < MAX_PRIO; i++) {
> 		offset = prio_runq_off + (i * jump);
> 		kvaddr = k_spu_prio + offset;
> 		uvaddr = (ulong)u_spu_prio + offset;
> 
> 		BCOPY((char *)uvaddr, (char *)&list_head[0], sizeof(ulong)*2);
> 
> 		if ((list_head[0] == kvaddr) && (list_head[1] == kvaddr))
> 			continue;
> 
> 		fprintf(fp, "PRIO[%i]:\n", i);
> 
> 		ld = &list_data;
> 
> 		BZERO(ld, sizeof(struct list_data));
> 		ld->start = list_head[0];
> 		ld->list_head_offset = ctx_rq_off;
> 		ld->flags |= VERBOSE;
> 		ld->end = kvaddr;
> 
> 		hq_open();
> 		cnt = do_list(ld);
> 		if (cnt == -1) {
> 			hq_close();
> 			FREEBUF(u_spu_prio);
> 			error(FATAL, "Couldn't walk runqueue[%i].\n", i);
> 		}
> 
> 		hq_close();
> 	}
> 
> 	FREEBUF(u_spu_prio);
> }
> 
> /*
>  * spurq stands for "spu run queue" and shows info about the contexts 
>  * that are on the SPU run queue
>  */
> void cmd_spurq()
> {
> 	int c;
> 	ulong spu_prio_addr, spu_prio;
> 	long size;
> 
> 	while ((c = getopt(argcnt, args, "")) != EOF) {
> 		switch(c)
> 		{
> 		default:
> 			argerrs++;
> 			break;
> 		}
> 	}
> 
> 	if (argerrs || args[optind])
> 		cmd_usage(pc->curcmd, SYNOPSIS);
> 	else {
> 		if (symbol_exists("spu_prio")) {
> 			spu_prio_addr = symbol_value("spu_prio");
> 			readmem(spu_prio_addr, KVADDR, &spu_prio,
> 				sizeof(spu_prio), "runq_array", FAULT_ON_ERROR);
> 			dump_spu_runq(spu_prio);
> 		} else
> 			error(FATAL, "Could not get SPU run queue data.\n");
> 	}
> }
> 
> /**********************************************************************************
>  * HELP TEXTS
>  */
> 
> char *help_spuctx[] = {
> 	SPUCTX_CMD_NAME,
> 	"shows complete info about a SPU context and its run control state",
> 	"[args]",
>  
> 	"  This command shows complete info regarding the run control state of \
> a SPU context, including debug info specially saved by kdump during a crash \
> event. The parameters can be the PID of the controller task, number of SPU \
> bound to the context, address of struct spu of this SPU or address of \
> the proper SPU context.",
> 	"\nEXAMPLES",
> 	"  Show info about contexts bound to SPUs 0 and 7, and the one \
> controlled by PID 1524:\n",
> 	"    crash> spuctx 0 7 1524",
> 	"    Dumping context fields for spu_context c00000003dcbdd80:",
> 	"    state                   = 0",
> 	"    prio                    = 120",
> 	"    local_store             = 0xc000000039055840",
> 	"    rq                      = 0xc00000003dcbe720",
> 	"    node                    = 0",
> 	"    number                  = 0",
> 	"    pid                     = 1524",
> 	"    name                    = ",
> 	"    slb_replace             = 0",
> 	"    mm                      = 0xc0000000005dd700",
> 	"    timestamp               = 0x10000566f",
> 	"    class_0_pending         = 0",
> 	"    problem                 = 0xd000080080210000",
> 	"    priv2                   = 0xd000080080230000",
> 	"    flags                   = 0",
> 	"    saved_mfc_sr1_RW        = 59",
> 	"    saved_mfc_dar           = 14987979559889612800",
> 	"    saved_mfc_dsisr         = 0",
> 	"    saved_spu_runcntl_RW    = 1",
> 	"    saved_spu_status_R      = 1",
> 	"    saved_spu_npc_RW        = 0",
> 	"    Dumping context fields for spu_context c00000003dec4e80:",
> 	"    state                   = 0",
> 	"    prio                    = 120",
> 	"    local_store             = 0xc00000003b1cea40",
> 	"    rq                      = 0xc00000003dec5820",
> 	"    node                    = 0",
> 	"    number                  = 7",
> 	"    pid                     = 1538",
> 	"    name                    = ",
> 	"    slb_replace             = 0",
> 	"    mm                      = 0xc0000000005d2b80",
> 	"    timestamp               = 0x10000566f",
> 	"    class_0_pending         = 0",
> 	"    problem                 = 0xd000080080600000",
> 	"    priv2                   = 0xd000080080620000",
> 	"    flags                   = 0",
> 	"    saved_mfc_sr1_RW        = 59",
> 	"    saved_mfc_dar           = 14987979559896297472",
> 	"    saved_mfc_dsisr         = 0",
> 	"    saved_spu_runcntl_RW    = 1",
> 	"    saved_spu_status_R      = 1",
> 	"    saved_spu_npc_RW        = 0",
> 	"    Dumping context fields for spu_context c00000003dcbdd80:",
> 	"    state                   = 0",
> 	"    prio                    = 120",
> 	"    local_store             = 0xc000000039055840",
> 	"    rq                      = 0xc00000003dcbe720",
> 	"    node                    = 0",
> 	"    number                  = 0",
> 	"    pid                     = 1524",
> 	"    name                    = ",
> 	"    slb_replace             = 0",
> 	"    mm                      = 0xc0000000005dd700",
> 	"    timestamp               = 0x10000566f",
> 	"    class_0_pending         = 0",
> 	"    problem                 = 0xd000080080210000",
> 	"    priv2                   = 0xd000080080230000",
> 	"    flags                   = 0",
> 	"    saved_mfc_sr1_RW        = 59",
> 	"    saved_mfc_dar           = 14987979559889612800",
> 	"    saved_mfc_dsisr         = 0",
> 	"    saved_spu_runcntl_RW    = 1",
> 	"    saved_spu_status_R      = 1",
> 	"    saved_spu_npc_RW        = 0",
> 	"    "",",
> 
> 	"  Show info about context whose struct spu_context address is \
> 0xc00000003dcbed80 and the one bound to SPU whose struct spu address is \
> 0xc000000001faca80:\n",
> 	"    crash> spuctx 0x 0xc000000001faca80",
> 	"    ...",
> 	NULL
> };
> 
> 
> char *help_spus[] = {
> 	SPUS_CMD_NAME,
> 	"shows SPU contexts running on each SPE",
> 	" ",
> 	"  This command shows info about all the SPU contexts bound to a SPU. \
> No parameter is needed.",
> 	"\nEXAMPLE",
> 	"  Show SPU contexts:\n",
> 	"    crash> spus",
> 	"    NODE 0:",
> 	"    ID           SPUADDR                 CTXADDR             STATE   PID",
> 	"     0      c000000001fac880        c00000003dcbdd80        LOADED   1524",
> 	"     1      c000000001faca80        c00000003bf34e00        LOADED   1528",
> 	"     2      c000000001facc80        c00000003bf30e00        LOADED   1525",
> 	"     3      c000000001face80        c000000039421d00        LOADED   1533",
> 	"     4      c00000003ee29080        c00000003dec3e80        LOADED   1534",
> 	"     5      c00000003ee28e80        c00000003bf32e00        LOADED   1526",
> 	"     6      c00000003ee28c80        c000000039e5e700        LOADED   1522",
> 	"     7      c00000003ee2e080        c00000003dec4e80        LOADED   1538",
> 	"",
> 	"    NODE 1:",
> 	"    ID           SPUADDR                 CTXADDR             STATE   PID",
> 	"     8      c00000003ee2de80        c00000003dcbed80        LOADED   1529",
> 	"     9      c00000003ee2dc80        c00000003bf39e00        LOADED   1535",
> 	"    10      c00000003ee2da80        c00000003bf3be00        LOADED   1521",
> 	"    11      c000000001fad080        c000000039420d00        LOADED   1532",
> 	"    12      c000000001fad280        c00000003bf3ee00        LOADED   1536",
> 	"    13      c000000001fad480        c00000003dec2e80        LOADED   1539",
> 	"    14      c000000001fad680        c00000003bf3ce00        LOADED   1537",
> 	"    15      c000000001fad880        c00000003dec6e80        LOADED   1540",
> 	NULL
> };
> 
> 
> char *help_spurq[] = {
> 	SPURQ_CMD_NAME,
> 	"shows SPU contexts on the runqueue",
> 	" ",
> 	"  This command shows info about all the SPU contexts waiting for \
> execution in the processor. No parameter is needed.",
> 	"\nEXAMPLE",
> 	"  Show SPU runqueue:\n",
> 	"    crash> spurq",
> 	"    PRIO[120]:",
> 	"    c000000000fd7380",
> 	"    c00000003bf31e00",
> 	"    PRIO[125]:",
> 	"    c000000039422d00",
> 	"    c00000000181eb80",
> 	NULL
> };
> 
> 
> 
> ------------------------------------------------------------------------
> 
> --
> Crash-utility mailing list
> Crash-utility at redhat.com
> https://www.redhat.com/mailman/listinfo/crash-utility





More information about the Crash-utility mailing list