~ubuntu-branches/ubuntu/hardy/kvm/hardy-backports

« back to all changes in this revision

Viewing changes to drivers/hypercall.c

  • Committer: Bazaar Package Importer
  • Author(s): Soren Hansen
  • Date: 2007-12-10 13:43:03 UTC
  • mfrom: (1.1.13 upstream)
  • Revision ID: james.westby@ubuntu.com-20071210134303-rw38y458ilx76vmv
Tags: 1:55+dfsg-1ubuntu1
* Merge with Debian. Remaining changes:
  - debian/control:
    - Demote kvm-source to Suggests
    - Mention kvm-source is unnecessary
    - Modify Maintainer value to match the DebianMaintainerField
      specification.
    - Depend on recent bochsbios-qemu.
    - Moved Vcs-* to XS-Original-Vcs-*.
    - Don't recommend linux-image-2.6 since Ubuntu is Linux 2.6 only anyway.
    - Rename suggestions of linux-{headers,source} to Ubuntu's naming scheme.
    - Add pkg-config to Build-Depends (fixes warning during build)
  - Add 08_default_tdf.patch to make -tdf the default.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
 
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 <linux/interrupt.h>
10
 
#include <asm/io.h>
11
 
#include <asm/uaccess.h>
12
 
#include <asm/irq.h>
13
 
 
14
 
#define HYPERCALL_DRIVER_NAME "Qumranet_hypercall_driver"
15
 
#define HYPERCALL_DRIVER_VERSION "1"
16
 
#define PCI_VENDOR_ID_HYPERCALL 0x5002
17
 
#define PCI_DEVICE_ID_HYPERCALL 0x2258
18
 
 
19
 
MODULE_AUTHOR ("Dor Laor <dor.laor@qumranet.com>");
20
 
MODULE_DESCRIPTION (HYPERCALL_DRIVER_NAME);
21
 
MODULE_LICENSE("GPL");
22
 
MODULE_VERSION(HYPERCALL_DRIVER_VERSION);
23
 
 
24
 
static int debug = 0;
25
 
module_param(debug, int, 0);
26
 
MODULE_PARM_DESC (debug, "toggle debug flag");
27
 
 
28
 
#define HYPERCALL_DEBUG 1
29
 
#if HYPERCALL_DEBUG
30
 
#  define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
31
 
