mirror of https://gitee.com/openkylin/linux.git
Not entirely surprising: the ongoing QEMU work on virtio 1.0 has revealed
more minor issues with our virtio 1.0 drivers just introduced in the kernel. (I would normally use my fixes branch for this, but there were a batch of them...) Thanks, Rusty. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJVB4gHAAoJENkgDmzRrbjx+BAP/0Z8TPfP5v2XQ0YlLPFpKMQ0 DdsL9s1Se74e0RUJ6fvpVZaVgBxFq1+xi2wiSOhlOyIn0fXlO8+eYK886QX13cYO CUAvuwbQhGHgj+1DfQ+7pJlQe905VvHVxWIVZU1dq+PEI181kOQQE9lOHhsKsYvQ IxEAX3/avYALAV29FN+PvGZcmY5fgeJf58RkQb5h3XXVaBlI175HhiGm3izgqyKe qmZqEDuUnsdlxT5rvJnb0kg/VfRJ2MdkpIcpjpqO4DK3lY+x90LibMmnGLdLkigS cEfjSXPmJKNug+IoxxQuDH6zRsWqTLnwI4gU/FqbOkN12Ovt5k4F+FrFCuXD7GdW tCiBblkQjQ8xS+OP5slXwYKE3a4q4ih6u+9/STNlSVlG1mqZxxmK56WD00CvBpvR CDyTO4yHUV9rjDIhD/r8guFXsPwaaiZxKiGP1k+nnel0E9dMmZf0dE8xqHpTrl0Z 8OAv3TgJFqhmfecFCBxj28e++dl7KvhiAGRKiZvHYkoxWZmJ5EFkw5E8FUOlJQNS 2apGPbBEyeEQho7emzb0l9vvAu+0jJGEObxvA9wUdEcXg2kbDmGIpidZfN6xBemJ 5WuMoGJh9UnYeImtGyXINTuQXagXdzt5bB/IkVmUYMcvsGty5lKIH1G87Q/qV4BE YCbKn/3J+G2TmF3+m8AH =8QwR -----END PGP SIGNATURE----- Merge tag 'virtio-next-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux Pull virtio fixes from Rusty Russell: "Not entirely surprising: the ongoing QEMU work on virtio 1.0 has revealed more minor issues with our virtio 1.0 drivers just introduced in the kernel. (I would normally use my fixes branch for this, but there were a batch of them...)" * tag 'virtio-next-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux: virtio_mmio: fix access width for mmio uapi/virtio_scsi: allow overriding CDB/SENSE size virtio_mmio: generation support virtio_rpmsg: set DRIVER_OK before using device 9p/trans_virtio: fix hot-unplug virtio-balloon: do not call blocking ops when !TASK_RUNNING virtio_blk: fix comment for virtio 1.0 virtio_blk: typo fix virtio_balloon: set DRIVER_OK before using device virtio_console: avoid config access from irq virtio_console: init work unconditionally
This commit is contained in:
commit
4d272f90a7
|
@ -142,6 +142,7 @@ struct ports_device {
|
||||||
* notification
|
* notification
|
||||||
*/
|
*/
|
||||||
struct work_struct control_work;
|
struct work_struct control_work;
|
||||||
|
struct work_struct config_work;
|
||||||
|
|
||||||
struct list_head ports;
|
struct list_head ports;
|
||||||
|
|
||||||
|
@ -1837,10 +1838,21 @@ static void config_intr(struct virtio_device *vdev)
|
||||||
|
|
||||||
portdev = vdev->priv;
|
portdev = vdev->priv;
|
||||||
|
|
||||||
|
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);
|
||||||
if (!use_multiport(portdev)) {
|
if (!use_multiport(portdev)) {
|
||||||
|
struct virtio_device *vdev;
|
||||||
struct port *port;
|
struct port *port;
|
||||||
u16 rows, cols;
|
u16 rows, cols;
|
||||||
|
|
||||||
|
vdev = portdev->vdev;
|
||||||
virtio_cread(vdev, struct virtio_console_config, cols, &cols);
|
virtio_cread(vdev, struct virtio_console_config, cols, &cols);
|
||||||
virtio_cread(vdev, struct virtio_console_config, rows, &rows);
|
virtio_cread(vdev, struct virtio_console_config, rows, &rows);
|
||||||
|
|
||||||
|
@ -2040,12 +2052,14 @@ static int virtcons_probe(struct virtio_device *vdev)
|
||||||
|
|
||||||
virtio_device_ready(portdev->vdev);
|
virtio_device_ready(portdev->vdev);
|
||||||
|
|
||||||
|
INIT_WORK(&portdev->config_work, &config_work_handler);
|
||||||
|
INIT_WORK(&portdev->control_work, &control_work_handler);
|
||||||
|
|
||||||
if (multiport) {
|
if (multiport) {
|
||||||
unsigned int nr_added_bufs;
|
unsigned int nr_added_bufs;
|
||||||
|
|
||||||
spin_lock_init(&portdev->c_ivq_lock);
|
spin_lock_init(&portdev->c_ivq_lock);
|
||||||
spin_lock_init(&portdev->c_ovq_lock);
|
spin_lock_init(&portdev->c_ovq_lock);
|
||||||
INIT_WORK(&portdev->control_work, &control_work_handler);
|
|
||||||
|
|
||||||
nr_added_bufs = fill_queue(portdev->c_ivq,
|
nr_added_bufs = fill_queue(portdev->c_ivq,
|
||||||
&portdev->c_ivq_lock);
|
&portdev->c_ivq_lock);
|
||||||
|
@ -2113,6 +2127,8 @@ static void virtcons_remove(struct virtio_device *vdev)
|
||||||
/* Finish up work that's lined up */
|
/* Finish up work that's lined up */
|
||||||
if (use_multiport(portdev))
|
if (use_multiport(portdev))
|
||||||
cancel_work_sync(&portdev->control_work);
|
cancel_work_sync(&portdev->control_work);
|
||||||
|
else
|
||||||
|
cancel_work_sync(&portdev->config_work);
|
||||||
|
|
||||||
list_for_each_entry_safe(port, port2, &portdev->ports, list)
|
list_for_each_entry_safe(port, port2, &portdev->ports, list)
|
||||||
unplug_port(port);
|
unplug_port(port);
|
||||||
|
@ -2164,6 +2180,7 @@ static int virtcons_freeze(struct virtio_device *vdev)
|
||||||
|
|
||||||
virtqueue_disable_cb(portdev->c_ivq);
|
virtqueue_disable_cb(portdev->c_ivq);
|
||||||
cancel_work_sync(&portdev->control_work);
|
cancel_work_sync(&portdev->control_work);
|
||||||
|
cancel_work_sync(&portdev->config_work);
|
||||||
/*
|
/*
|
||||||
* Once more: if control_work_handler() was running, it would
|
* Once more: if control_work_handler() was running, it would
|
||||||
* enable the cb as the last step.
|
* enable the cb as the last step.
|
||||||
|
|
|
@ -951,6 +951,7 @@ static int rpmsg_probe(struct virtio_device *vdev)
|
||||||
void *bufs_va;
|
void *bufs_va;
|
||||||
int err = 0, i;
|
int err = 0, i;
|
||||||
size_t total_buf_space;
|
size_t total_buf_space;
|
||||||
|
bool notify;
|
||||||
|
|
||||||
vrp = kzalloc(sizeof(*vrp), GFP_KERNEL);
|
vrp = kzalloc(sizeof(*vrp), GFP_KERNEL);
|
||||||
if (!vrp)
|
if (!vrp)
|
||||||
|
@ -1030,8 +1031,22 @@ static int rpmsg_probe(struct virtio_device *vdev)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Prepare to kick but don't notify yet - we can't do this before
|
||||||
|
* device is ready.
|
||||||
|
*/
|
||||||
|
notify = virtqueue_kick_prepare(vrp->rvq);
|
||||||
|
|
||||||
|
/* From this point on, we can notify and get callbacks. */
|
||||||
|
virtio_device_ready(vdev);
|
||||||
|
|
||||||
/* tell the remote processor it can start sending messages */
|
/* tell the remote processor it can start sending messages */
|
||||||
virtqueue_kick(vrp->rvq);
|
/*
|
||||||
|
* this might be concurrent with callbacks, but we are only
|
||||||
|
* doing notify, not a full kick here, so that's ok.
|
||||||
|
*/
|
||||||
|
if (notify)
|
||||||
|
virtqueue_notify(vrp->rvq);
|
||||||
|
|
||||||
dev_info(&vdev->dev, "rpmsg host is online\n");
|
dev_info(&vdev->dev, "rpmsg host is online\n");
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/balloon_compaction.h>
|
#include <linux/balloon_compaction.h>
|
||||||
#include <linux/oom.h>
|
#include <linux/oom.h>
|
||||||
|
#include <linux/wait.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Balloon device works in 4K page units. So each page is pointed to by
|
* Balloon device works in 4K page units. So each page is pointed to by
|
||||||
|
@ -334,17 +335,25 @@ static int virtballoon_oom_notify(struct notifier_block *self,
|
||||||
static int balloon(void *_vballoon)
|
static int balloon(void *_vballoon)
|
||||||
{
|
{
|
||||||
struct virtio_balloon *vb = _vballoon;
|
struct virtio_balloon *vb = _vballoon;
|
||||||
|
DEFINE_WAIT_FUNC(wait, woken_wake_function);
|
||||||
|
|
||||||
set_freezable();
|
set_freezable();
|
||||||
while (!kthread_should_stop()) {
|
while (!kthread_should_stop()) {
|
||||||
s64 diff;
|
s64 diff;
|
||||||
|
|
||||||
try_to_freeze();
|
try_to_freeze();
|
||||||
wait_event_interruptible(vb->config_change,
|
|
||||||
(diff = towards_target(vb)) != 0
|
add_wait_queue(&vb->config_change, &wait);
|
||||||
|| vb->need_stats_update
|
for (;;) {
|
||||||
|| kthread_should_stop()
|
if ((diff = towards_target(vb)) != 0 ||
|
||||||
|| freezing(current));
|
vb->need_stats_update ||
|
||||||
|
kthread_should_stop() ||
|
||||||
|
freezing(current))
|
||||||
|
break;
|
||||||
|
wait_woken(&wait, TASK_INTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT);
|
||||||
|
}
|
||||||
|
remove_wait_queue(&vb->config_change, &wait);
|
||||||
|
|
||||||
if (vb->need_stats_update)
|
if (vb->need_stats_update)
|
||||||
stats_handle_request(vb);
|
stats_handle_request(vb);
|
||||||
if (diff > 0)
|
if (diff > 0)
|
||||||
|
@ -499,6 +508,8 @@ static int virtballoon_probe(struct virtio_device *vdev)
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto out_oom_notify;
|
goto out_oom_notify;
|
||||||
|
|
||||||
|
virtio_device_ready(vdev);
|
||||||
|
|
||||||
vb->thread = kthread_run(balloon, vb, "vballoon");
|
vb->thread = kthread_run(balloon, vb, "vballoon");
|
||||||
if (IS_ERR(vb->thread)) {
|
if (IS_ERR(vb->thread)) {
|
||||||
err = PTR_ERR(vb->thread);
|
err = PTR_ERR(vb->thread);
|
||||||
|
|
|
@ -156,22 +156,95 @@ static void vm_get(struct virtio_device *vdev, unsigned offset,
|
||||||
void *buf, unsigned len)
|
void *buf, unsigned len)
|
||||||
{
|
{
|
||||||
struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev);
|
struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev);
|
||||||
u8 *ptr = buf;
|
void __iomem *base = vm_dev->base + VIRTIO_MMIO_CONFIG;
|
||||||
int i;
|
u8 b;
|
||||||
|
__le16 w;
|
||||||
|
__le32 l;
|
||||||
|
|
||||||
for (i = 0; i < len; i++)
|
if (vm_dev->version == 1) {
|
||||||
ptr[i] = readb(vm_dev->base + VIRTIO_MMIO_CONFIG + offset + i);
|
u8 *ptr = buf;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < len; i++)
|
||||||
|
ptr[i] = readb(base + offset + i);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (len) {
|
||||||
|
case 1:
|
||||||
|
b = readb(base + offset);
|
||||||
|
memcpy(buf, &b, sizeof b);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
w = cpu_to_le16(readw(base + offset));
|
||||||
|
memcpy(buf, &w, sizeof w);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
l = cpu_to_le32(readl(base + offset));
|
||||||
|
memcpy(buf, &l, sizeof l);
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
l = cpu_to_le32(readl(base + offset));
|
||||||
|
memcpy(buf, &l, sizeof l);
|
||||||
|
l = cpu_to_le32(ioread32(base + offset + sizeof l));
|
||||||
|
memcpy(buf + sizeof l, &l, sizeof l);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
BUG();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void vm_set(struct virtio_device *vdev, unsigned offset,
|
static void vm_set(struct virtio_device *vdev, unsigned offset,
|
||||||
const void *buf, unsigned len)
|
const void *buf, unsigned len)
|
||||||
{
|
{
|
||||||
struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev);
|
struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev);
|
||||||
const u8 *ptr = buf;
|
void __iomem *base = vm_dev->base + VIRTIO_MMIO_CONFIG;
|
||||||
int i;
|
u8 b;
|
||||||
|
__le16 w;
|
||||||
|
__le32 l;
|
||||||
|
|
||||||
for (i = 0; i < len; i++)
|
if (vm_dev->version == 1) {
|
||||||
writeb(ptr[i], vm_dev->base + VIRTIO_MMIO_CONFIG + offset + i);
|
const u8 *ptr = buf;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < len; i++)
|
||||||
|
writeb(ptr[i], base + offset + i);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (len) {
|
||||||
|
case 1:
|
||||||
|
memcpy(&b, buf, sizeof b);
|
||||||
|
writeb(b, base + offset);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
memcpy(&w, buf, sizeof w);
|
||||||
|
writew(le16_to_cpu(w), base + offset);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
memcpy(&l, buf, sizeof l);
|
||||||
|
writel(le32_to_cpu(l), base + offset);
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
memcpy(&l, buf, sizeof l);
|
||||||
|
writel(le32_to_cpu(l), base + offset);
|
||||||
|
memcpy(&l, buf + sizeof l, sizeof l);
|
||||||
|
writel(le32_to_cpu(l), base + offset + sizeof l);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
BUG();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static u32 vm_generation(struct virtio_device *vdev)
|
||||||
|
{
|
||||||
|
struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev);
|
||||||
|
|
||||||
|
if (vm_dev->version == 1)
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
return readl(vm_dev->base + VIRTIO_MMIO_CONFIG_GENERATION);
|
||||||
}
|
}
|
||||||
|
|
||||||
static u8 vm_get_status(struct virtio_device *vdev)
|
static u8 vm_get_status(struct virtio_device *vdev)
|
||||||
|
@ -440,6 +513,7 @@ static const char *vm_bus_name(struct virtio_device *vdev)
|
||||||
static const struct virtio_config_ops virtio_mmio_config_ops = {
|
static const struct virtio_config_ops virtio_mmio_config_ops = {
|
||||||
.get = vm_get,
|
.get = vm_get,
|
||||||
.set = vm_set,
|
.set = vm_set,
|
||||||
|
.generation = vm_generation,
|
||||||
.get_status = vm_get_status,
|
.get_status = vm_get_status,
|
||||||
.set_status = vm_set_status,
|
.set_status = vm_set_status,
|
||||||
.reset = vm_reset,
|
.reset = vm_reset,
|
||||||
|
|
|
@ -60,7 +60,7 @@ struct virtio_blk_config {
|
||||||
__u32 size_max;
|
__u32 size_max;
|
||||||
/* The maximum number of segments (if VIRTIO_BLK_F_SEG_MAX) */
|
/* The maximum number of segments (if VIRTIO_BLK_F_SEG_MAX) */
|
||||||
__u32 seg_max;
|
__u32 seg_max;
|
||||||
/* geometry the device (if VIRTIO_BLK_F_GEOMETRY) */
|
/* geometry of the device (if VIRTIO_BLK_F_GEOMETRY) */
|
||||||
struct virtio_blk_geometry {
|
struct virtio_blk_geometry {
|
||||||
__u16 cylinders;
|
__u16 cylinders;
|
||||||
__u8 heads;
|
__u8 heads;
|
||||||
|
@ -119,7 +119,11 @@ struct virtio_blk_config {
|
||||||
#define VIRTIO_BLK_T_BARRIER 0x80000000
|
#define VIRTIO_BLK_T_BARRIER 0x80000000
|
||||||
#endif /* !VIRTIO_BLK_NO_LEGACY */
|
#endif /* !VIRTIO_BLK_NO_LEGACY */
|
||||||
|
|
||||||
/* This is the first element of the read scatter-gather list. */
|
/*
|
||||||
|
* This comes first in the read scatter-gather list.
|
||||||
|
* For legacy virtio, if VIRTIO_F_ANY_LAYOUT is not negotiated,
|
||||||
|
* this is the first element of the read scatter-gather list.
|
||||||
|
*/
|
||||||
struct virtio_blk_outhdr {
|
struct virtio_blk_outhdr {
|
||||||
/* VIRTIO_BLK_T* */
|
/* VIRTIO_BLK_T* */
|
||||||
__virtio32 type;
|
__virtio32 type;
|
||||||
|
|
|
@ -29,8 +29,16 @@
|
||||||
|
|
||||||
#include <linux/virtio_types.h>
|
#include <linux/virtio_types.h>
|
||||||
|
|
||||||
#define VIRTIO_SCSI_CDB_SIZE 32
|
/* Default values of the CDB and sense data size configuration fields */
|
||||||
#define VIRTIO_SCSI_SENSE_SIZE 96
|
#define VIRTIO_SCSI_CDB_DEFAULT_SIZE 32
|
||||||
|
#define VIRTIO_SCSI_SENSE_DEFAULT_SIZE 96
|
||||||
|
|
||||||
|
#ifndef VIRTIO_SCSI_CDB_SIZE
|
||||||
|
#define VIRTIO_SCSI_CDB_SIZE VIRTIO_SCSI_CDB_DEFAULT_SIZE
|
||||||
|
#endif
|
||||||
|
#ifndef VIRTIO_SCSI_SENSE_SIZE
|
||||||
|
#define VIRTIO_SCSI_SENSE_SIZE VIRTIO_SCSI_SENSE_DEFAULT_SIZE
|
||||||
|
#endif
|
||||||
|
|
||||||
/* SCSI command request, followed by data-out */
|
/* SCSI command request, followed by data-out */
|
||||||
struct virtio_scsi_cmd_req {
|
struct virtio_scsi_cmd_req {
|
||||||
|
|
|
@ -658,14 +658,30 @@ p9_virtio_create(struct p9_client *client, const char *devname, char *args)
|
||||||
static void p9_virtio_remove(struct virtio_device *vdev)
|
static void p9_virtio_remove(struct virtio_device *vdev)
|
||||||
{
|
{
|
||||||
struct virtio_chan *chan = vdev->priv;
|
struct virtio_chan *chan = vdev->priv;
|
||||||
|
unsigned long warning_time;
|
||||||
if (chan->inuse)
|
|
||||||
p9_virtio_close(chan->client);
|
|
||||||
vdev->config->del_vqs(vdev);
|
|
||||||
|
|
||||||
mutex_lock(&virtio_9p_lock);
|
mutex_lock(&virtio_9p_lock);
|
||||||
|
|
||||||
|
/* Remove self from list so we don't get new users. */
|
||||||
list_del(&chan->chan_list);
|
list_del(&chan->chan_list);
|
||||||
|
warning_time = jiffies;
|
||||||
|
|
||||||
|
/* Wait for existing users to close. */
|
||||||
|
while (chan->inuse) {
|
||||||
|
mutex_unlock(&virtio_9p_lock);
|
||||||
|
msleep(250);
|
||||||
|
if (time_after(jiffies, warning_time + 10 * HZ)) {
|
||||||
|
dev_emerg(&vdev->dev,
|
||||||
|
"p9_virtio_remove: waiting for device in use.\n");
|
||||||
|
warning_time = jiffies;
|
||||||
|
}
|
||||||
|
mutex_lock(&virtio_9p_lock);
|
||||||
|
}
|
||||||
|
|
||||||
mutex_unlock(&virtio_9p_lock);
|
mutex_unlock(&virtio_9p_lock);
|
||||||
|
|
||||||
|
vdev->config->del_vqs(vdev);
|
||||||
|
|
||||||
sysfs_remove_file(&(vdev->dev.kobj), &dev_attr_mount_tag.attr);
|
sysfs_remove_file(&(vdev->dev.kobj), &dev_attr_mount_tag.attr);
|
||||||
kobject_uevent(&(vdev->dev.kobj), KOBJ_CHANGE);
|
kobject_uevent(&(vdev->dev.kobj), KOBJ_CHANGE);
|
||||||
kfree(chan->tag);
|
kfree(chan->tag);
|
||||||
|
|
Loading…
Reference in New Issue