# HG changeset patch
# User Jimi Xenidis <[EMAIL PROTECTED]>
# Node ID 985be3a2501b2d29c0848746080a8cff7931165a
# Parent  fb97509af21b244a68637810768820adb13759ee
[LINUX][XEN][POWERPC] Xen specific interfaces for grant tables

These interfaces allow for the use of grant tables for XenPPC to
support BLOCK VIO. They use the Foriegn Map work to allow driver
domains to map granted pages and use the in the block IO layer.  It
ever works with the IOMMU routines.

Signed-off-by: Jimi Xenidis <[EMAIL PROTECTED]>
---
 arch/powerpc/platforms/xen/Makefile |   13 +
 arch/powerpc/platforms/xen/gnttab.c |  297 ++++++++++++++++++++++++++++++++++++
 arch/powerpc/platforms/xen/hcall.c  |   45 -----
 arch/powerpc/platforms/xen/setup.h  |    2 
 4 files changed, 311 insertions(+), 46 deletions(-)

diff -r fb97509af21b -r 985be3a2501b arch/powerpc/platforms/xen/Makefile
--- a/arch/powerpc/platforms/xen/Makefile       Sun Oct 08 12:44:47 2006 -0400
+++ b/arch/powerpc/platforms/xen/Makefile       Sun Oct 08 12:48:24 2006 -0400
@@ -1,4 +1,11 @@ obj-y  += setup.o evtchn.o hcall.o udbg_x
-obj-y  += setup.o evtchn.o hcall.o udbg_xen.o xen_guest.o reboot.o xencomm.o
+obj-y  += evtchn.o
+obj-y  += gnttab.o
+obj-y  += hcall.o
+obj-y  += reboot.o
+obj-y  += setup.o
+obj-y  += udbg_xen.o
+obj-y  += xen_guest.o
+obj-y  += xencomm.o
 
 # we need the latest __XEN_INTERFACE_VERSION__ (see xen-compat.h)
 CFLAGS_hcall.o += -D__XEN_TOOLS__
@@ -6,3 +13,7 @@ ifndef CONFIG_XEN_BALLOON
 ifndef CONFIG_XEN_BALLOON
 obj-y += balloon.o
 endif
+
+ifndef CONFIG_XEN_UTIL
+obj-y  += util.o
+endif
diff -r fb97509af21b -r 985be3a2501b arch/powerpc/platforms/xen/hcall.c
--- a/arch/powerpc/platforms/xen/hcall.c        Sun Oct 08 12:44:47 2006 -0400
+++ b/arch/powerpc/platforms/xen/hcall.c        Sun Oct 08 12:48:24 2006 -0400
@@ -41,8 +41,6 @@
 #include <asm/hvcall.h>
 #include "setup.h"
 
