patch-2.4.22 linux-2.4.22/arch/s390/kernel/setup.c
Next file: linux-2.4.22/arch/s390/mm/init.c
Previous file: linux-2.4.22/arch/s390/kernel/s390_ksyms.c
Back to the patch index
Back to the overall index
- Lines: 179
- Date:
2003-08-25 04:44:40.000000000 -0700
- Orig file:
linux-2.4.21/arch/s390/kernel/setup.c
- Orig date:
2003-06-13 07:51:32.000000000 -0700
diff -urN linux-2.4.21/arch/s390/kernel/setup.c linux-2.4.22/arch/s390/kernel/setup.c
@@ -56,7 +56,117 @@
unsigned long cpu_initialized = 0;
volatile int __cpu_logical_map[NR_CPUS]; /* logical cpu to cpu address */
-void* *pfix_table=NULL;
+unsigned long *pfix_table;
+unsigned int __global_storage_key;
+
+unsigned int get_storage_key(void) { return __global_storage_key; }
+
+unsigned long pfix_get_page_addr(void *addr)
+{
+ if (!MACHINE_HAS_PFIX)
+ return (unsigned long) addr;
+
+ return pfix_table[(unsigned long)virt_to_phys(addr)>>PAGE_SHIFT];
+}
+
+unsigned long pfix_get_addr(void *addr)
+{
+ if (!MACHINE_HAS_PFIX)
+ return (unsigned long) addr;
+
+ return pfix_get_page_addr(addr) + ((unsigned long)addr&(PAGE_SIZE-1));
+}
+
+/*
+ * These functions allow to lock and unlock pages in VM. They need
+ * the absolute address of the page to be locked or unlocked. This will
+ * only work if the diag98 option in the user directory is enabled for
+ * the guest.
+ */
+
+/* if result is 0, addr will become the host absolute address */
+static inline int pfix_lock_page(void *addr)
+{
+ int ret;
+
+ __asm__ __volatile__(
+ " sske %1,%2\n" /* set storage key */
+ " l 0,0(%1)\n" /* addr into gpr 0 */
+ " lhi 2,0\n" /* function code is 0 */
+ " diag 2,0,0x98\n" /* result in gpr 1 */
+ " jnz 0f\n"
+ " lhi %0,0\n" /* if cc=0: return 0 */
+ " st 1,0(%1)\n" /* gpr1 contains host absol. addr */
+ " j 1f\n"
+ "0: lr %0,1\n" /* gpr1 contains error code */
+ " sske %1,2\n" /* reset storage key */
+ "1:\n"
+ : "=d" (ret), "+d" ((unsigned long)addr) : "d" (__global_storage_key)
+ : "0", "1", "2", "cc" );
+ return ret;
+}
+
+static inline void pfix_unlock_page(unsigned long addr)
+{
+ __asm__ __volatile__(
+ " lr 0,%0\n" /* parameter in gpr 0 */
+ " lhi 2,4\n" /* function code is 4 */
+ " diag 2,0,0x98\n" /* result in gpr 1 */
+ " sske %0,%1\n"
+ : : "a" (addr), "d" (0)
+ : "0", "1", "2", "cc" );
+}
+
+static void unpfix_all_pages(void)
+{
+ unsigned long i;
+
+ if (!pfix_table)
+ return;
+
+ for (i=0; i<sizeof(pfix_table); i++) {
+ if (pfix_table[i]) {
+ pfix_unlock_page(i << PAGE_SHIFT);
+ }
+ }
+}
+
+static void pfix_all_pages(unsigned long start_pfn, unsigned long max_pfn)
+{
+ unsigned long i,r;
+ unsigned long size;
+
+ size = ((max_pfn - start_pfn) >> PAGE_SHIFT) * sizeof(long);
+ pfix_table = alloc_bootmem(size);
+ if (!pfix_table)
+ return;
+
+ __global_storage_key = 6 << 4;
+ for (i = 0; i < 16 && memory_chunk[i].size > 0; i++) {
+ unsigned long start;
+
+ for(start = memory_chunk[i].addr;
+ (start < memory_chunk[i].addr + memory_chunk[i].size &&
+ start < max_pfn); start += PAGE_SIZE) {
+ unsigned long index;
+
+ index = start >> PAGE_SHIFT;
+ pfix_table[index] = start;
+ r = pfix_lock_page(&pfix_table[index]);
+ if (r) {
+ pfix_table[index] = 0;
+ unpfix_all_pages();
+ free_bootmem((unsigned long)pfix_table, size);
+ machine_flags &= ~128; /* MACHINE_HAS_PFIX=0 */
+ __global_storage_key = 0;
+ printk(KERN_WARNING "Error enabling PFIX at "
+ "address 0x%08lx.\n", start);
+ return;
+ }
+ }
+ }
+ printk (KERN_INFO "PFIX enabled.\n");
+}
/*
* Setup options
@@ -303,11 +413,12 @@
unsigned long memory_start, memory_end;
char c = ' ', cn, *to = command_line, *from = COMMAND_LINE;
struct resource *res;
- unsigned long start_pfn, end_pfn;
+ unsigned long start_pfn, end_pfn, max_pfn=0;
static unsigned int smptrap=0;
unsigned long delay = 0;
struct _lowcore *lowcore;
int i;
+ static int use_pfix;
if (smptrap)
return;
@@ -380,6 +491,14 @@
/* now wait for the requested amount of time */
udelay(delay);
}
+ /*
+ * "use_pfix" specifies whether we want to fix all pages,
+ * if possible.
+ */
+ if (c == ' ' && strncmp(from, "use_pfix", 8) == 0) {
+ use_pfix = 1;
+ from += 8;
+ }
cn = *(from++);
if (!cn)
break;
@@ -394,6 +513,10 @@
break;
*(to++) = c;
}
+
+ if (!use_pfix)
+ machine_flags &= ~128; /* MACHINE_HAS_PFIX = 0 */
+
if (c == ' ' && to > command_line) to--;
*to = '\0';
*cmdline_p = command_line;
@@ -429,6 +552,8 @@
if (start_chunk < end_chunk)
free_bootmem(start_chunk << PAGE_SHIFT,
(end_chunk - start_chunk) << PAGE_SHIFT);
+ if (start_chunk + memory_chunk[i].size > max_pfn)
+ max_pfn = start_chunk + memory_chunk[i].size;
}
/*
@@ -487,6 +612,10 @@
*/
paging_init();
+ if (MACHINE_HAS_PFIX)
+ /* max_pfn may be smaller than memory_end. */
+ pfix_all_pages(start_pfn, max_pfn);
+
res = alloc_bootmem_low(sizeof(struct resource));
res->start = 0;
res->end = memory_end;
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)