diff options
Diffstat (limited to 'drivers/char')
-rw-r--r-- | drivers/char/virtio_console.c | 266 |
1 files changed, 133 insertions, 133 deletions
diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index e1f92a0c5c5f..237eee26fbc3 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c | |||
@@ -855,6 +855,139 @@ static const struct file_operations port_debugfs_ops = { | |||
855 | .read = debugfs_read, | 855 | .read = debugfs_read, |
856 | }; | 856 | }; |
857 | 857 | ||
858 | static unsigned int fill_queue(struct virtqueue *vq, spinlock_t *lock) | ||
859 | { | ||
860 | struct port_buffer *buf; | ||
861 | unsigned int nr_added_bufs; | ||
862 | int ret; | ||
863 | |||
864 | nr_added_bufs = 0; | ||
865 | do { | ||
866 | buf = alloc_buf(PAGE_SIZE); | ||
867 | if (!buf) | ||
868 | break; | ||
869 | |||
870 | spin_lock_irq(lock); | ||
871 | ret = add_inbuf(vq, buf); | ||
872 | if (ret < 0) { | ||
873 | spin_unlock_irq(lock); | ||
874 | free_buf(buf); | ||
875 | break; | ||
876 | } | ||
877 | nr_added_bufs++; | ||
878 | spin_unlock_irq(lock); | ||
879 | } while (ret > 0); | ||
880 | |||
881 | return nr_added_bufs; | ||
882 | } | ||
883 | |||
884 | static int add_port(struct ports_device *portdev, u32 id) | ||
885 | { | ||
886 | char debugfs_name[16]; | ||
887 | struct port *port; | ||
888 | struct port_buffer *buf; | ||
889 | dev_t devt; | ||
890 | unsigned int nr_added_bufs; | ||
891 | int err; | ||
892 | |||
893 | port = kmalloc(sizeof(*port), GFP_KERNEL); | ||
894 | if (!port) { | ||
895 | err = -ENOMEM; | ||
896 | goto fail; | ||
897 | } | ||
898 | |||
899 | port->portdev = portdev; | ||
900 | port->id = id; | ||
901 | |||
902 | port->name = NULL; | ||
903 | port->inbuf = NULL; | ||
904 | port->cons.hvc = NULL; | ||
905 | |||
906 | port->host_connected = port->guest_connected = false; | ||
907 | |||
908 | port->in_vq = portdev->in_vqs[port->id]; | ||
909 | port->out_vq = portdev->out_vqs[port->id]; | ||
910 | |||
911 | cdev_init(&port->cdev, &port_fops); | ||
912 | |||
913 | devt = MKDEV(portdev->chr_major, id); | ||
914 | err = cdev_add(&port->cdev, devt, 1); | ||
915 | if (err < 0) { | ||
916 | dev_err(&port->portdev->vdev->dev, | ||
917 | "Error %d adding cdev for port %u\n", err, id); | ||
918 | goto free_port; | ||
919 | } | ||
920 | port->dev = device_create(pdrvdata.class, &port->portdev->vdev->dev, | ||
921 | devt, port, "vport%up%u", | ||
922 | port->portdev->drv_index, id); | ||
923 | if (IS_ERR(port->dev)) { | ||
924 | err = PTR_ERR(port->dev); | ||
925 | dev_err(&port->portdev->vdev->dev, | ||
926 | "Error %d creating device for port %u\n", | ||
927 | err, id); | ||
928 | goto free_cdev; | ||
929 | } | ||
930 | |||
931 | spin_lock_init(&port->inbuf_lock); | ||
932 | init_waitqueue_head(&port->waitqueue); | ||
933 | |||
934 | /* Fill the in_vq with buffers so the host can send us data. */ | ||
935 | nr_added_bufs = fill_queue(port->in_vq, &port->inbuf_lock); | ||
936 | if (!nr_added_bufs) { | ||
937 | dev_err(port->dev, "Error allocating inbufs\n"); | ||
938 | err = -ENOMEM; | ||
939 | goto free_device; | ||
940 | } | ||
941 | |||
942 | /* | ||
943 | * If we're not using multiport support, this has to be a console port | ||
944 | */ | ||
945 | if (!use_multiport(port->portdev)) { | ||
946 | err = init_port_console(port); | ||
947 | if (err) | ||
948 | goto free_inbufs; | ||
949 | } | ||
950 | |||
951 | spin_lock_irq(&portdev->ports_lock); | ||
952 | list_add_tail(&port->list, &port->portdev->ports); | ||
953 | spin_unlock_irq(&portdev->ports_lock); | ||
954 | |||
955 | /* | ||
956 | * Tell the Host we're set so that it can send us various | ||
957 | * configuration parameters for this port (eg, port name, | ||
958 | * caching, whether this is a console port, etc.) | ||
959 | */ | ||
960 | send_control_msg(port, VIRTIO_CONSOLE_PORT_READY, 1); | ||
961 | |||
962 | if (pdrvdata.debugfs_dir) { | ||
963 | /* | ||
964 | * Finally, create the debugfs file that we can use to | ||
965 | * inspect a port's state at any time | ||
966 | */ | ||
967 | sprintf(debugfs_name, "vport%up%u", | ||
968 | port->portdev->drv_index, id); | ||
969 | port->debugfs_file = debugfs_create_file(debugfs_name, 0444, | ||
970 | pdrvdata.debugfs_dir, | ||
971 | port, | ||
972 | &port_debugfs_ops); | ||
973 | } | ||
974 | return 0; | ||
975 | |||
976 | free_inbufs: | ||
977 | while ((buf = virtqueue_detach_unused_buf(port->in_vq))) | ||
978 | free_buf(buf); | ||
979 | free_device: | ||
980 | device_destroy(pdrvdata.class, port->dev->devt); | ||
981 | free_cdev: | ||
982 | cdev_del(&port->cdev); | ||
983 | free_port: | ||
984 | kfree(port); | ||
985 | fail: | ||
986 | /* The host might want to notify management sw about port add failure */ | ||
987 | send_control_msg(port, VIRTIO_CONSOLE_PORT_READY, 0); | ||
988 | return err; | ||
989 | } | ||
990 | |||
858 | /* Remove all port-specific data. */ | 991 | /* Remove all port-specific data. */ |
859 | static int remove_port(struct port *port) | 992 | static int remove_port(struct port *port) |
860 | { | 993 | { |
@@ -1093,139 +1226,6 @@ static void config_intr(struct virtio_device *vdev) | |||
1093 | resize_console(find_port_by_id(portdev, 0)); | 1226 | resize_console(find_port_by_id(portdev, 0)); |
1094 | } | 1227 | } |
1095 | 1228 | ||
1096 | static unsigned int fill_queue(struct virtqueue *vq, spinlock_t *lock) | ||
1097 | { | ||
1098 | struct port_buffer *buf; | ||
1099 | unsigned int nr_added_bufs; | ||
1100 | int ret; | ||
1101 | |||
1102 | nr_added_bufs = 0; | ||
1103 | do { | ||
1104 | buf = alloc_buf(PAGE_SIZE); | ||
1105 | if (!buf) | ||
1106 | break; | ||
1107 | |||
1108 | spin_lock_irq(lock); | ||
1109 | ret = add_inbuf(vq, buf); | ||
1110 | if (ret < 0) { | ||
1111 | spin_unlock_irq(lock); | ||
1112 | free_buf(buf); | ||
1113 | break; | ||
1114 | } | ||
1115 | nr_added_bufs++; | ||
1116 | spin_unlock_irq(lock); | ||
1117 | } while (ret > 0); | ||
1118 | |||
1119 | return nr_added_bufs; | ||
1120 | } | ||
1121 | |||
1122 | static int add_port(struct ports_device *portdev, u32 id) | ||
1123 | { | ||
1124 | char debugfs_name[16]; | ||
1125 | struct port *port; | ||
1126 | struct port_buffer *buf; | ||
1127 | dev_t devt; | ||
1128 | unsigned int nr_added_bufs; | ||
1129 | int err; | ||
1130 | |||
1131 | port = kmalloc(sizeof(*port), GFP_KERNEL); | ||
1132 | if (!port) { | ||
1133 | err = -ENOMEM; | ||
1134 | goto fail; | ||
1135 | } | ||
1136 | |||
1137 | port->portdev = portdev; | ||
1138 | port->id = id; | ||
1139 | |||
1140 | port->name = NULL; | ||
1141 | port->inbuf = NULL; | ||
1142 | port->cons.hvc = NULL; | ||
1143 | |||
1144 | port->host_connected = port->guest_connected = false; | ||
1145 | |||
1146 | port->in_vq = portdev->in_vqs[port->id]; | ||
1147 | port->out_vq = portdev->out_vqs[port->id]; | ||
1148 | |||
1149 | cdev_init(&port->cdev, &port_fops); | ||
1150 | |||
1151 | devt = MKDEV(portdev->chr_major, id); | ||
1152 | err = cdev_add(&port->cdev, devt, 1); | ||
1153 | if (err < 0) { | ||
1154 | dev_err(&port->portdev->vdev->dev, | ||
1155 | "Error %d adding cdev for port %u\n", err, id); | ||
1156 | goto free_port; | ||
1157 | } | ||
1158 | port->dev = device_create(pdrvdata.class, &port->portdev->vdev->dev, | ||
1159 | devt, port, "vport%up%u", | ||
1160 | port->portdev->drv_index, id); | ||
1161 | if (IS_ERR(port->dev)) { | ||
1162 | err = PTR_ERR(port->dev); | ||
1163 | dev_err(&port->portdev->vdev->dev, | ||
1164 | "Error %d creating device for port %u\n", | ||
1165 | err, id); | ||
1166 | goto free_cdev; | ||
1167 | } | ||
1168 | |||
1169 | spin_lock_init(&port->inbuf_lock); | ||
1170 | init_waitqueue_head(&port->waitqueue); | ||
1171 | |||
1172 | /* Fill the in_vq with buffers so the host can send us data. */ | ||
1173 | nr_added_bufs = fill_queue(port->in_vq, &port->inbuf_lock); | ||
1174 | if (!nr_added_bufs) { | ||
1175 | dev_err(port->dev, "Error allocating inbufs\n"); | ||
1176 | err = -ENOMEM; | ||
1177 | goto free_device; | ||
1178 | } | ||
1179 | |||
1180 | /* | ||
1181 | * If we're not using multiport support, this has to be a console port | ||
1182 | */ | ||
1183 | if (!use_multiport(port->portdev)) { | ||
1184 | err = init_port_console(port); | ||
1185 | if (err) | ||
1186 | goto free_inbufs; | ||
1187 | } | ||
1188 | |||
1189 | spin_lock_irq(&portdev->ports_lock); | ||
1190 | list_add_tail(&port->list, &port->portdev->ports); | ||
1191 | spin_unlock_irq(&portdev->ports_lock); | ||
1192 | |||
1193 | /* | ||
1194 | * Tell the Host we're set so that it can send us various | ||
1195 | * configuration parameters for this port (eg, port name, | ||
1196 | * caching, whether this is a console port, etc.) | ||
1197 | */ | ||
1198 | send_control_msg(port, VIRTIO_CONSOLE_PORT_READY, 1); | ||
1199 | |||
1200 | if (pdrvdata.debugfs_dir) { | ||
1201 | /* | ||
1202 | * Finally, create the debugfs file that we can use to | ||
1203 | * inspect a port's state at any time | ||
1204 | */ | ||
1205 | sprintf(debugfs_name, "vport%up%u", | ||
1206 | port->portdev->drv_index, id); | ||
1207 | port->debugfs_file = debugfs_create_file(debugfs_name, 0444, | ||
1208 | pdrvdata.debugfs_dir, | ||
1209 | port, | ||
1210 | &port_debugfs_ops); | ||
1211 | } | ||
1212 | return 0; | ||
1213 | |||
1214 | free_inbufs: | ||
1215 | while ((buf = virtqueue_detach_unused_buf(port->in_vq))) | ||
1216 | free_buf(buf); | ||
1217 | free_device: | ||
1218 | device_destroy(pdrvdata.class, port->dev->devt); | ||
1219 | free_cdev: | ||
1220 | cdev_del(&port->cdev); | ||
1221 | free_port: | ||
1222 | kfree(port); | ||
1223 | fail: | ||
1224 | /* The host might want to notify management sw about port add failure */ | ||
1225 | send_control_msg(port, VIRTIO_CONSOLE_PORT_READY, 0); | ||
1226 | return err; | ||
1227 | } | ||
1228 | |||
1229 | static int init_vqs(struct ports_device *portdev) | 1229 | static int init_vqs(struct ports_device *portdev) |
1230 | { | 1230 | { |
1231 | vq_callback_t **io_callbacks; | 1231 | vq_callback_t **io_callbacks; |