Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

VMCI: doorbell implementation.

VMCI doorbell code allows for notifcations between host and guest.

Signed-off-by: George Zhang <georgezhang@vmware.com>
Acked-by: Andy king <acking@vmware.com>
Acked-by: Dmitry Torokhov <dtor@vmware.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

George Zhang and committed by
Greg Kroah-Hartman
83e2ec76 a110b7eb

+655
+604
drivers/misc/vmw_vmci/vmci_doorbell.c
··· 1 + /* 2 + * VMware VMCI Driver 3 + * 4 + * Copyright (C) 2012 VMware, Inc. All rights reserved. 5 + * 6 + * This program is free software; you can redistribute it and/or modify it 7 + * under the terms of the GNU General Public License as published by the 8 + * Free Software Foundation version 2 and no later version. 9 + * 10 + * This program is distributed in the hope that it will be useful, but 11 + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 12 + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 13 + * for more details. 14 + */ 15 + 16 + #include <linux/vmw_vmci_defs.h> 17 + #include <linux/vmw_vmci_api.h> 18 + #include <linux/completion.h> 19 + #include <linux/hash.h> 20 + #include <linux/kernel.h> 21 + #include <linux/list.h> 22 + #include <linux/module.h> 23 + #include <linux/sched.h> 24 + #include <linux/slab.h> 25 + 26 + #include "vmci_datagram.h" 27 + #include "vmci_doorbell.h" 28 + #include "vmci_resource.h" 29 + #include "vmci_driver.h" 30 + #include "vmci_route.h" 31 + 32 + 33 + #define VMCI_DOORBELL_INDEX_BITS 6 34 + #define VMCI_DOORBELL_INDEX_TABLE_SIZE (1 << VMCI_DOORBELL_INDEX_BITS) 35 + #define VMCI_DOORBELL_HASH(_idx) hash_32(_idx, VMCI_DOORBELL_INDEX_BITS) 36 + 37 + /* 38 + * DoorbellEntry describes the a doorbell notification handle allocated by the 39 + * host. 40 + */ 41 + struct dbell_entry { 42 + struct vmci_resource resource; 43 + struct hlist_node node; 44 + struct work_struct work; 45 + vmci_callback notify_cb; 46 + void *client_data; 47 + u32 idx; 48 + u32 priv_flags; 49 + bool run_delayed; 50 + atomic_t active; /* Only used by guest personality */ 51 + }; 52 + 53 + /* The VMCI index table keeps track of currently registered doorbells. */ 54 + struct dbell_index_table { 55 + spinlock_t lock; /* Index table lock */ 56 + struct hlist_head entries[VMCI_DOORBELL_INDEX_TABLE_SIZE]; 57 + }; 58 + 59 + static struct dbell_index_table vmci_doorbell_it = { 60 + .lock = __SPIN_LOCK_UNLOCKED(vmci_doorbell_it.lock), 61 + }; 62 + 63 + /* 64 + * The max_notify_idx is one larger than the currently known bitmap index in 65 + * use, and is used to determine how much of the bitmap needs to be scanned. 66 + */ 67 + static u32 max_notify_idx; 68 + 69 + /* 70 + * The notify_idx_count is used for determining whether there are free entries 71 + * within the bitmap (if notify_idx_count + 1 < max_notify_idx). 72 + */ 73 + static u32 notify_idx_count; 74 + 75 + /* 76 + * The last_notify_idx_reserved is used to track the last index handed out - in 77 + * the case where multiple handles share a notification index, we hand out 78 + * indexes round robin based on last_notify_idx_reserved. 79 + */ 80 + static u32 last_notify_idx_reserved; 81 + 82 + /* This is a one entry cache used to by the index allocation. */ 83 + static u32 last_notify_idx_released = PAGE_SIZE; 84 + 85 + 86 + /* 87 + * Utility function that retrieves the privilege flags associated 88 + * with a given doorbell handle. For guest endpoints, the 89 + * privileges are determined by the context ID, but for host 90 + * endpoints privileges are associated with the complete 91 + * handle. Hypervisor endpoints are not yet supported. 92 + */ 93 + int vmci_dbell_get_priv_flags(struct vmci_handle handle, u32 *priv_flags) 94 + { 95 + if (priv_flags == NULL || handle.context == VMCI_INVALID_ID) 96 + return VMCI_ERROR_INVALID_ARGS; 97 + 98 + if (handle.context == VMCI_HOST_CONTEXT_ID) { 99 + struct dbell_entry *entry; 100 + struct vmci_resource *resource; 101 + 102 + resource = vmci_resource_by_handle(handle, 103 + VMCI_RESOURCE_TYPE_DOORBELL); 104 + if (!resource) 105 + return VMCI_ERROR_NOT_FOUND; 106 + 107 + entry = container_of(resource, struct dbell_entry, resource); 108 + *priv_flags = entry->priv_flags; 109 + vmci_resource_put(resource); 110 + } else if (handle.context == VMCI_HYPERVISOR_CONTEXT_ID) { 111 + /* 112 + * Hypervisor endpoints for notifications are not 113 + * supported (yet). 114 + */ 115 + return VMCI_ERROR_INVALID_ARGS; 116 + } else { 117 + *priv_flags = vmci_context_get_priv_flags(handle.context); 118 + } 119 + 120 + return VMCI_SUCCESS; 121 + } 122 + 123 + /* 124 + * Find doorbell entry by bitmap index. 125 + */ 126 + static struct dbell_entry *dbell_index_table_find(u32 idx) 127 + { 128 + u32 bucket = VMCI_DOORBELL_HASH(idx); 129 + struct dbell_entry *dbell; 130 + struct hlist_node *node; 131 + 132 + hlist_for_each_entry(dbell, node, &vmci_doorbell_it.entries[bucket], 133 + node) { 134 + if (idx == dbell->idx) 135 + return dbell; 136 + } 137 + 138 + return NULL; 139 + } 140 + 141 + /* 142 + * Add the given entry to the index table. This willi take a reference to the 143 + * entry's resource so that the entry is not deleted before it is removed from 144 + * the * table. 145 + */ 146 + static void dbell_index_table_add(struct dbell_entry *entry) 147 + { 148 + u32 bucket; 149 + u32 new_notify_idx; 150 + 151 + vmci_resource_get(&entry->resource); 152 + 153 + spin_lock_bh(&vmci_doorbell_it.lock); 154 + 155 + /* 156 + * Below we try to allocate an index in the notification 157 + * bitmap with "not too much" sharing between resources. If we 158 + * use less that the full bitmap, we either add to the end if 159 + * there are no unused flags within the currently used area, 160 + * or we search for unused ones. If we use the full bitmap, we 161 + * allocate the index round robin. 162 + */ 163 + if (max_notify_idx < PAGE_SIZE || notify_idx_count < PAGE_SIZE) { 164 + if (last_notify_idx_released < max_notify_idx && 165 + !dbell_index_table_find(last_notify_idx_released)) { 166 + new_notify_idx = last_notify_idx_released; 167 + last_notify_idx_released = PAGE_SIZE; 168 + } else { 169 + bool reused = false; 170 + new_notify_idx = last_notify_idx_reserved; 171 + if (notify_idx_count + 1 < max_notify_idx) { 172 + do { 173 + if (!dbell_index_table_find 174 + (new_notify_idx)) { 175 + reused = true; 176 + break; 177 + } 178 + new_notify_idx = (new_notify_idx + 1) % 179 + max_notify_idx; 180 + } while (new_notify_idx != 181 + last_notify_idx_released); 182 + } 183 + if (!reused) { 184 + new_notify_idx = max_notify_idx; 185 + max_notify_idx++; 186 + } 187 + } 188 + } else { 189 + new_notify_idx = (last_notify_idx_reserved + 1) % PAGE_SIZE; 190 + } 191 + 192 + last_notify_idx_reserved = new_notify_idx; 193 + notify_idx_count++; 194 + 195 + entry->idx = new_notify_idx; 196 + bucket = VMCI_DOORBELL_HASH(entry->idx); 197 + hlist_add_head(&entry->node, &vmci_doorbell_it.entries[bucket]); 198 + 199 + spin_unlock_bh(&vmci_doorbell_it.lock); 200 + } 201 + 202 + /* 203 + * Remove the given entry from the index table. This will release() the 204 + * entry's resource. 205 + */ 206 + static void dbell_index_table_remove(struct dbell_entry *entry) 207 + { 208 + spin_lock_bh(&vmci_doorbell_it.lock); 209 + 210 + hlist_del_init(&entry->node); 211 + 212 + notify_idx_count--; 213 + if (entry->idx == max_notify_idx - 1) { 214 + /* 215 + * If we delete an entry with the maximum known 216 + * notification index, we take the opportunity to 217 + * prune the current max. As there might be other 218 + * unused indices immediately below, we lower the 219 + * maximum until we hit an index in use. 220 + */ 221 + while (max_notify_idx > 0 && 222 + !dbell_index_table_find(max_notify_idx - 1)) 223 + max_notify_idx--; 224 + } 225 + 226 + last_notify_idx_released = entry->idx; 227 + 228 + spin_unlock_bh(&vmci_doorbell_it.lock); 229 + 230 + vmci_resource_put(&entry->resource); 231 + } 232 + 233 + /* 234 + * Creates a link between the given doorbell handle and the given 235 + * index in the bitmap in the device backend. A notification state 236 + * is created in hypervisor. 237 + */ 238 + static int dbell_link(struct vmci_handle handle, u32 notify_idx) 239 + { 240 + struct vmci_doorbell_link_msg link_msg; 241 + 242 + link_msg.hdr.dst = vmci_make_handle(VMCI_HYPERVISOR_CONTEXT_ID, 243 + VMCI_DOORBELL_LINK); 244 + link_msg.hdr.src = VMCI_ANON_SRC_HANDLE; 245 + link_msg.hdr.payload_size = sizeof(link_msg) - VMCI_DG_HEADERSIZE; 246 + link_msg.handle = handle; 247 + link_msg.notify_idx = notify_idx; 248 + 249 + return vmci_send_datagram(&link_msg.hdr); 250 + } 251 + 252 + /* 253 + * Unlinks the given doorbell handle from an index in the bitmap in 254 + * the device backend. The notification state is destroyed in hypervisor. 255 + */ 256 + static int dbell_unlink(struct vmci_handle handle) 257 + { 258 + struct vmci_doorbell_unlink_msg unlink_msg; 259 + 260 + unlink_msg.hdr.dst = vmci_make_handle(VMCI_HYPERVISOR_CONTEXT_ID, 261 + VMCI_DOORBELL_UNLINK); 262 + unlink_msg.hdr.src = VMCI_ANON_SRC_HANDLE; 263 + unlink_msg.hdr.payload_size = sizeof(unlink_msg) - VMCI_DG_HEADERSIZE; 264 + unlink_msg.handle = handle; 265 + 266 + return vmci_send_datagram(&unlink_msg.hdr); 267 + } 268 + 269 + /* 270 + * Notify another guest or the host. We send a datagram down to the 271 + * host via the hypervisor with the notification info. 272 + */ 273 + static int dbell_notify_as_guest(struct vmci_handle handle, u32 priv_flags) 274 + { 275 + struct vmci_doorbell_notify_msg notify_msg; 276 + 277 + notify_msg.hdr.dst = vmci_make_handle(VMCI_HYPERVISOR_CONTEXT_ID, 278 + VMCI_DOORBELL_NOTIFY); 279 + notify_msg.hdr.src = VMCI_ANON_SRC_HANDLE; 280 + notify_msg.hdr.payload_size = sizeof(notify_msg) - VMCI_DG_HEADERSIZE; 281 + notify_msg.handle = handle; 282 + 283 + return vmci_send_datagram(&notify_msg.hdr); 284 + } 285 + 286 + /* 287 + * Calls the specified callback in a delayed context. 288 + */ 289 + static void dbell_delayed_dispatch(struct work_struct *work) 290 + { 291 + struct dbell_entry *entry = container_of(work, 292 + struct dbell_entry, work); 293 + 294 + entry->notify_cb(entry->client_data); 295 + vmci_resource_put(&entry->resource); 296 + } 297 + 298 + /* 299 + * Dispatches a doorbell notification to the host context. 300 + */ 301 + int vmci_dbell_host_context_notify(u32 src_cid, struct vmci_handle handle) 302 + { 303 + struct dbell_entry *entry; 304 + struct vmci_resource *resource; 305 + 306 + if (vmci_handle_is_invalid(handle)) { 307 + pr_devel("Notifying an invalid doorbell (handle=0x%x:0x%x)\n", 308 + handle.context, handle.resource); 309 + return VMCI_ERROR_INVALID_ARGS; 310 + } 311 + 312 + resource = vmci_resource_by_handle(handle, 313 + VMCI_RESOURCE_TYPE_DOORBELL); 314 + if (!resource) { 315 + pr_devel("Notifying an unknown doorbell (handle=0x%x:0x%x)\n", 316 + handle.context, handle.resource); 317 + return VMCI_ERROR_NOT_FOUND; 318 + } 319 + 320 + entry = container_of(resource, struct dbell_entry, resource); 321 + if (entry->run_delayed) { 322 + schedule_work(&entry->work); 323 + } else { 324 + entry->notify_cb(entry->client_data); 325 + vmci_resource_put(resource); 326 + } 327 + 328 + return VMCI_SUCCESS; 329 + } 330 + 331 + /* 332 + * Register the notification bitmap with the host. 333 + */ 334 + bool vmci_dbell_register_notification_bitmap(u32 bitmap_ppn) 335 + { 336 + int result; 337 + struct vmci_notify_bm_set_msg bitmap_set_msg; 338 + 339 + bitmap_set_msg.hdr.dst = vmci_make_handle(VMCI_HYPERVISOR_CONTEXT_ID, 340 + VMCI_SET_NOTIFY_BITMAP); 341 + bitmap_set_msg.hdr.src = VMCI_ANON_SRC_HANDLE; 342 + bitmap_set_msg.hdr.payload_size = sizeof(bitmap_set_msg) - 343 + VMCI_DG_HEADERSIZE; 344 + bitmap_set_msg.bitmap_ppn = bitmap_ppn; 345 + 346 + result = vmci_send_datagram(&bitmap_set_msg.hdr); 347 + if (result != VMCI_SUCCESS) { 348 + pr_devel("Failed to register (PPN=%u) as notification bitmap (error=%d)\n", 349 + bitmap_ppn, result); 350 + return false; 351 + } 352 + return true; 353 + } 354 + 355 + /* 356 + * Executes or schedules the handlers for a given notify index. 357 + */ 358 + static void dbell_fire_entries(u32 notify_idx) 359 + { 360 + u32 bucket = VMCI_DOORBELL_HASH(notify_idx); 361 + struct dbell_entry *dbell; 362 + struct hlist_node *node; 363 + 364 + spin_lock_bh(&vmci_doorbell_it.lock); 365 + 366 + hlist_for_each_entry(dbell, node, 367 + &vmci_doorbell_it.entries[bucket], node) { 368 + if (dbell->idx == notify_idx && 369 + atomic_read(&dbell->active) == 1) { 370 + if (dbell->run_delayed) { 371 + vmci_resource_get(&dbell->resource); 372 + schedule_work(&dbell->work); 373 + } else { 374 + dbell->notify_cb(dbell->client_data); 375 + } 376 + } 377 + } 378 + 379 + spin_unlock_bh(&vmci_doorbell_it.lock); 380 + } 381 + 382 + /* 383 + * Scans the notification bitmap, collects pending notifications, 384 + * resets the bitmap and invokes appropriate callbacks. 385 + */ 386 + void vmci_dbell_scan_notification_entries(u8 *bitmap) 387 + { 388 + u32 idx; 389 + 390 + for (idx = 0; idx < max_notify_idx; idx++) { 391 + if (bitmap[idx] & 0x1) { 392 + bitmap[idx] &= ~1; 393 + dbell_fire_entries(idx); 394 + } 395 + } 396 + } 397 + 398 + /* 399 + * vmci_doorbell_create() - Creates a doorbell 400 + * @handle: A handle used to track the resource. Can be invalid. 401 + * @flags: Flag that determines context of callback. 402 + * @priv_flags: Privileges flags. 403 + * @notify_cb: The callback to be ivoked when the doorbell fires. 404 + * @client_data: A parameter to be passed to the callback. 405 + * 406 + * Creates a doorbell with the given callback. If the handle is 407 + * VMCI_INVALID_HANDLE, a free handle will be assigned, if 408 + * possible. The callback can be run immediately (potentially with 409 + * locks held - the default) or delayed (in a kernel thread) by 410 + * specifying the flag VMCI_FLAG_DELAYED_CB. If delayed execution 411 + * is selected, a given callback may not be run if the kernel is 412 + * unable to allocate memory for the delayed execution (highly 413 + * unlikely). 414 + */ 415 + int vmci_doorbell_create(struct vmci_handle *handle, 416 + u32 flags, 417 + u32 priv_flags, 418 + vmci_callback notify_cb, void *client_data) 419 + { 420 + struct dbell_entry *entry; 421 + struct vmci_handle new_handle; 422 + int result; 423 + 424 + if (!handle || !notify_cb || flags & ~VMCI_FLAG_DELAYED_CB || 425 + priv_flags & ~VMCI_PRIVILEGE_ALL_FLAGS) 426 + return VMCI_ERROR_INVALID_ARGS; 427 + 428 + entry = kmalloc(sizeof(*entry), GFP_KERNEL); 429 + if (entry == NULL) { 430 + pr_warn("Failed allocating memory for datagram entry\n"); 431 + return VMCI_ERROR_NO_MEM; 432 + } 433 + 434 + if (vmci_handle_is_invalid(*handle)) { 435 + u32 context_id = vmci_get_context_id(); 436 + 437 + /* Let resource code allocate a free ID for us */ 438 + new_handle = vmci_make_handle(context_id, VMCI_INVALID_ID); 439 + } else { 440 + bool valid_context = false; 441 + 442 + /* 443 + * Validate the handle. We must do both of the checks below 444 + * because we can be acting as both a host and a guest at the 445 + * same time. We always allow the host context ID, since the 446 + * host functionality is in practice always there with the 447 + * unified driver. 448 + */ 449 + if (handle->context == VMCI_HOST_CONTEXT_ID || 450 + (vmci_guest_code_active() && 451 + vmci_get_context_id() == handle->context)) { 452 + valid_context = true; 453 + } 454 + 455 + if (!valid_context || handle->resource == VMCI_INVALID_ID) { 456 + pr_devel("Invalid argument (handle=0x%x:0x%x)\n", 457 + handle->context, handle->resource); 458 + result = VMCI_ERROR_INVALID_ARGS; 459 + goto free_mem; 460 + } 461 + 462 + new_handle = *handle; 463 + } 464 + 465 + entry->idx = 0; 466 + INIT_HLIST_NODE(&entry->node); 467 + entry->priv_flags = priv_flags; 468 + INIT_WORK(&entry->work, dbell_delayed_dispatch); 469 + entry->run_delayed = flags & VMCI_FLAG_DELAYED_CB; 470 + entry->notify_cb = notify_cb; 471 + entry->client_data = client_data; 472 + atomic_set(&entry->active, 0); 473 + 474 + result = vmci_resource_add(&entry->resource, 475 + VMCI_RESOURCE_TYPE_DOORBELL, 476 + new_handle); 477 + if (result != VMCI_SUCCESS) { 478 + pr_warn("Failed to add new resource (handle=0x%x:0x%x), error: %d\n", 479 + new_handle.context, new_handle.resource, result); 480 + goto free_mem; 481 + } 482 + 483 + new_handle = vmci_resource_handle(&entry->resource); 484 + if (vmci_guest_code_active()) { 485 + dbell_index_table_add(entry); 486 + result = dbell_link(new_handle, entry->idx); 487 + if (VMCI_SUCCESS != result) 488 + goto destroy_resource; 489 + 490 + atomic_set(&entry->active, 1); 491 + } 492 + 493 + *handle = new_handle; 494 + 495 + return result; 496 + 497 + destroy_resource: 498 + dbell_index_table_remove(entry); 499 + vmci_resource_remove(&entry->resource); 500 + free_mem: 501 + kfree(entry); 502 + return result; 503 + } 504 + EXPORT_SYMBOL_GPL(vmci_doorbell_create); 505 + 506 + /* 507 + * vmci_doorbell_destroy() - Destroy a doorbell. 508 + * @handle: The handle tracking the resource. 509 + * 510 + * Destroys a doorbell previously created with vmcii_doorbell_create. This 511 + * operation may block waiting for a callback to finish. 512 + */ 513 + int vmci_doorbell_destroy(struct vmci_handle handle) 514 + { 515 + struct dbell_entry *entry; 516 + struct vmci_resource *resource; 517 + 518 + if (vmci_handle_is_invalid(handle)) 519 + return VMCI_ERROR_INVALID_ARGS; 520 + 521 + resource = vmci_resource_by_handle(handle, 522 + VMCI_RESOURCE_TYPE_DOORBELL); 523 + if (!resource) { 524 + pr_devel("Failed to destroy doorbell (handle=0x%x:0x%x)\n", 525 + handle.context, handle.resource); 526 + return VMCI_ERROR_NOT_FOUND; 527 + } 528 + 529 + entry = container_of(resource, struct dbell_entry, resource); 530 + 531 + if (vmci_guest_code_active()) { 532 + int result; 533 + 534 + dbell_index_table_remove(entry); 535 + 536 + result = dbell_unlink(handle); 537 + if (VMCI_SUCCESS != result) { 538 + 539 + /* 540 + * The only reason this should fail would be 541 + * an inconsistency between guest and 542 + * hypervisor state, where the guest believes 543 + * it has an active registration whereas the 544 + * hypervisor doesn't. One case where this may 545 + * happen is if a doorbell is unregistered 546 + * following a hibernation at a time where the 547 + * doorbell state hasn't been restored on the 548 + * hypervisor side yet. Since the handle has 549 + * now been removed in the guest, we just 550 + * print a warning and return success. 551 + */ 552 + pr_devel("Unlink of doorbell (handle=0x%x:0x%x) unknown by hypervisor (error=%d)\n", 553 + handle.context, handle.resource, result); 554 + } 555 + } 556 + 557 + /* 558 + * Now remove the resource from the table. It might still be in use 559 + * after this, in a callback or still on the delayed work queue. 560 + */ 561 + vmci_resource_put(&entry->resource); 562 + vmci_resource_remove(&entry->resource); 563 + 564 + kfree(entry); 565 + 566 + return VMCI_SUCCESS; 567 + } 568 + EXPORT_SYMBOL_GPL(vmci_doorbell_destroy); 569 + 570 + /* 571 + * vmci_doorbell_notify() - Ring the doorbell (and hide in the bushes). 572 + * @dst: The handlle identifying the doorbell resource 573 + * @priv_flags: Priviledge flags. 574 + * 575 + * Generates a notification on the doorbell identified by the 576 + * handle. For host side generation of notifications, the caller 577 + * can specify what the privilege of the calling side is. 578 + */ 579 + int vmci_doorbell_notify(struct vmci_handle dst, u32 priv_flags) 580 + { 581 + int retval; 582 + enum vmci_route route; 583 + struct vmci_handle src; 584 + 585 + if (vmci_handle_is_invalid(dst) || 586 + (priv_flags & ~VMCI_PRIVILEGE_ALL_FLAGS)) 587 + return VMCI_ERROR_INVALID_ARGS; 588 + 589 + src = VMCI_INVALID_HANDLE; 590 + retval = vmci_route(&src, &dst, false, &route); 591 + if (retval < VMCI_SUCCESS) 592 + return retval; 593 + 594 + if (VMCI_ROUTE_AS_HOST == route) 595 + return vmci_ctx_notify_dbell(VMCI_HOST_CONTEXT_ID, 596 + dst, priv_flags); 597 + 598 + if (VMCI_ROUTE_AS_GUEST == route) 599 + return dbell_notify_as_guest(dst, priv_flags); 600 + 601 + pr_warn("Unknown route (%d) for doorbell\n", route); 602 + return VMCI_ERROR_DST_UNREACHABLE; 603 + } 604 + EXPORT_SYMBOL_GPL(vmci_doorbell_notify);
+51
drivers/misc/vmw_vmci/vmci_doorbell.h
··· 1 + /* 2 + * VMware VMCI Driver 3 + * 4 + * Copyright (C) 2012 VMware, Inc. All rights reserved. 5 + * 6 + * This program is free software; you can redistribute it and/or modify it 7 + * under the terms of the GNU General Public License as published by the 8 + * Free Software Foundation version 2 and no later version. 9 + * 10 + * This program is distributed in the hope that it will be useful, but 11 + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 12 + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 13 + * for more details. 14 + */ 15 + 16 + #ifndef VMCI_DOORBELL_H 17 + #define VMCI_DOORBELL_H 18 + 19 + #include <linux/vmw_vmci_defs.h> 20 + #include <linux/types.h> 21 + 22 + #include "vmci_driver.h" 23 + 24 + /* 25 + * VMCINotifyResourceInfo: Used to create and destroy doorbells, and 26 + * generate a notification for a doorbell or queue pair. 27 + */ 28 + struct vmci_dbell_notify_resource_info { 29 + struct vmci_handle handle; 30 + u16 resource; 31 + u16 action; 32 + s32 result; 33 + }; 34 + 35 + /* 36 + * Structure used for checkpointing the doorbell mappings. It is 37 + * written to the checkpoint as is, so changing this structure will 38 + * break checkpoint compatibility. 39 + */ 40 + struct dbell_cpt_state { 41 + struct vmci_handle handle; 42 + u64 bitmap_idx; 43 + }; 44 + 45 + int vmci_dbell_host_context_notify(u32 src_cid, struct vmci_handle handle); 46 + int vmci_dbell_get_priv_flags(struct vmci_handle handle, u32 *priv_flags); 47 + 48 + bool vmci_dbell_register_notification_bitmap(u32 bitmap_ppn); 49 + void vmci_dbell_scan_notification_entries(u8 *bitmap); 50 + 51 + #endif /* VMCI_DOORBELL_H */