Skip to content

Commit

Permalink
Merge tag 'virtio-next-for-linus' of git://git.kernel.org/pub/scm/lin…
Browse files Browse the repository at this point in the history
…ux/kernel/git/rusty/linux

Pull virtio update from Rusty Russell:
 "Some nice cleanups, and even a patch my wife did as a "live" demo for
  Latinoware 2012.

  There's a slightly non-trivial merge in virtio-net, as we cleaned up
  the virtio add_buf interface while DaveM accepted the mq virtio-net
  patches."

* tag 'virtio-next-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux: (27 commits)
  virtio_console: Add support for remoteproc serial
  virtio_console: Merge struct buffer_token into struct port_buffer
  virtio: add drv_to_virtio to make code clearly
  virtio: use dev_to_virtio wrapper in virtio
  virtio-mmio: Fix irq parsing in command line parameter
  virtio_console: Free buffers from out-queue upon close
  virtio: Convert dev_printk(KERN_<LEVEL> to dev_<level>(
  virtio_console: Use kmalloc instead of kzalloc
  virtio_console: Free buffer if splice fails
  virtio: tools: make it clear that virtqueue_add_buf() no longer returns > 0
  virtio: scsi: make it clear that virtqueue_add_buf() no longer returns > 0
  virtio: rpmsg: make it clear that virtqueue_add_buf() no longer returns > 0
  virtio: net: make it clear that virtqueue_add_buf() no longer returns > 0
  virtio: console: make it clear that virtqueue_add_buf() no longer returns > 0
  virtio: make virtqueue_add_buf() returning 0 on success, not capacity.
  virtio: console: don't rely on virtqueue_add_buf() returning capacity.
  virtio_net: don't rely on virtqueue_add_buf() returning capacity.
  virtio-net: remove unused skb_vnet_hdr->num_sg field
  virtio-net: correct capacity math on ring full
  virtio: move queue_index and num_free fields into core struct virtqueue.
  ...
  • Loading branch information
torvalds committed Dec 20, 2012
2 parents 03c850e + 1b63704 commit b7dfde9
Show file tree
Hide file tree
Showing 17 changed files with 412 additions and 276 deletions.
329 changes: 230 additions & 99 deletions drivers/char/virtio_console.c

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion drivers/lguest/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ int run_guest(struct lg_cpu *cpu, unsigned long __user *user)
* eventfd (ie. the appropriate virtqueue thread)?
*/
if (!send_notify_to_eventfd(cpu)) {
/* OK, we tell the main Laucher. */
/* OK, we tell the main Launcher. */
if (put_user(cpu->pending_notify, user))
return -EFAULT;
return sizeof(cpu->pending_notify);
Expand Down
48 changes: 19 additions & 29 deletions drivers/net/virtio_net.c
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,6 @@ struct skb_vnet_hdr {
struct virtio_net_hdr hdr;
struct virtio_net_hdr_mrg_rxbuf mhdr;
};
unsigned int num_sg;
};

struct padded_vnet_hdr {
Expand Down Expand Up @@ -530,10 +529,10 @@ static bool try_fill_recv(struct receive_queue *rq, gfp_t gfp)
err = add_recvbuf_small(rq, gfp);

oom = err == -ENOMEM;
if (err < 0)
if (err)
break;
++rq->num;
} while (err > 0);
} while (rq->vq->num_free);
if (unlikely(rq->num > rq->max))
rq->max = rq->num;
virtqueue_kick(rq->vq);
Expand Down Expand Up @@ -640,10 +639,10 @@ static int virtnet_open(struct net_device *dev)
return 0;
}

