~pmdj/ubuntu/trusty/qemu/2.9+applesmc+fadtv3

« back to all changes in this revision

Viewing changes to roms/skiboot/core/errorlog.c

  • Committer: Phil Dennis-Jordan
  • Date: 2017-07-21 08:03:43 UTC
  • mfrom: (1.1.1)
  • Revision ID: phil@philjordan.eu-20170721080343-2yr2vdj7713czahv
New upstream release 2.9.0.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright 2013-2014 IBM Corp.
 
2
 *
 
3
 * Licensed under the Apache License, Version 2.0 (the "License");
 
4
 * you may not use this file except in compliance with the License.
 
5
 * You may obtain a copy of the License at
 
6
 *
 
7
 *      http://www.apache.org/licenses/LICENSE-2.0
 
8
 *
 
9
 * Unless required by applicable law or agreed to in writing, software
 
10
 * distributed under the License is distributed on an "AS IS" BASIS,
 
11
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 
12
 * implied.
 
13
 * See the License for the specific language governing permissions and
 
14
 * limitations under the License.
 
15
 */
 
16
 
 
17
/* This file contains the front end for OPAL error logging. It is used
 
18
 * to construct a struct errorlog representing the event/error to be
 
19
 * logged which is then passed to the platform specific backend to log
 
20
 * the actual errors.
 
21
 */
 
22
#include <skiboot.h>
 
23
#include <lock.h>
 
24
#include <errorlog.h>
 
25
#include <pool.h>
 
26
 
 
27
/*
 
28
 * Maximum number buffers that are pre-allocated
 
29
 * to hold elogs that are reported on Sapphire and
 
30
 * powernv.
 
31
 */
 
32
#define ELOG_WRITE_MAX_RECORD           64
 
33
 
 
34
/* Platform Log ID as per the spec */
 
35
static uint32_t sapphire_elog_id = 0xB0000000;
 
36
/* Reserved for future use */
 
37
/* static uint32_t powernv_elog_id = 0xB1000000; */
 
38
 
 
39
/* Pool to allocate elog messages from */
 
40
static struct pool elog_pool;
 
41
static struct lock elog_lock = LOCK_UNLOCKED;
 
42
 
 
43
static bool elog_available = false;
 
44
 
 
45
static struct errorlog *get_write_buffer(int opal_event_severity)
 
46
{
 
47
        struct errorlog *buf;
 
48
 
 
49
        if (!elog_available)
 
50
                return NULL;
 
51
 
 
52
        lock(&elog_lock);
 
53
        if (opal_event_severity == OPAL_ERROR_PANIC)
 
54
                buf = pool_get(&elog_pool, POOL_HIGH);
 
55
        else
 
56
                buf = pool_get(&elog_pool, POOL_NORMAL);
 
57
        unlock(&elog_lock);
 
58
        return buf;
 
59
}
 
60
 
 
61
/* Reporting of error via struct errorlog */
 
62
struct errorlog *opal_elog_create(struct opal_err_info *e_info, uint32_t tag)
 
63
{
 
64
        struct errorlog *buf;
 
65
 
 
66
        buf = get_write_buffer(e_info->sev);
 
67
        if (buf) {
 
68
                buf->error_event_type = e_info->err_type;
 
69
                buf->component_id = e_info->cmp_id;
 
70
                buf->subsystem_id = e_info->subsystem;
 
71
                buf->event_severity = e_info->sev;
 
72
                buf->event_subtype = e_info->event_subtype;
 
73
                buf->reason_code = e_info->reason_code;
 
74
                buf->elog_origin = ORG_SAPPHIRE;
 
75
 
 
76
                lock(&elog_lock);
 
77
                buf->plid = ++sapphire_elog_id;
 
78
                unlock(&elog_lock);
 
79
 
 
80
                /* Initialise the first user dump section */
 
81
                log_add_section(buf, tag);
 
82
        }
 
83
 
 
84
        return buf;
 
85
}
 
86
 
 
87
/* Add a new user data section to an existing error log */
 
88
void log_add_section(struct errorlog *buf, uint32_t tag)
 
89
{
 
90
        size_t size = sizeof(struct elog_user_data_section) - 1;
 
91
        struct elog_user_data_section *tmp;
 
92
 
 
93
        if (!buf) {
 
94
                prerror("ELOG: Cannot add user data section. "
 
95
                        "Buffer is invalid\n");
 
96
                return;
 
97
        }
 
98
 
 
99
        if ((buf->user_section_size + size) > OPAL_LOG_MAX_DUMP) {
 
100
                prerror("ELOG: Size of dump data overruns buffer\n");
 
101
                return;
 
102
        }
 
103
 
 
104
        tmp = (struct elog_user_data_section *)(buf->user_data_dump +
 
105
                                                buf->user_section_size);
 
106
        /* Use DESC if no other tag provided */
 
107
        tmp->tag = tag ? tag : 0x44455343;
 
108
        tmp->size = size;
 
109
 
 
110
        buf->user_section_size += tmp->size;
 
111
        buf->user_section_count++;
 
112
}
 
