Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 134287
b: refs/heads/master
c: 2a41f71
h: refs/heads/master
i:
  134285: 6f64f9f
  134283: 8e185b4
  134279: 0d86520
  134271: c79aadf
v: v3
  • Loading branch information
Alex Williamson authored and David S. Miller committed Feb 5, 2009
1 parent 39b729f commit 3fe6542
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 4 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 073a24364fe6de7eef0a3dec0ec7d48e56624092
refs/heads/master: 2a41f71d3bd97dde3305b4e1c43ab0eca46e7c71
68 changes: 65 additions & 3 deletions trunk/drivers/net/virtio_net.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,12 @@ module_param(gso, bool, 0444);
#define MAX_PACKET_LEN (ETH_HLEN + VLAN_HLEN + ETH_DATA_LEN)
#define GOOD_COPY_LEN 128

#define VIRTNET_SEND_COMMAND_SG_MAX 0

struct virtnet_info
{
struct virtio_device *vdev;
struct virtqueue *rvq, *svq;
struct virtqueue *rvq, *svq, *cvq;
struct net_device *dev;
struct napi_struct napi;
unsigned int status;
Expand Down Expand Up @@ -589,6 +591,53 @@ static int virtnet_open(struct net_device *dev)
return 0;
}

/*
* Send command via the control virtqueue and check status. Commands
* supported by the hypervisor, as indicated by feature bits, should
* never fail unless improperly formated.
*/
static bool virtnet_send_command(struct virtnet_info *vi, u8 class, u8 cmd,
struct scatterlist *data, int out, int in)
{
struct scatterlist sg[VIRTNET_SEND_COMMAND_SG_MAX + 2];
struct virtio_net_ctrl_hdr ctrl;
virtio_net_ctrl_ack status = ~0;
unsigned int tmp;

if (!virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ)) {
BUG(); /* Caller should know better */
return false;
}

BUG_ON(out + in > VIRTNET_SEND_COMMAND_SG_MAX);

out++; /* Add header */
in++; /* Add return status */

ctrl.class = class;
ctrl.cmd = cmd;

sg_init_table(sg, out + in);

sg_set_buf(&sg[0], &ctrl, sizeof(ctrl));
memcpy(&sg[1], data, sizeof(struct scatterlist) * (out + in - 2));
sg_set_buf(&sg[out + in - 1], &status, sizeof(status));

if (vi->cvq->vq_ops->add_buf(vi->cvq, sg, out, in, vi) != 0)
BUG();

vi->cvq->vq_ops->kick(vi->cvq);

/*
* Spin for a response, the kick causes an ioport write, trapping
* into the hypervisor, so the request should be handled immediately.
*/
while (!vi->cvq->vq_ops->get_buf(vi->cvq, &tmp))
cpu_relax();

return status == VIRTIO_NET_OK;
}

static int virtnet_close(struct net_device *dev)
{
struct virtnet_info *vi = netdev_priv(dev);
Expand Down Expand Up @@ -752,6 +801,14 @@ static int virtnet_probe(struct virtio_device *vdev)
goto free_recv;
}

if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ)) {
vi->cvq = vdev->config->find_vq(vdev, 2, NULL);
if (IS_ERR(vi->cvq)) {
err = PTR_ERR(vi->svq);
goto free_send;
}
}

/* Initialize our empty receive and send queues. */
skb_queue_head_init(&vi->recv);
skb_queue_head_init(&vi->send);
Expand All @@ -764,7 +821,7 @@ static int virtnet_probe(struct virtio_device *vdev)
err = register_netdev(dev);
if (err) {
pr_debug("virtio_net: registering device failed\n");
goto free_send;
goto free_ctrl;
}

/* Last of all, set up some receive buffers. */
Expand All @@ -784,6 +841,9 @@ static int virtnet_probe(struct virtio_device *vdev)

unregister:
unregister_netdev(dev);
free_ctrl:
if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ))
vdev->config->del_vq(vi->cvq);
free_send:
vdev->config->del_vq(vi->svq);
free_recv:
Expand Down Expand Up @@ -815,6 +875,8 @@ static void virtnet_remove(struct virtio_device *vdev)

vdev->config->del_vq(vi->svq);
vdev->config->del_vq(vi->rvq);
if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ))
vdev->config->del_vq(vi->cvq);
unregister_netdev(vi->dev);

while (vi->pages)
Expand All @@ -834,7 +896,7 @@ static unsigned int features[] = {
VIRTIO_NET_F_HOST_TSO4, VIRTIO_NET_F_HOST_UFO, VIRTIO_NET_F_HOST_TSO6,
VIRTIO_NET_F_HOST_ECN, VIRTIO_NET_F_GUEST_TSO4, VIRTIO_NET_F_GUEST_TSO6,
VIRTIO_NET_F_GUEST_ECN, /* We don't yet handle UFO input. */
VIRTIO_NET_F_MRG_RXBUF, VIRTIO_NET_F_STATUS,
VIRTIO_NET_F_MRG_RXBUF, VIRTIO_NET_F_STATUS, VIRTIO_NET_F_CTRL_VQ,
VIRTIO_F_NOTIFY_ON_EMPTY,
};

Expand Down
18 changes: 18 additions & 0 deletions trunk/include/linux/virtio_net.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#define VIRTIO_NET_F_HOST_UFO 14 /* Host can handle UFO in. */
#define VIRTIO_NET_F_MRG_RXBUF 15 /* Host can merge receive buffers. */
#define VIRTIO_NET_F_STATUS 16 /* virtio_net_config.status available */
#define VIRTIO_NET_F_CTRL_VQ 17 /* Control channel available */

#define VIRTIO_NET_S_LINK_UP 1 /* Link is up */

Expand Down Expand Up @@ -59,4 +60,21 @@ struct virtio_net_hdr_mrg_rxbuf {
__u16 num_buffers; /* Number of merged rx buffers */
};

/*
* Control virtqueue data structures
*
* The control virtqueue expects a header in the first sg entry
* and an ack/status response in the last entry. Data for the
* command goes in between.
*/
struct virtio_net_ctrl_hdr {
__u8 class;
__u8 cmd;
} __attribute__((packed));

typedef __u8 virtio_net_ctrl_ack;

#define VIRTIO_NET_OK 0
#define VIRTIO_NET_ERR 1

#endif /* _LINUX_VIRTIO_NET_H */

0 comments on commit 3fe6542

Please sign in to comment.