Slowmem support - turn uncacheable mem into ramdisk

Pavel Machek (pavel@elf.ucw.cz)
Mon, 9 Mar 1998 22:03:03 +0100


Hi!

This patch (relative to 2.1.89) helps systems with uncacheable (->
slow) memory. It adds one config time switch (sorry for strange
placement) and command line option.

It is based on 2.0 patch by keryan@andrew.cmu.edu. Is such kludge for
broken (but frequent) hw acceptable in standart tree? What should be
done to get it in?

By specifying fastmem=123M mem=456M, you say that all memory between
123 and 456M is slow, should not be used for normal purposes, and
should be mapped as /dev/slram. You can then mkswap-it and swapon-it.

Pavel

--- clean/arch/i386/config.in Thu Feb 12 12:32:56 1998
+++ linux/arch/i386/config.in Mon Mar 9 13:49:32 1998
@@ -64,6 +48,11 @@

endmenu

+mainmenu_option next_comment
+comment 'Processor type and features'
+bool 'Use slow memory as a ramdisk' CONFIG_BLK_DEV_SLRAM
+endmenu
+
source drivers/pnp/Config.in

source drivers/block/Config.in
--- clean/arch/i386/kernel/setup.c Sun Mar 8 12:49:53 1998
+++ linux/arch/i386/kernel/setup.c Mon Mar 9 17:33:54 1998
@@ -29,7 +31,7 @@
#ifdef CONFIG_APM
#include <linux/apm_bios.h>
#endif
-#ifdef CONFIG_BLK_DEV_RAM
+#if defined(CONFIG_BLK_DEV_RAM) || defined(CONFIG_BLK_DEV_SLRAM)
#include <linux/blk.h>
#endif
#include <asm/uaccess.h>
@@ -42,6 +44,10 @@

char ignore_irq13 = 0; /* set if exception 16 works */
struct cpuinfo_x86 boot_cpu_data = { 0, 0, 0, 0, -1, 1, 0, 0, -1 };
+#ifdef CONFIG_BLK_DEV_SLRAM
+int end_fast_mem = 0; /* end of fast memory - in case something
+ is not cached this is interesting */
+#endif