static unsigned int free_old_xmit_skbs(struct send_queue *sq)
static void free_old_xmit_skbs(struct send_queue *sq)
{
struct sk_buff *skb;
unsigned int len, tot_sgs = 0;
unsigned int len;
struct virtnet_info *vi = sq->vq->vdev->priv;
struct virtnet_stats *stats = this_cpu_ptr(vi->stats);

Expand All @@ -655,17 +654,16 @@ static unsigned int free_old_xmit_skbs(struct send_queue *sq)
stats->tx_packets++;
u64_stats_update_end(&stats->tx_syncp);

tot_sgs += skb_vnet_hdr(skb)->num_sg;
dev_kfree_skb_any(skb);
}
return tot_sgs;
}

static int xmit_skb(struct send_queue *sq, struct sk_buff *skb)
{
struct skb_vnet_hdr *hdr = skb_vnet_hdr(skb);
const unsigned char *dest = ((struct ethhdr *)skb->data)->h_dest;
struct virtnet_info *vi = sq->vq->vdev->priv;
unsigned num_sg;

pr_debug("%s: xmit %p %pM\n", vi->dev->name, skb, dest);

Expand Down Expand Up @@ -704,8 +702,8 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb)
else
sg_set_buf(sq->sg, &hdr->hdr, sizeof hdr->hdr);

hdr->num_sg = skb_to_sgvec(skb, sq->sg + 1, 0, skb->len) + 1;
return virtqueue_add_buf(sq->vq, sq->sg, hdr->num_sg,
num_sg = skb_to_sgvec(skb, sq->sg + 1, 0, skb->len) + 1;
return virtqueue_add_buf(sq->vq, sq->sg, num_sg,
0, skb, GFP_ATOMIC);
}

Expand All @@ -714,28 +712,20 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
struct virtnet_info *vi = netdev_priv(dev);
int qnum = skb_get_queue_mapping(skb);
struct send_queue *sq = &vi->sq[qnum];
int capacity;
int err;

/* Free up any pending old buffers before queueing new ones. */
free_old_xmit_skbs(sq);

/* Try to transmit */
capacity = xmit_skb(sq, skb);

