~ubuntu-branches/ubuntu/saucy/u-boot/saucy

« back to all changes in this revision

Viewing changes to common/bootstage.c

  • Committer: Package Import Robot
  • Author(s): Clint Adams
  • Date: 2012-05-01 18:07:19 UTC
  • mfrom: (16.1.23 sid)
  • Revision ID: package-import@ubuntu.com-20120501180719-rjntk3287im4a0ns
Tags: 2012.04.01-1
* New upstream version.
  - Update mipsel-native-endianness.diff.
  - Update no-error-on-set-but-unused-variables.diff (partially merged).
  - Drop kirkwood_spi-irq_mask.diff (merged).
  - Drop kirkwood-disable-l2c.diff (merged).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (c) 2011, Google Inc. All rights reserved.
 
3
 *
 
4
 * See file CREDITS for list of people who contributed to this
 
5
 * project.
 
6
 *
 
7
 * This program is free software; you can redistribute it and/or
 
8
 * modify it under the terms of the GNU General Public License as
 
9
 * published by the Free Software Foundation; either version 2 of
 
10
 * the License, or (at your option) any later version.
 
11
 *
 
12
 * This program is distributed in the hope that it will be useful,
 
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
 * GNU General Public License for more details.
 
16
 *
 
17
 * You should have received a copy of the GNU General Public License
 
18
 * along with this program; if not, write to the Free Software
 
19
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 
20
 * MA 02111-1307 USA
 
21
 */
 
22
 
 
23
 
 
24
/*
 
25
 * This module records the progress of boot and arbitrary commands, and
 
26
 * permits accurate timestamping of each.
 
27
 *
 
28
 * TBD: Pass timings to kernel in the FDT
 
29
 */
 
30
 
 
31
#include <common.h>
 
32
#include <libfdt.h>
 
33
 
 
34
DECLARE_GLOBAL_DATA_PTR;
 
35
 
 
36
enum bootstage_flags {
 
37
        BOOTSTAGEF_ERROR        = 1 << 0,       /* Error record */
 
38
        BOOTSTAGEF_ALLOC        = 1 << 1,       /* Allocate an id */
 
39
};
 
40
 
 
41
struct bootstage_record {
 
42
        ulong time_us;
 
43
        const char *name;
 
44
        int flags;              /* see enum bootstage_flags */
 
45
        enum bootstage_id id;
 
46
};
 
47
 
 
48
static struct bootstage_record record[BOOTSTAGE_ID_COUNT] = { {1} };
 
49
static int next_id = BOOTSTAGE_ID_USER;
 
50
 
 
51
ulong bootstage_add_record(enum bootstage_id id, const char *name,
 
52
                           int flags)
 
53
{
 
54
        struct bootstage_record *rec;
 
55
        ulong mark = timer_get_boot_us();
 
56
 
 
57
        if (flags & BOOTSTAGEF_ALLOC)
 
58
                id = next_id++;
 
59
 
 
60
        if (id < BOOTSTAGE_ID_COUNT) {
 
61
                rec = &record[id];
 
62
 
 
63
                /* Only record the first event for each */
 
64
                if (!rec->time_us) {
 
65
                        rec->time_us = mark;
 
66
                        rec->name = name;
 
67
                        rec->flags = flags;
 
68
                        rec->id = id;
 
69
                }
 
70
        }
 
71
 
 
72
        /* Tell the board about this progress */
 
73
        show_boot_progress(flags & BOOTSTAGEF_ERROR ? -id : id);
 
74
        return mark;
 
75
}
 
76
 
 
77
 
 
78
ulong bootstage_mark(enum bootstage_id id)
 
79
{
 
80
        return bootstage_add_record(id, NULL, 0);
 
81
}
 
82
 
 
83
ulong bootstage_error(enum bootstage_id id)
 
84
{
 
85
        return bootstage_add_record(id, NULL, BOOTSTAGEF_ERROR);
 
86
}
 
87
 
 
88
ulong bootstage_mark_name(enum bootstage_id id, const char *name)
 
89
{
 
90
        int flags = 0;
 
91
 
 
92
        if (id == BOOTSTAGE_ID_ALLOC)
 
93
                flags = BOOTSTAGEF_ALLOC;
 
94
        return bootstage_add_record(id, name, flags);
 
95
}
 
96
 
 
97
static void print_time(unsigned long us_time)
 
98
{
 
99
        char str[15], *s;
 
100
        int grab = 3;
 
101
 
 
102
        /* We don't seem to have %'d in U-Boot */
 
103
        sprintf(str, "%12lu", us_time);
 
104
        for (s = str + 3; *s; s += grab) {
 
105
                if (s != str + 3)
 
106
                        putc(s[-1] != ' ' ? ',' : ' ');
 
107
                printf("%.*s", grab, s);
 
108
                grab = 3;
 
109
        }
 
110
}
 
111
 
 
112
static uint32_t print_time_record(enum bootstage_id id,
 
113
                        struct bootstage_record *rec, uint32_t prev)
 
114
{
 
115
        print_time(rec->time_us);
 
116
        print_time(rec->time_us - prev);
 
117
        if (rec->name)
 
118
                printf("  %s\n", rec->name);
 
119
        else if (id >= BOOTSTAGE_ID_USER)
 
120
                printf("  user_%d\n", id - BOOTSTAGE_ID_USER);
 
121
        else
 
122
                printf("  id=%d\n", id);
 
123
        return rec->time_us;
 
124
}
 
125
 
 
126
static int h_compare_record(const void *r1, const void *r2)
 
127
{
 
128
        const struct bootstage_record *rec1 = r1, *rec2 = r2;
 
129
 
 
130
        return rec1->time_us > rec2->time_us ? 1 : -1;
 
131
}
 
132
 
 
133
void bootstage_report(void)
 
134
{
 
135
        struct bootstage_record *rec = record;
 
136
        int id;
 
137
        uint32_t prev;
 
138
 
 
139
        puts("Timer summary in microseconds:\n");
 
140
        printf("%11s%11s  %s\n", "Mark", "Elapsed", "Stage");
 
141
 
 
142
        /* Fake the first record - we could get it from early boot */
 
143
        rec->name = "reset";
 
144
        rec->time_us = 0;
 
145
        prev = print_time_record(BOOTSTAGE_ID_AWAKE, rec, 0);
 
146
 
 
147
        /* Sort records by increasing time */
 
148
        qsort(record, ARRAY_SIZE(record), sizeof(*rec), h_compare_record);
 
149
 
 
150
        for (id = 0; id < BOOTSTAGE_ID_COUNT; id++, rec++) {
 
151
                if (rec->time_us != 0)
 
152
                        prev = print_time_record(rec->id, rec, prev);
 
153
        }
 
154
        if (next_id > BOOTSTAGE_ID_COUNT)
 
155
                printf("(Overflowed internal boot id table by %d entries\n"
 
156
                        "- please increase CONFIG_BOOTSTAGE_USER_COUNT\n",
 
157
                       next_id - BOOTSTAGE_ID_COUNT);
 
158
}
 
159
 
 
160
ulong __timer_get_boot_us(void)
 
161
{
 
162
        static ulong base_time;
 
163
 
 
164
        /*
 
165
         * We can't implement this properly. Return 0 on the first call and
 
166
         * larger values after that.
 
167
         */
 
168
        if (base_time)
 
169
                return get_timer(base_time) * 1000;
 
170
        base_time = get_timer(0);
 
171
        return 0;
 
172
}
 
173
 
 
174
ulong timer_get_boot_us(void)
 
175
        __attribute__((weak, alias("__timer_get_boot_us")));