aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/hv
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/hv')
-rw-r--r--drivers/staging/hv/Channel.c1007
-rw-r--r--drivers/staging/hv/Channel.h112
-rw-r--r--drivers/staging/hv/ChannelInterface.c152
-rw-r--r--drivers/staging/hv/ChannelInterface.h35
-rw-r--r--drivers/staging/hv/ChannelMgmt.c686
-rw-r--r--drivers/staging/hv/Kconfig8
-rw-r--r--drivers/staging/hv/Makefile15
-rw-r--r--drivers/staging/hv/TODO5
-rw-r--r--drivers/staging/hv/blkvsc.c (renamed from drivers/staging/hv/BlkVsc.c)18
-rw-r--r--drivers/staging/hv/blkvsc_drv.c101
-rw-r--r--drivers/staging/hv/channel.c1057
-rw-r--r--drivers/staging/hv/channel.h112
-rw-r--r--drivers/staging/hv/channel_mgmt.c861
-rw-r--r--drivers/staging/hv/channel_mgmt.h (renamed from drivers/staging/hv/ChannelMgmt.h)24
-rw-r--r--drivers/staging/hv/connection.c (renamed from drivers/staging/hv/Connection.c)57
-rw-r--r--drivers/staging/hv/hv.c (renamed from drivers/staging/hv/Hv.c)263
-rw-r--r--drivers/staging/hv/hv.h (renamed from drivers/staging/hv/Hv.h)10
-rw-r--r--drivers/staging/hv/hv_timesource.c101
-rw-r--r--drivers/staging/hv/hv_utils.c308
-rw-r--r--drivers/staging/hv/logging.h24
-rw-r--r--drivers/staging/hv/netvsc.c (renamed from drivers/staging/hv/NetVsc.c)305
-rw-r--r--drivers/staging/hv/netvsc.h (renamed from drivers/staging/hv/NetVsc.h)7
-rw-r--r--drivers/staging/hv/netvsc_api.h (renamed from drivers/staging/hv/NetVscApi.h)13
-rw-r--r--drivers/staging/hv/netvsc_drv.c328
-rw-r--r--drivers/staging/hv/osd.c71
-rw-r--r--drivers/staging/hv/ring_buffer.c (renamed from drivers/staging/hv/RingBuffer.c)217
-rw-r--r--drivers/staging/hv/ring_buffer.h (renamed from drivers/staging/hv/RingBuffer.h)35
-rw-r--r--drivers/staging/hv/rndis.h2
-rw-r--r--drivers/staging/hv/rndis_filter.c (renamed from drivers/staging/hv/RndisFilter.c)148
-rw-r--r--drivers/staging/hv/rndis_filter.h (renamed from drivers/staging/hv/RndisFilter.h)2
-rw-r--r--drivers/staging/hv/storvsc.c (renamed from drivers/staging/hv/StorVsc.c)187
-rw-r--r--drivers/staging/hv/storvsc_api.h (renamed from drivers/staging/hv/StorVscApi.h)11
-rw-r--r--drivers/staging/hv/storvsc_drv.c349
-rw-r--r--drivers/staging/hv/utils.h119
-rw-r--r--drivers/staging/hv/version_info.h (renamed from drivers/staging/hv/VersionInfo.h)23
-rw-r--r--drivers/staging/hv/vmbus.c (renamed from drivers/staging/hv/Vmbus.c)89
-rw-r--r--drivers/staging/hv/vmbus.h18
-rw-r--r--drivers/staging/hv/vmbus_api.h (renamed from drivers/staging/hv/VmbusApi.h)37
-rw-r--r--drivers/staging/hv/vmbus_channel_interface.h (renamed from drivers/staging/hv/VmbusChannelInterface.h)0
-rw-r--r--drivers/staging/hv/vmbus_drv.c327
-rw-r--r--drivers/staging/hv/vmbus_packet_format.h (renamed from drivers/staging/hv/VmbusPacketFormat.h)1
-rw-r--r--drivers/staging/hv/vmbus_private.h (renamed from drivers/staging/hv/VmbusPrivate.h)13
-rw-r--r--drivers/staging/hv/vstorage.h2
43 files changed, 3597 insertions, 3663 deletions
diff --git a/drivers/staging/hv/Channel.c b/drivers/staging/hv/Channel.c
deleted file mode 100644
index 746370e..0000000
--- a/drivers/staging/hv/Channel.c
+++ /dev/null
@@ -1,1007 +0,0 @@
-/*
- * Copyright (c) 2009, Microsoft Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- * Place - Suite 330, Boston, MA 02111-1307 USA.
- *
- * Authors:
- * Haiyang Zhang <haiyangz@microsoft.com>
- * Hank Janssen <hjanssen@microsoft.com>
- */
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include "osd.h"
-#include "logging.h"
-#include "VmbusPrivate.h"
-
-/* Internal routines */
-static int VmbusChannelCreateGpadlHeader(
- void *Kbuffer, /* must be phys and virt contiguous */
- u32 Size, /* page-size multiple */
- struct vmbus_channel_msginfo **msgInfo,
- u32 *MessageCount);
-static void DumpVmbusChannel(struct vmbus_channel *channel);
-static void VmbusChannelSetEvent(struct vmbus_channel *channel);
-
-
-#if 0
-static void DumpMonitorPage(struct hv_monitor_page *MonitorPage)
-{
- int i = 0;
- int j = 0;
-
- DPRINT_DBG(VMBUS, "monitorPage - %p, trigger state - %d",
- MonitorPage, MonitorPage->TriggerState);
-
- for (i = 0; i < 4; i++)
- DPRINT_DBG(VMBUS, "trigger group (%d) - %llx", i,
- MonitorPage->TriggerGroup[i].AsUINT64);
-
- for (i = 0; i < 4; i++) {
- for (j = 0; j < 32; j++) {
- DPRINT_DBG(VMBUS, "latency (%d)(%d) - %llx", i, j,
- MonitorPage->Latency[i][j]);
- }
- }
- for (i = 0; i < 4; i++) {
- for (j = 0; j < 32; j++) {
- DPRINT_DBG(VMBUS, "param-conn id (%d)(%d) - %d", i, j,
- MonitorPage->Parameter[i][j].ConnectionId.Asu32);
- DPRINT_DBG(VMBUS, "param-flag (%d)(%d) - %d", i, j,
- MonitorPage->Parameter[i][j].FlagNumber);
- }
- }
-}
-#endif
-
-/**
- * VmbusChannelSetEvent - Trigger an event notification on the specified channel.
- */
-static void VmbusChannelSetEvent(struct vmbus_channel *Channel)
-{
- struct hv_monitor_page *monitorPage;
-
- DPRINT_ENTER(VMBUS);
-
- if (Channel->OfferMsg.MonitorAllocated) {
- /* Each u32 represents 32 channels */
- set_bit(Channel->OfferMsg.ChildRelId & 31,
- (unsigned long *) gVmbusConnection.SendInterruptPage +
- (Channel->OfferMsg.ChildRelId >> 5));
-
- monitorPage = gVmbusConnection.MonitorPages;
- monitorPage++; /* Get the child to parent monitor page */
-
- set_bit(Channel->MonitorBit,
- (unsigned long *)&monitorPage->TriggerGroup
- [Channel->MonitorGroup].Pending);
-
- } else {
- VmbusSetEvent(Channel->OfferMsg.ChildRelId);
- }
-
- DPRINT_EXIT(VMBUS);
-}
-
-#if 0
-static void VmbusChannelClearEvent(struct vmbus_channel *channel)
-{
- struct hv_monitor_page *monitorPage;
-
- DPRINT_ENTER(VMBUS);
-
- if (Channel->OfferMsg.MonitorAllocated) {
- /* Each u32 represents 32 channels */
- clear_bit(Channel->OfferMsg.ChildRelId & 31,
- (unsigned long *)gVmbusConnection.SendInterruptPage +
- (Channel->OfferMsg.ChildRelId >> 5));
-
- monitorPage =
- (struct hv_monitor_page *)gVmbusConnection.MonitorPages;
- monitorPage++; /* Get the child to parent monitor page */
-
- clear_bit(Channel->MonitorBit,
- (unsigned long *)&monitorPage->TriggerGroup
- [Channel->MonitorGroup].Pending);
- }
-
- DPRINT_EXIT(VMBUS);
-}
-
-#endif
-/**
- * VmbusChannelGetDebugInfo -Retrieve various channel debug info
- */
-void VmbusChannelGetDebugInfo(struct vmbus_channel *Channel,
- struct vmbus_channel_debug_info *DebugInfo)
-{
- struct hv_monitor_page *monitorPage;
- u8 monitorGroup = (u8)Channel->OfferMsg.MonitorId / 32;
- u8 monitorOffset = (u8)Channel->OfferMsg.MonitorId % 32;
- /* u32 monitorBit = 1 << monitorOffset; */
-
- DebugInfo->RelId = Channel->OfferMsg.ChildRelId;
- DebugInfo->State = Channel->State;
- memcpy(&DebugInfo->InterfaceType,
- &Channel->OfferMsg.Offer.InterfaceType, sizeof(struct hv_guid));
- memcpy(&DebugInfo->InterfaceInstance,
- &Channel->OfferMsg.Offer.InterfaceInstance,
- sizeof(struct hv_guid));
-
- monitorPage = (struct hv_monitor_page *)gVmbusConnection.MonitorPages;
-
- DebugInfo->MonitorId = Channel->OfferMsg.MonitorId;
-
- DebugInfo->ServerMonitorPending =
- monitorPage->TriggerGroup[monitorGroup].Pending;
- DebugInfo->ServerMonitorLatency =
- monitorPage->Latency[monitorGroup][monitorOffset];
- DebugInfo->ServerMonitorConnectionId =
- monitorPage->Parameter[monitorGroup]
- [monitorOffset].ConnectionId.u.Id;
-
- monitorPage++;
-
- DebugInfo->ClientMonitorPending =
- monitorPage->TriggerGroup[monitorGroup].Pending;
- DebugInfo->ClientMonitorLatency =
- monitorPage->Latency[monitorGroup][monitorOffset];
- DebugInfo->ClientMonitorConnectionId =
- monitorPage->Parameter[monitorGroup]
- [monitorOffset].ConnectionId.u.Id;
-
- RingBufferGetDebugInfo(&Channel->Inbound, &DebugInfo->Inbound);
- RingBufferGetDebugInfo(&Channel->Outbound, &DebugInfo->Outbound);
-}
-
-/**
- * VmbusChannelOpen - Open the specified channel.
- */
-int VmbusChannelOpen(struct vmbus_channel *NewChannel, u32 SendRingBufferSize,
- u32 RecvRingBufferSize, void *UserData, u32 UserDataLen,
- void (*OnChannelCallback)(void *context), void *Context)
-{
- struct vmbus_channel_open_channel *openMsg;
- struct vmbus_channel_msginfo *openInfo;
- void *in, *out;
- unsigned long flags;
- int ret;
-
- DPRINT_ENTER(VMBUS);
-
- /* Aligned to page size */
- ASSERT(!(SendRingBufferSize & (PAGE_SIZE - 1)));
- ASSERT(!(RecvRingBufferSize & (PAGE_SIZE - 1)));
-
- NewChannel->OnChannelCallback = OnChannelCallback;
- NewChannel->ChannelCallbackContext = Context;
-
- /* Allocate the ring buffer */
- out = osd_PageAlloc((SendRingBufferSize + RecvRingBufferSize)
- >> PAGE_SHIFT);
- ASSERT(out);
- ASSERT(((unsigned long)out & (PAGE_SIZE-1)) == 0);
-
- in = (void *)((unsigned long)out + SendRingBufferSize);
-
- NewChannel->RingBufferPages = out;
- NewChannel->RingBufferPageCount = (SendRingBufferSize +
- RecvRingBufferSize) >> PAGE_SHIFT;
-
- RingBufferInit(&NewChannel->Outbound, out, SendRingBufferSize);
-
- RingBufferInit(&NewChannel->Inbound, in, RecvRingBufferSize);
-
- /* Establish the gpadl for the ring buffer */
- DPRINT_DBG(VMBUS, "Establishing ring buffer's gpadl for channel %p...",
- NewChannel);
-
- NewChannel->RingBufferGpadlHandle = 0;
-
- ret = VmbusChannelEstablishGpadl(NewChannel,
- NewChannel->Outbound.RingBuffer,
- SendRingBufferSize +
- RecvRingBufferSize,
- &NewChannel->RingBufferGpadlHandle);
-
- DPRINT_DBG(VMBUS, "channel %p <relid %d gpadl 0x%x send ring %p "
- "size %d recv ring %p size %d, downstreamoffset %d>",
- NewChannel, NewChannel->OfferMsg.ChildRelId,
- NewChannel->RingBufferGpadlHandle,
- NewChannel->Outbound.RingBuffer,
- NewChannel->Outbound.RingSize,
- NewChannel->Inbound.RingBuffer,
- NewChannel->Inbound.RingSize,
- SendRingBufferSize);
-
- /* Create and init the channel open message */
- openInfo = kmalloc(sizeof(*openInfo) +
- sizeof(struct vmbus_channel_open_channel),
- GFP_KERNEL);
- ASSERT(openInfo != NULL);
-
- openInfo->WaitEvent = osd_WaitEventCreate();
-
- openMsg = (struct vmbus_channel_open_channel *)openInfo->Msg;
- openMsg->Header.MessageType = ChannelMessageOpenChannel;
- openMsg->OpenId = NewChannel->OfferMsg.ChildRelId; /* FIXME */
- openMsg->ChildRelId = NewChannel->OfferMsg.ChildRelId;
- openMsg->RingBufferGpadlHandle = NewChannel->RingBufferGpadlHandle;
- ASSERT(openMsg->RingBufferGpadlHandle);
- openMsg->DownstreamRingBufferPageOffset = SendRingBufferSize >>
- PAGE_SHIFT;
- openMsg->ServerContextAreaGpadlHandle = 0; /* TODO */
-
- ASSERT(UserDataLen <= MAX_USER_DEFINED_BYTES);
- if (UserDataLen)
- memcpy(openMsg->UserData, UserData, UserDataLen);
-
- spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
- list_add_tail(&openInfo->MsgListEntry,
- &gVmbusConnection.ChannelMsgList);
- spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
-
- DPRINT_DBG(VMBUS, "Sending channel open msg...");
-
- ret = VmbusPostMessage(openMsg,
- sizeof(struct vmbus_channel_open_channel));
- if (ret != 0) {
- DPRINT_ERR(VMBUS, "unable to open channel - %d", ret);
- goto Cleanup;
- }
-
- /* FIXME: Need to time-out here */
- osd_WaitEventWait(openInfo->WaitEvent);
-
- if (openInfo->Response.OpenResult.Status == 0)
- DPRINT_INFO(VMBUS, "channel <%p> open success!!", NewChannel);
- else
- DPRINT_INFO(VMBUS, "channel <%p> open failed - %d!!",
- NewChannel, openInfo->Response.OpenResult.Status);
-
-Cleanup:
- spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
- list_del(&openInfo->MsgListEntry);
- spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
-
- kfree(openInfo->WaitEvent);
- kfree(openInfo);
-
- DPRINT_EXIT(VMBUS);
-
- return 0;
-}
-
-/**
- * DumpGpadlBody - Dump the gpadl body message to the console for debugging purposes.
- */
-static void DumpGpadlBody(struct vmbus_channel_gpadl_body *Gpadl, u32 Len)
-{
- int i;
- int pfnCount;
-
- pfnCount = (Len - sizeof(struct vmbus_channel_gpadl_body)) /
- sizeof(u64);
- DPRINT_DBG(VMBUS, "gpadl body - len %d pfn count %d", Len, pfnCount);
-
- for (i = 0; i < pfnCount; i++)
- DPRINT_DBG(VMBUS, "gpadl body - %d) pfn %llu",
- i, Gpadl->Pfn[i]);
-}
-
-/**
- * DumpGpadlHeader - Dump the gpadl header message to the console for debugging purposes.
- */
-static void DumpGpadlHeader(struct vmbus_channel_gpadl_header *Gpadl)
-{
- int i, j;
- int pageCount;
-
- DPRINT_DBG(VMBUS,
- "gpadl header - relid %d, range count %d, range buflen %d",
- Gpadl->ChildRelId, Gpadl->RangeCount, Gpadl->RangeBufLen);
- for (i = 0; i < Gpadl->RangeCount; i++) {
- pageCount = Gpadl->Range[i].ByteCount >> PAGE_SHIFT;
- pageCount = (pageCount > 26) ? 26 : pageCount;
-
- DPRINT_DBG(VMBUS, "gpadl range %d - len %d offset %d "
- "page count %d", i, Gpadl->Range[i].ByteCount,
- Gpadl->Range[i].ByteOffset, pageCount);
-
- for (j = 0; j < pageCount; j++)
- DPRINT_DBG(VMBUS, "%d) pfn %llu", j,
- Gpadl->Range[i].PfnArray[j]);
- }
-}
-
-/**
- * VmbusChannelCreateGpadlHeader - Creates a gpadl for the specified buffer
- */
-static int VmbusChannelCreateGpadlHeader(void *Kbuffer, u32 Size,
- struct vmbus_channel_msginfo **MsgInfo,
- u32 *MessageCount)
-{
- int i;
- int pageCount;
- unsigned long long pfn;
- struct vmbus_channel_gpadl_header *gpaHeader;
- struct vmbus_channel_gpadl_body *gpadlBody;
- struct vmbus_channel_msginfo *msgHeader;
- struct vmbus_channel_msginfo *msgBody;
- u32 msgSize;
-
- int pfnSum, pfnCount, pfnLeft, pfnCurr, pfnSize;
-
- /* ASSERT((kbuffer & (PAGE_SIZE-1)) == 0); */
- ASSERT((Size & (PAGE_SIZE-1)) == 0);
-
- pageCount = Size >> PAGE_SHIFT;
- pfn = virt_to_phys(Kbuffer) >> PAGE_SHIFT;
-
- /* do we need a gpadl body msg */
- pfnSize = MAX_SIZE_CHANNEL_MESSAGE -
- sizeof(struct vmbus_channel_gpadl_header) -
- sizeof(struct gpa_range);
- pfnCount = pfnSize / sizeof(u64);
-
- if (pageCount > pfnCount) {
- /* we need a gpadl body */
- /* fill in the header */
- msgSize = sizeof(struct vmbus_channel_msginfo) +
- sizeof(struct vmbus_channel_gpadl_header) +
- sizeof(struct gpa_range) + pfnCount * sizeof(u64);
- msgHeader = kzalloc(msgSize, GFP_KERNEL);
-
- INIT_LIST_HEAD(&msgHeader->SubMsgList);
- msgHeader->MessageSize = msgSize;
-
- gpaHeader = (struct vmbus_channel_gpadl_header *)msgHeader->Msg;
- gpaHeader->RangeCount = 1;
- gpaHeader->RangeBufLen = sizeof(struct gpa_range) +
- pageCount * sizeof(u64);
- gpaHeader->Range[0].ByteOffset = 0;
- gpaHeader->Range[0].ByteCount = Size;
- for (i = 0; i < pfnCount; i++)
- gpaHeader->Range[0].PfnArray[i] = pfn+i;
- *MsgInfo = msgHeader;
- *MessageCount = 1;
-
- pfnSum = pfnCount;
- pfnLeft = pageCount - pfnCount;
-
- /* how many pfns can we fit */
- pfnSize = MAX_SIZE_CHANNEL_MESSAGE -
- sizeof(struct vmbus_channel_gpadl_body);
- pfnCount = pfnSize / sizeof(u64);
-
- /* fill in the body */
- while (pfnLeft) {
- if (pfnLeft > pfnCount)
- pfnCurr = pfnCount;
- else
- pfnCurr = pfnLeft;
-
- msgSize = sizeof(struct vmbus_channel_msginfo) +
- sizeof(struct vmbus_channel_gpadl_body) +
- pfnCurr * sizeof(u64);
- msgBody = kzalloc(msgSize, GFP_KERNEL);
- ASSERT(msgBody);
- msgBody->MessageSize = msgSize;
- (*MessageCount)++;
- gpadlBody =
- (struct vmbus_channel_gpadl_body *)msgBody->Msg;
-
- /*
- * FIXME:
- * Gpadl is u32 and we are using a pointer which could
- * be 64-bit
- */
- /* gpadlBody->Gpadl = kbuffer; */
- for (i = 0; i < pfnCurr; i++)
- gpadlBody->Pfn[i] = pfn + pfnSum + i;
-
- /* add to msg header */
- list_add_tail(&msgBody->MsgListEntry,
- &msgHeader->SubMsgList);
- pfnSum += pfnCurr;
- pfnLeft -= pfnCurr;
- }
- } else {
- /* everything fits in a header */
- msgSize = sizeof(struct vmbus_channel_msginfo) +
- sizeof(struct vmbus_channel_gpadl_header) +
- sizeof(struct gpa_range) + pageCount * sizeof(u64);
- msgHeader = kzalloc(msgSize, GFP_KERNEL);
- msgHeader->MessageSize = msgSize;
-
- gpaHeader = (struct vmbus_channel_gpadl_header *)msgHeader->Msg;
- gpaHeader->RangeCount = 1;
- gpaHeader->RangeBufLen = sizeof(struct gpa_range) +
- pageCount * sizeof(u64);
- gpaHeader->Range[0].ByteOffset = 0;
- gpaHeader->Range[0].ByteCount = Size;
- for (i = 0; i < pageCount; i++)
- gpaHeader->Range[0].PfnArray[i] = pfn+i;
-
- *MsgInfo = msgHeader;
- *MessageCount = 1;
- }
-
- return 0;
-}
-
-/**
- * VmbusChannelEstablishGpadl - Estabish a GPADL for the specified buffer
- *
- * @Channel: a channel
- * @Kbuffer: from kmalloc
- * @Size: page-size multiple
- * @GpadlHandle: some funky thing
- */
-int VmbusChannelEstablishGpadl(struct vmbus_channel *Channel, void *Kbuffer,
- u32 Size, u32 *GpadlHandle)
-{
- struct vmbus_channel_gpadl_header *gpadlMsg;
- struct vmbus_channel_gpadl_body *gpadlBody;
- /* struct vmbus_channel_gpadl_created *gpadlCreated; */
- struct vmbus_channel_msginfo *msgInfo;
- struct vmbus_channel_msginfo *subMsgInfo;
- u32 msgCount;
- struct list_head *curr;
- u32 nextGpadlHandle;
- unsigned long flags;
- int ret;
-
- DPRINT_ENTER(VMBUS);
-
- nextGpadlHandle = atomic_read(&gVmbusConnection.NextGpadlHandle);
- atomic_inc(&gVmbusConnection.NextGpadlHandle);
-
- VmbusChannelCreateGpadlHeader(Kbuffer, Size, &msgInfo, &msgCount);
- ASSERT(msgInfo != NULL);
- ASSERT(msgCount > 0);
-
- msgInfo->WaitEvent = osd_WaitEventCreate();
- gpadlMsg = (struct vmbus_channel_gpadl_header *)msgInfo->Msg;
- gpadlMsg->Header.MessageType = ChannelMessageGpadlHeader;
- gpadlMsg->ChildRelId = Channel->OfferMsg.ChildRelId;
- gpadlMsg->Gpadl = nextGpadlHandle;
-
- DumpGpadlHeader(gpadlMsg);
-
- spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
- list_add_tail(&msgInfo->MsgListEntry,
- &gVmbusConnection.ChannelMsgList);
-
- spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
- DPRINT_DBG(VMBUS, "buffer %p, size %d msg cnt %d",
- Kbuffer, Size, msgCount);
-
- DPRINT_DBG(VMBUS, "Sending GPADL Header - len %zd",
- msgInfo->MessageSize - sizeof(*msgInfo));
-
- ret = VmbusPostMessage(gpadlMsg, msgInfo->MessageSize -
- sizeof(*msgInfo));
- if (ret != 0) {
- DPRINT_ERR(VMBUS, "Unable to open channel - %d", ret);
- goto Cleanup;
- }
-
- if (msgCount > 1) {
- list_for_each(curr, &msgInfo->SubMsgList) {
-
- /* FIXME: should this use list_entry() instead ? */
- subMsgInfo = (struct vmbus_channel_msginfo *)curr;
- gpadlBody =
- (struct vmbus_channel_gpadl_body *)subMsgInfo->Msg;
-
- gpadlBody->Header.MessageType = ChannelMessageGpadlBody;
- gpadlBody->Gpadl = nextGpadlHandle;
-
- DPRINT_DBG(VMBUS, "Sending GPADL Body - len %zd",
- subMsgInfo->MessageSize -
- sizeof(*subMsgInfo));
-
- DumpGpadlBody(gpadlBody, subMsgInfo->MessageSize -
- sizeof(*subMsgInfo));
- ret = VmbusPostMessage(gpadlBody,
- subMsgInfo->MessageSize -
- sizeof(*subMsgInfo));
- ASSERT(ret == 0);
- }
- }
- osd_WaitEventWait(msgInfo->WaitEvent);
-
- /* At this point, we received the gpadl created msg */
- DPRINT_DBG(VMBUS, "Received GPADL created "
- "(relid %d, status %d handle %x)",
- Channel->OfferMsg.ChildRelId,
- msgInfo->Response.GpadlCreated.CreationStatus,
- gpadlMsg->Gpadl);
-
- *GpadlHandle = gpadlMsg->Gpadl;
-
-Cleanup:
- spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
- list_del(&msgInfo->MsgListEntry);
- spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
-
- kfree(msgInfo->WaitEvent);
- kfree(msgInfo);
-
- DPRINT_EXIT(VMBUS);
-
- return ret;
-}
-
-/**
- * VmbusChannelTeardownGpadl -Teardown the specified GPADL handle
- */
-int VmbusChannelTeardownGpadl(struct vmbus_channel *Channel, u32 GpadlHandle)
-{
- struct vmbus_channel_gpadl_teardown *msg;
- struct vmbus_channel_msginfo *info;
- unsigned long flags;
- int ret;
-
- DPRINT_ENTER(VMBUS);
-
- ASSERT(GpadlHandle != 0);
-
- info = kmalloc(sizeof(*info) +
- sizeof(struct vmbus_channel_gpadl_teardown), GFP_KERNEL);
- ASSERT(info != NULL);
-
- info->WaitEvent = osd_WaitEventCreate();
-
- msg = (struct vmbus_channel_gpadl_teardown *)info->Msg;
-
- msg->Header.MessageType = ChannelMessageGpadlTeardown;
- msg->ChildRelId = Channel->OfferMsg.ChildRelId;
- msg->Gpadl = GpadlHandle;
-
- spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
- list_add_tail(&info->MsgListEntry,
- &gVmbusConnection.ChannelMsgList);
- spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
-
- ret = VmbusPostMessage(msg,
- sizeof(struct vmbus_channel_gpadl_teardown));
- if (ret != 0) {
- /* TODO: */
- /* something... */
- }
-
- osd_WaitEventWait(info->WaitEvent);
-
- /* Received a torndown response */
- spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
- list_del(&info->MsgListEntry);
- spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
-
- kfree(info->WaitEvent);
- kfree(info);
-
- DPRINT_EXIT(VMBUS);
-
- return ret;
-}
-
-/**
- * VmbusChannelClose - Close the specified channel
- */
-void VmbusChannelClose(struct vmbus_channel *Channel)
-{
- struct vmbus_channel_close_channel *msg;
- struct vmbus_channel_msginfo *info;
- unsigned long flags;
- int ret;
-
- DPRINT_ENTER(VMBUS);
-
- /* Stop callback and cancel the timer asap */
- Channel->OnChannelCallback = NULL;
- del_timer_sync(&Channel->poll_timer);
-
- /* Send a closing message */
- info = kmalloc(sizeof(*info) +
- sizeof(struct vmbus_channel_close_channel), GFP_KERNEL);
- ASSERT(info != NULL);
-
- /* info->waitEvent = osd_WaitEventCreate(); */
-
- msg = (struct vmbus_channel_close_channel *)info->Msg;
- msg->Header.MessageType = ChannelMessageCloseChannel;
- msg->ChildRelId = Channel->OfferMsg.ChildRelId;
-
- ret = VmbusPostMessage(msg, sizeof(struct vmbus_channel_close_channel));
- if (ret != 0) {
- /* TODO: */
- /* something... */
- }
-
- /* Tear down the gpadl for the channel's ring buffer */
- if (Channel->RingBufferGpadlHandle)
- VmbusChannelTeardownGpadl(Channel,
- Channel->RingBufferGpadlHandle);
-
- /* TODO: Send a msg to release the childRelId */
-
- /* Cleanup the ring buffers for this channel */
- RingBufferCleanup(&Channel->Outbound);
- RingBufferCleanup(&Channel->Inbound);
-
- osd_PageFree(Channel->RingBufferPages, Channel->RingBufferPageCount);
-
- kfree(info);
-
- /*
- * If we are closing the channel during an error path in
- * opening the channel, don't free the channel since the
- * caller will free the channel
- */
-
- if (Channel->State == CHANNEL_OPEN_STATE) {
- spin_lock_irqsave(&gVmbusConnection.channel_lock, flags);
- list_del(&Channel->ListEntry);
- spin_unlock_irqrestore(&gVmbusConnection.channel_lock, flags);
-
- FreeVmbusChannel(Channel);
- }
-
- DPRINT_EXIT(VMBUS);
-}
-
-/**
- * VmbusChannelSendPacket - Send the specified buffer on the given channel
- */
-int VmbusChannelSendPacket(struct vmbus_channel *Channel, const void *Buffer,
- u32 BufferLen, u64 RequestId,
- enum vmbus_packet_type Type, u32 Flags)
-{
- struct vmpacket_descriptor desc;
- u32 packetLen = sizeof(struct vmpacket_descriptor) + BufferLen;
- u32 packetLenAligned = ALIGN_UP(packetLen, sizeof(u64));
- struct scatterlist bufferList[3];
- u64 alignedData = 0;
- int ret;
-
- DPRINT_ENTER(VMBUS);
- DPRINT_DBG(VMBUS, "channel %p buffer %p len %d",
- Channel, Buffer, BufferLen);
-
- DumpVmbusChannel(Channel);
-
- ASSERT((packetLenAligned - packetLen) < sizeof(u64));
-
- /* Setup the descriptor */
- desc.Type = Type; /* VmbusPacketTypeDataInBand; */
- desc.Flags = Flags; /* VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED; */
- /* in 8-bytes granularity */
- desc.DataOffset8 = sizeof(struct vmpacket_descriptor) >> 3;
- desc.Length8 = (u16)(packetLenAligned >> 3);
- desc.TransactionId = RequestId;
-
- sg_init_table(bufferList, 3);
- sg_set_buf(&bufferList[0], &desc, sizeof(struct vmpacket_descriptor));
- sg_set_buf(&bufferList[1], Buffer, BufferLen);
- sg_set_buf(&bufferList[2], &alignedData, packetLenAligned - packetLen);
-
- ret = RingBufferWrite(&Channel->Outbound, bufferList, 3);
-
- /* TODO: We should determine if this is optional */
- if (ret == 0 && !GetRingBufferInterruptMask(&Channel->Outbound))
- VmbusChannelSetEvent(Channel);
-
- DPRINT_EXIT(VMBUS);
-
- return ret;
-}
-
-/**
- * VmbusChannelSendPacketPageBuffer - Send a range of single-page buffer packets using a GPADL Direct packet type.
- */
-int VmbusChannelSendPacketPageBuffer(struct vmbus_channel *Channel,
- struct hv_page_buffer PageBuffers[],
- u32 PageCount, void *Buffer, u32 BufferLen,
- u64 RequestId)
-{
- int ret;
- int i;
- struct VMBUS_CHANNEL_PACKET_PAGE_BUFFER desc;
- u32 descSize;
- u32 packetLen;
- u32 packetLenAligned;
- struct scatterlist bufferList[3];
- u64 alignedData = 0;
-
- DPRINT_ENTER(VMBUS);
-
- ASSERT(PageCount <= MAX_PAGE_BUFFER_COUNT);
-
- DumpVmbusChannel(Channel);
-
- /*
- * Adjust the size down since VMBUS_CHANNEL_PACKET_PAGE_BUFFER is the
- * largest size we support
- */
- descSize = sizeof(struct VMBUS_CHANNEL_PACKET_PAGE_BUFFER) -
- ((MAX_PAGE_BUFFER_COUNT - PageCount) *
- sizeof(struct hv_page_buffer));
- packetLen = descSize + BufferLen;
- packetLenAligned = ALIGN_UP(packetLen, sizeof(u64));
-
- ASSERT((packetLenAligned - packetLen) < sizeof(u64));
-
- /* Setup the descriptor */
- desc.Type = VmbusPacketTypeDataUsingGpaDirect;
- desc.Flags = VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED;
- desc.DataOffset8 = descSize >> 3; /* in 8-bytes grandularity */
- desc.Length8 = (u16)(packetLenAligned >> 3);
- desc.TransactionId = RequestId;
- desc.RangeCount = PageCount;
-
- for (i = 0; i < PageCount; i++) {
- desc.Range[i].Length = PageBuffers[i].Length;
- desc.Range[i].Offset = PageBuffers[i].Offset;
- desc.Range[i].Pfn = PageBuffers[i].Pfn;
- }
-
- sg_init_table(bufferList, 3);
- sg_set_buf(&bufferList[0], &desc, descSize);
- sg_set_buf(&bufferList[1], Buffer, BufferLen);
- sg_set_buf(&bufferList[2], &alignedData, packetLenAligned - packetLen);
-
- ret = RingBufferWrite(&Channel->Outbound, bufferList, 3);
-
- /* TODO: We should determine if this is optional */
- if (ret == 0 && !GetRingBufferInterruptMask(&Channel->Outbound))
- VmbusChannelSetEvent(Channel);
-
- DPRINT_EXIT(VMBUS);
-
- return ret;
-}
-
-/**
- * VmbusChannelSendPacketMultiPageBuffer - Send a multi-page buffer packet using a GPADL Direct packet type.
- */
-int VmbusChannelSendPacketMultiPageBuffer(struct vmbus_channel *Channel,
- struct hv_multipage_buffer *MultiPageBuffer,
- void *Buffer, u32 BufferLen, u64 RequestId)
-{
- int ret;
- struct VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER desc;
- u32 descSize;
- u32 packetLen;
- u32 packetLenAligned;
- struct scatterlist bufferList[3];
- u64 alignedData = 0;
- u32 PfnCount = NUM_PAGES_SPANNED(MultiPageBuffer->Offset,
- MultiPageBuffer->Length);
-
- DPRINT_ENTER(VMBUS);
-
- DumpVmbusChannel(Channel);
-
- DPRINT_DBG(VMBUS, "data buffer - offset %u len %u pfn count %u",
- MultiPageBuffer->Offset, MultiPageBuffer->Length, PfnCount);
-
- ASSERT(PfnCount > 0);
- ASSERT(PfnCount <= MAX_MULTIPAGE_BUFFER_COUNT);
-
- /*
- * Adjust the size down since VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER is
- * the largest size we support
- */
- descSize = sizeof(struct VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER) -
- ((MAX_MULTIPAGE_BUFFER_COUNT - PfnCount) *
- sizeof(u64));
- packetLen = descSize + BufferLen;
- packetLenAligned = ALIGN_UP(packetLen, sizeof(u64));
-
- ASSERT((packetLenAligned - packetLen) < sizeof(u64));
-
- /* Setup the descriptor */
- desc.Type = VmbusPacketTypeDataUsingGpaDirect;
- desc.Flags = VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED;
- desc.DataOffset8 = descSize >> 3; /* in 8-bytes grandularity */
- desc.Length8 = (u16)(packetLenAligned >> 3);
- desc.TransactionId = RequestId;
- desc.RangeCount = 1;
-
- desc.Range.Length = MultiPageBuffer->Length;
- desc.Range.Offset = MultiPageBuffer->Offset;
-
- memcpy(desc.Range.PfnArray, MultiPageBuffer->PfnArray,
- PfnCount * sizeof(u64));
-
- sg_init_table(bufferList, 3);
- sg_set_buf(&bufferList[0], &desc, descSize);
- sg_set_buf(&bufferList[1], Buffer, BufferLen);
- sg_set_buf(&bufferList[2], &alignedData, packetLenAligned - packetLen);
-
- ret = RingBufferWrite(&Channel->Outbound, bufferList, 3);
-
- /* TODO: We should determine if this is optional */
- if (ret == 0 && !GetRingBufferInterruptMask(&Channel->Outbound))
- VmbusChannelSetEvent(Channel);
-
- DPRINT_EXIT(VMBUS);
-
- return ret;
-}
-
-/**
- * VmbusChannelRecvPacket - Retrieve the user packet on the specified channel
- */
-/* TODO: Do we ever receive a gpa direct packet other than the ones we send ? */
-int VmbusChannelRecvPacket(struct vmbus_channel *Channel, void *Buffer,
- u32 BufferLen, u32 *BufferActualLen, u64 *RequestId)
-{
- struct vmpacket_descriptor desc;
- u32 packetLen;
- u32 userLen;
- int ret;
- unsigned long flags;
-
- DPRINT_ENTER(VMBUS);
-
- *BufferActualLen = 0;
- *RequestId = 0;
-
- spin_lock_irqsave(&Channel->inbound_lock, flags);
-
- ret = RingBufferPeek(&Channel->Inbound, &desc,
- sizeof(struct vmpacket_descriptor));
- if (ret != 0) {
- spin_unlock_irqrestore(&Channel->inbound_lock, flags);
-
- /* DPRINT_DBG(VMBUS, "nothing to read!!"); */
- DPRINT_EXIT(VMBUS);
- return 0;
- }
-
- /* VmbusChannelClearEvent(Channel); */
-
- packetLen = desc.Length8 << 3;
- userLen = packetLen - (desc.DataOffset8 << 3);
- /* ASSERT(userLen > 0); */
-
- DPRINT_DBG(VMBUS, "packet received on channel %p relid %d <type %d "
- "flag %d tid %llx pktlen %d datalen %d> ",
- Channel, Channel->OfferMsg.ChildRelId, desc.Type,
- desc.Flags, desc.TransactionId, packetLen, userLen);
-
- *BufferActualLen = userLen;
-
- if (userLen > BufferLen) {
- spin_unlock_irqrestore(&Channel->inbound_lock, flags);
-
- DPRINT_ERR(VMBUS, "buffer too small - got %d needs %d",
- BufferLen, userLen);
- DPRINT_EXIT(VMBUS);
-
- return -1;
- }
-
- *RequestId = desc.TransactionId;
-
- /* Copy over the packet to the user buffer */
- ret = RingBufferRead(&Channel->Inbound, Buffer, userLen,
- (desc.DataOffset8 << 3));
-
- spin_unlock_irqrestore(&Channel->inbound_lock, flags);
-
- DPRINT_EXIT(VMBUS);
-
- return 0;
-}
-
-/**
- * VmbusChannelRecvPacketRaw - Retrieve the raw packet on the specified channel
- */
-int VmbusChannelRecvPacketRaw(struct vmbus_channel *Channel, void *Buffer,
- u32 BufferLen, u32 *BufferActualLen,
- u64 *RequestId)
-{
- struct vmpacket_descriptor desc;
- u32 packetLen;
- u32 userLen;
- int ret;
- unsigned long flags;
-
- DPRINT_ENTER(VMBUS);
-
- *BufferActualLen = 0;
- *RequestId = 0;
-
- spin_lock_irqsave(&Channel->inbound_lock, flags);
-
- ret = RingBufferPeek(&Channel->Inbound, &desc,
- sizeof(struct vmpacket_descriptor));
- if (ret != 0) {
- spin_unlock_irqrestore(&Channel->inbound_lock, flags);
-
- /* DPRINT_DBG(VMBUS, "nothing to read!!"); */
- DPRINT_EXIT(VMBUS);
- return 0;
- }
-
- /* VmbusChannelClearEvent(Channel); */
-
- packetLen = desc.Length8 << 3;
- userLen = packetLen - (desc.DataOffset8 << 3);
-
- DPRINT_DBG(VMBUS, "packet received on channel %p relid %d <type %d "
- "flag %d tid %llx pktlen %d datalen %d> ",
- Channel, Channel->OfferMsg.ChildRelId, desc.Type,
- desc.Flags, desc.TransactionId, packetLen, userLen);
-
- *BufferActualLen = packetLen;
-
- if (packetLen > BufferLen) {
- spin_unlock_irqrestore(&Channel->inbound_lock, flags);
-
- DPRINT_ERR(VMBUS, "buffer too small - needed %d bytes but "
- "got space for only %d bytes", packetLen, BufferLen);
- DPRINT_EXIT(VMBUS);
- return -2;
- }
-
- *RequestId = desc.TransactionId;
-
- /* Copy over the entire packet to the user buffer */
- ret = RingBufferRead(&Channel->Inbound, Buffer, packetLen, 0);
-
- spin_unlock_irqrestore(&Channel->inbound_lock, flags);
-
- DPRINT_EXIT(VMBUS);
-
- return 0;
-}
-
-/**
- * VmbusChannelOnChannelEvent - Channel event callback
- */
-void VmbusChannelOnChannelEvent(struct vmbus_channel *Channel)
-{
- DumpVmbusChannel(Channel);
- ASSERT(Channel->OnChannelCallback);
-
- Channel->OnChannelCallback(Channel->ChannelCallbackContext);
-
- mod_timer(&Channel->poll_timer, jiffies + usecs_to_jiffies(100));
-}
-
-/**
- * VmbusChannelOnTimer - Timer event callback
- */
-void VmbusChannelOnTimer(unsigned long data)
-{
- struct vmbus_channel *channel = (struct vmbus_channel *)data;
-
- if (channel->OnChannelCallback) {
- channel->OnChannelCallback(channel->ChannelCallbackContext);
- }
-}
-
-/**
- * DumpVmbusChannel - Dump vmbus channel info to the console
- */
-static void DumpVmbusChannel(struct vmbus_channel *Channel)
-{
- DPRINT_DBG(VMBUS, "Channel (%d)", Channel->OfferMsg.ChildRelId);
- DumpRingInfo(&Channel->Outbound, "Outbound ");
- DumpRingInfo(&Channel->Inbound, "Inbound ");
-}
diff --git a/drivers/staging/hv/Channel.h b/drivers/staging/hv/Channel.h
deleted file mode 100644
index 6b283ed..0000000
--- a/drivers/staging/hv/Channel.h
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- *
- * Copyright (c) 2009, Microsoft Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- * Place - Suite 330, Boston, MA 02111-1307 USA.
- *
- * Authors:
- * Haiyang Zhang <haiyangz@microsoft.com>
- * Hank Janssen <hjanssen@microsoft.com>
- *
- */
-
-
-#ifndef _CHANNEL_H_
-#define _CHANNEL_H_
-
-#include "ChannelMgmt.h"
-
-/* The format must be the same as struct vmdata_gpa_direct */
-struct VMBUS_CHANNEL_PACKET_PAGE_BUFFER {
- u16 Type;
- u16 DataOffset8;
- u16 Length8;
- u16 Flags;
- u64 TransactionId;
- u32 Reserved;
- u32 RangeCount;
- struct hv_page_buffer Range[MAX_PAGE_BUFFER_COUNT];
-} __attribute__((packed));
-
-/* The format must be the same as struct vmdata_gpa_direct */
-struct VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER {
- u16 Type;
- u16 DataOffset8;
- u16 Length8;
- u16 Flags;
- u64 TransactionId;
- u32 Reserved;
- u32 RangeCount; /* Always 1 in this case */
- struct hv_multipage_buffer Range;
-} __attribute__((packed));
-
-
-extern int VmbusChannelOpen(struct vmbus_channel *channel,
- u32 SendRingBufferSize,
- u32 RecvRingBufferSize,
- void *UserData,
- u32 UserDataLen,
- void(*OnChannelCallback)(void *context),
- void *Context);
-
-extern void VmbusChannelClose(struct vmbus_channel *channel);
-
-extern int VmbusChannelSendPacket(struct vmbus_channel *channel,
- const void *Buffer,
- u32 BufferLen,
- u64 RequestId,
- enum vmbus_packet_type Type,
- u32 Flags);
-
-extern int VmbusChannelSendPacketPageBuffer(struct vmbus_channel *channel,
- struct hv_page_buffer PageBuffers[],
- u32 PageCount,
- void *Buffer,
- u32 BufferLen,
- u64 RequestId);
-
-extern int VmbusChannelSendPacketMultiPageBuffer(struct vmbus_channel *channel,
- struct hv_multipage_buffer *mpb,
- void *Buffer,
- u32 BufferLen,
- u64 RequestId);
-
-extern int VmbusChannelEstablishGpadl(struct vmbus_channel *channel,
- void *Kbuffer,
- u32 Size,
- u32 *GpadlHandle);
-
-extern int VmbusChannelTeardownGpadl(struct vmbus_channel *channel,
- u32 GpadlHandle);
-
-extern int VmbusChannelRecvPacket(struct vmbus_channel *channel,
- void *Buffer,
- u32 BufferLen,
- u32 *BufferActualLen,
- u64 *RequestId);
-
-extern int VmbusChannelRecvPacketRaw(struct vmbus_channel *channel,
- void *Buffer,
- u32 BufferLen,
- u32 *BufferActualLen,
- u64 *RequestId);
-
-extern void VmbusChannelOnChannelEvent(struct vmbus_channel *channel);
-
-extern void VmbusChannelGetDebugInfo(struct vmbus_channel *channel,
- struct vmbus_channel_debug_info *debug);
-
-extern void VmbusChannelOnTimer(unsigned long data);
-
-#endif /* _CHANNEL_H_ */
diff --git a/drivers/staging/hv/ChannelInterface.c b/drivers/staging/hv/ChannelInterface.c
deleted file mode 100644
index 019b064..0000000
--- a/drivers/staging/hv/ChannelInterface.c
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- *
- * Copyright (c) 2009, Microsoft Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- * Place - Suite 330, Boston, MA 02111-1307 USA.
- *
- * Authors:
- * Haiyang Zhang <haiyangz@microsoft.com>
- * Hank Janssen <hjanssen@microsoft.com>
- *
- */
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include "osd.h"
-#include "VmbusPrivate.h"
-
-static int IVmbusChannelOpen(struct hv_device *device, u32 SendBufferSize,
- u32 RecvRingBufferSize, void *UserData,
- u32 UserDataLen,
- void (*ChannelCallback)(void *context),
- void *Context)
-{
- return VmbusChannelOpen(device->context, SendBufferSize,
- RecvRingBufferSize, UserData, UserDataLen,
- ChannelCallback, Context);
-}
-
-static void IVmbusChannelClose(struct hv_device *device)
-{
- VmbusChannelClose(device->context);
-}
-
-static int IVmbusChannelSendPacket(struct hv_device *device, const void *Buffer,
- u32 BufferLen, u64 RequestId, u32 Type,
- u32 Flags)
-{
- return VmbusChannelSendPacket(device->context, Buffer, BufferLen,
- RequestId, Type, Flags);
-}
-
-static int IVmbusChannelSendPacketPageBuffer(struct hv_device *device,
- struct hv_page_buffer PageBuffers[],
- u32 PageCount, void *Buffer,
- u32 BufferLen, u64 RequestId)
-{
- return VmbusChannelSendPacketPageBuffer(device->context, PageBuffers,
- PageCount, Buffer, BufferLen,
- RequestId);
-}
-
-static int IVmbusChannelSendPacketMultiPageBuffer(struct hv_device *device,
- struct hv_multipage_buffer *MultiPageBuffer,
- void *Buffer, u32 BufferLen, u64 RequestId)
-{
- return VmbusChannelSendPacketMultiPageBuffer(device->context,
- MultiPageBuffer, Buffer,
- BufferLen, RequestId);
-}
-
-static int IVmbusChannelRecvPacket(struct hv_device *device, void *Buffer,
- u32 BufferLen, u32 *BufferActualLen,
- u64 *RequestId)
-{
- return VmbusChannelRecvPacket(device->context, Buffer, BufferLen,
- BufferActualLen, RequestId);
-}
-
-static int IVmbusChannelRecvPacketRaw(struct hv_device *device, void *Buffer,
- u32 BufferLen, u32 *BufferActualLen,
- u64 *RequestId)
-{
- return VmbusChannelRecvPacketRaw(device->context, Buffer, BufferLen,
- BufferActualLen, RequestId);
-}
-
-static int IVmbusChannelEstablishGpadl(struct hv_device *device, void *Buffer,
- u32 BufferLen, u32 *GpadlHandle)
-{
- return VmbusChannelEstablishGpadl(device->context, Buffer, BufferLen,
- GpadlHandle);
-}
-
-static int IVmbusChannelTeardownGpadl(struct hv_device *device, u32 GpadlHandle)
-{
- return VmbusChannelTeardownGpadl(device->context, GpadlHandle);
-
-}
-
-void GetChannelInterface(struct vmbus_channel_interface *iface)
-{
- iface->Open = IVmbusChannelOpen;
- iface->Close = IVmbusChannelClose;
- iface->SendPacket = IVmbusChannelSendPacket;
- iface->SendPacketPageBuffer = IVmbusChannelSendPacketPageBuffer;
- iface->SendPacketMultiPageBuffer =
- IVmbusChannelSendPacketMultiPageBuffer;
- iface->RecvPacket = IVmbusChannelRecvPacket;
- iface->RecvPacketRaw = IVmbusChannelRecvPacketRaw;
- iface->EstablishGpadl = IVmbusChannelEstablishGpadl;
- iface->TeardownGpadl = IVmbusChannelTeardownGpadl;
- iface->GetInfo = GetChannelInfo;
-}
-
-void GetChannelInfo(struct hv_device *device, struct hv_device_info *info)
-{
- struct vmbus_channel_debug_info debugInfo;
-
- if (!device->context)
- return;
-
- VmbusChannelGetDebugInfo(device->context, &debugInfo);
-
- info->ChannelId = debugInfo.RelId;
- info->ChannelState = debugInfo.State;
- memcpy(&info->ChannelType, &debugInfo.InterfaceType,
- sizeof(struct hv_guid));
- memcpy(&info->ChannelInstance, &debugInfo.InterfaceInstance,
- sizeof(struct hv_guid));
-
- info->MonitorId = debugInfo.MonitorId;
-
- info->ServerMonitorPending = debugInfo.ServerMonitorPending;
- info->ServerMonitorLatency = debugInfo.ServerMonitorLatency;
- info->ServerMonitorConnectionId = debugInfo.ServerMonitorConnectionId;
-
- info->ClientMonitorPending = debugInfo.ClientMonitorPending;
- info->ClientMonitorLatency = debugInfo.ClientMonitorLatency;
- info->ClientMonitorConnectionId = debugInfo.ClientMonitorConnectionId;
-
- info->Inbound.InterruptMask = debugInfo.Inbound.CurrentInterruptMask;
- info->Inbound.ReadIndex = debugInfo.Inbound.CurrentReadIndex;
- info->Inbound.WriteIndex = debugInfo.Inbound.CurrentWriteIndex;
- info->Inbound.BytesAvailToRead = debugInfo.Inbound.BytesAvailToRead;
- info->Inbound.BytesAvailToWrite = debugInfo.Inbound.BytesAvailToWrite;
-
- info->Outbound.InterruptMask = debugInfo.Outbound.CurrentInterruptMask;
- info->Outbound.ReadIndex = debugInfo.Outbound.CurrentReadIndex;
- info->Outbound.WriteIndex = debugInfo.Outbound.CurrentWriteIndex;
- info->Outbound.BytesAvailToRead = debugInfo.Outbound.BytesAvailToRead;
- info->Outbound.BytesAvailToWrite = debugInfo.Outbound.BytesAvailToWrite;
-}
diff --git a/drivers/staging/hv/ChannelInterface.h b/drivers/staging/hv/ChannelInterface.h
deleted file mode 100644
index 27b7a25..0000000
--- a/drivers/staging/hv/ChannelInterface.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- *
- * Copyright (c) 2009, Microsoft Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- * Place - Suite 330, Boston, MA 02111-1307 USA.
- *
- * Authors:
- * Haiyang Zhang <haiyangz@microsoft.com>
- * Hank Janssen <hjanssen@microsoft.com>
- *
- */
-
-
-#ifndef _CHANNEL_INTERFACE_H_
-#define _CHANNEL_INTERFACE_H_
-
-#include "VmbusApi.h"
-
-void GetChannelInterface(struct vmbus_channel_interface *ChannelInterface);
-
-void GetChannelInfo(struct hv_device *Device,
- struct hv_device_info *DeviceInfo);
-
-#endif /* _CHANNEL_INTERFACE_H_ */
diff --git a/drivers/staging/hv/ChannelMgmt.c b/drivers/staging/hv/ChannelMgmt.c
deleted file mode 100644
index ef38467..0000000
--- a/drivers/staging/hv/ChannelMgmt.c
+++ /dev/null
@@ -1,686 +0,0 @@
-/*
- * Copyright (c) 2009, Microsoft Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- * Place - Suite 330, Boston, MA 02111-1307 USA.
- *
- * Authors:
- * Haiyang Zhang <haiyangz@microsoft.com>
- * Hank Janssen <hjanssen@microsoft.com>
- */
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/list.h>
-#include "osd.h"
-#include "logging.h"
-#include "VmbusPrivate.h"
-
-struct vmbus_channel_message_table_entry {
- enum vmbus_channel_message_type messageType;
- void (*messageHandler)(struct vmbus_channel_message_header *msg);
-};
-
-#define MAX_NUM_DEVICE_CLASSES_SUPPORTED 4
-static const struct hv_guid
- gSupportedDeviceClasses[MAX_NUM_DEVICE_CLASSES_SUPPORTED] = {
- /* {ba6163d9-04a1-4d29-b605-72e2ffb1dc7f} */
- /* Storage - SCSI */
- {
- .data = {
- 0xd9, 0x63, 0x61, 0xba, 0xa1, 0x04, 0x29, 0x4d,
- 0xb6, 0x05, 0x72, 0xe2, 0xff, 0xb1, 0xdc, 0x7f
- }
- },
-
- /* {F8615163-DF3E-46c5-913F-F2D2F965ED0E} */
- /* Network */
- {
- .data = {
- 0x63, 0x51, 0x61, 0xF8, 0x3E, 0xDF, 0xc5, 0x46,
- 0x91, 0x3F, 0xF2, 0xD2, 0xF9, 0x65, 0xED, 0x0E
- }
- },
-
- /* {CFA8B69E-5B4A-4cc0-B98B-8BA1A1F3F95A} */
- /* Input */
- {
- .data = {
- 0x9E, 0xB6, 0xA8, 0xCF, 0x4A, 0x5B, 0xc0, 0x4c,
- 0xB9, 0x8B, 0x8B, 0xA1, 0xA1, 0xF3, 0xF9, 0x5A
- }
- },
-
- /* {32412632-86cb-44a2-9b5c-50d1417354f5} */
- /* IDE */
- {
- .data = {
- 0x32, 0x26, 0x41, 0x32, 0xcb, 0x86, 0xa2, 0x44,
- 0x9b, 0x5c, 0x50, 0xd1, 0x41, 0x73, 0x54, 0xf5
- }
- },
-};
-
-/**
- * AllocVmbusChannel - Allocate and initialize a vmbus channel object
- */
-struct vmbus_channel *AllocVmbusChannel(void)
-{
- struct vmbus_channel *channel;
-
- channel = kzalloc(sizeof(*channel), GFP_ATOMIC);
- if (!channel)
- return NULL;
-
- spin_lock_init(&channel->inbound_lock);
-
- init_timer(&channel->poll_timer);
- channel->poll_timer.data = (unsigned long)channel;
- channel->poll_timer.function = VmbusChannelOnTimer;
-
- channel->ControlWQ = create_workqueue("hv_vmbus_ctl");
- if (!channel->ControlWQ) {
- kfree(channel);
- return NULL;
- }
-
- return channel;
-}
-
-/**
- * ReleaseVmbusChannel - Release the vmbus channel object itself
- */
-static inline void ReleaseVmbusChannel(void *context)
-{
- struct vmbus_channel *channel = context;
-
- DPRINT_ENTER(VMBUS);
-
- DPRINT_DBG(VMBUS, "releasing channel (%p)", channel);
- destroy_workqueue(channel->ControlWQ);
- DPRINT_DBG(VMBUS, "channel released (%p)", channel);
-
- kfree(channel);
-
- DPRINT_EXIT(VMBUS);
-}
-
-/**
- * FreeVmbusChannel - Release the resources used by the vmbus channel object
- */
-void FreeVmbusChannel(struct vmbus_channel *Channel)
-{
- del_timer_sync(&Channel->poll_timer);
-
- /*
- * We have to release the channel's workqueue/thread in the vmbus's
- * workqueue/thread context
- * ie we can't destroy ourselves.
- */
- osd_schedule_callback(gVmbusConnection.WorkQueue, ReleaseVmbusChannel,
- Channel);
-}
-
-/**
- * VmbusChannelProcessOffer - Process the offer by creating a channel/device associated with this offer
- */
-static void VmbusChannelProcessOffer(void *context)
-{
- struct vmbus_channel *newChannel = context;
- struct vmbus_channel *channel;
- bool fNew = true;
- int ret;
- unsigned long flags;
-
- DPRINT_ENTER(VMBUS);
-
- /* Make sure this is a new offer */
- spin_lock_irqsave(&gVmbusConnection.channel_lock, flags);
-
- list_for_each_entry(channel, &gVmbusConnection.ChannelList, ListEntry) {
- if (!memcmp(&channel->OfferMsg.Offer.InterfaceType,
- &newChannel->OfferMsg.Offer.InterfaceType,
- sizeof(struct hv_guid)) &&
- !memcmp(&channel->OfferMsg.Offer.InterfaceInstance,
- &newChannel->OfferMsg.Offer.InterfaceInstance,
- sizeof(struct hv_guid))) {
- fNew = false;
- break;
- }
- }
-
- if (fNew)
- list_add_tail(&newChannel->ListEntry,
- &gVmbusConnection.ChannelList);
-
- spin_unlock_irqrestore(&gVmbusConnection.channel_lock, flags);
-
- if (!fNew) {
- DPRINT_DBG(VMBUS, "Ignoring duplicate offer for relid (%d)",
- newChannel->OfferMsg.ChildRelId);
- FreeVmbusChannel(newChannel);
- DPRINT_EXIT(VMBUS);
- return;
- }
-
- /*
- * Start the process of binding this offer to the driver
- * We need to set the DeviceObject field before calling
- * VmbusChildDeviceAdd()
- */
- newChannel->DeviceObject = VmbusChildDeviceCreate(
- &newChannel->OfferMsg.Offer.InterfaceType,
- &newChannel->OfferMsg.Offer.InterfaceInstance,
- newChannel);
-
- DPRINT_DBG(VMBUS, "child device object allocated - %p",
- newChannel->DeviceObject);
-
- /*
- * Add the new device to the bus. This will kick off device-driver
- * binding which eventually invokes the device driver's AddDevice()
- * method.
- */
- ret = VmbusChildDeviceAdd(newChannel->DeviceObject);
- if (ret != 0) {
- DPRINT_ERR(VMBUS,
- "unable to add child device object (relid %d)",
- newChannel->OfferMsg.ChildRelId);
-
- spin_lock_irqsave(&gVmbusConnection.channel_lock, flags);
- list_del(&newChannel->ListEntry);
- spin_unlock_irqrestore(&gVmbusConnection.channel_lock, flags);
-
- FreeVmbusChannel(newChannel);
- } else {
- /*
- * This state is used to indicate a successful open
- * so that when we do close the channel normally, we
- * can cleanup properly
- */
- newChannel->State = CHANNEL_OPEN_STATE;
- }
- DPRINT_EXIT(VMBUS);
-}
-
-/**
- * VmbusChannelProcessRescindOffer - Rescind the offer by initiating a device removal
- */
-static void VmbusChannelProcessRescindOffer(void *context)
-{
- struct vmbus_channel *channel = context;
-
- DPRINT_ENTER(VMBUS);
- VmbusChildDeviceRemove(channel->DeviceObject);
- DPRINT_EXIT(VMBUS);
-}
-
-/**
- * VmbusChannelOnOffer - Handler for channel offers from vmbus in parent partition.
- *
- * We ignore all offers except network and storage offers. For each network and
- * storage offers, we create a channel object and queue a work item to the
- * channel object to process the offer synchronously
- */
-static void VmbusChannelOnOffer(struct vmbus_channel_message_header *hdr)
-{
- struct vmbus_channel_offer_channel *offer;
- struct vmbus_channel *newChannel;
- struct hv_guid *guidType;
- struct hv_guid *guidInstance;
- int i;
- int fSupported = 0;
-
- DPRINT_ENTER(VMBUS);
-
- offer = (struct vmbus_channel_offer_channel *)hdr;
- for (i = 0; i < MAX_NUM_DEVICE_CLASSES_SUPPORTED; i++) {
- if (memcmp(&offer->Offer.InterfaceType,
- &gSupportedDeviceClasses[i], sizeof(struct hv_guid)) == 0) {
- fSupported = 1;
- break;
- }
- }
-
- if (!fSupported) {
- DPRINT_DBG(VMBUS, "Ignoring channel offer notification for "
- "child relid %d", offer->ChildRelId);
- DPRINT_EXIT(VMBUS);
- return;
- }
-
- guidType = &offer->Offer.InterfaceType;
- guidInstance = &offer->Offer.InterfaceInstance;
-
- DPRINT_INFO(VMBUS, "Channel offer notification - "
- "child relid %d monitor id %d allocated %d, "
- "type {%02x%02x%02x%02x-%02x%02x-%02x%02x-"
- "%02x%02x%02x%02x%02x%02x%02x%02x} "
- "instance {%02x%02x%02x%02x-%02x%02x-%02x%02x-"
- "%02x%02x%02x%02x%02x%02x%02x%02x}",
- offer->ChildRelId, offer->MonitorId,
- offer->MonitorAllocated,
- guidType->data[3], guidType->data[2],
- guidType->data[1], guidType->data[0],
- guidType->data[5], guidType->data[4],
- guidType->data[7], guidType->data[6],
- guidType->data[8], guidType->data[9],
- guidType->data[10], guidType->data[11],
- guidType->data[12], guidType->data[13],
- guidType->data[14], guidType->data[15],
- guidInstance->data[3], guidInstance->data[2],
- guidInstance->data[1], guidInstance->data[0],
- guidInstance->data[5], guidInstance->data[4],
- guidInstance->data[7], guidInstance->data[6],
- guidInstance->data[8], guidInstance->data[9],
- guidInstance->data[10], guidInstance->data[11],
- guidInstance->data[12], guidInstance->data[13],
- guidInstance->data[14], guidInstance->data[15]);
-
- /* Allocate the channel object and save this offer. */
- newChannel = AllocVmbusChannel();
- if (!newChannel) {
- DPRINT_ERR(VMBUS, "unable to allocate channel object");
- return;
- }
-
- DPRINT_DBG(VMBUS, "channel object allocated - %p", newChannel);
-
- memcpy(&newChannel->OfferMsg, offer,
- sizeof(struct vmbus_channel_offer_channel));
- newChannel->MonitorGroup = (u8)offer->MonitorId / 32;
- newChannel->MonitorBit = (u8)offer->MonitorId % 32;
-
- /* TODO: Make sure the offer comes from our parent partition */
- osd_schedule_callback(newChannel->ControlWQ, VmbusChannelProcessOffer,
- newChannel);
-
- DPRINT_EXIT(VMBUS);
-}
-
-/**
- * VmbusChannelOnOfferRescind - Rescind offer handler.
- *
- * We queue a work item to process this offer synchronously
- */
-static void VmbusChannelOnOfferRescind(struct vmbus_channel_message_header *hdr)
-{
- struct vmbus_channel_rescind_offer *rescind;
- struct vmbus_channel *channel;
-
- DPRINT_ENTER(VMBUS);
-
- rescind = (struct vmbus_channel_rescind_offer *)hdr;
- channel = GetChannelFromRelId(rescind->ChildRelId);
- if (channel == NULL) {
- DPRINT_DBG(VMBUS, "channel not found for relId %d",
- rescind->ChildRelId);
- return;
- }
-
- osd_schedule_callback(channel->ControlWQ,
- VmbusChannelProcessRescindOffer,
- channel);
-
- DPRINT_EXIT(VMBUS);
-}
-
-/**
- * VmbusChannelOnOffersDelivered - This is invoked when all offers have been delivered.
- *
- * Nothing to do here.
- */
-static void VmbusChannelOnOffersDelivered(
- struct vmbus_channel_message_header *hdr)
-{
- DPRINT_ENTER(VMBUS);
- DPRINT_EXIT(VMBUS);
-}
-
-/**
- * VmbusChannelOnOpenResult - Open result handler.
- *
- * This is invoked when we received a response to our channel open request.
- * Find the matching request, copy the response and signal the requesting
- * thread.
- */
-static void VmbusChannelOnOpenResult(struct vmbus_channel_message_header *hdr)
-{
- struct vmbus_channel_open_result *result;
- struct list_head *curr;
- struct vmbus_channel_msginfo *msgInfo;
- struct vmbus_channel_message_header *requestHeader;
- struct vmbus_channel_open_channel *openMsg;
- unsigned long flags;
-
- DPRINT_ENTER(VMBUS);
-
- result = (struct vmbus_channel_open_result *)hdr;
- DPRINT_DBG(VMBUS, "vmbus open result - %d", result->Status);
-
- /*
- * Find the open msg, copy the result and signal/unblock the wait event
- */
- spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
-
- list_for_each(curr, &gVmbusConnection.ChannelMsgList) {
-/* FIXME: this should probably use list_entry() instead */
- msgInfo = (struct vmbus_channel_msginfo *)curr;
- requestHeader = (struct vmbus_channel_message_header *)msgInfo->Msg;
-
- if (requestHeader->MessageType == ChannelMessageOpenChannel) {
- openMsg = (struct vmbus_channel_open_channel *)msgInfo->Msg;
- if (openMsg->ChildRelId == result->ChildRelId &&
- openMsg->OpenId == result->OpenId) {
- memcpy(&msgInfo->Response.OpenResult,
- result,
- sizeof(struct vmbus_channel_open_result));
- osd_WaitEventSet(msgInfo->WaitEvent);
- break;
- }
- }
- }
- spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
-
- DPRINT_EXIT(VMBUS);
-}
-
-/**
- * VmbusChannelOnGpadlCreated - GPADL created handler.
- *
- * This is invoked when we received a response to our gpadl create request.
- * Find the matching request, copy the response and signal the requesting
- * thread.
- */
-static void VmbusChannelOnGpadlCreated(struct vmbus_channel_message_header *hdr)
-{
- struct vmbus_channel_gpadl_created *gpadlCreated;
- struct list_head *curr;
- struct vmbus_channel_msginfo *msgInfo;
- struct vmbus_channel_message_header *requestHeader;
- struct vmbus_channel_gpadl_header *gpadlHeader;
- unsigned long flags;
-
- DPRINT_ENTER(VMBUS);
-
- gpadlCreated = (struct vmbus_channel_gpadl_created *)hdr;
- DPRINT_DBG(VMBUS, "vmbus gpadl created result - %d",
- gpadlCreated->CreationStatus);
-
- /*
- * Find the establish msg, copy the result and signal/unblock the wait
- * event
- */
- spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
-
- list_for_each(curr, &gVmbusConnection.ChannelMsgList) {
-/* FIXME: this should probably use list_entry() instead */
- msgInfo = (struct vmbus_channel_msginfo *)curr;
- requestHeader = (struct vmbus_channel_message_header *)msgInfo->Msg;
-
- if (requestHeader->MessageType == ChannelMessageGpadlHeader) {
- gpadlHeader = (struct vmbus_channel_gpadl_header *)requestHeader;
-
- if ((gpadlCreated->ChildRelId ==
- gpadlHeader->ChildRelId) &&
- (gpadlCreated->Gpadl == gpadlHeader->Gpadl)) {
- memcpy(&msgInfo->Response.GpadlCreated,
- gpadlCreated,
- sizeof(struct vmbus_channel_gpadl_created));
- osd_WaitEventSet(msgInfo->WaitEvent);
- break;
- }
- }
- }
- spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
-
- DPRINT_EXIT(VMBUS);
-}
-
-/**
- * VmbusChannelOnGpadlTorndown - GPADL torndown handler.
- *
- * This is invoked when we received a response to our gpadl teardown request.
- * Find the matching request, copy the response and signal the requesting
- * thread.
- */
-static void VmbusChannelOnGpadlTorndown(
- struct vmbus_channel_message_header *hdr)
-{
- struct vmbus_channel_gpadl_torndown *gpadlTorndown;
- struct list_head *curr;
- struct vmbus_channel_msginfo *msgInfo;
- struct vmbus_channel_message_header *requestHeader;
- struct vmbus_channel_gpadl_teardown *gpadlTeardown;
- unsigned long flags;
-
- DPRINT_ENTER(VMBUS);
-
- gpadlTorndown = (struct vmbus_channel_gpadl_torndown *)hdr;
-
- /*
- * Find the open msg, copy the result and signal/unblock the wait event
- */
- spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
-
- list_for_each(curr, &gVmbusConnection.ChannelMsgList) {
-/* FIXME: this should probably use list_entry() instead */
- msgInfo = (struct vmbus_channel_msginfo *)curr;
- requestHeader = (struct vmbus_channel_message_header *)msgInfo->Msg;
-
- if (requestHeader->MessageType == ChannelMessageGpadlTeardown) {
- gpadlTeardown = (struct vmbus_channel_gpadl_teardown *)requestHeader;
-
- if (gpadlTorndown->Gpadl == gpadlTeardown->Gpadl) {
- memcpy(&msgInfo->Response.GpadlTorndown,
- gpadlTorndown,
- sizeof(struct vmbus_channel_gpadl_torndown));
- osd_WaitEventSet(msgInfo->WaitEvent);
- break;
- }
- }
- }
- spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
-
- DPRINT_EXIT(VMBUS);
-}
-
-/**
- * VmbusChannelOnVersionResponse - Version response handler
- *
- * This is invoked when we received a response to our initiate contact request.
- * Find the matching request, copy the response and signal the requesting
- * thread.
- */
-static void VmbusChannelOnVersionResponse(
- struct vmbus_channel_message_header *hdr)
-{
- struct list_head *curr;
- struct vmbus_channel_msginfo *msgInfo;
- struct vmbus_channel_message_header *requestHeader;
- struct vmbus_channel_initiate_contact *initiate;
- struct vmbus_channel_version_response *versionResponse;
- unsigned long flags;
-
- DPRINT_ENTER(VMBUS);
-
- versionResponse = (struct vmbus_channel_version_response *)hdr;
- spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
-
- list_for_each(curr, &gVmbusConnection.ChannelMsgList) {
-/* FIXME: this should probably use list_entry() instead */
- msgInfo = (struct vmbus_channel_msginfo *)curr;
- requestHeader = (struct vmbus_channel_message_header *)msgInfo->Msg;
-
- if (requestHeader->MessageType ==
- ChannelMessageInitiateContact) {
- initiate = (struct vmbus_channel_initiate_contact *)requestHeader;
- memcpy(&msgInfo->Response.VersionResponse,
- versionResponse,
- sizeof(struct vmbus_channel_version_response));
- osd_WaitEventSet(msgInfo->WaitEvent);
- }
- }
- spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
-
- DPRINT_EXIT(VMBUS);
-}
-
-/* Channel message dispatch table */
-static struct vmbus_channel_message_table_entry
- gChannelMessageTable[ChannelMessageCount] = {
- {ChannelMessageInvalid, NULL},
- {ChannelMessageOfferChannel, VmbusChannelOnOffer},
- {ChannelMessageRescindChannelOffer, VmbusChannelOnOfferRescind},
- {ChannelMessageRequestOffers, NULL},
- {ChannelMessageAllOffersDelivered, VmbusChannelOnOffersDelivered},
- {ChannelMessageOpenChannel, NULL},
- {ChannelMessageOpenChannelResult, VmbusChannelOnOpenResult},
- {ChannelMessageCloseChannel, NULL},
- {ChannelMessageGpadlHeader, NULL},
- {ChannelMessageGpadlBody, NULL},
- {ChannelMessageGpadlCreated, VmbusChannelOnGpadlCreated},
- {ChannelMessageGpadlTeardown, NULL},
- {ChannelMessageGpadlTorndown, VmbusChannelOnGpadlTorndown},
- {ChannelMessageRelIdReleased, NULL},
- {ChannelMessageInitiateContact, NULL},
- {ChannelMessageVersionResponse, VmbusChannelOnVersionResponse},
- {ChannelMessageUnload, NULL},
-};
-
-/**
- * VmbusOnChannelMessage - Handler for channel protocol messages.
- *
- * This is invoked in the vmbus worker thread context.
- */
-void VmbusOnChannelMessage(void *Context)
-{
- struct hv_message *msg = Context;
- struct vmbus_channel_message_header *hdr;
- int size;
-
- DPRINT_ENTER(VMBUS);
-
- hdr = (struct vmbus_channel_message_header *)msg->u.Payload;
- size = msg->Header.PayloadSize;
-
- DPRINT_DBG(VMBUS, "message type %d size %d", hdr->MessageType, size);
-
- if (hdr->MessageType >= ChannelMessageCount) {
- DPRINT_ERR(VMBUS,
- "Received invalid channel message type %d size %d",
- hdr->MessageType, size);
- print_hex_dump_bytes("", DUMP_PREFIX_NONE,
- (unsigned char *)msg->u.Payload, size);
- kfree(msg);
- return;
- }
-
- if (gChannelMessageTable[hdr->MessageType].messageHandler)
- gChannelMessageTable[hdr->MessageType].messageHandler(hdr);
- else
- DPRINT_ERR(VMBUS, "Unhandled channel message type %d",
- hdr->MessageType);
-
- /* Free the msg that was allocated in VmbusOnMsgDPC() */
- kfree(msg);
- DPRINT_EXIT(VMBUS);
-}
-
-/**
- * VmbusChannelRequestOffers - Send a request to get all our pending offers.
- */
-int VmbusChannelRequestOffers(void)
-{
- struct vmbus_channel_message_header *msg;
- struct vmbus_channel_msginfo *msgInfo;
- int ret;
-
- DPRINT_ENTER(VMBUS);
-
- msgInfo = kmalloc(sizeof(*msgInfo) +
- sizeof(struct vmbus_channel_message_header),
- GFP_KERNEL);
- ASSERT(msgInfo != NULL);
-
- msgInfo->WaitEvent = osd_WaitEventCreate();
- msg = (struct vmbus_channel_message_header *)msgInfo->Msg;
-
- msg->MessageType = ChannelMessageRequestOffers;
-
- /*SpinlockAcquire(gVmbusConnection.channelMsgLock);
- INSERT_TAIL_LIST(&gVmbusConnection.channelMsgList,
- &msgInfo->msgListEntry);
- SpinlockRelease(gVmbusConnection.channelMsgLock);*/
-
- ret = VmbusPostMessage(msg,
- sizeof(struct vmbus_channel_message_header));
- if (ret != 0) {
- DPRINT_ERR(VMBUS, "Unable to request offers - %d", ret);
-
- /*SpinlockAcquire(gVmbusConnection.channelMsgLock);
- REMOVE_ENTRY_LIST(&msgInfo->msgListEntry);
- SpinlockRelease(gVmbusConnection.channelMsgLock);*/
-
- goto Cleanup;
- }
- /* osd_WaitEventWait(msgInfo->waitEvent); */
-
- /*SpinlockAcquire(gVmbusConnection.channelMsgLock);
- REMOVE_ENTRY_LIST(&msgInfo->msgListEntry);
- SpinlockRelease(gVmbusConnection.channelMsgLock);*/
-
-
-Cleanup:
- if (msgInfo) {
- kfree(msgInfo->WaitEvent);
- kfree(msgInfo);
- }
-
- DPRINT_EXIT(VMBUS);
- return ret;
-}
-
-/**
- * VmbusChannelReleaseUnattachedChannels - Release channels that are unattached/unconnected ie (no drivers associated)
- */
-void VmbusChannelReleaseUnattachedChannels(void)
-{
- struct vmbus_channel *channel, *pos;
- struct vmbus_channel *start = NULL;
- unsigned long flags;
-
- spin_lock_irqsave(&gVmbusConnection.channel_lock, flags);
-
- list_for_each_entry_safe(channel, pos, &gVmbusConnection.ChannelList,
- ListEntry) {
- if (channel == start)
- break;
-
- if (!channel->DeviceObject->Driver) {
- list_del(&channel->ListEntry);
- DPRINT_INFO(VMBUS,
- "Releasing unattached device object %p",
- channel->DeviceObject);
-
- VmbusChildDeviceRemove(channel->DeviceObject);
- FreeVmbusChannel(channel);
- } else {
- if (!start)
- start = channel;
- }
- }
-
- spin_unlock_irqrestore(&gVmbusConnection.channel_lock, flags);
-}
-
-/* eof */
diff --git a/drivers/staging/hv/Kconfig b/drivers/staging/hv/Kconfig
index 4044702..7455c80 100644
--- a/drivers/staging/hv/Kconfig
+++ b/drivers/staging/hv/Kconfig
@@ -17,7 +17,7 @@ config HYPERV_STORAGE
config HYPERV_BLOCK
tristate "Microsoft Hyper-V virtual block driver"
- depends on BLOCK && SCSI
+ depends on BLOCK && SCSI && (LBDAF || 64BIT)
default HYPERV
help
Select this option to enable the Hyper-V virtual block driver.
@@ -29,4 +29,10 @@ config HYPERV_NET
help
Select this option to enable the Hyper-V virtual network driver.
+config HYPERV_UTILS
+ tristate "Microsoft Hyper-V Utilities driver"
+ default HYPERV
+ help
+ Select this option to enable the Hyper-V Utilities.
+
endif
diff --git a/drivers/staging/hv/Makefile b/drivers/staging/hv/Makefile
index 27ebae8..b46349b 100644
--- a/drivers/staging/hv/Makefile
+++ b/drivers/staging/hv/Makefile
@@ -1,11 +1,12 @@
-obj-$(CONFIG_HYPERV) += hv_vmbus.o
+obj-$(CONFIG_HYPERV) += hv_vmbus.o hv_timesource.o
obj-$(CONFIG_HYPERV_STORAGE) += hv_storvsc.o
obj-$(CONFIG_HYPERV_BLOCK) += hv_blkvsc.o
obj-$(CONFIG_HYPERV_NET) += hv_netvsc.o
+obj-$(CONFIG_HYPERV_UTILS) += hv_utils.o
-hv_vmbus-objs := vmbus_drv.o osd.o \
- Vmbus.o Hv.o Connection.o Channel.o \
- ChannelMgmt.o ChannelInterface.o RingBuffer.o
-hv_storvsc-objs := storvsc_drv.o StorVsc.o
-hv_blkvsc-objs := blkvsc_drv.o BlkVsc.o
-hv_netvsc-objs := netvsc_drv.o NetVsc.o RndisFilter.o
+hv_vmbus-y := vmbus_drv.o osd.o \
+ vmbus.o hv.o connection.o channel.o \
+ channel_mgmt.o ring_buffer.o
+hv_storvsc-y := storvsc_drv.o storvsc.o
+hv_blkvsc-y := blkvsc_drv.o blkvsc.o
+hv_netvsc-y := netvsc_drv.o netvsc.o rndis_filter.o
diff --git a/drivers/staging/hv/TODO b/drivers/staging/hv/TODO
index dbfbde9..582fd4a 100644
--- a/drivers/staging/hv/TODO
+++ b/drivers/staging/hv/TODO
@@ -1,15 +1,10 @@
TODO:
- fix remaining checkpatch warnings and errors
- - use of /** when it is not a kerneldoc header
- - remove RingBuffer.c to us in-kernel ringbuffer functions instead.
- audit the vmbus to verify it is working properly with the
driver model
- - convert vmbus driver interface function pointer tables
- to constant, a.k.a vmbus_ops
- see if the vmbus can be merged with the other virtual busses
in the kernel
- audit the network driver
- - use existing net_device_stats struct in network device
- checking for carrier inside open is wrong, network device API
confusion??
- audit the block driver
diff --git a/drivers/staging/hv/BlkVsc.c b/drivers/staging/hv/blkvsc.c
index a48ee3a..d5b0abd 100644
--- a/drivers/staging/hv/BlkVsc.c
+++ b/drivers/staging/hv/blkvsc.c
@@ -23,7 +23,7 @@
#include <linux/kernel.h>
#include <linux/mm.h>
#include "osd.h"
-#include "StorVsc.c"
+#include "storvsc.c"
static const char *gBlkDriverName = "blkvsc";
@@ -40,15 +40,11 @@ static int BlkVscOnDeviceAdd(struct hv_device *Device, void *AdditionalInfo)
struct storvsc_device_info *deviceInfo;
int ret = 0;
- DPRINT_ENTER(BLKVSC);
-
deviceInfo = (struct storvsc_device_info *)AdditionalInfo;
ret = StorVscOnDeviceAdd(Device, AdditionalInfo);
- if (ret != 0) {
- DPRINT_EXIT(BLKVSC);
+ if (ret != 0)
return ret;
- }
/*
* We need to use the device instance guid to set the path and target
@@ -63,8 +59,6 @@ static int BlkVscOnDeviceAdd(struct hv_device *Device, void *AdditionalInfo)
deviceInfo->TargetId = Device->deviceInstance.data[5] << 8 |
Device->deviceInstance.data[4];
- DPRINT_EXIT(BLKVSC);
-
return ret;
}
@@ -73,12 +67,10 @@ int BlkVscInitialize(struct hv_driver *Driver)
struct storvsc_driver_object *storDriver;
int ret = 0;
- DPRINT_ENTER(BLKVSC);
-
storDriver = (struct storvsc_driver_object *)Driver;
/* Make sure we are at least 2 pages since 1 page is used for control */
- ASSERT(storDriver->RingBufferSize >= (PAGE_SIZE << 1));
+ /* ASSERT(storDriver->RingBufferSize >= (PAGE_SIZE << 1)); */
Driver->name = gBlkDriverName;
memcpy(&Driver->deviceType, &gBlkVscDeviceType, sizeof(struct hv_guid));
@@ -89,7 +81,7 @@ int BlkVscInitialize(struct hv_driver *Driver)
* Divide the ring buffer data size (which is 1 page less than the ring
* buffer size since that page is reserved for the ring buffer indices)
* by the max request size (which is
- * VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER + struct vstor_packet + u64)
+ * vmbus_channel_packet_multipage_buffer + struct vstor_packet + u64)
*/
storDriver->MaxOutstandingRequestsPerChannel =
((storDriver->RingBufferSize - PAGE_SIZE) /
@@ -106,7 +98,5 @@ int BlkVscInitialize(struct hv_driver *Driver)
storDriver->Base.OnCleanup = StorVscOnCleanup;
storDriver->OnIORequest = StorVscOnIORequest;
- DPRINT_EXIT(BLKVSC);
-
return ret;
}
diff --git a/drivers/staging/hv/blkvsc_drv.c b/drivers/staging/hv/blkvsc_drv.c
index 62b2828..3f81ca5 100644
--- a/drivers/staging/hv/blkvsc_drv.c
+++ b/drivers/staging/hv/blkvsc_drv.c
@@ -25,14 +25,17 @@
#include <linux/major.h>
#include <linux/delay.h>
#include <linux/hdreg.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_eh.h>
#include <scsi/scsi_dbg.h>
#include "osd.h"
#include "logging.h"
+#include "version_info.h"
#include "vmbus.h"
-#include "StorVscApi.h"
+#include "storvsc_api.h"
#define BLKVSC_MINORS 64
@@ -92,7 +95,7 @@ struct blkvsc_request {
/* Per device structure */
struct block_device_context {
/* point back to our device context */
- struct device_context *device_ctx;
+ struct vm_device *device_ctx;
struct kmem_cache *request_pool;
spinlock_t lock;
struct gendisk *gd;
@@ -121,6 +124,7 @@ struct blkvsc_driver_context {
};
/* Static decl */
+static DEFINE_MUTEX(blkvsc_mutex);
static int blkvsc_probe(struct device *dev);
static int blkvsc_remove(struct device *device);
static void blkvsc_shutdown(struct device *device);
@@ -147,13 +151,14 @@ static int blkvsc_do_flush(struct block_device_context *blkdev);
static int blkvsc_cancel_pending_reqs(struct block_device_context *blkdev);
static int blkvsc_do_pending_reqs(struct block_device_context *blkdev);
-
static int blkvsc_ringbuffer_size = BLKVSC_RING_BUFFER_SIZE;
+module_param(blkvsc_ringbuffer_size, int, S_IRUGO);
+MODULE_PARM_DESC(ring_size, "Ring buffer size (in bytes)");
/* The one and only one */
static struct blkvsc_driver_context g_blkvsc_drv;
-static struct block_device_operations block_ops = {
+static const struct block_device_operations block_ops = {
.owner = THIS_MODULE,
.open = blkvsc_open,
.release = blkvsc_release,
@@ -163,7 +168,7 @@ static struct block_device_operations block_ops = {
.ioctl = blkvsc_ioctl,
};
-/**
+/*
* blkvsc_drv_init - BlkVsc driver initialization.
*/
static int blkvsc_drv_init(int (*drv_init)(struct hv_driver *drv))
@@ -172,10 +177,6 @@ static int blkvsc_drv_init(int (*drv_init)(struct hv_driver *drv))
struct driver_context *drv_ctx = &g_blkvsc_drv.drv_ctx;
int ret;
- DPRINT_ENTER(BLKVSC_DRV);
-
- vmbus_get_interface(&storvsc_drv_obj->Base.VmbusChannelInterface);
-
storvsc_drv_obj->RingBufferSize = blkvsc_ringbuffer_size;
/* Callback to client driver to complete the initialization */
@@ -192,8 +193,6 @@ static int blkvsc_drv_init(int (*drv_init)(struct hv_driver *drv))
/* The driver belongs to vmbus */
ret = vmbus_child_driver_register(drv_ctx);
- DPRINT_EXIT(BLKVSC_DRV);
-
return ret;
}
@@ -211,8 +210,6 @@ static void blkvsc_drv_exit(void)
struct device *current_dev;
int ret;
- DPRINT_ENTER(BLKVSC_DRV);
-
while (1) {
current_dev = NULL;
@@ -238,12 +235,10 @@ static void blkvsc_drv_exit(void)
vmbus_child_driver_unregister(drv_ctx);
- DPRINT_EXIT(BLKVSC_DRV);
-
return;
}
-/**
+/*
* blkvsc_probe - Add a new device for this driver
*/
static int blkvsc_probe(struct device *device)
@@ -254,7 +249,7 @@ static int blkvsc_probe(struct device *device)
(struct blkvsc_driver_context *)driver_ctx;
struct storvsc_driver_object *storvsc_drv_obj =
&blkvsc_drv_ctx->drv_obj;
- struct device_context *device_ctx = device_to_device_context(device);
+ struct vm_device *device_ctx = device_to_vm_device(device);
struct hv_device *device_obj = &device_ctx->device_obj;
struct block_device_context *blkdev = NULL;
@@ -265,8 +260,6 @@ static int blkvsc_probe(struct device *device)
static int ide0_registered;
static int ide1_registered;
- DPRINT_ENTER(BLKVSC_DRV);
-
DPRINT_DBG(BLKVSC_DRV, "blkvsc_probe - enter");
if (!storvsc_drv_obj->Base.OnDeviceAdd) {
@@ -286,8 +279,8 @@ static int blkvsc_probe(struct device *device)
/* Initialize what we can here */
spin_lock_init(&blkdev->lock);
- ASSERT(sizeof(struct blkvsc_request_group) <=
- sizeof(struct blkvsc_request));
+ /* ASSERT(sizeof(struct blkvsc_request_group) <= */
+ /* sizeof(struct blkvsc_request)); */
blkdev->request_pool = kmem_cache_create(dev_name(&device_ctx->device),
sizeof(struct blkvsc_request) +
@@ -363,10 +356,7 @@ static int blkvsc_probe(struct device *device)
blkdev->gd->queue = blk_init_queue(blkvsc_request, &blkdev->lock);
blk_queue_max_segment_size(blkdev->gd->queue, PAGE_SIZE);
- blk_queue_max_phys_segments(blkdev->gd->queue,
- MAX_MULTIPAGE_BUFFER_COUNT);
- blk_queue_max_hw_segments(blkdev->gd->queue,
- MAX_MULTIPAGE_BUFFER_COUNT);
+ blk_queue_max_segments(blkdev->gd->queue, MAX_MULTIPAGE_BUFFER_COUNT);
blk_queue_segment_boundary(blkdev->gd->queue, PAGE_SIZE-1);
blk_queue_bounce_limit(blkdev->gd->queue, BLK_BOUNCE_ANY);
blk_queue_dma_alignment(blkdev->gd->queue, 511);
@@ -413,8 +403,6 @@ Cleanup:
blkdev = NULL;
}
- DPRINT_EXIT(BLKVSC_DRV);
-
return ret;
}
@@ -556,7 +544,7 @@ static int blkvsc_do_inquiry(struct block_device_context *blkdev)
blkdev->device_type = UNKNOWN_DEV_TYPE;
}
- DPRINT_DBG(BLKVSC_DRV, "device type %d \n", device_type);
+ DPRINT_DBG(BLKVSC_DRV, "device type %d\n", device_type);
blkdev->device_id_len = buf[7];
if (blkdev->device_id_len > 64)
@@ -734,7 +722,7 @@ static int blkvsc_do_read_capacity16(struct block_device_context *blkdev)
return 0;
}
-/**
+/*
* blkvsc_remove() - Callback when our device is removed
*/
static int blkvsc_remove(struct device *device)
@@ -745,20 +733,16 @@ static int blkvsc_remove(struct device *device)
(struct blkvsc_driver_context *)driver_ctx;
struct storvsc_driver_object *storvsc_drv_obj =
&blkvsc_drv_ctx->drv_obj;
- struct device_context *device_ctx = device_to_device_context(device);
+ struct vm_device *device_ctx = device_to_vm_device(device);
struct hv_device *device_obj = &device_ctx->device_obj;
struct block_device_context *blkdev = dev_get_drvdata(device);
unsigned long flags;
int ret;
- DPRINT_ENTER(BLKVSC_DRV);
-
DPRINT_DBG(BLKVSC_DRV, "blkvsc_remove()\n");
- if (!storvsc_drv_obj->Base.OnDeviceRemove) {
- DPRINT_EXIT(BLKVSC_DRV);
+ if (!storvsc_drv_obj->Base.OnDeviceRemove)
return -1;
- }
/*
* Call to the vsc driver to let it know that the device is being
@@ -802,15 +786,13 @@ static int blkvsc_remove(struct device *device)
kfree(blkdev);
- DPRINT_EXIT(BLKVSC_DRV);
-
return ret;
}
static void blkvsc_init_rw(struct blkvsc_request *blkvsc_req)
{
- ASSERT(blkvsc_req->req);
- ASSERT(blkvsc_req->sector_count <= (MAX_MULTIPAGE_BUFFER_COUNT*8));
+ /* ASSERT(blkvsc_req->req); */
+ /* ASSERT(blkvsc_req->sector_count <= (MAX_MULTIPAGE_BUFFER_COUNT*8)); */
blkvsc_req->cmd_len = 16;
@@ -823,7 +805,8 @@ static void blkvsc_init_rw(struct blkvsc_request *blkvsc_req)
blkvsc_req->cmnd[0] = READ_16;
}
- blkvsc_req->cmnd[1] |= blk_fua_rq(blkvsc_req->req) ? 0x8 : 0;
+ blkvsc_req->cmnd[1] |=
+ (blkvsc_req->req->cmd_flags & REQ_FUA) ? 0x8 : 0;
*(unsigned long long *)&blkvsc_req->cmnd[2] =
cpu_to_be64(blkvsc_req->sector_start);
@@ -839,7 +822,8 @@ static void blkvsc_init_rw(struct blkvsc_request *blkvsc_req)
blkvsc_req->cmnd[0] = READ_10;
}
- blkvsc_req->cmnd[1] |= blk_fua_rq(blkvsc_req->req) ? 0x8 : 0;
+ blkvsc_req->cmnd[1] |=
+ (blkvsc_req->req->cmd_flags & REQ_FUA) ? 0x8 : 0;
*(unsigned int *)&blkvsc_req->cmnd[2] =
cpu_to_be32(blkvsc_req->sector_start);
@@ -865,7 +849,7 @@ static int blkvsc_submit_request(struct blkvsc_request *blkvsc_req,
void (*request_completion)(struct hv_storvsc_request *))
{
struct block_device_context *blkdev = blkvsc_req->dev;
- struct device_context *device_ctx = blkdev->device_ctx;
+ struct vm_device *device_ctx = blkdev->device_ctx;
struct driver_context *driver_ctx =
driver_to_driver_context(device_ctx->device.driver);
struct blkvsc_driver_context *blkvsc_drv_ctx =
@@ -941,7 +925,7 @@ static int blkvsc_do_request(struct block_device_context *blkdev,
int pending = 0;
struct blkvsc_request_group *group = NULL;
- DPRINT_DBG(BLKVSC_DRV, "blkdev %p req %p sect %lu \n", blkdev, req,
+ DPRINT_DBG(BLKVSC_DRV, "blkdev %p req %p sect %lu\n", blkdev, req,
(unsigned long)blk_rq_pos(req));
/* Create a group to tie req to list of blkvsc_reqs */
@@ -1117,7 +1101,7 @@ static void blkvsc_request_completion(struct hv_storvsc_request *request)
unsigned long flags;
struct blkvsc_request *comp_req, *tmp;
- ASSERT(blkvsc_req->group);
+ /* ASSERT(blkvsc_req->group); */
DPRINT_DBG(BLKVSC_DRV, "blkdev %p blkvsc_req %p group %p type %s "
"sect_start %lu sect_count %ld len %d group outstd %d "
@@ -1145,7 +1129,7 @@ static void blkvsc_request_completion(struct hv_storvsc_request *request)
&blkvsc_req->group->blkvsc_req_list,
req_entry) {
DPRINT_DBG(BLKVSC_DRV, "completing blkvsc_req %p "
- "sect_start %lu sect_count %ld \n",
+ "sect_start %lu sect_count %ld\n",
comp_req,
(unsigned long)comp_req->sector_start,
comp_req->sector_count);
@@ -1199,7 +1183,7 @@ static int blkvsc_cancel_pending_reqs(struct block_device_context *blkdev)
&pend_req->group->blkvsc_req_list,
req_entry) {
DPRINT_DBG(BLKVSC_DRV, "completing blkvsc_req %p "
- "sect_start %lu sect_count %ld \n",
+ "sect_start %lu sect_count %ld\n",
comp_req,
(unsigned long) comp_req->sector_start,
comp_req->sector_count);
@@ -1214,7 +1198,10 @@ static int blkvsc_cancel_pending_reqs(struct block_device_context *blkdev)
(!comp_req->request.Status ? 0 : -EIO),
comp_req->sector_count *
blkdev->sector_size);
- ASSERT(ret != 0);
+
+ /* FIXME: shouldn't this do more than return? */
+ if (ret)
+ goto out;
}
kmem_cache_free(blkdev->request_pool, comp_req);
@@ -1246,6 +1233,7 @@ static int blkvsc_cancel_pending_reqs(struct block_device_context *blkdev)
kmem_cache_free(blkdev->request_pool, pend_req);
}
+out:
return ret;
}
@@ -1277,12 +1265,12 @@ static void blkvsc_request(struct request_queue *queue)
struct request *req;
int ret = 0;
- DPRINT_DBG(BLKVSC_DRV, "- enter \n");
+ DPRINT_DBG(BLKVSC_DRV, "- enter\n");
while ((req = blk_peek_request(queue)) != NULL) {
DPRINT_DBG(BLKVSC_DRV, "- req %p\n", req);
blkdev = req->rq_disk->private_data;
- if (blkdev->shutting_down || !blk_fs_request(req) ||
+ if (blkdev->shutting_down || req->cmd_type != REQ_TYPE_FS ||
blkdev->media_not_present) {
__blk_end_request_cur(req, 0);
continue;
@@ -1320,6 +1308,7 @@ static int blkvsc_open(struct block_device *bdev, fmode_t mode)
DPRINT_DBG(BLKVSC_DRV, "- users %d disk %s\n", blkdev->users,
blkdev->gd->disk_name);
+ mutex_lock(&blkvsc_mutex);
spin_lock(&blkdev->lock);
if (!blkdev->users && blkdev->device_type == DVD_TYPE) {
@@ -1331,6 +1320,7 @@ static int blkvsc_open(struct block_device *bdev, fmode_t mode)
blkdev->users++;
spin_unlock(&blkdev->lock);
+ mutex_unlock(&blkvsc_mutex);
return 0;
}
@@ -1341,6 +1331,7 @@ static int blkvsc_release(struct gendisk *disk, fmode_t mode)
DPRINT_DBG(BLKVSC_DRV, "- users %d disk %s\n", blkdev->users,
blkdev->gd->disk_name);
+ mutex_lock(&blkvsc_mutex);
spin_lock(&blkdev->lock);
if (blkdev->users == 1) {
spin_unlock(&blkdev->lock);
@@ -1351,6 +1342,7 @@ static int blkvsc_release(struct gendisk *disk, fmode_t mode)
blkdev->users--;
spin_unlock(&blkdev->lock);
+ mutex_unlock(&blkvsc_mutex);
return 0;
}
@@ -1486,27 +1478,22 @@ static int __init blkvsc_init(void)
{
int ret;
- ASSERT(sizeof(sector_t) == 8); /* Make sure CONFIG_LBD is set */
-
- DPRINT_ENTER(BLKVSC_DRV);
+ BUILD_BUG_ON(sizeof(sector_t) != 8);
DPRINT_INFO(BLKVSC_DRV, "Blkvsc initializing....");
ret = blkvsc_drv_init(BlkVscInitialize);
- DPRINT_EXIT(BLKVSC_DRV);
-
return ret;
}
static void __exit blkvsc_exit(void)
{
- DPRINT_ENTER(BLKVSC_DRV);
blkvsc_drv_exit();
- DPRINT_ENTER(BLKVSC_DRV);
}
MODULE_LICENSE("GPL");
-module_param(blkvsc_ringbuffer_size, int, S_IRUGO);
+MODULE_VERSION(HV_DRV_VERSION);
+MODULE_DESCRIPTION("Microsoft Hyper-V virtual block driver");
module_init(blkvsc_init);
module_exit(blkvsc_exit);
diff --git a/drivers/staging/hv/channel.c b/drivers/staging/hv/channel.c
new file mode 100644
index 0000000..26ebc77
--- /dev/null
+++ b/drivers/staging/hv/channel.c
@@ -0,0 +1,1057 @@
+/*
+ * Copyright (c) 2009, Microsoft Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * Authors:
+ * Haiyang Zhang <haiyangz@microsoft.com>
+ * Hank Janssen <hjanssen@microsoft.com>
+ */
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include "osd.h"
+#include "logging.h"
+#include "vmbus_private.h"
+
+/* Internal routines */
+static int create_gpadl_header(
+ void *kbuffer, /* must be phys and virt contiguous */
+ u32 size, /* page-size multiple */
+ struct vmbus_channel_msginfo **msginfo,
+ u32 *messagecount);
+static void dump_vmbus_channel(struct vmbus_channel *channel);
+static void vmbus_setevent(struct vmbus_channel *channel);
+
+
+#if 0
+static void DumpMonitorPage(struct hv_monitor_page *MonitorPage)
+{
+ int i = 0;
+ int j = 0;
+
+ DPRINT_DBG(VMBUS, "monitorPage - %p, trigger state - %d",
+ MonitorPage, MonitorPage->TriggerState);
+
+ for (i = 0; i < 4; i++)
+ DPRINT_DBG(VMBUS, "trigger group (%d) - %llx", i,
+ MonitorPage->TriggerGroup[i].AsUINT64);
+
+ for (i = 0; i < 4; i++) {
+ for (j = 0; j < 32; j++) {
+ DPRINT_DBG(VMBUS, "latency (%d)(%d) - %llx", i, j,
+ MonitorPage->Latency[i][j]);
+ }
+ }
+ for (i = 0; i < 4; i++) {
+ for (j = 0; j < 32; j++) {
+ DPRINT_DBG(VMBUS, "param-conn id (%d)(%d) - %d", i, j,
+ MonitorPage->Parameter[i][j].ConnectionId.Asu32);
+ DPRINT_DBG(VMBUS, "param-flag (%d)(%d) - %d", i, j,
+ MonitorPage->Parameter[i][j].FlagNumber);
+ }
+ }
+}
+#endif
+
+/*
+ * vmbus_setevent- Trigger an event notification on the specified
+ * channel.
+ */
+static void vmbus_setevent(struct vmbus_channel *channel)
+{
+ struct hv_monitor_page *monitorpage;
+
+ if (channel->OfferMsg.MonitorAllocated) {
+ /* Each u32 represents 32 channels */
+ set_bit(channel->OfferMsg.ChildRelId & 31,
+ (unsigned long *) gVmbusConnection.SendInterruptPage +
+ (channel->OfferMsg.ChildRelId >> 5));
+
+ monitorpage = gVmbusConnection.MonitorPages;
+ monitorpage++; /* Get the child to parent monitor page */
+
+ set_bit(channel->MonitorBit,
+ (unsigned long *)&monitorpage->TriggerGroup
+ [channel->MonitorGroup].Pending);
+
+ } else {
+ VmbusSetEvent(channel->OfferMsg.ChildRelId);
+ }
+}
+
+#if 0
+static void VmbusChannelClearEvent(struct vmbus_channel *channel)
+{
+ struct hv_monitor_page *monitorPage;
+
+ if (Channel->OfferMsg.MonitorAllocated) {
+ /* Each u32 represents 32 channels */
+ clear_bit(Channel->OfferMsg.ChildRelId & 31,
+ (unsigned long *)gVmbusConnection.SendInterruptPage +
+ (Channel->OfferMsg.ChildRelId >> 5));
+
+ monitorPage =
+ (struct hv_monitor_page *)gVmbusConnection.MonitorPages;
+ monitorPage++; /* Get the child to parent monitor page */
+
+ clear_bit(Channel->MonitorBit,
+ (unsigned long *)&monitorPage->TriggerGroup
+ [Channel->MonitorGroup].Pending);
+ }
+}
+
+#endif
+/*
+ * vmbus_get_debug_info -Retrieve various channel debug info
+ */
+void vmbus_get_debug_info(struct vmbus_channel *channel,
+ struct vmbus_channel_debug_info *debuginfo)
+{
+ struct hv_monitor_page *monitorpage;
+ u8 monitor_group = (u8)channel->OfferMsg.MonitorId / 32;
+ u8 monitor_offset = (u8)channel->OfferMsg.MonitorId % 32;
+ /* u32 monitorBit = 1 << monitorOffset; */
+
+ debuginfo->RelId = channel->OfferMsg.ChildRelId;
+ debuginfo->State = channel->State;
+ memcpy(&debuginfo->InterfaceType,
+ &channel->OfferMsg.Offer.InterfaceType, sizeof(struct hv_guid));
+ memcpy(&debuginfo->InterfaceInstance,
+ &channel->OfferMsg.Offer.InterfaceInstance,
+ sizeof(struct hv_guid));
+
+ monitorpage = (struct hv_monitor_page *)gVmbusConnection.MonitorPages;
+
+ debuginfo->MonitorId = channel->OfferMsg.MonitorId;
+
+ debuginfo->ServerMonitorPending =
+ monitorpage->TriggerGroup[monitor_group].Pending;
+ debuginfo->ServerMonitorLatency =
+ monitorpage->Latency[monitor_group][monitor_offset];
+ debuginfo->ServerMonitorConnectionId =
+ monitorpage->Parameter[monitor_group]
+ [monitor_offset].ConnectionId.u.Id;
+
+ monitorpage++;
+
+ debuginfo->ClientMonitorPending =
+ monitorpage->TriggerGroup[monitor_group].Pending;
+ debuginfo->ClientMonitorLatency =
+ monitorpage->Latency[monitor_group][monitor_offset];
+ debuginfo->ClientMonitorConnectionId =
+ monitorpage->Parameter[monitor_group]
+ [monitor_offset].ConnectionId.u.Id;
+
+ RingBufferGetDebugInfo(&channel->Inbound, &debuginfo->Inbound);
+ RingBufferGetDebugInfo(&channel->Outbound, &debuginfo->Outbound);
+}
+
+/*
+ * vmbus_open - Open the specified channel.
+ */
+int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size,
+ u32 recv_ringbuffer_size, void *userdata, u32 userdatalen,
+ void (*onchannelcallback)(void *context), void *context)
+{
+ struct vmbus_channel_open_channel *openMsg;
+ struct vmbus_channel_msginfo *openInfo = NULL;
+ void *in, *out;
+ unsigned long flags;
+ int ret, err = 0;
+
+ /* Aligned to page size */
+ /* ASSERT(!(SendRingBufferSize & (PAGE_SIZE - 1))); */
+ /* ASSERT(!(RecvRingBufferSize & (PAGE_SIZE - 1))); */
+
+ newchannel->OnChannelCallback = onchannelcallback;
+ newchannel->ChannelCallbackContext = context;
+
+ /* Allocate the ring buffer */
+ out = osd_PageAlloc((send_ringbuffer_size + recv_ringbuffer_size)
+ >> PAGE_SHIFT);
+ if (!out)
+ return -ENOMEM;
+
+ /* ASSERT(((unsigned long)out & (PAGE_SIZE-1)) == 0); */
+
+ in = (void *)((unsigned long)out + send_ringbuffer_size);
+
+ newchannel->RingBufferPages = out;
+ newchannel->RingBufferPageCount = (send_ringbuffer_size +
+ recv_ringbuffer_size) >> PAGE_SHIFT;
+
+ ret = RingBufferInit(&newchannel->Outbound, out, send_ringbuffer_size);
+ if (ret != 0) {
+ err = ret;
+ goto errorout;
+ }
+
+ ret = RingBufferInit(&newchannel->Inbound, in, recv_ringbuffer_size);
+ if (ret != 0) {
+ err = ret;
+ goto errorout;
+ }
+
+
+ /* Establish the gpadl for the ring buffer */
+ DPRINT_DBG(VMBUS, "Establishing ring buffer's gpadl for channel %p...",
+ newchannel);
+
+ newchannel->RingBufferGpadlHandle = 0;
+
+ ret = vmbus_establish_gpadl(newchannel,
+ newchannel->Outbound.RingBuffer,
+ send_ringbuffer_size +
+ recv_ringbuffer_size,
+ &newchannel->RingBufferGpadlHandle);
+
+ if (ret != 0) {
+ err = ret;
+ goto errorout;
+ }
+
+ DPRINT_DBG(VMBUS, "channel %p <relid %d gpadl 0x%x send ring %p "
+ "size %d recv ring %p size %d, downstreamoffset %d>",
+ newchannel, newchannel->OfferMsg.ChildRelId,
+ newchannel->RingBufferGpadlHandle,
+ newchannel->Outbound.RingBuffer,
+ newchannel->Outbound.RingSize,
+ newchannel->Inbound.RingBuffer,
+ newchannel->Inbound.RingSize,
+ send_ringbuffer_size);
+
+ /* Create and init the channel open message */
+ openInfo = kmalloc(sizeof(*openInfo) +
+ sizeof(struct vmbus_channel_open_channel),
+ GFP_KERNEL);
+ if (!openInfo) {
+ err = -ENOMEM;
+ goto errorout;
+ }
+
+ openInfo->WaitEvent = osd_WaitEventCreate();
+ if (!openInfo->WaitEvent) {
+ err = -ENOMEM;
+ goto errorout;
+ }
+
+ openMsg = (struct vmbus_channel_open_channel *)openInfo->Msg;
+ openMsg->Header.MessageType = ChannelMessageOpenChannel;
+ openMsg->OpenId = newchannel->OfferMsg.ChildRelId; /* FIXME */
+ openMsg->ChildRelId = newchannel->OfferMsg.ChildRelId;
+ openMsg->RingBufferGpadlHandle = newchannel->RingBufferGpadlHandle;
+ openMsg->DownstreamRingBufferPageOffset = send_ringbuffer_size >>
+ PAGE_SHIFT;
+ openMsg->ServerContextAreaGpadlHandle = 0; /* TODO */
+
+ if (userdatalen > MAX_USER_DEFINED_BYTES) {
+ err = -EINVAL;
+ goto errorout;
+ }
+
+ if (userdatalen)
+ memcpy(openMsg->UserData, userdata, userdatalen);
+
+ spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
+ list_add_tail(&openInfo->MsgListEntry,
+ &gVmbusConnection.ChannelMsgList);
+ spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
+
+ DPRINT_DBG(VMBUS, "Sending channel open msg...");
+
+ ret = VmbusPostMessage(openMsg,
+ sizeof(struct vmbus_channel_open_channel));
+ if (ret != 0) {
+ DPRINT_ERR(VMBUS, "unable to open channel - %d", ret);
+ goto Cleanup;
+ }
+
+ /* FIXME: Need to time-out here */
+ osd_WaitEventWait(openInfo->WaitEvent);
+
+ if (openInfo->Response.OpenResult.Status == 0)
+ DPRINT_INFO(VMBUS, "channel <%p> open success!!", newchannel);
+ else
+ DPRINT_INFO(VMBUS, "channel <%p> open failed - %d!!",
+ newchannel, openInfo->Response.OpenResult.Status);
+
+Cleanup:
+ spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
+ list_del(&openInfo->MsgListEntry);
+ spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
+
+ kfree(openInfo->WaitEvent);
+ kfree(openInfo);
+ return 0;
+
+errorout:
+ RingBufferCleanup(&newchannel->Outbound);
+ RingBufferCleanup(&newchannel->Inbound);
+ osd_PageFree(out, (send_ringbuffer_size + recv_ringbuffer_size)
+ >> PAGE_SHIFT);
+ kfree(openInfo);
+ return err;
+}
+EXPORT_SYMBOL_GPL(vmbus_open);
+
+/*
+ * dump_gpadl_body - Dump the gpadl body message to the console for
+ * debugging purposes.
+ */
+static void dump_gpadl_body(struct vmbus_channel_gpadl_body *gpadl, u32 len)
+{
+ int i;
+ int pfncount;
+
+ pfncount = (len - sizeof(struct vmbus_channel_gpadl_body)) /
+ sizeof(u64);
+ DPRINT_DBG(VMBUS, "gpadl body - len %d pfn count %d", len, pfncount);
+
+ for (i = 0; i < pfncount; i++)
+ DPRINT_DBG(VMBUS, "gpadl body - %d) pfn %llu",
+ i, gpadl->Pfn[i]);
+}
+
+/*
+ * dump_gpadl_header - Dump the gpadl header message to the console for
+ * debugging purposes.
+ */
+static void dump_gpadl_header(struct vmbus_channel_gpadl_header *gpadl)
+{
+ int i, j;
+ int pagecount;
+
+ DPRINT_DBG(VMBUS,
+ "gpadl header - relid %d, range count %d, range buflen %d",
+ gpadl->ChildRelId, gpadl->RangeCount, gpadl->RangeBufLen);
+ for (i = 0; i < gpadl->RangeCount; i++) {
+ pagecount = gpadl->Range[i].ByteCount >> PAGE_SHIFT;
+ pagecount = (pagecount > 26) ? 26 : pagecount;
+
+ DPRINT_DBG(VMBUS, "gpadl range %d - len %d offset %d "
+ "page count %d", i, gpadl->Range[i].ByteCount,
+ gpadl->Range[i].ByteOffset, pagecount);
+
+ for (j = 0; j < pagecount; j++)
+ DPRINT_DBG(VMBUS, "%d) pfn %llu", j,
+ gpadl->Range[i].PfnArray[j]);
+ }
+}
+
+/*
+ * create_gpadl_header - Creates a gpadl for the specified buffer
+ */
+static int create_gpadl_header(void *kbuffer, u32 size,
+ struct vmbus_channel_msginfo **msginfo,
+ u32 *messagecount)
+{
+ int i;
+ int pagecount;
+ unsigned long long pfn;
+ struct vmbus_channel_gpadl_header *gpadl_header;
+ struct vmbus_channel_gpadl_body *gpadl_body;
+ struct vmbus_channel_msginfo *msgheader;
+ struct vmbus_channel_msginfo *msgbody = NULL;
+ u32 msgsize;
+
+ int pfnsum, pfncount, pfnleft, pfncurr, pfnsize;
+
+ /* ASSERT((kbuffer & (PAGE_SIZE-1)) == 0); */
+ /* ASSERT((Size & (PAGE_SIZE-1)) == 0); */
+
+ pagecount = size >> PAGE_SHIFT;
+ pfn = virt_to_phys(kbuffer) >> PAGE_SHIFT;
+
+ /* do we need a gpadl body msg */
+ pfnsize = MAX_SIZE_CHANNEL_MESSAGE -
+ sizeof(struct vmbus_channel_gpadl_header) -
+ sizeof(struct gpa_range);
+ pfncount = pfnsize / sizeof(u64);
+
+ if (pagecount > pfncount) {
+ /* we need a gpadl body */
+ /* fill in the header */
+ msgsize = sizeof(struct vmbus_channel_msginfo) +
+ sizeof(struct vmbus_channel_gpadl_header) +
+ sizeof(struct gpa_range) + pfncount * sizeof(u64);
+ msgheader = kzalloc(msgsize, GFP_KERNEL);
+ if (!msgheader)
+ goto nomem;
+
+ INIT_LIST_HEAD(&msgheader->SubMsgList);
+ msgheader->MessageSize = msgsize;
+
+ gpadl_header = (struct vmbus_channel_gpadl_header *)
+ msgheader->Msg;
+ gpadl_header->RangeCount = 1;
+ gpadl_header->RangeBufLen = sizeof(struct gpa_range) +
+ pagecount * sizeof(u64);
+ gpadl_header->Range[0].ByteOffset = 0;
+ gpadl_header->Range[0].ByteCount = size;
+ for (i = 0; i < pfncount; i++)
+ gpadl_header->Range[0].PfnArray[i] = pfn+i;
+ *msginfo = msgheader;
+ *messagecount = 1;
+
+ pfnsum = pfncount;
+ pfnleft = pagecount - pfncount;
+
+ /* how many pfns can we fit */
+ pfnsize = MAX_SIZE_CHANNEL_MESSAGE -
+ sizeof(struct vmbus_channel_gpadl_body);
+ pfncount = pfnsize / sizeof(u64);
+
+ /* fill in the body */
+ while (pfnleft) {
+ if (pfnleft > pfncount)
+ pfncurr = pfncount;
+ else
+ pfncurr = pfnleft;
+
+ msgsize = sizeof(struct vmbus_channel_msginfo) +
+ sizeof(struct vmbus_channel_gpadl_body) +
+ pfncurr * sizeof(u64);
+ msgbody = kzalloc(msgsize, GFP_KERNEL);
+ /* FIXME: we probably need to more if this fails */
+ if (!msgbody)
+ goto nomem;
+ msgbody->MessageSize = msgsize;
+ (*messagecount)++;
+ gpadl_body =
+ (struct vmbus_channel_gpadl_body *)msgbody->Msg;
+
+ /*
+ * FIXME:
+ * Gpadl is u32 and we are using a pointer which could
+ * be 64-bit
+ */
+ /* gpadl_body->Gpadl = kbuffer; */
+ for (i = 0; i < pfncurr; i++)
+ gpadl_body->Pfn[i] = pfn + pfnsum + i;
+
+ /* add to msg header */
+ list_add_tail(&msgbody->MsgListEntry,
+ &msgheader->SubMsgList);
+ pfnsum += pfncurr;
+ pfnleft -= pfncurr;
+ }
+ } else {
+ /* everything fits in a header */
+ msgsize = sizeof(struct vmbus_channel_msginfo) +
+ sizeof(struct vmbus_channel_gpadl_header) +
+ sizeof(struct gpa_range) + pagecount * sizeof(u64);
+ msgheader = kzalloc(msgsize, GFP_KERNEL);
+ if (msgheader == NULL)
+ goto nomem;
+ msgheader->MessageSize = msgsize;
+
+ gpadl_header = (struct vmbus_channel_gpadl_header *)
+ msgheader->Msg;
+ gpadl_header->RangeCount = 1;
+ gpadl_header->RangeBufLen = sizeof(struct gpa_range) +
+ pagecount * sizeof(u64);
+ gpadl_header->Range[0].ByteOffset = 0;
+ gpadl_header->Range[0].ByteCount = size;
+ for (i = 0; i < pagecount; i++)
+ gpadl_header->Range[0].PfnArray[i] = pfn+i;
+
+ *msginfo = msgheader;
+ *messagecount = 1;
+ }
+
+ return 0;
+nomem:
+ kfree(msgheader);
+ kfree(msgbody);
+ return -ENOMEM;
+}
+
+/*
+ * vmbus_establish_gpadl - Estabish a GPADL for the specified buffer
+ *
+ * @channel: a channel
+ * @kbuffer: from kmalloc
+ * @size: page-size multiple
+ * @gpadl_handle: some funky thing
+ */
+int vmbus_establish_gpadl(struct vmbus_channel *channel, void *kbuffer,
+ u32 size, u32 *gpadl_handle)
+{
+ struct vmbus_channel_gpadl_header *gpadlmsg;
+ struct vmbus_channel_gpadl_body *gpadl_body;
+ /* struct vmbus_channel_gpadl_created *gpadlCreated; */
+ struct vmbus_channel_msginfo *msginfo = NULL;
+ struct vmbus_channel_msginfo *submsginfo;
+ u32 msgcount;
+ struct list_head *curr;
+ u32 next_gpadl_handle;
+ unsigned long flags;
+ int ret = 0;
+
+ next_gpadl_handle = atomic_read(&gVmbusConnection.NextGpadlHandle);
+ atomic_inc(&gVmbusConnection.NextGpadlHandle);
+
+ ret = create_gpadl_header(kbuffer, size, &msginfo, &msgcount);
+ if (ret)
+ return ret;
+
+ msginfo->WaitEvent = osd_WaitEventCreate();
+ if (!msginfo->WaitEvent) {
+ ret = -ENOMEM;
+ goto Cleanup;
+ }
+
+ gpadlmsg = (struct vmbus_channel_gpadl_header *)msginfo->Msg;
+ gpadlmsg->Header.MessageType = ChannelMessageGpadlHeader;
+ gpadlmsg->ChildRelId = channel->OfferMsg.ChildRelId;
+ gpadlmsg->Gpadl = next_gpadl_handle;
+
+ dump_gpadl_header(gpadlmsg);
+
+ spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
+ list_add_tail(&msginfo->MsgListEntry,
+ &gVmbusConnection.ChannelMsgList);
+
+ spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
+ DPRINT_DBG(VMBUS, "buffer %p, size %d msg cnt %d",
+ kbuffer, size, msgcount);
+
+ DPRINT_DBG(VMBUS, "Sending GPADL Header - len %zd",
+ msginfo->MessageSize - sizeof(*msginfo));
+
+ ret = VmbusPostMessage(gpadlmsg, msginfo->MessageSize -
+ sizeof(*msginfo));
+ if (ret != 0) {
+ DPRINT_ERR(VMBUS, "Unable to open channel - %d", ret);
+ goto Cleanup;
+ }
+
+ if (msgcount > 1) {
+ list_for_each(curr, &msginfo->SubMsgList) {
+
+ /* FIXME: should this use list_entry() instead ? */
+ submsginfo = (struct vmbus_channel_msginfo *)curr;
+ gpadl_body =
+ (struct vmbus_channel_gpadl_body *)submsginfo->Msg;
+
+ gpadl_body->Header.MessageType =
+ ChannelMessageGpadlBody;
+ gpadl_body->Gpadl = next_gpadl_handle;
+
+ DPRINT_DBG(VMBUS, "Sending GPADL Body - len %zd",
+ submsginfo->MessageSize -
+ sizeof(*submsginfo));
+
+ dump_gpadl_body(gpadl_body, submsginfo->MessageSize -
+ sizeof(*submsginfo));
+ ret = VmbusPostMessage(gpadl_body,
+ submsginfo->MessageSize -
+ sizeof(*submsginfo));
+ if (ret != 0)
+ goto Cleanup;
+
+ }
+ }
+ osd_WaitEventWait(msginfo->WaitEvent);
+
+ /* At this point, we received the gpadl created msg */
+ DPRINT_DBG(VMBUS, "Received GPADL created "
+ "(relid %d, status %d handle %x)",
+ channel->OfferMsg.ChildRelId,
+ msginfo->Response.GpadlCreated.CreationStatus,
+ gpadlmsg->Gpadl);
+
+ *gpadl_handle = gpadlmsg->Gpadl;
+
+Cleanup:
+ spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
+ list_del(&msginfo->MsgListEntry);
+ spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
+
+ kfree(msginfo->WaitEvent);
+ kfree(msginfo);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(vmbus_establish_gpadl);
+
+/*
+ * vmbus_teardown_gpadl -Teardown the specified GPADL handle
+ */
+int vmbus_teardown_gpadl(struct vmbus_channel *channel, u32 gpadl_handle)
+{
+ struct vmbus_channel_gpadl_teardown *msg;
+ struct vmbus_channel_msginfo *info;
+ unsigned long flags;
+ int ret;
+
+ /* ASSERT(gpadl_handle != 0); */
+
+ info = kmalloc(sizeof(*info) +
+ sizeof(struct vmbus_channel_gpadl_teardown), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ info->WaitEvent = osd_WaitEventCreate();
+ if (!info->WaitEvent) {
+ kfree(info);
+ return -ENOMEM;
+ }
+
+ msg = (struct vmbus_channel_gpadl_teardown *)info->Msg;
+
+ msg->Header.MessageType = ChannelMessageGpadlTeardown;
+ msg->ChildRelId = channel->OfferMsg.ChildRelId;
+ msg->Gpadl = gpadl_handle;
+
+ spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
+ list_add_tail(&info->MsgListEntry,
+ &gVmbusConnection.ChannelMsgList);
+ spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
+
+ ret = VmbusPostMessage(msg,
+ sizeof(struct vmbus_channel_gpadl_teardown));
+ if (ret != 0) {
+ /* TODO: */
+ /* something... */
+ }
+
+ osd_WaitEventWait(info->WaitEvent);
+
+ /* Received a torndown response */
+ spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
+ list_del(&info->MsgListEntry);
+ spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
+
+ kfree(info->WaitEvent);
+ kfree(info);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(vmbus_teardown_gpadl);
+
+/*
+ * vmbus_close - Close the specified channel
+ */
+void vmbus_close(struct vmbus_channel *channel)
+{
+ struct vmbus_channel_close_channel *msg;
+ struct vmbus_channel_msginfo *info;
+ unsigned long flags;
+ int ret;
+
+ /* Stop callback and cancel the timer asap */
+ channel->OnChannelCallback = NULL;
+ del_timer_sync(&channel->poll_timer);
+
+ /* Send a closing message */
+ info = kmalloc(sizeof(*info) +
+ sizeof(struct vmbus_channel_close_channel), GFP_KERNEL);
+ /* FIXME: can't do anything other than return here because the
+ * function is void */
+ if (!info)
+ return;
+
+ /* info->waitEvent = osd_WaitEventCreate(); */
+
+ msg = (struct vmbus_channel_close_channel *)info->Msg;
+ msg->Header.MessageType = ChannelMessageCloseChannel;
+ msg->ChildRelId = channel->OfferMsg.ChildRelId;
+
+ ret = VmbusPostMessage(msg, sizeof(struct vmbus_channel_close_channel));
+ if (ret != 0) {
+ /* TODO: */
+ /* something... */
+ }
+
+ /* Tear down the gpadl for the channel's ring buffer */
+ if (channel->RingBufferGpadlHandle)
+ vmbus_teardown_gpadl(channel,
+ channel->RingBufferGpadlHandle);
+
+ /* TODO: Send a msg to release the childRelId */
+
+ /* Cleanup the ring buffers for this channel */
+ RingBufferCleanup(&channel->Outbound);
+ RingBufferCleanup(&channel->Inbound);
+
+ osd_PageFree(channel->RingBufferPages, channel->RingBufferPageCount);
+
+ kfree(info);
+
+ /*
+ * If we are closing the channel during an error path in
+ * opening the channel, don't free the channel since the
+ * caller will free the channel
+ */
+
+ if (channel->State == CHANNEL_OPEN_STATE) {
+ spin_lock_irqsave(&gVmbusConnection.channel_lock, flags);
+ list_del(&channel->ListEntry);
+ spin_unlock_irqrestore(&gVmbusConnection.channel_lock, flags);
+
+ free_channel(channel);
+ }
+}
+EXPORT_SYMBOL_GPL(vmbus_close);
+
+/**
+ * vmbus_sendpacket() - Send the specified buffer on the given channel
+ * @channel: Pointer to vmbus_channel structure.
+ * @buffer: Pointer to the buffer you want to receive the data into.
+ * @bufferlen: Maximum size of what the the buffer will hold
+ * @requestid: Identifier of the request
+ * @type: Type of packet that is being send e.g. negotiate, time
+ * packet etc.
+ *
+ * Sends data in @buffer directly to hyper-v via the vmbus
+ * This will send the data unparsed to hyper-v.
+ *
+ * Mainly used by Hyper-V drivers.
+ */
+int vmbus_sendpacket(struct vmbus_channel *channel, const void *buffer,
+ u32 bufferlen, u64 requestid,
+ enum vmbus_packet_type type, u32 flags)
+{
+ struct vmpacket_descriptor desc;
+ u32 packetlen = sizeof(struct vmpacket_descriptor) + bufferlen;
+ u32 packetlen_aligned = ALIGN_UP(packetlen, sizeof(u64));
+ struct scatterlist bufferlist[3];
+ u64 aligned_data = 0;
+ int ret;
+
+ DPRINT_DBG(VMBUS, "channel %p buffer %p len %d",
+ channel, buffer, bufferlen);
+
+ dump_vmbus_channel(channel);
+
+ /* ASSERT((packetLenAligned - packetLen) < sizeof(u64)); */
+
+ /* Setup the descriptor */
+ desc.Type = type; /* VmbusPacketTypeDataInBand; */
+ desc.Flags = flags; /* VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED; */
+ /* in 8-bytes granularity */
+ desc.DataOffset8 = sizeof(struct vmpacket_descriptor) >> 3;
+ desc.Length8 = (u16)(packetlen_aligned >> 3);
+ desc.TransactionId = requestid;
+
+ sg_init_table(bufferlist, 3);
+ sg_set_buf(&bufferlist[0], &desc, sizeof(struct vmpacket_descriptor));
+ sg_set_buf(&bufferlist[1], buffer, bufferlen);
+ sg_set_buf(&bufferlist[2], &aligned_data,
+ packetlen_aligned - packetlen);
+
+ ret = RingBufferWrite(&channel->Outbound, bufferlist, 3);
+
+ /* TODO: We should determine if this is optional */
+ if (ret == 0 && !GetRingBufferInterruptMask(&channel->Outbound))
+ vmbus_setevent(channel);
+
+ return ret;
+}
+EXPORT_SYMBOL(vmbus_sendpacket);
+
+/*
+ * vmbus_sendpacket_pagebuffer - Send a range of single-page buffer
+ * packets using a GPADL Direct packet type.
+ */
+int vmbus_sendpacket_pagebuffer(struct vmbus_channel *channel,
+ struct hv_page_buffer pagebuffers[],
+ u32 pagecount, void *buffer, u32 bufferlen,
+ u64 requestid)
+{
+ int ret;
+ int i;
+ struct vmbus_channel_packet_page_buffer desc;
+ u32 descsize;
+ u32 packetlen;
+ u32 packetlen_aligned;
+ struct scatterlist bufferlist[3];
+ u64 aligned_data = 0;
+
+ if (pagecount > MAX_PAGE_BUFFER_COUNT)
+ return -EINVAL;
+
+ dump_vmbus_channel(channel);
+
+ /*
+ * Adjust the size down since vmbus_channel_packet_page_buffer is the
+ * largest size we support
+ */
+ descsize = sizeof(struct vmbus_channel_packet_page_buffer) -
+ ((MAX_PAGE_BUFFER_COUNT - pagecount) *
+ sizeof(struct hv_page_buffer));
+ packetlen = descsize + bufferlen;
+ packetlen_aligned = ALIGN_UP(packetlen, sizeof(u64));
+
+ /* ASSERT((packetLenAligned - packetLen) < sizeof(u64)); */
+
+ /* Setup the descriptor */
+ desc.type = VmbusPacketTypeDataUsingGpaDirect;
+ desc.flags = VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED;
+ desc.dataoffset8 = descsize >> 3; /* in 8-bytes grandularity */
+ desc.length8 = (u16)(packetlen_aligned >> 3);
+ desc.transactionid = requestid;
+ desc.rangecount = pagecount;
+
+ for (i = 0; i < pagecount; i++) {
+ desc.range[i].Length = pagebuffers[i].Length;
+ desc.range[i].Offset = pagebuffers[i].Offset;
+ desc.range[i].Pfn = pagebuffers[i].Pfn;
+ }
+
+ sg_init_table(bufferlist, 3);
+ sg_set_buf(&bufferlist[0], &desc, descsize);
+ sg_set_buf(&bufferlist[1], buffer, bufferlen);
+ sg_set_buf(&bufferlist[2], &aligned_data,
+ packetlen_aligned - packetlen);
+
+ ret = RingBufferWrite(&channel->Outbound, bufferlist, 3);
+
+ /* TODO: We should determine if this is optional */
+ if (ret == 0 && !GetRingBufferInterruptMask(&channel->Outbound))
+ vmbus_setevent(channel);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(vmbus_sendpacket_pagebuffer);
+
+/*
+ * vmbus_sendpacket_multipagebuffer - Send a multi-page buffer packet
+ * using a GPADL Direct packet type.
+ */
+int vmbus_sendpacket_multipagebuffer(struct vmbus_channel *channel,
+ struct hv_multipage_buffer *multi_pagebuffer,
+ void *buffer, u32 bufferlen, u64 requestid)
+{
+ int ret;
+ struct vmbus_channel_packet_multipage_buffer desc;
+ u32 descsize;
+ u32 packetlen;
+ u32 packetlen_aligned;
+ struct scatterlist bufferlist[3];
+ u64 aligned_data = 0;
+ u32 pfncount = NUM_PAGES_SPANNED(multi_pagebuffer->Offset,
+ multi_pagebuffer->Length);
+
+ dump_vmbus_channel(channel);
+
+ DPRINT_DBG(VMBUS, "data buffer - offset %u len %u pfn count %u",
+ multi_pagebuffer->Offset,
+ multi_pagebuffer->Length, pfncount);
+
+ if ((pfncount < 0) || (pfncount > MAX_MULTIPAGE_BUFFER_COUNT))
+ return -EINVAL;
+
+ /*
+ * Adjust the size down since vmbus_channel_packet_multipage_buffer is
+ * the largest size we support
+ */
+ descsize = sizeof(struct vmbus_channel_packet_multipage_buffer) -
+ ((MAX_MULTIPAGE_BUFFER_COUNT - pfncount) *
+ sizeof(u64));
+ packetlen = descsize + bufferlen;
+ packetlen_aligned = ALIGN_UP(packetlen, sizeof(u64));
+
+ /* ASSERT((packetLenAligned - packetLen) < sizeof(u64)); */
+
+ /* Setup the descriptor */
+ desc.type = VmbusPacketTypeDataUsingGpaDirect;
+ desc.flags = VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED;
+ desc.dataoffset8 = descsize >> 3; /* in 8-bytes grandularity */
+ desc.length8 = (u16)(packetlen_aligned >> 3);
+ desc.transactionid = requestid;
+ desc.rangecount = 1;
+
+ desc.range.Length = multi_pagebuffer->Length;
+ desc.range.Offset = multi_pagebuffer->Offset;
+
+ memcpy(desc.range.PfnArray, multi_pagebuffer->PfnArray,
+ pfncount * sizeof(u64));
+
+ sg_init_table(bufferlist, 3);
+ sg_set_buf(&bufferlist[0], &desc, descsize);
+ sg_set_buf(&bufferlist[1], buffer, bufferlen);
+ sg_set_buf(&bufferlist[2], &aligned_data,
+ packetlen_aligned - packetlen);
+
+ ret = RingBufferWrite(&channel->Outbound, bufferlist, 3);
+
+ /* TODO: We should determine if this is optional */
+ if (ret == 0 && !GetRingBufferInterruptMask(&channel->Outbound))
+ vmbus_setevent(channel);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(vmbus_sendpacket_multipagebuffer);
+
+/**
+ * vmbus_recvpacket() - Retrieve the user packet on the specified channel
+ * @channel: Pointer to vmbus_channel structure.
+ * @buffer: Pointer to the buffer you want to receive the data into.
+ * @bufferlen: Maximum size of what the the buffer will hold
+ * @buffer_actual_len: The actual size of the data after it was received
+ * @requestid: Identifier of the request
+ *
+ * Receives directly from the hyper-v vmbus and puts the data it received
+ * into Buffer. This will receive the data unparsed from hyper-v.
+ *
+ * Mainly used by Hyper-V drivers.
+ */
+int vmbus_recvpacket(struct vmbus_channel *channel, void *buffer,
+ u32 bufferlen, u32 *buffer_actual_len, u64 *requestid)
+{
+ struct vmpacket_descriptor desc;
+ u32 packetlen;
+ u32 userlen;
+ int ret;
+ unsigned long flags;
+
+ *buffer_actual_len = 0;
+ *requestid = 0;
+
+ spin_lock_irqsave(&channel->inbound_lock, flags);
+
+ ret = RingBufferPeek(&channel->Inbound, &desc,
+ sizeof(struct vmpacket_descriptor));
+ if (ret != 0) {
+ spin_unlock_irqrestore(&channel->inbound_lock, flags);
+
+ /* DPRINT_DBG(VMBUS, "nothing to read!!"); */
+ return 0;
+ }
+
+ /* VmbusChannelClearEvent(Channel); */
+
+ packetlen = desc.Length8 << 3;
+ userlen = packetlen - (desc.DataOffset8 << 3);
+ /* ASSERT(userLen > 0); */
+
+ DPRINT_DBG(VMBUS, "packet received on channel %p relid %d <type %d "
+ "flag %d tid %llx pktlen %d datalen %d> ",
+ channel, channel->OfferMsg.ChildRelId, desc.Type,
+ desc.Flags, desc.TransactionId, packetlen, userlen);
+
+ *buffer_actual_len = userlen;
+
+ if (userlen > bufferlen) {
+ spin_unlock_irqrestore(&channel->inbound_lock, flags);
+
+ DPRINT_ERR(VMBUS, "buffer too small - got %d needs %d",
+ bufferlen, userlen);
+ return -1;
+ }
+
+ *requestid = desc.TransactionId;
+
+ /* Copy over the packet to the user buffer */
+ ret = RingBufferRead(&channel->Inbound, buffer, userlen,
+ (desc.DataOffset8 << 3));
+
+ spin_unlock_irqrestore(&channel->inbound_lock, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL(vmbus_recvpacket);
+
+/*
+ * vmbus_recvpacket_raw - Retrieve the raw packet on the specified channel
+ */
+int vmbus_recvpacket_raw(struct vmbus_channel *channel, void *buffer,
+ u32 bufferlen, u32 *buffer_actual_len,
+ u64 *requestid)
+{
+ struct vmpacket_descriptor desc;
+ u32 packetlen;
+ u32 userlen;
+ int ret;
+ unsigned long flags;
+
+ *buffer_actual_len = 0;
+ *requestid = 0;
+
+ spin_lock_irqsave(&channel->inbound_lock, flags);
+
+ ret = RingBufferPeek(&channel->Inbound, &desc,
+ sizeof(struct vmpacket_descriptor));
+ if (ret != 0) {
+ spin_unlock_irqrestore(&channel->inbound_lock, flags);
+
+ /* DPRINT_DBG(VMBUS, "nothing to read!!"); */
+ return 0;
+ }
+
+ /* VmbusChannelClearEvent(Channel); */
+
+ packetlen = desc.Length8 << 3;
+ userlen = packetlen - (desc.DataOffset8 << 3);
+
+ DPRINT_DBG(VMBUS, "packet received on channel %p relid %d <type %d "
+ "flag %d tid %llx pktlen %d datalen %d> ",
+ channel, channel->OfferMsg.ChildRelId, desc.Type,
+ desc.Flags, desc.TransactionId, packetlen, userlen);
+
+ *buffer_actual_len = packetlen;
+
+ if (packetlen > bufferlen) {
+ spin_unlock_irqrestore(&channel->inbound_lock, flags);
+
+ DPRINT_ERR(VMBUS, "buffer too small - needed %d bytes but "
+ "got space for only %d bytes", packetlen, bufferlen);
+ return -2;
+ }
+
+ *requestid = desc.TransactionId;
+
+ /* Copy over the entire packet to the user buffer */
+ ret = RingBufferRead(&channel->Inbound, buffer, packetlen, 0);
+
+ spin_unlock_irqrestore(&channel->inbound_lock, flags);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(vmbus_recvpacket_raw);
+
+/*
+ * vmbus_onchannel_event - Channel event callback
+ */
+void vmbus_onchannel_event(struct vmbus_channel *channel)
+{
+ dump_vmbus_channel(channel);
+ /* ASSERT(Channel->OnChannelCallback); */
+
+ channel->OnChannelCallback(channel->ChannelCallbackContext);
+
+ mod_timer(&channel->poll_timer, jiffies + usecs_to_jiffies(100));
+}
+
+/*
+ * vmbus_ontimer - Timer event callback
+ */
+void vmbus_ontimer(unsigned long data)
+{
+ struct vmbus_channel *channel = (struct vmbus_channel *)data;
+
+ if (channel->OnChannelCallback)
+ channel->OnChannelCallback(channel->ChannelCallbackContext);
+}
+
+/*
+ * dump_vmbus_channel- Dump vmbus channel info to the console
+ */
+static void dump_vmbus_channel(struct vmbus_channel *channel)
+{
+ DPRINT_DBG(VMBUS, "Channel (%d)", channel->OfferMsg.ChildRelId);
+ DumpRingInfo(&channel->Outbound, "Outbound ");
+ DumpRingInfo(&channel->Inbound, "Inbound ");
+}
diff --git a/drivers/staging/hv/channel.h b/drivers/staging/hv/channel.h
new file mode 100644
index 0000000..7997056
--- /dev/null
+++ b/drivers/staging/hv/channel.h
@@ -0,0 +1,112 @@
+/*
+ *
+ * Copyright (c) 2009, Microsoft Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * Authors:
+ * Haiyang Zhang <haiyangz@microsoft.com>
+ * Hank Janssen <hjanssen@microsoft.com>
+ *
+ */
+
+
+#ifndef _CHANNEL_H_
+#define _CHANNEL_H_
+
+#include "channel_mgmt.h"
+
+/* The format must be the same as struct vmdata_gpa_direct */
+struct vmbus_channel_packet_page_buffer {
+ u16 type;
+ u16 dataoffset8;
+ u16 length8;
+ u16 flags;
+ u64 transactionid;
+ u32 reserved;
+ u32 rangecount;
+ struct hv_page_buffer range[MAX_PAGE_BUFFER_COUNT];
+} __attribute__((packed));
+
+/* The format must be the same as struct vmdata_gpa_direct */
+struct vmbus_channel_packet_multipage_buffer {
+ u16 type;
+ u16 dataoffset8;
+ u16 length8;
+ u16 flags;
+ u64 transactionid;
+ u32 reserved;
+ u32 rangecount; /* Always 1 in this case */
+ struct hv_multipage_buffer range;
+} __attribute__((packed));
+
+
+extern int vmbus_open(struct vmbus_channel *channel,
+ u32 send_ringbuffersize,
+ u32 recv_ringbuffersize,
+ void *userdata,
+ u32 userdatalen,
+ void(*onchannel_callback)(void *context),
+ void *context);
+
+extern void vmbus_close(struct vmbus_channel *channel);
+
+extern int vmbus_sendpacket(struct vmbus_channel *channel,
+ const void *buffer,
+ u32 bufferLen,
+ u64 requestid,
+ enum vmbus_packet_type type,
+ u32 flags);
+
+extern int vmbus_sendpacket_pagebuffer(struct vmbus_channel *channel,
+ struct hv_page_buffer pagebuffers[],
+ u32 pagecount,
+ void *buffer,
+ u32 bufferlen,
+ u64 requestid);
+
+extern int vmbus_sendpacket_multipagebuffer(struct vmbus_channel *channel,
+ struct hv_multipage_buffer *mpb,
+ void *buffer,
+ u32 bufferlen,
+ u64 requestid);
+
+extern int vmbus_establish_gpadl(struct vmbus_channel *channel,
+ void *kbuffer,
+ u32 size,
+ u32 *gpadl_handle);
+
+extern int vmbus_teardown_gpadl(struct vmbus_channel *channel,
+ u32 gpadl_handle);
+
+extern int vmbus_recvpacket(struct vmbus_channel *channel,
+ void *buffer,
+ u32 bufferlen,
+ u32 *buffer_actual_len,
+ u64 *requestid);
+
+extern int vmbus_recvpacket_raw(struct vmbus_channel *channel,
+ void *buffer,
+ u32 bufferlen,
+ u32 *buffer_actual_len,
+ u64 *requestid);
+
+extern void vmbus_onchannel_event(struct vmbus_channel *channel);
+
+extern void vmbus_get_debug_info(struct vmbus_channel *channel,
+ struct vmbus_channel_debug_info *debug);
+
+extern void vmbus_ontimer(unsigned long data);
+
+#endif /* _CHANNEL_H_ */
diff --git a/drivers/staging/hv/channel_mgmt.c b/drivers/staging/hv/channel_mgmt.c
new file mode 100644
index 0000000..45dbe30
--- /dev/null
+++ b/drivers/staging/hv/channel_mgmt.c
@@ -0,0 +1,861 @@
+/*
+ * Copyright (c) 2009, Microsoft Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * Authors:
+ * Haiyang Zhang <haiyangz@microsoft.com>
+ * Hank Janssen <hjanssen@microsoft.com>
+ */
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/completion.h>
+#include "osd.h"
+#include "logging.h"
+#include "vmbus_private.h"
+#include "utils.h"
+
+struct vmbus_channel_message_table_entry {
+ enum vmbus_channel_message_type messageType;
+ void (*messageHandler)(struct vmbus_channel_message_header *msg);
+};
+
+#define MAX_MSG_TYPES 3
+#define MAX_NUM_DEVICE_CLASSES_SUPPORTED 7
+
+static const struct hv_guid
+ gSupportedDeviceClasses[MAX_NUM_DEVICE_CLASSES_SUPPORTED] = {
+ /* {ba6163d9-04a1-4d29-b605-72e2ffb1dc7f} */
+ /* Storage - SCSI */
+ {
+ .data = {
+ 0xd9, 0x63, 0x61, 0xba, 0xa1, 0x04, 0x29, 0x4d,
+ 0xb6, 0x05, 0x72, 0xe2, 0xff, 0xb1, 0xdc, 0x7f
+ }
+ },
+
+ /* {F8615163-DF3E-46c5-913F-F2D2F965ED0E} */
+ /* Network */
+ {
+ .data = {
+ 0x63, 0x51, 0x61, 0xF8, 0x3E, 0xDF, 0xc5, 0x46,
+ 0x91, 0x3F, 0xF2, 0xD2, 0xF9, 0x65, 0xED, 0x0E
+ }
+ },
+
+ /* {CFA8B69E-5B4A-4cc0-B98B-8BA1A1F3F95A} */
+ /* Input */
+ {
+ .data = {
+ 0x9E, 0xB6, 0xA8, 0xCF, 0x4A, 0x5B, 0xc0, 0x4c,
+ 0xB9, 0x8B, 0x8B, 0xA1, 0xA1, 0xF3, 0xF9, 0x5A
+ }
+ },
+
+ /* {32412632-86cb-44a2-9b5c-50d1417354f5} */
+ /* IDE */
+ {
+ .data = {
+ 0x32, 0x26, 0x41, 0x32, 0xcb, 0x86, 0xa2, 0x44,
+ 0x9b, 0x5c, 0x50, 0xd1, 0x41, 0x73, 0x54, 0xf5
+ }
+ },
+ /* 0E0B6031-5213-4934-818B-38D90CED39DB */
+ /* Shutdown */
+ {
+ .data = {
+ 0x31, 0x60, 0x0B, 0X0E, 0x13, 0x52, 0x34, 0x49,
+ 0x81, 0x8B, 0x38, 0XD9, 0x0C, 0xED, 0x39, 0xDB
+ }
+ },
+ /* {9527E630-D0AE-497b-ADCE-E80AB0175CAF} */
+ /* TimeSync */
+ {
+ .data = {
+ 0x30, 0xe6, 0x27, 0x95, 0xae, 0xd0, 0x7b, 0x49,
+ 0xad, 0xce, 0xe8, 0x0a, 0xb0, 0x17, 0x5c, 0xaf
+ }
+ },
+ /* {57164f39-9115-4e78-ab55-382f3bd5422d} */
+ /* Heartbeat */
+ {
+ .data = {
+ 0x39, 0x4f, 0x16, 0x57, 0x15, 0x91, 0x78, 0x4e,
+ 0xab, 0x55, 0x38, 0x2f, 0x3b, 0xd5, 0x42, 0x2d
+ }
+ },
+};
+
+
+/**
+ * prep_negotiate_resp() - Create default response for Hyper-V Negotiate message
+ * @icmsghdrp: Pointer to msg header structure
+ * @icmsg_negotiate: Pointer to negotiate message structure
+ * @buf: Raw buffer channel data
+ *
+ * @icmsghdrp is of type &struct icmsg_hdr.
+ * @negop is of type &struct icmsg_negotiate.
+ * Set up and fill in default negotiate response message. This response can
+ * come from both the vmbus driver and the hv_utils driver. The current api
+ * will respond properly to both Windows 2008 and Windows 2008-R2 operating
+ * systems.
+ *
+ * Mainly used by Hyper-V drivers.
+ */
+void prep_negotiate_resp(struct icmsg_hdr *icmsghdrp,
+ struct icmsg_negotiate *negop,
+ u8 *buf)
+{
+ if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
+ icmsghdrp->icmsgsize = 0x10;
+
+ negop = (struct icmsg_negotiate *)&buf[
+ sizeof(struct vmbuspipe_hdr) +
+ sizeof(struct icmsg_hdr)];
+
+ if (negop->icframe_vercnt == 2 &&
+ negop->icversion_data[1].major == 3) {
+ negop->icversion_data[0].major = 3;
+ negop->icversion_data[0].minor = 0;
+ negop->icversion_data[1].major = 3;
+ negop->icversion_data[1].minor = 0;
+ } else {
+ negop->icversion_data[0].major = 1;
+ negop->icversion_data[0].minor = 0;
+ negop->icversion_data[1].major = 1;
+ negop->icversion_data[1].minor = 0;
+ }
+
+ negop->icframe_vercnt = 1;
+ negop->icmsg_vercnt = 1;
+ }
+}
+EXPORT_SYMBOL(prep_negotiate_resp);
+
+/**
+ * chn_cb_negotiate() - Default handler for non IDE/SCSI/NETWORK
+ * Hyper-V requests
+ * @context: Pointer to argument structure.
+ *
+ * Set up the default handler for non device driver specific requests
+ * from Hyper-V. This stub responds to the default negotiate messages
+ * that come in for every non IDE/SCSI/Network request.
+ * This behavior is normally overwritten in the hv_utils driver. That
+ * driver handles requests like gracefull shutdown, heartbeats etc.
+ *
+ * Mainly used by Hyper-V drivers.
+ */
+void chn_cb_negotiate(void *context)
+{
+ struct vmbus_channel *channel = context;
+ u8 *buf;
+ u32 buflen, recvlen;
+ u64 requestid;
+
+ struct icmsg_hdr *icmsghdrp;
+ struct icmsg_negotiate *negop = NULL;
+
+ buflen = PAGE_SIZE;
+ buf = kmalloc(buflen, GFP_ATOMIC);
+
+ vmbus_recvpacket(channel, buf, buflen, &recvlen, &requestid);
+
+ if (recvlen > 0) {
+ icmsghdrp = (struct icmsg_hdr *)&buf[
+ sizeof(struct vmbuspipe_hdr)];
+
+ prep_negotiate_resp(icmsghdrp, negop, buf);
+
+ icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION
+ | ICMSGHDRFLAG_RESPONSE;
+
+ vmbus_sendpacket(channel, buf,
+ recvlen, requestid,
+ VmbusPacketTypeDataInBand, 0);
+ }
+
+ kfree(buf);
+}
+EXPORT_SYMBOL(chn_cb_negotiate);
+
+/*
+ * Function table used for message responses for non IDE/SCSI/Network type
+ * messages. (Such as KVP/Shutdown etc)
+ */
+struct hyperv_service_callback hv_cb_utils[MAX_MSG_TYPES] = {
+ /* 0E0B6031-5213-4934-818B-38D90CED39DB */
+ /* Shutdown */
+ {
+ .msg_type = HV_SHUTDOWN_MSG,
+ .data = {
+ 0x31, 0x60, 0x0B, 0X0E, 0x13, 0x52, 0x34, 0x49,
+ 0x81, 0x8B, 0x38, 0XD9, 0x0C, 0xED, 0x39, 0xDB
+ },
+ .callback = chn_cb_negotiate,
+ .log_msg = "Shutdown channel functionality initialized"
+ },
+
+ /* {9527E630-D0AE-497b-ADCE-E80AB0175CAF} */
+ /* TimeSync */
+ {
+ .msg_type = HV_TIMESYNC_MSG,
+ .data = {
+ 0x30, 0xe6, 0x27, 0x95, 0xae, 0xd0, 0x7b, 0x49,
+ 0xad, 0xce, 0xe8, 0x0a, 0xb0, 0x17, 0x5c, 0xaf
+ },
+ .callback = chn_cb_negotiate,
+ .log_msg = "Timesync channel functionality initialized"
+ },
+ /* {57164f39-9115-4e78-ab55-382f3bd5422d} */
+ /* Heartbeat */
+ {
+ .msg_type = HV_HEARTBEAT_MSG,
+ .data = {
+ 0x39, 0x4f, 0x16, 0x57, 0x15, 0x91, 0x78, 0x4e,
+ 0xab, 0x55, 0x38, 0x2f, 0x3b, 0xd5, 0x42, 0x2d
+ },
+ .callback = chn_cb_negotiate,
+ .log_msg = "Heartbeat channel functionality initialized"
+ },
+};
+EXPORT_SYMBOL(hv_cb_utils);
+
+/*
+ * alloc_channel - Allocate and initialize a vmbus channel object
+ */
+static struct vmbus_channel *alloc_channel(void)
+{
+ struct vmbus_channel *channel;
+
+ channel = kzalloc(sizeof(*channel), GFP_ATOMIC);
+ if (!channel)
+ return NULL;
+
+ spin_lock_init(&channel->inbound_lock);
+
+ init_timer(&channel->poll_timer);
+ channel->poll_timer.data = (unsigned long)channel;
+ channel->poll_timer.function = vmbus_ontimer;
+
+ channel->ControlWQ = create_workqueue("hv_vmbus_ctl");
+ if (!channel->ControlWQ) {
+ kfree(channel);
+ return NULL;
+ }
+
+ return channel;
+}
+
+/*
+ * release_hannel - Release the vmbus channel object itself
+ */
+static inline void release_channel(void *context)
+{
+ struct vmbus_channel *channel = context;
+
+ DPRINT_DBG(VMBUS, "releasing channel (%p)", channel);
+ destroy_workqueue(channel->ControlWQ);
+ DPRINT_DBG(VMBUS, "channel released (%p)", channel);
+
+ kfree(channel);
+}
+
+/*
+ * free_channel - Release the resources used by the vmbus channel object
+ */
+void free_channel(struct vmbus_channel *channel)
+{
+ del_timer_sync(&channel->poll_timer);
+
+ /*
+ * We have to release the channel's workqueue/thread in the vmbus's
+ * workqueue/thread context
+ * ie we can't destroy ourselves.
+ */
+ osd_schedule_callback(gVmbusConnection.WorkQueue, release_channel,
+ channel);
+}
+
+
+DECLARE_COMPLETION(hv_channel_ready);
+
+/*
+ * Count initialized channels, and ensure all channels are ready when hv_vmbus
+ * module loading completes.
+ */
+static void count_hv_channel(void)
+{
+ static int counter;
+ unsigned long flags;
+
+ spin_lock_irqsave(&gVmbusConnection.channel_lock, flags);
+ if (++counter == MAX_MSG_TYPES)
+ complete(&hv_channel_ready);
+ spin_unlock_irqrestore(&gVmbusConnection.channel_lock, flags);
+}
+
+
+/*
+ * vmbus_process_offer - Process the offer by creating a channel/device
+ * associated with this offer
+ */
+static void vmbus_process_offer(void *context)
+{
+ struct vmbus_channel *newchannel = context;
+ struct vmbus_channel *channel;
+ bool fnew = true;
+ int ret;
+ int cnt;
+ unsigned long flags;
+
+ /* Make sure this is a new offer */
+ spin_lock_irqsave(&gVmbusConnection.channel_lock, flags);
+
+ list_for_each_entry(channel, &gVmbusConnection.ChannelList, ListEntry) {
+ if (!memcmp(&channel->OfferMsg.Offer.InterfaceType,
+ &newchannel->OfferMsg.Offer.InterfaceType,
+ sizeof(struct hv_guid)) &&
+ !memcmp(&channel->OfferMsg.Offer.InterfaceInstance,
+ &newchannel->OfferMsg.Offer.InterfaceInstance,
+ sizeof(struct hv_guid))) {
+ fnew = false;
+ break;
+ }
+ }
+
+ if (fnew)
+ list_add_tail(&newchannel->ListEntry,
+ &gVmbusConnection.ChannelList);
+
+ spin_unlock_irqrestore(&gVmbusConnection.channel_lock, flags);
+
+ if (!fnew) {
+ DPRINT_DBG(VMBUS, "Ignoring duplicate offer for relid (%d)",
+ newchannel->OfferMsg.ChildRelId);
+ free_channel(newchannel);
+ return;
+ }
+
+ /*
+ * Start the process of binding this offer to the driver
+ * We need to set the DeviceObject field before calling
+ * VmbusChildDeviceAdd()
+ */
+ newchannel->DeviceObject = VmbusChildDeviceCreate(
+ &newchannel->OfferMsg.Offer.InterfaceType,
+ &newchannel->OfferMsg.Offer.InterfaceInstance,
+ newchannel);
+
+ DPRINT_DBG(VMBUS, "child device object allocated - %p",
+ newchannel->DeviceObject);
+
+ /*
+ * Add the new device to the bus. This will kick off device-driver
+ * binding which eventually invokes the device driver's AddDevice()
+ * method.
+ */
+ ret = VmbusChildDeviceAdd(newchannel->DeviceObject);
+ if (ret != 0) {
+ DPRINT_ERR(VMBUS,
+ "unable to add child device object (relid %d)",
+ newchannel->OfferMsg.ChildRelId);
+
+ spin_lock_irqsave(&gVmbusConnection.channel_lock, flags);
+ list_del(&newchannel->ListEntry);
+ spin_unlock_irqrestore(&gVmbusConnection.channel_lock, flags);
+
+ free_channel(newchannel);
+ } else {
+ /*
+ * This state is used to indicate a successful open
+ * so that when we do close the channel normally, we
+ * can cleanup properly
+ */
+ newchannel->State = CHANNEL_OPEN_STATE;
+
+ /* Open IC channels */
+ for (cnt = 0; cnt < MAX_MSG_TYPES; cnt++) {
+ if (memcmp(&newchannel->OfferMsg.Offer.InterfaceType,
+ &hv_cb_utils[cnt].data,
+ sizeof(struct hv_guid)) == 0 &&
+ vmbus_open(newchannel, 2 * PAGE_SIZE,
+ 2 * PAGE_SIZE, NULL, 0,
+ hv_cb_utils[cnt].callback,
+ newchannel) == 0) {
+ hv_cb_utils[cnt].channel = newchannel;
+ DPRINT_INFO(VMBUS, "%s",
+ hv_cb_utils[cnt].log_msg);
+ count_hv_channel();
+ }
+ }
+ }
+}
+
+/*
+ * vmbus_process_rescind_offer -
+ * Rescind the offer by initiating a device removal
+ */
+static void vmbus_process_rescind_offer(void *context)
+{
+ struct vmbus_channel *channel = context;
+
+ VmbusChildDeviceRemove(channel->DeviceObject);
+}
+
+/*
+ * vmbus_onoffer - Handler for channel offers from vmbus in parent partition.
+ *
+ * We ignore all offers except network and storage offers. For each network and
+ * storage offers, we create a channel object and queue a work item to the
+ * channel object to process the offer synchronously
+ */
+static void vmbus_onoffer(struct vmbus_channel_message_header *hdr)
+{
+ struct vmbus_channel_offer_channel *offer;
+ struct vmbus_channel *newchannel;
+ struct hv_guid *guidtype;
+ struct hv_guid *guidinstance;
+ int i;
+ int fsupported = 0;
+
+ offer = (struct vmbus_channel_offer_channel *)hdr;
+ for (i = 0; i < MAX_NUM_DEVICE_CLASSES_SUPPORTED; i++) {
+ if (memcmp(&offer->Offer.InterfaceType,
+ &gSupportedDeviceClasses[i], sizeof(struct hv_guid)) == 0) {
+ fsupported = 1;
+ break;
+ }
+ }
+
+ if (!fsupported) {
+ DPRINT_DBG(VMBUS, "Ignoring channel offer notification for "
+ "child relid %d", offer->ChildRelId);
+ return;
+ }
+
+ guidtype = &offer->Offer.InterfaceType;
+ guidinstance = &offer->Offer.InterfaceInstance;
+
+ DPRINT_INFO(VMBUS, "Channel offer notification - "
+ "child relid %d monitor id %d allocated %d, "
+ "type {%02x%02x%02x%02x-%02x%02x-%02x%02x-"
+ "%02x%02x%02x%02x%02x%02x%02x%02x} "
+ "instance {%02x%02x%02x%02x-%02x%02x-%02x%02x-"
+ "%02x%02x%02x%02x%02x%02x%02x%02x}",
+ offer->ChildRelId, offer->MonitorId,
+ offer->MonitorAllocated,
+ guidtype->data[3], guidtype->data[2],
+ guidtype->data[1], guidtype->data[0],
+ guidtype->data[5], guidtype->data[4],
+ guidtype->data[7], guidtype->data[6],
+ guidtype->data[8], guidtype->data[9],
+ guidtype->data[10], guidtype->data[11],
+ guidtype->data[12], guidtype->data[13],
+ guidtype->data[14], guidtype->data[15],
+ guidinstance->data[3], guidinstance->data[2],
+ guidinstance->data[1], guidinstance->data[0],
+ guidinstance->data[5], guidinstance->data[4],
+ guidinstance->data[7], guidinstance->data[6],
+ guidinstance->data[8], guidinstance->data[9],
+ guidinstance->data[10], guidinstance->data[11],
+ guidinstance->data[12], guidinstance->data[13],
+ guidinstance->data[14], guidinstance->data[15]);
+
+ /* Allocate the channel object and save this offer. */
+ newchannel = alloc_channel();
+ if (!newchannel) {
+ DPRINT_ERR(VMBUS, "unable to allocate channel object");
+ return;
+ }
+
+ DPRINT_DBG(VMBUS, "channel object allocated - %p", newchannel);
+
+ memcpy(&newchannel->OfferMsg, offer,
+ sizeof(struct vmbus_channel_offer_channel));
+ newchannel->MonitorGroup = (u8)offer->MonitorId / 32;
+ newchannel->MonitorBit = (u8)offer->MonitorId % 32;
+
+ /* TODO: Make sure the offer comes from our parent partition */
+ osd_schedule_callback(newchannel->ControlWQ, vmbus_process_offer,
+ newchannel);
+}
+
+/*
+ * vmbus_onoffer_rescind - Rescind offer handler.
+ *
+ * We queue a work item to process this offer synchronously
+ */
+static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr)
+{
+ struct vmbus_channel_rescind_offer *rescind;
+ struct vmbus_channel *channel;
+
+ rescind = (struct vmbus_channel_rescind_offer *)hdr;
+ channel = GetChannelFromRelId(rescind->ChildRelId);
+ if (channel == NULL) {
+ DPRINT_DBG(VMBUS, "channel not found for relId %d",
+ rescind->ChildRelId);
+ return;
+ }
+
+ osd_schedule_callback(channel->ControlWQ,
+ vmbus_process_rescind_offer,
+ channel);
+}
+
+/*
+ * vmbus_onoffers_delivered -
+ * This is invoked when all offers have been delivered.
+ *
+ * Nothing to do here.
+ */
+static void vmbus_onoffers_delivered(
+ struct vmbus_channel_message_header *hdr)
+{
+}
+
+/*
+ * vmbus_onopen_result - Open result handler.
+ *
+ * This is invoked when we received a response to our channel open request.
+ * Find the matching request, copy the response and signal the requesting
+ * thread.
+ */
+static void vmbus_onopen_result(struct vmbus_channel_message_header *hdr)
+{
+ struct vmbus_channel_open_result *result;
+ struct list_head *curr;
+ struct vmbus_channel_msginfo *msginfo;
+ struct vmbus_channel_message_header *requestheader;
+ struct vmbus_channel_open_channel *openmsg;
+ unsigned long flags;
+
+ result = (struct vmbus_channel_open_result *)hdr;
+ DPRINT_DBG(VMBUS, "vmbus open result - %d", result->Status);
+
+ /*
+ * Find the open msg, copy the result and signal/unblock the wait event
+ */
+ spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
+
+ list_for_each(curr, &gVmbusConnection.ChannelMsgList) {
+/* FIXME: this should probably use list_entry() instead */
+ msginfo = (struct vmbus_channel_msginfo *)curr;
+ requestheader =
+ (struct vmbus_channel_message_header *)msginfo->Msg;
+
+ if (requestheader->MessageType == ChannelMessageOpenChannel) {
+ openmsg =
+ (struct vmbus_channel_open_channel *)msginfo->Msg;
+ if (openmsg->ChildRelId == result->ChildRelId &&
+ openmsg->OpenId == result->OpenId) {
+ memcpy(&msginfo->Response.OpenResult,
+ result,
+ sizeof(struct vmbus_channel_open_result));
+ osd_WaitEventSet(msginfo->WaitEvent);
+ break;
+ }
+ }
+ }
+ spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
+}
+
+/*
+ * vmbus_ongpadl_created - GPADL created handler.
+ *
+ * This is invoked when we received a response to our gpadl create request.
+ * Find the matching request, copy the response and signal the requesting
+ * thread.
+ */
+static void vmbus_ongpadl_created(struct vmbus_channel_message_header *hdr)
+{
+ struct vmbus_channel_gpadl_created *gpadlcreated;
+ struct list_head *curr;
+ struct vmbus_channel_msginfo *msginfo;
+ struct vmbus_channel_message_header *requestheader;
+ struct vmbus_channel_gpadl_header *gpadlheader;
+ unsigned long flags;
+
+ gpadlcreated = (struct vmbus_channel_gpadl_created *)hdr;
+ DPRINT_DBG(VMBUS, "vmbus gpadl created result - %d",
+ gpadlcreated->CreationStatus);
+
+ /*
+ * Find the establish msg, copy the result and signal/unblock the wait
+ * event
+ */
+ spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
+
+ list_for_each(curr, &gVmbusConnection.ChannelMsgList) {
+/* FIXME: this should probably use list_entry() instead */
+ msginfo = (struct vmbus_channel_msginfo *)curr;
+ requestheader =
+ (struct vmbus_channel_message_header *)msginfo->Msg;
+
+ if (requestheader->MessageType == ChannelMessageGpadlHeader) {
+ gpadlheader =
+ (struct vmbus_channel_gpadl_header *)requestheader;
+
+ if ((gpadlcreated->ChildRelId ==
+ gpadlheader->ChildRelId) &&
+ (gpadlcreated->Gpadl == gpadlheader->Gpadl)) {
+ memcpy(&msginfo->Response.GpadlCreated,
+ gpadlcreated,
+ sizeof(struct vmbus_channel_gpadl_created));
+ osd_WaitEventSet(msginfo->WaitEvent);
+ break;
+ }
+ }
+ }
+ spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
+}
+
+/*
+ * vmbus_ongpadl_torndown - GPADL torndown handler.
+ *
+ * This is invoked when we received a response to our gpadl teardown request.
+ * Find the matching request, copy the response and signal the requesting
+ * thread.
+ */
+static void vmbus_ongpadl_torndown(
+ struct vmbus_channel_message_header *hdr)
+{
+ struct vmbus_channel_gpadl_torndown *gpadl_torndown;
+ struct list_head *curr;
+ struct vmbus_channel_msginfo *msginfo;
+ struct vmbus_channel_message_header *requestheader;
+ struct vmbus_channel_gpadl_teardown *gpadl_teardown;
+ unsigned long flags;
+
+ gpadl_torndown = (struct vmbus_channel_gpadl_torndown *)hdr;
+
+ /*
+ * Find the open msg, copy the result and signal/unblock the wait event
+ */
+ spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
+
+ list_for_each(curr, &gVmbusConnection.ChannelMsgList) {
+/* FIXME: this should probably use list_entry() instead */
+ msginfo = (struct vmbus_channel_msginfo *)curr;
+ requestheader =
+ (struct vmbus_channel_message_header *)msginfo->Msg;
+
+ if (requestheader->MessageType == ChannelMessageGpadlTeardown) {
+ gpadl_teardown =
+ (struct vmbus_channel_gpadl_teardown *)requestheader;
+
+ if (gpadl_torndown->Gpadl == gpadl_teardown->Gpadl) {
+ memcpy(&msginfo->Response.GpadlTorndown,
+ gpadl_torndown,
+ sizeof(struct vmbus_channel_gpadl_torndown));
+ osd_WaitEventSet(msginfo->WaitEvent);
+ break;
+ }
+ }
+ }
+ spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
+}
+
+/*
+ * vmbus_onversion_response - Version response handler
+ *
+ * This is invoked when we received a response to our initiate contact request.
+ * Find the matching request, copy the response and signal the requesting
+ * thread.
+ */
+static void vmbus_onversion_response(
+ struct vmbus_channel_message_header *hdr)
+{
+ struct list_head *curr;
+ struct vmbus_channel_msginfo *msginfo;
+ struct vmbus_channel_message_header *requestheader;
+ struct vmbus_channel_initiate_contact *initiate;
+ struct vmbus_channel_version_response *version_response;
+ unsigned long flags;
+
+ version_response = (struct vmbus_channel_version_response *)hdr;
+ spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
+
+ list_for_each(curr, &gVmbusConnection.ChannelMsgList) {
+/* FIXME: this should probably use list_entry() instead */
+ msginfo = (struct vmbus_channel_msginfo *)curr;
+ requestheader =
+ (struct vmbus_channel_message_header *)msginfo->Msg;
+
+ if (requestheader->MessageType ==
+ ChannelMessageInitiateContact) {
+ initiate =
+ (struct vmbus_channel_initiate_contact *)requestheader;
+ memcpy(&msginfo->Response.VersionResponse,
+ version_response,
+ sizeof(struct vmbus_channel_version_response));
+ osd_WaitEventSet(msginfo->WaitEvent);
+ }
+ }
+ spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
+}
+
+/* Channel message dispatch table */
+static struct vmbus_channel_message_table_entry
+ gChannelMessageTable[ChannelMessageCount] = {
+ {ChannelMessageInvalid, NULL},
+ {ChannelMessageOfferChannel, vmbus_onoffer},
+ {ChannelMessageRescindChannelOffer, vmbus_onoffer_rescind},
+ {ChannelMessageRequestOffers, NULL},
+ {ChannelMessageAllOffersDelivered, vmbus_onoffers_delivered},
+ {ChannelMessageOpenChannel, NULL},
+ {ChannelMessageOpenChannelResult, vmbus_onopen_result},
+ {ChannelMessageCloseChannel, NULL},
+ {ChannelMessageGpadlHeader, NULL},
+ {ChannelMessageGpadlBody, NULL},
+ {ChannelMessageGpadlCreated, vmbus_ongpadl_created},
+ {ChannelMessageGpadlTeardown, NULL},
+ {ChannelMessageGpadlTorndown, vmbus_ongpadl_torndown},
+ {ChannelMessageRelIdReleased, NULL},
+ {ChannelMessageInitiateContact, NULL},
+ {ChannelMessageVersionResponse, vmbus_onversion_response},
+ {ChannelMessageUnload, NULL},
+};
+
+/*
+ * vmbus_onmessage - Handler for channel protocol messages.
+ *
+ * This is invoked in the vmbus worker thread context.
+ */
+void vmbus_onmessage(void *context)
+{
+ struct hv_message *msg = context;
+ struct vmbus_channel_message_header *hdr;
+ int size;
+
+ hdr = (struct vmbus_channel_message_header *)msg->u.Payload;
+ size = msg->Header.PayloadSize;
+
+ DPRINT_DBG(VMBUS, "message type %d size %d", hdr->MessageType, size);
+
+ if (hdr->MessageType >= ChannelMessageCount) {
+ DPRINT_ERR(VMBUS,
+ "Received invalid channel message type %d size %d",
+ hdr->MessageType, size);
+ print_hex_dump_bytes("", DUMP_PREFIX_NONE,
+ (unsigned char *)msg->u.Payload, size);
+ kfree(msg);
+ return;
+ }
+
+ if (gChannelMessageTable[hdr->MessageType].messageHandler)
+ gChannelMessageTable[hdr->MessageType].messageHandler(hdr);
+ else
+ DPRINT_ERR(VMBUS, "Unhandled channel message type %d",
+ hdr->MessageType);
+
+ /* Free the msg that was allocated in VmbusOnMsgDPC() */
+ kfree(msg);
+}
+
+/*
+ * vmbus_request_offers - Send a request to get all our pending offers.
+ */
+int vmbus_request_offers(void)
+{
+ struct vmbus_channel_message_header *msg;
+ struct vmbus_channel_msginfo *msginfo;
+ int ret;
+
+ msginfo = kmalloc(sizeof(*msginfo) +
+ sizeof(struct vmbus_channel_message_header),
+ GFP_KERNEL);
+ if (!msginfo)
+ return -ENOMEM;
+
+ msginfo->WaitEvent = osd_WaitEventCreate();
+ if (!msginfo->WaitEvent) {
+ kfree(msginfo);
+ return -ENOMEM;
+ }
+
+ msg = (struct vmbus_channel_message_header *)msginfo->Msg;
+
+ msg->MessageType = ChannelMessageRequestOffers;
+
+ /*SpinlockAcquire(gVmbusConnection.channelMsgLock);
+ INSERT_TAIL_LIST(&gVmbusConnection.channelMsgList,
+ &msgInfo->msgListEntry);
+ SpinlockRelease(gVmbusConnection.channelMsgLock);*/
+
+ ret = VmbusPostMessage(msg,
+ sizeof(struct vmbus_channel_message_header));
+ if (ret != 0) {
+ DPRINT_ERR(VMBUS, "Unable to request offers - %d", ret);
+
+ /*SpinlockAcquire(gVmbusConnection.channelMsgLock);
+ REMOVE_ENTRY_LIST(&msgInfo->msgListEntry);
+ SpinlockRelease(gVmbusConnection.channelMsgLock);*/
+
+ goto Cleanup;
+ }
+ /* osd_WaitEventWait(msgInfo->waitEvent); */
+
+ /*SpinlockAcquire(gVmbusConnection.channelMsgLock);
+ REMOVE_ENTRY_LIST(&msgInfo->msgListEntry);
+ SpinlockRelease(gVmbusConnection.channelMsgLock);*/
+
+
+Cleanup:
+ if (msginfo) {
+ kfree(msginfo->WaitEvent);
+ kfree(msginfo);
+ }
+
+ return ret;
+}
+
+/*
+ * vmbus_release_unattached_channels - Release channels that are
+ * unattached/unconnected ie (no drivers associated)
+ */
+void vmbus_release_unattached_channels(void)
+{
+ struct vmbus_channel *channel, *pos;
+ struct vmbus_channel *start = NULL;
+ unsigned long flags;
+
+ spin_lock_irqsave(&gVmbusConnection.channel_lock, flags);
+
+ list_for_each_entry_safe(channel, pos, &gVmbusConnection.ChannelList,
+ ListEntry) {
+ if (channel == start)
+ break;
+
+ if (!channel->DeviceObject->Driver) {
+ list_del(&channel->ListEntry);
+ DPRINT_INFO(VMBUS,
+ "Releasing unattached device object %p",
+ channel->DeviceObject);
+
+ VmbusChildDeviceRemove(channel->DeviceObject);
+ free_channel(channel);
+ } else {
+ if (!start)
+ start = channel;
+ }
+ }
+
+ spin_unlock_irqrestore(&gVmbusConnection.channel_lock, flags);
+}
+
+/* eof */
diff --git a/drivers/staging/hv/ChannelMgmt.h b/drivers/staging/hv/channel_mgmt.h
index fa973d8..d16cc08 100644
--- a/drivers/staging/hv/ChannelMgmt.h
+++ b/drivers/staging/hv/channel_mgmt.h
@@ -27,9 +27,9 @@
#include <linux/list.h>
#include <linux/timer.h>
-#include "RingBuffer.h"
-#include "VmbusChannelInterface.h"
-#include "VmbusPacketFormat.h"
+#include "ring_buffer.h"
+#include "vmbus_channel_interface.h"
+#include "vmbus_packet_format.h"
/* Version 1 messages */
enum vmbus_channel_message_type {
@@ -247,8 +247,8 @@ struct vmbus_channel {
/* Allocated memory for ring buffer */
void *RingBufferPages;
u32 RingBufferPageCount;
- RING_BUFFER_INFO Outbound; /* send to parent */
- RING_BUFFER_INFO Inbound; /* receive from parent */
+ struct hv_ring_buffer_info Outbound; /* send to parent */
+ struct hv_ring_buffer_info Inbound; /* receive from parent */
spinlock_t inbound_lock;
struct workqueue_struct *ControlWQ;
@@ -272,8 +272,8 @@ struct vmbus_channel_debug_info {
u32 ClientMonitorLatency;
u32 ClientMonitorConnectionId;
- RING_BUFFER_DEBUG_INFO Inbound;
- RING_BUFFER_DEBUG_INFO Outbound;
+ struct hv_ring_buffer_debug_info Inbound;
+ struct hv_ring_buffer_debug_info Outbound;
};
/*
@@ -307,14 +307,12 @@ struct vmbus_channel_msginfo {
};
-struct vmbus_channel *AllocVmbusChannel(void);
+void free_channel(struct vmbus_channel *channel);
-void FreeVmbusChannel(struct vmbus_channel *Channel);
+void vmbus_onmessage(void *context);
-void VmbusOnChannelMessage(void *Context);
+int vmbus_request_offers(void);
-int VmbusChannelRequestOffers(void);
-
-void VmbusChannelReleaseUnattachedChannels(void);
+void vmbus_release_unattached_channels(void);
#endif /* _CHANNEL_MGMT_H_ */
diff --git a/drivers/staging/hv/Connection.c b/drivers/staging/hv/connection.c
index 43c2e68..f847707 100644
--- a/drivers/staging/hv/Connection.c
+++ b/drivers/staging/hv/connection.c
@@ -22,10 +22,11 @@
*/
#include <linux/kernel.h>
#include <linux/mm.h>
+#include <linux/slab.h>
#include <linux/vmalloc.h>
#include "osd.h"
#include "logging.h"
-#include "VmbusPrivate.h"
+#include "vmbus_private.h"
struct VMBUS_CONNECTION gVmbusConnection = {
@@ -33,7 +34,7 @@ struct VMBUS_CONNECTION gVmbusConnection = {
.NextGpadlHandle = ATOMIC_INIT(0xE1E10),
};
-/**
+/*
* VmbusConnect - Sends a connect request on the partition service connection
*/
int VmbusConnect(void)
@@ -43,8 +44,6 @@ int VmbusConnect(void)
struct vmbus_channel_initiate_contact *msg;
unsigned long flags;
- DPRINT_ENTER(VMBUS);
-
/* Make sure we are not connecting or connected */
if (gVmbusConnection.ConnectState != Disconnected)
return -1;
@@ -92,11 +91,16 @@ int VmbusConnect(void)
sizeof(struct vmbus_channel_initiate_contact),
GFP_KERNEL);
if (msgInfo == NULL) {
- ret = -1;
+ ret = -ENOMEM;
goto Cleanup;
}
msgInfo->WaitEvent = osd_WaitEventCreate();
+ if (!msgInfo->WaitEvent) {
+ ret = -ENOMEM;
+ goto Cleanup;
+ }
+
msg = (struct vmbus_channel_initiate_contact *)msgInfo->Msg;
msg->Header.MessageType = ChannelMessageInitiateContact;
@@ -149,8 +153,6 @@ int VmbusConnect(void)
kfree(msgInfo->WaitEvent);
kfree(msgInfo);
- DPRINT_EXIT(VMBUS);
-
return 0;
Cleanup:
@@ -174,12 +176,10 @@ Cleanup:
kfree(msgInfo);
}
- DPRINT_EXIT(VMBUS);
-
return ret;
}
-/**
+/*
* VmbusDisconnect - Sends a disconnect request on the partition service connection
*/
int VmbusDisconnect(void)
@@ -187,13 +187,13 @@ int VmbusDisconnect(void)
int ret = 0;
struct vmbus_channel_message_header *msg;
- DPRINT_ENTER(VMBUS);
-
/* Make sure we are connected */
if (gVmbusConnection.ConnectState != Connected)
return -1;
msg = kzalloc(sizeof(struct vmbus_channel_message_header), GFP_KERNEL);
+ if (!msg)
+ return -ENOMEM;
msg->MessageType = ChannelMessageUnload;
@@ -213,11 +213,10 @@ int VmbusDisconnect(void)
Cleanup:
kfree(msg);
- DPRINT_EXIT(VMBUS);
return ret;
}
-/**
+/*
* GetChannelFromRelId - Get the channel object given its child relative id (ie channel id)
*/
struct vmbus_channel *GetChannelFromRelId(u32 relId)
@@ -238,7 +237,7 @@ struct vmbus_channel *GetChannelFromRelId(u32 relId)
return foundChannel;
}
-/**
+/*
* VmbusProcessChannelEvent - Process a channel event notification
*/
static void VmbusProcessChannelEvent(void *context)
@@ -246,7 +245,7 @@ static void VmbusProcessChannelEvent(void *context)
struct vmbus_channel *channel;
u32 relId = (u32)(unsigned long)context;
- ASSERT(relId > 0);
+ /* ASSERT(relId > 0); */
/*
* Find the channel based on this relid and invokes the
@@ -255,18 +254,18 @@ static void VmbusProcessChannelEvent(void *context)
channel = GetChannelFromRelId(relId);
if (channel) {
- VmbusChannelOnChannelEvent(channel);
+ vmbus_onchannel_event(channel);
/*
* WorkQueueQueueWorkItem(channel->dataWorkQueue,
- * VmbusChannelOnChannelEvent,
- * (void*)channel);
+ * vmbus_onchannel_event,
+ * (void*)channel);
*/
} else {
DPRINT_ERR(VMBUS, "channel not found for relid - %d.", relId);
}
}
-/**
+/*
* VmbusOnEvents - Handler for events
*/
void VmbusOnEvents(void)
@@ -277,8 +276,6 @@ void VmbusOnEvents(void)
int relid;
u32 *recvInterruptPage = gVmbusConnection.RecvInterruptPage;
- DPRINT_ENTER(VMBUS);
-
/* Check events */
if (recvInterruptPage) {
for (dword = 0; dword < maxdword; dword++) {
@@ -302,12 +299,10 @@ void VmbusOnEvents(void)
}
}
}
- DPRINT_EXIT(VMBUS);
-
return;
}
-/**
+/*
* VmbusPostMessage - Send a msg on the vmbus's message connection
*/
int VmbusPostMessage(void *buffer, size_t bufferLen)
@@ -319,23 +314,15 @@ int VmbusPostMessage(void *buffer, size_t bufferLen)
return HvPostMessage(connId, 1, buffer, bufferLen);
}
-/**
+/*
* VmbusSetEvent - Send an event notification to the parent
*/
int VmbusSetEvent(u32 childRelId)
{
- int ret = 0;
-
- DPRINT_ENTER(VMBUS);
-
/* Each u32 represents 32 channels */
set_bit(childRelId & 31,
(unsigned long *)gVmbusConnection.SendInterruptPage +
(childRelId >> 5));
- ret = HvSignalEvent();
-
- DPRINT_EXIT(VMBUS);
-
- return ret;
+ return HvSignalEvent();
}
diff --git a/drivers/staging/hv/Hv.c b/drivers/staging/hv/hv.c
index c2809f2..86b1ddd 100644
--- a/drivers/staging/hv/Hv.c
+++ b/drivers/staging/hv/hv.c
@@ -21,10 +21,11 @@
*/
#include <linux/kernel.h>
#include <linux/mm.h>
+#include <linux/slab.h>
#include <linux/vmalloc.h>
#include "osd.h"
#include "logging.h"
-#include "VmbusPrivate.h"
+#include "vmbus_private.h"
/* The one and only */
struct hv_context gHvContext = {
@@ -34,7 +35,7 @@ struct hv_context gHvContext = {
.SignalEventBuffer = NULL,
};
-/**
+/*
* HvQueryHypervisorPresence - Query the cpuid for presense of windows hypervisor
*/
static int HvQueryHypervisorPresence(void)
@@ -55,7 +56,7 @@ static int HvQueryHypervisorPresence(void)
return ecx & HV_PRESENT_BIT;
}
-/**
+/*
* HvQueryHypervisorInfo - Get version info of the windows hypervisor
*/
static int HvQueryHypervisorInfo(void)
@@ -124,7 +125,7 @@ static int HvQueryHypervisorInfo(void)
return maxLeaf;
}
-/**
+/*
* HvDoHypercall - Invoke the specified hypercall
*/
static u64 HvDoHypercall(u64 Control, void *Input, void *Output)
@@ -179,7 +180,7 @@ static u64 HvDoHypercall(u64 Control, void *Input, void *Output)
#endif /* !x86_64 */
}
-/**
+/*
* HvInit - Main initialization routine.
*
* This routine must be called before any other routines in here are called
@@ -191,8 +192,6 @@ int HvInit(void)
union hv_x64_msr_hypercall_contents hypercallMsr;
void *virtAddr = NULL;
- DPRINT_ENTER(VMBUS);
-
memset(gHvContext.synICEventPage, 0, sizeof(void *) * MAX_NUM_CPUS);
memset(gHvContext.synICMessagePage, 0, sizeof(void *) * MAX_NUM_CPUS);
@@ -208,50 +207,51 @@ int HvInit(void)
/* HvQueryHypervisorFeatures(maxLeaf); */
/*
- * Determine if we are running on xenlinux (ie x2v shim) or native
- * linux
+ * We only support running on top of Hyper-V
*/
rdmsrl(HV_X64_MSR_GUEST_OS_ID, gHvContext.GuestId);
- if (gHvContext.GuestId == 0) {
- /* Write our OS info */
- wrmsrl(HV_X64_MSR_GUEST_OS_ID, HV_LINUX_GUEST_ID);
- gHvContext.GuestId = HV_LINUX_GUEST_ID;
+
+ if (gHvContext.GuestId != 0) {
+ DPRINT_ERR(VMBUS, "Unknown guest id (0x%llx)!!",
+ gHvContext.GuestId);
+ goto Cleanup;
}
+ /* Write our OS info */
+ wrmsrl(HV_X64_MSR_GUEST_OS_ID, HV_LINUX_GUEST_ID);
+ gHvContext.GuestId = HV_LINUX_GUEST_ID;
+
/* See if the hypercall page is already set */
rdmsrl(HV_X64_MSR_HYPERCALL, hypercallMsr.AsUINT64);
- if (gHvContext.GuestId == HV_LINUX_GUEST_ID) {
- /* Allocate the hypercall page memory */
- /* virtAddr = osd_PageAlloc(1); */
- virtAddr = osd_VirtualAllocExec(PAGE_SIZE);
-
- if (!virtAddr) {
- DPRINT_ERR(VMBUS,
- "unable to allocate hypercall page!!");
- goto Cleanup;
- }
- hypercallMsr.Enable = 1;
- /* hypercallMsr.GuestPhysicalAddress =
- * virt_to_phys(virtAddr) >> PAGE_SHIFT; */
- hypercallMsr.GuestPhysicalAddress = vmalloc_to_pfn(virtAddr);
- wrmsrl(HV_X64_MSR_HYPERCALL, hypercallMsr.AsUINT64);
+ /*
+ * Allocate the hypercall page memory
+ * virtAddr = osd_PageAlloc(1);
+ */
+ virtAddr = osd_VirtualAllocExec(PAGE_SIZE);
- /* Confirm that hypercall page did get setup. */
- hypercallMsr.AsUINT64 = 0;
- rdmsrl(HV_X64_MSR_HYPERCALL, hypercallMsr.AsUINT64);
- if (!hypercallMsr.Enable) {
- DPRINT_ERR(VMBUS, "unable to set hypercall page!!");
- goto Cleanup;
- }
+ if (!virtAddr) {
+ DPRINT_ERR(VMBUS,
+ "unable to allocate hypercall page!!");
+ goto Cleanup;
+ }
- gHvContext.HypercallPage = virtAddr;
- } else {
- DPRINT_ERR(VMBUS, "Unknown guest id (0x%llx)!!",
- gHvContext.GuestId);
+ hypercallMsr.Enable = 1;
+
+ hypercallMsr.GuestPhysicalAddress = vmalloc_to_pfn(virtAddr);
+ wrmsrl(HV_X64_MSR_HYPERCALL, hypercallMsr.AsUINT64);
+
+ /* Confirm that hypercall page did get setup. */
+ hypercallMsr.AsUINT64 = 0;
+ rdmsrl(HV_X64_MSR_HYPERCALL, hypercallMsr.AsUINT64);
+
+ if (!hypercallMsr.Enable) {
+ DPRINT_ERR(VMBUS, "unable to set hypercall page!!");
goto Cleanup;
}
+ gHvContext.HypercallPage = virtAddr;
+
DPRINT_INFO(VMBUS, "Hypercall page VA=%p, PA=0x%0llx",
gHvContext.HypercallPage,
(u64)hypercallMsr.GuestPhysicalAddress << PAGE_SHIFT);
@@ -273,10 +273,6 @@ int HvInit(void)
gHvContext.SignalEventParam->FlagNumber = 0;
gHvContext.SignalEventParam->RsvdZ = 0;
- /* DPRINT_DBG(VMBUS, "My id %llu", HvGetCurrentPartitionId()); */
-
- DPRINT_EXIT(VMBUS);
-
return ret;
Cleanup:
@@ -289,12 +285,10 @@ Cleanup:
vfree(virtAddr);
}
ret = -1;
- DPRINT_EXIT(VMBUS);
-
return ret;
}
-/**
+/*
* HvCleanup - Cleanup routine.
*
* This routine is called normally during driver unloading or exiting.
@@ -303,28 +297,19 @@ void HvCleanup(void)
{
union hv_x64_msr_hypercall_contents hypercallMsr;
- DPRINT_ENTER(VMBUS);
-
- if (gHvContext.SignalEventBuffer) {
- gHvContext.SignalEventBuffer = NULL;
- gHvContext.SignalEventParam = NULL;
- kfree(gHvContext.SignalEventBuffer);
- }
+ kfree(gHvContext.SignalEventBuffer);
+ gHvContext.SignalEventBuffer = NULL;
+ gHvContext.SignalEventParam = NULL;
- if (gHvContext.GuestId == HV_LINUX_GUEST_ID) {
- if (gHvContext.HypercallPage) {
- hypercallMsr.AsUINT64 = 0;
- wrmsrl(HV_X64_MSR_HYPERCALL, hypercallMsr.AsUINT64);
- vfree(gHvContext.HypercallPage);
- gHvContext.HypercallPage = NULL;
- }
+ if (gHvContext.HypercallPage) {
+ hypercallMsr.AsUINT64 = 0;
+ wrmsrl(HV_X64_MSR_HYPERCALL, hypercallMsr.AsUINT64);
+ vfree(gHvContext.HypercallPage);
+ gHvContext.HypercallPage = NULL;
}
-
- DPRINT_EXIT(VMBUS);
-
}
-/**
+/*
* HvPostMessage - Post a message using the hypervisor message IPC.
*
* This involves a hypercall.
@@ -365,7 +350,7 @@ u16 HvPostMessage(union hv_connection_id connectionId,
}
-/**
+/*
* HvSignalEvent - Signal an event on the specified connection using the hypervisor event IPC.
*
* This involves a hypercall.
@@ -379,7 +364,7 @@ u16 HvSignalEvent(void)
return status;
}
-/**
+/*
* HvSynicInit - Initialize the Synthethic Interrupt Controller.
*
* If it is already initialized by another entity (ie x2v shim), we need to
@@ -393,87 +378,53 @@ void HvSynicInit(void *irqarg)
union hv_synic_siefp siefp;
union hv_synic_sint sharedSint;
union hv_synic_scontrol sctrl;
- u64 guestID;
+
u32 irqVector = *((u32 *)(irqarg));
int cpu = smp_processor_id();
- DPRINT_ENTER(VMBUS);
-
- if (!gHvContext.HypercallPage) {
- DPRINT_EXIT(VMBUS);
+ if (!gHvContext.HypercallPage)
return;
- }
/* Check the version */
rdmsrl(HV_X64_MSR_SVERSION, version);
DPRINT_INFO(VMBUS, "SynIC version: %llx", version);
- /* TODO: Handle SMP */
- if (gHvContext.GuestId == HV_XENLINUX_GUEST_ID) {
- DPRINT_INFO(VMBUS, "Skipping SIMP and SIEFP setup since "
- "it is already set.");
-
- rdmsrl(HV_X64_MSR_SIMP, simp.AsUINT64);
- rdmsrl(HV_X64_MSR_SIEFP, siefp.AsUINT64);
-
- DPRINT_DBG(VMBUS, "Simp: %llx, Sifep: %llx",
- simp.AsUINT64, siefp.AsUINT64);
-
- /*
- * Determine if we are running on xenlinux (ie x2v shim) or
- * native linux
- */
- rdmsrl(HV_X64_MSR_GUEST_OS_ID, guestID);
- if (guestID == HV_LINUX_GUEST_ID) {
- gHvContext.synICMessagePage[cpu] =
- phys_to_virt(simp.BaseSimpGpa << PAGE_SHIFT);
- gHvContext.synICEventPage[cpu] =
- phys_to_virt(siefp.BaseSiefpGpa << PAGE_SHIFT);
- } else {
- DPRINT_ERR(VMBUS, "unknown guest id!!");
- goto Cleanup;
- }
- DPRINT_DBG(VMBUS, "MAPPED: Simp: %p, Sifep: %p",
- gHvContext.synICMessagePage[cpu],
- gHvContext.synICEventPage[cpu]);
- } else {
- gHvContext.synICMessagePage[cpu] = (void *)get_zeroed_page(GFP_ATOMIC);
- if (gHvContext.synICMessagePage[cpu] == NULL) {
- DPRINT_ERR(VMBUS,
- "unable to allocate SYNIC message page!!");
- goto Cleanup;
- }
+ gHvContext.synICMessagePage[cpu] = (void *)get_zeroed_page(GFP_ATOMIC);
- gHvContext.synICEventPage[cpu] = (void *)get_zeroed_page(GFP_ATOMIC);
- if (gHvContext.synICEventPage[cpu] == NULL) {
- DPRINT_ERR(VMBUS,
- "unable to allocate SYNIC event page!!");
- goto Cleanup;
- }
+ if (gHvContext.synICMessagePage[cpu] == NULL) {
+ DPRINT_ERR(VMBUS,
+ "unable to allocate SYNIC message page!!");
+ goto Cleanup;
+ }
- /* Setup the Synic's message page */
- rdmsrl(HV_X64_MSR_SIMP, simp.AsUINT64);
- simp.SimpEnabled = 1;
- simp.BaseSimpGpa = virt_to_phys(gHvContext.synICMessagePage[cpu])
- >> PAGE_SHIFT;
+ gHvContext.synICEventPage[cpu] = (void *)get_zeroed_page(GFP_ATOMIC);
- DPRINT_DBG(VMBUS, "HV_X64_MSR_SIMP msr set to: %llx",
- simp.AsUINT64);
+ if (gHvContext.synICEventPage[cpu] == NULL) {
+ DPRINT_ERR(VMBUS,
+ "unable to allocate SYNIC event page!!");
+ goto Cleanup;
+ }
- wrmsrl(HV_X64_MSR_SIMP, simp.AsUINT64);
+ /* Setup the Synic's message page */
+ rdmsrl(HV_X64_MSR_SIMP, simp.AsUINT64);
+ simp.SimpEnabled = 1;
+ simp.BaseSimpGpa = virt_to_phys(gHvContext.synICMessagePage[cpu])
+ >> PAGE_SHIFT;
- /* Setup the Synic's event page */
- rdmsrl(HV_X64_MSR_SIEFP, siefp.AsUINT64);
- siefp.SiefpEnabled = 1;
- siefp.BaseSiefpGpa = virt_to_phys(gHvContext.synICEventPage[cpu])
- >> PAGE_SHIFT;
+ DPRINT_DBG(VMBUS, "HV_X64_MSR_SIMP msr set to: %llx", simp.AsUINT64);
- DPRINT_DBG(VMBUS, "HV_X64_MSR_SIEFP msr set to: %llx",
- siefp.AsUINT64);
+ wrmsrl(HV_X64_MSR_SIMP, simp.AsUINT64);
- wrmsrl(HV_X64_MSR_SIEFP, siefp.AsUINT64);
- }
+ /* Setup the Synic's event page */
+ rdmsrl(HV_X64_MSR_SIEFP, siefp.AsUINT64);
+ siefp.SiefpEnabled = 1;
+ siefp.BaseSiefpGpa = virt_to_phys(gHvContext.synICEventPage[cpu])
+ >> PAGE_SHIFT;
+
+ DPRINT_DBG(VMBUS, "HV_X64_MSR_SIEFP msr set to: %llx", siefp.AsUINT64);
+
+ wrmsrl(HV_X64_MSR_SIEFP, siefp.AsUINT64);
/* Setup the interception SINT. */
/* wrmsrl((HV_X64_MSR_SINT0 + HV_SYNIC_INTERCEPTION_SINT_INDEX), */
@@ -499,25 +450,18 @@ void HvSynicInit(void *irqarg)
wrmsrl(HV_X64_MSR_SCONTROL, sctrl.AsUINT64);
gHvContext.SynICInitialized = true;
-
- DPRINT_EXIT(VMBUS);
-
return;
Cleanup:
- if (gHvContext.GuestId == HV_LINUX_GUEST_ID) {
- if (gHvContext.synICEventPage[cpu])
- osd_PageFree(gHvContext.synICEventPage[cpu], 1);
-
- if (gHvContext.synICMessagePage[cpu])
- osd_PageFree(gHvContext.synICMessagePage[cpu], 1);
- }
+ if (gHvContext.synICEventPage[cpu])
+ osd_PageFree(gHvContext.synICEventPage[cpu], 1);
- DPRINT_EXIT(VMBUS);
+ if (gHvContext.synICMessagePage[cpu])
+ osd_PageFree(gHvContext.synICMessagePage[cpu], 1);
return;
}
-/**
+/*
* HvSynicCleanup - Cleanup routine for HvSynicInit().
*/
void HvSynicCleanup(void *arg)
@@ -527,12 +471,8 @@ void HvSynicCleanup(void *arg)
union hv_synic_siefp siefp;
int cpu = smp_processor_id();
- DPRINT_ENTER(VMBUS);
-
- if (!gHvContext.SynICInitialized) {
- DPRINT_EXIT(VMBUS);
+ if (!gHvContext.SynICInitialized)
return;
- }
rdmsrl(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, sharedSint.AsUINT64);
@@ -542,27 +482,18 @@ void HvSynicCleanup(void *arg)
/* Disable the interrupt */
wrmsrl(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, sharedSint.AsUINT64);
- /*
- * Disable and free the resources only if we are running as
- * native linux since in xenlinux, we are sharing the
- * resources with the x2v shim
- */
- if (gHvContext.GuestId == HV_LINUX_GUEST_ID) {
- rdmsrl(HV_X64_MSR_SIMP, simp.AsUINT64);
- simp.SimpEnabled = 0;
- simp.BaseSimpGpa = 0;
-
- wrmsrl(HV_X64_MSR_SIMP, simp.AsUINT64);
+ rdmsrl(HV_X64_MSR_SIMP, simp.AsUINT64);
+ simp.SimpEnabled = 0;
+ simp.BaseSimpGpa = 0;
- rdmsrl(HV_X64_MSR_SIEFP, siefp.AsUINT64);
- siefp.SiefpEnabled = 0;
- siefp.BaseSiefpGpa = 0;
+ wrmsrl(HV_X64_MSR_SIMP, simp.AsUINT64);
- wrmsrl(HV_X64_MSR_SIEFP, siefp.AsUINT64);
+ rdmsrl(HV_X64_MSR_SIEFP, siefp.AsUINT64);
+ siefp.SiefpEnabled = 0;
+ siefp.BaseSiefpGpa = 0;
- osd_PageFree(gHvContext.synICMessagePage[cpu], 1);
- osd_PageFree(gHvContext.synICEventPage[cpu], 1);
- }
+ wrmsrl(HV_X64_MSR_SIEFP, siefp.AsUINT64);
- DPRINT_EXIT(VMBUS);
+ osd_PageFree(gHvContext.synICMessagePage[cpu], 1);
+ osd_PageFree(gHvContext.synICEventPage[cpu], 1);
}
diff --git a/drivers/staging/hv/Hv.h b/drivers/staging/hv/hv.h
index fce4b5c..41f5ebb 100644
--- a/drivers/staging/hv/Hv.h
+++ b/drivers/staging/hv/hv.h
@@ -41,11 +41,6 @@ enum {
#define HV_PRESENT_BIT 0x80000000
-#define HV_XENLINUX_GUEST_ID_LO 0x00000000
-#define HV_XENLINUX_GUEST_ID_HI 0x0B00B135
-#define HV_XENLINUX_GUEST_ID (((u64)HV_XENLINUX_GUEST_ID_HI << 32) \
- | HV_XENLINUX_GUEST_ID_LO)
-
#define HV_LINUX_GUEST_ID_LO 0x00000000
#define HV_LINUX_GUEST_ID_HI 0xB16B00B5
#define HV_LINUX_GUEST_ID (((u64)HV_LINUX_GUEST_ID_HI << 32) | \
@@ -102,8 +97,9 @@ struct hv_input_signal_event_buffer {
};
struct hv_context {
- /* XenLinux or native Linux. If XenLinux, the hypercall and synic pages
- * has already been initialized */
+ /* We only support running on top of Hyper-V
+ * So at this point this really can only contain the Hyper-V ID
+ */
u64 GuestId;
void *HypercallPage;
diff --git a/drivers/staging/hv/hv_timesource.c b/drivers/staging/hv/hv_timesource.c
new file mode 100644
index 0000000..a7ee533
--- /dev/null
+++ b/drivers/staging/hv/hv_timesource.c
@@ -0,0 +1,101 @@
+/*
+ * A clocksource for Linux running on HyperV.
+ *
+ *
+ * Copyright (C) 2010, Novell, Inc.
+ * Author : K. Y. Srinivasan <ksrinivasan@novell.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <linux/version.h>
+#include <linux/clocksource.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/dmi.h>
+#include <asm/hyperv.h>
+#include <asm/mshyperv.h>
+#include <asm/hypervisor.h>
+
+#define HV_CLOCK_SHIFT 22
+
+static cycle_t read_hv_clock(struct clocksource *arg)
+{
+ cycle_t current_tick;
+ /*
+ * Read the partition counter to get the current tick count. This count
+ * is set to 0 when the partition is created and is incremented in
+ * 100 nanosecond units.
+ */
+ rdmsrl(HV_X64_MSR_TIME_REF_COUNT, current_tick);
+ return current_tick;
+}
+
+static struct clocksource hyperv_cs = {
+ .name = "hyperv_clocksource",
+ .rating = 400, /* use this when running on Hyperv*/
+ .read = read_hv_clock,
+ .mask = CLOCKSOURCE_MASK(64),
+ /*
+ * The time ref counter in HyperV is in 100ns units.
+ * The definition of mult is:
+ * mult/2^shift = ns/cyc = 100
+ * mult = (100 << shift)
+ */
+ .mult = (100 << HV_CLOCK_SHIFT),
+ .shift = HV_CLOCK_SHIFT,
+};
+
+static const struct dmi_system_id __initconst
+hv_timesource_dmi_table[] __maybe_unused = {
+ {
+ .ident = "Hyper-V",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Virtual Machine"),
+ DMI_MATCH(DMI_BOARD_NAME, "Virtual Machine"),
+ },
+ },
+ { },
+};
+MODULE_DEVICE_TABLE(dmi, hv_timesource_dmi_table);
+
+static const struct pci_device_id __initconst
+hv_timesource_pci_table[] __maybe_unused = {
+ { PCI_DEVICE(0x1414, 0x5353) }, /* VGA compatible controller */
+ { 0 }
+};
+MODULE_DEVICE_TABLE(pci, hv_timesource_pci_table);
+
+
+static int __init init_hv_clocksource(void)
+{
+ if ((x86_hyper != &x86_hyper_ms_hyperv) ||
+ !(ms_hyperv.features & HV_X64_MSR_TIME_REF_COUNT_AVAILABLE))
+ return -ENODEV;
+
+ if (!dmi_check_system(hv_timesource_dmi_table))
+ return -ENODEV;
+
+ printk(KERN_INFO "Registering HyperV clock source\n");
+ return clocksource_register(&hyperv_cs);
+}
+
+module_init(init_hv_clocksource);
+MODULE_DESCRIPTION("HyperV based clocksource");
+MODULE_AUTHOR("K. Y. Srinivasan <ksrinivasan@novell.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/hv/hv_utils.c b/drivers/staging/hv/hv_utils.c
new file mode 100644
index 0000000..a99e900
--- /dev/null
+++ b/drivers/staging/hv/hv_utils.c
@@ -0,0 +1,308 @@
+/*
+ * Copyright (c) 2010, Microsoft Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * Authors:
+ * Haiyang Zhang <haiyangz@microsoft.com>
+ * Hank Janssen <hjanssen@microsoft.com>
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/sysctl.h>
+#include <linux/reboot.h>
+#include <linux/dmi.h>
+#include <linux/pci.h>
+
+#include "logging.h"
+#include "osd.h"
+#include "vmbus.h"
+#include "vmbus_packet_format.h"
+#include "vmbus_channel_interface.h"
+#include "version_info.h"
+#include "channel.h"
+#include "vmbus_private.h"
+#include "vmbus_api.h"
+#include "utils.h"
+
+
+static void shutdown_onchannelcallback(void *context)
+{
+ struct vmbus_channel *channel = context;
+ u8 *buf;
+ u32 buflen, recvlen;
+ u64 requestid;
+ u8 execute_shutdown = false;
+
+ struct shutdown_msg_data *shutdown_msg;
+
+ struct icmsg_hdr *icmsghdrp;
+ struct icmsg_negotiate *negop = NULL;
+
+ buflen = PAGE_SIZE;
+ buf = kmalloc(buflen, GFP_ATOMIC);
+
+ vmbus_recvpacket(channel, buf, buflen, &recvlen, &requestid);
+
+ if (recvlen > 0) {
+ DPRINT_DBG(VMBUS, "shutdown packet: len=%d, requestid=%lld",
+ recvlen, requestid);
+
+ icmsghdrp = (struct icmsg_hdr *)&buf[
+ sizeof(struct vmbuspipe_hdr)];
+
+ if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
+ prep_negotiate_resp(icmsghdrp, negop, buf);
+ } else {
+ shutdown_msg = (struct shutdown_msg_data *)&buf[
+ sizeof(struct vmbuspipe_hdr) +
+ sizeof(struct icmsg_hdr)];
+
+ switch (shutdown_msg->flags) {
+ case 0:
+ case 1:
+ icmsghdrp->status = HV_S_OK;
+ execute_shutdown = true;
+
+ DPRINT_INFO(VMBUS, "Shutdown request received -"
+ " gracefull shutdown initiated");
+ break;
+ default:
+ icmsghdrp->status = HV_E_FAIL;
+ execute_shutdown = false;
+
+ DPRINT_INFO(VMBUS, "Shutdown request received -"
+ " Invalid request");
+ break;
+ };
+ }
+
+ icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION
+ | ICMSGHDRFLAG_RESPONSE;
+
+ vmbus_sendpacket(channel, buf,
+ recvlen, requestid,
+ VmbusPacketTypeDataInBand, 0);
+ }
+
+ kfree(buf);
+
+ if (execute_shutdown == true)
+ orderly_poweroff(false);
+}
+
+/*
+ * Set guest time to host UTC time.
+ */
+static inline void do_adj_guesttime(u64 hosttime)
+{
+ s64 host_tns;
+ struct timespec host_ts;
+
+ host_tns = (hosttime - WLTIMEDELTA) * 100;
+ host_ts = ns_to_timespec(host_tns);
+
+ do_settimeofday(&host_ts);
+}
+
+/*
+ * Synchronize time with host after reboot, restore, etc.
+ *
+ * ICTIMESYNCFLAG_SYNC flag bit indicates reboot, restore events of the VM.
+ * After reboot the flag ICTIMESYNCFLAG_SYNC is included in the first time
+ * message after the timesync channel is opened. Since the hv_utils module is
+ * loaded after hv_vmbus, the first message is usually missed. The other
+ * thing is, systime is automatically set to emulated hardware clock which may
+ * not be UTC time or in the same time zone. So, to override these effects, we
+ * use the first 50 time samples for initial system time setting.
+ */
+static inline void adj_guesttime(u64 hosttime, u8 flags)
+{
+ static s32 scnt = 50;
+
+ if ((flags & ICTIMESYNCFLAG_SYNC) != 0) {
+ do_adj_guesttime(hosttime);
+ return;
+ }
+
+ if ((flags & ICTIMESYNCFLAG_SAMPLE) != 0 && scnt > 0) {
+ scnt--;
+ do_adj_guesttime(hosttime);
+ }
+}
+
+/*
+ * Time Sync Channel message handler.
+ */
+static void timesync_onchannelcallback(void *context)
+{
+ struct vmbus_channel *channel = context;
+ u8 *buf;
+ u32 buflen, recvlen;
+ u64 requestid;
+ struct icmsg_hdr *icmsghdrp;
+ struct ictimesync_data *timedatap;
+
+ buflen = PAGE_SIZE;
+ buf = kmalloc(buflen, GFP_ATOMIC);
+
+ vmbus_recvpacket(channel, buf, buflen, &recvlen, &requestid);
+
+ if (recvlen > 0) {
+ DPRINT_DBG(VMBUS, "timesync packet: recvlen=%d, requestid=%lld",
+ recvlen, requestid);
+
+ icmsghdrp = (struct icmsg_hdr *)&buf[
+ sizeof(struct vmbuspipe_hdr)];
+
+ if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
+ prep_negotiate_resp(icmsghdrp, NULL, buf);
+ } else {
+ timedatap = (struct ictimesync_data *)&buf[
+ sizeof(struct vmbuspipe_hdr) +
+ sizeof(struct icmsg_hdr)];
+ adj_guesttime(timedatap->parenttime, timedatap->flags);
+ }
+
+ icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION
+ | ICMSGHDRFLAG_RESPONSE;
+
+ vmbus_sendpacket(channel, buf,
+ recvlen, requestid,
+ VmbusPacketTypeDataInBand, 0);
+ }
+
+ kfree(buf);
+}
+
+/*
+ * Heartbeat functionality.
+ * Every two seconds, Hyper-V send us a heartbeat request message.
+ * we respond to this message, and Hyper-V knows we are alive.
+ */
+static void heartbeat_onchannelcallback(void *context)
+{
+ struct vmbus_channel *channel = context;
+ u8 *buf;
+ u32 buflen, recvlen;
+ u64 requestid;
+ struct icmsg_hdr *icmsghdrp;
+ struct heartbeat_msg_data *heartbeat_msg;
+
+ buflen = PAGE_SIZE;
+ buf = kmalloc(buflen, GFP_ATOMIC);
+
+ vmbus_recvpacket(channel, buf, buflen, &recvlen, &requestid);
+
+ if (recvlen > 0) {
+ DPRINT_DBG(VMBUS, "heartbeat packet: len=%d, requestid=%lld",
+ recvlen, requestid);
+
+ icmsghdrp = (struct icmsg_hdr *)&buf[
+ sizeof(struct vmbuspipe_hdr)];
+
+ if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
+ prep_negotiate_resp(icmsghdrp, NULL, buf);
+ } else {
+ heartbeat_msg = (struct heartbeat_msg_data *)&buf[
+ sizeof(struct vmbuspipe_hdr) +
+ sizeof(struct icmsg_hdr)];
+
+ DPRINT_DBG(VMBUS, "heartbeat seq = %lld",
+ heartbeat_msg->seq_num);
+
+ heartbeat_msg->seq_num += 1;
+ }
+
+ icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION
+ | ICMSGHDRFLAG_RESPONSE;
+
+ vmbus_sendpacket(channel, buf,
+ recvlen, requestid,
+ VmbusPacketTypeDataInBand, 0);
+ }
+
+ kfree(buf);
+}
+
+static const struct pci_device_id __initconst
+hv_utils_pci_table[] __maybe_unused = {
+ { PCI_DEVICE(0x1414, 0x5353) }, /* Hyper-V emulated VGA controller */
+ { 0 }
+};
+MODULE_DEVICE_TABLE(pci, hv_utils_pci_table);
+
+
+static const struct dmi_system_id __initconst
+hv_utils_dmi_table[] __maybe_unused = {
+ {
+ .ident = "Hyper-V",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Virtual Machine"),
+ DMI_MATCH(DMI_BOARD_NAME, "Virtual Machine"),
+ },
+ },
+ { },
+};
+MODULE_DEVICE_TABLE(dmi, hv_utils_dmi_table);
+
+
+static int __init init_hyperv_utils(void)
+{
+ printk(KERN_INFO "Registering HyperV Utility Driver\n");
+
+ if (!dmi_check_system(hv_utils_dmi_table))
+ return -ENODEV;
+
+ hv_cb_utils[HV_SHUTDOWN_MSG].channel->OnChannelCallback =
+ &shutdown_onchannelcallback;
+ hv_cb_utils[HV_SHUTDOWN_MSG].callback = &shutdown_onchannelcallback;
+
+ hv_cb_utils[HV_TIMESYNC_MSG].channel->OnChannelCallback =
+ &timesync_onchannelcallback;
+ hv_cb_utils[HV_TIMESYNC_MSG].callback = &timesync_onchannelcallback;
+
+ hv_cb_utils[HV_HEARTBEAT_MSG].channel->OnChannelCallback =
+ &heartbeat_onchannelcallback;
+ hv_cb_utils[HV_HEARTBEAT_MSG].callback = &heartbeat_onchannelcallback;
+
+ return 0;
+}
+
+static void exit_hyperv_utils(void)
+{
+ printk(KERN_INFO "De-Registered HyperV Utility Driver\n");
+
+ hv_cb_utils[HV_SHUTDOWN_MSG].channel->OnChannelCallback =
+ &chn_cb_negotiate;
+ hv_cb_utils[HV_SHUTDOWN_MSG].callback = &chn_cb_negotiate;
+
+ hv_cb_utils[HV_TIMESYNC_MSG].channel->OnChannelCallback =
+ &chn_cb_negotiate;
+ hv_cb_utils[HV_TIMESYNC_MSG].callback = &chn_cb_negotiate;
+
+ hv_cb_utils[HV_HEARTBEAT_MSG].channel->OnChannelCallback =
+ &chn_cb_negotiate;
+ hv_cb_utils[HV_HEARTBEAT_MSG].callback = &chn_cb_negotiate;
+}
+
+module_init(init_hyperv_utils);
+module_exit(exit_hyperv_utils);
+
+MODULE_DESCRIPTION("Hyper-V Utilities");
+MODULE_VERSION(HV_DRV_VERSION);
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/hv/logging.h b/drivers/staging/hv/logging.h
index 9e55617..20d4d12 100644
--- a/drivers/staging/hv/logging.h
+++ b/drivers/staging/hv/logging.h
@@ -61,13 +61,6 @@
extern unsigned int vmbus_loglevel;
-#define ASSERT(expr) \
- if (!(expr)) { \
- printk(KERN_CRIT "Assertion failed! %s,%s,%s,line=%d\n", \
- #expr, __FILE__, __func__, __LINE__); \
- __asm__ __volatile__("int3"); \
- }
-
#define DPRINT(mod, lvl, fmt, args...) do {\
if ((mod & (HIWORD(vmbus_loglevel))) && \
(lvl <= LOWORD(vmbus_loglevel))) \
@@ -99,21 +92,4 @@ extern unsigned int vmbus_loglevel;
__func__, ## args);\
} while (0)
-#ifdef DEBUG
-#define DPRINT_ENTER(mod) do {\
- if ((mod & (HIWORD(vmbus_loglevel))) && \
- (DEBUG_LVL_ENTEREXIT <= LOWORD(vmbus_loglevel))) \
- printk(KERN_DEBUG "["#mod"]: %s() enter\n", __func__);\
- } while (0)
-
-#define DPRINT_EXIT(mod) do {\
- if ((mod & (HIWORD(vmbus_loglevel))) && \
- (DEBUG_LVL_ENTEREXIT <= LOWORD(vmbus_loglevel))) \
- printk(KERN_DEBUG "["#mod"]: %s() exit\n", __func__);\
- } while (0)
-#else
-#define DPRINT_ENTER(mod)
-#define DPRINT_EXIT(mod)
-#endif
-
#endif /* _LOGGING_H_ */
diff --git a/drivers/staging/hv/NetVsc.c b/drivers/staging/hv/netvsc.c
index 1c717f9..4c2632c 100644
--- a/drivers/staging/hv/NetVsc.c
+++ b/drivers/staging/hv/netvsc.c
@@ -22,10 +22,12 @@
#include <linux/mm.h>
#include <linux/delay.h>
#include <linux/io.h>
+#include <linux/slab.h>
#include "osd.h"
#include "logging.h"
-#include "NetVsc.h"
-#include "RndisFilter.h"
+#include "netvsc.h"
+#include "rndis_filter.h"
+#include "channel.h"
/* Globals */
@@ -91,7 +93,7 @@ static struct netvsc_device *AllocNetDevice(struct hv_device *Device)
static void FreeNetDevice(struct netvsc_device *Device)
{
- ASSERT(atomic_read(&Device->RefCount) == 0);
+ WARN_ON(atomic_read(&Device->RefCount) == 0);
Device->Device->Extension = NULL;
kfree(Device);
}
@@ -130,7 +132,7 @@ static void PutNetDevice(struct hv_device *Device)
struct netvsc_device *netDevice;
netDevice = Device->Extension;
- ASSERT(netDevice);
+ /* ASSERT(netDevice); */
atomic_dec(&netDevice->RefCount);
}
@@ -166,15 +168,13 @@ static struct netvsc_device *ReleaseInboundNetDevice(struct hv_device *Device)
return netDevice;
}
-/**
+/*
* NetVscInitialize - Main entry point
*/
int NetVscInitialize(struct hv_driver *drv)
{
struct netvsc_driver *driver = (struct netvsc_driver *)drv;
- DPRINT_ENTER(NETVSC);
-
DPRINT_DBG(NETVSC, "sizeof(struct hv_netvsc_packet)=%zd, "
"sizeof(struct nvsp_message)=%zd, "
"sizeof(struct vmtransfer_page_packet_header)=%zd",
@@ -183,14 +183,15 @@ int NetVscInitialize(struct hv_driver *drv)
sizeof(struct vmtransfer_page_packet_header));
/* Make sure we are at least 2 pages since 1 page is used for control */
- ASSERT(driver->RingBufferSize >= (PAGE_SIZE << 1));
+ /* ASSERT(driver->RingBufferSize >= (PAGE_SIZE << 1)); */
drv->name = gDriverName;
memcpy(&drv->deviceType, &gNetVscDeviceType, sizeof(struct hv_guid));
/* Make sure it is set by the caller */
- ASSERT(driver->OnReceiveCallback);
- ASSERT(driver->OnLinkStatusChanged);
+ /* FIXME: These probably should still be tested in some way */
+ /* ASSERT(driver->OnReceiveCallback); */
+ /* ASSERT(driver->OnLinkStatusChanged); */
/* Setup the dispatch table */
driver->Base.OnDeviceAdd = NetVscOnDeviceAdd;
@@ -200,9 +201,6 @@ int NetVscInitialize(struct hv_driver *drv)
driver->OnSend = NetVscOnSend;
RndisFilterInit(driver);
-
- DPRINT_EXIT(NETVSC);
-
return 0;
}
@@ -212,18 +210,15 @@ static int NetVscInitializeReceiveBufferWithNetVsp(struct hv_device *Device)
struct netvsc_device *netDevice;
struct nvsp_message *initPacket;
- DPRINT_ENTER(NETVSC);
-
netDevice = GetOutboundNetDevice(Device);
if (!netDevice) {
DPRINT_ERR(NETVSC, "unable to get net device..."
"device being destroyed?");
- DPRINT_EXIT(NETVSC);
return -1;
}
- ASSERT(netDevice->ReceiveBufferSize > 0);
+ /* ASSERT(netDevice->ReceiveBufferSize > 0); */
/* page-size grandularity */
- ASSERT((netDevice->ReceiveBufferSize & (PAGE_SIZE - 1)) == 0);
+ /* ASSERT((netDevice->ReceiveBufferSize & (PAGE_SIZE - 1)) == 0); */
netDevice->ReceiveBuffer =
osd_PageAlloc(netDevice->ReceiveBufferSize >> PAGE_SHIFT);
@@ -235,8 +230,8 @@ static int NetVscInitializeReceiveBufferWithNetVsp(struct hv_device *Device)
goto Cleanup;
}
/* page-aligned buffer */
- ASSERT(((unsigned long)netDevice->ReceiveBuffer & (PAGE_SIZE - 1)) ==
- 0);
+ /* ASSERT(((unsigned long)netDevice->ReceiveBuffer & (PAGE_SIZE - 1)) == */
+ /* 0); */
DPRINT_INFO(NETVSC, "Establishing receive buffer's GPADL...");
@@ -245,10 +240,9 @@ static int NetVscInitializeReceiveBufferWithNetVsp(struct hv_device *Device)
* channel. Note: This call uses the vmbus connection rather
* than the channel to establish the gpadl handle.
*/
- ret = Device->Driver->VmbusChannelInterface.EstablishGpadl(Device,
- netDevice->ReceiveBuffer,
- netDevice->ReceiveBufferSize,
- &netDevice->ReceiveBufferGpadlHandle);
+ ret = vmbus_establish_gpadl(Device->channel, netDevice->ReceiveBuffer,
+ netDevice->ReceiveBufferSize,
+ &netDevice->ReceiveBufferGpadlHandle);
if (ret != 0) {
DPRINT_ERR(NETVSC,
"unable to establish receive buffer's gpadl");
@@ -269,12 +263,11 @@ static int NetVscInitializeReceiveBufferWithNetVsp(struct hv_device *Device)
initPacket->Messages.Version1Messages.SendReceiveBuffer.Id = NETVSC_RECEIVE_BUFFER_ID;
/* Send the gpadl notification request */
- ret = Device->Driver->VmbusChannelInterface.SendPacket(Device,
- initPacket,
- sizeof(struct nvsp_message),
- (unsigned long)initPacket,
- VmbusPacketTypeDataInBand,
- VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
+ ret = vmbus_sendpacket(Device->channel, initPacket,
+ sizeof(struct nvsp_message),
+ (unsigned long)initPacket,
+ VmbusPacketTypeDataInBand,
+ VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
if (ret != 0) {
DPRINT_ERR(NETVSC,
"unable to send receive buffer's gpadl to netvsp");
@@ -293,8 +286,8 @@ static int NetVscInitializeReceiveBufferWithNetVsp(struct hv_device *Device)
}
/* Parse the response */
- ASSERT(netDevice->ReceiveSectionCount == 0);
- ASSERT(netDevice->ReceiveSections == NULL);
+ /* ASSERT(netDevice->ReceiveSectionCount == 0); */
+ /* ASSERT(netDevice->ReceiveSections == NULL); */
netDevice->ReceiveSectionCount = initPacket->Messages.Version1Messages.SendReceiveBufferComplete.NumSections;
@@ -333,7 +326,6 @@ Cleanup:
Exit:
PutNetDevice(Device);
- DPRINT_EXIT(NETVSC);
return ret;
}
@@ -343,18 +335,19 @@ static int NetVscInitializeSendBufferWithNetVsp(struct hv_device *Device)
struct netvsc_device *netDevice;
struct nvsp_message *initPacket;
- DPRINT_ENTER(NETVSC);
-
netDevice = GetOutboundNetDevice(Device);
if (!netDevice) {
DPRINT_ERR(NETVSC, "unable to get net device..."
"device being destroyed?");
- DPRINT_EXIT(NETVSC);
return -1;
}
- ASSERT(netDevice->SendBufferSize > 0);
+ if (netDevice->SendBufferSize <= 0) {
+ ret = -EINVAL;
+ goto Cleanup;
+ }
+
/* page-size grandularity */
- ASSERT((netDevice->SendBufferSize & (PAGE_SIZE - 1)) == 0);
+ /* ASSERT((netDevice->SendBufferSize & (PAGE_SIZE - 1)) == 0); */
netDevice->SendBuffer =
osd_PageAlloc(netDevice->SendBufferSize >> PAGE_SHIFT);
@@ -365,7 +358,7 @@ static int NetVscInitializeSendBufferWithNetVsp(struct hv_device *Device)
goto Cleanup;
}
/* page-aligned buffer */
- ASSERT(((unsigned long)netDevice->SendBuffer & (PAGE_SIZE - 1)) == 0);
+ /* ASSERT(((unsigned long)netDevice->SendBuffer & (PAGE_SIZE - 1)) == 0); */
DPRINT_INFO(NETVSC, "Establishing send buffer's GPADL...");
@@ -374,10 +367,9 @@ static int NetVscInitializeSendBufferWithNetVsp(struct hv_device *Device)
* channel. Note: This call uses the vmbus connection rather
* than the channel to establish the gpadl handle.
*/
- ret = Device->Driver->VmbusChannelInterface.EstablishGpadl(Device,
- netDevice->SendBuffer,
- netDevice->SendBufferSize,
- &netDevice->SendBufferGpadlHandle);
+ ret = vmbus_establish_gpadl(Device->channel, netDevice->SendBuffer,
+ netDevice->SendBufferSize,
+ &netDevice->SendBufferGpadlHandle);
if (ret != 0) {
DPRINT_ERR(NETVSC, "unable to establish send buffer's gpadl");
goto Cleanup;
@@ -397,11 +389,11 @@ static int NetVscInitializeSendBufferWithNetVsp(struct hv_device *Device)
initPacket->Messages.Version1Messages.SendReceiveBuffer.Id = NETVSC_SEND_BUFFER_ID;
/* Send the gpadl notification request */
- ret = Device->Driver->VmbusChannelInterface.SendPacket(Device,
- initPacket, sizeof(struct nvsp_message),
- (unsigned long)initPacket,
- VmbusPacketTypeDataInBand,
- VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
+ ret = vmbus_sendpacket(Device->channel, initPacket,
+ sizeof(struct nvsp_message),
+ (unsigned long)initPacket,
+ VmbusPacketTypeDataInBand,
+ VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
if (ret != 0) {
DPRINT_ERR(NETVSC,
"unable to send receive buffer's gpadl to netvsp");
@@ -428,7 +420,6 @@ Cleanup:
Exit:
PutNetDevice(Device);
- DPRINT_EXIT(NETVSC);
return ret;
}
@@ -437,8 +428,6 @@ static int NetVscDestroyReceiveBuffer(struct netvsc_device *NetDevice)
struct nvsp_message *revokePacket;
int ret = 0;
- DPRINT_ENTER(NETVSC);
-
/*
* If we got a section count, it means we received a
* SendReceiveBufferComplete msg (ie sent
@@ -456,12 +445,10 @@ static int NetVscDestroyReceiveBuffer(struct netvsc_device *NetDevice)
revokePacket->Header.MessageType = NvspMessage1TypeRevokeReceiveBuffer;
revokePacket->Messages.Version1Messages.RevokeReceiveBuffer.Id = NETVSC_RECEIVE_BUFFER_ID;
- ret = NetDevice->Device->Driver->VmbusChannelInterface.SendPacket(
- NetDevice->Device,
- revokePacket,
- sizeof(struct nvsp_message),
- (unsigned long)revokePacket,
- VmbusPacketTypeDataInBand, 0);
+ ret = vmbus_sendpacket(NetDevice->Device->channel, revokePacket,
+ sizeof(struct nvsp_message),
+ (unsigned long)revokePacket,
+ VmbusPacketTypeDataInBand, 0);
/*
* If we failed here, we might as well return and
* have a leak rather than continue and a bugchk
@@ -469,7 +456,6 @@ static int NetVscDestroyReceiveBuffer(struct netvsc_device *NetDevice)
if (ret != 0) {
DPRINT_ERR(NETVSC, "unable to send revoke receive "
"buffer to netvsp");
- DPRINT_EXIT(NETVSC);
return -1;
}
}
@@ -478,15 +464,13 @@ static int NetVscDestroyReceiveBuffer(struct netvsc_device *NetDevice)
if (NetDevice->ReceiveBufferGpadlHandle) {
DPRINT_INFO(NETVSC, "Tearing down receive buffer's GPADL...");
- ret = NetDevice->Device->Driver->VmbusChannelInterface.TeardownGpadl(
- NetDevice->Device,
- NetDevice->ReceiveBufferGpadlHandle);
+ ret = vmbus_teardown_gpadl(NetDevice->Device->channel,
+ NetDevice->ReceiveBufferGpadlHandle);
/* If we failed here, we might as well return and have a leak rather than continue and a bugchk */
if (ret != 0) {
DPRINT_ERR(NETVSC,
"unable to teardown receive buffer's gpadl");
- DPRINT_EXIT(NETVSC);
return -1;
}
NetDevice->ReceiveBufferGpadlHandle = 0;
@@ -507,8 +491,6 @@ static int NetVscDestroyReceiveBuffer(struct netvsc_device *NetDevice)
NetDevice->ReceiveSections = NULL;
}
- DPRINT_EXIT(NETVSC);
-
return ret;
}
@@ -517,8 +499,6 @@ static int NetVscDestroySendBuffer(struct netvsc_device *NetDevice)
struct nvsp_message *revokePacket;
int ret = 0;
- DPRINT_ENTER(NETVSC);
-
/*
* If we got a section count, it means we received a
* SendReceiveBufferComplete msg (ie sent
@@ -536,11 +516,10 @@ static int NetVscDestroySendBuffer(struct netvsc_device *NetDevice)
revokePacket->Header.MessageType = NvspMessage1TypeRevokeSendBuffer;
revokePacket->Messages.Version1Messages.RevokeSendBuffer.Id = NETVSC_SEND_BUFFER_ID;
- ret = NetDevice->Device->Driver->VmbusChannelInterface.SendPacket(NetDevice->Device,
- revokePacket,
- sizeof(struct nvsp_message),
- (unsigned long)revokePacket,
- VmbusPacketTypeDataInBand, 0);
+ ret = vmbus_sendpacket(NetDevice->Device->channel, revokePacket,
+ sizeof(struct nvsp_message),
+ (unsigned long)revokePacket,
+ VmbusPacketTypeDataInBand, 0);
/*
* If we failed here, we might as well return and have a leak
* rather than continue and a bugchk
@@ -548,7 +527,6 @@ static int NetVscDestroySendBuffer(struct netvsc_device *NetDevice)
if (ret != 0) {
DPRINT_ERR(NETVSC, "unable to send revoke send buffer "
"to netvsp");
- DPRINT_EXIT(NETVSC);
return -1;
}
}
@@ -556,8 +534,8 @@ static int NetVscDestroySendBuffer(struct netvsc_device *NetDevice)
/* Teardown the gpadl on the vsp end */
if (NetDevice->SendBufferGpadlHandle) {
DPRINT_INFO(NETVSC, "Tearing down send buffer's GPADL...");
-
- ret = NetDevice->Device->Driver->VmbusChannelInterface.TeardownGpadl(NetDevice->Device, NetDevice->SendBufferGpadlHandle);
+ ret = vmbus_teardown_gpadl(NetDevice->Device->channel,
+ NetDevice->SendBufferGpadlHandle);
/*
* If we failed here, we might as well return and have a leak
@@ -566,7 +544,6 @@ static int NetVscDestroySendBuffer(struct netvsc_device *NetDevice)
if (ret != 0) {
DPRINT_ERR(NETVSC, "unable to teardown send buffer's "
"gpadl");
- DPRINT_EXIT(NETVSC);
return -1;
}
NetDevice->SendBufferGpadlHandle = 0;
@@ -581,8 +558,6 @@ static int NetVscDestroySendBuffer(struct netvsc_device *NetDevice)
NetDevice->SendBuffer = NULL;
}
- DPRINT_EXIT(NETVSC);
-
return ret;
}
@@ -594,13 +569,10 @@ static int NetVscConnectToVsp(struct hv_device *Device)
struct nvsp_message *initPacket;
int ndisVersion;
- DPRINT_ENTER(NETVSC);
-
netDevice = GetOutboundNetDevice(Device);
if (!netDevice) {
DPRINT_ERR(NETVSC, "unable to get net device..."
"device being destroyed?");
- DPRINT_EXIT(NETVSC);
return -1;
}
@@ -614,12 +586,11 @@ static int NetVscConnectToVsp(struct hv_device *Device)
DPRINT_INFO(NETVSC, "Sending NvspMessageTypeInit...");
/* Send the init request */
- ret = Device->Driver->VmbusChannelInterface.SendPacket(Device,
- initPacket,
- sizeof(struct nvsp_message),
- (unsigned long)initPacket,
- VmbusPacketTypeDataInBand,
- VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
+ ret = vmbus_sendpacket(Device->channel, initPacket,
+ sizeof(struct nvsp_message),
+ (unsigned long)initPacket,
+ VmbusPacketTypeDataInBand,
+ VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
if (ret != 0) {
DPRINT_ERR(NETVSC, "unable to send NvspMessageTypeInit");
@@ -664,11 +635,10 @@ static int NetVscConnectToVsp(struct hv_device *Device)
ndisVersion & 0xFFFF;
/* Send the init request */
- ret = Device->Driver->VmbusChannelInterface.SendPacket(Device,
- initPacket,
- sizeof(struct nvsp_message),
- (unsigned long)initPacket,
- VmbusPacketTypeDataInBand, 0);
+ ret = vmbus_sendpacket(Device->channel, initPacket,
+ sizeof(struct nvsp_message),
+ (unsigned long)initPacket,
+ VmbusPacketTypeDataInBand, 0);
if (ret != 0) {
DPRINT_ERR(NETVSC,
"unable to send NvspMessage1TypeSendNdisVersion");
@@ -690,21 +660,16 @@ static int NetVscConnectToVsp(struct hv_device *Device)
Cleanup:
PutNetDevice(Device);
- DPRINT_EXIT(NETVSC);
return ret;
}
static void NetVscDisconnectFromVsp(struct netvsc_device *NetDevice)
{
- DPRINT_ENTER(NETVSC);
-
NetVscDestroyReceiveBuffer(NetDevice);
NetVscDestroySendBuffer(NetDevice);
-
- DPRINT_EXIT(NETVSC);
}
-/**
+/*
* NetVscOnDeviceAdd - Callback when the device belonging to this driver is added
*/
static int NetVscOnDeviceAdd(struct hv_device *Device, void *AdditionalInfo)
@@ -716,8 +681,6 @@ static int NetVscOnDeviceAdd(struct hv_device *Device, void *AdditionalInfo)
struct netvsc_driver *netDriver =
(struct netvsc_driver *)Device->Driver;
- DPRINT_ENTER(NETVSC);
-
netDevice = AllocNetDevice(Device);
if (!netDevice) {
ret = -1;
@@ -748,14 +711,15 @@ static int NetVscOnDeviceAdd(struct hv_device *Device, void *AdditionalInfo)
&netDevice->ReceivePacketList);
}
netDevice->ChannelInitEvent = osd_WaitEventCreate();
+ if (!netDevice->ChannelInitEvent) {
+ ret = -ENOMEM;
+ goto Cleanup;
+ }
/* Open the channel */
- ret = Device->Driver->VmbusChannelInterface.Open(Device,
- netDriver->RingBufferSize,
- netDriver->RingBufferSize,
- NULL, 0,
- NetVscOnChannelCallback,
- Device);
+ ret = vmbus_open(Device->channel, netDriver->RingBufferSize,
+ netDriver->RingBufferSize, NULL, 0,
+ NetVscOnChannelCallback, Device);
if (ret != 0) {
DPRINT_ERR(NETVSC, "unable to open channel: %d", ret);
@@ -771,18 +735,17 @@ static int NetVscOnDeviceAdd(struct hv_device *Device, void *AdditionalInfo)
if (ret != 0) {
DPRINT_ERR(NETVSC, "unable to connect to NetVSP - %d", ret);
ret = -1;
- goto Close;
+ goto close;
}
DPRINT_INFO(NETVSC, "*** NetVSC channel handshake result - %d ***",
ret);
- DPRINT_EXIT(NETVSC);
return ret;
-Close:
+close:
/* Now, we can close the channel safely */
- Device->Driver->VmbusChannelInterface.Close(Device);
+ vmbus_close(Device->channel);
Cleanup:
@@ -802,11 +765,10 @@ Cleanup:
FreeNetDevice(netDevice);
}
- DPRINT_EXIT(NETVSC);
return ret;
}
-/**
+/*
* NetVscOnDeviceRemove - Callback when the root bus device is removed
*/
static int NetVscOnDeviceRemove(struct hv_device *Device)
@@ -814,8 +776,6 @@ static int NetVscOnDeviceRemove(struct hv_device *Device)
struct netvsc_device *netDevice;
struct hv_netvsc_packet *netvscPacket, *pos;
- DPRINT_ENTER(NETVSC);
-
DPRINT_INFO(NETVSC, "Disabling outbound traffic on net device (%p)...",
Device->Extension);
@@ -847,7 +807,7 @@ static int NetVscOnDeviceRemove(struct hv_device *Device)
DPRINT_INFO(NETVSC, "net device (%p) safe to remove", netDevice);
/* Now, we can close the channel safely */
- Device->Driver->VmbusChannelInterface.Close(Device);
+ vmbus_close(Device->channel);
/* Release all resources */
list_for_each_entry_safe(netvscPacket, pos,
@@ -858,18 +818,14 @@ static int NetVscOnDeviceRemove(struct hv_device *Device)
kfree(netDevice->ChannelInitEvent);
FreeNetDevice(netDevice);
-
- DPRINT_EXIT(NETVSC);
return 0;
}
-/**
+/*
* NetVscOnCleanup - Perform any cleanup when the driver is removed
*/
static void NetVscOnCleanup(struct hv_driver *drv)
{
- DPRINT_ENTER(NETVSC);
- DPRINT_EXIT(NETVSC);
}
static void NetVscOnSendCompletion(struct hv_device *Device,
@@ -879,13 +835,10 @@ static void NetVscOnSendCompletion(struct hv_device *Device,
struct nvsp_message *nvspPacket;
struct hv_netvsc_packet *nvscPacket;
- DPRINT_ENTER(NETVSC);
-
netDevice = GetInboundNetDevice(Device);
if (!netDevice) {
DPRINT_ERR(NETVSC, "unable to get net device..."
"device being destroyed?");
- DPRINT_EXIT(NETVSC);
return;
}
@@ -907,7 +860,7 @@ static void NetVscOnSendCompletion(struct hv_device *Device,
NvspMessage1TypeSendRNDISPacketComplete) {
/* Get the send context */
nvscPacket = (struct hv_netvsc_packet *)(unsigned long)Packet->TransactionId;
- ASSERT(nvscPacket);
+ /* ASSERT(nvscPacket); */
/* Notify the layer above us */
nvscPacket->Completion.Send.OnSendCompletion(nvscPacket->Completion.Send.SendCompletionContext);
@@ -919,7 +872,6 @@ static void NetVscOnSendCompletion(struct hv_device *Device,
}
PutNetDevice(Device);
- DPRINT_EXIT(NETVSC);
}
static int NetVscOnSend(struct hv_device *Device,
@@ -930,13 +882,10 @@ static int NetVscOnSend(struct hv_device *Device,
struct nvsp_message sendMessage;
- DPRINT_ENTER(NETVSC);
-
netDevice = GetOutboundNetDevice(Device);
if (!netDevice) {
DPRINT_ERR(NETVSC, "net device (%p) shutting down..."
"ignoring outbound packets", netDevice);
- DPRINT_EXIT(NETVSC);
return -2;
}
@@ -954,19 +903,18 @@ static int NetVscOnSend(struct hv_device *Device,
sendMessage.Messages.Version1Messages.SendRNDISPacket.SendBufferSectionSize = 0;
if (Packet->PageBufferCount) {
- ret = Device->Driver->VmbusChannelInterface.SendPacketPageBuffer(
- Device, Packet->PageBuffers,
- Packet->PageBufferCount,
- &sendMessage,
- sizeof(struct nvsp_message),
- (unsigned long)Packet);
+ ret = vmbus_sendpacket_pagebuffer(Device->channel,
+ Packet->PageBuffers,
+ Packet->PageBufferCount,
+ &sendMessage,
+ sizeof(struct nvsp_message),
+ (unsigned long)Packet);
} else {
- ret = Device->Driver->VmbusChannelInterface.SendPacket(Device,
- &sendMessage,
- sizeof(struct nvsp_message),
- (unsigned long)Packet,
- VmbusPacketTypeDataInBand,
- VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
+ ret = vmbus_sendpacket(Device->channel, &sendMessage,
+ sizeof(struct nvsp_message),
+ (unsigned long)Packet,
+ VmbusPacketTypeDataInBand,
+ VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
}
@@ -976,8 +924,6 @@ static int NetVscOnSend(struct hv_device *Device,
atomic_inc(&netDevice->NumOutstandingSends);
PutNetDevice(Device);
-
- DPRINT_EXIT(NETVSC);
return ret;
}
@@ -997,13 +943,10 @@ static void NetVscOnReceive(struct hv_device *Device,
unsigned long flags;
LIST_HEAD(listHead);
- DPRINT_ENTER(NETVSC);
-
netDevice = GetInboundNetDevice(Device);
if (!netDevice) {
DPRINT_ERR(NETVSC, "unable to get net device..."
"device being destroyed?");
- DPRINT_EXIT(NETVSC);
return;
}
@@ -1086,13 +1029,13 @@ static void NetVscOnReceive(struct hv_device *Device,
}
/* Remove the 1st packet to represent the xfer page packet itself */
- xferpagePacket = (struct xferpage_packet*)listHead.next;
+ xferpagePacket = (struct xferpage_packet *)listHead.next;
list_del(&xferpagePacket->ListEntry);
/* This is how much we can satisfy */
xferpagePacket->Count = count - 1;
- ASSERT(xferpagePacket->Count > 0 && xferpagePacket->Count <=
- vmxferpagePacket->RangeCount);
+ /* ASSERT(xferpagePacket->Count > 0 && xferpagePacket->Count <= */
+ /* vmxferpagePacket->RangeCount); */
if (xferpagePacket->Count != vmxferpagePacket->RangeCount) {
DPRINT_INFO(NETVSC, "Needed %d netvsc pkts to satisy this xfer "
@@ -1102,7 +1045,7 @@ static void NetVscOnReceive(struct hv_device *Device,
/* Each range represents 1 RNDIS pkt that contains 1 ethernet frame */
for (i = 0; i < (count - 1); i++) {
- netvscPacket = (struct hv_netvsc_packet*)listHead.next;
+ netvscPacket = (struct hv_netvsc_packet *)listHead.next;
list_del(&netvscPacket->ListEntry);
/* Initialize the netvsc packet */
@@ -1120,9 +1063,9 @@ static void NetVscOnReceive(struct hv_device *Device,
vmxferpagePacket->Ranges[i].ByteCount;
netvscPacket->PageBufferCount = 1;
- ASSERT(vmxferpagePacket->Ranges[i].ByteOffset +
- vmxferpagePacket->Ranges[i].ByteCount <
- netDevice->ReceiveBufferSize);
+ /* ASSERT(vmxferpagePacket->Ranges[i].ByteOffset + */
+ /* vmxferpagePacket->Ranges[i].ByteCount < */
+ /* netDevice->ReceiveBufferSize); */
netvscPacket->PageBuffers[0].Length =
vmxferpagePacket->Ranges[i].ByteCount;
@@ -1160,7 +1103,7 @@ static void NetVscOnReceive(struct hv_device *Device,
if (bytesRemain == 0)
break;
}
- ASSERT(bytesRemain == 0);
+ /* ASSERT(bytesRemain == 0); */
}
DPRINT_DBG(NETVSC, "[%d] - (abs offset %u len %u) => "
"(pfn %llx, offset %u, len %u)", i,
@@ -1176,10 +1119,9 @@ static void NetVscOnReceive(struct hv_device *Device,
NetVscOnReceiveCompletion(netvscPacket->Completion.Recv.ReceiveCompletionContext);
}
- ASSERT(list_empty(&listHead));
+ /* ASSERT(list_empty(&listHead)); */
PutNetDevice(Device);
- DPRINT_EXIT(NETVSC);
}
static void NetVscSendReceiveCompletion(struct hv_device *Device,
@@ -1200,11 +1142,9 @@ static void NetVscSendReceiveCompletion(struct hv_device *Device,
retry_send_cmplt:
/* Send the completion */
- ret = Device->Driver->VmbusChannelInterface.SendPacket(Device,
- &recvcompMessage,
- sizeof(struct nvsp_message),
- TransactionId,
- VmbusPacketTypeCompletion, 0);
+ ret = vmbus_sendpacket(Device->channel, &recvcompMessage,
+ sizeof(struct nvsp_message), TransactionId,
+ VmbusPacketTypeCompletion, 0);
if (ret == 0) {
/* success */
/* no-op */
@@ -1238,9 +1178,7 @@ static void NetVscOnReceiveCompletion(void *Context)
bool fSendReceiveComp = false;
unsigned long flags;
- DPRINT_ENTER(NETVSC);
-
- ASSERT(packet->XferPagePacket);
+ /* ASSERT(packet->XferPagePacket); */
/*
* Even though it seems logical to do a GetOutboundNetDevice() here to
@@ -1251,14 +1189,13 @@ static void NetVscOnReceiveCompletion(void *Context)
if (!netDevice) {
DPRINT_ERR(NETVSC, "unable to get net device..."
"device being destroyed?");
- DPRINT_EXIT(NETVSC);
return;
}
/* Overloading use of the lock. */
spin_lock_irqsave(&netDevice->receive_packet_list_lock, flags);
- ASSERT(packet->XferPagePacket->Count > 0);
+ /* ASSERT(packet->XferPagePacket->Count > 0); */
packet->XferPagePacket->Count--;
/*
@@ -1282,39 +1219,38 @@ static void NetVscOnReceiveCompletion(void *Context)
NetVscSendReceiveCompletion(device, transactionId);
PutNetDevice(device);
- DPRINT_EXIT(NETVSC);
}
-void NetVscOnChannelCallback(void *Context)
+static void NetVscOnChannelCallback(void *Context)
{
- const int netPacketSize = 2048;
int ret;
struct hv_device *device = Context;
struct netvsc_device *netDevice;
u32 bytesRecvd;
u64 requestId;
- unsigned char packet[netPacketSize];
+ unsigned char *packet;
struct vmpacket_descriptor *desc;
- unsigned char *buffer = packet;
- int bufferlen = netPacketSize;
+ unsigned char *buffer;
+ int bufferlen = NETVSC_PACKET_SIZE;
+ /* ASSERT(device); */
- DPRINT_ENTER(NETVSC);
-
- ASSERT(device);
+ packet = kzalloc(NETVSC_PACKET_SIZE * sizeof(unsigned char),
+ GFP_KERNEL);
+ if (!packet)
+ return;
+ buffer = packet;
netDevice = GetInboundNetDevice(device);
if (!netDevice) {
DPRINT_ERR(NETVSC, "net device (%p) shutting down..."
"ignoring inbound packets", netDevice);
- DPRINT_EXIT(NETVSC);
- return;
+ goto out;
}
do {
- ret = device->Driver->VmbusChannelInterface.RecvPacketRaw(
- device, buffer, bufferlen,
- &bytesRecvd, &requestId);
+ ret = vmbus_recvpacket_raw(device->channel, buffer, bufferlen,
+ &bytesRecvd, &requestId);
if (ret == 0) {
if (bytesRecvd > 0) {
DPRINT_DBG(NETVSC, "receive %d bytes, tid %llx",
@@ -1340,17 +1276,17 @@ void NetVscOnChannelCallback(void *Context)
}
/* reset */
- if (bufferlen > netPacketSize) {
+ if (bufferlen > NETVSC_PACKET_SIZE) {
kfree(buffer);
buffer = packet;
- bufferlen = netPacketSize;
+ bufferlen = NETVSC_PACKET_SIZE;
}
} else {
/* reset */
- if (bufferlen > netPacketSize) {
+ if (bufferlen > NETVSC_PACKET_SIZE) {
kfree(buffer);
buffer = packet;
- bufferlen = netPacketSize;
+ bufferlen = NETVSC_PACKET_SIZE;
}
break;
@@ -1367,12 +1303,11 @@ void NetVscOnChannelCallback(void *Context)
}
bufferlen = bytesRecvd;
- } else {
- ASSERT(0);
}
} while (1);
PutNetDevice(device);
- DPRINT_EXIT(NETVSC);
+out:
+ kfree(buffer);
return;
}
diff --git a/drivers/staging/hv/NetVsc.h b/drivers/staging/hv/netvsc.h
index 6e0e034..c71dce5 100644
--- a/drivers/staging/hv/NetVsc.h
+++ b/drivers/staging/hv/netvsc.h
@@ -26,9 +26,9 @@
#define _NETVSC_H_
#include <linux/list.h>
-#include "VmbusPacketFormat.h"
-#include "VmbusChannelInterface.h"
-#include "NetVscApi.h"
+#include "vmbus_packet_format.h"
+#include "vmbus_channel_interface.h"
+#include "netvsc_api.h"
#define NVSP_INVALID_PROTOCOL_VERSION ((u32)0xFFFFFFFF)
@@ -289,6 +289,7 @@ struct nvsp_message {
/* Preallocated receive packets */
#define NETVSC_RECEIVE_PACKETLIST_COUNT 256
+#define NETVSC_PACKET_SIZE 2048
/* Per netvsc channel-specific */
struct netvsc_device {
diff --git a/drivers/staging/hv/NetVscApi.h b/drivers/staging/hv/netvsc_api.h
index 1ce2b74..4b5b3ac 100644
--- a/drivers/staging/hv/NetVscApi.h
+++ b/drivers/staging/hv/netvsc_api.h
@@ -25,11 +25,7 @@
#ifndef _NETVSC_API_H_
#define _NETVSC_API_H_
-#include "VmbusApi.h"
-
-/* Defines */
-#define NETVSC_DEVICE_RING_BUFFER_SIZE (64*PAGE_SIZE)
-#define HW_MACADDR_LEN 6
+#include "vmbus_api.h"
/* Fwd declaration */
struct hv_netvsc_packet;
@@ -93,9 +89,6 @@ struct netvsc_driver {
u32 RingBufferSize;
u32 RequestExtSize;
- /* Additional num of page buffers to allocate */
- u32 AdditionalRequestPageBufferCount;
-
/*
* This is set by the caller to allow us to callback when we
* receive a packet from the "wire"
@@ -105,8 +98,6 @@ struct netvsc_driver {
void (*OnLinkStatusChanged)(struct hv_device *dev, u32 Status);
/* Specific to this driver */
- int (*OnOpen)(struct hv_device *dev);
- int (*OnClose)(struct hv_device *dev);
int (*OnSend)(struct hv_device *dev, struct hv_netvsc_packet *packet);
void *Context;
@@ -119,5 +110,7 @@ struct netvsc_device_info {
/* Interface */
int NetVscInitialize(struct hv_driver *drv);
+int RndisFilterOnOpen(struct hv_device *Device);
+int RndisFilterOnClose(struct hv_device *Device);
#endif /* _NETVSC_API_H_ */
diff --git a/drivers/staging/hv/netvsc_drv.c b/drivers/staging/hv/netvsc_drv.c
index 0d7459e..1415352 100644
--- a/drivers/staging/hv/netvsc_drv.c
+++ b/drivers/staging/hv/netvsc_drv.c
@@ -29,21 +29,23 @@
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/in.h>
+#include <linux/slab.h>
+#include <linux/dmi.h>
+#include <linux/pci.h>
#include <net/arp.h>
#include <net/route.h>
#include <net/sock.h>
#include <net/pkt_sched.h>
#include "osd.h"
#include "logging.h"
+#include "version_info.h"
#include "vmbus.h"
-#include "NetVscApi.h"
-
-MODULE_LICENSE("GPL");
+#include "netvsc_api.h"
struct net_device_context {
/* point back to our device context */
- struct device_context *device_ctx;
- struct net_device_stats stats;
+ struct vm_device *device_ctx;
+ unsigned long avail;
};
struct netvsc_driver_context {
@@ -53,18 +55,17 @@ struct netvsc_driver_context {
struct netvsc_driver drv_obj;
};
-static int netvsc_ringbuffer_size = NETVSC_DEVICE_RING_BUFFER_SIZE;
+#define PACKET_PAGES_LOWATER 8
+/* Need this many pages to handle worst case fragmented packet */
+#define PACKET_PAGES_HIWATER (MAX_SKB_FRAGS + 2)
+
+static int ring_size = 128;
+module_param(ring_size, int, S_IRUGO);
+MODULE_PARM_DESC(ring_size, "Ring buffer size (# of pages)");
/* The one and only one */
static struct netvsc_driver_context g_netvsc_drv;
-static struct net_device_stats *netvsc_get_stats(struct net_device *net)
-{
- struct net_device_context *net_device_ctx = netdev_priv(net);
-
- return &net_device_ctx->stats;
-}
-
static void netvsc_set_multicast_list(struct net_device *net)
{
}
@@ -72,22 +73,12 @@ static void netvsc_set_multicast_list(struct net_device *net)
static int netvsc_open(struct net_device *net)
{
struct net_device_context *net_device_ctx = netdev_priv(net);
- struct driver_context *driver_ctx =
- driver_to_driver_context(net_device_ctx->device_ctx->device.driver);
- struct netvsc_driver_context *net_drv_ctx =
- (struct netvsc_driver_context *)driver_ctx;
- struct netvsc_driver *net_drv_obj = &net_drv_ctx->drv_obj;
struct hv_device *device_obj = &net_device_ctx->device_ctx->device_obj;
int ret = 0;
- DPRINT_ENTER(NETVSC_DRV);
-
if (netif_carrier_ok(net)) {
- memset(&net_device_ctx->stats, 0,
- sizeof(struct net_device_stats));
-
/* Open up the device */
- ret = net_drv_obj->OnOpen(device_obj);
+ ret = RndisFilterOnOpen(device_obj);
if (ret != 0) {
DPRINT_ERR(NETVSC_DRV,
"unable to open device (ret %d).", ret);
@@ -99,31 +90,21 @@ static int netvsc_open(struct net_device *net)
DPRINT_ERR(NETVSC_DRV, "unable to open device...link is down.");
}
- DPRINT_EXIT(NETVSC_DRV);
return ret;
}
static int netvsc_close(struct net_device *net)
{
struct net_device_context *net_device_ctx = netdev_priv(net);
- struct driver_context *driver_ctx =
- driver_to_driver_context(net_device_ctx->device_ctx->device.driver);
- struct netvsc_driver_context *net_drv_ctx =
- (struct netvsc_driver_context *)driver_ctx;
- struct netvsc_driver *net_drv_obj = &net_drv_ctx->drv_obj;
struct hv_device *device_obj = &net_device_ctx->device_ctx->device_obj;
int ret;
- DPRINT_ENTER(NETVSC_DRV);
-
netif_stop_queue(net);
- ret = net_drv_obj->OnClose(device_obj);
+ ret = RndisFilterOnClose(device_obj);
if (ret != 0)
DPRINT_ERR(NETVSC_DRV, "unable to close device (ret %d).", ret);
- DPRINT_EXIT(NETVSC_DRV);
-
return ret;
}
@@ -132,25 +113,19 @@ static void netvsc_xmit_completion(void *context)
struct hv_netvsc_packet *packet = (struct hv_netvsc_packet *)context;
struct sk_buff *skb = (struct sk_buff *)
(unsigned long)packet->Completion.Send.SendCompletionTid;
- struct net_device *net;
-
- DPRINT_ENTER(NETVSC_DRV);
kfree(packet);
if (skb) {
- net = skb->dev;
- dev_kfree_skb_any(skb);
+ struct net_device *net = skb->dev;
+ struct net_device_context *net_device_ctx = netdev_priv(net);
+ unsigned int num_pages = skb_shinfo(skb)->nr_frags + 2;
- if (netif_queue_stopped(net)) {
- DPRINT_INFO(NETVSC_DRV, "net device (%p) waking up...",
- net);
+ dev_kfree_skb_any(skb);
- netif_wake_queue(net);
- }
+ if ((net_device_ctx->avail += num_pages) >= PACKET_PAGES_HIWATER)
+ netif_wake_queue(net);
}
-
- DPRINT_EXIT(NETVSC_DRV);
}
static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
@@ -162,65 +137,56 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
(struct netvsc_driver_context *)driver_ctx;
struct netvsc_driver *net_drv_obj = &net_drv_ctx->drv_obj;
struct hv_netvsc_packet *packet;
- int i;
int ret;
- int num_frags;
- int retries = 0;
-
- DPRINT_ENTER(NETVSC_DRV);
-
- /* Support only 1 chain of frags */
- ASSERT(skb_shinfo(skb)->frag_list == NULL);
- ASSERT(skb->dev == net);
+ unsigned int i, num_pages;
DPRINT_DBG(NETVSC_DRV, "xmit packet - len %d data_len %d",
skb->len, skb->data_len);
- /* Add 1 for skb->data and any additional ones requested */
- num_frags = skb_shinfo(skb)->nr_frags + 1 +
- net_drv_obj->AdditionalRequestPageBufferCount;
+ /* Add 1 for skb->data and additional one for RNDIS */
+ num_pages = skb_shinfo(skb)->nr_frags + 1 + 1;
+ if (num_pages > net_device_ctx->avail)
+ return NETDEV_TX_BUSY;
/* Allocate a netvsc packet based on # of frags. */
packet = kzalloc(sizeof(struct hv_netvsc_packet) +
- (num_frags * sizeof(struct hv_page_buffer)) +
+ (num_pages * sizeof(struct hv_page_buffer)) +
net_drv_obj->RequestExtSize, GFP_ATOMIC);
if (!packet) {
+ /* out of memory, silently drop packet */
DPRINT_ERR(NETVSC_DRV, "unable to allocate hv_netvsc_packet");
- return -1;
+
+ dev_kfree_skb(skb);
+ net->stats.tx_dropped++;
+ return NETDEV_TX_OK;
}
packet->Extension = (void *)(unsigned long)packet +
sizeof(struct hv_netvsc_packet) +
- (num_frags * sizeof(struct hv_page_buffer));
+ (num_pages * sizeof(struct hv_page_buffer));
/* Setup the rndis header */
- packet->PageBufferCount = num_frags;
+ packet->PageBufferCount = num_pages;
/* TODO: Flush all write buffers/ memory fence ??? */
/* wmb(); */
/* Initialize it from the skb */
- ASSERT(skb->data);
packet->TotalDataBufferLength = skb->len;
- /*
- * Start filling in the page buffers starting at
- * AdditionalRequestPageBufferCount offset
- */
- packet->PageBuffers[net_drv_obj->AdditionalRequestPageBufferCount].Pfn = virt_to_phys(skb->data) >> PAGE_SHIFT;
- packet->PageBuffers[net_drv_obj->AdditionalRequestPageBufferCount].Offset = (unsigned long)skb->data & (PAGE_SIZE - 1);
- packet->PageBuffers[net_drv_obj->AdditionalRequestPageBufferCount].Length = skb->len - skb->data_len;
-
- ASSERT((skb->len - skb->data_len) <= PAGE_SIZE);
-
- for (i = net_drv_obj->AdditionalRequestPageBufferCount + 1;
- i < num_frags; i++) {
- packet->PageBuffers[i].Pfn =
- page_to_pfn(skb_shinfo(skb)->frags[i-(net_drv_obj->AdditionalRequestPageBufferCount+1)].page);
- packet->PageBuffers[i].Offset =
- skb_shinfo(skb)->frags[i-(net_drv_obj->AdditionalRequestPageBufferCount+1)].page_offset;
- packet->PageBuffers[i].Length =
- skb_shinfo(skb)->frags[i-(net_drv_obj->AdditionalRequestPageBufferCount+1)].size;
+ /* Start filling in the page buffers starting after RNDIS buffer. */
+ packet->PageBuffers[1].Pfn = virt_to_phys(skb->data) >> PAGE_SHIFT;
+ packet->PageBuffers[1].Offset
+ = (unsigned long)skb->data & (PAGE_SIZE - 1);
+ packet->PageBuffers[1].Length = skb_headlen(skb);
+
+ /* Additional fragments are after SKB data */
+ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+ skb_frag_t *f = &skb_shinfo(skb)->frags[i];
+
+ packet->PageBuffers[i+2].Pfn = page_to_pfn(f->page);
+ packet->PageBuffers[i+2].Offset = f->page_offset;
+ packet->PageBuffers[i+2].Length = f->size;
}
/* Set the completion routine */
@@ -228,65 +194,36 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
packet->Completion.Send.SendCompletionContext = packet;
packet->Completion.Send.SendCompletionTid = (unsigned long)skb;
-retry_send:
ret = net_drv_obj->OnSend(&net_device_ctx->device_ctx->device_obj,
packet);
-
if (ret == 0) {
- ret = NETDEV_TX_OK;
- net_device_ctx->stats.tx_bytes += skb->len;
- net_device_ctx->stats.tx_packets++;
- } else {
- retries++;
- if (retries < 4) {
- DPRINT_ERR(NETVSC_DRV, "unable to send..."
- "retrying %d...", retries);
- udelay(100);
- goto retry_send;
- }
-
- /* no more room or we are shutting down */
- DPRINT_ERR(NETVSC_DRV, "unable to send (%d)..."
- "marking net device (%p) busy", ret, net);
- DPRINT_INFO(NETVSC_DRV, "net device (%p) stopping", net);
+ net->stats.tx_bytes += skb->len;
+ net->stats.tx_packets++;
- ret = NETDEV_TX_BUSY;
- net_device_ctx->stats.tx_dropped++;
-
- netif_stop_queue(net);
+ DPRINT_DBG(NETVSC_DRV, "# of xmits %lu total size %lu",
+ net->stats.tx_packets,
+ net->stats.tx_bytes);
- /*
- * Null it since the caller will free it instead of the
- * completion routine
- */
- packet->Completion.Send.SendCompletionTid = 0;
-
- /*
- * Release the resources since we will not get any send
- * completion
- */
- netvsc_xmit_completion((void *)packet);
+ if ((net_device_ctx->avail -= num_pages) < PACKET_PAGES_LOWATER)
+ netif_stop_queue(net);
+ } else {
+ /* we are shutting down or bus overloaded, just drop packet */
+ net->stats.tx_dropped++;
+ netvsc_xmit_completion(packet);
}
- DPRINT_DBG(NETVSC_DRV, "# of xmits %lu total size %lu",
- net_device_ctx->stats.tx_packets,
- net_device_ctx->stats.tx_bytes);
-
- DPRINT_EXIT(NETVSC_DRV);
- return ret;
+ return NETDEV_TX_OK;
}
-/**
+/*
* netvsc_linkstatus_callback - Link up/down notification
*/
static void netvsc_linkstatus_callback(struct hv_device *device_obj,
unsigned int status)
{
- struct device_context *device_ctx = to_device_context(device_obj);
+ struct vm_device *device_ctx = to_vm_device(device_obj);
struct net_device *net = dev_get_drvdata(&device_ctx->device);
- DPRINT_ENTER(NETVSC_DRV);
-
if (!net) {
DPRINT_ERR(NETVSC_DRV, "got link status but net device "
"not initialized yet");
@@ -300,40 +237,34 @@ static void netvsc_linkstatus_callback(struct hv_device *device_obj,
netif_carrier_off(net);
netif_stop_queue(net);
}
- DPRINT_EXIT(NETVSC_DRV);
}
-/**
- * netvsc_recv_callback - Callback when we receive a packet from the "wire" on the specified device.
+/*
+ * netvsc_recv_callback - Callback when we receive a packet from the
+ * "wire" on the specified device.
*/
static int netvsc_recv_callback(struct hv_device *device_obj,
struct hv_netvsc_packet *packet)
{
- struct device_context *device_ctx = to_device_context(device_obj);
+ struct vm_device *device_ctx = to_vm_device(device_obj);
struct net_device *net = dev_get_drvdata(&device_ctx->device);
- struct net_device_context *net_device_ctx;
struct sk_buff *skb;
void *data;
- int ret;
int i;
unsigned long flags;
- DPRINT_ENTER(NETVSC_DRV);
-
if (!net) {
DPRINT_ERR(NETVSC_DRV, "got receive callback but net device "
"not initialized yet");
return 0;
}
- net_device_ctx = netdev_priv(net);
-
- /* Allocate a skb - TODO preallocate this */
- /* Pad 2-bytes to align IP header to 16 bytes */
- skb = dev_alloc_skb(packet->TotalDataBufferLength + 2);
- ASSERT(skb);
- skb_reserve(skb, 2);
- skb->dev = net;
+ /* Allocate a skb - TODO direct I/O to pages? */
+ skb = netdev_alloc_skb_ip_align(net, packet->TotalDataBufferLength);
+ if (unlikely(!skb)) {
+ ++net->stats.rx_dropped;
+ return 0;
+ }
/* for kmap_atomic */
local_irq_save(flags);
@@ -358,40 +289,47 @@ static int netvsc_recv_callback(struct hv_device *device_obj,
local_irq_restore(flags);
skb->protocol = eth_type_trans(skb, net);
-
skb->ip_summed = CHECKSUM_NONE;
+ net->stats.rx_packets++;
+ net->stats.rx_bytes += skb->len;
+
/*
* Pass the skb back up. Network stack will deallocate the skb when it
- * is done
+ * is done.
+ * TODO - use NAPI?
*/
- ret = netif_rx(skb);
-
- switch (ret) {
- case NET_RX_DROP:
- net_device_ctx->stats.rx_dropped++;
- break;
- default:
- net_device_ctx->stats.rx_packets++;
- net_device_ctx->stats.rx_bytes += skb->len;
- break;
+ netif_rx(skb);
- }
DPRINT_DBG(NETVSC_DRV, "# of recvs %lu total size %lu",
- net_device_ctx->stats.rx_packets,
- net_device_ctx->stats.rx_bytes);
-
- DPRINT_EXIT(NETVSC_DRV);
+ net->stats.rx_packets, net->stats.rx_bytes);
return 0;
}
+static void netvsc_get_drvinfo(struct net_device *net,
+ struct ethtool_drvinfo *info)
+{
+ strcpy(info->driver, "hv_netvsc");
+ strcpy(info->version, HV_DRV_VERSION);
+ strcpy(info->fw_version, "N/A");
+}
+
+static const struct ethtool_ops ethtool_ops = {
+ .get_drvinfo = netvsc_get_drvinfo,
+ .get_sg = ethtool_op_get_sg,
+ .set_sg = ethtool_op_set_sg,
+ .get_link = ethtool_op_get_link,
+};
+
static const struct net_device_ops device_ops = {
.ndo_open = netvsc_open,
.ndo_stop = netvsc_close,
.ndo_start_xmit = netvsc_start_xmit,
- .ndo_get_stats = netvsc_get_stats,
.ndo_set_multicast_list = netvsc_set_multicast_list,
+ .ndo_change_mtu = eth_change_mtu,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_set_mac_address = eth_mac_addr,
};
static int netvsc_probe(struct device *device)
@@ -401,20 +339,17 @@ static int netvsc_probe(struct device *device)
struct netvsc_driver_context *net_drv_ctx =
(struct netvsc_driver_context *)driver_ctx;
struct netvsc_driver *net_drv_obj = &net_drv_ctx->drv_obj;
- struct device_context *device_ctx = device_to_device_context(device);
+ struct vm_device *device_ctx = device_to_vm_device(device);
struct hv_device *device_obj = &device_ctx->device_obj;
struct net_device *net = NULL;
struct net_device_context *net_device_ctx;
struct netvsc_device_info device_info;
int ret;
- DPRINT_ENTER(NETVSC_DRV);
-
if (!net_drv_obj->Base.OnDeviceAdd)
return -1;
- net = alloc_netdev(sizeof(struct net_device_context), "seth%d",
- ether_setup);
+ net = alloc_etherdev(sizeof(struct net_device_context));
if (!net)
return -1;
@@ -424,6 +359,7 @@ static int netvsc_probe(struct device *device)
net_device_ctx = netdev_priv(net);
net_device_ctx->device_ctx = device_ctx;
+ net_device_ctx->avail = ring_size;
dev_set_drvdata(device, net);
/* Notify the netvsc driver of the new device */
@@ -453,6 +389,10 @@ static int netvsc_probe(struct device *device)
net->netdev_ops = &device_ops;
+ /* TODO: Add GSO and Checksum offload */
+ net->features = NETIF_F_SG;
+
+ SET_ETHTOOL_OPS(net, &ethtool_ops);
SET_NETDEV_DEV(net, device);
ret = register_netdev(net);
@@ -462,7 +402,6 @@ static int netvsc_probe(struct device *device)
free_netdev(net);
}
- DPRINT_EXIT(NETVSC_DRV);
return ret;
}
@@ -473,23 +412,18 @@ static int netvsc_remove(struct device *device)
struct netvsc_driver_context *net_drv_ctx =
(struct netvsc_driver_context *)driver_ctx;
struct netvsc_driver *net_drv_obj = &net_drv_ctx->drv_obj;
- struct device_context *device_ctx = device_to_device_context(device);
+ struct vm_device *device_ctx = device_to_vm_device(device);
struct net_device *net = dev_get_drvdata(&device_ctx->device);
struct hv_device *device_obj = &device_ctx->device_obj;
int ret;
- DPRINT_ENTER(NETVSC_DRV);
-
if (net == NULL) {
DPRINT_INFO(NETVSC, "no net device to remove");
- DPRINT_EXIT(NETVSC_DRV);
return 0;
}
- if (!net_drv_obj->Base.OnDeviceRemove) {
- DPRINT_EXIT(NETVSC_DRV);
+ if (!net_drv_obj->Base.OnDeviceRemove)
return -1;
- }
/* Stop outbound asap */
netif_stop_queue(net);
@@ -508,7 +442,6 @@ static int netvsc_remove(struct device *device)
}
free_netdev(net);
- DPRINT_EXIT(NETVSC_DRV);
return ret;
}
@@ -528,8 +461,6 @@ static void netvsc_drv_exit(void)
struct device *current_dev;
int ret;
- DPRINT_ENTER(NETVSC_DRV);
-
while (1) {
current_dev = NULL;
@@ -555,8 +486,6 @@ static void netvsc_drv_exit(void)
vmbus_child_driver_unregister(drv_ctx);
- DPRINT_EXIT(NETVSC_DRV);
-
return;
}
@@ -566,11 +495,7 @@ static int netvsc_drv_init(int (*drv_init)(struct hv_driver *drv))
struct driver_context *drv_ctx = &g_netvsc_drv.drv_ctx;
int ret;
- DPRINT_ENTER(NETVSC_DRV);
-
- vmbus_get_interface(&net_drv_obj->Base.VmbusChannelInterface);
-
- net_drv_obj->RingBufferSize = netvsc_ringbuffer_size;
+ net_drv_obj->RingBufferSize = ring_size * PAGE_SIZE;
net_drv_obj->OnReceiveCallback = netvsc_recv_callback;
net_drv_obj->OnLinkStatusChanged = netvsc_linkstatus_callback;
@@ -587,33 +512,48 @@ static int netvsc_drv_init(int (*drv_init)(struct hv_driver *drv))
/* The driver belongs to vmbus */
ret = vmbus_child_driver_register(drv_ctx);
- DPRINT_EXIT(NETVSC_DRV);
-
return ret;
}
+static const struct dmi_system_id __initconst
+hv_netvsc_dmi_table[] __maybe_unused = {
+ {
+ .ident = "Hyper-V",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Virtual Machine"),
+ DMI_MATCH(DMI_BOARD_NAME, "Virtual Machine"),
+ },
+ },
+ { },
+};
+MODULE_DEVICE_TABLE(dmi, hv_netvsc_dmi_table);
+
static int __init netvsc_init(void)
{
- int ret;
-
- DPRINT_ENTER(NETVSC_DRV);
DPRINT_INFO(NETVSC_DRV, "Netvsc initializing....");
- ret = netvsc_drv_init(NetVscInitialize);
+ if (!dmi_check_system(hv_netvsc_dmi_table))
+ return -ENODEV;
- DPRINT_EXIT(NETVSC_DRV);
-
- return ret;
+ return netvsc_drv_init(NetVscInitialize);
}
static void __exit netvsc_exit(void)
{
- DPRINT_ENTER(NETVSC_DRV);
netvsc_drv_exit();
- DPRINT_EXIT(NETVSC_DRV);
}
-module_param(netvsc_ringbuffer_size, int, S_IRUGO);
+static const struct pci_device_id __initconst
+hv_netvsc_pci_table[] __maybe_unused = {
+ { PCI_DEVICE(0x1414, 0x5353) }, /* VGA compatible controller */
+ { 0 }
+};
+MODULE_DEVICE_TABLE(pci, hv_netvsc_pci_table);
+
+MODULE_LICENSE("GPL");
+MODULE_VERSION(HV_DRV_VERSION);
+MODULE_DESCRIPTION("Microsoft Hyper-V network driver");
module_init(netvsc_init);
module_exit(netvsc_exit);
diff --git a/drivers/staging/hv/osd.c b/drivers/staging/hv/osd.c
index 3a4793a..8c3eb27 100644
--- a/drivers/staging/hv/osd.c
+++ b/drivers/staging/hv/osd.c
@@ -40,6 +40,7 @@
#include <linux/time.h>
#include <linux/io.h>
#include <linux/bitops.h>
+#include <linux/slab.h>
#include "osd.h"
struct osd_callback_struct {
@@ -58,6 +59,15 @@ void *osd_VirtualAllocExec(unsigned int size)
#endif
}
+/**
+ * osd_PageAlloc() - Allocate pages
+ * @count: Total number of Kernel pages you want to allocate
+ *
+ * Tries to allocate @count number of consecutive free kernel pages.
+ * And if successful, it will set the pages to 0 before returning.
+ * If successfull it will return pointer to the @count pages.
+ * Mainly used by Hyper-V drivers.
+ */
void *osd_PageAlloc(unsigned int count)
{
void *p;
@@ -77,6 +87,14 @@ void *osd_PageAlloc(unsigned int count)
}
EXPORT_SYMBOL_GPL(osd_PageAlloc);
+/**
+ * osd_PageFree() - Free pages
+ * @page: Pointer to the first page to be freed
+ * @count: Total number of Kernel pages you free
+ *
+ * Frees the pages allocated by osd_PageAlloc()
+ * Mainly used by Hyper-V drivers.
+ */
void osd_PageFree(void *page, unsigned int count)
{
free_pages((unsigned long)page, get_order(count * PAGE_SIZE));
@@ -85,6 +103,17 @@ void osd_PageFree(void *page, unsigned int count)
}
EXPORT_SYMBOL_GPL(osd_PageFree);
+/**
+ * osd_WaitEventCreate() - Create the event queue
+ *
+ * Allocates memory for a &struct osd_waitevent. And then calls
+ * init_waitqueue_head to set up the wait queue for the event.
+ * This structure is usually part of a another structure that contains
+ * the actual Hyper-V device driver structure.
+ *
+ * Returns pointer to &struct osd_waitevent
+ * Mainly used by Hyper-V drivers.
+ */
struct osd_waitevent *osd_WaitEventCreate(void)
{
struct osd_waitevent *wait = kmalloc(sizeof(struct osd_waitevent),
@@ -98,6 +127,19 @@ struct osd_waitevent *osd_WaitEventCreate(void)
}
EXPORT_SYMBOL_GPL(osd_WaitEventCreate);
+
+/**
+ * osd_WaitEventSet() - Wake up the process
+ * @waitEvent: Structure to event to be woken up
+ *
+ * @waitevent is of type &struct osd_waitevent
+ *
+ * Wake up the sleeping process so it can do some work.
+ * And set condition indicator in &struct osd_waitevent to indicate
+ * the process is in a woken state.
+ *
+ * Only used by Network and Storage Hyper-V drivers.
+ */
void osd_WaitEventSet(struct osd_waitevent *waitEvent)
{
waitEvent->condition = 1;
@@ -105,6 +147,20 @@ void osd_WaitEventSet(struct osd_waitevent *waitEvent)
}
EXPORT_SYMBOL_GPL(osd_WaitEventSet);
+/**
+ * osd_WaitEventWait() - Wait for event till condition is true
+ * @waitEvent: Structure to event to be put to sleep
+ *
+ * @waitevent is of type &struct osd_waitevent
+ *
+ * Set up the process to sleep until waitEvent->condition get true.
+ * And set condition indicator in &struct osd_waitevent to indicate
+ * the process is in a sleeping state.
+ *
+ * Returns the status of 'wait_event_interruptible()' system call
+ *
+ * Mainly used by Hyper-V drivers.
+ */
int osd_WaitEventWait(struct osd_waitevent *waitEvent)
{
int ret = 0;
@@ -116,6 +172,21 @@ int osd_WaitEventWait(struct osd_waitevent *waitEvent)
}
EXPORT_SYMBOL_GPL(osd_WaitEventWait);
+/**
+ * osd_WaitEventWaitEx() - Wait for event or timeout for process wakeup
+ * @waitEvent: Structure to event to be put to sleep
+ * @TimeoutInMs: Total number of Milliseconds to wait before waking up
+ *
+ * @waitevent is of type &struct osd_waitevent
+ * Set up the process to sleep until @waitEvent->condition get true or
+ * @TimeoutInMs (Time out in Milliseconds) has been reached.
+ * And set condition indicator in &struct osd_waitevent to indicate
+ * the process is in a sleeping state.
+ *
+ * Returns the status of 'wait_event_interruptible_timeout()' system call
+ *
+ * Mainly used by Hyper-V drivers.
+ */
int osd_WaitEventWaitEx(struct osd_waitevent *waitEvent, u32 TimeoutInMs)
{
int ret = 0;
diff --git a/drivers/staging/hv/RingBuffer.c b/drivers/staging/hv/ring_buffer.c
index f69ae33..d78c569 100644
--- a/drivers/staging/hv/RingBuffer.c
+++ b/drivers/staging/hv/ring_buffer.c
@@ -25,14 +25,14 @@
#include <linux/mm.h>
#include "osd.h"
#include "logging.h"
-#include "RingBuffer.h"
+#include "ring_buffer.h"
/* #defines */
/* Amount of space to write to */
-#define BYTES_AVAIL_TO_WRITE(r, w, z) ((w) >= (r))?((z) - ((w) - (r))):((r) - (w))
+#define BYTES_AVAIL_TO_WRITE(r, w, z) ((w) >= (r)) ? ((z) - ((w) - (r))) : ((r) - (w))
/*++
@@ -46,9 +46,9 @@ Description:
--*/
static inline void
-GetRingBufferAvailBytes(RING_BUFFER_INFO *rbi, u32 *read, u32 *write)
+GetRingBufferAvailBytes(struct hv_ring_buffer_info *rbi, u32 *read, u32 *write)
{
- u32 read_loc,write_loc;
+ u32 read_loc, write_loc;
/* Capture the read/write indices before they changed */
read_loc = rbi->RingBuffer->ReadIndex;
@@ -68,11 +68,11 @@ Description:
--*/
static inline u32
-GetNextWriteLocation(RING_BUFFER_INFO* RingInfo)
+GetNextWriteLocation(struct hv_ring_buffer_info *RingInfo)
{
u32 next = RingInfo->RingBuffer->WriteIndex;
- ASSERT(next < RingInfo->RingDataSize);
+ /* ASSERT(next < RingInfo->RingDataSize); */
return next;
}
@@ -87,7 +87,8 @@ Description:
--*/
static inline void
-SetNextWriteLocation(RING_BUFFER_INFO* RingInfo, u32 NextWriteLocation)
+SetNextWriteLocation(struct hv_ring_buffer_info *RingInfo,
+ u32 NextWriteLocation)
{
RingInfo->RingBuffer->WriteIndex = NextWriteLocation;
}
@@ -102,11 +103,11 @@ Description:
--*/
static inline u32
-GetNextReadLocation(RING_BUFFER_INFO* RingInfo)
+GetNextReadLocation(struct hv_ring_buffer_info *RingInfo)
{
u32 next = RingInfo->RingBuffer->ReadIndex;
- ASSERT(next < RingInfo->RingDataSize);
+ /* ASSERT(next < RingInfo->RingDataSize); */
return next;
}
@@ -122,11 +123,11 @@ Description:
--*/
static inline u32
-GetNextReadLocationWithOffset(RING_BUFFER_INFO* RingInfo, u32 Offset)
+GetNextReadLocationWithOffset(struct hv_ring_buffer_info *RingInfo, u32 Offset)
{
u32 next = RingInfo->RingBuffer->ReadIndex;
- ASSERT(next < RingInfo->RingDataSize);
+ /* ASSERT(next < RingInfo->RingDataSize); */
next += Offset;
next %= RingInfo->RingDataSize;
@@ -143,7 +144,7 @@ Description:
--*/
static inline void
-SetNextReadLocation(RING_BUFFER_INFO* RingInfo, u32 NextReadLocation)
+SetNextReadLocation(struct hv_ring_buffer_info *RingInfo, u32 NextReadLocation)
{
RingInfo->RingBuffer->ReadIndex = NextReadLocation;
}
@@ -159,7 +160,7 @@ Description:
--*/
static inline void *
-GetRingBuffer(RING_BUFFER_INFO* RingInfo)
+GetRingBuffer(struct hv_ring_buffer_info *RingInfo)
{
return (void *)RingInfo->RingBuffer->Buffer;
}
@@ -175,7 +176,7 @@ Description:
--*/
static inline u32
-GetRingBufferSize(RING_BUFFER_INFO* RingInfo)
+GetRingBufferSize(struct hv_ring_buffer_info *RingInfo)
{
return RingInfo->RingDataSize;
}
@@ -190,9 +191,9 @@ Description:
--*/
static inline u64
-GetRingBufferIndices(RING_BUFFER_INFO* RingInfo)
+GetRingBufferIndices(struct hv_ring_buffer_info *RingInfo)
{
- return ((u64)RingInfo->RingBuffer->WriteIndex << 32) || RingInfo->RingBuffer->ReadIndex;
+ return (u64)RingInfo->RingBuffer->WriteIndex << 32;
}
@@ -205,14 +206,19 @@ Description:
Dump out to console the ring buffer info
--*/
-void DumpRingInfo(RING_BUFFER_INFO *RingInfo, char *Prefix)
+void DumpRingInfo(struct hv_ring_buffer_info *RingInfo, char *Prefix)
{
u32 bytesAvailToWrite;
u32 bytesAvailToRead;
- GetRingBufferAvailBytes(RingInfo, &bytesAvailToRead, &bytesAvailToWrite);
+ GetRingBufferAvailBytes(RingInfo,
+ &bytesAvailToRead,
+ &bytesAvailToWrite);
- DPRINT(VMBUS, DEBUG_RING_LVL, "%s <<ringinfo %p buffer %p avail write %u avail read %u read idx %u write idx %u>>",
+ DPRINT(VMBUS,
+ DEBUG_RING_LVL,
+ "%s <<ringinfo %p buffer %p avail write %u "
+ "avail read %u read idx %u write idx %u>>",
Prefix,
RingInfo,
RingInfo->RingBuffer->Buffer,
@@ -227,15 +233,15 @@ void DumpRingInfo(RING_BUFFER_INFO *RingInfo, char *Prefix)
static u32
CopyToRingBuffer(
- RING_BUFFER_INFO *RingInfo,
+ struct hv_ring_buffer_info *RingInfo,
u32 StartWriteOffset,
- void * Src,
+ void *Src,
u32 SrcLen);
static u32
CopyFromRingBuffer(
- RING_BUFFER_INFO *RingInfo,
- void * Dest,
+ struct hv_ring_buffer_info *RingInfo,
+ void *Dest,
u32 DestLen,
u32 StartReadOffset);
@@ -250,22 +256,22 @@ Description:
Get various debug metrics for the specified ring buffer
--*/
-void RingBufferGetDebugInfo(RING_BUFFER_INFO *RingInfo,
- RING_BUFFER_DEBUG_INFO *DebugInfo)
+void RingBufferGetDebugInfo(struct hv_ring_buffer_info *RingInfo,
+ struct hv_ring_buffer_debug_info *debug_info)
{
u32 bytesAvailToWrite;
u32 bytesAvailToRead;
- if (RingInfo->RingBuffer)
- {
- GetRingBufferAvailBytes(RingInfo, &bytesAvailToRead, &bytesAvailToWrite);
-
- DebugInfo->BytesAvailToRead = bytesAvailToRead;
- DebugInfo->BytesAvailToWrite = bytesAvailToWrite;
- DebugInfo->CurrentReadIndex = RingInfo->RingBuffer->ReadIndex;
- DebugInfo->CurrentWriteIndex = RingInfo->RingBuffer->WriteIndex;
+ if (RingInfo->RingBuffer) {
+ GetRingBufferAvailBytes(RingInfo,
+ &bytesAvailToRead,
+ &bytesAvailToWrite);
- DebugInfo->CurrentInterruptMask = RingInfo->RingBuffer->InterruptMask;
+ debug_info->BytesAvailToRead = bytesAvailToRead;
+ debug_info->BytesAvailToWrite = bytesAvailToWrite;
+ debug_info->CurrentReadIndex = RingInfo->RingBuffer->ReadIndex;
+ debug_info->CurrentWriteIndex = RingInfo->RingBuffer->WriteIndex;
+ debug_info->CurrentInterruptMask = RingInfo->RingBuffer->InterruptMask;
}
}
@@ -279,7 +285,7 @@ Description:
Get the interrupt mask for the specified ring buffer
--*/
-u32 GetRingBufferInterruptMask(RING_BUFFER_INFO *rbi)
+u32 GetRingBufferInterruptMask(struct hv_ring_buffer_info *rbi)
{
return rbi->RingBuffer->InterruptMask;
}
@@ -293,17 +299,18 @@ Description:
Initialize the ring buffer
--*/
-int RingBufferInit(RING_BUFFER_INFO *RingInfo, void *Buffer, u32 BufferLen)
+int RingBufferInit(struct hv_ring_buffer_info *RingInfo, void *Buffer, u32 BufferLen)
{
- ASSERT(sizeof(RING_BUFFER) == PAGE_SIZE);
+ if (sizeof(struct hv_ring_buffer) != PAGE_SIZE)
+ return -EINVAL;
- memset(RingInfo, 0, sizeof(RING_BUFFER_INFO));
+ memset(RingInfo, 0, sizeof(struct hv_ring_buffer_info));
- RingInfo->RingBuffer = (RING_BUFFER*)Buffer;
+ RingInfo->RingBuffer = (struct hv_ring_buffer *)Buffer;
RingInfo->RingBuffer->ReadIndex = RingInfo->RingBuffer->WriteIndex = 0;
RingInfo->RingSize = BufferLen;
- RingInfo->RingDataSize = BufferLen - sizeof(RING_BUFFER);
+ RingInfo->RingDataSize = BufferLen - sizeof(struct hv_ring_buffer);
spin_lock_init(&RingInfo->ring_lock);
@@ -319,7 +326,7 @@ Description:
Cleanup the ring buffer
--*/
-void RingBufferCleanup(RING_BUFFER_INFO* RingInfo)
+void RingBufferCleanup(struct hv_ring_buffer_info *RingInfo)
{
}
@@ -332,21 +339,19 @@ Description:
Write to the ring buffer
--*/
-int RingBufferWrite(RING_BUFFER_INFO *OutRingInfo,
+int RingBufferWrite(struct hv_ring_buffer_info *OutRingInfo,
struct scatterlist *sglist, u32 sgcount)
{
- int i=0;
+ int i = 0;
u32 byteAvailToWrite;
u32 byteAvailToRead;
- u32 totalBytesToWrite=0;
+ u32 totalBytesToWrite = 0;
struct scatterlist *sg;
volatile u32 nextWriteLocation;
- u64 prevIndices=0;
+ u64 prevIndices = 0;
unsigned long flags;
- DPRINT_ENTER(VMBUS);
-
for_each_sg(sglist, sg, sgcount, i)
{
totalBytesToWrite += sg->length;
@@ -356,22 +361,25 @@ int RingBufferWrite(RING_BUFFER_INFO *OutRingInfo,
spin_lock_irqsave(&OutRingInfo->ring_lock, flags);
- GetRingBufferAvailBytes(OutRingInfo, &byteAvailToRead, &byteAvailToWrite);
+ GetRingBufferAvailBytes(OutRingInfo,
+ &byteAvailToRead,
+ &byteAvailToWrite);
DPRINT_DBG(VMBUS, "Writing %u bytes...", totalBytesToWrite);
/* DumpRingInfo(OutRingInfo, "BEFORE "); */
- /* If there is only room for the packet, assume it is full. Otherwise, the next time around, we think the ring buffer */
+ /* If there is only room for the packet, assume it is full. */
+ /* Otherwise, the next time around, we think the ring buffer */
/* is empty since the read index == write index */
- if (byteAvailToWrite <= totalBytesToWrite)
- {
- DPRINT_DBG(VMBUS, "No more space left on outbound ring buffer (needed %u, avail %u)", totalBytesToWrite, byteAvailToWrite);
+ if (byteAvailToWrite <= totalBytesToWrite) {
+ DPRINT_DBG(VMBUS,
+ "No more space left on outbound ring buffer "
+ "(needed %u, avail %u)",
+ totalBytesToWrite,
+ byteAvailToWrite);
spin_unlock_irqrestore(&OutRingInfo->ring_lock, flags);
-
- DPRINT_EXIT(VMBUS);
-
return -1;
}
@@ -403,9 +411,6 @@ int RingBufferWrite(RING_BUFFER_INFO *OutRingInfo,
/* DumpRingInfo(OutRingInfo, "AFTER "); */
spin_unlock_irqrestore(&OutRingInfo->ring_lock, flags);
-
- DPRINT_EXIT(VMBUS);
-
return 0;
}
@@ -419,21 +424,26 @@ Description:
Read without advancing the read index
--*/
-int RingBufferPeek(RING_BUFFER_INFO *InRingInfo, void *Buffer, u32 BufferLen)
+int RingBufferPeek(struct hv_ring_buffer_info *InRingInfo, void *Buffer, u32 BufferLen)
{
u32 bytesAvailToWrite;
u32 bytesAvailToRead;
- u32 nextReadLocation=0;
+ u32 nextReadLocation = 0;
unsigned long flags;
spin_lock_irqsave(&InRingInfo->ring_lock, flags);
- GetRingBufferAvailBytes(InRingInfo, &bytesAvailToRead, &bytesAvailToWrite);
+ GetRingBufferAvailBytes(InRingInfo,
+ &bytesAvailToRead,
+ &bytesAvailToWrite);
/* Make sure there is something to read */
- if (bytesAvailToRead < BufferLen )
- {
- /* DPRINT_DBG(VMBUS, "got callback but not enough to read <avail to read %d read size %d>!!", bytesAvailToRead, BufferLen); */
+ if (bytesAvailToRead < BufferLen) {
+ /* DPRINT_DBG(VMBUS,
+ "got callback but not enough to read "
+ "<avail to read %d read size %d>!!",
+ bytesAvailToRead,
+ BufferLen); */
spin_unlock_irqrestore(&InRingInfo->ring_lock, flags);
@@ -444,9 +454,9 @@ int RingBufferPeek(RING_BUFFER_INFO *InRingInfo, void *Buffer, u32 BufferLen)
nextReadLocation = GetNextReadLocation(InRingInfo);
nextReadLocation = CopyFromRingBuffer(InRingInfo,
- Buffer,
- BufferLen,
- nextReadLocation);
+ Buffer,
+ BufferLen,
+ nextReadLocation);
spin_unlock_irqrestore(&InRingInfo->ring_lock, flags);
@@ -463,29 +473,35 @@ Description:
Read and advance the read index
--*/
-int RingBufferRead(RING_BUFFER_INFO *InRingInfo, void *Buffer,
+int RingBufferRead(struct hv_ring_buffer_info *InRingInfo, void *Buffer,
u32 BufferLen, u32 Offset)
{
u32 bytesAvailToWrite;
u32 bytesAvailToRead;
- u32 nextReadLocation=0;
- u64 prevIndices=0;
+ u32 nextReadLocation = 0;
+ u64 prevIndices = 0;
unsigned long flags;
- ASSERT(BufferLen > 0);
+ if (BufferLen <= 0)
+ return -EINVAL;
spin_lock_irqsave(&InRingInfo->ring_lock, flags);
- GetRingBufferAvailBytes(InRingInfo, &bytesAvailToRead, &bytesAvailToWrite);
+ GetRingBufferAvailBytes(InRingInfo,
+ &bytesAvailToRead,
+ &bytesAvailToWrite);
DPRINT_DBG(VMBUS, "Reading %u bytes...", BufferLen);
/* DumpRingInfo(InRingInfo, "BEFORE "); */
/* Make sure there is something to read */
- if (bytesAvailToRead < BufferLen )
- {
- DPRINT_DBG(VMBUS, "got callback but not enough to read <avail to read %d read size %d>!!", bytesAvailToRead, BufferLen);
+ if (bytesAvailToRead < BufferLen) {
+ DPRINT_DBG(VMBUS,
+ "got callback but not enough to read "
+ "<avail to read %d read size %d>!!",
+ bytesAvailToRead,
+ BufferLen);
spin_unlock_irqrestore(&InRingInfo->ring_lock, flags);
@@ -495,17 +511,18 @@ int RingBufferRead(RING_BUFFER_INFO *InRingInfo, void *Buffer,
nextReadLocation = GetNextReadLocationWithOffset(InRingInfo, Offset);
nextReadLocation = CopyFromRingBuffer(InRingInfo,
- Buffer,
- BufferLen,
- nextReadLocation);
+ Buffer,
+ BufferLen,
+ nextReadLocation);
nextReadLocation = CopyFromRingBuffer(InRingInfo,
- &prevIndices,
- sizeof(u64),
- nextReadLocation);
+ &prevIndices,
+ sizeof(u64),
+ nextReadLocation);
/* Make sure all reads are done before we update the read index since */
- /* the writer may start writing to the read area once the read index is updated */
+ /* the writer may start writing to the read area once the read index */
+ /*is updated */
mb();
/* Update the read index */
@@ -531,27 +548,24 @@ Description:
--*/
static u32
CopyToRingBuffer(
- RING_BUFFER_INFO *RingInfo,
+ struct hv_ring_buffer_info *RingInfo,
u32 StartWriteOffset,
- void * Src,
+ void *Src,
u32 SrcLen)
{
- void * ringBuffer=GetRingBuffer(RingInfo);
- u32 ringBufferSize=GetRingBufferSize(RingInfo);
+ void *ringBuffer = GetRingBuffer(RingInfo);
+ u32 ringBufferSize = GetRingBufferSize(RingInfo);
u32 fragLen;
- if (SrcLen > ringBufferSize - StartWriteOffset) /* wrap-around detected! */
- {
+ /* wrap-around detected! */
+ if (SrcLen > ringBufferSize - StartWriteOffset) {
DPRINT_DBG(VMBUS, "wrap-around detected!");
fragLen = ringBufferSize - StartWriteOffset;
memcpy(ringBuffer + StartWriteOffset, Src, fragLen);
memcpy(ringBuffer, Src + fragLen, SrcLen - fragLen);
- }
- else
- {
+ } else
memcpy(ringBuffer + StartWriteOffset, Src, SrcLen);
- }
StartWriteOffset += SrcLen;
StartWriteOffset %= ringBufferSize;
@@ -572,29 +586,28 @@ Description:
--*/
static u32
CopyFromRingBuffer(
- RING_BUFFER_INFO *RingInfo,
- void * Dest,
+ struct hv_ring_buffer_info *RingInfo,
+ void *Dest,
u32 DestLen,
u32 StartReadOffset)
{
- void * ringBuffer=GetRingBuffer(RingInfo);
- u32 ringBufferSize=GetRingBufferSize(RingInfo);
+ void *ringBuffer = GetRingBuffer(RingInfo);
+ u32 ringBufferSize = GetRingBufferSize(RingInfo);
u32 fragLen;
- if (DestLen > ringBufferSize - StartReadOffset) /* wrap-around detected at the src */
- {
+ /* wrap-around detected at the src */
+ if (DestLen > ringBufferSize - StartReadOffset) {
DPRINT_DBG(VMBUS, "src wrap-around detected!");
fragLen = ringBufferSize - StartReadOffset;
memcpy(Dest, ringBuffer + StartReadOffset, fragLen);
memcpy(Dest + fragLen, ringBuffer, DestLen - fragLen);
- }
- else
- {
+ } else
+
memcpy(Dest, ringBuffer + StartReadOffset, DestLen);
- }
+
StartReadOffset += DestLen;
StartReadOffset %= ringBufferSize;
diff --git a/drivers/staging/hv/RingBuffer.h b/drivers/staging/hv/ring_buffer.h
index 6202157..a7f1717 100644
--- a/drivers/staging/hv/RingBuffer.h
+++ b/drivers/staging/hv/ring_buffer.h
@@ -27,7 +27,7 @@
#include <linux/scatterlist.h>
-typedef struct _RING_BUFFER {
+struct hv_ring_buffer {
/* Offset in bytes from the start of ring data below */
volatile u32 WriteIndex;
@@ -51,51 +51,52 @@ typedef struct _RING_BUFFER {
* !!! DO NOT place any fields below this !!!
*/
u8 Buffer[0];
-} __attribute__((packed)) RING_BUFFER;
+} __attribute__((packed));
-typedef struct _RING_BUFFER_INFO {
- RING_BUFFER *RingBuffer;
+struct hv_ring_buffer_info {
+ struct hv_ring_buffer *RingBuffer;
u32 RingSize; /* Include the shared header */
spinlock_t ring_lock;
u32 RingDataSize; /* < ringSize */
u32 RingDataStartOffset;
+};
-} RING_BUFFER_INFO;
-
-typedef struct _RING_BUFFER_DEBUG_INFO {
+struct hv_ring_buffer_debug_info {
u32 CurrentInterruptMask;
u32 CurrentReadIndex;
u32 CurrentWriteIndex;
u32 BytesAvailToRead;
u32 BytesAvailToWrite;
-} RING_BUFFER_DEBUG_INFO;
+};
/* Interface */
-int RingBufferInit(RING_BUFFER_INFO *RingInfo, void *Buffer, u32 BufferLen);
+int RingBufferInit(struct hv_ring_buffer_info *RingInfo, void *Buffer,
+ u32 BufferLen);
-void RingBufferCleanup(RING_BUFFER_INFO *RingInfo);
+void RingBufferCleanup(struct hv_ring_buffer_info *RingInfo);
-int RingBufferWrite(RING_BUFFER_INFO *RingInfo,
+int RingBufferWrite(struct hv_ring_buffer_info *RingInfo,
struct scatterlist *sglist,
u32 sgcount);
-int RingBufferPeek(RING_BUFFER_INFO *RingInfo, void *Buffer, u32 BufferLen);
+int RingBufferPeek(struct hv_ring_buffer_info *RingInfo, void *Buffer,
+ u32 BufferLen);
-int RingBufferRead(RING_BUFFER_INFO *RingInfo,
+int RingBufferRead(struct hv_ring_buffer_info *RingInfo,
void *Buffer,
u32 BufferLen,
u32 Offset);
-u32 GetRingBufferInterruptMask(RING_BUFFER_INFO *RingInfo);
+u32 GetRingBufferInterruptMask(struct hv_ring_buffer_info *RingInfo);
-void DumpRingInfo(RING_BUFFER_INFO *RingInfo, char *Prefix);
+void DumpRingInfo(struct hv_ring_buffer_info *RingInfo, char *Prefix);
-void RingBufferGetDebugInfo(RING_BUFFER_INFO *RingInfo,
- RING_BUFFER_DEBUG_INFO *DebugInfo);
+void RingBufferGetDebugInfo(struct hv_ring_buffer_info *RingInfo,
+ struct hv_ring_buffer_debug_info *debug_info);
#endif /* _RING_BUFFER_H_ */
diff --git a/drivers/staging/hv/rndis.h b/drivers/staging/hv/rndis.h
index 7c73277..723e1f1 100644
--- a/drivers/staging/hv/rndis.h
+++ b/drivers/staging/hv/rndis.h
@@ -622,7 +622,7 @@ struct rndis_message {
/* get the size of an RNDIS message. Pass in the message type, */
/* struct rndis_set_request, struct rndis_packet for example */
#define RNDIS_MESSAGE_SIZE(Message) \
- (sizeof(Message) + (sizeof(struct rndis_message) - \
+ (sizeof(Message) + (sizeof(struct rndis_message) - \
sizeof(union rndis_message_container)))
/* get pointer to info buffer with message pointer */
diff --git a/drivers/staging/hv/RndisFilter.c b/drivers/staging/hv/rndis_filter.c
index 26d7997..fa2141f 100644
--- a/drivers/staging/hv/RndisFilter.c
+++ b/drivers/staging/hv/rndis_filter.c
@@ -20,11 +20,14 @@
*/
#include <linux/kernel.h>
#include <linux/highmem.h>
+#include <linux/slab.h>
#include <linux/io.h>
+#include <linux/if_ether.h>
+
#include "osd.h"
#include "logging.h"
-#include "NetVscApi.h"
-#include "RndisFilter.h"
+#include "netvsc_api.h"
+#include "rndis_filter.h"
/* Data types */
struct rndis_filter_driver_object {
@@ -49,7 +52,7 @@ struct rndis_device {
spinlock_t request_lock;
struct list_head RequestList;
- unsigned char HwMacAddr[HW_MACADDR_LEN];
+ unsigned char HwMacAddr[ETH_ALEN];
};
struct rndis_request {
@@ -85,10 +88,6 @@ static int RndisFilterOnDeviceRemove(struct hv_device *Device);
static void RndisFilterOnCleanup(struct hv_driver *Driver);
-static int RndisFilterOnOpen(struct hv_device *Device);
-
-static int RndisFilterOnClose(struct hv_device *Device);
-
static int RndisFilterOnSend(struct hv_device *Device,
struct hv_netvsc_packet *Packet);
@@ -245,8 +244,6 @@ static int RndisFilterSendRequest(struct rndis_device *Device,
int ret;
struct hv_netvsc_packet *packet;
- DPRINT_ENTER(NETVSC);
-
/* Setup the packet to send it */
packet = &Request->Packet;
@@ -266,7 +263,6 @@ static int RndisFilterSendRequest(struct rndis_device *Device,
packet->Completion.Send.SendCompletionTid = (unsigned long)Device;
ret = gRndisFilter.InnerDriver.OnSend(Device->NetDevice->Device, packet);
- DPRINT_EXIT(NETVSC);
return ret;
}
@@ -277,8 +273,6 @@ static void RndisFilterReceiveResponse(struct rndis_device *Device,
bool found = false;
unsigned long flags;
- DPRINT_ENTER(NETVSC);
-
spin_lock_irqsave(&Device->request_lock, flags);
list_for_each_entry(request, &Device->RequestList, ListEntry) {
/*
@@ -326,8 +320,6 @@ static void RndisFilterReceiveResponse(struct rndis_device *Device,
Response->Message.InitializeComplete.RequestId,
Response->NdisMessageType);
}
-
- DPRINT_EXIT(NETVSC);
}
static void RndisFilterReceiveIndicateStatus(struct rndis_device *Device,
@@ -354,11 +346,9 @@ static void RndisFilterReceiveData(struct rndis_device *Device,
struct rndis_packet *rndisPacket;
u32 dataOffset;
- DPRINT_ENTER(NETVSC);
-
/* empty ethernet frame ?? */
- ASSERT(Packet->PageBuffers[0].Length >
- RNDIS_MESSAGE_SIZE(struct rndis_packet));
+ /* ASSERT(Packet->PageBuffers[0].Length > */
+ /* RNDIS_MESSAGE_SIZE(struct rndis_packet)); */
rndisPacket = &Message->Message.Packet;
@@ -378,8 +368,6 @@ static void RndisFilterReceiveData(struct rndis_device *Device,
gRndisFilter.InnerDriver.OnReceiveCallback(Device->NetDevice->Device,
Packet);
-
- DPRINT_EXIT(NETVSC);
}
static int RndisFilterOnReceive(struct hv_device *Device,
@@ -390,14 +378,13 @@ static int RndisFilterOnReceive(struct hv_device *Device,
struct rndis_message rndisMessage;
struct rndis_message *rndisHeader;
- DPRINT_ENTER(NETVSC);
+ if (!netDevice)
+ return -EINVAL;
- ASSERT(netDevice);
/* Make sure the rndis device state is initialized */
if (!netDevice->Extension) {
DPRINT_ERR(NETVSC, "got rndis message but no rndis device..."
"dropping this message!");
- DPRINT_EXIT(NETVSC);
return -1;
}
@@ -405,7 +392,6 @@ static int RndisFilterOnReceive(struct hv_device *Device,
if (rndisDevice->State == RNDIS_DEV_UNINITIALIZED) {
DPRINT_ERR(NETVSC, "got rndis message but rndis device "
"uninitialized...dropping this message!");
- DPRINT_EXIT(NETVSC);
return -1;
}
@@ -430,7 +416,6 @@ static int RndisFilterOnReceive(struct hv_device *Device,
"bytes got %u)...dropping this message!",
rndisHeader->MessageLength,
Packet->TotalDataBufferLength);
- DPRINT_EXIT(NETVSC);
return -1;
}
#endif
@@ -478,7 +463,6 @@ static int RndisFilterOnReceive(struct hv_device *Device,
break;
}
- DPRINT_EXIT(NETVSC);
return 0;
}
@@ -491,9 +475,8 @@ static int RndisFilterQueryDevice(struct rndis_device *Device, u32 Oid,
struct rndis_query_complete *queryComplete;
int ret = 0;
- DPRINT_ENTER(NETVSC);
-
- ASSERT(Result);
+ if (!Result)
+ return -EINVAL;
*ResultSize = 0;
request = GetRndisRequest(Device, REMOTE_NDIS_QUERY_MSG,
@@ -534,14 +517,13 @@ static int RndisFilterQueryDevice(struct rndis_device *Device, u32 Oid,
Cleanup:
if (request)
PutRndisRequest(Device, request);
- DPRINT_EXIT(NETVSC);
return ret;
}
static int RndisFilterQueryDeviceMac(struct rndis_device *Device)
{
- u32 size = HW_MACADDR_LEN;
+ u32 size = ETH_ALEN;
return RndisFilterQueryDevice(Device,
RNDIS_OID_802_3_PERMANENT_ADDRESS,
@@ -566,10 +548,8 @@ static int RndisFilterSetPacketFilter(struct rndis_device *Device,
u32 status;
int ret;
- DPRINT_ENTER(NETVSC);
-
- ASSERT(RNDIS_MESSAGE_SIZE(struct rndis_set_request) + sizeof(u32) <=
- sizeof(struct rndis_message));
+ /* ASSERT(RNDIS_MESSAGE_SIZE(struct rndis_set_request) + sizeof(u32) <= */
+ /* sizeof(struct rndis_message)); */
request = GetRndisRequest(Device, REMOTE_NDIS_SET_MSG,
RNDIS_MESSAGE_SIZE(struct rndis_set_request) +
@@ -612,20 +592,15 @@ Cleanup:
if (request)
PutRndisRequest(Device, request);
Exit:
- DPRINT_EXIT(NETVSC);
-
return ret;
}
int RndisFilterInit(struct netvsc_driver *Driver)
{
- DPRINT_ENTER(NETVSC);
-
DPRINT_DBG(NETVSC, "sizeof(struct rndis_filter_packet) == %zd",
sizeof(struct rndis_filter_packet));
Driver->RequestExtSize = sizeof(struct rndis_filter_packet);
- Driver->AdditionalRequestPageBufferCount = 1; /* For rndis header */
/* Driver->Context = rndisDriver; */
@@ -642,8 +617,8 @@ int RndisFilterInit(struct netvsc_driver *Driver)
Driver->Base.OnDeviceRemove;
gRndisFilter.InnerDriver.Base.OnCleanup = Driver->Base.OnCleanup;
- ASSERT(Driver->OnSend);
- ASSERT(Driver->OnReceiveCallback);
+ /* ASSERT(Driver->OnSend); */
+ /* ASSERT(Driver->OnReceiveCallback); */
gRndisFilter.InnerDriver.OnSend = Driver->OnSend;
gRndisFilter.InnerDriver.OnReceiveCallback = Driver->OnReceiveCallback;
gRndisFilter.InnerDriver.OnLinkStatusChanged =
@@ -654,13 +629,9 @@ int RndisFilterInit(struct netvsc_driver *Driver)
Driver->Base.OnDeviceRemove = RndisFilterOnDeviceRemove;
Driver->Base.OnCleanup = RndisFilterOnCleanup;
Driver->OnSend = RndisFilterOnSend;
- Driver->OnOpen = RndisFilterOnOpen;
- Driver->OnClose = RndisFilterOnClose;
/* Driver->QueryLinkStatus = RndisFilterQueryDeviceLinkStatus; */
Driver->OnReceiveCallback = RndisFilterOnReceive;
- DPRINT_EXIT(NETVSC);
-
return 0;
}
@@ -672,8 +643,6 @@ static int RndisFilterInitDevice(struct rndis_device *Device)
u32 status;
int ret;
- DPRINT_ENTER(NETVSC);
-
request = GetRndisRequest(Device, REMOTE_NDIS_INITIALIZE_MSG,
RNDIS_MESSAGE_SIZE(struct rndis_initialize_request));
if (!request) {
@@ -711,7 +680,6 @@ static int RndisFilterInitDevice(struct rndis_device *Device)
Cleanup:
if (request)
PutRndisRequest(Device, request);
- DPRINT_EXIT(NETVSC);
return ret;
}
@@ -721,8 +689,6 @@ static void RndisFilterHaltDevice(struct rndis_device *Device)
struct rndis_request *request;
struct rndis_halt_request *halt;
- DPRINT_ENTER(NETVSC);
-
/* Attempt to do a rndis device halt */
request = GetRndisRequest(Device, REMOTE_NDIS_HALT_MSG,
RNDIS_MESSAGE_SIZE(struct rndis_halt_request));
@@ -741,7 +707,6 @@ static void RndisFilterHaltDevice(struct rndis_device *Device)
Cleanup:
if (request)
PutRndisRequest(Device, request);
- DPRINT_EXIT(NETVSC);
return;
}
@@ -749,18 +714,16 @@ static int RndisFilterOpenDevice(struct rndis_device *Device)
{
int ret;
- DPRINT_ENTER(NETVSC);
-
if (Device->State != RNDIS_DEV_INITIALIZED)
return 0;
ret = RndisFilterSetPacketFilter(Device,
NDIS_PACKET_TYPE_BROADCAST |
+ NDIS_PACKET_TYPE_ALL_MULTICAST |
NDIS_PACKET_TYPE_DIRECTED);
if (ret == 0)
Device->State = RNDIS_DEV_DATAINITIALIZED;
- DPRINT_EXIT(NETVSC);
return ret;
}
@@ -768,8 +731,6 @@ static int RndisFilterCloseDevice(struct rndis_device *Device)
{
int ret;
- DPRINT_ENTER(NETVSC);
-
if (Device->State != RNDIS_DEV_DATAINITIALIZED)
return 0;
@@ -777,8 +738,6 @@ static int RndisFilterCloseDevice(struct rndis_device *Device)
if (ret == 0)
Device->State = RNDIS_DEV_INITIALIZED;
- DPRINT_EXIT(NETVSC);
-
return ret;
}
@@ -790,13 +749,9 @@ static int RndisFilterOnDeviceAdd(struct hv_device *Device,
struct rndis_device *rndisDevice;
struct netvsc_device_info *deviceInfo = AdditionalInfo;
- DPRINT_ENTER(NETVSC);
-
rndisDevice = GetRndisDevice();
- if (!rndisDevice) {
- DPRINT_EXIT(NETVSC);
+ if (!rndisDevice)
return -1;
- }
DPRINT_DBG(NETVSC, "rndis device object allocated - %p", rndisDevice);
@@ -808,15 +763,14 @@ static int RndisFilterOnDeviceAdd(struct hv_device *Device,
ret = gRndisFilter.InnerDriver.Base.OnDeviceAdd(Device, AdditionalInfo);
if (ret != 0) {
kfree(rndisDevice);
- DPRINT_EXIT(NETVSC);
return ret;
}
/* Initialize the rndis device */
netDevice = Device->Extension;
- ASSERT(netDevice);
- ASSERT(netDevice->Device);
+ /* ASSERT(netDevice); */
+ /* ASSERT(netDevice->Device); */
netDevice->Extension = rndisDevice;
rndisDevice->NetDevice = netDevice;
@@ -838,16 +792,10 @@ static int RndisFilterOnDeviceAdd(struct hv_device *Device,
*/
}
- DPRINT_INFO(NETVSC, "Device 0x%p mac addr %02x%02x%02x%02x%02x%02x",
- rndisDevice,
- rndisDevice->HwMacAddr[0],
- rndisDevice->HwMacAddr[1],
- rndisDevice->HwMacAddr[2],
- rndisDevice->HwMacAddr[3],
- rndisDevice->HwMacAddr[4],
- rndisDevice->HwMacAddr[5]);
+ DPRINT_INFO(NETVSC, "Device 0x%p mac addr %pM",
+ rndisDevice, rndisDevice->HwMacAddr);
- memcpy(deviceInfo->MacAddr, rndisDevice->HwMacAddr, HW_MACADDR_LEN);
+ memcpy(deviceInfo->MacAddr, rndisDevice->HwMacAddr, ETH_ALEN);
RndisFilterQueryDeviceLinkStatus(rndisDevice);
@@ -855,8 +803,6 @@ static int RndisFilterOnDeviceAdd(struct hv_device *Device,
DPRINT_INFO(NETVSC, "Device 0x%p link state %s", rndisDevice,
((deviceInfo->LinkState) ? ("down") : ("up")));
- DPRINT_EXIT(NETVSC);
-
return ret;
}
@@ -865,8 +811,6 @@ static int RndisFilterOnDeviceRemove(struct hv_device *Device)
struct netvsc_device *netDevice = Device->Extension;
struct rndis_device *rndisDevice = netDevice->Extension;
- DPRINT_ENTER(NETVSC);
-
/* Halt and release the rndis device */
RndisFilterHaltDevice(rndisDevice);
@@ -876,46 +820,31 @@ static int RndisFilterOnDeviceRemove(struct hv_device *Device)
/* Pass control to inner driver to remove the device */
gRndisFilter.InnerDriver.Base.OnDeviceRemove(Device);
- DPRINT_EXIT(NETVSC);
-
return 0;
}
static void RndisFilterOnCleanup(struct hv_driver *Driver)
{
- DPRINT_ENTER(NETVSC);
-
- DPRINT_EXIT(NETVSC);
}
-static int RndisFilterOnOpen(struct hv_device *Device)
+int RndisFilterOnOpen(struct hv_device *Device)
{
- int ret;
struct netvsc_device *netDevice = Device->Extension;
- DPRINT_ENTER(NETVSC);
-
- ASSERT(netDevice);
- ret = RndisFilterOpenDevice(netDevice->Extension);
+ if (!netDevice)
+ return -EINVAL;
- DPRINT_EXIT(NETVSC);
-
- return ret;
+ return RndisFilterOpenDevice(netDevice->Extension);
}
-static int RndisFilterOnClose(struct hv_device *Device)
+int RndisFilterOnClose(struct hv_device *Device)
{
- int ret;
struct netvsc_device *netDevice = Device->Extension;
- DPRINT_ENTER(NETVSC);
-
- ASSERT(netDevice);
- ret = RndisFilterCloseDevice(netDevice->Extension);
-
- DPRINT_EXIT(NETVSC);
+ if (!netDevice)
+ return -EINVAL;
- return ret;
+ return RndisFilterCloseDevice(netDevice->Extension);
}
static int RndisFilterOnSend(struct hv_device *Device,
@@ -927,11 +856,9 @@ static int RndisFilterOnSend(struct hv_device *Device,
struct rndis_packet *rndisPacket;
u32 rndisMessageSize;
- DPRINT_ENTER(NETVSC);
-
/* Add the rndis header */
filterPacket = (struct rndis_filter_packet *)Packet->Extension;
- ASSERT(filterPacket);
+ /* ASSERT(filterPacket); */
memset(filterPacket, 0, sizeof(struct rndis_filter_packet));
@@ -973,8 +900,6 @@ static int RndisFilterOnSend(struct hv_device *Device,
filterPacket->CompletionContext;
}
- DPRINT_EXIT(NETVSC);
-
return ret;
}
@@ -982,19 +907,12 @@ static void RndisFilterOnSendCompletion(void *Context)
{
struct rndis_filter_packet *filterPacket = Context;
- DPRINT_ENTER(NETVSC);
-
/* Pass it back to the original handler */
filterPacket->OnCompletion(filterPacket->CompletionContext);
-
- DPRINT_EXIT(NETVSC);
}
static void RndisFilterOnSendRequestCompletion(void *Context)
{
- DPRINT_ENTER(NETVSC);
-
/* Noop */
- DPRINT_EXIT(NETVSC);
}
diff --git a/drivers/staging/hv/RndisFilter.h b/drivers/staging/hv/rndis_filter.h
index fa7dd79..764b9bf 100644
--- a/drivers/staging/hv/RndisFilter.h
+++ b/drivers/staging/hv/rndis_filter.h
@@ -27,7 +27,7 @@
#define __struct_bcount(x)
-#include "NetVsc.h"
+#include "netvsc.h"
#include "rndis.h"
diff --git a/drivers/staging/hv/StorVsc.c b/drivers/staging/hv/storvsc.c
index 2f7c425..19e87f6 100644
--- a/drivers/staging/hv/StorVsc.c
+++ b/drivers/staging/hv/storvsc.c
@@ -20,13 +20,15 @@
*/
#include <linux/kernel.h>
#include <linux/string.h>
+#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/delay.h>
#include "osd.h"
#include "logging.h"
-#include "StorVscApi.h"
-#include "VmbusPacketFormat.h"
+#include "storvsc_api.h"
+#include "vmbus_packet_format.h"
#include "vstorage.h"
+#include "channel.h"
struct storvsc_request_extension {
@@ -99,7 +101,7 @@ static inline struct storvsc_device *AllocStorDevice(struct hv_device *Device)
static inline void FreeStorDevice(struct storvsc_device *Device)
{
- ASSERT(atomic_read(&Device->RefCount) == 0);
+ /* ASSERT(atomic_read(&Device->RefCount) == 0); */
kfree(Device);
}
@@ -136,10 +138,10 @@ static inline void PutStorDevice(struct hv_device *Device)
struct storvsc_device *storDevice;
storDevice = (struct storvsc_device *)Device->Extension;
- ASSERT(storDevice);
+ /* ASSERT(storDevice); */
atomic_dec(&storDevice->RefCount);
- ASSERT(atomic_read(&storDevice->RefCount));
+ /* ASSERT(atomic_read(&storDevice->RefCount)); */
}
/* Drop ref count to 1 to effectively disable GetStorDevice() */
@@ -148,7 +150,7 @@ static inline struct storvsc_device *ReleaseStorDevice(struct hv_device *Device)
struct storvsc_device *storDevice;
storDevice = (struct storvsc_device *)Device->Extension;
- ASSERT(storDevice);
+ /* ASSERT(storDevice); */
/* Busy wait until the ref drop to 2, then set it to 1 */
while (atomic_cmpxchg(&storDevice->RefCount, 2, 1) != 2)
@@ -164,7 +166,7 @@ static inline struct storvsc_device *FinalReleaseStorDevice(
struct storvsc_device *storDevice;
storDevice = (struct storvsc_device *)Device->Extension;
- ASSERT(storDevice);
+ /* ASSERT(storDevice); */
/* Busy wait until the ref drop to 1, then set it to 0 */
while (atomic_cmpxchg(&storDevice->RefCount, 1, 0) != 1)
@@ -185,7 +187,6 @@ static int StorVscChannelInit(struct hv_device *Device)
if (!storDevice) {
DPRINT_ERR(STORVSC, "unable to get stor device..."
"device being destroyed?");
- DPRINT_EXIT(STORVSC);
return -1;
}
@@ -198,6 +199,10 @@ static int StorVscChannelInit(struct hv_device *Device)
*/
memset(request, 0, sizeof(struct storvsc_request_extension));
request->WaitEvent = osd_WaitEventCreate();
+ if (!request->WaitEvent) {
+ ret = -ENOMEM;
+ goto nomem;
+ }
vstorPacket->Operation = VStorOperationBeginInitialization;
vstorPacket->Flags = REQUEST_COMPLETION_FLAG;
@@ -208,12 +213,11 @@ static int StorVscChannelInit(struct hv_device *Device)
DPRINT_INFO(STORVSC, "BEGIN_INITIALIZATION_OPERATION...");
- ret = Device->Driver->VmbusChannelInterface.SendPacket(Device,
- vstorPacket,
- sizeof(struct vstor_packet),
- (unsigned long)request,
- VmbusPacketTypeDataInBand,
- VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
+ ret = vmbus_sendpacket(Device->channel, vstorPacket,
+ sizeof(struct vstor_packet),
+ (unsigned long)request,
+ VmbusPacketTypeDataInBand,
+ VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
if (ret != 0) {
DPRINT_ERR(STORVSC,
"unable to send BEGIN_INITIALIZATION_OPERATION");
@@ -240,12 +244,11 @@ static int StorVscChannelInit(struct hv_device *Device)
vstorPacket->Version.MajorMinor = VMSTOR_PROTOCOL_VERSION_CURRENT;
FILL_VMSTOR_REVISION(vstorPacket->Version.Revision);
- ret = Device->Driver->VmbusChannelInterface.SendPacket(Device,
- vstorPacket,
- sizeof(struct vstor_packet),
- (unsigned long)request,
- VmbusPacketTypeDataInBand,
- VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
+ ret = vmbus_sendpacket(Device->channel, vstorPacket,
+ sizeof(struct vstor_packet),
+ (unsigned long)request,
+ VmbusPacketTypeDataInBand,
+ VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
if (ret != 0) {
DPRINT_ERR(STORVSC,
"unable to send BEGIN_INITIALIZATION_OPERATION");
@@ -272,12 +275,11 @@ static int StorVscChannelInit(struct hv_device *Device)
vstorPacket->StorageChannelProperties.PortNumber =
storDevice->PortNumber;
- ret = Device->Driver->VmbusChannelInterface.SendPacket(Device,
- vstorPacket,
- sizeof(struct vstor_packet),
- (unsigned long)request,
- VmbusPacketTypeDataInBand,
- VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
+ ret = vmbus_sendpacket(Device->channel, vstorPacket,
+ sizeof(struct vstor_packet),
+ (unsigned long)request,
+ VmbusPacketTypeDataInBand,
+ VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
if (ret != 0) {
DPRINT_ERR(STORVSC,
@@ -309,12 +311,11 @@ static int StorVscChannelInit(struct hv_device *Device)
vstorPacket->Operation = VStorOperationEndInitialization;
vstorPacket->Flags = REQUEST_COMPLETION_FLAG;
- ret = Device->Driver->VmbusChannelInterface.SendPacket(Device,
- vstorPacket,
- sizeof(struct vstor_packet),
- (unsigned long)request,
- VmbusPacketTypeDataInBand,
- VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
+ ret = vmbus_sendpacket(Device->channel, vstorPacket,
+ sizeof(struct vstor_packet),
+ (unsigned long)request,
+ VmbusPacketTypeDataInBand,
+ VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
if (ret != 0) {
DPRINT_ERR(STORVSC,
@@ -337,10 +338,8 @@ static int StorVscChannelInit(struct hv_device *Device)
Cleanup:
kfree(request->WaitEvent);
request->WaitEvent = NULL;
-
+nomem:
PutStorDevice(Device);
-
- DPRINT_EXIT(STORVSC);
return ret;
}
@@ -351,13 +350,10 @@ static void StorVscOnIOCompletion(struct hv_device *Device,
struct hv_storvsc_request *request;
struct storvsc_device *storDevice;
- DPRINT_ENTER(STORVSC);
-
storDevice = MustGetStorDevice(Device);
if (!storDevice) {
DPRINT_ERR(STORVSC, "unable to get stor device..."
"device being destroyed?");
- DPRINT_EXIT(STORVSC);
return;
}
@@ -365,12 +361,12 @@ static void StorVscOnIOCompletion(struct hv_device *Device,
"completed bytes xfer %u", RequestExt,
VStorPacket->VmSrb.DataTransferLength);
- ASSERT(RequestExt != NULL);
- ASSERT(RequestExt->Request != NULL);
+ /* ASSERT(RequestExt != NULL); */
+ /* ASSERT(RequestExt->Request != NULL); */
request = RequestExt->Request;
- ASSERT(request->OnIOCompletion != NULL);
+ /* ASSERT(request->OnIOCompletion != NULL); */
/* Copy over the status...etc */
request->Status = VStorPacket->VmSrb.ScsiStatus;
@@ -390,8 +386,8 @@ static void StorVscOnIOCompletion(struct hv_device *Device,
"valid - len %d\n", RequestExt,
VStorPacket->VmSrb.SenseInfoLength);
- ASSERT(VStorPacket->VmSrb.SenseInfoLength <=
- request->SenseBufferSize);
+ /* ASSERT(VStorPacket->VmSrb.SenseInfoLength <= */
+ /* request->SenseBufferSize); */
memcpy(request->SenseBuffer,
VStorPacket->VmSrb.SenseData,
VStorPacket->VmSrb.SenseInfoLength);
@@ -409,8 +405,6 @@ static void StorVscOnIOCompletion(struct hv_device *Device,
atomic_dec(&storDevice->NumOutstandingRequests);
PutStorDevice(Device);
-
- DPRINT_EXIT(STORVSC);
}
static void StorVscOnReceive(struct hv_device *Device,
@@ -444,23 +438,19 @@ static void StorVscOnChannelCallback(void *context)
struct storvsc_request_extension *request;
int ret;
- DPRINT_ENTER(STORVSC);
-
- ASSERT(device);
+ /* ASSERT(device); */
storDevice = MustGetStorDevice(device);
if (!storDevice) {
DPRINT_ERR(STORVSC, "unable to get stor device..."
"device being destroyed?");
- DPRINT_EXIT(STORVSC);
return;
}
do {
- ret = device->Driver->VmbusChannelInterface.RecvPacket(device,
- packet,
- ALIGN_UP(sizeof(struct vstor_packet), 8),
- &bytesRecvd, &requestId);
+ ret = vmbus_recvpacket(device->channel, packet,
+ ALIGN_UP(sizeof(struct vstor_packet), 8),
+ &bytesRecvd, &requestId);
if (ret == 0 && bytesRecvd > 0) {
DPRINT_DBG(STORVSC, "receive %d bytes - tid %llx",
bytesRecvd, requestId);
@@ -469,7 +459,7 @@ static void StorVscOnChannelCallback(void *context)
request = (struct storvsc_request_extension *)
(unsigned long)requestId;
- ASSERT(request);
+ /* ASSERT(request);c */
/* if (vstorPacket.Flags & SYNTHETIC_FLAG) */
if ((request == &storDevice->InitRequest) ||
@@ -496,8 +486,6 @@ static void StorVscOnChannelCallback(void *context)
} while (1);
PutStorDevice(device);
-
- DPRINT_EXIT(STORVSC);
return;
}
@@ -511,13 +499,11 @@ static int StorVscConnectToVsp(struct hv_device *Device)
memset(&props, 0, sizeof(struct vmstorage_channel_properties));
/* Open the channel */
- ret = Device->Driver->VmbusChannelInterface.Open(Device,
- storDriver->RingBufferSize,
- storDriver->RingBufferSize,
- (void *)&props,
- sizeof(struct vmstorage_channel_properties),
- StorVscOnChannelCallback,
- Device);
+ ret = vmbus_open(Device->channel,
+ storDriver->RingBufferSize, storDriver->RingBufferSize,
+ (void *)&props,
+ sizeof(struct vmstorage_channel_properties),
+ StorVscOnChannelCallback, Device);
DPRINT_DBG(STORVSC, "storage props: path id %d, tgt id %d, max xfer %d",
props.PathId, props.TargetId, props.MaxTransferBytes);
@@ -532,7 +518,7 @@ static int StorVscConnectToVsp(struct hv_device *Device)
return ret;
}
-/**
+/*
* StorVscOnDeviceAdd - Callback when the device belonging to this driver is added
*/
static int StorVscOnDeviceAdd(struct hv_device *Device, void *AdditionalInfo)
@@ -542,8 +528,6 @@ static int StorVscOnDeviceAdd(struct hv_device *Device, void *AdditionalInfo)
struct storvsc_device_info *deviceInfo;
int ret = 0;
- DPRINT_ENTER(STORVSC);
-
deviceInfo = (struct storvsc_device_info *)AdditionalInfo;
storDevice = AllocStorDevice(Device);
if (!storDevice) {
@@ -553,7 +537,7 @@ static int StorVscOnDeviceAdd(struct hv_device *Device, void *AdditionalInfo)
/* Save the channel properties to our storvsc channel */
/* props = (struct vmstorage_channel_properties *)
- * channel->offerMsg.Offer.u.Standard.UserDefined; */
+ * channel->offerMsg.Offer.u.Standard.UserDefined; */
/* FIXME: */
/*
@@ -579,20 +563,16 @@ static int StorVscOnDeviceAdd(struct hv_device *Device, void *AdditionalInfo)
storDevice->TargetId);
Cleanup:
- DPRINT_EXIT(STORVSC);
-
return ret;
}
-/**
+/*
* StorVscOnDeviceRemove - Callback when the our device is being removed
*/
static int StorVscOnDeviceRemove(struct hv_device *Device)
{
struct storvsc_device *storDevice;
- DPRINT_ENTER(STORVSC);
-
DPRINT_INFO(STORVSC, "disabling storage device (%p)...",
Device->Extension);
@@ -617,30 +597,25 @@ static int StorVscOnDeviceRemove(struct hv_device *Device)
DPRINT_INFO(STORVSC, "storage device (%p) safe to remove", storDevice);
/* Close the channel */
- Device->Driver->VmbusChannelInterface.Close(Device);
+ vmbus_close(Device->channel);
FreeStorDevice(storDevice);
-
- DPRINT_EXIT(STORVSC);
return 0;
}
-static int StorVscOnHostReset(struct hv_device *Device)
+int StorVscOnHostReset(struct hv_device *Device)
{
struct storvsc_device *storDevice;
struct storvsc_request_extension *request;
struct vstor_packet *vstorPacket;
int ret;
- DPRINT_ENTER(STORVSC);
-
DPRINT_INFO(STORVSC, "resetting host adapter...");
storDevice = GetStorDevice(Device);
if (!storDevice) {
DPRINT_ERR(STORVSC, "unable to get stor device..."
"device being destroyed?");
- DPRINT_EXIT(STORVSC);
return -1;
}
@@ -648,17 +623,20 @@ static int StorVscOnHostReset(struct hv_device *Device)
vstorPacket = &request->VStorPacket;
request->WaitEvent = osd_WaitEventCreate();
+ if (!request->WaitEvent) {
+ ret = -ENOMEM;
+ goto Cleanup;
+ }
vstorPacket->Operation = VStorOperationResetBus;
vstorPacket->Flags = REQUEST_COMPLETION_FLAG;
vstorPacket->VmSrb.PathId = storDevice->PathId;
- ret = Device->Driver->VmbusChannelInterface.SendPacket(Device,
- vstorPacket,
- sizeof(struct vstor_packet),
- (unsigned long)&storDevice->ResetRequest,
- VmbusPacketTypeDataInBand,
- VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
+ ret = vmbus_sendpacket(Device->channel, vstorPacket,
+ sizeof(struct vstor_packet),
+ (unsigned long)&storDevice->ResetRequest,
+ VmbusPacketTypeDataInBand,
+ VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
if (ret != 0) {
DPRINT_ERR(STORVSC, "Unable to send reset packet %p ret %d",
vstorPacket, ret);
@@ -678,11 +656,10 @@ static int StorVscOnHostReset(struct hv_device *Device)
Cleanup:
PutStorDevice(Device);
- DPRINT_EXIT(STORVSC);
return ret;
}
-/**
+/*
* StorVscOnIORequest - Callback to initiate an I/O request
*/
static int StorVscOnIORequest(struct hv_device *Device,
@@ -693,8 +670,6 @@ static int StorVscOnIORequest(struct hv_device *Device,
struct vstor_packet *vstorPacket;
int ret = 0;
- DPRINT_ENTER(STORVSC);
-
requestExtension =
(struct storvsc_request_extension *)Request->Extension;
vstorPacket = &requestExtension->VStorPacket;
@@ -711,12 +686,11 @@ static int StorVscOnIORequest(struct hv_device *Device,
if (!storDevice) {
DPRINT_ERR(STORVSC, "unable to get stor device..."
"device being destroyed?");
- DPRINT_EXIT(STORVSC);
return -2;
}
/* print_hex_dump_bytes("", DUMP_PREFIX_NONE, Request->Cdb,
- * Request->CdbLen); */
+ * Request->CdbLen); */
requestExtension->Request = Request;
requestExtension->Device = Device;
@@ -754,19 +728,17 @@ static int StorVscOnIORequest(struct hv_device *Device,
vstorPacket->VmSrb.CdbLength);
if (requestExtension->Request->DataBuffer.Length) {
- ret = Device->Driver->VmbusChannelInterface.
- SendPacketMultiPageBuffer(Device,
+ ret = vmbus_sendpacket_multipagebuffer(Device->channel,
&requestExtension->Request->DataBuffer,
vstorPacket,
sizeof(struct vstor_packet),
(unsigned long)requestExtension);
} else {
- ret = Device->Driver->VmbusChannelInterface.SendPacket(Device,
- vstorPacket,
- sizeof(struct vstor_packet),
- (unsigned long)requestExtension,
- VmbusPacketTypeDataInBand,
- VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
+ ret = vmbus_sendpacket(Device->channel, vstorPacket,
+ sizeof(struct vstor_packet),
+ (unsigned long)requestExtension,
+ VmbusPacketTypeDataInBand,
+ VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
}
if (ret != 0) {
@@ -777,29 +749,23 @@ static int StorVscOnIORequest(struct hv_device *Device,
atomic_inc(&storDevice->NumOutstandingRequests);
PutStorDevice(Device);
-
- DPRINT_EXIT(STORVSC);
return ret;
}
-/**
+/*
* StorVscOnCleanup - Perform any cleanup when the driver is removed
*/
static void StorVscOnCleanup(struct hv_driver *Driver)
{
- DPRINT_ENTER(STORVSC);
- DPRINT_EXIT(STORVSC);
}
-/**
+/*
* StorVscInitialize - Main entry point
*/
int StorVscInitialize(struct hv_driver *Driver)
{
struct storvsc_driver_object *storDriver;
- DPRINT_ENTER(STORVSC);
-
storDriver = (struct storvsc_driver_object *)Driver;
DPRINT_DBG(STORVSC, "sizeof(STORVSC_REQUEST)=%zd "
@@ -812,7 +778,7 @@ int StorVscInitialize(struct hv_driver *Driver)
sizeof(struct vmscsi_request));
/* Make sure we are at least 2 pages since 1 page is used for control */
- ASSERT(storDriver->RingBufferSize >= (PAGE_SIZE << 1));
+ /* ASSERT(storDriver->RingBufferSize >= (PAGE_SIZE << 1)); */
Driver->name = gDriverName;
memcpy(&Driver->deviceType, &gStorVscDeviceType,
@@ -824,7 +790,7 @@ int StorVscInitialize(struct hv_driver *Driver)
* Divide the ring buffer data size (which is 1 page less
* than the ring buffer size since that page is reserved for
* the ring buffer indices) by the max request size (which is
- * VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER + struct vstor_packet + u64)
+ * vmbus_channel_packet_multipage_buffer + struct vstor_packet + u64)
*/
storDriver->MaxOutstandingRequestsPerChannel =
((storDriver->RingBufferSize - PAGE_SIZE) /
@@ -842,9 +808,6 @@ int StorVscInitialize(struct hv_driver *Driver)
storDriver->Base.OnCleanup = StorVscOnCleanup;
storDriver->OnIORequest = StorVscOnIORequest;
- storDriver->OnHostReset = StorVscOnHostReset;
-
- DPRINT_EXIT(STORVSC);
return 0;
}
diff --git a/drivers/staging/hv/StorVscApi.h b/drivers/staging/hv/storvsc_api.h
index 69c1406..8505a1c 100644
--- a/drivers/staging/hv/StorVscApi.h
+++ b/drivers/staging/hv/storvsc_api.h
@@ -25,13 +25,13 @@
#ifndef _STORVSC_API_H_
#define _STORVSC_API_H_
-#include "VmbusApi.h"
+#include "vmbus_api.h"
/* Defines */
-#define STORVSC_RING_BUFFER_SIZE (10*PAGE_SIZE)
+#define STORVSC_RING_BUFFER_SIZE (20*PAGE_SIZE)
#define BLKVSC_RING_BUFFER_SIZE (20*PAGE_SIZE)
-#define STORVSC_MAX_IO_REQUESTS 64
+#define STORVSC_MAX_IO_REQUESTS 128
/*
* In Hyper-V, each port/path/target maps to 1 scsi host adapter. In
@@ -91,13 +91,9 @@ struct storvsc_driver_object {
/* Maximum # of requests in flight per channel/device */
u32 MaxOutstandingRequestsPerChannel;
- /* Set by the caller to allow us to re-enumerate the bus on the host */
- void (*OnHostRescan)(struct hv_device *Device);
-
/* Specific to this driver */
int (*OnIORequest)(struct hv_device *Device,
struct hv_storvsc_request *Request);
- int (*OnHostReset)(struct hv_device *Device);
};
struct storvsc_device_info {
@@ -108,6 +104,7 @@ struct storvsc_device_info {
/* Interface */
int StorVscInitialize(struct hv_driver *driver);
+int StorVscOnHostReset(struct hv_device *Device);
int BlkVscInitialize(struct hv_driver *driver);
#endif /* _STORVSC_API_H_ */
diff --git a/drivers/staging/hv/storvsc_drv.c b/drivers/staging/hv/storvsc_drv.c
index d49dc21..6f8d67d 100644
--- a/drivers/staging/hv/storvsc_drv.c
+++ b/drivers/staging/hv/storvsc_drv.c
@@ -19,6 +19,7 @@
* Hank Janssen <hjanssen@microsoft.com>
*/
#include <linux/init.h>
+#include <linux/slab.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/blkdev.h>
@@ -32,17 +33,16 @@
#include <scsi/scsi_dbg.h>
#include "osd.h"
#include "logging.h"
+#include "version_info.h"
#include "vmbus.h"
-#include "StorVscApi.h"
+#include "storvsc_api.h"
struct host_device_context {
/* must be 1st field
* FIXME this is a bug */
- struct work_struct host_rescan_work;
-
/* point back to our device context */
- struct device_context *device_ctx;
+ struct vm_device *device_ctx;
struct kmem_cache *request_pool;
unsigned int port;
unsigned char path;
@@ -72,13 +72,10 @@ struct storvsc_driver_context {
/* Static decl */
static int storvsc_probe(struct device *dev);
-static int storvsc_queuecommand(struct scsi_cmnd *scmnd,
- void (*done)(struct scsi_cmnd *));
+static int storvsc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *scmnd);
static int storvsc_device_alloc(struct scsi_device *);
static int storvsc_device_configure(struct scsi_device *);
static int storvsc_host_reset_handler(struct scsi_cmnd *scmnd);
-static void storvsc_host_rescan_callback(struct work_struct *work);
-static void storvsc_host_rescan(struct hv_device *device_obj);
static int storvsc_remove(struct device *dev);
static struct scatterlist *create_bounce_buffer(struct scatterlist *sgl,
@@ -94,13 +91,13 @@ static unsigned int copy_to_bounce_buffer(struct scatterlist *orig_sgl,
struct scatterlist *bounce_sgl,
unsigned int orig_sgl_count);
-static int storvsc_report_luns(struct scsi_device *sdev, unsigned int luns[],
- unsigned int *lun_count);
static int storvsc_get_chs(struct scsi_device *sdev, struct block_device *bdev,
sector_t capacity, int *info);
static int storvsc_ringbuffer_size = STORVSC_RING_BUFFER_SIZE;
+module_param(storvsc_ringbuffer_size, int, S_IRUGO);
+MODULE_PARM_DESC(storvsc_ringbuffer_size, "Ring buffer size (bytes)");
/* The one and only one */
static struct storvsc_driver_context g_storvsc_drv;
@@ -116,7 +113,7 @@ static struct scsi_host_template scsi_driver = {
.slave_configure = storvsc_device_configure,
.cmd_per_lun = 1,
/* 64 max_queue * 1 target */
- .can_queue = STORVSC_MAX_IO_REQUESTS*STORVSC_MAX_TARGETS,
+ .can_queue = STORVSC_MAX_IO_REQUESTS*STORVSC_MAX_TARGETS,
.this_id = -1,
/* no use setting to 0 since ll_blk_rw reset it to 1 */
/* currently 32 */
@@ -134,7 +131,7 @@ static struct scsi_host_template scsi_driver = {
};
-/**
+/*
* storvsc_drv_init - StorVsc driver initialization.
*/
static int storvsc_drv_init(int (*drv_init)(struct hv_driver *drv))
@@ -143,12 +140,7 @@ static int storvsc_drv_init(int (*drv_init)(struct hv_driver *drv))
struct storvsc_driver_object *storvsc_drv_obj = &g_storvsc_drv.drv_obj;
struct driver_context *drv_ctx = &g_storvsc_drv.drv_ctx;
- DPRINT_ENTER(STORVSC_DRV);
-
- vmbus_get_interface(&storvsc_drv_obj->Base.VmbusChannelInterface);
-
storvsc_drv_obj->RingBufferSize = storvsc_ringbuffer_size;
- storvsc_drv_obj->OnHostRescan = storvsc_host_rescan;
/* Callback to client driver to complete the initialization */
drv_init(&storvsc_drv_obj->Base);
@@ -178,8 +170,6 @@ static int storvsc_drv_init(int (*drv_init)(struct hv_driver *drv))
/* The driver belongs to vmbus */
ret = vmbus_child_driver_register(drv_ctx);
- DPRINT_EXIT(STORVSC_DRV);
-
return ret;
}
@@ -197,8 +187,6 @@ static void storvsc_drv_exit(void)
struct device *current_dev = NULL;
int ret;
- DPRINT_ENTER(STORVSC_DRV);
-
while (1) {
current_dev = NULL;
@@ -222,13 +210,10 @@ static void storvsc_drv_exit(void)
storvsc_drv_obj->Base.OnCleanup(&storvsc_drv_obj->Base);
vmbus_child_driver_unregister(drv_ctx);
-
- DPRINT_EXIT(STORVSC_DRV);
-
return;
}
-/**
+/*
* storvsc_probe - Add a new device for this driver
*/
static int storvsc_probe(struct device *device)
@@ -240,14 +225,12 @@ static int storvsc_probe(struct device *device)
(struct storvsc_driver_context *)driver_ctx;
struct storvsc_driver_object *storvsc_drv_obj =
&storvsc_drv_ctx->drv_obj;
- struct device_context *device_ctx = device_to_device_context(device);
+ struct vm_device *device_ctx = device_to_vm_device(device);
struct hv_device *device_obj = &device_ctx->device_obj;
struct Scsi_Host *host;
struct host_device_context *host_device_ctx;
struct storvsc_device_info device_info;
- DPRINT_ENTER(STORVSC_DRV);
-
if (!storvsc_drv_obj->Base.OnDeviceAdd)
return -1;
@@ -266,9 +249,6 @@ static int storvsc_probe(struct device *device)
host_device_ctx->port = host->host_no;
host_device_ctx->device_ctx = device_ctx;
- INIT_WORK(&host_device_ctx->host_rescan_work,
- storvsc_host_rescan_callback);
-
host_device_ctx->request_pool =
kmem_cache_create(dev_name(&device_ctx->device),
sizeof(struct storvsc_cmd_request) +
@@ -277,8 +257,6 @@ static int storvsc_probe(struct device *device)
if (!host_device_ctx->request_pool) {
scsi_host_put(host);
- DPRINT_EXIT(STORVSC_DRV);
-
return -ENOMEM;
}
@@ -290,8 +268,6 @@ static int storvsc_probe(struct device *device)
DPRINT_ERR(STORVSC_DRV, "unable to add scsi vsc device");
kmem_cache_destroy(host_device_ctx->request_pool);
scsi_host_put(host);
- DPRINT_EXIT(STORVSC_DRV);
-
return -1;
}
@@ -315,19 +291,14 @@ static int storvsc_probe(struct device *device)
kmem_cache_destroy(host_device_ctx->request_pool);
scsi_host_put(host);
- DPRINT_EXIT(STORVSC_DRV);
-
return -1;
}
scsi_scan_host(host);
-
- DPRINT_EXIT(STORVSC_DRV);
-
return ret;
}
-/**
+/*
* storvsc_remove - Callback when our device is removed
*/
static int storvsc_remove(struct device *device)
@@ -339,19 +310,15 @@ static int storvsc_remove(struct device *device)
(struct storvsc_driver_context *)driver_ctx;
struct storvsc_driver_object *storvsc_drv_obj =
&storvsc_drv_ctx->drv_obj;
- struct device_context *device_ctx = device_to_device_context(device);
+ struct vm_device *device_ctx = device_to_vm_device(device);
struct hv_device *device_obj = &device_ctx->device_obj;
struct Scsi_Host *host = dev_get_drvdata(device);
struct host_device_context *host_device_ctx =
(struct host_device_context *)host->hostdata;
- DPRINT_ENTER(STORVSC_DRV);
-
- if (!storvsc_drv_obj->Base.OnDeviceRemove) {
- DPRINT_EXIT(STORVSC_DRV);
+ if (!storvsc_drv_obj->Base.OnDeviceRemove)
return -1;
- }
/*
* Call to the vsc driver to let it know that the device is being
@@ -374,13 +341,10 @@ static int storvsc_remove(struct device *device)
DPRINT_INFO(STORVSC, "releasing host adapter (%p)...", host);
scsi_host_put(host);
-
- DPRINT_EXIT(STORVSC_DRV);
-
return ret;
}
-/**
+/*
* storvsc_commmand_completion - Command completion processing
*/
static void storvsc_commmand_completion(struct hv_storvsc_request *request)
@@ -393,13 +357,11 @@ static void storvsc_commmand_completion(struct hv_storvsc_request *request)
void (*scsi_done_fn)(struct scsi_cmnd *);
struct scsi_sense_hdr sense_hdr;
- ASSERT(request == &cmd_request->request);
- ASSERT((unsigned long)scmnd->host_scribble ==
- (unsigned long)cmd_request);
- ASSERT(scmnd);
- ASSERT(scmnd->scsi_done);
-
- DPRINT_ENTER(STORVSC_DRV);
+ /* ASSERT(request == &cmd_request->request); */
+ /* ASSERT(scmnd); */
+ /* ASSERT((unsigned long)scmnd->host_scribble == */
+ /* (unsigned long)cmd_request); */
+ /* ASSERT(scmnd->scsi_done); */
if (cmd_request->bounce_sgl_count) {
/* using bounce buffer */
@@ -421,7 +383,7 @@ static void storvsc_commmand_completion(struct hv_storvsc_request *request)
scsi_print_sense_hdr("storvsc", &sense_hdr);
}
- ASSERT(request->BytesXfer <= request->DataBuffer.Length);
+ /* ASSERT(request->BytesXfer <= request->DataBuffer.Length); */
scsi_set_resid(scmnd, request->DataBuffer.Length - request->BytesXfer);
scsi_done_fn = scmnd->scsi_done;
@@ -433,8 +395,6 @@ static void storvsc_commmand_completion(struct hv_storvsc_request *request)
scsi_done_fn(scmnd);
kmem_cache_free(host_device_ctx->request_pool, cmd_request);
-
- DPRINT_EXIT(STORVSC_DRV);
}
static int do_bounce_buffer(struct scatterlist *sgl, unsigned int sg_count)
@@ -530,9 +490,9 @@ static unsigned int copy_to_bounce_buffer(struct scatterlist *orig_sgl,
src = src_addr;
srclen = orig_sgl[i].length;
- ASSERT(orig_sgl[i].offset + orig_sgl[i].length <= PAGE_SIZE);
+ /* ASSERT(orig_sgl[i].offset + orig_sgl[i].length <= PAGE_SIZE); */
- if (j == 0)
+ if (bounce_addr == 0)
bounce_addr = (unsigned long)kmap_atomic(sg_page((&bounce_sgl[j])), KM_IRQ0);
while (srclen) {
@@ -591,9 +551,9 @@ static unsigned int copy_from_bounce_buffer(struct scatterlist *orig_sgl,
KM_IRQ0) + orig_sgl[i].offset;
dest = dest_addr;
destlen = orig_sgl[i].length;
- ASSERT(orig_sgl[i].offset + orig_sgl[i].length <= PAGE_SIZE);
+ /* ASSERT(orig_sgl[i].offset + orig_sgl[i].length <= PAGE_SIZE); */
- if (j == 0)
+ if (bounce_addr == 0)
bounce_addr = (unsigned long)kmap_atomic(sg_page((&bounce_sgl[j])), KM_IRQ0);
while (destlen) {
@@ -631,16 +591,16 @@ static unsigned int copy_from_bounce_buffer(struct scatterlist *orig_sgl,
return total_copied;
}
-/**
+/*
* storvsc_queuecommand - Initiate command processing
*/
-static int storvsc_queuecommand(struct scsi_cmnd *scmnd,
+static int storvsc_queuecommand_lck(struct scsi_cmnd *scmnd,
void (*done)(struct scsi_cmnd *))
{
int ret;
struct host_device_context *host_device_ctx =
(struct host_device_context *)scmnd->device->host->hostdata;
- struct device_context *device_ctx = host_device_ctx->device_ctx;
+ struct vm_device *device_ctx = host_device_ctx->device_ctx;
struct driver_context *driver_ctx =
driver_to_driver_context(device_ctx->device.driver);
struct storvsc_driver_context *storvsc_drv_ctx =
@@ -652,8 +612,7 @@ static int storvsc_queuecommand(struct scsi_cmnd *scmnd,
unsigned int request_size = 0;
int i;
struct scatterlist *sgl;
-
- DPRINT_ENTER(STORVSC_DRV);
+ unsigned int sg_count = 0;
DPRINT_DBG(STORVSC_DRV, "scmnd %p dir %d, use_sg %d buf %p len %d "
"queue depth %d tagged %d", scmnd, scmnd->sc_data_direction,
@@ -663,7 +622,7 @@ static int storvsc_queuecommand(struct scsi_cmnd *scmnd,
/* If retrying, no need to prep the cmd */
if (scmnd->host_scribble) {
- ASSERT(scmnd->scsi_done != NULL);
+ /* ASSERT(scmnd->scsi_done != NULL); */
cmd_request =
(struct storvsc_cmd_request *)scmnd->host_scribble;
@@ -673,8 +632,8 @@ static int storvsc_queuecommand(struct scsi_cmnd *scmnd,
goto retry_request;
}
- ASSERT(scmnd->scsi_done == NULL);
- ASSERT(scmnd->host_scribble == NULL);
+ /* ASSERT(scmnd->scsi_done == NULL); */
+ /* ASSERT(scmnd->host_scribble == NULL); */
scmnd->scsi_done = done;
@@ -725,7 +684,7 @@ static int storvsc_queuecommand(struct scsi_cmnd *scmnd,
request->TargetId = scmnd->device->id;
request->LunId = scmnd->device->lun;
- ASSERT(scmnd->cmd_len <= 16);
+ /* ASSERT(scmnd->cmd_len <= 16); */
request->CdbLen = scmnd->cmd_len;
request->Cdb = scmnd->cmnd;
@@ -736,6 +695,7 @@ static int storvsc_queuecommand(struct scsi_cmnd *scmnd,
request->DataBuffer.Length = scsi_bufflen(scmnd);
if (scsi_sg_count(scmnd)) {
sgl = (struct scatterlist *)scsi_sglist(scmnd);
+ sg_count = scsi_sg_count(scmnd);
/* check if we need to bounce the sgl */
if (do_bounce_buffer(sgl, scsi_sg_count(scmnd)) != -1) {
@@ -770,24 +730,23 @@ static int storvsc_queuecommand(struct scsi_cmnd *scmnd,
scsi_sg_count(scmnd));
sgl = cmd_request->bounce_sgl;
+ sg_count = cmd_request->bounce_sgl_count;
}
request->DataBuffer.Offset = sgl[0].offset;
- for (i = 0; i < scsi_sg_count(scmnd); i++) {
- DPRINT_DBG(STORVSC_DRV, "sgl[%d] len %d offset %d \n",
+ for (i = 0; i < sg_count; i++) {
+ DPRINT_DBG(STORVSC_DRV, "sgl[%d] len %d offset %d\n",
i, sgl[i].length, sgl[i].offset);
request->DataBuffer.PfnArray[i] =
- page_to_pfn(sg_page((&sgl[i])));
+ page_to_pfn(sg_page((&sgl[i])));
}
} else if (scsi_sglist(scmnd)) {
- ASSERT(scsi_bufflen(scmnd) <= PAGE_SIZE);
+ /* ASSERT(scsi_bufflen(scmnd) <= PAGE_SIZE); */
request->DataBuffer.Offset =
virt_to_phys(scsi_sglist(scmnd)) & (PAGE_SIZE-1);
request->DataBuffer.PfnArray[0] =
virt_to_phys(scsi_sglist(scmnd)) >> PAGE_SHIFT;
- } else {
- ASSERT(scsi_bufflen(scmnd) == 0);
}
retry_request:
@@ -820,11 +779,11 @@ retry_request:
ret = SCSI_MLQUEUE_DEVICE_BUSY;
}
- DPRINT_EXIT(STORVSC_DRV);
-
return ret;
}
+static DEF_SCSI_QCMD(storvsc_queuecommand)
+
static int storvsc_merge_bvec(struct request_queue *q,
struct bvec_merge_data *bmd, struct bio_vec *bvec)
{
@@ -832,7 +791,7 @@ static int storvsc_merge_bvec(struct request_queue *q,
return bvec->bv_len;
}
-/**
+/*
* storvsc_device_configure - Configure the specified scsi device
*/
static int storvsc_device_alloc(struct scsi_device *sdevice)
@@ -871,7 +830,7 @@ static int storvsc_device_configure(struct scsi_device *sdevice)
return 0;
}
-/**
+/*
* storvsc_host_reset_handler - Reset the scsi HBA
*/
static int storvsc_host_reset_handler(struct scsi_cmnd *scmnd)
@@ -879,231 +838,22 @@ static int storvsc_host_reset_handler(struct scsi_cmnd *scmnd)
int ret;
struct host_device_context *host_device_ctx =
(struct host_device_context *)scmnd->device->host->hostdata;
- struct device_context *device_ctx = host_device_ctx->device_ctx;
- struct driver_context *driver_ctx =
- driver_to_driver_context(device_ctx->device.driver);
- struct storvsc_driver_context *storvsc_drv_ctx =
- (struct storvsc_driver_context *)driver_ctx;
-
- struct storvsc_driver_object *storvsc_drv_obj =
- &storvsc_drv_ctx->drv_obj;
-
- DPRINT_ENTER(STORVSC_DRV);
+ struct vm_device *device_ctx = host_device_ctx->device_ctx;
DPRINT_INFO(STORVSC_DRV, "sdev (%p) dev obj (%p) - host resetting...",
scmnd->device, &device_ctx->device_obj);
/* Invokes the vsc to reset the host/bus */
- ASSERT(storvsc_drv_obj->OnHostReset);
- ret = storvsc_drv_obj->OnHostReset(&device_ctx->device_obj);
- if (ret != 0) {
- DPRINT_EXIT(STORVSC_DRV);
+ ret = StorVscOnHostReset(&device_ctx->device_obj);
+ if (ret != 0)
return ret;
- }
DPRINT_INFO(STORVSC_DRV, "sdev (%p) dev obj (%p) - host reseted",
scmnd->device, &device_ctx->device_obj);
- DPRINT_EXIT(STORVSC_DRV);
-
return ret;
}
-/**
- * storvsc_host_rescan - Rescan the scsi HBA
- */
-static void storvsc_host_rescan_callback(struct work_struct *work)
-{
- struct hv_device *device_obj =
- &((struct host_device_context *)work)->device_ctx->device_obj;
- struct device_context *device_ctx = to_device_context(device_obj);
- struct Scsi_Host *host = dev_get_drvdata(&device_ctx->device);
- struct scsi_device *sdev;
- struct host_device_context *host_device_ctx;
- struct scsi_device **sdevs_remove_list;
- unsigned int sdevs_count = 0;
- unsigned int found;
- unsigned int i;
- unsigned int lun_count = 0;
- unsigned int *lun_list;
-
- DPRINT_ENTER(STORVSC_DRV);
-
- host_device_ctx = (struct host_device_context *)host->hostdata;
- lun_list = kcalloc(STORVSC_MAX_LUNS_PER_TARGET, sizeof(unsigned int),
- GFP_ATOMIC);
- if (!lun_list) {
- DPRINT_ERR(STORVSC_DRV, "unable to allocate lun list");
- return;
- }
-
- sdevs_remove_list = kcalloc(STORVSC_MAX_LUNS_PER_TARGET,
- sizeof(void *), GFP_ATOMIC);
- if (!sdevs_remove_list) {
- kfree(lun_list);
- DPRINT_ERR(STORVSC_DRV, "unable to allocate lun remove list");
- return;
- }
-
- DPRINT_INFO(STORVSC_DRV, "rescanning host for new scsi devices...");
-
- /* Rescan for new device */
- scsi_scan_target(&host->shost_gendev, host_device_ctx->path,
- host_device_ctx->target, SCAN_WILD_CARD, 1);
-
- DPRINT_INFO(STORVSC_DRV, "rescanning host for removed scsi device...");
-
- /* Use the 1st device to send the report luns cmd */
- shost_for_each_device(sdev, host) {
- lun_count = STORVSC_MAX_LUNS_PER_TARGET;
- storvsc_report_luns(sdev, lun_list, &lun_count);
-
- DPRINT_INFO(STORVSC_DRV,
- "report luns on scsi device (%p) found %u luns ",
- sdev, lun_count);
- DPRINT_INFO(STORVSC_DRV,
- "existing luns on scsi device (%p) host (%d)",
- sdev, host->host_no);
-
- scsi_device_put(sdev);
- break;
- }
-
- for (i = 0; i < lun_count; i++)
- DPRINT_INFO(STORVSC_DRV, "%d) lun %u", i, lun_list[i]);
-
- /* Rescan for devices that may have been removed.
- * We do not have to worry that new devices may have been added since
- * this callback is serialized by the workqueue ie add/remove are done
- * here.
- */
- shost_for_each_device(sdev, host) {
- /* See if this device is still here */
- found = 0;
- for (i = 0; i < lun_count; i++) {
- if (sdev->lun == lun_list[i]) {
- found = 1;
- break;
- }
- }
- if (!found) {
- DPRINT_INFO(STORVSC_DRV, "lun (%u) does not exists",
- sdev->lun);
- sdevs_remove_list[sdevs_count++] = sdev;
- }
- }
-
- /* Now remove the devices */
- for (i = 0; i < sdevs_count; i++) {
- DPRINT_INFO(STORVSC_DRV,
- "removing scsi device (%p) lun (%u)...",
- sdevs_remove_list[i], sdevs_remove_list[i]->lun);
-
- /* make sure it is not removed from underneath us */
- if (!scsi_device_get(sdevs_remove_list[i])) {
- scsi_remove_device(sdevs_remove_list[i]);
- scsi_device_put(sdevs_remove_list[i]);
- }
- }
-
- DPRINT_INFO(STORVSC_DRV, "rescan completed on dev obj (%p) "
- "target (%u) bus (%u)", device_obj,
- host_device_ctx->target, host_device_ctx->path);
-
- kfree(lun_list);
- kfree(sdevs_remove_list);
-
- DPRINT_EXIT(STORVSC_DRV);
-}
-
-static int storvsc_report_luns(struct scsi_device *sdev, unsigned int luns[],
- unsigned int *lun_count)
-{
- int i, j;
- unsigned int lun = 0;
- unsigned int num_luns;
- int result;
- unsigned char *data;
- struct scsi_sense_hdr sshdr;
- unsigned char cmd[16] = {0};
- /* Add 1 to cover the report_lun header */
- unsigned int report_len = 8 * (STORVSC_MAX_LUNS_PER_TARGET+1);
- unsigned long long *report_luns;
- const unsigned int in_lun_count = *lun_count;
-
- *lun_count = 0;
-
- report_luns = kzalloc(report_len, GFP_ATOMIC);
- if (!report_luns)
- return -ENOMEM;
-
- cmd[0] = REPORT_LUNS;
-
- /* cmd length */
- *(unsigned int *)&cmd[6] = cpu_to_be32(report_len);
-
- result = scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE,
- (unsigned char *)report_luns, report_len,
- &sshdr, 30 * HZ, 3, NULL);
- if (result != 0) {
- kfree(report_luns);
- return -EBUSY;
- }
-
- /* get the length from the first four bytes */
- report_len = be32_to_cpu(*(unsigned int *)&report_luns[0]);
-
- num_luns = (report_len / sizeof(unsigned long long));
- if (num_luns > in_lun_count) {
- kfree(report_luns);
- return -EINVAL;
- }
-
- *lun_count = num_luns;
-
- DPRINT_DBG(STORVSC_DRV,
- "report luns on scsi device (%p) found %u luns ",
- sdev, num_luns);
-
- /* lun id starts at 1 */
- for (i = 1; i < num_luns + 1; i++) {
- lun = 0;
- data = (unsigned char *)&report_luns[i];
- for (j = 0; j < sizeof(lun); j += 2) {
- lun = lun | (((data[j] << 8) | data[j + 1]) <<
- (j * 8));
- }
-
- luns[i-1] = lun;
- }
-
- kfree(report_luns);
- return 0;
-}
-
-static void storvsc_host_rescan(struct hv_device *device_obj)
-{
- struct device_context *device_ctx = to_device_context(device_obj);
- struct Scsi_Host *host = dev_get_drvdata(&device_ctx->device);
- struct host_device_context *host_device_ctx;
-
- DPRINT_ENTER(STORVSC_DRV);
-
- host_device_ctx = (struct host_device_context *)host->hostdata;
-
- DPRINT_INFO(STORVSC_DRV, "initiating rescan on dev obj (%p) "
- "target (%u) bus (%u)...", device_obj,
- host_device_ctx->target, host_device_ctx->path);
-
- /*
- * We need to queue this since the scanning may block and the caller
- * may be in an intr context
- */
- /* scsi_queue_work(host, &host_device_ctx->host_rescan_work); */
- schedule_work(&host_device_ctx->host_rescan_work);
- DPRINT_EXIT(STORVSC_DRV);
-}
-
static int storvsc_get_chs(struct scsi_device *sdev, struct block_device * bdev,
sector_t capacity, int *info)
{
@@ -1188,21 +938,18 @@ static int __init storvsc_init(void)
{
int ret;
- DPRINT_ENTER(STORVSC_DRV);
DPRINT_INFO(STORVSC_DRV, "Storvsc initializing....");
ret = storvsc_drv_init(StorVscInitialize);
- DPRINT_EXIT(STORVSC_DRV);
return ret;
}
static void __exit storvsc_exit(void)
{
- DPRINT_ENTER(STORVSC_DRV);
storvsc_drv_exit();
- DPRINT_ENTER(STORVSC_DRV);
}
MODULE_LICENSE("GPL");
-module_param(storvsc_ringbuffer_size, int, S_IRUGO);
+MODULE_VERSION(HV_DRV_VERSION);
+MODULE_DESCRIPTION("Microsoft Hyper-V virtual storage driver");
module_init(storvsc_init);
module_exit(storvsc_exit);
diff --git a/drivers/staging/hv/utils.h b/drivers/staging/hv/utils.h
new file mode 100644
index 0000000..7c07499
--- /dev/null
+++ b/drivers/staging/hv/utils.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2009, Microsoft Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * Authors:
+ * Haiyang Zhang <haiyangz@microsoft.com>
+ * Hank Janssen <hjanssen@microsoft.com>
+ */
+#ifndef __HV_UTILS_H_
+#define __HV_UTILS_H_
+
+/*
+ * Common header for Hyper-V ICs
+ */
+#define ICMSGTYPE_NEGOTIATE 0
+#define ICMSGTYPE_HEARTBEAT 1
+#define ICMSGTYPE_KVPEXCHANGE 2
+#define ICMSGTYPE_SHUTDOWN 3
+#define ICMSGTYPE_TIMESYNC 4
+#define ICMSGTYPE_VSS 5
+
+#define ICMSGHDRFLAG_TRANSACTION 1
+#define ICMSGHDRFLAG_REQUEST 2
+#define ICMSGHDRFLAG_RESPONSE 4
+
+#define HV_S_OK 0x00000000
+#define HV_E_FAIL 0x80004005
+#define HV_ERROR_NOT_SUPPORTED 0x80070032
+#define HV_ERROR_MACHINE_LOCKED 0x800704F7
+
+struct vmbuspipe_hdr {
+ u32 flags;
+ u32 msgsize;
+} __attribute__((packed));
+
+struct ic_version {
+ u16 major;
+ u16 minor;
+} __attribute__((packed));
+
+struct icmsg_hdr {
+ struct ic_version icverframe;
+ u16 icmsgtype;
+ struct ic_version icvermsg;
+ u16 icmsgsize;
+ u32 status;
+ u8 ictransaction_id;
+ u8 icflags;
+ u8 reserved[2];
+} __attribute__((packed));
+
+struct icmsg_negotiate {
+ u16 icframe_vercnt;
+ u16 icmsg_vercnt;
+ u32 reserved;
+ struct ic_version icversion_data[1]; /* any size array */
+} __attribute__((packed));
+
+struct shutdown_msg_data {
+ u32 reason_code;
+ u32 timeout_seconds;
+ u32 flags;
+ u8 display_message[2048];
+} __attribute__((packed));
+
+struct heartbeat_msg_data {
+ u64 seq_num;
+ u32 reserved[8];
+} __attribute__((packed));
+
+/* Time Sync IC defs */
+#define ICTIMESYNCFLAG_PROBE 0
+#define ICTIMESYNCFLAG_SYNC 1
+#define ICTIMESYNCFLAG_SAMPLE 2
+
+#ifdef __x86_64__
+#define WLTIMEDELTA 116444736000000000L /* in 100ns unit */
+#else
+#define WLTIMEDELTA 116444736000000000LL
+#endif
+
+struct ictimesync_data{
+ u64 parenttime;
+ u64 childtime;
+ u64 roundtriptime;
+ u8 flags;
+} __attribute__((packed));
+
+/* Index for each IC struct in array hv_cb_utils[] */
+#define HV_SHUTDOWN_MSG 0
+#define HV_TIMESYNC_MSG 1
+#define HV_HEARTBEAT_MSG 2
+
+struct hyperv_service_callback {
+ u8 msg_type;
+ char *log_msg;
+ unsigned char data[16];
+ struct vmbus_channel *channel;
+ void (*callback) (void *context);
+};
+
+extern void prep_negotiate_resp(struct icmsg_hdr *,
+ struct icmsg_negotiate *, u8 *);
+extern void chn_cb_negotiate(void *);
+extern struct hyperv_service_callback hv_cb_utils[];
+
+#endif /* __HV_UTILS_H_ */
diff --git a/drivers/staging/hv/VersionInfo.h b/drivers/staging/hv/version_info.h
index 9c3641d..35178f2 100644
--- a/drivers/staging/hv/VersionInfo.h
+++ b/drivers/staging/hv/version_info.h
@@ -24,8 +24,25 @@
#ifndef __HV_VERSION_INFO
#define __HV_VERSION_INFO
-static const char VersionDate[] = __DATE__;
-static const char VersionTime[] = __TIME__;
-static const char VersionDesc[] = "Version 2.0";
+/*
+ * We use the same version numbering for all Hyper-V modules.
+ *
+ * Definition of versioning is as follows;
+ *
+ * Major Number Changes for these scenarios;
+ * 1. When a new version of Windows Hyper-V
+ * is released.
+ * 2. A Major change has occurred in the
+ * Linux IC's.
+ * (For example the merge for the first time
+ * into the kernel) Every time the Major Number
+ * changes, the Revision number is reset to 0.
+ * Minor Number Changes when new functionality is added
+ * to the Linux IC's that is not a bug fix.
+ *
+ * 3.1 - Added completed hv_utils driver. Shutdown/Heartbeat/Timesync
+ */
+#define HV_DRV_VERSION "3.1"
+
#endif
diff --git a/drivers/staging/hv/Vmbus.c b/drivers/staging/hv/vmbus.c
index 35a023e..d449daf 100644
--- a/drivers/staging/hv/Vmbus.c
+++ b/drivers/staging/hv/vmbus.c
@@ -21,10 +21,11 @@
*/
#include <linux/kernel.h>
#include <linux/mm.h>
+#include <linux/slab.h>
#include "osd.h"
#include "logging.h"
-#include "VersionInfo.h"
-#include "VmbusPrivate.h"
+#include "version_info.h"
+#include "vmbus_private.h"
static const char *gDriverName = "vmbus";
@@ -51,47 +52,28 @@ static const struct hv_guid gVmbusDeviceId = {
static struct hv_driver *gDriver; /* vmbus driver object */
static struct hv_device *gDevice; /* vmbus root device */
-/**
+/*
* VmbusGetChannelOffers - Retrieve the channel offers from the parent partition
*/
static void VmbusGetChannelOffers(void)
{
- DPRINT_ENTER(VMBUS);
- VmbusChannelRequestOffers();
- DPRINT_EXIT(VMBUS);
+ vmbus_request_offers();
}
-/**
- * VmbusGetChannelInterface - Get the channel interface
- */
-static void VmbusGetChannelInterface(struct vmbus_channel_interface *Interface)
-{
- GetChannelInterface(Interface);
-}
-
-/**
- * VmbusGetChannelInfo - Get the device info for the specified device object
- */
-static void VmbusGetChannelInfo(struct hv_device *DeviceObject,
- struct hv_device_info *DeviceInfo)
-{
- GetChannelInfo(DeviceObject, DeviceInfo);
-}
-
-/**
+/*
* VmbusCreateChildDevice - Creates the child device on the bus that represents the channel offer
*/
struct hv_device *VmbusChildDeviceCreate(struct hv_guid *DeviceType,
struct hv_guid *DeviceInstance,
- void *Context)
+ struct vmbus_channel *channel)
{
struct vmbus_driver *vmbusDriver = (struct vmbus_driver *)gDriver;
return vmbusDriver->OnChildDeviceCreate(DeviceType, DeviceInstance,
- Context);
+ channel);
}
-/**
+/*
* VmbusChildDeviceAdd - Registers the child device with the vmbus
*/
int VmbusChildDeviceAdd(struct hv_device *ChildDevice)
@@ -101,7 +83,7 @@ int VmbusChildDeviceAdd(struct hv_device *ChildDevice)
return vmbusDriver->OnChildDeviceAdd(gDevice, ChildDevice);
}
-/**
+/*
* VmbusChildDeviceRemove Unregisters the child device from the vmbus
*/
void VmbusChildDeviceRemove(struct hv_device *ChildDevice)
@@ -111,7 +93,7 @@ void VmbusChildDeviceRemove(struct hv_device *ChildDevice)
vmbusDriver->OnChildDeviceRemove(ChildDevice);
}
-/**
+/*
* VmbusOnDeviceAdd - Callback when the root bus device is added
*/
static int VmbusOnDeviceAdd(struct hv_device *dev, void *AdditionalInfo)
@@ -119,8 +101,6 @@ static int VmbusOnDeviceAdd(struct hv_device *dev, void *AdditionalInfo)
u32 *irqvector = AdditionalInfo;
int ret;
- DPRINT_ENTER(VMBUS);
-
gDevice = dev;
memcpy(&gDevice->deviceType, &gVmbusDeviceType, sizeof(struct hv_guid));
@@ -135,40 +115,33 @@ static int VmbusOnDeviceAdd(struct hv_device *dev, void *AdditionalInfo)
ret = VmbusConnect();
/* VmbusSendEvent(device->localPortId+1); */
- DPRINT_EXIT(VMBUS);
-
return ret;
}
-/**
+/*
* VmbusOnDeviceRemove - Callback when the root bus device is removed
*/
static int VmbusOnDeviceRemove(struct hv_device *dev)
{
int ret = 0;
- DPRINT_ENTER(VMBUS);
- VmbusChannelReleaseUnattachedChannels();
+ vmbus_release_unattached_channels();
VmbusDisconnect();
on_each_cpu(HvSynicCleanup, NULL, 1);
- DPRINT_EXIT(VMBUS);
-
return ret;
}
-/**
+/*
* VmbusOnCleanup - Perform any cleanup when the driver is removed
*/
static void VmbusOnCleanup(struct hv_driver *drv)
{
/* struct vmbus_driver *driver = (struct vmbus_driver *)drv; */
- DPRINT_ENTER(VMBUS);
HvCleanup();
- DPRINT_EXIT(VMBUS);
}
-/**
+/*
* VmbusOnMsgDPC - DPC routine to handle messages from the hypervisior
*/
static void VmbusOnMsgDPC(struct hv_driver *drv)
@@ -184,13 +157,12 @@ static void VmbusOnMsgDPC(struct hv_driver *drv)
/* no msg */
break;
} else {
- copied = kmalloc(sizeof(*copied), GFP_ATOMIC);
+ copied = kmemdup(msg, sizeof(*copied), GFP_ATOMIC);
if (copied == NULL)
continue;
- memcpy(copied, msg, sizeof(*copied));
osd_schedule_callback(gVmbusConnection.WorkQueue,
- VmbusOnChannelMessage,
+ vmbus_onmessage,
(void *)copied);
}
@@ -216,7 +188,7 @@ static void VmbusOnMsgDPC(struct hv_driver *drv)
}
}
-/**
+/*
* VmbusOnEventDPC - DPC routine to handle events from the hypervisior
*/
static void VmbusOnEventDPC(struct hv_driver *drv)
@@ -225,7 +197,7 @@ static void VmbusOnEventDPC(struct hv_driver *drv)
VmbusOnEvents();
}
-/**
+/*
* VmbusOnISR - ISR routine
*/
static int VmbusOnISR(struct hv_driver *drv)
@@ -239,8 +211,6 @@ static int VmbusOnISR(struct hv_driver *drv)
page_addr = gHvContext.synICMessagePage[cpu];
msg = (struct hv_message *)page_addr + VMBUS_MESSAGE_SINT;
- DPRINT_ENTER(VMBUS);
-
/* Check if there are actual msgs to be process */
if (msg->Header.MessageType != HvMessageTypeNone) {
DPRINT_DBG(VMBUS, "received msg type %d size %d",
@@ -259,11 +229,10 @@ static int VmbusOnISR(struct hv_driver *drv)
ret |= 0x2;
}
- DPRINT_EXIT(VMBUS);
return ret;
}
-/**
+/*
* VmbusInitialize - Main entry point
*/
int VmbusInitialize(struct hv_driver *drv)
@@ -271,20 +240,16 @@ int VmbusInitialize(struct hv_driver *drv)
struct vmbus_driver *driver = (struct vmbus_driver *)drv;
int ret;
- DPRINT_ENTER(VMBUS);
-
- DPRINT_INFO(VMBUS, "+++++++ Build Date=%s %s +++++++",
- VersionDate, VersionTime);
- DPRINT_INFO(VMBUS, "+++++++ Build Description=%s +++++++",
- VersionDesc);
+ DPRINT_INFO(VMBUS, "+++++++ HV Driver version = %s +++++++",
+ HV_DRV_VERSION);
DPRINT_INFO(VMBUS, "+++++++ Vmbus supported version = %d +++++++",
VMBUS_REVISION_NUMBER);
DPRINT_INFO(VMBUS, "+++++++ Vmbus using SINT %d +++++++",
VMBUS_MESSAGE_SINT);
- DPRINT_DBG(VMBUS, "sizeof(VMBUS_CHANNEL_PACKET_PAGE_BUFFER)=%zd, "
+ DPRINT_DBG(VMBUS, "sizeof(vmbus_channel_packet_page_buffer)=%zd, "
"sizeof(VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER)=%zd",
- sizeof(struct VMBUS_CHANNEL_PACKET_PAGE_BUFFER),
- sizeof(struct VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER));
+ sizeof(struct vmbus_channel_packet_page_buffer),
+ sizeof(struct vmbus_channel_packet_multipage_buffer));
drv->name = gDriverName;
memcpy(&drv->deviceType, &gVmbusDeviceType, sizeof(struct hv_guid));
@@ -297,8 +262,6 @@ int VmbusInitialize(struct hv_driver *drv)
driver->OnMsgDpc = VmbusOnMsgDPC;
driver->OnEventDpc = VmbusOnEventDPC;
driver->GetChannelOffers = VmbusGetChannelOffers;
- driver->GetChannelInterface = VmbusGetChannelInterface;
- driver->GetChannelInfo = VmbusGetChannelInfo;
/* Hypervisor initialization...setup hypercall page..etc */
ret = HvInit();
@@ -307,7 +270,5 @@ int VmbusInitialize(struct hv_driver *drv)
ret);
gDriver = drv;
- DPRINT_EXIT(VMBUS);
-
return ret;
}
diff --git a/drivers/staging/hv/vmbus.h b/drivers/staging/hv/vmbus.h
index ae0a896..42f2adb 100644
--- a/drivers/staging/hv/vmbus.h
+++ b/drivers/staging/hv/vmbus.h
@@ -26,7 +26,7 @@
#define _VMBUS_H_
#include <linux/device.h>
-#include "VmbusApi.h"
+#include "vmbus_api.h"
struct driver_context {
struct hv_guid class_id;
@@ -43,23 +43,23 @@ struct driver_context {
void (*shutdown)(struct device *);
};
-struct device_context {
+struct vm_device {
struct work_struct probe_failed_work_item;
struct hv_guid class_id;
struct hv_guid device_id;
int probe_error;
- struct device device;
struct hv_device device_obj;
+ struct device device;
};
-static inline struct device_context *to_device_context(struct hv_device *d)
+static inline struct vm_device *to_vm_device(struct hv_device *d)
{
- return container_of(d, struct device_context, device_obj);
+ return container_of(d, struct vm_device, device_obj);
}
-static inline struct device_context *device_to_device_context(struct device *d)
+static inline struct vm_device *device_to_vm_device(struct device *d)
{
- return container_of(d, struct device_context, device);
+ return container_of(d, struct vm_device, device);
}
static inline struct driver_context *driver_to_driver_context(struct device_driver *d)
@@ -69,9 +69,9 @@ static inline struct driver_context *driver_to_driver_context(struct device_driv
/* Vmbus interface */
-
int vmbus_child_driver_register(struct driver_context *driver_ctx);
void vmbus_child_driver_unregister(struct driver_context *driver_ctx);
-void vmbus_get_interface(struct vmbus_channel_interface *interface);
+
+extern struct completion hv_channel_ready;
#endif /* _VMBUS_H_ */
diff --git a/drivers/staging/hv/VmbusApi.h b/drivers/staging/hv/vmbus_api.h
index d089bb1..2af42e5 100644
--- a/drivers/staging/hv/VmbusApi.h
+++ b/drivers/staging/hv/vmbus_api.h
@@ -84,33 +84,6 @@ struct hv_device_info {
struct hv_dev_port_info Outbound;
};
-struct vmbus_channel_interface {
- int (*Open)(struct hv_device *Device, u32 SendBufferSize,
- u32 RecvRingBufferSize, void *UserData, u32 UserDataLen,
- void (*ChannelCallback)(void *context),
- void *Context);
- void (*Close)(struct hv_device *device);
- int (*SendPacket)(struct hv_device *Device, const void *Buffer,
- u32 BufferLen, u64 RequestId, u32 Type, u32 Flags);
- int (*SendPacketPageBuffer)(struct hv_device *dev,
- struct hv_page_buffer PageBuffers[],
- u32 PageCount, void *Buffer, u32 BufferLen,
- u64 RequestId);
- int (*SendPacketMultiPageBuffer)(struct hv_device *device,
- struct hv_multipage_buffer *mpb,
- void *Buffer,
- u32 BufferLen,
- u64 RequestId);
- int (*RecvPacket)(struct hv_device *dev, void *buf, u32 buflen,
- u32 *BufferActualLen, u64 *RequestId);
- int (*RecvPacketRaw)(struct hv_device *dev, void *buf, u32 buflen,
- u32 *BufferActualLen, u64 *RequestId);
- int (*EstablishGpadl)(struct hv_device *dev, void *buf, u32 buflen,
- u32 *GpadlHandle);
- int (*TeardownGpadl)(struct hv_device *device, u32 GpadlHandle);
- void (*GetInfo)(struct hv_device *dev, struct hv_device_info *devinfo);
-};
-
/* Base driver object */
struct hv_driver {
const char *name;
@@ -121,8 +94,6 @@ struct hv_driver {
int (*OnDeviceAdd)(struct hv_device *device, void *data);
int (*OnDeviceRemove)(struct hv_device *device);
void (*OnCleanup)(struct hv_driver *driver);
-
- struct vmbus_channel_interface VmbusChannelInterface;
};
/* Base device object */
@@ -138,7 +109,7 @@ struct hv_device {
/* the device instance id of this device */
struct hv_guid deviceInstance;
- void *context;
+ struct vmbus_channel *channel;
/* Device extension; */
void *Extension;
@@ -153,7 +124,7 @@ struct vmbus_driver {
/* Set by the caller */
struct hv_device * (*OnChildDeviceCreate)(struct hv_guid *DeviceType,
struct hv_guid *DeviceInstance,
- void *Context);
+ struct vmbus_channel *channel);
void (*OnChildDeviceDestroy)(struct hv_device *device);
int (*OnChildDeviceAdd)(struct hv_device *RootDevice,
struct hv_device *ChildDevice);
@@ -164,10 +135,6 @@ struct vmbus_driver {
void (*OnMsgDpc)(struct hv_driver *driver);
void (*OnEventDpc)(struct hv_driver *driver);
void (*GetChannelOffers)(void);
-
- void (*GetChannelInterface)(struct vmbus_channel_interface *i);
- void (*GetChannelInfo)(struct hv_device *dev,
- struct hv_device_info *devinfo);
};
int VmbusInitialize(struct hv_driver *drv);
diff --git a/drivers/staging/hv/VmbusChannelInterface.h b/drivers/staging/hv/vmbus_channel_interface.h
index 2674282..2674282 100644
--- a/drivers/staging/hv/VmbusChannelInterface.h
+++ b/drivers/staging/hv/vmbus_channel_interface.h
diff --git a/drivers/staging/hv/vmbus_drv.c b/drivers/staging/hv/vmbus_drv.c
index 894eecf..0d9f3a4 100644
--- a/drivers/staging/hv/vmbus_drv.c
+++ b/drivers/staging/hv/vmbus_drv.c
@@ -24,9 +24,15 @@
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/sysctl.h>
+#include <linux/pci.h>
+#include <linux/dmi.h>
+#include <linux/slab.h>
+#include <linux/completion.h>
+#include "version_info.h"
#include "osd.h"
#include "logging.h"
#include "vmbus.h"
+#include "channel.h"
/* FIXME! We need to do this dynamically for PIC and APIC system */
@@ -47,7 +53,7 @@ struct vmbus_driver_context {
struct tasklet_struct event_dpc;
/* The bus root device */
- struct device_context device_ctx;
+ struct vm_device device_ctx;
};
static int vmbus_match(struct device *device, struct device_driver *driver);
@@ -65,13 +71,11 @@ static void vmbus_bus_release(struct device *device);
static struct hv_device *vmbus_child_device_create(struct hv_guid *type,
struct hv_guid *instance,
- void *context);
+ struct vmbus_channel *channel);
static void vmbus_child_device_destroy(struct hv_device *device_obj);
static int vmbus_child_device_register(struct hv_device *root_device_obj,
struct hv_device *child_device_obj);
static void vmbus_child_device_unregister(struct hv_device *child_device_obj);
-static void vmbus_child_device_get_info(struct hv_device *device_obj,
- struct hv_device_info *device_info);
static ssize_t vmbus_show_device_attr(struct device *dev,
struct device_attribute *dev_attr,
char *buf);
@@ -125,7 +129,48 @@ static struct vmbus_driver_context g_vmbus_drv = {
.bus.dev_attrs = vmbus_device_attrs,
};
-/**
+static void get_channel_info(struct hv_device *device,
+ struct hv_device_info *info)
+{
+ struct vmbus_channel_debug_info debug_info;
+
+ if (!device->channel)
+ return;
+
+ vmbus_get_debug_info(device->channel, &debug_info);
+
+ info->ChannelId = debug_info.RelId;
+ info->ChannelState = debug_info.State;
+ memcpy(&info->ChannelType, &debug_info.InterfaceType,
+ sizeof(struct hv_guid));
+ memcpy(&info->ChannelInstance, &debug_info.InterfaceInstance,
+ sizeof(struct hv_guid));
+
+ info->MonitorId = debug_info.MonitorId;
+
+ info->ServerMonitorPending = debug_info.ServerMonitorPending;
+ info->ServerMonitorLatency = debug_info.ServerMonitorLatency;
+ info->ServerMonitorConnectionId = debug_info.ServerMonitorConnectionId;
+
+ info->ClientMonitorPending = debug_info.ClientMonitorPending;
+ info->ClientMonitorLatency = debug_info.ClientMonitorLatency;
+ info->ClientMonitorConnectionId = debug_info.ClientMonitorConnectionId;
+
+ info->Inbound.InterruptMask = debug_info.Inbound.CurrentInterruptMask;
+ info->Inbound.ReadIndex = debug_info.Inbound.CurrentReadIndex;
+ info->Inbound.WriteIndex = debug_info.Inbound.CurrentWriteIndex;
+ info->Inbound.BytesAvailToRead = debug_info.Inbound.BytesAvailToRead;
+ info->Inbound.BytesAvailToWrite = debug_info.Inbound.BytesAvailToWrite;
+
+ info->Outbound.InterruptMask = debug_info.Outbound.CurrentInterruptMask;
+ info->Outbound.ReadIndex = debug_info.Outbound.CurrentReadIndex;
+ info->Outbound.WriteIndex = debug_info.Outbound.CurrentWriteIndex;
+ info->Outbound.BytesAvailToRead = debug_info.Outbound.BytesAvailToRead;
+ info->Outbound.BytesAvailToWrite =
+ debug_info.Outbound.BytesAvailToWrite;
+}
+
+/*
* vmbus_show_device_attr - Show the device attribute in sysfs.
*
* This is invoked when user does a
@@ -135,12 +180,12 @@ static ssize_t vmbus_show_device_attr(struct device *dev,
struct device_attribute *dev_attr,
char *buf)
{
- struct device_context *device_ctx = device_to_device_context(dev);
+ struct vm_device *device_ctx = device_to_vm_device(dev);
struct hv_device_info device_info;
memset(&device_info, 0, sizeof(struct hv_device_info));
- vmbus_child_device_get_info(&device_ctx->device_obj, &device_info);
+ get_channel_info(&device_ctx->device_obj, &device_info);
if (!strcmp(dev_attr->attr.name, "class_id")) {
return sprintf(buf, "{%02x%02x%02x%02x-%02x%02x-%02x%02x-"
@@ -229,28 +274,26 @@ static ssize_t vmbus_show_device_attr(struct device *dev,
}
}
-/**
+/*
* vmbus_bus_init -Main vmbus driver initialization routine.
*
* Here, we
- * - initialize the vmbus driver context
- * - setup various driver entry points
- * - invoke the vmbus hv main init routine
- * - get the irq resource
- * - invoke the vmbus to add the vmbus root device
- * - setup the vmbus root device
- * - retrieve the channel offers
+ * - initialize the vmbus driver context
+ * - setup various driver entry points
+ * - invoke the vmbus hv main init routine
+ * - get the irq resource
+ * - invoke the vmbus to add the vmbus root device
+ * - setup the vmbus root device
+ * - retrieve the channel offers
*/
static int vmbus_bus_init(int (*drv_init)(struct hv_driver *drv))
{
struct vmbus_driver_context *vmbus_drv_ctx = &g_vmbus_drv;
struct vmbus_driver *vmbus_drv_obj = &g_vmbus_drv.drv_obj;
- struct device_context *dev_ctx = &g_vmbus_drv.device_ctx;
+ struct vm_device *dev_ctx = &g_vmbus_drv.device_ctx;
int ret;
unsigned int vector;
- DPRINT_ENTER(VMBUS_DRV);
-
/*
* Set this up to allow lower layer to callback to add/remove child
* devices on the bus
@@ -307,7 +350,7 @@ static int vmbus_bus_init(int (*drv_init)(struct hv_driver *drv))
DPRINT_INFO(VMBUS_DRV, "irq 0x%x vector 0x%x", vmbus_irq, vector);
/* Call to bus driver to add the root device */
- memset(dev_ctx, 0, sizeof(struct device_context));
+ memset(dev_ctx, 0, sizeof(struct vm_device));
ret = vmbus_drv_obj->Base.OnDeviceAdd(&dev_ctx->device_obj, &vector);
if (ret != 0) {
@@ -352,13 +395,13 @@ static int vmbus_bus_init(int (*drv_init)(struct hv_driver *drv))
vmbus_drv_obj->GetChannelOffers();
-cleanup:
- DPRINT_EXIT(VMBUS_DRV);
+ wait_for_completion(&hv_channel_ready);
+cleanup:
return ret;
}
-/**
+/*
* vmbus_bus_exit - Terminate the vmbus driver.
*
* This routine is opposite of vmbus_bus_init()
@@ -368,9 +411,7 @@ static void vmbus_bus_exit(void)
struct vmbus_driver *vmbus_drv_obj = &g_vmbus_drv.drv_obj;
struct vmbus_driver_context *vmbus_drv_ctx = &g_vmbus_drv;
- struct device_context *dev_ctx = &g_vmbus_drv.device_ctx;
-
- DPRINT_ENTER(VMBUS_DRV);
+ struct vm_device *dev_ctx = &g_vmbus_drv.device_ctx;
/* Remove the root device */
if (vmbus_drv_obj->Base.OnDeviceRemove)
@@ -388,22 +429,26 @@ static void vmbus_bus_exit(void)
tasklet_kill(&vmbus_drv_ctx->msg_dpc);
tasklet_kill(&vmbus_drv_ctx->event_dpc);
-
- DPRINT_EXIT(VMBUS_DRV);
-
- return;
}
+
/**
- * vmbus_child_driver_register - Register a vmbus's child driver
+ * vmbus_child_driver_register() - Register a vmbus's child driver
+ * @driver_ctx: Pointer to driver structure you want to register
+ *
+ * @driver_ctx is of type &struct driver_context
+ *
+ * Registers the given driver with Linux through the 'driver_register()' call
+ * And sets up the hyper-v vmbus handling for this driver.
+ * It will return the state of the 'driver_register()' call.
+ *
+ * Mainly used by Hyper-V drivers.
*/
int vmbus_child_driver_register(struct driver_context *driver_ctx)
{
struct vmbus_driver *vmbus_drv_obj = &g_vmbus_drv.drv_obj;
int ret;
- DPRINT_ENTER(VMBUS_DRV);
-
DPRINT_INFO(VMBUS_DRV, "child driver (%p) registering - name %s",
driver_ctx, driver_ctx->driver.name);
@@ -414,75 +459,48 @@ int vmbus_child_driver_register(struct driver_context *driver_ctx)
vmbus_drv_obj->GetChannelOffers();
- DPRINT_EXIT(VMBUS_DRV);
-
return ret;
}
EXPORT_SYMBOL(vmbus_child_driver_register);
/**
- * vmbus_child_driver_unregister Unregister a vmbus's child driver
+ * vmbus_child_driver_unregister() - Unregister a vmbus's child driver
+ * @driver_ctx: Pointer to driver structure you want to un-register
+ *
+ * @driver_ctx is of type &struct driver_context
+ *
+ * Un-register the given driver with Linux through the 'driver_unregister()'
+ * call. And ungegisters the driver from the Hyper-V vmbus handler.
+ *
+ * Mainly used by Hyper-V drivers.
*/
void vmbus_child_driver_unregister(struct driver_context *driver_ctx)
{
- DPRINT_ENTER(VMBUS_DRV);
-
DPRINT_INFO(VMBUS_DRV, "child driver (%p) unregistering - name %s",
driver_ctx, driver_ctx->driver.name);
driver_unregister(&driver_ctx->driver);
driver_ctx->driver.bus = NULL;
-
- DPRINT_EXIT(VMBUS_DRV);
}
EXPORT_SYMBOL(vmbus_child_driver_unregister);
-/**
- * vmbus_get_interface - Get the vmbus channel interface.
- *
- * This is invoked by child/client driver that sits above vmbus
- */
-void vmbus_get_interface(struct vmbus_channel_interface *interface)
-{
- struct vmbus_driver *vmbus_drv_obj = &g_vmbus_drv.drv_obj;
-
- vmbus_drv_obj->GetChannelInterface(interface);
-}
-EXPORT_SYMBOL(vmbus_get_interface);
-
-/**
- * vmbus_child_device_get_info - Get the vmbus child device info.
- *
- * This is invoked to display various device attributes in sysfs.
- */
-static void vmbus_child_device_get_info(struct hv_device *device_obj,
- struct hv_device_info *device_info)
-{
- struct vmbus_driver *vmbus_drv_obj = &g_vmbus_drv.drv_obj;
-
- vmbus_drv_obj->GetChannelInfo(device_obj, device_info);
-}
-
-/**
- * vmbus_child_device_create - Creates and registers a new child device on the vmbus.
+/*
+ * vmbus_child_device_create - Creates and registers a new child device
+ * on the vmbus.
*/
static struct hv_device *vmbus_child_device_create(struct hv_guid *type,
struct hv_guid *instance,
- void *context)
+ struct vmbus_channel *channel)
{
- struct device_context *child_device_ctx;
+ struct vm_device *child_device_ctx;
struct hv_device *child_device_obj;
- DPRINT_ENTER(VMBUS_DRV);
-
/* Allocate the new child device */
- child_device_ctx = kzalloc(sizeof(struct device_context), GFP_KERNEL);
+ child_device_ctx = kzalloc(sizeof(struct vm_device), GFP_KERNEL);
if (!child_device_ctx) {
DPRINT_ERR(VMBUS_DRV,
"unable to allocate device_context for child device");
- DPRINT_EXIT(VMBUS_DRV);
-
return NULL;
}
@@ -506,7 +524,7 @@ static struct hv_device *vmbus_child_device_create(struct hv_guid *type,
instance->data[14], instance->data[15]);
child_device_obj = &child_device_ctx->device_obj;
- child_device_obj->context = context;
+ child_device_obj->channel = channel;
memcpy(&child_device_obj->deviceType, type, sizeof(struct hv_guid));
memcpy(&child_device_obj->deviceInstance, instance,
sizeof(struct hv_guid));
@@ -514,26 +532,22 @@ static struct hv_device *vmbus_child_device_create(struct hv_guid *type,
memcpy(&child_device_ctx->class_id, type, sizeof(struct hv_guid));
memcpy(&child_device_ctx->device_id, instance, sizeof(struct hv_guid));
- DPRINT_EXIT(VMBUS_DRV);
-
return child_device_obj;
}
-/**
+/*
* vmbus_child_device_register - Register the child device on the specified bus
*/
static int vmbus_child_device_register(struct hv_device *root_device_obj,
struct hv_device *child_device_obj)
{
int ret = 0;
- struct device_context *root_device_ctx =
- to_device_context(root_device_obj);
- struct device_context *child_device_ctx =
- to_device_context(child_device_obj);
+ struct vm_device *root_device_ctx =
+ to_vm_device(root_device_obj);
+ struct vm_device *child_device_ctx =
+ to_vm_device(child_device_obj);
static atomic_t device_num = ATOMIC_INIT(0);
- DPRINT_ENTER(VMBUS_DRV);
-
DPRINT_DBG(VMBUS_DRV, "child device (%p) registering",
child_device_ctx);
@@ -562,19 +576,16 @@ static int vmbus_child_device_register(struct hv_device *root_device_obj,
DPRINT_INFO(VMBUS_DRV, "child device (%p) registered",
&child_device_ctx->device);
- DPRINT_EXIT(VMBUS_DRV);
-
return ret;
}
-/**
- * vmbus_child_device_unregister - Remove the specified child device from the vmbus.
+/*
+ * vmbus_child_device_unregister - Remove the specified child device
+ * from the vmbus.
*/
static void vmbus_child_device_unregister(struct hv_device *device_obj)
{
- struct device_context *device_ctx = to_device_context(device_obj);
-
- DPRINT_ENTER(VMBUS_DRV);
+ struct vm_device *device_ctx = to_vm_device(device_obj);
DPRINT_INFO(VMBUS_DRV, "unregistering child device (%p)",
&device_ctx->device);
@@ -587,21 +598,16 @@ static void vmbus_child_device_unregister(struct hv_device *device_obj)
DPRINT_INFO(VMBUS_DRV, "child device (%p) unregistered",
&device_ctx->device);
-
- DPRINT_EXIT(VMBUS_DRV);
}
-/**
+/*
* vmbus_child_device_destroy - Destroy the specified child device on the vmbus.
*/
static void vmbus_child_device_destroy(struct hv_device *device_obj)
{
- DPRINT_ENTER(VMBUS_DRV);
-
- DPRINT_EXIT(VMBUS_DRV);
}
-/**
+/*
* vmbus_uevent - add uevent for our device
*
* This routine is invoked when a device is added or removed on the vmbus to
@@ -610,11 +616,9 @@ static void vmbus_child_device_destroy(struct hv_device *device_obj)
*/
static int vmbus_uevent(struct device *device, struct kobj_uevent_env *env)
{
- struct device_context *device_ctx = device_to_device_context(device);
+ struct vm_device *device_ctx = device_to_vm_device(device);
int ret;
- DPRINT_ENTER(VMBUS_DRV);
-
DPRINT_INFO(VMBUS_DRV, "generating uevent - VMBUS_DEVICE_CLASS_GUID={"
"%02x%02x%02x%02x-%02x%02x-%02x%02x-"
"%02x%02x%02x%02x%02x%02x%02x%02x}",
@@ -675,21 +679,17 @@ static int vmbus_uevent(struct device *device, struct kobj_uevent_env *env)
if (ret)
return ret;
- DPRINT_EXIT(VMBUS_DRV);
-
return 0;
}
-/**
+/*
* vmbus_match - Attempt to match the specified device to the specified driver
*/
static int vmbus_match(struct device *device, struct device_driver *driver)
{
int match = 0;
struct driver_context *driver_ctx = driver_to_driver_context(driver);
- struct device_context *device_ctx = device_to_device_context(device);
-
- DPRINT_ENTER(VMBUS_DRV);
+ struct vm_device *device_ctx = device_to_vm_device(device);
/* We found our driver ? */
if (memcmp(&device_ctx->class_id, &driver_ctx->class_id,
@@ -709,13 +709,10 @@ static int vmbus_match(struct device *device, struct device_driver *driver)
match = 1;
}
-
- DPRINT_EXIT(VMBUS_DRV);
-
return match;
}
-/**
+/*
* vmbus_probe_failed_cb - Callback when a driver probe failed in vmbus_probe()
*
* We need a callback because we cannot invoked device_unregister() inside
@@ -724,9 +721,7 @@ static int vmbus_match(struct device *device, struct device_driver *driver)
*/
static void vmbus_probe_failed_cb(struct work_struct *context)
{
- struct device_context *device_ctx = (struct device_context *)context;
-
- DPRINT_ENTER(VMBUS_DRV);
+ struct vm_device *device_ctx = (struct vm_device *)context;
/*
* Kick off the process of unregistering the device.
@@ -735,10 +730,9 @@ static void vmbus_probe_failed_cb(struct work_struct *context)
device_unregister(&device_ctx->device);
/* put_device(&device_ctx->device); */
- DPRINT_EXIT(VMBUS_DRV);
}
-/**
+/*
* vmbus_probe - Add the new vmbus's child device
*/
static int vmbus_probe(struct device *child_device)
@@ -746,10 +740,8 @@ static int vmbus_probe(struct device *child_device)
int ret = 0;
struct driver_context *driver_ctx =
driver_to_driver_context(child_device->driver);
- struct device_context *device_ctx =
- device_to_device_context(child_device);
-
- DPRINT_ENTER(VMBUS_DRV);
+ struct vm_device *device_ctx =
+ device_to_vm_device(child_device);
/* Let the specific open-source driver handles the probe if it can */
if (driver_ctx->probe) {
@@ -769,12 +761,10 @@ static int vmbus_probe(struct device *child_device)
child_device->driver->name);
ret = -1;
}
-
- DPRINT_EXIT(VMBUS_DRV);
return ret;
}
-/**
+/*
* vmbus_remove - Remove a vmbus device
*/
static int vmbus_remove(struct device *child_device)
@@ -782,15 +772,12 @@ static int vmbus_remove(struct device *child_device)
int ret;
struct driver_context *driver_ctx;
- DPRINT_ENTER(VMBUS_DRV);
-
/* Special case root bus device */
if (child_device->parent == NULL) {
/*
* No-op since it is statically defined and handle in
* vmbus_bus_exit()
*/
- DPRINT_EXIT(VMBUS_DRV);
return 0;
}
@@ -811,35 +798,28 @@ static int vmbus_remove(struct device *child_device)
}
}
- DPRINT_EXIT(VMBUS_DRV);
-
return 0;
}
-/**
+/*
* vmbus_shutdown - Shutdown a vmbus device
*/
static void vmbus_shutdown(struct device *child_device)
{
struct driver_context *driver_ctx;
- DPRINT_ENTER(VMBUS_DRV);
-
/* Special case root bus device */
if (child_device->parent == NULL) {
/*
* No-op since it is statically defined and handle in
* vmbus_bus_exit()
*/
- DPRINT_EXIT(VMBUS_DRV);
return;
}
/* The device may not be attached yet */
- if (!child_device->driver) {
- DPRINT_EXIT(VMBUS_DRV);
+ if (!child_device->driver)
return;
- }
driver_ctx = driver_to_driver_context(child_device->driver);
@@ -847,75 +827,58 @@ static void vmbus_shutdown(struct device *child_device)
if (driver_ctx->shutdown)
driver_ctx->shutdown(child_device);
- DPRINT_EXIT(VMBUS_DRV);
-
return;
}
-/**
+/*
* vmbus_bus_release - Final callback release of the vmbus root device
*/
static void vmbus_bus_release(struct device *device)
{
- DPRINT_ENTER(VMBUS_DRV);
/* FIXME */
/* Empty release functions are a bug, or a major sign
* of a problem design, this MUST BE FIXED! */
dev_err(device, "%s needs to be fixed!\n", __func__);
WARN_ON(1);
- DPRINT_EXIT(VMBUS_DRV);
}
-/**
+/*
* vmbus_device_release - Final callback release of the vmbus child device
*/
static void vmbus_device_release(struct device *device)
{
- struct device_context *device_ctx = device_to_device_context(device);
-
- DPRINT_ENTER(VMBUS_DRV);
+ struct vm_device *device_ctx = device_to_vm_device(device);
/* vmbus_child_device_destroy(&device_ctx->device_obj); */
kfree(device_ctx);
/* !!DO NOT REFERENCE device_ctx anymore at this point!! */
- DPRINT_EXIT(VMBUS_DRV);
-
- return;
}
-/**
+/*
* vmbus_msg_dpc - Tasklet routine to handle hypervisor messages
*/
static void vmbus_msg_dpc(unsigned long data)
{
struct vmbus_driver *vmbus_drv_obj = (struct vmbus_driver *)data;
- DPRINT_ENTER(VMBUS_DRV);
-
- ASSERT(vmbus_drv_obj->OnMsgDpc != NULL);
+ /* ASSERT(vmbus_drv_obj->OnMsgDpc != NULL); */
/* Call to bus driver to handle interrupt */
vmbus_drv_obj->OnMsgDpc(&vmbus_drv_obj->Base);
-
- DPRINT_EXIT(VMBUS_DRV);
}
-/**
+/*
* vmbus_msg_dpc - Tasklet routine to handle hypervisor events
*/
static void vmbus_event_dpc(unsigned long data)
{
struct vmbus_driver *vmbus_drv_obj = (struct vmbus_driver *)data;
- DPRINT_ENTER(VMBUS_DRV);
-
- ASSERT(vmbus_drv_obj->OnEventDpc != NULL);
+ /* ASSERT(vmbus_drv_obj->OnEventDpc != NULL); */
/* Call to bus driver to handle interrupt */
vmbus_drv_obj->OnEventDpc(&vmbus_drv_obj->Base);
-
- DPRINT_EXIT(VMBUS_DRV);
}
static irqreturn_t vmbus_isr(int irq, void *dev_id)
@@ -923,9 +886,7 @@ static irqreturn_t vmbus_isr(int irq, void *dev_id)
struct vmbus_driver *vmbus_driver_obj = &g_vmbus_drv.drv_obj;
int ret;
- DPRINT_ENTER(VMBUS_DRV);
-
- ASSERT(vmbus_driver_obj->OnIsr != NULL);
+ /* ASSERT(vmbus_driver_obj->OnIsr != NULL); */
/* Call to bus driver to handle interrupt */
ret = vmbus_driver_obj->OnIsr(&vmbus_driver_obj->Base);
@@ -938,42 +899,58 @@ static irqreturn_t vmbus_isr(int irq, void *dev_id)
if (test_bit(1, (unsigned long *)&ret))
tasklet_schedule(&g_vmbus_drv.event_dpc);
- DPRINT_EXIT(VMBUS_DRV);
return IRQ_HANDLED;
} else {
- DPRINT_EXIT(VMBUS_DRV);
return IRQ_NONE;
}
}
+static struct dmi_system_id __initdata microsoft_hv_dmi_table[] = {
+ {
+ .ident = "Hyper-V",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Virtual Machine"),
+ DMI_MATCH(DMI_BOARD_NAME, "Virtual Machine"),
+ },
+ },
+ { },
+};
+MODULE_DEVICE_TABLE(dmi, microsoft_hv_dmi_table);
+
static int __init vmbus_init(void)
{
- int ret = 0;
-
- DPRINT_ENTER(VMBUS_DRV);
-
DPRINT_INFO(VMBUS_DRV,
"Vmbus initializing.... current log level 0x%x (%x,%x)",
vmbus_loglevel, HIWORD(vmbus_loglevel), LOWORD(vmbus_loglevel));
/* Todo: it is used for loglevel, to be ported to new kernel. */
- ret = vmbus_bus_init(VmbusInitialize);
+ if (!dmi_check_system(microsoft_hv_dmi_table))
+ return -ENODEV;
- DPRINT_EXIT(VMBUS_DRV);
- return ret;
+ return vmbus_bus_init(VmbusInitialize);
}
static void __exit vmbus_exit(void)
{
- DPRINT_ENTER(VMBUS_DRV);
-
vmbus_bus_exit();
/* Todo: it is used for loglevel, to be ported to new kernel. */
- DPRINT_EXIT(VMBUS_DRV);
- return;
}
+/*
+ * We use a PCI table to determine if we should autoload this driver This is
+ * needed by distro tools to determine if the hyperv drivers should be
+ * installed and/or configured. We don't do anything else with the table, but
+ * it needs to be present.
+ */
+static const struct pci_device_id microsoft_hv_pci_table[] = {
+ { PCI_DEVICE(0x1414, 0x5353) }, /* VGA compatible controller */
+ { 0 }
+};
+MODULE_DEVICE_TABLE(pci, microsoft_hv_pci_table);
+
MODULE_LICENSE("GPL");
+MODULE_VERSION(HV_DRV_VERSION);
module_param(vmbus_irq, int, S_IRUGO);
module_param(vmbus_loglevel, int, S_IRUGO);
diff --git a/drivers/staging/hv/VmbusPacketFormat.h b/drivers/staging/hv/vmbus_packet_format.h
index 79120bc..f9f6b4b 100644
--- a/drivers/staging/hv/VmbusPacketFormat.h
+++ b/drivers/staging/hv/vmbus_packet_format.h
@@ -22,6 +22,7 @@
*/
#ifndef _VMBUSPACKETFORMAT_H_
+#define _VMBUSPACKETFORMAT_H_
struct vmpacket_descriptor {
u16 Type;
diff --git a/drivers/staging/hv/VmbusPrivate.h b/drivers/staging/hv/vmbus_private.h
index 05ad2c9..09eaec9 100644
--- a/drivers/staging/hv/VmbusPrivate.h
+++ b/drivers/staging/hv/vmbus_private.h
@@ -25,12 +25,11 @@
#ifndef _VMBUS_PRIVATE_H_
#define _VMBUS_PRIVATE_H_
-#include "Hv.h"
-#include "VmbusApi.h"
-#include "Channel.h"
-#include "ChannelMgmt.h"
-#include "ChannelInterface.h"
-#include "RingBuffer.h"
+#include "hv.h"
+#include "vmbus_api.h"
+#include "channel.h"
+#include "channel_mgmt.h"
+#include "ring_buffer.h"
#include <linux/list.h>
@@ -105,7 +104,7 @@ extern struct VMBUS_CONNECTION gVmbusConnection;
struct hv_device *VmbusChildDeviceCreate(struct hv_guid *deviceType,
struct hv_guid *deviceInstance,
- void *context);
+ struct vmbus_channel *channel);
int VmbusChildDeviceAdd(struct hv_device *Device);
diff --git a/drivers/staging/hv/vstorage.h b/drivers/staging/hv/vstorage.h
index 6d160a5..4ea597d 100644
--- a/drivers/staging/hv/vstorage.h
+++ b/drivers/staging/hv/vstorage.h
@@ -28,7 +28,7 @@
#define REVISION_STRING(REVISION_) #REVISION_
#define FILL_VMSTOR_REVISION(RESULT_LVALUE_) \
{ \
- char *revisionString = REVISION_STRING($Revision: 6 $) + 11; \
+ char *revisionString = REVISION_STRING($Revision : 6 $) + 11; \
RESULT_LVALUE_ = 0; \
while (*revisionString >= '0' && *revisionString <= '9') { \
RESULT_LVALUE_ *= 10; \