[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


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.