/* This can happen with OOM and indirect buffers. */
if (unlikely(capacity < 0)) {
if (likely(capacity == -ENOMEM)) {
if (net_ratelimit())
dev_warn(&dev->dev,
"TXQ (%d) failure: out of memory\n",
qnum);
} else {
dev->stats.tx_fifo_errors++;
if (net_ratelimit())
dev_warn(&dev->dev,
"Unexpected TXQ (%d) failure: %d\n",
qnum, capacity);
}
err = xmit_skb(sq, skb);

/* This should not happen! */
if (unlikely(err)) {
dev->stats.tx_fifo_errors++;
if (net_ratelimit())
dev_warn(&dev->dev,
"Unexpected TXQ (%d) queue failure: %d\n", qnum, err);
dev->stats.tx_dropped++;
kfree_skb(skb);
return NETDEV_TX_OK;
Expand All @@ -748,12 +738,12 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)

/* Apparently nice girls don't return TX_BUSY; stop the queue
* before it gets out of hand. Naturally, this wastes entries. */
if (capacity < 2+MAX_SKB_FRAGS) {
if (sq->vq->num_free < 2+MAX_SKB_FRAGS) {
netif_stop_subqueue(dev, qnum);
if (unlikely(!virtqueue_enable_cb_delayed(sq->vq))) {
/* More just got used, free them then recheck. */
capacity += free_old_xmit_skbs(sq);
if (capacity >= 2+MAX_SKB_FRAGS) {
free_old_xmit_skbs(sq);
if (sq->vq->num_free >= 2+MAX_SKB_FRAGS) {
netif_start_subqueue(dev, qnum);
virtqueue_disable_cb(sq->vq);
}
Expand Down
6 changes: 2 additions & 4 deletions drivers/rpmsg/virtio_rpmsg_bus.c
Original file line number Diff line number Diff line change
Expand Up @@ -764,7 +764,7 @@ int rpmsg_send_offchannel_raw(struct rpmsg_channel *rpdev, u32 src, u32 dst,

/* add message to the remote processor's virtqueue */
err = virtqueue_add_buf(vrp->svq, &sg, 1, 0, msg, GFP_KERNEL);
if (err < 0) {
if (err) {
/*
* need to reclaim the buffer here, otherwise it's lost
* (memory won't leak, but rpmsg won't use it again for TX).
Expand All @@ -776,8 +776,6 @@ int rpmsg_send_offchannel_raw(struct rpmsg_channel *rpdev, u32 src, u32 dst,

/* tell the remote processor it has a pending message to read */
virtqueue_kick(vrp->svq);

err = 0;
out:
mutex_unlock(&vrp->tx_lock);
return err;
Expand Down Expand Up @@ -980,7 +978,7 @@ static int rpmsg_probe(struct virtio_device *vdev)

err = virtqueue_add_buf(vrp->rvq, &sg, 0, 1, cpu_addr,
GFP_KERNEL);
WARN_ON(err < 0); /* sanity check; this can't really happen */
WARN_ON(err); /* sanity check; this can't really happen */
}

/* suppress "tx-complete" interrupts */
Expand Down
24 changes: 13 additions & 11 deletions drivers/scsi/virtio_scsi.c
Original file line number Diff line number Diff line change
Expand Up @@ -215,21 +215,22 @@ static void virtscsi_ctrl_done(struct virtqueue *vq)
static int virtscsi_kick_event(struct virtio_scsi *vscsi,
struct virtio_scsi_event_node *event_node)
{
int ret;
int err;
struct scatterlist sg;
unsigned long flags;

sg_init_one(&sg, &event_node->event, sizeof(struct virtio_scsi_event));

spin_lock_irqsave(&vscsi->event_vq.vq_lock, flags);

ret = virtqueue_add_buf(vscsi->event_vq.vq, &sg, 0, 1, event_node, GFP_ATOMIC);
if (ret >= 0)
err = virtqueue_add_buf(vscsi->event_vq.vq, &sg, 0, 1, event_node,
GFP_ATOMIC);
if (!err)
virtqueue_kick(vscsi->event_vq.vq);

spin_unlock_irqrestore(&vscsi->event_vq.vq_lock, flags);

return ret;
return err;
}

static int virtscsi_kick_event_all(struct virtio_scsi *vscsi)
Expand Down Expand Up @@ -410,22 +411,23 @@ static int virtscsi_kick_cmd(struct virtio_scsi_target_state *tgt,
{
unsigned int out_num, in_num;
unsigned long flags;
int ret;
int err;
bool needs_kick = false;

spin_lock_irqsave(&tgt->tgt_lock, flags);
virtscsi_map_cmd(tgt, cmd, &out_num, &in_num, req_size, resp_size);

spin_lock(&vq->vq_lock);
ret = virtqueue_add_buf(vq->vq, tgt->sg, out_num, in_num, cmd, gfp);
err = virtqueue_add_buf(vq->vq, tgt->sg, out_num, in_num, cmd, gfp);
spin_unlock(&tgt->tgt_lock);
if (ret >= 0)
ret = virtqueue_kick_prepare(vq->vq);
if (!err)
needs_kick = virtqueue_kick_prepare(vq->vq);

spin_unlock_irqrestore(&vq->vq_lock, flags);

if (ret > 0)
if (needs_kick)
virtqueue_notify(vq->vq);
return ret;
return err;
}

static int virtscsi_queuecommand(struct Scsi_Host *sh, struct scsi_cmnd *sc)
Expand Down Expand Up @@ -467,7 +469,7 @@ static int virtscsi_queuecommand(struct Scsi_Host *sh, struct scsi_cmnd *sc)

if (virtscsi_kick_cmd(tgt, &vscsi->req_vq, cmd,
sizeof cmd->req.cmd, sizeof cmd->resp.cmd,
GFP_ATOMIC) >= 0)
GFP_ATOMIC) == 0)
ret = 0;
else
mempool_free(cmd, virtscsi_cmd_pool);
Expand Down
30 changes: 13 additions & 17 deletions drivers/virtio/virtio.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,33 +10,32 @@ static DEFINE_IDA(virtio_index_ida);
static ssize_t device_show(struct device *_d,
struct device_attribute *attr, char *buf)
{
struct virtio_device *dev = container_of(_d,struct virtio_device,dev);
struct virtio_device *dev = dev_to_virtio(_d);
return sprintf(buf, "0x%04x\n", dev->id.device);
}
static ssize_t vendor_show(struct device *_d,
struct device_attribute *attr, char *buf)
{
struct virtio_device *dev = container_of(_d,struct virtio_device,dev);
struct virtio_device *dev = dev_to_virtio(_d);
return sprintf(buf, "0x%04x\n", dev->id.vendor);
}
static ssize_t status_show(struct device *_d,
struct device_attribute *attr, char *buf)
{
struct virtio_device *dev = container_of(_d,struct virtio_device,dev);
struct virtio_device *dev = dev_to_virtio(_d);
return sprintf(buf, "0x%08x\n", dev->config->get_status(dev));
}
static ssize_t modalias_show(struct device *_d,
struct device_attribute *attr, char *buf)
{
struct virtio_device *dev = container_of(_d,struct virtio_device,dev);

struct virtio_device *dev = dev_to_virtio(_d);
return sprintf(buf, "virtio:d%08Xv%08X\n",
dev->id.device, dev->id.vendor);
}
static ssize_t features_show(struct device *_d,
struct device_attribute *attr, char *buf)
{
struct virtio_device *dev = container_of(_d, struct virtio_device, dev);
struct virtio_device *dev = dev_to_virtio(_d);
unsigned int i;
ssize_t len = 0;

Expand Down Expand Up @@ -71,10 +70,10 @@ static inline int virtio_id_match(const struct virtio_device *dev,
static int virtio_dev_match(struct device *_dv, struct device_driver *_dr)
{
unsigned int i;
struct virtio_device *dev = container_of(_dv,struct virtio_device,dev);
struct virtio_device *dev = dev_to_virtio(_dv);
const struct virtio_device_id *ids;

ids = container_of(_dr, struct virtio_driver, driver)->id_table;
ids = drv_to_virtio(_dr)->id_table;
for (i = 0; ids[i].device; i++)
if (virtio_id_match(dev, &ids[i]))
return 1;
Expand All @@ -83,7 +82,7 @@ static int virtio_dev_match(struct device *_dv, struct device_driver *_dr)

static int virtio_uevent(struct device *_dv, struct kobj_uevent_env *env)
{
struct virtio_device *dev = container_of(_dv,struct virtio_device,dev);
struct virtio_device *dev = dev_to_virtio(_dv);

return add_uevent_var(env, "MODALIAS=virtio:d%08Xv%08X",
dev->id.device, dev->id.vendor);
Expand All @@ -98,8 +97,7 @@ void virtio_check_driver_offered_feature(const struct virtio_device *vdev,
unsigned int fbit)
{
unsigned int i;
struct virtio_driver *drv = container_of(vdev->dev.driver,
struct virtio_driver, driver);
struct virtio_driver *drv = drv_to_virtio(vdev->dev.driver);

for (i = 0; i < drv->feature_table_size; i++)
if (drv->feature_table[i] == fbit)
Expand All @@ -111,9 +109,8 @@ EXPORT_SYMBOL_GPL(virtio_check_driver_offered_feature);
static int virtio_dev_probe(struct device *_d)
{
int err, i;
struct virtio_device *dev = container_of(_d,struct virtio_device,dev);
struct virtio_driver *drv = container_of(dev->dev.driver,
struct virtio_driver, driver);
struct virtio_device *dev = dev_to_virtio(_d);
struct virtio_driver *drv = drv_to_virtio(dev->dev.driver);
u32 device_features;

/* We have a driver! */
Expand Down Expand Up @@ -152,9 +149,8 @@ static int virtio_dev_probe(struct device *_d)

static int virtio_dev_remove(struct device *_d)
{
struct virtio_device *dev = container_of(_d,struct virtio_device,dev);
struct virtio_driver *drv = container_of(dev->dev.driver,
struct virtio_driver, driver);
struct virtio_device *dev = dev_to_virtio(_d);
struct virtio_driver *drv = drv_to_virtio(dev->dev.driver);

drv->remove(dev);

Expand Down
7 changes: 3 additions & 4 deletions drivers/virtio/virtio_balloon.c
Original file line number Diff line number Diff line change
Expand Up @@ -139,10 +139,9 @@ static void fill_balloon(struct virtio_balloon *vb, size_t num)
struct page *page = balloon_page_enqueue(vb_dev_info);

if (!page) {
if (printk_ratelimit())
dev_printk(KERN_INFO, &vb->vdev->dev,
"Out of puff! Can't get %u pages\n",
VIRTIO_BALLOON_PAGES_PER_PAGE);
dev_info_ratelimited(&vb->vdev->dev,
"Out of puff! Can't get %u pages\n",
VIRTIO_BALLOON_PAGES_PER_PAGE);
/* Sleep for at least 1/5 of a second before retry. */
msleep(200);
break;
Expand Down
30 changes: 19 additions & 11 deletions drivers/virtio/virtio_mmio.c
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ static void vm_notify(struct virtqueue *vq)

/* We write the queue's selector into the notification register to
* signal the other end */
writel(virtqueue_get_queue_index(vq), vm_dev->base + VIRTIO_MMIO_QUEUE_NOTIFY);
writel(vq->index, vm_dev->base + VIRTIO_MMIO_QUEUE_NOTIFY);
}

/* Notify all virtqueues on an interrupt. */
Expand Down Expand Up @@ -266,7 +266,7 @@ static void vm_del_vq(struct virtqueue *vq)
struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vq->vdev);
struct virtio_mmio_vq_info *info = vq->priv;
unsigned long flags, size;
unsigned int index = virtqueue_get_queue_index(vq);
unsigned int index = vq->index;

spin_lock_irqsave(&vm_dev->lock, flags);
list_del(&info->node);
Expand Down Expand Up @@ -521,25 +521,33 @@ static int vm_cmdline_set(const char *device,
int err;
struct resource resources[2] = {};
char *str;
long long int base;
long long int base, size;
unsigned int irq;
int processed, consumed = 0;
struct platform_device *pdev;

resources[0].flags = IORESOURCE_MEM;
resources[1].flags = IORESOURCE_IRQ;

resources[0].end = memparse(device, &str) - 1;
/* Consume "size" part of the command line parameter */
size = memparse(device, &str);

/* Get "@<base>:<irq>[:<id>]" chunks */
processed = sscanf(str, "@%lli:%u%n:%d%n",
&base, &resources[1].start, &consumed,
&base, &irq, &consumed,
&vm_cmdline_id, &consumed);

if (processed < 2 || processed > 3 || str[consumed])
/*
* sscanf() must processes at least 2 chunks; also there
* must be no extra characters after the last chunk, so
* str[consumed] must be '\0'
*/
if (processed < 2 || str[consumed])
return -EINVAL;

resources[0].flags = IORESOURCE_MEM;
resources[0].start = base;
resources[0].end += base;
resources[1].end = resources[1].start;
resources[0].end = base + size - 1;

resources[1].flags = IORESOURCE_IRQ;
resources[1].start = resources[1].end = irq;

if (!vm_cmdline_parent_registered) {
err = device_register(&vm_cmdline_parent);
Expand Down
Loading

0 comments on commit b7dfde9

Please sign in to comment.