#  define assert(expr) \
32
 
        if(unlikely(!(expr))) {                                 \
33
 
        printk(KERN_ERR "Assertion failed! %s,%s,%s,line=%d\n", \
34
 
        #expr,__FILE__,__FUNCTION__,__LINE__);                  \
35
 
        }
36
 
#else
37
 
#  define DPRINTK(fmt, args...)
38
 
#  define assert(expr) do {} while (0)
39
 
#endif
40
 
 
41
 
static struct pci_device_id hypercall_pci_tbl[] = {
42
 
        {PCI_VENDOR_ID_HYPERCALL, PCI_DEVICE_ID_HYPERCALL, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
43
 
        {0,}
44
 
};
45
 
MODULE_DEVICE_TABLE (pci, hypercall_pci_tbl);
46
 
 
47
 
 
48
 
 
49
 
/****** Hypercall device definitions ***************/
50
 
#include <qemu/hw/hypercall.h>
51
 
 
52
 
/* read PIO/MMIO register */
53
 
#define HIO_READ8(reg, ioaddr)          ioread8(ioaddr + (reg))
54
 
#define HIO_READ16(reg, ioaddr)         ioread16(ioaddr + (reg))
55
 
#define HIO_READ32(reg, ioaddr)         ioread32(ioaddr + (reg))
56
 
 
57
 
/* write PIO/MMIO register */
58
 
#define HIO_WRITE8(reg, val8, ioaddr)   iowrite8((val8), ioaddr + (reg))
59
 
#define HIO_WRITE16(reg, val16, ioaddr) iowrite16((val16), ioaddr + (reg))
60
 
#define HIO_WRITE32(reg, val32, ioaddr) iowrite32((val32), ioaddr + (reg))
61
 
 
62
 
 
63
 
struct hypercall_dev {
64
 
        struct pci_dev  *pci_dev;
65
 
        struct kobject  kobject;
66
 
        u32             state;
67
 
        spinlock_t      lock;
68
 
        u8              name[128];
69
 
        u16             irq;
70
 
        u32             regs_len;
71
 
        void __iomem    *io_addr;
72
 
        unsigned long   base_addr;      /* device I/O address   */
73
 
        unsigned long   cmd;
74
 
};
75
 
 
76
 
 
77
 
static int hypercall_close(struct hypercall_dev* dev);
78
 
static int hypercall_open(struct hypercall_dev *dev);
79
 
static void hypercall_cleanup_dev(struct hypercall_dev *dev);
80
 
static irqreturn_t hypercall_interrupt(int irq, void *dev_instance,
81
 
                                       struct pt_regs *regs);
82
 
 
83
 
static void __exit hypercall_sysfs_remove(struct hypercall_dev *dev);
84
 
static int hypercall_sysfs_add(struct hypercall_dev *dev);
85
 
 
86
 
 
87
 
static int __devinit hypercall_init_board(struct pci_dev *pdev,
88
 
                                          struct hypercall_dev **dev_out)
89
 
{
90
 
        unsigned long ioaddr;
91
 
        struct hypercall_dev *dev;
92
 
        int rc;
93
 
        u32 disable_dev_on_err = 0;
94
 
        unsigned long pio_start, pio_end, pio_flags, pio_len;
95
 
        unsigned long mmio_start, mmio_end, mmio_flags, mmio_len;
96
 
 
97
 
        assert(pdev != NULL);
98
 
 
99
 
        *dev_out = NULL;
100
 
 
101
 
        dev = kzalloc(sizeof(*dev), GFP_KERNEL);
102
 
        if (dev == NULL) {
103
 
                printk (KERN_ERR "%s: Unable to alloc hypercall device\n", pci_name(pdev));
104
 
                return -ENOMEM;
105
 
        }
106
 
        dev->pci_dev = pdev;
107
 
        rc = pci_enable_device(pdev);
108
 
        if (rc)
109
 
                goto err_out;
110
 
        disable_dev_on_err = 1;
111
 
 
112
 
        pio_start = pci_resource_start (pdev, 0);
113
 
        pio_end = pci_resource_end (pdev, 0);
114
 
        pio_flags = pci_resource_flags (pdev, 0);
115
 
        pio_len = pci_resource_len (pdev, 0);
116
 
 
117
 
        mmio_start = pci_resource_start (pdev, 1);
118
 
        mmio_end = pci_resource_end (pdev, 1);
119
 
        mmio_flags = pci_resource_flags (pdev, 1);
120
 
        mmio_len = pci_resource_len (pdev, 1);
121
 
 
122
 
        DPRINTK("PIO region size == 0x%02lX\n", pio_len);
123
 
        DPRINTK("MMIO region size == 0x%02lX\n", mmio_len);
124
 
 
125
 
        rc = pci_request_regions (pdev, "hypercall");
126
 
        if (rc)
127
 
                goto err_out;
128
 
 
129
 
#define USE_IO_OPS 1
130
 
#ifdef USE_IO_OPS
131
 
        ioaddr = (unsigned long)pci_iomap(pdev, 0, 0);
132
 
        //ioaddr = ioport_map(pio_start, pio_len);
133
 
        if (!ioaddr) {
134
 
                printk(KERN_ERR "%s: cannot map PIO, aborting\n", pci_name(pdev));
135
 
                rc = -EIO;
136
 
                goto err_out;
137
 
        }
138
 
        dev->base_addr = (unsigned long)pio_start;
139
 
        dev->io_addr = (void*)ioaddr;
140
 
        dev->regs_len = pio_len;
141
 
#else
142
 
        ioaddr = pci_iomap(pdev, 1, 0);
143
 
        if (ioaddr == NULL) {
144
 
                printk(KERN_ERR "%s: cannot remap MMIO, aborting\n", pci_name(pdev));
145
 
                rc = -EIO;
146
 
                goto err_out;
147
 
        }
148
 
        dev->base_addr = ioaddr;
149
 
        dev->io_addr = (void*)ioaddr;
150
 
        dev->regs_len = mmio_len;
151
 
#endif /* USE_IO_OPS */
152
 
 
153
 
        *dev_out = dev;
154
 
        return 0;
155
 
 
156
 
err_out:
157
 
        hypercall_cleanup_dev(dev);
158
 
        if (disable_dev_on_err)
159
 
                pci_disable_device(pdev);
160
 
        return rc;
161
 
}
162
 
 
163
 
static int __devinit hypercall_init_one(struct pci_dev *pdev,
164
 
                                        const struct pci_device_id *ent)
165
 
{
166
 
        struct hypercall_dev *dev;
167
 
        u8 pci_rev;
168
 
 
169
 
        assert(pdev != NULL);
170
 
        assert(ent != NULL);
171
 
 
172
 
        pci_read_config_byte(pdev, PCI_REVISION_ID, &pci_rev);
173
 
 
174
 
        if (pdev->vendor == PCI_VENDOR_ID_HYPERCALL &&
175
 
            pdev->device == PCI_DEVICE_ID_HYPERCALL) {
176
 
                printk(KERN_INFO "pci dev %s (id %04x:%04x rev %02x) is a guest hypercall device\n",
177
 
                       pci_name(pdev), pdev->vendor, pdev->device, pci_rev);
178
 
        }
179
 
 
180
 
        if (hypercall_init_board(pdev, &dev) != 0)
181
 
                return -1;
182
 
        
183
 
        assert(dev != NULL);
184
 
                    
185
 
        dev->irq = pdev->irq;
186
 
 
187
 
        spin_lock_init(&dev->lock);
188
 
        pci_set_drvdata(pdev, dev);
189
 
 
190
 
        printk (KERN_INFO "name=%s: base_addr=0x%lx, io_addr=0x%lx, IRQ=%d\n",
191
 
                dev->name, dev->base_addr, (unsigned long)dev->io_addr, dev->irq);
192
 
        hypercall_open(dev);
193
 
 
194
 
        if (hypercall_sysfs_add(dev) != 0)
195
 
                return -1;
196
 
 
197
 
        return 0;
198
 
}
199
 
 
200
 
static void __devexit hypercall_remove_one(struct pci_dev *pdev)
201
 
{
202
 
        struct hypercall_dev *dev = pci_get_drvdata(pdev);
203
 
 
204
 
        assert(dev != NULL);
205
 
 
206
 
        hypercall_close(dev);
207
 
        hypercall_sysfs_remove(dev);
208
 
        hypercall_cleanup_dev(dev);
209
 
        pci_disable_device(pdev);
210
 
}
211
 
 
212
 
static int hypercall_tx(struct hypercall_dev *dev, unsigned char *buf, size_t len)
213
 
{
214
 
        void __iomem *ioaddr = (void __iomem*)dev->io_addr;
215
 
        int i;
216
 
 
217
 
        if (len > HP_MEM_SIZE)
218
 
                return -EINVAL;
219
 
 
220
 
        spin_lock(&dev->lock);
221
 
        HIO_WRITE8(HP_TXSIZE, len, ioaddr);
222
 
        for (i=0; i< len; i++)
223
 
                HIO_WRITE8(HP_TXBUFF, buf[i], ioaddr);
224
 
        spin_unlock(&dev->lock);
225
 
 
226
 
        return 0;
227
 
}
228
 
 
229
 
/* 
230
 
 * The interrupt handler does all of the rx  work and cleans up
231
 
 * after the tx
232
 
 */
233
 
static irqreturn_t hypercall_interrupt(int irq, void *dev_instance,
234
 
                                       struct pt_regs *regs)
235
 
{
236
 
        struct hypercall_dev *dev = (struct hypercall_dev *)dev_instance;
237
 
        void __iomem *ioaddr = (void __iomem*)dev->io_addr;
238
 
        u32 status;
239
 
        int irq_handled = IRQ_NONE;
240
 
        int rx_buf_size;
241
 
        int i;
242
 
        u8 buffer[HP_MEM_SIZE];
243
 
        u8 *pbuf;
244
 
 
245
 
        DPRINTK("base addr is 0x%lx, io_addr=0x%lx\n", dev->base_addr, (long)dev->io_addr);
246
 
        
247
 
        spin_lock(&dev->lock);
248
 
        status = HIO_READ8(HSR_REGISTER, ioaddr);
249
 
        DPRINTK("irq status is 0x%x\n", status);
250
 
 
251
 
        /* shared irq? */
252
 
        if (unlikely((status & HSR_VDR) == 0)) {
253
 
                DPRINTK("not handeling irq, not ours\n");
254
 
                goto out;
255
 
        }
256
 
        
257
 
        /* Disable device interrupts */
258
 
        HIO_WRITE8(HCR_REGISTER, HCR_DI, ioaddr);
259
 
        DPRINTK("disable device interrupts\n");
260
 
 
261
 
        rx_buf_size = HIO_READ8(HP_RXSIZE, ioaddr);
262
 
        DPRINTK("Rx buffer size is %d\n", rx_buf_size);
263
 
 
264
 
        if (rx_buf_size > HP_MEM_SIZE)
265
 
                rx_buf_size = HP_MEM_SIZE;
266
 
 
267
 
        for (i=0, pbuf=buffer; i<rx_buf_size; i++, pbuf++) {
268
 
                *pbuf = HIO_READ8(HP_RXBUFF, ioaddr + i);
269
 
                DPRINTK("Read 0x%x as dword %d\n", *pbuf, i);
270
 
        }
271
 
        *pbuf = '\0';
272
 
        DPRINTK("Read buffer %s", (char*)buffer);
273
 
 
274
 
        HIO_WRITE8(HCR_REGISTER, HCR_EI, ioaddr);
275
 
        DPRINTK("Enable interrupt\n");
276
 
        irq_handled = IRQ_HANDLED;
277
 
 out:
278
 
        spin_unlock(&dev->lock);
279
 
 
280
 
 
281
 
        hypercall_tx(dev, "hello host", sizeof("hello host"));
282
 
        return irq_handled;
283
 
}
284
 
 
285
 
 
286
 
static int hypercall_open(struct hypercall_dev *dev)
287
 
{
288
 
        int rc;
289
 
 
290
 
        rc = request_irq(dev->irq, &hypercall_interrupt,
291
 
                         SA_SHIRQ, dev->name, dev);
292
 
        if (rc) {
293
 
                printk(KERN_ERR "%s failed to request an irq\n", __FUNCTION__);
294
 
                return rc;
295
 
        }
296
 
 
297
 
        //hypercall_thread_start(dev);
298
 
 
299
 
        return 0;
300
 
}
301
 
 
302
 
static int hypercall_close(struct hypercall_dev* dev)
303
 
{
304
 
        //hypercall_thread_stop(dev);
305
 
        synchronize_irq(dev->irq);
306
 
        free_irq(dev->irq, dev);
307
 
 
308
 
        return 0;
309
 
}
310
 
 
311
 
#ifdef CONFIG_PM
312
 
 
313
 
static int hypercall_suspend(struct pci_dev *pdev, pm_message_t state)
314
 
{
315
 
        pci_save_state(pdev);
316
 
        pci_set_power_state(pdev, PCI_D3hot);
317
 
        DPRINTK("Power mgmt suspend, set power state to PCI_D3hot\n");
318
 
 
319
 
        return 0;
320
 
}
321
 
 
322
 
static int hypercall_resume(struct pci_dev *pdev)
323
 
{
324
 
        pci_restore_state(pdev);
325
 
        pci_set_power_state(pdev, PCI_D0);
326
 
        DPRINTK("Power mgmt resume, set power state to PCI_D0\n");
327
 
 
328
 
        return 0;
329
 
}
330
 
 
331
 
#endif /* CONFIG_PM */
332
 
 
333
 
static void hypercall_cleanup_dev(struct hypercall_dev *dev)
334
 
{
335
 
        DPRINTK("cleaning up\n");
336
 
        pci_release_regions(dev->pci_dev);
337
 
        pci_iounmap(dev->pci_dev, (void*)dev->io_addr);
338
 
        pci_set_drvdata (dev->pci_dev, NULL);
339
 
        kfree(dev);
340
 
}
341
 
 
342
 
static struct pci_driver hypercall_pci_driver = {
343
 
        .name           = HYPERCALL_DRIVER_NAME,
344
 
        .id_table       = hypercall_pci_tbl,
345
 
        .probe          = hypercall_init_one,
346
 
        .remove         = __devexit_p(hypercall_remove_one),
347
 
#ifdef CONFIG_PM
348
 
        .suspend        = hypercall_suspend,
349
 
        .resume         = hypercall_resume,
350
 
#endif /* CONFIG_PM */
351
 
};
352
 
 
353
 
static int __init hypercall_init_module(void)
354
 
{
355
 
        printk (KERN_INFO HYPERCALL_DRIVER_NAME "\n");
356
 
        return pci_module_init(&hypercall_pci_driver);
357
 
}
358
 
 
359
 
static void __exit hypercall_cleanup_module(void)
360
 
{
361
 
        pci_unregister_driver(&hypercall_pci_driver);
362
 
}
363
 
 
364
 
/*
365
 
 * sysfs support
366
 
 */
367
 
 
368
 
struct hypercall_attribute {
369
 
        struct attribute attr;
370
 
        ssize_t (*show)(struct hypercall_dev*, char *buf);
371
 
        ssize_t (*store)(struct hypercall_dev*, unsigned long val);
372
 
};
373
 
 
374
 
static ssize_t hypercall_attribute_show(struct kobject *kobj,
375
 
                struct attribute *attr, char *buf)
376
 
{
377
 
        struct hypercall_attribute *hypercall_attr;
378
 
        struct hypercall_dev *hdev;
379
 
 
380
 
        hypercall_attr = container_of(attr, struct hypercall_attribute, attr);
381
 
        hdev = container_of(kobj, struct hypercall_dev, kobject);
382
 
 
383
 
        if (!hypercall_attr->show)
384
 
                return -EIO;
385
 
 
386
 
        return hypercall_attr->show(hdev, buf);
387
 
}
388
 
 
389
 
static ssize_t hypercall_attribute_store(struct kobject *kobj,
390
 
                struct attribute *attr, const char *buf, size_t count)
391
 
{
392
 
        struct hypercall_attribute *hypercall_attr;
393
 
        struct hypercall_dev *hdev;
394
 
        char *endp;
395
 
        unsigned long val;
396
 
        int rc;
397
 
 
398
 
        val = simple_strtoul(buf, &endp, 0);
399
 
 
400
 
        hypercall_attr = container_of(attr, struct hypercall_attribute, attr);
401
 
        hdev = container_of(kobj, struct hypercall_dev, kobject);
402
 
 
403
 
        if (!hypercall_attr->store)
404
 
                return -EIO;
405
 
 
406
 
        rc = hypercall_attr->store(hdev, val);
407
 
        if (!rc)
408
 
                rc = count;
409
 
        return rc;
410
 
}
411
 
 
412
 
#define MAKE_HYPERCALL_R_ATTR(_name)                                    \
413
 
static ssize_t _name##_show(struct hypercall_dev *hdev, char *buf)      \
414
 
{                                                                       \
415
 
        return sprintf(buf, "%lu\n", (unsigned long)hdev->_name);       \
416
 
}                                                                       \
417
 
struct hypercall_attribute hypercall_attr_##_name = __ATTR_RO(_name)
418
 
 
419
 
#define MAKE_HYPERCALL_WR_ATTR(_name)                                   \
420
 
static int _name##_store(struct hypercall_dev *hdev, unsigned long val) \
421
 
{                                                                       \
422
 
        hdev->_name = (typeof(hdev->_name))val;                         \
423
 
        return 0;                                                       \
424
 
}                                                                       \
425
 
static ssize_t _name##_show(struct hypercall_dev *hdev, char *buf)      \
426
 
{                                                                       \
427
 
        return sprintf(buf, "%lu\n", (unsigned long)hdev->_name);       \
428
 
}                                                                       \
429
 
struct hypercall_attribute hypercall_attr_##_name =                     \
430
 
        __ATTR(_name,S_IRUGO|S_IWUGO,_name##_show,_name##_store)
431
 
 
432
 
MAKE_HYPERCALL_R_ATTR(base_addr);
433
 
MAKE_HYPERCALL_R_ATTR(irq);
434
 
MAKE_HYPERCALL_WR_ATTR(cmd);
435
 
 
436
 
#define GET_HYPERCALL_ATTR(_name)       (&hypercall_attr_##_name.attr)
437
 
 
438
 
static struct attribute *hypercall_default_attrs[] = {
439
 
        GET_HYPERCALL_ATTR(base_addr),
440
 
        GET_HYPERCALL_ATTR(irq),
441
 
        GET_HYPERCALL_ATTR(cmd),
442
 
        NULL
443
 
};
444
 
 
445
 
static struct sysfs_ops hypercall_sysfs_ops = {
446
 
        .show = hypercall_attribute_show,
447
 
        .store = hypercall_attribute_store,
448
 
};
449
 
 
450
 
static void hypercall_sysfs_release(struct kobject *kobj)
451
 
{
452
 
        DPRINTK(" called for obj name %s\n", kobj->name);
453
 
}
454
 
 
455
 
static struct kobj_type hypercall_ktype = {
456
 
        .release        = hypercall_sysfs_release,
457
 
        .sysfs_ops      = &hypercall_sysfs_ops,
458
 
        .default_attrs  = hypercall_default_attrs
459
 
};
460
 
 
461
 
 
462
 
static int hypercall_sysfs_add(struct hypercall_dev *dev)
463
 
{
464
 
        int rc;
465
 
 
466
 
        kobject_init(&dev->kobject);
467
 
        dev->kobject.ktype = &hypercall_ktype;
468
 
        rc = kobject_set_name(&dev->kobject, "%s", HYPERCALL_DRIVER_NAME);
469
 
        if (rc != 0) {
470
 
                printk("%s: kobject_set_name failed, err=%d\n", __FUNCTION__, rc);
471
 
                return rc;
472
 
        }
473
 
 
474
 
        rc = kobject_add(&dev->kobject);
475
 
        if (rc != 0) {
476
 
                printk("%s: kobject_add failed, err=%d\n", __FUNCTION__, rc);
477
 
                return rc;
478
 
        }
479
 
 
480
 
        rc = sysfs_create_link(&dev->pci_dev->dev.kobj, &dev->kobject,
481
 
                               HYPERCALL_DRIVER_NAME);
482
 
        if (rc != 0) {
483
 
                printk("%s: sysfs_create_link failed, err=%d\n", __FUNCTION__, rc);
484
 
                kobject_del(&dev->kobject);
485
 
        }
486
 
        
487
 
        return rc;
488
 
}
489
 
 
490
 
static void hypercall_sysfs_remove(struct hypercall_dev *dev)
491
 
{
492
 
        sysfs_remove_link(&dev->pci_dev->dev.kobj, HYPERCALL_DRIVER_NAME);
493
 
        kobject_del(&dev->kobject);
494
 
}
495
 
 
496
 
module_init(hypercall_init_module);
497
 
module_exit(hypercall_cleanup_module);