Skip to content

Commit 4892c9b

Browse files
roygerDavid Vrabel
authored andcommitted
xen: add support for MSI message groups
Add support for MSI message groups for Xen Dom0 using the MAP_PIRQ_TYPE_MULTI_MSI pirq map type. In order to keep track of which pirq is the first one in the group all pirqs in the MSI group except for the first one have the newly introduced PIRQ_MSI_GROUP flag set. This prevents calling PHYSDEVOP_unmap_pirq on them, since the unmap must be done with the first pirq in the group. Signed-off-by: Roger Pau Monné <[email protected]> Signed-off-by: David Vrabel <[email protected]> Cc: Boris Ostrovsky <[email protected]>
1 parent efdfa3e commit 4892c9b

File tree

5 files changed

+65
-27
lines changed

5 files changed

+65
-27
lines changed

arch/x86/pci/xen.c

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@ static int xen_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
178178
i = 0;
179179
list_for_each_entry(msidesc, &dev->msi_list, list) {
180180
irq = xen_bind_pirq_msi_to_irq(dev, msidesc, v[i],
181+
(type == PCI_CAP_ID_MSI) ? nvec : 1,
181182
(type == PCI_CAP_ID_MSIX) ?
182183
"pcifront-msi-x" :
183184
"pcifront-msi",
@@ -245,6 +246,7 @@ static int xen_hvm_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
245246
"xen: msi already bound to pirq=%d\n", pirq);
246247
}
247248
irq = xen_bind_pirq_msi_to_irq(dev, msidesc, pirq,
249+
(type == PCI_CAP_ID_MSI) ? nvec : 1,
248250
(type == PCI_CAP_ID_MSIX) ?
249251
"msi-x" : "msi",
250252
DOMID_SELF);
@@ -269,9 +271,6 @@ static int xen_initdom_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
269271
int ret = 0;
270272
struct msi_desc *msidesc;
271273

