summaryrefslogtreecommitdiffstats
path: root/drivers/char/mem.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/char/mem.c')
-rw-r--r--drivers/char/mem.c67
1 files changed, 56 insertions, 11 deletions
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index 6eaa07d23..47ae0706f 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -51,7 +51,16 @@ extern void mda_console_init(void);
#if defined(CONFIG_PPC) || defined(CONFIG_MAC)
extern void adbdev_init(void);
#endif
-
+#ifdef CONFIG_USB_UHCI
+int uhci_init(void);
+#endif
+#ifdef CONFIG_USB_OHCI
+int ohci_init(void);
+#endif
+#ifdef CONFIG_USB_OHCI_HCD
+int ohci_hcd_init(void);
+#endif
+
static ssize_t do_write_mem(struct file * file, void *p, unsigned long realp,
const char * buf, size_t count, loff_t *ppos)
{
@@ -138,8 +147,11 @@ static ssize_t write_mem(struct file * file, const char * buf,
static inline unsigned long pgprot_noncached(unsigned long prot)
{
#if defined(__i386__)
+ /* On PPro and successors, PCD alone doesn't always mean
+ uncached because of interactions with the MTRRs. PCD | PWT
+ means definitely uncached. */
if (boot_cpu_data.x86 > 3)
- prot |= _PAGE_PCD;
+ prot |= _PAGE_PCD | _PAGE_PWT;
#elif defined(__powerpc__)
prot |= _PAGE_NO_CACHE | _PAGE_GUARDED;
#elif defined(__mc68000__)
@@ -155,6 +167,28 @@ static inline unsigned long pgprot_noncached(unsigned long prot)
return prot;
}
+/*
+ * Architectures vary in how they handle caching for addresses
+ * outside of main memory.
+ */
+static inline int noncached_address(unsigned long addr)
+{
+#if defined(__i386__)
+ /*
+ * On the PPro and successors, the MTRRs are used to set
+ * memory types for physical addresses outside main memory,
+ * so blindly setting PCD or PWT on those pages is wrong.
+ * For Pentiums and earlier, the surround logic should disable
+ * caching for the high addresses through the KEN pin, but
+ * we maintain the tradition of paranoia in this code.
+ */
+ return !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR)
+ && addr >= __pa(high_memory);
+#else
+ return addr >= __pa(high_memory);
+#endif
+}
+
static int mmap_mem(struct file * file, struct vm_area_struct * vma)
{
unsigned long offset = vma->vm_offset;
@@ -166,20 +200,20 @@ static int mmap_mem(struct file * file, struct vm_area_struct * vma)
* Accessing memory above the top the kernel knows about or
* through a file pointer that was marked O_SYNC will be
* done non-cached.
- *
- * Set VM_IO, as this is likely a non-cached access to an
- * I/O area, and we don't want to include that in a core
- * file.
*/
- if (offset >= __pa(high_memory) || (file->f_flags & O_SYNC)) {
- pgprot_val(vma->vm_page_prot) = pgprot_noncached(pgprot_val(vma->vm_page_prot));
+ if (noncached_address(offset) || (file->f_flags & O_SYNC))
+ pgprot_val(vma->vm_page_prot)
+ = pgprot_noncached(pgprot_val(vma->vm_page_prot));
+
+ /*
+ * Don't dump addresses that are not real memory to a core file.
+ */
+ if (offset >= __pa(high_memory) || (file->f_flags & O_SYNC))
vma->vm_flags |= VM_IO;
- }
+
if (remap_page_range(vma->vm_start, offset, vma->vm_end-vma->vm_start,
vma->vm_page_prot))
return -EAGAIN;
- vma->vm_file = file;
- file->f_count++;
return 0;
}
@@ -574,6 +608,17 @@ __initfunc(int chr_dev_init(void))
if (register_chrdev(MEM_MAJOR,"mem",&memory_fops))
printk("unable to get major %d for memory devs\n", MEM_MAJOR);
rand_initialize();
+#ifdef CONFIG_USB
+#ifdef CONFIG_USB_UHCI
+ uhci_init();
+#endif
+#ifdef CONFIG_USB_OHCI
+ ohci_init();
+#endif
+#ifdef CONFIG_USB_OHCI_HCD
+ ohci_hcd_init();
+#endif
+#endif
#if defined (CONFIG_FB)
fbmem_init();
#endif