-#define xen_guest_handle(hnd)  ((hnd).p)
-
 /* Xencomm notes:
  *
  * For kernel memory, we assume that virtually contiguous pages are also
@@ -137,49 +135,6 @@ int HYPERVISOR_physdev_op(int cmd, void 
                                cmd, desc);
 }
 EXPORT_SYMBOL(HYPERVISOR_physdev_op);
-
-int HYPERVISOR_grant_table_op(unsigned int cmd, void *op, unsigned int count)
-{
-       void *desc;
-       void *frame_list;
-       int argsize;
-
-       switch (cmd) {
-       case GNTTABOP_map_grant_ref:
-               argsize = sizeof(struct gnttab_map_grant_ref);
-               break;
-       case GNTTABOP_unmap_grant_ref:
-               argsize = sizeof(struct gnttab_unmap_grant_ref);
-               break;
-       case GNTTABOP_setup_table: {
-               struct gnttab_setup_table setup;
-
-               memcpy(&setup, op, sizeof(setup));
-               argsize = sizeof(setup);
-
-               frame_list = 
xencomm_create_inline(xen_guest_handle(setup.frame_list));
-
-               set_xen_guest_handle(setup.frame_list, frame_list);
-               memcpy(op, &setup, sizeof(setup));
-               }
-               break;
-       case GNTTABOP_dump_table:
-               argsize = sizeof(struct gnttab_dump_table);
-               break;
-       case GNTTABOP_transfer:
-               argsize = sizeof(struct gnttab_transfer);
-               break;
-       default:
-               printk(KERN_ERR "%s: unknown grant table op %d\n", __func__, 
cmd);
-               return -ENOSYS;
-       }
-
-       desc = xencomm_create_inline(op);
-
-       return plpar_hcall_norets(XEN_MARK(__HYPERVISOR_grant_table_op), cmd,
-                       desc, count);
-}
-EXPORT_SYMBOL(HYPERVISOR_grant_table_op);
 
 int HYPERVISOR_sched_op(int cmd, void *arg)
 {
diff -r fb97509af21b -r 985be3a2501b arch/powerpc/platforms/xen/setup.h
--- a/arch/powerpc/platforms/xen/setup.h        Sun Oct 08 12:44:47 2006 -0400
+++ b/arch/powerpc/platforms/xen/setup.h        Sun Oct 08 12:48:24 2006 -0400
@@ -19,3 +19,5 @@ static inline u64 jiffies_to_ns(unsigned
 {
        return j * (1000000000UL / HZ);
 }
+
+#define xen_guest_handle(hnd)  ((hnd).p)
diff -r fb97509af21b -r 985be3a2501b arch/powerpc/platforms/xen/gnttab.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/arch/powerpc/platforms/xen/gnttab.c       Sun Oct 08 12:48:24 2006 -0400
@@ -0,0 +1,297 @@
+
+#include <linux/config.h>
+#include <linux/vmalloc.h>
+#include <linux/memory_hotplug.h>
+#include <xen/gnttab.h>
+#include <asm/hypervisor.h>
+#include <xen/interface/grant_table.h>
+#include <asm/pgtable.h>
+#include <asm/sections.h>
+#include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/prom.h>
+#include <asm/cacheflush.h>
+#include "setup.h"
+#include "../pseries/plpar_wrappers.h"
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(fmt...) printk(KERN_EMERG fmt)
+#else
+#define DBG(fmt...)
+#endif
+
+static ulong foreign_map_base;
+static ulong foreign_map_end;
+
+static long map_to_linear(ulong paddr)
+{
+       unsigned long vaddr;
+       int psize;
+       unsigned long mode;
+       int slot;
+       uint shift;
+       unsigned long tmp_mode;
+
+       psize = MMU_PAGE_4K;
+       shift = mmu_psize_defs[psize].shift;
+       mode = _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_COHERENT | PP_RWXX;
+       vaddr = (ulong)__va(paddr);
+
+       {
+               unsigned long vpn, hash, hpteg;
+               unsigned long vsid = get_kernel_vsid(vaddr);
+               unsigned long va = (vsid << 28) | (vaddr & 0x0fffffff);
+
+               vpn = va >> shift;
+               tmp_mode = mode;
+               
+               /* Make non-kernel text non-executable */
+               if (!in_kernel_text(vaddr))
+                       tmp_mode = mode | HPTE_R_N;
+
+               hash = hpt_hash(va, shift);
+               hpteg = ((hash & htab_hash_mask) * HPTES_PER_GROUP);
+
+               BUG_ON(!ppc_md.hpte_insert);
+               slot = ppc_md.hpte_insert(hpteg, va, paddr,
+                                         tmp_mode, HPTE_V_BOLTED, psize);
+               BUG_ON(slot < 0);
+       }
+       return slot;
+}
+
+static void gnttab_post_map_grant_ref(
+       struct gnttab_map_grant_ref *map, int count)
+{
+       int i;
+       long slot;
+
+       for (i = 0 ; i < count; i++) {
+               ulong pa = map[i].dev_bus_addr;
+               BUG_ON(pa < foreign_map_base || pa >= foreign_map_end);
+
+               slot = map_to_linear(pa);
+               /* store the slot somewhere */
+               map[i].host_addr = (ulong)__va(pa);
+       }
+}
+
+static unsigned long get_hpte_vsid(ulong slot)
+{
+       unsigned long dword0;
+       unsigned long lpar_rc;
+       unsigned long dummy_word1;
+       unsigned long flags;
+
+       /* Read 1 pte at a time                        */
+       /* Do not need RPN to logical page translation */
+       /* No cross CEC PFT access                     */
+       flags = 0;
+
+       lpar_rc = plpar_pte_read(flags, slot, &dword0, &dummy_word1);
+
+       BUG_ON(lpar_rc != H_SUCCESS);
+
+       return dword0;
+}
+
+static long find_hpte_slot(unsigned long va, int psize)
+{
+       unsigned long hash;
+       unsigned long i, j;
+       long slot;
+       unsigned long want_v, hpte_v;
+
+       hash = hpt_hash(va, mmu_psize_defs[psize].shift);
+       want_v = hpte_encode_v(va, psize);
+
+       for (j = 0; j < 2; j++) {
+               slot = (hash & htab_hash_mask) * HPTES_PER_GROUP;
+               for (i = 0; i < HPTES_PER_GROUP; i++) {
+                       hpte_v = get_hpte_vsid(slot);
+
+                       if (HPTE_V_COMPARE(hpte_v, want_v)
+                           && (hpte_v & HPTE_V_VALID)
+                           && (!!(hpte_v & HPTE_V_SECONDARY) == j)) {
+                               /* HPTE matches */
+                               if (j)
+                                       slot = -slot;
+                               return slot;
+                       }
+                       ++slot;
+               }
+               hash = ~hash;
+       }
+
+       return -1;
+} 
+
+static void gnttab_pre_unmap_grant_ref(
+       struct gnttab_unmap_grant_ref *unmap, int count)
+{
+       long slot;
+       ulong vsid;
+       ulong va;
+       int psize = MMU_PAGE_4K;
+       int i;
+       ulong ea;
+       unsigned long dummy1, dummy2;
+
+       for (i = 0 ; i < count; i++) {
+               ea = unmap[i].host_addr;
+               vsid = get_kernel_vsid(ea);
+               va = (vsid << 28) | (ea & 0x0fffffff);
+
+               slot = find_hpte_slot(va, psize);
+               BUG_ON(slot < 0);
+
+               plpar_pte_remove(0, slot, 0, &dummy1, &dummy2);
+
+               DBG("%s: remove_pages(0x%lx, 0x%lx)\n",
+                   __func__, unmap[i].host_addr, unmap[i].dev_bus_addr);
+       }
+}
+
+int HYPERVISOR_grant_table_op(unsigned int cmd, void *op, unsigned int count)
+{
+       void *desc;
+       void *frame_list;
+       int argsize;
+       int ret;
+
+       switch (cmd) {
+       case GNTTABOP_map_grant_ref:
+               argsize = sizeof(struct gnttab_map_grant_ref);
+               break;
+       case GNTTABOP_unmap_grant_ref:
+               gnttab_pre_unmap_grant_ref(op, count);
+               argsize = sizeof(struct gnttab_unmap_grant_ref);
+               break;
+       case GNTTABOP_setup_table: {
+               struct gnttab_setup_table setup;
+
+               memcpy(&setup, op, sizeof(setup));
+               argsize = sizeof(setup);
+
+               frame_list = 
xencomm_create_inline(xen_guest_handle(setup.frame_list));
+
+               set_xen_guest_handle(setup.frame_list, frame_list);
+               memcpy(op, &setup, sizeof(setup));
+               }
+               break;
+       case GNTTABOP_dump_table:
+               argsize = sizeof(struct gnttab_dump_table);
+               break;
+       case GNTTABOP_transfer:
+               argsize = sizeof(struct gnttab_transfer);
+               break;
+       default:
+               printk(KERN_EMERG "%s: unknown grant table op %d\n",
+                      __func__, cmd);
+               return -ENOSYS;
+       }
+
+       desc = xencomm_create_inline(op);
+
+       ret = plpar_hcall_norets(XEN_MARK(__HYPERVISOR_grant_table_op), cmd,
+                                desc, count);
+       if (cmd == GNTTABOP_map_grant_ref)
+               gnttab_post_map_grant_ref(op, count);
+
+       return ret;
+}
+EXPORT_SYMBOL(HYPERVISOR_grant_table_op);
+
+unsigned long alloc_empty_foreign_map_page_range(unsigned long pages)
+{
+       return (ulong)__va(foreign_map_base);
+}
+
+static ulong setup_grant_maps(void)
+{
+       struct device_node *xen;
+       u64 *gm;
+       u64 _gm[2];
+       u64 expect;
+
+       /* This value is currently hardcoded into the SLB logic that
+        * it written in assempler, See
+        * slb_miss_kernel_load_xen_linear for more information.
+        * Anything else and we can not run. */
+       expect = 34 - PAGE_SHIFT;
+
+       xen = of_find_node_by_path("/xen");
+
+       /* 
+        * The foreign is 2x2 Cells.
+         * The first entry is log2 of the base page frame.
+        * The second is the number of pages
+        */
+       gm = (u64 *)get_property(xen, "foreign-map", NULL);
+       if (gm == NULL) {
+               if (!is_initial_xendomain()) {
+                       printk("OF: /xen/foreign-map not present\n");
+                       _gm[0] = expect;
+                       _gm[1] = 1UL << expect;
+                       gm = _gm;
+               } else
+                       panic("OF: /xen/foreign-map must be present\n");
+       }
+
+       if (gm[0] != expect)
+               panic("foreign-map is 0x%lx, expect 0x%lx\n",
+                     gm[0], expect);
+
+       foreign_map_base = 1UL << (gm[0] + PAGE_SHIFT);
+       foreign_map_end = foreign_map_base + (gm[1] << PAGE_SHIFT);
+
+       return gm[1];
+}
+
+static int add_grant_pages(ulong pfn, ulong pgs)
+{
+       struct zone *zone;
+       struct pglist_data *pgdata;
+       int nid;
+       extern int *slb_miss_kernel_load_xen_nop;
+       ulong iaddr = (ulong)slb_miss_kernel_load_xen_nop;
+
+       /* By default Linux will branch around this logic we replace
+        * the branch with a NOP to turn the logic on */
+       *slb_miss_kernel_load_xen_nop = 0x60000000;
+       flush_icache_range(iaddr, iaddr + 4);
+
+       /* add pages to the zone */
+       nid = 0;
+       pgdata = NODE_DATA(nid);
+       zone = pgdata->node_zones;
+
+       /* add pages to the zone */
+       return  __add_pages(zone, pfn, pgs);
+}
+
+int arch_gnttab_suspend(volatile void __iomem *shared)
+{
+       iounmap(shared);
+       return 0;
+}
+
+void *arch_gnttab_map(unsigned long *frames)
+{
+       void *shared;
+       ulong pa = frames[0] << PAGE_SHIFT;
+       ulong pgs;
+
+       shared = ioremap(pa, PAGE_SIZE * NR_GRANT_FRAMES);
+       BUG_ON(shared == NULL);
+       printk("%s: grant table at %p\n", __func__, shared);
+
+       pgs = setup_grant_maps();
+
+       if (is_initial_xendomain())
+               add_grant_pages(foreign_map_base >> PAGE_SHIFT, pgs);
+
+       return shared;
+}

_______________________________________________
Xen-ppc-devel mailing list
Xen-ppc-devel@lists.xensource.com
http://lists.xensource.com/xen-ppc-devel

Reply via email to