diff options
Diffstat (limited to 'drivers/char/mem.c')
-rw-r--r-- | drivers/char/mem.c | 67 |
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 |