]> git.karo-electronics.de Git - mv-sheeva.git/blob - drivers/xen/xen-pciback/conf_space_capability_msi.c
xen/pciback: xen pci backend driver.
[mv-sheeva.git] / drivers / xen / xen-pciback / conf_space_capability_msi.c
1 /*
2  * PCI Backend -- Configuration overlay for MSI capability
3  */
4 #include <linux/pci.h>
5 #include <linux/slab.h>
6 #include "conf_space.h"
7 #include "conf_space_capability.h"
8 #include <xen/interface/io/pciif.h>
9 #include <xen/events.h>
10 #include "pciback.h"
11
12 int pciback_enable_msi(struct pciback_device *pdev,
13                 struct pci_dev *dev, struct xen_pci_op *op)
14 {
15         int otherend = pdev->xdev->otherend_id;
16         int status;
17
18         status = pci_enable_msi(dev);
19
20         if (status) {
21                 printk(KERN_ERR "error enable msi for guest %x status %x\n",
22                         otherend, status);
23                 op->value = 0;
24                 return XEN_PCI_ERR_op_failed;
25         }
26
27         /* The value the guest needs is actually the IDT vector, not the
28          * the local domain's IRQ number. */
29
30         op->value = dev->irq ? xen_pirq_from_irq(dev->irq) : 0;
31         return 0;
32 }
33
34 int pciback_disable_msi(struct pciback_device *pdev,
35                 struct pci_dev *dev, struct xen_pci_op *op)
36 {
37         pci_disable_msi(dev);
38
39         op->value = dev->irq ? xen_pirq_from_irq(dev->irq) : 0;
40         return 0;
41 }
42
43 int pciback_enable_msix(struct pciback_device *pdev,
44                 struct pci_dev *dev, struct xen_pci_op *op)
45 {
46         int i, result;
47         struct msix_entry *entries;
48
49         if (op->value > SH_INFO_MAX_VEC)
50                 return -EINVAL;
51
52         entries = kmalloc(op->value * sizeof(*entries), GFP_KERNEL);
53         if (entries == NULL)
54                 return -ENOMEM;
55
56         for (i = 0; i < op->value; i++) {
57                 entries[i].entry = op->msix_entries[i].entry;
58                 entries[i].vector = op->msix_entries[i].vector;
59         }
60
61         result = pci_enable_msix(dev, entries, op->value);
62
63         if (result == 0) {
64                 for (i = 0; i < op->value; i++) {
65                         op->msix_entries[i].entry = entries[i].entry;
66                         if (entries[i].vector)
67                                 op->msix_entries[i].vector =
68                                         xen_pirq_from_irq(entries[i].vector);
69                 }
70         } else {
71                 printk(KERN_WARNING "pciback: %s: failed to enable MSI-X: err %d!\n",
72                         pci_name(dev), result);
73         }
74         kfree(entries);
75
76         op->value = result;
77
78         return result;
79 }
80
81 int pciback_disable_msix(struct pciback_device *pdev,
82                 struct pci_dev *dev, struct xen_pci_op *op)
83 {
84
85         pci_disable_msix(dev);
86
87         /*
88          * SR-IOV devices (which don't have any legacy IRQ) have
89          * an undefined IRQ value of zero.
90          */
91         op->value = dev->irq ? xen_pirq_from_irq(dev->irq) : 0;
92         return 0;
93 }
94