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