1 // SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
2 /*
3  * This code will enable generation and pushing of error log from Sapphire
4  * to FSP.
5  * Critical events from Sapphire that needs to be reported will be pushed
6  * on to FSP after converting the error log to Platform Error Log(PEL) format.
7  * This is termed as write action to FSP.
8  *
9  * Copyright 2013-2016 IBM Corp.
10  */
11 
12 #include <cpu.h>
13 #include <errno.h>
14 #include <fsp.h>
15 #include <fsp-elog.h>
16 #include <lock.h>
17 #include <opal-api.h>
18 #include <pel.h>
19 #include <pool.h>
20 #include <skiboot.h>
21 #include <timebase.h>
22 
23 static LIST_HEAD(elog_write_to_fsp_pending);
24 static LIST_HEAD(elog_write_to_host_pending);
25 static LIST_HEAD(elog_write_to_host_processed);
26 
27 static struct lock elog_write_lock = LOCK_UNLOCKED;
28 static struct lock elog_panic_write_lock = LOCK_UNLOCKED;
29 static struct lock elog_write_to_host_lock = LOCK_UNLOCKED;
30 
31 #define ELOG_WRITE_TO_FSP_BUFFER_SIZE	0x00004000
32 /* Log buffer to copy OPAL log for write to FSP. */
33 static void *elog_write_to_fsp_buffer;
34 
35 #define ELOG_PANIC_WRITE_BUFFER_SIZE	0x00004000
36 static void *elog_panic_write_buffer;
37 
38 #define ELOG_WRITE_TO_HOST_BUFFER_SIZE	0x00004000
39 static void *elog_write_to_host_buffer;
40 
41 static uint32_t elog_write_retries;
42 
43 /* Manipulate this only with write_lock held */
44 static uint32_t elog_plid_fsp_commit = -1;
45 static enum elog_head_state elog_write_to_host_head_state = ELOG_STATE_NONE;
46 
47 /* Need forward declaration because of circular dependency */
48 static int opal_send_elog_to_fsp(void);
49 
remove_elog_head_entry(void)50 static void remove_elog_head_entry(void)
51 {
52 	struct errorlog *head, *entry;
53 
54 	lock(&elog_write_lock);
55 	if (!list_empty(&elog_write_to_fsp_pending)) {
56 		head = list_top(&elog_write_to_fsp_pending,
57 					struct errorlog, link);
58 		if (head->plid == elog_plid_fsp_commit) {
59 			entry = list_pop(&elog_write_to_fsp_pending,
60 					struct errorlog, link);
61 			opal_elog_complete(entry,
62 					elog_write_retries < MAX_RETRIES);
63 			/* Reset the counter */
64 			elog_plid_fsp_commit = -1;
65 		}
66 	}
67 
68 	elog_write_retries = 0;
69 	unlock(&elog_write_lock);
70 }
71 
opal_fsp_write_complete(struct fsp_msg * read_msg)72 static void opal_fsp_write_complete(struct fsp_msg *read_msg)
73 {
74 	uint8_t val;
75 
76 	val = (read_msg->resp->word1 >> 8) & 0xff;
77 	fsp_freemsg(read_msg);
78 
79 	switch (val) {
80 	case FSP_STATUS_SUCCESS:
81 		remove_elog_head_entry();
82 		break;
83 	default:
84 		if (elog_write_retries++ >= MAX_RETRIES) {
85 			remove_elog_head_entry();
86 			prerror("ELOG: Error in writing to FSP (0x%x)!\n", val);
87 		}
88 
89 		break;
90 	}
91 
92 	if (opal_send_elog_to_fsp() != OPAL_SUCCESS)
93 		prerror("ELOG: Error sending elog to FSP !\n");
94 }
95 
96 /* Write PEL format hex dump of the log to FSP */
fsp_opal_elog_write(size_t opal_elog_size)97 static int64_t fsp_opal_elog_write(size_t opal_elog_size)
98 {
99 	struct fsp_msg *elog_msg;
100 
101 	elog_msg = fsp_mkmsg(FSP_CMD_CREATE_ERRLOG, 3, opal_elog_size,
102 						 0, PSI_DMA_ERRLOG_WRITE_BUF);
103 	if (!elog_msg) {
104 		prerror("ELOG: Failed to create message for WRITE to FSP\n");
105 		return OPAL_INTERNAL_ERROR;
106 	}
107 
108 	if (fsp_queue_msg(elog_msg, opal_fsp_write_complete)) {
109 		fsp_freemsg(elog_msg);
110 		elog_msg = NULL;
111 		prerror("FSP: Error queueing elog update\n");
112 		return OPAL_INTERNAL_ERROR;
113 	}
114 
115 	return OPAL_SUCCESS;
116 }
117 
118 /* This should be called with elog_write_to_host_lock lock */
fsp_elog_write_set_head_state(enum elog_head_state state)119 static inline void fsp_elog_write_set_head_state(enum elog_head_state state)
120 {
121 	elog_set_head_state(true, state);
122 	elog_write_to_host_head_state = state;
123 }
124 
opal_elog_info(__be64 * opal_elog_id,__be64 * opal_elog_size)125 bool opal_elog_info(__be64 *opal_elog_id, __be64 *opal_elog_size)
126 {
127 	struct errorlog *head;
128 	bool rc = false;
129 
130 	lock(&elog_write_to_host_lock);
131 	if (elog_write_to_host_head_state == ELOG_STATE_FETCHED_DATA) {
132 		head = list_top(&elog_write_to_host_pending,
133 					struct errorlog, link);
134 		if (!head) {
135 			/**
136 			 * @fwts-label ElogListInconsistent
137 			 * @fwts-advice Bug in interaction between FSP and
138 			 * OPAL. The state maintained by OPAL didn't match
139 			 * what the FSP sent.
140 			 */
141 			prlog(PR_ERR,
142 			      "%s: Inconsistent internal list state !\n",
143 			      __func__);
144 			fsp_elog_write_set_head_state(ELOG_STATE_NONE);
145 		} else {
146 			*opal_elog_id = cpu_to_be64(head->plid);
147 			*opal_elog_size = cpu_to_be64(head->log_size);
148 			fsp_elog_write_set_head_state(ELOG_STATE_HOST_INFO);
149 			rc = true;
150 		}
151 	}
152 
153 	unlock(&elog_write_to_host_lock);
154 	return rc;
155 }
156 
opal_commit_elog_in_host(void)157 static void opal_commit_elog_in_host(void)
158 {
159 	struct errorlog *buf;
160 
161 	lock(&elog_write_to_host_lock);
162 	if (!list_empty(&elog_write_to_host_pending) &&
163 			(elog_write_to_host_head_state == ELOG_STATE_NONE)) {
164 		buf = list_top(&elog_write_to_host_pending,
165 				struct errorlog, link);
166 		buf->log_size = create_pel_log(buf,
167 					(char *)elog_write_to_host_buffer,
168 					ELOG_WRITE_TO_HOST_BUFFER_SIZE);
169 		fsp_elog_write_set_head_state(ELOG_STATE_FETCHED_DATA);
170 	}
171 
172 	unlock(&elog_write_to_host_lock);
173 }
174 
opal_elog_read(void * buffer,uint64_t opal_elog_size,uint64_t opal_elog_id)175 bool opal_elog_read(void *buffer, uint64_t opal_elog_size,
176 		    uint64_t opal_elog_id)
177 {
178 	struct errorlog *log_data;
179 	bool rc = false;
180 
181 	lock(&elog_write_to_host_lock);
182 	if (elog_write_to_host_head_state == ELOG_STATE_HOST_INFO) {
183 		log_data = list_top(&elog_write_to_host_pending,
184 					struct errorlog, link);
185 		if (!log_data) {
186 			fsp_elog_write_set_head_state(ELOG_STATE_NONE);
187 			unlock(&elog_write_to_host_lock);
188 			return rc;
189 		}
190 
191 		if ((opal_elog_id != log_data->plid) &&
192 		    (opal_elog_size != log_data->log_size)) {
193 			unlock(&elog_write_to_host_lock);
194 			return rc;
195 		}
196 
197 		memcpy(buffer, elog_write_to_host_buffer, opal_elog_size);
198 		list_del(&log_data->link);
199 		list_add(&elog_write_to_host_processed, &log_data->link);
200 		fsp_elog_write_set_head_state(ELOG_STATE_NONE);
201 		rc = true;
202 	}
203 
204 	unlock(&elog_write_to_host_lock);
205 	opal_commit_elog_in_host();
206 	return rc;
207 }
208 
opal_elog_ack(uint64_t ack_id)209 bool opal_elog_ack(uint64_t ack_id)
210 {
211 	bool rc = false;
212 	struct errorlog *log_data;
213 	struct errorlog *record, *next_record;
214 
215 	lock(&elog_write_to_host_lock);
216 	if (!list_empty(&elog_write_to_host_processed)) {
217 		list_for_each_safe(&elog_write_to_host_processed, record,
218 						next_record, link) {
219 			if (record->plid != ack_id)
220 				continue;
221 
222 			list_del(&record->link);
223 			opal_elog_complete(record, true);
224 			rc = true;
225 		}
226 	}
227 
228 	if ((!rc) && (!list_empty(&elog_write_to_host_pending))) {
229 		log_data = list_top(&elog_write_to_host_pending,
230 						struct errorlog, link);
231 		if (ack_id == log_data->plid)
232 			fsp_elog_write_set_head_state(ELOG_STATE_NONE);
233 
234 		list_for_each_safe(&elog_write_to_host_pending, record,
235 						next_record, link) {
236 			if (record->plid != ack_id)
237 				continue;
238 
239 			list_del(&record->link);
240 			opal_elog_complete(record, true);
241 			rc = true;
242 			unlock(&elog_write_to_host_lock);
243 			opal_commit_elog_in_host();
244 			return rc;
245 		}
246 	}
247 
248 	unlock(&elog_write_to_host_lock);
249 	return rc;
250 }
251 
opal_resend_pending_logs(void)252 void opal_resend_pending_logs(void)
253 {
254 	struct errorlog *record;
255 
256 	lock(&elog_write_to_host_lock);
257 	while (!list_empty(&elog_write_to_host_processed)) {
258 		record = list_pop(&elog_write_to_host_processed,
259 					struct errorlog, link);
260 		list_add_tail(&elog_write_to_host_pending, &record->link);
261 	}
262 
263 	fsp_elog_write_set_head_state(ELOG_STATE_NONE);
264 	unlock(&elog_write_to_host_lock);
265 	opal_commit_elog_in_host();
266 }
267 
get_elog_timeout(void)268 static inline u64 get_elog_timeout(void)
269 {
270 	return (mftb() + secs_to_tb(ERRORLOG_TIMEOUT_INTERVAL));
271 }
272 
opal_send_elog_to_fsp(void)273 static int opal_send_elog_to_fsp(void)
274 {
275 	struct errorlog *head;
276 	int rc = OPAL_SUCCESS;
277 
278 	/*
279 	 * Convert entry to PEL and push it down to FSP.
280 	 * Then we wait for the ack from FSP.
281 	 */
282 	lock(&elog_write_lock);
283 	if (!list_empty(&elog_write_to_fsp_pending)) {
284 		head = list_top(&elog_write_to_fsp_pending,
285 					 struct errorlog, link);
286 		/* Error needs to be committed, update the time out value */
287 		head->elog_timeout = get_elog_timeout();
288 
289 		elog_plid_fsp_commit = head->plid;
290 		head->log_size = create_pel_log(head,
291 					(char *)elog_write_to_fsp_buffer,
292 					ELOG_WRITE_TO_FSP_BUFFER_SIZE);
293 		rc = fsp_opal_elog_write(head->log_size);
294 		unlock(&elog_write_lock);
295 		return rc;
296 	}
297 
298 	unlock(&elog_write_lock);
299 	return rc;
300 }
301 
opal_push_logs_sync_to_fsp(struct errorlog * buf)302 static int opal_push_logs_sync_to_fsp(struct errorlog *buf)
303 {
304 	struct fsp_msg *elog_msg;
305 	int opal_elog_size = 0;
306 	int rc = OPAL_SUCCESS;
307 
308 	lock(&elog_panic_write_lock);
309 
310 	/* Error needs to be committed, update the time out value */
311 	buf->elog_timeout = get_elog_timeout();
312 
313 	opal_elog_size = create_pel_log(buf,
314 					(char *)elog_panic_write_buffer,
315 					ELOG_PANIC_WRITE_BUFFER_SIZE);
316 
317 	elog_msg = fsp_mkmsg(FSP_CMD_CREATE_ERRLOG, 3, opal_elog_size,
318 					0, PSI_DMA_ELOG_PANIC_WRITE_BUF);
319 	if (!elog_msg) {
320 		prerror("ELOG: PLID: 0x%x Failed to create message for WRITE "
321 							"to FSP\n", buf->plid);
322 		unlock(&elog_panic_write_lock);
323 		opal_elog_complete(buf, false);
324 		return OPAL_INTERNAL_ERROR;
325 	}
326 
327 	if (fsp_sync_msg(elog_msg, false)) {
328 		fsp_freemsg(elog_msg);
329 		rc = OPAL_INTERNAL_ERROR;
330 	} else {
331 		rc = (elog_msg->resp->word1 >> 8) & 0xff;
332 		fsp_freemsg(elog_msg);
333 	}
334 
335 	unlock(&elog_panic_write_lock);
336 	if (rc != OPAL_SUCCESS)
337 		opal_elog_complete(buf, false);
338 	else
339 		opal_elog_complete(buf, true);
340 
341 	return rc;
342 }
343 
elog_fsp_commit(struct errorlog * buf)344 int elog_fsp_commit(struct errorlog *buf)
345 {
346 	int rc = OPAL_SUCCESS;
347 
348 	if (buf->event_severity == OPAL_ERROR_PANIC) {
349 		rc = opal_push_logs_sync_to_fsp(buf);
350 		return rc;
351 	}
352 
353 	lock(&elog_write_lock);
354 	if (list_empty(&elog_write_to_fsp_pending)) {
355 		list_add_tail(&elog_write_to_fsp_pending, &buf->link);
356 		unlock(&elog_write_lock);
357 		rc = opal_send_elog_to_fsp();
358 		return rc;
359 	}
360 
361 	list_add_tail(&elog_write_to_fsp_pending, &buf->link);
362 	unlock(&elog_write_lock);
363 	return rc;
364 }
365 
elog_append_write_to_host(struct errorlog * buf)366 static void elog_append_write_to_host(struct errorlog *buf)
367 {
368 	lock(&elog_write_to_host_lock);
369 	if (list_empty(&elog_write_to_host_pending)) {
370 		list_add(&elog_write_to_host_pending, &buf->link);
371 		unlock(&elog_write_to_host_lock);
372 		opal_commit_elog_in_host();
373 	} else {
374 		list_add_tail(&elog_write_to_host_pending, &buf->link);
375 		unlock(&elog_write_to_host_lock);
376 	}
377 }
378 
elog_timeout_poll(void * data __unused)379 static void elog_timeout_poll(void *data __unused)
380 {
381 	uint64_t now;
382 	struct errorlog *head, *entry;
383 
384 	lock(&elog_write_lock);
385 	if (list_empty(&elog_write_to_fsp_pending)) {
386 		unlock(&elog_write_lock);
387 		return;
388 	}
389 
390 	head = list_top(&elog_write_to_fsp_pending, struct errorlog, link);
391 	now = mftb();
392 	if ((tb_compare(now, head->elog_timeout) == TB_AAFTERB) ||
393 			(tb_compare(now, head->elog_timeout) == TB_AEQUALB)) {
394 		entry = list_pop(&elog_write_to_fsp_pending,
395 				struct errorlog, link);
396 		unlock(&elog_write_lock);
397 		elog_append_write_to_host(entry);
398 	} else {
399 		unlock(&elog_write_lock);
400 	}
401 }
402 
403 /* FSP elog init function */
fsp_elog_write_init(void)404 void fsp_elog_write_init(void)
405 {
406 	if (!fsp_present())
407 		return;
408 
409 	elog_panic_write_buffer = memalign(TCE_PSIZE,
410 					ELOG_PANIC_WRITE_BUFFER_SIZE);
411 	if (!elog_panic_write_buffer) {
412 		prerror("FSP: could not allocate ELOG_PANIC_WRITE_BUFFER!\n");
413 		return;
414 	}
415 
416 	elog_write_to_fsp_buffer = memalign(TCE_PSIZE,
417 					ELOG_WRITE_TO_FSP_BUFFER_SIZE);
418 	if (!elog_write_to_fsp_buffer) {
419 		prerror("FSP: could not allocate ELOG_WRITE_BUFFER!\n");
420 		return;
421 	}
422 
423 	elog_write_to_host_buffer = memalign(TCE_PSIZE,
424 					ELOG_WRITE_TO_HOST_BUFFER_SIZE);
425 	if (!elog_write_to_host_buffer) {
426 		prerror("FSP: could not allocate ELOG_WRITE_TO_HOST_BUFFER!\n");
427 		return;
428 	}
429 
430 	/* Map TCEs */
431 	fsp_tce_map(PSI_DMA_ELOG_PANIC_WRITE_BUF, elog_panic_write_buffer,
432 					PSI_DMA_ELOG_PANIC_WRITE_BUF_SZ);
433 
434 	fsp_tce_map(PSI_DMA_ERRLOG_WRITE_BUF, elog_write_to_fsp_buffer,
435 					PSI_DMA_ERRLOG_WRITE_BUF_SZ);
436 
437 	elog_init();
438 
439 	/* Add a poller */
440 	opal_add_poller(elog_timeout_poll, NULL);
441 }
442