diff options
Diffstat (limited to 'drivers/staging/hv')
-rw-r--r-- | drivers/staging/hv/Channel.c | 1007 | ||||
-rw-r--r-- | drivers/staging/hv/Channel.h | 112 | ||||
-rw-r--r-- | drivers/staging/hv/ChannelInterface.c | 152 | ||||
-rw-r--r-- | drivers/staging/hv/ChannelInterface.h | 35 | ||||
-rw-r--r-- | drivers/staging/hv/ChannelMgmt.c | 686 | ||||
-rw-r--r-- | drivers/staging/hv/Kconfig | 8 | ||||
-rw-r--r-- | drivers/staging/hv/Makefile | 15 | ||||
-rw-r--r-- | drivers/staging/hv/TODO | 5 | ||||
-rw-r--r-- | drivers/staging/hv/blkvsc.c (renamed from drivers/staging/hv/BlkVsc.c) | 18 | ||||
-rw-r--r-- | drivers/staging/hv/blkvsc_drv.c | 101 | ||||
-rw-r--r-- | drivers/staging/hv/channel.c | 1057 | ||||
-rw-r--r-- | drivers/staging/hv/channel.h | 112 | ||||
-rw-r--r-- | drivers/staging/hv/channel_mgmt.c | 861 | ||||
-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.c | 101 | ||||
-rw-r--r-- | drivers/staging/hv/hv_utils.c | 308 | ||||
-rw-r--r-- | drivers/staging/hv/logging.h | 24 | ||||
-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.c | 328 | ||||
-rw-r--r-- | drivers/staging/hv/osd.c | 71 | ||||
-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.h | 2 | ||||
-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.c | 349 | ||||
-rw-r--r-- | drivers/staging/hv/utils.h | 119 | ||||
-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.h | 18 | ||||
-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.c | 327 | ||||
-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.h | 2 |
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 = + ×ync_onchannelcallback; + hv_cb_utils[HV_TIMESYNC_MSG].callback = ×ync_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, ðtool_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; \ |