[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [IA64] Add support to physdev_ops
# 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
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |