Lines Matching +full:x +full:- +full:rc
1 // SPDX-License-Identifier: GPL-2.0
19 #include <linux/fsi-sbefifo.h>
38 * The SBEFIFO is a pipe-like FSI device for communicating with
50 #define SBEFIFO_UP 0x00 /* FSI -> Host */
51 #define SBEFIFO_DOWN 0x40 /* Host -> FSI */
53 /* Per-bank registers */
85 SBE_STATE_IPLING = 0x1, // IPL'ing - autonomous mode (transient)
86 SBE_STATE_ISTEP = 0x2, // ISTEP - Running IPL by steps (transient)
92 SBE_STATE_QUIESCE = 0x8, // Final state - needs SBE reset to get out
103 #define sbefifo_vacant(sts) (SBEFIFO_FIFO_DEPTH - sbefifo_populated(sts))
151 return sysfs_emit(buf, "%d\n", sbefifo->timed_out ? 1 : 0); in timeout_show()
172 ffdc_sz -= 3; in __sbefifo_dump_ffdc()
174 dev_err(dev, "SBE invalid FFDC package signature %08x %08x %08x\n", in __sbefifo_dump_ffdc()
186 dev_warn(dev, "+---- SBE FFDC package %d for async err -----+\n", in __sbefifo_dump_ffdc()
189 dev_warn(dev, "+---- SBE FFDC package %d for cmd %02x:%02x -----+\n", in __sbefifo_dump_ffdc()
192 dev_warn(dev, "| Response code: %08x |\n", w2); in __sbefifo_dump_ffdc()
193 dev_warn(dev, "|-------------------------------------------|\n"); in __sbefifo_dump_ffdc()
197 p += sprintf(p, "| %04x:", i << 4); in __sbefifo_dump_ffdc()
199 p += sprintf(p, " %08x", be32_to_cpu(*(ffdc++))); in __sbefifo_dump_ffdc()
200 ffdc_sz--; in __sbefifo_dump_ffdc()
201 if ((i & 3) == 3 || i == (w0 - 1)) { in __sbefifo_dump_ffdc()
209 dev_warn(dev, "+-------------------------------------------+\n"); in __sbefifo_dump_ffdc()
228 pr_debug("sbefifo: cmd %04x, response too small: %zd\n", in sbefifo_parse_status()
230 return -ENXIO; in sbefifo_parse_status()
232 dh = be32_to_cpu(response[resp_len - 1]); in sbefifo_parse_status()
234 dev_err(dev, "SBE cmd %02x:%02x status offset out of range: %d/%zd\n", in sbefifo_parse_status()
236 return -ENXIO; in sbefifo_parse_status()
238 s0 = be32_to_cpu(response[resp_len - dh]); in sbefifo_parse_status()
239 s1 = be32_to_cpu(response[resp_len - dh + 1]); in sbefifo_parse_status()
241 dev_err(dev, "SBE cmd %02x:%02x, status signature invalid: 0x%08x 0x%08x\n", in sbefifo_parse_status()
243 return -ENXIO; in sbefifo_parse_status()
246 ffdc_sz = dh - 3; in sbefifo_parse_status()
247 dev_warn(dev, "SBE error cmd %02x:%02x status=%04x:%04x\n", in sbefifo_parse_status()
250 sbefifo_dump_ffdc(dev, &response[resp_len - dh + 2], in sbefifo_parse_status()
254 *data_len = resp_len - dh; in sbefifo_parse_status()
267 int rc; in sbefifo_regr() local
269 rc = fsi_device_read(sbefifo->fsi_dev, reg, &raw_word, in sbefifo_regr()
271 if (rc) in sbefifo_regr()
272 return rc; in sbefifo_regr()
283 return fsi_device_write(sbefifo->fsi_dev, reg, &raw_word, in sbefifo_regw()
291 int rc; in sbefifo_check_sbe_state() local
293 rc = fsi_slave_read(sbefifo->fsi_dev->slave, CFAM_GP_MBOX_SBM_ADDR, in sbefifo_check_sbe_state()
295 if (rc) in sbefifo_check_sbe_state()
296 return rc; in sbefifo_check_sbe_state()
301 return -ESHUTDOWN; in sbefifo_check_sbe_state()
306 return -ESHUTDOWN; in sbefifo_check_sbe_state()
308 return -EBUSY; in sbefifo_check_sbe_state()
317 return -ESHUTDOWN; in sbefifo_check_sbe_state()
322 sbefifo->async_ffdc = true; in sbefifo_check_sbe_state()
330 return fsi_device_read(sbefifo->fsi_dev, SBEFIFO_DOWN, word, in sbefifo_down_read()
336 return fsi_device_write(sbefifo->fsi_dev, SBEFIFO_UP, &word, in sbefifo_up_write()
342 struct device *dev = &sbefifo->fsi_dev->dev; in sbefifo_request_reset()
345 int rc; in sbefifo_request_reset() local
350 sbefifo->broken = true; in sbefifo_request_reset()
353 rc = sbefifo_regw(sbefifo, SBEFIFO_UP | SBEFIFO_REQ_RESET, 1); in sbefifo_request_reset()
354 if (rc) { in sbefifo_request_reset()
355 dev_err(dev, "Sending reset request failed, rc=%d\n", rc); in sbefifo_request_reset()
356 return rc; in sbefifo_request_reset()
362 rc = sbefifo_regr(sbefifo, SBEFIFO_UP | SBEFIFO_STS, &status); in sbefifo_request_reset()
363 if (rc) { in sbefifo_request_reset()
365 " , rc=%d\n", rc); in sbefifo_request_reset()
366 return rc; in sbefifo_request_reset()
371 sbefifo->broken = false; in sbefifo_request_reset()
379 return -ETIMEDOUT; in sbefifo_request_reset()
384 struct device *dev = &sbefifo->fsi_dev->dev; in sbefifo_cleanup_hw()
387 int rc; in sbefifo_cleanup_hw() local
389 rc = sbefifo_check_sbe_state(sbefifo); in sbefifo_cleanup_hw()
390 if (rc) { in sbefifo_cleanup_hw()
391 dev_dbg(dev, "SBE state=%d\n", rc); in sbefifo_cleanup_hw()
392 return rc; in sbefifo_cleanup_hw()
396 if (sbefifo->broken) in sbefifo_cleanup_hw()
399 rc = sbefifo_regr(sbefifo, SBEFIFO_UP | SBEFIFO_STS, &up_status); in sbefifo_cleanup_hw()
400 if (rc) { in sbefifo_cleanup_hw()
401 dev_err(dev, "Cleanup: Reading UP status failed, rc=%d\n", rc); in sbefifo_cleanup_hw()
404 sbefifo->broken = true; in sbefifo_cleanup_hw()
405 return rc; in sbefifo_cleanup_hw()
408 rc = sbefifo_regr(sbefifo, SBEFIFO_DOWN | SBEFIFO_STS, &down_status); in sbefifo_cleanup_hw()
409 if (rc) { in sbefifo_cleanup_hw()
410 dev_err(dev, "Cleanup: Reading DOWN status failed, rc=%d\n", rc); in sbefifo_cleanup_hw()
413 sbefifo->broken = true; in sbefifo_cleanup_hw()
414 return rc; in sbefifo_cleanup_hw()
420 rc = sbefifo_regw(sbefifo, SBEFIFO_DOWN, SBEFIFO_PERFORM_RESET); in sbefifo_cleanup_hw()
421 if (rc) { in sbefifo_cleanup_hw()
422 sbefifo->broken = true; in sbefifo_cleanup_hw()
423 dev_err(dev, "Cleanup: Reset reg write failed, rc=%d\n", rc); in sbefifo_cleanup_hw()
424 return rc; in sbefifo_cleanup_hw()
426 sbefifo->broken = false; in sbefifo_cleanup_hw()
441 dev_info(dev, "Cleanup: FIFO not clean (up=0x%08x down=0x%08x)\n", in sbefifo_cleanup_hw()
453 struct device *dev = &sbefifo->fsi_dev->dev; in sbefifo_wait()
457 int rc; in sbefifo_wait() local
466 rc = sbefifo_regr(sbefifo, addr, &sts); in sbefifo_wait()
467 if (rc < 0) { in sbefifo_wait()
468 dev_err(dev, "FSI error %d reading status register\n", rc); in sbefifo_wait()
469 return rc; in sbefifo_wait()
473 return -ENXIO; in sbefifo_wait()
480 sysfs_notify(&sbefifo->dev.kobj, NULL, dev_attr_timeout.attr.name); in sbefifo_wait()
481 sbefifo->timed_out = true; in sbefifo_wait()
482 dev_err(dev, "%s FIFO Timeout (%u ms)! status=%08x\n", in sbefifo_wait()
484 return -ETIMEDOUT; in sbefifo_wait()
486 dev_vdbg(dev, "End of wait status: %08x\n", sts); in sbefifo_wait()
488 sbefifo->timed_out = false; in sbefifo_wait()
497 struct device *dev = &sbefifo->fsi_dev->dev; in sbefifo_send_command()
501 int rc; in sbefifo_send_command() local
503 dev_dbg(dev, "sending command (%zd words, cmd=%04x)\n", in sbefifo_send_command()
510 rc = sbefifo_wait(sbefifo, true, &status, timeout); in sbefifo_send_command()
511 if (rc < 0) in sbefifo_send_command()
512 return rc; in sbefifo_send_command()
513 timeout = msecs_to_jiffies(sbefifo->timeout_in_cmd_ms); in sbefifo_send_command()
518 dev_vdbg(dev, " status=%08x vacant=%zd chunk=%zd\n", in sbefifo_send_command()
522 while (len--) { in sbefifo_send_command()
523 rc = sbefifo_up_write(sbefifo, *(command++)); in sbefifo_send_command()
524 if (rc) { in sbefifo_send_command()
525 dev_err(dev, "FSI error %d writing UP FIFO\n", rc); in sbefifo_send_command()
526 return rc; in sbefifo_send_command()
529 remaining -= chunk; in sbefifo_send_command()
530 vacant -= chunk; in sbefifo_send_command()
535 rc = sbefifo_wait(sbefifo, true, &status, timeout); in sbefifo_send_command()
536 if (rc) in sbefifo_send_command()
537 return rc; in sbefifo_send_command()
541 rc = sbefifo_regw(sbefifo, SBEFIFO_UP | SBEFIFO_EOT_RAISE, 0); in sbefifo_send_command()
542 if (rc) in sbefifo_send_command()
543 dev_err(dev, "FSI error %d writing EOT\n", rc); in sbefifo_send_command()
544 return rc; in sbefifo_send_command()
549 struct device *dev = &sbefifo->fsi_dev->dev; in sbefifo_read_response()
555 int rc; in sbefifo_read_response() local
559 timeout = msecs_to_jiffies(sbefifo->timeout_start_rsp_ms); in sbefifo_read_response()
562 rc = sbefifo_wait(sbefifo, false, &status, timeout); in sbefifo_read_response()
563 if (rc < 0) { in sbefifo_read_response()
565 return rc; in sbefifo_read_response()
573 dev_dbg(dev, " chunk size %zd eot_set=0x%x\n", len, eot_set); in sbefifo_read_response()
576 while(len--) { in sbefifo_read_response()
578 rc = sbefifo_down_read(sbefifo, &data); in sbefifo_read_response()
579 if (rc < 0) in sbefifo_read_response()
580 return rc; in sbefifo_read_response()
594 sbefifo->broken = true; in sbefifo_read_response()
598 rc = sbefifo_regw(sbefifo, in sbefifo_read_response()
606 if (rc) { in sbefifo_read_response()
607 dev_err(dev, "FSI error %d ack'ing EOT\n", rc); in sbefifo_read_response()
608 sbefifo->broken = true; in sbefifo_read_response()
612 return overflow ? -EOVERFLOW : 0; in sbefifo_read_response()
618 return -EFAULT; in sbefifo_read_response()
630 return -EIO; in sbefifo_read_response()
638 int rc = sbefifo_send_command(sbefifo, command, cmd_len); in sbefifo_do_command() local
639 if (rc) in sbefifo_do_command()
640 return rc; in sbefifo_do_command()
648 struct device *dev = &sbefifo->fsi_dev->dev; in sbefifo_collect_async_ffdc()
654 int rc; in sbefifo_collect_async_ffdc() local
656 sbefifo->async_ffdc = false; in sbefifo_collect_async_ffdc()
667 rc = sbefifo_do_command(sbefifo, cmd, 2, &ffdc_iter); in sbefifo_collect_async_ffdc()
668 if (rc != 0) { in sbefifo_collect_async_ffdc()
669 dev_err(dev, "Error %d retrieving SBE FFDC\n", rc); in sbefifo_collect_async_ffdc()
672 ffdc_sz = SBEFIFO_MAX_FFDC_SIZE - iov_iter_count(&ffdc_iter); in sbefifo_collect_async_ffdc()
674 rc = sbefifo_parse_status(dev, SBEFIFO_CMD_GET_SBE_FFDC, ffdc, in sbefifo_collect_async_ffdc()
676 if (rc != 0) { in sbefifo_collect_async_ffdc()
677 dev_err(dev, "Error %d decoding SBE FFDC\n", rc); in sbefifo_collect_async_ffdc()
691 struct device *dev = &sbefifo->fsi_dev->dev; in __sbefifo_submit()
692 int rc; in __sbefifo_submit() local
694 if (sbefifo->dead) in __sbefifo_submit()
695 return -ENODEV; in __sbefifo_submit()
700 return -EINVAL; in __sbefifo_submit()
704 rc = sbefifo_cleanup_hw(sbefifo); in __sbefifo_submit()
705 if (rc) in __sbefifo_submit()
706 return rc; in __sbefifo_submit()
709 if (sbefifo->async_ffdc) in __sbefifo_submit()
712 rc = sbefifo_do_command(sbefifo, command, cmd_len, response); in __sbefifo_submit()
713 if (rc != 0 && rc != -EOVERFLOW) in __sbefifo_submit()
715 return rc; in __sbefifo_submit()
724 return rc; in __sbefifo_submit()
728 * sbefifo_submit() - Submit and SBE fifo command and receive response
731 * @cmd_len: The command size (in 32-bit words)
736 * overflows, returns -EOVERFLOW
745 int rc; in sbefifo_submit() local
748 return -ENODEV; in sbefifo_submit()
751 return -ENODEV; in sbefifo_submit()
752 if (WARN_ON_ONCE(sbefifo->magic != SBEFIFO_MAGIC)) in sbefifo_submit()
753 return -ENODEV; in sbefifo_submit()
755 return -EINVAL; in sbefifo_submit()
764 rc = mutex_lock_interruptible(&sbefifo->lock); in sbefifo_submit()
765 if (rc) in sbefifo_submit()
766 return rc; in sbefifo_submit()
767 rc = __sbefifo_submit(sbefifo, command, cmd_len, &resp_iter); in sbefifo_submit()
768 mutex_unlock(&sbefifo->lock); in sbefifo_submit()
771 rbytes -= iov_iter_count(&resp_iter); in sbefifo_submit()
774 return rc; in sbefifo_submit()
784 if (is_vmalloc_addr(user->pending_cmd)) in sbefifo_release_command()
785 vfree(user->pending_cmd); in sbefifo_release_command()
786 user->pending_cmd = NULL; in sbefifo_release_command()
787 user->pending_len = 0; in sbefifo_release_command()
792 struct sbefifo *sbefifo = container_of(inode->i_cdev, struct sbefifo, cdev); in sbefifo_user_open()
797 return -ENOMEM; in sbefifo_user_open()
799 file->private_data = user; in sbefifo_user_open()
800 user->sbefifo = sbefifo; in sbefifo_user_open()
801 user->cmd_page = (void *)__get_free_page(GFP_KERNEL); in sbefifo_user_open()
802 if (!user->cmd_page) { in sbefifo_user_open()
804 return -ENOMEM; in sbefifo_user_open()
806 mutex_init(&user->file_lock); in sbefifo_user_open()
807 user->cmd_timeout_ms = SBEFIFO_TIMEOUT_IN_CMD; in sbefifo_user_open()
808 user->read_timeout_ms = SBEFIFO_TIMEOUT_START_RSP; in sbefifo_user_open()
816 struct sbefifo_user *user = file->private_data; in sbefifo_user_read()
821 int rc; in sbefifo_user_read() local
824 return -EINVAL; in sbefifo_user_read()
825 sbefifo = user->sbefifo; in sbefifo_user_read()
827 return -EINVAL; in sbefifo_user_read()
829 mutex_lock(&user->file_lock); in sbefifo_user_read()
831 /* Cronus relies on -EAGAIN after a short read */ in sbefifo_user_read()
832 if (user->pending_len == 0) { in sbefifo_user_read()
833 rc = -EAGAIN; in sbefifo_user_read()
836 if (user->pending_len < 8) { in sbefifo_user_read()
837 rc = -EINVAL; in sbefifo_user_read()
840 cmd_len = user->pending_len >> 2; in sbefifo_user_read()
848 rc = mutex_lock_interruptible(&sbefifo->lock); in sbefifo_user_read()
849 if (rc) in sbefifo_user_read()
851 sbefifo->timeout_in_cmd_ms = user->cmd_timeout_ms; in sbefifo_user_read()
852 sbefifo->timeout_start_rsp_ms = user->read_timeout_ms; in sbefifo_user_read()
853 rc = __sbefifo_submit(sbefifo, user->pending_cmd, cmd_len, &resp_iter); in sbefifo_user_read()
854 sbefifo->timeout_start_rsp_ms = SBEFIFO_TIMEOUT_START_RSP; in sbefifo_user_read()
855 sbefifo->timeout_in_cmd_ms = SBEFIFO_TIMEOUT_IN_CMD; in sbefifo_user_read()
856 mutex_unlock(&sbefifo->lock); in sbefifo_user_read()
857 if (rc < 0) in sbefifo_user_read()
861 rc = len - iov_iter_count(&resp_iter); in sbefifo_user_read()
864 mutex_unlock(&user->file_lock); in sbefifo_user_read()
865 return rc; in sbefifo_user_read()
871 struct sbefifo_user *user = file->private_data; in sbefifo_user_write()
873 int rc = len; in sbefifo_user_write() local
876 return -EINVAL; in sbefifo_user_write()
877 sbefifo = user->sbefifo; in sbefifo_user_write()
879 return -EINVAL; in sbefifo_user_write()
881 return -EINVAL; in sbefifo_user_write()
883 mutex_lock(&user->file_lock); in sbefifo_user_write()
885 /* Can we use the pre-allocate buffer ? If not, allocate */ in sbefifo_user_write()
887 user->pending_cmd = user->cmd_page; in sbefifo_user_write()
889 user->pending_cmd = vmalloc(len); in sbefifo_user_write()
890 if (!user->pending_cmd) { in sbefifo_user_write()
891 rc = -ENOMEM; in sbefifo_user_write()
896 if (copy_from_user(user->pending_cmd, buf, len)) { in sbefifo_user_write()
897 rc = -EFAULT; in sbefifo_user_write()
902 if (len == 4 && be32_to_cpu(*(__be32 *)user->pending_cmd) == in sbefifo_user_write()
906 user->pending_len = 0; in sbefifo_user_write()
909 rc = mutex_lock_interruptible(&sbefifo->lock); in sbefifo_user_write()
910 if (rc) in sbefifo_user_write()
912 rc = sbefifo_request_reset(user->sbefifo); in sbefifo_user_write()
913 mutex_unlock(&sbefifo->lock); in sbefifo_user_write()
914 if (rc == 0) in sbefifo_user_write()
915 rc = 4; in sbefifo_user_write()
920 user->pending_len = len; in sbefifo_user_write()
922 if (!user->pending_len) in sbefifo_user_write()
925 mutex_unlock(&user->file_lock); in sbefifo_user_write()
928 return rc; in sbefifo_user_write()
933 struct sbefifo_user *user = file->private_data; in sbefifo_user_release()
936 return -EINVAL; in sbefifo_user_release()
939 free_page((unsigned long)user->cmd_page); in sbefifo_user_release()
947 struct device *dev = &user->sbefifo->dev; in sbefifo_cmd_timeout()
951 return -EFAULT; in sbefifo_cmd_timeout()
954 user->cmd_timeout_ms = SBEFIFO_TIMEOUT_IN_CMD; in sbefifo_cmd_timeout()
955 dev_dbg(dev, "Command timeout reset to %us\n", user->cmd_timeout_ms / 1000); in sbefifo_cmd_timeout()
959 user->cmd_timeout_ms = timeout * 1000; /* user timeout is in sec */ in sbefifo_cmd_timeout()
966 struct device *dev = &user->sbefifo->dev; in sbefifo_read_timeout()
970 return -EFAULT; in sbefifo_read_timeout()
973 user->read_timeout_ms = SBEFIFO_TIMEOUT_START_RSP; in sbefifo_read_timeout()
974 dev_dbg(dev, "Timeout reset to %us\n", user->read_timeout_ms / 1000); in sbefifo_read_timeout()
978 user->read_timeout_ms = timeout * 1000; /* user timeout is in sec */ in sbefifo_read_timeout()
985 struct sbefifo_user *user = file->private_data; in sbefifo_user_ioctl()
986 int rc = -ENOTTY; in sbefifo_user_ioctl() local
989 return -EINVAL; in sbefifo_user_ioctl()
991 mutex_lock(&user->file_lock); in sbefifo_user_ioctl()
994 rc = sbefifo_cmd_timeout(user, (void __user *)arg); in sbefifo_user_ioctl()
997 rc = sbefifo_read_timeout(user, (void __user *)arg); in sbefifo_user_ioctl()
1000 mutex_unlock(&user->file_lock); in sbefifo_user_ioctl()
1001 return rc; in sbefifo_user_ioctl()
1017 put_device(&sbefifo->fsi_dev->dev); in sbefifo_free()
1032 int rc, didx, child_idx = 0; in sbefifo_probe() local
1038 return -ENOMEM; in sbefifo_probe()
1043 return -ENODEV; in sbefifo_probe()
1046 sbefifo->magic = SBEFIFO_MAGIC; in sbefifo_probe()
1047 sbefifo->fsi_dev = fsi_dev; in sbefifo_probe()
1049 mutex_init(&sbefifo->lock); in sbefifo_probe()
1050 sbefifo->timeout_in_cmd_ms = SBEFIFO_TIMEOUT_IN_CMD; in sbefifo_probe()
1051 sbefifo->timeout_start_rsp_ms = SBEFIFO_TIMEOUT_START_RSP; in sbefifo_probe()
1054 sbefifo->dev.type = &fsi_cdev_type; in sbefifo_probe()
1055 sbefifo->dev.parent = dev; in sbefifo_probe()
1056 sbefifo->dev.release = sbefifo_free; in sbefifo_probe()
1057 device_initialize(&sbefifo->dev); in sbefifo_probe()
1060 rc = fsi_get_new_minor(fsi_dev, fsi_dev_sbefifo, &sbefifo->dev.devt, &didx); in sbefifo_probe()
1061 if (rc) in sbefifo_probe()
1064 dev_set_name(&sbefifo->dev, "sbefifo%d", didx); in sbefifo_probe()
1065 cdev_init(&sbefifo->cdev, &sbefifo_fops); in sbefifo_probe()
1066 rc = cdev_device_add(&sbefifo->cdev, &sbefifo->dev); in sbefifo_probe()
1067 if (rc) { in sbefifo_probe()
1069 rc, dev_name(&sbefifo->dev)); in sbefifo_probe()
1074 for_each_available_child_of_node(dev->of_node, np) { in sbefifo_probe()
1075 snprintf(child_name, sizeof(child_name), "%s-dev%d", in sbefifo_probe()
1076 dev_name(&sbefifo->dev), child_idx++); in sbefifo_probe()
1083 device_create_file(&sbefifo->dev, &dev_attr_timeout); in sbefifo_probe()
1087 fsi_free_minor(sbefifo->dev.devt); in sbefifo_probe()
1089 put_device(&sbefifo->dev); in sbefifo_probe()
1090 return rc; in sbefifo_probe()
1098 if (dev->of_node) in sbefifo_unregister_child()
1099 of_node_clear_flag(dev->of_node, OF_POPULATED); in sbefifo_unregister_child()
1110 device_remove_file(&sbefifo->dev, &dev_attr_timeout); in sbefifo_remove()
1112 mutex_lock(&sbefifo->lock); in sbefifo_remove()
1113 sbefifo->dead = true; in sbefifo_remove()
1114 mutex_unlock(&sbefifo->lock); in sbefifo_remove()
1116 cdev_device_del(&sbefifo->cdev, &sbefifo->dev); in sbefifo_remove()
1117 fsi_free_minor(sbefifo->dev.devt); in sbefifo_remove()
1119 put_device(&sbefifo->dev); in sbefifo_remove()