1 /* 2 * 3 * Copyright (c) 2009, Microsoft Corporation. 4 * 5 * This program is free software; you can redistribute it and/or modify it 6 * under the terms and conditions of the GNU General Public License, 7 * version 2, as published by the Free Software Foundation. 8 * 9 * This program is distributed in the hope it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 12 * more details. 13 * 14 * You should have received a copy of the GNU General Public License along with 15 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple 16 * Place - Suite 330, Boston, MA 02111-1307 USA. 17 * 18 * Authors: 19 * Haiyang Zhang <haiyangz@microsoft.com> 20 * Hank Janssen <hjanssen@microsoft.com> 21 * 22 */ 23 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 24 25 #include <linux/kernel.h> 26 #include <linux/sched.h> 27 #include <linux/wait.h> 28 #include <linux/delay.h> 29 #include <linux/mm.h> 30 #include <linux/slab.h> 31 #include <linux/vmalloc.h> 32 #include <linux/hyperv.h> 33 #include <asm/hyperv.h> 34 #include "hyperv_vmbus.h" 35 36 37 struct vmbus_connection vmbus_connection = { 38 .conn_state = DISCONNECTED, 39 .next_gpadl_handle = ATOMIC_INIT(0xE1E10), 40 }; 41 42 /* 43 * vmbus_connect - Sends a connect request on the partition service connection 44 */ 45 int vmbus_connect(void) 46 { 47 int ret = 0; 48 int t; 49 struct vmbus_channel_msginfo *msginfo = NULL; 50 struct vmbus_channel_initiate_contact *msg; 51 unsigned long flags; 52 53 /* Initialize the vmbus connection */ 54 vmbus_connection.conn_state = CONNECTING; 55 vmbus_connection.work_queue = create_workqueue("hv_vmbus_con"); 56 if (!vmbus_connection.work_queue) { 57 ret = -ENOMEM; 58 goto cleanup; 59 } 60 61 INIT_LIST_HEAD(&vmbus_connection.chn_msg_list); 62 spin_lock_init(&vmbus_connection.channelmsg_lock); 63 64 INIT_LIST_HEAD(&vmbus_connection.chn_list); 65 spin_lock_init(&vmbus_connection.channel_lock); 66 67 /* 68 * Setup the vmbus event connection for channel interrupt 69 * abstraction stuff 70 */ 71 vmbus_connection.int_page = 72 (void *)__get_free_pages(GFP_KERNEL|__GFP_ZERO, 0); 73 if (vmbus_connection.int_page == NULL) { 74 ret = -ENOMEM; 75 goto cleanup; 76 } 77 78 vmbus_connection.recv_int_page = vmbus_connection.int_page; 79 vmbus_connection.send_int_page = 80 (void *)((unsigned long)vmbus_connection.int_page + 81 (PAGE_SIZE >> 1)); 82 83 /* 84 * Setup the monitor notification facility. The 1st page for 85 * parent->child and the 2nd page for child->parent 86 */ 87 vmbus_connection.monitor_pages = 88 (void *)__get_free_pages((GFP_KERNEL|__GFP_ZERO), 1); 89 if (vmbus_connection.monitor_pages == NULL) { 90 ret = -ENOMEM; 91 goto cleanup; 92 } 93 94 msginfo = kzalloc(sizeof(*msginfo) + 95 sizeof(struct vmbus_channel_initiate_contact), 96 GFP_KERNEL); 97 if (msginfo == NULL) { 98 ret = -ENOMEM; 99 goto cleanup; 100 } 101 102 init_completion(&msginfo->waitevent); 103 104 msg = (struct vmbus_channel_initiate_contact *)msginfo->msg; 105 106 msg->header.msgtype = CHANNELMSG_INITIATE_CONTACT; 107 msg->vmbus_version_requested = VMBUS_REVISION_NUMBER; 108 msg->interrupt_page = virt_to_phys(vmbus_connection.int_page); 109 msg->monitor_page1 = virt_to_phys(vmbus_connection.monitor_pages); 110 msg->monitor_page2 = virt_to_phys( 111 (void *)((unsigned long)vmbus_connection.monitor_pages + 112 PAGE_SIZE)); 113 114 /* 115 * Add to list before we send the request since we may 116 * receive the response before returning from this routine 117 */ 118 spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags); 119 list_add_tail(&msginfo->msglistentry, 120 &vmbus_connection.chn_msg_list); 121 122 spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags); 123 124 ret = vmbus_post_msg(msg, 125 sizeof(struct vmbus_channel_initiate_contact)); 126 if (ret != 0) { 127 spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags); 128 list_del(&msginfo->msglistentry); 129 spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, 130 flags); 131 goto cleanup; 132 } 133 134 /* Wait for the connection response */ 135 t = wait_for_completion_timeout(&msginfo->waitevent, 5*HZ); 136 if (t == 0) { 137 spin_lock_irqsave(&vmbus_connection.channelmsg_lock, 138 flags); 139 list_del(&msginfo->msglistentry); 140 spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, 141 flags); 142 ret = -ETIMEDOUT; 143 goto cleanup; 144 } 145 146 spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags); 147 list_del(&msginfo->msglistentry); 148 spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags); 149 150 /* Check if successful */ 151 if (msginfo->response.version_response.version_supported) { 152 vmbus_connection.conn_state = CONNECTED; 153 } else { 154 pr_err("Unable to connect, " 155 "Version %d not supported by Hyper-V\n", 156 VMBUS_REVISION_NUMBER); 157 ret = -ECONNREFUSED; 158 goto cleanup; 159 } 160 161 kfree(msginfo); 162 return 0; 163 164 cleanup: 165 vmbus_connection.conn_state = DISCONNECTED; 166 167 if (vmbus_connection.work_queue) 168 destroy_workqueue(vmbus_connection.work_queue); 169 170 if (vmbus_connection.int_page) { 171 free_pages((unsigned long)vmbus_connection.int_page, 0); 172 vmbus_connection.int_page = NULL; 173 } 174 175 if (vmbus_connection.monitor_pages) { 176 free_pages((unsigned long)vmbus_connection.monitor_pages, 1); 177 vmbus_connection.monitor_pages = NULL; 178 } 179 180 kfree(msginfo); 181 182 return ret; 183 } 184 185 186 /* 187 * relid2channel - Get the channel object given its 188 * child relative id (ie channel id) 189 */ 190 struct vmbus_channel *relid2channel(u32 relid) 191 { 192 struct vmbus_channel *channel; 193 struct vmbus_channel *found_channel = NULL; 194 unsigned long flags; 195 196 spin_lock_irqsave(&vmbus_connection.channel_lock, flags); 197 list_for_each_entry(channel, &vmbus_connection.chn_list, listentry) { 198 if (channel->offermsg.child_relid == relid) { 199 found_channel = channel; 200 break; 201 } 202 } 203 spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags); 204 205 return found_channel; 206 } 207 208 /* 209 * process_chn_event - Process a channel event notification 210 */ 211 static void process_chn_event(u32 relid) 212 { 213 struct vmbus_channel *channel; 214 unsigned long flags; 215 216 /* 217 * Find the channel based on this relid and invokes the 218 * channel callback to process the event 219 */ 220 channel = relid2channel(relid); 221 222 if (!channel) { 223 pr_err("channel not found for relid - %u\n", relid); 224 return; 225 } 226 227 /* 228 * A channel once created is persistent even when there 229 * is no driver handling the device. An unloading driver 230 * sets the onchannel_callback to NULL under the 231 * protection of the channel inbound_lock. Thus, checking 232 * and invoking the driver specific callback takes care of 233 * orderly unloading of the driver. 234 */ 235 236 spin_lock_irqsave(&channel->inbound_lock, flags); 237 if (channel->onchannel_callback != NULL) 238 channel->onchannel_callback(channel->channel_callback_context); 239 else 240 pr_err("no channel callback for relid - %u\n", relid); 241 242 spin_unlock_irqrestore(&channel->inbound_lock, flags); 243 } 244 245 /* 246 * vmbus_on_event - Handler for events 247 */ 248 void vmbus_on_event(unsigned long data) 249 { 250 u32 dword; 251 u32 maxdword = MAX_NUM_CHANNELS_SUPPORTED >> 5; 252 int bit; 253 u32 relid; 254 u32 *recv_int_page = vmbus_connection.recv_int_page; 255 256 /* Check events */ 257 if (!recv_int_page) 258 return; 259 for (dword = 0; dword < maxdword; dword++) { 260 if (!recv_int_page[dword]) 261 continue; 262 for (bit = 0; bit < 32; bit++) { 263 if (sync_test_and_clear_bit(bit, 264 (unsigned long *)&recv_int_page[dword])) { 265 relid = (dword << 5) + bit; 266 267 if (relid == 0) 268 /* 269 * Special case - vmbus 270 * channel protocol msg 271 */ 272 continue; 273 274 process_chn_event(relid); 275 } 276 } 277 } 278 } 279 280 /* 281 * vmbus_post_msg - Send a msg on the vmbus's message connection 282 */ 283 int vmbus_post_msg(void *buffer, size_t buflen) 284 { 285 union hv_connection_id conn_id; 286 int ret = 0; 287 int retries = 0; 288 289 conn_id.asu32 = 0; 290 conn_id.u.id = VMBUS_MESSAGE_CONNECTION_ID; 291 292 /* 293 * hv_post_message() can have transient failures because of 294 * insufficient resources. Retry the operation a couple of 295 * times before giving up. 296 */ 297 while (retries < 3) { 298 ret = hv_post_message(conn_id, 1, buffer, buflen); 299 if (ret != HV_STATUS_INSUFFICIENT_BUFFERS) 300 return ret; 301 retries++; 302 msleep(100); 303 } 304 return ret; 305 } 306 307 /* 308 * vmbus_set_event - Send an event notification to the parent 309 */ 310 int vmbus_set_event(u32 child_relid) 311 { 312 /* Each u32 represents 32 channels */ 313 sync_set_bit(child_relid & 31, 314 (unsigned long *)vmbus_connection.send_int_page + 315 (child_relid >> 5)); 316 317 return hv_signal_event(); 318 } 319