11f166439SGeorge Zhang /*
21f166439SGeorge Zhang  * VMware VMCI Driver
31f166439SGeorge Zhang  *
41f166439SGeorge Zhang  * Copyright (C) 2012 VMware, Inc. All rights reserved.
51f166439SGeorge Zhang  *
61f166439SGeorge Zhang  * This program is free software; you can redistribute it and/or modify it
71f166439SGeorge Zhang  * under the terms of the GNU General Public License as published by the
81f166439SGeorge Zhang  * Free Software Foundation version 2 and no later version.
91f166439SGeorge Zhang  *
101f166439SGeorge Zhang  * This program is distributed in the hope that it will be useful, but
111f166439SGeorge Zhang  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
121f166439SGeorge Zhang  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
131f166439SGeorge Zhang  * for more details.
141f166439SGeorge Zhang  */
151f166439SGeorge Zhang 
161f166439SGeorge Zhang #include <linux/vmw_vmci_defs.h>
171f166439SGeorge Zhang #include <linux/vmw_vmci_api.h>
181f166439SGeorge Zhang #include <linux/moduleparam.h>
191f166439SGeorge Zhang #include <linux/interrupt.h>
201f166439SGeorge Zhang #include <linux/highmem.h>
211f166439SGeorge Zhang #include <linux/kernel.h>
22ea8a83a4SDmitry Torokhov #include <linux/mm.h>
231f166439SGeorge Zhang #include <linux/module.h>
241f166439SGeorge Zhang #include <linux/sched.h>
25ea8a83a4SDmitry Torokhov #include <linux/slab.h>
261f166439SGeorge Zhang #include <linux/init.h>
271f166439SGeorge Zhang #include <linux/pci.h>
281f166439SGeorge Zhang #include <linux/smp.h>
291f166439SGeorge Zhang #include <linux/io.h>
30ea8a83a4SDmitry Torokhov #include <linux/vmalloc.h>
311f166439SGeorge Zhang 
321f166439SGeorge Zhang #include "vmci_datagram.h"
331f166439SGeorge Zhang #include "vmci_doorbell.h"
341f166439SGeorge Zhang #include "vmci_context.h"
351f166439SGeorge Zhang #include "vmci_driver.h"
361f166439SGeorge Zhang #include "vmci_event.h"
371f166439SGeorge Zhang 
381f166439SGeorge Zhang #define PCI_VENDOR_ID_VMWARE		0x15AD
391f166439SGeorge Zhang #define PCI_DEVICE_ID_VMWARE_VMCI	0x0740
401f166439SGeorge Zhang 
411f166439SGeorge Zhang #define VMCI_UTIL_NUM_RESOURCES 1
421f166439SGeorge Zhang 
431f166439SGeorge Zhang static bool vmci_disable_msi;
441f166439SGeorge Zhang module_param_named(disable_msi, vmci_disable_msi, bool, 0);
451f166439SGeorge Zhang MODULE_PARM_DESC(disable_msi, "Disable MSI use in driver - (default=0)");
461f166439SGeorge Zhang 
471f166439SGeorge Zhang static bool vmci_disable_msix;
481f166439SGeorge Zhang module_param_named(disable_msix, vmci_disable_msix, bool, 0);
491f166439SGeorge Zhang MODULE_PARM_DESC(disable_msix, "Disable MSI-X use in driver - (default=0)");
501f166439SGeorge Zhang 
511f166439SGeorge Zhang static u32 ctx_update_sub_id = VMCI_INVALID_ID;
521f166439SGeorge Zhang static u32 vm_context_id = VMCI_INVALID_ID;
531f166439SGeorge Zhang 
541f166439SGeorge Zhang struct vmci_guest_device {
551f166439SGeorge Zhang 	struct device *dev;	/* PCI device we are attached to */
561f166439SGeorge Zhang 	void __iomem *iobase;
571f166439SGeorge Zhang 
581f166439SGeorge Zhang 	unsigned int irq;
591f166439SGeorge Zhang 	unsigned int intr_type;
601f166439SGeorge Zhang 	bool exclusive_vectors;
611f166439SGeorge Zhang 	struct msix_entry msix_entries[VMCI_MAX_INTRS];
621f166439SGeorge Zhang 
631f166439SGeorge Zhang 	struct tasklet_struct datagram_tasklet;
641f166439SGeorge Zhang 	struct tasklet_struct bm_tasklet;
651f166439SGeorge Zhang 
661f166439SGeorge Zhang 	void *data_buffer;
671f166439SGeorge Zhang 	void *notification_bitmap;
686d6dfb4fSAndy King 	dma_addr_t notification_base;
691f166439SGeorge Zhang };
701f166439SGeorge Zhang 
711f166439SGeorge Zhang /* vmci_dev singleton device and supporting data*/
726d6dfb4fSAndy King struct pci_dev *vmci_pdev;
731f166439SGeorge Zhang static struct vmci_guest_device *vmci_dev_g;
741f166439SGeorge Zhang static DEFINE_SPINLOCK(vmci_dev_spinlock);
751f166439SGeorge Zhang 
761f166439SGeorge Zhang static atomic_t vmci_num_guest_devices = ATOMIC_INIT(0);
771f166439SGeorge Zhang 
781f166439SGeorge Zhang bool vmci_guest_code_active(void)
791f166439SGeorge Zhang {
801f166439SGeorge Zhang 	return atomic_read(&vmci_num_guest_devices) != 0;
811f166439SGeorge Zhang }
821f166439SGeorge Zhang 
831f166439SGeorge Zhang u32 vmci_get_vm_context_id(void)
841f166439SGeorge Zhang {
851f166439SGeorge Zhang 	if (vm_context_id == VMCI_INVALID_ID) {
861f166439SGeorge Zhang 		struct vmci_datagram get_cid_msg;
871f166439SGeorge Zhang 		get_cid_msg.dst =
881f166439SGeorge Zhang 		    vmci_make_handle(VMCI_HYPERVISOR_CONTEXT_ID,
891f166439SGeorge Zhang 				     VMCI_GET_CONTEXT_ID);
901f166439SGeorge Zhang 		get_cid_msg.src = VMCI_ANON_SRC_HANDLE;
911f166439SGeorge Zhang 		get_cid_msg.payload_size = 0;
925a19b789SAndy King 		vm_context_id = vmci_send_datagram(&get_cid_msg);
931f166439SGeorge Zhang 	}
941f166439SGeorge Zhang 	return vm_context_id;
951f166439SGeorge Zhang }
961f166439SGeorge Zhang 
971f166439SGeorge Zhang /*
981f166439SGeorge Zhang  * VM to hypervisor call mechanism. We use the standard VMware naming
991f166439SGeorge Zhang  * convention since shared code is calling this function as well.
1001f166439SGeorge Zhang  */
1011f166439SGeorge Zhang int vmci_send_datagram(struct vmci_datagram *dg)
1021f166439SGeorge Zhang {
1031f166439SGeorge Zhang 	unsigned long flags;
1041f166439SGeorge Zhang 	int result;
1051f166439SGeorge Zhang 
1061f166439SGeorge Zhang 	/* Check args. */
1071f166439SGeorge Zhang 	if (dg == NULL)
1081f166439SGeorge Zhang 		return VMCI_ERROR_INVALID_ARGS;
1091f166439SGeorge Zhang 
1101f166439SGeorge Zhang 	/*
1111f166439SGeorge Zhang 	 * Need to acquire spinlock on the device because the datagram
1121f166439SGeorge Zhang 	 * data may be spread over multiple pages and the monitor may
1131f166439SGeorge Zhang 	 * interleave device user rpc calls from multiple
1141f166439SGeorge Zhang 	 * VCPUs. Acquiring the spinlock precludes that
1151f166439SGeorge Zhang 	 * possibility. Disabling interrupts to avoid incoming
1161f166439SGeorge Zhang 	 * datagrams during a "rep out" and possibly landing up in
1171f166439SGeorge Zhang 	 * this function.
1181f166439SGeorge Zhang 	 */
1191f166439SGeorge Zhang 	spin_lock_irqsave(&vmci_dev_spinlock, flags);
1201f166439SGeorge Zhang 
1211f166439SGeorge Zhang 	if (vmci_dev_g) {
1221f166439SGeorge Zhang 		iowrite8_rep(vmci_dev_g->iobase + VMCI_DATA_OUT_ADDR,
1231f166439SGeorge Zhang 			     dg, VMCI_DG_SIZE(dg));
1241f166439SGeorge Zhang 		result = ioread32(vmci_dev_g->iobase + VMCI_RESULT_LOW_ADDR);
1251f166439SGeorge Zhang 	} else {
1261f166439SGeorge Zhang 		result = VMCI_ERROR_UNAVAILABLE;
1271f166439SGeorge Zhang 	}
1281f166439SGeorge Zhang 
1291f166439SGeorge Zhang 	spin_unlock_irqrestore(&vmci_dev_spinlock, flags);
1301f166439SGeorge Zhang 
1311f166439SGeorge Zhang 	return result;
1321f166439SGeorge Zhang }
1331f166439SGeorge Zhang EXPORT_SYMBOL_GPL(vmci_send_datagram);
1341f166439SGeorge Zhang 
1351f166439SGeorge Zhang /*
1361f166439SGeorge Zhang  * Gets called with the new context id if updated or resumed.
1371f166439SGeorge Zhang  * Context id.
1381f166439SGeorge Zhang  */
1391f166439SGeorge Zhang static void vmci_guest_cid_update(u32 sub_id,
1401f166439SGeorge Zhang 				  const struct vmci_event_data *event_data,
1411f166439SGeorge Zhang 				  void *client_data)
1421f166439SGeorge Zhang {
1431f166439SGeorge Zhang 	const struct vmci_event_payld_ctx *ev_payload =
1441f166439SGeorge Zhang 				vmci_event_data_const_payload(event_data);
1451f166439SGeorge Zhang 
1461f166439SGeorge Zhang 	if (sub_id != ctx_update_sub_id) {
1471f166439SGeorge Zhang 		pr_devel("Invalid subscriber (ID=0x%x)\n", sub_id);
1481f166439SGeorge Zhang 		return;
1491f166439SGeorge Zhang 	}
1501f166439SGeorge Zhang 
1511f166439SGeorge Zhang 	if (!event_data || ev_payload->context_id == VMCI_INVALID_ID) {
1521f166439SGeorge Zhang 		pr_devel("Invalid event data\n");
1531f166439SGeorge Zhang 		return;
1541f166439SGeorge Zhang 	}
1551f166439SGeorge Zhang 
1561f166439SGeorge Zhang 	pr_devel("Updating context from (ID=0x%x) to (ID=0x%x) on event (type=%d)\n",
1571f166439SGeorge Zhang 		 vm_context_id, ev_payload->context_id, event_data->event);
1581f166439SGeorge Zhang 
1591f166439SGeorge Zhang 	vm_context_id = ev_payload->context_id;
1601f166439SGeorge Zhang }
1611f166439SGeorge Zhang 
1621f166439SGeorge Zhang /*
1631f166439SGeorge Zhang  * Verify that the host supports the hypercalls we need. If it does not,
1641f166439SGeorge Zhang  * try to find fallback hypercalls and use those instead.  Returns
1651f166439SGeorge Zhang  * true if required hypercalls (or fallback hypercalls) are
1661f166439SGeorge Zhang  * supported by the host, false otherwise.
1671f166439SGeorge Zhang  */
168782f2445SDmitry Torokhov static int vmci_check_host_caps(struct pci_dev *pdev)
1691f166439SGeorge Zhang {
1701f166439SGeorge Zhang 	bool result;
1711f166439SGeorge Zhang 	struct vmci_resource_query_msg *msg;
1721f166439SGeorge Zhang 	u32 msg_size = sizeof(struct vmci_resource_query_hdr) +
1731f166439SGeorge Zhang 				VMCI_UTIL_NUM_RESOURCES * sizeof(u32);
1741f166439SGeorge Zhang 	struct vmci_datagram *check_msg;
1751f166439SGeorge Zhang 
1761f166439SGeorge Zhang 	check_msg = kmalloc(msg_size, GFP_KERNEL);
1771f166439SGeorge Zhang 	if (!check_msg) {
1781f166439SGeorge Zhang 		dev_err(&pdev->dev, "%s: Insufficient memory\n", __func__);
179782f2445SDmitry Torokhov 		return -ENOMEM;
1801f166439SGeorge Zhang 	}
1811f166439SGeorge Zhang 
1821f166439SGeorge Zhang 	check_msg->dst = vmci_make_handle(VMCI_HYPERVISOR_CONTEXT_ID,
1831f166439SGeorge Zhang 					  VMCI_RESOURCES_QUERY);
1841f166439SGeorge Zhang 	check_msg->src = VMCI_ANON_SRC_HANDLE;
1851f166439SGeorge Zhang 	check_msg->payload_size = msg_size - VMCI_DG_HEADERSIZE;
1861f166439SGeorge Zhang 	msg = (struct vmci_resource_query_msg *)VMCI_DG_PAYLOAD(check_msg);
1871f166439SGeorge Zhang 
1881f166439SGeorge Zhang 	msg->num_resources = VMCI_UTIL_NUM_RESOURCES;
1891f166439SGeorge Zhang 	msg->resources[0] = VMCI_GET_CONTEXT_ID;
1901f166439SGeorge Zhang 
1911f166439SGeorge Zhang 	/* Checks that hyper calls are supported */
1921f166439SGeorge Zhang 	result = vmci_send_datagram(check_msg) == 0x01;
1931f166439SGeorge Zhang 	kfree(check_msg);
1941f166439SGeorge Zhang 
1951f166439SGeorge Zhang 	dev_dbg(&pdev->dev, "%s: Host capability check: %s\n",
1961f166439SGeorge Zhang 		__func__, result ? "PASSED" : "FAILED");
1971f166439SGeorge Zhang 
1981f166439SGeorge Zhang 	/* We need the vector. There are no fallbacks. */
199782f2445SDmitry Torokhov 	return result ? 0 : -ENXIO;
2001f166439SGeorge Zhang }
2011f166439SGeorge Zhang 
2021f166439SGeorge Zhang /*
2031f166439SGeorge Zhang  * Reads datagrams from the data in port and dispatches them. We
2041f166439SGeorge Zhang  * always start reading datagrams into only the first page of the
2051f166439SGeorge Zhang  * datagram buffer. If the datagrams don't fit into one page, we
2061f166439SGeorge Zhang  * use the maximum datagram buffer size for the remainder of the
2071f166439SGeorge Zhang  * invocation. This is a simple heuristic for not penalizing
2081f166439SGeorge Zhang  * small datagrams.
2091f166439SGeorge Zhang  *
2101f166439SGeorge Zhang  * This function assumes that it has exclusive access to the data
2111f166439SGeorge Zhang  * in port for the duration of the call.
2121f166439SGeorge Zhang  */
2131f166439SGeorge Zhang static void vmci_dispatch_dgs(unsigned long data)
2141f166439SGeorge Zhang {
2151f166439SGeorge Zhang 	struct vmci_guest_device *vmci_dev = (struct vmci_guest_device *)data;
2161f166439SGeorge Zhang 	u8 *dg_in_buffer = vmci_dev->data_buffer;
2171f166439SGeorge Zhang 	struct vmci_datagram *dg;
2181f166439SGeorge Zhang 	size_t dg_in_buffer_size = VMCI_MAX_DG_SIZE;
2191f166439SGeorge Zhang 	size_t current_dg_in_buffer_size = PAGE_SIZE;
2201f166439SGeorge Zhang 	size_t remaining_bytes;
2211f166439SGeorge Zhang 
2221f166439SGeorge Zhang 	BUILD_BUG_ON(VMCI_MAX_DG_SIZE < PAGE_SIZE);
2231f166439SGeorge Zhang 
2241f166439SGeorge Zhang 	ioread8_rep(vmci_dev->iobase + VMCI_DATA_IN_ADDR,
2251f166439SGeorge Zhang 		    vmci_dev->data_buffer, current_dg_in_buffer_size);
2261f166439SGeorge Zhang 	dg = (struct vmci_datagram *)dg_in_buffer;
2271f166439SGeorge Zhang 	remaining_bytes = current_dg_in_buffer_size;
2281f166439SGeorge Zhang 
2291f166439SGeorge Zhang 	while (dg->dst.resource != VMCI_INVALID_ID ||
2301f166439SGeorge Zhang 	       remaining_bytes > PAGE_SIZE) {
2311f166439SGeorge Zhang 		unsigned dg_in_size;
2321f166439SGeorge Zhang 
2331f166439SGeorge Zhang 		/*
2341f166439SGeorge Zhang 		 * When the input buffer spans multiple pages, a datagram can
2351f166439SGeorge Zhang 		 * start on any page boundary in the buffer.
2361f166439SGeorge Zhang 		 */
2371f166439SGeorge Zhang 		if (dg->dst.resource == VMCI_INVALID_ID) {
2381f166439SGeorge Zhang 			dg = (struct vmci_datagram *)roundup(
2391f166439SGeorge Zhang 				(uintptr_t)dg + 1, PAGE_SIZE);
2401f166439SGeorge Zhang 			remaining_bytes =
2411f166439SGeorge Zhang 				(size_t)(dg_in_buffer +
2421f166439SGeorge Zhang 					 current_dg_in_buffer_size -
2431f166439SGeorge Zhang 					 (u8 *)dg);
2441f166439SGeorge Zhang 			continue;
2451f166439SGeorge Zhang 		}
2461f166439SGeorge Zhang 
2471f166439SGeorge Zhang 		dg_in_size = VMCI_DG_SIZE_ALIGNED(dg);
2481f166439SGeorge Zhang 
2491f166439SGeorge Zhang 		if (dg_in_size <= dg_in_buffer_size) {
2501f166439SGeorge Zhang 			int result;
2511f166439SGeorge Zhang 
2521f166439SGeorge Zhang 			/*
2531f166439SGeorge Zhang 			 * If the remaining bytes in the datagram
2541f166439SGeorge Zhang 			 * buffer doesn't contain the complete
2551f166439SGeorge Zhang 			 * datagram, we first make sure we have enough
2561f166439SGeorge Zhang 			 * room for it and then we read the reminder
2571f166439SGeorge Zhang 			 * of the datagram and possibly any following
2581f166439SGeorge Zhang 			 * datagrams.
2591f166439SGeorge Zhang 			 */
2601f166439SGeorge Zhang 			if (dg_in_size > remaining_bytes) {
2611f166439SGeorge Zhang 				if (remaining_bytes !=
2621f166439SGeorge Zhang 				    current_dg_in_buffer_size) {
2631f166439SGeorge Zhang 
2641f166439SGeorge Zhang 					/*
2651f166439SGeorge Zhang 					 * We move the partial
2661f166439SGeorge Zhang 					 * datagram to the front and
2671f166439SGeorge Zhang 					 * read the reminder of the
2681f166439SGeorge Zhang 					 * datagram and possibly
2691f166439SGeorge Zhang 					 * following calls into the
2701f166439SGeorge Zhang 					 * following bytes.
2711f166439SGeorge Zhang 					 */
2721f166439SGeorge Zhang 					memmove(dg_in_buffer, dg_in_buffer +
2731f166439SGeorge Zhang 						current_dg_in_buffer_size -
2741f166439SGeorge Zhang 						remaining_bytes,
2751f166439SGeorge Zhang 						remaining_bytes);
2761f166439SGeorge Zhang 					dg = (struct vmci_datagram *)
2771f166439SGeorge Zhang 					    dg_in_buffer;
2781f166439SGeorge Zhang 				}
2791f166439SGeorge Zhang 
2801f166439SGeorge Zhang 				if (current_dg_in_buffer_size !=
2811f166439SGeorge Zhang 				    dg_in_buffer_size)
2821f166439SGeorge Zhang 					current_dg_in_buffer_size =
2831f166439SGeorge Zhang 					    dg_in_buffer_size;
2841f166439SGeorge Zhang 
2851f166439SGeorge Zhang 				ioread8_rep(vmci_dev->iobase +
2861f166439SGeorge Zhang 						VMCI_DATA_IN_ADDR,
2871f166439SGeorge Zhang 					vmci_dev->data_buffer +
2881f166439SGeorge Zhang 						remaining_bytes,
2891f166439SGeorge Zhang 					current_dg_in_buffer_size -
2901f166439SGeorge Zhang 						remaining_bytes);
2911f166439SGeorge Zhang 			}
2921f166439SGeorge Zhang 
2931f166439SGeorge Zhang 			/*
2941f166439SGeorge Zhang 			 * We special case event datagrams from the
2951f166439SGeorge Zhang 			 * hypervisor.
2961f166439SGeorge Zhang 			 */
2971f166439SGeorge Zhang 			if (dg->src.context == VMCI_HYPERVISOR_CONTEXT_ID &&
2981f166439SGeorge Zhang 			    dg->dst.resource == VMCI_EVENT_HANDLER) {
2991f166439SGeorge Zhang 				result = vmci_event_dispatch(dg);
3001f166439SGeorge Zhang 			} else {
3011f166439SGeorge Zhang 				result = vmci_datagram_invoke_guest_handler(dg);
3021f166439SGeorge Zhang 			}
3031f166439SGeorge Zhang 			if (result < VMCI_SUCCESS)
3041f166439SGeorge Zhang 				dev_dbg(vmci_dev->dev,
3051f166439SGeorge Zhang 					"Datagram with resource (ID=0x%x) failed (err=%d)\n",
3061f166439SGeorge Zhang 					 dg->dst.resource, result);
3071f166439SGeorge Zhang 
3081f166439SGeorge Zhang 			/* On to the next datagram. */
3091f166439SGeorge Zhang 			dg = (struct vmci_datagram *)((u8 *)dg +
3101f166439SGeorge Zhang 						      dg_in_size);
3111f166439SGeorge Zhang 		} else {
3121f166439SGeorge Zhang 			size_t bytes_to_skip;
3131f166439SGeorge Zhang 
3141f166439SGeorge Zhang 			/*
3151f166439SGeorge Zhang 			 * Datagram doesn't fit in datagram buffer of maximal
3161f166439SGeorge Zhang 			 * size. We drop it.
3171f166439SGeorge Zhang 			 */
3181f166439SGeorge Zhang 			dev_dbg(vmci_dev->dev,
3191f166439SGeorge Zhang 				"Failed to receive datagram (size=%u bytes)\n",
3201f166439SGeorge Zhang 				 dg_in_size);
3211f166439SGeorge Zhang 
3221f166439SGeorge Zhang 			bytes_to_skip = dg_in_size - remaining_bytes;
3231f166439SGeorge Zhang 			if (current_dg_in_buffer_size != dg_in_buffer_size)
3241f166439SGeorge Zhang 				current_dg_in_buffer_size = dg_in_buffer_size;
3251f166439SGeorge Zhang 
3261f166439SGeorge Zhang 			for (;;) {
3271f166439SGeorge Zhang 				ioread8_rep(vmci_dev->iobase +
3281f166439SGeorge Zhang 						VMCI_DATA_IN_ADDR,
3291f166439SGeorge Zhang 					vmci_dev->data_buffer,
3301f166439SGeorge Zhang 					current_dg_in_buffer_size);
3311f166439SGeorge Zhang 				if (bytes_to_skip <= current_dg_in_buffer_size)
3321f166439SGeorge Zhang 					break;
3331f166439SGeorge Zhang 
3341f166439SGeorge Zhang 				bytes_to_skip -= current_dg_in_buffer_size;
3351f166439SGeorge Zhang 			}
3361f166439SGeorge Zhang 			dg = (struct vmci_datagram *)(dg_in_buffer +
3371f166439SGeorge Zhang 						      bytes_to_skip);
3381f166439SGeorge Zhang 		}
3391f166439SGeorge Zhang 
3401f166439SGeorge Zhang 		remaining_bytes =
3411f166439SGeorge Zhang 		    (size_t) (dg_in_buffer + current_dg_in_buffer_size -
3421f166439SGeorge Zhang 			      (u8 *)dg);
3431f166439SGeorge Zhang 
3441f166439SGeorge Zhang 		if (remaining_bytes < VMCI_DG_HEADERSIZE) {
3451f166439SGeorge Zhang 			/* Get the next batch of datagrams. */
3461f166439SGeorge Zhang 
3471f166439SGeorge Zhang 			ioread8_rep(vmci_dev->iobase + VMCI_DATA_IN_ADDR,
3481f166439SGeorge Zhang 				    vmci_dev->data_buffer,
3491f166439SGeorge Zhang 				    current_dg_in_buffer_size);
3501f166439SGeorge Zhang 			dg = (struct vmci_datagram *)dg_in_buffer;
3511f166439SGeorge Zhang 			remaining_bytes = current_dg_in_buffer_size;
3521f166439SGeorge Zhang 		}
3531f166439SGeorge Zhang 	}
3541f166439SGeorge Zhang }
3551f166439SGeorge Zhang 
3561f166439SGeorge Zhang /*
3571f166439SGeorge Zhang  * Scans the notification bitmap for raised flags, clears them
3581f166439SGeorge Zhang  * and handles the notifications.
3591f166439SGeorge Zhang  */
3601f166439SGeorge Zhang static void vmci_process_bitmap(unsigned long data)
3611f166439SGeorge Zhang {
3621f166439SGeorge Zhang 	struct vmci_guest_device *dev = (struct vmci_guest_device *)data;
3631f166439SGeorge Zhang 
3641f166439SGeorge Zhang 	if (!dev->notification_bitmap) {
3651f166439SGeorge Zhang 		dev_dbg(dev->dev, "No bitmap present in %s\n", __func__);
3661f166439SGeorge Zhang 		return;
3671f166439SGeorge Zhang 	}
3681f166439SGeorge Zhang 
3691f166439SGeorge Zhang 	vmci_dbell_scan_notification_entries(dev->notification_bitmap);
3701f166439SGeorge Zhang }
3711f166439SGeorge Zhang 
3721f166439SGeorge Zhang /*
3731f166439SGeorge Zhang  * Enable MSI-X.  Try exclusive vectors first, then shared vectors.
3741f166439SGeorge Zhang  */
3751f166439SGeorge Zhang static int vmci_enable_msix(struct pci_dev *pdev,
3761f166439SGeorge Zhang 			    struct vmci_guest_device *vmci_dev)
3771f166439SGeorge Zhang {
3781f166439SGeorge Zhang 	int i;
3791f166439SGeorge Zhang 	int result;
3801f166439SGeorge Zhang 
3811f166439SGeorge Zhang 	for (i = 0; i < VMCI_MAX_INTRS; ++i) {
3821f166439SGeorge Zhang 		vmci_dev->msix_entries[i].entry = i;
3831f166439SGeorge Zhang 		vmci_dev->msix_entries[i].vector = i;
3841f166439SGeorge Zhang 	}
3851f166439SGeorge Zhang 
386e0117521SAlexander Gordeev 	result = pci_enable_msix_exact(pdev,
387e0117521SAlexander Gordeev 				       vmci_dev->msix_entries, VMCI_MAX_INTRS);
3881f166439SGeorge Zhang 	if (result == 0)
3891f166439SGeorge Zhang 		vmci_dev->exclusive_vectors = true;
390e0117521SAlexander Gordeev 	else if (result == -ENOSPC)
391e0117521SAlexander Gordeev 		result = pci_enable_msix_exact(pdev, vmci_dev->msix_entries, 1);
3921f166439SGeorge Zhang 
3931f166439SGeorge Zhang 	return result;
3941f166439SGeorge Zhang }
3951f166439SGeorge Zhang 
3961f166439SGeorge Zhang /*
3971f166439SGeorge Zhang  * Interrupt handler for legacy or MSI interrupt, or for first MSI-X
3981f166439SGeorge Zhang  * interrupt (vector VMCI_INTR_DATAGRAM).
3991f166439SGeorge Zhang  */
4001f166439SGeorge Zhang static irqreturn_t vmci_interrupt(int irq, void *_dev)
4011f166439SGeorge Zhang {
4021f166439SGeorge Zhang 	struct vmci_guest_device *dev = _dev;
4031f166439SGeorge Zhang 
4041f166439SGeorge Zhang 	/*
4051f166439SGeorge Zhang 	 * If we are using MSI-X with exclusive vectors then we simply schedule
4061f166439SGeorge Zhang 	 * the datagram tasklet, since we know the interrupt was meant for us.
4071f166439SGeorge Zhang 	 * Otherwise we must read the ICR to determine what to do.
4081f166439SGeorge Zhang 	 */
4091f166439SGeorge Zhang 
4101f166439SGeorge Zhang 	if (dev->intr_type == VMCI_INTR_TYPE_MSIX && dev->exclusive_vectors) {
4111f166439SGeorge Zhang 		tasklet_schedule(&dev->datagram_tasklet);
4121f166439SGeorge Zhang 	} else {
4131f166439SGeorge Zhang 		unsigned int icr;
4141f166439SGeorge Zhang 
4151f166439SGeorge Zhang 		/* Acknowledge interrupt and determine what needs doing. */
4161f166439SGeorge Zhang 		icr = ioread32(dev->iobase + VMCI_ICR_ADDR);
4171f166439SGeorge Zhang 		if (icr == 0 || icr == ~0)
4181f166439SGeorge Zhang 			return IRQ_NONE;
4191f166439SGeorge Zhang 
4201f166439SGeorge Zhang 		if (icr & VMCI_ICR_DATAGRAM) {
4211f166439SGeorge Zhang 			tasklet_schedule(&dev->datagram_tasklet);
4221f166439SGeorge Zhang 			icr &= ~VMCI_ICR_DATAGRAM;
4231f166439SGeorge Zhang 		}
4241f166439SGeorge Zhang 
4251f166439SGeorge Zhang 		if (icr & VMCI_ICR_NOTIFICATION) {
4261f166439SGeorge Zhang 			tasklet_schedule(&dev->bm_tasklet);
4271f166439SGeorge Zhang 			icr &= ~VMCI_ICR_NOTIFICATION;
4281f166439SGeorge Zhang 		}
4291f166439SGeorge Zhang 
4301f166439SGeorge Zhang 		if (icr != 0)
4311f166439SGeorge Zhang 			dev_warn(dev->dev,
4321f166439SGeorge Zhang 				 "Ignoring unknown interrupt cause (%d)\n",
4331f166439SGeorge Zhang 				 icr);
4341f166439SGeorge Zhang 	}
4351f166439SGeorge Zhang 
4361f166439SGeorge Zhang 	return IRQ_HANDLED;
4371f166439SGeorge Zhang }
4381f166439SGeorge Zhang 
4391f166439SGeorge Zhang /*
4401f166439SGeorge Zhang  * Interrupt handler for MSI-X interrupt vector VMCI_INTR_NOTIFICATION,
4411f166439SGeorge Zhang  * which is for the notification bitmap.  Will only get called if we are
4421f166439SGeorge Zhang  * using MSI-X with exclusive vectors.
4431f166439SGeorge Zhang  */
4441f166439SGeorge Zhang static irqreturn_t vmci_interrupt_bm(int irq, void *_dev)
4451f166439SGeorge Zhang {
4461f166439SGeorge Zhang 	struct vmci_guest_device *dev = _dev;
4471f166439SGeorge Zhang 
4481f166439SGeorge Zhang 	/* For MSI-X we can just assume it was meant for us. */
4491f166439SGeorge Zhang 	tasklet_schedule(&dev->bm_tasklet);
4501f166439SGeorge Zhang 
4511f166439SGeorge Zhang 	return IRQ_HANDLED;
4521f166439SGeorge Zhang }
4531f166439SGeorge Zhang 
4541f166439SGeorge Zhang /*
4551f166439SGeorge Zhang  * Most of the initialization at module load time is done here.
4561f166439SGeorge Zhang  */
4571f166439SGeorge Zhang static int vmci_guest_probe_device(struct pci_dev *pdev,
4581f166439SGeorge Zhang 				   const struct pci_device_id *id)
4591f166439SGeorge Zhang {
4601f166439SGeorge Zhang 	struct vmci_guest_device *vmci_dev;
4611f166439SGeorge Zhang 	void __iomem *iobase;
4621f166439SGeorge Zhang 	unsigned int capabilities;
4631f166439SGeorge Zhang 	unsigned long cmd;
4641f166439SGeorge Zhang 	int vmci_err;
4651f166439SGeorge Zhang 	int error;
4661f166439SGeorge Zhang 
4671f166439SGeorge Zhang 	dev_dbg(&pdev->dev, "Probing for vmci/PCI guest device\n");
4681f166439SGeorge Zhang 
4691f166439SGeorge Zhang 	error = pcim_enable_device(pdev);
4701f166439SGeorge Zhang 	if (error) {
4711f166439SGeorge Zhang 		dev_err(&pdev->dev,
4721f166439SGeorge Zhang 			"Failed to enable VMCI device: %d\n", error);
4731f166439SGeorge Zhang 		return error;
4741f166439SGeorge Zhang 	}
4751f166439SGeorge Zhang 
4761f166439SGeorge Zhang 	error = pcim_iomap_regions(pdev, 1 << 0, KBUILD_MODNAME);
4771f166439SGeorge Zhang 	if (error) {
4781f166439SGeorge Zhang 		dev_err(&pdev->dev, "Failed to reserve/map IO regions\n");
4791f166439SGeorge Zhang 		return error;
4801f166439SGeorge Zhang 	}
4811f166439SGeorge Zhang 
4821f166439SGeorge Zhang 	iobase = pcim_iomap_table(pdev)[0];
4831f166439SGeorge Zhang 
4841f166439SGeorge Zhang 	dev_info(&pdev->dev, "Found VMCI PCI device at %#lx, irq %u\n",
4851f166439SGeorge Zhang 		 (unsigned long)iobase, pdev->irq);
4861f166439SGeorge Zhang 
4871f166439SGeorge Zhang 	vmci_dev = devm_kzalloc(&pdev->dev, sizeof(*vmci_dev), GFP_KERNEL);
4881f166439SGeorge Zhang 	if (!vmci_dev) {
4891f166439SGeorge Zhang 		dev_err(&pdev->dev,
4901f166439SGeorge Zhang 			"Can't allocate memory for VMCI device\n");
4911f166439SGeorge Zhang 		return -ENOMEM;
4921f166439SGeorge Zhang 	}
4931f166439SGeorge Zhang 
4941f166439SGeorge Zhang 	vmci_dev->dev = &pdev->dev;
4951f166439SGeorge Zhang 	vmci_dev->intr_type = VMCI_INTR_TYPE_INTX;
4961f166439SGeorge Zhang 	vmci_dev->exclusive_vectors = false;
4971f166439SGeorge Zhang 	vmci_dev->iobase = iobase;
4981f166439SGeorge Zhang 
4991f166439SGeorge Zhang 	tasklet_init(&vmci_dev->datagram_tasklet,
5001f166439SGeorge Zhang 		     vmci_dispatch_dgs, (unsigned long)vmci_dev);
5011f166439SGeorge Zhang 	tasklet_init(&vmci_dev->bm_tasklet,
5021f166439SGeorge Zhang 		     vmci_process_bitmap, (unsigned long)vmci_dev);
5031f166439SGeorge Zhang 
5041f166439SGeorge Zhang 	vmci_dev->data_buffer = vmalloc(VMCI_MAX_DG_SIZE);
5051f166439SGeorge Zhang 	if (!vmci_dev->data_buffer) {
5061f166439SGeorge Zhang 		dev_err(&pdev->dev,
5071f166439SGeorge Zhang 			"Can't allocate memory for datagram buffer\n");
5081f166439SGeorge Zhang 		return -ENOMEM;
5091f166439SGeorge Zhang 	}
5101f166439SGeorge Zhang 
5111f166439SGeorge Zhang 	pci_set_master(pdev);	/* To enable queue_pair functionality. */
5121f166439SGeorge Zhang 
5131f166439SGeorge Zhang 	/*
5141f166439SGeorge Zhang 	 * Verify that the VMCI Device supports the capabilities that
5151f166439SGeorge Zhang 	 * we need. If the device is missing capabilities that we would
5161f166439SGeorge Zhang 	 * like to use, check for fallback capabilities and use those
5171f166439SGeorge Zhang 	 * instead (so we can run a new VM on old hosts). Fail the load if
5181f166439SGeorge Zhang 	 * a required capability is missing and there is no fallback.
5191f166439SGeorge Zhang 	 *
5201f166439SGeorge Zhang 	 * Right now, we need datagrams. There are no fallbacks.
5211f166439SGeorge Zhang 	 */
5221f166439SGeorge Zhang 	capabilities = ioread32(vmci_dev->iobase + VMCI_CAPS_ADDR);
5231f166439SGeorge Zhang 	if (!(capabilities & VMCI_CAPS_DATAGRAM)) {
5241f166439SGeorge Zhang 		dev_err(&pdev->dev, "Device does not support datagrams\n");
5251f166439SGeorge Zhang 		error = -ENXIO;
5261f166439SGeorge Zhang 		goto err_free_data_buffer;
5271f166439SGeorge Zhang 	}
5281f166439SGeorge Zhang 
5291f166439SGeorge Zhang 	/*
5301f166439SGeorge Zhang 	 * If the hardware supports notifications, we will use that as
5311f166439SGeorge Zhang 	 * well.
5321f166439SGeorge Zhang 	 */
5331f166439SGeorge Zhang 	if (capabilities & VMCI_CAPS_NOTIFICATIONS) {
5346d6dfb4fSAndy King 		vmci_dev->notification_bitmap = dma_alloc_coherent(
5356d6dfb4fSAndy King 			&pdev->dev, PAGE_SIZE, &vmci_dev->notification_base,
5366d6dfb4fSAndy King 			GFP_KERNEL);
5371f166439SGeorge Zhang 		if (!vmci_dev->notification_bitmap) {
5381f166439SGeorge Zhang 			dev_warn(&pdev->dev,
5391f166439SGeorge Zhang 				 "Unable to allocate notification bitmap\n");
5401f166439SGeorge Zhang 		} else {
5411f166439SGeorge Zhang 			memset(vmci_dev->notification_bitmap, 0, PAGE_SIZE);
5421f166439SGeorge Zhang 			capabilities |= VMCI_CAPS_NOTIFICATIONS;
5431f166439SGeorge Zhang 		}
5441f166439SGeorge Zhang 	}
5451f166439SGeorge Zhang 
5461f166439SGeorge Zhang 	dev_info(&pdev->dev, "Using capabilities 0x%x\n", capabilities);
5471f166439SGeorge Zhang 
5481f166439SGeorge Zhang 	/* Let the host know which capabilities we intend to use. */
5491f166439SGeorge Zhang 	iowrite32(capabilities, vmci_dev->iobase + VMCI_CAPS_ADDR);
5501f166439SGeorge Zhang 
5511f166439SGeorge Zhang 	/* Set up global device so that we can start sending datagrams */
5521f166439SGeorge Zhang 	spin_lock_irq(&vmci_dev_spinlock);
5531f166439SGeorge Zhang 	vmci_dev_g = vmci_dev;
5546d6dfb4fSAndy King 	vmci_pdev = pdev;
5551f166439SGeorge Zhang 	spin_unlock_irq(&vmci_dev_spinlock);
5561f166439SGeorge Zhang 
5571f166439SGeorge Zhang 	/*
5581f166439SGeorge Zhang 	 * Register notification bitmap with device if that capability is
5591f166439SGeorge Zhang 	 * used.
5601f166439SGeorge Zhang 	 */
5611f166439SGeorge Zhang 	if (capabilities & VMCI_CAPS_NOTIFICATIONS) {
5626d6dfb4fSAndy King 		unsigned long bitmap_ppn =
5636d6dfb4fSAndy King 			vmci_dev->notification_base >> PAGE_SHIFT;
5641f166439SGeorge Zhang 		if (!vmci_dbell_register_notification_bitmap(bitmap_ppn)) {
5651f166439SGeorge Zhang 			dev_warn(&pdev->dev,
5661f166439SGeorge Zhang 				 "VMCI device unable to register notification bitmap with PPN 0x%x\n",
5671f166439SGeorge Zhang 				 (u32) bitmap_ppn);
568782f2445SDmitry Torokhov 			error = -ENXIO;
5691f166439SGeorge Zhang 			goto err_remove_vmci_dev_g;
5701f166439SGeorge Zhang 		}
5711f166439SGeorge Zhang 	}
5721f166439SGeorge Zhang 
5731f166439SGeorge Zhang 	/* Check host capabilities. */
574782f2445SDmitry Torokhov 	error = vmci_check_host_caps(pdev);
575782f2445SDmitry Torokhov 	if (error)
5761f166439SGeorge Zhang 		goto err_remove_bitmap;
5771f166439SGeorge Zhang 
5781f166439SGeorge Zhang 	/* Enable device. */
5791f166439SGeorge Zhang 
5801f166439SGeorge Zhang 	/*
5811f166439SGeorge Zhang 	 * We subscribe to the VMCI_EVENT_CTX_ID_UPDATE here so we can
5821f166439SGeorge Zhang 	 * update the internal context id when needed.
5831f166439SGeorge Zhang 	 */
5841f166439SGeorge Zhang 	vmci_err = vmci_event_subscribe(VMCI_EVENT_CTX_ID_UPDATE,
5851f166439SGeorge Zhang 					vmci_guest_cid_update, NULL,
5861f166439SGeorge Zhang 					&ctx_update_sub_id);
5871f166439SGeorge Zhang 	if (vmci_err < VMCI_SUCCESS)
5881f166439SGeorge Zhang 		dev_warn(&pdev->dev,
5891f166439SGeorge Zhang 			 "Failed to subscribe to event (type=%d): %d\n",
5901f166439SGeorge Zhang 			 VMCI_EVENT_CTX_ID_UPDATE, vmci_err);
5911f166439SGeorge Zhang 
5921f166439SGeorge Zhang 	/*
5931f166439SGeorge Zhang 	 * Enable interrupts.  Try MSI-X first, then MSI, and then fallback on
5941f166439SGeorge Zhang 	 * legacy interrupts.
5951f166439SGeorge Zhang 	 */
5961f166439SGeorge Zhang 	if (!vmci_disable_msix && !vmci_enable_msix(pdev, vmci_dev)) {
5971f166439SGeorge Zhang 		vmci_dev->intr_type = VMCI_INTR_TYPE_MSIX;
5981f166439SGeorge Zhang 		vmci_dev->irq = vmci_dev->msix_entries[0].vector;
5991f166439SGeorge Zhang 	} else if (!vmci_disable_msi && !pci_enable_msi(pdev)) {
6001f166439SGeorge Zhang 		vmci_dev->intr_type = VMCI_INTR_TYPE_MSI;
6011f166439SGeorge Zhang 		vmci_dev->irq = pdev->irq;
6021f166439SGeorge Zhang 	} else {
6031f166439SGeorge Zhang 		vmci_dev->intr_type = VMCI_INTR_TYPE_INTX;
6041f166439SGeorge Zhang 		vmci_dev->irq = pdev->irq;
6051f166439SGeorge Zhang 	}
6061f166439SGeorge Zhang 
6071f166439SGeorge Zhang 	/*
6081f166439SGeorge Zhang 	 * Request IRQ for legacy or MSI interrupts, or for first
6091f166439SGeorge Zhang 	 * MSI-X vector.
6101f166439SGeorge Zhang 	 */
6111f166439SGeorge Zhang 	error = request_irq(vmci_dev->irq, vmci_interrupt, IRQF_SHARED,
6121f166439SGeorge Zhang 			    KBUILD_MODNAME, vmci_dev);
6131f166439SGeorge Zhang 	if (error) {
6141f166439SGeorge Zhang 		dev_err(&pdev->dev, "Irq %u in use: %d\n",
6151f166439SGeorge Zhang 			vmci_dev->irq, error);
6161f166439SGeorge Zhang 		goto err_disable_msi;
6171f166439SGeorge Zhang 	}
6181f166439SGeorge Zhang 
6191f166439SGeorge Zhang 	/*
6201f166439SGeorge Zhang 	 * For MSI-X with exclusive vectors we need to request an
6211f166439SGeorge Zhang 	 * interrupt for each vector so that we get a separate
6221f166439SGeorge Zhang 	 * interrupt handler routine.  This allows us to distinguish
6231f166439SGeorge Zhang 	 * between the vectors.
6241f166439SGeorge Zhang 	 */
6251f166439SGeorge Zhang 	if (vmci_dev->exclusive_vectors) {
6261f166439SGeorge Zhang 		error = request_irq(vmci_dev->msix_entries[1].vector,
6271f166439SGeorge Zhang 				    vmci_interrupt_bm, 0, KBUILD_MODNAME,
6281f166439SGeorge Zhang 				    vmci_dev);
6291f166439SGeorge Zhang 		if (error) {
6301f166439SGeorge Zhang 			dev_err(&pdev->dev,
6311f166439SGeorge Zhang 				"Failed to allocate irq %u: %d\n",
6321f166439SGeorge Zhang 				vmci_dev->msix_entries[1].vector, error);
6331f166439SGeorge Zhang 			goto err_free_irq;
6341f166439SGeorge Zhang 		}
6351f166439SGeorge Zhang 	}
6361f166439SGeorge Zhang 
6371f166439SGeorge Zhang 	dev_dbg(&pdev->dev, "Registered device\n");
6381f166439SGeorge Zhang 
6391f166439SGeorge Zhang 	atomic_inc(&vmci_num_guest_devices);
6401f166439SGeorge Zhang 
6411f166439SGeorge Zhang 	/* Enable specific interrupt bits. */
6421f166439SGeorge Zhang 	cmd = VMCI_IMR_DATAGRAM;
6431f166439SGeorge Zhang 	if (capabilities & VMCI_CAPS_NOTIFICATIONS)
6441f166439SGeorge Zhang 		cmd |= VMCI_IMR_NOTIFICATION;
6451f166439SGeorge Zhang 	iowrite32(cmd, vmci_dev->iobase + VMCI_IMR_ADDR);
6461f166439SGeorge Zhang 
6471f166439SGeorge Zhang 	/* Enable interrupts. */
6481f166439SGeorge Zhang 	iowrite32(VMCI_CONTROL_INT_ENABLE,
6491f166439SGeorge Zhang 		  vmci_dev->iobase + VMCI_CONTROL_ADDR);
6501f166439SGeorge Zhang 
6511f166439SGeorge Zhang 	pci_set_drvdata(pdev, vmci_dev);
6521f166439SGeorge Zhang 	return 0;
6531f166439SGeorge Zhang 
6541f166439SGeorge Zhang err_free_irq:
6559089e3beSWei Yongjun 	free_irq(vmci_dev->irq, vmci_dev);
6561f166439SGeorge Zhang 	tasklet_kill(&vmci_dev->datagram_tasklet);
6571f166439SGeorge Zhang 	tasklet_kill(&vmci_dev->bm_tasklet);
6581f166439SGeorge Zhang 
6591f166439SGeorge Zhang err_disable_msi:
6601f166439SGeorge Zhang 	if (vmci_dev->intr_type == VMCI_INTR_TYPE_MSIX)
6611f166439SGeorge Zhang 		pci_disable_msix(pdev);
6621f166439SGeorge Zhang 	else if (vmci_dev->intr_type == VMCI_INTR_TYPE_MSI)
6631f166439SGeorge Zhang 		pci_disable_msi(pdev);
6641f166439SGeorge Zhang 
6651f166439SGeorge Zhang 	vmci_err = vmci_event_unsubscribe(ctx_update_sub_id);
6661f166439SGeorge Zhang 	if (vmci_err < VMCI_SUCCESS)
6671f166439SGeorge Zhang 		dev_warn(&pdev->dev,
6681f166439SGeorge Zhang 			 "Failed to unsubscribe from event (type=%d) with subscriber (ID=0x%x): %d\n",
6691f166439SGeorge Zhang 			 VMCI_EVENT_CTX_ID_UPDATE, ctx_update_sub_id, vmci_err);
6701f166439SGeorge Zhang 
6711f166439SGeorge Zhang err_remove_bitmap:
6721f166439SGeorge Zhang 	if (vmci_dev->notification_bitmap) {
6731f166439SGeorge Zhang 		iowrite32(VMCI_CONTROL_RESET,
6741f166439SGeorge Zhang 			  vmci_dev->iobase + VMCI_CONTROL_ADDR);
6756d6dfb4fSAndy King 		dma_free_coherent(&pdev->dev, PAGE_SIZE,
6766d6dfb4fSAndy King 				  vmci_dev->notification_bitmap,
6776d6dfb4fSAndy King 				  vmci_dev->notification_base);
6781f166439SGeorge Zhang 	}
6791f166439SGeorge Zhang 
6801f166439SGeorge Zhang err_remove_vmci_dev_g:
6811f166439SGeorge Zhang 	spin_lock_irq(&vmci_dev_spinlock);
6826d6dfb4fSAndy King 	vmci_pdev = NULL;
6831f166439SGeorge Zhang 	vmci_dev_g = NULL;
6841f166439SGeorge Zhang 	spin_unlock_irq(&vmci_dev_spinlock);
6851f166439SGeorge Zhang 
6861f166439SGeorge Zhang err_free_data_buffer:
6871f166439SGeorge Zhang 	vfree(vmci_dev->data_buffer);
6881f166439SGeorge Zhang 
6891f166439SGeorge Zhang 	/* The rest are managed resources and will be freed by PCI core */
6901f166439SGeorge Zhang 	return error;
6911f166439SGeorge Zhang }
6921f166439SGeorge Zhang 
6931f166439SGeorge Zhang static void vmci_guest_remove_device(struct pci_dev *pdev)
6941f166439SGeorge Zhang {
6951f166439SGeorge Zhang 	struct vmci_guest_device *vmci_dev = pci_get_drvdata(pdev);
6961f166439SGeorge Zhang 	int vmci_err;
6971f166439SGeorge Zhang 
6981f166439SGeorge Zhang 	dev_dbg(&pdev->dev, "Removing device\n");
6991f166439SGeorge Zhang 
7001f166439SGeorge Zhang 	atomic_dec(&vmci_num_guest_devices);
7011f166439SGeorge Zhang 
7021f166439SGeorge Zhang 	vmci_qp_guest_endpoints_exit();
7031f166439SGeorge Zhang 
7041f166439SGeorge Zhang 	vmci_err = vmci_event_unsubscribe(ctx_update_sub_id);
7051f166439SGeorge Zhang 	if (vmci_err < VMCI_SUCCESS)
7061f166439SGeorge Zhang 		dev_warn(&pdev->dev,
7071f166439SGeorge Zhang 			 "Failed to unsubscribe from event (type=%d) with subscriber (ID=0x%x): %d\n",
7081f166439SGeorge Zhang 			 VMCI_EVENT_CTX_ID_UPDATE, ctx_update_sub_id, vmci_err);
7091f166439SGeorge Zhang 
7101f166439SGeorge Zhang 	spin_lock_irq(&vmci_dev_spinlock);
7111f166439SGeorge Zhang 	vmci_dev_g = NULL;
7126d6dfb4fSAndy King 	vmci_pdev = NULL;
7131f166439SGeorge Zhang 	spin_unlock_irq(&vmci_dev_spinlock);
7141f166439SGeorge Zhang 
7151f166439SGeorge Zhang 	dev_dbg(&pdev->dev, "Resetting vmci device\n");
7161f166439SGeorge Zhang 	iowrite32(VMCI_CONTROL_RESET, vmci_dev->iobase + VMCI_CONTROL_ADDR);
7171f166439SGeorge Zhang 
7181f166439SGeorge Zhang 	/*
7191f166439SGeorge Zhang 	 * Free IRQ and then disable MSI/MSI-X as appropriate.  For
7201f166439SGeorge Zhang 	 * MSI-X, we might have multiple vectors, each with their own
7211f166439SGeorge Zhang 	 * IRQ, which we must free too.
7221f166439SGeorge Zhang 	 */
7231f166439SGeorge Zhang 	free_irq(vmci_dev->irq, vmci_dev);
7241f166439SGeorge Zhang 	if (vmci_dev->intr_type == VMCI_INTR_TYPE_MSIX) {
7251f166439SGeorge Zhang 		if (vmci_dev->exclusive_vectors)
7261f166439SGeorge Zhang 			free_irq(vmci_dev->msix_entries[1].vector, vmci_dev);
7271f166439SGeorge Zhang 		pci_disable_msix(pdev);
7281f166439SGeorge Zhang 	} else if (vmci_dev->intr_type == VMCI_INTR_TYPE_MSI) {
7291f166439SGeorge Zhang 		pci_disable_msi(pdev);
7301f166439SGeorge Zhang 	}
7311f166439SGeorge Zhang 
7321f166439SGeorge Zhang 	tasklet_kill(&vmci_dev->datagram_tasklet);
7331f166439SGeorge Zhang 	tasklet_kill(&vmci_dev->bm_tasklet);
7341f166439SGeorge Zhang 
7351f166439SGeorge Zhang 	if (vmci_dev->notification_bitmap) {
7361f166439SGeorge Zhang 		/*
7371f166439SGeorge Zhang 		 * The device reset above cleared the bitmap state of the
7381f166439SGeorge Zhang 		 * device, so we can safely free it here.
7391f166439SGeorge Zhang 		 */
7401f166439SGeorge Zhang 
7416d6dfb4fSAndy King 		dma_free_coherent(&pdev->dev, PAGE_SIZE,
7426d6dfb4fSAndy King 				  vmci_dev->notification_bitmap,
7436d6dfb4fSAndy King 				  vmci_dev->notification_base);
7441f166439SGeorge Zhang 	}
7451f166439SGeorge Zhang 
7461f166439SGeorge Zhang 	vfree(vmci_dev->data_buffer);
7471f166439SGeorge Zhang 
7481f166439SGeorge Zhang 	/* The rest are managed resources and will be freed by PCI core */
7491f166439SGeorge Zhang }
7501f166439SGeorge Zhang 
75132182cd3SGreg Kroah-Hartman static const struct pci_device_id vmci_ids[] = {
7521f166439SGeorge Zhang 	{ PCI_DEVICE(PCI_VENDOR_ID_VMWARE, PCI_DEVICE_ID_VMWARE_VMCI), },
7531f166439SGeorge Zhang 	{ 0 },
7541f166439SGeorge Zhang };
7551f166439SGeorge Zhang MODULE_DEVICE_TABLE(pci, vmci_ids);
7561f166439SGeorge Zhang 
7571f166439SGeorge Zhang static struct pci_driver vmci_guest_driver = {
7581f166439SGeorge Zhang 	.name		= KBUILD_MODNAME,
7591f166439SGeorge Zhang 	.id_table	= vmci_ids,
7601f166439SGeorge Zhang 	.probe		= vmci_guest_probe_device,
7611f166439SGeorge Zhang 	.remove		= vmci_guest_remove_device,
7621f166439SGeorge Zhang };
7631f166439SGeorge Zhang 
7641f166439SGeorge Zhang int __init vmci_guest_init(void)
7651f166439SGeorge Zhang {
7661f166439SGeorge Zhang 	return pci_register_driver(&vmci_guest_driver);
7671f166439SGeorge Zhang }
7681f166439SGeorge Zhang 
7691f166439SGeorge Zhang void __exit vmci_guest_exit(void)
7701f166439SGeorge Zhang {
7711f166439SGeorge Zhang 	pci_unregister_driver(&vmci_guest_driver);
7721f166439SGeorge Zhang }
773