Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 300755
b: refs/heads/master
c: 586d17c
h: refs/heads/master
i:
  300753: 094538c
  300751: dba54e4
v: v3
  • Loading branch information
Jason Wang authored and David S. Miller committed Apr 15, 2012
1 parent a88fa65 commit b4e81ad
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 6 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: 8831a3f2c9ee7d952e6d7a018d11c0c9c5b56749
refs/heads/master: 586d17c5a01bf1ae4e215adc6c48457eee5482bc
64 changes: 59 additions & 5 deletions trunk/drivers/net/virtio_net.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,12 +66,21 @@ struct virtnet_info {
/* Host will merge rx buffers for big packets (shake it! shake it!) */
bool mergeable_rx_bufs;

/* enable config space updates */
bool config_enable;

/* Active statistics */
struct virtnet_stats __percpu *stats;

/* Work struct for refilling if we run low on memory. */
struct delayed_work refill;

/* Work struct for config space updates */
struct work_struct config_work;

/* Lock for config space updates */
struct mutex config_lock;

/* Chain pages by the private ptr. */
struct page *pages;

Expand Down Expand Up @@ -780,6 +789,16 @@ static bool virtnet_send_command(struct virtnet_info *vi, u8 class, u8 cmd,
return status == VIRTIO_NET_OK;
}

static void virtnet_ack_link_announce(struct virtnet_info *vi)
{
rtnl_lock();
if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_ANNOUNCE,
VIRTIO_NET_CTRL_ANNOUNCE_ACK, NULL,
0, 0))
dev_warn(&vi->dev->dev, "Failed to ack link announce.\n");
rtnl_unlock();
}

static int virtnet_close(struct net_device *dev)
{
struct virtnet_info *vi = netdev_priv(dev);
Expand Down Expand Up @@ -951,20 +970,31 @@ static const struct net_device_ops virtnet_netdev = {
#endif
};

static void virtnet_update_status(struct virtnet_info *vi)
static void virtnet_config_changed_work(struct work_struct *work)
{
struct virtnet_info *vi =
container_of(work, struct virtnet_info, config_work);
u16 v;

mutex_lock(&vi->config_lock);
if (!vi->config_enable)
goto done;

if (virtio_config_val(vi->vdev, VIRTIO_NET_F_STATUS,
offsetof(struct virtio_net_config, status),
&v) < 0)
return;
goto done;

if (v & VIRTIO_NET_S_ANNOUNCE) {
netif_notify_peers(vi->dev);
virtnet_ack_link_announce(vi);
}

/* Ignore unknown (future) status bits */
v &= VIRTIO_NET_S_LINK_UP;

if (vi->status == v)
return;
goto done;

vi->status = v;

Expand All @@ -975,13 +1005,15 @@ static void virtnet_update_status(struct virtnet_info *vi)
netif_carrier_off(vi->dev);
netif_stop_queue(vi->dev);
}
done:
mutex_unlock(&vi->config_lock);
}

static void virtnet_config_changed(struct virtio_device *vdev)
{
struct virtnet_info *vi = vdev->priv;

virtnet_update_status(vi);
queue_work(system_nrt_wq, &vi->config_work);
}

static int init_vqs(struct virtnet_info *vi)
Expand Down Expand Up @@ -1075,6 +1107,9 @@ static int virtnet_probe(struct virtio_device *vdev)
goto free;

INIT_DELAYED_WORK(&vi->refill, refill_work);
mutex_init(&vi->config_lock);
vi->config_enable = true;
INIT_WORK(&vi->config_work, virtnet_config_changed_work);
sg_init_table(vi->rx_sg, ARRAY_SIZE(vi->rx_sg));
sg_init_table(vi->tx_sg, ARRAY_SIZE(vi->tx_sg));

Expand Down Expand Up @@ -1110,7 +1145,7 @@ static int virtnet_probe(struct virtio_device *vdev)
otherwise get link status from config. */
if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_STATUS)) {
netif_carrier_off(dev);
virtnet_update_status(vi);
queue_work(system_nrt_wq, &vi->config_work);
} else {
vi->status = VIRTIO_NET_S_LINK_UP;
netif_carrier_on(dev);
Expand Down Expand Up @@ -1169,10 +1204,17 @@ static void __devexit virtnet_remove(struct virtio_device *vdev)
{
struct virtnet_info *vi = vdev->priv;

/* Prevent config work handler from accessing the device. */
mutex_lock(&vi->config_lock);
vi->config_enable = false;
mutex_unlock(&vi->config_lock);

unregister_netdev(vi->dev);

remove_vq_common(vi);

flush_work(&vi->config_work);

free_percpu(vi->stats);
free_netdev(vi->dev);
}
Expand All @@ -1182,6 +1224,11 @@ static int virtnet_freeze(struct virtio_device *vdev)
{
struct virtnet_info *vi = vdev->priv;

/* Prevent config work handler from accessing the device */
mutex_lock(&vi->config_lock);
vi->config_enable = false;
mutex_unlock(&vi->config_lock);

virtqueue_disable_cb(vi->rvq);
virtqueue_disable_cb(vi->svq);
if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ))
Expand All @@ -1195,6 +1242,8 @@ static int virtnet_freeze(struct virtio_device *vdev)

remove_vq_common(vi);

flush_work(&vi->config_work);

return 0;
}

Expand All @@ -1215,6 +1264,10 @@ static int virtnet_restore(struct virtio_device *vdev)
if (!try_fill_recv(vi, GFP_KERNEL))
queue_delayed_work(system_nrt_wq, &vi->refill, 0);

mutex_lock(&vi->config_lock);
vi->config_enable = true;
mutex_unlock(&vi->config_lock);

return 0;
}
#endif
Expand All @@ -1232,6 +1285,7 @@ static unsigned int features[] = {
VIRTIO_NET_F_GUEST_ECN, VIRTIO_NET_F_GUEST_UFO,
VIRTIO_NET_F_MRG_RXBUF, VIRTIO_NET_F_STATUS, VIRTIO_NET_F_CTRL_VQ,
VIRTIO_NET_F_CTRL_RX, VIRTIO_NET_F_CTRL_VLAN,
VIRTIO_NET_F_GUEST_ANNOUNCE,
};

static struct virtio_driver virtio_net_driver = {
Expand Down
14 changes: 14 additions & 0 deletions trunk/include/linux/virtio_net.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,11 @@
#define VIRTIO_NET_F_CTRL_RX 18 /* Control channel RX mode support */
#define VIRTIO_NET_F_CTRL_VLAN 19 /* Control channel VLAN filtering */
#define VIRTIO_NET_F_CTRL_RX_EXTRA 20 /* Extra RX mode control support */
#define VIRTIO_NET_F_GUEST_ANNOUNCE 21 /* Guest can announce device on the
* network */

#define VIRTIO_NET_S_LINK_UP 1 /* Link is up */
#define VIRTIO_NET_S_ANNOUNCE 2 /* Announcement is needed */

struct virtio_net_config {
/* The config defining mac address (if VIRTIO_NET_F_MAC) */
Expand Down Expand Up @@ -152,4 +155,15 @@ struct virtio_net_ctrl_mac {
#define VIRTIO_NET_CTRL_VLAN_ADD 0
#define VIRTIO_NET_CTRL_VLAN_DEL 1

/*
* Control link announce acknowledgement
*
* The command VIRTIO_NET_CTRL_ANNOUNCE_ACK is used to indicate that
* driver has recevied the notification; device would clear the
* VIRTIO_NET_S_ANNOUNCE bit in the status field after it receives
* this command.
*/
#define VIRTIO_NET_CTRL_ANNOUNCE 3
#define VIRTIO_NET_CTRL_ANNOUNCE_ACK 0

#endif /* _LINUX_VIRTIO_NET_H */

0 comments on commit b4e81ad

Please sign in to comment.