diff options
| -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; |
