Cell/B.E. SPU commands extension

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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.


Thanks in advance,
-- 
Lucio Correia
Software Engineer
IBM LTC Brazil
/* spu.c - commands for viewing Cell/B.E. SPUs data
 *
 * (C) Copyright 2007 IBM Corp.
 *
 * Author: Lucio Correia <luciojhc@xxxxxxxxxx>
 *
 * 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@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/crash-utility

[Index of Archives]     [Fedora Development]     [Fedora Desktop]     [Fedora SELinux]     [Yosemite News]     [KDE Users]     [Fedora Tools]

 

Powered by Linux