/*
* 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 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