aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIan Campbell <ian.campbell@citrix.com>2011-02-18 11:43:32 -0500
committerKonrad Rzeszutek Wilk <konrad.wilk@oracle.com>2011-03-10 14:44:40 -0500
commitbf480d952bcf25e8ff7e95d2a23964107513ac51 (patch)
treeb2d1a75e39bfdf82021ccdefb5f9613a17087040
parent5cad61a6ba6f4956a218ffbb64cafcc1daefaca0 (diff)
xen: events: separate MSI PIRQ allocation from PIRQ binding to IRQ
Split the binding aspect of xen_allocate_pirq_msi out into a new xen_bind_pirq_to_irq function. In xen_hvm_setup_msi_irq when allocating a pirq write the MSI message to signal the PIRQ as soon as the pirq is obtained. There is no way to free the pirq back so if the subsequent binding to an IRQ fails we want to ensure that we will reuse the PIRQ next time rather than leak it. Signed-off-by: Ian Campbell <ian.campbell@citrix.com> Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
-rw-r--r--arch/x86/pci/xen.c68
-rw-r--r--drivers/xen/events.c30
-rw-r--r--include/xen/events.h4
3 files changed, 43 insertions, 59 deletions
diff --git a/arch/x86/pci/xen.c b/arch/x86/pci/xen.c
index 0d5087eeced8..93e42152d8d0 100644
--- a/arch/x86/pci/xen.c
+++ b/arch/x86/pci/xen.c
@@ -86,7 +86,7 @@ static void xen_msi_compose_msg(struct pci_dev *pdev, unsigned int pirq,
86 86
87static int xen_hvm_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) 87static int xen_hvm_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
88{ 88{
89 int irq, pirq, ret = 0; 89 int irq, pirq;
90 struct msi_desc *msidesc; 90 struct msi_desc *msidesc;
91 struct msi_msg msg; 91 struct msi_msg msg;
92 92
@@ -94,39 +94,32 @@ static int xen_hvm_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
94 __read_msi_msg(msidesc, &msg); 94 __read_msi_msg(msidesc, &msg);
95 pirq = MSI_ADDR_EXT_DEST_ID(msg.address_hi) | 95 pirq = MSI_ADDR_EXT_DEST_ID(msg.address_hi) |
96 ((msg.address_lo >> MSI_ADDR_DEST_ID_SHIFT) & 0xff); 96 ((msg.address_lo >> MSI_ADDR_DEST_ID_SHIFT) & 0xff);
97 if (xen_irq_from_pirq(pirq) >= 0 && msg.data == XEN_PIRQ_MSI_DATA) { 97 if (msg.data != XEN_PIRQ_MSI_DATA ||
98 irq = xen_allocate_pirq_msi((type == PCI_CAP_ID_MSIX) ? 98 xen_irq_from_pirq(pirq) < 0) {
99 "msi-x" : "msi", &pirq, 0); 99 pirq = xen_allocate_pirq_msi(dev, msidesc);
100 if (irq < 0) 100 if (pirq < 0)
101 goto error; 101 goto error;
102 ret = set_irq_msi(irq, msidesc); 102 xen_msi_compose_msg(dev, pirq, &msg);
103 if (ret < 0) 103 __write_msi_msg(msidesc, &msg);
104 goto error_while; 104 dev_dbg(&dev->dev, "xen: msi bound to pirq=%d\n", pirq);
105 printk(KERN_DEBUG "xen: msi already setup: msi --> irq=%d" 105 } else {
106 " pirq=%d\n", irq, pirq); 106 dev_dbg(&dev->dev,
107 return 0; 107 "xen: msi already bound to pirq=%d\n", pirq);
108 } 108 }
109 irq = xen_allocate_pirq_msi((type == PCI_CAP_ID_MSIX) ? 109 irq = xen_bind_pirq_msi_to_irq(dev, msidesc, pirq,
110 "msi-x" : "msi", &pirq, 1); 110 (type == PCI_CAP_ID_MSIX) ?
111 if (irq < 0 || pirq < 0) 111 "msi-x" : "msi");
112 if (irq < 0)
112 goto error; 113 goto error;
113 printk(KERN_DEBUG "xen: msi --> irq=%d, pirq=%d\n", irq, pirq); 114 dev_dbg(&dev->dev,
114 xen_msi_compose_msg(dev, pirq, &msg); 115 "xen: msi --> pirq=%d --> irq=%d\n", pirq, irq);
115 ret = set_irq_msi(irq, msidesc);
116 if (ret < 0)
117 goto error_while;
118 write_msi_msg(irq, &msg);
119 } 116 }
120 return 0; 117 return 0;
121 118
122error_while:
123 unbind_from_irqhandler(irq, NULL);
124error: 119error:
125 if (ret == -ENODEV) 120 dev_err(&dev->dev,
126 dev_err(&dev->dev, "Xen PCI frontend has not registered" \ 121 "Xen PCI frontend has not registered MSI/MSI-X support!\n");
127 " MSI/MSI-X support!\n"); 122 return -ENODEV;
128
129 return ret;
130} 123}
131 124
132/* 125/*
@@ -152,28 +145,19 @@ static int xen_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
152 goto error; 145 goto error;
153 i = 0; 146 i = 0;
154 list_for_each_entry(msidesc, &dev->msi_list, list) { 147 list_for_each_entry(msidesc, &dev->msi_list, list) {
155 irq = xen_allocate_pirq_msi( 148 irq = xen_bind_pirq_msi_to_irq(dev, msidesc, v[i],
156 (type == PCI_CAP_ID_MSIX) ? 149 (type == PCI_CAP_ID_MSIX) ?
157 "pcifront-msi-x" : "pcifront-msi", 150 "pcifront-msi-x" :
158 &v[i], 0); 151 "pcifront-msi");
159 if (irq < 0) { 152 if (irq < 0)
160 ret = -1;
161 goto free; 153 goto free;
162 }
163 ret = set_irq_msi(irq, msidesc);
164 if (ret)
165 goto error_while;
166 i++; 154 i++;
167 } 155 }
168 kfree(v); 156 kfree(v);
169 return 0; 157 return 0;
170 158
171error_while:
172 unbind_from_irqhandler(irq, NULL);
173error: 159error:
174 if (ret == -ENODEV) 160 dev_err(&dev->dev, "Xen PCI frontend has not registered MSI/MSI-X support!\n");
175 dev_err(&dev->dev, "Xen PCI frontend has not registered" \
176 " MSI/MSI-X support!\n");
177free: 161free:
178 kfree(v); 162 kfree(v);
179 return ret; 163 return ret;
diff --git a/drivers/xen/events.c b/drivers/xen/events.c
index c21066fc30be..1033f6284f31 100644
--- a/drivers/xen/events.c
+++ b/drivers/xen/events.c
@@ -647,12 +647,12 @@ out:
647#include <linux/msi.h> 647#include <linux/msi.h>
648#include "../pci/msi.h" 648#include "../pci/msi.h"
649 649
650static int find_unbound_pirq(int type) 650int xen_allocate_pirq_msi(struct pci_dev *dev, struct msi_desc *msidesc)
651{ 651{
652 int rc; 652 int rc;
653 struct physdev_get_free_pirq op_get_free_pirq; 653 struct physdev_get_free_pirq op_get_free_pirq;
654 654
655 op_get_free_pirq.type = type; 655 op_get_free_pirq.type = MAP_PIRQ_TYPE_MSI;
656 rc = HYPERVISOR_physdev_op(PHYSDEVOP_get_free_pirq, &op_get_free_pirq); 656 rc = HYPERVISOR_physdev_op(PHYSDEVOP_get_free_pirq, &op_get_free_pirq);
657 657
658 WARN_ONCE(rc == -ENOSYS, 658 WARN_ONCE(rc == -ENOSYS,
@@ -661,9 +661,10 @@ static int find_unbound_pirq(int type)
661 return rc ? -1 : op_get_free_pirq.pirq; 661 return rc ? -1 : op_get_free_pirq.pirq;
662} 662}
663 663
664int xen_allocate_pirq_msi(char *name, int *pirq, int alloc_pirq) 664int xen_bind_pirq_msi_to_irq(struct pci_dev *dev, struct msi_desc *msidesc,
665 int pirq, const char *name)
665{ 666{
666 int irq; 667 int irq, ret;
667 668
668 spin_lock(&irq_mapping_update_lock); 669 spin_lock(&irq_mapping_update_lock);
669 670
@@ -671,24 +672,21 @@ int xen_allocate_pirq_msi(char *name, int *pirq, int alloc_pirq)
671 if (irq == -1) 672 if (irq == -1)
672 goto out; 673 goto out;
673 674
674 if (alloc_pirq) {
675 *pirq = find_unbound_pirq(MAP_PIRQ_TYPE_MSI);
676 if (*pirq == -1) {
677 xen_free_irq(irq);
678 irq = -1;
679 goto out;
680 }
681 }
682
683 set_irq_chip_and_handler_name(irq, &xen_pirq_chip, 675 set_irq_chip_and_handler_name(irq, &xen_pirq_chip,
684 handle_level_irq, name); 676 handle_level_irq, name);
685 677
686 irq_info[irq] = mk_pirq_info(0, *pirq, 0, 0); 678 irq_info[irq] = mk_pirq_info(0, pirq, 0, 0);
687 pirq_to_irq[*pirq] = irq; 679 pirq_to_irq[pirq] = irq;
688 680 ret = set_irq_msi(irq, msidesc);
681 if (ret < 0)
682 goto error_irq;
689out: 683out:
690 spin_unlock(&irq_mapping_update_lock); 684 spin_unlock(&irq_mapping_update_lock);
691 return irq; 685 return irq;
686error_irq:
687 spin_unlock(&irq_mapping_update_lock);
688 xen_free_irq(irq);
689 return -1;
692} 690}
693 691
694int xen_create_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, int type) 692int xen_create_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, int type)
diff --git a/include/xen/events.h b/include/xen/events.h
index f70536af921c..18bf825bac66 100644
--- a/include/xen/events.h
+++ b/include/xen/events.h
@@ -75,7 +75,9 @@ int xen_allocate_pirq(unsigned gsi, int shareable, char *name);
75int xen_map_pirq_gsi(unsigned pirq, unsigned gsi, int shareable, char *name); 75int xen_map_pirq_gsi(unsigned pirq, unsigned gsi, int shareable, char *name);
76 76
77#ifdef CONFIG_PCI_MSI 77#ifdef CONFIG_PCI_MSI
78int xen_allocate_pirq_msi(char *name, int *pirq, int alloc_pirq); 78int xen_allocate_pirq_msi(struct pci_dev *dev, struct msi_desc *msidesc);
79int xen_bind_pirq_msi_to_irq(struct pci_dev *dev, struct msi_desc *msidesc,
80 int pirq, const char *name);
79int xen_create_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, int type); 81int xen_create_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, int type);
80#endif 82#endif
81 83