LCOV - code coverage report
Current view: top level - core - trace.c (source / functions) Hit Total Coverage
Test: skiboot.info Lines: 90 126 71.4 %
Date: 2024-09-10 18:37:41 Functions: 5 7 71.4 %
Branches: 0 0 -

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
       2                 :            : /*
       3                 :            :  * Trace various things into in-memory buffers
       4                 :            :  *
       5                 :            :  * Copyright 2013-2019 IBM Corp.
       6                 :            :  */
       7                 :            : 
       8                 :            : #include <trace.h>
       9                 :            : #include <timebase.h>
      10                 :            : #include <lock.h>
      11                 :            : #include <string.h>
      12                 :            : #include <stdlib.h>
      13                 :            : #include <inttypes.h>
      14                 :            : #include <cpu.h>
      15                 :            : #include <device.h>
      16                 :            : #include <libfdt.h>
      17                 :            : #include <processor.h>
      18                 :            : #include <skiboot.h>
      19                 :            : #include <opal-api.h>
      20                 :            : #include <debug_descriptor.h>
      21                 :            : #include <nvram.h>
      22                 :            : 
      23                 :            : #define DEBUG_TRACES
      24                 :            : 
      25                 :            : #define MAX_SIZE sizeof(union trace)
      26                 :            : 
      27                 :            : /* Smaller trace buffer for early booting */
      28                 :            : #define BOOT_TBUF_SZ 65536
      29                 :            : static struct {
      30                 :            :         struct trace_info trace_info;
      31                 :            :         char buf[BOOT_TBUF_SZ + MAX_SIZE];
      32                 :            : } boot_tracebuf __section(".data.boot_trace");
      33                 :            : 
      34                 :          0 : void init_boot_tracebuf(struct cpu_thread *boot_cpu)
      35                 :            : {
      36                 :          0 :         init_lock(&boot_tracebuf.trace_info.lock);
      37                 :          0 :         boot_tracebuf.trace_info.tb.buf_size = cpu_to_be64(BOOT_TBUF_SZ);
      38                 :          0 :         boot_tracebuf.trace_info.tb.max_size = cpu_to_be32(MAX_SIZE);
      39                 :            : 
      40                 :          0 :         boot_cpu->trace = &boot_tracebuf.trace_info;
      41                 :          0 : }
      42                 :            : 
      43                 :          4 : static size_t tracebuf_extra(void)
      44                 :            : {
      45                 :            :         /* We make room for the largest possible record */
      46                 :          4 :         return TBUF_SZ + MAX_SIZE;
      47                 :            : }
      48                 :            : 
      49                 :            : /* To avoid bloating each entry, repeats are actually specific entries.
      50                 :            :  * tb->last points to the last (non-repeat) entry. */
      51                 :    6418116 : static bool handle_repeat(struct tracebuf *tb, const union trace *trace)
      52                 :            : {
      53                 :            :         struct trace_hdr *prev;
      54                 :            :         struct trace_repeat *rpt;
      55                 :            :         u32 len;
      56                 :            : 
      57                 :    6418116 :         prev = (void *)tb->buf + be64_to_cpu(tb->last) % be64_to_cpu(tb->buf_size);
      58                 :            : 
      59                 :    6418116 :         if (prev->type != trace->hdr.type
      60                 :    3121739 :             || prev->len_div_8 != trace->hdr.len_div_8
      61                 :    3121739 :             || prev->cpu != trace->hdr.cpu)
      62                 :    3296377 :                 return false;
      63                 :            : 
      64                 :    3121739 :         len = prev->len_div_8 << 3;
      65                 :    3121739 :         if (memcmp(prev + 1, &trace->hdr + 1, len - sizeof(*prev)) != 0)
      66                 :          0 :                 return false;
      67                 :            : 
      68                 :            :         /* If they've consumed prev entry, don't repeat. */
      69                 :    3121739 :         if (be64_to_cpu(tb->last) < be64_to_cpu(tb->start))
      70                 :          0 :                 return false;
      71                 :            : 
      72                 :            :         /* OK, it's a duplicate.  Do we already have repeat? */
      73                 :    3121739 :         if (be64_to_cpu(tb->last) + len != be64_to_cpu(tb->end)) {
      74                 :    1985763 :                 u64 pos = be64_to_cpu(tb->last) + len;
      75                 :            :                 /* FIXME: Reader is not protected from seeing this! */
      76                 :    1985763 :                 rpt = (void *)tb->buf + pos % be64_to_cpu(tb->buf_size);
      77                 :    1985763 :                 assert(pos + rpt->len_div_8*8 == be64_to_cpu(tb->end));
      78                 :    1985763 :                 assert(rpt->type == TRACE_REPEAT);
      79                 :            : 
      80                 :            :                 /* If this repeat entry is full, don't repeat. */
      81                 :    1985763 :                 if (be16_to_cpu(rpt->num) == 0xFFFF)
      82                 :         16 :                         return false;
      83                 :            : 
      84                 :    1985747 :                 rpt->num = cpu_to_be16(be16_to_cpu(rpt->num) + 1);
      85                 :    1985747 :                 rpt->timestamp = trace->hdr.timestamp;
      86                 :    1985747 :                 return true;
      87                 :            :         }
      88                 :            : 
      89                 :            :         /*
      90                 :            :          * Generate repeat entry: it's the smallest possible entry, so we
      91                 :            :          * must have eliminated old entries.
      92                 :            :          */
      93                 :    1135976 :         assert(trace->hdr.len_div_8 * 8 >= sizeof(*rpt));
      94                 :            : 
      95                 :    1135976 :         rpt = (void *)tb->buf + be64_to_cpu(tb->end) % be64_to_cpu(tb->buf_size);
      96                 :    1135976 :         rpt->timestamp = trace->hdr.timestamp;
      97                 :    1135976 :         rpt->type = TRACE_REPEAT;
      98                 :    1135976 :         rpt->len_div_8 = sizeof(*rpt) >> 3;
      99                 :    1135976 :         rpt->cpu = trace->hdr.cpu;
     100                 :    1135976 :         rpt->prev_len = cpu_to_be16(trace->hdr.len_div_8 << 3);
     101                 :    1135976 :         rpt->num = cpu_to_be16(1);
     102                 :    1135976 :         lwsync(); /* write barrier: complete repeat record before exposing */
     103                 :    1135976 :         tb->end = cpu_to_be64(be64_to_cpu(tb->end) + sizeof(*rpt));
     104                 :    1135976 :         return true;
     105                 :            : }
     106                 :            : 
     107                 :    6418116 : void trace_add(union trace *trace, u8 type, u16 len)
     108                 :            : {
     109                 :    6418116 :         struct trace_info *ti = this_cpu()->trace;
     110                 :            :         unsigned int tsz;
     111                 :            : 
     112                 :    6418116 :         trace->hdr.type = type;
     113                 :    6418116 :         trace->hdr.len_div_8 = (len + 7) >> 3;
     114                 :            : 
     115                 :    6418116 :         tsz = trace->hdr.len_div_8 << 3;
     116                 :            : 
     117                 :            : #ifdef DEBUG_TRACES
     118                 :    6418116 :         assert(tsz >= sizeof(trace->hdr));
     119                 :    6418116 :         assert(tsz <= sizeof(*trace));
     120                 :    6418116 :         assert(trace->hdr.type != TRACE_REPEAT);
     121                 :    6418116 :         assert(trace->hdr.type != TRACE_OVERFLOW);
     122                 :            : #endif
     123                 :            :         /* Skip traces not enabled in the debug descriptor */
     124                 :    6418116 :         if (trace->hdr.type < (8 * sizeof(debug_descriptor.trace_mask)) &&
     125                 :    3997699 :             !((1ul << trace->hdr.type) & be64_to_cpu(debug_descriptor.trace_mask)))
     126                 :          0 :                 return;
     127                 :            : 
     128                 :    6418116 :         trace->hdr.timestamp = cpu_to_be64(mftb());
     129                 :    6418116 :         trace->hdr.cpu = cpu_to_be16(this_cpu()->server_no);
     130                 :            : 
     131                 :    6418116 :         lock(&ti->lock);
     132                 :            : 
     133                 :            :         /* Throw away old entries before we overwrite them. */
     134                 :   10572499 :         while ((be64_to_cpu(ti->tb.start) + be64_to_cpu(ti->tb.buf_size))
     135                 :   10572499 :                < (be64_to_cpu(ti->tb.end) + tsz)) {
     136                 :            :                 struct trace_hdr *hdr;
     137                 :            : 
     138                 :    8308766 :                 hdr = (void *)ti->tb.buf +
     139                 :    4154383 :                         be64_to_cpu(ti->tb.start) % be64_to_cpu(ti->tb.buf_size);
     140                 :    8308766 :                 ti->tb.start = cpu_to_be64(be64_to_cpu(ti->tb.start) +
     141                 :    4154383 :                                            (hdr->len_div_8 << 3));
     142                 :            :         }
     143                 :            : 
     144                 :            :         /* Must update ->start before we rewrite new entries. */
     145                 :    6418116 :         lwsync(); /* write barrier */
     146                 :            : 
     147                 :            :         /* Check for duplicates... */
     148                 :    6418116 :         if (!handle_repeat(&ti->tb, trace)) {
     149                 :            :                 /* This may go off end, and that's why ti->tb.buf is oversize */
     150                 :    3296393 :                 memcpy(ti->tb.buf + be64_to_cpu(ti->tb.end) % be64_to_cpu(ti->tb.buf_size),
     151                 :            :                        trace, tsz);
     152                 :    3296393 :                 ti->tb.last = ti->tb.end;
     153                 :    3296393 :                 lwsync(); /* write barrier: write entry before exposing */
     154                 :    3296393 :                 ti->tb.end = cpu_to_be64(be64_to_cpu(ti->tb.end) + tsz);
     155                 :            :         }
     156                 :    6418116 :         unlock(&ti->lock);
     157                 :            : }
     158                 :            : 
     159                 :          0 : void trace_add_dt_props(void)
     160                 :            : {
     161                 :          0 :         uint64_t boot_buf_phys = (uint64_t) &boot_tracebuf.trace_info;
     162                 :            :         struct dt_node *exports, *traces;
     163                 :            :         unsigned int i;
     164                 :            :         fdt64_t *prop;
     165                 :            :         u64 tmask;
     166                 :            :         char tname[256];
     167                 :            : 
     168                 :          0 :         exports = dt_find_by_path(opal_node, "firmware/exports");
     169                 :          0 :         if (!exports)
     170                 :          0 :                 return;
     171                 :            : 
     172                 :            :         /*
     173                 :            :          * nvram hack to put all the trace buffer exports in the exports
     174                 :            :          * node. This is useful if the kernel doesn't also export subnodes.
     175                 :            :          */
     176                 :          0 :         if (nvram_query_safe("flat-trace-buf"))
     177                 :          0 :                 traces = exports;
     178                 :            :         else
     179                 :          0 :                 traces = dt_new(exports, "traces");
     180                 :            : 
     181                 :          0 :         prop = malloc(sizeof(u64) * 2 * be32_to_cpu(debug_descriptor.num_traces));
     182                 :            : 
     183                 :          0 :         for (i = 0; i < be32_to_cpu(debug_descriptor.num_traces); i++) {
     184                 :          0 :                 uint64_t addr = be64_to_cpu(debug_descriptor.trace_phys[i]);
     185                 :          0 :                 uint64_t size = be32_to_cpu(debug_descriptor.trace_size[i]);
     186                 :          0 :                 uint32_t pir = be16_to_cpu(debug_descriptor.trace_pir[i]);
     187                 :            : 
     188                 :          0 :                 prop[i * 2]     = cpu_to_fdt64(addr);
     189                 :          0 :                 prop[i * 2 + 1] = cpu_to_fdt64(size);
     190                 :            : 
     191                 :          0 :                 if (addr == boot_buf_phys)
     192                 :          0 :                         snprintf(tname, sizeof(tname), "boot-%x", pir);
     193                 :            :                 else
     194                 :          0 :                         snprintf(tname, sizeof(tname), "trace-%x", pir);
     195                 :            : 
     196                 :          0 :                 dt_add_property_u64s(traces, tname, addr, size);
     197                 :            :         }
     198                 :            : 
     199                 :          0 :         dt_add_property(opal_node, "ibm,opal-traces",
     200                 :            :                         prop, sizeof(u64) * 2 * i);
     201                 :          0 :         free(prop);
     202                 :            : 
     203                 :          0 :         tmask = (uint64_t)&debug_descriptor.trace_mask;
     204                 :          0 :         dt_add_property_u64(opal_node, "ibm,opal-trace-mask", tmask);
     205                 :            : }
     206                 :            : 
     207                 :          3 : static void trace_add_desc(struct trace_info *t, uint64_t size, uint16_t pir)
     208                 :            : {
     209                 :          3 :         unsigned int i = be32_to_cpu(debug_descriptor.num_traces);
     210                 :            : 
     211                 :          3 :         if (i >= DEBUG_DESC_MAX_TRACES) {
     212                 :          0 :                 prerror("TRACE: Debug descriptor trace list full !\n");
     213                 :          0 :                 return;
     214                 :            :         }
     215                 :            : 
     216                 :          3 :         debug_descriptor.num_traces = cpu_to_be32(i + 1);
     217                 :          3 :         debug_descriptor.trace_phys[i] = cpu_to_be64((uint64_t)t);
     218                 :          3 :         debug_descriptor.trace_tce[i] = 0; /* populated later */
     219                 :          3 :         debug_descriptor.trace_size[i] = cpu_to_be32(size);
     220                 :          3 :         debug_descriptor.trace_pir[i] = cpu_to_be16(pir);
     221                 :            : }
     222                 :            : 
     223                 :            : /* Allocate trace buffers once we know memory topology */
     224                 :          1 : void init_trace_buffers(void)
     225                 :            : {
     226                 :            :         struct cpu_thread *t;
     227                 :          1 :         struct trace_info *any = &boot_tracebuf.trace_info;
     228                 :            :         uint64_t size;
     229                 :            : 
     230                 :            :         /* Boot the boot trace in the debug descriptor */
     231                 :          1 :         trace_add_desc(any, sizeof(boot_tracebuf), this_cpu()->pir);
     232                 :            : 
     233                 :            :         /* Allocate a trace buffer for each primary cpu. */
     234                 :          5 :         for_each_cpu(t) {
     235                 :          4 :                 if (t->is_secondary)
     236                 :          2 :                         continue;
     237                 :            : 
     238                 :            :                 /* Use a 64K alignment for TCE mapping */
     239                 :          2 :                 size = ALIGN_UP(sizeof(*t->trace) + tracebuf_extra(), 0x10000);
     240                 :          2 :                 t->trace = local_alloc(t->chip_id, size, 0x10000);
     241                 :          2 :                 if (t->trace) {
     242                 :          2 :                         any = t->trace;
     243                 :          2 :                         memset(t->trace, 0, size);
     244                 :          2 :                         init_lock(&t->trace->lock);
     245                 :          2 :                         t->trace->tb.max_size = cpu_to_be32(MAX_SIZE);
     246                 :          2 :                         t->trace->tb.buf_size = cpu_to_be64(TBUF_SZ);
     247                 :          2 :                         trace_add_desc(any, sizeof(t->trace->tb) +
     248                 :          2 :                                        tracebuf_extra(), t->pir);
     249                 :            :                 } else
     250                 :          0 :                         prerror("TRACE: cpu 0x%x allocation failed\n", t->pir);
     251                 :            :         }
     252                 :            : 
     253                 :            :         /* In case any allocations failed, share trace buffers. */
     254                 :          5 :         for_each_cpu(t) {
     255                 :          4 :                 if (!t->is_secondary && !t->trace)
     256                 :          0 :                         t->trace = any;
     257                 :            :         }
     258                 :            : 
     259                 :            :         /* And copy those to the secondaries. */
     260                 :          5 :         for_each_cpu(t) {
     261                 :          4 :                 if (!t->is_secondary)
     262                 :          2 :                         continue;
     263                 :          2 :                 t->trace = t->primary->trace;
     264                 :            :         }
     265                 :          1 : }

Generated by: LCOV version 1.14