Lines Matching +full:x +full:- +full:rc
1 // SPDX-License-Identifier: GPL-2.0
19 #include <linux/fsi-sbefifo.h>
36 * The SBEFIFO is a pipe-like FSI device for communicating with
48 #define SBEFIFO_UP 0x00 /* FSI -> Host */
49 #define SBEFIFO_DOWN 0x40 /* Host -> FSI */
51 /* Per-bank registers */
83 SBE_STATE_IPLING = 0x1, // IPL'ing - autonomous mode (transient)
84 SBE_STATE_ISTEP = 0x2, // ISTEP - Running IPL by steps (transient)
90 SBE_STATE_QUIESCE = 0x8, // Final state - needs SBE reset to get out
101 #define sbefifo_vacant(sts) (SBEFIFO_FIFO_DEPTH - sbefifo_populated(sts))
157 ffdc_sz -= 3; in __sbefifo_dump_ffdc()
159 dev_err(dev, "SBE invalid FFDC package signature %08x %08x %08x\n", in __sbefifo_dump_ffdc()
171 dev_warn(dev, "+---- SBE FFDC package %d for async err -----+\n", in __sbefifo_dump_ffdc()
174 dev_warn(dev, "+---- SBE FFDC package %d for cmd %02x:%02x -----+\n", in __sbefifo_dump_ffdc()
177 dev_warn(dev, "| Response code: %08x |\n", w2); in __sbefifo_dump_ffdc()
178 dev_warn(dev, "|-------------------------------------------|\n"); in __sbefifo_dump_ffdc()
182 p += sprintf(p, "| %04x:", i << 4); in __sbefifo_dump_ffdc()
184 p += sprintf(p, " %08x", be32_to_cpu(*(ffdc++))); in __sbefifo_dump_ffdc()
185 ffdc_sz--; in __sbefifo_dump_ffdc()
186 if ((i & 3) == 3 || i == (w0 - 1)) { in __sbefifo_dump_ffdc()
194 dev_warn(dev, "+-------------------------------------------+\n"); in __sbefifo_dump_ffdc()
213 pr_debug("sbefifo: cmd %04x, response too small: %zd\n", in sbefifo_parse_status()
215 return -ENXIO; in sbefifo_parse_status()
217 dh = be32_to_cpu(response[resp_len - 1]); in sbefifo_parse_status()
219 dev_err(dev, "SBE cmd %02x:%02x status offset out of range: %d/%zd\n", in sbefifo_parse_status()
221 return -ENXIO; in sbefifo_parse_status()
223 s0 = be32_to_cpu(response[resp_len - dh]); in sbefifo_parse_status()
224 s1 = be32_to_cpu(response[resp_len - dh + 1]); in sbefifo_parse_status()
226 dev_err(dev, "SBE cmd %02x:%02x, status signature invalid: 0x%08x 0x%08x\n", in sbefifo_parse_status()
228 return -ENXIO; in sbefifo_parse_status()
231 ffdc_sz = dh - 3; in sbefifo_parse_status()
232 dev_warn(dev, "SBE error cmd %02x:%02x status=%04x:%04x\n", in sbefifo_parse_status()
235 sbefifo_dump_ffdc(dev, &response[resp_len - dh + 2], in sbefifo_parse_status()
239 *data_len = resp_len - dh; in sbefifo_parse_status()
252 int rc; in sbefifo_regr() local
254 rc = fsi_device_read(sbefifo->fsi_dev, reg, &raw_word, in sbefifo_regr()
256 if (rc) in sbefifo_regr()
257 return rc; in sbefifo_regr()
268 return fsi_device_write(sbefifo->fsi_dev, reg, &raw_word, in sbefifo_regw()
276 int rc; in sbefifo_check_sbe_state() local
278 rc = fsi_slave_read(sbefifo->fsi_dev->slave, CFAM_GP_MBOX_SBM_ADDR, in sbefifo_check_sbe_state()
280 if (rc) in sbefifo_check_sbe_state()
281 return rc; in sbefifo_check_sbe_state()
286 return -ESHUTDOWN; in sbefifo_check_sbe_state()
291 return -ESHUTDOWN; in sbefifo_check_sbe_state()
293 return -EBUSY; in sbefifo_check_sbe_state()
302 return -ESHUTDOWN; in sbefifo_check_sbe_state()
307 sbefifo->async_ffdc = true; in sbefifo_check_sbe_state()
315 return fsi_device_read(sbefifo->fsi_dev, SBEFIFO_DOWN, word, in sbefifo_down_read()
321 return fsi_device_write(sbefifo->fsi_dev, SBEFIFO_UP, &word, in sbefifo_up_write()
327 struct device *dev = &sbefifo->fsi_dev->dev; in sbefifo_request_reset()
330 int rc; in sbefifo_request_reset() local
335 sbefifo->broken = true; in sbefifo_request_reset()
338 rc = sbefifo_regw(sbefifo, SBEFIFO_UP | SBEFIFO_REQ_RESET, 1); in sbefifo_request_reset()
339 if (rc) { in sbefifo_request_reset()
340 dev_err(dev, "Sending reset request failed, rc=%d\n", rc); in sbefifo_request_reset()
341 return rc; in sbefifo_request_reset()
347 rc = sbefifo_regr(sbefifo, SBEFIFO_UP | SBEFIFO_STS, &status); in sbefifo_request_reset()
348 if (rc) { in sbefifo_request_reset()
350 " , rc=%d\n", rc); in sbefifo_request_reset()
351 return rc; in sbefifo_request_reset()
356 sbefifo->broken = false; in sbefifo_request_reset()
364 return -ETIMEDOUT; in sbefifo_request_reset()
369 struct device *dev = &sbefifo->fsi_dev->dev; in sbefifo_cleanup_hw()
372 int rc; in sbefifo_cleanup_hw() local
374 rc = sbefifo_check_sbe_state(sbefifo); in sbefifo_cleanup_hw()
375 if (rc) { in sbefifo_cleanup_hw()
376 dev_dbg(dev, "SBE state=%d\n", rc); in sbefifo_cleanup_hw()
377 return rc; in sbefifo_cleanup_hw()
381 if (sbefifo->broken) in sbefifo_cleanup_hw()
384 rc = sbefifo_regr(sbefifo, SBEFIFO_UP | SBEFIFO_STS, &up_status); in sbefifo_cleanup_hw()
385 if (rc) { in sbefifo_cleanup_hw()
386 dev_err(dev, "Cleanup: Reading UP status failed, rc=%d\n", rc); in sbefifo_cleanup_hw()
389 sbefifo->broken = true; in sbefifo_cleanup_hw()
390 return rc; in sbefifo_cleanup_hw()
393 rc = sbefifo_regr(sbefifo, SBEFIFO_DOWN | SBEFIFO_STS, &down_status); in sbefifo_cleanup_hw()
394 if (rc) { in sbefifo_cleanup_hw()
395 dev_err(dev, "Cleanup: Reading DOWN status failed, rc=%d\n", rc); in sbefifo_cleanup_hw()
398 sbefifo->broken = true; in sbefifo_cleanup_hw()
399 return rc; in sbefifo_cleanup_hw()
405 rc = sbefifo_regw(sbefifo, SBEFIFO_DOWN, SBEFIFO_PERFORM_RESET); in sbefifo_cleanup_hw()
406 if (rc) { in sbefifo_cleanup_hw()
407 sbefifo->broken = true; in sbefifo_cleanup_hw()
408 dev_err(dev, "Cleanup: Reset reg write failed, rc=%d\n", rc); in sbefifo_cleanup_hw()
409 return rc; in sbefifo_cleanup_hw()
411 sbefifo->broken = false; in sbefifo_cleanup_hw()
426 dev_info(dev, "Cleanup: FIFO not clean (up=0x%08x down=0x%08x)\n", in sbefifo_cleanup_hw()
438 struct device *dev = &sbefifo->fsi_dev->dev; in sbefifo_wait()
442 int rc; in sbefifo_wait() local
451 rc = sbefifo_regr(sbefifo, addr, &sts); in sbefifo_wait()
452 if (rc < 0) { in sbefifo_wait()
453 dev_err(dev, "FSI error %d reading status register\n", rc); in sbefifo_wait()
454 return rc; in sbefifo_wait()
458 return -ENXIO; in sbefifo_wait()
465 dev_err(dev, "%s FIFO Timeout ! status=%08x\n", up ? "UP" : "DOWN", sts); in sbefifo_wait()
466 return -ETIMEDOUT; in sbefifo_wait()
468 dev_vdbg(dev, "End of wait status: %08x\n", sts); in sbefifo_wait()
478 struct device *dev = &sbefifo->fsi_dev->dev; in sbefifo_send_command()
482 int rc; in sbefifo_send_command() local
484 dev_vdbg(dev, "sending command (%zd words, cmd=%04x)\n", in sbefifo_send_command()
491 rc = sbefifo_wait(sbefifo, true, &status, timeout); in sbefifo_send_command()
492 if (rc < 0) in sbefifo_send_command()
493 return rc; in sbefifo_send_command()
499 dev_vdbg(dev, " status=%08x vacant=%zd chunk=%zd\n", in sbefifo_send_command()
503 while (len--) { in sbefifo_send_command()
504 rc = sbefifo_up_write(sbefifo, *(command++)); in sbefifo_send_command()
505 if (rc) { in sbefifo_send_command()
506 dev_err(dev, "FSI error %d writing UP FIFO\n", rc); in sbefifo_send_command()
507 return rc; in sbefifo_send_command()
510 remaining -= chunk; in sbefifo_send_command()
511 vacant -= chunk; in sbefifo_send_command()
516 rc = sbefifo_wait(sbefifo, true, &status, timeout); in sbefifo_send_command()
517 if (rc) in sbefifo_send_command()
518 return rc; in sbefifo_send_command()
522 rc = sbefifo_regw(sbefifo, SBEFIFO_UP | SBEFIFO_EOT_RAISE, 0); in sbefifo_send_command()
523 if (rc) in sbefifo_send_command()
524 dev_err(dev, "FSI error %d writing EOT\n", rc); in sbefifo_send_command()
525 return rc; in sbefifo_send_command()
530 struct device *dev = &sbefifo->fsi_dev->dev; in sbefifo_read_response()
536 int rc; in sbefifo_read_response() local
543 rc = sbefifo_wait(sbefifo, false, &status, timeout); in sbefifo_read_response()
544 if (rc < 0) in sbefifo_read_response()
545 return rc; in sbefifo_read_response()
552 dev_vdbg(dev, " chunk size %zd eot_set=0x%x\n", len, eot_set); in sbefifo_read_response()
555 while(len--) { in sbefifo_read_response()
557 rc = sbefifo_down_read(sbefifo, &data); in sbefifo_read_response()
558 if (rc < 0) in sbefifo_read_response()
559 return rc; in sbefifo_read_response()
573 sbefifo->broken = true; in sbefifo_read_response()
577 rc = sbefifo_regw(sbefifo, in sbefifo_read_response()
585 if (rc) { in sbefifo_read_response()
586 dev_err(dev, "FSI error %d ack'ing EOT\n", rc); in sbefifo_read_response()
587 sbefifo->broken = true; in sbefifo_read_response()
591 return overflow ? -EOVERFLOW : 0; in sbefifo_read_response()
597 return -EFAULT; in sbefifo_read_response()
609 return -EIO; in sbefifo_read_response()
617 int rc = sbefifo_send_command(sbefifo, command, cmd_len); in sbefifo_do_command() local
618 if (rc) in sbefifo_do_command()
619 return rc; in sbefifo_do_command()
627 struct device *dev = &sbefifo->fsi_dev->dev; in sbefifo_collect_async_ffdc()
633 int rc; in sbefifo_collect_async_ffdc() local
635 sbefifo->async_ffdc = false; in sbefifo_collect_async_ffdc()
646 rc = sbefifo_do_command(sbefifo, cmd, 2, &ffdc_iter); in sbefifo_collect_async_ffdc()
647 if (rc != 0) { in sbefifo_collect_async_ffdc()
648 dev_err(dev, "Error %d retrieving SBE FFDC\n", rc); in sbefifo_collect_async_ffdc()
651 ffdc_sz = SBEFIFO_MAX_FFDC_SIZE - iov_iter_count(&ffdc_iter); in sbefifo_collect_async_ffdc()
653 rc = sbefifo_parse_status(dev, SBEFIFO_CMD_GET_SBE_FFDC, ffdc, in sbefifo_collect_async_ffdc()
655 if (rc != 0) { in sbefifo_collect_async_ffdc()
656 dev_err(dev, "Error %d decoding SBE FFDC\n", rc); in sbefifo_collect_async_ffdc()
670 struct device *dev = &sbefifo->fsi_dev->dev; in __sbefifo_submit()
671 int rc; in __sbefifo_submit() local
673 if (sbefifo->dead) in __sbefifo_submit()
674 return -ENODEV; in __sbefifo_submit()
679 return -EINVAL; in __sbefifo_submit()
683 rc = sbefifo_cleanup_hw(sbefifo); in __sbefifo_submit()
684 if (rc) in __sbefifo_submit()
685 return rc; in __sbefifo_submit()
688 if (sbefifo->async_ffdc) in __sbefifo_submit()
691 rc = sbefifo_do_command(sbefifo, command, cmd_len, response); in __sbefifo_submit()
692 if (rc != 0 && rc != -EOVERFLOW) in __sbefifo_submit()
694 return rc; in __sbefifo_submit()
703 return rc; in __sbefifo_submit()
707 * sbefifo_submit() - Submit and SBE fifo command and receive response
710 * @cmd_len: The command size (in 32-bit words)
715 * overflows, returns -EOVERFLOW
724 int rc; in sbefifo_submit() local
727 return -ENODEV; in sbefifo_submit()
730 return -ENODEV; in sbefifo_submit()
731 if (WARN_ON_ONCE(sbefifo->magic != SBEFIFO_MAGIC)) in sbefifo_submit()
732 return -ENODEV; in sbefifo_submit()
734 return -EINVAL; in sbefifo_submit()
743 mutex_lock(&sbefifo->lock); in sbefifo_submit()
744 rc = __sbefifo_submit(sbefifo, command, cmd_len, &resp_iter); in sbefifo_submit()
745 mutex_unlock(&sbefifo->lock); in sbefifo_submit()
748 rbytes -= iov_iter_count(&resp_iter); in sbefifo_submit()
751 return rc; in sbefifo_submit()
761 if (is_vmalloc_addr(user->pending_cmd)) in sbefifo_release_command()
762 vfree(user->pending_cmd); in sbefifo_release_command()
763 user->pending_cmd = NULL; in sbefifo_release_command()
764 user->pending_len = 0; in sbefifo_release_command()
769 struct sbefifo *sbefifo = container_of(inode->i_cdev, struct sbefifo, cdev); in sbefifo_user_open()
774 return -ENOMEM; in sbefifo_user_open()
776 file->private_data = user; in sbefifo_user_open()
777 user->sbefifo = sbefifo; in sbefifo_user_open()
778 user->cmd_page = (void *)__get_free_page(GFP_KERNEL); in sbefifo_user_open()
779 if (!user->cmd_page) { in sbefifo_user_open()
781 return -ENOMEM; in sbefifo_user_open()
783 mutex_init(&user->file_lock); in sbefifo_user_open()
791 struct sbefifo_user *user = file->private_data; in sbefifo_user_read()
796 int rc; in sbefifo_user_read() local
799 return -EINVAL; in sbefifo_user_read()
800 sbefifo = user->sbefifo; in sbefifo_user_read()
802 return -EINVAL; in sbefifo_user_read()
804 mutex_lock(&user->file_lock); in sbefifo_user_read()
806 /* Cronus relies on -EAGAIN after a short read */ in sbefifo_user_read()
807 if (user->pending_len == 0) { in sbefifo_user_read()
808 rc = -EAGAIN; in sbefifo_user_read()
811 if (user->pending_len < 8) { in sbefifo_user_read()
812 rc = -EINVAL; in sbefifo_user_read()
815 cmd_len = user->pending_len >> 2; in sbefifo_user_read()
823 mutex_lock(&sbefifo->lock); in sbefifo_user_read()
824 rc = __sbefifo_submit(sbefifo, user->pending_cmd, cmd_len, &resp_iter); in sbefifo_user_read()
825 mutex_unlock(&sbefifo->lock); in sbefifo_user_read()
826 if (rc < 0) in sbefifo_user_read()
830 rc = len - iov_iter_count(&resp_iter); in sbefifo_user_read()
833 mutex_unlock(&user->file_lock); in sbefifo_user_read()
834 return rc; in sbefifo_user_read()
840 struct sbefifo_user *user = file->private_data; in sbefifo_user_write()
842 int rc = len; in sbefifo_user_write() local
845 return -EINVAL; in sbefifo_user_write()
846 sbefifo = user->sbefifo; in sbefifo_user_write()
848 return -EINVAL; in sbefifo_user_write()
850 return -EINVAL; in sbefifo_user_write()
852 mutex_lock(&user->file_lock); in sbefifo_user_write()
854 /* Can we use the pre-allocate buffer ? If not, allocate */ in sbefifo_user_write()
856 user->pending_cmd = user->cmd_page; in sbefifo_user_write()
858 user->pending_cmd = vmalloc(len); in sbefifo_user_write()
859 if (!user->pending_cmd) { in sbefifo_user_write()
860 rc = -ENOMEM; in sbefifo_user_write()
865 if (copy_from_user(user->pending_cmd, buf, len)) { in sbefifo_user_write()
866 rc = -EFAULT; in sbefifo_user_write()
871 if (len == 4 && be32_to_cpu(*(__be32 *)user->pending_cmd) == in sbefifo_user_write()
875 user->pending_len = 0; in sbefifo_user_write()
878 mutex_lock(&sbefifo->lock); in sbefifo_user_write()
879 rc = sbefifo_request_reset(user->sbefifo); in sbefifo_user_write()
880 mutex_unlock(&sbefifo->lock); in sbefifo_user_write()
881 if (rc == 0) in sbefifo_user_write()
882 rc = 4; in sbefifo_user_write()
887 user->pending_len = len; in sbefifo_user_write()
889 if (!user->pending_len) in sbefifo_user_write()
892 mutex_unlock(&user->file_lock); in sbefifo_user_write()
895 return rc; in sbefifo_user_write()
900 struct sbefifo_user *user = file->private_data; in sbefifo_user_release()
903 return -EINVAL; in sbefifo_user_release()
906 free_page((unsigned long)user->cmd_page); in sbefifo_user_release()
924 put_device(&sbefifo->fsi_dev->dev); in sbefifo_free()
939 int rc, didx, child_idx = 0; in sbefifo_probe() local
945 return -ENOMEM; in sbefifo_probe()
950 return -ENODEV; in sbefifo_probe()
953 sbefifo->magic = SBEFIFO_MAGIC; in sbefifo_probe()
954 sbefifo->fsi_dev = fsi_dev; in sbefifo_probe()
956 mutex_init(&sbefifo->lock); in sbefifo_probe()
962 rc = sbefifo_cleanup_hw(sbefifo); in sbefifo_probe()
963 if (rc && rc != -ESHUTDOWN) in sbefifo_probe()
967 sbefifo->dev.type = &fsi_cdev_type; in sbefifo_probe()
968 sbefifo->dev.parent = dev; in sbefifo_probe()
969 sbefifo->dev.release = sbefifo_free; in sbefifo_probe()
970 device_initialize(&sbefifo->dev); in sbefifo_probe()
973 rc = fsi_get_new_minor(fsi_dev, fsi_dev_sbefifo, &sbefifo->dev.devt, &didx); in sbefifo_probe()
974 if (rc) in sbefifo_probe()
977 dev_set_name(&sbefifo->dev, "sbefifo%d", didx); in sbefifo_probe()
978 cdev_init(&sbefifo->cdev, &sbefifo_fops); in sbefifo_probe()
979 rc = cdev_device_add(&sbefifo->cdev, &sbefifo->dev); in sbefifo_probe()
980 if (rc) { in sbefifo_probe()
982 rc, dev_name(&sbefifo->dev)); in sbefifo_probe()
987 for_each_available_child_of_node(dev->of_node, np) { in sbefifo_probe()
988 snprintf(child_name, sizeof(child_name), "%s-dev%d", in sbefifo_probe()
989 dev_name(&sbefifo->dev), child_idx++); in sbefifo_probe()
998 fsi_free_minor(sbefifo->dev.devt); in sbefifo_probe()
1000 put_device(&sbefifo->dev); in sbefifo_probe()
1001 return rc; in sbefifo_probe()
1009 if (dev->of_node) in sbefifo_unregister_child()
1010 of_node_clear_flag(dev->of_node, OF_POPULATED); in sbefifo_unregister_child()
1021 mutex_lock(&sbefifo->lock); in sbefifo_remove()
1022 sbefifo->dead = true; in sbefifo_remove()
1023 mutex_unlock(&sbefifo->lock); in sbefifo_remove()
1025 cdev_device_del(&sbefifo->cdev, &sbefifo->dev); in sbefifo_remove()
1026 fsi_free_minor(sbefifo->dev.devt); in sbefifo_remove()
1028 put_device(&sbefifo->dev); in sbefifo_remove()