Commit b746f9c7 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'virtio-next-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux

Pull virtio updates from Rusty Russell:
 "Nothing really exciting: some groundwork for changing virtio endian,
  and some robustness fixes for broken virtio devices, plus minor
  tweaks"

* tag 'virtio-next-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux:
  virtio_scsi: verify if queue is broken after virtqueue_get_buf()
  x86, asmlinkage, lguest: Pass in globals into assembler statement
  virtio: mmio: fix signature checking for BE guests
  virtio_ring: adapt to notify() returning bool
  virtio_net: verify if queue is broken after virtqueue_get_buf()
  virtio_console: verify if queue is broken after virtqueue_get_buf()
  virtio_blk: verify if queue is broken after virtqueue_get_buf()
  virtio_ring: add new function virtqueue_is_broken()
  virtio_test: verify if virtqueue_kick() succeeded
  virtio_net: verify if virtqueue_kick() succeeded
  virtio_ring: let virtqueue_{kick()/notify()} return a bool
  virtio_ring: change host notification API
  virtio_config: remove virtio_config_val
  virtio: use size-based config accessors.
  virtio_config: introduce size-based accessors.
  virtio_ring: plug kmemleak false positive.
  virtio: pm: use CONFIG_PM_SLEEP instead of CONFIG_PM
