From 1da82c4a408aab85be7814f392f45f81ed74dfea Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 20 Oct 2014 14:22:29 +1100 Subject: Move external trace stuff to a subdirectory Signed-off-by: Benjamin Herrenschmidt --- external/trace/Makefile | 7 ++ external/trace/dump_trace.c | 197 ++++++++++++++++++++++++++++++++++++++++++++ external/trace/trace.c | 105 +++++++++++++++++++++++ external/trace/trace.h | 20 +++++ 4 files changed, 329 insertions(+) create mode 100644 external/trace/Makefile create mode 100644 external/trace/dump_trace.c create mode 100644 external/trace/trace.c create mode 100644 external/trace/trace.h (limited to 'external/trace') diff --git a/external/trace/Makefile b/external/trace/Makefile new file mode 100644 index 00000000..b4b0091b --- /dev/null +++ b/external/trace/Makefile @@ -0,0 +1,7 @@ +HOSTEND=$(shell uname -m | sed -e 's/^i.*86$$/LITTLE/' -e 's/^x86.*/LITTLE/' -e 's/^ppc.*/BIG/') +CFLAGS=-g -Wall -DHAVE_$(HOSTEND)_ENDIAN -I../include + +dump_trace: dump_trace.c + +clean: + rm -f dump_trace *.o diff --git a/external/trace/dump_trace.c b/external/trace/dump_trace.c new file mode 100644 index 00000000..9364601c --- /dev/null +++ b/external/trace/dump_trace.c @@ -0,0 +1,197 @@ +/* Copyright 2013-2014 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../ccan/endian/endian.h" +#include "../ccan/short_types/short_types.h" +#include + +/* Handles trace from debugfs (one record at a time) or file */ +static bool get_trace(int fd, union trace *t, int *len) +{ + void *dest = t; + int r; + + /* Move down any extra we read last time. */ + if (*len >= sizeof(t->hdr) && *len >= t->hdr.len_div_8 * 8) { + u8 rlen = t->hdr.len_div_8 * 8; + memmove(dest, dest + rlen, *len - rlen); + *len -= rlen; + } + + r = read(fd, dest + *len, sizeof(*t) - *len); + if (r < 0) + return false; + + *len += r; + /* We should have a complete record. */ + return *len >= sizeof(t->hdr) && *len >= t->hdr.len_div_8 * 8; +} + +static void display_header(const struct trace_hdr *h) +{ + static u64 prev_ts; + u64 ts = be64_to_cpu(h->timestamp); + + printf("%16lx (+%8lx) [%03x] : ", + ts, prev_ts ? (ts - prev_ts) : 0, h->cpu); + prev_ts = ts; +} + +static void dump_fsp_event(struct trace_fsp_event *t) +{ + printf("FSP_EVT [st=%d] ", t->fsp_state); + + switch(t->event) { + case TRACE_FSP_EVT_LINK_DOWN: + printf("LINK DOWN"); + break; + case TRACE_FSP_EVT_DISR_CHG: + printf("DISR CHANGE (0x%08x)", t->data[0]); + break; + case TRACE_FSP_EVT_SOFT_RR: + printf("SOFT R&R (DISR=0x%08x)", t->data[0]); + break; + case TRACE_FSP_EVT_RR_COMPL: + printf("R&R COMPLETE"); + break; + case TRACE_FSP_EVT_HDES_CHG: + printf("HDES CHANGE (0x%08x)", t->data[0]); + break; + case TRACE_FSP_EVT_POLL_IRQ: + printf("%s HDIR=%08x CTL=%08x PSI_IRQ=%d", + t->data[0] ? "IRQ " : "POLL", t->data[1], + t->data[2], t->data[3]); + break; + default: + printf("Unknown %d (d: %08x %08x %08x %08x)", + t->event, t->data[0], t->data[1], + t->data[2], t->data[3]); + } + printf("\n"); +} + +static void dump_opal_call(struct trace_opal *t) +{ + unsigned int i, n; + + printf("OPAL CALL %"PRIu64, be64_to_cpu(t->token)); + printf(" LR=0x%016"PRIx64" SP=0x%016"PRIx64, + be64_to_cpu(t->lr), be64_to_cpu(t->sp)); + n = (t->hdr.len_div_8 * 8 - offsetof(union trace, opal.r3_to_11)) + / sizeof(u64); + for (i = 0; i < n; i++) + printf(" R%u=0x%016"PRIx64, + i+3, be64_to_cpu(t->r3_to_11[i])); + printf("\n"); +} + +static void dump_fsp_msg(struct trace_fsp_msg *t) +{ + unsigned int i; + + printf("FSP_MSG: CMD %u SEQ %u MOD %u SUB %u DLEN %u %s [", + be32_to_cpu(t->word0) & 0xFFFF, + be32_to_cpu(t->word0) >> 16, + be32_to_cpu(t->word1) >> 8, + be32_to_cpu(t->word1) & 0xFF, + t->dlen, + t->dir == TRACE_FSP_MSG_IN ? "IN" : + (t->dir == TRACE_FSP_MSG_OUT ? "OUT" : "UNKNOWN")); + + for (i = 0; i < t->dlen; i++) + printf("%s%02x", i ? " " : "", t->data[i]); + printf("]\n"); +} + +static void dump_uart(struct trace_uart *t) +{ + switch(t->ctx) { + case TRACE_UART_CTX_IRQ: + printf(": IRQ IRQEN=%d IN_CNT=%d\n", + !t->irq_state, t->in_count); + break; + case TRACE_UART_CTX_POLL: + printf(": POLL IRQEN=%d IN_CNT=%d\n", + !t->irq_state, t->in_count); + break; + case TRACE_UART_CTX_READ: + printf(": READ IRQEN=%d IN_CNT=%d READ=%d\n", + !t->irq_state, t->in_count, t->cnt); + break; + default: + printf(": ???? IRQEN=%d IN_CNT=%d\n", + !t->irq_state, t->in_count); + break; + } +} + +int main(int argc, char *argv[]) +{ + int fd, len = 0; + union trace t; + const char *in = "/sys/kernel/debug/powerpc/opal-trace"; + + if (argc > 2) + errx(1, "Usage: dump_trace [file]"); + + if (argv[1]) + in = argv[1]; + fd = open(in, O_RDONLY); + if (fd < 0) + err(1, "Opening %s", in); + + while (get_trace(fd, &t, &len)) { + display_header(&t.hdr); + switch (t.hdr.type) { + case TRACE_REPEAT: + printf("REPEATS: %u times\n", + be32_to_cpu(t.repeat.num)); + break; + case TRACE_OVERFLOW: + printf("**OVERFLOW**: %"PRIu64" bytes missed\n", + be64_to_cpu(t.overflow.bytes_missed)); + break; + case TRACE_OPAL: + dump_opal_call(&t.opal); + break; + case TRACE_FSP_MSG: + dump_fsp_msg(&t.fsp_msg); + break; + case TRACE_FSP_EVENT: + dump_fsp_event(&t.fsp_evt); + break; + case TRACE_UART: + dump_uart(&t.uart); + break; + default: + printf("UNKNOWN(%u) CPU %u length %u\n", + t.hdr.type, be16_to_cpu(t.hdr.cpu), + t.hdr.len_div_8 * 8); + } + } + return 0; +} diff --git a/external/trace/trace.c b/external/trace/trace.c new file mode 100644 index 00000000..43ed19bc --- /dev/null +++ b/external/trace/trace.c @@ -0,0 +1,105 @@ +/* Copyright 2013-2014 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. + */ +/* This example code shows how to read from the trace buffer. */ +#include +#include +#include + +bool trace_empty(const struct tracebuf *tb) +{ + const struct trace_repeat *rep; + + if (tb->rpos == tb->end) + return true; + + /* + * If we have a single element only, and it's a repeat buffer + * we've already seen every repeat for (yet which may be + * incremented in future), we're also empty. + */ + rep = (void *)tb->buf + (tb->rpos & tb->mask); + if (tb->end != tb->rpos + sizeof(*rep)) + return false; + + if (rep->type != TRACE_REPEAT) + return false; + + if (rep->num != tb->last_repeat) + return false; + + return true; +} + +/* You can't read in parallel, so some locking required in caller. */ +bool trace_get(union trace *t, struct tracebuf *tb) +{ + u64 start; + size_t len = sizeof(*t) < tb->max_size ? sizeof(*t) : tb->max_size; + + if (trace_empty(tb)) + return false; + +again: + /* + * The actual buffer is slightly larger than tbsize, so this + * memcpy is always valid. + */ + memcpy(t, tb->buf + (tb->rpos & tb->mask), len); + + rmb(); /* read barrier, so we read tb->start after copying record. */ + + start = tb->start; + + /* Now, was that overwritten? */ + if (tb->rpos < start) { + /* Create overflow record. */ + t->overflow.unused64 = 0; + t->overflow.type = TRACE_OVERFLOW; + t->overflow.len_div_8 = sizeof(t->overflow) / 8; + t->overflow.bytes_missed = start - tb->rpos; + tb->rpos += t->overflow.bytes_missed; + return true; + } + + /* Repeat entries need special handling */ + if (t->hdr.type == TRACE_REPEAT) { + u32 num = t->repeat.num; + + /* In case we've read some already... */ + t->repeat.num -= tb->last_repeat; + + /* Record how many repeats we saw this time. */ + tb->last_repeat = num; + + /* Don't report an empty repeat buffer. */ + if (t->repeat.num == 0) { + /* + * This can't be the last buffer, otherwise + * trace_empty would have returned true. + */ + assert(tb->end > tb->rpos + t->hdr.len_div_8 * 8); + /* Skip to next entry. */ + tb->rpos += t->hdr.len_div_8 * 8; + tb->last_repeat = 0; + goto again; + } + } else { + tb->last_repeat = 0; + tb->rpos += t->hdr.len_div_8 * 8; + } + + return true; +} diff --git a/external/trace/trace.h b/external/trace/trace.h new file mode 100644 index 00000000..4d2dbc79 --- /dev/null +++ b/external/trace/trace.h @@ -0,0 +1,20 @@ +/* Copyright 2013-2014 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. + */ +/* Is this tracebuf empty? */ +bool trace_empty(const struct tracebuf *tracebuf); + +/* Get the next trace from this buffer (false if empty). */ +bool trace_get(union trace *t, struct tracebuf *tb); -- cgit v1.2.1