Blame view
drivers/char/virtio_console.c
56.5 KB
a23ea9247 virtio: console: ... |
1 2 |
/* * Copyright (C) 2006, 2007, 2009 Rusty Russell, IBM Corporation |
5084f8930 virtio: console: ... |
3 4 |
* Copyright (C) 2009, 2010, 2011 Red Hat, Inc. * Copyright (C) 2009, 2010, 2011 Amit Shah <amit.shah@redhat.com> |
31610434b Virtio console dr... |
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ |
fb08bd274 virtio: console: ... |
20 |
#include <linux/cdev.h> |
d99393eff virtio: console: ... |
21 |
#include <linux/debugfs.h> |
5e38483b3 virtio: console: ... |
22 |
#include <linux/completion.h> |
fb08bd274 virtio: console: ... |
23 |
#include <linux/device.h> |
31610434b Virtio console dr... |
24 |
#include <linux/err.h> |
a08fa92d1 virtio: console: ... |
25 |
#include <linux/freezer.h> |
2030fa496 virtio: console: ... |
26 |
#include <linux/fs.h> |
eb5e89fc7 virtio/console: A... |
27 28 |
#include <linux/splice.h> #include <linux/pagemap.h> |
31610434b Virtio console dr... |
29 |
#include <linux/init.h> |
38edf58d7 virtio: console: ... |
30 |
#include <linux/list.h> |
2030fa496 virtio: console: ... |
31 32 |
#include <linux/poll.h> #include <linux/sched.h> |
5a0e3ad6a include cleanup: ... |
33 |
#include <linux/slab.h> |
38edf58d7 virtio: console: ... |
34 |
#include <linux/spinlock.h> |
31610434b Virtio console dr... |
35 36 |
#include <linux/virtio.h> #include <linux/virtio_console.h> |
2030fa496 virtio: console: ... |
37 |
#include <linux/wait.h> |
17634ba25 virtio: console: ... |
38 |
#include <linux/workqueue.h> |
c22405c98 drivers/char: Add... |
39 |
#include <linux/module.h> |
1b6370463 virtio_console: A... |
40 |
#include <linux/dma-mapping.h> |
51df0acc3 virtio: console: ... |
41 |
#include "../tty/hvc/hvc_console.h" |
31610434b Virtio console dr... |
42 |
|
1b6370463 virtio_console: A... |
43 |
#define is_rproc_enabled IS_ENABLED(CONFIG_REMOTEPROC) |
38edf58d7 virtio: console: ... |
44 45 46 47 48 49 50 51 52 |
/* * This is a global struct for storing common data for all the devices * this driver handles. * * Mainly, it has a linked list for all the consoles in one place so * that callbacks from hvc for get_chars(), put_chars() work properly * across multiple devices and multiple ports per device. */ struct ports_driver_data { |
fb08bd274 virtio: console: ... |
53 54 |
/* Used for registering chardevs */ struct class *class; |
d99393eff virtio: console: ... |
55 56 |
/* Used for exporting per-port information to debugfs */ struct dentry *debugfs_dir; |
6bdf2afd0 virtio: console: ... |
57 58 |
/* List of all the devices we're handling */ struct list_head portdevs; |
d8a02bd58 virtio: console: ... |
59 60 61 62 63 64 65 66 67 68 69 |
/* * This is used to keep track of the number of hvc consoles * spawned by this driver. This number is given as the first * argument to hvc_alloc(). To correctly map an initial * console spawned via hvc_instantiate to the console being * hooked up via hvc_alloc, we need to pass the same vtermno. * * We also just assume the first console being initialised was * the first one that got used as the initial console. */ unsigned int next_vtermno; |
38edf58d7 virtio: console: ... |
70 71 72 73 |
/* All the console devices handled by this driver */ struct list_head consoles; }; static struct ports_driver_data pdrvdata; |
3826835ab virtio_console: m... |
74 75 |
static DEFINE_SPINLOCK(pdrvdata_lock); static DECLARE_COMPLETION(early_console_added); |
38edf58d7 virtio: console: ... |
76 |
|
4f23c573c virtio: console: ... |
77 78 79 80 81 82 83 |
/* This struct holds information that's relevant only for console ports */ struct console { /* We'll place all consoles in a list in the pdrvdata struct */ struct list_head list; /* The hvc device associated with this console port */ struct hvc_struct *hvc; |
9778829cf virtio: console: ... |
84 85 |
/* The size of the console */ struct winsize ws; |
4f23c573c virtio: console: ... |
86 87 88 89 90 91 92 93 94 |
/* * This number identifies the number that we used to register * with hvc in hvc_instantiate() and hvc_alloc(); this is the * number passed on by the hvc callbacks to us to * differentiate between the other console ports handled by * this driver */ u32 vtermno; }; |
fdb9a0545 virtio: console: ... |
95 96 97 98 99 100 101 102 103 104 |
struct port_buffer { char *buf; /* size of the buffer in *buf above */ size_t size; /* used length of the buffer */ size_t len; /* offset in the buf from which to consume data */ size_t offset; |
276a3e954 virtio_console: M... |
105 |
|
1b6370463 virtio_console: A... |
106 107 108 109 110 111 112 113 |
/* DMA address of buffer */ dma_addr_t dma; /* Device we got DMA memory from */ struct device *dev; /* List of pending dma buffers to free */ struct list_head list; |
276a3e954 virtio_console: M... |
114 115 116 117 118 |
/* If sgpages == 0 then buf is used */ unsigned int sgpages; /* sg is used if spages > 0. sg must be the last in is struct */ struct scatterlist sg[0]; |
fdb9a0545 virtio: console: ... |
119 |
}; |
17634ba25 virtio: console: ... |
120 121 122 123 124 |
/* * This is a per-device struct that stores data common to all the * ports for that device (vdev->priv). */ struct ports_device { |
6bdf2afd0 virtio: console: ... |
125 126 |
/* Next portdev in the list, head is in the pdrvdata struct */ struct list_head list; |
17634ba25 virtio: console: ... |
127 128 129 130 131 |
/* * Workqueue handlers where we process deferred work after * notification */ struct work_struct control_work; |
eeb8a7e8b virtio_console: a... |
132 |
struct work_struct config_work; |
17634ba25 virtio: console: ... |
133 134 135 136 137 138 139 |
struct list_head ports; /* To protect the list of ports */ spinlock_t ports_lock; /* To protect the vq operations for the control channel */ |
165b1b8bb virtio: console: ... |
140 |
spinlock_t c_ivq_lock; |
9ba5c80b1 virtio: console: ... |
141 |
spinlock_t c_ovq_lock; |
17634ba25 virtio: console: ... |
142 143 |
/* The current config space is stored here */ |
b99fa815d virtio: Revert "v... |
144 |
struct virtio_console_config config; |
17634ba25 virtio: console: ... |
145 146 147 148 149 150 151 152 153 |
/* The virtio device we're associated with */ struct virtio_device *vdev; /* * A couple of virtqueues for the control channel: one for * guest->host transfers, one for host->guest transfers */ struct virtqueue *c_ivq, *c_ovq; |
5e59d9a1a virtio_console: S... |
154 155 156 157 158 |
/* * A control packet buffer for guest->host requests, protected * by c_ovq_lock. */ struct virtio_console_control cpkt; |
17634ba25 virtio: console: ... |
159 160 |
/* Array of per-port IO virtqueues */ struct virtqueue **in_vqs, **out_vqs; |
fb08bd274 virtio: console: ... |
161 |
|
fb08bd274 virtio: console: ... |
162 163 |
/* Major number for this device. Ports will be created as minors. */ int chr_major; |
17634ba25 virtio: console: ... |
164 |
}; |
17e5b4f20 virtio: console: ... |
165 166 167 |
struct port_stats { unsigned long bytes_sent, bytes_received, bytes_discarded; }; |
1c85bf354 virtio: console: ... |
168 |
/* This struct holds the per-port data */ |
21206ede8 virtio: console: ... |
169 |
struct port { |
17634ba25 virtio: console: ... |
170 171 |
/* Next port in the list, head is in the ports_device */ struct list_head list; |
1c85bf354 virtio: console: ... |
172 173 |
/* Pointer to the parent virtio_console device */ struct ports_device *portdev; |
fdb9a0545 virtio: console: ... |
174 175 176 |
/* The current buffer from which data has to be fed to readers */ struct port_buffer *inbuf; |
21206ede8 virtio: console: ... |
177 |
|
203baab8b virtio: console: ... |
178 179 180 181 182 183 |
/* * To protect the operations on the in_vq associated with this * port. Has to be a spinlock because it can be called from * interrupt context (get_char()). */ spinlock_t inbuf_lock; |
cdfadfc1a virtio: console: ... |
184 185 |
/* Protect the operations on the out_vq. */ spinlock_t outvq_lock; |
1c85bf354 virtio: console: ... |
186 187 |
/* The IO vqs for this port */ struct virtqueue *in_vq, *out_vq; |
d99393eff virtio: console: ... |
188 189 |
/* File in the debugfs directory that exposes this port's information */ struct dentry *debugfs_file; |
4f23c573c virtio: console: ... |
190 |
/* |
17e5b4f20 virtio: console: ... |
191 192 193 194 195 196 197 |
* Keep count of the bytes sent, received and discarded for * this port for accounting and debugging purposes. These * counts are not reset across port open / close events. */ struct port_stats stats; /* |
4f23c573c virtio: console: ... |
198 199 200 201 |
* The entries in this struct will be valid if this port is * hooked up to an hvc console */ struct console cons; |
17634ba25 virtio: console: ... |
202 |
|
fb08bd274 virtio: console: ... |
203 |
/* Each port associates with a separate char device */ |
d22a69892 virtio: console: ... |
204 |
struct cdev *cdev; |
fb08bd274 virtio: console: ... |
205 |
struct device *dev; |
b353a6b82 virtio: console: ... |
206 207 |
/* Reference-counting to handle port hot-unplugs and file operations */ struct kref kref; |
2030fa496 virtio: console: ... |
208 209 |
/* A waitqueue for poll() or blocking read operations */ wait_queue_head_t waitqueue; |
431edb8a8 virtio: console: ... |
210 211 |
/* The 'name' of the port that we expose via sysfs properties */ char *name; |
3eae0adea virtio: console: ... |
212 213 |
/* We can notify apps of host connect / disconnect events via SIGIO */ struct fasync_struct *async_queue; |
17634ba25 virtio: console: ... |
214 215 |
/* The 'id' to identify the port with the Host */ u32 id; |
2030fa496 virtio: console: ... |
216 |
|
cdfadfc1a virtio: console: ... |
217 |
bool outvq_full; |
2030fa496 virtio: console: ... |
218 219 |
/* Is the host device open */ bool host_connected; |
3c7969ccb virtio: console: ... |
220 221 222 |
/* We should allow only one process to open a port */ bool guest_connected; |
21206ede8 virtio: console: ... |
223 |
}; |
31610434b Virtio console dr... |
224 |
|
971f33900 virtio: console: ... |
225 226 |
/* This is the very early arch-specified put chars function. */ static int (*early_put_chars)(u32, const char *, int); |
38edf58d7 virtio: console: ... |
227 228 229 |
static struct port *find_port_by_vtermno(u32 vtermno) { struct port *port; |
4f23c573c virtio: console: ... |
230 |
struct console *cons; |
38edf58d7 virtio: console: ... |
231 232 233 |
unsigned long flags; spin_lock_irqsave(&pdrvdata_lock, flags); |
4f23c573c virtio: console: ... |
234 235 236 |
list_for_each_entry(cons, &pdrvdata.consoles, list) { if (cons->vtermno == vtermno) { port = container_of(cons, struct port, cons); |
38edf58d7 virtio: console: ... |
237 |
goto out; |
4f23c573c virtio: console: ... |
238 |
} |
38edf58d7 virtio: console: ... |
239 240 241 242 243 244 |
} port = NULL; out: spin_unlock_irqrestore(&pdrvdata_lock, flags); return port; } |
04950cdf0 virtio: console: ... |
245 246 247 248 249 250 251 |
static struct port *find_port_by_devt_in_portdev(struct ports_device *portdev, dev_t dev) { struct port *port; unsigned long flags; spin_lock_irqsave(&portdev->ports_lock, flags); |
057b82be3 virtio: console: ... |
252 253 254 |
list_for_each_entry(port, &portdev->ports, list) { if (port->cdev->dev == dev) { kref_get(&port->kref); |
04950cdf0 virtio: console: ... |
255 |
goto out; |
057b82be3 virtio: console: ... |
256 257 |
} } |
04950cdf0 virtio: console: ... |
258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 |
port = NULL; out: spin_unlock_irqrestore(&portdev->ports_lock, flags); return port; } static struct port *find_port_by_devt(dev_t dev) { struct ports_device *portdev; struct port *port; unsigned long flags; spin_lock_irqsave(&pdrvdata_lock, flags); list_for_each_entry(portdev, &pdrvdata.portdevs, list) { port = find_port_by_devt_in_portdev(portdev, dev); if (port) goto out; } port = NULL; out: spin_unlock_irqrestore(&pdrvdata_lock, flags); return port; } |
17634ba25 virtio: console: ... |
282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 |
static struct port *find_port_by_id(struct ports_device *portdev, u32 id) { struct port *port; unsigned long flags; spin_lock_irqsave(&portdev->ports_lock, flags); list_for_each_entry(port, &portdev->ports, list) if (port->id == id) goto out; port = NULL; out: spin_unlock_irqrestore(&portdev->ports_lock, flags); return port; } |
203baab8b virtio: console: ... |
297 298 299 300 |
static struct port *find_port_by_vq(struct ports_device *portdev, struct virtqueue *vq) { struct port *port; |
203baab8b virtio: console: ... |
301 |
unsigned long flags; |
17634ba25 virtio: console: ... |
302 303 |
spin_lock_irqsave(&portdev->ports_lock, flags); list_for_each_entry(port, &portdev->ports, list) |
203baab8b virtio: console: ... |
304 305 |
if (port->in_vq == vq || port->out_vq == vq) goto out; |
203baab8b virtio: console: ... |
306 307 |
port = NULL; out: |
17634ba25 virtio: console: ... |
308 |
spin_unlock_irqrestore(&portdev->ports_lock, flags); |
203baab8b virtio: console: ... |
309 310 |
return port; } |
17634ba25 virtio: console: ... |
311 312 313 314 315 316 |
static bool is_console_port(struct port *port) { if (port->cons.hvc) return true; return false; } |
1b6370463 virtio_console: A... |
317 318 319 320 |
static bool is_rproc_serial(const struct virtio_device *vdev) { return is_rproc_enabled && vdev->id.device == VIRTIO_ID_RPROC_SERIAL; } |
17634ba25 virtio: console: ... |
321 322 323 324 325 326 327 |
static inline bool use_multiport(struct ports_device *portdev) { /* * This condition can be true when put_chars is called from * early_init */ if (!portdev->vdev) |
f580d730c virtio_console: U... |
328 |
return false; |
e16e12be3 virtio: use u32, ... |
329 |
return __virtio_test_bit(portdev->vdev, VIRTIO_CONSOLE_F_MULTIPORT); |
17634ba25 virtio: console: ... |
330 |
} |
1b6370463 virtio_console: A... |
331 332 333 334 |
static DEFINE_SPINLOCK(dma_bufs_lock); static LIST_HEAD(pending_free_dma_bufs); static void free_buf(struct port_buffer *buf, bool can_sleep) |
fdb9a0545 virtio: console: ... |
335 |
{ |
276a3e954 virtio_console: M... |
336 |
unsigned int i; |
276a3e954 virtio_console: M... |
337 338 339 340 341 342 |
for (i = 0; i < buf->sgpages; i++) { struct page *page = sg_page(&buf->sg[i]); if (!page) break; put_page(page); } |
1b6370463 virtio_console: A... |
343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 |
if (!buf->dev) { kfree(buf->buf); } else if (is_rproc_enabled) { unsigned long flags; /* dma_free_coherent requires interrupts to be enabled. */ if (!can_sleep) { /* queue up dma-buffers to be freed later */ spin_lock_irqsave(&dma_bufs_lock, flags); list_add_tail(&buf->list, &pending_free_dma_bufs); spin_unlock_irqrestore(&dma_bufs_lock, flags); return; } dma_free_coherent(buf->dev, buf->size, buf->buf, buf->dma); /* Release device refcnt and allow it to be freed */ put_device(buf->dev); } |
fdb9a0545 virtio: console: ... |
361 362 |
kfree(buf); } |
1b6370463 virtio_console: A... |
363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 |
static void reclaim_dma_bufs(void) { unsigned long flags; struct port_buffer *buf, *tmp; LIST_HEAD(tmp_list); if (list_empty(&pending_free_dma_bufs)) return; /* Create a copy of the pending_free_dma_bufs while holding the lock */ spin_lock_irqsave(&dma_bufs_lock, flags); list_cut_position(&tmp_list, &pending_free_dma_bufs, pending_free_dma_bufs.prev); spin_unlock_irqrestore(&dma_bufs_lock, flags); /* Release the dma buffers, without irqs enabled */ list_for_each_entry_safe(buf, tmp, &tmp_list, list) { list_del(&buf->list); free_buf(buf, true); } } |
276a3e954 virtio_console: M... |
384 385 |
static struct port_buffer *alloc_buf(struct virtqueue *vq, size_t buf_size, int pages) |
fdb9a0545 virtio: console: ... |
386 387 |
{ struct port_buffer *buf; |
1b6370463 virtio_console: A... |
388 |
reclaim_dma_bufs(); |
276a3e954 virtio_console: M... |
389 390 391 392 393 394 |
/* * Allocate buffer and the sg list. The sg list array is allocated * directly after the port_buffer struct. */ buf = kmalloc(sizeof(*buf) + sizeof(struct scatterlist) * pages, GFP_KERNEL); |
fdb9a0545 virtio: console: ... |
395 396 |
if (!buf) goto fail; |
276a3e954 virtio_console: M... |
397 398 399 |
buf->sgpages = pages; if (pages > 0) { |
1b6370463 virtio_console: A... |
400 |
buf->dev = NULL; |
276a3e954 virtio_console: M... |
401 402 403 |
buf->buf = NULL; return buf; } |
1b6370463 virtio_console: A... |
404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 |
if (is_rproc_serial(vq->vdev)) { /* * Allocate DMA memory from ancestor. When a virtio * device is created by remoteproc, the DMA memory is * associated with the grandparent device: * vdev => rproc => platform-dev. * The code here would have been less quirky if * DMA_MEMORY_INCLUDES_CHILDREN had been supported * in dma-coherent.c */ if (!vq->vdev->dev.parent || !vq->vdev->dev.parent->parent) goto free_buf; buf->dev = vq->vdev->dev.parent->parent; /* Increase device refcnt to avoid freeing it */ get_device(buf->dev); buf->buf = dma_alloc_coherent(buf->dev, buf_size, &buf->dma, GFP_KERNEL); } else { buf->dev = NULL; buf->buf = kmalloc(buf_size, GFP_KERNEL); } |
fdb9a0545 virtio: console: ... |
426 427 428 429 430 431 432 433 434 435 436 437 |
if (!buf->buf) goto free_buf; buf->len = 0; buf->offset = 0; buf->size = buf_size; return buf; free_buf: kfree(buf); fail: return NULL; } |
a3cde4490 virtio: console: ... |
438 |
/* Callers should take appropriate locks */ |
defde6699 virtio: console: ... |
439 |
static struct port_buffer *get_inbuf(struct port *port) |
a3cde4490 virtio: console: ... |
440 441 |
{ struct port_buffer *buf; |
a3cde4490 virtio: console: ... |
442 |
unsigned int len; |
d25a9ddae virtio: console: ... |
443 444 445 446 |
if (port->inbuf) return port->inbuf; buf = virtqueue_get_buf(port->in_vq, &len); |
a3cde4490 virtio: console: ... |
447 448 449 |
if (buf) { buf->len = len; buf->offset = 0; |
17e5b4f20 virtio: console: ... |
450 |
port->stats.bytes_received += len; |
a3cde4490 virtio: console: ... |
451 452 453 |
} return buf; } |
a23ea9247 virtio: console: ... |
454 |
/* |
e27b51980 virtio: console: ... |
455 456 457 458 459 |
* Create a scatter-gather list representing our input buffer and put * it in the queue. * * Callers should take appropriate locks. */ |
203baab8b virtio: console: ... |
460 |
static int add_inbuf(struct virtqueue *vq, struct port_buffer *buf) |
e27b51980 virtio: console: ... |
461 462 |
{ struct scatterlist sg[1]; |
203baab8b virtio: console: ... |
463 |
int ret; |
1c85bf354 virtio: console: ... |
464 |
|
e27b51980 virtio: console: ... |
465 |
sg_init_one(sg, buf->buf, buf->size); |
6797999d9 virtio_console: u... |
466 |
ret = virtqueue_add_inbuf(vq, sg, 1, buf, GFP_ATOMIC); |
505b0451c virtio_console: u... |
467 |
virtqueue_kick(vq); |
49e86f168 virtio: console: ... |
468 469 |
if (!ret) ret = vq->num_free; |
203baab8b virtio: console: ... |
470 471 |
return ret; } |
88f251ac5 virtio: console: ... |
472 473 474 475 |
/* Discard any unread data this port has. Callers lockers. */ static void discard_port_data(struct port *port) { struct port_buffer *buf; |
2d24cdaa6 virtio: console: ... |
476 |
unsigned int err; |
88f251ac5 virtio: console: ... |
477 |
|
d7a62cd03 virtio: console: ... |
478 479 480 481 |
if (!port->portdev) { /* Device has been unplugged. vqs are already gone. */ return; } |
2d24cdaa6 virtio: console: ... |
482 |
buf = get_inbuf(port); |
88f251ac5 virtio: console: ... |
483 |
|
ce072a0ce virtio: console: ... |
484 |
err = 0; |
d69335619 virtio: console: ... |
485 |
while (buf) { |
17e5b4f20 virtio: console: ... |
486 |
port->stats.bytes_discarded += buf->len - buf->offset; |
2d24cdaa6 virtio: console: ... |
487 |
if (add_inbuf(port->in_vq, buf) < 0) { |
ce072a0ce virtio: console: ... |
488 |
err++; |
1b6370463 virtio_console: A... |
489 |
free_buf(buf, false); |
d69335619 virtio: console: ... |
490 |
} |
2d24cdaa6 virtio: console: ... |
491 492 |
port->inbuf = NULL; buf = get_inbuf(port); |
88f251ac5 virtio: console: ... |
493 |
} |
ce072a0ce virtio: console: ... |
494 |
if (err) |
d69335619 virtio: console: ... |
495 496 |
dev_warn(port->dev, "Errors adding %d buffers back to vq ", |
ce072a0ce virtio: console: ... |
497 |
err); |
88f251ac5 virtio: console: ... |
498 |
} |
203baab8b virtio: console: ... |
499 500 501 502 |
static bool port_has_data(struct port *port) { unsigned long flags; bool ret; |
d25a9ddae virtio: console: ... |
503 |
ret = false; |
203baab8b virtio: console: ... |
504 |
spin_lock_irqsave(&port->inbuf_lock, flags); |
d69335619 virtio: console: ... |
505 |
port->inbuf = get_inbuf(port); |
d25a9ddae virtio: console: ... |
506 |
if (port->inbuf) |
d69335619 virtio: console: ... |
507 |
ret = true; |
d25a9ddae virtio: console: ... |
508 |
|
203baab8b virtio: console: ... |
509 |
spin_unlock_irqrestore(&port->inbuf_lock, flags); |
203baab8b virtio: console: ... |
510 511 |
return ret; } |
3425e706b virtio: console: ... |
512 513 |
static ssize_t __send_control_msg(struct ports_device *portdev, u32 port_id, unsigned int event, unsigned int value) |
17634ba25 virtio: console: ... |
514 515 |
{ struct scatterlist sg[1]; |
17634ba25 virtio: console: ... |
516 |
struct virtqueue *vq; |
604b2ad7c virtio: console: ... |
517 |
unsigned int len; |
17634ba25 virtio: console: ... |
518 |
|
3425e706b virtio: console: ... |
519 |
if (!use_multiport(portdev)) |
17634ba25 virtio: console: ... |
520 |
return 0; |
3425e706b virtio: console: ... |
521 |
vq = portdev->c_ovq; |
17634ba25 virtio: console: ... |
522 |
|
9ba5c80b1 virtio: console: ... |
523 |
spin_lock(&portdev->c_ovq_lock); |
5e59d9a1a virtio_console: S... |
524 525 526 527 528 529 530 531 |
portdev->cpkt.id = cpu_to_virtio32(portdev->vdev, port_id); portdev->cpkt.event = cpu_to_virtio16(portdev->vdev, event); portdev->cpkt.value = cpu_to_virtio16(portdev->vdev, value); sg_init_one(sg, &portdev->cpkt, sizeof(struct virtio_console_control)); if (virtqueue_add_outbuf(vq, sg, 1, &portdev->cpkt, GFP_ATOMIC) == 0) { |
505b0451c virtio_console: u... |
532 |
virtqueue_kick(vq); |
40e4dc530 virtio_console: v... |
533 534 |
while (!virtqueue_get_buf(vq, &len) && !virtqueue_is_broken(vq)) |
17634ba25 virtio: console: ... |
535 536 |
cpu_relax(); } |
5e59d9a1a virtio_console: S... |
537 |
|
9ba5c80b1 virtio: console: ... |
538 |
spin_unlock(&portdev->c_ovq_lock); |
17634ba25 virtio: console: ... |
539 540 |
return 0; } |
3425e706b virtio: console: ... |
541 542 543 |
static ssize_t send_control_msg(struct port *port, unsigned int event, unsigned int value) { |
84ec06c59 virtio: console: ... |
544 545 546 547 |
/* Did the port get unplugged before userspace closed it? */ if (port->portdev) return __send_control_msg(port->portdev, port->id, event, value); return 0; |
3425e706b virtio: console: ... |
548 |
} |
eb5e89fc7 virtio/console: A... |
549 |
|
cdfadfc1a virtio: console: ... |
550 551 552 |
/* Callers must take the port->outvq_lock */ static void reclaim_consumed_buffers(struct port *port) { |
276a3e954 virtio_console: M... |
553 |
struct port_buffer *buf; |
cdfadfc1a virtio: console: ... |
554 |
unsigned int len; |
d7a62cd03 virtio: console: ... |
555 556 557 558 |
if (!port->portdev) { /* Device has been unplugged. vqs are already gone. */ return; } |
276a3e954 virtio_console: M... |
559 |
while ((buf = virtqueue_get_buf(port->out_vq, &len))) { |
1b6370463 virtio_console: A... |
560 |
free_buf(buf, false); |
cdfadfc1a virtio: console: ... |
561 562 563 |
port->outvq_full = false; } } |
eb5e89fc7 virtio/console: A... |
564 565 |
static ssize_t __send_to_port(struct port *port, struct scatterlist *sg, int nents, size_t in_count, |
276a3e954 virtio_console: M... |
566 |
void *data, bool nonblock) |
f997f00bf virtio: console: ... |
567 |
{ |
f997f00bf virtio: console: ... |
568 |
struct virtqueue *out_vq; |
589575a23 virtio: console: ... |
569 |
int err; |
cdfadfc1a virtio: console: ... |
570 |
unsigned long flags; |
f997f00bf virtio: console: ... |
571 572 573 |
unsigned int len; out_vq = port->out_vq; |
cdfadfc1a virtio: console: ... |
574 575 576 |
spin_lock_irqsave(&port->outvq_lock, flags); reclaim_consumed_buffers(port); |
6797999d9 virtio_console: u... |
577 |
err = virtqueue_add_outbuf(out_vq, sg, nents, data, GFP_ATOMIC); |
f997f00bf virtio: console: ... |
578 579 |
/* Tell Host to go! */ |
505b0451c virtio_console: u... |
580 |
virtqueue_kick(out_vq); |
f997f00bf virtio: console: ... |
581 |
|
589575a23 virtio: console: ... |
582 |
if (err) { |
9ff4cfab8 virtio: console m... |
583 |
in_count = 0; |
cdfadfc1a virtio: console: ... |
584 |
goto done; |
f997f00bf virtio: console: ... |
585 |
} |
589575a23 virtio: console: ... |
586 |
if (out_vq->num_free == 0) |
cdfadfc1a virtio: console: ... |
587 588 589 590 591 592 593 |
port->outvq_full = true; if (nonblock) goto done; /* * Wait till the host acknowledges it pushed out the data we |
531295e63 virtio: console: ... |
594 595 596 597 598 599 |
* sent. This is done for data from the hvc_console; the tty * operations are performed with spinlocks held so we can't * sleep here. An alternative would be to copy the data to a * buffer and relax the spinning requirement. The downside is * we need to kmalloc a GFP_ATOMIC buffer each time the * console driver writes something out. |
cdfadfc1a virtio: console: ... |
600 |
*/ |
40e4dc530 virtio_console: v... |
601 602 |
while (!virtqueue_get_buf(out_vq, &len) && !virtqueue_is_broken(out_vq)) |
f997f00bf virtio: console: ... |
603 |
cpu_relax(); |
cdfadfc1a virtio: console: ... |
604 605 |
done: spin_unlock_irqrestore(&port->outvq_lock, flags); |
17e5b4f20 virtio: console: ... |
606 607 |
port->stats.bytes_sent += in_count; |
cdfadfc1a virtio: console: ... |
608 609 610 611 |
/* * We're expected to return the amount of data we wrote -- all * of it */ |
9ff4cfab8 virtio: console m... |
612 |
return in_count; |
f997f00bf virtio: console: ... |
613 |
} |
203baab8b virtio: console: ... |
614 615 616 617 |
/* * Give out the data that's requested from the buffer that we have * queued up. */ |
48b36066b virtio_console: f... |
618 619 |
static ssize_t fill_readbuf(struct port *port, char __user *out_buf, size_t out_count, bool to_user) |
203baab8b virtio: console: ... |
620 621 622 623 624 625 626 627 |
{ struct port_buffer *buf; unsigned long flags; if (!out_count || !port_has_data(port)) return 0; buf = port->inbuf; |
b766ceed5 virtio: console: ... |
628 |
out_count = min(out_count, buf->len - buf->offset); |
203baab8b virtio: console: ... |
629 |
|
b766ceed5 virtio: console: ... |
630 631 632 633 634 635 636 |
if (to_user) { ssize_t ret; ret = copy_to_user(out_buf, buf->buf + buf->offset, out_count); if (ret) return -EFAULT; } else { |
48b36066b virtio_console: f... |
637 638 |
memcpy((__force char *)out_buf, buf->buf + buf->offset, out_count); |
b766ceed5 virtio: console: ... |
639 |
} |
203baab8b virtio: console: ... |
640 |
|
203baab8b virtio: console: ... |
641 642 643 644 645 646 647 648 649 650 651 |
buf->offset += out_count; if (buf->offset == buf->len) { /* * We're done using all the data in this buffer. * Re-queue so that the Host can send us more data. */ spin_lock_irqsave(&port->inbuf_lock, flags); port->inbuf = NULL; if (add_inbuf(port->in_vq, buf) < 0) |
fb08bd274 virtio: console: ... |
652 653 |
dev_warn(port->dev, "failed add_buf "); |
203baab8b virtio: console: ... |
654 655 656 |
spin_unlock_irqrestore(&port->inbuf_lock, flags); } |
b766ceed5 virtio: console: ... |
657 |
/* Return the number of bytes actually copied */ |
203baab8b virtio: console: ... |
658 |
return out_count; |
e27b51980 virtio: console: ... |
659 |
} |
2030fa496 virtio: console: ... |
660 |
/* The condition that must be true for polling to end */ |
60caacd3e virtio: console: ... |
661 |
static bool will_read_block(struct port *port) |
2030fa496 virtio: console: ... |
662 |
{ |
3709ea7ae virtio: console: ... |
663 664 665 666 |
if (!port->guest_connected) { /* Port got hot-unplugged. Let's exit. */ return false; } |
60caacd3e virtio: console: ... |
667 |
return !port_has_data(port) && port->host_connected; |
2030fa496 virtio: console: ... |
668 |
} |
cdfadfc1a virtio: console: ... |
669 670 671 |
static bool will_write_block(struct port *port) { bool ret; |
60e5e0b84 virtio: console: ... |
672 673 674 675 |
if (!port->guest_connected) { /* Port got hot-unplugged. Let's exit. */ return false; } |
cdfadfc1a virtio: console: ... |
676 677 678 679 680 681 682 683 684 685 686 687 688 689 |
if (!port->host_connected) return true; spin_lock_irq(&port->outvq_lock); /* * Check if the Host has consumed any buffers since we last * sent data (this is only applicable for nonblocking ports). */ reclaim_consumed_buffers(port); ret = port->outvq_full; spin_unlock_irq(&port->outvq_lock); return ret; } |
2030fa496 virtio: console: ... |
690 691 692 693 694 695 696 |
static ssize_t port_fops_read(struct file *filp, char __user *ubuf, size_t count, loff_t *offp) { struct port *port; ssize_t ret; port = filp->private_data; |
96f97a839 virtio: console: ... |
697 698 699 |
/* Port is hot-unplugged. */ if (!port->guest_connected) return -ENODEV; |
2030fa496 virtio: console: ... |
700 701 702 703 704 705 706 707 708 709 |
if (!port_has_data(port)) { /* * If nothing's connected on the host just return 0 in * case of list_empty; this tells the userspace app * that there's no connection */ if (!port->host_connected) return 0; if (filp->f_flags & O_NONBLOCK) return -EAGAIN; |
a08fa92d1 virtio: console: ... |
710 711 |
ret = wait_event_freezable(port->waitqueue, !will_read_block(port)); |
2030fa496 virtio: console: ... |
712 713 714 |
if (ret < 0) return ret; } |
96f97a839 virtio: console: ... |
715 |
/* Port got hot-unplugged while we were waiting above. */ |
b3dddb9e6 virtio: console: ... |
716 717 |
if (!port->guest_connected) return -ENODEV; |
2030fa496 virtio: console: ... |
718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 |
/* * We could've received a disconnection message while we were * waiting for more data. * * This check is not clubbed in the if() statement above as we * might receive some data as well as the host could get * disconnected after we got woken up from our wait. So we * really want to give off whatever data we have and only then * check for host_connected. */ if (!port_has_data(port) && !port->host_connected) return 0; return fill_readbuf(port, ubuf, count, true); } |
efe75d24a virtio/console: W... |
733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 |
static int wait_port_writable(struct port *port, bool nonblock) { int ret; if (will_write_block(port)) { if (nonblock) return -EAGAIN; ret = wait_event_freezable(port->waitqueue, !will_write_block(port)); if (ret < 0) return ret; } /* Port got hot-unplugged. */ if (!port->guest_connected) return -ENODEV; return 0; } |
2030fa496 virtio: console: ... |
752 753 754 755 |
static ssize_t port_fops_write(struct file *filp, const char __user *ubuf, size_t count, loff_t *offp) { struct port *port; |
276a3e954 virtio_console: M... |
756 |
struct port_buffer *buf; |
2030fa496 virtio: console: ... |
757 |
ssize_t ret; |
cdfadfc1a virtio: console: ... |
758 |
bool nonblock; |
276a3e954 virtio_console: M... |
759 |
struct scatterlist sg[1]; |
2030fa496 virtio: console: ... |
760 |
|
65745422a virtio: console: ... |
761 762 763 |
/* Userspace could be out to fool us */ if (!count) return 0; |
2030fa496 virtio: console: ... |
764 |
port = filp->private_data; |
cdfadfc1a virtio: console: ... |
765 |
nonblock = filp->f_flags & O_NONBLOCK; |
efe75d24a virtio/console: W... |
766 767 768 |
ret = wait_port_writable(port, nonblock); if (ret < 0) return ret; |
cdfadfc1a virtio: console: ... |
769 |
|
2030fa496 virtio: console: ... |
770 |
count = min((size_t)(32 * 1024), count); |
276a3e954 virtio_console: M... |
771 |
buf = alloc_buf(port->out_vq, count, 0); |
2030fa496 virtio: console: ... |
772 773 |
if (!buf) return -ENOMEM; |
276a3e954 virtio_console: M... |
774 |
ret = copy_from_user(buf->buf, ubuf, count); |
2030fa496 virtio: console: ... |
775 776 777 778 |
if (ret) { ret = -EFAULT; goto free_buf; } |
531295e63 virtio: console: ... |
779 780 781 782 783 784 785 786 |
/* * We now ask send_buf() to not spin for generic ports -- we * can re-use the same code path that non-blocking file * descriptors take for blocking file descriptors since the * wait is already done and we're certain the write will go * through to the host. */ nonblock = true; |
276a3e954 virtio_console: M... |
787 788 |
sg_init_one(sg, buf->buf, count); ret = __send_to_port(port, sg, 1, count, buf, nonblock); |
cdfadfc1a virtio: console: ... |
789 790 791 |
if (nonblock && ret > 0) goto out; |
2030fa496 virtio: console: ... |
792 |
free_buf: |
1b6370463 virtio_console: A... |
793 |
free_buf(buf, true); |
cdfadfc1a virtio: console: ... |
794 |
out: |
2030fa496 virtio: console: ... |
795 796 |
return ret; } |
eb5e89fc7 virtio/console: A... |
797 798 |
struct sg_list { unsigned int n; |
8ca84a50e virtio/console: A... |
799 |
unsigned int size; |
eb5e89fc7 virtio/console: A... |
800 801 802 803 804 805 806 807 |
size_t len; struct scatterlist *sg; }; static int pipe_to_sg(struct pipe_inode_info *pipe, struct pipe_buffer *buf, struct splice_desc *sd) { struct sg_list *sgl = sd->u.data; |
ec8fc8701 virtio/console: A... |
808 |
unsigned int offset, len; |
eb5e89fc7 virtio/console: A... |
809 |
|
8ca84a50e virtio/console: A... |
810 |
if (sgl->n == sgl->size) |
eb5e89fc7 virtio/console: A... |
811 812 813 |
return 0; /* Try lock this page */ |
ca76f5b6b pipe: add pipe_bu... |
814 |
if (pipe_buf_steal(pipe, buf) == 0) { |
eb5e89fc7 virtio/console: A... |
815 816 817 818 819 820 |
/* Get reference and unlock page for moving */ get_page(buf->page); unlock_page(buf->page); len = min(buf->len, sd->len); sg_set_page(&(sgl->sg[sgl->n]), buf->page, len, buf->offset); |
ec8fc8701 virtio/console: A... |
821 822 823 |
} else { /* Failback to copying a page */ struct page *page = alloc_page(GFP_KERNEL); |
c9efe5116 fix a kmap leak i... |
824 |
char *src; |
ec8fc8701 virtio/console: A... |
825 826 827 |
if (!page) return -ENOMEM; |
ec8fc8701 virtio/console: A... |
828 829 830 831 832 833 |
offset = sd->pos & ~PAGE_MASK; len = sd->len; if (len + offset > PAGE_SIZE) len = PAGE_SIZE - offset; |
fbb32750a pipe: kill ->map(... |
834 |
src = kmap_atomic(buf->page); |
c9efe5116 fix a kmap leak i... |
835 |
memcpy(page_address(page) + offset, src + buf->offset, len); |
fbb32750a pipe: kill ->map(... |
836 |
kunmap_atomic(src); |
ec8fc8701 virtio/console: A... |
837 838 |
sg_set_page(&(sgl->sg[sgl->n]), page, len, offset); |
eb5e89fc7 virtio/console: A... |
839 |
} |
ec8fc8701 virtio/console: A... |
840 841 |
sgl->n++; sgl->len += len; |
eb5e89fc7 virtio/console: A... |
842 843 844 845 846 847 848 849 850 851 852 853 |
return len; } /* Faster zero-copy write by splicing */ static ssize_t port_fops_splice_write(struct pipe_inode_info *pipe, struct file *filp, loff_t *ppos, size_t len, unsigned int flags) { struct port *port = filp->private_data; struct sg_list sgl; ssize_t ret; |
276a3e954 virtio_console: M... |
854 |
struct port_buffer *buf; |
eb5e89fc7 virtio/console: A... |
855 856 857 858 859 860 |
struct splice_desc sd = { .total_len = len, .flags = flags, .pos = *ppos, .u.data = &sgl, }; |
1b6370463 virtio_console: A... |
861 862 863 864 865 866 867 868 |
/* * Rproc_serial does not yet support splice. To support splice * pipe_to_sg() must allocate dma-buffers and copy content from * regular pages to dma pages. And alloc_buf and free_buf must * support allocating and freeing such a list of dma-buffers. */ if (is_rproc_serial(port->out_vq->vdev)) return -EINVAL; |
68c034fef virtio/console: Q... |
869 870 871 872 |
/* * pipe->nrbufs == 0 means there are no data to transfer, * so this returns just 0 for no data. */ |
2b4fbf029 virtio/console: A... |
873 874 875 876 877 |
pipe_lock(pipe); if (!pipe->nrbufs) { ret = 0; goto error_out; } |
68c034fef virtio/console: Q... |
878 |
|
efe75d24a virtio/console: W... |
879 880 |
ret = wait_port_writable(port, filp->f_flags & O_NONBLOCK); if (ret < 0) |
2b4fbf029 virtio/console: A... |
881 |
goto error_out; |
efe75d24a virtio/console: W... |
882 |
|
276a3e954 virtio_console: M... |
883 |
buf = alloc_buf(port->out_vq, 0, pipe->nrbufs); |
2b4fbf029 virtio/console: A... |
884 885 886 887 |
if (!buf) { ret = -ENOMEM; goto error_out; } |
276a3e954 virtio_console: M... |
888 |
|
eb5e89fc7 virtio/console: A... |
889 890 |
sgl.n = 0; sgl.len = 0; |
8ca84a50e virtio/console: A... |
891 |
sgl.size = pipe->nrbufs; |
276a3e954 virtio_console: M... |
892 |
sgl.sg = buf->sg; |
8ca84a50e virtio/console: A... |
893 |
sg_init_table(sgl.sg, sgl.size); |
eb5e89fc7 virtio/console: A... |
894 |
ret = __splice_from_pipe(pipe, &sd, pipe_to_sg); |
2b4fbf029 virtio/console: A... |
895 |
pipe_unlock(pipe); |
eb5e89fc7 virtio/console: A... |
896 |
if (likely(ret > 0)) |
276a3e954 virtio_console: M... |
897 |
ret = __send_to_port(port, buf->sg, sgl.n, sgl.len, buf, true); |
eb5e89fc7 virtio/console: A... |
898 |
|
fe5295374 virtio_console: F... |
899 |
if (unlikely(ret <= 0)) |
1b6370463 virtio_console: A... |
900 |
free_buf(buf, true); |
eb5e89fc7 virtio/console: A... |
901 |
return ret; |
2b4fbf029 virtio/console: A... |
902 903 904 905 |
error_out: pipe_unlock(pipe); return ret; |
eb5e89fc7 virtio/console: A... |
906 |
} |
2030fa496 virtio: console: ... |
907 908 909 910 911 912 913 |
static unsigned int port_fops_poll(struct file *filp, poll_table *wait) { struct port *port; unsigned int ret; port = filp->private_data; poll_wait(filp, &port->waitqueue, wait); |
8529a5042 virtio: console: ... |
914 915 916 917 |
if (!port->guest_connected) { /* Port got unplugged */ return POLLHUP; } |
2030fa496 virtio: console: ... |
918 |
ret = 0; |
6df7aadcd virtio: console: ... |
919 |
if (!will_read_block(port)) |
2030fa496 virtio: console: ... |
920 |
ret |= POLLIN | POLLRDNORM; |
cdfadfc1a virtio: console: ... |
921 |
if (!will_write_block(port)) |
2030fa496 virtio: console: ... |
922 923 924 925 926 927 |
ret |= POLLOUT; if (!port->host_connected) ret |= POLLHUP; return ret; } |
b353a6b82 virtio: console: ... |
928 |
static void remove_port(struct kref *kref); |
2030fa496 virtio: console: ... |
929 930 931 932 933 934 935 936 |
static int port_fops_release(struct inode *inode, struct file *filp) { struct port *port; port = filp->private_data; /* Notify host of port being closed */ send_control_msg(port, VIRTIO_CONSOLE_PORT_OPEN, 0); |
88f251ac5 virtio: console: ... |
937 |
spin_lock_irq(&port->inbuf_lock); |
3c7969ccb virtio: console: ... |
938 |
port->guest_connected = false; |
88f251ac5 virtio: console: ... |
939 940 941 |
discard_port_data(port); spin_unlock_irq(&port->inbuf_lock); |
cdfadfc1a virtio: console: ... |
942 943 944 |
spin_lock_irq(&port->outvq_lock); reclaim_consumed_buffers(port); spin_unlock_irq(&port->outvq_lock); |
1b6370463 virtio_console: A... |
945 |
reclaim_dma_bufs(); |
b353a6b82 virtio: console: ... |
946 947 948 949 950 951 952 953 954 |
/* * Locks aren't necessary here as a port can't be opened after * unplug, and if a port isn't unplugged, a kref would already * exist for the port. Plus, taking ports_lock here would * create a dependency on other locks taken by functions * inside remove_port if we're the last holder of the port, * creating many problems. */ kref_put(&port->kref, remove_port); |
2030fa496 virtio: console: ... |
955 956 957 958 959 960 961 |
return 0; } static int port_fops_open(struct inode *inode, struct file *filp) { struct cdev *cdev = inode->i_cdev; struct port *port; |
8ad37e83c virtio: console: ... |
962 |
int ret; |
2030fa496 virtio: console: ... |
963 |
|
057b82be3 virtio: console: ... |
964 |
/* We get the port with a kref here */ |
04950cdf0 virtio: console: ... |
965 |
port = find_port_by_devt(cdev->dev); |
671bdea2b virtio: console: ... |
966 967 968 969 |
if (!port) { /* Port was unplugged before we could proceed */ return -ENXIO; } |
2030fa496 virtio: console: ... |
970 971 972 973 974 975 |
filp->private_data = port; /* * Don't allow opening of console port devices -- that's done * via /dev/hvc */ |
8ad37e83c virtio: console: ... |
976 977 978 979 |
if (is_console_port(port)) { ret = -ENXIO; goto out; } |
2030fa496 virtio: console: ... |
980 |
|
3c7969ccb virtio: console: ... |
981 982 983 984 |
/* Allow only one process to open a particular port at a time */ spin_lock_irq(&port->inbuf_lock); if (port->guest_connected) { spin_unlock_irq(&port->inbuf_lock); |
74ff582cd virtio: console: ... |
985 |
ret = -EBUSY; |
8ad37e83c virtio: console: ... |
986 |
goto out; |
3c7969ccb virtio: console: ... |
987 988 989 990 |
} port->guest_connected = true; spin_unlock_irq(&port->inbuf_lock); |
cdfadfc1a virtio: console: ... |
991 992 993 994 995 996 997 998 |
spin_lock_irq(&port->outvq_lock); /* * There might be a chance that we missed reclaiming a few * buffers in the window of the port getting previously closed * and opening now. */ reclaim_consumed_buffers(port); spin_unlock_irq(&port->outvq_lock); |
299fb61c0 virtio: console: ... |
999 |
nonseekable_open(inode, filp); |
2030fa496 virtio: console: ... |
1000 1001 1002 1003 |
/* Notify host of port being opened */ send_control_msg(filp->private_data, VIRTIO_CONSOLE_PORT_OPEN, 1); return 0; |
8ad37e83c virtio: console: ... |
1004 |
out: |
b353a6b82 virtio: console: ... |
1005 |
kref_put(&port->kref, remove_port); |
8ad37e83c virtio: console: ... |
1006 |
return ret; |
2030fa496 virtio: console: ... |
1007 |
} |
3eae0adea virtio: console: ... |
1008 1009 1010 1011 1012 1013 1014 |
static int port_fops_fasync(int fd, struct file *filp, int mode) { struct port *port; port = filp->private_data; return fasync_helper(fd, filp, mode, &port->async_queue); } |
2030fa496 virtio: console: ... |
1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 |
/* * The file operations that we support: programs in the guest can open * a console device, read from it, write to it, poll for data and * close it. The devices are at * /dev/vport<device number>p<port number> */ static const struct file_operations port_fops = { .owner = THIS_MODULE, .open = port_fops_open, .read = port_fops_read, .write = port_fops_write, |
eb5e89fc7 virtio/console: A... |
1026 |
.splice_write = port_fops_splice_write, |
2030fa496 virtio: console: ... |
1027 1028 |
.poll = port_fops_poll, .release = port_fops_release, |
3eae0adea virtio: console: ... |
1029 |
.fasync = port_fops_fasync, |
299fb61c0 virtio: console: ... |
1030 |
.llseek = no_llseek, |
2030fa496 virtio: console: ... |
1031 |
}; |
e27b51980 virtio: console: ... |
1032 |
/* |
a23ea9247 virtio: console: ... |
1033 |
* The put_chars() callback is pretty straightforward. |
31610434b Virtio console dr... |
1034 |
* |
a23ea9247 virtio: console: ... |
1035 1036 1037 1038 1039 |
* We turn the characters into a scatter-gather list, add it to the * output queue and then kick the Host. Then we sit here waiting for * it to finish: inefficient in theory, but in practice * implementations will do it immediately (lguest's Launcher does). */ |
31610434b Virtio console dr... |
1040 1041 |
static int put_chars(u32 vtermno, const char *buf, int count) { |
21206ede8 virtio: console: ... |
1042 |
struct port *port; |
276a3e954 virtio_console: M... |
1043 |
struct scatterlist sg[1]; |
38edf58d7 virtio: console: ... |
1044 |
|
162a689a1 virtio: console: ... |
1045 1046 |
if (unlikely(early_put_chars)) return early_put_chars(vtermno, buf, count); |
38edf58d7 virtio: console: ... |
1047 1048 |
port = find_port_by_vtermno(vtermno); if (!port) |
6dc69f970 virtio: console: ... |
1049 |
return -EPIPE; |
31610434b Virtio console dr... |
1050 |
|
276a3e954 virtio_console: M... |
1051 1052 |
sg_init_one(sg, buf, count); return __send_to_port(port, sg, 1, count, (void *)buf, false); |
31610434b Virtio console dr... |
1053 |
} |
a23ea9247 virtio: console: ... |
1054 |
/* |
a23ea9247 virtio: console: ... |
1055 1056 |
* get_chars() is the callback from the hvc_console infrastructure * when an interrupt is received. |
31610434b Virtio console dr... |
1057 |
* |
203baab8b virtio: console: ... |
1058 1059 |
* We call out to fill_readbuf that gets us the required data from the * buffers that are queued up. |
a23ea9247 virtio: console: ... |
1060 |
*/ |
31610434b Virtio console dr... |
1061 1062 |
static int get_chars(u32 vtermno, char *buf, int count) { |
21206ede8 virtio: console: ... |
1063 |
struct port *port; |
6dc69f970 virtio: console: ... |
1064 1065 1066 |
/* If we've not set up the port yet, we have no input to give. */ if (unlikely(early_put_chars)) return 0; |
38edf58d7 virtio: console: ... |
1067 1068 |
port = find_port_by_vtermno(vtermno); if (!port) |
6dc69f970 virtio: console: ... |
1069 |
return -EPIPE; |
21206ede8 virtio: console: ... |
1070 |
|
31610434b Virtio console dr... |
1071 |
/* If we don't have an input queue yet, we can't get input. */ |
21206ede8 virtio: console: ... |
1072 |
BUG_ON(!port->in_vq); |
31610434b Virtio console dr... |
1073 |
|
48b36066b virtio_console: f... |
1074 |
return fill_readbuf(port, (__force char __user *)buf, count, false); |
31610434b Virtio console dr... |
1075 |
} |
31610434b Virtio console dr... |
1076 |
|
cb06e3676 virtio: console: ... |
1077 |
static void resize_console(struct port *port) |
c29834584 virtio_console: s... |
1078 |
{ |
cb06e3676 virtio: console: ... |
1079 |
struct virtio_device *vdev; |
c29834584 virtio_console: s... |
1080 |
|
2de16a493 virtio: console: ... |
1081 |
/* The port could have been hot-unplugged */ |
9778829cf virtio: console: ... |
1082 |
if (!port || !is_console_port(port)) |
2de16a493 virtio: console: ... |
1083 |
return; |
cb06e3676 virtio: console: ... |
1084 |
vdev = port->portdev->vdev; |
1b6370463 virtio_console: A... |
1085 1086 1087 1088 |
/* Don't test F_SIZE at all if we're rproc: not a valid feature! */ if (!is_rproc_serial(vdev) && virtio_has_feature(vdev, VIRTIO_CONSOLE_F_SIZE)) |
9778829cf virtio: console: ... |
1089 |
hvc_resize(port->cons.hvc, port->cons.ws); |
c29834584 virtio_console: s... |
1090 |
} |
38edf58d7 virtio: console: ... |
1091 |
/* We set the configuration at this point, since we now have a tty */ |
91fcad19d virtio_console: u... |
1092 1093 |
static int notifier_add_vio(struct hvc_struct *hp, int data) { |
38edf58d7 virtio: console: ... |
1094 1095 1096 1097 1098 |
struct port *port; port = find_port_by_vtermno(hp->vtermno); if (!port) return -EINVAL; |
91fcad19d virtio_console: u... |
1099 |
hp->irq_requested = 1; |
cb06e3676 virtio: console: ... |
1100 |
resize_console(port); |
c29834584 virtio_console: s... |
1101 |
|
91fcad19d virtio_console: u... |
1102 1103 1104 1105 1106 1107 1108 |
return 0; } static void notifier_del_vio(struct hvc_struct *hp, int data) { hp->irq_requested = 0; } |
17634ba25 virtio: console: ... |
1109 |
/* The operations for console ports. */ |
1dff39961 hvc_console: make... |
1110 |
static const struct hv_ops hv_ops = { |
971f33900 virtio: console: ... |
1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 |
.get_chars = get_chars, .put_chars = put_chars, .notifier_add = notifier_add_vio, .notifier_del = notifier_del_vio, .notifier_hangup = notifier_del_vio, }; /* * Console drivers are initialized very early so boot messages can go * out, so we do things slightly differently from the generic virtio * initialization of the net and block drivers. * * At this stage, the console is output-only. It's too early to set * up a virtqueue, so we let the drivers do some boutique early-output * thing. */ int __init virtio_cons_early_init(int (*put_chars)(u32, const char *, int)) { early_put_chars = put_chars; return hvc_instantiate(0, 0, &hv_ops); } |
3826835ab virtio_console: m... |
1132 |
static int init_port_console(struct port *port) |
cfa6d3792 virtio: console: ... |
1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 |
{ int ret; /* * The Host's telling us this port is a console port. Hook it * up with an hvc console. * * To set up and manage our virtual console, we call * hvc_alloc(). * * The first argument of hvc_alloc() is the virtual console * number. The second argument is the parameter for the * notification mechanism (like irq number). We currently * leave this as zero, virtqueues have implicit notifications. * * The third argument is a "struct hv_ops" containing the * put_chars() get_chars(), notifier_add() and notifier_del() * pointers. The final argument is the output buffer size: we * can do any size, so we put PAGE_SIZE here. */ port->cons.vtermno = pdrvdata.next_vtermno; port->cons.hvc = hvc_alloc(port->cons.vtermno, 0, &hv_ops, PAGE_SIZE); if (IS_ERR(port->cons.hvc)) { ret = PTR_ERR(port->cons.hvc); |
298add723 virtio: console: ... |
1158 1159 1160 |
dev_err(port->dev, "error %d allocating hvc for port ", ret); |
cfa6d3792 virtio: console: ... |
1161 1162 1163 1164 1165 1166 1167 |
port->cons.hvc = NULL; return ret; } spin_lock_irq(&pdrvdata_lock); pdrvdata.next_vtermno++; list_add_tail(&port->cons.list, &pdrvdata.consoles); spin_unlock_irq(&pdrvdata_lock); |
3c7969ccb virtio: console: ... |
1168 |
port->guest_connected = true; |
cfa6d3792 virtio: console: ... |
1169 |
|
1d05160be virtio: console: ... |
1170 1171 1172 1173 1174 1175 |
/* * Start using the new console output if this is the first * console to come up. */ if (early_put_chars) early_put_chars = NULL; |
2030fa496 virtio: console: ... |
1176 1177 |
/* Notify host of port being opened */ send_control_msg(port, VIRTIO_CONSOLE_PORT_OPEN, 1); |
cfa6d3792 virtio: console: ... |
1178 1179 |
return 0; } |
431edb8a8 virtio: console: ... |
1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 |
static ssize_t show_port_name(struct device *dev, struct device_attribute *attr, char *buffer) { struct port *port; port = dev_get_drvdata(dev); return sprintf(buffer, "%s ", port->name); } static DEVICE_ATTR(name, S_IRUGO, show_port_name, NULL); static struct attribute *port_sysfs_entries[] = { &dev_attr_name.attr, NULL }; static struct attribute_group port_attribute_group = { .name = NULL, /* put in device directory */ .attrs = port_sysfs_entries, }; |
d99393eff virtio: console: ... |
1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 |
static ssize_t debugfs_read(struct file *filp, char __user *ubuf, size_t count, loff_t *offp) { struct port *port; char *buf; ssize_t ret, out_offset, out_count; out_count = 1024; buf = kmalloc(out_count, GFP_KERNEL); if (!buf) return -ENOMEM; port = filp->private_data; out_offset = 0; out_offset += snprintf(buf + out_offset, out_count, "name: %s ", port->name ? port->name : ""); out_offset += snprintf(buf + out_offset, out_count - out_offset, "guest_connected: %d ", port->guest_connected); out_offset += snprintf(buf + out_offset, out_count - out_offset, "host_connected: %d ", port->host_connected); out_offset += snprintf(buf + out_offset, out_count - out_offset, |
cdfadfc1a virtio: console: ... |
1226 1227 1228 |
"outvq_full: %d ", port->outvq_full); out_offset += snprintf(buf + out_offset, out_count - out_offset, |
17e5b4f20 virtio: console: ... |
1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 |
"bytes_sent: %lu ", port->stats.bytes_sent); out_offset += snprintf(buf + out_offset, out_count - out_offset, "bytes_received: %lu ", port->stats.bytes_received); out_offset += snprintf(buf + out_offset, out_count - out_offset, "bytes_discarded: %lu ", port->stats.bytes_discarded); out_offset += snprintf(buf + out_offset, out_count - out_offset, |
d99393eff virtio: console: ... |
1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 |
"is_console: %s ", is_console_port(port) ? "yes" : "no"); out_offset += snprintf(buf + out_offset, out_count - out_offset, "console_vtermno: %u ", port->cons.vtermno); ret = simple_read_from_buffer(ubuf, count, offp, buf, out_offset); kfree(buf); return ret; } static const struct file_operations port_debugfs_ops = { .owner = THIS_MODULE, |
234e34058 simple_open: auto... |
1254 |
.open = simple_open, |
d99393eff virtio: console: ... |
1255 1256 |
.read = debugfs_read, }; |
9778829cf virtio: console: ... |
1257 1258 1259 1260 1261 1262 1263 1264 |
static void set_console_size(struct port *port, u16 rows, u16 cols) { if (!port || !is_console_port(port)) return; port->cons.ws.ws_row = rows; port->cons.ws.ws_col = cols; } |
c446f8fcc virtio: console: ... |
1265 1266 1267 1268 1269 1270 1271 1272 |
static unsigned int fill_queue(struct virtqueue *vq, spinlock_t *lock) { struct port_buffer *buf; unsigned int nr_added_bufs; int ret; nr_added_bufs = 0; do { |
276a3e954 virtio_console: M... |
1273 |
buf = alloc_buf(vq, PAGE_SIZE, 0); |
c446f8fcc virtio: console: ... |
1274 1275 1276 1277 1278 1279 1280 |
if (!buf) break; spin_lock_irq(lock); ret = add_inbuf(vq, buf); if (ret < 0) { spin_unlock_irq(lock); |
1b6370463 virtio_console: A... |
1281 |
free_buf(buf, true); |
c446f8fcc virtio: console: ... |
1282 1283 1284 1285 1286 1287 1288 1289 |
break; } nr_added_bufs++; spin_unlock_irq(lock); } while (ret > 0); return nr_added_bufs; } |
3eae0adea virtio: console: ... |
1290 1291 1292 1293 1294 |
static void send_sigio_to_port(struct port *port) { if (port->async_queue && port->guest_connected) kill_fasync(&port->async_queue, SIGIO, POLL_OUT); } |
c446f8fcc virtio: console: ... |
1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 |
static int add_port(struct ports_device *portdev, u32 id) { char debugfs_name[16]; struct port *port; struct port_buffer *buf; dev_t devt; unsigned int nr_added_bufs; int err; port = kmalloc(sizeof(*port), GFP_KERNEL); if (!port) { err = -ENOMEM; goto fail; } |
b353a6b82 virtio: console: ... |
1309 |
kref_init(&port->kref); |
c446f8fcc virtio: console: ... |
1310 1311 1312 1313 1314 1315 1316 |
port->portdev = portdev; port->id = id; port->name = NULL; port->inbuf = NULL; port->cons.hvc = NULL; |
3eae0adea virtio: console: ... |
1317 |
port->async_queue = NULL; |
c446f8fcc virtio: console: ... |
1318 |
|
9778829cf virtio: console: ... |
1319 |
port->cons.ws.ws_row = port->cons.ws.ws_col = 0; |
c446f8fcc virtio: console: ... |
1320 |
port->host_connected = port->guest_connected = false; |
17e5b4f20 virtio: console: ... |
1321 |
port->stats = (struct port_stats) { 0 }; |
c446f8fcc virtio: console: ... |
1322 |
|
cdfadfc1a virtio: console: ... |
1323 |
port->outvq_full = false; |
c446f8fcc virtio: console: ... |
1324 1325 |
port->in_vq = portdev->in_vqs[port->id]; port->out_vq = portdev->out_vqs[port->id]; |
d22a69892 virtio: console: ... |
1326 1327 1328 1329 1330 1331 1332 1333 |
port->cdev = cdev_alloc(); if (!port->cdev) { dev_err(&port->portdev->vdev->dev, "Error allocating cdev "); err = -ENOMEM; goto free_port; } port->cdev->ops = &port_fops; |
c446f8fcc virtio: console: ... |
1334 1335 |
devt = MKDEV(portdev->chr_major, id); |
d22a69892 virtio: console: ... |
1336 |
err = cdev_add(port->cdev, devt, 1); |
c446f8fcc virtio: console: ... |
1337 1338 1339 1340 |
if (err < 0) { dev_err(&port->portdev->vdev->dev, "Error %d adding cdev for port %u ", err, id); |
d22a69892 virtio: console: ... |
1341 |
goto free_cdev; |
c446f8fcc virtio: console: ... |
1342 1343 1344 |
} port->dev = device_create(pdrvdata.class, &port->portdev->vdev->dev, devt, port, "vport%up%u", |
dc18f0800 virtio_console: U... |
1345 |
port->portdev->vdev->index, id); |
c446f8fcc virtio: console: ... |
1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 |
if (IS_ERR(port->dev)) { err = PTR_ERR(port->dev); dev_err(&port->portdev->vdev->dev, "Error %d creating device for port %u ", err, id); goto free_cdev; } spin_lock_init(&port->inbuf_lock); |
cdfadfc1a virtio: console: ... |
1356 |
spin_lock_init(&port->outvq_lock); |
c446f8fcc virtio: console: ... |
1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 |
init_waitqueue_head(&port->waitqueue); /* Fill the in_vq with buffers so the host can send us data. */ nr_added_bufs = fill_queue(port->in_vq, &port->inbuf_lock); if (!nr_added_bufs) { dev_err(port->dev, "Error allocating inbufs "); err = -ENOMEM; goto free_device; } |
1b6370463 virtio_console: A... |
1367 1368 1369 1370 1371 1372 |
if (is_rproc_serial(port->portdev->vdev)) /* * For rproc_serial assume remote processor is connected. * rproc_serial does not want the console port, only * the generic port implementation. */ |
aabd6a8fa Revert "virtio_co... |
1373 |
port->host_connected = true; |
1b6370463 virtio_console: A... |
1374 1375 1376 1377 1378 |
else if (!use_multiport(port->portdev)) { /* * If we're not using multiport support, * this has to be a console port. */ |
c446f8fcc virtio: console: ... |
1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 |
err = init_port_console(port); if (err) goto free_inbufs; } spin_lock_irq(&portdev->ports_lock); list_add_tail(&port->list, &port->portdev->ports); spin_unlock_irq(&portdev->ports_lock); /* * Tell the Host we're set so that it can send us various * configuration parameters for this port (eg, port name, * caching, whether this is a console port, etc.) */ send_control_msg(port, VIRTIO_CONSOLE_PORT_READY, 1); if (pdrvdata.debugfs_dir) { /* * Finally, create the debugfs file that we can use to * inspect a port's state at any time */ |
db1700685 virtio_console: s... |
1400 1401 |
snprintf(debugfs_name, sizeof(debugfs_name), "vport%up%u", port->portdev->vdev->index, id); |
c446f8fcc virtio: console: ... |
1402 1403 1404 1405 1406 1407 1408 1409 1410 |
port->debugfs_file = debugfs_create_file(debugfs_name, 0444, pdrvdata.debugfs_dir, port, &port_debugfs_ops); } return 0; free_inbufs: while ((buf = virtqueue_detach_unused_buf(port->in_vq))) |
1b6370463 virtio_console: A... |
1411 |
free_buf(buf, true); |
c446f8fcc virtio: console: ... |
1412 1413 1414 |
free_device: device_destroy(pdrvdata.class, port->dev->devt); free_cdev: |
d22a69892 virtio: console: ... |
1415 |
cdev_del(port->cdev); |
c446f8fcc virtio: console: ... |
1416 1417 1418 1419 |
free_port: kfree(port); fail: /* The host might want to notify management sw about port add failure */ |
0643e4c6e drivers/char: Eli... |
1420 |
__send_control_msg(portdev, id, VIRTIO_CONSOLE_PORT_READY, 0); |
c446f8fcc virtio: console: ... |
1421 1422 |
return err; } |
b353a6b82 virtio: console: ... |
1423 1424 1425 1426 1427 1428 |
/* No users remain, remove all port-specific data. */ static void remove_port(struct kref *kref) { struct port *port; port = container_of(kref, struct port, kref); |
b353a6b82 virtio: console: ... |
1429 1430 |
kfree(port); } |
a0e2dbfc2 virtio: console: ... |
1431 1432 1433 |
static void remove_port_data(struct port *port) { struct port_buffer *buf; |
c6017e793 virtio: console: ... |
1434 |
spin_lock_irq(&port->inbuf_lock); |
a0e2dbfc2 virtio: console: ... |
1435 1436 |
/* Remove unused data this port might have received. */ discard_port_data(port); |
34563769e virtio: console: ... |
1437 |
spin_unlock_irq(&port->inbuf_lock); |
a0e2dbfc2 virtio: console: ... |
1438 |
|
a0e2dbfc2 virtio: console: ... |
1439 |
/* Remove buffers we queued up for the Host to send us data in. */ |
34563769e virtio: console: ... |
1440 1441 1442 1443 1444 1445 1446 |
do { spin_lock_irq(&port->inbuf_lock); buf = virtqueue_detach_unused_buf(port->in_vq); spin_unlock_irq(&port->inbuf_lock); if (buf) free_buf(buf, true); } while (buf); |
c6017e793 virtio: console: ... |
1447 1448 1449 |
spin_lock_irq(&port->outvq_lock); reclaim_consumed_buffers(port); |
34563769e virtio: console: ... |
1450 |
spin_unlock_irq(&port->outvq_lock); |
eb34f12b5 virtio_console: F... |
1451 1452 |
/* Free pending buffers from the out-queue. */ |
34563769e virtio: console: ... |
1453 1454 1455 1456 1457 1458 1459 |
do { spin_lock_irq(&port->outvq_lock); buf = virtqueue_detach_unused_buf(port->out_vq); spin_unlock_irq(&port->outvq_lock); if (buf) free_buf(buf, true); } while (buf); |
a0e2dbfc2 virtio: console: ... |
1460 |
} |
b353a6b82 virtio: console: ... |
1461 1462 1463 1464 1465 1466 |
/* * Port got unplugged. Remove port from portdev's list and drop the * kref reference. If no userspace has this port opened, it will * result in immediate removal the port. */ static void unplug_port(struct port *port) |
1f7aa42d1 virtio: console: ... |
1467 |
{ |
b353a6b82 virtio: console: ... |
1468 1469 1470 |
spin_lock_irq(&port->portdev->ports_lock); list_del(&port->list); spin_unlock_irq(&port->portdev->ports_lock); |
5549fb258 virtio: console: ... |
1471 |
spin_lock_irq(&port->inbuf_lock); |
0047634d3 virtio: console: ... |
1472 |
if (port->guest_connected) { |
92d345381 virtio: console: ... |
1473 1474 1475 1476 |
/* Let the app know the port is going down. */ send_sigio_to_port(port); /* Do this after sigio is actually sent */ |
0047634d3 virtio: console: ... |
1477 1478 |
port->guest_connected = false; port->host_connected = false; |
a461e11e7 virtio: console: ... |
1479 |
|
92d345381 virtio: console: ... |
1480 |
wake_up_interruptible(&port->waitqueue); |
0047634d3 virtio: console: ... |
1481 |
} |
5549fb258 virtio: console: ... |
1482 |
spin_unlock_irq(&port->inbuf_lock); |
0047634d3 virtio: console: ... |
1483 |
|
1f7aa42d1 virtio: console: ... |
1484 1485 1486 1487 1488 1489 |
if (is_console_port(port)) { spin_lock_irq(&pdrvdata_lock); list_del(&port->cons.list); spin_unlock_irq(&pdrvdata_lock); hvc_remove(port->cons.hvc); } |
1f7aa42d1 virtio: console: ... |
1490 |
|
a0e2dbfc2 virtio: console: ... |
1491 |
remove_port_data(port); |
a9cdd4855 virtio: console: ... |
1492 |
|
b353a6b82 virtio: console: ... |
1493 1494 1495 1496 1497 1498 |
/* * We should just assume the device itself has gone off -- * else a close on an open port later will try to send out a * control message. */ port->portdev = NULL; |
d99393eff virtio: console: ... |
1499 |
|
ea3768b43 virtio: console: ... |
1500 1501 1502 |
sysfs_remove_group(&port->dev->kobj, &port_attribute_group); device_destroy(pdrvdata.class, port->dev->devt); cdev_del(port->cdev); |
ea3768b43 virtio: console: ... |
1503 |
debugfs_remove(port->debugfs_file); |
3b868a407 virtio: console: ... |
1504 |
kfree(port->name); |
ea3768b43 virtio: console: ... |
1505 |
|
b353a6b82 virtio: console: ... |
1506 1507 1508 1509 1510 1511 |
/* * Locks around here are not necessary - a port can't be * opened after we removed the port struct from ports_list * above. */ kref_put(&port->kref, remove_port); |
1f7aa42d1 virtio: console: ... |
1512 |
} |
17634ba25 virtio: console: ... |
1513 |
/* Any private messages that the Host and Guest want to share */ |
1f0f9106f virtio_console: v... |
1514 1515 |
static void handle_control_message(struct virtio_device *vdev, struct ports_device *portdev, |
17634ba25 virtio: console: ... |
1516 1517 1518 1519 |
struct port_buffer *buf) { struct virtio_console_control *cpkt; struct port *port; |
431edb8a8 virtio: console: ... |
1520 1521 |
size_t name_size; int err; |
17634ba25 virtio: console: ... |
1522 1523 |
cpkt = (struct virtio_console_control *)(buf->buf + buf->offset); |
1f0f9106f virtio_console: v... |
1524 1525 1526 |
port = find_port_by_id(portdev, virtio32_to_cpu(vdev, cpkt->id)); if (!port && cpkt->event != cpu_to_virtio16(vdev, VIRTIO_CONSOLE_PORT_ADD)) { |
17634ba25 virtio: console: ... |
1527 1528 1529 1530 1531 1532 |
/* No valid header at start of buffer. Drop it. */ dev_dbg(&portdev->vdev->dev, "Invalid index %u in control packet ", cpkt->id); return; } |
1f0f9106f virtio_console: v... |
1533 |
switch (virtio16_to_cpu(vdev, cpkt->event)) { |
f909f850d virtio: console: ... |
1534 1535 |
case VIRTIO_CONSOLE_PORT_ADD: if (port) { |
1d05160be virtio: console: ... |
1536 1537 1538 |
dev_dbg(&portdev->vdev->dev, "Port %u already added ", port->id); |
f909f850d virtio: console: ... |
1539 1540 1541 |
send_control_msg(port, VIRTIO_CONSOLE_PORT_READY, 1); break; } |
1f0f9106f virtio_console: v... |
1542 1543 |
if (virtio32_to_cpu(vdev, cpkt->id) >= portdev->config.max_nr_ports) { |
f909f850d virtio: console: ... |
1544 |
dev_warn(&portdev->vdev->dev, |
1f0f9106f virtio_console: v... |
1545 1546 1547 |
"Request for adding port with " "out-of-bound id %u, max. supported id: %u ", |
f909f850d virtio: console: ... |
1548 1549 1550 |
cpkt->id, portdev->config.max_nr_ports - 1); break; } |
1f0f9106f virtio_console: v... |
1551 |
add_port(portdev, virtio32_to_cpu(vdev, cpkt->id)); |
f909f850d virtio: console: ... |
1552 1553 |
break; case VIRTIO_CONSOLE_PORT_REMOVE: |
b353a6b82 virtio: console: ... |
1554 |
unplug_port(port); |
f909f850d virtio: console: ... |
1555 |
break; |
17634ba25 virtio: console: ... |
1556 1557 1558 1559 1560 1561 1562 |
case VIRTIO_CONSOLE_CONSOLE_PORT: if (!cpkt->value) break; if (is_console_port(port)) break; init_port_console(port); |
5e38483b3 virtio: console: ... |
1563 |
complete(&early_console_added); |
17634ba25 virtio: console: ... |
1564 1565 1566 1567 1568 |
/* * Could remove the port here in case init fails - but * have to notify the host first. */ break; |
8345adbf9 virtio: console: ... |
1569 1570 1571 1572 1573 |
case VIRTIO_CONSOLE_RESIZE: { struct { __u16 rows; __u16 cols; } size; |
17634ba25 virtio: console: ... |
1574 1575 |
if (!is_console_port(port)) break; |
8345adbf9 virtio: console: ... |
1576 1577 1578 1579 |
memcpy(&size, buf->buf + buf->offset + sizeof(*cpkt), sizeof(size)); set_console_size(port, size.rows, size.cols); |
17634ba25 virtio: console: ... |
1580 1581 1582 |
port->cons.hvc->irq_requested = 1; resize_console(port); break; |
8345adbf9 virtio: console: ... |
1583 |
} |
2030fa496 virtio: console: ... |
1584 |
case VIRTIO_CONSOLE_PORT_OPEN: |
1f0f9106f virtio_console: v... |
1585 |
port->host_connected = virtio16_to_cpu(vdev, cpkt->value); |
2030fa496 virtio: console: ... |
1586 |
wake_up_interruptible(&port->waitqueue); |
cdfadfc1a virtio: console: ... |
1587 1588 1589 1590 1591 1592 1593 1594 |
/* * If the host port got closed and the host had any * unconsumed buffers, we'll be able to reclaim them * now. */ spin_lock_irq(&port->outvq_lock); reclaim_consumed_buffers(port); spin_unlock_irq(&port->outvq_lock); |
3eae0adea virtio: console: ... |
1595 1596 1597 1598 1599 |
/* * If the guest is connected, it'll be interested in * knowing the host connection state changed. */ |
314081f10 virtio: console: ... |
1600 |
spin_lock_irq(&port->inbuf_lock); |
3eae0adea virtio: console: ... |
1601 |
send_sigio_to_port(port); |
314081f10 virtio: console: ... |
1602 |
spin_unlock_irq(&port->inbuf_lock); |
2030fa496 virtio: console: ... |
1603 |
break; |
431edb8a8 virtio: console: ... |
1604 1605 |
case VIRTIO_CONSOLE_PORT_NAME: /* |
291024ef3 virtio: console: ... |
1606 1607 1608 1609 1610 1611 1612 |
* If we woke up after hibernation, we can get this * again. Skip it in that case. */ if (port->name) break; /* |
431edb8a8 virtio: console: ... |
1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 |
* Skip the size of the header and the cpkt to get the size * of the name that was sent */ name_size = buf->len - buf->offset - sizeof(*cpkt) + 1; port->name = kmalloc(name_size, GFP_KERNEL); if (!port->name) { dev_err(port->dev, "Not enough space to store port name "); break; } strncpy(port->name, buf->buf + buf->offset + sizeof(*cpkt), name_size - 1); port->name[name_size - 1] = 0; /* * Since we only have one sysfs attribute, 'name', * create it only if we have a name for the port. */ err = sysfs_create_group(&port->dev->kobj, &port_attribute_group); |
ec64213c4 virtio: console: ... |
1635 |
if (err) { |
431edb8a8 virtio: console: ... |
1636 1637 1638 1639 |
dev_err(port->dev, "Error %d creating sysfs device attributes ", err); |
ec64213c4 virtio: console: ... |
1640 1641 1642 1643 1644 1645 1646 1647 |
} else { /* * Generate a udev event so that appropriate * symlinks can be created based on udev * rules. */ kobject_uevent(&port->dev->kobj, KOBJ_CHANGE); } |
431edb8a8 virtio: console: ... |
1648 |
break; |
17634ba25 virtio: console: ... |
1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 |
} } static void control_work_handler(struct work_struct *work) { struct ports_device *portdev; struct virtqueue *vq; struct port_buffer *buf; unsigned int len; portdev = container_of(work, struct ports_device, control_work); vq = portdev->c_ivq; |
165b1b8bb virtio: console: ... |
1661 |
spin_lock(&portdev->c_ivq_lock); |
505b0451c virtio_console: u... |
1662 |
while ((buf = virtqueue_get_buf(vq, &len))) { |
165b1b8bb virtio: console: ... |
1663 |
spin_unlock(&portdev->c_ivq_lock); |
17634ba25 virtio: console: ... |
1664 1665 1666 |
buf->len = len; buf->offset = 0; |
1f0f9106f virtio_console: v... |
1667 |
handle_control_message(vq->vdev, portdev, buf); |
17634ba25 virtio: console: ... |
1668 |
|
165b1b8bb virtio: console: ... |
1669 |
spin_lock(&portdev->c_ivq_lock); |
17634ba25 virtio: console: ... |
1670 1671 1672 1673 |
if (add_inbuf(portdev->c_ivq, buf) < 0) { dev_warn(&portdev->vdev->dev, "Error adding buffer to queue "); |
1b6370463 virtio_console: A... |
1674 |
free_buf(buf, false); |
17634ba25 virtio: console: ... |
1675 1676 |
} } |
165b1b8bb virtio: console: ... |
1677 |
spin_unlock(&portdev->c_ivq_lock); |
17634ba25 virtio: console: ... |
1678 |
} |
2770c5ea5 virtio: console: ... |
1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 |
static void out_intr(struct virtqueue *vq) { struct port *port; port = find_port_by_vq(vq->vdev->priv, vq); if (!port) return; wake_up_interruptible(&port->waitqueue); } |
17634ba25 virtio: console: ... |
1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 |
static void in_intr(struct virtqueue *vq) { struct port *port; unsigned long flags; port = find_port_by_vq(vq->vdev->priv, vq); if (!port) return; spin_lock_irqsave(&port->inbuf_lock, flags); |
d25a9ddae virtio: console: ... |
1699 |
port->inbuf = get_inbuf(port); |
17634ba25 virtio: console: ... |
1700 |
|
88f251ac5 virtio: console: ... |
1701 |
/* |
aabd6a8fa Revert "virtio_co... |
1702 1703 1704 |
* Normally the port should not accept data when the port is * closed. For generic serial ports, the host won't (shouldn't) * send data till the guest is connected. But this condition |
88f251ac5 virtio: console: ... |
1705 |
* can be reached when a console port is not yet connected (no |
aabd6a8fa Revert "virtio_co... |
1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 |
* tty is spawned) and the other side sends out data over the * vring, or when a remote devices start sending data before * the ports are opened. * * A generic serial port will discard data if not connected, * while console ports and rproc-serial ports accepts data at * any time. rproc-serial is initiated with guest_connected to * false because port_fops_open expects this. Console ports are * hooked up with an HVC console and is initialized with * guest_connected to true. |
88f251ac5 virtio: console: ... |
1716 |
*/ |
aabd6a8fa Revert "virtio_co... |
1717 1718 |
if (!port->guest_connected && !is_rproc_serial(port->portdev->vdev)) |
88f251ac5 virtio: console: ... |
1719 |
discard_port_data(port); |
314081f10 virtio: console: ... |
1720 1721 |
/* Send a SIGIO indicating new data in case the process asked for it */ send_sigio_to_port(port); |
17634ba25 virtio: console: ... |
1722 |
spin_unlock_irqrestore(&port->inbuf_lock, flags); |
2030fa496 virtio: console: ... |
1723 |
wake_up_interruptible(&port->waitqueue); |
17634ba25 virtio: console: ... |
1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 |
if (is_console_port(port) && hvc_poll(port->cons.hvc)) hvc_kick(); } static void control_intr(struct virtqueue *vq) { struct ports_device *portdev; portdev = vq->vdev->priv; schedule_work(&portdev->control_work); } |
7f5d810da virtio: console: ... |
1735 1736 1737 1738 1739 |
static void config_intr(struct virtio_device *vdev) { struct ports_device *portdev; portdev = vdev->priv; |
99f905f88 virtio: console: ... |
1740 |
|
eeb8a7e8b virtio_console: a... |
1741 1742 1743 1744 1745 1746 1747 1748 1749 |
if (!use_multiport(portdev)) schedule_work(&portdev->config_work); } static void config_work_handler(struct work_struct *work) { struct ports_device *portdev; portdev = container_of(work, struct ports_device, control_work); |
4038f5b76 virtio: console: ... |
1750 |
if (!use_multiport(portdev)) { |
eeb8a7e8b virtio_console: a... |
1751 |
struct virtio_device *vdev; |
9778829cf virtio: console: ... |
1752 1753 |
struct port *port; u16 rows, cols; |
eeb8a7e8b virtio_console: a... |
1754 |
vdev = portdev->vdev; |
855e0c528 virtio: use size-... |
1755 1756 |
virtio_cread(vdev, struct virtio_console_config, cols, &cols); virtio_cread(vdev, struct virtio_console_config, rows, &rows); |
9778829cf virtio: console: ... |
1757 1758 1759 |
port = find_port_by_id(portdev, 0); set_console_size(port, rows, cols); |
4038f5b76 virtio: console: ... |
1760 1761 1762 1763 1764 1765 1766 |
/* * We'll use this way of resizing only for legacy * support. For newer userspace * (VIRTIO_CONSOLE_F_MULTPORT+), use control messages * to indicate console size changes so that it can be * done per-port. */ |
9778829cf virtio: console: ... |
1767 |
resize_console(port); |
4038f5b76 virtio: console: ... |
1768 |
} |
7f5d810da virtio: console: ... |
1769 |
} |
2658a79ac virtio: console: ... |
1770 1771 1772 1773 1774 |
static int init_vqs(struct ports_device *portdev) { vq_callback_t **io_callbacks; char **io_names; struct virtqueue **vqs; |
17634ba25 virtio: console: ... |
1775 |
u32 i, j, nr_ports, nr_queues; |
2658a79ac virtio: console: ... |
1776 |
int err; |
17634ba25 virtio: console: ... |
1777 1778 |
nr_ports = portdev->config.max_nr_ports; nr_queues = use_multiport(portdev) ? (nr_ports + 1) * 2 : 2; |
2658a79ac virtio: console: ... |
1779 1780 |
vqs = kmalloc(nr_queues * sizeof(struct virtqueue *), GFP_KERNEL); |
2658a79ac virtio: console: ... |
1781 |
io_callbacks = kmalloc(nr_queues * sizeof(vq_callback_t *), GFP_KERNEL); |
2658a79ac virtio: console: ... |
1782 |
io_names = kmalloc(nr_queues * sizeof(char *), GFP_KERNEL); |
2658a79ac virtio: console: ... |
1783 1784 |
portdev->in_vqs = kmalloc(nr_ports * sizeof(struct virtqueue *), GFP_KERNEL); |
2658a79ac virtio: console: ... |
1785 1786 |
portdev->out_vqs = kmalloc(nr_ports * sizeof(struct virtqueue *), GFP_KERNEL); |
22e132ff2 Char: virtio_cons... |
1787 |
if (!vqs || !io_callbacks || !io_names || !portdev->in_vqs || |
286f9a226 virtio: console: ... |
1788 |
!portdev->out_vqs) { |
2658a79ac virtio: console: ... |
1789 |
err = -ENOMEM; |
22e132ff2 Char: virtio_cons... |
1790 |
goto free; |
2658a79ac virtio: console: ... |
1791 |
} |
17634ba25 virtio: console: ... |
1792 1793 1794 1795 1796 1797 1798 |
/* * For backward compat (newer host but older guest), the host * spawns a console port first and also inits the vqs for port * 0 before others. */ j = 0; io_callbacks[j] = in_intr; |
2770c5ea5 virtio: console: ... |
1799 |
io_callbacks[j + 1] = out_intr; |
17634ba25 virtio: console: ... |
1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 |
io_names[j] = "input"; io_names[j + 1] = "output"; j += 2; if (use_multiport(portdev)) { io_callbacks[j] = control_intr; io_callbacks[j + 1] = NULL; io_names[j] = "control-i"; io_names[j + 1] = "control-o"; for (i = 1; i < nr_ports; i++) { j += 2; io_callbacks[j] = in_intr; |
2770c5ea5 virtio: console: ... |
1813 |
io_callbacks[j + 1] = out_intr; |
17634ba25 virtio: console: ... |
1814 1815 1816 1817 |
io_names[j] = "input"; io_names[j + 1] = "output"; } } |
2658a79ac virtio: console: ... |
1818 1819 1820 1821 1822 |
/* Find the queues. */ err = portdev->vdev->config->find_vqs(portdev->vdev, nr_queues, vqs, io_callbacks, (const char **)io_names); if (err) |
22e132ff2 Char: virtio_cons... |
1823 |
goto free; |
2658a79ac virtio: console: ... |
1824 |
|
17634ba25 virtio: console: ... |
1825 |
j = 0; |
2658a79ac virtio: console: ... |
1826 1827 |
portdev->in_vqs[0] = vqs[0]; portdev->out_vqs[0] = vqs[1]; |
17634ba25 virtio: console: ... |
1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 |
j += 2; if (use_multiport(portdev)) { portdev->c_ivq = vqs[j]; portdev->c_ovq = vqs[j + 1]; for (i = 1; i < nr_ports; i++) { j += 2; portdev->in_vqs[i] = vqs[j]; portdev->out_vqs[i] = vqs[j + 1]; } } |
2658a79ac virtio: console: ... |
1839 |
kfree(io_names); |
22e132ff2 Char: virtio_cons... |
1840 |
kfree(io_callbacks); |
2658a79ac virtio: console: ... |
1841 1842 1843 |
kfree(vqs); return 0; |
22e132ff2 Char: virtio_cons... |
1844 |
free: |
2658a79ac virtio: console: ... |
1845 |
kfree(portdev->out_vqs); |
2658a79ac virtio: console: ... |
1846 |
kfree(portdev->in_vqs); |
22e132ff2 Char: virtio_cons... |
1847 1848 |
kfree(io_names); kfree(io_callbacks); |
2658a79ac virtio: console: ... |
1849 |
kfree(vqs); |
22e132ff2 Char: virtio_cons... |
1850 |
|
2658a79ac virtio: console: ... |
1851 1852 |
return err; } |
fb08bd274 virtio: console: ... |
1853 1854 1855 |
static const struct file_operations portdev_fops = { .owner = THIS_MODULE, }; |
a0e2dbfc2 virtio: console: ... |
1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 |
static void remove_vqs(struct ports_device *portdev) { portdev->vdev->config->del_vqs(portdev->vdev); kfree(portdev->in_vqs); kfree(portdev->out_vqs); } static void remove_controlq_data(struct ports_device *portdev) { struct port_buffer *buf; unsigned int len; if (!use_multiport(portdev)) return; while ((buf = virtqueue_get_buf(portdev->c_ivq, &len))) |
1b6370463 virtio_console: A... |
1872 |
free_buf(buf, true); |
a0e2dbfc2 virtio: console: ... |
1873 1874 |
while ((buf = virtqueue_detach_unused_buf(portdev->c_ivq))) |
1b6370463 virtio_console: A... |
1875 |
free_buf(buf, true); |
a0e2dbfc2 virtio: console: ... |
1876 |
} |
1c85bf354 virtio: console: ... |
1877 1878 1879 |
/* * Once we're further in boot, we get probed like any other virtio * device. |
17634ba25 virtio: console: ... |
1880 1881 1882 1883 |
* * If the host also supports multiple console ports, we check the * config space to see how many ports the host has spawned. We * initialize each port found. |
1c85bf354 virtio: console: ... |
1884 |
*/ |
2223cbec3 char: remove use ... |
1885 |
static int virtcons_probe(struct virtio_device *vdev) |
1c85bf354 virtio: console: ... |
1886 |
{ |
1c85bf354 virtio: console: ... |
1887 1888 |
struct ports_device *portdev; int err; |
17634ba25 virtio: console: ... |
1889 |
bool multiport; |
5e38483b3 virtio: console: ... |
1890 |
bool early = early_put_chars != NULL; |
be8ff5952 virtio: don't req... |
1891 1892 1893 1894 |
/* We only need a config space if features are offered */ if (!vdev->config->get && (virtio_has_feature(vdev, VIRTIO_CONSOLE_F_SIZE) || virtio_has_feature(vdev, VIRTIO_CONSOLE_F_MULTIPORT))) { |
011f0e7a6 virtio/console: v... |
1895 1896 1897 1898 1899 |
dev_err(&vdev->dev, "%s failure: config access disabled ", __func__); return -EINVAL; } |
5e38483b3 virtio: console: ... |
1900 1901 |
/* Ensure to read early_put_chars now */ barrier(); |
1c85bf354 virtio: console: ... |
1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 |
portdev = kmalloc(sizeof(*portdev), GFP_KERNEL); if (!portdev) { err = -ENOMEM; goto fail; } /* Attach this portdev to this virtio_device, and vice-versa. */ portdev->vdev = vdev; vdev->priv = portdev; |
fb08bd274 virtio: console: ... |
1912 1913 1914 1915 1916 1917 |
portdev->chr_major = register_chrdev(0, "virtio-portsdev", &portdev_fops); if (portdev->chr_major < 0) { dev_err(&vdev->dev, "Error %d registering chrdev for device %u ", |
dc18f0800 virtio_console: U... |
1918 |
portdev->chr_major, vdev->index); |
fb08bd274 virtio: console: ... |
1919 1920 1921 |
err = portdev->chr_major; goto free; } |
17634ba25 virtio: console: ... |
1922 |
multiport = false; |
17634ba25 virtio: console: ... |
1923 |
portdev->config.max_nr_ports = 1; |
1b6370463 virtio_console: A... |
1924 1925 1926 |
/* Don't test MULTIPORT at all if we're rproc: not a valid feature! */ if (!is_rproc_serial(vdev) && |
855e0c528 virtio: use size-... |
1927 1928 1929 |
virtio_cread_feature(vdev, VIRTIO_CONSOLE_F_MULTIPORT, struct virtio_console_config, max_nr_ports, &portdev->config.max_nr_ports) == 0) { |
17634ba25 virtio: console: ... |
1930 |
multiport = true; |
1b6370463 virtio_console: A... |
1931 |
} |
17634ba25 virtio: console: ... |
1932 |
|
2658a79ac virtio: console: ... |
1933 1934 1935 1936 |
err = init_vqs(portdev); if (err < 0) { dev_err(&vdev->dev, "Error %d initializing vqs ", err); |
fb08bd274 virtio: console: ... |
1937 |
goto free_chrdev; |
2658a79ac virtio: console: ... |
1938 |
} |
1c85bf354 virtio: console: ... |
1939 |
|
17634ba25 virtio: console: ... |
1940 1941 |
spin_lock_init(&portdev->ports_lock); INIT_LIST_HEAD(&portdev->ports); |
65eca3a20 virtio_console: m... |
1942 |
virtio_device_ready(portdev->vdev); |
eeb8a7e8b virtio_console: a... |
1943 |
INIT_WORK(&portdev->config_work, &config_work_handler); |
4f6e24ed9 virtio_console: i... |
1944 |
INIT_WORK(&portdev->control_work, &control_work_handler); |
17634ba25 virtio: console: ... |
1945 |
if (multiport) { |
335a64a5c virtio: console: ... |
1946 |
unsigned int nr_added_bufs; |
165b1b8bb virtio: console: ... |
1947 |
spin_lock_init(&portdev->c_ivq_lock); |
9ba5c80b1 virtio: console: ... |
1948 |
spin_lock_init(&portdev->c_ovq_lock); |
17634ba25 virtio: console: ... |
1949 |
|
165b1b8bb virtio: console: ... |
1950 1951 |
nr_added_bufs = fill_queue(portdev->c_ivq, &portdev->c_ivq_lock); |
335a64a5c virtio: console: ... |
1952 |
if (!nr_added_bufs) { |
22a29eacd virtio: console: ... |
1953 1954 1955 1956 1957 1958 |
dev_err(&vdev->dev, "Error allocating buffers for control queue "); err = -ENOMEM; goto free_vqs; } |
1d05160be virtio: console: ... |
1959 1960 1961 1962 1963 1964 |
} else { /* * For backward compatibility: Create a console port * if we're running on older host. */ add_port(portdev, 0); |
17634ba25 virtio: console: ... |
1965 |
} |
6bdf2afd0 virtio: console: ... |
1966 1967 1968 |
spin_lock_irq(&pdrvdata_lock); list_add_tail(&portdev->list, &pdrvdata.portdevs); spin_unlock_irq(&pdrvdata_lock); |
f909f850d virtio: console: ... |
1969 1970 |
__send_control_msg(portdev, VIRTIO_CONSOLE_BAD_ID, VIRTIO_CONSOLE_DEVICE_READY, 1); |
5e38483b3 virtio: console: ... |
1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 |
/* * If there was an early virtio console, assume that there are no * other consoles. We need to wait until the hvc_alloc matches the * hvc_instantiate, otherwise tty_open will complain, resulting in * a "Warning: unable to open an initial console" boot failure. * Without multiport this is done in add_port above. With multiport * this might take some host<->guest communication - thus we have to * wait. */ if (multiport && early) wait_for_completion(&early_console_added); |
31610434b Virtio console dr... |
1983 |
return 0; |
22a29eacd virtio: console: ... |
1984 |
free_vqs: |
0643e4c6e drivers/char: Eli... |
1985 1986 1987 |
/* The host might want to notify mgmt sw about device add failure */ __send_control_msg(portdev, VIRTIO_CONSOLE_BAD_ID, VIRTIO_CONSOLE_DEVICE_READY, 0); |
a0e2dbfc2 virtio: console: ... |
1988 |
remove_vqs(portdev); |
fb08bd274 virtio: console: ... |
1989 1990 |
free_chrdev: unregister_chrdev(portdev->chr_major, "virtio-portsdev"); |
31610434b Virtio console dr... |
1991 |
free: |
1c85bf354 virtio: console: ... |
1992 |
kfree(portdev); |
31610434b Virtio console dr... |
1993 1994 1995 |
fail: return err; } |
7177876fe virtio: console: ... |
1996 1997 1998 1999 |
static void virtcons_remove(struct virtio_device *vdev) { struct ports_device *portdev; struct port *port, *port2; |
7177876fe virtio: console: ... |
2000 2001 |
portdev = vdev->priv; |
6bdf2afd0 virtio: console: ... |
2002 2003 2004 |
spin_lock_irq(&pdrvdata_lock); list_del(&portdev->list); spin_unlock_irq(&pdrvdata_lock); |
022389599 virtio: console: ... |
2005 2006 2007 |
/* Disable interrupts for vqs */ vdev->config->reset(vdev); /* Finish up work that's lined up */ |
aded024a1 virtio_console: D... |
2008 2009 |
if (use_multiport(portdev)) cancel_work_sync(&portdev->control_work); |
eeb8a7e8b virtio_console: a... |
2010 2011 |
else cancel_work_sync(&portdev->config_work); |
7177876fe virtio: console: ... |
2012 2013 |
list_for_each_entry_safe(port, port2, &portdev->ports, list) |
b353a6b82 virtio: console: ... |
2014 |
unplug_port(port); |
7177876fe virtio: console: ... |
2015 2016 |
unregister_chrdev(portdev->chr_major, "virtio-portsdev"); |
e062013c7 virtio: console: ... |
2017 2018 2019 2020 2021 2022 2023 2024 |
/* * When yanking out a device, we immediately lose the * (device-side) queues. So there's no point in keeping the * guest side around till we drop our final reference. This * also means that any ports which are in an open state will * have to just stop using the port, as the vqs are going * away. */ |
a0e2dbfc2 virtio: console: ... |
2025 2026 |
remove_controlq_data(portdev); remove_vqs(portdev); |
7177876fe virtio: console: ... |
2027 2028 |
kfree(portdev); } |
31610434b Virtio console dr... |
2029 2030 2031 2032 |
static struct virtio_device_id id_table[] = { { VIRTIO_ID_CONSOLE, VIRTIO_DEV_ANY_ID }, { 0 }, }; |
c29834584 virtio_console: s... |
2033 2034 |
static unsigned int features[] = { VIRTIO_CONSOLE_F_SIZE, |
b99fa815d virtio: Revert "v... |
2035 |
VIRTIO_CONSOLE_F_MULTIPORT, |
c29834584 virtio_console: s... |
2036 |
}; |
1b6370463 virtio_console: A... |
2037 2038 2039 2040 2041 2042 2043 2044 2045 |
static struct virtio_device_id rproc_serial_id_table[] = { #if IS_ENABLED(CONFIG_REMOTEPROC) { VIRTIO_ID_RPROC_SERIAL, VIRTIO_DEV_ANY_ID }, #endif { 0 }, }; static unsigned int rproc_serial_features[] = { }; |
891070003 virtio: pm: use C... |
2046 |
#ifdef CONFIG_PM_SLEEP |
2b8f41d84 virtio: console: ... |
2047 2048 2049 2050 2051 2052 2053 2054 |
static int virtcons_freeze(struct virtio_device *vdev) { struct ports_device *portdev; struct port *port; portdev = vdev->priv; vdev->config->reset(vdev); |
c743d09db virtio: console: ... |
2055 |
virtqueue_disable_cb(portdev->c_ivq); |
2b8f41d84 virtio: console: ... |
2056 |
cancel_work_sync(&portdev->control_work); |
eeb8a7e8b virtio_console: a... |
2057 |
cancel_work_sync(&portdev->config_work); |
c743d09db virtio: console: ... |
2058 2059 2060 2061 2062 |
/* * Once more: if control_work_handler() was running, it would * enable the cb as the last step. */ virtqueue_disable_cb(portdev->c_ivq); |
2b8f41d84 virtio: console: ... |
2063 2064 2065 |
remove_controlq_data(portdev); list_for_each_entry(port, &portdev->ports, list) { |
c743d09db virtio: console: ... |
2066 2067 |
virtqueue_disable_cb(port->in_vq); virtqueue_disable_cb(port->out_vq); |
2b8f41d84 virtio: console: ... |
2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 |
/* * We'll ask the host later if the new invocation has * the port opened or closed. */ port->host_connected = false; remove_port_data(port); } remove_vqs(portdev); return 0; } static int virtcons_restore(struct virtio_device *vdev) { struct ports_device *portdev; struct port *port; int ret; portdev = vdev->priv; ret = init_vqs(portdev); if (ret) return ret; |
401bbdc90 virtio_console: e... |
2091 |
virtio_device_ready(portdev->vdev); |
2b8f41d84 virtio: console: ... |
2092 |
if (use_multiport(portdev)) |
165b1b8bb virtio: console: ... |
2093 |
fill_queue(portdev->c_ivq, &portdev->c_ivq_lock); |
2b8f41d84 virtio: console: ... |
2094 2095 2096 2097 2098 2099 2100 2101 2102 |
list_for_each_entry(port, &portdev->ports, list) { port->in_vq = portdev->in_vqs[port->id]; port->out_vq = portdev->out_vqs[port->id]; fill_queue(port->in_vq, &port->inbuf_lock); /* Get port open/close status on the host */ send_control_msg(port, VIRTIO_CONSOLE_PORT_READY, 1); |
fa8b66ccd virtio: console: ... |
2103 2104 2105 2106 2107 2108 2109 |
/* * If a port was open at the time of suspending, we * have to let the host know that it's still open. */ if (port->guest_connected) send_control_msg(port, VIRTIO_CONSOLE_PORT_OPEN, 1); |
2b8f41d84 virtio: console: ... |
2110 2111 2112 2113 |
} return 0; } #endif |
31610434b Virtio console dr... |
2114 |
static struct virtio_driver virtio_console = { |
c29834584 virtio_console: s... |
2115 2116 |
.feature_table = features, .feature_table_size = ARRAY_SIZE(features), |
31610434b Virtio console dr... |
2117 2118 2119 2120 |
.driver.name = KBUILD_MODNAME, .driver.owner = THIS_MODULE, .id_table = id_table, .probe = virtcons_probe, |
7177876fe virtio: console: ... |
2121 |
.remove = virtcons_remove, |
7f5d810da virtio: console: ... |
2122 |
.config_changed = config_intr, |
891070003 virtio: pm: use C... |
2123 |
#ifdef CONFIG_PM_SLEEP |
2b8f41d84 virtio: console: ... |
2124 2125 2126 |
.freeze = virtcons_freeze, .restore = virtcons_restore, #endif |
31610434b Virtio console dr... |
2127 |
}; |
bcd2982a0 Drivers: char: re... |
2128 |
static struct virtio_driver virtio_rproc_serial = { |
1b6370463 virtio_console: A... |
2129 2130 2131 2132 2133 2134 2135 2136 |
.feature_table = rproc_serial_features, .feature_table_size = ARRAY_SIZE(rproc_serial_features), .driver.name = "virtio_rproc_serial", .driver.owner = THIS_MODULE, .id_table = rproc_serial_id_table, .probe = virtcons_probe, .remove = virtcons_remove, }; |
31610434b Virtio console dr... |
2137 2138 |
static int __init init(void) { |
fb08bd274 virtio: console: ... |
2139 2140 2141 2142 2143 2144 2145 2146 2147 |
int err; pdrvdata.class = class_create(THIS_MODULE, "virtio-ports"); if (IS_ERR(pdrvdata.class)) { err = PTR_ERR(pdrvdata.class); pr_err("Error %d creating virtio-ports class ", err); return err; } |
d99393eff virtio: console: ... |
2148 2149 |
pdrvdata.debugfs_dir = debugfs_create_dir("virtio-ports", NULL); |
3f0d0c9b4 virtio: console: ... |
2150 2151 2152 |
if (!pdrvdata.debugfs_dir) pr_warning("Error creating debugfs dir for virtio-ports "); |
38edf58d7 virtio: console: ... |
2153 |
INIT_LIST_HEAD(&pdrvdata.consoles); |
6bdf2afd0 virtio: console: ... |
2154 |
INIT_LIST_HEAD(&pdrvdata.portdevs); |
38edf58d7 virtio: console: ... |
2155 |
|
33e1afc3d virtio: console: ... |
2156 2157 2158 2159 2160 2161 |
err = register_virtio_driver(&virtio_console); if (err < 0) { pr_err("Error %d registering virtio driver ", err); goto free; } |
1b6370463 virtio_console: A... |
2162 2163 2164 2165 2166 2167 2168 |
err = register_virtio_driver(&virtio_rproc_serial); if (err < 0) { pr_err("Error %d registering virtio rproc serial driver ", err); goto unregister; } |
33e1afc3d virtio: console: ... |
2169 |
return 0; |
1b6370463 virtio_console: A... |
2170 2171 |
unregister: unregister_virtio_driver(&virtio_console); |
33e1afc3d virtio: console: ... |
2172 |
free: |
5885e48e4 virtio: console: ... |
2173 |
debugfs_remove_recursive(pdrvdata.debugfs_dir); |
33e1afc3d virtio: console: ... |
2174 2175 |
class_destroy(pdrvdata.class); return err; |
31610434b Virtio console dr... |
2176 |
} |
7177876fe virtio: console: ... |
2177 2178 2179 |
static void __exit fini(void) { |
1b6370463 virtio_console: A... |
2180 |
reclaim_dma_bufs(); |
7177876fe virtio: console: ... |
2181 |
unregister_virtio_driver(&virtio_console); |
1b6370463 virtio_console: A... |
2182 |
unregister_virtio_driver(&virtio_rproc_serial); |
7177876fe virtio: console: ... |
2183 2184 |
class_destroy(pdrvdata.class); |
5885e48e4 virtio: console: ... |
2185 |
debugfs_remove_recursive(pdrvdata.debugfs_dir); |
7177876fe virtio: console: ... |
2186 |
} |
31610434b Virtio console dr... |
2187 |
module_init(init); |
7177876fe virtio: console: ... |
2188 |
module_exit(fini); |
31610434b Virtio console dr... |
2189 2190 2191 2192 |
MODULE_DEVICE_TABLE(virtio, id_table); MODULE_DESCRIPTION("Virtio console driver"); MODULE_LICENSE("GPL"); |