ia64/linux-2.6.18-xen.hg

changeset 655:8925ce755252

linux/pci-msi: translate Xen-provided PIRQs

Previously, the kernel depended upon Xen's NR_IRQS to be no larger
than the kernel's NR_PIRQS.

Signed-off-by: Jan Beulich <jbeulich@novell.com>
author Keir Fraser <keir.fraser@citrix.com>
date Thu Sep 04 11:30:12 2008 +0100 (2008-09-04)
parents 8566781df55e
children c47b7e47ab19
files arch/i386/kernel/io_apic-xen.c arch/x86_64/kernel/io_apic-xen.c drivers/pci/msi-xen.c drivers/xen/core/evtchn.c include/asm-i386/mach-xen/irq_vectors.h include/xen/evtchn.h
line diff
     1.1 --- a/arch/i386/kernel/io_apic-xen.c	Mon Sep 01 10:46:19 2008 +0100
     1.2 +++ b/arch/i386/kernel/io_apic-xen.c	Thu Sep 04 11:30:12 2008 +0100
     1.3 @@ -47,6 +47,7 @@
     1.4  
     1.5  #include <xen/interface/xen.h>
     1.6  #include <xen/interface/physdev.h>
     1.7 +#include <xen/evtchn.h>
     1.8  
     1.9  /* Fake i8259 */
    1.10  #define make_8259A_irq(_irq)     (io_apic_irqs &= ~(1UL<<(_irq)))
    1.11 @@ -1260,7 +1261,7 @@ static void ioapic_register_intr(int irq
    1.12  	set_intr_gate(vector, interrupt[idx]);
    1.13  }
    1.14  #else
    1.15 -#define ioapic_register_intr(_irq,_vector,_trigger) ((void)0)
    1.16 +#define ioapic_register_intr(irq, vector, trigger) evtchn_register_pirq(irq)
    1.17  #endif
    1.18  
    1.19  static void __init setup_IO_APIC_irqs(void)
     2.1 --- a/arch/x86_64/kernel/io_apic-xen.c	Mon Sep 01 10:46:19 2008 +0100
     2.2 +++ b/arch/x86_64/kernel/io_apic-xen.c	Thu Sep 04 11:30:12 2008 +0100
     2.3 @@ -95,6 +95,7 @@ int vector_irq[NR_VECTORS] __read_mostly
     2.4  
     2.5  #include <xen/interface/xen.h>
     2.6  #include <xen/interface/physdev.h>
     2.7 +#include <xen/evtchn.h>
     2.8  
     2.9  /* Fake i8259 */
    2.10  #define make_8259A_irq(_irq)     (io_apic_irqs &= ~(1UL<<(_irq)))
    2.11 @@ -940,7 +941,7 @@ static void ioapic_register_intr(int irq
    2.12  	set_intr_gate(vector, interrupt[idx]);
    2.13  }
    2.14  #else
    2.15 -#define ioapic_register_intr(_irq,_vector,_trigger) ((void)0)
    2.16 +#define ioapic_register_intr(irq, vector, trigger) evtchn_register_pirq(irq)
    2.17  #endif /* !CONFIG_XEN */
    2.18  
    2.19  static void __init setup_IO_APIC_irqs(void)
     3.1 --- a/drivers/pci/msi-xen.c	Mon Sep 01 10:46:19 2008 +0100
     3.2 +++ b/drivers/pci/msi-xen.c	Thu Sep 04 11:30:12 2008 +0100
     3.3 @@ -15,6 +15,8 @@
     3.4  #include <linux/pci.h>
     3.5  #include <linux/proc_fs.h>
     3.6  
     3.7 +#include <xen/evtchn.h>
     3.8 +
     3.9  #include <asm/errno.h>
    3.10  #include <asm/io.h>
    3.11  #include <asm/smp.h>
    3.12 @@ -156,13 +158,15 @@ static int msi_unmap_pirq(struct pci_dev
    3.13  	int rc;
    3.14  
    3.15  	unmap.domid = msi_get_dev_owner(dev);
    3.16 -	unmap.pirq = pirq;
    3.17 +	unmap.pirq = evtchn_get_xen_pirq(pirq);
    3.18  
    3.19  	if ((rc = HYPERVISOR_physdev_op(PHYSDEVOP_unmap_pirq, &unmap)))
    3.20  		printk(KERN_WARNING "unmap irq %x failed\n", pirq);
    3.21  
    3.22  	if (rc < 0)
    3.23  		return rc;
    3.24 +
    3.25 +	evtchn_map_pirq(pirq, 0);
    3.26  	return 0;
    3.27  }
    3.28  
    3.29 @@ -197,7 +201,7 @@ static int msi_map_pirq_to_vector(struct
    3.30  	map_irq.domid = domid;
    3.31  	map_irq.type = MAP_PIRQ_TYPE_MSI;
    3.32  	map_irq.index = -1;
    3.33 -	map_irq.pirq = pirq;
    3.34 +	map_irq.pirq = pirq < 0 ? -1 : evtchn_get_xen_pirq(pirq);
    3.35  	map_irq.bus = dev->bus->number;
    3.36  	map_irq.devfn = dev->devfn;
    3.37  	map_irq.entry_nr = entry_nr;
    3.38 @@ -208,8 +212,12 @@ static int msi_map_pirq_to_vector(struct
    3.39  
    3.40  	if (rc < 0)
    3.41  		return rc;
    3.42 +	/* This happens when MSI support is not enabled in Xen. */
    3.43 +	if (rc == 0 && map_irq.pirq < 0)
    3.44 +		return -ENOSYS;
    3.45  
    3.46 -	return map_irq.pirq;
    3.47 +	BUG_ON(map_irq.pirq <= 0);
    3.48 +	return evtchn_map_pirq(pirq, map_irq.pirq);
    3.49  }
    3.50  
    3.51  static int msi_map_vector(struct pci_dev *dev, int entry_nr, u64 table_base)
     4.1 --- a/drivers/xen/core/evtchn.c	Mon Sep 01 10:46:19 2008 +0100
     4.2 +++ b/drivers/xen/core/evtchn.c	Thu Sep 04 11:30:12 2008 +0100
     4.3 @@ -66,13 +66,27 @@ enum {
     4.4  	IRQT_VIRQ,
     4.5  	IRQT_IPI,
     4.6  	IRQT_LOCAL_PORT,
     4.7 -	IRQT_CALLER_PORT
     4.8 +	IRQT_CALLER_PORT,
     4.9 +	_IRQT_COUNT
    4.10  };
    4.11  
    4.12 +#define _IRQT_BITS 4
    4.13 +#define _EVTCHN_BITS 12
    4.14 +#define _INDEX_BITS (32 - _IRQT_BITS - _EVTCHN_BITS)
    4.15 +
    4.16  /* Constructor for packed IRQ information. */
    4.17  static inline u32 mk_irq_info(u32 type, u32 index, u32 evtchn)
    4.18  {
    4.19 -	return ((type << 24) | (index << 16) | evtchn);
    4.20 +	BUILD_BUG_ON(_IRQT_COUNT > (1U << _IRQT_BITS));
    4.21 +
    4.22 +	BUILD_BUG_ON(NR_PIRQS > (1U << _INDEX_BITS));
    4.23 +	BUILD_BUG_ON(NR_VIRQS > (1U << _INDEX_BITS));
    4.24 +	BUILD_BUG_ON(NR_IPIS > (1U << _INDEX_BITS));
    4.25 +	BUG_ON(index >> _INDEX_BITS);
    4.26 +
    4.27 +	BUILD_BUG_ON(NR_EVENT_CHANNELS > (1U << _EVTCHN_BITS));
    4.28 +
    4.29 +	return ((type << (32 - _IRQT_BITS)) | (index << _EVTCHN_BITS) | evtchn);
    4.30  }
    4.31  
    4.32  /* Convenient shorthand for packed representation of an unbound IRQ. */
    4.33 @@ -84,17 +98,17 @@ static inline u32 mk_irq_info(u32 type, 
    4.34  
    4.35  static inline unsigned int evtchn_from_irq(int irq)
    4.36  {
    4.37 -	return (u16)(irq_info[irq]);
    4.38 +	return irq_info[irq] & ((1U << _EVTCHN_BITS) - 1);
    4.39  }
    4.40  
    4.41  static inline unsigned int index_from_irq(int irq)
    4.42  {
    4.43 -	return (u8)(irq_info[irq] >> 16);
    4.44 +	return (irq_info[irq] >> _EVTCHN_BITS) & ((1U << _INDEX_BITS) - 1);
    4.45  }
    4.46  
    4.47  static inline unsigned int type_from_irq(int irq)
    4.48  {
    4.49 -	return (u8)(irq_info[irq] >> 24);
    4.50 +	return irq_info[irq] >> (32 - _IRQT_BITS);
    4.51  }
    4.52  
    4.53  /* IRQ <-> VIRQ mapping. */
    4.54 @@ -742,6 +756,60 @@ static struct hw_interrupt_type dynirq_t
    4.55  	.retrigger = resend_irq_on_evtchn,
    4.56  };
    4.57  
    4.58 +void evtchn_register_pirq(int irq)
    4.59 +{
    4.60 +	irq_info[irq] = mk_irq_info(IRQT_PIRQ, irq, 0);
    4.61 +}
    4.62 +
    4.63 +#ifndef CONFIG_X86_IO_APIC
    4.64 +#undef IO_APIC_IRQ
    4.65 +#define IO_APIC_IRQ(irq) ((irq) >= pirq_to_irq(16))
    4.66 +#endif
    4.67 +
    4.68 +int evtchn_map_pirq(int irq, int xen_pirq)
    4.69 +{
    4.70 +	if (irq < 0) {
    4.71 +		static DEFINE_SPINLOCK(irq_alloc_lock);
    4.72 +
    4.73 +		irq = pirq_to_irq(NR_PIRQS - 1);
    4.74 +		spin_lock(&irq_alloc_lock);
    4.75 +		do {
    4.76 +			if (!IO_APIC_IRQ(irq))
    4.77 +				continue;
    4.78 +			if (!index_from_irq(irq)) {
    4.79 +				BUG_ON(type_from_irq(irq) != IRQT_UNBOUND);
    4.80 +				irq_info[irq] = mk_irq_info(IRQT_PIRQ,
    4.81 +							    xen_pirq, 0);
    4.82 +				break;
    4.83 +			}
    4.84 +		} while (--irq);
    4.85 +		spin_unlock(&irq_alloc_lock);
    4.86 +		if (irq < pirq_to_irq(16))
    4.87 +			return -ENOSPC;
    4.88 +	} else if (!xen_pirq) {
    4.89 +		if (unlikely(type_from_irq(irq) != IRQT_PIRQ))
    4.90 +			return -EINVAL;
    4.91 +		irq_info[irq] = IRQ_UNBOUND;
    4.92 +		return 0;
    4.93 +	} else if (type_from_irq(irq) != IRQT_PIRQ
    4.94 +		   || index_from_irq(irq) != xen_pirq) {
    4.95 +		printk(KERN_ERR "IRQ#%d is already mapped to %d:%u - "
    4.96 +				"cannot map to PIRQ#%u\n",
    4.97 +		       irq, type_from_irq(irq), index_from_irq(irq), xen_pirq);
    4.98 +		return -EINVAL;
    4.99 +	}
   4.100 +	return index_from_irq(irq) ? irq : -EINVAL;
   4.101 +}
   4.102 +
   4.103 +int evtchn_get_xen_pirq(int irq)
   4.104 +{
   4.105 +	if (!IO_APIC_IRQ(irq))
   4.106 +		return irq;
   4.107 +	if (unlikely(type_from_irq(irq) != IRQT_PIRQ))
   4.108 +		return 0;
   4.109 +	return index_from_irq(irq);
   4.110 +}
   4.111 +
   4.112  static inline void pirq_unmask_notify(int pirq)
   4.113  {
   4.114  	struct physdev_eoi eoi = { .irq = pirq };
   4.115 @@ -774,7 +842,7 @@ static unsigned int startup_pirq(unsigne
   4.116  	if (VALID_EVTCHN(evtchn))
   4.117  		goto out;
   4.118  
   4.119 -	bind_pirq.pirq  = irq;
   4.120 +	bind_pirq.pirq = evtchn_get_xen_pirq(irq);
   4.121  	/* NB. We are happy to share unless we are probing. */
   4.122  	bind_pirq.flags = probing_irq(irq) ? 0 : BIND_PIRQ__WILL_SHARE;
   4.123  	if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_pirq, &bind_pirq) != 0) {
   4.124 @@ -789,7 +857,7 @@ static unsigned int startup_pirq(unsigne
   4.125  
   4.126  	evtchn_to_irq[evtchn] = irq;
   4.127  	bind_evtchn_to_cpu(evtchn, 0);
   4.128 -	irq_info[irq] = mk_irq_info(IRQT_PIRQ, irq, evtchn);
   4.129 +	irq_info[irq] = mk_irq_info(IRQT_PIRQ, bind_pirq.pirq, evtchn);
   4.130  
   4.131   out:
   4.132  	unmask_evtchn(evtchn);
   4.133 @@ -814,7 +882,7 @@ static void shutdown_pirq(unsigned int i
   4.134  
   4.135  	bind_evtchn_to_cpu(evtchn, 0);
   4.136  	evtchn_to_irq[evtchn] = -1;
   4.137 -	irq_info[irq] = IRQ_UNBOUND;
   4.138 +	irq_info[irq] = mk_irq_info(IRQT_PIRQ, index_from_irq(irq), 0);
   4.139  }
   4.140  
   4.141  static void enable_pirq(unsigned int irq)
     5.1 --- a/include/asm-i386/mach-xen/irq_vectors.h	Mon Sep 01 10:46:19 2008 +0100
     5.2 +++ b/include/asm-i386/mach-xen/irq_vectors.h	Thu Sep 04 11:30:12 2008 +0100
     5.3 @@ -108,7 +108,11 @@
     5.4   */
     5.5  
     5.6  #define PIRQ_BASE		0
     5.7 -#define NR_PIRQS		256
     5.8 +#if NR_CPUS < MAX_IO_APICS
     5.9 +# define NR_PIRQS		(NR_VECTORS + 32 * NR_CPUS)
    5.10 +#else
    5.11 +# define NR_PIRQS		(NR_VECTORS + 32 * MAX_IO_APICS)
    5.12 +#endif
    5.13  
    5.14  #define DYNIRQ_BASE		(PIRQ_BASE + NR_PIRQS)
    5.15  #define NR_DYNIRQS		256
     6.1 --- a/include/xen/evtchn.h	Mon Sep 01 10:46:19 2008 +0100
     6.2 +++ b/include/xen/evtchn.h	Thu Sep 04 11:30:12 2008 +0100
     6.3 @@ -101,6 +101,13 @@ asmlinkage void evtchn_do_upcall(struct 
     6.4  /* Entry point for notifications into the userland character device. */
     6.5  void evtchn_device_upcall(int port);
     6.6  
     6.7 +/* Mark a PIRQ as unavailable for dynamic allocation. */
     6.8 +void evtchn_register_pirq(int irq);
     6.9 +/* Map a Xen-supplied PIRQ to a dynamically allocated one. */
    6.10 +int evtchn_map_pirq(int irq, int xen_pirq);
    6.11 +/* Look up a Xen-supplied PIRQ for a dynamically allocated one. */
    6.12 +int evtchn_get_xen_pirq(int irq);
    6.13 +
    6.14  void mask_evtchn(int port);
    6.15  void disable_all_local_evtchn(void);
    6.16  void unmask_evtchn(int port);