kvm: release: merge from trunk
[kvm-userspace.git] / drivers / hypercall.c
blob9c9462f66791981a9248e6eba9cfdb70d9291f1c
2 #include <linux/module.h>
3 #include <linux/kernel.h>
4 #include <linux/compiler.h>
5 #include <linux/pci.h>
6 #include <linux/init.h>
7 #include <linux/ioport.h>
8 #include <linux/completion.h>
9 #include <asm/io.h>
10 #include <asm/uaccess.h>
11 #include <asm/irq.h>
13 #define HYPERCALL_DRIVER_NAME "Qumranet hypercall driver"
14 #define HYPERCALL_DRIVER_VERSION "1"
15 #define PCI_VENDOR_ID_HYPERCALL 0x5002
16 #define PCI_DEVICE_ID_HYPERCALL 0x2258
18 MODULE_AUTHOR ("Dor Laor <dor.laor@qumranet.com>");
19 MODULE_DESCRIPTION (HYPERCALL_DRIVER_NAME);
20 MODULE_LICENSE("GPL");
21 MODULE_VERSION(HYPERCALL_DRIVER_VERSION);
23 static int debug = 0;
24 module_param(debug, int, 0);
25 MODULE_PARM_DESC (debug, "toggle debug flag");
27 #define HYPERCALL_DEBUG 1
28 #if HYPERCALL_DEBUG
29 # define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
30 # define assert(expr) \
31 if(unlikely(!(expr))) { \
32 printk(KERN_ERR "Assertion failed! %s,%s,%s,line=%d\n", \
33 #expr,__FILE__,__FUNCTION__,__LINE__); \
35 #else
36 # define DPRINTK(fmt, args...)
37 # define assert(expr) do {} while (0)
38 #endif
40 static struct pci_device_id hypercall_pci_tbl[] = {
41 {PCI_VENDOR_ID_HYPERCALL, PCI_DEVICE_ID_HYPERCALL, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
42 {0,}
44 MODULE_DEVICE_TABLE (pci, hypercall_pci_tbl);
46 struct hypercall_dev {
47 struct pci_dev *pci_dev;
48 u32 state;
49 spinlock_t lock;
50 u8 name[128];
51 u16 irq;
52 u32 regs_len;
53 void __iomem *mmio_addr;
54 unsigned long base_addr; /* device I/O address */
59 static void hypercall_cleanup_dev(struct hypercall_dev *dev);
62 static int __devinit hypercall_init_board(struct pci_dev *pdev,
63 struct hypercall_dev **dev_out)
65 unsigned long *ioaddr;
66 struct hypercall_dev *dev;
67 int rc;
68 u32 disable_dev_on_err = 0;
69 unsigned long pio_start, pio_end, pio_flags, pio_len;
70 unsigned long mmio_start, mmio_end, mmio_flags, mmio_len;
72 assert(pdev != NULL);
74 *dev_out = NULL;
76 dev = kzalloc(sizeof(*dev), GFP_KERNEL);
77 if (dev == NULL) {
78 printk (KERN_ERR "%s: Unable to alloc hypercall device\n", pci_name(pdev));
79 return -ENOMEM;
81 dev->pci_dev = pdev;
82 rc = pci_enable_device(pdev);
83 if (rc)
84 goto err_out;
85 disable_dev_on_err = 1;
87 pio_start = pci_resource_start (pdev, 0);
88 pio_end = pci_resource_end (pdev, 0);
89 pio_flags = pci_resource_flags (pdev, 0);
90 pio_len = pci_resource_len (pdev, 0);
92 mmio_start = pci_resource_start (pdev, 1);
93 mmio_end = pci_resource_end (pdev, 1);
94 mmio_flags = pci_resource_flags (pdev, 1);
95 mmio_len = pci_resource_len (pdev, 1);
97 DPRINTK("PIO region size == 0x%02lX\n", pio_len);
98 DPRINTK("MMIO region size == 0x%02lX\n", mmio_len);
100 rc = pci_request_regions (pdev, "hypercall");
101 if (rc)
102 goto err_out;
104 pci_set_master (pdev);
106 #define USE_IO_OPS 1
107 #ifdef USE_IO_OPS
108 ioaddr = pci_iomap(pdev, 0, 0);
109 if (!ioaddr) {
110 printk(KERN_ERR "%s: cannot map PIO, aborting\n", pci_name(pdev));
111 rc = -EIO;
112 goto err_out;
114 dev->base_addr = (unsigned long)ioaddr;
115 dev->regs_len = pio_len;
116 #else
117 ioaddr = pci_iomap(pdev, 1, 0);
118 if (ioaddr == NULL) {
119 printk(KERN_ERR "%s: cannot remap MMIO, aborting\n", pci_name(pdev));
120 rc = -EIO;
121 goto err_out;
123 dev->base_addr = ioaddr;
124 dev->regs_len = mmio_len;
125 #endif /* USE_IO_OPS */
127 *dev_out = dev;
128 return 0;
130 err_out:
131 hypercall_cleanup_dev(dev);
132 if (disable_dev_on_err)
133 pci_disable_device(pdev);
134 return rc;
137 static int __devinit hypercall_init_one(struct pci_dev *pdev,
138 const struct pci_device_id *ent)
140 struct hypercall_dev *dev;
141 u8 pci_rev;
143 assert(pdev != NULL);
144 assert(ent != NULL);
146 pci_read_config_byte(pdev, PCI_REVISION_ID, &pci_rev);
148 if (pdev->vendor == PCI_VENDOR_ID_HYPERCALL &&
149 pdev->device == PCI_DEVICE_ID_HYPERCALL) {
150 printk(KERN_INFO "pci dev %s (id %04x:%04x rev %02x) is a guest hypercall device\n",
151 pci_name(pdev), pdev->vendor, pdev->device, pci_rev);
154 if (hypercall_init_board(pdev, &dev) != 0)
155 return -1;
157 assert(dev != NULL);
159 dev->irq = pdev->irq;
161 spin_lock_init(&dev->lock);
162 pci_set_drvdata(pdev, dev);
164 printk (KERN_INFO "%s: 0x%lx, IRQ %d\n", dev->name, dev->base_addr, dev->irq);
165 return 0;
168 static void __devexit hypercall_remove_one(struct pci_dev *pdev)
170 struct hypercall_dev *dev = pci_get_drvdata(pdev);
172 assert(dev != NULL);
174 hypercall_cleanup_dev(dev);
175 pci_disable_device(pdev);
178 #ifdef CONFIG_PM
180 static int hypercall_suspend(struct pci_dev *pdev, pm_message_t state)
182 pci_save_state(pdev);
183 pci_set_power_state(pdev, PCI_D3hot);
184 DPRINTK("Power mgmt suspend, set power state to PCI_D3hot\n");
186 return 0;
189 static int hypercall_resume(struct pci_dev *pdev)
191 pci_restore_state(pdev);
192 pci_set_power_state(pdev, PCI_D0);
193 DPRINTK("Power mgmt resume, set power state to PCI_D0\n");
195 return 0;
198 #endif /* CONFIG_PM */
200 static void hypercall_cleanup_dev(struct hypercall_dev *dev)
202 DPRINTK("cleaning up\n");
203 pci_release_regions(dev->pci_dev);
204 pci_iounmap(dev->pci_dev, (void*)dev->base_addr);
205 kfree(dev);
208 static struct pci_driver hypercall_pci_driver = {
209 .name = HYPERCALL_DRIVER_NAME,
210 .id_table = hypercall_pci_tbl,
211 .probe = hypercall_init_one,
212 .remove = __devexit_p(hypercall_remove_one),
213 #ifdef CONFIG_PM
214 .suspend = hypercall_suspend,
215 .resume = hypercall_resume,
216 #endif /* CONFIG_PM */
219 static int __init hypercall_init_module(void)
221 printk (KERN_INFO HYPERCALL_DRIVER_NAME "\n");
222 return pci_module_init(&hypercall_pci_driver);
225 static void __exit hypercall_cleanup_module(void)
227 pci_unregister_driver(&hypercall_pci_driver);
230 module_init(hypercall_init_module);
231 module_exit(hypercall_cleanup_module);