# HG changeset patch
# User awilliam@xxxxxxxxxxx
# Node ID de2dc4e7966ab6e43ca8ce4405cf48306a3f1ff0
# Parent eab6fd4949f0bd40656a435cc7b0af47b9a91e88
[IA64] Add support to physdev_ops
Add support to physdev ops, and thus give IOSAPIC RTEs
managed by Xen now. Dom0 now issues hypercall to r/w
RTE entry. Another change is the irq vector allocation
which is also owned by xen now.
After this change, the IOSAPIC is almost owned by xen
with only exception as IOSAPIC EOI which is still issued
by dom0 directly. But that's OK since currently dom0
owns all external physical devices. Later full event
channel mechanism will provide necessary support for
driver domain, and at that time, dom0 instead issues
physdev_op (PHYSDEVOP_IRQ_UNMASK_NOTIFY) naturally as
replace of IOSAPIC EOI.
Signed-off-by Kevin Tian <kevin.tian@xxxxxxxxx>
diff -r eab6fd4949f0 -r de2dc4e7966a
linux-2.6-xen-sparse/arch/ia64/kernel/iosapic.c
--- a/linux-2.6-xen-sparse/arch/ia64/kernel/iosapic.c Fri Apr 21 08:56:34
2006 -0600
+++ b/linux-2.6-xen-sparse/arch/ia64/kernel/iosapic.c Fri Apr 21 09:03:19
2006 -0600
@@ -140,6 +140,68 @@ static int iosapic_kmalloc_ok;
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
*/
@@ -953,6 +1015,10 @@ iosapic_system_init (int system_pcat_com
}
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
diff -r eab6fd4949f0 -r de2dc4e7966a
linux-2.6-xen-sparse/arch/ia64/kernel/irq_ia64.c
--- a/linux-2.6-xen-sparse/arch/ia64/kernel/irq_ia64.c Fri Apr 21 08:56:34
2006 -0600
+++ b/linux-2.6-xen-sparse/arch/ia64/kernel/irq_ia64.c Fri Apr 21 09:03:19
2006 -0600
@@ -66,6 +66,11 @@ assign_irq_vector (int irq)
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;
diff -r eab6fd4949f0 -r de2dc4e7966a
linux-2.6-xen-sparse/include/asm-ia64/iosapic.h
--- a/linux-2.6-xen-sparse/include/asm-ia64/iosapic.h Fri Apr 21 08:56:34
2006 -0600
+++ b/linux-2.6-xen-sparse/include/asm-ia64/iosapic.h Fri Apr 21 09:03:19
2006 -0600
@@ -53,6 +53,7 @@
#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);
@@ -64,6 +65,7 @@ static inline void iosapic_write(char __
writel(reg, iosapic + IOSAPIC_REG_SELECT);
writel(val, iosapic + IOSAPIC_WINDOW);
}
+#endif
static inline void iosapic_eoi(char __iomem *iosapic, u32 vector)
{
diff -r eab6fd4949f0 -r de2dc4e7966a xen/arch/ia64/linux-xen/iosapic.c
--- a/xen/arch/ia64/linux-xen/iosapic.c Fri Apr 21 08:56:34 2006 -0600
+++ b/xen/arch/ia64/linux-xen/iosapic.c Fri Apr 21 09:03:19 2006 -0600
@@ -1118,3 +1118,114 @@ static int __init iosapic_enable_kmalloc
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 */
diff -r eab6fd4949f0 -r de2dc4e7966a xen/arch/ia64/linux-xen/irq_ia64.c
--- a/xen/arch/ia64/linux-xen/irq_ia64.c Fri Apr 21 08:56:34 2006 -0600
+++ b/xen/arch/ia64/linux-xen/irq_ia64.c Fri Apr 21 09:03:19 2006 -0600
@@ -60,7 +60,11 @@ __u8 isa_irq_to_vector_map[16] = {
};
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)
diff -r eab6fd4949f0 -r de2dc4e7966a xen/arch/ia64/xen/acpi.c
--- a/xen/arch/ia64/xen/acpi.c Fri Apr 21 08:56:34 2006 -0600
+++ b/xen/arch/ia64/xen/acpi.c Fri Apr 21 09:03:19 2006 -0600
@@ -44,7 +44,7 @@
#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>
@@ -121,9 +121,7 @@ acpi_get_sysname (void)
#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
@@ -147,7 +145,7 @@ acpi_request_vector (u32 int_type)
printk(KERN_ERR "acpi_request_vector(): invalid interrupt
type\n");
return vector;
}
-#endif
+
char *
__acpi_map_table (unsigned long phys_addr, unsigned long size)
{
@@ -253,9 +251,7 @@ acpi_parse_iosapic (acpi_table_entry_hea
acpi_table_print_madt_entry(header);
-#if 0
iosapic_init(iosapic->address, iosapic->global_irq_base);
-#endif
return 0;
}
@@ -265,9 +261,7 @@ acpi_parse_plat_int_src (
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;
@@ -276,7 +270,6 @@ acpi_parse_plat_int_src (
acpi_table_print_madt_entry(header);
-#if 0
/*
* Get vector assignment for this interrupt, set attributes,
* and program the IOSAPIC routing table.
@@ -290,7 +283,6 @@ acpi_parse_plat_int_src (
(plintsrc->flags.trigger == 1)
? IOSAPIC_EDGE : IOSAPIC_LEVEL);
platform_intr_list[plintsrc->type] = vector;
-#endif
return 0;
}
@@ -308,11 +300,9 @@ acpi_parse_int_src_ovr (
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;
}
@@ -364,9 +354,7 @@ acpi_parse_madt (unsigned long phys_addr
#else
has_8259 = acpi_madt->flags.pcat_compat;
#endif
-#if 0
iosapic_system_init(has_8259);
-#endif
/* Get base address of IPI Message Block */
diff -r eab6fd4949f0 -r de2dc4e7966a xen/arch/ia64/xen/hypercall.c
--- a/xen/arch/ia64/xen/hypercall.c Fri Apr 21 08:56:34 2006 -0600
+++ b/xen/arch/ia64/xen/hypercall.c Fri Apr 21 09:03:19 2006 -0600
@@ -21,8 +21,12 @@
#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);
@@ -51,7 +55,7 @@ hypercall_t ia64_hypercall_table[] =
(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 */
@@ -87,6 +91,11 @@ xen_hypercall (struct pt_regs *regs)
case __HYPERVISOR_event_channel_op:
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:
@@ -282,3 +291,80 @@ ia64_hypercall (struct pt_regs *regs)
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;
+}
diff -r eab6fd4949f0 -r de2dc4e7966a xen/arch/ia64/xen/irq.c
--- a/xen/arch/ia64/xen/irq.c Fri Apr 21 08:56:34 2006 -0600
+++ b/xen/arch/ia64/xen/irq.c Fri Apr 21 09:03:19 2006 -0600
@@ -33,7 +33,6 @@
#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>
@@ -44,11 +43,10 @@
#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
/*
@@ -70,7 +68,7 @@
/*
* 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,
diff -r eab6fd4949f0 -r de2dc4e7966a
xen/include/asm-ia64/linux-xen/asm/iosapic.h
--- a/xen/include/asm-ia64/linux-xen/asm/iosapic.h Fri Apr 21 08:56:34
2006 -0600
+++ b/xen/include/asm-ia64/linux-xen/asm/iosapic.h Fri Apr 21 09:03:19
2006 -0600
@@ -134,10 +134,30 @@ static inline void list_move(struct list
#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__ */
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|