| rjw | 1f88458 | 2022-01-06 17:20:42 +0800 | [diff] [blame] | 1 | /* | 
|  | 2 | * | 
|  | 3 | * Copyright (c) 2011, 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 | *   K. Y. Srinivasan <kys@microsoft.com> | 
|  | 22 | * | 
|  | 23 | */ | 
|  | 24 |  | 
|  | 25 | #ifndef _HYPERV_VMBUS_H | 
|  | 26 | #define _HYPERV_VMBUS_H | 
|  | 27 |  | 
|  | 28 | #include <linux/list.h> | 
|  | 29 | #include <asm/sync_bitops.h> | 
|  | 30 | #include <linux/atomic.h> | 
|  | 31 | #include <linux/hyperv.h> | 
|  | 32 | #include <linux/interrupt.h> | 
|  | 33 |  | 
|  | 34 | /* | 
|  | 35 | * Timeout for services such as KVP and fcopy. | 
|  | 36 | */ | 
|  | 37 | #define HV_UTIL_TIMEOUT 30 | 
|  | 38 |  | 
|  | 39 | /* | 
|  | 40 | * Timeout for guest-host handshake for services. | 
|  | 41 | */ | 
|  | 42 | #define HV_UTIL_NEGO_TIMEOUT 55 | 
|  | 43 |  | 
|  | 44 | /* Define synthetic interrupt controller flag constants. */ | 
|  | 45 | #define HV_EVENT_FLAGS_COUNT		(256 * 8) | 
|  | 46 | #define HV_EVENT_FLAGS_LONG_COUNT	(256 / sizeof(unsigned long)) | 
|  | 47 |  | 
|  | 48 | /* | 
|  | 49 | * Timer configuration register. | 
|  | 50 | */ | 
|  | 51 | union hv_timer_config { | 
|  | 52 | u64 as_uint64; | 
|  | 53 | struct { | 
|  | 54 | u64 enable:1; | 
|  | 55 | u64 periodic:1; | 
|  | 56 | u64 lazy:1; | 
|  | 57 | u64 auto_enable:1; | 
|  | 58 | u64 reserved_z0:12; | 
|  | 59 | u64 sintx:4; | 
|  | 60 | u64 reserved_z1:44; | 
|  | 61 | }; | 
|  | 62 | }; | 
|  | 63 |  | 
|  | 64 |  | 
|  | 65 | /* Define the synthetic interrupt controller event flags format. */ | 
|  | 66 | union hv_synic_event_flags { | 
|  | 67 | unsigned long flags[HV_EVENT_FLAGS_LONG_COUNT]; | 
|  | 68 | }; | 
|  | 69 |  | 
|  | 70 | /* Define SynIC control register. */ | 
|  | 71 | union hv_synic_scontrol { | 
|  | 72 | u64 as_uint64; | 
|  | 73 | struct { | 
|  | 74 | u64 enable:1; | 
|  | 75 | u64 reserved:63; | 
|  | 76 | }; | 
|  | 77 | }; | 
|  | 78 |  | 
|  | 79 | /* Define synthetic interrupt source. */ | 
|  | 80 | union hv_synic_sint { | 
|  | 81 | u64 as_uint64; | 
|  | 82 | struct { | 
|  | 83 | u64 vector:8; | 
|  | 84 | u64 reserved1:8; | 
|  | 85 | u64 masked:1; | 
|  | 86 | u64 auto_eoi:1; | 
|  | 87 | u64 reserved2:46; | 
|  | 88 | }; | 
|  | 89 | }; | 
|  | 90 |  | 
|  | 91 | /* Define the format of the SIMP register */ | 
|  | 92 | union hv_synic_simp { | 
|  | 93 | u64 as_uint64; | 
|  | 94 | struct { | 
|  | 95 | u64 simp_enabled:1; | 
|  | 96 | u64 preserved:11; | 
|  | 97 | u64 base_simp_gpa:52; | 
|  | 98 | }; | 
|  | 99 | }; | 
|  | 100 |  | 
|  | 101 | /* Define the format of the SIEFP register */ | 
|  | 102 | union hv_synic_siefp { | 
|  | 103 | u64 as_uint64; | 
|  | 104 | struct { | 
|  | 105 | u64 siefp_enabled:1; | 
|  | 106 | u64 preserved:11; | 
|  | 107 | u64 base_siefp_gpa:52; | 
|  | 108 | }; | 
|  | 109 | }; | 
|  | 110 |  | 
|  | 111 | /* Definitions for the monitored notification facility */ | 
|  | 112 | union hv_monitor_trigger_group { | 
|  | 113 | u64 as_uint64; | 
|  | 114 | struct { | 
|  | 115 | u32 pending; | 
|  | 116 | u32 armed; | 
|  | 117 | }; | 
|  | 118 | }; | 
|  | 119 |  | 
|  | 120 | struct hv_monitor_parameter { | 
|  | 121 | union hv_connection_id connectionid; | 
|  | 122 | u16 flagnumber; | 
|  | 123 | u16 rsvdz; | 
|  | 124 | }; | 
|  | 125 |  | 
|  | 126 | union hv_monitor_trigger_state { | 
|  | 127 | u32 asu32; | 
|  | 128 |  | 
|  | 129 | struct { | 
|  | 130 | u32 group_enable:4; | 
|  | 131 | u32 rsvdz:28; | 
|  | 132 | }; | 
|  | 133 | }; | 
|  | 134 |  | 
|  | 135 | /* struct hv_monitor_page Layout */ | 
|  | 136 | /* ------------------------------------------------------ */ | 
|  | 137 | /* | 0   | TriggerState (4 bytes) | Rsvd1 (4 bytes)     | */ | 
|  | 138 | /* | 8   | TriggerGroup[0]                              | */ | 
|  | 139 | /* | 10  | TriggerGroup[1]                              | */ | 
|  | 140 | /* | 18  | TriggerGroup[2]                              | */ | 
|  | 141 | /* | 20  | TriggerGroup[3]                              | */ | 
|  | 142 | /* | 28  | Rsvd2[0]                                     | */ | 
|  | 143 | /* | 30  | Rsvd2[1]                                     | */ | 
|  | 144 | /* | 38  | Rsvd2[2]                                     | */ | 
|  | 145 | /* | 40  | NextCheckTime[0][0]    | NextCheckTime[0][1] | */ | 
|  | 146 | /* | ...                                                | */ | 
|  | 147 | /* | 240 | Latency[0][0..3]                             | */ | 
|  | 148 | /* | 340 | Rsvz3[0]                                     | */ | 
|  | 149 | /* | 440 | Parameter[0][0]                              | */ | 
|  | 150 | /* | 448 | Parameter[0][1]                              | */ | 
|  | 151 | /* | ...                                                | */ | 
|  | 152 | /* | 840 | Rsvd4[0]                                     | */ | 
|  | 153 | /* ------------------------------------------------------ */ | 
|  | 154 | struct hv_monitor_page { | 
|  | 155 | union hv_monitor_trigger_state trigger_state; | 
|  | 156 | u32 rsvdz1; | 
|  | 157 |  | 
|  | 158 | union hv_monitor_trigger_group trigger_group[4]; | 
|  | 159 | u64 rsvdz2[3]; | 
|  | 160 |  | 
|  | 161 | s32 next_checktime[4][32]; | 
|  | 162 |  | 
|  | 163 | u16 latency[4][32]; | 
|  | 164 | u64 rsvdz3[32]; | 
|  | 165 |  | 
|  | 166 | struct hv_monitor_parameter parameter[4][32]; | 
|  | 167 |  | 
|  | 168 | u8 rsvdz4[1984]; | 
|  | 169 | }; | 
|  | 170 |  | 
|  | 171 | #define HV_HYPERCALL_PARAM_ALIGN	sizeof(u64) | 
|  | 172 |  | 
|  | 173 | /* Definition of the hv_post_message hypercall input structure. */ | 
|  | 174 | struct hv_input_post_message { | 
|  | 175 | union hv_connection_id connectionid; | 
|  | 176 | u32 reserved; | 
|  | 177 | u32 message_type; | 
|  | 178 | u32 payload_size; | 
|  | 179 | u64 payload[HV_MESSAGE_PAYLOAD_QWORD_COUNT]; | 
|  | 180 | }; | 
|  | 181 |  | 
|  | 182 |  | 
|  | 183 | enum { | 
|  | 184 | VMBUS_MESSAGE_CONNECTION_ID	= 1, | 
|  | 185 | VMBUS_MESSAGE_PORT_ID		= 1, | 
|  | 186 | VMBUS_EVENT_CONNECTION_ID	= 2, | 
|  | 187 | VMBUS_EVENT_PORT_ID		= 2, | 
|  | 188 | VMBUS_MONITOR_CONNECTION_ID	= 3, | 
|  | 189 | VMBUS_MONITOR_PORT_ID		= 3, | 
|  | 190 | VMBUS_MESSAGE_SINT		= 2, | 
|  | 191 | }; | 
|  | 192 |  | 
|  | 193 | /* | 
|  | 194 | * Per cpu state for channel handling | 
|  | 195 | */ | 
|  | 196 | struct hv_per_cpu_context { | 
|  | 197 | void *synic_message_page; | 
|  | 198 | void *synic_event_page; | 
|  | 199 | /* | 
|  | 200 | * buffer to post messages to the host. | 
|  | 201 | */ | 
|  | 202 | void *post_msg_page; | 
|  | 203 |  | 
|  | 204 | /* | 
|  | 205 | * Starting with win8, we can take channel interrupts on any CPU; | 
|  | 206 | * we will manage the tasklet that handles events messages on a per CPU | 
|  | 207 | * basis. | 
|  | 208 | */ | 
|  | 209 | struct tasklet_struct msg_dpc; | 
|  | 210 |  | 
|  | 211 | /* | 
|  | 212 | * To optimize the mapping of relid to channel, maintain | 
|  | 213 | * per-cpu list of the channels based on their CPU affinity. | 
|  | 214 | */ | 
|  | 215 | struct list_head chan_list; | 
|  | 216 | struct clock_event_device *clk_evt; | 
|  | 217 | }; | 
|  | 218 |  | 
|  | 219 | struct hv_context { | 
|  | 220 | /* We only support running on top of Hyper-V | 
|  | 221 | * So at this point this really can only contain the Hyper-V ID | 
|  | 222 | */ | 
|  | 223 | u64 guestid; | 
|  | 224 |  | 
|  | 225 | void *tsc_page; | 
|  | 226 |  | 
|  | 227 | bool synic_initialized; | 
|  | 228 |  | 
|  | 229 | struct hv_per_cpu_context __percpu *cpu_context; | 
|  | 230 |  | 
|  | 231 | /* | 
|  | 232 | * To manage allocations in a NUMA node. | 
|  | 233 | * Array indexed by numa node ID. | 
|  | 234 | */ | 
|  | 235 | struct cpumask *hv_numa_map; | 
|  | 236 | }; | 
|  | 237 |  | 
|  | 238 | extern struct hv_context hv_context; | 
|  | 239 |  | 
|  | 240 | /* Hv Interface */ | 
|  | 241 |  | 
|  | 242 | extern int hv_init(void); | 
|  | 243 |  | 
|  | 244 | extern int hv_post_message(union hv_connection_id connection_id, | 
|  | 245 | enum hv_message_type message_type, | 
|  | 246 | void *payload, size_t payload_size); | 
|  | 247 |  | 
|  | 248 | extern int hv_synic_alloc(void); | 
|  | 249 |  | 
|  | 250 | extern void hv_synic_free(void); | 
|  | 251 |  | 
|  | 252 | extern int hv_synic_init(unsigned int cpu); | 
|  | 253 |  | 
|  | 254 | extern int hv_synic_cleanup(unsigned int cpu); | 
|  | 255 |  | 
|  | 256 | extern void hv_synic_clockevents_cleanup(void); | 
|  | 257 |  | 
|  | 258 | /* Interface */ | 
|  | 259 |  | 
|  | 260 |  | 
|  | 261 | int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info, | 
|  | 262 | struct page *pages, u32 pagecnt); | 
|  | 263 |  | 
|  | 264 | void hv_ringbuffer_cleanup(struct hv_ring_buffer_info *ring_info); | 
|  | 265 |  | 
|  | 266 | int hv_ringbuffer_write(struct vmbus_channel *channel, | 
|  | 267 | const struct kvec *kv_list, u32 kv_count); | 
|  | 268 |  | 
|  | 269 | int hv_ringbuffer_read(struct vmbus_channel *channel, | 
|  | 270 | void *buffer, u32 buflen, u32 *buffer_actual_len, | 
|  | 271 | u64 *requestid, bool raw); | 
|  | 272 |  | 
|  | 273 | /* | 
|  | 274 | * Maximum channels is determined by the size of the interrupt page | 
|  | 275 | * which is PAGE_SIZE. 1/2 of PAGE_SIZE is for send endpoint interrupt | 
|  | 276 | * and the other is receive endpoint interrupt | 
|  | 277 | */ | 
|  | 278 | #define MAX_NUM_CHANNELS	((PAGE_SIZE >> 1) << 3)	/* 16348 channels */ | 
|  | 279 |  | 
|  | 280 | /* The value here must be in multiple of 32 */ | 
|  | 281 | /* TODO: Need to make this configurable */ | 
|  | 282 | #define MAX_NUM_CHANNELS_SUPPORTED	256 | 
|  | 283 |  | 
|  | 284 |  | 
|  | 285 | enum vmbus_connect_state { | 
|  | 286 | DISCONNECTED, | 
|  | 287 | CONNECTING, | 
|  | 288 | CONNECTED, | 
|  | 289 | DISCONNECTING | 
|  | 290 | }; | 
|  | 291 |  | 
|  | 292 | #define MAX_SIZE_CHANNEL_MESSAGE	HV_MESSAGE_PAYLOAD_BYTE_COUNT | 
|  | 293 |  | 
|  | 294 | struct vmbus_connection { | 
|  | 295 | /* | 
|  | 296 | * CPU on which the initial host contact was made. | 
|  | 297 | */ | 
|  | 298 | int connect_cpu; | 
|  | 299 |  | 
|  | 300 | atomic_t offer_in_progress; | 
|  | 301 |  | 
|  | 302 | enum vmbus_connect_state conn_state; | 
|  | 303 |  | 
|  | 304 | atomic_t next_gpadl_handle; | 
|  | 305 |  | 
|  | 306 | struct completion  unload_event; | 
|  | 307 | /* | 
|  | 308 | * Represents channel interrupts. Each bit position represents a | 
|  | 309 | * channel.  When a channel sends an interrupt via VMBUS, it finds its | 
|  | 310 | * bit in the sendInterruptPage, set it and calls Hv to generate a port | 
|  | 311 | * event. The other end receives the port event and parse the | 
|  | 312 | * recvInterruptPage to see which bit is set | 
|  | 313 | */ | 
|  | 314 | void *int_page; | 
|  | 315 | void *send_int_page; | 
|  | 316 | void *recv_int_page; | 
|  | 317 |  | 
|  | 318 | /* | 
|  | 319 | * 2 pages - 1st page for parent->child notification and 2nd | 
|  | 320 | * is child->parent notification | 
|  | 321 | */ | 
|  | 322 | struct hv_monitor_page *monitor_pages[2]; | 
|  | 323 | struct list_head chn_msg_list; | 
|  | 324 | spinlock_t channelmsg_lock; | 
|  | 325 |  | 
|  | 326 | /* List of channels */ | 
|  | 327 | struct list_head chn_list; | 
|  | 328 | struct mutex channel_mutex; | 
|  | 329 |  | 
|  | 330 | /* | 
|  | 331 | * An offer message is handled first on the work_queue, and then | 
|  | 332 | * is further handled on handle_primary_chan_wq or | 
|  | 333 | * handle_sub_chan_wq. | 
|  | 334 | */ | 
|  | 335 | struct workqueue_struct *work_queue; | 
|  | 336 | struct workqueue_struct *handle_primary_chan_wq; | 
|  | 337 | struct workqueue_struct *handle_sub_chan_wq; | 
|  | 338 | }; | 
|  | 339 |  | 
|  | 340 |  | 
|  | 341 | struct vmbus_msginfo { | 
|  | 342 | /* Bookkeeping stuff */ | 
|  | 343 | struct list_head msglist_entry; | 
|  | 344 |  | 
|  | 345 | /* The message itself */ | 
|  | 346 | unsigned char msg[0]; | 
|  | 347 | }; | 
|  | 348 |  | 
|  | 349 |  | 
|  | 350 | extern struct vmbus_connection vmbus_connection; | 
|  | 351 |  | 
|  | 352 | static inline void vmbus_send_interrupt(u32 relid) | 
|  | 353 | { | 
|  | 354 | sync_set_bit(relid, vmbus_connection.send_int_page); | 
|  | 355 | } | 
|  | 356 |  | 
|  | 357 | enum vmbus_message_handler_type { | 
|  | 358 | /* The related handler can sleep. */ | 
|  | 359 | VMHT_BLOCKING = 0, | 
|  | 360 |  | 
|  | 361 | /* The related handler must NOT sleep. */ | 
|  | 362 | VMHT_NON_BLOCKING = 1, | 
|  | 363 | }; | 
|  | 364 |  | 
|  | 365 | struct vmbus_channel_message_table_entry { | 
|  | 366 | enum vmbus_channel_message_type message_type; | 
|  | 367 | enum vmbus_message_handler_type handler_type; | 
|  | 368 | void (*message_handler)(struct vmbus_channel_message_header *msg); | 
|  | 369 | }; | 
|  | 370 |  | 
|  | 371 | extern const struct vmbus_channel_message_table_entry | 
|  | 372 | channel_message_table[CHANNELMSG_COUNT]; | 
|  | 373 |  | 
|  | 374 |  | 
|  | 375 | /* General vmbus interface */ | 
|  | 376 |  | 
|  | 377 | struct hv_device *vmbus_device_create(const uuid_le *type, | 
|  | 378 | const uuid_le *instance, | 
|  | 379 | struct vmbus_channel *channel); | 
|  | 380 |  | 
|  | 381 | int vmbus_device_register(struct hv_device *child_device_obj); | 
|  | 382 | void vmbus_device_unregister(struct hv_device *device_obj); | 
|  | 383 |  | 
|  | 384 | struct vmbus_channel *relid2channel(u32 relid); | 
|  | 385 |  | 
|  | 386 | void vmbus_free_channels(void); | 
|  | 387 |  | 
|  | 388 | /* Connection interface */ | 
|  | 389 |  | 
|  | 390 | int vmbus_connect(void); | 
|  | 391 | void vmbus_disconnect(void); | 
|  | 392 |  | 
|  | 393 | int vmbus_post_msg(void *buffer, size_t buflen, bool can_sleep); | 
|  | 394 |  | 
|  | 395 | void vmbus_on_event(unsigned long data); | 
|  | 396 | void vmbus_on_msg_dpc(unsigned long data); | 
|  | 397 |  | 
|  | 398 | int hv_kvp_init(struct hv_util_service *srv); | 
|  | 399 | void hv_kvp_deinit(void); | 
|  | 400 | void hv_kvp_onchannelcallback(void *context); | 
|  | 401 |  | 
|  | 402 | int hv_vss_init(struct hv_util_service *srv); | 
|  | 403 | void hv_vss_deinit(void); | 
|  | 404 | void hv_vss_onchannelcallback(void *context); | 
|  | 405 |  | 
|  | 406 | int hv_fcopy_init(struct hv_util_service *srv); | 
|  | 407 | void hv_fcopy_deinit(void); | 
|  | 408 | void hv_fcopy_onchannelcallback(void *context); | 
|  | 409 | void vmbus_initiate_unload(bool crash); | 
|  | 410 |  | 
|  | 411 | static inline void hv_poll_channel(struct vmbus_channel *channel, | 
|  | 412 | void (*cb)(void *)) | 
|  | 413 | { | 
|  | 414 | if (!channel) | 
|  | 415 | return; | 
|  | 416 |  | 
|  | 417 | if (in_interrupt() && (channel->target_cpu == smp_processor_id())) { | 
|  | 418 | cb(channel); | 
|  | 419 | return; | 
|  | 420 | } | 
|  | 421 | smp_call_function_single(channel->target_cpu, cb, channel, true); | 
|  | 422 | } | 
|  | 423 |  | 
|  | 424 | enum hvutil_device_state { | 
|  | 425 | HVUTIL_DEVICE_INIT = 0,  /* driver is loaded, waiting for userspace */ | 
|  | 426 | HVUTIL_READY,            /* userspace is registered */ | 
|  | 427 | HVUTIL_HOSTMSG_RECEIVED, /* message from the host was received */ | 
|  | 428 | HVUTIL_USERSPACE_REQ,    /* request to userspace was sent */ | 
|  | 429 | HVUTIL_USERSPACE_RECV,   /* reply from userspace was received */ | 
|  | 430 | HVUTIL_DEVICE_DYING,     /* driver unload is in progress */ | 
|  | 431 | }; | 
|  | 432 |  | 
|  | 433 | #endif /* _HYPERV_VMBUS_H */ |