USB device file system
CONFIG_USB_DEVICEFS
If you say Y here (and to "/proc file system support" below), you
- will get a file /proc/usb/devices which lists the devices currently
- connected to your USB busses, a file /proc/usb/drivers which lists
- the USB kernel client drivers currently loaded, and for every
- connected device a file named "/proc/usb/xxx/yyy", where xxx is the
- bus number and yyy the device number; the latter files can be used
- by user space programs to talk directly to the device. These files
- are "virtual", meaning they are generated on the fly and not stored
- on the hard drive.
+ will get a file /proc/bus/usb/devices which lists the devices
+ currently connected to your USB busses, a file /proc/bus/usb/drivers
+ which lists the USB kernel client drivers currently loaded, and for
+ every connected device a file named "/proc/bus/usb/xxx/yyy", where
+ xxx is the bus number and yyy the device number; the latter files
+ can be used by user space programs to talk directly to the device.
+ These files are "virtual", meaning they are generated on the fly
+ and not stored on the hard drive.
- For the format of the /proc/usb/ files, please read
+ For the format of the /proc/bus/usb/ files, please read
Documentation/usb/proc_usb_info.txt.
Please note that this code is completely unrelated to devfs, the
VERSION = 2
PATCHLEVEL = 4
SUBLEVEL = 4
-EXTRAVERSION =-pre3
+EXTRAVERSION =-pre4
KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
define_bool CONFIG_ALPHA y
define_bool CONFIG_UID16 n
+define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y
+define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n
mainmenu_name "Kernel configuration of Linux for Alpha machines"
EXPORT_SYMBOL(synchronize_irq);
EXPORT_SYMBOL(flush_tlb_all);
EXPORT_SYMBOL(flush_tlb_mm);
-EXPORT_SYMBOL(flush_tlb_page);
EXPORT_SYMBOL(flush_tlb_range);
EXPORT_SYMBOL(smp_imb);
EXPORT_SYMBOL(cpu_data);
#endif
__up(sem);
}
-
-
-/*
- * RW Semaphores
- */
-
-void
-__down_read_failed(struct rw_semaphore *sem, int count)
-{
- DECLARE_WAITQUEUE(wait, current);
-
- retry_down:
- if (count < 0) {
- /* Waiting on multiple readers and/or writers. */
-
- /* Undo the acquisition we started in down_read. */
- atomic_inc(&sem->count);
-
- current->state = TASK_UNINTERRUPTIBLE;
- wmb();
- add_wait_queue(&sem->wait, &wait);
- mb();
- while (atomic_read(&sem->count) < 0) {
- schedule();
- set_task_state(current, TASK_UNINTERRUPTIBLE);
- }
-
- remove_wait_queue(&sem->wait, &wait);
- current->state = TASK_RUNNING;
-
- mb();
- count = atomic_dec_return(&sem->count);
- if (count <= 0)
- goto retry_down;
- } else {
- /* Waiting on exactly one writer. */
-
- current->state = TASK_UNINTERRUPTIBLE;
- wmb();
- add_wait_queue(&sem->wait, &wait);
- mb();
-
- while (!test_and_clear_bit(0, &sem->granted)) {
- schedule();
- set_task_state(current, TASK_UNINTERRUPTIBLE);
- }
-
- remove_wait_queue(&sem->wait, &wait);
- current->state = TASK_RUNNING;
- }
-}
-
-void
-__down_write_failed(struct rw_semaphore *sem, int count)
-{
- DECLARE_WAITQUEUE(wait, current);
-
- retry_down:
- if (count + RW_LOCK_BIAS < 0) {
- /* Waiting on multiple readers and/or writers. */
-
- /* Undo the acquisition we started in down_write. */
- atomic_add(RW_LOCK_BIAS, &sem->count);
-
- current->state = TASK_UNINTERRUPTIBLE;
- wmb();
- add_wait_queue_exclusive(&sem->wait, &wait);
- mb();
-
- while (atomic_read(&sem->count) + RW_LOCK_BIAS < 0) {
- schedule();
- set_task_state(current, TASK_UNINTERRUPTIBLE);
- }
-
- remove_wait_queue(&sem->wait, &wait);
- current->state = TASK_RUNNING;
-
- count = atomic_sub_return(RW_LOCK_BIAS, &sem->count);
- if (count != 0)
- goto retry_down;
- } else {
- /* Waiting on exactly one writer. */
-
- current->state = TASK_UNINTERRUPTIBLE;
- wmb();
- add_wait_queue_exclusive(&sem->wait, &wait);
- mb();
-
- while (!test_and_clear_bit(1, &sem->granted)) {
- schedule();
- set_task_state(current, TASK_UNINTERRUPTIBLE);
- }
-
- remove_wait_queue(&sem->write_bias_wait, &wait);
- current->state = TASK_RUNNING;
-
- /* If the lock is currently unbiased, awaken the sleepers.
- FIXME: This wakes up the readers early in a bit of a
- stampede -> bad! */
- count = atomic_read(&sem->count);
- if (__builtin_expect(count >= 0, 0))
- wake_up(&sem->wait);
- }
-}
-
-void
-__rwsem_wake(struct rw_semaphore *sem, int readers)
-{
- if (readers) {
- if (test_and_set_bit(0, &sem->granted))
- BUG();
- wake_up(&sem->wait);
- } else {
- if (test_and_set_bit(1, &sem->granted))
- BUG();
- wake_up(&sem->write_bias_wait);
- }
-}
-
-void
-down_read(struct rw_semaphore *sem)
-{
-#if WAITQUEUE_DEBUG
- CHECK_MAGIC(sem->__magic);
-#endif
- __down_read(sem);
-#if WAITQUEUE_DEBUG
- if (sem->granted & 2)
- BUG();
- if (atomic_read(&sem->writers))
- BUG();
- atomic_inc(&sem->readers);
-#endif
-}
-
-void
-down_write(struct rw_semaphore *sem)
-{
-#if WAITQUEUE_DEBUG
- CHECK_MAGIC(sem->__magic);
-#endif
- __down_write(sem);
-#if WAITQUEUE_DEBUG
- if (sem->granted & 3)
- BUG();
- if (atomic_read(&sem->writers))
- BUG();
- if (atomic_read(&sem->readers))
- BUG();
- atomic_inc(&sem->writers);
-#endif
-}
-
-void
-up_read(struct rw_semaphore *sem)
-{
-#if WAITQUEUE_DEBUG
- CHECK_MAGIC(sem->__magic);
- if (sem->granted & 2)
- BUG();
- if (atomic_read(&sem->writers))
- BUG();
- atomic_dec(&sem->readers);
-#endif
- __up_read(sem);
-}
-
-void
-up_write(struct rw_semaphore *sem)
-{
-#if WAITQUEUE_DEBUG
- CHECK_MAGIC(sem->__magic);
- if (sem->granted & 3)
- BUG();
- if (atomic_read(&sem->readers))
- BUG();
- if (atomic_read(&sem->writers) != 1)
- BUG();
- atomic_dec(&sem->writers);
-#endif
- __up_write(sem);
-}
struct pgtable_cache_struct quicklists;
#endif
-void
-__bad_pmd(pgd_t *pgd)
-{
- printk("Bad pgd in pmd_alloc: %08lx\n", pgd_val(*pgd));
- pgd_set(pgd, BAD_PAGETABLE);
-}
-
-void
-__bad_pte(pmd_t *pmd)
-{
- printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
- pmd_set(pmd, (pte_t *) BAD_PAGETABLE);
-}
-
pgd_t *
get_pgd_slow(void)
{
return ret;
}
-pmd_t *
-get_pmd_slow(pgd_t *pgd, unsigned long offset)
-{
- pmd_t *pmd;
-
- pmd = (pmd_t *) __get_free_page(GFP_KERNEL);
- if (pgd_none(*pgd)) {
- if (pmd) {
- clear_page((void *)pmd);
- pgd_set(pgd, pmd);
- return pmd + offset;
- }
- pgd_set(pgd, BAD_PAGETABLE);
- return NULL;
- }
- free_page((unsigned long)pmd);
- if (pgd_bad(*pgd)) {
- __bad_pmd(pgd);
- return NULL;
- }
- return (pmd_t *) pgd_page(*pgd) + offset;
-}
-
-pte_t *
-get_pte_slow(pmd_t *pmd, unsigned long offset)
-{
- pte_t *pte;
-
- pte = (pte_t *) __get_free_page(GFP_KERNEL);
- if (pmd_none(*pmd)) {
- if (pte) {
- clear_page((void *)pte);
- pmd_set(pmd, pte);
- return pte + offset;
- }
- pmd_set(pmd, (pte_t *) BAD_PAGETABLE);
- return NULL;
- }
- free_page((unsigned long)pte);
- if (pmd_bad(*pmd)) {
- __bad_pte(pmd);
- return NULL;
- }
- return (pte_t *) pmd_page(*pmd) + offset;
-}
-
int do_check_pgt_cache(int low, int high)
{
int freed = 0;
- if(pgtable_cache_size > high) {
- do {
- if(pgd_quicklist)
- free_pgd_slow(get_pgd_fast()), freed++;
- if(pmd_quicklist)
- free_pmd_slow(get_pmd_fast()), freed++;
- if(pte_quicklist)
- free_pte_slow(get_pte_fast()), freed++;
- } while(pgtable_cache_size > low);
- }
- return freed;
+ if(pgtable_cache_size > high) {
+ do {
+ if(pgd_quicklist) {
+ free_pgd_slow(get_pgd_fast());
+ freed++;
+ }
+ if(pmd_quicklist) {
+ pmd_free_slow(pmd_alloc_one_fast(NULL, 0));
+ freed++;
+ }
+ if(pte_quicklist) {
+ pte_free_slow(pte_alloc_one_fast(NULL, 0));
+ freed++;
+ }
+ } while(pgtable_cache_size > low);
+ }
+ return freed;
}
/*
define_bool CONFIG_SBUS n
define_bool CONFIG_MCA n
define_bool CONFIG_UID16 y
+define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y
+define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n
mainmenu_option next_comment
mainmenu_option next_comment
comment 'Archimedes/A5000 Implementations'
# These architectures will be combined. However, until this
-# is complete... Note that the ARC will take precidence over
+# is complete... Note that the ARC will take precedence over
# A5K
comment 'Archimedes/A5000 Implementations (select only ONE)'
dep_bool ' Archimedes' CONFIG_ARCH_ARC $CONFIG_ARCH_ARCA5K
spin_unlock_irqrestore(&semaphore_lock, flags);
return 1;
}
-
-struct rw_semaphore *down_read_failed_biased(struct rw_semaphore *sem)
-{
- struct task_struct *tsk = current;
- DECLARE_WAITQUEUE(wait, tsk);
-
- add_wait_queue(&sem->wait, &wait); /* put ourselves at the head of the list */
-
- for (;;) {
- if (sem->read_bias_granted && xchg(&sem->read_bias_granted, 0))
- break;
- set_task_state(tsk, TASK_UNINTERRUPTIBLE);
- if (!sem->read_bias_granted)
- schedule();
- }
-
- remove_wait_queue(&sem->wait, &wait);
- tsk->state = TASK_RUNNING;
-
- return sem;
-}
-
-struct rw_semaphore *down_write_failed_biased(struct rw_semaphore *sem)
-{
- struct task_struct *tsk = current;
- DECLARE_WAITQUEUE(wait, tsk);
-
- add_wait_queue_exclusive(&sem->write_bias_wait, &wait); /* put ourselves at the end of the list */
-
- for (;;) {
- if (sem->write_bias_granted && xchg(&sem->write_bias_granted, 0))
- break;
- set_task_state(tsk, TASK_UNINTERRUPTIBLE);
- if (!sem->write_bias_granted)
- schedule();
- }
-
- remove_wait_queue(&sem->write_bias_wait, &wait);
- tsk->state = TASK_RUNNING;
-
- /* if the lock is currently unbiased, awaken the sleepers
- * FIXME: this wakes up the readers early in a bit of a
- * stampede -> bad!
- */
- if (atomic_read(&sem->count) >= 0)
- wake_up(&sem->wait);
-
- return sem;
-}
-
-/* Wait for the lock to become unbiased. Readers
- * are non-exclusive. =)
- */
-struct rw_semaphore *down_read_failed(struct rw_semaphore *sem)
-{
- struct task_struct *tsk = current;
- DECLARE_WAITQUEUE(wait, tsk);
-
- /* this takes care of granting the lock */
- __up_op_read(sem, __rwsem_wake);
-
- add_wait_queue(&sem->wait, &wait);
-
- while (atomic_read(&sem->count) < 0) {
- set_task_state(tsk, TASK_UNINTERRUPTIBLE);
- if (atomic_read(&sem->count) >= 0)
- break;
- schedule();
- }
-
- remove_wait_queue(&sem->wait, &wait);
- tsk->state = TASK_RUNNING;
-
- return sem;
-}
-
-/* Wait for the lock to become unbiased. Since we're
- * a writer, we'll make ourselves exclusive.
- */
-struct rw_semaphore *down_write_failed(struct rw_semaphore *sem)
-{
- struct task_struct *tsk = current;
- DECLARE_WAITQUEUE(wait, tsk);
-
- /* this takes care of granting the lock */
- __up_op_write(sem, __rwsem_wake);
-
- add_wait_queue_exclusive(&sem->wait, &wait);
-
- while (atomic_read(&sem->count) < 0) {
- set_task_state(tsk, TASK_UNINTERRUPTIBLE);
- if (atomic_read(&sem->count) >= 0)
- break; /* we must attempt to acquire or bias the lock */
- schedule();
- }
-
- remove_wait_queue(&sem->wait, &wait);
- tsk->state = TASK_RUNNING;
-
- return sem;
-}
-
-/* Called when someone has done an up that transitioned from
- * negative to non-negative, meaning that the lock has been
- * granted to whomever owned the bias.
- */
-struct rw_semaphore *rwsem_wake_readers(struct rw_semaphore *sem)
-{
- if (xchg(&sem->read_bias_granted, 1))
- BUG();
- wake_up(&sem->wait);
- return sem;
-}
-
-struct rw_semaphore *rwsem_wake_writer(struct rw_semaphore *sem)
-{
- if (xchg(&sem->write_bias_granted, 1))
- BUG();
- wake_up(&sem->write_bias_wait);
- return sem;
-}
-
-/*
- * The semaphore operations have a special calling sequence that
- * allow us to do a simpler in-line version of them. These routines
- * need to convert that sequence back into the C sequence when
- * there is contention on the semaphore.
- *
- * ip contains the semaphore pointer on entry. Save the C-clobbered
- * registers (r0 to r3 and lr), but not ip, as we use it as a return
- * value in some cases..
- */
-#ifdef CONFIG_CPU_26
-asm(" .section .text.lock, \"ax\"
- .align 5
- .globl __down_failed
-__down_failed:
- stmfd sp!, {r0 - r3, lr}
- mov r0, ip
- bl __down
- ldmfd sp!, {r0 - r3, pc}^
-
- .align 5
- .globl __down_interruptible_failed
-__down_interruptible_failed:
- stmfd sp!, {r0 - r3, lr}
- mov r0, ip
- bl __down_interruptible
- mov ip, r0
- ldmfd sp!, {r0 - r3, pc}^
-
- .align 5
- .globl __down_trylock_failed
-__down_trylock_failed:
- stmfd sp!, {r0 - r3, lr}
- mov r0, ip
- bl __down_trylock
- mov ip, r0
- ldmfd sp!, {r0 - r3, pc}^
-
- .align 5
- .globl __up_wakeup
-__up_wakeup:
- stmfd sp!, {r0 - r3, lr}
- mov r0, ip
- bl __up
- ldmfd sp!, {r0 - r3, pc}^
-
- .align 5
- .globl __down_read_failed
-__down_read_failed:
- stmfd sp!, {r0 - r3, lr}
- mov r0, ip
- bcc 1f
-1: bl down_read_failed_biased
- ldmfd sp!, {r0 - r3, pc}^
-2: bl down_read_failed
- mov r1, pc
- orr r2, r1, #
- teqp r2, #0
-
- ldr r3, [r0]
- subs r3, r3, #1
- str r3, [r0]
- ldmplfd sp!, {r0 - r3, pc}^
- orrcs r1, r1, #0x20000000 @ Set carry
- teqp r1, #0
- bcc 2b
- b 1b
-
- .align 5
- .globl __down_write_failed
-__down_write_failed:
- stmfd sp!, {r0 - r3, lr}
- mov r0, ip
- bcc 1f
-1: bl down_write_failed_biased
- ldmfd sp!, {r0 - r3, pc}^
-2: bl down_write_failed
- mov r1, pc
- orr r2, r1, #128
- teqp r2, #0
-
- ldr r3, [r0]
- subs r3, r3, #"RW_LOCK_BIAS_STR"
- str r3, [r0]
- ldmeqfd sp!, {r0 - r3, pc}^
- orrcs r1, r1, #0x20000000 @ Set carry
- teqp r1, #0
- bcc 2b
- b 1b
-
- .align 5
- .globl __rwsem_wake
-__rwsem_wake:
- stmfd sp!, {r0 - r3, lr}
- mov r0, ip
- beq 1f
- bl rwsem_wake_readers
- ldmfd sp!, {r0 - r3, pc}^
-1: bl rwsem_wake_writer
- ldmfd sp!, {r0 - r3, pc}^
-
- .previous
- ");
-
-#else
-/* 32 bit version */
-asm(" .section .text.lock, \"ax\"
- .align 5
- .globl __down_failed
-__down_failed:
- stmfd sp!, {r0 - r3, lr}
- mov r0, ip
- bl __down
- ldmfd sp!, {r0 - r3, pc}
-
- .align 5
- .globl __down_interruptible_failed
-__down_interruptible_failed:
- stmfd sp!, {r0 - r3, lr}
- mov r0, ip
- bl __down_interruptible
- mov ip, r0
- ldmfd sp!, {r0 - r3, pc}
-
- .align 5
- .globl __down_trylock_failed
-__down_trylock_failed:
- stmfd sp!, {r0 - r3, lr}
- mov r0, ip
- bl __down_trylock
- mov ip, r0
- ldmfd sp!, {r0 - r3, pc}
-
- .align 5
- .globl __up_wakeup
-__up_wakeup:
- stmfd sp!, {r0 - r3, lr}
- mov r0, ip
- bl __up
- ldmfd sp!, {r0 - r3, pc}
-
- .align 5
- .globl __down_read_failed
-__down_read_failed:
- stmfd sp!, {r0 - r3, lr}
- mov r0, ip
- bcc 1f
-1: bl down_read_failed_biased
- ldmfd sp!, {r0 - r3, pc}
-2: bl down_read_failed
- mrs r1, cpsr
- orr r2, r1, #128
- msr cpsr_c, r2
- ldr r3, [r0]
- subs r3, r3, #1
- str r3, [r0]
- msr cpsr_c, r1
- ldmplfd sp!, {r0 - r3, pc}
- bcc 2b
- b 1b
-
- .align 5
- .globl __down_write_failed
-__down_write_failed:
- stmfd sp!, {r0 - r3, lr}
- mov r0, ip
- bcc 1f
-1: bl down_write_failed_biased
- ldmfd sp!, {r0 - r3, pc}
-2: bl down_write_failed
- mrs r1, cpsr
- orr r2, r1, #128
- msr cpsr_c, r2
- ldr r3, [r0]
- subs r3, r3, #"RW_LOCK_BIAS_STR"
- str r3, [r0]
- msr cpsr_c, r1
- ldmeqfd sp!, {r0 - r3, pc}
- bcc 2b
- b 1b
-
- .align 5
- .globl __rwsem_wake
-__rwsem_wake:
- stmfd sp!, {r0 - r3, lr}
- mov r0, ip
- beq 1f
- bl rwsem_wake_readers
- ldmfd sp!, {r0 - r3, pc}
-1: bl rwsem_wake_writer
- ldmfd sp!, {r0 - r3, pc}
-
- .previous
- ");
-
-#endif
mainmenu_name "Linux/CRIS Kernel Configuration"
define_bool CONFIG_UID16 y
+define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y
+define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n
mainmenu_option next_comment
comment 'Code maturity level options'
{
return waking_non_zero_trylock(sem);
}
-
-/*
- * RW Semaphores
- */
-void
-__down_read(struct rw_semaphore *sem, int count)
-{
- DOWN_VAR;
-
- retry_down:
- if (count < 0) {
- /* Wait for the lock to become unbiased. Readers
- are non-exclusive. */
-
- /* This takes care of granting the lock. */
- up_read(sem);
-
- add_wait_queue(&sem->wait, &wait);
- while (atomic_read(&sem->count) < 0) {
- set_task_state(tsk, TASK_UNINTERRUPTIBLE);
- if (atomic_read(&sem->count) >= 0)
- break;
- schedule();
- }
-
- remove_wait_queue(&sem->wait, &wait);
- tsk->state = TASK_RUNNING;
-
- mb();
- count = atomic_dec_return(&sem->count);
- if (count <= 0)
- goto retry_down;
- } else {
- add_wait_queue(&sem->wait, &wait);
-
- while (1) {
- if (test_and_clear_bit(0, &sem->granted))
- break;
- set_task_state(tsk, TASK_UNINTERRUPTIBLE);
- if ((sem->granted & 1) == 0)
- schedule();
- }
-
- remove_wait_queue(&sem->wait, &wait);
- tsk->state = TASK_RUNNING;
- }
-}
-
-void
-__down_write(struct rw_semaphore *sem, int count)
-{
- DOWN_VAR;
-
- retry_down:
- if (count + RW_LOCK_BIAS < 0) {
- up_write(sem);
-
- add_wait_queue_exclusive(&sem->wait, &wait);
-
- while (atomic_read(&sem->count) < 0) {
- set_task_state(tsk, TASK_UNINTERRUPTIBLE);
- if (atomic_read(&sem->count) >= RW_LOCK_BIAS)
- break;
- schedule();
- }
-
- remove_wait_queue(&sem->wait, &wait);
- tsk->state = TASK_RUNNING;
-
- mb();
- count = atomic_sub_return(RW_LOCK_BIAS, &sem->count);
- if (count != 0)
- goto retry_down;
- } else {
- /* Put ourselves at the end of the list. */
- add_wait_queue_exclusive(&sem->write_bias_wait, &wait);
-
- while (1) {
- if (test_and_clear_bit(1, &sem->granted))
- break;
- set_task_state(tsk, TASK_UNINTERRUPTIBLE);
- if ((sem->granted & 2) == 0)
- schedule();
- }
-
- remove_wait_queue(&sem->write_bias_wait, &wait);
- tsk->state = TASK_RUNNING;
-
- /* If the lock is currently unbiased, awaken the sleepers.
- FIXME: This wakes up the readers early in a bit of a
- stampede -> bad! */
- if (atomic_read(&sem->count) >= 0)
- wake_up(&sem->wait);
- }
-}
-
-void
-__rwsem_wake(struct rw_semaphore *sem, unsigned long readers)
-{
- if (readers) {
- if (test_and_set_bit(0, &sem->granted))
- BUG();
- wake_up(&sem->wait);
- } else {
- if (test_and_set_bit(1, &sem->granted))
- BUG();
- wake_up(&sem->write_bias_wait);
- }
-}
define_bool CONFIG_SBUS n
define_bool CONFIG_UID16 y
+define_bool CONFIG_RWSEM_GENERIC_SPINLOCK n
+define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM y
mainmenu_option next_comment
comment 'Code maturity level options'
else
mmx_copy_user_zeroing(to, from, n);
}
+ else
+ memset(to, 0, n);
return n;
}
{
if (access_ok(VERIFY_READ, from, n))
__copy_user_zeroing(to,from,n);
+ else
+ memset(to, 0, n);
return n;
}
define_bool CONFIG_EISA n
define_bool CONFIG_MCA n
define_bool CONFIG_SBUS n
+define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y
+define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n
choice 'IA-64 processor type' \
"Itanium CONFIG_ITANIUM \
spin_unlock_irqrestore(&semaphore_lock, flags);
return 1;
}
-
-/*
- * Helper routines for rw semaphores. These could be optimized some
- * more, but since they're off the critical path, I prefer clarity for
- * now...
- */
-
-/*
- * This gets called if we failed to acquire the lock, but we're biased
- * to acquire the lock by virtue of causing the count to change from 0
- * to -1. Being biased, we sleep and attempt to grab the lock until
- * we succeed. When this function returns, we own the lock.
- */
-static inline void
-down_read_failed_biased (struct rw_semaphore *sem)
-{
- struct task_struct *tsk = current;
- DECLARE_WAITQUEUE(wait, tsk);
-
- add_wait_queue(&sem->wait, &wait); /* put ourselves at the head of the list */
-
- for (;;) {
- if (sem->read_bias_granted && xchg(&sem->read_bias_granted, 0))
- break;
- set_task_state(tsk, TASK_UNINTERRUPTIBLE);
- if (!sem->read_bias_granted)
- schedule();
- }
- remove_wait_queue(&sem->wait, &wait);
- tsk->state = TASK_RUNNING;
-}
-
-/*
- * This gets called if we failed to acquire the lock and we are not
- * biased to acquire the lock. We undo the decrement that was
- * done earlier, go to sleep, and then attempt to re-acquire the
- * lock afterwards.
- */
-static inline void
-down_read_failed (struct rw_semaphore *sem)
-{
- struct task_struct *tsk = current;
- DECLARE_WAITQUEUE(wait, tsk);
-
- /*
- * Undo the decrement we did in down_read() and check if we
- * need to wake up someone.
- */
- __up_read(sem);
-
- add_wait_queue(&sem->wait, &wait);
- while (sem->count < 0) {
- set_task_state(tsk, TASK_UNINTERRUPTIBLE);
- if (sem->count >= 0)
- break;
- schedule();
- }
- remove_wait_queue(&sem->wait, &wait);
- tsk->state = TASK_RUNNING;
-}
-
-/*
- * Wait for the lock to become unbiased. Readers are non-exclusive.
- */
-void
-__down_read_failed (struct rw_semaphore *sem, long count)
-{
- while (1) {
- if (count == -1) {
- down_read_failed_biased(sem);
- return;
- }
- /* unbiased */
- down_read_failed(sem);
-
- count = ia64_fetch_and_add(-1, &sem->count);
- if (count >= 0)
- return;
- }
-}
-
-static inline void
-down_write_failed_biased (struct rw_semaphore *sem)
-{
- struct task_struct *tsk = current;
- DECLARE_WAITQUEUE(wait, tsk);
-
- /* put ourselves at the end of the list */
- add_wait_queue_exclusive(&sem->write_bias_wait, &wait);
-
- for (;;) {
- if (sem->write_bias_granted && xchg(&sem->write_bias_granted, 0))
- break;
- set_task_state(tsk, TASK_UNINTERRUPTIBLE);
- if (!sem->write_bias_granted)
- schedule();
- }
-
- remove_wait_queue(&sem->write_bias_wait, &wait);
- tsk->state = TASK_RUNNING;
-
- /*
- * If the lock is currently unbiased, awaken the sleepers
- * FIXME: this wakes up the readers early in a bit of a
- * stampede -> bad!
- */
- if (sem->count >= 0)
- wake_up(&sem->wait);
-}
-
-
-static inline void
-down_write_failed (struct rw_semaphore *sem)
-{
- struct task_struct *tsk = current;
- DECLARE_WAITQUEUE(wait, tsk);
-
- __up_write(sem); /* this takes care of granting the lock */
-
- add_wait_queue_exclusive(&sem->wait, &wait);
-
- while (sem->count < 0) {
- set_task_state(tsk, TASK_UNINTERRUPTIBLE);
- if (sem->count >= 0)
- break; /* we must attempt to acquire or bias the lock */
- schedule();
- }
-
- remove_wait_queue(&sem->wait, &wait);
- tsk->state = TASK_RUNNING;
-}
-
-
-/*
- * Wait for the lock to become unbiased. Since we're a writer, we'll
- * make ourselves exclusive.
- */
-void
-__down_write_failed (struct rw_semaphore *sem, long count)
-{
- long old_count;
-
- while (1) {
- if (count == -RW_LOCK_BIAS) {
- down_write_failed_biased(sem);
- return;
- }
- down_write_failed(sem);
-
- do {
- old_count = sem->count;
- count = old_count - RW_LOCK_BIAS;
- } while (cmpxchg_acq(&sem->count, old_count, count) != old_count);
-
- if (count == 0)
- return;
- }
-}
-
-void
-__rwsem_wake (struct rw_semaphore *sem, long count)
-{
- wait_queue_head_t *wq;
-
- if (count == 0) {
- /* wake a writer */
- if (xchg(&sem->write_bias_granted, 1))
- BUG();
- wq = &sem->write_bias_wait;
- } else {
- /* wake reader(s) */
- if (xchg(&sem->read_bias_granted, 1))
- BUG();
- wq = &sem->wait;
- }
- wake_up(wq); /* wake up everyone on the wait queue */
-}
return 0;
}
-void dbprintf(const char *fmt , ...)
-{
- static char buf[1024];
- va_list args;
- extern void console_print (const char *str);
- extern int vsprintf(char * buf, const char * fmt, va_list args);
-
- va_start(args, fmt);
- vsprintf(buf, fmt, args);
- va_end(args);
-
- console_print (buf);
-}
-
static NORET_TYPE void amiga_reset( void )
ATTRIB_NORET;
#
define_bool CONFIG_UID16 y
+define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y
+define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n
mainmenu_name "Linux/68k Kernel Configuration"
{
return waking_non_zero_trylock(sem);
}
-
-
-/* Wait for the lock to become unbiased. Readers
- * are non-exclusive. =)
- */
-void down_read_failed(struct rw_semaphore *sem)
-{
- DECLARE_WAITQUEUE(wait, current);
-
- __up_read(sem); /* this takes care of granting the lock */
-
- add_wait_queue(&sem->wait, &wait);
-
- while (atomic_read(&sem->count) < 0) {
- set_task_state(current, TASK_UNINTERRUPTIBLE);
- if (atomic_read(&sem->count) >= 0)
- break;
- schedule();
- }
-
- remove_wait_queue(&sem->wait, &wait);
- current->state = TASK_RUNNING;
-}
-
-void down_read_failed_biased(struct rw_semaphore *sem)
-{
- DECLARE_WAITQUEUE(wait, current);
-
- add_wait_queue(&sem->wait, &wait); /* put ourselves at the head of the list */
-
- for (;;) {
- if (sem->read_bias_granted && xchg(&sem->read_bias_granted, 0))
- break;
- set_task_state(current, TASK_UNINTERRUPTIBLE);
- if (!sem->read_bias_granted)
- schedule();
- }
-
- remove_wait_queue(&sem->wait, &wait);
- current->state = TASK_RUNNING;
-}
-
-
-/* Wait for the lock to become unbiased. Since we're
- * a writer, we'll make ourselves exclusive.
- */
-void down_write_failed(struct rw_semaphore *sem)
-{
- DECLARE_WAITQUEUE(wait, current);
-
- __up_write(sem); /* this takes care of granting the lock */
-
- add_wait_queue_exclusive(&sem->wait, &wait);
-
- while (atomic_read(&sem->count) < 0) {
- set_task_state(current, TASK_UNINTERRUPTIBLE);
- if (atomic_read(&sem->count) >= 0)
- break; /* we must attempt to acquire or bias the lock */
- schedule();
- }
-
- remove_wait_queue(&sem->wait, &wait);
- current->state = TASK_RUNNING;
-}
-
-void down_write_failed_biased(struct rw_semaphore *sem)
-{
- DECLARE_WAITQUEUE(wait, current);
-
- add_wait_queue_exclusive(&sem->write_bias_wait, &wait); /* put ourselves at the end of the list */
-
- for (;;) {
- if (sem->write_bias_granted && xchg(&sem->write_bias_granted, 0))
- break;
- set_task_state(current, TASK_UNINTERRUPTIBLE);
- if (!sem->write_bias_granted)
- schedule();
- }
-
- remove_wait_queue(&sem->write_bias_wait, &wait);
- current->state = TASK_RUNNING;
-
- /* if the lock is currently unbiased, awaken the sleepers
- * FIXME: this wakes up the readers early in a bit of a
- * stampede -> bad!
- */
- if (atomic_read(&sem->count) >= 0)
- wake_up(&sem->wait);
-}
-
-
-/* Called when someone has done an up that transitioned from
- * negative to non-negative, meaning that the lock has been
- * granted to whomever owned the bias.
- */
-void rwsem_wake_readers(struct rw_semaphore *sem)
-{
- if (xchg(&sem->read_bias_granted, 1))
- BUG();
- wake_up(&sem->wait);
-}
-
-void rwsem_wake_writer(struct rw_semaphore *sem)
-{
- if (xchg(&sem->write_bias_granted, 1))
- BUG();
- wake_up(&sem->write_bias_wait);
-}
#include <linux/blk.h>
#endif
-#ifndef CONFIG_AMIGA
-#define dbprintf printk
-#endif
-
unsigned long m68k_machtype;
unsigned long m68k_cputype;
unsigned long m68k_fputype;
#
ifdef CONFIG_CPU_LITTLE_ENDIAN
tool-prefix = mipsel-linux-
+output-format = elf32-littlemips
else
tool-prefix = mips-linux-
+output-format = elf32-bigmips
endif
ifdef CONFIG_CROSSCOMPILE
endif
#
-# The ELF GCC uses -G0 -mabicalls -fpic as default. We don't need PIC
-# code in the kernel since it only slows down the whole thing. For the
-# old GCC these options are just the defaults. At some point we might
-# make use of global pointer optimizations.
+# GCC uses -G0 -mabicalls -fpic as default. We don't want PIC in the kernel
+# code since it only slows down the whole thing. At some point we might make
+# use of global pointer optimizations but their use of $28 conflicts with
+# the current pointer optimization.
#
# The DECStation requires an ECOFF kernel for remote booting, other MIPS
# machines may also. Since BFD is incredibly buggy with respect to
# crossformat linking we rely on the elf2ecoff tool for format conversion.
#
-CFLAGS += -G 0 -mno-abicalls -fno-pic
+GCCFLAGS := -G 0 -mno-abicalls -fno-pic
LINKFLAGS += -static -G 0
MODFLAGS += -mlong-calls
# CPU-dependent compiler/assembler options for optimization.
#
ifdef CONFIG_CPU_R3000
-CFLAGS := $(CFLAGS) -mcpu=r3000 -mips1
+GCCFLAGS += -mcpu=r3000 -mips1
+endif
+ifdef CONFIG_CPU_R3912
+GCCFLAGS += -mcpu=r3000 -mips1
endif
ifdef CONFIG_CPU_R6000
-CFLAGS := $(CFLAGS) -mcpu=r6000 -mips2 -Wa,--trap
+GCCFLAGS += -mcpu=r6000 -mips2 -Wa,--trap
endif
ifdef CONFIG_CPU_R4300
-CFLAGS := $(CFLAGS) -mcpu=r4300 -mips2 -Wa,--trap
+GCCFLAGS += -mcpu=r4300 -mips2 -Wa,--trap
endif
ifdef CONFIG_CPU_R4X00
-CFLAGS := $(CFLAGS) -mcpu=r4600 -mips2 -Wa,--trap
+GCCFLAGS += -mcpu=r4600 -mips2 -Wa,--trap
+endif
+ifdef CONFIG_CPU_MIPS32
+GCCFLAGS += -mcpu=r4600 -mips2 -Wa,--trap
endif
ifdef CONFIG_CPU_R5000
-CFLAGS := $(CFLAGS) -mcpu=r8000 -mips2 -Wa,--trap
+GCCFLAGS += -mcpu=r8000 -mips2 -Wa,--trap
+endif
+ifdef CONFIG_CPU_R5432
+GCCFLAGS += -mcpu=r8000 -mips2 -Wa,--trap
endif
ifdef CONFIG_CPU_NEVADA
-CFLAGS := $(CFLAGS) -mcpu=r8000 -mips2 -Wa,--trap -mmad
+GCCFLAGS += -mcpu=r8000 -mips2 -Wa,--trap -mmad
+endif
+ifdef CONFIG_CPU_RM7000
+GCCFLAGS += -mcpu=r8000 -mips2 -Wa,--trap
endif
ifdef CONFIG_CPU_R8000
-CFLAGS := $(CFLAGS) -mcpu=r8000 -mips2 -Wa,--trap
+GCCFLAGS += -mcpu=r8000 -mips2 -Wa,--trap
endif
ifdef CONFIG_CPU_R10000
-CFLAGS := $(CFLAGS) -mcpu=r8000 -mips2 -Wa,--trap
+GCCFLAGS += -mcpu=r8000 -mips2 -Wa,--trap
endif
+ifdef CONFIG_MIPS_FPU_EMULATOR
+CORE_FILES +=arch/mips/math-emu/fpu_emulator.o
+SUBDIRS +=arch/mips/math-emu
+endif
+
+#
+# The pipe options is bad for my low-mem machine
+# Uncomment this if you want this.
+#
+GCCFLAGS += -pipe
+
+CFLAGS := -I $(TOPDIR)/include/asm/gcc $(CFLAGS) $(GCCFLAGS)
+AFLAGS += $(GCCFLAGS)
+
#
# Board-dependent options and extra files
#
ifdef CONFIG_ALGOR_P4032
CORE_FILES += arch/mips/algor/algor.o
SUBDIRS += arch/mips/algor
-#LOADADDR += 0x80000000
+LOADADDR += 0x80000000
endif
#
LOADADDR += 0x80040000
endif
+ifdef CONFIG_MIPS_ATLAS
+LIBS += arch/mips/mips-boards/atlas/atlas.o arch/mips/mips-boards/generic/mipsboards.o
+SUBDIRS += arch/mips/mips-boards/generic arch/mips/mips-boards/atlas
+LOADADDR += 0x80100000
+endif
+
+ifdef CONFIG_MIPS_MALTA
+LIBS += arch/mips/mips-boards/malta/malta.o arch/mips/mips-boards/generic/mipsboards.o
+SUBDIRS += arch/mips/mips-boards/malta arch/mips/mips-boards/generic
+LOADADDR += 0x80100000
+endif
+
#
# Acer PICA 61, Mips Magnum 4000 and Olivetti M700.
#
LOADADDR += 0x80080000
endif
-ifdef CONFIG_COBALT_MICRO_SERVER
-ARCHIVES += arch/mips/cobalt/cobalt.o
-SUBDIRS += arch/mips/cobalt
-LOADADDR += 0x80000000
-endif
-
ifdef CONFIG_SNI_RM200_PCI
CORE_FILES += arch/mips/sni/sni.o
SUBDIRS += arch/mips/sni arch/mips/arc
endif
ifdef CONFIG_SGI_IP22
-LIBS += arch/mips/sgi/kernel/sgikern.a arch/mips/arc/arclib.a
+CORE_FILES += arch/mips/sgi/kernel/ip22-kern.o
+LIBS += arch/mips/arc/arclib.a
SUBDIRS += arch/mips/sgi/kernel arch/mips/arc
#
# Set LOADADDR to >= 0x88069000 if you want to leave space for symmon,
endif
#
-# Choosing incompatible machines durings configuration will result in
-# error messages during linking. Select a default linkscript if
-# none has been choosen above.
#
-ifndef LINKSCRIPT
-ifndef CONFIG_CPU_LITTLE_ENDIAN
-LINKSCRIPT = arch/mips/ld.script.big
-else
-LINKSCRIPT = arch/mips/ld.script.little
+# NEC DDB Vrc-5476
+#
+ifdef CONFIG_DDB5476
+SUBDIRS += arch/mips/ddb5476
+LIBS += arch/mips/ddb5476/ddb5476.a
+LOADADDR += 0x80080000
endif
+
+#
+# Galileo EV64120 Board
+#
+ifdef CONFIG_MIPS_EV64120
+LIBS += arch/mips/galileo-boards/ev64120/ev64120.o
+SUBDIRS += arch/mips/galileo-boards/ev64120
+LOADADDR += 0x80100000
endif
-LINKFLAGS += -T $(word 1,$(LINKSCRIPT))
-ifdef LOADADDR
-LINKFLAGS += -Ttext $(word 1,$(LOADADDR))
+#
+# Galileo EV96100 Board
+#
+ifdef CONFIG_MIPS_EV96100
+LIBS += arch/mips/galileo-boards/ev96100/ev96100.o arch/mips/galileo-boards/generic/galboards.o
+SUBDIRS += arch/mips/galileo-boards/generic arch/mips/galileo-boards/ev96100
+LOADADDR += 0x80100000
endif
#
-# The pipe options is bad for my low-mem machine
-# Uncomment this if you want this.
+# Momentum Ocelot board
+#
+ifdef CONFIG_MOMENCO_OCELOT
+LIBS += arch/mips/gt64120/common/gt64120.o arch/mips/gt64120/momenco_ocelot/momenco_ocelot.o
+SUBDIRS += arch/mips/gt64120/common arch/mips/gt64120/momenco_ocelot
+LOADADDR += 0x80100000
+endif
+
#
-CFLAGS += -pipe
+# Philips Nino
+#
+ifdef CONFIG_NINO
+CORE_FILES += arch/mips/philips/nino/nino.o \
+ arch/mips/philips/drivers/drivers.o
+SUBDIRS += arch/mips/philips/nino arch/mips/philips/drivers
+LOADADDR += 0x80000000
+endif
+
+#
+# ITE 8172 eval board with QED 5231 CPU
+#
+ifdef CONFIG_MIPS_ITE8172
+LIBS += arch/mips/ite-boards/qed-4n-s01b/ite.o \
+ arch/mips/ite-boards/generic/it8172.o
+SUBDIRS += arch/mips/ite-boards/generic \
+ arch/mips/ite-boards/qed-4n-s01b
+LOADADDR += 0x80100000
+endif
+
+#
+# Choosing incompatible machines durings configuration will result in
+# error messages during linking. Select a default linkscript if
+# none has been choosen above.
+#
+vmlinux: arch/$(ARCH)/ld.script
+
+arch/$(ARCH)/ld.script: arch/$(ARCH)/ld.script.in arch/$(ARCH)/Makefile
+ sed -e 's/@@OUTPUT_FORMAT@@/$(output-format)/' \
+ -e 's/@@LOADADDR@@/$(LOADADDR)/' <$< >$@
+LINKFLAGS += -T arch/$(ARCH)/ld.script
HEAD := arch/mips/kernel/head.o arch/mips/kernel/init_task.o
$(ORIONBOOT) orionboot
endif
+ifdef CONFIG_MIPS_EV64120
+GALILEOBOOT = $(MAKE) -C arch/$(ARCH)/galileo-boards/ev64120
+
+gboot: vmlinux
+ $(MAKE) -C arch/$(ARCH)/galileo-boards/ev64120/compressed
+endif
+
MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot
+vmlinux.ecoff: vmlinux
+ @$(MAKEBOOT) $@
+
zImage: vmlinux
@$(MAKEBOOT) zImage
archclean:
@$(MAKEBOOT) clean
- $(MAKE) -C arch/$(ARCH)/kernel clean
+ rm -f arch/$(ARCH)/ld.script
$(MAKE) -C arch/$(ARCH)/tools clean
$(MAKE) -C arch/mips/baget clean
-# $Id: Makefile,v 1.1 1998/10/18 13:32:08 tsbogend Exp $
#
# Makefile for the SGI arcs prom monitor library routines
# under Linux.
# Note 2! The CFLAGS definitions are now in the main makefile...
L_TARGET = arclib.a
-L_OBJS = console.o init.o printf.o memory.o tree.o env.o cmdline.o misc.o \
- time.o file.o identify.o
+
+obj-y += console.o init.o memory.o tree.o env.o cmdline.o misc.o \
+ time.o file.o identify.o
+
+obj-$(CONFIG_ARC_CONSOLE) += arc_con.o
include $(TOPDIR)/Rules.make
--- /dev/null
+/*
+ * Wrap-around code for a console using the
+ * ARC io-routines.
+ *
+ * Copyright (c) 1998 Harald Koerfgen
+ */
+
+#include <linux/tty.h>
+#include <linux/major.h>
+#include <linux/ptrace.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/fs.h>
+
+extern char prom_getchar (void);
+extern void prom_printf (char *, ...);
+
+static void prom_console_write(struct console *co, const char *s,
+ unsigned count)
+{
+ unsigned i;
+
+ /*
+ * Now, do each character
+ */
+ for (i = 0; i < count; i++) {
+ if (*s == 10)
+ prom_printf("%c", 13);
+ prom_printf("%c", *s++);
+ }
+}
+
+static int prom_console_wait_key(struct console *co)
+{
+ return prom_getchar();
+}
+
+static int __init prom_console_setup(struct console *co, char *options)
+{
+ return 0;
+}
+
+static kdev_t prom_console_device(struct console *c)
+{
+ return MKDEV(TTY_MAJOR, 64 + c->index);
+}
+
+static struct console arc_cons = {
+ "ttyS",
+ prom_console_write,
+ NULL,
+ prom_console_device,
+ prom_console_wait_key,
+ NULL,
+ prom_console_setup,
+ CON_PRINTBUFFER,
+ -1,
+ 0,
+ NULL
+};
+
+/*
+ * Register console.
+ */
+
+void __init arc_console_init(void)
+{
+ register_console(&arc_cons);
+}
* cmdline.c: Kernel command line creation using ARCS argc/argv.
*
* Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
- *
- * $Id: cmdline.c,v 1.1 1998/10/18 13:32:08 tsbogend Exp $
*/
#include <linux/init.h>
#include <linux/kernel.h>
#include <asm/sgialib.h>
#include <asm/bootinfo.h>
-/* #define DEBUG_CMDLINE */
+#undef DEBUG_CMDLINE
-char arcs_cmdline[CL_SIZE];
+char arcs_cmdline[COMMAND_LINE_SIZE];
char * __init prom_getcmdline(void)
{
/*
- * console.c: SGI arcs console code.
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
*
* Copyright (C) 1996 David S. Miller (dm@sgi.com)
* Compability with board caches, Ulf Carlsson
- *
- * $Id: console.c,v 1.3 1999/10/09 00:00:57 ralf Exp $
*/
#include <linux/config.h>
#include <linux/init.h>
+#include <linux/kernel.h>
#include <asm/sgialib.h>
#include <asm/bcache.h>
+#include <linux/console.h>
+#include <linux/kdev_t.h>
+#include <linux/major.h>
+
+#ifdef CONFIG_ARC_CONSOLE
+#define __init
+#endif
-/* The romvec is not compatible with board caches. Thus we disable it during
- * romvec action. Since r4xx0.c is always compiled and linked with your kernel,
- * this shouldn't cause any harm regardless what MIPS processor you have.
+/*
+ * IP22 boardcache is not compatible with board caches. Thus we disable it
+ * during romvec action. Since r4xx0.c is always compiled and linked with your
+ * kernel, this shouldn't cause any harm regardless what MIPS processor you
+ * have.
*
- * The romvec write and read functions seem to interfere with the serial lines
+ * The ARC write and read functions seem to interfere with the serial lines
* in some way. You should be careful with them.
*/
-extern struct bcache_ops *bcops;
-#ifdef CONFIG_SGI_PROM_CONSOLE
-void prom_putchar(char c)
-#else
void __init prom_putchar(char c)
-#endif
{
long cnt;
char it = c;
- bcops->bc_disable();
+ bc_disable();
romvec->write(1, &it, 1, &cnt);
- bcops->bc_enable();
+ bc_enable();
}
-#ifdef CONFIG_SGI_PROM_CONSOLE
-char prom_getchar(void)
-#else
char __init prom_getchar(void)
-#endif
{
long cnt;
char c;
- bcops->bc_disable();
+ bc_disable();
romvec->read(0, &c, 1, &cnt);
- bcops->bc_enable();
+ bc_enable();
+
return c;
}
+
+static char ppbuf[1024];
+
+void __init prom_printf(char *fmt, ...)
+{
+ va_list args;
+ char ch, *bptr;
+ int i;
+
+ va_start(args, fmt);
+ i = vsprintf(ppbuf, fmt, args);
+
+ bptr = ppbuf;
+
+ while ((ch = *(bptr++)) != 0) {
+ if (ch == '\n')
+ prom_putchar('\r');
+
+ prom_putchar(ch);
+ }
+ va_end(args);
+}
+
+static void
+arc_console_write(struct console *con, const char *s, unsigned n)
+{
+ prom_printf("%s", s);
+}
+
+static kdev_t
+arc_console_dev(struct console *c)
+{
+ return MKDEV(TTY_MAJOR, 64 + c->index);
+}
+
+static struct console arc_prom_console = {
+ name: "prom",
+ write: arc_console_write,
+ device: arc_console_dev,
+ flags: CON_PRINTBUFFER,
+ index: -1,
+};
+
+__init void arc_setup_console(void)
+{
+ register_console(&arc_prom_console);
+}
* This code is based on arch/mips/sgi/kernel/system.c, which is
*
* Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
- *
- * $Id: identify.c,v 1.2 1999/02/25 21:04:13 tsbogend Exp $
*/
#include <linux/init.h>
#include <linux/kernel.h>
#include <asm/bootinfo.h>
struct smatch {
- char *name;
- int group;
- int type;
- int flags;
+ char *name;
+ int group;
+ int type;
+ int flags;
};
static struct smatch mach_table[] = {
- { "SGI-IP22", MACH_GROUP_SGI, MACH_SGI_INDY, PROM_FLAG_ARCS },
- { "Microsoft-Jazz", MACH_GROUP_JAZZ, MACH_MIPS_MAGNUM_4000, 0 },
- { "PICA-61", MACH_GROUP_JAZZ, MACH_ACER_PICA_61, 0 },
- { "RM200PCI", MACH_GROUP_SNI_RM, MACH_SNI_RM200_PCI, 0 }
+ {"SGI-IP22", MACH_GROUP_SGI, MACH_SGI_INDY, PROM_FLAG_ARCS},
+ {"Microsoft-Jazz", MACH_GROUP_JAZZ, MACH_MIPS_MAGNUM_4000, 0},
+ {"PICA-61", MACH_GROUP_JAZZ, MACH_ACER_PICA_61, 0},
+ {"RM200PCI", MACH_GROUP_SNI_RM, MACH_SNI_RM200_PCI, 0}
};
int prom_flags;
-static struct smatch * __init string_to_mach(char *s)
+static struct smatch *__init string_to_mach(char *s)
{
- int i;
-
- for (i = 0; i < sizeof (mach_table); i++) {
- if(!strcmp(s, mach_table[i].name))
- return &mach_table[i];
- }
- prom_printf("\nYeee, could not determine architecture type <%s>\n", s);
- prom_printf("press a key to reboot\n");
- prom_getchar();
- romvec->imode();
- return NULL;
+ int i;
+
+ for (i = 0; i < sizeof(mach_table); i++) {
+ if (!strcmp(s, mach_table[i].name))
+ return &mach_table[i];
+ }
+ prom_printf("\nYeee, could not determine architecture type <%s>\n",
+ s);
+ prom_printf("press a key to reboot\n");
+ prom_getchar();
+ romvec->imode();
+ return NULL;
}
void __init prom_identify_arch(void)
{
- pcomponent *p;
- struct smatch *mach;
-
- /* The root component tells us what machine architecture we
- * have here.
- */
- p = prom_getchild(PROM_NULL_COMPONENT);
- printk("ARCH: %s\n", p->iname);
- mach = string_to_mach(p->iname);
+ pcomponent *p;
+ struct smatch *mach;
- mips_machgroup = mach->group;
- mips_machtype = mach->type;
- prom_flags = mach->flags;
-}
+ /*
+ * The root component tells us what machine architecture we
+ * have here.
+ */
+ p = prom_getchild(PROM_NULL_COMPONENT);
+ printk("ARCH: %s\n", p->iname);
+ mach = string_to_mach(p->iname);
+ mips_machgroup = mach->group;
+ mips_machtype = mach->type;
+ prom_flags = mach->flags;
+}
-/* $Id: init.c,v 1.5 2000/03/07 15:45:27 ralf Exp $
+/*
* This file is subject to the terms and conditions of the GNU General Public+
* License. See the file "COPYING" in the main directory of this archive
* for more details.
extern void prom_testtree(void);
-int __init prom_init(int argc, char **argv, char **envp, int *prom_vec)
+extern void arc_setup_console(void);
+
+void __init prom_init(int argc, char **argv, char **envp, int *prom_vec)
{
struct linux_promblock *pb;
prom_argv = argv;
prom_envp = envp;
- if(pb->magic != 0x53435241) {
+#if 0
+ /* arc_printf should not use prom_printf as soon as we free
+ * the prom buffers - This horribly breaks on Indys with framebuffer
+ * as it simply stops after initialising swap - On the Indigo2 serial
+ * console you will get A LOT illegal instructions - Only enable
+ * this for early init crashes - This also brings up artefacts of
+ * printing everything twice on serial console and on GFX Console
+ * this has the effect of having the prom printing everything
+ * in the small rectangle and the kernel printing around.
+ */
+
+ arc_setup_console();
+#endif
+ if (pb->magic != 0x53435241) {
prom_printf("Aieee, bad prom vector magic %08lx\n", pb->magic);
while(1)
;
romvec->imode();
}
#endif
- return 0;
}
* given to us from the ARCS firmware.
*
* Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
- *
- * $Id: memory.c,v 1.10 2000/01/27 23:21:57 ralf Exp $
*/
#include <linux/init.h>
#include <linux/kernel.h>
"LoadedProgram",
"FirmwareTemporary",
"FirmwarePermanent",
- "FreeContigiuous"
+ "FreeContiguous"
};
#define mtypes(a) (prom_flags & PROM_FLAG_ARCS) ? arcs_mtypes[a.arcs] : arc_mtypes[a.arc]
#endif
-static struct prom_pmemblock pblocks[PROM_MAX_PMEMBLOCKS];
-
-#define MEMTYPE_DONTUSE 0
-#define MEMTYPE_PROM 1
-#define MEMTYPE_FREE 2
-
static inline int memtype_classify_arcs (union linux_memtypes type)
{
switch (type.arcs) {
case arcs_fcontig:
case arcs_free:
- return MEMTYPE_FREE;
+ return BOOT_MEM_RAM;
case arcs_atmp:
- return MEMTYPE_PROM;
+ return BOOT_MEM_ROM_DATA;
case arcs_eblock:
case arcs_rvpage:
case arcs_bmem:
case arcs_prog:
case arcs_aperm:
- return MEMTYPE_DONTUSE;
+ return BOOT_MEM_RESERVED;
default:
BUG();
}
switch (type.arc) {
case arc_free:
case arc_fcontig:
- return MEMTYPE_FREE;
+ return BOOT_MEM_RAM;
case arc_atmp:
- return MEMTYPE_PROM;
+ return BOOT_MEM_ROM_DATA;
case arc_eblock:
case arc_rvpage:
case arc_bmem:
case arc_prog:
case arc_aperm:
- return MEMTYPE_DONTUSE;
+ return BOOT_MEM_RESERVED;
default:
BUG();
}
return memtype_classify_arc(type);
}
-static inline unsigned long find_max_low_pfn(void)
-{
- struct prom_pmemblock *p, *highest;
- unsigned long pfn;
-
- p = pblocks;
- highest = 0;
- while (p->size != 0) {
- if (!highest || p->base > highest->base)
- highest = p;
- p++;
- }
-
- pfn = (highest->base + highest->size) >> PAGE_SHIFT;
-#ifdef DEBUG
- prom_printf("find_max_low_pfn: 0x%lx pfns.\n", pfn);
-#endif
- return pfn;
-}
-
-static inline struct prom_pmemblock *find_largest_memblock(void)
-{
- struct prom_pmemblock *p, *largest;
-
- p = pblocks;
- largest = 0;
- while (p->size != 0) {
- if (!largest || p->size > largest->size)
- largest = p;
- p++;
- }
-
- return largest;
-}
-
void __init prom_meminit(void)
{
- struct prom_pmemblock *largest;
- unsigned long bootmap_size;
struct linux_mdesc *p;
- int totram;
- int i = 0;
#ifdef DEBUG
+ int i = 0;
+
prom_printf("ARCS MEMORY DESCRIPTOR dump:\n");
p = ArcGetMemoryDescriptor(PROM_NULL_MDESC);
while(p) {
}
#endif
- totram = 0;
- i = 0;
p = PROM_NULL_MDESC;
while ((p = ArcGetMemoryDescriptor(p))) {
- pblocks[i].type = prom_memtype_classify(p->type);
- pblocks[i].base = p->base << PAGE_SHIFT;
- pblocks[i].size = p->pages << PAGE_SHIFT;
+ unsigned long base, size;
+ long type;
- switch (pblocks[i].type) {
- case MEMTYPE_FREE:
- totram += pblocks[i].size;
-#ifdef DEBUG
- prom_printf("free_chunk[%d]: base=%08lx size=%x\n",
- i, pblocks[i].base,
- pblocks[i].size);
-#endif
- i++;
- break;
- case MEMTYPE_PROM:
-#ifdef DEBUG
- prom_printf("prom_chunk[%d]: base=%08lx size=%x\n",
- i, pblocks[i].base,
- pblocks[i].size);
-#endif
- i++;
- break;
- default:
- break;
- }
- }
- pblocks[i].size = 0;
-
- max_low_pfn = find_max_low_pfn();
-
- largest = find_largest_memblock();
- bootmap_size = init_bootmem(largest->base >> PAGE_SHIFT, max_low_pfn);
-
- for (i = 0; pblocks[i].size; i++)
- if (pblocks[i].type == MEMTYPE_FREE)
- free_bootmem(pblocks[i].base, pblocks[i].size);
+ base = p->base << PAGE_SHIFT;
+ size = p->pages << PAGE_SHIFT;
+ type = prom_memtype_classify(p->type);
- /* This test is simpleminded. It will fail if the bootmem bitmap
- falls into multiple adjacent ARC memory areas. */
- if (bootmap_size > largest->size) {
- prom_printf("CRITIAL: overwriting PROM data.\n");
- BUG();
+ add_memory_region(base, size, type);
}
-
- /* Reserve the memory bootmap itself */
- reserve_bootmem(largest->base, bootmap_size);
-
- printk("PROMLIB: Total free ram %dK / %dMB.\n",
- totram >> 10, totram >> 20);
}
void __init
prom_free_prom_memory (void)
{
- struct prom_pmemblock *p;
unsigned long freed = 0;
unsigned long addr;
+ int i;
- for (p = pblocks; p->size != 0; p++) {
- if (p->type != MEMTYPE_PROM)
+ for (i = 0; i < boot_mem_map.nr_map; i++) {
+ if (boot_mem_map.map[i].type != BOOT_MEM_ROM_DATA)
continue;
- addr = PAGE_OFFSET + p->base;
- while (addr < p->base + p->size) {
- ClearPageReserved(virt_to_page(addr));
- set_page_count(virt_to_page(addr), 1);
- free_page(addr);
+ addr = boot_mem_map.map[i].addr;
+ while (addr < boot_mem_map.map[i].addr
+ + boot_mem_map.map[i].size) {
+ ClearPageReserved(virt_to_page(__va(addr)));
+ set_page_count(virt_to_page(__va(addr)), 1);
+ free_page((unsigned long)__va(addr));
addr += PAGE_SIZE;
freed += PAGE_SIZE;
}
-/* $Id: misc.c,v 1.1 1998/10/18 13:32:09 tsbogend Exp $
- *
+/*
* misc.c: Miscellaneous ARCS PROM routines.
*
* Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
#include <asm/bootinfo.h>
#include <asm/system.h>
-extern unsigned long mips_cputype;
extern void *sgiwd93_host;
extern void reset_wd33c93(void *instance);
void prom_halt(void)
{
- bcops->bc_disable();
+ bc_disable();
cli();
#if CONFIG_SCSI_SGIWD93
reset_wd33c93(sgiwd93_host);
void prom_powerdown(void)
{
- bcops->bc_disable();
+ bc_disable();
cli();
#if CONFIG_SCSI_SGIWD93
reset_wd33c93(sgiwd93_host);
/* XXX is this a soft reset basically? XXX */
void prom_restart(void)
{
- bcops->bc_disable();
+ bc_disable();
cli();
#if CONFIG_SCSI_SGIWD93
reset_wd33c93(sgiwd93_host);
void prom_reboot(void)
{
- bcops->bc_disable();
+ bc_disable();
cli();
#if CONFIG_SCSI_SGIWD93
reset_wd33c93(sgiwd93_host);
void prom_imode(void)
{
- bcops->bc_disable();
+ bc_disable();
cli();
#if CONFIG_SCSI_SGIWD93
reset_wd33c93(sgiwd93_host);
+++ /dev/null
-/*
- * printf.c: Putting things on the screen using SGI arcs
- * PROM facilities.
- *
- * Copyright (C) 1996 David S. Miller (dm@sgi.com)
- *
- * $Id: printf.c,v 1.3 1999/10/09 00:00:57 ralf Exp $
- */
-#include <linux/config.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-
-#include <asm/sgialib.h>
-
-static char ppbuf[1024];
-
-#ifdef CONFIG_SGI_PROM_CONSOLE
-void prom_printf(char *fmt, ...)
-#else
-void __init prom_printf(char *fmt, ...)
-#endif
-{
- va_list args;
- char ch, *bptr;
- int i;
-
- va_start(args, fmt);
- i = vsprintf(ppbuf, fmt, args);
-
- bptr = ppbuf;
-
- while((ch = *(bptr++)) != 0) {
- if(ch == '\n')
- prom_putchar('\r');
-
- prom_putchar(ch);
- }
- va_end(args);
- return;
-}
-# $Id: Makefile,v 1.3 1999/08/13 17:07:26 harald Exp $
#
# Makefile for the Baget specific kernel interface routines
# under Linux.
all: baget.a
O_TARGET := baget.a
-O_OBJS := baget.o print.o setup.o time.o irq.o bagetIRQ.o reset.o wbflush.o
-
-ifeq ($(CONFIG_SERIAL),y)
- OX_OBJS += vacserial.o
-else
- ifeq ($(CONFIG_SERIAL),m)
- MX_OBJS += vacserial.o
- endif
-endif
-ifeq ($(CONFIG_VAC_RTC),y)
- OX_OBJS += vacrtc.o
-else
- ifeq ($(CONFIG_VAC_RTC),m)
- MX_OBJS += vacrtc.o
- endif
-endif
+
+export-objs := vacserial.o vacrtc.o
+obj-y := baget.o print.o setup.o time.o irq.o bagetIRQ.o \
+ reset.o wbflush.o
+obj-$(CONFIG_SERIAL) += vacserial.o
+obj-$(CONFIG_VAC_RTC) += vacrtc.o
bagetIRQ.o : bagetIRQ.S
$(CC) $(CFLAGS) -c -o $@ $<
-# $Id$
+#
# Makefile for the Baget/MIPS prom emulator library routines.
#
# Note! Dependencies are done automagically by 'make dep', which also
#
# Note 2! The CFLAGS definitions are now in the main makefile...
-O_TARGET := bagetlib.a
-O_OBJS := init.o
+L_TARGET := bagetlib.a
-all: $(O_TARGET)
+obj-y := init.o
include $(TOPDIR)/Rules.make
bool 'Support for SGI IP22' CONFIG_SGI_IP22
bool 'Support for SNI RM200 PCI' CONFIG_SNI_RM200_PCI
+define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y
+define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n
+
#
# Select some configuration options automatically for certain systems.
#
# if [ "$CONFIG_ACCESSBUS" = "y" ]; then
# bool 'MAXINE Access.Bus mouse (VSXXX-BB/GB) support' CONFIG_DTOP_MOUSE
# fi
- bool 'Enhanced Real Time Clock Support' CONFIG_RTC
+ bool 'Enhanced Real Time Clock Support' CONFIG_MIPS_RTC
+
+ define_tristate CONFIG_RTC $CONFIG_MIPS_RTC
+
endmenu
fi
#
# Note 2! The CFLAGS definitions are now in the main makefile...
#
-# $Id$
-#
.S.s:
$(CPP) $(CFLAGS) $< -o $*.s
$(CC) $(CFLAGS) -c $< -o $*.o
O_TARGET = ddb5074.a
-O_OBJS = setup.o irq.o time.o prom.o pci.o pci-dma.o int-handler.o nile4.o
+
+obj-y := setup.o irq.o time.o prom.o pci.o int-handler.o nile4.o
include $(TOPDIR)/Rules.make
*
* Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com>
* Sony Software Development Center Europe (SDCE), Brussels
- *
- * $Id: int-handler.S,v 1.1 2000/01/26 00:07:44 ralf Exp $
*/
-
#include <asm/asm.h>
#include <asm/mipsregs.h>
#include <asm/regdef.h>
#include <asm/stackframe.h>
- /* A lot of complication here is taken away because:
- *
- * 1) We handle one interrupt and return, sitting in a loop
- * and moving across all the pending IRQ bits in the cause
- * register is _NOT_ the answer, the common case is one
- * pending IRQ so optimize in that direction.
- *
- * 2) We need not check against bits in the status register
- * IRQ mask, that would make this routine slow as hell.
- *
- * 3) Linux only thinks in terms of all IRQs on or all IRQs
- * off, nothing in between like BSD spl() brain-damage.
- *
- * Furthermore, the IRQs on the INDY look basically (barring
- * software IRQs which we don't use at all) like:
- *
- * MIPS IRQ Source
- * -------- ------
- * 0 Software (ignored)
- * 1 Software (ignored)
- * 2 Local IRQ level zero
- * 3 Local IRQ level one
- * 4 8254 Timer zero
- * 5 8254 Timer one
- * 6 Bus Error
- * 7 R4k timer (what we use)
- *
- * We handle the IRQ according to _our_ priority which is:
- *
- * Highest ---- R4k Timer
- * Local IRQ zero
- * Local IRQ one
- * Bus Error
- * 8254 Timer zero
- * Lowest ---- 8254 Timer one
- *
- * then we just return, if multiple IRQs are pending then
- * we will just take another exception, big deal.
- */
+/* A lot of complication here is taken away because:
+ *
+ * 1) We handle one interrupt and return, sitting in a loop and moving across
+ * all the pending IRQ bits in the cause register is _NOT_ the answer, the
+ * common case is one pending IRQ so optimize in that direction.
+ *
+ * 2) We need not check against bits in the status register IRQ mask, that
+ * would make this routine slow as hell.
+ *
+ * 3) Linux only thinks in terms of all IRQs on or all IRQs off, nothing in
+ * between like BSD spl() brain-damage.
+ *
+ * Furthermore, the IRQs on the INDY look basically (barring software IRQs
+ * which we don't use at all) like:
+ *
+ * MIPS IRQ Source
+ * -------- ------
+ * 0 Software (ignored)
+ * 1 Software (ignored)
+ * 2 Local IRQ level zero
+ * 3 Local IRQ level one
+ * 4 8254 Timer zero
+ * 5 8254 Timer one
+ * 6 Bus Error
+ * 7 R4k timer (what we use)
+ *
+ * We handle the IRQ according to _our_ priority which is:
+ *
+ * Highest ---- R4k Timer
+ * Local IRQ zero
+ * Local IRQ one
+ * Bus Error
+ * 8254 Timer zero
+ * Lowest ---- 8254 Timer one
+ *
+ * then we just return, if multiple IRQs are pending then we will just take
+ * another exception, big deal.
+ */
.text
.set noreorder
*
* Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com>
* Sony Software Development Center Europe (SDCE), Brussels
- *
- * $Id: irq.c,v 1.1 2000/01/26 00:07:44 ralf Exp $
*/
-
#include <linux/config.h>
#include <linux/init.h>
#include <linux/signal.h>
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
+
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/ptrace.h>
extern asmlinkage void ddbIRQ(void);
extern asmlinkage void i8259_do_irq(int irq, struct pt_regs *regs);
-extern asmlinkage void do_IRQ(int irq, struct pt_regs * regs);
+extern asmlinkage void do_IRQ(int irq, struct pt_regs *regs);
void no_action(int cpl, void *dev_id, struct pt_regs *regs)
static void m1543_irq_setup(void)
{
- /*
- * The ALI M1543 has 13 interrupt inputs, IRQ1..IRQ13. Not all
- * the possible IO sources in the M1543 are in use by us. We will
- * use the following mapping:
- *
- * IRQ1 - keyboard (default set by M1543)
- * IRQ3 - reserved for UART B (default set by M1543) (note that
- * the schematics for the DDB Vrc-5074 board seem to
- * indicate that IRQ3 is connected to the DS1386
- * watchdog timer interrupt output so we might have
- * a conflict)
- * IRQ4 - reserved for UART A (default set by M1543)
- * IRQ5 - parallel (default set by M1543)
- * IRQ8 - DS1386 time of day (RTC) interrupt
- * IRQ12 - mouse
- */
-
- /*
- * Assing mouse interrupt to IRQ12
- */
-
- /* Enter configuration mode */
- outb(0x51, M1543_PNP_CONFIG);
- outb(0x23, M1543_PNP_CONFIG);
-
- /* Select logical device 7 (Keyboard) */
- outb(0x07, M1543_PNP_INDEX);
- outb(0x07, M1543_PNP_DATA);
-
- /* Select IRQ12 */
- outb(0x72, M1543_PNP_INDEX);
- outb(0x0c, M1543_PNP_DATA);
-
- /* Leave configration mode */
- outb(0xbb, M1543_PNP_CONFIG);
-
-
- /* Initialize the 8259 PIC in the M1543 */
- i8259_init();
-
- /* Enable the interrupt cascade */
- nile4_enable_irq(NILE4_INT_INTE);
-
- request_region(M1543_PNP_CONFIG, 2, "M1543 config");
- request_region(M1543_INT1_MASTER_ELCR, 2, "pic ELCR");
+ /*
+ * The ALI M1543 has 13 interrupt inputs, IRQ1..IRQ13. Not all
+ * the possible IO sources in the M1543 are in use by us. We will
+ * use the following mapping:
+ *
+ * IRQ1 - keyboard (default set by M1543)
+ * IRQ3 - reserved for UART B (default set by M1543) (note that
+ * the schematics for the DDB Vrc-5074 board seem to
+ * indicate that IRQ3 is connected to the DS1386
+ * watchdog timer interrupt output so we might have
+ * a conflict)
+ * IRQ4 - reserved for UART A (default set by M1543)
+ * IRQ5 - parallel (default set by M1543)
+ * IRQ8 - DS1386 time of day (RTC) interrupt
+ * IRQ12 - mouse
+ */
+
+ /*
+ * Assing mouse interrupt to IRQ12
+ */
+
+ /* Enter configuration mode */
+ outb(0x51, M1543_PNP_CONFIG);
+ outb(0x23, M1543_PNP_CONFIG);
+
+ /* Select logical device 7 (Keyboard) */
+ outb(0x07, M1543_PNP_INDEX);
+ outb(0x07, M1543_PNP_DATA);
+
+ /* Select IRQ12 */
+ outb(0x72, M1543_PNP_INDEX);
+ outb(0x0c, M1543_PNP_DATA);
+
+ /* Leave configration mode */
+ outb(0xbb, M1543_PNP_CONFIG);
+
+
+ /* Initialize the 8259 PIC in the M1543 */
+ i8259_init();
+
+ /* Enable the interrupt cascade */
+ nile4_enable_irq(NILE4_INT_INTE);
+
+ request_region(M1543_PNP_CONFIG, 2, "M1543 config");
+ request_region(M1543_INT1_MASTER_ELCR, 2, "pic ELCR");
}
static void nile4_irq_setup(void)
{
- int i;
+ int i;
- /* Map all interrupts to CPU int #0 */
- nile4_map_irq_all(0);
+ /* Map all interrupts to CPU int #0 */
+ nile4_map_irq_all(0);
- /* PCI INTA#-E# must be level triggered */
- nile4_set_pci_irq_level_or_edge(0, 1);
- nile4_set_pci_irq_level_or_edge(1, 1);
- nile4_set_pci_irq_level_or_edge(2, 1);
- nile4_set_pci_irq_level_or_edge(3, 1);
- nile4_set_pci_irq_level_or_edge(4, 1);
+ /* PCI INTA#-E# must be level triggered */
+ nile4_set_pci_irq_level_or_edge(0, 1);
+ nile4_set_pci_irq_level_or_edge(1, 1);
+ nile4_set_pci_irq_level_or_edge(2, 1);
+ nile4_set_pci_irq_level_or_edge(3, 1);
+ nile4_set_pci_irq_level_or_edge(4, 1);
- /* PCI INTA#-D# must be active low, INTE# must be active high */
- nile4_set_pci_irq_polarity(0, 0);
- nile4_set_pci_irq_polarity(1, 0);
- nile4_set_pci_irq_polarity(2, 0);
- nile4_set_pci_irq_polarity(3, 0);
- nile4_set_pci_irq_polarity(4, 1);
+ /* PCI INTA#-D# must be active low, INTE# must be active high */
+ nile4_set_pci_irq_polarity(0, 0);
+ nile4_set_pci_irq_polarity(1, 0);
+ nile4_set_pci_irq_polarity(2, 0);
+ nile4_set_pci_irq_polarity(3, 0);
+ nile4_set_pci_irq_polarity(4, 1);
- for (i = 0; i < 16; i++)
- nile4_clear_irq(i);
+ for (i = 0; i < 16; i++)
+ nile4_clear_irq(i);
- /* Enable CPU int #0 */
- nile4_enable_irq_output(0);
+ /* Enable CPU int #0 */
+ nile4_enable_irq_output(0);
- request_mem_region(NILE4_BASE, NILE4_SIZE, "Nile 4");
+ request_mem_region(NILE4_BASE, NILE4_SIZE, "Nile 4");
}
/*
* IRQ2 is cascade interrupt to second interrupt controller
*/
-
-static struct irqaction irq2 = { no_action, 0, 0, "cascade", NULL, NULL };
+static struct irqaction irq2 = { no_action, 0, 0, "cascade", NULL, NULL };
void disable_irq(unsigned int irq_nr)
{
- if (is_i8259_irq(irq_nr))
- i8259_disable_irq(irq_nr);
- else
- nile4_disable_irq(irq_to_nile4(irq_nr));
+ if (is_i8259_irq(irq_nr))
+ i8259_disable_irq(irq_nr);
+ else
+ nile4_disable_irq(irq_to_nile4(irq_nr));
}
void enable_irq(unsigned int irq_nr)
{
- if (is_i8259_irq(irq_nr))
- i8259_enable_irq(irq_nr);
- else
- nile4_enable_irq(irq_to_nile4(irq_nr));
+ if (is_i8259_irq(irq_nr))
+ i8259_enable_irq(irq_nr);
+ else
+ nile4_enable_irq(irq_to_nile4(irq_nr));
}
int table[16] = { 0, };
void ddb_local0_irqdispatch(struct pt_regs *regs)
{
- u32 mask;
- int nile4_irq;
+ u32 mask;
+ int nile4_irq;
#if 1
- volatile static int nesting = 0;
- if (nesting++ == 0)
- ddb5074_led_d3(1);
- ddb5074_led_hex(nesting < 16 ? nesting : 15);
+ volatile static int nesting = 0;
+ if (nesting++ == 0)
+ ddb5074_led_d3(1);
+ ddb5074_led_hex(nesting < 16 ? nesting : 15);
#endif
- mask = nile4_get_irq_stat(0);
- nile4_clear_irq_mask(mask);
-
- /* Handle the timer interrupt first */
- if (mask & (1<<NILE4_INT_GPT)) {
- nile4_disable_irq(NILE4_INT_GPT);
- do_IRQ(nile4_to_irq(NILE4_INT_GPT), regs);
- nile4_enable_irq(NILE4_INT_GPT);
- mask &= ~(1<<NILE4_INT_GPT);
- }
- for (nile4_irq = 0; mask; nile4_irq++, mask >>= 1)
- if (mask & 1) {
- nile4_disable_irq(nile4_irq);
- if (nile4_irq == NILE4_INT_INTE) {
- int i8259_irq = nile4_i8259_iack();
- i8259_do_irq(i8259_irq, regs);
- } else
- do_IRQ(nile4_to_irq(nile4_irq), regs);
- nile4_enable_irq(nile4_irq);
- }
+ mask = nile4_get_irq_stat(0);
+ nile4_clear_irq_mask(mask);
+ /* Handle the timer interrupt first */
+ if (mask & (1 << NILE4_INT_GPT)) {
+ nile4_disable_irq(NILE4_INT_GPT);
+ do_IRQ(nile4_to_irq(NILE4_INT_GPT), regs);
+ nile4_enable_irq(NILE4_INT_GPT);
+ mask &= ~(1 << NILE4_INT_GPT);
+ }
+ for (nile4_irq = 0; mask; nile4_irq++, mask >>= 1)
+ if (mask & 1) {
+ nile4_disable_irq(nile4_irq);
+ if (nile4_irq == NILE4_INT_INTE) {
+ int i8259_irq = nile4_i8259_iack();
+ i8259_do_irq(i8259_irq, regs);
+ } else
+ do_IRQ(nile4_to_irq(nile4_irq), regs);
+ nile4_enable_irq(nile4_irq);
+ }
#if 1
- if (--nesting == 0)
- ddb5074_led_d3(0);
- ddb5074_led_hex(nesting < 16 ? nesting : 15);
+ if (--nesting == 0)
+ ddb5074_led_d3(0);
+ ddb5074_led_hex(nesting < 16 ? nesting : 15);
#endif
}
void ddb_local1_irqdispatch(void)
{
- printk("ddb_local1_irqdispatch called\n");
+ printk("ddb_local1_irqdispatch called\n");
}
void ddb_buserror_irq(void)
{
- printk("ddb_buserror_irq called\n");
+ printk("ddb_buserror_irq called\n");
}
void ddb_8254timer_irq(void)
{
- printk("ddb_8254timer_irq called\n");
+ printk("ddb_8254timer_irq called\n");
}
void __init ddb_irq_setup(void)
{
#ifdef CONFIG_REMOTE_DEBUG
- if (remote_debug)
- set_debug_traps();
- breakpoint(); /* you may move this line to whereever you want :-) */
+ if (remote_debug)
+ set_debug_traps();
+ breakpoint(); /* you may move this line to whereever you want :-) */
#endif
- request_region(0x20, 0x20, "pic1");
- request_region(0xa0, 0x20, "pic2");
- i8259_setup_irq(2, &irq2);
+ request_region(0x20, 0x20, "pic1");
+ request_region(0xa0, 0x20, "pic2");
+ i8259_setup_irq(2, &irq2);
- nile4_irq_setup();
- m1543_irq_setup();
+ nile4_irq_setup();
+ m1543_irq_setup();
- set_except_vector(0, ddbIRQ);
+ set_except_vector(0, ddbIRQ);
}
-
*
* Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com>
* Sony Software Development Center Europe (SDCE), Brussels
- *
- * $Id$
*/
-
#include <linux/kernel.h>
#include <linux/types.h>
-#include <asm/nile4.h>
+#include <asm/nile4.h>
- /*
- * Physical Device Address Registers
- *
- * Note: 32 bit addressing only!
- */
-void nile4_set_pdar(u32 pdar, u32 phys, u32 size, int width, int on_memory_bus,
- int visible)
+/*
+ * Physical Device Address Registers
+ *
+ * Note: 32 bit addressing only!
+ */
+void nile4_set_pdar(u32 pdar, u32 phys, u32 size, int width,
+ int on_memory_bus, int visible)
{
- u32 maskbits;
- u32 widthbits;
-
- if (pdar > NILE4_BOOTCS || (pdar & 7)) {
- printk("nile4_set_pdar: invalid pdar %d\n", pdar);
- return;
- }
- if (pdar == NILE4_INTCS && size != 0x00200000) {
- printk("nile4_set_pdar: INTCS size must be 2 MB\n");
- return;
- }
- switch (size) {
-#if 0 /* We don't support 4 GB yet */
+ u32 maskbits;
+ u32 widthbits;
+
+ if (pdar > NILE4_BOOTCS || (pdar & 7)) {
+ printk("nile4_set_pdar: invalid pdar %d\n", pdar);
+ return;
+ }
+ if (pdar == NILE4_INTCS && size != 0x00200000) {
+ printk("nile4_set_pdar: INTCS size must be 2 MB\n");
+ return;
+ }
+ switch (size) {
+#if 0 /* We don't support 4 GB yet */
case 0x100000000: /* 4 GB */
- maskbits = 4;
- break;
+ maskbits = 4;
+ break;
#endif
case 0x80000000: /* 2 GB */
- maskbits = 5;
- break;
+ maskbits = 5;
+ break;
case 0x40000000: /* 1 GB */
- maskbits = 6;
- break;
+ maskbits = 6;
+ break;
case 0x20000000: /* 512 MB */
- maskbits = 7;
- break;
+ maskbits = 7;
+ break;
case 0x10000000: /* 256 MB */
- maskbits = 8;
- break;
+ maskbits = 8;
+ break;
case 0x08000000: /* 128 MB */
- maskbits = 9;
- break;
+ maskbits = 9;
+ break;
case 0x04000000: /* 64 MB */
- maskbits = 10;
- break;
+ maskbits = 10;
+ break;
case 0x02000000: /* 32 MB */
- maskbits = 11;
- break;
+ maskbits = 11;
+ break;
case 0x01000000: /* 16 MB */
- maskbits = 12;
- break;
+ maskbits = 12;
+ break;
case 0x00800000: /* 8 MB */
- maskbits = 13;
- break;
+ maskbits = 13;
+ break;
case 0x00400000: /* 4 MB */
- maskbits = 14;
- break;
+ maskbits = 14;
+ break;
case 0x00200000: /* 2 MB */
- maskbits = 15;
- break;
- case 0: /* OFF */
- maskbits = 0;
- break;
+ maskbits = 15;
+ break;
+ case 0: /* OFF */
+ maskbits = 0;
+ break;
default:
- printk("nile4_set_pdar: unsupported size %p\n", (void *)size);
- return;
- }
- switch (width) {
+ printk("nile4_set_pdar: unsupported size %p\n", (void *) size);
+ return;
+ }
+ switch (width) {
case 8:
- widthbits = 0;
- break;
+ widthbits = 0;
+ break;
case 16:
- widthbits = 1;
- break;
+ widthbits = 1;
+ break;
case 32:
- widthbits = 2;
- break;
+ widthbits = 2;
+ break;
case 64:
- widthbits = 3;
- break;
+ widthbits = 3;
+ break;
default:
- printk("nile4_set_pdar: unsupported width %d\n", width);
- return;
- }
- nile4_out32(pdar, maskbits | (on_memory_bus ? 0x10 : 0) |
- (visible ? 0x20 : 0) | (widthbits << 6) |
- (phys & 0xffe00000));
- nile4_out32(pdar+4, 0);
- /*
- * When programming a PDAR, the register should be read immediately after
- * writing it. This ensures that address decoders are properly configured.
- */
- (void)nile4_in32(pdar);
- (void)nile4_in32(pdar+4);
+ printk("nile4_set_pdar: unsupported width %d\n", width);
+ return;
+ }
+ nile4_out32(pdar, maskbits | (on_memory_bus ? 0x10 : 0) |
+ (visible ? 0x20 : 0) | (widthbits << 6) |
+ (phys & 0xffe00000));
+ nile4_out32(pdar + 4, 0);
+ /*
+ * When programming a PDAR, the register should be read immediately
+ * after writing it. This ensures that address decoders are properly
+ * configured.
+ */
+ nile4_in32(pdar);
+ nile4_in32(pdar + 4);
}
- /*
- * PCI Master Registers
- *
- * Note: 32 bit addressing only!
- */
-
+/*
+ * PCI Master Registers
+ *
+ * Note: 32 bit addressing only!
+ */
void nile4_set_pmr(u32 pmr, u32 type, u32 addr)
{
- if (pmr != NILE4_PCIINIT0 && pmr != NILE4_PCIINIT1) {
- printk("nile4_set_pmr: invalid pmr %d\n", pmr);
- return;
- }
- switch (type) {
+ if (pmr != NILE4_PCIINIT0 && pmr != NILE4_PCIINIT1) {
+ printk("nile4_set_pmr: invalid pmr %d\n", pmr);
+ return;
+ }
+ switch (type) {
case NILE4_PCICMD_IACK: /* PCI Interrupt Acknowledge */
case NILE4_PCICMD_IO: /* PCI I/O Space */
case NILE4_PCICMD_MEM: /* PCI Memory Space */
case NILE4_PCICMD_CFG: /* PCI Configuration Space */
- break;
+ break;
default:
- printk("nile4_set_pmr: invalid type %d\n", type);
- return;
- }
- nile4_out32(pmr, (type << 1) | 0x10 | (addr & 0xffe00000));
- nile4_out32(pmr+4, 0);
+ printk("nile4_set_pmr: invalid type %d\n", type);
+ return;
+ }
+ nile4_out32(pmr, (type << 1) | 0x10 | (addr & 0xffe00000));
+ nile4_out32(pmr + 4, 0);
}
- /*
- * Interrupt Programming
- */
-
+/*
+ * Interrupt Programming
+ */
void nile4_map_irq(int nile4_irq, int cpu_irq)
{
- u32 offset, t;
-
- offset = NILE4_INTCTRL;
- if (nile4_irq >= 8) {
- offset += 4;
- nile4_irq -= 8;
- }
- t = nile4_in32(offset);
- t &= ~(7 << (nile4_irq*4));
- t |= cpu_irq << (nile4_irq*4);
- nile4_out32(offset, t);
+ u32 offset, t;
+
+ offset = NILE4_INTCTRL;
+ if (nile4_irq >= 8) {
+ offset += 4;
+ nile4_irq -= 8;
+ }
+ t = nile4_in32(offset);
+ t &= ~(7 << (nile4_irq * 4));
+ t |= cpu_irq << (nile4_irq * 4);
+ nile4_out32(offset, t);
}
void nile4_map_irq_all(int cpu_irq)
{
- u32 all, t;
-
- all = cpu_irq;
- all |= all << 4;
- all |= all << 8;
- all |= all << 16;
- t = nile4_in32(NILE4_INTCTRL);
- t &= 0x88888888;
- t |= all;
- nile4_out32(NILE4_INTCTRL, t);
- t = nile4_in32(NILE4_INTCTRL+4);
- t &= 0x88888888;
- t |= all;
- nile4_out32(NILE4_INTCTRL+4, t);
+ u32 all, t;
+
+ all = cpu_irq;
+ all |= all << 4;
+ all |= all << 8;
+ all |= all << 16;
+ t = nile4_in32(NILE4_INTCTRL);
+ t &= 0x88888888;
+ t |= all;
+ nile4_out32(NILE4_INTCTRL, t);
+ t = nile4_in32(NILE4_INTCTRL + 4);
+ t &= 0x88888888;
+ t |= all;
+ nile4_out32(NILE4_INTCTRL + 4, t);
}
void nile4_enable_irq(int nile4_irq)
{
- u32 offset, t;
-
- offset = NILE4_INTCTRL;
- if (nile4_irq >= 8) {
- offset += 4;
- nile4_irq -= 8;
- }
- t = nile4_in32(offset);
- t |= 8 << (nile4_irq*4);
- nile4_out32(offset, t);
+ u32 offset, t;
+
+ offset = NILE4_INTCTRL;
+ if (nile4_irq >= 8) {
+ offset += 4;
+ nile4_irq -= 8;
+ }
+ t = nile4_in32(offset);
+ t |= 8 << (nile4_irq * 4);
+ nile4_out32(offset, t);
}
void nile4_disable_irq(int nile4_irq)
{
- u32 offset, t;
-
- offset = NILE4_INTCTRL;
- if (nile4_irq >= 8) {
- offset += 4;
- nile4_irq -= 8;
- }
- t = nile4_in32(offset);
- t &= ~(8 << (nile4_irq*4));
- nile4_out32(offset, t);
+ u32 offset, t;
+
+ offset = NILE4_INTCTRL;
+ if (nile4_irq >= 8) {
+ offset += 4;
+ nile4_irq -= 8;
+ }
+ t = nile4_in32(offset);
+ t &= ~(8 << (nile4_irq * 4));
+ nile4_out32(offset, t);
}
void nile4_disable_irq_all(void)
{
- nile4_out32(NILE4_INTCTRL, 0);
- nile4_out32(NILE4_INTCTRL+4, 0);
+ nile4_out32(NILE4_INTCTRL, 0);
+ nile4_out32(NILE4_INTCTRL + 4, 0);
}
u16 nile4_get_irq_stat(int cpu_irq)
{
- return nile4_in16(NILE4_INTSTAT0+cpu_irq*2);
+ return nile4_in16(NILE4_INTSTAT0 + cpu_irq * 2);
}
void nile4_enable_irq_output(int cpu_irq)
{
- u32 t;
+ u32 t;
- t = nile4_in32(NILE4_INTSTAT1+4);
- t |= 1 << (16+cpu_irq);
- nile4_out32(NILE4_INTSTAT1, t);
+ t = nile4_in32(NILE4_INTSTAT1 + 4);
+ t |= 1 << (16 + cpu_irq);
+ nile4_out32(NILE4_INTSTAT1, t);
}
void nile4_disable_irq_output(int cpu_irq)
{
- u32 t;
+ u32 t;
- t = nile4_in32(NILE4_INTSTAT1+4);
- t &= ~(1 << (16+cpu_irq));
- nile4_out32(NILE4_INTSTAT1, t);
+ t = nile4_in32(NILE4_INTSTAT1 + 4);
+ t &= ~(1 << (16 + cpu_irq));
+ nile4_out32(NILE4_INTSTAT1, t);
}
void nile4_set_pci_irq_polarity(int pci_irq, int high)
{
- u32 t;
-
- t = nile4_in32(NILE4_INTPPES);
- if (high)
- t &= ~(1 << (pci_irq*2));
- else
- t |= 1 << (pci_irq*2);
- nile4_out32(NILE4_INTPPES, t);
+ u32 t;
+
+ t = nile4_in32(NILE4_INTPPES);
+ if (high)
+ t &= ~(1 << (pci_irq * 2));
+ else
+ t |= 1 << (pci_irq * 2);
+ nile4_out32(NILE4_INTPPES, t);
}
void nile4_set_pci_irq_level_or_edge(int pci_irq, int level)
{
- u32 t;
-
- t = nile4_in32(NILE4_INTPPES);
- if (level)
- t |= 2 << (pci_irq*2);
- else
- t &= ~(2 << (pci_irq*2));
- nile4_out32(NILE4_INTPPES, t);
+ u32 t;
+
+ t = nile4_in32(NILE4_INTPPES);
+ if (level)
+ t |= 2 << (pci_irq * 2);
+ else
+ t &= ~(2 << (pci_irq * 2));
+ nile4_out32(NILE4_INTPPES, t);
}
void nile4_clear_irq(int nile4_irq)
{
- nile4_out32(NILE4_INTCLR, 1 << nile4_irq);
+ nile4_out32(NILE4_INTCLR, 1 << nile4_irq);
}
void nile4_clear_irq_mask(u32 mask)
{
- nile4_out32(NILE4_INTCLR, mask);
+ nile4_out32(NILE4_INTCLR, mask);
}
u8 nile4_i8259_iack(void)
{
- u8 irq;
-
- /* Set window 0 for interrupt acknowledge */
- nile4_set_pmr(NILE4_PCIINIT0, NILE4_PCICMD_IACK, 0);
- irq = *(volatile u8 *)NILE4_PCI_IACK_BASE;
- /* Set window 0 for PCI I/O space */
- nile4_set_pmr(NILE4_PCIINIT0, NILE4_PCICMD_IO, 0);
- return irq;
+ u8 irq;
+
+ /* Set window 0 for interrupt acknowledge */
+ nile4_set_pmr(NILE4_PCIINIT0, NILE4_PCICMD_IACK, 0);
+ irq = *(volatile u8 *) NILE4_PCI_IACK_BASE;
+ /* Set window 0 for PCI I/O space */
+ nile4_set_pmr(NILE4_PCIINIT0, NILE4_PCICMD_IO, 0);
+ return irq;
}
#if 0
void nile4_dump_irq_status(void)
{
- printk("CPUSTAT = %p:%p\n", (void *)nile4_in32(NILE4_CPUSTAT+4),
- (void *)nile4_in32(NILE4_CPUSTAT));
- printk("INTCTRL = %p:%p\n", (void *)nile4_in32(NILE4_INTCTRL+4),
- (void *)nile4_in32(NILE4_INTCTRL));
- printk("INTSTAT0 = %p:%p\n", (void *)nile4_in32(NILE4_INTSTAT0+4),
- (void *)nile4_in32(NILE4_INTSTAT0));
- printk("INTSTAT1 = %p:%p\n", (void *)nile4_in32(NILE4_INTSTAT1+4),
- (void *)nile4_in32(NILE4_INTSTAT1));
- printk("INTCLR = %p:%p\n", (void *)nile4_in32(NILE4_INTCLR+4),
- (void *)nile4_in32(NILE4_INTCLR));
- printk("INTPPES = %p:%p\n", (void *)nile4_in32(NILE4_INTPPES+4),
- (void *)nile4_in32(NILE4_INTPPES));
+ printk("CPUSTAT = %p:%p\n", (void *) nile4_in32(NILE4_CPUSTAT + 4),
+ (void *) nile4_in32(NILE4_CPUSTAT));
+ printk("INTCTRL = %p:%p\n", (void *) nile4_in32(NILE4_INTCTRL + 4),
+ (void *) nile4_in32(NILE4_INTCTRL));
+ printk("INTSTAT0 = %p:%p\n",
+ (void *) nile4_in32(NILE4_INTSTAT0 + 4),
+ (void *) nile4_in32(NILE4_INTSTAT0));
+ printk("INTSTAT1 = %p:%p\n",
+ (void *) nile4_in32(NILE4_INTSTAT1 + 4),
+ (void *) nile4_in32(NILE4_INTSTAT1));
+ printk("INTCLR = %p:%p\n", (void *) nile4_in32(NILE4_INTCLR + 4),
+ (void *) nile4_in32(NILE4_INTCLR));
+ printk("INTPPES = %p:%p\n", (void *) nile4_in32(NILE4_INTPPES + 4),
+ (void *) nile4_in32(NILE4_INTPPES));
}
#endif
+++ /dev/null
-/*
- * Copyright (C) 2000 Ani Joshi <ajoshi@unixbox.com>
- *
- *
- * Dynamic DMA mapping support.
- *
- * swiped from i386, and cloned for MIPS by Geert.
- *
- */
-
-#include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/string.h>
-#include <linux/pci.h>
-#include <asm/io.h>
-
-void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
- dma_addr_t *dma_handle)
-{
- void *ret;
- int gfp = GFP_ATOMIC;
-
- if (hwdev == NULL || hwdev->dma_mask != 0xffffffff)
- gfp |= GFP_DMA;
- ret = (void *)__get_free_pages(gfp, get_order(size));
-
- if (ret != NULL) {
- memset(ret, 0, size);
- *dma_handle = virt_to_bus(ret);
- }
- return ret;
-}
-
-void pci_free_consistent(struct pci_dev *hwdev, size_t size,
- void *vaddr, dma_addr_t dma_handle)
-{
- free_pages((unsigned long)vaddr, get_order(size));
-}
* Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com>
* Albert Dorofeev <albert@sonycom.com>
* Sony Software Development Center Europe (SDCE), Brussels
- *
- * $Id: pci.c,v 1.4 2000/02/18 00:02:17 ralf Exp $
*/
-
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/ioport.h>
-#include <asm-mips/nile4.h>
+
+#include <asm/nile4.h>
static u32 nile4_pre_pci_access0(int slot_num)
{
- u32 pci_addr = 0;
- u32 virt_addr = NILE4_PCI_CFG_BASE;
-
- /* Set window 1 address 8000000 - 64 bit - 2 MB (PCI config space) */
- nile4_set_pdar(NILE4_PCIW1, PHYSADDR(virt_addr), 0x00200000, 64, 0, 0);
- if (slot_num > 2)
- pci_addr = 0x00040000 << slot_num;
- else
- virt_addr += 0x00040000 << slot_num;
- nile4_set_pmr(NILE4_PCIINIT1, NILE4_PCICMD_CFG, pci_addr);
- return virt_addr;
+ u32 pci_addr = 0;
+ u32 virt_addr = NILE4_PCI_CFG_BASE;
+
+ /* Set window 1 address 8000000 - 64 bit - 2 MB (PCI config space) */
+ nile4_set_pdar(NILE4_PCIW1, PHYSADDR(virt_addr), 0x00200000, 64, 0,
+ 0);
+ if (slot_num > 2)
+ pci_addr = 0x00040000 << slot_num;
+ else
+ virt_addr += 0x00040000 << slot_num;
+ nile4_set_pmr(NILE4_PCIINIT1, NILE4_PCICMD_CFG, pci_addr);
+ return virt_addr;
}
static void nile4_post_pci_access0(void)
{
- /* Set window 1 back to address 8000000 - 64 bit - 128 MB (PCI IO space) */
- nile4_set_pdar(NILE4_PCIW1, PHYSADDR(NILE4_PCI_MEM_BASE), 0x08000000, 64,
- 1, 1);
- nile4_set_pmr(NILE4_PCIINIT1, NILE4_PCICMD_MEM, 0);
+ /*
+ * Set window 1 back to address 8000000 - 64 bit - 128 MB
+ * (PCI IO space)
+ */
+ nile4_set_pdar(NILE4_PCIW1, PHYSADDR(NILE4_PCI_MEM_BASE),
+ 0x08000000, 64, 1, 1);
+ nile4_set_pmr(NILE4_PCIINIT1, NILE4_PCICMD_MEM, 0);
}
-static int nile4_pci_read_config_dword( struct pci_dev *dev,
- int where, u32 *val)
+static int nile4_pci_read_config_dword(struct pci_dev *dev,
+ int where, u32 * val)
{
- int slot_num, func_num;
- u32 base;
-
- /*
- * For starters let's do configuration cycle 0 only (one bus only)
- */
- if (dev->bus->number)
- return PCIBIOS_FUNC_NOT_SUPPORTED;
-
- slot_num = PCI_SLOT(dev->devfn);
- func_num = PCI_FUNC(dev->devfn);
- if (slot_num == 5) {
+ int slot_num, func_num;
+ u32 base;
+
/*
- * This is Nile 4 and it will crash if we access it like other
- * devices
+ * For starters let's do configuration cycle 0 only (one bus only)
*/
- *val = nile4_in32(NILE4_PCI_BASE + where);
+ if (dev->bus->number)
+ return PCIBIOS_FUNC_NOT_SUPPORTED;
+
+ slot_num = PCI_SLOT(dev->devfn);
+ func_num = PCI_FUNC(dev->devfn);
+ if (slot_num == 5) {
+ /*
+ * This is Nile 4 and it will crash if we access it like other
+ * devices
+ */
+ *val = nile4_in32(NILE4_PCI_BASE + where);
+ return PCIBIOS_SUCCESSFUL;
+ }
+ base = nile4_pre_pci_access0(slot_num);
+ *val =
+ *((volatile u32 *) (base + (func_num << 8) + (where & 0xfc)));
+ nile4_post_pci_access0();
return PCIBIOS_SUCCESSFUL;
- }
- base = nile4_pre_pci_access0(slot_num);
- *val = *((volatile u32 *)(base + (func_num << 8) + (where & 0xfc)));
- nile4_post_pci_access0();
- return PCIBIOS_SUCCESSFUL;
}
static int nile4_pci_write_config_dword(struct pci_dev *dev, int where,
u32 val)
{
- int slot_num, func_num;
- u32 base;
-
- /*
- * For starters let's do configuration cycle 0 only (one bus only)
- */
- if (dev->bus->number)
- return PCIBIOS_FUNC_NOT_SUPPORTED;
-
- slot_num = PCI_SLOT(dev->devfn);
- func_num = PCI_FUNC(dev->devfn);
- if (slot_num == 5) {
+ int slot_num, func_num;
+ u32 base;
+
/*
- * This is Nile 4 and it will crash if we access it like other
- * devices
+ * For starters let's do configuration cycle 0 only (one bus only)
*/
- nile4_out32(NILE4_PCI_BASE + where, val);
+ if (dev->bus->number)
+ return PCIBIOS_FUNC_NOT_SUPPORTED;
+
+ slot_num = PCI_SLOT(dev->devfn);
+ func_num = PCI_FUNC(dev->devfn);
+ if (slot_num == 5) {
+ /*
+ * This is Nile 4 and it will crash if we access it like other
+ * devices
+ */
+ nile4_out32(NILE4_PCI_BASE + where, val);
+ return PCIBIOS_SUCCESSFUL;
+ }
+ base = nile4_pre_pci_access0(slot_num);
+ *((volatile u32 *) (base + (func_num << 8) + (where & 0xfc))) =
+ val;
+ nile4_post_pci_access0();
return PCIBIOS_SUCCESSFUL;
- }
- base = nile4_pre_pci_access0(slot_num);
- *((volatile u32 *)(base + (func_num << 8) + (where & 0xfc))) = val;
- nile4_post_pci_access0();
- return PCIBIOS_SUCCESSFUL;
}
-static int nile4_pci_read_config_word(struct pci_dev *dev, int where, u16 *val)
+static int nile4_pci_read_config_word(struct pci_dev *dev, int where,
+ u16 * val)
{
- int status;
- u32 result;
-
- status = nile4_pci_read_config_dword(dev, where, &result);
- if (status != PCIBIOS_SUCCESSFUL)
- return status;
- if (where & 2)
- result >>= 16;
- *val = result & 0xffff;
- return PCIBIOS_SUCCESSFUL;
+ int status;
+ u32 result;
+
+ status = nile4_pci_read_config_dword(dev, where, &result);
+ if (status != PCIBIOS_SUCCESSFUL)
+ return status;
+ if (where & 2)
+ result >>= 16;
+ *val = result & 0xffff;
+ return PCIBIOS_SUCCESSFUL;
}
-static int nile4_pci_read_config_byte(struct pci_dev *dev, int where, u8 *val)
+static int nile4_pci_read_config_byte(struct pci_dev *dev, int where,
+ u8 * val)
{
- int status;
- u32 result;
-
- status = nile4_pci_read_config_dword(dev, where, &result);
- if (status != PCIBIOS_SUCCESSFUL)
- return status;
- if (where & 1)
- result >>= 8;
- if (where & 2)
- result >>= 16;
- *val = result & 0xff;
- return PCIBIOS_SUCCESSFUL;
+ int status;
+ u32 result;
+
+ status = nile4_pci_read_config_dword(dev, where, &result);
+ if (status != PCIBIOS_SUCCESSFUL)
+ return status;
+ if (where & 1)
+ result >>= 8;
+ if (where & 2)
+ result >>= 16;
+ *val = result & 0xff;
+ return PCIBIOS_SUCCESSFUL;
}
-static int nile4_pci_write_config_word(struct pci_dev *dev, int where, u16 val)
+static int nile4_pci_write_config_word(struct pci_dev *dev, int where,
+ u16 val)
{
- int status, shift = 0;
- u32 result;
-
- status = nile4_pci_read_config_dword(dev, where, &result);
- if (status != PCIBIOS_SUCCESSFUL)
- return status;
- if (where & 2)
- shift += 16;
- result &= ~(0xffff << shift);
- result |= val << shift;
- return nile4_pci_write_config_dword(dev, where, result);
+ int status, shift = 0;
+ u32 result;
+
+ status = nile4_pci_read_config_dword(dev, where, &result);
+ if (status != PCIBIOS_SUCCESSFUL)
+ return status;
+ if (where & 2)
+ shift += 16;
+ result &= ~(0xffff << shift);
+ result |= val << shift;
+ return nile4_pci_write_config_dword(dev, where, result);
}
-static int nile4_pci_write_config_byte( struct pci_dev *dev, int where, u8 val)
+static int nile4_pci_write_config_byte(struct pci_dev *dev, int where,
+ u8 val)
{
- int status, shift = 0;
- u32 result;
-
- status = nile4_pci_read_config_dword(dev, where, &result);
- if (status != PCIBIOS_SUCCESSFUL)
- return status;
- if (where & 2)
- shift += 16;
- if (where & 1)
- shift += 8;
- result &= ~(0xff << shift);
- result |= val << shift;
- return nile4_pci_write_config_dword(dev, where, result);
+ int status, shift = 0;
+ u32 result;
+
+ status = nile4_pci_read_config_dword(dev, where, &result);
+ if (status != PCIBIOS_SUCCESSFUL)
+ return status;
+ if (where & 2)
+ shift += 16;
+ if (where & 1)
+ shift += 8;
+ result &= ~(0xff << shift);
+ result |= val << shift;
+ return nile4_pci_write_config_dword(dev, where, result);
}
struct pci_ops nile4_pci_ops = {
- nile4_pci_read_config_byte,
- nile4_pci_read_config_word,
- nile4_pci_read_config_dword,
- nile4_pci_write_config_byte,
- nile4_pci_write_config_word,
- nile4_pci_write_config_dword
+ nile4_pci_read_config_byte,
+ nile4_pci_read_config_word,
+ nile4_pci_read_config_dword,
+ nile4_pci_write_config_byte,
+ nile4_pci_write_config_word,
+ nile4_pci_write_config_dword
};
struct {
- struct resource ram;
- struct resource flash;
- struct resource isa_io;
- struct resource pci_io;
- struct resource isa_mem;
- struct resource pci_mem;
- struct resource nile4;
- struct resource boot;
+ struct resource ram;
+ struct resource flash;
+ struct resource isa_io;
+ struct resource pci_io;
+ struct resource isa_mem;
+ struct resource pci_mem;
+ struct resource nile4;
+ struct resource boot;
} ddb5074_resources = {
- { "RAM", 0x00000000, 0x03ffffff,
- IORESOURCE_MEM | PCI_BASE_ADDRESS_MEM_TYPE_64 },
- { "Flash ROM", 0x04000000, 0x043fffff },
- { "Nile4 ISA I/O", 0x06000000, 0x060fffff },
- { "Nile4 PCI I/O", 0x06100000, 0x07ffffff },
- { "Nile4 ISA mem", 0x08000000, 0x08ffffff, IORESOURCE_MEM },
- { "Nile4 PCI mem", 0x09000000, 0x0fffffff, IORESOURCE_MEM },
- { "Nile4 ctrl", 0x1fa00000, 0x1fbfffff,
- IORESOURCE_MEM | PCI_BASE_ADDRESS_MEM_TYPE_64 },
- { "Boot ROM", 0x1fc00000, 0x1fffffff }
+ { "RAM", 0x00000000, 0x03ffffff,
+ IORESOURCE_MEM | PCI_BASE_ADDRESS_MEM_TYPE_64},
+ { "Flash ROM", 0x04000000, 0x043fffff},
+ { "Nile4 ISA I/O", 0x06000000, 0x060fffff},
+ { "Nile4 PCI I/O", 0x06100000, 0x07ffffff},
+ { "Nile4 ISA mem", 0x08000000, 0x08ffffff, IORESOURCE_MEM},
+ { "Nile4 PCI mem", 0x09000000, 0x0fffffff, IORESOURCE_MEM},
+ { "Nile4 ctrl", 0x1fa00000, 0x1fbfffff,
+ IORESOURCE_MEM | PCI_BASE_ADDRESS_MEM_TYPE_64},
+ { "Boot ROM", 0x1fc00000, 0x1fffffff}
};
static void __init ddb5074_pci_fixup(void)
{
- struct pci_dev *dev;
-
- pci_for_each_dev(dev) {
- if (dev->vendor == PCI_VENDOR_ID_NEC &&
- dev->device == PCI_DEVICE_ID_NEC_NILE4) {
- /*
- * The first 64-bit PCI base register should point to the Nile4
- * control registers. Unfortunately this isn't the case, so we fix
- * it ourselves. This allows the serial driver to find the UART.
- */
- dev->resource[0] = ddb5074_resources.nile4;
- request_resource(&iomem_resource, &dev->resource[0]);
- /*
- * The second 64-bit PCI base register points to the first memory
- * bank. Unfortunately the address is wrong, so we fix it (again).
- */
- dev->resource[2] = ddb5074_resources.ram;
- request_resource(&iomem_resource, &dev->resource[2]);
- } else if (dev->vendor == PCI_VENDOR_ID_AL &&
- dev->device == PCI_DEVICE_ID_AL_M7101) {
- /*
- * It's nice to have the LEDs on the GPIO pins available for
- * debugging
- */
- extern struct pci_dev *pci_pmu;
- u8 t8;
-
- pci_pmu = dev; /* for LEDs D2 and D3 */
- /* Program the lines for LEDs D2 and D3 to output */
- nile4_pci_read_config_byte(dev, 0x7d, &t8);
- t8 |= 0xc0;
- nile4_pci_write_config_byte(dev, 0x7d, t8);
- /* Turn LEDs D2 and D3 off */
- nile4_pci_read_config_byte(dev, 0x7e, &t8);
- t8 |= 0xc0;
- nile4_pci_write_config_byte(dev, 0x7e, t8);
+ struct pci_dev *dev;
+
+ pci_for_each_dev(dev) {
+ if (dev->vendor == PCI_VENDOR_ID_NEC &&
+ dev->device == PCI_DEVICE_ID_NEC_NILE4) {
+ /*
+ * The first 64-bit PCI base register should point to
+ * the Nile4 control registers. Unfortunately this
+ * isn't the case, so we fix it ourselves. This allows
+ * the serial driver to find the UART.
+ */
+ dev->resource[0] = ddb5074_resources.nile4;
+ request_resource(&iomem_resource,
+ &dev->resource[0]);
+ /*
+ * The second 64-bit PCI base register points to the
+ * first memory bank. Unfortunately the address is
+ * wrong, so we fix it (again).
+ */
+ dev->resource[2] = ddb5074_resources.ram;
+ request_resource(&iomem_resource,
+ &dev->resource[2]);
+ } else if (dev->vendor == PCI_VENDOR_ID_AL
+ && dev->device == PCI_DEVICE_ID_AL_M7101) {
+ /*
+ * It's nice to have the LEDs on the GPIO pins
+ * available for debugging
+ */
+ extern struct pci_dev *pci_pmu;
+ u8 t8;
+
+ pci_pmu = dev; /* for LEDs D2 and D3 */
+ /* Program the lines for LEDs D2 and D3 to output */
+ nile4_pci_read_config_byte(dev, 0x7d, &t8);
+ t8 |= 0xc0;
+ nile4_pci_write_config_byte(dev, 0x7d, t8);
+ /* Turn LEDs D2 and D3 off */
+ nile4_pci_read_config_byte(dev, 0x7e, &t8);
+ t8 |= 0xc0;
+ nile4_pci_write_config_byte(dev, 0x7e, t8);
+ }
}
- }
}
static void __init pcibios_fixup_irqs(void)
{
- struct pci_dev *dev;
- int slot_num;
-
- pci_for_each_dev(dev) {
- slot_num = PCI_SLOT(dev->devfn);
- switch (slot_num) {
- case 0:
- dev->irq = nile4_to_irq(NILE4_INT_INTE);
- break;
- case 1:
- dev->irq = nile4_to_irq(NILE4_INT_INTA);
- break;
- case 2: /* slot 1 */
- dev->irq = nile4_to_irq(NILE4_INT_INTA);
- break;
- case 3: /* slot 2 */
- dev->irq = nile4_to_irq(NILE4_INT_INTB);
- break;
- case 4: /* slot 3 */
- dev->irq = nile4_to_irq(NILE4_INT_INTC);
- break;
- case 5:
- /*
- * Fixup so the serial driver can use the UART
- */
- dev->irq = nile4_to_irq(NILE4_INT_UART);
- break;
- case 13:
- dev->irq = nile4_to_irq(NILE4_INT_INTE);
- break;
- default:
- break;
+ struct pci_dev *dev;
+ int slot_num;
+
+ pci_for_each_dev(dev) {
+ slot_num = PCI_SLOT(dev->devfn);
+ switch (slot_num) {
+ case 0:
+ dev->irq = nile4_to_irq(NILE4_INT_INTE);
+ break;
+ case 1:
+ dev->irq = nile4_to_irq(NILE4_INT_INTA);
+ break;
+ case 2: /* slot 1 */
+ dev->irq = nile4_to_irq(NILE4_INT_INTA);
+ break;
+ case 3: /* slot 2 */
+ dev->irq = nile4_to_irq(NILE4_INT_INTB);
+ break;
+ case 4: /* slot 3 */
+ dev->irq = nile4_to_irq(NILE4_INT_INTC);
+ break;
+ case 5:
+ /*
+ * Fixup so the serial driver can use the UART
+ */
+ dev->irq = nile4_to_irq(NILE4_INT_UART);
+ break;
+ case 13:
+ dev->irq = nile4_to_irq(NILE4_INT_INTE);
+ break;
+ default:
+ break;
+ }
}
- }
}
void __init pcibios_init(void)
{
- printk("PCI: Probing PCI hardware\n");
- ioport_resource.end = 0x1ffffff; /* 32 MB */
- iomem_resource.end = 0x1fffffff; /* 512 MB */
- /* `ram' and `nile4' are requested through the Nile4 pci_dev */
- request_resource(&iomem_resource, &ddb5074_resources.flash);
- request_resource(&iomem_resource, &ddb5074_resources.isa_io);
- request_resource(&iomem_resource, &ddb5074_resources.pci_io);
- request_resource(&iomem_resource, &ddb5074_resources.isa_mem);
- request_resource(&iomem_resource, &ddb5074_resources.pci_mem);
- request_resource(&iomem_resource, &ddb5074_resources.boot);
-
- pci_scan_bus(0, &nile4_pci_ops, NULL);
- ddb5074_pci_fixup();
- pci_assign_unassigned_resources();
- pcibios_fixup_irqs();
+ printk("PCI: Probing PCI hardware\n");
+ ioport_resource.end = 0x1ffffff; /* 32 MB */
+ iomem_resource.end = 0x1fffffff; /* 512 MB */
+ /* `ram' and `nile4' are requested through the Nile4 pci_dev */
+ request_resource(&iomem_resource, &ddb5074_resources.flash);
+ request_resource(&iomem_resource, &ddb5074_resources.isa_io);
+ request_resource(&iomem_resource, &ddb5074_resources.pci_io);
+ request_resource(&iomem_resource, &ddb5074_resources.isa_mem);
+ request_resource(&iomem_resource, &ddb5074_resources.pci_mem);
+ request_resource(&iomem_resource, &ddb5074_resources.boot);
+
+ pci_scan_bus(0, &nile4_pci_ops, NULL);
+ ddb5074_pci_fixup();
+ pci_assign_unassigned_resources();
+ pcibios_fixup_irqs();
}
void __init pcibios_fixup_bus(struct pci_bus *bus)
{
- bus->resource[1] = &ddb5074_resources.pci_mem;
+ bus->resource[1] = &ddb5074_resources.pci_mem;
}
-char *pcibios_setup (char *str)
+char *pcibios_setup(char *str)
{
- return str;
+ return str;
}
void __init pcibios_update_irq(struct pci_dev *dev, int irq)
{
- pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
+ pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
}
void __init pcibios_fixup_pbus_ranges(struct pci_bus *bus,
struct pbus_set_ranges_data *ranges)
{
- ranges->io_start -= bus->resource[0]->start;
- ranges->io_end -= bus->resource[0]->start;
- ranges->mem_start -= bus->resource[1]->start;
- ranges->mem_end -= bus->resource[1]->start;
+ ranges->io_start -= bus->resource[0]->start;
+ ranges->io_end -= bus->resource[0]->start;
+ ranges->mem_start -= bus->resource[1]->start;
+ ranges->mem_end -= bus->resource[1]->start;
}
int pcibios_enable_resources(struct pci_dev *dev)
* Don't touch the Nile 4
*/
if (dev->vendor == PCI_VENDOR_ID_NEC &&
- dev->device == PCI_DEVICE_ID_NEC_NILE4)
- return 0;
+ dev->device == PCI_DEVICE_ID_NEC_NILE4) return 0;
pci_read_config_word(dev, PCI_COMMAND, &cmd);
old_cmd = cmd;
- for(idx=0; idx<6; idx++) {
+ for (idx = 0; idx < 6; idx++) {
r = &dev->resource[idx];
if (!r->start && r->end) {
- printk(KERN_ERR "PCI: Device %s not available because of resource collisions\n", dev->slot_name);
+ printk(KERN_ERR "PCI: Device %s not available because "
+ "of resource collisions\n", dev->slot_name);
return -EINVAL;
}
if (r->flags & IORESOURCE_IO)
cmd |= PCI_COMMAND_MEMORY;
}
if (cmd != old_cmd) {
- printk("PCI: Enabling device %s (%04x -> %04x)\n", dev->slot_name, old_cmd, cmd);
+ printk("PCI: Enabling device %s (%04x -> %04x)\n",
+ dev->slot_name, old_cmd, cmd);
pci_write_config_word(dev, PCI_COMMAND, cmd);
}
return 0;
int pcibios_enable_device(struct pci_dev *dev)
{
- return pcibios_enable_resources(dev);
+ return pcibios_enable_resources(dev);
}
void pcibios_update_resource(struct pci_dev *dev, struct resource *root,
new = res->start | (res->flags & PCI_REGION_FLAG_MASK);
if (resource < 6) {
- reg = PCI_BASE_ADDRESS_0 + 4*resource;
+ reg = PCI_BASE_ADDRESS_0 + 4 * resource;
} else if (resource == PCI_ROM_RESOURCE) {
res->flags |= PCI_ROM_ADDRESS_ENABLE;
reg = dev->rom_base_reg;
} else {
- /* Somebody might have asked allocation of a non-standard resource */
+ /*
+ * Somebody might have asked allocation of a non-standard
+ * resource
+ */
return;
}
-
+
pci_write_config_dword(dev, reg, new);
pci_read_config_dword(dev, reg, &check);
- if ((new ^ check) & ((new & PCI_BASE_ADDRESS_SPACE_IO) ? PCI_BASE_ADDRESS_IO_MASK : PCI_BASE_ADDRESS_MEM_MASK)) {
+ if ((new ^ check) &
+ ((new & PCI_BASE_ADDRESS_SPACE_IO) ? PCI_BASE_ADDRESS_IO_MASK :
+ PCI_BASE_ADDRESS_MEM_MASK)) {
printk(KERN_ERR "PCI: Error while updating region "
"%s/%d (%08x != %08x)\n", dev->slot_name, resource,
new, check);
}
-struct pci_fixup pcibios_fixups[] = {};
-
+struct pci_fixup pcibios_fixups[] = { };
*
* Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com>
* Sony Software Development Center Europe (SDCE), Brussels
- *
- * $Id: prom.c,v 1.1 2000/01/26 00:07:44 ralf Exp $
*/
-
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/bootmem.h>
+
#include <asm/addrspace.h>
#include <asm/bootinfo.h>
-char arcs_cmdline[CL_SIZE];
-
-extern char _end;
-
-#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
-#define PFN_ALIGN(x) (((unsigned long)(x) + (PAGE_SIZE - 1)) & PAGE_MASK)
-
+char arcs_cmdline[COMMAND_LINE_SIZE];
void __init prom_init(const char *s)
{
- int i = 0;
- unsigned long mem_size, free_start, free_end, start_pfn, bootmap_size;
+ int i = 0;
-// _serinit();
+ if (s != (void *) -1)
+ while (*s && i < sizeof(arcs_cmdline) - 1)
+ arcs_cmdline[i++] = *s++;
+ arcs_cmdline[i] = '\0';
- if (s != (void *)-1)
- while (*s && i < sizeof(arcs_cmdline)-1)
- arcs_cmdline[i++] = *s++;
- arcs_cmdline[i] = '\0';
+ mips_machgroup = MACH_GROUP_NEC_DDB;
+ mips_machtype = MACH_NEC_DDB5074;
- mips_machgroup = MACH_GROUP_NEC_DDB;
- mips_machtype = MACH_NEC_DDB5074;
- /* 64 MB non-upgradable */
- mem_size = 64 << 20;
-
- free_start = PHYSADDR(PFN_ALIGN(&_end));
- free_end = mem_size;
- start_pfn = PFN_UP((unsigned long)&_end);
-
- /* Register all the contiguous memory with the bootmem allocator
- and free it. Be careful about the bootmem freemap. */
- bootmap_size = init_bootmem(start_pfn, mem_size >> PAGE_SHIFT);
-
- /* Free the entire available memory after the _end symbol. */
- free_start += bootmap_size;
- free_bootmem(free_start, free_end-free_start);
-}
-
-void __init prom_fixup_mem_map(unsigned long start, unsigned long end)
-{
+ /* 64 MB non-upgradable */
+ add_memory_region(0, 64 << 20, BOOT_MEM_RAM);
}
void __init prom_free_prom_memory(void)
*
* Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com>
* Sony Software Development Center Europe (SDCE), Brussels
- *
- * $Id: setup.c,v 1.1 2000/01/26 00:07:44 ralf Exp $
*/
-
#include <linux/config.h>
#include <linux/init.h>
#include <linux/kbd_ll.h>
extern struct ide_ops std_ide_ops;
extern struct rtc_ops ddb_rtc_ops;
-static void (*back_to_prom)(void) = (void (*)(void))0xbfc00000;
+static void (*back_to_prom) (void) = (void (*)(void)) 0xbfc00000;
static void ddb_machine_restart(char *command)
{
- u32 t;
-
- /* PCI cold reset */
- t = nile4_in32(NILE4_PCICTRL+4);
- t |= 0x40000000;
- nile4_out32(NILE4_PCICTRL+4, t);
- /* CPU cold reset */
- t = nile4_in32(NILE4_CPUSTAT);
- t |= 1;
- nile4_out32(NILE4_CPUSTAT, t);
- /* Call the PROM */
- back_to_prom();
+ u32 t;
+
+ /* PCI cold reset */
+ t = nile4_in32(NILE4_PCICTRL + 4);
+ t |= 0x40000000;
+ nile4_out32(NILE4_PCICTRL + 4, t);
+ /* CPU cold reset */
+ t = nile4_in32(NILE4_CPUSTAT);
+ t |= 1;
+ nile4_out32(NILE4_CPUSTAT, t);
+ /* Call the PROM */
+ back_to_prom();
}
static void ddb_machine_halt(void)
{
- printk("DDB Vrc-5074 halted.\n");
- do {} while (1);
+ printk("DDB Vrc-5074 halted.\n");
+ do {
+ } while (1);
}
static void ddb_machine_power_off(void)
{
- printk("DDB Vrc-5074 halted. Please turn off the power.\n");
- do {} while (1);
+ printk("DDB Vrc-5074 halted. Please turn off the power.\n");
+ do {
+ } while (1);
}
extern void ddb_irq_setup(void);
-void (*board_time_init)(struct irqaction *irq);
+void (*board_time_init) (struct irqaction * irq);
static void __init ddb_time_init(struct irqaction *irq)
{
- /* set the clock to 1 Hz */
- nile4_out32(NILE4_T2CTRL, 1000000);
- /* enable the General-Purpose Timer */
- nile4_out32(NILE4_T2CTRL+4, 0x00000001);
- /* reset timer */
- nile4_out32(NILE4_T2CNTR, 0);
- /* enable interrupt */
- nile4_enable_irq(NILE4_INT_GPT);
- i8259_setup_irq(nile4_to_irq(NILE4_INT_GPT), irq);
- set_cp0_status(ST0_IM, IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4);
+ /* set the clock to 1 Hz */
+ nile4_out32(NILE4_T2CTRL, 1000000);
+ /* enable the General-Purpose Timer */
+ nile4_out32(NILE4_T2CTRL + 4, 0x00000001);
+ /* reset timer */
+ nile4_out32(NILE4_T2CNTR, 0);
+ /* enable interrupt */
+ nile4_enable_irq(NILE4_INT_GPT);
+ i8259_setup_irq(nile4_to_irq(NILE4_INT_GPT), irq);
+ change_cp0_status(ST0_IM,
+ IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4);
}
void __init ddb_setup(void)
{
- extern int panic_timeout;
-
- irq_setup = ddb_irq_setup;
- mips_io_port_base = NILE4_PCI_IO_BASE;
- isa_slot_offset = NILE4_PCI_MEM_BASE;
- request_region(0x00, 0x20, "dma1");
- request_region(0x40, 0x20, "timer");
- request_region(0x70, 0x10, "rtc");
- request_region(0x80, 0x10, "dma page reg");
- request_region(0xc0, 0x20, "dma2");
- board_time_init = ddb_time_init;
-
- _machine_restart = ddb_machine_restart;
- _machine_halt = ddb_machine_halt;
- _machine_power_off = ddb_machine_power_off;
+ extern int panic_timeout;
+
+ irq_setup = ddb_irq_setup;
+ mips_io_port_base = NILE4_PCI_IO_BASE;
+ isa_slot_offset = NILE4_PCI_MEM_BASE;
+ request_region(0x00, 0x20, "dma1");
+ request_region(0x40, 0x20, "timer");
+ request_region(0x70, 0x10, "rtc");
+ request_region(0x80, 0x10, "dma page reg");
+ request_region(0xc0, 0x20, "dma2");
+ board_time_init = ddb_time_init;
+
+ _machine_restart = ddb_machine_restart;
+ _machine_halt = ddb_machine_halt;
+ _machine_power_off = ddb_machine_power_off;
#ifdef CONFIG_BLK_DEV_IDE
- ide_ops = &std_ide_ops;
+ ide_ops = &std_ide_ops;
#endif
- rtc_ops = &ddb_rtc_ops;
+ rtc_ops = &ddb_rtc_ops;
- /* Reboot on panic */
- panic_timeout = 180;
-}
-
-int __init page_is_ram(unsigned long pagenr)
-{
- return 1;
+ /* Reboot on panic */
+ panic_timeout = 180;
}
#define NS16550_BASE (NILE4_PCI_IO_BASE+0x03f8)
static inline u8 ns16550_in(u32 reg)
{
- return *(volatile u8 *)(NS16550_BASE+reg);
+ return *(volatile u8 *) (NS16550_BASE + reg);
}
static inline void ns16550_out(u32 reg, u8 val)
{
- *(volatile u8 *)(NS16550_BASE+reg) = val;
+ *(volatile u8 *) (NS16550_BASE + reg) = val;
}
#endif
void _serinit(void)
{
#if USE_NILE4_SERIAL
- ns16550_out(NS16550_LCR, 0x80);
- ns16550_out(NS16550_DLM, 0x00);
- ns16550_out(NS16550_DLL, 0x36); /* 9600 baud */
- ns16550_out(NS16550_LCR, 0x00);
- ns16550_out(NS16550_LCR, 0x03);
- ns16550_out(NS16550_FCR, 0x47);
+ ns16550_out(NS16550_LCR, 0x80);
+ ns16550_out(NS16550_DLM, 0x00);
+ ns16550_out(NS16550_DLL, 0x36); /* 9600 baud */
+ ns16550_out(NS16550_LCR, 0x00);
+ ns16550_out(NS16550_LCR, 0x03);
+ ns16550_out(NS16550_FCR, 0x47);
#else
- /* done by PMON */
+ /* done by PMON */
#endif
}
void _putc(char c)
{
- while (!(ns16550_in(NS16550_LSR) & NS16550_LSR_THRE));
- ns16550_out(NS16550_THR, c);
- if (c == '\n') {
while (!(ns16550_in(NS16550_LSR) & NS16550_LSR_THRE));
- ns16550_out(NS16550_THR, '\r');
- }
+ ns16550_out(NS16550_THR, c);
+ if (c == '\n') {
+ while (!(ns16550_in(NS16550_LSR) & NS16550_LSR_THRE));
+ ns16550_out(NS16550_THR, '\r');
+ }
}
void _puts(const char *s)
{
- char c;
- while ((c = *s++))
- _putc(c);
+ char c;
+ while ((c = *s++))
+ _putc(c);
}
char _getc(void)
{
- while (!(ns16550_in(NS16550_LSR) & NS16550_LSR_DR));
- return ns16550_in(NS16550_RBR);
+ while (!(ns16550_in(NS16550_LSR) & NS16550_LSR_DR));
+ return ns16550_in(NS16550_RBR);
}
int _testc(void)
{
- return (ns16550_in(NS16550_LSR) & NS16550_LSR_DR) != 0;
+ return (ns16550_in(NS16550_LSR) & NS16550_LSR_DR) != 0;
}
- /*
- * Hexadecimal 7-segment LED
- */
-
+/*
+ * Hexadecimal 7-segment LED
+ */
void ddb5074_led_hex(int hex)
{
- outb(hex, 0x80);
+ outb(hex, 0x80);
}
- /*
- * LEDs D2 and D3, connected to the GPIO pins of the PMU in the ALi M1543
- */
-
+/*
+ * LEDs D2 and D3, connected to the GPIO pins of the PMU in the ALi M1543
+ */
struct pci_dev *pci_pmu = NULL;
void ddb5074_led_d2(int on)
{
- u8 t;
-
- if (pci_pmu) {
- pci_read_config_byte(pci_pmu, 0x7e, &t);
- if (on)
- t &= 0x7f;
- else
- t |= 0x80;
- pci_write_config_byte(pci_pmu, 0x7e, t);
- }
+ u8 t;
+
+ if (pci_pmu) {
+ pci_read_config_byte(pci_pmu, 0x7e, &t);
+ if (on)
+ t &= 0x7f;
+ else
+ t |= 0x80;
+ pci_write_config_byte(pci_pmu, 0x7e, t);
+ }
}
void ddb5074_led_d3(int on)
{
- u8 t;
-
- if (pci_pmu) {
- pci_read_config_byte(pci_pmu, 0x7e, &t);
- if (on)
- t &= 0xbf;
- else
- t |= 0x40;
- pci_write_config_byte(pci_pmu, 0x7e, t);
- }
-}
+ u8 t;
+ if (pci_pmu) {
+ pci_read_config_byte(pci_pmu, 0x7e, &t);
+ if (on)
+ t &= 0xbf;
+ else
+ t |= 0x40;
+ pci_write_config_byte(pci_pmu, 0x7e, t);
+ }
+}
*
* Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com>
* Sony Software Development Center Europe (SDCE), Brussels
- *
- * $Id*
*/
-
#include <linux/init.h>
#include <asm/mc146818rtc.h>
static unsigned char ddb_rtc_read_data(unsigned long addr)
{
- outb_p(addr, RTC_PORT(0));
- return inb_p(RTC_PORT(1));
+ outb_p(addr, RTC_PORT(0));
+
+ return inb_p(RTC_PORT(1));
}
static void ddb_rtc_write_data(unsigned char data, unsigned long addr)
{
- outb_p(addr, RTC_PORT(0));
- outb_p(data, RTC_PORT(1));
+ outb_p(addr, RTC_PORT(0));
+ outb_p(data, RTC_PORT(1));
}
static int ddb_rtc_bcd_mode(void)
{
- return 1;
+ return 1;
}
struct rtc_ops ddb_rtc_ops = {
- ddb_rtc_read_data,
- ddb_rtc_write_data,
- ddb_rtc_bcd_mode
+ ddb_rtc_read_data,
+ ddb_rtc_write_data,
+ ddb_rtc_bcd_mode
};
-
--- /dev/null
+#
+# Makefile for the NEC DDB Vrc-5074 specific kernel interface routines
+# under Linux.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile...
+#
+
+.S.s:
+ $(CPP) $(CFLAGS) $< -o $*.s
+.S.o:
+ $(CC) $(CFLAGS) -c $< -o $*.o
+
+O_TARGET = ddb5476.a
+
+obj-y += setup.o irq.o time.o prom.o pci.o \
+ int-handler.o nile4.o
+obj-$(CONFIG_REMOTE_DEBUG) += dbg_io.o
+
+include $(TOPDIR)/Rules.make
--- /dev/null
+
+#include <linux/config.h>
+
+#if (defined(CONFIG_DDB5476) && defined(CONFIG_REMOTE_DEBUG))
+
+/* --- CONFIG --- */
+
+/* we need uint32 uint8 */
+/* #include "types.h" */
+typedef unsigned char uint8;
+typedef unsigned int uint32;
+
+/* --- END OF CONFIG --- */
+
+#define UART16550_BAUD_2400 2400
+#define UART16550_BAUD_4800 4800
+#define UART16550_BAUD_9600 9600
+#define UART16550_BAUD_19200 19200
+#define UART16550_BAUD_38400 38400
+#define UART16550_BAUD_57600 57600
+#define UART16550_BAUD_115200 115200
+
+#define UART16550_PARITY_NONE 0
+#define UART16550_PARITY_ODD 0x08
+#define UART16550_PARITY_EVEN 0x18
+#define UART16550_PARITY_MARK 0x28
+#define UART16550_PARITY_SPACE 0x38
+
+#define UART16550_DATA_5BIT 0x0
+#define UART16550_DATA_6BIT 0x1
+#define UART16550_DATA_7BIT 0x2
+#define UART16550_DATA_8BIT 0x3
+
+#define UART16550_STOP_1BIT 0x0
+#define UART16550_STOP_2BIT 0x4
+
+/* ----------------------------------------------------- */
+
+/* === CONFIG === */
+
+/* [jsun] we use the second serial port for kdb */
+#define BASE 0xa60002f8
+#define MAX_BAUD 115200
+
+/* === END OF CONFIG === */
+
+/* register offset */
+#define OFS_RCV_BUFFER 0
+#define OFS_TRANS_HOLD 0
+#define OFS_SEND_BUFFER 0
+#define OFS_INTR_ENABLE 1
+#define OFS_INTR_ID 2
+#define OFS_DATA_FORMAT 3
+#define OFS_LINE_CONTROL 3
+#define OFS_MODEM_CONTROL 4
+#define OFS_RS232_OUTPUT 4
+#define OFS_LINE_STATUS 5
+#define OFS_MODEM_STATUS 6
+#define OFS_RS232_INPUT 6
+#define OFS_SCRATCH_PAD 7
+
+#define OFS_DIVISOR_LSB 0
+#define OFS_DIVISOR_MSB 1
+
+
+/* memory-mapped read/write of the port */
+#define UART16550_READ(y) (*((volatile uint8*)(BASE + y)))
+#define UART16550_WRITE(y, z) ((*((volatile uint8*)(BASE + y))) = z)
+
+void debugInit(uint32 baud, uint8 data, uint8 parity, uint8 stop)
+{
+ /* disable interrupts */
+ UART16550_WRITE(OFS_INTR_ENABLE, 0);
+
+ /* set up buad rate */
+ {
+ uint32 divisor;
+
+ /* set DIAB bit */
+ UART16550_WRITE(OFS_LINE_CONTROL, 0x80);
+
+ /* set divisor */
+ divisor = MAX_BAUD / baud;
+ UART16550_WRITE(OFS_DIVISOR_LSB, divisor & 0xff);
+ UART16550_WRITE(OFS_DIVISOR_MSB, (divisor & 0xff00) >> 8);
+
+ /* clear DIAB bit */
+ UART16550_WRITE(OFS_LINE_CONTROL, 0x0);
+ }
+
+ /* set data format */
+ UART16550_WRITE(OFS_DATA_FORMAT, data | parity | stop);
+}
+
+static int remoteDebugInitialized = 0;
+
+uint8 getDebugChar(void)
+{
+ if (!remoteDebugInitialized) {
+ remoteDebugInitialized = 1;
+ debugInit(UART16550_BAUD_38400,
+ UART16550_DATA_8BIT,
+ UART16550_PARITY_NONE, UART16550_STOP_1BIT);
+ }
+
+ while ((UART16550_READ(OFS_LINE_STATUS) & 0x1) == 0);
+ return UART16550_READ(OFS_RCV_BUFFER);
+}
+
+
+int putDebugChar(uint8 byte)
+{
+ if (!remoteDebugInitialized) {
+ remoteDebugInitialized = 1;
+ debugInit(UART16550_BAUD_9600,
+ UART16550_DATA_8BIT,
+ UART16550_PARITY_NONE, UART16550_STOP_1BIT);
+ }
+
+ while ((UART16550_READ(OFS_LINE_STATUS) & 0x20) == 0);
+ UART16550_WRITE(OFS_SEND_BUFFER, byte);
+ return 1;
+}
+
+#endif
--- /dev/null
+/*
+ * arch/mips/ddb5074/int-handler.S -- NEC DDB Vrc-5074 interrupt handler
+ *
+ * Based on arch/mips/sgi/kernel/indyIRQ.S
+ *
+ * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ *
+ * Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com>
+ * Sony Software Development Center Europe (SDCE), Brussels
+ */
+#include <asm/asm.h>
+#include <asm/mipsregs.h>
+#include <asm/regdef.h>
+#include <asm/stackframe.h>
+
+/*
+ * A lot of complication here is taken away because:
+ *
+ * 1) We handle one interrupt and return, sitting in a loop and moving across
+ * all the pending IRQ bits in the cause register is _NOT_ the answer, the
+ * common case is one pending IRQ so optimize in that direction.
+ *
+ * 2) We need not check against bits in the status register IRQ mask, that
+ * would make this routine slow as hell.
+ *
+ * 3) Linux only thinks in terms of all IRQs on or all IRQs off, nothing in
+ * between like BSD spl() brain-damage.
+ *
+ * Furthermore, the IRQs on the INDY look basically (barring software IRQs
+ * which we don't use at all) like:
+ *
+ * MIPS IRQ Source
+ * -------- ------
+ * 0 Software (ignored)
+ * 1 Software (ignored)
+ * 2 Local IRQ level zero
+ * 3 Local IRQ level one
+ * 4 8254 Timer zero
+ * 5 8254 Timer one
+ * 6 Bus Error
+ * 7 R4k timer (what we use)
+ *
+ * We handle the IRQ according to _our_ priority which is:
+ *
+ * Highest ---- R4k Timer
+ * Local IRQ zero
+ * Local IRQ one
+ * Bus Error
+ * 8254 Timer zero
+ * Lowest ---- 8254 Timer one
+ *
+ * then we just return, if multiple IRQs are pending then we will just take
+ * another exception, big deal.
+ */
+
+ .text
+ .set noreorder
+ .set noat
+ .align 5
+ NESTED(ddbIRQ, PT_SIZE, sp)
+ SAVE_ALL
+ CLI
+ .set at
+ mfc0 s1, CP0_CAUSE # get irq mask
+
+#if 1
+ mfc0 t2,CP0_STATUS # get enabled interrupts
+ and s0, s1, t2 # isolate allowed ones
+#endif
+ /* First we check for r4k counter/timer IRQ. */
+ andi a0, s0, CAUSEF_IP2 # delay slot, check local level zero
+ beq a0, zero, 1f
+ andi a0, s0, CAUSEF_IP3 # delay slot, check local level one
+
+ /* Wheee, local level zero interrupt. */
+ jal ddb_local0_irqdispatch
+ move a0, sp # delay slot
+
+ j ret_from_irq
+ nop # delay slot
+
+1:
+ beq a0, zero, 1f
+ andi a0, s0, CAUSEF_IP6 # delay slot, check bus error
+
+ /* Wheee, local level one interrupt. */
+ move a0, sp
+ jal ddb_local1_irqdispatch
+ nop
+
+ j ret_from_irq
+ nop
+
+1:
+ beq a0, zero, 1f
+ nop
+
+ /* Wheee, an asynchronous bus error... */
+ move a0, sp
+ jal ddb_buserror_irq
+ nop
+
+ j ret_from_irq
+ nop
+
+1:
+ /* Here by mistake? This is possible, what can happen
+ * is that by the time we take the exception the IRQ
+ * pin goes low, so just leave if this is the case.
+ */
+ andi a0, s0, (CAUSEF_IP4 | CAUSEF_IP5)
+ beq a0, zero, 1f
+
+ /* Must be one of the 8254 timers... */
+ move a0, sp
+ jal ddb_8254timer_irq
+ nop
+1:
+ /* phamtom interrupt */
+ move a0, s1
+ jal ddb_phantom_irq
+ nop
+ j ret_from_irq
+ nop
+ END(ddbIRQ)
--- /dev/null
+/*
+ * arch/mips/ddb5476/irq.c -- NEC DDB Vrc-5476 interrupt routines
+ *
+ * Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com>
+ * Sony Software Development Center Europe (SDCE), Brussels
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/ptrace.h>
+#include <asm/nile4.h>
+
+extern void __init i8259_init(void);
+extern void i8259_disable_irq(unsigned int irq_nr);
+extern void i8259_enable_irq(unsigned int irq_nr);
+
+extern asmlinkage void ddbIRQ(void);
+extern asmlinkage void i8259_do_irq(int irq, struct pt_regs *regs);
+extern asmlinkage void do_IRQ(int irq, struct pt_regs *regs);
+
+
+void no_action(int cpl, void *dev_id, struct pt_regs *regs)
+{
+}
+
+
+#define M1543_PNP_CONFIG 0x03f0 /* PnP Config Port */
+#define M1543_PNP_INDEX 0x03f0 /* PnP Index Port */
+#define M1543_PNP_DATA 0x03f1 /* PnP Data Port */
+
+#define M1543_PNP_ALT_CONFIG 0x0370 /* Alternative PnP Config Port */
+#define M1543_PNP_ALT_INDEX 0x0370 /* Alternative PnP Index Port */
+#define M1543_PNP_ALT_DATA 0x0371 /* Alternative PnP Data Port */
+
+#define M1543_INT1_MASTER_CTRL 0x0020 /* INT_1 (master) Control Register */
+#define M1543_INT1_MASTER_MASK 0x0021 /* INT_1 (master) Mask Register */
+
+#define M1543_INT1_SLAVE_CTRL 0x00a0 /* INT_1 (slave) Control Register */
+#define M1543_INT1_SLAVE_MASK 0x00a1 /* INT_1 (slave) Mask Register */
+
+#define M1543_INT1_MASTER_ELCR 0x04d0 /* INT_1 (master) Edge/Level Control */
+#define M1543_INT1_SLAVE_ELCR 0x04d1 /* INT_1 (slave) Edge/Level Control */
+
+static struct {
+ struct resource m1543_config;
+ struct resource pic_elcr;
+} m1543_ioport = {
+ { "M1543 config", M1543_PNP_CONFIG, M1543_PNP_CONFIG + 1,
+ IORESOURCE_BUSY},
+ { "pic ELCR", M1543_INT1_MASTER_ELCR, M1543_INT1_MASTER_ELCR + 1,
+ IORESOURCE_BUSY}
+};
+
+static void m1543_irq_setup(void)
+{
+ /*
+ * The ALI M1543 has 13 interrupt inputs, IRQ1..IRQ13. Not all
+ * the possible IO sources in the M1543 are in use by us. We will
+ * use the following mapping:
+ *
+ * IRQ1 - keyboard (default set by M1543)
+ * IRQ3 - reserved for UART B (default set by M1543) (note that
+ * the schematics for the DDB Vrc-5476 board seem to
+ * indicate that IRQ3 is connected to the DS1386
+ * watchdog timer interrupt output so we might have
+ * a conflict)
+ * IRQ4 - reserved for UART A (default set by M1543)
+ * IRQ5 - parallel (default set by M1543)
+ * IRQ8 - DS1386 time of day (RTC) interrupt
+ * IRQ9 - USB (hardwired in ddb_setup)
+ * IRQ10 - PMU (hardwired in ddb_setup)
+ * IRQ12 - mouse
+ * IRQ14,15 - IDE controller (need to be confirmed, jsun)
+ */
+
+ /*
+ * Assing mouse interrupt to IRQ12
+ */
+
+ /* Enter configuration mode */
+ outb(0x51, M1543_PNP_CONFIG);
+ outb(0x23, M1543_PNP_CONFIG);
+
+ /* Select logical device 7 (Keyboard) */
+ outb(0x07, M1543_PNP_INDEX);
+ outb(0x07, M1543_PNP_DATA);
+
+ /* Select IRQ12 */
+ outb(0x72, M1543_PNP_INDEX);
+ outb(0x0c, M1543_PNP_DATA);
+
+ /* Leave configration mode */
+ outb(0xbb, M1543_PNP_CONFIG);
+
+
+ /* Initialize the 8259 PIC in the M1543 */
+ i8259_init();
+
+ /* Enable the interrupt cascade from M1543 */
+ nile4_enable_irq(NILE4_INT_INTC);
+
+ /* request io ports */
+ if (request_resource(&ioport_resource, &m1543_ioport.m1543_config)
+ || request_resource(&ioport_resource, &m1543_ioport.pic_elcr)) {
+ printk("m1543_irq_setup : requesting io ports failed.\n");
+ for (;;);
+ }
+}
+
+static void nile4_irq_setup(void)
+{
+ int i;
+
+ /* Map all interrupts to CPU int #0 */
+ nile4_map_irq_all(0);
+
+ /* PCI INTA#-E# must be level triggered */
+ nile4_set_pci_irq_level_or_edge(0, 1);
+ nile4_set_pci_irq_level_or_edge(1, 1);
+ nile4_set_pci_irq_level_or_edge(2, 1);
+ nile4_set_pci_irq_level_or_edge(3, 1);
+
+ /* PCI INTA#, B#, D# must be active low, INTC# must be active high */
+ nile4_set_pci_irq_polarity(0, 0);
+ nile4_set_pci_irq_polarity(1, 0);
+ nile4_set_pci_irq_polarity(2, 1);
+ nile4_set_pci_irq_polarity(3, 0);
+
+ for (i = 0; i < 16; i++)
+ nile4_clear_irq(i);
+
+ /* Enable CPU int #0 */
+ nile4_enable_irq_output(0);
+
+ /* memory resource acquire in ddb_setup */
+}
+
+
+/*
+ * IRQ2 is cascade interrupt to second interrupt controller
+ */
+static struct irqaction irq2 = { no_action, 0, 0, "cascade", NULL, NULL };
+
+
+void disable_irq(unsigned int irq_nr)
+{
+ if (is_i8259_irq(irq_nr))
+ i8259_disable_irq(irq_nr);
+ else
+ nile4_disable_irq(irq_to_nile4(irq_nr));
+}
+
+void enable_irq(unsigned int irq_nr)
+{
+ if (is_i8259_irq(irq_nr))
+ i8259_enable_irq(irq_nr);
+ else
+ nile4_enable_irq(irq_to_nile4(irq_nr));
+}
+
+int table[16] = { 0, };
+
+void ddb_local0_irqdispatch(struct pt_regs *regs)
+{
+ u32 mask;
+ int nile4_irq;
+#if 0
+ volatile static int nesting = 0;
+ if (nesting++ == 0)
+ ddb5476_led_d3(1);
+ ddb5476_led_hex(nesting < 16 ? nesting : 15);
+#endif
+
+ mask = nile4_get_irq_stat(0);
+ nile4_clear_irq_mask(mask);
+
+ /* Handle the timer interrupt first */
+ if (mask & (1 << NILE4_INT_GPT)) {
+ nile4_disable_irq(NILE4_INT_GPT);
+ do_IRQ(nile4_to_irq(NILE4_INT_GPT), regs);
+ nile4_enable_irq(NILE4_INT_GPT);
+ mask &= ~(1 << NILE4_INT_GPT);
+ }
+ for (nile4_irq = 0; mask; nile4_irq++, mask >>= 1)
+ if (mask & 1) {
+ nile4_disable_irq(nile4_irq);
+ if (nile4_irq == NILE4_INT_INTC) {
+ int i8259_irq = nile4_i8259_iack();
+ i8259_do_irq(i8259_irq, regs);
+ } else {
+ do_IRQ(nile4_to_irq(nile4_irq), regs);
+ }
+ nile4_enable_irq(nile4_irq);
+ }
+#if 0
+ if (--nesting == 0)
+ ddb5476_led_d3(0);
+ ddb5476_led_hex(nesting < 16 ? nesting : 15);
+#endif
+}
+
+void ddb_local1_irqdispatch(void)
+{
+ printk("ddb_local1_irqdispatch called\n");
+}
+
+void ddb_buserror_irq(void)
+{
+ printk("ddb_buserror_irq called\n");
+}
+
+void ddb_8254timer_irq(void)
+{
+ printk("ddb_8254timer_irq called\n");
+}
+
+void ddb_phantom_irq(unsigned long cause)
+{
+ printk("phantom interrupts detected : \n");
+ printk("\tcause \t\t0x%08x\n", cause);
+ printk("\tcause reg\t0x%08x\n",
+ read_32bit_cp0_register(CP0_CAUSE));
+ printk("\tstatus reg\t0x%08x\n",
+ read_32bit_cp0_register(CP0_STATUS));
+}
+
+void __init ddb_irq_setup(void)
+{
+#ifdef CONFIG_REMOTE_DEBUG
+ printk("Wait for gdb client connection ...\n");
+ set_debug_traps();
+ breakpoint(); /* you may move this line to whereever you want :-) */
+#endif
+ i8259_setup_irq(2, &irq2);
+
+ nile4_irq_setup();
+ m1543_irq_setup();
+
+ /* we pin #0 - #4 (no internal timer) */
+ change_cp0_status(ST0_IM,
+ IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4);
+
+ set_except_vector(0, ddbIRQ);
+}
--- /dev/null
+/*
+ * arch/mips/ddb5074/nile4.c -- NEC Vrc-5074 Nile 4 support routines
+ *
+ * Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com>
+ * Sony Software Development Center Europe (SDCE), Brussels
+ */
+#include <linux/kernel.h>
+#include <linux/types.h>
+
+#include <asm/nile4.h>
+
+
+/*
+ * Physical Device Address Registers
+ *
+ * Note: 32 bit addressing only!
+ */
+void nile4_set_pdar(u32 pdar, u32 phys, u32 size, int width,
+ int on_memory_bus, int visible)
+{
+ u32 maskbits;
+ u32 widthbits;
+
+ if (pdar > NILE4_BOOTCS || (pdar & 7)) {
+ printk("nile4_set_pdar: invalid pdar %d\n", pdar);
+ return;
+ }
+ if (pdar == NILE4_INTCS && size != 0x00200000) {
+ printk("nile4_set_pdar: INTCS size must be 2 MB\n");
+ return;
+ }
+ switch (size) {
+#if 0 /* We don't support 4 GB yet */
+ case 0x100000000: /* 4 GB */
+ maskbits = 4;
+ break;
+#endif
+ case 0x80000000: /* 2 GB */
+ maskbits = 5;
+ break;
+ case 0x40000000: /* 1 GB */
+ maskbits = 6;
+ break;
+ case 0x20000000: /* 512 MB */
+ maskbits = 7;
+ break;
+ case 0x10000000: /* 256 MB */
+ maskbits = 8;
+ break;
+ case 0x08000000: /* 128 MB */
+ maskbits = 9;
+ break;
+ case 0x04000000: /* 64 MB */
+ maskbits = 10;
+ break;
+ case 0x02000000: /* 32 MB */
+ maskbits = 11;
+ break;
+ case 0x01000000: /* 16 MB */
+ maskbits = 12;
+ break;
+ case 0x00800000: /* 8 MB */
+ maskbits = 13;
+ break;
+ case 0x00400000: /* 4 MB */
+ maskbits = 14;
+ break;
+ case 0x00200000: /* 2 MB */
+ maskbits = 15;
+ break;
+ case 0: /* OFF */
+ maskbits = 0;
+ break;
+ default:
+ printk("nile4_set_pdar: unsupported size %p\n",
+ (void *) size);
+ return;
+ }
+ switch (width) {
+ case 8:
+ widthbits = 0;
+ break;
+ case 16:
+ widthbits = 1;
+ break;
+ case 32:
+ widthbits = 2;
+ break;
+ case 64:
+ widthbits = 3;
+ break;
+ default:
+ printk("nile4_set_pdar: unsupported width %d\n", width);
+ return;
+ }
+ nile4_out32(pdar, maskbits | (on_memory_bus ? 0x10 : 0) |
+ (visible ? 0x20 : 0) | (widthbits << 6) |
+ (phys & 0xffe00000));
+ nile4_out32(pdar + 4, 0);
+ /*
+ * When programming a PDAR, the register should be read immediately
+ * after writing it. This ensures that address decoders are properly
+ * configured.
+ */
+ nile4_in32(pdar);
+ nile4_in32(pdar + 4);
+}
+
+
+/*
+ * PCI Master Registers
+ *
+ * Note: 32 bit addressing only!
+ */
+void nile4_set_pmr(u32 pmr, u32 type, u32 addr)
+{
+ if (pmr != NILE4_PCIINIT0 && pmr != NILE4_PCIINIT1) {
+ printk("nile4_set_pmr: invalid pmr %d\n", pmr);
+ return;
+ }
+ switch (type) {
+ case NILE4_PCICMD_IACK: /* PCI Interrupt Acknowledge */
+ case NILE4_PCICMD_IO: /* PCI I/O Space */
+ case NILE4_PCICMD_MEM: /* PCI Memory Space */
+ case NILE4_PCICMD_CFG: /* PCI Configuration Space */
+ break;
+ default:
+ printk("nile4_set_pmr: invalid type %d\n", type);
+ return;
+ }
+ nile4_out32(pmr, (type << 1) | 0x10 | (addr & 0xffe00000));
+ nile4_out32(pmr + 4, 0);
+}
+
+
+/*
+ * Interrupt Programming
+ */
+void nile4_map_irq(int nile4_irq, int cpu_irq)
+{
+ u32 offset, t;
+
+ offset = NILE4_INTCTRL;
+ if (nile4_irq >= 8) {
+ offset += 4;
+ nile4_irq -= 8;
+ }
+ t = nile4_in32(offset);
+ t &= ~(7 << (nile4_irq * 4));
+ t |= cpu_irq << (nile4_irq * 4);
+ nile4_out32(offset, t);
+}
+
+void nile4_map_irq_all(int cpu_irq)
+{
+ u32 all, t;
+
+ all = cpu_irq;
+ all |= all << 4;
+ all |= all << 8;
+ all |= all << 16;
+ t = nile4_in32(NILE4_INTCTRL);
+ t &= 0x88888888;
+ t |= all;
+ nile4_out32(NILE4_INTCTRL, t);
+ t = nile4_in32(NILE4_INTCTRL + 4);
+ t &= 0x88888888;
+ t |= all;
+ nile4_out32(NILE4_INTCTRL + 4, t);
+}
+
+void nile4_enable_irq(int nile4_irq)
+{
+ u32 offset, t;
+
+ offset = NILE4_INTCTRL;
+ if (nile4_irq >= 8) {
+ offset += 4;
+ nile4_irq -= 8;
+ }
+ t = nile4_in32(offset);
+ t |= 8 << (nile4_irq * 4);
+ nile4_out32(offset, t);
+}
+
+void nile4_disable_irq(int nile4_irq)
+{
+ u32 offset, t;
+
+ offset = NILE4_INTCTRL;
+ if (nile4_irq >= 8) {
+ offset += 4;
+ nile4_irq -= 8;
+ }
+ t = nile4_in32(offset);
+ t &= ~(8 << (nile4_irq * 4));
+ nile4_out32(offset, t);
+}
+
+void nile4_disable_irq_all(void)
+{
+ nile4_out32(NILE4_INTCTRL, 0);
+ nile4_out32(NILE4_INTCTRL + 4, 0);
+}
+
+u16 nile4_get_irq_stat(int cpu_irq)
+{
+ return nile4_in16(NILE4_INTSTAT0 + cpu_irq * 2);
+}
+
+void nile4_enable_irq_output(int cpu_irq)
+{
+ u32 t;
+
+ t = nile4_in32(NILE4_INTSTAT1 + 4);
+ t |= 1 << (16 + cpu_irq);
+ nile4_out32(NILE4_INTSTAT1, t);
+}
+
+void nile4_disable_irq_output(int cpu_irq)
+{
+ u32 t;
+
+ t = nile4_in32(NILE4_INTSTAT1 + 4);
+ t &= ~(1 << (16 + cpu_irq));
+ nile4_out32(NILE4_INTSTAT1, t);
+}
+
+void nile4_set_pci_irq_polarity(int pci_irq, int high)
+{
+ u32 t;
+
+ t = nile4_in32(NILE4_INTPPES);
+ if (high)
+ t &= ~(1 << (pci_irq * 2));
+ else
+ t |= 1 << (pci_irq * 2);
+ nile4_out32(NILE4_INTPPES, t);
+}
+
+void nile4_set_pci_irq_level_or_edge(int pci_irq, int level)
+{
+ u32 t;
+
+ t = nile4_in32(NILE4_INTPPES);
+ if (level)
+ t |= 2 << (pci_irq * 2);
+ else
+ t &= ~(2 << (pci_irq * 2));
+ nile4_out32(NILE4_INTPPES, t);
+}
+
+void nile4_clear_irq(int nile4_irq)
+{
+ nile4_out32(NILE4_INTCLR, 1 << nile4_irq);
+}
+
+void nile4_clear_irq_mask(u32 mask)
+{
+ nile4_out32(NILE4_INTCLR, mask);
+}
+
+u8 nile4_i8259_iack(void)
+{
+ u8 irq;
+
+ /* Set window 0 for interrupt acknowledge */
+ nile4_set_pmr(NILE4_PCIINIT0, NILE4_PCICMD_IACK, 0);
+ irq = *(volatile u8 *) NILE4_PCI_IACK_BASE;
+ /* Set window 0 for PCI I/O space */
+ nile4_set_pmr(NILE4_PCIINIT0, NILE4_PCICMD_IO, 0);
+ return irq;
+}
+
+#if 0
+void nile4_dump_irq_status(void)
+{
+ printk("CPUSTAT = %p:%p\n", (void *) nile4_in32(NILE4_CPUSTAT + 4),
+ (void *) nile4_in32(NILE4_CPUSTAT));
+ printk("INTCTRL = %p:%p\n", (void *) nile4_in32(NILE4_INTCTRL + 4),
+ (void *) nile4_in32(NILE4_INTCTRL));
+ printk("INTSTAT0 = %p:%p\n",
+ (void *) nile4_in32(NILE4_INTSTAT0 + 4),
+ (void *) nile4_in32(NILE4_INTSTAT0));
+ printk("INTSTAT1 = %p:%p\n",
+ (void *) nile4_in32(NILE4_INTSTAT1 + 4),
+ (void *) nile4_in32(NILE4_INTSTAT1));
+ printk("INTCLR = %p:%p\n", (void *) nile4_in32(NILE4_INTCLR + 4),
+ (void *) nile4_in32(NILE4_INTCLR));
+ printk("INTPPES = %p:%p\n", (void *) nile4_in32(NILE4_INTPPES + 4),
+ (void *) nile4_in32(NILE4_INTPPES));
+}
+#endif
--- /dev/null
+/*
+ * arch/mips/ddb5476/pci.c -- NEC DDB Vrc-5074 PCI access routines
+ *
+ * Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com>
+ * Albert Dorofeev <albert@sonycom.com>
+ * Sony Software Development Center Europe (SDCE), Brussels
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+
+#include <asm-mips/nile4.h>
+
+
+static u32 nile4_pre_pci_access0(int slot_num)
+{
+ u32 pci_addr = 0;
+ u32 virt_addr = NILE4_PCI_CFG_BASE;
+
+ /* work around the bug for Vrc5476 */
+ if (slot_num == 13)
+ return NILE4_BASE + NILE4_PCI_BASE;
+
+ /* Set window 1 address 08000000 - 32 bit - 128 MB (PCI config space) */
+ nile4_set_pdar(NILE4_PCIW1, PHYSADDR(virt_addr), 0x08000000, 32, 0,
+ 0);
+
+ // [jsun] we start scanning from addr:10,
+ // with 128M we can go up to addr:26 (slot 16)
+ if (slot_num <= 16) {
+ virt_addr += 0x00000400 << slot_num;
+ } else {
+ /* for high slot, we have to set higher PCI base addr */
+ pci_addr = 0x00000400 << slot_num;
+ }
+ nile4_set_pmr(NILE4_PCIINIT1, NILE4_PCICMD_CFG, pci_addr);
+ return virt_addr;
+}
+
+static void nile4_post_pci_access0(void)
+{
+ /*
+ * Set window 1 back to address 08000000 - 32 bit - 128 MB
+ * (PCI IO space)
+ */
+ nile4_set_pdar(NILE4_PCIW1, PHYSADDR(NILE4_PCI_MEM_BASE),
+ 0x08000000, 32, 1, 1);
+ // nile4_set_pmr(NILE4_PCIINIT1, NILE4_PCICMD_MEM, 0);
+ nile4_set_pmr(NILE4_PCIINIT1, NILE4_PCICMD_MEM, 0x08000000);
+}
+
+
+static int nile4_pci_read_config_dword(struct pci_dev *dev,
+ int where, u32 * val)
+{
+ int slot_num, func_num;
+ u32 base;
+ u32 addr;
+
+ /*
+ * Do we need to generate type 1 configure transaction?
+ */
+ if (dev->bus->number) {
+ /* FIXME - not working yet */
+ return PCIBIOS_FUNC_NOT_SUPPORTED;
+
+ /*
+ * the largest type 1 configuration addr is 16M, < 256M
+ * config space
+ */
+ slot_num = 0;
+ addr =
+ (dev->bus->number << 16) | (dev->devfn <
+ 8) | where | 1;
+ } else {
+ slot_num = PCI_SLOT(dev->devfn);
+ func_num = PCI_FUNC(dev->devfn);
+ addr = (func_num << 8) + where;
+ }
+
+ base = nile4_pre_pci_access0(slot_num);
+ *val = *(volatile u32 *) (base + addr);
+ nile4_post_pci_access0();
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int nile4_pci_write_config_dword(struct pci_dev *dev, int where,
+ u32 val)
+{
+ int slot_num, func_num;
+ u32 base;
+ u32 addr;
+
+ /*
+ * Do we need to generate type 1 configure transaction?
+ */
+ if (dev->bus->number) {
+ /* FIXME - not working yet */
+ return PCIBIOS_FUNC_NOT_SUPPORTED;
+
+ /* the largest type 1 configuration addr is 16M, < 256M config space */
+ slot_num = 0;
+ addr =
+ (dev->bus->number << 16) | (dev->devfn <
+ 8) | where | 1;
+ } else {
+ slot_num = PCI_SLOT(dev->devfn);
+ func_num = PCI_FUNC(dev->devfn);
+ addr = (func_num << 8) + where;
+ }
+
+ base = nile4_pre_pci_access0(slot_num);
+ *(volatile u32 *) (base + addr) = val;
+ nile4_post_pci_access0();
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int nile4_pci_read_config_word(struct pci_dev *dev, int where,
+ u16 * val)
+{
+ int status;
+ u32 result;
+
+ status = nile4_pci_read_config_dword(dev, where & ~3, &result);
+ if (status != PCIBIOS_SUCCESSFUL)
+ return status;
+ if (where & 2)
+ result >>= 16;
+ *val = result & 0xffff;
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int nile4_pci_read_config_byte(struct pci_dev *dev, int where,
+ u8 * val)
+{
+ int status;
+ u32 result;
+
+ status = nile4_pci_read_config_dword(dev, where & ~3, &result);
+ if (status != PCIBIOS_SUCCESSFUL)
+ return status;
+ if (where & 1)
+ result >>= 8;
+ if (where & 2)
+ result >>= 16;
+ *val = result & 0xff;
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int nile4_pci_write_config_word(struct pci_dev *dev, int where,
+ u16 val)
+{
+ int status, shift = 0;
+ u32 result;
+
+ status = nile4_pci_read_config_dword(dev, where & ~3, &result);
+ if (status != PCIBIOS_SUCCESSFUL)
+ return status;
+ if (where & 2)
+ shift += 16;
+ result &= ~(0xffff << shift);
+ result |= val << shift;
+ return nile4_pci_write_config_dword(dev, where & ~3, result);
+}
+
+static int nile4_pci_write_config_byte(struct pci_dev *dev, int where,
+ u8 val)
+{
+ int status, shift = 0;
+ u32 result;
+
+ status = nile4_pci_read_config_dword(dev, where & ~3, &result);
+ if (status != PCIBIOS_SUCCESSFUL)
+ return status;
+ if (where & 2)
+ shift += 16;
+ if (where & 1)
+ shift += 8;
+ result &= ~(0xff << shift);
+ result |= val << shift;
+ return nile4_pci_write_config_dword(dev, where & ~3, result);
+}
+
+struct pci_ops nile4_pci_ops = {
+ nile4_pci_read_config_byte,
+ nile4_pci_read_config_word,
+ nile4_pci_read_config_dword,
+ nile4_pci_write_config_byte,
+ nile4_pci_write_config_word,
+ nile4_pci_write_config_dword
+};
+
+struct {
+ struct resource ram;
+ struct resource flash;
+ struct resource isa_io;
+ struct resource pci_io;
+ struct resource isa_mem;
+ struct resource pci_mem;
+ struct resource nile4;
+ struct resource boot;
+} ddb5476_resources = {
+ // { "RAM", 0x00000000, 0x03ffffff, IORESOURCE_MEM | PCI_BASE_ADDRESS_MEM_TYPE_64 },
+ {
+ "RAM", 0x00000000, 0x03ffffff, IORESOURCE_MEM}, {
+ "Flash ROM", 0x04000000, 0x043fffff}, {
+ "Nile4 ISA I/O", 0x06000000, 0x060fffff}, {
+ "Nile4 PCI I/O", 0x06100000, 0x07ffffff}, {
+ "Nile4 ISA mem", 0x08000000, 0x08ffffff, IORESOURCE_MEM}, {
+ "Nile4 PCI mem", 0x09000000, 0x0fffffff, IORESOURCE_MEM},
+ // { "Nile4 ctrl", 0x1fa00000, 0x1fbfffff, IORESOURCE_MEM | PCI_BASE_ADDRESS_MEM_TYPE_64 },
+ {
+ "Nile4 ctrl", 0x1fa00000, 0x1fbfffff, IORESOURCE_MEM}, {
+ "Boot ROM", 0x1fc00000, 0x1fffffff}
+};
+
+struct resource M5229_resources[5] = {
+ {"M5229 BAR0", 0x1f0, 0x1f3, IORESOURCE_IO},
+ {"M5229 BAR1", 0x3f4, 0x3f7, IORESOURCE_IO},
+ {"M5229 BAR2", 0x170, 0x173, IORESOURCE_IO},
+ {"M5229 BAR3", 0x374, 0x377, IORESOURCE_IO},
+ {"M5229 BAR4", 0xf000, 0xf00f, IORESOURCE_IO}
+};
+
+static void __init ddb5476_pci_fixup(void)
+{
+ struct pci_dev *dev;
+
+ pci_for_each_dev(dev) {
+ if (dev->vendor == PCI_VENDOR_ID_NEC &&
+ dev->device == PCI_DEVICE_ID_NEC_VRC5476) {
+ /*
+ * The first 64-bit PCI base register should point to
+ * the Nile4 control registers. Unfortunately this
+ * isn't the case, so we fix it ourselves. This allows
+ * the serial driver to find the UART.
+ */
+ dev->resource[0] = ddb5476_resources.nile4;
+ request_resource(&iomem_resource,
+ &dev->resource[0]);
+ /*
+ * The second 64-bit PCI base register points to the
+ * first memory bank. Unfortunately the address is
+ * wrong, so we fix it (again).
+ */
+
+ /* [jsun] We cannot request the resource anymore,
+ * because kernel/setup.c has already reserved "System
+ * RAM" resource at the same spot.
+ * The fundamental problem here is that PCI host
+ * controller should not put system RAM mapping in BAR
+ * and make subject to PCI resource assignement.
+ * Current fix is a total hack. We set parent to 1 so
+ * so that PCI resource assignement code is fooled to
+ * think the resource is assigned, and will not attempt
+ * to mess with it.
+ */
+ dev->resource[2] = ddb5476_resources.ram;
+ if (request_resource(&iomem_resource,
+ &dev->resource[2]) ) {
+ dev->resource[2].parent = 0x1;
+ }
+
+ } else if (dev->vendor == PCI_VENDOR_ID_AL
+ && dev->device == PCI_DEVICE_ID_AL_M7101) {
+ /*
+ * It's nice to have the LEDs on the GPIO pins
+ * available for debugging
+ */
+ extern struct pci_dev *pci_pmu;
+ u8 t8;
+
+ pci_pmu = dev; /* for LEDs D2 and D3 */
+ /* Program the lines for LEDs D2 and D3 to output */
+ nile4_pci_read_config_byte(dev, 0x7d, &t8);
+ t8 |= 0xc0;
+ nile4_pci_write_config_byte(dev, 0x7d, t8);
+ /* Turn LEDs D2 and D3 off */
+ nile4_pci_read_config_byte(dev, 0x7e, &t8);
+ t8 |= 0xc0;
+ nile4_pci_write_config_byte(dev, 0x7e, t8);
+ } else if (dev->vendor == PCI_VENDOR_ID_AL &&
+ dev->device == 0x5229) {
+ int i;
+ for (i = 0; i < 5; i++) {
+ dev->resource[i] = M5229_resources[i];
+ request_resource(&ioport_resource,
+ &dev->resource[i]);
+ }
+ }
+ }
+}
+
+static void __init pcibios_fixup_irqs(void)
+{
+ struct pci_dev *dev;
+ int slot_num;
+
+ pci_for_each_dev(dev) {
+ slot_num = PCI_SLOT(dev->devfn);
+ switch (slot_num) {
+ case 3: /* re-programmed to USB */
+ dev->irq = 9; /* hard-coded; see irq.c */
+ break;
+ case 4: /* re-programmed to PMU */
+ dev->irq = 10; /* hard-coded; see irq.c */
+ break;
+ case 6: /* on-board pci-pci bridge */
+ dev->irq = 0xff;
+ break;
+ case 7: /* on-board ether */
+ dev->irq = nile4_to_irq(NILE4_INT_INTB);
+ break;
+ case 8: /* ISA-PCI bridge */
+ dev->irq = nile4_to_irq(NILE4_INT_INTC);
+ break;
+ case 9: /* ext slot #3 */
+ dev->irq = nile4_to_irq(NILE4_INT_INTD);
+ break;
+ case 10: /* ext slot #4 */
+ dev->irq = nile4_to_irq(NILE4_INT_INTA);
+ break;
+ case 13: /* Vrc5476 */
+ dev->irq = 0xff;
+ break;
+ case 14: /* HD controller, M5229 */
+ dev->irq = 14;
+ break;
+ default:
+ printk
+ ("JSUN : in pcibios_fixup_irqs - unkown slot %d\n",
+ slot_num);
+ panic
+ ("JSUN : in pcibios_fixup_irqs - unkown slot.\n");
+ }
+ }
+}
+
+void __init pcibios_init(void)
+{
+ printk("PCI: Emulate bios initialization \n");
+ /* [jsun] we need to set BAR0 so that SDRAM 0 appears at 0x0 in PCI */
+ *(long *) (NILE4_BASE + NILE4_BAR0) = 0x8;
+
+ printk("PCI: Probing PCI hardware\n");
+ ioport_resource.end = 0x1ffffff; /* 32 MB */
+ iomem_resource.end = 0x1fffffff; /* 512 MB */
+
+ /* `ram' and `nile4' are requested through the Nile4 pci_dev */
+ request_resource(&iomem_resource, &ddb5476_resources.flash);
+ request_resource(&iomem_resource, &ddb5476_resources.isa_io);
+ request_resource(&iomem_resource, &ddb5476_resources.pci_io);
+ request_resource(&iomem_resource, &ddb5476_resources.isa_mem);
+ request_resource(&iomem_resource, &ddb5476_resources.pci_mem);
+ request_resource(&iomem_resource, &ddb5476_resources.boot);
+
+ pci_scan_bus(0, &nile4_pci_ops, NULL);
+ ddb5476_pci_fixup();
+ pci_assign_unassigned_resources();
+ pcibios_fixup_irqs();
+}
+
+void __init pcibios_fixup_bus(struct pci_bus *bus)
+{
+ /* [jsun] we don't know how to fix sub-buses yet */
+ if (bus->number == 0) {
+ bus->resource[1] = &ddb5476_resources.pci_mem;
+ }
+}
+
+char *pcibios_setup(char *str)
+{
+ return str;
+}
+
+void __init pcibios_update_irq(struct pci_dev *dev, int irq)
+{
+ pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
+}
+
+void __init pcibios_fixup_pbus_ranges(struct pci_bus *bus,
+ struct pbus_set_ranges_data *ranges)
+{
+ /*
+ * our caller figure out range by going through the dev structures.
+ * I guess this is the place to fix things up if the bus is using a
+ * different view of the addressing space.
+ */
+
+#if 0 /* original DDB5074 code */
+ if (bus->number == 0) {
+ ranges->io_start -= bus->resource[0]->start;
+ ranges->io_end -= bus->resource[0]->start;
+ ranges->mem_start -= bus->resource[1]->start;
+ ranges->mem_end -= bus->resource[1]->start;
+ }
+#endif
+}
+
+int pcibios_enable_resources(struct pci_dev *dev)
+{
+ u16 cmd, old_cmd;
+ int idx;
+ struct resource *r;
+
+ /*
+ * Don't touch the Nile 4
+ */
+ if (dev->vendor == PCI_VENDOR_ID_NEC &&
+ dev->device == PCI_DEVICE_ID_NEC_VRC5476) return 0;
+
+ pci_read_config_word(dev, PCI_COMMAND, &cmd);
+ old_cmd = cmd;
+ for (idx = 0; idx < 6; idx++) {
+ r = &dev->resource[idx];
+ if (!r->start && r->end) {
+ printk(KERN_ERR "PCI: Device %s not available because "
+ "of resource collisions\n", dev->slot_name);
+ return -EINVAL;
+ }
+ if (r->flags & IORESOURCE_IO)
+ cmd |= PCI_COMMAND_IO;
+ if (r->flags & IORESOURCE_MEM)
+ cmd |= PCI_COMMAND_MEMORY;
+ }
+ if (cmd != old_cmd) {
+ printk("PCI: Enabling device %s (%04x -> %04x)\n",
+ dev->slot_name, old_cmd, cmd);
+ pci_write_config_word(dev, PCI_COMMAND, cmd);
+ }
+ return 0;
+}
+
+int pcibios_enable_device(struct pci_dev *dev)
+{
+ return pcibios_enable_resources(dev);
+}
+
+void pcibios_update_resource(struct pci_dev *dev, struct resource *root,
+ struct resource *res, int resource)
+{
+ u32 new, check;
+ int reg;
+
+ new = res->start | (res->flags & PCI_REGION_FLAG_MASK);
+ if (resource < 6) {
+ reg = PCI_BASE_ADDRESS_0 + 4 * resource;
+ } else if (resource == PCI_ROM_RESOURCE) {
+ res->flags |= PCI_ROM_ADDRESS_ENABLE;
+ reg = dev->rom_base_reg;
+ } else {
+ /*
+ * Somebody might have asked allocation of a non-standard
+ * resource
+ */
+ return;
+ }
+
+ pci_write_config_dword(dev, reg, new);
+ pci_read_config_dword(dev, reg, &check);
+ if ((new ^ check) &
+ ((new & PCI_BASE_ADDRESS_SPACE_IO) ? PCI_BASE_ADDRESS_IO_MASK :
+ PCI_BASE_ADDRESS_MEM_MASK)) {
+ printk(KERN_ERR "PCI: Error while updating region "
+ "%s/%d (%08x != %08x)\n", dev->slot_name, resource,
+ new, check);
+ }
+}
+
+void pcibios_align_resource(void *data, struct resource *res,
+ unsigned long size)
+{
+ struct pci_dev *dev = data;
+
+ if (res->flags & IORESOURCE_IO) {
+ unsigned long start = res->start;
+
+ /* We need to avoid collisions with `mirrored' VGA ports
+ and other strange ISA hardware, so we always want the
+ addresses kilobyte aligned. */
+ if (size > 0x100) {
+ printk(KERN_ERR "PCI: I/O Region %s/%d too large"
+ " (%ld bytes)\n", dev->slot_name,
+ dev->resource - res, size);
+ }
+
+ start = (start + 1024 - 1) & ~(1024 - 1);
+ res->start = start;
+ }
+}
+
+struct pci_fixup pcibios_fixups[] = { {0} };
--- /dev/null
+/*
+ * arch/mips/ddb5476/prom.c -- NEC DDB Vrc-5476 PROM routines
+ *
+ * Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com>
+ * Sony Software Development Center Europe (SDCE), Brussels
+ *
+ * Jun Sun - modified for DDB5476.
+ */
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/bootmem.h>
+
+#include <asm/addrspace.h>
+#include <asm/bootinfo.h>
+
+
+char arcs_cmdline[COMMAND_LINE_SIZE];
+
+/* [jsun@junsun.net] PMON passes arguments in C main() style */
+void __init prom_init(int argc, const char **arg)
+{
+ int i;
+
+ /* arg[0] is "g", the rest is boot parameters */
+ arcs_cmdline[0] = '\0';
+ for (i = 1; i < argc; i++) {
+ if (strlen(arcs_cmdline) + strlen(arg[i] + 1)
+ >= sizeof(arcs_cmdline))
+ break;
+ strcat(arcs_cmdline, arg[i]);
+ strcat(arcs_cmdline, " ");
+ }
+
+ mips_machgroup = MACH_GROUP_NEC_DDB;
+ mips_machtype = MACH_NEC_DDB5476;
+ /* 64 MB non-upgradable */
+ add_memory_region(0, 64 << 20, BOOT_MEM_RAM);
+}
+
+void __init prom_free_prom_memory(void)
+{
+}
--- /dev/null
+/*
+ * arch/mips/ddb5476/setup.c -- NEC DDB Vrc-5476 setup routines
+ *
+ * Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com>
+ * Sony Software Development Center Europe (SDCE), Brussels
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/kbd_ll.h>
+#include <linux/kernel.h>
+#include <linux/kdev_t.h>
+#include <linux/types.h>
+#include <linux/console.h>
+#include <linux/sched.h>
+#include <linux/mc146818rtc.h>
+#include <linux/pc_keyb.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#include <asm/addrspace.h>
+#include <asm/bcache.h>
+#include <asm/keyboard.h>
+#include <asm/irq.h>
+#include <asm/reboot.h>
+#include <asm/gdb-stub.h>
+#include <asm/nile4.h>
+
+
+#ifdef CONFIG_REMOTE_DEBUG
+extern void rs_kgdb_hook(int);
+extern void breakpoint(void);
+#endif
+
+#if defined(CONFIG_SERIAL_CONSOLE)
+extern void console_setup(char *);
+#endif
+
+extern struct ide_ops std_ide_ops;
+extern struct rtc_ops ddb_rtc_ops;
+extern struct kbd_ops std_kbd_ops;
+
+static void (*back_to_prom) (void) = (void (*)(void)) 0xbfc00000;
+
+static void ddb_machine_restart(char *command)
+{
+ u32 t;
+
+ /* PCI cold reset */
+ t = nile4_in32(NILE4_PCICTRL + 4);
+ t |= 0x40000000;
+ nile4_out32(NILE4_PCICTRL + 4, t);
+ /* CPU cold reset */
+ t = nile4_in32(NILE4_CPUSTAT);
+ t |= 1;
+ nile4_out32(NILE4_CPUSTAT, t);
+ /* Call the PROM */
+ back_to_prom();
+}
+
+static void ddb_machine_halt(void)
+{
+ printk("DDB Vrc-5476 halted.\n");
+ while (1);
+}
+
+static void ddb_machine_power_off(void)
+{
+ printk("DDB Vrc-5476 halted. Please turn off the power.\n");
+ while (1);
+}
+
+extern void ddb_irq_setup(void);
+
+void (*board_time_init) (struct irqaction * irq);
+
+
+static void __init ddb_time_init(struct irqaction *irq)
+{
+ /* set the clock to 1 Hz */
+ nile4_out32(NILE4_T2CTRL, 1000000);
+ /* enable the General-Purpose Timer */
+ nile4_out32(NILE4_T2CTRL + 4, 0x00000001);
+ /* reset timer */
+ nile4_out32(NILE4_T2CNTR, 0);
+ /* enable interrupt */
+ nile4_enable_irq(NILE4_INT_GPT);
+ i8259_setup_irq(nile4_to_irq(NILE4_INT_GPT), irq);
+}
+
+static struct {
+ struct resource dma1;
+ struct resource pic1;
+ struct resource timer;
+ struct resource rtc;
+ struct resource dma_page_reg;
+ struct resource pic2;
+ struct resource dma2;
+} ddb5476_ioport = {
+ {
+ "dma1", 0x00, 0x1f, IORESOURCE_BUSY}, {
+ "pic1", 0x20, 0x3f, IORESOURCE_BUSY}, {
+ "timer", 0x40, 0x5f, IORESOURCE_BUSY}, {
+ "rtc", 0x70, 0x7f, IORESOURCE_BUSY}, {
+ "dma page reg", 0x80, 0x8f, IORESOURCE_BUSY}, {
+ "pic2", 0xa0, 0xbf, IORESOURCE_BUSY}, {
+ "dma2", 0xc0, 0xdf, IORESOURCE_BUSY}
+};
+
+static struct {
+ struct resource nile4;
+} ddb5476_iomem = {
+ { "Nile 4", NILE4_BASE, NILE4_BASE + NILE4_SIZE - 1, IORESOURCE_BUSY}
+};
+
+void __init ddb_setup(void)
+{
+ extern int panic_timeout;
+
+ irq_setup = ddb_irq_setup;
+ mips_io_port_base = NILE4_PCI_IO_BASE;
+ isa_slot_offset = NILE4_PCI_MEM_BASE;
+ board_time_init = ddb_time_init;
+
+ _machine_restart = ddb_machine_restart;
+ _machine_halt = ddb_machine_halt;
+ _machine_power_off = ddb_machine_power_off;
+
+ /* request io port/mem resources */
+ if (request_resource(&ioport_resource, &ddb5476_ioport.dma1) ||
+ request_resource(&ioport_resource, &ddb5476_ioport.pic1) ||
+ request_resource(&ioport_resource, &ddb5476_ioport.timer) ||
+ request_resource(&ioport_resource, &ddb5476_ioport.rtc) ||
+ request_resource(&ioport_resource,
+ &ddb5476_ioport.dma_page_reg)
+ || request_resource(&ioport_resource, &ddb5476_ioport.pic2)
+ || request_resource(&ioport_resource, &ddb5476_ioport.dma2)
+ || request_resource(&iomem_resource, &ddb5476_iomem.nile4)) {
+ printk
+ ("ddb_setup - requesting oo port resources failed.\n");
+ for (;;);
+ }
+#ifdef CONFIG_BLK_DEV_IDE
+ ide_ops = &std_ide_ops;
+#endif
+ rtc_ops = &ddb_rtc_ops;
+
+#ifdef CONFIG_PC_KEYB
+ kbd_ops = &std_kbd_ops;
+#endif
+
+ /* Reboot on panic */
+ panic_timeout = 180;
+
+ /* [jsun] we need to set BAR0 so that SDRAM 0 appears at 0x0 in PCI */
+ /* *(long*)0xbfa00218 = 0x8; */
+
+#ifdef CONFIG_FB
+ conswitchp = &dummy_con;
+#endif
+
+
+ /* board initialization stuff - non-fundamental, but need to be set
+ * before kernel runs */
+
+ /* setup I/O space */
+ nile4_set_pdar(NILE4_PCIW0,
+ PHYSADDR(NILE4_PCI_IO_BASE), 0x02000000, 32, 0, 0);
+ nile4_set_pmr(NILE4_PCIINIT0, NILE4_PCICMD_IO, 0);
+
+ /* map config space to 0xa8000000, 128MB */
+ nile4_set_pdar(NILE4_PCIW1,
+ PHYSADDR(NILE4_PCI_CFG_BASE), 0x08000000, 32, 0, 0);
+ nile4_set_pmr(NILE4_PCIINIT1, NILE4_PCICMD_CFG, 0x0);
+
+ /* ----- M1543 PCI setup ------ */
+
+ /* we know M1543 PCI-ISA controller is at addr:18 */
+ /* xxxx1010 makes USB at addr:13 and PMU at addr:14 */
+ *(volatile unsigned char *) 0xa8040072 &= 0xf0;
+ *(volatile unsigned char *) 0xa8040072 |= 0xa;
+
+ /* setup USB interrupt to IRQ 9, (bit 0:3 - 0001)
+ * no IOCHRDY signal, (bit 7 - 1)
+ * M1543C & M7101 VID and Subsys Device ID are read-only (bit 6 - 1)
+ * Bypass USB Master INTAJ level to edge conversion (bit 4 - 0)
+ */
+ *(unsigned char *) 0xa8040074 = 0xc1;
+
+ /* setup PMU(SCI to IRQ 10 (bit 0:3 - 0011)
+ * SCI routing to IRQ 13 disabled (bit 7 - 1)
+ * SCI interrupt level to edge conversion bypassed (bit 4 - 0)
+ */
+ *(unsigned char *) 0xa8040076 = 0x83;
+
+ /* setup IDE controller
+ * enable IDE controller (bit 6 - 1)
+ * IDE IDSEL to be addr:24 (bit 4:5 - 11)
+ * no IDE ATA Secondary Bus Signal Pad Control (bit 3 - 0)
+ * no IDE ATA Primary Bus Signal Pad Control (bit 2 - 0)
+ * primary IRQ is 14, secondary is 15 (bit 1:0 - 01
+ */
+ // *(unsigned char*)0xa8040058 = 0x71;
+ // *(unsigned char*)0xa8040058 = 0x79;
+ // *(unsigned char*)0xa8040058 = 0x74; // use SIRQ, primary tri-state
+ *(unsigned char *) 0xa8040058 = 0x75; // primary tri-state
+
+#if 0
+ /* this is not necessary if M5229 does not use SIRQ */
+ *(unsigned char *) 0xa8040044 = 0x0d; // primary to IRQ 14
+ *(unsigned char *) 0xa8040075 = 0x0d; // secondary to IRQ 14
+#endif
+
+ /* enable IDE in the M5229 config register 0x50 (bit 0 - 1) */
+ /* M5229 IDSEL is addr:24; see above setting */
+ *(unsigned char *) 0xa9000050 |= 0x1;
+
+ /* enable bus master (bit 2) and IO decoding (bit 0) */
+ *(unsigned char *) 0xa9000004 |= 0x5;
+
+ /* enable native, copied from arch/ppc/k2boot/head.S */
+ /* TODO - need volatile, need to be portable */
+ *(unsigned char *) 0xa9000009 = 0xff;
+
+ /* ----- end of M1543 PCI setup ------ */
+
+ /* ----- reset on-board ether chip ------ */
+ *((volatile u32 *) 0xa8020004) |= 1; /* decode I/O */
+ *((volatile u32 *) 0xa8020010) = 0; /* set BAR address */
+
+ /* send reset command */
+ *((volatile u32 *) 0xa6000000) = 1; /* do a soft reset */
+
+ /* disable ether chip */
+ *((volatile u32 *) 0xa8020004) = 0; /* disable any decoding */
+
+ /* put it into sleep */
+ *((volatile u32 *) 0xa8020040) = 0x80000000;
+
+ /* ----- end of reset on-board ether chip ------ */
+
+ /* ----- set pci window 1 to pci memory space -------- */
+ nile4_set_pdar(NILE4_PCIW1,
+ PHYSADDR(NILE4_PCI_MEM_BASE), 0x08000000, 32, 0, 0);
+ // nile4_set_pmr(NILE4_PCIINIT1, NILE4_PCICMD_MEM, 0);
+ nile4_set_pmr(NILE4_PCIINIT1, NILE4_PCICMD_MEM, 0x08000000);
+
+}
+
+#define USE_NILE4_SERIAL 0
+
+#if USE_NILE4_SERIAL
+#define ns16550_in(reg) nile4_in8((reg)*8)
+#define ns16550_out(reg, val) nile4_out8((reg)*8, (val))
+#else
+#define NS16550_BASE (NILE4_PCI_IO_BASE+0x03f8)
+static inline u8 ns16550_in(u32 reg)
+{
+ return *(volatile u8 *) (NS16550_BASE + reg);
+}
+
+static inline void ns16550_out(u32 reg, u8 val)
+{
+ *(volatile u8 *) (NS16550_BASE + reg) = val;
+}
+#endif
+
+#define NS16550_RBR 0
+#define NS16550_THR 0
+#define NS16550_DLL 0
+#define NS16550_IER 1
+#define NS16550_DLM 1
+#define NS16550_FCR 2
+#define NS16550_IIR 2
+#define NS16550_LCR 3
+#define NS16550_MCR 4
+#define NS16550_LSR 5
+#define NS16550_MSR 6
+#define NS16550_SCR 7
+
+#define NS16550_LSR_DR 0x01 /* Data ready */
+#define NS16550_LSR_OE 0x02 /* Overrun */
+#define NS16550_LSR_PE 0x04 /* Parity error */
+#define NS16550_LSR_FE 0x08 /* Framing error */
+#define NS16550_LSR_BI 0x10 /* Break */
+#define NS16550_LSR_THRE 0x20 /* Xmit holding register empty */
+#define NS16550_LSR_TEMT 0x40 /* Xmitter empty */
+#define NS16550_LSR_ERR 0x80 /* Error */
+
+
+void _serinit(void)
+{
+#if USE_NILE4_SERIAL
+ ns16550_out(NS16550_LCR, 0x80);
+ ns16550_out(NS16550_DLM, 0x00);
+ ns16550_out(NS16550_DLL, 0x36); /* 9600 baud */
+ ns16550_out(NS16550_LCR, 0x00);
+ ns16550_out(NS16550_LCR, 0x03);
+ ns16550_out(NS16550_FCR, 0x47);
+#else
+ /* done by PMON */
+#endif
+}
+
+void _putc(char c)
+{
+ while (!(ns16550_in(NS16550_LSR) & NS16550_LSR_THRE));
+ ns16550_out(NS16550_THR, c);
+ if (c == '\n') {
+ while (!(ns16550_in(NS16550_LSR) & NS16550_LSR_THRE));
+ ns16550_out(NS16550_THR, '\r');
+ }
+}
+
+void _puts(const char *s)
+{
+ char c;
+
+ while ((c = *s++))
+ _putc(c);
+}
+
+char _getc(void)
+{
+ while (!(ns16550_in(NS16550_LSR) & NS16550_LSR_DR));
+
+ return ns16550_in(NS16550_RBR);
+}
+
+int _testc(void)
+{
+ return (ns16550_in(NS16550_LSR) & NS16550_LSR_DR) != 0;
+}
+
+
+/*
+ * Hexadecimal 7-segment LED
+ */
+void ddb5476_led_hex(int hex)
+{
+ outb(hex, 0x80);
+}
+
+
+/*
+ * LEDs D2 and D3, connected to the GPIO pins of the PMU in the ALi M1543
+ */
+struct pci_dev *pci_pmu = NULL;
+
+void ddb5476_led_d2(int on)
+{
+ u8 t;
+
+ if (pci_pmu) {
+ pci_read_config_byte(pci_pmu, 0x7e, &t);
+ if (on)
+ t &= 0x7f;
+ else
+ t |= 0x80;
+ pci_write_config_byte(pci_pmu, 0x7e, t);
+ }
+}
+
+void ddb5476_led_d3(int on)
+{
+ u8 t;
+
+ if (pci_pmu) {
+ pci_read_config_byte(pci_pmu, 0x7e, &t);
+ if (on)
+ t &= 0xbf;
+ else
+ t |= 0x40;
+ pci_write_config_byte(pci_pmu, 0x7e, t);
+ }
+}
--- /dev/null
+/*
+ * arch/mips/ddb5074/time.c -- Timer routines
+ *
+ * Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com>
+ * Sony Software Development Center Europe (SDCE), Brussels
+ */
+#include <linux/init.h>
+
+#include <asm/mc146818rtc.h>
+
+static unsigned char ddb_rtc_read_data(unsigned long addr)
+{
+ outb_p(addr, RTC_PORT(0));
+ return inb_p(RTC_PORT(1));
+}
+
+static void ddb_rtc_write_data(unsigned char data, unsigned long addr)
+{
+ outb_p(addr, RTC_PORT(0));
+ outb_p(data, RTC_PORT(1));
+}
+
+static int ddb_rtc_bcd_mode(void)
+{
+ return 1;
+}
+
+struct rtc_ops ddb_rtc_ops = {
+ ddb_rtc_read_data,
+ ddb_rtc_write_data,
+ ddb_rtc_bcd_mode
+};
#
.S.s:
- $(CPP) $(CFLAGS) $< -o $*.s
+ $(CPP) $(AFLAGS) $< -o $@
.S.o:
- $(CC) $(CFLAGS) -c $< -o $*.o
+ $(CC) $(AFLAGS) -c $< -o $@
-all: dec.o
O_TARGET := dec.o
-O_OBJS := int-handler.o setup.o irq.o time.o reset.o rtc-dec.o
-ifdef CONFIG_PROM_CONSOLE
-O_OBJS += promcon.o
-endif
+all: dec.o
-ifdef CONFIG_SERIAL
-O_OBJS += serial.o
-endif
+export-objs := wbflush.o
+obj-y := int-handler.o setup.o irq.o time.o reset.o rtc-dec.o wbflush.o
-ifeq ($(CONFIG_MODULES),y)
- OX_OBJS = wbflush.o
-else
- O_OBJS += wbflush.o
-endif
+obj-$(CONFIG_PROM_CONSOLE) += promcon.o
+obj-$(CONFIG_SERIAL) += serial.o
int-handler.o: int-handler.S
-clean:
-
include $(TOPDIR)/Rules.make
all: dec_boot.o
O_TARGET := dec_boot.o
-O_OBJS := decstation.o
+
+obj-y := decstation.o
clean:
rm -f nbImage
# CONFIG_COBALT_MICRO_SERVER is not set
# CONFIG_DECSTATION is not set
# CONFIG_DDB5074 is not set
-# CONFIG_ORION is not set
# CONFIG_MIPS_MAGNUM_4000 is not set
# CONFIG_OLIVETTI_M700 is not set
CONFIG_SGI_IP22=y
# CONFIG_SNI_RM200_PCI is not set
+# CONFIG_MCA is not set
# CONFIG_SBUS is not set
CONFIG_ARC32=y
CONFIG_PC_KEYB=y
CONFIG_SGI=y
# CONFIG_ISA is not set
+# CONFIG_EISA is not set
# CONFIG_PCI is not set
#
# CONFIG_BLK_DEV_XD is not set
# CONFIG_PARIDE is not set
# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
# CONFIG_BLK_DEV_DAC960 is not set
# CONFIG_BLK_DEV_LOOP is not set
# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_LVM is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_BLK_DEV_INITRD is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
# CONFIG_BLK_DEV_MD is not set
# CONFIG_MD_LINEAR is not set
# CONFIG_MD_RAID0 is not set
# CONFIG_MD_RAID1 is not set
# CONFIG_MD_RAID5 is not set
-# CONFIG_BLK_DEV_RAM is not set
-# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_BLK_DEV_LVM is not set
#
# Networking options
CONFIG_IP_PNP=y
CONFIG_IP_PNP_BOOTP=y
# CONFIG_IP_PNP_RARP is not set
-# CONFIG_IP_ROUTER is not set
# CONFIG_NET_IPIP is not set
# CONFIG_NET_IPGRE is not set
-# CONFIG_IP_ALIAS is not set
# CONFIG_INET_ECN is not set
# CONFIG_SYN_COOKIES is not set
# CONFIG_IPV6 is not set
# CONFIG_X25 is not set
# CONFIG_LAPB is not set
# CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
# CONFIG_NET_FASTROUTE is not set
CONFIG_BLK_DEV_SD=y
CONFIG_SD_EXTRA_DEVS=40
CONFIG_CHR_DEV_ST=y
+# CONFIG_CHR_DEV_OSST is not set
CONFIG_BLK_DEV_SR=y
# CONFIG_BLK_DEV_SR_VENDOR is not set
CONFIG_SR_EXTRA_DEVS=2
# CONFIG_SCSI_INITIO is not set
# CONFIG_SCSI_INIA100 is not set
# CONFIG_SCSI_NCR53C406A is not set
-# CONFIG_SCSI_SYM53C416 is not set
-# CONFIG_SCSI_SIM710 is not set
# CONFIG_SCSI_NCR53C7xx is not set
# CONFIG_SCSI_PAS16 is not set
# CONFIG_SCSI_PCI2000 is not set
# CONFIG_SCSI_PCI2220I is not set
# CONFIG_SCSI_PSI240I is not set
# CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_SIM710 is not set
+# CONFIG_SCSI_SYM53C416 is not set
# CONFIG_SCSI_T128 is not set
# CONFIG_SCSI_U14_34F is not set
# CONFIG_SCSI_DEBUG is not set
# CONFIG_QUOTA is not set
CONFIG_AUTOFS_FS=y
CONFIG_AUTOFS4_FS=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_REISERFS_CHECK is not set
# CONFIG_ADFS_FS is not set
# CONFIG_ADFS_FS_RW is not set
# CONFIG_AFFS_FS is not set
# CONFIG_NCPFS_NFS_NS is not set
# CONFIG_NCPFS_OS2_NS is not set
# CONFIG_NCPFS_SMALLDOS is not set
-# CONFIG_NCPFS_MOUNT_SUBDIR is not set
-# CONFIG_NCPFS_NDS_DOMAINS is not set
# CONFIG_NCPFS_NLS is not set
# CONFIG_NCPFS_EXTRAS is not set
# CONFIG_MAC_PARTITION is not set
CONFIG_MSDOS_PARTITION=y
# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
# CONFIG_SOLARIS_X86_PARTITION is not set
# CONFIG_UNIXWARE_DISKLABEL is not set
CONFIG_SGI_PARTITION=y
# CONFIG_ULTRIX_PARTITION is not set
# CONFIG_SUN_PARTITION is not set
+# CONFIG_SMB_NLS is not set
# CONFIG_NLS is not set
#
# CONFIG_USB is not set
#
+# Input core support
+#
+# CONFIG_INPUT is not set
+
+#
# Kernel hacking
#
CONFIG_CROSSCOMPILE=y
CONFIG_COBALT_28=y
# CONFIG_DECSTATION is not set
# CONFIG_DDB5074 is not set
-# CONFIG_ORION is not set
# CONFIG_MIPS_MAGNUM_4000 is not set
# CONFIG_OLIVETTI_M700 is not set
# CONFIG_SGI_IP22 is not set
# CONFIG_SNI_RM200_PCI is not set
+# CONFIG_MCA is not set
# CONFIG_SBUS is not set
-# CONFIG_ISA is not set
CONFIG_COBALT_27=y
CONFIG_COBALT_LCD=y
CONFIG_COBALT_SERIAL=y
CONFIG_PCI=y
# CONFIG_ISA is not set
+# CONFIG_EISA is not set
#
# Loadable module support
# CONFIG_BLK_DEV_XD is not set
# CONFIG_PARIDE is not set
# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
# CONFIG_BLK_DEV_DAC960 is not set
CONFIG_BLK_DEV_LOOP=m
# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_LVM is not set
-CONFIG_BLK_DEV_MD=y
-CONFIG_MD_LINEAR=y
-# CONFIG_MD_RAID0 is not set
-# CONFIG_MD_RAID1 is not set
-# CONFIG_MD_RAID5 is not set
-# CONFIG_MD_BOOT is not set
-# CONFIG_AUTODETECT_RAID is not set
CONFIG_BLK_DEV_RAM=m
CONFIG_BLK_DEV_RAM_SIZE=4096
# CONFIG_BLK_DEV_INITRD is not set
#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+# CONFIG_BLK_DEV_MD is not set
+# CONFIG_MD_LINEAR is not set
+# CONFIG_MD_RAID0 is not set
+# CONFIG_MD_RAID1 is not set
+# CONFIG_MD_RAID5 is not set
+# CONFIG_BLK_DEV_LVM is not set
+
+#
# Networking options
#
# CONFIG_PACKET is not set
CONFIG_IP_MULTICAST=y
# CONFIG_IP_ADVANCED_ROUTER is not set
# CONFIG_IP_PNP is not set
-# CONFIG_IP_ROUTER is not set
# CONFIG_NET_IPIP is not set
# CONFIG_NET_IPGRE is not set
CONFIG_IP_MROUTE=y
# CONFIG_IP_PIMSM_V1 is not set
# CONFIG_IP_PIMSM_V2 is not set
-CONFIG_IP_ALIAS=y
# CONFIG_INET_ECN is not set
CONFIG_SYN_COOKIES=y
# CONFIG_IPV6 is not set
#
CONFIG_IPX=m
# CONFIG_IPX_INTERN is not set
-# CONFIG_SPX is not set
CONFIG_ATALK=m
# CONFIG_DECNET is not set
# CONFIG_BRIDGE is not set
# CONFIG_X25 is not set
# CONFIG_LAPB is not set
# CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
# CONFIG_NET_FASTROUTE is not set
CONFIG_BLK_DEV_SD=y
CONFIG_SD_EXTRA_DEVS=40
CONFIG_CHR_DEV_ST=m
+# CONFIG_CHR_DEV_OSST is not set
CONFIG_BLK_DEV_SR=m
# CONFIG_BLK_DEV_SR_VENDOR is not set
CONFIG_SR_EXTRA_DEVS=2
# CONFIG_SCSI_AHA1542 is not set
# CONFIG_SCSI_AHA1740 is not set
CONFIG_SCSI_AIC7XXX=y
-# CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT is not set
CONFIG_AIC7XXX_CMDS_PER_DEVICE=8
-# CONFIG_AIC7XXX_PROC_STATS is not set
CONFIG_AIC7XXX_RESET_DELAY=5
# CONFIG_SCSI_ADVANSYS is not set
# CONFIG_SCSI_IN2000 is not set
# CONFIG_SCSI_AM53C974 is not set
# CONFIG_SCSI_MEGARAID is not set
# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_CPQFCTS is not set
# CONFIG_SCSI_DMX3191D is not set
# CONFIG_SCSI_DTC3280 is not set
# CONFIG_SCSI_EATA is not set
# CONFIG_SCSI_INITIO is not set
# CONFIG_SCSI_INIA100 is not set
# CONFIG_SCSI_NCR53C406A is not set
-# CONFIG_SCSI_SYM53C416 is not set
-# CONFIG_SCSI_SIM710 is not set
# CONFIG_SCSI_NCR53C7xx is not set
CONFIG_SCSI_NCR53C8XX=y
# CONFIG_SCSI_SYM53C8XX is not set
# CONFIG_SCSI_QLOGIC_ISP is not set
# CONFIG_SCSI_QLOGIC_FC is not set
# CONFIG_SCSI_QLOGIC_1280 is not set
+# CONFIG_SCSI_SIM710 is not set
+# CONFIG_SCSI_SYM53C416 is not set
# CONFIG_SCSI_DC390T is not set
# CONFIG_SCSI_T128 is not set
# CONFIG_SCSI_U14_34F is not set
CONFIG_DUMMY=m
# CONFIG_BONDING is not set
# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
# CONFIG_NET_SB1000 is not set
#
# CONFIG_NET_VENDOR_RACAL is not set
# CONFIG_AT1700 is not set
# CONFIG_DEPCA is not set
+# CONFIG_HP100 is not set
# CONFIG_NET_ISA is not set
# CONFIG_NET_PCI is not set
# CONFIG_NET_POCKET is not set
#
# Ethernet (1000 Mbit)
#
-# CONFIG_YELLOWFIN is not set
# CONFIG_ACENIC is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
# CONFIG_SK98LIN is not set
# CONFIG_FDDI is not set
# CONFIG_HIPPI is not set
CONFIG_ISDN_PPP=y
CONFIG_ISDN_PPP_VJ=y
CONFIG_ISDN_MPP=y
+# CONFIG_ISDN_PPP_BSDCOMP is not set
CONFIG_ISDN_AUDIO=y
# CONFIG_ISDN_TTY_FAX is not set
# CONFIG_HISAX_NO_LLC is not set
# CONFIG_HISAX_NO_KEYPAD is not set
CONFIG_HISAX_1TR6=y
+# CONFIG_HISAX_NI1 is not set
#
# HiSax supported cards
# CONFIG_HISAX_SPORTSTER is not set
# CONFIG_HISAX_MIC is not set
# CONFIG_HISAX_NETJET is not set
+# CONFIG_HISAX_NETJET_U is not set
# CONFIG_HISAX_NICCY is not set
# CONFIG_HISAX_ISURF is not set
# CONFIG_HISAX_HSTSAPHIR is not set
# CONFIG_HISAX_HFC_PCI is not set
# CONFIG_HISAX_W6692 is not set
# CONFIG_HISAX_HFC_SX is not set
+# CONFIG_HISAX_SEDLBAUER_CS is not set
#
# Active ISDN cards
# CONFIG_ISDN_DRV_ACT2000 is not set
# CONFIG_ISDN_DRV_EICON is not set
# CONFIG_ISDN_CAPI is not set
-# CONFIG_ISDN_CAPI_MIDDLEWARE is not set
# CONFIG_HYSDN is not set
+# CONFIG_HYSDN_CAPI is not set
#
# Old CD-ROM drivers (not SCSI, not IDE)
# Joysticks
#
# CONFIG_JOYSTICK is not set
+
+#
+# Input core support is needed for joysticks
+#
# CONFIG_QIC02_TAPE is not set
#
# CONFIG_INTEL_RNG is not set
# CONFIG_NVRAM is not set
CONFIG_RTC=y
-
-#
-# Video For Linux
-#
-# CONFIG_VIDEO_DEV is not set
# CONFIG_DTLK is not set
# CONFIG_R3964 is not set
# CONFIG_APPLICOM is not set
# Ftape, the floppy tape device driver
#
# CONFIG_FTAPE is not set
-# CONFIG_DRM is not set
# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
#
# File systems
CONFIG_QUOTA=y
# CONFIG_AUTOFS_FS is not set
# CONFIG_AUTOFS4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_REISERFS_CHECK is not set
# CONFIG_ADFS_FS is not set
# CONFIG_ADFS_FS_RW is not set
# CONFIG_AFFS_FS is not set
CONFIG_SUNRPC=y
CONFIG_LOCKD=y
CONFIG_SMB_FS=m
+# CONFIG_SMB_NLS_DEFAULT is not set
# CONFIG_NCP_FS is not set
# CONFIG_NCPFS_PACKET_SIGNING is not set
# CONFIG_NCPFS_IOCTL_LOCKING is not set
# CONFIG_NCPFS_NFS_NS is not set
# CONFIG_NCPFS_OS2_NS is not set
# CONFIG_NCPFS_SMALLDOS is not set
-# CONFIG_NCPFS_MOUNT_SUBDIR is not set
-# CONFIG_NCPFS_NDS_DOMAINS is not set
# CONFIG_NCPFS_NLS is not set
# CONFIG_NCPFS_EXTRAS is not set
#
# CONFIG_PARTITION_ADVANCED is not set
CONFIG_MSDOS_PARTITION=y
+CONFIG_SMB_NLS=y
CONFIG_NLS=y
#
# CONFIG_USB is not set
#
+# Input core support
+#
+# CONFIG_INPUT is not set
+
+#
# Kernel hacking
#
# CONFIG_CROSSCOMPILE is not set
--- /dev/null
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_MIPS=y
+# CONFIG_SMP is not set
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+
+#
+# Machine selection
+#
+# CONFIG_ACER_PICA_61 is not set
+# CONFIG_ALGOR_P4032 is not set
+# CONFIG_BAGET_MIPS is not set
+# CONFIG_DECSTATION is not set
+# CONFIG_DDB5074 is not set
+# CONFIG_MIPS_EV96100 is not set
+# CONFIG_MIPS_EV64120 is not set
+# CONFIG_MIPS_ATLAS is not set
+# CONFIG_MIPS_MALTA is not set
+# CONFIG_NINO is not set
+# CONFIG_MIPS_MAGNUM_4000 is not set
+# CONFIG_MOMENCO_OCELOT is not set
+CONFIG_DDB5476=y
+# CONFIG_OLIVETTI_M700 is not set
+# CONFIG_SGI_IP22 is not set
+# CONFIG_SNI_RM200_PCI is not set
+# CONFIG_MIPS_ITE8172 is not set
+# CONFIG_MIPS_IVR is not set
+# CONFIG_MCA is not set
+# CONFIG_SBUS is not set
+CONFIG_I8259=y
+CONFIG_ISA=y
+CONFIG_PCI=y
+CONFIG_PC_KEYB=y
+CONFIG_ROTTEN_IRQ=y
+CONFIG_EISA=y
+
+#
+# Loadable module support
+#
+# CONFIG_MODULES is not set
+
+#
+# CPU selection
+#
+# CONFIG_CPU_R3000 is not set
+# CONFIG_CPU_R3912 is not set
+# CONFIG_CPU_R6000 is not set
+# CONFIG_CPU_R4300 is not set
+# CONFIG_CPU_R4X00 is not set
+# CONFIG_CPU_R5000 is not set
+CONFIG_CPU_R5432=y
+# CONFIG_CPU_RM7000 is not set
+# CONFIG_CPU_NEVADA is not set
+# CONFIG_CPU_R8000 is not set
+# CONFIG_CPU_R10000 is not set
+# CONFIG_CPU_MIPS32 is not set
+# CONFIG_CPU_ADVANCED is not set
+CONFIG_CPU_HAS_LLSC=y
+# CONFIG_CPU_HAS_WB is not set
+
+#
+# General setup
+#
+CONFIG_CPU_LITTLE_ENDIAN=y
+CONFIG_MIPS_FPU_EMULATOR=y
+CONFIG_KCORE_ELF=y
+CONFIG_ELF_KERNEL=y
+# CONFIG_BINFMT_AOUT is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+CONFIG_NET=y
+# CONFIG_PCI_NAMES is not set
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play configuration
+#
+# CONFIG_PNP is not set
+# CONFIG_ISAPNP is not set
+# CONFIG_PCMCIA is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_BLK_DEV_INITRD is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+# CONFIG_BLK_DEV_MD is not set
+# CONFIG_MD_LINEAR is not set
+# CONFIG_MD_RAID0 is not set
+# CONFIG_MD_RAID1 is not set
+# CONFIG_MD_RAID5 is not set
+# CONFIG_BLK_DEV_LVM is not set
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+# CONFIG_NETLINK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_FILTER is not set
+CONFIG_UNIX=y
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_INET_ECN is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_IPV6 is not set
+# CONFIG_KHTTPD is not set
+# CONFIG_ATM is not set
+
+#
+#
+#
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+# CONFIG_PHONE_IXJ is not set
+
+#
+# ATA/IDE/MFM/RLL support
+#
+CONFIG_IDE=y
+
+#
+# IDE, ATA and ATAPI Block devices
+#
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_HD_IDE is not set
+# CONFIG_BLK_DEV_HD is not set
+CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
+# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
+# CONFIG_BLK_DEV_IDEDISK_IBM is not set
+# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
+# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
+# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
+# CONFIG_BLK_DEV_IDEDISK_WD is not set
+# CONFIG_BLK_DEV_COMMERIAL is not set
+# CONFIG_BLK_DEV_TIVO is not set
+# CONFIG_BLK_DEV_IDECS is not set
+# CONFIG_BLK_DEV_IDECD is not set
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_BLK_DEV_IDESCSI is not set
+
+#
+# IDE chipset support/bugfixes
+#
+# CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
+# CONFIG_BLK_DEV_ISAPNP is not set
+# CONFIG_BLK_DEV_RZ1000 is not set
+CONFIG_BLK_DEV_IDEPCI=y
+# CONFIG_IDEPCI_SHARE_IRQ is not set
+# CONFIG_BLK_DEV_IDEDMA_PCI is not set
+# CONFIG_BLK_DEV_OFFBOARD is not set
+# CONFIG_IDEDMA_PCI_AUTO is not set
+# CONFIG_BLK_DEV_IDEDMA is not set
+# CONFIG_IDEDMA_PCI_WIP is not set
+# CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
+# CONFIG_BLK_DEV_AEC62XX is not set
+# CONFIG_AEC62XX_TUNING is not set
+# CONFIG_BLK_DEV_ALI15X3 is not set
+# CONFIG_WDC_ALI15X3 is not set
+# CONFIG_BLK_DEV_AMD7409 is not set
+# CONFIG_AMD7409_OVERRIDE is not set
+# CONFIG_BLK_DEV_CMD64X is not set
+# CONFIG_BLK_DEV_CY82C693 is not set
+# CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_HPT34X is not set
+# CONFIG_HPT34X_AUTODMA is not set
+# CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_NS87415 is not set
+# CONFIG_BLK_DEV_OPTI621 is not set
+# CONFIG_BLK_DEV_PDC202XX is not set
+# CONFIG_PDC202XX_BURST is not set
+# CONFIG_BLK_DEV_OSB4 is not set
+# CONFIG_BLK_DEV_SIS5513 is not set
+# CONFIG_BLK_DEV_SLC90E66 is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+# CONFIG_BLK_DEV_VIA82CXXX is not set
+# CONFIG_IDE_CHIPSETS is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_DMA_NONPCI is not set
+# CONFIG_BLK_DEV_IDE_MODES is not set
+
+#
+# SCSI support
+#
+# CONFIG_SCSI is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+# CONFIG_I2O_PCI is not set
+# CONFIG_I2O_BLOCK is not set
+# CONFIG_I2O_LAN is not set
+# CONFIG_I2O_SCSI is not set
+# CONFIG_I2O_PROC is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_NET_SB1000 is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_LANCE is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_AT1700 is not set
+# CONFIG_DEPCA is not set
+# CONFIG_HP100 is not set
+# CONFIG_NET_ISA is not set
+CONFIG_NET_PCI=y
+# CONFIG_PCNET32 is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_AC3200 is not set
+# CONFIG_APRICOT is not set
+# CONFIG_CS89x0 is not set
+CONFIG_TULIP=y
+# CONFIG_DE4X5 is not set
+# CONFIG_DGRS is not set
+# CONFIG_DM9102 is not set
+CONFIG_EEPRO100=y
+# CONFIG_EEPRO100_PM is not set
+# CONFIG_LNE390 is not set
+# CONFIG_NATSEMI is not set
+CONFIG_NE2K_PCI=y
+# CONFIG_NE3210 is not set
+# CONFIG_ES3210 is not set
+# CONFIG_8139TOO is not set
+# CONFIG_RTL8129 is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_TLAN is not set
+# CONFIG_VIA_RHINE is not set
+# CONFIG_WINBOND_840 is not set
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_LAN_SAA9730 is not set
+# CONFIG_NET_POCKET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+# CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
+# CONFIG_SHAPER is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Old CD-ROM drivers (not SCSI, not IDE)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+# CONFIG_VT_CONSOLE is not set
+CONFIG_SERIAL=y
+CONFIG_SERIAL_CONSOLE=y
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_UNIX98_PTYS is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+CONFIG_MOUSE=y
+CONFIG_PSMOUSE=y
+# CONFIG_82C710_MOUSE is not set
+# CONFIG_PC110_PAD is not set
+
+#
+# Joysticks
+#
+# CONFIG_JOYSTICK is not set
+
+#
+# Input core support is needed for joysticks
+#
+# CONFIG_QIC02_TAPE is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_INTEL_RNG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# File systems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_ADFS_FS_RW is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_UMSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_RAMFS is not set
+# CONFIG_ISO9660_FS is not set
+# CONFIG_JOLIET is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_MOUNT is not set
+# CONFIG_DEVFS_DEBUG is not set
+# CONFIG_DEVPTS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX4FS_RW is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_EXT2_FS=y
+# CONFIG_SYSV_FS is not set
+# CONFIG_SYSV_FS_WRITE is not set
+# CONFIG_UDF_FS is not set
+# CONFIG_UDF_RW is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_UFS_FS_WRITE is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+CONFIG_NFS_FS=y
+# CONFIG_NFS_V3 is not set
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+# CONFIG_NFSD_V3 is not set
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+# CONFIG_SMB_FS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_SMB_NLS is not set
+# CONFIG_NLS is not set
+
+#
+# Console drivers
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_FB=y
+
+#
+# Frame-buffer support
+#
+CONFIG_FB=y
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FB_RIVA is not set
+# CONFIG_FB_CLGEN is not set
+# CONFIG_FB_PM2 is not set
+# CONFIG_FB_CYBER2000 is not set
+# CONFIG_FB_MATROX is not set
+# CONFIG_FB_ATY is not set
+# CONFIG_FB_ATY128 is not set
+CONFIG_FB_3DFX=y
+# CONFIG_FB_SIS is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FBCON_ADVANCED is not set
+CONFIG_FBCON_CFB8=y
+CONFIG_FBCON_CFB16=y
+CONFIG_FBCON_CFB32=y
+# CONFIG_FBCON_FONTWIDTH8_ONLY is not set
+# CONFIG_FBCON_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
+# Input core support
+#
+# CONFIG_INPUT is not set
+
+#
+# Kernel hacking
+#
+CONFIG_CROSSCOMPILE=y
+# CONFIG_REMOTE_DEBUG is not set
+# CONFIG_LL_DEBUG is not set
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_MIPS_UNCACHED is not set
# CONFIG_COBALT_MICRO_SERVER is not set
CONFIG_DECSTATION=y
# CONFIG_DDB5074 is not set
-# CONFIG_ORION is not set
# CONFIG_MIPS_MAGNUM_4000 is not set
# CONFIG_OLIVETTI_M700 is not set
# CONFIG_SGI_IP22 is not set
# CONFIG_SNI_RM200_PCI is not set
+# CONFIG_MCA is not set
# CONFIG_SBUS is not set
# CONFIG_ISA is not set
+# CONFIG_EISA is not set
# CONFIG_PCI is not set
#
# CONFIG_BLK_DEV_XD is not set
# CONFIG_PARIDE is not set
# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
# CONFIG_BLK_DEV_DAC960 is not set
# CONFIG_BLK_DEV_LOOP is not set
# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_LVM is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_BLK_DEV_INITRD is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
# CONFIG_BLK_DEV_MD is not set
# CONFIG_MD_LINEAR is not set
# CONFIG_MD_RAID0 is not set
# CONFIG_MD_RAID1 is not set
# CONFIG_MD_RAID5 is not set
-# CONFIG_BLK_DEV_RAM is not set
-# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_BLK_DEV_LVM is not set
#
# Networking options
CONFIG_IP_PNP=y
CONFIG_IP_PNP_BOOTP=y
# CONFIG_IP_PNP_RARP is not set
-# CONFIG_IP_ROUTER is not set
# CONFIG_NET_IPIP is not set
# CONFIG_NET_IPGRE is not set
-# CONFIG_IP_ALIAS is not set
# CONFIG_INET_ECN is not set
# CONFIG_SYN_COOKIES is not set
# CONFIG_IPV6 is not set
# CONFIG_X25 is not set
# CONFIG_LAPB is not set
# CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
# CONFIG_NET_FASTROUTE is not set
CONFIG_BLK_DEV_SD=y
CONFIG_SD_EXTRA_DEVS=40
# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
# CONFIG_BLK_DEV_SR is not set
# CONFIG_CHR_DEV_SG is not set
# CONFIG_SCSI_AHA1542 is not set
# CONFIG_SCSI_AHA1740 is not set
# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
# CONFIG_SCSI_ADVANSYS is not set
# CONFIG_SCSI_IN2000 is not set
# CONFIG_SCSI_AM53C974 is not set
# CONFIG_SCSI_INITIO is not set
# CONFIG_SCSI_INIA100 is not set
# CONFIG_SCSI_NCR53C406A is not set
-# CONFIG_SCSI_SYM53C416 is not set
-# CONFIG_SCSI_SIM710 is not set
# CONFIG_SCSI_NCR53C7xx is not set
# CONFIG_SCSI_PAS16 is not set
# CONFIG_SCSI_PCI2000 is not set
# CONFIG_SCSI_PCI2220I is not set
# CONFIG_SCSI_PSI240I is not set
# CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_SIM710 is not set
+# CONFIG_SCSI_SYM53C416 is not set
# CONFIG_SCSI_T128 is not set
# CONFIG_SCSI_U14_34F is not set
# CONFIG_SCSI_DEBUG is not set
# CONFIG_QUOTA is not set
# CONFIG_AUTOFS_FS is not set
# CONFIG_AUTOFS4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_REISERFS_CHECK is not set
# CONFIG_ADFS_FS is not set
# CONFIG_ADFS_FS_RW is not set
# CONFIG_AFFS_FS is not set
# CONFIG_NCPFS_NFS_NS is not set
# CONFIG_NCPFS_OS2_NS is not set
# CONFIG_NCPFS_SMALLDOS is not set
-# CONFIG_NCPFS_MOUNT_SUBDIR is not set
-# CONFIG_NCPFS_NDS_DOMAINS is not set
# CONFIG_NCPFS_NLS is not set
# CONFIG_NCPFS_EXTRAS is not set
# CONFIG_MAC_PARTITION is not set
CONFIG_MSDOS_PARTITION=y
# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
# CONFIG_SOLARIS_X86_PARTITION is not set
# CONFIG_UNIXWARE_DISKLABEL is not set
# CONFIG_SGI_PARTITION is not set
CONFIG_ULTRIX_PARTITION=y
# CONFIG_SUN_PARTITION is not set
+# CONFIG_SMB_NLS is not set
# CONFIG_NLS is not set
#
# CONFIG_USB is not set
#
+# Input core support
+#
+# CONFIG_INPUT is not set
+
+#
# Kernel hacking
#
CONFIG_CROSSCOMPILE=y
# CONFIG_COBALT_MICRO_SERVER is not set
# CONFIG_DECSTATION is not set
# CONFIG_DDB5074 is not set
-# CONFIG_ORION is not set
# CONFIG_MIPS_MAGNUM_4000 is not set
# CONFIG_OLIVETTI_M700 is not set
CONFIG_SGI_IP22=y
# CONFIG_SNI_RM200_PCI is not set
+# CONFIG_MCA is not set
# CONFIG_SBUS is not set
CONFIG_ARC32=y
CONFIG_PC_KEYB=y
CONFIG_SGI=y
# CONFIG_ISA is not set
+# CONFIG_EISA is not set
# CONFIG_PCI is not set
#
# CONFIG_BLK_DEV_XD is not set
# CONFIG_PARIDE is not set
# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
# CONFIG_BLK_DEV_DAC960 is not set
# CONFIG_BLK_DEV_LOOP is not set
# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_LVM is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_BLK_DEV_INITRD is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
# CONFIG_BLK_DEV_MD is not set
# CONFIG_MD_LINEAR is not set
# CONFIG_MD_RAID0 is not set
# CONFIG_MD_RAID1 is not set
# CONFIG_MD_RAID5 is not set
-# CONFIG_BLK_DEV_RAM is not set
-# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_BLK_DEV_LVM is not set
#
# Networking options
CONFIG_IP_PNP=y
CONFIG_IP_PNP_BOOTP=y
# CONFIG_IP_PNP_RARP is not set
-# CONFIG_IP_ROUTER is not set
# CONFIG_NET_IPIP is not set
# CONFIG_NET_IPGRE is not set
-# CONFIG_IP_ALIAS is not set
# CONFIG_INET_ECN is not set
# CONFIG_SYN_COOKIES is not set
# CONFIG_IPV6 is not set
# CONFIG_X25 is not set
# CONFIG_LAPB is not set
# CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
# CONFIG_NET_FASTROUTE is not set
CONFIG_BLK_DEV_SD=y
CONFIG_SD_EXTRA_DEVS=40
CONFIG_CHR_DEV_ST=y
+# CONFIG_CHR_DEV_OSST is not set
CONFIG_BLK_DEV_SR=y
# CONFIG_BLK_DEV_SR_VENDOR is not set
CONFIG_SR_EXTRA_DEVS=2
# CONFIG_SCSI_AHA1542 is not set
# CONFIG_SCSI_AHA1740 is not set
# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
# CONFIG_SCSI_ADVANSYS is not set
# CONFIG_SCSI_IN2000 is not set
# CONFIG_SCSI_AM53C974 is not set
# CONFIG_SCSI_INITIO is not set
# CONFIG_SCSI_INIA100 is not set
# CONFIG_SCSI_NCR53C406A is not set
-# CONFIG_SCSI_SYM53C416 is not set
-# CONFIG_SCSI_SIM710 is not set
# CONFIG_SCSI_NCR53C7xx is not set
# CONFIG_SCSI_PAS16 is not set
# CONFIG_SCSI_PCI2000 is not set
# CONFIG_SCSI_PCI2220I is not set
# CONFIG_SCSI_PSI240I is not set
# CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_SIM710 is not set
+# CONFIG_SCSI_SYM53C416 is not set
# CONFIG_SCSI_T128 is not set
# CONFIG_SCSI_U14_34F is not set
# CONFIG_SCSI_DEBUG is not set
# CONFIG_QUOTA is not set
CONFIG_AUTOFS_FS=y
CONFIG_AUTOFS4_FS=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_REISERFS_CHECK is not set
# CONFIG_ADFS_FS is not set
# CONFIG_ADFS_FS_RW is not set
# CONFIG_AFFS_FS is not set
# CONFIG_NCPFS_NFS_NS is not set
# CONFIG_NCPFS_OS2_NS is not set
# CONFIG_NCPFS_SMALLDOS is not set
-# CONFIG_NCPFS_MOUNT_SUBDIR is not set
-# CONFIG_NCPFS_NDS_DOMAINS is not set
# CONFIG_NCPFS_NLS is not set
# CONFIG_NCPFS_EXTRAS is not set
# CONFIG_MAC_PARTITION is not set
CONFIG_MSDOS_PARTITION=y
# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
# CONFIG_SOLARIS_X86_PARTITION is not set
# CONFIG_UNIXWARE_DISKLABEL is not set
CONFIG_SGI_PARTITION=y
# CONFIG_ULTRIX_PARTITION is not set
# CONFIG_SUN_PARTITION is not set
+# CONFIG_SMB_NLS is not set
# CONFIG_NLS is not set
#
# CONFIG_USB is not set
#
+# Input core support
+#
+# CONFIG_INPUT is not set
+
+#
# Kernel hacking
#
CONFIG_CROSSCOMPILE=y
--- /dev/null
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_MIPS=y
+# CONFIG_SMP is not set
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+
+#
+# Machine selection
+#
+# CONFIG_ACER_PICA_61 is not set
+# CONFIG_ALGOR_P4032 is not set
+# CONFIG_BAGET_MIPS is not set
+# CONFIG_DECSTATION is not set
+# CONFIG_DDB5074 is not set
+# CONFIG_MIPS_EV96100 is not set
+# CONFIG_MIPS_EV64120 is not set
+# CONFIG_MIPS_ATLAS is not set
+# CONFIG_MIPS_MALTA is not set
+# CONFIG_NINO is not set
+# CONFIG_MIPS_MAGNUM_4000 is not set
+# CONFIG_MOMENCO_OCELOT is not set
+# CONFIG_DDB5476 is not set
+# CONFIG_OLIVETTI_M700 is not set
+# CONFIG_SGI_IP22 is not set
+# CONFIG_SNI_RM200_PCI is not set
+CONFIG_MIPS_ITE8172=y
+# CONFIG_IT8172_REVC is not set
+CONFIG_QTRONIX_KEYBOARD=y
+CONFIG_IT8172_CIR=y
+# CONFIG_IT8172_SCR0 is not set
+# CONFIG_IT8172_SCR1 is not set
+# CONFIG_MIPS_IVR is not set
+# CONFIG_MCA is not set
+# CONFIG_SBUS is not set
+CONFIG_PCI=y
+CONFIG_IT8712=y
+CONFIG_PC_KEYB=y
+# CONFIG_ISA is not set
+# CONFIG_EISA is not set
+# CONFIG_I8259 is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_KMOD is not set
+
+#
+# CPU selection
+#
+# CONFIG_CPU_R3000 is not set
+# CONFIG_CPU_R3912 is not set
+# CONFIG_CPU_R6000 is not set
+# CONFIG_CPU_R4300 is not set
+# CONFIG_CPU_R4X00 is not set
+# CONFIG_CPU_R5000 is not set
+# CONFIG_CPU_R5432 is not set
+# CONFIG_CPU_RM7000 is not set
+CONFIG_CPU_NEVADA=y
+# CONFIG_CPU_R8000 is not set
+# CONFIG_CPU_R10000 is not set
+# CONFIG_CPU_MIPS32 is not set
+# CONFIG_CPU_ADVANCED is not set
+CONFIG_CPU_HAS_LLSC=y
+# CONFIG_CPU_HAS_WB is not set
+
+#
+# General setup
+#
+CONFIG_CPU_LITTLE_ENDIAN=y
+CONFIG_MIPS_FPU_EMULATOR=y
+CONFIG_KCORE_ELF=y
+CONFIG_ELF_KERNEL=y
+# CONFIG_BINFMT_AOUT is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+CONFIG_NET=y
+CONFIG_PCI_NAMES=y
+CONFIG_SYSVIPC=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_SYSCTL=y
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+# CONFIG_PCMCIA is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC1000 is not set
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOCPROBE is not set
+
+#
+# RAM/ROM Device Drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_MTDRAM is not set
+
+#
+# Linearly Mapped Flash Device Drivers
+#
+CONFIG_MTD_CFI=y
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_JEDEC is not set
+CONFIG_MTD_PHYSMAP=y
+CONFIG_MTD_PHYSMAP_START=8000000
+CONFIG_MTD_PHYSMAP_LEN=2000000
+CONFIG_MTD_PHYSMAP_BUSWIDTH=4
+
+#
+# Drivers for chip mappings
+#
+# CONFIG_MTD_MIXMEM is not set
+# CONFIG_MTD_NORA is not set
+# CONFIG_MTD_OCTAGON is not set
+# CONFIG_MTD_PNC2000 is not set
+# CONFIG_MTD_RPXLITE is not set
+# CONFIG_MTD_VMAX is not set
+
+#
+# User modules and translation layers for MTD devices
+#
+CONFIG_MTD_CHAR=y
+# CONFIG_MTD_BLOCK is not set
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_BLK_DEV_INITRD is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+# CONFIG_BLK_DEV_MD is not set
+# CONFIG_MD_LINEAR is not set
+# CONFIG_MD_RAID0 is not set
+# CONFIG_MD_RAID1 is not set
+# CONFIG_MD_RAID5 is not set
+# CONFIG_BLK_DEV_LVM is not set
+
+#
+# Networking options
+#
+# CONFIG_PACKET is not set
+# CONFIG_NETLINK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_FILTER is not set
+# CONFIG_UNIX is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_INET_ECN is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_IPV6 is not set
+# CONFIG_KHTTPD is not set
+# CONFIG_ATM is not set
+
+#
+#
+#
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+# CONFIG_PHONE_IXJ is not set
+
+#
+# ATA/IDE/MFM/RLL support
+#
+CONFIG_IDE=y
+
+#
+# IDE, ATA and ATAPI Block devices
+#
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_HD_IDE is not set
+# CONFIG_BLK_DEV_HD is not set
+CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
+# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
+# CONFIG_BLK_DEV_IDEDISK_IBM is not set
+# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
+# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
+# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
+# CONFIG_BLK_DEV_IDEDISK_WD is not set
+# CONFIG_BLK_DEV_COMMERIAL is not set
+# CONFIG_BLK_DEV_TIVO is not set
+# CONFIG_BLK_DEV_IDECS is not set
+# CONFIG_BLK_DEV_IDECD is not set
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_BLK_DEV_IDESCSI is not set
+
+#
+# IDE chipset support/bugfixes
+#
+# CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
+# CONFIG_BLK_DEV_ISAPNP is not set
+# CONFIG_BLK_DEV_RZ1000 is not set
+CONFIG_BLK_DEV_IDEPCI=y
+CONFIG_IDEPCI_SHARE_IRQ=y
+CONFIG_BLK_DEV_IDEDMA_PCI=y
+# CONFIG_BLK_DEV_OFFBOARD is not set
+CONFIG_IDEDMA_PCI_AUTO=y
+CONFIG_BLK_DEV_IDEDMA=y
+# CONFIG_IDEDMA_PCI_WIP is not set
+# CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
+# CONFIG_BLK_DEV_AEC62XX is not set
+# CONFIG_AEC62XX_TUNING is not set
+# CONFIG_BLK_DEV_ALI15X3 is not set
+# CONFIG_WDC_ALI15X3 is not set
+# CONFIG_BLK_DEV_AMD7409 is not set
+# CONFIG_AMD7409_OVERRIDE is not set
+# CONFIG_BLK_DEV_CMD64X is not set
+# CONFIG_BLK_DEV_CY82C693 is not set
+# CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_HPT34X is not set
+# CONFIG_HPT34X_AUTODMA is not set
+# CONFIG_BLK_DEV_HPT366 is not set
+CONFIG_BLK_DEV_IT8172=y
+CONFIG_IT8172_TUNING=y
+# CONFIG_BLK_DEV_NS87415 is not set
+# CONFIG_BLK_DEV_OPTI621 is not set
+# CONFIG_BLK_DEV_PDC202XX is not set
+# CONFIG_PDC202XX_BURST is not set
+# CONFIG_BLK_DEV_OSB4 is not set
+# CONFIG_BLK_DEV_SIS5513 is not set
+# CONFIG_BLK_DEV_SLC90E66 is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+# CONFIG_BLK_DEV_VIA82CXXX is not set
+CONFIG_IDE_CHIPSETS=y
+
+#
+# Note: most of these also require special kernel boot parameters
+#
+# CONFIG_BLK_DEV_4DRIVES is not set
+# CONFIG_BLK_DEV_ALI14XX is not set
+# CONFIG_BLK_DEV_DTC2278 is not set
+# CONFIG_BLK_DEV_HT6560B is not set
+# CONFIG_BLK_DEV_PDC4030 is not set
+# CONFIG_BLK_DEV_QD6580 is not set
+# CONFIG_BLK_DEV_UMC8672 is not set
+CONFIG_IDEDMA_AUTO=y
+# CONFIG_IDEDMA_IVB is not set
+# CONFIG_DMA_NONPCI is not set
+CONFIG_BLK_DEV_IDE_MODES=y
+
+#
+# SCSI support
+#
+# CONFIG_SCSI is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+# CONFIG_I2O_PCI is not set
+# CONFIG_I2O_BLOCK is not set
+# CONFIG_I2O_LAN is not set
+# CONFIG_I2O_SCSI is not set
+# CONFIG_I2O_PROC is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_NET_SB1000 is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_LANCE is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_AT1700 is not set
+# CONFIG_DEPCA is not set
+# CONFIG_HP100 is not set
+# CONFIG_NET_ISA is not set
+CONFIG_NET_PCI=y
+# CONFIG_PCNET32 is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_APRICOT is not set
+# CONFIG_CS89x0 is not set
+CONFIG_TULIP=y
+# CONFIG_DE4X5 is not set
+# CONFIG_DGRS is not set
+# CONFIG_DM9102 is not set
+# CONFIG_EEPRO100 is not set
+# CONFIG_EEPRO100_PM is not set
+# CONFIG_LNE390 is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+# CONFIG_NE3210 is not set
+# CONFIG_ES3210 is not set
+CONFIG_8139TOO=y
+# CONFIG_RTL8129 is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_TLAN is not set
+# CONFIG_VIA_RHINE is not set
+# CONFIG_WINBOND_840 is not set
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_LAN_SAA9730 is not set
+# CONFIG_NET_POCKET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+# CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
+# CONFIG_SHAPER is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Old CD-ROM drivers (not SCSI, not IDE)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+CONFIG_SERIAL=y
+CONFIG_SERIAL_CONSOLE=y
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_UNIX98_PTYS is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+# CONFIG_MOUSE is not set
+
+#
+# Joysticks
+#
+# CONFIG_JOYSTICK is not set
+
+#
+# Input core support is needed for joysticks
+#
+# CONFIG_QIC02_TAPE is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_INTEL_RNG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# File systems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_ADFS_FS_RW is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_UMSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_RAMFS is not set
+# CONFIG_ISO9660_FS is not set
+# CONFIG_JOLIET is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_MOUNT is not set
+# CONFIG_DEVFS_DEBUG is not set
+# CONFIG_DEVPTS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX4FS_RW is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_EXT2_FS=y
+# CONFIG_SYSV_FS is not set
+# CONFIG_SYSV_FS_WRITE is not set
+# CONFIG_UDF_FS is not set
+# CONFIG_UDF_RW is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_UFS_FS_WRITE is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+CONFIG_NFS_FS=y
+# CONFIG_NFS_V3 is not set
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+# CONFIG_NFSD_V3 is not set
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+# CONFIG_SMB_FS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_SMB_NLS is not set
+# CONFIG_NLS is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
+# Input core support
+#
+# CONFIG_INPUT is not set
+
+#
+# Kernel hacking
+#
+CONFIG_CROSSCOMPILE=y
+# CONFIG_MIPS_FPE_MODULE is not set
+# CONFIG_REMOTE_DEBUG is not set
+# CONFIG_LL_DEBUG is not set
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_MIPS_UNCACHED is not set
# CONFIG_COBALT_MICRO_SERVER is not set
# CONFIG_DECSTATION is not set
# CONFIG_DDB5074 is not set
-CONFIG_ORION=y
# CONFIG_MIPS_MAGNUM_4000 is not set
# CONFIG_OLIVETTI_M700 is not set
# CONFIG_SGI_IP22 is not set
# CONFIG_SNI_RM200_PCI is not set
+# CONFIG_MCA is not set
# CONFIG_SBUS is not set
# CONFIG_ISA is not set
+# CONFIG_EISA is not set
# CONFIG_PCI is not set
#
# CONFIG_BLK_DEV_XD is not set
# CONFIG_PARIDE is not set
# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
# CONFIG_BLK_DEV_DAC960 is not set
# CONFIG_BLK_DEV_LOOP is not set
# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_LVM is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_INITRD=y
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
# CONFIG_BLK_DEV_MD is not set
# CONFIG_MD_LINEAR is not set
# CONFIG_MD_RAID0 is not set
# CONFIG_MD_RAID1 is not set
# CONFIG_MD_RAID5 is not set
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=4096
-CONFIG_BLK_DEV_INITRD=y
+# CONFIG_BLK_DEV_LVM is not set
#
# Networking options
# CONFIG_X25 is not set
# CONFIG_LAPB is not set
# CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
# CONFIG_ECONET_AUNUDP is not set
# CONFIG_ECONET_NATIVE is not set
# CONFIG_WAN_ROUTER is not set
# Joysticks
#
# CONFIG_JOYSTICK is not set
+
+#
+# Input core support is needed for joysticks
+#
# CONFIG_QIC02_TAPE is not set
#
# CONFIG_INTEL_RNG is not set
# CONFIG_NVRAM is not set
# CONFIG_RTC is not set
-
-#
-# Video For Linux
-#
-# CONFIG_VIDEO_DEV is not set
# CONFIG_DTLK is not set
# CONFIG_R3964 is not set
# CONFIG_APPLICOM is not set
# Ftape, the floppy tape device driver
#
# CONFIG_FTAPE is not set
-# CONFIG_DRM is not set
# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
#
# File systems
# CONFIG_QUOTA is not set
# CONFIG_AUTOFS_FS is not set
# CONFIG_AUTOFS4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_REISERFS_CHECK is not set
# CONFIG_ADFS_FS is not set
# CONFIG_ADFS_FS_RW is not set
# CONFIG_AFFS_FS is not set
#
# CONFIG_PARTITION_ADVANCED is not set
CONFIG_MSDOS_PARTITION=y
+# CONFIG_SMB_NLS is not set
# CONFIG_NLS is not set
#
# CONFIG_USB is not set
#
+# Input core support
+#
+# CONFIG_INPUT is not set
+
+#
# Kernel hacking
#
CONFIG_CROSSCOMPILE=y
# CONFIG_COBALT_MICRO_SERVER is not set
# CONFIG_DECSTATION is not set
# CONFIG_DDB5074 is not set
-# CONFIG_ORION is not set
# CONFIG_MIPS_MAGNUM_4000 is not set
# CONFIG_OLIVETTI_M700 is not set
# CONFIG_SGI_IP22 is not set
CONFIG_SNI_RM200_PCI=y
+# CONFIG_MCA is not set
# CONFIG_SBUS is not set
CONFIG_ARC32=y
CONFIG_PCI=y
CONFIG_ISA=y
CONFIG_PC_KEYB=y
+CONFIG_EISA=y
#
# Loadable module support
# CONFIG_BLK_DEV_XD is not set
# CONFIG_PARIDE is not set
# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
# CONFIG_BLK_DEV_DAC960 is not set
# CONFIG_BLK_DEV_LOOP is not set
# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_LVM is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_BLK_DEV_INITRD is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
# CONFIG_BLK_DEV_MD is not set
# CONFIG_MD_LINEAR is not set
# CONFIG_MD_RAID0 is not set
# CONFIG_MD_RAID1 is not set
# CONFIG_MD_RAID5 is not set
-# CONFIG_BLK_DEV_RAM is not set
-# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_BLK_DEV_LVM is not set
#
# Networking options
# CONFIG_IP_MULTICAST is not set
# CONFIG_IP_ADVANCED_ROUTER is not set
# CONFIG_IP_PNP is not set
-# CONFIG_IP_ROUTER is not set
# CONFIG_NET_IPIP is not set
# CONFIG_NET_IPGRE is not set
-# CONFIG_IP_ALIAS is not set
# CONFIG_INET_ECN is not set
# CONFIG_SYN_COOKIES is not set
# CONFIG_IPV6 is not set
# CONFIG_X25 is not set
# CONFIG_LAPB is not set
# CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
# CONFIG_NET_FASTROUTE is not set
# Joysticks
#
# CONFIG_JOYSTICK is not set
+
+#
+# Input core support is needed for joysticks
+#
# CONFIG_QIC02_TAPE is not set
#
# CONFIG_INTEL_RNG is not set
# CONFIG_NVRAM is not set
CONFIG_RTC=y
-
-#
-# Video For Linux
-#
-# CONFIG_VIDEO_DEV is not set
# CONFIG_DTLK is not set
# CONFIG_R3964 is not set
# CONFIG_APPLICOM is not set
# Ftape, the floppy tape device driver
#
# CONFIG_FTAPE is not set
-# CONFIG_DRM is not set
# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
#
# File systems
# CONFIG_QUOTA is not set
# CONFIG_AUTOFS_FS is not set
# CONFIG_AUTOFS4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_REISERFS_CHECK is not set
# CONFIG_ADFS_FS is not set
# CONFIG_ADFS_FS_RW is not set
# CONFIG_AFFS_FS is not set
# CONFIG_NCPFS_NFS_NS is not set
# CONFIG_NCPFS_OS2_NS is not set
# CONFIG_NCPFS_SMALLDOS is not set
-# CONFIG_NCPFS_MOUNT_SUBDIR is not set
-# CONFIG_NCPFS_NDS_DOMAINS is not set
# CONFIG_NCPFS_NLS is not set
# CONFIG_NCPFS_EXTRAS is not set
# CONFIG_MAC_PARTITION is not set
CONFIG_MSDOS_PARTITION=y
# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
# CONFIG_SOLARIS_X86_PARTITION is not set
# CONFIG_UNIXWARE_DISKLABEL is not set
CONFIG_SGI_PARTITION=y
# CONFIG_ULTRIX_PARTITION is not set
# CONFIG_SUN_PARTITION is not set
+# CONFIG_SMB_NLS is not set
# CONFIG_NLS is not set
#
# CONFIG_USB is not set
#
+# Input core support
+#
+# CONFIG_INPUT is not set
+
+#
# Kernel hacking
#
CONFIG_CROSSCOMPILE=y
--- /dev/null
+#
+# Copyright 2000 MontaVista Software Inc.
+# Author: MontaVista Software, Inc.
+# ppopov@mvista.com or support@mvista.com
+#
+# Makefile for the ITE 8172 (qed-4n-s01b) board, generic files.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+
+.S.s:
+ $(CPP) $(CFLAGS) $< -o $*.s
+.S.o:
+ $(CC) $(CFLAGS) -c $< -o $*.o
+
+all: it8172.o
+
+O_TARGET := it8172.o
+
+obj-y := it8172_rtc.o it8172_setup.o irq.o int-handler.o pmon_prom.o time.o lpc.o puts.o reset.o
+
+ifdef CONFIG_PCI
+obj-y += it8172_pci.o
+endif
+
+ifdef CONFIG_IT8172_CIR
+obj-y += it8172_cir.o
+endif
+
+ifdef CONFIG_REMOTE_DEBUG
+ obj-y += dbg_io.o
+endif
+
+include $(TOPDIR)/Rules.make
--- /dev/null
+
+#include <linux/config.h>
+
+#ifdef CONFIG_REMOTE_DEBUG
+
+/* --- CONFIG --- */
+
+/* we need uint32 uint8 */
+/* #include "types.h" */
+typedef unsigned char uint8;
+typedef unsigned int uint32;
+
+/* --- END OF CONFIG --- */
+
+#define UART16550_BAUD_2400 2400
+#define UART16550_BAUD_4800 4800
+#define UART16550_BAUD_9600 9600
+#define UART16550_BAUD_19200 19200
+#define UART16550_BAUD_38400 38400
+#define UART16550_BAUD_57600 57600
+#define UART16550_BAUD_115200 115200
+
+#define UART16550_PARITY_NONE 0
+#define UART16550_PARITY_ODD 0x08
+#define UART16550_PARITY_EVEN 0x18
+#define UART16550_PARITY_MARK 0x28
+#define UART16550_PARITY_SPACE 0x38
+
+#define UART16550_DATA_5BIT 0x0
+#define UART16550_DATA_6BIT 0x1
+#define UART16550_DATA_7BIT 0x2
+#define UART16550_DATA_8BIT 0x3
+
+#define UART16550_STOP_1BIT 0x0
+#define UART16550_STOP_2BIT 0x4
+
+/* ----------------------------------------------------- */
+
+/* === CONFIG === */
+
+/* [stevel] we use the IT8712 serial port for kgdb */
+#define DEBUG_BASE 0xB40003F8 /* 8712 serial port 1 base address */
+#define MAX_BAUD 115200
+
+/* === END OF CONFIG === */
+
+/* register offset */
+#define OFS_RCV_BUFFER 0
+#define OFS_TRANS_HOLD 0
+#define OFS_SEND_BUFFER 0
+#define OFS_INTR_ENABLE 1
+#define OFS_INTR_ID 2
+#define OFS_DATA_FORMAT 3
+#define OFS_LINE_CONTROL 3
+#define OFS_MODEM_CONTROL 4
+#define OFS_RS232_OUTPUT 4
+#define OFS_LINE_STATUS 5
+#define OFS_MODEM_STATUS 6
+#define OFS_RS232_INPUT 6
+#define OFS_SCRATCH_PAD 7
+
+#define OFS_DIVISOR_LSB 0
+#define OFS_DIVISOR_MSB 1
+
+
+/* memory-mapped read/write of the port */
+#define UART16550_READ(y) (*((volatile uint8*)(DEBUG_BASE + y)))
+#define UART16550_WRITE(y,z) ((*((volatile uint8*)(DEBUG_BASE + y))) = z)
+
+void debugInit(uint32 baud, uint8 data, uint8 parity, uint8 stop)
+{
+ /* disable interrupts */
+ UART16550_WRITE(OFS_INTR_ENABLE, 0);
+
+ /* set up buad rate */
+ {
+ uint32 divisor;
+
+ /* set DIAB bit */
+ UART16550_WRITE(OFS_LINE_CONTROL, 0x80);
+
+ /* set divisor */
+ divisor = MAX_BAUD / baud;
+ UART16550_WRITE(OFS_DIVISOR_LSB, divisor & 0xff);
+ UART16550_WRITE(OFS_DIVISOR_MSB, (divisor & 0xff00)>>8);
+
+ /* clear DIAB bit */
+ UART16550_WRITE(OFS_LINE_CONTROL, 0x0);
+ }
+
+ /* set data format */
+ UART16550_WRITE(OFS_DATA_FORMAT, data | parity | stop);
+}
+
+static int remoteDebugInitialized = 0;
+
+uint8 getDebugChar(void)
+{
+ if (!remoteDebugInitialized) {
+ remoteDebugInitialized = 1;
+ debugInit(UART16550_BAUD_115200,
+ UART16550_DATA_8BIT,
+ UART16550_PARITY_NONE,
+ UART16550_STOP_1BIT);
+ }
+
+ while((UART16550_READ(OFS_LINE_STATUS) & 0x1) == 0);
+ return UART16550_READ(OFS_RCV_BUFFER);
+}
+
+
+int putDebugChar(uint8 byte)
+{
+ if (!remoteDebugInitialized) {
+ remoteDebugInitialized = 1;
+ debugInit(UART16550_BAUD_115200,
+ UART16550_DATA_8BIT,
+ UART16550_PARITY_NONE,
+ UART16550_STOP_1BIT);
+ }
+
+ while ((UART16550_READ(OFS_LINE_STATUS) &0x20) == 0);
+ UART16550_WRITE(OFS_SEND_BUFFER, byte);
+ return 1;
+}
+
+#endif
--- /dev/null
+#include <asm/asm.h>
+#include <asm/mipsregs.h>
+#include <asm/regdef.h>
+#include <asm/stackframe.h>
+
+ .text
+ .set macro
+ .set noat
+ .align 5
+
+NESTED(it8172_IRQ, PT_SIZE, sp)
+ SAVE_ALL
+ CLI # Important: mark KERNEL mode !
+
+ /* We're working with 'reorder' set at this point. */
+ /*
+ * Get pending interrupts
+ */
+
+ mfc0 t0,CP0_CAUSE # get pending interrupts
+ mfc0 t1,CP0_STATUS # get enabled interrupts
+ and t0,t1 # isolate allowed ones
+
+ andi t0,0xff00 # isolate pending bits
+ beqz t0, 3f # spurious interrupt
+
+ andi a0, t0, CAUSEF_IP7
+ beq a0, zero, 1f
+ move a0, sp
+ jal mips_timer_interrupt
+ j ret_from_irq
+ nop
+
+1:
+ andi a0, t0, CAUSEF_IP2 # the only int we expect at this time
+ beq a0, zero, 3f
+ move a0,sp
+ jal it8172_hw0_irqdispatch
+
+ mfc0 t0,CP0_STATUS # disable interrupts
+ ori t0,1
+ xori t0,1
+ mtc0 t0,CP0_STATUS
+ nop
+ nop
+ nop
+
+ la a1, ret_from_irq
+ jr a1
+ nop
+
+3:
+ move a0, sp
+ jal mips_spurious_interrupt
+ nop
+ la a1, ret_from_irq
+ jr a1
+ nop
+
+END(it8172_IRQ)
+
--- /dev/null
+/*
+ *
+ * BRIEF MODULE DESCRIPTION
+ * ITE 8172G interrupt/setup routines.
+ *
+ * Copyright 2000,2001 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ * ppopov@mvista.com or support@mvista.com
+ *
+ * Part of this file was derived from Carsten Langgaard's
+ * arch/mips/mips-boards/atlas/atlas_int.c.
+ *
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel_stat.h>
+#include <linux/module.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/timex.h>
+#include <linux/malloc.h>
+#include <linux/random.h>
+#include <linux/serial_reg.h>
+
+#include <asm/bitops.h>
+#include <asm/bootinfo.h>
+#include <asm/io.h>
+#include <asm/mipsregs.h>
+#include <asm/system.h>
+#include <asm/it8172/it8172.h>
+#include <asm/it8172/it8172_int.h>
+#include <asm/it8172/it8172_dbg.h>
+
+#undef DEBUG_IRQ
+#ifdef DEBUG_IRQ
+/* note: prints function name for you */
+#define DPRINTK(fmt, args...) printk("%s: " fmt, __FUNCTION__ , ## args)
+#else
+#define DPRINTK(fmt, args...)
+#endif
+
+#ifdef CONFIG_REMOTE_DEBUG
+extern void breakpoint(void);
+#endif
+
+/* revisit */
+#define EXT_IRQ0_TO_IP 2 /* IP 2 */
+#define EXT_IRQ5_TO_IP 7 /* IP 7 */
+
+extern void set_debug_traps(void);
+extern void mips_timer_interrupt(int irq, struct pt_regs *regs);
+extern asmlinkage void it8172_IRQ(void);
+irq_cpustat_t irq_stat [NR_CPUS];
+unsigned int local_bh_count[NR_CPUS];
+unsigned int local_irq_count[NR_CPUS];
+unsigned long spurious_count = 0;
+irq_desc_t irq_desc[NR_IRQS];
+irq_desc_t *irq_desc_base=&irq_desc[0];
+
+struct it8172_intc_regs volatile *it8172_hw0_icregs
+ = (struct it8172_intc_regs volatile *)(KSEG1ADDR(IT8172_PCI_IO_BASE + IT_INTC_BASE));
+
+/* Function for careful CP0 interrupt mask access */
+static inline void modify_cp0_intmask(unsigned clr_mask, unsigned set_mask)
+{
+ unsigned long status = read_32bit_cp0_register(CP0_STATUS);
+ status &= ~((clr_mask & 0xFF) << 8);
+ status |= (set_mask & 0xFF) << 8;
+ write_32bit_cp0_register(CP0_STATUS, status);
+}
+
+static inline void mask_irq(unsigned int irq_nr)
+{
+ modify_cp0_intmask(irq_nr, 0);
+}
+
+static inline void unmask_irq(unsigned int irq_nr)
+{
+ modify_cp0_intmask(0, irq_nr);
+}
+
+void disable_irq(unsigned int irq_nr)
+{
+ unsigned long flags;
+
+ save_and_cli(flags);
+ mask_irq(irq_nr);
+ restore_flags(flags);
+}
+
+void enable_irq(unsigned int irq_nr)
+{
+ unsigned long flags;
+
+ save_and_cli(flags);
+ unmask_irq(irq_nr);
+ restore_flags(flags);
+}
+
+
+void disable_it8172_irq(unsigned int irq_nr)
+{
+ unsigned short mask;
+
+ DPRINTK("disable_it8172_irq %d\n", irq_nr);
+
+ if ( (irq_nr >= IT8172_LPC_IRQ_BASE) && (irq_nr <= IT8172_SERIRQ_15)) {
+ /* LPC interrupt */
+ DPRINTK("disable, before lpc_mask %x\n", it8172_hw0_icregs->lpc_mask);
+ it8172_hw0_icregs->lpc_mask |= (1 << (irq_nr - IT8172_LPC_IRQ_BASE));
+ DPRINTK("disable, after lpc_mask %x\n", it8172_hw0_icregs->lpc_mask);
+ }
+ else if ( (irq_nr >= IT8172_LB_IRQ_BASE) && (irq_nr <= IT8172_IOCHK_IRQ)) {
+ /* Local Bus interrupt */
+ DPRINTK("before lb_mask %x\n", it8172_hw0_icregs->lb_mask);
+ it8172_hw0_icregs->lb_mask |= (1 << (irq_nr - IT8172_LB_IRQ_BASE));
+ DPRINTK("after lb_mask %x\n", it8172_hw0_icregs->lb_mask);
+ }
+ else if ( (irq_nr >= IT8172_PCI_DEV_IRQ_BASE) && (irq_nr <= IT8172_DMA_IRQ)) {
+ /* PCI and other interrupts */
+ DPRINTK("before pci_mask %x\n", it8172_hw0_icregs->pci_mask);
+ it8172_hw0_icregs->pci_mask |= (1 << (irq_nr - IT8172_PCI_DEV_IRQ_BASE));
+ DPRINTK("after pci_mask %x\n", it8172_hw0_icregs->pci_mask);
+ }
+ else if ( (irq_nr >= IT8172_NMI_IRQ_BASE) && (irq_nr <= IT8172_POWER_NMI_IRQ)) {
+ /* NMI interrupts */
+ DPRINTK("before nmi_mask %x\n", it8172_hw0_icregs->nmi_mask);
+ it8172_hw0_icregs->nmi_mask |= (1 << (irq_nr - IT8172_NMI_IRQ_BASE));
+ DPRINTK("after nmi_mask %x\n", it8172_hw0_icregs->nmi_mask);
+ }
+ else {
+ panic("disable_it8172_irq: bad irq %d\n", irq_nr);
+ }
+}
+
+
+void enable_it8172_irq(unsigned int irq_nr)
+{
+ DPRINTK("enable_it8172_irq %d\n", irq_nr);
+ if ( (irq_nr >= IT8172_LPC_IRQ_BASE) && (irq_nr <= IT8172_SERIRQ_15)) {
+ /* LPC interrupt */
+ DPRINTK("enable, before lpc_mask %x\n", it8172_hw0_icregs->lpc_mask);
+ it8172_hw0_icregs->lpc_mask &= ~(1 << (irq_nr - IT8172_LPC_IRQ_BASE));
+ DPRINTK("enable, after lpc_mask %x\n", it8172_hw0_icregs->lpc_mask);
+ }
+ else if ( (irq_nr >= IT8172_LB_IRQ_BASE) && (irq_nr <= IT8172_IOCHK_IRQ)) {
+ /* Local Bus interrupt */
+ DPRINTK("before lb_mask %x\n", it8172_hw0_icregs->lb_mask);
+ it8172_hw0_icregs->lb_mask &= ~(1 << (irq_nr - IT8172_LB_IRQ_BASE));
+ DPRINTK("after lb_mask %x\n", it8172_hw0_icregs->lb_mask);
+ }
+ else if ( (irq_nr >= IT8172_PCI_DEV_IRQ_BASE) && (irq_nr <= IT8172_DMA_IRQ)) {
+ /* PCI and other interrupts */
+ DPRINTK("before pci_mask %x\n", it8172_hw0_icregs->pci_mask);
+ it8172_hw0_icregs->pci_mask &= ~(1 << (irq_nr - IT8172_PCI_DEV_IRQ_BASE));
+ DPRINTK("after pci_mask %x\n", it8172_hw0_icregs->pci_mask);
+ }
+ else if ( (irq_nr >= IT8172_NMI_IRQ_BASE) && (irq_nr <= IT8172_POWER_NMI_IRQ)) {
+ /* NMI interrupts */
+ DPRINTK("before nmi_mask %x\n", it8172_hw0_icregs->nmi_mask);
+ it8172_hw0_icregs->nmi_mask &= ~(1 << (irq_nr - IT8172_NMI_IRQ_BASE));
+ DPRINTK("after nmi_mask %x\n", it8172_hw0_icregs->nmi_mask);
+ }
+ else {
+ panic("enable_it8172_irq: bad irq %d\n", irq_nr);
+ }
+}
+
+static unsigned int startup_ite_irq(unsigned int irq)
+{
+ enable_it8172_irq(irq);
+ return 0;
+}
+
+#define shutdown_ite_irq disable_it8172_irq
+#define mask_and_ack_ite_irq disable_it8172_irq
+
+static void end_ite_irq(unsigned int irq)
+{
+ if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
+ enable_it8172_irq(irq);
+}
+
+static struct hw_interrupt_type it8172_irq_type = {
+ "ITE8172",
+ startup_ite_irq,
+ shutdown_ite_irq,
+ enable_it8172_irq,
+ disable_it8172_irq,
+ mask_and_ack_ite_irq,
+ end_ite_irq,
+ NULL
+};
+
+
+int get_irq_list(char *buf)
+{
+ int i, len = 0, j;
+ struct irqaction * action;
+
+ len += sprintf(buf+len, " ");
+ for (j=0; j<smp_num_cpus; j++)
+ len += sprintf(buf+len, "CPU%d ",j);
+ *(char *)(buf+len++) = '\n';
+
+ for (i = 0 ; i < NR_IRQS ; i++) {
+ action = irq_desc[i].action;
+ if ( !action || !action->handler )
+ continue;
+ len += sprintf(buf+len, "%3d: ", i);
+ len += sprintf(buf+len, "%10u ", kstat_irqs(i));
+ if ( irq_desc[i].handler )
+ len += sprintf(buf+len, " %s ", irq_desc[i].handler->typename );
+ else
+ len += sprintf(buf+len, " None ");
+ len += sprintf(buf+len, " %s",action->name);
+ for (action=action->next; action; action = action->next) {
+ len += sprintf(buf+len, ", %s", action->name);
+ }
+ len += sprintf(buf+len, "\n");
+ }
+ len += sprintf(buf+len, "BAD: %10lu\n", spurious_count);
+ return len;
+}
+
+asmlinkage void do_IRQ(int irq, struct pt_regs *regs)
+{
+ struct irqaction *action;
+ int cpu;
+
+ cpu = smp_processor_id();
+ irq_enter(cpu, irq);
+
+ kstat.irqs[cpu][irq]++;
+#if 0
+ if (irq_desc[irq].handler && irq_desc[irq].handler->ack) {
+ // printk("invoking ack handler\n");
+ irq_desc[irq].handler->ack(irq);
+ }
+#endif
+
+ action = irq_desc[irq].action;
+
+ if (action && action->handler)
+ {
+ //mask_irq(1<<irq);
+ //printk("action->handler %x\n", action->handler);
+ disable_it8172_irq(irq);
+ //if (!(action->flags & SA_INTERRUPT)) __sti(); /* reenable ints */
+ do {
+ action->handler(irq, action->dev_id, regs);
+ action = action->next;
+ } while ( action );
+ //__cli(); /* disable ints */
+ if (irq_desc[irq].handler)
+ {
+ }
+ //unmask_irq(1<<irq);
+ enable_it8172_irq(irq);
+ }
+ else
+ {
+ spurious_count++;
+ printk("Unhandled interrupt %d, cause %x, disabled\n",
+ (unsigned)irq, (unsigned)regs->cp0_cause);
+ disable_it8172_irq(irq);
+ //disable_irq(1<<irq);
+ }
+ irq_exit(cpu, irq);
+}
+
+int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
+ unsigned long irqflags, const char * devname, void *dev_id)
+{
+ struct irqaction *old, **p, *action;
+ unsigned long flags;
+
+ /*
+ * IP0 and IP1 are software interrupts. IP7 is typically the timer interrupt.
+ *
+ * The ITE QED-4N-S01B board has one single interrupt line going from
+ * the system controller to the CPU. It's connected to the CPU external
+ * irq pin 1, which is IP2. The interrupt numbers are listed in it8172_int.h;
+ * the ISA interrupts are numbered from 0 to 15, and the rest go from
+ * there.
+ */
+
+ //printk("request_irq: %d handler %x\n", irq, handler);
+ if (irq >= NR_IRQS)
+ return -EINVAL;
+
+ if (!handler)
+ {
+ /* Free */
+ for (p = &irq_desc[irq].action; (action = *p) != NULL; p = &action->next)
+ {
+ /* Found it - now free it */
+ save_flags(flags);
+ cli();
+ *p = action->next;
+ disable_it8172_irq(irq);
+ //disable_irq(1<<irq);
+ restore_flags(flags);
+ kfree(action);
+ return 0;
+ }
+ return -ENOENT;
+ }
+
+ action = (struct irqaction *)
+ kmalloc(sizeof(struct irqaction), GFP_KERNEL);
+ if (!action)
+ return -ENOMEM;
+ memset(action, 0, sizeof(struct irqaction));
+
+ save_flags(flags);
+ cli();
+
+ action->handler = handler;
+ action->flags = irqflags;
+ action->mask = 0;
+ action->name = devname;
+ action->dev_id = dev_id;
+ action->next = NULL;
+
+ p = &irq_desc[irq].action;
+
+ if ((old = *p) != NULL) {
+ /* Can't share interrupts unless both agree to */
+ if (!(old->flags & action->flags & SA_SHIRQ))
+ return -EBUSY;
+ /* add new interrupt at end of irq queue */
+ do {
+ p = &old->next;
+ old = *p;
+ } while (old);
+ }
+ *p = action;
+ enable_it8172_irq(irq);
+ restore_flags(flags);
+#if 0
+ printk("request_irq: status %x cause %x\n",
+ read_32bit_cp0_register(CP0_STATUS), read_32bit_cp0_register(CP0_CAUSE));
+#endif
+ return 0;
+}
+
+void free_irq(unsigned int irq, void *dev_id)
+{
+ request_irq(irq, NULL, 0, NULL, dev_id);
+}
+
+void enable_cpu_timer(void)
+{
+ enable_irq(1<<EXT_IRQ5_TO_IP); /* timer interrupt */
+}
+
+unsigned long probe_irq_on (void)
+{
+ return 0;
+}
+
+int probe_irq_off (unsigned long irqs)
+{
+ return 0;
+}
+
+
+void __init init_IRQ(void)
+{
+ int i;
+
+ memset(irq_desc, 0, sizeof(irq_desc));
+ set_except_vector(0, it8172_IRQ);
+
+ /* mask all interrupts */
+ it8172_hw0_icregs->lb_mask = 0xffff;
+ it8172_hw0_icregs->lpc_mask = 0xffff;
+ it8172_hw0_icregs->pci_mask = 0xffff;
+ it8172_hw0_icregs->nmi_mask = 0xffff;
+
+ /* make all interrupts level triggered */
+ it8172_hw0_icregs->lb_trigger = 0;
+ it8172_hw0_icregs->lpc_trigger = 0;
+ it8172_hw0_icregs->pci_trigger = 0;
+ it8172_hw0_icregs->nmi_trigger = 0;
+
+ /* active level setting */
+ /* uart, keyboard, and mouse are active high */
+ it8172_hw0_icregs->lpc_level = (0x10 | 0x2 | 0x1000);
+ it8172_hw0_icregs->lb_level |= 0x20;
+
+ /* keyboard and mouse are edge triggered */
+ it8172_hw0_icregs->lpc_trigger |= (0x2 | 0x1000);
+
+
+#if 0
+ // Enable this piece of code to make internal USB interrupt
+ // edge triggered.
+ it8172_hw0_icregs->pci_trigger |=
+ (1 << (IT8172_USB_IRQ - IT8172_PCI_DEV_IRQ_BASE));
+ it8172_hw0_icregs->pci_level &=
+ ~(1 << (IT8172_USB_IRQ - IT8172_PCI_DEV_IRQ_BASE));
+#endif
+
+ for (i = 0; i <= IT8172_INT_END; i++) {
+ irq_desc[i].status = IRQ_DISABLED;
+ irq_desc[i].action = 0;
+ irq_desc[i].depth = 1;
+ irq_desc[i].handler = &it8172_irq_type;
+ }
+
+ /*
+ * Enable external int line 2
+ * All ITE interrupts are masked for now.
+ */
+ enable_irq(1<<EXT_IRQ0_TO_IP);
+ //change_cp0_status(ST0_IM, IE_IRQ2);
+
+#ifdef CONFIG_REMOTE_DEBUG
+ /* If local serial I/O used for debug port, enter kgdb at once */
+ puts("Waiting for kgdb to connect...");
+ set_debug_traps();
+ breakpoint();
+#endif
+}
+
+void mips_spurious_interrupt(struct pt_regs *regs)
+{
+#if 1
+ return;
+#else
+ unsigned long status, cause;
+
+ printk("got spurious interrupt\n");
+ status = read_32bit_cp0_register(CP0_STATUS);
+ cause = read_32bit_cp0_register(CP0_CAUSE);
+ printk("status %x cause %x\n", status, cause);
+ printk("epc %x badvaddr %x \n", regs->cp0_epc, regs->cp0_badvaddr);
+// while(1);
+#endif
+}
+
+void it8172_hw0_irqdispatch(struct pt_regs *regs)
+{
+ int irq;
+ unsigned short intstatus, status;
+
+ intstatus = it8172_hw0_icregs->intstatus;
+ if (intstatus & 0x8) {
+ panic("Got NMI interrupt\n");
+ }
+ else if (intstatus & 0x4) {
+ /* PCI interrupt */
+ irq = 0;
+ status = it8172_hw0_icregs->pci_req;
+ while (!(status & 0x1)) {
+ irq++;
+ status >>= 1;
+ }
+ irq += IT8172_PCI_DEV_IRQ_BASE;
+ //printk("pci int %d\n", irq);
+ }
+ else if (intstatus & 0x1) {
+ /* Local Bus interrupt */
+ irq = 0;
+ status = it8172_hw0_icregs->lb_req;
+ while (!(status & 0x1)) {
+ irq++;
+ status >>= 1;
+ }
+ irq += IT8172_LB_IRQ_BASE;
+ //printk("lb int %d\n", irq);
+ }
+ else if (intstatus & 0x2) {
+ /* LPC interrupt */
+ /* Since some lpc interrupts are edge triggered,
+ * we could lose an interrupt this way because
+ * we acknowledge all ints at onces. Revisit.
+ */
+ status = it8172_hw0_icregs->lpc_req;
+ it8172_hw0_icregs->lpc_req = 0; /* acknowledge ints */
+ irq = 0;
+ while (!(status & 0x1)) {
+ irq++;
+ status >>= 1;
+ }
+ irq += IT8172_LPC_IRQ_BASE;
+ //printk("LPC int %d\n", irq);
+ }
+ else {
+ return;
+ }
+ do_IRQ(irq, regs);
+}
+
+void show_pending_irqs(void)
+{
+ fputs("intstatus: ");
+ put32(it8172_hw0_icregs->intstatus);
+ puts("");
+
+ fputs("pci_req: ");
+ put32(it8172_hw0_icregs->pci_req);
+ puts("");
+
+ fputs("lb_req: ");
+ put32(it8172_hw0_icregs->lb_req);
+ puts("");
+
+ fputs("lpc_req: ");
+ put32(it8172_hw0_icregs->lpc_req);
+ puts("");
+}
--- /dev/null
+/*
+ *
+ * BRIEF MODULE DESCRIPTION
+ * IT8172 Consumer IR port generic routines.
+ *
+ * Copyright 2001 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ * ppopov@mvista.com or support@mvista.com
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/config.h>
+
+#ifdef CONFIG_IT8172_CIR
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/it8172/it8172.h>
+#include <asm/it8172/it8172_cir.h>
+
+
+volatile struct it8172_cir_regs *cir_regs[NUM_CIR_PORTS] = {
+ (volatile struct it8172_cir_regs *)(KSEG1ADDR(IT8172_PCI_IO_BASE + IT_CIR0_BASE)),
+ (volatile struct it8172_cir_regs *)(KSEG1ADDR(IT8172_PCI_IO_BASE + IT_CIR1_BASE))};
+
+
+/*
+ * Initialize Consumer IR Port.
+ */
+int cir_port_init(struct cir_port *cir)
+{
+ int port = cir->port;
+ unsigned char data;
+
+ /* set baud rate */
+ cir_regs[port]->bdlr = cir->baud_rate & 0xff;
+ cir_regs[port]->bdhr = (cir->baud_rate >> 8) & 0xff;
+
+ /* set receiver control register */
+ cir_regs[port]->rcr = (CIR_SET_RDWOS(cir->rdwos) | CIR_SET_RXDCR(cir->rxdcr));
+
+ /* set carrier frequency register */
+ cir_regs[port]->cfr = (CIR_SET_CF(cir->cfq) | CIR_SET_HS(cir->hcfs));
+
+ /* set fifo threshold */
+ data = cir_regs[port]->mstcr & 0xf3;
+ data |= CIR_SET_FIFO_TL(cir->fifo_tl);
+ cir_regs[port]->mstcr = data;
+
+ clear_fifo(cir);
+ enable_receiver(cir);
+ disable_rx_demodulation(cir);
+
+ set_rx_active(cir);
+ int_enable(cir);
+ rx_int_enable(cir);
+
+ return 0;
+}
+
+
+void clear_fifo(struct cir_port *cir)
+{
+ cir_regs[cir->port]->mstcr |= CIR_FIFO_CLEAR;
+}
+
+void enable_receiver(struct cir_port *cir)
+{
+ cir_regs[cir->port]->rcr |= CIR_RXEN;
+}
+
+void disable_receiver(struct cir_port *cir)
+{
+ cir_regs[cir->port]->rcr &= ~CIR_RXEN;
+}
+
+void enable_rx_demodulation(struct cir_port *cir)
+{
+ cir_regs[cir->port]->rcr |= CIR_RXEND;
+}
+
+void disable_rx_demodulation(struct cir_port *cir)
+{
+ cir_regs[cir->port]->rcr &= ~CIR_RXEND;
+}
+
+void set_rx_active(struct cir_port *cir)
+{
+ cir_regs[cir->port]->rcr |= CIR_RXACT;
+}
+
+void int_enable(struct cir_port *cir)
+{
+ cir_regs[cir->port]->ier |= CIR_IEC;
+}
+
+void rx_int_enable(struct cir_port *cir)
+{
+ cir_regs[cir->port]->ier |= CIR_RDAIE;
+}
+
+void dump_regs(struct cir_port *cir)
+{
+ printk("mstcr %x ier %x iir %x cfr %x rcr %x tcr %x tfsr %x rfsr %x\n",
+ cir_regs[cir->port]->mstcr,
+ cir_regs[cir->port]->ier,
+ cir_regs[cir->port]->iir,
+ cir_regs[cir->port]->cfr,
+ cir_regs[cir->port]->rcr,
+ cir_regs[cir->port]->tcr,
+ cir_regs[cir->port]->tfsr,
+ cir_regs[cir->port]->rfsr);
+
+ while (cir_regs[cir->port]->iir & CIR_RDAI) {
+ printk("data %x\n", cir_regs[cir->port]->dr);
+ }
+}
+
+void dump_reg_addr(struct cir_port *cir)
+{
+ printk("dr %x mstcr %x ier %x iir %x cfr %x rcr %x tcr %x bdlr %x bdhr %x tfsr %x rfsr %x\n",
+ (unsigned)&cir_regs[cir->port]->dr,
+ (unsigned)&cir_regs[cir->port]->mstcr,
+ (unsigned)&cir_regs[cir->port]->ier,
+ (unsigned)&cir_regs[cir->port]->iir,
+ (unsigned)&cir_regs[cir->port]->cfr,
+ (unsigned)&cir_regs[cir->port]->rcr,
+ (unsigned)&cir_regs[cir->port]->tcr,
+ (unsigned)&cir_regs[cir->port]->bdlr,
+ (unsigned)&cir_regs[cir->port]->bdhr,
+ (unsigned)&cir_regs[cir->port]->tfsr,
+ (unsigned)&cir_regs[cir->port]->rfsr);
+}
+
+int cir_get_rx_count(struct cir_port *cir)
+{
+ return cir_regs[cir->port]->rfsr & CIR_RXFBC_MASK;
+}
+
+char cir_read_data(struct cir_port *cir)
+{
+ return cir_regs[cir->port]->dr;
+}
+
+char get_int_status(struct cir_port *cir)
+{
+ return cir_regs[cir->port]->iir;
+}
+#endif
--- /dev/null
+/*
+ *
+ * BRIEF MODULE DESCRIPTION
+ * IT8172 system controller specific pci support.
+ *
+ * Copyright 2000 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ * ppopov@mvista.com or support@mvista.com
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/config.h>
+
+#ifdef CONFIG_PCI
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/it8172/it8172.h>
+#include <asm/it8172/it8172_pci.h>
+
+#define PCI_ACCESS_READ 0
+#define PCI_ACCESS_WRITE 1
+
+#undef DEBUG
+#undef DEBUG_CONFIG_CYCLES
+
+static int
+it8172_pcibios_config_access(unsigned char access_type, struct pci_dev *dev,
+ unsigned char where, u32 *data)
+{
+ /*
+ * config cycles are on 4 byte boundary only
+ */
+ unsigned char bus = dev->bus->number;
+ unsigned char dev_fn = dev->devfn;
+
+#ifdef DEBUG_CONFIG_CYCLES
+ printk("it config: type %d dev %x bus %d dev_fn %x data %x\n",
+ access_type, dev, bus, dev_fn, *data);
+
+#endif
+
+ /* Setup address */
+ IT_WRITE(IT_CONFADDR, (bus << IT_BUSNUM_SHF) |
+ (dev_fn << IT_FUNCNUM_SHF) | (where & ~0x3));
+
+
+ if (access_type == PCI_ACCESS_WRITE) {
+ IT_WRITE(IT_CONFDATA, *data);
+ }
+ else {
+ IT_READ(IT_CONFDATA, *data);
+ }
+
+ /*
+ * Revisit: check for master or target abort.
+ */
+ return 0;
+
+
+}
+
+
+/*
+ * We can't address 8 and 16 bit words directly. Instead we have to
+ * read/write a 32bit word and mask/modify the data we actually want.
+ */
+static int
+it8172_pcibios_read_config_byte (struct pci_dev *dev, int where, u8 *val)
+{
+ u32 data = 0;
+
+ if (it8172_pcibios_config_access(PCI_ACCESS_READ, dev, where, &data))
+ return -1;
+
+ *val = (data >> ((where & 3) << 3)) & 0xff;
+#ifdef DEBUG
+ printk("cfg read byte: bus %d dev_fn %x where %x: val %x\n",
+ dev->bus->number, dev->devfn, where, *val);
+#endif
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+
+static int
+it8172_pcibios_read_config_word (struct pci_dev *dev, int where, u16 *val)
+{
+ u32 data = 0;
+
+ if (where & 1)
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+
+ if (it8172_pcibios_config_access(PCI_ACCESS_READ, dev, where, &data))
+ return -1;
+
+ *val = (data >> ((where & 3) << 3)) & 0xffff;
+#ifdef DEBUG
+ printk("cfg read word: bus %d dev_fn %x where %x: val %x\n",
+ dev->bus->number, dev->devfn, where, *val);
+#endif
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+it8172_pcibios_read_config_dword (struct pci_dev *dev, int where, u32 *val)
+{
+ u32 data = 0;
+
+ if (where & 3)
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+
+ if (it8172_pcibios_config_access(PCI_ACCESS_READ, dev, where, &data))
+ return -1;
+
+ *val = data;
+#ifdef DEBUG
+ printk("cfg read dword: bus %d dev_fn %x where %x: val %x\n",
+ dev->bus->number, dev->devfn, where, *val);
+#endif
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+
+static int
+it8172_pcibios_write_config_byte (struct pci_dev *dev, int where, u8 val)
+{
+ u32 data = 0;
+
+ if (it8172_pcibios_config_access(PCI_ACCESS_READ, dev, where, &data))
+ return -1;
+
+ data = (data & ~(0xff << ((where & 3) << 3))) |
+ (val << ((where & 3) << 3));
+
+ if (it8172_pcibios_config_access(PCI_ACCESS_WRITE, dev, where, &data))
+ return -1;
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+it8172_pcibios_write_config_word (struct pci_dev *dev, int where, u16 val)
+{
+ u32 data = 0;
+
+ if (where & 1)
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+
+ if (it8172_pcibios_config_access(PCI_ACCESS_READ, dev, where, &data))
+ return -1;
+
+ data = (data & ~(0xffff << ((where & 3) << 3))) |
+ (val << ((where & 3) << 3));
+
+ if (it8172_pcibios_config_access(PCI_ACCESS_WRITE, dev, where, &data))
+ return -1;
+
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+it8172_pcibios_write_config_dword(struct pci_dev *dev, int where, u32 val)
+{
+ if (where & 3)
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+
+ if (it8172_pcibios_config_access(PCI_ACCESS_WRITE, dev, where, &val))
+ return -1;
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+struct pci_ops it8172_pci_ops = {
+ it8172_pcibios_read_config_byte,
+ it8172_pcibios_read_config_word,
+ it8172_pcibios_read_config_dword,
+ it8172_pcibios_write_config_byte,
+ it8172_pcibios_write_config_word,
+ it8172_pcibios_write_config_dword
+};
+
+void __init pcibios_init(void)
+{
+
+ printk("PCI: Probing PCI hardware on host bus 0.\n");
+ pci_scan_bus(0, &it8172_pci_ops, NULL);
+}
+
+int __init
+pcibios_enable_device(struct pci_dev *dev)
+{
+ u16 cmd, old_cmd;
+ int idx;
+ struct resource *r;
+
+ pci_read_config_word(dev, PCI_COMMAND, &cmd);
+ old_cmd = cmd;
+ for(idx=0; idx<6; idx++) {
+ r = &dev->resource[idx];
+ if (!r->start && r->end) {
+ printk(KERN_ERR "PCI: Device %s not available because of resource collisions\n", dev->slot_name);
+ return -EINVAL;
+ }
+ if (r->flags & IORESOURCE_IO)
+ cmd |= PCI_COMMAND_IO;
+ if (r->flags & IORESOURCE_MEM)
+ cmd |= PCI_COMMAND_MEMORY;
+ }
+ if (dev->resource[PCI_ROM_RESOURCE].start)
+ cmd |= PCI_COMMAND_MEMORY;
+ if (cmd != old_cmd) {
+ printk("PCI: Enabling device %s (%04x -> %04x)\n", dev->slot_name, old_cmd, cmd);
+ pci_write_config_word(dev, PCI_COMMAND, cmd);
+ }
+ return 0;
+}
+
+
+void __init
+pcibios_align_resource(void *data, struct resource *res, unsigned long size)
+{
+ printk("pcibios_align_resource\n");
+}
+
+char * __init
+pcibios_setup(char *str)
+{
+ /* Nothing to do for now. */
+
+ return str;
+}
+
+void __init
+pcibios_update_resource(struct pci_dev *dev, struct resource *root,
+ struct resource *res, int resource)
+{
+ unsigned long where, size;
+ u32 reg;
+
+ where = PCI_BASE_ADDRESS_0 + (resource * 4);
+ size = res->end - res->start;
+ pci_read_config_dword(dev, where, ®);
+ reg = (reg & size) | (((u32)(res->start - root->start)) & ~size);
+ pci_write_config_dword(dev, where, reg);
+}
+
+void __init pcibios_fixup_bus(struct pci_bus *b)
+{
+ printk("pcibios_fixup_bus\n");
+}
+#endif /* CONFIG_PCI */
--- /dev/null
+/*
+ * Copyright 2000 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ * ppopov@mvista.com or support@mvista.com
+ *
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved.
+ *
+ * ########################################################################
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ *
+ * RTC routines for ITE8172 MC146818-compatible rtc chip.
+ *
+ */
+#include <asm/spinlock.h>
+#include <linux/mc146818rtc.h>
+#include <asm/it8172/it8172.h>
+
+#define IT8172_RTC_ADR_REG (IT8172_PCI_IO_BASE + IT_RTC_BASE)
+#define IT8172_RTC_DAT_REG (IT8172_RTC_ADR_REG + 1)
+
+static volatile char *rtc_adr_reg = KSEG1ADDR((volatile char *)IT8172_RTC_ADR_REG);
+static volatile char *rtc_dat_reg = KSEG1ADDR((volatile char *)IT8172_RTC_DAT_REG);
+
+unsigned char it8172_rtc_read_data(unsigned long addr)
+{
+ unsigned char retval;
+
+ *rtc_adr_reg = addr;
+ retval = *rtc_dat_reg;
+ return retval;
+}
+
+void it8172_rtc_write_data(unsigned char data, unsigned long addr)
+{
+ *rtc_adr_reg = addr;
+ *rtc_dat_reg = data;
+}
+
+static int it8172_rtc_bcd_mode(void)
+{
+ return 0;
+}
+
+struct rtc_ops it8172_rtc_ops = {
+ &it8172_rtc_read_data,
+ &it8172_rtc_write_data,
+ &it8172_rtc_bcd_mode
+};
--- /dev/null
+/*
+ *
+ * BRIEF MODULE DESCRIPTION
+ * IT8172/QED5231 board setup.
+ *
+ * Copyright 2000 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ * ppopov@mvista.com or support@mvista.com
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/console.h>
+#include <linux/mc146818rtc.h>
+#include <linux/serial_reg.h>
+
+#include <asm/cpu.h>
+#include <asm/bootinfo.h>
+#include <asm/irq.h>
+#include <asm/mipsregs.h>
+#include <asm/reboot.h>
+#include <asm/it8172/it8172.h>
+#include <asm/it8712.h>
+#ifdef CONFIG_PC_KEYB
+#include <asm/keyboard.h>
+#endif
+
+#if defined(CONFIG_SERIAL_CONSOLE) || defined(CONFIG_PROM_CONSOLE)
+extern void console_setup(char *, int *);
+char serial_console[20];
+#endif
+
+extern struct rtc_ops it8172_rtc_ops;
+extern struct resource ioport_resource;
+extern unsigned long mips_io_port_base;
+#ifdef CONFIG_BLK_DEV_IDE
+extern struct ide_ops std_ide_ops;
+extern struct ide_ops *ide_ops;
+#endif
+#ifdef CONFIG_PC_KEYB
+extern struct kbd_ops std_kbd_ops;
+int init_8712_keyboard(void);
+#endif
+
+extern int SearchIT8712(void);
+extern void InitLPCInterface(void);
+extern char * __init prom_getcmdline(void);
+extern void it8172_restart(void);
+extern void it8172_halt(void);
+extern void it8172_power_off(void);
+
+#ifdef CONFIG_IT8172_REVC
+struct {
+ struct resource ram;
+ struct resource pci_mem;
+ struct resource pci_io;
+ struct resource flash;
+ struct resource boot;
+} it8172_resources = {
+ { "RAM", 0, 0, IORESOURCE_MEM }, /* to be initted */
+ { "PCI Mem", 0x10000000, 0x13FFFFFF, IORESOURCE_MEM },
+ { "PCI I/O", 0x14000000, 0x17FFFFFF },
+ { "Flash", 0x08000000, 0x0CFFFFFF },
+ { "Boot ROM", 0x1FC00000, 0x1FFFFFFF }
+};
+#else
+struct {
+ struct resource ram;
+ struct resource pci_mem0;
+ struct resource pci_mem1;
+ struct resource pci_io;
+ struct resource pci_mem2;
+ struct resource pci_mem3;
+ struct resource flash;
+ struct resource boot;
+} it8172_resources = {
+ { "RAM", 0, 0, IORESOURCE_MEM }, /* to be initted */
+ { "PCI Mem0", 0x0C000000, 0x0FFFFFFF, IORESOURCE_MEM },
+ { "PCI Mem1", 0x10000000, 0x13FFFFFF, IORESOURCE_MEM },
+ { "PCI I/O", 0x14000000, 0x17FFFFFF },
+ { "PCI Mem2", 0x1A000000, 0x1BFFFFFF, IORESOURCE_MEM },
+ { "PCI Mem3", 0x1C000000, 0x1FBFFFFF, IORESOURCE_MEM },
+ { "Flash", 0x08000000, 0x0CFFFFFF },
+ { "Boot ROM", 0x1FC00000, 0x1FFFFFFF }
+};
+#endif
+
+
+void __init it8172_init_ram_resource(unsigned long memsize)
+{
+ it8172_resources.ram.end = memsize;
+}
+
+void __init it8172_setup(void)
+{
+#ifdef CONFIG_BLK_DEV_IT8172
+ unsigned short dsr;
+#endif
+ char *argptr;
+
+ argptr = prom_getcmdline();
+#ifdef CONFIG_SERIAL_CONSOLE
+ if ((argptr = strstr(argptr, "console=ttyS0")) == NULL) {
+ strcpy(serial_console, "ttyS0,115200");
+ console_setup(serial_console, NULL);
+ }
+#endif
+
+ rtc_ops = &it8172_rtc_ops;
+
+ _machine_restart = it8172_restart;
+ _machine_halt = it8172_halt;
+ _machine_power_off = it8172_power_off;
+
+ /*
+ * IO/MEM resources.
+ *
+ * revisit this area.
+ */
+ mips_io_port_base = KSEG1;
+ ioport_resource.start = it8172_resources.pci_io.start;
+ ioport_resource.end = it8172_resources.pci_io.end;
+#ifdef CONFIG_IT8172_REVC
+ iomem_resource.start = it8172_resources.pci_mem.start;
+ iomem_resource.end = it8172_resources.pci_mem.end;
+#else
+ iomem_resource.start = it8172_resources.pci_mem0.start;
+ iomem_resource.end = it8172_resources.pci_mem3.end;
+#endif
+
+#ifdef CONFIG_BLK_DEV_INITRD
+ ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0);
+#endif
+
+#ifdef CONFIG_BLK_DEV_IT8172
+ /*
+ * Pull IDE device out of standby mode.
+ */
+ IT_IO_READ16(IT_PM_DSR, dsr);
+ dsr &= ~IT_PM_DSR_IDESB;
+ IT_IO_WRITE16(IT_PM_DSR, dsr);
+
+ ide_ops = &std_ide_ops;
+#endif
+
+#ifdef CONFIG_FB
+ conswitchp = &dummy_con;
+#endif
+
+ InitLPCInterface();
+
+#ifdef CONFIG_MIPS_ITE8172
+ if (SearchIT8712()) {
+ printk("Found IT8712 Super IO\n");
+ // enable IT8712 serial port
+ LPCSetConfig(LDN_SERIAL1, 0x30, 0x01); /* enable */
+ LPCSetConfig(LDN_SERIAL1, 0x23, 0x01); /* clock selection */
+#ifdef CONFIG_PC_KEYB
+ if (init_8712_keyboard()) {
+ printk("Unable to initialize keyboard\n");
+ LPCSetConfig(LDN_KEYBOARD, 0x30, 0x0); /* disable keyboard */
+ }
+ else {
+ LPCSetConfig(LDN_KEYBOARD, 0x30, 0x1); /* enable keyboard */
+ LPCSetConfig(LDN_KEYBOARD, 0xf0, 0x2);
+ LPCSetConfig(LDN_KEYBOARD, 0x71, 0x3);
+
+ LPCSetConfig(LDN_MOUSE, 0x30, 0x1); /* enable mouse */
+
+ LPCSetConfig(0x4, 0x30, 0x1);
+ LPCSetConfig(0x4, 0xf4, LPCGetConfig(0x4, 0xf4) | 0x80);
+
+ if ((LPCGetConfig(LDN_KEYBOARD, 0x30) == 0) ||
+ (LPCGetConfig(LDN_MOUSE, 0x30) == 0))
+ printk("Error: keyboard or mouse not enabled\n");
+
+ kbd_ops = &std_kbd_ops;
+ }
+#endif
+ }
+ else {
+ printk("IT8712 Super IO not found\n");
+ }
+#endif
+
+#ifdef CONFIG_IT8172_CIR
+ {
+ unsigned long data;
+ //printk("Enabling CIR0\n");
+ IT_IO_READ16(IT_PM_DSR, data);
+ data &= ~IT_PM_DSR_CIR0SB;
+ IT_IO_WRITE16(IT_PM_DSR, data);
+ //printk("DSR register: %x\n", (unsigned)IT_IO_READ16(IT_PM_DSR, data));
+ }
+#endif
+#ifdef CONFIG_IT8172_SCR0
+ {
+ unsigned i;
+ /* Enable Smart Card Reader 0 */
+ /* First power it up */
+ IT_IO_READ16(IT_PM_DSR, i);
+ i &= ~IT_PM_DSR_SCR0SB;
+ IT_IO_WRITE16(IT_PM_DSR, i);
+ /* Then initialize its registers */
+ outb(( IT_SCR_SFR_GATE_UART_OFF << IT_SCR_SFR_GATE_UART_BIT
+ |IT_SCR_SFR_FET_CHARGE_213_US << IT_SCR_SFR_FET_CHARGE_BIT
+ |IT_SCR_SFR_CARD_FREQ_3_5_MHZ << IT_SCR_SFR_CARD_FREQ_BIT
+ |IT_SCR_SFR_FET_ACTIVE_INVERT << IT_SCR_SFR_FET_ACTIVE_BIT
+ |IT_SCR_SFR_ENABLE_ON << IT_SCR_SFR_ENABLE_BIT),
+ IT8172_PCI_IO_BASE + IT_SCR0_BASE + IT_SCR_SFR);
+ outb(IT_SCR_SCDR_RESET_MODE_ASYNC << IT_SCR_SCDR_RESET_MODE_BIT,
+ IT8172_PCI_IO_BASE + IT_SCR0_BASE + IT_SCR_SCDR);
+ }
+#endif /* CONFIG_IT8172_SCR0 */
+#ifdef CONFIG_IT8172_SCR1
+ {
+ unsigned i;
+ /* Enable Smart Card Reader 1 */
+ /* First power it up */
+ IT_IO_READ16(IT_PM_DSR, i);
+ i &= ~IT_PM_DSR_SCR1SB;
+ IT_IO_WRITE16(IT_PM_DSR, i);
+ /* Then initialize its registers */
+ outb(( IT_SCR_SFR_GATE_UART_OFF << IT_SCR_SFR_GATE_UART_BIT
+ |IT_SCR_SFR_FET_CHARGE_213_US << IT_SCR_SFR_FET_CHARGE_BIT
+ |IT_SCR_SFR_CARD_FREQ_3_5_MHZ << IT_SCR_SFR_CARD_FREQ_BIT
+ |IT_SCR_SFR_FET_ACTIVE_INVERT << IT_SCR_SFR_FET_ACTIVE_BIT
+ |IT_SCR_SFR_ENABLE_ON << IT_SCR_SFR_ENABLE_BIT),
+ IT8172_PCI_IO_BASE + IT_SCR1_BASE + IT_SCR_SFR);
+ outb(IT_SCR_SCDR_RESET_MODE_ASYNC << IT_SCR_SCDR_RESET_MODE_BIT,
+ IT8172_PCI_IO_BASE + IT_SCR1_BASE + IT_SCR_SCDR);
+ }
+#endif /* CONFIG_IT8172_SCR1 */
+}
+
+
+#ifdef CONFIG_PC_KEYB
+/*
+ * According to the ITE Special BIOS Note for waking up the
+ * keyboard controller...
+ */
+int init_8712_keyboard()
+{
+ unsigned int cmd_port = 0x14000064;
+ unsigned int data_port = 0x14000060;
+ unsigned char data;
+ int i;
+
+ printk("8712 keyboard init");
+
+ outb(0xaa, cmd_port); /* send self-test cmd */
+ i = 0;
+ while (!(inb(cmd_port) & 0x1)) { /* wait output buffer full */
+ i++;
+ if (i > 0xffffff)
+ return 1;
+ }
+
+ data = inb(data_port);
+ outb(0xcb, cmd_port); /* set ps2 mode */
+ while (inb(cmd_port) & 0x2) { /* wait while input buffer full */
+ i++;
+ if (i > 0xffffff)
+ return 1;
+ }
+ outb(0x01, data_port);
+ while (inb(cmd_port) & 0x2) { /* wait while input buffer full */
+ i++;
+ if (i > 0xffffff)
+ return 1;
+ }
+
+ outb(0x60, cmd_port); /* write 8042 command byte */
+ while (inb(cmd_port) & 0x2) { /* wait while input buffer full */
+ i++;
+ if (i > 0xffffff)
+ return 1;
+ }
+ outb(0x45, data_port); /* at interface, keyboard enabled, system flag */
+ while (inb(cmd_port) & 0x2) { /* wait while input buffer full */
+ i++;
+ if (i > 0xffffff)
+ return 1;
+ }
+
+ outb(0xae, cmd_port); /* enable interface */
+ return 0;
+}
+#endif
--- /dev/null
+/*
+ *
+ * BRIEF MODULE DESCRIPTION
+ * ITE Semi IT8712 Super I/O functions.
+ *
+ * Copyright 2001 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ * ppopov@mvista.com or support@mvista.com
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <asm/io.h>
+#include <asm/types.h>
+#include <asm/it8712.h>
+#include <asm/it8172/it8172.h>
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+void LPCEnterMBPnP()
+{
+ int i;
+ unsigned char key[4] = {0x87, 0x01, 0x55, 0x55};
+
+ for (i = 0; i<4; i++)
+ outb(key[i], LPC_KEY_ADDR);
+
+}
+
+void LPCExitMBPnP()
+{
+ outb(0x02, LPC_KEY_ADDR);
+ outb(0x02, LPC_DATA_ADDR);
+}
+
+void LPCSetConfig(char LdnNumber, char Index, char data)
+{
+ LPCEnterMBPnP(); // Enter IT8712 MB PnP mode
+ outb(0x07, LPC_KEY_ADDR);
+ outb(LdnNumber, LPC_DATA_ADDR);
+ outb(Index, LPC_KEY_ADDR);
+ outb(data, LPC_DATA_ADDR);
+ LPCExitMBPnP();
+}
+
+char LPCGetConfig(char LdnNumber, char Index)
+{
+ char rtn;
+
+ LPCEnterMBPnP(); // Enter IT8712 MB PnP mode
+ outb(0x07, LPC_KEY_ADDR);
+ outb(LdnNumber, LPC_DATA_ADDR);
+ outb(Index, LPC_KEY_ADDR);
+ rtn = inb(LPC_DATA_ADDR);
+ LPCExitMBPnP();
+ return rtn;
+}
+
+int SearchIT8712()
+{
+ unsigned char Id1, Id2;
+ unsigned short Id;
+
+ LPCEnterMBPnP();
+ outb(0x20, LPC_KEY_ADDR); /* chip id byte 1 */
+ Id1 = inb(LPC_DATA_ADDR);
+ outb(0x21, LPC_KEY_ADDR); /* chip id byte 2 */
+ Id2 = inb(LPC_DATA_ADDR);
+ Id = (Id1 << 8) | Id2;
+ LPCExitMBPnP();
+ if (Id == 0x8712)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+void InitLPCInterface()
+{
+ unsigned char bus, dev_fn;
+ unsigned long data;
+
+ bus = 0;
+ dev_fn = 1<<3 | 4;
+
+
+ /* pci cmd, SERR# Enable */
+ IT_WRITE(IT_CONFADDR,
+ (bus << IT_BUSNUM_SHF) |
+ (dev_fn << IT_FUNCNUM_SHF) |
+ ((0x4 / 4) << IT_REGNUM_SHF));
+ IT_READ(IT_CONFDATA, data);
+ data |= 0x0100;
+ IT_WRITE(IT_CONFADDR,
+ (bus << IT_BUSNUM_SHF) |
+ (dev_fn << IT_FUNCNUM_SHF) |
+ ((0x4 / 4) << IT_REGNUM_SHF));
+ IT_WRITE(IT_CONFDATA, data);
+
+ /* setup serial irq control register */
+ IT_WRITE(IT_CONFADDR,
+ (bus << IT_BUSNUM_SHF) |
+ (dev_fn << IT_FUNCNUM_SHF) |
+ ((0x48 / 4) << IT_REGNUM_SHF));
+ IT_READ(IT_CONFDATA, data);
+ data = (data & 0xffff00ff) | 0xc400;
+ IT_WRITE(IT_CONFADDR,
+ (bus << IT_BUSNUM_SHF) |
+ (dev_fn << IT_FUNCNUM_SHF) |
+ ((0x48 / 4) << IT_REGNUM_SHF));
+ IT_WRITE(IT_CONFDATA, data);
+
+
+ /* Enable I/O Space Subtractive Decode */
+ /* default 0x4C is 0x3f220000 */
+ IT_WRITE(IT_CONFADDR,
+ (bus << IT_BUSNUM_SHF) |
+ (dev_fn << IT_FUNCNUM_SHF) |
+ ((0x4C / 4) << IT_REGNUM_SHF));
+ IT_WRITE(IT_CONFDATA, 0x3f2200f3);
+}
--- /dev/null
+/*
+ *
+ * BRIEF MODULE DESCRIPTION
+ * PROM library initialisation code, assuming a version of
+ * pmon is the boot code.
+ *
+ * Copyright 2000 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ * ppopov@mvista.com or support@mvista.com
+ *
+ * This file was derived from Carsten Langgaard's
+ * arch/mips/mips-boards/xx files.
+ *
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/string.h>
+
+#include <asm/bootinfo.h>
+
+/* #define DEBUG_CMDLINE */
+
+char arcs_cmdline[COMMAND_LINE_SIZE];
+int prom_argc;
+char **prom_argv, **prom_envp;
+
+typedef struct
+{
+ char *name;
+/* char *val; */
+}t_env_var;
+
+
+char * __init prom_getcmdline(void)
+{
+ return &(arcs_cmdline[0]);
+}
+
+void __init prom_init_cmdline(void)
+{
+ char *cp;
+ int actr;
+
+ actr = 1; /* Always ignore argv[0] */
+
+ cp = &(arcs_cmdline[0]);
+ while(actr < prom_argc) {
+ strcpy(cp, prom_argv[actr]);
+ cp += strlen(prom_argv[actr]);
+ *cp++ = ' ';
+ actr++;
+ }
+ if (cp != &(arcs_cmdline[0])) /* get rid of trailing space */
+ --cp;
+ *cp = '\0';
+
+}
+
+
+char *prom_getenv(char *envname)
+{
+ /*
+ * Return a pointer to the given environment variable.
+ * Environment variables are stored in the form of "memsize=64".
+ */
+
+ t_env_var *env = (t_env_var *)prom_envp;
+ int i;
+
+ i = strlen(envname);
+
+ while(env->name) {
+ if(strncmp(envname, env->name, i) == 0) {
+ return(env->name + strlen(envname) + 1);
+ }
+ env++;
+ }
+ return(NULL);
+}
+
+static inline unsigned char str2hexnum(unsigned char c)
+{
+ if(c >= '0' && c <= '9')
+ return c - '0';
+ if(c >= 'a' && c <= 'f')
+ return c - 'a' + 10;
+ return 0; /* foo */
+}
+
+int __init page_is_ram(unsigned long pagenr)
+{
+ return 1;
+}
+
+void prom_free_prom_memory (void)
+{
+}
+
+unsigned long __init prom_get_memsize(void)
+{
+ char *memsize_str;
+ unsigned int memsize;
+
+ memsize_str = prom_getenv("memsize");
+ if (!memsize_str) {
+ printk("memsize unknown: setting to 32MB\n");
+ memsize = 32;
+ } else {
+#ifdef DEBUG
+ printk("prom_memsize: %s\n", memsize_str);
+#endif
+ memsize = simple_strtol(memsize_str, NULL, 0);
+ }
+ return memsize;
+}
--- /dev/null
+/*
+ *
+ * BRIEF MODULE DESCRIPTION
+ * Low level uart routines to directly access a 16550 uart.
+ *
+ * Copyright 2000,2001 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ * ppopov@mvista.com or support@mvista.com
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/types.h>
+
+#define SERIAL_BASE 0xB4011800 /* it8172 */
+#define SER_CMD 5
+#define SER_DATA 0x00
+#define TX_BUSY 0x20
+
+#define TIMEOUT 0xffff
+#undef SLOW_DOWN
+
+static const char digits[16] = "0123456789abcdef";
+static volatile unsigned char * const com1 = (unsigned char *)SERIAL_BASE;
+
+
+#ifdef SLOW_DOWN
+static inline void slow_down()
+{
+ int k;
+ for (k=0; k<10000; k++);
+}
+#else
+#define slow_down()
+#endif
+
+void
+putch(const unsigned char c)
+{
+ unsigned char ch;
+ int i = 0;
+
+ do {
+ ch = com1[SER_CMD];
+ slow_down();
+ i++;
+ if (i>TIMEOUT) {
+ break;
+ }
+ } while (0 == (ch & TX_BUSY));
+ com1[SER_DATA] = c;
+}
+
+void
+puts(unsigned char *cp)
+{
+ unsigned char ch;
+ int i = 0;
+
+ while (*cp) {
+ do {
+ ch = com1[SER_CMD];
+ slow_down();
+ i++;
+ if (i>TIMEOUT) {
+ break;
+ }
+ } while (0 == (ch & TX_BUSY));
+ com1[SER_DATA] = *cp++;
+ }
+ putch('\r');
+ putch('\n');
+}
+
+void
+fputs(unsigned char *cp)
+{
+ unsigned char ch;
+ int i = 0;
+
+ while (*cp) {
+
+ do {
+ ch = com1[SER_CMD];
+ slow_down();
+ i++;
+ if (i>TIMEOUT) {
+ break;
+ }
+ } while (0 == (ch & TX_BUSY));
+ com1[SER_DATA] = *cp++;
+ }
+}
+
+
+void
+put64(uint64_t ul)
+{
+ int cnt;
+ unsigned ch;
+
+ cnt = 16; /* 16 nibbles in a 64 bit long */
+ putch('0');
+ putch('x');
+ do {
+ cnt--;
+ ch = (unsigned char)(ul >> cnt * 4) & 0x0F;
+ putch(digits[ch]);
+ } while (cnt > 0);
+}
+
+void
+put32(unsigned u)
+{
+ int cnt;
+ unsigned ch;
+
+ cnt = 8; /* 8 nibbles in a 32 bit long */
+ putch('0');
+ putch('x');
+ do {
+ cnt--;
+ ch = (unsigned char)(u >> cnt * 4) & 0x0F;
+ putch(digits[ch]);
+ } while (cnt > 0);
+}
--- /dev/null
+/*
+ *
+ * BRIEF MODULE DESCRIPTION
+ * ITE 8172 reset routines.
+ *
+ * Copyright (C) 1997, 2001 Ralf Baechle
+ * Copyright 2001 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ * ppopov@mvista.com or support@mvista.com
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/processor.h>
+#include <asm/reboot.h>
+#include <asm/system.h>
+
+void it8172_restart(char *command)
+{
+ set_cp0_status(ST0_BEV | ST0_ERL);
+ change_cp0_config(CONF_CM_CMASK, CONF_CM_UNCACHED);
+ flush_cache_all();
+ write_32bit_cp0_register(CP0_WIRED, 0);
+ __asm__ __volatile__("jr\t%0"::"r"(0xbfc00000));
+}
+
+void it8172_halt(void)
+{
+ printk(KERN_NOTICE "\n** You can safely turn off the power\n");
+ while (1)
+ __asm__(".set\tmips3\n\t"
+ "wait\n\t"
+ ".set\tmips0");
+}
+
+void it8172_power_off(void)
+{
+ it8172_halt();
+}
--- /dev/null
+/*
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved.
+ *
+ * ########################################################################
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ *
+ * Setting up the clock on the MIPS boards.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/kernel_stat.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+
+#include <asm/mipsregs.h>
+#include <asm/ptrace.h>
+#include <asm/it8172/it8172_int.h>
+
+#include <linux/mc146818rtc.h>
+#include <linux/timex.h>
+
+extern void enable_cpu_timer(void);
+extern volatile unsigned long wall_jiffies;
+extern rwlock_t xtime_lock;
+
+unsigned long missed_heart_beats = 0;
+static long last_rtc_update = 0;
+static unsigned long r4k_offset; /* Amount to increment compare reg each time */
+static unsigned long r4k_cur; /* What counter should be at next timer irq */
+static unsigned int timer_tick_count=0;
+
+static inline void ack_r4ktimer(unsigned long newval)
+{
+ write_32bit_cp0_register(CP0_COMPARE, newval);
+}
+
+
+/*
+ * In order to set the CMOS clock precisely, set_rtc_mmss has to be
+ * called 500 ms after the second nowtime has started, because when
+ * nowtime is written into the registers of the CMOS clock, it will
+ * jump to the next second precisely 500 ms later. Check the Motorola
+ * MC146818A or Dallas DS12887 data sheet for details.
+ *
+ * BUG: This routine does not handle hour overflow properly; it just
+ * sets the minutes. Usually you won't notice until after reboot!
+ */
+static int set_rtc_mmss(unsigned long nowtime)
+{
+ int retval = 0;
+ int real_seconds, real_minutes, cmos_minutes;
+ unsigned char save_control, save_freq_select;
+
+ save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */
+ CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
+
+ save_freq_select = CMOS_READ(RTC_FREQ_SELECT); /* stop and reset prescaler */
+ CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
+
+ cmos_minutes = CMOS_READ(RTC_MINUTES);
+
+ /*
+ * since we're only adjusting minutes and seconds,
+ * don't interfere with hour overflow. This avoids
+ * messing with unknown time zones but requires your
+ * RTC not to be off by more than 15 minutes
+ */
+ real_seconds = nowtime % 60;
+ real_minutes = nowtime / 60;
+ if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1)
+ real_minutes += 30; /* correct for half hour time zone */
+ real_minutes %= 60;
+
+ if (abs(real_minutes - cmos_minutes) < 30) {
+ CMOS_WRITE(real_seconds,RTC_SECONDS);
+ CMOS_WRITE(real_minutes,RTC_MINUTES);
+ } else {
+ printk(KERN_WARNING
+ "set_rtc_mmss: can't update from %d to %d\n",
+ cmos_minutes, real_minutes);
+ retval = -1;
+ }
+
+ /* The following flags have to be released exactly in this order,
+ * otherwise the DS12887 (popular MC146818A clone with integrated
+ * battery and quartz) will not reset the oscillator and will not
+ * update precisely 500 ms later. You won't find this mentioned in
+ * the Dallas Semiconductor data sheets, but who believes data
+ * sheets anyway ... -- Markus Kuhn
+ */
+ CMOS_WRITE(save_control, RTC_CONTROL);
+ CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
+
+ return retval;
+}
+
+
+/*
+ * There are a lot of conceptually broken versions of the MIPS timer interrupt
+ * handler floating around. This one is rather different, but the algorithm
+ * is provably more robust.
+ */
+void mips_timer_interrupt(struct pt_regs *regs)
+{
+ if (r4k_offset == 0)
+ goto null;
+
+ do {
+ kstat.irqs[0][MIPS_CPU_TIMER_IRQ]++;
+ do_timer(regs);
+
+ /* Historical comment/code:
+ * RTC time of day s updated approx. every 11
+ * minutes. Because of how the numbers work out
+ * we need to make absolutely sure we do this update
+ * within 500ms before the * next second starts,
+ * thus the following code.
+ */
+ read_lock(&xtime_lock);
+ if ((time_status & STA_UNSYNC) == 0
+ && xtime.tv_sec > last_rtc_update + 660
+ && xtime.tv_usec >= 500000 - (tick >> 1)
+ && xtime.tv_usec <= 500000 + (tick >> 1))
+ if (set_rtc_mmss(xtime.tv_sec) == 0)
+ last_rtc_update = xtime.tv_sec;
+ else {
+ /* do it again in 60 s */
+ last_rtc_update = xtime.tv_sec - 600;
+ }
+ read_unlock(&xtime_lock);
+
+ r4k_cur += r4k_offset;
+ ack_r4ktimer(r4k_cur);
+
+ } while (((unsigned long)read_32bit_cp0_register(CP0_COUNT)
+ - r4k_cur) < 0x7fffffff);
+
+ return;
+
+null:
+ ack_r4ktimer(0);
+}
+
+/*
+ * Figure out the r4k offset, the amount to increment the compare
+ * register for each time tick.
+ * Use the RTC to calculate offset.
+ */
+static unsigned long __init cal_r4koff(void)
+{
+ unsigned long count;
+ unsigned int flags;
+
+ __save_and_cli(flags);
+
+ /* Start counter exactly on falling edge of update flag */
+ while (CMOS_READ(RTC_REG_A) & RTC_UIP);
+ while (!(CMOS_READ(RTC_REG_A) & RTC_UIP));
+
+ /* Start r4k counter. */
+ write_32bit_cp0_register(CP0_COUNT, 0);
+
+ /* Read counter exactly on falling edge of update flag */
+ while (CMOS_READ(RTC_REG_A) & RTC_UIP);
+ while (!(CMOS_READ(RTC_REG_A) & RTC_UIP));
+
+ count = read_32bit_cp0_register(CP0_COUNT);
+
+ /* restore interrupts */
+ __restore_flags(flags);
+
+ return (count / HZ);
+}
+
+static unsigned long __init get_mips_time(void)
+{
+ unsigned int year, mon, day, hour, min, sec;
+ unsigned char save_control;
+
+ save_control = CMOS_READ(RTC_CONTROL);
+
+ /* Freeze it. */
+ CMOS_WRITE(save_control | RTC_SET, RTC_CONTROL);
+
+ /* Read regs. */
+ sec = CMOS_READ(RTC_SECONDS);
+ min = CMOS_READ(RTC_MINUTES);
+ hour = CMOS_READ(RTC_HOURS);
+
+ if (!(save_control & RTC_24H))
+ {
+ if ((hour & 0xf) == 0xc)
+ hour &= 0x80;
+ if (hour & 0x80)
+ hour = (hour & 0xf) + 12;
+ }
+ day = CMOS_READ(RTC_DAY_OF_MONTH);
+ mon = CMOS_READ(RTC_MONTH);
+ year = CMOS_READ(RTC_YEAR);
+
+ /* Unfreeze clock. */
+ CMOS_WRITE(save_control, RTC_CONTROL);
+
+ if ((year += 1900) < 1970)
+ year += 100;
+
+ return mktime(year, mon, day, hour, min, sec);
+}
+
+void __init time_init(void)
+{
+ unsigned int est_freq, flags;
+
+ /* Set Data mode - binary. */
+ CMOS_WRITE(CMOS_READ(RTC_CONTROL) | RTC_DM_BINARY, RTC_CONTROL);
+
+ printk("calculating r4koff... ");
+ r4k_offset = cal_r4koff();
+ printk("%08lx(%d)\n", r4k_offset, (int) r4k_offset);
+
+ est_freq = 2*r4k_offset*HZ;
+ est_freq += 5000; /* round */
+ est_freq -= est_freq%10000;
+ printk("CPU frequency %d.%02d MHz\n", est_freq/1000000,
+ (est_freq%1000000)*100/1000000);
+ r4k_cur = (read_32bit_cp0_register(CP0_COUNT) + r4k_offset);
+
+ write_32bit_cp0_register(CP0_COMPARE, r4k_cur);
+
+ enable_cpu_timer();
+
+ /* Read time from the RTC chipset. */
+ write_lock_irqsave (&xtime_lock, flags);
+ xtime.tv_sec = get_mips_time();
+ xtime.tv_usec = 0;
+ write_unlock_irqrestore(&xtime_lock, flags);
+}
+
+/* This is for machines which generate the exact clock. */
+#define USECS_PER_JIFFY (1000000/HZ)
+
+/* Cycle counter value at the previous timer interrupt.. */
+
+static unsigned int timerhi = 0, timerlo = 0;
+
+/*
+ * FIXME: Does playing with the RP bit in c0_status interfere with this code?
+ */
+static unsigned long do_fast_gettimeoffset(void)
+{
+ u32 count;
+ unsigned long res, tmp;
+
+ /* Last jiffy when do_fast_gettimeoffset() was called. */
+ static unsigned long last_jiffies=0;
+ unsigned long quotient;
+
+ /*
+ * Cached "1/(clocks per usec)*2^32" value.
+ * It has to be recalculated once each jiffy.
+ */
+ static unsigned long cached_quotient=0;
+
+ tmp = jiffies;
+
+ quotient = cached_quotient;
+
+ if (tmp && last_jiffies != tmp) {
+ last_jiffies = tmp;
+ __asm__(".set\tnoreorder\n\t"
+ ".set\tnoat\n\t"
+ ".set\tmips3\n\t"
+ "lwu\t%0,%2\n\t"
+ "dsll32\t$1,%1,0\n\t"
+ "or\t$1,$1,%0\n\t"
+ "ddivu\t$0,$1,%3\n\t"
+ "mflo\t$1\n\t"
+ "dsll32\t%0,%4,0\n\t"
+ "nop\n\t"
+ "ddivu\t$0,%0,$1\n\t"
+ "mflo\t%0\n\t"
+ ".set\tmips0\n\t"
+ ".set\tat\n\t"
+ ".set\treorder"
+ :"=&r" (quotient)
+ :"r" (timerhi),
+ "m" (timerlo),
+ "r" (tmp),
+ "r" (USECS_PER_JIFFY)
+ :"$1");
+ cached_quotient = quotient;
+ }
+
+ /* Get last timer tick in absolute kernel time */
+ count = read_32bit_cp0_register(CP0_COUNT);
+
+ /* .. relative to previous jiffy (32 bits is enough) */
+ count -= timerlo;
+
+ __asm__("multu\t%1,%2\n\t"
+ "mfhi\t%0"
+ :"=r" (res)
+ :"r" (count),
+ "r" (quotient));
+
+ /*
+ * Due to possible jiffies inconsistencies, we need to check
+ * the result so that we'll get a timer that is monotonic.
+ */
+ if (res >= USECS_PER_JIFFY)
+ res = USECS_PER_JIFFY-1;
+
+ return res;
+}
+
+void do_gettimeofday(struct timeval *tv)
+{
+ unsigned int flags;
+
+ read_lock_irqsave (&xtime_lock, flags);
+ *tv = xtime;
+ tv->tv_usec += do_fast_gettimeoffset();
+
+ /*
+ * xtime is atomically updated in timer_bh. jiffies - wall_jiffies
+ * is nonzero if the timer bottom half hasnt executed yet.
+ */
+ if (jiffies - wall_jiffies)
+ tv->tv_usec += USECS_PER_JIFFY;
+
+ read_unlock_irqrestore (&xtime_lock, flags);
+
+ if (tv->tv_usec >= 1000000) {
+ tv->tv_usec -= 1000000;
+ tv->tv_sec++;
+ }
+}
+
+void do_settimeofday(struct timeval *tv)
+{
+ write_lock_irq (&xtime_lock);
+
+ /* This is revolting. We need to set the xtime.tv_usec correctly.
+ * However, the value in this location is is value at the last tick.
+ * Discover what correction gettimeofday would have done, and then
+ * undo it!
+ */
+ tv->tv_usec -= do_fast_gettimeoffset();
+
+ if (tv->tv_usec < 0) {
+ tv->tv_usec += 1000000;
+ tv->tv_sec--;
+ }
+
+ xtime = *tv;
+ time_adjust = 0; /* stop active adjtime() */
+ time_status |= STA_UNSYNC;
+ time_maxerror = NTP_PHASE_LIMIT;
+ time_esterror = NTP_PHASE_LIMIT;
+
+ write_unlock_irq (&xtime_lock);
+}
--- /dev/null
+#
+# Copyright 2000 MontaVista Software Inc.
+# Author: MontaVista Software, Inc.
+# ppopov@mvista.com or support@mvista.com
+#
+# Makefile for the ITE 8172 (qed-4n-s01b) board, board
+# specific files.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+
+.S.s:
+ $(CPP) $(CFLAGS) $< -o $*.s
+.S.o:
+ $(CC) $(CFLAGS) -c $< -o $*.o
+
+all: ite.o
+
+O_TARGET := ite.o
+
+obj-y := init.o
+
+ifdef CONFIG_PCI
+obj-y += pci_fixup.o
+endif
+
+ifdef CONFIG_BLK_DEV_INITRD
+obj-y += le_ramdisk.o
+endif
+
+
+dep:
+ $(CPP) -M *.c > .depend
+
+include $(TOPDIR)/Rules.make
--- /dev/null
+This is an ITE (www.iteusa.com) eval board for the ITE 8172G
+system controller, with a QED 5231 CPU.
--- /dev/null
+/*
+ *
+ * BRIEF MODULE DESCRIPTION
+ * IT8172/QED5231 board setup.
+ *
+ * Copyright 2000 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ * ppopov@mvista.com or support@mvista.com
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/bootmem.h>
+#include <asm/addrspace.h>
+#include <asm/bootinfo.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <asm/it8172/it8172.h>
+#include <asm/it8172/it8172_dbg.h>
+
+int prom_argc;
+char **prom_argv, **prom_envp;
+
+extern char _end;
+extern void __init prom_init_cmdline(void);
+extern unsigned long __init prom_get_memsize(void);
+extern void __init it8172_init_ram_resource(unsigned long memsize);
+
+#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
+#define PFN_ALIGN(x) (((unsigned long)(x) + (PAGE_SIZE - 1)) & PAGE_MASK)
+
+
+int __init prom_init(int argc, char **argv, char **envp, int *prom_vec)
+{
+ unsigned long mem_size, free_start, free_end, bootmap_size;
+ unsigned long pcicr;
+
+ prom_argc = argc;
+ prom_argv = argv;
+ prom_envp = envp;
+
+ puts("ITE board running...");
+
+ mips_machgroup = MACH_GROUP_ITE;
+ mips_machtype = MACH_QED_4N_S01B; /* ITE board name/number */
+
+ prom_init_cmdline();
+ mem_size = prom_get_memsize();
+
+ printk("Memory size: %dMB\n", (unsigned)mem_size);
+
+ mem_size <<= 20; /* MB */
+
+ /*
+ * make the entire physical memory visible to pci bus masters
+ */
+ IT_READ(IT_MC_PCICR, pcicr);
+ pcicr &= ~0x1f;
+ pcicr |= (mem_size - 1) >> 22;
+ IT_WRITE(IT_MC_PCICR, pcicr);
+
+ it8172_init_ram_resource(mem_size);
+ add_memory_region(0, 20 << 20, BOOT_MEM_RAM);
+
+ return 0;
+}
--- /dev/null
+/*
+ *
+ * BRIEF MODULE DESCRIPTION
+ * Board specific pci fixups.
+ *
+ * Copyright 2000 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ * ppopov@mvista.com or support@mvista.com
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/config.h>
+
+#ifdef CONFIG_PCI
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/it8172/it8172.h>
+#include <asm/it8172/it8172_pci.h>
+#include <asm/it8172/it8172_int.h>
+
+void __init board_int_line_fixup(struct pci_dev *dev)
+{
+ unsigned int slot, func;
+ unsigned char pin;
+ const int internal_func_irqs[7] = {
+ IT8172_AC97_IRQ,
+ IT8172_DMA_IRQ,
+ IT8172_CDMA_IRQ,
+ IT8172_USB_IRQ,
+ IT8172_BRIDGE_MASTER_IRQ,
+ IT8172_IDE_IRQ,
+ IT8172_MC68K_IRQ
+ };
+
+#ifdef DEBUG
+ printk("board_int_line_fixup bus %d\n", dev->bus->number);
+#endif
+ if (dev->bus->number != 0)
+ return;
+
+ pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
+
+#ifdef DEBUG
+ pci_read_config_dword(dev, PCI_SUBSYSTEM_VENDOR_ID, &vendor);
+#endif
+
+ slot = PCI_SLOT(dev->devfn);
+ func = PCI_FUNC(dev->devfn);
+
+ switch (slot) {
+ case 0x01:
+ /*
+ * Internal device 1 is actually 7 different internal
+ * devices on the IT8172G (a multi-function device).
+ */
+ if (func < 7)
+ dev->irq = internal_func_irqs[func];
+ break;
+ case 0x10:
+ switch (pin) {
+ case 1: /* pin A */
+ dev->irq = IT8172_PCI_INTA_IRQ;
+ break;
+ case 2: /* pin B */
+ dev->irq = IT8172_PCI_INTB_IRQ;
+ break;
+ case 3: /* pin C */
+ dev->irq = IT8172_PCI_INTC_IRQ;
+ break;
+ case 4: /* pin D */
+ dev->irq = IT8172_PCI_INTD_IRQ;
+ break;
+ default:
+ dev->irq = 0xff;
+ break;
+
+ }
+ break;
+ case 0x11:
+ switch (pin) {
+ case 1: /* pin A */
+ dev->irq = IT8172_PCI_INTA_IRQ;
+ break;
+ case 2: /* pin B */
+ dev->irq = IT8172_PCI_INTB_IRQ;
+ break;
+ case 3: /* pin C */
+ dev->irq = IT8172_PCI_INTC_IRQ;
+ break;
+ case 4: /* pin D */
+ dev->irq = IT8172_PCI_INTD_IRQ;
+ break;
+ default:
+ dev->irq = 0xff;
+ break;
+
+ }
+ break;
+ case 0x12:
+ switch (pin) {
+ case 1: /* pin A */
+ dev->irq = IT8172_PCI_INTB_IRQ;
+ break;
+ case 2: /* pin B */
+ dev->irq = IT8172_PCI_INTC_IRQ;
+ break;
+ case 3: /* pin C */
+ dev->irq = IT8172_PCI_INTD_IRQ;
+ break;
+ case 4: /* pin D */
+ dev->irq = IT8172_PCI_INTA_IRQ;
+ break;
+ default:
+ dev->irq = 0xff;
+ break;
+
+ }
+ break;
+ case 0x13:
+ switch (pin) {
+ case 1: /* pin A */
+ dev->irq = IT8172_PCI_INTC_IRQ;
+ break;
+ case 2: /* pin B */
+ dev->irq = IT8172_PCI_INTD_IRQ;
+ break;
+ case 3: /* pin C */
+ dev->irq = IT8172_PCI_INTA_IRQ;
+ break;
+ case 4: /* pin D */
+ dev->irq = IT8172_PCI_INTB_IRQ;
+ break;
+ default:
+ dev->irq = 0xff;
+ break;
+
+ }
+ break;
+ case 0x14:
+ switch (pin) {
+ case 1: /* pin A */
+ dev->irq = IT8172_PCI_INTD_IRQ;
+ break;
+ case 2: /* pin B */
+ dev->irq = IT8172_PCI_INTA_IRQ;
+ break;
+ case 3: /* pin C */
+ dev->irq = IT8172_PCI_INTB_IRQ;
+ break;
+ case 4: /* pin D */
+ dev->irq = IT8172_PCI_INTC_IRQ;
+ break;
+ default:
+ dev->irq = 0xff;
+ break;
+
+ }
+ break;
+ default:
+ return;
+ }
+
+#ifdef DEBUG
+ printk("irq fixup: slot %d, vendor %x, int line %d, int number %d\n",
+ slot, vendor, pin, dev->irq);
+#endif
+ pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
+
+}
+
+struct pci_fixup pcibios_fixups[] = {
+ { PCI_FIXUP_HEADER, PCI_ANY_ID, PCI_ANY_ID, board_int_line_fixup },
+ { 0 }
+};
+#endif
-# $Id: Makefile,v 1.5 1999/01/03 17:50:47 ralf Exp $
#
# Makefile for the Jazz family specific parts of the kernel
#
#
.S.s:
- $(CPP) $(CFLAGS) $< -o $*.s
+ $(CPP) $(CFLAGS) $< -o $@
.S.o:
- $(CC) $(CFLAGS) -c $< -o $*.o
+ $(CC) $(CFLAGS) -c $< -o $@
all: jazz.o
+
O_TARGET := jazz.o
-O_OBJS := int-handler.o jazzdma.o reset.o rtc-jazz.o setup.o floppy-jazz.o \
- kbd-jazz.o
-int-handler.o: int-handler.S
+obj-y := int-handler.o irq.o jazzdma.o reset.o rtc-jazz.o setup.o \
+ floppy-jazz.o kbd-jazz.o
-clean:
+int-handler.o: int-handler.S
include $(TOPDIR)/Rules.make
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (C) 1996, 1997 by Ralf Baechle
+ * Copyright (C) 1996, 97, 2000 by Ralf Baechle
*/
+#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/signal.h>
#include <asm/branch.h>
+#include <asm/cpu.h>
#include <asm/inst.h>
#include <asm/ptrace.h>
#include <asm/uaccess.h>
+#include <asm/bootinfo.h>
+#include <asm/processor.h>
/*
* Compute the return address and do emulate branch simulation, if required.
switch (insn.i_format.rt) {
case bltz_op:
case bltzl_op:
- if (regs->regs[insn.i_format.rs] < 0)
+ if ((long)regs->regs[insn.i_format.rs] < 0)
epc = epc + 4 + (insn.i_format.simmediate << 2);
else
epc += 8;
case bgez_op:
case bgezl_op:
- if (regs->regs[insn.i_format.rs] >= 0)
+ if ((long)regs->regs[insn.i_format.rs] >= 0)
epc = epc + 4 + (insn.i_format.simmediate << 2);
else
epc += 8;
case bltzal_op:
case bltzall_op:
regs->regs[31] = epc + 8;
- if (regs->regs[insn.i_format.rs] < 0)
+ if ((long)regs->regs[insn.i_format.rs] < 0)
epc = epc + 4 + (insn.i_format.simmediate << 2);
else
epc += 8;
case bgezal_op:
case bgezall_op:
regs->regs[31] = epc + 8;
- if (regs->regs[insn.i_format.rs] >= 0)
+ if ((long)regs->regs[insn.i_format.rs] >= 0)
epc = epc + 4 + (insn.i_format.simmediate << 2);
else
epc += 8;
case blez_op: /* not really i_format */
case blezl_op:
/* rt field assumed to be zero */
- if (regs->regs[insn.i_format.rs] <= 0)
+ if ((long)regs->regs[insn.i_format.rs] <= 0)
epc = epc + 4 + (insn.i_format.simmediate << 2);
else
epc += 8;
case bgtz_op:
case bgtzl_op:
/* rt field assumed to be zero */
- if (regs->regs[insn.i_format.rs] > 0)
+ if ((long)regs->regs[insn.i_format.rs] > 0)
epc = epc + 4 + (insn.i_format.simmediate << 2);
else
epc += 8;
* And now the FPA/cp1 branch instructions.
*/
case cop1_op:
+#ifdef CONFIG_MIPS_FPU_EMULATOR
+ if(!(mips_cpu.options & MIPS_CPU_FPU))
+ fcr31 = current->thread.fpu.soft.sr;
+ else
+#endif
asm ("cfc1\t%0,$31":"=r" (fcr31));
bit = (insn.i_format.rt >> 2);
bit += (bit != 0);
-/* $Id: process.c,v 1.18 2000/01/29 01:41:59 ralf Exp $
- *
+/*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (C) 1994 - 1999 by Ralf Baechle and others.
+ * Copyright (C) 1994 - 2000 by Ralf Baechle and others.
* Copyright (C) 1999 Silicon Graphics, Inc.
*/
+#include <linux/config.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/a.out.h>
#include <asm/bootinfo.h>
+#include <asm/cpu.h>
#include <asm/pgtable.h>
#include <asm/system.h>
#include <asm/mipsregs.h>
{
/* Forget lazy fpu state */
if (last_task_used_math == current) {
- set_cp0_status(ST0_CU1, ST0_CU1);
+ set_cp0_status(ST0_CU1);
__asm__ __volatile__("cfc1\t$0,$31");
last_task_used_math = NULL;
}
{
/* Forget lazy fpu state */
if (last_task_used_math == current) {
- set_cp0_status(ST0_CU1, ST0_CU1);
+ set_cp0_status(ST0_CU1);
__asm__ __volatile__("cfc1\t$0,$31");
last_task_used_math = NULL;
}
childksp = (unsigned long)p + KERNEL_STACK_SIZE - 32;
- if (last_task_used_math == current) {
- set_cp0_status(ST0_CU1, ST0_CU1);
- save_fp(p);
+ if (last_task_used_math == current)
+#ifdef CONFIG_MIPS_FPU_EMULATOR
+ if (mips_cpu.options & MIPS_CPU_FPU)
+#endif
+ {
+ set_cp0_status(ST0_CU1);
+ save_fp(p);
}
/* set up new TSS. */
childregs = (struct pt_regs *) childksp - 1;
-/* $Id: ptrace.c,v 1.17 1999/09/28 22:25:47 ralf Exp $
- *
+/*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* Copyright (C) 1992 Ross Biro
* Copyright (C) Linus Torvalds
- * Copyright (C) 1994, 1995, 1996, 1997, 1998 Ralf Baechle
+ * Copyright (C) 1994, 95, 96, 97, 98, 2000 Ralf Baechle
* Copyright (C) 1996 David S. Miller
+ * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 1999 MIPS Technologies, Inc.
*/
+#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <asm/page.h>
#include <asm/system.h>
#include <asm/uaccess.h>
+#include <asm/bootinfo.h>
+#include <asm/cpu.h>
asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
{
break;
case FPR_BASE ... FPR_BASE + 31:
if (child->used_math) {
+ unsigned long long *fregs
+ = (unsigned long long *)
+ &child->thread.fpu.hard.fp_regs[0];
+#ifdef CONFIG_MIPS_FPU_EMULATOR
+ if(!(mips_cpu.options & MIPS_CPU_FPU)) {
+ fregs = (unsigned long long *)
+ &child->thread.fpu.soft.regs[0];
+ } else
+#endif
if (last_task_used_math == child) {
enable_cp1();
save_fp(child);
disable_cp1();
last_task_used_math = NULL;
}
- tmp = child->thread.fpu.hard.fp_regs[addr - 32];
+ tmp = (unsigned long) fregs[(addr - 32)];
} else {
tmp = -1; /* FP not yet used */
}
tmp = regs->lo;
break;
case FPC_CSR:
+#ifdef CONFIG_MIPS_FPU_EMULATOR
+ if(!(mips_cpu.options & MIPS_CPU_FPU))
+ tmp = child->thread.fpu.soft.sr;
+ else
+#endif
tmp = child->thread.fpu.hard.control;
break;
case FPC_EIR: { /* implementation / version register */
regs->regs[addr] = data;
break;
case FPR_BASE ... FPR_BASE + 31: {
- unsigned int *fregs;
+ unsigned long long *fregs;
+ fregs = (unsigned long long *)&child->thread.fpu.hard.fp_regs[0];
if (child->used_math) {
- if (last_task_used_math == child) {
+ if (last_task_used_math == child)
+#ifdef CONFIG_MIPS_FPU_EMULATOR
+ if(!(mips_cpu.options & MIPS_CPU_FPU)) {
+ fregs = (unsigned long long *)
+ &child->thread.fpu.soft.regs[0];
+ } else
+#endif
+ {
enable_cp1();
save_fp(child);
disable_cp1();
sizeof(child->thread.fpu.hard));
child->thread.fpu.hard.control = 0;
}
- fregs = child->thread.fpu.hard.fp_regs;
fregs[addr - FPR_BASE] = data;
break;
}
regs->lo = data;
break;
case FPC_CSR:
+#ifdef CONFIG_MIPS_FPU_EMULATOR
+ if(!(mips_cpu.options & MIPS_CPU_FPU))
+ child->thread.fpu.soft.sr = data;
+ else
+#endif
child->thread.fpu.hard.control = data;
break;
default:
-/* $Id: r2300_fpu.S,v 1.6 1999/08/09 19:43:14 harald Exp $
- *
- * r2300_fpu.S: Save/restore floating point context for signal handlers.
- *
+/*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
.set noreorder
.set mips1
/* Save floating point context */
-LEAF(save_fp_context)
+LEAF(_save_fp_context)
li v0, 0 # assume success
cfc1 t1,fcr31
EX(swc1 $f0,(SC_FPREGS+0)(a0))
EX(swc1 $f29,(SC_FPREGS+232)(a0))
EX(swc1 $f30,(SC_FPREGS+240)(a0))
EX(swc1 $f31,(SC_FPREGS+248)(a0))
- EX(sw t1,SC_FPC_CSR(a0))
+ EX(sw t1,(SC_FPC_CSR)(a0))
cfc1 t0,$0 # implementation/version
jr ra
.set nomacro
- EX(sw t0,SC_FPC_EIR(a0))
+ EX(sw t0,(SC_FPC_EIR)(a0))
.set macro
- END(save_fp_context)
+ END(_save_fp_context)
/*
* Restore FPU state:
* frame on the current content of c0_status, not on the content of the
* stack frame which might have been changed by the user.
*/
-LEAF(restore_fp_context)
+LEAF(_restore_fp_context)
li v0, 0 # assume success
- EX(lw t0,SC_FPC_CSR(a0))
+ EX(lw t0,(SC_FPC_CSR)(a0))
EX(lwc1 $f0,(SC_FPREGS+0)(a0))
EX(lwc1 $f1,(SC_FPREGS+8)(a0))
EX(lwc1 $f2,(SC_FPREGS+16)(a0))
EX(lwc1 $f31,(SC_FPREGS+248)(a0))
jr ra
ctc1 t0,fcr31
- END(restore_fp_context)
+ END(_restore_fp_context)
.type fault@function
.ent fault
* Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
*
* Further modifications to make this work:
- * Copyright (c) 1998 Harald Koerfgen
+ * Copyright (c) 1998-2000 Harald Koerfgen
*/
#include <asm/asm.h>
#include <asm/bootinfo.h>
.align 5
/*
- * task_struct *r4xx0_resume(task_struct *prev,
- * task_struct *next)
+ * task_struct *resume(task_struct *prev,
+ * task_struct *next)
*/
LEAF(resume)
- .set reorder
mfc0 t1, CP0_STATUS
- .set noreorder
sw t1, THREAD_STATUS(a0)
CPU_SAVE_NONSCRATCH(a0)
sw ra, THREAD_REG31(a0)
and a2, a3
or a2, t1
mtc0 a2, CP0_STATUS
+ .set noreorder
jr ra
move v0, a0
+ .set reorder
END(resume)
/*
or t0, t3
mtc0 t0, CP0_STATUS
+ .set noreorder
beqz a0, 2f # Save floating point state
nor t3, zero, t3
.set reorder
lw t1, ST_OFF(a0) # last thread looses fpu
- .set noreorder
and t1, t3
sw t1, ST_OFF(a0)
- swc1 $f0, (THREAD_FPU + 0x00)(a0)
FPU_SAVE_SINGLE(a0, t1) # clobbers t1
2:
- lwc1 $f0, (THREAD_FPU + 0x00)($28)
- .set reorder
FPU_RESTORE_SINGLE($28, t0) # clobbers t0
jr ra
END(lazy_fpu_switch)
/*
* Save a thread's fp context.
*/
- .set noreorder
LEAF(save_fp)
FPU_SAVE_SINGLE(a0, t1) # clobbers t1
jr ra
- swc1 $f0, (THREAD_FPU + 0x00)(a0)
END(save_fp)
/*
+ * Restore a thread's fp context.
+ */
+LEAF(restore_fp)
+ FPU_RESTORE_SINGLE(a0, t1) # clobbers t1
+ jr ra
+ END(restore_fp)
+
+/*
* Load the FPU with signalling NANS. This bit pattern we're using has
* the property that no matter wether considered as single or as double
* precission represents signaling NANS.
mtc1 t0, $f28
mtc1 t0, $f29
mtc1 t0, $f30
+ .set noreorder
jr ra
mtc1 t0, $f31
+ .set reorder
END(init_fpu)
-/* $Id: r4k_fpu.S,v 1.8 1999/09/28 22:25:47 ralf Exp $
- *
- * r4k_fpu.S: Save/restore floating point context for signal handlers.
- *
+/*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (C) 1996, 1998 by Ralf Baechle
+ * Copyright (C) 1996, 1998, 2000 by Ralf Baechle
*
* Multi-arch abstraction and asm macros for easier reading:
* Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ *
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 2000 MIPS Technologies, Inc.
*/
#include <asm/asm.h>
#include <asm/errno.h>
#include <asm/regdef.h>
#define EX(a,b) \
-9: a,##b; \
+9: a,b; \
.section __ex_table,"a"; \
PTR 9b, fault; \
.previous
.set noreorder
.set mips3
/* Save floating point context */
-LEAF(save_fp_context)
+LEAF(_save_fp_context)
li v0, 0 # assume success
cfc1 t1,fcr31
.set nomacro
EX(sw t0,SC_FPC_EIR(a0))
.set macro
- END(save_fp_context)
+ END(_save_fp_context)
/*
* Restore FPU state:
* frame on the current content of c0_status, not on the content of the
* stack frame which might have been changed by the user.
*/
-LEAF(restore_fp_context)
+LEAF(_restore_fp_context)
li v0, 0 # assume success
EX(lw t0,SC_FPC_CSR(a0))
EX(ldc1 $f30,(SC_FPREGS+240)(a0))
jr ra
ctc1 t0,fcr31
- END(restore_fp_context)
+ END(_restore_fp_context)
.type fault@function
.ent fault
* Multi-cpu abstraction and reworking:
* Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
*/
+/**************************************************************************
+ * 14 Nov, 2000.
+ * Made support for MIPS32 CPUs.
+ *
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved.
+ *************************************************************************/
#include <asm/asm.h>
#include <asm/current.h>
#include <asm/offset.h>
sw pte, (ptr);
.set noreorder
- .set mips3
/*
* From the IDT errata for the QED RM5230 (Nevada), processor revision 1.0:
tlbwi
1:
nop
+ .set mips3
eret
+ .set mips0
#endif
nopage_tlbl:
tlbwi
1:
nop
+ .set mips3
eret
+ .set mips0
#endif
nopage_tlbs:
tlbwi
1:
nop
+ .set mips3
eret
+ .set mips0
#endif
nowrite_mod:
* Copyright (C) 1994, 1995, 1996, by Andreas Busse
* Copyright (C) 1999 Silicon Graphics, Inc.
*/
+/**************************************************************************
+ * 13 Nov, 2000.
+ * Made support for MIPS32 CPUs and restoring of fp registers.
+ *
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved.
+ *************************************************************************/
+
#include <asm/asm.h>
#include <asm/bootinfo.h>
#include <asm/cachectl.h>
#include <asm/asmmacro.h>
- .set mips3
-
/*
* task_struct *r4xx0_resume(task_struct *prev, task_struct *next)
*/
END(save_fp)
/*
+ * Restore a thread's fp context.
+ */
+LEAF(restore_fp)
+ FPU_RESTORE_DOUBLE(a0, t1) # clobbers t1
+ jr ra
+ END(restore_fp)
+
+/*
* Load the FPU with signalling NANS. This bit pattern we're using has
* the property that no matter whether considered as single or as double
* precision represents signaling NANS.
#define FPU_DEFAULT 0x00000000
LEAF(init_fpu)
+ .set mips3
mfc0 t0, CP0_STATUS
li t1, 0x20000000
or t0, t1
dmtc1 t0, $f30
.set reorder
END(init_fpu)
+
*
* Multi-arch abstraction and asm macros for easier reading:
* Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
- *
- * $Id: r6000_fpu.S,v 1.5 1999/05/01 22:40:37 ralf Exp $
*/
#include <asm/asm.h>
#include <asm/fpregdef.h>
.set noreorder
.set mips2
/* Save floating point context */
- LEAF(save_fp_context)
+ LEAF(_save_fp_context)
mfc0 t0,CP0_STATUS
sll t0,t0,2
bgez t0,1f
sw t0,SC_FPC_CSR(a0)
1: jr ra
nop
- END(save_fp_context)
+ END(_save_fp_context)
/* Restore FPU state:
* - fp gp registers
* frame on the current content of c0_status, not on the content of the
* stack frame which might have been changed by the user.
*/
- LEAF(restore_fp_context)
+ LEAF(_restore_fp_context)
mfc0 t0,CP0_STATUS
sll t0,t0,2
ctc1 t0,fcr31
1: jr ra
nop
- END(restore_fp_context)
+ END(_restore_fp_context)
{
return waking_non_zero_trylock(sem);
}
-
-/*
- * RW Semaphores
- */
-void
-__down_read(struct rw_semaphore *sem, int count)
-{
- DOWN_VAR;
-
- retry_down:
- if (count < 0) {
- /* Wait for the lock to become unbiased. Readers
- are non-exclusive. */
-
- /* This takes care of granting the lock. */
- up_read(sem);
-
- add_wait_queue(&sem->wait, &wait);
- while (atomic_read(&sem->count) < 0) {
- set_task_state(tsk, TASK_UNINTERRUPTIBLE);
- if (atomic_read(&sem->count) >= 0)
- break;
- schedule();
- }
-
- remove_wait_queue(&sem->wait, &wait);
- tsk->state = TASK_RUNNING;
-
- mb();
- count = atomic_dec_return(&sem->count);
- if (count <= 0)
- goto retry_down;
- } else {
- add_wait_queue(&sem->wait, &wait);
-
- while (1) {
- if (test_and_clear_bit(0, &sem->granted))
- break;
- set_task_state(tsk, TASK_UNINTERRUPTIBLE);
- if ((sem->granted & 1) == 0)
- schedule();
- }
-
- remove_wait_queue(&sem->wait, &wait);
- tsk->state = TASK_RUNNING;
- }
-}
-
-void
-__down_write(struct rw_semaphore *sem, int count)
-{
- DOWN_VAR;
-
- retry_down:
- if (count + RW_LOCK_BIAS < 0) {
- up_write(sem);
-
- add_wait_queue_exclusive(&sem->wait, &wait);
-
- while (atomic_read(&sem->count) < 0) {
- set_task_state(tsk, TASK_UNINTERRUPTIBLE);
- if (atomic_read(&sem->count) >= RW_LOCK_BIAS)
- break;
- schedule();
- }
-
- remove_wait_queue(&sem->wait, &wait);
- tsk->state = TASK_RUNNING;
-
- mb();
- count = atomic_sub_return(RW_LOCK_BIAS, &sem->count);
- if (count != 0)
- goto retry_down;
- } else {
- /* Put ourselves at the end of the list. */
- add_wait_queue_exclusive(&sem->write_bias_wait, &wait);
-
- while (1) {
- if (test_and_clear_bit(1, &sem->granted))
- break;
- set_task_state(tsk, TASK_UNINTERRUPTIBLE);
- if ((sem->granted & 2) == 0)
- schedule();
- }
-
- remove_wait_queue(&sem->write_bias_wait, &wait);
- tsk->state = TASK_RUNNING;
-
- /* If the lock is currently unbiased, awaken the sleepers.
- FIXME: This wakes up the readers early in a bit of a
- stampede -> bad! */
- if (atomic_read(&sem->count) >= 0)
- wake_up(&sem->wait);
- }
-}
-
-void
-__rwsem_wake(struct rw_semaphore *sem, unsigned long readers)
-{
- if (readers) {
- if (test_and_set_bit(0, &sem->granted))
- BUG();
- wake_up(&sem->wait);
- } else {
- if (test_and_set_bit(1, &sem->granted))
- BUG();
- wake_up(&sem->write_bias_wait);
- }
-}
* for more details.
*
* Copyright (C) 1995 Linus Torvalds
- * Copyright (C) 1995, 1996, 1997, 1998 Ralf Baechle
+ * Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000 Ralf Baechle
* Copyright (C) 1996 Stoned Elipot
+ * Copyright (C) 2000 Maciej W. Rozycki
*/
#include <linux/config.h>
#include <linux/errno.h>
#include <asm/asm.h>
#include <asm/bootinfo.h>
#include <asm/cachectl.h>
+#include <asm/cpu.h>
#include <asm/io.h>
#include <asm/stackframe.h>
#include <asm/system.h>
-#include <asm/cpu.h>
#ifdef CONFIG_SGI_IP22
#include <asm/sgialib.h>
#endif
#endif
}
+/* declaration of the global struct */
+struct mips_cpu mips_cpu = {PRID_IMP_UNKNOWN, CPU_UNKNOWN, 0, 0, 0,
+ {0,0,0,0}, {0,0,0,0}, {0,0,0,0}, {0,0,0,0}};
+
+/* Shortcut for assembler access to mips_cpu.options */
+int *cpuoptions = &mips_cpu.options;
+
+#define R4K_OPTS (MIPS_CPU_TLB | MIPS_CPU_4KEX | MIPS_CPU_4KTLB \
+ | MIPS_CPU_COUNTER | MIPS_CPU_CACHE_CDEX)
+
static inline void cpu_probe(void)
{
- unsigned int prid = read_32bit_cp0_register(CP0_PRID);
- switch(prid & 0xff00) {
+ unsigned long config1;
+
+ mips_cpu.processor_id = read_32bit_cp0_register(CP0_PRID);
+ switch (mips_cpu.processor_id & 0xff00) {
case PRID_IMP_R2000:
- mips_cputype = CPU_R2000;
+ mips_cpu.cputype = CPU_R2000;
+ mips_cpu.isa_level = MIPS_CPU_ISA_I;
+ mips_cpu.options = MIPS_CPU_TLB;
+ mips_cpu.tlbsize = 64;
break;
case PRID_IMP_R3000:
- if((prid & 0xff) == PRID_REV_R3000A)
- if(cpu_has_confreg())
- mips_cputype = CPU_R3081E;
+ if ((mips_cpu.processor_id & 0xff) == PRID_REV_R3000A)
+ if (cpu_has_confreg())
+ mips_cpu.cputype = CPU_R3081E;
else
- mips_cputype = CPU_R3000A;
+ mips_cpu.cputype = CPU_R3000A;
else
- mips_cputype = CPU_R3000;
+ mips_cpu.cputype = CPU_R3000;
+ mips_cpu.isa_level = MIPS_CPU_ISA_I;
+ mips_cpu.options = MIPS_CPU_TLB;
+ mips_cpu.tlbsize = 64;
break;
case PRID_IMP_R4000:
- if((prid & 0xff) == PRID_REV_R4400)
- mips_cputype = CPU_R4400SC;
+ if ((mips_cpu.processor_id & 0xff) == PRID_REV_R4400)
+ mips_cpu.cputype = CPU_R4400SC;
else
- mips_cputype = CPU_R4000SC;
+ mips_cpu.cputype = CPU_R4000SC;
+ mips_cpu.isa_level = MIPS_CPU_ISA_III;
+ mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR |
+ MIPS_CPU_WATCH | MIPS_CPU_VCE;
+ mips_cpu.tlbsize = 48;
break;
case PRID_IMP_R4600:
- mips_cputype = CPU_R4600;
+ mips_cpu.cputype = CPU_R4600;
+ mips_cpu.isa_level = MIPS_CPU_ISA_III;
+ mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU;
+ mips_cpu.tlbsize = 48;
break;
+/*
+ * This processor doesn't have an MMU, so it's not "real easy" to
+ * run Linux on it. It is left purely for documentation.
+ *
case PRID_IMP_R4650:
- mips_cputype = CPU_R4650;
+ mips_cpu.cputype = CPU_R4650;
+ mips_cpu.isa_level = MIPS_CPU_ISA_III;
+ mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU;
+ mips_cpu.tlbsize = 48;
+ break;
+ */
+ case PRID_IMP_R3912:
+ mips_cpu.cputype = CPU_R3912;
+ mips_cpu.isa_level = MIPS_CPU_ISA_I;
+ mips_cpu.options = MIPS_CPU_TLB;
+ mips_cpu.tlbsize = 32;
break;
case PRID_IMP_R4700:
- mips_cputype = CPU_R4700;
+ mips_cpu.cputype = CPU_R4700;
+ mips_cpu.isa_level = MIPS_CPU_ISA_III;
+ mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR;
+ mips_cpu.tlbsize = 48;
break;
case PRID_IMP_R5000:
- mips_cputype = CPU_R5000;
+ mips_cpu.cputype = CPU_R5000;
+ mips_cpu.isa_level = MIPS_CPU_ISA_IV;
+ mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR;
+ mips_cpu.tlbsize = 48;
+ break;
+ case PRID_IMP_R5432:
+ mips_cpu.cputype = CPU_R5432;
+ mips_cpu.isa_level = MIPS_CPU_ISA_IV;
+ mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR;
+ mips_cpu.tlbsize = 48;
break;
case PRID_IMP_NEVADA:
- mips_cputype = CPU_NEVADA;
+ mips_cpu.cputype = CPU_NEVADA;
+ mips_cpu.isa_level = MIPS_CPU_ISA_IV;
+ mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR |
+ MIPS_CPU_DIVEC;
+ mips_cpu.tlbsize = 48;
+ mips_cpu.icache.ways = 2;
+ mips_cpu.dcache.ways = 2;
break;
case PRID_IMP_R6000:
- mips_cputype = CPU_R6000;
+ mips_cpu.cputype = CPU_R6000;
+ mips_cpu.isa_level = MIPS_CPU_ISA_II;
+ mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_FPU;
+ mips_cpu.tlbsize = 32;
break;
case PRID_IMP_R6000A:
- mips_cputype = CPU_R6000A;
+ mips_cpu.cputype = CPU_R6000A;
+ mips_cpu.isa_level = MIPS_CPU_ISA_II;
+ mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_FPU;
+ mips_cpu.tlbsize = 32;
+ break;
+ case PRID_IMP_RM7000:
+ mips_cpu.cputype = CPU_RM7000;
+ mips_cpu.isa_level = MIPS_CPU_ISA_IV;
+ mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR;
break;
case PRID_IMP_R8000:
- mips_cputype = CPU_R8000;
+ mips_cpu.cputype = CPU_R8000;
+ mips_cpu.isa_level = MIPS_CPU_ISA_IV;
+ mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_4KEX |
+ MIPS_CPU_FPU | MIPS_CPU_32FPR;
+ mips_cpu.tlbsize = 384; /* has wierd TLB: 3-way x 128 */
break;
case PRID_IMP_R10000:
- mips_cputype = CPU_R10000;
+ mips_cpu.cputype = CPU_R10000;
+ mips_cpu.isa_level = MIPS_CPU_ISA_IV;
+ mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_4KEX |
+ MIPS_CPU_FPU | MIPS_CPU_32FPR |
+ MIPS_CPU_COUNTER | MIPS_CPU_WATCH;
+ mips_cpu.tlbsize = 64;
break;
- case PRID_IMP_RM7000:
- mips_cputype = CPU_R5000;
+#ifdef CONFIG_CPU_MIPS32
+ case PRID_IMP_4KC:
+ mips_cpu.cputype = CPU_4KC;
+ mips_cpu.isa_level = MIPS_CPU_ISA_M32;
+ mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_4KEX |
+ MIPS_CPU_4KTLB | MIPS_CPU_COUNTER |
+ MIPS_CPU_DIVEC | MIPS_CPU_WATCH;
+ config1 = read_mips32_cp0_config1();
+ if (config1 & (1 << 3))
+ mips_cpu.options |= MIPS_CPU_WATCH;
+ if (config1 & (1 << 2))
+ mips_cpu.options |= MIPS_CPU_MIPS16;
+ if (config1 & 1)
+ mips_cpu.options |= MIPS_CPU_FPU;
+ mips_cpu.scache.flags = MIPS_CACHE_NOT_PRESENT;
break;
+ case PRID_IMP_5KC:
+ mips_cpu.cputype = CPU_5KC;
+ mips_cpu.isa_level = MIPS_CPU_ISA_M64;
+ mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_4KEX |
+ MIPS_CPU_4KTLB | MIPS_CPU_COUNTER |
+ MIPS_CPU_DIVEC | MIPS_CPU_WATCH;
+ config1 = read_mips32_cp0_config1();
+ if (config1 & (1 << 3))
+ mips_cpu.options |= MIPS_CPU_WATCH;
+ if (config1 & (1 << 2))
+ mips_cpu.options |= MIPS_CPU_MIPS16;
+ if (config1 & 1)
+ mips_cpu.options |= MIPS_CPU_FPU;
+ mips_cpu.scache.flags = MIPS_CACHE_NOT_PRESENT;
+ break;
+#endif
default:
- mips_cputype = CPU_UNKNOWN;
+ mips_cpu.cputype = CPU_UNKNOWN;
}
}
-asmlinkage void __init init_arch(int argc, char **argv, char **envp, int *prom_vec)
+asmlinkage void __init
+init_arch(int argc, char **argv, char **envp, int *prom_vec)
{
unsigned int s;
*/
loadmmu();
- /* Disable coprocessors */
+ /* Disable coprocessors and set FPU for 16 FPRs */
s = read_32bit_cp0_register(CP0_STATUS);
- s &= ~(ST0_CU1|ST0_CU2|ST0_CU3|ST0_KX|ST0_SX);
+ s &= ~(ST0_CU1|ST0_CU2|ST0_CU3|ST0_KX|ST0_SX|ST0_FR);
s |= ST0_CU0;
write_32bit_cp0_register(CP0_STATUS, s);
- /*
- * Main should never return here, but
- * just in case, we know what happens.
- */
- for(;;)
- start_kernel();
+ start_kernel();
}
static void __init default_irq_setup(void)
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
extern asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs);
-extern asmlinkage int save_fp_context(struct sigcontext *sc);
-extern asmlinkage int restore_fp_context(struct sigcontext *sc);
+
+extern asmlinkage int (*save_fp_context)(struct sigcontext *sc);
+extern asmlinkage int (*restore_fp_context)(struct sigcontext *sc);
extern asmlinkage void syscall_trace(void);
/*
* Atomically swap in the new signal mask, and wait for a signal.
*/
-asmlinkage inline int
-sys_sigsuspend(struct pt_regs regs)
+save_static_function(sys_sigsuspend);
+static_unused int
+_sys_sigsuspend(struct pt_regs regs)
{
sigset_t *uset, saveset, newset;
- save_static(®s);
uset = (sigset_t *) regs.regs[4];
if (copy_from_user(&newset, uset, sizeof(sigset_t)))
return -EFAULT;
}
}
-asmlinkage int
-sys_rt_sigsuspend(struct pt_regs regs)
+
+save_static_function(sys_rt_sigsuspend);
+static_unused int
+_sys_rt_sigsuspend(struct pt_regs regs)
{
sigset_t *unewset, saveset, newset;
size_t sigsetsize;
- save_static(®s);
-
/* XXX Don't preclude handling different sized sigset_t's. */
sigsetsize = regs.regs[5];
if (sigsetsize != sizeof(sigset_t))
err |= __put_user(owned_fp, &sc->sc_ownedfp);
if (current->used_math) { /* fp is active. */
- set_cp0_status(ST0_CU1, ST0_CU1);
+ set_cp0_status(ST0_CU1);
err |= save_fp_context(sc);
last_task_used_math = NULL;
regs->cp0_status &= ~ST0_CU1;
* Modified for R3000 by Paul M. Antoine, 1995, 1996
* Complete output from die() by Ulf Carlsson, 1998
* Copyright (C) 1999 Silicon Graphics, Inc.
+ *
+ * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved.
*/
#include <linux/config.h>
#include <linux/init.h>
#include <linux/smp_lock.h>
#include <linux/spinlock.h>
+#include <asm/bootinfo.h>
#include <asm/branch.h>
+#include <asm/cpu.h>
#include <asm/cachectl.h>
+#include <asm/inst.h>
#include <asm/jazz.h>
#include <asm/pgtable.h>
#include <asm/io.h>
-#include <asm/bootinfo.h>
+#include <asm/siginfo.h>
#include <asm/watch.h>
#include <asm/system.h>
#include <asm/uaccess.h>
extern asmlinkage void handle_tr(void);
extern asmlinkage void handle_fpe(void);
extern asmlinkage void handle_watch(void);
+extern asmlinkage void handle_mcheck(void);
extern asmlinkage void handle_reserved(void);
+extern int fpu_emulator_cop1Handler(int, struct pt_regs *);
+
static char *cpu_names[] = CPU_NAMES;
char watch_available = 0;
char dedicated_iv_available = 0;
-char vce_available = 0;
void (*ibe_board_handler)(struct pt_regs *regs);
void (*dbe_board_handler)(struct pt_regs *regs);
*/
void do_fpe(struct pt_regs *regs, unsigned long fcr31)
{
- unsigned long pc;
- unsigned int insn;
- extern void simfp(unsigned int);
+
+#ifdef CONFIG_MIPS_FPU_EMULATOR
+ if(!(mips_cpu.options & MIPS_CPU_FPU))
+ panic("Floating Point Exception with No FPU");
+#endif
#ifdef CONFIG_MIPS_FPE_MODULE
if (fpe_handler != NULL) {
return;
}
#endif
- if (fcr31 & 0x20000) {
+
+ if (fcr31 & FPU_CSR_UNI_X) {
+#ifdef CONFIG_MIPS_FPU_EMULATOR
+ extern void save_fp(struct task_struct *);
+ extern void restore_fp(struct task_struct *);
+ int sig;
+ /*
+ * Unimplemented operation exception. If we've got the
+ * Full software emulator on-board, let's use it...
+ *
+ * Force FPU to dump state into task/thread context.
+ * We're moving a lot of data here for what is probably
+ * a single instruction, but the alternative is to
+ * pre-decode the FP register operands before invoking
+ * the emulator, which seems a bit extreme for what
+ * should be an infrequent event.
+ */
+ save_fp(current);
+
+ /* Run the emulator */
+ sig = fpu_emulator_cop1Handler(0, regs);
+
+ /*
+ * We can't allow the emulated instruction to leave the
+ * Unimplemented Operation bit set in the FCR31 fp-register.
+ */
+ current->thread.fpu.soft.sr &= ~FPU_CSR_UNI_X;
+
+ /* Restore the hardware register state */
+ restore_fp(current);
+
+ /* If something went wrong, signal */
+ if (sig)
+ force_sig(sig, current);
+#else
+ /* Else use mini-emulator */
+
+ extern void simfp(int);
+ unsigned long pc;
+ unsigned int insn;
+
/* Retry instruction with flush to zero ... */
if (!(fcr31 & (1<<24))) {
printk("Setting flush to zero for %s.\n",
current->comm);
- fcr31 &= ~0x20000;
+ fcr31 &= ~FPU_CSR_UNI_X;
fcr31 |= (1<<24);
__asm__ __volatile__(
"ctc1\t%0,$31"
return;
}
pc = regs->cp0_epc + ((regs->cp0_cause & CAUSEF_BD) ? 4 : 0);
- if (get_user(insn, (unsigned int *)pc)) {
+ if(pc & 0x80000000) insn = *(unsigned int *)pc;
+ else if (get_user(insn, (unsigned int *)pc)) {
/* XXX Can this happen? */
force_sig(SIGSEGV, current);
}
printk(KERN_DEBUG "Unimplemented exception for insn %08x at 0x%08lx in %s.\n",
insn, regs->cp0_epc, current->comm);
- simfp(insn);
+ simfp(MIPSInst(insn));
+ compute_return_epc(regs);
+#endif /* CONFIG_MIPS_FPU_EMULATOR */
+
+ return;
}
if (compute_return_epc(regs))
return;
- //force_sig(SIGFPE, current);
- printk(KERN_DEBUG "Should send SIGFPE to %s\n", current->comm);
+
+ force_sig(SIGFPE, current);
+ printk(KERN_DEBUG "Sent send SIGFPE to %s\n", current->comm);
}
static inline int get_insn_opcode(struct pt_regs *regs, unsigned int *opcode)
* (A short test says that IRIX 5.3 sends SIGTRAP for all break
* insns, even for break codes that indicate arithmetic failures.
* Weird ...)
+ * But should we continue the brokenness??? --macro
*/
- force_sig(SIGTRAP, current);
+ switch (bcode) {
+ case 6:
+ case 7:
+ if (bcode == 7)
+ info.si_code = FPE_INTDIV;
+ else
+ info.si_code = FPE_INTOVF;
+ info.si_signo = SIGFPE;
+ info.si_errno = 0;
+ info.si_addr = (void *)compute_return_epc(regs);
+ force_sig_info(SIGFPE, &info, current);
+ break;
+ default:
+ force_sig(SIGTRAP, current);
+ }
}
void do_tr(struct pt_regs *regs)
{
+ siginfo_t info;
unsigned int opcode, bcode;
if (get_insn_opcode(regs, &opcode))
* (A short test says that IRIX 5.3 sends SIGTRAP for all break
* insns, even for break codes that indicate arithmetic failures.
* Weird ...)
+ * But should we continue the brokenness??? --macro
*/
- force_sig(SIGTRAP, current);
+ switch (bcode) {
+ case 6:
+ case 7:
+ if (bcode == 7)
+ info.si_code = FPE_INTDIV;
+ else
+ info.si_code = FPE_INTOVF;
+ info.si_signo = SIGFPE;
+ info.si_errno = 0;
+ info.si_addr = (void *)compute_return_epc(regs);
+ force_sig_info(SIGFPE, &info, current);
+ break;
+ default:
+ force_sig(SIGTRAP, current);
+ }
}
#if !defined(CONFIG_CPU_HAS_LLSC)
unsigned int cpid;
extern void lazy_fpu_switch(void*);
extern void init_fpu(void);
-
+#ifdef CONFIG_MIPS_FPU_EMULATOR
+ void fpu_emulator_init_fpu(void);
+ int sig;
+#endif
cpid = (regs->cp0_cause >> CAUSEB_CE) & 3;
if (cpid != 1)
goto bad_cid;
+#ifdef CONFIG_MIPS_FPU_EMULATOR
+ if(!(mips_cpu.options & MIPS_CPU_FPU)) {
+ if (last_task_used_math != current) {
+ if(!current->used_math) {
+ fpu_emulator_init_fpu();
+ current->used_math = 1;
+ }
+ }
+ sig = fpu_emulator_cop1Handler(0, regs);
+ last_task_used_math = current;
+ if(sig) {
+ force_sig(sig, current);
+ }
+ return;
+ }
+#else
+ if(!(mips_cpu.options & MIPS_CPU_FPU)) goto bad_cid;
+#endif
+
regs->cp0_status |= ST0_CU1;
if (last_task_used_math == current)
return;
L_TARGET = lib.a
-L_OBJS = csum_partial.o csum_partial_copy.o \
- rtc-std.o rtc-no.o memcpy.o memset.o watch.o\
- strlen_user.o strncpy_user.o strnlen_user.o
+obj-y += csum_partial.o csum_partial_copy.o \
+ rtc-std.o rtc-no.o memcpy.o memset.o \
+ watch.o strlen_user.o strncpy_user.o \
+ strnlen_user.o
ifdef CONFIG_CPU_R3000
- L_OBJS += r3k_dump_tlb.o
+ obj-y += r3k_dump_tlb.o
else
- L_OBJS += dump_tlb.o
+ ifdef CONFIG_CPU_R3912
+ obj-y += r3k_dump_tlb.o
+ else
+ obj-y += dump_tlb.o
+ endif
endif
-ifdef CONFIG_BLK_DEV_FD
- L_OBJS += floppy-no.o floppy-std.o
-endif
-
-ifdef CONFIG_IDE
- L_OBJS += ide-std.o ide-no.o
-endif
-
-ifdef CONFIG_PC_KEYB
- L_OBJS += kbd-std.o kbd-no.o
-endif
+obj-$(CONFIG_BLK_DEV_FD) += floppy-no.o floppy-std.o
+obj-$(CONFIG_IDE) += ide-std.o ide-no.o
+obj-$(CONFIG_PC_KEYB) += kbd-std.o kbd-no.o
include $(TOPDIR)/Rules.make
*
* Copyright (C) 1998, 1999 by Ralf Baechle
*/
+#include <linux/config.h>
#include <linux/ioport.h>
#include <linux/sched.h>
#include <linux/pc_keyb.h>
static void std_kbd_request_region(void)
{
+#ifdef CONFIG_MIPS_ITE8172
+ printk("std_kbd_request_region\n");
+ request_region(0x14000060, 16, "keyboard");
+#else
request_region(0x60, 16, "keyboard");
+#endif
}
static int std_kbd_request_irq(void (*handler)(int, void *, struct pt_regs *))
{
+ printk("std_kbd_request_irq\n");
return request_irq(KEYBOARD_IRQ, handler, 0, "keyboard", NULL);
}
--- /dev/null
+#
+# Makefile for the Linux/MIPS kernel FPU emulation.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+
+.S.o:
+ $(CC) $(CFLAGS) -c $< -o $*.o
+
+EXTRA_ASFLAGS = -mips2 -mcpu=r4000
+
+O_TARGET:= fpu_emulator.o
+
+obj-y := cp1emu.o ieee754m.o ieee754d.o ieee754dp.o ieee754sp.o ieee754.o \
+ ieee754xcpt.o dp_frexp.o dp_modf.o dp_div.o dp_mul.o dp_sub.o \
+ dp_add.o dp_fsp.o dp_cmp.o dp_logb.o dp_scalb.o dp_simple.o \
+ dp_tint.o dp_fint.o dp_tlong.o dp_flong.o sp_frexp.o sp_modf.o \
+ sp_div.o sp_mul.o sp_sub.o sp_add.o sp_fdp.o sp_cmp.o sp_logb.o \
+ sp_scalb.o sp_simple.o sp_tint.o sp_fint.o sp_tlong.o sp_flong.o \
+ dp_sqrt.o sp_sqrt.o kernel_linkage.o
+
+include $(TOPDIR)/Rules.make
--- /dev/null
+/*
+ * cp1emu.c: a MIPS coprocessor 1 (fpu) instruction emulator
+ *
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ *
+ * A complete emulator for MIPS coprocessor 1 instructions. This is
+ * required for #float(switch) or #float(trap), where it catches all
+ * COP1 instructions via the "CoProcessor Unusable" exception.
+ *
+ * More surprisingly it is also required for #float(ieee), to help out
+ * the hardware fpu at the boundaries of the IEEE-754 representation
+ * (denormalised values, infinities, underflow, etc). It is made
+ * quite nasty because emulation of some non-COP1 instructions is
+ * required, e.g. in branch delay slots.
+ *
+ * Notes:
+ * 1) the IEEE754 library (-le) performs the actual arithmetic;
+ * 2) if you know that you won't have an fpu, then you'll get much
+ * better performance by compiling with -msoft-float! */
+
+/**************************************************************************
+ * Nov 7, 2000
+ * Massive changes to integrate with Linux kernel.
+ *
+ * Replace use of kernel data area with use of user stack
+ * for execution of instructions in branch delay slots.
+ *
+ * Replace use of static kernel variables with thread_struct elements.
+ *
+ * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved.
+ *************************************************************************/
+#include <linux/mm.h>
+#include <linux/signal.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+
+#include <asm/asm.h>
+#include <asm/branch.h>
+#include <asm/byteorder.h>
+#include <asm/inst.h>
+#include <asm/uaccess.h>
+#include <asm/processor.h>
+#include <asm/mipsregs.h>
+#include <asm/system.h>
+#include <asm/pgtable.h>
+
+#include <asm/fpu_emulator.h>
+
+#include "ieee754.h"
+
+/* Strap kernel emulator for full MIPS IV emulation */
+
+#ifdef __mips
+#undef __mips
+#endif
+#define __mips 4
+
+typedef void *vaddr_t;
+
+/* Function which emulates the instruction in a branch delay slot. */
+
+static int mips_dsemul(struct pt_regs *, mips_instruction, vaddr_t);
+
+/* Function which emulates a floating point instruction. */
+
+static int fpu_emu(struct pt_regs *, struct mips_fpu_soft_struct *,
+ mips_instruction);
+
+#if __mips >= 4 && __mips != 32
+static int fpux_emu(struct pt_regs *,
+ struct mips_fpu_soft_struct *, mips_instruction);
+#endif
+
+/* Further private data for which no space exists in mips_fpu_soft_struct */
+
+struct mips_fpu_emulator_private fpuemuprivate;
+
+/* Control registers */
+
+#define FPCREG_RID 0 /* $0 = revision id */
+#define FPCREG_CSR 31 /* $31 = csr */
+
+/* Convert Mips rounding mode (0..3) to IEEE library modes. */
+static const unsigned char ieee_rm[4] = {
+ IEEE754_RN, IEEE754_RZ, IEEE754_RU, IEEE754_RD
+};
+
+#if __mips >= 4
+/* convert condition code register number to csr bit */
+static const unsigned int fpucondbit[8] = {
+ FPU_CSR_COND0,
+ FPU_CSR_COND1,
+ FPU_CSR_COND2,
+ FPU_CSR_COND3,
+ FPU_CSR_COND4,
+ FPU_CSR_COND5,
+ FPU_CSR_COND6,
+ FPU_CSR_COND7
+};
+#endif
+
+
+
+/*
+ * Redundant with logic already in kernel/branch.c,
+ * embedded in compute_return_epc. At some point,
+ * a single subroutine should be used across both
+ * modules.
+ */
+static int isBranchInstr(mips_instruction * i)
+{
+ switch (MIPSInst_OPCODE(*i)) {
+ case spec_op:
+ switch (MIPSInst_FUNC(*i)) {
+ case jalr_op:
+ case jr_op:
+ return 1;
+ }
+ break;
+
+ case bcond_op:
+ switch (MIPSInst_RT(*i)) {
+ case bltz_op:
+ case bgez_op:
+ case bltzl_op:
+ case bgezl_op:
+ case bltzal_op:
+ case bgezal_op:
+ case bltzall_op:
+ case bgezall_op:
+ return 1;
+ }
+ break;
+
+ case j_op:
+ case jal_op:
+ case jalx_op:
+ case beq_op:
+ case bne_op:
+ case blez_op:
+ case bgtz_op:
+ case beql_op:
+ case bnel_op:
+ case blezl_op:
+ case bgtzl_op:
+ return 1;
+
+ case cop0_op:
+ case cop1_op:
+ case cop2_op:
+ case cop1x_op:
+ if (MIPSInst_RS(*i) == bc_op)
+ return 1;
+ break;
+ }
+
+ return 0;
+}
+
+#define REG_TO_VA (vaddr_t)
+#define VA_TO_REG (unsigned long)
+
+static unsigned long
+mips_get_word(struct pt_regs *xcp, void *va, int *perr)
+{
+ unsigned long temp;
+
+ if (!user_mode(xcp)) {
+ *perr = 0;
+ return (*(unsigned long *) va);
+ } else {
+ /* Use kernel get_user() macro */
+ *perr = (int) get_user(temp, (unsigned long *) va);
+ return temp;
+ }
+}
+
+static unsigned long long
+mips_get_dword(struct pt_regs *xcp, void *va, int *perr)
+{
+ unsigned long long temp;
+
+ if (!user_mode(xcp)) {
+ *perr = 0;
+ return (*(unsigned long long *) va);
+ } else {
+ /* Use kernel get_user() macro */
+ *perr = (int) get_user(temp, (unsigned long long *) va);
+ return temp;
+ }
+}
+
+static int mips_put_word(struct pt_regs *xcp, void *va, unsigned long val)
+{
+ if (!user_mode(xcp)) {
+ *(unsigned long *) va = val;
+ return 0;
+ } else {
+ /* Use kernel get_user() macro */
+ return (int) put_user(val, (unsigned long *) va);
+ }
+}
+
+static int mips_put_dword(struct pt_regs *xcp, void *va, long long val)
+{
+ if (!user_mode(xcp)) {
+ *(unsigned long long *) va = val;
+ return 0;
+ } else {
+ /* Use kernel get_user() macro */
+ return (int) put_user(val, (unsigned long long *) va);
+ }
+}
+
+
+/*
+ * In the Linux kernel, we support selection of FPR format on the
+ * basis of the Status.FR bit. This does imply that, if a full 32
+ * FPRs are desired, there needs to be a flip-flop that can be written
+ * to one at that bit position. In any case, normal MIPS ABI uses
+ * only the even FPRs (Status.FR = 0).
+ */
+
+#define CP0_STATUS_FR_SUPPORT
+
+/*
+ * Emulate the single floating point instruction pointed at by EPC.
+ * Two instructions if the instruction is in a branch delay slot.
+ */
+
+static int
+cop1Emulate(int xcptno, struct pt_regs *xcp,
+ struct mips_fpu_soft_struct *ctx)
+{
+ mips_instruction ir;
+ vaddr_t emulpc;
+ vaddr_t contpc;
+ unsigned int cond;
+ int err = 0;
+
+
+ ir = mips_get_word(xcp, REG_TO_VA xcp->cp0_epc, &err);
+ if (err) {
+ fpuemuprivate.stats.errors++;
+ return SIGBUS;
+ }
+
+ /* XXX NEC Vr54xx bug workaround */
+ if ((xcp->cp0_cause & CAUSEF_BD) && !isBranchInstr(&ir))
+ xcp->cp0_cause &= ~CAUSEF_BD;
+
+ if (xcp->cp0_cause & CAUSEF_BD) {
+ /*
+ * The instruction to be emulated is in a branch delay slot
+ * which means that we have to emulate the branch instruction
+ * BEFORE we do the cop1 instruction.
+ *
+ * This branch could be a COP1 branch, but in that case we
+ * would have had a trap for that instruction, and would not
+ * come through this route.
+ *
+ * Linux MIPS branch emulator operates on context, updating the
+ * cp0_epc.
+ */
+ emulpc = REG_TO_VA(xcp->cp0_epc + 4); /* Snapshot emulation target */
+
+ if (__compute_return_epc(xcp)) {
+#ifdef CP1DBG
+ printk("failed to emulate branch at %p\n",
+ REG_TO_VA(xcp->cp0_epc));
+#endif
+ return SIGILL;;
+ }
+ ir = mips_get_word(xcp, emulpc, &err);
+ if (err) {
+ fpuemuprivate.stats.errors++;
+ return SIGBUS;
+ }
+ contpc = REG_TO_VA xcp->cp0_epc;
+ } else {
+ emulpc = REG_TO_VA xcp->cp0_epc;
+ contpc = REG_TO_VA xcp->cp0_epc + 4;
+ }
+
+ emul:
+ fpuemuprivate.stats.emulated++;
+ switch (MIPSInst_OPCODE(ir)) {
+#ifdef CP0_STATUS_FR_SUPPORT
+ /* R4000+ 64-bit fpu registers */
+#ifndef SINGLE_ONLY_FPU
+ case ldc1_op:
+ {
+ void *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)])
+ + MIPSInst_SIMM(ir);
+ int ft = MIPSInst_RT(ir);
+ if (!(xcp->cp0_status & ST0_FR))
+ ft &= ~1;
+ ctx->regs[ft] = mips_get_dword(xcp, va, &err);
+ fpuemuprivate.stats.loads++;
+ if (err) {
+ fpuemuprivate.stats.errors++;
+ return SIGBUS;
+ }
+ }
+ break;
+
+ case sdc1_op:
+ {
+ void *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)])
+ + MIPSInst_SIMM(ir);
+ int ft = MIPSInst_RT(ir);
+ if (!(xcp->cp0_status & ST0_FR))
+ ft &= ~1;
+ fpuemuprivate.stats.stores++;
+ if (mips_put_dword(xcp, va, ctx->regs[ft])) {
+ fpuemuprivate.stats.errors++;
+ return SIGBUS;
+ }
+ }
+ break;
+#endif
+
+ case lwc1_op:
+ {
+ void *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)])
+ + MIPSInst_SIMM(ir);
+ fpureg_t val;
+ int ft = MIPSInst_RT(ir);
+ fpuemuprivate.stats.loads++;
+ val = mips_get_word(xcp, va, &err);
+ if (err) {
+ fpuemuprivate.stats.errors++;
+ return SIGBUS;
+ }
+ if (xcp->cp0_status & ST0_FR) {
+ /* load whole register */
+ ctx->regs[ft] = val;
+ } else if (ft & 1) {
+ /* load to m.s. 32 bits */
+#ifdef SINGLE_ONLY_FPU
+ /* illegal register in single-float mode */
+ return SIGILL;
+#else
+ ctx->regs[(ft & ~1)] &= 0xffffffff;
+ ctx->regs[(ft & ~1)] |= val << 32;
+#endif
+ } else {
+ /* load to l.s. 32 bits */
+ ctx->regs[ft] &= ~0xffffffffLL;
+ ctx->regs[ft] |= val;
+ }
+ }
+ break;
+
+ case swc1_op:
+ {
+ void *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)])
+ + MIPSInst_SIMM(ir);
+ unsigned int val;
+ int ft = MIPSInst_RT(ir);
+ fpuemuprivate.stats.stores++;
+ if (xcp->cp0_status & ST0_FR) {
+ /* store whole register */
+ val = ctx->regs[ft];
+ } else if (ft & 1) {
+#ifdef SINGLE_ONLY_FPU
+ /* illegal register in single-float mode */
+ return SIGILL;
+#else
+ /* store from m.s. 32 bits */
+ val = ctx->regs[(ft & ~1)] >> 32;
+#endif
+ } else {
+ /* store from l.s. 32 bits */
+ val = ctx->regs[ft];
+ }
+ if (mips_put_word(xcp, va, val)) {
+ fpuemuprivate.stats.errors++;
+ return SIGBUS;
+ }
+ }
+ break;
+#else /* old 32-bit fpu registers */
+ case lwc1_op:
+ {
+ void *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)])
+ + MIPSInst_SIMM(ir);
+ ctx->regs[MIPSInst_RT(ir)] =
+ mips_get_word(xcp, va, &err);
+ fpuemuprivate.stats.loads++;
+ if (err) {
+ fpuemuprivate.stats.errors++;
+ return SIGBUS;
+ }
+ }
+ break;
+
+ case swc1_op:
+ {
+ void *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)])
+ + MIPSInst_SIMM(ir);
+ fpuemuprivate.stats.stores++;
+ if (mips_put_word
+ (xcp, va, ctx->regs[MIPSInst_RT(ir)])) {
+ fpuemuprivate.stats.errors++;
+ return SIGBUS;
+ }
+ }
+ break;
+ case ldc1_op:
+ {
+ void *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)])
+ + MIPSInst_SIMM(ir);
+ unsigned int rt = MIPSInst_RT(ir) & ~1;
+ int errs = 0;
+ fpuemuprivate.stats.loads++;
+#if (defined(BYTE_ORDER) && BYTE_ORDER == BIG_ENDIAN) || defined(__MIPSEB__)
+ ctx->regs[rt + 1] =
+ mips_get_word(xcp, va + 0, &err);
+ errs += err;
+ ctx->regs[rt + 0] =
+ mips_get_word(xcp, va + 4, &err);
+ errs += err;
+#else
+ ctx->regs[rt + 0] =
+ mips_get_word(xcp, va + 0, &err);
+ errs += err;
+ ctx->regs[rt + 1] =
+ mips_get_word(xcp, va + 4, &err);
+ errs += err;
+#endif
+ if (err)
+ return SIGBUS;
+ }
+ break;
+
+ case sdc1_op:
+ {
+ void *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)])
+ + MIPSInst_SIMM(ir);
+ unsigned int rt = MIPSInst_RT(ir) & ~1;
+ fpuemuprivate.stats.stores++;
+#if (defined(BYTE_ORDER) && BYTE_ORDER == BIG_ENDIAN) || defined(__MIPSEB__)
+ if (mips_put_word(xcp, va + 0, ctx->regs[rt + 1]))
+ return SIGBUS;
+ if (mips_put_word(xcp, va + 4, ctx->regs[rt + 0]))
+ return SIGBUS;
+#else
+ if (mips_put_word(xcp, va + 0, ctx->regs[rt + 0]))
+ return SIGBUS;
+ if (mips_put_word(xcp, va + 4, ctx->regs[rt + 1]))
+ return SIGBUS;
+#endif
+ }
+ break;
+#endif
+
+ case cop1_op:
+ switch (MIPSInst_RS(ir)) {
+
+#ifdef CP0_STATUS_FR_SUPPORT
+#if __mips64 && !defined(SINGLE_ONLY_FPU)
+ case dmfc_op:
+ /* copregister fs -> gpr[rt] */
+ if (MIPSInst_RT(ir) != 0) {
+ int fs = MIPSInst_RD(ir);
+ if (!(xcp->cp0_status & ST0_FR))
+ fs &= ~1;
+ xcp->regs[MIPSInst_RT(ir)] = ctx->regs[fs];
+ }
+ break;
+
+ case dmtc_op:
+ /* copregister fs <- rt */
+ {
+ fpureg_t value;
+ int fs = MIPSInst_RD(ir);
+ if (!(xcp->cp0_status & ST0_FR))
+ fs &= ~1;
+ value =
+ (MIPSInst_RT(ir) ==
+ 0) ? 0 : xcp->regs[MIPSInst_RT(ir)];
+ ctx->regs[fs] = value;
+ }
+ break;
+#endif
+
+ case mfc_op:
+ /* copregister rd -> gpr[rt] */
+ if (MIPSInst_RT(ir) != 0) {
+ /* default value from l.s. 32 bits */
+ int value = ctx->regs[MIPSInst_RD(ir)];
+ if (MIPSInst_RD(ir) & 1) {
+#ifdef SINGLE_ONLY_FPU
+ /* illegal register in single-float mode */
+ return SIGILL;
+#else
+ if (!(xcp->cp0_status & ST0_FR)) {
+ /* move from m.s. 32 bits */
+ value =
+ ctx->
+ regs[MIPSInst_RD(ir) &
+ ~1] >> 32;
+ }
+#endif
+ }
+ xcp->regs[MIPSInst_RT(ir)] = value;
+ }
+ break;
+
+ case mtc_op:
+ /* copregister rd <- rt */
+ {
+ fpureg_t value;
+ if (MIPSInst_RT(ir) == 0)
+ value = 0;
+ else
+ value =
+ (unsigned int) xcp->
+ regs[MIPSInst_RT(ir)];
+ if (MIPSInst_RD(ir) & 1) {
+#ifdef SINGLE_ONLY_FPU
+ /* illegal register in single-float mode */
+ return SIGILL;
+#else
+ if (!(xcp->cp0_status & ST0_FR)) {
+ /* move to m.s. 32 bits */
+ ctx->
+ regs[
+ (MIPSInst_RD(ir) &
+ ~1)] &=
+ 0xffffffff;
+ ctx->
+ regs[
+ (MIPSInst_RD(ir) &
+ ~1)] |=
+ value << 32;
+ break;
+ }
+#endif
+ }
+ /* move to l.s. 32 bits */
+ ctx->regs[MIPSInst_RD(ir)] &=
+ ~0xffffffffLL;
+ ctx->regs[MIPSInst_RD(ir)] |= value;
+ }
+ break;
+#else
+
+ case mfc_op:
+ /* copregister rd -> gpr[rt] */
+ if (MIPSInst_RT(ir) != 0) {
+ unsigned value =
+ ctx->regs[MIPSInst_RD(ir)];
+ xcp->regs[MIPSInst_RT(ir)] = value;
+ }
+ break;
+
+ case mtc_op:
+ /* copregister rd <- rt */
+ {
+ unsigned value;
+ value =
+ (MIPSInst_RT(ir) ==
+ 0) ? 0 : xcp->regs[MIPSInst_RT(ir)];
+ ctx->regs[MIPSInst_RD(ir)] = value;
+ }
+ break;
+#endif
+
+ case cfc_op:
+ /* cop control register rd -> gpr[rt] */
+ {
+ unsigned value;
+
+ if (MIPSInst_RD(ir) == FPCREG_CSR) {
+ value = ctx->sr;
+#ifdef CSRTRACE
+ printk
+ ("%p gpr[%d]<-csr=%08x\n",
+ REG_TO_VA(xcp->cp0_epc),
+ MIPSInst_RT(ir), value);
+#endif
+ } else if (MIPSInst_RD(ir) == FPCREG_RID)
+ value = 0;
+ else
+ value = 0;
+ if (MIPSInst_RT(ir))
+ xcp->regs[MIPSInst_RT(ir)] = value;
+ }
+ break;
+
+ case ctc_op:
+ /* copregister rd <- rt */
+ {
+ unsigned value;
+
+ if (MIPSInst_RT(ir) == 0)
+ value = 0;
+ else
+ value = xcp->regs[MIPSInst_RT(ir)];
+
+ /* we only have one writable control reg
+ */
+ if (MIPSInst_RD(ir) == FPCREG_CSR) {
+#ifdef CSRTRACE
+ printk
+ ("%p gpr[%d]->csr=%08x\n",
+ REG_TO_VA(xcp->cp0_epc),
+ MIPSInst_RT(ir), value);
+#endif
+ ctx->sr = value;
+ /* copy new rounding mode to ieee library state! */
+ ieee754_csr.rm =
+ ieee_rm[value & 0x3];
+ }
+ }
+ break;
+
+ case bc_op:
+ if (xcp->cp0_cause & CAUSEF_BD) {
+ return SIGILL;
+ }
+ {
+ int likely = 0;
+
+#if __mips >= 4
+ cond =
+ ctx->
+ sr & fpucondbit[MIPSInst_RT(ir) >> 2];
+#else
+ cond = ctx->sr & FPU_CSR_COND;
+#endif
+ switch (MIPSInst_RT(ir) & 3) {
+ case bcfl_op:
+ likely = 1;
+ case bcf_op:
+ cond = !cond;
+ break;
+ case bctl_op:
+ likely = 1;
+ case bct_op:
+ break;
+ default:
+ /* thats an illegal instruction */
+ return SIGILL;
+ }
+
+ xcp->cp0_cause |= CAUSEF_BD;
+ if (cond) {
+ /* branch taken: emulate dslot instruction */
+ xcp->cp0_epc += 4;
+ contpc =
+ REG_TO_VA xcp->cp0_epc +
+ (MIPSInst_SIMM(ir) << 2);
+
+ ir =
+ mips_get_word(xcp,
+ REG_TO_VA(xcp->
+ cp0_epc),
+ &err);
+ if (err) {
+ fpuemuprivate.stats.
+ errors++;
+ return SIGBUS;
+ }
+
+ switch (MIPSInst_OPCODE(ir)) {
+ case lwc1_op:
+ case swc1_op:
+#if (__mips >= 2 || __mips64) && !defined(SINGLE_ONLY_FPU)
+ case ldc1_op:
+ case sdc1_op:
+#endif
+ case cop1_op:
+#if __mips >= 4 && __mips != 32
+ case cop1x_op:
+#endif
+ /* its one of ours */
+ goto emul;
+#if __mips >= 4
+ case spec_op:
+ if (MIPSInst_FUNC(ir) ==
+ movc_op) goto emul;
+ break;
+#endif
+ }
+
+ /* single step the non-cp1 instruction in the dslot */
+ return mips_dsemul(xcp, ir,
+ contpc);
+ } else {
+ /* branch not taken */
+ if (likely)
+ /* branch likely nullifies dslot if not taken */
+ xcp->cp0_epc += 4;
+ /* else continue & execute dslot as normal insn */
+ }
+ }
+ break;
+
+ default:
+ if (!(MIPSInst_RS(ir) & 0x10)) {
+ return SIGILL;
+ }
+ /* a real fpu computation instruction */
+ {
+ int sig;
+ if ((sig = fpu_emu(xcp, ctx, ir)))
+ return sig;
+ }
+ }
+ break;
+
+#if __mips >= 4 && __mips != 32
+ case cop1x_op:
+ {
+ int sig;
+ if ((sig = fpux_emu(xcp, ctx, ir)))
+ return sig;
+ }
+ break;
+#endif
+
+#if __mips >= 4
+ case spec_op:
+ if (MIPSInst_FUNC(ir) != movc_op)
+ return SIGILL;
+ cond = fpucondbit[MIPSInst_RT(ir) >> 2];
+ if (((ctx->sr & cond) != 0) !=
+ ((MIPSInst_RT(ir) & 1) != 0)) return 0;
+ xcp->regs[MIPSInst_RD(ir)] = xcp->regs[MIPSInst_RS(ir)];
+ break;
+#endif
+
+ default:
+ return SIGILL;
+ }
+
+ /* we did it !! */
+ xcp->cp0_epc = VA_TO_REG(contpc);
+ xcp->cp0_cause &= ~CAUSEF_BD;
+ return 0;
+}
+
+/*
+ * Emulate the arbritrary instruction ir at xcp->cp0_epc. Required when
+ * we have to emulate the instruction in a COP1 branch delay slot. Do
+ * not change cp0_epc due to the instruction
+ *
+ * According to the spec:
+ * 1) it shouldnt be a branch :-)
+ * 2) it can be a COP instruction :-(
+ * 3) if we are tring to run a protected memory space we must take
+ * special care on memory access instructions :-(
+ */
+
+/*
+ * "Trampoline" return routine to catch exception following
+ * execution of delay-slot instruction execution.
+ */
+
+int do_dsemulret(struct pt_regs *xcp)
+{
+#ifdef DSEMUL_TRACE
+ printk("desemulret\n");
+#endif
+ /* Set EPC to return to post-branch instruction */
+ xcp->cp0_epc = current->thread.dsemul_epc;
+ /*
+ * Clear the state that got us here.
+ */
+ current->thread.dsemul_aerpc = (unsigned long) 0;
+
+ return 0;
+}
+
+
+#define AdELOAD 0x8c000001 /* lw $0,1($0) */
+
+static int
+mips_dsemul(struct pt_regs *xcp, mips_instruction ir, vaddr_t cpc)
+{
+ mips_instruction *dsemul_insns;
+ mips_instruction forcetrap;
+ extern asmlinkage void handle_dsemulret(void);
+
+ if (ir == 0) { /* a nop is easy */
+ xcp->cp0_epc = VA_TO_REG(cpc);
+ return 0;
+ }
+#ifdef DSEMUL_TRACE
+ printk("desemul %p %p\n", REG_TO_VA(xcp->cp0_epc), cpc);
+#endif
+
+ /*
+ * The strategy is to push the instruction onto the user stack
+ * and put a trap after it which we can catch and jump to
+ * the required address any alternative apart from full
+ * instruction emulation!!.
+ */
+ dsemul_insns = (mips_instruction *) (xcp->regs[29] & ~3);
+ dsemul_insns -= 3; /* Two instructions, plus one for luck ;-) */
+ /* Verify that the stack pointer is not competely insane */
+ if (verify_area
+ (VERIFY_WRITE, dsemul_insns, sizeof(mips_instruction) * 2))
+ return SIGBUS;
+
+ if (mips_put_word(xcp, &dsemul_insns[0], ir)) {
+ fpuemuprivate.stats.errors++;
+ return (SIGBUS);
+ }
+
+ /*
+ * Algorithmics used a system call instruction, and
+ * borrowed that vector. MIPS/Linux version is a bit
+ * more heavyweight in the interests of portability and
+ * multiprocessor support. We flag the thread for special
+ * handling in the unaligned access handler and force an
+ * address error excpetion.
+ */
+
+ /* If one is *really* paranoid, one tests for a bad stack pointer */
+ if ((xcp->regs[29] & 0x3) == 0x3)
+ forcetrap = AdELOAD - 1;
+ else
+ forcetrap = AdELOAD;
+
+ if (mips_put_word(xcp, &dsemul_insns[1], forcetrap)) {
+ fpuemuprivate.stats.errors++;
+ return (SIGBUS);
+ }
+
+ /* Set thread state to catch and handle the exception */
+ current->thread.dsemul_epc = (unsigned long) cpc;
+ current->thread.dsemul_aerpc = (unsigned long) &dsemul_insns[1];
+ xcp->cp0_epc = VA_TO_REG & dsemul_insns[0];
+
+ /* What we'd really like to do is just flush the line(s) of the */
+ /* icache containing the dsemulret instructions, but there's no */
+ /* mechanism to do this yet... */
+ flush_cache_all();
+ return SIGILL; /* force out of emulation loop */
+}
+
+/*
+ * Conversion table from MIPS compare ops 48-63
+ * cond = ieee754dp_cmp(x,y,IEEE754_UN);
+ */
+static const unsigned char cmptab[8] = {
+ 0, /* cmp_0 (sig) cmp_sf */
+ IEEE754_CUN, /* cmp_un (sig) cmp_ngle */
+ IEEE754_CEQ, /* cmp_eq (sig) cmp_seq */
+ IEEE754_CEQ | IEEE754_CUN, /* cmp_ueq (sig) cmp_ngl */
+ IEEE754_CLT, /* cmp_olt (sig) cmp_lt */
+ IEEE754_CLT | IEEE754_CUN, /* cmp_ult (sig) cmp_nge */
+ IEEE754_CLT | IEEE754_CEQ, /* cmp_ole (sig) cmp_le */
+ IEEE754_CLT | IEEE754_CEQ | IEEE754_CUN, /* cmp_ule (sig) cmp_ngt */
+};
+
+#define SIFROMREG(si,x) ((si) = ctx->regs[x])
+#define SITOREG(si,x) (ctx->regs[x] = (int)(si))
+
+#if __mips64 && !defined(SINGLE_ONLY_FPU)
+#define DIFROMREG(di,x) ((di) = ctx->regs[x])
+#define DITOREG(di,x) (ctx->regs[x] = (di))
+#endif
+
+#define SPFROMREG(sp,x) ((sp).bits = ctx->regs[x])
+#define SPTOREG(sp,x) (ctx->regs[x] = (sp).bits)
+
+#ifdef CP0_STATUS_FR_SUPPORT
+#define DPFROMREG(dp,x) ((dp).bits = \
+ ctx->regs[(xcp->cp0_status & ST0_FR) ? x : (x & ~1)])
+#define DPTOREG(dp,x) (ctx->regs[(xcp->cp0_status & ST0_FR) ? x : (x & ~1)]\
+ = (dp).bits)
+#else
+/* Beware: MIPS COP1 doubles are always little_word endian in registers */
+#define DPFROMREG(dp,x) \
+ ((dp).bits = ((unsigned long long)ctx->regs[(x)+1] << 32) | ctx->regs[x])
+#define DPTOREG(dp,x) \
+ (ctx->regs[x] = (dp).bits, ctx->regs[(x)+1] = (dp).bits >> 32)
+#endif
+
+#if __mips >= 4 && __mips != 32
+
+/*
+ * Additional MIPS4 instructions
+ */
+
+static ieee754dp fpemu_dp_recip(ieee754dp d)
+{
+ return ieee754dp_div(ieee754dp_one(0), d);
+}
+
+static ieee754dp fpemu_dp_rsqrt(ieee754dp d)
+{
+ return ieee754dp_div(ieee754dp_one(0), ieee754dp_sqrt(d));
+}
+
+static ieee754sp fpemu_sp_recip(ieee754sp s)
+{
+ return ieee754sp_div(ieee754sp_one(0), s);
+}
+
+static ieee754sp fpemu_sp_rsqrt(ieee754sp s)
+{
+ return ieee754sp_div(ieee754sp_one(0), ieee754sp_sqrt(s));
+}
+
+
+static ieee754dp fpemu_dp_madd(ieee754dp r, ieee754dp s, ieee754dp t)
+{
+ return ieee754dp_add(ieee754dp_mul(s, t), r);
+}
+
+static ieee754dp fpemu_dp_msub(ieee754dp r, ieee754dp s, ieee754dp t)
+{
+ return ieee754dp_sub(ieee754dp_mul(s, t), r);
+}
+
+static ieee754dp fpemu_dp_nmadd(ieee754dp r, ieee754dp s, ieee754dp t)
+{
+ return ieee754dp_neg(ieee754dp_add(ieee754dp_mul(s, t), r));
+}
+
+static ieee754dp fpemu_dp_nmsub(ieee754dp r, ieee754dp s, ieee754dp t)
+{
+ return ieee754dp_neg(ieee754dp_sub(ieee754dp_mul(s, t), r));
+}
+
+
+static ieee754sp fpemu_sp_madd(ieee754sp r, ieee754sp s, ieee754sp t)
+{
+ return ieee754sp_add(ieee754sp_mul(s, t), r);
+}
+
+static ieee754sp fpemu_sp_msub(ieee754sp r, ieee754sp s, ieee754sp t)
+{
+ return ieee754sp_sub(ieee754sp_mul(s, t), r);
+}
+
+static ieee754sp fpemu_sp_nmadd(ieee754sp r, ieee754sp s, ieee754sp t)
+{
+ return ieee754sp_neg(ieee754sp_add(ieee754sp_mul(s, t), r));
+}
+
+static ieee754sp fpemu_sp_nmsub(ieee754sp r, ieee754sp s, ieee754sp t)
+{
+ return ieee754sp_neg(ieee754sp_sub(ieee754sp_mul(s, t), r));
+}
+
+static int
+fpux_emu(struct pt_regs *xcp, struct mips_fpu_soft_struct *ctx,
+ mips_instruction ir)
+{
+ unsigned rcsr = 0; /* resulting csr */
+
+ fpuemuprivate.stats.cp1xops++;
+
+ switch (MIPSInst_FMA_FFMT(ir)) {
+ case s_fmt: /* 0 */
+ {
+ ieee754sp(*handler) (ieee754sp, ieee754sp,
+ ieee754sp);
+ ieee754sp fd, fr, fs, ft;
+
+ switch (MIPSInst_FUNC(ir)) {
+ case lwxc1_op:
+ {
+ void *va =
+ REG_TO_VA(xcp->
+ regs[MIPSInst_FR(ir)]
+ +
+ xcp->
+ regs[MIPSInst_FT
+ (ir)]);
+ fpureg_t val;
+ int err = 0;
+ val = mips_get_word(xcp, va, &err);
+ if (err) {
+ fpuemuprivate.stats.
+ errors++;
+ return SIGBUS;
+ }
+ if (xcp->cp0_status & ST0_FR) {
+ /* load whole register */
+ ctx->
+ regs[MIPSInst_FD(ir)] =
+ val;
+ } else if (MIPSInst_FD(ir) & 1) {
+ /* load to m.s. 32 bits */
+#if defined(SINGLE_ONLY_FPU)
+ /* illegal register in single-float mode */
+ return SIGILL;
+#else
+ ctx->
+ regs[
+ (MIPSInst_FD(ir) &
+ ~1)] &=
+ 0xffffffff;
+ ctx->
+ regs[
+ (MIPSInst_FD(ir) &
+ ~1)] |=
+ val << 32;
+#endif
+ } else {
+ /* load to l.s. 32 bits */
+ ctx->
+ regs[MIPSInst_FD(ir)]
+ &= ~0xffffffffLL;
+ ctx->
+ regs[MIPSInst_FD(ir)]
+ |= val;
+ }
+ }
+ break;
+
+ case swxc1_op:
+ {
+ void *va =
+ REG_TO_VA(xcp->
+ regs[MIPSInst_FR(ir)]
+ +
+ xcp->
+ regs[MIPSInst_FT
+ (ir)]);
+ unsigned int val;
+ if (xcp->cp0_status & ST0_FR) {
+ /* store whole register */
+ val =
+ ctx->
+ regs[MIPSInst_FS(ir)];
+ } else if (MIPSInst_FS(ir) & 1) {
+#if defined(SINGLE_ONLY_FPU)
+ /* illegal register in single-float mode */
+ return SIGILL;
+#else
+ /* store from m.s. 32 bits */
+ val =
+ ctx->
+ regs[
+ (MIPSInst_FS(ir) &
+ ~1)] >> 32;
+#endif
+ } else {
+ /* store from l.s. 32 bits */
+ val =
+ ctx->
+ regs[MIPSInst_FS(ir)];
+ }
+ if (mips_put_word(xcp, va, val)) {
+ fpuemuprivate.stats.
+ errors++;
+ return SIGBUS;
+ }
+ }
+ break;
+
+ case madd_s_op:
+ handler = fpemu_sp_madd;
+ goto scoptop;
+ case msub_s_op:
+ handler = fpemu_sp_msub;
+ goto scoptop;
+ case nmadd_s_op:
+ handler = fpemu_sp_nmadd;
+ goto scoptop;
+ case nmsub_s_op:
+ handler = fpemu_sp_nmsub;
+ goto scoptop;
+
+ scoptop:
+ SPFROMREG(fr, MIPSInst_FR(ir));
+ SPFROMREG(fs, MIPSInst_FS(ir));
+ SPFROMREG(ft, MIPSInst_FT(ir));
+ fd = (*handler) (fr, fs, ft);
+ SPTOREG(fd, MIPSInst_FD(ir));
+
+ copcsr:
+ if (ieee754_cxtest(IEEE754_INEXACT))
+ rcsr |=
+ FPU_CSR_INE_X | FPU_CSR_INE_S;
+ if (ieee754_cxtest(IEEE754_UNDERFLOW))
+ rcsr |=
+ FPU_CSR_UDF_X | FPU_CSR_UDF_S;
+ if (ieee754_cxtest(IEEE754_OVERFLOW))
+ rcsr |=
+ FPU_CSR_OVF_X | FPU_CSR_OVF_S;
+ if (ieee754_cxtest
+ (IEEE754_INVALID_OPERATION)) rcsr |=
+ FPU_CSR_INV_X | FPU_CSR_INV_S;
+
+ ctx->sr =
+ (ctx->sr & ~FPU_CSR_ALL_X) | rcsr;
+ if ((ctx->sr >> 5) & ctx->
+ sr & FPU_CSR_ALL_E) {
+ /*printk ("SIGFPE: fpu csr = %08x\n",ctx->sr); */
+ return SIGFPE;
+ }
+
+ break;
+
+ default:
+ return SIGILL;
+ }
+ }
+ break;
+
+#if !defined(SINGLE_ONLY_FPU)
+ case d_fmt: /* 1 */
+ {
+ ieee754dp(*handler) (ieee754dp, ieee754dp,
+ ieee754dp);
+ ieee754dp fd, fr, fs, ft;
+
+ switch (MIPSInst_FUNC(ir)) {
+ case ldxc1_op:
+ {
+ void *va =
+ REG_TO_VA(xcp->
+ regs[MIPSInst_FR(ir)]
+ +
+ xcp->
+ regs[MIPSInst_FT
+ (ir)]);
+ int err = 0;
+ ctx->regs[MIPSInst_FD(ir)] =
+ mips_get_dword(xcp, va, &err);
+ if (err) {
+ fpuemuprivate.stats.
+ errors++;
+ return SIGBUS;
+ }
+ }
+ break;
+
+ case sdxc1_op:
+ {
+ void *va =
+ REG_TO_VA(xcp->
+ regs[MIPSInst_FR(ir)]
+ +
+ xcp->
+ regs[MIPSInst_FT
+ (ir)]);
+ if (mips_put_dword
+ (xcp, va,
+ ctx->regs[MIPSInst_FS(ir)])) {
+ fpuemuprivate.stats.
+ errors++;
+ return SIGBUS;
+ }
+ }
+ break;
+
+ case madd_d_op:
+ handler = fpemu_dp_madd;
+ goto dcoptop;
+ case msub_d_op:
+ handler = fpemu_dp_msub;
+ goto dcoptop;
+ case nmadd_d_op:
+ handler = fpemu_dp_nmadd;
+ goto dcoptop;
+ case nmsub_d_op:
+ handler = fpemu_dp_nmsub;
+ goto dcoptop;
+
+ dcoptop:
+ DPFROMREG(fr, MIPSInst_FR(ir));
+ DPFROMREG(fs, MIPSInst_FS(ir));
+ DPFROMREG(ft, MIPSInst_FT(ir));
+ fd = (*handler) (fr, fs, ft);
+ DPTOREG(fd, MIPSInst_FD(ir));
+ goto copcsr;
+
+ default:
+ return SIGILL;
+ }
+ }
+ break;
+#endif
+
+ case 0x7: /* 7 */
+ {
+ if (MIPSInst_FUNC(ir) != pfetch_op) {
+ return SIGILL;
+ }
+ /* ignore prefx operation */
+ }
+ break;
+
+ default:
+ return SIGILL;
+ }
+
+ return 0;
+}
+#endif
+
+
+
+/*
+ * Emulate a single COP1 arithmetic instruction.
+ */
+static int
+fpu_emu(struct pt_regs *xcp, struct mips_fpu_soft_struct *ctx,
+ mips_instruction ir)
+{
+ int rfmt; /* resulting format */
+ unsigned rcsr = 0; /* resulting csr */
+ unsigned cond;
+ union {
+ ieee754dp d;
+ ieee754sp s;
+ int w;
+#if __mips64
+ long long l;
+#endif
+ } rv; /* resulting value */
+
+ fpuemuprivate.stats.cp1ops++;
+ switch (rfmt = (MIPSInst_FFMT(ir) & 0xf)) {
+
+ case s_fmt:{ /* 0 */
+ ieee754sp(*handler) ();
+
+ switch (MIPSInst_FUNC(ir)) {
+ /* binary ops */
+ case fadd_op:
+ handler = ieee754sp_add;
+ goto scopbop;
+ case fsub_op:
+ handler = ieee754sp_sub;
+ goto scopbop;
+ case fmul_op:
+ handler = ieee754sp_mul;
+ goto scopbop;
+ case fdiv_op:
+ handler = ieee754sp_div;
+ goto scopbop;
+
+ /* unary ops */
+#if __mips >= 2 || __mips64
+ case fsqrt_op:
+ handler = ieee754sp_sqrt;
+ goto scopuop;
+#endif
+#if __mips >= 4 && __mips != 32
+ case frsqrt_op:
+ handler = fpemu_sp_rsqrt;
+ goto scopuop;
+ case frecip_op:
+ handler = fpemu_sp_recip;
+ goto scopuop;
+#endif
+#if __mips >= 4
+ case fmovc_op:
+ cond = fpucondbit[MIPSInst_FT(ir) >> 2];
+ if (((ctx->sr & cond) != 0) !=
+ ((MIPSInst_FT(ir) & 1) != 0))
+ return 0;
+ SPFROMREG(rv.s, MIPSInst_FS(ir));
+ break;
+ case fmovz_op:
+ if (xcp->regs[MIPSInst_FT(ir)] != 0)
+ return 0;
+ SPFROMREG(rv.s, MIPSInst_FS(ir));
+ break;
+ case fmovn_op:
+ if (xcp->regs[MIPSInst_FT(ir)] == 0)
+ return 0;
+ SPFROMREG(rv.s, MIPSInst_FS(ir));
+ break;
+#endif
+ case fabs_op:
+ handler = ieee754sp_abs;
+ goto scopuop;
+ case fneg_op:
+ handler = ieee754sp_neg;
+ goto scopuop;
+ case fmov_op:
+ /* an easy one */
+ SPFROMREG(rv.s, MIPSInst_FS(ir));
+ break;
+ /* binary op on handler */
+scopbop:
+ {
+ ieee754sp fs, ft;
+
+ SPFROMREG(fs, MIPSInst_FS(ir));
+ SPFROMREG(ft, MIPSInst_FT(ir));
+
+ rv.s = (*handler) (fs, ft);
+ goto copcsr;
+ }
+scopuop:
+ {
+ ieee754sp fs;
+
+ SPFROMREG(fs, MIPSInst_FS(ir));
+ rv.s = (*handler) (fs);
+ goto copcsr;
+ }
+copcsr:
+ if (ieee754_cxtest(IEEE754_INEXACT))
+ rcsr |= FPU_CSR_INE_X | FPU_CSR_INE_S;
+ if (ieee754_cxtest(IEEE754_UNDERFLOW))
+ rcsr |= FPU_CSR_UDF_X | FPU_CSR_UDF_S;
+ if (ieee754_cxtest(IEEE754_OVERFLOW))
+ rcsr |= FPU_CSR_OVF_X | FPU_CSR_OVF_S;
+ if (ieee754_cxtest(IEEE754_ZERO_DIVIDE))
+ rcsr |= FPU_CSR_DIV_X | FPU_CSR_DIV_S;
+ if (ieee754_cxtest
+ (IEEE754_INVALID_OPERATION)) rcsr |=
+ FPU_CSR_INV_X | FPU_CSR_INV_S;
+ break;
+
+ /* unary conv ops */
+ case fcvts_op:
+ return SIGILL; /* not defined */
+ case fcvtd_op:
+#if defined(SINGLE_ONLY_FPU)
+ return SIGILL; /* not defined */
+#else
+ {
+ ieee754sp fs;
+
+ SPFROMREG(fs, MIPSInst_FS(ir));
+ rv.d = ieee754dp_fsp(fs);
+ rfmt = d_fmt;
+ goto copcsr;
+ }
+#endif
+ case fcvtw_op:
+ {
+ ieee754sp fs;
+
+ SPFROMREG(fs, MIPSInst_FS(ir));
+ rv.w = ieee754sp_tint(fs);
+ rfmt = w_fmt;
+ goto copcsr;
+ }
+
+#if __mips >= 2 || __mips64
+ case fround_op:
+ case ftrunc_op:
+ case fceil_op:
+ case ffloor_op:
+ {
+ unsigned int oldrm = ieee754_csr.rm;
+ ieee754sp fs;
+
+ SPFROMREG(fs, MIPSInst_FS(ir));
+ ieee754_csr.rm = ieee_rm[MIPSInst_FUNC(ir) & 0x3];
+ rv.w = ieee754sp_tint(fs);
+ ieee754_csr.rm = oldrm;
+ rfmt = w_fmt;
+ goto copcsr;
+ }
+#endif /* __mips >= 2 */
+
+#if __mips64 && !defined(SINGLE_ONLY_FPU)
+ case fcvtl_op:
+ {
+ ieee754sp fs;
+
+ SPFROMREG(fs, MIPSInst_FS(ir));
+ rv.l = ieee754sp_tlong(fs);
+ rfmt = l_fmt;
+ goto copcsr;
+ }
+
+ case froundl_op:
+ case ftruncl_op:
+ case fceill_op:
+ case ffloorl_op:
+ {
+ unsigned int oldrm = ieee754_csr.rm;
+ ieee754sp fs;
+
+ SPFROMREG(fs, MIPSInst_FS(ir));
+ ieee754_csr.rm = ieee_rm[MIPSInst_FUNC(ir) & 0x3];
+ rv.l = ieee754sp_tlong(fs);
+ ieee754_csr.rm = oldrm;
+ rfmt = l_fmt;
+ goto copcsr;
+ }
+#endif /* __mips64 && !fpu(single) */
+
+ default:
+ if (MIPSInst_FUNC(ir) >= fcmp_op) {
+ unsigned cmpop = MIPSInst_FUNC(ir) - fcmp_op;
+ ieee754sp fs, ft;
+
+ SPFROMREG(fs, MIPSInst_FS(ir));
+ SPFROMREG(ft, MIPSInst_FT(ir));
+ rv.w = ieee754sp_cmp(fs, ft, cmptab[cmpop & 0x7]);
+ rfmt = -1;
+ if ((cmpop & 0x8) && ieee754_cxtest(IEEE754_INVALID_OPERATION))
+ rcsr = FPU_CSR_INV_X | FPU_CSR_INV_S;
+ } else {
+ return SIGILL;
+ }
+ break;
+ }
+ break;
+ }
+
+#if !defined(SINGLE_ONLY_FPU)
+ case d_fmt: {
+ ieee754dp(*handler) ();
+
+ switch (MIPSInst_FUNC(ir)) {
+ /* binary ops */
+ case fadd_op:
+ handler = ieee754dp_add;
+ goto dcopbop;
+ case fsub_op:
+ handler = ieee754dp_sub;
+ goto dcopbop;
+ case fmul_op:
+ handler = ieee754dp_mul;
+ goto dcopbop;
+ case fdiv_op:
+ handler = ieee754dp_div;
+ goto dcopbop;
+
+ /* unary ops */
+#if __mips >= 2 || __mips64
+ case fsqrt_op:
+ handler = ieee754dp_sqrt;
+ goto dcopuop;
+#endif
+#if __mips >= 4 && __mips != 32
+ case frsqrt_op:
+ handler = fpemu_dp_rsqrt;
+ goto dcopuop;
+ case frecip_op:
+ handler = fpemu_dp_recip;
+ goto dcopuop;
+#endif
+#if __mips >= 4
+ case fmovc_op:
+ cond = fpucondbit[MIPSInst_FT(ir) >> 2];
+ if (((ctx->sr & cond) != 0) != ((MIPSInst_FT(ir) & 1) != 0))
+ return 0;
+ DPFROMREG(rv.d, MIPSInst_FS(ir));
+ break;
+ case fmovz_op:
+ if (xcp->regs[MIPSInst_FT(ir)] != 0)
+ return 0;
+ DPFROMREG(rv.d, MIPSInst_FS(ir));
+ break;
+ case fmovn_op:
+ if (xcp->regs[MIPSInst_FT(ir)] == 0)
+ return 0;
+ DPFROMREG(rv.d, MIPSInst_FS(ir));
+ break;
+#endif
+ case fabs_op:
+ handler = ieee754dp_abs;
+ goto dcopuop;
+ case fneg_op:
+ handler = ieee754dp_neg;
+ goto dcopuop;
+ case fmov_op:
+ /* an easy one */
+ DPFROMREG(rv.d, MIPSInst_FS(ir));
+ break;
+
+ /* binary op on handler */
+dcopbop:
+ {
+ ieee754dp fs, ft;
+
+ DPFROMREG(fs, MIPSInst_FS(ir));
+ DPFROMREG(ft, MIPSInst_FT(ir));
+
+ rv.d = (*handler) (fs, ft);
+ goto copcsr;
+ }
+dcopuop:
+ {
+ ieee754dp fs;
+
+ DPFROMREG(fs, MIPSInst_FS(ir));
+ rv.d = (*handler) (fs);
+ goto copcsr;
+ }
+
+ /* unary conv ops */
+ case fcvts_op:
+ {
+ ieee754dp fs;
+
+ DPFROMREG(fs, MIPSInst_FS(ir));
+ rv.s = ieee754sp_fdp(fs);
+ rfmt = s_fmt;
+ goto copcsr;
+ }
+ case fcvtd_op:
+ return SIGILL; /* not defined */
+ case fcvtw_op:
+ {
+ ieee754dp fs;
+
+ DPFROMREG(fs, MIPSInst_FS(ir));
+ rv.w = ieee754dp_tint(fs); /* wrong */
+ rfmt = w_fmt;
+ goto copcsr;
+ }
+
+#if __mips >= 2 || __mips64
+ case fround_op:
+ case ftrunc_op:
+ case fceil_op:
+ case ffloor_op:
+ {
+ unsigned int oldrm = ieee754_csr.rm;
+ ieee754dp fs;
+
+ DPFROMREG(fs, MIPSInst_FS(ir));
+ ieee754_csr.rm = ieee_rm[MIPSInst_FUNC(ir) & 0x3];
+ rv.w = ieee754dp_tint(fs);
+ ieee754_csr.rm = oldrm;
+ rfmt = w_fmt;
+ goto copcsr;
+ }
+#endif
+
+#if __mips64 && !defined(SINGLE_ONLY_FPU)
+ case fcvtl_op:
+ {
+ ieee754dp fs;
+
+ DPFROMREG(fs, MIPSInst_FS(ir));
+ rv.l = ieee754dp_tlong(fs);
+ rfmt = l_fmt;
+ goto copcsr;
+ }
+
+ case froundl_op:
+ case ftruncl_op:
+ case fceill_op:
+ case ffloorl_op:
+ {
+ unsigned int oldrm = ieee754_csr.rm;
+ ieee754dp fs;
+
+ DPFROMREG(fs, MIPSInst_FS(ir));
+ ieee754_csr.rm = ieee_rm[MIPSInst_FUNC(ir) & 0x3];
+ rv.l = ieee754dp_tlong(fs);
+ ieee754_csr.rm = oldrm;
+ rfmt = l_fmt;
+ goto copcsr;
+ }
+#endif /* __mips >= 3 && !fpu(single) */
+
+ default:
+ if (MIPSInst_FUNC(ir) >= fcmp_op) {
+ unsigned cmpop = MIPSInst_FUNC(ir) - fcmp_op;
+ ieee754dp fs, ft;
+
+ DPFROMREG(fs, MIPSInst_FS(ir));
+ DPFROMREG(ft, MIPSInst_FT(ir));
+ rv.w = ieee754dp_cmp(fs, ft, cmptab[cmpop & 0x7]);
+ rfmt = -1;
+ if ((cmpop & 0x8) && ieee754_cxtest (IEEE754_INVALID_OPERATION))
+ rcsr = FPU_CSR_INV_X | FPU_CSR_INV_S;
+ } else {
+ return SIGILL;
+ }
+ break;
+ }
+ break;
+ }
+#endif /* !defined(SINGLE_ONLY_FPU) */
+
+ case w_fmt: {
+ switch (MIPSInst_FUNC(ir)) {
+ case fcvts_op:
+ /* convert word to single precision real */
+ rv.s = ieee754sp_fint(ctx-> regs[MIPSInst_FS(ir)]);
+ rfmt = s_fmt;
+ goto copcsr;
+#if !defined(SINGLE_ONLY_FPU)
+ case fcvtd_op:
+ /* convert word to double precision real */
+ rv.d = ieee754dp_fint(ctx-> regs[MIPSInst_FS(ir)]);
+ rfmt = d_fmt;
+ goto copcsr;
+#endif
+ default:
+ return SIGILL;
+ }
+ break;
+ }
+
+#if __mips64 && !defined(SINGLE_ONLY_FPU)
+ case l_fmt: {
+ switch (MIPSInst_FUNC(ir)) {
+ case fcvts_op:
+ /* convert long to single precision real */
+ rv.s = ieee754sp_flong(ctx-> regs[MIPSInst_FS(ir)]);
+ rfmt = s_fmt;
+ goto copcsr;
+ case fcvtd_op:
+ /* convert long to double precision real */
+ rv.d = ieee754dp_flong(ctx-> regs[MIPSInst_FS(ir)]);
+ rfmt = d_fmt;
+ goto copcsr;
+ default:
+ return SIGILL;
+ }
+ break;
+ }
+#endif
+
+ default:
+ return SIGILL;
+ }
+
+ /*
+ * Update the fpu CSR register for this operation.
+ * If an exception is required, generate a tidy SIGFPE exception,
+ * without updating the result register.
+ * Note: cause exception bits do not accumulate, they are rewritten
+ * for each op; only the flag/sticky bits accumulate.
+ */
+ ctx->sr = (ctx->sr & ~FPU_CSR_ALL_X) | rcsr;
+ if ((ctx->sr >> 5) & ctx->sr & FPU_CSR_ALL_E) {
+ /*printk ("SIGFPE: fpu csr = %08x\n",ctx->sr); */
+ return SIGFPE;
+ }
+
+ /*
+ * Now we can safely write the result back to the register file.
+ */
+ switch (rfmt) {
+ case -1: {
+#if __mips >= 4
+ cond = fpucondbit[MIPSInst_FD(ir) >> 2];
+#else
+ cond = FPU_CSR_COND;
+#endif
+ if (rv.w)
+ ctx->sr |= cond;
+ else
+ ctx->sr &= ~cond;
+ break;
+ }
+#if !defined(SINGLE_ONLY_FPU)
+ case d_fmt:
+ DPTOREG(rv.d, MIPSInst_FD(ir));
+ break;
+#endif
+ case s_fmt:
+ SPTOREG(rv.s, MIPSInst_FD(ir));
+ break;
+ case w_fmt:
+ SITOREG(rv.w, MIPSInst_FD(ir));
+ break;
+#if __mips64 && !defined(SINGLE_ONLY_FPU)
+ case l_fmt:
+ DITOREG(rv.l, MIPSInst_FD(ir));
+ break;
+#endif
+ default:
+ return SIGILL;
+ }
+
+ return 0;
+}
+
+
+/*
+ * Emulate the floating point instruction at EPC, and continue
+ * to run until we hit a non-fp instruction, or a backward
+ * branch. This cuts down dramatically on the per instruction
+ * exception overhead.
+ */
+int fpu_emulator_cop1Handler(int xcptno, struct pt_regs *xcp)
+{
+ struct mips_fpu_soft_struct *ctx = ¤t->thread.fpu.soft;
+ unsigned long oldepc, prevepc;
+ unsigned int insn;
+ int sig = 0;
+ int err = 0;
+
+ oldepc = xcp->cp0_epc;
+ do {
+ prevepc = xcp->cp0_epc;
+ insn = mips_get_word(xcp, REG_TO_VA(xcp->cp0_epc), &err);
+ if (err) {
+ fpuemuprivate.stats.errors++;
+ return SIGBUS;
+ }
+ if (insn != 0)
+ sig = cop1Emulate(xcptno, xcp, ctx);
+ else
+ xcp->cp0_epc += 4; /* skip nops */
+ } while (xcp->cp0_epc > prevepc && sig == 0);
+
+ /* SIGILL indicates a non-fpu instruction */
+ if (sig == SIGILL && xcp->cp0_epc != oldepc)
+ /* but if epc has advanced, then ignore it */
+ sig = 0;
+
+ return sig;
+}
+
+
+#ifdef NOTDEF
+/*
+ * Patch up the hardware fpu state when an f.p. exception occurs.
+ */
+static int cop1Patcher(int xcptno, struct pt_regs *xcp)
+{
+ struct mips_fpu_soft_struct *ctx = ¤t->thread.fpu.soft;
+ unsigned sr;
+ int sig;
+
+ /* reenable Cp1, else fpe_save() will get nested exception */
+ sr = mips_bissr(ST0_CU1);
+
+ /* get fpu registers and status, then clear pending exceptions */
+ fpe_save(ctx);
+ fpe_setsr(ctx->sr &= ~FPU_CSR_ALL_X);
+
+ /* get current rounding mode for IEEE library, and emulate insn */
+ ieee754_csr.rm = ieee_rm[ctx->sr & 0x3];
+ sig = cop1Emulate(xcptno, xcp, ctx);
+
+ /* don't return with f.p. exceptions pending */
+ ctx->sr &= ~FPU_CSR_ALL_X;
+ fpe_restore(ctx);
+
+ mips_setsr(sr);
+ return sig;
+}
+
+void _cop1_init(int emulate)
+{
+ extern int _nofpu;
+
+ if (emulate) {
+ /*
+ * Install cop1 emulator to handle "coprocessor unusable" exception
+ */
+ xcption(XCPTCPU, cop1Handler);
+ fpuemuactive = 1; /* tell dbg.c that we are in charge */
+ _nofpu = 0; /* tell setjmp() it "has" an fpu */
+ } else {
+ /*
+ * Install cop1 emulator for floating point exceptions only,
+ * i.e. denormalised results, underflow, overflow etc, which
+ * must be emulated in s/w.
+ */
+#ifdef 1
+ /* r4000 or above use dedicate exception */
+ xcption(XCPTFPE, cop1Patcher);
+#else
+ /* r3000 et al use interrupt */
+ extern int _sbd_getfpuintr(void);
+ int intno = _sbd_getfpuintr();
+ intrupt(intno, cop1Patcher, 0);
+ mips_bissr(SR_IM0 << intno);
+#endif
+
+#if (#cpu(r4640) || #cpu(r4650)) && !defined(SINGLE_ONLY_FPU)
+ /* For R4640/R4650 compiled *without* the -msingle-float flag,
+ then we share responsibility: the h/w handles the single
+ precision operations, and the trap emulator handles the
+ double precision. We set fpuemuactive so that dbg.c first
+ fetches the s/w state before saving the h/w state. */
+ fpuemuactive = 1;
+ {
+ int i;
+ /* initialise the unused d.p high order words to be NaN */
+ for (i = 0; i < 32; i++)
+ current->thread.fpu.soft.regs[i] =
+ 0x7ff80bad00000000LL;
+ }
+#endif /* (r4640 || r4650) && !fpu(single) */
+ }
+}
+#endif
+
--- /dev/null
+/* IEEE754 floating point arithmetic
+ * double precision: common utilities
+ */
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ *
+ */
+
+
+#include "ieee754dp.h"
+
+ieee754dp ieee754dp_add(ieee754dp x, ieee754dp y)
+{
+ COMPXDP;
+ COMPYDP;
+
+ EXPLODEXDP;
+ EXPLODEYDP;
+
+ CLEARCX;
+
+ switch (CLPAIR(xc, yc)) {
+ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN):
+ return ieee754dp_nanxcpt(ieee754dp_bestnan(x, y), "add", x,
+ y);
+
+ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN):
+ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN):
+ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN):
+ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN):
+ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN):
+ return ieee754dp_nanxcpt(y, "add", x, y);
+
+ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN):
+ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO):
+ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM):
+ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM):
+ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
+ return ieee754dp_nanxcpt(x, "add", x, y);
+
+ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
+ return ieee754dp_bestnan(x, y);
+
+ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
+ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
+ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN):
+ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN):
+ return y;
+
+ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO):
+ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM):
+ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM):
+ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF):
+ return x;
+
+
+ /* Inifity handeling
+ */
+
+ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
+ if (xs == ys)
+ return x;
+ SETCX(IEEE754_INVALID_OPERATION);
+ return ieee754dp_xcpt(ieee754dp_indef(), "add", x, y);
+
+ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF):
+ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF):
+ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF):
+ return y;
+
+ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO):
+ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM):
+ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
+ return x;
+
+ /* Zero handeling
+ */
+
+ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
+ if (xs == ys)
+ return x;
+ else
+ return ieee754dp_zero(ieee754_csr.rm ==
+ IEEE754_RD);
+
+ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO):
+ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO):
+ return x;
+
+ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM):
+ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM):
+ return y;
+
+ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
+ DPDNORMX;
+
+ /* FALL THROUGH */
+
+ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM):
+ DPDNORMY;
+ break;
+
+ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM):
+ DPDNORMX;
+ break;
+
+ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM):
+ break;
+ }
+ assert(xm & DP_HIDDEN_BIT);
+ assert(ym & DP_HIDDEN_BIT);
+
+ /* provide guard,round and stick bit space */
+ xm <<= 3;
+ ym <<= 3;
+
+ if (xe > ye) {
+ /* have to shift y fraction right to align
+ */
+ int s = xe - ye;
+ ym = XDPSRS(ym, s);
+ ye += s;
+ } else if (ye > xe) {
+ /* have to shift x fraction right to align
+ */
+ int s = ye - xe;
+ xm = XDPSRS(xm, s);
+ xe += s;
+ }
+ assert(xe == ye);
+ assert(xe <= DP_EMAX);
+
+ if (xs == ys) {
+ /* generate 28 bit result of adding two 27 bit numbers
+ * leaving result in xm,xs,xe
+ */
+ xm = xm + ym;
+ xe = xe;
+ xs = xs;
+
+ if (xm >> (DP_MBITS + 1 + 3)) { /* carry out */
+ xm = XDPSRS1(xm);
+ xe++;
+ }
+ } else {
+ if (xm >= ym) {
+ xm = xm - ym;
+ xe = xe;
+ xs = xs;
+ } else {
+ xm = ym - xm;
+ xe = xe;
+ xs = ys;
+ }
+ if (xm == 0)
+ return ieee754dp_zero(ieee754_csr.rm ==
+ IEEE754_RD);
+
+ /* normalize to rounding precision */
+ while ((xm >> (DP_MBITS + 3)) == 0) {
+ xm <<= 1;
+ xe--;
+ }
+
+ }
+ DPNORMRET2(xs, xe, xm, "add", x, y);
+}
--- /dev/null
+/* IEEE754 floating point arithmetic
+ * double precision: common utilities
+ */
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+
+#include "ieee754dp.h"
+
+int ieee754dp_cmp(ieee754dp x, ieee754dp y, int cmp)
+{
+ CLEARCX;
+
+ if (ieee754dp_isnan(x) || ieee754dp_isnan(y)) {
+ if (cmp & IEEE754_CUN)
+ return 1;
+ if (cmp & (IEEE754_CLT | IEEE754_CGT)) {
+ if (SETCX(IEEE754_INVALID_OPERATION))
+ return ieee754si_xcpt(0, "fcmpf", x);
+ }
+ return 0;
+ } else {
+ long long int vx = x.bits;
+ long long int vy = y.bits;
+
+ if (vx < 0)
+ vx = -vx ^ DP_SIGN_BIT;
+ if (vy < 0)
+ vy = -vy ^ DP_SIGN_BIT;
+
+ if (vx < vy)
+ return (cmp & IEEE754_CLT) != 0;
+ else if (vx == vy)
+ return (cmp & IEEE754_CEQ) != 0;
+ else
+ return (cmp & IEEE754_CGT) != 0;
+ }
+}
--- /dev/null
+/* IEEE754 floating point arithmetic
+ * double precision: common utilities
+ */
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+
+#include "ieee754dp.h"
+
+ieee754dp ieee754dp_div(ieee754dp x, ieee754dp y)
+{
+ COMPXDP;
+ COMPYDP;
+
+ CLEARCX;
+
+ EXPLODEXDP;
+ EXPLODEYDP;
+
+ switch (CLPAIR(xc, yc)) {
+ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN):
+ return ieee754dp_nanxcpt(ieee754dp_bestnan(x, y), "div", x,
+ y);
+
+ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN):
+ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN):
+ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN):
+ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN):
+ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN):
+ return ieee754dp_nanxcpt(y, "div", x, y);
+
+ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN):
+ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO):
+ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM):
+ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM):
+ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
+ return ieee754dp_nanxcpt(x, "div", x, y);
+
+ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
+ return ieee754dp_bestnan(x, y);
+
+ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
+ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
+ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN):
+ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN):
+ return y;
+
+ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO):
+ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM):
+ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM):
+ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF):
+ return x;
+
+
+ /* Infinity handeling
+ */
+
+ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
+ SETCX(IEEE754_INVALID_OPERATION);
+ return ieee754dp_xcpt(ieee754dp_indef(), "div", x, y);
+
+ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF):
+ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF):
+ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF):
+ return ieee754dp_zero(xs ^ ys);
+
+ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO):
+ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM):
+ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
+ return ieee754dp_inf(xs ^ ys);
+
+ /* Zero handeling
+ */
+
+ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
+ SETCX(IEEE754_INVALID_OPERATION);
+ return ieee754dp_xcpt(ieee754dp_indef(), "div", x, y);
+
+ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO):
+ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO):
+ SETCX(IEEE754_ZERO_DIVIDE);
+ return ieee754dp_xcpt(ieee754dp_inf(xs ^ ys), "div", x, y);
+
+ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM):
+ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM):
+ return ieee754dp_zero(xs == ys ? 0 : 1);
+
+ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
+ DPDNORMX;
+
+ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM):
+ DPDNORMY;
+ break;
+
+ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM):
+ DPDNORMX;
+ break;
+
+ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM):
+ break;
+ }
+ assert(xm & DP_HIDDEN_BIT);
+ assert(ym & DP_HIDDEN_BIT);
+
+ /* provide rounding space */
+ xm <<= 3;
+ ym <<= 3;
+
+ {
+ /* now the dirty work */
+
+ unsigned long long rm = 0;
+ int re = xe - ye;
+ unsigned long long bm;
+
+ for (bm = DP_MBIT(DP_MBITS + 2); bm; bm >>= 1) {
+ if (xm >= ym) {
+ xm -= ym;
+ rm |= bm;
+ if (xm == 0)
+ break;
+ }
+ xm <<= 1;
+ }
+ rm <<= 1;
+ if (xm)
+ rm |= 1; /* have remainder, set sticky */
+
+ assert(rm);
+
+ /* normalise rm to rounding precision ?
+ */
+ while ((rm >> (DP_MBITS + 3)) == 0) {
+ rm <<= 1;
+ re--;
+ }
+
+ DPNORMRET2(xs == ys ? 0 : 1, re, rm, "div", x, y);
+ }
+}
--- /dev/null
+/* IEEE754 floating point arithmetic
+ * double precision: common utilities
+ */
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+
+#include "ieee754dp.h"
+
+ieee754dp ieee754dp_fint(int x)
+{
+ COMPXDP;
+
+ CLEARCX;
+
+ if (x == 0)
+ return ieee754dp_zero(0);
+ if (x == 1 || x == -1)
+ return ieee754dp_one(x < 0);
+ if (x == 10 || x == -10)
+ return ieee754dp_ten(x < 0);
+
+ xs = (x < 0);
+ if (xs) {
+ if (x == (1 << 31))
+ xm = ((unsigned) 1 << 31); /* max neg can't be safely negated */
+ else
+ xm = -x;
+ } else {
+ xm = x;
+ }
+
+#if 1
+ /* normalize - result can never be inexact or overflow */
+ xe = DP_MBITS;
+ while ((xm >> DP_MBITS) == 0) {
+ xm <<= 1;
+ xe--;
+ }
+ return builddp(xs, xe + DP_EBIAS, xm & ~DP_HIDDEN_BIT);
+#else
+ /* normalize */
+ xe = DP_MBITS + 3;
+ while ((xm >> (DP_MBITS + 3)) == 0) {
+ xm <<= 1;
+ xe--;
+ }
+ DPNORMRET1(xs, xe, xm, "fint", x);
+#endif
+}
+
+ieee754dp ieee754dp_funs(unsigned int u)
+{
+ if ((int) u < 0)
+ return ieee754dp_add(ieee754dp_1e31(),
+ ieee754dp_fint(u & ~(1 << 31)));
+ return ieee754dp_fint(u);
+}
--- /dev/null
+/* IEEE754 floating point arithmetic
+ * double precision: common utilities
+ */
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+
+#include "ieee754dp.h"
+
+ieee754dp ieee754dp_flong(long long x)
+{
+ COMPXDP;
+
+ CLEARCX;
+
+ if (x == 0)
+ return ieee754dp_zero(0);
+ if (x == 1 || x == -1)
+ return ieee754dp_one(x < 0);
+ if (x == 10 || x == -10)
+ return ieee754dp_ten(x < 0);
+
+ xs = (x < 0);
+ if (xs) {
+ if (x == (1ULL << 63))
+ xm = (1ULL << 63); /* max neg can't be safely negated */
+ else
+ xm = -x;
+ } else {
+ xm = x;
+ }
+
+ /* normalize */
+ xe = DP_MBITS + 3;
+ if (xm >> (DP_MBITS + 1 + 3)) {
+ /* shunt out overflow bits */
+ while (xm >> (DP_MBITS + 1 + 3)) {
+ XDPSRSX1();
+ }
+ } else {
+ /* normalize in grs extended double precision */
+ while ((xm >> (DP_MBITS + 3)) == 0) {
+ xm <<= 1;
+ xe--;
+ }
+ }
+ DPNORMRET1(xs, xe, xm, "dp_flong", x);
+}
+
+ieee754dp ieee754dp_fulong(unsigned long long u)
+{
+ if ((long long) u < 0)
+ return ieee754dp_add(ieee754dp_1e63(),
+ ieee754dp_flong(u & ~(1ULL << 63)));
+ return ieee754dp_flong(u);
+}
--- /dev/null
+/* IEEE754 floating point arithmetic
+ * double precision: common utilities
+ */
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+
+#include "ieee754dp.h"
+
+/* close to ieeep754dp_logb
+*/
+ieee754dp ieee754dp_frexp(ieee754dp x, int *eptr)
+{
+ COMPXDP;
+ CLEARCX;
+ EXPLODEXDP;
+
+ switch (xc) {
+ case IEEE754_CLASS_SNAN:
+ case IEEE754_CLASS_QNAN:
+ case IEEE754_CLASS_INF:
+ case IEEE754_CLASS_ZERO:
+ *eptr = 0;
+ return x;
+ case IEEE754_CLASS_DNORM:
+ DPDNORMX;
+ break;
+ case IEEE754_CLASS_NORM:
+ break;
+ }
+ *eptr = xe + 1;
+ return builddp(xs, -1 + DP_EBIAS, xm & ~DP_HIDDEN_BIT);
+}
--- /dev/null
+/* IEEE754 floating point arithmetic
+ * double precision: common utilities
+ */
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+
+#include "ieee754dp.h"
+
+ieee754dp ieee754dp_fsp(ieee754sp x)
+{
+ COMPXSP;
+
+ CLEARCX;
+
+ EXPLODEXSP;
+
+ switch (xc) {
+ case IEEE754_CLASS_QNAN:
+ case IEEE754_CLASS_SNAN:
+ return ieee754dp_nanxcpt(builddp(xs,
+ DP_EMAX + 1 + DP_EBIAS,
+ ((unsigned long long) xm
+ << (DP_MBITS -
+ SP_MBITS))), "fsp",
+ x);
+ case IEEE754_CLASS_INF:
+ return ieee754dp_inf(xs);
+ case IEEE754_CLASS_ZERO:
+ return ieee754dp_zero(xs);
+ case IEEE754_CLASS_DNORM:
+ /* normalize */
+ while ((xm >> SP_MBITS) == 0) {
+ xm <<= 1;
+ xe--;
+ }
+ break;
+ case IEEE754_CLASS_NORM:
+ break;
+ }
+
+ /* CANT possibly overflow,underflow, or need rounding
+ */
+
+ /* drop the hidden bit */
+ xm &= ~SP_HIDDEN_BIT;
+
+ return builddp(xs, xe + DP_EBIAS,
+ (unsigned long long) xm << (DP_MBITS - SP_MBITS));
+}
--- /dev/null
+/* IEEE754 floating point arithmetic
+ * double precision: common utilities
+ */
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+
+#include "ieee754dp.h"
+
+ieee754dp ieee754dp_logb(ieee754dp x)
+{
+ COMPXDP;
+
+ CLEARCX;
+
+ EXPLODEXDP;
+
+ switch (xc) {
+ case IEEE754_CLASS_SNAN:
+ return ieee754dp_nanxcpt(x, "logb", x);
+ case IEEE754_CLASS_QNAN:
+ return x;
+ case IEEE754_CLASS_INF:
+ return ieee754dp_inf(0);
+ case IEEE754_CLASS_ZERO:
+ return ieee754dp_inf(1);
+ case IEEE754_CLASS_DNORM:
+ DPDNORMX;
+ break;
+ case IEEE754_CLASS_NORM:
+ break;
+ }
+ return ieee754dp_fint(xe);
+}
--- /dev/null
+/* IEEE754 floating point arithmetic
+ * double precision: common utilities
+ */
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+
+#include "ieee754dp.h"
+
+/* modf function is always exact for a finite number
+*/
+ieee754dp ieee754dp_modf(ieee754dp x, ieee754dp * ip)
+{
+ COMPXDP;
+
+ CLEARCX;
+
+ EXPLODEXDP;
+
+ switch (xc) {
+ case IEEE754_CLASS_SNAN:
+ case IEEE754_CLASS_QNAN:
+ case IEEE754_CLASS_INF:
+ case IEEE754_CLASS_ZERO:
+ *ip = x;
+ return x;
+ case IEEE754_CLASS_DNORM:
+ /* far to small */
+ *ip = ieee754dp_zero(xs);
+ return x;
+ case IEEE754_CLASS_NORM:
+ break;
+ }
+ if (xe < 0) {
+ *ip = ieee754dp_zero(xs);
+ return x;
+ }
+ if (xe >= DP_MBITS) {
+ *ip = x;
+ return ieee754dp_zero(xs);
+ }
+ /* generate ipart mantissa by clearing bottom bits
+ */
+ *ip = builddp(xs, xe + DP_EBIAS,
+ ((xm >> (DP_MBITS - xe)) << (DP_MBITS - xe)) &
+ ~DP_HIDDEN_BIT);
+
+ /* generate fpart mantissa by clearing top bits
+ * and normalizing (must be able to normalize)
+ */
+ xm = (xm << (64 - (DP_MBITS - xe))) >> (64 - (DP_MBITS - xe));
+ if (xm == 0)
+ return ieee754dp_zero(xs);
+
+ while ((xm >> DP_MBITS) == 0) {
+ xm <<= 1;
+ xe--;
+ }
+ return builddp(xs, xe + DP_EBIAS, xm & ~DP_HIDDEN_BIT);
+}
--- /dev/null
+/* IEEE754 floating point arithmetic
+ * double precision: common utilities
+ */
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+
+#include "ieee754dp.h"
+
+ieee754dp ieee754dp_mul(ieee754dp x, ieee754dp y)
+{
+ COMPXDP;
+ COMPYDP;
+
+ CLEARCX;
+
+ EXPLODEXDP;
+ EXPLODEYDP;
+
+ switch (CLPAIR(xc, yc)) {
+ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN):
+ return ieee754dp_nanxcpt(ieee754dp_bestnan(x, y), "mul", x,
+ y);
+
+ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN):
+ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN):
+ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN):
+ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN):
+ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN):
+ return ieee754dp_nanxcpt(y, "mul", x, y);
+
+ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN):
+ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO):
+ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM):
+ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM):
+ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
+ return ieee754dp_nanxcpt(x, "mul", x, y);
+
+ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
+ return ieee754dp_bestnan(x, y);
+
+ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
+ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
+ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN):
+ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN):
+ return y;
+
+ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO):
+ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM):
+ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM):
+ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF):
+ return x;
+
+
+ /* Infinity handeling */
+
+ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO):
+ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF):
+ SETCX(IEEE754_INVALID_OPERATION);
+ return ieee754dp_xcpt(ieee754dp_indef(), "mul", x, y);
+
+ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF):
+ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF):
+ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM):
+ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
+ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
+ return ieee754dp_inf(xs ^ ys);
+
+ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
+ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM):
+ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM):
+ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO):
+ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO):
+ return ieee754dp_zero(xs ^ ys);
+
+
+ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
+ DPDNORMX;
+
+ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM):
+ DPDNORMY;
+ break;
+
+ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM):
+ DPDNORMX;
+ break;
+
+ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM):
+ break;
+ }
+ /* rm = xm * ym, re = xe+ye basicly */
+ assert(xm & DP_HIDDEN_BIT);
+ assert(ym & DP_HIDDEN_BIT);
+ {
+ int re = xe + ye;
+ int rs = xs ^ ys;
+ unsigned long long rm;
+
+ /* shunt to top of word */
+ xm <<= 64 - (DP_MBITS + 1);
+ ym <<= 64 - (DP_MBITS + 1);
+
+ /* multiply 32bits xm,ym to give high 32bits rm with stickness
+ */
+
+ /* 32 * 32 => 64 */
+#define DPXMULT(x,y) ((unsigned long long)(x) * (unsigned long long)y)
+
+ {
+ unsigned lxm = xm;
+ unsigned hxm = xm >> 32;
+ unsigned lym = ym;
+ unsigned hym = ym >> 32;
+ unsigned long long lrm;
+ unsigned long long hrm;
+
+ lrm = DPXMULT(lxm, lym);
+ hrm = DPXMULT(hxm, hym);
+
+ {
+ unsigned long long t = DPXMULT(lxm, hym);
+ {
+ unsigned long long at =
+ lrm + (t << 32);
+ hrm += at < lrm;
+ lrm = at;
+ }
+ hrm = hrm + (t >> 32);
+ }
+
+ {
+ unsigned long long t = DPXMULT(hxm, lym);
+ {
+ unsigned long long at =
+ lrm + (t << 32);
+ hrm += at < lrm;
+ lrm = at;
+ }
+ hrm = hrm + (t >> 32);
+ }
+ rm = hrm | (lrm != 0);
+ }
+
+ /*
+ * sticky shift down to normal rounding precision
+ */
+ if ((signed long long) rm < 0) {
+ rm =
+ (rm >> (64 - (DP_MBITS + 1 + 3))) |
+ ((rm << (DP_MBITS + 1 + 3)) != 0);
+ re++;
+ } else {
+ rm =
+ (rm >> (64 - (DP_MBITS + 1 + 3 + 1))) |
+ ((rm << (DP_MBITS + 1 + 3 + 1)) != 0);
+ }
+ assert(rm & (DP_HIDDEN_BIT << 3));
+ DPNORMRET2(rs, re, rm, "mul", x, y);
+ }
+}
--- /dev/null
+/* IEEE754 floating point arithmetic
+ * double precision: common utilities
+ */
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+
+#include "ieee754dp.h"
+
+ieee754dp ieee754dp_scalb(ieee754dp x, int n)
+{
+ COMPXDP;
+
+ CLEARCX;
+
+ EXPLODEXDP;
+
+ switch (xc) {
+ case IEEE754_CLASS_SNAN:
+ return ieee754dp_nanxcpt(x, "scalb", x, n);
+ case IEEE754_CLASS_QNAN:
+ case IEEE754_CLASS_INF:
+ case IEEE754_CLASS_ZERO:
+ return x;
+ case IEEE754_CLASS_DNORM:
+ DPDNORMX;
+ break;
+ case IEEE754_CLASS_NORM:
+ break;
+ }
+ DPNORMRET2(xs, xe + n, xm << 3, "scalb", x, n);
+}
+
+
+ieee754dp ieee754dp_ldexp(ieee754dp x, int n)
+{
+ return ieee754dp_scalb(x, n);
+}
--- /dev/null
+/* IEEE754 floating point arithmetic
+ * double precision: common utilities
+ */
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+
+#include "ieee754dp.h"
+
+int ieee754dp_finite(ieee754dp x)
+{
+ return DPBEXP(x) != DP_EMAX + 1 + DP_EBIAS;
+}
+
+ieee754dp ieee754dp_copysign(ieee754dp x, ieee754dp y)
+{
+ CLEARCX;
+ DPSIGN(x) = DPSIGN(y);
+ return x;
+}
+
+
+ieee754dp ieee754dp_neg(ieee754dp x)
+{
+ CLEARCX;
+
+ if (ieee754dp_isnan(x)) /* but not infinity */
+ return ieee754dp_nanxcpt(x, "neg", x);
+
+ /* quick fix up */
+ DPSIGN(x) ^= 1;
+ return x;
+}
+
+
+ieee754dp ieee754dp_abs(ieee754dp x)
+{
+ CLEARCX;
+
+ if (ieee754dp_isnan(x)) /* but not infinity */
+ return ieee754dp_nanxcpt(x, "abs", x);
+
+ /* quick fix up */
+ DPSIGN(x) = 0;
+ return x;
+}
--- /dev/null
+/* IEEE754 floating point arithmetic
+ * double precision square root
+ */
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+
+#include "ieee754dp.h"
+
+static const struct ieee754dp_konst knan = {
+#if (defined(BYTE_ORDER) && BYTE_ORDER == LITTLE_ENDIAN) || defined(__MIPSEL__)
+ 0, 0, DP_EBIAS + DP_EMAX + 1, 0
+#else
+ 0, DP_EBIAS + DP_EMAX + 1, 0, 0
+#endif
+};
+
+#define nan ((ieee754dp)knan)
+
+static const unsigned table[] = {
+ 0, 1204, 3062, 5746, 9193, 13348, 18162, 23592,
+ 29598, 36145, 43202, 50740, 58733, 67158, 75992,
+ 85215, 83599, 71378, 60428, 50647, 41945, 34246,
+ 27478, 21581, 16499, 12183, 8588, 5674, 3403,
+ 1742, 661, 130
+};
+
+ieee754dp ieee754dp_sqrt(ieee754dp x)
+{
+ struct ieee754_csr oldcsr;
+ ieee754dp y, z, t;
+ unsigned scalx, yh;
+ COMPXDP;
+
+ EXPLODEXDP;
+
+ /* x == INF or NAN? */
+ switch (xc) {
+ case IEEE754_CLASS_QNAN:
+ case IEEE754_CLASS_SNAN:
+ /* sqrt(Nan) = Nan */
+ return ieee754dp_nanxcpt(x, "sqrt");
+ case IEEE754_CLASS_ZERO:
+ /* sqrt(0) = 0 */
+ return x;
+ case IEEE754_CLASS_INF:
+ if (xs)
+ /* sqrt(-Inf) = Nan */
+ return ieee754dp_nanxcpt(nan, "sqrt");
+ /* sqrt(+Inf) = Inf */
+ return x;
+ case IEEE754_CLASS_DNORM:
+ DPDNORMX;
+ /* fall through */
+ case IEEE754_CLASS_NORM:
+ if (xs)
+ /* sqrt(-x) = Nan */
+ return ieee754dp_nanxcpt(nan, "sqrt");
+ break;
+ }
+
+ /* save old csr; switch off INX enable & flag; set RN rounding */
+ oldcsr = ieee754_csr;
+ ieee754_csr.mx &= ~IEEE754_INEXACT;
+ ieee754_csr.sx &= ~IEEE754_INEXACT;
+ ieee754_csr.rm = IEEE754_RN;
+
+ /* adjust exponent to prevent overflow */
+ scalx = 0;
+ if (xe > 512) { /* x > 2**-512? */
+ xe -= 512; /* x = x / 2**512 */
+ scalx += 256;
+ } else if (xe < -512) { /* x < 2**-512? */
+ xe += 512; /* x = x * 2**512 */
+ scalx -= 256;
+ }
+
+ y = x = builddp(0, xe + DP_EBIAS, xm & ~DP_HIDDEN_BIT);
+
+ /* magic initial approximation to almost 8 sig. bits */
+ yh = y.bits >> 32;
+ yh = (yh >> 1) + 0x1ff80000;
+ yh = yh - table[(yh >> 15) & 31];
+ y.bits = ((unsigned long long) yh << 32) | (y.bits & 0xffffffff);
+
+ /* Heron's rule once with correction to improve to ~18 sig. bits */
+ /* t=x/y; y=y+t; py[n0]=py[n0]-0x00100006; py[n1]=0; */
+ t = ieee754dp_div(x, y);
+ y = ieee754dp_add(y, t);
+ y.bits -= 0x0010000600000000LL;
+ y.bits &= 0xffffffff00000000LL;
+
+ /* triple to almost 56 sig. bits: y ~= sqrt(x) to within 1 ulp */
+ /* t=y*y; z=t; pt[n0]+=0x00100000; t+=z; z=(x-z)*y; */
+ z = t = ieee754dp_mul(y, y);
+ t.parts.bexp += 0x001;
+ t = ieee754dp_add(t, z);
+ z = ieee754dp_mul(ieee754dp_sub(x, z), y);
+
+ /* t=z/(t+x) ; pt[n0]+=0x00100000; y+=t; */
+ t = ieee754dp_div(z, ieee754dp_add(t, x));
+ t.parts.bexp += 0x001;
+ y = ieee754dp_add(y, t);
+
+ /* twiddle last bit to force y correctly rounded */
+
+ /* set RZ, clear INEX flag */
+ ieee754_csr.rm = IEEE754_RZ;
+ ieee754_csr.sx &= ~IEEE754_INEXACT;
+
+ /* t=x/y; ...chopped quotient, possibly inexact */
+ t = ieee754dp_div(x, y);
+
+ if (ieee754_csr.sx & IEEE754_INEXACT || t.bits != y.bits) {
+
+ if (!(ieee754_csr.sx & IEEE754_INEXACT))
+ /* t = t-ulp */
+ t.bits -= 1;
+
+ /* add inexact to result status */
+ oldcsr.cx |= IEEE754_INEXACT;
+ oldcsr.sx |= IEEE754_INEXACT;
+
+ switch (oldcsr.rm) {
+ case IEEE754_RP:
+ y.bits += 1;
+ /* drop through */
+ case IEEE754_RN:
+ t.bits += 1;
+ break;
+ }
+
+ /* y=y+t; ...chopped sum */
+ y = ieee754dp_add(y, t);
+
+ /* adjust scalx for correctly rounded sqrt(x) */
+ scalx -= 1;
+ }
+
+ /* py[n0]=py[n0]+scalx; ...scale back y */
+ y.parts.bexp += scalx;
+
+ /* restore rounding mode, possibly set inexact */
+ ieee754_csr = oldcsr;
+
+ return y;
+}
--- /dev/null
+/* IEEE754 floating point arithmetic
+ * double precision: common utilities
+ */
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+
+#include "ieee754dp.h"
+
+ieee754dp ieee754dp_sub(ieee754dp x, ieee754dp y)
+{
+ COMPXDP;
+ COMPYDP;
+
+ CLEARCX;
+
+ EXPLODEXDP;
+ EXPLODEYDP;
+
+ switch (CLPAIR(xc, yc)) {
+ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN):
+ return ieee754dp_nanxcpt(ieee754dp_bestnan(x, y), "sub", x,
+ y);
+
+ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN):
+ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN):
+ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN):
+ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN):
+ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN):
+ return ieee754dp_nanxcpt(y, "sub", x, y);
+
+ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN):
+ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO):
+ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM):
+ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM):
+ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
+ return ieee754dp_nanxcpt(x, "sub", x, y);
+
+ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
+ return ieee754dp_bestnan(x, y);
+
+ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
+ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
+ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN):
+ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN):
+ return y;
+
+ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO):
+ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM):
+ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM):
+ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF):
+ return x;
+
+
+ /* Inifity handeling
+ */
+
+ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
+ if (xs != ys)
+ return x;
+ SETCX(IEEE754_INVALID_OPERATION);
+ return ieee754dp_xcpt(ieee754dp_indef(), "sub", x, y);
+
+ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF):
+ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF):
+ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF):
+ return ieee754dp_inf(ys ^ 1);
+
+ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO):
+ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM):
+ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
+ return x;
+
+ /* Zero handeling
+ */
+
+ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
+ if (xs != ys)
+ return x;
+ else
+ return ieee754dp_zero(ieee754_csr.rm ==
+ IEEE754_RD);
+
+ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO):
+ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO):
+ return x;
+
+ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM):
+ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM):
+ /* quick fix up */
+ DPSIGN(y) ^= 1;
+ return y;
+
+ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
+ DPDNORMX;
+ /* FAAL THOROUGH */
+
+ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM):
+ /* normalize ym,ye */
+ DPDNORMY;
+ break;
+
+ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM):
+ /* normalize xm,xe */
+ DPDNORMX;
+ break;
+
+ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM):
+ break;
+ }
+ /* flip sign of y and handle as add */
+ ys ^= 1;
+
+ assert(xm & DP_HIDDEN_BIT);
+ assert(ym & DP_HIDDEN_BIT);
+
+
+ /* provide guard,round and stick bit dpace */
+ xm <<= 3;
+ ym <<= 3;
+
+ if (xe > ye) {
+ /* have to shift y fraction right to align
+ */
+ int s = xe - ye;
+ ym = XDPSRS(ym, s);
+ ye += s;
+ } else if (ye > xe) {
+ /* have to shift x fraction right to align
+ */
+ int s = ye - xe;
+ xm = XDPSRS(xm, s);
+ xe += s;
+ }
+ assert(xe == ye);
+ assert(xe <= DP_EMAX);
+
+ if (xs == ys) {
+ /* generate 28 bit result of adding two 27 bit numbers
+ */
+ xm = xm + ym;
+ xe = xe;
+ xs = xs;
+
+ if (xm >> (DP_MBITS + 1 + 3)) { /* carry out */
+ xm = XDPSRS1(xm); /* shift preserving sticky */
+ xe++;
+ }
+ } else {
+ if (xm >= ym) {
+ xm = xm - ym;
+ xe = xe;
+ xs = xs;
+ } else {
+ xm = ym - xm;
+ xe = xe;
+ xs = ys;
+ }
+ if (xm == 0)
+ if (ieee754_csr.rm == IEEE754_RD)
+ return ieee754dp_zero(1); /* round negative inf. => sign = -1 */
+ else
+ return ieee754dp_zero(0); /* other round modes => sign = 1 */
+
+ /* normalize to rounding precision
+ */
+ while ((xm >> (DP_MBITS + 3)) == 0) {
+ xm <<= 1;
+ xe--;
+ }
+ }
+ DPNORMRET2(xs, xe, xm, "sub", x, y);
+}
--- /dev/null
+/* IEEE754 floating point arithmetic
+ * double precision: common utilities
+ */
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+
+#include <linux/kernel.h>
+#include "ieee754dp.h"
+
+int ieee754dp_tint(ieee754dp x)
+{
+ COMPXDP;
+
+ CLEARCX;
+
+ EXPLODEXDP;
+
+ switch (xc) {
+ case IEEE754_CLASS_SNAN:
+ case IEEE754_CLASS_QNAN:
+ SETCX(IEEE754_INVALID_OPERATION);
+ return ieee754si_xcpt(ieee754si_indef(), "fixdp", x);
+ case IEEE754_CLASS_INF:
+ SETCX(IEEE754_OVERFLOW);
+ return ieee754si_xcpt(ieee754si_indef(), "fixdp", x);
+ case IEEE754_CLASS_ZERO:
+ return 0;
+ case IEEE754_CLASS_DNORM: /* much to small */
+ SETCX(IEEE754_UNDERFLOW);
+ return ieee754si_xcpt(0, "fixdp", x);
+ case IEEE754_CLASS_NORM:
+ break;
+ }
+ if (xe >= 31) {
+ SETCX(IEEE754_OVERFLOW);
+ return ieee754si_xcpt(ieee754si_indef(), "fix", x);
+ }
+ if (xe < 0) {
+ SETCX(IEEE754_UNDERFLOW);
+ return ieee754si_xcpt(0, "fix", x);
+ }
+ /* oh gawd */
+ if (xe > DP_MBITS) {
+ xm <<= xe - DP_MBITS;
+ } else if (xe < DP_MBITS) {
+ /* XXX no rounding
+ */
+ xm >>= DP_MBITS - xe;
+ }
+ if (xs)
+ return -xm;
+ else
+ return xm;
+}
+
+
+unsigned int ieee754dp_tuns(ieee754dp x)
+{
+ ieee754dp hb = ieee754dp_1e31();
+
+ /* what if x < 0 ?? */
+ if (ieee754dp_lt(x, hb))
+ return (unsigned) ieee754dp_tint(x);
+
+ return (unsigned) ieee754dp_tint(ieee754dp_sub(x, hb)) |
+ ((unsigned) 1 << 31);
+}
--- /dev/null
+/* IEEE754 floating point arithmetic
+ * double precision: common utilities
+ */
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+
+#include "ieee754dp.h"
+
+long long ieee754dp_tlong(ieee754dp x)
+{
+ COMPXDP;
+
+ CLEARCX;
+
+ EXPLODEXDP;
+
+ switch (xc) {
+ case IEEE754_CLASS_SNAN:
+ case IEEE754_CLASS_QNAN:
+ SETCX(IEEE754_INVALID_OPERATION);
+ return ieee754di_xcpt(ieee754di_indef(), "dp_tlong", x);
+ case IEEE754_CLASS_INF:
+ SETCX(IEEE754_OVERFLOW);
+ return ieee754di_xcpt(ieee754di_indef(), "dp_tlong", x);
+ case IEEE754_CLASS_ZERO:
+ return 0;
+ case IEEE754_CLASS_DNORM: /* much too small */
+ SETCX(IEEE754_UNDERFLOW);
+ return ieee754di_xcpt(0, "dp_tlong", x);
+ case IEEE754_CLASS_NORM:
+ break;
+ }
+ if (xe >= 63) {
+ SETCX(IEEE754_OVERFLOW);
+ return ieee754di_xcpt(ieee754di_indef(), "dp_tlong", x);
+ }
+ if (xe < 0) {
+ if (ieee754_csr.rm == IEEE754_RU) {
+ if (xs) { /* Negative */
+ return 0x0000000000000000LL;
+ } else { /* Positive */
+ return 0x0000000000000001LL;
+ }
+ } else if (ieee754_csr.rm == IEEE754_RD) {
+ if (xs) { /* Negative , return -1 */
+ return 0xffffffffffffffffLL;
+ } else { /* Positive */
+ return 0x0000000000000000LL;
+ }
+ } else {
+ SETCX(IEEE754_UNDERFLOW);
+ return ieee754di_xcpt(0, "dp_tlong", x);
+ }
+ }
+ /* oh gawd */
+ if (xe > DP_MBITS) {
+ xm <<= xe - DP_MBITS;
+ } else if (xe < DP_MBITS) {
+ unsigned long long residue;
+ unsigned long long mask = 0;
+ int i;
+ int round;
+ int sticky;
+ int odd;
+
+ /* compute mask */
+ for (i = 0; i < DP_MBITS - xe; i++) {
+ mask = mask << 1;
+ mask = mask | 0x1;
+ }
+ residue = (xm & mask) << (64 - (DP_MBITS - xe));
+ round =
+ ((0x8000000000000000LL & residue) !=
+ 0x0000000000000000LL);
+ sticky =
+ ((0x7fffffffffffffffLL & residue) !=
+ 0x0000000000000000LL);
+
+ xm >>= DP_MBITS - xe;
+
+ odd = ((xm & 0x1) != 0x0000000000000000LL);
+
+ /* Do the rounding */
+ if (!round && sticky) {
+ if ((ieee754_csr.rm == IEEE754_RU && !xs)
+ || (ieee754_csr.rm == IEEE754_RD && xs)) {
+ xm++;
+ }
+ } else if (round && !sticky) {
+ if ((ieee754_csr.rm == IEEE754_RU && !xs)
+ || (ieee754_csr.rm == IEEE754_RD && xs)
+ || (ieee754_csr.rm == IEEE754_RN && odd)) {
+ xm++;
+ }
+ } else if (round && sticky) {
+ if ((ieee754_csr.rm == IEEE754_RU && !xs)
+ || (ieee754_csr.rm == IEEE754_RD && xs)
+ || (ieee754_csr.rm == IEEE754_RN)) {
+ xm++;
+ }
+ }
+ }
+ if (xs)
+ return -xm;
+ else
+ return xm;
+}
+
+
+unsigned long long ieee754dp_tulong(ieee754dp x)
+{
+ ieee754dp hb = ieee754dp_1e63();
+
+ /* what if x < 0 ?? */
+ if (ieee754dp_lt(x, hb))
+ return (unsigned long long) ieee754dp_tlong(x);
+
+ return (unsigned long long) ieee754dp_tlong(ieee754dp_sub(x, hb)) |
+ (1ULL << 63);
+}
--- /dev/null
+/* ieee754 floating point arithmetic
+ * single and double precision
+ *
+ * BUGS
+ * not much dp done
+ * doesnt generate IEEE754_INEXACT
+ *
+ */
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+
+#include "ieee754int.h"
+
+#define DP_EBIAS 1023
+#define DP_EMIN (-1022)
+#define DP_EMAX 1023
+
+#define SP_EBIAS 127
+#define SP_EMIN (-126)
+#define SP_EMAX 127
+
+/* indexed by class */
+const char *const ieee754_cname[] = {
+ "Normal",
+ "Zero",
+ "Denormal",
+ "Infinity",
+ "QNaN",
+ "SNaN",
+};
+
+/* the control status register
+*/
+struct ieee754_csr ieee754_csr;
+
+/* special constants
+*/
+
+
+#if (defined(BYTE_ORDER) && BYTE_ORDER == LITTLE_ENDIAN) || defined(__MIPSEL__)
+#define SPSTR(s,b,m) {m,b,s}
+#define DPSTR(s,b,mh,ml) {ml,mh,b,s}
+#endif
+
+#ifdef __MIPSEB__
+#define SPSTR(s,b,m) {s,b,m}
+#define DPSTR(s,b,mh,ml) {s,b,mh,ml}
+#endif
+
+const struct ieee754dp_konst __ieee754dp_spcvals[] = {
+ DPSTR(0, DP_EMIN - 1 + DP_EBIAS, 0, 0), /* + zero */
+ DPSTR(1, DP_EMIN - 1 + DP_EBIAS, 0, 0), /* - zero */
+ DPSTR(0, DP_EBIAS, 0, 0), /* + 1.0 */
+ DPSTR(1, DP_EBIAS, 0, 0), /* - 1.0 */
+ DPSTR(0, 3 + DP_EBIAS, 0x40000, 0), /* + 10.0 */
+ DPSTR(1, 3 + DP_EBIAS, 0x40000, 0), /* - 10.0 */
+ DPSTR(0, DP_EMAX + 1 + DP_EBIAS, 0, 0), /* + infinity */
+ DPSTR(1, DP_EMAX + 1 + DP_EBIAS, 0, 0), /* - infinity */
+ DPSTR(0, DP_EMAX + 1 + DP_EBIAS, 0x40000, 0), /* + indef quiet Nan */
+ DPSTR(0, DP_EMAX + DP_EBIAS, 0xFFFFF, 0xFFFFFFFF), /* + max */
+ DPSTR(1, DP_EMAX + DP_EBIAS, 0xFFFFF, 0xFFFFFFFF), /* - max */
+ DPSTR(0, DP_EMIN + DP_EBIAS, 0, 0), /* + min normal */
+ DPSTR(1, DP_EMIN + DP_EBIAS, 0, 0), /* - min normal */
+ DPSTR(0, DP_EMIN - 1 + DP_EBIAS, 0, 1), /* + min denormal */
+ DPSTR(1, DP_EMIN - 1 + DP_EBIAS, 0, 1), /* - min denormal */
+ DPSTR(0, 31 + DP_EBIAS, 0, 0), /* + 1.0e31 */
+ DPSTR(0, 63 + DP_EBIAS, 0, 0), /* + 1.0e63 */
+};
+
+const struct ieee754sp_konst __ieee754sp_spcvals[] = {
+ SPSTR(0, SP_EMIN - 1 + SP_EBIAS, 0), /* + zero */
+ SPSTR(1, SP_EMIN - 1 + SP_EBIAS, 0), /* - zero */
+ SPSTR(0, SP_EBIAS, 0), /* + 1.0 */
+ SPSTR(1, SP_EBIAS, 0), /* - 1.0 */
+ SPSTR(0, 3 + SP_EBIAS, 0x200000), /* + 10.0 */
+ SPSTR(1, 3 + SP_EBIAS, 0x200000), /* - 10.0 */
+ SPSTR(0, SP_EMAX + 1 + SP_EBIAS, 0), /* + infinity */
+ SPSTR(1, SP_EMAX + 1 + SP_EBIAS, 0), /* - infinity */
+ SPSTR(0, SP_EMAX + 1 + SP_EBIAS, 0x200000), /* + indef quiet Nan */
+ SPSTR(0, SP_EMAX + SP_EBIAS, 0x7FFFFF), /* + max normal */
+ SPSTR(1, SP_EMAX + SP_EBIAS, 0x7FFFFF), /* - max normal */
+ SPSTR(0, SP_EMIN + SP_EBIAS, 0), /* + min normal */
+ SPSTR(1, SP_EMIN + SP_EBIAS, 0), /* - min normal */
+ SPSTR(0, SP_EMIN - 1 + SP_EBIAS, 1), /* + min denormal */
+ SPSTR(1, SP_EMIN - 1 + SP_EBIAS, 1), /* - min denormal */
+ SPSTR(0, 31 + SP_EBIAS, 0), /* + 1.0e31 */
+ SPSTR(0, 63 + SP_EBIAS, 0), /* + 1.0e63 */
+};
+
+
+int ieee754si_xcpt(int r, const char *op, ...)
+{
+ struct ieee754xctx ax;
+
+ if (!TSTX())
+ return r;
+ ax.op = op;
+ ax.rt = IEEE754_RT_SI;
+ ax.rv.si = r;
+ va_start(ax.ap, op);
+ ieee754_xcpt(&ax);
+ return ax.rv.si;
+}
+
+long long ieee754di_xcpt(long long r, const char *op, ...)
+{
+ struct ieee754xctx ax;
+
+ if (!TSTX())
+ return r;
+ ax.op = op;
+ ax.rt = IEEE754_RT_DI;
+ ax.rv.di = r;
+ va_start(ax.ap, op);
+ ieee754_xcpt(&ax);
+ return ax.rv.di;
+}
--- /dev/null
+/* single and double precision fp ops
+ * missing extended precision.
+*/
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+/**************************************************************************
+ * Nov 7, 2000
+ * Modification to allow integration with Linux kernel
+ *
+ * Kevin D. Kissell, kevink@mips.com and Carsten Langgard, carstenl@mips.com
+ * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved.
+ *************************************************************************/
+
+#ifdef __KERNEL__
+/* Going from Algorithmics to Linux native environment, add this */
+#include <linux/types.h>
+
+/*
+ * Not very pretty, but the Linux kernel's normal va_list definition
+ * does not allow it to be used as a structure element, as it is here.
+ */
+#ifndef _STDARG_H
+#include <stdarg.h>
+#endif
+
+#else
+
+/* Note that __KERNEL__ is taken to mean Linux kernel */
+
+#if #system(OpenBSD)
+#include <machine/types.h>
+#endif
+#include <machine/endian.h>
+
+#endif /* __KERNEL__ */
+
+#if (defined(BYTE_ORDER) && BYTE_ORDER == LITTLE_ENDIAN) || defined(__MIPSEL__)
+struct ieee754dp_konst {
+ unsigned mantlo:32;
+ unsigned manthi:20;
+ unsigned bexp:11;
+ unsigned sign:1;
+};
+struct ieee754sp_konst {
+ unsigned mant:23;
+ unsigned bexp:8;
+ unsigned sign:1;
+};
+
+typedef union _ieee754dp {
+ struct ieee754dp_konst oparts;
+ struct {
+ unsigned long long mant:52;
+ unsigned int bexp:11;
+ unsigned int sign:1;
+ } parts;
+ unsigned long long bits;
+ double d;
+} ieee754dp;
+
+typedef union _ieee754sp {
+ struct ieee754sp_konst parts;
+ float f;
+ unsigned long bits;
+} ieee754sp;
+#endif
+
+#if (defined(BYTE_ORDER) && BYTE_ORDER == BIG_ENDIAN) || defined(__MIPSEB__)
+struct ieee754dp_konst {
+ unsigned sign:1;
+ unsigned bexp:11;
+ unsigned manthi:20;
+ unsigned mantlo:32;
+};
+typedef union _ieee754dp {
+ struct ieee754dp_konst oparts;
+ struct {
+ unsigned int sign:1;
+ unsigned int bexp:11;
+ unsigned long long mant:52;
+ } parts;
+ double d;
+ unsigned long long bits;
+} ieee754dp;
+
+struct ieee754sp_konst {
+ unsigned sign:1;
+ unsigned bexp:8;
+ unsigned mant:23;
+};
+
+typedef union _ieee754sp {
+ struct ieee754sp_konst parts;
+ float f;
+ unsigned long bits;
+} ieee754sp;
+#endif
+
+/*
+ * single precision (often aka float)
+*/
+int ieee754sp_finite(ieee754sp x);
+int ieee754sp_class(ieee754sp x);
+
+ieee754sp ieee754sp_abs(ieee754sp x);
+ieee754sp ieee754sp_neg(ieee754sp x);
+ieee754sp ieee754sp_scalb(ieee754sp x, int);
+ieee754sp ieee754sp_logb(ieee754sp x);
+
+/* x with sign of y */
+ieee754sp ieee754sp_copysign(ieee754sp x, ieee754sp y);
+
+ieee754sp ieee754sp_add(ieee754sp x, ieee754sp y);
+ieee754sp ieee754sp_sub(ieee754sp x, ieee754sp y);
+ieee754sp ieee754sp_mul(ieee754sp x, ieee754sp y);
+ieee754sp ieee754sp_div(ieee754sp x, ieee754sp y);
+
+ieee754sp ieee754sp_fint(int x);
+ieee754sp ieee754sp_funs(unsigned x);
+ieee754sp ieee754sp_flong(long long x);
+ieee754sp ieee754sp_fulong(unsigned long long x);
+ieee754sp ieee754sp_fdp(ieee754dp x);
+
+int ieee754sp_tint(ieee754sp x);
+unsigned int ieee754sp_tuns(ieee754sp x);
+long long ieee754sp_tlong(ieee754sp x);
+unsigned long long ieee754sp_tulong(ieee754sp x);
+
+int ieee754sp_cmp(ieee754sp x, ieee754sp y, int cop);
+/*
+ * basic sp math
+ */
+ieee754sp ieee754sp_modf(ieee754sp x, ieee754sp * ip);
+ieee754sp ieee754sp_frexp(ieee754sp x, int *exp);
+ieee754sp ieee754sp_ldexp(ieee754sp x, int exp);
+
+ieee754sp ieee754sp_ceil(ieee754sp x);
+ieee754sp ieee754sp_floor(ieee754sp x);
+ieee754sp ieee754sp_trunc(ieee754sp x);
+
+ieee754sp ieee754sp_sqrt(ieee754sp x);
+
+/*
+ * double precision (often aka double)
+*/
+int ieee754dp_finite(ieee754dp x);
+int ieee754dp_class(ieee754dp x);
+
+/* x with sign of y */
+ieee754dp ieee754dp_copysign(ieee754dp x, ieee754dp y);
+
+ieee754dp ieee754dp_add(ieee754dp x, ieee754dp y);
+ieee754dp ieee754dp_sub(ieee754dp x, ieee754dp y);
+ieee754dp ieee754dp_mul(ieee754dp x, ieee754dp y);
+ieee754dp ieee754dp_div(ieee754dp x, ieee754dp y);
+
+ieee754dp ieee754dp_abs(ieee754dp x);
+ieee754dp ieee754dp_neg(ieee754dp x);
+ieee754dp ieee754dp_scalb(ieee754dp x, int);
+
+/* return exponent as integer in floating point format
+ */
+ieee754dp ieee754dp_logb(ieee754dp x);
+
+ieee754dp ieee754dp_fint(int x);
+ieee754dp ieee754dp_funs(unsigned x);
+ieee754dp ieee754dp_flong(long long x);
+ieee754dp ieee754dp_fulong(unsigned long long x);
+ieee754dp ieee754dp_fsp(ieee754sp x);
+
+ieee754dp ieee754dp_ceil(ieee754dp x);
+ieee754dp ieee754dp_floor(ieee754dp x);
+ieee754dp ieee754dp_trunc(ieee754dp x);
+
+int ieee754dp_tint(ieee754dp x);
+unsigned int ieee754dp_tuns(ieee754dp x);
+long long ieee754dp_tlong(ieee754dp x);
+unsigned long long ieee754dp_tulong(ieee754dp x);
+
+int ieee754dp_cmp(ieee754dp x, ieee754dp y, int cop);
+/*
+ * basic sp math
+ */
+ieee754dp ieee754dp_modf(ieee754dp x, ieee754dp * ip);
+ieee754dp ieee754dp_frexp(ieee754dp x, int *exp);
+ieee754dp ieee754dp_ldexp(ieee754dp x, int exp);
+
+ieee754dp ieee754dp_ceil(ieee754dp x);
+ieee754dp ieee754dp_floor(ieee754dp x);
+ieee754dp ieee754dp_trunc(ieee754dp x);
+
+ieee754dp ieee754dp_sqrt(ieee754dp x);
+
+
+
+/* 5 types of floating point number
+*/
+#define IEEE754_CLASS_NORM 0x00
+#define IEEE754_CLASS_ZERO 0x01
+#define IEEE754_CLASS_DNORM 0x02
+#define IEEE754_CLASS_INF 0x03
+#define IEEE754_CLASS_SNAN 0x04
+#define IEEE754_CLASS_QNAN 0x05
+extern const char *const ieee754_cname[];
+
+/* exception numbers */
+#define IEEE754_INEXACT 0x01
+#define IEEE754_UNDERFLOW 0x02
+#define IEEE754_OVERFLOW 0x04
+#define IEEE754_ZERO_DIVIDE 0x08
+#define IEEE754_INVALID_OPERATION 0x10
+
+/* cmp operators
+*/
+#define IEEE754_CLT 0x01
+#define IEEE754_CEQ 0x02
+#define IEEE754_CGT 0x04
+#define IEEE754_CUN 0x08
+
+/* rounding mode
+*/
+#define IEEE754_RN 0 /* round to nearest */
+#define IEEE754_RZ 1 /* round toward zero */
+#define IEEE754_RD 2 /* round toward -Infinity */
+#define IEEE754_RU 3 /* round toward +Infinity */
+
+/* other naming */
+#define IEEE754_RM IEEE754_RD
+#define IEEE754_RP IEEE754_RU
+
+/* "normal" comparisons
+*/
+static __inline int ieee754sp_eq(ieee754sp x, ieee754sp y)
+{
+ return ieee754sp_cmp(x, y, IEEE754_CEQ);
+}
+
+static __inline int ieee754sp_ne(ieee754sp x, ieee754sp y)
+{
+ return ieee754sp_cmp(x, y,
+ IEEE754_CLT | IEEE754_CGT | IEEE754_CUN);
+}
+
+static __inline int ieee754sp_lt(ieee754sp x, ieee754sp y)
+{
+ return ieee754sp_cmp(x, y, IEEE754_CLT);
+}
+
+static __inline int ieee754sp_le(ieee754sp x, ieee754sp y)
+{
+ return ieee754sp_cmp(x, y, IEEE754_CLT | IEEE754_CEQ);
+}
+
+static __inline int ieee754sp_gt(ieee754sp x, ieee754sp y)
+{
+ return ieee754sp_cmp(x, y, IEEE754_CGT);
+}
+
+
+static __inline int ieee754sp_ge(ieee754sp x, ieee754sp y)
+{
+ return ieee754sp_cmp(x, y, IEEE754_CGT | IEEE754_CEQ);
+}
+
+static __inline int ieee754dp_eq(ieee754dp x, ieee754dp y)
+{
+ return ieee754dp_cmp(x, y, IEEE754_CEQ);
+}
+
+static __inline int ieee754dp_ne(ieee754dp x, ieee754dp y)
+{
+ return ieee754dp_cmp(x, y,
+ IEEE754_CLT | IEEE754_CGT | IEEE754_CUN);
+}
+
+static __inline int ieee754dp_lt(ieee754dp x, ieee754dp y)
+{
+ return ieee754dp_cmp(x, y, IEEE754_CLT);
+}
+
+static __inline int ieee754dp_le(ieee754dp x, ieee754dp y)
+{
+ return ieee754dp_cmp(x, y, IEEE754_CLT | IEEE754_CEQ);
+}
+
+static __inline int ieee754dp_gt(ieee754dp x, ieee754dp y)
+{
+ return ieee754dp_cmp(x, y, IEEE754_CGT);
+}
+
+static __inline int ieee754dp_ge(ieee754dp x, ieee754dp y)
+{
+ return ieee754dp_cmp(x, y, IEEE754_CGT | IEEE754_CEQ);
+}
+
+
+/* like strtod
+*/
+ieee754dp ieee754dp_fstr(const char *s, char **endp);
+char *ieee754dp_tstr(ieee754dp x, int prec, int fmt, int af);
+
+
+/* the control status register
+*/
+struct ieee754_csr {
+ unsigned pad:13;
+ unsigned noq:1; /* set 1 for no quiet NaN's */
+ unsigned nod:1; /* set 1 for no denormalised numbers */
+ unsigned cx:5; /* exceptions this operation */
+ unsigned mx:5; /* exception enable mask */
+ unsigned sx:5; /* exceptions total */
+ unsigned rm:2; /* current rounding mode */
+};
+extern struct ieee754_csr ieee754_csr;
+
+static __inline unsigned ieee754_getrm(void)
+{
+ return (ieee754_csr.rm);
+}
+static __inline unsigned ieee754_setrm(unsigned rm)
+{
+ return (ieee754_csr.rm = rm);
+}
+
+/*
+ * get current exceptions
+ */
+static __inline unsigned ieee754_getcx(void)
+{
+ return (ieee754_csr.cx);
+}
+
+/* test for current exception condition
+ */
+static __inline int ieee754_cxtest(unsigned n)
+{
+ return (ieee754_csr.cx & n);
+}
+
+/*
+ * get sticky exceptions
+ */
+static __inline unsigned ieee754_getsx(void)
+{
+ return (ieee754_csr.sx);
+}
+
+/* clear sticky conditions
+*/
+static __inline unsigned ieee754_clrsx(void)
+{
+ return (ieee754_csr.sx = 0);
+}
+
+/* test for sticky exception condition
+ */
+static __inline int ieee754_sxtest(unsigned n)
+{
+ return (ieee754_csr.sx & n);
+}
+
+/* debugging */
+ieee754sp ieee754sp_dump(char *s, ieee754sp x);
+ieee754dp ieee754dp_dump(char *s, ieee754dp x);
+
+#define IEEE754_SPCVAL_PZERO 0
+#define IEEE754_SPCVAL_NZERO 1
+#define IEEE754_SPCVAL_PONE 2
+#define IEEE754_SPCVAL_NONE 3
+#define IEEE754_SPCVAL_PTEN 4
+#define IEEE754_SPCVAL_NTEN 5
+#define IEEE754_SPCVAL_PINFINITY 6
+#define IEEE754_SPCVAL_NINFINITY 7
+#define IEEE754_SPCVAL_INDEF 8
+#define IEEE754_SPCVAL_PMAX 9 /* +max norm */
+#define IEEE754_SPCVAL_NMAX 10 /* -max norm */
+#define IEEE754_SPCVAL_PMIN 11 /* +min norm */
+#define IEEE754_SPCVAL_NMIN 12 /* +min norm */
+#define IEEE754_SPCVAL_PMIND 13 /* +min denorm */
+#define IEEE754_SPCVAL_NMIND 14 /* +min denorm */
+#define IEEE754_SPCVAL_P1E31 15 /* + 1.0e31 */
+#define IEEE754_SPCVAL_P1E63 16 /* + 1.0e63 */
+
+extern const struct ieee754dp_konst __ieee754dp_spcvals[];
+extern const struct ieee754sp_konst __ieee754sp_spcvals[];
+#define ieee754dp_spcvals ((const ieee754dp *)__ieee754dp_spcvals)
+#define ieee754sp_spcvals ((const ieee754sp *)__ieee754sp_spcvals)
+
+/* return infinity with given sign
+*/
+#define ieee754dp_inf(sn) \
+ (ieee754dp_spcvals[IEEE754_SPCVAL_PINFINITY+(sn)])
+#define ieee754dp_zero(sn) \
+ (ieee754dp_spcvals[IEEE754_SPCVAL_PZERO+(sn)])
+#define ieee754dp_one(sn) \
+ (ieee754dp_spcvals[IEEE754_SPCVAL_PONE+(sn)])
+#define ieee754dp_ten(sn) \
+ (ieee754dp_spcvals[IEEE754_SPCVAL_PTEN+(sn)])
+#define ieee754dp_indef() \
+ (ieee754dp_spcvals[IEEE754_SPCVAL_INDEF])
+#define ieee754dp_max(sn) \
+ (ieee754dp_spcvals[IEEE754_SPCVAL_PMAX+(sn)])
+#define ieee754dp_min(sn) \
+ (ieee754dp_spcvals[IEEE754_SPCVAL_PMIN+(sn)])
+#define ieee754dp_mind(sn) \
+ (ieee754dp_spcvals[IEEE754_SPCVAL_PMIND+(sn)])
+#define ieee754dp_1e31() \
+ (ieee754dp_spcvals[IEEE754_SPCVAL_P1E31])
+#define ieee754dp_1e63() \
+ (ieee754dp_spcvals[IEEE754_SPCVAL_P1E63])
+
+#define ieee754sp_inf(sn) \
+ (ieee754sp_spcvals[IEEE754_SPCVAL_PINFINITY+(sn)])
+#define ieee754sp_zero(sn) \
+ (ieee754sp_spcvals[IEEE754_SPCVAL_PZERO+(sn)])
+#define ieee754sp_one(sn) \
+ (ieee754sp_spcvals[IEEE754_SPCVAL_PONE+(sn)])
+#define ieee754sp_ten(sn) \
+ (ieee754sp_spcvals[IEEE754_SPCVAL_PTEN+(sn)])
+#define ieee754sp_indef() \
+ (ieee754sp_spcvals[IEEE754_SPCVAL_INDEF])
+#define ieee754sp_max(sn) \
+ (ieee754sp_spcvals[IEEE754_SPCVAL_PMAX+(sn)])
+#define ieee754sp_min(sn) \
+ (ieee754sp_spcvals[IEEE754_SPCVAL_PMIN+(sn)])
+#define ieee754sp_mind(sn) \
+ (ieee754sp_spcvals[IEEE754_SPCVAL_PMIND+(sn)])
+#define ieee754sp_1e31() \
+ (ieee754sp_spcvals[IEEE754_SPCVAL_P1E31])
+#define ieee754sp_1e63() \
+ (ieee754sp_spcvals[IEEE754_SPCVAL_P1E63])
+
+/* indefinite integer value
+*/
+#define ieee754si_indef() INT_MIN
+#ifdef LONG_LONG_MIN
+#define ieee754di_indef() LONG_LONG_MIN
+#else
+#define ieee754di_indef() (-9223372036854775807LL-1)
+#endif
+
+/* IEEE exception context, passed to handler */
+struct ieee754xctx {
+ const char *op; /* operation name */
+ int rt; /* result type */
+ union {
+ ieee754sp sp; /* single precision */
+ ieee754dp dp; /* double precision */
+#ifdef IEEE854_XP
+ ieee754xp xp; /* extended precision */
+#endif
+ int si; /* standard signed integer (32bits) */
+ long long di; /* extended signed integer (64bits) */
+ } rv; /* default result format implied by op */
+ va_list ap;
+};
+
+/* result types for xctx.rt */
+#define IEEE754_RT_SP 0
+#define IEEE754_RT_DP 1
+#define IEEE754_RT_XP 2
+#define IEEE754_RT_SI 3
+#define IEEE754_RT_DI 4
+
+extern void ieee754_xcpt(struct ieee754xctx *xcp);
+
+/* compat */
+#define ieee754dp_fix(x) ieee754dp_tint(x)
+#define ieee754sp_fix(x) ieee754sp_tint(x)
--- /dev/null
+/* some debug functions
+*/
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+/**************************************************************************
+ * Nov 7, 2000
+ * Modified to build and operate in Linux kernel environment.
+ *
+ * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved.
+ *************************************************************************/
+
+#include "ieee754.h"
+
+#define DP_EBIAS 1023
+#define DP_EMIN (-1022)
+#define DP_EMAX 1023
+#define DP_FBITS 52
+
+#define SP_EBIAS 127
+#define SP_EMIN (-126)
+#define SP_EMAX 127
+#define SP_FBITS 23
+
+#define DP_MBIT(x) ((unsigned long long)1 << (x))
+#define DP_HIDDEN_BIT DP_MBIT(DP_FBITS)
+#define DP_SIGN_BIT DP_MBIT(63)
+
+
+#define SP_MBIT(x) ((unsigned long)1 << (x))
+#define SP_HIDDEN_BIT SP_MBIT(SP_FBITS)
+#define SP_SIGN_BIT SP_MBIT(31)
+
+
+#define SPSIGN(sp) (sp.parts.sign)
+#define SPBEXP(sp) (sp.parts.bexp)
+#define SPMANT(sp) (sp.parts.mant)
+
+#define DPSIGN(dp) (dp.parts.sign)
+#define DPBEXP(dp) (dp.parts.bexp)
+#define DPMANT(dp) (dp.parts.mant)
+
+ieee754dp ieee754dp_dump(char *m, ieee754dp x)
+{
+ int i;
+
+ printk("%s", m);
+ printk("<%08x,%08x>\n", (unsigned) (x.bits >> 32),
+ (unsigned) x.bits);
+ printk("\t=");
+ switch (ieee754dp_class(x)) {
+ case IEEE754_CLASS_QNAN:
+ case IEEE754_CLASS_SNAN:
+ printk("Nan %c", DPSIGN(x) ? '-' : '+');
+ for (i = DP_FBITS - 1; i >= 0; i--)
+ printk("%c", DPMANT(x) & DP_MBIT(i) ? '1' : '0');
+ break;
+ case IEEE754_CLASS_INF:
+ printk("%cInfinity", DPSIGN(x) ? '-' : '+');
+ break;
+ case IEEE754_CLASS_ZERO:
+ printk("%cZero", DPSIGN(x) ? '-' : '+');
+ break;
+ case IEEE754_CLASS_DNORM:
+ printk("%c0.", DPSIGN(x) ? '-' : '+');
+ for (i = DP_FBITS - 1; i >= 0; i--)
+ printk("%c", DPMANT(x) & DP_MBIT(i) ? '1' : '0');
+ printk("e%d", DPBEXP(x) - DP_EBIAS);
+ break;
+ case IEEE754_CLASS_NORM:
+ printk("%c1.", DPSIGN(x) ? '-' : '+');
+ for (i = DP_FBITS - 1; i >= 0; i--)
+ printk("%c", DPMANT(x) & DP_MBIT(i) ? '1' : '0');
+ printk("e%d", DPBEXP(x) - DP_EBIAS);
+ break;
+ default:
+ printk("Illegal/Unknown IEEE754 value class");
+ }
+ printk("\n");
+ return x;
+}
+
+ieee754sp ieee754sp_dump(char *m, ieee754sp x)
+{
+ int i;
+
+ printk("%s=", m);
+ printk("<%08x>\n", (unsigned) x.bits);
+ printk("\t=");
+ switch (ieee754sp_class(x)) {
+ case IEEE754_CLASS_QNAN:
+ case IEEE754_CLASS_SNAN:
+ printk("Nan %c", SPSIGN(x) ? '-' : '+');
+ for (i = SP_FBITS - 1; i >= 0; i--)
+ printk("%c", SPMANT(x) & SP_MBIT(i) ? '1' : '0');
+ break;
+ case IEEE754_CLASS_INF:
+ printk("%cInfinity", SPSIGN(x) ? '-' : '+');
+ break;
+ case IEEE754_CLASS_ZERO:
+ printk("%cZero", SPSIGN(x) ? '-' : '+');
+ break;
+ case IEEE754_CLASS_DNORM:
+ printk("%c0.", SPSIGN(x) ? '-' : '+');
+ for (i = SP_FBITS - 1; i >= 0; i--)
+ printk("%c", SPMANT(x) & SP_MBIT(i) ? '1' : '0');
+ printk("e%d", SPBEXP(x) - SP_EBIAS);
+ break;
+ case IEEE754_CLASS_NORM:
+ printk("%c1.", SPSIGN(x) ? '-' : '+');
+ for (i = SP_FBITS - 1; i >= 0; i--)
+ printk("%c", SPMANT(x) & SP_MBIT(i) ? '1' : '0');
+ printk("e%d", SPBEXP(x) - SP_EBIAS);
+ break;
+ default:
+ printk("Illegal/Unknown IEEE754 value class");
+ }
+ printk("\n");
+ return x;
+}
+
--- /dev/null
+/* IEEE754 floating point arithmetic
+ * double precision: common utilities
+ */
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+
+#include "ieee754dp.h"
+
+int ieee754dp_class(ieee754dp x)
+{
+ COMPXDP;
+ EXPLODEXDP;
+ return xc;
+}
+
+int ieee754dp_isnan(ieee754dp x)
+{
+ return ieee754dp_class(x) >= IEEE754_CLASS_SNAN;
+}
+
+int ieee754dp_issnan(ieee754dp x)
+{
+ assert(ieee754dp_isnan(x));
+ if (ieee754_csr.noq)
+ return 1;
+ return !(DPMANT(x) & DP_MBIT(DP_MBITS - 1));
+}
+
+
+ieee754dp ieee754dp_xcpt(ieee754dp r, const char *op, ...)
+{
+ struct ieee754xctx ax;
+ if (!TSTX())
+ return r;
+
+ ax.op = op;
+ ax.rt = IEEE754_RT_DP;
+ ax.rv.dp = r;
+ va_start(ax.ap, op);
+ ieee754_xcpt(&ax);
+ return ax.rv.dp;
+}
+
+ieee754dp ieee754dp_nanxcpt(ieee754dp r, const char *op, ...)
+{
+ struct ieee754xctx ax;
+
+ assert(ieee754dp_isnan(r));
+
+ if (!ieee754dp_issnan(r)) /* QNAN does not cause invalid op !! */
+ return r;
+
+ if (!SETCX(IEEE754_INVALID_OPERATION)) {
+ /* not enabled convert to a quiet NaN */
+ if (ieee754_csr.noq)
+ return r;
+ DPMANT(r) |= DP_MBIT(DP_MBITS - 1);
+ return r;
+ }
+
+ ax.op = op;
+ ax.rt = 0;
+ ax.rv.dp = r;
+ va_start(ax.ap, op);
+ ieee754_xcpt(&ax);
+ return ax.rv.dp;
+}
+
+ieee754dp ieee754dp_bestnan(ieee754dp x, ieee754dp y)
+{
+ assert(ieee754dp_isnan(x));
+ assert(ieee754dp_isnan(y));
+
+ if (DPMANT(x) > DPMANT(y))
+ return x;
+ else
+ return y;
+}
+
+
+/* generate a normal/denormal number with over,under handeling
+ * sn is sign
+ * xe is an unbiased exponent
+ * xm is 3bit extended precision value.
+ */
+ieee754dp ieee754dp_format(int sn, int xe, unsigned long long xm)
+{
+ assert(xm); /* we dont gen exact zeros (probably should) */
+
+ assert((xm >> (DP_MBITS + 1 + 3)) == 0); /* no execess */
+ assert(xm & (DP_HIDDEN_BIT << 3));
+
+ if (xe < DP_EMIN) {
+ /* strip lower bits */
+ int es = DP_EMIN - xe;
+
+ if (ieee754_csr.nod) {
+ SETCX(IEEE754_UNDERFLOW);
+ return ieee754dp_zero(sn);
+ }
+
+ /* sticky right shift es bits
+ */
+ xm = XDPSRS(xm, es);
+ xe += es;
+
+ assert((xm & (DP_HIDDEN_BIT << 3)) == 0);
+ assert(xe == DP_EMIN);
+ }
+ if (xm & (DP_MBIT(3) - 1)) {
+ SETCX(IEEE754_INEXACT);
+ /* inexact must round of 3 bits
+ */
+ switch (ieee754_csr.rm) {
+ case IEEE754_RZ:
+ break;
+ case IEEE754_RN:
+ xm += 0x3 + ((xm >> 3) & 1);
+ /* xm += (xm&0x8)?0x4:0x3 */
+ break;
+ case IEEE754_RU: /* toward +Infinity */
+ if (!sn) /* ?? */
+ xm += 0x8;
+ break;
+ case IEEE754_RD: /* toward -Infinity */
+ if (sn) /* ?? */
+ xm += 0x8;
+ break;
+ }
+ /* adjust exponent for rounding add overflowing
+ */
+ if (xm >> (DP_MBITS + 3 + 1)) { /* add causes mantissa overflow */
+ xm >>= 1;
+ xe++;
+ }
+ }
+ /* strip grs bits */
+ xm >>= 3;
+
+ assert((xm >> (DP_MBITS + 1)) == 0); /* no execess */
+ assert(xe >= DP_EMIN);
+
+ if (xe > DP_EMAX) {
+ SETCX(IEEE754_OVERFLOW);
+ /* -O can be table indexed by (rm,sn) */
+ switch (ieee754_csr.rm) {
+ case IEEE754_RN:
+ return ieee754dp_inf(sn);
+ case IEEE754_RZ:
+ return ieee754dp_max(sn);
+ case IEEE754_RU: /* toward +Infinity */
+ if (sn == 0)
+ return ieee754dp_inf(0);
+ else
+ return ieee754dp_max(1);
+ case IEEE754_RD: /* toward -Infinity */
+ if (sn == 0)
+ return ieee754dp_max(0);
+ else
+ return ieee754dp_inf(1);
+ }
+ }
+ /* gen norm/denorm/zero */
+
+ if ((xm & DP_HIDDEN_BIT) == 0) {
+ /* we underflow (tiny/zero) */
+ assert(xe == DP_EMIN);
+ SETCX(IEEE754_UNDERFLOW);
+ return builddp(sn, DP_EMIN - 1 + DP_EBIAS, xm);
+ } else {
+ assert((xm >> (DP_MBITS + 1)) == 0); /* no execess */
+ assert(xm & DP_HIDDEN_BIT);
+
+ return builddp(sn, xe + DP_EBIAS, xm & ~DP_HIDDEN_BIT);
+ }
+}
--- /dev/null
+/*
+ * IEEE754 floating point
+ * double precision internal header file
+ */
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+
+#include "ieee754int.h"
+
+#define assert(expr) ((void)0)
+
+/* 3bit extended double precision sticky right shift */
+#define XDPSRS(v,rs) \
+ ((rs > (DP_MBITS+3))?1:((v) >> (rs)) | ((v) << (64-(rs)) != 0))
+
+#define XDPSRSX1() \
+ (xe++, (xm = (xm >> 1) | (xm & 1)))
+
+#define XDPSRS1(v) \
+ (((v) >> 1) | ((v) & 1))
+
+/* convert denormal to normalized with extended exponent */
+#define DPDNORMx(m,e) \
+ while( (m >> DP_MBITS) == 0) { m <<= 1; e--; }
+#define DPDNORMX DPDNORMx(xm,xe)
+#define DPDNORMY DPDNORMx(ym,ye)
+
+static __inline ieee754dp builddp(int s, int bx, unsigned long long m)
+{
+ ieee754dp r;
+
+ assert((s) == 0 || (s) == 1);
+ assert((bx) >= DP_EMIN - 1 + DP_EBIAS
+ && (bx) <= DP_EMAX + 1 + DP_EBIAS);
+ assert(((m) >> DP_MBITS) == 0);
+
+ r.parts.sign = s;
+ r.parts.bexp = bx;
+ r.parts.mant = m;
+ return r;
+}
+
+extern int ieee754dp_isnan(ieee754dp);
+extern int ieee754dp_issnan(ieee754dp);
+extern int ieee754si_xcpt(int, const char *, ...);
+extern long long ieee754di_xcpt(long long, const char *, ...);
+extern ieee754dp ieee754dp_xcpt(ieee754dp, const char *, ...);
+extern ieee754dp ieee754dp_nanxcpt(ieee754dp, const char *, ...);
+extern ieee754dp ieee754dp_bestnan(ieee754dp, ieee754dp);
+extern ieee754dp ieee754dp_format(int, int, unsigned long long);
+
+
+#define DPNORMRET2(s,e,m,name,a0,a1) \
+{ \
+ ieee754dp V = ieee754dp_format(s,e,m); \
+ if(TSTX()) \
+ return ieee754dp_xcpt(V,name,a0,a1); \
+ else \
+ return V; \
+}
+
+#define DPNORMRET1(s,e,m,name,a0) DPNORMRET2(s,e,m,name,a0,a0)
--- /dev/null
+/*
+ * IEEE754 floating point
+ * common internal header file
+ */
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+
+#include "ieee754.h"
+
+#define DP_EBIAS 1023
+#define DP_EMIN (-1022)
+#define DP_EMAX 1023
+#define DP_MBITS 52
+
+#define SP_EBIAS 127
+#define SP_EMIN (-126)
+#define SP_EMAX 127
+#define SP_MBITS 23
+
+#define DP_MBIT(x) ((unsigned long long)1 << (x))
+#define DP_HIDDEN_BIT DP_MBIT(DP_MBITS)
+#define DP_SIGN_BIT DP_MBIT(63)
+
+#define SP_MBIT(x) ((unsigned long)1 << (x))
+#define SP_HIDDEN_BIT SP_MBIT(SP_MBITS)
+#define SP_SIGN_BIT SP_MBIT(31)
+
+
+#define SPSIGN(sp) (sp.parts.sign)
+#define SPBEXP(sp) (sp.parts.bexp)
+#define SPMANT(sp) (sp.parts.mant)
+
+#define DPSIGN(dp) (dp.parts.sign)
+#define DPBEXP(dp) (dp.parts.bexp)
+#define DPMANT(dp) (dp.parts.mant)
+
+#define CLPAIR(x,y) ((x)*6+(y))
+
+#define CLEARCX \
+ (ieee754_csr.cx = 0)
+
+#define SETCX(x) \
+ (ieee754_csr.cx |= (x),ieee754_csr.sx |= (x),ieee754_csr.mx & (x))
+
+#define TSTX() \
+ (ieee754_csr.cx & ieee754_csr.mx)
+
+
+#define COMPXSP \
+ unsigned xm; int xe; int xs; int xc
+
+#define COMPYSP \
+ unsigned ym; int ye; int ys; int yc
+
+#define EXPLODESP(v,vc,vs,ve,vm) \
+{\
+ vs = SPSIGN(v);\
+ ve = SPBEXP(v);\
+ vm = SPMANT(v);\
+ if(ve == SP_EMAX+1+SP_EBIAS){\
+ if(vm == 0)\
+ vc = IEEE754_CLASS_INF;\
+ else if(vm & SP_MBIT(SP_MBITS-1)) \
+ vc = IEEE754_CLASS_QNAN;\
+ else \
+ vc = IEEE754_CLASS_SNAN;\
+ } else if(ve == SP_EMIN-1+SP_EBIAS) {\
+ if(vm) {\
+ ve = SP_EMIN;\
+ vc = IEEE754_CLASS_DNORM;\
+ } else\
+ vc = IEEE754_CLASS_ZERO;\
+ } else {\
+ ve -= SP_EBIAS;\
+ vm |= SP_HIDDEN_BIT;\
+ vc = IEEE754_CLASS_NORM;\
+ }\
+}
+#define EXPLODEXSP EXPLODESP(x,xc,xs,xe,xm)
+#define EXPLODEYSP EXPLODESP(y,yc,ys,ye,ym)
+
+
+#define COMPXDP \
+unsigned long long xm; int xe; int xs; int xc
+
+#define COMPYDP \
+unsigned long long ym; int ye; int ys; int yc
+
+#define EXPLODEDP(v,vc,vs,ve,vm) \
+{\
+ vm = DPMANT(v);\
+ vs = DPSIGN(v);\
+ ve = DPBEXP(v);\
+ if(ve == DP_EMAX+1+DP_EBIAS){\
+ if(vm == 0)\
+ vc = IEEE754_CLASS_INF;\
+ else if(vm & DP_MBIT(DP_MBITS-1)) \
+ vc = IEEE754_CLASS_QNAN;\
+ else \
+ vc = IEEE754_CLASS_SNAN;\
+ } else if(ve == DP_EMIN-1+DP_EBIAS) {\
+ if(vm) {\
+ ve = DP_EMIN;\
+ vc = IEEE754_CLASS_DNORM;\
+ } else\
+ vc = IEEE754_CLASS_ZERO;\
+ } else {\
+ ve -= DP_EBIAS;\
+ vm |= DP_HIDDEN_BIT;\
+ vc = IEEE754_CLASS_NORM;\
+ }\
+}
+#define EXPLODEXDP EXPLODEDP(x,xc,xs,xe,xm)
+#define EXPLODEYDP EXPLODEDP(y,yc,ys,ye,ym)
--- /dev/null
+/*
+ * floor, trunc, ceil
+ */
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+
+#include "ieee754.h"
+
+ieee754dp ieee754dp_floor(ieee754dp x)
+{
+ ieee754dp i;
+
+ if (ieee754dp_lt(ieee754dp_modf(x, &i), ieee754dp_zero(0)))
+ return ieee754dp_sub(i, ieee754dp_one(0));
+ else
+ return i;
+}
+
+ieee754dp ieee754dp_ceil(ieee754dp x)
+{
+ ieee754dp i;
+
+ if (ieee754dp_gt(ieee754dp_modf(x, &i), ieee754dp_zero(0)))
+ return ieee754dp_add(i, ieee754dp_one(0));
+ else
+ return i;
+}
+
+ieee754dp ieee754dp_trunc(ieee754dp x)
+{
+ ieee754dp i;
+
+ (void) ieee754dp_modf(x, &i);
+ return i;
+}
--- /dev/null
+/* IEEE754 floating point arithmetic
+ * single precision
+ */
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+
+#include "ieee754sp.h"
+
+int ieee754sp_class(ieee754sp x)
+{
+ COMPXSP;
+ EXPLODEXSP;
+ return xc;
+}
+
+int ieee754sp_isnan(ieee754sp x)
+{
+ return ieee754sp_class(x) >= IEEE754_CLASS_SNAN;
+}
+
+int ieee754sp_issnan(ieee754sp x)
+{
+ assert(ieee754sp_isnan(x));
+ if (ieee754_csr.noq)
+ return 1;
+ return !(SPMANT(x) & SP_MBIT(SP_MBITS - 1));
+}
+
+
+ieee754sp ieee754sp_xcpt(ieee754sp r, const char *op, ...)
+{
+ struct ieee754xctx ax;
+
+ if (!TSTX())
+ return r;
+
+ ax.op = op;
+ ax.rt = IEEE754_RT_SP;
+ ax.rv.sp = r;
+ va_start(ax.ap, op);
+ ieee754_xcpt(&ax);
+ return ax.rv.sp;
+}
+
+ieee754sp ieee754sp_nanxcpt(ieee754sp r, const char *op, ...)
+{
+ struct ieee754xctx ax;
+
+ assert(ieee754sp_isnan(r));
+
+ if (!ieee754sp_issnan(r)) /* QNAN does not cause invalid op !! */
+ return r;
+
+ if (!SETCX(IEEE754_INVALID_OPERATION)) {
+ /* not enabled convert to a quiet NaN */
+ if (ieee754_csr.noq)
+ return r;
+ SPMANT(r) |= SP_MBIT(SP_MBITS - 1);
+ return r;
+ }
+
+ ax.op = op;
+ ax.rt = 0;
+ ax.rv.sp = r;
+ va_start(ax.ap, op);
+ ieee754_xcpt(&ax);
+ return ax.rv.sp;
+}
+
+ieee754sp ieee754sp_bestnan(ieee754sp x, ieee754sp y)
+{
+ assert(ieee754sp_isnan(x));
+ assert(ieee754sp_isnan(y));
+
+ if (SPMANT(x) > SPMANT(y))
+ return x;
+ else
+ return y;
+}
+
+
+/* generate a normal/denormal number with over,under handeling
+ * sn is sign
+ * xe is an unbiased exponent
+ * xm is 3bit extended precision value.
+ */
+ieee754sp ieee754sp_format(int sn, int xe, unsigned xm)
+{
+ assert(xm); /* we dont gen exact zeros (probably should) */
+
+ assert((xm >> (SP_MBITS + 1 + 3)) == 0); /* no execess */
+ assert(xm & (SP_HIDDEN_BIT << 3));
+
+ if (xe < SP_EMIN) {
+ /* strip lower bits */
+ int es = SP_EMIN - xe;
+
+ if (ieee754_csr.nod) {
+ SETCX(IEEE754_UNDERFLOW);
+ return ieee754sp_zero(sn);
+ }
+
+ /* sticky right shift es bits
+ */
+ SPXSRSXn(es);
+
+ assert((xm & (SP_HIDDEN_BIT << 3)) == 0);
+ assert(xe == SP_EMIN);
+ }
+ if (xm & (SP_MBIT(3) - 1)) {
+ SETCX(IEEE754_INEXACT);
+ /* inexact must round of 3 bits
+ */
+ switch (ieee754_csr.rm) {
+ case IEEE754_RZ:
+ break;
+ case IEEE754_RN:
+ xm += 0x3 + ((xm >> 3) & 1);
+ /* xm += (xm&0x8)?0x4:0x3 */
+ break;
+ case IEEE754_RU: /* toward +Infinity */
+ if (!sn) /* ?? */
+ xm += 0x8;
+ break;
+ case IEEE754_RD: /* toward -Infinity */
+ if (sn) /* ?? */
+ xm += 0x8;
+ break;
+ }
+ /* adjust exponent for rounding add overflowing
+ */
+ if (xm >> (SP_MBITS + 1 + 3)) { /* add causes mantissa overflow */
+ xm >>= 1;
+ xe++;
+ }
+ }
+ /* strip grs bits */
+ xm >>= 3;
+
+ assert((xm >> (SP_MBITS + 1)) == 0); /* no execess */
+ assert(xe >= SP_EMIN);
+
+ if (xe > SP_EMAX) {
+ SETCX(IEEE754_OVERFLOW);
+ /* -O can be table indexed by (rm,sn) */
+ switch (ieee754_csr.rm) {
+ case IEEE754_RN:
+ return ieee754sp_inf(sn);
+ case IEEE754_RZ:
+ return ieee754sp_max(sn);
+ case IEEE754_RU: /* toward +Infinity */
+ if (sn == 0)
+ return ieee754sp_inf(0);
+ else
+ return ieee754sp_max(1);
+ case IEEE754_RD: /* toward -Infinity */
+ if (sn == 0)
+ return ieee754sp_max(0);
+ else
+ return ieee754sp_inf(1);
+ }
+ }
+ /* gen norm/denorm/zero */
+
+ if ((xm & SP_HIDDEN_BIT) == 0) {
+ /* we underflow (tiny/zero) */
+ assert(xe == SP_EMIN);
+ SETCX(IEEE754_UNDERFLOW);
+ return buildsp(sn, SP_EMIN - 1 + SP_EBIAS, xm);
+ } else {
+ assert((xm >> (SP_MBITS + 1)) == 0); /* no execess */
+ assert(xm & SP_HIDDEN_BIT);
+
+ return buildsp(sn, xe + SP_EBIAS, xm & ~SP_HIDDEN_BIT);
+ }
+}
--- /dev/null
+/*
+ * IEEE754 floating point
+ * double precision internal header file
+ */
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+
+#include "ieee754int.h"
+
+#define assert(expr) ((void)0)
+
+/* 3bit extended single precision sticky right shift */
+#define SPXSRSXn(rs) \
+ (xe += rs, \
+ xm = (rs > (SP_MBITS+3))?1:((xm) >> (rs)) | ((xm) << (32-(rs)) != 0))
+
+#define SPXSRSX1() \
+ (xe++, (xm = (xm >> 1) | (xm & 1)))
+
+#define SPXSRSYn(rs) \
+ (ye+=rs, \
+ ym = (rs > (SP_MBITS+3))?1:((ym) >> (rs)) | ((ym) << (32-(rs)) != 0))
+
+#define SPXSRSY1() \
+ (ye++, (ym = (ym >> 1) | (ym & 1)))
+
+/* convert denormal to normalized with extended exponent */
+#define SPDNORMx(m,e) \
+ while( (m >> SP_MBITS) == 0) { m <<= 1; e--; }
+#define SPDNORMX SPDNORMx(xm,xe)
+#define SPDNORMY SPDNORMx(ym,ye)
+
+static __inline ieee754sp buildsp(int s, int bx, unsigned m)
+{
+ ieee754sp r;
+
+ assert((s) == 0 || (s) == 1);
+ assert((bx) >= SP_EMIN - 1 + SP_EBIAS
+ && (bx) <= SP_EMAX + 1 + SP_EBIAS);
+ assert(((m) >> SP_MBITS) == 0);
+
+ r.parts.sign = s;
+ r.parts.bexp = bx;
+ r.parts.mant = m;
+
+ return r;
+}
+
+extern int ieee754sp_isnan(ieee754sp);
+extern int ieee754sp_issnan(ieee754sp);
+extern int ieee754si_xcpt(int, const char *, ...);
+extern long long ieee754di_xcpt(long long, const char *, ...);
+extern ieee754sp ieee754sp_xcpt(ieee754sp, const char *, ...);
+extern ieee754sp ieee754sp_nanxcpt(ieee754sp, const char *, ...);
+extern ieee754sp ieee754sp_bestnan(ieee754sp, ieee754sp);
+extern ieee754sp ieee754sp_format(int, int, unsigned);
+
+
+#define SPNORMRET2(s,e,m,name,a0,a1) \
+{ \
+ ieee754sp V = ieee754sp_format(s,e,m); \
+ if(TSTX()) \
+ return ieee754sp_xcpt(V,name,a0,a1); \
+ else \
+ return V; \
+}
+
+#define SPNORMRET1(s,e,m,name,a0) SPNORMRET2(s,e,m,name,a0,a0)
--- /dev/null
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+/**************************************************************************
+ * Nov 7, 2000
+ * Added preprocessor hacks to map to Linux kernel diagnostics.
+ *
+ * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved.
+ *************************************************************************/
+
+#include "ieee754.h"
+
+/*
+ * Very naff exception handler (you can plug in your own and
+ * override this).
+ */
+
+static const char *const rtnames[] = {
+ "sp", "dp", "xp", "si", "di"
+};
+
+void ieee754_xcpt(struct ieee754xctx *xcp)
+{
+ printk("floating point exception in \"%s\", type=%s\n",
+ xcp->op, rtnames[xcp->rt]);
+}
+
--- /dev/null
+/**************************************************************************
+ *
+ * arch/mips/math_emu/kernel_linkage.c
+ *
+ * Kevin D. Kissell, kevink@mips and Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved.
+ *
+ * ########################################################################
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ *************************************************************************/
+/*
+ * Routines corresponding to Linux kernel FP context
+ * manipulation primitives for the Algorithmics MIPS
+ * FPU Emulator
+ */
+
+#include <linux/sched.h>
+#include <asm/processor.h>
+#include <asm/signal.h>
+#include <asm/uaccess.h>
+
+#include <asm/fpu_emulator.h>
+
+extern struct mips_fpu_emulator_private fpuemuprivate;
+
+#define SIGNALLING_NAN 0x7ff800007ff80000LL
+
+void fpu_emulator_init_fpu(void)
+{
+ static int first = 1;
+ int i;
+
+ if (first) {
+ first = 0;
+ printk("Algorithmics/MIPS FPU Emulator v1.4\n");
+ }
+
+ current->thread.fpu.soft.sr = 0;
+ for (i = 0; i < 32; i++) {
+ current->thread.fpu.soft.regs[i] = SIGNALLING_NAN;
+ }
+}
+
+
+/*
+ * Emulator context save/restore to/from a signal context
+ * presumed to be on the user stack, and therefore accessed
+ * with appropriate macros from uaccess.h
+ */
+
+int fpu_emulator_save_context(struct sigcontext *sc)
+{
+ int i;
+ int err = 0;
+
+ for (i = 0; i < 32; i++) {
+ err |=
+ __put_user(current->thread.fpu.soft.regs[i],
+ &sc->sc_fpregs[i]);
+ }
+ err |= __put_user(current->thread.fpu.soft.sr, &sc->sc_fpc_csr);
+ err |= __put_user(fpuemuprivate.eir, &sc->sc_fpc_eir);
+
+ return err;
+}
+
+int fpu_emulator_restore_context(struct sigcontext *sc)
+{
+ int i;
+ int err = 0;
+
+ for (i = 0; i < 32; i++) {
+ err |=
+ __get_user(current->thread.fpu.soft.regs[i],
+ &sc->sc_fpregs[i]);
+ }
+ err |= __get_user(current->thread.fpu.soft.sr, &sc->sc_fpc_csr);
+ err |= __get_user(fpuemuprivate.eir, &sc->sc_fpc_eir);
+
+ return err;
+}
+
--- /dev/null
+/* IEEE754 floating point arithmetic
+ * single precision
+ */
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+
+#include "ieee754sp.h"
+
+ieee754sp ieee754sp_add(ieee754sp x, ieee754sp y)
+{
+ COMPXSP;
+ COMPYSP;
+
+ EXPLODEXSP;
+ EXPLODEYSP;
+
+ CLEARCX;
+
+ switch (CLPAIR(xc, yc)) {
+ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN):
+ return ieee754sp_nanxcpt(ieee754sp_bestnan(x, y), "add", x,
+ y);
+
+ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN):
+ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN):
+ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN):
+ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN):
+ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN):
+ return ieee754sp_nanxcpt(y, "add", x, y);
+
+ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN):
+ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO):
+ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM):
+ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM):
+ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
+ return ieee754sp_nanxcpt(x, "add", x, y);
+
+ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
+ return ieee754sp_bestnan(x, y);
+
+ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
+ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
+ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN):
+ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN):
+ return y;
+
+ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO):
+ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM):
+ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM):
+ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF):
+ return x;
+
+
+ /* Inifity handeling
+ */
+
+ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
+ if (xs == ys)
+ return x;
+ SETCX(IEEE754_INVALID_OPERATION);
+ return ieee754sp_xcpt(ieee754sp_indef(), "add", x, y);
+
+ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF):
+ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF):
+ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF):
+ return y;
+
+ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO):
+ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM):
+ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
+ return x;
+
+ /* Zero handeling
+ */
+
+ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
+ if (xs == ys)
+ return x;
+ else
+ return ieee754sp_zero(ieee754_csr.rm ==
+ IEEE754_RD);
+
+ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO):
+ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO):
+ return x;
+
+ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM):
+ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM):
+ return y;
+
+ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
+ SPDNORMX;
+
+ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM):
+ SPDNORMY;
+ break;
+
+ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM):
+ SPDNORMX;
+ break;
+
+ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM):
+ break;
+ }
+ assert(xm & SP_HIDDEN_BIT);
+ assert(ym & SP_HIDDEN_BIT);
+
+ /* provide guard,round and stick bit space */
+ xm <<= 3;
+ ym <<= 3;
+
+ if (xe > ye) {
+ /* have to shift y fraction right to align
+ */
+ int s = xe - ye;
+ SPXSRSYn(s);
+ } else if (ye > xe) {
+ /* have to shift x fraction right to align
+ */
+ int s = ye - xe;
+ SPXSRSXn(s);
+ }
+ assert(xe == ye);
+ assert(xe <= SP_EMAX);
+
+ if (xs == ys) {
+ /* generate 28 bit result of adding two 27 bit numbers
+ * leaving result in xm,xs,xe
+ */
+ xm = xm + ym;
+ xe = xe;
+ xs = xs;
+
+ if (xm >> (SP_MBITS + 1 + 3)) { /* carry out */
+ SPXSRSX1();
+ }
+ } else {
+ if (xm >= ym) {
+ xm = xm - ym;
+ xe = xe;
+ xs = xs;
+ } else {
+ xm = ym - xm;
+ xe = xe;
+ xs = ys;
+ }
+ if (xm == 0)
+ return ieee754sp_zero(ieee754_csr.rm ==
+ IEEE754_RD);
+
+ /* normalize in extended single precision */
+ while ((xm >> (SP_MBITS + 3)) == 0) {
+ xm <<= 1;
+ xe--;
+ }
+
+ }
+ SPNORMRET2(xs, xe, xm, "add", x, y);
+}
--- /dev/null
+/* IEEE754 floating point arithmetic
+ * single precision
+ */
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+
+#include "ieee754sp.h"
+
+int ieee754sp_cmp(ieee754sp x, ieee754sp y, int cmp)
+{
+ CLEARCX;
+
+ if (ieee754sp_isnan(x) || ieee754sp_isnan(y)) {
+ if (cmp & IEEE754_CUN)
+ return 1;
+ if (cmp & (IEEE754_CLT | IEEE754_CGT)) {
+ if (SETCX(IEEE754_INVALID_OPERATION))
+ return ieee754si_xcpt(0, "fcmpf", x);
+ }
+ return 0;
+ } else {
+ int vx = x.bits;
+ int vy = y.bits;
+
+ if (vx < 0)
+ vx = -vx ^ SP_SIGN_BIT;
+ if (vy < 0)
+ vy = -vy ^ SP_SIGN_BIT;
+
+ if (vx < vy)
+ return (cmp & IEEE754_CLT) != 0;
+ else if (vx == vy)
+ return (cmp & IEEE754_CEQ) != 0;
+ else
+ return (cmp & IEEE754_CGT) != 0;
+ }
+}
--- /dev/null
+/* IEEE754 floating point arithmetic
+ * single precision
+ */
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+
+#include "ieee754sp.h"
+
+ieee754sp ieee754sp_div(ieee754sp x, ieee754sp y)
+{
+ COMPXSP;
+ COMPYSP;
+
+ CLEARCX;
+
+ EXPLODEXSP;
+ EXPLODEYSP;
+
+ switch (CLPAIR(xc, yc)) {
+ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN):
+ return ieee754sp_nanxcpt(ieee754sp_bestnan(x, y), "div", x,
+ y);
+
+ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN):
+ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN):
+ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN):
+ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN):
+ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN):
+ return ieee754sp_nanxcpt(y, "div", x, y);
+
+ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN):
+ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO):
+ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM):
+ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM):
+ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
+ return ieee754sp_nanxcpt(x, "div", x, y);
+
+ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
+ return ieee754sp_bestnan(x, y);
+
+ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
+ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
+ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN):
+ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN):
+ return y;
+
+ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO):
+ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM):
+ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM):
+ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF):
+ return x;
+
+
+ /* Infinity handeling
+ */
+
+ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
+ SETCX(IEEE754_INVALID_OPERATION);
+ return ieee754sp_xcpt(ieee754sp_indef(), "div", x, y);
+
+ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF):
+ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF):
+ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF):
+ return ieee754sp_zero(xs ^ ys);
+
+ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO):
+ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM):
+ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
+ return ieee754sp_inf(xs ^ ys);
+
+ /* Zero handeling
+ */
+
+ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
+ SETCX(IEEE754_INVALID_OPERATION);
+ return ieee754sp_xcpt(ieee754sp_indef(), "div", x, y);
+
+ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO):
+ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO):
+ SETCX(IEEE754_ZERO_DIVIDE);
+ return ieee754sp_xcpt(ieee754sp_inf(xs ^ ys), "div", x, y);
+
+ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM):
+ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM):
+ return ieee754sp_zero(xs == ys ? 0 : 1);
+
+ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
+ SPDNORMX;
+
+ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM):
+ SPDNORMY;
+ break;
+
+ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM):
+ SPDNORMX;
+ break;
+
+ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM):
+ break;
+ }
+ assert(xm & SP_HIDDEN_BIT);
+ assert(ym & SP_HIDDEN_BIT);
+
+ /* provide rounding space */
+ xm <<= 3;
+ ym <<= 3;
+
+ {
+ /* now the dirty work */
+
+ unsigned rm = 0;
+ int re = xe - ye;
+ unsigned bm;
+
+ for (bm = SP_MBIT(SP_MBITS + 2); bm; bm >>= 1) {
+ if (xm >= ym) {
+ xm -= ym;
+ rm |= bm;
+ if (xm == 0)
+ break;
+ }
+ xm <<= 1;
+ }
+ rm <<= 1;
+ if (xm)
+ rm |= 1; /* have remainder, set sticky */
+
+ assert(rm);
+
+ /* normalise rm to rounding precision ?
+ */
+ while ((rm >> (SP_MBITS + 3)) == 0) {
+ rm <<= 1;
+ re--;
+ }
+
+ SPNORMRET2(xs == ys ? 0 : 1, re, rm, "div", x, y);
+ }
+}
--- /dev/null
+/* IEEE754 floating point arithmetic
+ * single precision
+ */
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+
+#include "ieee754sp.h"
+
+ieee754sp ieee754sp_fdp(ieee754dp x)
+{
+ COMPXDP;
+
+ CLEARCX;
+
+ EXPLODEXDP;
+
+ switch (xc) {
+ case IEEE754_CLASS_QNAN:
+ case IEEE754_CLASS_SNAN:
+ return ieee754sp_nanxcpt(buildsp(xs,
+ SP_EMAX + 1 + SP_EBIAS,
+ (unsigned long)
+ (xm >>
+ (DP_MBITS - SP_MBITS))),
+ "fdp", x);
+ case IEEE754_CLASS_INF:
+ return ieee754sp_inf(xs);
+ case IEEE754_CLASS_ZERO:
+ return ieee754sp_zero(xs);
+ case IEEE754_CLASS_DNORM:
+ /* cant possibly be sp representable */
+ SETCX(IEEE754_UNDERFLOW);
+ return ieee754sp_xcpt(ieee754sp_zero(xs), "fdp", x);
+ case IEEE754_CLASS_NORM:
+ break;
+ }
+
+ {
+ unsigned long rm;
+
+ /* convert from DP_MBITS to SP_MBITS+3 with sticky right shift
+ */
+ rm = (xm >> (DP_MBITS - (SP_MBITS + 3))) |
+ ((xm << (64 - (DP_MBITS - (SP_MBITS + 3)))) != 0);
+
+ SPNORMRET1(xs, xe, rm, "fdp", x);
+ }
+}
--- /dev/null
+/* IEEE754 floating point arithmetic
+ * single precision
+ */
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+
+#include "ieee754sp.h"
+
+ieee754sp ieee754sp_fint(int x)
+{
+ COMPXSP;
+
+ CLEARCX;
+
+ if (x == 0)
+ return ieee754sp_zero(0);
+ if (x == 1 || x == -1)
+ return ieee754sp_one(x < 0);
+ if (x == 10 || x == -10)
+ return ieee754sp_ten(x < 0);
+
+ xs = (x < 0);
+ if (xs) {
+ if (x == (1 << 31))
+ xm = ((unsigned) 1 << 31); /* max neg can't be safely negated */
+ else
+ xm = -x;
+ } else {
+ xm = x;
+ }
+ xe = SP_MBITS + 3;
+
+ if (xm >> (SP_MBITS + 1 + 3)) {
+ /* shunt out overflow bits
+ */
+ while (xm >> (SP_MBITS + 1 + 3)) {
+ SPXSRSX1();
+ }
+ } else {
+ /* normalize in grs extended single precision
+ */
+ while ((xm >> (SP_MBITS + 3)) == 0) {
+ xm <<= 1;
+ xe--;
+ }
+ }
+ SPNORMRET1(xs, xe, xm, "fint", x);
+}
+
+
+ieee754sp ieee754sp_funs(unsigned int u)
+{
+ if ((int) u < 0)
+ return ieee754sp_add(ieee754sp_1e31(),
+ ieee754sp_fint(u & ~(1 << 31)));
+ return ieee754sp_fint(u);
+}
--- /dev/null
+/* IEEE754 floating point arithmetic
+ * single precision
+ */
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+
+#include "ieee754sp.h"
+
+ieee754sp ieee754sp_flong(long long x)
+{
+ COMPXDP; /* <--- need 64-bit mantissa temp */
+
+ CLEARCX;
+
+ if (x == 0)
+ return ieee754sp_zero(0);
+ if (x == 1 || x == -1)
+ return ieee754sp_one(x < 0);
+ if (x == 10 || x == -10)
+ return ieee754sp_ten(x < 0);
+
+ xs = (x < 0);
+ if (xs) {
+ if (x == (1ULL << 63))
+ xm = (1ULL << 63); /* max neg can't be safely negated */
+ else
+ xm = -x;
+ } else {
+ xm = x;
+ }
+ xe = SP_MBITS + 3;
+
+ if (xm >> (SP_MBITS + 1 + 3)) {
+ /* shunt out overflow bits
+ */
+ while (xm >> (SP_MBITS + 1 + 3)) {
+ SPXSRSX1();
+ }
+ } else {
+ /* normalize in grs extended single precision */
+ while ((xm >> (SP_MBITS + 3)) == 0) {
+ xm <<= 1;
+ xe--;
+ }
+ }
+ SPNORMRET1(xs, xe, xm, "sp_flong", x);
+}
+
+
+ieee754sp ieee754sp_fulong(unsigned long long u)
+{
+ if ((long long) u < 0)
+ return ieee754sp_add(ieee754sp_1e63(),
+ ieee754sp_flong(u & ~(1ULL << 63)));
+ return ieee754sp_flong(u);
+}
--- /dev/null
+/* IEEE754 floating point arithmetic
+ * single precision
+ */
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+
+#include "ieee754sp.h"
+
+/* close to ieeep754sp_logb
+*/
+ieee754sp ieee754sp_frexp(ieee754sp x, int *eptr)
+{
+ COMPXSP;
+ CLEARCX;
+ EXPLODEXSP;
+
+ switch (xc) {
+ case IEEE754_CLASS_SNAN:
+ case IEEE754_CLASS_QNAN:
+ case IEEE754_CLASS_INF:
+ case IEEE754_CLASS_ZERO:
+ *eptr = 0;
+ return x;
+ case IEEE754_CLASS_DNORM:
+ SPDNORMX;
+ break;
+ case IEEE754_CLASS_NORM:
+ break;
+ }
+ *eptr = xe + 1;
+ return buildsp(xs, -1 + SP_EBIAS, xm & ~SP_HIDDEN_BIT);
+}
--- /dev/null
+/* IEEE754 floating point arithmetic
+ * single precision
+ */
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+
+#include "ieee754sp.h"
+
+ieee754sp ieee754sp_logb(ieee754sp x)
+{
+ COMPXSP;
+
+ CLEARCX;
+
+ EXPLODEXSP;
+
+ switch (xc) {
+ case IEEE754_CLASS_SNAN:
+ return ieee754sp_nanxcpt(x, "logb", x);
+ case IEEE754_CLASS_QNAN:
+ return x;
+ case IEEE754_CLASS_INF:
+ return ieee754sp_inf(0);
+ case IEEE754_CLASS_ZERO:
+ return ieee754sp_inf(1);
+ case IEEE754_CLASS_DNORM:
+ SPDNORMX;
+ break;
+ case IEEE754_CLASS_NORM:
+ break;
+ }
+ return ieee754sp_fint(xe);
+}
--- /dev/null
+/* IEEE754 floating point arithmetic
+ * single precision
+ */
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+
+#include "ieee754sp.h"
+
+/* modf function is always exact for a finite number
+*/
+ieee754sp ieee754sp_modf(ieee754sp x, ieee754sp * ip)
+{
+ COMPXSP;
+
+ CLEARCX;
+
+ EXPLODEXSP;
+
+ switch (xc) {
+ case IEEE754_CLASS_SNAN:
+ case IEEE754_CLASS_QNAN:
+ case IEEE754_CLASS_INF:
+ case IEEE754_CLASS_ZERO:
+ *ip = x;
+ return x;
+ case IEEE754_CLASS_DNORM:
+ /* far to small */
+ *ip = ieee754sp_zero(xs);
+ return x;
+ case IEEE754_CLASS_NORM:
+ break;
+ }
+ if (xe < 0) {
+ *ip = ieee754sp_zero(xs);
+ return x;
+ }
+ if (xe >= SP_MBITS) {
+ *ip = x;
+ return ieee754sp_zero(xs);
+ }
+ /* generate ipart mantissa by clearing bottom bits
+ */
+ *ip = buildsp(xs, xe + SP_EBIAS,
+ ((xm >> (SP_MBITS - xe)) << (SP_MBITS - xe)) &
+ ~SP_HIDDEN_BIT);
+
+ /* generate fpart mantissa by clearing top bits
+ * and normalizing (must be able to normalize)
+ */
+ xm = (xm << (32 - (SP_MBITS - xe))) >> (32 - (SP_MBITS - xe));
+ if (xm == 0)
+ return ieee754sp_zero(xs);
+
+ while ((xm >> SP_MBITS) == 0) {
+ xm <<= 1;
+ xe--;
+ }
+ return buildsp(xs, xe + SP_EBIAS, xm & ~SP_HIDDEN_BIT);
+}
--- /dev/null
+/* IEEE754 floating point arithmetic
+ * single precision
+ */
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+
+#include "ieee754sp.h"
+
+ieee754sp ieee754sp_mul(ieee754sp x, ieee754sp y)
+{
+ COMPXSP;
+ COMPYSP;
+
+ CLEARCX;
+
+ EXPLODEXSP;
+ EXPLODEYSP;
+
+ switch (CLPAIR(xc, yc)) {
+ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN):
+ return ieee754sp_nanxcpt(ieee754sp_bestnan(x, y), "mul", x,
+ y);
+
+ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN):
+ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN):
+ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN):
+ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN):
+ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN):
+ return ieee754sp_nanxcpt(y, "mul", x, y);
+
+ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN):
+ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO):
+ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM):
+ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM):
+ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
+ return ieee754sp_nanxcpt(x, "mul", x, y);
+
+ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
+ return ieee754sp_bestnan(x, y);
+
+ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
+ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
+ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN):
+ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN):
+ return y;
+
+ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO):
+ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM):
+ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM):
+ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF):
+ return x;
+
+
+ /* Infinity handeling */
+
+ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO):
+ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF):
+ SETCX(IEEE754_INVALID_OPERATION);
+ return ieee754sp_xcpt(ieee754sp_indef(), "mul", x, y);
+
+ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF):
+ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF):
+ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM):
+ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
+ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
+ return ieee754sp_inf(xs ^ ys);
+
+ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
+ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM):
+ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM):
+ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO):
+ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO):
+ return ieee754sp_zero(xs ^ ys);
+
+
+ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
+ SPDNORMX;
+
+ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM):
+ SPDNORMY;
+ break;
+
+ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM):
+ SPDNORMX;
+ break;
+
+ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM):
+ break;
+ }
+ /* rm = xm * ym, re = xe+ye basicly */
+ assert(xm & SP_HIDDEN_BIT);
+ assert(ym & SP_HIDDEN_BIT);
+
+ {
+ int re = xe + ye;
+ int rs = xs ^ ys;
+ unsigned rm;
+
+ /* shunt to top of word */
+ xm <<= 32 - (SP_MBITS + 1);
+ ym <<= 32 - (SP_MBITS + 1);
+
+ /* multiply 32bits xm,ym to give high 32bits rm with stickness
+ */
+ {
+ unsigned short lxm = xm & 0xffff;
+ unsigned short hxm = xm >> 16;
+ unsigned short lym = ym & 0xffff;
+ unsigned short hym = ym >> 16;
+ unsigned lrm;
+ unsigned hrm;
+
+ lrm = lxm * lym; /* 16 * 16 => 32 */
+ hrm = hxm * hym; /* 16 * 16 => 32 */
+
+ {
+ unsigned t = lxm * hym; /* 16 * 16 => 32 */
+ {
+ unsigned at = lrm + (t << 16);
+ hrm += at < lrm;
+ lrm = at;
+ }
+ hrm = hrm + (t >> 16);
+ }
+
+ {
+ unsigned t = hxm * lym; /* 16 * 16 => 32 */
+ {
+ unsigned at = lrm + (t << 16);
+ hrm += at < lrm;
+ lrm = at;
+ }
+ hrm = hrm + (t >> 16);
+ }
+ rm = hrm | (lrm != 0);
+ }
+
+ /*
+ * sticky shift down to normal rounding precision
+ */
+ if ((int) rm < 0) {
+ rm = (rm >> (32 - (SP_MBITS + 1 + 3))) |
+ ((rm << (SP_MBITS + 1 + 3)) != 0);
+ re++;
+ } else {
+ rm = (rm >> (32 - (SP_MBITS + 1 + 3 + 1))) |
+ ((rm << (SP_MBITS + 1 + 3 + 1)) != 0);
+ }
+ assert(rm & (SP_HIDDEN_BIT << 3));
+
+ SPNORMRET2(rs, re, rm, "mul", x, y);
+ }
+}
--- /dev/null
+/* IEEE754 floating point arithmetic
+ * single precision
+ */
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+
+#include "ieee754sp.h"
+
+ieee754sp ieee754sp_scalb(ieee754sp x, int n)
+{
+ COMPXSP;
+
+ CLEARCX;
+
+ EXPLODEXSP;
+
+ switch (xc) {
+ case IEEE754_CLASS_SNAN:
+ return ieee754sp_nanxcpt(x, "scalb", x, n);
+ case IEEE754_CLASS_QNAN:
+ case IEEE754_CLASS_INF:
+ case IEEE754_CLASS_ZERO:
+ return x;
+ case IEEE754_CLASS_DNORM:
+ SPDNORMX;
+ break;
+ case IEEE754_CLASS_NORM:
+ break;
+ }
+ SPNORMRET2(xs, xe + n, xm << 3, "scalb", x, n);
+}
+
+
+ieee754sp ieee754sp_ldexp(ieee754sp x, int n)
+{
+ return ieee754sp_scalb(x, n);
+}
--- /dev/null
+/* IEEE754 floating point arithmetic
+ * single precision
+ */
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+
+#include "ieee754sp.h"
+
+int ieee754sp_finite(ieee754sp x)
+{
+ return SPBEXP(x) != SP_EMAX + 1 + SP_EBIAS;
+}
+
+ieee754sp ieee754sp_copysign(ieee754sp x, ieee754sp y)
+{
+ CLEARCX;
+ SPSIGN(x) = SPSIGN(y);
+ return x;
+}
+
+
+ieee754sp ieee754sp_neg(ieee754sp x)
+{
+ CLEARCX;
+
+ if (ieee754sp_isnan(x)) /* but not infinity */
+ return ieee754sp_nanxcpt(x, "neg", x);
+
+ /* quick fix up */
+ SPSIGN(x) ^= 1;
+ return x;
+}
+
+
+ieee754sp ieee754sp_abs(ieee754sp x)
+{
+ CLEARCX;
+
+ if (ieee754sp_isnan(x)) /* but not infinity */
+ return ieee754sp_nanxcpt(x, "abs", x);
+
+ /* quick fix up */
+ SPSIGN(x) = 0;
+ return x;
+}
--- /dev/null
+/* IEEE754 floating point arithmetic
+ * single precision square root
+ */
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+
+#include "ieee754sp.h"
+
+static const struct ieee754sp_konst knan = {
+ 0, SP_EBIAS + SP_EMAX + 1, 0
+};
+
+#define nan ((ieee754sp)knan)
+
+ieee754sp ieee754sp_sqrt(ieee754sp x)
+{
+ int sign = (int) 0x80000000;
+ int ix, s, q, m, t, i;
+ unsigned int r;
+ COMPXDP;
+
+ /* take care of Inf and NaN */
+
+ EXPLODEXDP;
+
+ /* x == INF or NAN? */
+ switch (xc) {
+ case IEEE754_CLASS_QNAN:
+ case IEEE754_CLASS_SNAN:
+ /* sqrt(Nan) = Nan */
+ return ieee754sp_nanxcpt(x, "sqrt");
+ case IEEE754_CLASS_ZERO:
+ /* sqrt(0) = 0 */
+ return x;
+ case IEEE754_CLASS_INF:
+ if (xs)
+ /* sqrt(-Inf) = Nan */
+ return ieee754sp_nanxcpt(nan, "sqrt");
+ /* sqrt(+Inf) = Inf */
+ return x;
+ case IEEE754_CLASS_DNORM:
+ case IEEE754_CLASS_NORM:
+ if (xs)
+ /* sqrt(-x) = Nan */
+ return ieee754sp_nanxcpt(nan, "sqrt");
+ break;
+ }
+
+ ix = x.bits;
+
+ /* normalize x */
+ m = (ix >> 23);
+ if (m == 0) { /* subnormal x */
+ for (i = 0; (ix & 0x00800000) == 0; i++)
+ ix <<= 1;
+ m -= i - 1;
+ }
+ m -= 127; /* unbias exponent */
+ ix = (ix & 0x007fffff) | 0x00800000;
+ if (m & 1) /* odd m, double x to make it even */
+ ix += ix;
+ m >>= 1; /* m = [m/2] */
+
+ /* generate sqrt(x) bit by bit */
+ ix += ix;
+ q = s = 0; /* q = sqrt(x) */
+ r = 0x01000000; /* r = moving bit from right to left */
+
+ while (r != 0) {
+ t = s + r;
+ if (t <= ix) {
+ s = t + r;
+ ix -= t;
+ q += r;
+ }
+ ix += ix;
+ r >>= 1;
+ }
+
+ if (ix != 0) {
+ switch (ieee754_csr.rm) {
+ case IEEE754_RP:
+ q += 2;
+ break;
+ case IEEE754_RN:
+ q += (q & 1);
+ break;
+ }
+ }
+ ix = (q >> 1) + 0x3f000000;
+ ix += (m << 23);
+ x.bits = ix;
+ return x;
+}
--- /dev/null
+/* IEEE754 floating point arithmetic
+ * single precision
+ */
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+
+#include "ieee754sp.h"
+
+ieee754sp ieee754sp_sub(ieee754sp x, ieee754sp y)
+{
+ COMPXSP;
+ COMPYSP;
+
+ CLEARCX;
+
+ EXPLODEXSP;
+ EXPLODEYSP;
+
+ switch (CLPAIR(xc, yc)) {
+ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN):
+ return ieee754sp_nanxcpt(ieee754sp_bestnan(x, y), "sub", x,
+ y);
+
+ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN):
+ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN):
+ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN):
+ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN):
+ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN):
+ return ieee754sp_nanxcpt(y, "sub", x, y);
+
+ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN):
+ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO):
+ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM):
+ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM):
+ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
+ return ieee754sp_nanxcpt(x, "sub", x, y);
+
+ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
+ return ieee754sp_bestnan(x, y);
+
+ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
+ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
+ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN):
+ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN):
+ return y;
+
+ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO):
+ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM):
+ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM):
+ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF):
+ return x;
+
+
+ /* Inifity handeling
+ */
+
+ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
+ if (xs != ys)
+ return x;
+ SETCX(IEEE754_INVALID_OPERATION);
+ return ieee754sp_xcpt(ieee754sp_indef(), "sub", x, y);
+
+ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF):
+ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF):
+ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF):
+ return ieee754sp_inf(ys ^ 1);
+
+ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO):
+ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM):
+ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
+ return x;
+
+ /* Zero handeling
+ */
+
+ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
+ if (xs != ys)
+ return x;
+ else
+ return ieee754sp_zero(ieee754_csr.rm ==
+ IEEE754_RD);
+
+ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO):
+ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO):
+ return x;
+
+ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM):
+ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM):
+ /* quick fix up */
+ DPSIGN(y) ^= 1;
+ return y;
+
+ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
+ SPDNORMX;
+
+ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM):
+ SPDNORMY;
+ break;
+
+ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM):
+ SPDNORMX;
+ break;
+
+ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM):
+ break;
+ }
+ /* flip sign of y and handle as add */
+ ys ^= 1;
+
+ assert(xm & SP_HIDDEN_BIT);
+ assert(ym & SP_HIDDEN_BIT);
+
+
+ /* provide guard,round and stick bit space */
+ xm <<= 3;
+ ym <<= 3;
+
+ if (xe > ye) {
+ /* have to shift y fraction right to align
+ */
+ int s = xe - ye;
+ SPXSRSYn(s);
+ } else if (ye > xe) {
+ /* have to shift x fraction right to align
+ */
+ int s = ye - xe;
+ SPXSRSXn(s);
+ }
+ assert(xe == ye);
+ assert(xe <= SP_EMAX);
+
+ if (xs == ys) {
+ /* generate 28 bit result of adding two 27 bit numbers
+ */
+ xm = xm + ym;
+ xe = xe;
+ xs = xs;
+
+ if (xm >> (SP_MBITS + 1 + 3)) { /* carry out */
+ SPXSRSX1(); /* shift preserving sticky */
+ }
+ } else {
+ if (xm >= ym) {
+ xm = xm - ym;
+ xe = xe;
+ xs = xs;
+ } else {
+ xm = ym - xm;
+ xe = xe;
+ xs = ys;
+ }
+ if (xm == 0)
+ if (ieee754_csr.rm == IEEE754_RD)
+ return ieee754sp_zero(1); /* round negative inf. => sign = -1 */
+ else
+ return ieee754sp_zero(0); /* other round modes => sign = 1 */
+
+ /* normalize to rounding precision
+ */
+ while ((xm >> (SP_MBITS + 3)) == 0) {
+ xm <<= 1;
+ xe--;
+ }
+ }
+ SPNORMRET2(xs, xe, xm, "sub", x, y);
+}
--- /dev/null
+/* IEEE754 floating point arithmetic
+ * single precision
+ */
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+
+#include <linux/kernel.h>
+#include "ieee754sp.h"
+
+int ieee754sp_tint(ieee754sp x)
+{
+ COMPXSP;
+
+ CLEARCX;
+
+ EXPLODEXSP;
+
+ switch (xc) {
+ case IEEE754_CLASS_SNAN:
+ case IEEE754_CLASS_QNAN:
+ SETCX(IEEE754_INVALID_OPERATION);
+ return ieee754si_xcpt(ieee754si_indef(), "fixsp", x);
+ case IEEE754_CLASS_INF:
+ SETCX(IEEE754_OVERFLOW);
+ return ieee754si_xcpt(ieee754si_indef(), "fixsp", x);
+ case IEEE754_CLASS_ZERO:
+ return 0;
+ case IEEE754_CLASS_DNORM: /* much to small */
+ SETCX(IEEE754_UNDERFLOW);
+ return ieee754si_xcpt(0, "fixsp", x);
+ case IEEE754_CLASS_NORM:
+ break;
+ }
+ if (xe >= 31) {
+ SETCX(IEEE754_OVERFLOW);
+ return ieee754si_xcpt(ieee754si_indef(), "fix", x);
+ }
+ if (xe < 0) {
+ SETCX(IEEE754_UNDERFLOW);
+ return ieee754si_xcpt(0, "fix", x);
+ }
+ /* oh gawd */
+ if (xe > SP_MBITS) {
+ xm <<= xe - SP_MBITS;
+ } else if (xe < SP_MBITS) {
+ /* XXX no rounding
+ */
+ xm >>= SP_MBITS - xe;
+ }
+ if (xs)
+ return -xm;
+ else
+ return xm;
+}
+
+
+unsigned int ieee754sp_tuns(ieee754sp x)
+{
+ ieee754sp hb = ieee754sp_1e31();
+
+ /* what if x < 0 ?? */
+ if (ieee754sp_lt(x, hb))
+ return (unsigned) ieee754sp_tint(x);
+
+ return (unsigned) ieee754sp_tint(ieee754sp_sub(x, hb)) |
+ ((unsigned) 1 << 31);
+}
--- /dev/null
+/* IEEE754 floating point arithmetic
+ * single precision
+ */
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
+ * http://www.algor.co.uk
+ *
+ * ########################################################################
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ */
+
+
+#include "ieee754sp.h"
+
+long long ieee754sp_tlong(ieee754sp x)
+{
+ COMPXDP; /* <-- need 64-bit mantissa tmp */
+
+ CLEARCX;
+
+ EXPLODEXSP;
+
+ switch (xc) {
+ case IEEE754_CLASS_SNAN:
+ case IEEE754_CLASS_QNAN:
+ SETCX(IEEE754_INVALID_OPERATION);
+ return ieee754di_xcpt(ieee754di_indef(), "sp_tlong", x);
+ case IEEE754_CLASS_INF:
+ SETCX(IEEE754_OVERFLOW);
+ return ieee754di_xcpt(ieee754di_indef(), "sp_tlong", x);
+ case IEEE754_CLASS_ZERO:
+ return 0;
+ case IEEE754_CLASS_DNORM: /* much to small */
+ SETCX(IEEE754_UNDERFLOW);
+ return ieee754di_xcpt(0, "sp_tlong", x);
+ case IEEE754_CLASS_NORM:
+ break;
+ }
+ if (xe >= 63) {
+ SETCX(IEEE754_OVERFLOW);
+ return ieee754di_xcpt(ieee754di_indef(), "sp_tlong", x);
+ }
+ if (xe < 0) {
+ SETCX(IEEE754_UNDERFLOW);
+ return ieee754di_xcpt(0, "sp_tlong", x);
+ }
+ /* oh gawd */
+ if (xe > SP_MBITS) {
+ xm <<= xe - SP_MBITS;
+ } else if (xe < SP_MBITS) {
+ /* XXX no rounding
+ */
+ xm >>= SP_MBITS - xe;
+ }
+ if (xs)
+ return -xm;
+ else
+ return xm;
+}
+
+
+unsigned long long ieee754sp_tulong(ieee754sp x)
+{
+ ieee754sp hb = ieee754sp_1e63();
+
+ /* what if x < 0 ?? */
+ if (ieee754sp_lt(x, hb))
+ return (unsigned long long) ieee754sp_tlong(x);
+
+ return (unsigned long long) ieee754sp_tlong(ieee754sp_sub(x, hb)) |
+ (1ULL << 63);
+}
--- /dev/null
+#
+# Carsten Langgaard, carstenl@mips.com
+# Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved.
+#
+# ########################################################################
+#
+# This program is free software; you can distribute it and/or modify it
+# under the terms of the GNU General Public License (Version 2) as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+#
+# #######################################################################
+#
+# Makefile for the MIPS Atlas specific kernel interface routines
+# under Linux.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile...
+
+.S.s:
+ $(CPP) $(CFLAGS) $< -o $*.s
+.S.o:
+ $(CC) $(CFLAGS) -c $< -o $*.o
+
+all: atlas.o
+
+O_TARGET := atlas.o
+
+obj-y := atlas_int.o atlas_rtc.o atlas_setup.o
+
+include $(TOPDIR)/Rules.make
--- /dev/null
+/*
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved.
+ *
+ * ########################################################################
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ *
+ * Routines for generic manipulation of the interrupts found on the MIPS
+ * Atlas board.
+ *
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/kernel_stat.h>
+
+#include <asm/irq.h>
+#include <asm/mips-boards/atlas.h>
+#include <asm/mips-boards/atlasint.h>
+#include <asm/gdb-stub.h>
+
+
+struct atlas_ictrl_regs *atlas_hw0_icregs
+ = (struct atlas_ictrl_regs *)ATLAS_ICTRL_REGS_BASE;
+
+extern asmlinkage void mipsIRQ(void);
+extern void do_IRQ(int irq, struct pt_regs *regs);
+
+unsigned long spurious_count = 0;
+irq_desc_t irq_desc[NR_IRQS];
+
+#if 0
+#define DEBUG_INT(x...) printk(x)
+#else
+#define DEBUG_INT(x...)
+#endif
+
+void disable_atlas_irq(unsigned int irq_nr)
+{
+ atlas_hw0_icregs->intrsten = (1 << irq_nr);
+}
+
+void enable_atlas_irq(unsigned int irq_nr)
+{
+ atlas_hw0_icregs->intseten = (1 << irq_nr);
+}
+
+static unsigned int startup_atlas_irq(unsigned int irq)
+{
+ enable_atlas_irq(irq);
+ return 0; /* never anything pending */
+}
+
+#define shutdown_atlas_irq disable_atlas_irq
+
+#define mask_and_ack_atlas_irq disable_atlas_irq
+
+static void end_atlas_irq(unsigned int irq)
+{
+ if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
+ enable_atlas_irq(irq);
+}
+
+static struct hw_interrupt_type atlas_irq_type = {
+ "Atlas",
+ startup_atlas_irq,
+ shutdown_atlas_irq,
+ enable_atlas_irq,
+ disable_atlas_irq,
+ mask_and_ack_atlas_irq,
+ end_atlas_irq,
+ NULL
+};
+
+int get_irq_list(char *buf)
+{
+ int i, len = 0;
+ int num = 0;
+ struct irqaction *action;
+
+ for (i = 0; i < ATLASINT_END; i++, num++) {
+ action = irq_desc[i].action;
+ if (!action)
+ continue;
+ len += sprintf(buf+len, "%2d: %8d %c %s",
+ num, kstat.irqs[0][num],
+ (action->flags & SA_INTERRUPT) ? '+' : ' ',
+ action->name);
+ for (action=action->next; action; action = action->next) {
+ len += sprintf(buf+len, ",%s %s",
+ (action->flags & SA_INTERRUPT) ? " +" : "",
+ action->name);
+ }
+ len += sprintf(buf+len, " [hw0]\n");
+ }
+ return len;
+}
+
+int request_irq(unsigned int irq,
+ void (*handler)(int, void *, struct pt_regs *),
+ unsigned long irqflags,
+ const char * devname,
+ void *dev_id)
+{
+ struct irqaction *action;
+
+ DEBUG_INT("request_irq: irq=%d, devname = %s\n", irq, devname);
+
+ if (irq >= ATLASINT_END)
+ return -EINVAL;
+ if (!handler)
+ return -EINVAL;
+
+ action = (struct irqaction *)kmalloc(sizeof(struct irqaction), GFP_KERNEL);
+ if(!action)
+ return -ENOMEM;
+
+ action->handler = handler;
+ action->flags = irqflags;
+ action->mask = 0;
+ action->name = devname;
+ action->dev_id = dev_id;
+ action->next = 0;
+ irq_desc[irq].action = action;
+ enable_atlas_irq(irq);
+
+ return 0;
+}
+
+void free_irq(unsigned int irq, void *dev_id)
+{
+ struct irqaction *action;
+
+ if (irq >= ATLASINT_END) {
+ printk("Trying to free IRQ%d\n",irq);
+ return;
+ }
+
+ action = irq_desc[irq].action;
+ irq_desc[irq].action = NULL;
+ disable_atlas_irq(irq);
+ kfree(action);
+}
+
+static inline int ls1bit32(unsigned int x)
+{
+ int b = 31, s;
+
+ s = 16; if (x << 16 == 0) s = 0; b -= s; x <<= s;
+ s = 8; if (x << 8 == 0) s = 0; b -= s; x <<= s;
+ s = 4; if (x << 4 == 0) s = 0; b -= s; x <<= s;
+ s = 2; if (x << 2 == 0) s = 0; b -= s; x <<= s;
+ s = 1; if (x << 1 == 0) s = 0; b -= s;
+
+ return b;
+}
+
+void atlas_hw0_irqdispatch(struct pt_regs *regs)
+{
+ struct irqaction *action;
+ unsigned long int_status;
+ int irq, cpu = smp_processor_id();
+
+ int_status = atlas_hw0_icregs->intstatus;
+
+ /* if int_status == 0, then the interrupt has already been cleared */
+ if (int_status == 0)
+ return;
+
+ irq = ls1bit32(int_status);
+ action = irq_desc[irq].action;
+
+ DEBUG_INT("atlas_hw0_irqdispatch: irq=%d\n", irq);
+
+ /* if action == NULL, then we don't have a handler for the irq */
+ if ( action == NULL ) {
+ printk("No handler for hw0 irq: %i\n", irq);
+ spurious_count++;
+ return;
+ }
+
+ irq_enter(cpu, irq);
+ kstat.irqs[0][irq]++;
+ action->handler(irq, action->dev_id, regs);
+ irq_exit(cpu, irq);
+
+ return;
+}
+
+unsigned long probe_irq_on (void)
+{
+ return 0;
+}
+
+
+int probe_irq_off (unsigned long irqs)
+{
+ return 0;
+}
+
+#ifdef CONFIG_REMOTE_DEBUG
+extern void breakpoint(void);
+extern int remote_debug;
+#endif
+
+void __init init_IRQ(void)
+{
+ int i;
+
+ /*
+ * Mask out all interrupt by writing "1" to all bit position in
+ * the interrupt reset reg.
+ */
+ atlas_hw0_icregs->intrsten = 0xffffffff;
+
+ /* Now safe to set the exception vector. */
+ set_except_vector(0, mipsIRQ);
+
+ for (i = 0; i <= ATLASINT_END; i++) {
+ irq_desc[i].status = IRQ_DISABLED;
+ irq_desc[i].action = 0;
+ irq_desc[i].depth = 1;
+ irq_desc[i].handler = &atlas_irq_type;
+ }
+
+#ifdef CONFIG_REMOTE_DEBUG
+ if (remote_debug) {
+ set_debug_traps();
+ breakpoint();
+ }
+#endif
+}
--- /dev/null
+/*
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved.
+ *
+ * ########################################################################
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ *
+ * RTC routines for Atlas style attached Dallas chip.
+ *
+ */
+#include <linux/spinlock.h>
+#include <linux/mc146818rtc.h>
+#include <asm/mips-boards/atlas.h>
+
+
+static unsigned char atlas_rtc_read_data(unsigned long addr)
+{
+ volatile unsigned int *rtc_adr_reg = (void *)ATLAS_RTC_ADR_REG;
+ volatile unsigned int *rtc_dat_reg = (void *)ATLAS_RTC_DAT_REG;
+
+ *rtc_adr_reg = addr;
+
+ return *rtc_dat_reg;
+}
+
+static void atlas_rtc_write_data(unsigned char data, unsigned long addr)
+{
+ volatile unsigned int *rtc_adr_reg = (void *)ATLAS_RTC_ADR_REG;
+ volatile unsigned int *rtc_dat_reg = (void *)ATLAS_RTC_DAT_REG;
+
+ *rtc_adr_reg = addr;
+ *rtc_dat_reg = data;
+}
+
+static int atlas_rtc_bcd_mode(void)
+{
+ return 0;
+}
+
+struct rtc_ops atlas_rtc_ops = {
+ &atlas_rtc_read_data,
+ &atlas_rtc_write_data,
+ &atlas_rtc_bcd_mode
+};
--- /dev/null
+/*
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved.
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Atlas specific setup.
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/mc146818rtc.h>
+#include <linux/ioport.h>
+
+#include <asm/cpu.h>
+#include <asm/bootinfo.h>
+#include <asm/irq.h>
+#include <asm/mips-boards/generic.h>
+#include <asm/mips-boards/prom.h>
+#include <asm/gt64120.h>
+#include <asm/mips-boards/atlasint.h>
+
+#if defined(CONFIG_SERIAL_CONSOLE) || defined(CONFIG_PROM_CONSOLE)
+extern void console_setup(char *, int *);
+char serial_console[20];
+#endif
+
+#ifdef CONFIG_REMOTE_DEBUG
+extern void rs_kgdb_hook(int);
+extern void saa9730_kgdb_hook(void);
+extern void breakpoint(void);
+int remote_debug = 0;
+#endif
+
+extern struct rtc_ops atlas_rtc_ops;
+
+extern void mips_reboot_setup(void);
+
+void __init atlas_setup(void)
+{
+#ifdef CONFIG_REMOTE_DEBUG
+ int rs_putDebugChar(char);
+ char rs_getDebugChar(void);
+ int saa9730_putDebugChar(char);
+ char saa9730_getDebugChar(void);
+ extern int (*putDebugChar)(char);
+ extern char (*getDebugChar)(void);
+#endif
+ char *argptr;
+
+ ioport_resource.end = 0x7fffffff;
+
+#ifdef CONFIG_SERIAL_CONSOLE
+ argptr = prom_getcmdline();
+ if ((argptr = strstr(argptr, "console=ttyS0")) == NULL) {
+ int i = 0;
+ char *s = prom_getenv("modetty0");
+ while(s[i] >= '0' && s[i] <= '9')
+ i++;
+ strcpy(serial_console, "ttyS0,");
+ strncpy(serial_console + 6, s, i);
+ prom_printf("Config serial console: %s\n", serial_console);
+ console_setup(serial_console, NULL);
+ }
+#endif
+
+#ifdef CONFIG_REMOTE_DEBUG
+ argptr = prom_getcmdline();
+ if ((argptr = strstr(argptr, "kgdb=ttyS")) != NULL) {
+ int line;
+ argptr += strlen("kgdb=ttyS");
+ if (*argptr != '0' && *argptr != '1')
+ printk("KGDB: Uknown serial line /dev/ttyS%c, "
+ "falling back to /dev/ttyS1\n", *argptr);
+ line = *argptr == '0' ? 0 : 1;
+ printk("KGDB: Using serial line /dev/ttyS%d for session\n",
+ line ? 1 : 0);
+
+ if(line == 0) {
+ rs_kgdb_hook(line);
+ putDebugChar = rs_putDebugChar;
+ getDebugChar = rs_getDebugChar;
+ } else {
+ saa9730_kgdb_hook();
+ putDebugChar = saa9730_putDebugChar;
+ getDebugChar = saa9730_getDebugChar;
+ }
+
+ prom_printf("KGDB: Using serial line /dev/ttyS%d for session, "
+ "please connect your debugger\n", line ? 1 : 0);
+
+ remote_debug = 1;
+ /* Breakpoints and stuff are in atlas_irq_setup() */
+ }
+#endif
+ argptr = prom_getcmdline();
+
+ if ((argptr = strstr(argptr, "nofpu")) != NULL)
+ mips_cpu.options &= ~MIPS_CPU_FPU;
+
+ rtc_ops = &atlas_rtc_ops;
+
+ mips_reboot_setup();
+}
--- /dev/null
+#
+# Carsten Langgaard, carstenl@mips.com
+# Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved.
+#
+# ########################################################################
+#
+# This program is free software; you can distribute it and/or modify it
+# under the terms of the GNU General Public License (Version 2) as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+#
+# #######################################################################
+#
+# Makefile for the MIPS boards generic routines under Linux.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile...
+
+.S.s:
+ $(CPP) $(CFLAGS) $< -o $*.s
+.S.o:
+ $(CC) $(CFLAGS) -c $< -o $*.o
+
+O_TARGET := mipsboards.o
+
+obj-y := mipsIRQ.o pci.o reset.o display.o init.o \
+ memory.o printf.o cmdline.o time.o
+obj-$(CONFIG_REMOTE_DEBUG) += gdb_hook.o
+
+include $(TOPDIR)/Rules.make
--- /dev/null
+/*
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved.
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Kernel command line creation using the prom monitor (YAMON) argc/argv.
+ */
+#include <linux/init.h>
+#include <linux/string.h>
+
+#include <asm/bootinfo.h>
+
+extern int prom_argc;
+extern char **prom_argv;
+
+char arcs_cmdline[COMMAND_LINE_SIZE];
+
+char * __init prom_getcmdline(void)
+{
+ return &(arcs_cmdline[0]);
+}
+
+
+void __init prom_init_cmdline(void)
+{
+ char *cp;
+ int actr;
+
+ actr = 1; /* Always ignore argv[0] */
+
+ cp = &(arcs_cmdline[0]);
+ while(actr < prom_argc) {
+ strcpy(cp, prom_argv[actr]);
+ cp += strlen(prom_argv[actr]);
+ *cp++ = ' ';
+ actr++;
+ }
+ if (cp != &(arcs_cmdline[0])) /* get rid of trailing space */
+ --cp;
+ *cp = '\0';
+}
--- /dev/null
+/*
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved.
+ *
+ * ########################################################################
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ *
+ * Display routines for display messages in MIPS boards ascii display.
+ *
+ */
+
+#include <asm/mips-boards/generic.h>
+
+
+void mips_display_message(const char *str)
+{
+ volatile unsigned int *display = (void *)ASCII_DISPLAY_POS_BASE;
+ int i;
+
+ for (i = 0; i <= 14; i=i+2) {
+ if (*str)
+ display[i] = *str++;
+ else
+ display[i] = ' ';
+ }
+}
+
+void mips_display_word(unsigned int num)
+{
+ volatile unsigned int *display = (void *)ASCII_DISPLAY_WORD_BASE;
+
+ *display = num;
+}
--- /dev/null
+/*
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved.
+ *
+ * ########################################################################
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ *
+ * This is the interface to the remote debugger stub.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/serialP.h>
+#include <linux/serial_reg.h>
+
+#include <asm/serial.h>
+#include <asm/io.h>
+
+static struct serial_state rs_table[RS_TABLE_SIZE] = {
+ SERIAL_PORT_DFNS /* Defined in serial.h */
+};
+
+static struct async_struct kdb_port_info = {0};
+
+int (*putDebugChar)(char);
+char (*getDebugChar)(void);
+
+static __inline__ unsigned int serial_in(struct async_struct *info, int offset)
+{
+ return inb(info->port + offset);
+}
+
+static __inline__ void serial_out(struct async_struct *info, int offset,
+ int value)
+{
+ outb(value, info->port+offset);
+}
+
+void rs_kgdb_hook(int tty_no) {
+ int t;
+ struct serial_state *ser = &rs_table[tty_no];
+
+ kdb_port_info.state = ser;
+ kdb_port_info.magic = SERIAL_MAGIC;
+ kdb_port_info.port = ser->port;
+ kdb_port_info.flags = ser->flags;
+
+ /*
+ * Clear all interrupts
+ */
+ serial_in(&kdb_port_info, UART_LSR);
+ serial_in(&kdb_port_info, UART_RX);
+ serial_in(&kdb_port_info, UART_IIR);
+ serial_in(&kdb_port_info, UART_MSR);
+
+ /*
+ * Now, initialize the UART
+ */
+ serial_out(&kdb_port_info, UART_LCR, UART_LCR_WLEN8); /* reset DLAB */
+ if (kdb_port_info.flags & ASYNC_FOURPORT) {
+ kdb_port_info.MCR = UART_MCR_DTR | UART_MCR_RTS;
+ t = UART_MCR_DTR | UART_MCR_OUT1;
+ } else {
+ kdb_port_info.MCR
+ = UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2;
+ t = UART_MCR_DTR | UART_MCR_RTS;
+ }
+
+ kdb_port_info.MCR = t; /* no interrupts, please */
+ serial_out(&kdb_port_info, UART_MCR, kdb_port_info.MCR);
+
+ /*
+ * and set the speed of the serial port
+ * (currently hardwired to 9600 8N1
+ */
+
+ /* baud rate is fixed to 9600 (is this sufficient?)*/
+ t = kdb_port_info.state->baud_base / 9600;
+ /* set DLAB */
+ serial_out(&kdb_port_info, UART_LCR, UART_LCR_WLEN8 | UART_LCR_DLAB);
+ serial_out(&kdb_port_info, UART_DLL, t & 0xff);/* LS of divisor */
+ serial_out(&kdb_port_info, UART_DLM, t >> 8); /* MS of divisor */
+ /* reset DLAB */
+ serial_out(&kdb_port_info, UART_LCR, UART_LCR_WLEN8);
+}
+
+int rs_putDebugChar(char c)
+{
+
+ if (!kdb_port_info.state) { /* need to init device first */
+ return 0;
+ }
+
+ while ((serial_in(&kdb_port_info, UART_LSR) & UART_LSR_THRE) == 0)
+ ;
+
+ serial_out(&kdb_port_info, UART_TX, c);
+
+ return 1;
+}
+
+char rs_getDebugChar(void)
+{
+ if (!kdb_port_info.state) { /* need to init device first */
+ return 0;
+ }
+
+ while (!(serial_in(&kdb_port_info, UART_LSR) & 1))
+ ;
+
+ return(serial_in(&kdb_port_info, UART_RX));
+}
+
+
+#ifdef CONFIG_MIPS_ATLAS
+
+#include <asm/mips-boards/atlas.h>
+#include <asm/mips-boards/saa9730_uart.h>
+
+#define INB(a) inb((unsigned long)a)
+#define OUTB(x,a) outb(x,(unsigned long)a)
+
+/*
+ * This is the interface to the remote debugger stub
+ * if the Philips part is used for the debug port,
+ * called from the platform setup code.
+ *
+ * PCI init will not have been done yet, we make a
+ * universal assumption about the way the bootloader (YAMON)
+ * have located and set up the chip.
+ */
+static t_uart_saa9730_regmap *kgdb_uart = (void *)(ATLAS_SAA9730_REG + SAA9730_UART_REGS_ADDR);
+
+static int saa9730_kgdb_active = 0;
+
+void saa9730_kgdb_hook(void)
+{
+ volatile unsigned char t;
+
+ /*
+ * Clear all interrupts
+ */
+ t = INB(&kgdb_uart->Lsr);
+ t += INB(&kgdb_uart->Msr);
+ t += INB(&kgdb_uart->Thr_Rbr);
+ t += INB(&kgdb_uart->Iir_Fcr);
+
+ /*
+ * Now, initialize the UART
+ */
+ /* 8 data bits, one stop bit, no parity */
+ OUTB(SAA9730_LCR_DATA8, &kgdb_uart->Lcr);
+
+ /* baud rate is fixed to 9600 (is this sufficient?)*/
+ OUTB(0, &kgdb_uart->BaudDivMsb); /* HACK - Assumes standard crystal */
+ OUTB(23, &kgdb_uart->BaudDivLsb); /* HACK - known for MIPS Atlas */
+
+ /* Set RTS/DTR active */
+ OUTB(SAA9730_MCR_DTR | SAA9730_MCR_RTS, &kgdb_uart->Mcr);
+ saa9730_kgdb_active = 1;
+}
+
+int saa9730_putDebugChar(char c)
+{
+
+ if (!saa9730_kgdb_active) { /* need to init device first */
+ return 0;
+ }
+
+ while (!(INB(&kgdb_uart->Lsr) & SAA9730_LSR_THRE))
+ ;
+ OUTB(c, &kgdb_uart->Thr_Rbr);
+
+ return 1;
+}
+
+char saa9730_getDebugChar(void)
+{
+ char c;
+
+ if (!saa9730_kgdb_active) { /* need to init device first */
+ return 0;
+ }
+ while (!(INB(&kgdb_uart->Lsr) & SAA9730_LSR_DR))
+ ;
+
+ c = INB(&kgdb_uart->Thr_Rbr);
+ return(c);
+}
+
+#endif
--- /dev/null
+/*
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved.
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * PROM library initialisation code.
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+
+#include <asm/io.h>
+#include <asm/mips-boards/prom.h>
+#include <asm/mips-boards/generic.h>
+#include <asm/gt64120.h>
+#include <asm/mips-boards/malta.h>
+
+/* Environment variable */
+typedef struct
+{
+ char *name;
+ char *val;
+} t_env_var;
+
+int prom_argc;
+char **prom_argv, **prom_envp;
+
+int init_debug = 0;
+
+char *prom_getenv(char *envname)
+{
+ /*
+ * Return a pointer to the given environment variable.
+ */
+
+ t_env_var *env = (t_env_var *)prom_envp;
+ int i;
+
+ i = strlen(envname);
+
+ while(env->name) {
+ if(strncmp(envname, env->name, i) == 0) {
+ return(env->val);
+ }
+ env++;
+ }
+ return(NULL);
+}
+
+static inline unsigned char str2hexnum(unsigned char c)
+{
+ if(c >= '0' && c <= '9')
+ return c - '0';
+ if(c >= 'a' && c <= 'f')
+ return c - 'a' + 10;
+ return 0; /* foo */
+}
+
+static inline void str2eaddr(unsigned char *ea, unsigned char *str)
+{
+ int i;
+
+ for(i = 0; i < 6; i++) {
+ unsigned char num;
+
+ if((*str == '.') || (*str == ':'))
+ str++;
+ num = str2hexnum(*str++) << 4;
+ num |= (str2hexnum(*str++));
+ ea[i] = num;
+ }
+}
+
+int get_ethernet_addr(char *ethernet_addr)
+{
+ char *ethaddr_str;
+
+ ethaddr_str = prom_getenv("ethaddr");
+ if (!ethaddr_str) {
+ printk("ethaddr not set in boot prom\n");
+ return -1;
+ }
+ str2eaddr(ethernet_addr, ethaddr_str);
+
+ if (init_debug > 1) {
+ int i;
+ printk("get_ethernet_addr: ");
+ for (i=0; i<5; i++)
+ printk("%02x:", (unsigned char)*(ethernet_addr+i));
+ printk("%02x\n", *(ethernet_addr+i));
+ }
+
+ return 0;
+}
+
+int __init prom_init(int argc, char **argv, char **envp)
+{
+ prom_argc = argc;
+ prom_argv = argv;
+ prom_envp = envp;
+
+ mips_display_message("LINUX");
+
+ /*
+ * Setup the North bridge to do Master byte-lane swapping when
+ * running in bigendian.
+ */
+#if defined(__MIPSEL__)
+ GT_WRITE(GT_PCI0_CMD_OFS, GT_PCI0_CMD_MBYTESWAP_BIT |
+ GT_PCI0_CMD_SBYTESWAP_BIT);
+#else
+ GT_WRITE(GT_PCI0_CMD_OFS, 0);
+#endif
+
+#if defined(CONFIG_MIPS_MALTA)
+ mips_io_port_base = MALTA_PORT_BASE;
+#else
+ mips_io_port_base = KSEG1;
+#endif
+ setup_prom_printf(0);
+ prom_printf("\nLINUX started...\n");
+ prom_init_cmdline();
+ prom_meminit();
+
+ return 0;
+}
--- /dev/null
+/*
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved.
+ *
+ * ########################################################################
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ *
+ * PROM library functions for acquiring/using memory descriptors given to
+ * us from the YAMON.
+ *
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/bootmem.h>
+
+#include <asm/bootinfo.h>
+#include <asm/page.h>
+
+#include <asm/mips-boards/prom.h>
+
+/*#define DEBUG*/
+
+enum yamon_memtypes {
+ yamon_dontuse,
+ yamon_prom,
+ yamon_free,
+};
+struct prom_pmemblock mdesc[PROM_MAX_PMEMBLOCKS];
+
+#ifdef DEBUG
+static char *mtypes[3] = {
+ "Dont use memory",
+ "YAMON PROM memory",
+ "Free memmory",
+};
+#endif
+
+
+struct prom_pmemblock * __init prom_getmdesc(void)
+{
+ char *memsize_str;
+ unsigned int memsize;
+
+ memsize_str = prom_getenv("memsize");
+ if (!memsize_str) {
+ prom_printf("memsize not set in boot prom, set to default (32Mb)\n");
+ memsize = 0x02000000;
+ } else {
+#ifdef DEBUG
+ prom_printf("prom_memsize = %s\n", memsize_str);
+#endif
+ memsize = simple_strtol(memsize_str, NULL, 0);
+ }
+
+ memset(mdesc, 0, sizeof(mdesc));
+
+ mdesc[0].type = yamon_dontuse;
+ mdesc[0].base = 0x00000000;
+ mdesc[0].size = 0x00001000;
+
+ mdesc[1].type = yamon_prom;
+ mdesc[1].base = 0x00001000;
+ mdesc[1].size = 0x000ef000;
+
+#if (CONFIG_MIPS_MALTA)
+ /*
+ * The area 0x000f0000-0x000fffff is allocated for BIOS memory by the
+ * south bridge and PCI access always forwarded to the ISA Bus and
+ * BIOSCS# is always generated.
+ * This mean that this area can't be used as DMA memory for PCI
+ * devices.
+ */
+ mdesc[2].type = yamon_dontuse;
+ mdesc[2].base = 0x000f0000;
+ mdesc[2].size = 0x00010000;
+#else
+ mdesc[2].type = yamon_prom;
+ mdesc[2].base = 0x000f0000;
+ mdesc[2].size = 0x00010000;
+#endif
+
+ mdesc[3].type = yamon_free;
+ mdesc[3].base = 0x00100000;
+ mdesc[3].size = memsize - mdesc[3].base;
+
+ return &mdesc[0];
+}
+
+static int __init prom_memtype_classify (unsigned int type)
+{
+ switch (type) {
+ case yamon_free:
+ return BOOT_MEM_RAM;
+ case yamon_prom:
+ return BOOT_MEM_ROM_DATA;
+ default:
+ return BOOT_MEM_RESERVED;
+ }
+}
+
+void __init prom_meminit(void)
+{
+ struct prom_pmemblock *p;
+
+#ifdef DEBUG
+ int i = 0;
+
+ prom_printf("YAMON MEMORY DESCRIPTOR dump:\n");
+ p = prom_getmdesc();
+ while (p->size) {
+ prom_printf("[%d,%p]: base<%08lx> size<%08lx> type<%s>\n",
+ i, p, p->base, p->size, mtypes[p->type]);
+ p++;
+ i++;
+ }
+#endif
+ p = prom_getmdesc();
+ while (p->size) {
+ unsigned long base, size;
+ long type;
+
+ type = prom_memtype_classify (p->type);
+ base = p->base;
+ size = p->size;
+
+ add_memory_region(base, size, type);
+
+ p++;
+ }
+}
+
+void prom_free_prom_memory (void)
+{
+ int i;
+ struct prom_pmemblock *p;
+ unsigned long freed = 0;
+ unsigned long addr;
+
+ for (i = 0; i < boot_mem_map.nr_map; i++) {
+ if (boot_mem_map.map[i].type != BOOT_MEM_ROM_DATA)
+ continue;
+
+ addr = boot_mem_map.map[i].addr;
+ while (addr < boot_mem_map.map[i].addr
+ + boot_mem_map.map[i].size) {
+ ClearPageReserved(virt_to_page(phys_to_virt(addr)));
+ set_page_count(virt_to_page(phys_to_virt(addr)), 1);
+ free_page(phys_to_virt(addr));
+ addr += PAGE_SIZE;
+ freed += PAGE_SIZE;
+ }
+ }
+ printk("Freeing prom memory: %ldkb freed\n", freed >> 10);
+}
--- /dev/null
+/*
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 1999, 2000 MIPS Technologies, Inc. All rights reserved.
+ *
+ * ########################################################################
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ *
+ * Interrupt exception dispatch code.
+ *
+ */
+#include <linux/config.h>
+
+#include <asm/asm.h>
+#include <asm/mipsregs.h>
+#include <asm/regdef.h>
+#include <asm/stackframe.h>
+
+/* A lot of complication here is taken away because:
+ *
+ * 1) We handle one interrupt and return, sitting in a loop and moving across
+ * all the pending IRQ bits in the cause register is _NOT_ the answer, the
+ * common case is one pending IRQ so optimize in that direction.
+ *
+ * 2) We need not check against bits in the status register IRQ mask, that
+ * would make this routine slow as hell.
+ *
+ * 3) Linux only thinks in terms of all IRQs on or all IRQs off, nothing in
+ * between like BSD spl() brain-damage.
+ *
+ * Furthermore, the IRQs on the MIPS board look basically (barring software
+ * IRQs which we don't use at all and all external interrupt sources are
+ * combined together on hardware interrupt 0 (MIPS IRQ 2)) like:
+ *
+ * MIPS IRQ Source
+ * -------- ------
+ * 0 Software (ignored)
+ * 1 Software (ignored)
+ * 2 Combined hardware interrupt (hw0)
+ * 3 Hardware (ignored)
+ * 4 Hardware (ignored)
+ * 5 Hardware (ignored)
+ * 6 Hardware (ignored)
+ * 7 R4k timer (what we use)
+ *
+ * We handle the IRQ according to _our_ priority which is:
+ *
+ * Highest ---- R4k Timer
+ * Lowest ---- Combined hardware interrupt
+ *
+ * then we just return, if multiple IRQs are pending then we will just take
+ * another exception, big deal.
+ */
+
+ .text
+ .set noreorder
+ .set noat
+ .align 5
+ NESTED(mipsIRQ, PT_SIZE, sp)
+ SAVE_ALL
+ CLI
+ .set at
+
+ mfc0 s0, CP0_CAUSE # get irq mask
+
+ /* First we check for r4k counter/timer IRQ. */
+ andi a0, s0, CAUSEF_IP7
+ beq a0, zero, 1f
+ andi a0, s0, CAUSEF_IP2 # delay slot, check hw0 interrupt
+
+ /* Wheee, a timer interrupt. */
+ move a0, sp
+ jal mips_timer_interrupt
+ nop
+
+ j ret_from_irq
+ nop
+
+1:
+ beq a0, zero, 1f
+ nop
+
+ /* Wheee, combined hardware level zero interrupt. */
+#if defined(CONFIG_MIPS_ATLAS)
+ jal atlas_hw0_irqdispatch
+#elif defined(CONFIG_MIPS_MALTA)
+ jal malta_hw0_irqdispatch
+#else
+#error "MIPS board not supported\n"
+#endif
+ move a0, sp # delay slot
+
+ j ret_from_irq
+ nop # delay slot
+
+1:
+ /*
+ * Here by mistake? This is possible, what can happen is that by the
+ * time we take the exception the IRQ pin goes low, so just leave if
+ * this is the case.
+ */
+ move a1,s0
+ PRINT("Got interrupt: c0_cause = %08x\n")
+ mfc0 a1, CP0_EPC
+ PRINT("c0_epc = %08x\n")
+
+ j ret_from_irq
+ nop
+ END(mipsIRQ)
--- /dev/null
+/*
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved.
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * MIPS boards specific PCI support.
+ *
+ */
+#include <linux/config.h>
+
+#ifdef CONFIG_PCI
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/mips-boards/generic.h>
+#include <asm/gt64120.h>
+#ifdef CONFIG_MIPS_MALTA
+#include <asm/mips-boards/malta.h>
+#endif
+
+#define PCI_ACCESS_READ 0
+#define PCI_ACCESS_WRITE 1
+
+static int
+mips_pcibios_config_access(unsigned char access_type, struct pci_dev *dev,
+ unsigned char where, u32 *data)
+{
+ unsigned char bus = dev->bus->number;
+ unsigned char dev_fn = dev->devfn;
+ u32 intr;
+
+ if ((bus == 0) && (dev_fn >= PCI_DEVFN(31,0)))
+ return -1; /* Because of a bug in the galileo (for slot 31). */
+
+ /* Clear cause register bits */
+ GT_WRITE(GT_INTRCAUSE_OFS, ~(GT_INTRCAUSE_MASABORT0_BIT |
+ GT_INTRCAUSE_TARABORT0_BIT));
+
+ /* Setup address */
+ GT_WRITE(GT_PCI0_CFGADDR_OFS,
+ (bus << GT_PCI0_CFGADDR_BUSNUM_SHF) |
+ (dev_fn << GT_PCI0_CFGADDR_FUNCTNUM_SHF) |
+ ((where / 4) << GT_PCI0_CFGADDR_REGNUM_SHF) |
+ GT_PCI0_CFGADDR_CONFIGEN_BIT);
+
+ if (access_type == PCI_ACCESS_WRITE) {
+ if (bus == 0 && dev_fn == 0) {
+ /*
+ * Galileo is acting differently than other devices.
+ */
+ GT_WRITE(GT_PCI0_CFGDATA_OFS, *data);
+ } else {
+ GT_PCI_WRITE(GT_PCI0_CFGDATA_OFS, *data);
+ }
+ } else {
+ if (bus == 0 && dev_fn == 0) {
+ /*
+ * Galileo is acting differently than other devices.
+ */
+ GT_READ(GT_PCI0_CFGDATA_OFS, *data);
+ } else {
+ GT_PCI_READ(GT_PCI0_CFGDATA_OFS, *data);
+ }
+ }
+
+ /* Check for master or target abort */
+ GT_READ(GT_INTRCAUSE_OFS, intr);
+
+ if (intr & (GT_INTRCAUSE_MASABORT0_BIT | GT_INTRCAUSE_TARABORT0_BIT))
+ {
+ /* Error occured */
+
+ /* Clear bits */
+ GT_WRITE( GT_INTRCAUSE_OFS, ~(GT_INTRCAUSE_MASABORT0_BIT |
+ GT_INTRCAUSE_TARABORT0_BIT) );
+
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/*
+ * We can't address 8 and 16 bit words directly. Instead we have to
+ * read/write a 32bit word and mask/modify the data we actually want.
+ */
+static int
+mips_pcibios_read_config_byte (struct pci_dev *dev, int where, u8 *val)
+{
+ u32 data = 0;
+
+ if (mips_pcibios_config_access(PCI_ACCESS_READ, dev, where, &data))
+ return -1;
+
+ *val = (data >> ((where & 3) << 3)) & 0xff;
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+
+static int
+mips_pcibios_read_config_word (struct pci_dev *dev, int where, u16 *val)
+{
+ u32 data = 0;
+
+ if (where & 1)
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+
+ if (mips_pcibios_config_access(PCI_ACCESS_READ, dev, where, &data))
+ return -1;
+
+ *val = (data >> ((where & 3) << 3)) & 0xffff;
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+mips_pcibios_read_config_dword (struct pci_dev *dev, int where, u32 *val)
+{
+ u32 data = 0;
+
+ if (where & 3)
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+
+ if (mips_pcibios_config_access(PCI_ACCESS_READ, dev, where, &data))
+ return -1;
+
+ *val = data;
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+
+static int
+mips_pcibios_write_config_byte (struct pci_dev *dev, int where, u8 val)
+{
+ u32 data = 0;
+
+ if (mips_pcibios_config_access(PCI_ACCESS_READ, dev, where, &data))
+ return -1;
+
+ data = (data & ~(0xff << ((where & 3) << 3))) |
+ (val << ((where & 3) << 3));
+
+ if (mips_pcibios_config_access(PCI_ACCESS_WRITE, dev, where, &data))
+ return -1;
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+mips_pcibios_write_config_word (struct pci_dev *dev, int where, u16 val)
+{
+ u32 data = 0;
+
+ if (where & 1)
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+
+ if (mips_pcibios_config_access(PCI_ACCESS_READ, dev, where, &data))
+ return -1;
+
+ data = (data & ~(0xffff << ((where & 3) << 3))) |
+ (val << ((where & 3) << 3));
+
+ if (mips_pcibios_config_access(PCI_ACCESS_WRITE, dev, where, &data))
+ return -1;
+
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+mips_pcibios_write_config_dword(struct pci_dev *dev, int where, u32 val)
+{
+ if (where & 3)
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+
+ if (mips_pcibios_config_access(PCI_ACCESS_WRITE, dev, where, &val))
+ return -1;
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+struct pci_ops mips_pci_ops = {
+ mips_pcibios_read_config_byte,
+ mips_pcibios_read_config_word,
+ mips_pcibios_read_config_dword,
+ mips_pcibios_write_config_byte,
+ mips_pcibios_write_config_word,
+ mips_pcibios_write_config_dword
+};
+
+void __init pcibios_init(void)
+{
+#ifdef CONFIG_MIPS_MALTA
+ struct pci_dev *pdev;
+ unsigned char reg_val;
+#endif
+
+ printk("PCI: Probing PCI hardware on host bus 0.\n");
+ pci_scan_bus(0, &mips_pci_ops, NULL);
+
+ /*
+ * Due to a bug in the Galileo system controller, we need to setup
+ * the PCI BAR for the Galileo internal registers.
+ * This should be done in the bios/bootprom and will be fixed in
+ * a later revision of YAMON (the MIPS boards boot prom).
+ */
+ GT_WRITE(GT_PCI0_CFGADDR_OFS,
+ (0 << GT_PCI0_CFGADDR_BUSNUM_SHF) | /* Local bus */
+ (0 << GT_PCI0_CFGADDR_DEVNUM_SHF) | /* GT64120 device */
+ (0 << GT_PCI0_CFGADDR_FUNCTNUM_SHF) | /* Function 0 */
+ ((0x20/4) << GT_PCI0_CFGADDR_REGNUM_SHF) | /* BAR 4 */
+ GT_PCI0_CFGADDR_CONFIGEN_BIT );
+
+ /* Perform the write */
+ GT_WRITE( GT_PCI0_CFGDATA_OFS, PHYSADDR(MIPS_GT_BASE));
+
+#ifdef CONFIG_MIPS_MALTA
+ pci_for_each_dev(pdev) {
+ if ((pdev->vendor == PCI_VENDOR_ID_INTEL)
+ && (pdev->device == PCI_DEVICE_ID_INTEL_82371AB)
+ && (PCI_SLOT(pdev->devfn) == 0x0a)) {
+ /*
+ * IDE Decode enable.
+ */
+ pci_read_config_byte(pdev, 0x41, ®_val);
+ pci_write_config_byte(pdev, 0x41, reg_val | 0x80);
+ pci_read_config_byte(pdev, 0x43, ®_val);
+ pci_write_config_byte(pdev, 0x43, reg_val | 0x80);
+ }
+
+ if ((pdev->vendor == PCI_VENDOR_ID_INTEL)
+ && (pdev->device == PCI_DEVICE_ID_INTEL_82371AB_0)
+ && (PCI_SLOT(pdev->devfn) == 0x0a)) {
+ /*
+ * Set top of main memory accessible by ISA or DMA
+ * devices to 16 Mb.
+ */
+ pci_read_config_byte(pdev, 0x69, ®_val);
+ pci_write_config_byte(pdev, 0x69, reg_val | 0xf0);
+ }
+ }
+
+ /*
+ * Activate Floppy Controller in the SMSC FDC37M817 Super I/O
+ * Controller.
+ * This should be done in the bios/bootprom and will be fixed in
+ * a later revision of YAMON (the MIPS boards boot prom).
+ */
+ /* Entering config state. */
+ SMSC_WRITE(SMSC_CONFIG_ENTER, SMSC_CONFIG_REG);
+
+ /* Activate floppy controller. */
+ SMSC_WRITE(SMSC_CONFIG_DEVNUM, SMSC_CONFIG_REG);
+ SMSC_WRITE(SMSC_CONFIG_DEVNUM_FLOPPY, SMSC_DATA_REG);
+ SMSC_WRITE(SMSC_CONFIG_ACTIVATE, SMSC_CONFIG_REG);
+ SMSC_WRITE(SMSC_CONFIG_ACTIVATE_ENABLE, SMSC_DATA_REG);
+
+ /* Exit config state. */
+ SMSC_WRITE(SMSC_CONFIG_EXIT, SMSC_CONFIG_REG);
+#endif
+}
+
+int __init
+pcibios_enable_device(struct pci_dev *dev)
+{
+ /* Not needed, since we enable all devices at startup. */
+ return 0;
+}
+
+void __init
+pcibios_align_resource(void *data, struct resource *res, unsigned long size)
+{
+}
+
+char * __init
+pcibios_setup(char *str)
+{
+ /* Nothing to do for now. */
+
+ return str;
+}
+
+struct pci_fixup pcibios_fixups[] = {
+ { 0 }
+};
+
+void __init
+pcibios_update_resource(struct pci_dev *dev, struct resource *root,
+ struct resource *res, int resource)
+{
+ unsigned long where, size;
+ u32 reg;
+
+ where = PCI_BASE_ADDRESS_0 + (resource * 4);
+ size = res->end - res->start;
+ pci_read_config_dword(dev, where, ®);
+ reg = (reg & size) | (((u32)(res->start - root->start)) & ~size);
+ pci_write_config_dword(dev, where, reg);
+}
+
+/*
+ * Called after each bus is probed, but before its children
+ * are examined.
+ */
+void __init pcibios_fixup_bus(struct pci_bus *b)
+{
+ pci_read_bridge_bases(b);
+}
+
+#endif /* CONFIG_PCI */
--- /dev/null
+/*
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved.
+ *
+ * ########################################################################
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ *
+ * Putting things on the screen/serial line using YAMONs facilities.
+ *
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/serialP.h>
+#include <linux/serial_reg.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/serial.h>
+
+
+#ifdef CONFIG_MIPS_ATLAS
+/*
+ * Atlas registers are memory mapped on 64-bit aligned boundaries and
+ * only word access are allowed.
+ * When reading the UART 8 bit registers only the LSB are valid.
+ */
+unsigned int atlas_serial_in(struct async_struct *info, int offset)
+{
+ return (*(volatile unsigned int *)(info->port + mips_io_port_base + offset*8) & 0xff);
+}
+
+void atlas_serial_out(struct async_struct *info, int offset, int value)
+{
+ *(volatile unsigned int *)(info->port + mips_io_port_base + offset*8) = value;
+}
+
+#define serial_in atlas_serial_in
+#define serial_out atlas_serial_out
+
+#else
+
+static unsigned int serial_in(struct async_struct *info, int offset)
+{
+ return inb(info->port + offset);
+}
+
+static void serial_out(struct async_struct *info, int offset,
+ int value)
+{
+ outb(value, info->port + offset);
+}
+#endif
+
+static struct serial_state rs_table[] = {
+ SERIAL_PORT_DFNS /* Defined in serial.h */
+};
+
+/*
+ * Hooks to fake "prom" console I/O before devices
+ * are fully initialized.
+ */
+static struct async_struct prom_port_info = {0};
+
+void __init setup_prom_printf(int tty_no) {
+ struct serial_state *ser = &rs_table[tty_no];
+
+ prom_port_info.state = ser;
+ prom_port_info.magic = SERIAL_MAGIC;
+ prom_port_info.port = ser->port;
+ prom_port_info.flags = ser->flags;
+
+ /* No setup of UART - assume YAMON left in sane state */
+}
+
+int putPromChar(char c)
+{
+ if (!prom_port_info.state) { /* need to init device first */
+ return 0;
+ }
+
+ while ((serial_in(&prom_port_info, UART_LSR) & UART_LSR_THRE) == 0)
+ ;
+
+ serial_out(&prom_port_info, UART_TX, c);
+
+ return 1;
+}
+
+char getPromChar(void)
+{
+ if (!prom_port_info.state) { /* need to init device first */
+ return 0;
+ }
+
+ while (!(serial_in(&prom_port_info, UART_LSR) & 1))
+ ;
+
+ return(serial_in(&prom_port_info, UART_RX));
+}
+
+static char buf[1024];
+
+void __init prom_printf(char *fmt, ...)
+{
+ va_list args;
+ int l;
+ char *p, *buf_end;
+ long flags;
+
+ int putPromChar(char);
+
+ /* Low level, brute force, not SMP safe... */
+ save_and_cli(flags);
+ va_start(args, fmt);
+ l = vsprintf(buf, fmt, args); /* hopefully i < sizeof(buf) */
+ va_end(args);
+
+ buf_end = buf + l;
+
+ for (p = buf; p < buf_end; p++) {
+ /* Crude cr/nl handling is better than none */
+ if(*p == '\n')putPromChar('\r');
+ putPromChar(*p);
+ }
+ restore_flags(flags);
+}
--- /dev/null
+/*
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved.
+ *
+ * ########################################################################
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ *
+ * Reset the MIPS boards.
+ *
+ */
+#include <linux/config.h>
+
+#include <asm/reboot.h>
+#include <asm/mips-boards/generic.h>
+#if defined(CONFIG_MIPS_ATLAS)
+#include <asm/mips-boards/atlas.h>
+#endif
+
+static void mips_machine_restart(char *command);
+static void mips_machine_halt(void);
+#if defined(CONFIG_MIPS_ATLAS)
+static void atlas_machine_power_off(void);
+#endif
+
+static void mips_machine_restart(char *command)
+{
+ volatile unsigned int *softres_reg = (void *)SOFTRES_REG;
+
+ *softres_reg = GORESET;
+}
+
+static void mips_machine_halt(void)
+{
+ volatile unsigned int *softres_reg = (void *)SOFTRES_REG;
+
+ *softres_reg = GORESET;
+}
+
+#if defined(CONFIG_MIPS_ATLAS)
+static void atlas_machine_power_off(void)
+{
+ volatile unsigned int *psustby_reg = (void *)ATLAS_PSUSTBY_REG;
+
+ *psustby_reg = ATLAS_GOSTBY;
+}
+#endif
+
+void mips_reboot_setup(void)
+{
+ _machine_restart = mips_machine_restart;
+ _machine_halt = mips_machine_halt;
+#if defined(CONFIG_MIPS_ATLAS)
+ _machine_power_off = atlas_machine_power_off;
+#endif
+#if defined(CONFIG_MIPS_MALTA)
+ _machine_power_off = mips_machine_halt;
+#endif
+}
--- /dev/null
+/*
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved.
+ *
+ * ########################################################################
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ *
+ * Setting up the clock on the MIPS boards.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/kernel_stat.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+
+#include <asm/mipsregs.h>
+#include <asm/ptrace.h>
+#include <asm/div64.h>
+
+#include <linux/mc146818rtc.h>
+#include <linux/timex.h>
+
+#include <asm/mips-boards/generic.h>
+#include <asm/mips-boards/prom.h>
+
+extern volatile unsigned long wall_jiffies;
+static long last_rtc_update = 0;
+unsigned long missed_heart_beats = 0;
+
+static unsigned long r4k_offset; /* Amount to increment compare reg each time */
+static unsigned long r4k_cur; /* What counter should be at next timer irq */
+extern rwlock_t xtime_lock;
+
+#define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5)
+
+#if defined(CONFIG_MIPS_ATLAS)
+static char display_string[] = " LINUX ON ATLAS ";
+#endif
+#if defined(CONFIG_MIPS_MALTA)
+static char display_string[] = " LINUX ON MALTA ";
+#endif
+static unsigned int display_count = 0;
+#define MAX_DISPLAY_COUNT (sizeof(display_string) - 8)
+
+static unsigned int timer_tick_count=0;
+
+
+static inline void ack_r4ktimer(unsigned long newval)
+{
+ write_32bit_cp0_register(CP0_COMPARE, newval);
+}
+
+
+/*
+ * In order to set the CMOS clock precisely, set_rtc_mmss has to be
+ * called 500 ms after the second nowtime has started, because when
+ * nowtime is written into the registers of the CMOS clock, it will
+ * jump to the next second precisely 500 ms later. Check the Motorola
+ * MC146818A or Dallas DS12887 data sheet for details.
+ *
+ * BUG: This routine does not handle hour overflow properly; it just
+ * sets the minutes. Usually you won't notice until after reboot!
+ */
+static int set_rtc_mmss(unsigned long nowtime)
+{
+ int retval = 0;
+ int real_seconds, real_minutes, cmos_minutes;
+ unsigned char save_control, save_freq_select;
+
+ save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */
+ CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
+
+ save_freq_select = CMOS_READ(RTC_FREQ_SELECT); /* stop and reset prescaler */
+ CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
+
+ cmos_minutes = CMOS_READ(RTC_MINUTES);
+
+ /*
+ * since we're only adjusting minutes and seconds,
+ * don't interfere with hour overflow. This avoids
+ * messing with unknown time zones but requires your
+ * RTC not to be off by more than 15 minutes
+ */
+ real_seconds = nowtime % 60;
+ real_minutes = nowtime / 60;
+ if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1)
+ real_minutes += 30; /* correct for half hour time zone */
+ real_minutes %= 60;
+
+ if (abs(real_minutes - cmos_minutes) < 30) {
+ CMOS_WRITE(real_seconds,RTC_SECONDS);
+ CMOS_WRITE(real_minutes,RTC_MINUTES);
+ } else {
+ printk(KERN_WARNING
+ "set_rtc_mmss: can't update from %d to %d\n",
+ cmos_minutes, real_minutes);
+ retval = -1;
+ }
+
+ /* The following flags have to be released exactly in this order,
+ * otherwise the DS12887 (popular MC146818A clone with integrated
+ * battery and quartz) will not reset the oscillator and will not
+ * update precisely 500 ms later. You won't find this mentioned in
+ * the Dallas Semiconductor data sheets, but who believes data
+ * sheets anyway ... -- Markus Kuhn
+ */
+ CMOS_WRITE(save_control, RTC_CONTROL);
+ CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
+
+ return retval;
+}
+
+/*
+ * There are a lot of conceptually broken versions of the MIPS timer interrupt
+ * handler floating around. This one is rather different, but the algorithm
+ * is provably more robust.
+ */
+void mips_timer_interrupt(struct pt_regs *regs)
+{
+ int irq = 7;
+
+ if (r4k_offset == 0)
+ goto null;
+
+ do {
+ kstat.irqs[0][irq]++;
+ do_timer(regs);
+
+ /* Historical comment/code:
+ * RTC time of day s updated approx. every 11
+ * minutes. Because of how the numbers work out
+ * we need to make absolutely sure we do this update
+ * within 500ms before the * next second starts,
+ * thus the following code.
+ */
+ read_lock(&xtime_lock);
+ if ((time_status & STA_UNSYNC) == 0
+ && xtime.tv_sec > last_rtc_update + 660
+ && xtime.tv_usec >= 500000 - (tick >> 1)
+ && xtime.tv_usec <= 500000 + (tick >> 1))
+ if (set_rtc_mmss(xtime.tv_sec) == 0)
+ last_rtc_update = xtime.tv_sec;
+ else
+ /* do it again in 60 s */
+ last_rtc_update = xtime.tv_sec - 600;
+ read_unlock(&xtime_lock);
+
+ if ((timer_tick_count++ % HZ) == 0) {
+ mips_display_message(&display_string[display_count++]);
+ if (display_count == MAX_DISPLAY_COUNT)
+ display_count = 0;
+ }
+
+ r4k_cur += r4k_offset;
+ ack_r4ktimer(r4k_cur);
+
+ } while (((unsigned long)read_32bit_cp0_register(CP0_COUNT)
+ - r4k_cur) < 0x7fffffff);
+
+ return;
+
+null:
+ ack_r4ktimer(0);
+}
+
+/*
+ * Figure out the r4k offset, the amount to increment the compare
+ * register for each time tick.
+ * Use the RTC to calculate offset.
+ */
+static unsigned long __init cal_r4koff(void)
+{
+ unsigned long count;
+ unsigned int flags;
+
+ __save_and_cli(flags);
+
+ /* Start counter exactly on falling edge of update flag */
+ while (CMOS_READ(RTC_REG_A) & RTC_UIP);
+ while (!(CMOS_READ(RTC_REG_A) & RTC_UIP));
+
+ /* Start r4k counter. */
+ write_32bit_cp0_register(CP0_COUNT, 0);
+
+ /* Read counter exactly on falling edge of update flag */
+ while (CMOS_READ(RTC_REG_A) & RTC_UIP);
+ while (!(CMOS_READ(RTC_REG_A) & RTC_UIP));
+
+ count = read_32bit_cp0_register(CP0_COUNT);
+
+ /* restore interrupts */
+ __restore_flags(flags);
+
+ return (count / HZ);
+}
+
+static unsigned long __init get_mips_time(void)
+{
+ unsigned int year, mon, day, hour, min, sec;
+ unsigned char save_control;
+
+ save_control = CMOS_READ(RTC_CONTROL);
+
+ /* Freeze it. */
+ CMOS_WRITE(save_control | RTC_SET, RTC_CONTROL);
+
+ /* Read regs. */
+ sec = CMOS_READ(RTC_SECONDS);
+ min = CMOS_READ(RTC_MINUTES);
+ hour = CMOS_READ(RTC_HOURS);
+
+ if (!(save_control & RTC_24H))
+ {
+ if ((hour & 0xf) == 0xc)
+ hour &= 0x80;
+ if (hour & 0x80)
+ hour = (hour & 0xf) + 12;
+ }
+ day = CMOS_READ(RTC_DAY_OF_MONTH);
+ mon = CMOS_READ(RTC_MONTH);
+ year = CMOS_READ(RTC_YEAR);
+
+ /* Unfreeze clock. */
+ CMOS_WRITE(save_control, RTC_CONTROL);
+
+ if ((year += 1900) < 1970)
+ year += 100;
+
+ return mktime(year, mon, day, hour, min, sec);
+}
+
+void __init time_init(void)
+{
+ unsigned int est_freq, flags;
+
+ /* Set Data mode - binary. */
+ CMOS_WRITE(CMOS_READ(RTC_CONTROL) | RTC_DM_BINARY, RTC_CONTROL);
+
+ printk("calculating r4koff... ");
+ r4k_offset = cal_r4koff();
+ printk("%08lx(%d)\n", r4k_offset, (int) r4k_offset);
+
+ est_freq = 2*r4k_offset*HZ;
+ est_freq += 5000; /* round */
+ est_freq -= est_freq%10000;
+ printk("CPU frequency %d.%02d MHz\n", est_freq/1000000,
+ (est_freq%1000000)*100/1000000);
+ r4k_cur = (read_32bit_cp0_register(CP0_COUNT) + r4k_offset);
+
+ write_32bit_cp0_register(CP0_COMPARE, r4k_cur);
+ change_cp0_status(ST0_IM, ALLINTS);
+
+ /* Read time from the RTC chipset. */
+ write_lock_irqsave (&xtime_lock, flags);
+ xtime.tv_sec = get_mips_time();
+ xtime.tv_usec = 0;
+ write_unlock_irqrestore(&xtime_lock, flags);
+}
+
+/* This is for machines which generate the exact clock. */
+#define USECS_PER_JIFFY (1000000/HZ)
+#define USECS_PER_JIFFY_FRAC (0x100000000*1000000/HZ&0xffffffff)
+
+/* Cycle counter value at the previous timer interrupt.. */
+
+static unsigned int timerhi = 0, timerlo = 0;
+
+/*
+ * FIXME: Does playing with the RP bit in c0_status interfere with this code?
+ */
+static unsigned long do_fast_gettimeoffset(void)
+{
+ u32 count;
+ unsigned long res, tmp;
+
+ /* Last jiffy when do_fast_gettimeoffset() was called. */
+ static unsigned long last_jiffies=0;
+ unsigned long quotient;
+
+ /*
+ * Cached "1/(clocks per usec)*2^32" value.
+ * It has to be recalculated once each jiffy.
+ */
+ static unsigned long cached_quotient=0;
+
+ tmp = jiffies;
+
+ quotient = cached_quotient;
+
+ if (tmp && last_jiffies != tmp) {
+ last_jiffies = tmp;
+#ifdef CONFIG_CPU_MIPS32
+ if (last_jiffies != 0) {
+ unsigned long r0;
+ do_div64_32(r0, timerhi, timerlo, tmp);
+ do_div64_32(quotient, USECS_PER_JIFFY,
+ USECS_PER_JIFFY_FRAC, r0);
+ cached_quotient = quotient;
+ }
+#else
+ __asm__(".set\tnoreorder\n\t"
+ ".set\tnoat\n\t"
+ ".set\tmips3\n\t"
+ "lwu\t%0,%2\n\t"
+ "dsll32\t$1,%1,0\n\t"
+ "or\t$1,$1,%0\n\t"
+ "ddivu\t$0,$1,%3\n\t"
+ "mflo\t$1\n\t"
+ "dsll32\t%0,%4,0\n\t"
+ "nop\n\t"
+ "ddivu\t$0,%0,$1\n\t"
+ "mflo\t%0\n\t"
+ ".set\tmips0\n\t"
+ ".set\tat\n\t"
+ ".set\treorder"
+ :"=&r" (quotient)
+ :"r" (timerhi),
+ "m" (timerlo),
+ "r" (tmp),
+ "r" (USECS_PER_JIFFY)
+ :"$1");
+ cached_quotient = quotient;
+#endif
+ }
+
+ /* Get last timer tick in absolute kernel time */
+ count = read_32bit_cp0_register(CP0_COUNT);
+
+ /* .. relative to previous jiffy (32 bits is enough) */
+ count -= timerlo;
+
+ __asm__("multu\t%1,%2\n\t"
+ "mfhi\t%0"
+ :"=r" (res)
+ :"r" (count),
+ "r" (quotient));
+
+ /*
+ * Due to possible jiffies inconsistencies, we need to check
+ * the result so that we'll get a timer that is monotonic.
+ */
+ if (res >= USECS_PER_JIFFY)
+ res = USECS_PER_JIFFY-1;
+
+ return res;
+}
+
+void do_gettimeofday(struct timeval *tv)
+{
+ unsigned int flags;
+
+ read_lock_irqsave (&xtime_lock, flags);
+ *tv = xtime;
+ tv->tv_usec += do_fast_gettimeoffset();
+
+ /*
+ * xtime is atomically updated in timer_bh. jiffies - wall_jiffies
+ * is nonzero if the timer bottom half hasnt executed yet.
+ */
+ if (jiffies - wall_jiffies)
+ tv->tv_usec += USECS_PER_JIFFY;
+
+ read_unlock_irqrestore (&xtime_lock, flags);
+
+ if (tv->tv_usec >= 1000000) {
+ tv->tv_usec -= 1000000;
+ tv->tv_sec++;
+ }
+}
+
+void do_settimeofday(struct timeval *tv)
+{
+ write_lock_irq (&xtime_lock);
+
+ /* This is revolting. We need to set the xtime.tv_usec correctly.
+ * However, the value in this location is is value at the last tick.
+ * Discover what correction gettimeofday would have done, and then
+ * undo it!
+ */
+ tv->tv_usec -= do_fast_gettimeoffset();
+
+ if (tv->tv_usec < 0) {
+ tv->tv_usec += 1000000;
+ tv->tv_sec--;
+ }
+
+ xtime = *tv;
+ time_adjust = 0; /* stop active adjtime() */
+ time_status |= STA_UNSYNC;
+ time_maxerror = NTP_PHASE_LIMIT;
+ time_esterror = NTP_PHASE_LIMIT;
+
+ write_unlock_irq (&xtime_lock);
+}
--- /dev/null
+#
+# Carsten Langgaard, carstenl@mips.com
+# Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved.
+#
+# ########################################################################
+#
+# This program is free software; you can distribute it and/or modify it
+# under the terms of the GNU General Public License (Version 2) as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+#
+# #######################################################################
+#
+# Makefile for the MIPS Malta specific kernel interface routines
+# under Linux.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile...
+
+.S.s:
+ $(CPP) $(CFLAGS) $< -o $*.s
+.S.o:
+ $(CC) $(CFLAGS) -c $< -o $*.o
+
+O_TARGET := malta.o
+
+obj-y := malta_int.o malta_rtc.o malta_setup.o
+
+include $(TOPDIR)/Rules.make
--- /dev/null
+/*
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved.
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Routines for generic manipulation of the interrupts found on the MIPS
+ * Malta board.
+ * The interrupt controller is located in the South Bridge a PIIX4 device
+ * with two internal 82C95 interrupt controllers.
+ */
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/kernel_stat.h>
+#include <linux/random.h>
+
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/mips-boards/malta.h>
+#include <asm/mips-boards/maltaint.h>
+#include <asm/mips-boards/piix4.h>
+#include <asm/gt64120.h>
+#include <asm/mips-boards/generic.h>
+
+extern asmlinkage void mipsIRQ(void);
+
+unsigned int local_bh_count[NR_CPUS];
+unsigned int local_irq_count[NR_CPUS];
+unsigned long spurious_count = 0;
+
+static struct irqaction *hw0_irq_action[MALTAINT_END] = {
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL
+};
+
+static struct irqaction r4ktimer_action = {
+ NULL, 0, 0, "R4000 timer/counter", NULL, NULL,
+};
+
+static struct irqaction *irq_action[8] = {
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, &r4ktimer_action
+};
+
+#if 0
+#define DEBUG_INT(x...) printk(x)
+#else
+#define DEBUG_INT(x...)
+#endif
+
+/*
+ * This contains the interrupt mask for both 82C59 interrupt controllers.
+ */
+static unsigned int cached_int_mask = 0xffff;
+
+
+void disable_irq(unsigned int irq_nr)
+{
+ unsigned long flags;
+
+ if(irq_nr >= MALTAINT_END) {
+ printk("whee, invalid irq_nr %d\n", irq_nr);
+ panic("IRQ, you lose...");
+ }
+
+ save_and_cli(flags);
+ cached_int_mask |= (1 << irq_nr);
+ if (irq_nr & 8) {
+ outb((cached_int_mask >> 8) & 0xff, PIIX4_ICTLR2_OCW1);
+ } else {
+ outb(cached_int_mask & 0xff, PIIX4_ICTLR1_OCW1);
+ }
+ restore_flags(flags);
+}
+
+
+void enable_irq(unsigned int irq_nr)
+{
+ unsigned long flags;
+
+ if(irq_nr >= MALTAINT_END) {
+ printk("whee, invalid irq_nr %d\n", irq_nr);
+ panic("IRQ, you lose...");
+ }
+
+ save_and_cli(flags);
+ cached_int_mask &= ~(1 << irq_nr);
+ if (irq_nr & 8) {
+ outb((cached_int_mask >> 8) & 0xff, PIIX4_ICTLR2_OCW1);
+
+ /* Enable irq 2 (cascade interrupt). */
+ cached_int_mask &= ~(1 << 2);
+ outb(cached_int_mask & 0xff, PIIX4_ICTLR1_OCW1);
+ } else {
+ outb(cached_int_mask & 0xff, PIIX4_ICTLR1_OCW1);
+ }
+ restore_flags(flags);
+}
+
+
+int get_irq_list(char *buf)
+{
+ int i, len = 0;
+ int num = 0;
+ struct irqaction *action;
+
+ for (i = 0; i < 8; i++, num++) {
+ action = irq_action[i];
+ if (!action)
+ continue;
+ len += sprintf(buf+len, "%2d: %8d %c %s",
+ num, kstat.irqs[0][num],
+ (action->flags & SA_INTERRUPT) ? '+' : ' ',
+ action->name);
+ for (action=action->next; action; action = action->next) {
+ len += sprintf(buf+len, ",%s %s",
+ (action->flags & SA_INTERRUPT) ? " +" : "",
+ action->name);
+ }
+ len += sprintf(buf+len, " [on-chip]\n");
+ }
+ for (i = 0; i < MALTAINT_END; i++, num++) {
+ action = hw0_irq_action[i];
+ if (!action)
+ continue;
+ len += sprintf(buf+len, "%2d: %8d %c %s",
+ num, kstat.irqs[0][num],
+ (action->flags & SA_INTERRUPT) ? '+' : ' ',
+ action->name);
+ for (action=action->next; action; action = action->next) {
+ len += sprintf(buf+len, ",%s %s",
+ (action->flags & SA_INTERRUPT) ? " +" : "",
+ action->name);
+ }
+ len += sprintf(buf+len, " [hw0]\n");
+ }
+ return len;
+}
+
+
+static int setup_irq(unsigned int irq, struct irqaction * new)
+{
+ int shared = 0;
+ struct irqaction *old, **p;
+
+ p = &hw0_irq_action[irq];
+ if ((old = *p) != NULL) {
+ /* Can't share interrupts unless both agree to */
+ if (!(old->flags & new->flags & SA_SHIRQ))
+ return -EBUSY;
+
+ /* Can't share interrupts unless both are same type */
+ if ((old->flags ^ new->flags) & SA_INTERRUPT)
+ return -EBUSY;
+
+ /* add new interrupt at end of irq queue */
+ do {
+ p = &old->next;
+ old = *p;
+ } while (old);
+ shared = 1;
+ }
+
+ if (new->flags & SA_SAMPLE_RANDOM)
+ rand_initialize_irq(irq);
+
+ *p = new;
+ if (!shared)
+ enable_irq(irq);
+
+ return 0;
+}
+
+int request_irq(unsigned int irq,
+ void (*handler)(int, void *, struct pt_regs *),
+ unsigned long irqflags,
+ const char * devname,
+ void *dev_id)
+{
+ struct irqaction *action;
+ int retval;
+
+ DEBUG_INT("request_irq: irq=%d, devname = %s\n", irq, devname);
+
+ if (irq >= MALTAINT_END)
+ return -EINVAL;
+ if (!handler)
+ return -EINVAL;
+
+ action = (struct irqaction *)kmalloc(sizeof(struct irqaction), GFP_KERNEL);
+ if(!action)
+ return -ENOMEM;
+
+ action->handler = handler;
+ action->flags = irqflags;
+ action->mask = 0;
+ action->name = devname;
+ action->dev_id = dev_id;
+ action->next = 0;
+
+ retval = setup_irq(irq, action);
+ if (retval)
+ kfree(action);
+
+ return retval;
+}
+
+
+void free_irq(unsigned int irq, void *dev_id)
+{
+ struct irqaction *action, **p;
+
+ if (irq >= MALTAINT_END) {
+ printk("Trying to free IRQ%d\n",irq);
+ return;
+ }
+
+ for (p = &hw0_irq_action[irq]; (action = *p) != NULL;
+ p = &action->next)
+ {
+ if (action->dev_id != dev_id)
+ continue;
+
+ /* Found it - now free it */
+ *p = action->next;
+ kfree(action);
+ if (!hw0_irq_action[irq])
+ disable_irq(irq);
+ return;
+ }
+ printk("Trying to free IRQ%d\n",irq);
+}
+
+void __init init_IRQ(void)
+{
+ irq_setup();
+}
+
+static inline int get_int(int *irq)
+{
+ /*
+ * Determine highest priority pending interrupt by performing
+ * a PCI Interrupt Acknowledge cycle.
+ */
+ GT_READ(GT_PCI0_IACK_OFS, *irq);
+ *irq &= 0xFF;
+
+ /*
+ * IRQ7 is used to detect spurious interrupts.
+ * The interrupt acknowledge cycle returns IRQ7, if no
+ * interrupts is requested.
+ * We can differentiate between this situation and a
+ * "Normal" IRQ7 by reading the ISR.
+ */
+ if (*irq == 7)
+ {
+ outb(PIIX4_OCW3_SEL | PIIX4_OCW3_ISR, PIIX4_ICTLR1_OCW3);
+ if (!(inb(PIIX4_ICTLR1_OCW3) & (1 << 7)))
+ return -1; /* Spurious interrupt. */
+ }
+
+ return 0;
+}
+
+static inline void ack_int(int irq)
+{
+ if (irq & 8) {
+ /* Specific EOI to cascade */
+ outb(PIIX4_OCW2_SEL | PIIX4_OCW2_NSEOI | PIIX4_OCW2_ILS_2,
+ PIIX4_ICTLR1_OCW2);
+
+ /* Non specific EOI to cascade */
+ outb(PIIX4_OCW2_SEL | PIIX4_OCW2_NSEOI, PIIX4_ICTLR2_OCW2);
+ } else {
+ /* Non specific EOI to cascade */
+ outb(PIIX4_OCW2_SEL | PIIX4_OCW2_NSEOI, PIIX4_ICTLR1_OCW2);
+ }
+}
+
+void malta_hw0_irqdispatch(struct pt_regs *regs)
+{
+ struct irqaction *action;
+ int irq=0, cpu = smp_processor_id();
+
+ DEBUG_INT("malta_hw0_irqdispatch\n");
+
+ if (get_int(&irq))
+ return; /* interrupt has already been cleared */
+
+ disable_irq(irq);
+ ack_int(irq);
+
+ DEBUG_INT("malta_hw0_irqdispatch: irq=%d\n", irq);
+ action = hw0_irq_action[irq];
+
+ /*
+ * if action == NULL, then we don't have a handler
+ * for the irq
+ */
+ if ( action == NULL )
+ return;
+
+ irq_enter(cpu, irq);
+ kstat.irqs[0][irq + 8]++;
+ do {
+ action->handler(irq, action->dev_id, regs);
+ action = action->next;
+ } while (action);
+
+ enable_irq(irq);
+ irq_exit(cpu, irq);
+}
+
+
+unsigned long probe_irq_on (void)
+{
+ unsigned int i, irqs = 0;
+ unsigned long delay;
+
+ /* first, enable any unassigned irqs */
+ for (i = MALTAINT_END-1; i > 0; i--) {
+ if (!hw0_irq_action[i]) {
+ enable_irq(i);
+ irqs |= (1 << i);
+ }
+ }
+
+ /* wait for spurious interrupts to mask themselves out again */
+ for (delay = jiffies + HZ/10; time_before(jiffies, delay); )
+ /* about 100ms delay */;
+
+ /* now filter out any obviously spurious interrupts */
+ return irqs & ~cached_int_mask;
+}
+
+
+int probe_irq_off (unsigned long irqs)
+{
+ unsigned int i;
+
+ irqs &= cached_int_mask;
+ if (!irqs)
+ return 0;
+ i = ffz(~irqs);
+ if (irqs != (irqs & (1 << i)))
+ i = -i;
+
+ return i;
+}
+
+
+void __init maltaint_init(void)
+{
+ /*
+ * Mask out all interrupt by writing "1" to all bit position in
+ * the IMR register.
+ */
+ outb(cached_int_mask & 0xff, PIIX4_ICTLR1_OCW1);
+ outb((cached_int_mask >> 8) & 0xff, PIIX4_ICTLR2_OCW1);
+
+ /* Now safe to set the exception vector. */
+ set_except_vector(0, mipsIRQ);
+}
--- /dev/null
+/*
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved.
+ *
+ * ########################################################################
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ *
+ * RTC routines for Malta style attached PIIX4 device, which contains a
+ * Motorola MC146818A-compatible Real Time Clock.
+ *
+ */
+#include <linux/spinlock.h>
+#include <linux/mc146818rtc.h>
+#include <asm/mips-boards/malta.h>
+
+static unsigned char malta_rtc_read_data(unsigned long addr)
+{
+ outb(addr, MALTA_RTC_ADR_REG);
+ return inb(MALTA_RTC_DAT_REG);
+}
+
+static void malta_rtc_write_data(unsigned char data, unsigned long addr)
+{
+ outb(addr, MALTA_RTC_ADR_REG);
+ outb(data, MALTA_RTC_DAT_REG);
+}
+
+static int malta_rtc_bcd_mode(void)
+{
+ return 0;
+}
+
+struct rtc_ops malta_rtc_ops = {
+ &malta_rtc_read_data,
+ &malta_rtc_write_data,
+ &malta_rtc_bcd_mode
+};
--- /dev/null
+/*
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved.
+ *
+ * ########################################################################
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ *
+ * Malta specific setup, including init of the feature struct.
+ *
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/mc146818rtc.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#ifdef CONFIG_BLK_DEV_IDE
+#include <linux/ide.h>
+#endif
+
+#include <asm/cpu.h>
+#include <asm/bootinfo.h>
+#include <asm/irq.h>
+#include <asm/mips-boards/generic.h>
+#include <asm/mips-boards/prom.h>
+#include <asm/mips-boards/malta.h>
+#include <asm/mips-boards/maltaint.h>
+#ifdef CONFIG_BLK_DEV_FD
+#include <asm/floppy.h>
+#endif
+#include <asm/dma.h>
+
+#if defined(CONFIG_SERIAL_CONSOLE) || defined(CONFIG_PROM_CONSOLE)
+extern void console_setup(char *, int *);
+char serial_console[20];
+#endif
+
+#ifdef CONFIG_REMOTE_DEBUG
+extern void set_debug_traps(void);
+extern void rs_kgdb_hook(int);
+extern void breakpoint(void);
+static int remote_debug = 0;
+#endif
+
+#ifdef CONFIG_BLK_DEV_IDE
+extern struct ide_ops std_ide_ops;
+#endif
+#ifdef CONFIG_BLK_DEV_FD
+extern struct fd_ops std_fd_ops;
+#endif
+extern struct rtc_ops malta_rtc_ops;
+
+extern void mips_reboot_setup(void);
+
+struct resource standard_io_resources[] = {
+ { "dma1", 0x00, 0x1f, IORESOURCE_BUSY },
+ { "pic1", 0x20, 0x3f, IORESOURCE_BUSY },
+ { "timer", 0x40, 0x5f, IORESOURCE_BUSY },
+ { "dma page reg", 0x80, 0x8f, IORESOURCE_BUSY },
+ { "pic2", 0xa0, 0xbf, IORESOURCE_BUSY },
+ { "dma2", 0xc0, 0xdf, IORESOURCE_BUSY },
+};
+
+#define STANDARD_IO_RESOURCES (sizeof(standard_io_resources)/sizeof(struct resource))
+
+static void __init malta_irq_setup(void)
+{
+ maltaint_init();
+
+#ifdef CONFIG_REMOTE_DEBUG
+ if (remote_debug) {
+ set_debug_traps();
+ breakpoint();
+ }
+#endif
+}
+
+
+void __init malta_setup(void)
+{
+#ifdef CONFIG_REMOTE_DEBUG
+ int rs_putDebugChar(char);
+ char rs_getDebugChar(void);
+ extern int (*putDebugChar)(char);
+ extern char (*getDebugChar)(void);
+#endif
+ char *argptr;
+ int i;
+
+ irq_setup = malta_irq_setup;
+
+ /* Request I/O space for devices used on the Malta board. */
+ for (i = 0; i < STANDARD_IO_RESOURCES; i++)
+ request_resource(&ioport_resource, standard_io_resources+i);
+
+ /*
+ * Enable DMA channel 4 (cascade channel) in the PIIX4 south bridge.
+ */
+ enable_dma(4);
+
+#ifdef CONFIG_SERIAL_CONSOLE
+ argptr = prom_getcmdline();
+ if ((argptr = strstr(argptr, "console=")) == NULL) {
+ argptr = prom_getcmdline();
+ strcat(argptr, " console=ttyS0,38400");
+ }
+#endif
+
+#ifdef CONFIG_REMOTE_DEBUG
+ argptr = prom_getcmdline();
+ if ((argptr = strstr(argptr, "kgdb=ttyS")) != NULL) {
+ int line;
+ argptr += strlen("kgdb=ttyS");
+ if (*argptr != '0' && *argptr != '1')
+ printk("KGDB: Uknown serial line /dev/ttyS%c, "
+ "falling back to /dev/ttyS1\n", *argptr);
+ line = *argptr == '0' ? 0 : 1;
+ printk("KGDB: Using serial line /dev/ttyS%d for session\n",
+ line ? 1 : 0);
+
+ rs_kgdb_hook(line);
+ putDebugChar = rs_putDebugChar;
+ getDebugChar = rs_getDebugChar;
+
+ prom_printf("KGDB: Using serial line /dev/ttyS%d for session, "
+ "please connect your debugger\n", line ? 1 : 0);
+
+ remote_debug = 1;
+ /* Breakpoints and stuff are in malta_irq_setup() */
+ }
+#endif
+
+ argptr = prom_getcmdline();
+ if ((argptr = strstr(argptr, "nofpu")) != NULL)
+ mips_cpu.options &= ~MIPS_CPU_FPU;
+
+ rtc_ops = &malta_rtc_ops;
+#ifdef CONFIG_BLK_DEV_IDE
+ ide_ops = &std_ide_ops;
+#endif
+#ifdef CONFIG_BLK_DEV_FD
+ fd_ops = &std_fd_ops;
+#endif
+ mips_reboot_setup();
+}
# Note 2! The CFLAGS definition is now in the main makefile...
O_TARGET := mm.o
-O_OBJS := extable.o init.o fault.o loadmmu.o
-ifdef CONFIG_CPU_R3000
-O_OBJS += r2300.o
-endif
-
-ifdef CONFIG_CPU_R4300
-O_OBJS += r4xx0.o
-endif
-
-ifdef CONFIG_CPU_R4X00
-O_OBJS += r4xx0.o
-endif
-
-ifdef CONFIG_CPU_R5000
-O_OBJS += r4xx0.o
-endif
-
-ifdef CONFIG_CPU_NEVADA
-O_OBJS += r4xx0.o
-endif
-
-ifdef CONFIG_SGI_IP22
-O_OBJS += umap.o
-endif
-
-ifdef CONFIG_BAGET_MIPS
-O_OBJS += umap.o
-endif
+export-objs += umap.o
+obj-y += extable.o init.o fault.o loadmmu.o
+
+obj-$(CONFIG_CPU_R3000) += r2300.o
+obj-$(CONFIG_CPU_R3912) += r2300.o
+obj-$(CONFIG_CPU_R4300) += r4xx0.o
+obj-$(CONFIG_CPU_R4X00) += r4xx0.o
+obj-$(CONFIG_CPU_R5000) += r4xx0.o
+obj-$(CONFIG_CPU_NEVADA) += r4xx0.o
+obj-$(CONFIG_CPU_R5432) += r5432.o
+obj-$(CONFIG_CPU_RM7000) += rm7k.o
+obj-$(CONFIG_CPU_MIPS32) += mips32.o
+obj-$(CONFIG_SGI_IP22) += umap.o
+obj-$(CONFIG_BAGET_MIPS) += umap.o
include $(TOPDIR)/Rules.make
+++ /dev/null
-#
-# This file is subject to the terms and conditions of the GNU General Public
-# License. See the file "COPYING" in the main directory of this archive
-# for more details.
-#
-#
-# Produce a bootimage for the IPSX
-# Copyright (C) 2000 Cort Dougan <cort@fsmlabs.com>
-#
-
-.S.s:
- $(CPP) $(CFLAGS) $< -o $*.s
-.S.o:
- $(CC) $(CFLAGS) -c $< -o $*.o
-
-OBJS = promcon.o char.o serial.8530.o orion.hw.init.o setup.o irq.o int-handler.o
-
-all: orionkern.a
-
-orionkern.a: $(OBJS) initrd.o #no_initrd.o
- $(AR) rcs orionkern.a $(OBJS) initrd.o #no_initrd.o
- sync
-
-initrd.c: piggyback ramdisk.image.gz
- ./piggyback initrd < ramdisk.image.gz > initrd.c
-
-piggyback: piggyback.c
- $(HOSTCC) $(HOSTCFLAGS) -o piggyback piggyback.c
-
-orionboot: orion.ctl
-
-patchapp: patchapp.c
- $(HOSTCC) -o $@ $^
-
-orion.ctl: patchapp ../../../vmlinux
- $(OBJCOPY) -Obinary ../../../vmlinux orion.nosym
- ./patchapp orion.nosym orion
- cp -f orion.bin orion.ctl
-
-# Don't build dependencies, this may die if $(CC) isn't gcc
-dep:
-
-clean:
- rm -f patchapp orion.bin orion.nosym orion.ctl initrd.c
-
-dummy:
-
-include $(TOPDIR)/Rules.make
+++ /dev/null
-#include <asm/asm.h>
-#include <asm/mipsregs.h>
-#include <asm/regdef.h>
-#include <asm/stackframe.h>
-
- .text
- .set mips1
- .set reorder
- .set macro
- .set noat
- .align 5
-
-NESTED(orionIRQ, PT_SIZE, sp)
- SAVE_ALL
- CLI # Important: mark KERNEL mode !
- /*
- * Get pending interrupts
- */
- mfc0 t0,CP0_CAUSE # get pending interrupts
- mfc0 t1,CP0_STATUS # get enabled interrupts
- and t0,t1 # isolate allowed ones
- andi t0,0xff00 # isolate pending bits
- sll t0,16 # shift the pending bits down
- beqz t0,3f # no pending intrs, then spurious
- nop # delay slot
-
- /*
- * Find irq with highest priority
- * FIXME: This is slow - use binary search
- */
- la a0,7
-1: bltz t0,2f # found pending irq
- subu a0,1
- sll t0,1
- b 1b
- nop # delay slot
-
-call_do_IRQ:
-2: move a1,sp
- jal do_IRQ
- nop # delay slot
-
- mfc0 t0,CP0_STATUS # disable interrupts
- ori t0,1
- xori t0,1
- mtc0 t0,CP0_STATUS
-
- la a1, ret_from_irq
- jr a1
-
-3: j spurious_interrupt
-END(orionIRQ)
-
+++ /dev/null
-/*
- * Code to handle irqs on Orion boards
- * -- Cort <cort@fsmlabs.com>
- */
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/kernel_stat.h>
-#include <linux/module.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/types.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/timex.h>
-#include <linux/slab.h>
-#include <linux/random.h>
-
-#include <asm/bitops.h>
-#include <asm/bootinfo.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/mipsregs.h>
-#include <asm/system.h>
-#include <asm/orion.h>
-
-void (*board_time_init)(struct irqaction *irq);
-extern asmlinkage void orionIRQ(void);
-unsigned long spurious_count = 0;
-irq_desc_t irq_desc[NR_IRQS];
-
-static void galileo_ack(unsigned int irq_nr)
-{
- *((unsigned long *) (((unsigned)( 0x14000000 )|0xA0000000) + 0xC18) ) = (((( 0 )&0xff)<<24)+ ((( 0 )&0xff00)<<8)+ ((( 0 )&0xff0000)>>8)+ ((( 0 )&0xff000000)>>24)) ;
-}
-
-struct hw_interrupt_type galileo_pic = {
- " Galileo ",
- NULL,
- NULL,
- NULL, /* unmask_irq */
- NULL, /* mask_irq */
- galileo_ack, /* mask_and_ack */
- 0
-};
-
-/* Function for careful CP0 interrupt mask access */
-static inline void modify_cp0_intmask(unsigned clr_mask, unsigned set_mask)
-{
- unsigned long status = read_32bit_cp0_register(CP0_STATUS);
- status &= ~((clr_mask & 0xFF) << 8);
- status |= (set_mask & 0xFF) << 8;
- write_32bit_cp0_register(CP0_STATUS, status);
-}
-
-static inline void mask_irq(unsigned int irq_nr)
-{
- modify_cp0_intmask(irq_nr, 0);
-}
-
-static inline void unmask_irq(unsigned int irq_nr)
-{
- modify_cp0_intmask(0, irq_nr);
-}
-
-void disable_irq(unsigned int irq_nr)
-{
- unsigned long flags;
-
- save_and_cli(flags);
- mask_irq(irq_nr);
- restore_flags(flags);
-}
-
-void enable_irq(unsigned int irq_nr)
-{
- unsigned long flags;
-
- save_and_cli(flags);
- unmask_irq(irq_nr);
- restore_flags(flags);
-}
-
-/*static struct irqaction *irq_action[NR_IRQS] = {
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
-};
-*/
-void __init orion_time_init(struct irqaction *irq)
-{
- __u32 timer_count;
-
- irq_desc[2].handler = &galileo_pic;
- irq_desc[2].action = irq;
-
- /* This code was provided by the CoSine guys and despite its
- * appearance init's the timer.
- * -- Cort
- */
- *((__u32 *) (((unsigned)( 0x14000000 )|0xA0000000) + 0x864) ) = (((( 0 )&0xff)<<24)+ ((( 0 )&0xff00)<<8)+ ((( 0 )&0xff0000)>>8)+ ((( 0 )&0xff000000)>>24)) ;
-
- *((__u32 *) (((unsigned)( 0x14000000 )|0xA0000000) + 0x850) ) = (((( 0 )&0xff)<<24)+ ((( 0 )&0xff00)<<8)+ ((( 0 )&0xff0000)>>8)+ ((( 0 )&0xff000000)>>24)) ;
-
- timer_count = 300000000/100;
-
- *((__u32 *) (((unsigned)( 0x14000000 )|0xA0000000) + 0x850) ) = (((( timer_count )&0xff)<<24)+ ((( timer_count )&0xff00)<<8)+ ((( timer_count )&0xff0000)>>8)+ ((( timer_count )&0xff000000)>>24)) ;
-
- *((__u32 *) (((unsigned)( 0x14000000 )|0xA0000000) + 0xC1C) ) = (((( 0x100 )&0xff)<<24)+ ((( 0x100 )&0xff00)<<8)+ ((( 0x100 )&0xff0000)>>8)+ ((( 0x100 )&0xff000000)>>24)) ;
-
- *((__u32 *) (((unsigned)( 0x14000000 )|0xA0000000) + 0x864) ) = (((( 0x03 )&0xff)<<24)+ ((( 0x03 )&0xff00)<<8)+ ((( 0x03 )&0xff0000)>>8)+ ((( 0x03 )&0xff000000)>>24)) ;
-
- *((__u32 *) (((unsigned)( 0x14000000 )|0xA0000000) + 0xC18) ) = (((( 0 )&0xff)<<24)+ ((( 0 )&0xff00)<<8)+ ((( 0 )&0xff0000)>>8)+ ((( 0 )&0xff000000)>>24)) ;
-}
-
-int get_irq_list(char *buf)
-{
- int i, len = 0, j;
- struct irqaction * action;
-
- len += sprintf(buf+len, " ");
- for (j=0; j<smp_num_cpus; j++)
- len += sprintf(buf+len, "CPU%d ",j);
- *(char *)(buf+len++) = '\n';
-
- for (i = 0 ; i < NR_IRQS ; i++) {
- action = irq_desc[i].action;
- if ( !action || !action->handler )
- continue;
- len += sprintf(buf+len, "%3d: ", i);
- len += sprintf(buf+len, "%10u ", kstat_irqs(i));
- if ( irq_desc[i].handler )
- len += sprintf(buf+len, " %s ", irq_desc[i].handler->typename );
- else
- len += sprintf(buf+len, " None ");
- len += sprintf(buf+len, " %s",action->name);
- for (action=action->next; action; action = action->next) {
- len += sprintf(buf+len, ", %s", action->name);
- }
- len += sprintf(buf+len, "\n");
- }
- len += sprintf(buf+len, "BAD: %10lu\n", spurious_count);
- return len;
-}
-
-asmlinkage void do_IRQ(int irq, struct pt_regs * regs)
-{
- struct irqaction *action;
- int do_random, cpu;
- int status;
-
- cpu = smp_processor_id();
- irq_enter(cpu);
- kstat.irqs[cpu][irq]++;
- status = 0;
-
- if (irq_desc[irq].handler->ack)
- irq_desc[irq].handler->ack(irq);
-
- action = irq_desc[irq].action;
- if (action && action->handler)
- {
- if (!(action->flags & SA_INTERRUPT))
- __sti();
- do {
- status |= action->flags;
- action->handler(irq, action->dev_id, regs);
- action = action->next;
- } while ( action );
- __cli();
- if (irq_desc[irq].handler)
- {
- if (irq_desc[irq].handler->end)
- irq_desc[irq].handler->end(irq);
- else if (irq_desc[irq].handler->enable)
- irq_desc[irq].handler->enable(irq);
- }
- }
-
- irq_exit(cpu);
-
- if (softirq_active(cpu)&softirq_mask(cpu))
- do_softirq();
-
- /* unmasking and bottom half handling is done magically for us. */
-}
-
-int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
- unsigned long irqflags, const char * devname, void *dev_id)
-{
- struct irqaction *old, **p, *action;
- unsigned long flags;
-
- if (irq >= NR_IRQS)
- return -EINVAL;
- if (!handler)
- {
- /* Free */
- for (p = &irq_desc[irq].action; (action = *p) != NULL; p = &action->next)
- {
- /* Found it - now free it */
- save_flags(flags);
- cli();
- *p = action->next;
- restore_flags(flags);
- kfree(action);
- return 0;
- }
- return -ENOENT;
- }
-
- action = (struct irqaction *)
- kmalloc(sizeof(struct irqaction), GFP_KERNEL);
- if (!action)
- return -ENOMEM;
-
- save_flags(flags);
- cli();
-
- action->handler = handler;
- action->flags = irqflags;
- action->mask = 0;
- action->name = devname;
- action->dev_id = dev_id;
- action->next = NULL;
- enable_irq(irq);
-
- p = &irq_desc[irq].action;
-
- if ((old = *p) != NULL) {
- /* Can't share interrupts unless both agree to */
- if (!(old->flags & action->flags & SA_SHIRQ))
- return -EBUSY;
- /* add new interrupt at end of irq queue */
- do {
- p = &old->next;
- old = *p;
- } while (old);
- }
- *p = action;
-
- restore_flags(flags);
- return 0;
-}
-
-void free_irq(unsigned int irq, void *dev_id)
-{
- request_irq(irq, NULL, 0, NULL, dev_id);
-}
-
-
-unsigned long probe_irq_on (void)
-{
- return 0;
-}
-
-int probe_irq_off (unsigned long irqs)
-{
- return 0;
-}
-
-int (*irq_cannonicalize)(int irq);
-
-int orion_irq_cannonicalize(int i)
-{
- return i;
-}
-
-void __init init_IRQ(void)
-{
-
- irq_cannonicalize = orion_irq_cannonicalize;
- set_except_vector(0, orionIRQ);
-}
-
-EXPORT_SYMBOL(irq_cannonicalize);
-
+++ /dev/null
-OUTPUT_FORMAT("elf32-bigmips")
-OUTPUT_ARCH(mips)
-ENTRY(kernel_entry)
-SECTIONS
-{
- /* Read-only sections, merged into text segment: */
- . = 0x80100000;
- /* app_header is needed for the Orion bootloader -- Cort */
- .app_header : { *(.app_header) }
- .init : { *(.init) } =0
- .text :
- {
- _ftext = . ;
- *(.text)
- *(.rodata)
- *(.rodata1)
- /* .gnu.warning sections are handled specially by elf32.em. */
- *(.gnu.warning)
- } =0
- _etext = .;
- PROVIDE (etext = .);
-
- . = ALIGN(8192);
- .data.init_task : { *(.data.init_task) }
-
- /* Startup code */
- . = ALIGN(4096);
- __init_begin = .;
- .text.init : { *(.text.init) }
- .data.init : { *(.data.init) }
- . = ALIGN(16);
- __setup_start = .;
- .setup.init : { *(.setup.init) }
- __setup_end = .;
- __initcall_start = .;
- .initcall.init : { *(.initcall.init) }
- __initcall_end = .;
- . = ALIGN(4096); /* Align double page for init_task_union */
- __init_end = .;
-
- . = ALIGN(4096);
- .data.page_aligned : { *(.data.idt) }
-
- . = ALIGN(32);
- .data.cacheline_aligned : { *(.data.cacheline_aligned) }
-
- .fini : { *(.fini) } =0
- .reginfo : { *(.reginfo) }
- /* Adjust the address for the data segment. We want to adjust up to
- the same address within the page on the next page up. It would
- be more correct to do this:
- . = .;
- The current expression does not correctly handle the case of a
- text segment ending precisely at the end of a page; it causes the
- data segment to skip a page. The above expression does not have
- this problem, but it will currently (2/95) cause BFD to allocate
- a single segment, combining both text and data, for this case.
- This will prevent the text segment from being shared among
- multiple executions of the program; I think that is more
- important than losing a page of the virtual address space (note
- that no actual memory is lost; the page which is skipped can not
- be referenced). */
- . = .;
- .data :
- {
- _fdata = . ;
- *(.data)
- CONSTRUCTORS
- }
- .data1 : { *(.data1) }
- _gp = . + 0x8000;
- .lit8 : { *(.lit8) }
- .lit4 : { *(.lit4) }
- .ctors : { *(.ctors) }
- .dtors : { *(.dtors) }
- .got : { *(.got.plt) *(.got) }
- .dynamic : { *(.dynamic) }
- /* We want the small data sections together, so single-instruction offsets
- can access them all, and initialized data all before uninitialized, so
- we can shorten the on-disk segment size. */
- .sdata : { *(.sdata) }
- _edata = .;
- PROVIDE (edata = .);
-
- __bss_start = .;
- _fbss = .;
- .sbss : { *(.sbss) *(.scommon) }
- .bss :
- {
- *(.dynbss)
- *(.bss)
- *(COMMON)
- _end = . ;
- PROVIDE (end = .);
- }
- /* These are needed for ELF backends which have not yet been
- converted to the new style linker. */
- .stab 0 : { *(.stab) }
- .stabstr 0 : { *(.stabstr) }
- /* DWARF debug sections.
- Symbols in the .debug DWARF section are relative to the beginning of the
- section so we begin .debug at 0. It's not clear yet what needs to happen
- for the others. */
- .debug 0 : { *(.debug) }
- .debug_srcinfo 0 : { *(.debug_srcinfo) }
- .debug_aranges 0 : { *(.debug_aranges) }
- .debug_pubnames 0 : { *(.debug_pubnames) }
- .debug_sfnames 0 : { *(.debug_sfnames) }
- .line 0 : { *(.line) }
- /* These must appear regardless of . */
- .gptab.sdata : { *(.gptab.data) *(.gptab.sdata) }
- .gptab.sbss : { *(.gptab.bss) *(.gptab.sbss) }
-}
+++ /dev/null
-/*
- * Catch-all for Orion-specify code that doesn't fit easily elsewhere.
- * -- Cort
- */
-
-#include <linux/config.h>
-#include <linux/errno.h>
-#include <linux/hdreg.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/stddef.h>
-#include <linux/string.h>
-#include <linux/unistd.h>
-#include <linux/ptrace.h>
-#include <linux/slab.h>
-#include <linux/user.h>
-#include <linux/utsname.h>
-#include <linux/a.out.h>
-#include <linux/tty.h>
-#ifdef CONFIG_BLK_DEV_RAM
-#include <linux/blk.h>
-#endif
-#include <linux/ide.h>
-#ifdef CONFIG_RTC
-#include <linux/timex.h>
-#endif
-
-#include <asm/asm.h>
-#include <asm/bootinfo.h>
-#include <asm/cachectl.h>
-#include <asm/io.h>
-#include <asm/stackframe.h>
-#include <asm/system.h>
-#include <asm/cpu.h>
-#include <linux/bootmem.h>
-#include <asm/addrspace.h>
-#include <asm/mc146818rtc.h>
-
-char arcs_cmdline[CL_SIZE] = {0, };
-extern int _end;
-
-static unsigned char orion_rtc_read_data(unsigned long addr)
-{
- return 0;
-}
-
-static void orion_rtc_write_data(unsigned char data, unsigned long addr)
-{
-}
-
-static int orion_rtc_bcd_mode(void)
-{
- return 0;
-}
-
-struct rtc_ops orion_rtc_ops = {
- &orion_rtc_read_data,
- &orion_rtc_write_data,
- &orion_rtc_bcd_mode
-};
-
-extern void InitCIB(void);
-extern void InitQpic(void);
-extern void InitCupid(void);
-
-void __init orion_setup(void)
-{
- InitCIB();
- InitQpic();
- InitCupid();
-}
-
-#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
-#define PFN_ALIGN(x) (((unsigned long)(x) + (PAGE_SIZE - 1)) & PAGE_MASK)
-
-
-
-int orion_sysinit(void)
-{
- unsigned long mem_size, free_start, free_end, start_pfn, bootmap_size;
-
- mips_machgroup = MACH_GROUP_ORION;
- /* 64 MB non-upgradable */
- mem_size = 32 << 20;
-
- free_start = PHYSADDR(PFN_ALIGN(&_end));
- free_end = mem_size;
- start_pfn = PFN_UP((unsigned long)&_end);
-
- /* Register all the contiguous memory with the bootmem allocator
- and free it. Be careful about the bootmem freemap. */
- bootmap_size = init_bootmem(start_pfn, mem_size >> PAGE_SHIFT);
-
- /* Free the entire available memory after the _end symbol. */
- free_start += bootmap_size;
- free_bootmem(free_start, free_end-free_start);
-}
+++ /dev/null
-unsigned long *orion_initrd_start = 0;
-unsigned long orion_initrd_size = 0;
+++ /dev/null
-#include <stdio.h>
-#include <unistd.h>
-
-extern long ce_exec_config[];
-
-int main(int argc, char *argv[])
-{
- int i, cnt, pos, len;
- unsigned int cksum, val;
- unsigned char *lp;
- unsigned char buf[8192];
- if (argc != 2)
- {
- fprintf(stderr, "usage: %s name <in-file >out-file\n",
- argv[0]);
- exit(1);
- }
- fprintf(stdout, "/*\n");
- fprintf(stdout, "* Miscellaneous data structures:\n");
- fprintf(stdout, "* WARNING - this file is automatically generated!\n");
- fprintf(stdout, "*/\n");
- fprintf(stdout, "\n");
- fprintf(stdout, "unsigned long orion_%s_start[] = {\n", argv[1]);
- pos = 0;
- cksum = 0;
- while ((len = read(0, buf, sizeof(buf))) > 0)
- {
- cnt = 0;
- lp = (unsigned char *)buf;
- len = (len + 3) & ~3; /* Round up to longwords */
- for (i = 0; i < len; i += 4)
- {
- if (cnt == 0)
- {
- fprintf(stdout, "\t");
- }
- fprintf(stdout, "0x%02X%02X%02X%02X", lp[0], lp[1], lp[2], lp[3]);
- val = *(unsigned long *)lp;
- cksum ^= val;
- lp += 4;
- if (++cnt == 4)
- {
- cnt = 0;
- fprintf(stdout, ", /* %x */\n", pos+i-12);
- fflush(stdout);
- } else
- {
- fprintf(stdout, ",");
- }
- }
- pos += len;
- }
- fprintf(stdout, "0 };\n");
- fprintf(stdout, "unsigned long orion_%s_size = 0x%x;\n", argv[1], pos);
- fflush(stdout);
- fclose(stdout);
- fprintf(stderr, "cksum = %x\n", cksum);
- exit(0);
-}
+++ /dev/null
-/*
- * Wrap-around code for a console using the
- * SGI PROM io-routines.
- *
- * Copyright (c) 1999 Ulf Carlsson
- *
- * Derived from DECstation promcon.c
- * Copyright (c) 1998 Harald Koerfgen
- */
-
-#include <linux/tty.h>
-#include <linux/major.h>
-#include <linux/ptrace.h>
-#include <linux/init.h>
-#include <linux/console.h>
-#include <linux/fs.h>
-/*
-#include <asm/sgialib.h>
-*/
-extern void prom_printf(char *fmt, ...);
-unsigned long splx(unsigned long mask){return 0;}
-#if 0
-unsigned long ramsize=0x100000;
-unsigned long RamSize(){return ramsize;}
-extern void prom_printf(char *fmt, ...);
-unsigned long splx(unsigned long mask){return 0;}
-long PssSetIntHandler(unsigned long intnum, void *handler){}
-long PssEnableInt(unsigned long intnum){}
-long PssDisableInt(unsigned long intnum){}
-unsigned long t_ident(char name[4], unsigned long node, unsigned long *tid){}
-#endif
-
-extern void SerialPollConout(unsigned char c);
-static void prom_console_write(struct console *co, const char *s,
- unsigned count)
-{
- unsigned i;
-
- /*
- * Now, do each character
- */
- for (i = 0; i < count; i++) {
- if (*s == 10)
- SerialPollConout(13);
- SerialPollConout(*s++);
- }
-}
-extern int prom_getchar(void);
-static int prom_console_wait_key(struct console *co)
-{
- return prom_getchar();
-}
-
-extern void SerialPollInit(void);
-extern void SerialSetup(unsigned long baud, unsigned long console, unsigned long host, unsigned long intr_desc);
-static int __init prom_console_setup(struct console *co, char *options)
-{
- SerialSetup(19200,1,1,3);
- SerialPollInit();
- SerialPollOn();
- return 0;
-}
-
-static kdev_t prom_console_device(struct console *c)
-{
- return MKDEV(TTY_MAJOR, 64 + c->index);
-}
-
-static struct console sercons =
-{
- name: "ttyS",
- write: prom_console_write,
- device: prom_console_device,
- wait_key: prom_console_wait_key,
- setup: prom_console_setup,
- flags: CON_PRINTBUFFER,
- index: -1,
-};
-
-/*
- * Register console.
- */
-
-void serial_console_init(void)
-{
- register_console(&sercons);
-}
-
-extern void prom_putchar(int mychar);
-
-static char ppbuf[1000];
-
-
-void prom_printf(char *fmt, ...)
-{
- va_list args;
- char ch, *bptr;
- int i;
-
- va_start(args, fmt);
- i = vsprintf(ppbuf, fmt, args);
-
- bptr = ppbuf;
-
- while((ch = *(bptr++)) != 0) {
- if(ch == '\n')
- prom_putchar('\r');
-
- prom_putchar(ch);
- }
- va_end(args);
- return;
-}
-
-
-
-void prom_putchar(int mychar){}
-int prom_getchar(void){return 0;}
-struct app_header_s {
- unsigned long MAGIC_JMP;
- unsigned long MAGIC_NOP;
- unsigned long header_tag;
- unsigned long header_flags;
- unsigned long header_length;
- unsigned long header_cksum;
-
- void *load_addr;
- void *end_addr;
- void *start_addr;
- char *app_name_p;
- char *version_p;
- char *date_p;
- char *time_p;
- unsigned long type;
- unsigned long crc;
- unsigned long reserved;
-};
-typedef struct app_header_s app_header_t;
-char linked_app_name[]="linux";
-char *linked_app_name_p=&linked_app_name[0];
-
-char linked_app_ver[]="2.4 -test1";
-char *linked_app_ver_p=&linked_app_ver[0];
-
-char linked_app_date[]="today";
-char *linked_app_date_p=&linked_app_date[0];
-
-char linked_app_time[]="now";
-char *linked_app_time_p=&linked_app_time[0];
-extern void *__bss_start;
-extern void *kernel_entry;
-
-app_header_t app_header __attribute__ ((section (".app_header"))) = {
- (0x10000000 | (((sizeof(app_header_t)>>2)-1) & 0xffff)) ,
- 0 ,
- (((( 0x4321 ) & 0xFFFF) << 16) | (( 0x0100 ) & 0xFFFF)) ,
- 0x80000000 ,
- sizeof(app_header_t),
- 0,
- &app_header,
- &__bss_start,
- &kernel_entry,
- linked_app_name,
- linked_app_ver,
- linked_app_date,
- linked_app_time,
- 0
-};
+++ /dev/null
-/*
- * Catch-all for Orion-specific code that doesn't fit easily elsewhere.
- * -- Cort
- */
-#include <linux/config.h>
-#include <linux/errno.h>
-#include <linux/hdreg.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/stddef.h>
-#include <linux/string.h>
-#include <linux/unistd.h>
-#include <linux/ptrace.h>
-#include <linux/slab.h>
-#include <linux/user.h>
-#include <linux/utsname.h>
-#include <linux/a.out.h>
-#include <linux/tty.h>
-#include <linux/interrupt.h>
-#ifdef CONFIG_BLK_DEV_RAM
-#include <linux/blk.h>
-#endif
-#include <linux/ide.h>
-#ifdef CONFIG_RTC
-#include <linux/timex.h>
-#endif
-
-#include <asm/asm.h>
-#include <asm/bootinfo.h>
-#include <asm/cachectl.h>
-#include <asm/io.h>
-#include <asm/stackframe.h>
-#include <asm/system.h>
-#include <asm/cpu.h>
-#include <linux/bootmem.h>
-#include <asm/addrspace.h>
-#include <asm/mc146818rtc.h>
-#include <asm/orion.h>
-
-char arcs_cmdline[CL_SIZE] = { "console=ttyS0,19200" };
-extern int _end;
-
-static unsigned char orion_rtc_read_data(unsigned long addr)
-{
- return 0;
-}
-
-static void orion_rtc_write_data(unsigned char data, unsigned long addr)
-{
-}
-
-static int orion_rtc_bcd_mode(void)
-{
- return 0;
-}
-
-struct rtc_ops orion_rtc_ops = {
- &orion_rtc_read_data,
- &orion_rtc_write_data,
- &orion_rtc_bcd_mode
-};
-
-extern void InitCIB(void);
-extern void InitQpic(void);
-extern void InitCupid(void);
-
-void __init orion_setup(void)
-{
- extern void (*board_time_init)(struct irqaction *irq);
- void orion_time_init(struct irqaction *);
-
- rtc_ops = &orion_rtc_ops;
- board_time_init = orion_time_init;
- mips_io_port_base = GT64120_BASE;
-
- InitCIB();
- InitQpic();
- InitCupid();
-}
-
-#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
-#define PFN_ALIGN(x) (((unsigned long)(x) + (PAGE_SIZE - 1)) & PAGE_MASK)
-
-unsigned long mem_size;
-int __init prom_init(int a, char **b, char **c, int *d)
-{
- unsigned long free_start, free_end, start_pfn, bootmap_size;
- extern unsigned long orion_initrd_start[], orion_initrd_size;
-
- mips_machgroup = MACH_GROUP_ORION;
- /* 64 MB non-upgradable */
- mem_size = 64 << 20;
-
- free_start = PHYSADDR(PFN_ALIGN(&_end));
- free_end = mem_size;
- start_pfn = PFN_UP((unsigned long)&_end);
-
- /* Register all the contiguous memory with the bootmem allocator
- and free it. Be careful about the bootmem freemap. */
- bootmap_size = init_bootmem(start_pfn, mem_size >> PAGE_SHIFT);
-
- /* Free the entire available memory after the _end symbol. */
- free_start += bootmap_size;
- free_bootmem(free_start, free_end-free_start);
-
- initrd_start = (ulong)orion_initrd_start;
- initrd_end = (ulong)orion_initrd_start + (ulong)orion_initrd_size;
- initrd_below_start_ok = 1;
-
- return 0;
-}
-
-void prom_free_prom_memory (void)
-{
-}
-
-int page_is_ram(unsigned long pagenr)
-{
- if ( pagenr < (mem_size >> PAGE_SHIFT) )
- return 1;
- return 0;
-}
.S.o:
$(CC) $(CFLAGS) -c $< -o $*.o
-OBJS = indy_mc.o indy_sc.o indy_hpc.o indy_int.o indy_rtc.o \
- system.o indyIRQ.o reset.o setup.o time.o
-ifdef CONFIG_SGI_PROM_CONSOLE
-OBJS += promcon.o
-endif
+O_TARGET := ip22-kern.o
-all: sgikern.a
+all: ip22-kern.o indyIRQ.o
-sgikern.a: $(OBJS)
- $(AR) rcs sgikern.a $(OBJS)
- sync
+obj-y += indy_mc.o indy_sc.o indy_hpc.o indy_int.o indy_rtc.o system.o \
+ indyIRQ.o reset.o setup.o time.o
indyIRQ.o: indyIRQ.S
-dep:
- $(CPP) $(CPPFLAGS) -M *.c > .depend
-
include $(TOPDIR)/Rules.make
-# $Id: Makefile,v 1.3 1999/01/04 16:03:57 ralf Exp $
#
# Makefile for the SNI specific part of the kernel
#
.S.o:
$(CC) $(CFLAGS) -c $< -o $*.o
-all: sni.o
+all: sni.o int-handler.o
+
O_TARGET := sni.o
-O_OBJS := dma.o int-handler.o io.o pci.o pcimt_scache.o reset.o setup.o
-int-handler.o: int-handler.S
+obj-y := int-handler.o io.o irq.o pci.o pcimt_scache.o reset.o setup.o
-clean:
+int-handler.o: int-handler.S
include $(TOPDIR)/Rules.make
fi
endmenu
+define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y
+define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n
+
#
# Select some configuration options automatically based on user selections
#
# CONFIG_BRIDGE is not set
#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
# Telephony Support
#
# CONFIG_PHONE is not set
# CONFIG_MAC_PARTITION is not set
CONFIG_MSDOS_PARTITION=y
# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
# CONFIG_SOLARIS_X86_PARTITION is not set
# CONFIG_UNIXWARE_DISKLABEL is not set
CONFIG_SGI_PARTITION=y
# CONFIG_BRIDGE is not set
#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
# Telephony Support
#
# CONFIG_PHONE is not set
# CONFIG_BRIDGE is not set
#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
# Telephony Support
#
# CONFIG_PHONE is not set
# CONFIG_SCSI_AHA1542 is not set
# CONFIG_SCSI_AHA1740 is not set
# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
# CONFIG_SCSI_ADVANSYS is not set
# CONFIG_SCSI_IN2000 is not set
# CONFIG_SCSI_AM53C974 is not set
# CONFIG_MAC_PARTITION is not set
CONFIG_MSDOS_PARTITION=y
# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
# CONFIG_SOLARIS_X86_PARTITION is not set
# CONFIG_UNIXWARE_DISKLABEL is not set
CONFIG_SGI_PARTITION=y
{
return waking_non_zero_trylock(sem);
}
-
-/*
- * RW Semaphores
- */
-void
-__down_read(struct rw_semaphore *sem, int count)
-{
- DOWN_VAR;
-
- retry_down:
- if (count < 0) {
- /* Wait for the lock to become unbiased. Readers
- are non-exclusive. */
-
- /* This takes care of granting the lock. */
- up_read(sem);
-
- add_wait_queue(&sem->wait, &wait);
- while (atomic_read(&sem->count) < 0) {
- set_task_state(tsk, TASK_UNINTERRUPTIBLE);
- if (atomic_read(&sem->count) >= 0)
- break;
- schedule();
- }
-
- remove_wait_queue(&sem->wait, &wait);
- tsk->state = TASK_RUNNING;
-
- mb();
- count = atomic_dec_return(&sem->count);
- if (count <= 0)
- goto retry_down;
- } else {
- add_wait_queue(&sem->wait, &wait);
-
- while (1) {
- if (test_and_clear_bit(0, &sem->granted))
- break;
- set_task_state(tsk, TASK_UNINTERRUPTIBLE);
- if ((sem->granted & 1) == 0)
- schedule();
- }
-
- remove_wait_queue(&sem->wait, &wait);
- tsk->state = TASK_RUNNING;
- }
-}
-
-void
-__down_write(struct rw_semaphore *sem, int count)
-{
- DOWN_VAR;
-
- retry_down:
- if (count + RW_LOCK_BIAS < 0) {
- up_write(sem);
-
- add_wait_queue_exclusive(&sem->wait, &wait);
-
- while (atomic_read(&sem->count) < 0) {
- set_task_state(tsk, TASK_UNINTERRUPTIBLE);
- if (atomic_read(&sem->count) >= RW_LOCK_BIAS)
- break;
- schedule();
- }
-
- remove_wait_queue(&sem->wait, &wait);
- tsk->state = TASK_RUNNING;
-
- mb();
- count = atomic_sub_return(RW_LOCK_BIAS, &sem->count);
- if (count != 0)
- goto retry_down;
- } else {
- /* Put ourselves at the end of the list. */
- add_wait_queue_exclusive(&sem->write_bias_wait, &wait);
-
- while (1) {
- if (test_and_clear_bit(1, &sem->granted))
- break;
- set_task_state(tsk, TASK_UNINTERRUPTIBLE);
- if ((sem->granted & 2) == 0)
- schedule();
- }
-
- remove_wait_queue(&sem->write_bias_wait, &wait);
- tsk->state = TASK_RUNNING;
-
- /* If the lock is currently unbiased, awaken the sleepers.
- FIXME: This wakes up the readers early in a bit of a
- stampede -> bad! */
- if (atomic_read(&sem->count) >= 0)
- wake_up(&sem->wait);
- }
-}
-
-void
-__rwsem_wake(struct rw_semaphore *sem, unsigned long readers)
-{
- if (readers) {
- if (test_and_set_bit(0, &sem->granted))
- BUG();
- wake_up(&sem->wait);
- } else {
- if (test_and_set_bit(1, &sem->granted))
- BUG();
- wake_up(&sem->write_bias_wait);
- }
-}
O_TARGET := mm.o
-obj-y := extable.o init.o fault.o loadmmu.o
+export-objs += umap.o
+obj-y := extable.o init.o fault.o loadmmu.o
obj-$(CONFIG_CPU_R4300) += r4xx0.o
obj-$(CONFIG_CPU_R4X00) += r4xx0.o
-# $Id: Makefile,v 1.1 1999/08/18 21:46:53 ralf Exp $
#
# Makefile for MIPS kernel build tools.
#
define_bool CONFIG_PARISC y
define_bool CONFIG_UID16 n
+define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y
+define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n
mainmenu_option next_comment
comment 'Code maturity level options'
{
return waking_non_zero_trylock(sem);
}
-
-
-/* Wait for the lock to become unbiased. Readers
- * are non-exclusive. =)
- */
-void down_read_failed(struct rw_semaphore *sem)
-{
- DECLARE_WAITQUEUE(wait, current);
-
- __up_read(sem); /* this takes care of granting the lock */
-
- add_wait_queue(&sem->wait, &wait);
-
- while (atomic_read(&sem->count) < 0) {
- set_task_state(current, TASK_UNINTERRUPTIBLE);
- if (atomic_read(&sem->count) >= 0)
- break;
- schedule();
- }
-
- remove_wait_queue(&sem->wait, &wait);
- current->state = TASK_RUNNING;
-}
-
-void down_read_failed_biased(struct rw_semaphore *sem)
-{
- DECLARE_WAITQUEUE(wait, current);
-
- add_wait_queue(&sem->wait, &wait); /* put ourselves at the head of the list */
-
- for (;;) {
- if (sem->read_bias_granted && xchg(&sem->read_bias_granted, 0))
- break;
- set_task_state(current, TASK_UNINTERRUPTIBLE);
- if (!sem->read_bias_granted)
- schedule();
- }
-
- remove_wait_queue(&sem->wait, &wait);
- current->state = TASK_RUNNING;
-}
-
-
-/* Wait for the lock to become unbiased. Since we're
- * a writer, we'll make ourselves exclusive.
- */
-void down_write_failed(struct rw_semaphore *sem)
-{
- DECLARE_WAITQUEUE(wait, current);
-
- __up_write(sem); /* this takes care of granting the lock */
-
- add_wait_queue_exclusive(&sem->wait, &wait);
-
- while (atomic_read(&sem->count) < 0) {
- set_task_state(current, TASK_UNINTERRUPTIBLE | TASK_EXCLUSIVE);
- if (atomic_read(&sem->count) >= 0)
- break; /* we must attempt to aquire or bias the lock */
- schedule();
- }
-
- remove_wait_queue(&sem->wait, &wait);
- current->state = TASK_RUNNING;
-}
-
-void down_write_failed_biased(struct rw_semaphore *sem)
-{
- DECLARE_WAITQUEUE(wait, current);
-
- add_wait_queue_exclusive(&sem->write_bias_wait, &wait); /* put ourselves at the end of the list */
-
- for (;;) {
- if (sem->write_bias_granted && xchg(&sem->write_bias_granted, 0))
- break;
- set_task_state(current, TASK_UNINTERRUPTIBLE | TASK_EXCLUSIVE);
- if (!sem->write_bias_granted)
- schedule();
- }
-
- remove_wait_queue(&sem->write_bias_wait, &wait);
- current->state = TASK_RUNNING;
-
- /* if the lock is currently unbiased, awaken the sleepers
- * FIXME: this wakes up the readers early in a bit of a
- * stampede -> bad!
- */
- if (atomic_read(&sem->count) >= 0)
- wake_up(&sem->wait);
-}
-
-
-/* Called when someone has done an up that transitioned from
- * negative to non-negative, meaning that the lock has been
- * granted to whomever owned the bias.
- */
-void rwsem_wake_readers(struct rw_semaphore *sem)
-{
- if (xchg(&sem->read_bias_granted, 1))
- BUG();
- wake_up(&sem->wait);
-}
-
-void rwsem_wake_writer(struct rw_semaphore *sem)
-{
- if (xchg(&sem->write_bias_granted, 1))
- BUG();
- wake_up(&sem->write_bias_wait);
-}
# see Documentation/kbuild/config-language.txt.
#
define_bool CONFIG_UID16 n
+define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y
+define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n
mainmenu_name "Linux/PowerPC Kernel Configuration"
{
return waking_non_zero_trylock(sem);
}
-
-
-/*
- * rw semaphores Ani Joshi <ajoshi@unixbox.com>
- * based on alpha port by Andrea Arcangeli <andrea@suse.de>
- */
-
-void down_read_failed(struct rw_semaphore *sem)
-{
- struct task_struct *tsk = current;
- DECLARE_WAITQUEUE(wait, tsk);
-
- add_wait_queue_exclusive(&sem->wait, &wait);
-
- do {
- __set_task_state(tsk, TASK_UNINTERRUPTIBLE);
- spin_unlock_irq(&sem->lock);
- schedule();
- spin_lock_irq(&sem->lock);
- } while(sem->wr);
-
- remove_wait_queue(&sem->wait, &wait);
-}
-
-void down_write_failed(struct rw_semaphore *sem)
-{
- struct task_struct *tsk = current;
- DECLARE_WAITQUEUE(wait, tsk);
-
- add_wait_queue_exclusive(&sem->wait, &wait);
-
- do {
- __set_task_state(tsk, TASK_UNINTERRUPTIBLE);
- spin_unlock_irq(&sem->lock);
- schedule();
- spin_lock_irq(&sem->lock);
- } while(sem->rd || sem->wr);
-
- remove_wait_queue(&sem->wait, &wait);
-}
-
define_bool CONFIG_EISA n
define_bool CONFIG_MCA n
define_bool CONFIG_UID16 y
+define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y
+define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n
mainmenu_name "Linux Kernel Configuration"
define_bool CONFIG_ARCH_S390 y
spin_unlock_irqrestore(&semaphore_lock, flags);
return 1;
}
-
-void down_read_failed_biased(struct rw_semaphore *sem)
-{
- struct task_struct *tsk = current;
- DECLARE_WAITQUEUE(wait, tsk);
-
- add_wait_queue(&sem->wait, &wait); /* put ourselves at the head of the list */
-
- for (;;) {
- if (sem->read_bias_granted && xchg(&sem->read_bias_granted, 0))
- break;
- set_task_state(tsk, TASK_UNINTERRUPTIBLE);
- if (!sem->read_bias_granted)
- schedule();
- }
-
- remove_wait_queue(&sem->wait, &wait);
- tsk->state = TASK_RUNNING;
-}
-
-void down_write_failed_biased(struct rw_semaphore *sem)
-{
- struct task_struct *tsk = current;
- DECLARE_WAITQUEUE(wait, tsk);
-
- add_wait_queue_exclusive(&sem->write_bias_wait, &wait); /* put ourselves at the end of the list */
-
- for (;;) {
- if (sem->write_bias_granted && xchg(&sem->write_bias_granted, 0))
- break;
- set_task_state(tsk, TASK_UNINTERRUPTIBLE);
- if (!sem->write_bias_granted)
- schedule();
- }
-
- remove_wait_queue(&sem->write_bias_wait, &wait);
- tsk->state = TASK_RUNNING;
-
- /* if the lock is currently unbiased, awaken the sleepers
- * FIXME: this wakes up the readers early in a bit of a
- * stampede -> bad!
- */
- if (atomic_read(&sem->count) >= 0)
- wake_up(&sem->wait);
-}
-
-/* Wait for the lock to become unbiased. Readers
- * are non-exclusive. =)
- */
-void down_read_failed(struct rw_semaphore *sem)
-{
- struct task_struct *tsk = current;
- DECLARE_WAITQUEUE(wait, tsk);
-
- up_read(sem); /* this takes care of granting the lock */
-
- add_wait_queue(&sem->wait, &wait);
-
- while (atomic_read(&sem->count) < 0) {
- set_task_state(tsk, TASK_UNINTERRUPTIBLE);
- if (atomic_read(&sem->count) >= 0)
- break;
- schedule();
- }
-
- remove_wait_queue(&sem->wait, &wait);
- tsk->state = TASK_RUNNING;
-}
-
-/* Wait for the lock to become unbiased. Since we're
- * a writer, we'll make ourselves exclusive.
- */
-void down_write_failed(struct rw_semaphore *sem)
-{
- struct task_struct *tsk = current;
- DECLARE_WAITQUEUE(wait, tsk);
-
- up_write(sem); /* this takes care of granting the lock */
-
- add_wait_queue_exclusive(&sem->wait, &wait);
-
- while (atomic_read(&sem->count) < 0) {
- set_task_state(tsk, TASK_UNINTERRUPTIBLE);
- if (atomic_read(&sem->count) >= 0)
- break; /* we must attempt to acquire or bias the lock */
- schedule();
- }
-
- remove_wait_queue(&sem->wait, &wait);
- tsk->state = TASK_RUNNING;
-}
-
-/* Called when someone has done an up that transitioned from
- * negative to non-negative, meaning that the lock has been
- * granted to whomever owned the bias.
- */
-void rwsem_wake_readers(struct rw_semaphore *sem)
-{
- if (xchg(&sem->read_bias_granted, 1))
- BUG();
- wake_up(&sem->wait);
-}
-
-void rwsem_wake_writers(struct rw_semaphore *sem)
-{
- if (xchg(&sem->write_bias_granted, 1))
- BUG();
- wake_up(&sem->write_bias_wait);
-}
-
-void __down_read_failed(int count, struct rw_semaphore *sem)
-{
- do {
- if (count == -1) {
- down_read_failed_biased(sem);
- break;
- }
- down_read_failed(sem);
- count = atomic_dec_return(&sem->count);
- } while (count != 0);
-}
-
-void __down_write_failed(int count, struct rw_semaphore *sem)
-{
- do {
- if (count < 0 && count > -RW_LOCK_BIAS) {
- down_write_failed_biased(sem);
- break;
- }
- down_write_failed(sem);
- count = atomic_add_return(-RW_LOCK_BIAS, &sem->count);
- } while (count != 0);
-}
-
-void __rwsem_wake(int count, struct rw_semaphore *sem)
-{
- if (count == 0)
- rwsem_wake_readers(sem);
- else
- rwsem_wake_writers(sem);
-}
-
define_bool CONFIG_ISA n
define_bool CONFIG_EISA n
define_bool CONFIG_MCA n
+define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y
+define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n
mainmenu_name "Linux Kernel Configuration"
define_bool CONFIG_ARCH_S390 y
spin_unlock_irqrestore(&semaphore_lock, flags);
return 1;
}
-
-void down_read_failed_biased(struct rw_semaphore *sem)
-{
- struct task_struct *tsk = current;
- DECLARE_WAITQUEUE(wait, tsk);
-
- add_wait_queue(&sem->wait, &wait); /* put ourselves at the head of the list */
-
- for (;;) {
- if (sem->read_bias_granted && xchg(&sem->read_bias_granted, 0))
- break;
- set_task_state(tsk, TASK_UNINTERRUPTIBLE);
- if (!sem->read_bias_granted)
- schedule();
- }
-
- remove_wait_queue(&sem->wait, &wait);
- tsk->state = TASK_RUNNING;
-}
-
-void down_write_failed_biased(struct rw_semaphore *sem)
-{
- struct task_struct *tsk = current;
- DECLARE_WAITQUEUE(wait, tsk);
-
- add_wait_queue_exclusive(&sem->write_bias_wait, &wait); /* put ourselves at the end of the list */
-
- for (;;) {
- if (sem->write_bias_granted && xchg(&sem->write_bias_granted, 0))
- break;
- set_task_state(tsk, TASK_UNINTERRUPTIBLE);
- if (!sem->write_bias_granted)
- schedule();
- }
-
- remove_wait_queue(&sem->write_bias_wait, &wait);
- tsk->state = TASK_RUNNING;
-
- /* if the lock is currently unbiased, awaken the sleepers
- * FIXME: this wakes up the readers early in a bit of a
- * stampede -> bad!
- */
- if (atomic_read(&sem->count) >= 0)
- wake_up(&sem->wait);
-}
-
-/* Wait for the lock to become unbiased. Readers
- * are non-exclusive. =)
- */
-void down_read_failed(struct rw_semaphore *sem)
-{
- struct task_struct *tsk = current;
- DECLARE_WAITQUEUE(wait, tsk);
-
- up_read(sem); /* this takes care of granting the lock */
-
- add_wait_queue(&sem->wait, &wait);
-
- while (atomic_read(&sem->count) < 0) {
- set_task_state(tsk, TASK_UNINTERRUPTIBLE);
- if (atomic_read(&sem->count) >= 0)
- break;
- schedule();
- }
-
- remove_wait_queue(&sem->wait, &wait);
- tsk->state = TASK_RUNNING;
-}
-
-/* Wait for the lock to become unbiased. Since we're
- * a writer, we'll make ourselves exclusive.
- */
-void down_write_failed(struct rw_semaphore *sem)
-{
- struct task_struct *tsk = current;
- DECLARE_WAITQUEUE(wait, tsk);
-
- up_write(sem); /* this takes care of granting the lock */
-
- add_wait_queue_exclusive(&sem->wait, &wait);
-
- while (atomic_read(&sem->count) < 0) {
- set_task_state(tsk, TASK_UNINTERRUPTIBLE);
- if (atomic_read(&sem->count) >= 0)
- break; /* we must attempt to acquire or bias the lock */
- schedule();
- }
-
- remove_wait_queue(&sem->wait, &wait);
- tsk->state = TASK_RUNNING;
-}
-
-/* Called when someone has done an up that transitioned from
- * negative to non-negative, meaning that the lock has been
- * granted to whomever owned the bias.
- */
-void rwsem_wake_readers(struct rw_semaphore *sem)
-{
- if (xchg(&sem->read_bias_granted, 1))
- BUG();
- wake_up(&sem->wait);
-}
-
-void rwsem_wake_writers(struct rw_semaphore *sem)
-{
- if (xchg(&sem->write_bias_granted, 1))
- BUG();
- wake_up(&sem->write_bias_wait);
-}
-
-void __down_read_failed(int count, struct rw_semaphore *sem)
-{
- do {
- if (count == -1) {
- down_read_failed_biased(sem);
- break;
- }
- down_read_failed(sem);
- count = atomic_dec_return(&sem->count);
- } while (count != 0);
-}
-
-void __down_write_failed(int count, struct rw_semaphore *sem)
-{
- do {
- if (count < 0 && count > -RW_LOCK_BIAS) {
- down_write_failed_biased(sem);
- break;
- }
- down_write_failed(sem);
- count = atomic_add_return(-RW_LOCK_BIAS, &sem->count);
- } while (count != 0);
-}
-
-void __rwsem_wake(int count, struct rw_semaphore *sem)
-{
- if (count == 0)
- rwsem_wake_readers(sem);
- else
- rwsem_wake_writers(sem);
-}
-
define_bool CONFIG_SUPERH y
define_bool CONFIG_UID16 y
+define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y
+define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n
mainmenu_option next_comment
comment 'Code maturity level options'
{
return waking_non_zero_trylock(sem);
}
-
-/* Called when someone has done an up that transitioned from
- * negative to non-negative, meaning that the lock has been
- * granted to whomever owned the bias.
- */
-struct rw_semaphore *rwsem_wake_readers(struct rw_semaphore *sem)
-{
- if (xchg(&sem->read_bias_granted, 1))
- BUG();
- wake_up(&sem->wait);
- return sem;
-}
-
-struct rw_semaphore *rwsem_wake_writer(struct rw_semaphore *sem)
-{
- if (xchg(&sem->write_bias_granted, 1))
- BUG();
- wake_up(&sem->write_bias_wait);
- return sem;
-}
-
-struct rw_semaphore * __rwsem_wake(struct rw_semaphore *sem)
-{
- if (atomic_read(&sem->count) == 0)
- return rwsem_wake_writer(sem);
- else
- return rwsem_wake_readers(sem);
-}
-
-struct rw_semaphore *down_read_failed_biased(struct rw_semaphore *sem)
-{
- struct task_struct *tsk = current;
- DECLARE_WAITQUEUE(wait, tsk);
-
- add_wait_queue(&sem->wait, &wait); /* put ourselves at the head of the list */
-
- for (;;) {
- if (sem->read_bias_granted && xchg(&sem->read_bias_granted, 0))
- break;
- set_task_state(tsk, TASK_UNINTERRUPTIBLE);
- if (!sem->read_bias_granted)
- schedule();
- }
-
- remove_wait_queue(&sem->wait, &wait);
- tsk->state = TASK_RUNNING;
-
- return sem;
-}
-
-struct rw_semaphore *down_write_failed_biased(struct rw_semaphore *sem)
-{
- struct task_struct *tsk = current;
- DECLARE_WAITQUEUE(wait, tsk);
-
- add_wait_queue_exclusive(&sem->write_bias_wait, &wait); /* put ourselves at the end of the list */
-
- for (;;) {
- if (sem->write_bias_granted && xchg(&sem->write_bias_granted, 0))
- break;
- set_task_state(tsk, TASK_UNINTERRUPTIBLE);
- if (!sem->write_bias_granted)
- schedule();
- }
-
- remove_wait_queue(&sem->write_bias_wait, &wait);
- tsk->state = TASK_RUNNING;
-
- /* if the lock is currently unbiased, awaken the sleepers
- * FIXME: this wakes up the readers early in a bit of a
- * stampede -> bad!
- */
- if (atomic_read(&sem->count) >= 0)
- wake_up(&sem->wait);
-
- return sem;
-}
-
-/* Wait for the lock to become unbiased. Readers
- * are non-exclusive. =)
- */
-struct rw_semaphore *down_read_failed(struct rw_semaphore *sem)
-{
- struct task_struct *tsk = current;
- DECLARE_WAITQUEUE(wait, tsk);
-
- __up_read(sem); /* this takes care of granting the lock */
-
- add_wait_queue(&sem->wait, &wait);
-
- while (atomic_read(&sem->count) < 0) {
- set_task_state(tsk, TASK_UNINTERRUPTIBLE);
- if (atomic_read(&sem->count) >= 0)
- break;
- schedule();
- }
-
- remove_wait_queue(&sem->wait, &wait);
- tsk->state = TASK_RUNNING;
-
- return sem;
-}
-
-/* Wait for the lock to become unbiased. Since we're
- * a writer, we'll make ourselves exclusive.
- */
-struct rw_semaphore *down_write_failed(struct rw_semaphore *sem)
-{
- struct task_struct *tsk = current;
- DECLARE_WAITQUEUE(wait, tsk);
-
- __up_write(sem); /* this takes care of granting the lock */
-
- add_wait_queue_exclusive(&sem->wait, &wait);
-
- while (atomic_read(&sem->count) < 0) {
- set_task_state(tsk, TASK_UNINTERRUPTIBLE);
- if (atomic_read(&sem->count) >= 0)
- break; /* we must attempt to acquire or bias the lock */
- schedule();
- }
-
- remove_wait_queue(&sem->wait, &wait);
- tsk->state = TASK_RUNNING;
-
- return sem;
-}
-
-struct rw_semaphore *__down_read(struct rw_semaphore *sem, int carry)
-{
- if (carry) {
- int saved, new;
-
- do {
- down_read_failed(sem);
- saved = atomic_read(&sem->count);
- if ((new = atomic_dec_return(&sem->count)) >= 0)
- return sem;
- } while (!(new < 0 && saved >=0));
- }
-
- return down_read_failed_biased(sem);
-}
-
-struct rw_semaphore *__down_write(struct rw_semaphore *sem, int carry)
-{
- if (carry) {
- int saved, new;
-
- do {
- down_write_failed(sem);
- saved = atomic_read(&sem->count);
- if ((new = atomic_sub_return(RW_LOCK_BIAS, &sem->count) ) == 0)
- return sem;
- } while (!(new < 0 && saved >=0));
- }
-
- return down_write_failed_biased(sem);
-}
define_bool CONFIG_SUN_CONSOLE y
define_bool CONFIG_SUN_AUXIO y
define_bool CONFIG_SUN_IO y
+define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y
+define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n
bool 'Support for SUN4 machines (disables SUN4[CDM] support)' CONFIG_SUN4
if [ "$CONFIG_SUN4" != "y" ]; then
* Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx)
* Copyright (C) 1995 Pete A. Zaitcev (zaitcev@metabyte.com)
* Copyright (C) 1996 Dave Redman (djhr@tadpole.co.uk)
- * Copyright (C) 1998-2000 Anton Blanchard (anton@linuxcare.com)
+ * Copyright (C) 1998-2000 Anton Blanchard (anton@samba.org)
*/
#include <linux/config.h>
spin_unlock_irqrestore(&semaphore_lock, flags);
return 1;
}
-
-/* rw mutexes
- * Implemented by Jakub Jelinek (jakub@redhat.com) based on
- * i386 implementation by Ben LaHaise (bcrl@redhat.com).
- */
-
-extern inline int ldstub(unsigned char *p)
-{
- int ret;
- asm volatile("ldstub %1, %0" : "=r" (ret) : "m" (*p) : "memory");
- return ret;
-}
-
-#define DOWN_VAR \
- struct task_struct *tsk = current; \
- DECLARE_WAITQUEUE(wait, tsk);
-
-void down_read_failed_biased(struct rw_semaphore *sem)
-{
- DOWN_VAR
-
- add_wait_queue(&sem->wait, &wait); /* put ourselves at the head of the list */
-
- for (;;) {
- if (!ldstub(&sem->read_not_granted))
- break;
- set_task_state(tsk, TASK_UNINTERRUPTIBLE);
- if (sem->read_not_granted)
- schedule();
- }
-
- remove_wait_queue(&sem->wait, &wait);
- tsk->state = TASK_RUNNING;
-}
-
-void down_write_failed_biased(struct rw_semaphore *sem)
-{
- DOWN_VAR
-
- add_wait_queue_exclusive(&sem->write_bias_wait, &wait); /* put ourselves at the end of the list */
-
- for (;;) {
- if (!ldstub(&sem->write_not_granted))
- break;
- set_task_state(tsk, TASK_UNINTERRUPTIBLE);
- if (sem->write_not_granted)
- schedule();
- }
-
- remove_wait_queue(&sem->write_bias_wait, &wait);
- tsk->state = TASK_RUNNING;
-
- /* if the lock is currently unbiased, awaken the sleepers
- * FIXME: this wakes up the readers early in a bit of a
- * stampede -> bad!
- */
- if (sem->count >= 0)
- wake_up(&sem->wait);
-}
-
-/* Wait for the lock to become unbiased. Readers
- * are non-exclusive. =)
- */
-void down_read_failed(struct rw_semaphore *sem)
-{
- DOWN_VAR
-
- __up_read(sem); /* this takes care of granting the lock */
-
- add_wait_queue(&sem->wait, &wait);
-
- while (sem->count < 0) {
- set_task_state(tsk, TASK_UNINTERRUPTIBLE);
- if (sem->count >= 0)
- break;
- schedule();
- }
-
- remove_wait_queue(&sem->wait, &wait);
- tsk->state = TASK_RUNNING;
-}
-
-/* Wait for the lock to become unbiased. Since we're
- * a writer, we'll make ourselves exclusive.
- */
-void down_write_failed(struct rw_semaphore *sem)
-{
- DOWN_VAR
-
- __up_write(sem); /* this takes care of granting the lock */
-
- add_wait_queue_exclusive(&sem->wait, &wait);
-
- while (sem->count < 0) {
- set_task_state(tsk, TASK_UNINTERRUPTIBLE);
- if (sem->count >= 0)
- break; /* we must attempt to acquire or bias the lock */
- schedule();
- }
-
- remove_wait_queue(&sem->wait, &wait);
- tsk->state = TASK_RUNNING;
-}
-
-void __rwsem_wake(struct rw_semaphore *sem, unsigned long readers)
-{
- if (readers) {
- /* Due to lame ldstub we don't do here
- a BUG() consistency check */
- sem->read_not_granted = 0;
- wake_up(&sem->wait);
- } else {
- sem->write_not_granted = 0;
- wake_up(&sem->write_bias_wait);
- }
-}
* linux/arch/sparc/kernel/setup.c
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- * Copyright (C) 2000 Anton Blanchard (anton@linuxcare.com)
+ * Copyright (C) 2000 Anton Blanchard (anton@samba.org)
*/
#include <linux/errno.h>
-/* $Id: sys_sparc.c,v 1.69 2001/03/27 02:36:37 davem Exp $
+/* $Id: sys_sparc.c,v 1.70 2001/04/14 01:12:02 davem Exp $
* linux/arch/sparc/kernel/sys_sparc.c
*
* This file contains various random system calls that
} else if ((ARCH_SUN4C_SUN4 && addr < 0xe0000000 &&
addr + new_len > 0x20000000) ||
addr + new_len > TASK_SIZE - PAGE_SIZE) {
- unsigned long (*get_addr)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
unsigned long map_flags = 0;
struct file *file = NULL;
-/* $Id: init.c,v 1.97 2001/02/26 02:57:34 anton Exp $
+/* $Id: init.c,v 1.96 2000/11/30 08:51:50 anton Exp $
* linux/arch/sparc/mm/init.c
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
* Copyright (C) 1995 Eddie C. Dost (ecd@skynet.be)
* Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
- * Copyright (C) 2000 Anton Blanchard (anton@linuxcare.com.au)
+ * Copyright (C) 2000 Anton Blanchard (anton@samba.org)
*/
#include <linux/config.h>
* Copyright (C) 1995 Pete Zaitcev
* Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
* Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
- * Copyright (C) 1999,2000 Anton Blanchard (anton@linuxcare.com)
+ * Copyright (C) 1999,2000 Anton Blanchard (anton@samba.org)
*/
#include <linux/config.h>
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
* Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
* Copyright (C) 1996 Andrew Tridgell (Andrew.Tridgell@anu.edu.au)
- * Copyright (C) 1997-2000 Anton Blanchard (anton@linuxcare.com)
+ * Copyright (C) 1997-2000 Anton Blanchard (anton@samba.org)
* Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
*/
# Global things across all Sun machines.
define_bool CONFIG_HAVE_DEC_LOCK y
+define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y
+define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n
define_bool CONFIG_ISA n
define_bool CONFIG_EISA n
define_bool CONFIG_MCA n
CONFIG_EFS_FS=m
# CONFIG_JFFS_FS is not set
CONFIG_CRAMFS=m
+# CONFIG_TMPFS is not set
CONFIG_RAMFS=m
CONFIG_ISO9660_FS=m
CONFIG_JOLIET=y
-/* $Id: semaphore.c,v 1.5 2000/11/10 04:02:03 davem Exp $
+/* $Id: semaphore.c,v 1.6 2001/04/14 01:12:02 davem Exp $
* Generic semaphore code. Buyer beware. Do your own
* specific changes in <asm/semaphore-helper.h>
*/
{
return waking_non_zero_trylock(sem);
}
-
-/* rw mutexes
- * Implemented by Jakub Jelinek (jakub@redhat.com) based on
- * i386 implementation by Ben LaHaise (bcrl@redhat.com).
- */
-
-asm("
- .text
- .align 32
- .globl __down_read_failed
-__down_read_failed:
- save %sp, -160, %sp
- membar #StoreStore
- brz,pt %g5, 3f
- mov %g7, %l0
-1: call down_read_failed
- mov %l0, %o0
-2: lduw [%l0], %l1
- sub %l1, 1, %l2
- cas [%l0], %l1, %l2
-
- cmp %l1, %l2
- bne,pn %icc, 2b
- membar #StoreStore
- subcc %l1, 1, %g0
- bpos,pt %icc, 4f
- nop
- bcc,pn %icc, 1b
- nop
-
-3: call down_read_failed_biased
- mov %l0, %o0
-4: ret
- restore
- .previous
-");
-
-asm("
- .text
- .align 32
- .globl __down_write_failed
-__down_write_failed:
- save %sp, -160, %sp
- membar #StoreStore
- tst %g5
- bge,pt %icc, 3f
- mov %g7, %l0
-1: call down_write_failed
- mov %l0, %o0
-2: lduw [%l0], %l1
- sethi %hi (" RW_LOCK_BIAS_STR "), %l3
- sub %l1, %l3, %l2
- cas [%l0], %l1, %l2
-
- cmp %l1, %l2
- bne,pn %icc, 2b
- membar #StoreStore
- subcc %l1, %l3, %g0
- be,pt %icc, 4f
- nop
- bcc,pn %icc, 1b
- nop
-
-3: call down_write_failed_biased
- mov %l0, %o0
-4: ret
- restore
- .previous
-");
-
-void down_read_failed_biased(struct rw_semaphore *sem)
-{
- DOWN_VAR
-
- add_wait_queue(&sem->wait, &wait); /* put ourselves at the head of the list */
-
- for (;;) {
- if (test_and_clear_le_bit(0, &sem->granted))
- break;
- set_task_state(tsk, TASK_UNINTERRUPTIBLE);
- if (!test_le_bit(0, &sem->granted))
- schedule();
- }
-
- remove_wait_queue(&sem->wait, &wait);
- tsk->state = TASK_RUNNING;
-}
-
-void down_write_failed_biased(struct rw_semaphore *sem)
-{
- DOWN_VAR
-
- add_wait_queue_exclusive(&sem->write_bias_wait, &wait); /* put ourselves at the end of the list */
-
- for (;;) {
- if (test_and_clear_le_bit(1, &sem->granted))
- break;
- set_task_state(tsk, TASK_UNINTERRUPTIBLE);
- if (!test_le_bit(1, &sem->granted))
- schedule();
- }
-
- remove_wait_queue(&sem->write_bias_wait, &wait);
- tsk->state = TASK_RUNNING;
-
- /* if the lock is currently unbiased, awaken the sleepers
- * FIXME: this wakes up the readers early in a bit of a
- * stampede -> bad!
- */
- if (sem->count >= 0)
- wake_up(&sem->wait);
-}
-
-/* Wait for the lock to become unbiased. Readers
- * are non-exclusive. =)
- */
-void down_read_failed(struct rw_semaphore *sem)
-{
- DOWN_VAR
-
- __up_read(sem); /* this takes care of granting the lock */
-
- add_wait_queue(&sem->wait, &wait);
-
- while (sem->count < 0) {
- set_task_state(tsk, TASK_UNINTERRUPTIBLE);
- if (sem->count >= 0)
- break;
- schedule();
- }
-
- remove_wait_queue(&sem->wait, &wait);
- tsk->state = TASK_RUNNING;
-}
-
-/* Wait for the lock to become unbiased. Since we're
- * a writer, we'll make ourselves exclusive.
- */
-void down_write_failed(struct rw_semaphore *sem)
-{
- DOWN_VAR
-
- __up_write(sem); /* this takes care of granting the lock */
-
- add_wait_queue_exclusive(&sem->wait, &wait);
-
- while (sem->count < 0) {
- set_task_state(tsk, TASK_UNINTERRUPTIBLE);
- if (sem->count >= 0)
- break; /* we must attempt to acquire or bias the lock */
- schedule();
- }
-
- remove_wait_queue(&sem->wait, &wait);
- tsk->state = TASK_RUNNING;
-}
-
-void __rwsem_wake(struct rw_semaphore *sem, unsigned long readers)
-{
- if (readers) {
- if (test_and_set_le_bit(0, &sem->granted))
- BUG();
- wake_up(&sem->wait);
- } else {
- if (test_and_set_le_bit(1, &sem->granted))
- BUG();
- wake_up(&sem->write_bias_wait);
- }
-}
-/* $Id: sparc64_ksyms.c,v 1.104 2001/04/05 11:08:11 davem Exp $
+/* $Id: sparc64_ksyms.c,v 1.105 2001/04/14 01:12:02 davem Exp $
* arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
EXPORT_SYMBOL(__down_trylock);
EXPORT_SYMBOL(__up);
-/* rw semaphores */
-EXPORT_SYMBOL_NOVERS(__down_read_failed);
-EXPORT_SYMBOL_NOVERS(__down_write_failed);
-EXPORT_SYMBOL_NOVERS(__rwsem_wake);
-
/* Atomic counter implementation. */
EXPORT_SYMBOL(__atomic_add);
EXPORT_SYMBOL(__atomic_sub);
/* Atomic bit operations. */
-EXPORT_SYMBOL(__test_and_set_bit);
-EXPORT_SYMBOL(__test_and_clear_bit);
-EXPORT_SYMBOL(__test_and_change_bit);
-EXPORT_SYMBOL(__test_and_set_le_bit);
-EXPORT_SYMBOL(__test_and_clear_le_bit);
+EXPORT_SYMBOL(___test_and_set_bit);
+EXPORT_SYMBOL(___test_and_clear_bit);
+EXPORT_SYMBOL(___test_and_change_bit);
+EXPORT_SYMBOL(___test_and_set_le_bit);
+EXPORT_SYMBOL(___test_and_clear_le_bit);
EXPORT_SYMBOL(ivector_table);
EXPORT_SYMBOL(enable_irq);
* starfire.c: Starfire/E10000 support.
*
* Copyright (C) 1998 David S. Miller (davem@redhat.com)
- * Copyright (C) 2000 Anton Blanchard (anton@linuxcare.com)
+ * Copyright (C) 2000 Anton Blanchard (anton@samba.org)
*/
#include <linux/kernel.h>
-/* $Id: sys_sparc.c,v 1.51 2001/03/27 02:36:37 davem Exp $
+/* $Id: sys_sparc.c,v 1.52 2001/04/14 01:12:02 davem Exp $
* linux/arch/sparc64/kernel/sys_sparc.c
*
* This file contains various random system calls that
new_addr + new_len > -PAGE_OFFSET)
goto out_sem;
} else if (addr < PAGE_OFFSET && addr + new_len > -PAGE_OFFSET) {
- unsigned long (*get_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
unsigned long map_flags = 0;
struct file *file = NULL;
-/* $Id: sys_sparc32.c,v 1.175 2001/03/27 02:36:37 davem Exp $
+/* $Id: sys_sparc32.c,v 1.176 2001/04/14 01:12:02 davem Exp $
* sys_sparc32.c: Conversion between 32bit and 64bit native syscalls.
*
* Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
if (new_addr > 0xf0000000UL - new_len)
goto out_sem;
} else if (addr > 0xf0000000UL - new_len) {
- unsigned long (*get_addr)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
unsigned long map_flags = 0;
struct file *file = NULL;
}
/* MREMAP_FIXED checked above. */
- new_addr = get_unmapped_addr(file, addr, new_len,
+ new_addr = get_unmapped_area(file, addr, new_len,
vma ? vma->vm_pgoff : 0,
map_flags);
ret = new_addr;
-/* $Id: bitops.S,v 1.1 2000/03/27 10:38:41 davem Exp $
+/* $Id: bitops.S,v 1.2 2001/04/14 01:12:02 davem Exp $
* bitops.S: Sparc64 atomic bit operations.
*
* Copyright (C) 2000 David S. Miller (davem@redhat.com)
.globl __bitops_begin
__bitops_begin:
- .globl __test_and_set_bit
-__test_and_set_bit: /* %o0=nr, %o1=addr */
+ .globl ___test_and_set_bit
+___test_and_set_bit: /* %o0=nr, %o1=addr */
srlx %o0, 6, %g1
mov 1, %g5
sllx %g1, 3, %g3
2: retl
nop
- .globl __test_and_clear_bit
-__test_and_clear_bit: /* %o0=nr, %o1=addr */
+ .globl ___test_and_clear_bit
+___test_and_clear_bit: /* %o0=nr, %o1=addr */
srlx %o0, 6, %g1
mov 1, %g5
sllx %g1, 3, %g3
2: retl
nop
- .globl __test_and_change_bit
-__test_and_change_bit: /* %o0=nr, %o1=addr */
+ .globl ___test_and_change_bit
+___test_and_change_bit: /* %o0=nr, %o1=addr */
srlx %o0, 6, %g1
mov 1, %g5
sllx %g1, 3, %g3
nop
nop
- .globl __test_and_set_le_bit
-__test_and_set_le_bit: /* %o0=nr, %o1=addr */
+ .globl ___test_and_set_le_bit
+___test_and_set_le_bit: /* %o0=nr, %o1=addr */
srlx %o0, 5, %g1
mov 1, %g5
sllx %g1, 2, %g3
2: retl
nop
- .globl __test_and_clear_le_bit
-__test_and_clear_le_bit: /* %o0=nr, %o1=addr */
+ .globl ___test_and_clear_le_bit
+___test_and_clear_le_bit: /* %o0=nr, %o1=addr */
srlx %o0, 5, %g1
mov 1, %g5
sllx %g1, 2, %g3
return 0;
}
default:
- printk("timod_putmsg: unsuported command %u.\n", ret);
+ printk("timod_putmsg: unsupported command %u.\n", ret);
break;
}
return -EINVAL;
if (iocommand.Request.Type.Direction == XFER_WRITE)
{
/* Copy the data into the buffer we created */
- if (copy_from_user(buff, iocommand.buf, iocommand.buf_size))
+ if (copy_from_user(buff, iocommand.buf,
+ iocommand.buf_size)) {
+ kfree(buff);
return -EFAULT;
+ }
}
if ((c = cmd_alloc(NULL)) == NULL)
{
- if(buff!=NULL)
- kfree(buff);
+ kfree(buff);
return -ENOMEM;
}
// Fill in the command type
if ( copy_to_user((void *) arg, &iocommand, sizeof( IOCTL_Command_struct) ) )
{
cmd_free(NULL, c);
- if (buff != NULL)
- kfree(buff);
+ kfree(buff);
return( -EFAULT);
}
{
cmd_free(NULL, c);
kfree(buff);
+ return -EFAULT;
}
}
cmd_free(NULL, c);
- if (buff != NULL)
- kfree(buff);
+ kfree(buff);
return(0);
}
hba[ctlr]->gendisk.nr_real = 0;
/*
- * Tell the array controller not to give us any interupts while
+ * Tell the array controller not to give us any interrupts while
* we check the new geometry. Then turn interrupts back on when
* we're done.
*/
if (timeout)
status = 0;
if(cmd->err_info->CommandStatus != 0)
- { /* an error has occured */
+ { /* an error has occurred */
switch(cmd->err_info->CommandStatus)
{
case CMD_TARGET_STATUS:
|| (hba[i]->errinfo_pool == NULL))
{
nr_ctlr = i;
- if(hba[i]->cmd_pool_bits)
- kfree(hba[i]->cmd_pool_bits);
- if(hba[i]->cmd_pool)
- kfree(hba[i]->cmd_pool);
- if(hba[i]->errinfo_pool)
- kfree(hba[i]->errinfo_pool);
+ kfree(hba[i]->cmd_pool_bits);
+ kfree(hba[i]->cmd_pool);
+ kfree(hba[i]->errinfo_pool);
free_irq(hba[i]->intr, hba[i]);
unregister_blkdev(MAJOR_NR+i, hba[i]->devname);
num_cntlrs_reg--;
}
/*
- * This card is the oposite of the other cards.
+ * This card is the opposite of the other cards.
* 0 turns interrupts on...
* 0x08 turns them off...
*/
}
}
/*
- * This card is the oposite of the other cards.
+ * This card is the opposite of the other cards.
* 0 turns interrupts on...
* 0x04 turns them off...
*/
ErrDescriptor_struct ErrDesc;
SGDescriptor_struct SG[MAXSGENTRIES];
/* information associated with the command */
- __u32 busaddr; /* physical addres of this record */
+ __u32 busaddr; /* physical address of this record */
ErrorInfo_struct * err_info; /* pointer to the allocated mem */
int cmd_type;
struct _CommandList_struct *prev;
KEYBD = scan_keyb.o hp600_keyb.o
CONSOLE = console.o
endif
+ ifeq ($(CONFIG_SH_DMIDA),y)
+ # DMIDA does not connect the HD64465 PS/2 keyboard port
+ # but we allow for USB keyboards to be plugged in.
+ KEYMAP = defkeymap.o
+ KEYBD = # hd64465_keyb.o pc_keyb.o
+ CONSOLE = console.o
+ endif
+ ifeq ($(CONFIG_SH_EC3104),y)
+ KEYMAP = defkeymap.o
+ KEYBD = ec3104_keyb.o
+ CONSOLE = console.o
+ endif
+ ifeq ($(CONFIG_SH_DREAMCAST),y)
+ KEYMAP = defkeymap.o
+ KEYBD =
+ CONSOLE = console.o
+ endif
endif
ifeq ($(CONFIG_DECSTATION),y)
-/* $Id: ffb_drv.c,v 1.11 2001/03/27 02:36:37 davem Exp $
+/* $Id: ffb_drv.c,v 1.12 2001/04/14 01:12:03 davem Exp $
* ffb_drv.c: Creator/Creator3D direct rendering driver.
*
* Copyright (C) 2000 David S. Miller (davem@redhat.com)
--- /dev/null
+/*
+ * linux/drivers/char/ec3104_keyb.c
+ *
+ * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
+ *
+ * based on linux/drivers/char/pc_keyb.c, which had the following comments:
+ *
+ * Separation of the PC low-level part by Geert Uytterhoeven, May 1997
+ * See keyboard.c for the whole history.
+ *
+ * Major cleanup by Martin Mares, May 1997
+ *
+ * Combined the keyboard and PS/2 mouse handling into one file,
+ * because they share the same hardware.
+ * Johan Myreen <jem@iki.fi> 1998-10-08.
+ *
+ * Code fixes to handle mouse ACKs properly.
+ * C. Scott Ananian <cananian@alumni.princeton.edu> 1999-01-29.
+ */
+/* EC3104 note:
+ * This code was written without any documentation about the EC3104 chip. While
+ * I hope I got most of the basic functionality right, the register names I use
+ * are most likely completely different from those in the chip documentation.
+ *
+ * If you have any further information about the EC3104, please tell me
+ * (prumpf@tux.org).
+ */
+
+#include <linux/config.h>
+
+#include <linux/spinlock.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/mm.h>
+#include <linux/signal.h>
+#include <linux/init.h>
+#include <linux/kbd_ll.h>
+#include <linux/delay.h>
+#include <linux/random.h>
+#include <linux/poll.h>
+#include <linux/miscdevice.h>
+#include <linux/malloc.h>
+#include <linux/kbd_kern.h>
+#include <linux/smp_lock.h>
+
+#include <asm/keyboard.h>
+#include <asm/bitops.h>
+#include <asm/uaccess.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/ec3104.h>
+
+#include <asm/io.h>
+
+/* Some configuration switches are present in the include file... */
+
+#include <linux/pc_keyb.h>
+
+#define MSR_CTS 0x10
+#define MCR_RTS 0x02
+#define LSR_DR 0x01
+#define LSR_BOTH_EMPTY 0x60
+
+static struct e5_struct {
+ u8 packet[8];
+ int pos;
+ int length;
+
+ u8 cached_mcr;
+ u8 last_msr;
+} ec3104_keyb;
+
+/* Simple translation table for the SysRq keys */
+
+
+#ifdef CONFIG_MAGIC_SYSRQ
+unsigned char ec3104_kbd_sysrq_xlate[128] =
+ "\000\0331234567890-=\177\t" /* 0x00 - 0x0f */
+ "qwertyuiop[]\r\000as" /* 0x10 - 0x1f */
+ "dfghjkl;'`\000\\zxcv" /* 0x20 - 0x2f */
+ "bnm,./\000*\000 \000\201\202\203\204\205" /* 0x30 - 0x3f */
+ "\206\207\210\211\212\000\000789-456+1" /* 0x40 - 0x4f */
+ "230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */
+ "\r\000/"; /* 0x60 - 0x6f */
+#endif
+
+static void kbd_write_command_w(int data);
+static void kbd_write_output_w(int data);
+#ifdef CONFIG_PSMOUSE
+static void aux_write_ack(int val);
+static void __aux_write_ack(int val);
+#endif
+
+static spinlock_t kbd_controller_lock = SPIN_LOCK_UNLOCKED;
+static unsigned char handle_kbd_event(void);
+
+/* used only by send_data - set by keyboard_interrupt */
+static volatile unsigned char reply_expected;
+static volatile unsigned char acknowledge;
+static volatile unsigned char resend;
+
+
+int ec3104_kbd_setkeycode(unsigned int scancode, unsigned int keycode)
+{
+ return 0;
+}
+
+int ec3104_kbd_getkeycode(unsigned int scancode)
+{
+ return 0;
+}
+
+
+/* yes, it probably would be faster to use an array. I don't care. */
+
+static inline unsigned char ec3104_scan2key(unsigned char scancode)
+{
+ switch (scancode) {
+ case 1: /* '`' */
+ return 41;
+
+ case 2 ... 27:
+ return scancode;
+
+ case 28: /* '\\' */
+ return 43;
+
+ case 29 ... 39:
+ return scancode + 1;
+
+ case 40: /* '\r' */
+ return 28;
+
+ case 41 ... 50:
+ return scancode + 3;
+
+ case 51: /* ' ' */
+ return 57;
+
+ case 52: /* escape */
+ return 1;
+
+ case 54: /* insert/delete (labelled delete) */
+ /* this should arguably be 110, but I'd like to have ctrl-alt-del
+ * working with a standard keymap */
+ return 111;
+
+ case 55: /* left */
+ return 105;
+ case 56: /* home */
+ return 102;
+ case 57: /* end */
+ return 107;
+ case 58: /* up */
+ return 103;
+ case 59: /* down */
+ return 108;
+ case 60: /* pgup */
+ return 104;
+ case 61: /* pgdown */
+ return 109;
+ case 62: /* right */
+ return 106;
+
+ case 79 ... 88: /* f1 - f10 */
+ return scancode - 20;
+
+ case 89 ... 90: /* f11 - f12 */
+ return scancode - 2;
+
+ case 91: /* left shift */
+ return 42;
+
+ case 92: /* right shift */
+ return 54;
+
+ case 93: /* left alt */
+ return 56;
+ case 94: /* right alt */
+ return 100;
+ case 95: /* left ctrl */
+ return 29;
+ case 96: /* right ctrl */
+ return 97;
+
+ case 97: /* caps lock */
+ return 58;
+ case 102: /* left windows */
+ return 125;
+ case 103: /* right windows */
+ return 126;
+
+ case 106: /* Fn */
+ /* this is wrong. */
+ return 84;
+
+ default:
+ return 0;
+ }
+}
+
+int ec3104_kbd_translate(unsigned char scancode, unsigned char *keycode,
+ char raw_mode)
+{
+ scancode &= 0x7f;
+
+ *keycode = ec3104_scan2key(scancode);
+
+ return 1;
+}
+
+char ec3104_kbd_unexpected_up(unsigned char keycode)
+{
+ return 0200;
+}
+
+static inline void handle_keyboard_event(unsigned char scancode)
+{
+#ifdef CONFIG_VT
+ handle_scancode(scancode, !(scancode & 0x80));
+#endif
+ tasklet_schedule(&keyboard_tasklet);
+}
+
+void ec3104_kbd_leds(unsigned char leds)
+{
+}
+
+static u8 e5_checksum(u8 *packet, int count)
+{
+ int i;
+ u8 sum = 0;
+
+ for (i=0; i<count; i++)
+ sum ^= packet[i];
+
+ if (sum & 0x80)
+ sum ^= 0xc0;
+
+ return sum;
+}
+
+static void e5_wait_for_cts(struct e5_struct *k)
+{
+ u8 msr;
+
+ do {
+ msr = ctrl_inb(EC3104_SER4_MSR);
+ } while (!(msr & MSR_CTS));
+}
+
+
+static void e5_send_byte(u8 byte, struct e5_struct *k)
+{
+ u8 status;
+
+ do {
+ status = ctrl_inb(EC3104_SER4_LSR);
+ } while ((status & LSR_BOTH_EMPTY) != LSR_BOTH_EMPTY);
+
+ printk("<%02x>", byte);
+
+ ctrl_outb(byte, EC3104_SER4_DATA);
+
+ do {
+ status = ctrl_inb(EC3104_SER4_LSR);
+ } while ((status & LSR_BOTH_EMPTY) != LSR_BOTH_EMPTY);
+
+}
+
+static int e5_send_packet(u8 *packet, int count, struct e5_struct *k)
+{
+ int i;
+
+ disable_irq(EC3104_IRQ_SER4);
+
+ if (k->cached_mcr & MCR_RTS) {
+ printk("e5_send_packet: too slow\n");
+ enable_irq(EC3104_IRQ_SER4);
+ return -EAGAIN;
+ }
+
+ k->cached_mcr |= MCR_RTS;
+ ctrl_outb(k->cached_mcr, EC3104_SER4_MCR);
+
+ e5_wait_for_cts(k);
+
+ printk("p: ");
+
+ for(i=0; i<count; i++)
+ e5_send_byte(packet[i], k);
+
+ e5_send_byte(e5_checksum(packet, count), k);
+
+ printk("\n");
+
+ udelay(1500);
+
+ k->cached_mcr &= ~MCR_RTS;
+ ctrl_outb(k->cached_mcr, EC3104_SER4_MCR);
+
+ set_current_state(TASK_UNINTERRUPTIBLE);
+
+
+
+ enable_irq(EC3104_IRQ_SER4);
+
+
+
+ return 0;
+}
+
+/*
+ * E5 packets we know about:
+ * E5->host 0x80 0x05 <checksum> - resend packet
+ * host->E5 0x83 0x43 <contrast> - set LCD contrast
+ * host->E5 0x85 0x41 0x02 <brightness> 0x02 - set LCD backlight
+ * E5->host 0x87 <ps2 packet> 0x00 <checksum> - external PS2
+ * E5->host 0x88 <scancode> <checksum> - key press
+ */
+
+static void e5_receive(struct e5_struct *k)
+{
+ k->packet[k->pos++] = ctrl_inb(EC3104_SER4_DATA);
+
+ if (k->pos == 1) {
+ switch(k->packet[0]) {
+ case 0x80:
+ k->length = 3;
+ break;
+
+ case 0x87: /* PS2 ext */
+ k->length = 6;
+ break;
+
+ case 0x88: /* keyboard */
+ k->length = 3;
+ break;
+
+ default:
+ k->length = 1;
+ printk(KERN_WARNING "unknown E5 packet %02x\n",
+ k->packet[0]);
+ }
+ }
+
+ if (k->pos == k->length) {
+ int i;
+
+ if (e5_checksum(k->packet, k->length) != 0)
+ printk(KERN_WARNING "E5: wrong checksum\n");
+
+#if 0
+ printk("E5 packet [");
+ for(i=0; i<k->length; i++) {
+ printk("%02x ", k->packet[i]);
+ }
+
+ printk("(%02x)]\n", e5_checksum(k->packet, k->length-1));
+#endif
+
+ switch(k->packet[0]) {
+ case 0x80:
+ case 0x88:
+ handle_keyboard_event(k->packet[1]);
+ break;
+ }
+
+ k->pos = k->length = 0;
+ }
+}
+
+static void ec3104_keyb_interrupt(int irq, void *data, struct pt_regs *regs)
+{
+ struct e5_struct *k = &ec3104_keyb;
+ u8 msr, lsr;
+
+ kbd_pt_regs = regs;
+
+ msr = ctrl_inb(EC3104_SER4_MSR);
+
+ if ((msr & MSR_CTS) && !(k->last_msr & MSR_CTS)) {
+ if (k->cached_mcr & MCR_RTS)
+ printk("confused: RTS already high\n");
+ /* CTS went high. Send RTS. */
+ k->cached_mcr |= MCR_RTS;
+
+ ctrl_outb(k->cached_mcr, EC3104_SER4_MCR);
+ } else if ((!(msr & MSR_CTS)) && (k->last_msr & MSR_CTS)) {
+ /* CTS went low. */
+ if (!(k->cached_mcr & MCR_RTS))
+ printk("confused: RTS already low\n");
+
+ k->cached_mcr &= ~MCR_RTS;
+
+ ctrl_outb(k->cached_mcr, EC3104_SER4_MCR);
+ }
+
+ k->last_msr = msr;
+
+ lsr = ctrl_inb(EC3104_SER4_LSR);
+
+ if (lsr & LSR_DR)
+ e5_receive(k);
+}
+
+static void ec3104_keyb_clear_state(void)
+{
+ struct e5_struct *k = &ec3104_keyb;
+ u8 msr, lsr;
+
+ /* we want CTS to be low */
+ k->last_msr = 0;
+
+ for (;;) {
+ schedule_timeout(HZ/10);
+
+ msr = ctrl_inb(EC3104_SER4_MSR);
+
+ lsr = ctrl_inb(EC3104_SER4_LSR);
+
+ if (lsr & LSR_DR) {
+ e5_receive(k);
+ continue;
+ }
+
+ if ((msr & MSR_CTS) && !(k->last_msr & MSR_CTS)) {
+ if (k->cached_mcr & MCR_RTS)
+ printk("confused: RTS already high\n");
+ /* CTS went high. Send RTS. */
+ k->cached_mcr |= MCR_RTS;
+
+ ctrl_outb(k->cached_mcr, EC3104_SER4_MCR);
+ } else if ((!(msr & MSR_CTS)) && (k->last_msr & MSR_CTS)) {
+ /* CTS went low. */
+ if (!(k->cached_mcr & MCR_RTS))
+ printk("confused: RTS already low\n");
+
+ k->cached_mcr &= ~MCR_RTS;
+
+ ctrl_outb(k->cached_mcr, EC3104_SER4_MCR);
+ } else
+ break;
+
+ k->last_msr = msr;
+
+ continue;
+ }
+}
+
+void __init ec3104_kbd_init_hw(void)
+{
+ ec3104_keyb.last_msr = ctrl_inb(EC3104_SER4_MSR);
+ ec3104_keyb.cached_mcr = ctrl_inb(EC3104_SER4_MCR);
+
+ ec3104_keyb_clear_state();
+
+ /* Ok, finally allocate the IRQ, and off we go.. */
+ request_irq(EC3104_IRQ_SER4, ec3104_keyb_interrupt, 0, "keyboard", NULL);
+}
globalwinon(ch);
/* -----------------------------------------------------------------
- Anding against size will wrap the pointer back to its begining
+ Anding against size will wrap the pointer back to its beginning
position if it is necessary. This will only work if size is
a power of 2 which should always be the case. Size is determined
by the cards on board FEP/OS.
tail = bc->tout;
/* ------------------------------------------------------------------
- Anding against size will wrap the pointer back to its begining
+ Anding against size will wrap the pointer back to its beginning
position if it is necessary. This will only work if size is
a power of 2 which should always be the case. Size is determined
by the cards on board FEP/OS.
tail head
The above diagram shows that buffer locations 2,3,4,5 and 6 have
- data to be transmited, while head points at the next empty
+ data to be transmitted, while head points at the next empty
location. To calculate how much space is available first we have
to determine if the head pointer (tin) has wrapped. To do this
compare the head pointer to the tail pointer, If head is equal
that value from the buffers size. A one is subtracted from the
new value to indicate how much space is available between the
head pointer and end of buffer; as well as the space between the
- begining of the buffer and the tail. If the head is not greater
+ beginning of the buffer and the tail. If the head is not greater
or equal to the tail this indicates that the head has wrapped
- around to the begining of the buffer. To calculate the space
+ around to the beginning of the buffer. To calculate the space
available in this case simply subtract head from tail. This new
value minus one represents the space available betwwen the head
and tail pointers. In this example head (7) is greater than tail (2)
head tail
The above diagram shows that buffer locations 7,8,9,0 and 1 have
- data to be transmited, while head points at the next empty
+ data to be transmitted, while head points at the next empty
location. To find the space available we compare head to tail. If
head is not equal to, or greater than tail this indicates that head
has wrapped around. In this case head (2) is not equal to, or
}
/* ---------------------------------------------------------------
- Allow someone else to be scheduled. We will occasionaly go
+ Allow someone else to be scheduled. We will occasionally go
through this loop until one of the above conditions change.
The below schedule call will allow other processes to enter and
prevent this loop from hogging the cpu.
the boards array is correct. This could be wrong if
the card in question is PCI (And therefore has no ports
entry in the boards structure.) The rest of the
- information will be valid for PCI because the begining
+ information will be valid for PCI because the beginning
of pc_init scans for PCI and determines i/o and base
memory addresses. I am not sure if it is possible to
read the number of ports supported by the card prior to
/* -------------------------------------------------------------
This call is made by the user via. the ioctl call DIGI_INIT.
- It is resposible for setting up all the card specific stuff.
+ It is responsible for setting up all the card specific stuff.
---------------------------------------------------------------- */
bd = &boards[crd];
#ifdef CONFIG_MDA_CONSOLE
extern void mda_console_init(void);
#endif
+#if defined(CONFIG_S390_TAPE) && defined(CONFIG_S390_TAPE_CHAR)
+extern void tapechar_init(void);
+#endif
#if defined(CONFIG_ADB)
extern void adbdev_init(void);
#endif
#if defined(CONFIG_S390_TAPE) && defined(CONFIG_S390_TAPE_CHAR)
tapechar_init();
#endif
+#if defined(CONFIG_S390_TAPE) && defined(CONFIG_S390_TAPE_CHAR)
+ tapechar_init();
+#endif
#if defined(CONFIG_ADB)
adbdev_init();
#endif
extern int rtc_DP8570A_init(void);
extern int rtc_MK48T08_init(void);
extern int ds1286_init(void);
-extern int dsp56k_init(void);
extern int radio_init(void);
extern int pmu_device_init(void);
-extern int qpmouse_init(void);
extern int tosh_init(void);
static int misc_read_proc(char *buf, char **start, off_t offset,
int misc_register(struct miscdevice * misc)
{
static devfs_handle_t devfs_handle;
-
+ struct miscdevice *c;
+
if (misc->next || misc->prev)
return -EBUSY;
down(&misc_sem);
+ c = misc_list.next;
+
+ while ((c != &misc_list) && (c->minor != misc->minor))
+ c = c->next;
+ if (c != &misc_list) {
+ up(&misc_sem);
+ return -EBUSY;
+ }
+
if (misc->minor == MISC_DYNAMIC_MINOR) {
int i = DYNAMIC_MINORS;
while (--i >= 0)
int __init misc_init(void)
{
create_proc_read_entry("misc", 0, 0, misc_read_proc, NULL);
-#if defined CONFIG_82C710_MOUSE
- qpmouse_init();
-#endif
#ifdef CONFIG_MVME16x
rtc_MK48T08_init();
#endif
#ifdef CONFIG_SGI_DS1286
ds1286_init();
#endif
-#ifdef CONFIG_ATARI_DSP56K
- dsp56k_init();
-#endif
#ifdef CONFIG_MISC_RADIO
radio_init();
#endif
{
queue_the_message:
- save_flags(flags);
- cli();
-
pMsg = kmalloc(sizeof(struct r3964_message), GFP_KERNEL);
TRACE_M("add_msg - kmalloc %x",(int)pMsg);
- if(pMsg==NULL)
+ if(pMsg==NULL) {
return;
+ }
+
+ save_flags(flags);
+ cli();
pMsg->msg_id = msg_id;
pMsg->arg = arg;
*/
#include <linux/module.h>
-
-#include <linux/sched.h>
#include <linux/kernel.h>
+#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/fcntl.h>
#include <linux/errno.h>
fasync_qp(-1, file, 0);
if (!--qp_count) {
if (!poll_qp_status())
- printk("Warning: Mouse device busy in release_qp()\n");
+ printk(KERN_WARNING "Warning: Mouse device busy in release_qp()\n");
status = inb_p(qp_status);
outb_p(status & ~(QP_ENABLE|QP_INTS_ON), qp_status);
if (!poll_qp_status())
- printk("Warning: Mouse device busy in release_qp()\n");
+ printk(KERN_WARNING "Warning: Mouse device busy in release_qp()\n");
free_irq(QP_IRQ, NULL);
}
unlock_kernel();
outb_p(status, qp_status); /* Enable interrupts */
while (!poll_qp_status()) {
- printk("Error: Mouse device busy in open_qp()\n");
+ printk(KERN_ERR "Error: Mouse device busy in open_qp()\n");
qp_count--;
status &= ~(QP_ENABLE|QP_INTS_ON);
outb_p(status, qp_status);
* Initialize driver.
*/
static struct miscdevice qp_mouse = {
- PSMOUSE_MINOR, "QPmouse", &qp_fops
+ minor: PSMOUSE_MINOR,
+ name: "QPmouse",
+ fops: &qp_fops,
};
/*
return 1;
}
-int __init qpmouse_init(void)
+static const char msg_banner[] __initdata = KERN_INFO "82C710 type pointing device detected -- driver installed.\n";
+static const char msg_nomem[] __initdata = KERN_ERR "qpmouse: no queue memory.\n";
+
+static int __init qpmouse_init_driver(void)
{
if (!probe_qp())
return -EIO;
- printk(KERN_INFO "82C710 type pointing device detected -- driver installed.\n");
+ printk(msg_banner);
+
/* printk("82C710 address = %x (should be 0x310)\n", qp_data); */
queue = (struct qp_queue *) kmalloc(sizeof(*queue), GFP_KERNEL);
- if(queue==NULL)
- {
- printk(KERN_ERR "qpmouse: no queue memory.\n");
+ if (queue == NULL) {
+ printk(msg_nomem);
return -ENOMEM;
- }
+ }
qp_present = 1;
misc_register(&qp_mouse);
memset(queue, 0, sizeof(*queue));
queue->head = queue->tail = 0;
init_waitqueue_head(&queue->proc_list);
-
return 0;
}
-#ifdef MODULE
-int init_module(void)
-{
- return qpmouse_init();
-}
-
-void cleanup_module(void)
+static void __exit qpmouse_exit_driver(void)
{
misc_deregister(&qp_mouse);
kfree(queue);
}
-#endif
+
+module_init(qpmouse_init_driver);
+module_exit(qpmouse_exit_driver);
+
--- /dev/null
+/*
+ *
+ * BRIEF MODULE DESCRIPTION
+ * Qtronix 990P infrared keyboard driver.
+ *
+ *
+ * Copyright 2001 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ * ppopov@mvista.com or support@mvista.com
+ *
+ *
+ * The bottom portion of this driver was take from
+ * pc_keyb.c Please see that file for copyrights.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/config.h>
+
+/*
+ * NOTE:
+ *
+ * This driver has only been tested with the Consumer IR
+ * port of the ITE 8172 system controller.
+ *
+ * You do not need this driver if you are using the ps/2 or
+ * USB adapter that the keyboard ships with. You only need
+ * this driver if your board has a IR port and the keyboard
+ * data is being sent directly to the IR. In that case,
+ * you also need some low-level IR support. See it8172_cir.c.
+ *
+ */
+
+#ifdef CONFIG_QTRONIX_KEYBOARD
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+
+#include <asm/it8172/it8172.h>
+#include <asm/it8172/it8172_int.h>
+#include <asm/it8172/it8172_cir.h>
+
+#include <linux/spinlock.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/mm.h>
+#include <linux/signal.h>
+#include <linux/init.h>
+#include <linux/kbd_ll.h>
+#include <linux/delay.h>
+#include <linux/random.h>
+#include <linux/poll.h>
+#include <linux/miscdevice.h>
+#include <linux/malloc.h>
+#include <linux/kbd_kern.h>
+#include <linux/smp_lock.h>
+#include <asm/io.h>
+#include <linux/pc_keyb.h>
+
+#include <asm/keyboard.h>
+#include <asm/bitops.h>
+#include <asm/uaccess.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+
+#define leading1 0
+#define leading2 0xF
+
+#define KBD_CIR_PORT 0
+#define AUX_RECONNECT 170 /* scancode when ps2 device is plugged (back) in */
+
+static int data_index;
+struct cir_port *cir;
+static unsigned char kbdbytes[5];
+static unsigned char cir_data[32]; /* we only need 16 chars */
+
+static void kbd_int_handler(int irq, void *dev_id, struct pt_regs *regs);
+static int handle_data(unsigned char *p_data);
+static inline void handle_mouse_event(unsigned char scancode);
+static inline void handle_keyboard_event(unsigned char scancode, int down);
+static int __init psaux_init(void);
+
+static struct aux_queue *queue; /* Mouse data buffer. */
+static int aux_count = 0;
+
+/*
+ * Keys accessed through the 'Fn' key
+ * The Fn key does not produce a key-up sequence. So, the first
+ * time the user presses it, it will be key-down event. The key
+ * stays down until the user presses it again.
+ */
+#define NUM_FN_KEYS 56
+static unsigned char fn_keys[NUM_FN_KEYS] = {
+ 0,0,0,0,0,0,0,0, /* 0 7 */
+ 8,9,10,93,0,0,0,0, /* 8 15 */
+ 0,0,0,0,0,0,0,5, /* 16 23 */
+ 6,7,91,0,0,0,0,0, /* 24 31 */
+ 0,0,0,0,0,2,3,4, /* 32 39 */
+ 92,0,0,0,0,0,0,0, /* 40 47 */
+ 0,0,0,0,11,0,94,95 /* 48 55 */
+
+};
+
+void init_qtronix_990P_kbd(void)
+{
+ int retval;
+
+ cir = (struct cir_port *)kmalloc(sizeof(struct cir_port), GFP_KERNEL);
+ if (!cir) {
+ printk("Unable to initialize Qtronix keyboard\n");
+ return;
+ }
+
+ /*
+ * revisit
+ * this should be programmable, somehow by the, by the user.
+ */
+ cir->port = KBD_CIR_PORT;
+ cir->baud_rate = 0x1d;
+ cir->rdwos = 0;
+ cir->rxdcr = 0x3;
+ cir->hcfs = 0;
+ cir->fifo_tl = 0;
+ cir->cfq = 0x1d;
+ cir_port_init(cir);
+
+ retval = request_irq(IT8172_CIR0_IRQ, kbd_int_handler,
+ (unsigned long )(SA_INTERRUPT|SA_SHIRQ),
+ (const char *)"Qtronix IR Keyboard", (void *)cir);
+
+ if (retval) {
+ printk("unable to allocate cir %d irq %d\n",
+ cir->port, IT8172_CIR0_IRQ);
+ }
+#ifdef CONFIG_PSMOUSE
+ psaux_init();
+#endif
+}
+
+static inline unsigned char BitReverse(unsigned short key)
+{
+ unsigned char rkey = 0;
+ rkey |= (key & 0x1) << 7;
+ rkey |= (key & 0x2) << 5;
+ rkey |= (key & 0x4) << 3;
+ rkey |= (key & 0x8) << 1;
+ rkey |= (key & 0x10) >> 1;
+ rkey |= (key & 0x20) >> 3;
+ rkey |= (key & 0x40) >> 5;
+ rkey |= (key & 0x80) >> 7;
+ return rkey;
+
+}
+
+
+static inline u_int8_t UpperByte(u_int8_t data)
+{
+ return (data >> 4);
+}
+
+
+static inline u_int8_t LowerByte(u_int8_t data)
+{
+ return (data & 0xF);
+}
+
+
+int CheckSumOk(u_int8_t byte1, u_int8_t byte2,
+ u_int8_t byte3, u_int8_t byte4, u_int8_t byte5)
+{
+ u_int8_t CheckSum;
+
+ CheckSum = (byte1 & 0x0F) + byte2 + byte3 + byte4 + byte5;
+ if ( LowerByte(UpperByte(CheckSum) + LowerByte(CheckSum)) != UpperByte(byte1) )
+ return 0;
+ else
+ return 1;
+}
+
+
+static void kbd_int_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct cir_port *cir;
+ int j;
+ unsigned char int_status;
+
+ cir = (struct cir_port *)dev_id;
+ int_status = get_int_status(cir);;
+ if (int_status & 0x4) {
+ clear_fifo(cir);
+ return;
+ }
+
+ while (cir_get_rx_count(cir)) {
+
+ cir_data[data_index] = cir_read_data(cir);
+
+ if (data_index == 0) {/* expecting first byte */
+ if (cir_data[data_index] != leading1) {
+ //printk("!leading byte %x\n", cir_data[data_index]);
+ set_rx_active(cir);
+ clear_fifo(cir);
+ continue;
+ }
+ }
+ if (data_index == 1) {
+ if ((cir_data[data_index] & 0xf) != leading2) {
+ set_rx_active(cir);
+ data_index = 0; /* start over */
+ clear_fifo(cir);
+ continue;
+ }
+ }
+
+ if ( (cir_data[data_index] == 0xff)) { /* last byte */
+ //printk("data_index %d\n", data_index);
+ set_rx_active(cir);
+#if 0
+ for (j=0; j<=data_index; j++) {
+ printk("rx_data %d: %x\n", j, cir_data[j]);
+ }
+#endif
+ data_index = 0;
+ handle_data(cir_data);
+ return;
+ }
+ else if (data_index>16) {
+ set_rx_active(cir);
+#if 0
+ printk("warning: data_index %d\n", data_index);
+ for (j=0; j<=data_index; j++) {
+ printk("rx_data %d: %x\n", j, cir_data[j]);
+ }
+#endif
+ data_index = 0;
+ clear_fifo(cir);
+ return;
+ }
+ data_index++;
+ }
+}
+
+
+#define NUM_KBD_BYTES 5
+static int handle_data(unsigned char *p_data)
+{
+ u_int32_t bit_bucket;
+ u_int32_t i, j;
+ u_int32_t got_bits, next_byte;
+ int down = 0;
+
+ /* Reorganize the bit stream */
+ for (i=0; i<16; i++)
+ p_data[i] = BitReverse(~p_data[i]);
+
+ /*
+ * We've already previously checked that p_data[0]
+ * is equal to leading1 and that (p_data[1] & 0xf)
+ * is equal to leading2. These twelve bits are the
+ * leader code. We can now throw them away (the 12
+ * bits) and continue parsing the stream.
+ */
+ bit_bucket = p_data[1] << 12;
+ got_bits = 4;
+ next_byte = 2;
+
+ /*
+ * Process four bits at a time
+ */
+ for (i=0; i<NUM_KBD_BYTES; i++) {
+
+ kbdbytes[i]=0;
+
+ for (j=0; j<8; j++) /* 8 bits per byte */
+ {
+ if (got_bits < 4) {
+ bit_bucket |= (p_data[next_byte++] << (8 - got_bits));
+ got_bits += 8;
+ }
+
+ if ((bit_bucket & 0xF000) == 0x8000) {
+ /* Convert 1000b to 1 */
+ kbdbytes[i] = 0x80 | (kbdbytes[i] >> 1);
+ got_bits -= 4;
+ bit_bucket = bit_bucket << 4;
+ }
+ else if ((bit_bucket & 0xC000) == 0x8000) {
+ /* Convert 10b to 0 */
+ kbdbytes[i] = kbdbytes[i] >> 1;
+ got_bits -= 2;
+ bit_bucket = bit_bucket << 2;
+ }
+ else {
+ /* bad serial stream */
+ return 1;
+ }
+
+ if (next_byte > 16) {
+ //printk("error: too many bytes\n");
+ return 1;
+ }
+ }
+ }
+
+
+ if (!CheckSumOk(kbdbytes[0], kbdbytes[1],
+ kbdbytes[2], kbdbytes[3], kbdbytes[4])) {
+ //printk("checksum failed\n");
+ return 1;
+ }
+
+ if (kbdbytes[1] & 0x08) {
+ //printk("m: %x %x %x\n", kbdbytes[1], kbdbytes[2], kbdbytes[3]);
+ handle_mouse_event(kbdbytes[1]);
+ handle_mouse_event(kbdbytes[2]);
+ handle_mouse_event(kbdbytes[3]);
+ }
+ else {
+ if (kbdbytes[2] == 0) down = 1;
+#if 0
+ if (down)
+ printk("down %d\n", kbdbytes[3]);
+ else
+ printk("up %d\n", kbdbytes[3]);
+#endif
+ handle_keyboard_event(kbdbytes[3], down);
+ }
+ return 0;
+}
+
+
+spinlock_t kbd_controller_lock = SPIN_LOCK_UNLOCKED;
+static unsigned char handle_kbd_event(void);
+
+
+int pckbd_setkeycode(unsigned int scancode, unsigned int keycode)
+{
+ printk("pckbd_setkeycode scancode %x keycode %x\n", scancode, keycode);
+ return 0;
+}
+
+int pckbd_getkeycode(unsigned int scancode)
+{
+ return scancode;
+}
+
+
+int pckbd_translate(unsigned char scancode, unsigned char *keycode,
+ char raw_mode)
+{
+ static int prev_scancode = 0;
+
+ if (scancode == 0x00 || scancode == 0xff) {
+ prev_scancode = 0;
+ return 0;
+ }
+
+ /* todo */
+ if (!prev_scancode && scancode == 160) { /* Fn key down */
+ //printk("Fn key down\n");
+ prev_scancode = 160;
+ return 0;
+ }
+ else if (prev_scancode && scancode == 160) { /* Fn key up */
+ //printk("Fn key up\n");
+ prev_scancode = 0;
+ return 0;
+ }
+
+ /* todo */
+ if (prev_scancode == 160) {
+ if (scancode <= NUM_FN_KEYS) {
+ *keycode = fn_keys[scancode];
+ //printk("fn keycode %d\n", *keycode);
+ }
+ else
+ return 0;
+ }
+ else if (scancode <= 127) {
+ *keycode = scancode;
+ }
+ else
+ return 0;
+
+
+ return 1;
+}
+
+char pckbd_unexpected_up(unsigned char keycode)
+{
+ //printk("pckbd_unexpected_up\n");
+ return 0;
+}
+
+static unsigned char kbd_exists = 1;
+
+static inline void handle_keyboard_event(unsigned char scancode, int down)
+{
+ kbd_exists = 1;
+ handle_scancode(scancode, down);
+ tasklet_schedule(&keyboard_tasklet);
+}
+
+
+void pckbd_leds(unsigned char leds)
+{
+}
+
+/* dummy */
+void pckbd_init_hw(void)
+{
+}
+
+
+
+static inline void handle_mouse_event(unsigned char scancode)
+{
+ if(scancode == AUX_RECONNECT){
+ queue->head = queue->tail = 0; /* Flush input queue */
+ // __aux_write_ack(AUX_ENABLE_DEV); /* ping the mouse :) */
+ return;
+ }
+
+ add_mouse_randomness(scancode);
+ if (aux_count) {
+ int head = queue->head;
+
+ queue->buf[head] = scancode;
+ head = (head + 1) & (AUX_BUF_SIZE-1);
+ if (head != queue->tail) {
+ queue->head = head;
+ kill_fasync(&queue->fasync, SIGIO, POLL_IN);
+ wake_up_interruptible(&queue->proc_list);
+ }
+ }
+}
+
+static unsigned char get_from_queue(void)
+{
+ unsigned char result;
+ unsigned long flags;
+
+ spin_lock_irqsave(&kbd_controller_lock, flags);
+ result = queue->buf[queue->tail];
+ queue->tail = (queue->tail + 1) & (AUX_BUF_SIZE-1);
+ spin_unlock_irqrestore(&kbd_controller_lock, flags);
+ return result;
+}
+
+
+static inline int queue_empty(void)
+{
+ return queue->head == queue->tail;
+}
+
+static int fasync_aux(int fd, struct file *filp, int on)
+{
+ int retval;
+
+ //printk("fasync_aux\n");
+ retval = fasync_helper(fd, filp, on, &queue->fasync);
+ if (retval < 0)
+ return retval;
+ return 0;
+}
+
+
+/*
+ * Random magic cookie for the aux device
+ */
+#define AUX_DEV ((void *)queue)
+
+static int release_aux(struct inode * inode, struct file * file)
+{
+ lock_kernel();
+ fasync_aux(-1, file, 0);
+ aux_count--;
+ unlock_kernel();
+ return 0;
+}
+
+static int open_aux(struct inode * inode, struct file * file)
+{
+ if (aux_count++) {
+ return 0;
+ }
+ queue->head = queue->tail = 0; /* Flush input queue */
+ return 0;
+}
+
+/*
+ * Put bytes from input queue to buffer.
+ */
+
+static ssize_t read_aux(struct file * file, char * buffer,
+ size_t count, loff_t *ppos)
+{
+ DECLARE_WAITQUEUE(wait, current);
+ ssize_t i = count;
+ unsigned char c;
+
+ if (queue_empty()) {
+ if (file->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+ add_wait_queue(&queue->proc_list, &wait);
+repeat:
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (queue_empty() && !signal_pending(current)) {
+ schedule();
+ goto repeat;
+ }
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&queue->proc_list, &wait);
+ }
+ while (i > 0 && !queue_empty()) {
+ c = get_from_queue();
+ put_user(c, buffer++);
+ i--;
+ }
+ if (count-i) {
+ file->f_dentry->d_inode->i_atime = CURRENT_TIME;
+ return count-i;
+ }
+ if (signal_pending(current))
+ return -ERESTARTSYS;
+ return 0;
+}
+
+/*
+ * Write to the aux device.
+ */
+
+static ssize_t write_aux(struct file * file, const char * buffer,
+ size_t count, loff_t *ppos)
+{
+ /*
+ * The ITE boards this was tested on did not have the
+ * transmit wires connected.
+ */
+ return count;
+}
+
+static unsigned int aux_poll(struct file *file, poll_table * wait)
+{
+ poll_wait(file, &queue->proc_list, wait);
+ if (!queue_empty())
+ return POLLIN | POLLRDNORM;
+ return 0;
+}
+
+struct file_operations psaux_fops = {
+ read: read_aux,
+ write: write_aux,
+ poll: aux_poll,
+ open: open_aux,
+ release: release_aux,
+ fasync: fasync_aux,
+};
+
+/*
+ * Initialize driver.
+ */
+static struct miscdevice psaux_mouse = {
+ PSMOUSE_MINOR, "psaux", &psaux_fops
+};
+
+static int __init psaux_init(void)
+{
+ misc_register(&psaux_mouse);
+ queue = (struct aux_queue *) kmalloc(sizeof(*queue), GFP_KERNEL);
+ memset(queue, 0, sizeof(*queue));
+ queue->head = queue->tail = 0;
+ init_waitqueue_head(&queue->proc_list);
+
+ return 0;
+}
+#endif
--- /dev/null
+# Default kernel keymap. This uses 7 modifier combinations.
+keymaps 0-2,4-5,8,12
+# Change the above line into
+# keymaps 0-2,4-6,8,12
+# in case you want the entries
+# altgr control keycode 83 = Boot
+# altgr control keycode 111 = Boot
+# below.
+#
+# In fact AltGr is used very little, and one more keymap can
+# be saved by mapping AltGr to Alt (and adapting a few entries):
+# keycode 100 = Alt
+#
+keycode 1 = grave asciitilde
+ alt keycode 1 = Meta_Escape
+keycode 2 = one exclam
+ alt keycode 2 = Meta_one
+keycode 3 = two at at
+ control keycode 3 = nul
+ shift control keycode 3 = nul
+ alt keycode 3 = Meta_two
+keycode 4 = three numbersign
+ control keycode 4 = Escape
+ alt keycode 4 = Meta_three
+keycode 5 = four dollar dollar
+ control keycode 5 = Control_backslash
+ alt keycode 5 = Meta_four
+keycode 6 = five percent
+ control keycode 6 = Control_bracketright
+ alt keycode 6 = Meta_five
+keycode 7 = six asciicircum
+ control keycode 7 = Control_asciicircum
+ alt keycode 7 = Meta_six
+keycode 8 = seven ampersand braceleft
+ control keycode 8 = Control_underscore
+ alt keycode 8 = Meta_seven
+keycode 9 = eight asterisk bracketleft
+ control keycode 9 = Delete
+ alt keycode 9 = Meta_eight
+keycode 10 = nine parenleft bracketright
+ alt keycode 10 = Meta_nine
+keycode 11 = zero parenright braceright
+ alt keycode 11 = Meta_zero
+keycode 12 = minus underscore backslash
+ control keycode 12 = Control_underscore
+ shift control keycode 12 = Control_underscore
+ alt keycode 12 = Meta_minus
+keycode 13 = equal plus
+ alt keycode 13 = Meta_equal
+keycode 15 = Delete Delete
+ control keycode 15 = BackSpace
+ alt keycode 15 = Meta_Delete
+keycode 16 = Tab Tab
+ alt keycode 16 = Meta_Tab
+keycode 17 = q
+keycode 18 = w
+keycode 19 = e
+keycode 20 = r
+keycode 21 = t
+keycode 22 = y
+keycode 23 = u
+keycode 24 = i
+keycode 25 = o
+keycode 26 = p
+keycode 27 = bracketleft braceleft
+ control keycode 27 = Escape
+ alt keycode 27 = Meta_bracketleft
+keycode 28 = bracketright braceright
+ control keycode 28 = Control_bracketright
+ alt keycode 28 = Meta_bracketright
+keycode 29 = backslash bar
+ control keycode 29 = Control_backslash
+ alt keycode 29 = Meta_backslash
+keycode 30 = Caps_Lock
+keycode 31 = a
+keycode 32 = s
+keycode 33 = d
+keycode 34 = f
+keycode 35 = g
+keycode 36 = h
+keycode 37 = j
+keycode 38 = k
+keycode 39 = l
+keycode 40 = semicolon colon
+ alt keycode 39 = Meta_semicolon
+keycode 41 = apostrophe quotedbl
+ control keycode 40 = Control_g
+ alt keycode 40 = Meta_apostrophe
+keycode 42 = grave asciitilde
+ control keycode 41 = nul
+ alt keycode 41 = Meta_grave
+keycode 43 = Return
+ alt keycode 43 = Meta_Control_m
+keycode 44 = Shift
+keycode 46 = z
+keycode 47 = x
+keycode 48 = c
+keycode 49 = v
+keycode 50 = b
+keycode 51 = n
+keycode 52 = m
+keycode 53 = comma less
+ alt keycode 51 = Meta_comma
+keycode 54 = period greater
+ control keycode 52 = Compose
+ alt keycode 52 = Meta_period
+keycode 55 = slash question
+ control keycode 53 = Delete
+ alt keycode 53 = Meta_slash
+keycode 57 = Shift
+keycode 58 = Control
+keycode 60 = Alt
+keycode 61 = space space
+ control keycode 61 = nul
+ alt keycode 61 = Meta_space
+keycode 62 = Alt
+
+keycode 75 = Insert
+keycode 76 = Delete
+
+keycode 83 = Up
+keycode 84 = Down
+
+keycode 85 = Prior
+ shift keycode 85 = Scroll_Backward
+keycode 86 = Next
+ shift keycode 86 = Scroll_Forward
+keycode 89 = Right
+ alt keycode 89 = Incr_Console
+keycode 79 = Left
+ alt keycode 79 = Decr_Console
+
+keycode 90 = Num_Lock
+ shift keycode 90 = Bare_Num_Lock
+
+keycode 91 = minus
+keycode 92 = plus
+keycode 93 = KP_Multiply
+keycode 94 = period
+keycode 95 = KP_Divide
+
+keycode 107 = Select
+keycode 108 = Down
+
+keycode 110 = Escape Escape
+ alt keycode 1 = Meta_Escape
+
+keycode 112 = F1 F11 Console_13
+ control keycode 112 = F1
+ alt keycode 112 = Console_1
+ control alt keycode 112 = Console_1
+keycode 113 = F2 F12 Console_14
+ control keycode 113 = F2
+ alt keycode 113 = Console_2
+ control alt keycode 113 = Console_2
+keycode 114 = F3 F13 Console_15
+ control keycode 114 = F3
+ alt keycode 114 = Console_3
+ control alt keycode 114 = Console_3
+keycode 115 = F4 F14 Console_16
+ control keycode 115 = F4
+ alt keycode 115 = Console_4
+ control alt keycode 115 = Console_4
+keycode 116 = F5 F15 Console_17
+ control keycode 116 = F5
+ alt keycode 116 = Console_5
+ control alt keycode 116 = Console_5
+keycode 117 = F6 F16 Console_18
+ control keycode 117 = F6
+ alt keycode 117 = Console_6
+ control alt keycode 117 = Console_6
+keycode 118 = F7 F17 Console_19
+ control keycode 118 = F7
+ alt keycode 118 = Console_7
+ control alt keycode 118 = Console_7
+keycode 119 = F8 F18 Console_20
+ control keycode 119 = F8
+ alt keycode 119 = Console_8
+ control alt keycode 119 = Console_8
+keycode 120 = F9 F19 Console_21
+ control keycode 120 = F9
+ alt keycode 120 = Console_9
+ control alt keycode 120 = Console_9
+keycode 121 = F10 F20 Console_22
+ control keycode 121 = F10
+ alt keycode 121 = Console_10
+ control alt keycode 121 = Console_10
+
+keycode 126 = Pause
+
+
+string F1 = "\033[[A"
+string F2 = "\033[[B"
+string F3 = "\033[[C"
+string F4 = "\033[[D"
+string F5 = "\033[[E"
+string F6 = "\033[17~"
+string F7 = "\033[18~"
+string F8 = "\033[19~"
+string F9 = "\033[20~"
+string F10 = "\033[21~"
+string F11 = "\033[23~"
+string F12 = "\033[24~"
+string F13 = "\033[25~"
+string F14 = "\033[26~"
+string F15 = "\033[28~"
+string F16 = "\033[29~"
+string F17 = "\033[31~"
+string F18 = "\033[32~"
+string F19 = "\033[33~"
+string F20 = "\033[34~"
+string Find = "\033[1~"
+string Insert = "\033[2~"
+string Remove = "\033[3~"
+string Select = "\033[4~"
+string Prior = "\033[5~"
+string Next = "\033[6~"
+string Macro = "\033[M"
+string Pause = "\033[P"
+compose '`' 'A' to 'À'
+compose '`' 'a' to 'à'
+compose '\'' 'A' to 'Á'
+compose '\'' 'a' to 'á'
+compose '^' 'A' to 'Â'
+compose '^' 'a' to 'â'
+compose '~' 'A' to 'Ã'
+compose '~' 'a' to 'ã'
+compose '"' 'A' to 'Ä'
+compose '"' 'a' to 'ä'
+compose 'O' 'A' to 'Å'
+compose 'o' 'a' to 'å'
+compose '0' 'A' to 'Å'
+compose '0' 'a' to 'å'
+compose 'A' 'A' to 'Å'
+compose 'a' 'a' to 'å'
+compose 'A' 'E' to 'Æ'
+compose 'a' 'e' to 'æ'
+compose ',' 'C' to 'Ç'
+compose ',' 'c' to 'ç'
+compose '`' 'E' to 'È'
+compose '`' 'e' to 'è'
+compose '\'' 'E' to 'É'
+compose '\'' 'e' to 'é'
+compose '^' 'E' to 'Ê'
+compose '^' 'e' to 'ê'
+compose '"' 'E' to 'Ë'
+compose '"' 'e' to 'ë'
+compose '`' 'I' to 'Ì'
+compose '`' 'i' to 'ì'
+compose '\'' 'I' to 'Í'
+compose '\'' 'i' to 'í'
+compose '^' 'I' to 'Î'
+compose '^' 'i' to 'î'
+compose '"' 'I' to 'Ï'
+compose '"' 'i' to 'ï'
+compose '-' 'D' to 'Ð'
+compose '-' 'd' to 'ð'
+compose '~' 'N' to 'Ñ'
+compose '~' 'n' to 'ñ'
+compose '`' 'O' to 'Ò'
+compose '`' 'o' to 'ò'
+compose '\'' 'O' to 'Ó'
+compose '\'' 'o' to 'ó'
+compose '^' 'O' to 'Ô'
+compose '^' 'o' to 'ô'
+compose '~' 'O' to 'Õ'
+compose '~' 'o' to 'õ'
+compose '"' 'O' to 'Ö'
+compose '"' 'o' to 'ö'
+compose '/' 'O' to 'Ø'
+compose '/' 'o' to 'ø'
+compose '`' 'U' to 'Ù'
+compose '`' 'u' to 'ù'
+compose '\'' 'U' to 'Ú'
+compose '\'' 'u' to 'ú'
+compose '^' 'U' to 'Û'
+compose '^' 'u' to 'û'
+compose '"' 'U' to 'Ü'
+compose '"' 'u' to 'ü'
+compose '\'' 'Y' to 'Ý'
+compose '\'' 'y' to 'ý'
+compose 'T' 'H' to 'Þ'
+compose 't' 'h' to 'þ'
+compose 's' 's' to 'ß'
+compose '"' 'y' to 'ÿ'
+compose 's' 'z' to 'ß'
+compose 'i' 'j' to 'ÿ'
free2:kfree (p->RIOHosts);
free1:kfree (p);
free0:
- rio_dprintk (RIO_DEBUG_INIT, "Not enough memory! %p %p %p %p %p\n",
- p, p->RIOHosts, p->RIOPortp, rio_termios, rio_termios);
+ if (p) {
+ rio_dprintk (RIO_DEBUG_INIT, "Not enough memory! %p %p %p %p %p\n",
+ p, p->RIOHosts, p->RIOPortp, rio_termios, rio_termios);
+ }
return -ENOMEM;
}
PortP->Config &= ~RIO_WAITDRAIN;
}
/*
- ** Store setings if locking or unlocking port or if the
+ ** Store settings if locking or unlocking port or if the
** port is not locked, when setting the store option.
*/
if (PortP->Mapped &&
case 9600:
default:
cflag |= B9600;
+ /*
+ * Set this to a sane value to prevent a divide error
+ */
+ baud = 9600;
break;
}
switch(bits) {
#include <linux/module.h>
#include <linux/kbd_kern.h>
-#if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(__alpha__) || defined(__mips__) || defined(CONFIG_SPARC64)
+#if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(__alpha__) || \
+ defined(__mips__) || defined(CONFIG_SPARC64) || defined(CONFIG_SUPERH)
static int x86_sysrq_alt = 0;
#ifdef CONFIG_SPARC64
fi
dep_tristate ' Guillemot MAXI Radio FM 2000 radio' CONFIG_RADIO_MAXIRADIO $CONFIG_VIDEO_DEV
dep_tristate ' Maestro on board radio' CONFIG_RADIO_MAESTRO $CONFIG_VIDEO_DEV
-dep_tristate ' Miro PCM20 Radio' CONFIG_RADIO_MIROPCM20 $CONFIG_VIDEO_DEV
+dep_tristate ' miroSOUND PCM20 radio' CONFIG_RADIO_MIROPCM20 $CONFIG_VIDEO_DEV $CONFIG_SOUND_ACI_MIXER
dep_tristate ' SF16FMI Radio' CONFIG_RADIO_SF16FMI $CONFIG_VIDEO_DEV
if [ "$CONFIG_RADIO_SF16FMI" = "y" ]; then
hex ' SF16FMI I/O port (0x284 or 0x384)' CONFIG_RADIO_SF16FMI_PORT 284
export-objs :=
-list-multi :=
+list-multi := miropcm20.o
+
+miropcm20-objs := radio-miropcm20.o rds-miropcm20.o
obj-$(CONFIG_RADIO_AZTECH) += radio-aztech.o
obj-$(CONFIG_RADIO_RTRACK2) += radio-rtrack2.o
obj-$(CONFIG_RADIO_MAXIRADIO) += radio-maxiradio.o
obj-$(CONFIG_RADIO_RTRACK) += radio-aimslab.o
obj-$(CONFIG_RADIO_ZOLTRIX) += radio-zoltrix.o
-obj-$(CONFIG_RADIO_MIROPCM20) += radio-miropcm20.o
+obj-$(CONFIG_RADIO_MIROPCM20) += miropcm20.o
obj-$(CONFIG_RADIO_GEMTEK) += radio-gemtek.o
obj-$(CONFIG_RADIO_TRUST) += radio-trust.o
obj-$(CONFIG_RADIO_MAESTRO) += radio-maestro.o
include $(TOPDIR)/Rules.make
+
+miropcm20.o: $(miropcm20-objs)
+ $(LD) -r -o $@ $(miropcm20-objs)
* (c) 1998 Ruurd Reitsma <R.A.Reitsma@wbmt.tudelft.nl>
* Thanks to Norberto Pellici for the ACI device interface specification
* The API part is based on the radiotrack driver by M. Kirkwood
- * This driver relies on the aci mixer (drivers/sound/lowlevel/aci.c)
+ * This driver relies on the aci mixer (drivers/sound/aci.c)
* Look there for further info...
*/
-#include <linux/module.h> /* Modules */
-#include <linux/init.h> /* Initdata */
-#include <asm/uaccess.h> /* copy to/from user */
-#include <linux/videodev.h> /* kernel radio structs */
-#include "../../sound/miroaci.h" /* ACI Control by acimixer */
+/* Revision history:
+ *
+ * 1998 Ruurd Reitsma <R.A.Reitsma@wbmt.tudelft.nl>
+ * 2000-09-05 Robert Siemer <Robert.Siemer@gmx.de>
+ * removed unfinished volume control (maybe adding it later again)
+ * use OSS-mixer; added stereo control
+ */
+
+/* What ever you think about the ACI, version 0x07 is not very well!
+ * I cant get frequency, 'tuner status', 'tuner flags' or mute/mono
+ * conditions... Robert
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/videodev.h>
+#include <linux/devfs_fs_kernel.h>
+#include <asm/uaccess.h>
+
+char * aci_radio_name;
+
+#include "../../sound/aci.h"
static int users = 0;
struct pcm20_device
{
- int port;
- int curvol;
- unsigned long curfreq;
+ unsigned long freq;
int muted;
+ int stereo;
};
-/* local things */
-
-
-static void pcm20_mute(struct pcm20_device *dev)
+static int pcm20_mute(struct pcm20_device *dev, unsigned char mute)
{
-
- dev->muted = 1;
- aci_write_cmd(0xa3,0x01);
-
+ dev->muted = mute;
+ return aci_write_cmd(0xa3, mute);
}
-static int pcm20_setvol(struct pcm20_device *dev, int vol)
+static int pcm20_stereo(struct pcm20_device *dev, unsigned char stereo)
{
-
- if(vol == dev->curvol) { /* requested volume = current */
- if (dev->muted) { /* user is unmuting the card */
- dev->muted = 0;
- aci_write_cmd(0xa3,0x00); /* enable card */
- }
-
- return 0;
- }
-
- if(vol == 0) { /* volume = 0 means mute the card */
- aci_write_cmd(0x3d, 0x20);
- aci_write_cmd(0x35, 0x20);
- return 0;
- }
-
- dev->muted = 0;
- aci_write_cmd(0x3d, 32-vol); /* Right Channel */
- aci_write_cmd(0x35, 32-vol); /* Left Channel */
- dev->curvol = vol;
-
- return 0;
+ dev->stereo = stereo;
+ return aci_write_cmd(0xa4, !stereo);
}
static int pcm20_setfreq(struct pcm20_device *dev, unsigned long freq)
unsigned char freql;
unsigned char freqh;
- freq = (freq * 10) / 16;
- freql = freq & 0xff;
- freqh = freq >> 8;
+ dev->freq=freq;
+ freq /= 160;
+ if (!(aci_version==0x07 || aci_version>=0xb0))
+ freq /= 10; /* I don't know exactly which version
+ * needs this hack */
+ freql = freq & 0xff;
+ freqh = freq >> 8;
- aci_write_cmd_d(0xa7, freql, freqh); /* Tune to frequency */
+ aci_rds_cmd(RDS_RESET, 0, 0);
+ pcm20_stereo(dev, 1);
- return 0;
+ return aci_rw_cmd(0xa7, freql, freqh); /* Tune to frequency */
}
-int pcm20_getsigstr(struct pcm20_device *dev)
+static int pcm20_getflags(struct pcm20_device *dev, __u32 *flags, __u16 *signal)
{
+ /* okay, check for signal, stereo and rds here... */
+ int i;
unsigned char buf;
- aci_indexed_cmd(0xf0, 0x32, &buf);
- if ((buf & 0x80) == 0x80)
+
+ if ((i=aci_rw_cmd(0xa9, -1, -1))<0)
+ return i;
+#if DEBUG
+ printk("check_sig: 0x%x\n", i);
+#endif
+ if (i & 0x80) {
+ /* no signal from tuner */
+ *flags=0;
+ *signal=0;
+ return 0;
+ } else
+ *signal=0xffff;
+
+ if ((i=aci_rw_cmd(0xa8, -1, -1))<0)
+ return i;
+ if (i & 0x40) {
+ *flags=0;
+ } else {
+ /* stereo */
+ *flags=VIDEO_TUNER_STEREO_ON;
+ /* I cant see stereo, when forced to mono */
+ dev->stereo=1;
+ }
+
+ if ((i=aci_rds_cmd(RDS_STATUS, &buf, 1))<0)
+ return i;
+ if (buf & 1)
+ /* RDS available */
+ *flags|=VIDEO_TUNER_RDS_ON;
+ else
return 0;
- return 1; /* signal present */
+
+ if ((i=aci_rds_cmd(RDS_RXVALUE, &buf, 1))<0)
+ return i;
+#if DEBUG
+ printk("rds-signal: %d\n", buf);
+#endif
+ if (buf > 15) {
+ printk("rds-miropcm20: RX strengths unexpected high...\n");
+ buf=15;
+ }
+ /* refine signal */
+ if ((*signal=SCALE(15, 0xffff, buf))==0)
+ *signal = 1;
+
+ return 0;
}
static int pcm20_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
{
struct pcm20_device *pcm20=dev->priv;
+ int i;
switch(cmd)
{
return -EFAULT;
if(v.tuner) /* Only 1 tuner */
return -EINVAL;
- v.rangelow=(int)(87.5*16);
- v.rangehigh=(int)(108.0*16);
- v.flags=0;
+ v.rangelow=87*16000;
+ v.rangehigh=108*16000;
+ pcm20_getflags(pcm20, &v.flags, &v.signal);
+ v.flags|=VIDEO_TUNER_LOW;
v.mode=VIDEO_MODE_AUTO;
- v.signal=0xFFFF*pcm20_getsigstr(pcm20);
strcpy(v.name, "FM");
if(copy_to_user(arg,&v, sizeof(v)))
return -EFAULT;
return 0;
}
case VIDIOCGFREQ:
- if(copy_to_user(arg, &pcm20->curfreq, sizeof(pcm20->curfreq)))
+ if(copy_to_user(arg, &pcm20->freq, sizeof(pcm20->freq)))
return -EFAULT;
return 0;
case VIDIOCSFREQ:
- if(copy_from_user(&pcm20->curfreq, arg,sizeof(pcm20->curfreq)))
+ if(copy_from_user(&pcm20->freq, arg, sizeof(pcm20->freq)))
return -EFAULT;
- pcm20_setfreq(pcm20, pcm20->curfreq);
- return 0;
+ i=pcm20_setfreq(pcm20, pcm20->freq);
+#if DEBUG
+ printk("First view (setfreq): 0x%x\n", i);
+#endif
+ return i;
case VIDIOCGAUDIO:
{
struct video_audio v;
memset(&v,0, sizeof(v));
- v.flags|=VIDEO_AUDIO_MUTABLE|VIDEO_AUDIO_VOLUME;
- v.volume=pcm20->curvol * 2048;
+ v.flags=VIDEO_AUDIO_MUTABLE;
+ if (pcm20->muted)
+ v.flags|=VIDEO_AUDIO_MUTE;
+ v.mode=VIDEO_SOUND_STEREO;
+ if (pcm20->stereo)
+ v.mode|=VIDEO_SOUND_MONO;
+ /* v.step=2048; */
strcpy(v.name, "Radio");
if(copy_to_user(arg,&v, sizeof(v)))
return -EFAULT;
{
struct video_audio v;
if(copy_from_user(&v, arg, sizeof(v)))
- return -EFAULT;
+ return -EFAULT;
if(v.audio)
return -EINVAL;
- if(v.flags&VIDEO_AUDIO_MUTE)
- pcm20_mute(pcm20);
- else
- pcm20_setvol(pcm20,v.volume/2048);
+ pcm20_mute(pcm20, !!(v.flags&VIDEO_AUDIO_MUTE));
+ if(v.flags&VIDEO_SOUND_MONO)
+ pcm20_stereo(pcm20, 0);
+ if(v.flags&VIDEO_SOUND_STEREO)
+ pcm20_stereo(pcm20, 1);
return 0;
}
users--;
}
-static struct pcm20_device pcm20_unit;
+static struct pcm20_device pcm20_unit=
+{
+ freq: 87*16000,
+ muted: 1,
+ stereo: 0
+};
static struct video_device pcm20_radio=
{
open: pcm20_open,
close: pcm20_close,
ioctl: pcm20_ioctl,
+ priv: &pcm20_unit
};
static int __init pcm20_init(void)
{
-
- pcm20_radio.priv=&pcm20_unit;
-
if(video_register_device(&pcm20_radio, VFL_TYPE_RADIO)==-1)
return -EINVAL;
+ if(attach_aci_rds()<0) {
+ video_unregister_device(&pcm20_radio);
+ return -EINVAL;
+ }
+#if DEBUG
+ printk("v4l-name: %s\n", devfs_get_name(pcm20_radio.devfs_handle, 0));
+#endif
printk(KERN_INFO "Miro PCM20 radio card driver.\n");
- /* mute card - prevents noisy bootups */
-
- /* this ensures that the volume is all the way down */
-
- pcm20_unit.curvol = 0;
-
return 0;
}
static void __exit pcm20_cleanup(void)
{
+ unload_aci_rds();
video_unregister_device(&pcm20_radio);
}
module_init(pcm20_init);
module_exit(pcm20_cleanup);
-
--- /dev/null
+/*
+ * Many thanks to Fred Seidel <seidel@metabox.de>, the
+ * designer of the RDS decoder hardware. With his help
+ * I was able to code this driver.
+ * Thanks also to Norberto Pellicci, Dominic Mounteney
+ * <DMounteney@pinnaclesys.com> and www.teleauskunft.de
+ * for good hints on finding Fred. It was somewhat hard
+ * to locate him here in Germany... [:
+ *
+ * Revision history:
+ *
+ * 2000-08-09 Robert Siemer <Robert.Siemer@gmx.de>
+ * RDS support for MiroSound PCM20 radio
+ */
+
+#define _NO_VERSION_
+
+/* #include <linux/kernel.h> */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <asm/semaphore.h>
+#include <asm/io.h>
+#include "../../sound/aci.h"
+
+#define WATCHMASK 0352 /* 11101010 */
+
+#define DEBUG 0
+
+static struct semaphore aci_rds_sem;
+
+
+#define RDS_BUSYMASK 0x10 /* Bit 4 */
+#define RDS_CLOCKMASK 0x08 /* Bit 3 */
+#define RDS_DATAMASK 0x04 /* Bit 2 */
+
+
+static void print_matrix(char array[], unsigned int length)
+{
+ int i, j;
+
+ for (i=0; i<length; i++) {
+ printk("aci-rds: ");
+ for (j=7; j>=0; j--) {
+ printk("%d", (array[i] >> j) & 0x1);
+ }
+ if (i%8 == 0)
+ printk(" byte-border\n");
+ else
+ printk("\n");
+ }
+}
+
+static int byte2trans(unsigned char byte, unsigned char sendbuffer[], int size)
+{
+ int i;
+
+ if (size != 8)
+ return -1;
+ for (i = 7; i >= 0; i--)
+ sendbuffer[7-i] = (byte & (1 << i)) ? RDS_DATAMASK : 0;
+ sendbuffer[0] |= RDS_CLOCKMASK;
+
+ return 0;
+}
+
+static int trans2byte(unsigned char buffer[], int size)
+{
+ int i;
+ unsigned char byte=0;
+
+ if (size != 8)
+ return -1;
+ for (i = 7; i >= 0; i--)
+ byte |= ((buffer[7-i] & RDS_DATAMASK) ? 1 : 0) << i;
+
+ return byte;
+}
+
+static int trans2data(unsigned char readbuffer[], int readsize, unsigned char data[], int datasize)
+{
+ int i,j;
+
+ if (readsize != datasize*8)
+ return -1;
+ for (i = 0; i < datasize; i++)
+ if ((j=trans2byte(&readbuffer[i*8], 8)) < 0)
+ return -1;
+ else
+ data[i]=j;
+ return 0;
+}
+
+static int rds_waitread(void)
+{
+ unsigned char byte;
+ int i=2000;
+
+ do {
+ byte=inb(RDS_REGISTER);
+ if ((byte & WATCHMASK) != WATCHMASK)
+ printk("aci-rds: Hidden information discoverd!\n");
+ i--;
+ }
+ while ((byte & RDS_BUSYMASK) && i);
+
+ if (i) {
+#if DEBUG
+ printk("rds_waitread()");
+ print_matrix(&byte, 1);
+#endif
+ return (byte);
+ } else {
+ printk("aci-rds: rds_waitread() timeout...\n");
+ return -1;
+ }
+}
+
+/* dont use any ..._nowait() function if you are not sure what you do... */
+
+static inline void rds_rawwrite_nowait(unsigned char byte)
+{
+#if DEBUG
+ printk("rds_rawwrite()");
+ print_matrix(&byte, 1);
+#endif
+ outb(byte, RDS_REGISTER);
+}
+
+static int rds_rawwrite(unsigned char byte)
+{
+ if (rds_waitread() >= 0) {
+ rds_rawwrite_nowait(byte);
+ return 0;
+ } else
+ return -1;
+}
+
+static int rds_write(unsigned char cmd)
+{
+ unsigned char sendbuffer[8];
+ int i;
+
+ if (byte2trans(cmd, sendbuffer, 8) != 0){
+ return -1;
+ } else {
+ for (i=0; i<8; i++) {
+ rds_rawwrite(sendbuffer[i]);
+ }
+ }
+ return 0;
+}
+
+static int rds_readcycle_nowait(void)
+{
+ rds_rawwrite_nowait(0);
+ return rds_waitread();
+}
+
+static int rds_readcycle(void)
+{
+ if (rds_rawwrite(0) < 0)
+ return -1;
+ return rds_waitread();
+}
+
+static int rds_read(unsigned char databuffer[], int datasize)
+{
+
+#define READSIZE (8*datasize)
+
+ int i,j;
+ unsigned char* readbuffer;
+
+ if (!datasize) /* nothing to read */
+ return 0;
+
+ /* to be able to use rds_readcycle_nowait()
+ I have to readwait() here */
+ if (rds_waitread() < 0)
+ return -1;
+
+ if ((readbuffer=kmalloc(READSIZE, GFP_KERNEL)) == 0) {
+ printk("aci-rds: Out of memory...\n");
+ return -ENOMEM;
+ } else {
+ if (signal_pending(current)) {
+ kfree(readbuffer);
+ return -EINTR;
+ }
+ }
+
+ for (i=0; i< READSIZE; i++)
+ if((j=rds_readcycle_nowait()) < 0) {
+ kfree(readbuffer);
+ return -1;
+ } else
+ readbuffer[i]=j;
+ if (trans2data(readbuffer, READSIZE, databuffer, datasize) < 0) {
+ kfree(readbuffer);
+ return -1;
+ }
+ kfree(readbuffer);
+ return 0;
+}
+
+static int rds_ack(void)
+{
+ int i=rds_readcycle();
+
+ if (i < 0)
+ return -1;
+ if (i & RDS_DATAMASK) {
+ return 0; /* ACK */
+ } else {
+ return 1; /* NACK */
+ }
+}
+
+int aci_rds_cmd(unsigned char cmd, unsigned char databuffer[], int datasize)
+{
+ int ret;
+
+ if (down_interruptible(&aci_rds_sem))
+ return -EINTR;
+
+ if (rds_write(cmd))
+ ret = -2;
+
+ /* RDS_RESET doesn't need further processing */
+ if (cmd!=RDS_RESET && (rds_ack() || rds_read(databuffer, datasize)))
+ ret = -1;
+ else
+ ret = 0;
+
+ up(&aci_rds_sem);
+
+ return ret;
+}
+
+int __init attach_aci_rds(void)
+{
+ init_MUTEX(&aci_rds_sem);
+ return 0;
+}
+
+void __exit unload_aci_rds(void)
+{
+}
/*
* Local variables:
- * compile-command: "gcc -D__SMP__ -D__KERNEL__ -DMODULE -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -fno-strength-reduce -DMODVERSIONS -include ../../include/linux/modversions.h -c -o acenic.o acenic.c"
+ * compile-command: "gcc -D__KERNEL__ -DMODULE -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -fno-strength-reduce -DMODVERSIONS -include ../../include/linux/modversions.h -c -o acenic.o acenic.c"
* End:
*/
* Director, National Security Agency.
*
* This software may be used and distributed according to the terms
- * of the GNU Public License, incorporated herein by reference.
+ * of the GNU General Public License, incorporated herein by reference.
*/
-static const char *version =
- "ipddp.c:v0.01 8/28/97 Bradford W. Johnson <johns393@maroon.tc.umn.edu>\n";
-
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include "ipddp.h" /* Our stuff */
-static struct ipddp_route *ipddp_route_list = NULL;
+static const char version[] = KERN_INFO "ipddp.c:v0.01 8/28/97 Bradford W. Johnson <johns393@maroon.tc.umn.edu>\n";
+
+static struct ipddp_route *ipddp_route_list;
#ifdef CONFIG_IPDDP_ENCAP
static int ipddp_mode = IPDDP_ENCAP;
static int ipddp_mode = IPDDP_DECAP;
#endif
-/* Use 0 for production, 1 for verification, 2 for debug, 3 for verbose debug */
-#ifndef IPDDP_DEBUG
-#define IPDDP_DEBUG 1
-#endif
-static unsigned int ipddp_debug = IPDDP_DEBUG;
-
/* Index to functions, as function prototypes. */
static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev);
static struct net_device_stats *ipddp_get_stats(struct net_device *dev);
static int __init ipddp_init(struct net_device *dev)
{
- static unsigned version_printed = 0;
+ static unsigned version_printed;
SET_MODULE_OWNER(dev);
- if (ipddp_debug && version_printed++ == 0)
- printk("%s", version);
+ if (version_printed++ == 0)
+ printk(version);
/* Let the user now what mode we are in */
if(ipddp_mode == IPDDP_ENCAP)
static int ipddp_create(struct ipddp_route *new_rt)
{
struct ipddp_route *rt =(struct ipddp_route*) kmalloc(sizeof(*rt), GFP_KERNEL);
- struct ipddp_route *test;
- if(rt == NULL)
+ if (rt == NULL)
return -ENOMEM;
rt->ip = new_rt->ip;
rt->at = new_rt->at;
rt->next = NULL;
- rt->dev = atrtr_get_dev(&rt->at);
- if(rt->dev == NULL)
- {
- kfree(rt);
- return (-ENETUNREACH);
+ if ((rt->dev = atrtr_get_dev(&rt->at)) == NULL) {
+ kfree(rt);
+ return -ENETUNREACH;
}
- test = ipddp_find_route(rt);
- if(test != NULL)
- return (-EEXIST);
-
+ if (ipddp_find_route(rt)) {
+ kfree(rt);
+ return -EEXIST;
+ }
+
rt->next = ipddp_route_list;
ipddp_route_list = rt;
static void __exit ipddp_cleanup_module(void)
{
+ struct ipddp_route *p;
+
unregister_netdev(&dev_ipddp);
kfree(dev_ipddp.priv);
- memset(&dev_ipddp, 0, sizeof(dev_ipddp));
- dev_ipddp.init = ipddp_init;
+ while (ipddp_route_list) {
+ p = ipddp_route_list->next;
+ kfree(ipddp_route_list);
+ ipddp_route_list = p;
+ }
}
module_init(ipddp_init_module);
<mporter@eng.mcd.mot.com>
Remove double checking for DEBUG_RX in de4x5_dbg_rx()
from report by <geert@linux-m68k.org>
-
+ 0.546 22-Feb-01 Fixes Alpha XP1000 oops. The srom_search function
+ was causing a page fault when initializing the
+ variable 'pb', on a non de4x5 PCI device, in this
+ case a PCI bridge (DEC chip 21152). The value of
+ 'pb' is now only initialized if a de4x5 chip is
+ present.
+ <france@handhelds.org>
=========================================================================
*/
-static const char *version = "de4x5.c:V0.545 1999/11/28 davies@maniac.ultranet.com\n";
+static const char *version = "de4x5.c:V0.546 2001/02/22 davies@maniac.ultranet.com\n";
#include <linux/config.h>
#include <linux/module.h>
/* Skip the pci_bus list entry */
if (list_entry(walk, struct pci_bus, devices) == dev->bus) continue;
- pb = this_dev->bus->number;
vendor = this_dev->vendor;
device = this_dev->device << 8;
if (!(is_DC21040 || is_DC21041 || is_DC21140 || is_DC2114x)) continue;
/* Get the chip configuration revision register */
+ pb = this_dev->bus->number;
pcibios_read_config_dword(pb, this_dev->devfn, PCI_REVISION_ID, &cfrv);
/* Set the device number information */
}
skb = dev_alloc_skb(size+2);
- restore_flags(flags);
if (skb == NULL) {
printk("%s: Couldn't allocate a sk_buff of size %d.\n",
dev->name, size);
else { /* Yep! Go get it! */
skb_reserve(skb,2); /* Align */
skb->dev = dev;
- skb->used = 0;
/* skb->data points to the start of sk_buff data area */
buffer = skb_put(skb,size);
/* copy the packet into the buffer */
ManCode[5]='\0';
for (i=0;(*signatures[i] != '\0') && (*name == '\0');i++) {
- const char * volatile lhs = ManCode;
- const char * volatile rhs = signatures[i]; /* egcs-1.1.2 bug */
- if (strstr(lhs, rhs) != NULL) {
+ if (strstr(ManCode, signatures[i]) != NULL) {
strcpy(name,ManCode);
status = 1;
}
--- /dev/null
+/*
+ * Copyright 2000 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ * stevel@mvista.com or support@mvista.com
+ *
+ * ########################################################################
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ *
+ * Ethernet driver for the MIPS GT96100 Advanced Communication Controller.
+ *
+ */
+
+#ifndef __mips__
+#error This driver only works with MIPS architectures!
+#endif
+
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/errno.h>
+#include <linux/in.h>
+#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/delay.h>
+#include <asm/irq.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+
+#include "gt96100eth.h"
+
+#ifdef GT96100_DEBUG
+static int gt96100_debug = GT96100_DEBUG;
+#else
+static int gt96100_debug = 3;
+#endif
+
+// prototypes
+static void *dmaalloc(size_t size, dma_addr_t * dma_handle);
+static void dmafree(size_t size, void *vaddr);
+static int gt96100_add_hash_entry(struct net_device *dev,
+ unsigned char *addr);
+static void read_mib_counters(struct gt96100_private *gp);
+static int read_MII(struct net_device *dev, u32 reg);
+static int write_MII(struct net_device *dev, u32 reg, u16 data);
+static void dump_MII(struct net_device *dev);
+static void update_stats(struct gt96100_private *gp);
+static void abort(struct net_device *dev, u32 abort_bits);
+static void hard_stop(struct net_device *dev);
+static void enable_ether_irq(struct net_device *dev);
+static void disable_ether_irq(struct net_device *dev);
+static int __init gt96100_probe1(struct net_device *dev, long ioaddr,
+ int irq, int port_num);
+static int gt96100_init(struct net_device *dev);
+static int gt96100_open(struct net_device *dev);
+static int gt96100_close(struct net_device *dev);
+static int gt96100_tx(struct sk_buff *skb, struct net_device *dev);
+static int gt96100_rx(struct net_device *dev, u32 status);
+static void gt96100_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static void gt96100_tx_timeout(struct net_device *dev);
+static void gt96100_set_rx_mode(struct net_device *dev);
+static struct net_device_stats *gt96100_get_stats(struct net_device *dev);
+
+static char version[] __devinitdata =
+ "gt96100eth.c:0.1 stevel@mvista.com\n";
+
+// FIX! Need real Ethernet addresses
+static unsigned char gt96100_station_addr[2][6] __devinitdata =
+ { {0x01, 0x02, 0x03, 0x04, 0x05, 0x06},
+{0x01, 0x02, 0x03, 0x04, 0x05, 0x07}
+};
+
+#define nibswap(x) ((((x) >> 4) & 0x0f) | (((x) << 4) & 0xf0))
+
+#define RUN_AT(x) (jiffies + (x))
+
+// For reading/writing 32-bit words from/to DMA memory
+#define cpu_to_dma32 cpu_to_be32
+#define dma32_to_cpu be32_to_cpu
+
+/*
+ * Base address and interupt of the GT96100 ethernet controllers
+ */
+static struct {
+ unsigned int port;
+ int irq;
+} gt96100_iflist[NUM_INTERFACES] = {
+ {
+ GT96100_ETH0_BASE, GT96100_ETHER0_IRQ}, {
+ GT96100_ETH1_BASE, GT96100_ETHER1_IRQ}
+};
+
+/*
+ DMA memory allocation, derived from pci_alloc_consistent.
+*/
+static void *dmaalloc(size_t size, dma_addr_t * dma_handle)
+{
+ void *ret;
+
+ ret =
+ (void *) __get_free_pages(GFP_ATOMIC | GFP_DMA,
+ get_order(size));
+
+ if (ret != NULL) {
+ dma_cache_inv((unsigned long) ret, size);
+ if (dma_handle != NULL)
+ *dma_handle = virt_to_phys(ret);
+
+ /* bump virtual address up to non-cached area */
+ ret = KSEG1ADDR(ret);
+ }
+
+ return ret;
+}
+
+static void dmafree(size_t size, void *vaddr)
+{
+ vaddr = KSEG0ADDR(vaddr);
+ free_pages((unsigned long) vaddr, get_order(size));
+}
+
+
+static int read_MII(struct net_device *dev, u32 reg)
+{
+ struct gt96100_private *gp = (struct gt96100_private *) dev->priv;
+ int timedout = 20;
+ u32 smir = smirOpCode | (gp->phy_addr << smirPhyAdBit) |
+ (reg << smirRegAdBit);
+
+ // wait for last operation to complete
+ while (GT96100_READ(GT96100_ETH_SMI_REG) & smirBusy) {
+ // snooze for 1 msec and check again
+#if 0
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(10 * HZ / 10000);
+#else
+ mdelay(1);
+#endif
+
+ if (--timedout == 0) {
+ printk(KERN_ERR "%s: read_MII busy timeout!!\n",
+ dev->name);
+ return -1;
+ }
+ }
+
+ GT96100_WRITE(GT96100_ETH_SMI_REG, smir);
+
+ timedout = 20;
+ // wait for read to complete
+ while (!(smir = GT96100_READ(GT96100_ETH_SMI_REG) & smirReadValid)) {
+ // snooze for 1 msec and check again
+#if 0
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(10 * HZ / 10000);
+#else
+ mdelay(1);
+#endif
+
+ if (--timedout == 0) {
+ printk(KERN_ERR "%s: read_MII timeout!!\n",
+ dev->name);
+ return -1;
+ }
+ }
+
+ return (int) (smir & smirDataMask);
+}
+
+static int write_MII(struct net_device *dev, u32 reg, u16 data)
+{
+ struct gt96100_private *gp = (struct gt96100_private *) dev->priv;
+ int timedout = 20;
+ u32 smir =
+ (gp->phy_addr << smirPhyAdBit) | (reg << smirRegAdBit) | data;
+
+ // wait for last operation to complete
+ while (GT96100_READ(GT96100_ETH_SMI_REG) & smirBusy) {
+ // snooze for 1 msec and check again
+#if 0
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(10 * HZ / 10000);
+#else
+ mdelay(1);
+#endif
+
+ if (--timedout == 0) {
+ printk(KERN_ERR "%s: write_MII busy timeout!!\n",
+ dev->name);
+ return -1;
+ }
+ }
+
+ GT96100_WRITE(GT96100_ETH_SMI_REG, smir);
+ return 0;
+}
+
+
+static void dump_MII(struct net_device *dev)
+{
+ int i, val;
+
+ for (i = 0; i < 7; i++) {
+ if ((val = read_MII(dev, i)) >= 0)
+ printk("%s: MII Reg %d=%x\n", dev->name, i, val);
+ }
+ for (i = 16; i < 21; i++) {
+ if ((val = read_MII(dev, i)) >= 0)
+ printk("%s: MII Reg %d=%x\n", dev->name, i, val);
+ }
+}
+
+
+static int
+gt96100_add_hash_entry(struct net_device *dev, unsigned char *addr)
+{
+ struct gt96100_private *gp = (struct gt96100_private *) dev->priv;
+ u16 hashResult, stmp;
+ unsigned char ctmp, hash_ea[6];
+ u32 tblEntry, *tblEntryAddr;
+ int i;
+
+ for (i = 0; i < 6; i++) {
+ // nibble swap
+ ctmp = nibswap(addr[i]);
+ // invert every nibble
+ hash_ea[i] = ((ctmp & 1) << 3) | ((ctmp & 8) >> 3) |
+ ((ctmp & 2) << 1) | ((ctmp & 4) >> 1);
+ hash_ea[i] |= ((ctmp & 0x10) << 3) | ((ctmp & 0x80) >> 3) |
+ ((ctmp & 0x20) << 1) | ((ctmp & 0x40) >> 1);
+ }
+
+ if (gp->hash_mode == 0) {
+ hashResult = ((u16) hash_ea[0] & 0xfc) << 7;
+ stmp =
+ ((u16) hash_ea[0] & 0x03) | (((u16) hash_ea[1] & 0x7f)
+ << 2);
+ stmp ^=
+ (((u16) hash_ea[1] >> 7) & 0x01) | ((u16) hash_ea[2] <<
+ 1);
+ stmp ^= (u16) hash_ea[3] | (((u16) hash_ea[4] & 1) << 8);
+ hashResult |= stmp;
+ } else {
+ return -1; // don't support hash mode 1
+ }
+
+ tblEntryAddr =
+ (u32 *) (&gp->hash_table[((u32) hashResult & 0x7ff) << 3]);
+
+ for (i = 0; i < HASH_HOP_NUMBER; i++) {
+ if ((*tblEntryAddr & hteValid)
+ && !(*tblEntryAddr & hteSkip)) {
+ // This entry is already occupied, go to next entry
+ tblEntryAddr += 2;
+ } else {
+ memset(tblEntryAddr, 0, 8);
+ tblEntry = hteValid | hteRD;
+ tblEntry |= (u32) addr[5] << 3;
+ tblEntry |= (u32) addr[4] << 11;
+ tblEntry |= (u32) addr[3] << 19;
+ tblEntry |= ((u32) addr[2] & 0x1f) << 27;
+ *(tblEntryAddr + 1) = cpu_to_dma32(tblEntry);
+ tblEntry = ((u32) addr[2] >> 5) & 0x07;
+ tblEntry |= (u32) addr[1] << 3;
+ tblEntry |= (u32) addr[0] << 11;
+ *tblEntryAddr = cpu_to_dma32(tblEntry);
+ break;
+ }
+ }
+
+ if (i >= HASH_HOP_NUMBER) {
+ printk(KERN_ERR "%s: gt96100_add_hash_entry expired!\n",
+ dev->name);
+ return -1; // Couldn't find an unused entry
+ }
+
+ return 0;
+}
+
+
+static void read_mib_counters(struct gt96100_private *gp)
+{
+ u32 *mib_regs = (u32 *) & gp->mib;
+ int i;
+
+ for (i = 0; i < sizeof(mib_counters_t) / sizeof(u32); i++)
+ mib_regs[i] =
+ GT96100ETH_READ(gp,
+ GT96100_ETH_MIB_COUNT_BASE +
+ i * sizeof(u32));
+}
+
+
+static void update_stats(struct gt96100_private *gp)
+{
+ mib_counters_t *mib = &gp->mib;
+ struct net_device_stats *stats = &gp->stats;
+
+ read_mib_counters(gp);
+
+ stats->rx_packets = mib->totalFramesReceived;
+ stats->tx_packets = mib->framesSent;
+ stats->rx_bytes = mib->totalByteReceived;
+ stats->tx_bytes = mib->byteSent;
+ stats->rx_errors = mib->totalFramesReceived - mib->framesReceived;
+ //the tx error counters are incremented by the ISR
+ //rx_dropped incremented by gt96100_rx
+ //tx_dropped incremented by gt96100_tx
+ stats->multicast = mib->multicastFramesReceived;
+ // Tx collisions incremented by ISR, so add in MIB Rx collisions
+ stats->collisions += mib->collision + mib->lateCollision;
+ stats->rx_length_errors = mib->oversizeFrames + mib->fragments;
+ // The RxError condition means the Rx DMA encountered a
+ // CPU owned descriptor, which, if things are working as
+ // they should, means the Rx ring has overflowed.
+ stats->rx_over_errors = mib->macRxError;
+ stats->rx_crc_errors = mib->cRCError;
+}
+
+static void abort(struct net_device *dev, u32 abort_bits)
+{
+ struct gt96100_private *gp = (struct gt96100_private *) dev->priv;
+ int timedout = 100; // wait up to 100 msec for hard stop to complete
+
+ if (gt96100_debug > 2)
+ printk(KERN_INFO "%s: abort\n", dev->name);
+
+ // Return if neither Rx or Tx abort bits are set
+ if (!(abort_bits & (sdcmrAR | sdcmrAT)))
+ return;
+
+ // make sure only the Rx/Tx abort bits are set
+ abort_bits &= (sdcmrAR | sdcmrAT);
+
+ spin_lock(&gp->lock);
+
+ // abort any Rx/Tx DMA immediately
+ GT96100ETH_WRITE(gp, GT96100_ETH_SDMA_COMM, abort_bits);
+
+ if (gt96100_debug > 2)
+ printk(KERN_INFO "%s: abort: SDMA comm = %x\n",
+ dev->name, GT96100ETH_READ(gp,
+ GT96100_ETH_SDMA_COMM));
+
+ // wait for abort to complete
+ while (GT96100ETH_READ(gp, GT96100_ETH_SDMA_COMM) & abort_bits) {
+ // snooze for 20 msec and check again
+#if 0
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(10 * HZ / 10000);
+#else
+ mdelay(1);
+#endif
+
+ if (--timedout == 0) {
+ printk(KERN_ERR "%s: abort timeout!!\n",
+ dev->name);
+ break;
+ }
+ }
+
+ if (gt96100_debug > 2)
+ printk(KERN_INFO "%s: abort: timedout=%d\n", dev->name,
+ timedout);
+
+ spin_unlock(&gp->lock);
+}
+
+
+static void hard_stop(struct net_device *dev)
+{
+ struct gt96100_private *gp = (struct gt96100_private *) dev->priv;
+
+ if (gt96100_debug > 2)
+ printk(KERN_INFO "%s: hard stop\n", dev->name);
+
+ disable_ether_irq(dev);
+
+ abort(dev, sdcmrAR | sdcmrAT);
+
+ // disable port
+ GT96100ETH_WRITE(gp, GT96100_ETH_PORT_CONFIG, 0);
+}
+
+
+static void enable_ether_irq(struct net_device *dev)
+{
+ struct gt96100_private *gp = (struct gt96100_private *) dev->priv;
+ u32 intMask;
+
+ // unmask interrupts
+ GT96100ETH_WRITE(gp, GT96100_ETH_INT_MASK,
+ icrRxBuffer | icrTxBufferLow | icrTxEndLow |
+ icrRxError | icrTxErrorLow | icrRxOVR |
+ icrTxUdr | icrRxBufferQ0 | icrRxErrorQ0 |
+ icrMIIPhySTC);
+
+ // now route ethernet interrupts to GT Int0 (eth0 and eth1 will be
+ // sharing it).
+ // FIX! The kernel's irq code should do this
+ intMask = GT96100_READ(GT96100_INT0_HIGH_MASK);
+ intMask |= 1 << gp->port_num;
+ GT96100_WRITE(GT96100_INT0_HIGH_MASK, intMask);
+}
+
+static void disable_ether_irq(struct net_device *dev)
+{
+ struct gt96100_private *gp = (struct gt96100_private *) dev->priv;
+ u32 intMask;
+
+ // FIX! The kernel's irq code should do this
+ intMask = GT96100_READ(GT96100_INT0_HIGH_MASK);
+ intMask &= ~(1 << gp->port_num);
+ GT96100_WRITE(GT96100_INT0_HIGH_MASK, intMask);
+
+ GT96100ETH_WRITE(gp, GT96100_ETH_INT_MASK, 0);
+}
+
+
+/*
+ * Probe for a GT96100 ethernet controller.
+ */
+int __init gt96100_probe(struct net_device *dev)
+{
+ unsigned int base_addr = dev ? dev->base_addr : 0;
+ int i;
+
+#ifndef CONFIG_MIPS_GT96100ETH
+ return -ENODEV;
+#endif
+
+ if (gt96100_debug > 2)
+ printk(KERN_INFO "%s: gt96100_probe\n", dev->name);
+
+ if (base_addr >= KSEG0) /* Check a single specified location. */
+ return gt96100_probe1(dev, base_addr, dev->irq, 0);
+ else if (base_addr != 0) /* Don't probe at all. */
+ return -ENXIO;
+
+// for (i = 0; i<NUM_INTERFACES; i++) {
+ for (i = NUM_INTERFACES - 1; i >= 0; i--) {
+ int base_addr = gt96100_iflist[i].port;
+#if 0
+ if (check_region(base_addr, GT96100_ETH_IO_SIZE)) {
+ printk(KERN_ERR
+ "%s: gt96100_probe: ioaddr 0x%lx taken?\n",
+ dev->name, base_addr);
+ continue;
+ }
+#endif
+ if (gt96100_probe1
+ (dev, base_addr, gt96100_iflist[i].irq, i) == 0)
+ return 0;
+ }
+ return -ENODEV;
+}
+
+
+
+static int __init
+gt96100_probe1(struct net_device *dev, long ioaddr, int irq, int port_num)
+{
+ static unsigned version_printed = 0;
+ struct gt96100_private *gp = NULL;
+ int i, retval;
+ u32 cpuConfig;
+
+ // FIX! probe for GT96100 by reading a suitable register
+
+ if (gt96100_debug > 2)
+ printk(KERN_INFO "gt96100_probe1: ioaddr 0x%lx, irq %d\n",
+ ioaddr, irq);
+
+ request_region(ioaddr, GT96100_ETH_IO_SIZE, "GT96100ETH");
+
+ cpuConfig = GT96100_READ(GT96100_CPU_INTERF_CONFIG);
+ if (cpuConfig & (1 << 12)) {
+ printk(KERN_ERR
+ "gt96100_probe1: must be in Big Endian mode!\n");
+ retval = -ENODEV;
+ goto free_region;
+ }
+
+ if (gt96100_debug > 2)
+ printk(KERN_INFO
+ "gt96100_probe1: chip in Big Endian mode - cool\n");
+
+ /* Allocate a new 'dev' if needed. */
+ if (dev == NULL)
+ dev = init_etherdev(0, sizeof(struct gt96100_private));
+
+ if (gt96100_debug && version_printed++ == 0)
+ printk(version);
+
+ if (irq < 0) {
+ printk(KERN_ERR
+ "gt96100_probe1: irq unknown - probing not supported\n");
+ retval = -ENODEV;
+ goto free_region;
+ }
+
+ printk(KERN_INFO "%s: GT-96100 ethernet found at 0x%lx, irq %d\n",
+ dev->name, ioaddr, irq);
+
+ /* private struct aligned and zeroed by init_etherdev */
+ /* Fill in the 'dev' fields. */
+ dev->base_addr = ioaddr;
+ dev->irq = irq;
+ memcpy(dev->dev_addr, gt96100_station_addr[port_num],
+ sizeof(dev->dev_addr));
+
+ printk(KERN_INFO "%s: HW Address ", dev->name);
+ for (i = 0; i < sizeof(dev->dev_addr); i++) {
+ printk("%2.2x", dev->dev_addr[i]);
+ printk(i < 5 ? ":" : "\n");
+ }
+
+ /* Initialize our private structure. */
+ if (dev->priv == NULL) {
+
+ gp =
+ (struct gt96100_private *) kmalloc(sizeof(*gp),
+ GFP_KERNEL);
+ if (gp == NULL) {
+ retval = -ENOMEM;
+ goto free_region;
+ }
+
+ dev->priv = gp;
+ }
+
+ gp = dev->priv;
+
+ memset(gp, 0, sizeof(*gp)); // clear it
+
+ gp->port_num = port_num;
+ gp->io_size = GT96100_ETH_IO_SIZE;
+ gp->port_offset = port_num * GT96100_ETH_IO_SIZE;
+ gp->phy_addr = port_num + 1;
+
+ if (gt96100_debug > 2)
+ printk(KERN_INFO "%s: gt96100_probe1, port %d\n",
+ dev->name, gp->port_num);
+
+ // Allocate Rx and Tx descriptor rings
+ if (gp->rx_ring == NULL) {
+ // All descriptors in ring must be 16-byte aligned
+ gp->rx_ring = dmaalloc(sizeof(gt96100_rd_t) * RX_RING_SIZE
+ +
+ sizeof(gt96100_td_t) * TX_RING_SIZE,
+ &gp->rx_ring_dma);
+ if (gp->rx_ring == NULL) {
+ retval = -ENOMEM;
+ goto free_region;
+ }
+
+ gp->tx_ring =
+ (gt96100_td_t *) (gp->rx_ring + RX_RING_SIZE);
+ gp->tx_ring_dma =
+ gp->rx_ring_dma + sizeof(gt96100_rd_t) * RX_RING_SIZE;
+ }
+
+ if (gt96100_debug > 2)
+ printk(KERN_INFO
+ "%s: gt96100_probe1, rx_ring=%p, tx_ring=%p\n",
+ dev->name, gp->rx_ring, gp->tx_ring);
+
+ // Allocate Rx Hash Table
+ if (gp->hash_table == NULL) {
+ gp->hash_table = (char *) dmaalloc(RX_HASH_TABLE_SIZE,
+ &gp->hash_table_dma);
+ if (gp->hash_table == NULL) {
+ dmafree(sizeof(gt96100_rd_t) * RX_RING_SIZE
+ + sizeof(gt96100_td_t) * TX_RING_SIZE,
+ gp->rx_ring);
+ retval = -ENOMEM;
+ goto free_region;
+ }
+ }
+
+ if (gt96100_debug > 2)
+ printk(KERN_INFO "%s: gt96100_probe1, hash=%p\n",
+ dev->name, gp->hash_table);
+
+ spin_lock_init(&gp->lock);
+
+ dev->open = gt96100_open;
+ dev->hard_start_xmit = gt96100_tx;
+ dev->stop = gt96100_close;
+ dev->get_stats = gt96100_get_stats;
+ //dev->do_ioctl = gt96100_ioctl;
+ dev->set_multicast_list = gt96100_set_rx_mode;
+ dev->tx_timeout = gt96100_tx_timeout;
+ dev->watchdog_timeo = GT96100ETH_TX_TIMEOUT;
+
+ /* Fill in the fields of the device structure with ethernet values. */
+ ether_setup(dev);
+ return 0;
+
+ free_region:
+ release_region(ioaddr, gp->io_size);
+ unregister_netdev(dev);
+ if (dev->priv != NULL)
+ kfree(dev->priv);
+ kfree(dev);
+ printk(KERN_ERR "%s: gt96100_probe1 failed. Returns %d\n",
+ dev->name, retval);
+ return retval;
+}
+
+
+static int gt96100_init(struct net_device *dev)
+{
+ struct gt96100_private *gp = (struct gt96100_private *) dev->priv;
+ unsigned long flags;
+ u32 phyAD, ciu;
+ int i;
+
+ if (gt96100_debug > 2)
+ printk("%s: gt96100_init: dev=%p\n", dev->name, dev);
+
+ // Stop and disable Port
+ hard_stop(dev);
+
+ spin_lock_irqsave(&gp->lock, flags);
+
+ // First things first, set-up hash table
+ memset(gp->hash_table, 0, RX_HASH_TABLE_SIZE); // clear it
+ gp->hash_mode = 0;
+ // Add a single entry to hash table - our ethernet address
+ gt96100_add_hash_entry(dev, dev->dev_addr);
+ // Set-up DMA ptr to hash table
+ GT96100ETH_WRITE(gp, GT96100_ETH_HASH_TBL_PTR, gp->hash_table_dma);
+ if (gt96100_debug > 2)
+ printk("%s: gt96100_init: Hash Tbl Ptr=%x\n", dev->name,
+ GT96100ETH_READ(gp, GT96100_ETH_HASH_TBL_PTR));
+
+ // Setup Tx descriptor ring
+ for (i = 0; i < TX_RING_SIZE; i++) {
+ gp->tx_ring[i].cmdstat = 0; // CPU owns
+ gp->tx_ring[i].byte_cnt = 0;
+ gp->tx_ring[i].buff_ptr = 0;
+ gp->tx_ring[i].next =
+ cpu_to_dma32(gp->tx_ring_dma +
+ sizeof(gt96100_td_t) * (i + 1));
+ }
+ /* Wrap the ring. */
+ gp->tx_ring[i - 1].next = cpu_to_dma32(gp->tx_ring_dma);
+
+ // setup only the lowest priority TxCDP reg
+ GT96100ETH_WRITE(gp, GT96100_ETH_CURR_TX_DESC_PTR0,
+ gp->tx_ring_dma);
+ GT96100ETH_WRITE(gp, GT96100_ETH_CURR_TX_DESC_PTR1, 0);
+ if (gt96100_debug > 2)
+ printk("%s: gt96100_init: Curr Tx Desc Ptr0=%x\n",
+ dev->name, GT96100ETH_READ(gp,
+ GT96100_ETH_CURR_TX_DESC_PTR0));
+
+ // Setup Rx descriptor ring
+ for (i = 0; i < RX_RING_SIZE; i++) {
+ dma_addr_t rx_buff_dma;
+ gp->rx_ring[i].next =
+ cpu_to_dma32(gp->rx_ring_dma +
+ sizeof(gt96100_rd_t) * (i + 1));
+ if (gp->rx_buff[i] == NULL)
+ gp->rx_buff[i] =
+ dmaalloc(PKT_BUF_SZ, &rx_buff_dma);
+ else
+ rx_buff_dma = virt_to_phys(gp->rx_buff[i]);
+ if (gp->rx_buff[i] == NULL)
+ break;
+ gp->rx_ring[i].buff_ptr = cpu_to_dma32(rx_buff_dma);
+ gp->rx_ring[i].buff_cnt_sz =
+ cpu_to_dma32(PKT_BUF_SZ << rdBuffSzBit);
+ // Give ownership to device, enable interrupt
+ gp->rx_ring[i].cmdstat =
+ cpu_to_dma32((u32) (rxOwn | rxEI));
+ }
+
+ if (i != RX_RING_SIZE) {
+ int j;
+ for (j = 0; j < RX_RING_SIZE; j++) {
+ if (gp->rx_buff[j]) {
+ dmafree(PKT_BUF_SZ, gp->rx_buff[j]);
+ gp->rx_buff[j] = NULL;
+ }
+ }
+ printk(KERN_ERR "%s: Rx ring allocation failed.\n",
+ dev->name);
+ spin_unlock_irqrestore(&gp->lock, flags);
+ return -ENOMEM;
+ }
+
+ /* Wrap the ring. */
+ gp->rx_ring[i - 1].next = cpu_to_dma32(gp->rx_ring_dma);
+
+ // Set our MII PHY device address
+ phyAD = GT96100_READ(GT96100_ETH_PHY_ADDR_REG);
+ phyAD &= ~(0x1f << (gp->port_num * 5));
+ phyAD |= gp->phy_addr << (gp->port_num * 5);
+ GT96100_WRITE(GT96100_ETH_PHY_ADDR_REG, phyAD);
+
+ if (gt96100_debug > 2)
+ printk("%s: gt96100_init: PhyAD=%x\n", dev->name,
+ GT96100_READ(GT96100_ETH_PHY_ADDR_REG));
+
+ // Clear all the RxFDP and RXCDP regs...
+ for (i = 0; i < 4; i++) {
+ GT96100ETH_WRITE(gp, GT96100_ETH_1ST_RX_DESC_PTR0 + i * 4,
+ 0);
+ GT96100ETH_WRITE(gp, GT96100_ETH_CURR_RX_DESC_PTR0 + i * 4,
+ 0);
+ }
+ // and setup only the lowest priority RxFDP and RxCDP regs
+ GT96100ETH_WRITE(gp, GT96100_ETH_1ST_RX_DESC_PTR0,
+ gp->rx_ring_dma);
+ GT96100ETH_WRITE(gp, GT96100_ETH_CURR_RX_DESC_PTR0,
+ gp->rx_ring_dma);
+ if (gt96100_debug > 2)
+ printk("%s: gt96100_init: 1st/Curr Rx Desc Ptr0=%x/%x\n",
+ dev->name, GT96100ETH_READ(gp,
+ GT96100_ETH_1ST_RX_DESC_PTR0),
+ GT96100ETH_READ(gp, GT96100_ETH_CURR_RX_DESC_PTR0));
+
+ // init Rx/Tx indeces and pkt counters
+ gp->rx_next_out = gp->tx_next_in = gp->tx_next_out = 0;
+ gp->tx_count = 0;
+
+ // setup DMA
+
+ // FIX! this should be done by Kernel setup code
+ ciu = GT96100_READ(GT96100_CIU_ARBITER_CONFIG);
+ ciu |= (0x0c << (gp->port_num * 2)); // set Ether DMA req priority to high
+ // FIX! setting the following bit causes the EV96100 board to hang!!!
+ //ciu |= (1 << (24+gp->port_num)); // pull Ethernet port out of Reset???
+ // FIX! endian mode???
+ ciu &= ~(1 << 31); // set desc endianess to Big
+ GT96100_WRITE(GT96100_CIU_ARBITER_CONFIG, ciu);
+ if (gt96100_debug > 2)
+ printk("%s: gt96100_init: CIU Config=%x/%x\n", dev->name,
+ ciu, GT96100_READ(GT96100_CIU_ARBITER_CONFIG));
+
+ // We want the Rx/Tx DMA to write/read data to/from memory in
+ // Big Endian mode. Also set DMA Burst Size to 8 64Bit words.
+ // FIX! endian mode???
+ GT96100ETH_WRITE(gp, GT96100_ETH_SDMA_CONFIG,
+ //sdcrBLMR | sdcrBLMT |
+ (0xf << sdcrRCBit) | sdcrRIFB | (3 << sdcrBSZBit));
+ if (gt96100_debug > 2)
+ printk("%s: gt96100_init: SDMA Config=%x\n", dev->name,
+ GT96100ETH_READ(gp, GT96100_ETH_SDMA_CONFIG));
+
+ // start Rx DMA
+ GT96100ETH_WRITE(gp, GT96100_ETH_SDMA_COMM, sdcmrERD);
+ if (gt96100_debug > 2)
+ printk("%s: gt96100_init: SDMA Comm=%x\n", dev->name,
+ GT96100ETH_READ(gp, GT96100_ETH_SDMA_COMM));
+
+ // enable interrupts
+ enable_ether_irq(dev);
+
+ /*
+ * Disable all Type-of-Service queueing. All Rx packets will be
+ * treated normally and will be sent to the lowest priority
+ * queue.
+ *
+ * Disable flow-control for now. FIX! support flow control?
+ */
+ // clear all the MIB ctr regs
+ // Enable reg clear on read. FIX! desc of this bit is inconsistent
+ // in the GT-96100A datasheet.
+ GT96100ETH_WRITE(gp, GT96100_ETH_PORT_CONFIG_EXT,
+ pcxrFCTL | pcxrFCTLen | pcxrFLP);
+ read_mib_counters(gp);
+ GT96100ETH_WRITE(gp, GT96100_ETH_PORT_CONFIG_EXT,
+ pcxrFCTL | pcxrFCTLen | pcxrFLP | pcxrMIBclrMode);
+
+ if (gt96100_debug > 2)
+ printk("%s: gt96100_init: Port Config Ext=%x\n", dev->name,
+ GT96100ETH_READ(gp, GT96100_ETH_PORT_CONFIG_EXT));
+
+ // enable this port (set hash size to 1/2K)
+ GT96100ETH_WRITE(gp, GT96100_ETH_PORT_CONFIG, pcrEN | pcrHS);
+ if (gt96100_debug > 2)
+ printk("%s: gt96100_init: Port Config=%x\n", dev->name,
+ GT96100ETH_READ(gp, GT96100_ETH_PORT_CONFIG));
+
+ // we should now be receiving frames
+ if (gt96100_debug > 2)
+ dump_MII(dev);
+
+ spin_unlock_irqrestore(&gp->lock, flags);
+ return 0;
+}
+
+
+static int gt96100_open(struct net_device *dev)
+{
+ int retval;
+
+ MOD_INC_USE_COUNT;
+
+ if (gt96100_debug > 2)
+ printk("%s: gt96100_open: dev=%p\n", dev->name, dev);
+
+ if ((retval = request_irq(dev->irq, >96100_interrupt,
+ SA_SHIRQ, dev->name, dev))) {
+ printk(KERN_ERR "%s: unable to get IRQ %d\n", dev->name,
+ dev->irq);
+ MOD_DEC_USE_COUNT;
+ return retval;
+ }
+ // Initialize and startup the GT-96100 ethernet port
+ if ((retval = gt96100_init(dev))) {
+ printk(KERN_ERR "%s: error in gt96100_init\n", dev->name);
+ free_irq(dev->irq, dev);
+ MOD_DEC_USE_COUNT;
+ return retval;
+ }
+
+ netif_start_queue(dev);
+
+ if (gt96100_debug > 2)
+ printk("%s: gt96100_open: Initialization done.\n",
+ dev->name);
+
+ return 0;
+}
+
+static int gt96100_close(struct net_device *dev)
+{
+ struct gt96100_private *gp = (struct gt96100_private *) dev->priv;
+ int i;
+
+ if (gt96100_debug > 2)
+ printk("%s: gt96100_close: dev=%p\n", dev->name, dev);
+
+ // stop the device
+ if (netif_device_present(dev)) {
+ netif_stop_queue(dev);
+ hard_stop(dev);
+ }
+ // free the Rx DMA buffers
+ for (i = 0; i < RX_RING_SIZE; i++) {
+ if (gp->rx_buff[i]) {
+ dmafree(PKT_BUF_SZ, gp->rx_buff[i]);
+ gp->rx_buff[i] = NULL;
+ }
+ }
+
+ free_irq(dev->irq, dev);
+
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+
+static int gt96100_tx(struct sk_buff *skb, struct net_device *dev)
+{
+ struct gt96100_private *gp = (struct gt96100_private *) dev->priv;
+ unsigned long flags;
+ int nextIn;
+
+ if (gt96100_debug > 2)
+ printk("%s: gt96100_tx: skb->len=%d, skb->data=%p\n",
+ dev->name, skb->len, skb->data);
+
+ spin_lock_irqsave(&gp->lock, flags);
+
+ if (gp->tx_count >= TX_RING_SIZE) {
+ printk(KERN_WARNING
+ "%s: Tx Ring full, refusing to send buffer.\n",
+ dev->name);
+ gp->stats.tx_dropped++;
+ spin_unlock_irqrestore(&gp->lock, flags);
+ return 1;
+ }
+ // Prepare the Descriptor at tx_next_in
+ nextIn = gp->tx_next_in;
+
+ if (dma32_to_cpu(gp->tx_ring[nextIn].cmdstat) & txOwn) {
+ printk(KERN_ERR "%s: gt96100_tx: TxOwn bit wrong!!\n",
+ dev->name);
+ }
+
+ gp->tx_skbuff[nextIn] = skb;
+ gp->tx_ring[nextIn].byte_cnt =
+ cpu_to_dma32(skb->len << tdByteCntBit);
+ gp->tx_ring[nextIn].buff_ptr =
+ cpu_to_dma32(virt_to_phys(skb->data));
+ // Give ownership to device, set first and last desc, enable interrupt
+ // Setting of ownership bit must be *last*!
+ gp->tx_ring[nextIn].cmdstat =
+ cpu_to_dma32((u32) (txOwn | txEI | txFirst | txLast));
+
+ // increment tx_next_in with wrap
+ gp->tx_next_in = (nextIn + 1) % TX_RING_SIZE;
+ // If count is zero, DMA should be stopped, so restart
+ if (gp->tx_count == 0) {
+ if (GT96100ETH_READ(gp, GT96100_ETH_PORT_STATUS) &
+ psrTxLow) printk(KERN_WARNING
+ "%s: Tx count zero but Tx queue running!\n",
+ dev->name);
+ GT96100ETH_WRITE(gp, GT96100_ETH_SDMA_COMM,
+ sdcmrERD | sdcmrTXDL);
+ }
+ // increment count and stop queue if full
+ if (++gp->tx_count == TX_RING_SIZE)
+ netif_stop_queue(dev);
+
+ dev->trans_start = jiffies;
+ spin_unlock_irqrestore(&gp->lock, flags);
+
+ return 0;
+}
+
+
+static int gt96100_rx(struct net_device *dev, u32 status)
+{
+ struct gt96100_private *gp = (struct gt96100_private *) dev->priv;
+ struct sk_buff *skb;
+ int pkt_len, nextOut;
+ gt96100_rd_t *rd;
+ u32 cmdstat;
+
+ if (gt96100_debug > 2)
+ printk("%s: gt96100_rx: dev=%p, status = %x\n",
+ dev->name, dev, status);
+
+ // Continue until we reach the current descriptor pointer
+ for (nextOut = gp->rx_next_out;
+ nextOut !=
+ (GT96100ETH_READ(gp, GT96100_ETH_CURR_RX_DESC_PTR0) -
+ gp->rx_ring_dma) / sizeof(gt96100_rd_t);
+ nextOut = (nextOut + 1) % RX_RING_SIZE) {
+
+ rd = &gp->rx_ring[nextOut];
+ cmdstat = dma32_to_cpu(rd->cmdstat);
+
+ if (cmdstat & (u32) rxOwn) {
+ cmdstat &= ~((u32) rxOwn);
+ rd->cmdstat = cpu_to_dma32(cmdstat);
+ printk(KERN_ERR
+ "%s: gt96100_rx: ownership bit wrong!\n",
+ dev->name);
+ }
+ // must be first and last (ie only) buffer of packet
+ if (!(cmdstat & (u32) rxFirst)
+ || !(cmdstat & (u32) rxLast)) {
+ printk(KERN_ERR
+ "%s: gt96100_rx: desc not first and last!\n",
+ dev->name);
+ continue;
+ }
+ // drop this received pkt if there were any errors
+ if ((cmdstat & (u32) rxErrorSummary)
+ || (status & icrRxErrorQ0)) {
+ // update the detailed rx error counters that are not covered
+ // by the MIB counters.
+ if (cmdstat & (u32) rxOverrun)
+ gp->stats.rx_fifo_errors++;
+ continue;
+ }
+
+ pkt_len = dma32_to_cpu(rd->buff_cnt_sz) & rdByteCntMask;
+
+ /* Create new skb. */
+ skb = dev_alloc_skb(pkt_len + 2);
+ if (skb == NULL) {
+ printk(KERN_ERR
+ "%s: Memory squeeze, dropping packet.\n",
+ dev->name);
+ gp->stats.rx_dropped++;
+ continue;
+ }
+ skb->dev = dev;
+ skb_reserve(skb, 2); /* 16 byte IP header align */
+ skb_put(skb, pkt_len); /* Make room */
+ eth_copy_and_sum(skb, gp->rx_buff[nextOut], pkt_len, 0);
+ skb->protocol = eth_type_trans(skb, dev);
+ netif_rx(skb); /* pass the packet to upper layers */
+
+ // now we can release ownership of this desc back to device
+ cmdstat |= (u32) rxOwn;
+ rd->cmdstat = cpu_to_dma32(cmdstat);
+
+ dev->last_rx = jiffies;
+ }
+
+ gp->rx_next_out = nextOut;
+ return 0;
+}
+
+
+static void gt96100_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct net_device *dev = (struct net_device *) dev_id;
+ struct gt96100_private *gp = (struct gt96100_private *) dev->priv;
+ u32 status;
+
+ if (dev == NULL) {
+ printk(KERN_ERR "%s: isr: null dev ptr\n", dev->name);
+ return;
+ }
+
+ status = GT96100ETH_READ(gp, GT96100_ETH_INT_CAUSE);
+ // ACK interrupts
+#if 0
+ GT96100ETH_CLRBIT(gp, GT96100_ETH_INT_CAUSE,
+ icrEtherIntSum | icrRxBufferQ1 | icrRxBufferQ2 |
+ icrRxBufferQ3 | icrRxBufferQ0 | icrTxBufferHigh |
+ icrTxEndHigh | icrTxBufferLow | icrTxEndLow |
+ icrTxErrorHigh | icrTxErrorLow | icrTxUdr);
+#else
+ GT96100ETH_WRITE(gp, GT96100_ETH_INT_CAUSE, 0);
+#endif
+
+ if ((status & icrEtherIntSum) == 0) {
+ // not our interrupt
+ //printk("%s: isr: no ints? icr=%x,cp0_cause=%x\n",
+ // dev->name, status, read_32bit_cp0_register(CP0_CAUSE));
+ return;
+ }
+
+ if (gt96100_debug > 3)
+ printk("%s: isr: entry, icr=%x\n", dev->name, status);
+
+ if (status & (icrRxBufferQ1 | icrRxBufferQ2 | icrRxBufferQ3)) {
+ printk(KERN_ERR "%s: isr: Rx intr in unused queues!?\n",
+ dev->name);
+ }
+
+ if (status & icrRxBufferQ0) {
+ gt96100_rx(dev, status);
+ }
+
+ if (status & (icrTxBufferHigh | icrTxEndHigh)) {
+ printk(KERN_ERR "%s: isr: Tx intr in unused queue!?\n",
+ dev->name);
+ }
+
+ if (status & icrMIIPhySTC) {
+ u32 psr = GT96100ETH_READ(gp, GT96100_ETH_PORT_STATUS);
+ printk("%s: port status:\n", dev->name);
+ printk
+ ("%s: %s MBit/s, %s-duplex, flow-control %s, link is %s,\n",
+ dev->name, psr & psrSpeed ? "100" : "10",
+ psr & psrDuplex ? "full" : "half",
+ psr & psrFctl ? "disabled" : "enabled",
+ psr & psrLink ? "up" : "down");
+ printk
+ ("%s: TxLowQ is %s, TxHighQ is %s, Transmitter is %s\n",
+ dev->name, psr & psrTxLow ? "running" : "stopped",
+ psr & psrTxHigh ? "running" : "stopped",
+ psr & psrTxInProg ? "on" : "off");
+ gp->last_psr = psr;
+ }
+
+ if (status & (icrTxBufferLow | icrTxEndLow)) {
+ int nextOut;
+ gt96100_td_t *td;
+ u32 cmdstat;
+
+ // Continue until we reach the current descriptor pointer
+ for (nextOut = gp->tx_next_out;
+ nextOut !=
+ (GT96100ETH_READ(gp, GT96100_ETH_CURR_TX_DESC_PTR0) -
+ gp->tx_ring_dma) / sizeof(gt96100_td_t);
+ nextOut = (nextOut + 1) % TX_RING_SIZE) {
+
+ td = &gp->tx_ring[nextOut];
+ cmdstat = dma32_to_cpu(td->cmdstat);
+
+ if (gt96100_debug > 2)
+ printk("%s: isr: Tx desc cmdstat=%x\n",
+ dev->name, cmdstat);
+
+ if (cmdstat & (u32) txOwn) {
+ cmdstat &= ~((u32) txOwn);
+ td->cmdstat = cpu_to_dma32(cmdstat);
+ printk(KERN_ERR
+ "%s: isr: Tx ownership bit wrong!\n",
+ dev->name);
+ }
+ // increment Tx error stats
+ if (cmdstat & (u32) txErrorSummary) {
+ if (gt96100_debug > 2)
+ printk
+ ("%s: gt96100_interrupt: Tx error, cmdstat = %x\n",
+ dev->name, cmdstat);
+ gp->stats.tx_errors++;
+ if (cmdstat & (u32) txReTxLimit)
+ gp->stats.collisions++;
+ if (cmdstat & (u32) txUnderrun)
+ gp->stats.tx_fifo_errors++;
+ if (cmdstat & (u32) txLateCollision)
+ gp->stats.tx_window_errors++;
+ }
+ // Wake the queue if the ring was full
+ if (gp->tx_count == TX_RING_SIZE)
+ netif_wake_queue(dev);
+
+ // decrement tx ring buffer count
+ if (gp->tx_count)
+ gp->tx_count--;
+
+ // free the skb
+ if (gp->tx_skbuff[nextOut]) {
+ if (gt96100_debug > 2)
+ printk
+ ("%s: isr: good Tx, skb=%p\n",
+ dev->name,
+ gp->tx_skbuff[nextOut]);
+ dev_kfree_skb_irq(gp->tx_skbuff[nextOut]);
+ gp->tx_skbuff[nextOut] = NULL;
+ } else {
+ printk(KERN_ERR "%s: isr: no skb!\n",
+ dev->name);
+ }
+ }
+
+ if (gp->tx_count == 0 && nextOut != gp->tx_next_in) {
+ // FIX! this should probably be a panic
+ printk(KERN_ERR
+ "%s: isr: warning! Tx queue inconsistent\n",
+ dev->name);
+ }
+
+ gp->tx_next_out = nextOut;
+
+ if ((status & icrTxEndLow) && gp->tx_count != 0) {
+ // we must restart the DMA
+ if (gt96100_debug > 2)
+ printk("%s: isr: Restarting Tx DMA\n",
+ dev->name);
+ GT96100ETH_WRITE(gp, GT96100_ETH_SDMA_COMM,
+ sdcmrERD | sdcmrTXDL);
+ }
+ }
+ // Now check TX errors (RX errors were handled in gt96100_rx)
+
+ if (status & icrTxErrorHigh) {
+ printk(KERN_ERR
+ "%s: isr: Tx resource error in unused queue!?\n",
+ dev->name);
+ }
+
+ if (status & icrTxErrorLow) {
+ printk(KERN_ERR "%s: isr: Tx resource error\n", dev->name);
+ }
+
+ if (status & icrTxUdr) {
+ printk(KERN_ERR "%s: isr: Tx underrun error\n", dev->name);
+ }
+
+ if (gt96100_debug > 3)
+ printk("%s: isr: exit, icr=%x\n",
+ dev->name, GT96100ETH_READ(gp,
+ GT96100_ETH_INT_CAUSE));
+}
+
+
+/*
+ * The Tx ring has been full longer than the watchdog timeout
+ * value, meaning that the interrupt routine has not been freeing
+ * up space in the Tx ring buffer.
+ */
+static void gt96100_tx_timeout(struct net_device *dev)
+{
+// struct gt96100_private *gp = (struct gt96100_private *)dev->priv;
+
+ printk(KERN_ERR "%s: gt96100_tx_timeout: dev=%p\n", dev->name,
+ dev);
+
+ // FIX! do something, like reset the device
+}
+
+
+static void gt96100_set_rx_mode(struct net_device *dev)
+{
+ struct gt96100_private *gp = (struct gt96100_private *) dev->priv;
+ unsigned long flags;
+ struct dev_mc_list *mcptr;
+
+ if (gt96100_debug > 2)
+ printk("%s: gt96100_set_rx_mode: dev=%p, flags=%x\n",
+ dev->name, dev, dev->flags);
+
+ // stop the Receiver DMA
+ abort(dev, sdcmrAR);
+
+ spin_lock_irqsave(&gp->lock, flags);
+
+ if (dev->flags & IFF_PROMISC)
+ GT96100ETH_WRITE(gp, GT96100_ETH_PORT_CONFIG,
+ pcrEN | pcrHS | pcrPM);
+
+ memset(gp->hash_table, 0, RX_HASH_TABLE_SIZE); // clear hash table
+ // Add our ethernet address
+ gt96100_add_hash_entry(dev, dev->dev_addr);
+
+ if (dev->mc_count) {
+ for (mcptr = dev->mc_list; mcptr; mcptr = mcptr->next) {
+ gt96100_add_hash_entry(dev, mcptr->dmi_addr);
+ }
+ }
+ // restart Rx DMA
+ GT96100ETH_WRITE(gp, GT96100_ETH_SDMA_COMM, sdcmrERD);
+
+ spin_unlock_irqrestore(&gp->lock, flags);
+}
+
+static struct net_device_stats *gt96100_get_stats(struct net_device *dev)
+{
+ struct gt96100_private *gp = (struct gt96100_private *) dev->priv;
+ unsigned long flags;
+
+ if (gt96100_debug > 2)
+ printk("%s: gt96100_get_stats: dev=%p\n", dev->name, dev);
+
+ if (netif_device_present(dev)) {
+ spin_lock_irqsave(&gp->lock, flags);
+ update_stats(gp);
+ spin_unlock_irqrestore(&gp->lock, flags);
+ }
+
+ return &gp->stats;
+}
+
+module_init(gt96100_probe);
--- /dev/null
+/*
+ * Copyright 2000 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ * stevel@mvista.com or support@mvista.com
+ *
+ * ########################################################################
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ *
+ * Ethernet driver definitions for the MIPS GT96100 Advanced
+ * Communication Controller.
+ *
+ */
+#ifndef _GT96100ETH_H
+#define _GT96100ETH_H
+
+#include <linux/config.h>
+#include <asm/galileo-boards/gt96100.h>
+
+/* Keep the ring sizes a power of two for efficiency. */
+#define TX_RING_SIZE 16
+#define RX_RING_SIZE 32
+#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer. */
+
+#define RX_HASH_TABLE_SIZE 16384
+#define HASH_HOP_NUMBER 12
+
+#define NUM_INTERFACES 2
+
+#define GT96100ETH_TX_TIMEOUT HZ
+
+#define GT96100_ETH0_BASE (MIPS_GT96100_BASE + GT96100_ETH_PORT_CONFIG)
+#define GT96100_ETH1_BASE (GT96100_ETH0_BASE + GT96100_ETH_IO_SIZE)
+
+#ifdef CONFIG_MIPS_EV96100
+#define GT96100_ETHER0_IRQ 4
+#define GT96100_ETHER1_IRQ 4
+#else
+#define GT96100_ETHER0_IRQ -1
+#define GT96100_ETHER1_IRQ -1
+#endif
+
+#define GT96100ETH_READ(gp, offset) \
+ GT96100_READ((gp->port_offset + offset))
+
+#define GT96100ETH_WRITE(gp, offset, data) \
+ GT96100_WRITE((gp->port_offset + offset), data)
+
+#define GT96100ETH_SETBIT(gp, offset, bits) {\
+ u32 val = GT96100ETH_READ(gp, offset); val |= (u32)(bits); \
+ GT96100ETH_WRITE(gp, offset, val); }
+
+#define GT96100ETH_CLRBIT(gp, offset, bits) {\
+ u32 val = GT96100ETH_READ(gp, offset); val &= (u32)(~(bits)); \
+ GT96100ETH_WRITE(gp, offset, val); }
+
+
+/* Bit definitions of the SMI Reg */
+enum {
+ smirDataMask = 0xffff,
+ smirPhyAdMask = 0x1f << 16,
+ smirPhyAdBit = 16,
+ smirRegAdMask = 0x1f << 21,
+ smirRegAdBit = 21,
+ smirOpCode = 1 << 26,
+ smirReadValid = 1 << 27,
+ smirBusy = 1 << 28
+};
+
+/* Bit definitions of the Port Config Reg */
+enum pcr_bits {
+ pcrPM = 1,
+ pcrRBM = 2,
+ pcrPBF = 4,
+ pcrEN = 1 << 7,
+ pcrLPBKMask = 0x3 << 8,
+ pcrLPBKBit = 8,
+ pcrFC = 1 << 10,
+ pcrHS = 1 << 12,
+ pcrHM = 1 << 13,
+ pcrHDM = 1 << 14,
+ pcrHD = 1 << 15,
+ pcrISLMask = 0x7 << 28,
+ pcrISLBit = 28,
+ pcrACCS = 1 << 31
+};
+
+/* Bit definitions of the Port Config Extend Reg */
+enum pcxr_bits {
+ pcxrIGMP = 1,
+ pcxrSPAN = 2,
+ pcxrPAR = 4,
+ pcxrPRIOtxMask = 0x7 << 3,
+ pcxrPRIOtxBit = 3,
+ pcxrPRIOrxMask = 0x3 << 6,
+ pcxrPRIOrxBit = 6,
+ pcxrPRIOrxOverride = 1 << 8,
+ pcxrDPLXen = 1 << 9,
+ pcxrFCTLen = 1 << 10,
+ pcxrFLP = 1 << 11,
+ pcxrFCTL = 1 << 12,
+ pcxrMFLMask = 0x3 << 14,
+ pcxrMFLBit = 14,
+ pcxrMIBclrMode = 1 << 16,
+ pcxrSpeed = 1 << 18,
+ pcxrSpeeden = 1 << 19,
+ pcxrRMIIen = 1 << 20,
+ pcxrDSCPen = 1 << 21
+};
+
+/* Bit definitions of the Port Command Reg */
+enum pcmr_bits {
+ pcmrFJ = 1 << 15
+};
+
+
+/* Bit definitions of the Port Status Reg */
+enum psr_bits {
+ psrSpeed = 1,
+ psrDuplex = 2,
+ psrFctl = 4,
+ psrLink = 8,
+ psrPause = 1 << 4,
+ psrTxLow = 1 << 5,
+ psrTxHigh = 1 << 6,
+ psrTxInProg = 1 << 7
+};
+
+/* Bit definitions of the SDMA Config Reg */
+enum sdcr_bits {
+ sdcrRCMask = 0xf << 2,
+ sdcrRCBit = 2,
+ sdcrBLMR = 1 << 6,
+ sdcrBLMT = 1 << 7,
+ sdcrPOVR = 1 << 8,
+ sdcrRIFB = 1 << 9,
+ sdcrBSZMask = 0x3 << 12,
+ sdcrBSZBit = 12
+};
+
+/* Bit definitions of the SDMA Command Reg */
+enum sdcmr_bits {
+ sdcmrERD = 1 << 7,
+ sdcmrAR = 1 << 15,
+ sdcmrSTDH = 1 << 16,
+ sdcmrSTDL = 1 << 17,
+ sdcmrTXDH = 1 << 23,
+ sdcmrTXDL = 1 << 24,
+ sdcmrAT = 1 << 31
+};
+
+/* Bit definitions of the Interrupt Cause Reg */
+enum icr_bits {
+ icrRxBuffer = 1,
+ icrTxBufferHigh = 1 << 2,
+ icrTxBufferLow = 1 << 3,
+ icrTxEndHigh = 1 << 6,
+ icrTxEndLow = 1 << 7,
+ icrRxError = 1 << 8,
+ icrTxErrorHigh = 1 << 10,
+ icrTxErrorLow = 1 << 11,
+ icrRxOVR = 1 << 12,
+ icrTxUdr = 1 << 13,
+ icrRxBufferQ0 = 1 << 16,
+ icrRxBufferQ1 = 1 << 17,
+ icrRxBufferQ2 = 1 << 18,
+ icrRxBufferQ3 = 1 << 19,
+ icrRxErrorQ0 = 1 << 20,
+ icrRxErrorQ1 = 1 << 21,
+ icrRxErrorQ2 = 1 << 22,
+ icrRxErrorQ3 = 1 << 23,
+ icrMIIPhySTC = 1 << 28,
+ icrSMIdone = 1 << 29,
+ icrEtherIntSum = 1 << 31
+};
+
+
+/* The Rx and Tx descriptor lists. */
+
+typedef struct {
+ u32 cmdstat;
+ u32 byte_cnt;
+ u32 buff_ptr;
+ u32 next;
+} gt96100_td_t;
+
+#define tdByteCntBit 16
+
+typedef struct {
+ u32 cmdstat;
+ u32 buff_cnt_sz;
+ u32 buff_ptr;
+ u32 next;
+} gt96100_rd_t;
+
+#define rdBuffSzBit 16
+#define rdByteCntMask 0xffff
+
+
+/* Values for the Tx command-status descriptor entry. */
+enum td_cmdstat {
+ txOwn = 1 << 31,
+ txAutoMode = 1 << 30,
+ txEI = 1 << 23,
+ txGenCRC = 1 << 22,
+ txPad = 1 << 18,
+ txFirst = 1 << 17,
+ txLast = 1 << 16,
+ txErrorSummary = 1 << 15,
+ txReTxCntMask = 0x0f << 10,
+ txReTxCntBit = 10,
+ txCollision = 1 << 9,
+ txReTxLimit = 1 << 8,
+ txUnderrun = 1 << 6,
+ txLateCollision = 1 << 5
+};
+
+#define TxReTxCntBit 10
+
+/* Values for the Rx command-status descriptor entry. */
+enum rd_cmdstat {
+ rxOwn = 1 << 31,
+ rxAutoMode = 1 << 30,
+ rxEI = 1 << 23,
+ rxFirst = 1 << 17,
+ rxLast = 1 << 16,
+ rxErrorSummary = 1 << 15,
+ rxIGMP = 1 << 14,
+ rxHashExpired = 1 << 13,
+ rxMissedFrame = 1 << 12,
+ rxFrameType = 1 << 11,
+ rxShortFrame = 1 << 8,
+ rxMaxFrameLen = 1 << 7,
+ rxOverrun = 1 << 6,
+ rxCollision = 1 << 4,
+ rxCRCError = 1
+};
+
+/* Bit fields of a Hash Table Entry */
+enum hash_table_entry {
+ hteValid = 1,
+ hteSkip = 2,
+ hteRD = 4
+};
+
+// The MIB counters
+typedef struct {
+ u32 byteReceived;
+ u32 byteSent;
+ u32 framesReceived;
+ u32 framesSent;
+ u32 totalByteReceived;
+ u32 totalFramesReceived;
+ u32 broadcastFramesReceived;
+ u32 multicastFramesReceived;
+ u32 cRCError;
+ u32 oversizeFrames;
+ u32 fragments;
+ u32 jabber;
+ u32 collision;
+ u32 lateCollision;
+ u32 frames64;
+ u32 frames65_127;
+ u32 frames128_255;
+ u32 frames256_511;
+ u32 frames512_1023;
+ u32 frames1024_MaxSize;
+ u32 macRxError;
+ u32 droppedFrames;
+ u32 outMulticastFrames;
+ u32 outBroadcastFrames;
+ u32 undersizeFrames;
+} mib_counters_t;
+
+
+struct gt96100_private {
+ gt96100_rd_t *rx_ring;
+ gt96100_td_t *tx_ring;
+ // The Rx and Tx rings must be 16-byte aligned
+ dma_addr_t rx_ring_dma;
+ dma_addr_t tx_ring_dma;
+ char *hash_table;
+ // The Hash Table must be 8-byte aligned
+ dma_addr_t hash_table_dma;
+ int hash_mode;
+
+ // The Rx buffers must be 8-byte aligned
+ char *rx_buff[RX_RING_SIZE];
+ // Tx buffers (tx_skbuff[i]->data) with less than 8 bytes
+ // of payload must be 8-byte aligned
+ struct sk_buff *tx_skbuff[TX_RING_SIZE];
+ int rx_next_out; /* The next free ring entry to receive */
+ int tx_next_in; /* The next free ring entry to send */
+ int tx_next_out; /* The last ring entry the ISR processed */
+ int tx_count; /* current # of pkts waiting to be sent in Tx ring */
+
+ mib_counters_t mib;
+ struct net_device_stats stats;
+
+ int io_size;
+ int port_num; // 0 or 1
+ u32 port_offset;
+
+ int phy_addr; // PHY address
+ u32 last_psr; // last value of the port status register
+
+ int options; /* User-settable misc. driver options. */
+ int drv_flags;
+ unsigned char phys[2]; /* MII device addresses. */
+ spinlock_t lock; /* Serialise access to device */
+};
+
+#endif
/* Do sanity checks on maximum device parameter. */
if (sixpack_maxdev < 4)
sixpack_maxdev = 4;
- if (sixpack_maxdev * sizeof(void*) >= KMALLOC_MAXSIZE) {
- printk(msg_invparm);
- return -ENFILE;
- }
printk(msg_banner, sixpack_maxdev);
link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL);
if (!link)
return NULL;
+ memset(link, 0, sizeof(struct dev_link_t));
+
link->dev = kmalloc(sizeof(struct dev_node_t), GFP_KERNEL);
if (!link->dev) {
kfree(link);
return NULL;
}
- memset(link, 0, sizeof(struct dev_link_t));
+
memset(link->dev, 0, sizeof(struct dev_node_t));
link->release.function = &awc_release;
--- /dev/null
+/*
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved.
+ *
+ * ########################################################################
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ *
+ * SAA9730 ethernet driver.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/delay.h>
+#include <linux/etherdevice.h>
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/pci.h>
+
+#include <asm/addrspace.h>
+#include <asm/mips-boards/prom.h>
+
+#include "saa9730.h"
+
+#ifdef LAN_SAA9730_DEBUG
+int lan_saa9730_debug = LAN_SAA9730_DEBUG;
+#else
+int lan_saa9730_debug;
+#endif
+
+
+/* Non-zero only if the current card is a PCI with BIOS-set IRQ. */
+static unsigned int pci_irq_line = 0;
+
+#define INL(a) inl((unsigned long)a)
+#define OUTL(x,a) outl(x,(unsigned long)a)
+
+static void evm_saa9730_enable_lan_int(struct lan_saa9730_private *lp)
+{
+ OUTL(INL(&lp->evm_saa9730_regs->InterruptBlock1) | EVM_LAN_INT,
+ &lp->evm_saa9730_regs->InterruptBlock1);
+ OUTL(INL(&lp->evm_saa9730_regs->InterruptStatus1) | EVM_LAN_INT,
+ &lp->evm_saa9730_regs->InterruptStatus1);
+ OUTL(INL(&lp->evm_saa9730_regs->InterruptEnable1) | EVM_LAN_INT |
+ EVM_MASTER_EN, &lp->evm_saa9730_regs->InterruptEnable1);
+}
+static void evm_saa9730_disable_lan_int(struct lan_saa9730_private *lp)
+{
+ OUTL(INL(&lp->evm_saa9730_regs->InterruptBlock1) & ~EVM_LAN_INT,
+ &lp->evm_saa9730_regs->InterruptBlock1);
+ OUTL(INL(&lp->evm_saa9730_regs->InterruptEnable1) & ~EVM_LAN_INT,
+ &lp->evm_saa9730_regs->InterruptEnable1);
+}
+
+static void evm_saa9730_clear_lan_int(struct lan_saa9730_private *lp)
+{
+ OUTL(EVM_LAN_INT, &lp->evm_saa9730_regs->InterruptStatus1);
+}
+
+static void evm_saa9730_block_lan_int(struct lan_saa9730_private *lp)
+{
+ OUTL(INL(&lp->evm_saa9730_regs->InterruptBlock1) & ~EVM_LAN_INT,
+ &lp->evm_saa9730_regs->InterruptBlock1);
+}
+
+static void evm_saa9730_unblock_lan_int(struct lan_saa9730_private *lp)
+{
+ OUTL(INL(&lp->evm_saa9730_regs->InterruptBlock1) | EVM_LAN_INT,
+ &lp->evm_saa9730_regs->InterruptBlock1);
+}
+
+static void show_saa9730_regs(struct lan_saa9730_private *lp)
+{
+ int i, j;
+ printk("TxmBufferA = %x\n", lp->TxmBuffer[0][0]);
+ printk("TxmBufferB = %x\n", lp->TxmBuffer[1][0]);
+ printk("RcvBufferA = %x\n", lp->RcvBuffer[0][0]);
+ printk("RcvBufferB = %x\n", lp->RcvBuffer[1][0]);
+ for (i = 0; i < LAN_SAA9730_BUFFERS; i++) {
+ for (j = 0; j < LAN_SAA9730_TXM_Q_SIZE; j++) {
+ printk("TxmBuffer[%d][%d] = %x\n", i, j,
+ le32_to_cpu(*(unsigned int *)
+ lp->TxmBuffer[i][j]));
+ }
+ }
+ for (i = 0; i < LAN_SAA9730_BUFFERS; i++) {
+ for (j = 0; j < LAN_SAA9730_RCV_Q_SIZE; j++) {
+ printk("RcvBuffer[%d][%d] = %x\n", i, j,
+ le32_to_cpu(*(unsigned int *)
+ lp->RcvBuffer[i][j]));
+ }
+ }
+ printk("lp->evm_saa9730_regs->InterruptBlock1 = %x\n",
+ INL(&lp->evm_saa9730_regs->InterruptBlock1));
+ printk("lp->evm_saa9730_regs->InterruptStatus1 = %x\n",
+ INL(&lp->evm_saa9730_regs->InterruptStatus1));
+ printk("lp->evm_saa9730_regs->InterruptEnable1 = %x\n",
+ INL(&lp->evm_saa9730_regs->InterruptEnable1));
+ printk("lp->lan_saa9730_regs->Ok2Use = %x\n",
+ INL(&lp->lan_saa9730_regs->Ok2Use));
+ printk("lp->NextTxmBufferIndex = %x\n", lp->NextTxmBufferIndex);
+ printk("lp->NextTxmPacketIndex = %x\n", lp->NextTxmPacketIndex);
+ printk("lp->PendingTxmBufferIndex = %x\n",
+ lp->PendingTxmBufferIndex);
+ printk("lp->PendingTxmPacketIndex = %x\n",
+ lp->PendingTxmPacketIndex);
+ printk("lp->lan_saa9730_regs->LanDmaCtl = %x\n",
+ INL(&lp->lan_saa9730_regs->LanDmaCtl));
+ printk("lp->lan_saa9730_regs->DmaStatus = %x\n",
+ INL(&lp->lan_saa9730_regs->DmaStatus));
+ printk("lp->lan_saa9730_regs->CamCtl = %x\n",
+ INL(&lp->lan_saa9730_regs->CamCtl));
+ printk("lp->lan_saa9730_regs->TxCtl = %x\n",
+ INL(&lp->lan_saa9730_regs->TxCtl));
+ printk("lp->lan_saa9730_regs->TxStatus = %x\n",
+ INL(&lp->lan_saa9730_regs->TxStatus));
+ printk("lp->lan_saa9730_regs->RxCtl = %x\n",
+ INL(&lp->lan_saa9730_regs->RxCtl));
+ printk("lp->lan_saa9730_regs->RxStatus = %x\n",
+ INL(&lp->lan_saa9730_regs->RxStatus));
+ for (i = 0; i < LAN_SAA9730_CAM_DWORDS; i++) {
+ OUTL(i, &lp->lan_saa9730_regs->CamAddress);
+ printk("lp->lan_saa9730_regs->CamData = %x\n",
+ INL(&lp->lan_saa9730_regs->CamData));
+ }
+ printk("lp->stats.tx_packets = %lx\n", lp->stats.tx_packets);
+ printk("lp->stats.tx_errors = %lx\n", lp->stats.tx_errors);
+ printk("lp->stats.tx_aborted_errors = %lx\n",
+ lp->stats.tx_aborted_errors);
+ printk("lp->stats.tx_window_errors = %lx\n",
+ lp->stats.tx_window_errors);
+ printk("lp->stats.tx_carrier_errors = %lx\n",
+ lp->stats.tx_carrier_errors);
+ printk("lp->stats.tx_fifo_errors = %lx\n",
+ lp->stats.tx_fifo_errors);
+ printk("lp->stats.tx_heartbeat_errors = %lx\n",
+ lp->stats.tx_heartbeat_errors);
+ printk("lp->stats.collisions = %lx\n", lp->stats.collisions);
+
+ printk("lp->stats.rx_packets = %lx\n", lp->stats.rx_packets);
+ printk("lp->stats.rx_errors = %lx\n", lp->stats.rx_errors);
+ printk("lp->stats.rx_dropped = %lx\n", lp->stats.rx_dropped);
+ printk("lp->stats.rx_crc_errors = %lx\n", lp->stats.rx_crc_errors);
+ printk("lp->stats.rx_frame_errors = %lx\n",
+ lp->stats.rx_frame_errors);
+ printk("lp->stats.rx_fifo_errors = %lx\n",
+ lp->stats.rx_fifo_errors);
+ printk("lp->stats.rx_length_errors = %lx\n",
+ lp->stats.rx_length_errors);
+
+ printk("lp->lan_saa9730_regs->DebugPCIMasterAddr = %x\n",
+ INL(&lp->lan_saa9730_regs->DebugPCIMasterAddr));
+ printk("lp->lan_saa9730_regs->DebugLanTxStateMachine = %x\n",
+ INL(&lp->lan_saa9730_regs->DebugLanTxStateMachine));
+ printk("lp->lan_saa9730_regs->DebugLanRxStateMachine = %x\n",
+ INL(&lp->lan_saa9730_regs->DebugLanRxStateMachine));
+ printk("lp->lan_saa9730_regs->DebugLanTxFifoPointers = %x\n",
+ INL(&lp->lan_saa9730_regs->DebugLanTxFifoPointers));
+ printk("lp->lan_saa9730_regs->DebugLanRxFifoPointers = %x\n",
+ INL(&lp->lan_saa9730_regs->DebugLanRxFifoPointers));
+ printk("lp->lan_saa9730_regs->DebugLanCtlStateMachine = %x\n",
+ INL(&lp->lan_saa9730_regs->DebugLanCtlStateMachine));
+}
+
+static void lan_saa9730_buffer_init(struct lan_saa9730_private *lp)
+{
+ int i, j;
+
+ /* Init RX buffers */
+ for (i = 0; i < LAN_SAA9730_BUFFERS; i++) {
+ for (j = 0; j < LAN_SAA9730_RCV_Q_SIZE; j++) {
+ *(unsigned int *) lp->RcvBuffer[i][j] =
+ cpu_to_le32(RXSF_READY <<
+ RX_STAT_CTL_OWNER_SHF);
+ }
+ }
+
+ /* Init TX buffers */
+ for (i = 0; i < LAN_SAA9730_BUFFERS; i++) {
+ for (j = 0; j < LAN_SAA9730_TXM_Q_SIZE; j++) {
+ *(unsigned int *) lp->TxmBuffer[i][j] =
+ cpu_to_le32(TXSF_EMPTY <<
+ TX_STAT_CTL_OWNER_SHF);
+ }
+ }
+}
+
+static int lan_saa9730_allocate_buffers(struct lan_saa9730_private *lp)
+{
+ unsigned int mem_size;
+ void *Pa;
+ unsigned int i, j, RcvBufferSize, TxmBufferSize;
+ unsigned int buffer_start;
+
+ /*
+ * Allocate all RX and TX packets in one chunk.
+ * The Rx and Tx packets must be PACKET_SIZE aligned.
+ */
+ mem_size = ((LAN_SAA9730_RCV_Q_SIZE + LAN_SAA9730_TXM_Q_SIZE) *
+ LAN_SAA9730_PACKET_SIZE * LAN_SAA9730_BUFFERS) +
+ LAN_SAA9730_PACKET_SIZE;
+ buffer_start =
+ (unsigned int) kmalloc(mem_size, GFP_DMA | GFP_KERNEL);
+
+ /*
+ * Set DMA buffer to kseg1 (uncached).
+ * Make sure to flush before using it uncached.
+ */
+ Pa = (void *) KSEG1ADDR((buffer_start + LAN_SAA9730_PACKET_SIZE) &
+ ~(LAN_SAA9730_PACKET_SIZE - 1));
+ dma_cache_wback_inv((unsigned long) Pa, mem_size);
+
+ /* Initialize buffer space */
+ RcvBufferSize = LAN_SAA9730_PACKET_SIZE;
+ TxmBufferSize = LAN_SAA9730_PACKET_SIZE;
+ lp->DmaRcvPackets = LAN_SAA9730_RCV_Q_SIZE;
+ lp->DmaTxmPackets = LAN_SAA9730_TXM_Q_SIZE;
+
+ /* Init RX buffers */
+ for (i = 0; i < LAN_SAA9730_BUFFERS; i++) {
+ for (j = 0; j < LAN_SAA9730_RCV_Q_SIZE; j++) {
+ *(unsigned int *) Pa =
+ cpu_to_le32(RXSF_READY <<
+ RX_STAT_CTL_OWNER_SHF);
+ lp->RcvBuffer[i][j] = (unsigned int) Pa;
+ Pa += RcvBufferSize;
+ }
+ }
+
+ /* Init TX buffers */
+ for (i = 0; i < LAN_SAA9730_BUFFERS; i++) {
+ for (j = 0; j < LAN_SAA9730_TXM_Q_SIZE; j++) {
+ *(unsigned int *) Pa =
+ cpu_to_le32(TXSF_EMPTY <<
+ TX_STAT_CTL_OWNER_SHF);
+ lp->TxmBuffer[i][j] = (unsigned int) Pa;
+ Pa += TxmBufferSize;
+ }
+ }
+
+ /*
+ * Set rx buffer A and rx buffer B to point to the first two buffer
+ * spaces.
+ */
+ OUTL(PHYSADDR(lp->RcvBuffer[0][0]),
+ &lp->lan_saa9730_regs->RxBuffA);
+ OUTL(PHYSADDR(lp->RcvBuffer[1][0]),
+ &lp->lan_saa9730_regs->RxBuffB);
+
+ /* Initialize Buffer Index */
+ lp->NextRcvPacketIndex = 0;
+ lp->NextRcvToUseIsA = 1;
+
+ /* Set current buffer index & next availble packet index */
+ lp->NextTxmPacketIndex = 0;
+ lp->NextTxmBufferIndex = 0;
+ lp->PendingTxmPacketIndex = 0;
+ lp->PendingTxmBufferIndex = 0;
+
+ /*
+ * Set txm_buf_a and txm_buf_b to point to the first two buffer
+ * space
+ */
+ OUTL(PHYSADDR(lp->TxmBuffer[0][0]),
+ &lp->lan_saa9730_regs->TxBuffA);
+ OUTL(PHYSADDR(lp->TxmBuffer[1][0]),
+ &lp->lan_saa9730_regs->TxBuffB);
+
+ /* Set packet number */
+ OUTL((lp->DmaRcvPackets << PK_COUNT_RX_A_SHF) |
+ (lp->DmaRcvPackets << PK_COUNT_RX_B_SHF) |
+ (lp->DmaTxmPackets << PK_COUNT_TX_A_SHF) |
+ (lp->DmaTxmPackets << PK_COUNT_TX_B_SHF),
+ &lp->lan_saa9730_regs->PacketCount);
+
+ return 0;
+}
+
+static int lan_saa9730_cam_load(struct lan_saa9730_private *lp)
+{
+ unsigned int i;
+ unsigned char *NetworkAddress;
+
+ NetworkAddress = (unsigned char *) &lp->PhysicalAddress[0][0];
+
+ for (i = 0; i < LAN_SAA9730_CAM_DWORDS; i++) {
+ /* First set address to where data is written */
+ OUTL(i, &lp->lan_saa9730_regs->CamAddress);
+ OUTL((NetworkAddress[0] << 24) | (NetworkAddress[1] << 16)
+ | (NetworkAddress[2] << 8) | NetworkAddress[3],
+ &lp->lan_saa9730_regs->CamData);
+ NetworkAddress += 4;
+ }
+ return 0;
+}
+
+static int lan_saa9730_cam_init(struct net_device *dev)
+{
+ struct lan_saa9730_private *lp =
+ (struct lan_saa9730_private *) dev->priv;
+ unsigned int i;
+
+ /* Copy MAC-address into all entries. */
+ for (i = 0; i < LAN_SAA9730_CAM_ENTRIES; i++) {
+ memcpy((unsigned char *) lp->PhysicalAddress[i],
+ (unsigned char *) dev->dev_addr, 6);
+ }
+
+ return 0;
+}
+
+static int lan_saa9730_mii_init(struct lan_saa9730_private *lp)
+{
+ int i, l;
+
+ /* Check link status, spin here till station is not busy. */
+ i = 0;
+ while (INL(&lp->lan_saa9730_regs->StationMgmtCtl) & MD_CA_BUSY) {
+ i++;
+ if (i > 100) {
+ printk("Error: lan_saa9730_mii_init: timeout\n");
+ return -1;
+ }
+ udelay(1000); /* wait 1 ms. */
+ }
+
+ /* Now set the control and address register. */
+ OUTL(MD_CA_BUSY | PHY_STATUS | PHY_ADDRESS << MD_CA_PHY_SHF,
+ &lp->lan_saa9730_regs->StationMgmtCtl);
+
+ /* check link status, spin here till station is not busy */
+ i = 0;
+ while (INL(&lp->lan_saa9730_regs->StationMgmtCtl) & MD_CA_BUSY) {
+ i++;
+ if (i > 100) {
+ printk("Error: lan_saa9730_mii_init: timeout\n");
+ return -1;
+ }
+ udelay(1000); /* wait 1 ms. */
+ }
+
+ /* Wait for 1 ms. */
+ udelay(1000);
+
+ /* Check the link status. */
+ if (INL(&lp->lan_saa9730_regs->StationMgmtData) &
+ PHY_STATUS_LINK_UP) {
+ /* Link is up. */
+ return 0;
+ } else {
+ /* Link is down, reset the PHY first. */
+
+ /* set PHY address = 'CONTROL' */
+ OUTL(PHY_ADDRESS << MD_CA_PHY_SHF | MD_CA_WR | PHY_CONTROL,
+ &lp->lan_saa9730_regs->StationMgmtCtl);
+
+ /* Wait for 1 ms. */
+ udelay(1000);
+
+ /* set 'CONTROL' = force reset and renegotiate */
+ OUTL(PHY_CONTROL_RESET | PHY_CONTROL_AUTO_NEG |
+ PHY_CONTROL_RESTART_AUTO_NEG,
+ &lp->lan_saa9730_regs->StationMgmtData);
+
+ /* Wait for 50 ms. */
+ udelay(50 * 1000);
+
+ /* set 'BUSY' to start operation */
+ OUTL(MD_CA_BUSY | PHY_ADDRESS << MD_CA_PHY_SHF | MD_CA_WR |
+ PHY_CONTROL, &lp->lan_saa9730_regs->StationMgmtCtl);
+
+ /* await completion */
+ i = 0;
+ while (INL(&lp->lan_saa9730_regs->StationMgmtCtl) &
+ MD_CA_BUSY) {
+ i++;
+ if (i > 100) {
+ printk
+ ("Error: lan_saa9730_mii_init: timeout\n");
+ return -1;
+ }
+ udelay(1000); /* wait 1 ms. */
+ }
+
+ /* Wait for 1 ms. */
+ udelay(1000);
+
+ for (l = 0; l < 2; l++) {
+ /* set PHY address = 'STATUS' */
+ OUTL(MD_CA_BUSY | PHY_ADDRESS << MD_CA_PHY_SHF |
+ PHY_STATUS,
+ &lp->lan_saa9730_regs->StationMgmtCtl);
+
+ /* await completion */
+ i = 0;
+ while (INL(&lp->lan_saa9730_regs->StationMgmtCtl) &
+ MD_CA_BUSY) {
+ i++;
+ if (i > 100) {
+ printk
+ ("Error: lan_saa9730_mii_init: timeout\n");
+ return -1;
+ }
+ udelay(1000); /* wait 1 ms. */
+ }
+
+ /* wait for 3 sec. */
+ udelay(3000 * 1000);
+
+ /* check the link status */
+ if (INL(&lp->lan_saa9730_regs->StationMgmtData) &
+ PHY_STATUS_LINK_UP) {
+ /* link is up */
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int lan_saa9730_control_init(struct lan_saa9730_private *lp)
+{
+ /* Initialize DMA control register. */
+ OUTL((LANMB_ANY << DMA_CTL_MAX_XFER_SHF) |
+ (LANEND_LITTLE << DMA_CTL_ENDIAN_SHF) |
+ (LAN_SAA9730_RCV_Q_INT_THRESHOLD << DMA_CTL_RX_INT_COUNT_SHF)
+ | DMA_CTL_RX_INT_TO_EN | DMA_CTL_RX_INT_EN |
+ DMA_CTL_MAC_RX_INT_EN | DMA_CTL_MAC_TX_INT_EN,
+ &lp->lan_saa9730_regs->LanDmaCtl);
+
+ /* Initial MAC control register. */
+ OUTL((MACCM_MII << MAC_CONTROL_CONN_SHF) | MAC_CONTROL_FULL_DUP,
+ &lp->lan_saa9730_regs->MacCtl);
+
+ /* Initialize CAM control register. */
+ OUTL(CAM_CONTROL_COMP_EN | CAM_CONTROL_BROAD_ACC,
+ &lp->lan_saa9730_regs->CamCtl);
+
+ /*
+ * Initialize CAM enable register, only turn on first entry, should
+ * contain own addr.
+ */
+ OUTL(0x0001, &lp->lan_saa9730_regs->CamEnable);
+
+ /* Initialize Tx control register */
+ OUTL(TX_CTL_EN_COMP, &lp->lan_saa9730_regs->TxCtl);
+
+ /* Initialize Rcv control register */
+ OUTL(RX_CTL_STRIP_CRC, &lp->lan_saa9730_regs->RxCtl);
+
+ /* Reset DMA engine */
+ OUTL(DMA_TEST_SW_RESET, &lp->lan_saa9730_regs->DmaTest);
+
+ return 0;
+}
+
+static int lan_saa9730_stop(struct lan_saa9730_private *lp)
+{
+ int i;
+
+ /* Stop DMA first */
+ OUTL(INL(&lp->lan_saa9730_regs->LanDmaCtl) &
+ ~(DMA_CTL_EN_TX_DMA | DMA_CTL_EN_RX_DMA),
+ &lp->lan_saa9730_regs->LanDmaCtl);
+
+ /* Set the SW Reset bits in DMA and MAC control registers */
+ OUTL(DMA_TEST_SW_RESET, &lp->lan_saa9730_regs->DmaTest);
+ OUTL(INL(&lp->lan_saa9730_regs->MacCtl) | MAC_CONTROL_RESET,
+ &lp->lan_saa9730_regs->MacCtl);
+
+ /*
+ * Wait for MAC reset to have finished. The reset bit is auto cleared
+ * when the reset is done.
+ */
+ i = 0;
+ while (INL(&lp->lan_saa9730_regs->MacCtl) & MAC_CONTROL_RESET) {
+ i++;
+ if (i > 100) {
+ printk
+ ("Error: lan_sa9730_stop: MAC reset timeout\n");
+ return -1;
+ }
+ udelay(1000); /* wait 1 ms. */
+ }
+
+ return 0;
+}
+
+static int lan_saa9730_dma_init(struct lan_saa9730_private *lp)
+{
+ /* Stop lan controller. */
+ lan_saa9730_stop(lp);
+
+ OUTL(LAN_SAA9730_DEFAULT_TIME_OUT_CNT,
+ &lp->lan_saa9730_regs->Timeout);
+
+ return 0;
+}
+
+static int lan_saa9730_start(struct lan_saa9730_private *lp)
+{
+ lan_saa9730_buffer_init(lp);
+
+ /* Initialize Rx Buffer Index */
+ lp->NextRcvPacketIndex = 0;
+ lp->NextRcvToUseIsA = 1;
+
+ /* Set current buffer index & next availble packet index */
+ lp->NextTxmPacketIndex = 0;
+ lp->NextTxmBufferIndex = 0;
+ lp->PendingTxmPacketIndex = 0;
+ lp->PendingTxmBufferIndex = 0;
+
+ OUTL(INL(&lp->lan_saa9730_regs->LanDmaCtl) | DMA_CTL_EN_TX_DMA |
+ DMA_CTL_EN_RX_DMA, &lp->lan_saa9730_regs->LanDmaCtl);
+
+ /* For Tx, turn on MAC then DMA */
+ OUTL(INL(&lp->lan_saa9730_regs->TxCtl) | TX_CTL_TX_EN,
+ &lp->lan_saa9730_regs->TxCtl);
+
+ /* For Rx, turn on DMA then MAC */
+ OUTL(INL(&lp->lan_saa9730_regs->RxCtl) | RX_CTL_RX_EN,
+ &lp->lan_saa9730_regs->RxCtl);
+
+ /* Set Ok2Use to let hardware owns the buffers */
+ OUTL(OK2USE_RX_A | OK2USE_RX_B | OK2USE_TX_A | OK2USE_TX_B,
+ &lp->lan_saa9730_regs->Ok2Use);
+
+ return 0;
+}
+
+static int lan_saa9730_restart(struct lan_saa9730_private *lp)
+{
+ lan_saa9730_stop(lp);
+ lan_saa9730_start(lp);
+
+ return 0;
+}
+
+static int lan_saa9730_tx(struct net_device *dev)
+{
+ struct lan_saa9730_private *lp =
+ (struct lan_saa9730_private *) dev->priv;
+ unsigned int *pPacket;
+ unsigned int tx_status;
+
+ if (lan_saa9730_debug > 5)
+ printk("lan_saa9730_tx interrupt\n");
+
+ /* Clear interrupt. */
+ OUTL(DMA_STATUS_MAC_TX_INT, &lp->lan_saa9730_regs->DmaStatus);
+
+ while (1) {
+ pPacket =
+ (unsigned int *) lp->TxmBuffer[lp->
+ PendingTxmBufferIndex]
+ [lp->PendingTxmPacketIndex];
+
+ /* Get status of first packet transmitted. */
+ tx_status = le32_to_cpu(*pPacket);
+
+ /* Check ownership. */
+ if ((tx_status & TX_STAT_CTL_OWNER_MSK) !=
+ (TXSF_HWDONE << TX_STAT_CTL_OWNER_SHF)) break;
+
+ /* Check for error. */
+ if (tx_status & TX_STAT_CTL_ERROR_MSK) {
+ if (lan_saa9730_debug > 1)
+ printk("lan_saa9730_tx: tx error = %x\n",
+ tx_status);
+
+ lp->stats.tx_errors++;
+ if (tx_status &
+ (TX_STATUS_EX_COLL << TX_STAT_CTL_STATUS_SHF))
+ lp->stats.tx_aborted_errors++;
+ if (tx_status &
+ (TX_STATUS_LATE_COLL <<
+ TX_STAT_CTL_STATUS_SHF)) lp->stats.
+ tx_window_errors++;
+ if (tx_status &
+ (TX_STATUS_L_CARR << TX_STAT_CTL_STATUS_SHF))
+ lp->stats.tx_carrier_errors++;
+ if (tx_status &
+ (TX_STATUS_UNDER << TX_STAT_CTL_STATUS_SHF))
+ lp->stats.tx_fifo_errors++;
+ if (tx_status &
+ (TX_STATUS_SQ_ERR << TX_STAT_CTL_STATUS_SHF))
+ lp->stats.tx_heartbeat_errors++;
+
+ lp->stats.collisions +=
+ tx_status & TX_STATUS_TX_COLL_MSK;
+ }
+
+ /* Free buffer. */
+ *pPacket =
+ cpu_to_le32(TXSF_EMPTY << TX_STAT_CTL_OWNER_SHF);
+
+ /* Update pending index pointer. */
+ lp->PendingTxmPacketIndex++;
+ if (lp->PendingTxmPacketIndex >= LAN_SAA9730_TXM_Q_SIZE) {
+ lp->PendingTxmPacketIndex = 0;
+ lp->PendingTxmBufferIndex ^= 1;
+ }
+ }
+
+ /* Make sure A and B are available to hardware. */
+ OUTL(OK2USE_TX_A | OK2USE_TX_B, &lp->lan_saa9730_regs->Ok2Use);
+
+ if (netif_queue_stopped(dev)) {
+ /* The tx buffer is no longer full. */
+ netif_wake_queue(dev);
+ }
+
+ return 0;
+}
+
+static int lan_saa9730_rx(struct net_device *dev)
+{
+ struct lan_saa9730_private *lp =
+ (struct lan_saa9730_private *) dev->priv;
+ int len = 0;
+ struct sk_buff *skb = 0;
+ unsigned int rx_status;
+ int BufferIndex;
+ int PacketIndex;
+ unsigned int *pPacket;
+ unsigned char *pData;
+
+ if (lan_saa9730_debug > 5)
+ printk("lan_saa9730_rx interrupt\n");
+
+ /* Clear receive interrupts. */
+ OUTL(DMA_STATUS_MAC_RX_INT | DMA_STATUS_RX_INT |
+ DMA_STATUS_RX_TO_INT, &lp->lan_saa9730_regs->DmaStatus);
+
+ /* Address next packet */
+ if (lp->NextRcvToUseIsA)
+ BufferIndex = 0;
+ else
+ BufferIndex = 1;
+ PacketIndex = lp->NextRcvPacketIndex;
+ pPacket = (unsigned int *) lp->RcvBuffer[BufferIndex][PacketIndex];
+ rx_status = le32_to_cpu(*pPacket);
+
+ /* Process each packet. */
+ while ((rx_status & RX_STAT_CTL_OWNER_MSK) ==
+ (RXSF_HWDONE << RX_STAT_CTL_OWNER_SHF)) {
+ /* Check the rx status. */
+ if (rx_status & (RX_STATUS_GOOD << RX_STAT_CTL_STATUS_SHF)) {
+ /* Received packet is good. */
+ len = (rx_status & RX_STAT_CTL_LENGTH_MSK) >>
+ RX_STAT_CTL_LENGTH_SHF;
+
+ pData = (unsigned char *) pPacket;
+ pData += 4;
+ skb = dev_alloc_skb(len + 2);
+ if (skb == 0) {
+ printk
+ ("%s: Memory squeeze, deferring packet.\n",
+ dev->name);
+ lp->stats.rx_dropped++;
+ } else {
+ lp->stats.rx_bytes += len;
+ lp->stats.rx_packets++;
+ skb->dev = dev;
+ skb_reserve(skb, 2); /* 16 byte align */
+ skb_put(skb, len); /* make room */
+ eth_copy_and_sum(skb,
+ (unsigned char *) pData,
+ len, 0);
+ skb->protocol = eth_type_trans(skb, dev);
+ netif_rx(skb);
+ }
+ } else {
+ /* We got an error packet. */
+ if (lan_saa9730_debug > 2)
+ printk
+ ("lan_saa9730_rx: We got an error packet = %x\n",
+ rx_status);
+
+ lp->stats.rx_errors++;
+ if (rx_status &
+ (RX_STATUS_CRC_ERR << RX_STAT_CTL_STATUS_SHF))
+ lp->stats.rx_crc_errors++;
+ if (rx_status &
+ (RX_STATUS_ALIGN_ERR <<
+ RX_STAT_CTL_STATUS_SHF)) lp->stats.
+ rx_frame_errors++;
+ if (rx_status &
+ (RX_STATUS_OVERFLOW << RX_STAT_CTL_STATUS_SHF))
+ lp->stats.rx_fifo_errors++;
+ if (rx_status &
+ (RX_STATUS_LONG_ERR << RX_STAT_CTL_STATUS_SHF))
+ lp->stats.rx_length_errors++;
+ }
+
+ /* Indicate we have processed the buffer. */
+ *pPacket =
+ cpu_to_le32(RXSF_READY << RX_STAT_CTL_OWNER_SHF);
+
+ /* Go to next packet in sequence. */
+ lp->NextRcvPacketIndex++;
+ if (lp->NextRcvPacketIndex >= LAN_SAA9730_RCV_Q_SIZE) {
+ lp->NextRcvPacketIndex = 0;
+ if (BufferIndex) {
+ lp->NextRcvToUseIsA = 1;
+ } else {
+ lp->NextRcvToUseIsA = 0;
+ }
+ }
+ OUTL(OK2USE_RX_A | OK2USE_RX_B,
+ &lp->lan_saa9730_regs->Ok2Use);
+
+ /* Address next packet */
+ if (lp->NextRcvToUseIsA)
+ BufferIndex = 0;
+ else
+ BufferIndex = 1;
+ PacketIndex = lp->NextRcvPacketIndex;
+ pPacket =
+ (unsigned int *) lp->
+ RcvBuffer[BufferIndex][PacketIndex];
+ rx_status = le32_to_cpu(*pPacket);
+ }
+
+ /* Make sure A and B are available to hardware. */
+ OUTL(OK2USE_RX_A | OK2USE_RX_B, &lp->lan_saa9730_regs->Ok2Use);
+
+ return 0;
+}
+
+static void lan_saa9730_interrupt(const int irq, void *dev_id,
+ struct pt_regs *regs)
+{
+ struct net_device *dev = (struct net_device *) dev_id;
+ struct lan_saa9730_private *lp =
+ (struct lan_saa9730_private *) dev->priv;
+
+ if (lan_saa9730_debug > 5)
+ printk("lan_saa9730_interrupt\n");
+
+ /* Disable the EVM LAN interrupt. */
+ evm_saa9730_block_lan_int(lp);
+
+ /* Clear the EVM LAN interrupt. */
+ evm_saa9730_clear_lan_int(lp);
+
+ /* Service pending transmit interrupts. */
+ if (INL(&lp->lan_saa9730_regs->DmaStatus) & DMA_STATUS_MAC_TX_INT)
+ lan_saa9730_tx(dev);
+
+ /* Service pending receive interrupts. */
+ if (INL(&lp->lan_saa9730_regs->DmaStatus) &
+ (DMA_STATUS_MAC_RX_INT | DMA_STATUS_RX_INT |
+ DMA_STATUS_RX_TO_INT)) lan_saa9730_rx(dev);
+
+ /* Enable the EVM LAN interrupt. */
+ evm_saa9730_unblock_lan_int(lp);
+
+ return;
+}
+
+static int lan_saa9730_open_fail(struct net_device *dev)
+{
+ return -ENODEV;
+}
+
+static int lan_saa9730_open(struct net_device *dev)
+{
+ struct lan_saa9730_private *lp =
+ (struct lan_saa9730_private *) dev->priv;
+
+ /* Associate IRQ with lan_saa9730_interrupt */
+ if (request_irq(dev->irq, &lan_saa9730_interrupt, 0, "SAA9730 Eth",
+ dev)) {
+ printk("lan_saa9730_open: Can't get irq %d\n", dev->irq);
+ return -EAGAIN;
+ }
+
+ /* Enable the Lan interrupt in the event manager. */
+ evm_saa9730_enable_lan_int(lp);
+
+ /* Start the LAN controller */
+ if (lan_saa9730_start(lp))
+ return -1;
+
+ netif_start_queue(dev);
+
+ return 0;
+}
+
+static int lan_saa9730_write(struct lan_saa9730_private *lp,
+ struct sk_buff *skb, int skblen)
+{
+ unsigned char *pbData = skb->data;
+ unsigned int len = skblen;
+ unsigned char *pbPacketData;
+ unsigned int tx_status;
+ int BufferIndex;
+ int PacketIndex;
+
+ if (lan_saa9730_debug > 5)
+ printk("lan_saa9730_write: skb=%08x\n",
+ (unsigned int) skb);
+
+ BufferIndex = lp->NextTxmBufferIndex;
+ PacketIndex = lp->NextTxmPacketIndex;
+
+ tx_status =
+ le32_to_cpu(*(unsigned int *) lp->
+ TxmBuffer[BufferIndex][PacketIndex]);
+ if ((tx_status & TX_STAT_CTL_OWNER_MSK) !=
+ (TXSF_EMPTY << TX_STAT_CTL_OWNER_SHF)) {
+ if (lan_saa9730_debug > 4)
+ printk
+ ("lan_saa9730_write: Tx buffer not available: tx_status = %x\n",
+ tx_status);
+ return -1;
+ }
+
+ lp->NextTxmPacketIndex++;
+ if (lp->NextTxmPacketIndex >= LAN_SAA9730_TXM_Q_SIZE) {
+ lp->NextTxmPacketIndex = 0;
+ lp->NextTxmBufferIndex ^= 1;
+ }
+
+ pbPacketData =
+ (unsigned char *) lp->TxmBuffer[BufferIndex][PacketIndex];
+ pbPacketData += 4;
+
+ /* copy the bits */
+ memcpy(pbPacketData, pbData, len);
+
+ /* Set transmit status for hardware */
+ *(unsigned int *) lp->TxmBuffer[BufferIndex][PacketIndex] =
+ cpu_to_le32((TXSF_READY << TX_STAT_CTL_OWNER_SHF) |
+ (TX_STAT_CTL_INT_AFTER_TX << TX_STAT_CTL_FRAME_SHF)
+ | (len << TX_STAT_CTL_LENGTH_SHF));
+
+ /* Set hardware tx buffer. */
+ OUTL(OK2USE_TX_A | OK2USE_TX_B, &lp->lan_saa9730_regs->Ok2Use);
+
+ return 0;
+}
+
+static void lan_saa9730_tx_timeout(struct net_device *dev)
+{
+ struct lan_saa9730_private *lp =
+ (struct lan_saa9730_private *) dev->priv;
+
+ /* Transmitter timeout, serious problems */
+ lp->stats.tx_errors++;
+ printk("%s: transmit timed out, reset\n", dev->name);
+ /*show_saa9730_regs(lp); */
+ lan_saa9730_restart(lp);
+
+ dev->trans_start = jiffies;
+ netif_start_queue(dev);
+}
+
+static int lan_saa9730_start_xmit(struct sk_buff *skb,
+ struct net_device *dev)
+{
+ struct lan_saa9730_private *lp =
+ (struct lan_saa9730_private *) dev->priv;
+ unsigned long flags;
+ int skblen;
+ int len;
+
+ if (lan_saa9730_debug > 4)
+ printk("Send packet: skb=%08x\n", (unsigned int) skb);
+
+ skblen = skb->len;
+ save_and_cli(flags);
+ len = (skblen <= ETH_ZLEN) ? ETH_ZLEN : skblen;
+
+ if (lan_saa9730_write(lp, skb, skblen)) {
+ restore_flags(flags);
+ printk
+ ("Error when writing packet to controller: skb=%08x\n",
+ (unsigned int) skb);
+ netif_stop_queue(dev);
+ return -1;
+ }
+
+ lp->stats.tx_bytes += len;
+ lp->stats.tx_packets++;
+
+ dev->trans_start = jiffies;
+ netif_start_queue(dev);
+ dev_kfree_skb(skb);
+
+ restore_flags(flags);
+
+ return 0;
+}
+
+static int lan_saa9730_close(struct net_device *dev)
+{
+ struct lan_saa9730_private *lp =
+ (struct lan_saa9730_private *) dev->priv;
+
+ if (lan_saa9730_debug > 1)
+ printk("lan_saa9730_close:\n");
+
+ netif_stop_queue(dev);
+
+ /* Disable the Lan interrupt in the event manager. */
+ evm_saa9730_disable_lan_int(lp);
+
+ /* Stop the controller */
+ if (lan_saa9730_stop(lp))
+ return -1;
+
+ free_irq(dev->irq, (void *) dev);
+
+ return 0;
+}
+
+static struct net_device_stats *lan_saa9730_get_stats(struct net_device
+ *dev)
+{
+ struct lan_saa9730_private *lp =
+ (struct lan_saa9730_private *) dev->priv;
+
+ return &lp->stats;
+}
+
+static void lan_saa9730_set_multicast(struct net_device *dev)
+{
+ struct lan_saa9730_private *lp =
+ (struct lan_saa9730_private *) dev->priv;
+
+ /* Stop the controller */
+ lan_saa9730_stop(lp);
+
+ if (dev->flags & IFF_PROMISC) {
+ /* accept all packets */
+ OUTL(CAM_CONTROL_COMP_EN | CAM_CONTROL_STATION_ACC |
+ CAM_CONTROL_GROUP_ACC | CAM_CONTROL_BROAD_ACC,
+ &lp->lan_saa9730_regs->CamCtl);
+ } else {
+ if (dev->flags & IFF_ALLMULTI) {
+ /* accept all multicast packets */
+ OUTL(CAM_CONTROL_COMP_EN | CAM_CONTROL_GROUP_ACC |
+ CAM_CONTROL_BROAD_ACC,
+ &lp->lan_saa9730_regs->CamCtl);
+ } else {
+ /*
+ * Will handle the multicast stuff later. -carstenl
+ */
+ }
+ }
+
+ lan_saa9730_restart(lp);
+}
+
+static int lan_saa9730_init(struct net_device *dev, int ioaddr, int irq)
+{
+ struct lan_saa9730_private *lp;
+ unsigned char ethernet_addr[6];
+
+ dev = init_etherdev(dev, 0);
+
+ dev->open = lan_saa9730_open_fail;
+ if (get_ethernet_addr(ethernet_addr))
+ return -1;
+
+ memcpy(dev->dev_addr, ethernet_addr, 6);
+ dev->base_addr = ioaddr;
+ dev->irq = irq;
+
+ /*
+ * Make certain the data structures used by the controller are aligned
+ * and DMAble.
+ */
+ lp = (struct lan_saa9730_private *) (((unsigned long)
+ kmalloc(sizeof(*lp) + 7,
+ GFP_DMA | GFP_KERNEL)
+ + 7) & ~7);
+
+ dev->priv = lp;
+ memset(lp, 0, sizeof(*lp));
+
+ /* Set SAA9730 LAN base address. */
+ lp->lan_saa9730_regs = (t_lan_saa9730_regmap *) (ioaddr +
+ SAA9730_LAN_REGS_ADDR);
+
+ /* Set SAA9730 EVM base address. */
+ lp->evm_saa9730_regs = (t_evm_saa9730_regmap *) (ioaddr +
+ SAA9730_EVM_REGS_ADDR);
+
+ /* Allocate LAN RX/TX frame buffer space. */
+ if (lan_saa9730_allocate_buffers(lp))
+ return -1;
+
+ /* Stop LAN controller. */
+ if (lan_saa9730_stop(lp))
+ return -1;
+
+ /* Initialize CAM registers. */
+ if (lan_saa9730_cam_init(dev))
+ return -1;
+
+ /* Initialize MII registers. */
+ if (lan_saa9730_mii_init(lp))
+ return -1;
+
+ /* Initialize control registers. */
+ if (lan_saa9730_control_init(lp))
+ return -1;
+
+ /* Load CAM registers. */
+ if (lan_saa9730_cam_load(lp))
+ return -1;
+
+ /* Initialize DMA context registers. */
+ if (lan_saa9730_dma_init(lp))
+ return -1;
+
+ dev->open = lan_saa9730_open;
+ dev->hard_start_xmit = lan_saa9730_start_xmit;
+ dev->stop = lan_saa9730_close;
+ dev->get_stats = lan_saa9730_get_stats;
+ dev->set_multicast_list = lan_saa9730_set_multicast;
+ dev->tx_timeout = lan_saa9730_tx_timeout;
+ dev->watchdog_timeo = (HZ >> 1);
+ dev->dma = 0;
+
+ return 0;
+}
+
+
+static int __init saa9730_probe(void)
+{
+ struct net_device *dev = NULL;
+
+ if (pci_present()) {
+ struct pci_dev *pdev = NULL;
+ if (lan_saa9730_debug > 1)
+ printk
+ ("saa9730.c: PCI bios is present, checking for devices...\n");
+
+ while ((pdev = pci_find_device(PCI_VENDOR_ID_PHILIPS,
+ PCI_DEVICE_ID_PHILIPS_SAA9730,
+ pdev))) {
+ unsigned int pci_ioaddr;
+
+ pci_irq_line = pdev->irq;
+ /* LAN base address in located at BAR 1. */
+
+ pci_ioaddr = pci_resource_start(pdev, 1);
+ pci_set_master(pdev);
+
+ printk("Found SAA9730 (PCI) at %#x, irq %d.\n",
+ pci_ioaddr, pci_irq_line);
+ if (!lan_saa9730_init
+ (dev, pci_ioaddr, pci_irq_line)) return 0;
+ else
+ printk("Lan init failed.\n");
+ }
+ }
+
+ return -ENODEV;
+}
+
+module_init(saa9730_probe);
--- /dev/null
+/*
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved.
+ *
+ * ########################################################################
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ *
+ * SAA9730 ethernet driver description.
+ *
+ */
+#ifndef _SAA9730_H
+#define _SAA9730_H
+
+
+/* Number of 6-byte entries in the CAM. */
+#define LAN_SAA9730_CAM_ENTRIES 10
+#define LAN_SAA9730_CAM_DWORDS ((LAN_SAA9730_CAM_ENTRIES*6)/4)
+
+/* TX and RX packet size: fixed to 2048 bytes, according to HW requirements. */
+#define LAN_SAA9730_PACKET_SIZE 2048
+
+/*
+ * Number of TX buffers = number of RX buffers = 2, which is fixed according
+ * to HW requirements.
+ */
+#define LAN_SAA9730_BUFFERS 2
+
+/* Number of RX packets per RX buffer. */
+#define LAN_SAA9730_RCV_Q_SIZE 15
+
+/* Number of TX packets per TX buffer. */
+#define LAN_SAA9730_TXM_Q_SIZE 15
+
+/*
+ * We get an interrupt for each LAN_SAA9730_DEFAULT_RCV_Q_INT_THRESHOLD
+ * packets received.
+ * If however we receive less than LAN_SAA9730_DEFAULT_RCV_Q_INT_THRESHOLD
+ * packets, the hardware can timeout after a certain time and still tell
+ * us packets have arrived.
+ * The timeout value in unit of 32 PCI clocks (33Mhz).
+ * The value 200 approximates 0.0002 seconds.
+ */
+#define LAN_SAA9730_RCV_Q_INT_THRESHOLD 1
+#define LAN_SAA9730_DEFAULT_TIME_OUT_CNT 10
+
+#define RXSF_NDIS 0
+#define RXSF_READY 2
+#define RXSF_HWDONE 3
+
+#define TXSF_EMPTY 0
+#define TXSF_READY 2
+#define TXSF_HWDONE 3
+
+#define LANEND_LITTLE 0
+#define LANEND_BIG_2143 1
+#define LANEND_BIG_4321 2
+
+#define LANMB_ANY 0
+#define LANMB_8 1
+#define LANMB_32 2
+#define LANMB_64 3
+
+#define MACCM_AUTOMATIC 0
+#define MACCM_10MB 1
+#define MACCM_MII 2
+
+/*
+ * PHY definitions for Basic registers of QS6612 (used on MIPS ATLAS board)
+ */
+#define PHY_CONTROL 0x0
+#define PHY_STATUS 0x1
+#define PHY_STATUS_LINK_UP 0x4
+#define PHY_CONTROL_RESET 0x8000
+#define PHY_CONTROL_AUTO_NEG 0x1000
+#define PHY_CONTROL_RESTART_AUTO_NEG 0x0200
+#define PHY_ADDRESS 0x0
+
+/* PK_COUNT register. */
+#define PK_COUNT_TX_A_SHF 24
+#define PK_COUNT_TX_A_MSK (0xff << PK_COUNT_TX_A_SHF)
+#define PK_COUNT_TX_B_SHF 16
+#define PK_COUNT_TX_B_MSK (0xff << PK_COUNT_TX_B_SHF)
+#define PK_COUNT_RX_A_SHF 8
+#define PK_COUNT_RX_A_MSK (0xff << PK_COUNT_RX_A_SHF)
+#define PK_COUNT_RX_B_SHF 0
+#define PK_COUNT_RX_B_MSK (0xff << PK_COUNT_RX_B_SHF)
+
+/* OK2USE register. */
+#define OK2USE_TX_A 0x8
+#define OK2USE_TX_B 0x4
+#define OK2USE_RX_A 0x2
+#define OK2USE_RX_B 0x1
+
+/* LAN DMA CONTROL register. */
+#define DMA_CTL_BLK_INT 0x80000000
+#define DMA_CTL_MAX_XFER_SHF 18
+#define DMA_CTL_MAX_XFER_MSK (0x3 << LAN_DMA_CTL_MAX_XFER_SHF)
+#define DMA_CTL_ENDIAN_SHF 16
+#define DMA_CTL_ENDIAN_MSK (0x3 << LAN_DMA_CTL_ENDIAN_SHF)
+#define DMA_CTL_RX_INT_COUNT_SHF 8
+#define DMA_CTL_RX_INT_COUNT_MSK (0xff << LAN_DMA_CTL_RX_INT_COUNT_SHF)
+#define DMA_CTL_EN_TX_DMA 0x00000080
+#define DMA_CTL_EN_RX_DMA 0x00000040
+#define DMA_CTL_RX_INT_BUFFUL_EN 0x00000020
+#define DMA_CTL_RX_INT_TO_EN 0x00000010
+#define DMA_CTL_RX_INT_EN 0x00000008
+#define DMA_CTL_TX_INT_EN 0x00000004
+#define DMA_CTL_MAC_TX_INT_EN 0x00000002
+#define DMA_CTL_MAC_RX_INT_EN 0x00000001
+
+/* DMA STATUS register. */
+#define DMA_STATUS_BAD_ADDR_SHF 16
+#define DMA_STATUS_BAD_ADDR_MSK (0xf << DMA_STATUS_BAD_ADDR_SHF)
+#define DMA_STATUS_RX_PKTS_RECEIVED_SHF 8
+#define DMA_STATUS_RX_PKTS_RECEIVED_MSK (0xff << DMA_STATUS_RX_PKTS_RECEIVED_SHF)
+#define DMA_STATUS_TX_EN_SYNC 0x00000080
+#define DMA_STATUS_RX_BUF_A_FUL 0x00000040
+#define DMA_STATUS_RX_BUF_B_FUL 0x00000020
+#define DMA_STATUS_RX_TO_INT 0x00000010
+#define DMA_STATUS_RX_INT 0x00000008
+#define DMA_STATUS_TX_INT 0x00000004
+#define DMA_STATUS_MAC_TX_INT 0x00000002
+#define DMA_STATUS_MAC_RX_INT 0x00000001
+
+/* DMA TEST/PANIC SWITHES register. */
+#define DMA_TEST_LOOPBACK 0x01000000
+#define DMA_TEST_SW_RESET 0x00000001
+
+/* MAC CONTROL register. */
+#define MAC_CONTROL_EN_MISS_ROLL 0x00002000
+#define MAC_CONTROL_MISS_ROLL 0x00000400
+#define MAC_CONTROL_LOOP10 0x00000080
+#define MAC_CONTROL_CONN_SHF 5
+#define MAC_CONTROL_CONN_MSK (0x3 << MAC_CONTROL_CONN_SHF)
+#define MAC_CONTROL_MAC_LOOP 0x00000010
+#define MAC_CONTROL_FULL_DUP 0x00000008
+#define MAC_CONTROL_RESET 0x00000004
+#define MAC_CONTROL_HALT_IMM 0x00000002
+#define MAC_CONTROL_HALT_REQ 0x00000001
+
+/* CAM CONTROL register. */
+#define CAM_CONTROL_COMP_EN 0x00000010
+#define CAM_CONTROL_NEG_CAM 0x00000008
+#define CAM_CONTROL_BROAD_ACC 0x00000004
+#define CAM_CONTROL_GROUP_ACC 0x00000002
+#define CAM_CONTROL_STATION_ACC 0x00000001
+
+/* TRANSMIT CONTROL register. */
+#define TX_CTL_EN_COMP 0x00004000
+#define TX_CTL_EN_TX_PAR 0x00002000
+#define TX_CTL_EN_LATE_COLL 0x00001000
+#define TX_CTL_EN_EX_COLL 0x00000800
+#define TX_CTL_EN_L_CARR 0x00000400
+#define TX_CTL_EN_EX_DEFER 0x00000200
+#define TX_CTL_EN_UNDER 0x00000100
+#define TX_CTL_MII10 0x00000080
+#define TX_CTL_SD_PAUSE 0x00000040
+#define TX_CTL_NO_EX_DEF0 0x00000020
+#define TX_CTL_F_BACK 0x00000010
+#define TX_CTL_NO_CRC 0x00000008
+#define TX_CTL_NO_PAD 0x00000004
+#define TX_CTL_TX_HALT 0x00000002
+#define TX_CTL_TX_EN 0x00000001
+
+/* TRANSMIT STATUS register. */
+#define TX_STATUS_SQ_ERR 0x00010000
+#define TX_STATUS_TX_HALTED 0x00008000
+#define TX_STATUS_COMP 0x00004000
+#define TX_STATUS_TX_PAR 0x00002000
+#define TX_STATUS_LATE_COLL 0x00001000
+#define TX_STATUS_TX10_STAT 0x00000800
+#define TX_STATUS_L_CARR 0x00000400
+#define TX_STATUS_EX_DEFER 0x00000200
+#define TX_STATUS_UNDER 0x00000100
+#define TX_STATUS_IN_TX 0x00000080
+#define TX_STATUS_PAUSED 0x00000040
+#define TX_STATUS_TX_DEFERRED 0x00000020
+#define TX_STATUS_EX_COLL 0x00000010
+#define TX_STATUS_TX_COLL_SHF 0
+#define TX_STATUS_TX_COLL_MSK (0xf << TX_STATUS_TX_COLL_SHF)
+
+/* RECEIVE CONTROL register. */
+#define RX_CTL_EN_GOOD 0x00004000
+#define RX_CTL_EN_RX_PAR 0x00002000
+#define RX_CTL_EN_LONG_ERR 0x00000800
+#define RX_CTL_EN_OVER 0x00000400
+#define RX_CTL_EN_CRC_ERR 0x00000200
+#define RX_CTL_EN_ALIGN 0x00000100
+#define RX_CTL_IGNORE_CRC 0x00000040
+#define RX_CTL_PASS_CTL 0x00000020
+#define RX_CTL_STRIP_CRC 0x00000010
+#define RX_CTL_SHORT_EN 0x00000008
+#define RX_CTL_LONG_EN 0x00000004
+#define RX_CTL_RX_HALT 0x00000002
+#define RX_CTL_RX_EN 0x00000001
+
+/* RECEIVE STATUS register. */
+#define RX_STATUS_RX_HALTED 0x00008000
+#define RX_STATUS_GOOD 0x00004000
+#define RX_STATUS_RX_PAR 0x00002000
+#define RX_STATUS_LONG_ERR 0x00000800
+#define RX_STATUS_OVERFLOW 0x00000400
+#define RX_STATUS_CRC_ERR 0x00000200
+#define RX_STATUS_ALIGN_ERR 0x00000100
+#define RX_STATUS_RX10_STAT 0x00000080
+#define RX_STATUS_INT_RX 0x00000040
+#define RX_STATUS_CTL_RECD 0x00000020
+
+/* MD_CA register. */
+#define MD_CA_PRE_SUP 0x00001000
+#define MD_CA_BUSY 0x00000800
+#define MD_CA_WR 0x00000400
+#define MD_CA_PHY_SHF 5
+#define MD_CA_PHY_MSK (0x1f << MD_CA_PHY_SHF)
+#define MD_CA_ADDR_SHF 0
+#define MD_CA_ADDR_MSK (0x1f << MD_CA_ADDR_SHF)
+
+/* Tx Status/Control. */
+#define TX_STAT_CTL_OWNER_SHF 30
+#define TX_STAT_CTL_OWNER_MSK (0x3 << TX_STAT_CTL_OWNER_SHF)
+#define TX_STAT_CTL_FRAME_SHF 27
+#define TX_STAT_CTL_FRAME_MSK (0x7 << TX_STAT_CTL_FRAME_SHF)
+#define TX_STAT_CTL_STATUS_SHF 11
+#define TX_STAT_CTL_STATUS_MSK (0x1ffff << TX_STAT_CTL_STATUS_SHF)
+#define TX_STAT_CTL_LENGTH_SHF 0
+#define TX_STAT_CTL_LENGTH_MSK (0x7ff << TX_STAT_CTL_LENGTH_SHF)
+
+#define TX_STAT_CTL_ERROR_MSK ((TX_STATUS_SQ_ERR | \
+ TX_STATUS_TX_HALTED | \
+ TX_STATUS_TX_PAR | \
+ TX_STATUS_LATE_COLL | \
+ TX_STATUS_L_CARR | \
+ TX_STATUS_EX_DEFER | \
+ TX_STATUS_UNDER | \
+ TX_STATUS_PAUSED | \
+ TX_STATUS_TX_DEFERRED | \
+ TX_STATUS_EX_COLL | \
+ TX_STATUS_TX_COLL_MSK) \
+ << TX_STAT_CTL_STATUS_SHF)
+#define TX_STAT_CTL_INT_AFTER_TX 0x4
+
+/* Rx Status/Control. */
+#define RX_STAT_CTL_OWNER_SHF 30
+#define RX_STAT_CTL_OWNER_MSK (0x3 << RX_STAT_CTL_OWNER_SHF)
+#define RX_STAT_CTL_STATUS_SHF 11
+#define RX_STAT_CTL_STATUS_MSK (0xffff << RX_STAT_CTL_STATUS_SHF)
+#define RX_STAT_CTL_LENGTH_SHF 0
+#define RX_STAT_CTL_LENGTH_MSK (0x7ff << RX_STAT_CTL_LENGTH_SHF)
+
+
+
+/* The SAA9730 (LAN) controller register map, as seen via the PCI-bus. */
+#define SAA9730_LAN_REGS_ADDR 0x20400
+
+struct lan_saa9730_regmap {
+ volatile unsigned int TxBuffA; /* 0x20400 */
+ volatile unsigned int TxBuffB; /* 0x20404 */
+ volatile unsigned int RxBuffA; /* 0x20408 */
+ volatile unsigned int RxBuffB; /* 0x2040c */
+ volatile unsigned int PacketCount; /* 0x20410 */
+ volatile unsigned int Ok2Use; /* 0x20414 */
+ volatile unsigned int LanDmaCtl; /* 0x20418 */
+ volatile unsigned int Timeout; /* 0x2041c */
+ volatile unsigned int DmaStatus; /* 0x20420 */
+ volatile unsigned int DmaTest; /* 0x20424 */
+ volatile unsigned char filler20428[0x20430 - 0x20428];
+ volatile unsigned int PauseCount; /* 0x20430 */
+ volatile unsigned int RemotePauseCount; /* 0x20434 */
+ volatile unsigned char filler20438[0x20440 - 0x20438];
+ volatile unsigned int MacCtl; /* 0x20440 */
+ volatile unsigned int CamCtl; /* 0x20444 */
+ volatile unsigned int TxCtl; /* 0x20448 */
+ volatile unsigned int TxStatus; /* 0x2044c */
+ volatile unsigned int RxCtl; /* 0x20450 */
+ volatile unsigned int RxStatus; /* 0x20454 */
+ volatile unsigned int StationMgmtData; /* 0x20458 */
+ volatile unsigned int StationMgmtCtl; /* 0x2045c */
+ volatile unsigned int CamAddress; /* 0x20460 */
+ volatile unsigned int CamData; /* 0x20464 */
+ volatile unsigned int CamEnable; /* 0x20468 */
+ volatile unsigned char filler2046c[0x20500 - 0x2046c];
+ volatile unsigned int DebugPCIMasterAddr; /* 0x20500 */
+ volatile unsigned int DebugLanTxStateMachine; /* 0x20504 */
+ volatile unsigned int DebugLanRxStateMachine; /* 0x20508 */
+ volatile unsigned int DebugLanTxFifoPointers; /* 0x2050c */
+ volatile unsigned int DebugLanRxFifoPointers; /* 0x20510 */
+ volatile unsigned int DebugLanCtlStateMachine; /* 0x20514 */
+};
+typedef volatile struct lan_saa9730_regmap t_lan_saa9730_regmap;
+
+
+/* EVM interrupt control registers. */
+#define EVM_LAN_INT 0x00010000
+#define EVM_MASTER_EN 0x00000001
+
+/* The SAA9730 (EVM) controller register map, as seen via the PCI-bus. */
+#define SAA9730_EVM_REGS_ADDR 0x02000
+
+struct evm_saa9730_regmap {
+ volatile unsigned int InterruptStatus1; /* 0x2000 */
+ volatile unsigned int InterruptEnable1; /* 0x2004 */
+ volatile unsigned int InterruptMonitor1; /* 0x2008 */
+ volatile unsigned int Counter; /* 0x200c */
+ volatile unsigned int CounterThreshold; /* 0x2010 */
+ volatile unsigned int CounterControl; /* 0x2014 */
+ volatile unsigned int GpioControl1; /* 0x2018 */
+ volatile unsigned int InterruptStatus2; /* 0x201c */
+ volatile unsigned int InterruptEnable2; /* 0x2020 */
+ volatile unsigned int InterruptMonitor2; /* 0x2024 */
+ volatile unsigned int GpioControl2; /* 0x2028 */
+ volatile unsigned int InterruptBlock1; /* 0x202c */
+ volatile unsigned int InterruptBlock2; /* 0x2030 */
+};
+typedef volatile struct evm_saa9730_regmap t_evm_saa9730_regmap;
+
+
+struct lan_saa9730_private {
+ /* Pointer for the SAA9730 LAN controller register set. */
+ t_lan_saa9730_regmap *lan_saa9730_regs;
+
+ /* Pointer to the SAA9730 EVM register. */
+ t_evm_saa9730_regmap *evm_saa9730_regs;
+
+ /* TRUE if the next buffer to write is RxBuffA, FALSE if RxBuffB. */
+ unsigned char NextRcvToUseIsA;
+ /* Rcv buffer Index. */
+ unsigned char NextRcvPacketIndex;
+
+ /* Index of next packet to use in that buffer. */
+ unsigned char NextTxmPacketIndex;
+ /* Next buffer index. */
+ unsigned char NextTxmBufferIndex;
+
+ /* Index of first pending packet ready to send. */
+ unsigned char PendingTxmPacketIndex;
+ /* Pending buffer index. */
+ unsigned char PendingTxmBufferIndex;
+
+ unsigned char DmaRcvPackets;
+ unsigned char DmaTxmPackets;
+
+ unsigned char RcvAIndex; /* index into RcvBufferSpace[] for Blk A */
+ unsigned char RcvBIndex; /* index into RcvBufferSpace[] for Blk B */
+
+ unsigned int
+ TxmBuffer[LAN_SAA9730_BUFFERS][LAN_SAA9730_TXM_Q_SIZE];
+ unsigned int
+ RcvBuffer[LAN_SAA9730_BUFFERS][LAN_SAA9730_RCV_Q_SIZE];
+ unsigned int TxBufferFree[LAN_SAA9730_BUFFERS];
+
+ unsigned char PhysicalAddress[LAN_SAA9730_CAM_ENTRIES][6];
+
+ struct net_device_stats stats;
+};
+
+#endif /* _SAA9730_H */
return (POSITIVE_ACK);
}
-/* Reset the ring speed to the oposite of what it was. This auto-pilot
+/* Reset the ring speed to the opposite of what it was. This auto-pilot
* mode requires a complete reset and re-init of the adapter.
*/
static int smctr_set_ring_speed(struct net_device *dev)
#
obj-$(CONFIG_ALPHA) += setup-bus.o setup-irq.o
obj-$(CONFIG_ARM) += setup-bus.o setup-irq.o
+obj-$(CONFIG_SUPERH) += setup-bus.o setup-irq.o
ifndef CONFIG_X86
obj-y += syscall.o
* Architecture :
* This driver is built around a Linux queue of commands waiting to
* be executed, and a shared Linux/NCR array of commands to start. Commands
- * are transfered to the array by the run_process_issue_queue() function
+ * are transferred to the array by the run_process_issue_queue() function
* which is called whenever a command completes.
*
* As commands are completed, the interrupt routine is triggered,
{
printk("scsi%d : IRQ%d not free, detaching\n",
host->host_no, host->irq);
- scsi_unregister (host);
- return -1;
+ goto err_unregister;
}
if ((hostdata->run_tests && hostdata->run_tests(host) == -1) ||
(hostdata->options & OPTION_DEBUG_TESTS_ONLY)) {
/* XXX Should disable interrupts, etc. here */
- scsi_unregister (host);
- return -1;
+ goto err_free_irq;
} else {
if (host->io_port) {
host->n_io_port = 128;
- request_region (host->io_port, host->n_io_port, "ncr53c7xx");
+ if (!request_region (host->io_port, host->n_io_port, "ncr53c7xx"))
+ goto err_free_irq;
}
}
hard_reset (host);
}
return 0;
+
+ err_free_irq:
+ free_irq(host->irq, NCR53c7x0_intr);
+ err_unregister:
+ scsi_unregister(host);
+ return -1;
}
/*
size += 256;
#endif
/* Size should be < 8K, so we can fit it in two pages. */
- if (size > 8192)
- panic("53c7xx: hostdata > 8K");
+ if (size > 8192) {
+ printk(KERN_ERR "53c7xx: hostdata > 8K\n");
+ return -1;
+ }
+
instance = scsi_register (tpnt, 4);
if (!instance)
{
#endif
/* FIXME: for ISA bus '7xx chips, we need to or GFP_DMA in here */
- if (size > 4096)
- panic ("53c7xx: allocate_cmd size > 4K");
+ if (size > 4096) {
+ printk (KERN_ERR "53c7xx: allocate_cmd size > 4K\n");
+ return NULL;
+ }
real = get_free_page(GFP_ATOMIC);
if (real == 0)
return NULL;
/*
* The saved data pointer is set up so that a RESTORE POINTERS message
- * will start the data transfer over at the begining.
+ * will start the data transfer over at the beginning.
*/
tmp->saved_data_pointer = virt_to_bus (hostdata->script) +
* chances of this happening, and handle it if it occurs anyway.
*
* Simply continue with what we were doing, and control should
- * be transfered to the schedule routine which will ultimately
+ * be transferred to the schedule routine which will ultimately
* pass control onto the reselection or selection (not yet)
* code.
*/
#if (CHIP == 710)
#if defined(MVME16x_INTFLY)
; For MVME16x (ie CHIP=710) we will force an INTFLY by triggering a software
-; interupt (SW7). We can use SCRATCH, as we are about to jump to
+; interrupt (SW7). We can use SCRATCH, as we are about to jump to
; schedule, which corrupts it anyway. Will probably remove this later,
; but want to check performance effects first.
* Changed megaraid_command to use wait_queue.
*
* Version 1.00:
- * Checks to see if an irq ocurred while in isr, and runs through
+ * Checks to see if an irq occurred while in isr, and runs through
* routine again.
* Copies mailbox to temp area before processing in isr
* Added barrier() in busy wait to fix volatility bug
* Left 2.0 support but removed 2.1.x support.
* Collected much of the compat glue into one spot
*
+ * Version 1.14g-ac2 - 22/03/01
+ * Fixed a non obvious dereference after free in the driver unload path
+ *
* BUGS:
* Some older 2.1 kernels (eg. 2.1.90) have a bug in pci.c that
* fails to detect the controller as a pci device on the system.
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) /* 0x020200 */
+#include <linux/smp.h>
+#define cpuid smp_processor_id()
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) /* 0x020100 */
/*
- * Linux 2.2 and higher
+ * Linux 2.4 and higher
*
* No driver private lock
* Use the io_request_lock not cli/sti
* queue task is a simple api without irq forms
*/
-
-#include <linux/smp.h>
-#define cpuid smp_processor_id()
MODULE_AUTHOR ("American Megatrends Inc.");
MODULE_DESCRIPTION ("AMI MegaRAID driver");
#define IO_LOCK spin_lock_irqsave(&io_request_lock,io_flags);
#define IO_UNLOCK spin_unlock_irqrestore(&io_request_lock,io_flags);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) /* 0x020400 */
+#define queue_task_irq(a,b) queue_task(a,b)
+#define queue_task_irq_off(a,b) queue_task(a,b)
+
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) /* 0x020200 */
+
+/*
+ * Linux 2.2 and higher
+ *
+ * No driver private lock
+ * Use the io_request_lock not cli/sti
+ * No pci region api
+ * queue_task is now a single simple API
+ */
+
+static char kernel_version[] = UTS_RELEASE;
+MODULE_AUTHOR ("American Megatrends Inc.");
+MODULE_DESCRIPTION ("AMI MegaRAID driver");
+
+#define DRIVER_LOCK_T
+#define DRIVER_LOCK_INIT(p)
+#define DRIVER_LOCK(p)
+#define DRIVER_UNLOCK(p)
+#define IO_LOCK_T unsigned long io_flags = 0;
+#define IO_LOCK spin_lock_irqsave(&io_request_lock,io_flags);
+#define IO_UNLOCK spin_unlock_irqrestore(&io_request_lock,io_flags);
+
#define pci_free_consistent(a,b,c,d)
#define pci_unmap_single(a,b,c,d,e)
#define init_MUTEX_LOCKED(x) ((x)=MUTEX_LOCKED)
#define init_MUTEX(x) ((x)=MUTEX)
-#define DECLARE_WAIT_QUEUE_HEAD(x) struct wait_queue *x = NULL
-#endif
-
#define queue_task_irq(a,b) queue_task(a,b)
#define queue_task_irq_off(a,b) queue_task(a,b)
+
+#define DECLARE_WAIT_QUEUE_HEAD(x) struct wait_queue *x = NULL
#else
/*
sizeof (mega_mailbox64),
(void *) megaCfg->mailbox64ptr,
megaCfg->dma_handle64);
- scsi_unregister (pSHost);
#ifdef CONFIG_PROC_FS
if (megaCfg->controller_proc_dir_entry) {
#endif
/*
+ * Release the controller memory. A word of warning this frees
+ * hostdata and that includes megaCfg-> so be careful what you
+ * dereference beyond this point
+ */
+
+ scsi_unregister (pSHost);
+
+ /*
* Unregister the character device interface to the driver. Ideally this
* should have been done in cleanup_module routine. Since this is hidden
* in file "scsi_module.c", we do it here.
* major is the major number of the character device returned by call to
* register_chrdev() routine.
*/
+
unregister_chrdev (major, "megadev");
unregister_reboot_notifier (&mega_notifier);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
static
-#endif
+#endif /* LINUX VERSION 2.4.XX */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) || defined(MODULE)
Scsi_Host_Template driver_template = MEGARAID;
+
#include "scsi_module.c"
-#endif
+#endif /* LINUX VERSION 2.4.XX || MODULE */
#define M_RD_IOCTL_CMD_NEW 0x81
#define M_RD_DRIVER_IOCTL_INTERFACE 0x82
-#define MEGARAID_VERSION "v1.14g (Release Date: Feb 5, 2001; 11:42)"
+#define MEGARAID_VERSION "v1.14g-ac2 (Release Date: Mar 22, 2001; 19:34:02)"
#define MEGARAID_IOCTL_VERSION 114
/* Methods */
#define FLASH_BIOS_ADDR 0x00
#define FLASH_BIOS_DATA 0x02
#define ISP_CTRL_STATUS 0x06 /* configuration register #1 */
-#define PCI_INTER_CTL 0x08 /* pci interupt control */
-#define PCI_INTER_STS 0x0a /* pci interupt status */
+#define PCI_INTER_CTL 0x08 /* pci interrupt control */
+#define PCI_INTER_STS 0x0a /* pci interrupt status */
#define PCI_SEMAPHORE 0x0c /* pci semaphore */
#define PCI_NVRAM 0x0e /* pci nvram interface */
#define REQUEST_TRANSFER_ERROR 0x8003
#define RESPONSE_TRANSFER_ERROR 0x8004
#define REQUEST_QUEUE_WAKEUP 0x8005
-#define LIP_OCCURED 0x8010
+#define LIP_OCCURRED 0x8010
#define LOOP_UP 0x8011
#define LOOP_DOWN 0x8012
#define LIP_RECEIVED 0x8013
#define STF_ABORTED 0x0020
#define STF_TIMEOUT 0x0040
-/* interupt control commands */
+/* interrupt control commands */
#define ISP_EN_INT 0x8000
#define ISP_EN_RISC 0x0008
continue;
host = scsi_register(tmpt, sizeof(struct isp2x00_hostdata));
+ if (!host) {
+ printk("qlogicfc%d : could not register host.\n", hostdata->host_id);
+ continue;
+ }
host->max_id = QLOGICFC_MAX_ID + 1;
host->max_lun = QLOGICFC_MAX_LUN;
host->hostt->use_new_eh_code = 1;
if (!hostdata->res){
printk("qlogicfc%d : could not allocate memory for request and response queue.\n", hostdata->host_id);
+ pci64_free_consistent(pdev, RES_SIZE + REQ_SIZE, hostdata->res, busaddr);
scsi_unregister(host);
continue;
}
scsi_unregister(host);
continue;
}
- if (check_region(host->io_port, 0xff)) {
+ if (!request_region(host->io_port, 0xff, "qlogicfc")) {
printk("qlogicfc%d : i/o region 0x%lx-0x%lx already "
"in use\n",
hostdata->host_id, host->io_port, host->io_port + 0xff);
scsi_unregister(host);
continue;
}
- request_region(host->io_port, 0xff, "qlogicfc");
outw(0x0, host->io_port + PCI_SEMAPHORE);
outw(HCCR_CLEAR_RISC_INTR, host->io_port + HOST_HCCR);
if (hostdata->adapter_state == AS_LOOP_GOOD)
hostdata->adapter_state = AS_REDO_FABRIC_PORTDB;
break;
- case LIP_OCCURED:
+ case LIP_OCCURRED:
case LIP_RECEIVED:
printk("qlogicfc%d : Loop Reinitialized\n", hostdata->host_id);
if (hostdata->adapter_state == AS_LOOP_GOOD)
#
# Note 2! The CFLAGS definitions are now in the main makefile...
-SUB_DIRS :=
-MOD_SUB_DIRS := $(SUB_DIRS) char
-ALL_SUB_DIRS := $(SUB_DIRS) char
-
-
-L_OBJS :=
L_TARGET := sgi.a
+#
# Character and Audio devices for SGI machines.
#
-SUB_DIRS += char
-L_OBJS += char/sgichar.o
+subdir-y += char
+subdir-m += char
+obj-y += char/sgichar.o
include $(TOPDIR)/Rules.make
# Note 2! The CFLAGS definitions are now in the main makefile...
O_TARGET := sgichar.o
-OX_OBJS := newport.o
-O_OBJS := sgicons.o \
- usema.o shmiq.o streamable.o
-ifeq ($(CONFIG_SGI_SERIAL),y)
- O_OBJS += sgiserial.o
-endif
+export-objs := newport.o shmiq.o sgicons.o usema.o
+obj-y := newport.o shmiq.o sgicons.o usema.o streamable.o
-ifeq ($(CONFIG_SGI_DS1286),y)
- O_OBJS += ds1286.o
-endif
-
-ifeq ($(CONFIG_SGI_NEWPORT_GFX),y)
- O_OBJS += graphics.o rrm.o
-else
-ifeq ($(CONFIG_SGI_NEWPORT_GFX),m)
- OX_OBJS += graphics_syms.o
- MX_OBJS += graphics.o rrm.o
-endif
-endif
+obj-$(CONFIG_SGI_SERIAL) += sgiserial.o
+obj-$(CONFIG_SGI_DS1286) += ds1286.o
+obj-$(CONFIG_SGI_NEWPORT_GFX) += graphics.o rrm.o
include $(TOPDIR)/Rules.make
fi
dep_tristate ' Aztech Sound Galaxy (non-PnP) cards' CONFIG_SOUND_SGALAXY $CONFIG_SOUND_OSS
dep_tristate ' Adlib Cards' CONFIG_SOUND_ADLIB $CONFIG_SOUND_OSS
- dep_tristate ' ACI mixer (miroPCM12)' CONFIG_SOUND_ACI_MIXER $CONFIG_SOUND_OSS
+ dep_tristate ' ACI mixer (miroSOUND PCM1-pro/PCM12/PCM20)' CONFIG_SOUND_ACI_MIXER $CONFIG_SOUND_OSS
dep_tristate ' Crystal CS4232 based (PnP) cards' CONFIG_SOUND_CS4232 $CONFIG_SOUND_OSS
dep_tristate ' Ensoniq SoundScape support' CONFIG_SOUND_SSCAPE $CONFIG_SOUND_OSS
dep_tristate ' Gravis Ultrasound support' CONFIG_SOUND_GUS $CONFIG_SOUND_OSS
fi
if [ "$CONFIG_ARM" = "y" ]; then
- dep_tristate ' VIDC 16-bit sound' CONFIG_SOUND_VIDC $CONFIG_SOUND_OSS
- dep_tristate ' Netwinder WaveArtist' CONFIG_SOUND_WAVEARTIST $CONFIG_SOUND_OSS
+ if [ "$CONFIG_ARCH_ACORN" = "y" -o "$CONFIG_ARCH_CLPS7500" = "y" ]; then
+ dep_tristate ' VIDC 16-bit sound' CONFIG_SOUND_VIDC $CONFIG_SOUND_OSS
+ fi
+ dep_tristate ' Netwinder WaveArtist' CONFIG_SOUND_WAVEARTIST $CONFIG_SOUND_OSS $CONFIG_ARCH_NETWINDER
fi
fi
export-objs := ad1848.o audio_syms.o midi_syms.o mpu401.o \
msnd.o opl3.o sb_common.o sequencer_syms.o \
sound_core.o sound_syms.o uart401.o \
- nm256_audio.o ac97.o ac97_codec.o
+ nm256_audio.o ac97.o ac97_codec.o aci.o
# Each configuration option enables a list of files.
obj-$(CONFIG_SOUND_CS4232) += cs4232.o uart401.o
obj-$(CONFIG_SOUND_OPL3SA2) += opl3sa2.o ad1848.o mpu401.o
obj-$(CONFIG_SOUND_MSS) += ad1848.o
-obj-$(CONFIG_SOUND_PAS) += pas2.o sb_lib.o uart401.o
+obj-$(CONFIG_SOUND_PAS) += pas2.o sb.o sb_lib.o uart401.o
obj-$(CONFIG_SOUND_SB) += sb.o sb_lib.o uart401.o
obj-$(CONFIG_SOUND_WAVEFRONT) += wavefront.o
obj-$(CONFIG_SOUND_MAUI) += maui.o mpu401.o
* The main function of the ACI is to control the mixer and to get a
* product identification. On the PCM20, ACI also controls the radio
* tuner on this card, this is supported in the Video for Linux
- * radio-miropcm20 driver.
- *
- * This Voxware ACI driver currently only supports the ACI functions
- * on the miroSOUND PCM12 and PCM20 card. Support for miro sound cards
- * with additional ACI functions can easily be added later.
+ * miropcm20 driver.
+ * -
+ * This is a fullfeatured implementation. Unsupported features
+ * are bugs... (:
+ *
+ * It is not longer necessary to load the mad16 module first. The
+ * user is currently responsible to set the mad16 mixer correctly.
*
- * / NOTE / When compiling as a module, make sure to load the module
- * after loading the mad16 module. The initialisation code expects the
- * MAD16 default mixer to be already available.
+ * To toggle the solo mode for full duplex operation just use the OSS
+ * record switch for the pcm ('wave') controller. Robert
+ * -
*
* Revision history:
*
* 1998-08-18 Ruurd Reitsma <R.A.Reitsma@wbmt.tudelft.nl>
* Small modification to export ACI functions and
* complete modularisation.
+ * 2000-06-20 Robert Siemer <Robert.Siemer@gmx.de>
+ * Don't initialize the CS4231A mixer anymore, so the code is
+ * working again, and other small changes to fit in todays
+ * kernels.
+ * 2000-08-26 Robert Siemer
+ * Clean up and rewrite for 2.4.x. Maybe it's SMP safe now... (:
+ * ioctl bugfix, and integration of solo-mode into OSS-API,
+ * added (OSS-limited) equalizer support, return value bugfix,
+ * changed param aci_reset to reset, new params: ide, wss.
*/
-/*
- * Some driver specific information and features:
- *
- * This mixer driver identifies itself to applications as "ACI" in
- * mixer_info.id as retrieved by ioctl(fd, SOUND_MIXER_INFO, &mixer_info).
- *
- * Proprietary mixer features that go beyond the standard OSS mixer
- * interface are:
- *
- * Full duplex solo configuration:
- *
- * int solo_mode;
- * ioctl(fd, SOUND_MIXER_PRIVATE1, &solo_mode);
- *
- * solo_mode = 0: deactivate solo mode (default)
- * solo_mode > 0: activate solo mode
- * With activated solo mode, the PCM input can not any
- * longer hear the signals produced by the PCM output.
- * Activating solo mode is important in duplex mode in order
- * to avoid feedback distortions.
- * solo_mode < 0: do not change solo mode (just retrieve the status)
- *
- * When the ioctl() returns 0, solo_mode contains the previous
- * status (0 = deactivated, 1 = activated). If solo mode is not
- * implemented on this card, ioctl() returns -1 and sets errno to
- * EINVAL.
- *
- */
-
+#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
-
+#include <linux/proc_fs.h>
+#include <linux/slab.h>
+#include <asm/semaphore.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
#include "sound_config.h"
-#undef DEBUG /* if defined, produce a verbose report via syslog */
+int aci_port; /* as determined by bit 4 in the OPTi 929 MC4 register */
+int aci_idcode[2]; /* manufacturer and product ID */
+int aci_version; /* ACI firmware version */
+
+EXPORT_SYMBOL(aci_port);
+EXPORT_SYMBOL(aci_idcode);
+EXPORT_SYMBOL(aci_version);
-int aci_port = 0x354; /* as determined by bit 4 in the OPTi 929 MC4 register */
-unsigned char aci_idcode[2] = {0, 0}; /* manufacturer and product ID */
-unsigned char aci_version = 0; /* ACI firmware version */
-int aci_solo; /* status bit of the card that can't be *
+#include "aci.h"
+
+
+static int aci_solo=0; /* status bit of the card that can't be *
+ * checked with ACI versions prior to 0xb0 */
+static int aci_amp=0; /* status bit for power-amp/line-out level
+ but I have no docs about what is what... */
+static int aci_micpreamp=3; /* microphone preamp-level that can't be *
* checked with ACI versions prior to 0xb0 */
-static int aci_present = 0;
+static int mixer_device;
+static struct semaphore aci_sem;
-#ifdef MODULE /* Whether the aci mixer is to be reset. */
-int aci_reset = 0; /* Default: don't reset if the driver is a */
-MODULE_PARM(aci_reset,"i");
-#else /* module; use "insmod aci.o aci_reset=1" */
-int aci_reset = 1; /* to override. */
+#ifdef MODULE
+static int reset = 0;
+MODULE_PARM(reset,"i");
+MODULE_PARM_DESC(reset,"When set to 1, reset aci mixer.");
+#else
+static int reset = 1;
#endif
+static int ide=-1;
+MODULE_PARM(ide,"i");
+MODULE_PARM_DESC(ide,"1 enable, 0 disable ide-port - untested"
+ " default: do nothing");
+static int wss=-1;
+MODULE_PARM(wss,"i");
+MODULE_PARM_DESC(wss,"change between ACI/WSS-mixer; use 0 and 1 - untested"
+ " default: do nothing; for PCM1-pro only");
+
+static void print_bits(unsigned char c)
+{
+ int j;
+ printk(KERN_DEBUG "aci: ");
+
+ for (j=7; j>=0; j--) {
+ printk(KERN_DEBUG "%d", (c >> j) & 0x1);
+ }
-#define COMMAND_REGISTER (aci_port)
-#define STATUS_REGISTER (aci_port + 1)
-#define BUSY_REGISTER (aci_port + 2)
+ printk(KERN_DEBUG "\n");
+}
/*
- * Wait until the ACI microcontroller has set the READYFLAG in the
- * Busy/IRQ Source Register to 0. This is required to avoid
- * overrunning the sound card microcontroller. We do a busy wait here,
- * because the microcontroller is not supposed to signal a busy
- * condition for more than a few clock cycles. In case of a time-out,
- * this function returns -1.
- *
* This busy wait code normally requires less than 15 loops and
* practically always less than 100 loops on my i486/DX2 66 MHz.
*
* function can take a VERY long time, because the PCM12 does some kind
* of fade-in effect. For this reason, access to the MUTE function has
* not been implemented at all.
+ *
+ * - The OSS interface has no mute option. It takes about 3 seconds to
+ * fade-in on my PCM20. busy_wait() handles it great now... Robert
*/
static int busy_wait(void)
{
+ #define MINTIME 500
long timeout;
+ unsigned char byte;
- for (timeout = 0; timeout < 10000000L; timeout++)
- if ((inb_p(BUSY_REGISTER) & 1) == 0)
- return 0;
-
-#ifdef DEBUG
- printk("ACI: READYFLAG timed out.\n");
-#endif
-
- return -1;
-}
-
-
-/*
- * Read the GENERAL STATUS register.
- */
-
-static int read_general_status(void)
-{
- unsigned long flags;
- int status;
-
- save_flags(flags);
- cli();
-
- if (busy_wait()) {
- restore_flags(flags);
- return -1;
+ for (timeout = 1; timeout <= MINTIME+30; timeout++) {
+ if (((byte=inb(BUSY_REGISTER)) & 1) == 0) {
+ if (timeout >= MINTIME)
+ printk(KERN_DEBUG "aci: Got READYFLAG in round %ld.\n", timeout-MINTIME);
+ return byte;
+ }
+ if (timeout >= MINTIME) {
+ long out=10*HZ;
+ switch (timeout-MINTIME) {
+ case 0 ... 9:
+ out /= 10;
+ case 10 ... 19:
+ out /= 10;
+ case 20 ... 30:
+ out /= 10;
+ default:
+ current->state=TASK_UNINTERRUPTIBLE;
+ schedule_timeout(out);
+ break;
+ }
+ }
}
-
- status = (unsigned) inb_p(STATUS_REGISTER);
- restore_flags(flags);
- return status;
+ printk(KERN_WARNING "aci: busy_wait() time out.\n");
+ return -EBUSY;
}
+/* The four ACI command types are fucked up. [-:
+ * implied is: 1w - special case for INIT
+ * write is: 2w1r
+ * read is: x(1w1r) where x is 1 or 2 (1 CHECK_SIG, 1 CHECK_STER,
+ * 1 VERSION, 2 IDCODE)
+ * the command is only in the first write, rest is protocol overhead
+ *
+ * indexed is technically a write and used for STATUS
+ * and the special case for TUNE is: 3w1r
+ *
+ * Here the new general sheme: TUNE --> aci_rw_cmd(x, y, z)
+ * indexed and write --> aci_rw_cmd(x, y, -1)
+ * implied and read (x=1) --> aci_rw_cmd(x, -1, -1)
+ *
+ * Read (x>=2) is not implemented (only used during initialization).
+ * Use aci_idcode[2] and aci_version... Robert
+ */
-/*
- * The four ACI command types (implied, write, read and indexed) can
- * be sent to the microcontroller using the following four functions.
- * If a problem occurred, they return -1.
+/* Some notes for error detection: theoretically it is possible.
+ * But it doubles the I/O-traffic from ww(r) to wwwrw(r) in the normal
+ * case and doesn't seem to be designed for that... Robert
*/
-int aci_implied_cmd(unsigned char opcode)
+static inline int aci_rawwrite(unsigned char byte)
{
- unsigned long flags;
-
-#ifdef DEBUG
- printk("ACI: aci_implied_cmd(0x%02x)\n", opcode);
+ if (busy_wait() >= 0) {
+#if DEBUG
+ printk(KERN_DEBUG "aci_rawwrite(%d)\n", byte);
#endif
-
- save_flags(flags);
- cli();
-
- if (read_general_status() < 0 || busy_wait()) {
- restore_flags(flags);
- return -1;
- }
-
- outb_p(opcode, COMMAND_REGISTER);
-
- restore_flags(flags);
- return 0;
+ outb(byte, COMMAND_REGISTER);
+ return 0;
+ } else
+ return -EBUSY;
}
-
-int aci_write_cmd(unsigned char opcode, unsigned char parameter)
+static inline int aci_rawread(void)
{
- unsigned long flags;
- int status;
+ unsigned char byte;
-#ifdef DEBUG
- printk("ACI: aci_write_cmd(0x%02x, 0x%02x)\n", opcode, parameter);
+ if (busy_wait() >= 0) {
+ byte=inb(STATUS_REGISTER);
+#if DEBUG
+ printk(KERN_DEBUG "%d = aci_rawread()\n", byte);
#endif
+ return byte;
+ } else
+ return -EBUSY;
+}
- save_flags(flags);
- cli();
-
- if (read_general_status() < 0 || busy_wait()) {
- restore_flags(flags);
- return -1;
- }
- outb_p(opcode, COMMAND_REGISTER);
- if (busy_wait()) {
- restore_flags(flags);
- return -1;
- }
+int aci_rw_cmd(int write1, int write2, int write3)
+{
+ int write[] = {write1, write2, write3};
+ int read, i;
- outb_p(parameter, COMMAND_REGISTER);
+ if (down_interruptible(&aci_sem))
+ return -EINTR;
- if ((status = read_general_status()) < 0) {
- restore_flags(flags);
- return -1;
+ for (i=0; i<3; i++) {
+ if (write[i]< 0 || write[i] > 255)
+ break;
+ else
+ if (aci_rawwrite(write[i])<0) {
+ up(&aci_sem);
+ return -EBUSY;
+ }
}
-
- /* polarity of the INVALID flag depends on ACI version */
- if ((aci_version < 0xb0 && (status & 0x40) != 0) ||
- (aci_version >= 0xb0 && (status & 0x40) == 0)) {
- restore_flags(flags);
- printk("ACI: invalid write command 0x%02x, 0x%02x.\n",
- opcode, parameter);
- return -1;
+
+ if ((read=aci_rawread())<0) {
+ up(&aci_sem);
+ return -EBUSY;
}
- restore_flags(flags);
- return 0;
+ up(&aci_sem);
+ return read;
}
-/*
- * This write command send 2 parameters instead of one.
- * Only used in PCM20 radio frequency tuning control
- */
+EXPORT_SYMBOL(aci_rw_cmd);
-int aci_write_cmd_d(unsigned char opcode, unsigned char parameter, unsigned char parameter2)
+static int setvolume(caddr_t arg,
+ unsigned char left_index, unsigned char right_index)
{
- unsigned long flags;
- int status;
+ int vol, ret, uservol, buf;
-#ifdef DEBUG
- printk("ACI: aci_write_cmd_d(0x%02x, 0x%02x)\n", opcode, parameter, parameter2);
-#endif
+ __get_user(uservol, (int *)arg);
- save_flags(flags);
- cli();
-
- if (read_general_status() < 0 || busy_wait()) {
- restore_flags(flags);
- return -1;
- }
+ /* left channel */
+ vol = uservol & 0xff;
+ if (vol > 100)
+ vol = 100;
+ vol = SCALE(100, 0x20, vol);
+ if ((buf=aci_write_cmd(left_index, 0x20 - vol))<0)
+ return buf;
+ ret = SCALE(0x20, 100, vol);
- outb_p(opcode, COMMAND_REGISTER);
- if (busy_wait()) {
- restore_flags(flags);
- return -1;
- }
- outb_p(parameter, COMMAND_REGISTER);
- if (busy_wait()) {
- restore_flags(flags);
- return -1;
- }
-
- outb_p(parameter2, COMMAND_REGISTER);
-
- if ((status = read_general_status()) < 0) {
- restore_flags(flags);
- return -1;
- }
-
- /* polarity of the INVALID flag depends on ACI version */
- if ((aci_version < 0xb0 && (status & 0x40) != 0) ||
- (aci_version >= 0xb0 && (status & 0x40) == 0)) {
- restore_flags(flags);
-#if 0 /* Frequency tuning works, but the INVALID flag is set ??? */
- printk("ACI: invalid write (double) command 0x%02x, 0x%02x, 0x%02x.\n",
- opcode, parameter, parameter2);
-#endif
- return -1;
- }
-
- restore_flags(flags);
- return 0;
-}
-
-int aci_read_cmd(unsigned char opcode, int length, unsigned char *parameter)
-{
- unsigned long flags;
- int i = 0;
-
- save_flags(flags);
- cli();
+ /* right channel */
+ vol = (uservol >> 8) & 0xff;
+ if (vol > 100)
+ vol = 100;
+ vol = SCALE(100, 0x20, vol);
+ if ((buf=aci_write_cmd(right_index, 0x20 - vol))<0)
+ return buf;
+ ret |= SCALE(0x20, 100, vol) << 8;
- if (read_general_status() < 0) {
- restore_flags(flags);
- return -1;
- }
- while (i < length) {
- if (busy_wait()) {
- restore_flags(flags);
- return -1;
- }
-
- outb_p(opcode, COMMAND_REGISTER);
- if (busy_wait()) {
- restore_flags(flags);
- return -1;
- }
-
- parameter[i++] = inb_p(STATUS_REGISTER);
-#ifdef DEBUG
- if (i == 1)
- printk("ACI: aci_read_cmd(0x%02x, %d) = 0x%02x\n",
- opcode, length, parameter[i-1]);
- else
- printk("ACI: aci_read_cmd cont.: 0x%02x\n", parameter[i-1]);
-#endif
- }
+ __put_user(ret, (int *)arg);
- restore_flags(flags);
return 0;
}
-
-int aci_indexed_cmd(unsigned char opcode, unsigned char index,
- unsigned char *parameter)
+static int getvolume(caddr_t arg,
+ unsigned char left_index, unsigned char right_index)
{
- unsigned long flags;
-
- save_flags(flags);
- cli();
-
- if (read_general_status() < 0 || busy_wait()) {
- restore_flags(flags);
- return -1;
- }
-
- outb_p(opcode, COMMAND_REGISTER);
- if (busy_wait()) {
- restore_flags(flags);
- return -1;
- }
-
- outb_p(index, COMMAND_REGISTER);
- if (busy_wait()) {
- restore_flags(flags);
- return -1;
- }
+ int vol;
+ int buf;
+
+ /* left channel */
+ if ((buf=aci_indexed_cmd(0xf0, left_index))<0)
+ return buf;
+ vol = SCALE(0x20, 100, buf < 0x20 ? 0x20-buf : 0);
- *parameter = inb_p(STATUS_REGISTER);
-#ifdef DEBUG
- printk("ACI: aci_indexed_cmd(0x%02x, 0x%02x) = 0x%02x\n", opcode, index,
- *parameter);
-#endif
+ /* right channel */
+ if ((buf=aci_indexed_cmd(0xf0, right_index))<0)
+ return buf;
+ vol |= SCALE(0x20, 100, buf < 0x20 ? 0x20-buf : 0) << 8;
+
+ __put_user(vol, (int *)arg);
- restore_flags(flags);
return 0;
}
-/*
- * The following macro SCALE can be used to scale one integer volume
- * value into another one using only integer arithmetic. If the input
- * value x is in the range 0 <= x <= xmax, then the result will be in
- * the range 0 <= SCALE(xmax,ymax,x) <= ymax.
- *
- * This macro has for all xmax, ymax > 0 and all 0 <= x <= xmax the
- * following nice properties:
- *
- * - SCALE(xmax,ymax,xmax) = ymax
- * - SCALE(xmax,ymax,0) = 0
- * - SCALE(xmax,ymax,SCALE(ymax,xmax,SCALE(xmax,ymax,x))) = SCALE(xmax,ymax,x)
- *
- * In addition, the rounding error is minimal and nicely distributed.
- * The proofs are left as an exercise to the reader.
+/* The equalizer is somewhat strange on the ACI. From -12dB to +12dB
+ * write: 0xff..down.to..0x80==0x00..up.to..0x7f
*/
-#define SCALE(xmax,ymax,x) (((x)*(ymax)+(xmax)/2)/(xmax))
+static inline unsigned int eq_oss2aci(unsigned int vol)
+{
+ int boost=0;
+ unsigned int ret;
+
+ if (vol > 100)
+ vol = 100;
+ if (vol > 50) {
+ vol -= 51;
+ boost=1;
+ }
+ if (boost)
+ ret=SCALE(49, 0x7e, vol)+1;
+ else
+ ret=0xff - SCALE(50, 0x7f, vol);
+ return ret;
+}
+
+static inline unsigned int eq_aci2oss(unsigned int vol)
+{
+ if (vol < 0x80)
+ return SCALE(0x7f, 50, vol) + 50;
+ else
+ return SCALE(0x7f, 50, 0xff-vol);
+}
-static int getvolume(caddr_t arg,
- unsigned char left_index, unsigned char right_index)
+static int setequalizer(caddr_t arg,
+ unsigned char left_index, unsigned char right_index)
{
- int vol;
- unsigned char buf;
+ int buf;
+ unsigned int vol;
+
+ __get_user(vol, (int *)arg);
/* left channel */
- if (aci_indexed_cmd(0xf0, left_index, &buf))
- return -EIO;
- vol = SCALE(0x20, 100, buf < 0x20 ? 0x20-buf : 0);
-
+ if ((buf=aci_write_cmd(left_index, eq_oss2aci(vol & 0xff)))<0)
+ return buf;
+
/* right channel */
- if (aci_indexed_cmd(0xf0, right_index, &buf))
- return -EIO;
- vol |= SCALE(0x20, 100, buf < 0x20 ? 0x20-buf : 0) << 8;
+ if ((buf=aci_write_cmd(right_index, eq_oss2aci((vol>>8) & 0xff)))<0)
+ return buf;
- return (*(int *) arg = vol);
+ /* the ACI equalizer is more precise */
+ return 0;
}
-
-static int setvolume(caddr_t arg,
- unsigned char left_index, unsigned char right_index)
+static int getequalizer(caddr_t arg,
+ unsigned char left_index, unsigned char right_index)
{
- int vol, ret;
+ int buf;
+ unsigned int vol;
/* left channel */
- vol = *(int *)arg & 0xff;
- if (vol > 100)
- vol = 100;
- vol = SCALE(100, 0x20, vol);
- if (aci_write_cmd(left_index, 0x20 - vol))
- return -EIO;
- ret = SCALE(0x20, 100, vol);
+ if ((buf=aci_indexed_cmd(0xf0, left_index))<0)
+ return buf;
+ vol = eq_aci2oss(buf);
+
+ /* right channel */
+ if ((buf=aci_indexed_cmd(0xf0, right_index))<0)
+ return buf;
+ vol |= eq_aci2oss(buf) << 8;
+ __put_user(vol, (int *)arg);
- /* right channel */
- vol = (*(int *)arg >> 8) & 0xff;
- if (vol > 100)
- vol = 100;
- vol = SCALE(100, 0x20, vol);
- if (aci_write_cmd(right_index, 0x20 - vol))
- return -EIO;
- ret |= SCALE(0x20, 100, vol) << 8;
-
- return (*(int *) arg = ret);
+ return 0;
}
-
-static int
-aci_mixer_ioctl (int dev, unsigned int cmd, caddr_t arg)
+static int aci_mixer_ioctl (int dev, unsigned int cmd, caddr_t arg)
{
- int status, vol;
- unsigned char buf;
-
- /* handle solo mode control */
- if (cmd == SOUND_MIXER_PRIVATE1) {
- if (*(int *) arg >= 0) {
- aci_solo = !!*(int *) arg;
- if (aci_write_cmd(0xd2, aci_solo))
- return -EIO;
- } else if (aci_version >= 0xb0) {
- if ((status = read_general_status()) < 0)
- return -EIO;
- return (*(int *) arg = (status & 0x20) == 0);
+ int vol, buf;
+
+ switch (cmd) {
+ case SOUND_MIXER_WRITE_VOLUME:
+ return setvolume(arg, 0x01, 0x00);
+ case SOUND_MIXER_WRITE_CD:
+ return setvolume(arg, 0x3c, 0x34);
+ case SOUND_MIXER_WRITE_MIC:
+ return setvolume(arg, 0x38, 0x30);
+ case SOUND_MIXER_WRITE_LINE:
+ return setvolume(arg, 0x39, 0x31);
+ case SOUND_MIXER_WRITE_SYNTH:
+ return setvolume(arg, 0x3b, 0x33);
+ case SOUND_MIXER_WRITE_PCM:
+ return setvolume(arg, 0x3a, 0x32);
+ case MIXER_WRITE(SOUND_MIXER_RADIO): /* fall through */
+ case SOUND_MIXER_WRITE_LINE1: /* AUX1 or radio */
+ return setvolume(arg, 0x3d, 0x35);
+ case SOUND_MIXER_WRITE_LINE2: /* AUX2 */
+ return setvolume(arg, 0x3e, 0x36);
+ case SOUND_MIXER_WRITE_BASS: /* set band one and two */
+ if (aci_idcode[1]=='C') {
+ if ((buf=setequalizer(arg, 0x48, 0x40)) ||
+ (buf=setequalizer(arg, 0x49, 0x41)));
+ return buf;
}
-
- return (*(int *) arg = aci_solo);
- }
-
- if (((cmd >> 8) & 0xff) == 'M') {
- if (cmd & SIOC_IN)
- /* read and write */
- switch (cmd & 0xff) {
- case SOUND_MIXER_VOLUME:
- return setvolume(arg, 0x01, 0x00);
- case SOUND_MIXER_CD:
- return setvolume(arg, 0x3c, 0x34);
- case SOUND_MIXER_MIC:
- return setvolume(arg, 0x38, 0x30);
- case SOUND_MIXER_LINE:
- return setvolume(arg, 0x39, 0x31);
- case SOUND_MIXER_SYNTH:
- return setvolume(arg, 0x3b, 0x33);
- case SOUND_MIXER_PCM:
- return setvolume(arg, 0x3a, 0x32);
- case SOUND_MIXER_LINE1: /* AUX1 */
- return setvolume(arg, 0x3d, 0x35);
- case SOUND_MIXER_LINE2: /* AUX2 */
- return setvolume(arg, 0x3e, 0x36);
- case SOUND_MIXER_IGAIN: /* MIC pre-amp */
- vol = *(int *) arg & 0xff;
- if (vol > 100)
- vol = 100;
- vol = SCALE(100, 3, vol);
- if (aci_write_cmd(0x03, vol))
- return -EIO;
- vol = SCALE(3, 100, vol);
- return (*(int *) arg = vol | (vol << 8));
- case SOUND_MIXER_RECSRC:
- return (*(int *) arg = 0);
- break;
- default:
- return -EINVAL;
+ break;
+ case SOUND_MIXER_WRITE_TREBLE: /* set band six and seven */
+ if (aci_idcode[1]=='C') {
+ if ((buf=setequalizer(arg, 0x4d, 0x45)) ||
+ (buf=setequalizer(arg, 0x4e, 0x46)));
+ return buf;
+ }
+ break;
+ case SOUND_MIXER_WRITE_IGAIN: /* MIC pre-amp */
+ if (aci_idcode[1]=='B' || aci_idcode[1]=='C') {
+ __get_user(vol, (int *)arg);
+ vol = vol & 0xff;
+ if (vol > 100)
+ vol = 100;
+ vol = SCALE(100, 3, vol);
+ if ((buf=aci_write_cmd(0x03, vol))<0)
+ return buf;
+ aci_micpreamp = vol;
+ vol = SCALE(3, 100, vol);
+ vol |= (vol << 8);
+ __put_user(vol, (int *)arg);
+ return 0;
+ }
+ break;
+ case SOUND_MIXER_WRITE_OGAIN: /* Power-amp/line-out level */
+ if (aci_idcode[1]=='A' || aci_idcode[1]=='B') {
+ __get_user(buf, (int *)arg);
+ buf = buf & 0xff;
+ if (buf > 50)
+ vol = 1;
+ else
+ vol = 0;
+ if ((buf=aci_write_cmd(0x0f, vol))<0)
+ return buf;
+ aci_amp = vol;
+ if (aci_amp)
+ buf = (100 || 100<<8);
+ else
+ buf = 0;
+ __put_user(buf, (int *)arg);
+ return 0;
+ }
+ break;
+ case SOUND_MIXER_WRITE_RECSRC:
+ /* handle solo mode control */
+ __get_user(buf, (int *)arg);
+ /* unset solo when RECSRC for PCM is requested */
+ if (aci_idcode[1]=='B' || aci_idcode[1]=='C') {
+ vol = !(buf & SOUND_MASK_PCM);
+ if ((buf=aci_write_cmd(0xd2, vol))<0)
+ return buf;
+ aci_solo = vol;
+ }
+ buf = (SOUND_MASK_CD| SOUND_MASK_MIC| SOUND_MASK_LINE|
+ SOUND_MASK_SYNTH| SOUND_MASK_LINE2);
+ if (aci_idcode[1] == 'C') /* PCM20 radio */
+ buf |= SOUND_MASK_RADIO;
+ else
+ buf |= SOUND_MASK_LINE1;
+ if (!aci_solo)
+ buf |= SOUND_MASK_PCM;
+ __put_user(buf, (int *)arg);
+ return 0;
+ case SOUND_MIXER_READ_DEVMASK:
+ buf = (SOUND_MASK_VOLUME | SOUND_MASK_CD |
+ SOUND_MASK_MIC | SOUND_MASK_LINE |
+ SOUND_MASK_SYNTH | SOUND_MASK_PCM |
+ SOUND_MASK_LINE2);
+ switch (aci_idcode[1]) {
+ case 'C': /* PCM20 radio */
+ buf |= (SOUND_MASK_RADIO | SOUND_MASK_IGAIN |
+ SOUND_MASK_BASS | SOUND_MASK_TREBLE);
+ break;
+ case 'B': /* PCM12 */
+ buf |= (SOUND_MASK_LINE1 | SOUND_MASK_IGAIN |
+ SOUND_MASK_OGAIN);
+ break;
+ case 'A': /* PCM1-pro */
+ buf |= (SOUND_MASK_LINE1 | SOUND_MASK_OGAIN);
+ break;
+ default:
+ buf |= SOUND_MASK_LINE1;
+ }
+ __put_user(buf, (int *)arg);
+ return 0;
+ case SOUND_MIXER_READ_STEREODEVS:
+ buf = (SOUND_MASK_VOLUME | SOUND_MASK_CD |
+ SOUND_MASK_MIC | SOUND_MASK_LINE |
+ SOUND_MASK_SYNTH | SOUND_MASK_PCM |
+ SOUND_MASK_LINE2);
+ switch (aci_idcode[1]) {
+ case 'C': /* PCM20 radio */
+ buf |= (SOUND_MASK_RADIO |
+ SOUND_MASK_BASS | SOUND_MASK_TREBLE);
+ break;
+ default:
+ buf |= SOUND_MASK_LINE1;
+ }
+ __put_user(buf, (int *)arg);
+ return 0;
+ case SOUND_MIXER_READ_RECMASK:
+ buf = (SOUND_MASK_CD| SOUND_MASK_MIC| SOUND_MASK_LINE|
+ SOUND_MASK_SYNTH| SOUND_MASK_LINE2| SOUND_MASK_PCM);
+ if (aci_idcode[1] == 'C') /* PCM20 radio */
+ buf |= SOUND_MASK_RADIO;
+ else
+ buf |= SOUND_MASK_LINE1;
+
+ __put_user(buf, (int *)arg);
+ return 0;
+ case SOUND_MIXER_READ_RECSRC:
+ buf = (SOUND_MASK_CD | SOUND_MASK_MIC | SOUND_MASK_LINE |
+ SOUND_MASK_SYNTH | SOUND_MASK_LINE2);
+ /* do we need aci_solo or can I get it from the ACI? */
+ switch (aci_idcode[1]) {
+ case 'B': /* PCM12 */
+ case 'C': /* PCM20 radio */
+ if (aci_version >= 0xb0) {
+ if ((vol=aci_rw_cmd(0xf0, 0x00, -1))<0)
+ return vol;
+ if (vol & 0x20)
+ buf |= SOUND_MASK_PCM;
}
+ else
+ if (!aci_solo)
+ buf |= SOUND_MASK_PCM;
+ break;
+ default:
+ buf |= SOUND_MASK_PCM;
+ }
+ if (aci_idcode[1] == 'C') /* PCM20 radio */
+ buf |= SOUND_MASK_RADIO;
else
- /* only read */
- switch (cmd & 0xff) {
- case SOUND_MIXER_DEVMASK:
- return (*(int *) arg =
- SOUND_MASK_VOLUME | SOUND_MASK_CD |
- SOUND_MASK_MIC | SOUND_MASK_LINE |
- SOUND_MASK_SYNTH | SOUND_MASK_PCM |
-#if 0
- SOUND_MASK_IGAIN |
-#endif
- SOUND_MASK_LINE1 | SOUND_MASK_LINE2);
- break;
- case SOUND_MIXER_STEREODEVS:
- return (*(int *) arg =
- SOUND_MASK_VOLUME | SOUND_MASK_CD |
- SOUND_MASK_MIC | SOUND_MASK_LINE |
- SOUND_MASK_SYNTH | SOUND_MASK_PCM |
- SOUND_MASK_LINE1 | SOUND_MASK_LINE2);
- break;
- case SOUND_MIXER_RECMASK:
- return (*(int *) arg = 0);
- break;
- case SOUND_MIXER_RECSRC:
- return (*(int *) arg = 0);
- break;
- case SOUND_MIXER_CAPS:
- return (*(int *) arg = 0);
- break;
- case SOUND_MIXER_VOLUME:
- return getvolume(arg, 0x04, 0x03);
- case SOUND_MIXER_CD:
- return getvolume(arg, 0x0a, 0x09);
- case SOUND_MIXER_MIC:
- return getvolume(arg, 0x06, 0x05);
- case SOUND_MIXER_LINE:
- return getvolume(arg, 0x08, 0x07);
- case SOUND_MIXER_SYNTH:
- return getvolume(arg, 0x0c, 0x0b);
- case SOUND_MIXER_PCM:
- return getvolume(arg, 0x0e, 0x0d);
- case SOUND_MIXER_LINE1: /* AUX1 */
- return getvolume(arg, 0x11, 0x10);
- case SOUND_MIXER_LINE2: /* AUX2 */
- return getvolume(arg, 0x13, 0x12);
- case SOUND_MIXER_IGAIN: /* MIC pre-amp */
- if (aci_indexed_cmd(0xf0, 0x21, &buf))
- return -EIO;
- vol = SCALE(3, 100, buf <= 3 ? buf : 3);
- vol |= vol << 8;
- return (*(int *) arg = vol);
- default:
- return -EINVAL;
+ buf |= SOUND_MASK_LINE1;
+
+ __put_user(buf, (int *)arg);
+ return 0;
+ case SOUND_MIXER_READ_CAPS:
+ __put_user(0, (int *)arg);
+ return 0;
+ case SOUND_MIXER_READ_VOLUME:
+ return getvolume(arg, 0x04, 0x03);
+ case SOUND_MIXER_READ_CD:
+ return getvolume(arg, 0x0a, 0x09);
+ case SOUND_MIXER_READ_MIC:
+ return getvolume(arg, 0x06, 0x05);
+ case SOUND_MIXER_READ_LINE:
+ return getvolume(arg, 0x08, 0x07);
+ case SOUND_MIXER_READ_SYNTH:
+ return getvolume(arg, 0x0c, 0x0b);
+ case SOUND_MIXER_READ_PCM:
+ return getvolume(arg, 0x0e, 0x0d);
+ case MIXER_READ(SOUND_MIXER_RADIO): /* fall through */
+ case SOUND_MIXER_READ_LINE1: /* AUX1 */
+ return getvolume(arg, 0x11, 0x10);
+ case SOUND_MIXER_READ_LINE2: /* AUX2 */
+ return getvolume(arg, 0x13, 0x12);
+ case SOUND_MIXER_READ_BASS: /* get band one */
+ if (aci_idcode[1]=='C') {
+ return getequalizer(arg, 0x23, 0x22);
+ }
+ break;
+ case SOUND_MIXER_READ_TREBLE: /* get band seven */
+ if (aci_idcode[1]=='C') {
+ return getequalizer(arg, 0x2f, 0x2e);
+ }
+ break;
+ case SOUND_MIXER_READ_IGAIN: /* MIC pre-amp */
+ if (aci_idcode[1]=='B' || aci_idcode[1]=='C') {
+ /* aci_micpreamp or ACI? */
+ if (aci_version >= 0xb0) {
+ if ((buf=aci_indexed_cmd(0xf0, 0x21))<0)
+ return buf;
}
+ else
+ buf=aci_micpreamp;
+ vol = SCALE(3, 100, buf <= 3 ? buf : 3);
+ vol |= vol << 8;
+ __put_user(vol, (int *)arg);
+ return 0;
+ }
+ break;
+ case SOUND_MIXER_READ_OGAIN:
+ if (aci_amp)
+ buf = (100 || 100<<8);
+ else
+ buf = 0;
+ __put_user(buf, (int *)arg);
+ return 0;
}
-
return -EINVAL;
}
-
static struct mixer_operations aci_mixer_operations =
{
- owner: THIS_MODULE,
- id: "ACI",
- name: "ACI mixer",
- ioctl: aci_mixer_ioctl
+ owner: THIS_MODULE,
+ id: "ACI",
+ ioctl: aci_mixer_ioctl
};
-static unsigned char
-mad_read (int port)
-{
- outb (0xE3, 0xf8f); /* Write MAD16 password */
- return inb (port); /* Read from port */
-}
-
-
/*
- * Check, whether there actually is any ACI port operational and if
- * one was found, then initialize the ACI interface, reserve the I/O
- * addresses and attach the new mixer to the relevant VoxWare data
- * structures.
- *
- * Returns: 1 ACI mixer detected
- * 0 nothing there
- *
* There is also an internal mixer in the codec (CS4231A or AD1845),
* that deserves no purpose in an ACI based system which uses an
* external ACI controlled stereo mixer. Make sure that this codec
static int __init attach_aci(void)
{
- char *boardname = "unknown";
- int volume;
+ char *boardname;
+ int i;
-#define MC4_PORT 0xf90
+ init_MUTEX(&aci_sem);
- aci_port =
- (mad_read(MC4_PORT) & 0x10) ? 0x344 : 0x354;
+ outb(0xE3, 0xf8f); /* Write MAD16 password */
+ aci_port = (inb(0xf90) & 0x10) ?
+ 0x344: 0x354; /* Get aci_port from MC4_PORT */
if (check_region(aci_port, 3)) {
-#ifdef DEBUG
- printk("ACI: I/O area 0x%03x-0x%03x already used.\n",
- aci_port, aci_port+2);
-#endif
- return 0;
+ printk(KERN_NOTICE "aci: I/O area 0x%03x-0x%03x already used.\n",
+ aci_port, aci_port+2);
+ return -EBUSY;
}
-
- if (aci_read_cmd(0xf2, 2, aci_idcode)) {
-#ifdef DEBUG
- printk("ACI: Failed to read idcode.\n");
-#endif
- return 0;
+
+ /* force ACI into a known state */
+ for (i=0; i<3; i++)
+ if (aci_rw_cmd(0xdf, -1, -1)<0)
+ return -EFAULT;
+
+ /* official this is one aci read call: */
+ if ((aci_idcode[0]=aci_rw_cmd(0xf2, -1, -1))<0 ||
+ (aci_idcode[1]=aci_rw_cmd(0xf2, -1, -1))<0) {
+ printk(KERN_ERR "aci: Failed to read idcode on 0x%03x.\n", aci_port);
+ return -EFAULT;
}
-
- if (aci_read_cmd(0xf1, 1, &aci_version)) {
-#ifdef DEBUG
- printk("ACI: Failed to read version.\n");
-#endif
- return 0;
+
+ if ((aci_version=aci_rw_cmd(0xf1, -1, -1))<0) {
+ printk(KERN_ERR "aci: Failed to read version on 0x%03x.\n", aci_port);
+ return -EFAULT;
}
- if (aci_idcode[0] == 0x6d) {
+ if (aci_idcode[0] == 'm') {
/* It looks like a miro sound card. */
switch (aci_idcode[1]) {
- case 0x41:
- boardname = "PCM1 pro / early PCM12";
- break;
- case 0x42:
- boardname = "PCM12";
- break;
- case 0x43:
- boardname = "PCM20";
- break;
- default:
- boardname = "unknown miro";
+ case 'A':
+ boardname = "PCM1 pro / early PCM12";
+ break;
+ case 'B':
+ boardname = "PCM12";
+ break;
+ case 'C':
+ boardname = "PCM20 radio";
+ break;
+ default:
+ boardname = "unknown miro";
}
- } else
-#ifndef DEBUG
- return 0;
-#endif
-
- printk("<ACI %02x, id %02x %02x (%s)> at 0x%03x\n",
- aci_version, aci_idcode[0], aci_idcode[1], boardname, aci_port);
-
- if (aci_reset) {
- /* initialize ACI mixer */
- aci_implied_cmd(0xff);
- aci_solo = 0;
+ } else {
+ printk(KERN_WARNING "aci: Warning: unsupported card! - "
+ "no hardware, no specs...\n");
+ boardname = "unknown Cardinal Technologies";
}
- /* attach the mixer */
- request_region(aci_port, 3, "sound mixer (ACI)");
- if (num_mixers < MAX_MIXER_DEV) {
- if (num_mixers > 0 &&
- !strncmp("MAD16 WSS", mixer_devs[num_mixers-1]->name, 9)) {
- /*
- * The previously registered mixer device is the CS4231A which
- * has no function on an ACI card. Make the ACI mixer the first
- * of the two mixer devices.
- */
- mixer_devs[num_mixers] = mixer_devs[num_mixers-1];
- mixer_devs[num_mixers-1] = &aci_mixer_operations;
- /*
- * Initialize the CS4231A mixer with reasonable values. It is
- * unlikely that the user ever will want to change these as all
- * channels can be mixed via ACI.
- */
- volume = 0x6464;
- mixer_devs[num_mixers]->ioctl(num_mixers,
- SOUND_MIXER_WRITE_PCM, (caddr_t) &volume);
- volume = 0x6464;
- mixer_devs[num_mixers]->ioctl(num_mixers,
- SOUND_MIXER_WRITE_IGAIN, (caddr_t) &volume);
- volume = 0;
- mixer_devs[num_mixers]->ioctl(num_mixers,
- SOUND_MIXER_WRITE_SPEAKER, (caddr_t) &volume);
- volume = 0;
- mixer_devs[num_mixers]->ioctl(num_mixers,
- SOUND_MIXER_WRITE_MIC, (caddr_t) &volume);
- volume = 0;
- mixer_devs[num_mixers]->ioctl(num_mixers,
- SOUND_MIXER_WRITE_IMIX, (caddr_t) &volume);
- volume = 0;
- mixer_devs[num_mixers]->ioctl(num_mixers,
- SOUND_MIXER_WRITE_LINE1, (caddr_t) &volume);
- volume = 0;
- mixer_devs[num_mixers]->ioctl(num_mixers,
- SOUND_MIXER_WRITE_LINE2, (caddr_t) &volume);
- volume = 0;
- mixer_devs[num_mixers]->ioctl(num_mixers,
- SOUND_MIXER_WRITE_LINE3, (caddr_t) &volume);
- volume = SOUND_MASK_LINE1;
- mixer_devs[num_mixers]->ioctl(num_mixers,
- SOUND_MIXER_WRITE_RECSRC, (caddr_t) &volume);
- num_mixers++;
- } else
- mixer_devs[num_mixers++] = &aci_mixer_operations;
+ printk(KERN_INFO "<ACI 0x%02x, id %02x/%02x \"%c/%c\", (%s)> at 0x%03x\n",
+ aci_version,
+ aci_idcode[0], aci_idcode[1],
+ aci_idcode[0], aci_idcode[1],
+ boardname, aci_port);
+
+ if (reset) {
+ /* first write()s after reset fail with my PCM20 */
+ if (aci_rw_cmd(0xff, -1, -1)<0 ||
+ aci_rw_cmd(0xdf, 0xdf, 0xdf)<0 ||
+ aci_rw_cmd(0xdf, 0xdf, 0xdf)<0)
+ return -EBUSY;
}
- /* Just do something; otherwise the first write command fails, at
- * least with my PCM20.
- */
- aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_READ_VOLUME, (caddr_t) &volume);
+ /* the PCM20 is muted after reset (and reboot) */
+ if (aci_rw_cmd(0x0d, 0x00, -1)<0)
+ return -EBUSY;
+
+ if (ide>=0)
+ if (aci_rw_cmd(0xd0, !ide, -1)<0)
+ return -EBUSY;
- if (aci_reset) {
- /* Initialize ACI mixer with reasonable power-up values */
- volume = 0x3232;
- aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_VOLUME, (caddr_t) &volume);
- volume = 0x3232;
- aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_SYNTH, (caddr_t) &volume);
- volume = 0x3232;
- aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_PCM, (caddr_t) &volume);
- volume = 0x3232;
- aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_LINE, (caddr_t) &volume);
- volume = 0x3232;
- aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_MIC, (caddr_t) &volume);
- volume = 0x3232;
- aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_CD, (caddr_t) &volume);
- volume = 0x3232;
- aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_LINE1, (caddr_t) &volume);
- volume = 0x3232;
- aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_LINE2, (caddr_t) &volume);
+ if (wss>=0 && aci_idcode[1]=='A')
+ if (aci_rw_cmd(0xd1, !!wss, -1)<0)
+ return -EBUSY;
+
+ if (!request_region(aci_port, 3, "sound mixer (ACI)"))
+ return -ENOMEM;
+
+ if ((mixer_device = sound_install_mixer(MIXER_DRIVER_VERSION,
+ boardname,
+ &aci_mixer_operations,
+ sizeof(aci_mixer_operations),
+ NULL)) >= 0) {
+ /* Maybe initialize the CS4231A mixer here... */
+ } else {
+ printk(KERN_ERR "aci: Failed to install mixer.\n");
+ release_region(aci_port, 3);
+ return mixer_device;
}
- aci_present = 1;
-
- return 1;
+ return 0;
}
static void __exit unload_aci(void)
{
- if (aci_present)
- release_region(aci_port, 3);
+ sound_unload_mixerdev(mixer_device);
+ release_region(aci_port, 3);
}
-EXPORT_SYMBOL(aci_write_cmd);
-EXPORT_SYMBOL(aci_indexed_cmd);
-EXPORT_SYMBOL(aci_write_cmd_d);
-
module_init(attach_aci);
module_exit(unload_aci);
--- /dev/null
+#ifndef _ACI_H_
+#define _ACI_H_
+
+extern int aci_port;
+extern int aci_idcode[2]; /* manufacturer and product ID */
+extern int aci_version; /* ACI firmware version */
+extern int aci_rw_cmd(int write1, int write2, int write3);
+
+extern char * aci_radio_name;
+extern int aci_rds_cmd(unsigned char cmd, unsigned char databuffer[], int datasize);
+
+#define aci_indexed_cmd(a, b) aci_rw_cmd(a, b, -1)
+#define aci_write_cmd(a, b) aci_rw_cmd(a, b, -1)
+#define aci_read_cmd(a) aci_rw_cmd(a,-1, -1)
+
+#define COMMAND_REGISTER (aci_port) /* write register */
+#define STATUS_REGISTER (aci_port + 1) /* read register */
+#define BUSY_REGISTER (aci_port + 2) /* also used for rds */
+
+#define RDS_REGISTER BUSY_REGISTER
+
+#define RDS_STATUS 0x01
+#define RDS_STATIONNAME 0x02
+#define RDS_TEXT 0x03
+#define RDS_ALTFREQ 0x04
+#define RDS_TIMEDATE 0x05
+#define RDS_PI_CODE 0x06
+#define RDS_PTYTATP 0x07
+#define RDS_RESET 0x08
+#define RDS_RXVALUE 0x09
+
+/*
+ * The following macro SCALE can be used to scale one integer volume
+ * value into another one using only integer arithmetic. If the input
+ * value x is in the range 0 <= x <= xmax, then the result will be in
+ * the range 0 <= SCALE(xmax,ymax,x) <= ymax.
+ *
+ * This macro has for all xmax, ymax > 0 and all 0 <= x <= xmax the
+ * following nice properties:
+ *
+ * - SCALE(xmax,ymax,xmax) = ymax
+ * - SCALE(xmax,ymax,0) = 0
+ * - SCALE(xmax,ymax,SCALE(ymax,xmax,SCALE(xmax,ymax,x))) = SCALE(xmax,ymax,x)
+ *
+ * In addition, the rounding error is minimal and nicely distributed.
+ * The proofs are left as an exercise to the reader.
+ */
+
+#define SCALE(xmax,ymax,x) (((x)*(ymax)+(xmax)/2)/(xmax))
+
+extern void __exit unload_aci_rds(void);
+extern int __init attach_aci_rds(void);
+
+
+#endif /* _ACI_H_ */
#define VERSION "1.3" /* Version of Audio Excel DSP 16 driver */
-#undef AEDSP16_DEBUG 1 /* Define this to enable debug code */
-#undef AEDSP16_DEBUG_MORE 1 /* Define this to enable more debug */
-#undef AEDSP16_INFO 1 /* Define this to enable info code */
+#undef AEDSP16_DEBUG /* Define this to 1 to enable debug code */
+#undef AEDSP16_DEBUG_MORE /* Define this to 1 to enable more debug */
+#undef AEDSP16_INFO /* Define this to 1 to enable info code */
#if defined(AEDSP16_DEBUG)
# define DBG(x) printk x
#define _CARDMI_H
#include "icardmid.h"
+#include <linux/sched.h>
#include <linux/interrupt.h>
typedef enum
#ifndef _TIMER_H
#define _TIMER_H
+#include <linux/sched.h>
#include <linux/interrupt.h>
#include "hwaccess.h"
+++ /dev/null
-extern int aci_implied_cmd(unsigned char opcode);
-extern int aci_write_cmd(unsigned char opcode, unsigned char parameter);
-extern int aci_write_cmd_d(unsigned char opcode, unsigned char parameter, unsigned char parameter2);
-extern int aci_read_cmd(unsigned char opcode, int length, unsigned char *parameter);
-extern int aci_indexed_cmd(unsigned char opcode, unsigned char index, unsigned char *parameter);
* We currently support a mixer device, but it is currently non-functional.
*/
+#include <linux/config.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
static void (*old_mksound)(unsigned int hz, unsigned int ticks);
extern void (*kd_mksound)(unsigned int hz, unsigned int ticks);
extern void vidc_update_filler(int bits, int channels);
+extern int softoss_dev;
static void
vidc_mksound(unsigned int hz, unsigned int ticks)
rate = VIDC_SOUND_CLOCK / hwrate;
}
- outl(0xb0000000 | (hwrate - 2), IO_VIDC_BASE);
- outl(0xb1000000 | hwctrl, IO_VIDC_BASE);
+ vidc_writel(0xb0000000 | (hwrate - 2));
+ vidc_writel(0xb1000000 | hwctrl);
newsize = (10000 / hwrate) & ~3;
if (newsize < 208)
dma_interrupt = vidc_audio_dma_interrupt;
vidc_sound_dma_irq(0, NULL, NULL);
- outb(DMA_CR_E | 0x10, IOMD_SD0CR);
+ iomd_writeb(DMA_CR_E | 0x10, IOMD_SD0CR);
local_irq_restore(flags);
}
vidc_adev = adev;
vidc_mixer_set(SOUND_MIXER_VOLUME, (85 | 85 << 8));
+#if defined(CONFIG_SOUND_SOFTOSS) || defined(CONFIG_SOUND_SOFTOSS_MODULE)
+ softoss_dev = adev;
+#endif
return;
irq_failed:
io = ints[1];
irq = ints[2];
dma = ints[3];
- dma16 = ints[4];
+ dma2 = ints[4];
return 1;
}
#
# Note 2! The CFLAGS definitions are now in the main makefile...
-SUB_DIRS :=
-MOD_SUB_DIRS :=
-ALL_SUB_DIRS :=
-
-L_TARGET := tc.a
-L_OBJS := tc.o
-
-# Nasty trick as nobody references tcsyms.o, but we still want it linked.
-# Stolen from pci Makefile
-ifeq ($(CONFIG_MODULES),y)
-O_TARGET = tc_syms.o
-OX_OBJS = tcsyms.o
-O_OBJS = tc.o
-L_OBJS := tc_syms.o
-else
-L_OBJS := tc.o
-endif
-
-ifdef CONFIG_ZS
-L_OBJS += zs.o
-endif
+# All of the (potential) objects that export symbols.
+# This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'.
+
+export-objs := tc.o
+
+# Object file lists.
+
+obj-y :=
+obj-m :=
+obj-n :=
+obj- :=
+
+obj-$(CONFIG_TC) += tc.o
+obj-$(CONFIG_ZS) += zs.o
+obj-$(CONFIG_VT) += lk201.o lk201-map.o lk201-remap.o
+
+# Files that are both resident and modular: remove from modular.
+
+obj-m := $(filter-out $(obj-y), $(obj-m))
+
+# Translate to Rules.make lists.
+
+L_TARGET := tc.a
+
+L_OBJS := $(sort $(filter-out $(export-objs), $(obj-y)))
+LX_OBJS := $(sort $(filter $(export-objs), $(obj-y)))
+M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m)))
+MX_OBJS := $(sort $(filter $(export-objs), $(obj-m)))
include $(TOPDIR)/Rules.make
+lk201-map.c: lk201-map.map
+ loadkeys --mktable lk201-map.map > lk201-map.c
hub->nerrors = 0;
/* Something happened, let khubd figure it out */
- if (waitqueue_active(&khubd_wait)) {
- /* Add the hub to the event queue */
- spin_lock_irqsave(&hub_event_lock, flags);
- if (list_empty(&hub->event_list)) {
- list_add(&hub->event_list, &hub_event_list);
- wake_up(&khubd_wait);
- }
- spin_unlock_irqrestore(&hub_event_lock, flags);
+ spin_lock_irqsave(&hub_event_lock, flags);
+ if (list_empty(&hub->event_list)) {
+ list_add(&hub->event_list, &hub_event_list);
+ wake_up(&khubd_wait);
}
+ spin_unlock_irqrestore(&hub_event_lock, flags);
}
static void usb_hub_power_on(struct usb_hub *hub)
static void *hub_probe(struct usb_device *dev, unsigned int i,
const struct usb_device_id *id)
-
{
struct usb_interface_descriptor *interface;
struct usb_endpoint_descriptor *endpoint;
INIT_LIST_HEAD(&hub->event_list);
hub->dev = dev;
- init_MUTEX(&hub->khubd_sem);
+ atomic_set(&hub->refcnt, 1);
/* Record the new hub's existence */
spin_lock_irqsave(&hub_event_lock, flags);
return NULL;
}
+static void hub_get(struct usb_hub *hub)
+{
+ atomic_inc(&hub->refcnt);
+}
+
+static void hub_put(struct usb_hub *hub)
+{
+ if (atomic_dec_and_test(&hub->refcnt)) {
+ if (hub->urb) {
+ usb_unlink_urb(hub->urb);
+ usb_free_urb(hub->urb);
+ hub->urb = NULL;
+ }
+
+ if (hub->descriptor) {
+ kfree(hub->descriptor);
+ hub->descriptor = NULL;
+ }
+
+ kfree(hub);
+ }
+}
+
static void hub_disconnect(struct usb_device *dev, void *ptr)
{
struct usb_hub *hub = (struct usb_hub *)ptr;
spin_unlock_irqrestore(&hub_event_lock, flags);
- down(&hub->khubd_sem); /* Wait for khubd to leave this hub alone. */
- up(&hub->khubd_sem);
-
- if (hub->urb) {
- usb_unlink_urb(hub->urb);
- usb_free_urb(hub->urb);
- hub->urb = NULL;
- }
-
- if (hub->descriptor) {
- kfree(hub->descriptor);
- hub->descriptor = NULL;
- }
-
- /* Free the memory */
- kfree(hub);
+ hub_put(hub);
}
static int hub_ioctl(struct usb_device *hub, unsigned int code, void *user_data)
if (usb_reset_device(dev))
return -1;
+ hub->urb->dev = dev;
if (usb_submit_urb(hub->urb))
return -1;
list_del(tmp);
INIT_LIST_HEAD(tmp);
- down(&hub->khubd_sem); /* never blocks, we were on list */
+ hub_get(hub);
spin_unlock_irqrestore(&hub_event_lock, flags);
if (hub->error) {
if (usb_hub_reset(hub)) {
err("error resetting hub %d - disconnecting", dev->devnum);
usb_hub_disconnect(dev);
- up(&hub->khubd_sem);
+ hub_put(hub);
continue;
}
usb_hub_power_on(hub);
}
}
- up(&hub->khubd_sem);
+ hub_put(hub);
} /* end while (1) */
spin_unlock_irqrestore(&hub_event_lock, flags);
struct usb_hub_descriptor *descriptor;
- struct semaphore khubd_sem;
+ atomic_t refcnt;
};
#endif
bool ' CGsix (GX,TurboGX) support' CONFIG_FB_CGSIX
fi
fi
+ bool ' Epson 1355 framebuffer support' CONFIG_FB_E1355
+ if [ "$CONFIG_FB_E1355" = "y" ]; then
+ hex ' Register Base Address' CONFIG_E1355_REG_BASE a8000000
+ hex ' Framebuffer Base Address' CONFIG_E1355_FB_BASE a8200000
+ fi
+ if [ "$CONFIG_SH_DREAMCAST" = "y" ]; then
+ tristate ' Dreamcast Frame Buffer support' CONFIG_FB_DC
+ fi
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
if [ "$CONFIG_PCI" != "n" ]; then
tristate ' Matrox acceleration (EXPERIMENTAL)' CONFIG_FB_MATROX
obj-$(CONFIG_FB_SA1100) += sa1100fb.o
obj-$(CONFIG_FB_VIRTUAL) += vfb.o
obj-$(CONFIG_FB_HIT) += hitfb.o fbgen.o
+obj-$(CONFIG_FB_E1355) += epson1355fb.o fbgen.o
+obj-$(CONFIG_FB_DC) += dcfb.o fbgen.o
# Generic Low Level Drivers
--- /dev/null
+/*
+ * $Id: dcfb.c,v 1.1 2001/04/01 15:02:51 yaegashi Exp $
+ * SEGA Dreamcast framebuffer
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/malloc.h>
+#include <linux/delay.h>
+#include <linux/nubus.h>
+#include <linux/init.h>
+
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+#include <asm/io.h>
+
+#include <linux/fb.h>
+
+#include <video/fbcon.h>
+#include <video/fbcon-cfb16.h>
+#include <video/fbcon-cfb32.h>
+
+#define BORDERRGB 0xa05f8040
+#define DISPLAYMODE 0xa05f8044
+#define ALPHAMODE 0xa05f8048
+#define DISPLAYALIGN 0xa05f804c
+#define BASEOFFSET1 0xa05f8050
+#define BASEOFFSET2 0xa05f8054
+#define DISPLAYSIZE 0xa05f805c
+#define SYNCMODE 0xa05f80d0
+#define VERTICALRANGE 0xa05f80dc
+#define HORIZPOSITION 0xa05f80ec
+#define VERTPOSITION 0xa05f80f0
+#define PALETTEMODE 0xa05f8108
+#define VIDEOOUTPUT 0xa0702c00
+
+static unsigned long dc_parm_vga_16bpp[] = {
+ DISPLAYMODE, 0x00800005,
+ BASEOFFSET1, 0,
+ BASEOFFSET2, 640*2,
+ DISPLAYSIZE, (1<<20)+((480-1)<<10)+(640*2/4-1),
+ SYNCMODE, 0x100,
+ VERTPOSITION, 0x00230023,
+ VERTICALRANGE, 0x00280208,
+ HORIZPOSITION, 0x00000090,
+ VIDEOOUTPUT, 0,
+ 0, 0,
+};
+
+static unsigned long dc_parm_vga_32bpp[] = {
+ DISPLAYMODE, 0x0080000d,
+ BASEOFFSET1, 0,
+ BASEOFFSET2, 640*4,
+ DISPLAYSIZE, (1<<20)+((480-1)<<10)+(640*4/4-1),
+ SYNCMODE, 0x100,
+ VERTPOSITION, 0x00230023,
+ VERTICALRANGE, 0x00280208,
+ HORIZPOSITION, 0x00000090,
+ VIDEOOUTPUT, 0,
+ 0, 0,
+};
+
+static unsigned long *dc_parm_vga[] = {
+ dc_parm_vga_16bpp,
+ dc_parm_vga_32bpp,
+};
+
+static unsigned long dc_parm_composite_16bpp[] = {
+ DISPLAYMODE, 0x00000005,
+ BASEOFFSET1, 0,
+ BASEOFFSET2, 640*2,
+ DISPLAYSIZE, ((640*2/4+1)<<20)+((240-1)<<10)+(640*2/4-1),
+ SYNCMODE, 0x150,
+ VERTPOSITION, 0x00120012,
+ VERTICALRANGE, 0x00240204,
+ HORIZPOSITION, 0x000000a4,
+ VIDEOOUTPUT, 0x300,
+ 0, 0,
+};
+
+static unsigned long dc_parm_composite_32bpp[] = {
+ DISPLAYMODE, 0x0000000d,
+ BASEOFFSET1, 0,
+ BASEOFFSET2, 640*4,
+ DISPLAYSIZE, ((640*4/4+1)<<20)+((240-1)<<10)+(640*4/4-1),
+ SYNCMODE, 0x150,
+ VERTPOSITION, 0x00120012,
+ VERTICALRANGE, 0x00240204,
+ HORIZPOSITION, 0x000000a4,
+ VIDEOOUTPUT, 0x300,
+ 0, 0,
+};
+
+static unsigned long *dc_parm_composite[] = {
+ dc_parm_composite_16bpp,
+ dc_parm_composite_32bpp,
+};
+
+static unsigned long dc_parm_interlace_16bpp[] = {
+ DISPLAYMODE, 0x00000005,
+ BASEOFFSET1, 0,
+ BASEOFFSET2, 640*2,
+ DISPLAYSIZE, ((640*2/4+1)<<20)+((240-1)<<10)+(640*2/4-1),
+ SYNCMODE, 0x150,
+ VERTPOSITION, 0x00120012,
+ VERTICALRANGE, 0x00240204,
+ HORIZPOSITION, 0x000000a4,
+ VIDEOOUTPUT, 0,
+ 0, 0,
+};
+
+static unsigned long dc_parm_interlace_32bpp[] = {
+ DISPLAYMODE, 0x0000000d,
+ BASEOFFSET1, 0,
+ BASEOFFSET2, 640*4,
+ DISPLAYSIZE, ((640*4/4+1)<<20)+((240-1)<<10)+(640*4/4-1),
+ SYNCMODE, 0x150,
+ VERTPOSITION, 0x00120012,
+ VERTICALRANGE, 0x00240204,
+ HORIZPOSITION, 0x000000a4,
+ VIDEOOUTPUT, 0,
+ 0, 0,
+};
+
+static unsigned long *dc_parm_interlace[] = {
+ dc_parm_interlace_16bpp,
+ dc_parm_interlace_32bpp,
+};
+
+struct dcfb_info {
+ struct fb_info_gen gen;
+};
+
+struct dcfb_par
+{
+ int x, y;
+ int bpp;
+};
+
+static struct dcfb_info fb_info;
+static struct dcfb_par current_par;
+static int current_par_valid = 0;
+static struct display disp;
+
+static union {
+#ifdef FBCON_HAS_CFB16
+ u16 cfb16[16];
+#endif
+#ifdef FBCON_HAS_CFB32
+ u32 cfb32[16];
+#endif
+} fbcon_cmap;
+
+static unsigned long **dc_parms;
+static unsigned long dc_videobase, dc_videosize;
+static struct fb_var_screeninfo default_var;
+
+int dcfb_init(void);
+
+static void dcfb_set_par(struct dcfb_par *par, const struct fb_info *info);
+static void dcfb_encode_var(struct fb_var_screeninfo *var,
+ struct dcfb_par *par,
+ const struct fb_info *info);
+
+
+/*
+ * Check cable type.
+ * 0: VGA, 2: RGB, 3: Composite
+ */
+
+#define PCTRA 0xff80002c
+#define PDTRA 0xff800030
+
+static int dcfb_cable_check(void)
+{
+ unsigned long temp = ctrl_inl(PCTRA);
+ temp &= 0xfff0ffff;
+ temp |= 0x000a0000;
+ ctrl_outl(temp, PCTRA);
+ return (ctrl_inw(PDTRA)>>8)&3;
+}
+
+static void dcfb_detect(void)
+{
+ struct dcfb_par par;
+ int cable = dcfb_cable_check();
+ unsigned long **parm_list[4] = {
+ dc_parm_vga, dc_parm_vga, dc_parm_interlace, dc_parm_composite,
+ };
+ char *cable_name[] = { "VGA", "VGA", "Interlace", "Composite", };
+
+ dc_videobase = 0xa5000000;
+ dc_videosize = 0x00200000;
+
+ par.x = 640;
+ par.y = 480;
+ par.bpp = 32;
+ dc_parms = parm_list[cable];
+ printk(KERN_INFO "Dreamcast video cable detected: %s.\n", cable_name[cable]);
+
+ dcfb_set_par(&par, NULL);
+ dcfb_encode_var(&default_var, &par, NULL);
+}
+
+static int dcfb_encode_fix(struct fb_fix_screeninfo *fix,
+ struct dcfb_par *par,
+ const struct fb_info *info)
+{
+ memset(fix, 0, sizeof(struct fb_fix_screeninfo));
+
+ strcpy(fix->id, "SEGA Dreamcast");
+ fix->smem_start = dc_videobase;
+ fix->smem_len = dc_videosize;
+ fix->type = FB_TYPE_PACKED_PIXELS;
+ fix->type_aux = 0;
+ fix->visual = FB_VISUAL_TRUECOLOR;
+ fix->xpanstep = 0;
+ fix->ypanstep = 0;
+ fix->ywrapstep = 0;
+
+ switch(par->bpp) {
+ default:
+ case 16:
+ fix->line_length = par->x*2;
+ break;
+ case 32:
+ fix->line_length = par->x*4;
+ break;
+ }
+
+ return 0;
+}
+
+
+static int dcfb_decode_var(struct fb_var_screeninfo *var,
+ struct dcfb_par *par,
+ const struct fb_info *info)
+{
+ par->x = var->xres;
+ par->y = var->yres;
+ par->bpp = var->bits_per_pixel;
+ return 0;
+}
+
+
+static void dcfb_encode_var(struct fb_var_screeninfo *var,
+ struct dcfb_par *par,
+ const struct fb_info *info)
+{
+ memset(var, 0, sizeof(*var));
+
+ var->xres = par->x;
+ var->yres = par->y;
+ var->xres_virtual = var->xres;
+ var->yres_virtual = var->yres;
+ var->xoffset = 0;
+ var->yoffset = 0;
+ var->bits_per_pixel = par->bpp;
+ var->grayscale = 0;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ var->transp.msb_right = 0;
+ var->nonstd = 0;
+ var->activate = 0;
+ var->height = -1;
+ var->width = -1;
+ var->vmode = FB_VMODE_NONINTERLACED;
+ var->pixclock = 0;
+ var->sync = 0;
+ var->left_margin = 0;
+ var->right_margin = 0;
+ var->upper_margin = 0;
+ var->lower_margin = 0;
+ var->hsync_len = 0;
+ var->vsync_len = 0;
+
+ switch (var->bits_per_pixel) {
+
+ case 16: /* RGB 565 */
+ var->red.offset = 11;
+ var->red.length = 5;
+ var->green.offset = 5;
+ var->green.length = 6;
+ var->blue.offset = 0;
+ var->blue.length = 5;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ break;
+
+ case 32:
+ var->red.offset = 16;
+ var->red.length = 8;
+ var->green.offset = 8;
+ var->green.length = 8;
+ var->blue.offset = 0;
+ var->blue.length = 8;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ break;
+
+ }
+
+ var->red.msb_right = 0;
+ var->green.msb_right = 0;
+ var->blue.msb_right = 0;
+ var->transp.msb_right = 0;
+}
+
+
+static void dcfb_get_par(struct dcfb_par *par, const struct fb_info *info)
+{
+ *par = current_par;
+}
+
+
+static void dcfb_set_par(struct dcfb_par *par, const struct fb_info *info)
+{
+ unsigned long a, d, *p;
+
+ current_par = *par;
+ current_par_valid = 1;
+
+ switch(par->bpp) {
+ default:
+ case 16:
+ p = dc_parms[0];
+ break;
+ case 32:
+ p = dc_parms[1];
+ break;
+ }
+
+ ctrl_outl(0, 0xa05f8008); /* reset? */
+ ctrl_outl(0, BORDERRGB);
+
+ while(1) {
+ a = *p++; d = *p++;
+ if (!a) break;
+ ctrl_outl(d, a);
+ }
+
+}
+
+static struct {
+ u_int red, green, blue;
+} palette[256];
+
+static int dcfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
+ u_int *transp, struct fb_info *info)
+{
+ if (regno > 255)
+ return 1;
+
+ *red = palette[regno].red;
+ *green = palette[regno].green;
+ *blue = palette[regno].blue;
+ *transp = 0;
+
+ return 0;
+}
+
+
+static int dcfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+ u_int transp, struct fb_info *info)
+{
+ if (regno > 255)
+ return 1;
+
+ palette[regno].red = red;
+ palette[regno].green = green;
+ palette[regno].blue = blue;
+
+ if(regno<16) {
+ switch(current_par.bpp) {
+#ifdef FBCON_HAS_CFB16
+ case 16:
+ fbcon_cmap.cfb16[regno] =
+ ((red & 0xf800) ) |
+ ((green & 0xfc00) >> 5) |
+ ((blue & 0xf800) >> 11);
+ break;
+#endif
+#ifdef FBCON_HAS_CFB32
+ case 32:
+ fbcon_cmap.cfb32[regno] =
+ ((red & 0xff00) << 8) |
+ ((green & 0xff00) ) |
+ ((blue & 0xff00) >> 8);
+ break;
+#endif
+ }
+ }
+
+ return 0;
+}
+
+static int dcfb_blank(int blank_mode, const struct fb_info *info)
+{
+ return 0;
+}
+
+
+static void dcfb_set_disp(const void *par, struct display *disp,
+ struct fb_info_gen *info)
+{
+ disp->screen_base = (void *)dc_videobase;
+ disp->scrollmode = SCROLL_YREDRAW;
+
+ switch(((struct dcfb_par *)par)->bpp) {
+#ifdef FBCON_HAS_CFB16
+ case 16:
+ disp->dispsw = &fbcon_cfb16;
+ disp->dispsw_data = fbcon_cmap.cfb16;
+ break;
+#endif
+#ifdef FBCON_HAS_CFB32
+ case 32:
+ disp->dispsw = &fbcon_cfb32;
+ disp->dispsw_data = fbcon_cmap.cfb32;
+ break;
+#endif
+ default:
+ disp->dispsw = &fbcon_dummy;
+ }
+}
+
+
+struct fbgen_hwswitch dcfb_switch = {
+ dcfb_detect,
+ dcfb_encode_fix,
+ dcfb_decode_var,
+ dcfb_encode_var,
+ dcfb_get_par,
+ dcfb_set_par,
+ dcfb_getcolreg,
+ dcfb_setcolreg,
+ NULL,
+ dcfb_blank,
+ dcfb_set_disp
+};
+
+static struct fb_ops dcfb_ops = {
+ owner: THIS_MODULE,
+ fb_get_fix: fbgen_get_fix,
+ fb_get_var: fbgen_get_var,
+ fb_set_var: fbgen_set_var,
+ fb_get_cmap: fbgen_get_cmap,
+ fb_set_cmap: fbgen_set_cmap,
+};
+
+
+int __init dcfb_init(void)
+{
+ strcpy(fb_info.gen.info.modename, "SEGA Dreamcast");
+ fb_info.gen.info.node = -1;
+ fb_info.gen.info.flags = FBINFO_FLAG_DEFAULT;
+ fb_info.gen.info.fbops = &dcfb_ops;
+ fb_info.gen.info.disp = &disp;
+ fb_info.gen.info.changevar = NULL;
+ fb_info.gen.info.switch_con = &fbgen_switch;
+ fb_info.gen.info.updatevar = &fbgen_update_var;
+ fb_info.gen.info.blank = &fbgen_blank;
+ fb_info.gen.parsize = sizeof(struct dcfb_par);
+ fb_info.gen.fbhw = &dcfb_switch;
+ fb_info.gen.fbhw->detect();
+
+ fbgen_get_var(&disp.var, -1, &fb_info.gen.info);
+ disp.var.activate = FB_ACTIVATE_NOW;
+ fbgen_do_set_var(&disp.var, 1, &fb_info.gen);
+ fbgen_set_disp(-1, &fb_info.gen);
+ fbgen_install_cmap(0, &fb_info.gen);
+
+ if(register_framebuffer(&fb_info.gen.info)<0) return -EINVAL;
+
+ printk(KERN_INFO "fb%d: %s frame buffer device\n",
+ GET_FB_IDX(fb_info.gen.info.node), fb_info.gen.info.modename);
+
+ return 0;
+}
+
+
+void dcfb_cleanup(struct fb_info *info)
+{
+ unregister_framebuffer(info);
+}
+
+
+#ifdef MODULE
+int init_module(void)
+{
+ return dcfb_init();
+}
+
+void cleanup_module(void)
+{
+ dcfb_cleanup(void);
+}
+#endif
--- /dev/null
+/*
+ * linux/drivers/video/epson1355fb.c
+ * -- Support for the Epson SED1355 LCD/CRT controller
+ *
+ * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
+ *
+ * based on linux/drivers/video/skeletonfb.c, which was
+ * Created 28 Dec 1997 by Geert Uytterhoeven
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+/* TODO (roughly in order of priority):
+ * 16 bpp support
+ * crt support
+ * hw cursor support
+ * SwivelView
+ */
+
+#include <asm/io.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/malloc.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/tty.h>
+#include <video/fbcon-cfb8.h>
+#include <video/fbcon-mfb.h>
+#include <video/fbcon.h>
+
+/* Register defines. The docs don't seem to provide nice mnemonic names
+ * so I made them up myself ... */
+
+#define E1355_PANEL 0x02
+#define E1355_DISPLAY 0x0D
+#define E1355_MISC 0x1B
+#define E1355_GPIO 0x20
+#define E1355_LUT_INDEX 0x24
+#define E1355_LUT_DATA 0x26
+
+#ifdef CONFIG_SUPERH
+#define E1355_REG_BASE CONFIG_E1355_REG_BASE
+#define E1355_FB_BASE CONFIG_E1355_FB_BASE
+
+static inline u8 e1355_read_reg(int index)
+{
+ return ctrl_inb(E1355_REG_BASE + index);
+}
+
+static inline void e1355_write_reg(u8 data, int index)
+{
+ ctrl_outb(data, E1355_REG_BASE + index);
+}
+
+static inline u16 e1355_read_reg16(int index)
+{
+ return e1355_read_reg(index) + (e1355_read_reg(index+1) << 8);
+}
+
+static inline void e1355_write_reg16(u16 data, int index)
+{
+ e1355_write_reg((data&0xff), index);
+ e1355_write_reg(((data>>8)&0xff), index + 1);
+}
+#else
+#error unknown architecture
+#endif
+
+struct e1355fb_info {
+ struct fb_info_gen gen;
+};
+
+static int current_par_valid = 0;
+static struct display disp;
+
+static struct fb_var_screeninfo default_var;
+
+int e1355fb_init(void);
+int e1355fb_setup(char*);
+static int e1355_encode_var(struct fb_var_screeninfo *var, const void *par,
+ struct fb_info_gen *info);
+/* ------------------- chipset specific functions -------------------------- */
+
+
+static void disable_hw_cursor(void)
+{
+ u8 curs;
+
+ curs = e1355_read_reg(0x27);
+ curs &= ~0xc0;
+ e1355_write_reg(curs, 0x27);
+}
+
+static void e1355_detect(void)
+{
+ u8 rev;
+
+ e1355_write_reg(0x00, E1355_MISC);
+
+ rev = e1355_read_reg(0x00);
+
+ if ((rev & 0xfc) != 0x0c) {
+ printk(KERN_WARNING "Epson 1355 not detected\n");
+ }
+
+ /* XXX */
+ disable_hw_cursor();
+
+ e1355_encode_var(&default_var, NULL, NULL);
+}
+
+struct e1355_par {
+ u32 xres;
+ u32 yres;
+
+ int bpp;
+ int mem_bpp;
+
+ u32 panel_xres;
+ u32 panel_yres;
+
+ int panel_width;
+ int panel_ymul;
+};
+
+static int e1355_encode_fix(struct fb_fix_screeninfo *fix,
+ const void *raw_par,
+ struct fb_info_gen *info)
+{
+ const struct e1355_par *par = raw_par;
+
+ memset(fix, 0, sizeof *fix);
+
+ fix->type= FB_TYPE_PACKED_PIXELS;
+
+ if (!par)
+ BUG();
+
+ if (par->bpp == 1) {
+ fix->visual = FB_VISUAL_MONO10;
+ } else if (par->bpp <= 8) {
+ fix->visual = FB_VISUAL_PSEUDOCOLOR;
+ } else {
+ fix->visual = FB_VISUAL_TRUECOLOR;
+ }
+
+ return 0;
+}
+
+static int e1355_set_bpp(struct e1355_par *par, int bpp)
+{
+ int code;
+ u8 disp;
+ u16 bytes_per_line;
+
+ switch(bpp) {
+ case 1:
+ code = 0; break;
+ case 2:
+ code = 1; break;
+ case 4:
+ code = 2; break;
+ case 8:
+ code = 3; break;
+ case 16:
+ code = 5; break;
+ default:
+ return -EINVAL; break;
+ }
+
+ disp = e1355_read_reg(E1355_DISPLAY);
+ disp &= ~0x1c;
+ disp |= code << 2;
+ e1355_write_reg(disp, E1355_DISPLAY);
+
+ bytes_per_line = (par->xres * bpp) >> 3;
+
+ e1355_write_reg16(bytes_per_line, 0x16);
+
+ par->bpp = bpp;
+
+ return 0;
+}
+
+static int e1355_decode_var(const struct fb_var_screeninfo *var,
+ void *raw_par,
+ struct fb_info_gen *info)
+{
+ struct e1355_par *par = raw_par;
+ int ret;
+
+ if (!par)
+ BUG();
+
+ /*
+ * Don't allow setting any of these yet: xres and yres don't
+ * make sense for LCD panels; xres_virtual and yres_virtual
+ * should be supported fine by our hardware though.
+ */
+ if (var->xres != par->xres ||
+ var->yres != par->yres ||
+ var->xres != var->xres_virtual ||
+ var->yres != var->yres_virtual ||
+ var->xoffset != 0 ||
+ var->yoffset != 0)
+ return -EINVAL;
+
+ if(var->bits_per_pixel != par->bpp) {
+ ret = e1355_set_bpp(par, var->bits_per_pixel);
+
+ if (ret)
+ goto out_err;
+ }
+
+ return 0;
+
+ out_err:
+ return ret;
+}
+
+static void dump_panel_data(void)
+{
+ u8 panel = e1355_read_reg(E1355_PANEL);
+ int width[2][4] = { { 4, 8, 16, -1 }, { 9, 12, 16, -1 } };
+
+ printk("%s %s %s panel, width %d bits\n",
+ panel & 2 ? "dual" : "single",
+ panel & 4 ? "color" : "mono",
+ panel & 1 ? "TFT" : "passive",
+ width[panel&1][(panel>>4)&3]);
+
+ printk("resolution %d x %d\n",
+ (e1355_read_reg(0x04) + 1) * 8,
+ ((e1355_read_reg16(0x08) + 1) * (1 + ((panel & 3) == 2))));
+}
+
+static int e1355_bpp_to_var(int bpp, struct fb_var_screeninfo *var)
+{
+ switch(bpp) {
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ var->bits_per_pixel = bpp;
+ var->red.offset = var->green.offset = var->blue.offset = 0;
+ var->red.length = var->green.length = var->blue.length = bpp;
+ break;
+ case 16:
+ var->bits_per_pixel = 16;
+ var->red.offset = 11;
+ var->red.length = 5;
+ var->green.offset = 5;
+ var->green.length = 6;
+ var->blue.offset = 0;
+ var->blue.length = 5;
+ break;
+ }
+
+ return 0;
+}
+
+static int e1355_encode_var(struct fb_var_screeninfo *var, const void *raw_par,
+ struct fb_info_gen *info)
+{
+ u8 panel, display;
+ u32 xres, xres_virtual, yres;
+ static int width[2][4] = { { 4, 8, 16, -1 }, { 9, 12, 16, -1 } };
+ static int bpp_tab[8] = { 1, 2, 4, 8, 15, 16 };
+ int bpp, hw_bpp;
+ int is_color, is_dual, is_tft;
+ int lcd_enabled, crt_enabled;
+
+ panel = e1355_read_reg(E1355_PANEL);
+ display = e1355_read_reg(E1355_DISPLAY);
+
+ is_color = (panel & 0x04) != 0;
+ is_dual = (panel & 0x02) != 0;
+ is_tft = (panel & 0x01) != 0;
+
+ bpp = bpp_tab[(display>>2)&7];
+ e1355_bpp_to_var(bpp, var);
+
+ crt_enabled = (display & 0x02) != 0;
+ lcd_enabled = (display & 0x02) != 0;
+
+ hw_bpp = width[is_tft][(panel>>4)&3];
+
+ xres = e1355_read_reg(0x04) + 1;
+ yres = e1355_read_reg16(0x08) + 1;
+
+ xres *= 8;
+ /* talk about weird hardware .. */
+ yres *= (is_dual && !crt_enabled) ? 2 : 1;
+
+ xres_virtual = e1355_read_reg16(0x16);
+ /* it's in 2-byte words initially */
+ xres_virtual *= 16;
+ xres_virtual /= var->bits_per_pixel;
+
+ var->xres = xres;
+ var->yres = yres;
+ var->xres_virtual = xres_virtual;
+ var->yres_virtual = yres;
+
+ var->xoffset = var->yoffset = 0;
+
+ var->grayscale = !is_color;
+
+ return 0;
+}
+
+#define is_dual(panel) (((panel)&3)==2)
+
+static void get_panel_data(struct e1355_par *par)
+{
+ u8 panel;
+ int width[2][4] = { { 4, 8, 16, -1 }, { 9, 12, 16, -1 } };
+
+ panel = e1355_read_reg(E1355_PANEL);
+
+ par->panel_width = width[panel&1][(panel>>4)&3];
+ par->panel_xres = (e1355_read_reg(0x04) + 1) * 8;
+ par->panel_ymul = is_dual(panel) ? 2 : 1;
+ par->panel_yres = ((e1355_read_reg16(0x08) + 1)
+ * par->panel_ymul);
+}
+
+static void e1355_get_par(void *raw_par, struct fb_info_gen *info)
+{
+ struct e1355_par *par = raw_par;
+
+ get_panel_data(par);
+}
+
+static void e1355_set_par(const void *par, struct fb_info_gen *info)
+{
+}
+
+static int e1355_getcolreg(unsigned regno, unsigned *red, unsigned *green,
+ unsigned *blue, unsigned *transp,
+ struct fb_info *info)
+{
+ u8 r, g, b;
+
+ e1355_write_reg(regno, E1355_LUT_INDEX);
+ r = e1355_read_reg(E1355_LUT_DATA);
+ g = e1355_read_reg(E1355_LUT_DATA);
+ b = e1355_read_reg(E1355_LUT_DATA);
+
+ *red = r << 8;
+ *green = g << 8;
+ *blue = b << 8;
+
+ return 0;
+}
+
+static int e1355_setcolreg(unsigned regno, unsigned red, unsigned green,
+ unsigned blue, unsigned transp,
+ struct fb_info *info)
+{
+ u8 r = (red >> 8) & 0xf0;
+ u8 g = (green>>8) & 0xf0;
+ u8 b = (blue>> 8) & 0xf0;
+
+ e1355_write_reg(regno, E1355_LUT_INDEX);
+ e1355_write_reg(r, E1355_LUT_DATA);
+ e1355_write_reg(g, E1355_LUT_DATA);
+ e1355_write_reg(b, E1355_LUT_DATA);
+
+ return 0;
+}
+
+static int e1355_pan_display(const struct fb_var_screeninfo *var,
+ struct fb_info_gen *info)
+{
+ BUG();
+
+ return -EINVAL;
+}
+
+/*
+ * The AERO_HACKS parts disable/enable the backlight on the Compaq Aero 8000.
+ * I'm not sure they aren't dangerous to the hardware, so be warned.
+ */
+#undef AERO_HACKS
+
+static int e1355_blank(int blank_mode, struct fb_info_gen *info)
+{
+ u8 disp;
+
+ switch (blank_mode) {
+ case VESA_NO_BLANKING:
+ disp = e1355_read_reg(E1355_DISPLAY);
+ disp |= 1;
+ e1355_write_reg(disp, E1355_DISPLAY);
+
+#ifdef AERO_HACKS
+ e1355_write_reg(0x6, 0x20);
+#endif
+ break;
+
+ case VESA_VSYNC_SUSPEND:
+ case VESA_HSYNC_SUSPEND:
+ case VESA_POWERDOWN:
+ disp = e1355_read_reg(E1355_DISPLAY);
+ disp &= ~1;
+ e1355_write_reg(disp, E1355_DISPLAY);
+
+#ifdef AERO_HACKS
+ e1355_write_reg(0x0, 0x20);
+#endif
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static struct display_switch e1355_dispsw;
+
+static void e1355_set_disp(const void *unused, struct display *disp,
+ struct fb_info_gen *info)
+{
+ struct display_switch *d;
+
+ disp->screen_base = (void *)E1355_FB_BASE;
+ disp->dispsw = &e1355_dispsw;
+
+ switch(disp->var.bits_per_pixel) {
+#ifdef FBCON_HAS_MFB
+ case 1:
+ d = &fbcon_mfb; break;
+#endif
+#ifdef FBCON_HAS_CFB8
+ case 8:
+ d = &fbcon_cfb8; break;
+#endif
+ default:
+ BUG(); break;
+ }
+
+ memcpy(&e1355_dispsw, d, sizeof *d);
+
+ /* reading is terribly slow for us */
+#if 0 /* XXX: need to work out why this doesn't work */
+ e1355_dispsw.bmove = fbcon_redraw_bmove;
+#endif
+}
+
+/* ------------ Interfaces to hardware functions ------------ */
+
+
+struct fbgen_hwswitch e1355_switch = {
+ detect: e1355_detect,
+ encode_fix: e1355_encode_fix,
+ decode_var: e1355_decode_var,
+ encode_var: e1355_encode_var,
+ get_par: e1355_get_par,
+ set_par: e1355_set_par,
+ getcolreg: e1355_getcolreg,
+ setcolreg: e1355_setcolreg,
+ pan_display: e1355_pan_display,
+ blank: e1355_blank,
+ set_disp: e1355_set_disp,
+};
+
+
+/* ------------ Hardware Independent Functions ------------ */
+
+
+static struct fb_ops e1355fb_ops = {
+ owner: THIS_MODULE,
+ fb_get_fix: fbgen_get_fix,
+ fb_get_var: fbgen_get_var,
+ fb_set_var: fbgen_set_var,
+ fb_get_cmap: fbgen_get_cmap,
+ fb_set_cmap: fbgen_set_cmap,
+ fb_pan_display: fbgen_pan_display,
+};
+
+static struct e1355fb_info fb_info;
+
+int __init e1355fb_setup(char *str)
+{
+ return 0;
+}
+
+int __init e1355fb_init(void)
+{
+ fb_info.gen.fbhw = &e1355_switch;
+ fb_info.gen.fbhw->detect();
+ strcpy(fb_info.gen.info.modename, "SED1355");
+ fb_info.gen.info.changevar = NULL;
+ fb_info.gen.info.node = -1;
+ fb_info.gen.info.fbops = &e1355fb_ops;
+ fb_info.gen.info.disp = &disp;
+ fb_info.gen.parsize = sizeof(struct e1355_par);
+ fb_info.gen.info.switch_con = &fbgen_switch;
+ fb_info.gen.info.updatevar = &fbgen_update_var;
+ fb_info.gen.info.blank = &fbgen_blank;
+ fb_info.gen.info.flags = FBINFO_FLAG_DEFAULT;
+ /* This should give a reasonable default video mode */
+ fbgen_get_var(&disp.var, -1, &fb_info.gen.info);
+ fbgen_do_set_var(&disp.var, 1, &fb_info.gen);
+ fbgen_set_disp(-1, &fb_info.gen);
+ if (disp.var.bits_per_pixel > 1)
+ fbgen_install_cmap(0, &fb_info.gen);
+ if (register_framebuffer(&fb_info.gen.info) < 0)
+ return -EINVAL;
+ printk(KERN_INFO "fb%d: %s frame buffer device\n", GET_FB_IDX(fb_info.gen.info.node),
+ fb_info.gen.info.modename);
+
+ return 0;
+}
+
+
+ /*
+ * Cleanup
+ */
+
+void e1355fb_cleanup(struct fb_info *info)
+{
+ /*
+ * If your driver supports multiple boards, you should unregister and
+ * clean up all instances.
+ */
+
+ unregister_framebuffer(info);
+ /* ... */
+}
+
extern int stifb_setup(char*);
extern int radeonfb_init(void);
extern int radeonfb_setup(char*);
-
+extern int e1355fb_init(void);
+extern int e1355fb_setup(char*);
+extern int dcfb_init(void);
+
static struct {
const char *name;
int (*init)(void);
#ifdef CONFIG_FB_SIS
{ "sisfb", sisfb_init, sisfb_setup },
#endif
+#ifdef CONFIG_FB_E1355
+ { "e1355fb", e1355fb_init, e1355fb_setup },
+#endif
/*
* Generic drivers that are used as fallbacks
#ifdef CONFIG_FB_HIT
{ "hitfb", hitfb_init, NULL },
#endif
+#ifdef CONFIG_FB_DC
+ { "dcfb", dcfb_init, NULL },
+#endif
/*
* Generic drivers that don't use resource management (yet)
} /* End Function devfsd_close */
-int __init init_devfs_fs (void)
+static int __init init_devfs_fs (void)
{
int err;
if (err == 0) printk ("Mounted devfs on /dev\n");
else printk ("Warning: unable to mount devfs, err: %d\n", err);
} /* End Function mount_devfs_fs */
+
+module_init(init_devfs_fs)
}
}
-int __init init_devpts_fs(void)
+static int __init init_devpts_fs(void)
{
int err = register_filesystem(&devpts_fs_type);
if (!err) {
err = PTR_ERR(devpts_mnt);
if (!IS_ERR(devpts_mnt))
err = 0;
- }
- return err;
-}
-
#ifdef MODULE
-
-int init_module(void)
-{
- int err = init_devpts_fs();
- if ( !err ) {
- devpts_upcall_new = devpts_pty_new;
- devpts_upcall_kill = devpts_pty_kill;
+ if ( !err ) {
+ devpts_upcall_new = devpts_pty_new;
+ devpts_upcall_kill = devpts_pty_kill;
+ }
+#endif
}
return err;
}
-void cleanup_module(void)
+static void __exit exit_devpts_fs(void)
{
+#ifdef MODULE
devpts_upcall_new = NULL;
devpts_upcall_kill = NULL;
+#endif
unregister_filesystem(&devpts_fs_type);
kern_umount(devpts_mnt);
}
-#endif
+module_init(init_devpts_fs)
+module_exit(exit_devpts_fs)
*/
#include <linux/config.h>
-#include <linux/fs.h>
-
-#include <linux/devfs_fs_kernel.h>
-#include <linux/nfs_fs.h>
-#include <linux/auto_fs.h>
-#include <linux/devpts_fs.h>
-#include <linux/major.h>
-#include <linux/smp.h>
+#include <linux/sched.h>
#include <linux/smp_lock.h>
#include <linux/kmod.h>
-#include <linux/init.h>
-#include <linux/module.h>
#include <linux/nfsd/interface.h>
-#ifdef CONFIG_DEVPTS_FS
-extern int init_devpts_fs(void);
-#endif
-
-void __init filesystem_setup(void)
-{
- init_devfs_fs(); /* Header file may make this empty */
-
-#ifdef CONFIG_NFS_FS
- init_nfs_fs();
-#endif
-
-#ifdef CONFIG_DEVPTS_FS
- init_devpts_fs();
-#endif
-}
-
#if defined(CONFIG_NFSD_MODULE)
struct nfsd_linkage *nfsd_linkage = NULL;
#include <linux/config.h>
#include <linux/module.h>
+#include <linux/init.h>
#include <linux/sched.h>
#include <linux/kernel.h>
/*
* Initialize NFS
*/
-int
-init_nfs_fs(void)
+static int __init init_nfs_fs(void)
{
int err;
return register_filesystem(&nfs_fs_type);
}
-/*
- * Every kernel module contains stuff like this.
- */
-#ifdef MODULE
-
-EXPORT_NO_SYMBOLS;
-/* Not quite true; I just maintain it */
-MODULE_AUTHOR("Olaf Kirch <okir@monad.swb.de>");
-
-int
-init_module(void)
-{
- return init_nfs_fs();
-}
-
-void
-cleanup_module(void)
+static void __exit exit_nfs_fs(void)
{
nfs_destroy_readpagecache();
nfs_destroy_nfspagecache();
#endif
unregister_filesystem(&nfs_fs_type);
}
-#endif
+
+EXPORT_NO_SYMBOLS;
+/* Not quite true; I just maintain it */
+MODULE_AUTHOR("Olaf Kirch <okir@monad.swb.de>");
+
+module_init(init_nfs_fs)
+module_exit(exit_nfs_fs)
O_TARGET := partitions.o
-export-objs := check.o
+export-objs := check.o ibm.o
obj-y := check.o
/*
* File...........: linux/fs/partitions/ibm.c
* Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
+ * Volker Sameske <sameske@de.ibm.com>
* Bugreports.to..: <Linux390@de.ibm.com>
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
* History of changes (starts July 2000)
- * 07/10/00 Fixed detection of CMS formatted disks
-
+ * 07/10/00 Fixed detection of CMS formatted disks
+ * 02/13/00 VTOC partition support added
*/
+#include <linux/config.h>
+#include <linux/module.h>
#include <linux/fs.h>
#include <linux/genhd.h>
#include <linux/kernel.h>
#include "ibm.h"
#include "check.h"
+#include <asm/vtoc.h>
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
/* We hook in when DASD is a module... */
int (*genhd_dasd_name)(char*,int,int,struct gendisk*) = NULL;
+int (*genhd_dasd_fillgeo)(int,struct hd_geometry *) = NULL;
+EXPORT_SYMBOL(genhd_dasd_fillgeo);
+EXPORT_SYMBOL(genhd_dasd_name);
#endif /* LINUX_IS_24 */
typedef enum {
- ibm_partition_none = 0,
- ibm_partition_lnx1 = 1,
- ibm_partition_vol1 = 3,
- ibm_partition_cms1 = 4
+ ibm_partition_lnx1 = 0,
+ ibm_partition_vol1 = 1,
+ ibm_partition_cms1 = 2,
+ ibm_partition_none = 3
} ibm_partition_t;
+static char* part_names[] = { [ibm_partition_lnx1] = "LNX1",
+ [ibm_partition_vol1] = "VOL1",
+ [ibm_partition_cms1] = "CMS1",
+ [ibm_partition_none] = "(nonl)"
+};
+
static ibm_partition_t
get_partition_type ( char * type )
{
- static char lnx[5]="LNX1";
- static char vol[5]="VOL1";
- static char cms[5]="CMS1";
- if ( ! strncmp ( lnx, "LNX1",4 ) ) {
- ASCEBC(lnx,4);
- ASCEBC(vol,4);
- ASCEBC(cms,4);
- }
- if ( ! strncmp (type,lnx,4) ||
- ! strncmp (type,"LNX1",4) )
- return ibm_partition_lnx1;
- if ( ! strncmp (type,vol,4) )
- return ibm_partition_vol1;
- if ( ! strncmp (type,cms,4) )
- return ibm_partition_cms1;
- return ibm_partition_none;
+ int i;
+ for ( i = 0; i < 3; i ++) {
+ if ( ! strncmp (type,part_names[i],4) )
+ break;
+ }
+ return i;
+}
+
+/*
+ * add the two default partitions
+ * - whole dasd
+ * - whole dasd without "offset"
+ */
+static inline void
+two_partitions(struct gendisk *hd,
+ int minor,
+ int blocksize,
+ int offset,
+ int size) {
+
+ add_gd_partition( hd, minor, 0,size);
+ add_gd_partition( hd, minor + 1,
+ offset * (blocksize >> 9),
+ size-offset*(blocksize>>9));
+}
+
+
+/*
+ * compute the block number from a
+ * cyl-cyl-head-head structure
+ */
+static inline int
+cchh2blk (cchh_t *ptr, struct hd_geometry *geo) {
+ return ptr->cc * geo->heads * geo->sectors +
+ ptr->hh * geo->sectors;
+}
+
+
+/*
+ * compute the block number from a
+ * cyl-cyl-head-head-block structure
+ */
+static inline int
+cchhb2blk (cchhb_t *ptr, struct hd_geometry *geo) {
+ return ptr->cc * geo->heads * geo->sectors +
+ ptr->hh * geo->sectors +
+ ptr->b;
}
int
ibm_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector, int
first_part_minor)
{
- struct buffer_head *bh;
+ struct buffer_head *bh, *buf;
ibm_partition_t partition_type;
char type[5] = {0,};
char name[7] = {0,};
struct hd_geometry geo;
- mm_segment_t old_fs;
int blocksize;
- struct file *filp = NULL;
- struct inode *inode = NULL;
- int offset, size;
+ int offset=0, size=0, psize=0, counter=0;
+ unsigned int blk;
+ format1_label_t f1;
+ volume_label_t vlabel;
+ if ( first_sector != 0 ) {
+ BUG();
+ }
+ if ( !genhd_dasd_fillgeo ) {
+ return 0;
+ }
+ genhd_dasd_fillgeo(dev,&geo);
blocksize = hardsect_size[MAJOR(dev)][MINOR(dev)];
if ( blocksize <= 0 ) {
return 0;
}
- set_blocksize(dev, blocksize); /* OUCH !! */
- /* find out offset of volume label (partn table) */
- inode = get_empty_inode();
- inode -> i_rdev = dev;
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
- inode -> i_bdev = bdget(kdev_t_to_nr(dev));
-#endif /* KERNEL_VERSION */
- filp = (struct file *)kmalloc (sizeof(struct file),GFP_KERNEL);
- if (!filp)
- return 0;
- memset(filp,0,sizeof(struct file));
- filp ->f_mode = 1; /* read only */
- blkdev_open(inode,filp);
- old_fs=get_fs();
- set_fs(KERNEL_DS);
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
- inode-> i_bdev -> bd_op->ioctl (inode, filp, HDIO_GETGEO, (unsigned long)(&geo));
-#else
- filp->f_op->ioctl (inode, filp, HDIO_GETGEO, (unsigned long)(&geo));
-#endif /* KERNEL_VERSION */
- set_fs(old_fs);
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0))
- blkdev_put(inode->i_bdev,BDEV_FILE);
-#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
- blkdev_close(inode,filp);
-#else
- blkdev_release(inode);
-#endif /* LINUX_VERSION_CODE */
-
- size = hd -> sizes[MINOR(dev)]<<1;
+ set_blocksize(dev, blocksize); /* OUCH !! */
if ( ( bh = bread( dev, geo.start, blocksize) ) != NULL ) {
- strncpy ( type,bh -> b_data, 4);
+ strncpy ( type,bh -> b_data + 0, 4);
strncpy ( name,bh -> b_data + 4, 6);
+ memcpy (&vlabel, bh->b_data, sizeof(volume_label_t));
} else {
return 0;
}
- if ( (*(char *)bh -> b_data) & 0x80 ) {
- EBCASC(name,6);
- }
- switch ( partition_type = get_partition_type(type) ) {
- case ibm_partition_lnx1:
- offset = (geo.start + 1);
- printk ( "(LNX1)/%6s:",name);
- break;
- case ibm_partition_vol1:
- offset = 0;
- size = 0;
- printk ( "(VOL1)/%6s:",name);
- break;
+ EBCASC(type,4);
+ EBCASC(name,6);
+
+ partition_type = get_partition_type(type);
+ printk ( "%6s/%6s:",part_names[partition_type],name);
+ switch ( partition_type ) {
case ibm_partition_cms1:
- printk ( "(CMS1)/%6s:",name);
- if (* (((long *)bh->b_data) + 13) == 0) {
- /* disk holds a CMS filesystem */
- offset = (geo.start + 1);
- printk ("(CMS)");
- } else {
+ if (* (((long *)bh->b_data) + 13) != 0) {
/* disk is reserved minidisk */
- // mdisk_setup_data.size[i] =
- // (label[7] - 1 - label[13]) *
- // (label[3] >> 9) >> 1;
long *label=(long*)bh->b_data;
blocksize = label[3];
offset = label[13];
size = (label[7]-1)*(blocksize>>9);
printk ("(MDSK)");
+ } else {
+ offset = (geo.start + 1);
+ size = hd -> sizes[MINOR(dev)]<<1;
}
+ two_partitions( hd, MINOR(dev), blocksize,
+ offset, size);
break;
+ case ibm_partition_lnx1:
case ibm_partition_none:
- printk ( "(nonl)/ :");
- offset = (geo.start+1);
+ offset = (geo.start + 1);
+ size = hd -> sizes[MINOR(dev)]<<1;
+ two_partitions( hd, MINOR(dev), blocksize,
+ offset, size);
+ break;
+ case ibm_partition_vol1:
+ add_gd_partition(hd, MINOR(dev), 0, size);
+
+ /* get block number and read then first format1 label */
+ blk = cchhb2blk(&vlabel.vtoc, &geo) + 1;
+ if ((buf = bread( dev, blk, blocksize)) != NULL) {
+ memcpy (&f1, buf->b_data, sizeof(format1_label_t));
+ bforget(buf);
+ }
+
+ while (f1.DS1FMTID == _ascebc['1']) {
+ offset = cchh2blk(&f1.DS1EXT1.llimit, &geo);
+ psize = cchh2blk(&f1.DS1EXT1.ulimit, &geo) -
+ offset + 1;
+
+ counter++;
+ add_gd_partition(hd, MINOR(dev) + counter,
+ offset * (blocksize >> 9),
+ psize * (blocksize >> 9));
+
+ blk++;
+ if ((buf = bread( dev, blk, blocksize)) != NULL) {
+ memcpy (&f1, buf->b_data,
+ sizeof(format1_label_t));
+ bforget(buf);
+ }
+ }
break;
default:
- offset = 0;
- size = 0;
-
+ add_gd_partition( hd, MINOR(dev), 0, 0);
+ add_gd_partition( hd, MINOR(dev) + 1, 0, 0);
}
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
- add_gd_partition( hd, MINOR(dev), 0,size);
- add_gd_partition( hd, MINOR(dev) + 1, offset * (blocksize >> 9),
- size-offset*(blocksize>>9));
-#else
- add_partition( hd, MINOR(dev), 0,size,0);
- add_partition( hd, MINOR(dev) + 1, offset * (blocksize >> 9),
- size-offset*(blocksize>>9) ,0 );
-#endif /* LINUX_VERSION */
+
printk ( "\n" );
bforget(bh);
return 1;
user += kstat.per_cpu_user[cpu];
nice += kstat.per_cpu_nice[cpu];
system += kstat.per_cpu_system[cpu];
+#if !defined(CONFIG_ARCH_S390)
for (j = 0 ; j < NR_IRQS ; j++)
sum += kstat.irqs[cpu][j];
+#endif
}
len = sprintf(page, "cpu %u %u %u %lu\n", user, nice, system,
kstat.pswpout,
sum
);
+#if !defined(CONFIG_ARCH_S390)
for (i = 0 ; i < NR_IRQS ; i++)
len += sprintf(page + len, " %u", kstat_irqs(i));
+#endif
len += sprintf(page + len, "\ndisk_io: ");
// do not count last 'end_bytes' units of 'end_item'-th item
end_bytes = (to_bytes != -1) ? to_bytes : 0;
- /* go through all item begining from the start_item-th item and ending by
+ /* go through all item beginning from the start_item-th item and ending by
the end_item-th item. Do not count first 'start_bytes' units of
'start_item'-th item and last 'end_bytes' of 'end_item'-th item */
{
do_reiserfs_warning;
/* console_print (error_buf); */
- printk ("%s", error_buf);
+ printk (KERN_WARNING "%s", error_buf);
}
void reiserfs_debug (struct super_block *s, int level, const char * fmt, ...)
{
#ifdef CONFIG_REISERFS_CHECK
do_reiserfs_warning;
- printk ("%s", error_buf);
+ printk (KERN_DEBUG "%s", error_buf);
#else
;
#endif
/* Parent at the path is not in the tree now. */
if ( ! B_IS_IN_TREE(p_s_parent = PATH_OFFSET_PBUFFER(p_s_chk_path, n_path_offset)) )
return &MIN_KEY;
- /* Check whether position in the parrent is correct. */
+ /* Check whether position in the parent is correct. */
if ( (n_position = PATH_OFFSET_POSITION(p_s_chk_path, n_path_offset)) > B_NR_ITEMS(p_s_parent) )
return &MIN_KEY;
/* Check whether parent at the path really points to the child. */
SB_BUFFER_WITH_SB (s) = bh;
SB_DISK_SUPER_BLOCK (s) = rs;
s->s_op = &reiserfs_sops;
+ s->s_maxbytes = MAX_NON_LFS;
return 0;
}
#endif
void *buf;
int result = -EIO;
+ page_cache_get(page);
lock_kernel();
- get_page(page);
- buf = page_address(page);
+ buf = kmap(page);
+ if (!buf)
+ goto err_out;
/* 32 bit warning -- but not for us :) */
offset = page->index << PAGE_CACHE_SHIFT;
UnlockPage(page);
- __free_page(page);
+ kunmap(page);
+err_out:
+ page_cache_release(page);
unlock_kernel();
return result;
if (!copy_from_user(&opt, (void *)arg, sizeof(opt)))
result = smb_newconn(server, &opt);
break;
- default:
+ default:;
}
return result;
#else
/*
* We don't want to be interrupted. For example, what if 'current'
- * already has recieved a signal? sleep_on would terminate immediately
+ * already has received a signal? sleep_on would terminate immediately
* and smbmount would not be able to re-establish connection.
*
* smbmount should be able to reconnect later, but it can't because
if (server->state == CONN_VALID) {
/* This should be changed to VERBOSE, except many smbfs
problems is with the userspace daemon not reconnecting. */
- PARANOIA("sucessful, new pid=%d, generation=%d\n",
+ PARANOIA("successful, new pid=%d, generation=%d\n",
server->conn_pid, server->generation);
result = 1;
}
}
-#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(__s390__) && !defined(__hppa__)
+#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(CONFIG_ARCH_S390) && !defined(__hppa__)
/*
* For backward compatibility? Maybe this should be moved
if (warncount > 0) {
warncount--;
- printk("VFS: Warning: %s using old stat() call. Recompile your binary.\n",
+ printk(KERN_WARNING "VFS: Warning: %s using old stat() call. Recompile your binary.\n",
current->comm);
} else if (warncount < 0) {
/* it's laughable, but... */
SET_OLDSTAT_GID(tmp, inode->i_gid);
tmp.st_rdev = kdev_t_to_nr(inode->i_rdev);
#if BITS_PER_LONG == 32
- if (inode->i_size > 0x7fffffff)
+ if (inode->i_size > MAX_NON_LFS)
return -EOVERFLOW;
#endif
tmp.st_size = inode->i_size;
SET_STAT_GID(tmp, inode->i_gid);
tmp.st_rdev = kdev_t_to_nr(inode->i_rdev);
#if BITS_PER_LONG == 32
- if (inode->i_size > 0x7fffffff)
+ if (inode->i_size > MAX_NON_LFS)
return -EOVERFLOW;
#endif
tmp.st_size = inode->i_size;
* the request.
*/
-struct super_block *get_empty_super(void)
+static struct super_block *get_empty_super(void)
{
struct super_block *s;
sema_init(&s->s_dquot.dqio_sem, 1);
sema_init(&s->s_dquot.dqoff_sem, 1);
s->s_dquot.flags = 0;
+ s->s_maxbytes = MAX_NON_LFS;
lock_super(s);
if (!type->read_super(s, data, silent))
goto out_fail;
mapsize = (rtl * sizeof(Uint32)) +
((partlen/(1 << sdata->s_spar_pshift)) * sizeof(Uint8) * num);
sdata->s_spar_map = kmalloc(mapsize, GFP_KERNEL);
+ if (!sdata->s_spar_map) {
+ printk("couldnt allocate UDF s_spar_map!\n");
+ return;
+ }
sdata->s_spar_remap.s_spar_remap32 = &sdata->s_spar_map[rtl];
memset(sdata->s_spar_map, 0xFF, mapsize);
}
#ifndef __ALPHA_IO_H
#define __ALPHA_IO_H
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <asm/system.h>
-
/* We don't use IO slowdowns on the Alpha, but.. */
#define __SLOW_DOWN_IO do { } while (0)
#define SLOW_DOWN_IO do { } while (0)
#endif
#ifdef __KERNEL__
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <asm/system.h>
#include <asm/machvec.h>
/*
#define TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */
#define TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */
+#define TIOCGHAYESESP 0x545E /* Get Hayes ESP configuration */
+#define TIOCSHAYESESP 0x545F /* Set Hayes ESP configuration */
#endif /* _ASM_ALPHA_IOCTLS_H */
#define pte_quicklist (quicklists.pte_cache)
#define pgtable_cache_size (quicklists.pgtable_cache_sz)
+#define pmd_populate(mm, pmd, pte) pmd_set(pmd, pte)
+#define pgd_populate(mm, pgd, pmd) pgd_set(pgd, pmd)
+
extern pgd_t *get_pgd_slow(void);
static inline pgd_t *get_pgd_fast(void)
free_page((unsigned long)pgd);
}
-extern pmd_t *get_pmd_slow(pgd_t *pgd, unsigned long address_premasked);
+static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long address)
+{
+ pmd_t *ret = (pmd_t *)__get_free_page(GFP_KERNEL);
+ if (ret)
+ clear_page(ret);
+ return ret;
+}
-static inline pmd_t *get_pmd_fast(void)
+static inline pmd_t *pmd_alloc_one_fast(struct mm_struct *mm, unsigned long address)
{
unsigned long *ret;
return (pmd_t *)ret;
}
-static inline void free_pmd_fast(pmd_t *pmd)
+static inline void pmd_free_fast(pmd_t *pmd)
{
*(unsigned long *)pmd = (unsigned long) pte_quicklist;
pte_quicklist = (unsigned long *) pmd;
pgtable_cache_size++;
}
-static inline void free_pmd_slow(pmd_t *pmd)
+static inline void pmd_free_slow(pmd_t *pmd)
{
free_page((unsigned long)pmd);
}
-extern pte_t *get_pte_slow(pmd_t *pmd, unsigned long address_preadjusted);
+static inline pte_t *pte_alloc_one(struct mm_struct *mm, unsigned long address)
+{
+ pte_t *pte = (pte_t *)__get_free_page(GFP_KERNEL);
+ if (pte)
+ clear_page(pte);
+ return pte;
+}
-static inline pte_t *get_pte_fast(void)
+static inline pte_t *pte_alloc_one_fast(struct mm_struct *mm, unsigned long address)
{
unsigned long *ret;
return (pte_t *)ret;
}
-static inline void free_pte_fast(pte_t *pte)
+static inline void pte_free_fast(pte_t *pte)
{
*(unsigned long *)pte = (unsigned long) pte_quicklist;
pte_quicklist = (unsigned long *) pte;
pgtable_cache_size++;
}
-static inline void free_pte_slow(pte_t *pte)
+static inline void pte_free_slow(pte_t *pte)
{
free_page((unsigned long)pte);
}
-extern void __bad_pte(pmd_t *pmd);
-extern void __bad_pmd(pgd_t *pgd);
-
-#define pte_free_kernel(pte) free_pte_fast(pte)
-#define pte_free(pte) free_pte_fast(pte)
-#define pmd_free_kernel(pmd) free_pmd_fast(pmd)
-#define pmd_free(pmd) free_pmd_fast(pmd)
+#define pte_free(pte) pte_free_fast(pte)
+#define pmd_free(pmd) pmd_free_fast(pmd)
#define pgd_free(pgd) free_pgd_fast(pgd)
#define pgd_alloc() get_pgd_fast()
-static inline pte_t * pte_alloc(pmd_t *pmd, unsigned long address)
-{
- address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
- if (pmd_none(*pmd)) {
- pte_t *page = get_pte_fast();
-
- if (!page)
- return get_pte_slow(pmd, address);
- pmd_set(pmd, page);
- return page + address;
- }
- if (pmd_bad(*pmd)) {
- __bad_pte(pmd);
- return NULL;
- }
- return (pte_t *) pmd_page(*pmd) + address;
-}
-
-static inline pmd_t * pmd_alloc(pgd_t *pgd, unsigned long address)
-{
- address = (address >> PMD_SHIFT) & (PTRS_PER_PMD - 1);
- if (pgd_none(*pgd)) {
- pmd_t *page = get_pmd_fast();
-
- if (!page)
- return get_pmd_slow(pgd, address);
- pgd_set(pgd, page);
- return page + address;
- }
- if (pgd_bad(*pgd)) {
- __bad_pmd(pgd);
- return NULL;
- }
- return (pmd_t *) pgd_page(*pgd) + address;
-}
-
-#define pte_alloc_kernel pte_alloc
-#define pmd_alloc_kernel pmd_alloc
-
extern int do_check_pgt_cache(int, int);
#endif /* _ALPHA_PGALLOC_H */
#define _PAGE_FOW 0x0004 /* used for page protection (fault on write) */
#define _PAGE_FOE 0x0008 /* used for page protection (fault on exec) */
#define _PAGE_ASM 0x0010
-#if defined(CONFIG_ALPHA_EV6) && !defined(CONFIG_SMP)
-#define _PAGE_MBE 0x0080 /* MB disable bit for EV6. */
-#else
-#define _PAGE_MBE 0x0000
-#endif
#define _PAGE_KRE 0x0100 /* xxx - see below on the "accessed" bit */
#define _PAGE_URE 0x0200 /* xxx */
#define _PAGE_KWE 0x1000 /* used to do the dirty bit in software */
#define _PFN_MASK 0xFFFFFFFF00000000
#define _PAGE_TABLE (_PAGE_VALID | __DIRTY_BITS | __ACCESS_BITS)
-#define _PAGE_CHG_MASK (_PFN_MASK | __DIRTY_BITS | __ACCESS_BITS | _PAGE_MBE)
+#define _PAGE_CHG_MASK (_PFN_MASK | __DIRTY_BITS | __ACCESS_BITS)
/*
- * All the normal masks have the "page accessed" bits on, as any time they
- * are used, the page is accessed. They are cleared only by the page-out
- * routines.
+ * All the normal masks have the "page accessed" bits on, as any time they are used,
+ * the page is accessed. They are cleared only by the page-out routines
*/
#define PAGE_NONE __pgprot(_PAGE_VALID | __ACCESS_BITS | _PAGE_FOR | _PAGE_FOW | _PAGE_FOE)
#define PAGE_SHARED __pgprot(_PAGE_VALID | __ACCESS_BITS)
#define PAGE_COPY __pgprot(_PAGE_VALID | __ACCESS_BITS | _PAGE_FOW)
#define PAGE_READONLY __pgprot(_PAGE_VALID | __ACCESS_BITS | _PAGE_FOW)
-#define PAGE_KERNEL __pgprot(_PAGE_VALID | _PAGE_ASM | _PAGE_KRE | _PAGE_KWE | _PAGE_MBE)
+#define PAGE_KERNEL __pgprot(_PAGE_VALID | _PAGE_ASM | _PAGE_KRE | _PAGE_KWE)
-#define _PAGE_NORMAL(x) __pgprot(_PAGE_VALID | __ACCESS_BITS | _PAGE_MBE | (x))
+#define _PAGE_NORMAL(x) __pgprot(_PAGE_VALID | __ACCESS_BITS | (x))
#define _PAGE_P(x) _PAGE_NORMAL((x) | (((x) & _PAGE_FOW)?0:_PAGE_FOW))
#define _PAGE_S(x) _PAGE_NORMAL(x)
* Conversion functions: convert a page and protection to a page entry,
* and a page entry and page directory to the page they refer to.
*/
-
#define mk_pte(page, pgprot) \
({ \
pte_t pte; \
})
extern inline pte_t mk_pte_phys(unsigned long physpage, pgprot_t pgprot)
-{ pte_t pte; pte_val(pte) = (PHYS_TWIDDLE(physpage) << (32-PAGE_SHIFT)) | (pgprot_val(pgprot) & ~_PAGE_MBE); return pte; }
+{ pte_t pte; pte_val(pte) = (PHYS_TWIDDLE(physpage) << (32-PAGE_SHIFT)) | pgprot_val(pgprot); return pte; }
extern inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
{ pte_val(pte) = (pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot); return pte; }
#include <asm/atomic.h>
#include <asm/compiler.h> /* __builtin_expect */
#include <linux/wait.h>
+#include <linux/rwsem.h>
#define DEBUG_SEMAPHORE 0
#define DEBUG_RW_SEMAPHORE 0
}
#endif
-/* rw mutexes (should that be mutices? =) -- throw rw
- * spinlocks and semaphores together, and this is what we
- * end up with...
- *
- * The lock is initialized to BIAS. This way, a writer
- * subtracts BIAS ands gets 0 for the case of an uncontended
- * lock. Readers decrement by 1 and see a positive value
- * when uncontended, negative if there are writers waiting
- * (in which case it goes to sleep).
- *
- * The value 0x01000000 supports up to 128 processors and
- * lots of processes. BIAS must be chosen such that subtracting
- * BIAS once per CPU will result in the int remaining
- * negative.
- * In terms of fairness, this should result in the lock
- * flopping back and forth between readers and writers
- * under heavy use.
- *
- * -ben
- *
- * Once we start supporting machines with more than 128 CPUs,
- * we should go for using a 64bit atomic type instead of 32bit
- * as counter. We shall probably go for bias 0x80000000 then,
- * so that single sethi can set it.
- *
- * -jj
- */
-
-#define RW_LOCK_BIAS 0x01000000
-
-struct rw_semaphore {
- atomic_t count;
- /* bit 0 means read bias granted;
- bit 1 means write bias granted. */
- unsigned granted;
- wait_queue_head_t wait;
- wait_queue_head_t write_bias_wait;
-#if WAITQUEUE_DEBUG
- long __magic;
- atomic_t readers;
- atomic_t writers;
-#endif
-};
-
-#if WAITQUEUE_DEBUG
-#define __RWSEM_DEBUG_INIT , ATOMIC_INIT(0), ATOMIC_INIT(0)
-#else
-#define __RWSEM_DEBUG_INIT /* */
-#endif
-
-#define __RWSEM_INITIALIZER(name,count) \
- { ATOMIC_INIT(count), 0, __WAIT_QUEUE_HEAD_INITIALIZER((name).wait), \
- __WAIT_QUEUE_HEAD_INITIALIZER((name).write_bias_wait) \
- __SEM_DEBUG_INIT(name) __RWSEM_DEBUG_INIT }
-
-#define __DECLARE_RWSEM_GENERIC(name,count) \
- struct rw_semaphore name = __RWSEM_INITIALIZER(name,count)
-
-#define DECLARE_RWSEM(name) \
- __DECLARE_RWSEM_GENERIC(name, RW_LOCK_BIAS)
-#define DECLARE_RWSEM_READ_LOCKED(name) \
- __DECLARE_RWSEM_GENERIC(name, RW_LOCK_BIAS-1)
-#define DECLARE_RWSEM_WRITE_LOCKED(name) \
- __DECLARE_RWSEM_GENERIC(name, 0)
-
-static inline void init_rwsem(struct rw_semaphore *sem)
-{
- atomic_set (&sem->count, RW_LOCK_BIAS);
- sem->granted = 0;
- init_waitqueue_head(&sem->wait);
- init_waitqueue_head(&sem->write_bias_wait);
-#if WAITQUEUE_DEBUG
- sem->__magic = (long)&sem->__magic;
- atomic_set(&sem->readers, 0);
- atomic_set(&sem->writers, 0);
-#endif
-}
-
-extern void down_read(struct rw_semaphore *);
-extern void down_write(struct rw_semaphore *);
-extern void up_read(struct rw_semaphore *);
-extern void up_write(struct rw_semaphore *);
-extern void __down_read_failed(struct rw_semaphore *, int);
-extern void __down_write_failed(struct rw_semaphore *, int);
-extern void __rwsem_wake(struct rw_semaphore *, int);
-
-static inline void __down_read(struct rw_semaphore *sem)
-{
- long count = atomic_dec_return(&sem->count);
- if (__builtin_expect(count < 0, 0))
- __down_read_failed(sem, count);
-}
-
-static inline void __down_write(struct rw_semaphore *sem)
-{
- long count = atomic_sub_return(RW_LOCK_BIAS, &sem->count);
- if (__builtin_expect(count != 0, 0))
- __down_write_failed(sem, count);
-}
-
-/* When a reader does a release, the only significant case is when there
- was a writer waiting, and we've bumped the count to 0, then we must
- wake the writer up. */
-
-static inline void __up_read(struct rw_semaphore *sem)
-{
- long count;
- mb();
- count = atomic_inc_return(&sem->count);
- if (__builtin_expect(count == 0, 0))
- __rwsem_wake(sem, 0);
-}
-
-/* Releasing the writer is easy -- just release it and wake up
- any sleepers. */
-
-static inline void __up_write(struct rw_semaphore *sem)
-{
- long count, wake;
- mb();
- count = atomic_add_return(RW_LOCK_BIAS, &sem->count);
-
- /* Only do the wake if we were, but are no longer, negative. */
- wake = ((int)(count - RW_LOCK_BIAS) < 0) && count >= 0;
- if (__builtin_expect(wake, 0))
- __rwsem_wake(sem, count);
-}
-
-#if !WAITQUEUE_DEBUG && !DEBUG_RW_SEMAPHORE
-extern inline void down_read(struct rw_semaphore *sem)
-{
- __down_read(sem);
-}
-extern inline void down_write(struct rw_semaphore *sem)
-{
- __down_write(sem);
-}
-extern inline void up_read(struct rw_semaphore *sem)
-{
- __up_read(sem);
-}
-extern inline void up_write(struct rw_semaphore *sem)
-{
- __up_write(sem);
-}
#endif
#endif
#include <linux/linkage.h>
#include <linux/spinlock.h>
#include <linux/wait.h>
+#include <linux/rwsem.h>
#include <asm/atomic.h>
#include <asm/proc/locks.h>
__up_op(sem, __up_wakeup);
}
-/* rw mutexes (should that be mutices? =) -- throw rw
- * spinlocks and semaphores together, and this is what we
- * end up with...
- *
- * The lock is initialized to BIAS. This way, a writer
- * subtracts BIAS ands gets 0 for the case of an uncontended
- * lock. Readers decrement by 1 and see a positive value
- * when uncontended, negative if there are writers waiting
- * (in which case it goes to sleep).
- *
- * In terms of fairness, this should result in the lock
- * flopping back and forth between readers and writers
- * under heavy use.
- *
- * -ben
- */
-struct rw_semaphore {
- atomic_t count;
- volatile unsigned char write_bias_granted;
- volatile unsigned char read_bias_granted;
- volatile unsigned char pad1;
- volatile unsigned char pad2;
- wait_queue_head_t wait;
- wait_queue_head_t write_bias_wait;
-#if WAITQUEUE_DEBUG
- long __magic;
- atomic_t readers;
- atomic_t writers;
-#endif
-};
-
-#if WAITQUEUE_DEBUG
-#define __RWSEM_DEBUG_INIT , ATOMIC_INIT(0), ATOMIC_INIT(0)
-#else
-#define __RWSEM_DEBUG_INIT /* */
-#endif
-
-#define __RWSEM_INITIALIZER(name,count) \
-{ ATOMIC_INIT(count), 0, 0, 0, 0, __WAIT_QUEUE_HEAD_INITIALIZER((name).wait), \
- __WAIT_QUEUE_HEAD_INITIALIZER((name).write_bias_wait) \
- __SEM_DEBUG_INIT(name) __RWSEM_DEBUG_INIT }
-
-#define __DECLARE_RWSEM_GENERIC(name,count) \
- struct rw_semaphore name = __RWSEM_INITIALIZER(name,count)
-
-#define DECLARE_RWSEM(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS)
-#define DECLARE_RWSEM_READ_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS-1)
-#define DECLARE_RWSEM_WRITE_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,0)
-
-extern inline void init_rwsem(struct rw_semaphore *sem)
-{
- atomic_set(&sem->count, RW_LOCK_BIAS);
- sem->read_bias_granted = 0;
- sem->write_bias_granted = 0;
- init_waitqueue_head(&sem->wait);
- init_waitqueue_head(&sem->write_bias_wait);
-#if WAITQUEUE_DEBUG
- sem->__magic = (long)&sem->__magic;
- atomic_set(&sem->readers, 0);
- atomic_set(&sem->writers, 0);
-#endif
-}
-
-extern struct rw_semaphore *__down_read_failed(struct rw_semaphore *sem);
-extern struct rw_semaphore *__down_write_failed(struct rw_semaphore *sem);
-extern struct rw_semaphore *__rwsem_wake(struct rw_semaphore *sem);
-
-extern inline void down_read(struct rw_semaphore *sem)
-{
-#if WAITQUEUE_DEBUG
- CHECK_MAGIC(sem->__magic);
-#endif
- __down_op_read(sem, __down_read_failed);
-#if WAITQUEUE_DEBUG
- if (sem->write_bias_granted)
- BUG();
- if (atomic_read(&sem->writers))
- BUG();
- atomic_inc(&sem->readers);
-#endif
-}
-
-extern inline void down_write(struct rw_semaphore *sem)
-{
-#if WAITQUEUE_DEBUG
- CHECK_MAGIC(sem->__magic);
-#endif
- __down_op_write(sem, __down_write_failed);
-#if WAITQUEUE_DEBUG
- if (atomic_read(&sem->writers))
- BUG();
- if (atomic_read(&sem->readers))
- BUG();
- if (sem->read_bias_granted)
- BUG();
- if (sem->write_bias_granted)
- BUG();
- atomic_inc(&sem->writers);
-#endif
-}
-
-extern inline void up_read(struct rw_semaphore *sem)
-{
-#if WAITQUEUE_DEBUG
- if (sem->write_bias_granted)
- BUG();
- if (atomic_read(&sem->writers))
- BUG();
- atomic_dec(&sem->readers);
-#endif
- __up_op_read(sem, __rwsem_wake);
-}
-
-extern inline void up_write(struct rw_semaphore *sem)
-{
-#if WAITQUEUE_DEBUG
- if (sem->read_bias_granted)
- BUG();
- if (sem->write_bias_granted)
- BUG();
- if (atomic_read(&sem->readers))
- BUG();
- if (atomic_read(&sem->writers) != 1)
- BUG();
- atomic_dec(&sem->writers);
-#endif
- __up_op_write(sem, __rwsem_wake);
-}
-
#endif
#include <linux/wait.h>
#include <linux/spinlock.h>
+#include <linux/rwsem.h>
#include <asm/system.h>
#include <asm/atomic.h>
}
}
-/* rw mutexes (should that be mutices? =) -- throw rw
- * spinlocks and semaphores together, and this is what we
- * end up with...
- *
- * The lock is initialized to BIAS. This way, a writer
- * subtracts BIAS ands gets 0 for the case of an uncontended
- * lock. Readers decrement by 1 and see a positive value
- * when uncontended, negative if there are writers waiting
- * (in which case it goes to sleep).
- *
- * In terms of fairness, this should result in the lock
- * flopping back and forth between readers and writers
- * under heavy use.
- *
- * -ben
- */
-
-struct rw_semaphore {
- atomic_t count;
- /* bit 0 means read bias granted;
- bit 1 means write bias granted. */
- unsigned granted;
- wait_queue_head_t wait;
- wait_queue_head_t write_bias_wait;
-#if WAITQUEUE_DEBUG
- long __magic;
- atomic_t readers;
- atomic_t writers;
-#endif
-};
-
-#if WAITQUEUE_DEBUG
-#define __RWSEM_DEBUG_INIT , ATOMIC_INIT(0), ATOMIC_INIT(0)
-#else
-#define __RWSEM_DEBUG_INIT /* */
-#endif
-
-#define __RWSEM_INITIALIZER(name,count) \
-{ ATOMIC_INIT(count), 0, __WAIT_QUEUE_HEAD_INITIALIZER((name).wait), \
- __WAIT_QUEUE_HEAD_INITIALIZER((name).write_bias_wait) \
- __SEM_DEBUG_INIT(name) __RWSEM_DEBUG_INIT }
-
-#define __DECLARE_RWSEM_GENERIC(name,count) \
- struct rw_semaphore name = __RWSEM_INITIALIZER(name,count)
-
-#define DECLARE_RWSEM(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS)
-#define DECLARE_RWSEM_READ_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS-1)
-#define DECLARE_RWSEM_WRITE_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,0)
-
-extern inline void init_rwsem(struct rw_semaphore *sem)
-{
- atomic_set(&sem->count, RW_LOCK_BIAS);
- sem->granted = 0;
- init_waitqueue_head(&sem->wait);
- init_waitqueue_head(&sem->write_bias_wait);
-#if WAITQUEUE_DEBUG
- sem->__magic = (long)&sem->__magic;
- atomic_set(&sem->readers, 0);
- atomic_set(&sem->writers, 0);
-#endif
-}
-
-/* The expensive part is outlined. */
-extern void __down_read(struct rw_semaphore *sem, int count);
-extern void __down_write(struct rw_semaphore *sem, int count);
-extern void __rwsem_wake(struct rw_semaphore *sem, unsigned long readers);
-
-extern inline void down_read(struct rw_semaphore *sem)
-{
- int count;
-
-#if WAITQUEUE_DEBUG
- CHECK_MAGIC(sem->__magic);
-#endif
-
- count = atomic_dec_return(&sem->count);
- if (count < 0) {
- __down_read(sem, count);
- }
- mb();
-
-#if WAITQUEUE_DEBUG
- if (sem->granted & 2)
- BUG();
- if (atomic_read(&sem->writers))
- BUG();
- atomic_inc(&sem->readers);
-#endif
-}
-
-extern inline void down_write(struct rw_semaphore *sem)
-{
- int count;
-
-#if WAITQUEUE_DEBUG
- CHECK_MAGIC(sem->__magic);
-#endif
-
- count = atomic_sub_return(RW_LOCK_BIAS, &sem->count);
- if (count) {
- __down_write(sem, count);
- }
- mb();
-
-#if WAITQUEUE_DEBUG
- if (atomic_read(&sem->writers))
- BUG();
- if (atomic_read(&sem->readers))
- BUG();
- if (sem->granted & 3)
- BUG();
- atomic_inc(&sem->writers);
-#endif
-}
-
-/* When a reader does a release, the only significant case is when
- there was a writer waiting, and we've bumped the count to 0: we must
- wake the writer up. */
-
-extern inline void up_read(struct rw_semaphore *sem)
-{
-#if WAITQUEUE_DEBUG
- CHECK_MAGIC(sem->__magic);
- if (sem->granted & 2)
- BUG();
- if (atomic_read(&sem->writers))
- BUG();
- atomic_dec(&sem->readers);
-#endif
-
- mb();
- if (atomic_inc_return(&sem->count) == 0)
- __rwsem_wake(sem, 0);
-}
-
-/*
- * Releasing the writer is easy -- just release it and wake up any sleepers.
- */
-extern inline void up_write(struct rw_semaphore *sem)
-{
- int count;
-
-#if WAITQUEUE_DEBUG
- CHECK_MAGIC(sem->__magic);
- if (sem->granted & 3)
- BUG();
- if (atomic_read(&sem->readers))
- BUG();
- if (atomic_read(&sem->writers) != 1)
- BUG();
- atomic_dec(&sem->writers);
-#endif
-
- mb();
- count = atomic_add_return(RW_LOCK_BIAS, &sem->count);
- if (count - RW_LOCK_BIAS < 0 && count >= 0) {
- /* Only do the wake if we're no longer negative. */
- __rwsem_wake(sem, count);
- }
-}
-
#endif
#ifdef __KERNEL__
-#define CONFIG_USING_SPINLOCK_BASED_RWSEM 1
-
/*
* the semaphore definition
*/
-/* rwsem.h: R/W semaphores based on spinlocks
+/* rwsem.h: R/W semaphores optimised using i386 assembly
*
* Written by David Howells (dhowells@redhat.com).
*
#ifdef __KERNEL__
-#define __HAVE_ARCH_SPECIFIC_RWSEM_IMPLEMENTATION 1
#ifdef CONFIG_X86_XADD
#include <asm/rwsem-xadd.h> /* use XADD based semaphores if possible */
#else
(granularity << IA32_SEG_G) | \
(((base >> 24) & 0xFF) << IA32_SEG_HIGH_BASE))
-#define IA32_IOBASE 0x2000000000000000 /* Virtual addres for I/O space */
+#define IA32_IOBASE 0x2000000000000000 /* Virtual address for I/O space */
#define IA32_CR0 0x80000001 /* Enable PG and PE bits */
#define IA32_CR4 0 /* No architectural extensions */
*/
#include <linux/wait.h>
+#include <linux/rwsem.h>
#include <asm/atomic.h>
__up(sem);
}
-/*
- * rw mutexes (should that be mutices? =) -- throw rw spinlocks and
- * semaphores together, and this is what we end up with...
- *
- * The lock is initialized to BIAS. This way, a writer subtracts BIAS
- * ands gets 0 for the case of an uncontended lock. Readers decrement
- * by 1 and see a positive value when uncontended, negative if there
- * are writers waiting (in which case it goes to sleep). BIAS must be
- * chosen such that subtracting BIAS once per CPU will result either
- * in zero (uncontended case) or in a negative value (contention
- * case). On the other hand, BIAS must be at least as big as the
- * number of processes in the system.
- *
- * On IA-64, we use a BIAS value of 0x100000000, which supports up to
- * 2 billion (2^31) processors and 4 billion processes.
- *
- * In terms of fairness, when there is heavy use of the lock, we want
- * to see the lock being passed back and forth between readers and
- * writers (like in a producer/consumer style of communication).
- *
- * -ben (with clarifications & IA-64 comments by davidm)
- */
-#define RW_LOCK_BIAS 0x100000000ul
-
-struct rw_semaphore {
- volatile long count;
- volatile __u8 write_bias_granted;
- volatile __u8 read_bias_granted;
- __u16 pad1;
- __u32 pad2;
- wait_queue_head_t wait;
- wait_queue_head_t write_bias_wait;
-#if WAITQUEUE_DEBUG
- long __magic;
- atomic_t readers;
- atomic_t writers;
-#endif
-};
-
-#if WAITQUEUE_DEBUG
-# define __RWSEM_DEBUG_INIT , ATOMIC_INIT(0), ATOMIC_INIT(0)
-#else
-# define __RWSEM_DEBUG_INIT
-#endif
-
-#define __RWSEM_INITIALIZER(name,count) \
-{ \
- (count), 0, 0, 0, 0, __WAIT_QUEUE_HEAD_INITIALIZER((name).wait), \
- __WAIT_QUEUE_HEAD_INITIALIZER((name).write_bias_wait) \
- __SEM_DEBUG_INIT(name) __RWSEM_DEBUG_INIT \
-}
-
-#define __DECLARE_RWSEM_GENERIC(name,count) \
- struct rw_semaphore name = __RWSEM_INITIALIZER(name,count)
-
-#define DECLARE_RWSEM(name) __DECLARE_RWSEM_GENERIC(name, RW_LOCK_BIAS)
-#define DECLARE_RWSEM_READ_LOCKED(name) __DECLARE_RWSEM_GENERIC(name, RW_LOCK_BIAS - 1)
-#define DECLARE_RWSEM_WRITE_LOCKED(name) __DECLARE_RWSEM_GENERIC(name, 0)
-
-extern void __down_read_failed (struct rw_semaphore *sem, long count);
-extern void __down_write_failed (struct rw_semaphore *sem, long count);
-extern void __rwsem_wake (struct rw_semaphore *sem, long count);
-
-static inline void
-init_rwsem (struct rw_semaphore *sem)
-{
- sem->count = RW_LOCK_BIAS;
- sem->read_bias_granted = 0;
- sem->write_bias_granted = 0;
- init_waitqueue_head(&sem->wait);
- init_waitqueue_head(&sem->write_bias_wait);
-#if WAITQUEUE_DEBUG
- sem->__magic = (long)&sem->__magic;
- atomic_set(&sem->readers, 0);
- atomic_set(&sem->writers, 0);
-#endif
-}
-
-static inline void
-down_read (struct rw_semaphore *sem)
-{
- long count;
-
-#if WAITQUEUE_DEBUG
- CHECK_MAGIC(sem->__magic);
-#endif
-
- count = ia64_fetch_and_add(-1, &sem->count);
- if (count < 0)
- __down_read_failed(sem, count);
-
-#if WAITQUEUE_DEBUG
- if (sem->write_bias_granted)
- BUG();
- if (atomic_read(&sem->writers))
- BUG();
- atomic_inc(&sem->readers);
-#endif
-}
-
-static inline void
-down_write (struct rw_semaphore *sem)
-{
- long old_count, new_count;
-
-#if WAITQUEUE_DEBUG
- CHECK_MAGIC(sem->__magic);
-#endif
-
- do {
- old_count = sem->count;
- new_count = old_count - RW_LOCK_BIAS;
- } while (cmpxchg_acq(&sem->count, old_count, new_count) != old_count);
-
- if (new_count != 0)
- __down_write_failed(sem, new_count);
-#if WAITQUEUE_DEBUG
- if (atomic_read(&sem->writers))
- BUG();
- if (atomic_read(&sem->readers))
- BUG();
- if (sem->read_bias_granted)
- BUG();
- if (sem->write_bias_granted)
- BUG();
- atomic_inc(&sem->writers);
-#endif
-}
-
-/*
- * When a reader does a release, the only significant
- * case is when there was a writer waiting, and we've
- * bumped the count to 0: we must wake the writer up.
- */
-static inline void
-__up_read (struct rw_semaphore *sem)
-{
- long count;
-
- count = ia64_fetch_and_add(1, &sem->count);
- if (count == 0)
- /*
- * Other processes are blocked already; resolve
- * contention by letting either a writer or a reader
- * proceed...
- */
- __rwsem_wake(sem, count);
-}
-
-/*
- * Releasing the writer is easy -- just release it and
- * wake up any sleepers.
- */
-static inline void
-__up_write (struct rw_semaphore *sem)
-{
- long old_count, new_count;
-
- do {
- old_count = sem->count;
- new_count = old_count + RW_LOCK_BIAS;
- } while (cmpxchg_rel(&sem->count, old_count, new_count) != old_count);
-
- /*
- * Note: new_count <u RW_LOCK_BIAS <=> old_count < 0 && new_count >= 0.
- * (where <u is "unsigned less-than").
- */
- if ((unsigned long) new_count < RW_LOCK_BIAS)
- /* someone is blocked already, resolve contention... */
- __rwsem_wake(sem, new_count);
-}
-
-static inline void
-up_read (struct rw_semaphore *sem)
-{
-#if WAITQUEUE_DEBUG
- if (sem->write_bias_granted)
- BUG();
- if (atomic_read(&sem->writers))
- BUG();
- atomic_dec(&sem->readers);
-#endif
- __up_read(sem);
-}
-
-static inline void
-up_write (struct rw_semaphore *sem)
-{
-#if WAITQUEUE_DEBUG
- if (sem->read_bias_granted)
- BUG();
- if (sem->write_bias_granted)
- BUG();
- if (atomic_read(&sem->readers))
- BUG();
- if (atomic_read(&sem->writers) != 1)
- BUG();
- atomic_dec(&sem->writers);
-#endif
- __up_write(sem);
-}
-
#endif /* _ASM_IA64_SEMAPHORE_H */
#include <linux/linkage.h>
#include <linux/wait.h>
#include <linux/spinlock.h>
+#include <linux/rwsem.h>
#include <asm/system.h>
#include <asm/atomic.h>
: "memory");
}
-
-/* rw mutexes (should that be mutices? =) -- throw rw
- * spinlocks and semaphores together, and this is what we
- * end up with...
- *
- * m68k version by Roman Zippel
- */
-
-struct rw_semaphore {
- atomic_t count;
- volatile unsigned char write_bias_granted;
- volatile unsigned char read_bias_granted;
- volatile unsigned char pad1;
- volatile unsigned char pad2;
- wait_queue_head_t wait;
- wait_queue_head_t write_bias_wait;
-#if WAITQUEUE_DEBUG
- long __magic;
- atomic_t readers;
- atomic_t writers;
-#endif
-};
-
-#if WAITQUEUE_DEBUG
-#define __RWSEM_DEBUG_INIT , ATOMIC_INIT(0), ATOMIC_INIT(0)
-#else
-#define __RWSEM_DEBUG_INIT /* */
-#endif
-
-#define __RWSEM_INITIALIZER(name,count) \
-{ ATOMIC_INIT(count), 0, 0, 0, 0, __WAIT_QUEUE_HEAD_INITIALIZER((name).wait), \
- __WAIT_QUEUE_HEAD_INITIALIZER((name).write_bias_wait) \
- __SEM_DEBUG_INIT(name) __RWSEM_DEBUG_INIT }
-
-#define __DECLARE_RWSEM_GENERIC(name,count) \
- struct rw_semaphore name = __RWSEM_INITIALIZER(name,count)
-
-#define DECLARE_RWSEM(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS)
-#define DECLARE_RWSEM_READ_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS-1)
-#define DECLARE_RWSEM_WRITE_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,0)
-
-extern inline void init_rwsem(struct rw_semaphore *sem)
-{
- atomic_set(&sem->count, RW_LOCK_BIAS);
- sem->read_bias_granted = 0;
- sem->write_bias_granted = 0;
- init_waitqueue_head(&sem->wait);
- init_waitqueue_head(&sem->write_bias_wait);
-#if WAITQUEUE_DEBUG
- sem->__magic = (long)&sem->__magic;
- atomic_set(&sem->readers, 0);
- atomic_set(&sem->writers, 0);
-#endif
-}
-
-extern inline void down_read(struct rw_semaphore *sem)
-{
- register struct rw_semaphore *__sem __asm__ ("%a1") = sem;
-
-#if WAITQUEUE_DEBUG
- if (sem->__magic != (long)&sem->__magic)
- BUG();
-#endif
- __asm__ __volatile__(
- "| atomic down_read operation\n\t"
- "subql #1,%0@\n\t"
- "jmi 2f\n"
- "1:\n"
- ".section .text.lock,\"ax\"\n"
- ".even\n"
- "2:\n\t"
- "pea 1b\n\t"
- "jbra __down_read_failed\n"
- ".previous"
- : /* no outputs */
- : "a" (__sem)
- : "memory");
-#if WAITQUEUE_DEBUG
- if (sem->write_bias_granted)
- BUG();
- if (atomic_read(&sem->writers))
- BUG();
- atomic_inc(&sem->readers);
-#endif
-}
-
-extern inline void down_write(struct rw_semaphore *sem)
-{
- register struct rw_semaphore *__sem __asm__ ("%a1") = sem;
-
-#if WAITQUEUE_DEBUG
- if (sem->__magic != (long)&sem->__magic)
- BUG();
-#endif
- __asm__ __volatile__(
- "| atomic down_write operation\n\t"
- "subl %1,%0@\n\t"
- "jne 2f\n"
- "1:\n"
- ".section .text.lock,\"ax\"\n"
- ".even\n"
- "2:\n\t"
- "pea 1b\n\t"
- "jbra __down_write_failed\n"
- ".previous"
- : /* no outputs */
- : "a" (__sem), "id" (RW_LOCK_BIAS)
- : "memory");
-#if WAITQUEUE_DEBUG
- if (atomic_read(&sem->writers))
- BUG();
- if (atomic_read(&sem->readers))
- BUG();
- if (sem->read_bias_granted)
- BUG();
- if (sem->write_bias_granted)
- BUG();
- atomic_inc(&sem->writers);
-#endif
-}
-
-/* When a reader does a release, the only significant
- * case is when there was a writer waiting, and we've
- * bumped the count to 0: we must wake the writer up.
- */
-extern inline void __up_read(struct rw_semaphore *sem)
-{
- register struct rw_semaphore *__sem __asm__ ("%a1") = sem;
-
- __asm__ __volatile__(
- "| atomic up_read operation\n\t"
- "addql #1,%0@\n\t"
- "jeq 2f\n"
- "1:\n"
- ".section .text.lock,\"ax\"\n"
- ".even\n"
- "2:\n\t"
- "pea 1b\n\t"
- "jbra __rwsem_wake\n"
- ".previous"
- : /* no outputs */
- : "a" (__sem)
- : "memory");
-}
-
-extern inline void up_read(struct rw_semaphore *sem)
-{
-#if WAITQUEUE_DEBUG
- if (sem->write_bias_granted)
- BUG();
- if (atomic_read(&sem->writers))
- BUG();
- atomic_dec(&sem->readers);
-#endif
- __up_read(sem);
-}
-
-/* releasing the writer is easy -- just release it and
- * wake up any sleepers.
- */
-extern inline void __up_write(struct rw_semaphore *sem)
-{
- register struct rw_semaphore *__sem __asm__ ("%a1") = sem;
-
- __asm__ __volatile__(
- "| atomic up_write operation\n\t"
- "addl %1,%0@\n\t"
- "jcs 2f\n"
- "1:\n"
- ".section .text.lock,\"ax\"\n"
- ".even\n"
- "2:\n\t"
- "pea 1b\n\t"
- "jbra __rwsem_wake\n"
- ".previous"
- : /* no outputs */
- : "a" (__sem), "id" (RW_LOCK_BIAS)
- : "memory");
-}
-
-extern inline void up_write(struct rw_semaphore *sem)
-{
-#if WAITQUEUE_DEBUG
- if (sem->read_bias_granted)
- BUG();
- if (sem->write_bias_granted)
- BUG();
- if (atomic_read(&sem->readers))
- BUG();
- if (atomic_read(&sem->writers) != 1)
- BUG();
- atomic_dec(&sem->writers);
-#endif
- __up_write(sem);
-}
#endif /* __ASSEMBLY__ */
#endif
-/* $Id: bootinfo.h,v 1.11 2000/03/06 11:14:32 raiko Exp $
- *
- * bootinfo.h -- Definition of the Linux/MIPS boot information structure
- *
- * Copyright (C) 1995, 1996 by Ralf Baechle, Andreas Busse,
- * Stoned Elipot and Paul M. Antoine.
- *
+/*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of this archive
* for more details.
+ *
+ * Copyright (C) 1995, 1996 by Ralf Baechle, Andreas Busse,
+ * Stoned Elipot and Paul M. Antoine.
*/
-#ifndef __ASM_MIPS_BOOTINFO_H
-#define __ASM_MIPS_BOOTINFO_H
+#ifndef _ASM_BOOTINFO_H
+#define _ASM_BOOTINFO_H
/*
* Values for machgroup
* Valid machtype for group NEC DDB
*/
#define MACH_NEC_DDB5074 0 /* NEC DDB Vrc-5074 */
+#define MACH_NEC_DDB5476 1 /* NEC DDB Vrc-5476 */
-#define GROUP_NEC_DDB_NAMES { "Vrc-5074" }
+#define GROUP_NEC_DDB_NAMES { "Vrc-5074", "Vrc-5476"}
/*
* Valid machtype for group BAGET
--- /dev/null
+/*
+ *
+ * BRIEF MODULE DESCRIPTION
+ * IT8172 system controller defines.
+ *
+ * Copyright 2000 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ * ppopov@mvista.com or support@mvista.com
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __IT8172__H__
+#define __IT8172__H__
+
+#include <asm/addrspace.h>
+
+#define IT8172_BASE 0x18000000
+#define IT8172_PCI_IO_BASE 0x14000000
+#define IT8172_PCI_MEM_BASE 0x10000000
+
+// System registers offsets from IT8172_BASE
+#define IT_CMFPCR 0x0
+#define IT_DSRR 0x2
+#define IT_PCDCR 0x4
+#define IT_SPLLCR 0x6
+#define IT_CIDR 0x10
+#define IT_CRNR 0x12
+#define IT_CPUTR 0x14
+#define IT_CTCR 0x16
+#define IT_SDPR 0xF0
+
+// Power management register offset from IT8172_PCI_IO_BASE
+// Power Management Device Standby Register
+#define IT_PM_DSR 0x15800
+
+#define IT_PM_DSR_TMR0SB 0x0001
+#define IT_PM_DSR_TMR1SB 0x0002
+#define IT_PM_DSR_CIR0SB 0x0004
+#define IT_PM_DSR_CIR1SB 0x0008
+#define IT_PM_DSR_SCR0SB 0x0010
+#define IT_PM_DSR_SCR1SB 0x0020
+#define IT_PM_DSR_PPSB 0x0040
+#define IT_PM_DSR_I2CSB 0x0080
+#define IT_PM_DSR_UARTSB 0x0100
+#define IT_PM_DSR_IDESB 0x0200
+#define IT_PM_DSR_ACSB 0x0400
+#define IT_PM_DSR_M68KSB 0x0800
+
+// Power Management PCI Device Software Reset Register
+#define IT_PM_PCISR 0x15802
+
+#define IT_PM_PCISR_IDESR 0x0001
+#define IT_PM_PCISR_CDMASR 0x0002
+#define IT_PM_PCISR_USBSR 0x0004
+#define IT_PM_PCISR_DMASR 0x0008
+#define IT_PM_PCISR_ACSR 0x0010
+#define IT_PM_PCISR_MEMSR 0x0020
+#define IT_PM_PCISR_68KSR 0x0040
+
+
+// PCI Configuration address and data register offsets
+// from IT8172_BASE
+#define IT_CONFADDR 0x4000
+#define IT_BUSNUM_SHF 16
+#define IT_DEVNUM_SHF 11
+#define IT_FUNCNUM_SHF 8
+#define IT_REGNUM_SHF 2
+
+#define IT_CONFDATA 0x4004
+
+// PCI configuration header common register offsets
+#define IT_VID 0x00
+#define IT_DID 0x02
+#define IT_PCICMD 0x04
+#define IT_PCISTS 0x06
+#define IT_RID 0x08
+#define IT_CLASSC 0x09
+#define IT_HEADT 0x0E
+#define IT_SERIRQC 0x49
+
+// PCI to Internal/LPC Bus Bridge configuration header register offset
+#define IT_P2I_BCR 0x4C
+#define IT_P2I_D0IOSC 0x50
+#define IT_P2I_D1IOSC 0x54
+#define IT_P2I_D2IOSC 0x58
+#define IT_P2I_D3IOSC 0x5C
+#define IT_P2I_D4IOSC 0x60
+#define IT_P2I_D5IOSC 0x64
+#define IT_P2I_D6IOSC 0x68
+#define IT_P2I_D7IOSC 0x6C
+#define IT_P2I_D8IOSC 0x70
+#define IT_P2I_D9IOSC 0x74
+#define IT_P2I_D10IOSC 0x78
+#define IT_P2I_D11IOSC 0x7C
+
+// Memory controller register offsets from IT8172_BASE
+#define IT_MC_SDRMR 0x1000
+#define IT_MC_SDRTR 0x1004
+#define IT_MC_MCR 0x1008
+#define IT_MC_SDTYPE 0x100C
+#define IT_MC_WPBA 0x1010
+#define IT_MC_WPTA 0x1014
+#define IT_MC_HATR 0x1018
+#define IT_MC_PCICR 0x101C
+
+// Flash/ROM control register offsets from IT8172_BASE
+#define IT_FC_BRCR 0x2000
+#define IT_FC_FCR 0x2004
+#define IT_FC_DCR 0x2008
+
+// M68K interface bridge configuration header register offset
+#define IT_M68K_MBCSR 0x54
+#define IT_M68K_TMR 0x58
+#define IT_M68K_BCR 0x5C
+#define IT_M68K_BSR 0x5D
+#define IT_M68K_DTR 0x5F
+
+// Register offset from IT8172_PCI_IO_BASE
+// These registers are accessible through 8172 PCI IO window.
+
+// INTC
+#define IT_INTC_BASE 0x10000
+#define IT_INTC_LBDNIRR 0x10000
+#define IT_INTC_LBDNIMR 0x10002
+#define IT_INTC_LBDNITR 0x10004
+#define IT_INTC_LBDNIAR 0x10006
+#define IT_INTC_LPCNIRR 0x10010
+#define IT_INTC_LPCNIMR 0x10012
+#define IT_INTC_LPCNITR 0x10014
+#define IT_INTC_LPCNIAR 0x10016
+#define IT_INTC_PDNIRR 0x10020
+#define IT_INTC_PDNIMR 0x10022
+#define IT_INTC_PDNITR 0x10024
+#define IT_INTC_PDNIAR 0x10026
+#define IT_INTC_UMNIRR 0x10030
+#define IT_INTC_UMNITR 0x10034
+#define IT_INTC_UMNIAR 0x10036
+#define IT_INTC_TYPER 0x107FE
+
+// IT8172 PCI device number
+#define IT_C2P_DEVICE 0
+#define IT_AUDIO_DEVICE 1
+#define IT_DMAC_DEVICE 1
+#define IT_CDMAC_DEVICE 1
+#define IT_USB_DEVICE 1
+#define IT_P2I_DEVICE 1
+#define IT_IDE_DEVICE 1
+#define IT_M68K_DEVICE 1
+
+// IT8172 PCI function number
+#define IT_C2P_FUNCION 0
+#define IT_AUDIO_FUNCTION 0
+#define IT_DMAC_FUNCTION 1
+#define IT_CDMAC_FUNCTION 2
+#define IT_USB_FUNCTION 3
+#define IT_P2I_FUNCTION 4
+#define IT_IDE_FUNCTION 5
+#define IT_M68K_FUNCTION 6
+
+// IT8172 GPIO
+#define IT_GPADR 0x13800
+#define IT_GPBDR 0x13808
+#define IT_GPCDR 0x13810
+#define IT_GPACR 0x13802
+#define IT_GPBCR 0x1380A
+#define IT_GPCCR 0x13812
+#define IT_GPAICR 0x13804
+#define IT_GPBICR 0x1380C
+#define IT_GPCICR 0x13814
+#define IT_GPAISR 0x13806
+#define IT_GPBISR 0x1380E
+#define IT_GPCISR 0x13816
+#define IT_GCR 0x13818
+
+// IT8172 RTC
+#define IT_RTC_BASE 0x14800
+#define IT_RTC_RIR0 0x00
+#define IT_RTC_RTR0 0x01
+#define IT_RTC_RIR1 0x02
+#define IT_RTC_RTR1 0x03
+#define IT_RTC_RIR2 0x04
+#define IT_RTC_RTR2 0x05
+#define IT_RTC_RCTR 0x08
+#define IT_RTC_RA 0x0A
+#define IT_RTC_RB 0x0B
+#define IT_RTC_RC 0x0C
+#define IT_RTC_RD 0x0D
+
+#define RTC_SEC_INDEX 0x00
+#define RTC_MIN_INDEX 0x02
+#define RTC_HOUR_INDEX 0x04
+#define RTC_DAY_INDEX 0x06
+#define RTC_DATE_INDEX 0x07
+#define RTC_MONTH_INDEX 0x08
+#define RTC_YEAR_INDEX 0x09
+
+// IT8172 internal device registers
+#define IT_TIMER_BASE 0x10800
+#define IT_CIR0_BASE 0x11000
+#define IT_UART_BASE 0x11800
+#define IT_SCR0_BASE 0x12000
+#define IT_SCR1_BASE 0x12800
+#define IT_PP_BASE 0x13000
+#define IT_I2C_BASE 0x14000
+#define IT_CIR1_BASE 0x15000
+
+// IT8172 Smart Card Reader offsets from IT_SCR*_BASE
+#define IT_SCR_SFR 0x08
+#define IT_SCR_SCDR 0x09
+
+// IT8172 IT_SCR_SFR bit definition & mask
+#define IT_SCR_SFR_GATE_UART 0x40
+#define IT_SCR_SFR_GATE_UART_BIT 6
+#define IT_SCR_SFR_GATE_UART_OFF 0
+#define IT_SCR_SFR_GATE_UART_ON 1
+#define IT_SCR_SFR_FET_CHARGE 0x30
+#define IT_SCR_SFR_FET_CHARGE_BIT 4
+#define IT_SCR_SFR_FET_CHARGE_3_3_US 3
+#define IT_SCR_SFR_FET_CHARGE_13_US 2
+#define IT_SCR_SFR_FET_CHARGE_53_US 1
+#define IT_SCR_SFR_FET_CHARGE_213_US 0
+#define IT_SCR_SFR_CARD_FREQ 0x0C
+#define IT_SCR_SFR_CARD_FREQ_BIT 2
+#define IT_SCR_SFR_CARD_FREQ_STOP 3
+#define IT_SCR_SFR_CARD_FREQ_3_5_MHZ 0
+#define IT_SCR_SFR_CARD_FREQ_7_1_MHZ 2
+#define IT_SCR_SFR_CARD_FREQ_96_DIV_MHZ 1
+#define IT_SCR_SFR_FET_ACTIVE 0x02
+#define IT_SCR_SFR_FET_ACTIVE_BIT 1
+#define IT_SCR_SFR_FET_ACTIVE_INVERT 0
+#define IT_SCR_SFR_FET_ACTIVE_NONINVERT 1
+#define IT_SCR_SFR_ENABLE 0x01
+#define IT_SCR_SFR_ENABLE_BIT 0
+#define IT_SCR_SFR_ENABLE_OFF 0
+#define IT_SCR_SFR_ENABLE_ON 1
+
+// IT8172 IT_SCR_SCDR bit definition & mask
+#define IT_SCR_SCDR_RESET_MODE 0x80
+#define IT_SCR_SCDR_RESET_MODE_BIT 7
+#define IT_SCR_SCDR_RESET_MODE_ASYNC 0
+#define IT_SCR_SCDR_RESET_MODE_SYNC 1
+#define IT_SCR_SCDR_DIVISOR 0x7F
+#define IT_SCR_SCDR_DIVISOR_BIT 0
+#define IT_SCR_SCDR_DIVISOR_STOP_VAL_1 0x00
+#define IT_SCR_SCDR_DIVISOR_STOP_VAL_2 0x01
+#define IT_SCR_SCDR_DIVISOR_STOP_VAL_3 0x7F
+
+// IT8172 DMA
+#define IT_DMAC_BASE 0x16000
+#define IT_DMAC_BCAR0 0x00
+#define IT_DMAC_BCAR1 0x04
+#define IT_DMAC_BCAR2 0x08
+#define IT_DMAC_BCAR3 0x0C
+#define IT_DMAC_BCCR0 0x02
+#define IT_DMAC_BCCR1 0x06
+#define IT_DMAC_BCCR2 0x0a
+#define IT_DMAC_BCCR3 0x0e
+#define IT_DMAC_CR 0x10
+#define IT_DMAC_SR 0x12
+#define IT_DMAC_ESR 0x13
+#define IT_DMAC_RQR 0x14
+#define IT_DMAC_MR 0x16
+#define IT_DMAC_EMR 0x17
+#define IT_DMAC_MKR 0x18
+#define IT_DMAC_PAR0 0x20
+#define IT_DMAC_PAR1 0x22
+#define IT_DMAC_PAR2 0x24
+#define IT_DMAC_PAR3 0x26
+
+// IT8172 IDE
+#define IT_IDE_BASE 0x17800
+#define IT_IDE_STATUS 0x1F7
+
+// IT8172 Audio Controller
+#define IT_AC_BASE 0x17000
+#define IT_AC_PCMOV 0x00
+#define IT_AC_FMOV 0x02
+#define IT_AC_I2SV 0x04
+#define IT_AC_DRSS 0x06
+#define IT_AC_PCC 0x08
+#define IT_AC_PCDL 0x0A
+#define IT_AC_PCB1STA 0x0C
+#define IT_AC_PCB2STA 0x10
+#define IT_AC_CAPCC 0x14
+#define IT_AC_CAPCDL 0x16
+#define IT_AC_CAPB1STA 0x18
+#define IT_AC_CAPB2STA 0x1C
+#define IT_AC_CODECC 0x22
+#define IT_AC_I2SMC 0x24
+#define IT_AC_VS 0x26
+#define IT_AC_SRCS 0x28
+#define IT_AC_CIRCP 0x2A
+#define IT_AC_CIRDP 0x2C
+#define IT_AC_TM 0x4A
+#define IT_AC_PFDP 0x4C
+#define IT_AC_GC 0x54
+#define IT_AC_IMC 0x56
+#define IT_AC_ISC 0x5B
+#define IT_AC_OPL3SR 0x68
+#define IT_AC_OPL3DWDR 0x69
+#define IT_AC_OPL3AB1W 0x6A
+#define IT_AC_OPL3DW 0x6B
+#define IT_AC_BPDC 0x70
+
+// Audio : IT_AC_PCC bit definition & mask
+#define PCC_SM 0x8000
+#define PCC_SM_BIT 15
+#define PCC_SM_STEREO 1
+#define PCC_SM_MONO 0
+
+#define PCC_DF 0x4000
+#define PCC_DF_BIT 14
+#define PCC_DF_8 0
+#define PCC_DF_16 1
+
+#define PCC_CF 0x3000
+#define PCC_CF_BIT 12
+#define PCC_CF_2 0
+#define PCC_CF_4 1
+#define PCC_CF_6 2
+
+#define PCC_SR 0x0F00
+#define PCC_SR_BIT 8
+#define PCC_SR_5500 0
+#define PCC_SR_8000 1
+#define PCC_SR_9600 2
+#define PCC_SR_11025 3
+#define PCC_SR_16000 4
+#define PCC_SR_19200 5
+#define PCC_SR_22050 6
+#define PCC_SR_32000 7
+#define PCC_SR_38400 8
+#define PCC_SR_44100 9
+#define PCC_SR_48000 10
+
+#define PCC_CSP 0x0080
+#define PCC_CSP_BIT 7
+#define PCC_CSP_STOP 0
+#define PCC_CSP_STOP_NOW 1
+
+#define PCC_CP 0x0040
+#define PCC_CP_BIT 6
+#define PCC_CP_NORMAL 0
+#define PCC_CP_PAUSE 1
+
+#define PCC_CA 0x0020
+#define PCC_CA_BIT 5
+#define PCC_CA_NO_START 0
+#define PCC_CA_START 1
+
+#define PCC_CB2L 0x0004
+#define PCC_CB2L_BIT 2
+#define PCC_CB2L_NO 0
+#define PCC_CB2L_YES 1
+
+#define PCC_CB1L 0x0002
+#define PCC_CB1L_BIT 1
+#define PCC_CB1L_NO 0
+#define PCC_CB1L_YES 1
+
+#define PCC_DE 0x0001
+#define PCC_DE_BIT 0
+#define PCC_DE_NOT_EMPTY 0
+#define PCC_DE_EMPTY 1
+
+// IT8172 Timer
+#define IT_TIMER_BASE 0x10800
+#define TIMER_TCVR0 0x00
+#define TIMER_TRVR0 0x02
+#define TIMER_TCR0 0x04
+#define TIMER_TIRR 0x06
+#define TIMER_TCVR1 0x08
+#define TIMER_TRVR1 0x0A
+#define TIMER_TCR1 0x0C
+#define TIMER_TIDR 0x0E
+
+
+#define IT_WRITE(ofs, data) *(volatile u32 *)KSEG1ADDR((IT8172_BASE+ofs)) = data
+#define IT_READ(ofs, data) data = *(volatile u32 *)KSEG1ADDR((IT8172_BASE+ofs))
+
+#define IT_IO_WRITE(ofs, data) *(volatile u32 *)KSEG1ADDR((IT8172_PCI_IO_BASE+ofs)) = data
+#define IT_IO_READ(ofs, data) data = *(volatile u32 *)KSEG1ADDR((IT8172_PCI_IO_BASE+ofs))
+
+#define IT_IO_WRITE16(ofs, data) *(volatile u16 *)KSEG1ADDR((IT8172_PCI_IO_BASE+ofs)) = data
+#define IT_IO_READ16(ofs, data) data = *(volatile u16 *)KSEG1ADDR((IT8172_PCI_IO_BASE+ofs))
+
+#endif
--- /dev/null
+/*
+ *
+ * BRIEF MODULE DESCRIPTION
+ * IT8172 Consumer IR port defines.
+ *
+ * Copyright 2001 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ * ppopov@mvista.com or support@mvista.com
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#define NUM_CIR_PORTS 2
+
+/* Master Control Register */
+#define CIR_RESET 0x1
+#define CIR_FIFO_CLEAR 0x2
+#define CIR_SET_FIFO_TL(x) (((x)&0x3)<<2)
+#define CIR_ILE 0x10
+#define CIR_ILSEL 0x20
+
+/* Interrupt Enable Register */
+#define CIR_TLDLIE 0x1
+#define CIR_RDAIE 0x2
+#define CIR_RFOIE 0x4
+#define CIR_IEC 0x80
+
+/* Interrupt Identification Register */
+#define CIR_TLDLI 0x1
+#define CIR_RDAI 0x2
+#define CIR_RFOI 0x4
+#define CIR_NIP 0x80
+
+/* Carrier Frequency Register */
+#define CIR_SET_CF(x) ((x)&0x1f)
+ #define CFQ_38_480 0xB /* 38 KHz low, 480 KHz high */
+#define CIR_HCFS 0x20
+ #define CIR_SET_HS(x) (((x)&0x1)<<5)
+
+
+/* Receiver Control Register */
+#define CIR_SET_RXDCR(x) ((x)&0x7)
+#define CIR_RXACT 0x8
+#define CIR_RXEND 0x10
+#define CIR_RDWOS 0x20
+ #define CIR_SET_RDWOS(x) (((x)&0x1)<<5)
+#define CIR_RXEN 0x80
+
+/* Transmitter Control Register */
+#define CIR_SET_TXMPW(x) ((x)&0x7)
+#define CIR_SET_TXMPM(x) (((x)&0x3)<<3)
+#define CIR_TXENDF 0x20
+#define CIR_TXRLE 0x40
+
+/* Receiver FIFO Status Register */
+#define CIR_RXFBC_MASK 0x3f
+#define CIR_RXFTO 0x80
+
+/* Wakeup Code Length Register */
+#define CIR_SET_WCL ((x)&0x3f)
+#define CIR_WCL_MASK(x) ((x)&0x3f)
+
+/* Wakeup Power Control/Status Register */
+#define CIR_BTMON 0x2
+#define CIR_CIRON 0x4
+#define CIR_RCRST 0x10
+#define CIR_WCRST 0x20
+
+struct cir_port {
+ int port;
+ unsigned short baud_rate;
+ unsigned char fifo_tl;
+ unsigned char cfq;
+ unsigned char hcfs;
+ unsigned char rdwos;
+ unsigned char rxdcr;
+};
+
+struct it8172_cir_regs {
+ unsigned char dr; /* data */
+ char pad;
+ unsigned char mstcr; /* master control */
+ char pad1;
+ unsigned char ier; /* interrupt enable */
+ char pad2;
+ unsigned char iir; /* interrupt identification */
+ char pad3;
+ unsigned char cfr; /* carrier frequency */
+ char pad4;
+ unsigned char rcr; /* receiver control */
+ char pad5;
+ unsigned char tcr; /* transmitter control */
+ char pad6;
+ char pad7;
+ char pad8;
+ unsigned char bdlr; /* baud rate divisor low byte */
+ char pad9;
+ unsigned char bdhr; /* baud rate divisor high byte */
+ char pad10;
+ unsigned char tfsr; /* tx fifo byte count */
+ char pad11;
+ unsigned char rfsr; /* rx fifo status */
+ char pad12;
+ unsigned char wcl; /* wakeup code length */
+ char pad13;
+ unsigned char wcr; /* wakeup code read/write */
+ char pad14;
+ unsigned char wps; /* wakeup power control/status */
+};
+
+int cir_port_init(struct cir_port *cir);
+extern void clear_fifo(struct cir_port *cir);
+extern void enable_receiver(struct cir_port *cir);
+extern void disable_receiver(struct cir_port *cir);
+extern void enable_rx_demodulation(struct cir_port *cir);
+extern void disable_rx_demodulation(struct cir_port *cir);
+extern void set_rx_active(struct cir_port *cir);
+extern void int_enable(struct cir_port *cir);
+extern void rx_int_enable(struct cir_port *cir);
+extern char get_int_status(struct cir_port *cir);
+extern int cir_get_rx_count(struct cir_port *cir);
+extern char cir_read_data(struct cir_port *cir);
--- /dev/null
+/*
+ *
+ * BRIEF MODULE DESCRIPTION
+ * Function prototypes for low level uart routines to
+ * directly access a 16550 uart.
+ *
+ * Copyright 2000 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ * ppopov@mvista.com or support@mvista.com
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/types.h>
+
+extern void putch(const unsigned char c);
+extern void puts(unsigned char *cp);
+extern void fputs(unsigned char *cp);
+extern void put64(uint64_t ul);
+extern void put32(unsigned u);
--- /dev/null
+/*
+ *
+ * BRIEF MODULE DESCRIPTION
+ * ITE 8172 Interrupt Numbering
+ *
+ * Copyright 2000 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ * ppopov@mvista.com or support@mvista.com
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _MIPS_ITEINT_H
+#define _MIPS_ITEINT_H
+
+/*
+ * Here's the "strategy":
+ * We number the LPC serial irqs from 0 to 15,
+ * the local bus irqs from 16 to 31,
+ * the pci dev register interrupts from 32 to 47,
+ * and the non-maskable ints from 48 to 53.
+ */
+
+#define IT8172_LPC_IRQ_BASE 0 /* first LPC int number */
+#define IT8172_SERIRQ_0 (IT8172_LPC_IRQ_BASE + 0)
+#define IT8172_SERIRQ_1 (IT8172_LPC_IRQ_BASE + 1)
+#define IT8172_SERIRQ_2 (IT8172_LPC_IRQ_BASE + 2)
+#define IT8172_SERIRQ_3 (IT8172_LPC_IRQ_BASE + 3)
+#define IT8172_SERIRQ_4 (IT8172_LPC_IRQ_BASE + 4)
+#define IT8172_SERIRQ_5 (IT8172_LPC_IRQ_BASE + 5)
+#define IT8172_SERIRQ_6 (IT8172_LPC_IRQ_BASE + 6)
+#define IT8172_SERIRQ_7 (IT8172_LPC_IRQ_BASE + 7)
+#define IT8172_SERIRQ_8 (IT8172_LPC_IRQ_BASE + 8)
+#define IT8172_SERIRQ_9 (IT8172_LPC_IRQ_BASE + 9)
+#define IT8172_SERIRQ_10 (IT8172_LPC_IRQ_BASE + 10)
+#define IT8172_SERIRQ_11 (IT8172_LPC_IRQ_BASE + 11)
+#define IT8172_SERIRQ_12 (IT8172_LPC_IRQ_BASE + 12)
+#define IT8172_SERIRQ_13 (IT8172_LPC_IRQ_BASE + 13)
+#define IT8172_SERIRQ_14 (IT8172_LPC_IRQ_BASE + 14)
+#define IT8172_SERIRQ_15 (IT8172_LPC_IRQ_BASE + 15)
+
+#define IT8172_LB_IRQ_BASE 16 /* first local bus int number */
+#define IT8172_PPR_IRQ (IT8172_LB_IRQ_BASE + 0) /* parallel port */
+#define IT8172_TIMER0_IRQ (IT8172_LB_IRQ_BASE + 1)
+#define IT8172_TIMER1_IRQ (IT8172_LB_IRQ_BASE + 2)
+#define IT8172_I2C_IRQ (IT8172_LB_IRQ_BASE + 3)
+#define IT8172_GPIO_IRQ (IT8172_LB_IRQ_BASE + 4)
+#define IT8172_CIR0_IRQ (IT8172_LB_IRQ_BASE + 5)
+#define IT8172_CIR1_IRQ (IT8172_LB_IRQ_BASE + 6)
+#define IT8172_UART_IRQ (IT8172_LB_IRQ_BASE + 7)
+#define IT8172_SCR0_IRQ (IT8172_LB_IRQ_BASE + 8)
+#define IT8172_SCR1_IRQ (IT8172_LB_IRQ_BASE + 9)
+#define IT8172_RTC_IRQ (IT8172_LB_IRQ_BASE + 10)
+#define IT8172_IOCHK_IRQ (IT8172_LB_IRQ_BASE + 11)
+/* 12 - 15 reserved */
+
+/*
+ * Note here that the pci dev registers includes bits for more than
+ * just the pci devices.
+ */
+#define IT8172_PCI_DEV_IRQ_BASE 32 /* first pci dev irq */
+#define IT8172_AC97_IRQ (IT8172_PCI_DEV_IRQ_BASE + 0)
+#define IT8172_MC68K_IRQ (IT8172_PCI_DEV_IRQ_BASE + 1)
+#define IT8172_IDE_IRQ (IT8172_PCI_DEV_IRQ_BASE + 2)
+#define IT8172_USB_IRQ (IT8172_PCI_DEV_IRQ_BASE + 3)
+#define IT8172_BRIDGE_MASTER_IRQ (IT8172_PCI_DEV_IRQ_BASE + 4)
+#define IT8172_BRIDGE_TARGET_IRQ (IT8172_PCI_DEV_IRQ_BASE + 5)
+#define IT8172_PCI_INTA_IRQ (IT8172_PCI_DEV_IRQ_BASE + 6)
+#define IT8172_PCI_INTB_IRQ (IT8172_PCI_DEV_IRQ_BASE + 7)
+#define IT8172_PCI_INTC_IRQ (IT8172_PCI_DEV_IRQ_BASE + 8)
+#define IT8172_PCI_INTD_IRQ (IT8172_PCI_DEV_IRQ_BASE + 9)
+#define IT8172_S_INTA_IRQ (IT8172_PCI_DEV_IRQ_BASE + 10)
+#define IT8172_S_INTB_IRQ (IT8172_PCI_DEV_IRQ_BASE + 11)
+#define IT8172_S_INTC_IRQ (IT8172_PCI_DEV_IRQ_BASE + 12)
+#define IT8172_S_INTD_IRQ (IT8172_PCI_DEV_IRQ_BASE + 13)
+#define IT8172_CDMA_IRQ (IT8172_PCI_DEV_IRQ_BASE + 14)
+#define IT8172_DMA_IRQ (IT8172_PCI_DEV_IRQ_BASE + 15)
+
+#define IT8172_NMI_IRQ_BASE 48
+#define IT8172_SER_NMI_IRQ (IT8172_NMI_IRQ_BASE + 0)
+#define IT8172_PCI_NMI_IRQ (IT8172_NMI_IRQ_BASE + 1)
+#define IT8172_RTC_NMI_IRQ (IT8172_NMI_IRQ_BASE + 2)
+#define IT8172_CPUIF_NMI_IRQ (IT8172_NMI_IRQ_BASE + 3)
+#define IT8172_PMER_NMI_IRQ (IT8172_NMI_IRQ_BASE + 4)
+#define IT8172_POWER_NMI_IRQ (IT8172_NMI_IRQ_BASE + 5)
+
+/* Finally, let's move over here the mips cpu timer interrupt.
+ * This is more or less strictly for statistics.
+ */
+#define MIPS_CPU_TIMER_IRQ (IT8172_NMI_IRQ_BASE + 6)
+
+#define IT8172_INT_END MIPS_CPU_TIMER_IRQ
+
+/*
+ * IT8172 Interrupt Controller Registers
+ */
+struct it8172_intc_regs {
+ volatile unsigned short lb_req; /* offset 0 */
+ volatile unsigned short lb_mask;
+ volatile unsigned short lb_trigger;
+ volatile unsigned short lb_level;
+ unsigned char pad0[8];
+
+ volatile unsigned short lpc_req; /* offset 0x10 */
+ volatile unsigned short lpc_mask;
+ volatile unsigned short lpc_trigger;
+ volatile unsigned short lpc_level;
+ unsigned char pad1[8];
+
+ volatile unsigned short pci_req; /* offset 0x20 */
+ volatile unsigned short pci_mask;
+ volatile unsigned short pci_trigger;
+ volatile unsigned short pci_level;
+ unsigned char pad2[8];
+
+ volatile unsigned short nmi_req; /* offset 0x30 */
+ volatile unsigned short nmi_mask;
+ volatile unsigned short nmi_trigger;
+ volatile unsigned short nmi_level;
+ unsigned char pad3[6];
+
+ volatile unsigned short nmi_redir; /* offset 0x3E */
+ unsigned char pad4[0xBE];
+
+ volatile unsigned short intstatus; /* offset 0xFE */
+};
+
+#endif /* _MIPS_ITEINT_H */
--- /dev/null
+/*
+ *
+ * BRIEF MODULE DESCRIPTION
+ * IT8172 system controller defines.
+ *
+ * Copyright 2000 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ * ppopov@mvista.com or support@mvista.com
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
--- /dev/null
+/*
+ *
+ * BRIEF MODULE DESCRIPTION
+ * IT8172 system controller specific pci defines.
+ *
+ * Copyright 2000 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ * ppopov@mvista.com or support@mvista.com
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _8172PCI_H_
+#define _8172PCI_H_
+
+// PCI configuration space Type0
+#define PCI_IDREG 0x00
+#define PCI_CMDSTSREG 0x04
+#define PCI_CLASSREG 0x08
+#define PCI_BHLCREG 0x0C
+#define PCI_BASE1REG 0x10
+#define PCI_BASE2REG 0x14
+#define PCI_BASE3REG 0x18
+#define PCI_BASE4REG 0x1C
+#define PCI_BASE5REG 0x20
+#define PCI_BASE6REG 0x24
+#define PCI_ROMBASEREG 0x30
+#define PCI_INTRREG 0x3C
+
+// PCI configuration space Type1
+#define PCI_BUSNOREG 0x18
+
+#define IT_PCI_VENDORID(x) ((x) & 0xFFFF)
+#define IT_PCI_DEVICEID(x) (((x)>>16) & 0xFFFF)
+
+// Command register
+#define PCI_CMD_IOEN 0x00000001
+#define PCI_CMD_MEMEN 0x00000002
+#define PCI_CMD_BUSMASTER 0x00000004
+#define PCI_CMD_SPCYCLE 0x00000008
+#define PCI_CMD_WRINV 0x00000010
+#define PCI_CMD_VGASNOOP 0x00000020
+#define PCI_CMD_PERR 0x00000040
+#define PCI_CMD_WAITCTRL 0x00000080
+#define PCI_CMD_SERR 0x00000100
+#define PCI_CMD_FAST_BACKTOBACK 0x00000200
+
+// Status register
+#define PCI_STS_66MHZ 0x00200000
+#define PCI_STS_SUPPORT_UDF 0x00400000
+#define PCI_STS_FAST_BACKTOBACK 0x00800000
+#define PCI_STS_DATA_PERR 0x01000000
+#define PCI_STS_DEVSEL0 0x02000000
+#define PCI_STS_DEVSEL1 0x04000000
+#define PCI_STS_SIG_TGTABORT 0x08000000
+#define PCI_STS_RCV_TGTABORT 0x10000000
+#define PCI_STS_RCV_MSTABORT 0x20000000
+#define PCI_STS_SYSERR 0x40000000
+#define PCI_STS_DETCT_PERR 0x80000000
+
+#define IT_PCI_CLASS(x) (((x)>>24) & 0xFF)
+#define IT_PCI_SUBCLASS(x) (((x)>>16) & 0xFF)
+#define IT_PCI_INTERFACE(x) (((x)>>8) & 0xFF)
+#define IT_PCI_REVISION(x) ((x) & 0xFF)
+
+// PCI class code
+#define PCI_CLASS_BRIDGE 0x06
+
+// bridge subclass
+#define PCI_SUBCLASS_BRIDGE_HOST 0x00
+#define PCI_SUBCLASS_BRIDGE_PCI 0x04
+
+// BHLCREG
+#define IT_PCI_BIST(x) (((x)>>24) & 0xFF)
+#define IT_PCI_HEADERTYPE(x) (((x)>>16) & 0xFF)
+#define IT_PCI_LATENCYTIMER(x) (((x)>>8) & 0xFF)
+#define IT_PCI_CACHELINESIZE(x) ((x) & 0xFF)
+
+#define PCI_MULTIFUNC 0x80
+
+// INTRREG
+#define IT_PCI_MAXLAT(x) (((x)>>24) & 0xFF)
+#define IT_PCI_MINGNT(x) (((x)>>16) & 0xFF)
+#define IT_PCI_INTRPIN(x) (((x)>>8) & 0xFF)
+#define IT_PCI_INTRLINE(x) ((x) & 0xFF)
+
+#define PCI_VENDOR_NEC 0x1033
+#define PCI_VENDOR_DEC 0x1101
+
+#endif // _8172PCI_H_
--- /dev/null
+
+#ifndef __IT8712_H__
+#define __IT8712_H__
+
+#define LPC_BASE_ADDR 0x14000000
+
+// MB PnP configuration register
+#define LPC_KEY_ADDR 0x1400002E
+#define LPC_DATA_ADDR 0x1400002F
+
+// Device LDN
+#define LDN_SERIAL1 0x01
+#define LDN_SERIAL2 0x02
+#define LDN_PARALLEL 0x03
+#define LDN_KEYBOARD 0x05
+#define LDN_MOUSE 0x06
+
+#define IT8712_UART1_PORT 0x3F8
+#define IT8712_UART2_PORT 0x2F8
+
+#ifndef ASM_ONLY
+
+void LPCSetConfig(char LdnNumber, char Index, char data);
+char LPCGetConfig(char LdnNumber, char Index);
+
+#endif
+
+#endif
void (*kbd_request_region)(void);
int (*kbd_request_irq)(void (*handler)(int, void *, struct pt_regs *));
- /* PSaux driver resource managment */
+ /* PSaux driver resource management */
int (*aux_request_irq)(void (*handler)(int, void *, struct pt_regs *));
void (*aux_free_irq)(void);
/*
* Bitfields and bit numbers in the coprocessor 0 cause register.
*
- * Refer to to your MIPS R4xx0 manual, chapter 5 for explanation.
+ * Refer to your MIPS R4xx0 manual, chapter 5 for explanation.
*/
#define CAUSEB_EXCCODE 2
#define CAUSEF_EXCCODE (31 << 2)
#include <linux/string.h>
#include <asm/io.h>
-#ifdef CONFIG_DDB5074
+#if (defined(CONFIG_DDB5074) || defined(CONFIG_DDB5476))
#undef PCIBIOS_MIN_IO
#undef PCIBIOS_MIN_MEM
#define PCIBIOS_MIN_IO 0x0100000
#define NUM_FPU_REGS 32
struct mips_fpu_hard_struct {
- unsigned int fp_regs[NUM_FPU_REGS];
+ double fp_regs[NUM_FPU_REGS];
unsigned int control;
-} __attribute__((aligned(8)));
+};
/*
- * FIXME: no fpu emulator yet (but who cares anyway?)
+ * It would be nice to add some more fields for emulator statistics, but there
+ * are a number of fixed offsets in offset.h and elsewhere that would have to
+ * be recalculated by hand. So the additional information will be private to
+ * the FPU emulator for now. See asm-mips/fpu_emulator.h.
*/
+typedef u64 fpureg_t;
struct mips_fpu_soft_struct {
- long dummy;
+ fpureg_t regs[NUM_FPU_REGS];
+ unsigned int sr;
};
union mips_fpu_union {
mm_segment_t current_ds;
unsigned long irix_trampoline; /* Wheee... */
unsigned long irix_oldctx;
+
+ /*
+ * These are really only needed if the full FPU emulator is configured.
+ * Would be made conditional on MIPS_FPU_EMULATOR if it weren't for the
+ * fact that having offset.h rebuilt differently for different config
+ * options would be asking for trouble.
+ *
+ * Saved EPC during delay-slot emulation (see math-emu/cp1emu.c)
+ */
+ unsigned long dsemul_epc;
+
+ /*
+ * Pointer to instruction used to induce address error
+ */
+ unsigned long dsemul_aerpc;
};
#endif /* !defined (_LANGUAGE_ASSEMBLY) */
/* \
* For now the default is to fix address errors \
*/ \
- MF_FIXADE, { 0 }, 0, 0 \
+ MF_FIXADE, { 0 }, 0, 0, \
+ /* \
+ * dsemul_epc and dsemul_aerpc should never be used uninitialized, \
+ * but... \
+ */ \
+ 0 ,0 \
}
#ifdef __KERNEL__
#include <linux/spinlock.h>
#include <linux/wait.h>
#include <linux/config.h>
+#include <linux/rwsem.h>
struct semaphore {
#ifdef __MIPSEB__
atomic_t count;
/* bit 0 means read bias granted;
bit 1 means write bias granted. */
- unsigned granted;
+ unsigned long granted; /* pedant: long req'd for set_bit */
wait_queue_head_t wait;
wait_queue_head_t write_bias_wait;
#if WAITQUEUE_DEBUG
u32 _unused7;
volatile u32 dmamode; /* DMA mode config bit settings */
u32 _unused8;
- volatile u32 dmacount; /* Zoom and byte count for DMA */
+ volatile u32 dmaccount; /* Zoom and byte count for DMA */
u32 _unused9;
volatile u32 dmastart; /* Pedal to the metal. */
u32 _unused10;
/* get time since last event */
#define QIOCGETITIME _IOR('Q', 11, time_t)
-/* set curent screen */
+/* set current screen */
#define QIOCSETSCRN _IOW('Q',6,int)
*/
#define ENOMEDIUM 159 /* No medium found */
#define EMEDIUMTYPE 160 /* Wrong medium type */
-#define EHASHCOLLISION 125 /* Number of hash collisons exceeds maximum generation counter value. */
#define EDQUOT 1133 /* Quota exceeded */
void (*kbd_request_region)(void);
int (*kbd_request_irq)(void (*handler)(int, void *, struct pt_regs *));
- /* PSaux driver resource managment */
+ /* PSaux driver resource management */
int (*aux_request_irq)(void (*handler)(int, void *, struct pt_regs *));
void (*aux_free_irq)(void);
/*
* Bitfields and bit numbers in the coprocessor 0 cause register.
*
- * Refer to to your MIPS R4xx0 manual, chapter 5 for explanation.
+ * Refer to your MIPS R4xx0 manual, chapter 5 for explanation.
*/
#define CAUSEB_EXCCODE 2
#define CAUSEF_EXCCODE (31 << 2)
/*
* Given a kaddr, ADDR_TO_MAPBASE finds the owning node of the memory
- * and returns the the mem_map of that node.
+ * and returns the mem_map of that node.
*/
#define ADDR_TO_MAPBASE(kaddr) \
NODE_MEM_MAP(KVADDR_TO_NID((unsigned long)(kaddr)))
ds:2, /* Data size */
gbr:1, /* GBR enable */
vbpm:1, /* VBPM message */
- error:1, /* Error occured */
+ error:1, /* Error occurred */
barr:1, /* Barrier op */
rsvd:8;
} berr_st;
#include <asm/atomic.h>
#include <linux/spinlock.h>
#include <linux/wait.h>
+#include <linux/rwsem.h>
struct semaphore {
#ifdef __MIPSEB__
__up(sem);
}
-/*
- * rw mutexes (should that be mutices? =) -- throw rw spinlocks and
- * semaphores together, and this is what we end up with...
- *
- * The lock is initialized to BIAS. This way, a writer subtracts BIAS ands
- * gets 0 for the case of an uncontended lock. Readers decrement by 1 and
- * see a positive value when uncontended, negative if there are writers
- * waiting (in which case it goes to sleep).
- *
- * The value 0x01000000 supports up to 128 processors and lots of processes.
- * BIAS must be chosen such that subtracting BIAS once per CPU will result
- * in the int remaining negative. In terms of fairness, this should result
- * in the lock flopping back and forth between readers and writers under
- * heavy use.
- *
- * Once we start supporting machines with more than 128 CPUs, we should go
- * for using a 64bit atomic type instead of 32bit as counter. We shall
- * probably go for bias 0x80000000 then, so that single sethi can set it.
- * */
-
-#define RW_LOCK_BIAS 0x01000000
-
-struct rw_semaphore {
- atomic_t count;
- /* bit 0 means read bias granted;
- bit 1 means write bias granted. */
- unsigned long granted;
- wait_queue_head_t wait;
- wait_queue_head_t write_bias_wait;
-#if WAITQUEUE_DEBUG
- long __magic;
- atomic_t readers;
- atomic_t writers;
-#endif
-};
-
-#if WAITQUEUE_DEBUG
-#define __RWSEM_DEBUG_INIT , ATOMIC_INIT(0), ATOMIC_INIT(0)
-#else
-#define __RWSEM_DEBUG_INIT /* */
-#endif
-
-#define __RWSEM_INITIALIZER(name,count) \
- { ATOMIC_INIT(count), 0, \
- __WAIT_QUEUE_HEAD_INITIALIZER((name).wait), \
- __WAIT_QUEUE_HEAD_INITIALIZER((name).write_bias_wait) \
- __SEM_DEBUG_INIT(name) __RWSEM_DEBUG_INIT }
-
-#define __DECLARE_RWSEM_GENERIC(name,count) \
- struct rw_semaphore name = __RWSEM_INITIALIZER(name,count)
-
-#define DECLARE_RWSEM(name) \
- __DECLARE_RWSEM_GENERIC(name, RW_LOCK_BIAS)
-#define DECLARE_RWSEM_READ_LOCKED(name) \
- __DECLARE_RWSEM_GENERIC(name, RW_LOCK_BIAS-1)
-#define DECLARE_RWSEM_WRITE_LOCKED(name) \
- __DECLARE_RWSEM_GENERIC(name, 0)
-
-static inline void init_rwsem(struct rw_semaphore *sem)
-{
- atomic_set(&sem->count, RW_LOCK_BIAS);
- sem->granted = 0;
- init_waitqueue_head(&sem->wait);
- init_waitqueue_head(&sem->write_bias_wait);
-#if WAITQUEUE_DEBUG
- sem->__magic = (long)&sem->__magic;
- atomic_set(&sem->readers, 0);
- atomic_set(&sem->writers, 0);
-#endif
-}
-
-/* The expensive part is outlined. */
-extern void __down_read(struct rw_semaphore *sem, int count);
-extern void __down_write(struct rw_semaphore *sem, int count);
-extern void __rwsem_wake(struct rw_semaphore *sem, unsigned long readers);
-
-static inline void down_read(struct rw_semaphore *sem)
-{
- int count;
-
-#if WAITQUEUE_DEBUG
- CHECK_MAGIC(sem->__magic);
-#endif
-
- count = atomic_dec_return(&sem->count);
- if (count < 0) {
- __down_read(sem, count);
- }
- mb();
-
-#if WAITQUEUE_DEBUG
- if (sem->granted & 2)
- BUG();
- if (atomic_read(&sem->writers))
- BUG();
- atomic_inc(&sem->readers);
-#endif
-}
-
-static inline void down_write(struct rw_semaphore *sem)
-{
- int count;
-
-#if WAITQUEUE_DEBUG
- CHECK_MAGIC(sem->__magic);
-#endif
-
- count = atomic_sub_return(RW_LOCK_BIAS, &sem->count);
- if (count) {
- __down_write(sem, count);
- }
- mb();
-
-#if WAITQUEUE_DEBUG
- if (atomic_read(&sem->writers))
- BUG();
- if (atomic_read(&sem->readers))
- BUG();
- if (sem->granted & 3)
- BUG();
- atomic_inc(&sem->writers);
-#endif
-}
-
-/* When a reader does a release, the only significant case is when
- there was a writer waiting, and we've bumped the count to 0: we must
- wake the writer up. */
-
-static inline void up_read(struct rw_semaphore *sem)
-{
- int count;
-
-#if WAITQUEUE_DEBUG
- CHECK_MAGIC(sem->__magic);
- if (sem->granted & 2)
- BUG();
- if (atomic_read(&sem->writers))
- BUG();
- atomic_dec(&sem->readers);
-#endif
-
- mb();
- count = atomic_inc_return(&sem->count);
- if (count == 0) {
- __rwsem_wake(sem, 0);
- }
-}
-
-/*
- * Releasing the writer is easy -- just release it and wake up any sleepers.
- */
-static inline void up_write(struct rw_semaphore *sem)
-{
- int count;
-
-#if WAITQUEUE_DEBUG
- CHECK_MAGIC(sem->__magic);
- if (sem->granted & 3)
- BUG();
- if (atomic_read(&sem->readers))
- BUG();
- if (atomic_read(&sem->writers) != 1)
- BUG();
- atomic_dec(&sem->writers);
-#endif
-
- mb();
- count = atomic_add_return(RW_LOCK_BIAS, &sem->count);
- if (count - RW_LOCK_BIAS < 0 && count >= 0) {
- /* Only do the wake if we're no longer negative. */
- __rwsem_wake(sem, count);
- }
-}
-
#endif /* _ASM_SEMAPHORE_H */
/* get time since last event */
#define QIOCGETITIME _IOR('Q', 11, time_t)
-/* set curent screen */
+/* set current screen */
#define QIOCSETSCRN _IOW('Q',6,int)
*/
#include <linux/spinlock.h>
+#include <linux/rwsem.h>
#include <asm/system.h>
#include <asm/atomic.h>
__up(sem);
}
-/* rw mutexes (should that be mutices? =) -- throw rw
- * spinlocks and semaphores together, and this is what we
- * end up with...
- *
- * The lock is initialized to BIAS. This way, a writer
- * subtracts BIAS ands gets 0 for the case of an uncontended
- * lock. Readers decrement by 1 and see a positive value
- * when uncontended, negative if there are writers waiting
- * (in which case it goes to sleep).
- *
- * The value 0x01000000 supports up to 128 processors and
- * lots of processes. BIAS must be chosen such that subl'ing
- * BIAS once per CPU will result in the long remaining
- * negative.
- *
- * In terms of fairness, this should result in the lock
- * flopping back and forth between readers and writers
- * under heavy use.
- *
- * -ben
- */
-struct rw_semaphore {
- atomic_t count;
- volatile unsigned char write_bias_granted;
- volatile unsigned char read_bias_granted;
- volatile unsigned char pad1;
- volatile unsigned char pad2;
- wait_queue_head_t wait;
- wait_queue_head_t write_bias_wait;
-#if WAITQUEUE_DEBUG
- long __magic;
- atomic_t readers;
- atomic_t writers;
-#endif
-};
-
-#if WAITQUEUE_DEBUG
-#define __RWSEM_DEBUG_INIT , ATOMIC_INIT(0), ATOMIC_INIT(0)
-#else
-#define __RWSEM_DEBUG_INIT /* */
-#endif
-
-#define RW_LOCK_BIAS 0x01000000
-
-#define __RWSEM_INITIALIZER(name,count) \
-{ ATOMIC_INIT(count), 0, 0, 0, 0, __WAIT_QUEUE_HEAD_INITIALIZER((name).wait), \
- __WAIT_QUEUE_HEAD_INITIALIZER((name).write_bias_wait) \
- __SEM_DEBUG_INIT(name) __RWSEM_DEBUG_INIT }
-
-#define __DECLARE_RWSEM_GENERIC(name,count) \
- struct rw_semaphore name = __RWSEM_INITIALIZER(name,count)
-
-#define DECLARE_RWSEM(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS)
-#define DECLARE_RWSEM_READ_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS-1)
-#define DECLARE_RWSEM_WRITE_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,0)
-
-extern inline void init_rwsem(struct rw_semaphore *sem)
-{
- atomic_set(&sem->count, RW_LOCK_BIAS);
- sem->read_bias_granted = 0;
- sem->write_bias_granted = 0;
- init_waitqueue_head(&sem->wait);
- init_waitqueue_head(&sem->write_bias_wait);
-#if WAITQUEUE_DEBUG
- sem->__magic = (long)&sem->__magic;
- atomic_set(&sem->readers, 0);
- atomic_set(&sem->writers, 0);
-#endif
-}
-
-#ifdef FIXME_WILLY_FIXME_FOR_REAL_THIS_TIME
-extern struct rw_semaphore *__build_read_lock(struct rw_semaphore *sem, const char *what);
-extern struct rw_semaphore *__build_write_lock(struct rw_semaphore *sem, const char *what);
-#endif
-
-/* we use FASTCALL convention for the helpers */
-extern struct rw_semaphore *FASTCALL(__down_read_failed(struct rw_semaphore *sem));
-extern struct rw_semaphore *FASTCALL(__down_write_failed(struct rw_semaphore *sem));
-extern struct rw_semaphore *FASTCALL(__rwsem_wake(struct rw_semaphore *sem));
-
-extern inline void down_read(struct rw_semaphore *sem)
-{
-#if WAITQUEUE_DEBUG
- if (sem->__magic != (long)&sem->__magic)
- BUG();
-#endif
-#ifdef FIXME_WILLY_FIXME_FOR_REAL_THIS_TIME
- __build_read_lock(sem, "__down_read_failed");
-#endif
-#if WAITQUEUE_DEBUG
- if (sem->write_bias_granted)
- BUG();
- if (atomic_read(&sem->writers))
- BUG();
- atomic_inc(&sem->readers);
-#endif
-}
-
-extern inline void down_write(struct rw_semaphore *sem)
-{
-#if WAITQUEUE_DEBUG
- if (sem->__magic != (long)&sem->__magic)
- BUG();
-#endif
-#ifdef FIXME_WILLY_FIXME_FOR_REAL_THIS_TIME
- __build_write_lock(sem, "__down_write_failed");
-#endif
-#if WAITQUEUE_DEBUG
- if (atomic_read(&sem->writers))
- BUG();
- if (atomic_read(&sem->readers))
- BUG();
- if (sem->read_bias_granted)
- BUG();
- if (sem->write_bias_granted)
- BUG();
- atomic_inc(&sem->writers);
-#endif
-}
-
-/* When a reader does a release, the only significant
- * case is when there was a writer waiting, and we've
- * bumped the count to 0: we must wake the writer up.
- */
-extern inline void __up_read(struct rw_semaphore *sem)
-{
-}
-
-/* releasing the writer is easy -- just release it and
- * wake up any sleepers.
- */
-extern inline void __up_write(struct rw_semaphore *sem)
-{
-}
-
-extern inline void up_read(struct rw_semaphore *sem)
-{
-#if WAITQUEUE_DEBUG
- if (sem->write_bias_granted)
- BUG();
- if (atomic_read(&sem->writers))
- BUG();
- atomic_dec(&sem->readers);
-#endif
- __up_read(sem);
-}
-
-extern inline void up_write(struct rw_semaphore *sem)
-{
-#if WAITQUEUE_DEBUG
- if (sem->read_bias_granted)
- BUG();
- if (sem->write_bias_granted)
- BUG();
- if (atomic_read(&sem->readers))
- BUG();
- if (atomic_read(&sem->writers) != 1)
- BUG();
- atomic_dec(&sem->writers);
-#endif
- __up_write(sem);
-}
-
#endif /* _ASM_PARISC_SEMAPHORE_H */
#include <asm/atomic.h>
#include <asm/system.h>
#include <linux/wait.h>
+#include <linux/rwsem.h>
struct semaphore {
atomic_t count;
}
-/* RW spinlock-based semaphores */
-
-struct rw_semaphore
-{
- spinlock_t lock;
- int rd, wr;
- wait_queue_head_t wait;
-#if WAITQUEUE_DEBUG
- long __magic;
-#endif
-};
-
-#define RW_LOCK_BIAS 2 /* XXX bogus */
-#define __RWSEM_INITIALIZER(name, count) \
-{ \
- SPIN_LOCK_UNLOCKED, \
- (count) == 1, (count) == 0, \
- __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \
- __SEM_DEBUG_INIT(name) \
-}
-
-#define __DECLARE_RWSEM_GENERIC(name, count) \
- struct rw_semaphore name = __RWSEM_INITIALIZER(name, count)
-
-#define DECLARE_RWSEM(name) __DECLARE_RWSEM_GENERIC(name, RW_LOCK_BIAS)
-#define DECLARE_RWSEM_READ_LOCKED(name) __DECLARE_RWSEM_GENERIC(name, RW_LOCK_BIAS-1)
-#define DECLARE_RWSEM_WRITE_LOCKED(name) __DECLARE_RWSEM_GENERIC(name, 0)
-
-extern inline void init_rwsem(struct rw_semaphore *sem)
-{
- spin_lock_init(&sem->lock);
- sem->rd = sem->wr = 0;
- init_waitqueue_head(&sem->wait);
-#if WAITQUEUE_DEBUG
- sem->__magic = (long)&sem->__magic;
-#endif
-}
-
-#ifndef CHECK_MAGIC
-#define CHECK_MAGIC(x)
-#endif
-
-extern void down_read_failed(struct rw_semaphore *);
-extern void down_write_failed(struct rw_semaphore *);
-
-extern inline void down_read(struct rw_semaphore *sem)
-{
- CHECK_MAGIC(sem->__magic);
-
- spin_lock_irq(&sem->lock);
- if (sem->wr)
- down_read_failed(sem);
- sem->rd++;
- spin_unlock_irq(&sem->lock);
-}
-
-extern inline void down_write(struct rw_semaphore *sem)
-{
- CHECK_MAGIC(sem->__magic);
-
- spin_lock(&sem->lock);
- if(sem->rd || sem->wr)
- down_write_failed(sem);
- sem->wr = 1;
- spin_unlock(&sem->lock);
-}
-
-#define up_read(sem) \
- do { \
- unsigned long flags; \
- \
- CHECK_MAGIC((sem)->__magic); \
- \
- spin_lock_irqsave(&(sem)->lock, flags); \
- if (!--(sem)->rd && waitqueue_active(&(sem)->wait)) \
- wake_up(&(sem)->wait); \
- spin_unlock_irqrestore(&(sem)->lock, flags); \
- } while (0)
-
-#define up_write(sem) \
- do { \
- unsigned long flags; \
- \
- CHECK_MAGIC((sem)->__magic); \
- \
- spin_lock_irqsave(&(sem)->lock, flags); \
- (sem)->wr = 0; \
- if (waitqueue_active(&(sem)->wait)) \
- wake_up(&(sem)->wait); \
- spin_unlock_irqrestore(&(sem)->lock, flags); \
- } while (0)
-
-
#endif /* __KERNEL__ */
#endif /* !(_PPC_SEMAPHORE_H) */
#include <asm/system.h>
#include <asm/atomic.h>
#include <linux/wait.h>
+#include <linux/rwsem.h>
struct semaphore {
atomic_t count;
__up(sem);
}
-/* rw mutexes (should that be mutices? =) -- throw rw
- * spinlocks and semaphores together, and this is what we
- * end up with...
- *
- * The lock is initialized to BIAS. This way, a writer
- * subtracts BIAS ands gets 0 for the case of an uncontended
- * lock. Readers decrement by 1 and see a positive value
- * when uncontended, negative if there are writers waiting
- * (in which case it goes to sleep).
- *
- * The value 0x01000000 supports up to 128 processors and
- * lots of processes. BIAS must be chosen such that subl'ing
- * BIAS once per CPU will result in the long remaining
- * negative.
- *
- * In terms of fairness, this should result in the lock
- * flopping back and forth between readers and writers
- * under heavy use.
- *
- * -ben
- */
-struct rw_semaphore {
- atomic_t count;
- volatile unsigned int write_bias_granted;
- volatile unsigned int read_bias_granted;
- wait_queue_head_t wait;
- wait_queue_head_t write_bias_wait;
-};
-
-#define RW_LOCK_BIAS 0x01000000
-
-#define __RWSEM_DEBUG_INIT /* */
-
-#define __RWSEM_INITIALIZER(name,count) \
-{ ATOMIC_INIT(count), 0, 0, __WAIT_QUEUE_HEAD_INITIALIZER((name).wait), \
- __WAIT_QUEUE_HEAD_INITIALIZER((name).write_bias_wait) \
- __SEM_DEBUG_INIT(name) __RWSEM_DEBUG_INIT }
-
-#define __DECLARE_RWSEM_GENERIC(name,count) \
- struct rw_semaphore name = __RWSEM_INITIALIZER(name,count)
-
-#define DECLARE_RWSEM(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS)
-#define DECLARE_RWSEM_READ_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS-1)
-#define DECLARE_RWSEM_WRITE_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,0)
-
-static inline void init_rwsem(struct rw_semaphore *sem)
-{
- atomic_set(&sem->count, RW_LOCK_BIAS);
- sem->read_bias_granted = 0;
- sem->write_bias_granted = 0;
- init_waitqueue_head(&sem->wait);
- init_waitqueue_head(&sem->write_bias_wait);
-}
-
-extern void __down_read_failed(int, struct rw_semaphore *);
-extern void __down_write_failed(int, struct rw_semaphore *);
-extern void __rwsem_wake(int, struct rw_semaphore *);
-
-static inline void down_read(struct rw_semaphore *sem)
-{
- int count;
- count = atomic_dec_return(&sem->count);
- if (count < 0)
- __down_read_failed(count, sem);
-}
-
-static inline void down_write(struct rw_semaphore *sem)
-{
- int count;
- count = atomic_add_return (-RW_LOCK_BIAS, &sem->count);
- if (count < 0)
- __down_write_failed(count, sem);
-}
-
-/* When a reader does a release, the only significant
- * case is when there was a writer waiting, and we've
- * bumped the count to 0: we must wake the writer up.
- */
-static inline void up_read(struct rw_semaphore *sem)
-{
- int count;
- count = atomic_inc_return(&sem->count);
- if (count == 0)
- __rwsem_wake(count, sem);
-}
-
-/* releasing the writer is easy -- just release it and
- * wake up any sleepers.
- */
-static inline void up_write(struct rw_semaphore *sem)
-{
- int count;
- count = atomic_add_return(RW_LOCK_BIAS, &sem->count);
- if (count >= 0 && count < RW_LOCK_BIAS)
- __rwsem_wake(count, sem);
-}
-
#endif
#include <asm/system.h>
#include <asm/atomic.h>
#include <linux/wait.h>
+#include <linux/rwsem.h>
struct semaphore {
atomic_t count;
__up(sem);
}
-/* rw mutexes (should that be mutices? =) -- throw rw
- * spinlocks and semaphores together, and this is what we
- * end up with...
- *
- * The lock is initialized to BIAS. This way, a writer
- * subtracts BIAS ands gets 0 for the case of an uncontended
- * lock. Readers decrement by 1 and see a positive value
- * when uncontended, negative if there are writers waiting
- * (in which case it goes to sleep).
- *
- * The value 0x01000000 supports up to 128 processors and
- * lots of processes. BIAS must be chosen such that subl'ing
- * BIAS once per CPU will result in the long remaining
- * negative.
- *
- * In terms of fairness, this should result in the lock
- * flopping back and forth between readers and writers
- * under heavy use.
- *
- * -ben
- */
-struct rw_semaphore {
- atomic_t count;
- volatile unsigned int write_bias_granted;
- volatile unsigned int read_bias_granted;
- wait_queue_head_t wait;
- wait_queue_head_t write_bias_wait;
-};
-
-#define RW_LOCK_BIAS 0x01000000
-
-#define __RWSEM_DEBUG_INIT /* */
-
-#define __RWSEM_INITIALIZER(name,count) \
-{ ATOMIC_INIT(count), 0, 0, __WAIT_QUEUE_HEAD_INITIALIZER((name).wait), \
- __WAIT_QUEUE_HEAD_INITIALIZER((name).write_bias_wait) \
- __SEM_DEBUG_INIT(name) __RWSEM_DEBUG_INIT }
-
-#define __DECLARE_RWSEM_GENERIC(name,count) \
- struct rw_semaphore name = __RWSEM_INITIALIZER(name,count)
-
-#define DECLARE_RWSEM(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS)
-#define DECLARE_RWSEM_READ_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS-1)
-#define DECLARE_RWSEM_WRITE_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,0)
-
-static inline void init_rwsem(struct rw_semaphore *sem)
-{
- atomic_set(&sem->count, RW_LOCK_BIAS);
- sem->read_bias_granted = 0;
- sem->write_bias_granted = 0;
- init_waitqueue_head(&sem->wait);
- init_waitqueue_head(&sem->write_bias_wait);
-}
-
-extern void __down_read_failed(int, struct rw_semaphore *);
-extern void __down_write_failed(int, struct rw_semaphore *);
-extern void __rwsem_wake(int, struct rw_semaphore *);
-
-static inline void down_read(struct rw_semaphore *sem)
-{
- int count;
- count = atomic_dec_return(&sem->count);
- if (count < 0)
- __down_read_failed(count, sem);
-}
-
-static inline void down_write(struct rw_semaphore *sem)
-{
- int count;
- count = atomic_add_return (-RW_LOCK_BIAS, &sem->count);
- if (count < 0)
- __down_write_failed(count, sem);
-}
-
-/* When a reader does a release, the only significant
- * case is when there was a writer waiting, and we've
- * bumped the count to 0: we must wake the writer up.
- */
-static inline void up_read(struct rw_semaphore *sem)
-{
- int count;
- count = atomic_inc_return(&sem->count);
- if (count == 0)
- __rwsem_wake(count, sem);
-}
-
-/* releasing the writer is easy -- just release it and
- * wake up any sleepers.
- */
-static inline void up_write(struct rw_semaphore *sem)
-{
- int count;
- count = atomic_add_return(RW_LOCK_BIAS, &sem->count);
- if (count >= 0 && count < RW_LOCK_BIAS)
- __rwsem_wake(count, sem);
-}
-
#endif
*/
#include <linux/spinlock.h>
+#include <linux/rwsem.h>
#include <asm/system.h>
#include <asm/atomic.h>
__up(sem);
}
-/* rw mutexes (should that be mutices? =) -- throw rw
- * spinlocks and semaphores together, and this is what we
- * end up with...
- *
- * SuperH version by Niibe Yutaka
- */
-struct rw_semaphore {
- atomic_t count;
- volatile unsigned char write_bias_granted;
- volatile unsigned char read_bias_granted;
- volatile unsigned char pad1;
- volatile unsigned char pad2;
- wait_queue_head_t wait;
- wait_queue_head_t write_bias_wait;
-#if WAITQUEUE_DEBUG
- long __magic;
- atomic_t readers;
- atomic_t writers;
-#endif
-};
-
-#define RW_LOCK_BIAS 0x01000000
-
-#if WAITQUEUE_DEBUG
-#define __RWSEM_DEBUG_INIT , ATOMIC_INIT(0), ATOMIC_INIT(0)
-#else
-#define __RWSEM_DEBUG_INIT /* */
-#endif
-
-#define __RWSEM_INITIALIZER(name,count) \
-{ ATOMIC_INIT(count), 0, 0, 0, 0, __WAIT_QUEUE_HEAD_INITIALIZER((name).wait), \
- __WAIT_QUEUE_HEAD_INITIALIZER((name).write_bias_wait) \
- __SEM_DEBUG_INIT(name) __RWSEM_DEBUG_INIT }
-
-#define __DECLARE_RWSEM_GENERIC(name,count) \
- struct rw_semaphore name = __RWSEM_INITIALIZER(name,count)
-
-#define DECLARE_RWSEM(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS)
-#define DECLARE_RWSEM_READ_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS-1)
-#define DECLARE_RWSEM_WRITE_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,0)
-
-extern inline void init_rwsem(struct rw_semaphore *sem)
-{
- atomic_set(&sem->count, RW_LOCK_BIAS);
- sem->read_bias_granted = 0;
- sem->write_bias_granted = 0;
- init_waitqueue_head(&sem->wait);
- init_waitqueue_head(&sem->write_bias_wait);
-#if WAITQUEUE_DEBUG
- sem->__magic = (long)&sem->__magic;
- atomic_set(&sem->readers, 0);
- atomic_set(&sem->writers, 0);
-#endif
-}
-
-extern inline void down_read(struct rw_semaphore *sem)
-{
- int saved = atomic_read(&sem->count), new;
-#if WAITQUEUE_DEBUG
- if (sem->__magic != (long)&sem->__magic)
- BUG();
-#endif
- if ((new = atomic_dec_return(&sem->count)) < 0)
- __down_read(sem, (new < 0 && saved >=0));
-#if WAITQUEUE_DEBUG
- if (sem->write_bias_granted)
- BUG();
- if (atomic_read(&sem->writers))
- BUG();
- atomic_inc(&sem->readers);
-#endif
-}
-
-extern inline void down_write(struct rw_semaphore *sem)
-{
- int saved = atomic_read(&sem->count), new;
-#if WAITQUEUE_DEBUG
- if (sem->__magic != (long)&sem->__magic)
- BUG();
-#endif
- if ((new = atomic_sub_return(RW_LOCK_BIAS, &sem->count)) != 0)
- __down_write(sem, (new < 0 && saved >=0));
-#if WAITQUEUE_DEBUG
- if (atomic_read(&sem->writers))
- BUG();
- if (atomic_read(&sem->readers))
- BUG();
- if (sem->read_bias_granted)
- BUG();
- if (sem->write_bias_granted)
- BUG();
- atomic_inc(&sem->writers);
-#endif
-}
-
-/* When a reader does a release, the only significant
- * case is when there was a writer waiting, and we've
- * bumped the count to 0: we must wake the writer up.
- */
-extern inline void __up_read(struct rw_semaphore *sem)
-{
- if (atomic_inc_return(&sem->count) == 0)
- __rwsem_wake(sem);
-}
-
-/* releasing the writer is easy -- just release it and
- * wake up any sleepers.
- */
-extern inline void __up_write(struct rw_semaphore *sem)
-{
- int saved = atomic_read(&sem->count), new;
-
- new = atomic_add_return(RW_LOCK_BIAS, &sem->count);
- if (saved < 0 && new >= 0)
- __rwsem_wake(sem);
-}
-
-extern inline void up_read(struct rw_semaphore *sem)
-{
-#if WAITQUEUE_DEBUG
- if (sem->write_bias_granted)
- BUG();
- if (atomic_read(&sem->writers))
- BUG();
- atomic_dec(&sem->readers);
-#endif
- __up_read(sem);
-}
-
-extern inline void up_write(struct rw_semaphore *sem)
-{
-#if WAITQUEUE_DEBUG
- if (sem->read_bias_granted)
- BUG();
- if (sem->write_bias_granted)
- BUG();
- if (atomic_read(&sem->readers))
- BUG();
- if (atomic_read(&sem->writers) != 1)
- BUG();
- atomic_dec(&sem->writers);
-#endif
- __up_write(sem);
-}
-
#endif /* __ASM_SH_SEMAPHORE_H */
#include <asm/atomic.h>
#include <linux/wait.h>
+#include <linux/rwsem.h>
struct semaphore {
atomic_t count;
: "g3", "g4", "g7", "memory", "cc");
}
-/* rw mutexes (should that be mutices? =) -- throw rw
- * spinlocks and semaphores together, and this is what we
- * end up with...
- *
- * The lock is initialized to BIAS. This way, a writer
- * subtracts BIAS ands gets 0 for the case of an uncontended
- * lock. Readers decrement by 1 and see a positive value
- * when uncontended, negative if there are writers waiting
- * (in which case it goes to sleep).
- *
- * The value 0x01000000 supports up to 128 processors and
- * lots of processes. BIAS must be chosen such that subtracting
- * BIAS once per CPU will result in the int remaining
- * negative.
- * In terms of fairness, this should result in the lock
- * flopping back and forth between readers and writers
- * under heavy use.
- *
- * -ben
- */
-#define RW_LOCK_BIAS 0x01000000
-
-struct rw_semaphore {
- int count;
- unsigned char lock;
- unsigned char read_not_granted;
- unsigned char write_not_granted;
- wait_queue_head_t wait;
- wait_queue_head_t write_bias_wait;
-#if WAITQUEUE_DEBUG
- long __magic;
- atomic_t readers;
- atomic_t writers;
-#endif
-};
-
-#if WAITQUEUE_DEBUG
-#define __RWSEM_DEBUG_INIT , ATOMIC_INIT(0), ATOMIC_INIT(0)
-#else
-#define __RWSEM_DEBUG_INIT /* */
-#endif
-
-#define __RWSEM_INITIALIZER(name,count) \
-{ (count), 0, 0xff, 0xff, __WAIT_QUEUE_HEAD_INITIALIZER((name).wait), \
- __WAIT_QUEUE_HEAD_INITIALIZER((name).write_bias_wait) \
- __SEM_DEBUG_INIT(name) __RWSEM_DEBUG_INIT }
-
-#define __DECLARE_RWSEM_GENERIC(name,count) \
- struct rw_semaphore name = __RWSEM_INITIALIZER(name,count)
-
-#define DECLARE_RWSEM(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS)
-#define DECLARE_RWSEM_READ_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS-1)
-#define DECLARE_RWSEM_WRITE_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,0)
-
-static inline void init_rwsem(struct rw_semaphore *sem)
-{
- sem->count = RW_LOCK_BIAS;
- sem->lock = 0;
- sem->read_not_granted = 0xff;
- sem->write_not_granted = 0xff;
- init_waitqueue_head(&sem->wait);
- init_waitqueue_head(&sem->write_bias_wait);
-#if WAITQUEUE_DEBUG
- sem->__magic = (long)&sem->__magic;
- atomic_set(&sem->readers, 0);
- atomic_set(&sem->writers, 0);
-#endif
-}
-
-extern void ___down_read(/* Special calling convention */ void);
-extern void ___down_write(/* Special calling convention */ void);
-extern void ___up_read(/* Special calling convention */ void);
-extern void ___up_write(/* Special calling convention */ void);
-
-static inline void down_read(struct rw_semaphore *sem)
-{
- register volatile int *ptr asm("g1");
-
-#if WAITQUEUE_DEBUG
- CHECK_MAGIC(sem->__magic);
-#endif
-
- ptr = &sem->count;
-
- __asm__ __volatile__("
- mov %%o7, %%g4
- call %1
- add %%o7, 8, %%o7
- "
- :: "r" (ptr), "i" (___down_read)
- : "g2", "g3", "g4", "g7", "memory", "cc");
-#if WAITQUEUE_DEBUG
- if (!sem->write_not_granted)
- BUG();
- if (atomic_read(&sem->writers))
- BUG();
- atomic_inc(&sem->readers);
-#endif
-}
-
-static inline void down_write(struct rw_semaphore *sem)
-{
- register volatile int *ptr asm("g1");
-
-#if WAITQUEUE_DEBUG
- CHECK_MAGIC(sem->__magic);
-#endif
-
- ptr = &sem->count;
-
- __asm__ __volatile__("
- mov %%o7, %%g4
- call %1
- add %%o7, 8, %%o7
- "
- :: "r" (ptr), "i" (___down_write)
- : "g2", "g3", "g4", "g7", "memory", "cc");
-#if WAITQUEUE_DEBUG
- if (atomic_read(&sem->writers))
- BUG();
- if (atomic_read(&sem->readers))
- BUG();
- if (!sem->read_not_granted)
- BUG();
- if (!sem->write_not_granted)
- BUG();
- atomic_inc(&sem->writers);
-#endif
-}
-
-/* When a reader does a release, the only significant
- * case is when there was a writer waiting, and we've
- * bumped the count to 0: we must wake the writer up.
- */
-static inline void __up_read(struct rw_semaphore *sem)
-{
- register volatile int *ptr asm("g1");
-
- ptr = &sem->count;
-
- __asm__ __volatile__("
- mov %%o7, %%g4
- call %1
- add %%o7, 8, %%o7
- "
- :: "r" (ptr), "i" (___up_read)
- : "g2", "g3", "g4", "g7", "memory", "cc");
-}
-
-/* releasing the writer is easy -- just release it and
- * wake up any sleepers.
- */
-static inline void __up_write(struct rw_semaphore *sem)
-{
- register volatile int *ptr asm("g1");
-
- ptr = &sem->count;
-
- __asm__ __volatile__("
- mov %%o7, %%g4
- call %1
- add %%o7, 8, %%o7
- "
- :: "r" (ptr), "i" (___up_write)
- : "g2", "g3", "g4", "g7", "memory", "cc");
-}
-
-static inline void up_read(struct rw_semaphore *sem)
-{
-#if WAITQUEUE_DEBUG
- if (!sem->write_not_granted)
- BUG();
- if (atomic_read(&sem->writers))
- BUG();
- atomic_dec(&sem->readers);
-#endif
- __up_read(sem);
-}
-
-static inline void up_write(struct rw_semaphore *sem)
-{
-#if WAITQUEUE_DEBUG
- if (!sem->read_not_granted)
- BUG();
- if (!sem->write_not_granted)
- BUG();
- if (atomic_read(&sem->readers))
- BUG();
- if (atomic_read(&sem->writers) != 1)
- BUG();
- atomic_dec(&sem->writers);
-#endif
- __up_write(sem);
-}
-
#endif /* __KERNEL__ */
#endif /* !(_SPARC_SEMAPHORE_H) */
-/* $Id: bitops.h,v 1.31 2000/09/23 02:09:21 davem Exp $
+/* $Id: bitops.h,v 1.32 2001/04/14 01:12:16 davem Exp $
* bitops.h: Bit string operations on the V9.
*
* Copyright 1996, 1997 David S. Miller (davem@caip.rutgers.edu)
#include <asm/byteorder.h>
-extern long __test_and_set_bit(unsigned long nr, volatile void *addr);
-extern long __test_and_clear_bit(unsigned long nr, volatile void *addr);
-extern long __test_and_change_bit(unsigned long nr, volatile void *addr);
-
-#define test_and_set_bit(nr,addr) (__test_and_set_bit(nr,addr)!=0)
-#define test_and_clear_bit(nr,addr) (__test_and_clear_bit(nr,addr)!=0)
-#define test_and_change_bit(nr,addr) (__test_and_change_bit(nr,addr)!=0)
-#define set_bit(nr,addr) ((void)__test_and_set_bit(nr,addr))
-#define clear_bit(nr,addr) ((void)__test_and_clear_bit(nr,addr))
-#define change_bit(nr,addr) ((void)__test_and_change_bit(nr,addr))
+extern long ___test_and_set_bit(unsigned long nr, volatile void *addr);
+extern long ___test_and_clear_bit(unsigned long nr, volatile void *addr);
+extern long ___test_and_change_bit(unsigned long nr, volatile void *addr);
+
+#define test_and_set_bit(nr,addr) (___test_and_set_bit(nr,addr)!=0)
+#define test_and_clear_bit(nr,addr) (___test_and_clear_bit(nr,addr)!=0)
+#define test_and_change_bit(nr,addr) (___test_and_change_bit(nr,addr)!=0)
+#define set_bit(nr,addr) ((void)___test_and_set_bit(nr,addr))
+#define clear_bit(nr,addr) ((void)___test_and_clear_bit(nr,addr))
+#define change_bit(nr,addr) ((void)___test_and_change_bit(nr,addr))
+
+/* "non-atomic" versions, nothing special for now... */
+#define __set_bit(X,Y) set_bit(X,Y)
+#define __clear_bit(X,Y) clear_bit(X,Y)
+#define __change_bit(X,Y) change_bit(X,Y)
+#define __test_and_set_bit(X,Y) test_and_set_bit(X,Y)
+#define __test_and_clear_bit(X,Y) test_and_clear_bit(X,Y)
+#define __test_and_change_bit(X,Y) test_and_change_bit(X,Y)
#define smp_mb__before_clear_bit() do { } while(0)
#define smp_mb__after_clear_bit() do { } while(0)
#define find_first_zero_bit(addr, size) \
find_next_zero_bit((addr), (size), 0)
-extern long __test_and_set_le_bit(int nr, volatile void *addr);
-extern long __test_and_clear_le_bit(int nr, volatile void *addr);
+extern long ___test_and_set_le_bit(int nr, volatile void *addr);
+extern long ___test_and_clear_le_bit(int nr, volatile void *addr);
-#define test_and_set_le_bit(nr,addr) (__test_and_set_le_bit(nr,addr)!=0)
-#define test_and_clear_le_bit(nr,addr) (__test_and_clear_le_bit(nr,addr)!=0)
-#define set_le_bit(nr,addr) ((void)__test_and_set_le_bit(nr,addr))
-#define clear_le_bit(nr,addr) ((void)__test_and_clear_le_bit(nr,addr))
+#define test_and_set_le_bit(nr,addr) (___test_and_set_le_bit(nr,addr)!=0)
+#define test_and_clear_le_bit(nr,addr) (___test_and_clear_le_bit(nr,addr)!=0)
+#define set_le_bit(nr,addr) ((void)___test_and_set_le_bit(nr,addr))
+#define clear_le_bit(nr,addr) ((void)___test_and_clear_le_bit(nr,addr))
extern __inline__ int test_le_bit(int nr, __const__ void * addr)
{
-/* $Id: pgtable.h,v 1.139 2001/03/27 02:36:37 davem Exp $
+/* $Id: pgtable.h,v 1.140 2001/04/12 22:41:15 davem Exp $
* pgtable.h: SpitFire page table operations.
*
* Copyright 1996,1997 David S. Miller (davem@caip.rutgers.edu)
}
/* Encode and de-code a swap entry */
-#define SWP_TYPE(entry) (((entry).val >> PAGE_SHIFT) & 0xff)
-#define SWP_OFFSET(entry) ((entry).val >> (PAGE_SHIFT + 8))
+#define SWP_TYPE(entry) (((entry).val >> PAGE_SHIFT) & 0xffUL)
+#define SWP_OFFSET(entry) ((entry).val >> (PAGE_SHIFT + 8UL))
#define SWP_ENTRY(type, offset) \
( (swp_entry_t) \
{ \
- ((type << PAGE_SHIFT) | (offset << (PAGE_SHIFT + 8))) \
+ (((long)(type) << PAGE_SHIFT) | \
+ ((long)(offset) << (PAGE_SHIFT + 8UL))) \
} )
#define pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) })
#define swp_entry_to_pte(x) ((pte_t) { (x).val })
--- /dev/null
+/* $Id: rwsem.h,v 1.1 2001/04/14 01:12:16 davem Exp $ */
+#ifndef _SPARC64_RWSEM_H
+#define _SPARC64_RWSEM_H
+
+#ifndef _LINUX_RWSEM_H
+#error please dont include asm/rwsem.h directly, use linux/rwsem.h instead
+#endif
+
+#undef __HAVE_ARCH_SPECIFIC_RWSEM_IMPLEMENTATION
+
+#endif /* _SPARC64_RWSEM_H */
#include <asm/bitops.h>
#include <asm/system.h>
#include <linux/wait.h>
+#include <linux/rwsem.h>
struct semaphore {
atomic_t count;
: "g5", "g7", "memory", "cc");
}
-/* rw mutexes (should that be mutices? =) -- throw rw
- * spinlocks and semaphores together, and this is what we
- * end up with...
- *
- * The lock is initialized to BIAS. This way, a writer
- * subtracts BIAS ands gets 0 for the case of an uncontended
- * lock. Readers decrement by 1 and see a positive value
- * when uncontended, negative if there are writers waiting
- * (in which case it goes to sleep).
- *
- * The value 0x01000000 supports up to 128 processors and
- * lots of processes. BIAS must be chosen such that subtracting
- * BIAS once per CPU will result in the int remaining
- * negative.
- * In terms of fairness, this should result in the lock
- * flopping back and forth between readers and writers
- * under heavy use.
- *
- * -ben
- *
- * Once we start supporting machines with more than 128 CPUs,
- * we should go for using a 64bit atomic type instead of 32bit
- * as counter. We shall probably go for bias 0x80000000 then,
- * so that single sethi can set it.
- *
- * -jj
- */
-#define RW_LOCK_BIAS 0x01000000
-#define RW_LOCK_BIAS_STR "0x01000000"
-
-struct rw_semaphore {
- int count;
- /* So that this does not have to be 64bit type,
- * we'll use le bitops on it which use casa instead of casx.
- * bit 0 means read bias granted
- * bit 1 means write bias granted
- */
- unsigned granted;
- wait_queue_head_t wait;
- wait_queue_head_t write_bias_wait;
-#if WAITQUEUE_DEBUG
- long __magic;
- atomic_t readers;
- atomic_t writers;
-#endif
-};
-
-#if WAITQUEUE_DEBUG
-#define __RWSEM_DEBUG_INIT , ATOMIC_INIT(0), ATOMIC_INIT(0)
-#else
-#define __RWSEM_DEBUG_INIT /* */
-#endif
-
-#define __RWSEM_INITIALIZER(name,count) \
-{ (count), 0, __WAIT_QUEUE_HEAD_INITIALIZER((name).wait), \
- __WAIT_QUEUE_HEAD_INITIALIZER((name).write_bias_wait) \
- __SEM_DEBUG_INIT(name) __RWSEM_DEBUG_INIT }
-
-#define __DECLARE_RWSEM_GENERIC(name,count) \
- struct rw_semaphore name = __RWSEM_INITIALIZER(name,count)
-
-#define DECLARE_RWSEM(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS)
-#define DECLARE_RWSEM_READ_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS-1)
-#define DECLARE_RWSEM_WRITE_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,0)
-
-extern inline void init_rwsem(struct rw_semaphore *sem)
-{
- sem->count = RW_LOCK_BIAS;
- sem->granted = 0;
- init_waitqueue_head(&sem->wait);
- init_waitqueue_head(&sem->write_bias_wait);
-#if WAITQUEUE_DEBUG
- sem->__magic = (long)&sem->__magic;
- atomic_set(&sem->readers, 0);
- atomic_set(&sem->writers, 0);
-#endif
-}
-
-extern void __down_read_failed(/* Special calling convention */ void);
-extern void __down_write_failed(/* Special calling convention */ void);
-extern void __rwsem_wake(struct rw_semaphore *sem, unsigned long readers);
-
-extern inline void down_read(struct rw_semaphore *sem)
-{
-#if WAITQUEUE_DEBUG
- CHECK_MAGIC(sem->__magic);
-#endif
- __asm__ __volatile__("
- 1: lduw [%0], %%g5
- subcc %%g5, 1, %%g7
- cas [%0], %%g5, %%g7
- bneg,pn %%icc, 3f
- cmp %%g5, %%g7
- bne,pn %%icc, 1b
- membar #StoreStore
- 2:
- .subsection 2
- 3: bne,pn %%icc, 1b
- mov %0, %%g7
- save %%sp, -160, %%sp
- mov %%g1, %%l1
- mov %%g2, %%l2
- call %1
- mov %%g3, %%l3
- mov %%l1, %%g1
- mov %%l2, %%g2
- ba,pt %%xcc, 2b
- restore %%l3, %%g0, %%g3
- .previous\n"
- : : "r" (sem), "i" (__down_read_failed)
- : "g5", "g7", "memory", "cc");
-#if WAITQUEUE_DEBUG
- if (test_le_bit(1, &sem->granted))
- BUG();
- if (atomic_read(&sem->writers))
- BUG();
- atomic_inc(&sem->readers);
-#endif
-}
-
-extern inline void down_write(struct rw_semaphore *sem)
-{
-#if WAITQUEUE_DEBUG
- CHECK_MAGIC(sem->__magic);
-#endif
- __asm__ __volatile__("
- 1: lduw [%0], %%g5
- sethi %%hi(" RW_LOCK_BIAS_STR "), %%g7
- subcc %%g5, %%g7, %%g7
- cas [%0], %%g5, %%g7
- bne,pn %%icc, 3f
- cmp %%g5, %%g7
- bne,pn %%icc, 1b
- membar #StoreStore
- 2:
- .subsection 2
- 3: bne,pn %%icc, 1b
- mov %0, %%g7
- save %%sp, -160, %%sp
- mov %%g1, %%l1
- mov %%g2, %%l2
- call %1
- mov %%g3, %%l3
- mov %%l1, %%g1
- mov %%l2, %%g2
- ba,pt %%xcc, 2b
- restore %%l3, %%g0, %%g3
- .previous\n"
- : : "r" (sem), "i" (__down_write_failed)
- : "g5", "g7", "memory", "cc");
-#if WAITQUEUE_DEBUG
- if (atomic_read(&sem->writers))
- BUG();
- if (atomic_read(&sem->readers))
- BUG();
- if (test_le_bit(0, &sem->granted))
- BUG();
- if (test_le_bit(1, &sem->granted))
- BUG();
- atomic_inc(&sem->writers);
-#endif
-}
-
-/* When a reader does a release, the only significant
- * case is when there was a writer waiting, and we've
- * bumped the count to 0: we must wake the writer up.
- */
-extern inline void __up_read(struct rw_semaphore *sem)
-{
- __asm__ __volatile__("
- membar #StoreLoad | #LoadLoad
- 1: lduw [%0], %%g5
- addcc %%g5, 1, %%g7
- cas [%0], %%g5, %%g7
- be,pn %%icc, 3f
- cmp %%g5, %%g7
- bne,pn %%icc, 1b
- nop
- 2:
- .subsection 2
- 3: bne,pn %%icc, 1b
- mov %0, %%g7
- save %%sp, -160, %%sp
- mov %%g1, %%l1
- mov %%g2, %%l2
- clr %%o1
- mov %%g7, %%o0
- call %1
- mov %%g3, %%l3
- mov %%l1, %%g1
- mov %%l2, %%g2
- ba,pt %%xcc, 2b
- restore %%l3, %%g0, %%g3
- .previous\n"
- : : "r" (sem), "i" (__rwsem_wake)
- : "g5", "g7", "memory", "cc");
-}
-
-/* releasing the writer is easy -- just release it and
- * wake up any sleepers.
- */
-extern inline void __up_write(struct rw_semaphore *sem)
-{
- __asm__ __volatile__("
- membar #StoreLoad | #LoadLoad
- 1: lduw [%0], %%g5
- sethi %%hi(" RW_LOCK_BIAS_STR "), %%g7
- add %%g5, %%g7, %%g7
- cas [%0], %%g5, %%g7
- cmp %%g5, %%g7
- bne,pn %%icc, 1b
- sethi %%hi(" RW_LOCK_BIAS_STR "), %%g7
- addcc %%g5, %%g7, %%g5
- bcs,pn %%icc, 3f
- nop
- 2:
- .subsection 2
- 3: mov %0, %%g7
- save %%sp, -160, %%sp
- mov %%g1, %%l1
- mov %%g2, %%l2
- srl %%g5, 0, %%o1
- mov %%g7, %%o0
- call %1
- mov %%g3, %%l3
- mov %%l1, %%g1
- mov %%l2, %%g2
- ba,pt %%xcc, 2b
- restore %%l3, %%g0, %%g3
- .previous\n"
- : : "r" (sem), "i" (__rwsem_wake)
- : "g5", "g7", "memory", "cc");
-}
-
-extern inline void up_read(struct rw_semaphore *sem)
-{
-#if WAITQUEUE_DEBUG
- if (test_le_bit(1, &sem->granted))
- BUG();
- if (atomic_read(&sem->writers))
- BUG();
- atomic_dec(&sem->readers);
-#endif
- __up_read(sem);
-}
-
-extern inline void up_write(struct rw_semaphore *sem)
-{
-#if WAITQUEUE_DEBUG
- if (test_le_bit(0, &sem->granted))
- BUG();
- if (test_le_bit(1, &sem->granted))
- BUG();
- if (atomic_read(&sem->readers))
- BUG();
- if (atomic_read(&sem->writers) != 1)
- BUG();
- atomic_dec(&sem->writers);
-#endif
- __up_write(sem);
-}
-
#endif /* __KERNEL__ */
#endif /* !(_SPARC64_SEMAPHORE_H) */
unsigned int minor_start,
umode_t mode, void *ops, void *info);
-extern int init_devfs_fs (void);
extern void mount_devfs_fs (void);
extern void devfs_make_root (const char *name);
#else /* CONFIG_DEVFS_FS */
return;
}
-static inline int init_devfs_fs (void)
-{
- return 0;
-}
static inline void mount_devfs_fs (void)
{
return;
extern struct file_system_type *get_fs_type(const char *name);
extern struct super_block *get_super(kdev_t);
-struct super_block *get_empty_super(void);
extern void put_super(kdev_t);
unsigned long generate_cluster(kdev_t, int b[], int);
unsigned long generate_cluster_swab32(kdev_t, int b[], int);
#define ARPHRD_ECONET 782 /* Acorn Econet */
#define ARPHRD_IRDA 783 /* Linux-IrDA */
/* ARP works differently on different FC media .. so */
-#define ARPHRD_FCPP 784 /* Point to point fibrechanel */
+#define ARPHRD_FCPP 784 /* Point to point fibrechannel */
#define ARPHRD_FCAL 785 /* Fibrechannel arbitrated loop */
#define ARPHRD_FCPL 786 /* Fibrechannel public loop */
#define ARPHRD_FCFABRIC 787 /* Fibrechannel fabric */
* linux/fs/nfs/inode.c
*/
extern struct super_block *nfs_read_super(struct super_block *, void *, int);
-extern int init_nfs_fs(void);
extern void nfs_zap_caches(struct inode *);
extern int nfs_inode_is_stale(struct inode *, struct nfs_fh *,
struct nfs_fattr *);
#ifdef __KERNEL__
-#define CONFIG_USING_SPINLOCK_BASED_RWSEM 1
-
/*
* the semaphore definition
*/
#include <asm/atomic.h>
#include <linux/wait.h>
-#if RWSEM_DEBUG
-#define rwsemdebug(FMT, ARGS...) do { if (sem->debug) printk(FMT,##ARGS); } while(0)
+#ifdef CONFIG_RWSEM_GENERIC_SPINLOCK
+#include <linux/rwsem-spinlock.h> /* use a generic implementation */
#else
-#define rwsemdebug(FMT, ARGS...)
+#include <asm/rwsem.h> /* use an arch-specific implementation */
#endif
+/* defined contention handler functions for the generic case
+ * - these are also used for the exchange-and-add based algorithm
+ */
+#if defined(CONFIG_RWSEM_GENERIC) || defined(CONFIG_RWSEM_XCHGADD_ALGORITHM)
/* we use FASTCALL convention for the helpers */
extern struct rw_semaphore *FASTCALL(rwsem_down_read_failed(struct rw_semaphore *sem));
extern struct rw_semaphore *FASTCALL(rwsem_down_write_failed(struct rw_semaphore *sem));
extern struct rw_semaphore *FASTCALL(rwsem_wake(struct rw_semaphore *sem));
+#endif
-#include <asm/rwsem.h> /* find the arch specific bits */
-
-#ifndef __HAVE_ARCH_SPECIFIC_RWSEM_IMPLEMENTATION
-#include <linux/rwsem-spinlock.h>
+#ifndef rwsemtrace
+#if RWSEM_DEBUG
+#include <asm/current.h>
+#define rwsemtrace(SEM,FMT) do { if ((SEM)->debug) printk("[%d] "FMT"(count=%08lx)\n",current->pid,(SEM)->count); } while(0)
+#else
+#define rwsemtrace(SEM,FMT)
+#endif
#endif
/*
*/
static inline void down_read(struct rw_semaphore *sem)
{
- rwsemdebug("Entering down_read(count=%08lx)\n",sem->count);
+ rwsemtrace(sem,"Entering down_read");
#if RWSEM_DEBUG_MAGIC
if (sem->__magic != (long)&sem->__magic)
atomic_inc(&sem->readers);
#endif
- rwsemdebug("Leaving down_read(count=%08lx)\n",sem->count);
+ rwsemtrace(sem,"Leaving down_read");
}
/*
*/
static inline void down_write(struct rw_semaphore *sem)
{
- rwsemdebug("Entering down_write(count=%08lx)\n",sem->count);
+ rwsemtrace(sem,"Entering down_write");
#if RWSEM_DEBUG_MAGIC
if (sem->__magic != (long)&sem->__magic)
atomic_inc(&sem->writers);
#endif
- rwsemdebug("Leaving down_write(count=%08lx)\n",sem->count);
+ rwsemtrace(sem,"Leaving down_write");
}
/*
*/
static inline void up_read(struct rw_semaphore *sem)
{
- rwsemdebug("Entering up_read(count=%08lx)\n",sem->count);
+ rwsemtrace(sem,"Entering up_read");
#if RWSEM_DEBUG_MAGIC
if (atomic_read(&sem->writers))
#endif
__up_read(sem);
- rwsemdebug("Leaving up_read(count=%08lx)\n",sem->count);
+ rwsemtrace(sem,"Leaving up_read");
}
/*
*/
static inline void up_write(struct rw_semaphore *sem)
{
- rwsemdebug("Entering up_write(count=%08lx)\n",sem->count);
+ rwsemtrace(sem,"Entering up_write");
#if RWSEM_DEBUG_MAGIC
if (atomic_read(&sem->readers))
#endif
__up_write(sem);
- rwsemdebug("Leaving up_write(count=%08lx)\n",sem->count);
+ rwsemtrace(sem,"Leaving up_write");
}
unsigned short tk_lock; /* Task lock counter */
unsigned char tk_active : 1,/* Task has been activated */
tk_wakeup : 1;/* Task waiting to wake up */
- unsigned int tk_runstate; /* Task run status */
+ unsigned long tk_runstate; /* Task run status */
#ifdef RPC_DEBUG
unsigned short tk_pid; /* debugging aid */
#endif
#define _LINUX_TTY_LDISC_H
/*
- * This structure defines the interface between the tty line discpline
+ * This structure defines the interface between the tty line discipline
* implementation and the tty routines. The following routines can be
* defined; unless noted otherwise, they are optional, and can be
* filled in with a null pointer.
*
* int (*open)(struct tty_struct *);
*
- * This function is called when the line discpline is associated
- * with the tty. The line discpline can use this as an
+ * This function is called when the line discipline is associated
+ * with the tty. The line discipline can use this as an
* opportunity to initialize any state needed by the ldisc routines.
*
* void (*close)(struct tty_struct *);
*
- * This function is called when the line discpline is being
+ * This function is called when the line discipline is being
* shutdown, either because the tty is being closed or because
- * the tty is being changed to use a new line discpline
+ * the tty is being changed to use a new line discipline
*
* void (*flush_buffer)(struct tty_struct *tty);
*
* ssize_t (*chars_in_buffer)(struct tty_struct *tty);
*
* This function returns the number of input characters the line
- * iscpline may have queued up to be delivered to the user mode
+ * discipline may have queued up to be delivered to the user mode
* process.
*
* ssize_t (*read)(struct tty_struct * tty, struct file * file,
* unsigned char * buf, size_t nr);
*
* This function is called when the user requests to read from
- * the tty. The line discpline will return whatever characters
+ * the tty. The line discipline will return whatever characters
* it has buffered up for the user. If this function is not
* defined, the user will receive an EIO error.
*
* const unsigned char * buf, size_t nr);
*
* This function is called when the user requests to write to the
- * tty. The line discpline will deliver the characters to the
+ * tty. The line discipline will deliver the characters to the
* low-level tty device for transmission, optionally performing
* some processing on the characters first. If this function is
* not defined, the user will receive an EIO error.
* This function is called when the user requests an ioctl which
* is not handled by the tty layer or the low-level tty driver.
* It is intended for ioctls which affect line discpline
- * operation. Not that the search order for ioctls is (1) tty
+ * operation. Note that the search order for ioctls is (1) tty
* layer, (2) tty low-level driver, (3) line discpline. So a
* low-level driver can "grab" an ioctl request before the line
* discpline has a chance to see it.
* void (*set_termios)(struct tty_struct *tty, struct termios * old);
*
* This function notifies the line discpline that a change has
- * been made to the termios stucture.
+ * been made to the termios structure.
*
* int (*poll)(struct tty_struct * tty, struct file * file,
* poll_table *wait);
*
* Author: Nenad Corbic <ncorbic@sangoma.com>
* Gideon Hack
+* Additions: Arnaldo Melo
*
* Copyright: (c) 1995-2000 Sangoma Technologies Inc.
*
* Jan 28, 2000 Nenad Corbic Added support for the ASYNC protocol.
* Oct 04, 1999 Nenad Corbic Updated for 2.1.0 release
* Jun 02, 1999 Gideon Hack Added support for the S514 adapter.
+* May 23, 1999 Arnaldo Melo Added local_addr to wanif_conf_t
+* WAN_DISCONNECTING state added
* Jul 20, 1998 David Fong Added Inverse ARP options to 'wanif_conf_t'
* Jun 12, 1998 David Fong Added Cisco HDLC support.
* Dec 16, 1997 Jaspreet Singh Moved 'enable_IPX' and 'network_number' to
unsigned inarp_interval; /* sec, between InARP requests */
unsigned long network_number; /* Network Number for IPX */
char mc; /* Multicast on or off */
+ char local_addr[WAN_ADDRESS_SZ+1];/* local media address, ASCIIZ */
+ unsigned char port; /* board port */
+ unsigned char protocol; /* prococol used in this channel (TCPOX25 or X25) */
char pap; /* PAP enabled or disabled */
char chap; /* CHAP enabled or disabled */
unsigned char userid[511]; /* List of User Id */
unsigned char ignore_cts; /* Ignore these to determine */
unsigned char ignore_keepalive; /* link status (Yes or No) */
unsigned char hdlc_streaming; /* Hdlc streaming mode (Y/N) */
- unsigned char receive_only; /* no transmit buffering (Y/N) */
unsigned keepalive_tx_tmr; /* transmit keepalive timer */
unsigned keepalive_rx_tmr; /* receive keepalive timer */
unsigned keepalive_err_margin; /* keepalive_error_tolerance */
unsigned rx_complete_length;
unsigned xon_char;
unsigned xoff_char;
-
+ unsigned char receive_only; /* no transmit buffering (Y/N) */
} wanif_conf_t;
#ifdef __KERNEL__
/****** status and statistics *******/
char state; /* device state */
char api_status; /* device api status */
- #if defined(LINUX_2_1) || defined(LINUX_2_4)
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
struct net_device_stats stats; /* interface statistics */
- #else
+#else
struct enet_statistics stats; /* interface statistics */
- #endif
+#endif
unsigned reserved[16]; /* reserved for future use */
unsigned long critical; /* critical section flag */
spinlock_t lock; /* Support for SMP Locking */
struct wan_device* next; /* -> next device */
netdevice_t* dev; /* list of network interfaces */
unsigned ndev; /* number of interfaces */
- #ifdef LINUX_2_4
+#ifdef LINUX_2_4
struct proc_dir_entry *dent; /* proc filesystem entry */
- #else
+#else
struct proc_dir_entry dent; /* proc filesystem entry */
- #endif
+#endif
} wan_device_t;
/* Public functions available for device drivers */
extern void net_notifier_init(void);
extern void free_initmem(void);
-extern void filesystem_setup(void);
#ifdef CONFIG_TC
extern void tc_init(void);
start_context_thread();
do_initcalls();
- /* .. filesystems .. */
- filesystem_setup();
-
#ifdef CONFIG_IRDA
irda_device_init(); /* Must be done after protocol initialization */
#endif
EXPORT_SYMBOL(update_atime);
EXPORT_SYMBOL(get_fs_type);
EXPORT_SYMBOL(get_super);
-EXPORT_SYMBOL(get_empty_super);
EXPORT_SYMBOL(getname);
EXPORT_SYMBOL(names_cachep);
EXPORT_SYMBOL(fput);
L_TARGET := lib.a
-export-objs := cmdline.o rwsem.o
+export-objs := cmdline.o
-obj-y := errno.o ctype.o string.o vsprintf.o brlock.o cmdline.o rwsem.o
+obj-y := errno.o ctype.o string.o vsprintf.o brlock.o cmdline.o
+
+ifneq ($(CONFIG_RWSEM_GENERIC_SPINLOCK)$(CONFIG_RWSEM_XCHGADD_ALGORITHM),nn)
+export-objs += rwsem.o
+obj-y += rwsem.o
+endif
ifneq ($(CONFIG_HAVE_DEC_LOCK),y)
obj-y += dec_and_lock.o
DECLARE_WAITQUEUE(wait,tsk);
signed long count;
- rwsemdebug("[%d] Entering rwsem_down_read_failed(%08lx)\n",current->pid,sem->count);
+ rwsemtrace(sem,"Entering rwsem_down_read_failed");
/* this waitqueue context flag will be cleared when we are granted the lock */
__set_bit(RWSEM_WAITING_FOR_READ,&wait.flags);
/* note that we're now waiting on the lock, but no longer actively read-locking */
count = rwsem_atomic_update(RWSEM_WAITING_BIAS-RWSEM_ACTIVE_BIAS,sem);
- rwsemdebug("X(%08lx)\n",count);
/* if there are no longer active locks, wake the front queued process(es) up
* - it might even be this process, since the waker takes a more active part
remove_wait_queue(&sem->wait,&wait);
tsk->state = TASK_RUNNING;
- rwsemdebug("[%d] Leaving rwsem_down_read_failed(%08lx)\n",current->pid,sem->count);
-
+ rwsemtrace(sem,"Leaving rwsem_down_read_failed");
return sem;
}
DECLARE_WAITQUEUE(wait,tsk);
signed long count;
- rwsemdebug("[%d] Entering rwsem_down_write_failed(%08lx)\n",current->pid,sem->count);
+ rwsemtrace(sem,"Entering rwsem_down_write_failed");
/* this waitqueue context flag will be cleared when we are granted the lock */
__set_bit(RWSEM_WAITING_FOR_WRITE,&wait.flags);
/* note that we're waiting on the lock, but no longer actively locking */
count = rwsem_atomic_update(-RWSEM_ACTIVE_BIAS,sem);
- rwsemdebug("[%d] updated(%08lx)\n",current->pid,count);
/* if there are no longer active locks, wake the front queued process(es) up
* - it might even be this process, since the waker takes a more active part
remove_wait_queue(&sem->wait,&wait);
tsk->state = TASK_RUNNING;
- rwsemdebug("[%d] Leaving rwsem_down_write_failed(%08lx)\n",current->pid,sem->count);
-
+ rwsemtrace(sem,"Leaving rwsem_down_write_failed");
return sem;
}
signed long count;
int woken;
- rwsemdebug("[%d] Entering rwsem_wake(%08lx)\n",current->pid,sem->count);
+ rwsemtrace(sem,"Entering rwsem_wake");
try_again:
/* try to grab an 'activity' marker
* - be horribly naughty, and only deal with the LSW of the atomic counter
*/
if (rwsem_cmpxchgw(sem,0,RWSEM_ACTIVE_BIAS)!=0) {
- rwsemdebug("[%d] rwsem_wake: abort wakeup due to renewed activity\n",current->pid);
+ rwsemtrace(sem,"rwsem_wake: abort wakeup due to renewed activity");
goto out;
}
rwsem_atomic_update(woken,sem);
out:
- rwsemdebug("[%d] Leaving rwsem_wake(%08lx)\n",current->pid,sem->count);
+ rwsemtrace(sem,"Leaving rwsem_wake");
return sem;
/* come here if we need to correct the counter for odd SMP-isms */
counter_correction:
count = rwsem_atomic_update(-RWSEM_ACTIVE_BIAS,sem);
- rwsemdebug("[%d] corrected(%08lx)\n",current->pid,count);
+ rwsemtrace(sem,"corrected count");
if (!(count & RWSEM_ACTIVE_MASK))
goto try_again;
goto out;
* sprintf - Format a string and place it in a buffer
* @buf: The buffer to place the result into
* @fmt: The format string to use
- * @args: Arguments for the format string
+ * @...: Arguments for the format string
*/
int sprintf(char * buf, const char *fmt, ...)
{
preferred = 0;
goto restart_scan;
}
+ return NULL;
found:
if (start >= eidx)
BUG();
/*
* Whoops, we cannot satisfy the allocation request.
*/
- BUG();
+ printk(KERN_ALERT "bootmem alloc of %lu bytes failed!\n", size);
+ panic("Out of memory");
return NULL;
}
unsigned long written;
long status;
int err;
+ unsigned bytes;
cached_page = NULL;
if (!access_ok(VERIFY_READ, buf, count))
return -EFAULT;
-
+
down(&inode->i_sem);
pos = *ppos;
* Check whether we've reached the file size limit.
*/
err = -EFBIG;
+
if (limit != RLIM_INFINITY) {
if (pos >= limit) {
send_sig(SIGXFSZ, current, 0);
goto out;
}
- if (count > limit - pos) {
+ if (pos > 0xFFFFFFFFULL || count > limit - (u32)pos) {
+ /* send_sig(SIGXFSZ, current, 0); */
+ count = limit - (u32)pos;
+ }
+ }
+
+ /*
+ * LFS rule
+ */
+ if ( pos + count > MAX_NON_LFS && !(file->f_flags&O_LARGEFILE)) {
+ if (pos >= MAX_NON_LFS) {
send_sig(SIGXFSZ, current, 0);
- count = limit - pos;
+ goto out;
+ }
+ if (count > MAX_NON_LFS - (u32)pos) {
+ /* send_sig(SIGXFSZ, current, 0); */
+ count = MAX_NON_LFS - (u32)pos;
}
}
- status = 0;
- if (count) {
- remove_suid(inode);
- inode->i_ctime = inode->i_mtime = CURRENT_TIME;
- mark_inode_dirty_sync(inode);
+ /*
+ * Are we about to exceed the fs block limit ?
+ *
+ * If we have written data it becomes a short write
+ * If we have exceeded without writing data we send
+ * a signal and give them an EFBIG.
+ *
+ * Linus frestrict idea will clean these up nicely..
+ */
+
+ if (pos > inode->i_sb->s_maxbytes)
+ {
+ send_sig(SIGXFSZ, current, 0);
+ err = -EFBIG;
+ goto out;
}
+ if (pos + count > inode->i_sb->s_maxbytes)
+ count = inode->i_sb->s_maxbytes - pos;
+
+ if (count == 0) {
+ err = 0;
+ goto out;
+ }
+
+ status = 0;
+ remove_suid(inode);
+ inode->i_ctime = inode->i_mtime = CURRENT_TIME;
+ mark_inode_dirty_sync(inode);
+
while (count) {
- unsigned long bytes, index, offset;
+ unsigned long index, offset;
char *kaddr;
int deactivate = 1;
addr = vma->vm_end;
}
}
+#else
+extern unsigned long arch_get_unmapped_area(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
#endif
unsigned long get_unmapped_area(struct file *file, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags)
{
char tmpbuf[20], *p, c;
unsigned int value;
- int left, len;
+ size_t left, len;
if ((file->f_pos && !write) || !*lenp) {
*lenp = 0;