parents ce6513f7 2bf4fd31
...@@ -292,6 +292,8 @@ static void virtblk_done(struct virtqueue *vq) ...@@ -292,6 +292,8 @@ static void virtblk_done(struct virtqueue *vq)
req_done = true; req_done = true;
} }
} }
if (unlikely(virtqueue_is_broken(vq)))
break;
} while (!virtqueue_enable_cb(vq)); } while (!virtqueue_enable_cb(vq));
/* In case queue is stopped waiting for more buffers. */ /* In case queue is stopped waiting for more buffers. */
if (req_done) if (req_done)
...@@ -456,18 +458,15 @@ static int virtblk_ioctl(struct block_device *bdev, fmode_t mode, ...@@ -456,18 +458,15 @@ static int virtblk_ioctl(struct block_device *bdev, fmode_t mode,
static int virtblk_getgeo(struct block_device *bd, struct hd_geometry *geo) static int virtblk_getgeo(struct block_device *bd, struct hd_geometry *geo)
{ {
struct virtio_blk *vblk = bd->bd_disk->private_data; struct virtio_blk *vblk = bd->bd_disk->private_data;
struct virtio_blk_geometry vgeo;
int err;
/* see if the host passed in geometry config */ /* see if the host passed in geometry config */
err = virtio_config_val(vblk->vdev, VIRTIO_BLK_F_GEOMETRY, if (virtio_has_feature(vblk->vdev, VIRTIO_BLK_F_GEOMETRY)) {
offsetof(struct virtio_blk_config, geometry), virtio_cread(vblk->vdev, struct virtio_blk_config,
&vgeo); geometry.cylinders, &geo->cylinders);
virtio_cread(vblk->vdev, struct virtio_blk_config,
if (!err) { geometry.heads, &geo->heads);
geo->heads = vgeo.heads; virtio_cread(vblk->vdev, struct virtio_blk_config,
geo->sectors = vgeo.sectors; geometry.sectors, &geo->sectors);
geo->cylinders = vgeo.cylinders;
} else { } else {
/* some standard values, similar to sd */ /* some standard values, similar to sd */
geo->heads = 1 << 6; geo->heads = 1 << 6;
...@@ -529,8 +528,7 @@ static void virtblk_config_changed_work(struct work_struct *work) ...@@ -529,8 +528,7 @@ static void virtblk_config_changed_work(struct work_struct *work)
goto done; goto done;
/* Host must always specify the capacity. */ /* Host must always specify the capacity. */
vdev->config->get(vdev, offsetof(struct virtio_blk_config, capacity), virtio_cread(vdev, struct virtio_blk_config, capacity, &capacity);
&capacity, sizeof(capacity));
/* If capacity is too big, truncate with warning. */ /* If capacity is too big, truncate with warning. */
if ((sector_t)capacity != capacity) { if ((sector_t)capacity != capacity) {
...@@ -608,8 +606,8 @@ static int virtblk_get_cache_mode(struct virtio_device *vdev) ...@@ -608,8 +606,8 @@ static int virtblk_get_cache_mode(struct virtio_device *vdev)
u8 writeback; u8 writeback;
int err; int err;
err = virtio_config_val(vdev, VIRTIO_BLK_F_CONFIG_WCE, err = virtio_cread_feature(vdev, VIRTIO_BLK_F_CONFIG_WCE,
offsetof(struct virtio_blk_config, wce), struct virtio_blk_config, wce,
&writeback); &writeback);
if (err) if (err)
writeback = virtio_has_feature(vdev, VIRTIO_BLK_F_WCE); writeback = virtio_has_feature(vdev, VIRTIO_BLK_F_WCE);
...@@ -642,7 +640,6 @@ virtblk_cache_type_store(struct device *dev, struct device_attribute *attr, ...@@ -642,7 +640,6 @@ virtblk_cache_type_store(struct device *dev, struct device_attribute *attr,
struct virtio_blk *vblk = disk->private_data; struct virtio_blk *vblk = disk->private_data;
struct virtio_device *vdev = vblk->vdev; struct virtio_device *vdev = vblk->vdev;
int i; int i;
u8 writeback;
BUG_ON(!virtio_has_feature(vblk->vdev, VIRTIO_BLK_F_CONFIG_WCE)); BUG_ON(!virtio_has_feature(vblk->vdev, VIRTIO_BLK_F_CONFIG_WCE));
for (i = ARRAY_SIZE(virtblk_cache_types); --i >= 0; ) for (i = ARRAY_SIZE(virtblk_cache_types); --i >= 0; )
...@@ -652,11 +649,7 @@ virtblk_cache_type_store(struct device *dev, struct device_attribute *attr, ...@@ -652,11 +649,7 @@ virtblk_cache_type_store(struct device *dev, struct device_attribute *attr,
if (i < 0) if (i < 0)
return -EINVAL; return -EINVAL;
writeback = i; virtio_cwrite8(vdev, offsetof(struct virtio_blk_config, wce), i);
vdev->config->set(vdev,
offsetof(struct virtio_blk_config, wce),
&writeback, sizeof(writeback));
virtblk_update_cache_mode(vdev); virtblk_update_cache_mode(vdev);
return count; return count;
} }
...@@ -699,8 +692,8 @@ static int virtblk_probe(struct virtio_device *vdev) ...@@ -699,8 +692,8 @@ static int virtblk_probe(struct virtio_device *vdev)
index = err; index = err;
/* We need to know how many segments before we allocate. */ /* We need to know how many segments before we allocate. */
err = virtio_config_val(vdev, VIRTIO_BLK_F_SEG_MAX, err = virtio_cread_feature(vdev, VIRTIO_BLK_F_SEG_MAX,
offsetof(struct virtio_blk_config, seg_max), struct virtio_blk_config, seg_max,
&sg_elems); &sg_elems);
/* We need at least one SG element, whatever they say. */ /* We need at least one SG element, whatever they say. */
...@@ -772,8 +765,7 @@ static int virtblk_probe(struct virtio_device *vdev) ...@@ -772,8 +765,7 @@ static int virtblk_probe(struct virtio_device *vdev)
set_disk_ro(vblk->disk, 1); set_disk_ro(vblk->disk, 1);
/* Host must always specify the capacity. */ /* Host must always specify the capacity. */
vdev->config->get(vdev, offsetof(struct virtio_blk_config, capacity), virtio_cread(vdev, struct virtio_blk_config, capacity, &cap);
&cap, sizeof(cap));
/* If capacity is too big, truncate with warning. */ /* If capacity is too big, truncate with warning. */
if ((sector_t)cap != cap) { if ((sector_t)cap != cap) {
...@@ -794,17 +786,16 @@ static int virtblk_probe(struct virtio_device *vdev) ...@@ -794,17 +786,16 @@ static int virtblk_probe(struct virtio_device *vdev)
/* Host can optionally specify maximum segment size and number of /* Host can optionally specify maximum segment size and number of
* segments. */ * segments. */
err = virtio_config_val(vdev, VIRTIO_BLK_F_SIZE_MAX, err = virtio_cread_feature(vdev, VIRTIO_BLK_F_SIZE_MAX,
offsetof(struct virtio_blk_config, size_max), struct virtio_blk_config, size_max, &v);
&v);
if (!err) if (!err)
blk_queue_max_segment_size(q, v); blk_queue_max_segment_size(q, v);
else else
blk_queue_max_segment_size(q, -1U); blk_queue_max_segment_size(q, -1U);
/* Host can optionally specify the block size of the device */ /* Host can optionally specify the block size of the device */
err = virtio_config_val(vdev, VIRTIO_BLK_F_BLK_SIZE, err = virtio_cread_feature(vdev, VIRTIO_BLK_F_BLK_SIZE,
offsetof(struct virtio_blk_config, blk_size), struct virtio_blk_config, blk_size,
&blk_size); &blk_size);
if (!err) if (!err)
blk_queue_logical_block_size(q, blk_size); blk_queue_logical_block_size(q, blk_size);
...@@ -812,27 +803,27 @@ static int virtblk_probe(struct virtio_device *vdev) ...@@ -812,27 +803,27 @@ static int virtblk_probe(struct virtio_device *vdev)
blk_size = queue_logical_block_size(q); blk_size = queue_logical_block_size(q);
/* Use topology information if available */ /* Use topology information if available */
err = virtio_config_val(vdev, VIRTIO_BLK_F_TOPOLOGY, err = virtio_cread_feature(vdev, VIRTIO_BLK_F_TOPOLOGY,
offsetof(struct virtio_blk_config, physical_block_exp), struct virtio_blk_config, physical_block_exp,
&physical_block_exp); &physical_block_exp);
if (!err && physical_block_exp) if (!err && physical_block_exp)
blk_queue_physical_block_size(q, blk_queue_physical_block_size(q,
blk_size * (1 << physical_block_exp)); blk_size * (1 << physical_block_exp));
err = virtio_config_val(vdev, VIRTIO_BLK_F_TOPOLOGY, err = virtio_cread_feature(vdev, VIRTIO_BLK_F_TOPOLOGY,
offsetof(struct virtio_blk_config, alignment_offset), struct virtio_blk_config, alignment_offset,
&alignment_offset); &alignment_offset);
if (!err && alignment_offset) if (!err && alignment_offset)
blk_queue_alignment_offset(q, blk_size * alignment_offset); blk_queue_alignment_offset(q, blk_size * alignment_offset);
err = virtio_config_val(vdev, VIRTIO_BLK_F_TOPOLOGY, err = virtio_cread_feature(vdev, VIRTIO_BLK_F_TOPOLOGY,
offsetof(struct virtio_blk_config, min_io_size), struct virtio_blk_config, min_io_size,
&min_io_size); &min_io_size);
if (!err && min_io_size) if (!err && min_io_size)
blk_queue_io_min(q, blk_size * min_io_size); blk_queue_io_min(q, blk_size * min_io_size);
err = virtio_config_val(vdev, VIRTIO_BLK_F_TOPOLOGY, err = virtio_cread_feature(vdev, VIRTIO_BLK_F_TOPOLOGY,
offsetof(struct virtio_blk_config, opt_io_size), struct virtio_blk_config, opt_io_size,
&opt_io_size); &opt_io_size);
if (!err && opt_io_size) if (!err && opt_io_size)
blk_queue_io_opt(q, blk_size * opt_io_size); blk_queue_io_opt(q, blk_size * opt_io_size);
...@@ -899,7 +890,7 @@ static void virtblk_remove(struct virtio_device *vdev) ...@@ -899,7 +890,7 @@ static void virtblk_remove(struct virtio_device *vdev)
ida_simple_remove(&vd_index_ida, index); ida_simple_remove(&vd_index_ida, index);
} }
#ifdef CONFIG_PM #ifdef CONFIG_PM_SLEEP
static int virtblk_freeze(struct virtio_device *vdev) static int virtblk_freeze(struct virtio_device *vdev)
{ {
struct virtio_blk *vblk = vdev->priv; struct virtio_blk *vblk = vdev->priv;
...@@ -959,7 +950,7 @@ static struct virtio_driver virtio_blk = { ...@@ -959,7 +950,7 @@ static struct virtio_driver virtio_blk = {
.probe = virtblk_probe, .probe = virtblk_probe,
.remove = virtblk_remove, .remove = virtblk_remove,
.config_changed = virtblk_config_changed, .config_changed = virtblk_config_changed,
#ifdef CONFIG_PM #ifdef CONFIG_PM_SLEEP
.freeze = virtblk_freeze, .freeze = virtblk_freeze,
.restore = virtblk_restore, .restore = virtblk_restore,
#endif #endif
......
...@@ -133,7 +133,7 @@ static void virtrng_remove(struct virtio_device *vdev) ...@@ -133,7 +133,7 @@ static void virtrng_remove(struct virtio_device *vdev)
remove_common(vdev); remove_common(vdev);
} }
#ifdef CONFIG_PM #ifdef CONFIG_PM_SLEEP
static int virtrng_freeze(struct virtio_device *vdev) static int virtrng_freeze(struct virtio_device *vdev)
{ {
remove_common(vdev); remove_common(vdev);
...@@ -157,7 +157,7 @@ static struct virtio_driver virtio_rng_driver = { ...@@ -157,7 +157,7 @@ static struct virtio_driver virtio_rng_driver = {
.id_table = id_table, .id_table = id_table,
.probe = virtrng_probe, .probe = virtrng_probe,
.remove = virtrng_remove, .remove = virtrng_remove,
#ifdef CONFIG_PM #ifdef CONFIG_PM_SLEEP
.freeze = virtrng_freeze, .freeze = virtrng_freeze,
.restore = virtrng_restore, .restore = virtrng_restore,
#endif #endif
......
...@@ -577,7 +577,8 @@ static ssize_t __send_control_msg(struct ports_device *portdev, u32 port_id, ...@@ -577,7 +577,8 @@ static ssize_t __send_control_msg(struct ports_device *portdev, u32 port_id,
spin_lock(&portdev->c_ovq_lock); spin_lock(&portdev->c_ovq_lock);
if (virtqueue_add_outbuf(vq, sg, 1, &cpkt, GFP_ATOMIC) == 0) { if (virtqueue_add_outbuf(vq, sg, 1, &cpkt, GFP_ATOMIC) == 0) {
virtqueue_kick(vq); virtqueue_kick(vq);
while (!virtqueue_get_buf(vq, &len)) while (!virtqueue_get_buf(vq, &len)
&& !virtqueue_is_broken(vq))
cpu_relax(); cpu_relax();
} }
spin_unlock(&portdev->c_ovq_lock); spin_unlock(&portdev->c_ovq_lock);
...@@ -650,7 +651,8 @@ static ssize_t __send_to_port(struct port *port, struct scatterlist *sg, ...@@ -650,7 +651,8 @@ static ssize_t __send_to_port(struct port *port, struct scatterlist *sg,
* we need to kmalloc a GFP_ATOMIC buffer each time the * we need to kmalloc a GFP_ATOMIC buffer each time the
* console driver writes something out. * console driver writes something out.
*/ */
while (!virtqueue_get_buf(out_vq, &len)) while (!virtqueue_get_buf(out_vq, &len)
&& !virtqueue_is_broken(out_vq))
cpu_relax(); cpu_relax();
done: done:
spin_unlock_irqrestore(&port->outvq_lock, flags); spin_unlock_irqrestore(&port->outvq_lock, flags);
...@@ -1837,12 +1839,8 @@ static void config_intr(struct virtio_device *vdev) ...@@ -1837,12 +1839,8 @@ static void config_intr(struct virtio_device *vdev)
struct port *port; struct port *port;
u16 rows, cols; u16 rows, cols;
vdev->config->get(vdev, virtio_cread(vdev, struct virtio_console_config, cols, &cols);
offsetof(struct virtio_console_config, cols), virtio_cread(vdev, struct virtio_console_config, rows, &rows);
&cols, sizeof(u16));
vdev->config->get(vdev,
offsetof(struct virtio_console_config, rows),
&rows, sizeof(u16));
port = find_port_by_id(portdev, 0); port = find_port_by_id(portdev, 0);
set_console_size(port, rows, cols); set_console_size(port, rows, cols);
...@@ -2014,9 +2012,8 @@ static int virtcons_probe(struct virtio_device *vdev) ...@@ -2014,9 +2012,8 @@ static int virtcons_probe(struct virtio_device *vdev)
/* Don't test MULTIPORT at all if we're rproc: not a valid feature! */ /* Don't test MULTIPORT at all if we're rproc: not a valid feature! */
if (!is_rproc_serial(vdev) && if (!is_rproc_serial(vdev) &&
virtio_config_val(vdev, VIRTIO_CONSOLE_F_MULTIPORT, virtio_cread_feature(vdev, VIRTIO_CONSOLE_F_MULTIPORT,
offsetof(struct virtio_console_config, struct virtio_console_config, max_nr_ports,
max_nr_ports),
&portdev->config.max_nr_ports) == 0) { &portdev->config.max_nr_ports) == 0) {
multiport = true; multiport = true;
} }
...@@ -2142,7 +2139,7 @@ static struct virtio_device_id rproc_serial_id_table[] = { ...@@ -2142,7 +2139,7 @@ static struct virtio_device_id rproc_serial_id_table[] = {
static unsigned int rproc_serial_features[] = { static unsigned int rproc_serial_features[] = {
}; };
#ifdef CONFIG_PM #ifdef CONFIG_PM_SLEEP
static int virtcons_freeze(struct virtio_device *vdev) static int virtcons_freeze(struct virtio_device *vdev)
{ {
struct ports_device *portdev; struct ports_device *portdev;
...@@ -2220,7 +2217,7 @@ static struct virtio_driver virtio_console = { ...@@ -2220,7 +2217,7 @@ static struct virtio_driver virtio_console = {
.probe = virtcons_probe, .probe = virtcons_probe,
.remove = virtcons_remove, .remove = virtcons_remove,
.config_changed = config_intr, .config_changed = config_intr,
#ifdef CONFIG_PM #ifdef CONFIG_PM_SLEEP
.freeze = virtcons_freeze, .freeze = virtcons_freeze,
.restore = virtcons_restore, .restore = virtcons_restore,
#endif #endif
......
...@@ -229,7 +229,7 @@ struct lguest_vq_info { ...@@ -229,7 +229,7 @@ struct lguest_vq_info {
* make a hypercall. We hand the physical address of the virtqueue so the Host * make a hypercall. We hand the physical address of the virtqueue so the Host
* knows which virtqueue we're talking about. * knows which virtqueue we're talking about.
*/ */
static void lg_notify(struct virtqueue *vq) static bool lg_notify(struct virtqueue *vq)
{ {
/* /*
* We store our virtqueue information in the "priv" pointer of the * We store our virtqueue information in the "priv" pointer of the
...@@ -238,6 +238,7 @@ static void lg_notify(struct virtqueue *vq) ...@@ -238,6 +238,7 @@ static void lg_notify(struct virtqueue *vq)
struct lguest_vq_info *lvq = vq->priv; struct lguest_vq_info *lvq = vq->priv;
hcall(LHCALL_NOTIFY, lvq->config.pfn << PAGE_SHIFT, 0, 0, 0); hcall(LHCALL_NOTIFY, lvq->config.pfn << PAGE_SHIFT, 0, 0, 0);
return true;
} }
/* An extern declaration inside a C file is bad form. Don't do it. */ /* An extern declaration inside a C file is bad form. Don't do it. */
......
...@@ -157,7 +157,7 @@ static void run_guest_once(struct lg_cpu *cpu, struct lguest_pages *pages) ...@@ -157,7 +157,7 @@ static void run_guest_once(struct lg_cpu *cpu, struct lguest_pages *pages)
* stack, then the address of this call. This stack layout happens to * stack, then the address of this call. This stack layout happens to
* exactly match the stack layout created by an interrupt... * exactly match the stack layout created by an interrupt...
*/ */
asm volatile("pushf; lcall *lguest_entry" asm volatile("pushf; lcall *%4"
/* /*
* This is how we tell GCC that %eax ("a") and %ebx ("b") * This is how we tell GCC that %eax ("a") and %ebx ("b")
* are changed by this routine. The "=" means output. * are changed by this routine. The "=" means output.
...@@ -169,7 +169,9 @@ static void run_guest_once(struct lg_cpu *cpu, struct lguest_pages *pages) ...@@ -169,7 +169,9 @@ static void run_guest_once(struct lg_cpu *cpu, struct lguest_pages *pages)
* physical address of the Guest's top-level page * physical address of the Guest's top-level page
* directory. * directory.
*/ */
: "0"(pages), "1"(__pa(cpu->lg->pgdirs[cpu->cpu_pgd].pgdir)) : "0"(pages),
"1"(__pa(cpu->lg->pgdirs[cpu->cpu_pgd].pgdir)),
"m"(lguest_entry)
/* /*
* We tell gcc that all these registers could change, * We tell gcc that all these registers could change,
* which means we don't have to save and restore them in * which means we don't have to save and restore them in
......
...@@ -686,18 +686,19 @@ static int cfv_probe(struct virtio_device *vdev) ...@@ -686,18 +686,19 @@ static int cfv_probe(struct virtio_device *vdev)
goto err; goto err;
/* Get the CAIF configuration from virtio config space, if available */ /* Get the CAIF configuration from virtio config space, if available */
#define GET_VIRTIO_CONFIG_OPS(_v, _var, _f) \
((_v)->config->get(_v, offsetof(struct virtio_caif_transf_config, _f), \
&_var, \
FIELD_SIZEOF(struct virtio_caif_transf_config, _f)))
if (vdev->config->get) { if (vdev->config->get) {
GET_VIRTIO_CONFIG_OPS(vdev, cfv->tx_hr, headroom); virtio_cread(vdev, struct virtio_caif_transf_config, headroom,
GET_VIRTIO_CONFIG_OPS(vdev, cfv->rx_hr, headroom); &cfv->tx_hr);
GET_VIRTIO_CONFIG_OPS(vdev, cfv->tx_tr, tailroom); virtio_cread(vdev, struct virtio_caif_transf_config, headroom,
GET_VIRTIO_CONFIG_OPS(vdev, cfv->rx_tr, tailroom); &cfv->rx_hr);
GET_VIRTIO_CONFIG_OPS(vdev, cfv->mtu, mtu); virtio_cread(vdev, struct virtio_caif_transf_config, tailroom,
GET_VIRTIO_CONFIG_OPS(vdev, cfv->mru, mtu); &cfv->tx_tr);
virtio_cread(vdev, struct virtio_caif_transf_config, tailroom,
&cfv->rx_tr);
virtio_cread(vdev, struct virtio_caif_transf_config, mtu,
&cfv->mtu);
virtio_cread(vdev, struct virtio_caif_transf_config, mtu,
&cfv->mru);
} else { } else {
cfv->tx_hr = CFV_DEF_HEADROOM; cfv->tx_hr = CFV_DEF_HEADROOM;
cfv->rx_hr = CFV_DEF_HEADROOM; cfv->rx_hr = CFV_DEF_HEADROOM;
......
...@@ -591,7 +591,8 @@ static bool try_fill_recv(struct receive_queue *rq, gfp_t gfp) ...@@ -591,7 +591,8 @@ static bool try_fill_recv(struct receive_queue *rq, gfp_t gfp)
} while (rq->vq->num_free); } while (rq->vq->num_free);
if (unlikely(rq->num > rq->max)) if (unlikely(rq->num > rq->max))
rq->max = rq->num; rq->max = rq->num;
virtqueue_kick(rq->vq); if (unlikely(!virtqueue_kick(rq->vq)))
return false;
return !oom; return !oom;
} }
...@@ -797,7 +798,7 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -797,7 +798,7 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
err = xmit_skb(sq, skb); err = xmit_skb(sq, skb);
/* This should not happen! */ /* This should not happen! */
if (unlikely(err)) { if (unlikely(err) || unlikely(!virtqueue_kick(sq->vq))) {
dev->stats.tx_fifo_errors++; dev->stats.tx_fifo_errors++;
if (net_ratelimit()) if (net_ratelimit())
dev_warn(&dev->dev, dev_warn(&dev->dev,
...@@ -806,7 +807,6 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -806,7 +807,6 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
kfree_skb(skb); kfree_skb(skb);
return NETDEV_TX_OK; return NETDEV_TX_OK;
} }
virtqueue_kick(sq->vq);
/* Don't wait up for transmitted skbs to be freed. */ /* Don't wait up for transmitted skbs to be freed. */
skb_orphan(skb); skb_orphan(skb);
...@@ -865,12 +865,14 @@ static bool virtnet_send_command(struct virtnet_info *vi, u8 class, u8 cmd, ...@@ -865,12 +865,14 @@ static bool virtnet_send_command(struct virtnet_info *vi, u8 class, u8 cmd,
BUG_ON(virtqueue_add_sgs(vi->cvq, sgs, out_num, in_num, vi, GFP_ATOMIC) BUG_ON(virtqueue_add_sgs(vi->cvq, sgs, out_num, in_num, vi, GFP_ATOMIC)
< 0); < 0);
virtqueue_kick(vi->cvq); if (unlikely(!virtqueue_kick(vi->cvq)))
return status == VIRTIO_NET_OK;
/* Spin for a response, the kick causes an ioport write, trapping /* Spin for a response, the kick causes an ioport write, trapping
* into the hypervisor, so the request should be handled immediately. * into the hypervisor, so the request should be handled immediately.
*/ */
while (!virtqueue_get_buf(vi->cvq, &tmp)) while (!virtqueue_get_buf(vi->cvq, &tmp) &&
!virtqueue_is_broken(vi->cvq))
cpu_relax(); cpu_relax();
return status == VIRTIO_NET_OK; return status == VIRTIO_NET_OK;
...@@ -898,8 +900,13 @@ static int virtnet_set_mac_address(struct net_device *dev, void *p) ...@@ -898,8 +900,13 @@ static int virtnet_set_mac_address(struct net_device *dev, void *p)
return -EINVAL; return -EINVAL;
} }
} else if (virtio_has_feature(vdev, VIRTIO_NET_F_MAC)) { } else if (virtio_has_feature(vdev, VIRTIO_NET_F_MAC)) {
vdev->config->set(vdev, offsetof(struct virtio_net_config, mac), unsigned int i;
addr->sa_data, dev->addr_len);
/* Naturally, this has an atomicity problem. */
for (i = 0; i < dev->addr_len; i++)
virtio_cwrite8(vdev,
offsetof(struct virtio_net_config, mac) +
i, addr->sa_data[i]);
} }
eth_commit_mac_addr_change(dev, p); eth_commit_mac_addr_change(dev, p);
...@@ -1281,9 +1288,8 @@ static void virtnet_config_changed_work(struct work_struct *work) ...@@ -1281,9 +1288,8 @@ static void virtnet_config_changed_work(struct work_struct *work)
if (!vi->config_enable) if (!vi->config_enable)
goto done; goto done;
if (virtio_config_val(vi->vdev, VIRTIO_NET_F_STATUS, if (virtio_cread_feature(vi->vdev, VIRTIO_NET_F_STATUS,
offsetof(struct virtio_net_config, status), struct virtio_net_config, status, &v) < 0)
&v) < 0)
goto done; goto done;
if (v & VIRTIO_NET_S_ANNOUNCE) { if (v & VIRTIO_NET_S_ANNOUNCE) {
...@@ -1507,9 +1513,9 @@ static int virtnet_probe(struct virtio_device *vdev) ...@@ -1507,9 +1513,9 @@ static int virtnet_probe(struct virtio_device *vdev)
u16 max_queue_pairs; u16 max_queue_pairs;
/* Find if host supports multiqueue virtio_net device */ /* Find if host supports multiqueue virtio_net device */
err = virtio_config_val(vdev, VIRTIO_NET_F_MQ, err = virtio_cread_feature(vdev, VIRTIO_NET_F_MQ,
offsetof(struct virtio_net_config, struct virtio_net_config,
max_virtqueue_pairs), &max_queue_pairs); max_virtqueue_pairs, &max_queue_pairs);
/* We need at least 2 queue's */ /* We need at least 2 queue's */
if (err || max_queue_pairs < VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN || if (err || max_queue_pairs < VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN ||
...@@ -1561,9 +1567,11 @@ static int virtnet_probe(struct virtio_device *vdev) ...@@ -1561,9 +1567,11 @@ static int virtnet_probe(struct virtio_device *vdev)
dev->vlan_features = dev->features; dev->vlan_features = dev->features;
/* Configuration may specify what MAC to use. Otherwise random. */ /* Configuration may specify what MAC to use. Otherwise random. */
if (virtio_config_val_len(vdev, VIRTIO_NET_F_MAC, if (virtio_has_feature(vdev, VIRTIO_NET_F_MAC))
virtio_cread_bytes(vdev,
offsetof(struct virtio_net_config, mac), offsetof(struct virtio_net_config, mac),
dev->dev_addr, dev->addr_len) < 0) dev->dev_addr, dev->addr_len);
else
eth_hw_addr_random(dev); eth_hw_addr_random(dev);
/* Set up our device-specific information */ /* Set up our device-specific information */
...@@ -1704,7 +1712,7 @@ static void virtnet_remove(struct virtio_device *vdev) ...@@ -1704,7 +1712,7 @@ static void virtnet_remove(struct virtio_device *vdev)
free_netdev(vi->dev); free_netdev(vi->dev);
} }
#ifdef CONFIG_PM #ifdef CONFIG_PM_SLEEP
static int virtnet_freeze(struct virtio_device *vdev) static int virtnet_freeze(struct virtio_device *vdev)
{ {
struct virtnet_info *vi = vdev->priv; struct virtnet_info *vi = vdev->priv;
...@@ -1795,7 +1803,7 @@ static struct virtio_driver virtio_net_driver = { ...@@ -1795,7 +1803,7 @@ static struct virtio_driver virtio_net_driver = {
.probe = virtnet_probe, .probe = virtnet_probe,
.remove = virtnet_remove, .remove = virtnet_remove,
.config_changed = virtnet_config_changed, .config_changed = virtnet_config_changed,
#ifdef CONFIG_PM #ifdef CONFIG_PM_SLEEP
.freeze = virtnet_freeze, .freeze = virtnet_freeze,
.restore = virtnet_restore, .restore = virtnet_restore,
#endif #endif
......
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
#include "remoteproc_internal.h" #include "remoteproc_internal.h"
/* kick the remote processor, and let it know which virtqueue to poke at */ /* kick the remote processor, and let it know which virtqueue to poke at */
static void rproc_virtio_notify(struct virtqueue *vq) static bool rproc_virtio_notify(struct virtqueue *vq)
{ {
struct rproc_vring *rvring = vq->priv; struct rproc_vring *rvring = vq->priv;
struct rproc *rproc = rvring->rvdev->rproc; struct rproc *rproc = rvring->rvdev->rproc;
...@@ -39,6 +39,7 @@ static void rproc_virtio_notify(struct virtqueue *vq) ...@@ -39,6 +39,7 @@ static void rproc_virtio_notify(struct virtqueue *vq)
dev_dbg(&rproc->dev, "kicking vq index: %d\n", notifyid); dev_dbg(&rproc->dev, "kicking vq index: %d\n", notifyid);
rproc->ops->kick(rproc, notifyid); rproc->ops->kick(rproc, notifyid);
return true;
} }
/** /**
......
...@@ -166,11 +166,15 @@ static void kvm_reset(struct virtio_device *vdev) ...@@ -166,11 +166,15 @@ static void kvm_reset(struct virtio_device *vdev)
* make a hypercall. We hand the address of the virtqueue so the Host * make a hypercall. We hand the address of the virtqueue so the Host
* knows which virtqueue we're talking about. * knows which virtqueue we're talking about.
*/ */
static void kvm_notify(struct virtqueue *vq) static bool kvm_notify(struct virtqueue *vq)
{ {
long rc;
struct kvm_vqconfig *config = vq->priv; struct kvm_vqconfig *config = vq->priv;
kvm_hypercall1(KVM_S390_VIRTIO_NOTIFY, config->address); rc = kvm_hypercall1(KVM_S390_VIRTIO_NOTIFY, config->address);
if (rc < 0)
return false;
return true;
} }
/* /*
......
...@@ -162,7 +162,7 @@ static inline long do_kvm_notify(struct subchannel_id schid, ...@@ -162,7 +162,7 @@ static inline long do_kvm_notify(struct subchannel_id schid,
return __rc; return __rc;
} }
static void virtio_ccw_kvm_notify(struct virtqueue *vq) static bool virtio_ccw_kvm_notify(struct virtqueue *vq)
{ {
struct virtio_ccw_vq_info *info = vq->priv; struct virtio_ccw_vq_info *info = vq->priv;
struct virtio_ccw_device *vcdev; struct virtio_ccw_device *vcdev;
...@@ -171,6 +171,9 @@ static void virtio_ccw_kvm_notify(struct virtqueue *vq) ...@@ -171,6 +171,9 @@ static void virtio_ccw_kvm_notify(struct virtqueue *vq)
vcdev = to_vc_device(info->vq->vdev); vcdev = to_vc_device(info->vq->vdev);
ccw_device_get_schid(vcdev->cdev, &schid); ccw_device_get_schid(vcdev->cdev, &schid);
info->cookie = do_kvm_notify(schid, vq->index, info->cookie); info->cookie = do_kvm_notify(schid, vq->index, info->cookie);
if (info->cookie < 0)
return false;
return true;
} }
static int virtio_ccw_read_vq_conf(struct virtio_ccw_device *vcdev, static int virtio_ccw_read_vq_conf(struct virtio_ccw_device *vcdev,
......
...@@ -224,6 +224,9 @@ static void virtscsi_vq_done(struct virtio_scsi *vscsi, ...@@ -224,6 +224,9 @@ static void virtscsi_vq_done(struct virtio_scsi *vscsi,
virtqueue_disable_cb(vq); virtqueue_disable_cb(vq);
while ((buf = virtqueue_get_buf(vq, &len)) != NULL) while ((buf = virtqueue_get_buf(vq, &len)) != NULL)
fn(vscsi, buf); fn(vscsi, buf);
if (unlikely(virtqueue_is_broken(vq)))
break;
} while (!virtqueue_enable_cb(vq)); } while (!virtqueue_enable_cb(vq));
spin_unlock_irqrestore(&virtscsi_vq->vq_lock, flags); spin_unlock_irqrestore(&virtscsi_vq->vq_lock, flags);
} }
...@@ -710,19 +713,15 @@ static struct scsi_host_template virtscsi_host_template_multi = { ...@@ -710,19 +713,15 @@ static struct scsi_host_template virtscsi_host_template_multi = {
#define virtscsi_config_get(vdev, fld) \ #define virtscsi_config_get(vdev, fld) \
({ \ ({ \
typeof(((struct virtio_scsi_config *)0)->fld) __val; \ typeof(((struct virtio_scsi_config *)0)->fld) __val; \
vdev->config->get(vdev, \ virtio_cread(vdev, struct virtio_scsi_config, fld, &__val); \
offsetof(struct virtio_scsi_config, fld), \
&__val, sizeof(__val)); \
__val; \ __val; \
}) })
#define virtscsi_config_set(vdev, fld, val) \ #define virtscsi_config_set(vdev, fld, val) \
(void)({ \ do { \
typeof(((struct virtio_scsi_config *)0)->fld) __val = (val); \ typeof(((struct virtio_scsi_config *)0)->fld) __val = (val); \
vdev->config->set(vdev, \ virtio_cwrite(vdev, struct virtio_scsi_config, fld, &__val); \
offsetof(struct virtio_scsi_config, fld), \ } while(0)
&__val, sizeof(__val)); \
})
static void __virtscsi_set_affinity(struct virtio_scsi *vscsi, bool affinity) static void __virtscsi_set_affinity(struct virtio_scsi *vscsi, bool affinity)
{ {
...@@ -954,7 +953,7 @@ static void virtscsi_remove(struct virtio_device *vdev) ...@@ -954,7 +953,7 @@ static void virtscsi_remove(struct virtio_device *vdev)
scsi_host_put(shost); scsi_host_put(shost);
} }
#ifdef CONFIG_PM #ifdef CONFIG_PM_SLEEP
static int virtscsi_freeze(struct virtio_device *vdev) static int virtscsi_freeze(struct virtio_device *vdev)
{ {
virtscsi_remove_vqs(vdev); virtscsi_remove_vqs(vdev);
...@@ -988,7 +987,7 @@ static struct virtio_driver virtio_scsi_driver = { ...@@ -988,7 +987,7 @@ static struct virtio_driver virtio_scsi_driver = {
.id_table = id_table, .id_table = id_table,
.probe = virtscsi_probe, .probe = virtscsi_probe,
.scan = virtscsi_scan, .scan = virtscsi_scan,
#ifdef CONFIG_PM #ifdef CONFIG_PM_SLEEP
.freeze = virtscsi_freeze, .freeze = virtscsi_freeze,
.restore = virtscsi_restore, .restore = virtscsi_restore,
#endif #endif
......
...@@ -275,9 +275,8 @@ static inline s64 towards_target(struct virtio_balloon *vb) ...@@ -275,9 +275,8 @@ static inline s64 towards_target(struct virtio_balloon *vb)
__le32 v; __le32 v;
s64 target; s64 target;
vb->vdev->config->get(vb->vdev, virtio_cread(vb->vdev, struct virtio_balloon_config, num_pages, &v);
offsetof(struct virtio_balloon_config, num_pages),
&v, sizeof(v));
target = le32_to_cpu(v); target = le32_to_cpu(v);
return target - vb->num_pages; return target - vb->num_pages;
} }
...@@ -286,9 +285,8 @@ static void update_balloon_size(struct virtio_balloon *vb) ...@@ -286,9 +285,8 @@ static void update_balloon_size(struct virtio_balloon *vb)
{ {
__le32 actual = cpu_to_le32(vb->num_pages); __le32 actual = cpu_to_le32(vb->num_pages);
vb->vdev->config->set(vb->vdev, virtio_cwrite(vb->vdev, struct virtio_balloon_config, num_pages,
offsetof(struct virtio_balloon_config, actual), &actual);
&actual, sizeof(actual));
} }
static int balloon(void *_vballoon) static int balloon(void *_vballoon)
...@@ -513,7 +511,7 @@ static void virtballoon_remove(struct virtio_device *vdev) ...@@ -513,7 +511,7 @@ static void virtballoon_remove(struct virtio_device *vdev)
kfree(vb); kfree(vb);
} }
#ifdef CONFIG_PM #ifdef CONFIG_PM_SLEEP
static int virtballoon_freeze(struct virtio_device *vdev) static int virtballoon_freeze(struct virtio_device *vdev)
{ {
struct virtio_balloon *vb = vdev->priv; struct virtio_balloon *vb = vdev->priv;
...@@ -556,7 +554,7 @@ static struct virtio_driver virtio_balloon_driver = { ...@@ -556,7 +554,7 @@ static struct virtio_driver virtio_balloon_driver = {
.probe = virtballoon_probe, .probe = virtballoon_probe,
.remove = virtballoon_remove, .remove = virtballoon_remove,
.config_changed = virtballoon_changed, .config_changed = virtballoon_changed,
#ifdef CONFIG_PM #ifdef CONFIG_PM_SLEEP
.freeze = virtballoon_freeze, .freeze = virtballoon_freeze,
.restore = virtballoon_restore, .restore = virtballoon_restore,
#endif #endif
......
...@@ -219,13 +219,14 @@ static void vm_reset(struct virtio_device *vdev) ...@@ -219,13 +219,14 @@ static void vm_reset(struct virtio_device *vdev)
/* Transport interface */ /* Transport interface */
/* the notify function used when creating a virt queue */ /* the notify function used when creating a virt queue */
static void vm_notify(struct virtqueue *vq) static bool vm_notify(struct virtqueue *vq)
{ {
struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vq->vdev); struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vq->vdev);
/* We write the queue's selector into the notification register to /* We write the queue's selector into the notification register to
* signal the other end */ * signal the other end */
writel(vq->index, vm_dev->base + VIRTIO_MMIO_QUEUE_NOTIFY); writel(vq->index, vm_dev->base + VIRTIO_MMIO_QUEUE_NOTIFY);
return true;
} }
/* Notify all virtqueues on an interrupt. */ /* Notify all virtqueues on an interrupt. */
...@@ -470,7 +471,7 @@ static int virtio_mmio_probe(struct platform_device *pdev) ...@@ -470,7 +471,7 @@ static int virtio_mmio_probe(struct platform_device *pdev)
/* Check magic value */ /* Check magic value */
magic = readl(vm_dev->base + VIRTIO_MMIO_MAGIC_VALUE); magic = readl(vm_dev->base + VIRTIO_MMIO_MAGIC_VALUE);
if (memcmp(&magic, "virt", 4) != 0) { if (magic != ('v' | 'i' << 8 | 'r' << 16 | 't' << 24)) {
dev_warn(&pdev->dev, "Wrong magic value 0x%08lx!\n", magic); dev_warn(&pdev->dev, "Wrong magic value 0x%08lx!\n", magic);
return -ENODEV; return -ENODEV;
} }
......
...@@ -197,13 +197,14 @@ static void vp_reset(struct virtio_device *vdev) ...@@ -197,13 +197,14 @@ static void vp_reset(struct virtio_device *vdev)
} }
/* the notify function used when creating a virt queue */ /* the notify function used when creating a virt queue */
static void vp_notify(struct virtqueue *vq) static bool vp_notify(struct virtqueue *vq)
{ {
struct virtio_pci_device *vp_dev = to_vp_device(vq->vdev); struct virtio_pci_device *vp_dev = to_vp_device(vq->vdev);
/* we write the queue's selector into the notification register to /* we write the queue's selector into the notification register to
* signal the other end */ * signal the other end */
iowrite16(vq->index, vp_dev->ioaddr + VIRTIO_PCI_QUEUE_NOTIFY); iowrite16(vq->index, vp_dev->ioaddr + VIRTIO_PCI_QUEUE_NOTIFY);
return true;
} }
/* Handle a configuration change: Tell driver if it wants to know. */ /* Handle a configuration change: Tell driver if it wants to know. */
......
...@@ -81,7 +81,7 @@ struct vring_virtqueue ...@@ -81,7 +81,7 @@ struct vring_virtqueue
u16 last_used_idx; u16 last_used_idx;
/* How to notify other side. FIXME: commonalize hcalls! */ /* How to notify other side. FIXME: commonalize hcalls! */
void (*notify)(struct virtqueue *vq); bool (*notify)(struct virtqueue *vq);
#ifdef DEBUG #ifdef DEBUG
/* They're supposed to lock for us. */ /* They're supposed to lock for us. */
...@@ -173,6 +173,8 @@ static inline int vring_add_indirect(struct vring_virtqueue *vq, ...@@ -173,6 +173,8 @@ static inline int vring_add_indirect(struct vring_virtqueue *vq,
head = vq->free_head; head = vq->free_head;
vq->vring.desc[head].flags = VRING_DESC_F_INDIRECT; vq->vring.desc[head].flags = VRING_DESC_F_INDIRECT;
vq->vring.desc[head].addr = virt_to_phys(desc); vq->vring.desc[head].addr = virt_to_phys(desc);
/* kmemleak gives a false positive, as it's hidden by virt_to_phys */
kmemleak_ignore(desc);
vq->vring.desc[head].len = i * sizeof(struct vring_desc); vq->vring.desc[head].len = i * sizeof(struct vring_desc);
/* Update free pointer */ /* Update free pointer */
...@@ -428,13 +430,22 @@ EXPORT_SYMBOL_GPL(virtqueue_kick_prepare); ...@@ -428,13 +430,22 @@ EXPORT_SYMBOL_GPL(virtqueue_kick_prepare);
* @vq: the struct virtqueue * @vq: the struct virtqueue
* *
* This does not need to be serialized. * This does not need to be serialized.
*
* Returns false if host notify failed or queue is broken, otherwise true.
*/ */
void virtqueue_notify(struct virtqueue *_vq) bool virtqueue_notify(struct virtqueue *_vq)
{ {
struct vring_virtqueue *vq = to_vvq(_vq); struct vring_virtqueue *vq = to_vvq(_vq);
if (unlikely(vq->broken))
return false;
/* Prod other side to tell it about changes. */ /* Prod other side to tell it about changes. */
vq->notify(_vq); if (!vq->notify(_vq)) {
vq->broken = true;
return false;
}
return true;
} }
EXPORT_SYMBOL_GPL(virtqueue_notify); EXPORT_SYMBOL_GPL(virtqueue_notify);
...@@ -447,11 +458,14 @@ EXPORT_SYMBOL_GPL(virtqueue_notify); ...@@ -447,11 +458,14 @@ EXPORT_SYMBOL_GPL(virtqueue_notify);
* *
* Caller must ensure we don't call this with other virtqueue * Caller must ensure we don't call this with other virtqueue
* operations at the same time (except where noted). * operations at the same time (except where noted).
*
* Returns false if kick failed, otherwise true.
*/ */
void virtqueue_kick(struct virtqueue *vq) bool virtqueue_kick(struct virtqueue *vq)
{ {
if (virtqueue_kick_prepare(vq)) if (virtqueue_kick_prepare(vq))
virtqueue_notify(vq); return virtqueue_notify(vq);
return true;
} }
EXPORT_SYMBOL_GPL(virtqueue_kick); EXPORT_SYMBOL_GPL(virtqueue_kick);
...@@ -742,7 +756,7 @@ struct virtqueue *vring_new_virtqueue(unsigned int index, ...@@ -742,7 +756,7 @@ struct virtqueue *vring_new_virtqueue(unsigned int index,
struct virtio_device *vdev, struct virtio_device *vdev,
bool weak_barriers, bool weak_barriers,
void *pages, void *pages,
void (*notify)(struct virtqueue *), bool (*notify)(struct virtqueue *),
void (*callback)(struct virtqueue *), void (*callback)(struct virtqueue *),
const char *name) const char *name)
{ {
...@@ -837,4 +851,12 @@ unsigned int virtqueue_get_vring_size(struct virtqueue *_vq) ...@@ -837,4 +851,12 @@ unsigned int virtqueue_get_vring_size(struct virtqueue *_vq)
} }
EXPORT_SYMBOL_GPL(virtqueue_get_vring_size); EXPORT_SYMBOL_GPL(virtqueue_get_vring_size);
bool virtqueue_is_broken(struct virtqueue *_vq)
{
struct vring_virtqueue *vq = to_vvq(_vq);
return vq->broken;
}
EXPORT_SYMBOL_GPL(virtqueue_is_broken);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -51,11 +51,11 @@ int virtqueue_add_sgs(struct virtqueue *vq, ...@@ -51,11 +51,11 @@ int virtqueue_add_sgs(struct virtqueue *vq,
void *data, void *data,
gfp_t gfp); gfp_t gfp);
void virtqueue_kick(struct virtqueue *vq); bool virtqueue_kick(struct virtqueue *vq);
bool virtqueue_kick_prepare(struct virtqueue *vq); bool virtqueue_kick_prepare(struct virtqueue *vq);
void virtqueue_notify(struct virtqueue *vq); bool virtqueue_notify(struct virtqueue *vq);
void *virtqueue_get_buf(struct virtqueue *vq, unsigned int *len); void *virtqueue_get_buf(struct virtqueue *vq, unsigned int *len);
...@@ -73,6 +73,8 @@ void *virtqueue_detach_unused_buf(struct virtqueue *vq); ...@@ -73,6 +73,8 @@ void *virtqueue_detach_unused_buf(struct virtqueue *vq);
unsigned int virtqueue_get_vring_size(struct virtqueue *vq); unsigned int virtqueue_get_vring_size(struct virtqueue *vq);
bool virtqueue_is_broken(struct virtqueue *vq);
/** /**
* virtio_device - representation of a device using virtio * virtio_device - representation of a device using virtio
* @index: unique position on the virtio bus * @index: unique position on the virtio bus
......
...@@ -96,33 +96,6 @@ static inline bool virtio_has_feature(const struct virtio_device *vdev, ...@@ -96,33 +96,6 @@ static inline bool virtio_has_feature(const struct virtio_device *vdev,
return test_bit(fbit, vdev->features); return test_bit(fbit, vdev->features);
} }
/**
* virtio_config_val - look for a feature and get a virtio config entry.
* @vdev: the virtio device
* @fbit: the feature bit
* @offset: the type to search for.
* @v: a pointer to the value to fill in.
*
* The return value is -ENOENT if the feature doesn't exist. Otherwise
* the config value is copied into whatever is pointed to by v. */
#define virtio_config_val(vdev, fbit, offset, v) \
virtio_config_buf((vdev), (fbit), (offset), (v), sizeof(*v))
#define virtio_config_val_len(vdev, fbit, offset, v, len) \
virtio_config_buf((vdev), (fbit), (offset), (v), (len))
static inline int virtio_config_buf(struct virtio_device *vdev,
unsigned int fbit,
unsigned int offset,
void *buf, unsigned len)
{
if (!virtio_has_feature(vdev, fbit))
return -ENOENT;
vdev->config->get(vdev, offset, buf, len);
return 0;
}
static inline static inline
struct virtqueue *virtio_find_single_vq(struct virtio_device *vdev, struct virtqueue *virtio_find_single_vq(struct virtio_device *vdev,
vq_callback_t *c, const char *n) vq_callback_t *c, const char *n)
...@@ -162,5 +135,139 @@ int virtqueue_set_affinity(struct virtqueue *vq, int cpu) ...@@ -162,5 +135,139 @@ int virtqueue_set_affinity(struct virtqueue *vq, int cpu)
return 0; return 0;
} }
/* Config space accessors. */
#define virtio_cread(vdev, structname, member, ptr) \
do { \
/* Must match the member's type, and be integer */ \
if (!typecheck(typeof((((structname*)0)->member)), *(ptr))) \
(*ptr) = 1; \
\
switch (sizeof(*ptr)) { \
case 1: \
*(ptr) = virtio_cread8(vdev, \
offsetof(structname, member)); \
break; \
case 2: \
*(ptr) = virtio_cread16(vdev, \
offsetof(structname, member)); \
break; \
case 4: \
*(ptr) = virtio_cread32(vdev, \
offsetof(structname, member)); \
break; \
case 8: \
*(ptr) = virtio_cread64(vdev, \
offsetof(structname, member)); \
break; \
default: \
BUG(); \
} \
} while(0)
/* Config space accessors. */
#define virtio_cwrite(vdev, structname, member, ptr) \
do { \
/* Must match the member's type, and be integer */ \
if (!typecheck(typeof((((structname*)0)->member)), *(ptr))) \
BUG_ON((*ptr) == 1); \
\
switch (sizeof(*ptr)) { \
case 1: \
virtio_cwrite8(vdev, \
offsetof(structname, member), \
*(ptr)); \
break; \
case 2: \
virtio_cwrite16(vdev, \
offsetof(structname, member), \
*(ptr)); \
break; \
case 4: \
virtio_cwrite32(vdev, \
offsetof(structname, member), \
*(ptr)); \
break; \
case 8: \
virtio_cwrite64(vdev, \
offsetof(structname, member), \
*(ptr)); \
break; \
default: \
BUG(); \
} \
} while(0)
static inline u8 virtio_cread8(struct virtio_device *vdev, unsigned int offset)
{
u8 ret;
vdev->config->get(vdev, offset, &ret, sizeof(ret));
return ret;
}
static inline void virtio_cread_bytes(struct virtio_device *vdev,
unsigned int offset,
void *buf, size_t len)
{
vdev->config->get(vdev, offset, buf, len);
}
static inline void virtio_cwrite8(struct virtio_device *vdev,
unsigned int offset, u8 val)
{
vdev->config->set(vdev, offset, &val, sizeof(val));
}
static inline u16 virtio_cread16(struct virtio_device *vdev,
unsigned int offset)
{
u16 ret;
vdev->config->get(vdev, offset, &ret, sizeof(ret));
return ret;
}
static inline void virtio_cwrite16(struct virtio_device *vdev,
unsigned int offset, u16 val)
{
vdev->config->set(vdev, offset, &val, sizeof(val));
}
static inline u32 virtio_cread32(struct virtio_device *vdev,
unsigned int offset)
{
u32 ret;
vdev->config->get(vdev, offset, &ret, sizeof(ret));
return ret;
}
static inline void virtio_cwrite32(struct virtio_device *vdev,
unsigned int offset, u32 val)
{
vdev->config->set(vdev, offset, &val, sizeof(val));
}
static inline u64 virtio_cread64(struct virtio_device *vdev,
unsigned int offset)
{
u64 ret;
vdev->config->get(vdev, offset, &ret, sizeof(ret));
return ret;
}
static inline void virtio_cwrite64(struct virtio_device *vdev,
unsigned int offset, u64 val)
{
vdev->config->set(vdev, offset, &val, sizeof(val));
}
/* Conditional config space accessors. */
#define virtio_cread_feature(vdev, fbit, structname, member, ptr) \
({ \
int _r = 0; \
if (!virtio_has_feature(vdev, fbit)) \
_r = -ENOENT; \
else \
virtio_cread((vdev), structname, member, ptr); \
_r; \
})
#endif /* _LINUX_VIRTIO_CONFIG_H */ #endif /* _LINUX_VIRTIO_CONFIG_H */
...@@ -71,7 +71,7 @@ struct virtqueue *vring_new_virtqueue(unsigned int index, ...@@ -71,7 +71,7 @@ struct virtqueue *vring_new_virtqueue(unsigned int index,
struct virtio_device *vdev, struct virtio_device *vdev,
bool weak_barriers, bool weak_barriers,
void *pages, void *pages,
void (*notify)(struct virtqueue *vq), bool (*notify)(struct virtqueue *vq),
void (*callback)(struct virtqueue *vq), void (*callback)(struct virtqueue *vq),
const char *name); const char *name);
void vring_del_virtqueue(struct virtqueue *vq); void vring_del_virtqueue(struct virtqueue *vq);
......
...@@ -544,9 +544,7 @@ static int p9_virtio_probe(struct virtio_device *vdev) ...@@ -544,9 +544,7 @@ static int p9_virtio_probe(struct virtio_device *vdev)
chan->inuse = false; chan->inuse = false;
if (virtio_has_feature(vdev, VIRTIO_9P_MOUNT_TAG)) { if (virtio_has_feature(vdev, VIRTIO_9P_MOUNT_TAG)) {
vdev->config->get(vdev, virtio_cread(vdev, struct virtio_9p_config, tag_len, &tag_len);
offsetof(struct virtio_9p_config, tag_len),
&tag_len, sizeof(tag_len));
} else { } else {
err = -EINVAL; err = -EINVAL;
goto out_free_vq; goto out_free_vq;
...@@ -556,7 +554,8 @@ static int p9_virtio_probe(struct virtio_device *vdev) ...@@ -556,7 +554,8 @@ static int p9_virtio_probe(struct virtio_device *vdev)
err = -ENOMEM; err = -ENOMEM;
goto out_free_vq; goto out_free_vq;
} }
vdev->config->get(vdev, offsetof(struct virtio_9p_config, tag),
virtio_cread_bytes(vdev, offsetof(struct virtio_9p_config, tag),
tag, tag_len); tag, tag_len);
chan->tag = tag; chan->tag = tag;
chan->tag_len = tag_len; chan->tag_len = tag_len;
......
...@@ -41,13 +41,14 @@ struct vdev_info { ...@@ -41,13 +41,14 @@ struct vdev_info {
struct vhost_memory *mem; struct vhost_memory *mem;
}; };
void vq_notify(struct virtqueue *vq) bool vq_notify(struct virtqueue *vq)
{ {
struct vq_info *info = vq->priv; struct vq_info *info = vq->priv;
unsigned long long v = 1; unsigned long long v = 1;
int r; int r;
r = write(info->kick, &v, sizeof v); r = write(info->kick, &v, sizeof v);
assert(r == sizeof v); assert(r == sizeof v);
return true;
} }
void vq_callback(struct virtqueue *vq) void vq_callback(struct virtqueue *vq)
...@@ -171,7 +172,8 @@ static void run_test(struct vdev_info *dev, struct vq_info *vq, ...@@ -171,7 +172,8 @@ static void run_test(struct vdev_info *dev, struct vq_info *vq,
GFP_ATOMIC); GFP_ATOMIC);
if (likely(r == 0)) { if (likely(r == 0)) {
++started; ++started;
virtqueue_kick(vq->vq); if (unlikely(!virtqueue_kick(vq->vq))
r = -1;
} }
} else } else
r = -1; r = -1;
......
...@@ -22,7 +22,7 @@ static u64 user_addr_offset; ...@@ -22,7 +22,7 @@ static u64 user_addr_offset;
#define RINGSIZE 256 #define RINGSIZE 256
#define ALIGN 4096 #define ALIGN 4096
static void never_notify_host(struct virtqueue *vq) static bool never_notify_host(struct virtqueue *vq)
{ {
abort(); abort();
} }
...@@ -65,17 +65,22 @@ struct guest_virtio_device { ...@@ -65,17 +65,22 @@ struct guest_virtio_device {
unsigned long notifies; unsigned long notifies;
}; };
static void parallel_notify_host(struct virtqueue *vq) static bool parallel_notify_host(struct virtqueue *vq)
{ {
int rc;
struct guest_virtio_device *gvdev; struct guest_virtio_device *gvdev;
gvdev = container_of(vq->vdev, struct guest_virtio_device, vdev); gvdev = container_of(vq->vdev, struct guest_virtio_device, vdev);
write(gvdev->to_host_fd, "", 1); rc = write(gvdev->to_host_fd, "", 1);
if (rc < 0)
return false;
gvdev->notifies++; gvdev->notifies++;
return true;
} }
static void no_notify_host(struct virtqueue *vq) static bool no_notify_host(struct virtqueue *vq)
{ {
return true;
} }
#define NUM_XFERS (10000000) #define NUM_XFERS (10000000)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment