• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6/drivers/staging/hv/
1/*
2 * Copyright (c) 2009, Microsoft Corporation.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License along with
14 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
15 * Place - Suite 330, Boston, MA 02111-1307 USA.
16 *
17 * Authors:
18 *   Haiyang Zhang <haiyangz@microsoft.com>
19 *   Hank Janssen  <hjanssen@microsoft.com>
20 *
21 */
22#include <linux/kernel.h>
23#include <linux/mm.h>
24#include <linux/slab.h>
25#include "osd.h"
26#include "logging.h"
27#include "version_info.h"
28#include "vmbus_private.h"
29
30static const char *gDriverName = "vmbus";
31
32/*
33 * Windows vmbus does not defined this.
34 * We defined this to be consistent with other devices
35 */
36/* {c5295816-f63a-4d5f-8d1a-4daf999ca185} */
37static const struct hv_guid gVmbusDeviceType = {
38	.data = {
39		0x16, 0x58, 0x29, 0xc5, 0x3a, 0xf6, 0x5f, 0x4d,
40		0x8d, 0x1a, 0x4d, 0xaf, 0x99, 0x9c, 0xa1, 0x85
41	}
42};
43
44/* {ac3760fc-9adf-40aa-9427-a70ed6de95c5} */
45static const struct hv_guid gVmbusDeviceId = {
46	.data = {
47		0xfc, 0x60, 0x37, 0xac, 0xdf, 0x9a, 0xaa, 0x40,
48		0x94, 0x27, 0xa7, 0x0e, 0xd6, 0xde, 0x95, 0xc5
49	}
50};
51
52static struct hv_driver *gDriver; /* vmbus driver object */
53static struct hv_device *gDevice; /* vmbus root device */
54
55/*
56 * VmbusGetChannelOffers - Retrieve the channel offers from the parent partition
57 */
58static void VmbusGetChannelOffers(void)
59{
60	VmbusChannelRequestOffers();
61}
62
63/*
64 * VmbusGetChannelInterface - Get the channel interface
65 */
66static void VmbusGetChannelInterface(struct vmbus_channel_interface *Interface)
67{
68	GetChannelInterface(Interface);
69}
70
71/*
72 * VmbusGetChannelInfo - Get the device info for the specified device object
73 */
74static void VmbusGetChannelInfo(struct hv_device *DeviceObject,
75				struct hv_device_info *DeviceInfo)
76{
77	GetChannelInfo(DeviceObject, DeviceInfo);
78}
79
80/*
81 * VmbusCreateChildDevice - Creates the child device on the bus that represents the channel offer
82 */
83struct hv_device *VmbusChildDeviceCreate(struct hv_guid *DeviceType,
84					 struct hv_guid *DeviceInstance,
85					 void *Context)
86{
87	struct vmbus_driver *vmbusDriver = (struct vmbus_driver *)gDriver;
88
89	return vmbusDriver->OnChildDeviceCreate(DeviceType, DeviceInstance,
90						Context);
91}
92
93/*
94 * VmbusChildDeviceAdd - Registers the child device with the vmbus
95 */
96int VmbusChildDeviceAdd(struct hv_device *ChildDevice)
97{
98	struct vmbus_driver *vmbusDriver = (struct vmbus_driver *)gDriver;
99
100	return vmbusDriver->OnChildDeviceAdd(gDevice, ChildDevice);
101}
102
103/*
104 * VmbusChildDeviceRemove Unregisters the child device from the vmbus
105 */
106void VmbusChildDeviceRemove(struct hv_device *ChildDevice)
107{
108	struct vmbus_driver *vmbusDriver = (struct vmbus_driver *)gDriver;
109
110	vmbusDriver->OnChildDeviceRemove(ChildDevice);
111}
112
113/*
114 * VmbusOnDeviceAdd - Callback when the root bus device is added
115 */
116static int VmbusOnDeviceAdd(struct hv_device *dev, void *AdditionalInfo)
117{
118	u32 *irqvector = AdditionalInfo;
119	int ret;
120
121	gDevice = dev;
122
123	memcpy(&gDevice->deviceType, &gVmbusDeviceType, sizeof(struct hv_guid));
124	memcpy(&gDevice->deviceInstance, &gVmbusDeviceId,
125	       sizeof(struct hv_guid));
126
127	/* strcpy(dev->name, "vmbus"); */
128	/* SynIC setup... */
129	on_each_cpu(HvSynicInit, (void *)irqvector, 1);
130
131	/* Connect to VMBus in the root partition */
132	ret = VmbusConnect();
133
134	/* VmbusSendEvent(device->localPortId+1); */
135	return ret;
136}
137
138/*
139 * VmbusOnDeviceRemove - Callback when the root bus device is removed
140 */
141static int VmbusOnDeviceRemove(struct hv_device *dev)
142{
143	int ret = 0;
144
145	VmbusChannelReleaseUnattachedChannels();
146	VmbusDisconnect();
147	on_each_cpu(HvSynicCleanup, NULL, 1);
148	return ret;
149}
150
151/*
152 * VmbusOnCleanup - Perform any cleanup when the driver is removed
153 */
154static void VmbusOnCleanup(struct hv_driver *drv)
155{
156	/* struct vmbus_driver *driver = (struct vmbus_driver *)drv; */
157
158	HvCleanup();
159}
160
161/*
162 * VmbusOnMsgDPC - DPC routine to handle messages from the hypervisior
163 */
164static void VmbusOnMsgDPC(struct hv_driver *drv)
165{
166	int cpu = smp_processor_id();
167	void *page_addr = gHvContext.synICMessagePage[cpu];
168	struct hv_message *msg = (struct hv_message *)page_addr +
169				  VMBUS_MESSAGE_SINT;
170	struct hv_message *copied;
171
172	while (1) {
173		if (msg->Header.MessageType == HvMessageTypeNone) {
174			/* no msg */
175			break;
176		} else {
177			copied = kmemdup(msg, sizeof(*copied), GFP_ATOMIC);
178			if (copied == NULL)
179				continue;
180
181			osd_schedule_callback(gVmbusConnection.WorkQueue,
182					      VmbusOnChannelMessage,
183					      (void *)copied);
184		}
185
186		msg->Header.MessageType = HvMessageTypeNone;
187
188		/*
189		 * Make sure the write to MessageType (ie set to
190		 * HvMessageTypeNone) happens before we read the
191		 * MessagePending and EOMing. Otherwise, the EOMing
192		 * will not deliver any more messages since there is
193		 * no empty slot
194		 */
195		mb();
196
197		if (msg->Header.MessageFlags.MessagePending) {
198			/*
199			 * This will cause message queue rescan to
200			 * possibly deliver another msg from the
201			 * hypervisor
202			 */
203			wrmsrl(HV_X64_MSR_EOM, 0);
204		}
205	}
206}
207
208/*
209 * VmbusOnEventDPC - DPC routine to handle events from the hypervisior
210 */
211static void VmbusOnEventDPC(struct hv_driver *drv)
212{
213	/* TODO: Process any events */
214	VmbusOnEvents();
215}
216
217/*
218 * VmbusOnISR - ISR routine
219 */
220static int VmbusOnISR(struct hv_driver *drv)
221{
222	int ret = 0;
223	int cpu = smp_processor_id();
224	void *page_addr;
225	struct hv_message *msg;
226	union hv_synic_event_flags *event;
227
228	page_addr = gHvContext.synICMessagePage[cpu];
229	msg = (struct hv_message *)page_addr + VMBUS_MESSAGE_SINT;
230
231	/* Check if there are actual msgs to be process */
232	if (msg->Header.MessageType != HvMessageTypeNone) {
233		DPRINT_DBG(VMBUS, "received msg type %d size %d",
234				msg->Header.MessageType,
235				msg->Header.PayloadSize);
236		ret |= 0x1;
237	}
238
239	/* TODO: Check if there are events to be process */
240	page_addr = gHvContext.synICEventPage[cpu];
241	event = (union hv_synic_event_flags *)page_addr + VMBUS_MESSAGE_SINT;
242
243	/* Since we are a child, we only need to check bit 0 */
244	if (test_and_clear_bit(0, (unsigned long *) &event->Flags32[0])) {
245		DPRINT_DBG(VMBUS, "received event %d", event->Flags32[0]);
246		ret |= 0x2;
247	}
248
249	return ret;
250}
251
252/*
253 * VmbusInitialize - Main entry point
254 */
255int VmbusInitialize(struct hv_driver *drv)
256{
257	struct vmbus_driver *driver = (struct vmbus_driver *)drv;
258	int ret;
259
260	DPRINT_INFO(VMBUS, "+++++++ HV Driver version = %s +++++++",
261		    HV_DRV_VERSION);
262	DPRINT_INFO(VMBUS, "+++++++ Vmbus supported version = %d +++++++",
263			VMBUS_REVISION_NUMBER);
264	DPRINT_INFO(VMBUS, "+++++++ Vmbus using SINT %d +++++++",
265			VMBUS_MESSAGE_SINT);
266	DPRINT_DBG(VMBUS, "sizeof(VMBUS_CHANNEL_PACKET_PAGE_BUFFER)=%zd, "
267			"sizeof(VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER)=%zd",
268			sizeof(struct VMBUS_CHANNEL_PACKET_PAGE_BUFFER),
269			sizeof(struct VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER));
270
271	drv->name = gDriverName;
272	memcpy(&drv->deviceType, &gVmbusDeviceType, sizeof(struct hv_guid));
273
274	/* Setup dispatch table */
275	driver->Base.OnDeviceAdd	= VmbusOnDeviceAdd;
276	driver->Base.OnDeviceRemove	= VmbusOnDeviceRemove;
277	driver->Base.OnCleanup		= VmbusOnCleanup;
278	driver->OnIsr			= VmbusOnISR;
279	driver->OnMsgDpc		= VmbusOnMsgDPC;
280	driver->OnEventDpc		= VmbusOnEventDPC;
281	driver->GetChannelOffers	= VmbusGetChannelOffers;
282	driver->GetChannelInterface	= VmbusGetChannelInterface;
283	driver->GetChannelInfo		= VmbusGetChannelInfo;
284
285	/* Hypervisor initialization...setup hypercall page..etc */
286	ret = HvInit();
287	if (ret != 0)
288		DPRINT_ERR(VMBUS, "Unable to initialize the hypervisor - 0x%x",
289				ret);
290	gDriver = drv;
291
292	return ret;
293}
294