Nothing really exciting: some groundwork for changing virtio endian, and
some robustness fixes for broken virtio devices, plus minor tweaks. [vs last pull request: added the virtio-scsi broken vq escape patch, which I somehow lost.] Cheers, Rusty. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.14 (GNU/Linux) iQIcBAABAgAGBQJSgDsJAAoJENkgDmzRrbjxEE4P/jXqZHS/HdlxW9k0BjKKlEIF PdtCoP3UhWTdskXvy2pD8m6nYn214MEJYUIa4HFlIEZsdxhuexzQHY19Ynkjagyv 57sRsUUm5fYQLIL7IUh2DUD1VU38hUFinno/y333szzvCj9qITDA/QABsiWxK8NO dq+Lmeixgrhc5yN9iryW+gZV+hekJIZ4LsU5ejSaJucKblzXUH8qIbmSthG7RTYJ tr4J7xTTXbhxY4CoC5Dpx2hvsFkvzaAIvI4Nr1mDjfq5cR8BaYvnC89U1IbhdAey p1AbZE58JLrY+Z8K8LBRGV2KjO8qSZ6R47hbZ9nAnodJYB7sZLyj6jUe1q+/htuC Dh9Xm9O4eW2xNaFk20dYeIF4UU5/HzdsbvG/IlH8x4sm8/K706ocYyAOHlzYUg2T k7gltrgDzDokMgb2R44gwnr4oaJ2q8Gne6JXswlPEv2eRs6vNnA5Xhc0rEHGkU6C gYn1vNFN6yx0vf2syG/Ce5pZtMxGpefKQkHzzWdq8FKr1B9s54dDuf2hls7J8A9t OQT1gE33yURSelf4Kh4k9zWXaWk/Ohv9l2R1cqpALnJ4/+q0fP5t7HdK500S7aax DxLeFeqvsBw7nlWgsGxQmt+fjITQFHhcDiwst0ehnt6RbDEW7XPIguz0K/gyhxYG +UNbl/5Gr64jnUX3YCzm =vY2L -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
b746f9c794
21 changed files with 310 additions and 166 deletions
|
@ -292,6 +292,8 @@ static void virtblk_done(struct virtqueue *vq)
|
|||
req_done = true;
|
||||
}
|
||||
}
|
||||
if (unlikely(virtqueue_is_broken(vq)))
|
||||
break;
|
||||
} while (!virtqueue_enable_cb(vq));
|
||||
/* In case queue is stopped waiting for more buffers. */
|
||||
if (req_done)
|
||||
|
@ -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)
|
||||
{
|
||||
struct virtio_blk *vblk = bd->bd_disk->private_data;
|
||||
struct virtio_blk_geometry vgeo;
|
||||
int err;
|
||||
|
||||
/* see if the host passed in geometry config */
|
||||
err = virtio_config_val(vblk->vdev, VIRTIO_BLK_F_GEOMETRY,
|
||||
offsetof(struct virtio_blk_config, geometry),
|
||||
&vgeo);
|
||||
|
||||
if (!err) {
|
||||
geo->heads = vgeo.heads;
|
||||
geo->sectors = vgeo.sectors;
|
||||
geo->cylinders = vgeo.cylinders;
|
||||
if (virtio_has_feature(vblk->vdev, VIRTIO_BLK_F_GEOMETRY)) {
|
||||
virtio_cread(vblk->vdev, struct virtio_blk_config,
|
||||
geometry.cylinders, &geo->cylinders);
|
||||
virtio_cread(vblk->vdev, struct virtio_blk_config,
|
||||
geometry.heads, &geo->heads);
|
||||
virtio_cread(vblk->vdev, struct virtio_blk_config,
|
||||
geometry.sectors, &geo->sectors);
|
||||
} else {
|
||||
/* some standard values, similar to sd */
|
||||
geo->heads = 1 << 6;
|
||||
|
@ -529,8 +528,7 @@ static void virtblk_config_changed_work(struct work_struct *work)
|
|||
goto done;
|
||||
|
||||
/* Host must always specify the capacity. */
|
||||
vdev->config->get(vdev, offsetof(struct virtio_blk_config, capacity),
|
||||
&capacity, sizeof(capacity));
|
||||
virtio_cread(vdev, struct virtio_blk_config, capacity, &capacity);
|
||||
|
||||
/* If capacity is too big, truncate with warning. */
|
||||
if ((sector_t)capacity != capacity) {
|
||||
|
@ -608,9 +606,9 @@ static int virtblk_get_cache_mode(struct virtio_device *vdev)
|
|||
u8 writeback;
|
||||
int err;
|
||||
|
||||
err = virtio_config_val(vdev, VIRTIO_BLK_F_CONFIG_WCE,
|
||||
offsetof(struct virtio_blk_config, wce),
|
||||
&writeback);
|
||||
err = virtio_cread_feature(vdev, VIRTIO_BLK_F_CONFIG_WCE,
|
||||
struct virtio_blk_config, wce,
|
||||
&writeback);
|
||||
if (err)
|
||||
writeback = virtio_has_feature(vdev, VIRTIO_BLK_F_WCE);
|
||||
|
||||
|
@ -642,7 +640,6 @@ virtblk_cache_type_store(struct device *dev, struct device_attribute *attr,
|
|||
struct virtio_blk *vblk = disk->private_data;
|
||||
struct virtio_device *vdev = vblk->vdev;
|
||||
int i;
|
||||
u8 writeback;
|
||||
|
||||
BUG_ON(!virtio_has_feature(vblk->vdev, VIRTIO_BLK_F_CONFIG_WCE));
|
||||
for (i = ARRAY_SIZE(virtblk_cache_types); --i >= 0; )
|
||||
|
@ -652,11 +649,7 @@ virtblk_cache_type_store(struct device *dev, struct device_attribute *attr,
|
|||
if (i < 0)
|
||||
return -EINVAL;
|
||||
|
||||
writeback = i;
|
||||
vdev->config->set(vdev,
|
||||
offsetof(struct virtio_blk_config, wce),
|
||||
&writeback, sizeof(writeback));
|
||||
|
||||
virtio_cwrite8(vdev, offsetof(struct virtio_blk_config, wce), i);
|
||||
virtblk_update_cache_mode(vdev);
|
||||
return count;
|
||||
}
|
||||
|
@ -699,9 +692,9 @@ static int virtblk_probe(struct virtio_device *vdev)
|
|||
index = err;
|
||||
|
||||
/* We need to know how many segments before we allocate. */
|
||||
err = virtio_config_val(vdev, VIRTIO_BLK_F_SEG_MAX,
|
||||
offsetof(struct virtio_blk_config, seg_max),
|
||||
&sg_elems);
|
||||
err = virtio_cread_feature(vdev, VIRTIO_BLK_F_SEG_MAX,
|
||||
struct virtio_blk_config, seg_max,
|
||||
&sg_elems);
|
||||
|
||||
/* We need at least one SG element, whatever they say. */
|
||||
if (err || !sg_elems)
|
||||
|
@ -772,8 +765,7 @@ static int virtblk_probe(struct virtio_device *vdev)
|
|||
set_disk_ro(vblk->disk, 1);
|
||||
|
||||
/* Host must always specify the capacity. */
|
||||
vdev->config->get(vdev, offsetof(struct virtio_blk_config, capacity),
|
||||
&cap, sizeof(cap));
|
||||
virtio_cread(vdev, struct virtio_blk_config, capacity, &cap);
|
||||
|
||||
/* If capacity is too big, truncate with warning. */
|
||||
if ((sector_t)cap != cap) {
|
||||
|
@ -794,46 +786,45 @@ static int virtblk_probe(struct virtio_device *vdev)
|
|||
|
||||
/* Host can optionally specify maximum segment size and number of
|
||||
* segments. */
|
||||
err = virtio_config_val(vdev, VIRTIO_BLK_F_SIZE_MAX,
|
||||
offsetof(struct virtio_blk_config, size_max),
|
||||
&v);
|
||||
err = virtio_cread_feature(vdev, VIRTIO_BLK_F_SIZE_MAX,
|
||||
struct virtio_blk_config, size_max, &v);
|
||||
if (!err)
|
||||
blk_queue_max_segment_size(q, v);
|
||||
else
|
||||
blk_queue_max_segment_size(q, -1U);
|
||||
|
||||
/* Host can optionally specify the block size of the device */
|
||||
err = virtio_config_val(vdev, VIRTIO_BLK_F_BLK_SIZE,
|
||||
offsetof(struct virtio_blk_config, blk_size),
|
||||
&blk_size);
|
||||
err = virtio_cread_feature(vdev, VIRTIO_BLK_F_BLK_SIZE,
|
||||
struct virtio_blk_config, blk_size,
|
||||
&blk_size);
|
||||
if (!err)
|
||||
blk_queue_logical_block_size(q, blk_size);
|
||||
else
|
||||
blk_size = queue_logical_block_size(q);
|
||||
|
||||
/* Use topology information if available */
|
||||
err = virtio_config_val(vdev, VIRTIO_BLK_F_TOPOLOGY,
|
||||
offsetof(struct virtio_blk_config, physical_block_exp),
|
||||
&physical_block_exp);
|
||||
err = virtio_cread_feature(vdev, VIRTIO_BLK_F_TOPOLOGY,
|
||||
struct virtio_blk_config, physical_block_exp,
|
||||
&physical_block_exp);
|
||||
if (!err && physical_block_exp)
|
||||
blk_queue_physical_block_size(q,
|
||||
blk_size * (1 << physical_block_exp));
|
||||
|
||||
err = virtio_config_val(vdev, VIRTIO_BLK_F_TOPOLOGY,
|
||||
offsetof(struct virtio_blk_config, alignment_offset),
|
||||
&alignment_offset);
|
||||
err = virtio_cread_feature(vdev, VIRTIO_BLK_F_TOPOLOGY,
|
||||
struct virtio_blk_config, alignment_offset,
|
||||
&alignment_offset);
|
||||
if (!err && alignment_offset)
|
||||
blk_queue_alignment_offset(q, blk_size * alignment_offset);
|
||||
|
||||
err = virtio_config_val(vdev, VIRTIO_BLK_F_TOPOLOGY,
|
||||
offsetof(struct virtio_blk_config, min_io_size),
|
||||
&min_io_size);
|
||||
err = virtio_cread_feature(vdev, VIRTIO_BLK_F_TOPOLOGY,
|
||||
struct virtio_blk_config, min_io_size,
|
||||
&min_io_size);
|
||||
if (!err && min_io_size)
|
||||
blk_queue_io_min(q, blk_size * min_io_size);
|
||||
|
||||
err = virtio_config_val(vdev, VIRTIO_BLK_F_TOPOLOGY,
|
||||
offsetof(struct virtio_blk_config, opt_io_size),
|
||||
&opt_io_size);
|
||||
err = virtio_cread_feature(vdev, VIRTIO_BLK_F_TOPOLOGY,
|
||||
struct virtio_blk_config, opt_io_size,
|
||||
&opt_io_size);
|
||||
if (!err && 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)
|
|||
ida_simple_remove(&vd_index_ida, index);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int virtblk_freeze(struct virtio_device *vdev)
|
||||
{
|
||||
struct virtio_blk *vblk = vdev->priv;
|
||||
|
@ -959,7 +950,7 @@ static struct virtio_driver virtio_blk = {
|
|||
.probe = virtblk_probe,
|
||||
.remove = virtblk_remove,
|
||||
.config_changed = virtblk_config_changed,
|
||||
#ifdef CONFIG_PM
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
.freeze = virtblk_freeze,
|
||||
.restore = virtblk_restore,
|
||||
#endif
|
||||
|
|
|
@ -133,7 +133,7 @@ static void virtrng_remove(struct virtio_device *vdev)
|
|||
remove_common(vdev);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int virtrng_freeze(struct virtio_device *vdev)
|
||||
{
|
||||
remove_common(vdev);
|
||||
|
@ -157,7 +157,7 @@ static struct virtio_driver virtio_rng_driver = {
|
|||
.id_table = id_table,
|
||||
.probe = virtrng_probe,
|
||||
.remove = virtrng_remove,
|
||||
#ifdef CONFIG_PM
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
.freeze = virtrng_freeze,
|
||||
.restore = virtrng_restore,
|
||||
#endif
|
||||
|
|
|
@ -577,7 +577,8 @@ static ssize_t __send_control_msg(struct ports_device *portdev, u32 port_id,
|
|||
spin_lock(&portdev->c_ovq_lock);
|
||||
if (virtqueue_add_outbuf(vq, sg, 1, &cpkt, GFP_ATOMIC) == 0) {
|
||||
virtqueue_kick(vq);
|
||||
while (!virtqueue_get_buf(vq, &len))
|
||||
while (!virtqueue_get_buf(vq, &len)
|
||||
&& !virtqueue_is_broken(vq))
|
||||
cpu_relax();
|
||||
}
|
||||
spin_unlock(&portdev->c_ovq_lock);
|
||||
|
@ -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
|
||||
* 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();
|
||||
done:
|
||||
spin_unlock_irqrestore(&port->outvq_lock, flags);
|
||||
|
@ -1837,12 +1839,8 @@ static void config_intr(struct virtio_device *vdev)
|
|||
struct port *port;
|
||||
u16 rows, cols;
|
||||
|
||||
vdev->config->get(vdev,
|
||||
offsetof(struct virtio_console_config, cols),
|
||||
&cols, sizeof(u16));
|
||||
vdev->config->get(vdev,
|
||||
offsetof(struct virtio_console_config, rows),
|
||||
&rows, sizeof(u16));
|
||||
virtio_cread(vdev, struct virtio_console_config, cols, &cols);
|
||||
virtio_cread(vdev, struct virtio_console_config, rows, &rows);
|
||||
|
||||
port = find_port_by_id(portdev, 0);
|
||||
set_console_size(port, rows, cols);
|
||||
|
@ -2014,10 +2012,9 @@ static int virtcons_probe(struct virtio_device *vdev)
|
|||
|
||||
/* Don't test MULTIPORT at all if we're rproc: not a valid feature! */
|
||||
if (!is_rproc_serial(vdev) &&
|
||||
virtio_config_val(vdev, VIRTIO_CONSOLE_F_MULTIPORT,
|
||||
offsetof(struct virtio_console_config,
|
||||
max_nr_ports),
|
||||
&portdev->config.max_nr_ports) == 0) {
|
||||
virtio_cread_feature(vdev, VIRTIO_CONSOLE_F_MULTIPORT,
|
||||
struct virtio_console_config, max_nr_ports,
|
||||
&portdev->config.max_nr_ports) == 0) {
|
||||
multiport = true;
|
||||
}
|
||||
|
||||
|
@ -2142,7 +2139,7 @@ static struct virtio_device_id rproc_serial_id_table[] = {
|
|||
static unsigned int rproc_serial_features[] = {
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int virtcons_freeze(struct virtio_device *vdev)
|
||||
{
|
||||
struct ports_device *portdev;
|
||||
|
@ -2220,7 +2217,7 @@ static struct virtio_driver virtio_console = {
|
|||
.probe = virtcons_probe,
|
||||
.remove = virtcons_remove,
|
||||
.config_changed = config_intr,
|
||||
#ifdef CONFIG_PM
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
.freeze = virtcons_freeze,
|
||||
.restore = virtcons_restore,
|
||||
#endif
|
||||
|
|
|
@ -229,7 +229,7 @@ struct lguest_vq_info {
|
|||
* make a hypercall. We hand the physical address of the virtqueue so the Host
|
||||
* 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
|
||||
|
@ -238,6 +238,7 @@ static void lg_notify(struct virtqueue *vq)
|
|||
struct lguest_vq_info *lvq = vq->priv;
|
||||
|
||||
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. */
|
||||
|
|
|
@ -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
|
||||
* 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")
|
||||
* 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)
|
|||
* physical address of the Guest's top-level page
|
||||
* 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,
|
||||
* which means we don't have to save and restore them in
|
||||
|
|
|
@ -686,18 +686,19 @@ static int cfv_probe(struct virtio_device *vdev)
|
|||
goto err;
|
||||
|
||||
/* 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) {
|
||||
GET_VIRTIO_CONFIG_OPS(vdev, cfv->tx_hr, headroom);
|
||||
GET_VIRTIO_CONFIG_OPS(vdev, cfv->rx_hr, headroom);
|
||||
GET_VIRTIO_CONFIG_OPS(vdev, cfv->tx_tr, tailroom);
|
||||
GET_VIRTIO_CONFIG_OPS(vdev, cfv->rx_tr, tailroom);
|
||||
GET_VIRTIO_CONFIG_OPS(vdev, cfv->mtu, mtu);
|
||||
GET_VIRTIO_CONFIG_OPS(vdev, cfv->mru, mtu);
|
||||
virtio_cread(vdev, struct virtio_caif_transf_config, headroom,
|
||||
&cfv->tx_hr);
|
||||
virtio_cread(vdev, struct virtio_caif_transf_config, headroom,
|
||||
&cfv->rx_hr);
|
||||
virtio_cread(vdev, struct virtio_caif_transf_config, tailroom,
|
||||
&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 {
|
||||
cfv->tx_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)
|
|||
} while (rq->vq->num_free);
|
||||
if (unlikely(rq->num > rq->max))
|
||||
rq->max = rq->num;
|
||||
virtqueue_kick(rq->vq);
|
||||
if (unlikely(!virtqueue_kick(rq->vq)))
|
||||
return false;
|
||||
return !oom;
|
||||
}
|
||||
|
||||
|
@ -797,7 +798,7 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
|
|||
err = xmit_skb(sq, skb);
|
||||
|
||||
/* This should not happen! */
|
||||
if (unlikely(err)) {
|
||||
if (unlikely(err) || unlikely(!virtqueue_kick(sq->vq))) {
|
||||
dev->stats.tx_fifo_errors++;
|
||||
if (net_ratelimit())
|
||||
dev_warn(&dev->dev,
|
||||
|
@ -806,7 +807,6 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
|
|||
kfree_skb(skb);
|
||||
return NETDEV_TX_OK;
|
||||
}
|
||||
virtqueue_kick(sq->vq);
|
||||
|
||||
/* Don't wait up for transmitted skbs to be freed. */
|
||||
skb_orphan(skb);
|
||||
|
@ -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)
|
||||
< 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
|
||||
* 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();
|
||||
|
||||
return status == VIRTIO_NET_OK;
|
||||
|
@ -898,8 +900,13 @@ static int virtnet_set_mac_address(struct net_device *dev, void *p)
|
|||
return -EINVAL;
|
||||
}
|
||||
} else if (virtio_has_feature(vdev, VIRTIO_NET_F_MAC)) {
|
||||
vdev->config->set(vdev, offsetof(struct virtio_net_config, mac),
|
||||
addr->sa_data, dev->addr_len);
|
||||
unsigned int i;
|
||||
|
||||
/* 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);
|
||||
|
@ -1281,9 +1288,8 @@ static void virtnet_config_changed_work(struct work_struct *work)
|
|||
if (!vi->config_enable)
|
||||
goto done;
|
||||
|
||||
if (virtio_config_val(vi->vdev, VIRTIO_NET_F_STATUS,
|
||||
offsetof(struct virtio_net_config, status),
|
||||
&v) < 0)
|
||||
if (virtio_cread_feature(vi->vdev, VIRTIO_NET_F_STATUS,
|
||||
struct virtio_net_config, status, &v) < 0)
|
||||
goto done;
|
||||
|
||||
if (v & VIRTIO_NET_S_ANNOUNCE) {
|
||||
|
@ -1507,9 +1513,9 @@ static int virtnet_probe(struct virtio_device *vdev)
|
|||
u16 max_queue_pairs;
|
||||
|
||||
/* Find if host supports multiqueue virtio_net device */
|
||||
err = virtio_config_val(vdev, VIRTIO_NET_F_MQ,
|
||||
offsetof(struct virtio_net_config,
|
||||
max_virtqueue_pairs), &max_queue_pairs);
|
||||
err = virtio_cread_feature(vdev, VIRTIO_NET_F_MQ,
|
||||
struct virtio_net_config,
|
||||
max_virtqueue_pairs, &max_queue_pairs);
|
||||
|
||||
/* We need at least 2 queue's */
|
||||
if (err || max_queue_pairs < VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN ||
|
||||
|
@ -1561,9 +1567,11 @@ static int virtnet_probe(struct virtio_device *vdev)
|
|||
dev->vlan_features = dev->features;
|
||||
|
||||
/* Configuration may specify what MAC to use. Otherwise random. */
|
||||
if (virtio_config_val_len(vdev, VIRTIO_NET_F_MAC,
|
||||
offsetof(struct virtio_net_config, mac),
|
||||
dev->dev_addr, dev->addr_len) < 0)
|
||||
if (virtio_has_feature(vdev, VIRTIO_NET_F_MAC))
|
||||
virtio_cread_bytes(vdev,
|
||||
offsetof(struct virtio_net_config, mac),
|
||||
dev->dev_addr, dev->addr_len);
|
||||
else
|
||||
eth_hw_addr_random(dev);
|
||||
|
||||
/* Set up our device-specific information */
|
||||
|
@ -1704,7 +1712,7 @@ static void virtnet_remove(struct virtio_device *vdev)
|
|||
free_netdev(vi->dev);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int virtnet_freeze(struct virtio_device *vdev)
|
||||
{
|
||||
struct virtnet_info *vi = vdev->priv;
|
||||
|
@ -1795,7 +1803,7 @@ static struct virtio_driver virtio_net_driver = {
|
|||
.probe = virtnet_probe,
|
||||
.remove = virtnet_remove,
|
||||
.config_changed = virtnet_config_changed,
|
||||
#ifdef CONFIG_PM
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
.freeze = virtnet_freeze,
|
||||
.restore = virtnet_restore,
|
||||
#endif
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
#include "remoteproc_internal.h"
|
||||
|
||||
/* 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 *rproc = rvring->rvdev->rproc;
|
||||
|
@ -39,6 +39,7 @@ static void rproc_virtio_notify(struct virtqueue *vq)
|
|||
dev_dbg(&rproc->dev, "kicking vq index: %d\n", notifyid);
|
||||
|
||||
rproc->ops->kick(rproc, notifyid);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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
|
||||
* 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;
|
||||
|
||||
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,
|
|||
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_device *vcdev;
|
||||
|
@ -171,6 +171,9 @@ static void virtio_ccw_kvm_notify(struct virtqueue *vq)
|
|||
vcdev = to_vc_device(info->vq->vdev);
|
||||
ccw_device_get_schid(vcdev->cdev, &schid);
|
||||
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,
|
||||
|
|
|
@ -224,6 +224,9 @@ static void virtscsi_vq_done(struct virtio_scsi *vscsi,
|
|||
virtqueue_disable_cb(vq);
|
||||
while ((buf = virtqueue_get_buf(vq, &len)) != NULL)
|
||||
fn(vscsi, buf);
|
||||
|
||||
if (unlikely(virtqueue_is_broken(vq)))
|
||||
break;
|
||||
} while (!virtqueue_enable_cb(vq));
|
||||
spin_unlock_irqrestore(&virtscsi_vq->vq_lock, flags);
|
||||
}
|
||||
|
@ -710,19 +713,15 @@ static struct scsi_host_template virtscsi_host_template_multi = {
|
|||
#define virtscsi_config_get(vdev, fld) \
|
||||
({ \
|
||||
typeof(((struct virtio_scsi_config *)0)->fld) __val; \
|
||||
vdev->config->get(vdev, \
|
||||
offsetof(struct virtio_scsi_config, fld), \
|
||||
&__val, sizeof(__val)); \
|
||||
virtio_cread(vdev, struct virtio_scsi_config, fld, &__val); \
|
||||
__val; \
|
||||
})
|
||||
|
||||
#define virtscsi_config_set(vdev, fld, val) \
|
||||
(void)({ \
|
||||
do { \
|
||||
typeof(((struct virtio_scsi_config *)0)->fld) __val = (val); \
|
||||
vdev->config->set(vdev, \
|
||||
offsetof(struct virtio_scsi_config, fld), \
|
||||
&__val, sizeof(__val)); \
|
||||
})
|
||||
virtio_cwrite(vdev, struct virtio_scsi_config, fld, &__val); \
|
||||
} while(0)
|
||||
|
||||
static void __virtscsi_set_affinity(struct virtio_scsi *vscsi, bool affinity)
|
||||
{
|
||||
|
@ -954,7 +953,7 @@ static void virtscsi_remove(struct virtio_device *vdev)
|
|||
scsi_host_put(shost);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int virtscsi_freeze(struct virtio_device *vdev)
|
||||
{
|
||||
virtscsi_remove_vqs(vdev);
|
||||
|
@ -988,7 +987,7 @@ static struct virtio_driver virtio_scsi_driver = {
|
|||
.id_table = id_table,
|
||||
.probe = virtscsi_probe,
|
||||
.scan = virtscsi_scan,
|
||||
#ifdef CONFIG_PM
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
.freeze = virtscsi_freeze,
|
||||
.restore = virtscsi_restore,
|
||||
#endif
|
||||
|
|
|
@ -275,9 +275,8 @@ static inline s64 towards_target(struct virtio_balloon *vb)
|
|||
__le32 v;
|
||||
s64 target;
|
||||
|
||||
vb->vdev->config->get(vb->vdev,
|
||||
offsetof(struct virtio_balloon_config, num_pages),
|
||||
&v, sizeof(v));
|
||||
virtio_cread(vb->vdev, struct virtio_balloon_config, num_pages, &v);
|
||||
|
||||
target = le32_to_cpu(v);
|
||||
return target - vb->num_pages;
|
||||
}
|
||||
|
@ -286,9 +285,8 @@ static void update_balloon_size(struct virtio_balloon *vb)
|
|||
{
|
||||
__le32 actual = cpu_to_le32(vb->num_pages);
|
||||
|
||||
vb->vdev->config->set(vb->vdev,
|
||||
offsetof(struct virtio_balloon_config, actual),
|
||||
&actual, sizeof(actual));
|
||||
virtio_cwrite(vb->vdev, struct virtio_balloon_config, num_pages,
|
||||
&actual);
|
||||
}
|
||||
|
||||
static int balloon(void *_vballoon)
|
||||
|
@ -513,7 +511,7 @@ static void virtballoon_remove(struct virtio_device *vdev)
|
|||
kfree(vb);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int virtballoon_freeze(struct virtio_device *vdev)
|
||||
{
|
||||
struct virtio_balloon *vb = vdev->priv;
|
||||
|
@ -556,7 +554,7 @@ static struct virtio_driver virtio_balloon_driver = {
|
|||
.probe = virtballoon_probe,
|
||||
.remove = virtballoon_remove,
|
||||
.config_changed = virtballoon_changed,
|
||||
#ifdef CONFIG_PM
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
.freeze = virtballoon_freeze,
|
||||
.restore = virtballoon_restore,
|
||||
#endif
|
||||
|
|
|
@ -219,13 +219,14 @@ static void vm_reset(struct virtio_device *vdev)
|
|||
/* Transport interface */
|
||||
|
||||
/* 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);
|
||||
|
||||
/* We write the queue's selector into the notification register to
|
||||
* signal the other end */
|
||||
writel(vq->index, vm_dev->base + VIRTIO_MMIO_QUEUE_NOTIFY);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Notify all virtqueues on an interrupt. */
|
||||
|
@ -470,7 +471,7 @@ static int virtio_mmio_probe(struct platform_device *pdev)
|
|||
|
||||
/* Check 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);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
|
|
@ -197,13 +197,14 @@ static void vp_reset(struct virtio_device *vdev)
|
|||
}
|
||||
|
||||
/* 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);
|
||||
|
||||
/* we write the queue's selector into the notification register to
|
||||
* signal the other end */
|
||||
iowrite16(vq->index, vp_dev->ioaddr + VIRTIO_PCI_QUEUE_NOTIFY);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Handle a configuration change: Tell driver if it wants to know. */
|
||||
|
|
|
@ -81,7 +81,7 @@ struct vring_virtqueue
|
|||
u16 last_used_idx;
|
||||
|
||||
/* How to notify other side. FIXME: commonalize hcalls! */
|
||||
void (*notify)(struct virtqueue *vq);
|
||||
bool (*notify)(struct virtqueue *vq);
|
||||
|
||||
#ifdef DEBUG
|
||||
/* They're supposed to lock for us. */
|
||||
|
@ -173,6 +173,8 @@ static inline int vring_add_indirect(struct vring_virtqueue *vq,
|
|||
head = vq->free_head;
|
||||
vq->vring.desc[head].flags = VRING_DESC_F_INDIRECT;
|
||||
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);
|
||||
|
||||
/* Update free pointer */
|
||||
|
@ -428,13 +430,22 @@ EXPORT_SYMBOL_GPL(virtqueue_kick_prepare);
|
|||
* @vq: the struct virtqueue
|
||||
*
|
||||
* 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);
|
||||
|
||||
if (unlikely(vq->broken))
|
||||
return false;
|
||||
|
||||
/* 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);
|
||||
|
||||
|
@ -447,11 +458,14 @@ EXPORT_SYMBOL_GPL(virtqueue_notify);
|
|||
*
|
||||
* Caller must ensure we don't call this with other virtqueue
|
||||
* 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))
|
||||
virtqueue_notify(vq);
|
||||
return virtqueue_notify(vq);
|
||||
return true;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(virtqueue_kick);
|
||||
|
||||
|
@ -742,7 +756,7 @@ struct virtqueue *vring_new_virtqueue(unsigned int index,
|
|||
struct virtio_device *vdev,
|
||||
bool weak_barriers,
|
||||
void *pages,
|
||||
void (*notify)(struct virtqueue *),
|
||||
bool (*notify)(struct virtqueue *),
|
||||
void (*callback)(struct virtqueue *),
|
||||
const char *name)
|
||||
{
|
||||
|
@ -837,4 +851,12 @@ unsigned int virtqueue_get_vring_size(struct virtqueue *_vq)
|
|||
}
|
||||
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");
|
||||
|
|
|
@ -51,11 +51,11 @@ int virtqueue_add_sgs(struct virtqueue *vq,
|
|||
void *data,
|
||||
gfp_t gfp);
|
||||
|
||||
void virtqueue_kick(struct virtqueue *vq);
|
||||
bool virtqueue_kick(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);
|
||||
|
||||
|
@ -73,6 +73,8 @@ void *virtqueue_detach_unused_buf(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
|
||||
* @index: unique position on the virtio bus
|
||||
|
|
|
@ -96,33 +96,6 @@ static inline bool virtio_has_feature(const struct virtio_device *vdev,
|
|||
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
|
||||
struct virtqueue *virtio_find_single_vq(struct virtio_device *vdev,
|
||||
vq_callback_t *c, const char *n)
|
||||
|
@ -162,5 +135,139 @@ int virtqueue_set_affinity(struct virtqueue *vq, int cpu)
|
|||
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 */
|
||||
|
|
|
@ -71,7 +71,7 @@ struct virtqueue *vring_new_virtqueue(unsigned int index,
|
|||
struct virtio_device *vdev,
|
||||
bool weak_barriers,
|
||||
void *pages,
|
||||
void (*notify)(struct virtqueue *vq),
|
||||
bool (*notify)(struct virtqueue *vq),
|
||||
void (*callback)(struct virtqueue *vq),
|
||||
const char *name);
|
||||
void vring_del_virtqueue(struct virtqueue *vq);
|
||||
|
|
|
@ -544,9 +544,7 @@ static int p9_virtio_probe(struct virtio_device *vdev)
|
|||
|
||||
chan->inuse = false;
|
||||
if (virtio_has_feature(vdev, VIRTIO_9P_MOUNT_TAG)) {
|
||||
vdev->config->get(vdev,
|
||||
offsetof(struct virtio_9p_config, tag_len),
|
||||
&tag_len, sizeof(tag_len));
|
||||
virtio_cread(vdev, struct virtio_9p_config, tag_len, &tag_len);
|
||||
} else {
|
||||
err = -EINVAL;
|
||||
goto out_free_vq;
|
||||
|
@ -556,8 +554,9 @@ static int p9_virtio_probe(struct virtio_device *vdev)
|
|||
err = -ENOMEM;
|
||||
goto out_free_vq;
|
||||
}
|
||||
vdev->config->get(vdev, offsetof(struct virtio_9p_config, tag),
|
||||
tag, tag_len);
|
||||
|
||||
virtio_cread_bytes(vdev, offsetof(struct virtio_9p_config, tag),
|
||||
tag, tag_len);
|
||||
chan->tag = tag;
|
||||
chan->tag_len = tag_len;
|
||||
err = sysfs_create_file(&(vdev->dev.kobj), &dev_attr_mount_tag.attr);
|
||||
|
|
|
@ -41,13 +41,14 @@ struct vdev_info {
|
|||
struct vhost_memory *mem;
|
||||
};
|
||||
|
||||
void vq_notify(struct virtqueue *vq)
|
||||
bool vq_notify(struct virtqueue *vq)
|
||||
{
|
||||
struct vq_info *info = vq->priv;
|
||||
unsigned long long v = 1;
|
||||
int r;
|
||||
r = write(info->kick, &v, sizeof v);
|
||||
assert(r == sizeof v);
|
||||
return true;
|
||||
}
|
||||
|
||||
void vq_callback(struct virtqueue *vq)
|
||||
|
@ -171,7 +172,8 @@ static void run_test(struct vdev_info *dev, struct vq_info *vq,
|
|||
GFP_ATOMIC);
|
||||
if (likely(r == 0)) {
|
||||
++started;
|
||||
virtqueue_kick(vq->vq);
|
||||
if (unlikely(!virtqueue_kick(vq->vq))
|
||||
r = -1;
|
||||
}
|
||||
} else
|
||||
r = -1;
|
||||
|
|
|
@ -22,7 +22,7 @@ static u64 user_addr_offset;
|
|||
#define RINGSIZE 256
|
||||
#define ALIGN 4096
|
||||
|
||||
static void never_notify_host(struct virtqueue *vq)
|
||||
static bool never_notify_host(struct virtqueue *vq)
|
||||
{
|
||||
abort();
|
||||
}
|
||||
|
@ -65,17 +65,22 @@ struct guest_virtio_device {
|
|||
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;
|
||||
|
||||
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++;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void no_notify_host(struct virtqueue *vq)
|
||||
static bool no_notify_host(struct virtqueue *vq)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
#define NUM_XFERS (10000000)
|
||||
|
|
Loading…
Reference in a new issue