Commit | Line | Data |
---|---|---|
30edc14b KRW |
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 | { | |
0513fe9e | 15 | struct pciback_dev_data *dev_data; |
30edc14b KRW |
16 | int otherend = pdev->xdev->otherend_id; |
17 | int status; | |
18 | ||
19 | status = pci_enable_msi(dev); | |
20 | ||
21 | if (status) { | |
22 | printk(KERN_ERR "error enable msi for guest %x status %x\n", | |
23 | otherend, status); | |
24 | op->value = 0; | |
25 | return XEN_PCI_ERR_op_failed; | |
26 | } | |
27 | ||
28 | /* The value the guest needs is actually the IDT vector, not the | |
29 | * the local domain's IRQ number. */ | |
30 | ||
31 | op->value = dev->irq ? xen_pirq_from_irq(dev->irq) : 0; | |
0513fe9e KRW |
32 | dev_data = pci_get_drvdata(dev); |
33 | if (dev_data) | |
34 | dev_data->ack_intr = 0; | |
30edc14b KRW |
35 | return 0; |
36 | } | |
37 | ||
38 | int pciback_disable_msi(struct pciback_device *pdev, | |
39 | struct pci_dev *dev, struct xen_pci_op *op) | |
40 | { | |
0513fe9e | 41 | struct pciback_dev_data *dev_data; |
30edc14b KRW |
42 | pci_disable_msi(dev); |
43 | ||
44 | op->value = dev->irq ? xen_pirq_from_irq(dev->irq) : 0; | |
0513fe9e KRW |
45 | dev_data = pci_get_drvdata(dev); |
46 | if (dev_data) | |
47 | dev_data->ack_intr = 1; | |
30edc14b KRW |
48 | return 0; |
49 | } | |
50 | ||
51 | int pciback_enable_msix(struct pciback_device *pdev, | |
52 | struct pci_dev *dev, struct xen_pci_op *op) | |
53 | { | |
0513fe9e | 54 | struct pciback_dev_data *dev_data; |
30edc14b KRW |
55 | int i, result; |
56 | struct msix_entry *entries; | |
57 | ||
58 | if (op->value > SH_INFO_MAX_VEC) | |
59 | return -EINVAL; | |
60 | ||
61 | entries = kmalloc(op->value * sizeof(*entries), GFP_KERNEL); | |
62 | if (entries == NULL) | |
63 | return -ENOMEM; | |
64 | ||
65 | for (i = 0; i < op->value; i++) { | |
66 | entries[i].entry = op->msix_entries[i].entry; | |
67 | entries[i].vector = op->msix_entries[i].vector; | |
68 | } | |
69 | ||
70 | result = pci_enable_msix(dev, entries, op->value); | |
71 | ||
72 | if (result == 0) { | |
73 | for (i = 0; i < op->value; i++) { | |
74 | op->msix_entries[i].entry = entries[i].entry; | |
75 | if (entries[i].vector) | |
76 | op->msix_entries[i].vector = | |
77 | xen_pirq_from_irq(entries[i].vector); | |
78 | } | |
79 | } else { | |
80 | printk(KERN_WARNING "pciback: %s: failed to enable MSI-X: err %d!\n", | |
81 | pci_name(dev), result); | |
82 | } | |
83 | kfree(entries); | |
84 | ||
85 | op->value = result; | |
0513fe9e KRW |
86 | dev_data = pci_get_drvdata(dev); |
87 | if (dev_data) | |
88 | dev_data->ack_intr = 0; | |
30edc14b KRW |
89 | |
90 | return result; | |
91 | } | |
92 | ||
93 | int pciback_disable_msix(struct pciback_device *pdev, | |
94 | struct pci_dev *dev, struct xen_pci_op *op) | |
95 | { | |
0513fe9e | 96 | struct pciback_dev_data *dev_data; |
30edc14b KRW |
97 | |
98 | pci_disable_msix(dev); | |
99 | ||
100 | /* | |
101 | * SR-IOV devices (which don't have any legacy IRQ) have | |
102 | * an undefined IRQ value of zero. | |
103 | */ | |
104 | op->value = dev->irq ? xen_pirq_from_irq(dev->irq) : 0; | |
0513fe9e KRW |
105 | dev_data = pci_get_drvdata(dev); |
106 | if (dev_data) | |
107 | dev_data->ack_intr = 1; | |
108 | ||
30edc14b KRW |
109 | return 0; |
110 | } | |
111 |