13e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen/*
23e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen *
33e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen * Copyright (c) 2009, Microsoft Corporation.
43e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen *
53e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen * This program is free software; you can redistribute it and/or modify it
63e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen * under the terms and conditions of the GNU General Public License,
73e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen * version 2, as published by the Free Software Foundation.
83e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen *
93e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen * This program is distributed in the hope it will be useful, but WITHOUT
103e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
113e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
123e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen * more details.
133e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen *
143e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen * You should have received a copy of the GNU General Public License along with
153e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
163e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen * Place - Suite 330, Boston, MA 02111-1307 USA.
173e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen *
183e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen * Authors:
193e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen *   Haiyang Zhang <haiyangz@microsoft.com>
203e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen *   Hank Janssen  <hjanssen@microsoft.com>
213e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen *
223e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen */
230a46618d58c90f93e8b8e9a18062d1691b70297eHank Janssen#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
240a46618d58c90f93e8b8e9a18062d1691b70297eHank Janssen
25a0086dc512ba6c2161dcf48195daf177ad0c3615Greg Kroah-Hartman#include <linux/kernel.h>
260c3b7b2f75158f9420ceeb87d5924bdbd8d0304aK. Y. Srinivasan#include <linux/sched.h>
270c3b7b2f75158f9420ceeb87d5924bdbd8d0304aK. Y. Srinivasan#include <linux/wait.h>
285289d3d160e8d5c63974502696ab5def71891f18K. Y. Srinivasan#include <linux/delay.h>
29a0086dc512ba6c2161dcf48195daf177ad0c3615Greg Kroah-Hartman#include <linux/mm.h>
305a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
31a0086dc512ba6c2161dcf48195daf177ad0c3615Greg Kroah-Hartman#include <linux/vmalloc.h>
3246a971913611a23478283931460a95be962ce329Greg Kroah-Hartman#include <linux/hyperv.h>
33407dd1644302ea78fa5d740e67a1c09677aa18a4Greg Kroah-Hartman#include <asm/hyperv.h>
340f2a6619eeef158d11832436ce151987f18cb08dK. Y. Srinivasan#include "hyperv_vmbus.h"
353e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
363e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
37da9fcb7260af0cd85351740b526afdc88d4f348aHaiyang Zhangstruct vmbus_connection vmbus_connection = {
38da9fcb7260af0cd85351740b526afdc88d4f348aHaiyang Zhang	.conn_state		= DISCONNECTED,
39da9fcb7260af0cd85351740b526afdc88d4f348aHaiyang Zhang	.next_gpadl_handle	= ATOMIC_INIT(0xE1E10),
403e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen};
413e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
423e18951955797872558dad615851a4ca63b2770eHank Janssen/*
43c69776771f5fcc49d9a49580234d3a481409c80eHaiyang Zhang * vmbus_connect - Sends a connect request on the partition service connection
44fd8b85eae9928f84c7780f93b8005b3dee7ccbb2Greg Kroah-Hartman */
45c69776771f5fcc49d9a49580234d3a481409c80eHaiyang Zhangint vmbus_connect(void)
463e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen{
47fd8b85eae9928f84c7780f93b8005b3dee7ccbb2Greg Kroah-Hartman	int ret = 0;
489568a1931cd2066ed0f2df6f311e86dd851ab452K. Y. Srinivasan	int t;
4915b2f6479b5c5220848ba159248665d56694d2f9Haiyang Zhang	struct vmbus_channel_msginfo *msginfo = NULL;
5082250213d08689ab34589923be3064bb8f4c1964Greg Kroah-Hartman	struct vmbus_channel_initiate_contact *msg;
51dd0813b6f51b33529f37ba43334ac65e82d772e8Greg Kroah-Hartman	unsigned long flags;
523e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
53454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	/* Initialize the vmbus connection */
54da9fcb7260af0cd85351740b526afdc88d4f348aHaiyang Zhang	vmbus_connection.conn_state = CONNECTING;
55da9fcb7260af0cd85351740b526afdc88d4f348aHaiyang Zhang	vmbus_connection.work_queue = create_workqueue("hv_vmbus_con");
56da9fcb7260af0cd85351740b526afdc88d4f348aHaiyang Zhang	if (!vmbus_connection.work_queue) {
573a7546d934ca210ebeb51b1bb5180a3774cee443K. Y. Srinivasan		ret = -ENOMEM;
58b0043863a0097c3ebe59f91a91fc25d8e1e575e8K. Y. Srinivasan		goto cleanup;
59de65a38406bdf712abc2a845fe1f3db7d1a083edBill Pemberton	}
603e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
61da9fcb7260af0cd85351740b526afdc88d4f348aHaiyang Zhang	INIT_LIST_HEAD(&vmbus_connection.chn_msg_list);
6215b2f6479b5c5220848ba159248665d56694d2f9Haiyang Zhang	spin_lock_init(&vmbus_connection.channelmsg_lock);
633e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
64da9fcb7260af0cd85351740b526afdc88d4f348aHaiyang Zhang	INIT_LIST_HEAD(&vmbus_connection.chn_list);
6515b2f6479b5c5220848ba159248665d56694d2f9Haiyang Zhang	spin_lock_init(&vmbus_connection.channel_lock);
663e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
67454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	/*
68454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	 * Setup the vmbus event connection for channel interrupt
69454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	 * abstraction stuff
70454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	 */
71df3493e0b3ba72f9b6192a91b24197cac41ce557K. Y. Srinivasan	vmbus_connection.int_page =
72df3493e0b3ba72f9b6192a91b24197cac41ce557K. Y. Srinivasan	(void *)__get_free_pages(GFP_KERNEL|__GFP_ZERO, 0);
73da9fcb7260af0cd85351740b526afdc88d4f348aHaiyang Zhang	if (vmbus_connection.int_page == NULL) {
743a7546d934ca210ebeb51b1bb5180a3774cee443K. Y. Srinivasan		ret = -ENOMEM;
75b0043863a0097c3ebe59f91a91fc25d8e1e575e8K. Y. Srinivasan		goto cleanup;
763e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	}
773e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
78da9fcb7260af0cd85351740b526afdc88d4f348aHaiyang Zhang	vmbus_connection.recv_int_page = vmbus_connection.int_page;
79da9fcb7260af0cd85351740b526afdc88d4f348aHaiyang Zhang	vmbus_connection.send_int_page =
80da9fcb7260af0cd85351740b526afdc88d4f348aHaiyang Zhang		(void *)((unsigned long)vmbus_connection.int_page +
81fd8b85eae9928f84c7780f93b8005b3dee7ccbb2Greg Kroah-Hartman			(PAGE_SIZE >> 1));
823e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
83fd8b85eae9928f84c7780f93b8005b3dee7ccbb2Greg Kroah-Hartman	/*
84fd8b85eae9928f84c7780f93b8005b3dee7ccbb2Greg Kroah-Hartman	 * Setup the monitor notification facility. The 1st page for
85fd8b85eae9928f84c7780f93b8005b3dee7ccbb2Greg Kroah-Hartman	 * parent->child and the 2nd page for child->parent
86454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	 */
87df3493e0b3ba72f9b6192a91b24197cac41ce557K. Y. Srinivasan	vmbus_connection.monitor_pages =
88df3493e0b3ba72f9b6192a91b24197cac41ce557K. Y. Srinivasan	(void *)__get_free_pages((GFP_KERNEL|__GFP_ZERO), 1);
89da9fcb7260af0cd85351740b526afdc88d4f348aHaiyang Zhang	if (vmbus_connection.monitor_pages == NULL) {
903a7546d934ca210ebeb51b1bb5180a3774cee443K. Y. Srinivasan		ret = -ENOMEM;
91b0043863a0097c3ebe59f91a91fc25d8e1e575e8K. Y. Srinivasan		goto cleanup;
923e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	}
933e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
9415b2f6479b5c5220848ba159248665d56694d2f9Haiyang Zhang	msginfo = kzalloc(sizeof(*msginfo) +
95fd8b85eae9928f84c7780f93b8005b3dee7ccbb2Greg Kroah-Hartman			  sizeof(struct vmbus_channel_initiate_contact),
96fd8b85eae9928f84c7780f93b8005b3dee7ccbb2Greg Kroah-Hartman			  GFP_KERNEL);
9715b2f6479b5c5220848ba159248665d56694d2f9Haiyang Zhang	if (msginfo == NULL) {
988cad0af9a1a1882cd00f12f8f7c79690f563b1d7Bill Pemberton		ret = -ENOMEM;
99b0043863a0097c3ebe59f91a91fc25d8e1e575e8K. Y. Srinivasan		goto cleanup;
1003e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	}
1013e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
1029568a1931cd2066ed0f2df6f311e86dd851ab452K. Y. Srinivasan	init_completion(&msginfo->waitevent);
10380d11b2ae26543656f7226b44ed9d6a184766e85Bill Pemberton
10415b2f6479b5c5220848ba159248665d56694d2f9Haiyang Zhang	msg = (struct vmbus_channel_initiate_contact *)msginfo->msg;
1053e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
106c50f7fb28400bc4829c26bb4a2d6c06a45e90b1aHaiyang Zhang	msg->header.msgtype = CHANNELMSG_INITIATE_CONTACT;
107c50f7fb28400bc4829c26bb4a2d6c06a45e90b1aHaiyang Zhang	msg->vmbus_version_requested = VMBUS_REVISION_NUMBER;
108da9fcb7260af0cd85351740b526afdc88d4f348aHaiyang Zhang	msg->interrupt_page = virt_to_phys(vmbus_connection.int_page);
109da9fcb7260af0cd85351740b526afdc88d4f348aHaiyang Zhang	msg->monitor_page1 = virt_to_phys(vmbus_connection.monitor_pages);
110c50f7fb28400bc4829c26bb4a2d6c06a45e90b1aHaiyang Zhang	msg->monitor_page2 = virt_to_phys(
111da9fcb7260af0cd85351740b526afdc88d4f348aHaiyang Zhang			(void *)((unsigned long)vmbus_connection.monitor_pages +
112fd8b85eae9928f84c7780f93b8005b3dee7ccbb2Greg Kroah-Hartman				 PAGE_SIZE));
1133e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
114454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	/*
115454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	 * Add to list before we send the request since we may
116454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	 * receive the response before returning from this routine
117454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	 */
11815b2f6479b5c5220848ba159248665d56694d2f9Haiyang Zhang	spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
11915b2f6479b5c5220848ba159248665d56694d2f9Haiyang Zhang	list_add_tail(&msginfo->msglistentry,
120da9fcb7260af0cd85351740b526afdc88d4f348aHaiyang Zhang		      &vmbus_connection.chn_msg_list);
12153af545b277508d6b4829e90546cbd1beef536a9Bill Pemberton
12215b2f6479b5c5220848ba159248665d56694d2f9Haiyang Zhang	spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
1233e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
124c69776771f5fcc49d9a49580234d3a481409c80eHaiyang Zhang	ret = vmbus_post_msg(msg,
125fd8b85eae9928f84c7780f93b8005b3dee7ccbb2Greg Kroah-Hartman			       sizeof(struct vmbus_channel_initiate_contact));
126fd8b85eae9928f84c7780f93b8005b3dee7ccbb2Greg Kroah-Hartman	if (ret != 0) {
1270c3b7b2f75158f9420ceeb87d5924bdbd8d0304aK. Y. Srinivasan		spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
12815b2f6479b5c5220848ba159248665d56694d2f9Haiyang Zhang		list_del(&msginfo->msglistentry);
1290c3b7b2f75158f9420ceeb87d5924bdbd8d0304aK. Y. Srinivasan		spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock,
1300c3b7b2f75158f9420ceeb87d5924bdbd8d0304aK. Y. Srinivasan					flags);
131b0043863a0097c3ebe59f91a91fc25d8e1e575e8K. Y. Srinivasan		goto cleanup;
1323e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	}
1333e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
134454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	/* Wait for the connection response */
1352dfde9644fe8c4a77f9c73f95b25d6300ca23b5dK. Y. Srinivasan	t =  wait_for_completion_timeout(&msginfo->waitevent, 5*HZ);
1369568a1931cd2066ed0f2df6f311e86dd851ab452K. Y. Srinivasan	if (t == 0) {
1370c3b7b2f75158f9420ceeb87d5924bdbd8d0304aK. Y. Srinivasan		spin_lock_irqsave(&vmbus_connection.channelmsg_lock,
1380c3b7b2f75158f9420ceeb87d5924bdbd8d0304aK. Y. Srinivasan				flags);
1390c3b7b2f75158f9420ceeb87d5924bdbd8d0304aK. Y. Srinivasan		list_del(&msginfo->msglistentry);
1400c3b7b2f75158f9420ceeb87d5924bdbd8d0304aK. Y. Srinivasan		spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock,
1410c3b7b2f75158f9420ceeb87d5924bdbd8d0304aK. Y. Srinivasan					flags);
1420c3b7b2f75158f9420ceeb87d5924bdbd8d0304aK. Y. Srinivasan		ret = -ETIMEDOUT;
143b0043863a0097c3ebe59f91a91fc25d8e1e575e8K. Y. Srinivasan		goto cleanup;
1440c3b7b2f75158f9420ceeb87d5924bdbd8d0304aK. Y. Srinivasan	}
1453e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
1460c3b7b2f75158f9420ceeb87d5924bdbd8d0304aK. Y. Srinivasan	spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
14715b2f6479b5c5220848ba159248665d56694d2f9Haiyang Zhang	list_del(&msginfo->msglistentry);
1480c3b7b2f75158f9420ceeb87d5924bdbd8d0304aK. Y. Srinivasan	spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
1493e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
150454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	/* Check if successful */
15115b2f6479b5c5220848ba159248665d56694d2f9Haiyang Zhang	if (msginfo->response.version_response.version_supported) {
152da9fcb7260af0cd85351740b526afdc88d4f348aHaiyang Zhang		vmbus_connection.conn_state = CONNECTED;
153fd8b85eae9928f84c7780f93b8005b3dee7ccbb2Greg Kroah-Hartman	} else {
1540a46618d58c90f93e8b8e9a18062d1691b70297eHank Janssen		pr_err("Unable to connect, "
1550a46618d58c90f93e8b8e9a18062d1691b70297eHank Janssen			"Version %d not supported by Hyper-V\n",
1560a46618d58c90f93e8b8e9a18062d1691b70297eHank Janssen			VMBUS_REVISION_NUMBER);
1573a7546d934ca210ebeb51b1bb5180a3774cee443K. Y. Srinivasan		ret = -ECONNREFUSED;
158b0043863a0097c3ebe59f91a91fc25d8e1e575e8K. Y. Srinivasan		goto cleanup;
1593e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	}
1603e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
16115b2f6479b5c5220848ba159248665d56694d2f9Haiyang Zhang	kfree(msginfo);
1623e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	return 0;
1633e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
164b0043863a0097c3ebe59f91a91fc25d8e1e575e8K. Y. Srinivasancleanup:
165da9fcb7260af0cd85351740b526afdc88d4f348aHaiyang Zhang	vmbus_connection.conn_state = DISCONNECTED;
1663e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
167da9fcb7260af0cd85351740b526afdc88d4f348aHaiyang Zhang	if (vmbus_connection.work_queue)
168da9fcb7260af0cd85351740b526afdc88d4f348aHaiyang Zhang		destroy_workqueue(vmbus_connection.work_queue);
1693e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
170da9fcb7260af0cd85351740b526afdc88d4f348aHaiyang Zhang	if (vmbus_connection.int_page) {
171df3493e0b3ba72f9b6192a91b24197cac41ce557K. Y. Srinivasan		free_pages((unsigned long)vmbus_connection.int_page, 0);
172da9fcb7260af0cd85351740b526afdc88d4f348aHaiyang Zhang		vmbus_connection.int_page = NULL;
1733e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	}
1743e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
175da9fcb7260af0cd85351740b526afdc88d4f348aHaiyang Zhang	if (vmbus_connection.monitor_pages) {
176df3493e0b3ba72f9b6192a91b24197cac41ce557K. Y. Srinivasan		free_pages((unsigned long)vmbus_connection.monitor_pages, 1);
177da9fcb7260af0cd85351740b526afdc88d4f348aHaiyang Zhang		vmbus_connection.monitor_pages = NULL;
1783e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	}
1793e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
180dd9b15dc03075993f63a8a69667a3a8989aedfa1Ilia Mirkin	kfree(msginfo);
1813e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
1823e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	return ret;
1833e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen}
1843e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
1853e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
1863e18951955797872558dad615851a4ca63b2770eHank Janssen/*
187c69776771f5fcc49d9a49580234d3a481409c80eHaiyang Zhang * relid2channel - Get the channel object given its
188c69776771f5fcc49d9a49580234d3a481409c80eHaiyang Zhang * child relative id (ie channel id)
189fd8b85eae9928f84c7780f93b8005b3dee7ccbb2Greg Kroah-Hartman */
190c69776771f5fcc49d9a49580234d3a481409c80eHaiyang Zhangstruct vmbus_channel *relid2channel(u32 relid)
1913e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen{
192aded7165f262e0f018b23a6cd5cba6e33fd6efd1Greg Kroah-Hartman	struct vmbus_channel *channel;
19315b2f6479b5c5220848ba159248665d56694d2f9Haiyang Zhang	struct vmbus_channel *found_channel  = NULL;
1940f5e44ca6e777660af6b0eb44d4787563932eda8Greg Kroah-Hartman	unsigned long flags;
1953e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
19615b2f6479b5c5220848ba159248665d56694d2f9Haiyang Zhang	spin_lock_irqsave(&vmbus_connection.channel_lock, flags);
197da9fcb7260af0cd85351740b526afdc88d4f348aHaiyang Zhang	list_for_each_entry(channel, &vmbus_connection.chn_list, listentry) {
19815b2f6479b5c5220848ba159248665d56694d2f9Haiyang Zhang		if (channel->offermsg.child_relid == relid) {
19915b2f6479b5c5220848ba159248665d56694d2f9Haiyang Zhang			found_channel = channel;
2003e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen			break;
2013e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen		}
2023e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	}
20315b2f6479b5c5220848ba159248665d56694d2f9Haiyang Zhang	spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags);
2043e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
20515b2f6479b5c5220848ba159248665d56694d2f9Haiyang Zhang	return found_channel;
2063e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen}
2073e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
2083e18951955797872558dad615851a4ca63b2770eHank Janssen/*
209c69776771f5fcc49d9a49580234d3a481409c80eHaiyang Zhang * process_chn_event - Process a channel event notification
210fd8b85eae9928f84c7780f93b8005b3dee7ccbb2Greg Kroah-Hartman */
21135436487e954d903237cdd2e1b4f8ca6de4dfe61Olaf Heringstatic void process_chn_event(u32 relid)
2123e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen{
213aded7165f262e0f018b23a6cd5cba6e33fd6efd1Greg Kroah-Hartman	struct vmbus_channel *channel;
214dad76bf73fc20b42d020fe5a93dbe4b4868e7681K. Y. Srinivasan	unsigned long flags;
2153e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
216454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	/*
217454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	 * Find the channel based on this relid and invokes the
218454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	 * channel callback to process the event
219454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	 */
220c69776771f5fcc49d9a49580234d3a481409c80eHaiyang Zhang	channel = relid2channel(relid);
2213e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
22224326039b9685e8bfb1532932e18cb458f2a3517K. Y. Srinivasan	if (!channel) {
22324326039b9685e8bfb1532932e18cb458f2a3517K. Y. Srinivasan		pr_err("channel not found for relid - %u\n", relid);
22424326039b9685e8bfb1532932e18cb458f2a3517K. Y. Srinivasan		return;
22524326039b9685e8bfb1532932e18cb458f2a3517K. Y. Srinivasan	}
22624326039b9685e8bfb1532932e18cb458f2a3517K. Y. Srinivasan
22724326039b9685e8bfb1532932e18cb458f2a3517K. Y. Srinivasan	/*
22824326039b9685e8bfb1532932e18cb458f2a3517K. Y. Srinivasan	 * A channel once created is persistent even when there
22924326039b9685e8bfb1532932e18cb458f2a3517K. Y. Srinivasan	 * is no driver handling the device. An unloading driver
23024326039b9685e8bfb1532932e18cb458f2a3517K. Y. Srinivasan	 * sets the onchannel_callback to NULL under the
23124326039b9685e8bfb1532932e18cb458f2a3517K. Y. Srinivasan	 * protection of the channel inbound_lock. Thus, checking
23224326039b9685e8bfb1532932e18cb458f2a3517K. Y. Srinivasan	 * and invoking the driver specific callback takes care of
23324326039b9685e8bfb1532932e18cb458f2a3517K. Y. Srinivasan	 * orderly unloading of the driver.
23424326039b9685e8bfb1532932e18cb458f2a3517K. Y. Srinivasan	 */
23524326039b9685e8bfb1532932e18cb458f2a3517K. Y. Srinivasan
236dad76bf73fc20b42d020fe5a93dbe4b4868e7681K. Y. Srinivasan	spin_lock_irqsave(&channel->inbound_lock, flags);
23724326039b9685e8bfb1532932e18cb458f2a3517K. Y. Srinivasan	if (channel->onchannel_callback != NULL)
238df452fa120cfe0ac6aa4255425b303a9863e3cc1K. Y. Srinivasan		channel->onchannel_callback(channel->channel_callback_context);
239d9add43b485538bd1e6c52d8177231ae31143265K. Y. Srinivasan	else
24024326039b9685e8bfb1532932e18cb458f2a3517K. Y. Srinivasan		pr_err("no channel callback for relid - %u\n", relid);
241d9add43b485538bd1e6c52d8177231ae31143265K. Y. Srinivasan
242dad76bf73fc20b42d020fe5a93dbe4b4868e7681K. Y. Srinivasan	spin_unlock_irqrestore(&channel->inbound_lock, flags);
2433e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen}
2443e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
2453e18951955797872558dad615851a4ca63b2770eHank Janssen/*
246c69776771f5fcc49d9a49580234d3a481409c80eHaiyang Zhang * vmbus_on_event - Handler for events
247fd8b85eae9928f84c7780f93b8005b3dee7ccbb2Greg Kroah-Hartman */
2486de3d6aa9ad455726eb7b689e2d3e57d89374e55K. Y. Srinivasanvoid vmbus_on_event(unsigned long data)
2493e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen{
25035436487e954d903237cdd2e1b4f8ca6de4dfe61Olaf Hering	u32 dword;
25135436487e954d903237cdd2e1b4f8ca6de4dfe61Olaf Hering	u32 maxdword = MAX_NUM_CHANNELS_SUPPORTED >> 5;
2523e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	int bit;
25335436487e954d903237cdd2e1b4f8ca6de4dfe61Olaf Hering	u32 relid;
254da9fcb7260af0cd85351740b526afdc88d4f348aHaiyang Zhang	u32 *recv_int_page = vmbus_connection.recv_int_page;
2553e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
256454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	/* Check events */
257242b45aa8d93f7fc46ed551db9eb06cc33da7167Olaf Hering	if (!recv_int_page)
258242b45aa8d93f7fc46ed551db9eb06cc33da7167Olaf Hering		return;
259242b45aa8d93f7fc46ed551db9eb06cc33da7167Olaf Hering	for (dword = 0; dword < maxdword; dword++) {
260242b45aa8d93f7fc46ed551db9eb06cc33da7167Olaf Hering		if (!recv_int_page[dword])
261242b45aa8d93f7fc46ed551db9eb06cc33da7167Olaf Hering			continue;
262242b45aa8d93f7fc46ed551db9eb06cc33da7167Olaf Hering		for (bit = 0; bit < 32; bit++) {
263d9add43b485538bd1e6c52d8177231ae31143265K. Y. Srinivasan			if (sync_test_and_clear_bit(bit,
264d9add43b485538bd1e6c52d8177231ae31143265K. Y. Srinivasan				(unsigned long *)&recv_int_page[dword])) {
265242b45aa8d93f7fc46ed551db9eb06cc33da7167Olaf Hering				relid = (dword << 5) + bit;
266242b45aa8d93f7fc46ed551db9eb06cc33da7167Olaf Hering
267d9add43b485538bd1e6c52d8177231ae31143265K. Y. Srinivasan				if (relid == 0)
2686d81d33059e3a062660fd671ea8842662373dfb9K. Y. Srinivasan					/*
2696d81d33059e3a062660fd671ea8842662373dfb9K. Y. Srinivasan					 * Special case - vmbus
2706d81d33059e3a062660fd671ea8842662373dfb9K. Y. Srinivasan					 * channel protocol msg
2716d81d33059e3a062660fd671ea8842662373dfb9K. Y. Srinivasan					 */
272242b45aa8d93f7fc46ed551db9eb06cc33da7167Olaf Hering					continue;
273d9add43b485538bd1e6c52d8177231ae31143265K. Y. Srinivasan
27435436487e954d903237cdd2e1b4f8ca6de4dfe61Olaf Hering				process_chn_event(relid);
2753e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen			}
276242b45aa8d93f7fc46ed551db9eb06cc33da7167Olaf Hering		}
2773e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen	}
2783e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen}
2793e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
2803e18951955797872558dad615851a4ca63b2770eHank Janssen/*
281c69776771f5fcc49d9a49580234d3a481409c80eHaiyang Zhang * vmbus_post_msg - Send a msg on the vmbus's message connection
282fd8b85eae9928f84c7780f93b8005b3dee7ccbb2Greg Kroah-Hartman */
283c69776771f5fcc49d9a49580234d3a481409c80eHaiyang Zhangint vmbus_post_msg(void *buffer, size_t buflen)
2843e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen{
28515b2f6479b5c5220848ba159248665d56694d2f9Haiyang Zhang	union hv_connection_id conn_id;
2865289d3d160e8d5c63974502696ab5def71891f18K. Y. Srinivasan	int ret = 0;
2875289d3d160e8d5c63974502696ab5def71891f18K. Y. Srinivasan	int retries = 0;
2883e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
28915b2f6479b5c5220848ba159248665d56694d2f9Haiyang Zhang	conn_id.asu32 = 0;
29015b2f6479b5c5220848ba159248665d56694d2f9Haiyang Zhang	conn_id.u.id = VMBUS_MESSAGE_CONNECTION_ID;
2915289d3d160e8d5c63974502696ab5def71891f18K. Y. Srinivasan
2925289d3d160e8d5c63974502696ab5def71891f18K. Y. Srinivasan	/*
2935289d3d160e8d5c63974502696ab5def71891f18K. Y. Srinivasan	 * hv_post_message() can have transient failures because of
2945289d3d160e8d5c63974502696ab5def71891f18K. Y. Srinivasan	 * insufficient resources. Retry the operation a couple of
2955289d3d160e8d5c63974502696ab5def71891f18K. Y. Srinivasan	 * times before giving up.
2965289d3d160e8d5c63974502696ab5def71891f18K. Y. Srinivasan	 */
2975289d3d160e8d5c63974502696ab5def71891f18K. Y. Srinivasan	while (retries < 3) {
2985289d3d160e8d5c63974502696ab5def71891f18K. Y. Srinivasan		ret =  hv_post_message(conn_id, 1, buffer, buflen);
2995289d3d160e8d5c63974502696ab5def71891f18K. Y. Srinivasan		if (ret != HV_STATUS_INSUFFICIENT_BUFFERS)
3005289d3d160e8d5c63974502696ab5def71891f18K. Y. Srinivasan			return ret;
3015289d3d160e8d5c63974502696ab5def71891f18K. Y. Srinivasan		retries++;
3025289d3d160e8d5c63974502696ab5def71891f18K. Y. Srinivasan		msleep(100);
3035289d3d160e8d5c63974502696ab5def71891f18K. Y. Srinivasan	}
3045289d3d160e8d5c63974502696ab5def71891f18K. Y. Srinivasan	return ret;
3053e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen}
3063e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen
3073e18951955797872558dad615851a4ca63b2770eHank Janssen/*
308c69776771f5fcc49d9a49580234d3a481409c80eHaiyang Zhang * vmbus_set_event - Send an event notification to the parent
309fd8b85eae9928f84c7780f93b8005b3dee7ccbb2Greg Kroah-Hartman */
310c69776771f5fcc49d9a49580234d3a481409c80eHaiyang Zhangint vmbus_set_event(u32 child_relid)
3113e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen{
312454f18a963cf6519bf317e74e6b9781ffef8d253Bill Pemberton	/* Each u32 represents 32 channels */
31322356585712d1ff08fbfed152edd8b386873b238Olaf Hering	sync_set_bit(child_relid & 31,
314da9fcb7260af0cd85351740b526afdc88d4f348aHaiyang Zhang		(unsigned long *)vmbus_connection.send_int_page +
31515b2f6479b5c5220848ba159248665d56694d2f9Haiyang Zhang		(child_relid >> 5));
3167c369f405bc918f3245c7ee0b0ad6c6b6c750166Bill Pemberton
317d44890c8d2a83116463c230b59b9b9d356aafe85Haiyang Zhang	return hv_signal_event();
3183e7ee4902fe6996048f03433dd111426db3cfa92Hank Janssen}
319