/*
* Bus types ..
@@ -184,6 +190,21 @@
}
}
}
+#ifdef CONFIG_BLK_DEV_SLRAM
+ if (c == ' ' && *(const unsigned long *)from == *(const unsigned long *)"fastmem=") {
+ if (to != command_line) to--;
+ {
+ end_fast_mem = simple_strtoul(from+8, &from, 0);
+ if ( *from == 'K' || *from == 'k' ) {
+ end_fast_mem = end_fast_mem << 10;
+ from++;
+ } else if ( *from == 'M' || *from == 'm' ) {
+ end_fast_mem = end_fast_mem << 20;
+ from++;
+ }
+ }
+ }
+#endif
c = *(from++);
if (!c)
break;
@@ -193,6 +214,18 @@
}
*to = '\0';
*cmdline_p = command_line;
+#ifdef CONFIG_BLK_DEV_SLRAM
+ if (!end_fast_mem)
+ end_fast_mem = memory_end;
+ if (!slram_size && (memory_end > end_fast_mem)) {
+ slram_size = memory_end - end_fast_mem;
+ printk("RAM above %luk declared slow, reserving %luk for slram\n", end_fast_mem >>10, slram_size >>10 );
+ slram_phys = end_fast_mem;
+ } else {
+ slram_phys = 0;
+ }
+ slram_virt = 0;
+#endif
memory_end += PAGE_OFFSET;
*memory_start_p = memory_start;
*memory_end_p = memory_end;
--- clean/arch/i386/mm/init.c Wed Jan 14 21:45:29 1998
+++ linux/arch/i386/mm/init.c Mon Mar 9 17:47:28 1998
@@ -31,6 +31,9 @@

extern void die_if_kernel(char *,struct pt_regs *,long);
extern void show_net_buffers(void);
+#ifdef CONFIG_BLK_DEV_SLRAM
+extern int end_fast_mem;
+#endif

/*
* BAD_PAGE is the page that is used for page faults when linux
@@ -337,11 +342,17 @@
start_low_mem += PAGE_SIZE;
}

- while (start_mem < end_mem) {
+ while (start_mem <
+#ifdef CONFIG_BLK_DEV_SLRAM
+ ((end_fast_mem+PAGE_OFFSET) & PAGE_MASK)
+#else
+ end_mem
+#endif
+ ) {
clear_bit(PG_reserved, &mem_map[MAP_NR(start_mem)].flags);
start_mem += PAGE_SIZE;
}
- for (tmp = PAGE_OFFSET ; tmp < end_mem ; tmp += PAGE_SIZE) {
+ for (tmp = end_mem - PAGE_SIZE; tmp >= PAGE_OFFSET ; tmp -= PAGE_SIZE) {
if (tmp >= MAX_DMA_ADDRESS)
clear_bit(PG_DMA, &mem_map[MAP_NR(tmp)].flags);
if (PageReserved(mem_map+MAP_NR(tmp))) {
--- clean/drivers/block/ll_rw_blk.c Sun Mar 8 12:49:55 1998
+++ linux/drivers/block/ll_rw_blk.c Mon Mar 9 13:46:53 1998
@@ -797,6 +854,9 @@
#endif
#ifdef CONFIG_DDV
ddv_init();
+#endif
+#ifdef CONFIG_BLK_DEV_SLRAM
+ slram_init();
#endif
return 0;
};
--- clean/include/linux/blk.h Sun Mar 8 12:49:34 1998
+++ linux/include/linux/blk.h Mon Mar 9 13:46:09 1998
@@ -139,6 +142,12 @@
extern int ps2esdi_init(void);
#endif

+#ifdef CONFIG_BLK_DEV_SLRAM
+extern unsigned long slram_size, slram_phys, slram_virt;
+void slram_init(void);
+void slram_unregister(void);
+#endif
+
#define RO_IOCTLS(dev,where) \
case BLKROSET: { int __val; if (!suser()) return -EACCES; \
if (get_user(__val, (int *)(where))) return -EFAULT; \
--- /dev/null Sun Jun 2 15:30:20 1996
+++ linux/drivers/block/slram.c Mon Mar 9 17:40:06 1998
@@ -0,0 +1,190 @@
+/*
+ * slram (slow RAM): a way to use large amounts of RAM on 486 and Pentium
+ * systems without slowing the system down. Reserves all RAM above a specified
+ * amount for a special ramdisk. Takes advantage of Larry Augustin's RAM
+ * detection patch (BIOS int 15h, ah=c7h returns amount of cached RAM; support
+ * for this in slram is untested, however)
+ *
+ * written by Brad Keryan <keryan@andrew.cmu.edu>
+ *
+ * Heavily based on z2ram by Ingo Wilken
+ * (Ingo.Wilken@informatik.uni-oldenburg.de) and on
+ * drivers/block/rd.c. Also drivers/block/ide.c.
+ */
+
+/* the original z2ram copyright is as follows: */
+/* Copyright (C) 1994 by Ingo Wilken (Ingo.Wilken@informatik.uni-oldenburg.de)
+**
+** Permission to use, copy, modify, and distribute this software and its
+** documentation for any purpose and without fee is hereby granted, provided
+** that the above copyright notice appear in all copies and that both that
+** copyright notice and this permission notice appear in supporting
+** documentation. This software is provided "as is" without express or
+** implied warranty.
+*/
+
+
+#include <linux/config.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/malloc.h>
+#include <linux/ioctl.h>
+#include <linux/fd.h>
+#include <linux/module.h>
+
+#include <asm/system.h>
+#include <asm/segment.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+/* note: this is a very unofficial major number. Maybe would sharing
+z2ram's major number be a good idea? After all, this driver is
+i386-only and z2ram is m68k-only . . . */
+#ifndef SLRAM_MAJOR
+#define SLRAM_MAJOR 123
+#endif
+
+#define MAJOR_NR SLRAM_MAJOR
+#define MINOR_NR 0
+#define DEVICE_NAME "slram"
+#define DEVICE_REQUEST do_slram_request
+#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_ON(device)
+#define DEVICE_OFF(device)
+#define DEVICE_NO_RANDOM
+
+#include <linux/blk.h>
+
+#define BLKSIZE 1024
+
+unsigned long slram_size = 0, slram_phys, slram_virt;
+
+static int slram_blksizes[1]; /* only one device is possible right now */
+
+static void do_slram_request (void)
+{
+ unsigned int minor;
+ unsigned int offset, len;
+
+ repeat:
+ INIT_REQUEST;
+
+ minor = MINOR(CURRENT->rq_dev);
+ if (minor != MINOR_NR) {
+ end_request(0);
+ goto repeat;
+ }
+
+ offset = CURRENT->sector << 9;
+ len = CURRENT->current_nr_sectors << 9;
+
+ if ((offset + len) > slram_size) {
+ end_request(0);
+ goto repeat;
+ }
+
+ switch(CURRENT->cmd) {
+ case READ :
+ memcpy(CURRENT->buffer, (char *) slram_virt + offset, len);
+ break;
+ case WRITE :
+ memcpy((char *) slram_virt + offset, CURRENT->buffer, len);
+ break;
+ default :
+ printk("do_slram_request: unknown command\n");
+ }
+ end_request(1);
+ goto repeat;
+}
+
+static int slram_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ /* more or less copied from rd.c */
+ int err;
+
+ /* printk(KERN_NOTICE "slram ioctl(0x%x, 0x%x)\n", cmd,
+ arg); */
+
+ if (!inode || !inode->i_rdev)
+ return -EINVAL;
+
+ switch (cmd) {
+ case BLKFLSBUF:
+ if (!suser()) return -EACCES;
+ invalidate_buffers(inode->i_rdev);
+ break;
+ case BLKGETSIZE: /* Return device size */
+ if (!arg) return -EINVAL;
+ err = verify_area(VERIFY_WRITE, (long *) arg,
+ sizeof(long));
+ if (err)
+ return err;
+ put_user(slram_size / 512, (long *) arg);
+ return 0;
+ default:
+ break;
+ };
+
+ return 0;
+}
+
+static int slram_open(struct inode *inode, struct file *file)
+{
+ if (MINOR(inode->i_rdev) != MINOR_NR)
+ return -ENXIO;
+
+ /* perhaps this driver could be modularized */
+ /* maybe use mem=64M and then specify the memory range for the module
+ to use */
+ /* MOD_INC_USE_COUNT? */
+ return 0;
+}
+
+static int slram_release(struct inode *inode, struct file *file)
+{
+ /* MOD_DEC_USE_COUNT? */
+ return 0;
+}
+
+static struct file_operations slram_fops = {
+ NULL, /* lseek - default */
+ block_read, /* read - general block-dev read */
+ block_write, /* write - general block-dev write */
+ NULL, /* readdir - bad */
+ NULL, /* select */
+ slram_ioctl, /* ioctl */
+ NULL, /* mmap */
+ slram_open, /* open */
+ slram_release, /* release */
+ block_fsync, /* fsync */
+};
+
+void slram_init(void)
+{
+ if (register_blkdev(MAJOR_NR, DEVICE_NAME, &slram_fops)) {
+ printk("Unable to allocate major %d for slram\n",
+ MAJOR_NR);
+ return;
+ }
+ blk_dev[MAJOR_NR].request_fn = do_slram_request;
+ slram_blksizes[MINOR_NR] = BLKSIZE;
+ blksize_size[MAJOR_NR] = slram_blksizes;
+ slram_virt = (unsigned long) __va(slram_phys);
+ printk("Slow RAM %luk-%luk mapped to %lx for slram disk\n",
+ (slram_phys)>>10,
+ (slram_phys + slram_size)>>10,
+ slram_virt );
+}
+
+void slram_unregister(void)
+{
+ unregister_blkdev(MAJOR_NR, DEVICE_NAME);
+
+ blk_dev[MAJOR_NR].request_fn = NULL;
+ blksize_size[MAJOR_NR] = NULL;
+}
+

-- 
I'm really pavel@atrey.karlin.mff.cuni.cz. 	   Pavel
Look at http://atrey.karlin.mff.cuni.cz/~pavel/ ;-).

- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu