summaryrefslogtreecommitdiff
path: root/drivers/staging/hv
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/hv')
-rw-r--r--drivers/staging/hv/channel.c8
-rw-r--r--drivers/staging/hv/connection.c4
-rw-r--r--drivers/staging/hv/netvsc_drv.c24
-rw-r--r--drivers/staging/hv/vmbus_drv.c2
-rw-r--r--drivers/staging/hv/vmbus_private.h1
5 files changed, 32 insertions, 7 deletions
diff --git a/drivers/staging/hv/channel.c b/drivers/staging/hv/channel.c
index 45a627d77b4..09e596a506b 100644
--- a/drivers/staging/hv/channel.c
+++ b/drivers/staging/hv/channel.c
@@ -76,14 +76,14 @@ static void vmbus_setevent(struct vmbus_channel *channel)
if (channel->offermsg.monitor_allocated) {
/* Each u32 represents 32 channels */
- set_bit(channel->offermsg.child_relid & 31,
+ sync_set_bit(channel->offermsg.child_relid & 31,
(unsigned long *) gVmbusConnection.SendInterruptPage +
(channel->offermsg.child_relid >> 5));
monitorpage = gVmbusConnection.MonitorPages;
monitorpage++; /* Get the child to parent monitor page */
- set_bit(channel->monitor_bit,
+ sync_set_bit(channel->monitor_bit,
(unsigned long *)&monitorpage->trigger_group
[channel->monitor_grp].pending);
@@ -99,7 +99,7 @@ static void VmbusChannelClearEvent(struct vmbus_channel *channel)
if (Channel->offermsg.monitor_allocated) {
/* Each u32 represents 32 channels */
- clear_bit(Channel->offermsg.child_relid & 31,
+ sync_clear_bit(Channel->offermsg.child_relid & 31,
(unsigned long *)gVmbusConnection.SendInterruptPage +
(Channel->offermsg.child_relid >> 5));
@@ -107,7 +107,7 @@ static void VmbusChannelClearEvent(struct vmbus_channel *channel)
(struct hv_monitor_page *)gVmbusConnection.MonitorPages;
monitorPage++; /* Get the child to parent monitor page */
- clear_bit(Channel->monitor_bit,
+ sync_clear_bit(Channel->monitor_bit,
(unsigned long *)&monitorPage->trigger_group
[Channel->monitor_grp].Pending);
}
diff --git a/drivers/staging/hv/connection.c b/drivers/staging/hv/connection.c
index c2e298ff483..0739eb7b6ee 100644
--- a/drivers/staging/hv/connection.c
+++ b/drivers/staging/hv/connection.c
@@ -281,7 +281,7 @@ void VmbusOnEvents(void)
for (dword = 0; dword < maxdword; dword++) {
if (recvInterruptPage[dword]) {
for (bit = 0; bit < 32; bit++) {
- if (test_and_clear_bit(bit, (unsigned long *)&recvInterruptPage[dword])) {
+ if (sync_test_and_clear_bit(bit, (unsigned long *)&recvInterruptPage[dword])) {
relid = (dword << 5) + bit;
DPRINT_DBG(VMBUS, "event detected for relid - %d", relid);
@@ -320,7 +320,7 @@ int VmbusPostMessage(void *buffer, size_t bufferLen)
int VmbusSetEvent(u32 childRelId)
{
/* Each u32 represents 32 channels */
- set_bit(childRelId & 31,
+ sync_set_bit(childRelId & 31,
(unsigned long *)gVmbusConnection.SendInterruptPage +
(childRelId >> 5));
diff --git a/drivers/staging/hv/netvsc_drv.c b/drivers/staging/hv/netvsc_drv.c
index b41c9640b72..f433addaae5 100644
--- a/drivers/staging/hv/netvsc_drv.c
+++ b/drivers/staging/hv/netvsc_drv.c
@@ -46,6 +46,7 @@ struct net_device_context {
/* point back to our device context */
struct vm_device *device_ctx;
unsigned long avail;
+ struct work_struct work;
};
struct netvsc_driver_context {
@@ -225,6 +226,7 @@ static void netvsc_linkstatus_callback(struct hv_device *device_obj,
unsigned int status)
{
struct vm_device *device_ctx = to_vm_device(device_obj);
+ struct net_device_context *ndev_ctx;
struct net_device *net = dev_get_drvdata(&device_ctx->device);
if (!net) {
@@ -237,6 +239,8 @@ static void netvsc_linkstatus_callback(struct hv_device *device_obj,
netif_carrier_on(net);
netif_wake_queue(net);
netif_notify_peers(net);
+ ndev_ctx = netdev_priv(net);
+ schedule_work(&ndev_ctx->work);
} else {
netif_carrier_off(net);
netif_stop_queue(net);
@@ -336,6 +340,25 @@ static const struct net_device_ops device_ops = {
.ndo_set_mac_address = eth_mac_addr,
};
+/*
+ * Send GARP packet to network peers after migrations.
+ * After Quick Migration, the network is not immediately operational in the
+ * current context when receiving RNDIS_STATUS_MEDIA_CONNECT event. So, add
+ * another netif_notify_peers() into a scheduled work, otherwise GARP packet
+ * will not be sent after quick migration, and cause network disconnection.
+ */
+static void netvsc_send_garp(struct work_struct *w)
+{
+ struct net_device_context *ndev_ctx;
+ struct net_device *net;
+
+ msleep(20);
+ ndev_ctx = container_of(w, struct net_device_context, work);
+ net = dev_get_drvdata(&ndev_ctx->device_ctx->device);
+ netif_notify_peers(net);
+}
+
+
static int netvsc_probe(struct device *device)
{
struct driver_context *driver_ctx =
@@ -364,6 +387,7 @@ static int netvsc_probe(struct device *device)
net_device_ctx->device_ctx = device_ctx;
net_device_ctx->avail = ring_size;
dev_set_drvdata(device, net);
+ INIT_WORK(&net_device_ctx->work, netvsc_send_garp);
/* Notify the netvsc driver of the new device */
ret = net_drv_obj->base.OnDeviceAdd(device_obj, &device_info);
diff --git a/drivers/staging/hv/vmbus_drv.c b/drivers/staging/hv/vmbus_drv.c
index 84fdb64d3ce..87e6cf2086f 100644
--- a/drivers/staging/hv/vmbus_drv.c
+++ b/drivers/staging/hv/vmbus_drv.c
@@ -291,7 +291,7 @@ static int vmbus_on_isr(struct hv_driver *drv)
event = (union hv_synic_event_flags *)page_addr + VMBUS_MESSAGE_SINT;
/* Since we are a child, we only need to check bit 0 */
- if (test_and_clear_bit(0, (unsigned long *) &event->flags32[0])) {
+ if (sync_test_and_clear_bit(0, (unsigned long *) &event->flags32[0])) {
DPRINT_DBG(VMBUS, "received event %d", event->flags32[0]);
ret |= 0x2;
}
diff --git a/drivers/staging/hv/vmbus_private.h b/drivers/staging/hv/vmbus_private.h
index 07f6d22eeab..c75b2d7fb2f 100644
--- a/drivers/staging/hv/vmbus_private.h
+++ b/drivers/staging/hv/vmbus_private.h
@@ -31,6 +31,7 @@
#include "channel_mgmt.h"
#include "ring_buffer.h"
#include <linux/list.h>
+#include <asm/sync_bitops.h>
/*