which is also the spinlock that page stealers use to protect changes to
the victim process' ptes. Thus we have a reduction in the total number
of locks.
+
+swap_list_lock/swap_device_lock
+-------------------------------
+The swap devices are chained in priority order from the "swap_list" header.
+The "swap_list" is used for the round-robin swaphandle allocation strategy.
+The #free swaphandles is maintained in "nr_swap_pages". These two together
+are protected by the swap_list_lock.
+
+The swap_device_lock, which is per swap device, protects the reference
+counts on the corresponding swaphandles, maintained in the "swap_map"
+array, and the "highest_bit" and "lowest_bit" fields.
+
+Both of these are spinlocks, and are never acquired from intr level. The
+locking heirarchy is swap_list_lock -> swap_device_lock.
+
+To prevent races between swap space deletion or async readahead swapins
+deciding whether a swap handle is being used, ie worthy of being read in
+from disk, and an unmap -> swap_free making the handle unused, the swap
+delete and readahead code grabs a temp reference on the swaphandle to
+prevent warning messages from swap_duplicate <- read_swap_cache_async.
+
O_TARGET := kernel.o
O_OBJS := entry.o traps.o process.o osf_sys.o irq.o signal.o setup.o \
- ptrace.o time.o fpreg.o semaphore.o
+ ptrace.o time.o semaphore.o
OX_OBJS := alpha_ksyms.o
EXPORT_SYMBOL(wrusp);
EXPORT_SYMBOL(start_thread);
EXPORT_SYMBOL(alpha_read_fp_reg);
+EXPORT_SYMBOL(alpha_read_fp_reg_s);
EXPORT_SYMBOL(alpha_write_fp_reg);
+EXPORT_SYMBOL(alpha_write_fp_reg_s);
/* In-kernel system calls. */
EXPORT_SYMBOL(kernel_thread);
static int
mcpcia_read_config_byte(struct pci_dev *dev, int where, u8 *value)
{
- struct pci_controler *hose = dev->sysdata ? : probing_hose;
+ struct pci_controler *hose = dev->sysdata;
unsigned long addr, w;
unsigned char type1;
static int
mcpcia_read_config_word(struct pci_dev *dev, int where, u16 *value)
{
- struct pci_controler *hose = dev->sysdata ? : probing_hose;
+ struct pci_controler *hose = dev->sysdata;
unsigned long addr, w;
unsigned char type1;
static int
mcpcia_read_config_dword(struct pci_dev *dev, int where, u32 *value)
{
- struct pci_controler *hose = dev->sysdata ? : probing_hose;
+ struct pci_controler *hose = dev->sysdata;
unsigned long addr;
unsigned char type1;
static int
mcpcia_write_config(struct pci_dev *dev, int where, u32 value, long mask)
{
- struct pci_controler *hose = dev->sysdata ? : probing_hose;
+ struct pci_controler *hose = dev->sysdata;
unsigned long addr;
unsigned char type1;
int TSUNAMI_bootcpu;
+static struct
+{
+ unsigned long wsba[4];
+ unsigned long wsm[4];
+ unsigned long tba[4];
+} saved_pchip[2];
+
/*
* NOTE: Herein lie back-to-back mb instructions. They are magic.
* One plausible explanation is that the I/O controller does not properly
mk_conf_addr(struct pci_dev *dev, int where, unsigned long *pci_addr,
unsigned char *type1)
{
- struct pci_controler *hose = dev->sysdata ? : probing_hose;
+ struct pci_controler *hose = dev->sysdata;
unsigned long addr;
u8 bus = dev->bus->number;
u8 device_fn = dev->devfn;
hose->index = index;
hose->io_space->start = TSUNAMI_IO(index) - TSUNAMI_IO_BIAS;
- hose->io_space->end = hose->io_space->start + 0xffff;
+ hose->io_space->end = hose->io_space->start + TSUNAMI_IO_SPACE - 1;
hose->io_space->name = pci_io_names[index];
hose->io_space->flags = IORESOURCE_IO;
if (request_resource(&iomem_resource, hose->mem_space) < 0)
printk(KERN_ERR "Failed to request MEM on hose %d\n", index);
+ /*
+ * Save the existing PCI window translations. SRM will
+ * need them when we go to reboot.
+ */
+
+ saved_pchip[index].wsba[0] = pchip->wsba[0].csr;
+ saved_pchip[index].wsm[0] = pchip->wsm[0].csr;
+ saved_pchip[index].tba[0] = pchip->tba[0].csr;
+
+ saved_pchip[index].wsba[1] = pchip->wsba[1].csr;
+ saved_pchip[index].wsm[1] = pchip->wsm[1].csr;
+ saved_pchip[index].tba[1] = pchip->tba[1].csr;
+
+ saved_pchip[index].wsba[2] = pchip->wsba[2].csr;
+ saved_pchip[index].wsm[2] = pchip->wsm[2].csr;
+ saved_pchip[index].tba[2] = pchip->tba[2].csr;
+
+ saved_pchip[index].wsba[3] = pchip->wsba[3].csr;
+ saved_pchip[index].wsm[3] = pchip->wsm[3].csr;
+ saved_pchip[index].tba[3] = pchip->tba[3].csr;
+
/*
* Set up the PCI->physical memory translation windows.
* For now, windows 1,2 and 3 are disabled. In the future,
tsunami_init_one_pchip(TSUNAMI_pchip1, 1);
}
+static void
+tsunami_kill_one_pchip(tsunami_pchip *pchip, int index)
+{
+ pchip->wsba[0].csr = saved_pchip[index].wsba[0];
+ pchip->wsm[0].csr = saved_pchip[index].wsm[0];
+ pchip->tba[0].csr = saved_pchip[index].tba[0];
+
+ pchip->wsba[1].csr = saved_pchip[index].wsba[1];
+ pchip->wsm[1].csr = saved_pchip[index].wsm[1];
+ pchip->tba[1].csr = saved_pchip[index].tba[1];
+
+ pchip->wsba[2].csr = saved_pchip[index].wsba[2];
+ pchip->wsm[2].csr = saved_pchip[index].wsm[2];
+ pchip->tba[2].csr = saved_pchip[index].tba[2];
+
+ pchip->wsba[3].csr = saved_pchip[index].wsba[3];
+ pchip->wsm[3].csr = saved_pchip[index].wsm[3];
+ pchip->tba[3].csr = saved_pchip[index].tba[3];
+}
+
+void
+tsunami_kill_arch(int mode)
+{
+ tsunami_kill_one_pchip(TSUNAMI_pchip0, 0);
+ if (TSUNAMI_cchip->csc.csr & 1L<<14)
+ tsunami_kill_one_pchip(TSUNAMI_pchip1, 1);
+}
+
static inline void
tsunami_pci_clr_err_1(tsunami_pchip *pchip)
{
+++ /dev/null
-/*
- * arch/alpha/kernel/fpreg.c
- *
- * (C) Copyright 1998 Linus Torvalds
- */
-
-#if defined(__alpha_cix__) || defined(__alpha_fix__)
-#define STT(reg,val) asm volatile ("ftoit $f"#reg",%0" : "=r"(val));
-#else
-#define STT(reg,val) asm volatile ("stt $f"#reg",%0" : "=m"(val));
-#endif
-
-unsigned long
-alpha_read_fp_reg (unsigned long reg)
-{
- unsigned long val;
-
- switch (reg) {
- case 0: STT( 0, val); break;
- case 1: STT( 1, val); break;
- case 2: STT( 2, val); break;
- case 3: STT( 3, val); break;
- case 4: STT( 4, val); break;
- case 5: STT( 5, val); break;
- case 6: STT( 6, val); break;
- case 7: STT( 7, val); break;
- case 8: STT( 8, val); break;
- case 9: STT( 9, val); break;
- case 10: STT(10, val); break;
- case 11: STT(11, val); break;
- case 12: STT(12, val); break;
- case 13: STT(13, val); break;
- case 14: STT(14, val); break;
- case 15: STT(15, val); break;
- case 16: STT(16, val); break;
- case 17: STT(17, val); break;
- case 18: STT(18, val); break;
- case 19: STT(19, val); break;
- case 20: STT(20, val); break;
- case 21: STT(21, val); break;
- case 22: STT(22, val); break;
- case 23: STT(23, val); break;
- case 24: STT(24, val); break;
- case 25: STT(25, val); break;
- case 26: STT(26, val); break;
- case 27: STT(27, val); break;
- case 28: STT(28, val); break;
- case 29: STT(29, val); break;
- case 30: STT(30, val); break;
- case 31: STT(31, val); break;
- }
- return val;
-}
-
-#if defined(__alpha_cix__) || defined(__alpha_fix__)
-#define LDT(reg,val) asm volatile ("itoft %0,$f"#reg : : "r"(val));
-#else
-#define LDT(reg,val) asm volatile ("ldt $f"#reg",%0" : : "m"(val));
-#endif
-
-void
-alpha_write_fp_reg (unsigned long reg, unsigned long val)
-{
- switch (reg) {
- case 0: LDT( 0, val); break;
- case 1: LDT( 1, val); break;
- case 2: LDT( 2, val); break;
- case 3: LDT( 3, val); break;
- case 4: LDT( 4, val); break;
- case 5: LDT( 5, val); break;
- case 6: LDT( 6, val); break;
- case 7: LDT( 7, val); break;
- case 8: LDT( 8, val); break;
- case 9: LDT( 9, val); break;
- case 10: LDT(10, val); break;
- case 11: LDT(11, val); break;
- case 12: LDT(12, val); break;
- case 13: LDT(13, val); break;
- case 14: LDT(14, val); break;
- case 15: LDT(15, val); break;
- case 16: LDT(16, val); break;
- case 17: LDT(17, val); break;
- case 18: LDT(18, val); break;
- case 19: LDT(19, val); break;
- case 20: LDT(20, val); break;
- case 21: LDT(21, val); break;
- case 22: LDT(22, val); break;
- case 23: LDT(23, val); break;
- case 24: LDT(24, val); break;
- case 25: LDT(25, val); break;
- case 26: LDT(26, val); break;
- case 27: LDT(27, val); break;
- case 28: LDT(28, val); break;
- case 29: LDT(29, val); break;
- case 30: LDT(30, val); break;
- case 31: LDT(31, val); break;
- }
-}
static void show(char * str, void *where);
-#define SYNC_OTHER_CPUS(x) udelay((x)+1);
-
static inline void
wait_on_irq(int cpu, void *where)
{
/* Duh, we have to loop. Release the lock to avoid deadlocks */
spin_unlock(&global_irq_lock);
- mb();
for (;;) {
if (!--count) {
count = MAXCOUNT;
}
__sti();
- SYNC_OTHER_CPUS(cpu);
+ udelay(1); /* make sure to run pending irqs */
__cli();
if (atomic_read(&global_irq_count))
*/
struct pci_controler *hose_head, **hose_tail = &hose_head;
-struct pci_controler *probing_hose;
/*
* Quirks.
{
/* Propogate hose info into the subordinate devices. */
- struct pci_controler *hose = probing_hose;
+ struct pci_controler *hose = (struct pci_controler *) bus->sysdata;
struct pci_dev *dev;
bus->resource[0] = hose->io_space;
bus->resource[1] = hose->mem_space;
for (dev = bus->devices; dev; dev = dev->sibling) {
- dev->sysdata = hose;
if ((dev->class >> 8) != PCI_CLASS_BRIDGE_PCI)
pcibios_fixup_device_resources(dev, bus);
}
for (next_busno = 0, hose = hose_head; hose; hose = hose->next) {
hose->first_busno = next_busno;
hose->last_busno = 0xff;
- probing_hose = hose;
bus = pci_scan_bus(next_busno, alpha_mv.pci_ops, hose);
hose->bus = bus;
next_busno = hose->last_busno = bus->subordinate;
next_busno += 1;
}
- probing_hose = NULL;
pci_assign_unassigned_resources(alpha_mv.min_io_address,
alpha_mv.min_mem_address);
/* The hose list. */
extern struct pci_controler *hose_head, **hose_tail;
-extern struct pci_controler *probing_hose;
extern void common_init_pci(void);
extern u8 common_swizzle(struct pci_dev *, u8 *);
}
}
-void
-common_kill_arch (int mode, char *restart_cmd)
+static void
+common_shutdown(int mode, char *restart_cmd)
{
/* The following currently only has any effect on SRM. We should
fix MILO to understand it. Should be pretty easy. Also we can
rtc_kill_pit();
#endif
+ if (alpha_mv.kill_arch)
+ alpha_mv.kill_arch(mode);
+
if (!alpha_using_srm && mode != LINUX_REBOOT_CMD_RESTART) {
/* Unfortunately, since MILO doesn't currently understand
the hwrpb bits above, we can't reliably halt the
void
machine_restart(char *restart_cmd)
{
- alpha_mv.kill_arch(LINUX_REBOOT_CMD_RESTART, restart_cmd);
+ common_shutdown(LINUX_REBOOT_CMD_RESTART, restart_cmd);
}
void
machine_halt(void)
{
- alpha_mv.kill_arch(LINUX_REBOOT_CMD_HALT, NULL);
+ common_shutdown(LINUX_REBOOT_CMD_HALT, NULL);
}
-void machine_power_off(void)
+void
+machine_power_off(void)
{
- alpha_mv.kill_arch(LINUX_REBOOT_CMD_POWER_OFF, NULL);
+ common_shutdown(LINUX_REBOOT_CMD_POWER_OFF, NULL);
}
-void show_regs(struct pt_regs * regs)
+void
+show_regs(struct pt_regs * regs)
{
printk("\nps: %04lx pc: [<%016lx>]\n", regs->ps, regs->pc);
printk("rp: [<%016lx>] sp: %p\n", regs->r26, regs+1);
/*
* Re-start a thread when doing execve()
*/
-void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp)
+void
+start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp)
{
set_fs(USER_DS);
regs->pc = pc;
/*
* Free current thread data structures etc..
*/
-void exit_thread(void)
+void
+exit_thread(void)
{
}
-void flush_thread(void)
+void
+flush_thread(void)
{
/* Arrange for each exec'ed process to start off with a clean slate
with respect to the FPU. This is all exceptions disabled. Note
wrfpcr(FPCR_DYN_NORMAL | FPCR_INVD | FPCR_DZED | FPCR_OVFD | FPCR_INED);
}
-void release_thread(struct task_struct *dead_task)
+void
+release_thread(struct task_struct *dead_task)
{
}
* Notice that "fork()" is implemented in terms of clone,
* with parameters (SIGCHLD, 0).
*/
-int alpha_clone(unsigned long clone_flags, unsigned long usp,
- struct switch_stack * swstack)
+int
+alpha_clone(unsigned long clone_flags, unsigned long usp,
+ struct switch_stack * swstack)
{
if (!usp)
usp = rdusp();
return do_fork(clone_flags, usp, (struct pt_regs *) (swstack+1));
}
-int alpha_vfork(struct switch_stack * swstack)
+int
+alpha_vfork(struct switch_stack * swstack)
{
return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(),
(struct pt_regs *) (swstack+1));
* for a kernel fork().
*/
-int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
- struct task_struct * p, struct pt_regs * regs)
+int
+copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
+ struct task_struct * p, struct pt_regs * regs)
{
extern void ret_from_sys_call(void);
extern void ret_from_smp_fork(void);
/*
* fill in the user structure for a core dump..
*/
-void dump_thread(struct pt_regs * pt, struct user * dump)
+void
+dump_thread(struct pt_regs * pt, struct user * dump)
{
/* switch stack follows right below pt_regs: */
struct switch_stack * sw = ((struct switch_stack *) pt) - 1;
memcpy((char *)dump->regs + EF_SIZE, sw->fp, 32 * 8);
}
-int dump_fpu (struct pt_regs * regs, elf_fpregset_t *r)
+int
+dump_fpu(struct pt_regs * regs, elf_fpregset_t *r)
{
/* switch stack follows right below pt_regs: */
struct switch_stack * sw = ((struct switch_stack *) regs) - 1;
*
* Don't do this at home.
*/
-asmlinkage int sys_execve(unsigned long a0, unsigned long a1, unsigned long a2,
+asmlinkage int
+sys_execve(unsigned long a0, unsigned long a1, unsigned long a2,
unsigned long a3, unsigned long a4, unsigned long a5,
struct pt_regs regs)
{
#define first_sched ((unsigned long) scheduling_functions_start_here)
#define last_sched ((unsigned long) scheduling_functions_end_here)
-unsigned long get_wchan(struct task_struct *p)
+unsigned long
+get_wchan(struct task_struct *p)
{
unsigned long schedule_frame;
unsigned long pc;
/* core_tsunami.c */
extern struct pci_ops tsunami_pci_ops;
extern void tsunami_init_arch(void);
+extern void tsunami_kill_arch(int);
extern void tsunami_machine_check(u64, u64, struct pt_regs *);
/* setup.c */
extern void entDbg(void);
/* process.c */
-extern void common_kill_arch (int mode, char *reboot_cmd);
extern void cpu_idle(void) __attribute__((noreturn));
/* ptrace.c */
}
#endif /* CONFIG_BLK_DEV_INITRD */
}
+
+int __init page_is_ram(unsigned long pfn)
+{
+ struct memclust_struct * cluster;
+ struct memdesc_struct * memdesc;
+ int i;
+
+ memdesc = (struct memdesc_struct *) (hwrpb->mddt_offset + (unsigned long) hwrpb);
+ for_each_mem_cluster(memdesc, cluster, i)
+ {
+ if (pfn >= cluster->start_pfn &&
+ pfn < cluster->start_pfn + cluster->numpages)
+ {
+ if (cluster->usage & 3)
+ return 0;
+ else
+ return 1;
+ }
+ }
+
+ return 0;
+}
#undef PFN_UP
#undef PFN_DOWN
#undef PFN_PHYS
return 0;
}
+static int __init fork_by_hand(void)
+{
+ struct pt_regs regs;
+ /*
+ * don't care about the regs settings since
+ * we'll never reschedule the forked task.
+ */
+ return do_fork(CLONE_VM|CLONE_PID, 0, ®s);
+}
+
/*
* Bring one cpu online.
*/
to kernel_thread is irrelevant -- it's going to start where
HWRPB.CPU_restart says to start. But this gets all the other
task-y sort of data structures set up like we wish. */
- kernel_thread((void *)__smp_callin, NULL, CLONE_PID|CLONE_VM);
+ /*
+ * We can't use kernel_thread since we must avoid to
+ * reschedule the child.
+ */
+ if (fork_by_hand() < 0)
+ panic("failed fork for CPU %d", cpuid);
idle = init_task.prev_task;
if (!idle)
- panic("No idle process for CPU %d", cpunum);
- del_from_runqueue(idle);
- init_tasks[cpunum] = idle;
- idle->processor = cpuid;
+ panic("No idle process for CPU %d", cpuid);
- /* Schedule the first task manually. */
- /* ??? Ingo, what is this? */
- idle->has_cpu = 1;
+ idle->processor = cpuid;
+ __cpu_logical_map[cpunum] = cpuid;
+ cpu_number_map[cpuid] = cpunum;
+ idle->has_cpu = 1; /* we schedule the first task manually */
+
+ del_from_runqueue(idle);
+ unhash_process(idle);
+ init_tasks[cpunum] = idle;
DBGS(("smp_boot_one_cpu: CPU %d state 0x%lx flags 0x%lx\n",
cpuid, idle->state, idle->flags));
barrier();
}
+ /* we must invalidate our stuff as we failed to boot the CPU */
+ __cpu_logical_map[cpunum] = -1;
+ cpu_number_map[cpuid] = -1;
+
+ /* the idle task is local to us so free it as we don't use it */
+ free_task_struct(idle);
+
printk(KERN_ERR "SMP: Processor %d is stuck.\n", cpuid);
return -1;
alive:
/* Another "Red Snapper". */
- cpu_number_map[cpuid] = cpunum;
- __cpu_logical_map[cpunum] = cpuid;
return 0;
}
mb();
}
-/*
- * Only broken Intel needs this, thus it should not even be
- * referenced globally.
- */
-
-void __init
-initialize_secondary(void)
-{
-}
-
\f
extern void update_one_process(struct task_struct *p, unsigned long ticks,
unsigned long user, unsigned long system,
}
static void
-alcor_kill_arch(int mode, char *reboot_cmd)
+alcor_kill_arch(int mode)
{
/* Who said DEC engineer's have no sense of humor? ;-) */
if (alpha_using_srm) {
*(vuip) GRU_RESET = 0x0000dead;
mb();
}
-
- common_kill_arch(mode, reboot_cmd);
}
init_irq: cabriolet_init_irq,
init_pit: common_init_pit,
init_pci: cabriolet_init_pci,
- kill_arch: common_kill_arch,
+ kill_arch: NULL,
pci_map_irq: cabriolet_map_irq,
pci_swizzle: common_swizzle,
};
init_irq: dp264_init_irq,
init_pit: common_init_pit,
init_pci: dp264_init_pci,
- kill_arch: common_kill_arch,
+ kill_arch: tsunami_kill_arch,
pci_map_irq: dp264_map_irq,
pci_swizzle: common_swizzle,
};
init_irq: dp264_init_irq,
init_pit: common_init_pit,
init_pci: monet_init_pci,
- kill_arch: common_kill_arch,
+ kill_arch: tsunami_kill_arch,
pci_map_irq: monet_map_irq,
pci_swizzle: monet_swizzle,
};
init_irq: dp264_init_irq,
init_pit: common_init_pit,
init_pci: common_init_pci,
- kill_arch: common_kill_arch,
+ kill_arch: tsunami_kill_arch,
pci_map_irq: webbrick_map_irq,
pci_swizzle: common_swizzle,
};
init_irq: clipper_init_irq,
init_pit: common_init_pit,
init_pci: common_init_pci,
- kill_arch: common_kill_arch,
+ kill_arch: tsunami_kill_arch,
pci_map_irq: clipper_map_irq,
pci_swizzle: common_swizzle,
};
init_irq: eb64p_init_irq,
init_pit: common_init_pit,
init_pci: common_init_pci,
- kill_arch: common_kill_arch,
+ kill_arch: NULL,
pci_map_irq: eb64p_map_irq,
pci_swizzle: common_swizzle,
};
init_irq: eiger_init_irq,
init_pit: common_init_pit,
init_pci: common_init_pci,
- kill_arch: common_kill_arch,
+ kill_arch: tsunami_kill_arch,
pci_map_irq: eiger_map_irq,
pci_swizzle: eiger_swizzle,
};
init_irq: jensen_init_irq,
init_pit: common_init_pit,
init_pci: NULL,
- kill_arch: common_kill_arch,
+ kill_arch: NULL,
};
ALIAS_MV(jensen)
}
static void
-miata_kill_arch (int mode, char *reboot_cmd)
+miata_kill_arch(int mode)
{
/* Who said DEC engineers have no sense of humor? ;-) */
if (alpha_using_srm) {
*(vuip) PYXIS_RESET = 0x0000dead;
mb();
}
- common_kill_arch(mode, reboot_cmd);
}
init_irq: mikasa_init_irq,
init_pit: common_init_pit,
init_pci: common_init_pci,
- kill_arch: common_kill_arch,
+ kill_arch: NULL,
pci_map_irq: mikasa_map_irq,
pci_swizzle: common_swizzle,
};
}
void
-nautilus_kill_arch (int mode, char *restart_cmd)
+nautilus_kill_arch(int mode)
{
u8 tmp;
-#ifdef CONFIG_RTC
- rtc_kill_pit();
-#endif
-
- switch(mode) {
- case LINUX_REBOOT_CMD_HALT:
- printk("Press Reset bottun");
- break;
- case LINUX_REBOOT_CMD_RESTART:
+ if (mode == LINUX_REBOOT_CMD_RESTART) {
pcibios_read_config_byte(0, 0x38, 0x43, &tmp);
pcibios_write_config_byte(0, 0x38, 0x43, tmp | 0x80);
outb(1, 0x92);
outb(0, 0x92);
- printk("Press Reset button");
- break;
- case LINUX_REBOOT_CMD_POWER_OFF:
}
-
- while (1);
}
/* Machine check handler code
init_irq: noritake_init_irq,
init_pit: common_init_pit,
init_pci: common_init_pci,
- kill_arch: common_kill_arch,
+ kill_arch: NULL,
pci_map_irq: noritake_map_irq,
pci_swizzle: noritake_swizzle,
};
init_irq: rawhide_init_irq,
init_pit: common_init_pit,
init_pci: common_init_pci,
- kill_arch: common_kill_arch,
+ kill_arch: NULL,
pci_map_irq: rawhide_map_irq,
pci_swizzle: common_swizzle,
};
}
static void
-ruffian_kill_arch (int mode, char *reboot_cmd)
+ruffian_kill_arch (int mode)
{
#if 0
- /* this only causes re-entry to ARCSBIOS */
+ /* This only causes re-entry to ARCSBIOS */
/* Perhaps this works for other PYXIS as well? */
*(vuip) PYXIS_RESET = 0x0000dead;
mb();
#endif
- common_kill_arch(mode, reboot_cmd);
}
static int __init
init_irq: rx164_init_irq,
init_pit: common_init_pit,
init_pci: common_init_pci,
- kill_arch: common_kill_arch,
+ kill_arch: NULL,
pci_map_irq: rx164_map_irq,
pci_swizzle: common_swizzle,
};
init_irq: sable_init_irq,
init_pit: common_init_pit,
init_pci: common_init_pci,
- kill_arch: common_kill_arch,
+ kill_arch: NULL,
pci_map_irq: sable_map_irq,
pci_swizzle: common_swizzle,
init_irq: sio_init_irq,
init_pit: common_init_pit,
init_pci: alphabook1_init_pci,
- kill_arch: common_kill_arch,
+ kill_arch: NULL,
pci_map_irq: noname_map_irq,
pci_swizzle: common_swizzle,
init_irq: sx164_init_irq,
init_pit: common_init_pit,
init_pci: sx164_init_pci,
- kill_arch: common_kill_arch,
+ kill_arch: NULL,
pci_map_irq: sx164_map_irq,
pci_swizzle: common_swizzle,
};
init_irq: takara_init_irq,
init_pit: common_init_pit,
init_pci: takara_init_pci,
- kill_arch: common_kill_arch,
+ kill_arch: NULL,
pci_map_irq: takara_map_irq,
pci_swizzle: takara_swizzle,
};
}
#ifndef CONFIG_MATHEMU
-static long dummy_emul() { return 0; }
+static long dummy_emul(void) { return 0; }
long (*alpha_fp_emul_imprecise)(struct pt_regs *regs, unsigned long writemask)
= (void *)dummy_emul;
long (*alpha_fp_emul) (unsigned long pc)
strcat.o strcpy.o strncat.o strncpy.o stxcpy.o stxncpy.o \
strchr.o strrchr.o memchr.o \
copy_user.o clear_user.o strncpy_from_user.o strlen_user.o \
- csum_ipv6_magic.o strcasecmp.o semaphore.o \
+ csum_ipv6_magic.o strcasecmp.o semaphore.o fpreg.o \
srm_dispatch.o srm_fixup.o srm_puts.o srm_printk.o
lib.a: $(OBJS)
--- /dev/null
+/*
+ * arch/alpha/lib/fpreg.c
+ *
+ * (C) Copyright 1998 Linus Torvalds
+ */
+
+#if defined(__alpha_cix__) || defined(__alpha_fix__)
+#define STT(reg,val) asm volatile ("ftoit $f"#reg",%0" : "=r"(val));
+#else
+#define STT(reg,val) asm volatile ("stt $f"#reg",%0" : "=m"(val));
+#endif
+
+unsigned long
+alpha_read_fp_reg (unsigned long reg)
+{
+ unsigned long val;
+
+ switch (reg) {
+ case 0: STT( 0, val); break;
+ case 1: STT( 1, val); break;
+ case 2: STT( 2, val); break;
+ case 3: STT( 3, val); break;
+ case 4: STT( 4, val); break;
+ case 5: STT( 5, val); break;
+ case 6: STT( 6, val); break;
+ case 7: STT( 7, val); break;
+ case 8: STT( 8, val); break;
+ case 9: STT( 9, val); break;
+ case 10: STT(10, val); break;
+ case 11: STT(11, val); break;
+ case 12: STT(12, val); break;
+ case 13: STT(13, val); break;
+ case 14: STT(14, val); break;
+ case 15: STT(15, val); break;
+ case 16: STT(16, val); break;
+ case 17: STT(17, val); break;
+ case 18: STT(18, val); break;
+ case 19: STT(19, val); break;
+ case 20: STT(20, val); break;
+ case 21: STT(21, val); break;
+ case 22: STT(22, val); break;
+ case 23: STT(23, val); break;
+ case 24: STT(24, val); break;
+ case 25: STT(25, val); break;
+ case 26: STT(26, val); break;
+ case 27: STT(27, val); break;
+ case 28: STT(28, val); break;
+ case 29: STT(29, val); break;
+ case 30: STT(30, val); break;
+ case 31: STT(31, val); break;
+ }
+ return val;
+}
+
+#if defined(__alpha_cix__) || defined(__alpha_fix__)
+#define LDT(reg,val) asm volatile ("itoft %0,$f"#reg : : "r"(val));
+#else
+#define LDT(reg,val) asm volatile ("ldt $f"#reg",%0" : : "m"(val));
+#endif
+
+void
+alpha_write_fp_reg (unsigned long reg, unsigned long val)
+{
+ switch (reg) {
+ case 0: LDT( 0, val); break;
+ case 1: LDT( 1, val); break;
+ case 2: LDT( 2, val); break;
+ case 3: LDT( 3, val); break;
+ case 4: LDT( 4, val); break;
+ case 5: LDT( 5, val); break;
+ case 6: LDT( 6, val); break;
+ case 7: LDT( 7, val); break;
+ case 8: LDT( 8, val); break;
+ case 9: LDT( 9, val); break;
+ case 10: LDT(10, val); break;
+ case 11: LDT(11, val); break;
+ case 12: LDT(12, val); break;
+ case 13: LDT(13, val); break;
+ case 14: LDT(14, val); break;
+ case 15: LDT(15, val); break;
+ case 16: LDT(16, val); break;
+ case 17: LDT(17, val); break;
+ case 18: LDT(18, val); break;
+ case 19: LDT(19, val); break;
+ case 20: LDT(20, val); break;
+ case 21: LDT(21, val); break;
+ case 22: LDT(22, val); break;
+ case 23: LDT(23, val); break;
+ case 24: LDT(24, val); break;
+ case 25: LDT(25, val); break;
+ case 26: LDT(26, val); break;
+ case 27: LDT(27, val); break;
+ case 28: LDT(28, val); break;
+ case 29: LDT(29, val); break;
+ case 30: LDT(30, val); break;
+ case 31: LDT(31, val); break;
+ }
+}
+
+#if defined(__alpha_cix__) || defined(__alpha_fix__)
+#define STS(reg,val) asm volatile ("ftois $f"#reg",%0" : "=r"(val));
+#else
+#define STS(reg,val) asm volatile ("sts $f"#reg",%0" : "=m"(val));
+#endif
+
+unsigned long
+alpha_read_fp_reg_s (unsigned long reg)
+{
+ unsigned long val;
+
+ switch (reg) {
+ case 0: STS( 0, val); break;
+ case 1: STS( 1, val); break;
+ case 2: STS( 2, val); break;
+ case 3: STS( 3, val); break;
+ case 4: STS( 4, val); break;
+ case 5: STS( 5, val); break;
+ case 6: STS( 6, val); break;
+ case 7: STS( 7, val); break;
+ case 8: STS( 8, val); break;
+ case 9: STS( 9, val); break;
+ case 10: STS(10, val); break;
+ case 11: STS(11, val); break;
+ case 12: STS(12, val); break;
+ case 13: STS(13, val); break;
+ case 14: STS(14, val); break;
+ case 15: STS(15, val); break;
+ case 16: STS(16, val); break;
+ case 17: STS(17, val); break;
+ case 18: STS(18, val); break;
+ case 19: STS(19, val); break;
+ case 20: STS(20, val); break;
+ case 21: STS(21, val); break;
+ case 22: STS(22, val); break;
+ case 23: STS(23, val); break;
+ case 24: STS(24, val); break;
+ case 25: STS(25, val); break;
+ case 26: STS(26, val); break;
+ case 27: STS(27, val); break;
+ case 28: STS(28, val); break;
+ case 29: STS(29, val); break;
+ case 30: STS(30, val); break;
+ case 31: STS(31, val); break;
+ }
+ return val;
+}
+
+#if defined(__alpha_cix__) || defined(__alpha_fix__)
+#define LDS(reg,val) asm volatile ("itofs %0,$f"#reg : : "r"(val));
+#else
+#define LDS(reg,val) asm volatile ("lds $f"#reg",%0" : : "m"(val));
+#endif
+
+void
+alpha_write_fp_reg_s (unsigned long reg, unsigned long val)
+{
+ switch (reg) {
+ case 0: LDS( 0, val); break;
+ case 1: LDS( 1, val); break;
+ case 2: LDS( 2, val); break;
+ case 3: LDS( 3, val); break;
+ case 4: LDS( 4, val); break;
+ case 5: LDS( 5, val); break;
+ case 6: LDS( 6, val); break;
+ case 7: LDS( 7, val); break;
+ case 8: LDS( 8, val); break;
+ case 9: LDS( 9, val); break;
+ case 10: LDS(10, val); break;
+ case 11: LDS(11, val); break;
+ case 12: LDS(12, val); break;
+ case 13: LDS(13, val); break;
+ case 14: LDS(14, val); break;
+ case 15: LDS(15, val); break;
+ case 16: LDS(16, val); break;
+ case 17: LDS(17, val); break;
+ case 18: LDS(18, val); break;
+ case 19: LDS(19, val); break;
+ case 20: LDS(20, val); break;
+ case 21: LDS(21, val); break;
+ case 22: LDS(22, val); break;
+ case 23: LDS(23, val); break;
+ case 24: LDS(24, val); break;
+ case 25: LDS(25, val); break;
+ case 26: LDS(26, val); break;
+ case 27: LDS(27, val); break;
+ case 28: LDS(28, val); break;
+ case 29: LDS(29, val); break;
+ case 30: LDS(30, val); break;
+ case 31: LDS(31, val); break;
+ }
+}
#
-# Makefile for math-emulator files...
+# Makefile for the FPU instruction 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).
+#
+# Note 2! The CFLAGS definition is now in the main makefile...
O_TARGET := math-emu.o
-O_OBJS := fp-emul.o ieee-math.o
+O_OBJS := math.o
+CFLAGS += -I. -I$(TOPDIR)/include/math-emu -w
ifeq ($(CONFIG_MATHEMU),m)
M_OBJS := $(O_TARGET)
+++ /dev/null
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-
-#include <asm/uaccess.h>
-
-#include "ieee-math.h"
-
-#define OPC_PAL 0x00
-
-#define OPC_INTA 0x10
-#define OPC_INTL 0x11
-#define OPC_INTS 0x12
-#define OPC_INTM 0x13
-#define OPC_FLTC 0x14
-#define OPC_FLTV 0x15
-#define OPC_FLTI 0x16
-#define OPC_FLTL 0x17
-
-#define OPC_MISC 0x18
-
-#define OPC_JSR 0x1a
-
-#define OP_FUN(OP,FUN) ((OP << 26) | (FUN << 5))
-
-/*
- * "Base" function codes for the FLTI-class instructions.
- * Note that in most cases these actually correspond to the "chopped"
- * form of the instruction. Not to worry---we extract the qualifier
- * bits separately and deal with them separately. Notice that base
- * function code 0x2c is used for both CVTTS and CVTST. The other bits
- * in the function code are used to distinguish the two.
- */
-#define FLTI_FUNC_ADDS OP_FUN(OPC_FLTI, 0x000)
-#define FLTI_FUNC_ADDT OP_FUN(OPC_FLTI, 0x020)
-#define FLTI_FUNC_CMPTEQ OP_FUN(OPC_FLTI, 0x025)
-#define FLTI_FUNC_CMPTLT OP_FUN(OPC_FLTI, 0x026)
-#define FLTI_FUNC_CMPTLE OP_FUN(OPC_FLTI, 0x027)
-#define FLTI_FUNC_CMPTUN OP_FUN(OPC_FLTI, 0x024)
-#define FLTI_FUNC_CVTTS_or_CVTST OP_FUN(OPC_FLTI, 0x02c)
-#define FLTI_FUNC_CVTTQ OP_FUN(OPC_FLTI, 0x02f)
-#define FLTI_FUNC_CVTQS OP_FUN(OPC_FLTI, 0x03c)
-#define FLTI_FUNC_CVTQT OP_FUN(OPC_FLTI, 0x03e)
-#define FLTI_FUNC_DIVS OP_FUN(OPC_FLTI, 0x003)
-#define FLTI_FUNC_DIVT OP_FUN(OPC_FLTI, 0x023)
-#define FLTI_FUNC_MULS OP_FUN(OPC_FLTI, 0x002)
-#define FLTI_FUNC_MULT OP_FUN(OPC_FLTI, 0x022)
-#define FLTI_FUNC_SUBS OP_FUN(OPC_FLTI, 0x001)
-#define FLTI_FUNC_SUBT OP_FUN(OPC_FLTI, 0x021)
-
-#define FLTC_FUNC_SQRTS OP_FUN(OPC_FLTC, 0x00B)
-#define FLTC_FUNC_SQRTT OP_FUN(OPC_FLTC, 0x02B)
-
-#define FLTL_FUNC_CVTQL OP_FUN(OPC_FLTL, 0x030)
-
-#define MISC_TRAPB 0x0000
-#define MISC_EXCB 0x0400
-
-extern unsigned long alpha_read_fp_reg (unsigned long reg);
-extern void alpha_write_fp_reg (unsigned long reg, unsigned long val);
-
-
-#ifdef MODULE
-
-MODULE_DESCRIPTION("FP Software completion module");
-
-extern long (*alpha_fp_emul_imprecise)(struct pt_regs *, unsigned long);
-extern long (*alpha_fp_emul) (unsigned long pc);
-
-static long (*save_emul_imprecise)(struct pt_regs *, unsigned long);
-static long (*save_emul) (unsigned long pc);
-
-long do_alpha_fp_emul_imprecise(struct pt_regs *, unsigned long);
-long do_alpha_fp_emul(unsigned long);
-
-int init_module(void)
-{
- save_emul_imprecise = alpha_fp_emul_imprecise;
- save_emul = alpha_fp_emul;
- alpha_fp_emul_imprecise = do_alpha_fp_emul_imprecise;
- alpha_fp_emul = do_alpha_fp_emul;
- return 0;
-}
-
-void cleanup_module(void)
-{
- alpha_fp_emul_imprecise = save_emul_imprecise;
- alpha_fp_emul = save_emul;
-}
-
-#undef alpha_fp_emul_imprecise
-#define alpha_fp_emul_imprecise do_alpha_fp_emul_imprecise
-#undef alpha_fp_emul
-#define alpha_fp_emul do_alpha_fp_emul
-
-#endif /* MODULE */
-
-/*
- * Emulate the floating point instruction at address PC. Returns 0 if
- * emulation fails. Notice that the kernel does not and cannot use FP
- * regs. This is good because it means that instead of
- * saving/restoring all fp regs, we simply stick the result of the
- * operation into the appropriate register.
- */
-long
-alpha_fp_emul (unsigned long pc)
-{
- unsigned long op_fun, fa, fb, fc, func, mode;
- unsigned long fpcw = current->thread.flags;
- unsigned long va, vb, vc, res, fpcr;
- __u32 insn;
-
- MOD_INC_USE_COUNT;
-
- get_user(insn, (__u32*)pc);
- fc = (insn >> 0) & 0x1f; /* destination register */
- fb = (insn >> 16) & 0x1f;
- fa = (insn >> 21) & 0x1f;
- func = (insn >> 5) & 0x7ff;
- mode = (insn >> 5) & 0xc0;
- op_fun = insn & OP_FUN(0x3f, 0x3f);
-
- va = alpha_read_fp_reg(fa);
- vb = alpha_read_fp_reg(fb);
- fpcr = rdfpcr();
-
- /*
- * Try the operation in software. First, obtain the rounding
- * mode...
- */
- if (mode == 0xc0) {
- /* dynamic---get rounding mode from fpcr: */
- mode = ((fpcr & FPCR_DYN_MASK) >> FPCR_DYN_SHIFT) << ROUND_SHIFT;
- }
- mode |= (fpcw & IEEE_TRAP_ENABLE_MASK);
-
- if ((IEEE_TRAP_ENABLE_MASK & 0xc0)) {
- extern int something_is_wrong (void);
- something_is_wrong();
- }
-
- switch (op_fun) {
- case FLTI_FUNC_CMPTEQ:
- res = ieee_CMPTEQ(va, vb, &vc);
- break;
-
- case FLTI_FUNC_CMPTLT:
- res = ieee_CMPTLT(va, vb, &vc);
- break;
-
- case FLTI_FUNC_CMPTLE:
- res = ieee_CMPTLE(va, vb, &vc);
- break;
-
- case FLTI_FUNC_CMPTUN:
- res = ieee_CMPTUN(va, vb, &vc);
- break;
-
- case FLTL_FUNC_CVTQL:
- /*
- * Notice: We can get here only due to an integer
- * overflow. Such overflows are reported as invalid
- * ops. We return the result the hw would have
- * computed.
- */
- vc = ((vb & 0xc0000000) << 32 | /* sign and msb */
- (vb & 0x3fffffff) << 29); /* rest of the integer */
- res = FPCR_INV;
- break;
-
- case FLTI_FUNC_CVTQS:
- res = ieee_CVTQS(mode, vb, &vc);
- break;
-
- case FLTI_FUNC_CVTQT:
- res = ieee_CVTQT(mode, vb, &vc);
- break;
-
- case FLTI_FUNC_CVTTS_or_CVTST:
- if (func == 0x6ac) {
- /*
- * 0x2ac is also CVTST, but if the /S
- * qualifier isn't set, we wouldn't be here in
- * the first place...
- */
- res = ieee_CVTST(mode, vb, &vc);
- } else {
- res = ieee_CVTTS(mode, vb, &vc);
- }
- break;
-
- case FLTI_FUNC_DIVS:
- res = ieee_DIVS(mode, va, vb, &vc);
- break;
-
- case FLTI_FUNC_DIVT:
- res = ieee_DIVT(mode, va, vb, &vc);
- break;
-
- case FLTI_FUNC_MULS:
- res = ieee_MULS(mode, va, vb, &vc);
- break;
-
- case FLTI_FUNC_MULT:
- res = ieee_MULT(mode, va, vb, &vc);
- break;
-
- case FLTI_FUNC_SUBS:
- res = ieee_SUBS(mode, va, vb, &vc);
- break;
-
- case FLTI_FUNC_SUBT:
- res = ieee_SUBT(mode, va, vb, &vc);
- break;
-
- case FLTI_FUNC_ADDS:
- res = ieee_ADDS(mode, va, vb, &vc);
- break;
-
- case FLTI_FUNC_ADDT:
- res = ieee_ADDT(mode, va, vb, &vc);
- break;
-
- case FLTI_FUNC_CVTTQ:
- res = ieee_CVTTQ(mode, vb, &vc);
- break;
-
- case FLTC_FUNC_SQRTS:
- res = ieee_SQRTS(mode, vb, &vc);
- break;
-
- case FLTC_FUNC_SQRTT:
- res = ieee_SQRTT(mode, vb, &vc);
- break;
-
- default:
- printk("alpha_fp_emul: unexpected function code %#lx at %#lx\n",
- func & 0x3f, pc);
- MOD_DEC_USE_COUNT;
- return 0;
- }
-
- /*
- * Take the appropriate action for each possible
- * floating-point result:
- *
- * - Set the appropriate bits in the FPCR
- * - If the specified exception is enabled in the FPCR,
- * return. The caller (entArith) will dispatch
- * the appropriate signal to the translated program.
- *
- * In addition, properly track the exception state in software
- * as described in the Alpha Architectre Handbook section 4.7.7.3.
- */
- if (res) {
- /* Record exceptions in software control word. */
- current->thread.flags = fpcw |= res >> 35;
-
- /* Update hardware control register */
- fpcr &= (~FPCR_MASK | FPCR_DYN_MASK);
- fpcr |= ieee_swcr_to_fpcr(fpcw);
- wrfpcr(fpcr);
-
- /* Do we generate a signal? */
- if (res >> 51 & fpcw & IEEE_TRAP_ENABLE_MASK) {
- MOD_DEC_USE_COUNT;
- return 0;
- }
- }
-
- /*
- * Whoo-kay... we got this far, and we're not generating a signal
- * to the translated program. All that remains is to write the
- * result:
- */
- alpha_write_fp_reg(fc, vc);
-
- MOD_DEC_USE_COUNT;
- return 1;
-}
-
-
-long
-alpha_fp_emul_imprecise (struct pt_regs *regs, unsigned long write_mask)
-{
- unsigned long trigger_pc = regs->pc - 4;
- unsigned long insn, opcode, rc;
-
- MOD_INC_USE_COUNT;
-
- /*
- * Turn off the bits corresponding to registers that are the
- * target of instructions that set bits in the exception
- * summary register. We have some slack doing this because a
- * register that is the target of a trapping instruction can
- * be written at most once in the trap shadow.
- *
- * Branches, jumps, TRAPBs, EXCBs and calls to PALcode all
- * bound the trap shadow, so we need not look any further than
- * up to the first occurrence of such an instruction.
- */
- while (write_mask) {
- get_user(insn, (__u32*)(trigger_pc));
- opcode = insn >> 26;
- rc = insn & 0x1f;
-
- switch (opcode) {
- case OPC_PAL:
- case OPC_JSR:
- case 0x30 ... 0x3f: /* branches */
- MOD_DEC_USE_COUNT;
- return 0;
-
- case OPC_MISC:
- switch (insn & 0xffff) {
- case MISC_TRAPB:
- case MISC_EXCB:
- MOD_DEC_USE_COUNT;
- return 0;
-
- default:
- break;
- }
- break;
-
- case OPC_INTA:
- case OPC_INTL:
- case OPC_INTS:
- case OPC_INTM:
- write_mask &= ~(1UL << rc);
- break;
-
- case OPC_FLTC:
- case OPC_FLTV:
- case OPC_FLTI:
- case OPC_FLTL:
- write_mask &= ~(1UL << (rc + 32));
- break;
- }
- if (!write_mask) {
- if (alpha_fp_emul(trigger_pc)) {
- /* re-execute insns in trap-shadow: */
- regs->pc = trigger_pc + 4;
- MOD_DEC_USE_COUNT;
- return 1;
- }
- break;
- }
- trigger_pc -= 4;
- }
- MOD_DEC_USE_COUNT;
- return 0;
-}
+++ /dev/null
-/*
- * These defines correspond to the dynamic rounding mode bits in the
- * Floating Point Control Register. They also happen to correspond to
- * the instruction encodings except that 0x03 signifies dynamic
- * rounding mode in that case.
- */
-#define ROUND_CHOP 0x00 /* chopped (aka round towards zero) */
-#define ROUND_NINF 0x01 /* round towards negative infinity */
-#define ROUND_NEAR 0x02 /* round towards nearest number */
-#define ROUND_PINF 0x03 /* round towards positive infinity */
+++ /dev/null
-/*
- * ieee-math.c - IEEE floating point emulation code
- * Copyright (C) 1989,1990,1991,1995 by
- * Digital Equipment Corporation, Maynard, Massachusetts.
- *
- * Heavily modified for Linux/Alpha. Changes are Copyright (c) 1995
- * by David Mosberger (davidm@azstarnet.com).
- *
- * This file may be redistributed according to the terms of the
- * GNU General Public License.
- */
-/*
- * The original code did not have any comments. I have created many
- * comments as I fix the bugs in the code. My comments are based on
- * my observation and interpretation of the code. If the original
- * author would have spend a few minutes to comment the code, we would
- * never had a problem of misinterpretation. -HA
- *
- * This code could probably be a lot more optimized (especially the
- * division routine). However, my foremost concern was to get the
- * IEEE behavior right. Performance is less critical as these
- * functions are used on exceptional numbers only (well, assuming you
- * don't turn on the "trap on inexact"...).
- */
-#include <linux/sched.h>
-#include "ieee-math.h"
-
-#define STICKY_S 0x20000000 /* both in longword 0 of fraction */
-#define STICKY_T 1
-
-/*
- * Careful: order matters here!
- */
-enum {
- NaN, QNaN, INFTY, ZERO, DENORM, NORMAL
-};
-
-enum {
- SINGLE, DOUBLE
-};
-
-typedef unsigned long fpclass_t;
-
-#define IEEE_TMAX 0x7fefffffffffffff
-#define IEEE_SMAX 0x47efffffe0000000
-#define IEEE_SNaN 0xfff00000000f0000
-#define IEEE_QNaN 0xfff8000000000000
-#define IEEE_PINF 0x7ff0000000000000
-#define IEEE_NINF 0xfff0000000000000
-
-
-/*
- * The memory format of S floating point numbers differs from the
- * register format. In the following, the bitnumbers above the
- * diagram below give the memory format while the numbers below give
- * the register format.
- *
- * 31 30 23 22 0
- * +-----------------------------------------------+
- * S | s | exp | fraction |
- * +-----------------------------------------------+
- * 63 62 52 51 29
- *
- * For T floating point numbers, the register and memory formats
- * match:
- *
- * +-------------------------------------------------------------------+
- * T | s | exp | frac | tion |
- * +-------------------------------------------------------------------+
- * 63 62 52 51 32 31 0
- */
-typedef struct {
- unsigned long f[2]; /* bit 55 in f[0] is the factor of 2^0*/
- int s; /* 1 bit sign (0 for +, 1 for -) */
- int e; /* 16 bit signed exponent */
-} EXTENDED;
-
-
-/*
- * Return the sign of a Q integer, S or T fp number in the register
- * format.
- */
-static inline int
-sign (unsigned long a)
-{
- if ((long) a < 0)
- return -1;
- else
- return 1;
-}
-
-
-static inline long
-cmp128 (const long a[2], const long b[2])
-{
- if (a[1] < b[1]) return -1;
- if (a[1] > b[1]) return 1;
- return a[0] - b[0];
-}
-
-
-static inline void
-sll128 (unsigned long a[2])
-{
- a[1] = (a[1] << 1) | (a[0] >> 63);
- a[0] <<= 1;
-}
-
-
-static inline void
-srl128 (unsigned long a[2])
-{
- a[0] = (a[0] >> 1) | (a[1] << 63);
- a[1] >>= 1;
-}
-
-
-static inline void
-add128 (const unsigned long a[2], const unsigned long b[2], unsigned long c[2])
-{
- unsigned long carry = a[0] > (0xffffffffffffffff - b[0]);
-
- c[0] = a[0] + b[0];
- c[1] = a[1] + b[1] + carry;
-}
-
-
-static inline void
-sub128 (const unsigned long a[2], const unsigned long b[2], unsigned long c[2])
-{
- unsigned long borrow = a[0] < b[0];
-
- c[0] = a[0] - b[0];
- c[1] = a[1] - b[1] - borrow;
-}
-
-
-static inline void
-mul64 (const unsigned long a, const unsigned long b, unsigned long c[2])
-{
- c[0] = a * b;
- asm ("umulh %1,%2,%0" : "=r"(c[1]) : "r"(a), "r"(b));
-}
-
-
-static void
-div128 (unsigned long a[2], unsigned long b[2], unsigned long c[2])
-{
- unsigned long mask[2] = {1, 0};
-
- /*
- * Shift b until either the sign bit is set or until it is at
- * least as big as the dividend:
- */
- while (cmp128(b, a) < 0 && sign(b[1]) >= 0) {
- sll128(b);
- sll128(mask);
- }
- c[0] = c[1] = 0;
- do {
- if (cmp128(a, b) >= 0) {
- sub128(a, b, a);
- add128(mask, c, c);
- }
- srl128(mask);
- srl128(b);
- } while (mask[0] || mask[1]);
-}
-
-
-static void
-normalize (EXTENDED *a)
-{
- if (!a->f[0] && !a->f[1])
- return; /* zero fraction, unnormalizable... */
- /*
- * In "extended" format, the "1" in "1.f" is explicit; it is
- * in bit 55 of f[0], and the decimal point is understood to
- * be between bit 55 and bit 54. To normalize, shift the
- * fraction until we have a "1" in bit 55.
- */
- if ((a->f[0] & 0xff00000000000000) != 0 || a->f[1] != 0) {
- /*
- * Mantissa is greater than 1.0:
- */
- while ((a->f[0] & 0xff80000000000000) != 0x0080000000000000 ||
- a->f[1] != 0)
- {
- unsigned long sticky;
-
- ++a->e;
- sticky = a->f[0] & 1;
- srl128(a->f);
- a->f[0] |= sticky;
- }
- return;
- }
-
- if (!(a->f[0] & 0x0080000000000000)) {
- /*
- * Mantissa is less than 1.0:
- */
- while (!(a->f[0] & 0x0080000000000000)) {
- --a->e;
- a->f[0] <<= 1;
- }
- return;
- }
-}
-
-
-static inline fpclass_t
-ieee_fpclass (unsigned long a)
-{
- unsigned long exp, fract;
-
- exp = (a >> 52) & 0x7ff; /* 11 bits of exponent */
- fract = a & 0x000fffffffffffff; /* 52 bits of fraction */
- if (exp == 0) {
- if (fract == 0)
- return ZERO;
- return DENORM;
- }
- if (exp == 0x7ff) {
- if (fract == 0)
- return INFTY;
- if (((fract >> 51) & 1) != 0)
- return QNaN;
- return NaN;
- }
- return NORMAL;
-}
-
-
-/*
- * Translate S/T fp number in register format into extended format.
- */
-static fpclass_t
-extend_ieee (unsigned long a, EXTENDED *b, int prec)
-{
- fpclass_t result_kind;
-
- b->s = a >> 63;
- b->e = ((a >> 52) & 0x7ff) - 0x3ff; /* remove bias */
- b->f[1] = 0;
- /*
- * We shift f[1] left three bits so that the higher order bits
- * of the fraction will reside in bits 55 through 0 of f[0].
- */
- b->f[0] = (a & 0x000fffffffffffff) << 3;
- result_kind = ieee_fpclass(a);
- if (result_kind == NORMAL) {
- /* set implied 1. bit: */
- b->f[0] |= 1UL << 55;
- } else if (result_kind == DENORM) {
- if (prec == SINGLE)
- b->e = -126;
- else
- b->e = -1022;
- }
- return result_kind;
-}
-
-
-/*
- * INPUT PARAMETERS:
- * a a number in EXTENDED format to be converted to
- * s-floating format.
- * f rounding mode and exception enable bits.
- * OUTPUT PARAMETERS:
- * b will contain the s-floating number that "a" was
- * converted to (in register format).
- */
-static unsigned long
-make_s_ieee (long f, EXTENDED *a, unsigned long *b)
-{
- unsigned long res, sticky;
-
- if (!a->e && !a->f[0] && !a->f[1]) {
- *b = (unsigned long) a->s << 63; /* return +/-0 */
- return 0;
- }
-
- normalize(a);
- res = 0;
-
- if (a->e < -0x7e) {
- res = FPCR_INE;
- if (f & IEEE_TRAP_ENABLE_UNF) {
- res |= FPCR_UNF;
- a->e += 0xc0; /* scale up result by 2^alpha */
- } else {
- /* try making denormalized number: */
- while (a->e < -0x7e) {
- ++a->e;
- sticky = a->f[0] & 1;
- srl128(a->f);
- if (!a->f[0] && !a->f[0]) {
- /* underflow: replace with exact 0 */
- res |= FPCR_UNF;
- break;
- }
- a->f[0] |= sticky;
- }
- a->e = -0x3ff;
- }
- }
- if (a->e >= 0x80) {
- res = FPCR_OVF | FPCR_INE;
- if (f & IEEE_TRAP_ENABLE_OVF) {
- a->e -= 0xc0; /* scale down result by 2^alpha */
- } else {
- /*
- * Overflow without trap enabled, substitute
- * result according to rounding mode:
- */
- switch (RM(f)) {
- case ROUND_NEAR:
- *b = IEEE_PINF;
- break;
-
- case ROUND_CHOP:
- *b = IEEE_SMAX;
- break;
-
- case ROUND_NINF:
- if (a->s) {
- *b = IEEE_PINF;
- } else {
- *b = IEEE_SMAX;
- }
- break;
-
- case ROUND_PINF:
- if (a->s) {
- *b = IEEE_SMAX;
- } else {
- *b = IEEE_PINF;
- }
- break;
- }
- *b |= ((unsigned long) a->s << 63);
- return res;
- }
- }
-
- *b = (((unsigned long) a->s << 63) |
- (((unsigned long) a->e + 0x3ff) << 52) |
- ((a->f[0] >> 3) & 0x000fffffe0000000));
- return res;
-}
-
-
-static unsigned long
-make_t_ieee (long f, EXTENDED *a, unsigned long *b)
-{
- unsigned long res, sticky;
-
- if (!a->e && !a->f[0] && !a->f[1]) {
- *b = (unsigned long) a->s << 63; /* return +/-0 */
- return 0;
- }
-
- normalize(a);
- res = 0;
- if (a->e < -0x3fe) {
- res = FPCR_INE;
- if (f & IEEE_TRAP_ENABLE_UNF) {
- res |= FPCR_UNF;
- a->e += 0x600;
- } else {
- /* try making denormalized number: */
- while (a->e < -0x3fe) {
- ++a->e;
- sticky = a->f[0] & 1;
- srl128(a->f);
- if (!a->f[0] && !a->f[0]) {
- /* underflow: replace with exact 0 */
- res |= FPCR_UNF;
- break;
- }
- a->f[0] |= sticky;
- }
- a->e = -0x3ff;
- }
- }
- if (a->e >= 0x3ff) {
- res = FPCR_OVF | FPCR_INE;
- if (f & IEEE_TRAP_ENABLE_OVF) {
- a->e -= 0x600; /* scale down result by 2^alpha */
- } else {
- /*
- * Overflow without trap enabled, substitute
- * result according to rounding mode:
- */
- switch (RM(f)) {
- case ROUND_NEAR:
- *b = IEEE_PINF;
- break;
-
- case ROUND_CHOP:
- *b = IEEE_TMAX;
- break;
-
- case ROUND_NINF:
- if (a->s) {
- *b = IEEE_PINF;
- } else {
- *b = IEEE_TMAX;
- }
- break;
-
- case ROUND_PINF:
- if (a->s) {
- *b = IEEE_TMAX;
- } else {
- *b = IEEE_PINF;
- }
- break;
- }
- *b |= ((unsigned long) a->s << 63);
- return res;
- }
- }
- *b = (((unsigned long) a->s << 63) |
- (((unsigned long) a->e + 0x3ff) << 52) |
- ((a->f[0] >> 3) & 0x000fffffffffffff));
- return res;
-}
-
-
-/*
- * INPUT PARAMETERS:
- * a EXTENDED format number to be rounded.
- * rm integer with value ROUND_NEAR, ROUND_CHOP, etc.
- * indicates how "a" should be rounded to produce "b".
- * OUTPUT PARAMETERS:
- * b s-floating number produced by rounding "a".
- * RETURN VALUE:
- * if no errors occurred, will be zero. Else will contain flags
- * like FPCR_INE_OP, etc.
- */
-static unsigned long
-round_s_ieee (int f, EXTENDED *a, unsigned long *b)
-{
- unsigned long diff1, diff2, res = 0;
- EXTENDED z1, z2;
-
- if (!(a->f[0] & 0xffffffff)) {
- return make_s_ieee(f, a, b); /* no rounding error */
- }
-
- /*
- * z1 and z2 are the S-floating numbers with the next smaller/greater
- * magnitude than a, respectively.
- */
- z1.s = z2.s = a->s;
- z1.e = z2.e = a->e;
- z1.f[0] = z2.f[0] = a->f[0] & 0xffffffff00000000;
- z1.f[1] = z2.f[1] = 0;
- z2.f[0] += 0x100000000; /* next bigger S float number */
-
- switch (RM(f)) {
- case ROUND_NEAR:
- diff1 = a->f[0] - z1.f[0];
- diff2 = z2.f[0] - a->f[0];
- if (diff1 > diff2)
- res = make_s_ieee(f, &z2, b);
- else if (diff2 > diff1)
- res = make_s_ieee(f, &z1, b);
- else
- /* equal distance: round towards even */
- if (z1.f[0] & 0x100000000)
- res = make_s_ieee(f, &z2, b);
- else
- res = make_s_ieee(f, &z1, b);
- break;
-
- case ROUND_CHOP:
- res = make_s_ieee(f, &z1, b);
- break;
-
- case ROUND_PINF:
- if (a->s) {
- res = make_s_ieee(f, &z1, b);
- } else {
- res = make_s_ieee(f, &z2, b);
- }
- break;
-
- case ROUND_NINF:
- if (a->s) {
- res = make_s_ieee(f, &z2, b);
- } else {
- res = make_s_ieee(f, &z1, b);
- }
- break;
- }
- return FPCR_INE | res;
-}
-
-
-static unsigned long
-round_t_ieee (int f, EXTENDED *a, unsigned long *b)
-{
- unsigned long diff1, diff2, res;
- EXTENDED z1, z2;
-
- if (!(a->f[0] & 0x7)) {
- /* no rounding error */
- return make_t_ieee(f, a, b);
- }
-
- z1.s = z2.s = a->s;
- z1.e = z2.e = a->e;
- z1.f[0] = z2.f[0] = a->f[0] & ~0x7;
- z1.f[1] = z2.f[1] = 0;
- z2.f[0] += (1 << 3);
-
- res = 0;
- switch (RM(f)) {
- case ROUND_NEAR:
- diff1 = a->f[0] - z1.f[0];
- diff2 = z2.f[0] - a->f[0];
- if (diff1 > diff2)
- res = make_t_ieee(f, &z2, b);
- else if (diff2 > diff1)
- res = make_t_ieee(f, &z1, b);
- else
- /* equal distance: round towards even */
- if (z1.f[0] & (1 << 3))
- res = make_t_ieee(f, &z2, b);
- else
- res = make_t_ieee(f, &z1, b);
- break;
-
- case ROUND_CHOP:
- res = make_t_ieee(f, &z1, b);
- break;
-
- case ROUND_PINF:
- if (a->s) {
- res = make_t_ieee(f, &z1, b);
- } else {
- res = make_t_ieee(f, &z2, b);
- }
- break;
-
- case ROUND_NINF:
- if (a->s) {
- res = make_t_ieee(f, &z2, b);
- } else {
- res = make_t_ieee(f, &z1, b);
- }
- break;
- }
- return FPCR_INE | res;
-}
-
-
-static fpclass_t
-add_kernel_ieee (EXTENDED *op_a, EXTENDED *op_b, EXTENDED *op_c)
-{
- unsigned long mask, fa, fb, fc;
- int diff;
-
- diff = op_a->e - op_b->e;
- fa = op_a->f[0];
- fb = op_b->f[0];
- if (diff < 0) {
- diff = -diff;
- op_c->e = op_b->e;
- mask = (1UL << diff) - 1;
- fa >>= diff;
- if (op_a->f[0] & mask) {
- fa |= 1; /* set sticky bit */
- }
- } else {
- op_c->e = op_a->e;
- mask = (1UL << diff) - 1;
- fb >>= diff;
- if (op_b->f[0] & mask) {
- fb |= 1; /* set sticky bit */
- }
- }
- if (op_a->s)
- fa = -fa;
- if (op_b->s)
- fb = -fb;
- fc = fa + fb;
- op_c->f[1] = 0;
- op_c->s = fc >> 63;
- if (op_c->s) {
- fc = -fc;
- }
- op_c->f[0] = fc;
- normalize(op_c);
- return 0;
-}
-
-
-/*
- * converts s-floating "a" to t-floating "b".
- *
- * INPUT PARAMETERS:
- * a a s-floating number to be converted
- * f the rounding mode (ROUND_NEAR, etc. )
- * OUTPUT PARAMETERS:
- * b the t-floating number that "a" is converted to.
- * RETURN VALUE:
- * error flags - i.e., zero if no errors occurred,
- * FPCR_INV if invalid operation occurred, etc.
- */
-unsigned long
-ieee_CVTST (int f, unsigned long a, unsigned long *b)
-{
- EXTENDED temp;
- fpclass_t a_type;
-
- a_type = extend_ieee(a, &temp, SINGLE);
- if (a_type >= NaN && a_type <= INFTY) {
- *b = a;
- if (a_type == NaN) {
- *b |= (1UL << 51); /* turn SNaN into QNaN */
- return FPCR_INV;
- }
- return 0;
- }
- return round_t_ieee(f, &temp, b);
-}
-
-
-/*
- * converts t-floating "a" to s-floating "b".
- *
- * INPUT PARAMETERS:
- * a a t-floating number to be converted
- * f the rounding mode (ROUND_NEAR, etc. )
- * OUTPUT PARAMETERS:
- * b the s-floating number that "a" is converted to.
- * RETURN VALUE:
- * error flags - i.e., zero if no errors occurred,
- * FPCR_INV if invalid operation occurred, etc.
- */
-unsigned long
-ieee_CVTTS (int f, unsigned long a, unsigned long *b)
-{
- EXTENDED temp;
- fpclass_t a_type;
-
- a_type = extend_ieee(a, &temp, DOUBLE);
- if (a_type >= NaN && a_type <= INFTY) {
- *b = a;
- if (a_type == NaN) {
- *b |= (1UL << 51); /* turn SNaN into QNaN */
- return FPCR_INV;
- }
- return 0;
- }
- return round_s_ieee(f, &temp, b);
-}
-
-
-/*
- * converts q-format (64-bit integer) "a" to s-floating "b".
- *
- * INPUT PARAMETERS:
- * a an 64-bit integer to be converted.
- * f the rounding mode (ROUND_NEAR, etc. )
- * OUTPUT PARAMETERS:
- * b the s-floating number "a" is converted to.
- * RETURN VALUE:
- * error flags - i.e., zero if no errors occurred,
- * FPCR_INV if invalid operation occurred, etc.
- */
-unsigned long
-ieee_CVTQS (int f, unsigned long a, unsigned long *b)
-{
- EXTENDED op_b;
-
- op_b.s = 0;
- op_b.f[0] = a;
- op_b.f[1] = 0;
- if (sign(a) < 0) {
- op_b.s = 1;
- op_b.f[0] = -a;
- }
- op_b.e = 55;
- normalize(&op_b);
- return round_s_ieee(f, &op_b, b);
-}
-
-
-/*
- * converts 64-bit integer "a" to t-floating "b".
- *
- * INPUT PARAMETERS:
- * a a 64-bit integer to be converted.
- * f the rounding mode (ROUND_NEAR, etc.)
- * OUTPUT PARAMETERS:
- * b the t-floating number "a" is converted to.
- * RETURN VALUE:
- * error flags - i.e., zero if no errors occurred,
- * FPCR_INV if invalid operation occurred, etc.
- */
-unsigned long
-ieee_CVTQT (int f, long a, unsigned long *b)
-{
- EXTENDED op_b;
-
- if (a != 0) {
- op_b.s = (a < 0 ? 1 : 0);
- op_b.f[0] = (a < 0 ? -a : a);
- op_b.f[1] = 0;
- op_b.e = 55;
- normalize(&op_b);
- return round_t_ieee(f, &op_b, b);
- } else {
- *b = 0;
- return 0;
- }
-}
-
-
-/*
- * converts t-floating "a" to 64-bit integer (q-format) "b".
- *
- * INPUT PARAMETERS:
- * a a t-floating number to be converted.
- * f the rounding mode (ROUND_NEAR, etc. )
- * OUTPUT PARAMETERS:
- * b the 64-bit integer "a" is converted to.
- * RETURN VALUE:
- * error flags - i.e., zero if no errors occurred,
- * FPCR_INV if invalid operation occurred, etc.
- */
-unsigned long
-ieee_CVTTQ (int f, unsigned long a, unsigned long *pb)
-{
- unsigned int midway;
- unsigned long ov, uv, res, b;
- fpclass_t a_type;
- EXTENDED temp;
-
- a_type = extend_ieee(a, &temp, DOUBLE);
-
- b = 0x7fffffffffffffff;
- res = FPCR_INV;
- if (a_type == NaN || a_type == INFTY)
- goto out;
-
- res = 0;
- if (a_type == QNaN)
- goto out;
-
- if (temp.e > 0) {
- ov = 0;
- while (temp.e > 0) {
- --temp.e;
- ov |= temp.f[1] >> 63;
- sll128(temp.f);
- }
- if (ov || (temp.f[1] & 0xffc0000000000000))
- res |= FPCR_IOV | FPCR_INE;
- }
- else if (temp.e < 0) {
- while (temp.e < 0) {
- ++temp.e;
- uv = temp.f[0] & 1; /* save sticky bit */
- srl128(temp.f);
- temp.f[0] |= uv;
- }
- }
- b = (temp.f[1] << 9) | (temp.f[0] >> 55);
-
- /*
- * Notice: the fraction is only 52 bits long. Thus, rounding
- * cannot possibly result in an integer overflow.
- */
- switch (RM(f)) {
- case ROUND_NEAR:
- if (temp.f[0] & 0x0040000000000000) {
- midway = (temp.f[0] & 0x003fffffffffffff) == 0;
- if ((midway && (temp.f[0] & 0x0080000000000000)) ||
- !midway)
- ++b;
- }
- break;
-
- case ROUND_PINF:
- b += ((temp.f[0] & 0x007fffffffffffff) != 0 && !temp.s);
- break;
-
- case ROUND_NINF:
- b += ((temp.f[0] & 0x007fffffffffffff) != 0 && temp.s);
- break;
-
- case ROUND_CHOP:
- /* no action needed */
- break;
- }
- if ((temp.f[0] & 0x007fffffffffffff) != 0)
- res |= FPCR_INE;
-
- if (temp.s) {
- b = -b;
- }
-
-out:
- *pb = b;
- return res;
-}
-
-
-unsigned long
-ieee_CMPTEQ (unsigned long a, unsigned long b, unsigned long *c)
-{
- EXTENDED op_a, op_b;
- fpclass_t a_type, b_type;
-
- *c = 0;
- a_type = extend_ieee(a, &op_a, DOUBLE);
- b_type = extend_ieee(b, &op_b, DOUBLE);
- if (a_type == NaN || b_type == NaN)
- return FPCR_INV;
- if (a_type == QNaN || b_type == QNaN)
- return 0;
-
- if ((op_a.e == op_b.e && op_a.s == op_b.s &&
- op_a.f[0] == op_b.f[0] && op_a.f[1] == op_b.f[1]) ||
- (a_type == ZERO && b_type == ZERO))
- *c = 0x4000000000000000;
- return 0;
-}
-
-
-unsigned long
-ieee_CMPTLT (unsigned long a, unsigned long b, unsigned long *c)
-{
- fpclass_t a_type, b_type;
- EXTENDED op_a, op_b;
-
- *c = 0;
- a_type = extend_ieee(a, &op_a, DOUBLE);
- b_type = extend_ieee(b, &op_b, DOUBLE);
- if (a_type == NaN || b_type == NaN)
- return FPCR_INV;
- if (a_type == QNaN || b_type == QNaN)
- return 0;
-
- if ((op_a.s == 1 && op_b.s == 0 &&
- (a_type != ZERO || b_type != ZERO)) ||
- (op_a.s == 1 && op_b.s == 1 &&
- (op_a.e > op_b.e || (op_a.e == op_b.e &&
- cmp128(op_a.f, op_b.f) > 0))) ||
- (op_a.s == 0 && op_b.s == 0 &&
- (op_a.e < op_b.e || (op_a.e == op_b.e &&
- cmp128(op_a.f,op_b.f) < 0))))
- *c = 0x4000000000000000;
- return 0;
-}
-
-
-unsigned long
-ieee_CMPTLE (unsigned long a, unsigned long b, unsigned long *c)
-{
- fpclass_t a_type, b_type;
- EXTENDED op_a, op_b;
-
- *c = 0;
- a_type = extend_ieee(a, &op_a, DOUBLE);
- b_type = extend_ieee(b, &op_b, DOUBLE);
- if (a_type == NaN || b_type == NaN)
- return FPCR_INV;
- if (a_type == QNaN || b_type == QNaN)
- return 0;
-
- if ((a_type == ZERO && b_type == ZERO) ||
- (op_a.s == 1 && op_b.s == 0) ||
- (op_a.s == 1 && op_b.s == 1 &&
- (op_a.e > op_b.e || (op_a.e == op_b.e &&
- cmp128(op_a.f,op_b.f) >= 0))) ||
- (op_a.s == 0 && op_b.s == 0 &&
- (op_a.e < op_b.e || (op_a.e == op_b.e &&
- cmp128(op_a.f,op_b.f) <= 0))))
- *c = 0x4000000000000000;
- return 0;
-}
-
-
-unsigned long
-ieee_CMPTUN (unsigned long a, unsigned long b, unsigned long *c)
-{
- fpclass_t a_type, b_type;
- EXTENDED op_a, op_b;
-
- *c = 0x4000000000000000;
- a_type = extend_ieee(a, &op_a, DOUBLE);
- b_type = extend_ieee(b, &op_b, DOUBLE);
- if (a_type == NaN || b_type == NaN)
- return FPCR_INV;
- if (a_type == QNaN || b_type == QNaN)
- return 0;
- *c = 0;
- return 0;
-}
-
-
-/*
- * Add a + b = c, where a, b, and c are ieee s-floating numbers. "f"
- * contains the rounding mode etc.
- */
-unsigned long
-ieee_ADDS (int f, unsigned long a, unsigned long b, unsigned long *c)
-{
- fpclass_t a_type, b_type;
- EXTENDED op_a, op_b, op_c;
-
- a_type = extend_ieee(a, &op_a, SINGLE);
- b_type = extend_ieee(b, &op_b, SINGLE);
- if ((a_type >= NaN && a_type <= INFTY) ||
- (b_type >= NaN && b_type <= INFTY))
- {
- /* propagate NaNs according to arch. ref. handbook: */
- if (b_type == QNaN)
- *c = b;
- else if (b_type == NaN)
- *c = b | (1UL << 51);
- else if (a_type == QNaN)
- *c = a;
- else if (a_type == NaN)
- *c = a | (1UL << 51);
-
- if (a_type == NaN || b_type == NaN)
- return FPCR_INV;
- if (a_type == QNaN || b_type == QNaN)
- return 0;
-
- if (a_type == INFTY && b_type == INFTY && sign(a) != sign(b)) {
- *c = IEEE_QNaN;
- return FPCR_INV;
- }
- if (a_type == INFTY)
- *c = a;
- else
- *c = b;
- return 0;
- }
-
- add_kernel_ieee(&op_a, &op_b, &op_c);
- /* special case for -0 + -0 ==> -0 */
- if (a_type == ZERO && b_type == ZERO)
- op_c.s = op_a.s && op_b.s;
- return round_s_ieee(f, &op_c, c);
-}
-
-
-/*
- * Add a + b = c, where a, b, and c are ieee t-floating numbers. "f"
- * contains the rounding mode etc.
- */
-unsigned long
-ieee_ADDT (int f, unsigned long a, unsigned long b, unsigned long *c)
-{
- fpclass_t a_type, b_type;
- EXTENDED op_a, op_b, op_c;
-
- a_type = extend_ieee(a, &op_a, DOUBLE);
- b_type = extend_ieee(b, &op_b, DOUBLE);
- if ((a_type >= NaN && a_type <= INFTY) ||
- (b_type >= NaN && b_type <= INFTY))
- {
- /* propagate NaNs according to arch. ref. handbook: */
- if (b_type == QNaN)
- *c = b;
- else if (b_type == NaN)
- *c = b | (1UL << 51);
- else if (a_type == QNaN)
- *c = a;
- else if (a_type == NaN)
- *c = a | (1UL << 51);
-
- if (a_type == NaN || b_type == NaN)
- return FPCR_INV;
- if (a_type == QNaN || b_type == QNaN)
- return 0;
-
- if (a_type == INFTY && b_type == INFTY && sign(a) != sign(b)) {
- *c = IEEE_QNaN;
- return FPCR_INV;
- }
- if (a_type == INFTY)
- *c = a;
- else
- *c = b;
- return 0;
- }
- add_kernel_ieee(&op_a, &op_b, &op_c);
- /* special case for -0 + -0 ==> -0 */
- if (a_type == ZERO && b_type == ZERO)
- op_c.s = op_a.s && op_b.s;
-
- return round_t_ieee(f, &op_c, c);
-}
-
-
-/*
- * Subtract a - b = c, where a, b, and c are ieee s-floating numbers.
- * "f" contains the rounding mode etc.
- */
-unsigned long
-ieee_SUBS (int f, unsigned long a, unsigned long b, unsigned long *c)
-{
- fpclass_t a_type, b_type;
- EXTENDED op_a, op_b, op_c;
-
- a_type = extend_ieee(a, &op_a, SINGLE);
- b_type = extend_ieee(b, &op_b, SINGLE);
- if ((a_type >= NaN && a_type <= INFTY) ||
- (b_type >= NaN && b_type <= INFTY))
- {
- /* propagate NaNs according to arch. ref. handbook: */
- if (b_type == QNaN)
- *c = b;
- else if (b_type == NaN)
- *c = b | (1UL << 51);
- else if (a_type == QNaN)
- *c = a;
- else if (a_type == NaN)
- *c = a | (1UL << 51);
-
- if (a_type == NaN || b_type == NaN)
- return FPCR_INV;
- if (a_type == QNaN || b_type == QNaN)
- return 0;
-
- if (a_type == INFTY && b_type == INFTY && sign(a) == sign(b)) {
- *c = IEEE_QNaN;
- return FPCR_INV;
- }
- if (a_type == INFTY)
- *c = a;
- else
- *c = b ^ (1UL << 63);
- return 0;
- }
- op_b.s = !op_b.s;
- add_kernel_ieee(&op_a, &op_b, &op_c);
- /* special case for -0 - +0 ==> -0 */
- if (a_type == ZERO && b_type == ZERO)
- op_c.s = op_a.s && op_b.s;
-
- return round_s_ieee(f, &op_c, c);
-}
-
-
-/*
- * Subtract a - b = c, where a, b, and c are ieee t-floating numbers.
- * "f" contains the rounding mode etc.
- */
-unsigned long
-ieee_SUBT (int f, unsigned long a, unsigned long b, unsigned long *c)
-{
- fpclass_t a_type, b_type;
- EXTENDED op_a, op_b, op_c;
-
- a_type = extend_ieee(a, &op_a, DOUBLE);
- b_type = extend_ieee(b, &op_b, DOUBLE);
- if ((a_type >= NaN && a_type <= INFTY) ||
- (b_type >= NaN && b_type <= INFTY))
- {
- /* propagate NaNs according to arch. ref. handbook: */
- if (b_type == QNaN)
- *c = b;
- else if (b_type == NaN)
- *c = b | (1UL << 51);
- else if (a_type == QNaN)
- *c = a;
- else if (a_type == NaN)
- *c = a | (1UL << 51);
-
- if (a_type == NaN || b_type == NaN)
- return FPCR_INV;
- if (a_type == QNaN || b_type == QNaN)
- return 0;
-
- if (a_type == INFTY && b_type == INFTY && sign(a) == sign(b)) {
- *c = IEEE_QNaN;
- return FPCR_INV;
- }
- if (a_type == INFTY)
- *c = a;
- else
- *c = b ^ (1UL << 63);
- return 0;
- }
- op_b.s = !op_b.s;
- add_kernel_ieee(&op_a, &op_b, &op_c);
- /* special case for -0 - +0 ==> -0 */
- if (a_type == ZERO && b_type == ZERO)
- op_c.s = op_a.s && op_b.s;
-
- return round_t_ieee(f, &op_c, c);
-}
-
-
-/*
- * Multiply a x b = c, where a, b, and c are ieee s-floating numbers.
- * "f" contains the rounding mode.
- */
-unsigned long
-ieee_MULS (int f, unsigned long a, unsigned long b, unsigned long *c)
-{
- fpclass_t a_type, b_type;
- EXTENDED op_a, op_b, op_c;
-
- a_type = extend_ieee(a, &op_a, SINGLE);
- b_type = extend_ieee(b, &op_b, SINGLE);
- if ((a_type >= NaN && a_type <= INFTY) ||
- (b_type >= NaN && b_type <= INFTY))
- {
- /* propagate NaNs according to arch. ref. handbook: */
- if (b_type == QNaN)
- *c = b;
- else if (b_type == NaN)
- *c = b | (1UL << 51);
- else if (a_type == QNaN)
- *c = a;
- else if (a_type == NaN)
- *c = a | (1UL << 51);
-
- if (a_type == NaN || b_type == NaN)
- return FPCR_INV;
- if (a_type == QNaN || b_type == QNaN)
- return 0;
-
- if ((a_type == INFTY && b_type == ZERO) ||
- (b_type == INFTY && a_type == ZERO))
- {
- *c = IEEE_QNaN; /* return canonical QNaN */
- return FPCR_INV;
- }
- if (a_type == INFTY)
- *c = a ^ ((b >> 63) << 63);
- else if (b_type == INFTY)
- *c = b ^ ((a >> 63) << 63);
- else
- /* either of a and b are +/-0 */
- *c = ((unsigned long) op_a.s ^ op_b.s) << 63;
- return 0;
- }
- op_c.s = op_a.s ^ op_b.s;
- op_c.e = op_a.e + op_b.e - 55;
- mul64(op_a.f[0], op_b.f[0], op_c.f);
-
- return round_s_ieee(f, &op_c, c);
-}
-
-
-/*
- * Multiply a x b = c, where a, b, and c are ieee t-floating numbers.
- * "f" contains the rounding mode.
- */
-unsigned long
-ieee_MULT (int f, unsigned long a, unsigned long b, unsigned long *c)
-{
- fpclass_t a_type, b_type;
- EXTENDED op_a, op_b, op_c;
-
- *c = IEEE_QNaN;
- a_type = extend_ieee(a, &op_a, DOUBLE);
- b_type = extend_ieee(b, &op_b, DOUBLE);
- if ((a_type >= NaN && a_type <= ZERO) ||
- (b_type >= NaN && b_type <= ZERO))
- {
- /* propagate NaNs according to arch. ref. handbook: */
- if (b_type == QNaN)
- *c = b;
- else if (b_type == NaN)
- *c = b | (1UL << 51);
- else if (a_type == QNaN)
- *c = a;
- else if (a_type == NaN)
- *c = a | (1UL << 51);
-
- if (a_type == NaN || b_type == NaN)
- return FPCR_INV;
- if (a_type == QNaN || b_type == QNaN)
- return 0;
-
- if ((a_type == INFTY && b_type == ZERO) ||
- (b_type == INFTY && a_type == ZERO))
- {
- *c = IEEE_QNaN; /* return canonical QNaN */
- return FPCR_INV;
- }
- if (a_type == INFTY)
- *c = a ^ ((b >> 63) << 63);
- else if (b_type == INFTY)
- *c = b ^ ((a >> 63) << 63);
- else
- /* either of a and b are +/-0 */
- *c = ((unsigned long) op_a.s ^ op_b.s) << 63;
- return 0;
- }
- op_c.s = op_a.s ^ op_b.s;
- op_c.e = op_a.e + op_b.e - 55;
- mul64(op_a.f[0], op_b.f[0], op_c.f);
-
- return round_t_ieee(f, &op_c, c);
-}
-
-
-/*
- * Divide a / b = c, where a, b, and c are ieee s-floating numbers.
- * "f" contains the rounding mode etc.
- */
-unsigned long
-ieee_DIVS (int f, unsigned long a, unsigned long b, unsigned long *c)
-{
- fpclass_t a_type, b_type;
- EXTENDED op_a, op_b, op_c;
-
- a_type = extend_ieee(a, &op_a, SINGLE);
- b_type = extend_ieee(b, &op_b, SINGLE);
- if ((a_type >= NaN && a_type <= ZERO) ||
- (b_type >= NaN && b_type <= ZERO))
- {
- unsigned long res;
-
- /* propagate NaNs according to arch. ref. handbook: */
- if (b_type == QNaN)
- *c = b;
- else if (b_type == NaN)
- *c = b | (1UL << 51);
- else if (a_type == QNaN)
- *c = a;
- else if (a_type == NaN)
- *c = a | (1UL << 51);
-
- if (a_type == NaN || b_type == NaN)
- return FPCR_INV;
- if (a_type == QNaN || b_type == QNaN)
- return 0;
-
- res = 0;
- *c = IEEE_PINF;
- if (a_type == INFTY) {
- if (b_type == INFTY) {
- *c = IEEE_QNaN;
- return FPCR_INV;
- }
- } else if (b_type == ZERO) {
- if (a_type == ZERO) {
- *c = IEEE_QNaN;
- return FPCR_INV;
- }
- res = FPCR_DZE;
- } else
- /* a_type == ZERO || b_type == INFTY */
- *c = 0;
- *c |= (unsigned long) (op_a.s ^ op_b.s) << 63;
- return res;
- }
- op_c.s = op_a.s ^ op_b.s;
- op_c.e = op_a.e - op_b.e;
-
- op_a.f[1] = op_a.f[0];
- op_a.f[0] = 0;
- div128(op_a.f, op_b.f, op_c.f);
- if (a_type != ZERO)
- /* force a sticky bit because DIVs never hit exact .5: */
- op_c.f[0] |= STICKY_S;
- normalize(&op_c);
- op_c.e -= 9; /* remove excess exp from original shift */
- return round_s_ieee(f, &op_c, c);
-}
-
-
-/*
- * Divide a/b = c, where a, b, and c are ieee t-floating numbers. "f"
- * contains the rounding mode etc.
- */
-unsigned long
-ieee_DIVT (int f, unsigned long a, unsigned long b, unsigned long *c)
-{
- fpclass_t a_type, b_type;
- EXTENDED op_a, op_b, op_c;
-
- *c = IEEE_QNaN;
- a_type = extend_ieee(a, &op_a, DOUBLE);
- b_type = extend_ieee(b, &op_b, DOUBLE);
- if ((a_type >= NaN && a_type <= ZERO) ||
- (b_type >= NaN && b_type <= ZERO))
- {
- unsigned long res;
-
- /* propagate NaNs according to arch. ref. handbook: */
- if (b_type == QNaN)
- *c = b;
- else if (b_type == NaN)
- *c = b | (1UL << 51);
- else if (a_type == QNaN)
- *c = a;
- else if (a_type == NaN)
- *c = a | (1UL << 51);
-
- if (a_type == NaN || b_type == NaN)
- return FPCR_INV;
- if (a_type == QNaN || b_type == QNaN)
- return 0;
-
- res = 0;
- *c = IEEE_PINF;
- if (a_type == INFTY) {
- if (b_type == INFTY) {
- *c = IEEE_QNaN;
- return FPCR_INV;
- }
- } else if (b_type == ZERO) {
- if (a_type == ZERO) {
- *c = IEEE_QNaN;
- return FPCR_INV;
- }
- res = FPCR_DZE;
- } else
- /* a_type == ZERO || b_type == INFTY */
- *c = 0;
- *c |= (unsigned long) (op_a.s ^ op_b.s) << 63;
- return res;
- }
- op_c.s = op_a.s ^ op_b.s;
- op_c.e = op_a.e - op_b.e;
-
- op_a.f[1] = op_a.f[0];
- op_a.f[0] = 0;
- div128(op_a.f, op_b.f, op_c.f);
- if (a_type != ZERO)
- /* force a sticky bit because DIVs never hit exact .5 */
- op_c.f[0] |= STICKY_T;
- normalize(&op_c);
- op_c.e -= 9; /* remove excess exp from original shift */
- return round_t_ieee(f, &op_c, c);
-}
-
-/*
- * Sqrt a = b, where a and b are ieee s-floating numbers. "f"
- * contains the rounding mode etc.
- */
-unsigned long
-ieee_SQRTS (int f, unsigned long a, unsigned long *b)
-{
- fpclass_t a_type;
- EXTENDED op_a, op_b;
-
- *b = IEEE_QNaN;
- a_type = extend_ieee(a, &op_a, SINGLE);
- if (op_a.s == 0) {
- /* FIXME -- handle positive denormals. */
- send_sig(SIGFPE, current, 1);
- }
- return FPCR_INV;
-}
-
-/*
- * Sqrt a = b, where a and b are ieee t-floating numbers. "f"
- * contains the rounding mode etc.
- */
-unsigned long
-ieee_SQRTT (int f, unsigned long a, unsigned long *b)
-{
- fpclass_t a_type;
- EXTENDED op_a, op_b;
-
- *b = IEEE_QNaN;
- a_type = extend_ieee(a, &op_a, DOUBLE);
- if (op_a.s == 0) {
- /* FIXME -- handle positive denormals. */
- send_sig(SIGFPE, current, 1);
- }
- return FPCR_INV;
-}
+++ /dev/null
-/*
- * Copyright (C) 1992,1995 by
- * Digital Equipment Corporation, Maynard, Massachusetts.
- * This file may be redistributed according to the terms of the
- * GNU General Public License.
- */
-#ifndef __ieee_math_h__
-#define __ieee_math_h__
-
-#include <asm/fpu.h>
-
-#define ROUND_SHIFT 6 /* make space for trap-enable bits */
-#define RM(f) (((f) >> ROUND_SHIFT) & 0x3)
-
-#define ROUND_CHOP (FPCR_DYN_CHOPPED >> FPCR_DYN_SHIFT)
-#define ROUND_NINF (FPCR_DYN_MINUS >> FPCR_DYN_SHIFT)
-#define ROUND_NEAR (FPCR_DYN_NORMAL >> FPCR_DYN_SHIFT)
-#define ROUND_PINF (FPCR_DYN_PLUS >> FPCR_DYN_SHIFT)
-
-extern unsigned long ieee_CVTST (int rm, unsigned long a, unsigned long *b);
-extern unsigned long ieee_CVTTS (int rm, unsigned long a, unsigned long *b);
-extern unsigned long ieee_CVTQS (int rm, unsigned long a, unsigned long *b);
-extern unsigned long ieee_CVTQT (int rm, long a, unsigned long *b);
-extern unsigned long ieee_CVTTQ (int rm, unsigned long a, unsigned long *b);
-
-extern unsigned long ieee_CMPTEQ (unsigned long a, unsigned long b,
- unsigned long *c);
-extern unsigned long ieee_CMPTLT (unsigned long a, unsigned long b,
- unsigned long *c);
-extern unsigned long ieee_CMPTLE (unsigned long a, unsigned long b,
- unsigned long *c);
-extern unsigned long ieee_CMPTUN (unsigned long a, unsigned long b,
- unsigned long *c);
-
-extern unsigned long ieee_ADDS (int rm, unsigned long a, unsigned long b,
- unsigned long *c);
-extern unsigned long ieee_ADDT (int rm, unsigned long a, unsigned long b,
- unsigned long *c);
-extern unsigned long ieee_SUBS (int rm, unsigned long a, unsigned long b,
- unsigned long *c);
-extern unsigned long ieee_SUBT (int rm, unsigned long a, unsigned long b,
- unsigned long *c);
-extern unsigned long ieee_MULS (int rm, unsigned long a, unsigned long b,
- unsigned long *c);
-extern unsigned long ieee_MULT (int rm, unsigned long a, unsigned long b,
- unsigned long *c);
-extern unsigned long ieee_DIVS (int rm, unsigned long a, unsigned long b,
- unsigned long *c);
-extern unsigned long ieee_DIVT (int rm, unsigned long a, unsigned long b,
- unsigned long *c);
-extern unsigned long ieee_SQRTS (int rm, unsigned long a, unsigned long *b);
-extern unsigned long ieee_SQRTT (int rm, unsigned long a, unsigned long *b);
-
-#endif /* __ieee_math_h__ */
--- /dev/null
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+
+#include <asm/uaccess.h>
+
+#include "sfp-util.h"
+#include <math-emu/soft-fp.h>
+#include <math-emu/single.h>
+#include <math-emu/double.h>
+
+#define OPC_PAL 0x00
+#define OPC_INTA 0x10
+#define OPC_INTL 0x11
+#define OPC_INTS 0x12
+#define OPC_INTM 0x13
+#define OPC_FLTC 0x14
+#define OPC_FLTV 0x15
+#define OPC_FLTI 0x16
+#define OPC_FLTL 0x17
+#define OPC_MISC 0x18
+#define OPC_JSR 0x1a
+
+#define FOP_SRC_S 0
+#define FOP_SRC_T 2
+#define FOP_SRC_Q 3
+
+#define FOP_FNC_ADDx 0
+#define FOP_FNC_CVTQL 0
+#define FOP_FNC_SUBx 1
+#define FOP_FNC_MULx 2
+#define FOP_FNC_DIVx 3
+#define FOP_FNC_CMPxUN 4
+#define FOP_FNC_CMPxEQ 5
+#define FOP_FNC_CMPxLT 6
+#define FOP_FNC_CMPxLE 7
+#define FOP_FNC_SQRTx 11
+#define FOP_FNC_CVTxS 12
+#define FOP_FNC_CVTxT 14
+#define FOP_FNC_CVTxQ 15
+
+#define MISC_TRAPB 0x0000
+#define MISC_EXCB 0x0400
+
+extern unsigned long alpha_read_fp_reg (unsigned long reg);
+extern void alpha_write_fp_reg (unsigned long reg, unsigned long val);
+extern unsigned long alpha_read_fp_reg_s (unsigned long reg);
+extern void alpha_write_fp_reg_s (unsigned long reg, unsigned long val);
+
+
+#ifdef MODULE
+
+MODULE_DESCRIPTION("FP Software completion module");
+
+extern long (*alpha_fp_emul_imprecise)(struct pt_regs *, unsigned long);
+extern long (*alpha_fp_emul) (unsigned long pc);
+
+static long (*save_emul_imprecise)(struct pt_regs *, unsigned long);
+static long (*save_emul) (unsigned long pc);
+
+long do_alpha_fp_emul_imprecise(struct pt_regs *, unsigned long);
+long do_alpha_fp_emul(unsigned long);
+
+int init_module(void)
+{
+ save_emul_imprecise = alpha_fp_emul_imprecise;
+ save_emul = alpha_fp_emul;
+ alpha_fp_emul_imprecise = do_alpha_fp_emul_imprecise;
+ alpha_fp_emul = do_alpha_fp_emul;
+ return 0;
+}
+
+void cleanup_module(void)
+{
+ alpha_fp_emul_imprecise = save_emul_imprecise;
+ alpha_fp_emul = save_emul;
+}
+
+#undef alpha_fp_emul_imprecise
+#define alpha_fp_emul_imprecise do_alpha_fp_emul_imprecise
+#undef alpha_fp_emul
+#define alpha_fp_emul do_alpha_fp_emul
+
+#endif /* MODULE */
+
+/* For 128-bit division. */
+
+void
+udiv128(unsigned long divisor_f0, unsigned long divisor_f1,
+ unsigned long dividend_f0, unsigned long dividend_f1,
+ unsigned long *quot, unsigned long *remd)
+{
+ _FP_FRAC_DECL_2(quo);
+ _FP_FRAC_DECL_2(rem);
+ _FP_FRAC_DECL_2(tmp);
+ unsigned long i, num_bits, bit;
+
+ _FP_FRAC_SET_2(rem, _FP_ZEROFRAC_2);
+ _FP_FRAC_SET_2(quo, _FP_ZEROFRAC_2);
+
+ if (_FP_FRAC_ZEROP_2(divisor))
+ goto out;
+
+ if (_FP_FRAC_GT_2(divisor, dividend)) {
+ _FP_FRAC_COPY_2(rem, dividend);
+ goto out;
+ }
+
+ if (_FP_FRAC_EQ_2(divisor, dividend)) {
+ __FP_FRAC_SET_2(quo, 0, 1);
+ goto out;
+ }
+
+ num_bits = 128;
+ while (1) {
+ bit = _FP_FRAC_NEGP_2(dividend);
+ _FP_FRAC_COPY_2(tmp, rem);
+ _FP_FRAC_SLL_2(tmp, 1);
+ _FP_FRAC_LOW_2(tmp) |= bit;
+ if (! _FP_FRAC_GE_2(tmp, divisor))
+ break;
+ _FP_FRAC_COPY_2(rem, tmp);
+ _FP_FRAC_SLL_2(dividend, 1);
+ num_bits--;
+ }
+
+ for (i = 0; i < num_bits; i++) {
+ bit = _FP_FRAC_NEGP_2(dividend);
+ _FP_FRAC_SLL_2(rem, 1);
+ _FP_FRAC_LOW_2(rem) |= bit;
+ _FP_FRAC_SUB_2(tmp, rem, divisor);
+ bit = _FP_FRAC_NEGP_2(tmp);
+ _FP_FRAC_SLL_2(dividend, 1);
+ _FP_FRAC_SLL_2(quo, 1);
+ if (!bit) {
+ _FP_FRAC_LOW_2(quo) |= 1;
+ _FP_FRAC_COPY_2(rem, tmp);
+ }
+ }
+
+out:
+ *quot = quo_f1;
+ *remd = rem_f1;
+ return;
+}
+
+/*
+ * Emulate the floating point instruction at address PC. Returns 0 if
+ * emulation fails. Notice that the kernel does not and cannot use FP
+ * regs. This is good because it means that instead of
+ * saving/restoring all fp regs, we simply stick the result of the
+ * operation into the appropriate register.
+ */
+long
+alpha_fp_emul (unsigned long pc)
+{
+ FP_DECL_EX;
+ FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR);
+ FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR);
+
+ unsigned long fa, fb, fc, func, mode, src;
+ unsigned long fpcw = current->thread.flags;
+ unsigned long res, va, vb, vc, fpcr;
+ __u32 insn;
+
+ MOD_INC_USE_COUNT;
+
+ get_user(insn, (__u32*)pc);
+ fc = (insn >> 0) & 0x1f; /* destination register */
+ fb = (insn >> 16) & 0x1f;
+ fa = (insn >> 21) & 0x1f;
+ func = (insn >> 5) & 0xf;
+ src = (insn >> 9) & 0x3;
+ mode = (insn >> 11) & 0x3;
+
+ fpcr = rdfpcr();
+
+ if (mode == 3) {
+ /* Dynamic -- get rounding mode from fpcr. */
+ mode = (fpcr >> FPCR_DYN_SHIFT) & 3;
+ }
+
+ switch (src) {
+ case FOP_SRC_S:
+ va = alpha_read_fp_reg_s(fa);
+ vb = alpha_read_fp_reg_s(fb);
+
+ FP_UNPACK_SP(SA, &va);
+ FP_UNPACK_SP(SB, &vb);
+
+ switch (func) {
+ case FOP_FNC_SUBx:
+ FP_SUB_S(SR, SA, SB);
+ goto pack_s;
+
+ case FOP_FNC_ADDx:
+ FP_ADD_S(SR, SA, SB);
+ goto pack_s;
+
+ case FOP_FNC_MULx:
+ FP_MUL_S(SR, SA, SB);
+ goto pack_s;
+
+ case FOP_FNC_DIVx:
+ FP_DIV_S(SR, SA, SB);
+ goto pack_s;
+
+ case FOP_FNC_SQRTx:
+ FP_SQRT_S(SR, SB);
+ goto pack_s;
+ }
+ goto bad_insn;
+
+ case FOP_SRC_T:
+ va = alpha_read_fp_reg(fa);
+ vb = alpha_read_fp_reg(fb);
+
+ if ((func & ~3) == FOP_FNC_CMPxUN) {
+ FP_UNPACK_RAW_DP(DA, &va);
+ FP_UNPACK_RAW_DP(DB, &vb);
+ if (!DA_e && !_FP_FRAC_ZEROP_1(DA)) {
+ FP_SET_EXCEPTION(FP_EX_DENORM);
+ if (FP_DENORM_ZERO)
+ _FP_FRAC_SET_1(DA, _FP_ZEROFRAC_1);
+ }
+ if (!DB_e && !_FP_FRAC_ZEROP_1(DB)) {
+ FP_SET_EXCEPTION(FP_EX_DENORM);
+ if (FP_DENORM_ZERO)
+ _FP_FRAC_SET_1(DB, _FP_ZEROFRAC_1);
+ }
+ FP_CMP_D(res, DA, DB, 3);
+ vc = 0x4000000000000000;
+ /* CMPTEQ, CMPTUN don't trap on QNaN, while CMPTLT and CMPTLE do */
+ if (res == 3 && ((func & 3) >= 2 || FP_ISSIGNAN_D(DA) || FP_ISSIGNAN_D(DB)))
+ FP_SET_EXCEPTION(FP_EX_INVALID);
+ switch (func) {
+ case FOP_FNC_CMPxUN: if (res != 3) vc = 0; break;
+ case FOP_FNC_CMPxEQ: if (res) vc = 0; break;
+ case FOP_FNC_CMPxLT: if (res != -1) vc = 0; break;
+ case FOP_FNC_CMPxLE: if ((long)res > 0) vc = 0; break;
+ }
+ goto done_d;
+ }
+
+ FP_UNPACK_DP(DA, &va);
+ FP_UNPACK_DP(DB, &vb);
+
+ switch (func) {
+ case FOP_FNC_SUBx:
+ FP_SUB_D(DR, DA, DB);
+ goto pack_d;
+
+ case FOP_FNC_ADDx:
+ FP_ADD_D(DR, DA, DB);
+ goto pack_d;
+
+ case FOP_FNC_MULx:
+ FP_MUL_D(DR, DA, DB);
+ goto pack_d;
+
+ case FOP_FNC_DIVx:
+ FP_DIV_D(DR, DA, DB);
+ goto pack_d;
+
+ case FOP_FNC_SQRTx:
+ FP_SQRT_D(DR, DB);
+ goto pack_d;
+
+ case FOP_FNC_CVTxS:
+ /* It is irritating that DEC encoded CVTST with
+ SRC == T_floating. It is also interesting that
+ the bit used to tell the two apart is /U... */
+ if (insn & 0x2000) {
+ FP_CONV(S,D,1,1,SR,DB);
+ goto pack_s;
+ } else {
+ /* CVTST need do nothing else but copy the
+ bits and repack. */
+ DR_c = DB_c;
+ DR_s = DB_s;
+ DR_e = DB_e;
+ DR_f = DB_f;
+ goto pack_d;
+ }
+
+ case FOP_FNC_CVTxQ:
+ if (DB_c == FP_CLS_NAN && (_FP_FRAC_HIGH_RAW_D(DB) & _FP_QNANBIT_D))
+ vc = 0; /* AAHB Table B-2 sais QNaN should not trigger INV */
+ else
+ FP_TO_INT_ROUND_D(vc, DB, 64, 2);
+ goto done_d;
+ }
+ goto bad_insn;
+
+ case FOP_SRC_Q:
+ vb = alpha_read_fp_reg(fb);
+
+ switch (func) {
+ case FOP_FNC_CVTQL:
+ /* Notice: We can get here only due to an integer
+ overflow. Such overflows are reported as invalid
+ ops. We return the result the hw would have
+ computed. */
+ vc = ((vb & 0xc0000000) << 32 | /* sign and msb */
+ (vb & 0x3fffffff) << 29); /* rest of the int */
+ FP_SET_EXCEPTION (FP_EX_INVALID);
+ goto done_d;
+
+ case FOP_FNC_CVTxS:
+ FP_FROM_INT_S(SR, ((long)vb), 64, long);
+ goto pack_s;
+
+ case FOP_FNC_CVTxT:
+ FP_FROM_INT_D(DR, ((long)vb), 64, long);
+ goto pack_d;
+ }
+ goto bad_insn;
+ }
+ goto bad_insn;
+
+pack_s:
+ FP_PACK_SP(&vc, SR);
+ alpha_write_fp_reg_s(fc, vc);
+ goto done;
+
+pack_d:
+ FP_PACK_DP(&vc, DR);
+done_d:
+ alpha_write_fp_reg(fc, vc);
+ goto done;
+
+ /*
+ * Take the appropriate action for each possible
+ * floating-point result:
+ *
+ * - Set the appropriate bits in the FPCR
+ * - If the specified exception is enabled in the FPCR,
+ * return. The caller (entArith) will dispatch
+ * the appropriate signal to the translated program.
+ *
+ * In addition, properly track the exception state in software
+ * as described in the Alpha Architectre Handbook section 4.7.7.3.
+ */
+done:
+ if (_fex) {
+ /* Record exceptions in software control word. */
+ current->thread.flags
+ = fpcw |= (_fex << IEEE_STATUS_TO_EXCSUM_SHIFT);
+
+ /* Update hardware control register */
+ fpcr &= (~FPCR_MASK | FPCR_DYN_MASK);
+ fpcr |= ieee_swcr_to_fpcr(fpcw);
+ wrfpcr(fpcr);
+
+ /* Do we generate a signal? */
+ if (_fex & fpcw & IEEE_TRAP_ENABLE_MASK) {
+ MOD_DEC_USE_COUNT;
+ return 0;
+ }
+ }
+
+ /* We used to write the destination register here, but DEC FORTRAN
+ requires that the result *always* be written... so we do the write
+ immediately after the operations above. */
+
+ MOD_DEC_USE_COUNT;
+ return 1;
+
+bad_insn:
+ printk(KERN_ERR "alpha_fp_emul: Invalid FP insn %#x at %#lx\n",
+ insn, pc);
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+long
+alpha_fp_emul_imprecise (struct pt_regs *regs, unsigned long write_mask)
+{
+ unsigned long trigger_pc = regs->pc - 4;
+ unsigned long insn, opcode, rc;
+
+ MOD_INC_USE_COUNT;
+
+ /*
+ * Turn off the bits corresponding to registers that are the
+ * target of instructions that set bits in the exception
+ * summary register. We have some slack doing this because a
+ * register that is the target of a trapping instruction can
+ * be written at most once in the trap shadow.
+ *
+ * Branches, jumps, TRAPBs, EXCBs and calls to PALcode all
+ * bound the trap shadow, so we need not look any further than
+ * up to the first occurrence of such an instruction.
+ */
+ while (write_mask) {
+ get_user(insn, (__u32*)(trigger_pc));
+ opcode = insn >> 26;
+ rc = insn & 0x1f;
+
+ switch (opcode) {
+ case OPC_PAL:
+ case OPC_JSR:
+ case 0x30 ... 0x3f: /* branches */
+ MOD_DEC_USE_COUNT;
+ return 0;
+
+ case OPC_MISC:
+ switch (insn & 0xffff) {
+ case MISC_TRAPB:
+ case MISC_EXCB:
+ MOD_DEC_USE_COUNT;
+ return 0;
+
+ default:
+ break;
+ }
+ break;
+
+ case OPC_INTA:
+ case OPC_INTL:
+ case OPC_INTS:
+ case OPC_INTM:
+ write_mask &= ~(1UL << rc);
+ break;
+
+ case OPC_FLTC:
+ case OPC_FLTV:
+ case OPC_FLTI:
+ case OPC_FLTL:
+ write_mask &= ~(1UL << (rc + 32));
+ break;
+ }
+ if (!write_mask) {
+ if (alpha_fp_emul(trigger_pc)) {
+ /* re-execute insns in trap-shadow: */
+ regs->pc = trigger_pc + 4;
+ MOD_DEC_USE_COUNT;
+ return 1;
+ }
+ break;
+ }
+ trigger_pc -= 4;
+ }
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
--- /dev/null
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <asm/byteorder.h>
+#include <asm/fpu.h>
+
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+ ((sl) = (al) + (bl), (sh) = (ah) + (bh) + ((sl) < (al)))
+
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+ ((sl) = (al) - (bl), (sh) = (ah) - (bh) - ((al) < (bl)))
+
+#define umul_ppmm(wh, wl, u, v) \
+ __asm__ ("mulq %2,%3,%1; umulh %2,%3,%0" \
+ : "=r" ((UDItype)(wh)), \
+ "=&r" ((UDItype)(wl)) \
+ : "r" ((UDItype)(u)), \
+ "r" ((UDItype)(v)))
+
+extern void udiv128(unsigned long, unsigned long,
+ unsigned long, unsigned long,
+ unsigned long *,
+ unsigned long *);
+
+#define udiv_qrnnd(q, r, n1, n0, d) \
+ do { \
+ unsigned long xr, xi; \
+ udiv128((n0), (n1), 0, (d), &xr, &xi); \
+ (q) = xr; \
+ (r) = xi; \
+ } while (0)
+
+#define UDIV_NEEDS_NORMALIZATION 1
+
+#define abort() goto bad_insn
+
+#ifndef __LITTLE_ENDIAN
+#define __LITTLE_ENDIAN -1
+#endif
+#define __BYTE_ORDER __LITTLE_ENDIAN
}
#endif
+static void printk_memory_info(void)
+{
+ unsigned long codesize, reservedpages, datasize, initsize, tmp;
+ extern int page_is_ram(unsigned long) __init;
+ extern char _text, _etext, _data, _edata;
+ extern char __init_begin, __init_end;
+
+ /* printk all informations */
+ reservedpages = 0;
+ for (tmp = 0; tmp < max_low_pfn; tmp++)
+ /*
+ * Only count reserved RAM pages
+ */
+ if (page_is_ram(tmp) && PageReserved(mem_map+tmp))
+ reservedpages++;
+
+ codesize = (unsigned long) &_etext - (unsigned long) &_text;
+ datasize = (unsigned long) &_edata - (unsigned long) &_data;
+ initsize = (unsigned long) &__init_end - (unsigned long) &__init_begin;
+
+ printk("Memory: %luk/%luk available (%luk kernel code, %luk reserved, %luk data, %luk init)\n",
+ (unsigned long) nr_free_pages() << (PAGE_SHIFT-10),
+ max_mapnr << (PAGE_SHIFT-10),
+ codesize >> 10,
+ reservedpages << (PAGE_SHIFT-10),
+ datasize >> 10,
+ initsize >> 10);
+}
+
void
mem_init(void)
{
max_mapnr = num_physpages = max_low_pfn;
totalram_pages += free_all_bootmem();
- printk("Memory: %luk available\n", totalram_pages << (PAGE_SHIFT-10));
+
+ printk_memory_info();
}
void
ifeq ($(CONFIG_ARCH_ACORN),y)
SUBDIRS += drivers/acorn
DRIVERS += drivers/acorn/block/acorn-block.a
-DRIVERS += drivers/acorn/char/acorn-char.a
+DRIVERS += drivers/acorn/char/acorn-char.o
DRIVERS += drivers/acorn/net/acorn-net.a
DRIVERS += drivers/acorn/scsi/acorn-scsi.a
endif
}
}
+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;
+}
+
static u8 __init no_swizzle(struct pci_dev *dev, u8 *pin)
{
return 0;
#include <asm/hardware.h>
#include <asm/io.h>
#include <asm/irq.h>
-#include <asm/pgtable.h>
+#include <asm/pgalloc.h>
#include <asm/mmu_context.h>
#ifdef CONFIG_ARCH_ARC
b __real_stubs_start + (vector_IRQ - __stubs_start)
b __real_stubs_start + (vector_FIQ - __stubs_start)
-ENTRY(trap_init)
+ENTRY(__trap_init)
stmfd sp!, {r4 - r6, lr}
adr r1, .LCvectors @ set up the vectors
#include <asm/fiq.h>
#include <asm/io.h>
-#include <asm/pgtable.h>
+#include <asm/pgalloc.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
#include <asm/uaccess.h>
+unsigned long
+resource_fixup(struct pci_dev * dev, struct resource * res,
+ unsigned long start, unsigned long size)
+{
+ return start;
+}
+
#ifdef CONFIG_CPU_32
asmlinkage int sys_iopl(unsigned long turn_on)
{
* Origional Copyright (C) 1995 Linus Torvalds
*/
-/*
- * This file handles the architecture-dependent parts of process handling..
- */
-
#include <stdarg.h>
#include <linux/errno.h>
asmlinkage void ret_from_sys_call(void) __asm__("ret_from_sys_call");
-static int hlt_counter=0;
+static int hlt_counter;
void disable_hlt(void)
{
hlt_counter--;
}
+static int __init nohlt_setup(char *__unused)
+{
+ hlt_counter = 1;
+ return 0;
+}
+
+static int __init hlt_setup(char *__unused)
+{
+ hlt_counter = 0;
+ return 0;
+}
+
+__setup("nohlt", nohlt_setup);
+__setup("hlt", hlt_setup);
+
/*
* The idle loop on an ARM...
*/
mdelay(1000);
printk("Reboot failed -- System halted\n");
+ cli();
while (1);
}
flags = condition_codes(regs);
- printk( "pc : [<%08lx>] lr : [<%08lx>]\n"
- "sp : %08lx ip : %08lx fp : %08lx\n",
+ printk("pc : [<%08lx>] lr : [<%08lx>]\n"
+ "sp : %08lx ip : %08lx fp : %08lx\n",
instruction_pointer(regs),
regs->ARM_lr, regs->ARM_sp,
regs->ARM_ip, regs->ARM_fp);
- printk( "r10: %08lx r9 : %08lx r8 : %08lx\n",
+ printk("r10: %08lx r9 : %08lx r8 : %08lx\n",
regs->ARM_r10, regs->ARM_r9,
regs->ARM_r8);
- printk( "r7 : %08lx r6 : %08lx r5 : %08lx r4 : %08lx\n",
+ printk("r7 : %08lx r6 : %08lx r5 : %08lx r4 : %08lx\n",
regs->ARM_r7, regs->ARM_r6,
regs->ARM_r5, regs->ARM_r4);
- printk( "r3 : %08lx r2 : %08lx r1 : %08lx r0 : %08lx\n",
+ printk("r3 : %08lx r2 : %08lx r1 : %08lx r0 : %08lx\n",
regs->ARM_r3, regs->ARM_r2,
regs->ARM_r1, regs->ARM_r0);
printk("Flags: %c%c%c%c",
*
* Copyright (C) 1995-1999 Russell King
*/
-
-/*
- * This file obtains various parameters about the system that the kernel
- * is running on.
- */
-
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#define CONFIG_CMDLINE ""
#endif
-#ifndef PARAMS_BASE
-#define PARAMS_BASE NULL
-#endif
-
-extern void reboot_setup(char *str, int *ints);
+extern void reboot_setup(char *str);
extern void disable_hlt(void);
extern int root_mountflags;
extern int _stext, _text, _etext, _edata, _end;
struct meminfo meminfo;
+struct machine_desc {
+ const char *name; /* architecture name */
+ unsigned int param_offset; /* parameter page */
+ unsigned int reserve_lp0 :1; /* never has lp0 */
+ unsigned int reserve_lp1 :1; /* never has lp1 */
+ unsigned int reserve_lp2 :1; /* never has lp2 */
+ unsigned int broken_hlt :1; /* hlt is broken */
+ unsigned int soft_reboot :1; /* soft reboot */
+ unsigned int video_start; /* start of video RAM */
+ unsigned int video_end; /* end of video RAM */
+ void (*fixup)(struct machine_desc *,
+ struct param_struct *, char **);
+};
+
#ifdef MULTI_CPU
struct processor processor;
#endif
char saved_command_line[COMMAND_LINE_SIZE];
static struct proc_info_item proc_info;
+static const char *machine_name;
static char command_line[COMMAND_LINE_SIZE] = { 0, };
static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE;
* Standard memory resources
*/
static struct resource mem_res[] = {
- { "System RAM", 0, 0, IORESOURCE_MEM | IORESOURCE_BUSY },
{ "Video RAM", 0, 0, IORESOURCE_MEM },
{ "Kernel code", 0, 0, IORESOURCE_MEM },
{ "Kernel data", 0, 0, IORESOURCE_MEM }
};
-#define system_ram mem_res[0]
-#define video_ram mem_res[1]
-#define kernel_code mem_res[2]
-#define kernel_data mem_res[3]
+#define video_ram mem_res[0]
+#define kernel_code mem_res[1]
+#define kernel_data mem_res[2]
static struct resource io_res[] = {
{ "reserved", 0x3bc, 0x3be, IORESOURCE_IO | IORESOURCE_BUSY },
#ifdef MULTI_CPU
processor = *list->proc;
+
+ printk("Processor: %s %s revision %d\n",
+ proc_info.manufacturer, proc_info.cpu_name,
+ (int)processor_id & 15);
#endif
sprintf(system_utsname.machine, "%s%c", list->arch_name, ENDIANNESS);
setup_ramdisk(int doload, int prompt, int image_start, unsigned int rd_sz)
{
#ifdef CONFIG_BLK_DEV_RAM
- extern int rd_doload;
- extern int rd_prompt;
- extern int rd_image_start;
- extern int rd_size;
+ extern int rd_doload, rd_prompt, rd_image_start, rd_size;
rd_image_start = image_start;
rd_prompt = prompt;
#endif
}
-static void __init request_standard_resources(void)
+static void __init request_standard_resources(struct machine_desc *mdesc)
{
- kernel_code.start = __virt_to_bus((unsigned long) &_text);
- kernel_code.end = __virt_to_bus((unsigned long) &_etext - 1);
- kernel_data.start = __virt_to_bus((unsigned long) &_etext);
- kernel_data.end = __virt_to_bus((unsigned long) &_edata - 1);
- system_ram.start = __virt_to_bus(PAGE_OFFSET);
- system_ram.end = __virt_to_bus(meminfo.end + PAGE_OFFSET - 1);
-
- request_resource(&iomem_resource, &system_ram);
- request_resource(&system_ram, &kernel_code);
- request_resource(&system_ram, &kernel_data);
-
- if (video_ram.start != video_ram.end)
+ struct resource *res;
+ int i;
+
+ kernel_code.start = __virt_to_bus(init_mm.start_code);
+ kernel_code.end = __virt_to_bus(init_mm.end_code - 1);
+ kernel_data.start = __virt_to_bus(init_mm.end_code);
+ kernel_data.end = __virt_to_bus(init_mm.brk - 1);
+
+ for (i = 0; i < meminfo.nr_banks; i++) {
+ unsigned long virt_start, virt_end;
+
+ if (meminfo.bank[i].size == 0)
+ continue;
+
+ virt_start = __phys_to_virt(meminfo.bank[i].start);
+ virt_end = virt_start + meminfo.bank[i].size - 1;
+
+ res = alloc_bootmem(sizeof(*res));
+ res->name = "System RAM";
+ res->start = __virt_to_bus(virt_start);
+ res->end = __virt_to_bus(virt_end);
+ res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
+
+ request_resource(&iomem_resource, res);
+
+ if (kernel_code.start >= res->start &&
+ kernel_code.end <= res->end)
+ request_resource(res, &kernel_code);
+ if (kernel_data.start >= res->start &&
+ kernel_data.end <= res->end)
+ request_resource(res, &kernel_data);
+ }
+
+ if (mdesc->video_start) {
+ video_ram.start = mdesc->video_start;
+ video_ram.end = mdesc->video_end;
request_resource(&iomem_resource, &video_ram);
+ }
/*
* Some machines don't have the possibility of ever
- * possessing LPT1 (lp0) and LPT3 (lp2)
+ * possessing lp0, lp1 or lp2
*/
- if (machine_is_ebsa110() || machine_is_riscpc() ||
- machine_is_netwinder())
+ if (mdesc->reserve_lp0)
request_resource(&ioport_resource, &lp0);
- if (machine_is_riscpc())
+ if (mdesc->reserve_lp1)
request_resource(&ioport_resource, &lp1);
- if (machine_is_ebsa110() || machine_is_netwinder())
+ if (mdesc->reserve_lp2)
request_resource(&ioport_resource, &lp2);
}
-void __init setup_arch(char **cmdline_p)
+/*
+ * Architecture specific fixups. This is where any
+ * parameters in the params struct are fixed up, or
+ * any additional architecture specific information
+ * is pulled from the params struct.
+ */
+static void __init
+fixup_acorn(struct machine_desc *desc, struct param_struct *params,
+ char **cmdline)
{
- struct param_struct *params = (struct param_struct *)PARAMS_BASE;
- char *from = default_command_line;
-
-#if defined(CONFIG_ARCH_ARC)
- __machine_arch_type = MACH_TYPE_ARCHIMEDES;
-#elif defined(CONFIG_ARCH_A5K)
- __machine_arch_type = MACH_TYPE_A5K;
-#endif
-
- setup_processor();
-
- /*
- * Defaults
- */
- ROOT_DEV = MKDEV(0, 255);
- setup_ramdisk(1, 1, 0, 0);
-
- /*
- * Add your machine dependencies here
- */
- switch (machine_arch_type) {
- case MACH_TYPE_EBSA110:
- /* EBSA110 locks if we execute 'wait for interrupt' */
- disable_hlt();
- if (params && params->u1.s.page_size != PAGE_SIZE)
- params = NULL;
- break;
-
#ifdef CONFIG_ARCH_ACORN
-#ifdef CONFIG_ARCH_RPC
- case MACH_TYPE_RISCPC:
- /* RiscPC can't handle half-word loads and stores */
+ int i;
+
+ if (machine_is_riscpc()) {
+ /*
+ * RiscPC can't handle half-word loads and stores
+ */
elf_hwcap &= ~HWCAP_HALF;
switch (params->u1.s.pages_in_vram) {
default:
break;
}
- {
- int i;
-
- for (i = 0; i < 4; i++) {
- meminfo.bank[i].start = i << 26;
- meminfo.bank[i].size =
- params->u1.s.pages_in_bank[i] *
- params->u1.s.page_size;
- }
- meminfo.nr_banks = 4;
+
+ if (vram_size) {
+ desc->video_start = 0x02000000;
+ desc->video_end = 0x02000000 + vram_size;
}
-#endif
- case MACH_TYPE_ARCHIMEDES:
- case MACH_TYPE_A5K:
- memc_ctrl_reg = params->u1.s.memc_control_reg;
- number_mfm_drives = (params->u1.s.adfsdrives >> 3) & 3;
- break;
-#endif
- case MACH_TYPE_EBSA285:
- if (params) {
- ORIG_X = params->u1.s.video_x;
- ORIG_Y = params->u1.s.video_y;
- ORIG_VIDEO_COLS = params->u1.s.video_num_cols;
- ORIG_VIDEO_LINES = params->u1.s.video_num_rows;
- video_ram.start = 0x0a0000;
- video_ram.end = 0x0bffff;
+ for (i = 0; i < 4; i++) {
+ meminfo.bank[i].start = i << 26;
+ meminfo.bank[i].size =
+ params->u1.s.pages_in_bank[i] *
+ params->u1.s.page_size;
}
- break;
+ meminfo.nr_banks = 4;
+ }
+ memc_ctrl_reg = params->u1.s.memc_control_reg;
+ number_mfm_drives = (params->u1.s.adfsdrives >> 3) & 3;
+#endif
+}
+
+static void __init
+fixup_ebsa285(struct machine_desc *desc, struct param_struct *params,
+ char **cmdline)
+{
+ ORIG_X = params->u1.s.video_x;
+ ORIG_Y = params->u1.s.video_y;
+ ORIG_VIDEO_COLS = params->u1.s.video_num_cols;
+ ORIG_VIDEO_LINES = params->u1.s.video_num_rows;
+}
- case MACH_TYPE_CO285:
- {
+/*
+ * Older NeTTroms either do not provide a parameters
+ * page, or they don't supply correct information in
+ * the parameter page.
+ */
+static void __init
+fixup_netwinder(struct machine_desc *desc, struct param_struct *params,
+ char **cmdline)
+{
+ if (params->u1.s.nr_pages != 0x2000 &&
+ params->u1.s.nr_pages != 0x4000) {
+ printk(KERN_WARNING "Warning: bad NeTTrom parameters "
+ "detected, using defaults\n");
+
+ params->u1.s.nr_pages = 0x2000; /* 32MB */
+ params->u1.s.ramdisk_size = 0;
+ params->u1.s.flags = FLAG_READONLY;
+ params->u1.s.initrd_start = 0;
+ params->u1.s.initrd_size = 0;
+ params->u1.s.rd_start = 0;
+ }
+}
+
+/*
+ * CATS uses soft-reboot by default, since
+ * hard reboots fail on early boards.
+ */
+static void __init
+fixup_cats(struct machine_desc *desc, struct param_struct *params,
+ char **cmdline)
+{
+ ORIG_VIDEO_LINES = 25;
+ ORIG_VIDEO_POINTS = 16;
+ ORIG_Y = 24;
+}
+
+static void __init
+fixup_coebsa285(struct machine_desc *desc, struct param_struct *params,
+ char **cmdline)
+{
#if 0
- extern unsigned long boot_memory_end;
- extern char boot_command_line[];
+ if (machine_is_co285()) {
+ extern unsigned long boot_memory_end;
+ extern char boot_command_line[];
- from = boot_command_line;
- memory_end = boot_memory_end;
-#endif
- params = NULL;
- }
- break;
+ meminfo.nr_banks = 1;
+ meminfo.bank[0].start = PHYS_OFFSET;
+ meminfo.bank[0].size = boot_memory_end;
- case MACH_TYPE_CATS:
- /* CATS uses soft-reboot by default, since hard reboots
- * fail on early boards.
- */
- reboot_setup("s", NULL);
- params = NULL;
- ORIG_VIDEO_LINES = 25;
- ORIG_VIDEO_POINTS = 16;
- ORIG_Y = 24;
- video_ram.start = 0x0a0000;
- video_ram.end = 0x0bffff;
- break;
+ *cmdline = boot_command_line;
+ }
+#endif
+}
- case MACH_TYPE_NETWINDER:
- /*
- * to be fixed in a future NeTTrom
- */
- if (params->u1.s.page_size == PAGE_SIZE) {
- if (params->u1.s.nr_pages != 0x2000 &&
- params->u1.s.nr_pages != 0x4000) {
- printk("Warning: bad NeTTrom parameters detected, using defaults\n");
- /*
- * This stuff doesn't appear to be initialised
- * properly by NeTTrom 2.0.6 and 2.0.7
- */
- params->u1.s.nr_pages = 0x2000; /* 32MB */
- params->u1.s.ramdisk_size = 0;
- params->u1.s.flags = FLAG_READONLY;
- params->u1.s.initrd_start = 0;
- params->u1.s.initrd_size = 0;
- params->u1.s.rd_start = 0;
- }
- } else {
- printk("Warning: no NeTTrom parameter page detected, using "
- "compiled-in settings\n");
- params = NULL;
- }
- video_ram.start = 0x0a0000;
- video_ram.end = 0x0bffff;
- break;
+#define NO_PARAMS 0
+#define NO_VIDEO 0, 0
- default:
- break;
+/*
+ * This is the list of all architectures supported by
+ * this kernel. This should be integrated with the list
+ * in head-armv.S.
+ */
+static struct machine_desc machine_desc[] __initdata = {
+ { "EBSA110", /* RMK */
+ 0x00000400,
+ NO_VIDEO,
+ 1, 0, 1, 1, 1,
+ NULL
+ }, { "Acorn-RiscPC", /* RMK */
+ 0x10000100,
+ NO_VIDEO,
+ 1, 1, 0, 0, 0,
+ fixup_acorn
+ }, { "unknown",
+ NO_PARAMS,
+ NO_VIDEO,
+ 0, 0, 0, 0, 0,
+ NULL
+ }, { "Nexus-FTV/PCI", /* Philip Blundell */
+ NO_PARAMS,
+ NO_VIDEO,
+ 0, 0, 0, 0, 0,
+ NULL
+ }, { "EBSA285", /* RMK */
+ 0x00000100,
+ 0x000a0000, 0x000bffff,
+ 0, 0, 0, 0, 0,
+ fixup_ebsa285
+ }, { "Rebel-NetWinder", /* RMK */
+ 0x00000100,
+ 0x000a0000, 0x000bffff,
+ 1, 0, 1, 0, 0,
+ fixup_netwinder
+ }, { "Chalice-CATS", /* Philip Blundell */
+ NO_PARAMS,
+ 0x000a0000, 0x000bffff,
+ 0, 0, 0, 0, 1,
+ fixup_cats
+ }, { "unknown-TBOX", /* Philip Blundell */
+ NO_PARAMS,
+ NO_VIDEO,
+ 0, 0, 0, 0, 0,
+ NULL
+ }, { "co-EBSA285", /* Mark van Doesburg */
+ NO_PARAMS,
+ NO_VIDEO,
+ 0, 0, 0, 0, 0,
+ fixup_coebsa285
+ }, { "CL-PS7110", /* Werner Almesberger */
+ NO_PARAMS,
+ NO_VIDEO,
+ 0, 0, 0, 0, 0,
+ NULL
+ }, { "Acorn-Archimedes",/* RMK/DAG */
+ 0x0207c000,
+ NO_VIDEO,
+ 0, 0, 0, 0, 0,
+ fixup_acorn
+ }, { "Acorn-A5000", /* RMK/PB */
+ 0x0207c000,
+ NO_VIDEO,
+ 0, 0, 0, 0, 0,
+ fixup_acorn
+ }, { "Etoile", /* Alex de Vries */
+ NO_PARAMS,
+ NO_VIDEO,
+ 0, 0, 0, 0, 0,
+ NULL
+ }, { "LaCie_NAS", /* Benjamin Herrenschmidt */
+ NO_PARAMS,
+ NO_VIDEO,
+ 0, 0, 0, 0, 0,
+ NULL
+ }, { "CL-PS7500", /* Philip Blundell */
+ NO_PARAMS,
+ NO_VIDEO,
+ 0, 0, 0, 0, 0,
+ NULL
+ }, { "Shark", /* Alexander Schulz */
+ NO_PARAMS,
+ NO_VIDEO,
+ 0, 0, 0, 0, 0,
+ NULL
}
+};
+
+void __init setup_arch(char **cmdline_p)
+{
+ struct param_struct *params = NULL;
+ struct machine_desc *mdesc;
+ char *from = default_command_line;
+
+#if defined(CONFIG_ARCH_ARC)
+ __machine_arch_type = MACH_TYPE_ARCHIMEDES;
+#elif defined(CONFIG_ARCH_A5K)
+ __machine_arch_type = MACH_TYPE_A5K;
+#endif
+
+ setup_processor();
+
+ ROOT_DEV = MKDEV(0, 255);
+
+ mdesc = machine_desc + machine_arch_type;
+ machine_name = mdesc->name;
+
+ if (mdesc->broken_hlt)
+ disable_hlt();
+
+ if (mdesc->soft_reboot)
+ reboot_setup("s");
+
+ if (mdesc->param_offset)
+ params = phys_to_virt(mdesc->param_offset);
+
+ if (mdesc->fixup)
+ mdesc->fixup(mdesc, params, &from);
if (params && params->u1.s.page_size != PAGE_SIZE) {
- printk("Warning: wrong page size configuration, "
+ printk(KERN_WARNING "Warning: bad configuration page, "
"trying to continue\n");
params = NULL;
}
if (params) {
- if (meminfo.nr_banks == 0) {
- meminfo.nr_banks = 1;
- meminfo.bank[0].start = 0;
- meminfo.bank[0].size = params->u1.s.nr_pages << PAGE_SHIFT;
- }
ROOT_DEV = to_kdev_t(params->u1.s.rootdev);
system_rev = params->u1.s.system_rev;
system_serial_low = params->u1.s.system_serial_low;
if (meminfo.nr_banks == 0) {
meminfo.nr_banks = 1;
meminfo.bank[0].start = 0;
- meminfo.bank[0].size = MEM_SIZE;
+ if (params)
+ meminfo.bank[0].size = params->u1.s.nr_pages << PAGE_SHIFT;
+ else
+ meminfo.bank[0].size = MEM_SIZE;
}
init_mm.start_code = (unsigned long) &_text;
init_mm.end_data = (unsigned long) &_edata;
init_mm.brk = (unsigned long) &_end;
- /* Save unparsed command line copy for /proc/cmdline */
memcpy(saved_command_line, from, COMMAND_LINE_SIZE);
saved_command_line[COMMAND_LINE_SIZE-1] = '\0';
parse_cmdline(cmdline_p, from);
setup_bootmem();
- request_standard_resources();
+ request_standard_resources(mdesc);
#ifdef CONFIG_VT
#if defined(CONFIG_VGA_CONSOLE)
#endif
}
-static const char *machine_desc[] = {
- /* Machine name Allocater */
- "EBSA110", /* RMK */
- "Acorn-RiscPC", /* RMK */
- "unknown",
- "Nexus-FTV/PCI", /* Philip Blundell */
- "EBSA285", /* RMK */
- "Rebel-NetWinder", /* RMK */
- "Chalice-CATS", /* Philip Blundell */
- "unknown-TBOX", /* Philip Blundell */
- "co-EBSA285", /* Mark van Doesburg */
- "CL-PS7110", /* Werner Almesberger */
- "Acorn-Archimedes", /* RMK/DAG */
- "Acorn-A5000", /* RMK/PB */
- "Etoile", /* Alex de Vries */
- "LaCie_NAS", /* Benjamin Herrenschmidt */
- "CL-PS7500", /* Philip Blundell */
- "Shark" /* Alexander Schulz */
-};
-
int get_cpuinfo(char * buffer)
{
char *p = buffer;
(loops_per_sec+2500) / 500000,
((loops_per_sec+2500) / 5000) % 100);
- p += sprintf(p, "Hardware\t: %s\n",
- machine_desc[machine_arch_type]);
+ p += sprintf(p, "Hardware\t: %s\n", machine_name);
p += sprintf(p, "Revision\t: %04x\n",
system_rev);
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/spinlock.h>
+#include <linux/init.h>
#include <asm/system.h>
#include <asm/uaccess.h>
printk("Division by zero in kernel.\n");
__backtrace();
}
+
+void __init trap_init(void)
+{
+ extern void __trap_init(void);
+
+ __trap_init();
+#ifdef CONFIG_CPU_32
+ modify_domain(DOMAIN_USER, DOMAIN_CLIENT);
+#endif
+}
unsigned int codepages, datapages, initpages;
int i;
+ codepages = &_etext - &_text;
+ datapages = &_end - &_etext;
+ initpages = &__init_end - &__init_begin;
+
max_mapnr = max_low_pfn;
high_memory = (void *)__va(max_low_pfn * PAGE_SIZE);
* Since our memory may not be contiguous, calculate the
* real number of pages we have in this system
*/
+ printk("Memory:");
+
num_physpages = 0;
- for (i = 0; i < meminfo.nr_banks; i++)
+ for (i = 0; i < meminfo.nr_banks; i++) {
num_physpages += meminfo.bank[i].size >> PAGE_SHIFT;
+ printk(" %ldMB", meminfo.bank[i].size >> 20);
+ }
- codepages = (int)&_etext - &_text;
- datapages = (int)&_end - &_etext;
- initpages = (int)&__init_end - &__init_start;
-
- printk("Memory: %luk/%luM available (%dK code, %dK data, %dK init)\n",
+ printk(" = %luMB total\n", num_physpages >> (20 - PAGE_SHIFT));
+ printk("Memory: %luKB available (%dK code, %dK data, %dK init)\n",
(unsigned long) nr_free_pages() << (PAGE_SHIFT-10),
- num_physpages >> (20 - PAGE_SHIFT),
- codepages << (PAGE_SHIFT-10),
- datapages << (PAGE_SHIFT-10),
- initpages << (PAGE_SHIFT-10));
+ codepages >> 10, datapages >> 10, initpages >> 10);
-#ifdef CONFIG_CPU_26
- if (max_mapnr <= 128) {
+ if (PAGE_SIZE >= 16384 && max_mapnr <= 128) {
extern int sysctl_overcommit_memory;
- /* On a machine this small we won't get anywhere without
- overcommit, so turn it on by default. */
+ /*
+ * On a machine this small we won't get
+ * anywhere without overcommit, so turn
+ * it on by default.
+ */
sysctl_overcommit_memory = 1;
}
-#endif
}
static inline void free_area(unsigned long addr, unsigned long end, char *s)
printk("\n");
}
+#ifdef CONFIG_BLK_DEV_INITRD
+void free_initrd_mem(unsigned long start, unsigned long end)
+{
+ for (; start < end; start += PAGE_SIZE) {
+ ClearPageReserved(mem_map + MAP_NR(start));
+ set_page_count(mem_map+MAP_NR(start), 1);
+ free_page(start);
+ totalram_pages++;
+ }
+ printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10);
+}
+#endif
+
void si_meminfo(struct sysinfo *val)
{
val->totalram = totalram_pages;
extern void free_page_2k(unsigned long page);
extern pte_t *get_bad_pte_table(void);
+/*
+ * These are useful for identifing cache coherency
+ * problems by allowing the cache or the cache and
+ * writebuffer to be turned off. (Note: the write
+ * buffer should not be on and the cache off).
+ */
+static int __init nocache_setup(char *__unused)
+{
+ cr_alignment &= ~4;
+ cr_no_alignment &= ~4;
+ set_cr(cr_alignment);
+}
+
+static int __init nowrite_setup(char *__unused)
+{
+ cr_alignment &= ~(8|4);
+ cr_no_alignment &= ~(8|4);
+ set_cr(cr_alignment);
+}
+
+__setup("nocache", nocache_setup);
+__setup("nowb", nowrite_setup);
+
/*
* need to get a 16k page for level 1
*/
{
unsigned int start_pfn, end_pfn = -1;
struct page *pg = NULL;
- unsigned int sz, i;
+ unsigned int i;
for (i = 0; i < meminfo.nr_banks; i++) {
if (meminfo.bank[i].size == 0)
bics pc, lr, #0x04000000 @ Clear FIQ disable bit
armvlsi_name: .asciz "ARM/VLSI"
-_arm2_name: .asciz "arm2"
-_arm250_name: .asciz "arm250"
-_arm3_name: .asciz "arm3"
+_arm2_name: .asciz "ARM 2"
+_arm250_name: .asciz "ARM 250"
+_arm3_name: .asciz "ARM 3"
.section ".text.init", #alloc, #execinstr
/*
cpu_armvlsi_name:
.asciz "ARM/VLSI"
-cpu_arm6_name: .asciz "arm6"
+cpu_arm6_name: .asciz "ARM 6"
cpu_arm610_name:
- .asciz "arm610"
-cpu_arm7_name: .asciz "arm7"
+ .asciz "ARM 610"
+cpu_arm7_name: .asciz "ARM 7"
cpu_arm710_name:
- .asciz "arm710"
+ .asciz "ARM 710"
.align
.section ".text.init", #alloc, #execinstr
cpu_manu_name: .asciz "Intel"
ENTRY(cpu_sa110_name)
- .asciz "sa110"
+ .asciz "StrongARM-110"
ENTRY(cpu_sa1100_name)
- .asciz "sa1100"
+ .asciz "StrongARM-1100"
.align
.section ".text.init", #alloc, #execinstr
extern void dump_thread(struct pt_regs *, struct user *);
extern int dump_fpu(elf_fpregset_t *);
+#ifdef __SMP__
+extern void FASTCALL( __write_lock_failed(rwlock_t *rw));
+extern void FASTCALL( __read_lock_failed(rwlock_t *rw));
+#endif
+
#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_HD) || defined(CONFIG_BLK_DEV_IDE_MODULE) || defined(CONFIG_BLK_DEV_HD_MODULE)
extern struct drive_info_struct drive_info;
EXPORT_SYMBOL(drive_info);
EXPORT_SYMBOL(smp_num_cpus);
EXPORT_SYMBOL(cpu_present_map);
EXPORT_SYMBOL(cpu_online_map);
+EXPORT_SYMBOL_NOVERS(__write_lock_failed);
+EXPORT_SYMBOL_NOVERS(__read_lock_failed);
/* Global SMP irq stuff */
EXPORT_SYMBOL(synchronize_irq);
static inline void do_flush_tlb_all_local(void)
{
local_flush_tlb();
- if(current->mm==0) {
+ if (!current->mm && current->active_mm) {
unsigned long cpu = smp_processor_id();
- clear_bit(cpu, ¤t->active_mm->cpu_vm_mask);
+ clear_bit(cpu, ¤t->active_mm->cpu_vm_mask);
cpu_tlbbad[cpu] = 1;
}
}
void flush_tlb_all(void)
{
- if(cpu_online_map ^ (1<<smp_processor_id()))
- smp_call_function (flush_tlb_all_ipi,0,1,1);
+ if (cpu_online_map ^ (1 << smp_processor_id()))
+ while (smp_call_function (flush_tlb_all_ipi,0,0,1) == -EBUSY)
+ mb();
do_flush_tlb_all_local();
}
* Permanent kmaps:
*/
vaddr = PKMAP_BASE;
- fixrange_init(vaddr, vaddr + 4*1024*1024, pgd_base);
+ fixrange_init(vaddr, vaddr + PAGE_SIZE*LAST_PKMAP, pgd_base);
pgd = swapper_pg_dir + __pgd_offset(vaddr);
pmd = pmd_offset(pgd, vaddr);
/* now swapping to this device ok */
p->pages = j + k;
+ swap_list_lock();
nr_swap_pages += j;
p->flags = SWP_WRITEOK;
} else {
swap_info[prev].next = p - swap_info;
}
+ swap_list_unlock();
printk( KERN_INFO "Using %dk (%d pages) of ST-RAM as swap space.\n",
p->pages << 2, p->pages );
DPRINTK("unswap: map[i=%lu]=%u nr_swap=%u\n",
i, map[i], nr_swap_pages);
+ swap_device_lock(stram_swap_info);
+ map[i]++;
+ swap_device_unlock(stram_swap_info);
/* Get a page for the entry, using the existing
swap cache page if there is one. Otherwise,
get a clean page and read the swap into it. */
stat_swap_force++;
#endif
}
- else if (map[i])
+ else {
+ swap_free(entry);
return -ENOMEM;
+ }
}
DPRINTK( "unswap: map[i=%lu]=%u nr_swap=%u\n",
i, map[i], nr_swap_pages );
+ swap_list_lock();
+ swap_device_lock(stram_swap_info);
map[i] = SWAP_MAP_BAD;
if (stram_swap_info->lowest_bit == i)
stram_swap_info->lowest_bit++;
if (stram_swap_info->highest_bit == i)
stram_swap_info->highest_bit--;
--nr_swap_pages;
+ swap_device_unlock(stram_swap_info);
+ swap_list_unlock();
}
return 0;
return;
}
+ swap_list_lock();
+ swap_device_lock(stram_swap_info);
/* un-reserve the freed pages */
for( ; n_pages > 0; ++offset, --n_pages ) {
if (map[offset] != SWAP_MAP_BAD)
if (stram_swap_info->prio > swap_info[swap_list.next].prio)
swap_list.next = swap_list.head;
nr_swap_pages += n_pages;
+ swap_device_unlock(stram_swap_info);
+ swap_list_unlock();
}
\f
else
ifdef CONFIG_8xx
HEAD := arch/ppc/kernel/head_8xx.o
+ else
+ HEAD := arch/ppc/kernel/head.o
endif
- HEAD := arch/ppc/kernel/head.o
endif
ARCH_SUBDIRS = arch/ppc/kernel arch/ppc/mm arch/ppc/lib
LD = $(CROSS_COMPILE)ld
CFLAGS = -O -fno-builtin -I$(TOPDIR)/include
OBJCOPY = $(CROSS_COMPILE)objcopy
-OBJCOPY_ARGS = -O aixcoff-rs6000 -R .stab -R .stabstr -R .comment \
- --add-section=image=vmlinux.gz
-LD_ARGS = -e _start -T ld.script -Ttext 500000 -Tdata 510000 -Bstatic
+OBJCOPY_ARGS = -O aixcoff-rs6000 -R .stab -R .stabstr -R .comment
+COFF_LD_ARGS = -e _start -T ld.script -Ttext 500000 -Tdata 510000 -Bstatic
+CHRP_LD_ARGS = -Ttext 0x00400000
GZ = gzip -9
-OBJS = crt0.o start.o main.o misc.o string.o zlib.o
+COFFOBJS = coffcrt0.o start.o coffmain.o misc.o string.o zlib.o image.o
+CHRPOBJS = crt0.o start.o chrpmain.o misc.o string.o zlib.o image.o
LIBS = $(TOPDIR)/lib/lib.a
-ifeq ($(CONFIG_ALL_PPC),y)
-# yes, we want to build pmac stuff
-CONFIG_PMAC = y
-endif
-
ifeq ($(CONFIG_PPC64),y)
MSIZE=.64
else
MSIZE=
endif
+ifeq ($(CONFIG_ALL_PPC),y)
+# yes, we want to build pmac stuff
+CONFIG_PMAC = y
+endif
+
ifeq ($(CONFIG_SMP),y)
TFTPIMAGE=/tftpboot/zImage.pmac.smp$(MSIZE)
else
hack-coff: hack-coff.c
$(HOSTCC) $(HOSTCFLAGS) -o hack-coff hack-coff.c
+znetboot: vmlinux.coff zImage
+ cp vmlinux.coff $(TFTPIMAGE)
+
+znetboot.initrd: vmlinux.coff.initrd
+ cp vmlinux.coff.initrd $(TFTPIMAGE)
+
floppy: zImage
# mount -t hfs /dev/fd0 /mnt
# cp vmlinux.coff /mnt
# umount /mnt
-znetboot: vmlinux.coff
- cp vmlinux.coff $(TFTPIMAGE)
+coffboot: $(COFFOBJS) no_initrd.o ld.script
+ $(LD) -o $@ $(COFF_LD_ARGS) $(COFFOBJS) no_initrd.o $(LIBS)
-znetboot.initrd: vmlinux.coff.initrd
- cp vmlinux.coff.initrd $(TFTPIMAGE)
+coffboot.initrd: $(COFFOBJS) initrd.o ld.script
+ $(LD) -o $@ $(COFF_LD_ARGS) $(COFFOBJS) initrd.o $(LIBS)
-coffboot: $(OBJS) ld.script
- $(LD) -o coffboot $(LD_ARGS) $(OBJS) $(LIBS)
+piggyback: piggyback.c
+ $(HOSTCC) $(HOSTCFLAGS) -DKERNELBASE=$(KERNELBASE) -o piggyback piggyback.c
-zImage: vmlinux.coff
+mknote: mknote.c
+ $(HOSTCC) $(HOSTCFLAGS) -o mknote mknote.c
-zImage.initrd: vmlinux.coff.initrd
+image.o: piggyback vmlinux.gz
+ ./piggyback image < vmlinux.gz | $(AS) -o image.o
-vmlinux.coff: coffboot hack-coff vmlinux.gz
+initrd.o: ramdisk.image.gz piggyback
+ ./piggyback initrd < ramdisk.image.gz | $(AS) -o initrd.o
+
+vmlinux.coff: coffboot hack-coff
$(OBJCOPY) $(OBJCOPY_ARGS) coffboot $@
./hack-coff $@
ln -sf vmlinux.coff zImage
-vmlinux.coff.initrd: coffboot hack-coff vmlinux.gz ramdisk.image.gz
- $(OBJCOPY) $(OBJCOPY_ARGS) --add-section=initrd=ramdisk.image.gz \
- coffboot $@
+vmlinux.coff.initrd: coffboot.initrd hack-coff
+ $(OBJCOPY) $(OBJCOPY_ARGS) coffboot $@
./hack-coff $@
+vmlinux.elf: $(CHRPOBJS) no_initrd.o mknote
+ $(LD) $(CHRP_LD_ARGS) -o $@ $(CHRPOBJS) no_initrd.o $(LIBS)
+ ./mknote > note
+ $(OBJCOPY) $@ $@ --add-section=.note=note -R .comment
+
+vmlinux.elf.initrd: $(CHRPOBJS) initrd.o mknote
+ $(LD) $(CHRP_LD_ARGS) -o $@ $(CHRPOBJS) initrd.o $(LIBS)
+ ./mknote > note
+ $(OBJCOPY) $@ $@ --add-section=.note=note -R .comment
+
+zImage: vmlinux.coff vmlinux.elf
+
+zImage.initrd: vmlinux.coff.initrd vmlinux.elf.initrd
+
else
znetboot: vmlinux.gz
--- /dev/null
+/*
+ * Copyright (C) Paul Mackerras 1997.
+ *
+ * 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.
+ */
+#include "nonstdio.h"
+#include "zlib.h"
+#include <asm/bootinfo.h>
+#include <asm/processor.h>
+#define __KERNEL__
+#include <asm/page.h>
+
+extern void *finddevice(const char *);
+extern int getprop(void *, const char *, void *, int);
+void make_bi_recs(unsigned long);
+void gunzip(void *, int, unsigned char *, int *);
+void stop_imac_ethernet(void);
+void stop_imac_usb(void);
+
+#define get_16be(x) (*(unsigned short *)(x))
+#define get_32be(x) (*(unsigned *)(x))
+
+#define RAM_START 0x00000000
+#define RAM_END (8<<20)
+
+#define PROG_START 0x00010000
+
+char *avail_ram;
+char *end_avail;
+
+extern char _end[];
+extern char image_data[];
+extern int image_len;
+extern char initrd_data[];
+extern int initrd_len;
+
+
+boot(int a1, int a2, void *prom)
+{
+ int ns, oh, i;
+ unsigned sa, len;
+ void *dst;
+ unsigned char *im;
+ unsigned initrd_start, initrd_size;
+ extern char _start;
+
+ printf("chrpboot starting: loaded at 0x%x\n", &_start);
+ if (initrd_len) {
+ initrd_size = initrd_len;
+ initrd_start = (RAM_END - initrd_size) & ~0xFFF;
+ a1 = initrd_start;
+ a2 = initrd_size;
+ claim(initrd_start, RAM_END - initrd_start, 0);
+ printf("initial ramdisk moving 0x%x <- 0x%x (%x bytes)\n", initrd_start,
+ initrd_data,initrd_size);
+ memcpy((char *)initrd_start, initrd_data, initrd_size);
+ }
+ im = image_data;
+ len = image_len;
+ /* claim 3MB starting at PROG_START */
+ claim(PROG_START, 3 << 20, 0);
+ dst = (void *) PROG_START;
+ if (im[0] == 0x1f && im[1] == 0x8b) {
+ /* claim 512kB for scratch space */
+ avail_ram = (char *) claim(0, 512 << 10, 0x10);
+ end_avail = avail_ram + (512 << 10);
+ printf("avail_ram = %x\n", avail_ram);
+ printf("gunzipping (0x%x <- 0x%x:0x%0x)...", dst, im, im+len);
+ gunzip(dst, 3 << 20, im, &len);
+ printf("done %u bytes\n", len);
+ } else {
+ memmove(dst, im, len);
+ }
+
+ flush_cache(dst, len);
+ stop_imac_ethernet();
+ stop_imac_usb();
+ make_bi_recs((unsigned long) dst + len);
+
+ sa = (unsigned long)PROG_START;
+ printf("start address = 0x%x\n", sa);
+
+ (*(void (*)())sa)(0, 0, prom, a1, a2);
+
+ printf("returned?\n");
+
+ pause();
+}
+
+void make_bi_recs(unsigned long addr)
+{
+ struct bi_record *rec;
+
+ rec = (struct bi_record *)PAGE_ALIGN(addr);
+
+ rec->tag = BI_FIRST;
+ rec->size = sizeof(struct bi_record);
+ rec = (struct bi_record *)((unsigned long)rec + rec->size);
+
+ rec->tag = BI_BOOTLOADER_ID;
+ sprintf( (char *)rec->data, "coffboot");
+ rec->size = sizeof(struct bi_record) + strlen("coffboot") + 1;
+ rec = (struct bi_record *)((unsigned long)rec + rec->size);
+
+ rec->tag = BI_MACHTYPE;
+ rec->data[0] = _MACH_Pmac;
+ rec->data[1] = 1;
+ rec->size = sizeof(struct bi_record) + sizeof(unsigned long);
+ rec = (struct bi_record *)((unsigned long)rec + rec->size);
+
+ rec->tag = BI_LAST;
+ rec->size = sizeof(struct bi_record);
+ rec = (struct bi_record *)((unsigned long)rec + rec->size);
+}
+
+#define eieio() asm volatile("eieio");
+
+void stop_imac_ethernet(void)
+{
+ void *macio, *enet;
+ unsigned int macio_addr[5], enet_reg[6];
+ int len;
+ volatile unsigned int *dbdma;
+
+ macio = finddevice("/pci/mac-io");
+ enet = finddevice("/pci/mac-io/ethernet");
+ if (macio == NULL || enet == NULL)
+ return;
+ len = getprop(macio, "assigned-addresses", macio_addr, sizeof(macio_addr));
+ if (len != sizeof(macio_addr))
+ return;
+ len = getprop(enet, "reg", enet_reg, sizeof(enet_reg));
+ if (len != sizeof(enet_reg))
+ return;
+ printf("macio base %x, dma at %x & %x\n",
+ macio_addr[2], enet_reg[2], enet_reg[4]);
+
+ /* hope this is mapped... */
+ dbdma = (volatile unsigned int *) (macio_addr[2] + enet_reg[2]);
+ *dbdma = 0x80; /* clear the RUN bit */
+ eieio();
+ dbdma = (volatile unsigned int *) (macio_addr[2] + enet_reg[4]);
+ *dbdma = 0x80; /* clear the RUN bit */
+ eieio();
+}
+
+void stop_imac_usb(void)
+{
+ void *usb;
+ unsigned int usb_addr[5];
+ int len;
+ volatile unsigned int *usb_ctrl;
+
+ usb = finddevice("/pci/usb");
+ if (usb == NULL)
+ return;
+ len = getprop(usb, "assigned-addresses", usb_addr, sizeof(usb_addr));
+ if (len != sizeof(usb_addr))
+ return;
+ printf("usb base %x\n", usb_addr[2]);
+
+ usb_ctrl = (volatile unsigned int *) (usb_addr[2] + 8);
+ *usb_ctrl = 0x01000000; /* cpu_to_le32(1) */
+ eieio();
+}
+
+void *zalloc(void *x, unsigned items, unsigned size)
+{
+ void *p = avail_ram;
+
+ size *= items;
+ size = (size + 7) & -8;
+ avail_ram += size;
+ if (avail_ram > end_avail) {
+ printf("oops... out of memory\n");
+ pause();
+ }
+ return p;
+}
+
+void zfree(void *x, void *addr, unsigned nb)
+{
+}
+
+#define HEAD_CRC 2
+#define EXTRA_FIELD 4
+#define ORIG_NAME 8
+#define COMMENT 0x10
+#define RESERVED 0xe0
+
+#define DEFLATED 8
+
+void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp)
+{
+ z_stream s;
+ int r, i, flags;
+
+ /* skip header */
+ i = 10;
+ flags = src[3];
+ if (src[2] != DEFLATED || (flags & RESERVED) != 0) {
+ printf("bad gzipped data\n");
+ exit();
+ }
+ if ((flags & EXTRA_FIELD) != 0)
+ i = 12 + src[10] + (src[11] << 8);
+ if ((flags & ORIG_NAME) != 0)
+ while (src[i++] != 0)
+ ;
+ if ((flags & COMMENT) != 0)
+ while (src[i++] != 0)
+ ;
+ if ((flags & HEAD_CRC) != 0)
+ i += 2;
+ if (i >= *lenp) {
+ printf("gunzip: ran out of data in header\n");
+ exit();
+ }
+
+ s.zalloc = zalloc;
+ s.zfree = zfree;
+ r = inflateInit2(&s, -MAX_WBITS);
+ if (r != Z_OK) {
+ printf("inflateInit2 returned %d\n", r);
+ exit();
+ }
+ s.next_in = src + i;
+ s.avail_in = *lenp - i;
+ s.next_out = dst;
+ s.avail_out = dstlen;
+ r = inflate(&s, Z_FINISH);
+ if (r != Z_OK && r != Z_STREAM_END) {
+ printf("inflate returned %d msg: %s\n", r, s.msg);
+ exit();
+ }
+ *lenp = s.next_out - (unsigned char *) dst;
+ inflateEnd(&s);
+}
--- /dev/null
+/*
+ * Copyright (C) Paul Mackerras 1997.
+ *
+ * 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.
+ */
+ .text
+ .globl _start
+_start:
+ .long __start,0,0
+
+ .globl __start
+__start:
+ lis 9,_start@h
+ lis 8,_etext@ha
+ addi 8,8,_etext@l
+1: dcbf 0,9
+ icbi 0,9
+ addi 9,9,0x20
+ cmplwi 0,9,8
+ blt 1b
+ b start
--- /dev/null
+/*
+ * Copyright (C) Paul Mackerras 1997.
+ *
+ * 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.
+ */
+#include "nonstdio.h"
+#include "zlib.h"
+#include <asm/bootinfo.h>
+#include <asm/processor.h>
+#define __KERNEL__
+#include <asm/page.h>
+
+extern void *finddevice(const char *);
+extern int getprop(void *, const char *, void *, int);
+extern char *claim(unsigned, unsigned, unsigned);
+void make_bi_recs(unsigned long);
+void gunzip(void *, int, unsigned char *, int *);
+
+#define get_16be(x) (*(unsigned short *)(x))
+#define get_32be(x) (*(unsigned *)(x))
+
+#define RAM_START 0xc0000000
+#define PROG_START RAM_START
+#define RAM_END (RAM_START + 0x800000) /* only 8M mapped with BATs */
+
+char *avail_ram;
+char *end_avail;
+
+extern char _start[], _end[];
+extern char image_data[];
+extern int image_len;
+extern char initrd_data[];
+extern int initrd_len;
+
+
+boot(int a1, int a2, void *prom)
+{
+ int ns, oh, i;
+ unsigned sa, len;
+ void *dst;
+ unsigned char *im;
+ unsigned initrd_start, initrd_size;
+
+ printf("coffboot starting: loaded at 0x%x\n", _start);
+ setup_bats(RAM_START);
+ if (initrd_len) {
+ initrd_size = initrd_len;
+ initrd_start = (RAM_END - initrd_size) & ~0xFFF;
+ a1 = initrd_start;
+ a2 = initrd_size;
+ claim(initrd_start - RAM_START, RAM_END - initrd_start, 0);
+ printf("initial ramdisk moving 0x%x <- 0x%x (%x bytes)\n",
+ initrd_start, initrd_data, initrd_size);
+ memcpy((char *)initrd_start, initrd_data, initrd_size);
+ }
+ im = image_data;
+ len = image_len;
+ /* claim 3MB starting at 0 */
+ claim(0, 3 << 20, 0);
+ dst = (void *) RAM_START;
+ if (im[0] == 0x1f && im[1] == 0x8b) {
+ /* claim 512kB for scratch space */
+ avail_ram = claim(0, 512 << 10, 0x10) + RAM_START;
+ end_avail = avail_ram + (512 << 10);
+ printf("avail_ram = %x\n", avail_ram);
+ printf("gunzipping (0x%x <- 0x%x:0x%0x)...", dst, im, im+len);
+ gunzip(dst, 3 << 20, im, &len);
+ printf("done %u bytes\n", len);
+ } else {
+ memmove(dst, im, len);
+ }
+
+ flush_cache(dst, len);
+ make_bi_recs((unsigned long)dst + len);
+
+ sa = (unsigned long)PROG_START;
+ printf("start address = 0x%x\n", sa);
+
+#if 0
+ pause();
+#endif
+ (*(void (*)())sa)(a1, a2, prom);
+
+ printf("returned?\n");
+
+ pause();
+}
+
+void make_bi_recs(unsigned long addr)
+{
+ struct bi_record *rec;
+
+ rec = (struct bi_record *)PAGE_ALIGN(addr);
+
+ rec->tag = BI_FIRST;
+ rec->size = sizeof(struct bi_record);
+ rec = (struct bi_record *)((unsigned long)rec + rec->size);
+
+ rec->tag = BI_BOOTLOADER_ID;
+ sprintf( (char *)rec->data, "coffboot");
+ rec->size = sizeof(struct bi_record) + strlen("coffboot") + 1;
+ rec = (struct bi_record *)((unsigned long)rec + rec->size);
+
+ rec->tag = BI_MACHTYPE;
+ rec->data[0] = _MACH_Pmac;
+ rec->data[1] = 1;
+ rec->size = sizeof(struct bi_record) + sizeof(unsigned long);
+ rec = (struct bi_record *)((unsigned long)rec + rec->size);
+
+ rec->tag = BI_LAST;
+ rec->size = sizeof(struct bi_record);
+ rec = (struct bi_record *)((unsigned long)rec + rec->size);
+}
+
+void *zalloc(void *x, unsigned items, unsigned size)
+{
+ void *p = avail_ram;
+
+ size *= items;
+ size = (size + 7) & -8;
+ avail_ram += size;
+ if (avail_ram > end_avail) {
+ printf("oops... out of memory\n");
+ pause();
+ }
+ return p;
+}
+
+void zfree(void *x, void *addr, unsigned nb)
+{
+}
+
+#define HEAD_CRC 2
+#define EXTRA_FIELD 4
+#define ORIG_NAME 8
+#define COMMENT 0x10
+#define RESERVED 0xe0
+
+#define DEFLATED 8
+
+void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp)
+{
+ z_stream s;
+ int r, i, flags;
+
+ /* skip header */
+ i = 10;
+ flags = src[3];
+ if (src[2] != DEFLATED || (flags & RESERVED) != 0) {
+ printf("bad gzipped data\n");
+ exit();
+ }
+ if ((flags & EXTRA_FIELD) != 0)
+ i = 12 + src[10] + (src[11] << 8);
+ if ((flags & ORIG_NAME) != 0)
+ while (src[i++] != 0)
+ ;
+ if ((flags & COMMENT) != 0)
+ while (src[i++] != 0)
+ ;
+ if ((flags & HEAD_CRC) != 0)
+ i += 2;
+ if (i >= *lenp) {
+ printf("gunzip: ran out of data in header\n");
+ exit();
+ }
+
+ s.zalloc = zalloc;
+ s.zfree = zfree;
+ r = inflateInit2(&s, -MAX_WBITS);
+ if (r != Z_OK) {
+ printf("inflateInit2 returned %d\n", r);
+ exit();
+ }
+ s.next_in = src + i;
+ s.avail_in = *lenp - i;
+ s.next_out = dst;
+ s.avail_out = dstlen;
+ r = inflate(&s, Z_FINISH);
+ if (r != Z_OK && r != Z_STREAM_END) {
+ printf("inflate returned %d msg: %s\n", r, s.msg);
+ exit();
+ }
+ *lenp = s.next_out - (unsigned char *) dst;
+ inflateEnd(&s);
+}
.text
.globl _start
_start:
- .long __start,0,0
-
- .globl __start
-__start:
lis 9,_start@h
lis 8,_etext@ha
addi 8,8,_etext@l
*/
.globl setup_bats
setup_bats:
- mr 4,3
- mfpvr 3
- rlwinm 3,3,16,16,31 /* r3 = 1 for 601, 4 for 604 */
- cmpi 0,3,1
+ mfpvr 5
+ rlwinm 5,5,16,16,31 /* r3 = 1 for 601, 4 for 604 */
+ cmpi 0,5,1
+ li 0,0
bne 4f
- ori 4,4,4 /* set up BAT registers for 601 */
- li 5,0x7f
- mtibatu 3,4
- mtibatl 3,5
- isync
- blr
-4: ori 4,4,0xfe /* set up BAT registers for 604 */
- li 5,2
- mtdbatl 3,5
- mtdbatu 3,4
- mtibatl 3,5
- mtibatu 3,4
+ mtibatl 3,0 /* invalidate BAT first */
+ ori 3,3,4 /* set up BAT registers for 601 */
+ li 4,0x7f
+ mtibatu 3,3
+ mtibatl 3,4
+ b 5f
+4: mtdbatu 3,0 /* invalidate BATs first */
+ mtibatu 3,0
+ ori 3,3,0xff /* set up BAT registers for 604 */
+ li 4,2
+ mtdbatl 3,4
+ mtdbatu 3,3
+ mtibatl 3,4
+ mtibatu 3,3
+5: sync
isync
blr
--- /dev/null
+/*
+ * Copyright (C) Cort Dougan 1999.
+ *
+ * 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.
+ *
+ * Generate a note section as per the CHRP specification.
+ *
+ */
+
+#include <stdio.h>
+
+#define PL(x) printf("%c%c%c%c", ((x)>>24)&0xff, ((x)>>16)&0xff, ((x)>>8)&0xff, (x)&0xff );
+
+int main(void)
+{
+/* header */
+ /* namesz */
+ PL(strlen("PowerPC")+1);
+ /* descrsz */
+ PL(6*4);
+ /* type */
+ PL(0x1275);
+ /* name */
+ printf("PowerPC"); printf("%c", 0);
+
+/* descriptor */
+ /* real-mode */
+ PL(0xffffffff);
+ /* real-base */
+ PL(0x00c00000);
+ /* real-size */
+ PL(0xffffffff);
+ /* virt-base */
+ PL(0xffffffff);
+ /* virt-size */
+ PL(0xffffffff);
+ /* load-base */
+ PL(0x4000);
+ return 0;
+}
--- /dev/null
+char initrd_data[1];
+int initrd_len = 0;
--- /dev/null
+#include <stdio.h>
+
+extern long ce_exec_config[];
+
+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, "\t.data\n");
+ fprintf(stdout, "\t.globl %s_data\n", argv[1]);
+ fprintf(stdout, "%s_data:\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.long\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, ",");
+ }
+ }
+ if (cnt)
+ {
+ fprintf(stdout, "0\n");
+ }
+ pos += len;
+ }
+ fprintf(stdout, "\t.globl %s_len\n", argv[1]);
+ fprintf(stdout, "%s_len:\t.long\t0x%x\n", argv[1], pos);
+ fflush(stdout);
+ fclose(stdout);
+ fprintf(stderr, "cksum = %x\n", cksum);
+ exit(0);
+}
+
if (getprop(chosen_handle, "stdin", &stdin, sizeof(stdin)) != 4)
exit();
- coffboot(a1, a2, promptr);
+ boot(a1, a2, promptr);
for (;;)
exit();
}
return args.actual;
}
+int writestring(void *f, char *ptr, int nb)
+{
+ int w = 0, i;
+ char *ret = "\r";
+
+ for (i = 0; i < nb; ++i) {
+ if (ptr[i] == '\n') {
+ if (i > w) {
+ write(f, ptr + w, i - w);
+ w = i;
+ }
+ write(f, ret, 1);
+ }
+ }
+ if (w < nb)
+ write(f, ptr + w, nb - w);
+ return nb;
+}
+
int
read(void *handle, void *ptr, int nb)
{
return args.phandle;
}
+void *
+claim(unsigned int virt, unsigned int size, unsigned int align)
+{
+ struct prom_args {
+ char *service;
+ int nargs;
+ int nret;
+ unsigned int virt;
+ unsigned int size;
+ unsigned int align;
+ void *ret;
+ } args;
+
+ args.service = "claim";
+ args.nargs = 3;
+ args.nret = 1;
+ args.virt = virt;
+ args.size = size;
+ args.align = align;
+ (*prom)(&args);
+ return args.ret;
+}
+
int
getprop(void *phandle, const char *name, void *buf, int buflen)
{
{
char ch = c;
- if (c == '\n')
- putc('\r', f);
- return write(f, &ch, 1) == 1? c: -1;
+ return writestring(f, &ch, 1) == 1? c: -1;
}
int
{
int n = strlen(str);
- return write(f, str, n) == n? 0: -1;
+ return writestring(f, str, n) == n? 0: -1;
}
int
case 1:
return ch;
case -1:
- printk("read(stdin) returned -1\r\n");
+ printk("read(stdin) returned -1\n");
return -1;
}
}
va_start(args, fmt);
n = vsprintf(sprint_buf, fmt, args);
va_end(args);
- write(stdout, sprint_buf, n);
+ writestring(stdout, sprint_buf, n);
}
int
va_start(args, fmt);
n = vsprintf(sprint_buf, fmt, args);
va_end(args);
- write(stdout, sprint_buf, n);
+ writestring(stdout, sprint_buf, n);
return n;
}
define_bool CONFIG_MACH_SPECIFIC y
fi
-if [ "$CONFIG_4xx" = "y" ] || [ "$CONFIG_8xx" = "y" ]; then
+if [ "$CONFIG_4xx" = "y" -o "$CONFIG_8xx" = "y" ]; then
bool 'Math emulation' CONFIG_MATH_EMULATION
fi
endmenu
# CONFIG_LANCE is not set
# CONFIG_NET_VENDOR_SMC is not set
# CONFIG_NET_VENDOR_RACAL is not set
-# CONFIG_YELLOWFIN is not set
# CONFIG_RTL8139 is not set
# CONFIG_DM9102 is not set
# CONFIG_AT1700 is not set
CONFIG_NET_EISA=y
CONFIG_PCNET32=y
# CONFIG_ADAPTEC_STARFIRE is not set
-# CONFIG_ACENIC is not set
# CONFIG_AC3200 is not set
# CONFIG_APRICOT is not set
# CONFIG_CS89x0 is not set
# CONFIG_EPIC100 is not set
# CONFIG_ZNET is not set
# CONFIG_NET_POCKET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_YELLOWFIN is not set
+# CONFIG_ACENIC is not set
+# CONFIG_SK98LIN is not set
# CONFIG_FDDI is not set
# CONFIG_HIPPI is not set
# CONFIG_LANCE is not set
# CONFIG_NET_VENDOR_SMC is not set
# CONFIG_NET_VENDOR_RACAL is not set
-# CONFIG_YELLOWFIN is not set
# CONFIG_RTL8139 is not set
# CONFIG_DM9102 is not set
# CONFIG_AT1700 is not set
CONFIG_NET_EISA=y
CONFIG_PCNET32=y
# CONFIG_ADAPTEC_STARFIRE is not set
-# CONFIG_ACENIC is not set
# CONFIG_AC3200 is not set
# CONFIG_APRICOT is not set
# CONFIG_CS89x0 is not set
# CONFIG_EPIC100 is not set
# CONFIG_ZNET is not set
# CONFIG_NET_POCKET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_YELLOWFIN is not set
+# CONFIG_ACENIC is not set
+# CONFIG_SK98LIN is not set
# CONFIG_FDDI is not set
# CONFIG_HIPPI is not set
* Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
* PowerPC 403GCX/405GP modifications.
*/
+#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <asm/ptrace.h>
* here so it's easy to add arch-specific sections later.
* -- Cort
*/
-#if defined(CONFIG_CHRP) || defined(CONFIG_ALL_PPC)
+#if defined(CONFIG_CHRP) || defined(CONFIG_PMAC) || defined(CONFIG_ALL_PPC)
/*
* On CHRP, the Run-Time Abstraction Services (RTAS) have to be
* called with the MMU off.
mtspr SRR0,r8
mtspr SRR1,r9
rfi /* return to caller */
-#endif /* defined(CONFIG_CHRP) || defined(CONFIG_ALL_PPC) */
+#endif /* CONFIG_CHRP || CONFIG_PMAC || CONFIG_ALL_PPC */
/* gemini has no 8259 */
open_pic.irq_offset = 0;
- for( i=0; i < OPENPIC_VEC_SPURIOUS; i++ )
+ for( i=0; i < NR_IRQS; i++ )
irq_desc[i].ctl = &open_pic;
openpic_init(1);
#ifdef __SMP__
SYNC
blr
-/*
- * We put a few things here that have to be page-aligned.
- * This stuff goes at the beginning of the data segment,
- * which is page-aligned.
- */
- .data
- .globl sdata
-sdata:
- .globl empty_zero_page
-empty_zero_page:
- .space 4096
-
- .globl swapper_pg_dir
-swapper_pg_dir:
- .space 4096
-
-/*
- * This space gets a copy of optional info passed to us by the bootstrap
- * Used to pass parameters into the kernel like root=/dev/sda1, etc.
- */
- .globl cmd_line
-cmd_line:
- .space 512
-
/*
* An undocumented "feature" of 604e requires that the v bit
* be cleared before changing BAT values.
#endif /* !defined(CONFIG_GEMINI) */
blr
-flush_tlbs:
- lis r20, 0x1000
-1: addic. r20, r20, -0x1000
- tlbie r20
- blt 1b
- sync
- blr
+/*
+ * We put a few things here that have to be page-aligned.
+ * This stuff goes at the beginning of the data segment,
+ * which is page-aligned.
+ */
+ .data
+ .globl sdata
+sdata:
+ .globl empty_zero_page
+empty_zero_page:
+ .space 4096
+
+ .globl swapper_pg_dir
+swapper_pg_dir:
+ .space 4096
+
+/*
+ * This space gets a copy of optional info passed to us by the bootstrap
+ * Used to pass parameters into the kernel like root=/dev/sda1, etc.
+ */
+ .globl cmd_line
+cmd_line:
+ .space 512
* The *_ns versions don't do byte-swapping.
*/
_GLOBAL(_insb)
+ cmpw 0,r5,0
mtctr r5
subi r4,r4,1
+ blelr-
00: lbz r5,0(r3)
eieio
stbu r5,1(r4)
blr
_GLOBAL(_outsb)
+ cmpw 0,r5,0
mtctr r5
subi r4,r4,1
+ blelr-
00: lbzu r5,1(r4)
stb r5,0(r3)
eieio
blr
_GLOBAL(_insw)
+ cmpw 0,r5,0
mtctr r5
subi r4,r4,2
+ blelr-
00: lhbrx r5,0,r3
eieio
sthu r5,2(r4)
blr
_GLOBAL(_outsw)
+ cmpw 0,r5,0
mtctr r5
subi r4,r4,2
+ blelr-
00: lhzu r5,2(r4)
eieio
sthbrx r5,0,r3
blr
_GLOBAL(_insl)
+ cmpw 0,r5,0
mtctr r5
subi r4,r4,4
+ blelr-
00: lwbrx r5,0,r3
eieio
stwu r5,4(r4)
blr
_GLOBAL(_outsl)
+ cmpw 0,r5,0
mtctr r5
subi r4,r4,4
+ blelr-
00: lwzu r5,4(r4)
stwbrx r5,0,r3
eieio
_GLOBAL(ide_insw)
_GLOBAL(_insw_ns)
+ cmpw 0,r5,0
mtctr r5
subi r4,r4,2
+ blelr-
00: lhz r5,0(r3)
eieio
sthu r5,2(r4)
_GLOBAL(ide_outsw)
_GLOBAL(_outsw_ns)
+ cmpw 0,r5,0
mtctr r5
subi r4,r4,2
+ blelr-
00: lhzu r5,2(r4)
sth r5,0(r3)
eieio
blr
_GLOBAL(_insl_ns)
+ cmpw 0,r5,0
mtctr r5
subi r4,r4,4
+ blelr-
00: lwz r5,0(r3)
eieio
stwu r5,4(r4)
blr
_GLOBAL(_outsl_ns)
+ cmpw 0,r5,0
mtctr r5
subi r4,r4,4
+ blelr-
00: lwzu r5,4(r4)
stw r5,0(r3)
eieio
.long sys_sigpending
.long sys_sethostname
.long sys_setrlimit /* 75 */
- .long sys_getrlimit
+ .long sys_old_getrlimit
.long sys_getrusage
.long sys_gettimeofday
.long sys_settimeofday
.long sys_ni_syscall /* streams1 */
.long sys_ni_syscall /* streams2 */
.long sys_vfork
- .space (NR_syscalls-183)*4
+ .long sys_getrlimit /* 190 */
+ .space (NR_syscalls-190)*4
#define check_arg_pri(pri) \
if (pri < 0 || pri >= OPENPIC_NUM_PRI) \
printk("openpic.c:%d: illegal priority %d\n", __LINE__, pri);
-#define check_arg_irq(irq) \
+/*
+ * Turned this check off since the IPI's are treated as irqs
+ * but they're above NumSources -- Cort
+ */
+#define check_arg_irq(irq)
+#if 0
if (irq < 0 || irq >= (NumSources+open_pic.irq_offset)) \
printk("openpic.c:%d: illegal irq %d\n", __LINE__, irq);
+#endif
#define check_arg_cpu(cpu) \
if (cpu < 0 || cpu >= NumProcessors) \
printk("openpic.c:%d: illegal cpu %d\n", __LINE__, cpu);
/* Initialize IPI interrupts */
if ( ppc_md.progress ) ppc_md.progress("openpic ipi",0x3bb);
for (i = 0; i < OPENPIC_NUM_IPI; i++) {
- /* Disabled, Priority 0 */
- openpic_initipi(i, 0, OPENPIC_VEC_IPI+i);
+ /* Disabled, Priority 8 */
+ openpic_initipi(i, 8, OPENPIC_VEC_IPI+i);
}
/* Initialize external interrupts */
if ( ppc_md.progress ) ppc_md.progress("openpic ext",0x3bc);
- /* SIOint (8259 cascade) is special */
- openpic_initirq(0, 8, open_pic.irq_offset, 1, 1);
- openpic_mapirq(0, 1<<0);
for (i = 1; i < NumSources; i++) {
/* Enabled, Priority 8 */
openpic_initirq(i, 8, open_pic.irq_offset+i, 0,
openpic_set_spurious(OPENPIC_VEC_SPURIOUS);
if ( _machine != _MACH_gemini )
{
+ /* SIOint (8259 cascade) is special */
+ openpic_initirq(0, 8, open_pic.irq_offset, 1, 1);
+ openpic_mapirq(0, 1<<0);
if (request_irq(IRQ_8259_CASCADE, no_action, SA_INTERRUPT,
"82c59 cascade", NULL))
printk("Unable to get OpenPIC IRQ 0 for cascade\n");
#include <linux/delay.h>
#include <linux/string.h>
#include <linux/init.h>
-#include <linux/config.h>
#include <linux/openpic.h>
#include <asm/processor.h>
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/stddef.h>
-#include <linux/reboot.h>
#include <linux/nvram.h>
#include <linux/init.h>
#include <asm/init.h>
-#include <asm/ptrace.h>
#include <asm/io.h>
-#include <asm/pgtable.h>
#include <asm/system.h>
#include <asm/prom.h>
#include <linux/adb.h>
#include <asm/init.h>
#include <asm/io.h>
-#include <asm/pgtable.h>
#include <asm/prom.h>
#include <asm/pci-bridge.h>
#include <asm/machdep.h>
EXPORT_SYMBOL(find_compatible_devices);
EXPORT_SYMBOL(find_path_device);
EXPORT_SYMBOL(find_phandle);
+EXPORT_SYMBOL(device_is_compatible);
+EXPORT_SYMBOL(machine_is_compatible);
EXPORT_SYMBOL(get_property);
EXPORT_SYMBOL(pci_io_base);
EXPORT_SYMBOL(pci_device_loc);
EXPORT_SYMBOL(feature_set);
EXPORT_SYMBOL(feature_clear);
EXPORT_SYMBOL(feature_test);
-EXPORT_SYMBOL(device_is_compatible);
#endif /* defined(CONFIG_PMAC) || defined(CONFIG_ALL_PPC) */
#if defined(CONFIG_SCSI) && (defined(CONFIG_PMAC) || defined(CONFIG_ALL_PPC))
EXPORT_SYMBOL(note_scsi_host);
return len;
}
+#ifndef CONFIG_MACH_SPECIFIC
+void __init
+intuit_machine_type(void)
+{
+ char *model;
+ struct device_node *root;
+
+ /* ask the OF info if we're a chrp or pmac */
+ root = find_path_device("/");
+ if (root != 0) {
+ /* assume pmac unless proven to be chrp -- Cort */
+ _machine = _MACH_Pmac;
+ model = get_property(root, "device_type", NULL);
+ if (model && !strncmp("chrp", model, 4))
+ _machine = _MACH_chrp;
+ else {
+ model = get_property(root, "model", NULL);
+ if (model && !strncmp(model, "IBM", 3))
+ _machine = _MACH_chrp;
+ }
+ }
+}
+#endif /* CONFIG_MACH_SPECIFIC */
+
/*
* Find out what kind of machine we're on and save any data we need
* from the early boot process (devtree is copied on pmac by prom_init() )
{
_machine = _MACH_prep;
} else
- {
- char *model;
- struct device_node *root;
-
have_of = 1;
-
- /* prom_init has already been called from __start */
- if (boot_infos)
- relocate_nodes();
-
- /* ask the OF info if we're a chrp or pmac */
- /* we need to set _machine before calling finish_device_tree */
- root = find_path_device("/");
- if (root != 0) {
- /* assume pmac unless proven to be chrp -- Cort */
- _machine = _MACH_Pmac;
- model = get_property(root, "device_type", NULL);
- if (model && !strncmp("chrp", model, 4))
- _machine = _MACH_chrp;
- else {
- model = get_property(root, "model", NULL);
- if (model && !strncmp(model, "IBM", 3))
- _machine = _MACH_chrp;
- }
- }
-
- finish_device_tree();
- }
}
#endif /* CONFIG_MACH_SPECIFIC */
/* prom_init has already been called from __start */
if (boot_infos)
relocate_nodes();
+#ifndef CONFIG_MACH_SPECIFIC
+ /* we need to set _machine before calling finish_device_tree */
+ if (_machine == 0)
+ intuit_machine_type();
+#endif /* CONFIG_MACH_SPECIFIC */
finish_device_tree();
+
/*
* If we were booted via quik, r3 points to the physical
* address of the command-line parameters.
void smp_send_reschedule(int cpu)
{
/*
+ * This is only used if `cpu' is running an idle task,
+ * so it will reschedule itself anyway...
+ *
* This isn't the case anymore since the other CPU could be
* sleeping and won't reschedule until the next interrupt (such
* as the timer).
* -- Cort
*/
- /* This is only used if `cpu' is running an idle task,
- so it will reschedule itself anyway... */
- /*smp_message_pass(cpu, MSG_RESCHEDULE, 0, 0);*/
+ smp_message_pass(cpu, MSG_RESCHEDULE, 0, 0);
}
void smp_send_stop(void)
openpic_enable_IPI(i);
cpu_nr = (readb(GEMINI_CPUSTAT) & GEMINI_CPU_COUNT_MASK)>>2;
cpu_nr = (cpu_nr == 0) ? 4 : cpu_nr;
-cpu_nr = 2;
break;
}
* len is in words and is always >= 5.
*/
_GLOBAL(ip_fast_csum)
- cmpi 0,r4,0
- beq 10f
lwz r0,0(r3)
lwzu r5,4(r3)
- addi r4,r4,-2
+ addic. r4,r4,-2
addc r0,r0,r5
mtctr r4
+ blelr-
1: lwzu r4,4(r3)
adde r0,r0,r4
bdnz 1b
not r3,r3
srwi r3,r3,16
blr
-10: li r3,0
- blr
/*
* Compute checksum of TCP or UDP pseudo-header:
void si_meminfo(struct sysinfo *val)
{
- int i;
+ int i, c;
i = max_mapnr;
- val->totalram = 0;
- val->sharedram = 0;
+ val->totalram = totalram_pages;
val->freeram = nr_free_pages();
val->bufferram = atomic_read(&buffermem_pages);
+ val->sharedram = 0;
while (i-- > 0) {
if (PageReserved(mem_map+i))
continue;
- val->totalram++;
- if (!atomic_read(&mem_map[i].count))
- continue;
- val->sharedram += atomic_read(&mem_map[i].count) - 1;
+ c = atomic_read(&mem_map[i].count);
+ if (c > 1)
+ val->sharedram += c - 1;
}
- val->totalram <<= PAGE_SHIFT;
- val->sharedram <<= PAGE_SHIFT;
- return;
+ val->totalhigh = 0;
+ val->freehigh = 0;
+ val->mem_unit = PAGE_SIZE;
}
void *
f |= _PAGE_RW | _PAGE_DIRTY | _PAGE_HWWRITE;
#ifndef CONFIG_8xx
else
- /* On the powerpc (not 8xx), no user access
+ /* On the powerpc, denying user access
forces R/W kernel access */
f |= _PAGE_USER;
#endif /* CONFIG_8xx */
setbat(3, 0x90000000, 0x90000000, 0x10000000, IO_PAGE);
break;
case _MACH_Pmac:
-#if 0
+#if 1
{
unsigned long base = 0xf3000000;
struct device_node *macio = find_devices("mac-io");
/* remove the bootmem bitmap from the available memory */
mem_pieces_remove(&phys_avail, start, boot_mapsize, 1);
+
/* add everything in phys_avail into the bootmem map */
for (i = 0; i < phys_avail.n_regions; ++i)
free_bootmem(phys_avail.regions[i].address,
int codepages = 0;
int datapages = 0;
int initpages = 0;
-#if defined(CONFIG_CHRP) || defined(CONFIG_ALL_PPC)
+#if defined(CONFIG_CHRP) || defined(CONFIG_PMAC) || defined(CONFIG_ALL_PPC)
extern unsigned int rtas_data, rtas_size;
-#endif /* defined(CONFIG_CHRP) || defined(CONFIG_ALL_PPC) */
+#endif /* CONFIG_CHRP || CONFIG_PMAC || CONFIG_ALL_PPC */
max_mapnr = max_low_pfn;
high_memory = (void *) __va(max_low_pfn * PAGE_SIZE);
num_physpages = max_mapnr; /* RAM is assumed contiguous */
}
#endif /* CONFIG_BLK_DEV_INITRD */
-#if defined(CONFIG_CHRP) || defined(CONFIG_ALL_PPC)
+#if defined(CONFIG_CHRP) || defined(CONFIG_PMAC) || defined(CONFIG_ALL_PPC)
/* mark the RTAS pages as reserved */
if ( rtas_data )
for (addr = rtas_data; addr < PAGE_ALIGN(rtas_data+rtas_size) ;
addr += PAGE_SIZE)
SetPageReserved(mem_map + MAP_NR(addr));
-#endif /* defined(CONFIG_CHRP) || defined(CONFIG_ALL_PPC) */
+#endif /* CONFIG_CHRP || CONFIG_PMAC || CONFIG_ALL_PPC */
for (addr = PAGE_OFFSET; addr < (unsigned long)end_of_DRAM;
addr += PAGE_SIZE) {
else if (addr >= (unsigned long)&__init_begin
&& addr < (unsigned long)&__init_end)
initpages++;
- else if (addr < (ulong) klimit)
+ else
datapages++;
}
printk("Memory: %luk available (%dk kernel code, %dk data, %dk init) [%08x,%08lx]\n",
- (unsigned long) nr_free_pages << (PAGE_SHIFT-10),
+ (unsigned long) nr_free_pages() << (PAGE_SHIFT-10),
codepages << (PAGE_SHIFT-10),
datapages << (PAGE_SHIFT-10),
initpages << (PAGE_SHIFT-10),
#ifndef __MEM_PIECES_H__
#define __MEM_PIECES_H__
-#include <linux/config.h>
#include <linux/init.h>
asm volatile ("dcbst 0,%0; sync; icbi 0,%0; isync" : : "r" (p));
}
+static inline void cflush(void *p)
+{
+ asm volatile ("dcbf 0,%0; icbi 0,%0" : : "r" (p));
+}
+
+static inline void cinval(void *p)
+{
+ asm volatile ("dcbi 0,%0; icbi 0,%0" : : "r" (p));
+}
#include <asm/machdep.h>
#include <asm/io.h>
#include <asm/page.h>
-#include <asm/pgtable.h>
#include <linux/adb.h>
#include <linux/pmu.h>
#include <asm/prom.h>
#include <asm/bootx.h>
+#include <asm/processor.h>
static volatile unsigned char *sccc, *sccd;
unsigned long TXRDY, RXRDY;
#ifdef CONFIG_BOOTX_TEXT
if (boot_infos != 0 && find_via_pmu()) {
- printk(KERN_INFO "xmon uses screen and keyboard\n");
+ printk("xmon uses screen and keyboard\n");
use_screen = 1;
map_bootx_text();
return;
static void insert_bpts(void);
static struct bpt *at_breakpoint(unsigned pc);
static void bpt_cmds(void);
+static void cacheflush(void);
extern int print_insn_big_powerpc(FILE *, unsigned long, unsigned);
extern void printf(const char *fmt, ...);
case 't':
backtrace(excp);
break;
-#if 0
case 'f':
- openforth();
+ cacheflush();
break;
-#endif
case 'h':
dump_hash_table();
break;
fp->ctr, fp->xer, fp->trap);
}
+void
+cacheflush(void)
+{
+ int cmd;
+ unsigned nflush;
+
+ cmd = inchar();
+ if (cmd != 'i')
+ termch = cmd;
+ scanhex(&adrs);
+ if (termch != '\n')
+ termch = 0;
+ nflush = 1;
+ scanhex(&nflush);
+ nflush = (nflush + 31) / 32;
+ if (cmd != 'i') {
+ for (; nflush > 0; --nflush, adrs += 0x20)
+ cflush((void *) adrs);
+ } else {
+ for (; nflush > 0; --nflush, adrs += 0x20)
+ cinval((void *) adrs);
+ }
+}
+
unsigned int
read_spr(int n)
{
#include <asm/uaccess.h>
#include "sfp-util.h"
-#include "soft-fp.h"
-#include "single.h"
-#include "double.h"
-#include "quad.h"
+#include <math-emu/soft-fp.h>
+#include <math-emu/single.h>
+#include <math-emu/double.h>
+#include <math-emu/quad.h>
#define FLOATFUNC(x) extern int x(void *,void *,void *)
+++ /dev/null
-/* Machine-dependent software floating-point definitions.
- Sparc userland (_Q_*) version.
- Copyright (C) 1997,1998,1999 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- Contributed by Richard Henderson (rth@cygnus.com),
- Jakub Jelinek (jj@ultra.linux.cz),
- David S. Miller (davem@redhat.com) and
- Peter Maydell (pmaydell@chiark.greenend.org.uk).
-
- The GNU C Library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Library General Public License as
- published by the Free Software Foundation; either version 2 of the
- License, or (at your option) any later version.
-
- The GNU C Library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public
- License along with the GNU C Library; see the file COPYING.LIB. If
- not, write to the Free Software Foundation, Inc.,
- 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
-
-#ifndef _SFP_MACHINE_H
-#define _SFP_MACHINE_H
-
-#define _FP_W_TYPE_SIZE 32
-#define _FP_W_TYPE unsigned long
-#define _FP_WS_TYPE signed long
-#define _FP_I_TYPE long
-
-#define _FP_MUL_MEAT_S(R,X,Y) \
- _FP_MUL_MEAT_1_wide(_FP_WFRACBITS_S,R,X,Y,umul_ppmm)
-#define _FP_MUL_MEAT_D(R,X,Y) \
- _FP_MUL_MEAT_2_wide(_FP_WFRACBITS_D,R,X,Y,umul_ppmm)
-#define _FP_MUL_MEAT_Q(R,X,Y) \
- _FP_MUL_MEAT_4_wide(_FP_WFRACBITS_Q,R,X,Y,umul_ppmm)
-
-#define _FP_DIV_MEAT_S(R,X,Y) _FP_DIV_MEAT_1_udiv(S,R,X,Y)
-#define _FP_DIV_MEAT_D(R,X,Y) _FP_DIV_MEAT_2_udiv(D,R,X,Y)
-#define _FP_DIV_MEAT_Q(R,X,Y) _FP_DIV_MEAT_4_udiv(Q,R,X,Y)
-
-#define _FP_NANFRAC_S ((_FP_QNANBIT_S << 1) - 1)
-#define _FP_NANFRAC_D ((_FP_QNANBIT_D << 1) - 1), -1
-#define _FP_NANFRAC_Q ((_FP_QNANBIT_Q << 1) - 1), -1, -1, -1
-#define _FP_NANSIGN_S 0
-#define _FP_NANSIGN_D 0
-#define _FP_NANSIGN_Q 0
-
-#define _FP_KEEPNANFRACP 1
-
-/* If one NaN is signaling and the other is not,
- * we choose that one, otherwise we choose X.
- */
-/* For _Qp_* and _Q_*, this should prefer X, for
- * CPU instruction emulation this should prefer Y.
- * (see SPAMv9 B.2.2 section).
- */
-#define _FP_CHOOSENAN(fs, wc, R, X, Y, OP) \
- do { \
- if ((_FP_FRAC_HIGH_RAW_##fs(Y) & _FP_QNANBIT_##fs) \
- && !(_FP_FRAC_HIGH_RAW_##fs(X) & _FP_QNANBIT_##fs)) \
- { \
- R##_s = X##_s; \
- _FP_FRAC_COPY_##wc(R,X); \
- } \
- else \
- { \
- R##_s = Y##_s; \
- _FP_FRAC_COPY_##wc(R,Y); \
- } \
- R##_c = FP_CLS_NAN; \
- } while (0)
-
-/* Some assembly to speed things up. */
-#define __FP_FRAC_ADD_3(r2,r1,r0,x2,x1,x0,y2,y1,y0) \
- __asm__ ("addcc %r7,%8,%2
- addxcc %r5,%6,%1
- addx %r3,%4,%0" \
- : "=r" ((USItype)(r2)), \
- "=&r" ((USItype)(r1)), \
- "=&r" ((USItype)(r0)) \
- : "%rJ" ((USItype)(x2)), \
- "rI" ((USItype)(y2)), \
- "%rJ" ((USItype)(x1)), \
- "rI" ((USItype)(y1)), \
- "%rJ" ((USItype)(x0)), \
- "rI" ((USItype)(y0)) \
- : "cc")
-
-#define __FP_FRAC_SUB_3(r2,r1,r0,x2,x1,x0,y2,y1,y0) \
- __asm__ ("subcc %r7,%8,%2
- subxcc %r5,%6,%1
- subx %r3,%4,%0" \
- : "=r" ((USItype)(r2)), \
- "=&r" ((USItype)(r1)), \
- "=&r" ((USItype)(r0)) \
- : "%rJ" ((USItype)(x2)), \
- "rI" ((USItype)(y2)), \
- "%rJ" ((USItype)(x1)), \
- "rI" ((USItype)(y1)), \
- "%rJ" ((USItype)(x0)), \
- "rI" ((USItype)(y0)) \
- : "cc")
-
-#define __FP_FRAC_ADD_4(r3,r2,r1,r0,x3,x2,x1,x0,y3,y2,y1,y0) \
- do { \
- /* We need to fool gcc, as we need to pass more than 10 \
- input/outputs. */ \
- register USItype _t1 __asm__ ("g1"), _t2 __asm__ ("g2"); \
- __asm__ __volatile__ ("
- addcc %r8,%9,%1
- addxcc %r6,%7,%0
- addxcc %r4,%5,%%g2
- addx %r2,%3,%%g1" \
- : "=&r" ((USItype)(r1)), \
- "=&r" ((USItype)(r0)) \
- : "%rJ" ((USItype)(x3)), \
- "rI" ((USItype)(y3)), \
- "%rJ" ((USItype)(x2)), \
- "rI" ((USItype)(y2)), \
- "%rJ" ((USItype)(x1)), \
- "rI" ((USItype)(y1)), \
- "%rJ" ((USItype)(x0)), \
- "rI" ((USItype)(y0)) \
- : "cc", "g1", "g2"); \
- __asm__ __volatile__ ("" : "=r" (_t1), "=r" (_t2)); \
- r3 = _t1; r2 = _t2; \
- } while (0)
-
-#define __FP_FRAC_SUB_4(r3,r2,r1,r0,x3,x2,x1,x0,y3,y2,y1,y0) \
- do { \
- /* We need to fool gcc, as we need to pass more than 10 \
- input/outputs. */ \
- register USItype _t1 __asm__ ("g1"), _t2 __asm__ ("g2"); \
- __asm__ __volatile__ ("
- subcc %r8,%9,%1
- subxcc %r6,%7,%0
- subxcc %r4,%5,%%g2
- subx %r2,%3,%%g1" \
- : "=&r" ((USItype)(r1)), \
- "=&r" ((USItype)(r0)) \
- : "%rJ" ((USItype)(x3)), \
- "rI" ((USItype)(y3)), \
- "%rJ" ((USItype)(x2)), \
- "rI" ((USItype)(y2)), \
- "%rJ" ((USItype)(x1)), \
- "rI" ((USItype)(y1)), \
- "%rJ" ((USItype)(x0)), \
- "rI" ((USItype)(y0)) \
- : "cc", "g1", "g2"); \
- __asm__ __volatile__ ("" : "=r" (_t1), "=r" (_t2)); \
- r3 = _t1; r2 = _t2; \
- } while (0)
-
-#define __FP_FRAC_DEC_3(x2,x1,x0,y2,y1,y0) __FP_FRAC_SUB_3(x2,x1,x0,x2,x1,x0,y2,y1,y0)
-
-#define __FP_FRAC_DEC_4(x3,x2,x1,x0,y3,y2,y1,y0) __FP_FRAC_SUB_4(x3,x2,x1,x0,x3,x2,x1,x0,y3,y2,y1,y0)
-
-#define __FP_FRAC_ADDI_4(x3,x2,x1,x0,i) \
- __asm__ ("addcc %3,%4,%3
- addxcc %2,%%g0,%2
- addxcc %1,%%g0,%1
- addx %0,%%g0,%0" \
- : "=&r" ((USItype)(x3)), \
- "=&r" ((USItype)(x2)), \
- "=&r" ((USItype)(x1)), \
- "=&r" ((USItype)(x0)) \
- : "rI" ((USItype)(i)), \
- "0" ((USItype)(x3)), \
- "1" ((USItype)(x2)), \
- "2" ((USItype)(x1)), \
- "3" ((USItype)(x0)) \
- : "cc")
-
-#ifndef __SMP__
-extern struct task_struct *last_task_used_math;
-#endif
-
-/* Obtain the current rounding mode. */
-#ifndef FP_ROUNDMODE
-#ifdef __SMP__
-#define FP_ROUNDMODE ((current->thread.fsr >> 30) & 0x3)
-#else
-#define FP_ROUNDMODE ((last_task_used_math->thread.fsr >> 30) & 0x3)
-#endif
-#endif
-
-/* Exception flags. */
-#define FP_EX_INVALID (1 << 4)
-#define FP_EX_OVERFLOW (1 << 3)
-#define FP_EX_UNDERFLOW (1 << 2)
-#define FP_EX_DIVZERO (1 << 1)
-#define FP_EX_INEXACT (1 << 0)
-
-#define FP_HANDLE_EXCEPTIONS return _fex
-
-#ifdef __SMP__
-#define FP_INHIBIT_RESULTS ((current->thread.fsr >> 23) & _fex)
-#else
-#define FP_INHIBIT_RESULTS ((last_task_used_math->thread.fsr >> 23) & _fex)
-#endif
-
-#endif
#include <asm/uaccess.h>
#include "sfp-util.h"
-#include "soft-fp.h"
-#include "single.h"
-#include "double.h"
-#include "quad.h"
+#include <math-emu/soft-fp.h>
+#include <math-emu/single.h>
+#include <math-emu/double.h>
+#include <math-emu/quad.h>
/* QUAD - ftt == 3 */
#define FMOVQ 0x003
+++ /dev/null
-/* Machine-dependent software floating-point definitions.
- Sparc64 kernel version.
- Copyright (C) 1997,1998,1999 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- Contributed by Richard Henderson (rth@cygnus.com),
- Jakub Jelinek (jj@ultra.linux.cz) and
- David S. Miller (davem@redhat.com).
-
- The GNU C Library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Library General Public License as
- published by the Free Software Foundation; either version 2 of the
- License, or (at your option) any later version.
-
- The GNU C Library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public
- License along with the GNU C Library; see the file COPYING.LIB. If
- not, write to the Free Software Foundation, Inc.,
- 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
-
-#ifndef _SFP_MACHINE_H
-#define _SFP_MACHINE_H
-
-#define _FP_W_TYPE_SIZE 64
-#define _FP_W_TYPE unsigned long
-#define _FP_WS_TYPE signed long
-#define _FP_I_TYPE long
-
-#define _FP_MUL_MEAT_S(R,X,Y) \
- _FP_MUL_MEAT_1_imm(_FP_WFRACBITS_S,R,X,Y)
-#define _FP_MUL_MEAT_D(R,X,Y) \
- _FP_MUL_MEAT_1_wide(_FP_WFRACBITS_D,R,X,Y,umul_ppmm)
-#define _FP_MUL_MEAT_Q(R,X,Y) \
- _FP_MUL_MEAT_2_wide_3mul(_FP_WFRACBITS_Q,R,X,Y,umul_ppmm)
-
-#define _FP_DIV_MEAT_S(R,X,Y) _FP_DIV_MEAT_1_imm(S,R,X,Y,_FP_DIV_HELP_imm)
-#define _FP_DIV_MEAT_D(R,X,Y) _FP_DIV_MEAT_1_udiv(D,R,X,Y)
-#define _FP_DIV_MEAT_Q(R,X,Y) _FP_DIV_MEAT_2_udiv(Q,R,X,Y)
-
-#define _FP_NANFRAC_S ((_FP_QNANBIT_S << 1) - 1)
-#define _FP_NANFRAC_D ((_FP_QNANBIT_D << 1) - 1)
-#define _FP_NANFRAC_Q ((_FP_QNANBIT_Q << 1) - 1), -1
-#define _FP_NANSIGN_S 0
-#define _FP_NANSIGN_D 0
-#define _FP_NANSIGN_Q 0
-
-#define _FP_KEEPNANFRACP 1
-
-/* If one NaN is signaling and the other is not,
- * we choose that one, otherwise we choose X.
- */
-/* For _Qp_* and _Q_*, this should prefer X, for
- * CPU instruction emulation this should prefer Y.
- * (see SPAMv9 B.2.2 section).
- */
-#define _FP_CHOOSENAN(fs, wc, R, X, Y, OP) \
- do { \
- if ((_FP_FRAC_HIGH_RAW_##fs(Y) & _FP_QNANBIT_##fs) \
- && !(_FP_FRAC_HIGH_RAW_##fs(X) & _FP_QNANBIT_##fs)) \
- { \
- R##_s = X##_s; \
- _FP_FRAC_COPY_##wc(R,X); \
- } \
- else \
- { \
- R##_s = Y##_s; \
- _FP_FRAC_COPY_##wc(R,Y); \
- } \
- R##_c = FP_CLS_NAN; \
- } while (0)
-
-/* Obtain the current rounding mode. */
-#ifndef FP_ROUNDMODE
-#define FP_ROUNDMODE ((current->thread.xfsr[0] >> 30) & 0x3)
-#endif
-
-/* Exception flags. */
-#define FP_EX_INVALID (1 << 4)
-#define FP_EX_OVERFLOW (1 << 3)
-#define FP_EX_UNDERFLOW (1 << 2)
-#define FP_EX_DIVZERO (1 << 1)
-#define FP_EX_INEXACT (1 << 0)
-
-#define FP_HANDLE_EXCEPTIONS return _fex
-
-#define FP_INHIBIT_RESULTS ((current->thread.xfsr[0] >> 23) & _fex)
-
-#endif
#define MY_CARD_LIST { MANU_ATOMWIDE, PROD_ATOMWIDE_3PSERIAL }
#define MY_NUMPORTS 3
#define MY_BAUD_BASE (7372800 / 16)
-#define MY_INIT atomwide_serial_init
#define MY_BASE_ADDRESS(ec) \
ecard_address ((ec), ECARD_IOC, ECARD_SLOW) + (0x2000 >> 2)
#define MY_PORT_ADDRESS(port,cardaddr) \
((cardaddr) + 0x200 - (port) * 0x100)
+
+#define INIT serial_card_atomwide_init
+#define EXIT serial_card_atomwide_exit
+
#include "serial-card.c"
/*
* linux/arch/arm/drivers/char/serial-card.c
*
- * Copyright (c) 1996 Russell King.
+ * Copyright (c) 1996-1999 Russell King.
*
* A generic handler of serial expansion cards that use 16550s or
* the like.
* 22-04-1998 RMK Removed old register_pre_init_serial
*/
#include <linux/module.h>
+#include <linux/types.h>
#include <linux/serial.h>
#include <linux/errno.h>
+#include <linux/init.h>
+
#include <asm/ecard.h>
+#include <asm/string.h>
#ifndef NUM_SERIALS
#define NUM_SERIALS MY_NUMPORTS * MAX_ECARDS
__serial_addr[__serial_pcount] = (addr); \
__serial_pcount += 1; \
} while (0)
-#undef MY_INIT
-#define MY_INIT init_module
#else
#define ADD_ECARD(ec,card)
#define ADD_PORT(port,addr)
{
struct serial_struct req;
- memset(&req, 0, sizeof(serial_struct));
-
+ memset(&req, 0, sizeof(req));
req.baud_base = MY_BAUD_BASE;
req.irq = irq;
req.port = port;
return register_serial(&req);
}
-int MY_INIT (void)
+static int __init INIT (void)
{
int card = 0;
return card ? 0 : -ENODEV;
}
-#ifdef MODULE
-void cleanup_module (void)
+static void __exit EXIT (void)
{
+#ifdef MODULE
int i;
for (i = 0; i < __serial_pcount; i++) {
for (i = 0; i < MAX_ECARDS; i++)
if (expcard[i])
ecard_release (expcard[i]);
-}
#endif
+}
+
+EXPORT_NO_SYMBOLS;
+
+module_init(INIT);
+module_exit(EXIT);
#define MY_CARD_LIST { MANU_SERPORT, PROD_SERPORT_DSPORT }
#define MY_NUMPORTS 2
#define MY_BAUD_BASE (3686400 / 16)
-#define MY_INIT dualsp_serial_init
#define MY_BASE_ADDRESS(ec) \
ecard_address (ec, ECARD_IOC, ECARD_SLOW) + (0x2000 >> 2)
#define MY_PORT_ADDRESS(port,cardaddress) \
((cardaddress) + (port) * 8)
+
+#define INIT serial_card_dualsp_init
+#define EXIT serial_card_dualsp_exit
+
#include "serial-card.c"
struct packet_command *pc = (struct packet_command *) rq->buffer;
unsigned long wait = 0;
- printk("in expiry\n");
/* blank and format can take an extremly long time to
* complete, if the IMMED bit was not set.
*/
#ifdef CONFIG_MD_BOOT
struct {
- int set;
- int ints[100];
- char str[100];
+ unsigned long set;
+ int pers[MAX_MD_DEV];
+ kdev_t devices[MAX_MD_DEV][MAX_REAL];
} md_setup_args __initdata = {
- 0,{0},{0}
+ 0,{0},{{0}}
};
-/* called from init/main.c */
-void __init md_setup(char *str,int *ints)
-{
- int i;
- for(i=0;i<=ints[0];i++) {
- md_setup_args.ints[i] = ints[i];
- strcpy(md_setup_args.str, str);
-/* printk ("md: ints[%d]=%d.\n", i, ints[i]);*/
- }
- md_setup_args.set=1;
- return;
-}
-
-void __init do_md_setup(char *str,int *ints)
+/*
+ * Parse the command-line parameters given our kernel, but do not
+ * actually try to invoke the MD device now; that is handled by
+ * md_setup_drive after the low-level disk drivers have initialised.
+ *
+ * 27/11/1999: Fixed to work correctly with the 2.3 kernel (which
+ * assigns the task of parsing integer arguments to the
+ * invoked program now). Added ability to initialise all
+ * the MD devices (by specifying multiple "md=" lines)
+ * instead of just one. -- KTK
+ */
+int __init md_setup(char *str)
{
- int minor, pers, factor, fault;
- kdev_t dev;
- int i=1;
-
- if(ints[0] < 4) {
- printk ("md: Too few Arguments (%d).\n", ints[0]);
- return;
- }
-
- minor=ints[i++];
-
- if (minor >= MAX_MD_DEV) {
+ int minor, level, factor, fault, i;
+ kdev_t device;
+ char *devnames, *pername;
+
+ if(get_option(&str, &minor) != 2 || /* MD Number */
+ get_option(&str, &level) != 2 || /* RAID Personality */
+ get_option(&str, &factor) != 2 || /* Chunk Size */
+ get_option(&str, &fault) != 2) {
+ printk("md: Too few arguments supplied to md=.\n");
+ return 0;
+ } else if (minor >= MAX_MD_DEV) {
printk ("md: Minor device number too high.\n");
- return;
+ return 0;
+ } else if (md_setup_args.set & (1 << minor)) {
+ printk ("md: Warning - md=%d,... has been specified twice;\n"
+ " will discard the first definition.\n", minor);
}
-
- pers = 0;
-
- switch(ints[i++]) { /* Raidlevel */
- case -1:
+ switch(level) {
#ifdef CONFIG_MD_LINEAR
- pers = LINEAR;
- printk ("md: Setting up md%d as linear device.\n",minor);
-#else
- printk ("md: Linear mode not configured."
- "Recompile the kernel with linear mode enabled!\n");
-#endif
+ case -1:
+ level = LINEAR;
+ pername = "linear";
break;
- case 0:
- pers = STRIPED;
-#ifdef CONFIG_MD_STRIPED
- printk ("md: Setting up md%d as a striped device.\n",minor);
-#else
- printk ("md: Striped mode not configured."
- "Recompile the kernel with striped mode enabled!\n");
#endif
+#ifdef CONFIG_MD_STRIPED
+ case 0:
+ level = STRIPED;
+ pername = "striped";
break;
-/* not supported yet
- case 1:
- pers = RAID1;
- printk ("md: Setting up md%d as a raid1 device.\n",minor);
- break;
- case 5:
- pers = RAID5;
- printk ("md: Setting up md%d as a raid5 device.\n",minor);
- break;
-*/
- default:
- printk ("md: Unknown or not supported raid level %d.\n", ints[--i]);
- return;
+#endif
+ default:
+ printk ("md: The kernel has not been configured for raid%d"
+ " support!\n", level);
+ return 0;
}
-
- if(pers) {
-
- factor=ints[i++]; /* Chunksize */
- fault =ints[i++]; /* Faultlevel */
-
- pers=pers | factor | (fault << FAULT_SHIFT);
-
- while( str && (dev = name_to_kdev_t(str))) {
- do_md_add (minor, dev);
- if((str = strchr (str, ',')) != NULL)
- str++;
- }
-
- do_md_run (minor, pers);
- printk ("md: Loading md%d.\n",minor);
+ devnames = str;
+ for (i = 0; str; i++) {
+ if ((device = name_to_kdev_t(str))) {
+ md_setup_args.devices[minor][i] = device;
+ } else {
+ printk ("md: Unknown device name, %s.\n", str);
+ return 0;
+ }
+ if ((str = strchr(str, ',')) != NULL)
+ str++;
}
-
+ if (!i) {
+ printk ("md: No devices specified for md%d?\n", minor);
+ return 0;
+ }
+
+ printk ("md: Will configure md%d (%s) from %s, below.\n",
+ minor, pername, devnames);
+ md_setup_args.devices[minor][i] = (kdev_t) 0;
+ md_setup_args.pers[minor] = level | factor | (fault << FAULT_SHIFT);
+ md_setup_args.set |= (1 << minor);
+ return 0;
}
+
#endif
void linear_init (void);
#ifdef CONFIG_MD_BOOT
void __init md_setup_drive(void)
{
- if(md_setup_args.set)
- do_md_setup(md_setup_args.str, md_setup_args.ints);
+ int minor, i;
+ kdev_t dev;
+
+ for (minor = 0; minor < MAX_MD_DEV; minor++) {
+ if ((md_setup_args.set & (1 << minor)) == 0)
+ continue;
+ printk("md: Loading md%d.\n", minor);
+ for (i = 0; (dev = md_setup_args.devices[minor][i]); i++)
+ do_md_add (minor, dev);
+ do_md_run (minor, md_setup_args.pers[minor]);
+ }
}
+
+__setup("md=", md_setup);
#endif
static int ide_set_drive_pio_mode(ide_drive_t *drive, byte pio)
{
ide_hwif_t *hwif = HWIF(drive);
+ ide_startstop_t startstop;
if (pio > 2) {
/* FIXME: I don't believe that this SELECT_DRIVE is required,
OUT_BYTE(0x03, IDE_FEATURE_REG);
OUT_BYTE(WIN_SETFEATURES, IDE_COMMAND_REG);
- if (ide_wait_stat(drive, DRIVE_READY,
+ if (ide_wait_stat(&startstop, drive, DRIVE_READY,
BUSY_STAT|DRQ_STAT|ERR_STAT, WAIT_CMD)) {
printk("%s: drive not ready for command\n",
drive->name);
return ret;
break;
+ /* Get region settings */
+ case DVD_LU_SEND_RPC_STATE:
+ cdinfo(CD_DVD, "entering DVD_LU_SEND_RPC_STATE\n");
+ setup_report_key(&cgc, 0, 8);
+
+ if ((ret = cdo->generic_packet(cdi, &cgc)))
+ return ret;
+
+ ai->lrpcs.type = (buf[4] >> 6) & 3;
+ ai->lrpcs.vra = (buf[4] >> 3) & 7;
+ ai->lrpcs.ucca = buf[4] & 7;
+ ai->lrpcs.region_mask = buf[5];
+ ai->lrpcs.rpc_scheme = buf[6];
+ break;
+
+ /* Set region settings */
+ case DVD_HOST_SEND_RPC_STATE:
+ cdinfo(CD_DVD, "entering DVD_HOST_SEND_RPC_STATE\n");
+ setup_send_key(&cgc, 0, 6);
+ buf[4] = ai->hrpcs.pdrc;
+
+ if ((ret = cdo->generic_packet(cdi, &cgc)))
+ return ret;
+ break;
+
default:
cdinfo(CD_WARNING, "Invalid DVD key ioctl (%d)\n", ai->type);
return -ENOTTY;
if (!CDROM_CAN(CDC_LOCK))
return -EDRIVE_CANT_DO_THIS;
keeplocked = arg ? 1 : 0;
+ /* don't unlock the door on multiple opens */
+ if ((cdi->use_count != 1) && !arg)
+ return -EBUSY;
return cdo->lock_door(cdi, arg);
}
case CDROMPLAYTRKIND: {
struct cdrom_ti ti;
struct cdrom_tocentry entry;
+ struct cdrom_tochdr tochdr;
cdinfo(CD_DO_IOCTL, "entering CDROMPLAYTRKIND\n");
IOCTL_IN(arg, struct cdrom_ti, ti);
entry.cdte_format = CDROM_MSF;
/* get toc entry for start and end track */
- entry.cdte_track = ti.cdti_trk0;
- if (cdi->ops->audio_ioctl(cdi, CDROMREADTOCENTRY, &entry))
+ if (cdo->audio_ioctl(cdi, CDROMREADTOCHDR, &tochdr))
+ return -EINVAL;
+ entry.cdte_track = ti.cdti_trk1 + 1;
+ if (entry.cdte_track > tochdr.cdth_trk1)
+ return -EINVAL;
+ if (cdo->audio_ioctl(cdi, CDROMREADTOCENTRY, &entry))
return -EINVAL;
cgc.cmd[3] = entry.cdte_addr.msf.minute;
int error = 0;
unsigned int last = lp_table[minor].last_error;
unsigned char status = r_str(minor);
- if (status & LP_PERRORP)
+ if ((status & LP_PERRORP) && !(LP_F(minor) & LP_CAREFUL))
/* No error. */
last = 0;
else if ((status & LP_POUTPA)) {
printk(KERN_INFO "lp%d off-line\n", minor);
}
error = -EIO;
- } else {
+ } else if (!(status & LP_PERRORP)) {
if (last != LP_PERRORP) {
last = LP_PERRORP;
printk(KERN_INFO "lp%d on fire\n", minor);
}
error = -EIO;
+ } else {
+ last = 0; /* Come here if LP_CAREFUL is set and no
+ errors are reported. */
}
lp_table[minor].last_error = last;
else
LP_F(minor) &= ~LP_ABORTOPEN;
break;
-#ifdef OBSOLETED
case LPCAREFUL:
if (arg)
LP_F(minor) |= LP_CAREFUL;
else
LP_F(minor) &= ~LP_CAREFUL;
break;
-#endif
case LPWAIT:
LP_WAIT(minor) = arg;
break;
{
int i;
struct serial_state * state;
- extern void atomwide_serial_init (void);
- extern void dualsp_serial_init (void);
-
-#ifdef CONFIG_ATOMWIDE_SERIAL
- atomwide_serial_init ();
-#endif
-#ifdef CONFIG_DUALSP_SERIAL
- dualsp_serial_init ();
-#endif
if (timer_table[RS_TIMER].fn) {
printk("RS_TIMER already set, another serial driver "
#include <linux/init.h>
#include <linux/miscdevice.h>
#include <linux/sched.h>
+#include <linux/time.h>
#include <linux/wait.h>
#include <linux/spinlock.h>
#include <linux/ioport.h>
#define DECLARE_WAIT_QUEUE_HEAD(x) struct wait_queue * x = NULL
#endif
+/*
+ * Yes, it's unfortunate that we are relying on get_cmos_time
+ * because it is slow (> 1 sec.) and i386 only. It might be better
+ * to use some of the code from drivers/char/rtc.c in the near future
+ */
+extern unsigned long get_cmos_time(void);
+
static int acpi_control_thread(void *context);
static int acpi_do_ulong(ctl_table *ctl,
int write,
struct file *file,
void *buffer,
size_t *len);
-#if 0
-static int acpi_do_sleep_wake(ctl_table *ctl,
- int write,
- struct file *file,
- void *buffer,
- size_t *len);
-#endif
+static int acpi_do_sleep(ctl_table *ctl,
+ int write,
+ struct file *file,
+ void *buffer,
+ size_t *len);
-DECLARE_WAIT_QUEUE_HEAD(acpi_idle_wait);
+DECLARE_WAIT_QUEUE_HEAD(acpi_control_wait);
static struct ctl_table_header *acpi_sysctl = NULL;
static unsigned long acpi_facp_addr = 0;
static unsigned long acpi_dsdt_addr = 0;
+// current system sleep state (S0 - S4)
+static acpi_sstate_t acpi_sleep_state = ACPI_S0;
+// time sleep began
+static unsigned long acpi_sleep_start = 0;
+
static spinlock_t acpi_event_lock = SPIN_LOCK_UNLOCKED;
static volatile u32 acpi_pm1_status = 0;
static volatile u32 acpi_gpe_status = 0;
static volatile u32 acpi_gpe_level = 0;
+static volatile acpi_sstate_t acpi_event_state = ACPI_S0;
static DECLARE_WAIT_QUEUE_HEAD(acpi_event_wait);
static spinlock_t acpi_devs_lock = SPIN_LOCK_UNLOCKED;
&acpi_p_lvl3_lat, sizeof(acpi_p_lvl3_lat),
0644, NULL, &acpi_do_ulong},
+ {ACPI_S0_SLP_TYP, "s0_slp_typ",
+ &acpi_slp_typ[ACPI_S0], sizeof(acpi_slp_typ[ACPI_S0]),
+ 0600, NULL, &acpi_do_ulong},
+
+ {ACPI_S1_SLP_TYP, "s1_slp_typ",
+ &acpi_slp_typ[ACPI_S1], sizeof(acpi_slp_typ[ACPI_S1]),
+ 0600, NULL, &acpi_do_ulong},
+
{ACPI_S5_SLP_TYP, "s5_slp_typ",
- &acpi_slp_typ[5], sizeof(acpi_slp_typ[5]),
+ &acpi_slp_typ[ACPI_S5], sizeof(acpi_slp_typ[ACPI_S5]),
0600, NULL, &acpi_do_ulong},
-#if 0
- {123, "sleep", (void*) 1, 0, 0600, NULL, &acpi_do_sleep_wake},
- {124, "wake", NULL, 0, 0600, NULL, &acpi_do_sleep_wake},
-#endif
+ {ACPI_SLEEP, "sleep", NULL, 0, 0600, NULL, &acpi_do_sleep},
{0}
};
acpi_pm1_status |= pm1_status;
acpi_gpe_status |= gpe_status;
spin_unlock_irqrestore(&acpi_event_lock, flags);
+ acpi_event_state = acpi_sleep_state;
wake_up_interruptible(&acpi_event_wait);
}
return status;
}
+/*
+ * Update system time from real-time clock
+ */
+static void acpi_update_clock(void)
+{
+ if (acpi_sleep_start) {
+ unsigned long delta;
+ struct timeval tv;
+
+ delta = get_cmos_time() - acpi_sleep_start;
+ do_gettimeofday(&tv);
+ tv.tv_sec += delta;
+ do_settimeofday(&tv);
+
+ acpi_sleep_start = 0;
+ }
+}
+
+
/*
* Enter system sleep state
*/
typb = ((typb << ACPI_SLP_TYP_SHIFT) & ACPI_SLP_TYP_MASK);
if (state != ACPI_S0) {
+ acpi_sleep_start = get_cmos_time();
acpi_enter_dx(ACPI_D3);
+ acpi_sleep_state = state;
}
+ // clear wake status
+ acpi_write_pm1_status(acpi_facp, ACPI_WAK);
+
// set SLP_TYPa/b and SLP_EN
if (acpi_facp->pm1a_cnt) {
value = inw(acpi_facp->pm1a_cnt) & ~ACPI_SLP_TYP_MASK;
}
if (state == ACPI_S0) {
+ acpi_sleep_state = state;
acpi_enter_dx(ACPI_D0);
+ acpi_sleep_start = 0;
+ }
+ else if (state == ACPI_S1) {
+ // wait until S1 is entered
+ while (!(acpi_read_pm1_status(acpi_facp) & ACPI_WAK)) ;
+ // finished sleeping, update system time
+ acpi_update_clock();
}
}
}
size_t *len)
{
u32 pm1_status = 0, gpe_status = 0;
- char str[4 * sizeof(u32) + 7];
+ acpi_sstate_t event_state = 0;
+ char str[27];
int size;
if (write)
gpe_status = acpi_gpe_status;
acpi_gpe_status = 0;
spin_unlock_irqrestore(&acpi_event_lock, flags);
+ event_state = acpi_event_state;
if (pm1_status || gpe_status)
break;
return -ERESTARTSYS;
}
- size = sprintf(str, "0x%08x 0x%08x\n", pm1_status, gpe_status);
+ size = sprintf(str, "0x%08x 0x%08x 0x%01x\n",
+ pm1_status,
+ gpe_status,
+ event_state);
copy_to_user(buffer, str, size);
*len = size;
file->f_pos += size;
return 0;
}
-#if 0
/*
- * Sleep or wake system
+ * Enter system sleep state
*/
-static int acpi_do_sleep_wake(ctl_table *ctl,
- int write,
- struct file *file,
- void *buffer,
- size_t *len)
+static int acpi_do_sleep(ctl_table *ctl,
+ int write,
+ struct file *file,
+ void *buffer,
+ size_t *len)
{
if (!write) {
if (file->f_pos) {
}
else
{
- // just shutdown some devices for now
- if (ctl->data) {
- acpi_enter_dx(ACPI_D3);
- }
- else {
- acpi_enter_dx(ACPI_D0);
- }
+ acpi_enter_sx(ACPI_S1);
+ acpi_enter_sx(ACPI_S0);
}
file->f_pos += *len;
return 0;
}
-#endif
/*
* Initialize and enable ACPI
strcpy(current->comm, "acpi");
for(;;) {
- interruptible_sleep_on(&acpi_idle_wait);
+ interruptible_sleep_on(&acpi_control_wait);
if (signal_pending(current))
break;
- // find all idle devices and set idle timer based on policy
+ // find all idle devices and set idle timer
}
return 0;
/*
* Module visible symbols
*/
-EXPORT_SYMBOL(acpi_idle_wait);
+EXPORT_SYMBOL(acpi_control_wait);
EXPORT_SYMBOL(acpi_register);
EXPORT_SYMBOL(acpi_unregister);
EXPORT_SYMBOL(acpi_wakeup);
0.544 8-May-99 Fix for buggy SROM in Motorola embedded boards using
a 21143 by <mmporter@home.com>.
Change PCI/EISA bus probing order.
+ 0.545 28-Nov-99 Further Moto SROM bug fix from
+ <mporter@eng.mcd.mot.com>
+ Remove double checking for DEBUG_RX in de4x5_dbg_rx()
+ from report by <geert@linux-m68k.org>
=========================================================================
*/
-static const char *version = "de4x5.c:V0.544 1999/5/8 davies@maniac.ultranet.com\n";
+static const char *version = "de4x5.c:V0.545 1999/11/28 davies@maniac.ultranet.com\n";
#include <linux/config.h>
#include <linux/module.h>
} else if ((lp->media == INIT) && (lp->timeout < 0)) {
lp->ibn = 3;
lp->active = *p;
+ if (MOTO_SROM_BUG) lp->active = 0;
lp->infoblock_csr6 = OMR_MII_100;
lp->useMII = TRUE;
lp->infoblock_media = ANS;
(u_char)skb->data[12],
(u_char)skb->data[13],
len);
- if (de4x5_debug & DEBUG_RX) {
- for (j=0; len>0;j+=16, len-=16) {
- printk(" %03x: ",j);
- for (i=0; i<16 && i<len; i++) {
- printk("%02x ",(u_char)skb->data[i+j]);
- }
- printk("\n");
- }
+ for (j=0; len>0;j+=16, len-=16) {
+ printk(" %03x: ",j);
+ for (i=0; i<16 && i<len; i++) {
+ printk("%02x ",(u_char)skb->data[i+j]);
+ }
+ printk("\n");
}
}
** hp100.c
** HP CASCADE Architecture Driver for 100VG-AnyLan Network Adapters
**
-** $Id: hp100.c,v 1.57 1998/04/10 16:27:23 perex Exp perex $
+** $Id: hp100.c,v 1.58 1999/11/30 17:20:20 perex Exp perex $
**
** Based on the HP100 driver written by Jaroslav Kysela <perex@jcu.cz>
** Extended for new busmaster capable chipsets by
-** Siegfried "Frieder" Loeffler (dg1sek) <floeff@mathematik.uni-stuttgart.de>
+** Siegfried "Frieder" Loeffler (dg1sek) <loeffler@cdi.fr>
**
** Maintained by: Jaroslav Kysela <perex@jcu.cz>
**
** along with this program; if not, write to the Free Software
** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
**
+** 1.57 -> 1.58
+** - 'no connection found' message is time limited now
**
** 1.56 -> 1.57
** - updates for new PCI interface for 2.1 kernels
hp100_stop_interface( dev );
if ( ( lp->lan_type = hp100_sense_lan( dev ) ) < 0 )
{
- printk( "hp100: %s: no connection found - check wire\n", dev->name );
+ /* Added Mon Nov 1 06:13:19 1999 by Brian Moore
+ * (mooreb@iname.com) to prevent too much kernel IO
+ * in the case of not having a network connection
+ */
+ {
+ int thistime = jiffies;
+ static int delaytime = 10*HZ;
+ static int lasttime = thistime - delaytime;
+ // We don't worry about rollover
+ if(thistime >= (lasttime + delaytime)) {
+ printk( "hp100: %s: no connection found - check wire\n", dev->name );
+ lasttime = thistime;
+ }
+ }
hp100_start_interface( dev ); /* 10Mb/s RX pkts maybe handled */
return -EIO;
}
dev = dev_cache;
memset(dev, 0, sizeof(*dev));
dev->bus = bus;
+ dev->sysdata = bus->sysdata;
dev->devfn = devfn;
if (pci_read_config_byte(dev, PCI_HEADER_TYPE, &hdr_type))
child->self = dev;
child->parent = bus;
child->ops = bus->ops;
+ child->sysdata = bus->sysdata;
/*
* Set up the primary, secondary and subordinate
int isapnp_disable = 0; /* Disable ISA PnP */
int isapnp_rdp = 0; /* Read Data Port */
-int isapnp_reset = 0; /* reset all PnP cards (deactivate) */
+int isapnp_reset = 1; /* reset all PnP cards (deactivate) */
int isapnp_skip_pci_scan = 0; /* skip PCI resource scanning */
int isapnp_verbose = 1; /* verbose mode */
int isapnp_reserve_irq[16] = { [0 ... 15] = -1 }; /* reserve (don't use) some IRQ */
static inline void write_address(unsigned char x)
{
outb(x, _PIDXR);
- udelay(10);
+ udelay(20);
}
static inline unsigned char read_data(void)
{
isapnp_device(logdev);
isapnp_write_byte(ISAPNP_CFG_ACTIVATE, 0);
+ udelay(500);
}
static void __init isapnp_peek(unsigned char *data, int bytes)
d = isapnp_read_byte(0x05);
if (d & 1)
break;
- udelay(10);
+ udelay(100);
}
if (!(d & 1)) {
*data++ = 0xff;
udelay(250);
iteration++;
isapnp_wake(0x00);
+ isapnp_set_rdp();
+ udelay(1000);
write_address(0x01);
+ udelay(1000);
goto __next;
}
if (iteration == 1) {
static unsigned char isapnp_get_hex(unsigned char c)
{
- if (c >= '0' || c <= '9')
+ if (c >= '0' && c <= '9')
return c - '0';
- if (c >= 'a' || c <= 'f')
+ if (c >= 'a' && c <= 'f')
return (c - 'a') + 10;
- if (c >= 'A' || c <= 'F')
+ if (c >= 'A' && c <= 'F')
return (c - 'A') + 10;
return 0;
}
#include <linux/proc_fs.h>
#include <linux/blk.h>
#include <linux/tqueue.h>
+#include <linux/init.h>
#include "sd.h"
#include "scsi.h"
#include "hosts.h"
* to a parameter with a ':' between the parameter and the value.
* ie. aic7xxx=unpause:0x0A,extended
*-F*************************************************************************/
-void
-aic7xxx_setup(char *s, int *dummy)
+static void
+aic7xxx_setup(char *s)
{
int i, n;
char *p;
}
}
+__setup("aic7xxx=", aix7xxx_setup);
+
/*+F*************************************************************************
* Function:
* pause_sequencer
#define PCI_ID_LOW 0x00 /* vendor id */
#define PCI_ID_HIGH 0x02 /* device id */
#define ISP_CFG0 0x04 /* configuration register #0 */
+#define ISP_CFG0_HWMSK 0x000f /* Hardware revision mask */
+#define ISP_CFG0_1020 0x0001 /* ISP1020 */
+#define ISP_CFG0_1020A 0x0002 /* ISP1020A */
+#define ISP_CFG0_1040 0x0003 /* ISP1040 */
+#define ISP_CFG0_1040A 0x0004 /* ISP1040A */
+#define ISP_CFG0_1040B 0x0005 /* ISP1040B */
+#define ISP_CFG0_1040C 0x0006 /* ISP1040C */
#define ISP_CFG1 0x06 /* configuration register #1 */
+#define ISP_CFG1_F128 0x0040 /* 128-byte FIFO threshold */
+#define ISP_CFG1_F64 0x0030 /* 128-byte FIFO threshold */
+#define ISP_CFG1_F32 0x0020 /* 128-byte FIFO threshold */
+#define ISP_CFG1_F16 0x0010 /* 128-byte FIFO threshold */
+#define ISP_CFG1_BENAB 0x0004 /* Global Bus burst enable */
+#define ISP_CFG1_SXP 0x0001 /* SXP register select */
#define PCI_INTF_CTL 0x08 /* pci interface control */
#define PCI_INTF_STS 0x0a /* pci interface status */
#define PCI_SEMAPHORE 0x0c /* pci semaphore */
#define PCI_NVRAM 0x0e /* pci nvram interface */
+#define CDMA_CONF 0x20 /* Command DMA Config */
+#define DDMA_CONF 0x40 /* Data DMA Config */
+#define DMA_CONF_SENAB 0x0008 /* SXP to DMA Data enable */
+#define DMA_CONF_RIRQ 0x0004 /* RISC interrupt enable */
+#define DMA_CONF_BENAB 0x0002 /* Bus burst enable */
+#define DMA_CONF_DIR 0x0001 /* DMA direction (0=fifo->host 1=host->fifo) */
/* mailbox registers */
#define MBOX0 0x70 /* mailbox 0 */
#define QUEUE_ENTRY_LEN 64
struct isp1020_hostdata {
+ u_long memaddr;
u_char revision;
struct host_param host_param;
struct dev_param dev_param[MAX_TARGETS];
static void isp1020_print_status_entry(struct Status_Entry *);
#endif
+static inline u_short isp_inw(struct Scsi_Host *host, long offset)
+{
+ struct isp1020_hostdata *h = (struct isp1020_hostdata *)host->hostdata;
+ if (h->memaddr)
+ return readw(h->memaddr + offset);
+ else
+ return inw(host->io_port + offset);
+}
+
+static inline void isp_outw(u_short val, struct Scsi_Host *host, long offset)
+{
+ struct isp1020_hostdata *h = (struct isp1020_hostdata *)host->hostdata;
+ if (h->memaddr)
+ writew(val, h->memaddr + offset);
+ else
+ outw(val, host->io_port + offset);
+}
+
static inline void isp1020_enable_irqs(struct Scsi_Host *host)
{
- outw(ISP_EN_INT|ISP_EN_RISC, host->io_port + PCI_INTF_CTL);
+ isp_outw(ISP_EN_INT|ISP_EN_RISC, host, PCI_INTF_CTL);
}
static inline void isp1020_disable_irqs(struct Scsi_Host *host)
{
- outw(0x0, host->io_port + PCI_INTF_CTL);
+ isp_outw(0x0, host, PCI_INTF_CTL);
}
request_region(host->io_port, 0xff, "qlogicisp");
- outw(0x0, host->io_port + PCI_SEMAPHORE);
- outw(HCCR_CLEAR_RISC_INTR, host->io_port + HOST_HCCR);
+ isp_outw(0x0, host, PCI_SEMAPHORE);
+ isp_outw(HCCR_CLEAR_RISC_INTR, host, HOST_HCCR);
isp1020_enable_irqs(host);
hosts++;
hostdata = (struct isp1020_hostdata *) host->hostdata;
- outw(0x0, host->io_port + PCI_INTF_CTL);
+ isp_outw(0x0, host, PCI_INTF_CTL);
free_irq(host->irq, host);
release_region(host->io_port, 0xff);
hostdata = (struct isp1020_hostdata *) host->hostdata;
sprintf(buf,
- "QLogic ISP1020 SCSI on PCI bus %02x device %02x irq %d base 0x%lx",
+ "QLogic ISP1020 SCSI on PCI bus %02x device %02x irq %d %s base 0x%lx",
hostdata->pci_dev->bus->number, hostdata->pci_dev->devfn, host->irq,
- host->io_port);
+ (host->io_port ? "I/O" : "MEM"),
+ (host->io_port ? host->io_port : hostdata->memaddr));
LEAVE("isp1020_info");
DEBUG(isp1020_print_scsi_cmd(Cmnd));
- out_ptr = inw(host->io_port + MBOX4);
+ out_ptr = isp_inw(host, + MBOX4);
in_ptr = hostdata->req_in_ptr;
DEBUG(printk("qlogicisp : request queue depth %d\n",
hostdata->send_marker = 0;
if (((in_ptr + 1) & QLOGICISP_REQ_QUEUE_LEN) == out_ptr) {
- outw(in_ptr, host->io_port + MBOX4);
+ isp_outw(in_ptr, host, MBOX4);
hostdata->req_in_ptr = in_ptr;
printk("qlogicisp : request queue overflow\n");
return 1;
cmd->segment_cnt = cpu_to_le16(1);
}
- outw(in_ptr, host->io_port + MBOX4);
+ isp_outw(in_ptr, host, MBOX4);
hostdata->req_in_ptr = in_ptr;
num_free = QLOGICISP_REQ_QUEUE_LEN - REQ_QUEUE_DEPTH(in_ptr, out_ptr);
DEBUG_INTR(printk("qlogicisp : interrupt on line %d\n", irq));
- if (!(inw(host->io_port + PCI_INTF_STS) & 0x04)) {
+ if (!(isp_inw(host, PCI_INTF_STS) & 0x04)) {
/* spurious interrupts can happen legally */
DEBUG_INTR(printk("qlogicisp: got spurious interrupt\n"));
return;
}
- in_ptr = inw(host->io_port + MBOX5);
- outw(HCCR_CLEAR_RISC_INTR, host->io_port + HOST_HCCR);
+ in_ptr = isp_inw(host, MBOX5);
+ isp_outw(HCCR_CLEAR_RISC_INTR, host, HOST_HCCR);
- if ((inw(host->io_port + PCI_SEMAPHORE) & ASYNC_EVENT_INTERRUPT)) {
- status = inw(host->io_port + MBOX0);
+ if ((isp_inw(host, PCI_SEMAPHORE) & ASYNC_EVENT_INTERRUPT)) {
+ status = isp_inw(host, MBOX0);
DEBUG_INTR(printk("qlogicisp : mbox completion status: %x\n",
status));
printk("qlogicisp : bad mailbox return status\n");
break;
}
- outw(0x0, host->io_port + PCI_SEMAPHORE);
+ isp_outw(0x0, host, PCI_SEMAPHORE);
}
out_ptr = hostdata->res_out_ptr;
else
Cmnd->result = DID_ERROR << 16;
- outw(out_ptr, host->io_port + MBOX5);
+ isp_outw(out_ptr, host, MBOX5);
(*Cmnd->scsi_done)(Cmnd);
}
hostdata->res_out_ptr = out_ptr;
ENTER("isp1020_reset_hardware");
- outw(ISP_RESET, host->io_port + PCI_INTF_CTL);
+ isp_outw(ISP_RESET, host, PCI_INTF_CTL);
udelay(100);
- outw(HCCR_RESET, host->io_port + HOST_HCCR);
+ isp_outw(HCCR_RESET, host, HOST_HCCR);
udelay(100);
- outw(HCCR_RELEASE, host->io_port + HOST_HCCR);
- outw(HCCR_BIOS_DISABLE, host->io_port + HOST_HCCR);
+ isp_outw(HCCR_RELEASE, host, HOST_HCCR);
+ isp_outw(HCCR_BIOS_DISABLE, host, HOST_HCCR);
loop_count = DEFAULT_LOOP_COUNT;
- while (--loop_count && inw(host->io_port + HOST_HCCR) == RISC_BUSY)
+ while (--loop_count && isp_inw(host, HOST_HCCR) == RISC_BUSY)
barrier();
if (!loop_count)
printk("qlogicisp: reset_hardware loop timeout\n");
- outw(0, host->io_port + ISP_CFG1);
+ isp_outw(0, host, ISP_CFG1);
#if DEBUG_ISP1020
- printk("qlogicisp : mbox 0 0x%04x \n", inw(host->io_port + MBOX0));
- printk("qlogicisp : mbox 1 0x%04x \n", inw(host->io_port + MBOX1));
- printk("qlogicisp : mbox 2 0x%04x \n", inw(host->io_port + MBOX2));
- printk("qlogicisp : mbox 3 0x%04x \n", inw(host->io_port + MBOX3));
- printk("qlogicisp : mbox 4 0x%04x \n", inw(host->io_port + MBOX4));
- printk("qlogicisp : mbox 5 0x%04x \n", inw(host->io_port + MBOX5));
+ printk("qlogicisp : mbox 0 0x%04x \n", isp_inw(host, MBOX0));
+ printk("qlogicisp : mbox 1 0x%04x \n", isp_inw(host, MBOX1));
+ printk("qlogicisp : mbox 2 0x%04x \n", isp_inw(host, MBOX2));
+ printk("qlogicisp : mbox 3 0x%04x \n", isp_inw(host, MBOX3));
+ printk("qlogicisp : mbox 4 0x%04x \n", isp_inw(host, MBOX4));
+ printk("qlogicisp : mbox 5 0x%04x \n", isp_inw(host, MBOX5));
#endif /* DEBUG_ISP1020 */
param[0] = MBOX_NO_OP;
static int isp1020_init(struct Scsi_Host *sh)
{
- u_long io_base, io_flags;
+ u_long io_base, mem_base, io_flags, mem_flags;
struct isp1020_hostdata *hostdata;
u_char revision;
u_int irq;
}
io_base = pdev->resource[0].start;
+ mem_base = pdev->resource[1].start;
io_flags = pdev->resource[0].flags;
+ mem_flags = pdev->resource[1].flags;
irq = pdev->irq;
if (pdev->vendor != PCI_VENDOR_ID_QLOGIC) {
}
#ifdef __sparc__
+ if (mem_base)
+ mem_base = __pa(mem_base);
command |= (PCI_COMMAND_MASTER|PCI_COMMAND_IO|PCI_COMMAND_MEMORY|
PCI_COMMAND_INVALIDATE|PCI_COMMAND_SERR);
pci_write_config_word(pdev, PCI_COMMAND, command);
pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 64);
#endif
- if (! ((command & PCI_COMMAND_IO)
- && ((io_flags & PCI_BASE_ADDRESS_SPACE)
- == PCI_BASE_ADDRESS_SPACE_IO))) {
- printk("qlogicisp : i/o mapping is disabled\n");
- return 1;
+ if ((command & PCI_COMMAND_MEMORY) &&
+ ((mem_flags & 1) == 0)) {
+ mem_base = (u_long) ioremap(mem_base, PAGE_SIZE);
+ hostdata->memaddr = mem_base;
+ io_base = 0;
+ } else {
+ if (command & PCI_COMMAND_IO && (io_flags & 3) != 1)
+ {
+ printk("qlogicisp : i/o mapping is disabled\n");
+ return 1;
+ }
+ hostdata->memaddr = 0;
+ sh->io_port = io_base;
+ mem_base = 0;
}
if (!(command & PCI_COMMAND_MASTER)) {
if (revision != ISP1020_REV_ID)
printk("qlogicisp : new isp1020 revision ID (%d)\n", revision);
- if (inw(io_base + PCI_ID_LOW) != PCI_VENDOR_ID_QLOGIC
- || inw(io_base + PCI_ID_HIGH) != PCI_DEVICE_ID_QLOGIC_ISP1020)
+ if (isp_inw(sh, PCI_ID_LOW) != PCI_VENDOR_ID_QLOGIC
+ || isp_inw(sh, PCI_ID_HIGH) != PCI_DEVICE_ID_QLOGIC_ISP1020)
{
- printk("qlogicisp : can't decode i/o address space 0x%lx\n",
- io_base);
+ printk("qlogicisp : can't decode %s address space 0x%lx\n",
+ (io_base ? "I/O" : "MEM"),
+ (io_base ? io_base : mem_base));
return 1;
}
hostdata->revision = revision;
sh->irq = irq;
- sh->io_port = io_base;
sh->max_id = MAX_TARGETS;
sh->max_lun = MAX_LUNS;
for (i = 8; i >= 0; i--) {
output = ((byte >> i) & 0x1) ? 0x4 : 0x0;
- outw(output | 0x2, host->io_port + PCI_NVRAM); NVRAM_DELAY();
- outw(output | 0x3, host->io_port + PCI_NVRAM); NVRAM_DELAY();
- outw(output | 0x2, host->io_port + PCI_NVRAM); NVRAM_DELAY();
+ isp_outw(output | 0x2, host, PCI_NVRAM); NVRAM_DELAY();
+ isp_outw(output | 0x3, host, PCI_NVRAM); NVRAM_DELAY();
+ isp_outw(output | 0x2, host, PCI_NVRAM); NVRAM_DELAY();
}
for (i = 0xf, value = 0; i >= 0; i--) {
value <<= 1;
- outw(0x3, host->io_port + PCI_NVRAM); NVRAM_DELAY();
- input = inw(host->io_port + PCI_NVRAM); NVRAM_DELAY();
- outw(0x2, host->io_port + PCI_NVRAM); NVRAM_DELAY();
+ isp_outw(0x3, host, PCI_NVRAM); NVRAM_DELAY();
+ input = isp_inw(host, PCI_NVRAM); NVRAM_DELAY();
+ isp_outw(0x2, host, PCI_NVRAM); NVRAM_DELAY();
if (input & 0x8) value |= 1;
}
- outw(0x0, host->io_port + PCI_NVRAM); NVRAM_DELAY();
+ isp_outw(0x0, host, PCI_NVRAM); NVRAM_DELAY();
return value;
}
int i, k;
u_int queue_addr;
u_short param[6];
- u_short isp_cfg1;
+ u_short isp_cfg1, hwrev;
unsigned long flags;
struct isp1020_hostdata *hostdata =
(struct isp1020_hostdata *) host->hostdata;
save_flags(flags);
cli();
- outw(hostdata->host_param.fifo_threshold, host->io_port + ISP_CFG1);
+ hwrev = isp_inw(host, ISP_CFG0) & ISP_CFG0_HWMSK;
+ isp_cfg1 = ISP_CFG1_F64 | ISP_CFG1_BENAB;
+ if (hwrev == ISP_CFG0_1040A) {
+ /* Busted fifo, says mjacob. */
+ isp_cfg1 &= ISP_CFG1_BENAB;
+ }
+
+ isp_outw(isp_inw(host, ISP_CFG1) | isp_cfg1, host, ISP_CFG1);
+ isp_outw(isp_inw(host, CDMA_CONF) | DMA_CONF_BENAB, host, CDMA_CONF);
+ isp_outw(isp_inw(host, DDMA_CONF) | DMA_CONF_BENAB, host, DDMA_CONF);
param[0] = MBOX_SET_INIT_SCSI_ID;
param[1] = hostdata->host_param.initiator_scsi_id;
return 1;
}
- isp_cfg1 = inw(host->io_port + ISP_CFG1);
-
- if (hostdata->host_param.data_dma_burst_enable
- || hostdata->host_param.command_dma_burst_enable)
- isp_cfg1 |= 0x0004;
- else
- isp_cfg1 &= 0xfffb;
-
- outw(isp_cfg1, host->io_port + ISP_CFG1);
-
param[0] = MBOX_SET_TAG_AGE_LIMIT;
param[1] = hostdata->host_param.tag_aging;
return 1;
loop_count = DEFAULT_LOOP_COUNT;
- while (--loop_count && inw(host->io_port + HOST_HCCR) & 0x0080)
+ while (--loop_count && isp_inw(host, HOST_HCCR) & 0x0080)
barrier();
if (!loop_count)
printk("qlogicisp: mbox_command loop timeout #1\n");
switch(mbox_param[param[0]] >> 4) {
- case 6: outw(param[5], host->io_port + MBOX5);
- case 5: outw(param[4], host->io_port + MBOX4);
- case 4: outw(param[3], host->io_port + MBOX3);
- case 3: outw(param[2], host->io_port + MBOX2);
- case 2: outw(param[1], host->io_port + MBOX1);
- case 1: outw(param[0], host->io_port + MBOX0);
+ case 6: isp_outw(param[5], host, MBOX5);
+ case 5: isp_outw(param[4], host, MBOX4);
+ case 4: isp_outw(param[3], host, MBOX3);
+ case 3: isp_outw(param[2], host, MBOX2);
+ case 2: isp_outw(param[1], host, MBOX1);
+ case 1: isp_outw(param[0], host, MBOX0);
}
- outw(0x0, host->io_port + PCI_SEMAPHORE);
- outw(HCCR_CLEAR_RISC_INTR, host->io_port + HOST_HCCR);
- outw(HCCR_SET_HOST_INTR, host->io_port + HOST_HCCR);
+ isp_outw(0x0, host, PCI_SEMAPHORE);
+ isp_outw(HCCR_CLEAR_RISC_INTR, host, HOST_HCCR);
+ isp_outw(HCCR_SET_HOST_INTR, host, HOST_HCCR);
loop_count = DEFAULT_LOOP_COUNT;
- while (--loop_count && !(inw(host->io_port + PCI_INTF_STS) & 0x04))
+ while (--loop_count && !(isp_inw(host, PCI_INTF_STS) & 0x04))
barrier();
if (!loop_count)
printk("qlogicisp: mbox_command loop timeout #2\n");
loop_count = DEFAULT_LOOP_COUNT;
- while (--loop_count && inw(host->io_port + MBOX0) == 0x04)
+ while (--loop_count && isp_inw(host, MBOX0) == 0x04)
barrier();
if (!loop_count)
printk("qlogicisp: mbox_command loop timeout #3\n");
switch(mbox_param[param[0]] & 0xf) {
- case 6: param[5] = inw(host->io_port + MBOX5);
- case 5: param[4] = inw(host->io_port + MBOX4);
- case 4: param[3] = inw(host->io_port + MBOX3);
- case 3: param[2] = inw(host->io_port + MBOX2);
- case 2: param[1] = inw(host->io_port + MBOX1);
- case 1: param[0] = inw(host->io_port + MBOX0);
+ case 6: param[5] = isp_inw(host, MBOX5);
+ case 5: param[4] = isp_inw(host, MBOX4);
+ case 4: param[3] = isp_inw(host, MBOX3);
+ case 3: param[2] = isp_inw(host, MBOX2);
+ case 2: param[1] = isp_inw(host, MBOX1);
+ case 1: param[0] = isp_inw(host, MBOX0);
}
- outw(0x0, host->io_port + PCI_SEMAPHORE);
- outw(HCCR_CLEAR_RISC_INTR, host->io_port + HOST_HCCR);
+ isp_outw(0x0, host, PCI_SEMAPHORE);
+ isp_outw(HCCR_CLEAR_RISC_INTR, host, HOST_HCCR);
return 0;
}
char *bus_type, dma_name[16];
/* Allowed BIOS base addresses (NULL indicates reserved) */
- void *bios_segment_table[8] = {
- NULL,
- (void *) 0xc4000, (void *) 0xc8000, (void *) 0xcc000, (void *) 0xd0000,
- (void *) 0xd4000, (void *) 0xd8000, (void *) 0xdc000
+ unsigned long bios_segment_table[8] = {
+ 0,
+ 0xc4000, 0xc8000, 0xcc000, 0xd0000,
+ 0xd4000, 0xd8000, 0xdc000
};
/* Allowed IRQs */
* 03.09.99 0.21 change read semantics for MIDI to match
* OSS more closely; remove possible wakeup race
* 28.10.99 0.22 More waitqueue races fixed
+ * 01.12.99 0.23 New argument to allocate_resource
*
*/
if (!pci_present()) /* No PCI bus in this machine! */
return -ENODEV;
- printk(KERN_INFO "sv: version v0.22 time " __TIME__ " " __DATE__ "\n");
+ printk(KERN_INFO "sv: version v0.23 time " __TIME__ " " __DATE__ "\n");
#if 0
if (!(wavetable_mem = __get_free_pages(GFP_KERNEL, 20-PAGE_SHIFT)))
printk(KERN_INFO "sv: cannot allocate 1MB of contiguous nonpageable memory for wavetable data\n");
memcpy(ddmaname, sv_ddma_name, ddmanamelen);
pcidev->resource[RESOURCE_DDMA].name = ddmaname;
if (allocate_resource(&ioport_resource, pcidev->resource+RESOURCE_DDMA,
- 2*SV_EXTENT_DMA, 0x1000, 0x10000-2*SV_EXTENT_DMA, 1024)) {
+ 2*SV_EXTENT_DMA, 0x1000, 0x10000-2*SV_EXTENT_DMA, 1024, pcidev)) {
pcidev->resource[RESOURCE_DDMA].name = NULL;
kfree(ddmaname);
printk(KERN_ERR "sv: cannot allocate DDMA controller io ports\n");
if (prev_auto_state != devc->no_autoselect)
vnc_configure_mixer(devc);
- waveartist_mixer_set(devc, SOUND_MIXER_RECSRC, SOUND_MASK_MIC);
+
return 0;
}
/*
* Look like a PS/2 mouse, please..
+ * In XFree86 (3.3.5 tested) you must select Protocol "NetMousePS/2",
+ * then use your wheel as Button 4 and 5 via ZAxisMapping 4 5.
*
* The PS/2 protocol is fairly strange, but
* oh, well, it's at least common..
"$CONFIG_FB_CONTROL" = "m" -o "$CONFIG_FB_CLGEN" = "m" -o \
"$CONFIG_FB_TGA" = "m" -o "$CONFIG_FB_PLATINUM" = "m" -o \
"$CONFIG_FB_MATROX" = "m" -o "$CONFIG_FB_PM2" = "m" -o \
- "$CONFIG_FB_ATY128" = "m" -o \
+ "$CONFIG_FB_ATY128" = "m" -o \
"$CONFIG_FB_SGIVW" = "m" ]; then
define_tristate CONFIG_FBCON_CFB32 m
fi
ext_ctl = acornfb_default_econtrol();
- if (var->sync & FB_SYNC_HOR_HIGH_ACT)
- ext_ctl |= VIDC20_ECTL_HS_HSYNC;
- else
- ext_ctl |= VIDC20_ECTL_HS_NHSYNC;
+ if (var->sync & FB_SYNC_COMP_HIGH_ACT) /* should be FB_SYNC_COMP */
+ ext_ctl |= VIDC20_ECTL_HS_NCSYNC | VIDC20_ECTL_VS_NCSYNC;
+ else {
+ if (var->sync & FB_SYNC_HOR_HIGH_ACT)
+ ext_ctl |= VIDC20_ECTL_HS_HSYNC;
+ else
+ ext_ctl |= VIDC20_ECTL_HS_NHSYNC;
- if (var->sync & FB_SYNC_VERT_HIGH_ACT)
- ext_ctl |= VIDC20_ECTL_VS_VSYNC;
- else
- ext_ctl |= VIDC20_ECTL_VS_NVSYNC;
+ if (var->sync & FB_SYNC_VERT_HIGH_ACT)
+ ext_ctl |= VIDC20_ECTL_VS_VSYNC;
+ else
+ ext_ctl |= VIDC20_ECTL_VS_NVSYNC;
+ }
outl(VIDC20_ECTL | ext_ctl, IO_VIDC_BASE);
* Everything after here is initialisation!!!
*/
static struct fb_videomode modedb[] __initdata = {
- { /* 640x250 @ 50Hz, 15.6 kHz hsync */
- NULL, 50, 640, 250, 62500, 185, 123, 38, 21, 76, 3,
+ { /* 320x256 @ 50Hz */
+ NULL, 50, 320, 256, 125000, 92, 62, 35, 19, 38, 2,
+ FB_SYNC_COMP_HIGH_ACT,
+ FB_VMODE_NONINTERLACED
+ }, { /* 640x250 @ 50Hz, 15.6 kHz hsync */
+ NULL, 50, 640, 250, 62500, 185, 123, 38, 21, 76, 3,
0,
FB_VMODE_NONINTERLACED
}, { /* 640x256 @ 50Hz, 15.6 kHz hsync */
- NULL, 50, 640, 256, 62500, 185, 123, 35, 18, 76, 3,
+ NULL, 50, 640, 256, 62500, 185, 123, 35, 18, 76, 3,
0,
FB_VMODE_NONINTERLACED
}, { /* 640x512 @ 50Hz, 26.8 kHz hsync */
- NULL, 50, 640, 512, 41667, 113, 87, 18, 1, 56, 3,
+ NULL, 50, 640, 512, 41667, 113, 87, 18, 1, 56, 3,
0,
FB_VMODE_NONINTERLACED
}, { /* 640x250 @ 70Hz, 31.5 kHz hsync */
- NULL, 70, 640, 250, 39722, 48, 16, 109, 88, 96, 2,
+ NULL, 70, 640, 250, 39722, 48, 16, 109, 88, 96, 2,
0,
FB_VMODE_NONINTERLACED
}, { /* 640x256 @ 70Hz, 31.5 kHz hsync */
- NULL, 70, 640, 256, 39722, 48, 16, 106, 85, 96, 2,
+ NULL, 70, 640, 256, 39722, 48, 16, 106, 85, 96, 2,
0,
FB_VMODE_NONINTERLACED
}, { /* 640x352 @ 70Hz, 31.5 kHz hsync */
- NULL, 70, 640, 352, 39722, 48, 16, 58, 37, 96, 2,
+ NULL, 70, 640, 352, 39722, 48, 16, 58, 37, 96, 2,
0,
FB_VMODE_NONINTERLACED
}, { /* 640x480 @ 60Hz, 31.5 kHz hsync */
- NULL, 60, 640, 480, 39722, 48, 16, 32, 11, 96, 2,
+ NULL, 60, 640, 480, 39722, 48, 16, 32, 11, 96, 2,
0,
FB_VMODE_NONINTERLACED
}, { /* 800x600 @ 56Hz, 35.2 kHz hsync */
- NULL, 56, 800, 600, 27778, 101, 23, 22, 1, 100, 2,
+ NULL, 56, 800, 600, 27778, 101, 23, 22, 1, 100, 2,
0,
FB_VMODE_NONINTERLACED
}, { /* 896x352 @ 60Hz, 21.8 kHz hsync */
- NULL, 60, 896, 352, 41667, 59, 27, 9, 0, 118, 3,
+ NULL, 60, 896, 352, 41667, 59, 27, 9, 0, 118, 3,
+ 0,
+ FB_VMODE_NONINTERLACED
+ }, { /* 1024x 768 @ 60Hz, 48.4 kHz hsync */
+ NULL, 60, 1024, 768, 15385, 160, 24, 29, 3, 136, 6,
0,
FB_VMODE_NONINTERLACED
- },
+ }, { /* 1280x1024 @ 60Hz, 63.8 kHz hsync */
+ NULL, 60, 1280, 1024, 9090, 186, 96, 38, 1, 160, 3,
+ 0,
+ FB_VMODE_NONINTERLACED
+ }
};
static struct fb_videomode __initdata
#include <linux/fb.h>
#include <asm/atarikb.h>
+#include <video/fbcon.h>
#include <video/fbcon-cfb8.h>
#include <video/fbcon-cfb16.h>
#include <video/fbcon-iplan2p2.h>
static int
cyber2000fb_decode_clock(struct par_info *hw, struct fb_var_screeninfo *var)
{
+ static unsigned int divisors_2000[] = { 1, 2, 4, 8 };
+ static unsigned int divisors_2010[] = { 1, 2, 4, 6 };
unsigned long pll_ps = var->pixclock;
unsigned long ref_ps = 69842;
+ unsigned int *divisors;
int div2, div1, mult;
/*
* Step 1:
- * find div2 such that 150MHz < fpll < 220MHz
+ * find div2 such that 115MHz < fpll < 257MHz
* and 0 <= div2 < 4
*/
- for (div2 = 0; div2 < 4; div2++, pll_ps >>= 1)
- if (6667 > pll_ps && pll_ps > 4545)
+ if (current_par.dev_id == PCI_DEVICE_ID_INTERG_2010)
+ divisors = divisors_2010;
+ else
+ divisors = divisors_2000;
+
+ for (div2 = 0; div2 < 4; div2++) {
+ unsigned long new_pll;
+
+ new_pll = pll_ps / divisors[div2];
+ if (8696 > new_pll && new_pll > 3891) {
+ pll_ps = new_pll;
break;
+ }
+ }
if (div2 == 4)
return -EINVAL;
break;
}
#else
- if (pll_ps == 4630) { /* 216.0, 108.0, 54.00, 27.000 */
- mult = 181; /* 4630 9260 18520 37040 */
+ /* /1 /2 /4 /6 /8 */
+ /* (2010) (2000) */
+ if (pll_ps == 4630) { /* 216.0, 108.0, 54.00, 36.000 27.000 */
+ mult = 181; /* 4630 9260 18520 27780 37040 */
div1 = 12;
- } else if (pll_ps == 4965) { /* 201.0, 100.5, 50.25, 25.125 */
- mult = 211; /* 4965 9930 19860 39720 */
+ } else if (pll_ps == 4965) { /* 201.0, 100.5, 50.25, 33.500 25.125 */
+ mult = 211; /* 4965 9930 19860 29790 39720 */
div1 = 15;
- } else if (pll_ps == 5050) { /* 198.0, 99.0, 49.50, 24.750 */
- mult = 83; /* 5050 10100 20200 40400 */
+ } else if (pll_ps == 5050) { /* 198.0, 99.0, 49.50, 33.000 24.750 */
+ mult = 83; /* 5050 10100 20200 30300 40400 */
div1 = 6;
- } else if (pll_ps == 6349) { /* 158.0, 79.0, 39.50, 19.750 */
- mult = 209; /* 6349 12698 25396 50792 */
+ } else if (pll_ps == 6349) { /* 158.0, 79.0, 39.50, 26.333 19.750 */
+ mult = 209; /* 6349 12698 25396 38094 50792 */
div1 = 19;
- } else if (pll_ps == 6422) { /* 156.0, 78.0, 39.00, 19.500 */
- mult = 190; /* 6422 12844 25688 51376 */
+ } else if (pll_ps == 6422) { /* 156.0, 78.0, 39.00, 26.000 19.500 */
+ mult = 190; /* 6422 12844 25688 38532 51376 */
div1 = 17;
} else
return -EINVAL;
cyber2000fb_ioctl
};
+int cyber2000fb_attach(struct cyberpro_info *info)
+{
+ if (current_par.initialised) {
+ info->regs = CyberRegs;
+ info->fb = current_par.screen_base;
+ info->fb_size = current_par.screen_size;
+
+ strncpy(info->dev_name, current_par.dev_name, sizeof(info->dev_name));
+
+ MOD_INC_USE_COUNT;
+ }
+
+ return current_par.initialised;
+}
+
+void cyber2000fb_detach(void)
+{
+ MOD_DEC_USE_COUNT;
+}
+
+EXPORT_SYMBOL(cyber2000fb_attach);
+EXPORT_SYMBOL(cyber2000fb_detach);
+
/*
* These parameters give
* 640x480, hsync 31.5kHz, vsync 60Hz
smem_base = dev->resource[0].start;
mmio_base = dev->resource[0].start + 0x00800000;
+ current_par.dev_id = dev->device;
/*
* Map in the registers
signed int currcon;
char dev_name[32];
unsigned int initialised;
+ unsigned int dev_id;
/*
* palette
#define VISUALID_16M 4
#define VISUALID_32K 6
+#define K_CAP_X2_CTL1 0x49
+
+#define CAP_X_START 0x60
+#define CAP_X_END 0x62
+#define CAP_Y_START 0x64
+#define CAP_Y_END 0x66
+#define CAP_DDA_X_INIT 0x68
+#define CAP_DDA_X_INC 0x6a
+#define CAP_DDA_Y_INIT 0x6c
+#define CAP_DDA_Y_INC 0x6e
+
+#define EXT_FIFO_CTL 0x74
+
+#define CAP_PIP_X_START 0x80
+#define CAP_PIP_X_END 0x82
+#define CAP_PIP_Y_START 0x84
+#define CAP_PIP_Y_END 0x86
+
+#define CAP_NEW_CTL1 0x88
+
+#define CAP_NEW_CTL2 0x89
+
+#define CAP_MODE1 0xa4
+#define CAP_MODE1_8BIT 0x01 /* enable 8bit capture mode */
+#define CAP_MODE1_CCIR656 0x02 /* CCIR656 mode */
+#define CAP_MODE1_IGNOREVGT 0x04 /* ignore VGT */
+#define CAP_MODE1_ALTFIFO 0x10 /* use alternate FIFO for capture */
+#define CAP_MODE1_SWAPUV 0x20 /* swap UV bytes */
+#define CAP_MODE1_MIRRORY 0x40 /* mirror vertically */
+#define CAP_MODE1_MIRRORX 0x80 /* mirror horizontally */
+
+#define CAP_MODE2 0xa5
+
+#define Y_TV_CTL 0xae
+
+#define EXT_MEM_START 0xc0 /* ext start address 21 bits */
+#define HOR_PHASE_SHIFT 0xc2 /* high 3 bits */
+#define EXT_SRC_WIDTH 0xc3 /* ext offset phase 10 bits */
+#define EXT_SRC_HEIGHT 0xc4 /* high 6 bits */
+#define EXT_X_START 0xc5 /* ext->screen, 16 bits */
+#define EXT_X_END 0xc7 /* ext->screen, 16 bits */
+#define EXT_Y_START 0xc9 /* ext->screen, 16 bits */
+#define EXT_Y_END 0xcb /* ext->screen, 16 bits */
+#define EXT_SRC_WIN_WIDTH 0xcd /* 8 bits */
+#define EXT_COLOUR_COMPARE 0xce /* 24 bits */
+#define EXT_DDA_X_INIT 0xd1 /* ext->screen 16 bits */
+#define EXT_DDA_X_INC 0xd3 /* ext->screen 16 bits */
+#define EXT_DDA_Y_INIT 0xd5 /* ext->screen 16 bits */
+#define EXT_DDA_Y_INC 0xd7 /* ext->screen 16 bits */
+
+#define VID_FIFO_CTL 0xd9
+
+#define VID_CAP_VFC 0xdb
+#define VID_CAP_VFC_YUV422 0x00 /* formats - does this cause conversion? */
+#define VID_CAP_VFC_RGB555 0x01
+#define VID_CAP_VFC_RGB565 0x02
+#define VID_CAP_VFC_RGB888_24 0x03
+#define VID_CAP_VFC_RGB888_32 0x04
+#define VID_CAP_VFC_DUP_PIX_ZOON 0x08 /* duplicate pixel zoom */
+#define VID_CAP_VFC_MOD_3RD_PIX 0x20 /* modify 3rd duplicated pixel */
+#define VID_CAP_VFC_DBL_H_PIX 0x40 /* double horiz pixels */
+#define VID_CAP_VFC_UV128 0x80 /* UV data offset by 128 */
+
+#define VID_DISP_CTL1 0xdc
+#define VID_DISP_CTL1_INTRAM 0x01 /* video pixels go to internal RAM */
+#define VID_DISP_CTL1_IGNORE_CCOMP 0x02 /* ignore colour compare registers */
+#define VID_DISP_CTL1_NOCLIP 0x04 /* do not clip to 16235,16240 */
+#define VID_DISP_CTL1_UV_AVG 0x08 /* U/V data is averaged */
+#define VID_DISP_CTL1_Y128 0x10 /* Y data offset by 128 */
+#define VID_DISP_CTL1_VINTERPOL_OFF 0x20 /* vertical interpolation off */
+#define VID_DISP_CTL1_VID_OUT_WIN_FULL 0x40 /* video out window full */
+#define VID_DISP_CTL1_ENABLE_VID_WINDOW 0x80 /* enable video window */
+
+#define VID_FIFO_CTL1 0xdd
+
+#define VFAC_CTL1 0xe8
+#define VFAC_CTL1_CAPTURE 0x01 /* capture enable */
+#define VFAC_CTL1_VFAC_ENABLE 0x02 /* vfac enable */
+#define VFAC_CTL1_FREEZE_CAPTURE 0x04 /* freeze capture */
+#define VFAC_CTL1_FREEZE_CAPTURE_SYNC 0x08 /* sync freeze capture */
+#define VFAC_CTL1_VALIDFRAME_SRC 0x10 /* select valid frame source */
+#define VFAC_CTL1_PHILIPS 0x40 /* select Philips mode */
+#define VFAC_CTL1_MODVINTERPOLCLK 0x80 /* modify vertical interpolation clocl */
+
+#define VFAC_CTL2 0xe9
+#define VFAC_CTL2_INVERT_VIDDATAVALID 0x01 /* invert video data valid */
+#define VFAC_CTL2_INVERT_GRAPHREADY 0x02 /* invert graphic ready output sig */
+#define VFAC_CTL2_INVERT_DATACLK 0x04 /* invert data clock signal */
+#define VFAC_CTL2_INVERT_HSYNC 0x08 /* invert hsync input */
+#define VFAC_CTL2_INVERT_VSYNC 0x10 /* invert vsync input */
+#define VFAC_CTL2_INVERT_FRAME 0x20 /* invert frame odd/even input */
+#define VFAC_CTL2_INVERT_BLANK 0x40 /* invert blank output */
+#define VFAC_CTL2_INVERT_OVSYNC 0x80 /* invert other vsync input */
+
+#define VFAC_CTL3 0xea
+
+#define CAP_MEM_START 0xeb /* 18 bits */
+#define CAP_MAP_WIDTH 0xed /* high 6 bits */
+#define CAP_PITCH 0xee /* 8 bits */
+
+#define CAP_CTL_MISC 0xef
+#define CAP_CTL_MISC_HDIV 0x01
+#define CAP_CTL_MISC_HDIV4 0x02
+#define CAP_CTL_MISC_ODDEVEN 0x04
+#define CAP_CTL_MISC_HSYNCDIV2 0x08
+#define CAP_CTL_MISC_SYNCTZHIGH 0x10
+#define CAP_CTL_MISC_SYNCTZOR 0x20
+#define CAP_CTL_MISC_DISPUSED 0x80
+
+#define REG_BANK 0xfa
+#define REG_BANK_Y 0x01
+#define REG_BANK_K 0x05
+
+
#define CO_CMD_L_PATTERN_FGCOL 0x8000
#define CO_CMD_L_INC_LEFT 0x0004
#define CO_CMD_L_INC_UP 0x0002
#define CO_REG_SRC_PTR 0xbf170
#define CO_REG_DEST_PTR 0xbf178
#define CO_REG_DEST_WIDTH 0xbf218
+
+struct cyberpro_info {
+ unsigned char *regs;
+ char *fb;
+ char dev_name[32];
+ unsigned int fb_size;
+};
+
+/*
+ * Note! Writing to the Cyber20x0 registers from an interrupt
+ * routine is definitely a bad idea atm.
+ */
+int cyber2000fb_attach(struct cyberpro_info *info);
+void cyber2000fb_detach(void);
+
#include <linux/fb.h>
#include <linux/module.h>
+#include <video/fbcon.h>
#include <video/fbcon-mfb.h>
#define LOGO_LINE (LOGO_W/8)
struct display fb_display[MAX_NR_CONSOLES];
+char con2fb_map[MAX_NR_CONSOLES];
static int logo_lines;
static int logo_shown = -1;
/* Software scrollback */
-extern int fbcon_softback_size;
+int fbcon_softback_size = 32768;
static unsigned long softback_buf, softback_curr;
static unsigned long softback_in;
static unsigned long softback_top, softback_end;
add_timer(&cursor_timer);
}
+int PROC_CONSOLE(const struct fb_info *info)
+{
+ int fgc;
+
+ if (info->display_fg != NULL)
+ fgc = info->display_fg->vc_num;
+ else
+ return -1;
+
+ if (!current->tty)
+ return fgc;
+
+ if (current->tty->driver.type != TTY_DRIVER_TYPE_CONSOLE)
+ /* XXX Should report error here? */
+ return fgc;
+
+ if (MINOR(current->tty->device) < 1)
+ return fgc;
+
+ return MINOR(current->tty->device) - 1;
+}
+
+int set_all_vcs(int fbidx, struct fb_ops *fb, struct fb_var_screeninfo *var,
+ struct fb_info *info)
+{
+ int unit, err;
+
+ var->activate |= FB_ACTIVATE_TEST;
+ err = fb->fb_set_var(var, PROC_CONSOLE(info), info);
+ var->activate &= ~FB_ACTIVATE_TEST;
+ if (err)
+ return err;
+ for (unit = 0; unit < MAX_NR_CONSOLES; unit++)
+ if (fb_display[unit].conp && con2fb_map[unit] == fbidx)
+ fb->fb_set_var(var, unit, info);
+ return 0;
+}
+
+void set_con2fb_map(int unit, int newidx)
+{
+ int oldidx = con2fb_map[unit];
+ struct fb_info *oldfb, *newfb;
+ struct vc_data *conp;
+ char *fontdata;
+ unsigned short fontwidth, fontheight, fontwidthlog, fontheightlog;
+ int userfont;
+
+ if (newidx != con2fb_map[unit]) {
+ oldfb = registered_fb[oldidx];
+ newfb = registered_fb[newidx];
+ if (newfb->fbops->fb_open(newfb,0))
+ return;
+ oldfb->fbops->fb_release(oldfb,0);
+ conp = fb_display[unit].conp;
+ fontdata = fb_display[unit].fontdata;
+ fontwidth = fb_display[unit]._fontwidth;
+ fontheight = fb_display[unit]._fontheight;
+ fontwidthlog = fb_display[unit]._fontwidthlog;
+ fontheightlog = fb_display[unit]._fontheightlog;
+ userfont = fb_display[unit].userfont;
+ con2fb_map[unit] = newidx;
+ fb_display[unit] = *(newfb->disp);
+ fb_display[unit].conp = conp;
+ fb_display[unit].fontdata = fontdata;
+ fb_display[unit]._fontwidth = fontwidth;
+ fb_display[unit]._fontheight = fontheight;
+ fb_display[unit]._fontwidthlog = fontwidthlog;
+ fb_display[unit]._fontheightlog = fontheightlog;
+ fb_display[unit].userfont = userfont;
+ fb_display[unit].fb_info = newfb;
+ if (!newfb->changevar)
+ newfb->changevar = oldfb->changevar;
+ /* tell console var has changed */
+ if (newfb->changevar)
+ newfb->changevar(unit);
+ }
+}
+
/*
* Low Level Operations
*/
#include <linux/mman.h>
#include <linux/tty.h>
#include <linux/console.h>
-#include <linux/console_struct.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
#ifdef CONFIG_KMOD
#if defined(__mc68000__) || defined(CONFIG_APUS)
#include <asm/setup.h>
#endif
-#ifdef __powerpc__
+
#include <asm/io.h>
-#endif
#include <asm/uaccess.h>
#include <asm/page.h>
#include <asm/pgtable.h>
#include <linux/fb.h>
-
+#include <video/fbcon.h>
/*
* Frame buffer device initialization and setup routines
struct fb_info *registered_fb[FB_MAX];
int num_registered_fb = 0;
-int fbcon_softback_size = 32768;
-
-char con2fb_map[MAX_NR_CONSOLES];
+extern int fbcon_softback_size;
static int first_fb_vc = 0;
static int last_fb_vc = MAX_NR_CONSOLES-1;
static int fbcon_is_default = 1;
-static int PROC_CONSOLE(const struct fb_info *info)
-{
- int fgc;
-
- if (info->display_fg != NULL)
- fgc = info->display_fg->vc_num;
- else
- return -1;
-
- if (!current->tty)
- return fgc;
-
- if (current->tty->driver.type != TTY_DRIVER_TYPE_CONSOLE)
- /* XXX Should report error here? */
- return fgc;
-
- if (MINOR(current->tty->device) < 1)
- return fgc;
-
- return MINOR(current->tty->device) - 1;
-}
-
static int fbmem_read_proc(char *buf, char **start, off_t offset,
int len, int *eof, void *private)
{
return copy_size;
}
-
-static int set_all_vcs(int fbidx, struct fb_ops *fb,
- struct fb_var_screeninfo *var, struct fb_info *info)
-{
- int unit, err;
-
- var->activate |= FB_ACTIVATE_TEST;
- err = fb->fb_set_var(var, PROC_CONSOLE(info), info);
- var->activate &= ~FB_ACTIVATE_TEST;
- if (err)
- return err;
- for (unit = 0; unit < MAX_NR_CONSOLES; unit++)
- if (fb_display[unit].conp && con2fb_map[unit] == fbidx)
- fb->fb_set_var(var, unit, info);
- return 0;
-}
-
-static void set_con2fb_map(int unit, int newidx)
-{
- int oldidx = con2fb_map[unit];
- struct fb_info *oldfb, *newfb;
- struct vc_data *conp;
- char *fontdata;
- unsigned short fontwidth, fontheight, fontwidthlog, fontheightlog;
- int userfont;
-
- if (newidx != con2fb_map[unit]) {
- oldfb = registered_fb[oldidx];
- newfb = registered_fb[newidx];
- if (newfb->fbops->fb_open(newfb,0))
- return;
- oldfb->fbops->fb_release(oldfb,0);
- conp = fb_display[unit].conp;
- fontdata = fb_display[unit].fontdata;
- fontwidth = fb_display[unit]._fontwidth;
- fontheight = fb_display[unit]._fontheight;
- fontwidthlog = fb_display[unit]._fontwidthlog;
- fontheightlog = fb_display[unit]._fontheightlog;
- userfont = fb_display[unit].userfont;
- con2fb_map[unit] = newidx;
- fb_display[unit] = *(newfb->disp);
- fb_display[unit].conp = conp;
- fb_display[unit].fontdata = fontdata;
- fb_display[unit]._fontwidth = fontwidth;
- fb_display[unit]._fontheight = fontheight;
- fb_display[unit]._fontwidthlog = fontwidthlog;
- fb_display[unit]._fontheightlog = fontheightlog;
- fb_display[unit].userfont = userfont;
- fb_display[unit].fb_info = newfb;
- if (!newfb->changevar)
- newfb->changevar = oldfb->changevar;
- /* tell console var has changed */
- if (newfb->changevar)
- newfb->changevar(unit);
- }
-}
-
#ifdef CONFIG_KMOD
static void try_to_load(int fb)
{
#include <asm/blinken.h>
#include <asm/hwtest.h>
+#include <video/fbcon.h>
#include <video/fbcon-mfb.h>
#include <video/fbcon-cfb2.h>
#include <video/fbcon-cfb4.h>
return err;
}
-int block_write_partial_page(struct file *file, struct page *page, unsigned long offset, unsigned long bytes, const char * buf)
+int block_write_range(struct dentry *dentry, struct page *page,
+ unsigned zerofrom, unsigned from, unsigned to,
+ const char * buf)
{
- struct dentry *dentry = file->f_dentry;
struct inode *inode = dentry->d_inode;
+ unsigned zeroto = 0, block_start, block_end;
unsigned long block;
- int err, partial;
- unsigned long blocksize, start_block, end_block;
- unsigned long start_offset, start_bytes, end_bytes;
- unsigned long bbits, blocks, i, len;
- struct buffer_head *bh, *head;
- char *target_buf, *kaddr;
- int need_balance_dirty;
-
- kaddr = (char *)kmap(page);
- target_buf = kaddr + offset;
-
- if (!PageLocked(page))
- BUG();
+ int err = 0, partial = 0, need_balance_dirty = 0;
+ unsigned blocksize, bbits;
+ struct buffer_head *bh, *head, *wait[2], **wait_bh=wait;
+ char *kaddr = (char *)kmap(page);
blocksize = inode->i_sb->s_blocksize;
if (!page->buffers)
bbits = inode->i_sb->s_blocksize_bits;
block = page->index << (PAGE_CACHE_SHIFT - bbits);
- blocks = PAGE_CACHE_SIZE >> bbits;
- start_block = offset >> bbits;
- end_block = (offset + bytes - 1) >> bbits;
- start_offset = offset & (blocksize - 1);
- start_bytes = blocksize - start_offset;
- if (start_bytes > bytes)
- start_bytes = bytes;
- end_bytes = (offset+bytes) & (blocksize - 1);
- if (end_bytes > bytes)
- end_bytes = bytes;
-
- if (offset < 0 || offset >= PAGE_SIZE)
- BUG();
- if (bytes+offset < 0 || bytes+offset > PAGE_SIZE)
- BUG();
- if (start_block < 0 || start_block >= blocks)
- BUG();
- if (end_block < 0 || end_block >= blocks)
- BUG();
- i = 0;
- bh = head;
- partial = 0;
- need_balance_dirty = 0;
- do {
+ /*
+ * First pass - map what needs to be mapped, initiate reads
+ * on the boundaries if needed (i.e. if block is partially covered
+ * _and_ is not up-to-date _and_ is not new).
+ */
+ for(bh = head, block_start = 0; bh != head || !block_start;
+ block++, block_start=block_end, bh = bh->b_this_page) {
if (!bh)
BUG();
-
- if ((i < start_block) || (i > end_block)) {
- if (!buffer_uptodate(bh))
- partial = 1;
- goto skip;
- }
-
- /*
- * If the buffer is not up-to-date, we need to ask the low-level
- * FS to do something for us (we used to have assumptions about
- * the meaning of b_blocknr etc, that's bad).
- *
- * If "update" is set, that means that the low-level FS should
- * try to make sure that the block is up-to-date because we're
- * not going to fill it completely.
- */
+ block_end = block_start+blocksize;
+ if (block_end <= zerofrom)
+ continue;
+ if (block_start >= to)
+ break;
bh->b_end_io = end_buffer_io_sync;
if (!buffer_mapped(bh)) {
err = inode->i_op->get_block(inode, block, bh, 1);
goto out;
unmap_underlying_metadata(bh);
}
-
- if (!buffer_uptodate(bh) && (start_offset || (end_bytes && (i == end_block)))) {
- if (buffer_new(bh)) {
- memset(kaddr + i*blocksize, 0, blocksize);
- } else {
- ll_rw_block(READ, 1, &bh);
- wait_on_buffer(bh);
- err = -EIO;
- if (!buffer_uptodate(bh))
- goto out;
- }
- }
-
- len = blocksize;
- if (start_offset) {
- len = start_bytes;
- start_offset = 0;
- } else if (end_bytes && (i == end_block)) {
- len = end_bytes;
- end_bytes = 0;
+ if (buffer_new(bh)) {
+ zeroto = block_end;
+ if (block_start < zerofrom)
+ zerofrom = block_start;
+ continue;
}
- if (target_buf >= kaddr + PAGE_SIZE)
- BUG();
- if (target_buf+len-1 >= kaddr + PAGE_SIZE)
- BUG();
- err = copy_from_user(target_buf, buf, len);
- target_buf += len;
- buf += len;
-
- /*
- * we dirty buffers only after copying the data into
- * the page - this way we can dirty the buffer even if
- * the bh is still doing IO.
- *
- * NOTE! This also does a direct dirty balace check,
- * rather than relying on bdflush just waking up every
- * once in a while. This is to catch (and slow down)
- * the processes that write tons of buffer..
- *
- * Note how we do NOT want to do this in the full block
- * case: full pages are flushed not by the people who
- * dirtied them, but by people who need memory. And we
- * should not penalize them for somebody else writing
- * lots of dirty pages.
- */
- set_bit(BH_Uptodate, &bh->b_state);
- if (!test_and_set_bit(BH_Dirty, &bh->b_state)) {
- __mark_dirty(bh, 0);
- need_balance_dirty = 1;
+ if (!buffer_uptodate(bh) &&
+ (block_start < zerofrom || block_end > to)) {
+ ll_rw_block(READ, 1, &bh);
+ *wait_bh++=bh;
}
-
- if (err) {
- err = -EFAULT;
+ }
+ /*
+ * If we issued read requests - let them complete.
+ */
+ while(wait_bh > wait) {
+ wait_on_buffer(*--wait_bh);
+ err = -EIO;
+ if (!buffer_uptodate(*wait_bh))
goto out;
+ }
+ /*
+ * Now we can copy the data.
+ */
+ if (zerofrom < from)
+ memset(kaddr+zerofrom, 0, from-zerofrom);
+ if (from < to)
+ err = copy_from_user(kaddr+from, buf, to-from);
+ if (to < zeroto)
+ memset(kaddr+to, 0, zeroto-to);
+ if (err < 0)
+ goto out;
+ /*
+ * Second pass: check if all out-of-range blocks are up-to-date
+ * and mark the rest up-to-date and dirty.
+ *
+ * NOTE! This also does a direct dirty balace check,
+ * rather than relying on bdflush just waking up every
+ * once in a while. This is to catch (and slow down)
+ * the processes that write tons of buffer..
+ *
+ * Note how we do NOT want to do this in the full block
+ * case: full pages are flushed not by the people who
+ * dirtied them, but by people who need memory. And we
+ * should not penalize them for somebody else writing
+ * lots of dirty pages.
+ */
+ for(bh = head, block_start = 0;
+ bh != head || !block_start;
+ block_start=block_end, bh = bh->b_this_page) {
+ block_end = block_start + blocksize;
+ if (block_end <= zerofrom || block_start >= zeroto) {
+ if (!buffer_uptodate(bh))
+ partial = 1;
+ } else {
+ set_bit(BH_Uptodate, &bh->b_state);
+ if (!test_and_set_bit(BH_Dirty, &bh->b_state)) {
+ __mark_dirty(bh, 0);
+ need_balance_dirty = 1;
+ }
}
-
-skip:
- i++;
- block++;
- bh = bh->b_this_page;
- } while (bh != head);
+ }
if (need_balance_dirty)
balance_dirty(bh->b_dev);
-
/*
* is this a partial write that happened to make all buffers
* uptodate then we can optimize away a bogus readpage() for
if (!partial)
SetPageUptodate(page);
kunmap(page);
- return bytes;
+ return 0;
out:
ClearPageUptodate(page);
kunmap(page);
return err;
}
-/*
- * For moronic filesystems that do not allow holes in file.
- * we allow offset==PAGE_SIZE, bytes==0
- */
-
-int block_write_cont_page(struct file *file, struct page *page, unsigned long offset, unsigned long bytes, const char * buf)
+int block_write_partial_page(struct file *file, struct page *page, unsigned long offset, unsigned long bytes, const char * buf)
{
struct dentry *dentry = file->f_dentry;
- struct inode *inode = dentry->d_inode;
- unsigned long block;
- int err, partial;
- unsigned long blocksize, start_block, end_block;
- unsigned long start_offset, start_bytes, end_bytes;
- unsigned long bbits, blocks, i, len;
- struct buffer_head *bh, *head;
- char * target_buf, *target_data;
- unsigned long data_offset = offset;
- int need_balance_dirty;
-
- offset = inode->i_size - (page->index << PAGE_CACHE_SHIFT);
- if (page->index > (inode->i_size >> PAGE_CACHE_SHIFT))
- offset = 0;
- else if (offset >= data_offset)
- offset = data_offset;
- bytes += data_offset - offset;
-
- target_buf = (char *)page_address(page) + offset;
- target_data = (char *)page_address(page) + data_offset;
+ int err;
if (!PageLocked(page))
BUG();
-
- blocksize = inode->i_sb->s_blocksize;
- if (!page->buffers)
- create_empty_buffers(page, inode, blocksize);
- head = page->buffers;
-
- bbits = inode->i_sb->s_blocksize_bits;
- block = page->index << (PAGE_CACHE_SHIFT - bbits);
- blocks = PAGE_CACHE_SIZE >> bbits;
- start_block = offset >> bbits;
- end_block = (offset + bytes - 1) >> bbits;
- start_offset = offset & (blocksize - 1);
- start_bytes = blocksize - start_offset;
- if (start_bytes > bytes)
- start_bytes = bytes;
- end_bytes = (offset+bytes) & (blocksize - 1);
- if (end_bytes > bytes)
- end_bytes = bytes;
-
- if (offset < 0 || offset > PAGE_SIZE)
+ if (offset < 0 || offset >= PAGE_SIZE)
BUG();
if (bytes+offset < 0 || bytes+offset > PAGE_SIZE)
BUG();
- if (start_block < 0 || start_block > blocks)
- BUG();
- if (end_block < 0 || end_block >= blocks)
- BUG();
-
- i = 0;
- bh = head;
- partial = 0;
- need_balance_dirty = 0;
- do {
- if (!bh)
- BUG();
- if ((i < start_block) || (i > end_block)) {
- if (!buffer_uptodate(bh))
- partial = 1;
- goto skip;
- }
-
- /*
- * If the buffer is not up-to-date, we need to ask the low-level
- * FS to do something for us (we used to have assumptions about
- * the meaning of b_blocknr etc, that's bad).
- *
- * If "update" is set, that means that the low-level FS should
- * try to make sure that the block is up-to-date because we're
- * not going to fill it completely.
- */
- bh->b_end_io = end_buffer_io_sync;
- if (!buffer_mapped(bh)) {
- err = inode->i_op->get_block(inode, block, bh, 1);
- if (err)
- goto out;
- unmap_underlying_metadata(bh);
- }
-
- if (!buffer_uptodate(bh) && (start_offset || (end_bytes && (i == end_block)))) {
- if (buffer_new(bh)) {
- memset(bh->b_data, 0, bh->b_size);
- } else {
- ll_rw_block(READ, 1, &bh);
- wait_on_buffer(bh);
- err = -EIO;
- if (!buffer_uptodate(bh))
- goto out;
- }
- }
-
- len = blocksize;
- if (start_offset) {
- len = start_bytes;
- start_offset = 0;
- } else if (end_bytes && (i == end_block)) {
- len = end_bytes;
- end_bytes = 0;
- }
- err = 0;
- if (target_buf+len<=target_data)
- memset(target_buf, 0, len);
- else if (target_buf<target_data) {
- memset(target_buf, 0, target_data-target_buf);
- copy_from_user(target_data, buf,
- len+target_buf-target_data);
- } else
- err = copy_from_user(target_buf, buf, len);
- target_buf += len;
- buf += len;
-
- /*
- * we dirty buffers only after copying the data into
- * the page - this way we can dirty the buffer even if
- * the bh is still doing IO.
- *
- * NOTE! This also does a direct dirty balace check,
- * rather than relying on bdflush just waking up every
- * once in a while. This is to catch (and slow down)
- * the processes that write tons of buffer..
- *
- * Note how we do NOT want to do this in the full block
- * case: full pages are flushed not by the people who
- * dirtied them, but by people who need memory. And we
- * should not penalize them for somebody else writing
- * lots of dirty pages.
- */
- set_bit(BH_Uptodate, &bh->b_state);
- if (!test_and_set_bit(BH_Dirty, &bh->b_state)) {
- __mark_dirty(bh, 0);
- need_balance_dirty = 1;
- }
-
- if (err) {
- err = -EFAULT;
- goto out;
- }
+ err = block_write_range(dentry, page, offset,offset,offset+bytes, buf);
+ return err ? err : bytes;
+}
-skip:
- i++;
- block++;
- bh = bh->b_this_page;
- } while (bh != head);
+/*
+ * For moronic filesystems that do not allow holes in file.
+ * we allow offset==PAGE_SIZE, bytes==0
+ */
- if (need_balance_dirty)
- balance_dirty(bh->b_dev);
+int block_write_cont_page(struct file *file, struct page *page, unsigned long offset, unsigned long bytes, const char * buf)
+{
+ struct dentry *dentry = file->f_dentry;
+ struct inode *inode = dentry->d_inode;
+ int err;
+ unsigned zerofrom = offset;
- /*
- * is this a partial write that happened to make all buffers
- * uptodate then we can optimize away a bogus readpage() for
- * the next read(). Here we 'discover' wether the page went
- * uptodate as a result of this (potentially partial) write.
- */
- if (!partial)
- SetPageUptodate(page);
- return bytes;
-out:
- ClearPageUptodate(page);
- return err;
+ if (page->index > (inode->i_size >> PAGE_CACHE_SHIFT))
+ zerofrom = 0;
+ else if (page->index == (inode->i_size >> PAGE_CACHE_SHIFT) &&
+ offset > (inode->i_size & ~PAGE_CACHE_MASK))
+ zerofrom = inode->i_size & ~PAGE_CACHE_MASK;
+ err = block_write_range(dentry, page, zerofrom,offset,offset+bytes,buf);
+ return err ? err : bytes;
}
* Universite Pierre et Marie Curie (Paris VI)
*/
-#include <linux/module.h>
#include <linux/fs.h>
#include <linux/sched.h>
* David S. Miller (davem@caip.rutgers.edu), 1995
*/
-#include <linux/module.h>
#include <linux/fs.h>
#include <linux/locks.h>
#include <linux/quotaops.h>
* Universite Pierre et Marie Curie (Paris VI)
*/
-#include <linux/module.h>
#include <linux/fs.h>
* David S. Miller (davem@caip.rutgers.edu), 1995
*/
-#include <linux/module.h>
#include <linux/fs.h>
* (jj@sunsite.ms.mff.cuni.cz)
*/
-#include <linux/module.h>
#include <linux/fs.h>
#include <linux/sched.h>
* we can depend on generic_block_fdatasync() to sync the data blocks.
*/
-#include <linux/module.h>
#include <linux/fs.h>
* David S. Miller (davem@caip.rutgers.edu), 1995
*/
-#include <linux/module.h>
#include <linux/fs.h>
#include <linux/locks.h>
#include <linux/quotaops.h>
* (jj@sunsite.ms.mff.cuni.cz)
*/
-#include <linux/module.h>
#include <linux/fs.h>
#include <linux/locks.h>
#include <linux/smp_lock.h>
* Universite Pierre et Marie Curie (Paris VI)
*/
-#include <linux/module.h>
#include <linux/fs.h>
#include <linux/sched.h>
#include <asm/uaccess.h>
* for B-tree directories by Theodore Ts'o (tytso@mit.edu), 1998
*/
-#include <linux/module.h>
#include <linux/fs.h>
#include <linux/locks.h>
#include <linux/quotaops.h>
* ext2 symlink handling code
*/
-#include <linux/module.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
* General cleanup and race fixes, wsh, 1998
*/
-#include <linux/module.h>
#include <linux/fs.h>
#include <linux/locks.h>
#include <linux/hfs_fs.h>
#include <linux/devpts_fs.h>
#include <linux/bfs_fs.h>
+#include <linux/adfs_fs.h>
#include <linux/major.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
ctl.head.eof = ctl.valid;
finished:
if (page) {
- kunmap(page);
cache->head = ctl.head;
+ kunmap(page);
SetPageUptodate(page);
UnlockPage(page);
page_cache_release(page);
#define TSUNAMI_IO_BIAS TSUNAMI_IO(0)
#define TSUNAMI_MEM_BIAS TSUNAMI_MEM(0)
+/* The IO address space is larger than 0xffff */
+#define TSUNAMI_IO_SPACE (TSUNAMI_CONF(0) - TSUNAMI_IO(0))
/*
* Data structure for handling TSUNAMI machine checks:
/*
* Alpha floating-point control register defines:
*/
+#define FPCR_DNOD (1UL<<47) /* denorm INV trap disable */
+#define FPCR_DNZ (1UL<<48) /* denorms to zero */
#define FPCR_INVD (1UL<<49) /* invalid op disable (opt.) */
#define FPCR_DZED (1UL<<50) /* division by zero disable (opt.) */
#define FPCR_OVFD (1UL<<51) /* overflow disable (optional) */
#define IEEE_TRAP_ENABLE_OVF (1UL<<3) /* overflow */
#define IEEE_TRAP_ENABLE_UNF (1UL<<4) /* underflow */
#define IEEE_TRAP_ENABLE_INE (1UL<<5) /* inexact */
+#define IEEE_TRAP_ENABLE_DNO (1UL<<6) /* denorm */
#define IEEE_TRAP_ENABLE_MASK (IEEE_TRAP_ENABLE_INV | IEEE_TRAP_ENABLE_DZE |\
IEEE_TRAP_ENABLE_OVF | IEEE_TRAP_ENABLE_UNF |\
- IEEE_TRAP_ENABLE_INE)
+ IEEE_TRAP_ENABLE_INE | IEEE_TRAP_ENABLE_DNO)
+
+/* Denorm and Underflow flushing */
+#define IEEE_MAP_DMZ (1UL<<12) /* Map denorm inputs to zero */
+#define IEEE_MAP_UMZ (1UL<<13) /* Map underflowed outputs to zero */
+
+#define IEEE_MAP_MASK (IEEE_MAP_DMZ | IEEE_MAP_UMZ)
/* status bits coming from fpcr: */
#define IEEE_STATUS_INV (1UL<<17)
#define IEEE_STATUS_OVF (1UL<<19)
#define IEEE_STATUS_UNF (1UL<<20)
#define IEEE_STATUS_INE (1UL<<21)
+#define IEEE_STATUS_DNO (1UL<<22)
#define IEEE_STATUS_MASK (IEEE_STATUS_INV | IEEE_STATUS_DZE | \
IEEE_STATUS_OVF | IEEE_STATUS_UNF | \
- IEEE_STATUS_INE)
+ IEEE_STATUS_INE | IEEE_STATUS_DNO)
+
+#define IEEE_SW_MASK (IEEE_TRAP_ENABLE_MASK | IEEE_STATUS_MASK | IEEE_MAP_MASK)
-#define IEEE_SW_MASK (IEEE_TRAP_ENABLE_MASK | IEEE_STATUS_MASK)
+#define IEEE_CURRENT_RM_SHIFT 32
+#define IEEE_CURRENT_RM_MASK (3UL<<IEEE_CURRENT_RM_SHIFT)
#define IEEE_STATUS_TO_EXCSUM_SHIFT 16
| IEEE_TRAP_ENABLE_DZE
| IEEE_TRAP_ENABLE_OVF)) << 48;
fp |= (~sw & (IEEE_TRAP_ENABLE_UNF | IEEE_TRAP_ENABLE_INE)) << 57;
+ fp |= (~sw & IEEE_TRAP_ENABLE_DNO) << 41;
return fp;
}
| IEEE_TRAP_ENABLE_DZE
| IEEE_TRAP_ENABLE_OVF);
sw |= (~fp >> 57) & (IEEE_TRAP_ENABLE_UNF | IEEE_TRAP_ENABLE_INE);
+ sw |= (~fp >> 41) & IEEE_TRAP_ENABLE_DNO;
return sw;
}
extern unsigned long alpha_read_fp_reg (unsigned long reg);
extern void alpha_write_fp_reg (unsigned long reg, unsigned long val);
+extern unsigned long alpha_read_fp_reg_s (unsigned long reg);
+extern void alpha_write_fp_reg_s (unsigned long reg, unsigned long val);
#endif /* __KERNEL__ */
void (*init_irq)(void);
void (*init_pit)(void);
void (*init_pci)(void);
- void (*kill_arch)(int, char *);
+ void (*kill_arch)(int);
u8 (*pci_swizzle)(struct pci_dev *, u8 *);
int (*pci_map_irq)(struct pci_dev *, u8, u8);
current->thread.ptbr
= ((unsigned long) next_mm->pgd - IDENT_ADDR) >> PAGE_SHIFT;
+
+ __reload_thread(¤t->thread);
}
__EXTERN_INLINE void
--- /dev/null
+/* Machine-dependent software floating-point definitions.
+ Alpha kernel version.
+ Copyright (C) 1997,1998,1999 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Richard Henderson (rth@cygnus.com),
+ Jakub Jelinek (jakub@redhat.com) and
+ David S. Miller (davem@redhat.com).
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If
+ not, write to the Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ifndef _SFP_MACHINE_H
+#define _SFP_MACHINE_H
+
+#define _FP_W_TYPE_SIZE 64
+#define _FP_W_TYPE unsigned long
+#define _FP_WS_TYPE signed long
+#define _FP_I_TYPE long
+
+#define _FP_MUL_MEAT_S(R,X,Y) \
+ _FP_MUL_MEAT_1_imm(_FP_WFRACBITS_S,R,X,Y)
+#define _FP_MUL_MEAT_D(R,X,Y) \
+ _FP_MUL_MEAT_1_wide(_FP_WFRACBITS_D,R,X,Y,umul_ppmm)
+#define _FP_MUL_MEAT_Q(R,X,Y) \
+ _FP_MUL_MEAT_2_wide(_FP_WFRACBITS_Q,R,X,Y,umul_ppmm)
+
+#define _FP_DIV_MEAT_S(R,X,Y) _FP_DIV_MEAT_1_imm(S,R,X,Y,_FP_DIV_HELP_imm)
+#define _FP_DIV_MEAT_D(R,X,Y) _FP_DIV_MEAT_1_udiv(D,R,X,Y)
+#define _FP_DIV_MEAT_Q(R,X,Y) _FP_DIV_MEAT_2_udiv(Q,R,X,Y)
+
+#define _FP_NANFRAC_S _FP_QNANBIT_S
+#define _FP_NANFRAC_D _FP_QNANBIT_D
+#define _FP_NANFRAC_Q _FP_QNANBIT_Q
+#define _FP_NANSIGN_S 1
+#define _FP_NANSIGN_D 1
+#define _FP_NANSIGN_Q 1
+
+#define _FP_KEEPNANFRACP 1
+
+/* Alpha Architecture Handbook, 4.7.10.4 sais that
+ * we should prefer any type of NaN in Fb, then Fa.
+ */
+#define _FP_CHOOSENAN(fs, wc, R, X, Y, OP) \
+ do { \
+ R##_s = Y##_s; \
+ _FP_FRAC_COPY_##wc(R,X); \
+ R##_c = FP_CLS_NAN; \
+ } while (0)
+
+/* Obtain the current rounding mode. */
+#define FP_ROUNDMODE mode
+#define FP_RND_NEAREST (FPCR_DYN_NORMAL >> FPCR_DYN_SHIFT)
+#define FP_RND_ZERO (FPCR_DYN_CHOPPED >> FPCR_DYN_SHIFT)
+#define FP_RND_PINF (FPCR_DYN_PLUS >> FPCR_DYN_SHIFT)
+#define FP_RND_MINF (FPCR_DYN_MINUS >> FPCR_DYN_SHIFT)
+
+/* Exception flags. */
+#define FP_EX_INVALID IEEE_TRAP_ENABLE_INV
+#define FP_EX_OVERFLOW IEEE_TRAP_ENABLE_OVF
+#define FP_EX_UNDERFLOW IEEE_TRAP_ENABLE_UNF
+#define FP_EX_DIVZERO IEEE_TRAP_ENABLE_DZE
+#define FP_EX_INEXACT IEEE_TRAP_ENABLE_INE
+#define FP_EX_DENORM IEEE_TRAP_ENABLE_DNO
+
+#define FP_DENORM_ZERO (fpcw & IEEE_MAP_DMZ)
+
+#define FP_HANDLE_EXCEPTIONS return _fex
+
+/* We write the results always */
+#define FP_INHIBIT_RESULTS 0
+
+#endif
#include <asm/iomd.h>
-#define arch_reset(mode) { \
- outb (0, IOMD_ROMCR0); \
- cli(); \
- __asm__ __volatile__("msr spsr, r1;" \
- "mcr p15, 0, %0, c1, c0, 0;" \
- "movs pc, #0" \
- : \
- : "r" (cpu_reset())); \
+#define arch_reset(mode) { \
+ outb (0, IOMD_ROMCR0); \
+ cli(); \
+ __asm__ __volatile__( \
+ "mcr p15, 0, %0, c1, c0, 0;" \
+ "mov pc, #0" \
+ : \
+ : "r" (cpu_reset())); \
}
/*
* We can wait for an interrupt...
*/
-#define proc_idle() \
+#define arch_do_idle() \
outb(0, IOMD_SUSMODE)
#endif
#ifndef __ASM_ARCH_SYSTEM_H
#define __ASM_ARCH_SYSTEM_H
-#define arch_do_idle() do { } while (0)
-#define arch_reset(mode) do { } while (0)
+#define arch_do_idle() cpu_do_idle()
+
+extern __inline__ void arch_reset(char mode)
+{
+ if (mode == 's') {
+ __asm__ volatile(
+ "mcr p15, 0, %0, c1, c0, 0 @ MMU off
+ mov pc, #0x80000000 @ jump to flash"
+ : : "r" (cpu_reset()) : "cc");
+ }
+}
#endif
{
if (mode == 's') {
__asm__ volatile (
- "mov lr, #0x41000000 @ prepare to jump to ROM
- mcr p15, 0, %0, c1, c0, 0 @ MMU off
- mov pc, lr" : : "r" (cpu_reset()) : "cc");
+ "mcr p15, 0, %0, c1, c0, 0 @ MMU off
+ mov pc, #0x41000000 @ jump to ROM" : :
+ "r" (cpu_reset()) : "cc");
} else {
if (machine_is_netwinder()) {
/* open up the SuperIO chip
#else
-#define arch_reset( x ) { \
+#define arch_reset(x) { \
__asm__ volatile ( \
" mcr p15, 0, %0, c1, c0 @ MMU off\n" \
-" mov pc, #0\n" : : "r" (cpu_reset())); \
+" mov pc, #0\n" : : "r" (cpu_reset()) : "cc"); \
}
#endif
* easily, subsequent pte tables have to be allocated in one physical
* chunk of RAM.
*/
-#define PKMAP_BASE (0xff000000UL)
+#define PKMAP_BASE (0xfe000000UL)
#ifdef CONFIG_X86_PAE
#define LAST_PKMAP 512
#else
"jmp 1b\n" \
".previous"
+/*
+ * Sadly, some early PPro chips require the locked access,
+ * otherwise we could just always simply do
+ *
+ * #define spin_unlock_string \
+ * "movb $0,%0"
+ *
+ * Which is noticeably faster.
+ */
#define spin_unlock_string \
- "movb $0,%0"
+ "lock ; btrl $0,%0"
extern inline void spin_lock(spinlock_t *lock)
{
#define _PPC_BOOTINFO_H
struct bi_record {
- unsigned short tag; /* tag ID */
+ unsigned long tag; /* tag ID */
unsigned long size; /* size of record (in bytes) */
unsigned long data[0]; /* data */
};
#ifndef _PPC_PGALLOC_H
#define _PPC_PGALLOC_H
+#include <linux/config.h>
+#include <linux/threads.h>
+#include <asm/processor.h>
+/*
+ * This is handled very differently on the PPC since out page tables
+ * are all 0's and I want to be able to use these zero'd pages elsewhere
+ * as well - it gives us quite a speedup.
+ *
+ * Note that the SMP/UP versions are the same but we don't need a
+ * per cpu list of zero pages because we do the zero-ing with the cache
+ * off and the access routines are lock-free but the pgt cache stuff
+ * is per-cpu since it isn't done with any lock-free access routines
+ * (although I think we need arch-specific routines so I can do lock-free).
+ *
+ * I need to generalize this so we can use it for other arch's as well.
+ * -- Cort
+ */
+#ifdef __SMP__
+#define quicklists cpu_data[smp_processor_id()]
+#else
+extern struct pgtable_cache_struct {
+ unsigned long *pgd_cache;
+ unsigned long *pte_cache;
+ unsigned long pgtable_cache_sz;
+} quicklists;
+#endif
+
+#define pgd_quicklist (quicklists.pgd_cache)
+#define pmd_quicklist ((unsigned long *)0)
+#define pte_quicklist (quicklists.pte_cache)
+#define pgtable_cache_size (quicklists.pgtable_cache_sz)
+
+extern unsigned long *zero_cache; /* head linked list of pre-zero'd pages */
+extern atomic_t zero_sz; /* # currently pre-zero'd pages */
+extern atomic_t zeropage_hits; /* # zero'd pages request that we've done */
+extern atomic_t zeropage_calls; /* # zero'd pages request that've been made */
+extern atomic_t zerototal; /* # pages zero'd over time */
+
+#define zero_quicklist (zero_cache)
+#define zero_cache_sz (zero_sz)
+#define zero_cache_calls (zeropage_calls)
+#define zero_cache_hits (zeropage_hits)
+#define zero_cache_total (zerototal)
+
+/* return a pre-zero'd page from the list, return NULL if none available -- Cort */
+extern unsigned long get_zero_page_fast(void);
+
+extern void __bad_pte(pmd_t *pmd);
+
+extern inline void set_pgdir(unsigned long address, pgd_t entry)
+{
+ struct task_struct * p;
+ pgd_t *pgd;
+#ifdef __SMP__
+ int i;
+#endif
+
+ read_lock(&tasklist_lock);
+ for_each_task(p) {
+ if (!p->mm)
+ continue;
+ *pgd_offset(p->mm,address) = entry;
+ }
+ read_unlock(&tasklist_lock);
+#ifndef __SMP__
+ for (pgd = (pgd_t *)pgd_quicklist; pgd; pgd = (pgd_t *)*(unsigned long *)pgd)
+ pgd[address >> PGDIR_SHIFT] = entry;
+#else
+ /* To pgd_alloc/pgd_free, one holds master kernel lock and so does our callee, so we can
+ modify pgd caches of other CPUs as well. -jj */
+ for (i = 0; i < NR_CPUS; i++)
+ for (pgd = (pgd_t *)cpu_data[i].pgd_cache; pgd; pgd = (pgd_t *)*(unsigned long *)pgd)
+ pgd[address >> PGDIR_SHIFT] = entry;
+#endif
+}
/* We don't use pmd cache, so this is a dummy routine */
extern __inline__ pmd_t *get_pmd_fast(void)
{
unsigned long *ret;
- if((ret = pgd_quicklist) != NULL) {
+ if ((ret = pgd_quicklist) != NULL) {
pgd_quicklist = (unsigned long *)(*ret);
- ret[0] = ret[1];
+ ret[0] = 0;
pgtable_cache_size--;
} else
ret = (unsigned long *)get_pgd_slow();
extern __inline__ void free_pgd_fast(pgd_t *pgd)
{
- *(unsigned long *)pgd = (unsigned long) pgd_quicklist;
+ *(unsigned long **)pgd = pgd_quicklist;
pgd_quicklist = (unsigned long *) pgd;
pgtable_cache_size++;
}
{
unsigned long *ret;
- if((ret = (unsigned long *)pte_quicklist) != NULL) {
+ if ((ret = pte_quicklist) != NULL) {
pte_quicklist = (unsigned long *)(*ret);
- ret[0] = ret[1];
+ ret[0] = 0;
pgtable_cache_size--;
}
return (pte_t *)ret;
extern __inline__ void free_pte_fast(pte_t *pte)
{
- *(unsigned long *)pte = (unsigned long) pte_quicklist;
+ *(unsigned long **)pte = pte_quicklist;
pte_quicklist = (unsigned long *) pte;
pgtable_cache_size++;
}
{
free_page((unsigned long)pte);
}
+
#define pte_free_kernel(pte) free_pte_fast(pte)
#define pte_free(pte) free_pte_fast(pte)
#define pgd_free(pgd) free_pgd_fast(pgd)
extern int do_check_pgt_cache(int, int);
-extern __inline__ pte_t *find_pte(struct mm_struct *mm,unsigned long va)
-{
- pgd_t *dir;
- pmd_t *pmd;
- pte_t *pte;
-
- va &= PAGE_MASK;
-
- dir = pgd_offset( mm, va );
- if (dir)
- {
- pmd = pmd_offset(dir, va & PAGE_MASK);
- if (pmd && pmd_present(*pmd))
- {
- pte = pte_offset(pmd, va);
- if (pte && pte_present(*pte))
- {
- pte_uncache(*pte);
- flush_tlb_page(find_vma(mm,va),va);
- }
- }
- }
- return pte;
-}
-
#endif /* _PPC_PGALLOC_H */
-#include <linux/config.h>
-
#ifndef _PPC_PGTABLE_H
#define _PPC_PGTABLE_H
+#include <linux/config.h>
+
#ifndef __ASSEMBLY__
#include <linux/threads.h>
-#include <linux/sched.h>
-#include <asm/atomic.h>
#include <asm/processor.h> /* For TASK_SIZE */
#include <asm/mmu.h>
#include <asm/page.h>
/*
* Permanent address of a page.
*/
-#define page_address(page) (PAGE_OFFSET + (((page) - mem_map) << PAGE_SHIFT))
-#define __page_address(page) ({ if (PageHighMem(page)) BUG(); PAGE_OFFSET + (((page) - mem_map) << PAGE_SHIFT); })
+#define page_address(page) ({ if (!(page)->virtual) BUG(); (page)->virtual; })
+#define __page_address(page) (PAGE_OFFSET + (((page) - mem_map) << PAGE_SHIFT))
#define pages_to_mb(x) ((x) >> (20-PAGE_SHIFT))
#define pte_page(x) (mem_map+pte_pagenr(x))
extern inline int pgd_none(pgd_t pgd) { return 0; }
extern inline int pgd_bad(pgd_t pgd) { return 0; }
extern inline int pgd_present(pgd_t pgd) { return 1; }
-#define pgd_clear(xp) do { } while(0)
+#define pgd_clear(xp) do { } while (0)
#define pgd_page(pgd) \
((unsigned long) __va(pgd_val(pgd) & PAGE_MASK))
return pte;
}
-#define page_pte_prot(page,prot) mk_pte(page, prot)
-#define page_pte(page) page_pte_prot(page, __pgprot(0))
-
#define pmd_page(pmd) (pmd_val(pmd))
/* to find an entry in a kernel page-table-directory */
#define pgd_offset_k(address) pgd_offset(&init_mm, address)
/* to find an entry in a page-table-directory */
-extern inline pgd_t * pgd_offset(struct mm_struct * mm, unsigned long address)
-{
- return mm->pgd + (address >> PGDIR_SHIFT);
-}
+#define pgd_offset(mm, address) ((mm)->pgd + ((address) >> PGDIR_SHIFT))
/* Find an entry in the second-level page table.. */
extern inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address)
return (pte_t *) pmd_page(*dir) + ((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1));
}
-/*
- * This is handled very differently on the PPC since out page tables
- * are all 0's and I want to be able to use these zero'd pages elsewhere
- * as well - it gives us quite a speedup.
- *
- * Note that the SMP/UP versions are the same but we don't need a
- * per cpu list of zero pages because we do the zero-ing with the cache
- * off and the access routines are lock-free but the pgt cache stuff
- * is per-cpu since it isn't done with any lock-free access routines
- * (although I think we need arch-specific routines so I can do lock-free).
- *
- * I need to generalize this so we can use it for other arch's as well.
- * -- Cort
- */
-#ifdef __SMP__
-#define quicklists cpu_data[smp_processor_id()]
-#else
-extern struct pgtable_cache_struct {
- unsigned long *pgd_cache;
- unsigned long *pte_cache;
- unsigned long pgtable_cache_sz;
-} quicklists;
-#endif
-
-#define pgd_quicklist (quicklists.pgd_cache)
-#define pmd_quicklist ((unsigned long *)0)
-#define pte_quicklist (quicklists.pte_cache)
-#define pgtable_cache_size (quicklists.pgtable_cache_sz)
-
-extern unsigned long *zero_cache; /* head linked list of pre-zero'd pages */
-extern atomic_t zero_sz; /* # currently pre-zero'd pages */
-extern atomic_t zeropage_hits; /* # zero'd pages request that we've done */
-extern atomic_t zeropage_calls; /* # zero'd pages request that've been made */
-extern atomic_t zerototal; /* # pages zero'd over time */
-
-#define zero_quicklist (zero_cache)
-#define zero_cache_sz (zero_sz)
-#define zero_cache_calls (zeropage_calls)
-#define zero_cache_hits (zeropage_hits)
-#define zero_cache_total (zerototal)
-
-/* return a pre-zero'd page from the list, return NULL if none available -- Cort */
-extern unsigned long get_zero_page_fast(void);
-
-extern void __bad_pte(pmd_t *pmd);
-
-extern inline void set_pgdir(unsigned long address, pgd_t entry)
-{
- struct task_struct * p;
- pgd_t *pgd;
-#ifdef __SMP__
- int i;
-#endif
-
- read_lock(&tasklist_lock);
- for_each_task(p) {
- if (!p->mm)
- continue;
- *pgd_offset(p->mm,address) = entry;
- }
- read_unlock(&tasklist_lock);
-#ifndef __SMP__
- for (pgd = (pgd_t *)pgd_quicklist; pgd; pgd = (pgd_t *)*(unsigned long *)pgd)
- pgd[address >> PGDIR_SHIFT] = entry;
-#else
- /* To pgd_alloc/pgd_free, one holds master kernel lock and so does our callee, so we can
- modify pgd caches of other CPUs as well. -jj */
- for (i = 0; i < NR_CPUS; i++)
- for (pgd = (pgd_t *)cpu_data[i].pgd_cache; pgd; pgd = (pgd_t *)*(unsigned long *)pgd)
- pgd[address >> PGDIR_SHIFT] = entry;
-#endif
-}
-
extern pgd_t swapper_pg_dir[1024];
/*
extern void flush_hash_segments(unsigned low_vsid, unsigned high_vsid);
extern void flush_hash_page(unsigned context, unsigned long va);
-
/* Encode and de-code a swap entry */
-#define SWP_TYPE(entry) (((entry).val >> 1) & 0x3f)
-#define SWP_OFFSET(entry) ((entry).val >> 8)
-#define SWP_ENTRY(type,offset) ((swp_entry_t) { (((type) << 1) | ((offset) << 8)) })
+#define SWP_TYPE(entry) (((entry).val >> 1) & 0x3f)
+#define SWP_OFFSET(entry) ((entry).val >> 8)
+#define SWP_ENTRY(type, offset) ((swp_entry_t) { ((type) << 1) | ((offset) << 8) })
#define pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) })
#define swp_entry_to_pte(x) ((pte_t) { (x).val })
#define INIT_RLIMITS \
{ \
- {LONG_MAX, LONG_MAX}, /* RLIMIT_CPU */ \
- {LONG_MAX, LONG_MAX}, /* RLIMIT_FSIZE */ \
- {LONG_MAX, LONG_MAX}, /* RLIMIT_DATA */ \
- {_STK_LIM, LONG_MAX}, /* RLIMIT_STACK */ \
- { 0, LONG_MAX}, /* RLIMIT_CORE */ \
- {LONG_MAX, LONG_MAX}, /* RLIMIT_RSS */ \
- {0, 0}, \
- {INR_OPEN, INR_OPEN}, /* RLIMIT_NOFILE */ \
- {LONG_MAX, LONG_MAX}, /* RLIMIT_MEMLOCK */ \
- {LONG_MAX, LONG_MAX}, /* RLIMIT_AS */ \
+ { RLIM_INFINITY, RLIM_INFINITY }, \
+ { RLIM_INFINITY, RLIM_INFINITY }, \
+ { RLIM_INFINITY, RLIM_INFINITY }, \
+ { _STK_LIM, RLIM_INFINITY }, \
+ { 0, RLIM_INFINITY }, \
+ { RLIM_INFINITY, RLIM_INFINITY }, \
+ { 0, 0 }, \
+ { INR_OPEN, INR_OPEN }, \
+ { RLIM_INFINITY, RLIM_INFINITY }, \
+ { RLIM_INFINITY, RLIM_INFINITY }, \
}
#endif /* __KERNEL__ */
#define __NR_getpmsg 187 /* some people actually want streams */
#define __NR_putpmsg 188 /* some people actually want streams */
#define __NR_vfork 189
+#define __NR_ugetrlimit 191 /* SuS compliant getrlimit */
#define __NR(n) #n
--- /dev/null
+/* Machine-dependent software floating-point definitions.
+ Sparc userland (_Q_*) version.
+ Copyright (C) 1997,1998,1999 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Richard Henderson (rth@cygnus.com),
+ Jakub Jelinek (jj@ultra.linux.cz),
+ David S. Miller (davem@redhat.com) and
+ Peter Maydell (pmaydell@chiark.greenend.org.uk).
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If
+ not, write to the Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ifndef _SFP_MACHINE_H
+#define _SFP_MACHINE_H
+
+#define _FP_W_TYPE_SIZE 32
+#define _FP_W_TYPE unsigned long
+#define _FP_WS_TYPE signed long
+#define _FP_I_TYPE long
+
+#define _FP_MUL_MEAT_S(R,X,Y) \
+ _FP_MUL_MEAT_1_wide(_FP_WFRACBITS_S,R,X,Y,umul_ppmm)
+#define _FP_MUL_MEAT_D(R,X,Y) \
+ _FP_MUL_MEAT_2_wide(_FP_WFRACBITS_D,R,X,Y,umul_ppmm)
+#define _FP_MUL_MEAT_Q(R,X,Y) \
+ _FP_MUL_MEAT_5_wide(_FP_WFRACBITS_Q,R,X,Y,umul_ppmm)
+
+#define _FP_DIV_MEAT_S(R,X,Y) _FP_DIV_MEAT_1_udiv(S,R,X,Y)
+#define _FP_DIV_MEAT_D(R,X,Y) _FP_DIV_MEAT_2_udiv(D,R,X,Y)
+#define _FP_DIV_MEAT_Q(R,X,Y) _FP_DIV_MEAT_4_udiv(Q,R,X,Y)
+
+#define _FP_NANFRAC_S ((_FP_QNANBIT_S << 1) - 1)
+#define _FP_NANFRAC_D ((_FP_QNANBIT_D << 1) - 1), -1
+#define _FP_NANFRAC_Q ((_FP_QNANBIT_Q << 1) - 1), -1, -1, -1
+#define _FP_NANSIGN_S 0
+#define _FP_NANSIGN_D 0
+#define _FP_NANSIGN_Q 0
+
+#define _FP_KEEPNANFRACP 1
+
+/* If one NaN is signaling and the other is not,
+ * we choose that one, otherwise we choose X.
+ */
+/* For _Qp_* and _Q_*, this should prefer X, for
+ * CPU instruction emulation this should prefer Y.
+ * (see SPAMv9 B.2.2 section).
+ */
+#define _FP_CHOOSENAN(fs, wc, R, X, Y, OP) \
+ do { \
+ if ((_FP_FRAC_HIGH_RAW_##fs(Y) & _FP_QNANBIT_##fs) \
+ && !(_FP_FRAC_HIGH_RAW_##fs(X) & _FP_QNANBIT_##fs)) \
+ { \
+ R##_s = X##_s; \
+ _FP_FRAC_COPY_##wc(R,X); \
+ } \
+ else \
+ { \
+ R##_s = Y##_s; \
+ _FP_FRAC_COPY_##wc(R,Y); \
+ } \
+ R##_c = FP_CLS_NAN; \
+ } while (0)
+
+/* Some assembly to speed things up. */
+#define __FP_FRAC_ADD_3(r2,r1,r0,x2,x1,x0,y2,y1,y0) \
+ __asm__ ("addcc %r7,%8,%2
+ addxcc %r5,%6,%1
+ addx %r3,%4,%0" \
+ : "=r" ((USItype)(r2)), \
+ "=&r" ((USItype)(r1)), \
+ "=&r" ((USItype)(r0)) \
+ : "%rJ" ((USItype)(x2)), \
+ "rI" ((USItype)(y2)), \
+ "%rJ" ((USItype)(x1)), \
+ "rI" ((USItype)(y1)), \
+ "%rJ" ((USItype)(x0)), \
+ "rI" ((USItype)(y0)) \
+ : "cc")
+
+#define __FP_FRAC_SUB_3(r2,r1,r0,x2,x1,x0,y2,y1,y0) \
+ __asm__ ("subcc %r7,%8,%2
+ subxcc %r5,%6,%1
+ subx %r3,%4,%0" \
+ : "=r" ((USItype)(r2)), \
+ "=&r" ((USItype)(r1)), \
+ "=&r" ((USItype)(r0)) \
+ : "%rJ" ((USItype)(x2)), \
+ "rI" ((USItype)(y2)), \
+ "%rJ" ((USItype)(x1)), \
+ "rI" ((USItype)(y1)), \
+ "%rJ" ((USItype)(x0)), \
+ "rI" ((USItype)(y0)) \
+ : "cc")
+
+#define __FP_FRAC_ADD_4(r3,r2,r1,r0,x3,x2,x1,x0,y3,y2,y1,y0) \
+ do { \
+ /* We need to fool gcc, as we need to pass more than 10 \
+ input/outputs. */ \
+ register USItype _t1 __asm__ ("g1"), _t2 __asm__ ("g2"); \
+ __asm__ __volatile__ ("
+ addcc %r8,%9,%1
+ addxcc %r6,%7,%0
+ addxcc %r4,%5,%%g2
+ addx %r2,%3,%%g1" \
+ : "=&r" ((USItype)(r1)), \
+ "=&r" ((USItype)(r0)) \
+ : "%rJ" ((USItype)(x3)), \
+ "rI" ((USItype)(y3)), \
+ "%rJ" ((USItype)(x2)), \
+ "rI" ((USItype)(y2)), \
+ "%rJ" ((USItype)(x1)), \
+ "rI" ((USItype)(y1)), \
+ "%rJ" ((USItype)(x0)), \
+ "rI" ((USItype)(y0)) \
+ : "cc", "g1", "g2"); \
+ __asm__ __volatile__ ("" : "=r" (_t1), "=r" (_t2)); \
+ r3 = _t1; r2 = _t2; \
+ } while (0)
+
+#define __FP_FRAC_SUB_4(r3,r2,r1,r0,x3,x2,x1,x0,y3,y2,y1,y0) \
+ do { \
+ /* We need to fool gcc, as we need to pass more than 10 \
+ input/outputs. */ \
+ register USItype _t1 __asm__ ("g1"), _t2 __asm__ ("g2"); \
+ __asm__ __volatile__ ("
+ subcc %r8,%9,%1
+ subxcc %r6,%7,%0
+ subxcc %r4,%5,%%g2
+ subx %r2,%3,%%g1" \
+ : "=&r" ((USItype)(r1)), \
+ "=&r" ((USItype)(r0)) \
+ : "%rJ" ((USItype)(x3)), \
+ "rI" ((USItype)(y3)), \
+ "%rJ" ((USItype)(x2)), \
+ "rI" ((USItype)(y2)), \
+ "%rJ" ((USItype)(x1)), \
+ "rI" ((USItype)(y1)), \
+ "%rJ" ((USItype)(x0)), \
+ "rI" ((USItype)(y0)) \
+ : "cc", "g1", "g2"); \
+ __asm__ __volatile__ ("" : "=r" (_t1), "=r" (_t2)); \
+ r3 = _t1; r2 = _t2; \
+ } while (0)
+
+#define __FP_FRAC_DEC_3(x2,x1,x0,y2,y1,y0) __FP_FRAC_SUB_3(x2,x1,x0,x2,x1,x0,y2,y1,y0)
+
+#define __FP_FRAC_DEC_4(x3,x2,x1,x0,y3,y2,y1,y0) __FP_FRAC_SUB_4(x3,x2,x1,x0,x3,x2,x1,x0,y3,y2,y1,y0)
+
+#define __FP_FRAC_ADDI_4(x3,x2,x1,x0,i) \
+ __asm__ ("addcc %3,%4,%3
+ addxcc %2,%%g0,%2
+ addxcc %1,%%g0,%1
+ addx %0,%%g0,%0" \
+ : "=&r" ((USItype)(x3)), \
+ "=&r" ((USItype)(x2)), \
+ "=&r" ((USItype)(x1)), \
+ "=&r" ((USItype)(x0)) \
+ : "rI" ((USItype)(i)), \
+ "0" ((USItype)(x3)), \
+ "1" ((USItype)(x2)), \
+ "2" ((USItype)(x1)), \
+ "3" ((USItype)(x0)) \
+ : "cc")
+
+#ifndef __SMP__
+extern struct task_struct *last_task_used_math;
+#endif
+
+/* Obtain the current rounding mode. */
+#ifndef FP_ROUNDMODE
+#ifdef __SMP__
+#define FP_ROUNDMODE ((current->thread.fsr >> 30) & 0x3)
+#else
+#define FP_ROUNDMODE ((last_task_used_math->thread.fsr >> 30) & 0x3)
+#endif
+#endif
+
+/* Exception flags. */
+#define FP_EX_INVALID (1 << 4)
+#define FP_EX_OVERFLOW (1 << 3)
+#define FP_EX_UNDERFLOW (1 << 2)
+#define FP_EX_DIVZERO (1 << 1)
+#define FP_EX_INEXACT (1 << 0)
+
+#define FP_HANDLE_EXCEPTIONS return _fex
+
+#ifdef __SMP__
+#define FP_INHIBIT_RESULTS ((current->thread.fsr >> 23) & _fex)
+#else
+#define FP_INHIBIT_RESULTS ((last_task_used_math->thread.fsr >> 23) & _fex)
+#endif
+
+#endif
--- /dev/null
+/* Machine-dependent software floating-point definitions.
+ Sparc64 kernel version.
+ Copyright (C) 1997,1998,1999 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Richard Henderson (rth@cygnus.com),
+ Jakub Jelinek (jj@ultra.linux.cz) and
+ David S. Miller (davem@redhat.com).
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If
+ not, write to the Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ifndef _SFP_MACHINE_H
+#define _SFP_MACHINE_H
+
+#define _FP_W_TYPE_SIZE 64
+#define _FP_W_TYPE unsigned long
+#define _FP_WS_TYPE signed long
+#define _FP_I_TYPE long
+
+#define _FP_MUL_MEAT_S(R,X,Y) \
+ _FP_MUL_MEAT_1_imm(_FP_WFRACBITS_S,R,X,Y)
+#define _FP_MUL_MEAT_D(R,X,Y) \
+ _FP_MUL_MEAT_1_wide(_FP_WFRACBITS_D,R,X,Y,umul_ppmm)
+#define _FP_MUL_MEAT_Q(R,X,Y) \
+ _FP_MUL_MEAT_2_wide_3mul(_FP_WFRACBITS_Q,R,X,Y,umul_ppmm)
+
+#define _FP_DIV_MEAT_S(R,X,Y) _FP_DIV_MEAT_1_imm(S,R,X,Y,_FP_DIV_HELP_imm)
+#define _FP_DIV_MEAT_D(R,X,Y) _FP_DIV_MEAT_1_udiv(D,R,X,Y)
+#define _FP_DIV_MEAT_Q(R,X,Y) _FP_DIV_MEAT_2_udiv(Q,R,X,Y)
+
+#define _FP_NANFRAC_S ((_FP_QNANBIT_S << 1) - 1)
+#define _FP_NANFRAC_D ((_FP_QNANBIT_D << 1) - 1)
+#define _FP_NANFRAC_Q ((_FP_QNANBIT_Q << 1) - 1), -1
+#define _FP_NANSIGN_S 0
+#define _FP_NANSIGN_D 0
+#define _FP_NANSIGN_Q 0
+
+#define _FP_KEEPNANFRACP 1
+
+/* If one NaN is signaling and the other is not,
+ * we choose that one, otherwise we choose X.
+ */
+/* For _Qp_* and _Q_*, this should prefer X, for
+ * CPU instruction emulation this should prefer Y.
+ * (see SPAMv9 B.2.2 section).
+ */
+#define _FP_CHOOSENAN(fs, wc, R, X, Y, OP) \
+ do { \
+ if ((_FP_FRAC_HIGH_RAW_##fs(Y) & _FP_QNANBIT_##fs) \
+ && !(_FP_FRAC_HIGH_RAW_##fs(X) & _FP_QNANBIT_##fs)) \
+ { \
+ R##_s = X##_s; \
+ _FP_FRAC_COPY_##wc(R,X); \
+ } \
+ else \
+ { \
+ R##_s = Y##_s; \
+ _FP_FRAC_COPY_##wc(R,Y); \
+ } \
+ R##_c = FP_CLS_NAN; \
+ } while (0)
+
+/* Obtain the current rounding mode. */
+#ifndef FP_ROUNDMODE
+#define FP_ROUNDMODE ((current->thread.xfsr[0] >> 30) & 0x3)
+#endif
+
+/* Exception flags. */
+#define FP_EX_INVALID (1 << 4)
+#define FP_EX_OVERFLOW (1 << 3)
+#define FP_EX_UNDERFLOW (1 << 2)
+#define FP_EX_DIVZERO (1 << 1)
+#define FP_EX_INEXACT (1 << 0)
+
+#define FP_HANDLE_EXCEPTIONS return _fex
+
+#define FP_INHIBIT_RESULTS ((current->thread.xfsr[0] >> 23) & _fex)
+
+#endif
#include <linux/types.h>
#include <linux/ioctl.h>
-
#ifdef __KERNEL__
-
#include <linux/config.h>
#include <linux/sched.h>
#include <linux/wait.h>
+#endif /* __KERNEL__ */
/*
- * Device types
+ * System sleep states
*/
enum
{
- ACPI_SYS_DEV, /* system device (fan, KB controller, ...) */
- ACPI_PCI_DEV, /* generic PCI device */
- ACPI_PCI_BUS, /* PCI bus */
- ACPI_ISA_DEV, /* generic ISA device */
- ACPI_ISA_BUS, /* ISA bus */
- ACPI_USB_DEV, /* generic USB device */
- ACPI_USB_HUB, /* USB hub device */
- ACPI_USB_CTRL, /* USB controller */
- ACPI_SCSI_DEV, /* generic SCSI device */
- ACPI_SCSI_CTRL, /* SCSI controller */
+ ACPI_S0, /* working */
+ ACPI_S1, /* sleep */
+ ACPI_S2, /* sleep */
+ ACPI_S3, /* sleep */
+ ACPI_S4, /* non-volatile sleep */
+ ACPI_S5, /* soft-off */
};
-typedef int acpi_dev_t;
+typedef int acpi_sstate_t;
/*
- * Device addresses
+ * Device states
*/
-#define ACPI_PCI_ADR(dev) ((dev)->bus->number << 16 | (dev)->devfn)
+enum
+{
+ ACPI_D0, /* fully-on */
+ ACPI_D1, /* partial-on */
+ ACPI_D2, /* partial-on */
+ ACPI_D3, /* fully-off */
+};
+
+typedef int acpi_dstate_t;
/*
* HID (PnP) values
typedef int acpi_hid_t;
+#ifdef __KERNEL__
+
/*
- * Device states
+ * Device types
*/
enum
{
- ACPI_D0, /* fully-on */
- ACPI_D1, /* partial-on */
- ACPI_D2, /* partial-on */
- ACPI_D3, /* fully-off */
+ ACPI_SYS_DEV, /* system device (fan, KB controller, ...) */
+ ACPI_PCI_DEV, /* generic PCI device */
+ ACPI_PCI_BUS, /* PCI bus */
+ ACPI_ISA_DEV, /* generic ISA device */
+ ACPI_ISA_BUS, /* ISA bus */
+ ACPI_USB_DEV, /* generic USB device */
+ ACPI_USB_HUB, /* USB hub device */
+ ACPI_USB_CTRL, /* USB controller */
+ ACPI_SCSI_DEV, /* generic SCSI device */
+ ACPI_SCSI_CTRL, /* SCSI controller */
};
-typedef int acpi_dstate_t;
+typedef int acpi_dev_t;
/*
- * System sleep states
+ * Device addresses
*/
-enum
-{
- ACPI_S0, /* working */
- ACPI_S1, /* sleep */
- ACPI_S2, /* sleep */
- ACPI_S3, /* sleep */
- ACPI_S4, /* non-volatile sleep */
- ACPI_S5, /* soft-off */
-};
-
-typedef int acpi_sstate_t;
+#define ACPI_PCI_ADR(dev) ((dev)->bus->number << 16 | (dev)->devfn)
struct acpi_dev;
#ifdef CONFIG_ACPI
-extern wait_queue_head_t acpi_idle_wait;
+extern wait_queue_head_t acpi_control_wait;
/*
* Register a device with the ACPI subsystem
{
if (dev) {
dev->idle = jiffies;
- if (waitqueue_active(&acpi_idle_wait))
- wake_up(&acpi_idle_wait);
+ if (waitqueue_active(&acpi_control_wait))
+ wake_up(&acpi_control_wait);
}
}
ACPI_P_BLK,
ACPI_P_LVL2_LAT,
ACPI_P_LVL3_LAT,
+ ACPI_S0_SLP_TYP,
+ ACPI_S1_SLP_TYP,
ACPI_S5_SLP_TYP,
+ ACPI_SLEEP,
};
#define ACPI_SLP_TYP_DISABLED (~0UL)
#define DVD_LU_SEND_TITLE_KEY 7
#define DVD_LU_SEND_ASF 8
#define DVD_INVALIDATE_AGID 9
+#define DVD_LU_SEND_RPC_STATE 10
+#define DVD_HOST_SEND_RPC_STATE 11
/* State data */
typedef __u8 dvd_key[5]; /* 40-bit value, MSB is first elem. */
unsigned asf : 1;
};
+struct dvd_host_send_rpcstate {
+ __u8 pdrc;
+};
+
+struct dvd_lu_send_rpcstate {
+ __u8 type : 2;
+ __u8 vra : 3;
+ __u8 ucca : 3;
+ __u8 region_mask;
+ __u8 rpc_scheme;
+};
+
typedef union {
__u8 type;
struct dvd_send_key hsk;
struct dvd_lu_send_title_key lstk;
struct dvd_lu_send_asf lsasf;
+ struct dvd_host_send_rpcstate hrpcs;
+ struct dvd_lu_send_rpcstate lrpcs;
} dvd_authinfo;
#ifdef __KERNEL__
int (*fb_rasterimg)(struct fb_info *info, int start);
};
-
- /*
- * This is the interface between the low-level console driver and the
- * low-level frame buffer device
- */
-
-struct display {
- /* Filled in by the frame buffer device */
-
- struct fb_var_screeninfo var; /* variable infos. yoffset and vmode */
- /* are updated by fbcon.c */
- struct fb_cmap cmap; /* colormap */
- char *screen_base; /* pointer to top of virtual screen */
- /* (virtual address) */
- int visual;
- int type; /* see FB_TYPE_* */
- int type_aux; /* Interleave for interleaved Planes */
- u_short ypanstep; /* zero if no hardware ypan */
- u_short ywrapstep; /* zero if no hardware ywrap */
- u_long line_length; /* length of a line in bytes */
- u_short can_soft_blank; /* zero if no hardware blanking */
- u_short inverse; /* != 0 text black on white as default */
- struct display_switch *dispsw; /* low level operations */
- void *dispsw_data; /* optional dispsw helper data */
-
-#if 0
- struct fb_fix_cursorinfo fcrsr;
- struct fb_var_cursorinfo *vcrsr;
- struct fb_cursorstate crsrstate;
-#endif
-
- /* Filled in by the low-level console driver */
-
- struct vc_data *conp; /* pointer to console data */
- struct fb_info *fb_info; /* frame buffer for this console */
- int vrows; /* number of virtual rows */
- unsigned short cursor_x; /* current cursor position */
- unsigned short cursor_y;
- int fgcol; /* text colors */
- int bgcol;
- u_long next_line; /* offset to one line below */
- u_long next_plane; /* offset to next plane */
- u_char *fontdata; /* Font associated to this display */
- unsigned short _fontheightlog;
- unsigned short _fontwidthlog;
- unsigned short _fontheight;
- unsigned short _fontwidth;
- int userfont; /* != 0 if fontdata kmalloc()ed */
- u_short scrollmode; /* Scroll Method */
- short yscroll; /* Hardware scrolling */
- unsigned char fgshift, bgshift;
- unsigned short charmask; /* 0xff or 0x1ff */
-};
-
-
struct fb_info {
char modename[40]; /* default video mode */
kdev_t node;
extern int num_registered_fb;
extern struct fb_info *registered_fb[FB_MAX];
-extern char con2fb_map[MAX_NR_CONSOLES];
/* drivers/video/fbmon.c */
extern int fbmon_valid_timings(u_int pixclock, u_int htotal, u_int vtotal,
const struct fb_info *fb_info);
extern int fbmon_dpms(const struct fb_info *fb_info);
-/* drivers/video/fbcon.c */
-extern struct display fb_display[MAX_NR_CONSOLES];
-
/* drivers/video/fbcmap.c */
extern int fb_alloc_cmap(struct fb_cmap *cmap, int len, int transp);
extern void fb_copy_cmap(struct fb_cmap *from, struct fb_cmap *to,
#define TASK_EXCLUSIVE 32
#define __set_task_state(tsk, state_value) \
- do { tsk->state = state_value; } while (0)
+ do { (tsk)->state = (state_value); } while (0)
#ifdef __SMP__
#define set_task_state(tsk, state_value) \
- set_mb(tsk->state, state_value)
+ set_mb((tsk)->state, (state_value))
#else
#define set_task_state(tsk, state_value) \
- __set_task_state(tsk, state_value)
+ __set_task_state((tsk), (state_value))
#endif
#define __set_current_state(state_value) \
- do { current->state = state_value; } while (0)
+ do { current->state = (state_value); } while (0)
#ifdef __SMP__
#define set_current_state(state_value) \
- set_mb(current->state, state_value)
+ set_mb(current->state, (state_value))
#else
#define set_current_state(state_value) \
__set_current_state(state_value)
#ifndef _LINUX_SWAP_H
#define _LINUX_SWAP_H
+#include <linux/spinlock.h>
#include <asm/page.h>
#define SWAP_FLAG_PREFER 0x8000 /* set if swap priority specified */
struct swap_info_struct {
unsigned int flags;
kdev_t swap_device;
+ spinlock_t sdev_lock;
struct dentry * swap_file;
unsigned short * swap_map;
unsigned int lowest_bit;
/* linux/mm/swap_state.c */
extern void show_swap_cache_info(void);
extern void add_to_swap_cache(struct page *, swp_entry_t);
-extern int swap_duplicate(swp_entry_t);
extern int swap_check_entry(unsigned long);
extern struct page * lookup_swap_cache(swp_entry_t);
extern struct page * read_swap_cache_async(swp_entry_t, int);
#define read_swap_cache(entry) read_swap_cache_async(entry, 1);
-extern int swap_count(struct page *);
-extern swp_entry_t acquire_swap_entry(struct page *page);
/*
* Make these inline later once they are working properly.
extern int is_swap_partition(kdev_t);
extern void si_swapinfo(struct sysinfo *);
extern swp_entry_t __get_swap_page(unsigned short);
+extern void get_swaphandle_info(swp_entry_t, unsigned long *, kdev_t *,
+ struct inode **);
+extern int swap_duplicate(swp_entry_t);
+extern int swap_count(struct page *);
+extern swp_entry_t acquire_swap_entry(struct page *page);
+extern int valid_swaphandles(swp_entry_t, unsigned long *);
#define get_swap_page() __get_swap_page(1)
extern void __swap_free(swp_entry_t, unsigned short);
#define swap_free(entry) __swap_free((entry), 1)
spin_unlock(&pagemap_lru_lock); \
} while (0)
+extern spinlock_t swaplock;
+
+#define swap_list_lock() spin_lock(&swaplock)
+#define swap_list_unlock() spin_unlock(&swaplock)
+#define swap_device_lock(p) spin_lock(&p->sdev_lock)
+#define swap_device_unlock(p) spin_unlock(&p->sdev_lock)
+
#endif /* __KERNEL__*/
#endif /* _LINUX_SWAP_H */
#define FP_CMP_EQ_D(r,X,Y) _FP_CMP_EQ(D,2,r,X,Y)
#define FP_TO_INT_D(r,X,rsz,rsg) _FP_TO_INT(D,2,r,X,rsz,rsg)
+#define FP_TO_INT_ROUND_D(r,X,rsz,rsg) _FP_TO_INT_ROUND(D,2,r,X,rsz,rsg)
#define FP_FROM_INT_D(X,r,rs,rt) _FP_FROM_INT(D,2,X,r,rs,rt)
#define _FP_FRAC_HIGH_D(X) _FP_FRAC_HIGH_2(X)
#define FP_CMP_EQ_D(r,X,Y) _FP_CMP_EQ(D,1,r,X,Y)
#define FP_TO_INT_D(r,X,rsz,rsg) _FP_TO_INT(D,1,r,X,rsz,rsg)
+#define FP_TO_INT_ROUND_D(r,X,rsz,rsg) _FP_TO_INT_ROUND(D,1,r,X,rsz,rsg)
#define FP_FROM_INT_D(X,r,rs,rt) _FP_FROM_INT(D,1,X,r,rs,rt)
#define _FP_FRAC_HIGH_D(X) _FP_FRAC_HIGH_1(X)
#define FP_CMP_EQ_E(r,X,Y) _FP_CMP_EQ(E,4,r,X,Y)
#define FP_TO_INT_E(r,X,rsz,rsg) _FP_TO_INT(E,4,r,X,rsz,rsg)
+#define FP_TO_INT_ROUND_E(r,X,rsz,rsg) _FP_TO_INT_ROUND(E,4,r,X,rsz,rsg)
#define FP_FROM_INT_E(X,r,rs,rt) _FP_FROM_INT(E,4,X,r,rs,rt)
#define _FP_FRAC_HIGH_E(X) (X##_f[2])
#define FP_CMP_EQ_E(r,X,Y) _FP_CMP_EQ(E,2,r,X,Y)
#define FP_TO_INT_E(r,X,rsz,rsg) _FP_TO_INT(E,2,r,X,rsz,rsg)
+#define FP_TO_INT_ROUND_E(r,X,rsz,rsg) _FP_TO_INT_ROUND(E,2,r,X,rsz,rsg)
#define FP_FROM_INT_E(X,r,rs,rt) _FP_FROM_INT(E,2,X,r,rs,rt)
#define _FP_FRAC_HIGH_E(X) (X##_f1)
#define _FP_FRAC_OVERP_2(fs,X) (_FP_FRAC_HIGH_##fs(X) & _FP_OVERFLOW_##fs)
#define _FP_FRAC_EQ_2(X, Y) (X##_f1 == Y##_f1 && X##_f0 == Y##_f0)
#define _FP_FRAC_GT_2(X, Y) \
- (X##_f1 > Y##_f1 || X##_f1 == Y##_f1 && X##_f0 > Y##_f0)
+ (X##_f1 > Y##_f1 || (X##_f1 == Y##_f1 && X##_f0 > Y##_f0))
#define _FP_FRAC_GE_2(X, Y) \
- (X##_f1 > Y##_f1 || X##_f1 == Y##_f1 && X##_f0 >= Y##_f0)
+ (X##_f1 > Y##_f1 || (X##_f1 == Y##_f1 && X##_f0 >= Y##_f0))
#define _FP_ZEROFRAC_2 0, 0
#define _FP_MINFRAC_2 0, 1
X##_e -= _FP_EXPBIAS_##fs - 1 + _shift; \
X##_c = FP_CLS_NORMAL; \
FP_SET_EXCEPTION(FP_EX_DENORM); \
+ if (FP_DENORM_ZERO) \
+ { \
+ FP_SET_EXCEPTION(FP_EX_INEXACT); \
+ X##_c = FP_CLS_ZERO; \
+ } \
} \
break; \
\
* 1: the number is required to be -(2^(rsize-1))..(2^(rsize-1))-1, if not, NV is
* set plus the result is either -(2^(rsize-1)) or (2^(rsize-1))-1 depending
* on the sign in such case.
+ * 2: the number is required to be -(2^(rsize-1))..(2^(rsize-1))-1, if not, NV is
+ * set plus the result is truncated to fit into destination.
* -1: the number is required to be -(2^(rsize-1))..(2^rsize)-1, if not, NV is
* set plus the result is either -(2^(rsize-1)) or (2^(rsize-1))-1 depending
* on the sign in such case.
{ /* overflow */ \
case FP_CLS_NAN: \
case FP_CLS_INF: \
- if (rsigned) \
+ if (rsigned == 2) \
+ { \
+ if (X##_c != FP_CLS_NORMAL \
+ || X##_e >= rsize - 1 + _FP_WFRACBITS_##fs) \
+ r = 0; \
+ else \
+ { \
+ _FP_FRAC_SLL_##wc(X, (X##_e - _FP_WFRACBITS_##fs + 1)); \
+ _FP_FRAC_ASSEMBLE_##wc(r, X, rsize); \
+ } \
+ } \
+ else if (rsigned) \
{ \
r = 1; \
r <<= rsize - 1; \
r -= 1 - X##_s; \
- } else { \
+ } \
+ else \
+ { \
r = 0; \
if (X##_s) \
r = ~r; \
} \
} while (0)
+#define _FP_TO_INT_ROUND(fs, wc, r, X, rsize, rsigned) \
+ do { \
+ r = 0; \
+ switch (X##_c) \
+ { \
+ case FP_CLS_NORMAL: \
+ if (X##_e >= _FP_FRACBITS_##fs - 1) \
+ { \
+ if (X##_e < rsize - 1 + _FP_WFRACBITS_##fs) \
+ { \
+ if (X##_e >= _FP_WFRACBITS_##fs - 1) \
+ { \
+ _FP_FRAC_ASSEMBLE_##wc(r, X, rsize); \
+ r <<= X##_e - _FP_WFRACBITS_##fs + 1; \
+ } \
+ else \
+ { \
+ _FP_FRAC_SRL_##wc(X, _FP_WORKBITS - X##_e \
+ + _FP_FRACBITS_##fs - 1); \
+ _FP_FRAC_ASSEMBLE_##wc(r, X, rsize); \
+ } \
+ } \
+ } \
+ else \
+ { \
+ if (X##_e <= -_FP_WORKBITS - 1) \
+ _FP_FRAC_SET_##wc(X, _FP_MINFRAC_##wc); \
+ else \
+ _FP_FRAC_SRS_##wc(X, _FP_FRACBITS_##fs - 1 - X##_e, \
+ _FP_WFRACBITS_##fs); \
+ _FP_ROUND(wc, X); \
+ _FP_FRAC_SRL_##wc(X, _FP_WORKBITS); \
+ _FP_FRAC_ASSEMBLE_##wc(r, X, rsize); \
+ } \
+ if (rsigned && X##_s) \
+ r = -r; \
+ if (X##_e >= rsize - (rsigned > 0 || X##_s) \
+ || (!rsigned && X##_s)) \
+ { /* overflow */ \
+ case FP_CLS_NAN: \
+ case FP_CLS_INF: \
+ if (!rsigned) \
+ { \
+ r = 0; \
+ if (X##_s) \
+ r = ~r; \
+ } \
+ else if (rsigned != 2) \
+ { \
+ r = 1; \
+ r <<= rsize - 1; \
+ r -= 1 - X##_s; \
+ } \
+ FP_SET_EXCEPTION(FP_EX_INVALID); \
+ } \
+ break; \
+ case FP_CLS_ZERO: \
+ break; \
+ } \
+ } while (0)
+
#define _FP_FROM_INT(fs, wc, X, r, rsize, rtype) \
do { \
if (r) \
#define FP_CMP_EQ_Q(r,X,Y) _FP_CMP_EQ(Q,4,r,X,Y)
#define FP_TO_INT_Q(r,X,rsz,rsg) _FP_TO_INT(Q,4,r,X,rsz,rsg)
+#define FP_TO_INT_ROUND_Q(r,X,rsz,rsg) _FP_TO_INT_ROUND(Q,4,r,X,rsz,rsg)
#define FP_FROM_INT_Q(X,r,rs,rt) _FP_FROM_INT(Q,4,X,r,rs,rt)
#define _FP_FRAC_HIGH_Q(X) _FP_FRAC_HIGH_4(X)
#define FP_CMP_EQ_Q(r,X,Y) _FP_CMP_EQ(Q,2,r,X,Y)
#define FP_TO_INT_Q(r,X,rsz,rsg) _FP_TO_INT(Q,2,r,X,rsz,rsg)
+#define FP_TO_INT_ROUND_Q(r,X,rsz,rsg) _FP_TO_INT_ROUND(Q,2,r,X,rsz,rsg)
#define FP_FROM_INT_Q(X,r,rs,rt) _FP_FROM_INT(Q,2,X,r,rs,rt)
#define _FP_FRAC_HIGH_Q(X) _FP_FRAC_HIGH_2(X)
#define FP_CMP_EQ_S(r,X,Y) _FP_CMP_EQ(S,1,r,X,Y)
#define FP_TO_INT_S(r,X,rsz,rsg) _FP_TO_INT(S,1,r,X,rsz,rsg)
+#define FP_TO_INT_ROUND_S(r,X,rsz,rsg) _FP_TO_INT_ROUND(S,1,r,X,rsz,rsg)
#define FP_FROM_INT_S(X,r,rs,rt) _FP_FROM_INT(S,1,X,r,rs,rt)
#define _FP_FRAC_HIGH_S(X) _FP_FRAC_HIGH_1(X)
#ifndef SOFT_FP_H
#define SOFT_FP_H
-#include "sfp-machine.h"
+#include <asm/sfp-machine.h>
/* Allow sfp-machine to have its own byte order definitions. */
#ifndef __BYTE_ORDER
#define FP_HANDLE_EXCEPTIONS do {} while (0)
#endif
+/* By default we never flush denormal input operands to signed zero. */
+#ifndef FP_DENORM_ZERO
+#define FP_DENORM_ZERO 0
+#endif
+
#ifndef FP_INHIBIT_RESULTS
/* By default we write the results always.
* sfp-machine may override this and e.g.
extern struct display_switch fbcon_dummy;
+ /*
+ * This is the interface between the low-level console driver and the
+ * low-level frame buffer device
+ */
+
+struct display {
+ /* Filled in by the frame buffer device */
+
+ struct fb_var_screeninfo var; /* variable infos. yoffset and vmode */
+ /* are updated by fbcon.c */
+ struct fb_cmap cmap; /* colormap */
+ char *screen_base; /* pointer to top of virtual screen */
+ /* (virtual address) */
+ int visual;
+ int type; /* see FB_TYPE_* */
+ int type_aux; /* Interleave for interleaved Planes */
+ u_short ypanstep; /* zero if no hardware ypan */
+ u_short ywrapstep; /* zero if no hardware ywrap */
+ u_long line_length; /* length of a line in bytes */
+ u_short can_soft_blank; /* zero if no hardware blanking */
+ u_short inverse; /* != 0 text black on white as default */
+ struct display_switch *dispsw; /* low level operations */
+ void *dispsw_data; /* optional dispsw helper data */
+
+#if 0
+ struct fb_fix_cursorinfo fcrsr;
+ struct fb_var_cursorinfo *vcrsr;
+ struct fb_cursorstate crsrstate;
+#endif
+
+ /* Filled in by the low-level console driver */
+
+ struct vc_data *conp; /* pointer to console data */
+ struct fb_info *fb_info; /* frame buffer for this console */
+ int vrows; /* number of virtual rows */
+ unsigned short cursor_x; /* current cursor position */
+ unsigned short cursor_y;
+ int fgcol; /* text colors */
+ int bgcol;
+ u_long next_line; /* offset to one line below */
+ u_long next_plane; /* offset to next plane */
+ u_char *fontdata; /* Font associated to this display */
+ unsigned short _fontheightlog;
+ unsigned short _fontwidthlog;
+ unsigned short _fontheight;
+ unsigned short _fontwidth;
+ int userfont; /* != 0 if fontdata kmalloc()ed */
+ u_short scrollmode; /* Scroll Method */
+ short yscroll; /* Hardware scrolling */
+ unsigned char fgshift, bgshift;
+ unsigned short charmask; /* 0xff or 0x1ff */
+};
+
+/* drivers/video/fbcon.c */
+extern struct display fb_display[MAX_NR_CONSOLES];
+extern char con2fb_map[MAX_NR_CONSOLES];
+extern int PROC_CONSOLE(const struct fb_info *info);
+extern void set_con2fb_map(int unit, int newidx);
+extern int set_all_vcs(int fbidx, struct fb_ops *fb,
+ struct fb_var_screeninfo *var, struct fb_info *info);
+
#define fontheight(p) ((p)->_fontheight)
#define fontheightlog(p) ((p)->_fontheightlog)
__free_page (pte_page(pte));
rss++;
} else {
- lock_kernel();
swap_free(pte_to_swp_entry(pte));
- unlock_kernel();
swp++;
}
}
}
delete_from_swap_cache(page);
page = replace_with_highmem(page);
- lock_kernel();
swap_free(entry);
- unlock_kernel();
if(shp != shm_lock(shp->id))
BUG();
shm_swp--;
if (--counter < 0) { /* failed */
failed:
shm_unlockall();
- lock_kernel();
__swap_free(swap_entry, 2);
- unlock_kernel();
return 0;
}
if (page_count(page_map) != 1)
*/
static int pkmap_count[LAST_PKMAP];
static unsigned int last_pkmap_nr = 0;
-static spinlock_t kmap_lock;
+static spinlock_t kmap_lock = SPIN_LOCK_UNLOCKED;
pte_t * pkmap_page_table;
*/
void swapin_readahead(swp_entry_t entry)
{
- int i;
+ int i, num;
struct page *new_page;
- unsigned long offset = SWP_OFFSET(entry);
- struct swap_info_struct *swapdev = SWP_TYPE(entry) + swap_info;
-
- offset = (offset >> page_cluster) << page_cluster;
+ unsigned long offset;
- i = 1 << page_cluster;
- do {
- /* Don't read-ahead past the end of the swap area */
- if (offset >= swapdev->max)
- break;
+ /*
+ * Get the number of handles we should do readahead io to. Also,
+ * grab temporary references on them, releasing them as io completes.
+ */
+ num = valid_swaphandles(entry, &offset);
+ for (i = 0; i < num; offset++, i++) {
/* Don't block on I/O for read-ahead */
- if (atomic_read(&nr_async_pages) >= pager_daemon.swap_cluster)
+ if (atomic_read(&nr_async_pages) >= pager_daemon.swap_cluster) {
+ while (i++ < num)
+ swap_free(SWP_ENTRY(SWP_TYPE(entry), offset++));
break;
- /* Don't read in bad or busy pages */
- if (!swapdev->swap_map[offset])
- break;
- if (swapdev->swap_map[offset] == SWAP_MAP_BAD)
- break;
-
+ }
/* Ok, do the async read-ahead now */
new_page = read_swap_cache_async(SWP_ENTRY(SWP_TYPE(entry), offset), 0);
if (new_page != NULL)
__free_page(new_page);
- offset++;
- } while (--i);
+ swap_free(SWP_ENTRY(SWP_TYPE(entry), offset));
+ }
return;
}
vma->vm_mm->rss++;
tsk->min_flt++;
- lock_kernel();
swap_free(entry);
- unlock_kernel();
pte = mk_pte(page, vma->vm_page_prot);
static int rw_swap_page_base(int rw, swp_entry_t entry, struct page *page, int wait)
{
- unsigned long type, offset;
- struct swap_info_struct * p;
+ unsigned long offset;
int zones[PAGE_SIZE/512];
int zones_used;
kdev_t dev = 0;
int block_size;
-
- type = SWP_TYPE(entry);
- if (type >= nr_swapfiles) {
- printk("Internal error: bad swap-device\n");
- return 0;
- }
+ struct inode *swapf = 0;
/* Don't allow too many pending pages in flight.. */
if (atomic_read(&nr_async_pages) > pager_daemon.swap_cluster)
wait = 1;
- p = &swap_info[type];
- offset = SWP_OFFSET(entry);
- if (offset >= p->max) {
- printk("rw_swap_page: weirdness\n");
- return 0;
- }
- if (p->swap_map && !p->swap_map[offset]) {
- printk("VM: Bad swap entry %08lx\n", entry.val);
- return 0;
- }
- if (!(p->flags & SWP_USED)) {
- printk(KERN_ERR "rw_swap_page: "
- "Trying to swap to unused swap-device\n");
- return 0;
- }
-
if (rw == READ) {
ClearPageUptodate(page);
kstat.pswpin++;
} else
kstat.pswpout++;
- if (p->swap_device) {
+ get_swaphandle_info(entry, &offset, &dev, &swapf);
+ if (dev) {
zones[0] = offset;
zones_used = 1;
- dev = p->swap_device;
block_size = PAGE_SIZE;
- } else if (p->swap_file) {
- struct inode *swapf = p->swap_file->d_inode;
- int i;
- int j;
+ } else if (swapf) {
+ int i, j;
unsigned int block = offset
<< (PAGE_SHIFT - swapf->i_sb->s_blocksize_bits);
zones_used = i;
dev = swapf->i_dev;
} else {
- printk(KERN_ERR "rw_swap_page: no swap file or device\n");
return 0;
}
if (!wait) {
add_to_page_cache(page, &swapper_space, entry.val);
}
-/*
- * Verify that a swap entry is valid and increment its swap map count.
- *
- * Note: if swap_map[] reaches SWAP_MAP_MAX the entries are treated as
- * "permanent", but will be reclaimed by the next swapoff.
- */
-int swap_duplicate(swp_entry_t entry)
-{
- struct swap_info_struct * p;
- unsigned long offset, type;
- int result = 0;
-
- /* Swap entry 0 is illegal */
- if (!entry.val)
- goto out;
- type = SWP_TYPE(entry);
- if (type >= nr_swapfiles)
- goto bad_file;
- p = type + swap_info;
- offset = SWP_OFFSET(entry);
- if (offset >= p->max)
- goto bad_offset;
- if (!p->swap_map[offset])
- goto bad_unused;
- /*
- * Entry is valid, so increment the map count.
- */
- if (p->swap_map[offset] < SWAP_MAP_MAX)
- p->swap_map[offset]++;
- else {
- static int overflow = 0;
- if (overflow++ < 5)
- printk("VM: swap entry overflow\n");
- p->swap_map[offset] = SWAP_MAP_MAX;
- }
- result = 1;
-out:
- return result;
-
-bad_file:
- printk("Bad swap file entry %08lx\n", entry.val);
- goto out;
-bad_offset:
- printk("Bad swap offset entry %08lx\n", entry.val);
- goto out;
-bad_unused:
- printk("Unused swap offset entry %08lx\n", entry.val);
- goto out;
-}
-
-int swap_count(struct page *page)
-{
- struct swap_info_struct * p;
- unsigned long offset, type;
- swp_entry_t entry;
- int retval = 0;
-
- entry.val = page->index;
- if (!entry.val)
- goto bad_entry;
- type = SWP_TYPE(entry);
- if (type >= nr_swapfiles)
- goto bad_file;
- p = type + swap_info;
- offset = SWP_OFFSET(entry);
- if (offset >= p->max)
- goto bad_offset;
- if (!p->swap_map[offset])
- goto bad_unused;
- retval = p->swap_map[offset];
-out:
- return retval;
-
-bad_entry:
- printk(KERN_ERR "swap_count: null entry!\n");
- goto out;
-bad_file:
- printk("Bad swap file entry %08lx\n", entry.val);
- goto out;
-bad_offset:
- printk("Bad swap offset entry %08lx\n", entry.val);
- goto out;
-bad_unused:
- printk("Unused swap offset entry %08lx\n", entry.val);
- goto out;
-}
-
static inline void remove_from_swap_cache(struct page *page)
{
struct address_space *mapping = page->mapping;
swap_cache_del_total++;
#endif
remove_from_swap_cache(page);
- lock_kernel();
swap_free(entry);
- unlock_kernel();
}
static void delete_from_swap_cache_nolock(struct page *page)
#include <asm/pgtable.h>
+spinlock_t swaplock = SPIN_LOCK_UNLOCKED;
unsigned int nr_swapfiles = 0;
struct swap_list_t swap_list = {-1, -1};
int type, wrapped = 0;
entry.val = 0; /* Out of memory */
+ if (count >= SWAP_MAP_MAX)
+ goto bad_count;
+ swap_list_lock();
type = swap_list.next;
if (type < 0)
goto out;
if (nr_swap_pages == 0)
goto out;
- if (count >= SWAP_MAP_MAX)
- goto bad_count;
while (1) {
p = &swap_info[type];
if ((p->flags & SWP_WRITEOK) == SWP_WRITEOK) {
+ swap_device_lock(p);
offset = scan_swap_map(p, count);
+ swap_device_unlock(p);
if (offset) {
+ int curtp = type;
+
entry = SWP_ENTRY(type,offset);
type = swap_info[type].next;
if (type < 0 ||
p->prio != swap_info[type].prio) {
- swap_list.next = swap_list.head;
+ swap_list.next = curtp;
} else {
swap_list.next = type;
}
goto out; /* out of swap space */
}
out:
+ swap_list_unlock();
return entry;
bad_count:
}
+/*
+ * Caller has made sure that the swapdevice corresponding to entry
+ * is still around or has not been recycled.
+ */
void __swap_free(swp_entry_t entry, unsigned short count)
{
struct swap_info_struct * p;
p = & swap_info[type];
if (!(p->flags & SWP_USED))
goto bad_device;
- if (p->prio > swap_info[swap_list.next].prio)
- swap_list.next = swap_list.head;
offset = SWP_OFFSET(entry);
if (offset >= p->max)
goto bad_offset;
if (!p->swap_map[offset])
goto bad_free;
+ swap_list_lock();
+ if (p->prio > swap_info[swap_list.next].prio)
+ swap_list.next = type;
+ swap_device_lock(p);
if (p->swap_map[offset] < SWAP_MAP_MAX) {
if (p->swap_map[offset] < count)
goto bad_count;
nr_swap_pages++;
}
}
+ swap_device_unlock(p);
+ swap_list_unlock();
out:
return;
printk("VM: Bad swap entry %08lx\n", entry.val);
goto out;
bad_count:
+ swap_device_unlock(p);
+ swap_list_unlock();
printk(KERN_ERR "VM: Bad count %hd current count %hd\n", count, p->swap_map[offset]);
goto out;
}
if (offset >= p->max)
goto new_swap_entry;
/* Has it been re-used for something else? */
+ swap_list_lock();
+ swap_device_lock(p);
if (p->swap_map[offset])
- goto new_swap_entry;
+ goto unlock_new_swap_entry;
/* We're cool, we can just use the old one */
p->swap_map[offset] = 1;
+ swap_device_unlock(p);
nr_swap_pages--;
+ swap_list_unlock();
return entry;
+unlock_new_swap_entry:
+ swap_device_unlock(p);
+ swap_list_unlock();
new_swap_entry:
return get_swap_page();
}
/*
* Find a swap page in use and read it in.
*/
+ swap_device_lock(si);
for (i = 1; i < si->max ; i++) {
if (si->swap_map[i] > 0 && si->swap_map[i] != SWAP_MAP_BAD) {
+ /*
+ * Prevent swaphandle from being completely
+ * unused by swap_free while we are trying
+ * to read in the page - this prevents warning
+ * messages from rw_swap_page_base.
+ */
+ if (si->swap_map[i] != SWAP_MAP_MAX)
+ si->swap_map[i]++;
+ swap_device_unlock(si);
goto found_entry;
}
}
+ swap_device_unlock(si);
break;
found_entry:
page and read the swap into it. */
page = read_swap_cache(entry);
if (!page) {
- /*
- * Continue searching if the entry became unused.
- */
- if (si->swap_map[i] == 0)
- continue;
+ swap_free(entry);
return -ENOMEM;
}
read_lock(&tasklist_lock);
/*
* Check for and clear any overflowed swap map counts.
*/
- if (si->swap_map[i] != 0) {
+ swap_free(entry);
+ swap_list_lock();
+ swap_device_lock(si);
+ if (si->swap_map[i] > 0) {
if (si->swap_map[i] != SWAP_MAP_MAX)
- printk("VM: Undead swap entry %08lx\n", entry.val);
- si->swap_map[i] = 0;
+ printk("VM: Undead swap entry %08lx\n",
+ entry.val);
nr_swap_pages++;
+ si->swap_map[i] = 0;
}
+ swap_device_unlock(si);
+ swap_list_unlock();
}
return 0;
}
goto out;
prev = -1;
+ swap_list_lock();
for (type = swap_list.head; type >= 0; type = swap_info[type].next) {
p = swap_info + type;
if ((p->flags & SWP_WRITEOK) == SWP_WRITEOK) {
prev = type;
}
err = -EINVAL;
- if (type < 0)
+ if (type < 0) {
+ swap_list_unlock();
goto out_dput;
+ }
if (prev < 0) {
swap_list.head = p->next;
/* just pick something that's safe... */
swap_list.next = swap_list.head;
}
+ nr_swap_pages -= p->pages;
+ swap_list_unlock();
p->flags = SWP_USED;
err = try_to_unuse(type);
if (err) {
/* re-insert swap space back into swap_list */
+ swap_list_lock();
for (prev = -1, i = swap_list.head; i >= 0; prev = i, i = swap_info[i].next)
if (p->prio >= swap_info[i].prio)
break;
swap_list.head = swap_list.next = p - swap_info;
else
swap_info[prev].next = p - swap_info;
+ nr_swap_pages += p->pages;
+ swap_list_unlock();
p->flags = SWP_WRITEOK;
goto out_dput;
}
dentry = p->swap_file;
p->swap_file = NULL;
- nr_swap_pages -= p->pages;
p->swap_device = 0;
vfree(p->swap_map);
p->swap_map = NULL;
p->lowest_bit = 0;
p->highest_bit = 0;
p->cluster_nr = 0;
+ p->sdev_lock = SPIN_LOCK_UNLOCKED;
p->max = 1;
p->next = -1;
if (swap_flags & SWAP_FLAG_PREFER) {
p->swap_map[0] = SWAP_MAP_BAD;
p->flags = SWP_WRITEOK;
p->pages = nr_good_pages;
+ swap_list_lock();
nr_swap_pages += nr_good_pages;
printk(KERN_INFO "Adding Swap: %dk swap-space (priority %d)\n",
nr_good_pages<<(PAGE_SHIFT-10), p->prio);
} else {
swap_info[prev].next = p - swap_info;
}
+ swap_list_unlock();
error = 0;
goto out;
bad_swap:
val->totalswap = totalswap;
return;
}
+
+/*
+ * Verify that a swap entry is valid and increment its swap map count.
+ * Kernel_lock is held, which guarantees existance of swap device.
+ *
+ * Note: if swap_map[] reaches SWAP_MAP_MAX the entries are treated as
+ * "permanent", but will be reclaimed by the next swapoff.
+ */
+int swap_duplicate(swp_entry_t entry)
+{
+ struct swap_info_struct * p;
+ unsigned long offset, type;
+ int result = 0;
+
+ /* Swap entry 0 is illegal */
+ if (!entry.val)
+ goto out;
+ type = SWP_TYPE(entry);
+ if (type >= nr_swapfiles)
+ goto bad_file;
+ p = type + swap_info;
+ offset = SWP_OFFSET(entry);
+ if (offset >= p->max)
+ goto bad_offset;
+ if (!p->swap_map[offset])
+ goto bad_unused;
+ /*
+ * Entry is valid, so increment the map count.
+ */
+ swap_device_lock(p);
+ if (p->swap_map[offset] < SWAP_MAP_MAX)
+ p->swap_map[offset]++;
+ else {
+ static int overflow = 0;
+ if (overflow++ < 5)
+ printk("VM: swap entry overflow\n");
+ p->swap_map[offset] = SWAP_MAP_MAX;
+ }
+ swap_device_unlock(p);
+ result = 1;
+out:
+ return result;
+
+bad_file:
+ printk("Bad swap file entry %08lx\n", entry.val);
+ goto out;
+bad_offset:
+ printk("Bad swap offset entry %08lx\n", entry.val);
+ goto out;
+bad_unused:
+ printk("Unused swap offset entry in swap_dup %08lx\n", entry.val);
+ goto out;
+}
+
+/*
+ * Page lock needs to be held in all cases to prevent races with
+ * swap file deletion.
+ */
+int swap_count(struct page *page)
+{
+ struct swap_info_struct * p;
+ unsigned long offset, type;
+ swp_entry_t entry;
+ int retval = 0;
+
+ entry.val = page->index;
+ if (!entry.val)
+ goto bad_entry;
+ type = SWP_TYPE(entry);
+ if (type >= nr_swapfiles)
+ goto bad_file;
+ p = type + swap_info;
+ offset = SWP_OFFSET(entry);
+ if (offset >= p->max)
+ goto bad_offset;
+ if (!p->swap_map[offset])
+ goto bad_unused;
+ retval = p->swap_map[offset];
+out:
+ return retval;
+
+bad_entry:
+ printk(KERN_ERR "swap_count: null entry!\n");
+ goto out;
+bad_file:
+ printk("Bad swap file entry %08lx\n", entry.val);
+ goto out;
+bad_offset:
+ printk("Bad swap offset entry %08lx\n", entry.val);
+ goto out;
+bad_unused:
+ printk("Unused swap offset entry in swap_count %08lx\n", entry.val);
+ goto out;
+}
+
+/*
+ * Kernel_lock protects against swap device deletion.
+ */
+void get_swaphandle_info(swp_entry_t entry, unsigned long *offset,
+ kdev_t *dev, struct inode **swapf)
+{
+ unsigned long type;
+ struct swap_info_struct *p;
+
+ type = SWP_TYPE(entry);
+ if (type >= nr_swapfiles) {
+ printk("Internal error: bad swap-device\n");
+ return;
+ }
+
+ p = &swap_info[type];
+ *offset = SWP_OFFSET(entry);
+ if (*offset >= p->max) {
+ printk("rw_swap_page: weirdness\n");
+ return;
+ }
+ if (p->swap_map && !p->swap_map[*offset]) {
+ printk("VM: Bad swap entry %08lx\n", entry.val);
+ return;
+ }
+ if (!(p->flags & SWP_USED)) {
+ printk(KERN_ERR "rw_swap_page: "
+ "Trying to swap to unused swap-device\n");
+ return;
+ }
+
+ if (p->swap_device) {
+ *dev = p->swap_device;
+ } else if (p->swap_file) {
+ *swapf = p->swap_file->d_inode;
+ } else {
+ printk(KERN_ERR "rw_swap_page: no swap file or device\n");
+ }
+ return;
+}
+
+/*
+ * Kernel_lock protects against swap device deletion. Grab an extra
+ * reference on the swaphandle so that it dos not become unused.
+ */
+int valid_swaphandles(swp_entry_t entry, unsigned long *offset)
+{
+ int ret = 0, i = 1 << page_cluster;
+ unsigned long toff;
+ struct swap_info_struct *swapdev = SWP_TYPE(entry) + swap_info;
+
+ *offset = SWP_OFFSET(entry);
+ toff = *offset = (*offset >> page_cluster) << page_cluster;
+
+ swap_device_lock(swapdev);
+ do {
+ /* Don't read-ahead past the end of the swap area */
+ if (toff >= swapdev->max)
+ break;
+ /* Don't read in bad or busy pages */
+ if (!swapdev->swap_map[toff])
+ break;
+ if (swapdev->swap_map[toff] == SWAP_MAP_BAD)
+ break;
+ swapdev->swap_map[toff]++;
+ toff++;
+ ret++;
+ } while (--i);
+ swap_device_unlock(swapdev);
+ return ret;
+}