static int iosapic_kmalloc_ok;
static LIST_HEAD(free_rte_list);
+#ifdef CONFIG_XEN
+#include <xen/interface/xen.h>
+#include <xen/interface/physdev.h>
+#include <asm/hypervisor.h>
+static inline unsigned int xen_iosapic_read(char __iomem *iosapic, unsigned int reg)
+{
+ physdev_op_t op;
+ int ret;
+
+ op.cmd = PHYSDEVOP_APIC_READ;
+ op.u.apic_op.apic_physbase = (unsigned long)iosapic -
+ __IA64_UNCACHED_OFFSET;
+ op.u.apic_op.reg = reg;
+ ret = HYPERVISOR_physdev_op(&op);
+ if (ret)
+ return ret;
+ return op.u.apic_op.value;
+}
+
+static inline void xen_iosapic_write(char __iomem *iosapic, unsigned int reg, u32 val)
+{
+ physdev_op_t op;
+
+ op.cmd = PHYSDEVOP_APIC_WRITE;
+ op.u.apic_op.apic_physbase = (unsigned long)iosapic -
+ __IA64_UNCACHED_OFFSET;
+ op.u.apic_op.reg = reg;
+ op.u.apic_op.value = val;
+ HYPERVISOR_physdev_op(&op);
+}
+
+static inline unsigned int iosapic_read(char __iomem *iosapic, unsigned int reg)
+{
+ if (!running_on_xen) {
+ writel(reg, iosapic + IOSAPIC_REG_SELECT);
+ return readl(iosapic + IOSAPIC_WINDOW);
+ } else
+ return xen_iosapic_read(iosapic, reg);
+}
+
+static inline void iosapic_write(char __iomem *iosapic, unsigned int reg, u32 val)
+{
+ if (!running_on_xen) {
+ writel(reg, iosapic + IOSAPIC_REG_SELECT);
+ writel(val, iosapic + IOSAPIC_WINDOW);
+ } else
+ xen_iosapic_write(iosapic, reg, val);
+}
+
+int xen_assign_irq_vector(int irq)
+{
+ physdev_op_t op;
+
+ op.cmd = PHYSDEVOP_ASSIGN_VECTOR;
+ op.u.irq_op.irq = irq;
+ if (HYPERVISOR_physdev_op(&op))
+ return -ENOSPC;
+
+ return op.u.irq_op.vector;
+}
+#endif /* XEN */
+
/*
* Find an IOSAPIC associated with a GSI
*/
}
pcat_compat = system_pcat_compat;
+#ifdef CONFIG_XEN
+ if (running_on_xen)
+ return;
+#endif
if (pcat_compat) {
/*
* Disable the compatibility mode interrupts (8259 style), needs IN/OUT support
assign_irq_vector (int irq)
{
int pos, vector;
+#ifdef CONFIG_XEN
+ extern int xen_assign_irq_vector(int);
+ if (running_on_xen)
+ return xen_assign_irq_vector(irq);
+#endif /* CONFIG_XEN */
again:
pos = find_first_zero_bit(ia64_vector_mask, IA64_NUM_DEVICE_VECTORS);
vector = IA64_FIRST_DEVICE_VECTOR + pos;
#define NR_IOSAPICS 256
+#ifndef CONFIG_XEN
static inline unsigned int iosapic_read(char __iomem *iosapic, unsigned int reg)
{
writel(reg, iosapic + IOSAPIC_REG_SELECT);
writel(reg, iosapic + IOSAPIC_REG_SELECT);
writel(val, iosapic + IOSAPIC_WINDOW);
}
+#endif
static inline void iosapic_eoi(char __iomem *iosapic, u32 vector)
{
return 0;
}
core_initcall (iosapic_enable_kmalloc);
+
+#ifdef XEN
+/* nop for now */
+void set_irq_affinity_info(unsigned int irq, int hwid, int redir) {}
+
+static int iosapic_physbase_to_id(unsigned long physbase)
+{
+ int i;
+ unsigned long addr = physbase | __IA64_UNCACHED_OFFSET;
+
+ for (i = 0; i < NR_IOSAPICS; i++) {
+ if ((unsigned long)(iosapic_lists[i].addr) == addr)
+ return i;
+ }
+
+ return -1;
+}
+
+int iosapic_guest_read(unsigned long physbase, unsigned int reg, u32 *pval)
+{
+ int id;
+ unsigned long flags;
+
+ if ((id = (iosapic_physbase_to_id(physbase))) < 0)
+ return id;
+
+ spin_lock_irqsave(&iosapic_lock, flags);
+ *pval = iosapic_read(iosapic_lists[id].addr, reg);
+ spin_unlock_irqrestore(&iosapic_lock, flags);
+
+ return 0;
+}
+
+int iosapic_guest_write(unsigned long physbase, unsigned int reg, u32 val)
+{
+ unsigned int id, gsi, vec, dest, high32;
+ char rte_index;
+ struct iosapic *ios;
+ struct iosapic_intr_info *info;
+ struct rte_entry rte;
+ unsigned long flags;
+
+ if ((id = (iosapic_physbase_to_id(physbase))) < 0)
+ return -EINVAL;
+ ios = &iosapic_lists[id];
+
+ /* Only handle first half of RTE update */
+ if ((reg < 0x10) || (reg & 1))
+ return 0;
+
+ rte.val = val;
+ rte_index = IOSAPIC_RTEINDEX(reg);
+ vec = rte.lo.vector;
+#if 0
+ /* Take PMI/NMI/INIT/EXTINT handled by xen */
+ if (rte.delivery_mode > IOSAPIC_LOWEST_PRIORITY) {
+ printk("Attempt to write IOSAPIC dest mode owned by xen!\n");
+ printk("IOSAPIC/PIN = (%d/%d), lo = 0x%x\n",
+ id, rte_index, val);
+ return -EINVAL;
+ }
+#endif
+
+ /* Sanity check. Vector should be allocated before this update */
+ if ((rte_index > ios->num_rte) ||
+ ((vec > IA64_FIRST_DEVICE_VECTOR) &&
+ (vec < IA64_LAST_DEVICE_VECTOR) &&
+ (!test_bit(vec - IA64_FIRST_DEVICE_VECTOR, ia64_vector_mask))))
+ return -EINVAL;
+
+ gsi = ios->gsi_base + rte_index;
+ info = &iosapic_intr_info[vec];
+ spin_lock_irqsave(&irq_descp(vec)->lock, flags);
+ spin_lock(&iosapic_lock);
+ if (!gsi_vector_to_rte(gsi, vec)) {
+ register_intr(gsi, vec, IOSAPIC_LOWEST_PRIORITY,
+ rte.lo.polarity, rte.lo.trigger);
+ } else if (vector_is_shared(vec)) {
+ if ((info->trigger != rte.lo.trigger) ||
+ (info->polarity != rte.lo.polarity)) {
+ printk("WARN: can't override shared interrupt vec\n");
+ printk("IOSAPIC/PIN = (%d/%d), ori = 0x%x, new = 0x%x\n",
+ id, rte_index, info->low32, rte.val);
+ spin_unlock(&iosapic_lock);
+ spin_unlock_irqrestore(&irq_descp(vec)->lock, flags);
+ return -EINVAL;
+ }
+
+ /* If the vector is shared and already unmasked for other
+ * interrupt sources, don't mask it.
+ *
+ * Same check may also apply to single gsi pin, which may
+ * be shared by devices belonging to different domain. But
+ * let's see how to act later on demand.
+ */
+ if (!(info->low32 & IOSAPIC_MASK))
+ rte.lo.mask = 0;
+ }
+
+ /* time to update physical RTE */
+ dest = cpu_physical_id(smp_processor_id());
+ high32 = (dest << IOSAPIC_DEST_SHIFT);
+ iosapic_write(iosapic_lists[id].addr, reg + 1, high32);
+ iosapic_write(iosapic_lists[id].addr, reg, rte.val);
+ info->low32 = rte.val;
+ info->dest = dest;
+ spin_unlock(&iosapic_lock);
+ spin_unlock_irqrestore(&irq_descp(vec)->lock, flags);
+ return 0;
+}
+#endif /* XEN */
};
EXPORT_SYMBOL(isa_irq_to_vector_map);
+#ifdef XEN
+unsigned long ia64_vector_mask[BITS_TO_LONGS(IA64_NUM_DEVICE_VECTORS)];
+#else
static unsigned long ia64_vector_mask[BITS_TO_LONGS(IA64_NUM_DEVICE_VECTORS)];
+#endif
int
assign_irq_vector (int irq)
#include <linux/efi.h>
#include <linux/mmzone.h>
#include <asm/io.h>
-//#include <asm/iosapic.h>
+#include <asm/iosapic.h>
#include <asm/machvec.h>
#include <asm/page.h>
#include <asm/system.h>
#ifdef CONFIG_ACPI_BOOT
#define ACPI_MAX_PLATFORM_INTERRUPTS 256
-#define NR_IOSAPICS 4
-#if 0
/* Array to record platform interrupt vectors for generic interrupt routing. */
int platform_intr_list[ACPI_MAX_PLATFORM_INTERRUPTS] = {
[0 ... ACPI_MAX_PLATFORM_INTERRUPTS - 1] = -1
printk(KERN_ERR "acpi_request_vector(): invalid interrupt type\n");
return vector;
}
-#endif
+
char *
__acpi_map_table (unsigned long phys_addr, unsigned long size)
{
acpi_table_print_madt_entry(header);
-#if 0
iosapic_init(iosapic->address, iosapic->global_irq_base);
-#endif
return 0;
}
acpi_table_entry_header *header, const unsigned long end)
{
struct acpi_table_plat_int_src *plintsrc;
-#if 0
int vector;
-#endif
plintsrc = (struct acpi_table_plat_int_src *) header;
acpi_table_print_madt_entry(header);
-#if 0
/*
* Get vector assignment for this interrupt, set attributes,
* and program the IOSAPIC routing table.
(plintsrc->flags.trigger == 1) ? IOSAPIC_EDGE : IOSAPIC_LEVEL);
platform_intr_list[plintsrc->type] = vector;
-#endif
return 0;
}
acpi_table_print_madt_entry(header);
-#if 0
iosapic_override_isa_irq(p->bus_irq, p->global_irq,
(p->flags.polarity == 1) ? IOSAPIC_POL_HIGH : IOSAPIC_POL_LOW,
(p->flags.trigger == 1) ? IOSAPIC_EDGE : IOSAPIC_LEVEL);
-#endif
return 0;
}
#else
has_8259 = acpi_madt->flags.pcat_compat;
#endif
-#if 0
iosapic_system_init(has_8259);
-#endif
/* Get base address of IPI Message Block */
#include <public/event_channel.h>
#include <public/memory.h>
#include <public/sched.h>
+#include <xen/irq.h>
+#include <asm/hw_irq.h>
+#include <public/physdev.h>
extern unsigned long translate_domain_mpaddr(unsigned long);
+static long do_physdev_op(GUEST_HANDLE(physdev_op_t) uop);
/* FIXME: where these declarations should be there ? */
extern int dump_privop_counts_to_user(char *, int);
extern int zero_privop_counts_to_user(char *, int);
(hypercall_t)do_event_channel_op,
(hypercall_t)do_xen_version,
(hypercall_t)do_console_io,
- (hypercall_t)do_ni_hypercall, /* do_physdev_op */
+ (hypercall_t)do_physdev_op, /* do_physdev_op */
(hypercall_t)do_grant_table_op, /* 20 */
(hypercall_t)do_ni_hypercall, /* do_vm_assist */
(hypercall_t)do_ni_hypercall, /* do_update_va_mapping_otherdomain */
regs->r8 = do_event_channel_op(guest_handle_from_ptr(regs->r14, evtchn_op_t));
break;
+ case __HYPERVISOR_physdev_op:
+ regs->r8 = do_physdev_op(guest_handle_from_ptr(regs->r14,
+ physdev_op_t));
+ break;
+
case __HYPERVISOR_grant_table_op:
regs->r8 = do_grant_table_op((unsigned int) regs->r14,
guest_handle_from_ptr(regs->r15, void),
else
return xen_hypercall (regs);
}
+
+/* Need make this function common */
+extern int
+iosapic_guest_read(
+ unsigned long physbase, unsigned int reg, u32 *pval);
+extern int
+iosapic_guest_write(
+ unsigned long physbase, unsigned int reg, u32 pval);
+
+static long do_physdev_op(GUEST_HANDLE(physdev_op_t) uop)
+{
+ struct physdev_op op;
+ long ret;
+ int irq;
+
+ if ( unlikely(copy_from_guest(&op, uop, 1) != 0) )
+ return -EFAULT;
+
+ switch ( op.cmd )
+ {
+ case PHYSDEVOP_IRQ_UNMASK_NOTIFY:
+ ret = pirq_guest_unmask(current->domain);
+ break;
+
+ case PHYSDEVOP_IRQ_STATUS_QUERY:
+ irq = op.u.irq_status_query.irq;
+ ret = -EINVAL;
+ if ( (irq < 0) || (irq >= NR_IRQS) )
+ break;
+ op.u.irq_status_query.flags = 0;
+ /* Edge-triggered interrupts don't need an explicit unmask downcall. */
+ if ( !strstr(irq_desc[irq_to_vector(irq)].handler->typename, "edge") )
+ op.u.irq_status_query.flags |= PHYSDEVOP_IRQ_NEEDS_UNMASK_NOTIFY;
+ ret = 0;
+ break;
+
+ case PHYSDEVOP_APIC_READ:
+ ret = -EPERM;
+ if ( !IS_PRIV(current->domain) )
+ break;
+ ret = iosapic_guest_read(
+ op.u.apic_op.apic_physbase,
+ op.u.apic_op.reg,
+ &op.u.apic_op.value);
+ break;
+
+ case PHYSDEVOP_APIC_WRITE:
+ ret = -EPERM;
+ if ( !IS_PRIV(current->domain) )
+ break;
+ ret = iosapic_guest_write(
+ op.u.apic_op.apic_physbase,
+ op.u.apic_op.reg,
+ op.u.apic_op.value);
+ break;
+
+ case PHYSDEVOP_ASSIGN_VECTOR:
+ if ( !IS_PRIV(current->domain) )
+ return -EPERM;
+
+ if ( (irq = op.u.irq_op.irq) >= NR_IRQS )
+ return -EINVAL;
+
+ op.u.irq_op.vector = assign_irq_vector(irq);
+ ret = 0;
+ break;
+
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ if ( copy_to_guest(uop, &op, 1) )
+ ret = -EFAULT;
+
+ return ret;
+}
#include <linux/slab.h>
#include <linux/ctype.h>
#include <linux/init.h>
-#include <linux/irq.h>
#include <linux/seq_file.h>
#include <asm/atomic.h>
#include <asm/uaccess.h>
#include <asm/pgalloc.h>
#include <asm/delay.h>
-#include <asm/irq.h>
+#include <xen/irq.h>
+#include <asm/hw_irq.h>
#include <xen/event.h>
-#define _irq_desc irq_desc
-#define irq_descp(irq) &irq_desc[irq]
#define apicid_to_phys_cpu_present(x) 1
/*
/*
* Controller mappings for all interrupt sources:
*/
-irq_desc_t _irq_desc[NR_IRQS] __cacheline_aligned = {
+irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned = {
[0 ... NR_IRQS-1] = {
.status = IRQ_DISABLED | IRQ_GUEST,
.handler = &no_irq_type,
#undef nop
#endif
-/* nop for now */
-static inline void
-set_irq_affinity_info(unsigned int irq, int hwid, int redir) {}
-
+struct rte_entry {
+ union {
+ struct {
+ u32 vector : 8,
+ delivery_mode : 3,
+ dest_mode : 1, /* always 0 for iosapic */
+ delivery_status : 1,
+ polarity : 1,
+ __reserved0 : 1,
+ trigger : 1,
+ mask : 1,
+ __reserved1 : 15;
+ } lo;
+ struct {
+ u32 __reserved2 : 16,
+ eid : 8,
+ id : 8;
+ } hi;
+ u32 val;
+ };
+};
+
+#define IOSAPIC_RTEINDEX(reg) (((reg) - 0x10) >> 1)
+extern unsigned long ia64_vector_mask[];
#endif /* XEN */
# endif /* !__ASSEMBLY__ */