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 
18 /*
19  * LED location code and indicator handling
20  */
21 
22 #define pr_fmt(fmt) "FSPLED: " fmt
23 #include <skiboot.h>
24 #include <fsp.h>
25 #include <device.h>
26 #include <spcn.h>
27 #include <lock.h>
28 #include <errorlog.h>
29 #include <opal.h>
30 #include <opal-msg.h>
31 #include <fsp-leds.h>
32 #include <fsp-sysparam.h>
33 
34 #define buf_write(p, type, val)  do { *(type *)(p) = val;\
35 					p += sizeof(type); } while(0)
36 #define buf_read(p, type, addr)  do { *addr = *(type *)(p);\
37 					p += sizeof(type); } while(0)
38 
39 /* SPCN replay threshold */
40 #define SPCN_REPLAY_THRESHOLD 2
41 
42 /* LED support status */
43 enum led_support_state {
44 	LED_STATE_ABSENT,
45 	LED_STATE_READING,
46 	LED_STATE_PRESENT,
47 };
48 
49 static enum led_support_state led_support = LED_STATE_ABSENT;
50 
51 /*
52  *  PSI mapped buffer for LED data
53  *
54  * Mapped once and never unmapped. Used for fetching all
55  * available LED information and creating the list. Also
56  * used for setting individual LED state.
57  *
58  */
59 static void *led_buffer;
60 static u8 *loc_code_list_buffer = NULL;
61 
62 /* Maintain list of all LEDs
63  *
64  * The contents here will be used to cater requests from FSP
65  * async commands and HV initiated OPAL calls.
66  */
67 static struct list_head  cec_ledq;		/* CEC LED list */
68 static struct list_head	 encl_ledq;	/* Enclosure LED list */
69 static struct list_head  spcn_cmdq;	/* SPCN command queue */
70 
71 /* LED lock */
72 static struct lock led_lock = LOCK_UNLOCKED;
73 static struct lock spcn_cmd_lock = LOCK_UNLOCKED;
74 static struct lock sai_lock = LOCK_UNLOCKED;
75 
76 static bool spcn_cmd_complete = true;	/* SPCN command complete */
77 
78 /* Last SPCN command */
79 static u32 last_spcn_cmd;
80 static int replay = 0;
81 
82 /*
83  * FSP controls System Attention Indicator. But it expects hypervisor
84  * keep track of the status and serve get LED state request (both from
85  * Linux and FSP itself)!
86  */
87 static struct sai_data sai_data;
88 
89 /* Forward declaration */
90 static void fsp_read_leds_data_complete(struct fsp_msg *msg);
91 static int process_led_state_change(void);
92 
93 
94 DEFINE_LOG_ENTRY(OPAL_RC_LED_SPCN, OPAL_PLATFORM_ERR_EVT, OPAL_LED,
95 		OPAL_PLATFORM_FIRMWARE, OPAL_PREDICTIVE_ERR_GENERAL,
96 		OPAL_NA);
97 
98 DEFINE_LOG_ENTRY(OPAL_RC_LED_BUFF, OPAL_PLATFORM_ERR_EVT, OPAL_LED,
99 		OPAL_PLATFORM_FIRMWARE, OPAL_PREDICTIVE_ERR_GENERAL,
100 		OPAL_NA);
101 
102 DEFINE_LOG_ENTRY(OPAL_RC_LED_LC, OPAL_PLATFORM_ERR_EVT, OPAL_LED,
103 		OPAL_PLATFORM_FIRMWARE, OPAL_INFO, OPAL_NA);
104 
105 DEFINE_LOG_ENTRY(OPAL_RC_LED_STATE, OPAL_PLATFORM_ERR_EVT, OPAL_LED,
106 		OPAL_PLATFORM_FIRMWARE, OPAL_PREDICTIVE_ERR_GENERAL,
107 		OPAL_NA);
108 
109 DEFINE_LOG_ENTRY(OPAL_RC_LED_SUPPORT, OPAL_PLATFORM_ERR_EVT, OPAL_LED,
110 		OPAL_PLATFORM_FIRMWARE, OPAL_INFO, OPAL_NA);
111 
112 
113 /* Find descendent LED record with CEC location code in CEC list */
fsp_find_cec_led(char * loc_code)114 static struct fsp_led_data *fsp_find_cec_led(char *loc_code)
115 {
116 	struct fsp_led_data *led, *next;
117 
118 	list_for_each_safe(&cec_ledq, led, next, link) {
119 		if (strcmp(led->loc_code, loc_code))
120 			continue;
121 		return led;
122 	}
123 	return NULL;
124 }
125 
126 /* Find encl LED record with ENCL location code in ENCL list */
fsp_find_encl_led(char * loc_code)127 static struct fsp_led_data *fsp_find_encl_led(char *loc_code)
128 {
129 	struct fsp_led_data *led, *next;
130 
131 	list_for_each_safe(&encl_ledq, led, next, link) {
132 		if (strcmp(led->loc_code, loc_code))
133 			continue;
134 		return led;
135 	}
136 	return NULL;
137 }
138 
139 /* Find encl LED record with CEC location code in CEC list */
fsp_find_encl_cec_led(char * loc_code)140 static struct fsp_led_data *fsp_find_encl_cec_led(char *loc_code)
141 {
142 	struct fsp_led_data *led, *next;
143 
144 	list_for_each_safe(&cec_ledq, led, next, link) {
145 		if (strstr(led->loc_code, "-"))
146 			continue;
147 		if (!strstr(loc_code, led->loc_code))
148 			continue;
149 		return led;
150 	}
151 	return NULL;
152 }
153 
154 /* Find encl LED record with CEC location code in ENCL list */
fsp_find_encl_encl_led(char * loc_code)155 static struct fsp_led_data *fsp_find_encl_encl_led(char *loc_code)
156 {
157 	struct fsp_led_data *led, *next;
158 
159 	list_for_each_safe(&encl_ledq, led, next, link) {
160 		if (!strstr(loc_code, led->loc_code))
161 			continue;
162 		return led;
163 	}
164 	return NULL;
165 }
166 
167 /* Compute the ENCL LED status in CEC list */
compute_encl_status_cec(struct fsp_led_data * encl_led)168 static void compute_encl_status_cec(struct fsp_led_data *encl_led)
169 {
170 	struct fsp_led_data *led, *next;
171 
172 	encl_led->status &= ~SPCN_LED_IDENTIFY_MASK;
173 	encl_led->status &= ~SPCN_LED_FAULT_MASK;
174 
175 	list_for_each_safe(&cec_ledq, led, next, link) {
176 		if (!strstr(led->loc_code, encl_led->loc_code))
177 			continue;
178 
179 		/* Don't count the enclsure LED itself */
180 		if (!strcmp(led->loc_code, encl_led->loc_code))
181 			continue;
182 
183 		if (led->status & SPCN_LED_IDENTIFY_MASK)
184 			encl_led->status |= SPCN_LED_IDENTIFY_MASK;
185 
186 		if (led->status & SPCN_LED_FAULT_MASK)
187 			encl_led->status |= SPCN_LED_FAULT_MASK;
188 	}
189 }
190 
191 /* Is a enclosure LED */
is_enclosure_led(char * loc_code)192 static bool is_enclosure_led(char *loc_code)
193 {
194 	if (strstr(loc_code, "-"))
195 		return false;
196 	if (!fsp_find_cec_led(loc_code) || !fsp_find_encl_led(loc_code))
197 		return false;
198 	return true;
199 }
200 
opal_led_update_complete(u64 async_token,u64 result)201 static inline void opal_led_update_complete(u64 async_token, u64 result)
202 {
203 	opal_queue_msg(OPAL_MSG_ASYNC_COMP, NULL, NULL, async_token, result);
204 }
205 
is_sai_loc_code(const char * loc_code)206 static inline bool is_sai_loc_code(const char *loc_code)
207 {
208 	if (!loc_code)
209 		return false;
210 
211 	if (!strncmp(sai_data.loc_code, loc_code, strlen(sai_data.loc_code)))
212 		return true;
213 
214 	return false;
215 }
216 
217 /* Set/Reset System attention indicator */
fsp_set_sai_complete(struct fsp_msg * msg)218 static void fsp_set_sai_complete(struct fsp_msg *msg)
219 {
220 	int ret = OPAL_SUCCESS;
221 	int rc = msg->resp->word1 & 0xff00;
222 	struct led_set_cmd *spcn_cmd = (struct led_set_cmd *)msg->user_data;
223 
224 	if (rc) {
225 		/**
226 		 * @fwts-label FSPSAIFailed
227 		 * @fwts-advice Failed to update System Attention Indicator.
228 		 * Likely means some bug with OPAL interacting with FSP.
229 		 */
230 		prlog(PR_ERR, "Update SAI cmd failed [rc=%d].\n", rc);
231 		ret = OPAL_INTERNAL_ERROR;
232 
233 		/* Roll back */
234 		lock(&sai_lock);
235 		sai_data.state = spcn_cmd->ckpt_status;
236 		unlock(&sai_lock);
237 	}
238 
239 	if (spcn_cmd->cmd_src == SPCN_SRC_OPAL)
240 		opal_led_update_complete(spcn_cmd->async_token, ret);
241 
242 	/* free msg and spcn command */
243 	free(spcn_cmd);
244 	fsp_freemsg(msg);
245 
246 	/* Process pending LED update request */
247 	process_led_state_change();
248 }
249 
fsp_set_sai(struct led_set_cmd * spcn_cmd)250 static int fsp_set_sai(struct led_set_cmd *spcn_cmd)
251 {
252 	int rc = -ENOMEM;
253 	uint32_t cmd = FSP_CMD_SA_INDICATOR;
254 	struct fsp_msg *msg;
255 
256 	/*
257 	 * FSP does not allow hypervisor to set real SAI, but we can
258 	 * reset real SAI. Also in our case only host can control
259 	 * LEDs, not guests. Hence we will set platform virtual SAI
260 	 * and reset real SAI.
261 	 */
262 	if (spcn_cmd->state == LED_STATE_ON)
263 		cmd |= FSP_LED_SET_PLAT_SAI;
264 	else
265 		cmd |= FSP_LED_RESET_REAL_SAI;
266 
267 	prlog(PR_TRACE, "Update SAI Indicator [cur : 0x%x, new : 0x%x].\n",
268 	      sai_data.state, spcn_cmd->state);
269 
270 	msg = fsp_mkmsg(cmd, 0);
271 	if (!msg) {
272 		/**
273 		 * @fwts-label SAIMallocFail
274 		 * @fwts-advice OPAL ran out of memory while trying to
275 		 * allocate an FSP message in SAI code path. This indicates
276 		 * an OPAL bug that caused OPAL to run out of memory.
277 		 */
278 		prlog(PR_ERR, "%s: Memory allocation failed.\n", __func__);
279 		goto sai_fail;
280 	}
281 
282 	spcn_cmd->ckpt_status = sai_data.state;
283 	msg->user_data = spcn_cmd;
284 	rc = fsp_queue_msg(msg, fsp_set_sai_complete);
285 	if (rc) {
286 		fsp_freemsg(msg);
287 		/**
288 		 * @fwts-label SAIQueueFail
289 		 * @fwts-advice Error in queueing message to FSP in SAI code
290 		 * path. Likely an OPAL bug.
291 		 */
292 		prlog(PR_ERR, "%s: Failed to queue the message\n", __func__);
293 		goto sai_fail;
294 	}
295 
296 	lock(&sai_lock);
297 	sai_data.state = spcn_cmd->state;
298 	unlock(&sai_lock);
299 
300 	return OPAL_SUCCESS;
301 
302 sai_fail:
303 	if (spcn_cmd->cmd_src == SPCN_SRC_OPAL)
304 		opal_led_update_complete(spcn_cmd->async_token,
305 					 OPAL_INTERNAL_ERROR);
306 
307 	return OPAL_INTERNAL_ERROR;
308 }
309 
fsp_get_sai_complete(struct fsp_msg * msg)310 static void fsp_get_sai_complete(struct fsp_msg *msg)
311 {
312 	int rc = msg->resp->word1 & 0xff00;
313 
314 	if (rc) {
315 		/**
316 		 * @fwts-label FSPSAIGetFailed
317 		 * @fwts-advice Possibly an error on FSP side, OPAL failed
318 		 * to read state from FSP.
319 		 */
320 		prlog(PR_ERR, "Read real SAI cmd failed [rc = 0x%x].\n", rc);
321 	} else { /* Update SAI state */
322 		lock(&sai_lock);
323 		sai_data.state = msg->resp->data.words[0] & 0xff;
324 		unlock(&sai_lock);
325 
326 		prlog(PR_TRACE, "SAI initial state = 0x%x\n", sai_data.state);
327 	}
328 
329 	fsp_freemsg(msg);
330 }
331 
332 /* Read initial SAI state. */
fsp_get_sai(void)333 static void fsp_get_sai(void)
334 {
335 	int rc;
336 	uint32_t cmd = FSP_CMD_SA_INDICATOR | FSP_LED_READ_REAL_SAI;
337 	struct fsp_msg *msg;
338 
339 	msg = fsp_mkmsg(cmd, 0);
340 	if (!msg) {
341 		/**
342 		 * @fwts-label FSPGetSAIMallocFail
343 		 * @fwts-advice OPAL ran out of memory: OPAL bug.
344 		 */
345 		prlog(PR_ERR, "%s: Memory allocation failed.\n", __func__);
346 		return;
347 	}
348 	rc = fsp_queue_msg(msg, fsp_get_sai_complete);
349 	if (rc) {
350 		fsp_freemsg(msg);
351 		/**
352 		 * @fwts-label FSPGetSAIQueueFail
353 		 * @fwts-advice Failed to queue message to FSP: OPAL bug
354 		 */
355 		prlog(PR_ERR, "%s: Failed to queue the message\n", __func__);
356 	}
357 }
358 
sai_update_notification(struct fsp_msg * msg)359 static bool sai_update_notification(struct fsp_msg *msg)
360 {
361 	uint32_t *state = &msg->data.words[2];
362 	uint32_t param_id = msg->data.words[0];
363 	int len = msg->data.words[1] & 0xffff;
364 
365 	if (param_id != SYS_PARAM_REAL_SAI && param_id != SYS_PARAM_PLAT_SAI)
366 		return false;
367 
368 	if ( len != 4)
369 		return false;
370 
371 	if (*state != LED_STATE_ON && *state != LED_STATE_OFF)
372 		return false;
373 
374 	/* Update SAI state */
375 	lock(&sai_lock);
376 	sai_data.state = *state;
377 	unlock(&sai_lock);
378 
379 	prlog(PR_TRACE, "SAI updated. New SAI state = 0x%x\n", *state);
380 	return true;
381 }
382 
383 
384 /*
385  * Update both the local LED lists to reflect upon led state changes
386  * occurred with the recent SPCN command. Subsequent LED requests will
387  * be served with these updates changed to the list.
388  */
update_led_list(char * loc_code,u32 led_state,u32 excl_bit)389 static void update_led_list(char *loc_code, u32 led_state, u32 excl_bit)
390 {
391 	struct fsp_led_data *led = NULL, *encl_led = NULL, *encl_cec_led = NULL;
392 	bool is_encl_led = is_enclosure_led(loc_code);
393 
394 	/* Enclosure LED in CEC list */
395 	encl_cec_led = fsp_find_encl_cec_led(loc_code);
396 	if (!encl_cec_led) {
397 		log_simple_error(&e_info(OPAL_RC_LED_LC),
398 			"Could not find enclosure LED in CEC LC=%s\n",
399 			loc_code);
400 		return;
401 	}
402 
403 	/* Update state */
404 	if (is_encl_led) {
405 		/* Enclosure exclusive bit */
406 		encl_cec_led->excl_bit = excl_bit;
407 	} else {	/* Descendant LED in CEC list */
408 		led = fsp_find_cec_led(loc_code);
409 		if (!led) {
410 			log_simple_error(&e_info(OPAL_RC_LED_LC),
411 					 "Could not find descendent LED in \
412 					 CEC LC=%s\n", loc_code);
413 			return;
414 		}
415 		led->status = led_state;
416 	}
417 
418 	/* Enclosure LED in ENCL list */
419 	encl_led = fsp_find_encl_encl_led(loc_code);
420 	if (!encl_led) {
421 		log_simple_error(&e_info(OPAL_RC_LED_LC),
422 			"Could not find enclosure LED in ENCL LC=%s\n",
423 			loc_code);
424 		return;
425 	}
426 
427 	/* Compute descendent rolled up status */
428 	compute_encl_status_cec(encl_cec_led);
429 
430 	/* Check whether exclussive bits set */
431 	if (encl_cec_led->excl_bit & FSP_LED_EXCL_FAULT)
432 		encl_cec_led->status |= SPCN_LED_FAULT_MASK;
433 
434 	if (encl_cec_led->excl_bit & FSP_LED_EXCL_IDENTIFY)
435 		encl_cec_led->status |= SPCN_LED_IDENTIFY_MASK;
436 
437 	/* Copy over */
438 	encl_led->status = encl_cec_led->status;
439 	encl_led->excl_bit = encl_cec_led->excl_bit;
440 }
441 
fsp_set_led_response(uint32_t cmd)442 static int fsp_set_led_response(uint32_t cmd)
443 {
444 	struct fsp_msg *msg;
445 	int rc = -1;
446 
447 	msg = fsp_mkmsg(cmd, 0);
448 	if (!msg) {
449 		prerror("Failed to allocate FSP_RSP_SET_LED_STATE [cmd=%x])\n",
450 			cmd);
451 	} else {
452 		rc = fsp_queue_msg(msg, fsp_freemsg);
453 		if (rc != OPAL_SUCCESS) {
454 			fsp_freemsg(msg);
455 			prerror("Failed to queue FSP_RSP_SET_LED_STATE"
456 				" [cmd=%x]\n", cmd);
457 		}
458 	}
459 	return rc;
460 }
461 
fsp_spcn_set_led_completion(struct fsp_msg * msg)462 static void fsp_spcn_set_led_completion(struct fsp_msg *msg)
463 {
464 	struct fsp_msg *resp = msg->resp;
465 	u32 cmd = FSP_RSP_SET_LED_STATE;
466 	u8 status = resp->word1 & 0xff00;
467 	struct led_set_cmd *spcn_cmd = (struct led_set_cmd *)msg->user_data;
468 
469 	lock(&led_lock);
470 
471 	/*
472 	 * LED state update request came as part of FSP async message
473 	 * FSP_CMD_SET_LED_STATE, we need to send response message.
474 	 *
475 	 * Also if SPCN command failed, then roll back changes.
476 	 */
477 	if (status != FSP_STATUS_SUCCESS) {
478 		log_simple_error(&e_info(OPAL_RC_LED_SPCN),
479 			"Last SPCN command failed, status=%02x\n",
480 			status);
481 		cmd |= FSP_STATUS_GENERIC_ERROR;
482 
483 		/* Rollback the changes */
484 		update_led_list(spcn_cmd->loc_code,
485 				spcn_cmd->ckpt_status, spcn_cmd->ckpt_excl_bit);
486 	}
487 
488 	/* FSP initiated SPCN command */
489 	if (spcn_cmd->cmd_src == SPCN_SRC_FSP)
490 		fsp_set_led_response(cmd);
491 
492 	/* OPAL initiated SPCN command */
493 	if (spcn_cmd->cmd_src == SPCN_SRC_OPAL) {
494 		if (status != FSP_STATUS_SUCCESS)
495 			opal_led_update_complete(spcn_cmd->async_token,
496 						 OPAL_INTERNAL_ERROR);
497 		else
498 			opal_led_update_complete(spcn_cmd->async_token,
499 						 OPAL_SUCCESS);
500 	}
501 
502 	unlock(&led_lock);
503 
504 	/* free msg and spcn command */
505 	free(spcn_cmd);
506 	fsp_freemsg(msg);
507 
508 	/* Process pending LED update request */
509 	process_led_state_change();
510 }
511 
512 /*
513  * Set the state of the LED pointed by the location code
514  *
515  * LED command:		FAULT state or IDENTIFY state
516  * LED state  :		OFF (reset) or ON (set)
517  *
518  * SPCN TCE mapped buffer entries for setting LED state
519  *
520  * struct spcn_led_data {
521  *	u8	lc_len;
522  *	u16	state;
523  *	char	lc_code[LOC_CODE_SIZE];
524  *};
525  */
fsp_msg_set_led_state(struct led_set_cmd * spcn_cmd)526 static int fsp_msg_set_led_state(struct led_set_cmd *spcn_cmd)
527 {
528 	struct spcn_led_data sled;
529 	struct fsp_msg *msg = NULL;
530 	struct fsp_led_data *led = NULL;
531 	void *buf = led_buffer;
532 	u16 data_len = 0;
533 	u32 cmd_hdr = 0;
534 	u32 cmd = FSP_RSP_SET_LED_STATE;
535 	int rc = -1;
536 
537 	memset(sled.lc_code, 0, LOC_CODE_SIZE);
538 	sled.lc_len = strlen(spcn_cmd->loc_code);
539 	if (sled.lc_len >= LOC_CODE_SIZE)
540 		sled.lc_len = LOC_CODE_SIZE - 1;
541 	strncpy(sled.lc_code, spcn_cmd->loc_code, LOC_CODE_SIZE - 1);
542 
543 	lock(&led_lock);
544 
545 	/* Location code length + Location code + LED control */
546 	data_len = LOC_CODE_LEN + sled.lc_len + LED_CONTROL_LEN;
547 	cmd_hdr =  SPCN_MOD_SET_LED_CTL_LOC_CODE << 24 | SPCN_CMD_SET << 16 |
548 		data_len;
549 
550 	/* Fetch the current state of LED */
551 	led = fsp_find_cec_led(spcn_cmd->loc_code);
552 
553 	/* LED not present */
554 	if (led == NULL) {
555 		if (spcn_cmd->cmd_src == SPCN_SRC_FSP) {
556 			cmd |= FSP_STATUS_INVALID_LC;
557 			fsp_set_led_response(cmd);
558 		}
559 
560 		if (spcn_cmd->cmd_src == SPCN_SRC_OPAL)
561 			opal_led_update_complete(spcn_cmd->async_token,
562 						 OPAL_INTERNAL_ERROR);
563 
564 		unlock(&led_lock);
565 		return rc;
566 	}
567 
568 	/*
569 	 * Checkpoint the status here, will use it if the SPCN
570 	 * command eventually fails.
571 	 */
572 	spcn_cmd->ckpt_status = led->status;
573 	spcn_cmd->ckpt_excl_bit = led->excl_bit;
574 	sled.state = led->status;
575 
576 	/* Update the exclussive LED bits  */
577 	if (is_enclosure_led(spcn_cmd->loc_code)) {
578 		if (spcn_cmd->command == LED_COMMAND_FAULT) {
579 			if (spcn_cmd->state == LED_STATE_ON)
580 				led->excl_bit |= FSP_LED_EXCL_FAULT;
581 			if (spcn_cmd->state == LED_STATE_OFF)
582 				led->excl_bit &= ~FSP_LED_EXCL_FAULT;
583 		}
584 
585 		if (spcn_cmd->command == LED_COMMAND_IDENTIFY) {
586 			if (spcn_cmd->state == LED_STATE_ON)
587 				led->excl_bit |= FSP_LED_EXCL_IDENTIFY;
588 			if (spcn_cmd->state == LED_STATE_OFF)
589 				led->excl_bit &= ~FSP_LED_EXCL_IDENTIFY;
590 		}
591 	}
592 
593 	/* LED FAULT commad */
594 	if (spcn_cmd->command == LED_COMMAND_FAULT) {
595 		if (spcn_cmd->state == LED_STATE_ON)
596 			sled.state |= SPCN_LED_FAULT_MASK;
597 		if (spcn_cmd->state == LED_STATE_OFF)
598 			sled.state &= ~SPCN_LED_FAULT_MASK;
599 	}
600 
601 	/* LED IDENTIFY command */
602 	if (spcn_cmd->command == LED_COMMAND_IDENTIFY) {
603 		if (spcn_cmd->state == LED_STATE_ON)
604 			sled.state |= SPCN_LED_IDENTIFY_MASK;
605 		if (spcn_cmd->state == LED_STATE_OFF)
606 			sled.state &= ~SPCN_LED_IDENTIFY_MASK;
607 	}
608 
609 	/* Write into SPCN TCE buffer */
610 	buf_write(buf, u8, sled.lc_len);	/* Location code length */
611 	memcpy(buf, sled.lc_code, sled.lc_len);	/* Location code */
612 	buf += sled.lc_len;
613 	buf_write(buf, u16, sled.state);	/* LED state */
614 
615 	msg = fsp_mkmsg(FSP_CMD_SPCN_PASSTHRU, 4,
616 			SPCN_ADDR_MODE_CEC_NODE, cmd_hdr, 0, PSI_DMA_LED_BUF);
617 	if (!msg) {
618 		cmd |= FSP_STATUS_GENERIC_ERROR;
619 		rc = -1;
620 		goto update_fail;
621 	}
622 
623 	/*
624 	 * Update the local lists based on the attempted SPCN command to
625 	 * set/reset an individual led (CEC or ENCL).
626 	 */
627 	update_led_list(spcn_cmd->loc_code, sled.state, led->excl_bit);
628 	msg->user_data = spcn_cmd;
629 
630 	rc = fsp_queue_msg(msg, fsp_spcn_set_led_completion);
631 	if (rc != OPAL_SUCCESS) {
632 		cmd |= FSP_STATUS_GENERIC_ERROR;
633 		fsp_freemsg(msg);
634 		/* Revert LED state update */
635 		update_led_list(spcn_cmd->loc_code, spcn_cmd->ckpt_status,
636 				spcn_cmd->ckpt_excl_bit);
637 	}
638 
639 update_fail:
640 	if (rc) {
641 		log_simple_error(&e_info(OPAL_RC_LED_STATE),
642 				 "Set led state failed at LC=%s\n",
643 				 spcn_cmd->loc_code);
644 
645 		if (spcn_cmd->cmd_src == SPCN_SRC_FSP)
646 			fsp_set_led_response(cmd);
647 
648 		if (spcn_cmd->cmd_src == SPCN_SRC_OPAL)
649 			opal_led_update_complete(spcn_cmd->async_token,
650 						 OPAL_INTERNAL_ERROR);
651 	}
652 
653 	unlock(&led_lock);
654 	return rc;
655 }
656 
657 /*
658  * process_led_state_change
659  *
660  * If the command queue is empty, it sets the 'spcn_cmd_complete' as true
661  * and just returns. Else it pops one element from the command queue
662  * and processes the command for the requested LED state change.
663  */
process_led_state_change(void)664 static int process_led_state_change(void)
665 {
666 	struct led_set_cmd *spcn_cmd;
667 	int rc = 0;
668 
669 	/*
670 	 * The command queue is empty. This will only
671 	 * happen during the SPCN command callback path
672 	 * in which case we set 'spcn_cmd_complete' as true.
673 	 */
674 	lock(&spcn_cmd_lock);
675 	if (list_empty(&spcn_cmdq)) {
676 		spcn_cmd_complete = true;
677 		unlock(&spcn_cmd_lock);
678 		return rc;
679 	}
680 
681 	spcn_cmd = list_pop(&spcn_cmdq, struct led_set_cmd, link);
682 	unlock(&spcn_cmd_lock);
683 
684 	if (is_sai_loc_code(spcn_cmd->loc_code))
685 		rc = fsp_set_sai(spcn_cmd);
686 	else
687 		rc = fsp_msg_set_led_state(spcn_cmd);
688 
689 	if (rc) {
690 		free(spcn_cmd);
691 		process_led_state_change();
692 	}
693 
694 	return rc;
695 }
696 
697 /*
698  * queue_led_state_change
699  *
700  * FSP async command or OPAL based request for LED state change gets queued
701  * up in the command queue. If no previous SPCN command is pending, then it
702  * immediately pops up one element from the list and processes it. If previous
703  * SPCN commands are still pending then it just queues up and return. When the
704  * SPCN command callback gets to execute, it processes one element from the
705  * list and keeps the chain execution going. At last when there are no elements
706  * in the command queue it sets 'spcn_cmd_complete' as true again.
707  */
queue_led_state_change(char * loc_code,u8 command,u8 state,int cmd_src,uint64_t async_token)708 static int queue_led_state_change(char *loc_code, u8 command,
709 				  u8 state, int cmd_src, uint64_t async_token)
710 {
711 	struct led_set_cmd *cmd;
712 	int rc = 0;
713 
714 	/* New request node */
715 	cmd = zalloc(sizeof(struct led_set_cmd));
716 	if (!cmd) {
717 		/**
718 		 * @fwts-label FSPLEDRequestMallocFail
719 		 * @fwts-advice OPAL failed to allocate memory for FSP LED
720 		 * command. Likely an OPAL bug led to out of memory.
721 		 */
722 		prlog(PR_ERR, "SPCN set command node allocation failed\n");
723 		return -1;
724 	}
725 
726 	/* Save the request */
727 	strncpy(cmd->loc_code, loc_code, LOC_CODE_SIZE - 1);
728 	cmd->command = command;
729 	cmd->state = state;
730 	cmd->cmd_src = cmd_src;
731 	cmd->async_token = async_token;
732 
733 	/* Add to the queue */
734 	lock(&spcn_cmd_lock);
735 	list_add_tail(&spcn_cmdq,  &cmd->link);
736 
737 	/* No previous SPCN command pending */
738 	if (spcn_cmd_complete) {
739 		spcn_cmd_complete = false;
740 		unlock(&spcn_cmd_lock);
741 		rc = process_led_state_change();
742 		return rc;
743 	}
744 
745 	unlock(&spcn_cmd_lock);
746 	return rc;
747 }
748 
749 /*
750  * Write single location code information into the TCE outbound buffer
751  *
752  * Data layout
753  *
754  * 2 bytes - Length of location code structure
755  * 4 bytes - CCIN in ASCII
756  * 1 byte  - Resource status flag
757  * 1 byte  - Indicator state
758  * 1 byte  - Raw loc code length
759  * 1 byte  - Loc code field size
760  * Field size byte - Null terminated ASCII string padded to 4 byte boundary
761  *
762  */
fsp_push_data_to_tce(struct fsp_led_data * led,u8 * out_data,u32 total_size)763 static u32 fsp_push_data_to_tce(struct fsp_led_data *led, u8 *out_data,
764 				u32 total_size)
765 {
766 	struct fsp_loc_code_data lcode;
767 
768 	/* CCIN value is irrelevant */
769 	lcode.ccin = 0x0;
770 
771 	lcode.status = FSP_IND_NOT_IMPLMNTD;
772 
773 	if (led->parms & SPCN_LED_IDENTIFY_MASK)
774 		lcode.status = FSP_IND_IMPLMNTD;
775 
776 	/* LED indicator status */
777 	lcode.ind_state = FSP_IND_INACTIVE;
778 	if (led->status & SPCN_LED_IDENTIFY_MASK)
779 		lcode.ind_state |= FSP_IND_IDENTIFY_ACTV;
780 	if (led->status & SPCN_LED_FAULT_MASK)
781 		lcode.ind_state |= FSP_IND_FAULT_ACTV;
782 
783 	/* Location code */
784 	memset(lcode.loc_code, 0, LOC_CODE_SIZE);
785 	lcode.raw_len = strlen(led->loc_code);
786 	strncpy(lcode.loc_code, led->loc_code, LOC_CODE_SIZE - 1);
787 	lcode.fld_sz = sizeof(lcode.loc_code);
788 
789 	/* Rest of the structure */
790 	lcode.size = sizeof(lcode);
791 	lcode.status &= 0x0f;
792 
793 	/*
794 	 * Check for outbound buffer overflow. If there are still
795 	 * more LEDs to be sent across to FSP, don't send, ignore.
796 	 */
797 	if ((total_size + lcode.size) > PSI_DMA_LOC_COD_BUF_SZ)
798 		return 0;
799 
800 	/* Copy over to the buffer */
801 	memcpy(out_data, &lcode, sizeof(lcode));
802 
803 	return lcode.size;
804 }
805 
806 /*
807  * Send out LED information structure pointed by "loc_code"
808  * to FSP through the PSI DMA mapping. Buffer layout structure
809  * must be followed.
810  */
fsp_ret_loc_code_list(u16 req_type,char * loc_code)811 static void fsp_ret_loc_code_list(u16 req_type, char *loc_code)
812 {
813 	struct fsp_led_data *led, *next;
814 	struct fsp_msg *msg;
815 
816 	u8 *data;			/* Start of TCE mapped buffer */
817 	u8 *out_data;			/* Start of location code data */
818 	u32 bytes_sent = 0, total_size = 0;
819 	u16 header_size = 0, flags = 0;
820 
821 	if (loc_code_list_buffer == NULL) {
822 		prerror("No loc_code_list_buffer\n");
823 		return;
824 	}
825 
826 	/* Init the addresses */
827 	data = loc_code_list_buffer;
828 	out_data = NULL;
829 
830 	/* Unmapping through FSP_CMD_RET_LOC_BUFFER command */
831 	fsp_tce_map(PSI_DMA_LOC_COD_BUF, (void *)data, PSI_DMA_LOC_COD_BUF_SZ);
832 	out_data = data + 8;
833 
834 	/* CEC LED list */
835 	list_for_each_safe(&cec_ledq, led, next, link) {
836 		/*
837 		 * When the request type is system wide led list
838 		 * i.e GET_LC_CMPLT_SYS, send the entire contents
839 		 * of the CEC list including both all descendents
840 		 * and all of their enclosures.
841 		 */
842 
843 		if (req_type == GET_LC_ENCLOSURES)
844 			break;
845 
846 		if (req_type == GET_LC_ENCL_DESCENDANTS) {
847 			if (strstr(led->loc_code, loc_code) == NULL)
848 				continue;
849 		}
850 
851 		if (req_type == GET_LC_SINGLE_LOC_CODE) {
852 			if (strcmp(led->loc_code, loc_code))
853 				continue;
854 		}
855 
856 		/* Push the data into TCE buffer */
857 		bytes_sent = fsp_push_data_to_tce(led, out_data, total_size);
858 
859 		/* Advance the TCE pointer */
860 		out_data += bytes_sent;
861 		total_size += bytes_sent;
862 	}
863 
864 	/* Enclosure LED list */
865 	if (req_type == GET_LC_ENCLOSURES) {
866 		list_for_each_safe(&encl_ledq, led, next, link) {
867 
868 			/* Push the data into TCE buffer */
869 			bytes_sent = fsp_push_data_to_tce(led,
870 							  out_data, total_size);
871 
872 			/* Advance the TCE pointer */
873 			out_data += bytes_sent;
874 			total_size += bytes_sent;
875 		}
876 	}
877 
878 	/* Count from 'data' instead of 'data_out' */
879 	total_size += 8;
880 	memcpy(data, &total_size, sizeof(total_size));
881 
882 	header_size = OUTBUF_HEADER_SIZE;
883 	memcpy(data + sizeof(total_size), &header_size, sizeof(header_size));
884 
885 	if (req_type == GET_LC_ENCL_DESCENDANTS)
886 		flags = 0x8000;
887 
888 	memcpy(data +  sizeof(total_size) + sizeof(header_size), &flags,
889 	       sizeof(flags));
890 	msg = fsp_mkmsg(FSP_RSP_GET_LED_LIST, 3, 0,
891 			PSI_DMA_LOC_COD_BUF, total_size);
892 	if (!msg) {
893 		prerror("Failed to allocate FSP_RSP_GET_LED_LIST.\n");
894 	} else {
895 		if (fsp_queue_msg(msg, fsp_freemsg)) {
896 			fsp_freemsg(msg);
897 			prerror("Failed to queue FSP_RSP_GET_LED_LIST\n");
898 		}
899 	}
900 }
901 
902 /*
903  * FSP async command: FSP_CMD_GET_LED_LIST
904  *
905  * (1) FSP sends the list of location codes through inbound buffer
906  * (2) HV sends the status of those location codes through outbound buffer
907  *
908  * Inbound buffer data layout (loc code request structure)
909  *
910  * 2 bytes - Length of entire structure
911  * 2 bytes - Request type
912  * 1 byte - Raw length of location code
913  * 1 byte - Location code field size
914  * `Field size` bytes - NULL terminated ASCII location code string
915  */
fsp_get_led_list(struct fsp_msg * msg)916 static void fsp_get_led_list(struct fsp_msg *msg)
917 {
918 	struct fsp_loc_code_req req;
919 	u32 tce_token = msg->data.words[1];
920 	void *buf;
921 
922 	/* Parse inbound buffer */
923 	buf = fsp_inbound_buf_from_tce(tce_token);
924 	if (!buf) {
925 		struct fsp_msg *msg;
926 		msg = fsp_mkmsg(FSP_RSP_GET_LED_LIST | FSP_STATUS_INVALID_DATA,
927 				0);
928 		if (!msg) {
929 			prerror("Failed to allocate FSP_RSP_GET_LED_LIST"
930 				" | FSP_STATUS_INVALID_DATA\n");
931 		} else {
932 			if (fsp_queue_msg(msg, fsp_freemsg)) {
933 				fsp_freemsg(msg);
934 				prerror("Failed to queue "
935 					"FSP_RSP_GET_LED_LIST |"
936 					" FSP_STATUS_INVALID_DATA\n");
937 			}
938 		}
939 		return;
940 	}
941 	memcpy(&req, buf, sizeof(req));
942 
943 	prlog(PR_TRACE, "Request for loc code list type 0x%04x LC=%s\n",
944 	       req.req_type, req.loc_code);
945 
946 	fsp_ret_loc_code_list(req.req_type, req.loc_code);
947 }
948 
949 /*
950  * FSP async command: FSP_CMD_RET_LOC_BUFFER
951  *
952  * With this command FSP returns ownership of the outbound buffer
953  * used by Sapphire to pass the indicator list previous time. That
954  * way FSP tells Sapphire that it has consumed all the data present
955  * on the outbound buffer and Sapphire can reuse it for next request.
956  */
fsp_free_led_list_buf(struct fsp_msg * msg)957 static void fsp_free_led_list_buf(struct fsp_msg *msg)
958 {
959 	u32 tce_token = msg->data.words[1];
960 	u32 cmd = FSP_RSP_RET_LED_BUFFER;
961 	struct fsp_msg *resp;
962 
963 	/* Token does not point to outbound buffer */
964 	if (tce_token != PSI_DMA_LOC_COD_BUF) {
965 		log_simple_error(&e_info(OPAL_RC_LED_BUFF),
966 			"Invalid tce token from FSP\n");
967 		cmd |=  FSP_STATUS_GENERIC_ERROR;
968 		resp = fsp_mkmsg(cmd, 0);
969 		if (!resp) {
970 			prerror("Failed to allocate FSP_RSP_RET_LED_BUFFER"
971 				"| FSP_STATUS_GENERIC_ERROR\n");
972 			return;
973 		}
974 
975 		if (fsp_queue_msg(resp, fsp_freemsg)) {
976 			fsp_freemsg(resp);
977 			prerror("Failed to queue "
978 				"RET_LED_BUFFER|ERROR\n");
979 		}
980 		return;
981 	}
982 
983 	/* Unmap the location code DMA buffer */
984 	fsp_tce_unmap(PSI_DMA_LOC_COD_BUF, PSI_DMA_LOC_COD_BUF_SZ);
985 
986 	resp = fsp_mkmsg(cmd, 0);
987 	if (!resp) {
988 		prerror("Failed to allocate FSP_RSP_RET_LED_BUFFER\n");
989 		return;
990 	}
991 	if (fsp_queue_msg(resp, fsp_freemsg)) {
992 		fsp_freemsg(resp);
993 		prerror("Failed to queue FSP_RSP_RET_LED_BUFFER\n");
994 	}
995 }
996 
fsp_ret_led_state(char * loc_code)997 static void fsp_ret_led_state(char *loc_code)
998 {
999 	bool found = false;
1000 	u8 ind_state = 0;
1001 	u32 cmd = FSP_RSP_GET_LED_STATE;
1002 	struct fsp_led_data *led, *next;
1003 	struct fsp_msg *msg;
1004 
1005 	if (is_sai_loc_code(loc_code)) {
1006 		if (sai_data.state & OPAL_SLOT_LED_STATE_ON)
1007 			ind_state = FSP_IND_FAULT_ACTV;
1008 		found = true;
1009 	} else {
1010 		list_for_each_safe(&cec_ledq, led, next, link) {
1011 			if (strcmp(loc_code, led->loc_code))
1012 				continue;
1013 
1014 			/* Found the location code */
1015 			if (led->status & SPCN_LED_IDENTIFY_MASK)
1016 				ind_state |= FSP_IND_IDENTIFY_ACTV;
1017 			if (led->status & SPCN_LED_FAULT_MASK)
1018 				ind_state |= FSP_IND_FAULT_ACTV;
1019 
1020 			found = true;
1021 			break;
1022 		}
1023 	}
1024 
1025 	/* Location code not found */
1026 	if (!found) {
1027 		log_simple_error(&e_info(OPAL_RC_LED_LC),
1028 				 "Could not find the location code LC=%s\n",
1029 				 loc_code);
1030 		cmd |= FSP_STATUS_INVALID_LC;
1031 		ind_state = 0xff;
1032 	}
1033 
1034 	msg = fsp_mkmsg(cmd, 1, ind_state);
1035 	if (!msg) {
1036 		prerror("Couldn't alloc FSP_RSP_GET_LED_STATE\n");
1037 		return;
1038 	}
1039 
1040 	if (fsp_queue_msg(msg, fsp_freemsg)) {
1041 		fsp_freemsg(msg);
1042 		prerror("Couldn't queue FSP_RSP_GET_LED_STATE\n");
1043 	}
1044 }
1045 
1046 /*
1047  * FSP async command: FSP_CMD_GET_LED_STATE
1048  *
1049  * With this command FSP query the state for any given LED
1050  */
fsp_get_led_state(struct fsp_msg * msg)1051 static void fsp_get_led_state(struct fsp_msg *msg)
1052 {
1053 	struct fsp_get_ind_state_req req;
1054 	u32 tce_token = msg->data.words[1];
1055 	void *buf;
1056 
1057 	/* Parse the inbound buffer */
1058 	buf = fsp_inbound_buf_from_tce(tce_token);
1059 	if (!buf) {
1060 		struct fsp_msg *msg;
1061 		msg = fsp_mkmsg(FSP_RSP_GET_LED_STATE |
1062 				FSP_STATUS_INVALID_DATA, 0);
1063 		if (!msg) {
1064 			prerror("Failed to allocate FSP_RSP_GET_LED_STATE"
1065 				" | FSP_STATUS_INVALID_DATA\n");
1066 			return;
1067 		}
1068 		if (fsp_queue_msg(msg, fsp_freemsg)) {
1069 			fsp_freemsg(msg);
1070 			prerror("Failed to queue FSP_RSP_GET_LED_STATE"
1071 				" | FSP_STATUS_INVALID_DATA\n");
1072 		}
1073 		return;
1074 	}
1075 	memcpy(&req, buf, sizeof(req));
1076 
1077 	prlog(PR_TRACE, "%s: tce=0x%08x buf=%p rq.sz=%d rq.lc_len=%d"
1078 	      " rq.fld_sz=%d LC: %02x %02x %02x %02x....\n", __func__,
1079 	      tce_token, buf, req.size, req.lc_len, req.fld_sz,
1080 	      req.loc_code[0], req.loc_code[1],
1081 	      req.loc_code[2], req.loc_code[3]);
1082 
1083 	/* Bound check */
1084 	if (req.lc_len >= LOC_CODE_SIZE) {
1085 		log_simple_error(&e_info(OPAL_RC_LED_LC),
1086 				 "Loc code too large in %s: %d bytes\n",
1087 				 __func__, req.lc_len);
1088 		req.lc_len = LOC_CODE_SIZE - 1;
1089 	}
1090 	/* Ensure NULL termination */
1091 	req.loc_code[req.lc_len] = 0;
1092 
1093 	/* Do the deed */
1094 	fsp_ret_led_state(req.loc_code);
1095 }
1096 
1097 /*
1098  * FSP async command: FSP_CMD_SET_LED_STATE
1099  *
1100  * With this command FSP sets/resets the state for any given LED
1101  */
fsp_set_led_state(struct fsp_msg * msg)1102 static void fsp_set_led_state(struct fsp_msg *msg)
1103 {
1104 	struct fsp_set_ind_state_req req;
1105 	struct fsp_led_data *led, *next;
1106 	u32 tce_token = msg->data.words[1];
1107 	bool command, state;
1108 	void *buf;
1109 	int rc;
1110 
1111 	/* Parse the inbound buffer */
1112 	buf = fsp_inbound_buf_from_tce(tce_token);
1113 	if (!buf) {
1114 		fsp_set_led_response(FSP_RSP_SET_LED_STATE |
1115 				     FSP_STATUS_INVALID_DATA);
1116 		return;
1117 	}
1118 	memcpy(&req, buf, sizeof(req));
1119 
1120 	prlog(PR_TRACE, "%s: tce=0x%08x buf=%p rq.sz=%d rq.typ=0x%04x"
1121 	      " rq.lc_len=%d rq.fld_sz=%d LC: %02x %02x %02x %02x....\n",
1122 	      __func__, tce_token, buf, req.size, req.lc_len, req.fld_sz,
1123 	      req.req_type,
1124 	      req.loc_code[0], req.loc_code[1],
1125 	      req.loc_code[2], req.loc_code[3]);
1126 
1127 	/* Bound check */
1128 	if (req.lc_len >= LOC_CODE_SIZE) {
1129 		log_simple_error(&e_info(OPAL_RC_LED_LC),
1130 				 "Loc code too large in %s: %d bytes\n",
1131 				 __func__, req.lc_len);
1132 		req.lc_len = LOC_CODE_SIZE - 1;
1133 	}
1134 	/* Ensure NULL termination */
1135 	req.loc_code[req.lc_len] = 0;
1136 
1137 	/* Decode command */
1138 	command =  (req.ind_state & LOGICAL_IND_STATE_MASK) ?
1139 		LED_COMMAND_FAULT : LED_COMMAND_IDENTIFY;
1140 	state = (req.ind_state & ACTIVE_LED_STATE_MASK) ?
1141 		LED_STATE_ON : LED_STATE_OFF;
1142 
1143 	/* Handle requests */
1144 	switch (req.req_type) {
1145 	case SET_IND_ENCLOSURE:
1146 		list_for_each_safe(&cec_ledq, led, next, link) {
1147 			/* Only descendants of the same enclosure */
1148 			if (!strstr(led->loc_code, req.loc_code))
1149 				continue;
1150 
1151 			/* Skip the enclosure */
1152 			if (!strcmp(led->loc_code, req.loc_code))
1153 				continue;
1154 
1155 			rc = queue_led_state_change(led->loc_code, command,
1156 						    state, SPCN_SRC_FSP, 0);
1157 			if (rc != 0)
1158 				fsp_set_led_response(FSP_RSP_SET_LED_STATE |
1159 						     FSP_STATUS_GENERIC_ERROR);
1160 		}
1161 		break;
1162 	case SET_IND_SINGLE_LOC_CODE:
1163 		/* Set led state for single descendent led */
1164 		rc = queue_led_state_change(req.loc_code,
1165 					    command, state, SPCN_SRC_FSP, 0);
1166 		if (rc != 0)
1167 			fsp_set_led_response(FSP_RSP_SET_LED_STATE |
1168 					     FSP_STATUS_GENERIC_ERROR);
1169 		break;
1170 	default:
1171 		fsp_set_led_response(FSP_RSP_SET_LED_STATE |
1172 				     FSP_STATUS_NOT_SUPPORTED);
1173 		break;
1174 	}
1175 }
1176 
1177 /* Handle received indicator message from FSP */
fsp_indicator_message(u32 cmd_sub_mod,struct fsp_msg * msg)1178 static bool fsp_indicator_message(u32 cmd_sub_mod, struct fsp_msg *msg)
1179 {
1180 	u32 cmd;
1181 	struct fsp_msg *resp;
1182 
1183 	/* LED support not available yet */
1184 	if (led_support != LED_STATE_PRESENT) {
1185 		log_simple_error(&e_info(OPAL_RC_LED_SUPPORT),
1186 			"Indicator message while LED support not"
1187 			" available yet\n");
1188 		return false;
1189 	}
1190 
1191 	switch (cmd_sub_mod) {
1192 	case FSP_CMD_GET_LED_LIST:
1193 		prlog(PR_TRACE, "FSP_CMD_GET_LED_LIST command received\n");
1194 		fsp_get_led_list(msg);
1195 		return true;
1196 	case FSP_CMD_RET_LED_BUFFER:
1197 		prlog(PR_TRACE, "FSP_CMD_RET_LED_BUFFER command received\n");
1198 		fsp_free_led_list_buf(msg);
1199 		return true;
1200 	case FSP_CMD_GET_LED_STATE:
1201 		prlog(PR_TRACE, "FSP_CMD_GET_LED_STATE command received\n");
1202 		fsp_get_led_state(msg);
1203 		return true;
1204 	case FSP_CMD_SET_LED_STATE:
1205 		prlog(PR_TRACE, "FSP_CMD_SET_LED_STATE command received\n");
1206 		fsp_set_led_state(msg);
1207 		return true;
1208 	/*
1209 	 * FSP async sub commands which have not been implemented.
1210 	 * For these async sub commands, print for the log and ack
1211 	 * the field service processor with a generic error.
1212 	 */
1213 	case FSP_CMD_GET_MTMS_LIST:
1214 		prlog(PR_TRACE, "FSP_CMD_GET_MTMS_LIST command received\n");
1215 		cmd = FSP_RSP_GET_MTMS_LIST;
1216 		break;
1217 	case FSP_CMD_RET_MTMS_BUFFER:
1218 		prlog(PR_TRACE, "FSP_CMD_RET_MTMS_BUFFER command received\n");
1219 		cmd = FSP_RSP_RET_MTMS_BUFFER;
1220 		break;
1221 	case FSP_CMD_SET_ENCL_MTMS:
1222 		prlog(PR_TRACE, "FSP_CMD_SET_MTMS command received\n");
1223 		cmd = FSP_RSP_SET_ENCL_MTMS;
1224 		break;
1225 	case FSP_CMD_CLR_INCT_ENCL:
1226 		prlog(PR_TRACE, "FSP_CMD_CLR_INCT_ENCL command received\n");
1227 		cmd = FSP_RSP_CLR_INCT_ENCL;
1228 		break;
1229 	case FSP_CMD_ENCL_MCODE_INIT:
1230 		prlog(PR_TRACE, "FSP_CMD_ENCL_MCODE_INIT command received\n");
1231 		cmd = FSP_RSP_ENCL_MCODE_INIT;
1232 		break;
1233 	case FSP_CMD_ENCL_MCODE_INTR:
1234 		prlog(PR_TRACE, "FSP_CMD_ENCL_MCODE_INTR command received\n");
1235 		cmd = FSP_RSP_ENCL_MCODE_INTR;
1236 		break;
1237 	case FSP_CMD_ENCL_POWR_TRACE:
1238 		prlog(PR_TRACE, "FSP_CMD_ENCL_POWR_TRACE command received\n");
1239 		cmd = FSP_RSP_ENCL_POWR_TRACE;
1240 		break;
1241 	case FSP_CMD_RET_ENCL_TRACE_BUFFER:
1242 		prlog(PR_TRACE, "FSP_CMD_RET_ENCL_TRACE_BUFFER command received\n");
1243 		cmd = FSP_RSP_RET_ENCL_TRACE_BUFFER;
1244 		break;
1245 	case FSP_CMD_GET_SPCN_LOOP_STATUS:
1246 		prlog(PR_TRACE, "FSP_CMD_GET_SPCN_LOOP_STATUS command received\n");
1247 		cmd = FSP_RSP_GET_SPCN_LOOP_STATUS;
1248 		break;
1249 	case FSP_CMD_INITIATE_LAMP_TEST:
1250 		/* XXX: FSP ACK not required for this sub command */
1251 		prlog(PR_TRACE, "FSP_CMD_INITIATE_LAMP_TEST command received\n");
1252 		return true;
1253 	default:
1254 		return false;
1255 	}
1256 	cmd |= FSP_STATUS_GENERIC_ERROR;
1257 	resp = fsp_mkmsg(cmd, 0);
1258 	if (!resp) {
1259 		prerror("Failed to allocate FSP_STATUS_GENERIC_ERROR\n");
1260 		return false;
1261 	}
1262 	if (fsp_queue_msg(resp, fsp_freemsg)) {
1263 		fsp_freemsg(resp);
1264 		prerror("Failed to queue FSP_STATUS_GENERIC_ERROR\n");
1265 		return false;
1266 	}
1267 	return true;
1268 }
1269 
1270 /* Indicator class client */
1271 static struct fsp_client fsp_indicator_client = {
1272 	.message = fsp_indicator_message,
1273 };
1274 
1275 
fsp_opal_get_sai(u64 * led_mask,u64 * led_value)1276 static int fsp_opal_get_sai(u64 *led_mask, u64 *led_value)
1277 {
1278 	*led_mask |= OPAL_SLOT_LED_STATE_ON << OPAL_SLOT_LED_TYPE_ATTN;
1279 	if (sai_data.state & OPAL_SLOT_LED_STATE_ON)
1280 		*led_value |=
1281 			OPAL_SLOT_LED_STATE_ON << OPAL_SLOT_LED_TYPE_ATTN;
1282 
1283 	return OPAL_SUCCESS;
1284 }
1285 
fsp_opal_set_sai(uint64_t async_token,char * loc_code,const u64 led_mask,const u64 led_value)1286 static int fsp_opal_set_sai(uint64_t async_token, char *loc_code,
1287 			    const u64 led_mask, const u64 led_value)
1288 {
1289 	int state = LED_STATE_OFF;
1290 
1291 	if (!((led_mask >> OPAL_SLOT_LED_TYPE_ATTN) & OPAL_SLOT_LED_STATE_ON))
1292 		return OPAL_PARAMETER;
1293 
1294 	if ((led_value >> OPAL_SLOT_LED_TYPE_ATTN) & OPAL_SLOT_LED_STATE_ON)
1295 		state = LED_STATE_ON;
1296 
1297 	return queue_led_state_change(loc_code, 0,
1298 				      state, SPCN_SRC_OPAL, async_token);
1299 }
1300 
1301 /*
1302  * fsp_opal_leds_get_ind (OPAL_LEDS_GET_INDICATOR)
1303  *
1304  * Argument	 Description				Updated By
1305  * --------	 -----------				----------
1306  * loc_code	 Location code of the LEDs		(Host)
1307  * led_mask	 LED types whose status is available	(OPAL)
1308  * led_value	 Status of the available LED types	(OPAL)
1309  * max_led_type  Maximum number of supported LED types	(Host/OPAL)
1310  *
1311  * The host will pass the location code of the LED types (loc_code) and
1312  * maximum number of LED types it understands (max_led_type). OPAL will
1313  * update the 'led_mask' with set bits pointing to LED types whose status
1314  * is available and updates the 'led_value' with actual status. OPAL checks
1315  * the 'max_led_type' to understand whether the host is newer or older
1316  * compared to itself. In the case where the OPAL is newer compared
1317  * to host (OPAL's max_led_type > host's max_led_type), it will update
1318  * led_mask and led_value according to max_led_type requested by the host.
1319  * When the host is newer compared to the OPAL (host's max_led_type >
1320  * OPAL's max_led_type), OPAL updates 'max_led_type' to the maximum
1321  * number of LED type it understands and updates 'led_mask', 'led_value'
1322  * based on that maximum value of LED types.
1323  */
fsp_opal_leds_get_ind(char * loc_code,u64 * led_mask,u64 * led_value,u64 * max_led_type)1324 static int64_t fsp_opal_leds_get_ind(char *loc_code, u64 *led_mask,
1325 				     u64 *led_value, u64 *max_led_type)
1326 {
1327 	bool supported = true;
1328 	int64_t max;
1329 	int rc;
1330 	struct fsp_led_data *led;
1331 
1332 	/* FSP not present */
1333 	if (!fsp_present())
1334 		return OPAL_HARDWARE;
1335 
1336 	/* LED support not available */
1337 	if (led_support != LED_STATE_PRESENT)
1338 		return OPAL_HARDWARE;
1339 
1340 	/* Adjust max LED type */
1341 	if (*max_led_type > OPAL_SLOT_LED_TYPE_MAX) {
1342 		supported = false;
1343 		*max_led_type = OPAL_SLOT_LED_TYPE_MAX;
1344 	}
1345 
1346 	/* Invalid parameter */
1347 	max = *max_led_type;
1348 	if (max <= 0)
1349 		return OPAL_PARAMETER;
1350 
1351 	/* Get System attention indicator state */
1352 	if (is_sai_loc_code(loc_code)) {
1353 		rc = fsp_opal_get_sai(led_mask, led_value);
1354 		return rc;
1355 	}
1356 
1357 	/* LED not found */
1358 	led = fsp_find_cec_led(loc_code);
1359 	if (!led)
1360 		return OPAL_PARAMETER;
1361 
1362 	*led_mask = 0;
1363 	*led_value = 0;
1364 
1365 	/* Identify LED */
1366 	--max;
1367 	*led_mask |= OPAL_SLOT_LED_STATE_ON << OPAL_SLOT_LED_TYPE_ID;
1368 	if (led->status & SPCN_LED_IDENTIFY_MASK)
1369 		*led_value |=
1370 			OPAL_SLOT_LED_STATE_ON << OPAL_SLOT_LED_TYPE_ID;
1371 
1372 	/* Fault LED */
1373 	if (!max)
1374 		return OPAL_SUCCESS;
1375 
1376 	--max;
1377 	*led_mask |= OPAL_SLOT_LED_STATE_ON << OPAL_SLOT_LED_TYPE_FAULT;
1378 	if (led->status & SPCN_LED_FAULT_MASK)
1379 		*led_value |=
1380 			OPAL_SLOT_LED_STATE_ON << OPAL_SLOT_LED_TYPE_FAULT;
1381 
1382 	/* OPAL doesn't support all the LED type requested by payload */
1383 	if (!supported)
1384 		return OPAL_PARTIAL;
1385 
1386 	return OPAL_SUCCESS;
1387 }
1388 
1389 /*
1390  * fsp_opal_leds_set_ind (OPAL_LEDS_SET_INDICATOR)
1391  *
1392  * Argument	 Description				Updated By
1393  * --------	 -----------				----------
1394  * loc_code	 Location code of the LEDs		(Host)
1395  * led_mask	 LED types whose status will be updated	(Host)
1396  * led_value	 Requested status of various LED types	(Host)
1397  * max_led_type  Maximum number of supported LED types	(Host/OPAL)
1398  *
1399  * The host will pass the location code of the LED types, mask, value
1400  * and maximum number of LED types it understands. OPAL will update
1401  * LED status for all the LED types mentioned in the mask with their
1402  * value mentioned. OPAL checks the 'max_led_type' to understand
1403  * whether the host is newer or older compared to itself. In case where
1404  * the OPAL is newer compared to the host (OPAL's max_led_type >
1405  * host's max_led_type), it updates LED status based on max_led_type
1406  * requested from the host. When the host is newer compared to the OPAL
1407  * (host's max_led_type > OPAL's max_led_type), OPAL updates
1408  * 'max_led_type' to the maximum number of LED type it understands and
1409  * then it updates LED status based on that updated  maximum value of LED
1410  * types. Host needs to check the returned updated value of max_led_type
1411  * to figure out which part of it's request got served and which ones got
1412  * ignored.
1413  */
fsp_opal_leds_set_ind(uint64_t async_token,char * loc_code,const u64 led_mask,const u64 led_value,u64 * max_led_type)1414 static int64_t fsp_opal_leds_set_ind(uint64_t async_token,
1415 				     char *loc_code, const u64 led_mask,
1416 				     const u64 led_value, u64 *max_led_type)
1417 {
1418 	bool supported = true;
1419 	int command, state, rc = OPAL_SUCCESS;
1420 	int64_t max;
1421 	struct fsp_led_data *led;
1422 
1423 	/* FSP not present */
1424 	if (!fsp_present())
1425 		return OPAL_HARDWARE;
1426 
1427 	/* LED support not available */
1428 	if (led_support != LED_STATE_PRESENT)
1429 		return OPAL_HARDWARE;
1430 
1431 	/* Adjust max LED type */
1432 	if (*max_led_type > OPAL_SLOT_LED_TYPE_MAX) {
1433 		supported = false;
1434 		*max_led_type = OPAL_SLOT_LED_TYPE_MAX;
1435 	}
1436 
1437 	max = *max_led_type;
1438 	/* Invalid parameter */
1439 	if (max <= 0)
1440 		return OPAL_PARAMETER;
1441 
1442 	/* Set System attention indicator state */
1443 	if (is_sai_loc_code(loc_code)) {
1444 		supported = true;
1445 		rc = fsp_opal_set_sai(async_token,
1446 				      loc_code, led_mask, led_value);
1447 		goto success;
1448 	}
1449 
1450 	/* LED not found */
1451 	led = fsp_find_cec_led(loc_code);
1452 	if (!led)
1453 		return OPAL_PARAMETER;
1454 
1455 	/* Indentify LED mask */
1456 	--max;
1457 
1458 	if ((led_mask >> OPAL_SLOT_LED_TYPE_ID) & OPAL_SLOT_LED_STATE_ON) {
1459 		supported = true;
1460 
1461 		command = LED_COMMAND_IDENTIFY;
1462 		state = LED_STATE_OFF;
1463 		if ((led_value >> OPAL_SLOT_LED_TYPE_ID)
1464 					& OPAL_SLOT_LED_STATE_ON)
1465 			state = LED_STATE_ON;
1466 
1467 		rc = queue_led_state_change(loc_code, command,
1468 					    state, SPCN_SRC_OPAL, async_token);
1469 	}
1470 
1471 	if (!max)
1472 		goto success;
1473 
1474 	/* Fault LED mask */
1475 	--max;
1476 	if ((led_mask >> OPAL_SLOT_LED_TYPE_FAULT) & OPAL_SLOT_LED_STATE_ON) {
1477 		supported = true;
1478 
1479 		command = LED_COMMAND_FAULT;
1480 		state = LED_STATE_OFF;
1481 		if ((led_value >> OPAL_SLOT_LED_TYPE_FAULT)
1482 					& OPAL_SLOT_LED_STATE_ON)
1483 			state = LED_STATE_ON;
1484 
1485 		rc = queue_led_state_change(loc_code, command,
1486 					    state, SPCN_SRC_OPAL, async_token);
1487 	}
1488 
1489 success:
1490 	/* Unsupported LED type */
1491 	if (!supported)
1492 		return OPAL_UNSUPPORTED;
1493 
1494 	if (rc == OPAL_SUCCESS)
1495 		rc = OPAL_ASYNC_COMPLETION;
1496 	else
1497 		rc = OPAL_INTERNAL_ERROR;
1498 
1499 	return rc;
1500 }
1501 
1502 /* Get LED node from device tree */
dt_get_led_node(void)1503 static struct dt_node *dt_get_led_node(void)
1504 {
1505 	struct dt_node *pled;
1506 
1507 	if (!opal_node) {
1508 		prlog(PR_WARNING, "OPAL parent device node not available\n");
1509 		return NULL;
1510 	}
1511 
1512 	pled = dt_find_by_path(opal_node, DT_PROPERTY_LED_NODE);
1513 	if (!pled)
1514 		prlog(PR_WARNING, "Parent device node not available\n");
1515 
1516 	return pled;
1517 }
1518 
1519 /* Get System attention indicator location code from device tree */
dt_get_sai_loc_code(void)1520 static void dt_get_sai_loc_code(void)
1521 {
1522 	struct dt_node *pled, *child;
1523 	const char *led_type = NULL;
1524 
1525 	memset(sai_data.loc_code, 0, LOC_CODE_SIZE);
1526 
1527 	pled = dt_get_led_node();
1528 	if (!pled)
1529 		return;
1530 
1531 	list_for_each(&pled->children, child, list) {
1532 		led_type = dt_prop_get(child, DT_PROPERTY_LED_TYPES);
1533 		if (!led_type)
1534 			continue;
1535 
1536 		if (strcmp(led_type, LED_TYPE_ATTENTION))
1537 			continue;
1538 
1539 		memcpy(sai_data.loc_code, child->name, LOC_CODE_SIZE - 1);
1540 
1541 		prlog(PR_TRACE, "SAI Location code = %s\n", sai_data.loc_code);
1542 		return;
1543 	}
1544 }
1545 
1546 /*
1547  * create_led_device_node
1548  *
1549  * Creates the system parent LED device node and all individual
1550  * child LED device nodes under it. This is called right before
1551  * starting the payload (Linux) to ensure that the SPCN command
1552  * sequence to fetch the LED location code list has been finished
1553  * and to have a better chance of creating the deviced nodes.
1554  */
create_led_device_nodes(void)1555 void create_led_device_nodes(void)
1556 {
1557 	const char *led_mode = NULL;
1558 	struct fsp_led_data *led, *next;
1559 	struct dt_node *pled, *cled;
1560 
1561 	if (!fsp_present())
1562 		return;
1563 
1564 	/* Make sure LED list read is completed */
1565 	while (led_support == LED_STATE_READING)
1566 		opal_run_pollers();
1567 
1568 	if (led_support == LED_STATE_ABSENT) {
1569 		prlog(PR_WARNING, "LED support not available, \
1570 		      hence device tree nodes will not be created\n");
1571 		return;
1572 	}
1573 
1574 	/* Get LED node */
1575 	pled = dt_get_led_node();
1576 	if (!pled)
1577 		return;
1578 
1579 	/* Check if already populated (fast-reboot) */
1580 	if (dt_has_node_property(pled, "compatible", NULL))
1581 		return;
1582 	dt_add_property_strings(pled, "compatible", DT_PROPERTY_LED_COMPATIBLE);
1583 
1584 	led_mode = dt_prop_get(pled, DT_PROPERTY_LED_MODE);
1585 	if (!led_mode) {
1586 		prlog(PR_WARNING, "Unknown LED operating mode\n");
1587 		return;
1588 	}
1589 
1590 	/* LED child nodes */
1591 	list_for_each_safe(&cec_ledq, led, next, link) {
1592 		/* Duplicate LED location code */
1593 		if (dt_find_by_path(pled, led->loc_code)) {
1594 			prlog(PR_WARNING, "duplicate location code %s\n",
1595 			      led->loc_code);
1596 			continue;
1597 		}
1598 
1599 		cled = dt_new(pled, led->loc_code);
1600 		if (!cled) {
1601 			prlog(PR_WARNING, "Child device node creation "
1602 			      "failed\n");
1603 			continue;
1604 		}
1605 
1606 		if (!strcmp(led_mode, LED_MODE_LIGHT_PATH))
1607 			dt_add_property_strings(cled, DT_PROPERTY_LED_TYPES,
1608 						LED_TYPE_IDENTIFY,
1609 						LED_TYPE_FAULT);
1610 		else
1611 			dt_add_property_strings(cled, DT_PROPERTY_LED_TYPES,
1612 						LED_TYPE_IDENTIFY);
1613 	}
1614 }
1615 
1616 /*
1617  * Process the received LED data from SPCN
1618  *
1619  * Every LED state data is added into the CEC list. If the location
1620  * code is a enclosure type, its added into the enclosure list as well.
1621  *
1622  */
fsp_process_leds_data(u16 len)1623 static void fsp_process_leds_data(u16 len)
1624 {
1625 	struct fsp_led_data *led_data = NULL;
1626 	void *buf = NULL;
1627 
1628 	/*
1629 	 * Process the entire captured data from the last command
1630 	 *
1631 	 * TCE mapped 'led_buffer' contains the fsp_led_data structure
1632 	 * one after the other till the total length 'len'.
1633 	 *
1634 	 */
1635 	buf = led_buffer;
1636 	while (len) {
1637 		size_t lc_len;
1638 
1639 		/* Prepare */
1640 		led_data = zalloc(sizeof(struct fsp_led_data));
1641 		assert(led_data);
1642 
1643 		/* Resource ID */
1644 		buf_read(buf, u16, &led_data->rid);
1645 		len -= sizeof(led_data->rid);
1646 
1647 		/* Location code length */
1648 		buf_read(buf, u8, &led_data->lc_len);
1649 		len -= sizeof(led_data->lc_len);
1650 
1651 		lc_len = led_data->lc_len;
1652 		if (lc_len == 0) {
1653 			free(led_data);
1654 			break;
1655 		}
1656 
1657 		if (lc_len >= LOC_CODE_SIZE)
1658 			lc_len = LOC_CODE_SIZE - 1;
1659 
1660 		/* Location code */
1661 		strncpy(led_data->loc_code, buf, lc_len);
1662 		led_data->loc_code[lc_len] = '\0';
1663 
1664 		buf += led_data->lc_len;
1665 		len -= led_data->lc_len;
1666 
1667 		/* Parameters */
1668 		buf_read(buf, u16, &led_data->parms);
1669 		len -=  sizeof(led_data->parms);
1670 
1671 		/* Status */
1672 		buf_read(buf, u16, &led_data->status);
1673 		len -=  sizeof(led_data->status);
1674 
1675 		/*
1676 		 * This is Enclosure LED's location code, need to go
1677 		 * inside the enclosure LED list as well.
1678 		 */
1679 		if (!strstr(led_data->loc_code, "-")) {
1680 			struct fsp_led_data *encl_led_data = NULL;
1681 			encl_led_data = zalloc(sizeof(struct fsp_led_data));
1682 			assert(encl_led_data);
1683 
1684 			/* copy over the original */
1685 			memcpy(encl_led_data, led_data, sizeof(struct fsp_led_data));
1686 
1687 			/* Add to the list of enclosure LEDs */
1688 			list_add_tail(&encl_ledq, &encl_led_data->link);
1689 		}
1690 
1691 		/* Push this onto the list */
1692 		list_add_tail(&cec_ledq, &led_data->link);
1693 	}
1694 }
1695 
1696 /* Replay the SPCN command */
replay_spcn_cmd(u32 last_spcn_cmd)1697 static void replay_spcn_cmd(u32 last_spcn_cmd)
1698 {
1699 	u32 cmd_hdr = 0;
1700 	int rc = -1;
1701 
1702 	/* Reached threshold */
1703 	if (replay == SPCN_REPLAY_THRESHOLD) {
1704 		replay = 0;
1705 		led_support = LED_STATE_ABSENT;
1706 		return;
1707 	}
1708 
1709 	replay++;
1710 	if (last_spcn_cmd == SPCN_MOD_PRS_LED_DATA_FIRST) {
1711 		cmd_hdr = SPCN_MOD_PRS_LED_DATA_FIRST << 24 |
1712 			SPCN_CMD_PRS << 16;
1713 		rc = fsp_queue_msg(fsp_mkmsg(FSP_CMD_SPCN_PASSTHRU, 4,
1714 					     SPCN_ADDR_MODE_CEC_NODE,
1715 					     cmd_hdr, 0,
1716 					     PSI_DMA_LED_BUF),
1717 				   fsp_read_leds_data_complete);
1718 		if (rc)
1719 			prlog(PR_ERR, "Replay SPCN_MOD_PRS_LED_DATA_FIRST"
1720 			      " command could not be queued\n");
1721 	}
1722 
1723 	if (last_spcn_cmd == SPCN_MOD_PRS_LED_DATA_SUB) {
1724 		cmd_hdr = SPCN_MOD_PRS_LED_DATA_SUB << 24 | SPCN_CMD_PRS << 16;
1725 		rc = fsp_queue_msg(fsp_mkmsg(FSP_CMD_SPCN_PASSTHRU, 4,
1726 					     SPCN_ADDR_MODE_CEC_NODE, cmd_hdr,
1727 					     0, PSI_DMA_LED_BUF),
1728 				   fsp_read_leds_data_complete);
1729 		if (rc)
1730 			prlog(PR_ERR, "Replay SPCN_MOD_PRS_LED_DATA_SUB"
1731 			      " command could not be queued\n");
1732 	}
1733 
1734 	/* Failed to queue MBOX message */
1735 	if (rc)
1736 		led_support = LED_STATE_ABSENT;
1737 }
1738 
1739 /*
1740  * FSP message response handler for following SPCN LED commands
1741  * which are used to fetch all of the LED data from SPCN
1742  *
1743  * 1. SPCN_MOD_PRS_LED_DATA_FIRST      --> First 1KB of LED data
1744  * 2. SPCN_MOD_PRS_LED_DATA_SUB        --> Subsequent 1KB of LED data
1745  *
1746  * Once the SPCN_RSP_STATUS_SUCCESS response code has been received
1747  * indicating the last batch of 1KB LED data is here, the list addition
1748  * process is now complete and we enable LED support for FSP async commands
1749  * and for OPAL interface.
1750  */
fsp_read_leds_data_complete(struct fsp_msg * msg)1751 static void fsp_read_leds_data_complete(struct fsp_msg *msg)
1752 {
1753 	struct fsp_led_data *led, *next;
1754 	struct fsp_msg *resp = msg->resp;
1755 	u32 cmd_hdr = 0;
1756 	int rc = 0;
1757 
1758 	u32 msg_status = resp->word1 & 0xff00;
1759 	u32 led_status = (resp->data.words[1] >> 24) & 0xff;
1760 	u16 data_len = (u16)(resp->data.words[1] & 0xffff);
1761 
1762 	if (msg_status != FSP_STATUS_SUCCESS) {
1763 		log_simple_error(&e_info(OPAL_RC_LED_SUPPORT),
1764 				 "FSP returned error %x LED not supported\n",
1765 				 msg_status);
1766 		/* LED support not available */
1767 		led_support = LED_STATE_ABSENT;
1768 
1769 		fsp_freemsg(msg);
1770 		return;
1771 	}
1772 
1773 	/* SPCN command status */
1774 	switch (led_status) {
1775 	/* Last 1KB of LED data */
1776 	case SPCN_RSP_STATUS_SUCCESS:
1777 		prlog(PR_DEBUG, "SPCN_RSP_STATUS_SUCCESS: %d bytes received\n",
1778 		      data_len);
1779 
1780 		led_support = LED_STATE_PRESENT;
1781 
1782 		/* Copy data to the local list */
1783 		fsp_process_leds_data(data_len);
1784 
1785 		/* LEDs captured on the system */
1786 		prlog(PR_DEBUG, "CEC LEDs captured on the system:\n");
1787 		list_for_each_safe(&cec_ledq, led, next, link) {
1788 			prlog(PR_DEBUG,
1789 			       "rid: %x\t"
1790 			       "len: %x      "
1791 			       "lcode: %-30s\t"
1792 			       "parms: %04x\t"
1793 			       "status: %04x\n",
1794 			       led->rid,
1795 			       led->lc_len,
1796 			       led->loc_code,
1797 			       led->parms,
1798 			       led->status);
1799 		}
1800 
1801 		prlog(PR_DEBUG, "ENCL LEDs captured on the system:\n");
1802 		list_for_each_safe(&encl_ledq, led, next, link) {
1803 			prlog(PR_DEBUG,
1804 			       "rid: %x\t"
1805 			       "len: %x      "
1806 			       "lcode: %-30s\t"
1807 			       "parms: %04x\t"
1808 			       "status: %04x\n",
1809 			       led->rid,
1810 			       led->lc_len,
1811 			       led->loc_code,
1812 			       led->parms,
1813 			       led->status);
1814 		}
1815 
1816 		break;
1817 
1818 	/* If more 1KB of LED data present */
1819 	case SPCN_RSP_STATUS_COND_SUCCESS:
1820 		prlog(PR_DEBUG, "SPCN_RSP_STATUS_COND_SUCCESS: %d bytes "
1821 		      " received\n", data_len);
1822 
1823 		/* Copy data to the local list */
1824 		fsp_process_leds_data(data_len);
1825 
1826 		/* Fetch the remaining data from SPCN */
1827 		last_spcn_cmd = SPCN_MOD_PRS_LED_DATA_SUB;
1828 		cmd_hdr = SPCN_MOD_PRS_LED_DATA_SUB << 24 | SPCN_CMD_PRS << 16;
1829 		rc = fsp_queue_msg(fsp_mkmsg(FSP_CMD_SPCN_PASSTHRU, 4,
1830 					     SPCN_ADDR_MODE_CEC_NODE,
1831 					     cmd_hdr, 0, PSI_DMA_LED_BUF),
1832 				   fsp_read_leds_data_complete);
1833 		if (rc) {
1834 			prlog(PR_ERR, "SPCN_MOD_PRS_LED_DATA_SUB command"
1835 			      " could not be queued\n");
1836 
1837 			led_support = LED_STATE_ABSENT;
1838 		}
1839 		break;
1840 
1841 	/* Other expected error codes*/
1842 	case SPCN_RSP_STATUS_INVALID_RACK:
1843 	case SPCN_RSP_STATUS_INVALID_SLAVE:
1844 	case SPCN_RSP_STATUS_INVALID_MOD:
1845 	case SPCN_RSP_STATUS_STATE_PROHIBIT:
1846 	case SPCN_RSP_STATUS_UNKNOWN:
1847 	default:
1848 		/* Replay the previous SPCN command */
1849 		replay_spcn_cmd(last_spcn_cmd);
1850 	}
1851 	fsp_freemsg(msg);
1852 }
1853 
1854 /*
1855  * Init the LED state
1856  *
1857  * This is called during the host boot process. This is the place where
1858  * we figure out all the LEDs present on the system, their state and then
1859  * create structure out of those information and popullate two master lists.
1860  * One for all the LEDs on the CEC and one for all the LEDs on the enclosure.
1861  * The LED information contained in the lists will cater either to various
1862  * FSP initiated async commands or POWERNV initiated OPAL calls. Need to make
1863  * sure that this initialization process is complete before allowing any requets
1864  * on LED. Also need to be called to re-fetch data from SPCN after any LED state
1865  * have been updated.
1866  */
fsp_leds_query_spcn(void)1867 static void fsp_leds_query_spcn(void)
1868 {
1869 	struct fsp_led_data *led = NULL;
1870 	int rc = 0;
1871 
1872 	u32 cmd_hdr = SPCN_MOD_PRS_LED_DATA_FIRST << 24 | SPCN_CMD_PRS << 16;
1873 
1874 	/* Till the last batch of LED data */
1875 	last_spcn_cmd = 0;
1876 
1877 	/* Empty the lists */
1878 	while (!list_empty(&cec_ledq)) {
1879 		led = list_pop(&cec_ledq, struct fsp_led_data, link);
1880 		free(led);
1881 	}
1882 
1883 	while (!list_empty(&encl_ledq)) {
1884 		led = list_pop(&encl_ledq, struct fsp_led_data, link);
1885 		free(led);
1886 	}
1887 
1888 	/* Allocate buffer with alignment requirements */
1889 	if (led_buffer == NULL) {
1890 		led_buffer = memalign(TCE_PSIZE, PSI_DMA_LED_BUF_SZ);
1891 		if (!led_buffer)
1892 			return;
1893 	}
1894 
1895 	/* TCE mapping - will not unmap */
1896 	fsp_tce_map(PSI_DMA_LED_BUF, led_buffer, PSI_DMA_LED_BUF_SZ);
1897 
1898 	/* Request the first 1KB of LED data */
1899 	last_spcn_cmd = SPCN_MOD_PRS_LED_DATA_FIRST;
1900 	rc = fsp_queue_msg(fsp_mkmsg(FSP_CMD_SPCN_PASSTHRU, 4,
1901 			SPCN_ADDR_MODE_CEC_NODE, cmd_hdr, 0,
1902 				PSI_DMA_LED_BUF), fsp_read_leds_data_complete);
1903 	if (rc)
1904 		prlog(PR_ERR,
1905 		      "SPCN_MOD_PRS_LED_DATA_FIRST command could"
1906 		      " not be queued\n");
1907 	else	/* Initiated LED list fetch MBOX command */
1908 		led_support = LED_STATE_READING;
1909 }
1910 
1911 /* Init the LED subsystem at boot time */
fsp_led_init(void)1912 void fsp_led_init(void)
1913 {
1914 	led_buffer = NULL;
1915 
1916 	if (!fsp_present())
1917 		return;
1918 
1919 	/* Init the master lists */
1920 	list_head_init(&cec_ledq);
1921 	list_head_init(&encl_ledq);
1922 	list_head_init(&spcn_cmdq);
1923 
1924 	fsp_leds_query_spcn();
1925 
1926 	loc_code_list_buffer = memalign(TCE_PSIZE, PSI_DMA_LOC_COD_BUF_SZ);
1927 	if (loc_code_list_buffer == NULL)
1928 		prerror("ERROR: Unable to allocate loc_code_list_buffer!\n");
1929 
1930 	prlog(PR_TRACE, "Init completed\n");
1931 
1932 	/* Get System attention indicator state */
1933 	dt_get_sai_loc_code();
1934 	fsp_get_sai();
1935 
1936 	/* Handle FSP initiated async LED commands */
1937 	fsp_register_client(&fsp_indicator_client, FSP_MCLASS_INDICATOR);
1938 	prlog(PR_TRACE, "FSP async command client registered\n");
1939 
1940 	/* Register for SAI update notification */
1941 	sysparam_add_update_notifier(sai_update_notification);
1942 
1943 	opal_register(OPAL_LEDS_GET_INDICATOR, fsp_opal_leds_get_ind, 4);
1944 	opal_register(OPAL_LEDS_SET_INDICATOR, fsp_opal_leds_set_ind, 5);
1945 	prlog(PR_TRACE, "LED OPAL interface registered\n");
1946 }
1947