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