272-
if (type == PCI_CAP_ID_MSI && nvec > 1)
273-
return 1;
274-
275274
list_for_each_entry(msidesc, &dev->msi_list, list) {
276275
struct physdev_map_pirq map_irq;
277276
domid_t domid;
@@ -291,7 +290,10 @@ static int xen_initdom_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
291290
(pci_domain_nr(dev->bus) << 16);
292291
map_irq.devfn = dev->devfn;
293292

294-
if (type == PCI_CAP_ID_MSIX) {
293+
if (type == PCI_CAP_ID_MSI && nvec > 1) {
294+
map_irq.type = MAP_PIRQ_TYPE_MULTI_MSI;
295+
map_irq.entry_nr = nvec;
296+
} else if (type == PCI_CAP_ID_MSIX) {
295297
int pos;
296298
u32 table_offset, bir;
297299

@@ -308,6 +310,16 @@ static int xen_initdom_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
308310
if (pci_seg_supported)
309311
ret = HYPERVISOR_physdev_op(PHYSDEVOP_map_pirq,
310312
&map_irq);
313+
if (type == PCI_CAP_ID_MSI && nvec > 1 && ret) {
314+
/*
315+
* If MAP_PIRQ_TYPE_MULTI_MSI is not available
316+
* there's nothing else we can do in this case.
317+
* Just set ret > 0 so driver can retry with
318+
* single MSI.
319+
*/
320+
ret = 1;
321+
goto out;
322+
}
311323
if (ret == -EINVAL && !pci_domain_nr(dev->bus)) {
312324
map_irq.type = MAP_PIRQ_TYPE_MSI;
313325
map_irq.index = -1;
@@ -324,11 +336,10 @@ static int xen_initdom_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
324336
goto out;
325337
}
326338

327-
ret = xen_bind_pirq_msi_to_irq(dev, msidesc,
328-
map_irq.pirq,
329-
(type == PCI_CAP_ID_MSIX) ?
330-
"msi-x" : "msi",
331-
domid);
339+
ret = xen_bind_pirq_msi_to_irq(dev, msidesc, map_irq.pirq,
340+
(type == PCI_CAP_ID_MSI) ? nvec : 1,
341+
(type == PCI_CAP_ID_MSIX) ? "msi-x" : "msi",
342+
domid);
332343
if (ret < 0)
333344
goto out;
334345
}

drivers/xen/events/events_base.c

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -391,10 +391,10 @@ static void xen_irq_init(unsigned irq)
391391
list_add_tail(&info->list, &xen_irq_list_head);
392392
}
393393

394-
static int __must_check xen_allocate_irq_dynamic(void)
394+
static int __must_check xen_allocate_irqs_dynamic(int nvec)
395395
{
396396
int first = 0;
397-
int irq;
397+
int i, irq;
398398

399399
#ifdef CONFIG_X86_IO_APIC
400400
/*
@@ -408,14 +408,22 @@ static int __must_check xen_allocate_irq_dynamic(void)
408408
first = get_nr_irqs_gsi();
409409
#endif
410410

411-
irq = irq_alloc_desc_from(first, -1);
411+
irq = irq_alloc_descs_from(first, nvec, -1);
412412

413-
if (irq >= 0)
414-
xen_irq_init(irq);
413+
if (irq >= 0) {
414+
for (i = 0; i < nvec; i++)
415+
xen_irq_init(irq + i);
416+
}
415417

416418
return irq;
417419
}
418420

421+
static inline int __must_check xen_allocate_irq_dynamic(void)
422+
{
423+
424+
return xen_allocate_irqs_dynamic(1);
425+
}
426+
419427
static int __must_check xen_allocate_irq_gsi(unsigned gsi)
420428
{
421429
int irq;
@@ -738,30 +746,34 @@ int xen_allocate_pirq_msi(struct pci_dev *dev, struct msi_desc *msidesc)
738746
}
739747

740748
int xen_bind_pirq_msi_to_irq(struct pci_dev *dev, struct msi_desc *msidesc,
741-
int pirq, const char *name, domid_t domid)
749+
int pirq, int nvec, const char *name, domid_t domid)
742750
{
743-
int irq, ret;
751+
int i, irq, ret;
744752

745753
mutex_lock(&irq_mapping_update_lock);
746754

747-
irq = xen_allocate_irq_dynamic();
755+
irq = xen_allocate_irqs_dynamic(nvec);
748756
if (irq < 0)
749757
goto out;
750758

751-
irq_set_chip_and_handler_name(irq, &xen_pirq_chip, handle_edge_irq,
752-
name);
759+
for (i = 0; i < nvec; i++) {
760+
irq_set_chip_and_handler_name(irq + i, &xen_pirq_chip, handle_edge_irq, name);
761+
762+
ret = xen_irq_info_pirq_setup(irq + i, 0, pirq + i, 0, domid,
763+
i == 0 ? 0 : PIRQ_MSI_GROUP);
764+
if (ret < 0)
765+
goto error_irq;
766+
}
753767

754-
ret = xen_irq_info_pirq_setup(irq, 0, pirq, 0, domid, 0);
755-
if (ret < 0)
756-
goto error_irq;
757768
ret = irq_set_msi_desc(irq, msidesc);
758769
if (ret < 0)
759770
goto error_irq;
760771
out:
761772
mutex_unlock(&irq_mapping_update_lock);
762773
return irq;
763774
error_irq:
764-
__unbind_from_irq(irq);
775+
for (; i >= 0; i--)
776+
__unbind_from_irq(irq + i);
765777
mutex_unlock(&irq_mapping_update_lock);
766778
return ret;
767779
}
@@ -780,7 +792,12 @@ int xen_destroy_irq(int irq)
780792
if (!desc)
781793
goto out;
782794

783-
if (xen_initial_domain()) {
795+
/*
796+
* If trying to remove a vector in a MSI group different
797+
* than the first one skip the PIRQ unmap unless this vector
798+
* is the first one in the group.
799+
*/
800+
if (xen_initial_domain() && !(info->u.pirq.flags & PIRQ_MSI_GROUP)) {
784801
unmap_irq.pirq = info->u.pirq.pirq;
785802
unmap_irq.domid = info->u.pirq.domid;
786803
rc = HYPERVISOR_physdev_op(PHYSDEVOP_unmap_pirq, &unmap_irq);

drivers/xen/events/events_internal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ struct irq_info {
5353

5454
#define PIRQ_NEEDS_EOI (1 << 0)
5555
#define PIRQ_SHAREABLE (1 << 1)
56+
#define PIRQ_MSI_GROUP (1 << 2)
5657

5758
struct evtchn_ops {
5859
unsigned (*max_channels)(void);

include/xen/events.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
#define _XEN_EVENTS_H
33

44
#include <linux/interrupt.h>
5+
#ifdef CONFIG_PCI_MSI
6+
#include <linux/msi.h>
7+
#endif
58

69
#include <xen/interface/event_channel.h>
710
#include <asm/xen/hypercall.h>
@@ -101,7 +104,7 @@ int xen_bind_pirq_gsi_to_irq(unsigned gsi,
101104
int xen_allocate_pirq_msi(struct pci_dev *dev, struct msi_desc *msidesc);
102105
/* Bind an PSI pirq to an irq. */
103106
int xen_bind_pirq_msi_to_irq(struct pci_dev *dev, struct msi_desc *msidesc,
104-
int pirq, const char *name, domid_t domid);
107+
int pirq, int nvec, const char *name, domid_t domid);
105108
#endif
106109

107110
/* De-allocates the above mentioned physical interrupt. */

include/xen/interface/physdev.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ struct physdev_irq {
131131
#define MAP_PIRQ_TYPE_GSI 0x1
132132
#define MAP_PIRQ_TYPE_UNKNOWN 0x2
133133
#define MAP_PIRQ_TYPE_MSI_SEG 0x3
134+
#define MAP_PIRQ_TYPE_MULTI_MSI 0x4
134135

135136
#define PHYSDEVOP_map_pirq 13
136137
struct physdev_map_pirq {
@@ -141,11 +142,16 @@ struct physdev_map_pirq {
141142
int index;
142143
/* IN or OUT */
143144
int pirq;
144-
/* IN - high 16 bits hold segment for MAP_PIRQ_TYPE_MSI_SEG */
145+
/* IN - high 16 bits hold segment for ..._MSI_SEG and ..._MULTI_MSI */
145146
int bus;
146147
/* IN */
147148
int devfn;
148-
/* IN */
149+
/* IN
150+
* - For MSI-X contains entry number.
151+
* - For MSI with ..._MULTI_MSI contains number of vectors.
152+
* OUT (..._MULTI_MSI only)
153+
* - Number of vectors allocated.
154+
*/
149155
int entry_nr;
150156
/* IN */
151157
uint64_t table_base;

0 commit comments

Comments
 (0)