diff options
author | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2018-08-08 02:37:53 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2018-08-08 02:37:53 -0400 |
commit | 6d33b3069ed84be9b8430ccc7705d0e747542a4f (patch) | |
tree | 495801abfd12692d4f9d0b0bffc234ee299baa4c | |
parent | a39284ae9d2ad09975c8ae33f1bd0f05fbfbf6ee (diff) | |
parent | 15e2a7218c2788d79c5633336d17cb9428c221e7 (diff) |
Merge tag 'fsi-updates-2018-08-08' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/linux-fsi into char-misc-next
Ben writes:
FSI Updates for 4.19
This adds two FSI fixes:
- Fix a NULL dereference in the scom driver
- Fix a command buffer size issue in the sbefifo driver that
breaks some operations with POWER system debugger (cronus)
-rw-r--r-- | drivers/fsi/fsi-sbefifo.c | 39 | ||||
-rw-r--r-- | drivers/fsi/fsi-scom.c | 1 |
2 files changed, 33 insertions, 7 deletions
diff --git a/drivers/fsi/fsi-sbefifo.c b/drivers/fsi/fsi-sbefifo.c index 7550497da8ef..ae861342626e 100644 --- a/drivers/fsi/fsi-sbefifo.c +++ b/drivers/fsi/fsi-sbefifo.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <linux/delay.h> | 30 | #include <linux/delay.h> |
31 | #include <linux/uio.h> | 31 | #include <linux/uio.h> |
32 | #include <linux/vmalloc.h> | 32 | #include <linux/vmalloc.h> |
33 | #include <linux/mm.h> | ||
33 | 34 | ||
34 | /* | 35 | /* |
35 | * The SBEFIFO is a pipe-like FSI device for communicating with | 36 | * The SBEFIFO is a pipe-like FSI device for communicating with |
@@ -110,7 +111,7 @@ enum sbe_state | |||
110 | #define SBEFIFO_TIMEOUT_IN_RSP 1000 | 111 | #define SBEFIFO_TIMEOUT_IN_RSP 1000 |
111 | 112 | ||
112 | /* Other constants */ | 113 | /* Other constants */ |
113 | #define SBEFIFO_MAX_CMD_LEN PAGE_SIZE | 114 | #define SBEFIFO_MAX_USER_CMD_LEN (0x100000 + PAGE_SIZE) |
114 | #define SBEFIFO_RESET_MAGIC 0x52534554 /* "RSET" */ | 115 | #define SBEFIFO_RESET_MAGIC 0x52534554 /* "RSET" */ |
115 | 116 | ||
116 | struct sbefifo { | 117 | struct sbefifo { |
@@ -128,6 +129,7 @@ struct sbefifo { | |||
128 | struct sbefifo_user { | 129 | struct sbefifo_user { |
129 | struct sbefifo *sbefifo; | 130 | struct sbefifo *sbefifo; |
130 | struct mutex file_lock; | 131 | struct mutex file_lock; |
132 | void *cmd_page; | ||
131 | void *pending_cmd; | 133 | void *pending_cmd; |
132 | size_t pending_len; | 134 | size_t pending_len; |
133 | }; | 135 | }; |
@@ -726,7 +728,7 @@ int sbefifo_submit(struct device *dev, const __be32 *command, size_t cmd_len, | |||
726 | return -ENODEV; | 728 | return -ENODEV; |
727 | if (WARN_ON_ONCE(sbefifo->magic != SBEFIFO_MAGIC)) | 729 | if (WARN_ON_ONCE(sbefifo->magic != SBEFIFO_MAGIC)) |
728 | return -ENODEV; | 730 | return -ENODEV; |
729 | if (!resp_len || !command || !response || cmd_len > SBEFIFO_MAX_CMD_LEN) | 731 | if (!resp_len || !command || !response) |
730 | return -EINVAL; | 732 | return -EINVAL; |
731 | 733 | ||
732 | /* Prepare iov iterator */ | 734 | /* Prepare iov iterator */ |
@@ -751,6 +753,15 @@ EXPORT_SYMBOL_GPL(sbefifo_submit); | |||
751 | /* | 753 | /* |
752 | * Char device interface | 754 | * Char device interface |
753 | */ | 755 | */ |
756 | |||
757 | static void sbefifo_release_command(struct sbefifo_user *user) | ||
758 | { | ||
759 | if (is_vmalloc_addr(user->pending_cmd)) | ||
760 | vfree(user->pending_cmd); | ||
761 | user->pending_cmd = NULL; | ||
762 | user->pending_len = 0; | ||
763 | } | ||
764 | |||
754 | static int sbefifo_user_open(struct inode *inode, struct file *file) | 765 | static int sbefifo_user_open(struct inode *inode, struct file *file) |
755 | { | 766 | { |
756 | struct sbefifo *sbefifo = container_of(inode->i_cdev, struct sbefifo, cdev); | 767 | struct sbefifo *sbefifo = container_of(inode->i_cdev, struct sbefifo, cdev); |
@@ -762,8 +773,8 @@ static int sbefifo_user_open(struct inode *inode, struct file *file) | |||
762 | 773 | ||
763 | file->private_data = user; | 774 | file->private_data = user; |
764 | user->sbefifo = sbefifo; | 775 | user->sbefifo = sbefifo; |
765 | user->pending_cmd = (void *)__get_free_page(GFP_KERNEL); | 776 | user->cmd_page = (void *)__get_free_page(GFP_KERNEL); |
766 | if (!user->pending_cmd) { | 777 | if (!user->cmd_page) { |
767 | kfree(user); | 778 | kfree(user); |
768 | return -ENOMEM; | 779 | return -ENOMEM; |
769 | } | 780 | } |
@@ -816,7 +827,7 @@ static ssize_t sbefifo_user_read(struct file *file, char __user *buf, | |||
816 | /* Extract the response length */ | 827 | /* Extract the response length */ |
817 | rc = len - iov_iter_count(&resp_iter); | 828 | rc = len - iov_iter_count(&resp_iter); |
818 | bail: | 829 | bail: |
819 | user->pending_len = 0; | 830 | sbefifo_release_command(user); |
820 | mutex_unlock(&user->file_lock); | 831 | mutex_unlock(&user->file_lock); |
821 | return rc; | 832 | return rc; |
822 | } | 833 | } |
@@ -831,13 +842,23 @@ static ssize_t sbefifo_user_write(struct file *file, const char __user *buf, | |||
831 | if (!user) | 842 | if (!user) |
832 | return -EINVAL; | 843 | return -EINVAL; |
833 | sbefifo = user->sbefifo; | 844 | sbefifo = user->sbefifo; |
834 | if (len > SBEFIFO_MAX_CMD_LEN) | 845 | if (len > SBEFIFO_MAX_USER_CMD_LEN) |
835 | return -EINVAL; | 846 | return -EINVAL; |
836 | if (len & 3) | 847 | if (len & 3) |
837 | return -EINVAL; | 848 | return -EINVAL; |
838 | 849 | ||
839 | mutex_lock(&user->file_lock); | 850 | mutex_lock(&user->file_lock); |
840 | 851 | ||
852 | /* Can we use the pre-allocate buffer ? If not, allocate */ | ||
853 | if (len <= PAGE_SIZE) | ||
854 | user->pending_cmd = user->cmd_page; | ||
855 | else | ||
856 | user->pending_cmd = vmalloc(len); | ||
857 | if (!user->pending_cmd) { | ||
858 | rc = -ENOMEM; | ||
859 | goto bail; | ||
860 | } | ||
861 | |||
841 | /* Copy the command into the staging buffer */ | 862 | /* Copy the command into the staging buffer */ |
842 | if (copy_from_user(user->pending_cmd, buf, len)) { | 863 | if (copy_from_user(user->pending_cmd, buf, len)) { |
843 | rc = -EFAULT; | 864 | rc = -EFAULT; |
@@ -863,6 +884,9 @@ static ssize_t sbefifo_user_write(struct file *file, const char __user *buf, | |||
863 | /* Update the staging buffer size */ | 884 | /* Update the staging buffer size */ |
864 | user->pending_len = len; | 885 | user->pending_len = len; |
865 | bail: | 886 | bail: |
887 | if (!user->pending_len) | ||
888 | sbefifo_release_command(user); | ||
889 | |||
866 | mutex_unlock(&user->file_lock); | 890 | mutex_unlock(&user->file_lock); |
867 | 891 | ||
868 | /* And that's it, we'll issue the command on a read */ | 892 | /* And that's it, we'll issue the command on a read */ |
@@ -876,7 +900,8 @@ static int sbefifo_user_release(struct inode *inode, struct file *file) | |||
876 | if (!user) | 900 | if (!user) |
877 | return -EINVAL; | 901 | return -EINVAL; |
878 | 902 | ||
879 | free_page((unsigned long)user->pending_cmd); | 903 | sbefifo_release_command(user); |
904 | free_page((unsigned long)user->cmd_page); | ||
880 | kfree(user); | 905 | kfree(user); |
881 | 906 | ||
882 | return 0; | 907 | return 0; |
diff --git a/drivers/fsi/fsi-scom.c b/drivers/fsi/fsi-scom.c index 0f303a700f69..df94021dd9d1 100644 --- a/drivers/fsi/fsi-scom.c +++ b/drivers/fsi/fsi-scom.c | |||
@@ -598,6 +598,7 @@ static int scom_probe(struct device *dev) | |||
598 | kfree(scom); | 598 | kfree(scom); |
599 | return -ENODEV; | 599 | return -ENODEV; |
600 | } | 600 | } |
601 | scom->fsi_dev = fsi_dev; | ||
601 | 602 | ||
602 | /* Create chardev for userspace access */ | 603 | /* Create chardev for userspace access */ |
603 | scom->dev.type = &fsi_cdev_type; | 604 | scom->dev.type = &fsi_cdev_type; |