113
 
 
114
void opal_elog_complete(struct errorlog *buf, bool success)
 
115
{
 
116
        if (!success)
 
117
                printf("Unable to log error\n");
 
118
 
 
119
        lock(&elog_lock);
 
120
        pool_free_object(&elog_pool, buf);
 
121
        unlock(&elog_lock);
 
122
}
 
123
 
 
124
void log_commit(struct errorlog *elog)
 
125
{
 
126
        int rc;
 
127
 
 
128
        if (!elog)
 
129
                return;
 
130
 
 
131
        if (platform.elog_commit) {
 
132
                rc = platform.elog_commit(elog);
 
133
                if (rc)
 
134
                        prerror("ELOG: Platform commit error %d\n", rc);
 
135
                return;
 
136
        }
 
137
        opal_elog_complete(elog, false);
 
138
}
 
139
 
 
140
void log_append_data(struct errorlog *buf, unsigned char *data, uint16_t size)
 
141
{
 
142
        struct elog_user_data_section *section;
 
143
        uint8_t n_sections;
 
144
        char *buffer;
 
145
 
 
146
        if (!buf) {
 
147
                prerror("ELOG: Cannot update user data. Buffer is invalid\n");
 
148
                return;
 
149
        }
 
150
 
 
151
        if ((buf->user_section_size + size) > OPAL_LOG_MAX_DUMP) {
 
152
                prerror("ELOG: Size of dump data overruns buffer\n");
 
153
                return;
 
154
        }
 
155
 
 
156
        /* Step through user sections to find latest dump section */
 
157
        buffer = buf->user_data_dump;
 
158
        n_sections = buf->user_section_count;
 
159
 
 
160
        if (!n_sections) {
 
161
                prerror("ELOG: User section invalid\n");
 
162
                return;
 
163
        }
 
164
 
 
165
        while (--n_sections) {
 
166
                section = (struct elog_user_data_section *)buffer;
 
167
                buffer += section->size;
 
168
        }
 
169
 
 
170
        section = (struct elog_user_data_section *)buffer;
 
171
        buffer += section->size;
 
172
        memcpy(buffer, data, size);
 
173
 
 
174
        section->size += size;
 
175
        buf->user_section_size += size;
 
176
}
 
177
 
 
178
void log_append_msg(struct errorlog *buf, const char *fmt, ...)
 
179
{
 
180
        char err_msg[250];
 
181
        va_list list;
 
182
 
 
183
        if (!buf) {
 
184
                prerror("Tried to append log to NULL buffer\n");
 
185
                return;
 
186
        }
 
187
 
 
188
        va_start(list, fmt);
 
189
        vsnprintf(err_msg, sizeof(err_msg), fmt, list);
 
190
        va_end(list);
 
191
 
 
192
        /* Log the error on to Sapphire console */
 
193
        prerror("%s", err_msg);
 
194
 
 
195
        log_append_data(buf, err_msg, strlen(err_msg));
 
196
}
 
197
 
 
198
void log_simple_error(struct opal_err_info *e_info, const char *fmt, ...)
 
199
{
 
200
        struct errorlog *buf;
 
201
        va_list list;
 
202
        char err_msg[250];
 
203
 
 
204
        va_start(list, fmt);
 
205
        vsnprintf(err_msg, sizeof(err_msg), fmt, list);
 
206
        va_end(list);
 
207
 
 
208
        /* Log the error on to Sapphire console */
 
209
        prerror("%s", err_msg);
 
210
 
 
211
        buf = opal_elog_create(e_info, 0);
 
212
        if (buf == NULL)
 
213
                prerror("ELOG: Error getting buffer to log error\n");
 
214
        else {
 
215
                log_append_data(buf, err_msg, strlen(err_msg));
 
216
                log_commit(buf);
 
217
        }
 
218
}
 
219
 
 
220
int elog_init(void)
 
221
{
 
222
        /* pre-allocate memory for records */
 
223
        if (pool_init(&elog_pool, sizeof(struct errorlog), ELOG_WRITE_MAX_RECORD, 1))
 
224
                return OPAL_RESOURCE;
 
225
 
 
226
        elog_available = true;
 
227
        return 0;
 
228
}