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
|