diff options
| -rw-r--r-- | drivers/char/virtio_console.c | 50 |
1 files changed, 33 insertions, 17 deletions
diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index 5096d92f5b89..d01051060be3 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c | |||
| @@ -233,6 +233,38 @@ static bool port_has_data(struct port *port) | |||
| 233 | return ret; | 233 | return ret; |
| 234 | } | 234 | } |
| 235 | 235 | ||
| 236 | static ssize_t send_buf(struct port *port, void *in_buf, size_t in_count) | ||
| 237 | { | ||
| 238 | struct scatterlist sg[1]; | ||
| 239 | struct virtqueue *out_vq; | ||
| 240 | ssize_t ret; | ||
| 241 | unsigned int len; | ||
| 242 | |||
| 243 | out_vq = port->out_vq; | ||
| 244 | |||
| 245 | sg_init_one(sg, in_buf, in_count); | ||
| 246 | ret = out_vq->vq_ops->add_buf(out_vq, sg, 1, 0, in_buf); | ||
| 247 | |||
| 248 | /* Tell Host to go! */ | ||
| 249 | out_vq->vq_ops->kick(out_vq); | ||
| 250 | |||
| 251 | if (ret < 0) { | ||
| 252 | len = 0; | ||
| 253 | goto fail; | ||
| 254 | } | ||
| 255 | |||
| 256 | /* | ||
| 257 | * Wait till the host acknowledges it pushed out the data we | ||
| 258 | * sent. Also ensure we return to userspace the number of | ||
| 259 | * bytes that were successfully consumed by the host. | ||
| 260 | */ | ||
| 261 | while (!out_vq->vq_ops->get_buf(out_vq, &len)) | ||
| 262 | cpu_relax(); | ||
| 263 | fail: | ||
| 264 | /* We're expected to return the amount of data we wrote */ | ||
| 265 | return len; | ||
| 266 | } | ||
| 267 | |||
| 236 | /* | 268 | /* |
| 237 | * Give out the data that's requested from the buffer that we have | 269 | * Give out the data that's requested from the buffer that we have |
| 238 | * queued up. | 270 | * queued up. |
| @@ -280,10 +312,7 @@ static ssize_t fill_readbuf(struct port *port, char *out_buf, size_t out_count) | |||
| 280 | */ | 312 | */ |
| 281 | static int put_chars(u32 vtermno, const char *buf, int count) | 313 | static int put_chars(u32 vtermno, const char *buf, int count) |
| 282 | { | 314 | { |
| 283 | struct scatterlist sg[1]; | ||
| 284 | struct port *port; | 315 | struct port *port; |
| 285 | struct virtqueue *out_vq; | ||
| 286 | unsigned int len; | ||
| 287 | 316 | ||
| 288 | port = find_port_by_vtermno(vtermno); | 317 | port = find_port_by_vtermno(vtermno); |
| 289 | if (!port) | 318 | if (!port) |
| @@ -292,20 +321,7 @@ static int put_chars(u32 vtermno, const char *buf, int count) | |||
| 292 | if (unlikely(early_put_chars)) | 321 | if (unlikely(early_put_chars)) |
| 293 | return early_put_chars(vtermno, buf, count); | 322 | return early_put_chars(vtermno, buf, count); |
| 294 | 323 | ||
| 295 | out_vq = port->out_vq; | 324 | return send_buf(port, (void *)buf, count); |
| 296 | /* This is a convenient routine to initialize a single-elem sg list */ | ||
| 297 | sg_init_one(sg, buf, count); | ||
| 298 | |||
| 299 | /* This shouldn't fail: if it does, we lose chars. */ | ||
| 300 | if (out_vq->vq_ops->add_buf(out_vq, sg, 1, 0, port) >= 0) { | ||
| 301 | /* Tell Host to go! */ | ||
| 302 | out_vq->vq_ops->kick(out_vq); | ||
| 303 | while (!out_vq->vq_ops->get_buf(out_vq, &len)) | ||
| 304 | cpu_relax(); | ||
| 305 | } | ||
| 306 | |||
| 307 | /* We're expected to return the amount of data we wrote: all of it. */ | ||
| 308 | return count; | ||
| 309 | } | 325 | } |
| 310 | 326 | ||
| 311 | /* | 327 | /* |
