Commit 3eb6861c authored by Linus Torvalds's avatar Linus Torvalds

Import 2.2.8pre5

parent c88c0e6a
......@@ -779,14 +779,14 @@ S: Maintained
USB HUB AND UHCI DRIVERS
P: Johannes Erdfelt
M: jerdfelt@sventech.com
L: linux-usb@peloncho.fis.ucm.es
L: linux-usb@suse.com
S: Maintained
USB OHCI DRIVER
P: Gregory P. Smith
M: greg@electricrain.com
M: greg@suitenine.com
L: linux-usb@peloncho.fis.ucm.es
L: linux-usb@suse.com
S: Maintained (not yet usable)
W: http://suitenine.com/usb/
......
......@@ -141,6 +141,7 @@ asmlinkage int osf_getdirentries(unsigned int fd, struct osf_dirent *dirent,
struct inode *inode;
struct osf_dirent_callback buf;
lock_kernel();
error = -EBADF;
file = fget(fd);
if (!file)
......@@ -173,6 +174,7 @@ asmlinkage int osf_getdirentries(unsigned int fd, struct osf_dirent *dirent,
out_putf:
fput(file);
out:
unlock_kernel();
return error;
}
......
......@@ -77,12 +77,14 @@ asmlinkage int old_mmap(struct mmap_arg_struct *arg)
goto out;
if (!(a.flags & MAP_ANONYMOUS)) {
error = -EBADF;
if (a.fd >= current->files->max_fds ||
!(file = current->files->fd[a.fd]))
file = fget(a.fd);
if (!file)
goto out;
}
a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
error = do_mmap(file, a.addr, a.len, a.prot, a.flags, a.offset);
if (file)
fput(file);
out:
unlock_kernel();
return error;
......
......@@ -8,37 +8,30 @@
# Note 2! The CFLAGS definition is now in the main makefile...
all: lib first_rule
ifeq ($(MACHINE),a5k)
MMARCH=arc
else
MMARCH=$(MACHINE)
endif
O_TARGET := mm.o
O_OBJS := init.o extable.o fault-$(PROCESSOR).o mm-$(MMARCH).o
O_OBJS := init.o extable.o fault-$(PROCESSOR).o small_page.o
ifeq ($(PROCESSOR),armo)
O_OBJS += proc-arm2,3.o
endif
ifeq ($(PROCESSOR),armv)
O_OBJS += small_page.o proc-arm6,7.o proc-sa110.o
O_OBJS += mm-$(MACHINE).o proc-arm6,7.o proc-sa110.o ioremap.o
endif
include $(TOPDIR)/Rules.make
proc-arm2,3.o: ../lib/constants.h
proc-arm6,7.o: ../lib/constants.h
proc-sa110.o: ../lib/constants.h
%.o: %.S
ifneq ($(CONFIG_BINUTILS_NEW),y)
$(CC) $(CFLAGS) -D__ASSEMBLY__ -E $< | tr ';$$' '\n#' > ..$@.tmp.s
$(CC) $(CFLAGS:-pipe=) -c -o $@ ..$@.tmp.s
$(RM) ..$@.tmp.s
else
$(CC) $(CFLAGS) -D__ASSEMBLY__ -c -o $@ $<
endif
.PHONY: lib
lib:; @$(MAKE) -C ../lib constants.h
# Special dependencies
fault-armv.o: fault-common.c
fault-armo.o: fault-common.c
proc-arm2,3.o: ../lib/constants.h
proc-arm6,7.o: ../lib/constants.h
proc-sa110.o: ../lib/constants.h
/*
* linux/arch/arm/mm/fault.c
* linux/arch/arm/mm/fault-armo.c
*
* Copyright (C) 1995 Linus Torvalds
* Modifications for ARM processor (c) 1995, 1996 Russell King
* Modifications for ARM processor (c) 1995-1999 Russell King
*/
#include <linux/config.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/kernel.h>
......@@ -15,8 +14,7 @@
#include <linux/ptrace.h>
#include <linux/mman.h>
#include <linux/mm.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
#include <linux/interrupt.h>
#include <asm/system.h>
#include <asm/uaccess.h>
......@@ -27,35 +25,32 @@
#define FAULT_CODE_WRITE 0x02
#define FAULT_CODE_USER 0x01
struct pgtable_cache_struct quicklists;
#define DO_COW(m) ((m) & (FAULT_CODE_WRITE|FAULT_CODE_FORCECOW))
#define READ_FAULT(m) (!((m) & FAULT_CODE_WRITE))
void __bad_pmd(pmd_t *pmd)
#include "fault-common.c"
static void *alloc_table(int size, int prio)
{
printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
#ifdef CONFIG_DEBUG_ERRORS
__backtrace();
#endif
set_pmd(pmd, mk_pmd(BAD_PAGETABLE));
if (size != 128)
printk("invalid table size\n");
return (void *)get_page_8k(prio);
}
void __bad_pmd_kernel(pmd_t *pmd)
void free_table(void *table)
{
printk("Bad pmd in pte_alloc_kernel: %08lx\n", pmd_val(*pmd));
#ifdef CONFIG_DEBUG_ERRORS
__backtrace();
#endif
set_pmd(pmd, mk_pmd(BAD_PAGETABLE));
free_page_8k((unsigned long)table);
}
pgd_t *get_pgd_slow(void)
{
pgd_t *pgd = (pgd_t *) kmalloc(PTRS_PER_PGD * BYTES_PER_PTR, GFP_KERNEL);
pgd_t *pgd = (pgd_t *)alloc_table(PTRS_PER_PGD * BYTES_PER_PTR, GFP_KERNEL);
pgd_t *init;
if (pgd) {
init = pgd_offset(&init_mm, 0);
memzero (pgd, USER_PTRS_PER_PGD * BYTES_PER_PTR);
memcpy (pgd + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD,
memzero(pgd, USER_PTRS_PER_PGD * BYTES_PER_PTR);
memcpy(pgd + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD,
(PTRS_PER_PGD - USER_PTRS_PER_PGD) * BYTES_PER_PTR);
}
return pgd;
......@@ -65,17 +60,17 @@ pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset)
{
pte_t *pte;
pte = (pte_t *) kmalloc (PTRS_PER_PTE * BYTES_PER_PTR, GFP_KERNEL);
pte = (pte_t *)alloc_table(PTRS_PER_PTE * BYTES_PER_PTR, GFP_KERNEL);
if (pmd_none(*pmd)) {
if (pte) {
memzero (pte, PTRS_PER_PTE * BYTES_PER_PTR);
memzero(pte, PTRS_PER_PTE * BYTES_PER_PTR);
set_pmd(pmd, mk_pmd(pte));
return pte + offset;
}
set_pmd(pmd, mk_pmd(BAD_PAGETABLE));
return NULL;
}
kfree (pte);
free_table((void *)pte);
if (pmd_bad(*pmd)) {
__bad_pmd(pmd);
return NULL;
......@@ -83,126 +78,22 @@ pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset)
return (pte_t *) pmd_page(*pmd) + offset;
}
extern void die_if_kernel(char *msg, struct pt_regs *regs, unsigned int err, unsigned int ret);
static void kernel_page_fault (unsigned long addr, int mode, struct pt_regs *regs,
struct task_struct *tsk, struct mm_struct *mm)
{
/*
* Oops. The kernel tried to access some bad page. We'll have to
* terminate things with extreme prejudice.
*/
pgd_t *pgd;
if (addr < PAGE_SIZE)
printk (KERN_ALERT "Unable to handle kernel NULL pointer dereference");
else
printk (KERN_ALERT "Unable to handle kernel paging request");
printk (" at virtual address %08lx\n", addr);
printk (KERN_ALERT "current->tss.memmap = %08lX\n", tsk->tss.memmap);
pgd = pgd_offset (mm, addr);
printk (KERN_ALERT "*pgd = %08lx", pgd_val (*pgd));
if (!pgd_none (*pgd)) {
pmd_t *pmd;
pmd = pmd_offset (pgd, addr);
printk (", *pmd = %08lx", pmd_val (*pmd));
if (!pmd_none (*pmd))
printk (", *pte = %08lx", pte_val (*pte_offset (pmd, addr)));
}
printk ("\n");
die_if_kernel ("Oops", regs, mode, SIGKILL);
do_exit (SIGKILL);
}
static void
handle_dataabort (unsigned long addr, int mode, struct pt_regs *regs)
{
struct task_struct *tsk;
struct mm_struct *mm;
struct vm_area_struct *vma;
unsigned long fixup;
lock_kernel();
tsk = current;
mm = tsk->mm;
down(&mm->mmap_sem);
vma = find_vma (mm, addr);
if (!vma)
goto bad_area;
if (addr >= vma->vm_start)
goto good_area;
if (!(vma->vm_flags & VM_GROWSDOWN) || expand_stack (vma, addr))
goto bad_area;
/*
* Ok, we have a good vm_area for this memory access, so
* we can handle it..
*/
good_area:
if (!(mode & FAULT_CODE_WRITE)) { /* write? */
if (!(vma->vm_flags & (VM_READ|VM_EXEC)))
goto bad_area;
} else {
if (!(vma->vm_flags & VM_WRITE))
goto bad_area;
}
handle_mm_fault (tsk, vma, addr, mode & (FAULT_CODE_WRITE|FAULT_CODE_FORCECOW));
up(&mm->mmap_sem);
goto out;
/*
* Something tried to access memory that isn't in our memory map..
* Fix it, but check if it's kernel or user first..
*/
bad_area:
up(&mm->mmap_sem);
if (mode & FAULT_CODE_USER) {
//extern int console_loglevel;
//cli();
tsk->tss.error_code = mode;
tsk->tss.trap_no = 14;
//console_loglevel = 9;
printk ("%s: memory violation at pc=0x%08lx, lr=0x%08lx (bad address=0x%08lx, code %d)\n",
tsk->comm, regs->ARM_pc, regs->ARM_lr, addr, mode);
//#ifdef DEBUG
show_regs (regs);
c_backtrace (regs->ARM_fp, 0);
//#endif
force_sig(SIGSEGV, tsk);
//while (1);
goto out;
}
/* Are we prepared to handle this kernel fault? */
if ((fixup = search_exception_table(instruction_pointer(regs))) != 0) {
printk(KERN_DEBUG "%s: Exception at [<%lx>] addr=%lx (fixup: %lx)\n",
tsk->comm, regs->ARM_pc, addr, fixup);
regs->ARM_pc = fixup;
goto out;
}
kernel_page_fault (addr, mode, regs, tsk, mm);
out:
unlock_kernel();
}
/*
* Handle a data abort. Note that we have to handle a range of addresses
* on ARM2/3 for ldm. If both pages are zero-mapped, then we have to force
* a copy-on-write
* a copy-on-write. However, on the second page, we always force COW.
*/
asmlinkage void
do_DataAbort (unsigned long min_addr, unsigned long max_addr, int mode, struct pt_regs *regs)
do_DataAbort(unsigned long min_addr, unsigned long max_addr, int mode, struct pt_regs *regs)
{
handle_dataabort (min_addr, mode, regs);
do_page_fault(min_addr, mode, regs);
if ((min_addr ^ max_addr) >> PAGE_SHIFT)
handle_dataabort (max_addr, mode | FAULT_CODE_FORCECOW, regs);
do_page_fault(max_addr, mode | FAULT_CODE_FORCECOW, regs);
}
asmlinkage int
do_PrefetchAbort (unsigned long addr, int mode, struct pt_regs *regs)
do_PrefetchAbort(unsigned long addr, struct pt_regs *regs)
{
#if 0
if (the memc mapping for this page exists - can check now...) {
......@@ -210,6 +101,6 @@ do_PrefetchAbort (unsigned long addr, int mode, struct pt_regs *regs)
return 0;
}
#endif
handle_dataabort (addr, mode, regs);
do_page_fault(addr, FAULT_CODE_USER|FAULT_CODE_PREFETCH, regs);
return 1;
}
This diff is collapsed.
/*
* linux/arch/arm/mm/fault-common.c
*
* Copyright (C) 1995 Linus Torvalds
* Modifications for ARM processor (c) 1995-1999 Russell King
*/
#include <linux/config.h>
extern void die(char *msg, struct pt_regs *regs, unsigned int err);
void __bad_pmd(pmd_t *pmd)
{
printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
#ifdef CONFIG_DEBUG_ERRORS
__backtrace();
#endif
set_pmd(pmd, mk_user_pmd(BAD_PAGETABLE));
}
void __bad_pmd_kernel(pmd_t *pmd)
{
printk("Bad pmd in pte_alloc_kernel: %08lx\n", pmd_val(*pmd));
#ifdef CONFIG_DEBUG_ERRORS
__backtrace();
#endif
set_pmd(pmd, mk_kernel_pmd(BAD_PAGETABLE));
}
static void
kernel_page_fault(unsigned long addr, int mode, struct pt_regs *regs,
struct task_struct *tsk, struct mm_struct *mm)
{
char *reason;
/*
* Oops. The kernel tried to access some bad page. We'll have to
* terminate things with extreme prejudice.
*/
pgd_t *pgd;
if (addr < PAGE_SIZE)
reason = "NULL pointer dereference";
else
reason = "paging request";
printk(KERN_ALERT "Unable to handle kernel %s at virtual address %08lx\n",
reason, addr);
printk(KERN_ALERT "memmap = %08lX, pgd = %p\n", tsk->tss.memmap, mm->pgd);
pgd = pgd_offset(mm, addr);
printk(KERN_ALERT "*pgd = %08lx", pgd_val(*pgd));
do {
pmd_t *pmd;
pte_t *pte;
if (pgd_none(*pgd))
break;
if (pgd_bad(*pgd)) {
printk("(bad)\n");
break;
}
pmd = pmd_offset(pgd, addr);
printk(", *pmd = %08lx", pmd_val(*pmd));
if (pmd_none(*pmd))
break;
if (pmd_bad(*pmd)) {
printk("(bad)\n");
break;
}
pte = pte_offset(pmd, addr);
printk(", *pte = %08lx", pte_val(*pte));
printk(", *ppte = %08lx", pte_val(pte[-PTRS_PER_PTE]));
} while(0);
printk("\n");
die("Oops", regs, mode);
do_exit(SIGKILL);
}
static void do_page_fault(unsigned long addr, int mode, struct pt_regs *regs)
{
struct task_struct *tsk;
struct mm_struct *mm;
struct vm_area_struct *vma;
unsigned long fixup;
tsk = current;
mm = tsk->mm;
/*
* If we're in an interrupt or have no user
* context, we must not take the fault..
*/
if (in_interrupt() || mm == &init_mm)
goto no_context;
down(&mm->mmap_sem);
vma = find_vma(mm, addr);
if (!vma)
goto bad_area;
if (vma->vm_start <= addr)
goto good_area;
if (!(vma->vm_flags & VM_GROWSDOWN) || expand_stack(vma, addr))
goto bad_area;
/*
* Ok, we have a good vm_area for this memory access, so
* we can handle it..
*/
good_area:
if (READ_FAULT(mode)) { /* read? */
if (!(vma->vm_flags & (VM_READ|VM_EXEC)))
goto bad_area;
} else {
if (!(vma->vm_flags & VM_WRITE))
goto bad_area;
}
/*
* If for any reason at all we couldn't handle the fault,
* make sure we exit gracefully rather than endlessly redo
* the fault.
*/
if (!handle_mm_fault(tsk, vma, addr & PAGE_MASK, DO_COW(mode)))
goto do_sigbus;
up(&mm->mmap_sem);
return;
/*
* Something tried to access memory that isn't in our memory map..
* Fix it, but check if it's kernel or user first..
*/
bad_area:
up(&mm->mmap_sem);
/* User mode accesses just cause a SIGSEGV */
if (mode & FAULT_CODE_USER) {
tsk->tss.error_code = mode;
tsk->tss.trap_no = 14;
#ifdef CONFIG_DEBUG_USER
printk("%s: memory violation at pc=0x%08lx, lr=0x%08lx (bad address=0x%08lx, code %d)\n",
tsk->comm, regs->ARM_pc, regs->ARM_lr, addr, mode);
#endif
force_sig(SIGSEGV, tsk);
return;
}
no_context:
/* Are we prepared to handle this kernel fault? */
if ((fixup = search_exception_table(instruction_pointer(regs))) != 0) {
#ifdef DEBUG
printk(KERN_DEBUG "%s: Exception at [<%lx>] addr=%lx (fixup: %lx)\n",
tsk->comm, regs->ARM_pc, addr, fixup);
#endif
regs->ARM_pc = fixup;
return;
}
kernel_page_fault(addr, mode, regs, tsk, mm);
return;
do_sigbus:
/*
* We ran out of memory, or some other thing happened to us that made
* us unable to handle the page fault gracefully.
*/
up(&mm->mmap_sem);
/*
* Send a sigbus, regardless of whether we were in kernel
* or user mode.
*/
tsk->tss.error_code = mode;
tsk->tss.trap_no = 14;
force_sig(SIGBUS, tsk);
/* Kernel mode? Handle exceptions or die */
if (!(mode & FAULT_CODE_USER))
goto no_context;
}
......@@ -29,6 +29,9 @@
#include <asm/proc/mm-init.h>
pgd_t swapper_pg_dir[PTRS_PER_PGD];
#ifndef CONFIG_NO_PGT_CACHE
struct pgtable_cache_struct quicklists;
#endif
extern char _etext, _stext, _edata, __bss_start, _end;
extern char __init_begin, __init_end;
......@@ -36,6 +39,7 @@ extern char __init_begin, __init_end;
int do_check_pgt_cache(int low, int high)
{
int freed = 0;
#ifndef CONFIG_NO_PGT_CACHE
if(pgtable_cache_size > high) {
do {
if(pgd_quicklist)
......@@ -46,6 +50,7 @@ int do_check_pgt_cache(int low, int high)
free_pte_slow(get_pte_fast()), freed++;
} while(pgtable_cache_size > low);
}
#endif
return freed;
}
......@@ -63,17 +68,18 @@ int do_check_pgt_cache(int low, int high)
* data and COW.
*/
#if PTRS_PER_PTE != 1
unsigned long *empty_bad_page_table;
pte_t *empty_bad_page_table;
pte_t *__bad_pagetable(void)
{
int i;
pte_t bad_page;
int i;
bad_page = BAD_PAGE;
for (i = 0; i < PTRS_PER_PTE; i++)
empty_bad_page_table[i] = (unsigned long)pte_val(bad_page);
return (pte_t *) empty_bad_page_table;
set_pte(empty_bad_page_table + i, bad_page);
return empty_bad_page_table;
}
#endif
......@@ -128,8 +134,11 @@ __initfunc(unsigned long paging_init(unsigned long start_mem, unsigned long end_
empty_bad_page = (unsigned long *)start_mem;
start_mem += PAGE_SIZE;
#if PTRS_PER_PTE != 1
empty_bad_page_table = (unsigned long *)start_mem;
start_mem += PTRS_PER_PTE * sizeof (void *);
#ifdef CONFIG_CPU_32
start_mem += PTRS_PER_PTE * BYTES_PER_PTR;
#endif
empty_bad_page_table = (pte_t *)start_mem;
start_mem += PTRS_PER_PTE * BYTES_PER_PTR;
#endif
memzero (empty_zero_page, PAGE_SIZE);
start_mem = setup_pagetables (start_mem, end_mem);
......@@ -137,6 +146,9 @@ __initfunc(unsigned long paging_init(unsigned long start_mem, unsigned long end_
flush_tlb_all();
update_memc_all();
end_mem &= PAGE_MASK;
high_memory = (void *)end_mem;
return free_area_init(start_mem, end_mem);
}
......@@ -161,19 +173,18 @@ __initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem))
/* mark usable pages in the mem_map[] */
mark_usable_memory_areas(&start_mem, end_mem);
#define BETWEEN(w,min,max) ((w) >= (unsigned long)(min) && \
(w) < (unsigned long)(max))
for (tmp = PAGE_OFFSET; tmp < end_mem ; tmp += PAGE_SIZE) {
if (PageReserved(mem_map+MAP_NR(tmp))) {
if (tmp >= KERNTOPHYS(_stext) &&
tmp < KERNTOPHYS(_edata)) {
if (tmp < KERNTOPHYS(_etext))
codepages++;
else
datapages++;
} else if (tmp >= KERNTOPHYS(__init_begin)
&& tmp < KERNTOPHYS(__init_end))
if (BETWEEN(tmp, &__init_begin, &__init_end))
initpages++;
else if (tmp >= KERNTOPHYS(__bss_start)
&& tmp < (unsigned long) start_mem)
else if (BETWEEN(tmp, &_stext, &_etext))
codepages++;
else if (BETWEEN(tmp, &_etext, &_edata))
datapages++;
else if (BETWEEN(tmp, &__bss_start, start_mem))
datapages++;
else
reservedpages++;
......@@ -181,13 +192,16 @@ __initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem))
}
atomic_set(&mem_map[MAP_NR(tmp)].count, 1);
#ifdef CONFIG_BLK_DEV_INITRD
if (!initrd_start || (tmp < initrd_start || tmp >= initrd_end))
if (!initrd_start || !BETWEEN(tmp, initrd_start, initrd_end))
#endif
free_page(tmp);
}
printk ("Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data, %dk init)\n",
#undef BETWEEN
printk ("Memory: %luk/%luM available (%dk code, %dk reserved, %dk data, %dk init)\n",
(unsigned long) nr_free_pages << (PAGE_SHIFT-10),
max_mapnr << (PAGE_SHIFT-10),
max_mapnr >> (20 - PAGE_SHIFT),
codepages << (PAGE_SHIFT-10),
reservedpages << (PAGE_SHIFT-10),
datapages << (PAGE_SHIFT-10),
......@@ -203,17 +217,45 @@ __initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem))
#endif
}
void free_initmem (void)
static void free_area(unsigned long addr, unsigned long end, char *s)
{
unsigned long addr;
unsigned int size = (end - addr) >> 10;
addr = (unsigned long)(&__init_begin);
for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) {
for (; addr < end; addr += PAGE_SIZE) {
mem_map[MAP_NR(addr)].flags &= ~(1 << PG_reserved);
atomic_set(&mem_map[MAP_NR(addr)].count, 1);
free_page(addr);
}
printk ("Freeing unused kernel memory: %dk freed\n", (&__init_end - &__init_begin) >> 10);
if (size)
printk(" %dk %s", size, s);
}
void free_initmem (void)
{
printk("Freeing unused kernel memory:");
free_area((unsigned long)(&__init_begin),
(unsigned long)(&__init_end),
"init");
#ifdef CONFIG_FOOTBRIDGE
{
extern int __netwinder_begin, __netwinder_end, __ebsa285_begin, __ebsa285_end;
if (!machine_is_netwinder())
free_area((unsigned long)(&__netwinder_begin),
(unsigned long)(&__netwinder_end),
"netwinder");
if (!machine_is_ebsa285() && !machine_is_cats())
free_area((unsigned long)(&__ebsa285_begin),
(unsigned long)(&__ebsa285_end),
"ebsa285/cats");
}
#endif
printk("\n");
}
void si_meminfo(struct sysinfo *val)
......
/*
* arch/arm/mm/ioremap.c
*
* Re-map IO memory to kernel address space so that we can access it.
*
* (C) Copyright 1995 1996 Linus Torvalds
*
* Hacked for ARM by Phil Blundell <philb@gnu.org>
* Hacked to allow all architectures to build, and various cleanups
* by Russell King
*/
/*
* This allows a driver to remap an arbitrary region of bus memory into
* virtual space. One should *only* use readl, writel, memcpy_toio and
* so on with such remapped areas.
*
* Because the ARM only has a 32-bit address space we can't address the
* whole of the (physical) PCI space at once. PCI huge-mode addressing
* allows us to circumvent this restriction by splitting PCI space into
* two 2GB chunks and mapping only one at a time into processor memory.
* We use MMU protection domains to trap any attempt to access the bank
* that is not currently mapped. (This isn't fully implemented yet.)
*
* DC21285 currently has a bug in that the PCI address extension
* register affects the address of any writes waiting in the outbound
* FIFO. Unfortunately, it is not possible to tell the DC21285 to
* flush this - flushing the area causes the bus to lock.
*/
#include <linux/vmalloc.h>
#include <asm/io.h>
static inline void remap_area_pte(pte_t * pte, unsigned long address, unsigned long size,
unsigned long phys_addr, pgprot_t pgprot)
{
unsigned long end;
address &= ~PMD_MASK;
end = address + size;
if (end > PMD_SIZE)
end = PMD_SIZE;
do {
if (!pte_none(*pte))
printk("remap_area_pte: page already exists\n");
set_pte(pte, mk_pte_phys(phys_addr, pgprot));
address += PAGE_SIZE;
phys_addr += PAGE_SIZE;
pte++;
} while (address < end);
}
static inline int remap_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size,
unsigned long phys_addr, unsigned long flags)
{
unsigned long end;
pgprot_t pgprot;
address &= ~PGDIR_MASK;
end = address + size;
if (end > PGDIR_SIZE)
end = PGDIR_SIZE;
phys_addr -= address;
pgprot = __pgprot(L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY | L_PTE_WRITE | flags);
do {
pte_t * pte = pte_alloc_kernel(pmd, address);
if (!pte)
return -ENOMEM;
remap_area_pte(pte, address, end - address, address + phys_addr, pgprot);
address = (address + PMD_SIZE) & PMD_MASK;
pmd++;
} while (address < end);
return 0;
}
static int remap_area_pages(unsigned long address, unsigned long phys_addr,
unsigned long size, unsigned long flags)
{
pgd_t * dir;
unsigned long end = address + size;
phys_addr -= address;
dir = pgd_offset(&init_mm, address);
flush_cache_all();
while (address < end) {
pmd_t *pmd = pmd_alloc_kernel(dir, address);
if (!pmd)
return -ENOMEM;
if (remap_area_pmd(pmd, address, end - address,
phys_addr + address, flags))
return -ENOMEM;
set_pgdir(address, *dir);
address = (address + PGDIR_SIZE) & PGDIR_MASK;
dir++;
}
flush_tlb_all();
return 0;
}
/*
* Remap an arbitrary physical address space into the kernel virtual
* address space. Needed when the kernel wants to access high addresses
* directly.
*
* NOTE! We need to allow non-page-aligned mappings too: we will obviously
* have to convert them into an offset in a page-aligned mapping, but the
* caller shouldn't need to know that small detail.
*
* 'flags' are the extra L_PTE_ flags that you want to specify for this
* mapping. See include/asm-arm/proc-armv/pgtable.h for more information.
*/
void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags)
{
void * addr;
struct vm_struct * area;
unsigned long offset;
/*
* Mappings have to be page-aligned
*/
offset = phys_addr & ~PAGE_MASK;
size = PAGE_ALIGN(size + offset);
/*
* Don't allow mappings that wrap..
*/
if (!size || size > phys_addr + size)
return NULL;
/*
* Ok, go for it..
*/
area = get_vm_area(size);
if (!area)
return NULL;
addr = area->addr;
if (remap_area_pages(VMALLOC_VMADDR(addr), phys_addr, size, flags)) {
vfree(addr);
return NULL;
}
return (void *) (offset + (char *)addr);
}
void iounmap(void *addr)
{
return vfree((void *) (PAGE_MASK & (unsigned long) addr));
}
/*
* arch/arm/mm/mm-arc.c
*
* Extra MM routines for the Archimedes architecture
*
* Copyright (C) 1998 Russell King
*/
#include <linux/init.h>
#include <asm/hardware.h>
#include <asm/pgtable.h>
unsigned long phys_screen_end;
/*
* This routine needs more work to make it dynamically release/allocate mem!
*/
__initfunc(unsigned long map_screen_mem(unsigned long log_start, unsigned long kmem, int update))
{
static int updated = 0;
if (updated)
return 0;
updated = update;
if (update) {
unsigned long address = log_start, offset;
pgd_t *pgdp;
kmem = (kmem + 3) & ~3;
pgdp = pgd_offset (&init_mm, address); /* +31 */
offset = SCREEN_START;
while (address < SCREEN1_END) {
unsigned long addr_pmd, end_pmd;
pmd_t *pmdp;
/* if (pgd_none (*pgdp)) alloc pmd */
pmdp = pmd_offset (pgdp, address); /* +0 */
addr_pmd = address & ~PGDIR_MASK; /* 088000 */
end_pmd = addr_pmd + SCREEN1_END - address; /* 100000 */
if (end_pmd > PGDIR_SIZE)
end_pmd = PGDIR_SIZE;
do {
unsigned long addr_pte, end_pte;
pte_t *ptep;
if (pmd_none (*pmdp)) {
pte_t *new_pte = (pte_t *)kmem;
kmem += PTRS_PER_PTE * BYTES_PER_PTR;
memzero (new_pte, PTRS_PER_PTE * BYTES_PER_PTR);
set_pmd (pmdp, mk_pmd(new_pte));
}
ptep = pte_offset (pmdp, addr_pmd); /* +11 */
addr_pte = addr_pmd & ~PMD_MASK; /* 088000 */
end_pte = addr_pte + end_pmd - addr_pmd; /* 100000 */
if (end_pte > PMD_SIZE)
end_pte = PMD_SIZE;
do {
set_pte (ptep, mk_pte(offset, PAGE_KERNEL));
addr_pte += PAGE_SIZE;
offset += PAGE_SIZE;
ptep++;
} while (addr_pte < end_pte);
pmdp++;
addr_pmd = (addr_pmd + PMD_SIZE) & PMD_MASK;
} while (addr_pmd < end_pmd);
address = (address + PGDIR_SIZE) & PGDIR_MASK;
pgdp ++;
}
phys_screen_end = offset;
flush_tlb_all ();
update_memc_all ();
}
return kmem;
}
......@@ -37,7 +37,8 @@ __initfunc(unsigned long setup_io_pagetables(unsigned long start_mem))
virtual = mp->virtual;
physical = mp->physical;
length = mp->length;
prot = (mp->prot_read ? PTE_AP_READ : 0) | (mp->prot_write ? PTE_AP_WRITE : 0);
prot = (mp->prot_read ? L_PTE_USER : 0) | (mp->prot_write ? L_PTE_WRITE : 0)
| L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY;
while ((virtual & 1048575 || physical & 1048575) && length >= PAGE_SIZE) {
alloc_init_page(&start_mem, virtual, physical, mp->domain, prot);
......@@ -56,7 +57,8 @@ __initfunc(unsigned long setup_io_pagetables(unsigned long start_mem))
physical += 1048576;
}
prot = (mp->prot_read ? PTE_AP_READ : 0) | (mp->prot_write ? PTE_AP_WRITE : 0);
prot = (mp->prot_read ? L_PTE_USER : 0) | (mp->prot_write ? L_PTE_WRITE : 0)
| L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY;
while (length >= PAGE_SIZE) {
alloc_init_page(&start_mem, virtual, physical, mp->domain, prot);
......
/*
* arch/arm/mm/mm-ebsa285.c
*
* Extra MM routines for the EBSA285 architecture
*
* Copyright (C) 1998 Russell King, Dave Gilbert.
*/
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/init.h>
#include <asm/pgtable.h>
#include <asm/page.h>
#include <asm/io.h>
#include <asm/proc/mm-init.h>
#include <asm/dec21285.h>
/*
* This is to allow us to fiddle with the EEPROM
* This entry will go away in time, once the fmu
* can mmap() the flash.
*
* These ones are so that we can fiddle
* with the various cards (eg VGA)
* until we're happy with them...
*/
#define MAPPING \
{ 0xd8000000, DC21285_FLASH, 0x00400000, DOMAIN_USER, 1, 1 }, /* EEPROM */ \
{ 0xdc000000, 0x7c000000, 0x00100000, DOMAIN_USER, 1, 1 }, /* VGA */ \
{ 0xe0000000, DC21285_PCI_MEM, 0x18000000, DOMAIN_USER, 1, 1 }, /* VGA */ \
{ 0xf8000000, DC21285_PCI_TYPE_0_CONFIG, 0x01000000, DOMAIN_IO , 0, 1 }, /* Type 0 Config */ \
{ 0xf9000000, DC21285_PCI_TYPE_1_CONFIG, 0x01000000, DOMAIN_IO , 0, 1 }, /* Type 1 Config */ \
{ PCI_IACK, DC21285_PCI_IACK, 0x01000000, DOMAIN_IO , 0, 1 }, /* PCI IACK */ \
{ 0xfd000000, DC21285_OUTBOUND_WRITE_FLUSH, 0x01000000, DOMAIN_IO , 0, 1 }, /* Out wrflsh */ \
{ 0xfe000000, DC21285_ARMCSR_BASE, 0x01000000, DOMAIN_IO , 0, 1 }, /* CSR */ \
{ 0xffe00000, DC21285_PCI_IO, 0x00100000, DOMAIN_IO , 0, 1 }, /* PCI I/O */ \
{ 0xfff00000, 0x40000000, 0x00100000, DOMAIN_IO , 0, 1 }, /* X-Bus */
#include "mm-armv.c"
/*
* arch/arm/mm/mm-ebsa285.c
*
* Extra MM routines for the EBSA285 architecture
*
* Copyright (C) 1998 Russell King, Dave Gilbert.
*/
#include <linux/config.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/init.h>
#include <asm/pgtable.h>
#include <asm/page.h>
#include <asm/io.h>
#include <asm/proc/mm-init.h>
#include <asm/dec21285.h>
/*
* The first entry allows us to fiddle with the EEPROM from user-space.
* This entry will go away in time, once the fmu32 can mmap() the
* flash. It can't at the moment.
*
* If you want to fiddle with PCI VGA cards from user space, then
* change the '0, 1 }' for the PCI MEM and PCI IO to '1, 1 }'
* You can then access the PCI bus at 0xe0000000 and 0xffe00000.
*/
#ifdef CONFIG_HOST_FOOTBRIDGE
/*
* The mapping when the footbridge is in host mode.
*/
#define MAPPING \
{ FLASH_BASE, DC21285_FLASH, FLASH_SIZE, DOMAIN_IO, 0, 1 }, \
{ PCIMEM_BASE, DC21285_PCI_MEM, PCIMEM_SIZE, DOMAIN_IO, 0, 1 }, \
{ PCICFG0_BASE, DC21285_PCI_TYPE_0_CONFIG, PCICFG0_SIZE, DOMAIN_IO, 0, 1 }, \
{ PCICFG1_BASE, DC21285_PCI_TYPE_1_CONFIG, PCICFG1_SIZE, DOMAIN_IO, 0, 1 }, \
{ PCIIACK_BASE, DC21285_PCI_IACK, PCIIACK_SIZE, DOMAIN_IO, 0, 1 }, \
{ WFLUSH_BASE, DC21285_OUTBOUND_WRITE_FLUSH, WFLUSH_SIZE, DOMAIN_IO, 0, 1 }, \
{ ARMCSR_BASE, DC21285_ARMCSR_BASE, ARMCSR_SIZE, DOMAIN_IO, 0, 1 }, \
{ PCIO_BASE, DC21285_PCI_IO, PCIO_SIZE, DOMAIN_IO, 0, 1 }, \
{ XBUS_BASE, 0x40000000, XBUS_SIZE, DOMAIN_IO, 0, 1 }
#else
/*
* These two functions convert virtual addresses to PCI addresses
* and PCI addresses to virtual addresses. Note that it is only
* legal to use these on memory obtained via get_free_page or
* kmalloc.
*/
unsigned long __virt_to_bus(unsigned long res)
{
#ifdef CONFIG_DEBUG_ERRORS
if (res < PAGE_OFFSET || res >= (unsigned long)high_memory) {
printk("__virt_to_phys: invalid virtual address 0x%08lx\n", res);
__backtrace();
}
#endif
return (res - PAGE_OFFSET) + (*CSR_PCISDRAMBASE & 0xfffffff0);
}
unsigned long __bus_to_virt(unsigned long res)
{
res -= (*CSR_PCISDRAMBASE & 0xfffffff0);
res += PAGE_OFFSET;
#ifdef CONFIG_DEBUG_ERRORS
if (res < PAGE_OFFSET || res >= (unsigned long)high_memory) {
printk("__phys_to_virt: invalid virtual address 0x%08lx\n", res);
__backtrace();
}
#endif
return res;
}
/*
* The mapping when the footbridge is in add-in mode.
*/
#define MAPPING \
{ PCIO_BASE, DC21285_PCI_IO, PCIO_SIZE, DOMAIN_IO, 0, 1 }, \
{ XBUS_BASE, 0x40000000, XBUS_SIZE, DOMAIN_IO, 0, 1 }, \
{ ARMCSR_BASE, DC21285_ARMCSR_BASE, ARMCSR_SIZE, DOMAIN_IO, 0, 1 }, \
{ WFLUSH_BASE, DC21285_OUTBOUND_WRITE_FLUSH, WFLUSH_SIZE, DOMAIN_IO, 0, 1 }, \
{ FLASH_BASE, DC21285_FLASH, FLASH_SIZE, DOMAIN_IO, 0, 1 }, \
{ PCIMEM_BASE, DC21285_PCI_MEM, PCIMEM_SIZE, DOMAIN_IO, 0, 1 }
#endif
#include "mm-armv.c"
/*
* arch/arm/mm/mm-vnc.c
*
* Extra MM routines for the Corel VNC architecture
*
* Copyright (C) 1998 Russell King
*/
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/init.h>
#include <asm/pgtable.h>
#include <asm/page.h>
#include <asm/io.h>
#include <asm/proc/mm-init.h>
#include <asm/dec21285.h>
/* Table describing the MMU translation mapping
* mainly used to set up the I/O mappings.
*/
#define MAPPING \
{ 0xd0000000, DC21285_FLASH, 0x00800000, DOMAIN_IO , 0, 1 }, /* Flash */ \
{ 0xe0000000, DC21285_PCI_MEM, 0x18000000, DOMAIN_IO , 0, 1 }, /* PCI Mem */ \
{ 0xf8000000, DC21285_PCI_TYPE_0_CONFIG, 0x01000000, DOMAIN_IO , 0, 1 }, /* Type 0 Config */ \
{ 0xf9000000, DC21285_PCI_TYPE_1_CONFIG, 0x01000000, DOMAIN_IO , 0, 1 }, /* Type 1 Config */ \
{ PCI_IACK, DC21285_PCI_IACK, 0x01000000, DOMAIN_IO , 0, 1 }, /* PCI IACK */ \
{ 0xfd000000, DC21285_OUTBOUND_WRITE_FLUSH, 0x01000000, DOMAIN_IO , 0, 1 }, /* Out wrflsh */ \
{ 0xfe000000, DC21285_ARMCSR_BASE, 0x01000000, DOMAIN_IO , 0, 1 }, /* CSR */ \
{ 0xffe00000, DC21285_PCI_IO, 0x00100000, DOMAIN_IO , 0, 1 }, /* PCI I/O */ \
#include "mm-armv.c"
......@@ -193,7 +193,7 @@ _arm2_3_data_abort:
movs pc, lr
_arm2_3_check_bugs:
movs pc, lr
bics pc, lr, #0x04000000 @ Clear FIQ disable bit
/*
* Processor specific - ARM2
......@@ -206,6 +206,8 @@ LC0: .word SYMBOL_NAME(page_nr)
* Params : prev Old task structure
* : next New task structure for process to run
*
* Returns : prev
*
* Purpose : Perform a task switch, saving the old processes state, and restoring
* the new.
*
......@@ -218,15 +220,15 @@ _arm2_switch_to:
str sp, [r0, #TSS_SAVE] @ Save sp_SVC
ldr sp, [r1, #TSS_SAVE] @ Get saved sp_SVC
mov r4, r1
add r0, r1, #TSS_MEMCMAP @ Remap MEMC
add r7, r1, #TSS_MEMCMAP @ Remap MEMC
ldr r1, LC0
ldr r1, [r1]
1: ldmia r0!, {r2, r3, r5, r6}
1: ldmia r7!, {r2, r3, r5, r6}
strb r2, [r2]
strb r3, [r3]
strb r5, [r5]
strb r6, [r6]
ldmia r0!, {r2, r3, r5, r6}
ldmia r7!, {r2, r3, r5, r6}
strb r2, [r2]
strb r3, [r3]
strb r5, [r5]
......@@ -318,6 +320,8 @@ _arm2_proc_fin: movs pc, lr
* Params : prev Old task structure
* : next New task structure for process to run
*
* Returns : prev
*
* Purpose : Perform a task switch, saving the old processes state, and restoring
* the new.
*
......@@ -330,22 +334,22 @@ _arm3_switch_to:
str sp, [r0, #TSS_SAVE] @ Save sp_SVC
ldr sp, [r1, #TSS_SAVE] @ Get saved sp_SVC
mov r4, r1
add r0, r1, #TSS_MEMCMAP @ Remap MEMC
add r7, r1, #TSS_MEMCMAP @ Remap MEMC
ldr r1, LC0
ldr r1, [r1]
1: ldmia r0!, {r2, r3, r5, r6}
1: ldmia r7!, {r2, r3, r5, r6}
strb r2, [r2]
strb r3, [r3]
strb r5, [r5]
strb r6, [r6]
ldmia r0!, {r2, r3, r5, r6}
ldmia r7!, {r2, r3, r5, r6}
strb r2, [r2]
strb r3, [r3]
strb r5, [r5]
strb r6, [r6]
subs r1, r1, #8
bhi 1b
mcr p15, 0, r0, c1, c0, 0 @ flush cache
mcr p15, 0, r7, c1, c0, 0 @ flush cache
ldmfd sp!, {r4 - r9, fp, pc}^ @ Load all regs saved previously
/*
* Function: arm3_remap_memc (struct task_struct *tsk)
......
......@@ -52,13 +52,14 @@ _arm6_7_flush_tlb_area:
blt 1b
mov pc, lr
@LC0: .word _current
/*
* Function: arm6_7_switch_to (struct task_struct *prev, struct task_struct *next)
*
* Params : prev Old task structure
* : next New task structure for process to run
*
* Returns : prev
*
* Purpose : Perform a task switch, saving the old processes state, and restoring
* the new.
*
......@@ -72,15 +73,15 @@ _arm6_7_switch_to:
stmfd sp!, {ip} @ Save cpsr_SVC
str sp, [r0, #TSS_SAVE] @ Save sp_SVC
ldr sp, [r1, #TSS_SAVE] @ Get saved sp_SVC
ldr r0, [r1, #TSK_ADDR_LIMIT]
teq r0, #0
moveq r0, #DOM_KERNELDOMAIN
movne r0, #DOM_USERDOMAIN
mcr p15, 0, r0, c3, c0 @ Set domain reg
ldr r0, [r1, #TSS_MEMMAP] @ Page table pointer
ldr r2, [r1, #TSK_ADDR_LIMIT]
teq r2, #0
moveq r2, #DOM_KERNELDOMAIN
movne r2, #DOM_USERDOMAIN
mcr p15, 0, r2, c3, c0 @ Set domain reg
ldr r2, [r1, #TSS_MEMMAP] @ Page table pointer
mov r1, #0
mcr p15, 0, r1, c7, c0, 0 @ flush cache
mcr p15, 0, r0, c2, c0, 0 @ update page table ptr
mcr p15, 0, r2, c2, c0, 0 @ update page table ptr
mcr p15, 0, r1, c5, c0, 0 @ flush TLBs
ldmfd sp!, {ip}
msr spsr, ip @ Save tasks CPSR into SPSR for this return
......@@ -368,6 +369,35 @@ _arm7_set_pmd: tst r1, #3
str r1, [r0]
mov pc, lr
/*
* Function: arm6_7_set_pte(pte_t *ptep, pte_t pte)
* Params : r0 = Address to set
* : r1 = value to set
* Purpose : Set a PTE and flush it out of any WB cache
*/
.align 5
_arm6_7_set_pte:
str r1, [r0], #-1024 @ linux version
bic r2, r1, #0xff0
bic r2, r2, #3
orr r2, r2, #HPTE_TYPE_SMALL
tst r1, #LPTE_USER | LPTE_EXEC
orrne r2, r2, #HPTE_AP_READ
tst r1, #LPTE_WRITE
tstne r1, #LPTE_DIRTY
orrne r2, r2, #HPTE_AP_WRITE
tst r1, #LPTE_PRESENT
tstne r1, #LPTE_YOUNG
moveq r2, #0
str r2, [r0] @ hardware version
mcr p15, 0, r0, c7, c10, 1 @ clean D entry (drain is done by TLB fns)
mov pc, lr
/*
* Function: _arm6_7_reset
*
......@@ -405,8 +435,12 @@ ENTRY(arm6_processor_functions)
.word _arm6_7_flush_tlb_all @ 44
.word _arm6_7_flush_tlb_area @ 48
.word _arm6_set_pmd @ 52
.word _arm6_7_reset @ 54
.word _arm6_7_flush_cache @ 58
.word _arm6_7_set_pte @ 56
.word _arm6_7_reset @ 60
.word _arm6_7_flush_cache @ 64
.word _arm6_7_flush_cache @ 68
.word _arm6_7_flush_cache @ 72
/*
* Purpose : Function pointers used to access above functions - all calls
......@@ -431,8 +465,9 @@ ENTRY(arm7_processor_functions)
.word _arm6_7_flush_tlb_all @ 44
.word _arm6_7_flush_tlb_area @ 48
.word _arm7_set_pmd @ 52
.word _arm6_7_reset @ 56
.word _arm6_7_flush_cache @ 60
.word _arm6_7_set_pte @ 56
.word _arm6_7_reset @ 60
.word _arm6_7_flush_cache @ 64
.word _arm6_7_flush_cache @ 68
.word _arm6_7_flush_cache @ 72
......@@ -8,6 +8,7 @@
*/
#include <linux/linkage.h>
#include <asm/assembler.h>
#include <asm/hardware.h>
#include "../lib/constants.h"
/* This is the maximum size of an area which will be flushed. If the area
......@@ -21,7 +22,6 @@ Lclean_switch: .long 0
/*
* Function: sa110_flush_cache_all (void)
*
* Purpose : Flush all cache lines
*/
.align 5
......@@ -33,7 +33,7 @@ _sa110_flush_cache_all_r2:
ands r1, r1, #1
eor r1, r1, #1
str r1, [r3]
ldr ip, =0xdf000000
ldr ip, =FLUSH_BASE
addne ip, ip, #32768
add r1, ip, #16384 @ only necessary for 16k
1: ldr r3, [ip], #32
......@@ -47,11 +47,9 @@ _sa110_flush_cache_all_r2:
/*
* Function: sa110_flush_cache_area (unsigned long address, int end, int flags)
*
* Params : address Area start address
* : end Area end address
* : flags b0 = I cache as well
*
* Purpose : clean & flush all cache lines associated with this area of memory
*/
.align 5
......@@ -74,10 +72,8 @@ _sa110_flush_cache_area:
/*
* Function: sa110_cache_wback_area(unsigned long address, unsigned long end)
*
* Params : address Area start address
* : end Area end address
*
* Purpose : ensure all dirty cachelines in the specified area have been
* written out to memory (for DMA)
*/
......@@ -99,13 +95,10 @@ _sa110_cache_wback_area:
/*
* Function: sa110_cache_purge_area(unsigned long address, unsigned long end)
*
* Params : address Area start address
* : end Area end address
*
* Purpose : throw away all D-cached data in specified region without
* an obligation to write it ack.
*
* an obligation to write it back.
* Note : Must clean the D-cached entries around the boundaries if the
* start and/or end address are not cache aligned.
*/
......@@ -124,9 +117,7 @@ _sa110_cache_purge_area:
/*
* Function: sa110_flush_cache_entry (unsigned long address)
*
* Params : address Address of cache line to flush
*
* Purpose : clean & flush an entry
*/
.align 5
......@@ -138,24 +129,23 @@ _sa110_flush_cache_entry:
mov pc, lr
/*
* Function: sa110_flush_cache_pte (unsigned long address)
*
* Function: sa110_clean_cache_area(unsigned long start, unsigned long size)
* Params : address Address of cache line to clean
*
* Purpose : Ensure that physical memory reflects cache at this location
* for page table purposes.
*/
_sa110_flush_cache_pte:
mcr p15, 0, r0, c7, c10, 1 @ clean D entry (drain is done by TLB fns)
_sa110_clean_cache_area:
1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry (drain is done by TLB fns)
add r0, r0, #32
subs r1, r1, #32
bhi 1b
mov pc, lr
/*
* Function: sa110_flush_ram_page (unsigned long page)
*
* Params : address Area start address
* : size size of area
* : flags b0 = I cache as well
*
* Purpose : clean & flush all cache lines associated with this area of memory
*/
.align 5
......@@ -176,7 +166,6 @@ _sa110_flush_ram_page:
/*
* Function: sa110_flush_tlb_all (void)
*
* Purpose : flush all TLB entries in all caches
*/
.align 5
......@@ -188,11 +177,9 @@ _sa110_flush_tlb_all:
/*
* Function: sa110_flush_tlb_area (unsigned long address, unsigned long end, int flags)
*
* Params : address Area start address
* : end Area end address
* : flags b0 = I cache as well
*
* Purpose : flush a TLB entry
*/
.align 5
......@@ -212,22 +199,21 @@ _sa110_flush_tlb_area:
.align 5
_sa110_flush_icache_area:
mov r3, #0
1: mcr p15, 0, r0, c7, c10, 1 @ Clean D entry
add r0, r0, #32
cmp r0, r1
blt 1b
subs r1, r1, #32
bhi 1b
mov r0, #0
mcr p15, 0, r0, c7, c10, 4 @ drain WB
mcr p15, 0, r0, c7, c5, 0 @ flush I cache
mov pc, lr
/*
* Function: sa110_switch_to (struct task_struct *prev, struct task_struct *next)
*
* Params : prev Old task structure
* : next New task structure for process to run
*
* Returns : prev
* Purpose : Perform a task switch, saving the old processes state, and restoring
* the new.
*
* Notes : We don't fiddle with the FP registers here - we postpone this until
* the new task actually uses FP. This way, we don't swap FP for tasks
* that do not require it.
......@@ -237,20 +223,30 @@ _sa110_switch_to:
stmfd sp!, {r4 - r9, fp, lr} @ Store most regs on stack
mrs ip, cpsr
stmfd sp!, {ip} @ Save cpsr_SVC
ldr r2, [r0, #TSS_MEMMAP] @ Get old page tables
str sp, [r0, #TSS_SAVE] @ Save sp_SVC
ldr sp, [r1, #TSS_SAVE] @ Get saved sp_SVC
ldr r0, [r1, #TSK_ADDR_LIMIT]
teq r0, #0
moveq r0, #DOM_KERNELDOMAIN
movne r0, #DOM_USERDOMAIN
mcr p15, 0, r0, c3, c0 @ Set segment
ldr r0, [r1, #TSS_MEMMAP] @ Page table pointer
ldr r4, [r1, #TSK_ADDR_LIMIT]
teq r4, #0
moveq r4, #DOM_KERNELDOMAIN
movne r4, #DOM_USERDOMAIN
mcr p15, 0, r4, c3, c0 @ Set segment
ldr r4, [r1, #TSS_MEMMAP] @ Page table pointer
/*
* Flushing the cache is nightmarishly slow, so we take any excuse
* to get out of it. If the old page table is the same as the new,
* this is a CLONE_VM relative of the old task and there is no need
* to flush. The overhead of the tests isn't even on the radar
* compared to the cost of the flush itself.
*/
teq r4, r2
beq 2f
ldr r3, =Lclean_switch
ldr r2, [r3]
ands r2, r2, #1
eor r2, r2, #1
str r2, [r3]
ldr r2, =0xdf000000
ldr r2, =FLUSH_BASE
addne r2, r2, #32768
add r1, r2, #16384 @ only necessary for 16k
1: ldr r3, [r2], #32
......@@ -259,19 +255,16 @@ _sa110_switch_to:
mov r1, #0
mcr p15, 0, r1, c7, c5, 0 @ flush I cache
mcr p15, 0, r1, c7, c10, 4 @ drain WB
mcr p15, 0, r0, c2, c0, 0 @ load page table pointer
mcr p15, 0, r4, c2, c0, 0 @ load page table pointer
mcr p15, 0, r1, c8, c7, 0 @ flush TLBs
ldmfd sp!, {ip}
2: ldmfd sp!, {ip}
msr spsr, ip @ Save tasks CPSR into SPSR for this return
ldmfd sp!, {r4 - r9, fp, pc}^ @ Load all regs saved previously
/*
* Function: sa110_data_abort ()
*
* Params : r0 = address of aborted instruction
*
* Purpose : obtain information about current aborted instruction
*
* Returns : r0 = address of abort
* : r1 = FSR
* : r2 != 0 if writing
......@@ -288,36 +281,62 @@ _sa110_data_abort:
mov pc, lr
/*
* Function: sa110_set_pmd ()
*
* Function: sa110_set_pmd(pmd_t *pmdp, pmd_t pmd)
* Params : r0 = Address to set
* : r1 = value to set
*
* Purpose : Set a PMD and flush it out of any WB cache
* Purpose : Set a PMD and flush it out
*/
.align 5
_sa110_set_pmd: str r1, [r0]
mcr p15, 0, r0, c7, c10, 1 @ clean D entry (drain is done by TLB fns)
mov pc, lr
/*
* Function: sa110_set_pte(pte_t *ptep, pte_t pte)
* Params : r0 = Address to set
* : r1 = value to set
* Purpose : Set a PTE and flush it out
*/
.align 5
_sa110_set_pte: str r1, [r0], #-1024 @ linux version
eor r1, r1, #LPTE_PRESENT | LPTE_YOUNG | LPTE_WRITE | LPTE_DIRTY
bic r2, r1, #0xff0
bic r2, r2, #3
orr r2, r2, #HPTE_TYPE_SMALL
tst r1, #LPTE_USER | LPTE_EXEC @ User or Exec?
orrne r2, r2, #HPTE_AP_READ
tst r1, #LPTE_WRITE | LPTE_DIRTY @ Write and Dirty?
orreq r2, r2, #HPTE_AP_WRITE
tst r1, #LPTE_PRESENT | LPTE_YOUNG @ Present and Young?
movne r2, #0
str r2, [r0] @ hardware version
mov r0, r0
mcr p15, 0, r0, c7, c10, 1 @ clean D entry (drain is done by TLB fns)
mov pc, lr
/*
* Function: sa110_check_bugs (void)
* : sa110_proc_init (void)
* : sa110_proc_fin (void)
*
* Notes : This processor does not require these
*/
_sa110_check_bugs:
mrs ip, cpsr
bic ip, ip, #F_BIT
msr cpsr, ip
_sa110_proc_init:
_sa110_proc_fin:
mov pc, lr
/*
* Function: sa110_reset
*
* Notes : This sets up everything for a reset
*/
_sa110_reset: mrs r1, cpsr
......@@ -350,14 +369,15 @@ ENTRY(sa110_processor_functions)
.word _sa110_flush_cache_all @ 24
.word _sa110_flush_cache_area @ 28
.word _sa110_flush_cache_entry @ 32
.word _sa110_flush_cache_pte @ 36
.word _sa110_clean_cache_area @ 36
.word _sa110_flush_ram_page @ 40
.word _sa110_flush_tlb_all @ 44
.word _sa110_flush_tlb_area @ 48
.word _sa110_set_pmd @ 52
.word _sa110_reset @ 56
.word _sa110_flush_icache_area @ 60
.word _sa110_set_pte @ 56
.word _sa110_reset @ 60
.word _sa110_flush_icache_area @ 64
.word _sa110_cache_wback_area @ 64
.word _sa110_cache_purge_area @ 68
.word _sa110_cache_wback_area @ 68
.word _sa110_cache_purge_area @ 72
......@@ -5,6 +5,8 @@
*
* Changelog:
* 26/01/1996 RMK Cleaned up various areas to make little more generic
* 07/02/1999 RMK Support added for 16K and 32K page sizes
* containing 8K blocks
*/
#include <linux/signal.h>
......@@ -19,21 +21,32 @@
#include <linux/swap.h>
#include <linux/smp.h>
#define SMALL_ALLOC_SHIFT (10)
#if PAGE_SIZE == 4096
/* 2K blocks */
#define SMALL_ALLOC_SHIFT (11)
#define NAME(x) x##_2k
#elif PAGE_SIZE == 32768 || PAGE_SIZE == 16384
/* 8K blocks */
#define SMALL_ALLOC_SHIFT (13)
#define NAME(x) x##_8k
#endif
#define SMALL_ALLOC_SIZE (1 << SMALL_ALLOC_SHIFT)
#define NR_BLOCKS (PAGE_SIZE / SMALL_ALLOC_SIZE)
#define BLOCK_MASK ((1 << NR_BLOCKS) - 1)
#if NR_BLOCKS != 4
#error I only support 4 blocks per page!
#endif
#define USED(pg) ((atomic_read(&(pg)->count) >> 8) & 15)
#define USED(pg) ((atomic_read(&(pg)->count) >> 8) & BLOCK_MASK)
#define SET_USED(pg,off) (atomic_read(&(pg)->count) |= 256 << off)
#define CLEAR_USED(pg,off) (atomic_read(&(pg)->count) &= ~(256 << off))
#define ALL_USED BLOCK_MASK
#define IS_FREE(pg,off) (!(atomic_read(&(pg)->count) & (256 << off)))
#define PAGE_PTR(page,block) ((struct free_small_page *)((page) + \
#define SM_PAGE_PTR(page,block) ((struct free_small_page *)((page) + \
((block) << SMALL_ALLOC_SHIFT)))
#if NR_BLOCKS != 2 && NR_BLOCKS != 4
#error I only support 2 or 4 blocks per page
#endif
struct free_small_page {
unsigned long next;
unsigned long prev;
......@@ -52,6 +65,7 @@ static unsigned char offsets[1<<NR_BLOCKS] = {
1, /* 0001 */
0, /* 0010 */
2, /* 0011 */
#if NR_BLOCKS == 4
0, /* 0100 */
1, /* 0101 */
0, /* 0110 */
......@@ -64,6 +78,7 @@ static unsigned char offsets[1<<NR_BLOCKS] = {
1, /* 1101 */
0, /* 1110 */
4 /* 1111 */
#endif
};
static inline void clear_page_links(unsigned long page)
......@@ -72,7 +87,7 @@ static inline void clear_page_links(unsigned long page)
int i;
for (i = 0; i < NR_BLOCKS; i++) {
fsp = PAGE_PTR(page, i);
fsp = SM_PAGE_PTR(page, i);
fsp->next = fsp->prev = 0;
}
}
......@@ -90,7 +105,7 @@ static inline void set_page_links_prev(unsigned long page, unsigned long prev)
for (i = 0; i < NR_BLOCKS; i++) {
if (mask & (1 << i))
continue;
fsp = PAGE_PTR(page, i);
fsp = SM_PAGE_PTR(page, i);
fsp->prev = prev;
}
}
......@@ -108,12 +123,12 @@ static inline void set_page_links_next(unsigned long page, unsigned long next)
for (i = 0; i < NR_BLOCKS; i++) {
if (mask & (1 << i))
continue;
fsp = PAGE_PTR(page, i);
fsp = SM_PAGE_PTR(page, i);
fsp->next = next;
}
}
unsigned long get_small_page(int priority)
unsigned long NAME(get_page)(int priority)
{
struct free_small_page *fsp;
unsigned long new_page;
......@@ -129,8 +144,8 @@ unsigned long get_small_page(int priority)
page = mem_map + MAP_NR(small_page_ptr);
offset = offsets[USED(page)];
SET_USED(page, offset);
new_page = (unsigned long)PAGE_PTR(small_page_ptr, offset);
if (USED(page) == 15) {
new_page = (unsigned long)SM_PAGE_PTR(small_page_ptr, offset);
if (USED(page) == ALL_USED) {
fsp = (struct free_small_page *)new_page;
set_page_links_prev (fsp->next, 0);
small_page_ptr = fsp->next;
......@@ -156,30 +171,31 @@ unsigned long get_small_page(int priority)
goto again;
}
void free_small_page(unsigned long spage)
void NAME(free_page)(unsigned long spage)
{
struct free_small_page *ofsp, *cfsp;
unsigned long flags;
struct page *page;
int offset, oldoffset;
if (!spage)
goto none;
offset = (spage >> SMALL_ALLOC_SHIFT) & (NR_BLOCKS - 1);
spage -= offset << SMALL_ALLOC_SHIFT;
page = mem_map + MAP_NR(spage);
if (!PageReserved(page) || !USED(page)) {
printk ("Trying to free non-small page from %p\n", __builtin_return_address(0));
return;
}
if (IS_FREE(page, offset)) {
printk ("Trying to free free small page from %p\n", __builtin_return_address(0));
return;
}
if (!PageReserved(page) || !USED(page))
goto non_small;
if (IS_FREE(page, offset))
goto free;
save_flags_cli (flags);
oldoffset = offsets[USED(page)];
CLEAR_USED(page, offset);
ofsp = PAGE_PTR(spage, oldoffset);
cfsp = PAGE_PTR(spage, offset);
ofsp = SM_PAGE_PTR(spage, oldoffset);
cfsp = SM_PAGE_PTR(spage, offset);
if (oldoffset == NR_BLOCKS) { /* going from totally used to mostly used */
cfsp->prev = 0;
......@@ -197,4 +213,13 @@ void free_small_page(unsigned long spage)
} else
*cfsp = *ofsp;
restore_flags(flags);
return;
non_small:
printk ("Trying to free non-small page from %p\n", __builtin_return_address(0));
return;
free:
printk ("Trying to free free small page from %p\n", __builtin_return_address(0));
none:
return;
}
......@@ -33,13 +33,15 @@ static struct tty_struct *get_tty(int fd)
{
struct file *filp;
if(fd >= NR_OPEN || !(filp = current->files->fd[fd]))
file = fcheck(fd);
if(!file)
return ((struct tty_struct *) 0);
if(filp->private_data) {
struct tty_struct *ttyp = (struct tty_struct *) filp->private_data;
if(ttyp->magic == TTY_MAGIC)
if(ttyp->magic == TTY_MAGIC) {
return ttyp;
}
}
return ((struct tty_struct *) 0);
}
......
This diff is collapsed.
......@@ -205,12 +205,15 @@ asmlinkage unsigned long sys_mmap(unsigned long addr, size_t len,
lock_kernel();
if (!(flags & MAP_ANONYMOUS)) {
if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
file = fget(fd);
if (!file)
goto out;
}
flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
ret = do_mmap(file, addr, len, prot, flags, offset);
if (file)
fput(file);
out:
unlock_kernel();
return ret;
......
......@@ -225,12 +225,19 @@
to determine this in advance other than by trial and error and common
sense, e.g. call a BNC connectored port 'BNC', not '10Mb'.
TO DO:
Changed the bus probing. EISA used to be done first, followed by PCI.
Most people probably don't even know what a de425 is today and the EISA
probe has messed up some SCSI cards in the past, so now PCI is always
probed first followed by EISA if a) the architecture allows EISA and
either b) there have been no PCI cards detected or c) an EISA probe is
forced by the user. To force a probe include "force_eisa" in your
insmod "args" line; for built-in kernels either change the driver to do
this automatically or include #define DE4X5_FORCE_EISA on or before
line 1040 in the driver.
TO DO:
------
o check what revision numbers the 21142 and 21143 have
o
Revision History
----------------
......@@ -416,11 +423,14 @@
access traps. This flag is merely for log messages:
should do something more definitive though...
0.543 30-Dec-98 Add SMP spin locking.
0.544 8-May-99 Fix for buggy SROM in Motorola embedded boards using
a 21143 by <mmporter@home.com>.
Change PCI/EISA bus probing order.
=========================================================================
*/
static const char *version = "de4x5.c:V0.543 1998/12/30 davies@maniac.ultranet.com\n";
static const char *version = "de4x5.c:V0.544 1999/5/8 davies@maniac.ultranet.com\n";
#include <linux/config.h>
#include <linux/module.h>
......@@ -1027,8 +1037,11 @@ static char name[DE4X5_NAME_LENGTH + 1];
#if !defined(__sparc_v9__) && !defined(__powerpc__) && !defined(__alpha__)
static u_char de4x5_irq[] = EISA_ALLOWED_IRQ_LIST;
static int lastEISA = 0;
#else
static int lastEISA = MAX_EISA_SLOTS; /* Only PCI probes */
# ifdef DE4X5_FORCE_EISA /* Force an EISA bus probe or not */
static int forceEISA = 1;
# else
static int forceEISA = 0;
# endif
#endif
static int num_de4x5s = 0;
static int cfrv = 0, useSROM = 0;
......@@ -1098,12 +1111,12 @@ de4x5_probe(struct device *dev))
{
u_long iobase = dev->base_addr;
pci_probe(dev, iobase);
#if !defined(__sparc_v9__) && !defined(__powerpc__) && !defined(__alpha__)
eisa_probe(dev, iobase);
#endif
if (lastEISA == MAX_EISA_SLOTS) {
pci_probe(dev, iobase);
if ((lastPCI == NO_MORE_PCI) && ((num_de4x5s == 0) || forceEISA)) {
eisa_probe(dev, iobase);
}
#endif
return (dev->priv ? 0 : -ENODEV);
}
......@@ -1230,6 +1243,7 @@ de4x5_hw_init(struct device *dev, u_long iobase))
if ((tmp = (void *)kmalloc(RX_BUFF_SZ * NUM_RX_DESC + ALIGN,
GFP_KERNEL)) == NULL) {
kfree(lp->cache.priv);
lp->cache.priv = NULL;
return -ENOMEM;
}
......@@ -2066,38 +2080,36 @@ eisa_probe(struct device *dev, u_long ioaddr))
}
for (status = -ENODEV; (i<maxSlots) && (dev!=NULL); i++, iobase+=EISA_SLOT_INC) {
if (EISA_signature(name, EISA_ID)) {
cfid = (u32) inl(PCI_CFID);
cfrv = (u_short) inl(PCI_CFRV);
device = (cfid >> 8) & 0x00ffff00;
vendor = (u_short) cfid;
if (check_region(iobase, DE4X5_EISA_TOTAL_SIZE)) continue;
if (!EISA_signature(name, EISA_ID)) continue;
cfid = (u32) inl(PCI_CFID);
cfrv = (u_short) inl(PCI_CFRV);
device = (cfid >> 8) & 0x00ffff00;
vendor = (u_short) cfid;
/* Read the EISA Configuration Registers */
irq = inb(EISA_REG0);
irq = de4x5_irq[(irq >> 1) & 0x03];
/* Read the EISA Configuration Registers */
irq = inb(EISA_REG0);
irq = de4x5_irq[(irq >> 1) & 0x03];
if (is_DC2114x) {
device = ((cfrv & CFRV_RN) < DC2114x_BRK ? DC21142 : DC21143);
}
lp->chipset = device;
if (is_DC2114x) {
device = ((cfrv & CFRV_RN) < DC2114x_BRK ? DC21142 : DC21143);
}
lp->chipset = device;
/* Write the PCI Configuration Registers */
outl(PCI_COMMAND_IO | PCI_COMMAND_MASTER, PCI_CFCS);
outl(0x00006000, PCI_CFLT);
outl(iobase, PCI_CBIO);
/* Write the PCI Configuration Registers */
outl(PCI_COMMAND_IO | PCI_COMMAND_MASTER, PCI_CFCS);
outl(0x00006000, PCI_CFLT);
outl(iobase, PCI_CBIO);
DevicePresent(EISA_APROM);
if (check_region(iobase, DE4X5_EISA_TOTAL_SIZE) == 0) {
dev->irq = irq;
if ((status = de4x5_hw_init(dev, iobase)) == 0) {
num_de4x5s++;
if (loading_module) link_modules(lastModule, dev);
lastEISA = i;
return;
}
} else if (ioaddr != 0) {
printk("%s: region already allocated at 0x%04lx.\n", dev->name,iobase);
}
DevicePresent(EISA_APROM);
dev->irq = irq;
if ((status = de4x5_hw_init(dev, iobase)) == 0) {
num_de4x5s++;
if (loading_module) link_modules(lastModule, dev);
lastEISA = i;
return;
}
}
......@@ -4794,6 +4806,7 @@ type3_infoblock(struct device *dev, u_char count, u_char *p)
if (lp->state == INITIALISED) {
lp->ibn = 3;
lp->active = *p++;
if (MOTO_SROM_BUG) lp->active = 0;
lp->phy[lp->active].gep = (*p ? p : 0); p += (2 * (*p) + 1);
lp->phy[lp->active].rst = (*p ? p : 0); p += (2 * (*p) + 1);
lp->phy[lp->active].mc = TWIDDLE(p); p += 2;
......@@ -5326,6 +5339,9 @@ de4x5_parse_params(struct device *dev)
t = *q;
*q = '\0';
#if !defined(__sparc_v9__) && !defined(__powerpc__) && !defined(__alpha__)
if (strstr(p, "force_eisa") || strstr(p, "FORCE_EISA")) forceEISA = 1;
#endif
if (strstr(p, "fdx") || strstr(p, "FDX")) lp->params.fdx = 1;
if (strstr(p, "autosense") || strstr(p, "AUTOSENSE")) {
......@@ -5766,6 +5782,12 @@ init_module(void)
release_region(p->base_addr, (lp->bus == PCI ?
DE4X5_PCI_TOTAL_SIZE :
DE4X5_EISA_TOTAL_SIZE));
if (lp->cache.buf) { /* MAC buffers allocated? */
kfree(lp->cache.buf); /* Free the MAC buffers */
}
if (lp->cache.priv) { /* Private area allocated? */
kfree(lp->cache.priv); /* Free the private area */
}
}
kfree(p);
} else {
......@@ -5799,10 +5821,10 @@ unlink_modules(struct device *p)
if (lp->cache.buf) { /* MAC buffers allocated? */
kfree(lp->cache.buf); /* Free the MAC buffers */
}
kfree(lp->cache.priv); /* Free the private area */
release_region(p->base_addr, (lp->bus == PCI ?
DE4X5_PCI_TOTAL_SIZE :
DE4X5_EISA_TOTAL_SIZE));
kfree(lp->cache.priv); /* Free the private area */
}
unregister_netdev(p);
kfree(p); /* Free the device structure */
......@@ -5867,6 +5889,9 @@ insert_device(struct device *dev, u_long iobase, int (*init)(struct device *)))
* Local variables:
* compile-command: "gcc -D__KERNEL__ -I/linux/include -Wall -Wstrict-prototypes -fomit-frame-pointer -fno-strength-reduce -malign-loops=2 -malign-jumps=2 -malign-functions=2 -O2 -m486 -c de4x5.c"
*
* compile-command: "gcc -D__KERNEL__ -DMODULE -I/linux/include -Wall -Wstrict-prototypes -fomit-frame-pointer -fno-strength-reduce -malign-loops=2 -malign-jumps=2 -malign-functions=2 -O2 -m486 -c de4x5.c"
* Delete -D__SMP__ below if you didn't define this in your kernel
* Delete -DMODVERSIONS below if you didn't define this in your kernel
*
* compile-command: "gcc -D__KERNEL__ -DMODULE -I/linux/include -Wall -Wstrict-prototypes -fomit-frame-pointer -fno-strength-reduce -malign-loops=2 -malign-jumps=2 -malign-functions=2 -O2 -m486 -DMODVERSIONS -include /linux/include/linux/modversions.h -c de4x5.c"
* End:
*/
......@@ -1027,3 +1027,5 @@ struct de4x5_ioctl {
#define DE4X5_GET_REG 0x0e /* Get the DE4X5 Registers */
#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
#define MOTO_SROM_BUG ((lp->active == 8) && ((*((s32 *)le32_to_cpu(get_unaligned(dev->dev_addr)))&0x00ffffff)==0x3e0008))
......@@ -168,7 +168,7 @@ static int try_to_fill_dentry(struct dentry *dentry, struct super_block *sb, str
* yet completely filled in, and revalidate has to delay such
* lookups..
*/
static int autofs_revalidate(struct dentry * dentry)
static int autofs_revalidate(struct dentry * dentry, int flags)
{
struct inode * dir = dentry->d_parent->d_inode;
struct autofs_sb_info *sbi = autofs_sbi(dir->i_sb);
......@@ -241,7 +241,7 @@ static struct dentry *autofs_root_lookup(struct inode *dir, struct dentry *dentr
d_add(dentry, NULL);
up(&dir->i_sem);
autofs_revalidate(dentry);
autofs_revalidate(dentry, 0);
down(&dir->i_sem);
/*
......
......@@ -44,7 +44,7 @@ static int coda_rename(struct inode *old_inode, struct dentry *old_dentry,
static int coda_readdir(struct file *file, void *dirent, filldir_t filldir);
/* dentry ops */
static int coda_dentry_revalidate(struct dentry *de);
static int coda_dentry_revalidate(struct dentry *de, int);
static void coda_dentry_delete(struct dentry *);
/* support routines */
......@@ -778,7 +778,7 @@ CDEBUG(D_FILE, "entry %d: ino %ld, namlen %d, reclen %d, type %d, pos %d, string
}
/* called when a cache lookup succeeds */
static int coda_dentry_revalidate(struct dentry *de)
static int coda_dentry_revalidate(struct dentry *de, int flags)
{
int valid = 1;
struct inode *inode = de->d_inode;
......
......@@ -18,7 +18,7 @@
static int devpts_root_readdir(struct file *,void *,filldir_t);
static struct dentry *devpts_root_lookup(struct inode *,struct dentry *);
static int devpts_revalidate(struct dentry *);
static int devpts_revalidate(struct dentry *, int);
static struct file_operations devpts_root_operations = {
NULL, /* llseek */
......@@ -116,7 +116,7 @@ static int devpts_root_readdir(struct file *filp, void *dirent, filldir_t filldi
* the pty really does still exist. Never revalidate negative dentries;
* for simplicity (fix later?)
*/
static int devpts_revalidate(struct dentry * dentry)
static int devpts_revalidate(struct dentry * dentry, int flags)
{
struct devpts_sb_info *sbi;
......
......@@ -1349,8 +1349,8 @@ asmlinkage int sys_quotactl(int cmd, const char *special, int id, caddr_t addr)
case Q_GETSTATS:
break;
case Q_GETQUOTA:
if (((type == USRQUOTA && current->uid != id) ||
(type == GRPQUOTA && current->gid != id)) &&
if (((type == USRQUOTA && current->euid != id) ||
(type == GRPQUOTA && current->egid != id)) &&
!capable(CAP_SYS_RESOURCE))
goto out;
break;
......
......@@ -18,7 +18,7 @@
#include <linux/hfs_fs_i.h>
#include <linux/hfs_fs.h>
static int hfs_revalidate_dentry(struct dentry *);
static int hfs_revalidate_dentry(struct dentry *, int);
static int hfs_hash_dentry(struct dentry *, struct qstr *);
static int hfs_compare_dentry(struct dentry *, struct qstr *, struct qstr *);
static void hfs_dentry_iput(struct dentry *, struct inode *);
......@@ -89,7 +89,7 @@ static void hfs_dentry_iput(struct dentry *dentry, struct inode *inode)
iput(inode);
}
static int hfs_revalidate_dentry(struct dentry *dentry)
static int hfs_revalidate_dentry(struct dentry *dentry, int flags)
{
struct inode *inode = dentry->d_inode;
int diff;
......
......@@ -23,18 +23,6 @@
#include <asm/page.h>
#include <asm/pgtable.h>
/*
* The bitmask for a lookup event:
* - follow links at the end
* - require a directory
* - ending slashes ok even for nonexistent files
* - internal "there are more path compnents" flag
*/
#define LOOKUP_FOLLOW (1)
#define LOOKUP_DIRECTORY (2)
#define LOOKUP_SLASHOK (4)
#define LOOKUP_CONTINUE (8)
#include <asm/namei.h>
/* This can be removed after the beta phase. */
......@@ -225,12 +213,12 @@ static struct dentry * reserved_lookup(struct dentry * parent, struct qstr * nam
/*
* Internal lookup() using the new generic dcache.
*/
static struct dentry * cached_lookup(struct dentry * parent, struct qstr * name)
static struct dentry * cached_lookup(struct dentry * parent, struct qstr * name, int flags)
{
struct dentry * dentry = d_lookup(parent, name);
if (dentry && dentry->d_op && dentry->d_op->d_revalidate) {
if (!dentry->d_op->d_revalidate(dentry) && !d_invalidate(dentry)) {
if (!dentry->d_op->d_revalidate(dentry, flags) && !d_invalidate(dentry)) {
dput(dentry);
dentry = NULL;
}
......@@ -245,7 +233,7 @@ static struct dentry * cached_lookup(struct dentry * parent, struct qstr * name)
* We get the directory semaphore, and after getting that we also
* make sure that nobody added the entry to the dcache in the meantime..
*/
static struct dentry * real_lookup(struct dentry * parent, struct qstr * name)
static struct dentry * real_lookup(struct dentry * parent, struct qstr * name, int flags)
{
struct dentry * result;
struct inode *dir = parent->d_inode;
......@@ -258,7 +246,7 @@ static struct dentry * real_lookup(struct dentry * parent, struct qstr * name)
* FIXME! This could use version numbering or similar to
* avoid unnecessary cache lookups.
*/
result = cached_lookup(parent, name);
result = cached_lookup(parent, name, flags);
if (!result) {
struct dentry * dentry = d_alloc(parent, name);
result = ERR_PTR(-ENOMEM);
......@@ -392,9 +380,9 @@ struct dentry * lookup_dentry(const char * name, struct dentry * base, unsigned
/* This does the actual lookups.. */
dentry = reserved_lookup(base, &this);
if (!dentry) {
dentry = cached_lookup(base, &this);
dentry = cached_lookup(base, &this, flags);
if (!dentry) {
dentry = real_lookup(base, &this);
dentry = real_lookup(base, &this, flags);
if (IS_ERR(dentry))
break;
}
......
......@@ -112,14 +112,14 @@ ncp_dir_read(struct file *filp, char *buf, size_t count, loff_t *ppos)
/*
* Dentry operations routines
*/
static int ncp_lookup_validate(struct dentry *);
static int ncp_lookup_validate(struct dentry *, int);
static int ncp_hash_dentry(struct dentry *, struct qstr *);
static int ncp_compare_dentry (struct dentry *, struct qstr *, struct qstr *);
static void ncp_delete_dentry(struct dentry *);
struct dentry_operations ncp_dentry_operations =
{
ncp_lookup_validate, /* d_validate(struct dentry *) */
ncp_lookup_validate, /* d_revalidate(struct dentry *, int) */
ncp_hash_dentry, /* d_hash */
ncp_compare_dentry, /* d_compare */
ncp_delete_dentry /* d_delete(struct dentry *) */
......@@ -345,7 +345,7 @@ leave_me:;
static int
ncp_lookup_validate(struct dentry * dentry)
ncp_lookup_validate(struct dentry * dentry, int flags)
{
struct ncp_server *server;
struct inode *dir = dentry->d_parent->d_inode;
......
......@@ -72,9 +72,9 @@ static struct file_operations nfs_dir_operations = {
NULL, /* select - default */
NULL, /* ioctl - default */
NULL, /* mmap */
nfs_open, /* open - revalidate the inode */
nfs_open, /* open */
NULL, /* flush */
NULL, /* no special release code */
nfs_release, /* release */
NULL /* fsync */
};
......@@ -364,7 +364,43 @@ static inline void nfs_renew_times(struct dentry * dentry)
dentry->d_time = jiffies;
}
#define NFS_REVALIDATE_INTERVAL (5*HZ)
static inline int nfs_dentry_force_reval(struct dentry *dentry, int flags)
{
struct inode *inode = dentry->d_inode;
unsigned long timeout = NFS_ATTRTIMEO(inode);
/*
* If it's the last lookup in a series, we use a stricter
* cache consistency check!
*/
if (!(flags & LOOKUP_CONTINUE))
timeout = 0;
return time_after(jiffies,dentry->d_time + timeout);
}
/*
* We judge how long we want to trust negative
* dentries by looking at the parent inode mtime.
*
* If mtime is close to present time, we revalidate
* more often.
*/
static inline int nfs_neg_need_reval(struct dentry *dentry)
{
unsigned long timeout = 30 * HZ;
struct inode *dir = dentry->d_parent->d_inode;
if (dir) {
/* Modified in the last two minutes? */
long diff = CURRENT_TIME - dir->i_mtime;
if (diff < 2*60)
timeout = 1 * HZ;
}
return time_after(jiffies, dentry->d_time + timeout);
}
/*
* This is called every time the dcache has a lookup hit,
* and we should check whether we can really trust that
......@@ -377,7 +413,7 @@ static inline void nfs_renew_times(struct dentry * dentry)
* we do a new lookup and verify that the dentry is still
* correct.
*/
static int nfs_lookup_revalidate(struct dentry * dentry)
static int nfs_lookup_revalidate(struct dentry * dentry, int flags)
{
struct dentry * parent = dentry->d_parent;
struct inode * inode = dentry->d_inode;
......@@ -386,11 +422,12 @@ static int nfs_lookup_revalidate(struct dentry * dentry)
struct nfs_fattr fattr;
/*
* If we don't have an inode, let's just assume
* a 5-second "live" time for negative dentries.
* If we don't have an inode, let's look at the parent
* directory mtime to get a hint about how often we
* should validate things..
*/
if (!inode) {
if (time_after(jiffies, dentry->d_time + NFS_REVALIDATE_INTERVAL))
if (nfs_neg_need_reval(dentry))
goto out_bad;
goto out_valid;
}
......@@ -401,16 +438,16 @@ static int nfs_lookup_revalidate(struct dentry * dentry)
goto out_bad;
}
if (time_before(jiffies,dentry->d_time+NFS_ATTRTIMEO(inode)))
if (IS_ROOT(dentry))
goto out_valid;
if (IS_ROOT(dentry))
if (!nfs_dentry_force_reval(dentry, flags))
goto out_valid;
/*
* Do a new lookup and check the dentry attributes.
*/
error = nfs_proc_lookup(NFS_DSERVER(parent), NFS_FH(parent),
error = nfs_proc_lookup(NFS_DSERVER(parent), NFS_FH(parent),
dentry->d_name.name, &fhandle, &fattr);
if (error)
goto out_bad;
......@@ -489,7 +526,7 @@ static void nfs_dentry_release(struct dentry *dentry)
}
struct dentry_operations nfs_dentry_operations = {
nfs_lookup_revalidate, /* d_validate(struct dentry *) */
nfs_lookup_revalidate, /* d_revalidate(struct dentry *, int) */
NULL, /* d_hash */
NULL, /* d_compare */
nfs_dentry_delete, /* d_delete(struct dentry *) */
......
......@@ -46,9 +46,9 @@ static struct file_operations nfs_file_operations = {
NULL, /* select - default */
NULL, /* ioctl - default */
nfs_file_mmap, /* mmap */
nfs_open, /* open - revalidate the inode */
nfs_open, /* open */
nfs_file_flush, /* flush */
NULL, /* release */
nfs_release, /* release */
nfs_fsync, /* fsync */
NULL, /* fasync */
NULL, /* check_media_change */
......
......@@ -696,25 +696,19 @@ nfs_revalidate(struct dentry *dentry)
}
/*
* Revalidate the file on open (this
* is separate from the path-revalidation
* that we do on any lookup).
*
* When we actually open a file, we want
* fairly strict consistency: make sure that
* we've updated the attributes within the
* last second or so..
* These are probably going to contain hooks for
* allocating and releasing RPC credentials for
* the file. I'll have to think about Tronds patch
* a bit more..
*/
int nfs_open(struct inode *inode, struct file *filp)
{
int retval = 0;
return 0;
}
if (time_after(jiffies, NFS_READTIME(inode) + HZ/2)) {
struct dentry *dentry = filp->f_dentry;
struct nfs_server *server = NFS_DSERVER(dentry);
retval = _nfs_revalidate_inode(server, dentry);
}
return retval;
int nfs_release(struct inode *inode, struct file *filp)
{
return 0;
}
/*
......
......@@ -191,14 +191,14 @@ file->f_dentry->d_name.name);
/*
* Dentry operations routines
*/
static int smb_lookup_validate(struct dentry *);
static int smb_lookup_validate(struct dentry *, int);
static int smb_hash_dentry(struct dentry *, struct qstr *);
static int smb_compare_dentry(struct dentry *, struct qstr *, struct qstr *);
static void smb_delete_dentry(struct dentry *);
static struct dentry_operations smbfs_dentry_operations =
{
smb_lookup_validate, /* d_validate(struct dentry *) */
smb_lookup_validate, /* d_revalidate(struct dentry *) */
smb_hash_dentry, /* d_hash */
smb_compare_dentry, /* d_compare */
smb_delete_dentry /* d_delete(struct dentry *) */
......@@ -208,7 +208,7 @@ static struct dentry_operations smbfs_dentry_operations =
* This is the callback when the dcache has a lookup hit.
*/
static int
smb_lookup_validate(struct dentry * dentry)
smb_lookup_validate(struct dentry * dentry, int flags)
{
struct inode * inode = dentry->d_inode;
unsigned long age = jiffies - dentry->d_time;
......
......@@ -30,7 +30,7 @@ extern struct inode *pseudo_root;
*/
/* nothing for now ... */
static int umsdos_dentry_validate(struct dentry *dentry)
static int umsdos_dentry_validate(struct dentry *dentry, int flags)
{
return 1;
}
......@@ -46,7 +46,7 @@ static void umsdos_dentry_dput(struct dentry *dentry)
struct dentry_operations umsdos_dentry_operations =
{
umsdos_dentry_validate, /* d_validate(struct dentry *) */
umsdos_dentry_validate, /* d_revalidate(struct dentry *, int) */
NULL, /* d_hash */
NULL, /* d_compare */
umsdos_dentry_dput, /* d_delete(struct dentry *) */
......
......@@ -71,7 +71,7 @@ static int vfat_hashi(struct dentry *parent, struct qstr *qstr);
static int vfat_hash(struct dentry *parent, struct qstr *qstr);
static int vfat_cmpi(struct dentry *dentry, struct qstr *a, struct qstr *b);
static int vfat_cmp(struct dentry *dentry, struct qstr *a, struct qstr *b);
static int vfat_revalidate(struct dentry *dentry);
static int vfat_revalidate(struct dentry *dentry, int);
static struct dentry_operations vfat_dentry_ops[4] = {
{
......@@ -106,7 +106,7 @@ void vfat_put_super(struct super_block *sb)
MOD_DEC_USE_COUNT;
}
static int vfat_revalidate(struct dentry *dentry)
static int vfat_revalidate(struct dentry *dentry, int flags)
{
PRINTK1(("vfat_revalidate: %s\n", dentry->d_name.name));
if (dentry->d_time == dentry->d_parent->d_inode->i_version) {
......
......@@ -26,7 +26,9 @@ struct exec
#define M_ARM 103
#ifdef __KERNEL__
#include <asm/arch/a.out.h>
#endif
#ifndef LIBRARY_START_TEXT
#define LIBRARY_START_TEXT (0x00c00000)
......
/*
* linux/include/asm-arm/arch-arc/a.out.h
*
* Copyright (C) 1996 Russell King
*
* Acorn Archimedes/A5000 a.out.h specs
* Copyright (C) 1996-1999 Russell King
*/
#ifndef __ASM_ARCH_A_OUT_H
#define __ASM_ARCH_A_OUT_H
#ifdef __KERNEL__
#define STACK_TOP (0x01a00000)
#endif
#include <asm/arch/memory.h>
#define STACK_TOP TASK_SIZE
#endif
/*
* linux/include/asm-arm/arch-arc/hardware.h
*
* Copyright (C) 1996 Russell King.
* Copyright (C) 1996-1999 Russell King.
*
* This file contains the hardware definitions of the
* Acorn Archimedes/A5000 machines.
......@@ -9,21 +9,20 @@
* Modifications:
* 04-04-1998 PJB/RMK Merged arc and a5k versions
*/
#ifndef __ASM_ARCH_HARDWARE_H
#define __ASM_ARCH_HARDWARE_H
#include <linux/config.h>
#include <asm/arch/memory.h>
/*
* What hardware must be present - these can be tested by the kernel
* source.
*/
#define HAS_IOC
#include <asm/ioc.h>
#define HAS_MEMC
#include <asm/memc.h>
#define HAS_MEMC1A
#define HAS_VIDC
/*
......@@ -56,6 +55,12 @@
* for use with inb/outb
*/
#define IO_VIDC_BASE 0x80100000
#ifdef CONFIG_ARCH_A5K
#define IOEB_VID_CTL 0x800d4012
#define IOEB_PRESENT 0x800d4014
#define IOEB_PSCLR 0x800d4016
#define IOEB_MONTYPE 0x800d401c
#endif
#ifdef CONFIG_ARCH_ARC
#define LATCHAADDR 0x80094010
#define LATCHBADDR 0x80094006
......@@ -66,6 +71,14 @@
#define IO_EC_IOC_BASE 0x80090000
#define IO_EC_MEMC_BASE 0x80000000
#ifdef CONFIG_ARCH_ARC
/* A680 hardware */
#define WD1973_BASE 0x03290000
#define WD1973_LATCH 0x03350000
#define Z8530_BASE 0x032b0008
#define SCSI_BASE 0x03100000
#endif
/*
* IO definitions
*/
......@@ -77,11 +90,8 @@
/*
* RAM definitions
*/
#define MAPTOPHYS(a) (((unsigned long)a & 0x007fffff) + PAGE_OFFSET)
#define KERNTOPHYS(a) ((((unsigned long)(&a)) & 0x007fffff) + PAGE_OFFSET)
#define GET_MEMORY_END(p) (PAGE_OFFSET + (p->u1.s.page_size) * (p->u1.s.nr_pages))
#define PARAMS_BASE (PAGE_OFFSET + 0x7c000)
#define KERNEL_BASE (PAGE_OFFSET + 0x80000)
#else
......
......@@ -10,6 +10,9 @@
* 11-01-1998 RMK Added mask_and_ack_irq
* 22-08-1998 RMK Restructured IRQ routines
*/
#include <asm/ioc.h>
#define fixup_irq(x) (x)
static void arc_mask_irq_ack_a(unsigned int irq)
{
......@@ -108,10 +111,17 @@ static __inline__ void irq_init_irq(void)
outb(0, IOC_FIQMASK);
for (irq = 0; irq < NR_IRQS; irq++) {
switch (irq & 0xf8) {
switch (irq) {
case 0 ... 6:
irq_desc[irq].probe_ok = 1;
irq_desc[irq].valid = 1;
irq_desc[irq].mask_ack = arc_mask_irq_ack_a;
irq_desc[irq].mask = arc_mask_irq_a;
irq_desc[irq].unmask = arc_unmask_irq_a;
break;
case 7:
irq_desc[irq].noautoenable = 1;
irq_desc[irq].valid = 1;
irq_desc[irq].mask_ack = arc_mask_irq_ack_a;
irq_desc[irq].mask = arc_mask_irq_a;
......
......@@ -11,7 +11,6 @@
#define NR_SCANCODES 128
extern int a5kkbd_translate(unsigned char scancode, unsigned char *keycode_p, char *up_flag_p);
extern void a5kkbd_leds(unsigned char leds);
extern void a5kkbd_init_hw(void);
extern unsigned char a5kkbd_sysrq_xlate[NR_SCANCODES];
......@@ -19,11 +18,7 @@ extern unsigned char a5kkbd_sysrq_xlate[NR_SCANCODES];
#define kbd_setkeycode(sc,kc) (-EINVAL)
#define kbd_getkeycode(sc) (-EINVAL)
/* Prototype: int kbd_translate(scancode, *keycode, *up_flag, raw_mode)
* Returns : 0 to ignore scancode, *keycode set to keycode, *up_flag
* set to 0200 if scancode indicates release
*/
#define kbd_translate(sc, kcp, ufp, rm) a5kkbd_translate(sc, kcp, ufp)
#define kbd_translate(sc, kcp, rm) ({ *(kcp) = (sc); 1; })
#define kbd_unexpected_up(kc) (0200)
#define kbd_leds(leds) a5kkbd_leds(leds)
#define kbd_init_hw() a5kkbd_init_hw()
......
/*
* linux/include/asm-arm/arch-arc/mmu.h
* linux/include/asm-arm/arch-arc/memory.h
*
* Copyright (c) 1996 Russell King.
* Copyright (c) 1996-1999 Russell King.
*
* Changelog:
* 22-11-1996 RMK Created
* 22-Nov-1996 RMK Created
* 21-Mar-1999 RMK Renamed to memory.h
* RMK Moved PAGE_OFFSET and TASK_SIZE here
*/
#ifndef __ASM_ARCH_MMU_H
#define __ASM_ARCH_MMU_H
#ifndef __ASM_ARCH_MEMORY_H
#define __ASM_ARCH_MEMORY_H
/*
* User space: 26MB
*/
#define TASK_SIZE (0x01a00000UL)
/*
* Page offset: 32MB
*/
#define PAGE_OFFSET (0x02000000UL)
#define __virt_to_phys__is_a_macro
#define __virt_to_phys(vpage) vpage
......
......@@ -34,6 +34,8 @@ void oldlatch_bupdate(unsigned char mask,unsigned char newdata);
/* newval=(oldval & mask)|newdata */
void oldlatch_aupdate(unsigned char mask,unsigned char newdata);
void oldlatch_init(void);
#elif defined(CONFIG_ARCH_A5K)
#ifdef __need_oldlatches
......
/*
* linux/include/asm-arm/arch-arc/processor.h
*
* Copyright (c) 1996 Russell King.
* Copyright (c) 1996-1999 Russell King.
*
* Changelog:
* 10-09-1996 RMK Created
* 10-Sep-1996 RMK Created
* 21-Mar-1999 RMK Added asm/arch/memory.h
*/
#ifndef __ASM_ARCH_PROCESSOR_H
#define __ASM_ARCH_PROCESSOR_H
#include <asm/arch/memory.h>
/*
* Bus types
*/
......@@ -18,17 +21,9 @@
#define MCA_bus 0
#define MCA_bus__is_a_macro /* for versions in ksyms.c */
/*
* User space: 26MB
*/
#define TASK_SIZE (0x01a00000UL)
/* This decides where the kernel will search for a free chunk of vm
* space during mmap's.
*/
#define TASK_UNMAPPED_BASE (TASK_SIZE / 3)
#define INIT_MMAP \
{ &init_mm, 0, 0, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, NULL, &init_mm.mmap }
#endif
......@@ -8,6 +8,9 @@
* 10-Oct-1996 RMK Brought up to date with arch-sa110eval
* 04-Dec-1997 RMK Updated for new arch/arm/time.c
*/
#include <asm/ioc.h>
static long last_rtc_update = 0; /* last time the cmos clock got updated */
extern __inline__ unsigned long gettimeoffset (void)
{
......@@ -51,46 +54,140 @@ extern __inline__ unsigned long gettimeoffset (void)
return offset;
}
/*
* No need to reset the timer at every irq
*/
#define reset_timer() 1
extern int iic_control (unsigned char, int, char *, int);
/*
* Updating of the RTC. We don't currently write the time to the
* CMOS clock.
*/
#define update_rtc()
static int set_rtc_time(unsigned long nowtime)
{
char buf[5], ctrl;
if (iic_control(0xa1, 0, &ctrl, 1) != 0)
printk("RTC: failed to read control reg\n");
/*
* Reset divider
*/
ctrl |= 0x80;
if (iic_control(0xa0, 0, &ctrl, 1) != 0)
printk("RTC: failed to stop the clock\n");
/*
* We only set the time - we don't set the date.
* This means that there is the possibility once
* a day for the correction to disrupt the date.
* We really ought to write the time and date, or
* nothing at all.
*/
buf[0] = 0;
buf[1] = nowtime % 60; nowtime /= 60;
buf[2] = nowtime % 60; nowtime /= 60;
buf[3] = nowtime % 24;
BIN_TO_BCD(buf[1]);
BIN_TO_BCD(buf[2]);
BIN_TO_BCD(buf[3]);
if (iic_control(0xa0, 1, buf, 4) != 0)
printk("RTC: Failed to set the time\n");
/*
* Re-enable divider
*/
ctrl &= ~0x80;
if (iic_control(0xa0, 0, &ctrl, 1) != 0)
printk("RTC: failed to start the clock\n");
return 0;
}
extern __inline__ unsigned long get_rtc_time(void)
{
unsigned int year, i;
char buf[8];
/*
* The year is not part of the RTC counter
* registers, and is stored in RAM. This
* means that it will not be automatically
* updated.
*/
if (iic_control(0xa1, 0xc0, buf, 1) != 0)
printk("RTC: failed to read the year\n");
/*
* If the year is before 1970, then the year
* is actually 100 in advance. This gives us
* a year 2070 bug...
*/
year = 1900 + buf[0];
if (year < 1970)
year += 100;
/*
* Read the time and date in one go - this
* will ensure that we don't get any effects
* due to carry (the RTC latches the counters
* during a read).
*/
if (iic_control(0xa1, 2, buf, 5) != 0) {
printk("RTC: failed to read the time and date\n");
memset(buf, 0, sizeof(buf));
}
/*
* The RTC combines years with date and weekday
* with month. We need to mask off this extra
* information before converting the date to
* binary.
*/
buf[4] &= 0x1f;
buf[3] &= 0x3f;
for (i = 0; i < 5; i++)
BCD_TO_BIN(buf[i]);
return mktime(year, buf[4], buf[3], buf[2], buf[1], buf[0]);
}
static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
do_timer(regs);
/* If we have an externally synchronized linux clock, then update
* CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
* called as close as possible to 500 ms before the new second starts.
*/
if ((time_status & STA_UNSYNC) == 0 &&
xtime.tv_sec > last_rtc_update + 660 &&
xtime.tv_usec >= 50000 - (tick >> 1) &&
xtime.tv_usec < 50000 + (tick >> 1)) {
if (set_rtc_time(xtime.tv_sec) == 0)
last_rtc_update = xtime.tv_sec;
else
last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
}
}
static struct irqaction timerirq = {
timer_interrupt,
0,
0,
"timer",
NULL,
NULL
};
/*
* Set up timer interrupt, and return the current time in seconds.
*/
extern __inline__ unsigned long setup_timer (void)
extern __inline__ void setup_timer(void)
{
extern int iic_control (unsigned char, int, char *, int);
unsigned int year, mon, day, hour, min, sec;
char buf[8];
outb(LATCH & 255, IOC_T0LTCHL);
outb(LATCH >> 8, IOC_T0LTCHH);
outb(0, IOC_T0GO);
iic_control (0xa0, 0xc0, buf, 1);
year = buf[0];
if ((year += 1900) < 1970)
year += 100;
xtime.tv_sec = get_rtc_time();
iic_control (0xa0, 2, buf, 5);
mon = buf[4] & 0x1f;
day = buf[3] & 0x3f;
hour = buf[2];
min = buf[1];
sec = buf[0];
BCD_TO_BIN(mon);
BCD_TO_BIN(day);
BCD_TO_BIN(hour);
BCD_TO_BIN(min);
BCD_TO_BIN(sec);
return mktime(year, mon, day, hour, min, sec);
setup_arm_irq(IRQ_TIMER, &timerirq);
}
......@@ -5,8 +5,6 @@
*/
#define VIDMEM ((char *)0x02000000)
#include "../arch/arm/drivers/char/font.h"
int video_num_columns, video_num_lines, video_size_row;
int white, bytes_per_char_h;
extern unsigned long con_charconvtable[256];
......
/*
* linux/include/asm-arm/arch-ebsa110/a.out.h
*
* Copyright (C) 1996 Russell King
* Copyright (C) 1996-1999 Russell King
*/
#ifndef __ASM_ARCH_A_OUT_H
#define __ASM_ARCH_A_OUT_H
#ifdef __KERNEL__
#define STACK_TOP ((current->personality==PER_LINUX_32BIT)? 0xc0000000 : 0x04000000)
#endif
#include <asm/arch/memory.h>
#define STACK_TOP \
((current->personality == PER_LINUX_32BIT) ? \
TASK_SIZE : 0x04000000)
#endif
/*
* linux/include/asm-arm/arch-ebsa110/hardware.h
*
* Copyright (C) 1996,1997,1998 Russell King.
* Copyright (C) 1996-1999 Russell King.
*
* This file contains the hardware definitions of the EBSA-110.
*/
#ifndef __ASM_ARCH_HARDWARE_H
#define __ASM_ARCH_HARDWARE_H
/*
* What hardware must be present
*/
#define HAS_PCIO
#ifndef __ASSEMBLER__
/*
......@@ -23,28 +17,28 @@
#define PIT_T2 ((volatile unsigned char *)0xf2000009)
#define PIT_T1 ((volatile unsigned char *)0xf2000005)
#define PIT_T0 ((volatile unsigned char *)0xf2000001)
#define PCIO_BASE 0xf0000000
/*
* Mapping areas
*/
#define IO_BASE 0xe0000000
#define IO_SIZE 0x20000000
#define IO_START 0xe0000000
/*
* RAM definitions
*/
#define MAPTOPHYS(a) ((unsigned long)(a) - PAGE_OFFSET)
#define KERNTOPHYS(a) ((unsigned long)(&a))
#define KERNEL_BASE (0xc0008000)
#define FLUSH_BASE_PHYS 0x40000000
#else
#define PCIO_BASE 0xf0000000
#define IO_BASE 0
#endif
#define IO_SIZE 0x20000000
#define IO_START 0xe0000000
#define FLUSH_BASE 0xdf000000
#define PCIO_BASE 0xf0000000
#endif
......@@ -11,6 +11,8 @@
#define IRQ_MSET ((volatile unsigned char *)0xf2c00000)
#define IRQ_MASK ((volatile unsigned char *)0xf2c00000)
#define fixup_irq(x) (x)
static void ebsa110_mask_and_ack_irq(unsigned int irq)
{
*IRQ_MCLR = 1 << irq;
......
/*
* linux/include/asm-arm/arch-ebsa110/mmu.h
* linux/include/asm-arm/arch-ebsa110/memory.h
*
* Copyright (c) 1996,1997,1998 Russell King.
* Copyright (c) 1996-1999 Russell King.
*
* Changelog:
* 20-10-1996 RMK Created
* 31-12-1997 RMK Fixed definitions to reduce warnings
* 20-Oct-1996 RMK Created
* 31-Dec-1997 RMK Fixed definitions to reduce warnings
* 21-Mar-1999 RMK Renamed to memory.h
* RMK Moved TASK_SIZE and PAGE_OFFSET here
*/
#ifndef __ASM_ARCH_MMU_H
#define __ASM_ARCH_MMU_H
#ifndef __ASM_ARCH_MEMORY_H
#define __ASM_ARCH_MEMORY_H
/*
* Task size: 3GB
*/
#define TASK_SIZE (0xc0000000UL)
/*
* Page offset: 3GB
*/
#define PAGE_OFFSET (0xc0000000UL)
#define __virt_to_phys__is_a_macro
#define __virt_to_phys(vpage) ((vpage) - PAGE_OFFSET)
......
/*
* linux/include/asm-arm/arch-ebsa110/mmap.h
*
* Copyright (C) 1996,1997,1998 Russell King
*/
/*
* Dummy oldlatches.h
*
* Copyright (C) 1996 Russell King
*/
#ifdef __need_oldlatches
#error "Old latches not present in this (rpc) machine"
#endif
/*
* linux/include/asm-arm/arch-ebsa110/processor.h
*
* Copyright (C) 1996,1997,1998 Russell King
* Copyright (C) 1996-1999 Russell King
*
* Changelog:
* 21-Mar-1999 RMK Added asm/arch/memory.h
*/
#ifndef __ASM_ARCH_PROCESSOR_H
#define __ASM_ARCH_PROCESSOR_H
#include <asm/arch/memory.h>
/*
* Bus types
*/
......@@ -15,17 +20,9 @@
#define MCA_bus 0
#define MCA_bus__is_a_macro /* for versions in ksyms.c */
/*
* User space: 3GB
*/
#define TASK_SIZE (0xc0000000UL)
/* This decides where the kernel will search for a free chunk of vm
* space during mmap's.
*/
#define TASK_UNMAPPED_BASE (TASK_SIZE / 3)
#define INIT_MMAP \
{ &init_mm, 0, 0, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, NULL, &init_mm.mmap }
#endif
......@@ -38,63 +38,67 @@ extern __inline__ unsigned long gettimeoffset (void)
return 0;
}
#ifndef DIVISOR
extern __inline__ int reset_timer (void)
static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
*PIT_T1 = (PIT1_COUNT) & 0xff;
*PIT_T1 = (PIT1_COUNT) >> 8;
return 1;
}
#else
extern __inline__ int reset_timer (void)
{
static unsigned int divisor;
#ifdef CONFIG_LEDS
static int count = 50;
#endif
*PIT_T1 = (PIT1_COUNT) & 0xff;
*PIT_T1 = (PIT1_COUNT) >> 8;
#ifdef CONFIG_LEDS
if (--count == 0) {
count = 50;
leds_event(led_timer);
{
static int count = 50;
if (--count == 0) {
count = 50;
leds_event(led_timer);
}
}
#endif
if (divisor == 0) {
divisor = DIVISOR - 1;
return 1;
{
#ifdef DIVISOR
static unsigned int divisor;
if (divisor-- == 0) {
divisor = DIVISOR - 1;
#else
{
#endif
do_timer(regs);
}
}
divisor -= 1;
return 0;
}
#endif
/*
* We don't have a RTC to update!
*/
#define update_rtc()
static struct irqaction timerirq = {
timer_interrupt,
0,
0,
"timer",
NULL,
NULL
};
/*
* Set up timer interrupt, and return the current time in seconds.
*/
extern __inline__ unsigned long setup_timer (void)
extern __inline__ void setup_timer(void)
{
/*
* Timer 1, mode 0, 16-bit, autoreload
*/
*PIT_CTRL = 0x70;
/*
* Refresh counter clocked at 47.8MHz/7 = 146.4ns
* We want centi-second interrupts
*/
reset_timer ();
*PIT_T1 = (PIT1_COUNT) & 0xff;
*PIT_T1 = (PIT1_COUNT) >> 8;
/*
* Default the date to 1 Jan 1970 0:0:0
* You will have to run a time daemon to set the
* clock correctly at bootup
*/
return mktime(1970, 1, 1, 0, 0, 0);
xtime.tv_sec = mktime(1970, 1, 1, 0, 0, 0);
setup_arm_irq(IRQ_TIMER, &timerirq);
}
/*
* linux/include/asm-arm/arch-ebsa110/a.out.h
*
* Copyright (C) 1996 Russell King
* Copyright (C) 1996-1999 Russell King
*/
#ifndef __ASM_ARCH_A_OUT_H
#define __ASM_ARCH_A_OUT_H
#ifdef __KERNEL__
#define STACK_TOP ((current->personality==PER_LINUX_32BIT)? 0xc0000000 : 0x04000000)
#endif
#include <asm/arch/memory.h>
#define STACK_TOP \
((current->personality == PER_LINUX_32BIT) ? \
TASK_SIZE : 0x04000000)
#endif
......@@ -3,8 +3,8 @@
*
* Architecture DMA routines
*
* Copyright (C) 1998 Russell King
* Copyright (C) 1998 Philip Blundell
* Copyright (C) 1998,1999 Russell King
* Copyright (C) 1998,1999 Philip Blundell
*/
#ifndef __ASM_ARCH_DMA_H
#define __ASM_ARCH_DMA_H
......@@ -15,12 +15,16 @@
#define MAX_DMA_ADDRESS 0xffffffff
/*
* The 21285 has two internal DMA channels; we call these 0 and 1.
* The 21285 has two internal DMA channels; we call these 8 and 9.
* On CATS hardware we have an additional eight ISA dma channels
* numbered 2..9.
* numbered 0..7.
*/
#define _ISA_DMA(x) (0+(x))
#define _DC21285_DMA(x) (8+(x))
#define MAX_DMA_CHANNELS 10
#define DMA_ISA_BASE 2
#define DMA_FLOPPY (DMA_ISA_BASE + 2)
#define DMA_FLOPPY _ISA_DMA(2)
#define DMA_ISA_CASCADE _ISA_DMA(4)
#endif /* _ASM_ARCH_DMA_H */
/*
* linux/include/asm-arm/arch-ebsa285/hardware.h
*
* Copyright (C) 1998 Russell King.
* Copyright (C) 1998-1999 Russell King.
*
* This file contains the hardware definitions of the EBSA-285.
*/
#ifndef __ASM_ARCH_HARDWARE_H
#define __ASM_ARCH_HARDWARE_H
#include <linux/config.h>
#include <asm/arch/memory.h>
/* Logical Physical
#ifdef CONFIG_HOST_FOOTBRIDGE
/* Virtual Physical
* 0xfff00000 0x40000000 X-Bus
* 0xffe00000 0x7c000000 PCI I/O space
* 0xff000000 0x7c000000 PCI I/O space
*
* 0xfe000000 0x42000000 CSR
* 0xfd000000 0x78000000 Outbound write flush
* 0xfc000000 0x79000000 PCI IACK/special space
*
* 0xf9000000 0x7a010000 PCI Config type 1
* 0xf8000000 0x7b010000 PCI Config type 0
* 0xf9000000 0x7a000000 PCI Config type 1
* 0xf8000000 0x7b000000 PCI Config type 0
*
*/
#define XBUS_SIZE 0x00100000
#define XBUS_BASE 0xfff00000
#include <asm/dec21285.h>
#define IO_BASE 0xe0000000
#define PCIO_BASE 0xffe00000
#define PCI_IACK 0xfc000000
#define PCIO_SIZE 0x00100000
#define PCIO_BASE 0xff000000
#define XBUS_LEDS ((volatile unsigned char *)0xfff12000)
#define ARMCSR_SIZE 0x01000000
#define ARMCSR_BASE 0xfe000000
#define WFLUSH_SIZE 0x01000000
#define WFLUSH_BASE 0xfd000000
#define PCIIACK_SIZE 0x01000000
#define PCIIACK_BASE 0xfc000000
#define PCICFG1_SIZE 0x01000000
#define PCICFG1_BASE 0xf9000000
#define PCICFG0_SIZE 0x01000000
#define PCICFG0_BASE 0xf8000000
#define PCIMEM_SIZE 0x18000000
#define PCIMEM_BASE 0xe0000000
#define FLUSH_SIZE 0x00100000
#define FLUSH_BASE 0xdf000000
#define FLASH_SIZE 0x00400000
#define FLASH_BASE 0xd8000000
#elif defined(CONFIG_ARCH_CO285)
#define PCIMEM_SIZE 0x80000000
#define PCIMEM_BASE 0x80000000
#define FLASH_SIZE 0x01000000
#define FLASH_BASE 0x7f000000
#define FLUSH_SIZE 0x00100000
#define FLUSH_BASE 0x7e000000
#define WFLUSH_SIZE 0x01000000
#define WFLUSH_BASE 0x7d000000
#define ARMCSR_SIZE 0x00100000
#define ARMCSR_BASE 0x7cf00000
#define XBUS_SIZE 0x00020000
#define XBUS_BASE 0x7cee0000
#define PCIO_SIZE 0x00010000
#define PCIO_BASE 0x7ced0000
#else
#error Add your add-in architecture here
#endif
#define XBUS_LEDS ((volatile unsigned char *)(XBUS_BASE + 0x12000))
#define XBUS_LED_AMBER (1 << 0)
#define XBUS_LED_GREEN (1 << 1)
#define XBUS_LED_RED (1 << 2)
#define XBUS_LED_TOGGLE (1 << 8)
#define XBUS_SWITCH ((volatile unsigned char *)0xfff12000)
#define XBUS_SWITCH ((volatile unsigned char *)(XBUS_BASE + 0x12000))
#define XBUS_SWITCH_SWITCH ((*XBUS_SWITCH) & 15)
#define XBUS_SWITCH_J17_13 ((*XBUS_SWITCH) & (1 << 4))
#define XBUS_SWITCH_J17_11 ((*XBUS_SWITCH) & (1 << 5))
#define XBUS_SWITCH_J17_9 ((*XBUS_SWITCH) & (1 << 6))
#define KERNTOPHYS(a) ((unsigned long)(&a))
#define PARAMS_OFFSET 0x0100
#define PARAMS_BASE (PAGE_OFFSET + PARAMS_OFFSET)
#define FLUSH_BASE_PHYS 0x50000000
/* PIC irq control */
#define PIC_LO 0x20
#define PIC_MASK_LO 0x21
#define PIC_HI 0xA0
#define PIC_MASK_HI 0xA1
/* GPIO pins */
#define GPIO_CCLK 0x800
#define GPIO_DSCLK 0x400
#define GPIO_E2CLK 0x200
#define GPIO_IOLOAD 0x100
#define GPIO_RED_LED 0x080
#define GPIO_WDTIMER 0x040
#define GPIO_DATA 0x020
#define GPIO_IOCLK 0x010
#define GPIO_DONE 0x008
#define GPIO_FAN 0x004
#define GPIO_GREEN_LED 0x002
#define GPIO_RESET 0x001
/* CPLD pins */
#define CPLD_DSRESET 8
#define CPLD_UNMUTE 2
#ifndef __ASSEMBLY__
extern void gpio_modify_op(int mask, int set);
extern void gpio_modify_io(int mask, int in);
extern int gpio_read(void);
extern void cpld_modify(int mask, int set);
#endif
#endif
......@@ -16,34 +16,37 @@
* has the constant-optimised IO
*/
#undef ARCH_IO_DELAY
#define ARCH_READWRITE
/*
* Dynamic IO functions - let the compiler
* optimize the expressions
*/
#define DECLARE_DYN_OUT(fnsuffix,instr,typ) \
extern __inline__ void __out##fnsuffix (unsigned int value, unsigned int port) \
{ \
__asm__ __volatile__( \
"str%?" ##instr## " %0, [%1, %2] @ out"###fnsuffix \
: \
: "r" (value), "r" (PCIO_BASE), typ (port)); \
#define DECLARE_DYN_OUT(fnsuffix,instr,typ) \
extern __inline__ void \
__out##fnsuffix (unsigned int value, unsigned int port) \
{ \
__asm__ __volatile__( \
"str%?" ##instr## " %0, [%1, %2] @ out"###fnsuffix \
: \
: "r" (value), "r" (PCIO_BASE), typ (port)); \
}
#define DECLARE_DYN_IN(sz,fnsuffix,instr,typ) \
extern __inline__ unsigned sz __in##fnsuffix (unsigned int port) \
{ \
unsigned long value; \
__asm__ __volatile__( \
"ldr%?" ##instr## " %0, [%1, %2] @ in"###fnsuffix \
: "=&r" (value) \
: "r" (PCIO_BASE), typ (port)); \
return (unsigned sz)value; \
#define DECLARE_DYN_IN(sz,fnsuffix,instr,typ) \
extern __inline__ unsigned sz \
__in##fnsuffix (unsigned int port) \
{ \
unsigned long value; \
__asm__ __volatile__( \
"ldr%?" ##instr## " %0, [%1, %2] @ in"###fnsuffix \
: "=&r" (value) \
: "r" (PCIO_BASE), typ (port)); \
return (unsigned sz)value; \
}
extern __inline__ unsigned int __ioaddr (unsigned int port) \
{ \
return (unsigned int)(PCIO_BASE + port); \
extern __inline__ unsigned int __ioaddr (unsigned int port) \
{ \
return (unsigned int)(PCIO_BASE + port); \
}
#define DECLARE_IO(sz,fnsuffix,instr,typ) \
......@@ -64,65 +67,65 @@ DECLARE_IO(long,l,"","Jr")
* These have to be macros for the 'J' constraint to work -
* +/-4096 immediate operand.
*/
#define __outbc(value,port) \
({ \
__asm__ __volatile__( \
"str%?b %0, [%1, %2] @ outbc" \
: \
: "r" (value), "r" (PCIO_BASE), "Jr" (port)); \
#define __outbc(value,port) \
({ \
__asm__ __volatile__( \
"str%?b %0, [%1, %2] @ outbc" \
: \
: "r" (value), "r" (PCIO_BASE), "Jr" (port)); \
})
#define __inbc(port) \
({ \
unsigned char result; \
__asm__ __volatile__( \
"ldr%?b %0, [%1, %2] @ inbc" \
: "=r" (result) \
: "r" (PCIO_BASE), "Jr" (port)); \
result; \
#define __inbc(port) \
({ \
unsigned char result; \
__asm__ __volatile__( \
"ldr%?b %0, [%1, %2] @ inbc" \
: "=r" (result) \
: "r" (PCIO_BASE), "Jr" (port)); \
result; \
})
#define __outwc(value,port) \
({ \
__asm__ __volatile__( \
"str%?h %0, [%1, %2] @ outwc" \
: \
: "r" (value), "r" (PCIO_BASE), "r" (port)); \
#define __outwc(value,port) \
({ \
__asm__ __volatile__( \
"str%?h %0, [%1, %2] @ outwc" \
: \
: "r" (value), "r" (PCIO_BASE), "r" (port)); \
})
#define __inwc(port) \
({ \
unsigned short result; \
__asm__ __volatile__( \
"ldr%?h %0, [%1, %2] @ inwc" \
: "=r" (result) \
: "r" (PCIO_BASE), "r" (port)); \
result & 0xffff; \
#define __inwc(port) \
({ \
unsigned short result; \
__asm__ __volatile__( \
"ldr%?h %0, [%1, %2] @ inwc" \
: "=r" (result) \
: "r" (PCIO_BASE), "r" (port)); \
result & 0xffff; \
})
#define __outlc(value,port) \
({ \
__asm__ __volatile__( \
"str%? %0, [%1, %2] @ outlc" \
: \
: "r" (value), "r" (PCIO_BASE), "Jr" (port)); \
#define __outlc(value,port) \
({ \
__asm__ __volatile__( \
"str%? %0, [%1, %2] @ outlc" \
: \
: "r" (value), "r" (PCIO_BASE), "Jr" (port)); \
})
#define __inlc(port) \
({ \
unsigned long result; \
__asm__ __volatile__( \
"ldr%? %0, [%1, %2] @ inlc" \
: "=r" (result) \
: "r" (PCIO_BASE), "Jr" (port)); \
result; \
#define __inlc(port) \
({ \
unsigned long result; \
__asm__ __volatile__( \
"ldr%? %0, [%1, %2] @ inlc" \
: "=r" (result) \
: "r" (PCIO_BASE), "Jr" (port)); \
result; \
})
#define __ioaddrc(port) \
({ \
unsigned long addr; \
addr = PCIO_BASE + port; \
addr; \
#define __ioaddrc(port) \
({ \
unsigned long addr; \
addr = PCIO_BASE + port; \
addr; \
})
/*
......@@ -130,20 +133,22 @@ DECLARE_IO(long,l,"","Jr")
*
* IO address has already been translated to a virtual address
*/
#define outb_t(v,p) \
#define outb_t(v,p) \
(*(volatile unsigned char *)(p) = (v))
#define inb_t(p) \
#define inb_t(p) \
(*(volatile unsigned char *)(p))
#define outl_t(v,p) \
#define outl_t(v,p) \
(*(volatile unsigned long *)(p) = (v))
#define inl_t(p) \
#define inl_t(p) \
(*(volatile unsigned long *)(p))
/*
* ioremap support
* ioremap support - validate a PCI memory address,
* and convert a PCI memory address to a physical
* address for the page tables.
*/
#define valid_ioaddr(iomem,size) ((iomem) < 0x80000000 && (iomem) + (size) <= 0x80000000)
#define io_to_phys(iomem) ((iomem) + DC21285_PCI_MEM)
......@@ -153,58 +158,48 @@ DECLARE_IO(long,l,"","Jr")
* is using read*() and so on with addresses they didn't get from ioremap
* this can go away.
*/
#define IO_FUDGE_FACTOR 0xe0000000
#define IO_FUDGE_FACTOR PCIMEM_BASE
extern inline void *ioremap(unsigned long iomem_addr, unsigned long size)
{
unsigned long phys_addr;
if (!valid_ioaddr(iomem_addr, size))
return NULL;
phys_addr = io_to_phys(iomem_addr & PAGE_MASK);
return (void *)((unsigned long)__ioremap(phys_addr, size, 0)
- IO_FUDGE_FACTOR);
}
/*
* ioremap takes a PCI memory address, as specified in
* linux/Documentation/IO-mapping.txt
*/
#define ioremap(iomem_addr,size) \
({ \
unsigned long _addr = (iomem_addr), _size = (size); \
void *_ret = NULL; \
if (valid_ioaddr(_addr, _size)) { \
_addr = io_to_phys(_addr); \
_ret = __ioremap(_addr, _size, 0) - IO_FUDGE_FACTOR; \
} \
_ret; })
#define ioremap_nocache(iomem_addr,size) ioremap((iomem_addr),(size))
extern void iounmap(void *addr);
/*
* We'd probably be better off with these as macros rather than functions.
* Firstly that would be more efficient and secondly we could do with the
* ability to stop GCC whinging about type conversions. --philb
*/
static inline void writeb(unsigned char b, unsigned int addr)
{
*(volatile unsigned char *)(IO_FUDGE_FACTOR + (addr)) = b;
}
static inline unsigned char readb(unsigned int addr)
{
return *(volatile unsigned char *)(IO_FUDGE_FACTOR + (addr));
#define DECLARE_PCI_WRITE(typ,fnsuffix) \
static inline void write##fnsuffix(unsigned typ val, unsigned int addr) \
{ \
*(volatile unsigned typ *)(IO_FUDGE_FACTOR + addr) = val; \
}
static inline void writew(unsigned short b, unsigned int addr)
{
*(volatile unsigned short *)(IO_FUDGE_FACTOR + (addr)) = b;
#define DECLARE_PCI_READ(typ,fnsuffix) \
static inline unsigned typ read##fnsuffix (unsigned int addr) \
{ \
return *(volatile unsigned typ *)(IO_FUDGE_FACTOR + addr); \
}
static inline unsigned short readw(unsigned int addr)
{
return *(volatile unsigned short *)(IO_FUDGE_FACTOR + (addr));
}
#define DECLARE_PCI(typ,fnsuffix) \
DECLARE_PCI_WRITE(typ,fnsuffix) \
DECLARE_PCI_READ(typ,fnsuffix)
static inline void writel(unsigned long b, unsigned int addr)
{
*(volatile unsigned long *)(IO_FUDGE_FACTOR + (addr)) = b;
}
DECLARE_PCI(char,b)
DECLARE_PCI(short,w)
DECLARE_PCI(long,l)
static inline unsigned short readl(unsigned int addr)
{
return *(volatile unsigned long *)(IO_FUDGE_FACTOR + (addr));
}
#undef DECLARE_PCI
#undef DECLARE_PCI_READ
#undef DECLARE_PCI_WRITE
#endif
......@@ -4,136 +4,205 @@
* Copyright (C) 1996-1998 Russell King
*
* Changelog:
* 22-08-1998 RMK Restructured IRQ routines
* 03-09-1998 PJB Merged CATS support
* 22-Aug-1998 RMK Restructured IRQ routines
* 03-Sep-1998 PJB Merged CATS support
* 20-Jan-1998 RMK Started merge of EBSA286, CATS and NetWinder
* 26-Jan-1999 PJB Don't use IACK on CATS
* 16-Mar-1999 RMK Added autodetect of ISA PICs
*/
#include <linux/config.h>
#include <asm/hardware.h>
#include <asm/dec21285.h>
#include <asm/irq.h>
static void ebsa285_mask_irq(unsigned int irq)
/*
* Footbridge IRQ translation table
* Converts from our IRQ numbers into FootBridge masks
*/
static int dc21285_irq_mask[] = {
IRQ_MASK_UART_RX, /* 0 */
IRQ_MASK_UART_TX, /* 1 */
IRQ_MASK_TIMER1, /* 2 */
IRQ_MASK_TIMER2, /* 3 */
IRQ_MASK_TIMER3, /* 4 */
IRQ_MASK_IN0, /* 5 */
IRQ_MASK_IN1, /* 6 */
IRQ_MASK_IN2, /* 7 */
IRQ_MASK_IN3, /* 8 */
IRQ_MASK_DOORBELLHOST, /* 9 */
IRQ_MASK_DMA1, /* 10 */
IRQ_MASK_DMA2, /* 11 */
IRQ_MASK_PCI, /* 12 */
IRQ_MASK_SDRAMPARITY, /* 13 */
IRQ_MASK_I2OINPOST, /* 14 */
IRQ_MASK_PCI_ERR /* 15 */
};
static int isa_irq = -1;
static inline int fixup_irq(unsigned int irq)
{
*CSR_IRQ_DISABLE = 1 << irq;
#ifdef CONFIG_HOST_FOOTBRIDGE
if (irq == isa_irq)
irq = *(unsigned char *)PCIIACK_BASE;
#endif
return irq;
}
static void ebsa285_unmask_irq(unsigned int irq)
static void dc21285_mask_irq(unsigned int irq)
{
*CSR_IRQ_ENABLE = 1 << irq;
*CSR_IRQ_DISABLE = dc21285_irq_mask[irq & 15];
}
#ifdef CONFIG_CATS
static void dc21285_unmask_irq(unsigned int irq)
{
*CSR_IRQ_ENABLE = dc21285_irq_mask[irq & 15];
}
/*
* This contains the irq mask for both 8259A irq controllers,
*/
static unsigned int isa_irq_mask = 0xffff;
static void isa_mask_pic_lo_irq(unsigned int irq)
{
unsigned int mask = 1 << (irq & 7);
outb(inb(PIC_MASK_LO) | mask, PIC_MASK_LO);
}
#define cached_21 (isa_irq_mask & 0xff)
#define cached_A1 ((isa_irq_mask >> 8) & 0xff)
static void isa_mask_ack_pic_lo_irq(unsigned int irq)
{
unsigned int mask = 1 << (irq & 7);
#define update_8259(_irq) \
if ((_irq) & 8) \
outb(cached_A1, 0xa1); \
else \
outb(cached_21, 0x21);
outb(inb(PIC_MASK_LO) | mask, PIC_MASK_LO);
outb(0x20, PIC_LO);
}
static void isa_interrupt(int irq, void *h, struct pt_regs *regs)
static void isa_unmask_pic_lo_irq(unsigned int irq)
{
asmlinkage void do_IRQ(int irq, struct pt_regs * regs);
unsigned int irqbits = inb(0x20) | (inb(0xa0) << 8), irqnr = 0;
irqbits &= ~(1<<2); /* don't try to service the cascade */
while (irqbits) {
if (irqbits & 1)
do_IRQ(32 + irqnr, regs);
irqbits >>= 1;
irqnr++;
}
unsigned int mask = 1 << (irq & 7);
outb(inb(PIC_MASK_LO) & ~mask, PIC_MASK_LO);
}
static void no_action(int cpl, void *dev_id, struct pt_regs *regs) { }
static void isa_mask_pic_hi_irq(unsigned int irq)
{
unsigned int mask = 1 << (irq & 7);
static struct irqaction irq_isa =
{ isa_interrupt, SA_INTERRUPT, 0, "ISA PIC", NULL, NULL };
static struct irqaction irq_cascade =
{ no_action, 0, 0, "cascade", NULL, NULL };
outb(inb(PIC_MASK_HI) | mask, PIC_MASK_HI);
}
static void cats_mask_and_ack_isa_irq(unsigned int irq)
static void isa_mask_ack_pic_hi_irq(unsigned int irq)
{
isa_irq_mask |= (1 << (irq - 32));
update_8259(irq);
if (irq & 8) {
inb(0xA1); /* DUMMY */
outb(cached_A1,0xA1);
outb(0x62,0x20); /* Specific EOI to cascade */
outb(0x20,0xA0);
} else {
inb(0x21); /* DUMMY */
outb(cached_21,0x21);
outb(0x20,0x20);
}
unsigned int mask = 1 << (irq & 7);
outb(inb(PIC_MASK_HI) | mask, PIC_MASK_HI);
outb(0x62, PIC_LO);
outb(0x20, PIC_HI);
}
static void cats_mask_isa_irq(unsigned int irq)
static void isa_unmask_pic_hi_irq(unsigned int irq)
{
isa_irq_mask |= (1 << (irq - 32));
update_8259(irq);
unsigned int mask = 1 << (irq & 7);
outb(inb(PIC_MASK_HI) & ~mask, PIC_MASK_HI);
}
static void cats_unmask_isa_irq(unsigned int irq)
static void no_action(int cpl, void *dev_id, struct pt_regs *regs)
{
isa_irq_mask &= ~(1 << (irq - 32));
update_8259(irq);
}
#endif
static struct irqaction irq_cascade = { no_action, 0, 0, "cascade", NULL, NULL };
static __inline__ void irq_init_irq(void)
{
int irq;
/*
* setup DC21285 IRQs
*/
*CSR_IRQ_DISABLE = -1;
*CSR_FIQ_DISABLE = -1;
for (irq = 0; irq < NR_IRQS; irq++) {
for (irq = _DC21285_IRQ(0); irq < _DC21285_IRQ(16); irq++) {
irq_desc[irq].valid = 1;
irq_desc[irq].probe_ok = 1;
#ifdef CONFIG_CATS
if (machine_is_cats() && IRQ_IS_ISA(irq)) {
irq_desc[irq].mask_ack = cats_mask_and_ack_isa_irq;
irq_desc[irq].mask = cats_mask_isa_irq;
irq_desc[irq].unmask = cats_unmask_isa_irq;
irq_desc[irq].mask_ack = dc21285_mask_irq;
irq_desc[irq].mask = dc21285_mask_irq;
irq_desc[irq].unmask = dc21285_unmask_irq;
}
/*
* Determine the ISA settings for
* the machine we're running on.
*/
switch (machine_arch_type) {
default:
isa_irq = -1;
break;
case MACH_TYPE_EBSA285:
/* The following is dependent on which slot
* you plug the Southbridge card into. We
* currently assume that you plug it into
* the right-hand most slot.
*/
isa_irq = IRQ_PCI;
break;
case MACH_TYPE_CATS:
isa_irq = IRQ_IN2;
break;
case MACH_TYPE_NETWINDER:
isa_irq = IRQ_IN3;
break;
}
if (isa_irq != -1) {
/*
* Setup, and then probe for an ISA PIC
*/
outb(0x11, PIC_LO);
outb(_ISA_IRQ(0), PIC_MASK_LO); /* IRQ number */
outb(0x04, PIC_MASK_LO); /* Slave on Ch2 */
outb(0x01, PIC_MASK_LO); /* x86 */
outb(0xf5, PIC_MASK_LO); /* pattern: 11110101 */
outb(0x11, PIC_HI);
outb(_ISA_IRQ(8), PIC_MASK_HI); /* IRQ number */
outb(0x02, PIC_MASK_HI); /* Slave on Ch1 */
outb(0x01, PIC_MASK_HI); /* x86 */
outb(0xfa, PIC_MASK_HI); /* pattern: 11111010 */
// outb(0x68, PIC_LO); /* enable special mode */
// outb(0x68, PIC_HI); /* enable special mode */
outb(0x0b, PIC_LO);
outb(0x0b, PIC_HI);
if (inb(PIC_MASK_LO) == 0xf5 && inb(PIC_MASK_HI) == 0xfa) {
outb(0xff, PIC_MASK_LO);/* mask all IRQs */
outb(0xff, PIC_MASK_HI);/* mask all IRQs */
} else
#endif
{
irq_desc[irq].mask_ack = ebsa285_mask_irq;
irq_desc[irq].mask = ebsa285_mask_irq;
irq_desc[irq].unmask = ebsa285_unmask_irq;
}
isa_irq = -1;
}
#ifdef CONFIG_CATS
if (machine_is_cats()) {
request_region(0x20, 2, "pic1");
request_region(0xa0, 2, "pic2");
/* set up master 8259 */
outb(0x11, 0x20);
outb(0, 0x21);
outb(1<<2, 0x21);
outb(0x1, 0x21);
outb(0xff, 0x21);
outb(0x68, 0x20);
outb(0xa, 0x20);
/* set up slave 8259 */
outb(0x11, 0xa0);
outb(0, 0xa1);
outb(2, 0xa1);
outb(0x1, 0xa1);
outb(0xff, 0xa1);
outb(0x68, 0xa0);
outb(0xa, 0xa0);
setup_arm_irq(IRQ_ISA_PIC, &irq_isa);
if (isa_irq != -1) {
for (irq = _ISA_IRQ(0); irq < _ISA_IRQ(8); irq++) {
irq_desc[irq].valid = 1;
irq_desc[irq].probe_ok = 1;
irq_desc[irq].mask_ack = isa_mask_ack_pic_lo_irq;
irq_desc[irq].mask = isa_mask_pic_lo_irq;
irq_desc[irq].unmask = isa_unmask_pic_lo_irq;
}
for (irq = _ISA_IRQ(8); irq < _ISA_IRQ(16); irq++) {
irq_desc[irq].valid = 1;
irq_desc[irq].probe_ok = 1;
irq_desc[irq].mask_ack = isa_mask_ack_pic_hi_irq;
irq_desc[irq].mask = isa_mask_pic_hi_irq;
irq_desc[irq].unmask = isa_unmask_pic_hi_irq;
}
request_region(PIC_LO, 2, "pic1");
request_region(PIC_HI, 2, "pic2");
setup_arm_irq(IRQ_ISA_CASCADE, &irq_cascade);
setup_arm_irq(isa_irq, &irq_cascade);
}
#endif
}
......@@ -3,55 +3,85 @@
*
* Copyright (C) 1998 Russell King
* Copyright (C) 1998 Phil Blundell
*
* Changelog:
* 20-Jan-1998 RMK Started merge of EBSA286, CATS and NetWinder
* 01-Feb-1999 PJB ISA IRQs start at 0 not 16
*/
#define NR_IRQS 48
#define NR_IRQS 32
#define NR_DC21285_IRQS 16
#define _ISA_IRQ(x) (0 + (x))
#define _DC21285_IRQ(x) (16 + (x))
/*
* This is a list of all interrupts that the 21285
* can generate
* can generate and we handle.
*/
#define IRQ_RESERVED 0
#define IRQ_SOFTIRQ 1
#define IRQ_CONRX 2
#define IRQ_CONTX 3
#define IRQ_TIMER1 4
#define IRQ_TIMER2 5
#define IRQ_TIMER3 6
#define IRQ_TIMER4 7
#define IRQ_IN0 8
#define IRQ_IN1 9
#define IRQ_IN2 10
#define IRQ_IN3 11
#define IRQ_XCS0 12
#define IRQ_XCS1 13
#define IRQ_XCS2 14
#define IRQ_DOORBELLHOST 15
#define IRQ_DMA1 16
#define IRQ_DMA2 17
#define IRQ_PCI 18
#define IRQ_BIST 22
#define IRQ_SERR 23
#define IRQ_SDRAMPARITY 24
#define IRQ_I2OINPOST 25
#define IRQ_DISCARDTIMER 27
#define IRQ_PCIDATAPARITY 28
#define IRQ_PCIMASTERABORT 29
#define IRQ_PCITARGETABORT 30
#define IRQ_PCIPARITY 31
/* IRQs 32-47 are the 16 ISA interrupts on a CATS board. */
#define IRQ_ISA_PIC IRQ_IN2
#define IRQ_IS_ISA(_x) (((_x) >= 32) && ((_x) <= 47))
#define IRQ_ISA(_x) ((_x) + 0x20)
#define IRQ_ISA_CASCADE IRQ_ISA(2)
#define IRQ_CONRX _DC21285_IRQ(0)
#define IRQ_CONTX _DC21285_IRQ(1)
#define IRQ_TIMER1 _DC21285_IRQ(2)
#define IRQ_TIMER2 _DC21285_IRQ(3)
#define IRQ_TIMER3 _DC21285_IRQ(4)
#define IRQ_IN0 _DC21285_IRQ(5)
#define IRQ_IN1 _DC21285_IRQ(6)
#define IRQ_IN2 _DC21285_IRQ(7)
#define IRQ_IN3 _DC21285_IRQ(8)
#define IRQ_DOORBELLHOST _DC21285_IRQ(9)
#define IRQ_DMA1 _DC21285_IRQ(10)
#define IRQ_DMA2 _DC21285_IRQ(11)
#define IRQ_PCI _DC21285_IRQ(12)
#define IRQ_SDRAMPARITY _DC21285_IRQ(13)
#define IRQ_I2OINPOST _DC21285_IRQ(14)
#define IRQ_PCI_ERR _DC21285_IRQ(15)
#define IRQ_ISA_TIMER _ISA_IRQ(0)
#define IRQ_ISA_KEYBOARD _ISA_IRQ(1)
#define IRQ_ISA_CASCADE _ISA_IRQ(2)
#define IRQ_ISA_UART2 _ISA_IRQ(3)
#define IRQ_ISA_UART _ISA_IRQ(4)
#define IRQ_ISA_FLOPPY _ISA_IRQ(6)
#define IRQ_ISA_PRINTER _ISA_IRQ(7)
#define IRQ_ISA_RTC_ALARM _ISA_IRQ(8)
#define IRQ_ISA_2 _ISA_IRQ(9)
#define IRQ_ISA_PS2MOUSE _ISA_IRQ(12)
#define IRQ_ISA_HARDDISK1 _ISA_IRQ(14)
#define IRQ_ISA_HARDDISK2 _ISA_IRQ(15)
#define IRQ_MASK_UART_RX (1 << 2)
#define IRQ_MASK_UART_TX (1 << 3)
#define IRQ_MASK_TIMER1 (1 << 4)
#define IRQ_MASK_TIMER2 (1 << 5)
#define IRQ_MASK_TIMER3 (1 << 6)
#define IRQ_MASK_IN0 (1 << 8)
#define IRQ_MASK_IN1 (1 << 9)
#define IRQ_MASK_IN2 (1 << 10)
#define IRQ_MASK_IN3 (1 << 11)
#define IRQ_MASK_DOORBELLHOST (1 << 15)
#define IRQ_MASK_DMA1 (1 << 16)
#define IRQ_MASK_DMA2 (1 << 17)
#define IRQ_MASK_PCI (1 << 18)
#define IRQ_MASK_SDRAMPARITY (1 << 24)
#define IRQ_MASK_I2OINPOST (1 << 25)
#define IRQ_MASK_PCI_ERR ((1 <<23) | (1 << 27) | (1 << 28) | (1 << 29) | (1 << 30) | (1 << 31))
/*
* Now map them to the Linux interrupts
* Netwinder interrupt allocations
*/
#define IRQ_TIMER IRQ_TIMER1
#define IRQ_FLOPPYDISK IRQ_ISA(6)
#define IRQ_HARDDISK IRQ_ISA(14)
#define IRQ_HARDDISK_SECONDARY IRQ_ISA(15)
#define IRQ_NETWINDER_ETHER10 IRQ_IN0
#define IRQ_NETWINDER_ETHER100 IRQ_IN1
#define IRQ_NETWINDER_VIDCOMP IRQ_IN2
#define IRQ_NETWINDER_PS2MOUSE _ISA_IRQ(5)
#define IRQ_NETWINDER_IR _ISA_IRQ(6)
#define IRQ_NETWINDER_BUTTON _ISA_IRQ(10)
#define IRQ_NETWINDER_VGA _ISA_IRQ(11)
#define IRQ_NETWINDER_SOUND _ISA_IRQ(12)
#undef RTC_IRQ
#define RTC_IRQ IRQ_ISA_RTC_ALARM
#undef AUX_IRQ
#define AUX_IRQ (machine_is_netwinder() ? IRQ_NETWINDER_PS2MOUSE : IRQ_ISA_PS2MOUSE)
#define IRQ_FLOPPYDISK IRQ_ISA_FLOPPY
#define irq_cannonicalize(_i) (((_i) == IRQ_ISA_CASCADE) ? IRQ_ISA(9) : _i)
#define irq_cannonicalize(_i) (((_i) == IRQ_ISA_CASCADE) ? IRQ_ISA_2 : _i)
This diff is collapsed.
This diff is collapsed.
/*
* linux/include/asm-arm/arch-ebsa110/mmap.h
*
* Copyright (C) 1996,1997,1998 Russell King
*/
/*
* linux/include/asm-arm/arch-ebsa285/mmu.h
*
* Copyright (c) 1996,1997,1998 Russell King.
*
* Changelog:
* 20-10-1996 RMK Created
* 31-12-1997 RMK Fixed definitions to reduce warnings
* 17-05-1998 DAG Added __virt_to_bus and __bus_to_virt functions.
* 21-11-1998 RMK Changed __virt_to_bus and __bus_to_virt to macros.
*/
#ifndef __ASM_ARCH_MMU_H
#define __ASM_ARCH_MMU_H
/*
* On ebsa285, the dram is contiguous
*/
#define __virt_to_phys__is_a_macro
#define __virt_to_phys(vpage) ((unsigned long)(vpage) - PAGE_OFFSET)
#define __phys_to_virt__is_a_macro
#define __phys_to_virt(ppage) ((unsigned long)(ppage) + PAGE_OFFSET)
#define __virt_to_bus__is_a_macro
#define __virt_to_bus(x) ((x) - 0xe0000000)
#define __bus_to_virt__is_a_macro
#define __bus_to_virt(x) ((x) + 0xe0000000)
#endif
/*
* Dummy oldlatches.h
*
* Copyright (C) 1996 Russell King
*/
#ifdef __need_oldlatches
#error "Old latches not present in this (rpc) machine"
#endif
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -9,6 +9,8 @@
#include <asm/io.h>
#define fixup_irq(x) (x)
#define INTCONT 0xffe00000
extern unsigned long soft_irq_mask;
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment