summaryrefslogtreecommitdiffstats
path: root/external/trace
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2014-10-20 14:22:29 +1100
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2014-10-20 17:41:04 +1100
commit1da82c4a408aab85be7814f392f45f81ed74dfea (patch)
treeaaa6f42c70b9b680a807cf232087edee22657f7d /external/trace
parenta8d479c63a4bbc99808a37f6958b3de517569918 (diff)
downloadtalos-skiboot-1da82c4a408aab85be7814f392f45f81ed74dfea.tar.gz
talos-skiboot-1da82c4a408aab85be7814f392f45f81ed74dfea.zip
Move external trace stuff to a subdirectory
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'external/trace')
-rw-r--r--external/trace/Makefile7
-rw-r--r--external/trace/dump_trace.c197
-rw-r--r--external/trace/trace.c105
-rw-r--r--external/trace/trace.h20
4 files changed, 329 insertions, 0 deletions
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 <err.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <unistd.h>
+
+#include "../ccan/endian/endian.h"
+#include "../ccan/short_types/short_types.h"
+#include <trace_types.h>
+
+/* 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 <external/trace.h>
+#include <trace_types.h>
+#include <errno.h>
+
+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);
OpenPOWER on IntegriCloud