[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-ia64-devel] [PATCH] Extended I/O port space support
This version doesn't have any significant functional changes from the RFC I sent out before. I just wanted to provide an opportunity to comment before I check it in. See here for a complete description: http://lists.xensource.com/archives/html/xen-ia64-devel/2007-06/msg00087.html Thanks, Alex Signed-off-by: Alex Williamson <alex.williamson@xxxxxx> --- diff -r 0cf6b75423e9 linux-2.6-xen-sparse/arch/ia64/pci/pci.c --- a/linux-2.6-xen-sparse/arch/ia64/pci/pci.c Mon Jun 04 14:17:54 2007 -0600 +++ b/linux-2.6-xen-sparse/arch/ia64/pci/pci.c Sun Jun 10 12:12:33 2007 -0600 @@ -164,6 +164,11 @@ new_space (u64 phys_base, int sparse) i = num_io_spaces++; io_space[i].mmio_base = mmio_base; io_space[i].sparse = sparse; + +#ifdef CONFIG_XEN + if (is_initial_xendomain()) + HYPERVISOR_add_io_space(phys_base, sparse, i); +#endif return i; } diff -r 0cf6b75423e9 linux-2.6-xen-sparse/include/asm-ia64/hypercall.h --- a/linux-2.6-xen-sparse/include/asm-ia64/hypercall.h Mon Jun 04 14:17:54 2007 -0600 +++ b/linux-2.6-xen-sparse/include/asm-ia64/hypercall.h Thu Jun 07 08:37:01 2007 -0600 @@ -387,6 +387,15 @@ xencomm_arch_hypercall_fpswa_revision(st { return _hypercall2(int, ia64_dom0vp_op, IA64_DOM0VP_fpswa_revision, arg); +} + +static inline int +HYPERVISOR_add_io_space(unsigned long phys_base, + unsigned long sparse, + unsigned long space_number) +{ + return _hypercall4(int, ia64_dom0vp_op, IA64_DOM0VP_add_io_space, + phys_base, sparse, space_number); } // for balloon driver diff -r 0cf6b75423e9 xen/arch/ia64/xen/dom0_ops.c --- a/xen/arch/ia64/xen/dom0_ops.c Mon Jun 04 14:17:54 2007 -0600 +++ b/xen/arch/ia64/xen/dom0_ops.c Sat Jun 09 14:18:21 2007 -0600 @@ -363,6 +363,40 @@ dom0vp_fpswa_revision(XEN_GUEST_HANDLE(u return 0; } +static unsigned long +dom0vp_add_io_space(struct domain *d, unsigned long phys_base, + unsigned long sparse, unsigned long space_number) +{ + unsigned int fp, lp; + + /* + * Registering new io_space roughly based on linux + * arch/ia64/pci/pci.c:new_space() + */ + + /* Skip legacy I/O port space, we already know about it */ + if (phys_base == 0) + return 0; + + /* + * Dom0 Linux initializes io spaces sequentially, if that changes, + * we'll need to add thread protection and the ability to handle + * a sparsely populated io_space array. + */ + if (space_number > MAX_IO_SPACES || space_number != num_io_spaces) + return -EINVAL; + + io_space[space_number].mmio_base = phys_base; + io_space[space_number].sparse = sparse; + + num_io_spaces++; + + fp = space_number << IO_SPACE_BITS; + lp = fp | 0xffff; + + return ioports_permit_access(d, fp, lp); +} + unsigned long do_dom0vp_op(unsigned long cmd, unsigned long arg0, unsigned long arg1, unsigned long arg2, @@ -419,6 +453,9 @@ do_dom0vp_op(unsigned long cmd, ret = dom0vp_fpswa_revision(hnd); break; } + case IA64_DOM0VP_add_io_space: + ret = dom0vp_add_io_space(d, arg0, arg1, arg2); + break; default: ret = -1; printk("unknown dom0_vp_op 0x%lx\n", cmd); diff -r 0cf6b75423e9 xen/arch/ia64/xen/mm.c --- a/xen/arch/ia64/xen/mm.c Mon Jun 04 14:17:54 2007 -0600 +++ b/xen/arch/ia64/xen/mm.c Sat Jun 09 15:53:50 2007 -0600 @@ -886,81 +886,144 @@ assign_domain_page(struct domain *d, } int -ioports_permit_access(struct domain *d, unsigned long fp, unsigned long lp) -{ +ioports_permit_access(struct domain *d, unsigned int fp, unsigned int lp) +{ + struct io_space *space; + unsigned long mmio_start, mmio_end, mach_start; int ret; - unsigned long off; - unsigned long fp_offset; - unsigned long lp_offset; - + + if (IO_SPACE_NR(fp) >= num_io_spaces) { + dprintk(XENLOG_WARNING, "Unknown I/O Port range 0x%x - 0x%x\n", fp, lp); + return -EFAULT; + } + + /* + * The ioport_cap rangeset tracks the I/O port address including + * the port space ID. This means port space IDs need to match + * between Xen and dom0. This is also a requirement because + * the hypercall to pass these port ranges only uses a u32. + * + * NB - non-dom0 driver domains may only have a subset of the + * I/O port spaces and thus will number port spaces differently. + * This is ok, they don't make use of this interface. + */ ret = rangeset_add_range(d->arch.ioport_caps, fp, lp); if (ret != 0) return ret; - /* Domain 0 doesn't virtualize IO ports space. */ - if (d == dom0) + space = &io_space[IO_SPACE_NR(fp)]; + + /* Legacy I/O on dom0 is already setup */ + if (d == dom0 && space == &io_space[0]) return 0; - fp_offset = IO_SPACE_SPARSE_ENCODING(fp) & ~PAGE_MASK; - lp_offset = PAGE_ALIGN(IO_SPACE_SPARSE_ENCODING(lp)); - - for (off = fp_offset; off <= lp_offset; off += PAGE_SIZE) - (void)__assign_domain_page(d, IO_PORTS_PADDR + off, - __pa(ia64_iobase) + off, ASSIGN_nocache); + fp = IO_SPACE_PORT(fp); + lp = IO_SPACE_PORT(lp); + + if (space->sparse) { + mmio_start = IO_SPACE_SPARSE_ENCODING(fp) & ~PAGE_MASK; + mmio_end = PAGE_ALIGN(IO_SPACE_SPARSE_ENCODING(lp)); + } else { + mmio_start = fp & ~PAGE_MASK; + mmio_end = PAGE_ALIGN(lp); + } + + /* + * The "machine first port" is not necessarily identity mapped + * to the guest first port. At least for the legacy range. + */ + mach_start = mmio_start | __pa(space->mmio_base); + + if (space == &io_space[0]) { + mmio_start |= IO_PORTS_PADDR; + mmio_end |= IO_PORTS_PADDR; + } else { + mmio_start |= __pa(space->mmio_base); + mmio_end |= __pa(space->mmio_base); + } + + while (mmio_start <= mmio_end) { + (void)__assign_domain_page(d, mmio_start, mach_start, ASSIGN_nocache); + mmio_start += PAGE_SIZE; + mach_start += PAGE_SIZE; + } return 0; } static int -ioports_has_allowed(struct domain *d, unsigned long fp, unsigned long lp) -{ - unsigned long i; - for (i = fp; i < lp; i++) - if (rangeset_contains_singleton(d->arch.ioport_caps, i)) +ioports_has_allowed(struct domain *d, unsigned int fp, unsigned int lp) +{ + for (; fp < lp; fp++) + if (rangeset_contains_singleton(d->arch.ioport_caps, fp)) return 1; + return 0; } int -ioports_deny_access(struct domain *d, unsigned long fp, unsigned long lp) +ioports_deny_access(struct domain *d, unsigned int fp, unsigned int lp) { int ret; struct mm_struct *mm = &d->arch.mm; - unsigned long off; - unsigned long io_ports_base; - unsigned long fp_offset; - unsigned long lp_offset; + unsigned long mmio_start, mmio_end, mmio_base; + unsigned int fp_base, lp_base; + struct io_space *space; + + if (IO_SPACE_NR(fp) >= num_io_spaces) { + dprintk(XENLOG_WARNING, "Unknown I/O Port range 0x%x - 0x%x\n", fp, lp); + return -EFAULT; + } ret = rangeset_remove_range(d->arch.ioport_caps, fp, lp); if (ret != 0) return ret; - if (d == dom0) - io_ports_base = __pa(ia64_iobase); + + space = &io_space[IO_SPACE_NR(fp)]; + fp_base = IO_SPACE_PORT(fp); + lp_base = IO_SPACE_PORT(lp); + + if (space->sparse) { + mmio_start = IO_SPACE_SPARSE_ENCODING(fp_base) & ~PAGE_MASK; + mmio_end = PAGE_ALIGN(IO_SPACE_SPARSE_ENCODING(lp_base)); + } else { + mmio_start = fp_base & ~PAGE_MASK; + mmio_end = PAGE_ALIGN(lp_base); + } + + if (space == &io_space[0] && d != dom0) + mmio_base = IO_PORTS_PADDR; else - io_ports_base = IO_PORTS_PADDR; - - fp_offset = IO_SPACE_SPARSE_ENCODING(fp) & PAGE_MASK; - lp_offset = PAGE_ALIGN(IO_SPACE_SPARSE_ENCODING(lp)); - - for (off = fp_offset; off < lp_offset; off += PAGE_SIZE) { - unsigned long mpaddr = io_ports_base + off; - unsigned long port; + mmio_base = __pa(space->mmio_base); + + for (; mmio_start < mmio_end; mmio_start += PAGE_SIZE) { + unsigned int port, range; + unsigned long mpaddr; volatile pte_t *pte; pte_t old_pte; - port = IO_SPACE_SPARSE_DECODING (off); - if (port < fp || port + IO_SPACE_SPARSE_PORTS_PER_PAGE - 1 > lp) { + if (space->sparse) { + port = IO_SPACE_SPARSE_DECODING(mmio_start); + range = IO_SPACE_SPARSE_PORTS_PER_PAGE - 1; + } else { + port = mmio_start; + range = PAGE_SIZE - 1; + } + + port |= IO_SPACE_BASE(IO_SPACE_NR(fp)); + + if (port < fp || port + range > lp) { /* Maybe this covers an allowed port. */ - if (ioports_has_allowed(d, port, - port + IO_SPACE_SPARSE_PORTS_PER_PAGE - 1)) + if (ioports_has_allowed(d, port, port + range)) continue; } + mpaddr = mmio_start | mmio_base; pte = lookup_noalloc_domain_pte_none(d, mpaddr); BUG_ON(pte == NULL); BUG_ON(pte_none(*pte)); - // clear pte + /* clear pte */ old_pte = ptep_get_and_clear(mm, mpaddr, pte); } domain_flush_vtlb_all(d); diff -r 0cf6b75423e9 xen/include/asm-ia64/iocap.h --- a/xen/include/asm-ia64/iocap.h Mon Jun 04 14:17:54 2007 -0600 +++ b/xen/include/asm-ia64/iocap.h Thu Jun 07 15:57:30 2007 -0600 @@ -8,9 +8,9 @@ #define __IA64_IOCAP_H__ extern int ioports_permit_access(struct domain *d, - unsigned long s, unsigned long e); + unsigned int s, unsigned int e); extern int ioports_deny_access(struct domain *d, - unsigned long s, unsigned long e); + unsigned int s, unsigned int e); #define ioports_access_permitted(d, s, e) \ rangeset_contains_range((d)->arch.ioport_caps, s, e) diff -r 0cf6b75423e9 xen/include/public/arch-ia64.h --- a/xen/include/public/arch-ia64.h Mon Jun 04 14:17:54 2007 -0600 +++ b/xen/include/public/arch-ia64.h Wed Jun 06 16:52:17 2007 -0600 @@ -526,6 +526,9 @@ DEFINE_XEN_GUEST_HANDLE(vcpu_guest_conte /* get fpswa revision */ #define IA64_DOM0VP_fpswa_revision 10 +/* Add an I/O port space range */ +#define IA64_DOM0VP_add_io_space 11 + // flags for page assignement to pseudo physical address space #define _ASSIGN_readonly 0 #define ASSIGN_readonly (1UL << _ASSIGN_readonly) _______________________________________________ Xen-ia64-devel mailing list Xen-ia64-devel@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-ia64-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |