summaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-02-05 06:47:02 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-02-05 06:47:02 +0000
commit99a7e12f34b3661a0d1354eef83a0eef4df5e34c (patch)
tree3560aca9ca86792f9ab7bd87861ea143a1b3c7a3 /arch
parente73a04659c0b8cdee4dd40e58630e2cf63afb316 (diff)
Merge with Linux 2.3.38.
Diffstat (limited to 'arch')
-rw-r--r--arch/alpha/Makefile22
-rw-r--r--arch/alpha/boot/Makefile4
-rw-r--r--arch/alpha/kernel/alpha_ksyms.c6
-rw-r--r--arch/alpha/kernel/core_irongate.c1
-rw-r--r--arch/alpha/kernel/core_mcpcia.c31
-rw-r--r--arch/alpha/kernel/entry.S10
-rw-r--r--arch/alpha/kernel/head.S18
-rw-r--r--arch/alpha/kernel/osf_sys.c182
-rw-r--r--arch/alpha/kernel/pci.c21
-rw-r--r--arch/alpha/kernel/sys_nautilus.c43
-rw-r--r--arch/alpha/kernel/sys_sio.c2
-rw-r--r--arch/alpha/lib/Makefile8
-rw-r--r--arch/alpha/mm/init.c1
-rw-r--r--arch/arm/boot/compressed/Makefile6
-rw-r--r--arch/arm/kernel/Makefile2
-rw-r--r--arch/arm/kernel/bios32.c5
-rw-r--r--arch/arm/kernel/calls.S11
-rw-r--r--arch/i386/boot/Makefile8
-rw-r--r--arch/i386/boot/compressed/Makefile2
-rw-r--r--arch/i386/boot/compressed/head.S4
-rw-r--r--arch/i386/boot/setup.S4
-rw-r--r--arch/i386/config.in11
-rw-r--r--arch/i386/defconfig24
-rw-r--r--arch/i386/kernel/Makefile4
-rw-r--r--arch/i386/kernel/acpi.c1344
-rw-r--r--arch/i386/kernel/apm.c150
-rw-r--r--arch/i386/kernel/entry.S17
-rw-r--r--arch/i386/kernel/head.S26
-rw-r--r--arch/i386/kernel/i386_ksyms.c3
-rw-r--r--arch/i386/kernel/irq.c46
-rw-r--r--arch/i386/kernel/mtrr.c32
-rw-r--r--arch/i386/kernel/pci-i386.c60
-rw-r--r--arch/i386/kernel/pci-pc.c98
-rw-r--r--arch/i386/kernel/pci-visws.c4
-rw-r--r--arch/i386/kernel/process.c114
-rw-r--r--arch/i386/kernel/setup.c17
-rw-r--r--arch/i386/kernel/smp.c8
-rw-r--r--arch/i386/kernel/vm86.c2
-rw-r--r--arch/i386/math-emu/Makefile2
-rw-r--r--arch/m68k/atari/stram.c15
-rw-r--r--arch/m68k/fpsp040/Makefile2
-rw-r--r--arch/m68k/ifpsp060/Makefile2
-rw-r--r--arch/m68k/kernel/Makefile2
-rw-r--r--arch/m68k/kernel/bios32.c65
-rw-r--r--arch/m68k/lib/Makefile2
-rw-r--r--arch/m68k/math-emu/Makefile2
-rw-r--r--arch/m68k/sun3/Makefile2
-rw-r--r--arch/m68k/sun3/prom/Makefile2
-rw-r--r--arch/mips/config.in4
-rw-r--r--arch/mips/dec/prom/Makefile4
-rw-r--r--arch/mips/defconfig21
-rw-r--r--arch/mips/defconfig-ip2273
-rw-r--r--arch/mips/kernel/signal.c4
-rw-r--r--arch/mips/kernel/syscalls.h5
-rw-r--r--arch/mips/kernel/sysirix.c4
-rw-r--r--arch/mips/kernel/sysmips.c4
-rw-r--r--arch/mips/lib/csum_partial_copy.c19
-rw-r--r--arch/mips/sgi/kernel/Makefile4
-rw-r--r--arch/mips/sni/pci.c4
-rw-r--r--arch/mips64/config.in4
-rw-r--r--arch/mips64/defconfig21
-rw-r--r--arch/mips64/defconfig-ip2214
-rw-r--r--arch/mips64/defconfig-ip2721
-rw-r--r--arch/mips64/kernel/scall_o32.S8
-rw-r--r--arch/mips64/lib/csum_partial_copy.c19
-rw-r--r--arch/ppc/Makefile4
-rw-r--r--arch/ppc/boot/Makefile8
-rw-r--r--arch/ppc/chrpboot/Makefile8
-rw-r--r--arch/ppc/coffboot/Makefile2
-rw-r--r--arch/ppc/config.in8
-rw-r--r--arch/ppc/kernel/chrp_pci.c3
-rw-r--r--arch/ppc/kernel/chrp_setup.c8
-rw-r--r--arch/ppc/kernel/gemini_setup.c13
-rw-r--r--arch/ppc/kernel/irq.c7
-rw-r--r--arch/ppc/kernel/local_irq.h2
-rw-r--r--arch/ppc/kernel/m8xx_setup.c4
-rw-r--r--arch/ppc/kernel/mbx_pci.c269
-rw-r--r--arch/ppc/kernel/mbx_setup.c486
-rw-r--r--arch/ppc/kernel/open_pic.c49
-rw-r--r--arch/ppc/kernel/open_pic.h1
-rw-r--r--arch/ppc/kernel/pci.c16
-rw-r--r--arch/ppc/kernel/pmac_pci.c2
-rw-r--r--arch/ppc/kernel/pmac_pic.c8
-rw-r--r--arch/ppc/kernel/pmac_setup.c24
-rw-r--r--arch/ppc/kernel/ppc_ksyms.c3
-rw-r--r--arch/ppc/kernel/prep_pci.c5
-rw-r--r--arch/ppc/kernel/prep_setup.c4
-rw-r--r--arch/ppc/kernel/process.c9
-rw-r--r--arch/ppc/kernel/smp.c174
-rw-r--r--arch/ppc/lib/Makefile2
-rw-r--r--arch/ppc/mbxboot/Makefile8
-rw-r--r--arch/ppc/mm/init.c51
-rw-r--r--arch/sparc/ap1000/Makefile4
-rw-r--r--arch/sparc/config.in19
-rw-r--r--arch/sparc/defconfig24
-rw-r--r--arch/sparc/kernel/Makefile22
-rw-r--r--arch/sparc/kernel/auxio.c21
-rw-r--r--arch/sparc/kernel/ebus.c67
-rw-r--r--arch/sparc/kernel/entry.S80
-rw-r--r--arch/sparc/kernel/head.S26
-rw-r--r--arch/sparc/kernel/ioport.c572
-rw-r--r--arch/sparc/kernel/irq.c5
-rw-r--r--arch/sparc/kernel/pcic.c594
-rw-r--r--arch/sparc/kernel/process.c41
-rw-r--r--arch/sparc/kernel/semaphore.c119
-rw-r--r--arch/sparc/kernel/setup.c72
-rw-r--r--arch/sparc/kernel/signal.c3
-rw-r--r--arch/sparc/kernel/smp.c3
-rw-r--r--arch/sparc/kernel/sparc-stub.c3
-rw-r--r--arch/sparc/kernel/sparc_ksyms.c41
-rw-r--r--arch/sparc/kernel/sun4c_irq.c32
-rw-r--r--arch/sparc/kernel/sun4d_irq.c28
-rw-r--r--arch/sparc/kernel/sun4d_smp.c9
-rw-r--r--arch/sparc/kernel/sun4m_irq.c43
-rw-r--r--arch/sparc/kernel/sun4m_smp.c9
-rw-r--r--arch/sparc/kernel/sys_solaris.c16
-rw-r--r--arch/sparc/kernel/sys_sparc.c52
-rw-r--r--arch/sparc/kernel/sys_sunos.c35
-rw-r--r--arch/sparc/kernel/systbls.S19
-rw-r--r--arch/sparc/kernel/time.c39
-rw-r--r--arch/sparc/lib/Makefile84
-rw-r--r--arch/sparc/lib/ashldi3.S36
-rw-r--r--arch/sparc/lib/ashrdi3.S6
-rw-r--r--arch/sparc/lib/rwsem.S191
-rw-r--r--arch/sparc/lib/strlen_user.S21
-rw-r--r--arch/sparc/math-emu/Makefile4
-rw-r--r--arch/sparc/mm/Makefile7
-rw-r--r--arch/sparc/mm/asyncd.c3
-rw-r--r--arch/sparc/mm/btfixup.c3
-rw-r--r--arch/sparc/mm/fault.c37
-rw-r--r--arch/sparc/mm/generic.c32
-rw-r--r--arch/sparc/mm/init.c430
-rw-r--r--arch/sparc/mm/io-unit.c58
-rw-r--r--arch/sparc/mm/iommu.c104
-rw-r--r--arch/sparc/mm/nosrmmu.c8
-rw-r--r--arch/sparc/mm/srmmu.c387
-rw-r--r--arch/sparc/mm/sun4c.c1285
-rw-r--r--arch/sparc/mm/swift.S275
-rw-r--r--arch/sparc/mm/tsunami.S64
-rw-r--r--arch/sparc/prom/Makefile4
-rw-r--r--arch/sparc/prom/ranges.c47
-rw-r--r--arch/sparc64/Makefile10
-rw-r--r--arch/sparc64/config.in22
-rw-r--r--arch/sparc64/defconfig64
-rw-r--r--arch/sparc64/kernel/Makefile31
-rw-r--r--arch/sparc64/kernel/auxio.c27
-rw-r--r--arch/sparc64/kernel/central.c286
-rw-r--r--arch/sparc64/kernel/devices.c22
-rw-r--r--arch/sparc64/kernel/dtlb_backend.S4
-rw-r--r--arch/sparc64/kernel/ebus.c82
-rw-r--r--arch/sparc64/kernel/entry.S104
-rw-r--r--arch/sparc64/kernel/head.S31
-rw-r--r--arch/sparc64/kernel/ioctl32.c14
-rw-r--r--arch/sparc64/kernel/iommu_common.c233
-rw-r--r--arch/sparc64/kernel/iommu_common.h34
-rw-r--r--arch/sparc64/kernel/ioport.c107
-rw-r--r--arch/sparc64/kernel/irq.c187
-rw-r--r--arch/sparc64/kernel/pci.c62
-rw-r--r--arch/sparc64/kernel/pci_common.c116
-rw-r--r--arch/sparc64/kernel/pci_impl.h4
-rw-r--r--arch/sparc64/kernel/pci_iommu.c616
-rw-r--r--arch/sparc64/kernel/pci_psycho.c72
-rw-r--r--arch/sparc64/kernel/pci_sabre.c152
-rw-r--r--arch/sparc64/kernel/power.c14
-rw-r--r--arch/sparc64/kernel/process.c37
-rw-r--r--arch/sparc64/kernel/sbus.c1145
-rw-r--r--arch/sparc64/kernel/semaphore.c174
-rw-r--r--arch/sparc64/kernel/setup.c89
-rw-r--r--arch/sparc64/kernel/signal.c2
-rw-r--r--arch/sparc64/kernel/signal32.c33
-rw-r--r--arch/sparc64/kernel/smp.c64
-rw-r--r--arch/sparc64/kernel/sparc64_ksyms.c40
-rw-r--r--arch/sparc64/kernel/starfire.c19
-rw-r--r--arch/sparc64/kernel/sys32.S11
-rw-r--r--arch/sparc64/kernel/sys_sparc.c28
-rw-r--r--arch/sparc64/kernel/sys_sparc32.c350
-rw-r--r--arch/sparc64/kernel/sys_sunos32.c29
-rw-r--r--arch/sparc64/kernel/systbls.S22
-rw-r--r--arch/sparc64/kernel/time.c41
-rw-r--r--arch/sparc64/kernel/trampoline.S220
-rw-r--r--arch/sparc64/kernel/traps.c36
-rw-r--r--arch/sparc64/kernel/ttable.S5
-rw-r--r--arch/sparc64/lib/VISmemset.S29
-rw-r--r--arch/sparc64/lib/blockops.S18
-rw-r--r--arch/sparc64/lib/strlen_user.S21
-rw-r--r--arch/sparc64/math-emu/math.c2
-rw-r--r--arch/sparc64/math-emu/sfp-util.h2
-rw-r--r--arch/sparc64/mm/asyncd.c3
-rw-r--r--arch/sparc64/mm/fault.c6
-rw-r--r--arch/sparc64/mm/generic.c32
-rw-r--r--arch/sparc64/mm/init.c1354
-rw-r--r--arch/sparc64/mm/ultra.S38
-rw-r--r--arch/sparc64/prom/Makefile12
-rw-r--r--arch/sparc64/prom/init.c5
-rw-r--r--arch/sparc64/prom/map.S70
-rw-r--r--arch/sparc64/prom/misc.c99
-rw-r--r--arch/sparc64/prom/p1275.c18
-rw-r--r--arch/sparc64/prom/ranges.c192
-rw-r--r--arch/sparc64/solaris/fs.c30
-rw-r--r--arch/sparc64/solaris/ioctl.c94
-rw-r--r--arch/sparc64/solaris/ipc.c3
-rw-r--r--arch/sparc64/solaris/misc.c12
-rw-r--r--arch/sparc64/solaris/socket.c56
-rw-r--r--arch/sparc64/solaris/timod.c2
204 files changed, 9618 insertions, 6061 deletions
diff --git a/arch/alpha/Makefile b/arch/alpha/Makefile
index 28ba0dd51..36f4d4e6d 100644
--- a/arch/alpha/Makefile
+++ b/arch/alpha/Makefile
@@ -29,23 +29,32 @@ ifeq ($(have_mcpu),y)
# the host compiler might have on by default. Given that EV4 and EV5
# have the same instruction set, prefer EV5 because an EV5 schedule is
# more likely to keep an EV4 processor busy than vice-versa.
+ mcpu_done := n
ifeq ($(CONFIG_ALPHA_GENERIC),y)
CFLAGS := $(CFLAGS) -mcpu=ev5
+ mcpu_done := y
endif
- ifeq ($(CONFIG_ALPHA_EV4),y)
- CFLAGS := $(CFLAGS) -mcpu=ev4
- endif
- ifeq ($(CONFIG_ALPHA_PYXIS),y)
+ ifeq ($(mcpu_done)$(CONFIG_ALPHA_PYXIS),ny)
CFLAGS := $(CFLAGS) -mcpu=ev56
+ mcpu_done := y
endif
- ifeq ($(CONFIG_ALPHA_POLARIS),y)
+ ifeq ($(mcpu_done)$(CONFIG_ALPHA_POLARIS),ny)
ifeq ($(have_mcpu_pca56),y)
CFLAGS := $(CFLAGS) -mcpu=pca56
else
CFLAGS := $(CFLAGS) -mcpu=ev56
endif
+ mcpu_done := y
+ endif
+ ifeq ($(mcpu_done)$(CONFIG_ALPHA_NAUTILUS)$(have_mcpu_ev67),nyy)
+ CFLAGS := $(CFLAGS) -mcpu=ev67
+ mcpu_done := y
+ endif
+ ifeq ($(mcpu_done)$(CONFIG_ALPHA_EV4),ny)
+ CFLAGS := $(CFLAGS) -mcpu=ev4
+ mcpu_done := y
endif
- ifeq ($(CONFIG_ALPHA_EV6),y)
+ ifeq ($(mcpu_done)$(CONFIG_ALPHA_EV6),ny)
ifeq ($(have_mcpu_ev6),y)
CFLAGS := $(CFLAGS) -mcpu=ev6
else
@@ -55,6 +64,7 @@ ifeq ($(have_mcpu),y)
CFLAGS := $(CFLAGS) -mcpu=ev56
endif
endif
+ mcpu_done := y
endif
endif
diff --git a/arch/alpha/boot/Makefile b/arch/alpha/boot/Makefile
index ee3460463..ee2ac0ac0 100644
--- a/arch/alpha/boot/Makefile
+++ b/arch/alpha/boot/Makefile
@@ -11,9 +11,9 @@
LINKFLAGS = -static -T bootloader.lds #-N -relax
.S.s:
- $(CC) -D__ASSEMBLY__ -traditional -E -o $*.o $<
+ $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -E -o $*.o $<
.S.o:
- $(CC) -D__ASSEMBLY__ -traditional -c -o $*.o $<
+ $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c -o $*.o $<
OBJECTS = head.o main.o
BPOBJECTS = head.o bootp.o
diff --git a/arch/alpha/kernel/alpha_ksyms.c b/arch/alpha/kernel/alpha_ksyms.c
index ef8be067c..877926974 100644
--- a/arch/alpha/kernel/alpha_ksyms.c
+++ b/arch/alpha/kernel/alpha_ksyms.c
@@ -36,7 +36,6 @@
extern struct hwrpb_struct *hwrpb;
extern void dump_thread(struct pt_regs *, struct user *);
extern int dump_fpu(struct pt_regs *, elf_fpregset_t *);
-extern void ___delay(void);
/* these are C runtime functions with special calling conventions: */
extern void __divl (void);
@@ -151,11 +150,6 @@ EXPORT_SYMBOL_NOVERS(__down_failed);
EXPORT_SYMBOL_NOVERS(__down_failed_interruptible);
EXPORT_SYMBOL_NOVERS(__up_wakeup);
-/*
- * This is called specially from __delay.
- */
-EXPORT_SYMBOL_NOVERS(___delay);
-
/*
* SMP-specific symbols.
*/
diff --git a/arch/alpha/kernel/core_irongate.c b/arch/alpha/kernel/core_irongate.c
index ef686277c..81615dbdf 100644
--- a/arch/alpha/kernel/core_irongate.c
+++ b/arch/alpha/kernel/core_irongate.c
@@ -338,6 +338,7 @@ irongate_init_arch(void)
{
struct pci_controler *hose;
+ IRONGATE0->stat_cmd = IRONGATE0->stat_cmd & ~0x100;
irongate_pci_clr_err();
irongate_register_dump(__FUNCTION__);
diff --git a/arch/alpha/kernel/core_mcpcia.c b/arch/alpha/kernel/core_mcpcia.c
index b4fe28849..4b165940d 100644
--- a/arch/alpha/kernel/core_mcpcia.c
+++ b/arch/alpha/kernel/core_mcpcia.c
@@ -306,7 +306,7 @@ mcpcia_probe_hose(int h)
mb();
draina();
wrmces(7);
- mcheck_expected(cpu) = 1;
+ mcheck_expected(cpu) = 2; /* indicates probing */
mcheck_taken(cpu) = 0;
mcheck_extra(cpu) = mid;
mb();
@@ -415,7 +415,7 @@ mcpcia_startup_hose(struct pci_controler *hose)
#if 0
tmp = *(vuip)MCPCIA_INT_CTL(mid);
- printk("mcpcia_init_arch: INT_CTL was 0x%x\n", tmp);
+ printk("mcpcia_startup_hose: INT_CTL was 0x%x\n", tmp);
*(vuip)MCPCIA_INT_CTL(mid) = 1U;
mb();
tmp = *(vuip)MCPCIA_INT_CTL(mid);
@@ -548,30 +548,37 @@ mcpcia_machine_check(unsigned long vector, unsigned long la_ptr,
struct el_common *mchk_header;
struct el_MCPCIA_uncorrected_frame_mcheck *mchk_logout;
unsigned int cpu = smp_processor_id();
+ int expected;
mchk_header = (struct el_common *)la_ptr;
mchk_logout = (struct el_MCPCIA_uncorrected_frame_mcheck *)la_ptr;
+ expected = mcheck_expected(cpu);
mb();
mb(); /* magic */
draina();
- if (mcheck_expected(cpu)) {
- mcpcia_pci_clr_err(mcheck_extra(cpu));
- } else {
+
+ switch (expected) {
+ case 0:
/* FIXME: how do we figure out which hose the
error was on? */
struct pci_controler *hose;
for (hose = hose_head; hose; hose = hose->next)
mcpcia_pci_clr_err(hose2mid(hose->index));
+ break;
+ case 1:
+ mcpcia_pci_clr_err(mcheck_extra(cpu));
+ break;
+ default:
+ /* Otherwise, we're being called from mcpcia_probe_hose
+ and there's no hose clear an error from. */
+ break;
}
+
wrmces(0x7);
mb();
- if (mcheck_expected(cpu)) {
- process_mcheck_info(vector, la_ptr, regs, "MCPCIA", 1);
- } else {
- process_mcheck_info(vector, la_ptr, regs, "MCPCIA", 0);
- if (vector != 0x620 && vector != 0x630)
- mcpcia_print_uncorrectable(mchk_logout);
- }
+ process_mcheck_info(vector, la_ptr, regs, "MCPCIA", expected != 0);
+ if (!expected && vector != 0x620 && vector != 0x630)
+ mcpcia_print_uncorrectable(mchk_logout);
}
diff --git a/arch/alpha/kernel/entry.S b/arch/alpha/kernel/entry.S
index 1e34d5a33..6b37bd23c 100644
--- a/arch/alpha/kernel/entry.S
+++ b/arch/alpha/kernel/entry.S
@@ -8,7 +8,7 @@
#define SIGCHLD 20
-#define NR_SYSCALLS 373
+#define NR_SYSCALLS 374
/*
* These offsets must match with alpha_mv in <asm/machvec.h>.
@@ -84,8 +84,8 @@
ldq $1,8($30); \
ldq $2,16($30); \
ldq $3,24($30); \
- ldq $20,152($30); \
- ldq $21,HAE_CACHE($19); \
+ ldq $21,152($30); \
+ ldq $20,HAE_CACHE($19); \
ldq $4,32($30); \
ldq $5,40($30); \
ldq $6,48($30); \
@@ -985,7 +985,7 @@ sys_call_table:
.quad osf_utsname
.quad sys_lchown
.quad osf_shmat
- .quad sys_shmctl /* 210 */
+ .quad sys_shmctlold /* 210 */
.quad sys_shmdt
.quad sys_shmget
.quad alpha_ni_syscall
@@ -1149,3 +1149,5 @@ sys_call_table:
.quad sys_sendfile /* 370 */
.quad sys_setresgid
.quad sys_getresgid
+ .quad sys_ni_syscall /* sys_dipc */
+ .quad sys_shmctl
diff --git a/arch/alpha/kernel/head.S b/arch/alpha/kernel/head.S
index e410e2684..3b004b7f6 100644
--- a/arch/alpha/kernel/head.S
+++ b/arch/alpha/kernel/head.S
@@ -95,21 +95,3 @@ halt:
.prologue 0
call_pal PAL_halt
.end halt
-
- #
- # Having the delay loop out of line guarantees that we wont
- # run into weird alignment conditions (on new processors)
- # that vary the speed of the loop.
- #
- .align 5
- .globl ___delay
- .ent ___delay
-___delay:
- .set noat
- .frame $30,0,$28,0
- .prologue 0
-1: subq $0,1,$0
- bge $0,1b
- ret $31,($28),0
- .set at
- .end ___delay
diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c
index e888c91e3..e81687bdb 100644
--- a/arch/alpha/kernel/osf_sys.c
+++ b/arch/alpha/kernel/osf_sys.c
@@ -31,6 +31,8 @@
#include <linux/shm.h>
#include <linux/poll.h>
#include <linux/file.h>
+#include <linux/types.h>
+#include <linux/ipc.h>
#include <asm/fpu.h>
#include <asm/io.h>
@@ -38,16 +40,11 @@
#include <asm/system.h>
#include <asm/sysinfo.h>
#include <asm/hwrpb.h>
+#include <asm/processor.h>
-extern int do_mount(kdev_t, const char *, const char *, char *, int, void *);
+extern int do_mount(struct block_device *, const char *, const char *, char *, int, void *);
extern int do_pipe(int *);
-extern struct file_operations *get_blkfops(unsigned int);
-extern struct file_operations *get_chrfops(unsigned int);
-
-extern kdev_t get_unnamed_dev(void);
-extern void put_unnamed_dev(kdev_t);
-
extern asmlinkage int sys_swapon(const char *specialfile, int swap_flags);
extern asmlinkage unsigned long sys_brk(unsigned long);
@@ -396,18 +393,16 @@ struct procfs_args {
uid_t exroot;
};
-static int getdev(const char *name, int rdonly, struct dentry **dp)
+static struct dentry *getdev(const char *name, int rdonly)
{
- kdev_t dev;
struct dentry *dentry;
struct inode *inode;
- struct file_operations *fops;
int retval;
dentry = namei(name);
retval = PTR_ERR(dentry);
if (IS_ERR(dentry))
- return retval;
+ return dentry;
retval = -ENOTBLK;
inode = dentry->d_inode;
@@ -417,48 +412,20 @@ static int getdev(const char *name, int rdonly, struct dentry **dp)
retval = -EACCES;
if (IS_NODEV(inode))
goto out_dput;
-
- retval = -ENXIO;
- dev = inode->i_rdev;
- if (MAJOR(dev) >= MAX_BLKDEV)
- goto out_dput;
-
- retval = -ENODEV;
- fops = get_blkfops(MAJOR(dev));
- if (!fops)
- goto out_dput;
- if (fops->open) {
- struct file dummy;
- memset(&dummy, 0, sizeof(dummy));
- dummy.f_dentry = dentry;
- dummy.f_mode = rdonly ? 1 : 3;
- retval = fops->open(inode, &dummy);
- if (retval)
- goto out_dput;
- }
- *dp = dentry;
- retval = 0;
-out:
- return retval;
+ return dentry;
out_dput:
dput(dentry);
- goto out;
-}
-
-static void putdev(struct dentry *dentry)
-{
- struct file_operations *fops;
-
- fops = get_blkfops(MAJOR(dentry->d_inode->i_rdev));
- if (fops->release)
- fops->release(dentry->d_inode, NULL);
+ return ERR_PTR(retval);
}
/*
* We can't actually handle ufs yet, so we translate UFS mounts to
* ext2fs mounts. I wouldn't mind a UFS filesystem, but the UFS
* layout is so braindead it's a major headache doing it.
+ *
+ * Just how long ago was it written? OTOH our UFS driver may be still
+ * unhappy with OSF UFS. [CHECKME]
*/
static int osf_ufs_mount(char *dirname, struct ufs_args *args, int flags)
{
@@ -470,13 +437,12 @@ static int osf_ufs_mount(char *dirname, struct ufs_args *args, int flags)
if (copy_from_user(&tmp, args, sizeof(tmp)))
goto out;
- retval = getdev(tmp.devname, 0, &dentry);
- if (retval)
+ dentry = getdev(tmp.devname, 0);
+ retval = PTR_ERR(dentry);
+ if (IS_ERR(dentry)
goto out;
- retval = do_mount(dentry->d_inode->i_rdev, tmp.devname, dirname,
+ retval = do_mount(dentry->d_inode->i_bdev, tmp.devname, dirname,
"ext2", flags, NULL);
- if (retval)
- putdev(dentry);
dput(dentry);
out:
return retval;
@@ -492,13 +458,12 @@ static int osf_cdfs_mount(char *dirname, struct cdfs_args *args, int flags)
if (copy_from_user(&tmp, args, sizeof(tmp)))
goto out;
- retval = getdev(tmp.devname, 1, &dentry);
- if (retval)
+ dentry = getdev(tmp.devname, 1);
+ retval = PTR_ERR(dentry);
+ if (IS_ERR(dentry))
goto out;
- retval = do_mount(dentry->d_inode->i_rdev, tmp.devname, dirname,
+ retval = do_mount(dentry->d_inode->i_bdev, tmp.devname, dirname,
"iso9660", flags, NULL);
- if (retval)
- putdev(dentry);
dput(dentry);
out:
return retval;
@@ -506,19 +471,12 @@ out:
static int osf_procfs_mount(char *dirname, struct procfs_args *args, int flags)
{
- kdev_t dev;
int retval;
struct procfs_args tmp;
if (copy_from_user(&tmp, args, sizeof(tmp)))
return -EFAULT;
- dev = get_unnamed_dev();
- if (!dev)
- return -ENODEV;
- retval = do_mount(dev, "", dirname, "proc", flags, NULL);
- if (retval)
- put_unnamed_dev(dev);
- return retval;
+ return do_mount(NULL, "", dirname, "proc", flags, NULL);
}
asmlinkage int osf_mount(unsigned long typenr, char *path, int flag, void *data)
@@ -1442,3 +1400,103 @@ asmlinkage int sys_old_adjtimex(struct timex32 *txc_p)
return ret;
}
+
+struct shmid_ds_old {
+ struct ipc_perm shm_perm; /* operation perms */
+ int shm_segsz; /* size of segment (bytes) */
+ __kernel_time_t shm_atime; /* last attach time */
+ __kernel_time_t shm_dtime; /* last detach time */
+ __kernel_time_t shm_ctime; /* last change time */
+ __kernel_ipc_pid_t shm_cpid; /* pid of creator */
+ __kernel_ipc_pid_t shm_lpid; /* pid of last operator */
+ unsigned short shm_nattch; /* no. of current attaches */
+ unsigned short shm_unused; /* compatibility */
+ void *shm_unused2; /* ditto - used by DIPC */
+ void *shm_unused3; /* unused */
+};
+
+struct shminfo_old {
+ int shmmax;
+ int shmmin;
+ int shmmni;
+ int shmseg;
+ int shmall;
+};
+
+asmlinkage long sys_shmctlold(int shmid, int cmd, struct shmid_ds_old *buf)
+{
+ struct shmid_ds arg;
+ long ret;
+ mm_segment_t old_fs;
+
+ if (cmd == IPC_SET) {
+ struct shmid_ds_old tbuf;
+
+ if(copy_from_user (&tbuf, buf, sizeof(*buf)))
+ return -EFAULT;
+ arg.shm_perm = tbuf.shm_perm;
+ arg.shm_segsz = tbuf.shm_segsz;
+ arg.shm_atime = tbuf.shm_atime;
+ arg.shm_dtime = tbuf.shm_dtime;
+ arg.shm_ctime = tbuf.shm_ctime;
+ arg.shm_cpid = tbuf.shm_cpid;
+ arg.shm_lpid = tbuf.shm_lpid;
+ arg.shm_nattch = tbuf.shm_nattch;
+ arg.shm_unused = tbuf.shm_unused;
+ arg.shm_unused2 = tbuf.shm_unused2;
+ arg.shm_unused3 = tbuf.shm_unused3;
+ }
+ old_fs = get_fs ();
+ set_fs (KERNEL_DS);
+ ret = sys_shmctl(shmid, cmd, &arg);
+ set_fs (old_fs);
+ if (ret < 0)
+ return(ret);
+ switch(cmd) {
+ case IPC_INFO:
+ {
+ struct shminfo *tbuf = (struct shminfo *) &arg;
+ struct shminfo_old shminfo_oldst;
+
+ shminfo_oldst.shmmax = (tbuf->shmmax > INT_MAX ?
+ INT_MAX : tbuf->shmmax);
+ shminfo_oldst.shmmin = tbuf->shmmin;
+ shminfo_oldst.shmmni = tbuf->shmmni;
+ shminfo_oldst.shmseg = tbuf->shmseg;
+ shminfo_oldst.shmall = tbuf->shmall;
+ if (copy_to_user(buf, &shminfo_oldst,
+ sizeof(struct shminfo_old)))
+ return -EFAULT;
+ return(ret);
+ }
+ case SHM_INFO:
+ {
+ struct shm_info *tbuf = (struct shm_info *) &arg;
+
+ if (copy_to_user (buf, tbuf, sizeof(struct shm_info)))
+ return -EFAULT;
+ return(ret);
+ }
+ case SHM_STAT:
+ case IPC_STAT:
+ {
+ struct shmid_ds_old tbuf;
+
+ tbuf.shm_perm = arg.shm_perm;
+ tbuf.shm_segsz = arg.shm_segsz;
+ tbuf.shm_atime = arg.shm_atime;
+ tbuf.shm_dtime = arg.shm_dtime;
+ tbuf.shm_ctime = arg.shm_ctime;
+ tbuf.shm_cpid = arg.shm_cpid;
+ tbuf.shm_lpid = arg.shm_lpid;
+ tbuf.shm_nattch = arg.shm_nattch;
+ tbuf.shm_unused = arg.shm_unused;
+ tbuf.shm_unused2 = arg.shm_unused2;
+ tbuf.shm_unused3 = arg.shm_unused3;
+ if (copy_to_user (buf, &tbuf, sizeof(tbuf)))
+ return -EFAULT;
+ return(ret);
+ }
+ }
+ return(ret);
+}
diff --git a/arch/alpha/kernel/pci.c b/arch/alpha/kernel/pci.c
index 9a61a4e99..601cb9401 100644
--- a/arch/alpha/kernel/pci.c
+++ b/arch/alpha/kernel/pci.c
@@ -58,6 +58,17 @@ quirk_isa_bridge(struct pci_dev *dev)
}
static void __init
+quirk_ali_ide_ports(struct pci_dev *dev)
+{
+ if (dev->resource[0].end == 0xffff)
+ dev->resource[0].end = dev->resource[0].start + 7;
+ if (dev->resource[2].end == 0xffff)
+ dev->resource[2].end = dev->resource[2].start + 7;
+ if (dev->resource[3].end == 0xffff)
+ dev->resource[3].end = dev->resource[3].start + 7;
+}
+
+static void __init
quirk_vga_enable_rom(struct pci_dev *dev)
{
/* If it's a VGA, enable its BIOS ROM at C0000.
@@ -82,6 +93,8 @@ struct pci_fixup pcibios_fixups[] __initdata = {
quirk_eisa_bridge },
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82378,
quirk_isa_bridge },
+ { PCI_FIXUP_HEADER, PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M5229,
+ quirk_ali_ide_ports },
{ PCI_FIXUP_FINAL, PCI_ANY_ID, PCI_ANY_ID, quirk_vga_enable_rom },
{ 0 }
};
@@ -131,13 +144,7 @@ pcibios_align_resource(void *data, struct resource *res, unsigned long size)
/* Align to multiple of size of minimum base. */
alignto = MAX(0x1000, size);
start = ALIGN(start, alignto);
- if (size > 7 * 16*MB) {
- printk(KERN_WARNING "PCI: dev %s "
- "requests %ld bytes of contiguous "
- "address space---don't use sparse "
- "memory accesses on this device!\n",
- dev->name, size);
- } else {
+ if (size <= 7 * 16*MB) {
if (((start / (16*MB)) & 0x7) == 0) {
start &= ~(128*MB - 1);
start += 16*MB;
diff --git a/arch/alpha/kernel/sys_nautilus.c b/arch/alpha/kernel/sys_nautilus.c
index b51eee671..423589924 100644
--- a/arch/alpha/kernel/sys_nautilus.c
+++ b/arch/alpha/kernel/sys_nautilus.c
@@ -88,13 +88,28 @@ nautilus_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
void
nautilus_kill_arch(int mode)
{
- u8 tmp;
+ switch (mode) {
+ case LINUX_REBOOT_CMD_RESTART:
+ {
+ u8 t8;
+ pcibios_read_config_byte(0, 0x38, 0x43, &t8);
+ pcibios_write_config_byte(0, 0x38, 0x43, t8 | 0x80);
+ outb(1, 0x92);
+ outb(0, 0x92);
+ /* NOTREACHED */
+ }
+ break;
- 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);
+ case LINUX_REBOOT_CMD_POWER_OFF:
+ {
+ u32 pmuport;
+ pcibios_read_config_dword(0, 0x88, 0x10, &pmuport);
+ pmuport &= 0xfffe;
+ outl(0xffff, pmuport); /* clear pending events */
+ outw(0x2000, pmuport+4); /* power off */
+ /* NOTREACHED */
+ }
+ break;
}
}
@@ -435,8 +450,8 @@ nautilus_machine_check(unsigned long vector, unsigned long la_ptr,
Add to that the two levels of severity - correctable or not. */
if (vector == SCB_Q_SYSMCHK
- && ((IRONGATE0->dramms & 0x3FF) == 0x300)) {
- unsigned long nmi_ctl, temp;
+ && ((IRONGATE0->dramms & 0x300) == 0x300)) {
+ unsigned long nmi_ctl;
/* Clear ALI NMI */
nmi_ctl = inb(0x61);
@@ -445,15 +460,15 @@ nautilus_machine_check(unsigned long vector, unsigned long la_ptr,
nmi_ctl &= ~0x0c;
outb(nmi_ctl, 0x61);
- temp = IRONGATE0->stat_cmd;
- IRONGATE0->stat_cmd = temp; /* write again clears error bits */
+ /* Write again clears error bits. */
+ IRONGATE0->stat_cmd = IRONGATE0->stat_cmd & ~0x100;
mb();
- temp = IRONGATE0->stat_cmd; /* re-read to force write */
+ IRONGATE0->stat_cmd;
- temp = IRONGATE0->dramms;
- IRONGATE0->dramms = temp; /* write again clears error bits */
+ /* Write again clears error bits. */
+ IRONGATE0->dramms = IRONGATE0->dramms;
mb();
- temp = IRONGATE0->dramms; /* re-read to force write */
+ IRONGATE0->dramms;
draina();
wrmces(0x7);
diff --git a/arch/alpha/kernel/sys_sio.c b/arch/alpha/kernel/sys_sio.c
index f26991f55..78025bec9 100644
--- a/arch/alpha/kernel/sys_sio.c
+++ b/arch/alpha/kernel/sys_sio.c
@@ -141,7 +141,7 @@ sio_collect_irq_levels(void)
struct pci_dev *dev;
/* Iterate through the devices, collecting IRQ levels. */
- for (dev = pci_devices; dev; dev = dev->next) {
+ pci_for_each_dev(dev) {
if ((dev->class >> 16 == PCI_BASE_CLASS_BRIDGE) &&
(dev->class >> 8 != PCI_CLASS_BRIDGE_PCMCIA))
continue;
diff --git a/arch/alpha/lib/Makefile b/arch/alpha/lib/Makefile
index a224f84bb..52571557b 100644
--- a/arch/alpha/lib/Makefile
+++ b/arch/alpha/lib/Makefile
@@ -14,16 +14,16 @@ lib.a: $(OBJS)
$(AR) rcs lib.a $(OBJS)
__divqu.o: divide.S
- $(CC) -DDIV -c -o __divqu.o divide.S
+ $(CC) $(AFLAGS) -DDIV -c -o __divqu.o divide.S
__remqu.o: divide.S
- $(CC) -DREM -c -o __remqu.o divide.S
+ $(CC) $(AFLAGS) -DREM -c -o __remqu.o divide.S
__divlu.o: divide.S
- $(CC) -DDIV -DINTSIZE -c -o __divlu.o divide.S
+ $(CC) $(AFLAGS) -DDIV -DINTSIZE -c -o __divlu.o divide.S
__remlu.o: divide.S
- $(CC) -DREM -DINTSIZE -c -o __remlu.o divide.S
+ $(CC) $(AFLAGS) -DREM -DINTSIZE -c -o __remlu.o divide.S
dep:
diff --git a/arch/alpha/mm/init.c b/arch/alpha/mm/init.c
index 8c40bc6a2..daaa36e09 100644
--- a/arch/alpha/mm/init.c
+++ b/arch/alpha/mm/init.c
@@ -308,6 +308,7 @@ mem_init(void)
{
max_mapnr = num_physpages = max_low_pfn;
totalram_pages += free_all_bootmem();
+ high_memory = (void *) __va(max_low_pfn * PAGE_SIZE);
printk_memory_info();
}
diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile
index a9d71cb7b..8a100eb77 100644
--- a/arch/arm/boot/compressed/Makefile
+++ b/arch/arm/boot/compressed/Makefile
@@ -6,7 +6,7 @@
HEAD = head.o
OBJS = misc.o
SYSTEM = $(TOPDIR)/vmlinux
-CFLAGS = -O2 -DSTDC_HEADERS $(CFLAGS_PROC)
+CFLAGS = $(CPPFLAGS) -O2 -DSTDC_HEADERS $(CFLAGS_PROC)
FONTC = $(TOPDIR)/drivers/video/font_acorn_8x8.c
ZLDFLAGS = -p -X -T vmlinux.lds
@@ -77,7 +77,7 @@ vmlinux: $(HEAD) $(OBJS) piggy.o vmlinux.lds
$(LD) $(ZLDFLAGS) $(HEAD) $(OBJS) piggy.o $(GCCLIB) -o vmlinux
$(HEAD): $(HEAD:.o=.S)
- $(CC) -traditional -c $(HEAD:.o=.S)
+ $(CC) $(AFLAGS) -traditional -c $(HEAD:.o=.S)
piggy.o: $(SYSTEM)
$(OBJCOPY) $(SYSTEM) piggy
@@ -86,7 +86,7 @@ piggy.o: $(SYSTEM)
rm -f piggy piggy.gz
font.o: $(FONTC)
- $(CC) -Dstatic= -c -o $@ $(FONTC)
+ $(CC) $(CFLAGS) -Dstatic= -c -o $@ $(FONTC)
vmlinux.lds: vmlinux.lds.in
@sed "$(SEDFLAGS)" < vmlinux.lds.in > $@
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index 31ca81ddc..3b79f080b 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -75,7 +75,7 @@ else
endif
$(HEAD_OBJ): $(HEAD_OBJ:.o=.S)
- $(CC) -D__ASSEMBLY__ -DTEXTADDR=$(TEXTADDR) -traditional -c $(HEAD_OBJ:.o=.S) -o $@
+ $(CC) -D__ASSEMBLY__ $(AFLAGS) -DTEXTADDR=$(TEXTADDR) -traditional -c $(HEAD_OBJ:.o=.S) -o $@
include $(TOPDIR)/Rules.make
diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c
index 041d4f4ed..b9b7d57b4 100644
--- a/arch/arm/kernel/bios32.c
+++ b/arch/arm/kernel/bios32.c
@@ -24,7 +24,7 @@ void pcibios_report_device_errors(void)
{
struct pci_dev *dev;
- for (dev = pci_devices; dev; dev = dev->next) {
+ pci_for_each_dev(dev) {
u16 status;
pci_read_config_word(dev, PCI_STATUS, &status);
@@ -121,11 +121,12 @@ static void __init pcibios_claim_resources(void)
struct pci_dev *dev;
int idx;
- for (dev = pci_devices; dev; dev = dev->next)
+ pci_for_each_dev(dev) {
for (idx = 0; idx < PCI_NUM_RESOURCES; idx++)
if (dev->resource[idx].flags &&
dev->resource[idx].start)
pci_claim_resource(dev, idx);
+ }
}
void __init
diff --git a/arch/arm/kernel/calls.S b/arch/arm/kernel/calls.S
index c95eeb1b0..51f3dcde2 100644
--- a/arch/arm/kernel/calls.S
+++ b/arch/arm/kernel/calls.S
@@ -85,7 +85,7 @@
.long SYMBOL_NAME(sys_sigpending)
.long SYMBOL_NAME(sys_sethostname)
/* 75 */ .long SYMBOL_NAME(sys_setrlimit)
- .long SYMBOL_NAME(sys_getrlimit)
+ .long SYMBOL_NAME(sys_old_getrlimit)
.long SYMBOL_NAME(sys_getrusage)
.long SYMBOL_NAME(sys_gettimeofday)
.long SYMBOL_NAME(sys_settimeofday)
@@ -200,8 +200,15 @@
.long SYMBOL_NAME(sys_ni_syscall)
.long SYMBOL_NAME(sys_ni_syscall)
/* 190 */ .long SYMBOL_NAME(sys_vfork_wrapper)
+ .long SYMBOL_NAME(sys_getrlimit)
+ .long SYMBOL_NAME(sys_mmap2)
+ .long SYMBOL_NAME(sys_truncate64)
+ .long SYMBOL_NAME(sys_ftruncate64)
+/* 195 */ .long SYMBOL_NAME(sys_stat64)
+ .long SYMBOL_NAME(sys_lstat64)
+ .long SYMBOL_NAME(sys_fstat64)
- .rept NR_syscalls-186
+ .rept NR_syscalls-197
.long SYMBOL_NAME(sys_ni_syscall)
.endr
#endif
diff --git a/arch/i386/boot/Makefile b/arch/i386/boot/Makefile
index 56a941a62..e75eb2fdf 100644
--- a/arch/i386/boot/Makefile
+++ b/arch/i386/boot/Makefile
@@ -49,7 +49,7 @@ bootsect.o: bootsect.s
$(AS) -o $@ $<
bootsect.s: bootsect.S Makefile $(BOOT_INCL)
- $(CPP) -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@
+ $(CPP) $(CPPFLAGS) -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@
bbootsect: bbootsect.o
$(LD) -Ttext 0x0 -s -oformat binary $< -o $@
@@ -58,7 +58,7 @@ bbootsect.o: bbootsect.s
$(AS) -o $@ $<
bbootsect.s: bootsect.S Makefile $(BOOT_INCL)
- $(CPP) -D__BIG_KERNEL__ -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@
+ $(CPP) $(CPPFLAGS) -D__BIG_KERNEL__ -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@
setup: setup.o
$(LD) -Ttext 0x0 -s -oformat binary -e begtext -o $@ $<
@@ -67,7 +67,7 @@ setup.o: setup.s
$(AS) -o $@ $<
setup.s: setup.S video.S Makefile $(BOOT_INCL) $(TOPDIR)/include/linux/version.h $(TOPDIR)/include/linux/compile.h
- $(CPP) -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@
+ $(CPP) $(CPPFLAGS) -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@
bsetup: bsetup.o
$(LD) -Ttext 0x0 -s -oformat binary -e begtext -o $@ $<
@@ -76,7 +76,7 @@ bsetup.o: bsetup.s
$(AS) -o $@ $<
bsetup.s: setup.S video.S Makefile $(BOOT_INCL) $(TOPDIR)/include/linux/version.h $(TOPDIR)/include/linux/compile.h
- $(CPP) -D__BIG_KERNEL__ -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@
+ $(CPP) $(CPPFLAGS) -D__BIG_KERNEL__ -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@
dep:
diff --git a/arch/i386/boot/compressed/Makefile b/arch/i386/boot/compressed/Makefile
index 83a245add..6e4b4998d 100644
--- a/arch/i386/boot/compressed/Makefile
+++ b/arch/i386/boot/compressed/Makefile
@@ -9,7 +9,7 @@ SYSTEM = $(TOPDIR)/vmlinux
OBJECTS = $(HEAD) misc.o
-CFLAGS = -O2 -DSTDC_HEADERS
+CFLAGS = $(CPPFLAGS) -O2 -DSTDC_HEADERS
ZLDFLAGS = -e startup_32
#
diff --git a/arch/i386/boot/compressed/head.S b/arch/i386/boot/compressed/head.S
index 0aa8ddc44..eb2a9a2c5 100644
--- a/arch/i386/boot/compressed/head.S
+++ b/arch/i386/boot/compressed/head.S
@@ -53,9 +53,9 @@ startup_32:
xorl %eax,%eax # Back to 0
mov %cx,%ax # SP low 16 bits
movl %eax,%esp
- pushl 0 # Clear NT
+ pushl $0 # Clear NT
popfl
- ljmp $(__KERNEL_CS), $0x100000 # Into C and sanity
+ ljmp $(__KERNEL_CS), $0x100000 # Into C and sanity
2:
#endif
diff --git a/arch/i386/boot/setup.S b/arch/i386/boot/setup.S
index cbfa7b3e8..1a08bc3ab 100644
--- a/arch/i386/boot/setup.S
+++ b/arch/i386/boot/setup.S
@@ -202,9 +202,9 @@ bad_sig:
xorb %bh, %bh
movb (497), %bl # get setup sect from bootsect
subw $4, %bx # LILO loads 4 sectors of setup
- shlw $7, %bx # convert to dwords (1sect=2^7 dwords)
+ shlw $8, %bx # convert to words (1sect=2^8 words)
movw %bx, %cx
- shrw $2, %bx # convert to segment
+ shrw $3, %bx # convert to segment
addw $SYSSEG, %bx
movw %bx, %cs:start_sys_seg
# Move rest of setup code/data to here
diff --git a/arch/i386/config.in b/arch/i386/config.in
index 4a09997b2..654602855 100644
--- a/arch/i386/config.in
+++ b/arch/i386/config.in
@@ -119,6 +119,13 @@ tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
source drivers/parport/Config.in
+bool 'ACPI support' CONFIG_ACPI
+if [ "$CONFIG_ACPI" != "n" ]; then
+ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ bool ' Enter S1 for sleep (EXPERIMENTAL)' CONFIG_ACPI_S1_SLEEP
+ fi
+fi
+
bool 'Advanced Power Management BIOS support' CONFIG_APM
if [ "$CONFIG_APM" != "n" ]; then
bool ' Ignore USER SUSPEND' CONFIG_APM_IGNORE_USER_SUSPEND
@@ -129,6 +136,8 @@ if [ "$CONFIG_APM" != "n" ]; then
bool ' Ignore multiple suspend/resume cycles' CONFIG_APM_IGNORE_SUSPEND_BOUNCE
bool ' RTC stores time in GMT' CONFIG_APM_RTC_IS_GMT
bool ' Allow interrupts during APM BIOS calls' CONFIG_APM_ALLOW_INTS
+ bool ' Entry point offset fix (some Acer laptops)' CONFIG_APM_BAD_ENTRY_OFFSET
+ bool ' Use real mode APM BIOS call to power off' CONFIG_APM_REAL_MODE_POWER_OFF
fi
endmenu
@@ -142,6 +151,8 @@ if [ "$CONFIG_NET" = "y" ]; then
source net/Config.in
fi
+source drivers/telephony/Config.in
+
mainmenu_option next_comment
comment 'SCSI support'
diff --git a/arch/i386/defconfig b/arch/i386/defconfig
index 8d1e2a67f..9b248a6be 100644
--- a/arch/i386/defconfig
+++ b/arch/i386/defconfig
@@ -59,8 +59,9 @@ CONFIG_PCI_NAMES=y
#
CONFIG_PCMCIA=y
CONFIG_CARDBUS=y
-CONFIG_I82365=y
-# CONFIG_TCIC is not set
+CONFIG_YENTA=y
+# CONFIG_I82365 is not set
+CONFIG_TCIC=y
CONFIG_SYSVIPC=y
# CONFIG_BSD_PROCESS_ACCT is not set
CONFIG_SYSCTL=y
@@ -70,6 +71,7 @@ CONFIG_BINFMT_AOUT=y
CONFIG_BINFMT_ELF=y
CONFIG_BINFMT_MISC=y
# CONFIG_PARPORT is not set
+CONFIG_ACPI=y
# CONFIG_APM is not set
#
@@ -105,8 +107,6 @@ CONFIG_BLK_DEV_IDEPCI=y
# CONFIG_BLK_DEV_IDEDMA_PCI is not set
# CONFIG_BLK_DEV_OFFBOARD is not set
# CONFIG_BLK_DEV_AEC6210 is not set
-CONFIG_BLK_DEV_PIIX=y
-# CONFIG_BLK_DEV_PIIX_TUNING is not set
# CONFIG_IDE_CHIPSETS is not set
# CONFIG_BLK_CPQ_DA is not set
@@ -155,6 +155,12 @@ CONFIG_SKB_LARGE=y
# CONFIG_ATALK is not set
#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+# CONFIG_PHONE_IXJ is not set
+
+#
# SCSI support
#
CONFIG_SCSI=y
@@ -311,6 +317,7 @@ CONFIG_PCMCIA_PCNET=y
# CONFIG_PCMCIA_3C575 is not set
# CONFIG_PCMCIA_TULIP is not set
# CONFIG_PCMCIA_EPIC100 is not set
+CONFIG_NET_PCMCIA_RADIO=y
CONFIG_PCMCIA_RAYCS=y
# CONFIG_PCMCIA_NETWAVE is not set
# CONFIG_PCMCIA_WAVELAN is not set
@@ -349,6 +356,11 @@ CONFIG_UNIX98_PTYS=y
CONFIG_UNIX98_PTY_COUNT=256
#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
# Mice
#
# CONFIG_BUSMOUSE is not set
@@ -393,14 +405,13 @@ CONFIG_DRM_TDFX=y
# CONFIG_PCMCIA_SERIAL_CB is not set
#
-# Support for USB
+# USB support
#
# CONFIG_USB is not set
#
# Misc devices
#
-CONFIG_ACPI=y
#
# Filesystems
@@ -412,6 +423,7 @@ CONFIG_AUTOFS_FS=y
# CONFIG_MSDOS_FS is not set
# CONFIG_UMSDOS_FS is not set
# CONFIG_VFAT_FS is not set
+# CONFIG_CRAMFS is not set
CONFIG_ISO9660_FS=y
# CONFIG_JOLIET is not set
# CONFIG_MINIX_FS is not set
diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile
index 55790ac25..e60e15620 100644
--- a/arch/i386/kernel/Makefile
+++ b/arch/i386/kernel/Makefile
@@ -39,6 +39,10 @@ else
endif
endif
+ifeq ($(CONFIG_ACPI),y)
+ OX_OBJS += acpi.o
+endif
+
ifeq ($(CONFIG_APM),y)
OX_OBJS += apm.o
else
diff --git a/arch/i386/kernel/acpi.c b/arch/i386/kernel/acpi.c
new file mode 100644
index 000000000..49444d258
--- /dev/null
+++ b/arch/i386/kernel/acpi.c
@@ -0,0 +1,1344 @@
+/*
+ * acpi.c - Linux ACPI driver
+ *
+ * Copyright (C) 1999 Andrew Henroid
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * See http://www.geocities.com/SiliconValley/Hardware/3165/
+ * for the user-level ACPI stuff
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/string.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>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <linux/sysctl.h>
+#include <linux/delay.h>
+#include <linux/acpi.h>
+
+/*
+ * Defines for 2.2.x
+ */
+#ifndef __exit
+#define __exit
+#endif
+#ifndef module_init
+#define module_init(x) int init_module(void) {return x();}
+#endif
+#ifndef module_exit
+#define module_exit(x) void cleanup_module(void) {x();}
+#endif
+#ifndef DECLARE_WAIT_QUEUE_HEAD
+#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);
+static int acpi_do_event_reg(ctl_table *ctl,
+ int write,
+ struct file *file,
+ void *buffer,
+ size_t *len);
+static int acpi_do_event(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);
+
+DECLARE_WAIT_QUEUE_HEAD(acpi_control_wait);
+
+static struct ctl_table_header *acpi_sysctl = NULL;
+
+static struct acpi_facp *acpi_facp = NULL;
+static int acpi_fake_facp = 0;
+static struct acpi_facs *acpi_facs = 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;
+static LIST_HEAD(acpi_devs);
+
+/* Make it impossible to enter C2/C3 until after we've initialized */
+static unsigned long acpi_enter_lvl2_lat = ACPI_INFINITE_LAT;
+static unsigned long acpi_enter_lvl3_lat = ACPI_INFINITE_LAT;
+static unsigned long acpi_p_lvl2_lat = ACPI_INFINITE_LAT;
+static unsigned long acpi_p_lvl3_lat = ACPI_INFINITE_LAT;
+
+static unsigned long acpi_p_blk = 0;
+
+static int acpi_p_lvl2_tested = 0;
+static int acpi_p_lvl3_tested = 0;
+
+static int acpi_disabled = 0;
+int acpi_active = 0;
+
+// bits 8-15 are SLP_TYPa, bits 0-7 are SLP_TYPb
+static unsigned long acpi_slp_typ[] =
+{
+ ACPI_SLP_TYP_DISABLED, /* S0 */
+ ACPI_SLP_TYP_DISABLED, /* S1 */
+ ACPI_SLP_TYP_DISABLED, /* S2 */
+ ACPI_SLP_TYP_DISABLED, /* S3 */
+ ACPI_SLP_TYP_DISABLED, /* S4 */
+ ACPI_SLP_TYP_DISABLED /* S5 */
+};
+
+static struct ctl_table acpi_table[] =
+{
+ {ACPI_FACP, "facp",
+ &acpi_facp_addr, sizeof(acpi_facp_addr),
+ 0400, NULL, &acpi_do_ulong},
+
+ {ACPI_DSDT, "dsdt",
+ &acpi_dsdt_addr, sizeof(acpi_dsdt_addr),
+ 0400, NULL, &acpi_do_ulong},
+
+ {ACPI_PM1_ENABLE, "pm1_enable",
+ NULL, 0,
+ 0600, NULL, &acpi_do_event_reg},
+
+ {ACPI_GPE_ENABLE, "gpe_enable",
+ NULL, 0,
+ 0600, NULL, &acpi_do_event_reg},
+
+ {ACPI_GPE_LEVEL, "gpe_level",
+ NULL, 0,
+ 0600, NULL, &acpi_do_event_reg},
+
+ {ACPI_EVENT, "event", NULL, 0, 0400, NULL, &acpi_do_event},
+
+ {ACPI_P_BLK, "p_blk",
+ &acpi_p_blk, sizeof(acpi_p_blk),
+ 0600, NULL, &acpi_do_ulong},
+
+ {ACPI_P_LVL2_LAT, "p_lvl2_lat",
+ &acpi_p_lvl2_lat, sizeof(acpi_p_lvl2_lat),
+ 0644, NULL, &acpi_do_ulong},
+
+ {ACPI_P_LVL3_LAT, "p_lvl3_lat",
+ &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[ACPI_S5], sizeof(acpi_slp_typ[ACPI_S5]),
+ 0600, NULL, &acpi_do_ulong},
+
+ {ACPI_SLEEP, "sleep", NULL, 0, 0600, NULL, &acpi_do_sleep},
+
+ {0}
+};
+
+static struct ctl_table acpi_dir_table[] =
+{
+ {CTL_ACPI, "acpi", NULL, 0, 0555, acpi_table},
+ {0}
+};
+
+
+/*
+ * Get the value of the PM1 control register (SCI_EN, ...)
+ */
+static u32 acpi_read_pm1_control(struct acpi_facp *facp)
+{
+ u32 value = 0;
+ if (facp->pm1a_cnt)
+ value = inw(facp->pm1a_cnt);
+ if (facp->pm1b_cnt)
+ value |= inw(facp->pm1b_cnt);
+ return value;
+}
+
+/*
+ * Set the value of the PM1 control register (BM_RLD, ...)
+ */
+static void acpi_write_pm1_control(struct acpi_facp *facp, u32 value)
+{
+ if (facp->pm1a_cnt)
+ outw(value, facp->pm1a_cnt);
+ if (facp->pm1b_cnt)
+ outw(value, facp->pm1b_cnt);
+}
+
+/*
+ * Get the value of the fixed event status register
+ */
+static u32 acpi_read_pm1_status(struct acpi_facp *facp)
+{
+ u32 value = 0;
+ if (facp->pm1a_evt)
+ value = inw(facp->pm1a_evt);
+ if (facp->pm1b_evt)
+ value |= inw(facp->pm1b_evt);
+ return value;
+}
+
+/*
+ * Set the value of the fixed event status register (clear events)
+ */
+static void acpi_write_pm1_status(struct acpi_facp *facp, u32 value)
+{
+ if (facp->pm1a_evt)
+ outw(value, facp->pm1a_evt);
+ if (facp->pm1b_evt)
+ outw(value, facp->pm1b_evt);
+}
+
+/*
+ * Get the value of the fixed event enable register
+ */
+static u32 acpi_read_pm1_enable(struct acpi_facp *facp)
+{
+ int offset = facp->pm1_evt_len >> 1;
+ u32 value = 0;
+ if (facp->pm1a_evt)
+ value = inw(facp->pm1a_evt + offset);
+ if (facp->pm1b_evt)
+ value |= inw(facp->pm1b_evt + offset);
+ return value;
+}
+
+/*
+ * Set the value of the fixed event enable register (enable events)
+ */
+static void acpi_write_pm1_enable(struct acpi_facp *facp, u32 value)
+{
+ int offset = facp->pm1_evt_len >> 1;
+ if (facp->pm1a_evt)
+ outw(value, facp->pm1a_evt + offset);
+ if (facp->pm1b_evt)
+ outw(value, facp->pm1b_evt + offset);
+}
+
+/*
+ * Get the value of the general-purpose event status register
+ */
+static u32 acpi_read_gpe_status(struct acpi_facp *facp)
+{
+ u32 value = 0;
+ int i, size;
+
+ if (facp->gpe1) {
+ size = facp->gpe1_len >> 1;
+ for (i = size - 1; i >= 0; i--)
+ value = (value << 8) | inb(facp->gpe1 + i);
+ }
+ if (facp->gpe0) {
+ size = facp->gpe0_len >> 1;
+ for (i = size - 1; i >= 0; i--)
+ value = (value << 8) | inb(facp->gpe0 + i);
+ }
+ return value;
+}
+
+/*
+ * Set the value of the general-purpose event status register (clear events)
+ */
+static void acpi_write_gpe_status(struct acpi_facp *facp, u32 value)
+{
+ int i, size;
+
+ if (facp->gpe0) {
+ size = facp->gpe0_len >> 1;
+ for (i = 0; i < size; i++) {
+ outb(value & 0xff, facp->gpe0 + i);
+ value >>= 8;
+ }
+ }
+ if (facp->gpe1) {
+ size = facp->gpe1_len >> 1;
+ for (i = 0; i < size; i++) {
+ outb(value & 0xff, facp->gpe1 + i);
+ value >>= 8;
+ }
+ }
+}
+
+/*
+ * Get the value of the general-purpose event enable register
+ */
+static u32 acpi_read_gpe_enable(struct acpi_facp *facp)
+{
+ u32 value = 0;
+ int i, size, offset;
+
+ offset = facp->gpe0_len >> 1;
+ if (facp->gpe1) {
+ size = facp->gpe1_len >> 1;
+ for (i = size - 1; i >= 0; i--) {
+ value = (value << 8) | inb(facp->gpe1 + offset + i);
+ }
+ }
+ if (facp->gpe0) {
+ size = facp->gpe0_len >> 1;
+ for (i = size - 1; i >= 0; i--)
+ value = (value << 8) | inb(facp->gpe0 + offset + i);
+ }
+ return value;
+}
+
+/*
+ * Set the value of the general-purpose event enable register (enable events)
+ */
+static void acpi_write_gpe_enable(struct acpi_facp *facp, u32 value)
+{
+ int i, offset;
+
+ offset = facp->gpe0_len >> 1;
+ if (facp->gpe0) {
+ for (i = 0; i < offset; i++) {
+ outb(value & 0xff, facp->gpe0 + offset + i);
+ value >>= 8;
+ }
+ }
+ if (facp->gpe1) {
+ offset = facp->gpe1_len >> 1;
+ for (i = 0; i < offset; i++) {
+ outb(value & 0xff, facp->gpe1 + offset + i);
+ value >>= 8;
+ }
+ }
+}
+
+/*
+ * Map an ACPI table into virtual memory
+ */
+static struct acpi_table *__init acpi_map_table(u32 addr)
+{
+ struct acpi_table *table = NULL;
+ if (addr) {
+ // map table header to determine size
+ table = (struct acpi_table *)
+ ioremap((unsigned long) addr,
+ sizeof(struct acpi_table));
+ if (table) {
+ unsigned long table_size = table->length;
+ iounmap(table);
+ // remap entire table
+ table = (struct acpi_table *)
+ ioremap((unsigned long) addr, table_size);
+ }
+
+ if (!table) {
+ /* ioremap is a pain, it returns NULL if the
+ * table starts within mapped physical memory.
+ * Hopefully, no table straddles a mapped/unmapped
+ * physical memory boundary, ugh
+ */
+ table = (struct acpi_table*) phys_to_virt(addr);
+ }
+ }
+ return table;
+}
+
+/*
+ * Unmap an ACPI table from virtual memory
+ */
+static void acpi_unmap_table(struct acpi_table *table)
+{
+ // iounmap ignores addresses within physical memory
+ if (table)
+ iounmap(table);
+}
+
+/*
+ * Locate and map ACPI tables
+ */
+static int __init acpi_find_tables(void)
+{
+ struct acpi_rsdp *rsdp;
+ struct acpi_table *rsdt;
+ u32 *rsdt_entry;
+ int rsdt_entry_count;
+ unsigned long i;
+
+ // search BIOS memory for RSDP
+ for (i = ACPI_BIOS_ROM_BASE; i < ACPI_BIOS_ROM_END; i += 16) {
+ rsdp = (struct acpi_rsdp *) phys_to_virt(i);
+ if (rsdp->signature[0] == ACPI_RSDP1_SIG
+ && rsdp->signature[1] == ACPI_RSDP2_SIG) {
+ char oem[7];
+ int j;
+
+ // strip trailing space and print OEM identifier
+ memcpy(oem, rsdp->oem, 6);
+ oem[6] = '\0';
+ for (j = 5;
+ j > 0 && (oem[j] == '\0' || oem[j] == ' ');
+ j--) {
+ oem[j] = '\0';
+ }
+ printk(KERN_INFO "ACPI: \"%s\" found at 0x%p\n",
+ oem, (void *) i);
+
+ break;
+ }
+ }
+ if (i >= ACPI_BIOS_ROM_END)
+ return -ENODEV;
+
+ // fetch RSDT from RSDP
+ rsdt = acpi_map_table(rsdp->rsdt);
+ if (!rsdt) {
+ printk(KERN_ERR "ACPI: missing RSDT at 0x%p\n",
+ (void*) rsdp->rsdt);
+ return -ENODEV;
+ }
+ else if (rsdt->signature != ACPI_RSDT_SIG) {
+ printk(KERN_ERR "ACPI: bad RSDT at 0x%p (%08x)\n",
+ (void*) rsdp->rsdt, (unsigned) rsdt->signature);
+ acpi_unmap_table(rsdt);
+ return -ENODEV;
+ }
+ // search RSDT for FACP
+ acpi_facp = NULL;
+ rsdt_entry = (u32 *) (rsdt + 1);
+ rsdt_entry_count = (int) ((rsdt->length - sizeof(*rsdt)) >> 2);
+ while (rsdt_entry_count) {
+ struct acpi_table *dt = acpi_map_table(*rsdt_entry);
+ if (dt && dt->signature == ACPI_FACP_SIG) {
+ acpi_facp = (struct acpi_facp*) dt;
+ acpi_facp_addr = *rsdt_entry;
+ acpi_dsdt_addr = acpi_facp->dsdt;
+
+ // map FACS if it exists
+ if (acpi_facp->facs) {
+ dt = acpi_map_table(acpi_facp->facs);
+ if (dt && dt->signature == ACPI_FACS_SIG) {
+ acpi_facs = (struct acpi_facs*) dt;
+ }
+ else {
+ acpi_unmap_table(dt);
+ }
+ }
+ }
+ else {
+ acpi_unmap_table(dt);
+ }
+ rsdt_entry++;
+ rsdt_entry_count--;
+ }
+
+ acpi_unmap_table(rsdt);
+
+ if (!acpi_facp) {
+ printk(KERN_ERR "ACPI: missing FACP\n");
+ return -ENODEV;
+ }
+ return 0;
+}
+
+/*
+ * Unmap or destroy ACPI tables
+ */
+static void acpi_destroy_tables(void)
+{
+ if (!acpi_fake_facp)
+ acpi_unmap_table((struct acpi_table*) acpi_facp);
+ else
+ kfree(acpi_facp);
+ acpi_unmap_table((struct acpi_table*) acpi_facs);
+}
+
+/*
+ * Locate PIIX4 device and create a fake FACP
+ */
+static int __init acpi_find_piix4(void)
+{
+ struct pci_dev *dev;
+ u32 base;
+ u16 cmd;
+ u8 pmregmisc;
+
+ dev = pci_find_device(PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_82371AB_3,
+ NULL);
+ if (!dev)
+ return -ENODEV;
+
+ pci_read_config_word(dev, PCI_COMMAND, &cmd);
+ if (!(cmd & PCI_COMMAND_IO))
+ return -ENODEV;
+
+ pci_read_config_byte(dev, ACPI_PIIX4_PMREGMISC, &pmregmisc);
+ if (!(pmregmisc & ACPI_PIIX4_PMIOSE))
+ return -ENODEV;
+
+ pci_read_config_dword(dev, 0x40, &base);
+ if (!(base & PCI_BASE_ADDRESS_SPACE_IO))
+ return -ENODEV;
+
+ base &= PCI_BASE_ADDRESS_IO_MASK;
+ if (!base)
+ return -ENODEV;
+
+ printk(KERN_INFO "ACPI: found PIIX4 at 0x%04x\n", base);
+
+ acpi_facp = kmalloc(sizeof(struct acpi_facp), GFP_KERNEL);
+ if (!acpi_facp)
+ return -ENOMEM;
+
+ acpi_fake_facp = 1;
+ memset(acpi_facp, 0, sizeof(struct acpi_facp));
+ acpi_facp->int_model = ACPI_PIIX4_INT_MODEL;
+ acpi_facp->sci_int = ACPI_PIIX4_SCI_INT;
+ acpi_facp->smi_cmd = ACPI_PIIX4_SMI_CMD;
+ acpi_facp->acpi_enable = ACPI_PIIX4_ACPI_ENABLE;
+ acpi_facp->acpi_disable = ACPI_PIIX4_ACPI_DISABLE;
+ acpi_facp->s4bios_req = ACPI_PIIX4_S4BIOS_REQ;
+ acpi_facp->pm1a_evt = base + ACPI_PIIX4_PM1_EVT;
+ acpi_facp->pm1a_cnt = base + ACPI_PIIX4_PM1_CNT;
+ acpi_facp->pm2_cnt = ACPI_PIIX4_PM2_CNT;
+ acpi_facp->pm_tmr = base + ACPI_PIIX4_PM_TMR;
+ acpi_facp->gpe0 = base + ACPI_PIIX4_GPE0;
+ acpi_facp->pm1_evt_len = ACPI_PIIX4_PM1_EVT_LEN;
+ acpi_facp->pm1_cnt_len = ACPI_PIIX4_PM1_CNT_LEN;
+ acpi_facp->pm2_cnt_len = ACPI_PIIX4_PM2_CNT_LEN;
+ acpi_facp->pm_tm_len = ACPI_PIIX4_PM_TM_LEN;
+ acpi_facp->gpe0_len = ACPI_PIIX4_GPE0_LEN;
+ acpi_facp->p_lvl2_lat = (__u16) ACPI_INFINITE_LAT;
+ acpi_facp->p_lvl3_lat = (__u16) ACPI_INFINITE_LAT;
+
+ acpi_facp_addr = virt_to_phys(acpi_facp);
+ acpi_dsdt_addr = 0;
+
+ acpi_p_blk = base + ACPI_PIIX4_P_BLK;
+
+ return 0;
+}
+
+/*
+ * Handle an ACPI SCI (fixed or general purpose event)
+ */
+static void acpi_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+ u32 pm1_status, gpe_status, gpe_level, gpe_edge;
+ unsigned long flags;
+
+ // detect and clear fixed events
+ pm1_status = (acpi_read_pm1_status(acpi_facp)
+ & acpi_read_pm1_enable(acpi_facp));
+ acpi_write_pm1_status(acpi_facp, pm1_status);
+
+ // detect and handle general-purpose events
+ gpe_status = (acpi_read_gpe_status(acpi_facp)
+ & acpi_read_gpe_enable(acpi_facp));
+ gpe_level = gpe_status & acpi_gpe_level;
+ if (gpe_level) {
+ // disable level-triggered events (re-enabled after handling)
+ acpi_write_gpe_enable(
+ acpi_facp,
+ acpi_read_gpe_enable(acpi_facp) & ~gpe_level);
+ }
+ gpe_edge = gpe_status & ~gpe_level;
+ if (gpe_edge) {
+ // clear edge-triggered events
+ while (acpi_read_gpe_status(acpi_facp) & gpe_edge)
+ acpi_write_gpe_status(acpi_facp, gpe_edge);
+ }
+
+ // notify process waiting on /dev/acpi
+ spin_lock_irqsave(&acpi_event_lock, flags);
+ 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);
+}
+
+/*
+ * Is ACPI enabled or not?
+ */
+static inline int acpi_is_enabled(struct acpi_facp *facp)
+{
+ return ((acpi_read_pm1_control(facp) & ACPI_SCI_EN) ? 1:0);
+}
+
+/*
+ * Enable SCI
+ */
+static int acpi_enable(struct acpi_facp *facp)
+{
+ if (facp->smi_cmd)
+ outb(facp->acpi_enable, facp->smi_cmd);
+ return (acpi_is_enabled(facp) ? 0:-1);
+}
+
+/*
+ * Disable SCI
+ */
+static int acpi_disable(struct acpi_facp *facp)
+{
+ // disable and clear any pending events
+ acpi_write_gpe_enable(facp, 0);
+ while (acpi_read_gpe_status(facp))
+ acpi_write_gpe_status(facp, acpi_read_gpe_status(facp));
+ acpi_write_pm1_enable(facp, 0);
+ acpi_write_pm1_status(facp, acpi_read_pm1_status(facp));
+
+ /* writing acpi_disable to smi_cmd would be appropriate
+ * here but this causes a nasty crash on many systems
+ */
+
+ return 0;
+}
+
+static inline int bm_activity(void)
+{
+ return 0 && acpi_read_pm1_status(acpi_facp) & ACPI_BM;
+}
+
+static inline void clear_bm_activity(void)
+{
+ acpi_write_pm1_status(acpi_facp, ACPI_BM);
+}
+
+static void sleep_on_busmaster(void)
+{
+ u32 pm1_cntr = acpi_read_pm1_control(acpi_facp);
+ if (pm1_cntr & ACPI_BM_RLD) {
+ pm1_cntr &= ~ACPI_BM_RLD;
+ acpi_write_pm1_control(acpi_facp, pm1_cntr);
+ }
+}
+
+static void wake_on_busmaster(void)
+{
+ u32 pm1_cntr = acpi_read_pm1_control(acpi_facp);
+ if (!(pm1_cntr & ACPI_BM_RLD)) {
+ pm1_cntr |= ACPI_BM_RLD;
+ acpi_write_pm1_control(acpi_facp, pm1_cntr);
+ }
+ clear_bm_activity();
+}
+
+/*
+ * Idle loop (uniprocessor only)
+ */
+static void acpi_idle_handler(void)
+{
+ static int sleep_level = 1;
+
+ if (!acpi_facp->pm_tmr || !acpi_p_blk)
+ goto not_initialized;
+
+ /*
+ * start from the previous sleep level..
+ */
+ if (sleep_level == 1)
+ goto sleep1;
+ if (sleep_level == 2 || bm_activity())
+ goto sleep2;
+sleep3:
+ sleep_level = 3;
+ if (!acpi_p_lvl3_tested) {
+ printk("ACPI C3 works\n");
+ acpi_p_lvl3_tested = 1;
+ }
+ wake_on_busmaster();
+ if (acpi_facp->pm2_cnt)
+ goto sleep3_with_arbiter;
+
+ for (;;) {
+ unsigned long time;
+ __cli();
+ if (current->need_resched)
+ goto out;
+ time = inl(acpi_facp->pm_tmr);
+ inb(acpi_p_blk + ACPI_P_LVL3);
+ time = inl(acpi_facp->pm_tmr) - time;
+ __sti();
+ if (time > acpi_p_lvl3_lat || bm_activity())
+ goto sleep2;
+ }
+
+sleep3_with_arbiter:
+ for (;;) {
+ unsigned long time;
+ unsigned int pm2_cntr = acpi_facp->pm2_cnt;
+ __cli();
+ if (current->need_resched)
+ goto out;
+ time = inl(acpi_facp->pm_tmr);
+ outb(inb(pm2_cntr) | ACPI_ARB_DIS, pm2_cntr);
+ inb(acpi_p_blk + ACPI_P_LVL3);
+ outb(inb(pm2_cntr) & ~ACPI_ARB_DIS, pm2_cntr);
+ time = inl(acpi_facp->pm_tmr) - time;
+ __sti();
+ if (time > acpi_p_lvl3_lat || bm_activity())
+ goto sleep2;
+ }
+
+sleep2:
+ sleep_level = 2;
+ if (!acpi_p_lvl2_tested) {
+ printk("ACPI C2 works\n");
+ acpi_p_lvl2_tested = 1;
+ }
+ wake_on_busmaster(); /* Required to track BM activity.. */
+ for (;;) {
+ unsigned long time;
+ __cli();
+ if (current->need_resched)
+ goto out;
+ time = inl(acpi_facp->pm_tmr);
+ inb(acpi_p_blk + ACPI_P_LVL2);
+ time = inl(acpi_facp->pm_tmr) - time;
+ __sti();
+ if (time > acpi_p_lvl2_lat)
+ goto sleep1;
+ if (bm_activity()) {
+ clear_bm_activity();
+ continue;
+ }
+ if (time < acpi_enter_lvl3_lat)
+ goto sleep3;
+ }
+
+sleep1:
+ sleep_level = 1;
+ sleep_on_busmaster();
+ for (;;) {
+ unsigned long time;
+ __cli();
+ if (current->need_resched)
+ goto out;
+ time = inl(acpi_facp->pm_tmr);
+ __asm__ __volatile__("sti ; hlt": : :"memory");
+ time = inl(acpi_facp->pm_tmr) - time;
+ if (time < acpi_enter_lvl2_lat)
+ goto sleep2;
+ }
+
+not_initialized:
+ for (;;) {
+ __cli();
+ if (current->need_resched)
+ goto out;
+ __asm__ __volatile__("sti ; hlt": : :"memory");
+ }
+
+out:
+ __sti();
+}
+
+/*
+ * Put all devices into specified D-state
+ */
+static int acpi_enter_dx(acpi_dstate_t state)
+{
+ int status = 0;
+ struct list_head *i = acpi_devs.next;
+
+ while (i != &acpi_devs) {
+ struct acpi_dev *dev = list_entry(i, struct acpi_dev, entry);
+ if (dev->state != state) {
+ int dev_status = 0;
+ if (dev->info.transition)
+ dev_status = dev->info.transition(dev, state);
+ if (!dev_status) {
+ // put hardware into D-state
+ dev->state = state;
+ }
+ if (dev_status)
+ status = dev_status;
+ }
+
+ i = i->next;
+ }
+
+ 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
+ */
+static void acpi_enter_sx(acpi_sstate_t state)
+{
+ unsigned long slp_typ = acpi_slp_typ[(int) state];
+ if (slp_typ != ACPI_SLP_TYP_DISABLED) {
+ u16 typa, typb, value;
+
+ // bits 8-15 are SLP_TYPa, bits 0-7 are SLP_TYPb
+ typa = (slp_typ >> 8) & 0xff;
+ typb = slp_typ & 0xff;
+
+ typa = ((typa << ACPI_SLP_TYP_SHIFT) & ACPI_SLP_TYP_MASK);
+ 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;
+ outw(value | typa | ACPI_SLP_EN, acpi_facp->pm1a_cnt);
+ }
+ if (acpi_facp->pm1b_cnt) {
+ value = inw(acpi_facp->pm1b_cnt) & ~ACPI_SLP_TYP_MASK;
+ outw(value | typb | ACPI_SLP_EN, acpi_facp->pm1b_cnt);
+ }
+
+ 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();
+ }
+ }
+}
+
+/*
+ * Enter soft-off (S5)
+ */
+static void acpi_power_off_handler(void)
+{
+ acpi_enter_sx(ACPI_S5);
+}
+
+/*
+ * Claim ACPI I/O ports
+ */
+static int acpi_claim_ioports(struct acpi_facp *facp)
+{
+ // we don't get a guarantee of contiguity for any of the ACPI registers
+ if (facp->pm1a_evt)
+ request_region(facp->pm1a_evt, facp->pm1_evt_len, "acpi");
+ if (facp->pm1b_evt)
+ request_region(facp->pm1b_evt, facp->pm1_evt_len, "acpi");
+ if (facp->pm1a_cnt)
+ request_region(facp->pm1a_cnt, facp->pm1_cnt_len, "acpi");
+ if (facp->pm1b_cnt)
+ request_region(facp->pm1b_cnt, facp->pm1_cnt_len, "acpi");
+ if (facp->pm_tmr)
+ request_region(facp->pm_tmr, facp->pm_tm_len, "acpi");
+ if (facp->gpe0)
+ request_region(facp->gpe0, facp->gpe0_len, "acpi");
+ if (facp->gpe1)
+ request_region(facp->gpe1, facp->gpe1_len, "acpi");
+
+ return 0;
+}
+
+/*
+ * Free ACPI I/O ports
+ */
+static int acpi_release_ioports(struct acpi_facp *facp)
+{
+ // we don't get a guarantee of contiguity for any of the ACPI registers
+ if (facp->pm1a_evt)
+ release_region(facp->pm1a_evt, facp->pm1_evt_len);
+ if (facp->pm1b_evt)
+ release_region(facp->pm1b_evt, facp->pm1_evt_len);
+ if (facp->pm1a_cnt)
+ release_region(facp->pm1a_cnt, facp->pm1_cnt_len);
+ if (facp->pm1b_cnt)
+ release_region(facp->pm1b_cnt, facp->pm1_cnt_len);
+ if (facp->pm_tmr)
+ release_region(facp->pm_tmr, facp->pm_tm_len);
+ if (facp->gpe0)
+ release_region(facp->gpe0, facp->gpe0_len);
+ if (facp->gpe1)
+ release_region(facp->gpe1, facp->gpe1_len);
+
+ return 0;
+}
+
+/*
+ * Examine/modify value
+ */
+static int acpi_do_ulong(ctl_table *ctl,
+ int write,
+ struct file *file,
+ void *buffer,
+ size_t *len)
+{
+ char str[2 * sizeof(unsigned long) + 4], *strend;
+ unsigned long val;
+ int size;
+
+ if (!write) {
+ if (file->f_pos) {
+ *len = 0;
+ return 0;
+ }
+
+ val = *(unsigned long*) ctl->data;
+ size = sprintf(str, "0x%08lx\n", val);
+ if (*len >= size) {
+ copy_to_user(buffer, str, size);
+ *len = size;
+ }
+ else
+ *len = 0;
+ }
+ else {
+ size = sizeof(str) - 1;
+ if (size > *len)
+ size = *len;
+ copy_from_user(str, buffer, size);
+ str[size] = '\0';
+ val = simple_strtoul(str, &strend, 0);
+ if (strend == str)
+ return -EINVAL;
+ *(unsigned long*) ctl->data = val;
+ }
+
+ file->f_pos += *len;
+ return 0;
+}
+
+/*
+ * Examine/modify event register
+ */
+static int acpi_do_event_reg(ctl_table *ctl,
+ int write,
+ struct file *file,
+ void *buffer,
+ size_t *len)
+{
+ char str[2 * sizeof(u32) + 4], *strend;
+ u32 val, enabling;
+ int size;
+
+ if (!write) {
+ if (file->f_pos) {
+ *len = 0;
+ return 0;
+ }
+
+ val = 0;
+ switch (ctl->ctl_name) {
+ case ACPI_PM1_ENABLE:
+ val = acpi_read_pm1_enable(acpi_facp);
+ break;
+ case ACPI_GPE_ENABLE:
+ val = acpi_read_gpe_enable(acpi_facp);
+ break;
+ case ACPI_GPE_LEVEL:
+ val = acpi_gpe_level;
+ break;
+ }
+
+ size = sprintf(str, "0x%08x\n", val);
+ if (*len >= size) {
+ copy_to_user(buffer, str, size);
+ *len = size;
+ }
+ else
+ *len = 0;
+ }
+ else
+ {
+ // fetch user value
+ size = sizeof(str) - 1;
+ if (size > *len)
+ size = *len;
+ copy_from_user(str, buffer, size);
+ str[size] = '\0';
+ val = (u32) simple_strtoul(str, &strend, 0);
+ if (strend == str)
+ return -EINVAL;
+
+ // store value in register
+ switch (ctl->ctl_name) {
+ case ACPI_PM1_ENABLE:
+ // clear previously disabled events
+ enabling = (val
+ & ~acpi_read_pm1_enable(acpi_facp));
+ acpi_write_pm1_status(acpi_facp, enabling);
+
+ if (val) {
+ // enable ACPI unless it is already
+ if (!acpi_is_enabled(acpi_facp))
+ acpi_enable(acpi_facp);
+ }
+ else if (!acpi_read_gpe_enable(acpi_facp)) {
+ // disable ACPI unless it is already
+ if (acpi_is_enabled(acpi_facp))
+ acpi_disable(acpi_facp);
+ }
+
+ acpi_write_pm1_enable(acpi_facp, val);
+ break;
+ case ACPI_GPE_ENABLE:
+ // clear previously disabled events
+ enabling = (val
+ & ~acpi_read_gpe_enable(acpi_facp));
+ while (acpi_read_gpe_status(acpi_facp) & enabling)
+ acpi_write_gpe_status(acpi_facp, enabling);
+
+ if (val) {
+ // enable ACPI unless it is already
+ if (!acpi_is_enabled(acpi_facp))
+ acpi_enable(acpi_facp);
+ }
+ else if (!acpi_read_pm1_enable(acpi_facp)) {
+ // disable ACPI unless it is already
+ if (acpi_is_enabled(acpi_facp))
+ acpi_disable(acpi_facp);
+ }
+
+ acpi_write_gpe_enable(acpi_facp, val);
+ break;
+ case ACPI_GPE_LEVEL:
+ acpi_gpe_level = val;
+ break;
+ }
+ }
+
+ file->f_pos += *len;
+ return 0;
+}
+
+/*
+ * Wait for next event
+ */
+static int acpi_do_event(ctl_table *ctl,
+ int write,
+ struct file *file,
+ void *buffer,
+ size_t *len)
+{
+ u32 pm1_status = 0, gpe_status = 0;
+ acpi_sstate_t event_state = 0;
+ char str[27];
+ int size;
+
+ if (write)
+ return -EPERM;
+ if (*len < sizeof(str)) {
+ *len = 0;
+ return 0;
+ }
+
+ for (;;) {
+ unsigned long flags;
+
+ // we need an atomic exchange here
+ spin_lock_irqsave(&acpi_event_lock, flags);
+ pm1_status = acpi_pm1_status;
+ acpi_pm1_status = 0;
+ 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;
+
+ // wait for an event to arrive
+ interruptible_sleep_on(&acpi_event_wait);
+ if (signal_pending(current))
+ return -ERESTARTSYS;
+ }
+
+ 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;
+}
+
+/*
+ * Enter system sleep state
+ */
+static int acpi_do_sleep(ctl_table *ctl,
+ int write,
+ struct file *file,
+ void *buffer,
+ size_t *len)
+{
+ if (!write) {
+ if (file->f_pos) {
+ *len = 0;
+ return 0;
+ }
+ }
+ else
+ {
+#ifdef CONFIG_ACPI_S1_SLEEP
+ acpi_enter_sx(ACPI_S1);
+ acpi_enter_sx(ACPI_S0);
+#endif
+ }
+ file->f_pos += *len;
+ return 0;
+}
+
+/*
+ * Initialize and enable ACPI
+ */
+static int __init acpi_init(void)
+{
+ int pid;
+
+ if (acpi_disabled)
+ return -ENODEV;
+
+ if (acpi_find_tables() && acpi_find_piix4()) {
+ // no ACPI tables and not PIIX4
+ return -ENODEV;
+ }
+
+ /*
+ * Internally we always keep latencies in timer
+ * ticks, which is simpler and more consistent (what is
+ * an uS to us?). Besides, that gives people more
+ * control in the /proc interfaces.
+ */
+ if (acpi_facp->p_lvl2_lat
+ && acpi_facp->p_lvl2_lat <= ACPI_MAX_P_LVL2_LAT) {
+ acpi_p_lvl2_lat = ACPI_uS_TO_TMR_TICKS(acpi_facp->p_lvl2_lat);
+ acpi_enter_lvl2_lat = ACPI_uS_TO_TMR_TICKS(ACPI_TMR_HZ / 1000);
+ }
+ if (acpi_facp->p_lvl3_lat
+ && acpi_facp->p_lvl3_lat <= ACPI_MAX_P_LVL3_LAT) {
+ acpi_p_lvl3_lat = ACPI_uS_TO_TMR_TICKS(acpi_facp->p_lvl3_lat);
+ acpi_enter_lvl3_lat
+ = ACPI_uS_TO_TMR_TICKS(acpi_facp->p_lvl3_lat * 5);
+ }
+
+ if (acpi_facp->sci_int
+ && request_irq(acpi_facp->sci_int,
+ acpi_irq,
+ SA_INTERRUPT | SA_SHIRQ,
+ "acpi",
+ acpi_facp)) {
+ printk(KERN_ERR "ACPI: SCI (IRQ%d) allocation failed\n",
+ acpi_facp->sci_int);
+ acpi_destroy_tables();
+ return -ENODEV;
+ }
+
+ acpi_claim_ioports(acpi_facp);
+ acpi_sysctl = register_sysctl_table(acpi_dir_table, 1);
+
+ pid = kernel_thread(acpi_control_thread,
+ NULL,
+ CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
+
+ acpi_power_off = acpi_power_off_handler;
+
+ acpi_active = 1;
+
+ /*
+ * Set up the ACPI idle function. Note that we can't really
+ * do this with multiple CPU's, we'd need a per-CPU ACPI
+ * device..
+ */
+#ifdef __SMP__
+ if (smp_num_cpus > 1)
+ return 0;
+#endif
+
+ if (acpi_facp->pm_tmr)
+ acpi_idle = acpi_idle_handler;
+
+ return 0;
+}
+
+/*
+ * Disable and deinitialize ACPI
+ */
+static void __exit acpi_exit(void)
+{
+ acpi_idle = NULL;
+ acpi_power_off = NULL;
+
+ unregister_sysctl_table(acpi_sysctl);
+ acpi_disable(acpi_facp);
+ acpi_release_ioports(acpi_facp);
+
+ if (acpi_facp->sci_int)
+ free_irq(acpi_facp->sci_int, acpi_facp);
+
+ acpi_destroy_tables();
+}
+
+static int __init acpi_setup(char *str)
+{
+ while (str && *str) {
+ if (strncmp(str, "off", 3) == 0)
+ acpi_disabled = 1;
+ else if (strncmp(str, "on", 2) == 0)
+ acpi_disabled = 0;
+ str = strpbrk(str, ",");
+ if (str)
+ str += strspn(str, ",");
+ }
+ return 1;
+}
+
+__setup("acpi=", acpi_setup);
+
+/*
+ * Register a device with the ACPI subsystem
+ */
+struct acpi_dev* acpi_register(struct acpi_dev_info *info, unsigned long adr)
+{
+ struct acpi_dev *dev = NULL;
+ if (info) {
+ dev = kmalloc(sizeof(struct acpi_dev), GFP_KERNEL);
+ if (dev) {
+ unsigned long flags;
+
+ memset(dev, 0, sizeof(*dev));
+ memcpy(&dev->info, info, sizeof(dev->info));
+ dev->adr = adr;
+
+ spin_lock_irqsave(&acpi_devs_lock, flags);
+ list_add(&dev->entry, &acpi_devs);
+ spin_unlock_irqrestore(&acpi_devs_lock, flags);
+ }
+ }
+ return dev;
+}
+
+/*
+ * Unregister a device with ACPI
+ */
+void acpi_unregister(struct acpi_dev *dev)
+{
+ if (dev) {
+ unsigned long flags;
+
+ spin_lock_irqsave(&acpi_devs_lock, flags);
+ list_del(&dev->entry);
+ spin_unlock_irqrestore(&acpi_devs_lock, flags);
+
+ kfree(dev);
+ }
+}
+
+/*
+ * Wake up a device
+ */
+void acpi_wakeup(struct acpi_dev *dev)
+{
+ // run _PS0 or tell parent bus to wake device up
+}
+
+/*
+ * Manage idle devices
+ */
+static int acpi_control_thread(void *context)
+{
+ exit_mm(current);
+ exit_files(current);
+ strcpy(current->comm, "acpi");
+
+ for(;;) {
+ interruptible_sleep_on(&acpi_control_wait);
+ if (signal_pending(current))
+ break;
+
+ // find all idle devices and set idle timer
+ }
+
+ return 0;
+}
+
+__initcall(acpi_init);
+
+/*
+ * Module visible symbols
+ */
+EXPORT_SYMBOL(acpi_control_wait);
+EXPORT_SYMBOL(acpi_register);
+EXPORT_SYMBOL(acpi_unregister);
+EXPORT_SYMBOL(acpi_wakeup);
diff --git a/arch/i386/kernel/apm.c b/arch/i386/kernel/apm.c
index 564e6b42b..8f3d24645 100644
--- a/arch/i386/kernel/apm.c
+++ b/arch/i386/kernel/apm.c
@@ -34,6 +34,7 @@
* Jan 1999, Version 1.8
* Jan 1999, Version 1.9
* Oct 1999, Version 1.10
+ * Nov 1999, Version 1.11
*
* History:
* 0.6b: first version in official kernel, Linux 1.3.46
@@ -101,6 +102,14 @@
* configurable (default on).
* Make debug only a boot time parameter (remove APM_DEBUG).
* Try to blank all devices on any error.
+ * 1.11: Remove APM dependencies in drivers/char/console.c
+ * Check nr_running to detect if we are idle (from
+ * Borislav Deianov <borislav@lix.polytechnique.fr>)
+ * Fix for bioses that don't zero the top part of the
+ * entrypoint offset (Mario Sitta <sitta@al.unipmn.it>)
+ * (reported by Panos Katsaloulis <teras@writeme.com>).
+ * Real mode power off patch (Walter Hofmann
+ * <Walter.Hofmann@physik.stud.uni-erlangen.de>).
*
* APM 1.1 Reference:
*
@@ -135,6 +144,7 @@
#include <linux/miscdevice.h>
#include <linux/apm_bios.h>
#include <linux/init.h>
+#include <linux/sched.h>
#include <asm/system.h>
#include <asm/uaccess.h>
@@ -149,8 +159,14 @@ EXPORT_SYMBOL(apm_register_callback);
EXPORT_SYMBOL(apm_unregister_callback);
extern unsigned long get_cmos_time(void);
+extern void machine_real_restart(unsigned char *, int);
+#ifdef CONFIG_MAGIC_SYSRQ
extern void (*sysrq_power_off)(void);
+#endif
+#if defined(CONFIG_APM_DISPLAY_BLANK) && defined(CONFIG_VT)
+extern int (*console_blank_hook)(int);
+#endif
/*
* The apm_bios device is one of the misc char devices.
@@ -269,7 +285,7 @@ static int power_off_enabled = 1;
static DECLARE_WAIT_QUEUE_HEAD(apm_waitqueue);
static struct apm_bios_struct * user_list = NULL;
-static char driver_version[] = "1.10"; /* no spaces */
+static char driver_version[] = "1.11"; /* no spaces */
static char * apm_event_name[] = {
"system standby",
@@ -380,7 +396,7 @@ static u8 apm_bios_call(u32 func, u32 ebx_in, u32 ecx_in,
__asm__ __volatile__(APM_DO_ZERO_SEGS
"pushl %%edi\n\t"
"pushl %%ebp\n\t"
- "lcall %%cs:" SYMBOL_NAME_STR(apm_bios_entry) "; cld\n\t"
+ "lcall %%cs:" SYMBOL_NAME_STR(apm_bios_entry) "\n\t"
"setc %%al\n\t"
"popl %%ebp\n\t"
"popl %%edi\n\t"
@@ -413,7 +429,7 @@ static u8 apm_bios_call_simple(u32 func, u32 ebx_in, u32 ecx_in, u32 *eax)
__asm__ __volatile__(APM_DO_ZERO_SEGS
"pushl %%edi\n\t"
"pushl %%ebp\n\t"
- "lcall %%cs:" SYMBOL_NAME_STR(apm_bios_entry)"; cld\n\t"
+ "lcall %%cs:" SYMBOL_NAME_STR(apm_bios_entry)"\n\t"
"setc %%bl\n\t"
"popl %%ebp\n\t"
"popl %%edi\n\t"
@@ -551,24 +567,24 @@ static void apm_power_off(void)
* they are doing because they booted with the smp-power-off
* kernel option.
*/
- if (apm_enabled || (smp_hack == 2))
+ if (apm_enabled || (smp_hack == 2)) {
+#ifdef CONFIG_APM_REAL_MODE_POWER_OFF
+ unsigned char po_bios_call[] = {
+ 0xb8, 0x00, 0x10, /* movw $0x1000,ax */
+ 0x8e, 0xd0, /* movw ax,ss */
+ 0xbc, 0x00, 0xf0, /* movw $0xf000,sp */
+ 0xb8, 0x07, 0x53, /* movw $0x5307,ax */
+ 0xbb, 0x01, 0x00, /* movw $0x0001,bx */
+ 0xb9, 0x03, 0x00, /* movw $0x0003,cx */
+ 0xcd, 0x15 /* int $0x15 */
+ };
+
+ machine_real_restart(po_bios_call, sizeof(po_bios_call));
+#else
(void) apm_set_power_state(APM_STATE_OFF);
-}
-
-#ifdef CONFIG_APM_DISPLAY_BLANK
-/* Called by apm_display_blank and apm_display_unblank when apm_enabled. */
-static int apm_set_display_power_state(u_short state)
-{
- int error;
-
- /* Blank the first display device */
- error = set_power_state(0x0100, state);
- if (error != APM_SUCCESS)
- /* try to blank them all instead */
- error = set_power_state(0x01ff, state);
- return error;
-}
#endif
+ }
+}
#ifdef CONFIG_APM_DO_ENABLE
static int __init apm_enable_power_management(void)
@@ -651,33 +667,25 @@ static void apm_error(char *str, int err)
str, err);
}
+#if defined(CONFIG_APM_DISPLAY_BLANK) && defined(CONFIG_VT)
/* Called from console driver -- must make sure apm_enabled. */
-int apm_display_blank(void)
+static int apm_console_blank(int blank)
{
-#ifdef CONFIG_APM_DISPLAY_BLANK
- if (apm_enabled) {
- int error = apm_set_display_power_state(APM_STATE_STANDBY);
- if ((error == APM_SUCCESS) || (error == APM_NO_ERROR))
- return 1;
- apm_error("set display standby", error);
- }
-#endif
- return 0;
-}
+ int error;
+ u_short state;
-/* Called from console driver -- must make sure apm_enabled. */
-int apm_display_unblank(void)
-{
-#ifdef CONFIG_APM_DISPLAY_BLANK
- if (apm_enabled) {
- int error = apm_set_display_power_state(APM_STATE_READY);
- if ((error == APM_SUCCESS) || (error == APM_NO_ERROR))
- return 1;
- apm_error("set display ready", error);
- }
-#endif
+ state = blank ? APM_STATE_STANDBY : APM_STATE_READY;
+ /* Blank the first display device */
+ error = set_power_state(0x100, state);
+ if (error != APM_SUCCESS)
+ /* try to blank them all instead */
+ error = set_power_state(0x1ff, state);
+ if ((error == APM_SUCCESS) || (error == APM_NO_ERROR))
+ return 1;
+ apm_error("set display", error);
return 0;
}
+#endif
int apm_register_callback(int (*callback)(apm_event_t))
{
@@ -884,12 +892,15 @@ static void check_events(void)
case APM_USER_STANDBY:
#ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND
if (waiting_for_resume)
- return;
- waiting_for_resume = 1;
+ break;
#endif
- if (send_event(event, APM_STANDBY_RESUME, NULL)
- && (standbys_pending <= 0))
- standby();
+ if (send_event(event, APM_STANDBY_RESUME, NULL)) {
+#ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND
+ waiting_for_resume = 1;
+#endif
+ if (standbys_pending <= 0)
+ standby();
+ }
break;
case APM_USER_SUSPEND:
@@ -905,12 +916,15 @@ static void check_events(void)
#endif
#ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND
if (waiting_for_resume)
- return;
- waiting_for_resume = 1;
+ break;
+#endif
+ if (send_event(event, APM_NORMAL_RESUME, NULL)) {
+#ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND
+ waiting_for_resume = 1;
#endif
- if (send_event(event, APM_NORMAL_RESUME, NULL)
- && (suspends_pending <= 0))
- suspend();
+ if (suspends_pending <= 0)
+ suspend();
+ }
break;
case APM_NORMAL_RESUME:
@@ -947,21 +961,18 @@ static void check_events(void)
static void apm_event_handler(void)
{
static int pending_count = 0;
+ int err;
- if (((standbys_pending > 0) || (suspends_pending > 0))
- && (apm_bios_info.version > 0x100)) {
- if (pending_count-- <= 0) {
- int err;
-
+ if ((standbys_pending > 0) || (suspends_pending > 0)) {
+ if ((apm_bios_info.version > 0x100) && (pending_count-- <= 0)) {
pending_count = 4;
err = apm_set_power_state(APM_STATE_BUSY);
if (err)
apm_error("busy", err);
}
- } else {
+ } else
pending_count = 0;
- check_events();
- }
+ check_events();
}
/*
@@ -970,12 +981,8 @@ static void apm_event_handler(void)
* Check whether we're the only running process to
* decide if we should just power down.
*
- * Do this by checking the runqueue: if we're the
- * only one, then the current process run_list will
- * have both prev and next pointing to the same
- * entry (the true idle process)
*/
-#define system_idle() (current->run_list.next == current->run_list.prev)
+#define system_idle() (nr_running == 1)
static void apm_mainloop(void)
{
@@ -1367,10 +1374,13 @@ static int apm(void *unused)
/* Install our power off handler.. */
if (power_off_enabled)
acpi_power_off = apm_power_off;
-
#ifdef CONFIG_MAGIC_SYSRQ
sysrq_power_off = apm_power_off;
#endif
+#if defined(CONFIG_APM_DISPLAY_BLANK) && defined(CONFIG_VT)
+ console_blank_hook = apm_console_blank;
+#endif
+
apm_mainloop();
return 0;
}
@@ -1481,6 +1491,13 @@ static int __init apm_init(void)
APM_INIT_ERROR_RETURN;
}
+#ifdef CONFIG_ACPI
+ if (acpi_active) {
+ printk(KERN_NOTICE "apm: overridden by ACPI.\n");
+ APM_INIT_ERROR_RETURN;
+ }
+#endif
+
/*
* Set up a segment that references the real mode segment 0x40
* that extends up to the end of page zero (that we have reserved).
@@ -1492,6 +1509,9 @@ static int __init apm_init(void)
_set_limit((char *)&gdt[APM_40 >> 3], 4095 - (0x40 << 4));
apm_bios_entry.offset = apm_bios_info.offset;
+#ifdef CONFIG_APM_BAD_ENTRY_OFFSET
+ apm_bios_entry.offset &= 0xffff;
+#endif
apm_bios_entry.segment = APM_CS;
set_base(gdt[APM_CS >> 3],
__va((unsigned long)apm_bios_info.cseg << 4));
diff --git a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S
index 4eef2d8c9..ecfe0697d 100644
--- a/arch/i386/kernel/entry.S
+++ b/arch/i386/kernel/entry.S
@@ -92,8 +92,8 @@ ENOSYS = 38
pushl %ecx; \
pushl %ebx; \
movl $(__KERNEL_DS),%edx; \
- movl %dx,%ds; \
- movl %dx,%es;
+ movl %edx,%ds; \
+ movl %edx,%es;
#define RESTORE_ALL \
popl %ebx; \
@@ -288,15 +288,15 @@ error_code:
pushl %ecx
pushl %ebx
cld
- movl %es,%cx
+ movl %es,%ecx
xchgl %eax, ORIG_EAX(%esp) # orig_eax (get the error code. )
movl %esp,%edx
xchgl %ecx, ES(%esp) # get the address and save es.
pushl %eax # push the error code
pushl %edx
movl $(__KERNEL_DS),%edx
- movl %dx,%ds
- movl %dx,%es
+ movl %edx,%ds
+ movl %edx,%es
GET_CURRENT(%ebx)
call *%ecx
addl $8,%esp
@@ -595,7 +595,10 @@ ENTRY(sys_call_table)
.long SYMBOL_NAME(sys_mmap2)
.long SYMBOL_NAME(sys_truncate64)
.long SYMBOL_NAME(sys_ftruncate64)
- /* 195 */
+ .long SYMBOL_NAME(sys_stat64) /* 195 */
+ .long SYMBOL_NAME(sys_lstat64)
+ .long SYMBOL_NAME(sys_fstat64)
+
/*
* NOTE!! This doesn't have to be exact - we just have
@@ -603,6 +606,6 @@ ENTRY(sys_call_table)
* entries. Don't panic if you notice that this hasn't
* been shrunk every time we add a new system call.
*/
- .rept NR_syscalls-194
+ .rept NR_syscalls-197
.long SYMBOL_NAME(sys_ni_syscall)
.endr
diff --git a/arch/i386/kernel/head.S b/arch/i386/kernel/head.S
index b3f1335d0..0c8250ad3 100644
--- a/arch/i386/kernel/head.S
+++ b/arch/i386/kernel/head.S
@@ -47,10 +47,10 @@ startup_32:
*/
cld
movl $(__KERNEL_DS),%eax
- movl %ax,%ds
- movl %ax,%es
- movl %ax,%fs
- movl %ax,%gs
+ movl %eax,%ds
+ movl %eax,%es
+ movl %eax,%fs
+ movl %eax,%gs
#ifdef __SMP__
orw %bx,%bx
jz 1f
@@ -133,9 +133,9 @@ startup_32:
movl $ SYMBOL_NAME(empty_zero_page)+2048,%edi
movzwl CL_OFFSET,%esi
addl $(CL_BASE_ADDR),%esi
- movl $2048,%ecx
+ movl $512,%ecx
rep
- movsb
+ movsl
1:
#ifdef __SMP__
checkCPUtype:
@@ -231,13 +231,13 @@ is386: pushl %ecx # restore original EFLAGS
lidt idt_descr
ljmp $(__KERNEL_CS),$1f
1: movl $(__KERNEL_DS),%eax # reload all the segment registers
- movl %ax,%ds # after changing gdt.
- movl %ax,%es
- movl %ax,%fs
- movl %ax,%gs
+ movl %eax,%ds # after changing gdt.
+ movl %eax,%es
+ movl %eax,%fs
+ movl %eax,%gs
#ifdef __SMP__
movl $(__KERNEL_DS), %eax
- mov %ax,%ss # Reload the stack pointer (segment only)
+ movl %eax,%ss # Reload the stack pointer (segment only)
#else
lss stack_start,%esp # Load processor stack
#endif
@@ -323,8 +323,8 @@ ignore_int:
pushl %es
pushl %ds
movl $(__KERNEL_DS),%eax
- movl %ax,%ds
- movl %ax,%es
+ movl %eax,%ds
+ movl %eax,%es
pushl $int_msg
call SYMBOL_NAME(printk)
popl %eax
diff --git a/arch/i386/kernel/i386_ksyms.c b/arch/i386/kernel/i386_ksyms.c
index 3c72c9cb5..9f75d94bf 100644
--- a/arch/i386/kernel/i386_ksyms.c
+++ b/arch/i386/kernel/i386_ksyms.c
@@ -56,6 +56,9 @@ EXPORT_SYMBOL_NOVERS(__down_failed);
EXPORT_SYMBOL_NOVERS(__down_failed_interruptible);
EXPORT_SYMBOL_NOVERS(__down_failed_trylock);
EXPORT_SYMBOL_NOVERS(__up_wakeup);
+EXPORT_SYMBOL_NOVERS(__down_write_failed);
+EXPORT_SYMBOL_NOVERS(__down_read_failed);
+EXPORT_SYMBOL_NOVERS(__rwsem_wake);
/* Networking helper routines. */
EXPORT_SYMBOL(csum_partial_copy);
EXPORT_SYMBOL(csum_partial_copy_generic);
diff --git a/arch/i386/kernel/irq.c b/arch/i386/kernel/irq.c
index 041e44320..a111eb516 100644
--- a/arch/i386/kernel/irq.c
+++ b/arch/i386/kernel/irq.c
@@ -707,9 +707,11 @@ void free_irq(unsigned int irq, void *dev_id)
}
spin_unlock_irqrestore(&irq_controller_lock,flags);
+#ifdef __SMP__
/* Wait to make sure it's not being used on another CPU */
while (irq_desc[irq].status & IRQ_INPROGRESS)
barrier();
+#endif
kfree(action);
return;
}
@@ -731,6 +733,7 @@ unsigned long probe_irq_on(void)
{
unsigned int i;
unsigned long delay;
+ unsigned long val;
/*
* first, enable any unassigned irqs
@@ -754,6 +757,7 @@ unsigned long probe_irq_on(void)
/*
* Now filter out any obviously spurious interrupts
*/
+ val = 0;
spin_lock_irq(&irq_controller_lock);
for (i=0; i<NR_IRQS; i++) {
unsigned int status = irq_desc[i].status;
@@ -766,18 +770,50 @@ unsigned long probe_irq_on(void)
irq_desc[i].status = status & ~IRQ_AUTODETECT;
irq_desc[i].handler->shutdown(i);
}
+
+ if (i < 32)
+ val |= 1 << i;
}
spin_unlock_irq(&irq_controller_lock);
- return 0x12345678;
+ return val;
}
-int probe_irq_off(unsigned long unused)
+/*
+ * Return a mask of triggered interrupts (this
+ * can handle only legacy ISA interrupts).
+ */
+unsigned int probe_irq_mask(unsigned long val)
{
- int i, irq_found, nr_irqs;
+ int i;
+ unsigned int mask;
+
+ mask = 0;
+ spin_lock_irq(&irq_controller_lock);
+ for (i = 0; i < 16; i++) {
+ unsigned int status = irq_desc[i].status;
+
+ if (!(status & IRQ_AUTODETECT))
+ continue;
- if (unused != 0x12345678)
- printk("Bad IRQ probe from %lx\n", (&unused)[-1]);
+ if (!(status & IRQ_WAITING))
+ mask |= 1 << i;
+
+ irq_desc[i].status = status & ~IRQ_AUTODETECT;
+ irq_desc[i].handler->shutdown(i);
+ }
+ spin_unlock_irq(&irq_controller_lock);
+
+ return mask & val;
+}
+
+/*
+ * Return the one interrupt that triggered (this can
+ * handle any interrupt source)
+ */
+int probe_irq_off(unsigned long val)
+{
+ int i, irq_found, nr_irqs;
nr_irqs = 0;
irq_found = 0;
diff --git a/arch/i386/kernel/mtrr.c b/arch/i386/kernel/mtrr.c
index 1c1f6b74b..0061bc14d 100644
--- a/arch/i386/kernel/mtrr.c
+++ b/arch/i386/kernel/mtrr.c
@@ -139,41 +139,41 @@
Changed locking to spin with reschedule.
Made use of new <smp_call_function>.
v1.28
- 19990201 Zoltan Boszormenyi <zboszor@mol.hu>
+ 19990201 Zoltán Böszörményi <zboszor@mail.externet.hu>
Extended the driver to be able to use Cyrix style ARRs.
19990204 Richard Gooch <rgooch@atnf.csiro.au>
Restructured Cyrix support.
v1.29
- 19990204 Zoltan Boszormenyi <zboszor@mol.hu>
+ 19990204 Zoltán Böszörményi <zboszor@mail.externet.hu>
Refined ARR support: enable MAPEN in set_mtrr_prepare()
and disable MAPEN in set_mtrr_done().
19990205 Richard Gooch <rgooch@atnf.csiro.au>
Minor cleanups.
v1.30
- 19990208 Zoltan Boszormenyi <zboszor@mol.hu>
+ 19990208 Zoltán Böszörményi <zboszor@mail.externet.hu>
Protect plain 6x86s (and other processors without the
Page Global Enable feature) against accessing CR4 in
set_mtrr_prepare() and set_mtrr_done().
19990210 Richard Gooch <rgooch@atnf.csiro.au>
Turned <set_mtrr_up> and <get_mtrr> into function pointers.
v1.31
- 19990212 Zoltan Boszormenyi <zboszor@mol.hu>
+ 19990212 Zoltán Böszörményi <zboszor@mail.externet.hu>
Major rewrite of cyrix_arr_init(): do not touch ARRs,
leave them as the BIOS have set them up.
Enable usage of all 8 ARRs.
Avoid multiplications by 3 everywhere and other
code clean ups/speed ups.
- 19990213 Zoltan Boszormenyi <zboszor@mol.hu>
+ 19990213 Zoltán Böszörményi <zboszor@mail.externet.hu>
Set up other Cyrix processors identical to the boot cpu.
Since Cyrix don't support Intel APIC, this is l'art pour l'art.
Weigh ARRs by size:
If size <= 32M is given, set up ARR# we were given.
If size > 32M is given, set up ARR7 only if it is free,
fail otherwise.
- 19990214 Zoltan Boszormenyi <zboszor@mol.hu>
+ 19990214 Zoltán Böszörményi <zboszor@mail.externet.hu>
Also check for size >= 256K if we are to set up ARR7,
mtrr_add() returns the value it gets from set_mtrr()
- 19990218 Zoltan Boszormenyi <zboszor@mol.hu>
+ 19990218 Zoltán Böszörményi <zboszor@mail.externet.hu>
Remove Cyrix "coma bug" workaround from here.
Moved to linux/arch/i386/kernel/setup.c and
linux/include/asm-i386/bugs.h
@@ -187,7 +187,7 @@
19990305 Richard Gooch <rgooch@atnf.csiro.au>
Temporarily disable AMD support now MTRR capability flag is set.
v1.32
- 19990308 Zoltan Boszormenyi <zboszor@mol.hu>
+ 19990308 Zoltán Böszörményi <zboszor@mail.externet.hu>
Adjust my changes (19990212-19990218) to Richard Gooch's
latest changes. (19990228-19990305)
v1.33
@@ -201,23 +201,23 @@
19990512 Richard Gooch <rgooch@atnf.csiro.au>
Minor cleanups.
v1.35
- 19990707 Zoltan Boszormenyi <zboszor@mol.hu>
+ 19990707 Zoltán Böszörményi <zboszor@mail.externet.hu>
Check whether ARR3 is protected in cyrix_get_free_region()
and mtrr_del(). The code won't attempt to delete or change it
from now on if the BIOS protected ARR3. It silently skips ARR3
in cyrix_get_free_region() or returns with an error code from
mtrr_del().
- 19990711 Zoltan Boszormenyi <zboszor@mol.hu>
+ 19990711 Zoltán Böszörményi <zboszor@mail.externet.hu>
Reset some bits in the CCRs in cyrix_arr_init() to disable SMM
if ARR3 isn't protected. This is needed because if SMM is active
and ARR3 isn't protected then deleting and setting ARR3 again
may lock up the processor. With SMM entirely disabled, it does
not happen.
- 19990812 Zoltan Boszormenyi <zboszor@mol.hu>
+ 19990812 Zoltán Böszörményi <zboszor@mail.externet.hu>
Rearrange switch() statements so the driver accomodates to
the fact that the AMD Athlon handles its MTRRs the same way
as Intel does.
- 19990814 Zoltan Boszormenyi <zboszor@mol.hu>
+ 19990814 Zoltán Böszörményi <zboszor@mail.externet.hu>
Double check for Intel in mtrr_add()'s big switch() because
that revision check is only valid for Intel CPUs.
19990819 Alan Cox <alan@redhat.com>
@@ -957,11 +957,11 @@ static void set_mtrr_smp (unsigned int reg, unsigned long base,
wait_barrier_execute = TRUE;
wait_barrier_cache_enable = TRUE;
atomic_set (&undone_count, smp_num_cpus - 1);
- /* Flush and disable the local CPU's cache and start the ball rolling on
- other CPUs */
- set_mtrr_prepare (&ctxt);
+ /* Start the ball rolling on other CPUs */
if (smp_call_function (ipi_handler, &data, 1, 0) != 0)
panic ("mtrr: timed out waiting for other CPUs\n");
+ /* Flush and disable the local CPU's cache */
+ set_mtrr_prepare (&ctxt);
/* Wait for all other CPUs to flush and disable their caches */
while (atomic_read (&undone_count) > 0) barrier ();
/* Set up for completion wait and then release other CPUs to change MTRRs*/
@@ -1481,8 +1481,6 @@ static struct file_operations mtrr_fops =
mtrr_close, /* Release */
NULL, /* Fsync */
NULL, /* Fasync */
- NULL, /* CheckMediaChange */
- NULL, /* Revalidate */
NULL, /* Lock */
};
diff --git a/arch/i386/kernel/pci-i386.c b/arch/i386/kernel/pci-i386.c
index 746b21258..e94868cd9 100644
--- a/arch/i386/kernel/pci-i386.c
+++ b/arch/i386/kernel/pci-i386.c
@@ -12,7 +12,7 @@
* Hannover, Germany
* hm@ix.de
*
- * Copyright 1997--1999 Martin Mares <mj@suse.cz>
+ * Copyright 1997--2000 Martin Mares <mj@suse.cz>
*
* For more information, please consult the following manuals (look at
* http://www.pcisig.com/ for how to get them):
@@ -102,7 +102,7 @@
* Expects start=0, end=size-1, flags=resource type.
*/
-static int __init pcibios_assign_resource(struct pci_dev *dev, int i)
+int pci_assign_resource(struct pci_dev *dev, int i)
{
struct resource *r = &dev->resource[i];
struct resource *pr = pci_find_parent_resource(dev, r);
@@ -180,14 +180,17 @@ static int __init pcibios_assign_resource(struct pci_dev *dev, int i)
* as well.
*/
-static void __init pcibios_allocate_bus_resources(struct pci_bus *bus)
+static void __init pcibios_allocate_bus_resources(struct list_head *bus_list)
{
+ struct list_head *ln;
+ struct pci_bus *bus;
struct pci_dev *dev;
int idx;
struct resource *r, *pr;
/* Depth-First Search on bus tree */
- while (bus) {
+ for (ln=bus_list->next; ln != bus_list; ln=ln->next) {
+ bus = pci_bus_b(ln);
if ((dev = bus->self)) {
for (idx = PCI_BRIDGE_RESOURCES; idx < PCI_NUM_RESOURCES; idx++) {
r = &dev->resource[idx];
@@ -198,9 +201,7 @@ static void __init pcibios_allocate_bus_resources(struct pci_bus *bus)
printk(KERN_ERR "PCI: Cannot allocate resource region %d of bridge %s\n", idx, dev->slot_name);
}
}
- if (bus->children)
- pcibios_allocate_bus_resources(bus->children);
- bus = bus->next;
+ pcibios_allocate_bus_resources(&bus->children);
}
}
@@ -211,7 +212,7 @@ static void __init pcibios_allocate_resources(int pass)
u16 command;
struct resource *r, *pr;
- for(dev=pci_devices; dev; dev=dev->next) {
+ pci_for_each_dev(dev) {
pci_read_config_word(dev, PCI_COMMAND, &command);
for(idx = 0; idx < 6; idx++) {
r = &dev->resource[idx];
@@ -255,39 +256,46 @@ static void __init pcibios_assign_resources(void)
int idx;
struct resource *r;
- for(dev=pci_devices; dev; dev=dev->next) {
+ pci_for_each_dev(dev) {
+ int class = dev->class >> 8;
+
+ /* Don't touch classless devices and host bridges */
+ if (!class || class == PCI_CLASS_BRIDGE_HOST)
+ continue;
+
for(idx=0; idx<6; idx++) {
r = &dev->resource[idx];
- if (((dev->class >> 8) == PCI_CLASS_STORAGE_IDE && idx < 4) ||
- ((dev->class >> 8) == PCI_CLASS_DISPLAY_VGA && (r->flags & IORESOURCE_IO)) ||
- !dev->class || (dev->class >> 8) == PCI_CLASS_BRIDGE_HOST)
- /*
- * Don't touch IDE controllers and I/O ports of video cards!
- * Also avoid classless devices and host bridges.
- */
+
+ /*
+ * Don't touch IDE controllers and I/O ports of video cards!
+ */
+ if ((class == PCI_CLASS_STORAGE_IDE && idx < 4) ||
+ (class == PCI_CLASS_DISPLAY_VGA && (r->flags & IORESOURCE_IO)))
continue;
- if (!r->start && r->end) {
- /*
- * We shall assign a new address to this resource, either because
- * the BIOS forgot to do so or because we have decided the old
- * address was unusable for some reason.
- */
- pcibios_assign_resource(dev, idx);
- }
+
+ /*
+ * We shall assign a new address to this resource, either because
+ * the BIOS forgot to do so or because we have decided the old
+ * address was unusable for some reason.
+ */
+ if (!r->start && r->end)
+ pci_assign_resource(dev, idx);
}
+
if (pci_probe & PCI_ASSIGN_ROMS) {
r = &dev->resource[PCI_ROM_RESOURCE];
r->end -= r->start;
r->start = 0;
if (r->end)
- pcibios_assign_resource(dev, PCI_ROM_RESOURCE);
+ pci_assign_resource(dev, PCI_ROM_RESOURCE);
}
}
}
void __init pcibios_resource_survey(void)
{
- pcibios_allocate_bus_resources(pci_root);
+ DBG("PCI: Allocating resources\n");
+ pcibios_allocate_bus_resources(&pci_root_buses);
pcibios_allocate_resources(0);
pcibios_allocate_resources(1);
pcibios_assign_resources();
diff --git a/arch/i386/kernel/pci-pc.c b/arch/i386/kernel/pci-pc.c
index 9ee1d6355..6b7d65589 100644
--- a/arch/i386/kernel/pci-pc.c
+++ b/arch/i386/kernel/pci-pc.c
@@ -1,7 +1,7 @@
/*
* Low-Level PCI Support for PC
*
- * (c) 1999 Martin Mares <mj@suse.cz>
+ * (c) 1999--2000 Martin Mares <mj@suse.cz>
*/
#include <linux/config.h>
@@ -22,6 +22,8 @@
unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2;
+static struct pci_bus *pci_root_bus;
+
/*
* IRQ routing table provided by the BIOS
*/
@@ -624,26 +626,30 @@ static struct pci_ops * __init pci_find_bios(void)
static void __init pcibios_sort(void)
{
- struct pci_dev *dev = pci_devices;
- struct pci_dev **last = &pci_devices;
- struct pci_dev *d, **dd, *e;
- int idx;
+ LIST_HEAD(sorted_devices);
+ struct list_head *ln;
+ struct pci_dev *dev, *d;
+ int idx, found;
unsigned char bus, devfn;
DBG("PCI: Sorting device list...\n");
- while ((e = dev)) {
- idx = 0;
- while (pci_bios_find_device(e->vendor, e->device, idx, &bus, &devfn) == PCIBIOS_SUCCESSFUL) {
+ while (!list_empty(&pci_devices)) {
+ ln = pci_devices.next;
+ dev = pci_dev_g(ln);
+ idx = found = 0;
+ while (pci_bios_find_device(dev->vendor, dev->device, idx, &bus, &devfn) == PCIBIOS_SUCCESSFUL) {
idx++;
- for(dd=&dev; (d = *dd); dd = &d->next) {
+ for (ln=pci_devices.next; ln != &pci_devices; ln=ln->next) {
+ d = pci_dev_g(ln);
if (d->bus->number == bus && d->devfn == devfn) {
- *dd = d->next;
- *last = d;
- last = &d->next;
+ list_del(&d->global_list);
+ list_add_tail(&d->global_list, &sorted_devices);
+ if (d == dev)
+ found = 1;
break;
}
}
- if (!d) {
+ if (ln == &pci_devices) {
printk("PCI: BIOS reporting unknown device %02x:%02x\n", bus, devfn);
/*
* We must not continue scanning as several buggy BIOSes
@@ -652,16 +658,14 @@ static void __init pcibios_sort(void)
break;
}
}
- if (e == dev) {
+ if (!found) {
printk("PCI: Device %02x:%02x not found by BIOS\n",
dev->bus->number, dev->devfn);
- d = dev;
- dev = dev->next;
- *last = d;
- last = &d->next;
+ list_del(&dev->global_list);
+ list_add_tail(&dev->global_list, &sorted_devices);
}
}
- *last = NULL;
+ list_splice(&sorted_devices, &pci_devices);
}
/*
@@ -736,16 +740,19 @@ static struct irq_routing_table * __init pcibios_get_irq_routing_table(void)
static void __init pcibios_fixup_ghosts(struct pci_bus *b)
{
- struct pci_dev *d, *e, **z;
+ struct list_head *ln, *mn;
+ struct pci_dev *d, *e;
int mirror = PCI_DEVFN(16,0);
int seen_host_bridge = 0;
int i;
DBG("PCI: Scanning for ghost devices on bus %d\n", b->number);
- for(d=b->devices; d && d->devfn < mirror; d=d->sibling) {
+ for (ln=b->devices.next; ln != &b->devices; ln=ln->next) {
+ d = pci_dev_b(ln);
if ((d->class >> 8) == PCI_CLASS_BRIDGE_HOST)
seen_host_bridge++;
- for(e=d->next; e; e=e->sibling) {
+ for (mn=ln->next; mn != &b->devices; mn=mn->next) {
+ e = pci_dev_b(mn);
if (e->devfn != d->devfn + mirror ||
e->vendor != d->vendor ||
e->device != d->device ||
@@ -758,20 +765,23 @@ static void __init pcibios_fixup_ghosts(struct pci_bus *b)
continue;
break;
}
- if (!e)
+ if (mn == &b->devices)
return;
}
if (!seen_host_bridge)
return;
printk("PCI: Ignoring ghost devices on bus %02x\n", b->number);
- for(e=b->devices; e->sibling != d; e=e->sibling);
- e->sibling = NULL;
- for(z=&pci_devices; (d=*z);)
- if (d->bus == b && d->devfn >= mirror) {
- *z = d->next;
- kfree_s(d, sizeof(*d));
+
+ ln = &b->devices;
+ while (ln->next != &b->devices) {
+ d = pci_dev_b(ln->next);
+ if (d->devfn >= mirror) {
+ list_del(&d->global_list);
+ list_del(&d->bus_list);
+ kfree(d);
} else
- z = &d->next;
+ ln = ln->next;
+ }
}
/*
@@ -783,10 +793,10 @@ static void __init pcibios_fixup_ghosts(struct pci_bus *b)
*/
static void __init pcibios_fixup_peer_bridges(void)
{
- struct pci_bus *b = pci_root;
+ struct list_head *ln;
+ struct pci_bus *b = pci_root_bus;
int n, cnt=-1;
- struct pci_dev *d;
- struct pci_ops *ops = pci_root->ops;
+ struct pci_ops *ops = pci_root_bus->ops;
#ifdef CONFIG_PCI_DIRECT
/*
@@ -798,8 +808,10 @@ static void __init pcibios_fixup_peer_bridges(void)
return;
#endif
- for(d=b->devices; d; d=d->sibling)
- if ((d->class >> 8) == PCI_CLASS_BRIDGE_HOST)
+ DBG("PCI: Peer bridge fixup\n");
+
+ for(ln=b->devices.next; ln != &b->devices; ln=ln->next)
+ if ((pci_dev_b(ln)->class >> 8) == PCI_CLASS_BRIDGE_HOST)
cnt++;
n = b->subordinate + 1;
while (n <= 0xff) {
@@ -864,9 +876,9 @@ static void __init pci_fixup_i450nx(struct pci_dev *d)
pci_read_config_byte(d, reg++, &subb);
DBG("i450NX PXB %d: %02x/%02x/%02x\n", pxb, busno, suba, subb);
if (busno)
- pci_scan_bus(busno, pci_root->ops, NULL); /* Bus A */
+ pci_scan_bus(busno, pci_root_bus->ops, NULL); /* Bus A */
if (suba < subb)
- pci_scan_bus(suba+1, pci_root->ops, NULL); /* Bus B */
+ pci_scan_bus(suba+1, pci_root_bus->ops, NULL); /* Bus B */
}
}
@@ -879,7 +891,7 @@ static void __init pci_fixup_rcc(struct pci_dev *d)
u8 busno;
pci_read_config_byte(d, 0x44, &busno);
printk("PCI: RCC host bridge: secondary bus %02x\n", busno);
- pci_scan_bus(busno, pci_root->ops, NULL);
+ pci_scan_bus(busno, pci_root_bus->ops, NULL);
}
static void __init pci_fixup_compaq(struct pci_dev *d)
@@ -891,7 +903,7 @@ static void __init pci_fixup_compaq(struct pci_dev *d)
u8 busno;
pci_read_config_byte(d, 0xc8, &busno);
printk("PCI: Compaq host bridge: secondary bus %02x\n", busno);
- pci_scan_bus(busno, pci_root->ops, NULL);
+ pci_scan_bus(busno, pci_root_bus->ops, NULL);
}
static void __init pci_fixup_umc_ide(struct pci_dev *d)
@@ -1000,7 +1012,7 @@ static void __init pcibios_irq_peer_trick(struct irq_routing_table *rt)
* It might be a secondary bus, but in this case its parent is already
* known (ascending bus order) and therefore pci_scan_bus returns immediately.
*/
- if (busmap[i] && pci_scan_bus(i, pci_root->ops, NULL))
+ if (busmap[i] && pci_scan_bus(i, pci_root_bus->ops, NULL))
printk("PCI: Discovered primary peer bus %02x [IRQ]\n", i);
}
@@ -1077,6 +1089,7 @@ static char *pcibios_lookup_irq(struct pci_dev *dev, struct irq_routing_table *r
}
DBG(" -> [PIIX] sink\n");
return NULL;
+ case ID(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533):
default:
DBG(" -> unknown router %04x/%04x\n", rt->rtr_vendor, rt->rtr_device);
if (newirq && mask == (1 << newirq)) {
@@ -1095,6 +1108,7 @@ static void __init pcibios_fixup_irqs(void)
struct pci_dev *dev;
u8 pin;
+ DBG("PCI: IRQ fixup\n");
rtable = pirq_table = pcibios_find_irq_routing_table();
#ifdef CONFIG_PCI_BIOS
if (!rtable && pci_bios_present)
@@ -1104,7 +1118,7 @@ static void __init pcibios_fixup_irqs(void)
if (rtable)
pcibios_irq_peer_trick(rtable);
- for(dev=pci_devices; dev; dev=dev->next) {
+ pci_for_each_dev(dev) {
pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
#if defined(CONFIG_X86_IO_APIC)
/*
@@ -1197,7 +1211,7 @@ void __init pcibios_init(void)
}
printk("PCI: Probing PCI hardware\n");
- pci_scan_bus(0, ops, NULL);
+ pci_root_bus = pci_scan_bus(0, ops, NULL);
pcibios_fixup_irqs();
if (pci_probe & PCI_PEER_FIXUP)
diff --git a/arch/i386/kernel/pci-visws.c b/arch/i386/kernel/pci-visws.c
index 2ba24c8b3..401a4ee13 100644
--- a/arch/i386/kernel/pci-visws.c
+++ b/arch/i386/kernel/pci-visws.c
@@ -1,7 +1,7 @@
/*
* Low-Level PCI Support for SGI Visual Workstation
*
- * (c) 1999 Martin Mares <mj@suse.cz>
+ * (c) 1999--2000 Martin Mares <mj@suse.cz>
*/
#include <linux/config.h>
@@ -85,7 +85,7 @@ static void __init pcibios_fixup_irqs(void)
u8 pin;
int irq;
- for(dev=pci_devices; dev; dev=dev->next) {
+ pci_for_each_dev(dev) {
pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
dev->irq = 0;
if (!pin)
diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c
index 4f9c94353..703482425 100644
--- a/arch/i386/kernel/process.c
+++ b/arch/i386/kernel/process.c
@@ -69,6 +69,16 @@ void (*acpi_idle)(void) = NULL;
void (*acpi_power_off)(void) = NULL;
/*
+ * We use this if we don't have any better
+ * idle routine..
+ */
+static void default_idle(void)
+{
+ if (current_cpu_data.hlt_works_ok && !hlt_counter)
+ asm volatile("sti ; hlt" : : : "memory");
+}
+
+/*
* The idle thread. There's no useful work to be
* done, so just try to conserve power and have a
* low exit latency (ie sit in a loop waiting for
@@ -82,26 +92,16 @@ void cpu_idle(void)
current->counter = -100;
while (1) {
- while (!current->need_resched) {
- if (!current_cpu_data.hlt_works_ok)
- continue;
- if (hlt_counter)
- continue;
- asm volatile("sti ; hlt" : : : "memory");
- }
+ void (*idle)(void) = acpi_idle;
+ if (!idle)
+ idle = default_idle;
+ while (!current->need_resched)
+ idle();
schedule();
check_pgt_cache();
- if (acpi_idle)
- acpi_idle();
}
}
-/*
- * This routine reboots the machine by asking the keyboard
- * controller to pulse the reset-line low. We try that for a while,
- * and if it doesn't work, we do some other stupid things.
- */
-
static long no_idt[2] = {0, 0};
static int reboot_mode = 0;
static int reboot_thru_bios = 0;
@@ -187,7 +187,10 @@ static unsigned char real_mode_switch [] =
0x74, 0x02, /* jz f */
0x0f, 0x08, /* invd */
0x24, 0x10, /* f: andb $0x10,al */
- 0x66, 0x0f, 0x22, 0xc0, /* movl %eax,%cr0 */
+ 0x66, 0x0f, 0x22, 0xc0 /* movl %eax,%cr0 */
+};
+static unsigned char jump_to_bios [] =
+{
0xea, 0x00, 0x00, 0xff, 0xff /* ljmp $0xffff,$0x0000 */
};
@@ -200,34 +203,13 @@ static inline void kb_wait(void)
break;
}
-void machine_restart(char * __unused)
+/*
+ * Switch to real mode and then execute the code
+ * specified by the code and length parameters.
+ * We assume that length will aways be less that 100!
+ */
+void machine_real_restart(unsigned char *code, int length)
{
-#if __SMP__
- /*
- * Stop all CPUs and turn off local APICs and the IO-APIC, so
- * other OSs see a clean IRQ state.
- */
- smp_send_stop();
- disable_IO_APIC();
-#endif
-
- if(!reboot_thru_bios) {
- /* rebooting needs to touch the page at absolute addr 0 */
- *((unsigned short *)__va(0x472)) = reboot_mode;
- for (;;) {
- int i;
- for (i=0; i<100; i++) {
- kb_wait();
- udelay(50);
- outb(0xfe,0x64); /* pulse reset low */
- udelay(50);
- }
- /* That didn't work - force a triple fault.. */
- __asm__ __volatile__("lidt %0": :"m" (no_idt));
- __asm__ __volatile__("int3");
- }
- }
-
cli();
/* Write zero to CMOS register number 0x0f, which the BIOS POST
@@ -273,8 +255,9 @@ void machine_restart(char * __unused)
off paging. Copy it near the end of the first page, out of the way
of BIOS variables. */
- memcpy ((void *) (0x1000 - sizeof (real_mode_switch)),
+ memcpy ((void *) (0x1000 - sizeof (real_mode_switch) - 100),
real_mode_switch, sizeof (real_mode_switch));
+ memcpy ((void *) (0x1000 - 100), code, length);
/* Set up the IDT for real mode. */
@@ -293,11 +276,11 @@ void machine_restart(char * __unused)
the values are consistent for real mode operation already. */
__asm__ __volatile__ ("movl $0x0010,%%eax\n"
- "\tmovl %%ax,%%ds\n"
- "\tmovl %%ax,%%es\n"
- "\tmovl %%ax,%%fs\n"
- "\tmovl %%ax,%%gs\n"
- "\tmovl %%ax,%%ss" : : : "eax");
+ "\tmovl %%eax,%%ds\n"
+ "\tmovl %%eax,%%es\n"
+ "\tmovl %%eax,%%fs\n"
+ "\tmovl %%eax,%%gs\n"
+ "\tmovl %%eax,%%ss" : : : "eax");
/* Jump to the 16-bit code that we copied earlier. It disables paging
and the cache, switches to real mode, and jumps to the BIOS reset
@@ -305,7 +288,38 @@ void machine_restart(char * __unused)
__asm__ __volatile__ ("ljmp $0x0008,%0"
:
- : "i" ((void *) (0x1000 - sizeof (real_mode_switch))));
+ : "i" ((void *) (0x1000 - sizeof (real_mode_switch) - 100)));
+}
+
+void machine_restart(char * __unused)
+{
+#if __SMP__
+ /*
+ * Stop all CPUs and turn off local APICs and the IO-APIC, so
+ * other OSs see a clean IRQ state.
+ */
+ smp_send_stop();
+ disable_IO_APIC();
+#endif
+
+ if(!reboot_thru_bios) {
+ /* rebooting needs to touch the page at absolute addr 0 */
+ *((unsigned short *)__va(0x472)) = reboot_mode;
+ for (;;) {
+ int i;
+ for (i=0; i<100; i++) {
+ kb_wait();
+ udelay(50);
+ outb(0xfe,0x64); /* pulse reset low */
+ udelay(50);
+ }
+ /* That didn't work - force a triple fault.. */
+ __asm__ __volatile__("lidt %0": :"m" (no_idt));
+ __asm__ __volatile__("int3");
+ }
+ }
+
+ machine_real_restart(jump_to_bios, sizeof(jump_to_bios));
}
void machine_halt(void)
diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c
index 646532f86..cd80009d4 100644
--- a/arch/i386/kernel/setup.c
+++ b/arch/i386/kernel/setup.c
@@ -7,8 +7,8 @@
* and Martin Mares, November 1997.
*
* Force Cyrix 6x86(MX) and M II processors to report MTRR capability
- * and fix against Cyrix "coma bug" by
- * Zoltan Boszormenyi <zboszor@mol.hu> February 1999.
+ * and Cyrix "coma bug" recognition by
+ * Zoltán Böszörményi <zboszor@mail.externet.hu> February 1999.
*
* Force Centaur C6 processors to report MTRR capability.
* Bart Hartgers <bart@etpmod.phys.tue.nl>, May 1999.
@@ -592,13 +592,16 @@ void __init setup_arch(char **cmdline_p)
*/
max_pfn = 0;
for (i = 0; i < e820.nr_map; i++) {
- unsigned long curr_pfn;
+ unsigned long start, end;
/* RAM? */
if (e820.map[i].type != E820_RAM)
continue;
- curr_pfn = PFN_DOWN(e820.map[i].addr + e820.map[i].size);
- if (curr_pfn > max_pfn)
- max_pfn = curr_pfn;
+ start = PFN_UP(e820.map[i].addr);
+ end = PFN_DOWN(e820.map[i].addr + e820.map[i].size);
+ if (start >= end)
+ continue;
+ if (end > max_pfn)
+ max_pfn = end;
}
/*
@@ -706,7 +709,7 @@ void __init setup_arch(char **cmdline_p)
#endif
#ifdef CONFIG_BLK_DEV_INITRD
- if (LOADER_TYPE) {
+ if (LOADER_TYPE && INITRD_START) {
if (INITRD_START + INITRD_SIZE < (max_low_pfn << PAGE_SHIFT)) {
reserve_bootmem(INITRD_START, INITRD_SIZE);
initrd_start =
diff --git a/arch/i386/kernel/smp.c b/arch/i386/kernel/smp.c
index 59af7034d..9acf81556 100644
--- a/arch/i386/kernel/smp.c
+++ b/arch/i386/kernel/smp.c
@@ -11,6 +11,7 @@
#include <linux/init.h>
#include <linux/mm.h>
+#include <linux/spinlock.h>
#include <linux/kernel_stat.h>
#include <linux/smp_lock.h>
#include <linux/irq.h>
@@ -638,12 +639,19 @@ int prof_counter[NR_CPUS] = { 1, };
*/
static unsigned int __init get_8254_timer_count(void)
{
+ extern rwlock_t xtime_lock;
+ unsigned long flags;
+
unsigned int count;
+ write_lock_irqsave(&xtime_lock, flags);
+
outb_p(0x00, 0x43);
count = inb_p(0x40);
count |= inb_p(0x40) << 8;
+ write_unlock_irqrestore(&xtime_lock, flags);
+
return count;
}
diff --git a/arch/i386/kernel/vm86.c b/arch/i386/kernel/vm86.c
index 5719ecaf1..4974d5c32 100644
--- a/arch/i386/kernel/vm86.c
+++ b/arch/i386/kernel/vm86.c
@@ -260,7 +260,7 @@ static void do_sys_vm86(struct kernel_vm86_struct *info, struct task_struct *tsk
mark_screen_rdonly(tsk);
unlock_kernel();
__asm__ __volatile__(
- "xorl %%eax,%%eax; movl %%ax,%%fs; movl %%ax,%%gs\n\t"
+ "xorl %%eax,%%eax; movl %%eax,%%fs; movl %%eax,%%gs\n\t"
"movl %0,%%esp\n\t"
"jmp ret_from_sys_call"
: /* no outputs */
diff --git a/arch/i386/math-emu/Makefile b/arch/i386/math-emu/Makefile
index 588f7ada2..68b327a2a 100644
--- a/arch/i386/math-emu/Makefile
+++ b/arch/i386/math-emu/Makefile
@@ -10,7 +10,7 @@ PARANOID = -DPARANOID
CFLAGS := $(CFLAGS) $(PARANOID) $(DEBUG) -fno-builtin $(MATH_EMULATION)
.S.o:
- $(CC) -D__ASSEMBLY__ $(PARANOID) -c $<
+ $(CC) -D__ASSEMBLY__ $(AFLAGS) $(PARANOID) -c $<
# From 'C' language sources:
C_OBJS =fpu_entry.o errors.o \
diff --git a/arch/m68k/atari/stram.c b/arch/m68k/atari/stram.c
index 471e9a85f..81dc17103 100644
--- a/arch/m68k/atari/stram.c
+++ b/arch/m68k/atari/stram.c
@@ -1230,18 +1230,9 @@ static int stram_release( struct inode *inode, struct file *filp )
}
-static struct file_operations stram_fops = {
- NULL, /* lseek - default */
- block_read, /* read - general block-dev read */
- block_write, /* write - general block-dev write */
- NULL, /* readdir - bad */
- NULL, /* select */
- NULL, /* ioctl */
- NULL, /* mmap */
- stram_open, /* open */
- NULL, /* flush */
- stram_release, /* release */
- block_fsync /* fsync */
+static struct block_device_operations stram_fops = {
+ open: stram_open,
+ release: stram_release,
};
int __init stram_device_init(void)
diff --git a/arch/m68k/fpsp040/Makefile b/arch/m68k/fpsp040/Makefile
index d3ec21217..bbfc0b174 100644
--- a/arch/m68k/fpsp040/Makefile
+++ b/arch/m68k/fpsp040/Makefile
@@ -8,7 +8,7 @@
# Note 2! The CFLAGS definitions are now in the main makefile...
.S.o:
- $(CC) -D__ASSEMBLY__ -traditional -c -o $*.o $<
+ $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c -o $*.o $<
OS_TARGET := fpsp.o
diff --git a/arch/m68k/ifpsp060/Makefile b/arch/m68k/ifpsp060/Makefile
index 94eea44a4..7836197a6 100644
--- a/arch/m68k/ifpsp060/Makefile
+++ b/arch/m68k/ifpsp060/Makefile
@@ -5,7 +5,7 @@
# for more details.
.S.o:
- $(CC) -D__ASSEMBLY__ -traditional -c -o $*.o $<
+ $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c -o $*.o $<
OS_TARGET := ifpsp.o
diff --git a/arch/m68k/kernel/Makefile b/arch/m68k/kernel/Makefile
index 146fcb69b..3d2000724 100644
--- a/arch/m68k/kernel/Makefile
+++ b/arch/m68k/kernel/Makefile
@@ -8,7 +8,7 @@
# Note 2! The CFLAGS definitions are now in the main makefile...
.S.o:
- $(CC) -D__ASSEMBLY__ -traditional -c $< -o $*.o
+ $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $*.o
ifndef CONFIG_SUN3
all: head.o kernel.o
diff --git a/arch/m68k/kernel/bios32.c b/arch/m68k/kernel/bios32.c
index 55b762bbd..082fda543 100644
--- a/arch/m68k/kernel/bios32.c
+++ b/arch/m68k/kernel/bios32.c
@@ -449,69 +449,6 @@ static void __init layout_bus(struct pci_bus *bus, unsigned long pci_mem_base,
#endif /* !PCI_MODIFY */
-/*
- * Given the vendor and device ids, find the n'th instance of that device
- * in the system.
- */
-
-int pcibios_find_device(unsigned short vendor, unsigned short device_id,
- unsigned short index, unsigned char *bus,
- unsigned char *devfn)
-{
- unsigned int curr = 0;
- struct pci_dev *dev;
-
- for (dev = pci_devices; dev; dev = dev->next)
- {
- if (dev->vendor == vendor && dev->device == device_id)
- {
- if (curr == index)
- {
- *devfn = dev->devfn;
- *bus = dev->bus->number;
- return PCIBIOS_SUCCESSFUL;
- }
- ++curr;
- }
- }
- return PCIBIOS_DEVICE_NOT_FOUND;
-}
-
-/*
- * Given the class, find the n'th instance of that device
- * in the system.
- */
-
-int pcibios_find_class(unsigned int class_code, unsigned short index,
- unsigned char *bus, unsigned char *devfn)
-{
- unsigned int curr = 0;
- struct pci_dev *dev;
-
- for (dev = pci_devices; dev; dev = dev->next)
- {
- if (dev->class == class_code)
- {
- if (curr == index)
- {
- *devfn = dev->devfn;
- *bus = dev->bus->number;
- return PCIBIOS_SUCCESSFUL;
- }
- ++curr;
- }
- }
- return PCIBIOS_DEVICE_NOT_FOUND;
-}
-
-int pcibios_present(void)
-{
- if (MACH_IS_HADES)
- return 1;
- else
- return 0;
-}
-
void __init pcibios_init(void)
{
printk("Linux/m68k PCI BIOS32 revision %x.%02x\n", MAJOR_REV, MINOR_REV);
@@ -574,7 +511,7 @@ void __init pcibios_fixup(void)
* Scan the tree, allocating PCI memory and I/O space.
*/
- layout_bus(&pci_root, orig_mem_base, orig_io_base);
+ layout_bus(pci_bus_b(pci_root.next), orig_mem_base, orig_io_base);
pci_mem_base = orig_mem_base;
pci_io_base = orig_io_base;
diff --git a/arch/m68k/lib/Makefile b/arch/m68k/lib/Makefile
index f152e28e4..d1d6b1d7d 100644
--- a/arch/m68k/lib/Makefile
+++ b/arch/m68k/lib/Makefile
@@ -3,7 +3,7 @@
#
.S.o:
- $(CC) -D__ASSEMBLY__ -traditional -c $< -o $@
+ $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $@
L_TARGET = lib.a
L_OBJS = ashrdi3.o checksum.o memcpy.o memcmp.o memset.o semaphore.o
diff --git a/arch/m68k/math-emu/Makefile b/arch/m68k/math-emu/Makefile
index fe379cb2c..0e22edc96 100644
--- a/arch/m68k/math-emu/Makefile
+++ b/arch/m68k/math-emu/Makefile
@@ -8,7 +8,7 @@
# Note 2! The CFLAGS definitions are now in the main makefile...
.S.o:
- $(CC) $(EXTRA_CFLAGS) -D__ASSEMBLY__ -traditional -c $< -o $*.o
+ $(CC) $(EXTRA_CFLAGS) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $*.o
#EXTRA_CFLAGS=-DFPU_EMU_DEBUG
diff --git a/arch/m68k/sun3/Makefile b/arch/m68k/sun3/Makefile
index bf987e3d2..998a4eee1 100644
--- a/arch/m68k/sun3/Makefile
+++ b/arch/m68k/sun3/Makefile
@@ -8,7 +8,7 @@
# Note 2! The CFLAGS definitions are now in the main makefile...
.S.o:
- $(CC) -D__ASSEMBLY__ -traditional -Wa,-m68020 -c $< -o $*.o
+ $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -Wa,-m68020 -c $< -o $*.o
O_TARGET := sun3.o
O_OBJS := config.o idprom.o mmu_emu.o sun3ints.o leds.o dvma.o sbus.o
diff --git a/arch/m68k/sun3/prom/Makefile b/arch/m68k/sun3/prom/Makefile
index d1aeb0602..aea488ed2 100644
--- a/arch/m68k/sun3/prom/Makefile
+++ b/arch/m68k/sun3/prom/Makefile
@@ -17,6 +17,6 @@ promlib.a: $(OBJS)
sync
dep:
- $(CPP) -M *.c > .depend
+ $(CPP) $(CPPFLAGS) -M *.c > .depend
include $(TOPDIR)/Rules.make
diff --git a/arch/mips/config.in b/arch/mips/config.in
index 8cfe976e9..b6b8443ba 100644
--- a/arch/mips/config.in
+++ b/arch/mips/config.in
@@ -1,4 +1,4 @@
-# $Id: config.in,v 1.37 2000/01/29 01:41:59 ralf Exp $
+# $Id: config.in,v 1.38 2000/02/04 07:40:23 ralf Exp $
# For a description of the syntax of this configuration file,
# see the Configure script.
#
@@ -167,6 +167,8 @@ if [ "$CONFIG_NET" = "y" ]; then
source net/Config.in
fi
+source drivers/telephony/Config.in
+
mainmenu_option next_comment
comment 'SCSI support'
diff --git a/arch/mips/dec/prom/Makefile b/arch/mips/dec/prom/Makefile
index 33f906ece..c139bbda3 100644
--- a/arch/mips/dec/prom/Makefile
+++ b/arch/mips/dec/prom/Makefile
@@ -1,4 +1,4 @@
-# $Id: $
+# $Id: Makefile,v 1.1 1999/01/17 03:49:44 ralf Exp $
# Makefile for the DECstation prom monitor library routines
# under Linux.
#
@@ -24,6 +24,6 @@ rexlib.a: $(OBJS)
locore.o: locore.S
dep:
- $(CPP) -M *.c > .depend
+ $(CPP) $(CPPFLAGS) -M *.c > .depend
include $(TOPDIR)/Rules.make
diff --git a/arch/mips/defconfig b/arch/mips/defconfig
index d64e49531..1154cd149 100644
--- a/arch/mips/defconfig
+++ b/arch/mips/defconfig
@@ -143,6 +143,12 @@ CONFIG_IP_PNP_BOOTP=y
# CONFIG_NET_SCHED is not set
#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+# CONFIG_PHONE_IXJ is not set
+
+#
# SCSI support
#
CONFIG_SCSI=y
@@ -190,8 +196,7 @@ CONFIG_SGISEEQ=y
#
CONFIG_VT=y
CONFIG_VT_CONSOLE=y
-CONFIG_SERIAL=y
-# CONFIG_SERIAL_CONSOLE is not set
+# CONFIG_SERIAL is not set
# CONFIG_SERIAL_EXTENDED is not set
# CONFIG_SERIAL_NONSTANDARD is not set
# CONFIG_UNIX98_PTYS is not set
@@ -199,6 +204,11 @@ CONFIG_SERIAL=y
# CONFIG_PPDEV is not set
#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
# Mice
#
# CONFIG_BUSMOUSE is not set
@@ -237,14 +247,13 @@ CONFIG_PSMOUSE=y
# CONFIG_AGP is not set
#
-# Support for USB
+# USB support
#
# CONFIG_USB is not set
#
# Misc devices
#
-# CONFIG_ACPI is not set
#
# Filesystems
@@ -260,6 +269,7 @@ CONFIG_AUTOFS_FS=y
# CONFIG_UMSDOS_FS is not set
# CONFIG_VFAT_FS is not set
# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
CONFIG_ISO9660_FS=y
# CONFIG_JOLIET is not set
# CONFIG_MINIX_FS is not set
@@ -292,6 +302,7 @@ CONFIG_LOCKD=y
# CONFIG_PARTITION_ADVANCED is not set
CONFIG_MSDOS_PARTITION=y
CONFIG_SGI_PARTITION=y
+# CONFIG_ULTRIX_PARTITION is not set
# CONFIG_SUN_PARTITION is not set
# CONFIG_NLS is not set
@@ -309,7 +320,6 @@ CONFIG_SGI_NEWPORT_CONSOLE=y
# SGI devices
#
CONFIG_SGI_SERIAL=y
-CONFIG_SERIAL=y
CONFIG_SGI_DS1286=y
# CONFIG_SGI_NEWPORT_GFX is not set
@@ -318,5 +328,4 @@ CONFIG_SGI_DS1286=y
#
CONFIG_CROSSCOMPILE=y
# CONFIG_MIPS_FPE_MODULE is not set
-# CONFIG_REMOTE_DEBUG is not set
# CONFIG_MAGIC_SYSRQ is not set
diff --git a/arch/mips/defconfig-ip22 b/arch/mips/defconfig-ip22
index 3e8d63570..1154cd149 100644
--- a/arch/mips/defconfig-ip22
+++ b/arch/mips/defconfig-ip22
@@ -39,6 +39,7 @@ CONFIG_CPU_HAS_LLSC=y
# General setup
#
# CONFIG_CPU_LITTLE_ENDIAN is not set
+CONFIG_KCORE_ELF=y
CONFIG_ELF_KERNEL=y
CONFIG_BINFMT_IRIX=y
CONFIG_FORWARD_KEYBOARD=y
@@ -46,6 +47,11 @@ CONFIG_FORWARD_KEYBOARD=y
CONFIG_BINFMT_ELF=y
# CONFIG_BINFMT_MISC is not set
CONFIG_NET=y
+
+#
+# PCMCIA/CardBus support
+#
+# CONFIG_PCMCIA is not set
CONFIG_SYSVIPC=y
# CONFIG_BSD_PROCESS_ACCT is not set
CONFIG_SYSCTL=y
@@ -58,16 +64,6 @@ CONFIG_MODULES=y
CONFIG_KMOD=y
#
-# I2O device support
-#
-# CONFIG_I2O is not set
-# CONFIG_I2O_PCI is not set
-# CONFIG_I2O_BLOCK is not set
-# CONFIG_I2O_LAN is not set
-# CONFIG_I2O_SCSI is not set
-# CONFIG_I2O_PROC is not set
-
-#
# Plug and Play configuration
#
# CONFIG_PNP is not set
@@ -147,6 +143,12 @@ CONFIG_IP_PNP_BOOTP=y
# CONFIG_NET_SCHED is not set
#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+# CONFIG_PHONE_IXJ is not set
+
+#
# SCSI support
#
CONFIG_SCSI=y
@@ -171,10 +173,20 @@ CONFIG_SCSI_CONSTANTS=y
CONFIG_SCSI_SGIWD93=y
#
+# I2O device support
+#
+# CONFIG_I2O is not set
+# CONFIG_I2O_PCI is not set
+# CONFIG_I2O_BLOCK is not set
+# CONFIG_I2O_LAN is not set
+# CONFIG_I2O_SCSI is not set
+# CONFIG_I2O_PROC is not set
+
+#
# Network device support
#
CONFIG_NETDEVICES=y
-CONFIG_DUMMY=y
+# CONFIG_DUMMY is not set
# CONFIG_SLIP is not set
# CONFIG_PPP is not set
CONFIG_SGISEEQ=y
@@ -184,8 +196,7 @@ CONFIG_SGISEEQ=y
#
CONFIG_VT=y
CONFIG_VT_CONSOLE=y
-CONFIG_SERIAL=y
-# CONFIG_SERIAL_CONSOLE is not set
+# CONFIG_SERIAL is not set
# CONFIG_SERIAL_EXTENDED is not set
# CONFIG_SERIAL_NONSTANDARD is not set
# CONFIG_UNIX98_PTYS is not set
@@ -193,6 +204,11 @@ CONFIG_SERIAL=y
# CONFIG_PPDEV is not set
#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
# Mice
#
# CONFIG_BUSMOUSE is not set
@@ -200,7 +216,16 @@ CONFIG_MOUSE=y
CONFIG_PSMOUSE=y
# CONFIG_82C710_MOUSE is not set
# CONFIG_PC110_PAD is not set
+
+#
+# Joysticks
+#
+# CONFIG_JOYSTICK is not set
# CONFIG_QIC02_TAPE is not set
+
+#
+# Watchdog Cards
+#
# CONFIG_WATCHDOG is not set
# CONFIG_NVRAM is not set
# CONFIG_RTC is not set
@@ -209,11 +234,6 @@ CONFIG_PSMOUSE=y
# Video For Linux
#
# CONFIG_VIDEO_DEV is not set
-
-#
-# Joystick support
-#
-# CONFIG_JOYSTICK is not set
# CONFIG_DTLK is not set
# CONFIG_R3964 is not set
# CONFIG_APPLICOM is not set
@@ -223,16 +243,17 @@ CONFIG_PSMOUSE=y
#
# CONFIG_FTAPE is not set
# CONFIG_DRM is not set
+# CONFIG_DRM_TDFX is not set
+# CONFIG_AGP is not set
#
-# USB drivers - not for the faint of heart
+# USB support
#
# CONFIG_USB is not set
#
# Misc devices
#
-# CONFIG_ACPI is not set
#
# Filesystems
@@ -242,14 +263,15 @@ CONFIG_AUTOFS_FS=y
# CONFIG_ADFS_FS is not set
# CONFIG_AFFS_FS is not set
# CONFIG_HFS_FS is not set
+# CONFIG_BFS_FS is not set
# CONFIG_FAT_FS is not set
# CONFIG_MSDOS_FS is not set
# CONFIG_UMSDOS_FS is not set
# CONFIG_VFAT_FS is not set
# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
CONFIG_ISO9660_FS=y
# CONFIG_JOLIET is not set
-# CONFIG_UDF_FS is not set
# CONFIG_MINIX_FS is not set
# CONFIG_NTFS_FS is not set
# CONFIG_HPFS_FS is not set
@@ -258,6 +280,7 @@ CONFIG_PROC_FS=y
# CONFIG_ROMFS_FS is not set
CONFIG_EXT2_FS=y
# CONFIG_SYSV_FS is not set
+# CONFIG_UDF_FS is not set
# CONFIG_UFS_FS is not set
#
@@ -267,7 +290,7 @@ CONFIG_EXT2_FS=y
CONFIG_NFS_FS=y
CONFIG_ROOT_NFS=y
CONFIG_NFSD=y
-# CONFIG_NFSD_SUN is not set
+# CONFIG_NFSD_V3 is not set
CONFIG_SUNRPC=y
CONFIG_LOCKD=y
# CONFIG_SMB_FS is not set
@@ -278,10 +301,8 @@ CONFIG_LOCKD=y
#
# CONFIG_PARTITION_ADVANCED is not set
CONFIG_MSDOS_PARTITION=y
-# CONFIG_BSD_DISKLABEL is not set
-# CONFIG_SOLARIS_X86_PARTITION is not set
-# CONFIG_UNIXWARE_DISKLABEL is not set
CONFIG_SGI_PARTITION=y
+# CONFIG_ULTRIX_PARTITION is not set
# CONFIG_SUN_PARTITION is not set
# CONFIG_NLS is not set
@@ -299,7 +320,6 @@ CONFIG_SGI_NEWPORT_CONSOLE=y
# SGI devices
#
CONFIG_SGI_SERIAL=y
-CONFIG_SERIAL=y
CONFIG_SGI_DS1286=y
# CONFIG_SGI_NEWPORT_GFX is not set
@@ -308,5 +328,4 @@ CONFIG_SGI_DS1286=y
#
CONFIG_CROSSCOMPILE=y
# CONFIG_MIPS_FPE_MODULE is not set
-# CONFIG_REMOTE_DEBUG is not set
# CONFIG_MAGIC_SYSRQ is not set
diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c
index 5142258a3..a912be2e1 100644
--- a/arch/mips/kernel/signal.c
+++ b/arch/mips/kernel/signal.c
@@ -1,4 +1,4 @@
-/* $Id: signal.c,v 1.23 1999/10/09 00:00:58 ralf Exp $
+/* $Id: signal.c,v 1.24 2000/02/04 07:40:23 ralf Exp $
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
@@ -22,7 +22,7 @@
#include <asm/asm.h>
#include <asm/bitops.h>
-#include <asm/pgtable.h>
+#include <asm/pgalloc.h>
#include <asm/stackframe.h>
#include <asm/uaccess.h>
#include <asm/ucontext.h>
diff --git a/arch/mips/kernel/syscalls.h b/arch/mips/kernel/syscalls.h
index be6f4691a..66aa9ff50 100644
--- a/arch/mips/kernel/syscalls.h
+++ b/arch/mips/kernel/syscalls.h
@@ -1,4 +1,4 @@
-/* $Id: syscalls.h,v 1.19 2000/01/29 01:41:59 ralf Exp $
+/* $Id: syscalls.h,v 1.20 2000/02/04 07:40:23 ralf Exp $
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
@@ -228,3 +228,6 @@ SYS(sys_ni_syscall, 0)
SYS(sys_mmap2, 6) /* 4210 */
SYS(sys_truncate64, 2)
SYS(sys_ftruncate64, 2)
+SYS(sys_stat64, 3)
+SYS(sys_lstat64, 3)
+SYS(sys_fstat64, 3) /* 4215 */
diff --git a/arch/mips/kernel/sysirix.c b/arch/mips/kernel/sysirix.c
index acec2b569..362d6a760 100644
--- a/arch/mips/kernel/sysirix.c
+++ b/arch/mips/kernel/sysirix.c
@@ -1,4 +1,4 @@
-/* $Id: sysirix.c,v 1.22 1999/12/04 03:59:00 ralf Exp $
+/* $Id: sysirix.c,v 1.23 2000/02/04 07:40:23 ralf Exp $
*
* sysirix.c: IRIX system call emulation.
*
@@ -27,7 +27,7 @@
#include <asm/ptrace.h>
#include <asm/page.h>
-#include <asm/pgtable.h>
+#include <asm/pgalloc.h>
#include <asm/uaccess.h>
#include <asm/sgialib.h>
#include <asm/inventory.h>
diff --git a/arch/mips/kernel/sysmips.c b/arch/mips/kernel/sysmips.c
index 21ffd92e6..870cdac2d 100644
--- a/arch/mips/kernel/sysmips.c
+++ b/arch/mips/kernel/sysmips.c
@@ -7,7 +7,7 @@
*
* Copyright (C) 1995, 1996, 1997 by Ralf Baechle
*
- * $Id: sysmips.c,v 1.6 1998/08/25 09:14:42 ralf Exp $
+ * $Id: sysmips.c,v 1.7 1999/10/09 00:00:58 ralf Exp $
*/
#include <linux/errno.h>
#include <linux/linkage.h>
@@ -19,7 +19,7 @@
#include <linux/utsname.h>
#include <asm/cachectl.h>
-#include <asm/pgtable.h>
+#include <asm/pgalloc.h>
#include <asm/sysmips.h>
#include <asm/uaccess.h>
diff --git a/arch/mips/lib/csum_partial_copy.c b/arch/mips/lib/csum_partial_copy.c
index 5d810b04f..c73ae974c 100644
--- a/arch/mips/lib/csum_partial_copy.c
+++ b/arch/mips/lib/csum_partial_copy.c
@@ -14,7 +14,7 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
- * $Id: csum_partial_copy.c,v 1.1 1998/07/10 01:14:49 ralf Exp $
+ * $Id: csum_partial_copy.c,v 1.2 1998/09/19 19:16:17 ralf Exp $
*/
#include <net/checksum.h>
#include <linux/types.h>
@@ -56,20 +56,3 @@ unsigned int csum_partial_copy_from_user (const char *src, char *dst,
return csum_partial(dst, len, sum);
}
-
-/*
- * Copy to userspace and compute checksum.
- */
-unsigned int csum_partial_copy_to_user (const char *src, char *dst,
- int len, unsigned int sum,
- int *err_ptr)
-{
- sum = csum_partial(src, len, sum);
-
- if (copy_to_user(dst, src, len)) {
- *err_ptr = -EFAULT;
- return sum;
- }
-
- return sum;
-}
diff --git a/arch/mips/sgi/kernel/Makefile b/arch/mips/sgi/kernel/Makefile
index 588ec64ea..760e9fe51 100644
--- a/arch/mips/sgi/kernel/Makefile
+++ b/arch/mips/sgi/kernel/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.6 1999/02/07 21:56:33 ulfc Exp $
+# $Id: Makefile,v 1.7 1999/05/07 18:00:16 ulfc Exp $
# Makefile for the SGI specific kernel interface routines
# under Linux.
#
@@ -28,6 +28,6 @@ sgikern.a: $(OBJS)
indyIRQ.o: indyIRQ.S
dep:
- $(CPP) -M *.c > .depend
+ $(CPP) $(CPPFLAGS) -M *.c > .depend
include $(TOPDIR)/Rules.make
diff --git a/arch/mips/sni/pci.c b/arch/mips/sni/pci.c
index 8b8154007..cfbc4b3e7 100644
--- a/arch/mips/sni/pci.c
+++ b/arch/mips/sni/pci.c
@@ -1,4 +1,4 @@
-/* $Id: pci.c,v 1.8 1999/10/09 00:00:59 ralf Exp $
+/* $Id: pci.c,v 1.9 1999/12/04 03:59:00 ralf Exp $
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
@@ -32,7 +32,7 @@ static void pcimt_pcibios_fixup (void)
{
struct pci_dev *dev;
- for (dev=pci_devices; dev; dev=dev->next) {
+ pci_for_each_dev(dev) {
/*
* TODO: Take care of RM300 revision D boards for where the
* network slot became an ordinary PCI slot.
diff --git a/arch/mips64/config.in b/arch/mips64/config.in
index c1c3d59cf..e8833c51a 100644
--- a/arch/mips64/config.in
+++ b/arch/mips64/config.in
@@ -1,4 +1,4 @@
-# $Id: config.in,v 1.10 2000/01/31 21:57:09 kanoj Exp $
+# $Id: config.in,v 1.11 2000/02/04 07:40:23 ralf Exp $
#
# For a description of the syntax of this configuration file,
# see the Configure script.
@@ -108,6 +108,8 @@ if [ "$CONFIG_NET" = "y" ]; then
source net/Config.in
fi
+source drivers/telephony/Config.in
+
mainmenu_option next_comment
comment 'SCSI support'
diff --git a/arch/mips64/defconfig b/arch/mips64/defconfig
index 5d6d9f3d5..3fd8237b7 100644
--- a/arch/mips64/defconfig
+++ b/arch/mips64/defconfig
@@ -112,6 +112,12 @@ CONFIG_SKB_LARGE=y
# CONFIG_ATALK is not set
#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+# CONFIG_PHONE_IXJ is not set
+
+#
# SCSI support
#
CONFIG_SCSI=y
@@ -127,6 +133,7 @@ CONFIG_BLK_DEV_SD=y
#
# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
#
+# CONFIG_SCSI_DEBUG_QUEUES is not set
# CONFIG_SCSI_MULTI_LUN is not set
# CONFIG_SCSI_CONSTANTS is not set
# CONFIG_SCSI_LOGGING is not set
@@ -272,10 +279,20 @@ CONFIG_SERIAL_CONSOLE=y
# CONFIG_PPDEV is not set
#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
# Mice
#
# CONFIG_BUSMOUSE is not set
# CONFIG_MOUSE is not set
+
+#
+# Joysticks
+#
+# CONFIG_JOYSTICK is not set
# CONFIG_QIC02_TAPE is not set
#
@@ -301,7 +318,7 @@ CONFIG_SERIAL_CONSOLE=y
# CONFIG_DRM_TDFX is not set
#
-# Support for USB
+# USB support
#
# CONFIG_USB is not set
@@ -315,6 +332,7 @@ CONFIG_SERIAL_CONSOLE=y
# CONFIG_MSDOS_FS is not set
# CONFIG_UMSDOS_FS is not set
# CONFIG_VFAT_FS is not set
+# CONFIG_CRAMFS is not set
# CONFIG_ISO9660_FS is not set
# CONFIG_JOLIET is not set
# CONFIG_MINIX_FS is not set
@@ -345,6 +363,7 @@ CONFIG_LOCKD=y
# CONFIG_PARTITION_ADVANCED is not set
CONFIG_MSDOS_PARTITION=y
CONFIG_SGI_PARTITION=y
+# CONFIG_ULTRIX_PARTITION is not set
# CONFIG_SUN_PARTITION is not set
# CONFIG_NLS is not set
CONFIG_KCORE_ELF=y
diff --git a/arch/mips64/defconfig-ip22 b/arch/mips64/defconfig-ip22
index ebd6cb9d1..88f4eecd1 100644
--- a/arch/mips64/defconfig-ip22
+++ b/arch/mips64/defconfig-ip22
@@ -104,6 +104,12 @@ CONFIG_SKB_LARGE=y
# CONFIG_ATALK is not set
#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+# CONFIG_PHONE_IXJ is not set
+
+#
# SCSI support
#
# CONFIG_SCSI is not set
@@ -196,6 +202,11 @@ CONFIG_VT_CONSOLE=y
# CONFIG_PPDEV is not set
#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
# Mice
#
# CONFIG_BUSMOUSE is not set
@@ -230,7 +241,7 @@ CONFIG_VT_CONSOLE=y
# CONFIG_DRM_TDFX is not set
#
-# Support for USB
+# USB support
#
# CONFIG_USB is not set
@@ -244,6 +255,7 @@ CONFIG_VT_CONSOLE=y
# CONFIG_MSDOS_FS is not set
# CONFIG_UMSDOS_FS is not set
# CONFIG_VFAT_FS is not set
+# CONFIG_CRAMFS is not set
# CONFIG_ISO9660_FS is not set
# CONFIG_JOLIET is not set
# CONFIG_MINIX_FS is not set
diff --git a/arch/mips64/defconfig-ip27 b/arch/mips64/defconfig-ip27
index 5d6d9f3d5..3fd8237b7 100644
--- a/arch/mips64/defconfig-ip27
+++ b/arch/mips64/defconfig-ip27
@@ -112,6 +112,12 @@ CONFIG_SKB_LARGE=y
# CONFIG_ATALK is not set
#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+# CONFIG_PHONE_IXJ is not set
+
+#
# SCSI support
#
CONFIG_SCSI=y
@@ -127,6 +133,7 @@ CONFIG_BLK_DEV_SD=y
#
# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
#
+# CONFIG_SCSI_DEBUG_QUEUES is not set
# CONFIG_SCSI_MULTI_LUN is not set
# CONFIG_SCSI_CONSTANTS is not set
# CONFIG_SCSI_LOGGING is not set
@@ -272,10 +279,20 @@ CONFIG_SERIAL_CONSOLE=y
# CONFIG_PPDEV is not set
#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
# Mice
#
# CONFIG_BUSMOUSE is not set
# CONFIG_MOUSE is not set
+
+#
+# Joysticks
+#
+# CONFIG_JOYSTICK is not set
# CONFIG_QIC02_TAPE is not set
#
@@ -301,7 +318,7 @@ CONFIG_SERIAL_CONSOLE=y
# CONFIG_DRM_TDFX is not set
#
-# Support for USB
+# USB support
#
# CONFIG_USB is not set
@@ -315,6 +332,7 @@ CONFIG_SERIAL_CONSOLE=y
# CONFIG_MSDOS_FS is not set
# CONFIG_UMSDOS_FS is not set
# CONFIG_VFAT_FS is not set
+# CONFIG_CRAMFS is not set
# CONFIG_ISO9660_FS is not set
# CONFIG_JOLIET is not set
# CONFIG_MINIX_FS is not set
@@ -345,6 +363,7 @@ CONFIG_LOCKD=y
# CONFIG_PARTITION_ADVANCED is not set
CONFIG_MSDOS_PARTITION=y
CONFIG_SGI_PARTITION=y
+# CONFIG_ULTRIX_PARTITION is not set
# CONFIG_SUN_PARTITION is not set
# CONFIG_NLS is not set
CONFIG_KCORE_ELF=y
diff --git a/arch/mips64/kernel/scall_o32.S b/arch/mips64/kernel/scall_o32.S
index f7490a4be..7906258d2 100644
--- a/arch/mips64/kernel/scall_o32.S
+++ b/arch/mips64/kernel/scall_o32.S
@@ -1,4 +1,4 @@
-/* $Id: scall_o32.S,v 1.4 2000/01/29 01:41:59 ralf Exp $
+/* $Id: scall_o32.S,v 1.5 2000/02/04 07:40:24 ralf Exp $
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
@@ -401,10 +401,12 @@ illegal_syscall:
sys sys_sendfile 3
sys sys_ni_syscall 0
sys sys_ni_syscall 0
- sys sys_getrlimit 2 /* 4210 */
- sys sys_mmap2 6
+ sys sys_mmap2 6 /* 4210 */
sys sys_truncate64 2
sys sys_ftruncate64 2
+ sys sys_stat64 3
+ sys sys_lstat64 3
+ sys sys_fstat64 3 /* 4210 */
.endm
.macro sys function, nargs
diff --git a/arch/mips64/lib/csum_partial_copy.c b/arch/mips64/lib/csum_partial_copy.c
index 9f08f405a..49607c466 100644
--- a/arch/mips64/lib/csum_partial_copy.c
+++ b/arch/mips64/lib/csum_partial_copy.c
@@ -1,4 +1,4 @@
-/* $Id: csum_partial_copy.c,v 1.1 1999/08/21 21:43:00 ralf Exp $
+/* $Id: csum_partial_copy.c,v 1.2 1999/12/04 03:59:00 ralf Exp $
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
@@ -48,20 +48,3 @@ unsigned int csum_partial_copy_from_user (const char *src, char *dst,
return csum_partial(dst, len, sum);
}
-
-/*
- * Copy to userspace and compute checksum.
- */
-unsigned int csum_partial_copy_to_user (const char *src, char *dst,
- int len, unsigned int sum,
- int *err_ptr)
-{
- sum = csum_partial(src, len, sum);
-
- if (copy_to_user(dst, src, len)) {
- *err_ptr = -EFAULT;
- return sum;
- }
-
- return sum;
-}
diff --git a/arch/ppc/Makefile b/arch/ppc/Makefile
index 8a6db08e2..6552a7140 100644
--- a/arch/ppc/Makefile
+++ b/arch/ppc/Makefile
@@ -20,8 +20,8 @@ endif
ASFLAGS =
LINKFLAGS = -T arch/ppc/vmlinux.lds -Ttext $(KERNELLOAD) -Bstatic
-CFLAGSINC = -D__KERNEL__ -I$(TOPDIR)/include -D__powerpc__
-CFLAGS := $(CFLAGS) -I$(HPATH) -D__powerpc__ -fsigned-char \
+CPPFLAGS := $(CPPFLAGS) -D__powerpc__
+CFLAGS := $(CFLAGS) -D__powerpc__ -fsigned-char \
-msoft-float -pipe -fno-builtin -ffixed-r2 -Wno-uninitialized \
-mmultiple -mstring
CPP = $(CC) -E $(CFLAGS)
diff --git a/arch/ppc/boot/Makefile b/arch/ppc/boot/Makefile
index 96b6ba306..eb48313f4 100644
--- a/arch/ppc/boot/Makefile
+++ b/arch/ppc/boot/Makefile
@@ -16,9 +16,9 @@
.c.o:
$(CC) $(CFLAGS) -DINITRD_OFFSET=$(IOFF) -DINITRD_SIZE=$(ISZ) -DZIMAGE_OFFSET=$(ZOFF) -DZIMAGE_SIZE=$(ZSZ) -c -o $*.o $<
.S.s:
- $(CC) -D__ASSEMBLY__ -traditional -E -o $*.o $<
+ $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -E -o $*.o $<
.S.o:
- $(CC) -D__ASSEMBLY__ -traditional -c -o $*.o $<
+ $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c -o $*.o $<
ZOFF = 0
ZSZ = 0
@@ -52,7 +52,7 @@ ZLINKFLAGS = -T ../vmlinux.lds -Ttext 0x00800000
GZIP_FLAGS = -v9
OBJECTS := head.o misc.o ../coffboot/zlib.o
-CFLAGS = -O2 -DSTDC_HEADERS -fno-builtin -I$(TOPDIR)/include
+CFLAGS = $(CPPFLAGS) -O2 -DSTDC_HEADERS -fno-builtin
OBJCOPY = $(CROSS_COMPILE)objcopy
OBJCOPY_ARGS = -O elf32-powerpc
@@ -140,7 +140,7 @@ fastdep:
$(TOPDIR)/scripts/mkdep *.[Sch] > .depend
dep:
- $(CPP) -M *.S *.c > .depend
+ $(CPP) $(CPPFLAGS) -M *.S *.c > .depend
# just here to match coffboot/Makefile
vmlinux.coff:
diff --git a/arch/ppc/chrpboot/Makefile b/arch/ppc/chrpboot/Makefile
index 15f9a8e53..70ae95eb8 100644
--- a/arch/ppc/chrpboot/Makefile
+++ b/arch/ppc/chrpboot/Makefile
@@ -12,11 +12,11 @@
.c.o:
$(CC) $(CFLAGS) -DKERNELBASE=$(KERNELBASE) -c -o $*.o $<
.S.s:
- $(CC) -D__ASSEMBLY__ -traditional -E -o $*.o $<
+ $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -E -o $*.o $<
.S.o:
- $(CC) -D__ASSEMBLY__ -traditional -c -o $*.o $<
+ $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c -o $*.o $<
-CFLAGS = -O -fno-builtin -DSTDC_HEADERS -I$(TOPDIR)/include
+CFLAGS = $(CPPFLAGS) -O -fno-builtin -DSTDC_HEADERS
LD_ARGS = -Ttext 0x00400000
OBJCOPY = $(CROSS_COMPILE)objcopy
@@ -102,5 +102,5 @@ fastdep:
$(TOPDIR)/scripts/mkdep *.[Sch] > .depend
dep:
- $(CPP) -M *.S *.c > .depend
+ $(CPP) $(CPPFLAGS) -M *.S *.c > .depend
diff --git a/arch/ppc/coffboot/Makefile b/arch/ppc/coffboot/Makefile
index a7ed94074..b9868e6ac 100644
--- a/arch/ppc/coffboot/Makefile
+++ b/arch/ppc/coffboot/Makefile
@@ -7,7 +7,7 @@ HOSTCFLAGS = -O -I$(TOPDIR)/include
CC = $(CROSS_COMPILE)gcc
LD = $(CROSS_COMPILE)ld
-CFLAGS = -O -fno-builtin -I$(TOPDIR)/include
+CFLAGS = $(CPPFLAGS) -O -fno-builtin
OBJCOPY = $(CROSS_COMPILE)objcopy
OBJCOPY_ARGS = -O aixcoff-rs6000 -R .stab -R .stabstr -R .comment
COFF_LD_ARGS = -e _start -T ld.script -Ttext 500000 -Tdata 510000 -Bstatic
diff --git a/arch/ppc/config.in b/arch/ppc/config.in
index 279d81438..fa98b5fcf 100644
--- a/arch/ppc/config.in
+++ b/arch/ppc/config.in
@@ -85,12 +85,16 @@ comment 'General setup'
if [ "$CONFIG_APUS" = "y" ]; then
define_bool CONFIG_PCI n
-else if [ "$CONFIG_OAK" = "y" ]; then
+fi
+if [ "$CONFIG_OAK" = "y" ]; then
define_bool CONFIG_PCI n
-else if [ "$CONFIG_8xx" = "y" ]; then
+fi
+if [ "$CONFIG_8xx" = "y" ]; then
bool 'QSpan PCI' CONFIG_PCI
else
+ if [ "$CONFIG_APUS" != "y" ]; then
define_bool CONFIG_PCI y
+ fi
fi
bool 'Networking support' CONFIG_NET
diff --git a/arch/ppc/kernel/chrp_pci.c b/arch/ppc/kernel/chrp_pci.c
index 88686acc4..b93bc45f7 100644
--- a/arch/ppc/kernel/chrp_pci.c
+++ b/arch/ppc/kernel/chrp_pci.c
@@ -282,8 +282,7 @@ chrp_pcibios_fixup(void)
}
/* PCI interrupts are controlled by the OpenPIC */
- for( dev=pci_devices ; dev; dev=dev->next )
- {
+ pci_for_each_dev(dev) {
if ( dev->irq )
dev->irq = openpic_to_irq( dev->irq );
/* these need to be absolute addrs for OF and Matrox FB -- Cort */
diff --git a/arch/ppc/kernel/chrp_setup.c b/arch/ppc/kernel/chrp_setup.c
index 938cea36d..e76aa8dd9 100644
--- a/arch/ppc/kernel/chrp_setup.c
+++ b/arch/ppc/kernel/chrp_setup.c
@@ -249,7 +249,7 @@ chrp_setup_arch(void)
else
#endif
ROOT_DEV = to_kdev_t(0x0802); /* sda2 (sda1 is for the kernel) */
-
+sprintf(cmd_line, "console=ttyS0,9600 console=tty0");
printk("Boot arguments: %s\n", cmd_line);
request_region(0x20,0x20,"pic1");
@@ -391,7 +391,7 @@ void chrp_post_irq(int irq)
* openpic irq. So we just check to make sure the controller
* is an openpic and if it is then eoi
*
- * We do it this way since our irq_desc[irq].ctl can change
+ * We do it this way since our irq_desc[irq].handler can change
* with RTL and no longer be open_pic -- Cort
*/
if ( irq >= open_pic.irq_offset)
@@ -413,10 +413,10 @@ void __init chrp_init_IRQ(void)
}
open_pic.irq_offset = 16;
for ( i = 16 ; i < NR_IRQS ; i++ )
- irq_desc[i].ctl = &open_pic;
+ irq_desc[i].handler = &open_pic;
openpic_init(1);
for ( i = 0 ; i < 16 ; i++ )
- irq_desc[i].ctl = &i8259_pic;
+ irq_desc[i].handler = &i8259_pic;
i8259_init();
#ifdef CONFIG_XMON
request_irq(openpic_to_irq(HYDRA_INT_ADB_NMI),
diff --git a/arch/ppc/kernel/gemini_setup.c b/arch/ppc/kernel/gemini_setup.c
index 57ea34687..fadddda8b 100644
--- a/arch/ppc/kernel/gemini_setup.c
+++ b/arch/ppc/kernel/gemini_setup.c
@@ -332,10 +332,17 @@ void __init gemini_init_IRQ(void)
/* gemini has no 8259 */
open_pic.irq_offset = 0;
for( i=0; i < NR_IRQS; i++ )
- irq_desc[i].ctl = &open_pic;
+ irq_desc[i].handler = &open_pic;
openpic_init(1);
#ifdef __SMP__
- request_irq(OPENPIC_VEC_IPI, openpic_ipi_action, 0, "IPI0", 0);
+ request_irq(OPENPIC_VEC_IPI, openpic_ipi_action,
+ 0, "IPI0", 0);
+ request_irq(OPENPIC_VEC_IPI+1, openpic_ipi_action,
+ 0, "IPI1 (invalidate TLB)", 0);
+ request_irq(OPENPIC_VEC_IPI+2, openpic_ipi_action,
+ 0, "IPI2 (stop CPU)", 0);
+ request_irq(OPENPIC_VEC_IPI+3, openpic_ipi_action,
+ 0, "IPI3 (reschedule)", 0);
#endif /* __SMP__ */
}
@@ -505,7 +512,7 @@ void gemini_post_irq(int irq)
* openpic irq. So we just check to make sure the controller
* is an openpic and if it is then eoi
*
- * We do it this way since our irq_desc[irq].ctl can change
+ * We do it this way since our irq_desc[irq].handler can change
* with RTL and no longer be open_pic -- Cort
*/
if ( irq >= open_pic.irq_offset)
diff --git a/arch/ppc/kernel/irq.c b/arch/ppc/kernel/irq.c
index 4427e801f..a09d6ad98 100644
--- a/arch/ppc/kernel/irq.c
+++ b/arch/ppc/kernel/irq.c
@@ -44,6 +44,7 @@
#include <linux/openpic.h>
#include <linux/pci.h>
#include <linux/delay.h>
+#include <linux/irq.h>
#include <asm/bitops.h>
#include <asm/hydra.h>
@@ -71,7 +72,7 @@ volatile unsigned char *chrp_int_ack_special;
#define NR_MASK_WORDS ((NR_IRQS + 31) / 32)
-struct irqdesc irq_desc[NR_IRQS] = {{0, 0}, };
+irq_desc_t irq_desc[NR_IRQS];
int ppc_spurious_interrupts = 0;
unsigned int ppc_local_bh_count[NR_CPUS];
unsigned int ppc_local_irq_count[NR_CPUS];
@@ -244,8 +245,8 @@ int get_irq_list(char *buf)
#else
len += sprintf(buf+len, "%10u ", kstat_irqs(i));
#endif /* __SMP__ */
- if ( irq_desc[i].ctl )
- len += sprintf(buf+len, " %s ", irq_desc[i].ctl->typename );
+ if ( irq_desc[i].handler )
+ len += sprintf(buf+len, " %s ", irq_desc[i].handler->typename );
else
len += sprintf(buf+len, " None ");
len += sprintf(buf+len, " %s",action->name);
diff --git a/arch/ppc/kernel/local_irq.h b/arch/ppc/kernel/local_irq.h
index 8e9fe6df6..602192013 100644
--- a/arch/ppc/kernel/local_irq.h
+++ b/arch/ppc/kernel/local_irq.h
@@ -4,7 +4,7 @@
#include <linux/kernel_stat.h>
#include <linux/interrupt.h>
-#include <asm/irq_control.h>
+#include <linux/irq.h>
void ppc_irq_dispatch_handler(struct pt_regs *regs, int irq);
diff --git a/arch/ppc/kernel/m8xx_setup.c b/arch/ppc/kernel/m8xx_setup.c
index 4d510612b..36e886d0c 100644
--- a/arch/ppc/kernel/m8xx_setup.c
+++ b/arch/ppc/kernel/m8xx_setup.c
@@ -278,7 +278,7 @@ m8xx_init_IRQ(void)
ppc8xx_pic.irq_offset = 0;
for ( i = 0 ; i < NR_SIU_INTS ; i++ )
- irq_desc[i].ctl = &ppc8xx_pic;
+ irq_desc[i].handler = &ppc8xx_pic;
/* We could probably incorporate the CPM into the multilevel
* interrupt structure.
@@ -288,7 +288,7 @@ m8xx_init_IRQ(void)
#if defined(CONFIG_PCI)
for ( i = NR_SIU_INTS ; i < (NR_SIU_INTS + NR_8259_INTS) ; i++ )
- irq_desc[i].ctl = &i8259_pic;
+ irq_desc[i].handler = &i8259_pic;
i8259_pic.irq_offset = NR_SIU_INTS;
i8259_init();
request_8xxirq(ISA_BRIDGE_INT, mbx_i8259_action, 0, "8259 cascade", NULL);
diff --git a/arch/ppc/kernel/mbx_pci.c b/arch/ppc/kernel/mbx_pci.c
deleted file mode 100644
index d7473e128..000000000
--- a/arch/ppc/kernel/mbx_pci.c
+++ /dev/null
@@ -1,269 +0,0 @@
-/*
- * MBX pci routines.
- * The MBX uses the QSpan PCI bridge. The config address register
- * is located 0x500 from the base of the bridge control/status registers.
- * The data register is located at 0x504.
- * This is a two step operation. First, the address register is written,
- * then the data register is read/written as required.
- * I don't know what to do about interrupts (yet).
- */
-
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/bios32.h>
-#include <linux/delay.h>
-#include <linux/string.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-#include <asm/mbx.h>
-
-
-/*
- * This blows......The MBX uses the Tundra QSpan PCI bridge. When
- * reading the configuration space, if something does not respond
- * the bus times out and we get a machine check interrupt. So, the
- * good ol' exception tables come to mind to trap it and return some
- * value.
- *
- * On an error we just return a -1, since that is what the caller wants
- * returned if nothing is present. I copied this from __get_user_asm,
- * with the only difference of returning -1 instead of EFAULT.
- * There is an associated hack in the machine check trap code.
- *
- * The QSPAN is also a big endian device, that is it makes the PCI
- * look big endian to us. This presents a problem for the Linux PCI
- * functions, which assume little endian. For example, we see the
- * first 32-bit word like this:
- * ------------------------
- * | Device ID | Vendor ID |
- * ------------------------
- * If we read/write as a double word, that's OK. But in our world,
- * when read as a word, device ID is at location 0, not location 2 as
- * the little endian PCI would believe. We have to switch bits in
- * the PCI addresses given to us to get the data to/from the correct
- * byte lanes.
- *
- * The QSPAN only supports 4 bits of "slot" in the dev_fn instead of 5.
- * It always forces the MS bit to zero. Therefore, dev_fn values
- * greater than 128 are returned as "no device found" errors.
- *
- * The QSPAN can only perform long word (32-bit) configuration cycles.
- * The "offset" must have the two LS bits set to zero. Read operations
- * require we read the entire word and then sort out what should be
- * returned. Write operations other than long word require that we
- * read the long word, update the proper word or byte, then write the
- * entire long word back.
- *
- * PCI Bridge hack. We assume (correctly) that bus 0 is the primary
- * PCI bus from the QSPAN. If we are called with a bus number other
- * than zero, we create a Type 1 configuration access that a downstream
- * PCI bridge will interpret.
- */
-
-#define __get_mbx_pci_config(x, addr, op) \
- __asm__ __volatile__( \
- "1: "op" %0,0(%1)\n" \
- " eieio\n" \
- "2:\n" \
- ".section .fixup,\"ax\"\n" \
- "3: li %0,-1\n" \
- " b 2b\n" \
- ".section __ex_table,\"a\"\n" \
- " .align 2\n" \
- " .long 1b,3b\n" \
- ".text" \
- : "=r"(x) : "r"(addr))
-
-#define QS_CONFIG_ADDR ((volatile uint *)(PCI_CSR_ADDR + 0x500))
-#define QS_CONFIG_DATA ((volatile uint *)(PCI_CSR_ADDR + 0x504))
-
-#define mk_config_addr(bus, dev, offset) \
- (((bus)<<16) | ((dev)<<8) | (offset & 0xfc))
-
-#define mk_config_type1(bus, dev, offset) \
- mk_config_addr(bus, dev, offset) | 1;
-
-int mbx_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
- unsigned char offset, unsigned char *val)
-{
- uint temp;
- u_char *cp;
-
- if ((bus > 7) || (dev_fn > 127)) {
- *val = 0xff;
- return PCIBIOS_DEVICE_NOT_FOUND;
- }
-
- if (bus == 0)
- *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset);
- else
- *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset);
- __get_mbx_pci_config(temp, QS_CONFIG_DATA, "lwz");
-
- offset ^= 0x03;
- cp = ((u_char *)&temp) + (offset & 0x03);
- *val = *cp;
- return PCIBIOS_SUCCESSFUL;
-}
-
-int mbx_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
- unsigned char offset, unsigned short *val)
-{
- uint temp;
- ushort *sp;
-
- if ((bus > 7) || (dev_fn > 127)) {
- *val = 0xffff;
- return PCIBIOS_DEVICE_NOT_FOUND;
- }
-
- if (bus == 0)
- *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset);
- else
- *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset);
- __get_mbx_pci_config(temp, QS_CONFIG_DATA, "lwz");
- offset ^= 0x02;
-
- sp = ((ushort *)&temp) + ((offset >> 1) & 1);
- *val = *sp;
- return PCIBIOS_SUCCESSFUL;
-}
-
-int mbx_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
- unsigned char offset, unsigned int *val)
-{
- if ((bus > 7) || (dev_fn > 127)) {
- *val = 0xffffffff;
- return PCIBIOS_DEVICE_NOT_FOUND;
- }
- if (bus == 0)
- *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset);
- else
- *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset);
- __get_mbx_pci_config(*val, QS_CONFIG_DATA, "lwz");
- return PCIBIOS_SUCCESSFUL;
-}
-
-int mbx_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
- unsigned char offset, unsigned char val)
-{
- uint temp;
- u_char *cp;
-
- if ((bus > 7) || (dev_fn > 127))
- return PCIBIOS_DEVICE_NOT_FOUND;
-
- mbx_pcibios_read_config_dword(bus, dev_fn, offset, &temp);
-
- offset ^= 0x03;
- cp = ((u_char *)&temp) + (offset & 0x03);
- *cp = val;
-
- if (bus == 0)
- *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset);
- else
- *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset);
- *QS_CONFIG_DATA = temp;
-
- return PCIBIOS_SUCCESSFUL;
-}
-
-int mbx_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
- unsigned char offset, unsigned short val)
-{
- uint temp;
- ushort *sp;
-
- if ((bus > 7) || (dev_fn > 127))
- return PCIBIOS_DEVICE_NOT_FOUND;
-
- mbx_pcibios_read_config_dword(bus, dev_fn, offset, &temp);
-
- offset ^= 0x02;
- sp = ((ushort *)&temp) + ((offset >> 1) & 1);
- *sp = val;
-
- if (bus == 0)
- *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset);
- else
- *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset);
- *QS_CONFIG_DATA = temp;
-
- return PCIBIOS_SUCCESSFUL;
-}
-
-int mbx_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
- unsigned char offset, unsigned int val)
-{
- if ((bus > 7) || (dev_fn > 127))
- return PCIBIOS_DEVICE_NOT_FOUND;
-
- if (bus == 0)
- *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset);
- else
- *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset);
- *(unsigned int *)QS_CONFIG_DATA = val;
-
- return PCIBIOS_SUCCESSFUL;
-}
-
-int mbx_pcibios_find_device(unsigned short vendor, unsigned short dev_id,
- unsigned short index, unsigned char *bus_ptr,
- unsigned char *dev_fn_ptr)
-{
- int num, devfn;
- unsigned int x, vendev;
-
- if (vendor == 0xffff)
- return PCIBIOS_BAD_VENDOR_ID;
- vendev = (dev_id << 16) + vendor;
- num = 0;
- for (devfn = 0; devfn < 32; devfn++) {
- mbx_pcibios_read_config_dword(0, devfn<<3, PCI_VENDOR_ID, &x);
- if (x == vendev) {
- if (index == num) {
- *bus_ptr = 0;
- *dev_fn_ptr = devfn<<3;
- return PCIBIOS_SUCCESSFUL;
- }
- ++num;
- }
- }
- return PCIBIOS_DEVICE_NOT_FOUND;
-}
-
-int mbx_pcibios_find_class(unsigned int class_code, unsigned short index,
- unsigned char *bus_ptr, unsigned char *dev_fn_ptr)
-{
- int devnr, x, num;
-
- num = 0;
- for (devnr = 0; devnr < 32; devnr++) {
- mbx_pcibios_read_config_dword(0, devnr<<3, PCI_CLASS_REVISION, &x);
- if ((x>>8) == class_code) {
- if (index == num) {
- *bus_ptr = 0;
- *dev_fn_ptr = devnr<<3;
- return PCIBIOS_SUCCESSFUL;
- }
- ++num;
- }
- }
- return PCIBIOS_DEVICE_NOT_FOUND;
-}
-
-void __init
-mbx_pcibios_fixup(void)
-{
- /* Nothing to do here? */
-}
-
-void __init
-mbx_setup_pci_ptrs(void)
-{
- set_config_access_method(mbx);
-
- ppc_md.pcibios_fixup = mbx_pcibios_fixup;
-}
-
diff --git a/arch/ppc/kernel/mbx_setup.c b/arch/ppc/kernel/mbx_setup.c
deleted file mode 100644
index f6487783b..000000000
--- a/arch/ppc/kernel/mbx_setup.c
+++ /dev/null
@@ -1,486 +0,0 @@
-/*
- * $Id: mbx_setup.c,v 1.12 1999/08/31 06:53:56 davem Exp $
- *
- * linux/arch/ppc/kernel/setup.c
- *
- * Copyright (C) 1995 Linus Torvalds
- * Adapted from 'alpha' version by Gary Thomas
- * Modified by Cort Dougan (cort@cs.nmt.edu)
- * Modified for MBX using prep/chrp/pmac functions by Dan (dmalek@jlc.net)
- */
-
-/*
- * bootup setup stuff..
- */
-
-#include <linux/config.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/stddef.h>
-#include <linux/unistd.h>
-#include <linux/ptrace.h>
-#include <linux/malloc.h>
-#include <linux/user.h>
-#include <linux/a.out.h>
-#include <linux/tty.h>
-#include <linux/major.h>
-#include <linux/interrupt.h>
-#include <linux/reboot.h>
-#include <linux/init.h>
-#include <linux/blk.h>
-#include <linux/ide.h>
-#include <linux/ioport.h>
-
-#include <asm/mmu.h>
-#include <asm/processor.h>
-#include <asm/residual.h>
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/mbx.h>
-#include <asm/machdep.h>
-
-#include "time.h"
-#include "local_irq.h"
-
-static int mbx_set_rtc_time(unsigned long time);
-unsigned long mbx_get_rtc_time(void);
-void mbx_calibrate_decr(void);
-
-extern int mackbd_setkeycode(unsigned int scancode, unsigned int keycode);
-extern int mackbd_getkeycode(unsigned int scancode);
-extern int mackbd_translate(unsigned char scancode, unsigned char *keycode,
- char raw_mode);
-extern char mackbd_unexpected_up(unsigned char keycode);
-extern void mackbd_leds(unsigned char leds);
-extern void mackbd_init_hw(void);
-
-extern unsigned long loops_per_sec;
-
-unsigned long empty_zero_page[1024];
-
-#ifdef CONFIG_BLK_DEV_RAM
-extern int rd_doload; /* 1 = load ramdisk, 0 = don't load */
-extern int rd_prompt; /* 1 = prompt for ramdisk, 0 = don't prompt */
-extern int rd_image_start; /* starting block # of image */
-#endif
-
-extern char saved_command_line[256];
-
-extern unsigned long find_available_memory(void);
-extern void m8xx_cpm_reset(uint);
-
-void __init adbdev_init(void)
-{
-}
-
-void __init
-mbx_setup_arch(void)
-{
- int cpm_page;
- extern char cmd_line[];
-
- cpm_page = (int) alloc_bootmem_pages(PAGE_SIZE);
-
- sprintf(cmd_line,
-"%s root=/dev/nfs nfsroot=/sys/mbxroot",
- cmd_line);
- printk("Boot arguments: %s\n", cmd_line);
-
- /* Reset the Communication Processor Module.
- */
- m8xx_cpm_reset(cpm_page);
-
-#ifdef notdef
- ROOT_DEV = to_kdev_t(0x0301); /* hda1 */
-#endif
-
-#ifdef CONFIG_BLK_DEV_INITRD
-#if 0
- ROOT_DEV = to_kdev_t(0x0200); /* floppy */
- rd_prompt = 1;
- rd_doload = 1;
- rd_image_start = 0;
-#endif
-#if 0 /* XXX this may need to be updated for the new bootmem stuff,
- or possibly just deleted (see set_phys_avail() in init.c).
- - paulus. */
- /* initrd_start and size are setup by boot/head.S and kernel/head.S */
- if ( initrd_start )
- {
- if (initrd_end > *memory_end_p)
- {
- printk("initrd extends beyond end of memory "
- "(0x%08lx > 0x%08lx)\ndisabling initrd\n",
- initrd_end,*memory_end_p);
- initrd_start = 0;
- }
- }
-#endif
-#endif
-
-#ifdef notdef
- request_region(0x20,0x20,"pic1");
- request_region(0xa0,0x20,"pic2");
- request_region(0x00,0x20,"dma1");
- request_region(0x40,0x20,"timer");
- request_region(0x80,0x10,"dma page reg");
- request_region(0xc0,0x20,"dma2");
-#endif
-}
-
-void
-abort(void)
-{
-#ifdef CONFIG_XMON
- extern void xmon(void *);
- xmon(0);
-#endif
- machine_restart(NULL);
-}
-
-/* The decrementer counts at the system (internal) clock frequency divided by
- * sixteen, or external oscillator divided by four. Currently, we only
- * support the MBX, which is system clock divided by sixteen.
- */
-void __init mbx_calibrate_decr(void)
-{
- bd_t *binfo = (bd_t *)&res;
- int freq, fp, divisor;
-
- if ((((immap_t *)MBX_IMAP_ADDR)->im_clkrst.car_sccr & 0x02000000) == 0)
- printk("WARNING: Wrong decrementer source clock.\n");
-
- /* The manual says the frequency is in Hz, but it is really
- * as MHz. The value 'fp' is the number of decrementer ticks
- * per second.
- */
- fp = (binfo->bi_intfreq * 1000000) / 16;
- freq = fp*60; /* try to make freq/1e6 an integer */
- divisor = 60;
- printk("time_init: decrementer frequency = %d/%d\n", freq, divisor);
- decrementer_count = freq / HZ / divisor;
- count_period_num = divisor;
- count_period_den = freq / 1000000;
-}
-
-/* A place holder for time base interrupts, if they are ever enabled.
-*/
-void timebase_interrupt(int irq, void * dev, struct pt_regs * regs)
-{
- printk("timebase_interrupt()\n");
-}
-
-/* The RTC on the MPC8xx is an internal register.
- * We want to protect this during power down, so we need to unlock,
- * modify, and re-lock.
- */
-static int
-mbx_set_rtc_time(unsigned long time)
-{
- ((immap_t *)MBX_IMAP_ADDR)->im_sitk.sitk_rtck = KAPWR_KEY;
- ((immap_t *)MBX_IMAP_ADDR)->im_sit.sit_rtc = time;
- ((immap_t *)MBX_IMAP_ADDR)->im_sitk.sitk_rtck = ~KAPWR_KEY;
- return(0);
-}
-
-unsigned long __init mbx_get_rtc_time(void)
-{
- /* First, unlock all of the registers we are going to modify.
- * To protect them from corruption during power down, registers
- * that are maintained by keep alive power are "locked". To
- * modify these registers we have to write the key value to
- * the key location associated with the register.
- */
- ((immap_t *)MBX_IMAP_ADDR)->im_sitk.sitk_tbscrk = KAPWR_KEY;
- ((immap_t *)MBX_IMAP_ADDR)->im_sitk.sitk_rtcsck = KAPWR_KEY;
-
-
- /* Disable the RTC one second and alarm interrupts.
- */
- ((immap_t *)MBX_IMAP_ADDR)->im_sit.sit_rtcsc &=
- ~(RTCSC_SIE | RTCSC_ALE);
-
- /* Enabling the decrementer also enables the timebase interrupts
- * (or from the other point of view, to get decrementer interrupts
- * we have to enable the timebase). The decrementer interrupt
- * is wired into the vector table, nothing to do here for that.
- */
- ((immap_t *)MBX_IMAP_ADDR)->im_sit.sit_tbscr =
- ((mk_int_int_mask(DEC_INTERRUPT) << 8) |
- (TBSCR_TBF | TBSCR_TBE));
- if (request_irq(DEC_INTERRUPT, timebase_interrupt, 0, "tbint", NULL) != 0)
- panic("Could not allocate timer IRQ!");
-
- /* Get time from the RTC.
- */
- return ((immap_t *)MBX_IMAP_ADDR)->im_sit.sit_rtc;
-}
-
-void
-mbx_restart(char *cmd)
-{
- extern void MBX_gorom(void);
-
- MBX_gorom();
-}
-
-void
-mbx_power_off(void)
-{
- mbx_restart(NULL);
-}
-
-void
-mbx_halt(void)
-{
- mbx_restart(NULL)
-}
-
-
-int mbx_setup_residual(char *buffer)
-{
- int len = 0;
- bd_t *bp;
- extern RESIDUAL *res;
-
- bp = (bd_t *)res;
-
- len += sprintf(len+buffer,"clock\t\t: %dMHz\n"
- "bus clock\t: %dMHz\n",
- bp->bi_intfreq /*/ 1000000*/,
- bp->bi_busfreq /*/ 1000000*/);
-
- return len;
-}
-
-void
-mbx_do_IRQ(struct pt_regs *regs,
- int cpu,
- int isfake)
-{
- int irq;
- unsigned long bits = 0;
-
- /* For MPC8xx, read the SIVEC register and shift the bits down
- * to get the irq number. */
- bits = ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sivec;
- irq = bits >> 26;
- irq += ppc8xx_pic.irq_offset;
- bits = 1UL << irq;
-
- if (irq < 0) {
- printk(KERN_DEBUG "Bogus interrupt %d from PC = %lx\n",
- irq, regs->nip);
- spurious_interrupts++;
- }
- else {
- ppc_irq_dispatch_handler( regs, irq );
- }
-
-}
-
-static void mbx_i8259_action(int cpl, void *dev_id, struct pt_regs *regs)
-{
- int bits, irq;
-
- /* A bug in the QSpan chip causes it to give us 0xff always
- * when doing a character read. So read 32 bits and shift.
- * This doesn't seem to return useful values anyway, but
- * read it to make sure things are acked.
- * -- Cort
- */
- irq = (inl(0x508) >> 24)&0xff;
- if ( irq != 0xff ) printk("iack %d\n", irq);
-
- outb(0x0C, 0x20);
- irq = inb(0x20) & 7;
- if (irq == 2)
- {
- outb(0x0C, 0xA0);
- irq = inb(0xA0);
- irq = (irq&7) + 8;
- }
- bits = 1UL << irq;
- irq += i8259_pic.irq_offset;
- ppc_irq_dispatch_handler( regs, irq );
-}
-
-
-/* On MBX8xx, the interrupt control (SIEL) was set by EPPC-bug. External
- * interrupts can be either edge or level triggered, but there is no
- * reason for us to change the EPPC-bug values (it would not work if we did).
- */
-void __init
-mbx_init_IRQ(void)
-{
- int i;
-
- ppc8xx_pic.irq_offset = 16;
- for ( i = 16 ; i < 32 ; i++ )
- irq_desc[i].ctl = &ppc8xx_pic;
- unmask_irq(CPM_INTERRUPT);
-
- for ( i = 0 ; i < 16 ; i++ )
- irq_desc[i].ctl = &i8259_pic;
- i8259_init();
- request_irq(ISA_BRIDGE_INT, mbx_i8259_action, 0, "8259 cascade", NULL);
- enable_irq(ISA_BRIDGE_INT);
-}
-
-#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
-/*
- * IDE stuff.
- */
-void
-mbx_ide_insw(ide_ioreg_t port, void *buf, int ns)
-{
- ide_insw(port+_IO_BASE), buf, ns);
-}
-
-void
-mbx_ide_outsw(ide_ioreg_t port, void *buf, int ns)
-{
- ide_outsw(port+_IO_BASE, buf, ns);
-}
-
-int
-mbx_ide_default_irq(ide_ioreg_t base)
-{
- return 14;
-}
-
-ide_ioreg_t
-mbx_ide_default_io_base(int index)
-{
- return index;
-}
-
-int
-mbx_ide_check_region(ide_ioreg_t from, unsigned int extent)
-{
- return 0
-}
-
-void
-mbx_ide_request_region(ide_ioreg_t from,
- unsigned int extent,
- const char *name)
-{
-}
-
-void
-mbx_ide_release_region(ide_ioreg_t from,
- unsigned int extent)
-{
-}
-
-void
-mbx_ide_fix_driveid(struct hd_driveid *id)
-{
- ppc_generic_ide_fix_driveid(id);
-}
-
-void
-mbx_ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq)
-{
- ide_ioreg_t reg = data_port;
- int i;
-
- *irq = 0;
-
- if (data_port != 0) /* Only map the first ATA flash drive */
- return;
-
-#ifdef ATA_FLASH
-
- reg = (ide_ioreg_t) ioremap(PCMCIA_MEM_ADDR, 0x200);
-
- for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
- hw->io_ports[i] = reg;
- reg += 1;
- }
-
- /* Does not matter */
-
- if (ctrl_port) {
- hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port;
- } else {
- hw->io_ports[IDE_CONTROL_OFFSET] = reg;
- }
- if (irq)
- hw->irq = 13;
-#endif
-}
-#endif
-
-void __init
-mbx_init(unsigned long r3, unsigned long r4, unsigned long r5,
- unsigned long r6, unsigned long r7)
-{
-
- if ( r3 )
- memcpy( (void *)&res,(void *)(r3+KERNELBASE), sizeof(bd_t) );
-
-#ifdef CONFIG_PCI
- mbx_setup_pci_ptrs();
-#endif
-
-#ifdef CONFIG_BLK_DEV_INITRD
- /* take care of initrd if we have one */
- if ( r4 )
- {
- initrd_start = r4 + KERNELBASE;
- initrd_end = r5 + KERNELBASE;
- }
-#endif /* CONFIG_BLK_DEV_INITRD */
- /* take care of cmd line */
- if ( r6 )
- {
-
- *(char *)(r7+KERNELBASE) = 0;
- strcpy(cmd_line, (char *)(r6+KERNELBASE));
- }
-
- ppc_md.setup_arch = mbx_setup_arch;
- ppc_md.setup_residual = mbx_setup_residual;
- ppc_md.get_cpuinfo = NULL;
- ppc_md.irq_cannonicalize = NULL;
- ppc_md.init_IRQ = mbx_init_IRQ;
- ppc_md.do_IRQ = mbx_do_IRQ;
- ppc_md.init = NULL;
-
- ppc_md.restart = mbx_restart;
- ppc_md.power_off = mbx_power_off;
- ppc_md.halt = mbx_halt;
-
- ppc_md.time_init = NULL;
- ppc_md.set_rtc_time = mbx_set_rtc_time;
- ppc_md.get_rtc_time = mbx_get_rtc_time;
- ppc_md.calibrate_decr = mbx_calibrate_decr;
-
- ppc_md.kbd_setkeycode = pckbd_setkeycode;
- ppc_md.kbd_getkeycode = pckbd_getkeycode;
- ppc_md.kbd_translate = pckbd_translate;
- ppc_md.kbd_unexpected_up = pckbd_unexpected_up;
- ppc_md.kbd_leds = pckbd_leds;
- ppc_md.kbd_init_hw = pckbd_init_hw;
-#ifdef CONFIG_MAGIC_SYSRQ
- ppc_md.kbd_sysrq_xlate = pckbd_sysrq_xlate;
-#endif
-
-#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
- ppc_ide_md.insw = mbx_ide_insw;
- ppc_ide_md.outsw = mbx_ide_outsw;
- ppc_ide_md.default_irq = mbx_ide_default_irq;
- ppc_ide_md.default_io_base = mbx_ide_default_io_base;
- ppc_ide_md.ide_check_region = mbx_ide_check_region;
- ppc_ide_md.ide_request_region = mbx_ide_request_region;
- ppc_ide_md.ide_release_region = mbx_ide_release_region;
- ppc_ide_md.fix_driveid = mbx_ide_fix_driveid;
- ppc_ide_md.ide_init_hwif = mbx_ide_init_hwif_ports;
-
- ppc_ide_md.io_base = _IO_BASE;
-#endif
-}
diff --git a/arch/ppc/kernel/open_pic.c b/arch/ppc/kernel/open_pic.c
index 4b0375433..02e276729 100644
--- a/arch/ppc/kernel/open_pic.c
+++ b/arch/ppc/kernel/open_pic.c
@@ -64,14 +64,13 @@ struct hw_interrupt_type open_pic = {
if (pri < 0 || pri >= OPENPIC_NUM_PRI) \
printk("openpic.c:%d: illegal priority %d\n", __LINE__, pri);
/*
- * 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
+ * I changed this to return to keep us from from trying to use irq #'s
+ * that we're using for IPI's.
+ * -- Cort
+ */
+#define check_arg_irq(irq) \
+ /*if (irq < 0 || irq >= (NumSources+open_pic.irq_offset)) \
+ printk("openpic.c:%d: illegal irq %d\n", __LINE__, irq);*/
#define check_arg_cpu(cpu) \
if (cpu < 0 || cpu >= NumProcessors) \
printk("openpic.c:%d: illegal cpu %d\n", __LINE__, cpu);
@@ -91,8 +90,7 @@ static void no_action(int ir1, void *dev, struct pt_regs *regs)
#ifdef __SMP__
void openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs)
{
-printk("openpic_ipi_action\n");
- smp_message_recv();
+ smp_message_recv(cpl-OPENPIC_VEC_IPI);
}
#endif /* __SMP__ */
@@ -213,6 +211,9 @@ void __init openpic_init(int main_pic)
/* 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,
@@ -226,9 +227,6 @@ void __init openpic_init(int main_pic)
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");
@@ -366,6 +364,27 @@ void openpic_enable_IPI(u_int ipi)
}
/*
+ * Do per-cpu setup for SMP systems.
+ *
+ * Get IPI's working and start taking interrupts.
+ * -- Cort
+ */
+void do_openpic_setup_cpu(void)
+{
+ int i;
+
+ for ( i = 0; i < OPENPIC_NUM_IPI ; i++ )
+ openpic_enable_IPI(i);
+#if 0
+ /* let the openpic know we want intrs */
+ for ( i = 0; i < NumSources ; i++ )
+ openpic_mapirq(i, openpic_read(&OpenPIC->Source[i].Destination)
+ | (1<<smp_processor_id()) );
+#endif
+ openpic_set_priority(smp_processor_id(), 0);
+}
+
+/*
* Initialize a timer interrupt (and disable it)
*
* timer: OpenPIC timer number
@@ -397,13 +416,13 @@ void openpic_maptimer(u_int timer, u_int cpumask)
void openpic_enable_irq(u_int irq)
{
check_arg_irq(irq);
- openpic_clearfield(&OpenPIC->Source[irq-irq_desc[irq].ctl->irq_offset].Vector_Priority, OPENPIC_MASK);
+ openpic_clearfield(&OpenPIC->Source[irq-irq_desc[irq].handler->irq_offset].Vector_Priority, OPENPIC_MASK);
}
void openpic_disable_irq(u_int irq)
{
check_arg_irq(irq);
- openpic_setfield(&OpenPIC->Source[irq-irq_desc[irq].ctl->irq_offset].Vector_Priority, OPENPIC_MASK);
+ openpic_setfield(&OpenPIC->Source[irq-irq_desc[irq].handler->irq_offset].Vector_Priority, OPENPIC_MASK);
}
/*
diff --git a/arch/ppc/kernel/open_pic.h b/arch/ppc/kernel/open_pic.h
index 1097c70bf..2673263cf 100644
--- a/arch/ppc/kernel/open_pic.h
+++ b/arch/ppc/kernel/open_pic.h
@@ -5,5 +5,6 @@ extern struct hw_interrupt_type open_pic;
void openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs);
void openpic_enable_IPI(u_int ipi);
+void do_openpic_setup_cpu(void);
#endif /* _PPC_KERNEL_OPEN_PIC_H */
diff --git a/arch/ppc/kernel/pci.c b/arch/ppc/kernel/pci.c
index 054eee918..ec1ff3565 100644
--- a/arch/ppc/kernel/pci.c
+++ b/arch/ppc/kernel/pci.c
@@ -91,15 +91,17 @@ unsigned long resource_fixup(struct pci_dev * dev, struct resource * res,
return start;
}
-static void __init pcibios_claim_resources(struct pci_bus *bus)
+static void __init pcibios_claim_resources(struct list_head *bus_list)
{
+ struct list_head *ln, *dn;
+ struct pci_bus *bus;
struct pci_dev *dev;
int idx;
- while (bus)
- {
- for (dev=bus->devices; dev; dev=dev->sibling)
- {
+ for (ln=bus_list->next; ln != bus_list; ln=ln->next) {
+ bus = pci_bus_b(ln);
+ for (dn=bus->devices.next; dn != &bus->devices; dn=dn->next) {
+ dev = pci_dev_b(dn);
for (idx = 0; idx < PCI_NUM_RESOURCES; idx++)
{
struct resource *r = &dev->resource[idx];
@@ -114,9 +116,7 @@ static void __init pcibios_claim_resources(struct pci_bus *bus)
}
}
}
- if (bus->children)
- pcibios_claim_resources(bus->children);
- bus = bus->next;
+ pcibios_claim_resources(&bus->children);
}
}
diff --git a/arch/ppc/kernel/pmac_pci.c b/arch/ppc/kernel/pmac_pci.c
index a9166da34..75f8097fd 100644
--- a/arch/ppc/kernel/pmac_pci.c
+++ b/arch/ppc/kernel/pmac_pci.c
@@ -476,7 +476,7 @@ pmac_pcibios_fixup(void)
* honor the existence of multi-function devices where
* different functions have different interrupt pins. [mj]
*/
- for(dev=pci_devices; dev; dev=dev->next)
+ pci_for_each_dev(dev)
{
/*
* Open Firmware often doesn't initialize the,
diff --git a/arch/ppc/kernel/pmac_pic.c b/arch/ppc/kernel/pmac_pic.c
index f7224f5dd..385e23327 100644
--- a/arch/ppc/kernel/pmac_pic.c
+++ b/arch/ppc/kernel/pmac_pic.c
@@ -135,7 +135,7 @@ static void gatwick_action(int cpl, void *dev_id, struct pt_regs *regs)
* don't. Put this here to check for it.
* -- Cort
*/
- if ( irq_desc[irq].ctl != &gatwick_pic )
+ if ( irq_desc[irq].handler != &gatwick_pic )
printk("gatwick irq not from gatwick pic\n");
else
ppc_irq_dispatch_handler( regs, irq );
@@ -159,7 +159,7 @@ pmac_do_IRQ(struct pt_regs *regs,
if (xmon_2nd)
xmon(regs);
#endif
- smp_message_recv();
+ pmac_smp_message_recv();
return -1;
}
@@ -361,7 +361,7 @@ pmac_pic_init(void)
max_irqs = 64;
}
for ( i = 0; i < max_real_irqs ; i++ )
- irq_desc[i].ctl = &pmac_pic;
+ irq_desc[i].handler = &pmac_pic;
/* get addresses of first controller */
if (irqctrler) {
@@ -401,7 +401,7 @@ pmac_pic_init(void)
if (device_is_compatible(irqctrler, "gatwick"))
pmac_fix_gatwick_interrupts(irqctrler, max_real_irqs);
for ( i = max_real_irqs ; i < max_irqs ; i++ )
- irq_desc[i].ctl = &gatwick_pic;
+ irq_desc[i].handler = &gatwick_pic;
request_irq( second_irq, gatwick_action, SA_INTERRUPT,
"gatwick cascade", 0 );
}
diff --git a/arch/ppc/kernel/pmac_setup.c b/arch/ppc/kernel/pmac_setup.c
index 4c3e9a790..72d23a934 100644
--- a/arch/ppc/kernel/pmac_setup.c
+++ b/arch/ppc/kernel/pmac_setup.c
@@ -198,32 +198,12 @@ pmac_get_cpuinfo(char *buffer)
#ifdef CONFIG_SCSI
/* Find the device number for the disk (if any) at target tgt
- on host adaptor host.
- XXX this really really should be in drivers/scsi/sd.c. */
+ on host adaptor host. We just need to get the prototype from
+ sd.h */
#include <linux/blkdev.h>
#include "../../../drivers/scsi/scsi.h"
#include "../../../drivers/scsi/sd.h"
-#include "../../../drivers/scsi/hosts.h"
-#define SD_MAJOR(i) (!(i) ? SCSI_DISK0_MAJOR : SCSI_DISK1_MAJOR-1+(i))
-#define SD_MAJOR_NUMBER(i) SD_MAJOR((i) >> 8)
-#define SD_MINOR_NUMBER(i) ((i) & 255)
-#define MKDEV_SD_PARTITION(i) MKDEV(SD_MAJOR_NUMBER(i), SD_MINOR_NUMBER(i))
-#define MKDEV_SD(index) MKDEV_SD_PARTITION((index) << 4)
-
-__init
-kdev_t sd_find_target(void *host, int tgt)
-{
- Scsi_Disk *dp;
- int i;
-#ifdef CONFIG_BLK_DEV_SD
- for (dp = rscsi_disks, i = 0; i < sd_template.dev_max; ++i, ++dp)
- if (dp->device != NULL && dp->device->host == host
- && dp->device->id == tgt)
- return MKDEV_SD(i);
-#endif /* CONFIG_BLK_DEV_SD */
- return 0;
-}
#endif
/*
diff --git a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c
index 11d2cd114..397685d43 100644
--- a/arch/ppc/kernel/ppc_ksyms.c
+++ b/arch/ppc/kernel/ppc_ksyms.c
@@ -9,6 +9,8 @@
#include <linux/vt_kern.h>
#include <linux/nvram.h>
#include <linux/spinlock.h>
+#include <linux/console.h>
+#include <linux/irq.h>
#include <asm/page.h>
#include <asm/semaphore.h>
@@ -269,3 +271,4 @@ void ppc_irq_dispatch_handler(struct pt_regs *, int);
EXPORT_SYMBOL(ppc_irq_dispatch_handler);
EXPORT_SYMBOL(decrementer_count);
EXPORT_SYMBOL(get_wchan);
+EXPORT_SYMBOL(console_drivers);
diff --git a/arch/ppc/kernel/prep_pci.c b/arch/ppc/kernel/prep_pci.c
index a01962b12..633757875 100644
--- a/arch/ppc/kernel/prep_pci.c
+++ b/arch/ppc/kernel/prep_pci.c
@@ -998,7 +998,7 @@ prep_pcibios_fixup(void)
printk("Setting PCI interrupts for a \"%s\"\n", Motherboard_map_name);
if (OpenPIC) {
/* PCI interrupts are controlled by the OpenPIC */
- for(dev=pci_devices; dev; dev=dev->next) {
+ pci_for_each_dev(dev) {
if (dev->bus->number == 0) {
dev->irq = openpic_to_irq(Motherboard_map[PCI_SLOT(dev->devfn)]);
pcibios_write_config_byte(dev->bus->number, dev->devfn, PCI_INTERRUPT_PIN, dev->irq);
@@ -1007,8 +1007,7 @@ prep_pcibios_fixup(void)
return;
}
- for(dev=pci_devices; dev; dev=dev->next)
- {
+ pci_for_each_dev(dev) {
/*
* Use our old hard-coded kludge to figure out what
* irq this device uses. This is necessary on things
diff --git a/arch/ppc/kernel/prep_setup.c b/arch/ppc/kernel/prep_setup.c
index e7f62c429..19ae61450 100644
--- a/arch/ppc/kernel/prep_setup.c
+++ b/arch/ppc/kernel/prep_setup.c
@@ -617,12 +617,12 @@ prep_init_IRQ(void)
if (OpenPIC != NULL) {
for ( i = 16 ; i < 36 ; i++ )
- irq_desc[i].ctl = &open_pic;
+ irq_desc[i].handler = &open_pic;
openpic_init(1);
}
for ( i = 0 ; i < 16 ; i++ )
- irq_desc[i].ctl = &i8259_pic;
+ irq_desc[i].handler = &i8259_pic;
i8259_init();
#ifdef __SMP__
request_irq(openpic_to_irq(OPENPIC_VEC_SPURIOUS), openpic_ipi_action,
diff --git a/arch/ppc/kernel/process.c b/arch/ppc/kernel/process.c
index 403213883..64b171042 100644
--- a/arch/ppc/kernel/process.c
+++ b/arch/ppc/kernel/process.c
@@ -204,15 +204,6 @@ _switch_to(struct task_struct *prev, struct task_struct *new,
if ( (prev->thread.regs && (prev->thread.regs->msr & MSR_VEC)) &&
prev->thread.vrsave )
giveup_altivec(prev);
- /*
- * The 750 doesn't broadcast invalidates with tlbie's
- * so flush every processor switch.
- * -- Cort
- */
- if ( ((_get_PVR()>>16) == 8) &&
- (new->last_processor != NO_PROC_ID) &&
- (new->last_processor != new->processor) && new->mm )
- flush_tlb_mm(new->mm);
prev->last_processor = prev->processor;
current_set[smp_processor_id()] = new;
#endif /* __SMP__ */
diff --git a/arch/ppc/kernel/smp.c b/arch/ppc/kernel/smp.c
index fad7c7c1d..c2891e21f 100644
--- a/arch/ppc/kernel/smp.c
+++ b/arch/ppc/kernel/smp.c
@@ -108,34 +108,8 @@ void smp_local_timer_interrupt(struct pt_regs * regs)
}
}
-/*
- * Dirty hack to get smp message passing working.
- *
- * As it is now, if we're sending two message at the same time
- * we have race conditions. The PowerSurge doesn't easily
- * allow us to send IPI messages so we put the messages in
- * smp_message[].
- *
- * This is because don't have several IPI's on the PowerSurge even though
- * we do on the chrp. It would be nice to use the actual IPI's on the chrp
- * rather than this but having two methods of doing IPI isn't a good idea
- * right now.
- * -- Cort
- */
-int smp_message[NR_CPUS];
-void smp_message_recv(void)
+void smp_message_recv(int msg)
{
- int msg = smp_message[smp_processor_id()];
-
- if ( _machine == _MACH_Pmac )
- {
- /* clear interrupt */
- out_be32(PSURGE_INTR, ~0);
- }
-
- /* make sure msg is for us */
- if ( msg == -1 ) return;
-
ipi_count++;
switch( msg )
@@ -147,15 +121,54 @@ void smp_message_recv(void)
case MSG_RESCHEDULE:
current->need_resched = 1;
break;
- case 0xf0f0: /* syncing time bases - just return */
+ case MSG_INVALIDATE_TLB:
+ _tlbia();
+ case 0xf0f0: /* pmac syncing time bases - just return */
break;
default:
printk("SMP %d: smp_message_recv(): unknown msg %d\n",
smp_processor_id(), msg);
break;
}
- /* reset message */
- smp_message[smp_processor_id()] = -1;
+}
+
+/*
+ * As it is now, if we're sending two message at the same time
+ * we have race conditions on Pmac. The PowerSurge doesn't easily
+ * allow us to send IPI messages so we put the messages in
+ * smp_message[].
+ *
+ * This is because don't have several IPI's on the PowerSurge even though
+ * we do on the chrp. It would be nice to use actual IPI's such as with openpic
+ * rather than this.
+ * -- Cort
+ */
+int pmac_smp_message[NR_CPUS];
+void pmac_smp_message_recv(void)
+{
+ int msg = pmac_smp_message[smp_processor_id()];
+
+ /* clear interrupt */
+ out_be32(PSURGE_INTR, ~0);
+
+ /* make sure msg is for us */
+ if ( msg == -1 ) return;
+
+ smp_message_recv(msg);
+
+ /* reset message */
+ pmac_smp_message[smp_processor_id()] = -1;
+}
+
+/*
+ * 750's don't broadcast tlb invalidates so
+ * we have to emulate that behavior.
+ * -- Cort
+ */
+void smp_send_tlb_invalidate(int cpu)
+{
+ if ( (_get_PVR()>>16) == 8 )
+ smp_message_pass(MSG_ALL_BUT_SELF, MSG_INVALIDATE_TLB, 0, 0);
}
void smp_send_reschedule(int cpu)
@@ -169,6 +182,8 @@ void smp_send_reschedule(int cpu)
* 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);
}
@@ -177,38 +192,39 @@ void smp_send_stop(void)
smp_message_pass(MSG_ALL_BUT_SELF, MSG_STOP_CPU, 0, 0);
}
-spinlock_t mesg_pass_lock = SPIN_LOCK_UNLOCKED;
void smp_message_pass(int target, int msg, unsigned long data, int wait)
{
int i;
- if ( !(_machine & (_MACH_Pmac|_MACH_chrp|_MACH_gemini)) )
+
+ if ( !(_machine & (_MACH_Pmac|_MACH_chrp|_MACH_prep|_MACH_gemini)) )
return;
- spin_lock(&mesg_pass_lock);
-
- /*
- * We assume here that the msg is not -1. If it is,
- * the recipient won't know the message was destined
- * for it. -- Cort
- */
-
- switch( target )
- {
- case MSG_ALL:
- smp_message[smp_processor_id()] = msg;
- /* fall through */
- case MSG_ALL_BUT_SELF:
- for ( i = 0 ; i < smp_num_cpus ; i++ )
- if ( i != smp_processor_id () )
- smp_message[i] = msg;
- break;
- default:
- smp_message[target] = msg;
- break;
- }
-
- if ( _machine == _MACH_Pmac )
- {
+ switch (_machine) {
+ case _MACH_Pmac:
+ /*
+ * IPI's on the Pmac are a hack but without reasonable
+ * IPI hardware SMP on Pmac is a hack.
+ *
+ * We assume here that the msg is not -1. If it is,
+ * the recipient won't know the message was destined
+ * for it. -- Cort
+ */
+ for ( i = 0; i <= smp_num_cpus ; i++ )
+ pmac_smp_message[i] = -1;
+ switch( target )
+ {
+ case MSG_ALL:
+ pmac_smp_message[smp_processor_id()] = msg;
+ /* fall through */
+ case MSG_ALL_BUT_SELF:
+ for ( i = 0 ; i < smp_num_cpus ; i++ )
+ if ( i != smp_processor_id () )
+ pmac_smp_message[i] = msg;
+ break;
+ default:
+ pmac_smp_message[target] = msg;
+ break;
+ }
/* interrupt secondary processor */
out_be32(PSURGE_INTR, ~0);
out_be32(PSURGE_INTR, 0);
@@ -218,40 +234,28 @@ void smp_message_pass(int target, int msg, unsigned long data, int wait)
*/
/* interrupt primary */
/**(volatile unsigned long *)(0xf3019000);*/
- }
-
- if ( _machine == _MACH_chrp )
- {
- /*
- * There has to be some way of doing this better -
- * perhaps a send-to-all or send-to-all-but-self
- * in the openpic. This gets us going for now, though.
- * -- Cort
- */
+ break;
+ case _MACH_chrp:
+ case _MACH_prep:
+ case _MACH_gemini:
+ /* make sure we're sending something that translates to an IPI */
+ if ( msg > 0x3 )
+ break;
switch ( target )
{
case MSG_ALL:
- openpic_cause_IPI(smp_processor_id(), 0, 0x0 );
- openpic_cause_IPI(smp_processor_id(), 0, 0xffffffff );
+ openpic_cause_IPI(smp_processor_id(), msg, 0xffffffff);
break;
case MSG_ALL_BUT_SELF:
- for ( i = 0 ; i < smp_num_cpus ; i++ )
- if ( i != smp_processor_id () )
- {
- openpic_cause_IPI(smp_processor_id(), 0,
- 0x0 );
- openpic_cause_IPI(smp_processor_id(), 0,
+ openpic_cause_IPI(smp_processor_id(), msg,
0xffffffff & ~(1 << smp_processor_id()));
- }
break;
default:
- openpic_cause_IPI(smp_processor_id(), 0, 0x0 );
- openpic_cause_IPI(target, 0, 1U << target );
+ openpic_cause_IPI(smp_processor_id(), msg, 1<<target);
break;
}
+ break;
}
-
- spin_unlock(&mesg_pass_lock);
}
void __init smp_boot_cpus(void)
@@ -387,6 +391,9 @@ void __init smp_boot_cpus(void)
}
}
+ if ( _machine & (_MACH_gemini|_MACH_chrp|_MACH_prep) )
+ do_openpic_setup_cpu();
+
if ( _machine == _MACH_Pmac )
{
/* reset the entry point so if we get another intr we won't
@@ -432,6 +439,13 @@ void __init smp_callin(void)
current->mm->mmap->vm_end = init_mm.mmap->vm_end;
#endif
cpu_callin_map[current->processor] = 1;
+ /*
+ * Each processor has to do this and this is the best
+ * place to stick it for now.
+ * -- Cort
+ */
+ if ( _machine & (_MACH_gemini|_MACH_chrp|_MACH_prep) )
+ do_openpic_setup_cpu();
while(!smp_commenced)
barrier();
__sti();
diff --git a/arch/ppc/lib/Makefile b/arch/ppc/lib/Makefile
index 8ca9a3cd5..e454e952d 100644
--- a/arch/ppc/lib/Makefile
+++ b/arch/ppc/lib/Makefile
@@ -3,7 +3,7 @@
#
.S.o:
- $(CC) -D__ASSEMBLY__ -c $< -o $*.o
+ $(CC) -D__ASSEMBLY__ $(AFLAGS) -c $< -o $*.o
O_TARGET = lib.o
O_OBJS = checksum.o string.o strcase.o
diff --git a/arch/ppc/mbxboot/Makefile b/arch/ppc/mbxboot/Makefile
index ce86ebbe8..0a70462a7 100644
--- a/arch/ppc/mbxboot/Makefile
+++ b/arch/ppc/mbxboot/Makefile
@@ -16,9 +16,9 @@
.c.o:
$(CC) $(CFLAGS) -DINITRD_OFFSET=$(IOFF) -DINITRD_SIZE=$(ISZ) -DZIMAGE_OFFSET=$(ZOFF) -DZIMAGE_SIZE=$(ZSZ) -c -o $*.o $<
.S.s:
- $(CC) -D__ASSEMBLY__ -traditional -E -o $*.o $<
+ $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -E -o $*.o $<
.S.o:
- $(CC) -D__ASSEMBLY__ -traditional -c -o $*.o $<
+ $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c -o $*.o $<
ZOFF = 0
ZSZ = 0
@@ -30,7 +30,7 @@ ZLINKFLAGS = -T ../vmlinux.lds -Ttext 0x00100000
GZIP_FLAGS = -v9
OBJECTS := head.o misc.o ../coffboot/zlib.o m8xx_tty.o
-CFLAGS = -O2 -DSTDC_HEADERS -fno-builtin -I$(TOPDIR)/include -DCONFIG_8xx
+CFLAGS = $(CPPFLAGS) -O2 -DSTDC_HEADERS -fno-builtin -DCONFIG_8xx
OBJCOPY = $(CROSS_COMPILE)objcopy
OBJCOPY_ARGS = -O elf32-powerpc
@@ -109,7 +109,7 @@ fastdep:
$(TOPDIR)/scripts/mkdep *.[Sch] > .depend
dep:
- $(CPP) -M *.S *.c > .depend
+ $(CPP) $(CPPFLAGS) -M *.S *.c > .depend
# just here to match coffboot/Makefile
vmlinux.coff:
diff --git a/arch/ppc/mm/init.c b/arch/ppc/mm/init.c
index 397083aca..34117098e 100644
--- a/arch/ppc/mm/init.c
+++ b/arch/ppc/mm/init.c
@@ -324,23 +324,24 @@ void show_mem(void)
void si_meminfo(struct sysinfo *val)
{
- int i, c;
+ int i;
i = max_mapnr;
- val->totalram = totalram_pages;
+ val->totalram = 0;
+ val->sharedram = 0;
val->freeram = nr_free_pages();
val->bufferram = atomic_read(&buffermem_pages);
- val->sharedram = 0;
while (i-- > 0) {
if (PageReserved(mem_map+i))
continue;
- c = atomic_read(&mem_map[i].count);
- if (c > 1)
- val->sharedram += c - 1;
+ val->totalram++;
+ if (!atomic_read(&mem_map[i].count))
+ continue;
+ val->sharedram += atomic_read(&mem_map[i].count) - 1;
}
- val->totalhigh = 0;
- val->freehigh = 0;
- val->mem_unit = PAGE_SIZE;
+ val->totalram <<= PAGE_SHIFT;
+ val->sharedram <<= PAGE_SHIFT;
+ return;
}
void *
@@ -498,6 +499,9 @@ local_flush_tlb_all(void)
{
__clear_user(Hash, Hash_size);
_tlbia();
+#ifdef __SMP__
+ smp_send_tlb_invalidate(0);
+#endif
}
/*
@@ -511,6 +515,9 @@ local_flush_tlb_mm(struct mm_struct *mm)
mm->context = NO_CONTEXT;
if (mm == current->mm)
activate_mm(mm, mm);
+#ifdef __SMP__
+ smp_send_tlb_invalidate(0);
+#endif
}
void
@@ -520,6 +527,9 @@ local_flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr)
flush_hash_page(vma->vm_mm->context, vmaddr);
else
flush_hash_page(0, vmaddr);
+#ifdef __SMP__
+ smp_send_tlb_invalidate(0);
+#endif
}
@@ -545,6 +555,9 @@ local_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long e
{
flush_hash_page(mm->context, start);
}
+#ifdef __SMP__
+ smp_send_tlb_invalidate(0);
+#endif
}
/*
@@ -566,6 +579,9 @@ mmu_context_overflow(void)
}
read_unlock(&tasklist_lock);
flush_hash_segments(0x10, 0xffffff);
+#ifdef __SMP__
+ smp_send_tlb_invalidate(0);
+#endif
atomic_set(&next_mmu_context, 0);
/* make sure current always has a context */
current->mm->context = MUNGE_CONTEXT(atomic_inc_return(&next_mmu_context));
@@ -715,7 +731,7 @@ static void __init mapin_ram(void)
f |= _PAGE_RW | _PAGE_DIRTY | _PAGE_HWWRITE;
#ifndef CONFIG_8xx
else
- /* On the powerpc, denying user access
+ /* On the powerpc (not 8xx), no user access
forces R/W kernel access */
f |= _PAGE_USER;
#endif /* CONFIG_8xx */
@@ -874,7 +890,7 @@ void __init MMU_init(void)
setbat(3, 0x90000000, 0x90000000, 0x10000000, IO_PAGE);
break;
case _MACH_Pmac:
-#if 1
+#if 0
{
unsigned long base = 0xf3000000;
struct device_node *macio = find_devices("mac-io");
@@ -967,7 +983,6 @@ void __init do_init_bootmem(void)
/* 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,
@@ -1053,9 +1068,9 @@ void __init mem_init(void)
int codepages = 0;
int datapages = 0;
int initpages = 0;
-#if defined(CONFIG_CHRP) || defined(CONFIG_PMAC) || defined(CONFIG_ALL_PPC)
+#if defined(CONFIG_CHRP) || defined(CONFIG_ALL_PPC)
extern unsigned int rtas_data, rtas_size;
-#endif /* CONFIG_CHRP || CONFIG_PMAC || CONFIG_ALL_PPC */
+#endif /* defined(CONFIG_CHRP) || defined(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 */
@@ -1071,13 +1086,13 @@ void __init mem_init(void)
}
#endif /* CONFIG_BLK_DEV_INITRD */
-#if defined(CONFIG_CHRP) || defined(CONFIG_PMAC) || defined(CONFIG_ALL_PPC)
+#if defined(CONFIG_CHRP) || 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 /* CONFIG_CHRP || CONFIG_PMAC || CONFIG_ALL_PPC */
+#endif /* defined(CONFIG_CHRP) || defined(CONFIG_ALL_PPC) */
for (addr = PAGE_OFFSET; addr < (unsigned long)end_of_DRAM;
addr += PAGE_SIZE) {
@@ -1088,12 +1103,12 @@ void __init mem_init(void)
else if (addr >= (unsigned long)&__init_begin
&& addr < (unsigned long)&__init_end)
initpages++;
- else
+ else if (addr < (ulong) klimit)
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),
diff --git a/arch/sparc/ap1000/Makefile b/arch/sparc/ap1000/Makefile
index 83df0ef8e..f070f7675 100644
--- a/arch/sparc/ap1000/Makefile
+++ b/arch/sparc/ap1000/Makefile
@@ -6,9 +6,9 @@
#
.S.s:
- $(CPP) -D__ASSEMBLY__ -ansi $< -o $*.s
+ $(CPP) -D__ASSEMBLY__ $(AFLAGS) -ansi $< -o $*.s
.S.o:
- $(CC) -D__ASSEMBLY__ -ansi -c $< -o $*.o
+ $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c $< -o $*.o
all: ap1000lib.o
diff --git a/arch/sparc/config.in b/arch/sparc/config.in
index 27a756a2a..9ed06dc1f 100644
--- a/arch/sparc/config.in
+++ b/arch/sparc/config.in
@@ -1,4 +1,4 @@
-# $Id: config.in,v 1.73 1999/08/31 10:09:01 davem Exp $
+# $Id: config.in,v 1.79 1999/12/23 01:46:00 davem Exp $
# For a description of the syntax of this configuration file,
# see the Configure script.
#
@@ -57,21 +57,18 @@ else
fi
fi
-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- tristate 'Openprom tree appears in /proc/openprom (EXPERIMENTAL)' CONFIG_SUN_OPENPROMFS
-fi
+tristate 'Openprom tree appears in /proc/openprom' CONFIG_SUN_OPENPROMFS
bool 'Networking support' CONFIG_NET
bool 'System V IPC' CONFIG_SYSVIPC
bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT
bool 'Sysctl support' CONFIG_SYSCTL
if [ "$CONFIG_PROC_FS" = "y" ]; then
- choice 'Kernel core (/proc/kcore) format' \
- "ELF CONFIG_KCORE_ELF \
- A.OUT CONFIG_KCORE_AOUT" ELF
+ define_bool CONFIG_KCORE_ELF y
fi
tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT
tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
+bool 'SunOS binary emulation' CONFIG_SUNOS_EMUL
source drivers/parport/Config.in
dep_tristate ' Parallel printer support' CONFIG_PRINTER $CONFIG_PARPORT
endmenu
@@ -89,7 +86,7 @@ mainmenu_option next_comment
comment 'Floppy, IDE, and other block devices'
bool 'Normal floppy disk support' CONFIG_BLK_DEV_FD
-
+define_bool CONFIG_BLK_DEV_IDE n
bool 'Multiple devices driver support' CONFIG_BLK_DEV_MD
if [ "$CONFIG_BLK_DEV_MD" = "y" ]; then
tristate ' Linear (append) mode' CONFIG_MD_LINEAR
@@ -146,7 +143,7 @@ if [ "$CONFIG_SCSI" != "n" ]; then
mainmenu_option next_comment
comment 'SCSI low-level drivers'
- bool 'Sparc ESP Scsi Driver' CONFIG_SCSI_SUNESP $CONFIG_SCSI
+ tristate 'Sparc ESP Scsi Driver' CONFIG_SCSI_SUNESP $CONFIG_SCSI
tristate 'PTI Qlogic,ISP Driver' CONFIG_SCSI_QLOGICPTI $CONFIG_SCSI
endmenu
fi
@@ -173,9 +170,7 @@ if [ "$CONFIG_NET" = "y" ]; then
fi
tristate ' Sun LANCE support' CONFIG_SUNLANCE
tristate ' Sun Happy Meal 10/100baseT support' CONFIG_HAPPYMEAL
- if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- tristate ' Sun BigMAC 10/100baseT support (EXPERIMENTAL)' CONFIG_SUNBMAC
- fi
+ tristate ' Sun BigMAC 10/100baseT support (EXPERIMENTAL)' CONFIG_SUNBMAC
tristate ' Sun QuadEthernet support' CONFIG_SUNQE
tristate ' MyriCOM Gigabit Ethernet support' CONFIG_MYRI_SBUS
# bool ' FDDI driver support' CONFIG_FDDI
diff --git a/arch/sparc/defconfig b/arch/sparc/defconfig
index 1c14e11ff..b02a836b6 100644
--- a/arch/sparc/defconfig
+++ b/arch/sparc/defconfig
@@ -37,6 +37,7 @@ CONFIG_FB_BWTWO=y
CONFIG_FB_CGTHREE=y
CONFIG_FB_TCX=y
CONFIG_FB_CGFOURTEEN=y
+# CONFIG_FB_P9100 is not set
CONFIG_FB_LEO=y
# CONFIG_FB_VIRTUAL is not set
# CONFIG_FBCON_ADVANCED is not set
@@ -47,7 +48,7 @@ CONFIG_FONT_SUN8x16=y
# CONFIG_FBCON_FONTS is not set
CONFIG_SBUS=y
CONFIG_SBUSCHAR=y
-CONFIG_MOUSE=y
+CONFIG_BUSMOUSE=y
CONFIG_SUN_MOUSE=y
CONFIG_SERIAL=y
CONFIG_SUN_SERIAL=y
@@ -65,6 +66,7 @@ CONFIG_SUN_MOSTEK_RTC=y
# CONFIG_SUN_BPP is not set
# CONFIG_SUN_VIDEOPIX is not set
CONFIG_SUN_AURORA=m
+# CONFIG_TADPOLE_TS102_UCTRL is not set
#
# Linux/SPARC audio subsystem (EXPERIMENTAL)
@@ -84,6 +86,9 @@ CONFIG_KCORE_ELF=y
CONFIG_BINFMT_AOUT=y
CONFIG_BINFMT_ELF=y
CONFIG_BINFMT_MISC=m
+CONFIG_SUNOS_EMUL=y
+# CONFIG_PARPORT is not set
+# CONFIG_PRINTER is not set
#
# Floppy, IDE, and other block devices
@@ -103,8 +108,9 @@ CONFIG_BLK_DEV_NBD=m
# Networking options
#
CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
# CONFIG_NETLINK is not set
-# CONFIG_FIREWALL is not set
+# CONFIG_NETFILTER is not set
# CONFIG_FILTER is not set
CONFIG_UNIX=y
CONFIG_INET=y
@@ -120,10 +126,11 @@ CONFIG_INET=y
#
# (it is safe to leave these untouched)
#
-CONFIG_INET_RARP=m
CONFIG_SKB_LARGE=y
CONFIG_IPV6=m
# CONFIG_IPV6_EUI64 is not set
+# CONFIG_KHTTPD is not set
+# CONFIG_ATM is not set
#
#
@@ -144,7 +151,6 @@ CONFIG_DECNET_RAW=y
# CONFIG_WAN_ROUTER is not set
# CONFIG_NET_FASTROUTE is not set
# CONFIG_NET_HW_FLOWCONTROL is not set
-# CONFIG_CPU_IS_SLOW is not set
#
# QoS and/or fair queueing
@@ -240,6 +246,7 @@ CONFIG_VFAT_FS=m
CONFIG_EFS_FS=m
CONFIG_ISO9660_FS=m
# CONFIG_JOLIET is not set
+# CONFIG_UDF_FS is not set
CONFIG_MINIX_FS=m
# CONFIG_NTFS_FS is not set
CONFIG_HPFS_FS=m
@@ -275,13 +282,13 @@ CONFIG_NCP_FS=m
#
# Partition Types
#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
CONFIG_BSD_DISKLABEL=y
-# CONFIG_MAC_PARTITION is not set
-CONFIG_SMD_DISKLABEL=y
CONFIG_SOLARIS_X86_PARTITION=y
-# CONFIG_SGI_DISKLABEL is not set
# CONFIG_UNIXWARE_DISKLABEL is not set
-CONFIG_AMIGA_PARTITION=y
+# CONFIG_SGI_PARTITION is not set
+CONFIG_SUN_PARTITION=y
CONFIG_NLS=y
#
@@ -312,6 +319,7 @@ CONFIG_NLS=y
# CONFIG_NLS_ISO8859_7 is not set
# CONFIG_NLS_ISO8859_8 is not set
# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_14 is not set
# CONFIG_NLS_ISO8859_15 is not set
# CONFIG_NLS_KOI8_R is not set
diff --git a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile
index 2e2fdef2c..0d93f3a2b 100644
--- a/arch/sparc/kernel/Makefile
+++ b/arch/sparc/kernel/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.50 1999/08/31 13:26:13 anton Exp $
+# $Id: Makefile,v 1.52 1999/12/21 04:02:17 davem Exp $
# Makefile for the linux kernel.
#
# Note! Dependencies are done automagically by 'make dep', which also
@@ -19,9 +19,9 @@ O_TARGET := kernel.o
IRQ_OBJS := irq.o sun4m_irq.o sun4c_irq.o sun4d_irq.o
O_OBJS := entry.o wof.o wuf.o etrap.o rtrap.o traps.o ${IRQ_OBJS} \
process.o signal.o ioport.o setup.o idprom.o \
- sys_sparc.o sunos_asm.o sparc-stub.o systbls.o sys_sunos.o \
- sunos_ioctl.o time.o windows.o cpu.o devices.o \
- sclow.o solaris.o tadpole.o tick14.o ptrace.o sys_solaris.o \
+ sys_sparc.o sunos_asm.o sparc-stub.o systbls.o \
+ time.o windows.o cpu.o devices.o sclow.o solaris.o \
+ tadpole.o tick14.o ptrace.o sys_solaris.o \
unaligned.o muldiv.o pcic.o semaphore.o
OX_OBJS := sparc_ksyms.o
@@ -30,6 +30,10 @@ ifdef CONFIG_SUN4
O_OBJS += sun4setup.o
endif
+ifdef CONFIG_SUNOS_EMUL
+O_OBJS += sys_sunos.o sunos_ioctl.o
+endif
+
ifdef CONFIG_SMP
O_OBJS += trampoline.o smp.o sun4m_smp.o sun4d_smp.o
endif
@@ -55,11 +59,13 @@ check_asm: dummy
@echo "#ifndef CONFIG_SMP" >> asm_offsets.h
@echo "" >> asm_offsets.h
@echo "#include <linux/config.h>" > tmp.c
+ @echo "#undef __SMP__" >> tmp.c
@echo "#undef CONFIG_SMP" >> tmp.c
@echo "#include <linux/sched.h>" >> tmp.c
- $(CC) -E tmp.c -o tmp.i
+ $(CC) $(CPPFLAGS) -E tmp.c -o tmp.i
@echo "/* Automatically generated. Do not edit. */" > check_asm.c
@echo "#include <linux/config.h>" >> check_asm.c
+ @echo "#undef __SMP__" >> check_asm.c
@echo "#undef CONFIG_SMP" >> check_asm.c
@echo "#include <linux/sched.h>" >> check_asm.c
@echo 'struct task_struct _task;' >> check_asm.c
@@ -71,7 +77,7 @@ check_asm: dummy
$(SH) ./check_asm.sh thread tmp.i check_asm.c
@echo 'return 0; }' >> check_asm.c
@rm -f tmp.[ci]
- $(CC) -o check_asm check_asm.c
+ $(CC) $(CFLAGS) -o check_asm check_asm.c
./check_asm >> asm_offsets.h
@rm -f check_asm check_asm.c
@echo "" >> asm_offsets.h
@@ -81,7 +87,7 @@ check_asm: dummy
@echo "#undef CONFIG_SMP" >> tmp.c
@echo "#define CONFIG_SMP 1" >> tmp.c
@echo "#include <linux/sched.h>" >> tmp.c
- $(CC) -D__SMP__ -E tmp.c -o tmp.i
+ $(CC) $(CPPFLAGS) -D__SMP__ -E tmp.c -o tmp.i
@echo "/* Automatically generated. Do not edit. */" > check_asm.c
@echo "#include <linux/config.h>" >> check_asm.c
@echo "#undef CONFIG_SMP" >> check_asm.c
@@ -96,7 +102,7 @@ check_asm: dummy
$(SH) ./check_asm.sh thread tmp.i check_asm.c
@echo 'return 0; }' >> check_asm.c
@rm -f tmp.[ci]
- $(CC) -D__SMP__ -o check_asm check_asm.c
+ $(CC) $(CFLAGS) -D__SMP__ -o check_asm check_asm.c
./check_asm >> asm_offsets.h
@rm -f check_asm check_asm.c
@echo "" >> asm_offsets.h
diff --git a/arch/sparc/kernel/auxio.c b/arch/sparc/kernel/auxio.c
index 099c14eca..fe34b0900 100644
--- a/arch/sparc/kernel/auxio.c
+++ b/arch/sparc/kernel/auxio.c
@@ -9,6 +9,7 @@
#include <asm/oplib.h>
#include <asm/io.h>
#include <asm/auxio.h>
+#include <asm/string.h> /* memset(), Linux has no bzero() */
/* Probe and map in the Auxiliary I/O register */
unsigned char *auxio_register;
@@ -17,6 +18,7 @@ void __init auxio_probe(void)
{
int node, auxio_nd;
struct linux_prom_registers auxregs[1];
+ struct resource r;
switch (sparc_cpu_model) {
case sun4d:
@@ -51,10 +53,11 @@ void __init auxio_probe(void)
prom_getproperty(auxio_nd, "reg", (char *) auxregs, sizeof(auxregs));
prom_apply_obio_ranges(auxregs, 0x1);
/* Map the register both read and write */
- auxio_register = (unsigned char *) sparc_alloc_io(auxregs[0].phys_addr, 0,
- auxregs[0].reg_size,
- "auxiliaryIO",
- auxregs[0].which_io, 0x0);
+ r.flags = auxregs[0].which_io & 0xF;
+ r.start = auxregs[0].phys_addr;
+ r.end = auxregs[0].phys_addr + auxregs[0].reg_size - 1;
+ auxio_register = (unsigned char *) sbus_ioremap(&r, 0,
+ auxregs[0].reg_size, "auxio");
/* Fix the address on sun4m and sun4c. */
if((((unsigned long) auxregs[0].phys_addr) & 3) == 3 ||
sparc_cpu_model == sun4c)
@@ -72,6 +75,7 @@ void __init auxio_power_probe(void)
{
struct linux_prom_registers regs;
int node;
+ struct resource r;
/* Attempt to find the sun4m power control node. */
node = prom_getchild(prom_root_node);
@@ -84,9 +88,12 @@ void __init auxio_power_probe(void)
/* Map the power control register. */
prom_getproperty(node, "reg", (char *)&regs, sizeof(regs));
prom_apply_obio_ranges(&regs, 1);
- auxio_power_register = (volatile unsigned char *)
- sparc_alloc_io(regs.phys_addr, 0, regs.reg_size,
- "power off control", regs.which_io, 0);
+ memset(&r, 0, sizeof(r));
+ r.flags = regs.which_io & 0xF;
+ r.start = regs.phys_addr;
+ r.end = regs.phys_addr + regs.reg_size - 1;
+ auxio_power_register = (unsigned char *) sbus_ioremap(&r, 0,
+ regs.reg_size, "auxpower");
/* Display a quick message on the console. */
if (auxio_power_register)
diff --git a/arch/sparc/kernel/ebus.c b/arch/sparc/kernel/ebus.c
index d0a9c622a..c1ef01be3 100644
--- a/arch/sparc/kernel/ebus.c
+++ b/arch/sparc/kernel/ebus.c
@@ -1,4 +1,4 @@
-/* $Id: ebus.c,v 1.4 1999/08/31 06:54:19 davem Exp $
+/* $Id: ebus.c,v 1.8 1999/11/27 22:40:38 zaitcev Exp $
* ebus.c: PCI to EBus bridge device.
*
* Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
@@ -23,9 +23,8 @@
#include <asm/bpp.h>
#undef PROM_DEBUG
-#undef DEBUG_FILL_EBUS_DEV
-#ifdef PROM_DEBUG
+#if 0 /* separate from PROM_DEBUG for the sake of PROLL */
#define dprintk prom_printf
#else
#define dprintk printk
@@ -79,7 +78,7 @@ void __init fill_ebus_child(int node, struct linux_prom_registers *preg,
dev->prom_name, len, dev->parent->num_addrs);
panic(__FUNCTION__);
}
- dev->base_address[i] = dev->parent->base_address[regs[i]];
+ dev->resource[i].start = dev->parent->resource[regs[i]].start; /* XXX resource */
}
/*
@@ -110,22 +109,8 @@ void __init fill_ebus_child(int node, struct linux_prom_registers *preg,
dev->irqs[0] = 0;
} else {
dev->irqs[0] = pcic_pin_to_irq(irqs[0], dev->prom_name);
-/* P3 remove */ printk("EBUS: dev %s irq %d from PROM\n", dev->prom_name, dev->irqs[0]);
}
}
-
-#ifdef DEBUG_FILL_EBUS_DEV
- dprintk("child '%s': address%s\n", dev->prom_name,
- dev->num_addrs > 1 ? "es" : "");
- for (i = 0; i < dev->num_addrs; i++)
- dprintk(" %016lx\n", dev->base_address[i]);
- if (dev->num_irqs) {
- dprintk(" IRQ%s", dev->num_irqs > 1 ? "s" : "");
- for (i = 0; i < dev->num_irqs; i++)
- dprintk(" %08x", dev->irqs[i]);
- dprintk("\n");
- }
-#endif
}
void __init fill_ebus_device(int node, struct linux_ebus_device *dev)
@@ -135,6 +120,7 @@ void __init fill_ebus_device(int node, struct linux_ebus_device *dev)
int irqs[PROMINTR_MAX];
char lbuf[128];
int i, n, len;
+ unsigned long baseaddr;
dev->prom_node = node;
prom_getstring(node, "name", lbuf, sizeof(lbuf));
@@ -175,28 +161,20 @@ void __init fill_ebus_device(int node, struct linux_ebus_device *dev)
;
}
- dev->base_address[i] = dev->bus->self->base_address[n];
- dev->base_address[i] += regs[i].phys_addr;
-
- if (dev->base_address[i]) {
- dev->base_address[i] =
- (unsigned long)sparc_alloc_io (dev->base_address[i], 0,
- regs[i].reg_size,
- dev->prom_name, 0, 0);
-#if 0
/*
- * This release_region() screwes those who do sparc_alloc_io().
- * Change drivers which do check_region(). See drivers/block/floppy.c.
+ * XXX Now as we have regions, why don't we make an on-demand allocation...
*/
- /* Some drivers call 'check_region', so we release it */
- release_region(dev->base_address[i] & PAGE_MASK, PAGE_SIZE);
-#endif
-
- if (dev->base_address[i] == 0 ) {
- panic("ebus: unable sparc_alloc_io for dev %s",
- dev->prom_name);
- }
+ dev->resource[i].start = 0;
+ if ((baseaddr = dev->bus->self->resource[n].start +
+ regs[i].phys_addr) != 0) {
+ /* dev->resource[i].name = dev->prom_name; */
+ if ((baseaddr = (unsigned long) ioremap(baseaddr,
+ regs[i].reg_size)) == 0) {
+ panic("ebus: unable to remap dev %s",
+ dev->prom_name);
+ }
}
+ dev->resource[i].start = baseaddr; /* XXX Unaligned */
}
len = prom_getproperty(node, "interrupts", (char *)&irqs, sizeof(irqs));
@@ -216,22 +194,9 @@ void __init fill_ebus_device(int node, struct linux_ebus_device *dev)
dev->irqs[0] = 0;
} else {
dev->irqs[0] = pcic_pin_to_irq(irqs[0], dev->prom_name);
-/* P3 remove */ printk("EBUS: child %s irq %d from PROM\n", dev->prom_name, dev->irqs[0]);
}
}
-#ifdef DEBUG_FILL_EBUS_DEV
- dprintk("'%s': address%s\n", dev->prom_name,
- dev->num_addrs > 1 ? "es" : "");
- for (i = 0; i < dev->num_addrs; i++)
- dprintk(" %016lx\n", dev->base_address[i]);
- if (dev->num_irqs) {
- dprintk(" IRQ%s", dev->num_irqs > 1 ? "s" : "");
- for (i = 0; i < dev->num_irqs; i++)
- dprintk(" %08x", dev->irqs[i]);
- dprintk("\n");
- }
-#endif
if ((node = prom_getchild(node))) {
dev->children = (struct linux_ebus_child *)
ebus_alloc(sizeof(struct linux_ebus_child));
@@ -312,7 +277,7 @@ void __init ebus_init(void)
}
nreg = len / sizeof(struct linux_prom_pci_registers);
- base = &ebus->self->base_address[0];
+ base = &ebus->self->resource[0].start;
for (reg = 0; reg < nreg; reg++) {
if (!(regs[reg].which_io & 0x03000000))
continue;
diff --git a/arch/sparc/kernel/entry.S b/arch/sparc/kernel/entry.S
index 0f1d1122e..226e53897 100644
--- a/arch/sparc/kernel/entry.S
+++ b/arch/sparc/kernel/entry.S
@@ -1,4 +1,4 @@
-/* $Id: entry.S,v 1.161 1999/08/14 03:51:05 anton Exp $
+/* $Id: entry.S,v 1.163 1999/11/19 04:11:24 davem Exp $
* arch/sparc/kernel/entry.S: Sparc trap low-level entry points.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -826,13 +826,13 @@ linux_trap_nmi_sun4c:
.globl C_LABEL(invalid_segment_patch1_ff)
.globl C_LABEL(invalid_segment_patch2_ff)
C_LABEL(invalid_segment_patch1_ff): cmp %l4, 0xff
-C_LABEL(invalid_segment_patch2_ff): mov 0xff, %l4
+C_LABEL(invalid_segment_patch2_ff): mov 0xff, %l3
.align 4
.globl C_LABEL(invalid_segment_patch1_1ff)
.globl C_LABEL(invalid_segment_patch2_1ff)
C_LABEL(invalid_segment_patch1_1ff): cmp %l4, 0x1ff
-C_LABEL(invalid_segment_patch2_1ff): mov 0x1ff, %l4
+C_LABEL(invalid_segment_patch2_1ff): mov 0x1ff, %l3
.align 4
.globl C_LABEL(num_context_patch1_16), C_LABEL(num_context_patch2_16)
@@ -853,7 +853,7 @@ C_LABEL(vac_linesize_patch_32): subcc %l7, 32, %l7
#ifdef CONFIG_SUN4
C_LABEL(vac_hwflush_patch1_on): nop
#else
-C_LABEL(vac_hwflush_patch1_on): subcc %l7, (PAGE_SIZE - 4), %l7
+C_LABEL(vac_hwflush_patch1_on): addcc %l7, -PAGE_SIZE, %l7
#endif
C_LABEL(vac_hwflush_patch2_on): sta %g0, [%l3 + %l7] ASI_HWFLUSHSEG
@@ -969,12 +969,12 @@ C_LABEL(invalid_segment_patch1):
bne 1f
sethi %hi(C_LABEL(sun4c_kfree_ring)), %l4
or %l4, %lo(C_LABEL(sun4c_kfree_ring)), %l4
- ld [%l4 + 0x10], %l3
+ ld [%l4 + 0x18], %l3
deccc %l3 ! do we have a free entry?
bcs,a 2f ! no, unmap one.
sethi %hi(C_LABEL(sun4c_kernel_ring)), %l4
- st %l3, [%l4 + 0x10] ! sun4c_kfree_ring.num_entries--
+ st %l3, [%l4 + 0x18] ! sun4c_kfree_ring.num_entries--
ld [%l4 + 0x00], %l6 ! entry = sun4c_kfree_ring.ringhd.next
st %l5, [%l6 + 0x08] ! entry->vaddr = address
@@ -997,10 +997,10 @@ C_LABEL(invalid_segment_patch1):
st %l6, [%l4 + 0x00] ! head->next = entry
- ld [%l4 + 0x10], %l3
+ ld [%l4 + 0x18], %l3
inc %l3 ! sun4c_kernel_ring.num_entries++
b 4f
- st %l3, [%l4 + 0x10]
+ ld [%l6 + 0x08], %l5
2:
or %l4, %lo(C_LABEL(sun4c_kernel_ring)), %l4
@@ -1020,7 +1020,7 @@ C_LABEL(invalid_segment_patch1):
C_LABEL(vac_hwflush_patch1):
C_LABEL(vac_linesize_patch):
subcc %l7, 16, %l7
- bg 9b
+ bne 9b
C_LABEL(vac_hwflush_patch2):
sta %g0, [%l3 + %l7] ASI_FLUSHSEG
@@ -1041,47 +1041,36 @@ C_LABEL(vac_hwflush_patch2):
mov %l3, %l5 ! address = tmp
+4:
C_LABEL(num_context_patch1):
mov 0x08, %l7
-C_LABEL(invalid_segment_patch2):
- mov 0x7f, %l4
+ ld [%l6 + 0x08], %l4
+ ldub [%l6 + 0x0c], %l3
+ or %l4, %l3, %l4 ! encode new vaddr/pseg into l4
sethi %hi(AC_CONTEXT), %l3
lduba [%l3] ASI_CONTROL, %l6
-3:
- deccc %l7
- stba %l7, [%l3] ASI_CONTROL
- bne 3b
- stXa %l4, [%l5] ASI_SEGMAP
-
- stba %l6, [%l3] ASI_CONTROL
-
- ! reload the entry
-
- sethi %hi(C_LABEL(sun4c_kernel_ring)), %l4
- ld [%l4 + %lo(C_LABEL(sun4c_kernel_ring))], %l6
-
- ld [%l6 + 0x08], %l5 ! restore address from entry->vaddr
-
-4:
-C_LABEL(num_context_patch2):
- mov 0x08, %l7
-
- ldub [%l6 + 0x0c], %l4 ! entry->pseg
-
+ /* Invalidate old mapping, instantiate new mapping,
+ * for each context. Registers l6/l7 are live across
+ * this loop.
+ */
+3: deccc %l7
sethi %hi(AC_CONTEXT), %l3
- lduba [%l3] ASI_CONTROL, %l6
-
-3:
- deccc %l7
stba %l7, [%l3] ASI_CONTROL
+C_LABEL(invalid_segment_patch2):
+ mov 0x7f, %l3
+ stXa %l3, [%l5] ASI_SEGMAP
+ andn %l4, 0x1ff, %l3
bne 3b
- stXa %l4, [%l5] ASI_SEGMAP
+ stXa %l4, [%l3] ASI_SEGMAP
+ sethi %hi(AC_CONTEXT), %l3
stba %l6, [%l3] ASI_CONTROL
+ andn %l4, 0x1ff, %l5
+
1:
sethi %hi(SUN4C_VMALLOC_START), %l4
cmp %l5, %l4
@@ -1149,6 +1138,7 @@ C_LABEL(num_context_patch2):
sun4c_fault_fromuser:
SAVE_ALL
+ nop
mov %l7, %o1 ! Decode the info from %l7
mov %l7, %o2
@@ -1199,6 +1189,7 @@ C_LABEL(srmmu_fault):
RESTORE_ALL
+#ifdef CONFIG_SUNOS_EMUL
/* SunOS uses syscall zero as the 'indirect syscall' it looks
* like indir_syscall(scall_num, arg0, arg1, arg2...); etc.
* This is complete brain damage.
@@ -1226,6 +1217,7 @@ C_LABEL(sunos_indir):
mov %o5, %o4
call %l6
mov %l4, %o7
+#endif
.align 4
.globl C_LABEL(sys_nis_syscall)
@@ -1639,6 +1631,20 @@ solaris_syscall:
b ret_trap_entry
st %l1, [%sp + REGWIN_SZ + PT_NPC]
+#ifndef CONFIG_SUNOS_EMUL
+ .align 4
+ .globl sunos_syscall
+sunos_syscall:
+ SAVE_ALL_HEAD
+ rd %wim, %l3
+ wr %l0, PSR_ET, %psr
+ nop
+ nop
+ mov %i0, %l5
+ call C_LABEL(do_sunos_syscall)
+ add %sp, REGWIN_SZ, %o0
+#endif
+
/* {net, open}bsd system calls enter here... */
.align 4
.globl bsd_syscall
diff --git a/arch/sparc/kernel/head.S b/arch/sparc/kernel/head.S
index fbb2e680d..eb3d007f0 100644
--- a/arch/sparc/kernel/head.S
+++ b/arch/sparc/kernel/head.S
@@ -1,4 +1,4 @@
-/* $Id: head.S,v 1.97 1999/08/14 03:51:10 anton Exp $
+/* $Id: head.S,v 1.101 1999/12/02 08:34:56 jj Exp $
* head.S: The initial boot code for the Sparc port of Linux.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -78,6 +78,11 @@ sun4e_notsup:
.asciz "Sparc-Linux sun4e support does not exist\n\n"
.align 4
+#ifndef CONFIG_SUNOS_EMUL
+#undef SUNOS_SYSCALL_TRAP
+#define SUNOS_SYSCALL_TRAP SUNOS_NO_SYSCALL_TRAP
+#endif
+
/* The Sparc trap table, bootloader gives us control at _start. */
.text
.globl start, _stext, _start, __stext
@@ -171,7 +176,8 @@ t_bad96:BAD_TRAP(0x96) BAD_TRAP(0x97) BAD_TRAP(0x98) BAD_TRAP(0x99) BAD_TRAP(0x9
t_bad9b:BAD_TRAP(0x9b) BAD_TRAP(0x9c) BAD_TRAP(0x9d) BAD_TRAP(0x9e) BAD_TRAP(0x9f)
t_getcc:GETCC_TRAP /* Get Condition Codes */
t_setcc:SETCC_TRAP /* Set Condition Codes */
-t_bada2:BAD_TRAP(0xa2) BAD_TRAP(0xa3) BAD_TRAP(0xa4) BAD_TRAP(0xa5) BAD_TRAP(0xa6)
+t_getpsr:GETPSR_TRAP /* Get PSR Register */
+t_bada3:BAD_TRAP(0xa3) BAD_TRAP(0xa4) BAD_TRAP(0xa5) BAD_TRAP(0xa6)
t_slowi:INDIRECT_SOLARIS_SYSCALL(156)
t_bada8:BAD_TRAP(0xa8) BAD_TRAP(0xa9) BAD_TRAP(0xaa) BAD_TRAP(0xab)
t_badac:BAD_TRAP(0xac) BAD_TRAP(0xad) BAD_TRAP(0xae) BAD_TRAP(0xaf) BAD_TRAP(0xb0)
@@ -247,8 +253,8 @@ C_LABEL(trapbase_cpu1):
LINUX_SYSCALL_TRAP BAD_TRAP(0x91) BAD_TRAP(0x92) BAD_TRAP(0x93) BAD_TRAP(0x94)
BAD_TRAP(0x95) BAD_TRAP(0x96) BAD_TRAP(0x97) BAD_TRAP(0x98) BAD_TRAP(0x99)
BAD_TRAP(0x9a) BAD_TRAP(0x9b) BAD_TRAP(0x9c) BAD_TRAP(0x9d) BAD_TRAP(0x9e)
- BAD_TRAP(0x9f) GETCC_TRAP SETCC_TRAP
- BAD_TRAP(0xa2) BAD_TRAP(0xa3) BAD_TRAP(0xa4) BAD_TRAP(0xa5) BAD_TRAP(0xa6)
+ BAD_TRAP(0x9f) GETCC_TRAP SETCC_TRAP GETPSR_TRAP
+ BAD_TRAP(0xa3) BAD_TRAP(0xa4) BAD_TRAP(0xa5) BAD_TRAP(0xa6)
INDIRECT_SOLARIS_SYSCALL(156) BAD_TRAP(0xa8) BAD_TRAP(0xa9) BAD_TRAP(0xaa) BAD_TRAP(0xab)
BAD_TRAP(0xac) BAD_TRAP(0xad) BAD_TRAP(0xae) BAD_TRAP(0xaf) BAD_TRAP(0xb0)
BAD_TRAP(0xb1) BAD_TRAP(0xb2) BAD_TRAP(0xb3) BAD_TRAP(0xb4) BAD_TRAP(0xb5)
@@ -315,8 +321,8 @@ C_LABEL(trapbase_cpu2):
LINUX_SYSCALL_TRAP BAD_TRAP(0x91) BAD_TRAP(0x92) BAD_TRAP(0x93) BAD_TRAP(0x94)
BAD_TRAP(0x95) BAD_TRAP(0x96) BAD_TRAP(0x97) BAD_TRAP(0x98) BAD_TRAP(0x99)
BAD_TRAP(0x9a) BAD_TRAP(0x9b) BAD_TRAP(0x9c) BAD_TRAP(0x9d) BAD_TRAP(0x9e)
- BAD_TRAP(0x9f) GETCC_TRAP SETCC_TRAP
- BAD_TRAP(0xa2) BAD_TRAP(0xa3) BAD_TRAP(0xa4) BAD_TRAP(0xa5) BAD_TRAP(0xa6)
+ BAD_TRAP(0x9f) GETCC_TRAP SETCC_TRAP GETPSR_TRAP
+ BAD_TRAP(0xa3) BAD_TRAP(0xa4) BAD_TRAP(0xa5) BAD_TRAP(0xa6)
INDIRECT_SOLARIS_SYSCALL(156) BAD_TRAP(0xa8) BAD_TRAP(0xa9) BAD_TRAP(0xaa) BAD_TRAP(0xab)
BAD_TRAP(0xac) BAD_TRAP(0xad) BAD_TRAP(0xae) BAD_TRAP(0xaf) BAD_TRAP(0xb0)
BAD_TRAP(0xb1) BAD_TRAP(0xb2) BAD_TRAP(0xb3) BAD_TRAP(0xb4) BAD_TRAP(0xb5)
@@ -383,8 +389,8 @@ C_LABEL(trapbase_cpu3):
LINUX_SYSCALL_TRAP BAD_TRAP(0x91) BAD_TRAP(0x92) BAD_TRAP(0x93) BAD_TRAP(0x94)
BAD_TRAP(0x95) BAD_TRAP(0x96) BAD_TRAP(0x97) BAD_TRAP(0x98) BAD_TRAP(0x99)
BAD_TRAP(0x9a) BAD_TRAP(0x9b) BAD_TRAP(0x9c) BAD_TRAP(0x9d) BAD_TRAP(0x9e)
- BAD_TRAP(0x9f) GETCC_TRAP SETCC_TRAP
- BAD_TRAP(0xa2) BAD_TRAP(0xa3) BAD_TRAP(0xa4) BAD_TRAP(0xa5) BAD_TRAP(0xa6)
+ BAD_TRAP(0x9f) GETCC_TRAP SETCC_TRAP GETPSR_TRAP
+ BAD_TRAP(0xa3) BAD_TRAP(0xa4) BAD_TRAP(0xa5) BAD_TRAP(0xa6)
INDIRECT_SOLARIS_SYSCALL(156) BAD_TRAP(0xa8) BAD_TRAP(0xa9) BAD_TRAP(0xaa) BAD_TRAP(0xab)
BAD_TRAP(0xac) BAD_TRAP(0xad) BAD_TRAP(0xae) BAD_TRAP(0xaf) BAD_TRAP(0xb0)
BAD_TRAP(0xb1) BAD_TRAP(0xb2) BAD_TRAP(0xb3) BAD_TRAP(0xb4) BAD_TRAP(0xb5)
@@ -436,7 +442,7 @@ C_LABEL(empty_zero_page): .skip PAGE_SIZE
*/
.ascii "HdrS"
.word LINUX_VERSION_CODE
- .half 0x0201 /* HdrS version */
+ .half 0x0203 /* HdrS version */
C_LABEL(root_flags):
.half 1
C_LABEL(root_dev):
@@ -448,6 +454,8 @@ C_LABEL(sparc_ramdisk_image):
C_LABEL(sparc_ramdisk_size):
.word 0
.word C_LABEL(reboot_command)
+ .word 0, 0, 0
+ .word _end
/* Cool, here we go. Pick up the romvec pointer in %o0 and stash it in
* %g7 and at prom_vector_p. And also quickly check whether we are on
diff --git a/arch/sparc/kernel/ioport.c b/arch/sparc/kernel/ioport.c
index 74706e79a..e2b6b1ae4 100644
--- a/arch/sparc/kernel/ioport.c
+++ b/arch/sparc/kernel/ioport.c
@@ -1,139 +1,539 @@
-/* $Id: ioport.c,v 1.24 1997/04/10 03:02:32 davem Exp $
+/* $Id: ioport.c,v 1.28 1999/12/27 06:08:28 anton Exp $
* ioport.c: Simple io mapping allocator.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
* Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx)
*
- * The routines in this file should be changed for a memory allocator
- * that would be setup just like NetBSD does : you create regions that
- * are administered by a general purpose allocator, and then you call
- * that allocator with your handle and the block size instead of this
- * weak stuff.
+ * 1996: sparc_free_io, 1999: ioremap()/iounmap() by Pete Zaitcev.
*/
+#include <linux/config.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/ioport.h>
#include <linux/mm.h>
+#include <linux/malloc.h>
#include <asm/io.h>
#include <asm/vaddrs.h>
#include <asm/oplib.h>
#include <asm/page.h>
+#include <asm/pgalloc.h>
#include <asm/pgtable.h>
-/* This points to the next to use virtual memory for io mappings */
-static unsigned long dvma_next_free = DVMA_VADDR;
-unsigned long sparc_iobase_vaddr = IOBASE_VADDR;
+struct resource *sparc_find_resource_bystart(struct resource *, unsigned long);
+struct resource *sparc_find_resource_by_hit(struct resource *, unsigned long);
+
+static void *_sparc_ioremap(struct resource *res, u32 bus, u32 pa, int sz);
+static void *_sparc_alloc_io(unsigned int busno, unsigned long phys,
+ unsigned long size, char *name);
+static void _sparc_free_io(struct resource *res);
+
+/* This points to the next to use virtual memory for DVMA mappings */
+static struct resource sparc_dvma = {
+ "sparc_dvma", DVMA_VADDR, DVMA_VADDR + DVMA_LEN - 1
+};
+/* This points to the start of I/O mappings, cluable from outside. */
+ struct resource sparc_iomap = {
+ "sparc_iomap", IOBASE_VADDR, IOBASE_END-1
+};
/*
- * sparc_alloc_io:
- * Map and allocates an obio device.
- * Implements a simple linear allocator, you can force the function
- * to use your own mapping, but in practice this should not be used.
- *
- * Input:
- * address: the obio address to map
- * virtual: if non zero, specifies a fixed virtual address where
- * the mapping should take place.
- * len: the length of the mapping
- * bus_type: The bus on which this io area sits.
+ * Our mini-allocator...
+ * Boy this is gross! We need it because we must map I/O for
+ * timers and interrupt controller before the kmalloc is available.
+ */
+
+#define XNMLN 15
+#define XNRES 10 /* SS-10 uses 8 */
+
+struct xresource {
+ struct resource xres; /* Must be first */
+ int xflag; /* 1 == used */
+ char xname[XNMLN+1];
+};
+
+static struct xresource xresv[XNRES];
+
+static struct xresource *xres_alloc(void) {
+ struct xresource *xrp;
+ int n;
+
+ xrp = xresv;
+ for (n = 0; n < XNRES; n++) {
+ if (xrp->xflag == 0) {
+ xrp->xflag = 1;
+ return xrp;
+ }
+ xrp++;
+ }
+ return NULL;
+}
+
+static void xres_free(struct xresource *xrp) {
+ xrp->xflag = 0;
+}
+
+/*
+ */
+extern void sun4c_mapioaddr(unsigned long, unsigned long, int bus_type, int rdonly);
+extern void srmmu_mapioaddr(unsigned long, unsigned long, int bus_type, int rdonly);
+
+static void mapioaddr(unsigned long physaddr, unsigned long virt_addr,
+ int bus, int rdonly)
+{
+ switch(sparc_cpu_model) {
+ case sun4c:
+ case sun4:
+ sun4c_mapioaddr(physaddr, virt_addr, bus, rdonly);
+ break;
+ case sun4m:
+ case sun4d:
+ case sun4e:
+ srmmu_mapioaddr(physaddr, virt_addr, bus, rdonly);
+ break;
+ default:
+ printk("mapioaddr: Trying to map IO space for unsupported machine.\n");
+ printk("mapioaddr: sparc_cpu_model = %d\n", sparc_cpu_model);
+ printk("mapioaddr: Halting...\n");
+ halt();
+ };
+ return;
+}
+
+extern void srmmu_unmapioaddr(unsigned long virt);
+extern void sun4c_unmapioaddr(unsigned long virt);
+
+static void unmapioaddr(unsigned long virt_addr)
+{
+ switch(sparc_cpu_model) {
+ case sun4c:
+ case sun4:
+ sun4c_unmapioaddr(virt_addr);
+ break;
+ case sun4m:
+ case sun4d:
+ case sun4e:
+ srmmu_unmapioaddr(virt_addr);
+ break;
+ default:
+ printk("unmapioaddr: sparc_cpu_model = %d, halt...\n", sparc_cpu_model);
+ halt();
+ };
+ return;
+}
+
+/*
+ * These are typically used in PCI drivers
+ * which are trying to be cross-platform.
*
- * Returns:
- * The virtual address where the mapping actually took place.
+ * Bus type is always zero on IIep.
*/
+void *ioremap(unsigned long offset, unsigned long size)
+{
+ char name[14];
+
+ sprintf(name, "phys_%08x", (u32)offset);
+ return _sparc_alloc_io(0, offset, size, name);
+}
-void *sparc_alloc_io (u32 address, void *virtual, int len, char *name,
- u32 bus_type, int rdonly)
+/*
+ * Comlimentary to ioremap().
+ */
+void iounmap(void *virtual)
{
- unsigned long vaddr, base_address;
- unsigned long addr = (unsigned long) address;
- unsigned long offset = (addr & (~PAGE_MASK));
+ unsigned long vaddr = (unsigned long) virtual & PAGE_MASK;
+ struct resource *res;
- if (virtual) {
- vaddr = (unsigned long) virtual;
+ if ((res = sparc_find_resource_bystart(&sparc_iomap, vaddr)) == NULL) {
+ printk("free_io/iounmap: cannot free %lx\n", vaddr);
+ return;
+ }
+ _sparc_free_io(res);
- len += offset;
- if(((unsigned long) virtual + len) > (IOBASE_VADDR + IOBASE_LEN)) {
- prom_printf("alloc_io: Mapping outside IOBASE area\n");
- prom_halt();
- }
- if(check_region ((vaddr | offset), len)) {
- prom_printf("alloc_io: 0x%lx is already in use\n", vaddr);
- prom_halt();
- }
+ if ((char *)res >= (char*)xresv && (char *)res < (char *)&xresv[XNRES]) {
+ xres_free((struct xresource *)res);
+ } else {
+ kfree(res);
+ }
+}
+
+/*
+ * Davem's version of sbus_ioremap.
+ */
+unsigned long sbus_ioremap(struct resource *phyres, unsigned long offset,
+ unsigned long size, char *name)
+{
+ return (unsigned long) _sparc_alloc_io(phyres->flags & 0xF,
+ phyres->start + offset, size, name);
+}
- /* Tell Linux resource manager about the mapping */
- request_region ((vaddr | offset), len, name);
+/*
+ */
+void sbus_iounmap(unsigned long addr, unsigned long size)
+{
+ iounmap((void *)addr);
+}
+
+/*
+ * Meat of mapping
+ */
+static void *_sparc_alloc_io(unsigned int busno, unsigned long phys,
+ unsigned long size, char *name)
+{
+ static int printed_full = 0;
+ struct xresource *xres;
+ struct resource *res;
+ char *tack;
+ int tlen;
+ void *va; /* P3 diag */
+
+ if (name == NULL) name = "???";
+
+ if ((xres = xres_alloc()) != 0) {
+ tack = xres->xname;
+ res = &xres->xres;
} else {
- vaddr = occupy_region(sparc_iobase_vaddr, IOBASE_END,
- (offset + len + PAGE_SIZE-1) & PAGE_MASK, PAGE_SIZE, name);
- if (vaddr == 0) {
- /* Usually we cannot see printks in this case. */
- prom_printf("alloc_io: cannot occupy %d region\n", len);
- prom_halt();
+ if (!printed_full) {
+ printk("ioremap: done with statics, switching to malloc\n");
+ printed_full = 1;
}
+ tlen = strlen(name);
+ tack = kmalloc(sizeof (struct resource) + tlen + 1, GFP_KERNEL);
+ if (tack == NULL) return NULL;
+ res = (struct resource *) tack;
+ tack += sizeof (struct resource);
}
- base_address = vaddr;
- /* Do the actual mapping */
- for (; len > 0; len -= PAGE_SIZE) {
- mapioaddr(addr, vaddr, bus_type, rdonly);
- vaddr += PAGE_SIZE;
- addr += PAGE_SIZE;
- }
+ strncpy(tack, name, XNMLN);
+ tack[XNMLN] = 0;
+ res->name = tack;
- return (void *) (base_address | offset);
+ va = _sparc_ioremap(res, busno, phys, size);
+ /* printk("ioremap(0x%x:%08lx[0x%lx])=%p\n", busno, phys, size, va); */ /* P3 diag */
+ return va;
}
-void sparc_free_io (void *virtual, int len)
+/*
+ * This is called from _sparc_alloc_io only, we left it separate
+ * in case Davem changes his mind about interface to sbus_ioremap().
+ */
+static void *
+_sparc_ioremap(struct resource *res, u32 bus, u32 pa, int sz)
{
- unsigned long vaddr = (unsigned long) virtual & PAGE_MASK;
- unsigned long plen = (((unsigned long)virtual & ~PAGE_MASK) + len + PAGE_SIZE-1) & PAGE_MASK;
+ unsigned long offset = ((unsigned long) pa) & (~PAGE_MASK);
+ unsigned long va;
+ unsigned int psz;
+
+ if (allocate_resource(&sparc_iomap, res,
+ (offset + sz + PAGE_SIZE-1) & PAGE_MASK,
+ sparc_iomap.start, sparc_iomap.end, PAGE_SIZE, NULL, NULL) != 0) {
+ /* Usually we cannot see printks in this case. */
+ prom_printf("alloc_io_res(%s): cannot occupy\n",
+ (res->name != NULL)? res->name: "???");
+ prom_halt();
+ }
+
+ va = res->start;
+ pa &= PAGE_MASK;
+ for (psz = res->end - res->start + 1; psz != 0; psz -= PAGE_SIZE) {
+ mapioaddr(pa, va, bus, 0);
+ va += PAGE_SIZE;
+ pa += PAGE_SIZE;
+ }
+
+ /*
+ * XXX Playing with implementation details here.
+ * On sparc64 Ebus has resources with precise boundaries.
+ * We share drivers with sparc64. Too clever drivers use
+ * start of a resource instead of a base adress.
+ *
+ * XXX-2 This may be not valid anymore, clean when
+ * interface to sbus_ioremap() is resolved.
+ */
+ res->start += offset;
+ res->end = res->start + sz - 1; /* not strictly necessary.. */
+
+ return (void *) res->start;
+}
- release_region(vaddr, plen);
+/*
+ * Comlimentary to _sparc_ioremap().
+ */
+static void _sparc_free_io(struct resource *res)
+{
+ unsigned long plen;
- for (; plen != 0;) {
+ plen = res->end - res->start + 1;
+ while (plen != 0) {
plen -= PAGE_SIZE;
- unmapioaddr(vaddr + plen);
+ unmapioaddr(res->start + plen);
+ }
+
+ release_resource(res);
+}
+
+#ifdef CONFIG_SBUS
+
+void sbus_set_sbus64(struct sbus_dev *sdev, int x) {
+ printk("sbus_set_sbus64: unsupported\n");
+}
+
+/*
+ * Allocate a chunk of memory suitable for DMA.
+ * Typically devices use them for control blocks.
+ * CPU may access them without any explicit flushing.
+ */
+void *sbus_alloc_consistant(struct sbus_dev *sdev, long len, u32 *dma_addrp)
+{
+ unsigned long len_total = (len + PAGE_SIZE-1) & PAGE_MASK;
+ unsigned long va;
+ struct resource *res;
+ int order;
+
+ /* XXX why are some lenghts signed, others unsigned? */
+ if (len <= 0) {
+ return NULL;
+ }
+ /* XXX So what is maxphys for us and how do drivers know it? */
+ if (len > 256*1024) { /* __get_free_pages() limit */
+ return NULL;
}
+
+ for (order = 0; order < 6; order++) /* 2^6 pages == 256K */
+ if ((1 << (order + PAGE_SHIFT)) >= len_total)
+ break;
+ va = __get_free_pages(GFP_KERNEL, order);
+ if (va == 0) {
+ /*
+ * printk here may be flooding... Consider removal XXX.
+ */
+ printk("sbus_alloc_consistant: no %ld pages\n", len_total>>PAGE_SHIFT);
+ return NULL;
+ }
+
+ if ((res = kmalloc(sizeof(struct resource), GFP_KERNEL)) == NULL) {
+ free_pages(va, order);
+ printk("sbus_alloc_consistant: no core\n");
+ return NULL;
+ }
+
+ if (allocate_resource(&sparc_dvma, res, len_total,
+ sparc_dvma.start, sparc_dvma.end, PAGE_SIZE, NULL, NULL) != 0) {
+ printk("sbus_alloc_consistant: cannot occupy 0x%lx", len);
+ free_pages(va, order);
+ kfree(res);
+ return NULL;
+ }
+
+ *dma_addrp = res->start;
+ mmu_map_dma_area(va, res->start, len);
+
+ /*
+ * "Official" or "natural" address of pages we got is va.
+ * We want to return uncached range. We could make va[len]
+ * uncached but it's difficult to make cached back [P3: hmm]
+ * We use the artefact of sun4c, replicated everywhere else,
+ * that CPU can use bus addresses to access the same memory.
+ */
+ res->name = (void *)va; /* XXX Ouch.. we got to hide it somewhere */
+ return (void *)res->start;
}
-/* Does DVMA allocations with PAGE_SIZE granularity. How this basically
- * works is that the ESP chip can do DVMA transfers at ANY address with
- * certain size and boundary restrictions. But other devices that are
- * attached to it and would like to do DVMA have to set things up in
- * a special way, if the DVMA sees a device attached to it transfer data
- * at addresses above DVMA_VADDR it will grab them, this way it does not
- * now have to know the peculiarities of where to read the Lance data
- * from. (for example)
+void sbus_free_consistant(struct sbus_dev *sdev, long n, void *p, u32 ba)
+{
+ struct resource *res;
+ unsigned long pgp;
+ int order;
+
+ if ((res = sparc_find_resource_bystart(&sparc_dvma,
+ (unsigned long)p)) == NULL) {
+ printk("sbus_free_consistant: cannot free %p\n", p);
+ return;
+ }
+
+ if (((unsigned long)p & (PAGE_MASK-1)) != 0) {
+ printk("sbus_free_consistant: unaligned va %p\n", p);
+ return;
+ }
+
+ n = (n + PAGE_SIZE-1) & PAGE_MASK;
+ if ((res->end-res->start)+1 != n) {
+ printk("sbus_free_consistant: region 0x%lx asked 0x%lx\n",
+ (long)((res->end-res->start)+1), n);
+ return;
+ }
+
+ mmu_inval_dma_area((unsigned long)res->name, n); /* XXX Ouch */
+ mmu_unmap_dma_area(ba, n);
+ release_resource(res);
+
+ pgp = (unsigned long) res->name; /* XXX Ouch */
+ for (order = 0; order < 6; order++)
+ if ((1 << (order + PAGE_SHIFT)) >= n)
+ break;
+ free_pages(pgp, order);
+
+ kfree(res);
+}
+
+/*
+ * Map a chunk of memory so that devices can see it.
+ * CPU view of this memory may be inconsistent with
+ * a device view and explicit flushing is necessary.
*/
-void *_sparc_dvma_malloc (int len, char *name)
+u32 sbus_map_single(struct sbus_dev *sdev, void *va, long len)
{
- unsigned long vaddr, base_address;
+#if 0 /* This is the version that abuses consistant space */
+ unsigned long len_total = (len + PAGE_SIZE-1) & PAGE_MASK;
+ struct resource *res;
- vaddr = dvma_next_free;
- if(check_region (vaddr, len)) {
- prom_printf("alloc_dma: 0x%lx is already in use\n", vaddr);
- prom_halt();
+ /* XXX why are some lenghts signed, others unsigned? */
+ if (len <= 0) {
+ return 0;
}
- if(vaddr + len > (DVMA_VADDR + DVMA_LEN)) {
- prom_printf("alloc_dvma: out of dvma memory\n");
- prom_halt();
+ /* XXX So what is maxphys for us and how do drivers know it? */
+ if (len > 256*1024) { /* __get_free_pages() limit */
+ return 0;
+ }
+
+ if ((res = kmalloc(sizeof(struct resource), GFP_KERNEL)) == NULL) {
+ printk("sbus_map_single: no core\n");
+ return 0;
+ }
+ res->name = va;
+
+ if (allocate_resource(&sparc_dvma, res, len_total,
+ sparc_dvma.start, sparc_dvma.end, PAGE_SIZE) != 0) {
+ printk("sbus_map_single: cannot occupy 0x%lx", len);
+ kfree(res);
+ return 0;
+ }
+
+ mmu_map_dma_area(va, res->start, len_total);
+ mmu_flush_dma_area((unsigned long)va, len_total); /* in all contexts? */
+
+ return res->start;
+#endif
+#if 1 /* "trampoline" version */
+ /* XXX why are some lenghts signed, others unsigned? */
+ if (len <= 0) {
+ return 0;
+ }
+ /* XXX So what is maxphys for us and how do drivers know it? */
+ if (len > 256*1024) { /* __get_free_pages() limit */
+ return 0;
+ }
+/* BTFIXUPDEF_CALL(__u32, mmu_get_scsi_one, char *, unsigned long, struct sbus_bus *sbus) */
+ return mmu_get_scsi_one(va, len, sdev->bus);
+#endif
+}
+
+void sbus_unmap_single(struct sbus_dev *sdev, u32 ba, long n)
+{
+#if 0 /* This is the version that abuses consistant space */
+ struct resource *res;
+ unsigned long va;
+
+ if ((res = sparc_find_resource_bystart(&sparc_dvma, ba)) == NULL) {
+ printk("sbus_unmap_single: cannot find %08x\n", (unsigned)ba);
+ return;
}
- /* Basically these can be mapped just like any old
- * IO pages, cacheable bit off, etc. The physical
- * pages are now mapped dynamically to save space.
+ n = (n + PAGE_SIZE-1) & PAGE_MASK;
+ if ((res->end-res->start)+1 != n) {
+ printk("sbus_unmap_single: region 0x%lx asked 0x%lx\n",
+ (long)((res->end-res->start)+1), n);
+ return;
+ }
+
+ va = (unsigned long) res->name; /* XXX Ouch */
+ mmu_inval_dma_area(va, n); /* in all contexts, mm's?... */
+ mmu_unmap_dma_area(ba, n); /* iounit cache flush is here */
+ release_resource(res);
+ kfree(res);
+#endif
+#if 1 /* "trampoline" version */
+/* BTFIXUPDEF_CALL(void, mmu_release_scsi_one, __u32, unsigned long, struct sbus_bus *sbus) */
+ mmu_release_scsi_one(ba, n, sdev->bus);
+#endif
+}
+
+int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sg, int n)
+{
+/* BTFIXUPDEF_CALL(void, mmu_get_scsi_sgl, struct scatterlist *, int, struct sbus_bus *sbus) */
+ mmu_get_scsi_sgl(sg, n, sdev->bus);
+
+ /*
+ * XXX sparc64 can return a partial length here. sun4c should do this
+ * but it currently panics if it can't fulfill the request - Anton
*/
- base_address = vaddr;
- mmu_map_dma_area(base_address, len);
- /* Assign the memory area. */
- dvma_next_free = PAGE_ALIGN(dvma_next_free+len);
+ return n;
+}
- request_region(base_address, len, name);
+void sbus_unmap_sg(struct sbus_dev *sdev, struct scatterlist *sg, int n)
+{
+/* BTFIXUPDEF_CALL(void, mmu_release_scsi_sgl, struct scatterlist *, int, struct sbus_bus *sbus) */
+ mmu_release_scsi_sgl(sg, n, sdev->bus);
+}
+#endif
+
+/*
+ * P3: I think a partial flush is permitted...
+ * We are not too efficient at doing it though.
+ *
+ * If only DaveM understood a concept of an allocation cookie,
+ * we could avoid find_resource_by_hit() here and a major
+ * performance hit.
+ */
+void sbus_dma_sync_single(struct sbus_dev *sdev, u32 ba, long size)
+{
+ unsigned long va;
+ struct resource *res;
+
+ res = sparc_find_resource_by_hit(&sparc_dvma, ba);
+ if (res == NULL)
+ panic("sbus_dma_sync_single: 0x%x\n", ba);
+
+ va = (unsigned long) res->name;
+ /* if (va == 0) */
+
+ mmu_inval_dma_area(va, (res->end - res->start) + 1);
+}
+
+void sbus_dma_sync_sg(struct sbus_dev *sdev, struct scatterlist *sg, int n)
+{
+ printk("dma_sync_sg: not implemented yet\n");
+}
+
+/*
+ * This is a version of find_resource and it belongs to kernel/resource.c.
+ * Until we have agreement with Linus and Martin, it lingers here.
+ *
+ * "same start" is more strict than "hit into"
+ */
+struct resource *
+sparc_find_resource_bystart(struct resource *root, unsigned long start)
+{
+ struct resource *tmp;
+
+ for (tmp = root->child; tmp != 0; tmp = tmp->sibling) {
+ if (tmp->start == start)
+ return tmp;
+ }
+ return NULL;
+}
+
+struct resource *
+sparc_find_resource_by_hit(struct resource *root, unsigned long hit)
+{
+ struct resource *tmp;
- return (void *) base_address;
+ for (tmp = root->child; tmp != 0; tmp = tmp->sibling) {
+ if (tmp->start <= hit && tmp->end >= hit)
+ return tmp;
+ }
+ return NULL;
}
diff --git a/arch/sparc/kernel/irq.c b/arch/sparc/kernel/irq.c
index fb4e0dab1..c89d04872 100644
--- a/arch/sparc/kernel/irq.c
+++ b/arch/sparc/kernel/irq.c
@@ -1,4 +1,4 @@
-/* $Id: irq.c,v 1.97 1999/09/10 10:40:21 davem Exp $
+/* $Id: irq.c,v 1.99 1999/12/27 06:08:29 anton Exp $
* arch/sparc/kernel/irq.c: Interrupt request handling routines. On the
* Sparc the IRQ's are basically 'cast in stone'
* and you are supposed to probe the prom's device
@@ -40,6 +40,7 @@
#include <asm/traps.h>
#include <asm/irq.h>
#include <asm/io.h>
+#include <asm/pgalloc.h>
#include <asm/pgtable.h>
#include <asm/hardirq.h>
#include <asm/softirq.h>
@@ -726,7 +727,7 @@ void __init init_IRQ(void)
case sun4m:
#ifdef CONFIG_PCI
pcic_probe();
- if (pci_present()) {
+ if (pcic_present()) {
sun4m_pci_init_IRQ();
break;
}
diff --git a/arch/sparc/kernel/pcic.c b/arch/sparc/kernel/pcic.c
index 53bf4623b..94847460b 100644
--- a/arch/sparc/kernel/pcic.c
+++ b/arch/sparc/kernel/pcic.c
@@ -1,4 +1,4 @@
-/* $Id: pcic.c,v 1.8 1999/08/31 06:54:22 davem Exp $
+/* $Id: pcic.c,v 1.11 1999/11/25 05:22:05 zaitcev Exp $
* pcic.c: Sparc/PCI controller support
*
* Copyright (C) 1998 V. Roganov and G. Raiko
@@ -22,17 +22,6 @@
#include <asm/swift.h> /* for cache flushing. */
#include <asm/io.h>
-#undef PROM_DEBUG
-#undef FIXUP_REGS_DEBUG
-#undef FIXUP_IRQ_DEBUG
-#undef FIXUP_VMA_DEBUG
-
-#ifdef PROM_DEBUG
-#define dprintf prom_printf
-#else
-#define dprintf printk
-#endif
-
#include <linux/ctype.h>
#include <linux/pci.h>
#include <linux/timex.h>
@@ -57,7 +46,7 @@ asmlinkage int sys_pciconfig_read(unsigned long bus,
unsigned long len,
unsigned char *buf)
{
- return 0;
+ return -EINVAL;
}
asmlinkage int sys_pciconfig_write(unsigned long bus,
@@ -66,11 +55,19 @@ asmlinkage int sys_pciconfig_write(unsigned long bus,
unsigned long len,
unsigned char *buf)
{
- return 0;
+ return -EINVAL;
}
#else
+#ifdef CONFIG_SUN_JSFLASH
+extern int jsflash_init(void);
+#endif
+
+struct pci_fixup pcibios_fixups[] = {
+ { 0 }
+};
+
unsigned int pcic_pin_to_irq(unsigned int pin, char *name);
/*
@@ -120,7 +117,8 @@ static struct pcic_ca2irq pcic_i_jse[] = {
{ 0, 0x00, 0, 13, 0 }, /* Ebus - serial and keyboard */
{ 0, 0x01, 1, 6, 0 }, /* hme */
{ 0, 0x08, 2, 9, 0 }, /* VGA - we hope not used :) */
- { 0, 0x18, 6, 8, 0 }, /* PCI INTA# in Slot 1 */
+ { 0, 0x10, 6, 8, 0 }, /* PCI INTA# in Slot 1 */
+ { 0, 0x18, 7, 12, 0 }, /* PCI INTA# in Slot 2, shared w. RTC */
{ 0, 0x38, 4, 9, 0 }, /* All ISA devices. Read 8259. */
{ 0, 0x80, 5, 11, 0 }, /* EIDE */
/* {0,0x88, 0,0,0} - unknown device... PMU? Probably no interrupt. */
@@ -144,6 +142,16 @@ static struct pcic_ca2irq pcic_i_se6[] = {
};
/*
+ * Krups (courtesy of Varol Kaptan)
+ * No documentation available, so we guess it, based on Espresso layout.
+ * Since we always run PROLL on Krups we may put map in there.
+ */
+static struct pcic_ca2irq pcic_i_jk[] = {
+ { 0, 0x00, 0, 13, 0 }, /* Ebus - serial and keyboard */
+ { 0, 0x01, 1, 6, 0 }, /* hme */
+};
+
+/*
* Several entries in this list may point to the same routing map
* as several PROMs may be installed on the same physical board.
*/
@@ -154,11 +162,17 @@ static struct pcic_sn2list pcic_known_sysnames[] = {
SN2L_INIT("JE-1-name", pcic_i_je1), /* XXX Gleb, put name here, pls */
SN2L_INIT("SUNW,JS-E", pcic_i_jse), /* PROLL JavaStation-E */
SN2L_INIT("SUNW,SPARCengine-6", pcic_i_se6), /* SPARCengine-6/CP-1200 */
+ SN2L_INIT("SUNW,JS-NC", pcic_i_jk), /* PROLL JavaStation-NC */
+ SN2L_INIT("SUNW,JSIIep", pcic_i_jk), /* OBP JavaStation-NC */
{ NULL, NULL, 0 }
};
-static struct linux_pcic PCIC;
-static struct linux_pcic *pcic = NULL;
+/*
+ * Only one PCIC per IIep,
+ * and since we have no SMP IIep, only one per system.
+ */
+static int pcic0_up = 0;
+static struct linux_pcic pcic0;
unsigned int pcic_regs;
volatile int pcic_speculative;
@@ -167,23 +181,144 @@ volatile int pcic_trapped;
static void pci_do_gettimeofday(struct timeval *tv);
static void pci_do_settimeofday(struct timeval *tv);
-void __init pcic_probe(void)
+#define CONFIG_CMD(bus, device_fn, where) (0x80000000 | (((unsigned int)bus) << 16) | (((unsigned int)device_fn) << 8) | (where & ~3))
+
+static int pcic_read_config_dword(struct pci_dev *dev, int where, u32 *value);
+static int pcic_write_config_dword(struct pci_dev *dev, int where, u32 value);
+
+static int pcic_read_config_byte(struct pci_dev *dev, int where, u8 *value)
+{
+ unsigned int v;
+
+ pcic_read_config_dword(dev, where&~3, &v);
+ *value = 0xff & (v >> (8*(where & 3)));
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int pcic_read_config_word(struct pci_dev *dev, int where, u16 *value)
+{
+ unsigned int v;
+ if (where&1) return PCIBIOS_BAD_REGISTER_NUMBER;
+
+ pcic_read_config_dword(dev, where&~3, &v);
+ *value = 0xffff & (v >> (8*(where & 3)));
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int pcic_read_config_dword(struct pci_dev *dev, int where, u32 *value)
+{
+ unsigned char bus = dev->bus->number;
+ unsigned char device_fn = dev->devfn;
+ /* unsigned char where; */
+
+ struct linux_pcic *pcic;
+ unsigned long flags;
+
+ if (where&3) return PCIBIOS_BAD_REGISTER_NUMBER;
+ if (bus != 0) return PCIBIOS_DEVICE_NOT_FOUND;
+ pcic = &pcic0;
+
+ save_and_cli(flags);
+#if 0 /* does not fail here */
+ pcic_speculative = 1;
+ pcic_trapped = 0;
+#endif
+ writel(CONFIG_CMD(bus,device_fn,where), pcic->pcic_config_space_addr);
+#if 0 /* does not fail here */
+ nop();
+ if (pcic_trapped) {
+ restore_flags(flags);
+ *value = ~0;
+ return PCIBIOS_SUCCESSFUL;
+ }
+#endif
+ pcic_speculative = 2;
+ pcic_trapped = 0;
+ *value = readl(pcic->pcic_config_space_data + (where&4));
+ nop();
+ if (pcic_trapped) {
+ pcic_speculative = 0;
+ restore_flags(flags);
+ *value = ~0;
+ return PCIBIOS_SUCCESSFUL;
+ }
+ pcic_speculative = 0;
+ restore_flags(flags);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int pcic_write_config_byte(struct pci_dev *dev, int where, u8 value)
{
+ unsigned int v;
+
+ pcic_read_config_dword(dev, where&~3, &v);
+ v = (v & ~(0xff << (8*(where&3)))) |
+ ((0xff&(unsigned)value) << (8*(where&3)));
+ return pcic_write_config_dword(dev, where&~3, v);
+}
+
+static int pcic_write_config_word(struct pci_dev *dev, int where, u16 value)
+{
+ unsigned int v;
+
+ if (where&1) return PCIBIOS_BAD_REGISTER_NUMBER;
+ pcic_read_config_dword(dev, where&~3, &v);
+ v = (v & ~(0xffff << (8*(where&3)))) |
+ ((0xffff&(unsigned)value) << (8*(where&3)));
+ return pcic_write_config_dword(dev, where&~3, v);
+}
+
+static int pcic_write_config_dword(struct pci_dev *dev, int where, u32 value)
+{
+ unsigned char bus = dev->bus->number;
+ unsigned char devfn = dev->devfn;
+ struct linux_pcic *pcic;
+ unsigned long flags;
+
+ if (where&3) return PCIBIOS_BAD_REGISTER_NUMBER;
+ if (bus != 0) return PCIBIOS_DEVICE_NOT_FOUND;
+ pcic = &pcic0;
+
+ save_and_cli(flags);
+ writel(CONFIG_CMD(bus,devfn,where), pcic->pcic_config_space_addr);
+ writel(value, pcic->pcic_config_space_data + (where&4));
+ restore_flags(flags);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static struct pci_ops pcic_ops = {
+ pcic_read_config_byte,
+ pcic_read_config_word,
+ pcic_read_config_dword,
+ pcic_write_config_byte,
+ pcic_write_config_word,
+ pcic_write_config_dword,
+};
+
+/*
+ * On sparc64 pcibios_init() calls pci_controller_probe().
+ * We want PCIC probed little ahead so that interrupt controller
+ * would be operational.
+ */
+int __init pcic_probe(void)
+{
+ struct linux_pcic *pcic;
struct linux_prom_registers regs[PROMREG_MAX];
struct linux_pbm_info* pbm;
char namebuf[64];
int node;
int err;
- if (pcibios_present()) {
+ if (pcic0_up) {
prom_printf("PCIC: called twice!\n");
prom_halt();
}
+ pcic = &pcic0;
node = prom_getchild (prom_root_node);
node = prom_searchsiblings (node, "pci");
if (node == 0)
- return;
+ return -ENODEV;
/*
* Map in PCIC register set, config space, and IO base
*/
@@ -193,31 +328,27 @@ void __init pcic_probe(void)
"from PROM.\n");
prom_halt();
}
-
- pcic = &PCIC;
- pcic->pcic_regs = (unsigned long)sparc_alloc_io(regs[0].phys_addr, NULL,
- regs[0].reg_size,
- "PCIC Registers", 0, 0);
+ pcic0_up = 1;
+
+ pcic->pcic_res_regs.name = "pcic_registers";
+ pcic->pcic_regs = (unsigned long)
+ ioremap(regs[0].phys_addr, regs[0].reg_size);
if (!pcic->pcic_regs) {
prom_printf("PCIC: Error, cannot map PCIC registers.\n");
prom_halt();
}
- pcic->pcic_io_phys = regs[1].phys_addr;
- pcic->pcic_io = (unsigned long)sparc_alloc_io(regs[1].phys_addr, NULL,
- regs[1].reg_size,
- "PCIC IO Base", 0, 0);
- if (pcic->pcic_io == 0UL) {
+ pcic->pcic_res_io.name = "pcic_io";
+ if ((pcic->pcic_io = (unsigned long)
+ ioremap(regs[1].phys_addr, 0x10000)) == 0) {
prom_printf("PCIC: Error, cannot map PCIC IO Base.\n");
prom_halt();
}
- pcic->pcic_config_space_addr =
- (unsigned long)sparc_alloc_io (regs[2].phys_addr, NULL,
- regs[2].reg_size * 2,
- "PCI Config Space Address", 0, 0);
- if (pcic->pcic_config_space_addr == 0UL) {
+ pcic->pcic_res_cfg_addr.name = "pcic_cfg_addr";
+ if ((pcic->pcic_config_space_addr = (unsigned long)
+ ioremap(regs[2].phys_addr, regs[2].reg_size * 2)) == 0) {
prom_printf("PCIC: Error, cannot map"
"PCI Configuration Space Address.\n");
prom_halt();
@@ -227,11 +358,9 @@ void __init pcic_probe(void)
* Docs say three least significant bits in address and data
* must be the same. Thus, we need adjust size of data.
*/
- pcic->pcic_config_space_data =
- (unsigned long)sparc_alloc_io (regs[3].phys_addr, NULL,
- regs[3].reg_size * 2,
- "PCI Config Space Data", 0, 0);
- if (pcic->pcic_config_space_data == 0UL) {
+ pcic->pcic_res_cfg_data.name = "pcic_cfg_data";
+ if ((pcic->pcic_config_space_data = (unsigned long)
+ ioremap(regs[3].phys_addr, regs[3].reg_size * 2)) == 0) {
prom_printf("PCIC: Error, cannot map"
"PCI Configuration Space Data.\n");
prom_halt();
@@ -239,7 +368,7 @@ void __init pcic_probe(void)
pbm = &pcic->pbm;
pbm->prom_node = node;
- prom_getstring(node, "name", namebuf, sizeof(namebuf));
+ prom_getstring(node, "name", namebuf, 63); namebuf[63] = 0;
strcpy(pbm->prom_name, namebuf);
{
@@ -254,7 +383,7 @@ void __init pcic_probe(void)
pcic_regs = pcic->pcic_regs;
}
- prom_getstring(prom_root_node, "name", namebuf, sizeof(namebuf));
+ prom_getstring(prom_root_node, "name", namebuf, 63); namebuf[63] = 0;
{
struct pcic_sn2list *p;
@@ -272,21 +401,37 @@ void __init pcic_probe(void)
printk("PCIC: System %s is unknown, cannot route interrupts\n",
namebuf);
}
+
+ return 0;
}
+static void __init pcic_pbm_scan_bus(struct linux_pcic *pcic)
+{
+ struct linux_pbm_info *pbm = &pcic->pbm;
+
+ pbm->pci_bus = pci_scan_bus(pbm->pci_first_busno, &pcic_ops, pbm);
+#if 0 /* deadwood transplanted from sparc64 */
+ pci_fill_in_pbm_cookies(pbm->pci_bus, pbm, pbm->prom_node);
+ pci_record_assignments(pbm, pbm->pci_bus);
+ pci_assign_unassigned(pbm, pbm->pci_bus);
+ pci_fixup_irq(pbm, pbm->pci_bus);
+#endif
+}
+
+/*
+ * Main entry point from the PCI subsystem.
+ */
void __init pcibios_init(void)
{
+ struct linux_pcic *pcic;
+
/*
* PCIC should be initialized at start of the timer.
* So, here we report the presence of PCIC and do some magic passes.
*/
- if(!pcic)
+ if(!pcic0_up)
return;
-
- printk("PCIC MAP: config addr=0x%lx; config data=0x%lx, "
- "regs=0x%lx io=0x%lx\n",
- pcic->pcic_config_space_addr, pcic->pcic_config_space_data,
- pcic->pcic_regs, pcic->pcic_io);
+ pcic = &pcic0;
/*
* Switch off IOTLB translation.
@@ -302,11 +447,18 @@ void __init pcibios_init(void)
writel(0xF0000000UL, pcic->pcic_regs+PCI_SIZE_0);
writel(0+PCI_BASE_ADDRESS_SPACE_MEMORY,
pcic->pcic_regs+PCI_BASE_ADDRESS_0);
+
+ pcic_pbm_scan_bus(pcic);
+
+ ebus_init();
+#ifdef CONFIG_SUN_JSFLASH
+ jsflash_init();
+#endif
}
-int pcibios_present(void)
+int pcic_present(void)
{
- return pcic != NULL;
+ return pcic0_up;
}
static int __init pdev_to_pnode(struct linux_pbm_info *pbm,
@@ -334,91 +486,77 @@ static inline struct pcidev_cookie *pci_devcookie_alloc(void)
return kmalloc(sizeof(struct pcidev_cookie), GFP_ATOMIC);
}
-static void pcic_map_pci_device (struct pci_dev *dev, int node) {
- struct linux_prom_pci_assigned_addresses addrs[6];
- int addrlen;
- int i, j;
-
- /* Is any valid address present ? */
- i = 0;
- for(j = 0; j < 6; j++)
- if (dev->base_address[j]) i++;
- if (!i) return; /* nothing to do */
+static void pcic_map_pci_device(struct linux_pcic *pcic,
+ struct pci_dev *dev, int node)
+{
+ char namebuf[64];
+ unsigned long address;
+ unsigned long flags;
+ int j;
if (node == 0 || node == -1) {
- printk("PCIC: no prom node for device ID (%x,%x)\n",
- dev->device, dev->vendor);
- return;
- }
-
- /*
- * find related address and get it's window length
- */
- addrlen = prom_getproperty(node,"assigned-addresses",
- (char*)addrs, sizeof(addrs));
- if (addrlen == -1) {
- printk("PCIC: no \"assigned-addresses\" for device (%x,%x)\n",
- dev->device, dev->vendor);
- return;
+ strcpy(namebuf, "???");
+ } else {
+ prom_getstring(node, "name", namebuf, 63); namebuf[63] = 0;
}
- addrlen /= sizeof(struct linux_prom_pci_assigned_addresses);
- for (i = 0; i < addrlen; i++ )
- for (j = 0; j < 6; j++) {
- if (!dev->base_address[j] || !addrs[i].phys_lo)
- continue;
- if (addrs[i].phys_lo == dev->base_address[j]) {
- unsigned long address = dev->base_address[j];
- int length = addrs[i].size_lo;
- char namebuf[128] = { 0, };
- unsigned long mapaddr, addrflags;
-
- prom_getstring(node, "name", namebuf, sizeof(namebuf));
-
- /*
- * failure in allocation too large space
- */
- if (length > 0x200000) {
- length = 0x200000;
- prom_printf("PCIC: map window for device '%s' "
- "reduced to 2MB !\n", namebuf);
- }
-
- /*
- * Be careful with MEM/IO address flags
- */
- if ((address & PCI_BASE_ADDRESS_SPACE) ==
- PCI_BASE_ADDRESS_SPACE_IO) {
- mapaddr = address & PCI_BASE_ADDRESS_IO_MASK;
+ for (j = 0; j < 6; j++) {
+ address = dev->resource[j].start;
+ if (address == 0) break; /* are sequential */
+ flags = dev->resource[j].flags;
+ if ((flags & IORESOURCE_IO) != 0) {
+ if (address < 0x10000) {
+ /*
+ * A device responds to I/O cycles on PCI.
+ * We generate these cycles with memory
+ * access into the fixed map (phys 0x30000000).
+ *
+ * Since a device driver does not want to
+ * do ioremap() before accessing PC-style I/O,
+ * we supply virtual, ready to access address.
+ *
+ * Ebus devices do not come here even if
+ * CheerIO makes a similar conversion.
+ * See ebus.c for details.
+ *
+ * Note that check_region()/request_region()
+ * work for these devices.
+ *
+ * XXX Neat trick, but it's a *bad* idea
+ * to shit into regions like that.
+ * What if we want to allocate one more
+ * PCI base address...
+ */
+ dev->resource[j].start =
+ pcic->pcic_io + address;
+ dev->resource[j].end = 1; /* XXX */
+ dev->resource[j].flags =
+ (flags & ~IORESOURCE_IO) | IORESOURCE_MEM;
} else {
- mapaddr = address & PCI_BASE_ADDRESS_MEM_MASK;
+ /*
+ * OOPS... PCI Spec allows this. Sun does
+ * not have any devices getting above 64K
+ * so it must be user with a weird I/O
+ * board in a PCI slot. We must remap it
+ * under 64K but it is not done yet. XXX
+ */
+ printk("PCIC: Skipping I/O space at 0x%lx,"
+ "this will Oops if a driver attaches;"
+ "device '%s' (%x,%x)\n", address, namebuf,
+ dev->device, dev->vendor);
}
- addrflags = address ^ mapaddr;
-
- dev->base_address[j] =
- (unsigned long)sparc_alloc_io(address, 0,
- length,
- namebuf, 0, 0);
- if ( dev->base_address[j] == 0 )
- panic("PCIC: failed make mapping for "
- "pci device '%s' with address %lx\n",
- namebuf, address);
-
- dev->base_address[j] ^= addrflags;
- return;
}
- }
-
- printk("PCIC: unable to match addresses for device (%x,%x)\n",
- dev->device, dev->vendor);
+ }
}
-static void pcic_fill_irq(struct pci_dev *dev, int node) {
+static void
+pcic_fill_irq(struct linux_pcic *pcic, struct pci_dev *dev, int node)
+{
struct pcic_ca2irq *p;
int i, ivec;
char namebuf[64]; /* P3 remove */
- if (node == -1) {
+ if (node == 0 || node == -1) {
strcpy(namebuf, "???");
} else {
prom_getstring(node, "name", namebuf, sizeof(namebuf)); /* P3 remove */
@@ -474,53 +612,33 @@ static void pcic_fill_irq(struct pci_dev *dev, int node) {
}
/*
- * Assign IO space for a device.
- * This is a chance for devices which have the same IO and Mem Space to
- * fork access to IO and Mem.
- *
- * Now, we assume there is one such device only (IGA 1682) but code below
- * should work in cases when space of all such devices is less then 16MB.
- */
-unsigned long pcic_alloc_io( unsigned long* addr )
-{
- unsigned long paddr = *addr;
- unsigned long offset;
-
- if(pcic->pcic_mapped_io == 0) {
- pcic->pcic_mapped_io = paddr & ~(PCI_SPACE_SIZE-1) ;
- writeb((pcic->pcic_mapped_io>>24) & 0xff,
- pcic->pcic_regs+PCI_PIBAR);
- writeb((pcic->pcic_io_phys>>24) & PCI_SIBAR_ADDRESS_MASK,
- pcic->pcic_regs+PCI_SIBAR);
- writeb(PCI_ISIZE_16M, pcic->pcic_regs+PCI_ISIZE);
-
- }
- if(paddr < pcic->pcic_mapped_io ||
- paddr >= pcic->pcic_mapped_io + 0x10000)
- return 0;
- offset = paddr - pcic->pcic_mapped_io;
- *addr = pcic->pcic_io_phys + offset;
- return pcic->pcic_io + offset;
-}
-
-/*
- * Stolen from both i386 and sparc64 branch
+ * Normally called from {do_}pci_scan_bus...
*/
-void __init pcibios_fixup(void)
+void __init pcibios_fixup_bus(struct pci_bus *bus)
{
- struct pci_dev *dev;
- int i, has_io, has_mem;
- unsigned short cmd;
- struct linux_pbm_info* pbm = &pcic->pbm;
+ struct pci_dev *dev;
+ int i, has_io, has_mem;
+ unsigned short cmd;
+ struct linux_pcic *pcic;
+ /* struct linux_pbm_info* pbm = &pcic->pbm; */
int node;
struct pcidev_cookie *pcp;
- if(pcic == NULL) {
- prom_printf("PCI: Error, PCIC not found.\n");
- prom_halt();
+ if (!pcic0_up) {
+ printk("pcibios_fixup_bus: no PCIC\n");
+ return;
}
+ pcic = &pcic0;
- for (dev = pci_devices; dev; dev=dev->next) {
+ /*
+ * Next crud is an equivalent of pbm = pcic_bus_to_pbm(bus);
+ */
+ if (bus->number != 0) {
+ printk("pcibios_fixup_bus: nonzero bus 0x%x\n", bus->number);
+ return;
+ }
+
+ for (dev = bus->devices; dev; dev = dev->sibling) {
/*
* Comment from i386 branch:
* There are buggy BIOSes that forget to enable I/O and memory
@@ -531,44 +649,42 @@ void __init pcibios_fixup(void)
*/
has_io = has_mem = 0;
for(i=0; i<6; i++) {
- unsigned long a = dev->base_address[i];
- if (a & PCI_BASE_ADDRESS_SPACE_IO) {
+ unsigned long f = dev->resource[i].flags;
+ if (f & IORESOURCE_IO) {
has_io = 1;
- } else if (a & PCI_BASE_ADDRESS_MEM_MASK)
+ } else if (f & IORESOURCE_MEM)
has_mem = 1;
}
- pci_read_config_word(dev, PCI_COMMAND, &cmd);
+ pcic_read_config_word(dev, PCI_COMMAND, &cmd);
if (has_io && !(cmd & PCI_COMMAND_IO)) {
printk("PCIC: Enabling I/O for device %02x:%02x\n",
dev->bus->number, dev->devfn);
cmd |= PCI_COMMAND_IO;
- pci_write_config_word(dev, PCI_COMMAND, cmd);
+ pcic_write_config_word(dev, PCI_COMMAND, cmd);
}
if (has_mem && !(cmd & PCI_COMMAND_MEMORY)) {
printk("PCIC: Enabling memory for device %02x:%02x\n",
dev->bus->number, dev->devfn);
cmd |= PCI_COMMAND_MEMORY;
- pci_write_config_word(dev, PCI_COMMAND, cmd);
+ pcic_write_config_word(dev, PCI_COMMAND, cmd);
}
- node = pdev_to_pnode(pbm, dev);
+ node = pdev_to_pnode(&pcic->pbm, dev);
if(node == 0)
node = -1;
/* cookies */
pcp = pci_devcookie_alloc();
- pcp->pbm = pbm;
+ pcp->pbm = &pcic->pbm;
pcp->prom_node = node;
dev->sysdata = pcp;
- /* memory mapping */
+ /* fixing I/O to look like memory */
if ((dev->class>>16) != PCI_BASE_CLASS_BRIDGE)
- pcic_map_pci_device(dev, node);
+ pcic_map_pci_device(pcic, dev, node);
- pcic_fill_irq(dev, node);
+ pcic_fill_irq(pcic, dev, node);
}
-
- ebus_init();
}
/*
@@ -577,6 +693,7 @@ void __init pcibios_fixup(void)
unsigned int
pcic_pin_to_irq(unsigned int pin, char *name)
{
+ struct linux_pcic *pcic = &pcic0;
unsigned int irq;
unsigned int ivec;
@@ -599,7 +716,7 @@ static volatile int pcic_timer_dummy;
static void pcic_clear_clock_irq(void)
{
- pcic_timer_dummy = readl(pcic->pcic_regs+PCI_SYS_LIMIT);
+ pcic_timer_dummy = readl(pcic0.pcic_regs+PCI_SYS_LIMIT);
}
static void pcic_timer_handler (int irq, void *h, struct pt_regs *regs)
@@ -613,6 +730,7 @@ static void pcic_timer_handler (int irq, void *h, struct pt_regs *regs)
void __init pci_time_init(void)
{
+ struct linux_pcic *pcic = &pcic0;
unsigned long v;
int timer_irq, irq;
@@ -620,9 +738,9 @@ void __init pci_time_init(void)
/* A hack until do_gettimeofday prototype is moved to arch specific headers
and btfixupped. Patch do_gettimeofday with ba pci_do_gettimeofday; nop */
((unsigned int *)do_gettimeofday)[0] =
- 0x10800000 | ((((unsigned long)pci_do_gettimeofday - (unsigned long)do_gettimeofday) >> 2) & 0x003fffff);
- ((unsigned int *)do_gettimeofday)[1] =
- 0x01000000;
+ 0x10800000 | ((((unsigned long)pci_do_gettimeofday -
+ (unsigned long)do_gettimeofday) >> 2) & 0x003fffff);
+ ((unsigned int *)do_gettimeofday)[1] = 0x01000000;
BTFIXUPSET_CALL(bus_do_settimeofday, pci_do_settimeofday, BTFIXUPCALL_NORM);
btfixup();
@@ -650,7 +768,7 @@ static __inline__ unsigned long do_gettimeoffset(void)
* to have microsecond resolution and to avoid overflow
*/
unsigned long count =
- readl(pcic->pcic_regs+PCI_SYS_COUNTER) & ~PCI_SYS_COUNTER_OVERFLOW;
+ readl(pcic0.pcic_regs+PCI_SYS_COUNTER) & ~PCI_SYS_COUNTER_OVERFLOW;
count = ((count/100)*USECS_PER_JIFFY) / (TICK_TIMER_LIMIT/100);
if(test_bit(TIMER_BH, &bh_active))
@@ -705,103 +823,9 @@ static void watchdog_reset() {
}
#endif
-#define CONFIG_CMD(bus, device_fn, where) (0x80000000 | (((unsigned int)bus) << 16) | (((unsigned int)device_fn) << 8) | (where & ~3))
-
-int pcibios_read_config_byte(unsigned char bus, unsigned char device_fn,
- unsigned char where, unsigned char *value)
-{
- unsigned int v;
-
- pcibios_read_config_dword (bus, device_fn, where&~3, &v);
- *value = 0xff & (v >> (8*(where & 3)));
- return PCIBIOS_SUCCESSFUL;
-}
-
-int pcibios_read_config_word (unsigned char bus,
- unsigned char device_fn,
- unsigned char where, unsigned short *value)
-{
- unsigned int v;
- if (where&1) return PCIBIOS_BAD_REGISTER_NUMBER;
-
- pcibios_read_config_dword (bus, device_fn, where&~3, &v);
- *value = 0xffff & (v >> (8*(where & 3)));
- return PCIBIOS_SUCCESSFUL;
-}
-
-int pcibios_read_config_dword (unsigned char bus, unsigned char device_fn,
- unsigned char where, unsigned int *value)
-{
- unsigned long flags;
-
- if (where&3) return PCIBIOS_BAD_REGISTER_NUMBER;
-
- save_and_cli(flags);
-#if 0
- pcic_speculative = 1;
- pcic_trapped = 0;
-#endif
- writel(CONFIG_CMD(bus,device_fn,where), pcic->pcic_config_space_addr);
-#if 0
- nop();
- if (pcic_trapped) {
- restore_flags(flags);
- *value = ~0;
- return PCIBIOS_SUCCESSFUL;
- }
-#endif
- pcic_speculative = 2;
- pcic_trapped = 0;
- *value = readl(pcic->pcic_config_space_data + (where&4));
- nop();
- if (pcic_trapped) {
- pcic_speculative = 0;
- restore_flags(flags);
- *value = ~0;
- return PCIBIOS_SUCCESSFUL;
- }
- pcic_speculative = 0;
- restore_flags(flags);
- return PCIBIOS_SUCCESSFUL;
-}
-
-int pcibios_write_config_byte (unsigned char bus, unsigned char devfn,
- unsigned char where, unsigned char value)
-{
- unsigned int v;
-
- pcibios_read_config_dword (bus, devfn, where&~3, &v);
- v = (v & ~(0xff << (8*(where&3)))) |
- ((0xff&(unsigned)value) << (8*(where&3)));
- return pcibios_write_config_dword (bus, devfn, where&~3, v);
-}
-
-int pcibios_write_config_word (unsigned char bus, unsigned char devfn,
- unsigned char where, unsigned short value)
-{
- unsigned int v;
- if (where&1) return PCIBIOS_BAD_REGISTER_NUMBER;
-
- pcibios_read_config_dword (bus, devfn, where&~3, &v);
- v = (v & ~(0xffff << (8*(where&3)))) |
- ((0xffff&(unsigned)value) << (8*(where&3)));
- return pcibios_write_config_dword (bus, devfn, where&~3, v);
-}
-
-int pcibios_write_config_dword (unsigned char bus, unsigned char devfn,
- unsigned char where, unsigned int value)
-{
- unsigned long flags;
-
- if (where&3) return PCIBIOS_BAD_REGISTER_NUMBER;
-
- save_and_cli(flags);
- writel(CONFIG_CMD(bus,devfn,where),pcic->pcic_config_space_addr);
- writel(value, pcic->pcic_config_space_data + (where&4));
- restore_flags(flags);
- return PCIBIOS_SUCCESSFUL;
-}
-
+/*
+ * Other archs parse arguments here.
+ */
char * __init pcibios_setup(char *str)
{
return str;
@@ -831,6 +855,9 @@ void pcic_nmi(unsigned int pend, struct pt_regs *regs)
}
/*
+ * XXX Gleb wrote me that he needs this for X server (only).
+ * Since we successfuly use XF86_FBDev, we do not need these anymore.
+ *
* Following code added to handle extra PCI-related system calls
*/
asmlinkage int sys_pciconfig_read(unsigned long bus,
@@ -870,7 +897,7 @@ asmlinkage int sys_pciconfig_read(unsigned long bus,
return err;
}
-
+
asmlinkage int sys_pciconfig_write(unsigned long bus,
unsigned long dfn,
unsigned long off,
@@ -936,7 +963,7 @@ static void pcic_disable_irq(unsigned int irq_nr)
mask = get_irqmask(irq_nr);
save_and_cli(flags);
- writel(mask, pcic->pcic_regs+PCI_SYS_INT_TARGET_MASK_SET);
+ writel(mask, pcic0.pcic_regs+PCI_SYS_INT_TARGET_MASK_SET);
restore_flags(flags);
}
@@ -946,7 +973,7 @@ static void pcic_enable_irq(unsigned int irq_nr)
mask = get_irqmask(irq_nr);
save_and_cli(flags);
- writel(mask, pcic->pcic_regs+PCI_SYS_INT_TARGET_MASK_CLEAR);
+ writel(mask, pcic0.pcic_regs+PCI_SYS_INT_TARGET_MASK_CLEAR);
restore_flags(flags);
}
@@ -965,12 +992,12 @@ static void pcic_load_profile_irq(int cpu, unsigned int limit)
*/
static void pcic_disable_pil_irq(unsigned int pil)
{
- writel(get_irqmask(pil), pcic->pcic_regs+PCI_SYS_INT_TARGET_MASK_SET);
+ writel(get_irqmask(pil), pcic0.pcic_regs+PCI_SYS_INT_TARGET_MASK_SET);
}
static void pcic_enable_pil_irq(unsigned int pil)
{
- writel(get_irqmask(pil), pcic->pcic_regs+PCI_SYS_INT_TARGET_MASK_CLEAR);
+ writel(get_irqmask(pil), pcic0.pcic_regs+PCI_SYS_INT_TARGET_MASK_CLEAR);
}
void __init sun4m_pci_init_IRQ(void)
@@ -985,8 +1012,9 @@ void __init sun4m_pci_init_IRQ(void)
BTFIXUPSET_CALL(__irq_itoa, pcic_irq_itoa, BTFIXUPCALL_NORM);
}
-void __init pcibios_fixup_bus(struct pci_bus *bus)
+int pcibios_assign_resource(struct pci_dev *pdev, int resource)
{
+ return -ENXIO;
}
#endif
diff --git a/arch/sparc/kernel/process.c b/arch/sparc/kernel/process.c
index 88db458e0..195f26df5 100644
--- a/arch/sparc/kernel/process.c
+++ b/arch/sparc/kernel/process.c
@@ -1,4 +1,4 @@
-/* $Id: process.c,v 1.139 1999/08/14 03:51:14 anton Exp $
+/* $Id: process.c,v 1.142 1999/12/27 06:08:31 anton Exp $
* linux/arch/sparc/kernel/process.c
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -33,6 +33,7 @@
#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/page.h>
+#include <asm/pgalloc.h>
#include <asm/pgtable.h>
#include <asm/delay.h>
#include <asm/processor.h>
@@ -55,7 +56,6 @@ int cpu_idle(void)
{
int ret = -EPERM;
- lock_kernel();
if (current->pid != 0)
goto out;
@@ -100,7 +100,6 @@ int cpu_idle(void)
}
ret = 0;
out:
- unlock_kernel();
return ret;
}
@@ -188,9 +187,7 @@ void show_regwindow(struct reg_window *rw)
rw->ins[4], rw->ins[5], rw->ins[6], rw->ins[7]);
}
-#ifdef __SMP__
static spinlock_t sparc_backtrace_lock = SPIN_LOCK_UNLOCKED;
-#endif
void __show_backtrace(unsigned long fp)
{
@@ -702,37 +699,3 @@ pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
"g1", "g2", "g3", "o0", "o1", "memory", "cc");
return retval;
}
-
-/*
- * These bracket the sleeping functions..
- */
-extern void scheduling_functions_start_here(void);
-extern void scheduling_functions_end_here(void);
-#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 pc, fp, bias = 0;
- unsigned long task_base = (unsigned long) p;
- struct reg_window *rw;
- int count = 0;
- if (!p || p == current || p->state == TASK_RUNNING)
- return 0;
-
- fp = p->thread.ksp + bias;
- do {
- /* Bogus frame pointer? */
- if (fp < (task_base + sizeof(struct task_struct)) ||
- fp >= (task_base + (2 * PAGE_SIZE)))
- break;
- rw = (struct reg_window *) fp;
- pc = rw->ins[7];
- if (pc < first_sched || pc >= last_sched)
- return pc;
- fp = rw->ins[6] + bias;
- } while (++count < 16);
- return 0;
-}
-#undef last_sched
-#undef first_sched
diff --git a/arch/sparc/kernel/semaphore.c b/arch/sparc/kernel/semaphore.c
index 2f2c8ecc7..1dcf35d42 100644
--- a/arch/sparc/kernel/semaphore.c
+++ b/arch/sparc/kernel/semaphore.c
@@ -1,5 +1,5 @@
-/* $Id: semaphore.c,v 1.1 1999/08/31 13:26:15 anton Exp $
- * Generic semaphore code. Buyer beware. Do your own
+/* $Id: semaphore.c,v 1.2 1999/12/28 11:50:37 jj Exp $
+ * Generic semaphore code. Buyer beware. Do your own
* specific changes in <asm/semaphore-helper.h>
*/
@@ -62,8 +62,7 @@ void __up(struct semaphore *sem)
#define DOWN_VAR \
struct task_struct *tsk = current; \
- wait_queue_t wait; \
- init_waitqueue_entry(&wait, tsk);
+ DECLARE_WAITQUEUE(wait, tsk);
#define DOWN_HEAD(task_state) \
\
@@ -127,3 +126,115 @@ int __down_trylock(struct semaphore * sem)
{
return waking_non_zero_trylock(sem);
}
+
+/* rw mutexes
+ * Implemented by Jakub Jelinek (jakub@redhat.com) based on
+ * i386 implementation by Ben LaHaise (bcrl@redhat.com).
+ */
+
+extern inline int ldstub(unsigned char *p)
+{
+ int ret;
+ asm volatile("ldstub %1, %0" : "=r" (ret) : "m" (*p) : "memory");
+ return ret;
+}
+
+void down_read_failed_biased(struct rw_semaphore *sem)
+{
+ DOWN_VAR
+
+ add_wait_queue(&sem->wait, &wait); /* put ourselves at the head of the list */
+
+ for (;;) {
+ if (!ldstub(&sem->read_not_granted))
+ break;
+ set_task_state(tsk, TASK_UNINTERRUPTIBLE);
+ if (sem->read_not_granted)
+ schedule();
+ }
+
+ remove_wait_queue(&sem->wait, &wait);
+ tsk->state = TASK_RUNNING;
+}
+
+void down_write_failed_biased(struct rw_semaphore *sem)
+{
+ DOWN_VAR
+
+ add_wait_queue_exclusive(&sem->write_bias_wait, &wait); /* put ourselves at the end of the list */
+
+ for (;;) {
+ if (!ldstub(&sem->write_not_granted))
+ break;
+ set_task_state(tsk, TASK_UNINTERRUPTIBLE | TASK_EXCLUSIVE);
+ if (sem->write_not_granted)
+ schedule();
+ }
+
+ remove_wait_queue(&sem->write_bias_wait, &wait);
+ tsk->state = TASK_RUNNING;
+
+ /* if the lock is currently unbiased, awaken the sleepers
+ * FIXME: this wakes up the readers early in a bit of a
+ * stampede -> bad!
+ */
+ if (sem->count >= 0)
+ wake_up(&sem->wait);
+}
+
+/* Wait for the lock to become unbiased. Readers
+ * are non-exclusive. =)
+ */
+void down_read_failed(struct rw_semaphore *sem)
+{
+ DOWN_VAR
+
+ __up_read(sem); /* this takes care of granting the lock */
+
+ add_wait_queue(&sem->wait, &wait);
+
+ while (sem->count < 0) {
+ set_task_state(tsk, TASK_UNINTERRUPTIBLE);
+ if (sem->count >= 0)
+ break;
+ schedule();
+ }
+
+ remove_wait_queue(&sem->wait, &wait);
+ tsk->state = TASK_RUNNING;
+}
+
+/* Wait for the lock to become unbiased. Since we're
+ * a writer, we'll make ourselves exclusive.
+ */
+void down_write_failed(struct rw_semaphore *sem)
+{
+ DOWN_VAR
+
+ __up_write(sem); /* this takes care of granting the lock */
+
+ add_wait_queue_exclusive(&sem->wait, &wait);
+
+ while (sem->count < 0) {
+ set_task_state(tsk, TASK_UNINTERRUPTIBLE | TASK_EXCLUSIVE);
+ if (sem->count >= 0)
+ break; /* we must attempt to aquire or bias the lock */
+ schedule();
+ }
+
+ remove_wait_queue(&sem->wait, &wait);
+ tsk->state = TASK_RUNNING;
+}
+
+void __rwsem_wake(struct rw_semaphore *sem, unsigned long readers)
+{
+ if (readers) {
+ /* Due to lame ldstub we don't do here
+ a BUG() consistency check */
+ sem->read_not_granted = 0;
+ wake_up(&sem->wait);
+ } else {
+ sem->write_not_granted = 0;
+ wake_up(&sem->write_bias_wait);
+ }
+}
diff --git a/arch/sparc/kernel/setup.c b/arch/sparc/kernel/setup.c
index c812e1b5f..60928d7aa 100644
--- a/arch/sparc/kernel/setup.c
+++ b/arch/sparc/kernel/setup.c
@@ -1,4 +1,4 @@
-/* $Id: setup.c,v 1.111 1999/09/10 10:40:24 davem Exp $
+/* $Id: setup.c,v 1.113 1999/12/16 14:37:35 anton Exp $
* linux/arch/sparc/kernel/setup.c
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -124,7 +124,9 @@ unsigned int boot_flags;
#ifdef CONFIG_SUN_CONSOLE
static int console_fb = 0;
#endif
-static unsigned long memory_size __initdata = 0;
+
+/* Exported for mm/init.c:paging_init. */
+unsigned long cmdline_memory_size __initdata = 0;
void kernel_enter_debugger(void)
{
@@ -238,13 +240,13 @@ static void __init boot_flags_init(char *commands)
* "mem=XXX[kKmM] overrides the PROM-reported
* memory size.
*/
- memory_size = simple_strtoul(commands + 4,
+ cmdline_memory_size = simple_strtoul(commands + 4,
&commands, 0);
if (*commands == 'K' || *commands == 'k') {
- memory_size <<= 10;
+ cmdline_memory_size <<= 10;
commands++;
} else if (*commands=='M' || *commands=='m') {
- memory_size <<= 20;
+ cmdline_memory_size <<= 20;
commands++;
}
}
@@ -266,7 +268,7 @@ extern char cputypval;
extern unsigned long start, end;
extern void panic_setup(char *, int *);
extern void srmmu_end_memory(unsigned long, unsigned long *);
-extern unsigned long sun_serial_setup(unsigned long);
+extern void sun_serial_setup(void);
extern unsigned short root_flags;
extern unsigned short root_dev;
@@ -297,10 +299,10 @@ static struct console prom_console = {
"PROM", prom_cons_write, 0, 0, 0, 0, 0, CON_PRINTBUFFER, 0, 0, 0
};
-void __init setup_arch(char **cmdline_p,
- unsigned long * memory_start_p, unsigned long * memory_end_p)
+void __init setup_arch(char **cmdline_p)
{
- int total, i, packed;
+ int i;
+ unsigned long highest_paddr;
sparc_ttable = (struct tt_entry *) &start;
@@ -329,27 +331,21 @@ void __init setup_arch(char **cmdline_p,
strcpy(&cputypval, "ap+");
#endif
printk("ARCH: ");
- packed = 0;
switch(sparc_cpu_model) {
case sun4:
printk("SUN4\n");
- packed = 0;
break;
case sun4c:
printk("SUN4C\n");
- packed = 0;
break;
case sun4m:
printk("SUN4M\n");
- packed = 1;
break;
case sun4d:
printk("SUN4D\n");
- packed = 1;
break;
case sun4e:
printk("SUN4E\n");
- packed = 0;
break;
case sun4u:
printk("SUN4U\n");
@@ -357,7 +353,6 @@ void __init setup_arch(char **cmdline_p,
case ap1000:
register_console(&prom_console);
printk("AP1000\n");
- packed = 1;
break;
default:
printk("UNKNOWN!\n");
@@ -375,26 +370,20 @@ void __init setup_arch(char **cmdline_p,
if (ARCH_SUN4C_SUN4)
sun4c_probe_vac();
load_mmu();
- total = prom_probe_memory();
- *memory_start_p = PAGE_ALIGN(((unsigned long) &end));
-
- if(!packed) {
- for(i=0; sp_banks[i].num_bytes != 0; i++) {
- end_of_phys_memory = sp_banks[i].base_addr +
- sp_banks[i].num_bytes;
- if (memory_size) {
- if (end_of_phys_memory > memory_size) {
- sp_banks[i].num_bytes -=
- (end_of_phys_memory - memory_size);
- end_of_phys_memory = memory_size;
- sp_banks[++i].base_addr = 0xdeadbeef;
- sp_banks[i].num_bytes = 0;
- }
- }
- }
- *memory_end_p = (end_of_phys_memory + KERNBASE);
- } else
- srmmu_end_memory(memory_size, memory_end_p);
+ (void) prom_probe_memory();
+
+ phys_base = 0xffffffffUL;
+ highest_paddr = 0UL;
+ for (i = 0; sp_banks[i].num_bytes != 0; i++) {
+ unsigned long top;
+
+ if (sp_banks[i].base_addr < phys_base)
+ phys_base = sp_banks[i].base_addr;
+ top = sp_banks[i].base_addr +
+ sp_banks[i].num_bytes;
+ if (highest_paddr < top)
+ highest_paddr = top;
+ }
if (!root_flags)
root_mountflags &= ~MS_RDONLY;
@@ -405,6 +394,7 @@ void __init setup_arch(char **cmdline_p,
rd_doload = ((ram_flags & RAMDISK_LOAD_FLAG) != 0);
#endif
#ifdef CONFIG_BLK_DEV_INITRD
+// FIXME needs to do the new bootmem alloc stuff
if (sparc_ramdisk_image) {
initrd_start = sparc_ramdisk_image;
if (initrd_start < KERNBASE) initrd_start += KERNBASE;
@@ -434,7 +424,10 @@ void __init setup_arch(char **cmdline_p,
prom_setsync(prom_sync_me);
#ifdef CONFIG_SUN_SERIAL
- *memory_start_p = sun_serial_setup(*memory_start_p); /* set this up ASAP */
+#if 0
+ /* XXX We can't do this until the bootmem allocator is working. */
+ sun_serial_setup(); /* set this up ASAP */
+#endif
#endif
{
#if !CONFIG_SUN_SERIAL
@@ -489,11 +482,10 @@ void __init setup_arch(char **cmdline_p,
breakpoint();
}
-
/* Due to stack alignment restrictions and assumptions... */
init_mm.mmap->vm_page_prot = PAGE_SHARED;
- init_mm.mmap->vm_start = KERNBASE;
- init_mm.mmap->vm_end = *memory_end_p;
+ init_mm.mmap->vm_start = PAGE_OFFSET;
+ init_mm.mmap->vm_end = PAGE_OFFSET + highest_paddr;
init_mm.context = (unsigned long) NO_CONTEXT;
init_task.thread.kregs = &fake_swapper_regs;
diff --git a/arch/sparc/kernel/signal.c b/arch/sparc/kernel/signal.c
index f2065d20e..ea0c7e1ff 100644
--- a/arch/sparc/kernel/signal.c
+++ b/arch/sparc/kernel/signal.c
@@ -1,4 +1,4 @@
-/* $Id: signal.c,v 1.95 1999/08/14 03:51:22 anton Exp $
+/* $Id: signal.c,v 1.99 1999/12/27 06:08:32 anton Exp $
* linux/arch/sparc/kernel/signal.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
@@ -22,6 +22,7 @@
#include <asm/bitops.h>
#include <asm/ptrace.h>
#include <asm/svr4.h>
+#include <asm/pgalloc.h>
#include <asm/pgtable.h>
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
diff --git a/arch/sparc/kernel/smp.c b/arch/sparc/kernel/smp.c
index e611cd828..58f1be4e8 100644
--- a/arch/sparc/kernel/smp.c
+++ b/arch/sparc/kernel/smp.c
@@ -22,6 +22,7 @@
#include <asm/delay.h>
#include <asm/irq.h>
#include <asm/page.h>
+#include <asm/pgalloc.h>
#include <asm/pgtable.h>
#include <asm/oplib.h>
#include <asm/atops.h>
@@ -163,7 +164,7 @@ void smp_flush_tlb_mm(struct mm_struct *mm)
local_flush_tlb_mm(mm);
} else {
xc1((smpfunc_t) BTFIXUP_CALL(local_flush_tlb_mm), (unsigned long) mm);
- if(atomic_read(&mm->count) == 1 && current->mm == mm)
+ if(atomic_read(&mm->mm_users) == 1 && current->active_mm == mm)
mm->cpu_vm_mask = (1 << smp_processor_id());
}
}
diff --git a/arch/sparc/kernel/sparc-stub.c b/arch/sparc/kernel/sparc-stub.c
index 8cd0e8b6d..c9bb60a86 100644
--- a/arch/sparc/kernel/sparc-stub.c
+++ b/arch/sparc/kernel/sparc-stub.c
@@ -1,4 +1,4 @@
-/* $Id: sparc-stub.c,v 1.25 1999/07/23 01:56:13 davem Exp $
+/* $Id: sparc-stub.c,v 1.26 1999/12/27 06:08:34 anton Exp $
* sparc-stub.c: KGDB support for the Linux kernel.
*
* Modifications to run under Linux
@@ -107,6 +107,7 @@
#include <asm/traps.h>
#include <asm/vac-ops.h>
#include <asm/kgdb.h>
+#include <asm/pgalloc.h>
#include <asm/pgtable.h>
/*
*
diff --git a/arch/sparc/kernel/sparc_ksyms.c b/arch/sparc/kernel/sparc_ksyms.c
index 95c5e37be..0c955178f 100644
--- a/arch/sparc/kernel/sparc_ksyms.c
+++ b/arch/sparc/kernel/sparc_ksyms.c
@@ -1,4 +1,4 @@
-/* $Id: sparc_ksyms.c,v 1.79 1999/09/10 10:40:28 davem Exp $
+/* $Id: sparc_ksyms.c,v 1.84 2000/01/07 18:15:14 jj Exp $
* arch/sparc/kernel/ksyms.c: Sparc specific ksyms support.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -50,8 +50,6 @@ struct poll {
extern int svr4_getcontext (svr4_ucontext_t *, struct pt_regs *);
extern int svr4_setcontext (svr4_ucontext_t *, struct pt_regs *);
-extern unsigned long sunos_mmap(unsigned long, unsigned long, unsigned long,
- unsigned long, unsigned long, unsigned long);
void _sigpause_common (unsigned int set, struct pt_regs *);
extern void (*__copy_1page)(void *, const void *);
extern void __memmove(void *, const void *, __kernel_size_t);
@@ -65,6 +63,7 @@ extern char saved_command_line[];
extern void bcopy (const char *, char *, int);
extern int __ashrdi3(int, int);
+extern int __ashldi3(int, int);
extern int __lshrdi3(int, int);
extern void dump_thread(struct pt_regs *, struct user *);
@@ -118,6 +117,12 @@ EXPORT_SYMBOL_PRIVATE(_global_cli);
#endif
#endif
+/* rw semaphores */
+EXPORT_SYMBOL_NOVERS(___down_read);
+EXPORT_SYMBOL_NOVERS(___down_write);
+EXPORT_SYMBOL_NOVERS(___up_read);
+EXPORT_SYMBOL_NOVERS(___up_write);
+
EXPORT_SYMBOL(page_offset);
EXPORT_SYMBOL(sparc_valid_addr_bitmap);
@@ -157,11 +162,10 @@ EXPORT_SYMBOL(mstk48t02_regs);
EXPORT_SYMBOL(auxio_register);
#endif
EXPORT_SYMBOL(request_fast_irq);
-EXPORT_SYMBOL(sparc_alloc_io);
-EXPORT_SYMBOL(sparc_free_io);
EXPORT_SYMBOL(io_remap_page_range);
-EXPORT_SYMBOL(iounit_map_dma_init);
-EXPORT_SYMBOL(iounit_map_dma_page);
+ /* P3: iounit_xxx may be needed, sun4d users */
+/* EXPORT_SYMBOL(iounit_map_dma_init); */
+/* EXPORT_SYMBOL(iounit_map_dma_page); */
/* Btfixup stuff cannot have versions, it would be complicated too much */
#ifndef __SMP__
@@ -180,19 +184,27 @@ EXPORT_SYMBOL_NOVERS(BTFIXUP_CALL(mmu_get_scsi_one));
EXPORT_SYMBOL_NOVERS(BTFIXUP_CALL(mmu_release_scsi_sgl));
EXPORT_SYMBOL_NOVERS(BTFIXUP_CALL(mmu_release_scsi_one));
-EXPORT_SYMBOL(_sparc_dvma_malloc);
-EXPORT_SYMBOL(sun4c_unmapioaddr);
-EXPORT_SYMBOL(srmmu_unmapioaddr);
#if CONFIG_SBUS
-EXPORT_SYMBOL(SBus_chain);
+EXPORT_SYMBOL(sbus_root);
EXPORT_SYMBOL(dma_chain);
+EXPORT_SYMBOL(sbus_set_sbus64);
+EXPORT_SYMBOL(sbus_alloc_consistant);
+EXPORT_SYMBOL(sbus_free_consistant);
+EXPORT_SYMBOL(sbus_map_single);
+EXPORT_SYMBOL(sbus_unmap_single);
+EXPORT_SYMBOL(sbus_map_sg);
+EXPORT_SYMBOL(sbus_unmap_sg);
+EXPORT_SYMBOL(sbus_dma_sync_single);
+EXPORT_SYMBOL(sbus_dma_sync_sg);
+#endif
+#if CONFIG_PCI
+/* We do not have modular drivers for PCI devices yet. */
#endif
/* Solaris/SunOS binary compatibility */
EXPORT_SYMBOL(svr4_setcontext);
EXPORT_SYMBOL(svr4_getcontext);
EXPORT_SYMBOL(_sigpause_common);
-EXPORT_SYMBOL(sunos_mmap);
/* Should really be in linux/kernel/ksyms.c */
EXPORT_SYMBOL(dump_thread);
@@ -215,9 +227,9 @@ EXPORT_SYMBOL(prom_getname);
EXPORT_SYMBOL(prom_feval);
EXPORT_SYMBOL(prom_getbool);
EXPORT_SYMBOL(prom_getstring);
-EXPORT_SYMBOL(prom_apply_sbus_ranges);
EXPORT_SYMBOL(prom_getint);
EXPORT_SYMBOL(prom_getintdefault);
+EXPORT_SYMBOL(prom_finddevice);
EXPORT_SYMBOL(romvec);
EXPORT_SYMBOL(__prom_getchild);
EXPORT_SYMBOL(__prom_getsibling);
@@ -271,6 +283,7 @@ EXPORT_SYMBOL_NOVERS(memcpy);
EXPORT_SYMBOL_NOVERS(memset);
EXPORT_SYMBOL_NOVERS(memmove);
EXPORT_SYMBOL_NOVERS(__ashrdi3);
+EXPORT_SYMBOL_NOVERS(__ashldi3);
EXPORT_SYMBOL_NOVERS(__lshrdi3);
EXPORT_SYMBOL_DOT(rem);
@@ -279,5 +292,3 @@ EXPORT_SYMBOL_DOT(mul);
EXPORT_SYMBOL_DOT(umul);
EXPORT_SYMBOL_DOT(div);
EXPORT_SYMBOL_DOT(udiv);
-
-EXPORT_SYMBOL(get_wchan);
diff --git a/arch/sparc/kernel/sun4c_irq.c b/arch/sparc/kernel/sun4c_irq.c
index e954c2ec1..a8efdd12a 100644
--- a/arch/sparc/kernel/sun4c_irq.c
+++ b/arch/sparc/kernel/sun4c_irq.c
@@ -35,6 +35,11 @@
#include <asm/idprom.h>
#include <asm/machines.h>
+#if 0
+static struct resource sun4c_timer_eb = { "sun4c_timer" };
+static struct resource sun4c_intr_eb = { "sun4c_intr" };
+#endif
+
/* Pointer to the interrupt enable byte
*
* Dave Redman (djhr@tadpole.co.uk)
@@ -150,10 +155,9 @@ static void __init sun4c_init_timers(void (*counter_fn)(int, void *, struct pt_r
sun4c_timers = &sun4_timer;
else
#endif
- sun4c_timers = sparc_alloc_io (SUN_TIMER_PHYSADDR, 0,
- sizeof(struct sun4c_timer_info),
- "timer", 0x0, 0x0);
-
+ sun4c_timers = ioremap(SUN_TIMER_PHYSADDR,
+ sizeof(struct sun4c_timer_info));
+
/* Have the level 10 timer tick at 100HZ. We don't touch the
* level 14 timer limit since we are letting the prom handle
* them until we have a real console driver so L1-A works.
@@ -190,13 +194,11 @@ void __init sun4c_init_IRQ(void)
int ie_node;
if (ARCH_SUN4) {
- interrupt_enable =
- (char *) sparc_alloc_io(sun4_ie_physaddr, 0,
- PAGE_SIZE,
- "sun4c_interrupts",
- 0x0, 0x0);
+ interrupt_enable = (char *)
+ ioremap(sun4_ie_physaddr, PAGE_SIZE);
} else {
-
+ struct resource phyres;
+
ie_node = prom_searchsiblings (prom_getchild(prom_root_node),
"interrupt-enable");
if(ie_node == 0)
@@ -204,11 +206,11 @@ void __init sun4c_init_IRQ(void)
/* Depending on the "address" property is bad news... */
prom_getproperty(ie_node, "reg", (char *) int_regs, sizeof(int_regs));
- interrupt_enable =
- (char *) sparc_alloc_io(int_regs[0].phys_addr, 0,
- int_regs[0].reg_size,
- "sun4c_interrupts",
- int_regs[0].which_io, 0x0);
+ memset(&phyres, 0, sizeof(struct resource));
+ phyres.flags = int_regs[0].which_io;
+ phyres.start = int_regs[0].phys_addr;
+ interrupt_enable = (char *) sbus_ioremap(&phyres, 0,
+ int_regs[0].reg_size, "sun4c_intr");
}
BTFIXUPSET_CALL(enable_irq, sun4c_enable_irq, BTFIXUPCALL_NORM);
diff --git a/arch/sparc/kernel/sun4d_irq.c b/arch/sparc/kernel/sun4d_irq.c
index 9b9112d4c..dbbb4edca 100644
--- a/arch/sparc/kernel/sun4d_irq.c
+++ b/arch/sparc/kernel/sun4d_irq.c
@@ -1,4 +1,4 @@
-/* $Id: sun4d_irq.c,v 1.20 1999/09/10 10:40:30 davem Exp $
+/* $Id: sun4d_irq.c,v 1.24 1999/12/27 06:08:34 anton Exp $
* arch/sparc/kernel/sun4d_irq.c:
* SS1000/SC2000 interrupt handling.
*
@@ -32,6 +32,7 @@
#include <asm/traps.h>
#include <asm/irq.h>
#include <asm/io.h>
+#include <asm/pgalloc.h>
#include <asm/pgtable.h>
#include <asm/sbus.h>
#include <asm/sbi.h>
@@ -237,12 +238,12 @@ void sun4d_handler_irq(int irq, struct pt_regs * regs)
irq_exit(cpu, irq);
}
-unsigned int sun4d_build_irq(struct linux_sbus_device *sdev, int irq)
+unsigned int sun4d_build_irq(struct sbus_dev *sdev, int irq)
{
int sbusl = pil_to_sbus[irq];
-
+
if (sbusl)
- return ((sdev->my_bus->board + 1) << 5) + (sbusl << 2) + sdev->slot;
+ return ((sdev->bus->board + 1) << 5) + (sbusl << 2) + sdev->slot;
else
return irq;
}
@@ -369,7 +370,7 @@ static void sun4d_set_udt(int cpu)
void __init sun4d_distribute_irqs(void)
{
#ifdef DISTRIBUTE_IRQS
- struct linux_sbus *sbus;
+ struct sbus_bus *sbus;
unsigned long sbus_serving_map;
sbus_serving_map = cpu_present_map;
@@ -401,7 +402,7 @@ void __init sun4d_distribute_irqs(void)
set_sbi_tid(sbus->devid, sbus_tid[sbus->board] << 3);
}
#else
- struct linux_sbus *sbus;
+ struct sbus_bus *sbus;
int cpuid = cpu_logical_map(1);
if (cpuid == -1)
@@ -436,16 +437,19 @@ static void __init sun4d_init_timers(void (*counter_fn)(int, void *, struct pt_r
int irq;
extern struct prom_cpuinfo linux_cpus[NR_CPUS];
int cpu;
+ struct resource r;
/* Map the User Timer registers. */
+ memset(&r, 0, sizeof(r));
#ifdef __SMP__
- sun4d_timers = sparc_alloc_io(CSR_BASE(boot_cpu_id)+BW_TIMER_LIMIT, 0,
- PAGE_SIZE, "user timer", 0xf, 0x0);
+ r.start = CSR_BASE(boot_cpu_id)+BW_TIMER_LIMIT;
#else
- sun4d_timers = sparc_alloc_io(CSR_BASE(0)+BW_TIMER_LIMIT, 0,
- PAGE_SIZE, "user timer", 0xf, 0x0);
+ r.start = CSR_BASE(0)+BW_TIMER_LIMIT;
#endif
-
+ r.flags = 0xf;
+ sun4d_timers = (struct sun4d_timer_regs *) sbus_ioremap(&r, 0,
+ PAGE_SIZE, "user timer");
+
sun4d_timers->l10_timer_limit = (((1000000/HZ) + 1) << 10);
master_l10_counter = &sun4d_timers->l10_cur_count;
master_l10_limit = &sun4d_timers->l10_timer_limit;
@@ -494,7 +498,7 @@ static void __init sun4d_init_timers(void (*counter_fn)(int, void *, struct pt_r
void __init sun4d_init_sbi_irq(void)
{
- struct linux_sbus *sbus;
+ struct sbus_bus *sbus;
unsigned mask;
nsbi = 0;
diff --git a/arch/sparc/kernel/sun4d_smp.c b/arch/sparc/kernel/sun4d_smp.c
index b52cd08a8..ec105ec18 100644
--- a/arch/sparc/kernel/sun4d_smp.c
+++ b/arch/sparc/kernel/sun4d_smp.c
@@ -25,6 +25,7 @@
#include <asm/delay.h>
#include <asm/irq.h>
#include <asm/page.h>
+#include <asm/pgalloc.h>
#include <asm/pgtable.h>
#include <asm/oplib.h>
#include <asm/atops.h>
@@ -99,6 +100,14 @@ void __init smp4d_callin(void)
local_flush_cache_all();
local_flush_tlb_all();
+ /*
+ * Unblock the master CPU _only_ when the scheduler state
+ * of all secondary CPUs will be up-to-date, so after
+ * the SMP initialization the master will be just allowed
+ * to call the scheduler code.
+ */
+ init_idle();
+
/* Get our local ticker going. */
smp_setup_percpu_timer();
diff --git a/arch/sparc/kernel/sun4m_irq.c b/arch/sparc/kernel/sun4m_irq.c
index 3f2959f16..0f3cf9564 100644
--- a/arch/sparc/kernel/sun4m_irq.c
+++ b/arch/sparc/kernel/sun4m_irq.c
@@ -19,6 +19,7 @@
#include <linux/interrupt.h>
#include <linux/malloc.h>
#include <linux/init.h>
+#include <linux/ioport.h>
#include <asm/ptrace.h>
#include <asm/processor.h>
@@ -29,6 +30,7 @@
#include <asm/openprom.h>
#include <asm/oplib.h>
#include <asm/traps.h>
+#include <asm/pgalloc.h>
#include <asm/pgtable.h>
#include <asm/smp.h>
#include <asm/irq.h>
@@ -225,6 +227,7 @@ static void __init sun4m_init_timers(void (*counter_fn)(int, void *, struct pt_r
int reg_count, irq, cpu;
struct linux_prom_registers cnt_regs[PROMREG_MAX];
int obio_node, cnt_node;
+ struct resource r;
cnt_node = 0;
if((obio_node =
@@ -250,18 +253,19 @@ static void __init sun4m_init_timers(void (*counter_fn)(int, void *, struct pt_r
cnt_regs[obio_node].reg_size = cnt_regs[obio_node-1].reg_size;
cnt_regs[obio_node].which_io = cnt_regs[obio_node-1].which_io;
}
-
+
+ memset((char*)&r, 0, sizeof(struct resource));
/* Map the per-cpu Counter registers. */
- sun4m_timers = sparc_alloc_io(cnt_regs[0].phys_addr, 0,
- PAGE_SIZE*SUN4M_NCPUS, "counters_percpu",
- cnt_regs[0].which_io, 0x0);
-
+ r.flags = cnt_regs[0].which_io;
+ r.start = cnt_regs[0].phys_addr;
+ sun4m_timers = (struct sun4m_timer_regs *) sbus_ioremap(&r, 0,
+ PAGE_SIZE*SUN4M_NCPUS, "sun4m_cpu_cnt");
/* Map the system Counter register. */
- sparc_alloc_io(cnt_regs[4].phys_addr, 0,
- cnt_regs[4].reg_size,
- "counters_system",
- cnt_regs[4].which_io, 0x0);
-
+ /* XXX Here we expect consequent calls to yeld adjusent maps. */
+ r.flags = cnt_regs[4].which_io;
+ r.start = cnt_regs[4].phys_addr;
+ sbus_ioremap(&r, 0, cnt_regs[4].reg_size, "sun4m_sys_cnt");
+
sun4m_timers->l10_timer_limit = (((1000000/HZ) + 1) << 10);
master_l10_counter = &sun4m_timers->l10_cur_count;
master_l10_limit = &sun4m_timers->l10_timer_limit;
@@ -308,6 +312,7 @@ void __init sun4m_init_IRQ(void)
int ie_node,i;
struct linux_prom_registers int_regs[PROMREG_MAX];
int num_regs;
+ struct resource r;
__cli();
if((ie_node = prom_searchsiblings(prom_getchild(prom_root_node), "obio")) == 0 ||
@@ -332,16 +337,18 @@ void __init sun4m_init_IRQ(void)
int_regs[ie_node].which_io = int_regs[ie_node-1].which_io;
}
+ memset((char *)&r, 0, sizeof(struct resource));
/* Map the interrupt registers for all possible cpus. */
- sun4m_interrupts = sparc_alloc_io(int_regs[0].phys_addr, 0,
- PAGE_SIZE*SUN4M_NCPUS, "interrupts_percpu",
- int_regs[0].which_io, 0x0);
-
+ r.flags = int_regs[0].which_io;
+ r.start = int_regs[0].phys_addr;
+ sun4m_interrupts = (struct sun4m_intregs *) sbus_ioremap(&r, 0,
+ PAGE_SIZE*SUN4M_NCPUS, "interrupts_percpu");
+
/* Map the system interrupt control registers. */
- sparc_alloc_io(int_regs[4].phys_addr, 0,
- int_regs[4].reg_size, "interrupts_system",
- int_regs[4].which_io, 0x0);
-
+ r.flags = int_regs[4].which_io;
+ r.start = int_regs[4].phys_addr;
+ sbus_ioremap(&r, 0, int_regs[4].reg_size, "interrupts_system");
+
sun4m_interrupts->set = ~SUN4M_INT_MASKALL;
for (i=0; i<linux_num_cpus; i++)
sun4m_interrupts->cpu_intregs[i].clear = ~0x17fff;
diff --git a/arch/sparc/kernel/sun4m_smp.c b/arch/sparc/kernel/sun4m_smp.c
index b9990ce0d..2d2d97810 100644
--- a/arch/sparc/kernel/sun4m_smp.c
+++ b/arch/sparc/kernel/sun4m_smp.c
@@ -21,6 +21,7 @@
#include <asm/delay.h>
#include <asm/irq.h>
#include <asm/page.h>
+#include <asm/pgalloc.h>
#include <asm/pgtable.h>
#include <asm/oplib.h>
#include <asm/atops.h>
@@ -93,6 +94,14 @@ void __init smp4m_callin(void)
local_flush_cache_all();
local_flush_tlb_all();
+ /*
+ * Unblock the master CPU _only_ when the scheduler state
+ * of all secondary CPUs will be up-to-date, so after
+ * the SMP initialization the master will be just allowed
+ * to call the scheduler code.
+ */
+ init_idle();
+
/* Allow master to continue. */
swap((unsigned long *)&cpu_callin_map[cpuid], 1);
local_flush_cache_all();
diff --git a/arch/sparc/kernel/sys_solaris.c b/arch/sparc/kernel/sys_solaris.c
index 6bef6e523..6c46c60f0 100644
--- a/arch/sparc/kernel/sys_solaris.c
+++ b/arch/sparc/kernel/sys_solaris.c
@@ -4,6 +4,7 @@
* Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
*/
+#include <linux/config.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/string.h>
@@ -24,7 +25,7 @@ do_solaris_syscall (struct pt_regs *regs)
current->exec_domain = lookup_exec_domain(PER_SVR4);
if (current->exec_domain && current->exec_domain->handler){
- current->exec_domain->handler (regs);
+ current->exec_domain->handler (0, regs);
/* What is going on here? Why do we do this? */
@@ -39,3 +40,16 @@ do_solaris_syscall (struct pt_regs *regs)
unlock_kernel();
return ret;
}
+
+#ifndef CONFIG_SUNOS_EMUL
+asmlinkage int
+do_sunos_syscall (struct pt_regs *regs)
+{
+ static int cnt = 0;
+ if (++cnt < 10) printk ("SunOS binary emulation not compiled in\n");
+ lock_kernel();
+ force_sig (SIGSEGV, current);
+ unlock_kernel();
+ return 0;
+}
+#endif
diff --git a/arch/sparc/kernel/sys_sparc.c b/arch/sparc/kernel/sys_sparc.c
index f946b36a2..69379de4a 100644
--- a/arch/sparc/kernel/sys_sparc.c
+++ b/arch/sparc/kernel/sys_sparc.c
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc.c,v 1.53 1999/08/14 03:51:25 anton Exp $
+/* $Id: sys_sparc.c,v 1.56 2000/01/04 11:01:26 jj Exp $
* linux/arch/sparc/kernel/sys_sparc.c
*
* This file contains various random system calls that
@@ -176,26 +176,34 @@ out:
}
/* Linux version of mmap */
-asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len,
+static unsigned long do_mmap2(unsigned long addr, unsigned long len,
unsigned long prot, unsigned long flags, unsigned long fd,
- unsigned long off)
+ unsigned long pgoff)
{
struct file * file = NULL;
unsigned long retval = -EBADF;
- down(&current->mm->mmap_sem);
- lock_kernel();
if (!(flags & MAP_ANONYMOUS)) {
file = fget(fd);
if (!file)
goto out;
}
+
+ down(&current->mm->mmap_sem);
+ lock_kernel();
retval = -ENOMEM;
len = PAGE_ALIGN(len);
- if(!(flags & MAP_FIXED) && !addr) {
- addr = get_unmapped_area(addr, len);
+ if(!(flags & MAP_FIXED) &&
+ (!addr || (ARCH_SUN4C_SUN4 &&
+ (addr >= 0x20000000 && addr < 0xe0000000)))) {
+ addr = get_unmapped_area(0, len);
if(!addr)
goto out_putf;
+ if (ARCH_SUN4C_SUN4 &&
+ (addr >= 0x20000000 && addr < 0xe0000000)) {
+ retval = -EINVAL;
+ goto out_putf;
+ }
}
/* See asm-sparc/uaccess.h */
@@ -203,26 +211,34 @@ asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len,
if((len > (TASK_SIZE - PAGE_SIZE)) || (addr > (TASK_SIZE-len-PAGE_SIZE)))
goto out_putf;
- if(ARCH_SUN4C_SUN4) {
- if(((addr >= 0x20000000) && (addr < 0xe0000000))) {
- /* VM hole */
- retval = current->mm->brk;
- goto out_putf;
- }
- }
-
flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
- retval = do_mmap(file, addr, len, prot, flags, off);
+ retval = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
out_putf:
+ unlock_kernel();
+ up(&current->mm->mmap_sem);
if (file)
fput(file);
out:
- unlock_kernel();
- up(&current->mm->mmap_sem);
return retval;
}
+asmlinkage unsigned long sys_mmap2(unsigned long addr, unsigned long len,
+ unsigned long prot, unsigned long flags, unsigned long fd,
+ unsigned long pgoff)
+{
+ /* Make sure the shift for mmap2 is constant (12), no matter what PAGE_SIZE
+ we have. */
+ return do_mmap2(addr, len, prot, flags, fd, pgoff >> (PAGE_SHIFT - 12));
+}
+
+asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len,
+ unsigned long prot, unsigned long flags, unsigned long fd,
+ unsigned long off)
+{
+ return do_mmap2(addr, len, prot, flags, fd, off >> PAGE_SHIFT);
+}
+
/* we come to here via sys_nis_syscall so it can setup the regs argument */
asmlinkage unsigned long
c_sys_nis_syscall (struct pt_regs *regs)
diff --git a/arch/sparc/kernel/sys_sunos.c b/arch/sparc/kernel/sys_sunos.c
index 56075e512..ddac348fe 100644
--- a/arch/sparc/kernel/sys_sunos.c
+++ b/arch/sparc/kernel/sys_sunos.c
@@ -1,4 +1,4 @@
-/* $Id: sys_sunos.c,v 1.104 1999/08/31 12:30:50 anton Exp $
+/* $Id: sys_sunos.c,v 1.108 2000/01/06 23:51:46 davem Exp $
* sys_sunos.c: SunOS specific syscall compatibility support.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -85,10 +85,17 @@ asmlinkage unsigned long sunos_mmap(unsigned long addr, unsigned long len,
}
retval = -ENOMEM;
- if(!(flags & MAP_FIXED) && !addr) {
- addr = get_unmapped_area(addr, len);
+ if(!(flags & MAP_FIXED) &&
+ (!addr || (ARCH_SUN4C_SUN4 &&
+ (addr >= 0x20000000 && addr < 0xe0000000)))) {
+ addr = get_unmapped_area(0, len);
if(!addr)
goto out_putf;
+ if (ARCH_SUN4C_SUN4 &&
+ (addr >= 0x20000000 && addr < 0xe0000000)) {
+ retval = -EINVAL;
+ goto out_putf;
+ }
}
/* If this is ld.so or a shared library doing an mmap
* of /dev/zero, transform it into an anonymous mapping.
@@ -111,13 +118,6 @@ asmlinkage unsigned long sunos_mmap(unsigned long addr, unsigned long len,
if((len > (TASK_SIZE - PAGE_SIZE)) || (addr > (TASK_SIZE-len-PAGE_SIZE)))
goto out_putf;
- if(ARCH_SUN4C_SUN4) {
- if(((addr >= 0x20000000) && (addr < 0xe0000000))) {
- retval = current->mm->brk;
- goto out_putf;
- }
- }
-
flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
retval = do_mmap(file, addr, len, prot, flags, off);
if(!ret_type)
@@ -195,10 +195,10 @@ asmlinkage int sunos_brk(unsigned long brk)
* simple, it hopefully works in most obvious cases.. Easy to
* fool it, but this should catch most mistakes.
*/
- freepages = atomic_read(&buffermem) >> PAGE_SHIFT;
+ freepages = atomic_read(&buffermem_pages) >> PAGE_SHIFT;
freepages += atomic_read(&page_cache_size);
freepages >>= 1;
- freepages += nr_free_pages;
+ freepages += nr_free_pages();
freepages += nr_swap_pages;
freepages -= num_physpages >> 4;
freepages -= (newbrk-oldbrk) >> PAGE_SHIFT;
@@ -721,7 +721,7 @@ struct sunos_nfs_mount_args {
};
-extern int do_mount(kdev_t, const char *, const char *, char *, int, void *);
+extern int do_mount(struct block_device *, const char *, const char *, char *, int, void *);
extern dev_t get_unnamed_dev(void);
extern void put_unnamed_dev(dev_t);
extern asmlinkage int sys_mount(char *, char *, char *, unsigned long, void *);
@@ -797,7 +797,6 @@ asmlinkage int sunos_nfs_mount(char *dir_name, int linux_flags, void *data)
char *the_name;
struct nfs_mount_data linux_nfs_mount;
struct sunos_nfs_mount_args *sunos_mount = data;
- dev_t dev;
/* Ok, here comes the fun part: Linux's nfs mount needs a
* socket connection to the server, but SunOS mount does not
@@ -839,13 +838,7 @@ asmlinkage int sunos_nfs_mount(char *dir_name, int linux_flags, void *data)
linux_nfs_mount.hostname [255] = 0;
putname (the_name);
- dev = get_unnamed_dev ();
-
- ret = do_mount (dev, "", dir_name, "nfs", linux_flags, &linux_nfs_mount);
- if (ret)
- put_unnamed_dev(dev);
-
- return ret;
+ return do_mount (NULL, "", dir_name, "nfs", linux_flags, &linux_nfs_mount);
}
asmlinkage int
diff --git a/arch/sparc/kernel/systbls.S b/arch/sparc/kernel/systbls.S
index 97e7df77b..d4be69030 100644
--- a/arch/sparc/kernel/systbls.S
+++ b/arch/sparc/kernel/systbls.S
@@ -1,4 +1,4 @@
-/* $Id: systbls.S,v 1.84 1999/08/14 03:51:29 anton Exp $
+/* $Id: systbls.S,v 1.88 1999/12/21 14:09:06 jj Exp $
* systbls.S: System call entry point tables for OS compatibility.
* The native Linux system call table lives here also.
*
@@ -9,6 +9,8 @@
* Copyright (C) 1995 Adrian M. Rodriguez (adrian@remus.rutgers.edu)
*/
+#include <linux/config.h>
+
.data
.align 4
@@ -27,12 +29,12 @@ sys_call_table:
/*40*/ .long sys_newlstat, sys_dup, sys_pipe, sys_times, sys_nis_syscall
/*45*/ .long sys_umount, sys_setgid, sys_getgid, sys_signal, sys_geteuid
/*50*/ .long sys_getegid, sys_acct, sys_nis_syscall, sys_nis_syscall, sys_ioctl
-/*55*/ .long sys_reboot, sys_nis_syscall, sys_symlink, sys_readlink, sys_execve
-/*60*/ .long sys_umask, sys_chroot, sys_newfstat, sys_nis_syscall, sys_getpagesize
+/*55*/ .long sys_reboot, sys_mmap2, sys_symlink, sys_readlink, sys_execve
+/*60*/ .long sys_umask, sys_chroot, sys_newfstat, sys_fstat64, sys_getpagesize
/*65*/ .long sys_msync, sys_vfork, sys_pread, sys_pwrite, sys_nis_syscall
/*70*/ .long sys_nis_syscall, sys_mmap, sys_nis_syscall, sys_munmap, sys_mprotect
-/*75*/ .long sys_nis_syscall, sys_vhangup, sys_nis_syscall, sys_nis_syscall, sys_getgroups
-/*80*/ .long sys_setgroups, sys_getpgrp, sys_nis_syscall, sys_setitimer, sys_nis_syscall
+/*75*/ .long sys_nis_syscall, sys_vhangup, sys_truncate64, sys_nis_syscall, sys_getgroups
+/*80*/ .long sys_setgroups, sys_getpgrp, sys_nis_syscall, sys_setitimer, sys_ftruncate64
/*85*/ .long sys_swapon, sys_getitimer, sys_nis_syscall, sys_sethostname, sys_nis_syscall
/*90*/ .long sys_dup2, sys_nis_syscall, sys_fcntl, sys_select, sys_nis_syscall
/*95*/ .long sys_fsync, sys_setpriority, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
@@ -42,8 +44,8 @@ sys_call_table:
/*115*/ .long sys_nis_syscall, sys_gettimeofday, sys_getrusage, sys_nis_syscall, sys_getcwd
/*120*/ .long sys_readv, sys_writev, sys_settimeofday, sys_fchown, sys_fchmod
/*125*/ .long sys_nis_syscall, sys_setreuid, sys_setregid, sys_rename, sys_truncate
-/*130*/ .long sys_ftruncate, sys_flock, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-/*135*/ .long sys_nis_syscall, sys_mkdir, sys_rmdir, sys_utimes, sys_nis_syscall
+/*130*/ .long sys_ftruncate, sys_flock, sys_lstat64, sys_nis_syscall, sys_nis_syscall
+/*135*/ .long sys_nis_syscall, sys_mkdir, sys_rmdir, sys_utimes, sys_stat64
/*140*/ .long sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_getrlimit
/*145*/ .long sys_setrlimit, sys_nis_syscall, sys_prctl, sys_pciconfig_read, sys_pciconfig_write
/*150*/ .long sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_nis_syscall
@@ -70,6 +72,7 @@ sys_call_table:
/*250*/ .long sys_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl
/*255*/ .long sys_aplib, sys_nis_syscall
+#ifdef CONFIG_SUNOS_EMUL
/* Now the SunOS syscall table. */
.align 4
@@ -162,3 +165,5 @@ sunos_sys_table:
.long sunos_nosys, sunos_nosys
/*250*/ .long sunos_nosys, sunos_nosys, sunos_nosys
.long sunos_nosys, sunos_nosys, sys_aplib
+
+#endif
diff --git a/arch/sparc/kernel/time.c b/arch/sparc/kernel/time.c
index 7ee196241..008567aba 100644
--- a/arch/sparc/kernel/time.c
+++ b/arch/sparc/kernel/time.c
@@ -1,4 +1,4 @@
-/* $Id: time.c,v 1.46 1999/08/31 13:11:26 anton Exp $
+/* $Id: time.c,v 1.49 1999/11/17 07:34:07 zaitcev Exp $
* linux/arch/sparc/kernel/time.c
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -26,6 +26,7 @@
#include <linux/timex.h>
#include <linux/init.h>
#include <linux/pci.h>
+#include <linux/ioport.h>
#include <asm/oplib.h>
#include <asm/segment.h>
@@ -38,6 +39,7 @@
#include <asm/machines.h>
#include <asm/sun4paddr.h>
#include <asm/page.h>
+#include <asm/pcic.h>
extern rwlock_t xtime_lock;
@@ -207,13 +209,14 @@ static __inline__ void sun4_clock_probe(void)
{
#ifdef CONFIG_SUN4
int temp;
+ struct resource r;
+ memset(&r, 0, sizeof(r));
if( idprom->id_machtype == (SM_SUN4 | SM_4_330) ) {
sp_clock_typ = MSTK48T02;
- mstk48t02_regs = (unsigned long)
- sparc_alloc_io(sun4_clock_physaddr, 0,
- sizeof(struct mostek48t02),
- "clock", 0x0, 0x0);
+ r.start = sun4_clock_physaddr;
+ mstk48t02_regs = sbus_ioremap(&r, 0,
+ sizeof(struct mostek48t02), 0);
mstk48t08_regs = 0; /* To catch weirdness */
intersil_clock = 0; /* just in case */
@@ -224,10 +227,9 @@ static __inline__ void sun4_clock_probe(void)
/* intersil setup code */
printk("Clock: INTERSIL at %8x ",sun4_clock_physaddr);
sp_clock_typ = INTERSIL;
+ r.start = sun4_clock_physaddr;
intersil_clock = (struct intersil *)
- sparc_alloc_io(sun4_clock_physaddr, 0,
- sizeof(*intersil_clock),
- "clock", 0x0, 0x0);
+ sparc_ioremap(&r, 0, sizeof(*intersil_clock), "intersil");
mstk48t02_regs = 0; /* just be sure */
mstk48t08_regs = 0; /* ditto */
/* initialise the clock */
@@ -256,8 +258,10 @@ static __inline__ void clock_probe(void)
struct linux_prom_registers clk_reg[2];
char model[128];
register int node, cpuunit, bootbus;
+ struct resource r;
cpuunit = bootbus = 0;
+ memset(&r, 0, sizeof(r));
/* Determine the correct starting PROM node for the probe. */
node = prom_getchild(prom_root_node);
@@ -297,10 +301,10 @@ static __inline__ void clock_probe(void)
else
prom_apply_obio_ranges(clk_reg, 1);
/* Map the clock register io area read-only */
- mstk48t02_regs = (unsigned long)
- sparc_alloc_io(clk_reg[0].phys_addr,
- (void *) 0, sizeof(struct mostek48t02),
- "clock", clk_reg[0].which_io, 0x0);
+ r.flags = clk_reg[0].which_io;
+ r.start = clk_reg[0].phys_addr;
+ mstk48t02_regs = sbus_ioremap(&r, 0,
+ sizeof(struct mostek48t02), "mk48t02");
mstk48t08_regs = 0; /* To catch weirdness */
} else if (strcmp(model, "mk48t08") == 0) {
sp_clock_typ = MSTK48T08;
@@ -314,10 +318,11 @@ static __inline__ void clock_probe(void)
else
prom_apply_obio_ranges(clk_reg, 1);
/* Map the clock register io area read-only */
- mstk48t08_regs = (struct mostek48t08 *)
- sparc_alloc_io(clk_reg[0].phys_addr,
- (void *) 0, sizeof(*mstk48t08_regs),
- "clock", clk_reg[0].which_io, 0x0);
+ /* XXX r/o attribute is somewhere in r.flags */
+ r.flags = clk_reg[0].which_io;
+ r.start = clk_reg[0].phys_addr;
+ mstk48t08_regs = (struct mostek48t08 *) sbus_ioremap(&r, 0,
+ sizeof(struct mostek48t08), "mk48t08");
mstk48t02_regs = (unsigned long)&mstk48t08_regs->regs;
} else {
@@ -420,7 +425,7 @@ void __init time_init(void)
{
#ifdef CONFIG_PCI
extern void pci_time_init(void);
- if (pci_present()) {
+ if (pcic_present()) {
pci_time_init();
return;
}
diff --git a/arch/sparc/lib/Makefile b/arch/sparc/lib/Makefile
index d5b475480..1a8c404e2 100644
--- a/arch/sparc/lib/Makefile
+++ b/arch/sparc/lib/Makefile
@@ -1,11 +1,12 @@
-# $Id: Makefile,v 1.28 1999/03/21 06:37:44 davem Exp $
+# $Id: Makefile,v 1.31 1999/12/28 11:50:39 jj Exp $
# Makefile for Sparc library files..
#
OBJS = mul.o rem.o sdiv.o udiv.o umul.o urem.o ashrdi3.o memcpy.o memset.o \
strlen.o checksum.o blockops.o memscan.o memcmp.o strncmp.o \
strncpy_from_user.o divdi3.o udivdi3.o strlen_user.o \
- copy_user.o locks.o atomic.o bitops.o debuglocks.o lshrdi3.o
+ copy_user.o locks.o atomic.o bitops.o debuglocks.o lshrdi3.o \
+ ashldi3.o rwsem.o
ifdef CONFIG_SMP
OBJS += irqlock.o
@@ -15,82 +16,11 @@ lib.a: $(OBJS)
$(AR) rcs lib.a $(OBJS)
sync
-checksum.o: checksum.S
- $(CC) -D__ASSEMBLY__ -ansi -c -o checksum.o checksum.S
+.S.s:
+ $(CPP) -D__ASSEMBLY__ $(AFLAGS) -ansi -DST_DIV0=0x2 $< -o $*.s
-memcpy.o: memcpy.S
- $(CC) -D__ASSEMBLY__ -ansi -c -o memcpy.o memcpy.S
-
-memcmp.o: memcmp.S
- $(CC) -D__ASSEMBLY__ -ansi -c -o memcmp.o memcmp.S
-
-memscan.o: memscan.S
- $(CC) -D__ASSEMBLY__ -ansi -c -o memscan.o memscan.S
-
-strncmp.o: strncmp.S
- $(CC) -D__ASSEMBLY__ -ansi -c -o strncmp.o strncmp.S
-
-strncpy_from_user.o: strncpy_from_user.S
- $(CC) -D__ASSEMBLY__ -ansi -c -o strncpy_from_user.o strncpy_from_user.S
-
-strlen_user.o: strlen_user.S
- $(CC) -D__ASSEMBLY__ -ansi -c -o strlen_user.o strlen_user.S
-
-copy_user.o: copy_user.S
- $(CC) -D__ASSEMBLY__ -ansi -c -o copy_user.o copy_user.S
-
-blockops.o: blockops.S
- $(CC) -D__ASSEMBLY__ -ansi -c -o blockops.o blockops.S
-
-memset.o: memset.S
- $(CC) -D__ASSEMBLY__ -ansi -c -o memset.o memset.S
-
-locks.o: locks.S
- $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o locks.o locks.S
-
-atomic.o: atomic.S
- $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o atomic.o atomic.S
-
-bitops.o: bitops.S
- $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o bitops.o bitops.S
-
-ifdef CONFIG_SMP
-irqlock.o: irqlock.S
- $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o irqlock.o irqlock.S
-endif
-
-strlen.o: strlen.S
- $(CC) -D__ASSEMBLY__ -ansi -c -o strlen.o strlen.S
-
-divdi3.o: divdi3.S
- $(CC) -D__ASSEMBLY__ -ansi -c -o divdi3.o divdi3.S
-
-udivdi3.o: udivdi3.S
- $(CC) -D__ASSEMBLY__ -ansi -c -o udivdi3.o udivdi3.S
-
-mul.o: mul.S
- $(CC) -D__ASSEMBLY__ -c -o mul.o mul.S
-
-rem.o: rem.S
- $(CC) -D__ASSEMBLY__ -DST_DIV0=0x2 -c -o rem.o rem.S
-
-sdiv.o: sdiv.S
- $(CC) -D__ASSEMBLY__ -DST_DIV0=0x2 -c -o sdiv.o sdiv.S
-
-udiv.o: udiv.S
- $(CC) -D__ASSEMBLY__ -DST_DIV0=0x2 -c -o udiv.o udiv.S
-
-umul.o: umul.S
- $(CC) -D__ASSEMBLY__ -c -o umul.o umul.S
-
-urem.o: urem.S
- $(CC) -D__ASSEMBLY__ -DST_DIV0=0x2 -c -o urem.o urem.S
-
-ashrdi3.o: ashrdi3.S
- $(CC) -D__ASSEMBLY__ -c -o ashrdi3.o ashrdi3.S
-
-lshrdi3.o: lshrdi3.S
- $(CC) -D__ASSEMBLY__ -c -o lshrdi3.o lshrdi3.S
+.S.o:
+ $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -DST_DIV0=0x2 -c $< -o $*.o
dep:
diff --git a/arch/sparc/lib/ashldi3.S b/arch/sparc/lib/ashldi3.S
new file mode 100644
index 000000000..e3b8e0572
--- /dev/null
+++ b/arch/sparc/lib/ashldi3.S
@@ -0,0 +1,36 @@
+/* $Id: ashldi3.S,v 1.2 1999/11/19 04:11:46 davem Exp $
+ * ashldi3.S: GCC emits these for certain drivers playing
+ * with long longs.
+ *
+ * Copyright (C) 1999 David S. Miller (davem@redhat.com)
+ */
+
+#include <asm/cprefix.h>
+
+ .text
+ .align 4
+ .globl C_LABEL(__ashldi3)
+C_LABEL(__ashldi3):
+ cmp %o2, 0
+ be 9f
+ mov 0x20, %g2
+
+ sub %g2, %o2, %g2
+ cmp %g2, 0
+ bg 7f
+ sll %o0, %o2, %g3
+
+ neg %g2
+ clr %o5
+ b 8f
+ sll %o1, %g2, %o4
+7:
+ srl %o1, %g2, %g2
+ sll %o1, %o2, %o5
+ or %g3, %g2, %o4
+8:
+ mov %o4, %o0
+ mov %o5, %o1
+9:
+ retl
+ nop
diff --git a/arch/sparc/lib/ashrdi3.S b/arch/sparc/lib/ashrdi3.S
index bf589c283..871d4521e 100644
--- a/arch/sparc/lib/ashrdi3.S
+++ b/arch/sparc/lib/ashrdi3.S
@@ -1,4 +1,4 @@
-/* $Id: ashrdi3.S,v 1.3 1996/09/07 23:18:10 davem Exp $
+/* $Id: ashrdi3.S,v 1.4 1999/11/19 04:11:49 davem Exp $
* ashrdi3.S: The filesystem code creates all kinds of references to
* this little routine on the sparc with gcc.
*
@@ -7,7 +7,9 @@
#include <asm/cprefix.h>
- .globl C_LABEL(__ashrdi3)
+ .text
+ .align 4
+ .globl C_LABEL(__ashrdi3)
C_LABEL(__ashrdi3):
tst %o2
be 3f
diff --git a/arch/sparc/lib/rwsem.S b/arch/sparc/lib/rwsem.S
new file mode 100644
index 000000000..0d5f74139
--- /dev/null
+++ b/arch/sparc/lib/rwsem.S
@@ -0,0 +1,191 @@
+/* $Id: rwsem.S,v 1.2 2000/01/05 01:00:38 davem Exp $
+ * Assembly part of rw semaphores.
+ *
+ * Copyright (C) 1999 Jakub Jelinek (jakub@redhat.com)
+ */
+
+#include <asm/ptrace.h>
+#include <asm/psr.h>
+
+ .text
+ .align 4
+
+ .globl ___down_read
+___down_read:
+ rd %psr, %g3
+ nop
+ nop
+ nop
+ or %g3, PSR_PIL, %g7
+ wr %g7, 0, %psr
+ nop
+ nop
+ nop
+#ifdef __SMP__
+1: ldstub [%g1 + 4], %g7
+ tst %g7
+ bne 1b
+ ld [%g1], %g7
+ subcc %g7, 1, %g7
+ st %g7, [%g1]
+ stb %g0, [%g1 + 4]
+#else
+ ld [%g1], %g7
+ subcc %g7, 1, %g7
+ st %g7, [%g1]
+#endif
+ wr %g3, 0, %psr
+ nop
+ bneg 3f
+ nop
+2: jmpl %o7, %g0
+ mov %g4, %o7
+3: save %sp, -64, %sp
+ mov %g1, %l1
+ mov %g4, %l4
+ bcs 4f
+ mov %g5, %l5
+ call down_read_failed
+ mov %l1, %o0
+ mov %l1, %g1
+ mov %l4, %g4
+ ba ___down_read
+ restore %l5, %g0, %g5
+4: call down_read_failed_biased
+ mov %l1, %o0
+ mov %l1, %g1
+ mov %l4, %g4
+ ba 2b
+ restore %l5, %g0, %g5
+
+ .globl ___down_write
+___down_write:
+ rd %psr, %g3
+ nop
+ nop
+ nop
+ or %g3, PSR_PIL, %g7
+ wr %g7, 0, %psr
+ sethi %hi(0x01000000), %g2
+ nop
+ nop
+#ifdef __SMP__
+1: ldstub [%g1 + 4], %g7
+ tst %g7
+ bne 1b
+ ld [%g1], %g7
+ subcc %g7, %g2, %g7
+ st %g7, [%g1]
+ stb %g0, [%g1 + 4]
+#else
+ ld [%g1], %g7
+ subcc %g7, %g2, %g7
+ st %g7, [%g1]
+#endif
+ wr %g3, 0, %psr
+ nop
+ bne 3f
+ nop
+2: jmpl %o7, %g0
+ mov %g4, %o7
+3: save %sp, -64, %sp
+ mov %g1, %l1
+ mov %g4, %l4
+ bcs 4f
+ mov %g5, %l5
+ call down_write_failed
+ mov %l1, %o0
+ mov %l1, %g1
+ mov %l4, %g4
+ ba ___down_write
+ restore %l5, %g0, %g5
+4: call down_write_failed_biased
+ mov %l1, %o0
+ mov %l1, %g1
+ mov %l4, %g4
+ ba 2b
+ restore %l5, %g0, %g5
+
+ .globl ___up_read
+___up_read:
+ rd %psr, %g3
+ nop
+ nop
+ nop
+ or %g3, PSR_PIL, %g7
+ wr %g7, 0, %psr
+ nop
+ nop
+ nop
+#ifdef __SMP__
+1: ldstub [%g1 + 4], %g7
+ tst %g7
+ bne 1b
+ ld [%g1], %g7
+ addcc %g7, 1, %g7
+ st %g7, [%g1]
+ stb %g0, [%g1 + 4]
+#else
+ ld [%g1], %g7
+ addcc %g7, 1, %g7
+ st %g7, [%g1]
+#endif
+ wr %g3, 0, %psr
+ nop
+ be 3f
+ nop
+2: jmpl %o7, %g0
+ mov %g4, %o7
+3: save %sp, -64, %sp
+ mov %g1, %l1
+ mov %g4, %l4
+ mov %g5, %l5
+ clr %o1
+ call __rwsem_wake
+ mov %l1, %o0
+ mov %l1, %g1
+ mov %l4, %g4
+ ba 2b
+ restore %l5, %g0, %g5
+
+ .globl ___up_write
+___up_write:
+ rd %psr, %g3
+ nop
+ nop
+ nop
+ or %g3, PSR_PIL, %g7
+ wr %g7, 0, %psr
+ sethi %hi(0x01000000), %g2
+ nop
+ nop
+#ifdef __SMP__
+1: ldstub [%g1 + 4], %g7
+ tst %g7
+ bne 1b
+ ld [%g1], %g7
+ addcc %g7, %g2, %g7
+ st %g7, [%g1]
+ stb %g0, [%g1 + 4]
+#else
+ ld [%g1], %g7
+ addcc %g7, %g2, %g7
+ st %g7, [%g1]
+#endif
+ wr %g3, 0, %psr
+ nop
+ bcs 3f
+ nop
+2: jmpl %o7, %g0
+ mov %g4, %o7
+3: save %sp, -64, %sp
+ mov %g1, %l1
+ mov %g4, %l4
+ mov %g5, %l5
+ mov %g7, %o1
+ call __rwsem_wake
+ mov %l1, %o0
+ mov %l1, %g1
+ mov %l4, %g4
+ ba 2b
+ restore %l5, %g0, %g5
diff --git a/arch/sparc/lib/strlen_user.S b/arch/sparc/lib/strlen_user.S
index 6f2328e06..3dc3c3820 100644
--- a/arch/sparc/lib/strlen_user.S
+++ b/arch/sparc/lib/strlen_user.S
@@ -47,8 +47,11 @@
mov 3, %o0
.align 4
- .global C_LABEL(__strlen_user)
+ .global C_LABEL(__strlen_user), C_LABEL(__strnlen_user)
C_LABEL(__strlen_user):
+ sethi %hi(32768), %o1
+C_LABEL(__strnlen_user):
+ mov %o1, %g1
mov %o0, %o1
andcc %o0, 3, %g0
bne 10b
@@ -63,11 +66,16 @@ C_LABEL(__strlen_user):
2:
sub %o5, %o2, %o4
andcc %o4, %o3, %g0
- be 13b
+ bne 82f
add %o0, 4, %o0
+ sub %o0, %o1, %g2
+81: cmp %g2, %g1
+ blu 13b
+ mov %o0, %o4
+ ba,a 1f
/* Check every byte. */
- srl %o5, 24, %g5
+82: srl %o5, 24, %g5
andcc %g5, 0xff, %g0
be 1f
add %o0, -3, %o4
@@ -80,9 +88,9 @@ C_LABEL(__strlen_user):
be 1f
add %o4, 1, %o4
andcc %o5, 0xff, %g0
- bne,a 2b
-14:
- ld [%o0], %o5
+ bne 81b
+ sub %o0, %o1, %g2
+
add %o4, 1, %o4
1:
retl
@@ -101,4 +109,3 @@ C_LABEL(__strlen_user):
.word 11b, 9b
.word 12b, 9b
.word 13b, 9b
- .word 14b, 9b
diff --git a/arch/sparc/math-emu/Makefile b/arch/sparc/math-emu/Makefile
index 6e4862a83..e8880cd07 100644
--- a/arch/sparc/math-emu/Makefile
+++ b/arch/sparc/math-emu/Makefile
@@ -11,10 +11,10 @@ O_TARGET := math-emu.o
O_OBJS := math.o ashldi3.o
.S.s:
- $(CPP) -D__ASSEMBLY__ -ansi $< -o $*.s
+ $(CPP) -D__ASSEMBLY__ $(AFLAGS) -ansi $< -o $*.s
.S.o:
- $(CC) -D__ASSEMBLY__ -ansi -c $< -o $*.o
+ $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c $< -o $*.o
CFLAGS += -I. -I$(TOPDIR)/include/math-emu -w
diff --git a/arch/sparc/mm/Makefile b/arch/sparc/mm/Makefile
index 7caf69e90..5e304411c 100644
--- a/arch/sparc/mm/Makefile
+++ b/arch/sparc/mm/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.34 1999/08/14 03:51:42 anton Exp $
+# $Id: Makefile,v 1.35 1999/10/09 05:32:01 zaitcev Exp $
# Makefile for the linux Sparc-specific parts of the memory manager.
#
# Note! Dependencies are done automagically by 'make dep', which also
@@ -15,7 +15,7 @@ endif
ifeq ($(CONFIG_SUN4),y)
O_OBJS += nosrmmu.o
else
-O_OBJS += srmmu.o iommu.o io-unit.o hypersparc.o viking.o tsunami.o
+O_OBJS += srmmu.o iommu.o io-unit.o hypersparc.o viking.o tsunami.o swift.o
endif
ifdef CONFIG_SMP
O_OBJS += nosun4c.o
@@ -33,3 +33,6 @@ viking.o: viking.S
tsunami.o: tsunami.S
$(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o tsunami.o tsunami.S
+
+swift.o: swift.S
+ $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o swift.o swift.S
diff --git a/arch/sparc/mm/asyncd.c b/arch/sparc/mm/asyncd.c
index d17979cd4..6ed8a3c99 100644
--- a/arch/sparc/mm/asyncd.c
+++ b/arch/sparc/mm/asyncd.c
@@ -1,4 +1,4 @@
-/* $Id: asyncd.c,v 1.17 1999/08/14 03:51:44 anton Exp $
+/* $Id: asyncd.c,v 1.18 1999/12/27 06:30:02 anton Exp $
* The asyncd kernel daemon. This handles paging on behalf of
* processes that receive page faults due to remote (async) memory
* accesses.
@@ -25,6 +25,7 @@
#include <asm/system.h> /* for cli()/sti() */
#include <asm/segment.h> /* for memcpy_to/fromfs */
#include <asm/bitops.h>
+#include <asm/pgalloc.h>
#include <asm/pgtable.h>
#define DEBUG 0
diff --git a/arch/sparc/mm/btfixup.c b/arch/sparc/mm/btfixup.c
index 4ecf94360..9b766f4eb 100644
--- a/arch/sparc/mm/btfixup.c
+++ b/arch/sparc/mm/btfixup.c
@@ -1,4 +1,4 @@
-/* $Id: btfixup.c,v 1.8 1999/08/31 06:54:31 davem Exp $
+/* $Id: btfixup.c,v 1.9 1999/12/27 06:30:02 anton Exp $
* btfixup.c: Boot time code fixup and relocator, so that
* we can get rid of most indirect calls to achieve single
* image sun4c and srmmu kernel.
@@ -11,6 +11,7 @@
#include <linux/init.h>
#include <asm/btfixup.h>
#include <asm/page.h>
+#include <asm/pgalloc.h>
#include <asm/pgtable.h>
#include <asm/oplib.h>
#include <asm/system.h>
diff --git a/arch/sparc/mm/fault.c b/arch/sparc/mm/fault.c
index c400a0179..ba75681b1 100644
--- a/arch/sparc/mm/fault.c
+++ b/arch/sparc/mm/fault.c
@@ -1,4 +1,4 @@
-/* $Id: fault.c,v 1.107 1999/08/14 03:51:46 anton Exp $
+/* $Id: fault.c,v 1.111 1999/10/24 13:45:59 anton Exp $
* fault.c: Page fault handlers for the Sparc.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -146,10 +146,11 @@ static void unhandled_fault(unsigned long address, struct task_struct *tsk,
printk(KERN_ALERT "Unable to handle kernel paging request "
"at virtual address %08lx\n", address);
}
- printk(KERN_ALERT "tsk->mm->context = %08lx\n",
- (unsigned long) tsk->mm->context);
- printk(KERN_ALERT "tsk->mm->pgd = %08lx\n",
- (unsigned long) tsk->mm->pgd);
+ printk(KERN_ALERT "tsk->{mm,active_mm}->context = %08lx\n",
+ (tsk->mm ? tsk->mm->context : tsk->active_mm->context));
+ printk(KERN_ALERT "tsk->{mm,active_mm}->pgd = %08lx\n",
+ (tsk->mm ? (unsigned long) tsk->mm->pgd :
+ (unsigned long) tsk->active_mm->pgd));
die_if_kernel("Oops", regs);
}
@@ -309,8 +310,18 @@ asmlinkage void do_sun4c_fault(struct pt_regs *regs, int text_fault, int write,
pgd_t *pgdp;
pte_t *ptep;
- if (text_fault)
+ if (text_fault) {
address = regs->pc;
+ } else if (!write &&
+ !(regs->psr & PSR_PS)) {
+ unsigned int insn, *ip;
+
+ ip = (unsigned int *)regs->pc;
+ if (! get_user(insn, ip)) {
+ if ((insn & 0xc1680000) == 0xc0680000)
+ write = 1;
+ }
+ }
pgdp = sun4c_pgd_offset(mm, address);
ptep = sun4c_pte_offset((pmd_t *) pgdp, address);
@@ -319,28 +330,36 @@ asmlinkage void do_sun4c_fault(struct pt_regs *regs, int text_fault, int write,
if (write) {
if ((pte_val(*ptep) & (_SUN4C_PAGE_WRITE|_SUN4C_PAGE_PRESENT))
== (_SUN4C_PAGE_WRITE|_SUN4C_PAGE_PRESENT)) {
+ unsigned long flags;
*ptep = __pte(pte_val(*ptep) | _SUN4C_PAGE_ACCESSED |
_SUN4C_PAGE_MODIFIED |
_SUN4C_PAGE_VALID |
_SUN4C_PAGE_DIRTY);
+ save_and_cli(flags);
if (sun4c_get_segmap(address) != invalid_segment) {
sun4c_put_pte(address, pte_val(*ptep));
+ restore_flags(flags);
return;
}
+ restore_flags(flags);
}
} else {
if ((pte_val(*ptep) & (_SUN4C_PAGE_READ|_SUN4C_PAGE_PRESENT))
== (_SUN4C_PAGE_READ|_SUN4C_PAGE_PRESENT)) {
+ unsigned long flags;
*ptep = __pte(pte_val(*ptep) | _SUN4C_PAGE_ACCESSED |
_SUN4C_PAGE_VALID);
+ save_and_cli(flags);
if (sun4c_get_segmap(address) != invalid_segment) {
sun4c_put_pte(address, pte_val(*ptep));
+ restore_flags(flags);
return;
}
+ restore_flags(flags);
}
}
}
@@ -415,31 +434,25 @@ void window_overflow_fault(void)
{
unsigned long sp;
- lock_kernel();
sp = current->thread.rwbuf_stkptrs[0];
if(((sp + 0x38) & PAGE_MASK) != (sp & PAGE_MASK))
force_user_fault(sp + 0x38, 1);
force_user_fault(sp, 1);
- unlock_kernel();
}
void window_underflow_fault(unsigned long sp)
{
- lock_kernel();
if(((sp + 0x38) & PAGE_MASK) != (sp & PAGE_MASK))
force_user_fault(sp + 0x38, 0);
force_user_fault(sp, 0);
- unlock_kernel();
}
void window_ret_fault(struct pt_regs *regs)
{
unsigned long sp;
- lock_kernel();
sp = regs->u_regs[UREG_FP];
if(((sp + 0x38) & PAGE_MASK) != (sp & PAGE_MASK))
force_user_fault(sp + 0x38, 0);
force_user_fault(sp, 0);
- unlock_kernel();
}
diff --git a/arch/sparc/mm/generic.c b/arch/sparc/mm/generic.c
index 9669f5111..9e599fd9d 100644
--- a/arch/sparc/mm/generic.c
+++ b/arch/sparc/mm/generic.c
@@ -1,4 +1,4 @@
-/* $Id: generic.c,v 1.6 1998/10/27 23:28:00 davem Exp $
+/* $Id: generic.c,v 1.9 1999/12/27 06:30:03 anton Exp $
* generic.c: Generic Sparc mm routines that are not dependent upon
* MMU type but are Sparc specific.
*
@@ -9,46 +9,26 @@
#include <linux/mm.h>
#include <linux/swap.h>
+#include <asm/pgalloc.h>
#include <asm/pgtable.h>
#include <asm/page.h>
-
-/* Allocate a block of RAM which is aligned to its size.
- * This procedure can be used until the call to mem_init().
- */
-void *sparc_init_alloc(unsigned long *kbrk, unsigned long size)
-{
- unsigned long mask = size - 1;
- unsigned long ret;
-
- if(!size)
- return 0x0;
- if(size & mask) {
- prom_printf("panic: sparc_init_alloc botch\n");
- prom_halt();
- }
- ret = (*kbrk + mask) & ~mask;
- *kbrk = ret + size;
- memset((void*) ret, 0, size);
- return (void*) ret;
-}
-
static inline void forget_pte(pte_t page)
{
if (pte_none(page))
return;
if (pte_present(page)) {
- unsigned long addr = pte_page(page);
- if (MAP_NR(addr) >= max_mapnr || PageReserved(mem_map+MAP_NR(addr)))
+ unsigned long nr = pte_pagenr(page);
+ if (nr >= max_mapnr || PageReserved(mem_map+nr))
return;
/*
* free_page() used to be able to clear swap cache
* entries. We may now have to do it manually.
*/
- free_page_and_swap_cache(addr);
+ free_page_and_swap_cache(mem_map+nr);
return;
}
- swap_free(pte_val(page));
+ swap_free(pte_to_swp_entry(page));
}
/* Remap IO memory, the same way as remap_page_range(), but use
diff --git a/arch/sparc/mm/init.c b/arch/sparc/mm/init.c
index 40aab1d66..221496f98 100644
--- a/arch/sparc/mm/init.c
+++ b/arch/sparc/mm/init.c
@@ -1,4 +1,4 @@
-/* $Id: init.c,v 1.69 1999/09/06 22:56:17 ecd Exp $
+/* $Id: init.c,v 1.72 1999/12/27 06:30:06 anton Exp $
* linux/arch/sparc/mm/init.c
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -22,6 +22,8 @@
#include <linux/blk.h>
#endif
#include <linux/init.h>
+#include <linux/highmem.h>
+#include <linux/bootmem.h>
#include <asm/system.h>
#include <asm/segment.h>
@@ -30,22 +32,21 @@
#include <asm/pgtable.h>
#include <asm/vaddrs.h>
-/* Turn this off if you suspect some place in some physical memory hole
- might get into page tables (something would be broken very much). */
-
-#define FREE_UNUSED_MEM_MAP
-
extern void show_net_buffers(void);
unsigned long *sparc_valid_addr_bitmap;
+unsigned long phys_base;
+
struct sparc_phys_banks sp_banks[SPARC_PHYS_BANKS];
unsigned long sparc_unmapped_base;
struct pgtable_cache_struct pgt_quicklists;
/* References to section boundaries */
-extern char __init_begin, __init_end, etext;
+extern char __init_begin, __init_end, _start, _end, etext , edata;
+
+static unsigned long totalram_pages = 0;
/*
* BAD_PAGE is the page that is used for page faults when linux
@@ -62,50 +63,31 @@ extern char __init_begin, __init_end, etext;
*/
pte_t *__bad_pagetable(void)
{
- memset((void *) EMPTY_PGT, 0, PAGE_SIZE);
- return (pte_t *) EMPTY_PGT;
+ memset((void *) &empty_bad_page_table, 0, PAGE_SIZE);
+ return (pte_t *) &empty_bad_page_table;
}
pte_t __bad_page(void)
{
- memset((void *) EMPTY_PGE, 0, PAGE_SIZE);
- return pte_mkdirty(mk_pte((unsigned long) EMPTY_PGE, PAGE_SHARED));
+ memset((void *) &empty_bad_page, 0, PAGE_SIZE);
+ return pte_mkdirty(mk_pte_phys((((unsigned long) &empty_bad_page)
+ - PAGE_OFFSET + phys_base),
+ PAGE_SHARED));
}
void show_mem(void)
{
- int free = 0,total = 0,reserved = 0;
- int shared = 0, cached = 0;
- struct page *page, *end;
-
- printk("\nMem-info:\n");
+ printk("Mem-info:\n");
show_free_areas();
- printk("Free swap: %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10));
- for (page = mem_map, end = mem_map + max_mapnr;
- page < end; page++) {
- if (PageSkip(page)) {
- if (page->next_hash < page)
- break;
- page = page->next_hash;
- }
- total++;
- if (PageReserved(page))
- reserved++;
- else if (PageSwapCache(page))
- cached++;
- else if (!atomic_read(&page->count))
- free++;
- else
- shared += atomic_read(&page->count) - 1;
- }
- printk("%d pages of RAM\n",total);
- printk("%d free pages\n",free);
- printk("%d reserved pages\n",reserved);
- printk("%d pages shared\n",shared);
- printk("%d pages swap cached\n",cached);
- printk("%ld page tables cached\n",pgtable_cache_size);
+ printk("Free swap: %6dkB\n",
+ nr_swap_pages << (PAGE_SHIFT-10));
+ printk("%ld pages of RAM\n", totalram_pages);
+ printk("%d free pages\n", nr_free_pages());
+ printk("%ld pages in page table cache\n",pgtable_cache_size);
+#ifndef __SMP__
if (sparc_cpu_model == sun4m || sparc_cpu_model == sun4d)
- printk("%ld page dirs cached\n", pgd_cache_size);
+ printk("%ld entries in page dir cache\n",pgd_cache_size);
+#endif
show_buffers();
#ifdef CONFIG_NET
show_net_buffers();
@@ -114,12 +96,12 @@ void show_mem(void)
extern pgprot_t protection_map[16];
-unsigned long __init sparc_context_init(unsigned long start_mem, int numctx)
+void __init sparc_context_init(int numctx)
{
int ctx;
- ctx_list_pool = (struct ctx_list *) start_mem;
- start_mem += (numctx * sizeof(struct ctx_list));
+ ctx_list_pool = __alloc_bootmem(numctx * sizeof(struct ctx_list), SMP_CACHE_BYTES, 0UL);
+
for(ctx = 0; ctx < numctx; ctx++) {
struct ctx_list *clist;
@@ -131,7 +113,98 @@ unsigned long __init sparc_context_init(unsigned long start_mem, int numctx)
ctx_used.next = ctx_used.prev = &ctx_used;
for(ctx = 0; ctx < numctx; ctx++)
add_to_free_ctxlist(ctx_list_pool + ctx);
- return start_mem;
+}
+
+#undef DEBUG_BOOTMEM
+
+extern unsigned long cmdline_memory_size;
+
+unsigned long __init bootmem_init(void)
+{
+ unsigned long bootmap_size, start_pfn, end_pfn;
+ unsigned long end_of_phys_memory = 0UL;
+ int i;
+
+ /* XXX It is a bit ambiguous here, whether we should
+ * XXX treat the user specified mem=xxx as total wanted
+ * XXX physical memory, or as a limit to the upper
+ * XXX physical address we allow. For now it is the
+ * XXX latter. -DaveM
+ */
+#ifdef DEBUG_BOOTMEM
+ prom_printf("bootmem_init: Scan sp_banks, ");
+#endif
+ for (i = 0; sp_banks[i].num_bytes != 0; i++) {
+ end_of_phys_memory = sp_banks[i].base_addr +
+ sp_banks[i].num_bytes;
+ if (cmdline_memory_size) {
+ if (end_of_phys_memory > cmdline_memory_size) {
+ if (cmdline_memory_size > sp_banks[i].base_addr) {
+ end_of_phys_memory =
+ sp_banks[i-1].base_addr +
+ sp_banks[i-1].num_bytes;
+ sp_banks[i].base_addr = 0xdeadbeef;
+ sp_banks[i].num_bytes = 0;
+ } else {
+ sp_banks[i].num_bytes -=
+ (end_of_phys_memory -
+ cmdline_memory_size);
+ end_of_phys_memory = cmdline_memory_size;
+ sp_banks[++i].base_addr = 0xdeadbeef;
+ sp_banks[i].num_bytes = 0;
+ }
+ break;
+ }
+ }
+ }
+
+ /* Start with page aligned address of last symbol in kernel
+ * image.
+ */
+ start_pfn = PAGE_ALIGN((unsigned long) &_end) - PAGE_OFFSET;
+
+ /* Adjust up to the physical address where the kernel begins. */
+ start_pfn += phys_base;
+
+ /* Now shift down to get the real physical page frame number. */
+ start_pfn >>= PAGE_SHIFT;
+
+ end_pfn = end_of_phys_memory >> PAGE_SHIFT;
+
+ /* Initialize the boot-time allocator. */
+#ifdef DEBUG_BOOTMEM
+ prom_printf("init_bootmem(spfn[%lx],epfn[%lx])\n",
+ start_pfn, end_pfn);
+#endif
+ bootmap_size = init_bootmem(start_pfn, end_pfn);
+
+ /* Now register the available physical memory with the
+ * allocator.
+ */
+ for (i = 0; sp_banks[i].num_bytes != 0; i++) {
+#ifdef DEBUG_BOOTMEM
+ prom_printf("free_bootmem: base[%lx] size[%lx]\n",
+ sp_banks[i].base_addr,
+ sp_banks[i].num_bytes);
+#endif
+ free_bootmem(sp_banks[i].base_addr,
+ sp_banks[i].num_bytes);
+ }
+
+ /* Reserve the kernel text/data/bss and the bootmem bitmap. */
+#ifdef DEBUG_BOOTMEM
+ prom_printf("reserve_bootmem: base[%lx] size[%lx]\n",
+ phys_base,
+ (((start_pfn << PAGE_SHIFT) +
+ bootmap_size) - phys_base));
+#endif
+ reserve_bootmem(phys_base, (((start_pfn << PAGE_SHIFT) +
+ bootmap_size) - phys_base));
+
+#ifdef DEBUG_BOOTMEM
+ prom_printf("init_bootmem: return end_pfn[%lx]\n", end_pfn);
+#endif
+ return end_pfn;
}
/*
@@ -139,31 +212,32 @@ unsigned long __init sparc_context_init(unsigned long start_mem, int numctx)
* init routine based upon the Sun model type on the Sparc.
*
*/
-extern unsigned long sun4c_paging_init(unsigned long, unsigned long);
-extern unsigned long srmmu_paging_init(unsigned long, unsigned long);
-extern unsigned long device_scan(unsigned long);
+extern void sun4c_paging_init(void);
+extern void srmmu_paging_init(void);
+extern void device_scan(void);
+
+unsigned long last_valid_pfn;
-unsigned long __init
-paging_init(unsigned long start_mem, unsigned long end_mem)
+void __init paging_init(void)
{
switch(sparc_cpu_model) {
case sun4c:
case sun4e:
case sun4:
- start_mem = sun4c_paging_init(start_mem, end_mem);
+ sun4c_paging_init();
sparc_unmapped_base = 0xe0000000;
BTFIXUPSET_SETHI(sparc_unmapped_base, 0xe0000000);
break;
case sun4m:
case sun4d:
- start_mem = srmmu_paging_init(start_mem, end_mem);
+ srmmu_paging_init();
sparc_unmapped_base = 0x50000000;
BTFIXUPSET_SETHI(sparc_unmapped_base, 0x50000000);
break;
case ap1000:
#if CONFIG_AP1000
- start_mem = apmmu_paging_init(start_mem, end_mem);
+ apmmu_paging_init();
sparc_unmapped_base = 0x50000000;
BTFIXUPSET_SETHI(sparc_unmapped_base, 0x50000000);
break;
@@ -194,74 +268,121 @@ paging_init(unsigned long start_mem, unsigned long end_mem)
protection_map[14] = PAGE_SHARED;
protection_map[15] = PAGE_SHARED;
btfixup();
- return device_scan(start_mem);
+ device_scan();
}
struct cache_palias *sparc_aliases;
-extern void srmmu_frob_mem_map(unsigned long);
+static void __init taint_real_pages(void)
+{
+ int i;
-int physmem_mapped_contig __initdata = 1;
+ for (i = 0; sp_banks[i].num_bytes; i++) {
+ unsigned long start, end;
-static void __init taint_real_pages(unsigned long start_mem, unsigned long end_mem)
-{
- unsigned long addr, tmp2 = 0;
-
- if(physmem_mapped_contig) {
- for(addr = PAGE_OFFSET; addr < end_mem; addr += PAGE_SIZE) {
- if(addr >= KERNBASE && addr < start_mem)
- addr = start_mem;
- for(tmp2=0; sp_banks[tmp2].num_bytes != 0; tmp2++) {
- unsigned long phys_addr = (addr - PAGE_OFFSET);
- unsigned long base = sp_banks[tmp2].base_addr;
- unsigned long limit = base + sp_banks[tmp2].num_bytes;
-
- if((phys_addr >= base) && (phys_addr < limit) &&
- ((phys_addr + PAGE_SIZE) < limit)) {
- mem_map[MAP_NR(addr)].flags &= ~(1<<PG_reserved);
- set_bit(MAP_NR(addr) >> 8, sparc_valid_addr_bitmap);
- }
- }
+ start = sp_banks[i].base_addr;
+ end = start +
+ sp_banks[i].num_bytes;
+ while (start < end) {
+ set_bit (start >> 20,
+ sparc_valid_addr_bitmap);
+ start += PAGE_SIZE;
}
- } else {
- if((sparc_cpu_model == sun4m) || (sparc_cpu_model == sun4d)) {
- srmmu_frob_mem_map(start_mem);
+ }
+}
+
+void __init free_mem_map_range(struct page *first, struct page *last)
+{
+ first = (struct page *) PAGE_ALIGN((unsigned long)first);
+ last = (struct page *) ((unsigned long)last & PAGE_MASK);
+#ifdef DEBUG_BOOTMEM
+ prom_printf("[%p,%p] ", first, last);
+#endif
+ while (first < last) {
+ ClearPageReserved(mem_map + MAP_NR(first));
+ set_page_count(mem_map + MAP_NR(first), 1);
+ free_page((unsigned long)first);
+ totalram_pages++;
+ num_physpages++;
+
+ first = (struct page *)((unsigned long)first + PAGE_SIZE);
+ }
+}
+
+/* Walk through holes in sp_banks regions, if the mem_map array
+ * areas representing those holes consume a page or more, free
+ * up such pages. This helps a lot on machines where physical
+ * ram is configured such that it begins at some hugh value.
+ *
+ * The sp_banks array is sorted by base address.
+ */
+void __init free_unused_mem_map(void)
+{
+ int i;
+
+#ifdef DEBUG_BOOTMEM
+ prom_printf("free_unused_mem_map: ");
+#endif
+ for (i = 0; sp_banks[i].num_bytes; i++) {
+ if (i == 0) {
+ struct page *first, *last;
+
+ first = mem_map;
+ last = &mem_map[sp_banks[i].base_addr >> PAGE_SHIFT];
+ free_mem_map_range(first, last);
} else {
- for(addr = start_mem; addr < end_mem; addr += PAGE_SIZE) {
- mem_map[MAP_NR(addr)].flags &= ~(1<<PG_reserved);
- set_bit(MAP_NR(addr) >> 8, sparc_valid_addr_bitmap);
+ struct page *first, *last;
+ unsigned long prev_end;
+
+ prev_end = sp_banks[i-1].base_addr +
+ sp_banks[i-1].num_bytes;
+ prev_end = PAGE_ALIGN(prev_end);
+ first = &mem_map[prev_end >> PAGE_SHIFT];
+ last = &mem_map[sp_banks[i].base_addr >> PAGE_SHIFT];
+
+ free_mem_map_range(first, last);
+
+ if (!sp_banks[i+1].num_bytes) {
+ prev_end = sp_banks[i].base_addr +
+ sp_banks[i].num_bytes;
+ first = &mem_map[prev_end >> PAGE_SHIFT];
+ last = &mem_map[last_valid_pfn];
+ free_mem_map_range(first, last);
}
}
}
+#ifdef DEBUG_BOOTMEM
+ prom_printf("\n");
+#endif
}
-void __init mem_init(unsigned long start_mem, unsigned long end_mem)
+void __init mem_init(void)
{
int codepages = 0;
int datapages = 0;
int initpages = 0;
int i;
- unsigned long addr;
- struct page *page, *end;
+ unsigned long addr, last;
/* Saves us work later. */
memset((void *) ZERO_PAGE(0), 0, PAGE_SIZE);
- end_mem &= PAGE_MASK;
- max_mapnr = MAP_NR(end_mem);
- high_memory = (void *) end_mem;
-
- sparc_valid_addr_bitmap = (unsigned long *)start_mem;
- i = max_mapnr >> (8 + 5);
+ i = last_valid_pfn >> (8 + 5);
i += 1;
- memset(sparc_valid_addr_bitmap, 0, i << 2);
- start_mem += i << 2;
- start_mem = PAGE_ALIGN(start_mem);
- num_physpages = 0;
+ sparc_valid_addr_bitmap = (unsigned long *)
+ __alloc_bootmem(i << 2, SMP_CACHE_BYTES, 0UL);
+
+ if (sparc_valid_addr_bitmap == NULL) {
+ prom_printf("mem_init: Cannot alloc valid_addr_bitmap.\n");
+ prom_halt();
+ }
+ memset(sparc_valid_addr_bitmap, 0, i << 2);
addr = KERNBASE;
- while(addr < start_mem) {
+ last = PAGE_ALIGN((unsigned long)&_end);
+ /* fix this */
+ while(addr < last) {
#ifdef CONFIG_BLK_DEV_INITRD
if (initrd_below_start_ok && addr >= initrd_start && addr < initrd_end)
mem_map[MAP_NR(addr)].flags &= ~(1<<PG_reserved);
@@ -272,69 +393,39 @@ void __init mem_init(unsigned long start_mem, unsigned long end_mem)
addr += PAGE_SIZE;
}
- taint_real_pages(start_mem, end_mem);
-
-#ifdef FREE_UNUSED_MEM_MAP
- end = mem_map + max_mapnr;
- for (page = mem_map; page < end; page++) {
- if (PageSkip(page)) {
- unsigned long low, high;
-
- /* See srmmu_frob_mem_map() for why this is done. -DaveM */
- page++;
-
- low = PAGE_ALIGN((unsigned long)(page+1));
- if (page->next_hash < page)
- high = ((unsigned long)end) & PAGE_MASK;
- else
- high = ((unsigned long)page->next_hash) & PAGE_MASK;
- while (low < high) {
- mem_map[MAP_NR(low)].flags &= ~(1<<PG_reserved);
- low += PAGE_SIZE;
- }
- }
- }
+ taint_real_pages();
+
+ max_mapnr = last_valid_pfn;
+ high_memory = __va(last_valid_pfn << PAGE_SHIFT);
+
+#ifdef DEBUG_BOOTMEM
+ prom_printf("mem_init: Calling free_all_bootmem().\n");
#endif
-
- for (addr = PAGE_OFFSET; addr < end_mem; addr += PAGE_SIZE) {
- if (PageSkip(mem_map + MAP_NR(addr))) {
- unsigned long next = mem_map[MAP_NR(addr)].next_hash - mem_map;
+ num_physpages = totalram_pages = free_all_bootmem();
- next = (next << PAGE_SHIFT) + PAGE_OFFSET;
- if (next < addr || next >= end_mem)
- break;
- addr = next;
- }
- num_physpages++;
- if(PageReserved(mem_map + MAP_NR(addr))) {
- if ((addr < (unsigned long) &etext) && (addr >= KERNBASE))
- codepages++;
- else if((addr >= (unsigned long)&__init_begin && addr < (unsigned long)&__init_end))
- initpages++;
- else if((addr < start_mem) && (addr >= KERNBASE))
- datapages++;
- continue;
- }
- atomic_set(&mem_map[MAP_NR(addr)].count, 1);
-#ifdef CONFIG_BLK_DEV_INITRD
- if (!initrd_start ||
- (addr < initrd_start || addr >= initrd_end))
+#if 0
+ free_unused_mem_map();
#endif
- free_page(addr);
- }
+
+ codepages = (((unsigned long) &etext) - ((unsigned long)&_start));
+ codepages = PAGE_ALIGN(codepages) >> PAGE_SHIFT;
+ datapages = (((unsigned long) &edata) - ((unsigned long)&etext));
+ datapages = PAGE_ALIGN(datapages) >> PAGE_SHIFT;
+ initpages = (((unsigned long) &__init_end) - ((unsigned long) &__init_begin));
+ initpages = PAGE_ALIGN(initpages) >> PAGE_SHIFT;
printk("Memory: %dk available (%dk kernel code, %dk data, %dk init) [%08lx,%08lx]\n",
- nr_free_pages << (PAGE_SHIFT-10),
+ nr_free_pages() << (PAGE_SHIFT-10),
codepages << (PAGE_SHIFT-10),
datapages << (PAGE_SHIFT-10),
initpages << (PAGE_SHIFT-10),
- (unsigned long)PAGE_OFFSET, end_mem);
+ (unsigned long)PAGE_OFFSET, (last_valid_pfn << PAGE_SHIFT));
/* NOTE NOTE NOTE NOTE
* Please keep track of things and make sure this
* always matches the code in mm/page_alloc.c -DaveM
*/
- i = nr_free_pages >> 7;
+ i = nr_free_pages() >> 7;
if (i < 48)
i = 48;
if (i > 256)
@@ -347,39 +438,34 @@ void __init mem_init(unsigned long start_mem, unsigned long end_mem)
void free_initmem (void)
{
unsigned long addr;
-
+
addr = (unsigned long)(&__init_begin);
for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) {
- mem_map[MAP_NR(addr)].flags &= ~(1 << PG_reserved);
- atomic_set(&mem_map[MAP_NR(addr)].count, 1);
- free_page(addr);
+ unsigned long page;
+ struct page *p;
+
+ page = (addr +
+ ((unsigned long) __va(phys_base)) -
+ PAGE_OFFSET);
+ p = mem_map + MAP_NR(page);
+
+ ClearPageReserved(p);
+ set_page_count(p, 1);
+ __free_page(p);
+ totalram_pages++;
+ num_physpages++;
}
}
void si_meminfo(struct sysinfo *val)
{
- struct page *page, *end;
-
- val->totalram = 0;
+ val->totalram = totalram_pages;
val->sharedram = 0;
- val->freeram = nr_free_pages << PAGE_SHIFT;
- val->bufferram = atomic_read(&buffermem);
- for (page = mem_map, end = mem_map + max_mapnr;
- page < end; page++) {
- if (PageSkip(page)) {
- if (page->next_hash < page)
- break;
- page = page->next_hash;
- }
- if (PageReserved(page))
- continue;
- val->totalram++;
- if (!atomic_read(&page->count))
- continue;
- val->sharedram += atomic_read(&page->count) - 1;
- }
- val->totalram <<= PAGE_SHIFT;
- val->sharedram <<= PAGE_SHIFT;
- val->totalbig = 0;
- val->freebig = 0;
+ val->freeram = nr_free_pages();
+ val->bufferram = atomic_read(&buffermem_pages);
+
+ val->totalhigh = 0;
+ val->freehigh = 0;
+
+ val->mem_unit = PAGE_SIZE;
}
diff --git a/arch/sparc/mm/io-unit.c b/arch/sparc/mm/io-unit.c
index 45c74c0aa..1a3476a16 100644
--- a/arch/sparc/mm/io-unit.c
+++ b/arch/sparc/mm/io-unit.c
@@ -1,4 +1,4 @@
-/* $Id: io-unit.c,v 1.15 1999/09/10 10:40:38 davem Exp $
+/* $Id: io-unit.c,v 1.18 1999/12/28 04:28:55 anton Exp $
* io-unit.c: IO-UNIT specific routines for memory management.
*
* Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -9,6 +9,8 @@
#include <linux/init.h>
#include <linux/malloc.h>
#include <linux/spinlock.h>
+#include <asm/scatterlist.h>
+#include <asm/pgalloc.h>
#include <asm/pgtable.h>
#include <asm/sbus.h>
#include <asm/io.h>
@@ -27,14 +29,15 @@
#define MKIOPTE(phys) __iopte((((phys)>>4) & IOUPTE_PAGE) | IOPERM)
void __init
-iounit_init(int sbi_node, int io_node, struct linux_sbus *sbus)
+iounit_init(int sbi_node, int io_node, struct sbus_bus *sbus)
{
iopte_t *xpt, *xptend;
struct iounit_struct *iounit;
struct linux_prom_registers iommu_promregs[PROMREG_MAX];
-
+ struct resource r;
+
iounit = kmalloc(sizeof(struct iounit_struct), GFP_ATOMIC);
-
+
memset(iounit, 0, sizeof(*iounit));
iounit->limit[0] = IOUNIT_BMAP1_START;
iounit->limit[1] = IOUNIT_BMAP2_START;
@@ -42,13 +45,14 @@ iounit_init(int sbi_node, int io_node, struct linux_sbus *sbus)
iounit->limit[3] = IOUNIT_BMAPM_END;
iounit->rotor[1] = IOUNIT_BMAP2_START;
iounit->rotor[2] = IOUNIT_BMAPM_START;
-
+
prom_getproperty(sbi_node, "reg", (void *) iommu_promregs,
sizeof(iommu_promregs));
prom_apply_generic_ranges(io_node, 0, iommu_promregs, 3);
- xpt = (iopte_t *)
- sparc_alloc_io(iommu_promregs[2].phys_addr, 0, (PAGE_SIZE * 16),
- "XPT", iommu_promregs[2].which_io, 0x0);
+ memset(&r, 0, sizeof(r));
+ r.flags = iommu_promregs[2].which_io;
+ r.start = iommu_promregs[2].phys_addr;
+ xpt = (iopte_t *) sbus_ioremap(&r, 0, PAGE_SIZE * 16, "XPT");
if(!xpt) panic("Cannot map External Page Table.");
sbus->iommu = (struct iommu_struct *)iounit;
@@ -108,7 +112,7 @@ nexti: scan = find_next_zero_bit(iounit->bmap, limit, scan);
return vaddr;
}
-static __u32 iounit_get_scsi_one(char *vaddr, unsigned long len, struct linux_sbus *sbus)
+static __u32 iounit_get_scsi_one(char *vaddr, unsigned long len, struct sbus_bus *sbus)
{
unsigned long ret, flags;
struct iounit_struct *iounit = (struct iounit_struct *)sbus->iommu;
@@ -119,7 +123,7 @@ static __u32 iounit_get_scsi_one(char *vaddr, unsigned long len, struct linux_sb
return ret;
}
-static void iounit_get_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus)
+static void iounit_get_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_bus *sbus)
{
unsigned long flags;
struct iounit_struct *iounit = (struct iounit_struct *)sbus->iommu;
@@ -127,12 +131,13 @@ static void iounit_get_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_sbus
/* FIXME: Cache some resolved pages - often several sg entries are to the same page */
spin_lock_irqsave(&iounit->lock, flags);
for (; sz >= 0; sz--) {
- sg[sz].dvma_addr = iounit_get_area(iounit, (unsigned long)sg[sz].addr, sg[sz].len);
+ sg[sz].dvma_address = iounit_get_area(iounit, (unsigned long)sg[sz].address, sg[sz].length);
+ sg[sz].dvma_length = sg[sz].length;
}
spin_unlock_irqrestore(&iounit->lock, flags);
}
-static void iounit_release_scsi_one(__u32 vaddr, unsigned long len, struct linux_sbus *sbus)
+static void iounit_release_scsi_one(__u32 vaddr, unsigned long len, struct sbus_bus *sbus)
{
unsigned long flags;
struct iounit_struct *iounit = (struct iounit_struct *)sbus->iommu;
@@ -146,16 +151,16 @@ static void iounit_release_scsi_one(__u32 vaddr, unsigned long len, struct linux
spin_unlock_irqrestore(&iounit->lock, flags);
}
-static void iounit_release_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus)
+static void iounit_release_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_bus *sbus)
{
unsigned long flags;
unsigned long vaddr, len;
struct iounit_struct *iounit = (struct iounit_struct *)sbus->iommu;
-
+
spin_lock_irqsave(&iounit->lock, flags);
for (; sz >= 0; sz--) {
- len = ((sg[sz].dvma_addr & ~PAGE_MASK) + sg[sz].len + (PAGE_SIZE-1)) >> PAGE_SHIFT;
- vaddr = (sg[sz].dvma_addr - IOUNIT_DMA_BASE) >> PAGE_SHIFT;
+ len = ((sg[sz].dvma_address & ~PAGE_MASK) + sg[sz].length + (PAGE_SIZE-1)) >> PAGE_SHIFT;
+ vaddr = (sg[sz].dvma_address - IOUNIT_DMA_BASE) >> PAGE_SHIFT;
IOD(("iounit_release %08lx-%08lx\n", (long)vaddr, (long)len+vaddr));
for (len += vaddr; vaddr < len; vaddr++)
clear_bit(vaddr, iounit->bmap);
@@ -164,21 +169,18 @@ static void iounit_release_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_
}
#ifdef CONFIG_SBUS
-static void iounit_map_dma_area(unsigned long addr, int len)
+static void iounit_map_dma_area(unsigned long va, __u32 addr, int len)
{
unsigned long page, end;
pgprot_t dvma_prot;
iopte_t *iopte;
- struct linux_sbus *sbus;
+ struct sbus_bus *sbus;
dvma_prot = __pgprot(SRMMU_CACHE | SRMMU_ET_PTE | SRMMU_PRIV);
end = PAGE_ALIGN((addr + len));
while(addr < end) {
- page = get_free_page(GFP_KERNEL);
- if(!page) {
- prom_printf("alloc_dvma: Cannot get a dvma page\n");
- prom_halt();
- } else {
+ page = va;
+ {
pgd_t *pgdp;
pmd_t *pmdp;
pte_t *ptep;
@@ -200,10 +202,15 @@ static void iounit_map_dma_area(unsigned long addr, int len)
}
}
addr += PAGE_SIZE;
+ va += PAGE_SIZE;
}
flush_cache_all();
flush_tlb_all();
}
+
+static void iounit_unmap_dma_area(unsigned long addr, int len)
+{
+}
#endif
static char *iounit_lockarea(char *vaddr, unsigned long len)
@@ -229,10 +236,11 @@ void __init ld_mmu_iounit(void)
#ifdef CONFIG_SBUS
BTFIXUPSET_CALL(mmu_map_dma_area, iounit_map_dma_area, BTFIXUPCALL_NORM);
+ BTFIXUPSET_CALL(mmu_unmap_dma_area, iounit_unmap_dma_area, BTFIXUPCALL_NORM);
#endif
}
-__u32 iounit_map_dma_init(struct linux_sbus *sbus, int size)
+__u32 iounit_map_dma_init(struct sbus_bus *sbus, int size)
{
int i, j, k, npages;
unsigned long rotor, scan, limit;
@@ -271,7 +279,7 @@ nexti: scan = find_next_zero_bit(iounit->bmap, limit, scan);
return ret;
}
-__u32 iounit_map_dma_page(__u32 vaddr, void *addr, struct linux_sbus *sbus)
+__u32 iounit_map_dma_page(__u32 vaddr, void *addr, struct sbus_bus *sbus)
{
int scan = (vaddr - IOUNIT_DMA_BASE) >> PAGE_SHIFT;
struct iounit_struct *iounit = (struct iounit_struct *)sbus->iommu;
diff --git a/arch/sparc/mm/iommu.c b/arch/sparc/mm/iommu.c
index 99f29c655..041e00c6a 100644
--- a/arch/sparc/mm/iommu.c
+++ b/arch/sparc/mm/iommu.c
@@ -1,8 +1,8 @@
-/* $Id: iommu.c,v 1.11 1999/08/31 06:54:34 davem Exp $
+/* $Id: iommu.c,v 1.16 1999/12/28 04:28:54 anton Exp $
* iommu.c: IOMMU specific routines for memory management.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- * Copyright (C) 1995 Peter A. Zaitcev (zaitcev@ithil.mcst.ru)
+ * Copyright (C) 1995 Pete Zaitcev
* Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
* Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
*/
@@ -12,10 +12,13 @@
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/malloc.h>
+#include <asm/scatterlist.h>
+#include <asm/pgalloc.h>
#include <asm/pgtable.h>
#include <asm/sbus.h>
#include <asm/io.h>
#include <asm/mxcc.h>
+#include <asm/mbus.h>
/* srmmu.c */
extern int viking_mxcc_present;
@@ -45,20 +48,23 @@ static inline void iommu_map_dvma_pages_for_iommu(struct iommu_struct *iommu)
}
void __init
-iommu_init(int iommund, struct linux_sbus *sbus)
+iommu_init(int iommund, struct sbus_bus *sbus)
{
unsigned int impl, vers, ptsize;
unsigned long tmp;
struct iommu_struct *iommu;
struct linux_prom_registers iommu_promregs[PROMREG_MAX];
+ struct resource r;
int i;
iommu = kmalloc(sizeof(struct iommu_struct), GFP_ATOMIC);
prom_getproperty(iommund, "reg", (void *) iommu_promregs,
sizeof(iommu_promregs));
+ memset(&r, 0, sizeof(r));
+ r.flags = iommu_promregs[0].which_io;
+ r.start = iommu_promregs[0].phys_addr;
iommu->regs = (struct iommu_regs *)
- sparc_alloc_io(iommu_promregs[0].phys_addr, 0, (PAGE_SIZE * 3),
- "IOMMU registers", iommu_promregs[0].which_io, 0x0);
+ sbus_ioremap(&r, 0, PAGE_SIZE * 3, "iommu_regs");
if(!iommu->regs)
panic("Cannot map IOMMU registers.");
impl = (iommu->regs->control & IOMMU_CTRL_IMPL) >> 28;
@@ -137,18 +143,18 @@ iommu_init(int iommund, struct linux_sbus *sbus)
impl, vers, iommu->page_table, ptsize);
}
-static __u32 iommu_get_scsi_one_noflush(char *vaddr, unsigned long len, struct linux_sbus *sbus)
+static __u32 iommu_get_scsi_one_noflush(char *vaddr, unsigned long len, struct sbus_bus *sbus)
{
return (__u32)vaddr;
}
-static __u32 iommu_get_scsi_one_gflush(char *vaddr, unsigned long len, struct linux_sbus *sbus)
+static __u32 iommu_get_scsi_one_gflush(char *vaddr, unsigned long len, struct sbus_bus *sbus)
{
flush_page_for_dma(0);
return (__u32)vaddr;
}
-static __u32 iommu_get_scsi_one_pflush(char *vaddr, unsigned long len, struct linux_sbus *sbus)
+static __u32 iommu_get_scsi_one_pflush(char *vaddr, unsigned long len, struct sbus_bus *sbus)
{
unsigned long page = ((unsigned long) vaddr) & PAGE_MASK;
@@ -159,81 +165,110 @@ static __u32 iommu_get_scsi_one_pflush(char *vaddr, unsigned long len, struct li
return (__u32)vaddr;
}
-static void iommu_get_scsi_sgl_noflush(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus)
+static void iommu_get_scsi_sgl_noflush(struct scatterlist *sg, int sz, struct sbus_bus *sbus)
{
- for (; sz >= 0; sz--)
- sg[sz].dvma_addr = (__u32) (sg[sz].addr);
+ for (; sz >= 0; sz--) {
+ sg[sz].dvma_address = (__u32) (sg[sz].address);
+ sg[sz].dvma_length = (__u32) (sg[sz].length);
+ }
}
-static void iommu_get_scsi_sgl_gflush(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus)
+static void iommu_get_scsi_sgl_gflush(struct scatterlist *sg, int sz, struct sbus_bus *sbus)
{
flush_page_for_dma(0);
- for (; sz >= 0; sz--)
- sg[sz].dvma_addr = (__u32) (sg[sz].addr);
+ for (; sz >= 0; sz--) {
+ sg[sz].dvma_address = (__u32) (sg[sz].address);
+ sg[sz].dvma_length = (__u32) (sg[sz].length);
+ }
}
-static void iommu_get_scsi_sgl_pflush(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus)
+static void iommu_get_scsi_sgl_pflush(struct scatterlist *sg, int sz, struct sbus_bus *sbus)
{
unsigned long page, oldpage = 0;
while(sz >= 0) {
- page = ((unsigned long) sg[sz].addr) & PAGE_MASK;
+ page = ((unsigned long) sg[sz].address) & PAGE_MASK;
if (oldpage == page)
page += PAGE_SIZE; /* We flushed that page already */
- while(page < (unsigned long)(sg[sz].addr + sg[sz].len)) {
+ while(page < (unsigned long)(sg[sz].address + sg[sz].length)) {
flush_page_for_dma(page);
page += PAGE_SIZE;
}
- sg[sz].dvma_addr = (__u32) (sg[sz].addr);
+ sg[sz].dvma_address = (__u32) (sg[sz].address);
+ sg[sz].dvma_length = (__u32) (sg[sz].length);
sz--;
oldpage = page - PAGE_SIZE;
}
}
-static void iommu_release_scsi_one(__u32 vaddr, unsigned long len, struct linux_sbus *sbus)
+static void iommu_release_scsi_one(__u32 vaddr, unsigned long len, struct sbus_bus *sbus)
{
}
-static void iommu_release_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus)
+static void iommu_release_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_bus *sbus)
{
}
#ifdef CONFIG_SBUS
-static void iommu_map_dma_area(unsigned long addr, int len)
+static void iommu_map_dma_area(unsigned long va, __u32 addr, int len)
{
- unsigned long page, end;
+ unsigned long page, end, ipte_cache;
pgprot_t dvma_prot;
- struct iommu_struct *iommu = SBus_chain->iommu;
+ struct iommu_struct *iommu = sbus_root->iommu;
iopte_t *iopte = iommu->page_table;
iopte_t *first;
- if(viking_mxcc_present)
+ if(viking_mxcc_present || srmmu_modtype == HyperSparc) {
dvma_prot = __pgprot(SRMMU_CACHE | SRMMU_ET_PTE | SRMMU_PRIV);
- else
+ ipte_cache = 1;
+ } else {
dvma_prot = __pgprot(SRMMU_ET_PTE | SRMMU_PRIV);
+ ipte_cache = 0;
+ }
iopte += ((addr - iommu->start) >> PAGE_SHIFT);
first = iopte;
end = PAGE_ALIGN((addr + len));
while(addr < end) {
- page = get_free_page(GFP_KERNEL);
- if(!page) {
- prom_printf("alloc_dvma: Cannot get a dvma page\n");
- prom_halt();
- } else {
+ page = va;
+ {
pgd_t *pgdp;
pmd_t *pmdp;
pte_t *ptep;
- pgdp = pgd_offset(init_task.mm, addr);
+ if (viking_mxcc_present)
+ viking_mxcc_flush_page(page);
+ else if (viking_flush)
+ viking_flush_page(page);
+ else
+ flush_page_to_ram(page);
+
+ pgdp = pgd_offset(&init_mm, addr);
pmdp = pmd_offset(pgdp, addr);
ptep = pte_offset(pmdp, addr);
set_pte(ptep, pte_val(mk_pte(page, dvma_prot)));
- iopte_val(*iopte++) = MKIOPTE(mmu_v2p(page));
+ if (ipte_cache != 0) {
+ iopte_val(*iopte++) = MKIOPTE(mmu_v2p(page));
+ } else {
+ iopte_val(*iopte++) =
+ MKIOPTE(mmu_v2p(page)) & ~IOPTE_CACHE;
+ }
}
addr += PAGE_SIZE;
+ va += PAGE_SIZE;
}
+ /* P3: why do we need this?
+ *
+ * DAVEM: Because there are several aspects, none of which
+ * are handled by a single interface. Some cpus are
+ * completely not I/O DMA coherent, and some have
+ * virtually indexed caches. The driver DMA flushing
+ * methods handle the former case, but here during
+ * IOMMU page table modifications, and usage of non-cacheable
+ * cpu mappings of pages potentially in the cpu caches, we have
+ * to handle the latter case as well.
+ */
flush_cache_all();
if(viking_mxcc_present) {
unsigned long start = ((unsigned long) first) & PAGE_MASK;
@@ -253,6 +288,10 @@ static void iommu_map_dma_area(unsigned long addr, int len)
flush_tlb_all();
iommu_invalidate(iommu->regs);
}
+
+static void iommu_unmap_dma_area(unsigned long addr, int len)
+{
+}
#endif
static char *iommu_lockarea(char *vaddr, unsigned long len)
@@ -287,5 +326,6 @@ void __init ld_mmu_iommu(void)
#ifdef CONFIG_SBUS
BTFIXUPSET_CALL(mmu_map_dma_area, iommu_map_dma_area, BTFIXUPCALL_NORM);
+ BTFIXUPSET_CALL(mmu_unmap_dma_area, iommu_unmap_dma_area, BTFIXUPCALL_NORM);
#endif
}
diff --git a/arch/sparc/mm/nosrmmu.c b/arch/sparc/mm/nosrmmu.c
index bae3bd140..4e49380d2 100644
--- a/arch/sparc/mm/nosrmmu.c
+++ b/arch/sparc/mm/nosrmmu.c
@@ -1,4 +1,4 @@
-/* $Id: nosrmmu.c,v 1.3 1999/08/31 06:54:35 davem Exp $
+/* $Id: nosrmmu.c,v 1.5 1999/11/19 04:11:54 davem Exp $
* nosrmmu.c: This file is a bunch of dummies for sun4 compiles,
* so that it does not need srmmu and avoid ifdefs.
*
@@ -14,6 +14,8 @@ static char shouldnothappen[] __initdata = "SUN4 kernel can only run on SUN4\n";
enum mbus_module srmmu_modtype;
+int vac_cache_size = 0;
+
static void __init should_not_happen(void)
{
prom_printf(shouldnothappen);
@@ -49,12 +51,12 @@ void __init srmmu_end_memory(unsigned long memory_size, unsigned long *mem_end_p
return 0;
}
-__u32 iounit_map_dma_init(struct linux_sbus *sbus, int size)
+__u32 iounit_map_dma_init(struct sbus_bus *sbus, int size)
{
return 0;
}
-__u32 iounit_map_dma_page(__u32 vaddr, void *addr, struct linux_sbus *sbus)
+__u32 iounit_map_dma_page(__u32 vaddr, void *addr, struct sbus_bus *sbus)
{
return 0;
}
diff --git a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c
index 5d99b02dd..c365cf0d5 100644
--- a/arch/sparc/mm/srmmu.c
+++ b/arch/sparc/mm/srmmu.c
@@ -1,8 +1,8 @@
-/* $Id: srmmu.c,v 1.192 1999/09/10 10:40:40 davem Exp $
+/* $Id: srmmu.c,v 1.199 1999/12/23 02:00:51 davem Exp $
* srmmu.c: SRMMU specific routines for memory management.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- * Copyright (C) 1995 Peter A. Zaitcev (zaitcev@ithil.mcst.ru)
+ * Copyright (C) 1995 Pete Zaitcev
* Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
* Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
*/
@@ -53,7 +53,7 @@ int vac_cache_size;
int vac_line_size;
int vac_badbits;
-extern unsigned long sparc_iobase_vaddr;
+extern struct resource sparc_iomap;
#ifdef __SMP__
#define FLUSH_BEGIN(mm)
@@ -284,7 +284,7 @@ void __init srmmu_frob_mem_map(unsigned long start_mem)
}
/* The very generic SRMMU page table operations. */
-static inline int srmmu_device_memory(unsigned long x)
+static inline int srmmu_device_memory(unsigned long x)
{
return ((x & 0xF0000000) != 0);
}
@@ -464,17 +464,6 @@ static inline pte_t *srmmu_s_pte_offset(pmd_t * dir, unsigned long address)
return (pte_t *) srmmu_s_pmd_page(*dir) + ((address >> PAGE_SHIFT) & (SRMMU_PTRS_PER_PTE - 1));
}
-/* This must update the context table entry for this process. */
-static void srmmu_update_rootmmu_dir(struct task_struct *tsk, pgd_t *pgdp)
-{
- if(tsk->mm->context != NO_CONTEXT &&
- tsk->mm->pgd != pgdp) {
- flush_cache_mm(tsk->mm);
- ctxd_set(&srmmu_context_table[tsk->mm->context], pgdp);
- flush_tlb_mm(tsk->mm);
- }
-}
-
static inline pte_t *srmmu_get_pte_fast(void)
{
struct page *ret;
@@ -777,11 +766,11 @@ static void srmmu_quick_kernel_fault(unsigned long address)
#else
printk("Kernel faults at addr=0x%08lx\n", address);
printk("PTE=%08lx\n", srmmu_hwprobe((address & PAGE_MASK)));
- die_if_kernel("SRMMU bolixed...", current->tss.kregs);
+ die_if_kernel("SRMMU bolixed...", current->thread.kregs);
#endif
}
-static inline void alloc_context(struct mm_struct *mm)
+static inline void alloc_context(struct mm_struct *old_mm, struct mm_struct *mm)
{
struct ctx_list *ctxp;
@@ -794,7 +783,7 @@ static inline void alloc_context(struct mm_struct *mm)
return;
}
ctxp = ctx_used.next;
- if(ctxp->ctx_mm == current->mm)
+ if(ctxp->ctx_mm == old_mm)
ctxp = ctxp->next;
if(ctxp == &ctx_used)
panic("out of mmu contexts");
@@ -817,29 +806,16 @@ static inline void free_context(int context)
}
-static void srmmu_switch_to_context(struct task_struct *tsk)
+static void srmmu_switch_mm(struct mm_struct *old_mm, struct mm_struct *mm,
+ struct task_struct *tsk, int cpu)
{
- if(tsk->mm->context == NO_CONTEXT) {
+ if(mm->context == NO_CONTEXT) {
spin_lock(&srmmu_context_spinlock);
- alloc_context(tsk->mm);
+ alloc_context(old_mm, mm);
spin_unlock(&srmmu_context_spinlock);
- ctxd_set(&srmmu_context_table[tsk->mm->context], tsk->mm->pgd);
+ ctxd_set(&srmmu_context_table[mm->context], mm->pgd);
}
- srmmu_set_context(tsk->mm->context);
-}
-
-static void srmmu_init_new_context(struct mm_struct *mm)
-{
- spin_lock(&srmmu_context_spinlock);
- alloc_context(mm);
- spin_unlock(&srmmu_context_spinlock);
-
- flush_cache_mm(mm);
- ctxd_set(&srmmu_context_table[mm->context], mm->pgd);
- flush_tlb_mm(mm);
-
- if(mm == current->mm)
- srmmu_set_context(mm->context);
+ srmmu_set_context(mm->context);
}
/* Low level IO area allocation on the SRMMU. */
@@ -885,9 +861,6 @@ void srmmu_unmapioaddr(unsigned long virt_addr)
flush_tlb_all();
}
-/* This is used in many routines below. */
-#define UWINMASK_OFFSET (const unsigned long)(&(((struct task_struct *)0)->tss.uwinmask))
-
/* On the SRMMU we do not have the problems with limited tlb entries
* for mapping kernel pages, so we just take things from the free page
* pool. As a side effect we are putting a little too much pressure
@@ -919,110 +892,85 @@ extern void tsunami_flush_tlb_all(void);
extern void tsunami_flush_tlb_mm(struct mm_struct *mm);
extern void tsunami_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end);
extern void tsunami_flush_tlb_page(struct vm_area_struct *vma, unsigned long page);
-
-/* Workaround, until we find what's going on with Swift. When low on memory, it sometimes
- * loops in fault/handle_mm_fault incl. flush_tlb_page to find out it is already in page tables/
- * fault again on the same instruction. I really don't understand it, have checked it and contexts
- * are right, flush_tlb_all is done as well, and it faults again... Strange. -jj
+extern void tsunami_setup_blockops(void);
+
+/* Workaround, until we find what's going on with Swift. When low on memory,
+ * it sometimes loops in fault/handle_mm_fault incl. flush_tlb_page to find
+ * out it is already in page tables/ fault again on the same instruction.
+ * I really don't understand it, have checked it and contexts
+ * are right, flush_tlb_all is done as well, and it faults again...
+ * Strange. -jj
+ *
+ * The following code is a deadwood that may be necessary when
+ * we start to make precise page flushes again. --zaitcev
*/
static void swift_update_mmu_cache(struct vm_area_struct * vma, unsigned long address, pte_t pte)
{
+#if 0
static unsigned long last;
-
- if (last == address) viking_hwprobe(address);
+ unsigned int val;
+ /* unsigned int n; */
+
+ if (address == last) {
+ val = srmmu_hwprobe(address);
+ if (val != 0 && pte_val(pte) != val) {
+ printk("swift_update_mmu_cache: "
+ "addr %lx put %08x probed %08x from %p\n",
+ address, pte_val(pte), val,
+ __builtin_return_address(0));
+ srmmu_flush_whole_tlb();
+ }
+ }
last = address;
+#endif
}
-/* Swift flushes. It has the recommended SRMMU specification flushing
- * facilities, so we can do things in a more fine grained fashion than we
- * could on the tsunami. Let's watch out for HARDWARE BUGS...
- */
-
-static void swift_flush_cache_all(void)
-{
- flush_user_windows();
- swift_idflash_clear();
-}
-
-static void swift_flush_cache_mm(struct mm_struct *mm)
-{
- FLUSH_BEGIN(mm)
- flush_user_windows();
- swift_idflash_clear();
- FLUSH_END
-}
-
-static void swift_flush_cache_range(struct mm_struct *mm, unsigned long start, unsigned long end)
-{
- FLUSH_BEGIN(mm)
- flush_user_windows();
- swift_idflash_clear();
- FLUSH_END
-}
-
-static void swift_flush_cache_page(struct vm_area_struct *vma, unsigned long page)
-{
- FLUSH_BEGIN(vma->vm_mm)
- flush_user_windows();
- if(vma->vm_flags & VM_EXEC)
- swift_flush_icache();
- swift_flush_dcache();
- FLUSH_END
-}
-
-/* Not copy-back on swift. */
-static void swift_flush_page_to_ram(unsigned long page)
-{
-}
-
-/* But not IO coherent either. */
-static void swift_flush_page_for_dma(unsigned long page)
-{
- swift_flush_dcache();
-}
-
-/* Again, Swift is non-snooping split I/D cache'd just like tsunami,
- * so have to punt the icache for on-stack signal insns. Only the
- * icache need be flushed since the dcache is write-through.
- */
-static void swift_flush_sig_insns(struct mm_struct *mm, unsigned long insn_addr)
-{
- swift_flush_icache();
-}
-
-static void swift_flush_chunk(unsigned long chunk)
-{
-}
-
-static void swift_flush_tlb_all(void)
-{
- srmmu_flush_whole_tlb();
- module_stats.invall++;
-}
-
-static void swift_flush_tlb_mm(struct mm_struct *mm)
-{
- FLUSH_BEGIN(mm)
- srmmu_flush_whole_tlb();
- module_stats.invmm++;
- FLUSH_END
-}
+/* swift.S */
+extern void swift_flush_cache_all(void);
+extern void swift_flush_cache_mm(struct mm_struct *mm);
+extern void swift_flush_cache_range(struct mm_struct *mm,
+ unsigned long start, unsigned long end);
+extern void swift_flush_cache_page(struct vm_area_struct *vma, unsigned long page);
+extern void swift_flush_page_to_ram(unsigned long page);
+extern void swift_flush_page_for_dma(unsigned long page);
+extern void swift_flush_sig_insns(struct mm_struct *mm, unsigned long insn_addr);
+extern void swift_flush_chunk(unsigned long chunk);
+extern void swift_flush_tlb_all(void);
+extern void swift_flush_tlb_mm(struct mm_struct *mm);
+extern void swift_flush_tlb_range(struct mm_struct *mm,
+ unsigned long start, unsigned long end);
+extern void swift_flush_tlb_page(struct vm_area_struct *vma, unsigned long page);
-static void swift_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end)
+#if 0 /* P3: deadwood to debug precise flushes on Swift. */
+void swift_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
{
- FLUSH_BEGIN(mm)
- srmmu_flush_whole_tlb();
- module_stats.invrnge++;
- FLUSH_END
-}
+ int cctx, ctx1;
-static void swift_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
-{
- FLUSH_BEGIN(vma->vm_mm)
- srmmu_flush_whole_tlb();
+ page &= PAGE_MASK;
+ if ((ctx1 = vma->vm_mm->context) != -1) {
+ cctx = srmmu_get_context();
+/* Is context # ever different from current context? P3 */
+ if (cctx != ctx1) {
+ printk("flush ctx %02x curr %02x\n", ctx1, cctx);
+ srmmu_set_context(ctx1);
+ swift_flush_page(page);
+ __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
+ "r" (page), "i" (ASI_M_FLUSH_PROBE));
+ srmmu_set_context(cctx);
+ } else {
+ /* Rm. prot. bits from virt. c. */
+ /* swift_flush_cache_all(); */
+ /* swift_flush_cache_page(vma, page); */
+ swift_flush_page(page);
+
+ __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
+ "r" (page), "i" (ASI_M_FLUSH_PROBE));
+ /* same as above: srmmu_flush_tlb_page() */
+ }
+ }
module_stats.invpg++;
- FLUSH_END
}
+#endif
/* The following are all MBUS based SRMMU modules, and therefore could
* be found in a multiprocessor configuration. On the whole, these
@@ -1333,103 +1281,21 @@ static void hypersparc_ctxd_set(ctxd_t *ctxp, pgd_t *pgdp)
hyper_flush_whole_icache();
}
-static void hypersparc_update_rootmmu_dir(struct task_struct *tsk, pgd_t *pgdp)
+static void hypersparc_switch_mm(struct mm_struct *old_mm,
+ struct mm_struct *mm, struct task_struct *tsk, int cpu)
{
- unsigned long page = ((unsigned long) pgdp) & PAGE_MASK;
-
- if(pgdp != swapper_pg_dir)
- hypersparc_flush_page_to_ram(page);
-
- if(tsk->mm->context != NO_CONTEXT &&
- tsk->mm->pgd != pgdp) {
- flush_cache_mm(tsk->mm);
- ctxd_set(&srmmu_context_table[tsk->mm->context], pgdp);
- flush_tlb_mm(tsk->mm);
- }
-}
-
-static void viking_update_rootmmu_dir(struct task_struct *tsk, pgd_t *pgdp)
-{
- if(pgdp != swapper_pg_dir)
- flush_chunk((unsigned long)pgdp);
- if(tsk->mm->context != NO_CONTEXT &&
- tsk->mm->pgd != pgdp) {
- flush_cache_mm(tsk->mm);
- ctxd_set(&srmmu_context_table[tsk->mm->context], pgdp);
- flush_tlb_mm(tsk->mm);
- }
-}
-
-static void cypress_update_rootmmu_dir(struct task_struct *tsk, pgd_t *pgdp)
-{
- register unsigned long a, b, c, d, e, f, g;
- unsigned long page = ((unsigned long) pgdp) & PAGE_MASK;
- unsigned long line;
-
- if(pgdp == swapper_pg_dir)
- goto skip_flush;
-
- a = 0x20; b = 0x40; c = 0x60; d = 0x80; e = 0xa0; f = 0xc0; g = 0xe0;
- page &= PAGE_MASK;
- line = (page + PAGE_SIZE) - 0x100;
- goto inside;
- do {
- line -= 0x100;
- inside:
- __asm__ __volatile__("sta %%g0, [%0] %1\n\t"
- "sta %%g0, [%0 + %2] %1\n\t"
- "sta %%g0, [%0 + %3] %1\n\t"
- "sta %%g0, [%0 + %4] %1\n\t"
- "sta %%g0, [%0 + %5] %1\n\t"
- "sta %%g0, [%0 + %6] %1\n\t"
- "sta %%g0, [%0 + %7] %1\n\t"
- "sta %%g0, [%0 + %8] %1\n\t" : :
- "r" (line),
- "i" (ASI_M_FLUSH_PAGE),
- "r" (a), "r" (b), "r" (c), "r" (d),
- "r" (e), "r" (f), "r" (g));
- } while(line != page);
-skip_flush:
- if(tsk->mm->context != NO_CONTEXT &&
- tsk->mm->pgd != pgdp) {
- flush_cache_mm(tsk->mm);
- ctxd_set(&srmmu_context_table[tsk->mm->context], pgdp);
- flush_tlb_mm(tsk->mm);
- }
-}
-
-static void hypersparc_switch_to_context(struct task_struct *tsk)
-{
- if(tsk->mm->context == NO_CONTEXT) {
+ if(mm->context == NO_CONTEXT) {
ctxd_t *ctxp;
spin_lock(&srmmu_context_spinlock);
- alloc_context(tsk->mm);
+ alloc_context(old_mm, mm);
spin_unlock(&srmmu_context_spinlock);
- ctxp = &srmmu_context_table[tsk->mm->context];
- srmmu_set_entry((pte_t *)ctxp, __pte((SRMMU_ET_PTD | (srmmu_v2p((unsigned long) tsk->mm->pgd) >> 4))));
+ ctxp = &srmmu_context_table[mm->context];
+ srmmu_set_entry((pte_t *)ctxp, __pte((SRMMU_ET_PTD | (srmmu_v2p((unsigned long) mm->pgd) >> 4))));
hypersparc_flush_page_to_ram((unsigned long)ctxp);
}
hyper_flush_whole_icache();
- srmmu_set_context(tsk->mm->context);
-}
-
-static void hypersparc_init_new_context(struct mm_struct *mm)
-{
- ctxd_t *ctxp;
-
- spin_lock(&srmmu_context_spinlock);
- alloc_context(mm);
- spin_unlock(&srmmu_context_spinlock);
-
- ctxp = &srmmu_context_table[mm->context];
- srmmu_set_entry((pte_t *)ctxp, __pte((SRMMU_ET_PTD | (srmmu_v2p((unsigned long) mm->pgd) >> 4))));
- hypersparc_flush_page_to_ram((unsigned long)ctxp);
-
- if(mm == current->mm) {
- hyper_flush_whole_icache();
- srmmu_set_context(mm->context);
- }
+ srmmu_set_context(mm->context);
}
static unsigned long mempool;
@@ -1694,7 +1560,8 @@ static unsigned long __init map_spbank(unsigned long vbase, int sp_entry)
srmmu_map[srmmu_bank].vbase = vbase;
srmmu_map[srmmu_bank].pbase = sp_banks[sp_entry].base_addr;
srmmu_map[srmmu_bank].size = sp_banks[sp_entry].num_bytes;
- srmmu_bank++;
+ if (srmmu_map[srmmu_bank].size)
+ srmmu_bank++;
map_spbank_last_pa = pstart - SRMMU_PGDIR_SIZE;
return vstart;
}
@@ -1949,8 +1816,8 @@ unsigned long __init srmmu_paging_init(unsigned long start_mem, unsigned long en
int i, cpunode;
char node_str[128];
- sparc_iobase_vaddr = 0xfd000000; /* 16MB of IOSPACE on all sun4m's. */
- physmem_mapped_contig = 0; /* for init.c:taint_real_pages() */
+ sparc_iomap.start = 0xfd000000; /* 16MB of IOSPACE on all sun4m's. */
+ physmem_mapped_contig = 0; /* for init.c:taint_real_pages() */
if (sparc_cpu_model == sun4d)
num_contexts = 65536; /* We know it is Viking */
@@ -1981,7 +1848,7 @@ unsigned long __init srmmu_paging_init(unsigned long start_mem, unsigned long en
srmmu_allocate_ptable_skeleton(KERNBASE, end_mem);
#if CONFIG_SUN_IO
- srmmu_allocate_ptable_skeleton(sparc_iobase_vaddr, IOBASE_END);
+ srmmu_allocate_ptable_skeleton(sparc_iomap.start, IOBASE_END);
srmmu_allocate_ptable_skeleton(DVMA_VADDR, DVMA_END);
#endif
@@ -2051,16 +1918,14 @@ static void srmmu_update_mmu_cache(struct vm_area_struct * vma, unsigned long ad
static void srmmu_destroy_context(struct mm_struct *mm)
{
- if(mm->context != NO_CONTEXT && atomic_read(&mm->count) == 1) {
- /* XXX This could be drastically improved.
- * XXX We are only called from __exit_mm and it just did
- * XXX cache/tlb mm flush and right after this will (re-)
- * XXX SET_PAGE_DIR to swapper_pg_dir. -DaveM
- */
+
+ if(mm->context != NO_CONTEXT) {
flush_cache_mm(mm);
ctxd_set(&srmmu_context_table[mm->context], swapper_pg_dir);
flush_tlb_mm(mm);
+ spin_lock(&srmmu_context_spinlock);
free_context(mm->context);
+ spin_unlock(&srmmu_context_spinlock);
mm->context = NO_CONTEXT;
}
}
@@ -2136,7 +2001,7 @@ static void srmmu_vac_update_mmu_cache(struct vm_area_struct * vma,
static void hypersparc_destroy_context(struct mm_struct *mm)
{
- if(mm->context != NO_CONTEXT && atomic_read(&mm->count) == 1) {
+ if(mm->context != NO_CONTEXT) {
ctxd_t *ctxp;
/* HyperSparc is copy-back, any data for this
@@ -2151,7 +2016,9 @@ static void hypersparc_destroy_context(struct mm_struct *mm)
hypersparc_flush_page_to_ram((unsigned long)ctxp);
flush_tlb_mm(mm);
+ spin_lock(&srmmu_context_spinlock);
free_context(mm->context);
+ spin_unlock(&srmmu_context_spinlock);
mm->context = NO_CONTEXT;
}
}
@@ -2267,11 +2134,9 @@ static void __init init_hypersparc(void)
BTFIXUPSET_CALL(flush_chunk, hypersparc_flush_chunk, BTFIXUPCALL_NORM); /* local flush _only_ */
BTFIXUPSET_CALL(ctxd_set, hypersparc_ctxd_set, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(switch_to_context, hypersparc_switch_to_context, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(init_new_context, hypersparc_init_new_context, BTFIXUPCALL_NORM);
+ BTFIXUPSET_CALL(switch_mm, hypersparc_switch_mm, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(destroy_context, hypersparc_destroy_context, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(update_mmu_cache, srmmu_vac_update_mmu_cache, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(sparc_update_rootmmu_dir, hypersparc_update_rootmmu_dir, BTFIXUPCALL_NORM);
poke_srmmu = poke_hypersparc;
hypersparc_setup_blockops();
@@ -2339,7 +2204,6 @@ static void __init init_cypress_common(void)
BTFIXUPSET_CALL(flush_page_to_ram, cypress_flush_page_to_ram, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(flush_sig_insns, cypress_flush_sig_insns, BTFIXUPCALL_NOP);
BTFIXUPSET_CALL(flush_page_for_dma, cypress_flush_page_for_dma, BTFIXUPCALL_NOP);
- BTFIXUPSET_CALL(sparc_update_rootmmu_dir, cypress_update_rootmmu_dir, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(update_mmu_cache, srmmu_vac_update_mmu_cache, BTFIXUPCALL_NORM);
poke_srmmu = poke_cypress;
@@ -2371,12 +2235,14 @@ static void __init init_cypress_605(unsigned long mrev)
static void __init poke_swift(void)
{
- unsigned long mreg = srmmu_get_mmureg();
+ unsigned long mreg;
/* Clear any crap from the cache or else... */
- swift_idflash_clear();
- mreg |= (SWIFT_IE | SWIFT_DE); /* I & D caches on */
+ swift_flush_cache_all();
+ /* Enable I & D caches */
+ mreg = srmmu_get_mmureg();
+ mreg |= (SWIFT_IE | SWIFT_DE);
/* The Swift branch folding logic is completely broken. At
* trap time, if things are just right, if can mistakenly
* think that a trap is coming from kernel mode when in fact
@@ -2442,19 +2308,21 @@ static void __init init_swift(void)
BTFIXUPSET_CALL(flush_cache_page, swift_flush_cache_page, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(flush_cache_range, swift_flush_cache_range, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_chunk, swift_flush_chunk, BTFIXUPCALL_NOP); /* local flush _only_ */
+ BTFIXUPSET_CALL(flush_chunk, swift_flush_chunk, BTFIXUPCALL_NORM); /* local flush _only_ */
BTFIXUPSET_CALL(flush_tlb_all, swift_flush_tlb_all, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(flush_tlb_mm, swift_flush_tlb_mm, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(flush_tlb_page, swift_flush_tlb_page, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(flush_tlb_range, swift_flush_tlb_range, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_page_to_ram, swift_flush_page_to_ram, BTFIXUPCALL_NOP);
+ BTFIXUPSET_CALL(flush_page_to_ram, swift_flush_page_to_ram, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(flush_sig_insns, swift_flush_sig_insns, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(flush_page_for_dma, swift_flush_page_for_dma, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(update_mmu_cache, swift_update_mmu_cache, BTFIXUPCALL_NORM);
+ flush_page_for_dma_global = 0;
+
/* Are you now convinced that the Swift is one of the
* biggest VLSI abortions of all time? Bravo Fujitsu!
* Fujitsu, the !#?!%$'d up processor people. I bet if
@@ -2611,7 +2479,7 @@ static void __init init_turbosparc(void)
BTFIXUPSET_CALL(flush_chunk, turbosparc_flush_chunk, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(flush_sig_insns, turbosparc_flush_sig_insns, BTFIXUPCALL_NOP);
- BTFIXUPSET_CALL(flush_page_for_dma, turbosparc_flush_page_for_dma, BTFIXUPCALL_NOP);
+ BTFIXUPSET_CALL(flush_page_for_dma, turbosparc_flush_page_for_dma, BTFIXUPCALL_NORM);
poke_srmmu = poke_turbosparc;
}
@@ -2642,7 +2510,7 @@ static void __init init_tsunami(void)
BTFIXUPSET_CALL(flush_cache_page, tsunami_flush_cache_page, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(flush_cache_range, tsunami_flush_cache_range, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_chunk, tsunami_flush_chunk, BTFIXUPCALL_NOP); /* local flush _only_ */
+ BTFIXUPSET_CALL(flush_chunk, tsunami_flush_chunk, BTFIXUPCALL_NORM); /* local flush _only_ */
BTFIXUPSET_CALL(flush_tlb_all, tsunami_flush_tlb_all, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(flush_tlb_mm, tsunami_flush_tlb_mm, BTFIXUPCALL_NORM);
@@ -2654,6 +2522,8 @@ static void __init init_tsunami(void)
BTFIXUPSET_CALL(flush_page_for_dma, tsunami_flush_page_for_dma, BTFIXUPCALL_NORM);
poke_srmmu = poke_tsunami;
+
+ tsunami_setup_blockops();
}
static void __init poke_viking(void)
@@ -2725,7 +2595,6 @@ static void __init init_viking(void)
BTFIXUPSET_CALL(pte_clear, srmmu_pte_clear, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(pmd_clear, srmmu_pmd_clear, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(pgd_clear, srmmu_pgd_clear, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(sparc_update_rootmmu_dir, viking_update_rootmmu_dir, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(flush_chunk, viking_flush_chunk, BTFIXUPCALL_NORM); /* local flush _only_ */
@@ -2736,8 +2605,7 @@ static void __init init_viking(void)
* which we use the IOMMU.
*/
BTFIXUPSET_CALL(flush_page_for_dma, viking_flush_page, BTFIXUPCALL_NORM);
- /* Also, this is so far the only chip which actually uses
- the page argument to flush_page_for_dma */
+
flush_page_for_dma_global = 0;
} else {
srmmu_name = "TI Viking/MXCC";
@@ -2928,6 +2796,16 @@ static int srmmu_check_pgt_cache(int low, int high)
return freed;
}
+static void srmmu_flush_dma_area(unsigned long addr, int len)
+{
+ /* XXX Later */
+}
+
+static void srmmu_inval_dma_area(unsigned long addr, int len)
+{
+ /* XXX Later */
+}
+
extern unsigned long spwin_mmu_patchme, fwin_mmu_patchme,
tsetup_mmu_patchme, rtrap_mmu_patchme;
@@ -2999,21 +2877,18 @@ void __init ld_mmu_srmmu(void)
BTFIXUPSET_CALL(free_pte_slow, srmmu_free_pte_slow, BTFIXUPCALL_NOP);
BTFIXUPSET_CALL(free_pgd_slow, srmmu_free_pgd_slow, BTFIXUPCALL_NOP);
BTFIXUPSET_CALL(do_check_pgt_cache, srmmu_check_pgt_cache, BTFIXUPCALL_NORM);
-
+
BTFIXUPSET_CALL(set_pgdir, srmmu_set_pgdir, BTFIXUPCALL_NORM);
-
+
BTFIXUPSET_CALL(set_pte, srmmu_set_pte_cacheable, BTFIXUPCALL_SWAPO0O1);
- BTFIXUPSET_CALL(init_new_context, srmmu_init_new_context, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(switch_to_context, srmmu_switch_to_context, BTFIXUPCALL_NORM);
+ BTFIXUPSET_CALL(switch_mm, srmmu_switch_mm, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(pte_page, srmmu_pte_page, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(pmd_page, srmmu_pmd_page, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(pgd_page, srmmu_pgd_page, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(sparc_update_rootmmu_dir, srmmu_update_rootmmu_dir, BTFIXUPCALL_NORM);
+ BTFIXUPSET_SETHI(none_mask, 0xF0000000); /* P3: is it used? */
- BTFIXUPSET_SETHI(none_mask, 0xF0000000);
-
BTFIXUPSET_CALL(pte_present, srmmu_pte_present, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(pte_clear, srmmu_pte_clear, BTFIXUPCALL_SWAPO0G0);
@@ -3072,6 +2947,11 @@ void __init ld_mmu_srmmu(void)
BTFIXUPSET_CALL(ctxd_set, srmmu_ctxd_set, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(pmd_set, srmmu_pmd_set, BTFIXUPCALL_NORM);
+/* hmm isn't flush_dma_area the same thing as flush_page_for_dma? */
+/* It is, except flush_page_for_dma was local to srmmu.c */
+ BTFIXUPSET_CALL(mmu_flush_dma_area, srmmu_flush_dma_area, BTFIXUPCALL_NORM);
+ BTFIXUPSET_CALL(mmu_inval_dma_area, srmmu_inval_dma_area, BTFIXUPCALL_NORM);
+
get_srmmu_type();
patch_window_trap_handlers();
@@ -3104,6 +2984,7 @@ void __init ld_mmu_srmmu(void)
BTFIXUPSET_CALL(flush_sig_insns, smp_flush_sig_insns, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(flush_page_for_dma, smp_flush_page_for_dma, BTFIXUPCALL_NORM);
#endif
+
if (sparc_cpu_model == sun4d)
ld_mmu_iounit();
else
diff --git a/arch/sparc/mm/sun4c.c b/arch/sparc/mm/sun4c.c
index f91ab1ce6..0530e635f 100644
--- a/arch/sparc/mm/sun4c.c
+++ b/arch/sparc/mm/sun4c.c
@@ -1,19 +1,24 @@
-/* $Id: sun4c.c,v 1.176 1999/08/31 06:54:42 davem Exp $
+/* $Id: sun4c.c,v 1.182 1999/12/27 06:30:04 anton Exp $
* sun4c.c: Doing in software what should be done in hardware.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
* Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
* Copyright (C) 1996 Andrew Tridgell (Andrew.Tridgell@anu.edu.au)
- * Copyright (C) 1997 Anton Blanchard (anton@progsoc.uts.edu.au)
+ * Copyright (C) 1997,99 Anton Blanchard (anton@progsoc.uts.edu.au)
* Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
*/
+#define NR_TASK_BUCKETS 512
+
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/init.h>
+#include <linux/bootmem.h>
+#include <asm/scatterlist.h>
#include <asm/page.h>
+#include <asm/pgalloc.h>
#include <asm/pgtable.h>
#include <asm/vaddrs.h>
#include <asm/idprom.h>
@@ -27,42 +32,19 @@
#include <asm/mmu_context.h>
#include <asm/sun4paddr.h>
-/* TODO: Make it such that interrupt handlers cannot dick with
- * the user segment lists, most of the cli/sti pairs can
- * disappear once that is taken care of.
- */
-
-/* XXX Ok the real performance win, I figure, will be to use a combined hashing
- * XXX and bitmap scheme to keep track of what we have mapped where. The whole
- * XXX incentive is to make it such that the range flushes can be serviced
- * XXX always in near constant time. --DaveM
+/* Because of our dynamic kernel TLB miss strategy, and how
+ * our DVMA mapping allocation works, you _MUST_:
+ *
+ * 1) Disable interrupts _and_ not touch any dynamic kernel
+ * memory while messing with kernel MMU state. By
+ * dynamic memory I mean any object which is not in
+ * the kernel image itself or a task_struct (both of
+ * which are locked into the MMU).
+ * 2) Disable interrupts while messing with user MMU state.
*/
extern int num_segmaps, num_contexts;
-/* Define this to get extremely anal debugging, undefine for performance. */
-/* #define DEBUG_SUN4C_MM */
-
-#define UWINMASK_OFFSET (const unsigned long)(&(((struct task_struct *)0)->tss.uwinmask))
-
-/* This is used in many routines below. */
-#define FUW_INLINE do { \
- register int ctr asm("g5"); \
- ctr = 0; \
- __asm__ __volatile__("\n" \
- "1: ld [%%g6 + %2], %%g4 ! flush user windows\n" \
- " orcc %%g0, %%g4, %%g0\n" \
- " add %0, 1, %0\n" \
- " bne 1b\n" \
- " save %%sp, -64, %%sp\n" \
- "2: subcc %0, 1, %0\n" \
- " bne 2b\n" \
- " restore %%g0, %%g0, %%g0\n" \
- : "=&r" (ctr) \
- : "0" (ctr), "i" (UWINMASK_OFFSET) \
- : "g4", "cc"); \
-} while(0);
-
#ifdef CONFIG_SUN4
#define SUN4C_VAC_SIZE sun4c_vacinfo.num_bytes
#else
@@ -82,58 +64,21 @@ extern int num_segmaps, num_contexts;
#define MIN(a,b) ((a)<(b)?(a):(b))
#endif
-
-#define KGPROF_PROFILING 0
-#if KGPROF_PROFILING
-#define KGPROF_DEPTH 3 /* this needs to match the code below */
-#define KGPROF_SIZE 100
-static struct {
- unsigned addr[KGPROF_DEPTH];
- unsigned count;
-} kgprof_counters[KGPROF_SIZE];
-
-/* just call this function from whatever function you think needs it then
- look at /proc/cpuinfo to see where the function is being called from
- and how often. This gives a type of "kernel gprof" */
-#define NEXT_PROF(prev,lvl) (prev>PAGE_OFFSET?__builtin_return_address(lvl):0)
-static inline void kgprof_profile(void)
-{
- unsigned ret[KGPROF_DEPTH];
- int i,j;
- /* you can't use a variable argument to __builtin_return_address() */
- ret[0] = (unsigned)__builtin_return_address(0);
- ret[1] = (unsigned)NEXT_PROF(ret[0],1);
- ret[2] = (unsigned)NEXT_PROF(ret[1],2);
-
- for (i=0;i<KGPROF_SIZE && kgprof_counters[i].addr[0];i++) {
- for (j=0;j<KGPROF_DEPTH;j++)
- if (ret[j] != kgprof_counters[i].addr[j]) break;
- if (j==KGPROF_DEPTH) break;
- }
- if (i<KGPROF_SIZE) {
- for (j=0;j<KGPROF_DEPTH;j++)
- kgprof_counters[i].addr[j] = ret[j];
- kgprof_counters[i].count++;
- }
-}
-#endif
-
-
/* Flushing the cache. */
struct sun4c_vac_props sun4c_vacinfo;
-static int ctxflushes, segflushes, pageflushes;
unsigned long sun4c_kernel_faults;
/* convert a virtual address to a physical address and vice
- versa. Easy on the 4c */
+ * versa. Easy on the 4c
+ */
static unsigned long sun4c_v2p(unsigned long vaddr)
{
- return(vaddr - PAGE_OFFSET);
+ return (vaddr - PAGE_OFFSET);
}
static unsigned long sun4c_p2v(unsigned long vaddr)
{
- return(vaddr + PAGE_OFFSET);
+ return (vaddr + PAGE_OFFSET);
}
@@ -142,44 +87,64 @@ void sun4c_flush_all(void)
{
unsigned long begin, end;
- if(sun4c_vacinfo.on)
+ if (sun4c_vacinfo.on)
panic("SUN4C: AIEEE, trying to invalidate vac while"
" it is on.");
/* Clear 'valid' bit in all cache line tags */
begin = AC_CACHETAGS;
end = (AC_CACHETAGS + SUN4C_VAC_SIZE);
- while(begin < end) {
+ while (begin < end) {
__asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
"r" (begin), "i" (ASI_CONTROL));
begin += sun4c_vacinfo.linesize;
}
}
-/* Context level flush. */
-static inline void sun4c_flush_context_hw(void)
+static __inline__ void sun4c_flush_context_hw(void)
{
unsigned long end = SUN4C_VAC_SIZE;
- unsigned pgsz = PAGE_SIZE;
- ctxflushes++;
- __asm__ __volatile__("
-1: subcc %0, %2, %0
- bg 1b
- sta %%g0, [%0] %3
- nop; nop; nop; ! Weitek hwbug
-" : "=&r" (end)
- : "0" (end), "r" (pgsz), "i" (ASI_HWFLUSHCONTEXT)
+ __asm__ __volatile__(
+ "1: addcc %0, -4096, %0\n\t"
+ " bne 1b\n\t"
+ " sta %%g0, [%0] %2"
+ : "=&r" (end)
+ : "0" (end), "i" (ASI_HWFLUSHCONTEXT)
: "cc");
}
+/* Must be called minimally with IRQs disabled. */
+static void sun4c_flush_segment_hw(unsigned long addr)
+{
+ if (sun4c_get_segmap(addr) != invalid_segment) {
+ unsigned long vac_size = SUN4C_VAC_SIZE;
+
+ __asm__ __volatile__(
+ "1: addcc %0, -4096, %0\n\t"
+ " bne 1b\n\t"
+ " sta %%g0, [%2 + %0] %3"
+ : "=&r" (vac_size)
+ : "0" (vac_size), "r" (addr), "i" (ASI_HWFLUSHSEG)
+ : "cc");
+ }
+}
+
+/* Must be called minimally with interrupts disabled. */
+static __inline__ void sun4c_flush_page_hw(unsigned long addr)
+{
+ addr &= PAGE_MASK;
+ if ((int)sun4c_get_pte(addr) < 0)
+ __asm__ __volatile__("sta %%g0, [%0] %1"
+ : : "r" (addr), "i" (ASI_HWFLUSHPAGE));
+}
+
/* Don't inline the software version as it eats too many cache lines if expanded. */
static void sun4c_flush_context_sw(void)
{
unsigned long nbytes = SUN4C_VAC_SIZE;
unsigned long lsize = sun4c_vacinfo.linesize;
- ctxflushes++;
__asm__ __volatile__("
add %2, %2, %%g1
add %2, %%g1, %%g2
@@ -203,72 +168,13 @@ static void sun4c_flush_context_sw(void)
: "g1", "g2", "g3", "g4", "g5", "o4", "o5", "cc");
}
-/* Scrape the segment starting at ADDR from the virtual cache. */
-static inline void sun4c_flush_segment(unsigned long addr)
-{
- if(sun4c_get_segmap(addr) == invalid_segment)
- return;
-
- segflushes++;
- if(sun4c_vacinfo.do_hwflushes) {
- unsigned long end = (addr + SUN4C_VAC_SIZE);
-
- for( ; addr < end; addr += PAGE_SIZE)
- __asm__ __volatile__("sta %%g0, [%0] %1;nop;nop;nop;\n\t" : :
- "r" (addr), "i" (ASI_HWFLUSHSEG));
- } else {
- unsigned long nbytes = SUN4C_VAC_SIZE;
- unsigned long lsize = sun4c_vacinfo.linesize;
-
- __asm__ __volatile__("add %2, %2, %%g1\n\t"
- "add %2, %%g1, %%g2\n\t"
- "add %2, %%g2, %%g3\n\t"
- "add %2, %%g3, %%g4\n\t"
- "add %2, %%g4, %%g5\n\t"
- "add %2, %%g5, %%o4\n\t"
- "add %2, %%o4, %%o5\n"
- "1:\n\t"
- "subcc %1, %%o5, %1\n\t"
- "sta %%g0, [%0] %6\n\t"
- "sta %%g0, [%0 + %2] %6\n\t"
- "sta %%g0, [%0 + %%g1] %6\n\t"
- "sta %%g0, [%0 + %%g2] %6\n\t"
- "sta %%g0, [%0 + %%g3] %6\n\t"
- "sta %%g0, [%0 + %%g4] %6\n\t"
- "sta %%g0, [%0 + %%g5] %6\n\t"
- "sta %%g0, [%0 + %%o4] %6\n\t"
- "bg 1b\n\t"
- " add %0, %%o5, %0\n\t"
- : "=&r" (addr), "=&r" (nbytes), "=&r" (lsize)
- : "0" (addr), "1" (nbytes), "2" (lsize),
- "i" (ASI_FLUSHSEG)
- : "g1", "g2", "g3", "g4", "g5", "o4", "o5", "cc");
- }
-}
-
-/* Call this version when you know hardware flushes are available. */
-static inline void sun4c_flush_segment_hw(unsigned long addr)
-{
- if(sun4c_get_segmap(addr) != invalid_segment) {
- unsigned long end;
-
- segflushes++;
- for(end = addr + SUN4C_VAC_SIZE; addr < end; addr += PAGE_SIZE)
- __asm__ __volatile__("sta %%g0, [%0] %1"
- : : "r" (addr), "i" (ASI_HWFLUSHSEG));
- /* Weitek POWER-UP hwbug workaround. */
- __asm__ __volatile__("nop;nop;nop; ! Weitek hwbug");
- }
-}
-
/* Don't inline the software version as it eats too many cache lines if expanded. */
static void sun4c_flush_segment_sw(unsigned long addr)
{
- if(sun4c_get_segmap(addr) != invalid_segment) {
+ if (sun4c_get_segmap(addr) != invalid_segment) {
unsigned long nbytes = SUN4C_VAC_SIZE;
unsigned long lsize = sun4c_vacinfo.linesize;
- segflushes++;
__asm__ __volatile__("
add %2, %2, %%g1
add %2, %%g1, %%g2
@@ -300,12 +206,11 @@ static void sun4c_flush_page(unsigned long addr)
{
addr &= PAGE_MASK;
- if((sun4c_get_pte(addr) & (_SUN4C_PAGE_NOCACHE | _SUN4C_PAGE_VALID)) !=
- _SUN4C_PAGE_VALID)
+ if ((sun4c_get_pte(addr) & (_SUN4C_PAGE_NOCACHE | _SUN4C_PAGE_VALID)) !=
+ _SUN4C_PAGE_VALID)
return;
- pageflushes++;
- if(sun4c_vacinfo.do_hwflushes) {
+ if (sun4c_vacinfo.do_hwflushes) {
__asm__ __volatile__("sta %%g0, [%0] %1;nop;nop;nop;\n\t" : :
"r" (addr), "i" (ASI_HWFLUSHPAGE));
} else {
@@ -338,30 +243,15 @@ static void sun4c_flush_page(unsigned long addr)
}
}
-/* Again, hw-only and sw-only cache page-level flush variants. */
-static inline void sun4c_flush_page_hw(unsigned long addr)
-{
- addr &= PAGE_MASK;
- if((sun4c_get_pte(addr) & (_SUN4C_PAGE_NOCACHE | _SUN4C_PAGE_VALID)) ==
- _SUN4C_PAGE_VALID) {
- pageflushes++;
- __asm__ __volatile__("sta %%g0, [%0] %1"
- : : "r" (addr), "i" (ASI_HWFLUSHPAGE));
- /* Weitek POWER-UP hwbug workaround. */
- __asm__ __volatile__("nop;nop;nop; ! Weitek hwbug");
- }
-}
-
/* Don't inline the software version as it eats too many cache lines if expanded. */
static void sun4c_flush_page_sw(unsigned long addr)
{
addr &= PAGE_MASK;
- if((sun4c_get_pte(addr) & (_SUN4C_PAGE_NOCACHE | _SUN4C_PAGE_VALID)) ==
- _SUN4C_PAGE_VALID) {
+ if ((sun4c_get_pte(addr) & (_SUN4C_PAGE_NOCACHE | _SUN4C_PAGE_VALID)) ==
+ _SUN4C_PAGE_VALID) {
unsigned long left = PAGE_SIZE;
unsigned long lsize = sun4c_vacinfo.linesize;
- pageflushes++;
__asm__ __volatile__("
add %2, %2, %%g1
add %2, %%g1, %%g2
@@ -411,7 +301,7 @@ static inline void sun4c_init_clean_segmap(unsigned char pseg)
unsigned long vaddr;
sun4c_put_segmap(0, pseg);
- for(vaddr = 0; vaddr < SUN4C_REAL_PGDIR_SIZE; vaddr+=PAGE_SIZE)
+ for (vaddr = 0; vaddr < SUN4C_REAL_PGDIR_SIZE; vaddr += PAGE_SIZE)
sun4c_put_pte(vaddr, 0);
sun4c_put_segmap(0, invalid_segment);
}
@@ -423,15 +313,15 @@ static inline void sun4c_init_clean_mmu(unsigned long kernel_end)
savectx = sun4c_get_context();
kernel_end = SUN4C_REAL_PGDIR_ALIGN(kernel_end);
- for(ctx = 0; ctx < num_contexts; ctx++) {
+ for (ctx = 0; ctx < num_contexts; ctx++) {
sun4c_set_context(ctx);
- for(vaddr = 0; vaddr < 0x20000000; vaddr += SUN4C_REAL_PGDIR_SIZE)
+ for (vaddr = 0; vaddr < 0x20000000; vaddr += SUN4C_REAL_PGDIR_SIZE)
sun4c_put_segmap(vaddr, invalid_segment);
- for(vaddr = 0xe0000000; vaddr < KERNBASE; vaddr += SUN4C_REAL_PGDIR_SIZE)
+ for (vaddr = 0xe0000000; vaddr < KERNBASE; vaddr += SUN4C_REAL_PGDIR_SIZE)
sun4c_put_segmap(vaddr, invalid_segment);
- for(vaddr = kernel_end; vaddr < KADB_DEBUGGER_BEGVM; vaddr += SUN4C_REAL_PGDIR_SIZE)
+ for (vaddr = kernel_end; vaddr < KADB_DEBUGGER_BEGVM; vaddr += SUN4C_REAL_PGDIR_SIZE)
sun4c_put_segmap(vaddr, invalid_segment);
- for(vaddr = LINUX_OPPROM_ENDVM; vaddr; vaddr += SUN4C_REAL_PGDIR_SIZE)
+ for (vaddr = LINUX_OPPROM_ENDVM; vaddr; vaddr += SUN4C_REAL_PGDIR_SIZE)
sun4c_put_segmap(vaddr, invalid_segment);
}
sun4c_set_context(savectx);
@@ -442,7 +332,7 @@ void __init sun4c_probe_vac(void)
sun4c_disable_vac();
if (ARCH_SUN4) {
- switch(idprom->id_machtype) {
+ switch (idprom->id_machtype) {
case (SM_SUN4|SM_4_110):
sun4c_vacinfo.type = NONE;
@@ -477,12 +367,12 @@ void __init sun4c_probe_vac(void)
default:
prom_printf("Cannot initialize VAC - wierd sun4 model idprom->id_machtype = %d", idprom->id_machtype);
prom_halt();
- }
+ };
} else {
sun4c_vacinfo.type = WRITE_THROUGH;
- if((idprom->id_machtype == (SM_SUN4C | SM_4C_SS1)) ||
- (idprom->id_machtype == (SM_SUN4C | SM_4C_SS1PLUS))) {
+ if ((idprom->id_machtype == (SM_SUN4C | SM_4C_SS1)) ||
+ (idprom->id_machtype == (SM_SUN4C | SM_4C_SS1PLUS))) {
/* PROM on SS1 lacks this info, to be super safe we
* hard code it here since this arch is cast in stone.
*/
@@ -497,7 +387,7 @@ void __init sun4c_probe_vac(void)
sun4c_vacinfo.do_hwflushes =
prom_getintdefault(prom_root_node, "vac-hwflush", 0);
- if(sun4c_vacinfo.do_hwflushes == 0)
+ if (sun4c_vacinfo.do_hwflushes == 0)
sun4c_vacinfo.do_hwflushes =
prom_getintdefault(prom_root_node, "vac_hwflush", 0);
@@ -509,7 +399,7 @@ void __init sun4c_probe_vac(void)
sun4c_vacinfo.num_lines =
(sun4c_vacinfo.num_bytes / sun4c_vacinfo.linesize);
- switch(sun4c_vacinfo.linesize) {
+ switch (sun4c_vacinfo.linesize) {
case 16:
sun4c_vacinfo.log2lsize = 4;
break;
@@ -566,7 +456,7 @@ static void patch_kernel_fault_handler(void)
prom_printf("Unhandled number of segmaps: %d\n",
num_segmaps);
prom_halt();
- }
+ };
switch (num_contexts) {
case 8:
/* Default, nothing to do. */
@@ -574,19 +464,22 @@ static void patch_kernel_fault_handler(void)
case 16:
PATCH_INSN(num_context_patch1_16,
num_context_patch1);
+#if 0
PATCH_INSN(num_context_patch2_16,
num_context_patch2);
+#endif
break;
default:
prom_printf("Unhandled number of contexts: %d\n",
num_contexts);
prom_halt();
- }
- if(sun4c_vacinfo.do_hwflushes != 0) {
+ };
+
+ if (sun4c_vacinfo.do_hwflushes != 0) {
PATCH_INSN(vac_hwflush_patch1_on, vac_hwflush_patch1);
PATCH_INSN(vac_hwflush_patch2_on, vac_hwflush_patch2);
} else {
- switch(sun4c_vacinfo.linesize) {
+ switch (sun4c_vacinfo.linesize) {
case 16:
/* Default, nothing to do. */
break;
@@ -604,7 +497,7 @@ static void patch_kernel_fault_handler(void)
static void __init sun4c_probe_mmu(void)
{
if (ARCH_SUN4) {
- switch(idprom->id_machtype) {
+ switch (idprom->id_machtype) {
case (SM_SUN4|SM_4_110):
prom_printf("No support for 4100 yet\n");
prom_halt();
@@ -631,10 +524,10 @@ static void __init sun4c_probe_mmu(void)
default:
prom_printf("Invalid SUN4 model\n");
prom_halt();
- }
+ };
} else {
- if((idprom->id_machtype == (SM_SUN4C | SM_4C_SS1)) ||
- (idprom->id_machtype == (SM_SUN4C | SM_4C_SS1PLUS))) {
+ if ((idprom->id_machtype == (SM_SUN4C | SM_4C_SS1)) ||
+ (idprom->id_machtype == (SM_SUN4C | SM_4C_SS1PLUS))) {
/* Hardcode these just to be safe, PROM on SS1 does
* not have this info available in the root node.
*/
@@ -658,20 +551,15 @@ void __init sun4c_probe_memerr_reg(void)
struct linux_prom_registers regs[1];
if (ARCH_SUN4) {
- sun4c_memerr_reg = sparc_alloc_io(sun4_memreg_physaddr, 0,
- PAGE_SIZE,
- "memory parity error",
- 0x0, 0);
+ sun4c_memerr_reg = ioremap(sun4_memreg_physaddr, PAGE_SIZE);
} else {
node = prom_getchild(prom_root_node);
node = prom_searchsiblings(prom_root_node, "memory-error");
if (!node)
return;
prom_getproperty(node, "reg", (char *)regs, sizeof(regs));
- sun4c_memerr_reg = sparc_alloc_io(regs[0].phys_addr, 0,
- regs[0].reg_size,
- "memory parity error",
- regs[0].which_io, 0);
+ /* hmm I think regs[0].which_io is zero here anyways */
+ sun4c_memerr_reg = ioremap(regs[0].phys_addr, regs[0].reg_size);
}
}
@@ -679,10 +567,10 @@ static inline void sun4c_init_ss2_cache_bug(void)
{
extern unsigned long start;
- if((idprom->id_machtype == (SM_SUN4C | SM_4C_SS2)) ||
- (idprom->id_machtype == (SM_SUN4C | SM_4C_IPX)) ||
- (idprom->id_machtype == (SM_SUN4 | SM_4_330)) ||
- (idprom->id_machtype == (SM_SUN4C | SM_4C_ELC))) {
+ if ((idprom->id_machtype == (SM_SUN4C | SM_4C_SS2)) ||
+ (idprom->id_machtype == (SM_SUN4C | SM_4C_IPX)) ||
+ (idprom->id_machtype == (SM_SUN4 | SM_4_330)) ||
+ (idprom->id_machtype == (SM_SUN4C | SM_4C_ELC))) {
/* Whee.. */
printk("SS2 cache bug detected, uncaching trap table page\n");
sun4c_flush_page((unsigned int) &start);
@@ -692,17 +580,13 @@ static inline void sun4c_init_ss2_cache_bug(void)
}
/* Addr is always aligned on a page boundry for us already. */
-static void sun4c_map_dma_area(unsigned long addr, int len)
+static void sun4c_map_dma_area(unsigned long va, u32 addr, int len)
{
unsigned long page, end;
end = PAGE_ALIGN((addr + len));
- while(addr < end) {
- page = get_free_page(GFP_KERNEL);
- if(!page) {
- prom_printf("alloc_dvma: Cannot get a dvma page\n");
- prom_halt();
- }
+ while (addr < end) {
+ page = va;
sun4c_flush_page(page);
page -= PAGE_OFFSET;
page >>= PAGE_SHIFT;
@@ -710,9 +594,21 @@ static void sun4c_map_dma_area(unsigned long addr, int len)
_SUN4C_PAGE_NOCACHE | _SUN4C_PAGE_PRIV);
sun4c_put_pte(addr, page);
addr += PAGE_SIZE;
+ va += PAGE_SIZE;
}
}
+static void sun4c_unmap_dma_area(unsigned long addr, int len)
+{
+}
+
+static void sun4c_inval_dma_area(unsigned long addr, int len)
+{
+}
+
+static void sun4c_flush_dma_area(unsigned long addr, int len)
+{
+}
/* TLB management. */
@@ -726,6 +622,13 @@ struct sun4c_mmu_entry {
unsigned long vaddr;
unsigned char pseg;
unsigned char locked;
+
+ /* For user mappings only, and completely hidden from kernel
+ * TLB miss code.
+ */
+ unsigned char ctx;
+ struct sun4c_mmu_entry *lru_next;
+ struct sun4c_mmu_entry *lru_prev;
};
static struct sun4c_mmu_entry mmu_entry_pool[SUN4C_MAX_SEGMAPS];
@@ -734,12 +637,15 @@ static void __init sun4c_init_mmu_entry_pool(void)
{
int i;
- for(i=0; i < SUN4C_MAX_SEGMAPS; i++) {
+ for (i=0; i < SUN4C_MAX_SEGMAPS; i++) {
mmu_entry_pool[i].pseg = i;
mmu_entry_pool[i].next = 0;
mmu_entry_pool[i].prev = 0;
mmu_entry_pool[i].vaddr = 0;
mmu_entry_pool[i].locked = 0;
+ mmu_entry_pool[i].ctx = 0;
+ mmu_entry_pool[i].lru_next = 0;
+ mmu_entry_pool[i].lru_prev = 0;
}
mmu_entry_pool[invalid_segment].locked = 1;
}
@@ -750,8 +656,8 @@ static inline void fix_permissions(unsigned long vaddr, unsigned long bits_on,
unsigned long start, end;
end = vaddr + SUN4C_REAL_PGDIR_SIZE;
- for(start = vaddr; start < end; start += PAGE_SIZE)
- if(sun4c_get_pte(start) & _SUN4C_PAGE_VALID)
+ for (start = vaddr; start < end; start += PAGE_SIZE)
+ if (sun4c_get_pte(start) & _SUN4C_PAGE_VALID)
sun4c_put_pte(start, (sun4c_get_pte(start) | bits_on) &
~bits_off);
}
@@ -762,16 +668,16 @@ static inline void sun4c_init_map_kernelprom(unsigned long kernel_end)
unsigned char pseg, ctx;
#ifdef CONFIG_SUN4
/* sun4/110 and 260 have no kadb. */
- if((idprom->id_machtype != (SM_SUN4 | SM_4_260)) &&
- (idprom->id_machtype != (SM_SUN4 | SM_4_110))) {
+ if ((idprom->id_machtype != (SM_SUN4 | SM_4_260)) &&
+ (idprom->id_machtype != (SM_SUN4 | SM_4_110))) {
#endif
- for(vaddr = KADB_DEBUGGER_BEGVM;
- vaddr < LINUX_OPPROM_ENDVM;
- vaddr += SUN4C_REAL_PGDIR_SIZE) {
+ for (vaddr = KADB_DEBUGGER_BEGVM;
+ vaddr < LINUX_OPPROM_ENDVM;
+ vaddr += SUN4C_REAL_PGDIR_SIZE) {
pseg = sun4c_get_segmap(vaddr);
- if(pseg != invalid_segment) {
+ if (pseg != invalid_segment) {
mmu_entry_pool[pseg].locked = 1;
- for(ctx = 0; ctx < num_contexts; ctx++)
+ for (ctx = 0; ctx < num_contexts; ctx++)
prom_putsegment(ctx, vaddr, pseg);
fix_permissions(vaddr, _SUN4C_PAGE_PRIV, 0);
}
@@ -779,10 +685,10 @@ static inline void sun4c_init_map_kernelprom(unsigned long kernel_end)
#ifdef CONFIG_SUN4
}
#endif
- for(vaddr = KERNBASE; vaddr < kernel_end; vaddr += SUN4C_REAL_PGDIR_SIZE) {
+ for (vaddr = KERNBASE; vaddr < kernel_end; vaddr += SUN4C_REAL_PGDIR_SIZE) {
pseg = sun4c_get_segmap(vaddr);
mmu_entry_pool[pseg].locked = 1;
- for(ctx = 0; ctx < num_contexts; ctx++)
+ for (ctx = 0; ctx < num_contexts; ctx++)
prom_putsegment(ctx, vaddr, pseg);
fix_permissions(vaddr, _SUN4C_PAGE_PRIV, _SUN4C_PAGE_NOCACHE);
}
@@ -792,13 +698,13 @@ static void __init sun4c_init_lock_area(unsigned long start, unsigned long end)
{
int i, ctx;
- while(start < end) {
- for(i=0; i < invalid_segment; i++)
- if(!mmu_entry_pool[i].locked)
+ while (start < end) {
+ for (i = 0; i < invalid_segment; i++)
+ if (!mmu_entry_pool[i].locked)
break;
mmu_entry_pool[i].locked = 1;
sun4c_init_clean_segmap(i);
- for(ctx = 0; ctx < num_contexts; ctx++)
+ for (ctx = 0; ctx < num_contexts; ctx++)
prom_putsegment(ctx, start, mmu_entry_pool[i].pseg);
start += SUN4C_REAL_PGDIR_SIZE;
}
@@ -815,13 +721,15 @@ struct sun4c_mmu_ring {
static struct sun4c_mmu_ring sun4c_context_ring[SUN4C_MAX_CONTEXTS]; /* used user entries */
static struct sun4c_mmu_ring sun4c_ufree_ring; /* free user entries */
+static struct sun4c_mmu_ring sun4c_ulru_ring; /* LRU user entries */
struct sun4c_mmu_ring sun4c_kernel_ring; /* used kernel entries */
struct sun4c_mmu_ring sun4c_kfree_ring; /* free kernel entries */
-static inline void sun4c_init_rings(unsigned long *mempool)
+static inline void sun4c_init_rings(void)
{
int i;
- for(i=0; i<SUN4C_MAX_CONTEXTS; i++) {
+
+ for (i = 0; i < SUN4C_MAX_CONTEXTS; i++) {
sun4c_context_ring[i].ringhd.next =
sun4c_context_ring[i].ringhd.prev =
&sun4c_context_ring[i].ringhd;
@@ -830,6 +738,9 @@ static inline void sun4c_init_rings(unsigned long *mempool)
sun4c_ufree_ring.ringhd.next = sun4c_ufree_ring.ringhd.prev =
&sun4c_ufree_ring.ringhd;
sun4c_ufree_ring.num_entries = 0;
+ sun4c_ulru_ring.ringhd.lru_next = sun4c_ulru_ring.ringhd.lru_prev =
+ &sun4c_ulru_ring.ringhd;
+ sun4c_ulru_ring.num_entries = 0;
sun4c_kernel_ring.ringhd.next = sun4c_kernel_ring.ringhd.prev =
&sun4c_kernel_ring.ringhd;
sun4c_kernel_ring.num_entries = 0;
@@ -838,8 +749,8 @@ static inline void sun4c_init_rings(unsigned long *mempool)
sun4c_kfree_ring.num_entries = 0;
}
-static inline void add_ring(struct sun4c_mmu_ring *ring,
- struct sun4c_mmu_entry *entry)
+static void add_ring(struct sun4c_mmu_ring *ring,
+ struct sun4c_mmu_entry *entry)
{
struct sun4c_mmu_entry *head = &ring->ringhd;
@@ -849,49 +760,58 @@ static inline void add_ring(struct sun4c_mmu_ring *ring,
ring->num_entries++;
}
-static inline void add_ring_ordered(struct sun4c_mmu_ring *ring,
- struct sun4c_mmu_entry *entry)
+static __inline__ void add_lru(struct sun4c_mmu_entry *entry)
+{
+ struct sun4c_mmu_ring *ring = &sun4c_ulru_ring;
+ struct sun4c_mmu_entry *head = &ring->ringhd;
+
+ entry->lru_next = head;
+ (entry->lru_prev = head->lru_prev)->lru_next = entry;
+ head->lru_prev = entry;
+}
+
+static void add_ring_ordered(struct sun4c_mmu_ring *ring,
+ struct sun4c_mmu_entry *entry)
{
struct sun4c_mmu_entry *head = &ring->ringhd;
unsigned long addr = entry->vaddr;
- if(head->next != &ring->ringhd) {
- while((head->next != &ring->ringhd) && (head->next->vaddr < addr))
- head = head->next;
- }
+ while ((head->next != &ring->ringhd) && (head->next->vaddr < addr))
+ head = head->next;
+
entry->prev = head;
(entry->next = head->next)->prev = entry;
head->next = entry;
ring->num_entries++;
+
+ add_lru(entry);
}
-static inline void remove_ring(struct sun4c_mmu_ring *ring,
- struct sun4c_mmu_entry *entry)
+static __inline__ void remove_ring(struct sun4c_mmu_ring *ring,
+ struct sun4c_mmu_entry *entry)
{
struct sun4c_mmu_entry *next = entry->next;
(next->prev = entry->prev)->next = next;
ring->num_entries--;
-#ifdef DEBUG_SUN4C_MM
- if(ring->num_entries < 0)
- panic("sun4c: Ring num_entries < 0!");
-#endif
}
-static inline void free_user_entry(int ctx, struct sun4c_mmu_entry *entry)
+static void remove_lru(struct sun4c_mmu_entry *entry)
{
- remove_ring(sun4c_context_ring+ctx, entry);
- add_ring(&sun4c_ufree_ring, entry);
+ struct sun4c_mmu_entry *next = entry->lru_next;
+
+ (next->lru_prev = entry->lru_prev)->lru_next = next;
}
-static inline void assign_user_entry(int ctx, struct sun4c_mmu_entry *entry)
+static void free_user_entry(int ctx, struct sun4c_mmu_entry *entry)
{
- remove_ring(&sun4c_ufree_ring, entry);
- add_ring_ordered(sun4c_context_ring+ctx, entry);
+ remove_ring(sun4c_context_ring+ctx, entry);
+ remove_lru(entry);
+ add_ring(&sun4c_ufree_ring, entry);
}
-static inline void free_kernel_entry(struct sun4c_mmu_entry *entry,
- struct sun4c_mmu_ring *ring)
+static void free_kernel_entry(struct sun4c_mmu_entry *entry,
+ struct sun4c_mmu_ring *ring)
{
remove_ring(ring, entry);
add_ring(&sun4c_kfree_ring, entry);
@@ -901,9 +821,9 @@ static void __init sun4c_init_fill_kernel_ring(int howmany)
{
int i;
- while(howmany) {
- for(i=0; i < invalid_segment; i++)
- if(!mmu_entry_pool[i].locked)
+ while (howmany) {
+ for (i = 0; i < invalid_segment; i++)
+ if (!mmu_entry_pool[i].locked)
break;
mmu_entry_pool[i].locked = 1;
sun4c_init_clean_segmap(i);
@@ -916,54 +836,40 @@ static void __init sun4c_init_fill_user_ring(void)
{
int i;
- for(i=0; i < invalid_segment; i++) {
- if(mmu_entry_pool[i].locked)
+ for (i = 0; i < invalid_segment; i++) {
+ if (mmu_entry_pool[i].locked)
continue;
sun4c_init_clean_segmap(i);
add_ring(&sun4c_ufree_ring, &mmu_entry_pool[i]);
}
}
-static inline void sun4c_kernel_unmap(struct sun4c_mmu_entry *kentry)
+static void sun4c_kernel_unmap(struct sun4c_mmu_entry *kentry)
{
int savectx, ctx;
savectx = sun4c_get_context();
- for(ctx = 0; ctx < num_contexts; ctx++) {
+ for (ctx = 0; ctx < num_contexts; ctx++) {
sun4c_set_context(ctx);
sun4c_put_segmap(kentry->vaddr, invalid_segment);
}
sun4c_set_context(savectx);
}
-static inline void sun4c_kernel_map(struct sun4c_mmu_entry *kentry)
+static void sun4c_kernel_map(struct sun4c_mmu_entry *kentry)
{
int savectx, ctx;
savectx = sun4c_get_context();
- for(ctx = 0; ctx < num_contexts; ctx++) {
+ for (ctx = 0; ctx < num_contexts; ctx++) {
sun4c_set_context(ctx);
sun4c_put_segmap(kentry->vaddr, kentry->pseg);
}
sun4c_set_context(savectx);
}
-static inline void sun4c_user_unmap(struct sun4c_mmu_entry *uentry)
-{
- sun4c_put_segmap(uentry->vaddr, invalid_segment);
-}
-
-static inline void sun4c_user_map(struct sun4c_mmu_entry *uentry)
-{
- unsigned long start = uentry->vaddr;
- unsigned long end = start + SUN4C_REAL_PGDIR_SIZE;
-
- sun4c_put_segmap(uentry->vaddr, uentry->pseg);
- while(start < end) {
- sun4c_put_pte(start, 0);
- start += PAGE_SIZE;
- }
-}
+#define sun4c_user_unmap(__entry) \
+ sun4c_put_segmap((__entry)->vaddr, invalid_segment)
static void sun4c_demap_context_hw(struct sun4c_mmu_ring *crp, unsigned char ctx)
{
@@ -971,11 +877,11 @@ static void sun4c_demap_context_hw(struct sun4c_mmu_ring *crp, unsigned char ctx
unsigned long flags;
save_and_cli(flags);
- if(head->next != head) {
+ if (head->next != head) {
struct sun4c_mmu_entry *entry = head->next;
int savectx = sun4c_get_context();
- FUW_INLINE
+ flush_user_windows();
sun4c_set_context(ctx);
sun4c_flush_context_hw();
do {
@@ -985,7 +891,7 @@ static void sun4c_demap_context_hw(struct sun4c_mmu_ring *crp, unsigned char ctx
free_user_entry(ctx, entry);
entry = next;
- } while(entry != head);
+ } while (entry != head);
sun4c_set_context(savectx);
}
restore_flags(flags);
@@ -997,11 +903,11 @@ static void sun4c_demap_context_sw(struct sun4c_mmu_ring *crp, unsigned char ctx
unsigned long flags;
save_and_cli(flags);
- if(head->next != head) {
+ if (head->next != head) {
struct sun4c_mmu_entry *entry = head->next;
int savectx = sun4c_get_context();
- FUW_INLINE
+ flush_user_windows();
sun4c_set_context(ctx);
sun4c_flush_context_sw();
do {
@@ -1011,49 +917,31 @@ static void sun4c_demap_context_sw(struct sun4c_mmu_ring *crp, unsigned char ctx
free_user_entry(ctx, entry);
entry = next;
- } while(entry != head);
+ } while (entry != head);
sun4c_set_context(savectx);
}
restore_flags(flags);
}
-static inline void sun4c_demap_one(struct sun4c_mmu_ring *crp, unsigned char ctx)
-{
- /* by using .prev we get a kind of "lru" algorithm */
- struct sun4c_mmu_entry *entry = crp->ringhd.prev;
- unsigned long flags;
- int savectx = sun4c_get_context();
-
-#ifdef DEBUG_SUN4C_MM
- if(entry == &crp->ringhd)
- panic("sun4c_demap_one: Freeing from empty ctx ring.");
-#endif
- FUW_INLINE
- save_and_cli(flags);
- sun4c_set_context(ctx);
- sun4c_flush_segment(entry->vaddr);
- sun4c_user_unmap(entry);
- free_user_entry(ctx, entry);
- sun4c_set_context(savectx);
- restore_flags(flags);
-}
-
static int sun4c_user_taken_entries = 0; /* This is how much we have. */
static int max_user_taken_entries = 0; /* This limits us and prevents deadlock. */
-static inline struct sun4c_mmu_entry *sun4c_kernel_strategy(void)
+static struct sun4c_mmu_entry *sun4c_kernel_strategy(void)
{
struct sun4c_mmu_entry *this_entry;
/* If some are free, return first one. */
- if(sun4c_kfree_ring.num_entries) {
+ if (sun4c_kfree_ring.num_entries) {
this_entry = sun4c_kfree_ring.ringhd.next;
return this_entry;
}
/* Else free one up. */
this_entry = sun4c_kernel_ring.ringhd.prev;
- sun4c_flush_segment(this_entry->vaddr);
+ if (sun4c_vacinfo.do_hwflushes)
+ sun4c_flush_segment_hw(this_entry->vaddr);
+ else
+ sun4c_flush_segment_sw(this_entry->vaddr);
sun4c_kernel_unmap(this_entry);
free_kernel_entry(this_entry, &sun4c_kernel_ring);
this_entry = sun4c_kfree_ring.ringhd.next;
@@ -1061,141 +949,73 @@ static inline struct sun4c_mmu_entry *sun4c_kernel_strategy(void)
return this_entry;
}
-void sun4c_shrink_kernel_ring(void)
-{
- struct sun4c_mmu_entry *entry;
- unsigned long flags;
-
- /* If an interrupt comes in here, we die... */
- save_and_cli(flags);
-
- if (sun4c_user_taken_entries) {
- entry = sun4c_kernel_strategy();
- remove_ring(&sun4c_kfree_ring, entry);
- add_ring(&sun4c_ufree_ring, entry);
- sun4c_user_taken_entries--;
-#if 0
- printk("shrink: ufree= %d, kfree= %d, kernel= %d\n",
- sun4c_ufree_ring.num_entries,
- sun4c_kfree_ring.num_entries,
- sun4c_kernel_ring.num_entries);
-#endif
-#ifdef DEBUG_SUN4C_MM
- if(sun4c_user_taken_entries < 0)
- panic("sun4c_shrink_kernel_ring: taken < 0.");
-#endif
- }
- restore_flags(flags);
-}
-
/* Using this method to free up mmu entries eliminates a lot of
* potential races since we have a kernel that incurs tlb
* replacement faults. There may be performance penalties.
+ *
+ * NOTE: Must be called with interrupts disabled.
*/
-static inline struct sun4c_mmu_entry *sun4c_user_strategy(void)
+static struct sun4c_mmu_entry *sun4c_user_strategy(void)
{
- struct ctx_list *next_one;
- struct sun4c_mmu_ring *rp = 0;
+ struct sun4c_mmu_entry *entry;
unsigned char ctx;
-#ifdef DEBUG_SUN4C_MM
- int lim = num_contexts;
-#endif
+ int savectx;
/* If some are free, return first one. */
- if(sun4c_ufree_ring.num_entries) {
-#ifdef DEBUG_SUN4C_MM
- if(sun4c_ufree_ring.ringhd.next == &sun4c_ufree_ring.ringhd)
- panic("sun4c_user_strategy: num_entries!=0 but ring empty.");
-#endif
- return sun4c_ufree_ring.ringhd.next;
+ if (sun4c_ufree_ring.num_entries) {
+ entry = sun4c_ufree_ring.ringhd.next;
+ goto unlink_out;
}
if (sun4c_user_taken_entries) {
- sun4c_shrink_kernel_ring();
-#ifdef DEBUG_SUN4C_MM
- if(sun4c_ufree_ring.ringhd.next == &sun4c_ufree_ring.ringhd)
- panic("sun4c_user_strategy: kernel shrunk but ufree empty.");
-#endif
- return sun4c_ufree_ring.ringhd.next;
+ entry = sun4c_kernel_strategy();
+ sun4c_user_taken_entries--;
+ goto kunlink_out;
}
- /* Grab one from the LRU context. */
- next_one = ctx_used.next;
- while ((sun4c_context_ring[next_one->ctx_number].num_entries == 0)
-#ifdef DEBUG_SUN4C_MM
- && (--lim >= 0)
-#endif
- )
- next_one = next_one->next;
+ /* Grab from the beginning of the LRU list. */
+ entry = sun4c_ulru_ring.ringhd.lru_next;
+ ctx = entry->ctx;
-#ifdef DEBUG_SUN4C_MM
- if(lim < 0)
- panic("No user segmaps!");
-#endif
+ savectx = sun4c_get_context();
+ flush_user_windows();
+ sun4c_set_context(ctx);
+ if (sun4c_vacinfo.do_hwflushes)
+ sun4c_flush_segment_hw(entry->vaddr);
+ else
+ sun4c_flush_segment_sw(entry->vaddr);
+ sun4c_user_unmap(entry);
+ remove_ring(sun4c_context_ring + ctx, entry);
+ remove_lru(entry);
+ sun4c_set_context(savectx);
- ctx = next_one->ctx_number;
- rp = &sun4c_context_ring[ctx];
+ return entry;
- sun4c_demap_one(rp, ctx);
-#ifdef DEBUG_SUN4C_MM
- if(sun4c_ufree_ring.ringhd.next == &sun4c_ufree_ring.ringhd)
- panic("sun4c_user_strategy: demapped one but ufree empty.");
-#endif
- return sun4c_ufree_ring.ringhd.next;
+unlink_out:
+ remove_ring(&sun4c_ufree_ring, entry);
+ return entry;
+kunlink_out:
+ remove_ring(&sun4c_kfree_ring, entry);
+ return entry;
}
+/* NOTE: Must be called with interrupts disabled. */
void sun4c_grow_kernel_ring(void)
{
struct sun4c_mmu_entry *entry;
-#if 0
- printk("grow: ");
-#endif
-
/* Prevent deadlock condition. */
- if(sun4c_user_taken_entries >= max_user_taken_entries) {
-#if 0
- printk("deadlock avoidance, taken= %d max= %d\n",
- sun4c_user_taken_entries, max_user_taken_entries);
-#endif
+ if (sun4c_user_taken_entries >= max_user_taken_entries)
return;
- }
if (sun4c_ufree_ring.num_entries) {
entry = sun4c_ufree_ring.ringhd.next;
-#ifdef DEBUG_SUN4C_MM
- if(entry == &sun4c_ufree_ring.ringhd)
- panic("\nsun4c_grow_kernel_ring: num_entries!=0, ring empty.");
-#endif
remove_ring(&sun4c_ufree_ring, entry);
add_ring(&sun4c_kfree_ring, entry);
-#ifdef DEBUG_SUN4C_MM
- if(sun4c_user_taken_entries < 0)
- panic("\nsun4c_grow_kernel_ring: taken < 0.");
-#endif
sun4c_user_taken_entries++;
-#if 0
- printk("ufree= %d, kfree= %d, kernel= %d\n",
- sun4c_ufree_ring.num_entries,
- sun4c_kfree_ring.num_entries,
- sun4c_kernel_ring.num_entries);
-#endif
}
}
-static inline void alloc_user_segment(unsigned long address, unsigned char ctx)
-{
- struct sun4c_mmu_entry *entry;
- unsigned long flags;
-
- save_and_cli(flags);
- entry = sun4c_user_strategy();
- entry->vaddr = (address & SUN4C_REAL_PGDIR_MASK);
- assign_user_entry(ctx, entry);
- sun4c_user_map(entry);
- restore_flags(flags);
-}
-
/* This is now a fast in-window trap handler to avoid any and all races. */
static void sun4c_quick_kernel_fault(unsigned long address)
{
@@ -1209,8 +1029,8 @@ static void sun4c_quick_kernel_fault(unsigned long address)
* bucket[0]
* bucket[1]
* [ ... ]
- * bucket[NR_TASKS-1]
- * TASK_STACK_BEGIN + (sizeof(struct task_bucket) * NR_TASKS)
+ * bucket[NR_TASK_BUCKETS-1]
+ * TASK_STACK_BEGIN + (sizeof(struct task_bucket) * NR_TASK_BUCKETS)
*
* Each slot looks like:
*
@@ -1218,7 +1038,7 @@ static void sun4c_quick_kernel_fault(unsigned long address)
* page 2 -- rest of kernel stack
*/
-union task_union *sun4c_bucket[NR_TASKS];
+union task_union *sun4c_bucket[NR_TASK_BUCKETS];
static int sun4c_lowbucket_avail;
@@ -1232,7 +1052,7 @@ static int sun4c_lowbucket_avail;
#define BUCKET_PTE_PAGE(pte) \
(PAGE_OFFSET + (((pte) & SUN4C_PFN_MASK) << PAGE_SHIFT))
-static inline void get_locked_segment(unsigned long addr)
+static void get_locked_segment(unsigned long addr)
{
struct sun4c_mmu_entry *stolen;
unsigned long flags;
@@ -1240,19 +1060,14 @@ static inline void get_locked_segment(unsigned long addr)
save_and_cli(flags);
addr &= SUN4C_REAL_PGDIR_MASK;
stolen = sun4c_user_strategy();
- remove_ring(&sun4c_ufree_ring, stolen);
max_user_taken_entries--;
-#ifdef DEBUG_SUN4C_MM
- if(max_user_taken_entries < 0)
- panic("get_locked_segment: max_user_taken < 0.");
-#endif
stolen->vaddr = addr;
- FUW_INLINE
+ flush_user_windows();
sun4c_kernel_map(stolen);
restore_flags(flags);
}
-static inline void free_locked_segment(unsigned long addr)
+static void free_locked_segment(unsigned long addr)
{
struct sun4c_mmu_entry *entry;
unsigned long flags;
@@ -1263,14 +1078,13 @@ static inline void free_locked_segment(unsigned long addr)
pseg = sun4c_get_segmap(addr);
entry = &mmu_entry_pool[pseg];
- FUW_INLINE
- sun4c_flush_segment(addr);
+ flush_user_windows();
+ if (sun4c_vacinfo.do_hwflushes)
+ sun4c_flush_segment_hw(addr);
+ else
+ sun4c_flush_segment_sw(addr);
sun4c_kernel_unmap(entry);
add_ring(&sun4c_ufree_ring, entry);
-#ifdef DEBUG_SUN4C_MM
- if(max_user_taken_entries < 0)
- panic("free_locked_segment: max_user_taken < 0.");
-#endif
max_user_taken_entries++;
restore_flags(flags);
}
@@ -1282,8 +1096,8 @@ static inline void garbage_collect(int entry)
/* 32 buckets per segment... */
entry &= ~31;
start = entry;
- for(end = (start + 32); start < end; start++)
- if(sun4c_bucket[start] != BUCKET_EMPTY)
+ for (end = (start + 32); start < end; start++)
+ if (sun4c_bucket[start] != BUCKET_EMPTY)
return;
/* Entire segment empty, release it. */
@@ -1302,23 +1116,39 @@ static struct task_struct *sun4c_alloc_task_struct(void)
int entry;
pages = __get_free_pages(GFP_KERNEL, TASK_STRUCT_ORDER);
- if(!pages)
+ if (!pages)
return (struct task_struct *) 0;
- for(entry = sun4c_lowbucket_avail; entry < NR_TASKS; entry++)
- if(sun4c_bucket[entry] == BUCKET_EMPTY)
+ for (entry = sun4c_lowbucket_avail; entry < NR_TASK_BUCKETS; entry++)
+ if (sun4c_bucket[entry] == BUCKET_EMPTY)
break;
- if(entry == NR_TASKS) {
+ if (entry == NR_TASK_BUCKETS) {
free_pages(pages, TASK_STRUCT_ORDER);
return (struct task_struct *) 0;
}
- if(entry >= sun4c_lowbucket_avail)
+ if (entry >= sun4c_lowbucket_avail)
sun4c_lowbucket_avail = entry + 1;
addr = BUCKET_ADDR(entry);
sun4c_bucket[entry] = (union task_union *) addr;
if(sun4c_get_segmap(addr) == invalid_segment)
get_locked_segment(addr);
+
+ /* We are changing the virtual color of the page(s)
+ * so we must flush the cache to guarentee consistancy.
+ */
+ if (sun4c_vacinfo.do_hwflushes) {
+ sun4c_flush_page_hw(pages);
+#ifndef CONFIG_SUN4
+ sun4c_flush_page_hw(pages + PAGE_SIZE);
+#endif
+ } else {
+ sun4c_flush_page_sw(pages);
+#ifndef CONFIG_SUN4
+ sun4c_flush_page_sw(pages + PAGE_SIZE);
+#endif
+ }
+
sun4c_put_pte(addr, BUCKET_PTE(pages));
#ifndef CONFIG_SUN4
sun4c_put_pte(addr + PAGE_SIZE, BUCKET_PTE(pages + PAGE_SIZE));
@@ -1342,7 +1172,7 @@ static void sun4c_free_task_struct_hw(struct task_struct *tsk)
sun4c_put_pte(tsaddr + PAGE_SIZE, 0);
#endif
sun4c_bucket[entry] = BUCKET_EMPTY;
- if(entry < sun4c_lowbucket_avail)
+ if (entry < sun4c_lowbucket_avail)
sun4c_lowbucket_avail = entry;
free_pages(pages, TASK_STRUCT_ORDER);
@@ -1365,7 +1195,7 @@ static void sun4c_free_task_struct_sw(struct task_struct *tsk)
sun4c_put_pte(tsaddr + PAGE_SIZE, 0);
#endif
sun4c_bucket[entry] = BUCKET_EMPTY;
- if(entry < sun4c_lowbucket_avail)
+ if (entry < sun4c_lowbucket_avail)
sun4c_lowbucket_avail = entry;
free_pages(pages, TASK_STRUCT_ORDER);
@@ -1376,10 +1206,10 @@ static void __init sun4c_init_buckets(void)
{
int entry;
- if(sizeof(union task_union) != (PAGE_SIZE << TASK_STRUCT_ORDER)) {
+ if (sizeof(union task_union) != (PAGE_SIZE << TASK_STRUCT_ORDER)) {
prom_printf("task union not %d page(s)!\n", 1 << TASK_STRUCT_ORDER);
}
- for(entry = 0; entry < NR_TASKS; entry++)
+ for (entry = 0; entry < NR_TASK_BUCKETS; entry++)
sun4c_bucket[entry] = BUCKET_EMPTY;
sun4c_lowbucket_avail = 0;
}
@@ -1494,37 +1324,38 @@ static void sun4c_unlockarea(char *vaddr, unsigned long size)
* by implication and fool the page locking code above
* if passed to by mistake.
*/
-static __u32 sun4c_get_scsi_one(char *bufptr, unsigned long len, struct linux_sbus *sbus)
+static __u32 sun4c_get_scsi_one(char *bufptr, unsigned long len, struct sbus_bus *sbus)
{
unsigned long page;
page = ((unsigned long)bufptr) & PAGE_MASK;
- if(MAP_NR(page) > max_mapnr) {
+ if (MAP_NR(page) > max_mapnr) {
sun4c_flush_page(page);
return (__u32)bufptr; /* already locked */
}
return (__u32)sun4c_lockarea(bufptr, len);
}
-static void sun4c_get_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus)
+static void sun4c_get_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_bus *sbus)
{
- while(sz >= 0) {
- sg[sz].dvma_addr = (__u32)sun4c_lockarea(sg[sz].addr, sg[sz].len);
+ while (sz >= 0) {
+ sg[sz].dvma_address = (__u32)sun4c_lockarea(sg[sz].address, sg[sz].length);
+ sg[sz].dvma_length = sg[sz].length;
sz--;
}
}
-static void sun4c_release_scsi_one(__u32 bufptr, unsigned long len, struct linux_sbus *sbus)
+static void sun4c_release_scsi_one(__u32 bufptr, unsigned long len, struct sbus_bus *sbus)
{
- if(bufptr < sun4c_iobuffer_start)
+ if (bufptr < sun4c_iobuffer_start)
return; /* On kernel stack or similar, see above */
sun4c_unlockarea((char *)bufptr, len);
}
-static void sun4c_release_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus)
+static void sun4c_release_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_bus *sbus)
{
- while(sz >= 0) {
- sun4c_unlockarea((char *)sg[sz].dvma_addr, sg[sz].len);
+ while (sz >= 0) {
+ sun4c_unlockarea((char *)sg[sz].dvma_address, sg[sz].length);
sz--;
}
}
@@ -1534,7 +1365,7 @@ static void sun4c_release_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_s
struct vm_area_struct sun4c_kstack_vma;
-static unsigned long __init sun4c_init_lock_areas(unsigned long start_mem)
+static void __init sun4c_init_lock_areas(void)
{
unsigned long sun4c_taskstack_start;
unsigned long sun4c_taskstack_end;
@@ -1543,9 +1374,9 @@ static unsigned long __init sun4c_init_lock_areas(unsigned long start_mem)
sun4c_init_buckets();
sun4c_taskstack_start = SUN4C_LOCK_VADDR;
sun4c_taskstack_end = (sun4c_taskstack_start +
- (TASK_ENTRY_SIZE * NR_TASKS));
- if(sun4c_taskstack_end >= SUN4C_LOCK_END) {
- prom_printf("Too many tasks, decrease NR_TASKS please.\n");
+ (TASK_ENTRY_SIZE * NR_TASK_BUCKETS));
+ if (sun4c_taskstack_end >= SUN4C_LOCK_END) {
+ prom_printf("Too many tasks, decrease NR_TASK_BUCKETS please.\n");
prom_halt();
}
@@ -1556,9 +1387,8 @@ static unsigned long __init sun4c_init_lock_areas(unsigned long start_mem)
bitmap_size = (bitmap_size + 7) >> 3;
bitmap_size = LONG_ALIGN(bitmap_size);
iobuffer_map_size = bitmap_size << 3;
- sun4c_iobuffer_map = (unsigned long *) start_mem;
- memset((void *) start_mem, 0, bitmap_size);
- start_mem += bitmap_size;
+ sun4c_iobuffer_map = __alloc_bootmem(bitmap_size, SMP_CACHE_BYTES, 0UL);
+ memset((void *) sun4c_iobuffer_map, 0, bitmap_size);
sun4c_kstack_vma.vm_mm = &init_mm;
sun4c_kstack_vma.vm_start = sun4c_taskstack_start;
@@ -1566,7 +1396,6 @@ static unsigned long __init sun4c_init_lock_areas(unsigned long start_mem)
sun4c_kstack_vma.vm_page_prot = PAGE_SHARED;
sun4c_kstack_vma.vm_flags = VM_READ | VM_WRITE | VM_EXEC;
insert_vm_struct(&init_mm, &sun4c_kstack_vma);
- return start_mem;
}
/* Cache flushing on the sun4c. */
@@ -1574,12 +1403,12 @@ static void sun4c_flush_cache_all(void)
{
unsigned long begin, end;
- FUW_INLINE
+ flush_user_windows();
begin = (KERNBASE + SUN4C_REAL_PGDIR_SIZE);
end = (begin + SUN4C_VAC_SIZE);
- if(sun4c_vacinfo.linesize == 32) {
- while(begin < end) {
+ if (sun4c_vacinfo.linesize == 32) {
+ while (begin < end) {
__asm__ __volatile__("
ld [%0 + 0x00], %%g0
ld [%0 + 0x20], %%g0
@@ -1601,7 +1430,7 @@ static void sun4c_flush_cache_all(void)
begin += 512;
}
} else {
- while(begin < end) {
+ while (begin < end) {
__asm__ __volatile__("
ld [%0 + 0x00], %%g0
ld [%0 + 0x10], %%g0
@@ -1629,29 +1458,31 @@ static void sun4c_flush_cache_mm_hw(struct mm_struct *mm)
{
int new_ctx = mm->context;
- if(new_ctx != NO_CONTEXT && sun4c_context_ring[new_ctx].num_entries) {
- struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd;
- unsigned long flags;
+ if (new_ctx != NO_CONTEXT) {
+ flush_user_windows();
+ if (sun4c_context_ring[new_ctx].num_entries) {
+ struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd;
+ unsigned long flags;
- save_and_cli(flags);
- if(head->next != head) {
- struct sun4c_mmu_entry *entry = head->next;
- int savectx = sun4c_get_context();
+ save_and_cli(flags);
+ if (head->next != head) {
+ struct sun4c_mmu_entry *entry = head->next;
+ int savectx = sun4c_get_context();
- FUW_INLINE
- sun4c_set_context(new_ctx);
- sun4c_flush_context_hw();
- do {
- struct sun4c_mmu_entry *next = entry->next;
+ sun4c_set_context(new_ctx);
+ sun4c_flush_context_hw();
+ do {
+ struct sun4c_mmu_entry *next = entry->next;
- sun4c_user_unmap(entry);
- free_user_entry(new_ctx, entry);
+ sun4c_user_unmap(entry);
+ free_user_entry(new_ctx, entry);
- entry = next;
- } while(entry != head);
- sun4c_set_context(savectx);
+ entry = next;
+ } while (entry != head);
+ sun4c_set_context(savectx);
+ }
+ restore_flags(flags);
}
- restore_flags(flags);
}
}
@@ -1659,29 +1490,28 @@ static void sun4c_flush_cache_range_hw(struct mm_struct *mm, unsigned long start
{
int new_ctx = mm->context;
-#if KGPROF_PROFILING
- kgprof_profile();
-#endif
- if(new_ctx != NO_CONTEXT) {
+ if (new_ctx != NO_CONTEXT) {
struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd;
struct sun4c_mmu_entry *entry;
unsigned long flags;
- FUW_INLINE
+ flush_user_windows();
+
save_and_cli(flags);
/* All user segmap chains are ordered on entry->vaddr. */
- for(entry = head->next;
- (entry != head) && ((entry->vaddr+SUN4C_REAL_PGDIR_SIZE) < start);
- entry = entry->next)
+ for (entry = head->next;
+ (entry != head) && ((entry->vaddr+SUN4C_REAL_PGDIR_SIZE) < start);
+ entry = entry->next)
;
/* Tracing various job mixtures showed that this conditional
* only passes ~35% of the time for most worse case situations,
* therefore we avoid all of this gross overhead ~65% of the time.
*/
- if((entry != head) && (entry->vaddr < end)) {
+ if ((entry != head) && (entry->vaddr < end)) {
int octx = sun4c_get_context();
+
sun4c_set_context(new_ctx);
/* At this point, always, (start >= entry->vaddr) and
@@ -1696,11 +1526,11 @@ static void sun4c_flush_cache_range_hw(struct mm_struct *mm, unsigned long start
/* "realstart" is always >= entry->vaddr */
realend = entry->vaddr + SUN4C_REAL_PGDIR_SIZE;
- if(end < realend)
+ if (end < realend)
realend = end;
- if((realend - entry->vaddr) <= (PAGE_SIZE << 3)) {
+ if ((realend - entry->vaddr) <= (PAGE_SIZE << 3)) {
unsigned long page = entry->vaddr;
- while(page < realend) {
+ while (page < realend) {
sun4c_flush_page_hw(page);
page += PAGE_SIZE;
}
@@ -1710,14 +1540,13 @@ static void sun4c_flush_cache_range_hw(struct mm_struct *mm, unsigned long start
free_user_entry(new_ctx, entry);
}
entry = next;
- } while((entry != head) && (entry->vaddr < end));
+ } while ((entry != head) && (entry->vaddr < end));
sun4c_set_context(octx);
}
restore_flags(flags);
}
}
-/* XXX no save_and_cli/restore_flags needed, but put here if darkside still crashes */
static void sun4c_flush_cache_page_hw(struct vm_area_struct *vma, unsigned long page)
{
struct mm_struct *mm = vma->vm_mm;
@@ -1726,76 +1555,85 @@ static void sun4c_flush_cache_page_hw(struct vm_area_struct *vma, unsigned long
/* Sun4c has no separate I/D caches so cannot optimize for non
* text page flushes.
*/
- if(new_ctx != NO_CONTEXT) {
+ if (new_ctx != NO_CONTEXT) {
int octx = sun4c_get_context();
+ unsigned long flags;
- FUW_INLINE
+ flush_user_windows();
+ save_and_cli(flags);
sun4c_set_context(new_ctx);
sun4c_flush_page_hw(page);
sun4c_set_context(octx);
+ restore_flags(flags);
}
}
-static void sun4c_flush_page_to_ram_hw(unsigned long page)
+static void sun4c_flush_page_to_ram_hw(struct page *page)
{
- sun4c_flush_page_hw(page);
+ unsigned long flags;
+ unsigned long addr = page_address(page);
+
+ save_and_cli(flags);
+ sun4c_flush_page_hw(addr);
+ restore_flags(flags);
}
static void sun4c_flush_cache_mm_sw(struct mm_struct *mm)
{
int new_ctx = mm->context;
- if(new_ctx != NO_CONTEXT && sun4c_context_ring[new_ctx].num_entries) {
- struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd;
- unsigned long flags;
+ if (new_ctx != NO_CONTEXT) {
+ flush_user_windows();
- save_and_cli(flags);
- if(head->next != head) {
- struct sun4c_mmu_entry *entry = head->next;
- int savectx = sun4c_get_context();
+ if (sun4c_context_ring[new_ctx].num_entries) {
+ struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd;
+ unsigned long flags;
- FUW_INLINE
- sun4c_set_context(new_ctx);
- sun4c_flush_context_sw();
- do {
- struct sun4c_mmu_entry *next = entry->next;
+ save_and_cli(flags);
+ if (head->next != head) {
+ struct sun4c_mmu_entry *entry = head->next;
+ int savectx = sun4c_get_context();
- sun4c_user_unmap(entry);
- free_user_entry(new_ctx, entry);
+ sun4c_set_context(new_ctx);
+ sun4c_flush_context_sw();
+ do {
+ struct sun4c_mmu_entry *next = entry->next;
- entry = next;
- } while(entry != head);
- sun4c_set_context(savectx);
+ sun4c_user_unmap(entry);
+ free_user_entry(new_ctx, entry);
+
+ entry = next;
+ } while (entry != head);
+ sun4c_set_context(savectx);
+ }
+ restore_flags(flags);
}
- restore_flags(flags);
}
}
static void sun4c_flush_cache_range_sw(struct mm_struct *mm, unsigned long start, unsigned long end)
{
int new_ctx = mm->context;
-
-#if KGPROF_PROFILING
- kgprof_profile();
-#endif
- if(new_ctx != NO_CONTEXT) {
+
+ if (new_ctx != NO_CONTEXT) {
struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd;
struct sun4c_mmu_entry *entry;
unsigned long flags;
- FUW_INLINE
+ flush_user_windows();
+
save_and_cli(flags);
/* All user segmap chains are ordered on entry->vaddr. */
- for(entry = head->next;
- (entry != head) && ((entry->vaddr+SUN4C_REAL_PGDIR_SIZE) < start);
- entry = entry->next)
+ for (entry = head->next;
+ (entry != head) && ((entry->vaddr+SUN4C_REAL_PGDIR_SIZE) < start);
+ entry = entry->next)
;
/* Tracing various job mixtures showed that this conditional
* only passes ~35% of the time for most worse case situations,
* therefore we avoid all of this gross overhead ~65% of the time.
*/
- if((entry != head) && (entry->vaddr < end)) {
+ if ((entry != head) && (entry->vaddr < end)) {
int octx = sun4c_get_context();
sun4c_set_context(new_ctx);
@@ -1811,11 +1649,11 @@ static void sun4c_flush_cache_range_sw(struct mm_struct *mm, unsigned long start
/* "realstart" is always >= entry->vaddr */
realend = entry->vaddr + SUN4C_REAL_PGDIR_SIZE;
- if(end < realend)
+ if (end < realend)
realend = end;
- if((realend - entry->vaddr) <= (PAGE_SIZE << 3)) {
+ if ((realend - entry->vaddr) <= (PAGE_SIZE << 3)) {
unsigned long page = entry->vaddr;
- while(page < realend) {
+ while (page < realend) {
sun4c_flush_page_sw(page);
page += PAGE_SIZE;
}
@@ -1825,7 +1663,7 @@ static void sun4c_flush_cache_range_sw(struct mm_struct *mm, unsigned long start
free_user_entry(new_ctx, entry);
}
entry = next;
- } while((entry != head) && (entry->vaddr < end));
+ } while ((entry != head) && (entry->vaddr < end));
sun4c_set_context(octx);
}
restore_flags(flags);
@@ -1840,19 +1678,27 @@ static void sun4c_flush_cache_page_sw(struct vm_area_struct *vma, unsigned long
/* Sun4c has no separate I/D caches so cannot optimize for non
* text page flushes.
*/
- if(new_ctx != NO_CONTEXT) {
+ if (new_ctx != NO_CONTEXT) {
int octx = sun4c_get_context();
+ unsigned long flags;
- FUW_INLINE
+ flush_user_windows();
+ save_and_cli(flags);
sun4c_set_context(new_ctx);
sun4c_flush_page_sw(page);
sun4c_set_context(octx);
+ restore_flags(flags);
}
}
-static void sun4c_flush_page_to_ram_sw(unsigned long page)
+static void sun4c_flush_page_to_ram_sw(struct page *page)
{
- sun4c_flush_page_sw(page);
+ unsigned long flags;
+ unsigned long addr = page_address(page);
+
+ save_and_cli(flags);
+ sun4c_flush_page_sw(addr);
+ restore_flags(flags);
}
/* Sun4c cache is unified, both instructions and data live there, so
@@ -1879,8 +1725,11 @@ static void sun4c_flush_tlb_all(void)
flush_user_windows();
while (sun4c_kernel_ring.num_entries) {
next_entry = this_entry->next;
- sun4c_flush_segment(this_entry->vaddr);
- for(ctx = 0; ctx < num_contexts; ctx++) {
+ if (sun4c_vacinfo.do_hwflushes)
+ sun4c_flush_segment_hw(this_entry->vaddr);
+ else
+ sun4c_flush_segment_sw(this_entry->vaddr);
+ for (ctx = 0; ctx < num_contexts; ctx++) {
sun4c_set_context(ctx);
sun4c_put_segmap(this_entry->vaddr, invalid_segment);
}
@@ -1895,16 +1744,15 @@ static void sun4c_flush_tlb_mm_hw(struct mm_struct *mm)
{
int new_ctx = mm->context;
- if(new_ctx != NO_CONTEXT) {
+ if (new_ctx != NO_CONTEXT) {
struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd;
unsigned long flags;
save_and_cli(flags);
- if(head->next != head) {
+ if (head->next != head) {
struct sun4c_mmu_entry *entry = head->next;
int savectx = sun4c_get_context();
- FUW_INLINE
sun4c_set_context(new_ctx);
sun4c_flush_context_hw();
do {
@@ -1914,7 +1762,7 @@ static void sun4c_flush_tlb_mm_hw(struct mm_struct *mm)
free_user_entry(new_ctx, entry);
entry = next;
- } while(entry != head);
+ } while (entry != head);
sun4c_set_context(savectx);
}
restore_flags(flags);
@@ -1925,26 +1773,21 @@ static void sun4c_flush_tlb_range_hw(struct mm_struct *mm, unsigned long start,
{
int new_ctx = mm->context;
- if(new_ctx != NO_CONTEXT) {
+ if (new_ctx != NO_CONTEXT) {
struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd;
struct sun4c_mmu_entry *entry;
unsigned long flags;
-#if KGPROF_PROFILING
- kgprof_profile();
-#endif
save_and_cli(flags);
/* See commentary in sun4c_flush_cache_range_*(). */
- for(entry = head->next;
- (entry != head) && ((entry->vaddr+SUN4C_REAL_PGDIR_SIZE) < start);
- entry = entry->next)
+ for (entry = head->next;
+ (entry != head) && ((entry->vaddr+SUN4C_REAL_PGDIR_SIZE) < start);
+ entry = entry->next)
;
- if((entry != head) && (entry->vaddr < end)) {
+ if ((entry != head) && (entry->vaddr < end)) {
int octx = sun4c_get_context();
- /* This window flush is paranoid I think... -DaveM */
- FUW_INLINE
sun4c_set_context(new_ctx);
do {
struct sun4c_mmu_entry *next = entry->next;
@@ -1954,7 +1797,7 @@ static void sun4c_flush_tlb_range_hw(struct mm_struct *mm, unsigned long start,
free_user_entry(new_ctx, entry);
entry = next;
- } while((entry != head) && (entry->vaddr < end));
+ } while ((entry != head) && (entry->vaddr < end));
sun4c_set_context(octx);
}
restore_flags(flags);
@@ -1966,15 +1809,17 @@ static void sun4c_flush_tlb_page_hw(struct vm_area_struct *vma, unsigned long pa
struct mm_struct *mm = vma->vm_mm;
int new_ctx = mm->context;
- if(new_ctx != NO_CONTEXT) {
+ if (new_ctx != NO_CONTEXT) {
int savectx = sun4c_get_context();
+ unsigned long flags;
- FUW_INLINE
+ save_and_cli(flags);
sun4c_set_context(new_ctx);
page &= PAGE_MASK;
sun4c_flush_page_hw(page);
sun4c_put_pte(page, 0);
sun4c_set_context(savectx);
+ restore_flags(flags);
}
}
@@ -1982,16 +1827,15 @@ static void sun4c_flush_tlb_mm_sw(struct mm_struct *mm)
{
int new_ctx = mm->context;
- if(new_ctx != NO_CONTEXT) {
+ if (new_ctx != NO_CONTEXT) {
struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd;
unsigned long flags;
save_and_cli(flags);
- if(head->next != head) {
+ if (head->next != head) {
struct sun4c_mmu_entry *entry = head->next;
int savectx = sun4c_get_context();
- FUW_INLINE
sun4c_set_context(new_ctx);
sun4c_flush_context_sw();
do {
@@ -2001,7 +1845,7 @@ static void sun4c_flush_tlb_mm_sw(struct mm_struct *mm)
free_user_entry(new_ctx, entry);
entry = next;
- } while(entry != head);
+ } while (entry != head);
sun4c_set_context(savectx);
}
restore_flags(flags);
@@ -2012,27 +1856,21 @@ static void sun4c_flush_tlb_range_sw(struct mm_struct *mm, unsigned long start,
{
int new_ctx = mm->context;
- if(new_ctx != NO_CONTEXT) {
+ if (new_ctx != NO_CONTEXT) {
struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd;
struct sun4c_mmu_entry *entry;
unsigned long flags;
-#if KGPROF_PROFILING
- kgprof_profile();
-#endif
-
save_and_cli(flags);
/* See commentary in sun4c_flush_cache_range_*(). */
- for(entry = head->next;
- (entry != head) && ((entry->vaddr+SUN4C_REAL_PGDIR_SIZE) < start);
- entry = entry->next)
+ for (entry = head->next;
+ (entry != head) && ((entry->vaddr+SUN4C_REAL_PGDIR_SIZE) < start);
+ entry = entry->next)
;
- if((entry != head) && (entry->vaddr < end)) {
+ if ((entry != head) && (entry->vaddr < end)) {
int octx = sun4c_get_context();
- /* This window flush is paranoid I think... -DaveM */
- FUW_INLINE
sun4c_set_context(new_ctx);
do {
struct sun4c_mmu_entry *next = entry->next;
@@ -2042,7 +1880,7 @@ static void sun4c_flush_tlb_range_sw(struct mm_struct *mm, unsigned long start,
free_user_entry(new_ctx, entry);
entry = next;
- } while((entry != head) && (entry->vaddr < end));
+ } while ((entry != head) && (entry->vaddr < end));
sun4c_set_context(octx);
}
restore_flags(flags);
@@ -2054,15 +1892,17 @@ static void sun4c_flush_tlb_page_sw(struct vm_area_struct *vma, unsigned long pa
struct mm_struct *mm = vma->vm_mm;
int new_ctx = mm->context;
- if(new_ctx != NO_CONTEXT) {
+ if (new_ctx != NO_CONTEXT) {
int savectx = sun4c_get_context();
+ unsigned long flags;
- FUW_INLINE
+ save_and_cli(flags);
sun4c_set_context(new_ctx);
page &= PAGE_MASK;
sun4c_flush_page_sw(page);
sun4c_put_pte(page, 0);
sun4c_set_context(savectx);
+ restore_flags(flags);
}
}
@@ -2075,7 +1915,6 @@ static void sun4c_pgd_set(pgd_t * pgdp, pmd_t * pmdp)
{
}
-
void sun4c_mapioaddr(unsigned long physaddr, unsigned long virt_addr,
int bus_type, int rdonly)
{
@@ -2083,7 +1922,7 @@ void sun4c_mapioaddr(unsigned long physaddr, unsigned long virt_addr,
page_entry = ((physaddr >> PAGE_SHIFT) & SUN4C_PFN_MASK);
page_entry |= ((pg_iobits | _SUN4C_PAGE_PRIV) & ~(_SUN4C_PAGE_PRESENT));
- if(rdonly)
+ if (rdonly)
page_entry &= ~_SUN4C_WRITEABLE;
sun4c_put_pte(virt_addr, page_entry);
}
@@ -2093,12 +1932,12 @@ void sun4c_unmapioaddr(unsigned long virt_addr)
sun4c_put_pte(virt_addr, 0);
}
-static void sun4c_alloc_context_hw(struct mm_struct *mm)
+static void sun4c_alloc_context_hw(struct mm_struct *old_mm, struct mm_struct *mm)
{
struct ctx_list *ctxp;
ctxp = ctx_free.next;
- if(ctxp != &ctx_free) {
+ if (ctxp != &ctx_free) {
remove_from_ctx_list(ctxp);
add_to_used_ctxlist(ctxp);
mm->context = ctxp->ctx_number;
@@ -2106,40 +1945,33 @@ static void sun4c_alloc_context_hw(struct mm_struct *mm)
return;
}
ctxp = ctx_used.next;
- if(ctxp->ctx_mm == current->mm)
+ if (ctxp->ctx_mm == old_mm)
ctxp = ctxp->next;
-#ifdef DEBUG_SUN4C_MM
- if(ctxp == &ctx_used)
- panic("out of mmu contexts");
-#endif
remove_from_ctx_list(ctxp);
add_to_used_ctxlist(ctxp);
ctxp->ctx_mm->context = NO_CONTEXT;
ctxp->ctx_mm = mm;
mm->context = ctxp->ctx_number;
sun4c_demap_context_hw(&sun4c_context_ring[ctxp->ctx_number],
- ctxp->ctx_number);
+ ctxp->ctx_number);
}
-static void sun4c_switch_to_context_hw(struct task_struct *tsk)
+/* Switch the current MM context. */
+static void sun4c_switch_mm_hw(struct mm_struct *old_mm, struct mm_struct *mm, struct task_struct *tsk, int cpu)
{
struct ctx_list *ctx;
+ int dirty = 0;
- if(tsk->mm->context == NO_CONTEXT) {
- sun4c_alloc_context_hw(tsk->mm);
+ if (mm->context == NO_CONTEXT) {
+ dirty = 1;
+ sun4c_alloc_context_hw(old_mm, mm);
} else {
/* Update the LRU ring of contexts. */
- ctx = ctx_list_pool + tsk->mm->context;
+ ctx = ctx_list_pool + mm->context;
remove_from_ctx_list(ctx);
add_to_used_ctxlist(ctx);
}
- sun4c_set_context(tsk->mm->context);
-}
-
-static void sun4c_init_new_context_hw(struct mm_struct *mm)
-{
- sun4c_alloc_context_hw(mm);
- if(mm == current->mm)
+ if (dirty || old_mm != mm)
sun4c_set_context(mm->context);
}
@@ -2147,7 +1979,7 @@ static void sun4c_destroy_context_hw(struct mm_struct *mm)
{
struct ctx_list *ctx_old;
- if(mm->context != NO_CONTEXT && atomic_read(&mm->count) == 1) {
+ if (mm->context != NO_CONTEXT) {
sun4c_demap_context_hw(&sun4c_context_ring[mm->context], mm->context);
ctx_old = ctx_list_pool + mm->context;
remove_from_ctx_list(ctx_old);
@@ -2156,12 +1988,12 @@ static void sun4c_destroy_context_hw(struct mm_struct *mm)
}
}
-static void sun4c_alloc_context_sw(struct mm_struct *mm)
+static void sun4c_alloc_context_sw(struct mm_struct *old_mm, struct mm_struct *mm)
{
struct ctx_list *ctxp;
ctxp = ctx_free.next;
- if(ctxp != &ctx_free) {
+ if (ctxp != &ctx_free) {
remove_from_ctx_list(ctxp);
add_to_used_ctxlist(ctxp);
mm->context = ctxp->ctx_number;
@@ -2169,40 +2001,34 @@ static void sun4c_alloc_context_sw(struct mm_struct *mm)
return;
}
ctxp = ctx_used.next;
- if(ctxp->ctx_mm == current->mm)
+ if(ctxp->ctx_mm == old_mm)
ctxp = ctxp->next;
-#ifdef DEBUG_SUN4C_MM
- if(ctxp == &ctx_used)
- panic("out of mmu contexts");
-#endif
remove_from_ctx_list(ctxp);
add_to_used_ctxlist(ctxp);
ctxp->ctx_mm->context = NO_CONTEXT;
ctxp->ctx_mm = mm;
mm->context = ctxp->ctx_number;
sun4c_demap_context_sw(&sun4c_context_ring[ctxp->ctx_number],
- ctxp->ctx_number);
+ ctxp->ctx_number);
}
-static void sun4c_switch_to_context_sw(struct task_struct *tsk)
+/* Switch the current MM context. */
+static void sun4c_switch_mm_sw(struct mm_struct *old_mm, struct mm_struct *mm, struct task_struct *tsk, int cpu)
{
struct ctx_list *ctx;
+ int dirty = 0;
- if(tsk->mm->context == NO_CONTEXT) {
- sun4c_alloc_context_sw(tsk->mm);
+ if (mm->context == NO_CONTEXT) {
+ dirty = 1;
+ sun4c_alloc_context_sw(old_mm, mm);
} else {
/* Update the LRU ring of contexts. */
- ctx = ctx_list_pool + tsk->mm->context;
+ ctx = ctx_list_pool + mm->context;
remove_from_ctx_list(ctx);
add_to_used_ctxlist(ctx);
}
- sun4c_set_context(tsk->mm->context);
-}
-static void sun4c_init_new_context_sw(struct mm_struct *mm)
-{
- sun4c_alloc_context_sw(mm);
- if(mm == current->mm)
+ if (dirty || old_mm != mm)
sun4c_set_context(mm->context);
}
@@ -2210,7 +2036,7 @@ static void sun4c_destroy_context_sw(struct mm_struct *mm)
{
struct ctx_list *ctx_old;
- if(mm->context != NO_CONTEXT && atomic_read(&mm->count) == 1) {
+ if (mm->context != NO_CONTEXT) {
sun4c_demap_context_sw(&sun4c_context_ring[mm->context], mm->context);
ctx_old = ctx_list_pool + mm->context;
remove_from_ctx_list(ctx_old);
@@ -2225,7 +2051,7 @@ static int sun4c_mmu_info(char *buf)
int len;
used_user_entries = 0;
- for(i=0; i < num_contexts; i++)
+ for (i = 0; i < num_contexts; i++)
used_user_entries += sun4c_context_ring[i].num_entries;
len = sprintf(buf,
@@ -2239,10 +2065,7 @@ static int sun4c_mmu_info(char *buf)
"usedpsegs\t: %d\n"
"ufreepsegs\t: %d\n"
"user_taken\t: %d\n"
- "max_taken\t: %d\n"
- "context\t\t: %d flushes\n"
- "segment\t\t: %d flushes\n"
- "page\t\t: %d flushes\n",
+ "max_taken\t: %d\n",
sun4c_vacinfo.num_bytes,
(sun4c_vacinfo.do_hwflushes ? "yes" : "no"),
sun4c_vacinfo.linesize,
@@ -2253,22 +2076,7 @@ static int sun4c_mmu_info(char *buf)
used_user_entries,
sun4c_ufree_ring.num_entries,
sun4c_user_taken_entries,
- max_user_taken_entries,
- ctxflushes, segflushes, pageflushes);
-
-#if KGPROF_PROFILING
- {
- int i,j;
- len += sprintf(buf + len,"kgprof profiling:\n");
- for (i=0;i<KGPROF_SIZE && kgprof_counters[i].addr[0];i++) {
- len += sprintf(buf + len,"%5d ",kgprof_counters[i].count);
- for (j=0;j<KGPROF_DEPTH;j++) {
- len += sprintf(buf + len,"%08x ",kgprof_counters[i].addr[j]);
- }
- len += sprintf(buf + len,"\n");
- }
- }
-#endif
+ max_user_taken_entries);
return len;
}
@@ -2277,13 +2085,6 @@ static int sun4c_mmu_info(char *buf)
* data structures.
*/
-#if 0 /* Not used due to BTFIXUPs */
-static unsigned int sun4c_pmd_align(unsigned int addr) { return SUN4C_PMD_ALIGN(addr); }
-#endif
-#if 0 /* Not used due to BTFIXUPs */
-static unsigned int sun4c_pgdir_align(unsigned int addr) { return SUN4C_PGDIR_ALIGN(addr); }
-#endif
-
/* First the functions which the mid-level code uses to directly
* manipulate the software page tables. Some defines since we are
* emulating the i386 page directory layout.
@@ -2295,17 +2096,6 @@ static unsigned int sun4c_pgdir_align(unsigned int addr) { return SUN4C_PGDIR_AL
#define PGD_DIRTY 0x040
#define PGD_TABLE (PGD_PRESENT | PGD_RW | PGD_USER | PGD_ACCESSED | PGD_DIRTY)
-#if 0 /* Not used due to BTFIXUPs */
-static unsigned long sun4c_vmalloc_start(void)
-{
- return SUN4C_VMALLOC_START;
-}
-#endif
-
-#if 0 /* Not used due to BTFIXUPs */
-static int sun4c_pte_none(pte_t pte) { return !pte_val(pte); }
-#endif
-
static int sun4c_pte_present(pte_t pte)
{
return ((pte_val(pte) & (_SUN4C_PAGE_PRESENT | _SUN4C_PAGE_PRIV)) != 0);
@@ -2334,48 +2124,6 @@ static void sun4c_pgd_clear(pgd_t * pgdp) { }
* The following only work if pte_present() is true.
* Undefined behaviour if not..
*/
-#if 0 /* Not used due to BTFIXUPs */
-static int sun4c_pte_write(pte_t pte)
-{
- return pte_val(pte) & _SUN4C_PAGE_WRITE;
-}
-#endif
-
-#if 0 /* Not used due to BTFIXUPs */
-static int sun4c_pte_dirty(pte_t pte)
-{
- return pte_val(pte) & _SUN4C_PAGE_MODIFIED;
-}
-#endif
-
-#if 0 /* Not used due to BTFIXUPs */
-static int sun4c_pte_young(pte_t pte)
-{
- return pte_val(pte) & _SUN4C_PAGE_ACCESSED;
-}
-#endif
-
-#if 0 /* Not used due to BTFIXUPs */
-static pte_t sun4c_pte_wrprotect(pte_t pte)
-{
- return __pte(pte_val(pte) & ~(_SUN4C_PAGE_WRITE | _SUN4C_PAGE_SILENT_WRITE));
-}
-#endif
-
-#if 0 /* Not used due to BTFIXUPs */
-static pte_t sun4c_pte_mkclean(pte_t pte)
-{
- return __pte(pte_val(pte) & ~(_SUN4C_PAGE_MODIFIED | _SUN4C_PAGE_SILENT_WRITE));
-}
-#endif
-
-#if 0 /* Not used due to BTFIXUPs */
-static pte_t sun4c_pte_mkold(pte_t pte)
-{
- return __pte(pte_val(pte) & ~(_SUN4C_PAGE_ACCESSED | _SUN4C_PAGE_SILENT_READ));
-}
-#endif
-
static pte_t sun4c_pte_mkwrite(pte_t pte)
{
pte = __pte(pte_val(pte) | _SUN4C_PAGE_WRITE);
@@ -2404,9 +2152,9 @@ static pte_t sun4c_pte_mkyoung(pte_t pte)
* Conversion functions: convert a page and protection to a page entry,
* and a page entry and page directory to the page they refer to.
*/
-static pte_t sun4c_mk_pte(unsigned long page, pgprot_t pgprot)
+static pte_t sun4c_mk_pte(struct page *page, pgprot_t pgprot)
{
- return __pte(((page - PAGE_OFFSET) >> PAGE_SHIFT) | pgprot_val(pgprot));
+ return __pte((page - mem_map) | pgprot_val(pgprot));
}
static pte_t sun4c_mk_pte_phys(unsigned long phys_page, pgprot_t pgprot)
@@ -2419,17 +2167,9 @@ static pte_t sun4c_mk_pte_io(unsigned long page, pgprot_t pgprot, int space)
return __pte(((page - PAGE_OFFSET) >> PAGE_SHIFT) | pgprot_val(pgprot));
}
-#if 0 /* Not used due to BTFIXUPs */
-static pte_t sun4c_pte_modify(pte_t pte, pgprot_t newprot)
-{
- return __pte((pte_val(pte) & _SUN4C_PAGE_CHG_MASK) |
- pgprot_val(newprot));
-}
-#endif
-
-static unsigned long sun4c_pte_page(pte_t pte)
+static unsigned long sun4c_pte_pagenr(pte_t pte)
{
- return (PAGE_OFFSET + ((pte_val(pte) & SUN4C_PFN_MASK) << (PAGE_SHIFT)));
+ return (pte_val(pte) & SUN4C_PFN_MASK);
}
static inline unsigned long sun4c_pmd_page(pmd_t pmd)
@@ -2460,11 +2200,6 @@ pte_t *sun4c_pte_offset(pmd_t * dir, unsigned long address)
return (pte_t *) sun4c_pmd_page(*dir) + ((address >> PAGE_SHIFT) & (SUN4C_PTRS_PER_PTE - 1));
}
-/* Update the root mmu directory. */
-static void sun4c_update_rootmmu_dir(struct task_struct *tsk, pgd_t *pgdir)
-{
-}
-
/* Please take special note on the foo_kernel() routines below, our
* fast in window fault handler wants to get at the pte's for vmalloc
* area with traps off, therefore they _MUST_ be locked down to prevent
@@ -2487,7 +2222,7 @@ static void sun4c_pte_free_kernel(pte_t *pte)
static pte_t *sun4c_pte_alloc_kernel(pmd_t *pmd, unsigned long address)
{
- if(address >= SUN4C_LOCK_VADDR)
+ if (address >= SUN4C_LOCK_VADDR)
return NULL;
address = (address >> PAGE_SHIFT) & (SUN4C_PTRS_PER_PTE - 1);
if (sun4c_pmd_none(*pmd))
@@ -2527,7 +2262,7 @@ extern __inline__ pgd_t *sun4c_get_pgd_fast(void)
{
unsigned long *ret;
- if((ret = pgd_quicklist) != NULL) {
+ if ((ret = pgd_quicklist) != NULL) {
pgd_quicklist = (unsigned long *)(*ret);
ret[0] = ret[1];
pgtable_cache_size--;
@@ -2546,15 +2281,15 @@ extern __inline__ pgd_t *sun4c_get_pgd_fast(void)
static int sun4c_check_pgt_cache(int low, int high)
{
int freed = 0;
- if(pgtable_cache_size > high) {
+ if (pgtable_cache_size > high) {
do {
- if(pgd_quicklist)
+ if (pgd_quicklist)
free_pgd_slow(get_pgd_fast()), freed++;
- if(pmd_quicklist)
+ if (pmd_quicklist)
free_pmd_slow(get_pmd_fast()), freed++;
- if(pte_quicklist)
+ if (pte_quicklist)
free_pte_slow(get_pte_fast()), freed++;
- } while(pgtable_cache_size > low);
+ } while (pgtable_cache_size > low);
}
return freed;
}
@@ -2575,7 +2310,7 @@ extern __inline__ pte_t *sun4c_get_pte_fast(void)
{
unsigned long *ret;
- if((ret = (unsigned long *)pte_quicklist) != NULL) {
+ if ((ret = (unsigned long *)pte_quicklist) != NULL) {
pte_quicklist = (unsigned long *)(*ret);
ret[0] = ret[1];
pgtable_cache_size--;
@@ -2691,19 +2426,21 @@ static void sun4c_vac_alias_fixup(struct vm_area_struct *vma, unsigned long addr
unsigned long start;
/* Do not mistake ourselves as another mapping. */
- if(vmaring == vma)
+ if (vmaring == vma)
continue;
if (S4CVAC_BADALIAS(vaddr, address)) {
alias_found++;
start = vmaring->vm_start;
- while(start < vmaring->vm_end) {
+ while (start < vmaring->vm_end) {
pgdp = sun4c_pgd_offset(vmaring->vm_mm, start);
- if(!pgdp) goto next;
+ if (!pgdp)
+ goto next;
ptep = sun4c_pte_offset((pmd_t *) pgdp, start);
- if(!ptep) goto next;
+ if (!ptep)
+ goto next;
- if(pte_val(*ptep) & _SUN4C_PAGE_PRESENT) {
+ if (pte_val(*ptep) & _SUN4C_PAGE_PRESENT) {
flush_cache_page(vmaring, start);
*ptep = __pte(pte_val(*ptep) |
_SUN4C_PAGE_NOCACHE);
@@ -2716,54 +2453,112 @@ static void sun4c_vac_alias_fixup(struct vm_area_struct *vma, unsigned long addr
} while ((vmaring = vmaring->vm_next_share) != NULL);
spin_unlock(&inode->i_shared_lock);
- if(alias_found && !(pte_val(pte) & _SUN4C_PAGE_NOCACHE)) {
+ if (alias_found && !(pte_val(pte) & _SUN4C_PAGE_NOCACHE)) {
pgdp = sun4c_pgd_offset(vma->vm_mm, address);
ptep = sun4c_pte_offset((pmd_t *) pgdp, address);
*ptep = __pte(pte_val(*ptep) | _SUN4C_PAGE_NOCACHE);
- pte = pte_val(*ptep);
+ pte = *ptep;
}
}
}
+/* An experiment, turn off by default for now... -DaveM */
+#define SUN4C_PRELOAD_PSEG
+
void sun4c_update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t pte)
{
unsigned long flags;
+ int pseg;
save_and_cli(flags);
address &= PAGE_MASK;
- if(sun4c_get_segmap(address) == invalid_segment)
- alloc_user_segment(address, sun4c_get_context());
+ if ((pseg = sun4c_get_segmap(address)) == invalid_segment) {
+ struct sun4c_mmu_entry *entry = sun4c_user_strategy();
+ struct mm_struct *mm = vma->vm_mm;
+ unsigned long start, end;
+
+ entry->vaddr = start = (address & SUN4C_REAL_PGDIR_MASK);
+ entry->ctx = mm->context;
+ add_ring_ordered(sun4c_context_ring + mm->context, entry);
+ sun4c_put_segmap(entry->vaddr, entry->pseg);
+ end = start + SUN4C_REAL_PGDIR_SIZE;
+ while (start < end) {
+#ifdef SUN4C_PRELOAD_PSEG
+ pgd_t *pgdp = sun4c_pgd_offset(mm, start);
+ pte_t *ptep;
+
+ if (!pgdp)
+ goto no_mapping;
+ ptep = sun4c_pte_offset((pmd_t *) pgdp, start);
+ if (!ptep || !(pte_val(*ptep) & _SUN4C_PAGE_PRESENT))
+ goto no_mapping;
+ sun4c_put_pte(start, pte_val(*ptep));
+ goto next;
+
+ no_mapping:
+#endif
+ sun4c_put_pte(start, 0);
+#ifdef SUN4C_PRELOAD_PSEG
+ next:
+#endif
+ start += PAGE_SIZE;
+ }
+ if ((vma->vm_flags & (VM_WRITE|VM_SHARED)) == (VM_WRITE|VM_SHARED))
+ sun4c_vac_alias_fixup(vma, address, pte);
+#ifndef SUN4C_PRELOAD_PSEG
+ sun4c_put_pte(address, pte_val(pte));
+#endif
+ restore_flags(flags);
+ return;
+ } else {
+ struct sun4c_mmu_entry *entry = &mmu_entry_pool[pseg];
+
+ remove_lru(entry);
+ add_lru(entry);
+ }
- if((vma->vm_flags & (VM_WRITE|VM_SHARED)) == (VM_WRITE|VM_SHARED))
+ if ((vma->vm_flags & (VM_WRITE|VM_SHARED)) == (VM_WRITE|VM_SHARED))
sun4c_vac_alias_fixup(vma, address, pte);
sun4c_put_pte(address, pte_val(pte));
restore_flags(flags);
}
-extern unsigned long free_area_init(unsigned long, unsigned long);
-extern unsigned long sparc_context_init(unsigned long, int);
+extern void sparc_context_init(int);
extern unsigned long end;
+extern unsigned long bootmem_init(void);
+extern unsigned long last_valid_pfn;
+extern void sun_serial_setup(void);
-unsigned long __init sun4c_paging_init(unsigned long start_mem, unsigned long end_mem)
+void __init sun4c_paging_init(void)
{
int i, cnt;
unsigned long kernel_end, vaddr;
- extern unsigned long sparc_iobase_vaddr;
+ extern struct resource sparc_iomap;
+ unsigned long end_pfn;
kernel_end = (unsigned long) &end;
kernel_end += (SUN4C_REAL_PGDIR_SIZE * 4);
kernel_end = SUN4C_REAL_PGDIR_ALIGN(kernel_end);
+
+ last_valid_pfn = end_pfn = bootmem_init();
+
+ /* This does not logically belong here, but we need to
+ * call it at the moment we are able to use the bootmem
+ * allocator.
+ */
+ sun_serial_setup();
+
sun4c_probe_mmu();
invalid_segment = (num_segmaps - 1);
sun4c_init_mmu_entry_pool();
- sun4c_init_rings(&start_mem);
+ sun4c_init_rings();
sun4c_init_map_kernelprom(kernel_end);
sun4c_init_clean_mmu(kernel_end);
sun4c_init_fill_kernel_ring(SUN4C_KERNEL_BUCKETS);
- sun4c_init_lock_area(sparc_iobase_vaddr, IOBASE_END);
+ sun4c_init_lock_area(sparc_iomap.start, IOBASE_END);
sun4c_init_lock_area(DVMA_VADDR, DVMA_END);
- start_mem = sun4c_init_lock_areas(start_mem);
+ sun4c_init_lock_areas();
sun4c_init_fill_user_ring();
sun4c_set_context(0);
@@ -2783,18 +2578,23 @@ unsigned long __init sun4c_paging_init(unsigned long start_mem, unsigned long en
vaddr += SUN4C_PGDIR_SIZE;
swapper_pg_dir[vaddr>>SUN4C_PGDIR_SHIFT] = __pgd(PGD_TABLE | (unsigned long) pg3);
sun4c_init_ss2_cache_bug();
- start_mem = PAGE_ALIGN(start_mem);
- start_mem = sparc_context_init(start_mem, num_contexts);
- start_mem = free_area_init(start_mem, end_mem);
+ sparc_context_init(num_contexts);
+
+ {
+ unsigned int zones_size[MAX_NR_ZONES] = { 0, 0, 0};
+
+ zones_size[ZONE_DMA] = end_pfn;
+ free_area_init(zones_size);
+ }
+
cnt = 0;
- for(i = 0; i < num_segmaps; i++)
- if(mmu_entry_pool[i].locked)
+ for (i = 0; i < num_segmaps; i++)
+ if (mmu_entry_pool[i].locked)
cnt++;
max_user_taken_entries = num_segmaps - cnt - 40 - 1;
printk("SUN4C: %d mmu entries for the kernel\n", cnt);
- return start_mem;
}
/* Load up routines and constants for sun4c mmu */
@@ -2839,7 +2639,7 @@ void __init ld_mmu_sun4c(void)
BTFIXUPSET_CALL(flush_cache_all, sun4c_flush_cache_all, BTFIXUPCALL_NORM);
- if(sun4c_vacinfo.do_hwflushes) {
+ if (sun4c_vacinfo.do_hwflushes) {
BTFIXUPSET_CALL(flush_cache_mm, sun4c_flush_cache_mm_hw, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(flush_cache_range, sun4c_flush_cache_range_hw, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(flush_cache_page, sun4c_flush_cache_page_hw, BTFIXUPCALL_NORM);
@@ -2848,9 +2648,8 @@ void __init ld_mmu_sun4c(void)
BTFIXUPSET_CALL(flush_tlb_range, sun4c_flush_tlb_range_hw, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(flush_tlb_page, sun4c_flush_tlb_page_hw, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(free_task_struct, sun4c_free_task_struct_hw, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(switch_to_context, sun4c_switch_to_context_hw, BTFIXUPCALL_NORM);
+ BTFIXUPSET_CALL(switch_mm, sun4c_switch_mm_hw, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(destroy_context, sun4c_destroy_context_hw, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(init_new_context, sun4c_init_new_context_hw, BTFIXUPCALL_NORM);
} else {
BTFIXUPSET_CALL(flush_cache_mm, sun4c_flush_cache_mm_sw, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(flush_cache_range, sun4c_flush_cache_range_sw, BTFIXUPCALL_NORM);
@@ -2860,9 +2659,8 @@ void __init ld_mmu_sun4c(void)
BTFIXUPSET_CALL(flush_tlb_range, sun4c_flush_tlb_range_sw, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(flush_tlb_page, sun4c_flush_tlb_page_sw, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(free_task_struct, sun4c_free_task_struct_sw, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(switch_to_context, sun4c_switch_to_context_sw, BTFIXUPCALL_NORM);
+ BTFIXUPSET_CALL(switch_mm, sun4c_switch_mm_sw, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(destroy_context, sun4c_destroy_context_sw, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(init_new_context, sun4c_init_new_context_sw, BTFIXUPCALL_NORM);
}
BTFIXUPSET_CALL(flush_tlb_all, sun4c_flush_tlb_all, BTFIXUPCALL_NORM);
@@ -2871,15 +2669,13 @@ void __init ld_mmu_sun4c(void)
BTFIXUPSET_CALL(set_pte, sun4c_set_pte, BTFIXUPCALL_STO1O0);
- BTFIXUPSET_CALL(pte_page, sun4c_pte_page, BTFIXUPCALL_NORM);
+ BTFIXUPSET_CALL(pte_pagenr, sun4c_pte_pagenr, BTFIXUPCALL_NORM);
#if PAGE_SHIFT <= 12
BTFIXUPSET_CALL(pmd_page, sun4c_pmd_page, BTFIXUPCALL_ANDNINT(PAGE_SIZE - 1));
#else
BTFIXUPSET_CALL(pmd_page, sun4c_pmd_page, BTFIXUPCALL_NORM);
#endif
- BTFIXUPSET_CALL(sparc_update_rootmmu_dir, sun4c_update_rootmmu_dir, BTFIXUPCALL_NOP);
-
BTFIXUPSET_CALL(pte_present, sun4c_pte_present, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(pte_clear, sun4c_pte_clear, BTFIXUPCALL_STG0O0);
@@ -2931,6 +2727,9 @@ void __init ld_mmu_sun4c(void)
BTFIXUPSET_CALL(mmu_release_scsi_sgl, sun4c_release_scsi_sgl, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(mmu_map_dma_area, sun4c_map_dma_area, BTFIXUPCALL_NORM);
+ BTFIXUPSET_CALL(mmu_unmap_dma_area, sun4c_unmap_dma_area, BTFIXUPCALL_NORM);
+ BTFIXUPSET_CALL(mmu_flush_dma_area, sun4c_flush_dma_area, BTFIXUPCALL_NOP);
+ BTFIXUPSET_CALL(mmu_inval_dma_area, sun4c_inval_dma_area, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(mmu_v2p, sun4c_v2p, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(mmu_p2v, sun4c_p2v, BTFIXUPCALL_NORM);
diff --git a/arch/sparc/mm/swift.S b/arch/sparc/mm/swift.S
new file mode 100644
index 000000000..e9fe43293
--- /dev/null
+++ b/arch/sparc/mm/swift.S
@@ -0,0 +1,275 @@
+/* $Id: swift.S,v 1.3 1999/11/14 06:13:56 zaitcev Exp $
+ * swift.S: MicroSparc-II mmu/cache operations.
+ *
+ * Copyright (C) 1999 David S. Miller (davem@redhat.com)
+ */
+
+#include <asm/psr.h>
+#include <asm/asi.h>
+#include <asm/page.h>
+#include <asm/pgtsrmmu.h>
+#include <asm/asm_offsets.h>
+
+#define WINDOW_FLUSH(tmp1, tmp2) \
+ mov 0, tmp1; \
+98: ld [%g6 + AOFF_task_thread + AOFF_thread_uwinmask], tmp2; \
+ orcc %g0, tmp2, %g0; \
+ add tmp1, 1, tmp1; \
+ bne 98b; \
+ save %sp, -64, %sp; \
+99: subcc tmp1, 1, tmp1; \
+ bne 99b; \
+ restore %g0, %g0, %g0;
+
+ .text
+ .align 4
+
+#if 1 /* XXX screw this, I can't get the VAC flushes working
+ * XXX reliably... -DaveM
+ */
+ .globl swift_flush_cache_all, swift_flush_cache_mm
+ .globl swift_flush_cache_range, swift_flush_cache_page
+ .globl swift_flush_page_for_dma, swift_flush_chunk
+ .globl swift_flush_page_to_ram
+
+swift_flush_cache_all:
+swift_flush_cache_mm:
+swift_flush_cache_range:
+swift_flush_cache_page:
+swift_flush_page_for_dma:
+swift_flush_chunk:
+swift_flush_page_to_ram:
+ sethi %hi(0x2000), %o0
+1: subcc %o0, 0x10, %o0
+ sta %g0, [%o0] ASI_M_TXTC_TAG
+ sta %g0, [%o0] ASI_M_DATAC_TAG
+ bne 1b
+ nop
+ retl
+ nop
+#else
+
+ .globl swift_flush_cache_all
+swift_flush_cache_all:
+ WINDOW_FLUSH(%g4, %g5)
+
+ /* Just clear out all the tags. */
+ sethi %hi(16 * 1024), %o0
+1: subcc %o0, 16, %o0
+ sta %g0, [%o0] ASI_M_TXTC_TAG
+ bne 1b
+ sta %g0, [%o0] ASI_M_DATAC_TAG
+ retl
+ nop
+
+ .globl swift_flush_cache_mm
+swift_flush_cache_mm:
+#ifndef __SMP__
+ ld [%o0 + AOFF_mm_context], %g2
+ cmp %g2, -1
+ be swift_flush_cache_mm_out
+#endif
+ WINDOW_FLUSH(%g4, %g5)
+ rd %psr, %g1
+ andn %g1, PSR_ET, %g3
+ wr %g3, 0x0, %psr
+ nop
+ nop
+ mov SRMMU_CTX_REG, %g7
+ lda [%g7] ASI_M_MMUREGS, %g5
+ sta %g2, [%g7] ASI_M_MMUREGS
+
+#if 1
+ sethi %hi(0x2000), %o0
+1: subcc %o0, 0x10, %o0
+ sta %g0, [%o0] ASI_M_FLUSH_CTX
+ bne 1b
+ nop
+#else
+ clr %o0
+ or %g0, 2048, %g7
+ or %g0, 2048, %o1
+ add %o1, 2048, %o2
+ add %o2, 2048, %o3
+ mov 16, %o4
+ add %o4, 2048, %o5
+ add %o5, 2048, %g2
+ add %g2, 2048, %g3
+1: sta %g0, [%o0 ] ASI_M_FLUSH_CTX
+ sta %g0, [%o0 + %o1] ASI_M_FLUSH_CTX
+ sta %g0, [%o0 + %o2] ASI_M_FLUSH_CTX
+ sta %g0, [%o0 + %o3] ASI_M_FLUSH_CTX
+ sta %g0, [%o0 + %o4] ASI_M_FLUSH_CTX
+ sta %g0, [%o0 + %o5] ASI_M_FLUSH_CTX
+ sta %g0, [%o0 + %g2] ASI_M_FLUSH_CTX
+ sta %g0, [%o0 + %g3] ASI_M_FLUSH_CTX
+ subcc %g7, 32, %g7
+ bne 1b
+ add %o0, 32, %o0
+#endif
+
+ mov SRMMU_CTX_REG, %g7
+ sta %g5, [%g7] ASI_M_MMUREGS
+ wr %g1, 0x0, %psr
+ nop
+ nop
+swift_flush_cache_mm_out:
+ retl
+ nop
+
+ .globl swift_flush_cache_range
+swift_flush_cache_range:
+ sub %o2, %o1, %o2
+ sethi %hi(4096), %o3
+ cmp %o2, %o3
+ bgu swift_flush_cache_mm
+ nop
+ b 70f
+ nop
+
+ .globl swift_flush_cache_page
+swift_flush_cache_page:
+ ld [%o0 + 0x0], %o0 /* XXX vma->vm_mm, GROSS XXX */
+70:
+#ifndef __SMP__
+ ld [%o0 + AOFF_mm_context], %g2
+ cmp %g2, -1
+ be swift_flush_cache_page_out
+#endif
+ WINDOW_FLUSH(%g4, %g5)
+ rd %psr, %g1
+ andn %g1, PSR_ET, %g3
+ wr %g3, 0x0, %psr
+ nop
+ nop
+ mov SRMMU_CTX_REG, %g7
+ lda [%g7] ASI_M_MMUREGS, %g5
+ sta %g2, [%g7] ASI_M_MMUREGS
+
+ andn %o1, (PAGE_SIZE - 1), %o1
+#if 1
+ sethi %hi(0x1000), %o0
+1: subcc %o0, 0x10, %o0
+ sta %g0, [%o1 + %o0] ASI_M_FLUSH_PAGE
+ bne 1b
+ nop
+#else
+ or %g0, 512, %g7
+ or %g0, 512, %o0
+ add %o0, 512, %o2
+ add %o2, 512, %o3
+ add %o3, 512, %o4
+ add %o4, 512, %o5
+ add %o5, 512, %g3
+ add %g3, 512, %g4
+1: sta %g0, [%o1 ] ASI_M_FLUSH_PAGE
+ sta %g0, [%o1 + %o0] ASI_M_FLUSH_PAGE
+ sta %g0, [%o1 + %o2] ASI_M_FLUSH_PAGE
+ sta %g0, [%o1 + %o3] ASI_M_FLUSH_PAGE
+ sta %g0, [%o1 + %o4] ASI_M_FLUSH_PAGE
+ sta %g0, [%o1 + %o5] ASI_M_FLUSH_PAGE
+ sta %g0, [%o1 + %g3] ASI_M_FLUSH_PAGE
+ sta %g0, [%o1 + %g4] ASI_M_FLUSH_PAGE
+ subcc %g7, 16, %g7
+ bne 1b
+ add %o1, 16, %o1
+#endif
+
+ mov SRMMU_CTX_REG, %g7
+ sta %g5, [%g7] ASI_M_MMUREGS
+ wr %g1, 0x0, %psr
+ nop
+ nop
+swift_flush_cache_page_out:
+ retl
+ nop
+
+ /* Swift is write-thru, however it is not
+ * I/O nor TLB-walk coherent. Also it has
+ * caches which are virtually indexed and tagged.
+ */
+ .globl swift_flush_page_for_dma
+ .globl swift_flush_chunk
+ .globl swift_flush_page_to_ram
+swift_flush_page_for_dma:
+swift_flush_chunk:
+swift_flush_page_to_ram:
+ andn %o0, (PAGE_SIZE - 1), %o1
+#if 1
+ sethi %hi(0x1000), %o0
+1: subcc %o0, 0x10, %o0
+ sta %g0, [%o1 + %o0] ASI_M_FLUSH_PAGE
+ bne 1b
+ nop
+#else
+ or %g0, 512, %g7
+ or %g0, 512, %o0
+ add %o0, 512, %o2
+ add %o2, 512, %o3
+ add %o3, 512, %o4
+ add %o4, 512, %o5
+ add %o5, 512, %g3
+ add %g3, 512, %g4
+1: sta %g0, [%o1 ] ASI_M_FLUSH_PAGE
+ sta %g0, [%o1 + %o0] ASI_M_FLUSH_PAGE
+ sta %g0, [%o1 + %o2] ASI_M_FLUSH_PAGE
+ sta %g0, [%o1 + %o3] ASI_M_FLUSH_PAGE
+ sta %g0, [%o1 + %o4] ASI_M_FLUSH_PAGE
+ sta %g0, [%o1 + %o5] ASI_M_FLUSH_PAGE
+ sta %g0, [%o1 + %g3] ASI_M_FLUSH_PAGE
+ sta %g0, [%o1 + %g4] ASI_M_FLUSH_PAGE
+ subcc %g7, 16, %g7
+ bne 1b
+ add %o1, 16, %o1
+#endif
+ retl
+ nop
+#endif
+
+ .globl swift_flush_sig_insns
+swift_flush_sig_insns:
+ flush %o1
+ retl
+ flush %o1 + 4
+
+ .globl swift_flush_tlb_mm
+ .globl swift_flush_tlb_range
+ .globl swift_flush_tlb_all
+swift_flush_tlb_mm:
+swift_flush_tlb_range:
+#ifndef __SMP__
+ ld [%o0 + AOFF_mm_context], %g2
+ cmp %g2, -1
+ be swift_flush_tlb_all_out
+#endif
+swift_flush_tlb_all:
+ mov 0x400, %o1
+ sta %g0, [%o1] ASI_M_FLUSH_PROBE
+swift_flush_tlb_all_out:
+ retl
+ nop
+
+ .globl swift_flush_tlb_page
+swift_flush_tlb_page:
+ ld [%o0 + 0x00], %o0 /* XXX vma->vm_mm GROSS XXX */
+ mov SRMMU_CTX_REG, %g1
+ ld [%o0 + AOFF_mm_context], %o3
+ andn %o1, (PAGE_SIZE - 1), %o1
+#ifndef __SMP__
+ cmp %o3, -1
+ be swift_flush_tlb_page_out
+ nop
+#endif
+#if 1
+ mov 0x400, %o1
+ sta %g0, [%o1] ASI_M_FLUSH_PROBE
+#else
+ lda [%g1] ASI_M_MMUREGS, %g5
+ sta %o3, [%g1] ASI_M_MMUREGS
+ sta %g0, [%o1] ASI_M_FLUSH_PAGE /* rem. virt. cache. prot. */
+ sta %g0, [%o1] ASI_M_FLUSH_PROBE
+ sta %g5, [%g1] ASI_M_MMUREGS
+#endif
+swift_flush_tlb_page_out:
+ retl
+ nop
diff --git a/arch/sparc/mm/tsunami.S b/arch/sparc/mm/tsunami.S
index 1c4356fa0..07c5ed620 100644
--- a/arch/sparc/mm/tsunami.S
+++ b/arch/sparc/mm/tsunami.S
@@ -1,4 +1,4 @@
-/* $Id: tsunami.S,v 1.2 1999/08/14 03:51:48 anton Exp $
+/* $Id: tsunami.S,v 1.3 1999/10/09 05:32:19 zaitcev Exp $
* tsunami.S: High speed MicroSparc-I mmu/cache operations.
*
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -44,11 +44,11 @@ tsunami_flush_cache_range:
tsunami_flush_cache_all:
WINDOW_FLUSH(%g4, %g5)
tsunami_flush_page_for_dma:
- sta %g0, [%g0] ASI_M_DC_FLCLEAR
sta %g0, [%g0] ASI_M_IC_FLCLEAR
+tsunami_flush_chunk:
+ sta %g0, [%g0] ASI_M_DC_FLCLEAR
tsunami_flush_cache_out:
tsunami_flush_page_to_ram:
-tsunami_flush_chunk:
retl
nop
@@ -68,6 +68,11 @@ tsunami_flush_tlb_range:
tsunami_flush_tlb_all:
mov 0x400, %o1
sta %g0, [%o1] ASI_M_FLUSH_PROBE
+ nop
+ nop
+ nop
+ nop
+ nop
tsunami_flush_tlb_out:
retl
nop
@@ -85,6 +90,59 @@ tsunami_flush_tlb_page:
lda [%g1] ASI_M_MMUREGS, %g5
sta %o3, [%g1] ASI_M_MMUREGS
sta %g0, [%o1] ASI_M_FLUSH_PROBE
+ nop
+ nop
+ nop
+ nop
+ nop
tsunami_flush_tlb_page_out:
retl
sta %g5, [%g1] ASI_M_MMUREGS
+
+#define MIRROR_BLOCK(dst, src, offset, t0, t1, t2, t3) \
+ ldd [src + offset + 0x18], t0; \
+ std t0, [dst + offset + 0x18]; \
+ ldd [src + offset + 0x10], t2; \
+ std t2, [dst + offset + 0x10]; \
+ ldd [src + offset + 0x08], t0; \
+ std t0, [dst + offset + 0x08]; \
+ ldd [src + offset + 0x00], t2; \
+ std t2, [dst + offset + 0x00];
+
+ .globl tsunami_copy_1page
+tsunami_copy_1page:
+/* NOTE: This routine has to be shorter than 70insns --jj */
+ or %g0, (PAGE_SIZE >> 8), %g1
+1:
+ MIRROR_BLOCK(%o0, %o1, 0x00, %o2, %o3, %o4, %o5)
+ MIRROR_BLOCK(%o0, %o1, 0x20, %o2, %o3, %o4, %o5)
+ MIRROR_BLOCK(%o0, %o1, 0x40, %o2, %o3, %o4, %o5)
+ MIRROR_BLOCK(%o0, %o1, 0x60, %o2, %o3, %o4, %o5)
+ MIRROR_BLOCK(%o0, %o1, 0x80, %o2, %o3, %o4, %o5)
+ MIRROR_BLOCK(%o0, %o1, 0xa0, %o2, %o3, %o4, %o5)
+ MIRROR_BLOCK(%o0, %o1, 0xc0, %o2, %o3, %o4, %o5)
+ MIRROR_BLOCK(%o0, %o1, 0xe0, %o2, %o3, %o4, %o5)
+ subcc %g1, 1, %g1
+ add %o0, 0x100, %o0
+ bne 1b
+ add %o1, 0x100, %o1
+
+ .globl tsunami_setup_blockops
+tsunami_setup_blockops:
+ sethi %hi(__copy_1page), %o0
+ or %o0, %lo(__copy_1page), %o0
+ sethi %hi(tsunami_copy_1page), %o1
+ or %o1, %lo(tsunami_copy_1page), %o1
+ sethi %hi(tsunami_setup_blockops), %o2
+ or %o2, %lo(tsunami_setup_blockops), %o2
+ ld [%o1], %o4
+1: add %o1, 4, %o1
+ st %o4, [%o0]
+ add %o0, 4, %o0
+ cmp %o1, %o2
+ bne 1b
+ ld [%o1], %o4
+ sta %g0, [%g0] ASI_M_IC_FLCLEAR
+ sta %g0, [%g0] ASI_M_DC_FLCLEAR
+ retl
+ nop
diff --git a/arch/sparc/prom/Makefile b/arch/sparc/prom/Makefile
index 917aa9ad7..f8c41ccdf 100644
--- a/arch/sparc/prom/Makefile
+++ b/arch/sparc/prom/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.6 1998/01/30 10:58:59 jj Exp $
+# $Id: Makefile,v 1.7 1999/12/21 04:02:21 davem Exp $
# Makefile for the Sun Boot PROM interface library under
# Linux.
#
@@ -22,6 +22,6 @@ promlib.a: $(OBJS)
sync
dep:
- $(CPP) -M *.c > .depend
+ $(CPP) $(CPPFLAGS) -M *.c > .depend
include $(TOPDIR)/Rules.make
diff --git a/arch/sparc/prom/ranges.c b/arch/sparc/prom/ranges.c
index 89748c49c..244619eb6 100644
--- a/arch/sparc/prom/ranges.c
+++ b/arch/sparc/prom/ranges.c
@@ -1,4 +1,4 @@
-/* $Id: ranges.c,v 1.12 1999/08/31 06:54:47 davem Exp $
+/* $Id: ranges.c,v 1.14 1999/10/06 19:28:54 zaitcev Exp $
* ranges.c: Handle ranges in newer proms for obio/sbus.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -8,6 +8,7 @@
#include <linux/init.h>
#include <asm/openprom.h>
#include <asm/oplib.h>
+#include <asm/types.h>
#include <asm/sbus.h>
#include <asm/system.h>
@@ -64,24 +65,6 @@ prom_apply_obio_ranges(struct linux_prom_registers *regs, int nregs)
prom_adjust_regs(regs, nregs, promlib_obio_ranges, num_obio_ranges);
}
-/* Apply probed sbus ranges to registers passed, if no ranges return. */
-void prom_apply_sbus_ranges(struct linux_sbus *sbus, struct linux_prom_registers *regs,
- int nregs, struct linux_sbus_device *sdev)
-{
- if(sbus && sbus->num_sbus_ranges) {
- if(sdev && (sdev->ranges_applied == 0)) {
- sdev->ranges_applied = 1;
- prom_adjust_regs(regs, nregs, sbus->sbus_ranges,
- sbus->num_sbus_ranges);
- } else if(!sdev) {
- printk("PROMLIB: Aieee, old SBUS driver, update it to use new "
- "prom_apply_sbus_ranges interface now!\n");
- prom_adjust_regs(regs, nregs, sbus->sbus_ranges,
- sbus->num_sbus_ranges);
- }
- }
-}
-
void __init prom_ranges_init(void)
{
int node, obio_node;
@@ -107,32 +90,6 @@ void __init prom_ranges_init(void)
return;
}
-void __init prom_sbus_ranges_init(int parentnd, struct linux_sbus *sbus)
-{
- int success;
-
- sbus->num_sbus_ranges = 0;
- if(sparc_cpu_model == sun4c)
- return;
- success = prom_getproperty(sbus->prom_node, "ranges",
- (char *) sbus->sbus_ranges,
- sizeof (sbus->sbus_ranges));
- if (success != -1)
- sbus->num_sbus_ranges = (success/sizeof(struct linux_prom_ranges));
- if (sparc_cpu_model == sun4d) {
- struct linux_prom_ranges iounit_ranges[PROMREG_MAX];
- int num_iounit_ranges;
-
- success = prom_getproperty(parentnd, "ranges",
- (char *) iounit_ranges,
- sizeof (iounit_ranges));
- if (success != -1) {
- num_iounit_ranges = (success/sizeof(struct linux_prom_ranges));
- prom_adjust_ranges (sbus->sbus_ranges, sbus->num_sbus_ranges, iounit_ranges, num_iounit_ranges);
- }
- }
-}
-
void
prom_apply_generic_ranges (int node, int parent, struct linux_prom_registers *regs, int nregs)
{
diff --git a/arch/sparc64/Makefile b/arch/sparc64/Makefile
index 1216a3a4f..4f51537e2 100644
--- a/arch/sparc64/Makefile
+++ b/arch/sparc64/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.40 1999/08/19 02:31:57 davem Exp $
+# $Id: Makefile,v 1.41 1999/12/21 04:02:23 davem Exp $
# sparc64/Makefile
#
# Makefile for the architecture dependent flags and dependencies on the
@@ -12,17 +12,11 @@
# line...
SHELL =/bin/bash
-CC := sparc64-linux-gcc -D__KERNEL__ -I$(TOPDIR)/include
+CC := sparc64-linux-gcc
-CC_HAS_ARGS := $(shell if echo "$(CC)" | grep '\(__KERNEL__\| \)' > /dev/null; then echo y; else echo n; fi)
IS_EGCS := $(shell if $(CC) -m64 -mcmodel=medlow -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo y; else echo n; fi; )
NEW_GAS := $(shell if $(LD) --version 2>&1 | grep 'elf64_sparc' > /dev/null; then echo y; else echo n; fi)
-ifneq ($(CC_HAS_ARGS),y)
-MAKEOVERRIDES := $(shell echo "$(MAKEOVERRIDES)" | sed 's CC=$(CC) CC=$(CC)\\\ -D__KERNEL__\\\ -I$(TOPDIR)/include ')
-override CC := $(CC) -D__KERNEL__ -I$(TOPDIR)/include
-endif
-
ifneq ($(NEW_GAS),y)
AS = sparc64-linux-as
LD = sparc64-linux-ld
diff --git a/arch/sparc64/config.in b/arch/sparc64/config.in
index 01fc2e43a..c1ef46648 100644
--- a/arch/sparc64/config.in
+++ b/arch/sparc64/config.in
@@ -1,4 +1,4 @@
-# $Id: config.in,v 1.78 1999/09/06 01:17:28 davem Exp $
+# $Id: config.in,v 1.86 1999/12/23 01:46:09 davem Exp $
# For a description of the syntax of this configuration file,
# see the Configure script.
#
@@ -41,17 +41,13 @@ source drivers/pci/Config.in
source drivers/sbus/char/Config.in
source drivers/sbus/audio/Config.in
-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- tristate 'Openprom tree appears in /proc/openprom (EXPERIMENTAL)' CONFIG_SUN_OPENPROMFS
-fi
+tristate 'Openprom tree appears in /proc/openprom' CONFIG_SUN_OPENPROMFS
bool 'Networking support' CONFIG_NET
bool 'System V IPC' CONFIG_SYSVIPC
bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT
bool 'Sysctl support' CONFIG_SYSCTL
if [ "$CONFIG_PROC_FS" = "y" ]; then
- choice 'Kernel core (/proc/kcore) format' \
- "ELF CONFIG_KCORE_ELF \
- A.OUT CONFIG_KCORE_AOUT" ELF
+ define_bool CONFIG_KCORE_ELF y
fi
bool 'Kernel support for Linux/Sparc 32bit binary compatibility' CONFIG_SPARC32_COMPAT
if [ "$CONFIG_SPARC32_COMPAT" != "n" ]; then
@@ -60,6 +56,7 @@ if [ "$CONFIG_SPARC32_COMPAT" != "n" ]; then
fi
tristate 'Kernel support for 64-bit ELF binaries' CONFIG_BINFMT_ELF
tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
+bool 'SunOS binary emulation' CONFIG_SUNOS_EMUL
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
tristate 'Solaris binary emulation (EXPERIMENTAL)' CONFIG_SOLARIS_EMUL
fi
@@ -148,7 +145,7 @@ if [ "$CONFIG_SCSI" != "n" ]; then
mainmenu_option next_comment
comment 'SCSI low-level drivers'
- bool 'Sparc ESP Scsi Driver' CONFIG_SCSI_SUNESP $CONFIG_SCSI
+ tristate 'Sparc ESP Scsi Driver' CONFIG_SCSI_SUNESP $CONFIG_SCSI
tristate 'PTI Qlogic, ISP Driver' CONFIG_SCSI_QLOGICPTI $CONFIG_SCSI
if [ "$CONFIG_PCI" != "n" ]; then
@@ -159,8 +156,8 @@ if [ "$CONFIG_SCSI" != "n" ]; then
bool ' Collect statistics to report in /proc' CONFIG_AIC7XXX_PROC_STATS N
int ' Delay in seconds after SCSI bus reset' CONFIG_AIC7XXX_RESET_DELAY 5
fi
- dep_tristate 'NCR53C8XX SCSI support' CONFIG_SCSI_NCR53C8XX $CONFIG_SCSI
- if [ "$CONFIG_SCSI_NCR53C8XX" != "n" ]; then
+ dep_tristate 'SYM53C8XX SCSI support' CONFIG_SCSI_SYM53C8XX $CONFIG_SCSI
+ if [ "$CONFIG_SCSI_SYM53C8XX" != "n" ]; then
int 'default tagged command queue depth' CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS 8
int 'maximum number of queued commands' CONFIG_SCSI_NCR53C8XX_MAX_TAGS 32
int 'synchronous transfers frequency in MHz' CONFIG_SCSI_NCR53C8XX_SYNC 10
@@ -190,7 +187,10 @@ if [ "$CONFIG_NET" = "y" ]; then
tristate ' Dummy net driver support' CONFIG_DUMMY
tristate ' PPP (point-to-point) support' CONFIG_PPP
if [ ! "$CONFIG_PPP" = "n" ]; then
- comment ' CCP compressors for PPP are only built as modules.'
+ dep_tristate ' PPP support for async serial ports' CONFIG_PPP_ASYNC $CONFIG_PPP
+ dep_tristate ' PPP support for sync tty ports' CONFIG_PPP_SYNC_TTY $CONFIG_PPP
+ dep_tristate ' PPP Deflate compression' CONFIG_PPP_DEFLATE $CONFIG_PPP
+ dep_tristate ' PPP BSD-Compress compression' CONFIG_PPP_BSDCOMP m
fi
tristate ' SLIP (serial line) support' CONFIG_SLIP
if [ "$CONFIG_SLIP" != "n" ]; then
diff --git a/arch/sparc64/defconfig b/arch/sparc64/defconfig
index 904027e07..848984fef 100644
--- a/arch/sparc64/defconfig
+++ b/arch/sparc64/defconfig
@@ -8,13 +8,6 @@
CONFIG_EXPERIMENTAL=y
#
-# Loadable module support
-#
-CONFIG_MODULES=y
-CONFIG_MODVERSIONS=y
-CONFIG_KMOD=y
-
-#
# General setup
#
CONFIG_VT=y
@@ -26,11 +19,21 @@ CONFIG_VT_CONSOLE=y
#
CONFIG_PROM_CONSOLE=y
CONFIG_FB=y
+
+#
+# Frame-buffer support
+#
+CONFIG_FB=y
CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FB_RIVA is not set
# CONFIG_FB_CLGEN is not set
-# CONFIG_FB_PM2 is not set
+CONFIG_FB_PM2=y
+# CONFIG_FB_PM2_FIFO_DISCONNECT is not set
+CONFIG_FB_PM2_PCI=y
# CONFIG_FB_MATROX is not set
CONFIG_FB_ATY=y
+# CONFIG_FB_ATY128 is not set
+# CONFIG_FB_3DFX is not set
CONFIG_FB_SBUS=y
CONFIG_FB_CREATOR=y
CONFIG_FB_CGSIX=y
@@ -73,6 +76,7 @@ CONFIG_OBP_FLASH=m
# CONFIG_SUN_VIDEOPIX is not set
CONFIG_SUN_AURORA=m
# CONFIG_TADPOLE_TS102_UCTRL is not set
+# CONFIG_SUN_JSFLASH is not set
CONFIG_APM_RTC_IS_GMT=y
# CONFIG_RTC is not set
@@ -90,12 +94,12 @@ CONFIG_SYSVIPC=y
# CONFIG_BSD_PROCESS_ACCT is not set
CONFIG_SYSCTL=y
CONFIG_KCORE_ELF=y
-# CONFIG_KCORE_AOUT is not set
CONFIG_SPARC32_COMPAT=y
-CONFIG_BINFMT_ELF=y
CONFIG_BINFMT_ELF32=y
# CONFIG_BINFMT_AOUT32 is not set
+CONFIG_BINFMT_ELF=y
CONFIG_BINFMT_MISC=m
+# CONFIG_SUNOS_EMUL is not set
CONFIG_SOLARIS_EMUL=m
CONFIG_PARPORT=m
CONFIG_PARPORT_PC=m
@@ -110,12 +114,18 @@ CONFIG_PRINTER=m
CONFIG_ENVCTRL=m
#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODVERSIONS=y
+CONFIG_KMOD=y
+
+#
# Floppy, IDE, and other block devices
#
CONFIG_BLK_DEV_FD=y
# CONFIG_BLK_DEV_MD is not set
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_INITRD=y
+# CONFIG_BLK_DEV_RAM is not set
CONFIG_BLK_DEV_LOOP=m
CONFIG_BLK_DEV_NBD=m
CONFIG_BLK_DEV_IDE=y
@@ -127,7 +137,7 @@ CONFIG_BLK_DEV_IDEFLOPPY=m
CONFIG_BLK_DEV_IDEPCI=y
CONFIG_BLK_DEV_IDEDMA=y
CONFIG_IDEDMA_AUTO=y
-IDEDMA_NEW_DRIVE_LISTINGS=y
+CONFIG_IDEDMA_NEW_DRIVE_LISTINGS=y
CONFIG_BLK_DEV_NS87415=y
CONFIG_BLK_DEV_CMD646=y
@@ -210,11 +220,11 @@ CONFIG_SCSI_CONSTANTS=y
CONFIG_SCSI_SUNESP=y
CONFIG_SCSI_QLOGICPTI=m
CONFIG_SCSI_AIC7XXX=y
-# CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT is not set
-# CONFIG_CMDS_PER_DEVICE is not set
+CONFIG_AIC7XXX_TAGGED_QUEUEING=y
+CONFIG_AIC7XXX_CMDS_PER_DEVICE=8
CONFIG_AIC7XXX_PROC_STATS=y
CONFIG_AIC7XXX_RESET_DELAY=5
-CONFIG_SCSI_NCR53C8XX=y
+CONFIG_SCSI_SYM53C8XX=y
CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=4
CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32
CONFIG_SCSI_NCR53C8XX_SYNC=10
@@ -245,10 +255,10 @@ CONFIG_SCSI_FCAL=m
CONFIG_NETDEVICES=y
CONFIG_DUMMY=m
CONFIG_PPP=m
-
-#
-# CCP compressors for PPP are only built as modules.
-#
+# CONFIG_PPP_ASYNC is not set
+# CONFIG_PPP_SYNC_TTY is not set
+# CONFIG_PPP_DEFLATE is not set
+# CONFIG_PPP_BSDCOMP is not set
CONFIG_SLIP=m
CONFIG_SLIP_COMPRESSED=y
CONFIG_SLIP_SMART=y
@@ -275,7 +285,7 @@ CONFIG_UNIX98_PTY_COUNT=256
# Video For Linux
#
CONFIG_VIDEO_DEV=y
-CONFIG_VIDEO_BT848=y
+# CONFIG_VIDEO_BT848 is not set
#
# Filesystems
@@ -285,15 +295,16 @@ CONFIG_AUTOFS_FS=m
# CONFIG_ADFS_FS is not set
CONFIG_AFFS_FS=m
# CONFIG_HFS_FS is not set
+CONFIG_BFS_FS=m
+# CONFIG_BFS_FS_WRITE is not set
CONFIG_FAT_FS=m
CONFIG_MSDOS_FS=m
# CONFIG_UMSDOS_FS is not set
CONFIG_VFAT_FS=m
CONFIG_EFS_FS=m
+CONFIG_CRAMFS=m
CONFIG_ISO9660_FS=m
# CONFIG_JOLIET is not set
-CONFIG_UDF_FS=m
-# CONFIG_UDF_RW is not set
CONFIG_MINIX_FS=m
# CONFIG_NTFS_FS is not set
CONFIG_HPFS_FS=m
@@ -303,6 +314,9 @@ CONFIG_DEVPTS_FS=y
CONFIG_ROMFS_FS=m
CONFIG_EXT2_FS=y
CONFIG_SYSV_FS=m
+# CONFIG_SYSV_FS_WRITE is not set
+CONFIG_UDF_FS=m
+# CONFIG_UDF_RW is not set
CONFIG_UFS_FS=m
CONFIG_UFS_FS_WRITE=y
@@ -312,7 +326,7 @@ CONFIG_UFS_FS_WRITE=y
CONFIG_CODA_FS=m
CONFIG_NFS_FS=y
CONFIG_NFSD=m
-# CONFIG_NFSD_SUN is not set
+CONFIG_NFSD_V3=y
CONFIG_SUNRPC=y
CONFIG_LOCKD=y
CONFIG_SMB_FS=m
@@ -322,7 +336,9 @@ CONFIG_NCP_FS=m
# CONFIG_NCPFS_STRONG is not set
# CONFIG_NCPFS_NFS_NS is not set
# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
# CONFIG_NCPFS_MOUNT_SUBDIR is not set
+# CONFIG_NCPFS_NDS_DOMAINS is not set
# CONFIG_NCPFS_NLS is not set
# CONFIG_NCPFS_EXTRAS is not set
diff --git a/arch/sparc64/kernel/Makefile b/arch/sparc64/kernel/Makefile
index 34f52698e..c84f5872e 100644
--- a/arch/sparc64/kernel/Makefile
+++ b/arch/sparc64/kernel/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.46 1999/08/31 04:39:34 davem Exp $
+# $Id: Makefile,v 1.50 1999/12/21 04:02:24 davem Exp $
# Makefile for the linux kernel.
#
# Note! Dependencies are done automagically by 'make dep', which also
@@ -17,18 +17,25 @@ all: kernel.o head.o init_task.o
O_TARGET := kernel.o
O_OBJS := process.o setup.o cpu.o idprom.o \
- traps.o devices.o auxio.o ioport.o \
+ traps.o devices.o auxio.o \
irq.o ptrace.o time.o sys_sparc.o signal.o \
- unaligned.o sys_sunos32.o sunos_ioctl32.o \
- central.o pci.o pci_common.o pci_iommu.o \
+ unaligned.o central.o pci.o pci_common.o pci_iommu.o \
pci_psycho.o pci_sabre.o starfire.o semaphore.o \
- power.o
+ power.o sbus.o iommu_common.o
OX_OBJS := sparc64_ksyms.o
ifdef CONFIG_PCI
O_OBJS += ebus.o
endif
+ifdef CONFIG_SUNOS_EMUL
+ O_OBJS += sys_sunos32.o sunos_ioctl32.o
+else
+ ifdef CONFIG_SOLARIS_EMUL
+ O_OBJS += sys_sunos32.o sunos_ioctl32.o
+ endif
+endif
+
ifdef CONFIG_SMP
O_OBJS += smp.o trampoline.o
endif
@@ -74,11 +81,13 @@ check_asm: dummy
@echo -e "# error Please issue 'make check_asm' in linux top-level directory first\n# endif\n#endif\n" >> asm_offsets.h
@echo -e "#ifndef CONFIG_SMP\n" >> asm_offsets.h
@echo "#include <linux/config.h>" > tmp.c
+ @echo "#undef __SMP__" >> tmp.c
@echo "#undef CONFIG_SMP" >> tmp.c
@echo "#include <linux/sched.h>" >> tmp.c
- $(CC) -E tmp.c -o tmp.i
+ $(CC) $(CPPFLAGS) -E tmp.c -o tmp.i
@echo "/* Automatically generated. Do not edit. */" > check_asm.c
@echo "#include <linux/config.h>" >> check_asm.c
+ @echo "#undef __SMP__" >> check_asm.c
@echo "#undef CONFIG_SMP" >> check_asm.c
@echo "#include <linux/sched.h>" >> check_asm.c
@echo 'struct task_struct _task;' >> check_asm.c
@@ -92,7 +101,7 @@ check_asm: dummy
@rm -f tmp.[ci]
#$(CC) -o check_asm check_asm.c
# <hack> Until we can do this natively, a hack has to take place
- $(CC) $(CMODEL_CFLAG) -ffixed-g4 -S -o check_asm.s check_asm.c
+ $(CC) $(CPPFLAGS) $(CMODEL_CFLAG) -ffixed-g4 -S -o check_asm.s check_asm.c
$(HOSTCC) -Wa,-Av9a -o check_asm check_asm.s
@rm -f check_asm.s
# </hack>
@@ -104,7 +113,7 @@ check_asm: dummy
@echo "#undef CONFIG_SMP" >> tmp.c
@echo "#define CONFIG_SMP 1" >> tmp.c
@echo "#include <linux/sched.h>" >> tmp.c
- $(CC) -D__SMP__ -E tmp.c -o tmp.i
+ $(CC) $(CPPFLAGS) -D__SMP__ -E tmp.c -o tmp.i
@echo "/* Automatically generated. Do not edit. */" > check_asm.c
@echo "#include <linux/config.h>" >> check_asm.c
@echo "#undef CONFIG_SMP" >> check_asm.c
@@ -121,7 +130,7 @@ check_asm: dummy
@rm -f tmp.[ci]
#$(CC) -D__SMP__ -o check_asm check_asm.c
# <hack> Until we can do this natively, a hack has to take place
- $(CC) -D__SMP__ $(CMODEL_CFLAG) -ffixed-g4 -S -o check_asm.s check_asm.c
+ $(CC) $(CPPFLAGS) -D__SMP__ $(CMODEL_CFLAG) -ffixed-g4 -S -o check_asm.s check_asm.c
$(HOSTCC) -Wa,-Av9a -o check_asm check_asm.s
@rm -f check_asm.s
# </hack>
@@ -129,7 +138,7 @@ check_asm: dummy
@rm -f check_asm check_asm.c
@echo -e "\n#else /* SPIN_LOCK_DEBUG */\n" >> asm_offsets.h
@echo "#include <linux/sched.h>" > tmp.c
- $(CC) -D__SMP__ -DSPIN_LOCK_DEBUG -E tmp.c -o tmp.i
+ $(CC) $(CPPFLAGS) -D__SMP__ -DSPIN_LOCK_DEBUG -E tmp.c -o tmp.i
@echo "/* Automatically generated. Do not edit. */" > check_asm.c
@echo "#include <linux/config.h>" >> check_asm.c
@echo "#undef CONFIG_SMP" >> check_asm.c
@@ -146,7 +155,7 @@ check_asm: dummy
@rm -f tmp.[ci]
#$(CC) -D__SMP__ -DSPIN_LOCK_DEBUG -o check_asm check_asm.c
# <hack> Until we can do this natively, a hack has to take place
- $(CC) -D__SMP__ -DSPIN_LOCK_DEBUG $(CMODEL_CFLAG) -ffixed-g4 -S -o check_asm.s check_asm.c
+ $(CC) $(CPPFLAGS) -D__SMP__ -DSPIN_LOCK_DEBUG $(CMODEL_CFLAG) -ffixed-g4 -S -o check_asm.s check_asm.c
$(HOSTCC) -Wa,-Av9a -o check_asm check_asm.s
@rm -f check_asm.s
# </hack>
diff --git a/arch/sparc64/kernel/auxio.c b/arch/sparc64/kernel/auxio.c
index c6bcb6bd7..9be09c3b0 100644
--- a/arch/sparc64/kernel/auxio.c
+++ b/arch/sparc64/kernel/auxio.c
@@ -20,22 +20,21 @@
#include <asm/fhc.h>
/* Probe and map in the Auxiliary I/O register */
-unsigned char *auxio_register;
+unsigned long auxio_register = 0;
void __init auxio_probe(void)
{
- struct linux_sbus *bus;
- struct linux_sbus_device *sdev = 0;
- struct linux_prom_registers auxregs[1];
+ struct sbus_bus *sbus;
+ struct sbus_dev *sdev = 0;
- for_each_sbus(bus) {
- for_each_sbusdev(sdev, bus) {
- if(!strcmp(sdev->prom_name, "auxio")) {
- break;
- }
+ for_each_sbus(sbus) {
+ for_each_sbusdev(sdev, sbus) {
+ if(!strcmp(sdev->prom_name, "auxio"))
+ goto found_sdev;
}
}
+found_sdev:
if (!sdev) {
#ifdef CONFIG_PCI
struct linux_ebus *ebus;
@@ -57,19 +56,15 @@ void __init auxio_probe(void)
}
#endif
if(central_bus) {
- auxio_register = NULL;
+ auxio_register = 0UL;
return;
}
prom_printf("Cannot find auxio node, cannot continue...\n");
prom_halt();
}
- prom_getproperty(sdev->prom_node, "reg", (char *) auxregs, sizeof(auxregs));
- prom_apply_sbus_ranges(sdev->my_bus, auxregs, 0x1, sdev);
/* Map the register both read and write */
- auxio_register = (unsigned char *) sparc_alloc_io(auxregs[0].phys_addr, 0,
- auxregs[0].reg_size,
- "auxiliaryIO",
- auxregs[0].which_io, 0x0);
+ auxio_register = sbus_ioremap(&sdev->resource[0], 0,
+ sdev->reg_addrs[0].reg_size, "auxiliaryIO");
TURN_ON_LED;
}
diff --git a/arch/sparc64/kernel/central.c b/arch/sparc64/kernel/central.c
index 198841f89..2c4fb1355 100644
--- a/arch/sparc64/kernel/central.c
+++ b/arch/sparc64/kernel/central.c
@@ -1,7 +1,7 @@
-/* $Id: central.c,v 1.11 1998/12/14 12:18:16 davem Exp $
+/* $Id: central.c,v 1.13 1999/12/01 10:44:43 davem Exp $
* central.c: Central FHC driver for Sunfire/Starfire/Wildfire.
*
- * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1997, 1999 David S. Miller (davem@redhat.com)
*/
#include <linux/kernel.h>
@@ -10,6 +10,8 @@
#include <linux/timer.h>
#include <linux/sched.h>
#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/bootmem.h>
#include <asm/page.h>
#include <asm/fhc.h>
@@ -25,10 +27,80 @@ static inline unsigned long long_align(unsigned long addr)
~(sizeof(unsigned long) - 1));
}
-extern void prom_central_ranges_init(int cnode, struct linux_central *central);
-extern void prom_fhc_ranges_init(int fnode, struct linux_fhc *fhc);
+static void central_ranges_init(int cnode, struct linux_central *central)
+{
+ int success;
+
+ central->num_central_ranges = 0;
+ success = prom_getproperty(central->prom_node, "ranges",
+ (char *) central->central_ranges,
+ sizeof (central->central_ranges));
+ if (success != -1)
+ central->num_central_ranges = (success/sizeof(struct linux_prom_ranges));
+}
-static unsigned long probe_other_fhcs(unsigned long memory_start)
+static void fhc_ranges_init(int fnode, struct linux_fhc *fhc)
+{
+ int success;
+
+ fhc->num_fhc_ranges = 0;
+ success = prom_getproperty(fhc->prom_node, "ranges",
+ (char *) fhc->fhc_ranges,
+ sizeof (fhc->fhc_ranges));
+ if (success != -1)
+ fhc->num_fhc_ranges = (success/sizeof(struct linux_prom_ranges));
+}
+
+/* Range application routines are exported to various drivers,
+ * so do not __init this.
+ */
+static void adjust_regs(struct linux_prom_registers *regp, int nregs,
+ struct linux_prom_ranges *rangep, int nranges)
+{
+ int regc, rngc;
+
+ for (regc = 0; regc < nregs; regc++) {
+ for (rngc = 0; rngc < nranges; rngc++)
+ if (regp[regc].which_io == rangep[rngc].ot_child_space)
+ break; /* Fount it */
+ if (rngc == nranges) /* oops */
+ prom_printf("adjust_regs: Could not find range with matching bus type...\n");
+ regp[regc].which_io = rangep[rngc].ot_parent_space;
+ regp[regc].phys_addr += rangep[rngc].ot_parent_base;
+ }
+}
+
+/* Apply probed fhc ranges to registers passed, if no ranges return. */
+void apply_fhc_ranges(struct linux_fhc *fhc,
+ struct linux_prom_registers *regs,
+ int nregs)
+{
+ if(fhc->num_fhc_ranges)
+ adjust_regs(regs, nregs, fhc->fhc_ranges,
+ fhc->num_fhc_ranges);
+}
+
+/* Apply probed central ranges to registers passed, if no ranges return. */
+void apply_central_ranges(struct linux_central *central,
+ struct linux_prom_registers *regs, int nregs)
+{
+ if(central->num_central_ranges)
+ adjust_regs(regs, nregs, central->central_ranges,
+ central->num_central_ranges);
+}
+
+void * __init central_alloc_bootmem(unsigned long size)
+{
+ void *ret;
+
+ ret = __alloc_bootmem(size, SMP_CACHE_BYTES, 0UL);
+ if (ret != NULL)
+ memset(ret, 0, size);
+
+ return ret;
+}
+
+static void probe_other_fhcs(void)
{
struct linux_prom64_registers fpregs[6];
char namebuf[128];
@@ -45,9 +117,12 @@ static unsigned long probe_other_fhcs(unsigned long memory_start)
int board;
u32 tmp;
- fhc = (struct linux_fhc *)memory_start;
- memory_start += sizeof(struct linux_fhc);
- memory_start = long_align(memory_start);
+ fhc = (struct linux_fhc *)
+ central_alloc_bootmem(sizeof(struct linux_fhc));
+ if (fhc == NULL) {
+ prom_printf("probe_other_fhcs: Cannot alloc fhc.\n");
+ prom_halt();
+ }
/* Link it into the FHC chain. */
fhc->next = fhc_list;
@@ -59,7 +134,7 @@ static unsigned long probe_other_fhcs(unsigned long memory_start)
fhc->prom_node = node;
prom_getstring(node, "name", namebuf, sizeof(namebuf));
strcpy(fhc->prom_name, namebuf);
- prom_fhc_ranges_init(node, fhc);
+ fhc_ranges_init(node, fhc);
/* Non-central FHC's have 64-bit OBP format registers. */
if(prom_getproperty(node, "reg",
@@ -69,29 +144,23 @@ static unsigned long probe_other_fhcs(unsigned long memory_start)
}
/* Only central FHC needs special ranges applied. */
- fhc->fhc_regs.pregs = (struct fhc_internal_regs *)
- __va(fpregs[0].phys_addr);
- fhc->fhc_regs.ireg = (struct fhc_ign_reg *)
- __va(fpregs[1].phys_addr);
- fhc->fhc_regs.ffregs = (struct fhc_fanfail_regs *)
- __va(fpregs[2].phys_addr);
- fhc->fhc_regs.sregs = (struct fhc_system_regs *)
- __va(fpregs[3].phys_addr);
- fhc->fhc_regs.uregs = (struct fhc_uart_regs *)
- __va(fpregs[4].phys_addr);
- fhc->fhc_regs.tregs = (struct fhc_tod_regs *)
- __va(fpregs[5].phys_addr);
+ fhc->fhc_regs.pregs = fpregs[0].phys_addr;
+ fhc->fhc_regs.ireg = fpregs[1].phys_addr;
+ fhc->fhc_regs.ffregs = fpregs[2].phys_addr;
+ fhc->fhc_regs.sregs = fpregs[3].phys_addr;
+ fhc->fhc_regs.uregs = fpregs[4].phys_addr;
+ fhc->fhc_regs.tregs = fpregs[5].phys_addr;
board = prom_getintdefault(node, "board#", -1);
fhc->board = board;
- tmp = fhc->fhc_regs.pregs->fhc_jtag_ctrl;
+ tmp = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_JCTRL);
if((tmp & FHC_JTAG_CTRL_MENAB) != 0)
fhc->jtag_master = 1;
else
fhc->jtag_master = 0;
- tmp = fhc->fhc_regs.pregs->fhc_id;
+ tmp = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_ID);
printk("FHC(board %d): Version[%x] PartID[%x] Manuf[%x] %s\n",
board,
(tmp & FHC_ID_VERS) >> 28,
@@ -103,7 +172,9 @@ static unsigned long probe_other_fhcs(unsigned long memory_start)
* the system. When it is clear, this identifies
* the central board.
*/
- fhc->fhc_regs.pregs->fhc_control |= FHC_CONTROL_IXIST;
+ tmp = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_CTRL);
+ tmp |= FHC_CONTROL_IXIST;
+ upa_writel(tmp, fhc->fhc_regs.pregs + FHC_PREGS_CTRL);
/* Look for the next FHC. */
node = prom_getsibling(node);
@@ -113,8 +184,6 @@ static unsigned long probe_other_fhcs(unsigned long memory_start)
if(node == 0)
break;
}
-
- return memory_start;
}
static void probe_clock_board(struct linux_central *central,
@@ -135,22 +204,20 @@ static void probe_clock_board(struct linux_central *central,
prom_halt();
}
nregs /= sizeof(struct linux_prom_registers);
- prom_apply_fhc_ranges(fhc, &cregs[0], nregs);
- prom_apply_central_ranges(central, &cregs[0], nregs);
- central->cfreg = (volatile u8 *)
- __va((((unsigned long)cregs[0].which_io) << 32) |
- (((unsigned long)cregs[0].phys_addr)+0x02));
- central->clkregs = (struct clock_board_regs *)
- __va((((unsigned long)cregs[1].which_io) << 32) |
- (((unsigned long)cregs[1].phys_addr)));
+ apply_fhc_ranges(fhc, &cregs[0], nregs);
+ apply_central_ranges(central, &cregs[0], nregs);
+ central->cfreg = ((((unsigned long)cregs[0].which_io) << 32UL) |
+ ((unsigned long)cregs[0].phys_addr));
+ central->clkregs = ((((unsigned long)cregs[1].which_io) << 32UL) |
+ ((unsigned long)cregs[1].phys_addr));
+
if(nregs == 2)
- central->clkver = NULL;
+ central->clkver = 0UL;
else
- central->clkver = (volatile u8 *)
- __va((((unsigned long)cregs[2].which_io) << 32) |
- (((unsigned long)cregs[2].phys_addr)));
+ central->clkver = ((((unsigned long)cregs[2].which_io) << 32UL) |
+ ((unsigned long)cregs[2].phys_addr));
- tmp = central->clkregs->stat1;
+ tmp = upa_readb(central->clkregs + CLOCK_STAT1);
tmp &= 0xc0;
switch(tmp) {
case 0x40:
@@ -160,9 +227,9 @@ static void probe_clock_board(struct linux_central *central,
nslots = 8;
break;
case 0x80:
- if(central->clkver != NULL &&
- *(central->clkver) != 0) {
- if((*(central->clkver) & 0x80) != 0)
+ if(central->clkver != 0UL &&
+ upa_readb(central->clkver) != 0) {
+ if((upa_readb(central->clkver) & 0x80) != 0)
nslots = 4;
else
nslots = 5;
@@ -174,11 +241,11 @@ static void probe_clock_board(struct linux_central *central,
};
central->slots = nslots;
printk("CENTRAL: Detected %d slot Enterprise system. cfreg[%02x] cver[%02x]\n",
- central->slots, *(central->cfreg),
- (central->clkver ? *(central->clkver) : 0x00));
+ central->slots, upa_readb(central->cfreg),
+ (central->clkver ? upa_readb(central->clkver) : 0x00));
}
-unsigned long central_probe(unsigned long memory_start)
+void central_probe(void)
{
struct linux_prom_registers fpregs[6];
struct linux_fhc *fhc;
@@ -190,18 +257,23 @@ unsigned long central_probe(unsigned long memory_start)
extern void starfire_check(void);
starfire_check();
- return memory_start;
+ return;
}
/* Ok we got one, grab some memory for software state. */
- memory_start = long_align(memory_start);
- central_bus = (struct linux_central *) (memory_start);
+ central_bus = (struct linux_central *)
+ central_alloc_bootmem(sizeof(struct linux_central));
+ if (central_bus == NULL) {
+ prom_printf("central_probe: Cannot alloc central_bus.\n");
+ prom_halt();
+ }
- memory_start += sizeof(struct linux_central);
- memory_start = long_align(memory_start);
- fhc = (struct linux_fhc *)(memory_start);
- memory_start += sizeof(struct linux_fhc);
- memory_start = long_align(memory_start);
+ fhc = (struct linux_fhc *)
+ central_alloc_bootmem(sizeof(struct linux_fhc));
+ if (fhc == NULL) {
+ prom_printf("central_probe: Cannot alloc central fhc.\n");
+ prom_halt();
+ }
/* First init central. */
central_bus->child = fhc;
@@ -210,7 +282,7 @@ unsigned long central_probe(unsigned long memory_start)
prom_getstring(cnode, "name", namebuf, sizeof(namebuf));
strcpy(central_bus->prom_name, namebuf);
- prom_central_ranges_init(cnode, central_bus);
+ central_ranges_init(cnode, central_bus);
/* And then central's FHC. */
fhc->next = fhc_list;
@@ -226,38 +298,32 @@ unsigned long central_probe(unsigned long memory_start)
prom_getstring(fnode, "name", namebuf, sizeof(namebuf));
strcpy(fhc->prom_name, namebuf);
- prom_fhc_ranges_init(fnode, fhc);
+ fhc_ranges_init(fnode, fhc);
/* Now, map in FHC register set. */
if (prom_getproperty(fnode, "reg", (char *)&fpregs[0], sizeof(fpregs)) == -1) {
prom_printf("CENTRAL: Fatal error, cannot get fhc regs.\n");
prom_halt();
}
- prom_apply_central_ranges(central_bus, &fpregs[0], 6);
+ apply_central_ranges(central_bus, &fpregs[0], 6);
- fhc->fhc_regs.pregs = (struct fhc_internal_regs *)
- __va((((unsigned long)fpregs[0].which_io)<<32) |
- (((unsigned long)fpregs[0].phys_addr)));
- fhc->fhc_regs.ireg = (struct fhc_ign_reg *)
- __va((((unsigned long)fpregs[1].which_io)<<32) |
- (((unsigned long)fpregs[1].phys_addr)));
- fhc->fhc_regs.ffregs = (struct fhc_fanfail_regs *)
- __va((((unsigned long)fpregs[2].which_io)<<32) |
- (((unsigned long)fpregs[2].phys_addr)));
- fhc->fhc_regs.sregs = (struct fhc_system_regs *)
- __va((((unsigned long)fpregs[3].which_io)<<32) |
- (((unsigned long)fpregs[3].phys_addr)));
- fhc->fhc_regs.uregs = (struct fhc_uart_regs *)
- __va((((unsigned long)fpregs[4].which_io)<<32) |
- (((unsigned long)fpregs[4].phys_addr)));
- fhc->fhc_regs.tregs = (struct fhc_tod_regs *)
- __va((((unsigned long)fpregs[5].which_io)<<32) |
- (((unsigned long)fpregs[5].phys_addr)));
+ fhc->fhc_regs.pregs = ((((unsigned long)fpregs[0].which_io)<<32UL) |
+ ((unsigned long)fpregs[0].phys_addr));
+ fhc->fhc_regs.ireg = ((((unsigned long)fpregs[1].which_io)<<32UL) |
+ ((unsigned long)fpregs[1].phys_addr));
+ fhc->fhc_regs.ffregs = ((((unsigned long)fpregs[2].which_io)<<32UL) |
+ ((unsigned long)fpregs[2].phys_addr));
+ fhc->fhc_regs.sregs = ((((unsigned long)fpregs[3].which_io)<<32UL) |
+ ((unsigned long)fpregs[3].phys_addr));
+ fhc->fhc_regs.uregs = ((((unsigned long)fpregs[4].which_io)<<32UL) |
+ ((unsigned long)fpregs[4].phys_addr));
+ fhc->fhc_regs.tregs = ((((unsigned long)fpregs[5].which_io)<<32UL) |
+ ((unsigned long)fpregs[5].phys_addr));
/* Obtain board number from board status register, Central's
* FHC lacks "board#" property.
*/
- err = fhc->fhc_regs.pregs->fhc_bsr;
+ err = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_BSR);
fhc->board = (((err >> 16) & 0x01) |
((err >> 12) & 0x0e));
@@ -266,23 +332,21 @@ unsigned long central_probe(unsigned long memory_start)
/* Attach the clock board registers for CENTRAL. */
probe_clock_board(central_bus, fhc, cnode, fnode);
- err = fhc->fhc_regs.pregs->fhc_id;
+ err = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_ID);
printk("FHC(board %d): Version[%x] PartID[%x] Manuf[%x] (CENTRAL)\n",
fhc->board,
((err & FHC_ID_VERS) >> 28),
((err & FHC_ID_PARTID) >> 12),
((err & FHC_ID_MANUF) >> 1));
- return probe_other_fhcs(memory_start);
+ probe_other_fhcs();
}
static __inline__ void fhc_ledblink(struct linux_fhc *fhc, int on)
{
- volatile u32 *ctrl = (volatile u32 *)
- &fhc->fhc_regs.pregs->fhc_control;
u32 tmp;
- tmp = *ctrl;
+ tmp = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_CTRL);
/* NOTE: reverse logic on this bit */
if (on)
@@ -291,16 +355,15 @@ static __inline__ void fhc_ledblink(struct linux_fhc *fhc, int on)
tmp |= FHC_CONTROL_RLED;
tmp &= ~(FHC_CONTROL_AOFF | FHC_CONTROL_BOFF | FHC_CONTROL_SLINE);
- *ctrl = tmp;
- tmp = *ctrl;
+ upa_writel(tmp, fhc->fhc_regs.pregs + FHC_PREGS_CTRL);
+ upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_CTRL);
}
static __inline__ void central_ledblink(struct linux_central *central, int on)
{
- volatile u8 *ctrl = (volatile u8 *) &central->clkregs->control;
- int tmp;
+ u8 tmp;
- tmp = *ctrl;
+ tmp = upa_readb(central->clkregs + CLOCK_CTRL);
/* NOTE: reverse logic on this bit */
if(on)
@@ -308,8 +371,8 @@ static __inline__ void central_ledblink(struct linux_central *central, int on)
else
tmp |= CLOCK_CTRL_RLED;
- *ctrl = tmp;
- tmp = *ctrl;
+ upa_writeb(tmp, central->clkregs + CLOCK_CTRL);
+ upa_readb(central->clkregs + CLOCK_CTRL);
}
static struct timer_list sftimer;
@@ -335,41 +398,41 @@ void firetruck_init(void)
{
struct linux_central *central = central_bus;
struct linux_fhc *fhc;
+ u8 ctrl;
/* No central bus, nothing to do. */
if (central == NULL)
return;
for(fhc = fhc_list; fhc != NULL; fhc = fhc->next) {
- volatile u32 *ctrl = (volatile u32 *)
- &fhc->fhc_regs.pregs->fhc_control;
u32 tmp;
/* Clear all of the interrupt mapping registers
* just in case OBP left them in a foul state.
*/
-#define ZAP(REG1, REG2) \
-do { volatile u32 *__iclr = (volatile u32 *)(&(REG1)); \
- volatile u32 *__imap = (volatile u32 *)(&(REG2)); \
- *(__iclr) = 0; \
- (void) *(__iclr); \
- *(__imap) &= ~(0x80000000); \
- (void) *(__imap); \
-} while(0)
-
- ZAP(fhc->fhc_regs.ffregs->fhc_ff_iclr,
- fhc->fhc_regs.ffregs->fhc_ff_imap);
- ZAP(fhc->fhc_regs.sregs->fhc_sys_iclr,
- fhc->fhc_regs.sregs->fhc_sys_imap);
- ZAP(fhc->fhc_regs.uregs->fhc_uart_iclr,
- fhc->fhc_regs.uregs->fhc_uart_imap);
- ZAP(fhc->fhc_regs.tregs->fhc_tod_iclr,
- fhc->fhc_regs.tregs->fhc_tod_imap);
+#define ZAP(ICLR, IMAP) \
+do { u32 imap_tmp; \
+ upa_writel(0, (ICLR)); \
+ upa_readl(ICLR); \
+ imap_tmp = upa_readl(IMAP); \
+ imap_tmp &= ~(0x80000000); \
+ upa_writel(imap_tmp, (IMAP)); \
+ upa_readl(IMAP); \
+} while (0)
+
+ ZAP(fhc->fhc_regs.ffregs + FHC_FFREGS_ICLR,
+ fhc->fhc_regs.ffregs + FHC_FFREGS_IMAP);
+ ZAP(fhc->fhc_regs.sregs + FHC_SREGS_ICLR,
+ fhc->fhc_regs.sregs + FHC_SREGS_IMAP);
+ ZAP(fhc->fhc_regs.uregs + FHC_UREGS_ICLR,
+ fhc->fhc_regs.uregs + FHC_UREGS_IMAP);
+ ZAP(fhc->fhc_regs.tregs + FHC_TREGS_ICLR,
+ fhc->fhc_regs.tregs + FHC_TREGS_IMAP);
#undef ZAP
/* Setup FHC control register. */
- tmp = *ctrl;
+ tmp = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_CTRL);
/* All non-central boards have this bit set. */
if(! IS_CENTRAL_FHC(fhc))
@@ -379,14 +442,17 @@ do { volatile u32 *__iclr = (volatile u32 *)(&(REG1)); \
* line and both low power mode enables.
*/
tmp &= ~(FHC_CONTROL_AOFF | FHC_CONTROL_BOFF | FHC_CONTROL_SLINE);
- *ctrl = tmp;
- tmp = *ctrl; /* Ensure completion */
+
+ upa_writel(tmp, fhc->fhc_regs.pregs + FHC_PREGS_CTRL);
+ upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_CTRL);
}
/* OBP leaves it on, turn it off so clock board timer LED
* is in sync with FHC ones.
*/
- central->clkregs->control &= ~(CLOCK_CTRL_RLED);
+ ctrl = upa_readb(central->clkregs + CLOCK_CTRL);
+ ctrl &= ~(CLOCK_CTRL_RLED);
+ upa_writeb(ctrl, central->clkregs + CLOCK_CTRL);
led_state = 0;
init_timer(&sftimer);
diff --git a/arch/sparc64/kernel/devices.c b/arch/sparc64/kernel/devices.c
index d8085bf06..be8771985 100644
--- a/arch/sparc64/kernel/devices.c
+++ b/arch/sparc64/kernel/devices.c
@@ -19,10 +19,9 @@ unsigned prom_cpu_nodes[64];
int linux_num_cpus = 0;
extern void cpu_probe(void);
-extern unsigned long central_probe(unsigned long);
+extern void central_probe(void);
-unsigned long __init
-device_scan(unsigned long mem_start)
+void __init device_scan(void)
{
char node_str[128];
int nd, prom_node_cpu, thismid;
@@ -54,13 +53,8 @@ device_scan(unsigned long mem_start)
prom_getproperty(scan, "upa-portid",
(char *) &thismid, sizeof(thismid));
linux_cpus[cpu_ctr].mid = thismid;
-#ifdef __SMP__
- /* Don't pollute PROM screen with these messages. If the kernel is screwed enough
- that console does not start up, then we don't care how many CPUs have been found,
- if it starts up, the user can use console=prom to see it. */
- /* prom_printf("Found CPU %d (node=%08x,mid=%d)\n", cpu_ctr, (unsigned) scan, thismid); */
- printk("Found CPU %d (node=%08x,mid=%d)\n", cpu_ctr, (unsigned) scan, thismid);
-#endif
+ printk("Found CPU %d (node=%08x,mid=%d)\n",
+ cpu_ctr, (unsigned) scan, thismid);
cpu_ctr++;
}
};
@@ -68,19 +62,15 @@ device_scan(unsigned long mem_start)
prom_printf("No CPU nodes found, cannot continue.\n");
prom_halt();
}
-#ifdef __SMP__
printk("Found %d CPU prom device tree node(s).\n", cpu_ctr);
-#endif
- };
+ }
prom_node_cpu = cpu_nds[0];
linux_num_cpus = cpu_ctr;
prom_cpu_nodes[0] = prom_node_cpu;
- mem_start = central_probe(mem_start);
+ central_probe();
cpu_probe();
-
- return mem_start;
}
diff --git a/arch/sparc64/kernel/dtlb_backend.S b/arch/sparc64/kernel/dtlb_backend.S
index 9fe613a51..81f4fd366 100644
--- a/arch/sparc64/kernel/dtlb_backend.S
+++ b/arch/sparc64/kernel/dtlb_backend.S
@@ -1,4 +1,4 @@
-/* $Id: dtlb_backend.S,v 1.7 1998/12/16 04:33:28 davem Exp $
+/* $Id: dtlb_backend.S,v 1.8 1999/12/05 10:41:35 davem Exp $
* dtlb_backend.S: Back end to DTLB miss replacement strategy.
* This is included directly into the trap table.
*
@@ -10,7 +10,7 @@
#define VPTE_SHIFT (PAGE_SHIFT - 3)
#define PMD_SHIFT (23 - PAGE_SHIFT + 3)
#define PGD_SHIFT (34 - PAGE_SHIFT + 3)
-#define VPTE_BITS (_PAGE_CP | _PAGE_P | _PAGE_W)
+#define VPTE_BITS (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W)
/* Ways we can get here:
*
diff --git a/arch/sparc64/kernel/ebus.c b/arch/sparc64/kernel/ebus.c
index 0b3d16007..903bcf445 100644
--- a/arch/sparc64/kernel/ebus.c
+++ b/arch/sparc64/kernel/ebus.c
@@ -1,4 +1,4 @@
-/* $Id: ebus.c,v 1.44 1999/09/05 09:28:09 ecd Exp $
+/* $Id: ebus.c,v 1.46 1999/11/19 05:52:48 davem Exp $
* ebus.c: PCI to EBus bridge device.
*
* Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
@@ -22,9 +22,6 @@
struct linux_ebus *ebus_chain = 0;
-extern void prom_ebus_ranges_init(struct linux_ebus *);
-extern void prom_ebus_intmap_init(struct linux_ebus *);
-
#ifdef CONFIG_SUN_OPENPROMIO
extern int openprom_init(void);
#endif
@@ -49,15 +46,49 @@ static inline void *ebus_alloc(size_t size)
return mem;
}
-void __init ebus_intmap_match(struct linux_ebus *ebus,
- struct linux_prom_registers *reg,
- int *interrupt)
+static void __init ebus_ranges_init(struct linux_ebus *ebus)
+{
+ int success;
+
+ ebus->num_ebus_ranges = 0;
+ success = prom_getproperty(ebus->prom_node, "ranges",
+ (char *)ebus->ebus_ranges,
+ sizeof(ebus->ebus_ranges));
+ if (success != -1)
+ ebus->num_ebus_ranges = (success/sizeof(struct linux_prom_ebus_ranges));
+}
+
+static void __init ebus_intmap_init(struct linux_ebus *ebus)
+{
+ int success;
+
+ ebus->num_ebus_intmap = 0;
+ success = prom_getproperty(ebus->prom_node, "interrupt-map",
+ (char *)ebus->ebus_intmap,
+ sizeof(ebus->ebus_intmap));
+ if (success == -1)
+ return;
+
+ ebus->num_ebus_intmap = (success/sizeof(struct linux_prom_ebus_intmap));
+
+ success = prom_getproperty(ebus->prom_node, "interrupt-map-mask",
+ (char *)&ebus->ebus_intmask,
+ sizeof(ebus->ebus_intmask));
+ if (success == -1) {
+ prom_printf("%s: can't get interrupt-map-mask\n", __FUNCTION__);
+ prom_halt();
+ }
+}
+
+int __init ebus_intmap_match(struct linux_ebus *ebus,
+ struct linux_prom_registers *reg,
+ int *interrupt)
{
unsigned int hi, lo, irq;
int i;
if (!ebus->num_ebus_intmap)
- return;
+ return 0;
hi = reg->which_io & ebus->ebus_intmask.phys_hi;
lo = reg->phys_addr & ebus->ebus_intmask.phys_lo;
@@ -67,13 +98,10 @@ void __init ebus_intmap_match(struct linux_ebus *ebus,
(ebus->ebus_intmap[i].phys_lo == lo) &&
(ebus->ebus_intmap[i].interrupt == irq)) {
*interrupt = ebus->ebus_intmap[i].cinterrupt;
- return;
+ return 0;
}
}
-
- prom_printf("ebus: IRQ [%08x.%08x.%08x] not found in interrupt-map\n",
- reg->which_io, reg->phys_addr, *interrupt);
- prom_halt();
+ return -1;
}
void __init fill_ebus_child(int node, struct linux_prom_registers *preg,
@@ -139,8 +167,16 @@ void __init fill_ebus_child(int node, struct linux_prom_registers *preg,
struct pci_pbm_info *pbm = dev->bus->parent;
struct pci_controller_info *p = pbm->parent;
- ebus_intmap_match(dev->bus, preg, &irqs[i]);
- dev->irqs[i] = p->irq_build(p, dev->bus->self, irqs[i]);
+ if (ebus_intmap_match(dev->bus, preg, &irqs[i]) != -1) {
+ dev->irqs[i] = p->irq_build(p,
+ dev->bus->self,
+ irqs[i]);
+ } else {
+ /* If we get a bogus interrupt property, just
+ * record the raw value instead of punting.
+ */
+ dev->irqs[i] = irqs[i];
+ }
}
}
}
@@ -194,8 +230,16 @@ void __init fill_ebus_device(int node, struct linux_ebus_device *dev)
struct pci_pbm_info *pbm = dev->bus->parent;
struct pci_controller_info *p = pbm->parent;
- ebus_intmap_match(dev->bus, &regs[0], &irqs[i]);
- dev->irqs[i] = p->irq_build(p, dev->bus->self, irqs[i]);
+ if (ebus_intmap_match(dev->bus, &regs[0], &irqs[i]) != -1) {
+ dev->irqs[i] = p->irq_build(p,
+ dev->bus->self,
+ irqs[i]);
+ } else {
+ /* If we get a bogus interrupt property, just
+ * record the raw value instead of punting.
+ */
+ dev->irqs[i] = irqs[i];
+ }
}
}
@@ -295,8 +339,8 @@ void __init ebus_init(void)
/* NOTE: Cache line size is in 32-bit word units. */
pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 64/sizeof(u32));
- prom_ebus_ranges_init(ebus);
- prom_ebus_intmap_init(ebus);
+ ebus_ranges_init(ebus);
+ ebus_intmap_init(ebus);
nd = prom_getchild(ebusnd);
if (!nd)
diff --git a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S
index fbd64a507..f62e3506d 100644
--- a/arch/sparc64/kernel/entry.S
+++ b/arch/sparc64/kernel/entry.S
@@ -1,4 +1,4 @@
-/* $Id: entry.S,v 1.107 1999/08/31 19:25:29 davem Exp $
+/* $Id: entry.S,v 1.110 1999/11/19 05:52:50 davem Exp $
* arch/sparc64/kernel/entry.S: Sparc64 trap low-level entry points.
*
* Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -214,8 +214,8 @@ do_fptrap:
.align 32
.globl do_ivec
do_ivec:
- wr %g0, ASI_UDB_INTR_R, %asi
- ldxa [%g0 + 0x40] %asi, %g3
+ mov 0x40, %g3
+ ldxa [%g3 + %g0] ASI_UDB_INTR_R, %g3
sethi %hi(KERNBASE), %g4
cmp %g3, %g4
bgeu,pn %xcc, do_ivec_xcall
@@ -234,22 +234,25 @@ do_ivec:
sllx %g2, %g4, %g2
sllx %g4, 2, %g4
- lduw [%g1 + %g4], %g5 /* g5 = irq_work(cpu, pil) */
+ lduw [%g6 + %g4], %g5 /* g5 = irq_work(cpu, pil) */
stw %g5, [%g3 + 0x00] /* bucket->irq_chain = g5 */
- stw %g3, [%g1 + %g4] /* irq_work(cpu, pil) = bucket */
+ stw %g3, [%g6 + %g4] /* irq_work(cpu, pil) = bucket */
wr %g2, 0x0, %set_softint
retry
do_ivec_xcall:
- ldxa [%g0 + 0x50] %asi, %g6
+ mov 0x50, %g1
+ ldxa [%g1 + %g0] ASI_UDB_INTR_R, %g1
srl %g3, 0, %g3
- ldxa [%g0 + 0x60] %asi, %g7
+ mov 0x60, %g7
+ ldxa [%g7 + %g0] ASI_UDB_INTR_R, %g7
stxa %g0, [%g0] ASI_INTR_RECEIVE
membar #Sync
jmpl %g3, %g0
nop
+
do_ivec_spurious:
- stw %g3, [%g1 + 0x00] /* irq_work(cpu, 0) = bucket */
+ stw %g3, [%g6 + 0x00] /* irq_work(cpu, 0) = bucket */
rdpr %pstate, %g5
wrpr %g5, PSTATE_IG | PSTATE_AG, %pstate
@@ -261,6 +264,76 @@ do_ivec_spurious:
ba,pt %xcc, rtrap
clr %l6
+ .globl save_alternate_globals
+save_alternate_globals: /* %o0 = save_area */
+ rdpr %pstate, %o5
+ andn %o5, PSTATE_IE, %o1
+ wrpr %o1, PSTATE_AG, %pstate
+ stx %g0, [%o0 + 0x00]
+ stx %g1, [%o0 + 0x08]
+ stx %g2, [%o0 + 0x10]
+ stx %g3, [%o0 + 0x18]
+ stx %g4, [%o0 + 0x20]
+ stx %g5, [%o0 + 0x28]
+ stx %g6, [%o0 + 0x30]
+ stx %g7, [%o0 + 0x38]
+ wrpr %o1, PSTATE_IG, %pstate
+ stx %g0, [%o0 + 0x40]
+ stx %g1, [%o0 + 0x48]
+ stx %g2, [%o0 + 0x50]
+ stx %g3, [%o0 + 0x58]
+ stx %g4, [%o0 + 0x60]
+ stx %g5, [%o0 + 0x68]
+ stx %g6, [%o0 + 0x70]
+ stx %g7, [%o0 + 0x78]
+ wrpr %o1, PSTATE_MG, %pstate
+ stx %g0, [%o0 + 0x80]
+ stx %g1, [%o0 + 0x88]
+ stx %g2, [%o0 + 0x90]
+ stx %g3, [%o0 + 0x98]
+ stx %g4, [%o0 + 0xa0]
+ stx %g5, [%o0 + 0xa8]
+ stx %g6, [%o0 + 0xb0]
+ stx %g7, [%o0 + 0xb8]
+ wrpr %o5, 0x0, %pstate
+ retl
+ nop
+
+ .globl restore_alternate_globals
+restore_alternate_globals: /* %o0 = save_area */
+ rdpr %pstate, %o5
+ andn %o5, PSTATE_IE, %o1
+ wrpr %o1, PSTATE_AG, %pstate
+ ldx [%o0 + 0x00], %g0
+ ldx [%o0 + 0x08], %g1
+ ldx [%o0 + 0x10], %g2
+ ldx [%o0 + 0x18], %g3
+ ldx [%o0 + 0x20], %g4
+ ldx [%o0 + 0x28], %g5
+ ldx [%o0 + 0x30], %g6
+ ldx [%o0 + 0x38], %g7
+ wrpr %o1, PSTATE_IG, %pstate
+ ldx [%o0 + 0x40], %g0
+ ldx [%o0 + 0x48], %g1
+ ldx [%o0 + 0x50], %g2
+ ldx [%o0 + 0x58], %g3
+ ldx [%o0 + 0x60], %g4
+ ldx [%o0 + 0x68], %g5
+ ldx [%o0 + 0x70], %g6
+ ldx [%o0 + 0x78], %g7
+ wrpr %o1, PSTATE_MG, %pstate
+ ldx [%o0 + 0x80], %g0
+ ldx [%o0 + 0x88], %g1
+ ldx [%o0 + 0x90], %g2
+ ldx [%o0 + 0x98], %g3
+ ldx [%o0 + 0xa0], %g4
+ ldx [%o0 + 0xa8], %g5
+ ldx [%o0 + 0xb0], %g6
+ ldx [%o0 + 0xb8], %g7
+ wrpr %o5, 0x0, %pstate
+ retl
+ nop
+
.globl getcc, setcc
getcc:
ldx [%o0 + PT_V9_TSTATE], %o1
@@ -313,7 +386,7 @@ floppy_hardint:
ldx [%g5 + %lo(pdma_size)], %g5
next_byte:
- ldub [%g3], %g7
+ lduba [%g3] ASI_PHYS_BYPASS_EC_E, %g7
andcc %g7, 0x80, %g0
be,pn %icc, floppy_fifo_emptied
andcc %g7, 0x20, %g0
@@ -322,7 +395,9 @@ next_byte:
be,pn %icc, floppy_write
sub %g5, 1, %g5
- ldub [%g3 + 1], %g7
+ inc %g3
+ lduba [%g3] ASI_PHYS_BYPASS_EC_E, %g7
+ dec %g3
orcc %g0, %g5, %g0
stb %g7, [%g4]
bne,pn %xcc, next_byte
@@ -334,7 +409,9 @@ next_byte:
floppy_write:
ldub [%g4], %g7
orcc %g0, %g5, %g0
- stb %g7, [%g3 + 1]
+ inc %g3
+ stba %g7, [%g3] ASI_PHYS_BYPASS_EC_E
+ dec %g3
bne,pn %xcc, next_byte
add %g4, 1, %g4
@@ -368,7 +445,7 @@ floppy_fifo_emptied:
ldx [%g1 + (11 << 3)], %g3 ! irqaction[floppy_irq]
ldx [%g3 + 0x10], %g4 ! action->mask == ino_bucket ptr
ldx [%g4 + 0x10], %g4 ! bucket->iclr
- stw %g0, [%g4] ! SYSIO_ICLR_IDLE
+ stwa %g0, [%g4] ASI_PHYS_BYPASS_EC_E ! ICLR_IDLE
membar #Sync ! probably not needed...
retry
@@ -652,6 +729,8 @@ breakpoint_trap:
ba,pt %xcc, rtrap
nop
+#if defined(CONFIG_SUNOS_EMUL) || defined(CONFIG_SOLARIS_EMUL) || \
+ defined(CONFIG_SOLARIS_EMUL_MODULE)
/* SunOS uses syscall zero as the 'indirect syscall' it looks
* like indir_syscall(scall_num, arg0, arg1, arg2...); etc.
* This is complete brain damage.
@@ -705,6 +784,7 @@ sunos_getgid:
stx %o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I1]
b,pt %xcc, ret_sys_call
stx %o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0]
+#endif
/* SunOS's execv() call only specifies the argv argument, the
* environment settings are the same as the calling processes.
diff --git a/arch/sparc64/kernel/head.S b/arch/sparc64/kernel/head.S
index ad863a71d..47a170f54 100644
--- a/arch/sparc64/kernel/head.S
+++ b/arch/sparc64/kernel/head.S
@@ -1,4 +1,4 @@
-/* $Id: head.S,v 1.61 1999/05/25 16:53:10 jj Exp $
+/* $Id: head.S,v 1.63 1999/11/19 05:52:49 davem Exp $
* head.S: Initial boot code for the Sparc64 port of Linux.
*
* Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -52,7 +52,7 @@ bootup_user_stack:
.ascii "HdrS"
.word LINUX_VERSION_CODE
- .half 0x0202 /* HdrS version */
+ .half 0x0203 /* HdrS version */
root_flags:
.half 1
root_dev:
@@ -65,6 +65,7 @@ sparc_ramdisk_size:
.word 0
.xword reboot_command
.xword bootstr_len
+ .word _end
/* We must be careful, 32-bit OpenBOOT will get confused if it
* tries to save away a register window to a 64-bit kernel
@@ -92,28 +93,6 @@ sparc64_boot:
wrpr %g0, (PSTATE_PRIV|PSTATE_PEF|PSTATE_IE), %pstate
wr %g0, 0, %fprs
-#ifdef __SMP__
- /* Ugly but necessary... */
- sethi %hi(KERNBASE), %g7
- sethi %hi(sparc64_cpu_startup), %g5
- or %g5, %lo(sparc64_cpu_startup), %g5
- sub %g5, %g7, %g5
- sethi %hi(sparc64_cpu_startup_end), %g6
- or %g6, %lo(sparc64_cpu_startup_end), %g6
- sub %g6, %g7, %g6
- sethi %hi(smp_trampoline), %g3
- or %g3, %lo(smp_trampoline), %g3
- sub %g3, %g7, %g3
-1: ldx [%g5], %g1
- stx %g1, [%g3]
- membar #StoreStore
- flush %g3
- add %g5, 8, %g5
- cmp %g5, %g6
- blu,pt %xcc, 1b
- add %g3, 8, %g3
-#endif
-
create_mappings:
/* %g5 holds the tlb data */
sethi %uhi(_PAGE_VALID | _PAGE_SZ4MB), %g5
@@ -380,7 +359,7 @@ setup_tba: /* i0 = is_starfire */
wrpr %o1, (PSTATE_IG|PSTATE_IE), %pstate
#ifndef __SMP__
sethi %hi(__up_workvec), %g5
- or %g5, %lo(__up_workvec), %g1
+ or %g5, %lo(__up_workvec), %g6
#else
/* By definition of where we are, this is boot_cpu. */
sethi %hi(cpu_data), %g5
@@ -404,7 +383,7 @@ not_starfire:
set_worklist:
sllx %g1, 7, %g1
add %g5, %g1, %g5
- add %g5, 64, %g1
+ add %g5, 64, %g6
#endif
/* Kill PROM timer */
diff --git a/arch/sparc64/kernel/ioctl32.c b/arch/sparc64/kernel/ioctl32.c
index 0affcf0eb..ef0fb3e94 100644
--- a/arch/sparc64/kernel/ioctl32.c
+++ b/arch/sparc64/kernel/ioctl32.c
@@ -1,4 +1,4 @@
-/* $Id: ioctl32.c,v 1.68 1999/09/10 05:59:25 davem Exp $
+/* $Id: ioctl32.c,v 1.72 2000/01/04 15:43:45 davem Exp $
* ioctl32.c: Conversion between 32bit and 64bit native ioctls.
*
* Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -1921,6 +1921,9 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
case TIOCSCTTY:
case TIOCGPTN:
case TIOCSPTLCK:
+ case TIOCGSERIAL:
+ case TIOCSSERIAL:
+ case TIOCSERGETLSR:
/* Big F */
case FBIOGTYPE:
@@ -2124,6 +2127,9 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
case OPROMGETCONS:
case OPROMGETFBNAME:
case OPROMGETBOOTARGS:
+ case OPROMSETCUR:
+ case OPROMPCI2NODE:
+ case OPROMPATH2NODE:
/* Socket level stuff */
case FIOSETOWN:
@@ -2175,6 +2181,9 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
case PPPIOCSNPMODE:
case PPPIOCGDEBUG:
case PPPIOCSDEBUG:
+ case PPPIOCNEWUNIT:
+ case PPPIOCATTACH:
+ case PPPIOCDETACH:
/* CDROM stuff */
case CDROMPAUSE:
@@ -2204,6 +2213,9 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
case CDROM_DRIVE_STATUS:
case CDROM_DISC_STATUS:
case CDROM_CHANGER_NSLOTS:
+ case CDROM_LOCKDOOR:
+ case CDROM_DEBUG:
+ case CDROM_GET_CAPABILITY:
/* Big L */
case LOOP_SET_FD:
diff --git a/arch/sparc64/kernel/iommu_common.c b/arch/sparc64/kernel/iommu_common.c
new file mode 100644
index 000000000..c537353e0
--- /dev/null
+++ b/arch/sparc64/kernel/iommu_common.c
@@ -0,0 +1,233 @@
+/* $Id: iommu_common.c,v 1.2 1999/12/19 09:17:53 davem Exp $
+ * iommu_common.c: UltraSparc SBUS/PCI common iommu code.
+ *
+ * Copyright (C) 1999 David S. Miller (davem@redhat.com)
+ */
+
+#include "iommu_common.h"
+
+/* You are _strongly_ advised to enable the following debugging code
+ * any time you make changes to the sg code below, run it for a while
+ * with filesystems mounted read-only before buying the farm... -DaveM
+ */
+
+#ifdef VERIFY_SG
+int verify_lengths(struct scatterlist *sg, int nents, int npages)
+{
+ int sg_len, dma_len;
+ int i, pgcount;
+
+ sg_len = 0;
+ for (i = 0; i < nents; i++)
+ sg_len += sg[i].length;
+
+ dma_len = 0;
+ for (i = 0; i < nents && sg[i].dvma_length; i++)
+ dma_len += sg[i].dvma_length;
+
+ if (sg_len != dma_len) {
+ printk("verify_lengths: Error, different, sg[%d] dma[%d]\n",
+ sg_len, dma_len);
+ return -1;
+ }
+
+ pgcount = 0;
+ for (i = 0; i < nents && sg[i].dvma_length; i++) {
+ unsigned long start, end;
+
+ start = sg[i].dvma_address;
+ start = start & PAGE_MASK;
+
+ end = sg[i].dvma_address + sg[i].dvma_length;
+ end = (end + (PAGE_SIZE - 1)) & PAGE_MASK;
+
+ pgcount += ((end - start) >> PAGE_SHIFT);
+ }
+
+ if (pgcount != npages) {
+ printk("verify_langths: Error, page count wrong, "
+ "npages[%d] pgcount[%d]\n",
+ npages, pgcount);
+ return -1;
+ }
+
+ /* This test passes... */
+ return 0;
+}
+
+int verify_one_map(struct scatterlist *dma_sg, struct scatterlist **__sg, int nents, iopte_t **__iopte)
+{
+ struct scatterlist *sg = *__sg;
+ iopte_t *iopte = *__iopte;
+ int retval = 0;
+ u32 dlen = dma_sg->dvma_length;
+ u32 daddr = dma_sg->dvma_address;
+ unsigned int sglen;
+ unsigned long sgaddr;
+
+ sglen = sg->length;
+ sgaddr = (unsigned long) sg->address;
+ while (dlen > 0) {
+ unsigned long paddr;
+
+ /* SG and DMA_SG must begin at the same sub-page boundary. */
+ if ((sgaddr & ~PAGE_MASK) != (daddr & ~PAGE_MASK)) {
+ printk("verify_one_map: Wrong start offset "
+ "sg[%08lx] dma[%08x]\n",
+ sgaddr, daddr);
+ retval = -nents;
+ goto out;
+ }
+
+ /* Verify the IOPTE points to the right page. */
+ paddr = iopte_val(*iopte) & IOPTE_PAGE;
+ if ((paddr + PAGE_OFFSET) != (sgaddr & PAGE_MASK)) {
+ printk("verify_one_map: IOPTE[%08lx] maps the "
+ "wrong page, should be [%08lx]\n",
+ iopte_val(*iopte), (sgaddr & PAGE_MASK) - PAGE_OFFSET);
+ retval = -nents;
+ goto out;
+ }
+
+ /* If this SG crosses a page, adjust to that next page
+ * boundary and loop.
+ */
+ if ((sgaddr & PAGE_MASK) ^ ((sgaddr + sglen - 1) & PAGE_MASK)) {
+ unsigned long next_page, diff;
+
+ next_page = (sgaddr + PAGE_SIZE) & PAGE_MASK;
+ diff = next_page - sgaddr;
+ sgaddr += diff;
+ daddr += diff;
+ sglen -= diff;
+ dlen -= diff;
+ if (dlen > 0)
+ iopte++;
+ continue;
+ }
+
+ /* SG wholly consumed within this page. */
+ daddr += sglen;
+ dlen -= sglen;
+
+ if (dlen > 0 && ((daddr & ~PAGE_MASK) == 0))
+ iopte++;
+
+ sg++;
+ sgaddr = (unsigned long) sg->address;
+ sglen = sg->length;
+ }
+ if (dlen < 0) {
+ /* Transfer overrun, big problems. */
+ printk("verify_one_map: Transfer overrun by %d bytes.\n",
+ -dlen);
+ retval = -nents;
+ } else {
+ /* Advance to next dma_sg implies that the next iopte will
+ * begin it.
+ */
+ iopte++;
+ }
+
+out:
+ *__sg = sg;
+ *__iopte = iopte;
+ return retval;
+}
+
+int verify_maps(struct scatterlist *sg, int nents, iopte_t *iopte)
+{
+ struct scatterlist *dma_sg = sg;
+ struct scatterlist *orig_dma_sg = dma_sg;
+ int orig_nents = nents;
+
+ for (;;) {
+ nents = verify_one_map(dma_sg, &sg, nents, &iopte);
+ if (nents <= 0)
+ break;
+ dma_sg++;
+ if (dma_sg->dvma_length == 0)
+ break;
+ }
+
+ if (nents > 0) {
+ printk("verify_maps: dma maps consumed by some sgs remain (%d)\n",
+ nents);
+ return -1;
+ }
+
+ if (nents < 0) {
+ printk("verify_maps: Error, messed up mappings, "
+ "at sg %d dma_sg %d\n",
+ (int) (orig_nents + nents), (int) (dma_sg - orig_dma_sg));
+ return -1;
+ }
+
+ /* This test passes... */
+ return 0;
+}
+
+void verify_sglist(struct scatterlist *sg, int nents, iopte_t *iopte, int npages)
+{
+ if (verify_lengths(sg, nents, npages) < 0 ||
+ verify_maps(sg, nents, iopte) < 0) {
+ int i;
+
+ printk("verify_sglist: Crap, messed up mappings, dumping, iodma at %08x.\n",
+ (u32) (sg->dvma_address & PAGE_MASK));
+ for (i = 0; i < nents; i++) {
+ printk("sg(%d): address(%p) length(%x) "
+ "dma_address[%08x] dma_length[%08x]\n",
+ i,
+ sg[i].address, sg[i].length,
+ sg[i].dvma_address, sg[i].dvma_length);
+ }
+ }
+
+ /* Seems to be ok */
+}
+#endif
+
+/* Two addresses are "virtually contiguous" if and only if:
+ * 1) They are equal, or...
+ * 2) They are both on a page boundry
+ */
+#define VCONTIG(__X, __Y) (((__X) == (__Y)) || \
+ (((__X) | (__Y)) << (64UL - PAGE_SHIFT)) == 0UL)
+
+unsigned long prepare_sg(struct scatterlist *sg, int nents)
+{
+ struct scatterlist *dma_sg = sg;
+ unsigned long prev;
+ u32 dent_addr, dent_len;
+
+ prev = (unsigned long) sg->address;
+ prev += (unsigned long) (dent_len = sg->length);
+ dent_addr = (u32) ((unsigned long)sg->address & (PAGE_SIZE - 1UL));
+ while (--nents) {
+ unsigned long addr;
+
+ sg++;
+ addr = (unsigned long) sg->address;
+ if (! VCONTIG(prev, addr)) {
+ dma_sg->dvma_address = dent_addr;
+ dma_sg->dvma_length = dent_len;
+ dma_sg++;
+
+ dent_addr = ((dent_addr +
+ dent_len +
+ (PAGE_SIZE - 1UL)) >> PAGE_SHIFT);
+ dent_addr <<= PAGE_SHIFT;
+ dent_addr += addr & (PAGE_SIZE - 1UL);
+ dent_len = 0;
+ }
+ dent_len += sg->length;
+ prev = addr + sg->length;
+ }
+ dma_sg->dvma_address = dent_addr;
+ dma_sg->dvma_length = dent_len;
+
+ return ((unsigned long) dent_addr +
+ (unsigned long) dent_len +
+ (PAGE_SIZE - 1UL)) >> PAGE_SHIFT;
+}
diff --git a/arch/sparc64/kernel/iommu_common.h b/arch/sparc64/kernel/iommu_common.h
new file mode 100644
index 000000000..30cbd4385
--- /dev/null
+++ b/arch/sparc64/kernel/iommu_common.h
@@ -0,0 +1,34 @@
+/* $Id: iommu_common.h,v 1.1 1999/12/17 12:31:54 jj Exp $
+ * iommu_common.h: UltraSparc SBUS/PCI common iommu declarations.
+ *
+ * Copyright (C) 1999 David S. Miller (davem@redhat.com)
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+
+#include <asm/page.h>
+#include <asm/iommu.h>
+#include <asm/scatterlist.h>
+
+/* You are _strongly_ advised to enable the following debugging code
+ * any time you make changes to the sg code below, run it for a while
+ * with filesystems mounted read-only before buying the farm... -DaveM
+ */
+#undef VERIFY_SG
+
+#ifdef VERIFY_SG
+int verify_lengths(struct scatterlist *sg, int nents, int npages);
+int verify_one_map(struct scatterlist *dma_sg, struct scatterlist **__sg, int nents, iopte_t **__iopte);
+int verify_maps(struct scatterlist *sg, int nents, iopte_t *iopte);
+void verify_sglist(struct scatterlist *sg, int nents, iopte_t *iopte, int npages);
+#endif
+
+/* Two addresses are "virtually contiguous" if and only if:
+ * 1) They are equal, or...
+ * 2) They are both on a page boundry
+ */
+#define VCONTIG(__X, __Y) (((__X) == (__Y)) || \
+ (((__X) | (__Y)) << (64UL - PAGE_SHIFT)) == 0UL)
+
+unsigned long prepare_sg(struct scatterlist *sg, int nents);
diff --git a/arch/sparc64/kernel/ioport.c b/arch/sparc64/kernel/ioport.c
deleted file mode 100644
index 84b097d3f..000000000
--- a/arch/sparc64/kernel/ioport.c
+++ /dev/null
@@ -1,107 +0,0 @@
-/* $Id: ioport.c,v 1.14 1998/05/11 06:23:36 davem Exp $
- * ioport.c: Simple io mapping allocator.
- *
- * Copyright (C) 1995,1996 David S. Miller (davem@caip.rutgers.edu)
- * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx)
- */
-
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/types.h>
-#include <linux/ioport.h>
-#include <linux/mm.h>
-
-#include <asm/io.h>
-#include <asm/vaddrs.h>
-#include <asm/oplib.h>
-#include <asm/page.h>
-#include <asm/pgtable.h>
-
-/* This points to the next to use virtual memory for io mappings */
-static unsigned long dvma_next_free = DVMA_VADDR;
-
-extern void mmu_map_dma_area(unsigned long addr, int len, __u32 *dvma_addr);
-
-/*
- * sparc_alloc_io:
- * Map and allocates an obio device.
- * Implements a simple linear allocator, you can force the function
- * to use your own mapping, but in practice this should not be used.
- *
- * Input:
- * address: Physical address to map
- * virtual: if non zero, specifies a fixed virtual address where
- * the mapping should take place, not supported on Ultra
- * and this feature is scheduled to be removed as nobody
- * uses it. -DaveM
- * len: the length of the mapping
- * bus_type: Optional high word of physical address.
- *
- * Returns:
- * The virtual address where the mapping actually took place.
- */
-
-void *sparc_alloc_io (u32 address, void *virtual, int len, char *name,
- u32 bus_type, int rdonly)
-{
- unsigned long addr = ((unsigned long)address) + (((unsigned long)bus_type)<<32);
- unsigned long vaddr = (unsigned long) __va(addr);
-
- if(virtual)
- panic("sparc_alloc_io: Fixed virtual mappings unsupported on Ultra.");
-
- if(!check_region(vaddr, len))
- request_region(vaddr, len, name);
-
- return (void *) vaddr;
-}
-
-void sparc_free_io (void *virtual, int len)
-{
- unsigned long vaddr = (unsigned long) virtual & PAGE_MASK;
- unsigned long plen = (((unsigned long)virtual & ~PAGE_MASK) +
- len + PAGE_SIZE-1) & PAGE_MASK;
- release_region(vaddr, plen);
-}
-
-/* Does DVMA allocations with PAGE_SIZE granularity. How this basically
- * works is that the ESP chip can do DVMA transfers at ANY address with
- * certain size and boundary restrictions. But other devices that are
- * attached to it and would like to do DVMA have to set things up in
- * a special way, if the DVMA sees a device attached to it transfer data
- * at addresses above DVMA_VADDR it will grab them, this way it does not
- * now have to know the peculiarities of where to read the Lance data
- * from. (for example)
- *
- * Returns CPU visible address for the buffer returned, dvma_addr is
- * set to the DVMA visible address.
- */
-void *sparc_dvma_malloc (int len, char *name, __u32 *dvma_addr)
-{
- unsigned long vaddr, base_address;
-
- vaddr = dvma_next_free;
- if(check_region (vaddr, len)) {
- prom_printf("alloc_dma: 0x%lx is already in use\n", vaddr);
- prom_halt();
- }
- if(vaddr + len > (DVMA_VADDR + DVMA_LEN)) {
- prom_printf("alloc_dvma: out of dvma memory\n");
- prom_halt();
- }
-
- /* Basically these can be mapped just like any old
- * IO pages, cacheable bit off, etc. The physical
- * pages are now mapped dynamically to save space.
- */
- base_address = vaddr;
- mmu_map_dma_area(base_address, len, dvma_addr);
-
- /* Assign the memory area. */
- dvma_next_free = PAGE_ALIGN(dvma_next_free+len);
-
- request_region(base_address, len, name);
-
- return (void *) base_address;
-}
diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c
index 598cece4e..b70d936c3 100644
--- a/arch/sparc64/kernel/irq.c
+++ b/arch/sparc64/kernel/irq.c
@@ -1,4 +1,4 @@
-/* $Id: irq.c,v 1.78 1999/08/31 06:54:54 davem Exp $
+/* $Id: irq.c,v 1.80 1999/12/06 03:14:48 davem Exp $
* irq.c: UltraSparc IRQ handling/init/registry.
*
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -106,89 +106,16 @@ int get_irq_list(char *buf)
return len;
}
-/* SBUS SYSIO INO number to Sparc PIL level. */
-unsigned char sysio_ino_to_pil[] = {
- 0, 1, 2, 7, 5, 7, 8, 9, /* SBUS slot 0 */
- 0, 1, 2, 7, 5, 7, 8, 9, /* SBUS slot 1 */
- 0, 1, 2, 7, 5, 7, 8, 9, /* SBUS slot 2 */
- 0, 1, 2, 7, 5, 7, 8, 9, /* SBUS slot 3 */
- 3, /* Onboard SCSI */
- 5, /* Onboard Ethernet */
-/*XXX*/ 8, /* Onboard BPP */
- 0, /* Bogon */
- 13, /* Audio */
-/*XXX*/15, /* PowerFail */
- 0, /* Bogon */
- 0, /* Bogon */
- 12, /* Zilog Serial Channels (incl. Keyboard/Mouse lines) */
- 11, /* Floppy */
- 0, /* Spare Hardware (bogon for now) */
- 0, /* Keyboard (bogon for now) */
- 0, /* Mouse (bogon for now) */
- 0, /* Serial (bogon for now) */
- 0, 0, /* Bogon, Bogon */
- 10, /* Timer 0 */
- 11, /* Timer 1 */
- 0, 0, /* Bogon, Bogon */
- 15, /* Uncorrectable SBUS Error */
- 15, /* Correctable SBUS Error */
- 15, /* SBUS Error */
-/*XXX*/ 0, /* Power Management (bogon for now) */
-};
-
-/* INO number to IMAP register offset for SYSIO external IRQ's.
- * This should conform to both Sunfire/Wildfire server and Fusion
- * desktop designs.
- */
-#define offset(x) ((unsigned long)(&(((struct sysio_regs *)0)->x)))
-#define bogon ((unsigned long) -1)
-static unsigned long sysio_irq_offsets[] = {
-/* SBUS Slot 0 --> 3, level 1 --> 7 */
-offset(imap_slot0),offset(imap_slot0),offset(imap_slot0),offset(imap_slot0),
-offset(imap_slot0),offset(imap_slot0),offset(imap_slot0),offset(imap_slot0),
-offset(imap_slot1),offset(imap_slot1),offset(imap_slot1),offset(imap_slot1),
-offset(imap_slot1),offset(imap_slot1),offset(imap_slot1),offset(imap_slot1),
-offset(imap_slot2),offset(imap_slot2),offset(imap_slot2),offset(imap_slot2),
-offset(imap_slot2),offset(imap_slot2),offset(imap_slot2),offset(imap_slot2),
-offset(imap_slot3),offset(imap_slot3),offset(imap_slot3),offset(imap_slot3),
-offset(imap_slot3),offset(imap_slot3),offset(imap_slot3),offset(imap_slot3),
-/* Onboard devices (not relevant/used on SunFire). */
-offset(imap_scsi), offset(imap_eth), offset(imap_bpp), bogon,
-offset(imap_audio), offset(imap_pfail), bogon, bogon,
-offset(imap_kms), offset(imap_flpy), offset(imap_shw),
-offset(imap_kbd), offset(imap_ms), offset(imap_ser), bogon, bogon,
-offset(imap_tim0), offset(imap_tim1), bogon, bogon,
-offset(imap_ue), offset(imap_ce), offset(imap_sberr),
-offset(imap_pmgmt),
-};
-
-#undef bogon
-
-#define NUM_SYSIO_OFFSETS (sizeof(sysio_irq_offsets) / sizeof(sysio_irq_offsets[0]))
-
-/* Convert Interrupt Mapping register pointer to assosciated
- * Interrupt Clear register pointer, SYSIO specific version.
- */
-static volatile unsigned int *sysio_imap_to_iclr(volatile unsigned int *imap)
-{
- unsigned long diff;
-
- diff = offset(iclr_unused0) - offset(imap_slot0);
- return (volatile unsigned int *) (((unsigned long)imap) + diff);
-}
-
-#undef offset
-
/* Now these are always passed a true fully specified sun4u INO. */
void enable_irq(unsigned int irq)
{
extern int this_is_starfire;
struct ino_bucket *bucket = __bucket(irq);
- volatile unsigned int *imap;
+ unsigned long imap;
unsigned long tid;
imap = bucket->imap;
- if (!imap)
+ if (imap == 0UL)
return;
if(this_is_starfire == 0) {
@@ -198,7 +125,7 @@ void enable_irq(unsigned int irq)
: "i" (ASI_UPA_CONFIG));
tid = ((tid & UPA_CONFIG_MID) << 9);
} else {
- extern unsigned int starfire_translate(volatile unsigned int *imap,
+ extern unsigned int starfire_translate(unsigned long imap,
unsigned int upaid);
tid = (starfire_translate(imap, current->processor) << 26);
@@ -208,27 +135,31 @@ void enable_irq(unsigned int irq)
* of this SYSIO's preconfigured IGN in the SYSIO Control
* Register, the hardware just mirrors that value here.
* However for Graphics and UPA Slave devices the full
- * SYSIO_IMAP_INR field can be set by the programmer here.
+ * IMAP_INR field can be set by the programmer here.
*
* Things like FFB can now be handled via the new IRQ mechanism.
*/
- *imap = SYSIO_IMAP_VALID | (tid & SYSIO_IMAP_TID);
+ upa_writel(IMAP_VALID | (tid & IMAP_TID), imap);
}
/* This now gets passed true ino's as well. */
void disable_irq(unsigned int irq)
{
struct ino_bucket *bucket = __bucket(irq);
- volatile unsigned int *imap;
+ unsigned long imap;
imap = bucket->imap;
- if (imap != NULL) {
+ if (imap != 0UL) {
+ u32 tmp;
+
/* NOTE: We do not want to futz with the IRQ clear registers
* and move the state to IDLE, the SCSI code does call
* disable_irq() to assure atomicity in the queue cmd
* SCSI adapter driver code. Thus we'd lose interrupts.
*/
- *imap &= ~(SYSIO_IMAP_VALID);
+ tmp = upa_readl(imap);
+ tmp &= ~IMAP_VALID;
+ upa_writel(tmp, imap);
}
}
@@ -243,18 +174,18 @@ static struct ino_bucket pil0_dummy_bucket = {
0, /* flags */
0, /* __unused */
NULL, /* irq_info */
- NULL, /* iclr */
- NULL, /* imap */
+ 0UL, /* iclr */
+ 0UL, /* imap */
};
-unsigned int build_irq(int pil, int inofixup, volatile unsigned int *iclr, volatile unsigned int *imap)
+unsigned int build_irq(int pil, int inofixup, unsigned long iclr, unsigned long imap)
{
struct ino_bucket *bucket;
int ino;
if(pil == 0) {
- if(iclr != NULL || imap != NULL) {
- prom_printf("Invalid dummy bucket for PIL0 (%p:%p)\n",
+ if(iclr != 0UL || imap != 0UL) {
+ prom_printf("Invalid dummy bucket for PIL0 (%lx:%lx)\n",
iclr, imap);
prom_halt();
}
@@ -262,13 +193,13 @@ unsigned int build_irq(int pil, int inofixup, volatile unsigned int *iclr, volat
}
/* RULE: Both must be specified in all other cases. */
- if (iclr == NULL || imap == NULL) {
+ if (iclr == 0UL || imap == 0UL) {
prom_printf("Invalid build_irq %d %d %016lx %016lx\n",
pil, inofixup, iclr, imap);
prom_halt();
}
- ino = (*imap & (SYSIO_IMAP_IGN | SYSIO_IMAP_INO)) + inofixup;
+ ino = (upa_readl(imap) & (IMAP_IGN | IMAP_INO)) + inofixup;
if(ino > NUM_IVECS) {
prom_printf("Invalid INO %04x (%d:%d:%016lx:%016lx)\n",
ino, pil, inofixup, iclr, imap);
@@ -300,64 +231,6 @@ unsigned int build_irq(int pil, int inofixup, volatile unsigned int *iclr, volat
return __irq(bucket);
}
-unsigned int sbus_build_irq(void *buscookie, unsigned int ino)
-{
- struct linux_sbus *sbus = (struct linux_sbus *)buscookie;
- struct sysio_regs *sregs = sbus->iommu->sysio_regs;
- unsigned long offset;
- int pil;
- volatile unsigned int *imap, *iclr;
- int sbus_level = 0;
-
- pil = sysio_ino_to_pil[ino];
- if(!pil) {
- printk("sbus_irq_build: Bad SYSIO INO[%x]\n", ino);
- panic("Bad SYSIO IRQ translations...");
- }
- offset = sysio_irq_offsets[ino];
- if(offset == ((unsigned long)-1)) {
- printk("get_irq_translations: Bad SYSIO INO[%x] cpu[%d]\n",
- ino, pil);
- panic("BAD SYSIO IRQ offset...");
- }
- offset += ((unsigned long)sregs);
- imap = ((volatile unsigned int *)offset);
-
- /* SYSIO inconsistancy. For external SLOTS, we have to select
- * the right ICLR register based upon the lower SBUS irq level
- * bits.
- */
- if(ino >= 0x20) {
- iclr = sysio_imap_to_iclr(imap);
- } else {
- unsigned long iclraddr;
- int sbus_slot = (ino & 0x18)>>3;
-
- sbus_level = ino & 0x7;
-
- switch(sbus_slot) {
- case 0:
- iclr = &sregs->iclr_slot0;
- break;
- case 1:
- iclr = &sregs->iclr_slot1;
- break;
- case 2:
- iclr = &sregs->iclr_slot2;
- break;
- default:
- case 3:
- iclr = &sregs->iclr_slot3;
- break;
- };
-
- iclraddr = (unsigned long) iclr;
- iclraddr += ((sbus_level - 1) * 8);
- iclr = (volatile unsigned int *) iclraddr;
- }
- return build_irq(pil, sbus_level, iclr, imap);
-}
-
static void atomic_bucket_insert(struct ino_bucket *bucket)
{
unsigned long pstate;
@@ -602,7 +475,7 @@ void free_irq(unsigned int irq, void *dev_id)
*(bucket->pil + irq_action) = action->next;
if(action->flags & SA_IMAP_MASKED) {
- volatile unsigned int *imap = bucket->imap;
+ unsigned long imap = bucket->imap;
void **vector, *orig;
int ent;
@@ -696,10 +569,10 @@ static void show(char * str)
int cpu = smp_processor_id();
printk("\n%s, CPU %d:\n", str, cpu);
- printk("irq: %d [%ld %ld]\n",
+ printk("irq: %d [%u %u]\n",
atomic_read(&global_irq_count),
cpu_data[0].irq_count, cpu_data[1].irq_count);
- printk("bh: %d [%ld %ld]\n",
+ printk("bh: %d [%u %u]\n",
(spin_is_locked(&global_bh_count) ? 1 : 0),
cpu_data[0].bh_count, cpu_data[1].bh_count);
}
@@ -947,10 +820,10 @@ void handler_irq(int irq, struct pt_regs *regs)
if (should_forward != 0) {
/* Push it to our buddy. */
should_forward = 0;
- *(bp->imap) = (buddy | SYSIO_IMAP_VALID);
+ upa_writel(buddy | IMAP_VALID, bp->imap);
}
#endif
- *(bp->iclr) = SYSIO_ICLR_IDLE;
+ upa_writel(ICLR_IDLE, bp->iclr);
}
} else
bp->pending = 1;
@@ -974,7 +847,7 @@ void sparc_floppy_irq(int irq, void *dev_cookie, struct pt_regs *regs)
bucket = (struct ino_bucket *)action->mask;
floppy_interrupt(irq, dev_cookie, regs);
- *(bucket->iclr) = SYSIO_ICLR_IDLE;
+ upa_writel(ICLR_IDLE, bucket->iclr);
irq_exit(cpu, irq);
}
@@ -1116,7 +989,7 @@ void init_timers(void (*cfunc)(int, void *, struct pt_regs *),
#endif
/* Register IRQ handler. */
- err = request_irq(build_irq(0, 0, NULL, NULL), cfunc, (SA_INTERRUPT | SA_STATIC_ALLOC),
+ err = request_irq(build_irq(0, 0, 0UL, 0UL), cfunc, (SA_INTERRUPT | SA_STATIC_ALLOC),
"timer", NULL);
if(err) {
@@ -1157,7 +1030,7 @@ static int retarget_one_irq(struct irqaction *p, int goal_cpu)
{
extern int this_is_starfire;
struct ino_bucket *bucket = __bucket(p->mask);
- volatile unsigned int *imap = bucket->imap;
+ unsigned long imap = bucket->imap;
unsigned int tid;
/* Never change this, it causes problems on Ex000 systems. */
@@ -1167,12 +1040,12 @@ static int retarget_one_irq(struct irqaction *p, int goal_cpu)
if(this_is_starfire == 0) {
tid = __cpu_logical_map[goal_cpu] << 26;
} else {
- extern unsigned int starfire_translate(volatile unsigned int *imap,
+ extern unsigned int starfire_translate(unsigned long imap,
unsigned int upaid);
tid = (starfire_translate(imap, __cpu_logical_map[goal_cpu]) << 26);
}
- *imap = SYSIO_IMAP_VALID | (tid & SYSIO_IMAP_TID);
+ upa_writel(IMAP_VALID | (tid & IMAP_TID), imap);
goal_cpu++;
if(goal_cpu >= NR_CPUS ||
diff --git a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c
index c9e3681dd..c102a6205 100644
--- a/arch/sparc64/kernel/pci.c
+++ b/arch/sparc64/kernel/pci.c
@@ -1,4 +1,4 @@
-/* $Id: pci.c,v 1.6 1999/09/08 03:40:41 davem Exp $
+/* $Id: pci.c,v 1.13 2000/01/06 23:51:49 davem Exp $
* pci.c: UltraSparc PCI controller support.
*
* Copyright (C) 1997, 1998, 1999 David S. Miller (davem@redhat.com)
@@ -20,8 +20,11 @@
#include <asm/irq.h>
#include <asm/ebus.h>
+#ifndef NEW_PCI_DMA_MAP
unsigned long pci_dvma_v2p_hash[PCI_DVMA_HASHSZ];
unsigned long pci_dvma_p2v_hash[PCI_DVMA_HASHSZ];
+#endif
+
unsigned long pci_memspace_mask = 0xffffffffUL;
#ifndef CONFIG_PCI
@@ -158,25 +161,19 @@ static void pci_scan_each_controller_bus(void)
*/
static void __init pci_reorder_devs(void)
{
- struct pci_dev **pci_onboard = &pci_devices;
- struct pci_dev **pci_tail = &pci_devices;
- struct pci_dev *pdev = pci_devices, *pci_other = NULL;
+ struct list_head *pci_onboard = &pci_devices;
+ struct list_head *walk = pci_onboard->next;
+
+ while (walk != pci_onboard) {
+ struct pci_dev *pdev = pci_dev_g(walk);
+ struct list_head *walk_next = walk->next;
- while (pdev) {
if (pdev->irq && (__irq_ino(pdev->irq) & 0x20)) {
- if (pci_other) {
- *pci_onboard = pdev;
- pci_onboard = &pdev->next;
- pdev = pdev->next;
- *pci_onboard = pci_other;
- *pci_tail = pdev;
- continue;
- } else
- pci_onboard = &pdev->next;
- } else if (!pci_other)
- pci_other = pdev;
- pci_tail = &pdev->next;
- pdev = pdev->next;
+ list_del(walk);
+ list_add(walk, pci_onboard);
+ }
+
+ walk = walk_next;
}
}
@@ -202,6 +199,35 @@ void pcibios_fixup_bus(struct pci_bus *pbus)
{
}
+void pcibios_update_resource(struct pci_dev *pdev, struct resource *res1,
+ struct resource *res2, int index)
+{
+}
+
+void pcibios_update_irq(struct pci_dev *pdev, int irq)
+{
+}
+
+unsigned long resource_fixup(struct pci_dev *pdev, struct resource *res,
+ unsigned long start, unsigned long size)
+{
+ return start;
+}
+
+void pcibios_fixup_pbus_ranges(struct pci_bus *pbus,
+ struct pbus_set_ranges_data *pranges)
+{
+}
+
+void pcibios_align_resource(void *data, struct resource *res, unsigned long size)
+{
+}
+
+int pci_assign_resource(struct pci_dev *dev, int i)
+{
+ return -ENOSYS; /* :-)... actually implement this soon */
+}
+
char * __init pcibios_setup(char *str)
{
if (!strcmp(str, "onboardfirst")) {
diff --git a/arch/sparc64/kernel/pci_common.c b/arch/sparc64/kernel/pci_common.c
index a3600df9c..154ee0181 100644
--- a/arch/sparc64/kernel/pci_common.c
+++ b/arch/sparc64/kernel/pci_common.c
@@ -1,4 +1,4 @@
-/* $Id: pci_common.c,v 1.3 1999/09/04 22:26:32 ecd Exp $
+/* $Id: pci_common.c,v 1.6 2000/01/06 23:51:49 davem Exp $
* pci_common.c: PCI controller common support.
*
* Copyright (C) 1999 David S. Miller (davem@redhat.com)
@@ -59,29 +59,8 @@ static int __init find_device_prom_node(struct pci_pbm_info *pbm,
*/
static void pci_device_delete(struct pci_dev *pdev)
{
- struct pci_dev **dpp;
-
- /* First, unlink from list of all devices. */
- dpp = &pci_devices;
- while (*dpp != NULL) {
- if (*dpp == pdev) {
- *dpp = pdev->next;
- pdev->next = NULL;
- break;
- }
- dpp = &(*dpp)->next;
- }
-
- /* Next, unlink from bus sibling chain. */
- dpp = &pdev->bus->devices;
- while (*dpp != NULL) {
- if (*dpp == pdev) {
- *dpp = pdev->sibling;
- pdev->sibling = NULL;
- break;
- }
- dpp = &(*dpp)->sibling;
- }
+ list_del(&pdev->global_list);
+ list_del(&pdev->bus_list);
/* Ok, all references are gone, free it up. */
kfree(pdev);
@@ -175,23 +154,31 @@ void __init pci_fill_in_pbm_cookies(struct pci_bus *pbus,
struct pci_pbm_info *pbm,
int prom_node)
{
- struct pci_dev *pdev;
+ struct list_head *walk = &pbus->devices;
/* This loop is coded like this because the cookie
* fillin routine can delete devices from the tree.
*/
- pdev = pbus->devices;
- while (pdev != NULL) {
- struct pci_dev *next = pdev->sibling;
+ walk = walk->next;
+ while (walk != &pbus->devices) {
+ struct pci_dev *pdev = pci_dev_b(walk);
+ struct list_head *walk_next = walk->next;
pdev_cookie_fillin(pbm, pdev, prom_node);
- pdev = next;
+ walk = walk_next;
}
- for (pbus = pbus->children; pbus; pbus = pbus->next) {
- struct pcidev_cookie *pcp = pbus->self->sysdata;
- pci_fill_in_pbm_cookies(pbus, pbm, pcp->prom_node);
+ walk = &pbus->children;
+ walk = walk->next;
+ while (walk != &pbus->children) {
+ struct pci_bus *this_pbus = pci_bus_b(walk);
+ struct pcidev_cookie *pcp = this_pbus->self->sysdata;
+ struct list_head *walk_next = walk->next;
+
+ pci_fill_in_pbm_cookies(this_pbus, pbm, pcp->prom_node);
+
+ walk = walk_next;
}
}
@@ -315,13 +302,14 @@ static void __init pdev_record_assignments(struct pci_pbm_info *pbm,
void __init pci_record_assignments(struct pci_pbm_info *pbm,
struct pci_bus *pbus)
{
- struct pci_dev *pdev;
+ struct list_head *walk = &pbus->devices;
- for (pdev = pbus->devices; pdev; pdev = pdev->sibling)
- pdev_record_assignments(pbm, pdev);
+ for (walk = walk->next; walk != &pbus->devices; walk = walk->next)
+ pdev_record_assignments(pbm, pci_dev_b(walk));
- for (pbus = pbus->children; pbus; pbus = pbus->next)
- pci_record_assignments(pbm, pbus);
+ walk = &pbus->children;
+ for (walk = walk->next; walk != &pbus->children; walk = walk->next)
+ pci_record_assignments(pbm, pci_bus_b(walk));
}
static void __init pdev_assign_unassigned(struct pci_pbm_info *pbm,
@@ -362,7 +350,7 @@ static void __init pdev_assign_unassigned(struct pci_pbm_info *pbm,
size = res->end - res->start;
align = size + 1;
- if (allocate_resource(root, res, size + 1, min, max, align) < 0) {
+ if (allocate_resource(root, res, size + 1, min, max, align, NULL, NULL) < 0) {
/* uh oh */
prom_printf("PCI: Failed to allocate resource %d for %s\n",
i, pdev->name);
@@ -415,13 +403,14 @@ static void __init pdev_assign_unassigned(struct pci_pbm_info *pbm,
void __init pci_assign_unassigned(struct pci_pbm_info *pbm,
struct pci_bus *pbus)
{
- struct pci_dev *pdev;
+ struct list_head *walk = &pbus->devices;
- for (pdev = pbus->devices; pdev; pdev = pdev->sibling)
- pdev_assign_unassigned(pbm, pdev);
+ for (walk = walk->next; walk != &pbus->devices; walk = walk->next)
+ pdev_assign_unassigned(pbm, pci_dev_b(walk));
- for (pbus = pbus->children; pbus; pbus = pbus->next)
- pci_assign_unassigned(pbm, pbus);
+ walk = &pbus->children;
+ for (walk = walk->next; walk != &pbus->children; walk = walk->next)
+ pci_assign_unassigned(pbm, pci_bus_b(walk));
}
static int __init pci_intmap_match(struct pci_dev *pdev, unsigned int *interrupt)
@@ -566,13 +555,14 @@ have_irq:
void __init pci_fixup_irq(struct pci_pbm_info *pbm,
struct pci_bus *pbus)
{
- struct pci_dev *pdev;
+ struct list_head *walk = &pbus->devices;
- for (pdev = pbus->devices; pdev; pdev = pdev->sibling)
- pdev_fixup_irq(pdev);
+ for (walk = walk->next; walk != &pbus->devices; walk = walk->next)
+ pdev_fixup_irq(pci_dev_b(walk));
- for (pbus = pbus->children; pbus; pbus = pbus->next)
- pci_fixup_irq(pbm, pbus);
+ walk = &pbus->children;
+ for (walk = walk->next; walk != &pbus->children; walk = walk->next)
+ pci_fixup_irq(pbm, pci_bus_b(walk));
}
/* Generic helper routines for PCI error reporting. */
@@ -580,9 +570,10 @@ void pci_scan_for_target_abort(struct pci_controller_info *p,
struct pci_pbm_info *pbm,
struct pci_bus *pbus)
{
- struct pci_dev *pdev;
+ struct list_head *walk = &pbus->devices;
- for (pdev = pbus->devices; pdev; pdev = pdev->sibling) {
+ for (walk = walk->next; walk != &pbus->devices; walk = walk->next) {
+ struct pci_dev *pdev = pci_dev_b(walk);
u16 status, error_bits;
pci_read_config_word(pdev, PCI_STATUS, &status);
@@ -597,17 +588,19 @@ void pci_scan_for_target_abort(struct pci_controller_info *p,
}
}
- for (pbus = pbus->children; pbus; pbus = pbus->next)
- pci_scan_for_target_abort(p, pbm, pbus);
+ walk = &pbus->children;
+ for (walk = walk->next; walk != &pbus->children; walk = walk->next)
+ pci_scan_for_target_abort(p, pbm, pci_bus_b(walk));
}
void pci_scan_for_master_abort(struct pci_controller_info *p,
struct pci_pbm_info *pbm,
struct pci_bus *pbus)
{
- struct pci_dev *pdev;
+ struct list_head *walk = &pbus->devices;
- for (pdev = pbus->devices; pdev; pdev = pdev->sibling) {
+ for (walk = walk->next; walk != &pbus->devices; walk = walk->next) {
+ struct pci_dev *pdev = pci_dev_b(walk);
u16 status, error_bits;
pci_read_config_word(pdev, PCI_STATUS, &status);
@@ -621,17 +614,19 @@ void pci_scan_for_master_abort(struct pci_controller_info *p,
}
}
- for (pbus = pbus->children; pbus; pbus = pbus->next)
- pci_scan_for_master_abort(p, pbm, pbus);
+ walk = &pbus->children;
+ for (walk = walk->next; walk != &pbus->children; walk = walk->next)
+ pci_scan_for_master_abort(p, pbm, pci_bus_b(walk));
}
void pci_scan_for_parity_error(struct pci_controller_info *p,
struct pci_pbm_info *pbm,
struct pci_bus *pbus)
{
- struct pci_dev *pdev;
+ struct list_head *walk = &pbus->devices;
- for (pdev = pbus->devices; pdev; pdev = pdev->sibling) {
+ for (walk = walk->next; walk != &pbus->devices; walk = walk->next) {
+ struct pci_dev *pdev = pci_dev_b(walk);
u16 status, error_bits;
pci_read_config_word(pdev, PCI_STATUS, &status);
@@ -646,6 +641,7 @@ void pci_scan_for_parity_error(struct pci_controller_info *p,
}
}
- for (pbus = pbus->children; pbus; pbus = pbus->next)
- pci_scan_for_parity_error(p, pbm, pbus);
+ walk = &pbus->children;
+ for (walk = walk->next; walk != &pbus->children; walk = walk->next)
+ pci_scan_for_parity_error(p, pbm, pci_bus_b(walk));
}
diff --git a/arch/sparc64/kernel/pci_impl.h b/arch/sparc64/kernel/pci_impl.h
index 24ed0319b..12b6af71e 100644
--- a/arch/sparc64/kernel/pci_impl.h
+++ b/arch/sparc64/kernel/pci_impl.h
@@ -1,4 +1,4 @@
-/* $Id: pci_impl.h,v 1.3 1999/09/10 10:40:44 davem Exp $
+/* $Id: pci_impl.h,v 1.4 1999/12/17 12:32:03 jj Exp $
* pci_impl.h: Helper definitions for PCI controller support.
*
* Copyright (C) 1999 David S. Miller (davem@redhat.com)
@@ -34,6 +34,7 @@ extern void pci_scan_for_target_abort(struct pci_controller_info *, struct pci_p
extern void pci_scan_for_master_abort(struct pci_controller_info *, struct pci_pbm_info *, struct pci_bus *);
extern void pci_scan_for_parity_error(struct pci_controller_info *, struct pci_pbm_info *, struct pci_bus *);
+#ifndef NEW_PCI_DMA_MAP
/* IOMMU/DVMA initialization. */
#define PCI_DVMA_HASH_NONE ~0UL
static __inline__ void set_dvma_hash(unsigned long dvma_offset,
@@ -46,6 +47,7 @@ static __inline__ void set_dvma_hash(unsigned long dvma_offset,
pci_dvma_v2p_hash[pci_dvma_ahashfn(paddr)] = dvma_addr - vaddr;
pci_dvma_p2v_hash[pci_dvma_ahashfn(dvma_addr)] = vaddr - dvma_addr;
}
+#endif
/* Configuration space access. */
extern spinlock_t pci_poke_lock;
diff --git a/arch/sparc64/kernel/pci_iommu.c b/arch/sparc64/kernel/pci_iommu.c
index a7f469ec8..12f7211d1 100644
--- a/arch/sparc64/kernel/pci_iommu.c
+++ b/arch/sparc64/kernel/pci_iommu.c
@@ -1,12 +1,17 @@
-/* $Id: pci_iommu.c,v 1.1 1999/08/30 10:00:47 davem Exp $
+/* $Id: pci_iommu.c,v 1.7 1999/12/20 14:08:15 jj Exp $
* pci_iommu.c: UltraSparc PCI controller IOM/STC support.
*
* Copyright (C) 1999 David S. Miller (davem@redhat.com)
+ * Copyright (C) 1999 Jakub Jelinek (jakub@redhat.com)
*/
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+
#include <asm/pbm.h>
-#include <asm/iommu.h>
-#include <asm/scatterlist.h>
+
+#include "iommu_common.h"
#define PCI_STC_CTXMATCH_ADDR(STC, CTX) \
((STC)->strbuf_ctxmatch_base + ((CTX) << 3))
@@ -29,27 +34,67 @@
: "r" (__val), "r" (__reg), \
"i" (ASI_PHYS_BYPASS_EC_E))
-/* Find a range of iommu mappings of size NPAGES in page
- * table PGT. Return pointer to first iopte.
- */
-static iopte_t *iommu_find_range(unsigned long npages, iopte_t *pgt, int pgt_size)
+static iopte_t *alloc_streaming_cluster(struct pci_iommu *iommu, unsigned long npages)
{
- int i;
+ iopte_t *iopte;
+ unsigned long cnum, ent;
+
+ cnum = 0;
+ while ((1UL << cnum) < npages)
+ cnum++;
+ iopte = iommu->page_table + (cnum << (iommu->page_table_sz_bits - PBM_LOGCLUSTERS));
+ iopte += ((ent = iommu->lowest_free[cnum]) << cnum);
+
+ if (iopte_val(iopte[(1UL << cnum)]) == 0UL) {
+ /* Fast path. */
+ iommu->lowest_free[cnum] = ent + 1;
+ } else {
+ unsigned long pte_off = 1;
- pgt_size -= npages;
- for (i = 0; i < pgt_size; i++) {
- if (!iopte_val(pgt[i]) & IOPTE_VALID) {
- int scan;
+ ent += 1;
+ do {
+ pte_off++;
+ ent++;
+ } while (iopte_val(iopte[(pte_off << cnum)]) != 0UL);
+ iommu->lowest_free[cnum] = ent;
+ }
- for (scan = 1; scan < npages; scan++) {
- if (iopte_val(pgt[i + scan]) & IOPTE_VALID) {
- i += scan;
- goto do_next;
- }
+ /* I've got your streaming cluster right here buddy boy... */
+ return iopte;
+}
+
+static inline void free_streaming_cluster(struct pci_iommu *iommu, u32 base, unsigned long npages)
+{
+ unsigned long cnum, ent;
+
+ cnum = 0;
+ while ((1UL << cnum) < npages)
+ cnum++;
+ ent = (base << (32 - PAGE_SHIFT + PBM_LOGCLUSTERS - iommu->page_table_sz_bits))
+ >> (32 + PBM_LOGCLUSTERS + cnum - iommu->page_table_sz_bits);
+ if (ent < iommu->lowest_free[cnum])
+ iommu->lowest_free[cnum] = ent;
+}
+
+/* We allocate consistant mappings from the end of cluster zero. */
+static iopte_t *alloc_consistant_cluster(struct pci_iommu *iommu, unsigned long npages)
+{
+ iopte_t *iopte;
+
+ iopte = iommu->page_table + (1 << (iommu->page_table_sz_bits - PBM_LOGCLUSTERS));
+ while (iopte > iommu->page_table) {
+ iopte--;
+ if (!(iopte_val(*iopte) & IOPTE_VALID)) {
+ unsigned long tmp = npages;
+
+ while (--tmp) {
+ iopte--;
+ if (iopte_val(*iopte) & IOPTE_VALID)
+ break;
}
- return &pgt[i];
+ if (tmp == 0)
+ return iopte;
}
- do_next:
}
return NULL;
}
@@ -64,123 +109,168 @@ static iopte_t *iommu_find_range(unsigned long npages, iopte_t *pgt, int pgt_siz
#define IOPTE_INVALID 0UL
-/* Map kernel buffer at ADDR of size SZ using consistant mode
- * DMA for PCI device PDEV. Return 32-bit PCI DMA address.
+/* Allocate and map kernel buffer of size SIZE using consistant mode
+ * DMA for PCI device PDEV. Return non-NULL cpu-side address if
+ * successful and set *DMA_ADDRP to the PCI side dma address.
*/
-u32 pci_map_consistant(struct pci_dev *pdev, void *addr, int sz)
+void *pci_alloc_consistant(struct pci_dev *pdev, long size, u32 *dma_addrp)
{
- struct pcidev_cookie *pcp = pdev->sysdata;
- struct pci_iommu *iommu = &pcp->pbm->parent->iommu;
- iopte_t *base;
- unsigned long flags, npages, oaddr;
- u32 ret;
+ struct pcidev_cookie *pcp;
+ struct pci_iommu *iommu;
+ iopte_t *iopte;
+ unsigned long flags, order, first_page, ctx;
+ void *ret;
+ int npages;
+
+ if (size <= 0 || pdev == NULL ||
+ pdev->sysdata == NULL || dma_addrp == NULL)
+ return NULL;
+
+ size = PAGE_ALIGN(size);
+ for (order = 0; order < 10; order++) {
+ if ((PAGE_SIZE << order) >= size)
+ break;
+ }
+ if (order == 10)
+ return NULL;
+
+ first_page = __get_free_pages(GFP_ATOMIC, order);
+ if (first_page == 0UL)
+ return NULL;
+ memset((char *)first_page, 0, PAGE_SIZE << order);
+
+ pcp = pdev->sysdata;
+ iommu = &pcp->pbm->parent->iommu;
spin_lock_irqsave(&iommu->lock, flags);
- oaddr = (unsigned long)addr;
- npages = PAGE_ALIGN(oaddr + sz) - (oaddr & PAGE_MASK);
- npages >>= PAGE_SHIFT;
- base = iommu_find_range(npages,
- iommu->page_table, iommu->page_table_sz);
- ret = 0;
- if (base != NULL) {
- unsigned long i, base_paddr, ctx;
-
- ret = (iommu->page_table_map_base +
- ((base - iommu->page_table) << PAGE_SHIFT));
- ret |= (oaddr & ~PAGE_MASK);
- base_paddr = __pa(oaddr & PAGE_MASK);
- ctx = 0;
- if (iommu->iommu_has_ctx_flush)
- ctx = iommu->iommu_cur_ctx++;
- for (i = 0; i < npages; i++, base++, base_paddr += PAGE_SIZE)
- iopte_val(*base) = IOPTE_CONSISTANT(ctx, base_paddr);
+ iopte = alloc_consistant_cluster(iommu, size >> PAGE_SHIFT);
+ if (iopte == NULL) {
+ spin_unlock_irqrestore(&iommu->lock, flags);
+ free_pages(first_page, order);
+ return NULL;
}
+
+ *dma_addrp = (iommu->page_table_map_base +
+ ((iopte - iommu->page_table) << PAGE_SHIFT));
+ ret = (void *) first_page;
+ npages = size >> PAGE_SHIFT;
+ ctx = 0;
+ if (iommu->iommu_ctxflush)
+ ctx = iommu->iommu_cur_ctx++;
+ first_page = __pa(first_page);
+ while (npages--) {
+ iopte_val(*iopte) = IOPTE_CONSISTANT(ctx, first_page);
+ iopte++;
+ first_page += PAGE_SIZE;
+ }
+
+ if (iommu->iommu_ctxflush) {
+ pci_iommu_write(iommu->iommu_ctxflush, ctx);
+ } else {
+ int i;
+ u32 daddr = *dma_addrp;
+
+ npages = size >> PAGE_SHIFT;
+ for (i = 0; i < npages; i++) {
+ pci_iommu_write(iommu->iommu_flush, daddr);
+ daddr += PAGE_SIZE;
+ }
+ }
+
spin_unlock_irqrestore(&iommu->lock, flags);
return ret;
}
-/* Unmap a consistant DMA translation. */
-void pci_unmap_consistant(struct pci_dev *pdev, u32 bus_addr, int sz)
+/* Free and unmap a consistant DMA translation. */
+void pci_free_consistant(struct pci_dev *pdev, long size, void *cpu, u32 dvma)
{
- struct pcidev_cookie *pcp = pdev->sysdata;
- struct pci_iommu *iommu = &pcp->pbm->parent->iommu;
- iopte_t *base;
- unsigned long flags, npages, i, ctx;
+ struct pcidev_cookie *pcp;
+ struct pci_iommu *iommu;
+ iopte_t *iopte;
+ unsigned long flags, order, npages, i;
+
+ if (size <= 0 || pdev == NULL ||
+ pdev->sysdata == NULL || cpu == NULL)
+ return;
+
+ npages = PAGE_ALIGN(size) >> PAGE_SHIFT;
+ pcp = pdev->sysdata;
+ iommu = &pcp->pbm->parent->iommu;
+ iopte = iommu->page_table +
+ ((dvma - iommu->page_table_map_base) >> PAGE_SHIFT);
spin_lock_irqsave(&iommu->lock, flags);
- npages = PAGE_ALIGN(bus_addr + sz) - (bus_addr & PAGE_MASK);
- npages >>= PAGE_SHIFT;
- base = iommu->page_table +
- ((bus_addr - iommu->page_table_map_base) >> PAGE_SHIFT);
/* Data for consistant mappings cannot enter the streaming
- * buffers, so we only need to update the TSB and flush
- * those entries from the IOMMU's TLB.
+ * buffers, so we only need to update the TSB. Flush of the
+ * IOTLB is done later when these ioptes are used for a new
+ * allocation.
*/
- /* Step 1: Clear out the TSB entries. Save away
- * the context if necessary.
- */
- ctx = 0;
- if (iommu->iommu_has_ctx_flush)
- ctx = (iopte_val(*base) & IOPTE_CONTEXT) >> 47UL;
- for (i = 0; i < npages; i++, base++)
- iopte_val(*base) = IOPTE_INVALID;
-
- /* Step 2: Flush from IOMMU TLB. */
- if (iommu->iommu_has_ctx_flush) {
- pci_iommu_write(iommu->iommu_ctxflush, ctx);
- } else {
- bus_addr &= PAGE_MASK;
- for (i = 0; i < npages; i++, bus_addr += PAGE_SIZE)
- pci_iommu_write(iommu->iommu_flush, bus_addr);
- }
-
- /* Step 3: Ensure completion of previous PIO writes. */
- (void) pci_iommu_read(iommu->write_complete_reg);
+ for (i = 0; i < npages; i++, iopte++)
+ iopte_val(*iopte) = IOPTE_INVALID;
spin_unlock_irqrestore(&iommu->lock, flags);
+
+ for (order = 0; order < 10; order++) {
+ if ((PAGE_SIZE << order) >= size)
+ break;
+ }
+ if (order < 10)
+ free_pages((unsigned long)cpu, order);
}
/* Map a single buffer at PTR of SZ bytes for PCI DMA
* in streaming mode.
*/
-u32 pci_map_single(struct pci_dev *pdev, void *ptr, int sz)
+u32 pci_map_single(struct pci_dev *pdev, void *ptr, long sz)
{
struct pcidev_cookie *pcp = pdev->sysdata;
struct pci_iommu *iommu = &pcp->pbm->parent->iommu;
+ struct pci_strbuf *strbuf = &pcp->pbm->stc;
iopte_t *base;
unsigned long flags, npages, oaddr;
- u32 ret;
+ unsigned long i, base_paddr, ctx;
+ u32 bus_addr, ret;
- spin_lock_irqsave(&iommu->lock, flags);
oaddr = (unsigned long)ptr;
npages = PAGE_ALIGN(oaddr + sz) - (oaddr & PAGE_MASK);
npages >>= PAGE_SHIFT;
- base = iommu_find_range(npages,
- iommu->page_table, iommu->page_table_sz);
- ret = 0;
- if (base != NULL) {
- unsigned long i, base_paddr, ctx;
-
- ret = (iommu->page_table_map_base +
- ((base - iommu->page_table) << PAGE_SHIFT));
- ret |= (oaddr & ~PAGE_MASK);
- base_paddr = __pa(oaddr & PAGE_MASK);
- ctx = 0;
- if (iommu->iommu_has_ctx_flush)
- ctx = iommu->iommu_cur_ctx++;
+
+ spin_lock_irqsave(&iommu->lock, flags);
+
+ base = alloc_streaming_cluster(iommu, npages);
+ bus_addr = (iommu->page_table_map_base +
+ ((base - iommu->page_table) << PAGE_SHIFT));
+ ret = bus_addr | (oaddr & ~PAGE_MASK);
+ base_paddr = __pa(oaddr & PAGE_MASK);
+ ctx = 0;
+ if (iommu->iommu_ctxflush)
+ ctx = iommu->iommu_cur_ctx++;
+ if (strbuf->strbuf_enabled) {
for (i = 0; i < npages; i++, base++, base_paddr += PAGE_SIZE)
iopte_val(*base) = IOPTE_STREAMING(ctx, base_paddr);
+ } else {
+ for (i = 0; i < npages; i++, base++, base_paddr += PAGE_SIZE)
+ iopte_val(*base) = IOPTE_CONSISTANT(ctx, base_paddr);
+ }
+
+ /* Flush the IOMMU TLB. */
+ if (iommu->iommu_ctxflush) {
+ pci_iommu_write(iommu->iommu_ctxflush, ctx);
+ } else {
+ for (i = 0; i < npages; i++, bus_addr += PAGE_SIZE)
+ pci_iommu_write(iommu->iommu_flush, bus_addr);
}
+
spin_unlock_irqrestore(&iommu->lock, flags);
return ret;
}
/* Unmap a single streaming mode DMA translation. */
-void pci_unmap_single(struct pci_dev *pdev, u32 bus_addr, int sz)
+void pci_unmap_single(struct pci_dev *pdev, u32 bus_addr, long sz)
{
struct pcidev_cookie *pcp = pdev->sysdata;
struct pci_iommu *iommu = &pcp->pbm->parent->iommu;
@@ -188,25 +278,26 @@ void pci_unmap_single(struct pci_dev *pdev, u32 bus_addr, int sz)
iopte_t *base;
unsigned long flags, npages, i, ctx;
- spin_lock_irqsave(&iommu->lock, flags);
npages = PAGE_ALIGN(bus_addr + sz) - (bus_addr & PAGE_MASK);
npages >>= PAGE_SHIFT;
base = iommu->page_table +
((bus_addr - iommu->page_table_map_base) >> PAGE_SHIFT);
bus_addr &= PAGE_MASK;
- /* Step 1: Record the context, if any. */
- ctx = 0;
- if (iommu->iommu_has_ctx_flush)
- ctx = (iopte_val(*base) & IOPTE_CONTEXT) >> 47UL;
+ spin_lock_irqsave(&iommu->lock, flags);
- /* Step 2: Kick data out of streaming buffers if necessary. */
+ /* Step 1: Kick data out of streaming buffers if necessary. */
if (strbuf->strbuf_enabled) {
u32 vaddr = bus_addr;
+ /* Record the context, if any. */
+ ctx = 0;
+ if (iommu->iommu_ctxflush)
+ ctx = (iopte_val(*base) & IOPTE_CONTEXT) >> 47UL;
+
PCI_STC_FLUSHFLAG_INIT(strbuf);
- if (strbuf->strbuf_has_ctx_flush &&
- iommu->iommu_has_ctx_flush) {
+ if (strbuf->strbuf_ctxflush &&
+ iommu->iommu_ctxflush) {
unsigned long matchreg, flushreg;
flushreg = strbuf->strbuf_ctxflush;
@@ -225,69 +316,159 @@ void pci_unmap_single(struct pci_dev *pdev, u32 bus_addr, int sz)
membar("#LoadLoad");
}
- /* Step 3: Clear out TSB entries. */
- for (i = 0; i < npages; i++, base++)
- iopte_val(*base) = IOPTE_INVALID;
+ /* Step 2: Clear out first TSB entry. */
+ iopte_val(*base) = IOPTE_INVALID;
- /* Step 4: Flush the IOMMU TLB. */
- if (iommu->iommu_has_ctx_flush) {
- pci_iommu_write(iommu->iommu_ctxflush, ctx);
- } else {
- for (i = 0; i < npages; i++, bus_addr += PAGE_SIZE)
- pci_iommu_write(iommu->iommu_flush, bus_addr);
- }
+ free_streaming_cluster(iommu, bus_addr - iommu->page_table_map_base, npages);
- /* Step 5: Ensure completion of previous PIO writes. */
+ /* Step 3: Ensure completion of previous PIO writes. */
(void) pci_iommu_read(iommu->write_complete_reg);
spin_unlock_irqrestore(&iommu->lock, flags);
}
+static inline struct scatterlist *fill_sg(iopte_t *iopte, struct scatterlist *sg, int nents, unsigned long ctx, int streaming)
+{
+ struct scatterlist *dma_sg = sg;
+
+ do {
+ unsigned long pteval = ~0UL;
+ u32 dma_npages;
+
+ dma_npages = ((dma_sg->dvma_address & (PAGE_SIZE - 1UL)) +
+ dma_sg->dvma_length +
+ ((u32)(PAGE_SIZE - 1UL))) >> PAGE_SHIFT;
+ do {
+ unsigned long offset;
+ signed int len;
+
+ /* If we are here, we know we have at least one
+ * more page to map. So walk forward until we
+ * hit a page crossing, and begin creating new
+ * mappings from that spot.
+ */
+ for (;;) {
+ unsigned long tmp;
+
+ tmp = (unsigned long) __pa(sg->address);
+ len = sg->length;
+ if (((tmp ^ pteval) >> PAGE_SHIFT) != 0UL) {
+ pteval = tmp & PAGE_MASK;
+ offset = tmp & (PAGE_SIZE - 1UL);
+ break;
+ }
+ if (((tmp ^ (tmp + len - 1UL)) >> PAGE_SHIFT) != 0UL) {
+ pteval = (tmp + PAGE_SIZE) & PAGE_MASK;
+ offset = 0UL;
+ len -= (PAGE_SIZE - (tmp & (PAGE_SIZE - 1UL)));
+ break;
+ }
+ sg++;
+ }
+
+ if (streaming)
+ pteval = IOPTE_STREAMING(ctx, pteval);
+ else
+ pteval = IOPTE_CONSISTANT(ctx, pteval);
+ while (len > 0) {
+ *iopte++ = __iopte(pteval);
+ pteval += PAGE_SIZE;
+ len -= (PAGE_SIZE - offset);
+ offset = 0;
+ dma_npages--;
+ }
+
+ pteval = (pteval & IOPTE_PAGE) + len;
+ sg++;
+
+ /* Skip over any tail mappings we've fully mapped,
+ * adjusting pteval along the way. Stop when we
+ * detect a page crossing event.
+ */
+ while ((pteval << (64 - PAGE_SHIFT)) != 0UL &&
+ pteval == __pa(sg->address) &&
+ ((pteval ^
+ (__pa(sg->address) + sg->length - 1UL)) >> PAGE_SHIFT) == 0UL) {
+ pteval += sg->length;
+ sg++;
+ }
+ if ((pteval << (64 - PAGE_SHIFT)) == 0UL)
+ pteval = ~0UL;
+ } while (dma_npages != 0);
+ dma_sg++;
+ } while (dma_sg->dvma_length != 0);
+ return dma_sg;
+}
+
/* Map a set of buffers described by SGLIST with NELEMS array
* elements in streaming mode for PCI DMA.
+ * When making changes here, inspect the assembly output. I was having
+ * hard time to kepp this routine out of using stack slots for holding variables.
*/
-void pci_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems)
+int pci_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems)
{
- struct pcidev_cookie *pcp = pdev->sysdata;
- struct pci_iommu *iommu = &pcp->pbm->parent->iommu;
- unsigned long flags, ctx, i;
+ struct pcidev_cookie *pcp;
+ struct pci_iommu *iommu;
+ struct pci_strbuf *strbuf;
+ unsigned long flags, ctx, i, npages;
+ iopte_t *base;
+ u32 dma_base;
+ struct scatterlist *sgtmp;
+ int tmp;
+
+ /* Fast path single entry scatterlists. */
+ if (nelems == 1) {
+ sglist->dvma_address = pci_map_single(pdev, sglist->address, sglist->length);
+ sglist->dvma_length = sglist->length;
+ return 1;
+ }
+
+ pcp = pdev->sysdata;
+ iommu = &pcp->pbm->parent->iommu;
+ strbuf = &pcp->pbm->stc;
+
+ /* Step 1: Prepare scatter list. */
+
+ npages = prepare_sg(sglist, nelems);
+
+ /* Step 2: Allocate a cluster. */
spin_lock_irqsave(&iommu->lock, flags);
- /* Step 1: Choose a context if necessary. */
+ base = alloc_streaming_cluster(iommu, npages);
+ dma_base = iommu->page_table_map_base + ((base - iommu->page_table) << PAGE_SHIFT);
+
+ /* Step 3: Normalize DMA addresses. */
+ tmp = nelems;
+
+ sgtmp = sglist;
+ while (tmp-- && sgtmp->dvma_length) {
+ sgtmp->dvma_address += dma_base;
+ sgtmp++;
+ }
+
+ /* Step 4: Choose a context if necessary. */
ctx = 0;
- if (iommu->iommu_has_ctx_flush)
+ if (iommu->iommu_ctxflush)
ctx = iommu->iommu_cur_ctx++;
- /* Step 2: Create the mappings. */
- for (i = 0; i < nelems; i++) {
- unsigned long oaddr, npages;
- iopte_t *base;
-
- oaddr = (unsigned long)sglist[i].address;
- npages = PAGE_ALIGN(oaddr + sglist[i].length) - (oaddr & PAGE_MASK);
- npages >>= PAGE_SHIFT;
- base = iommu_find_range(npages,
- iommu->page_table, iommu->page_table_sz);
- if (base != NULL) {
- unsigned long j, base_paddr;
- u32 dvma_addr;
-
- dvma_addr = (iommu->page_table_map_base +
- ((base - iommu->page_table) << PAGE_SHIFT));
- dvma_addr |= (oaddr & ~PAGE_MASK);
- sglist[i].dvma_address = dvma_addr;
- sglist[i].dvma_length = sglist[i].length;
- base_paddr = __pa(oaddr & PAGE_MASK);
- for (j = 0; j < npages; j++, base++, base_paddr += PAGE_SIZE)
- iopte_val(*base) = IOPTE_STREAMING(ctx, base_paddr);
- } else {
- sglist[i].dvma_address = 0;
- sglist[i].dvma_length = 0;
- }
+ /* Step 5: Create the mappings. */
+ sgtmp = fill_sg (base, sglist, nelems, ctx, strbuf->strbuf_enabled);
+#ifdef VERIFY_SG
+ verify_sglist(sglist, nelems, base, npages);
+#endif
+
+ /* Step 6: Flush the IOMMU TLB. */
+ if (iommu->iommu_ctxflush) {
+ pci_iommu_write(iommu->iommu_ctxflush, ctx);
+ } else {
+ for (i = 0; i < npages; i++, dma_base += PAGE_SIZE)
+ pci_iommu_write(iommu->iommu_flush, dma_base);
}
spin_unlock_irqrestore(&iommu->lock, flags);
+
+ return sgtmp - sglist;
}
/* Unmap a set of streaming mode DMA translations. */
@@ -296,25 +477,38 @@ void pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems)
struct pcidev_cookie *pcp = pdev->sysdata;
struct pci_iommu *iommu = &pcp->pbm->parent->iommu;
struct pci_strbuf *strbuf = &pcp->pbm->stc;
- unsigned long flags, ctx, i;
+ iopte_t *base;
+ unsigned long flags, ctx, i, npages;
+ u32 bus_addr;
+
+ bus_addr = sglist->dvma_address & PAGE_MASK;
+
+ i = 0;
+ if (nelems > 1) {
+ for (; i < nelems; i++)
+ if (sglist[i].dvma_length == 0)
+ break;
+ i--;
+ }
+ npages = (PAGE_ALIGN(sglist[i].dvma_address + sglist[i].dvma_length) - bus_addr) >> PAGE_SHIFT;
+
+ base = iommu->page_table +
+ ((bus_addr - iommu->page_table_map_base) >> PAGE_SHIFT);
spin_lock_irqsave(&iommu->lock, flags);
- /* Step 1: Record the context, if any. */
- ctx = 0;
- if (iommu->iommu_has_ctx_flush) {
- iopte_t *iopte;
+ /* Step 1: Kick data out of streaming buffers if necessary. */
+ if (strbuf->strbuf_enabled) {
+ u32 vaddr = bus_addr;
- iopte = iommu->page_table +
- ((sglist[0].dvma_address - iommu->page_table_map_base) >> PAGE_SHIFT);
- ctx = (iopte_val(*iopte) & IOPTE_CONTEXT) >> 47UL;
- }
+ /* Record the context, if any. */
+ ctx = 0;
+ if (iommu->iommu_ctxflush)
+ ctx = (iopte_val(*base) & IOPTE_CONTEXT) >> 47UL;
- /* Step 2: Kick data out of streaming buffers if necessary. */
- if (strbuf->strbuf_enabled) {
PCI_STC_FLUSHFLAG_INIT(strbuf);
- if (strbuf->strbuf_has_ctx_flush &&
- iommu->iommu_has_ctx_flush) {
+ if (strbuf->strbuf_ctxflush &&
+ iommu->iommu_ctxflush) {
unsigned long matchreg, flushreg;
flushreg = strbuf->strbuf_ctxflush;
@@ -323,66 +517,22 @@ void pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems)
pci_iommu_write(flushreg, ctx);
} while(((long)pci_iommu_read(matchreg)) < 0L);
} else {
- for (i = 0; i < nelems; i++) {
- unsigned long j, npages;
- u32 vaddr;
-
- j = sglist[i].dvma_length;
- if (!j)
- break;
- vaddr = sglist[i].dvma_address;
- npages = PAGE_ALIGN(vaddr + j) - (vaddr & PAGE_MASK);
- npages >>= PAGE_SHIFT;
- vaddr &= PAGE_MASK;
- for (j = 0; j < npages; j++, vaddr += PAGE_SIZE)
- pci_iommu_write(strbuf->strbuf_pflush, vaddr);
- }
-
- pci_iommu_write(strbuf->strbuf_fsync, strbuf->strbuf_flushflag_pa);
- (void) pci_iommu_read(iommu->write_complete_reg);
- while (!PCI_STC_FLUSHFLAG_SET(strbuf))
- membar("#LoadLoad");
+ for (i = 0; i < npages; i++, vaddr += PAGE_SIZE)
+ pci_iommu_write(strbuf->strbuf_pflush, vaddr);
}
- }
-
- /* Step 3: Clear out TSB entries. */
- for (i = 0; i < nelems; i++) {
- unsigned long j, npages;
- iopte_t *base;
- u32 vaddr;
- j = sglist[i].dvma_length;
- if (!j)
- break;
- vaddr = sglist[i].dvma_address;
- npages = PAGE_ALIGN(vaddr + j) - (vaddr & PAGE_MASK);
- npages >>= PAGE_SHIFT;
- base = iommu->page_table +
- ((vaddr - iommu->page_table_map_base) >> PAGE_SHIFT);
- for (j = 0; j < npages; j++, base++)
- iopte_val(*base) = IOPTE_INVALID;
+ pci_iommu_write(strbuf->strbuf_fsync, strbuf->strbuf_flushflag_pa);
+ (void) pci_iommu_read(iommu->write_complete_reg);
+ while (!PCI_STC_FLUSHFLAG_SET(strbuf))
+ membar("#LoadLoad");
}
- /* Step 4: Flush the IOMMU TLB. */
- if (iommu->iommu_has_ctx_flush) {
- pci_iommu_write(iommu->iommu_ctxflush, ctx);
- } else {
- for (i = 0; i < nelems; i++) {
- unsigned long j, npages;
- u32 vaddr;
+ /* Step 2: Clear out first TSB entry. */
+ iopte_val(*base) = IOPTE_INVALID;
- j = sglist[i].dvma_length;
- if (!j)
- break;
- vaddr = sglist[i].dvma_address;
- npages = PAGE_ALIGN(vaddr + j) - (vaddr & PAGE_MASK);
- npages >>= PAGE_SHIFT;
- for (j = 0; j < npages; j++, vaddr += PAGE_SIZE)
- pci_iommu_write(iommu->iommu_flush, vaddr);
- }
- }
+ free_streaming_cluster(iommu, bus_addr - iommu->page_table_map_base, npages);
- /* Step 5: Ensure completion of previous PIO writes. */
+ /* Step 3: Ensure completion of previous PIO writes. */
(void) pci_iommu_read(iommu->write_complete_reg);
spin_unlock_irqrestore(&iommu->lock, flags);
@@ -391,7 +541,7 @@ void pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems)
/* Make physical memory consistant for a single
* streaming mode DMA translation after a transfer.
*/
-void pci_dma_sync_single(struct pci_dev *pdev, u32 bus_addr, int sz)
+void pci_dma_sync_single(struct pci_dev *pdev, u32 bus_addr, long sz)
{
struct pcidev_cookie *pcp = pdev->sysdata;
struct pci_iommu *iommu = &pcp->pbm->parent->iommu;
@@ -409,8 +559,8 @@ void pci_dma_sync_single(struct pci_dev *pdev, u32 bus_addr, int sz)
/* Step 1: Record the context, if any. */
ctx = 0;
- if (iommu->iommu_has_ctx_flush &&
- strbuf->strbuf_has_ctx_flush) {
+ if (iommu->iommu_ctxflush &&
+ strbuf->strbuf_ctxflush) {
iopte_t *iopte;
iopte = iommu->page_table +
@@ -420,8 +570,8 @@ void pci_dma_sync_single(struct pci_dev *pdev, u32 bus_addr, int sz)
/* Step 2: Kick data out of streaming buffers. */
PCI_STC_FLUSHFLAG_INIT(strbuf);
- if (iommu->iommu_has_ctx_flush &&
- strbuf->strbuf_has_ctx_flush) {
+ if (iommu->iommu_ctxflush &&
+ strbuf->strbuf_ctxflush) {
unsigned long matchreg, flushreg;
flushreg = strbuf->strbuf_ctxflush;
@@ -462,8 +612,8 @@ void pci_dma_sync_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelem
/* Step 1: Record the context, if any. */
ctx = 0;
- if (iommu->iommu_has_ctx_flush &&
- strbuf->strbuf_has_ctx_flush) {
+ if (iommu->iommu_ctxflush &&
+ strbuf->strbuf_ctxflush) {
iopte_t *iopte;
iopte = iommu->page_table +
@@ -473,8 +623,8 @@ void pci_dma_sync_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelem
/* Step 2: Kick data out of streaming buffers. */
PCI_STC_FLUSHFLAG_INIT(strbuf);
- if (iommu->iommu_has_ctx_flush &&
- strbuf->strbuf_has_ctx_flush) {
+ if (iommu->iommu_ctxflush &&
+ strbuf->strbuf_ctxflush) {
unsigned long matchreg, flushreg;
flushreg = strbuf->strbuf_ctxflush;
@@ -483,21 +633,21 @@ void pci_dma_sync_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelem
pci_iommu_write(flushreg, ctx);
} while (((long)pci_iommu_read(matchreg)) < 0L);
} else {
- unsigned long i;
+ unsigned long i, npages;
+ u32 bus_addr;
- for(i = 0; i < nelems; i++) {
- unsigned long bus_addr, npages, j;
+ i = 0;
+ bus_addr = sglist[0].dvma_address & PAGE_MASK;
- j = sglist[i].dvma_length;
- if (!j)
- break;
- bus_addr = sglist[i].dvma_address;
- npages = PAGE_ALIGN(bus_addr + j) - (bus_addr & PAGE_MASK);
- npages >>= PAGE_SHIFT;
- bus_addr &= PAGE_MASK;
- for(j = 0; i < npages; i++, bus_addr += PAGE_SIZE)
- pci_iommu_write(strbuf->strbuf_pflush, bus_addr);
+ if (nelems > 1) {
+ for(; i < nelems; i++)
+ if (!sglist[i].dvma_length)
+ break;
+ i--;
}
+ npages = (PAGE_ALIGN(sglist[i].dvma_address + sglist[i].dvma_length) - bus_addr) >> PAGE_SHIFT;
+ for (i = 0; i < npages; i++, bus_addr += PAGE_SIZE)
+ pci_iommu_write(strbuf->strbuf_pflush, bus_addr);
}
/* Step 3: Perform flush synchronization sequence. */
diff --git a/arch/sparc64/kernel/pci_psycho.c b/arch/sparc64/kernel/pci_psycho.c
index 1afe5a67b..d66086bfa 100644
--- a/arch/sparc64/kernel/pci_psycho.c
+++ b/arch/sparc64/kernel/pci_psycho.c
@@ -1,9 +1,9 @@
-/* $Id: pci_psycho.c,v 1.4 1999/09/05 09:33:36 ecd Exp $
+/* $Id: pci_psycho.c,v 1.7 1999/12/17 12:31:57 jj Exp $
* pci_psycho.c: PSYCHO/U2P specific PCI controller support.
*
* Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu)
* Copyright (C) 1998, 1999 Eddie C. Dost (ecd@skynet.be)
- * Copyright (C) 1999 Jakub Jelinek (jj@ultra.linux.cz)
+ * Copyright (C) 1999 Jakub Jelinek (jakub@redhat.com)
*/
#include <linux/kernel.h>
@@ -380,7 +380,7 @@ static unsigned int __init psycho_irq_build(struct pci_controller_info *p,
unsigned int ino)
{
struct ino_bucket *bucket;
- volatile unsigned int *imap, *iclr;
+ unsigned long imap, iclr;
unsigned long imap_off, iclr_off;
int pil, inofixup = 0;
@@ -399,12 +399,12 @@ static unsigned int __init psycho_irq_build(struct pci_controller_info *p,
/* Now build the IRQ bucket. */
pil = psycho_ino_to_pil(pdev, ino);
- imap = (volatile unsigned int *)__va(p->controller_regs + imap_off);
- imap += 1;
+ imap = p->controller_regs + imap_off;
+ imap += 4;
iclr_off = psycho_iclr_offset(ino);
- iclr = (volatile unsigned int *)__va(p->controller_regs + iclr_off);
- iclr += 1;
+ iclr = p->controller_regs + iclr_off;
+ iclr += 4;
if ((ino & 0x20) == 0)
inofixup = ino & 0x03;
@@ -838,6 +838,10 @@ static void psycho_ce_intr(int irq, void *dev_id, struct pt_regs *regs)
"DMA Read" :
((error_bits & PSYCHO_CEAFSR_PDWR) ?
"DMA Write" : "???")))));
+
+ /* XXX Use syndrome and afar to print out module string just like
+ * XXX UDB CE trap handler does... -DaveM
+ */
printk("PSYCHO%d: syndrome[%02lx] bytemask[%04lx] dword_offset[%lx] "
"UPA_MID[%02lx] was_block(%d)\n",
p->index,
@@ -1213,26 +1217,28 @@ static void __init psycho_scan_bus(struct pci_controller_info *p)
psycho_register_error_handlers(p);
}
-static void __init psycho_iommu_init(struct pci_controller_info *p, int tsbsize)
+static void __init psycho_iommu_init(struct pci_controller_info *p)
{
- extern int this_is_starfire;
- extern void *starfire_hookup(int);
+#ifndef NEW_PCI_DMA_MAP
struct linux_mlist_p1275 *mlist;
- unsigned long tsbbase, i, n, order;
+ unsigned long n;
iopte_t *iopte;
+ int tsbsize = 32;
+#endif
+ extern int this_is_starfire;
+ extern void *starfire_hookup(int);
+ unsigned long tsbbase, i;
u64 control;
/* Setup initial software IOMMU state. */
spin_lock_init(&p->iommu.lock);
p->iommu.iommu_cur_ctx = 0;
- /* PSYCHO's IOMMU lacks ctx flushing. */
- p->iommu.iommu_has_ctx_flush = 0;
-
/* Register addresses. */
p->iommu.iommu_control = p->controller_regs + PSYCHO_IOMMU_CONTROL;
p->iommu.iommu_tsbbase = p->controller_regs + PSYCHO_IOMMU_TSBBASE;
p->iommu.iommu_flush = p->controller_regs + PSYCHO_IOMMU_FLUSH;
+ /* PSYCHO's IOMMU lacks ctx flushing. */
p->iommu.iommu_ctxflush = 0;
/* We use the main control register of PSYCHO as the write
@@ -1252,18 +1258,29 @@ static void __init psycho_iommu_init(struct pci_controller_info *p, int tsbsize)
control &= ~(PSYCHO_IOMMU_CTRL_DENAB);
psycho_write(p->controller_regs + PSYCHO_IOMMU_CONTROL, control);
- for(order = 0;; order++)
- if((PAGE_SIZE << order) >= ((tsbsize * 1024) * 8))
- break;
-
- tsbbase = __get_free_pages(GFP_DMA, order);
+#ifndef NEW_PCI_DMA_MAP
+ /* Using assumed page size 64K with 32K entries we need 256KB iommu page
+ * table (32K ioptes * 8 bytes per iopte). This is
+ * page order 5 on UltraSparc.
+ */
+ tsbbase = __get_free_pages(GFP_KERNEL, 5);
+#else
+ /* Using assumed page size 8K with 128K entries we need 1MB iommu page
+ * table (128K ioptes * 8 bytes per iopte). This is
+ * page order 7 on UltraSparc.
+ */
+ tsbbase = __get_free_pages(GFP_KERNEL, 7);
+#endif
if (!tsbbase) {
prom_printf("PSYCHO_IOMMU: Error, gfp(tsb) failed.\n");
prom_halt();
}
- p->iommu.page_table = iopte = (iopte_t *)tsbbase;
- p->iommu.page_table_sz = (tsbsize * 1024);
+ p->iommu.page_table = (iopte_t *)tsbbase;
+ p->iommu.page_table_sz_bits = 17;
+ p->iommu.page_table_map_base = 0xc0000000;
+#ifndef NEW_PCI_DMA_MAP
+ iopte = (iopte_t *)tsbbase;
/* Initialize to "none" settings. */
for(i = 0; i < PCI_DVMA_HASHSZ; i++) {
pci_dvma_v2p_hash[i] = PCI_DVMA_HASH_NONE;
@@ -1329,10 +1346,11 @@ out:
prom_printf("Try booting with mem=xxxM or similar\n");
prom_halt();
}
-
+#endif
psycho_write(p->controller_regs + PSYCHO_IOMMU_TSBBASE, __pa(tsbbase));
control = psycho_read(p->controller_regs + PSYCHO_IOMMU_CONTROL);
+#ifndef NEW_PCI_DMA_MAP
control &= ~(PSYCHO_IOMMU_CTRL_TSBSZ);
control |= (PSYCHO_IOMMU_CTRL_TBWSZ | PSYCHO_IOMMU_CTRL_ENAB);
switch(tsbsize) {
@@ -1353,6 +1371,10 @@ out:
prom_halt();
break;
}
+#else
+ control &= ~(PSYCHO_IOMMU_CTRL_TSBSZ | PSYCHO_IOMMU_CTRL_TBWSZ);
+ control |= (PSYCHO_IOMMU_TSBSZ_128K | PSYCHO_IOMMU_CTRL_ENAB);
+#endif
psycho_write(p->controller_regs + PSYCHO_IOMMU_CONTROL, control);
/* If necessary, hook us up for starfire IRQ translations. */
@@ -1426,9 +1448,6 @@ static void psycho_pbm_strbuf_init(struct pci_controller_info *p,
/* Currently we don't even use it. */
pbm->stc.strbuf_enabled = 0;
- /* PSYCHO's streaming buffer lacks ctx flushing. */
- pbm->stc.strbuf_has_ctx_flush = 0;
-
if (is_pbm_a) {
pbm->stc.strbuf_control = base + PSYCHO_STRBUF_CONTROL_A;
pbm->stc.strbuf_pflush = base + PSYCHO_STRBUF_FLUSH_A;
@@ -1438,6 +1457,7 @@ static void psycho_pbm_strbuf_init(struct pci_controller_info *p,
pbm->stc.strbuf_pflush = base + PSYCHO_STRBUF_FLUSH_B;
pbm->stc.strbuf_fsync = base + PSYCHO_STRBUF_FSYNC_B;
}
+ /* PSYCHO's streaming buffer lacks ctx flushing. */
pbm->stc.strbuf_ctxflush = 0;
pbm->stc.strbuf_ctxmatch_base = 0;
@@ -1599,7 +1619,7 @@ void __init psycho_init(int node)
psycho_controller_hwinit(p);
- psycho_iommu_init(p, 32);
+ psycho_iommu_init(p);
is_pbm_a = ((pr_regs[0].phys_addr & 0x6000) == 0x2000);
psycho_pbm_init(p, node, is_pbm_a);
diff --git a/arch/sparc64/kernel/pci_sabre.c b/arch/sparc64/kernel/pci_sabre.c
index 46a9b31cf..3788f71d3 100644
--- a/arch/sparc64/kernel/pci_sabre.c
+++ b/arch/sparc64/kernel/pci_sabre.c
@@ -1,9 +1,9 @@
-/* $Id: pci_sabre.c,v 1.2 1999/09/05 04:58:06 davem Exp $
+/* $Id: pci_sabre.c,v 1.8 2000/01/06 23:51:49 davem Exp $
* pci_sabre.c: Sabre specific PCI controller support.
*
* Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu)
* Copyright (C) 1998, 1999 Eddie C. Dost (ecd@skynet.be)
- * Copyright (C) 1999 Jakub Jelinek (jj@ultra.linux.cz)
+ * Copyright (C) 1999 Jakub Jelinek (jakub@redhat.com)
*/
#include <linux/kernel.h>
@@ -65,6 +65,14 @@
#define SABRE_IOMMUCTRL_LCKEN 0x0000000000800000UL /* IOTLB lock enable */
#define SABRE_IOMMUCTRL_LCKPTR 0x0000000000780000UL /* IOTLB lock pointer */
#define SABRE_IOMMUCTRL_TSBSZ 0x0000000000070000UL /* TSB Size */
+#define SABRE_IOMMU_TSBSZ_1K 0x0000000000000000
+#define SABRE_IOMMU_TSBSZ_2K 0x0000000000010000
+#define SABRE_IOMMU_TSBSZ_4K 0x0000000000020000
+#define SABRE_IOMMU_TSBSZ_8K 0x0000000000030000
+#define SABRE_IOMMU_TSBSZ_16K 0x0000000000040000
+#define SABRE_IOMMU_TSBSZ_32K 0x0000000000050000
+#define SABRE_IOMMU_TSBSZ_64K 0x0000000000060000
+#define SABRE_IOMMU_TSBSZ_128K 0x0000000000070000
#define SABRE_IOMMUCTRL_TBWSZ 0x0000000000000004UL /* TSB assumed page size */
#define SABRE_IOMMUCTRL_DENAB 0x0000000000000002UL /* Diagnostic Mode Enable */
#define SABRE_IOMMUCTRL_ENAB 0x0000000000000001UL /* IOMMU Enable */
@@ -601,7 +609,7 @@ static unsigned int __init sabre_irq_build(struct pci_controller_info *p,
unsigned int ino)
{
struct ino_bucket *bucket;
- volatile unsigned int *imap, *iclr;
+ unsigned long imap, iclr;
unsigned long imap_off, iclr_off;
int pil, inofixup = 0;
@@ -620,12 +628,12 @@ static unsigned int __init sabre_irq_build(struct pci_controller_info *p,
/* Now build the IRQ bucket. */
pil = sabre_ino_to_pil(pdev, ino);
- imap = (volatile unsigned int *)__va(p->controller_regs + imap_off);
- imap += 1;
+ imap = p->controller_regs + imap_off;
+ imap += 4;
iclr_off = sabre_iclr_offset(ino);
- iclr = (volatile unsigned int *)__va(p->controller_regs + iclr_off);
- iclr += 1;
+ iclr = p->controller_regs + iclr_off;
+ iclr += 4;
if ((ino & 0x20) == 0)
inofixup = ino & 0x03;
@@ -717,13 +725,13 @@ static void sabre_check_iommu_error(struct pci_controller_info *p,
type_string = "Unknown";
break;
};
- printk("SABRE%d: IOMMU TAG(%d)[error(%s)wr(%d)sz(%dK)vpg(%08lx)]\n",
- p->index, i, type_string,
+ printk("SABRE%d: IOMMU TAG(%d)[RAW(%016lx)error(%s)wr(%d)sz(%dK)vpg(%08lx)]\n",
+ p->index, i, tag, type_string,
((tag & SABRE_IOMMUTAG_WRITE) ? 1 : 0),
((tag & SABRE_IOMMUTAG_SIZE) ? 64 : 8),
((tag & SABRE_IOMMUTAG_VPN) << PAGE_SHIFT));
- printk("SABRE%d: IOMMU DATA(%d)[valid(%d)used(%d)cache(%d)ppg(%016lx)\n",
- p->index, i,
+ printk("SABRE%d: IOMMU DATA(%d)[RAW(%016lx)valid(%d)used(%d)cache(%d)ppg(%016lx)\n",
+ p->index, i, data,
((data & SABRE_IOMMUDATA_VALID) ? 1 : 0),
((data & SABRE_IOMMUDATA_USED) ? 1 : 0),
((data & SABRE_IOMMUDATA_CACHE) ? 1 : 0),
@@ -814,6 +822,10 @@ static void sabre_ce_intr(int irq, void *dev_id, struct pt_regs *regs)
"DMA Read" :
((error_bits & SABRE_CEAFSR_PDWR) ?
"DMA Write" : "???")));
+
+ /* XXX Use syndrome and afar to print out module string just like
+ * XXX UDB CE trap handler does... -DaveM
+ */
printk("SABRE%d: syndrome[%02lx] bytemask[%04lx] dword_offset[%lx] "
"was_block(%d)\n",
p->index,
@@ -1020,21 +1032,15 @@ static void __init sabre_base_address_update(struct pci_dev *pdev, int resource)
static void __init apb_init(struct pci_controller_info *p, struct pci_bus *sabre_bus)
{
- struct pci_dev *pdev;
- u32 dword;
- u16 word;
-
- for(pdev = pci_devices; pdev; pdev = pdev->next) {
- if(pdev->vendor == PCI_VENDOR_ID_SUN &&
- pdev->device == PCI_DEVICE_ID_SUN_SABRE) {
- sabre_write_byte(pdev, PCI_LATENCY_TIMER, 64);
- break;
- }
- }
+ struct list_head *walk = &sabre_bus->devices;
+
+ for (walk = walk->next; walk != &sabre_bus->devices; walk = walk->next) {
+ struct pci_dev *pdev = pci_dev_b(walk);
- for (pdev = sabre_bus->devices; pdev; pdev = pdev->sibling) {
if (pdev->vendor == PCI_VENDOR_ID_SUN &&
pdev->device == PCI_DEVICE_ID_SUN_SIMBA) {
+ u16 word;
+
sabre_read_word(pdev, PCI_COMMAND, &word);
word |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY |
PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY |
@@ -1044,32 +1050,6 @@ static void __init apb_init(struct pci_controller_info *p, struct pci_bus *sabre
/* Status register bits are "write 1 to clear". */
sabre_write_word(pdev, PCI_STATUS, 0xffff);
sabre_write_word(pdev, PCI_SEC_STATUS, 0xffff);
-
- sabre_read_word(pdev, PCI_BRIDGE_CONTROL, &word);
- word = PCI_BRIDGE_CTL_MASTER_ABORT |
- PCI_BRIDGE_CTL_SERR |
- PCI_BRIDGE_CTL_PARITY;
- sabre_write_word(pdev, PCI_BRIDGE_CONTROL, word);
-
- sabre_read_dword(pdev, APB_PCI_CONTROL_HIGH, &dword);
- dword = APB_PCI_CTL_HIGH_SERR |
- APB_PCI_CTL_HIGH_ARBITER_EN;
- sabre_write_dword(pdev, APB_PCI_CONTROL_HIGH, dword);
-
- /* Systems with SIMBA are usually workstations, so
- * we configure to park to SIMBA not to the previous
- * bus owner.
- */
- sabre_read_dword(pdev, APB_PCI_CONTROL_LOW, &dword);
- dword = APB_PCI_CTL_LOW_ERRINT_EN | 0x0f;
- sabre_write_dword(pdev, APB_PCI_CONTROL_LOW, dword);
-
- /* Don't mess with the retry limit and PIO/DMA latency
- * timer settings. But do set primary and secondary
- * latency timers.
- */
- sabre_write_byte(pdev, PCI_LATENCY_TIMER, 64);
- sabre_write_byte(pdev, PCI_SEC_LATENCY_TIMER, 64);
}
}
}
@@ -1077,7 +1057,8 @@ static void __init apb_init(struct pci_controller_info *p, struct pci_bus *sabre
static void __init sabre_scan_bus(struct pci_controller_info *p)
{
static int once = 0;
- struct pci_bus *sabre_bus, *pbus;
+ struct pci_bus *sabre_bus;
+ struct list_head *walk;
/* Unlike for PSYCHO, we can only have one SABRE
* in a system. Having multiple SABREs is thus
@@ -1100,7 +1081,9 @@ static void __init sabre_scan_bus(struct pci_controller_info *p)
&p->pbm_A);
apb_init(p, sabre_bus);
- for (pbus = sabre_bus->children; pbus; pbus = pbus->next) {
+ walk = &sabre_bus->children;
+ for (walk = walk->next; walk != &sabre_bus->children; walk = walk->next) {
+ struct pci_bus *pbus = pci_bus_b(walk);
struct pci_pbm_info *pbm;
if (pbus->number == p->pbm_A.pci_first_busno) {
@@ -1124,30 +1107,49 @@ static void __init sabre_scan_bus(struct pci_controller_info *p)
static void __init sabre_iommu_init(struct pci_controller_info *p,
int tsbsize, unsigned long dvma_offset)
{
+#ifndef NEW_PCI_DMA_MAP
struct linux_mlist_p1275 *mlist;
- unsigned long tsbbase, i, n, order;
+ unsigned long n;
iopte_t *iopte;
+#endif
+ unsigned long tsbbase, i, order;
u64 control;
+ /* Setup initial software IOMMU state. */
+ spin_lock_init(&p->iommu.lock);
+ p->iommu.iommu_cur_ctx = 0;
+
+ /* Register addresses. */
+ p->iommu.iommu_control = p->controller_regs + SABRE_IOMMU_CONTROL;
+ p->iommu.iommu_tsbbase = p->controller_regs + SABRE_IOMMU_TSBBASE;
+ p->iommu.iommu_flush = p->controller_regs + SABRE_IOMMU_FLUSH;
+ p->iommu.write_complete_reg = p->controller_regs + SABRE_WRSYNC;
+ /* Sabre's IOMMU lacks ctx flushing. */
+ p->iommu.iommu_ctxflush = 0;
+
/* Invalidate TLB Entries. */
control = sabre_read(p->controller_regs + SABRE_IOMMU_CONTROL);
- control |= IOMMU_CTRL_DENAB;
+ control |= SABRE_IOMMUCTRL_DENAB;
sabre_write(p->controller_regs + SABRE_IOMMU_CONTROL, control);
for(i = 0; i < 16; i++)
sabre_write(p->controller_regs + SABRE_IOMMU_DATA + (i * 8UL), 0);
- control &= ~(IOMMU_CTRL_DENAB);
+ control &= ~(SABRE_IOMMUCTRL_DENAB);
sabre_write(p->controller_regs + SABRE_IOMMU_CONTROL, control);
for(order = 0;; order++)
if((PAGE_SIZE << order) >= ((tsbsize * 1024) * 8))
break;
- tsbbase = __get_free_pages(GFP_DMA, order);
+ tsbbase = __get_free_pages(GFP_KERNEL, order);
if (!tsbbase) {
prom_printf("SABRE_IOMMU: Error, gfp(tsb) failed.\n");
prom_halt();
}
+ p->iommu.page_table = (iopte_t *)tsbbase;
+ p->iommu.page_table_map_base = dvma_offset;
+
+#ifndef NEW_PCI_DMA_MAP
iopte = (iopte_t *)tsbbase;
/* Initialize to "none" settings. */
@@ -1216,27 +1218,47 @@ out:
prom_printf("Try booting with mem=xxxM or similar\n");
prom_halt();
}
+#endif
sabre_write(p->controller_regs + SABRE_IOMMU_TSBBASE, __pa(tsbbase));
control = sabre_read(p->controller_regs + SABRE_IOMMU_CONTROL);
- control &= ~(IOMMU_CTRL_TSBSZ);
- control |= (IOMMU_CTRL_TBWSZ | IOMMU_CTRL_ENAB);
+#ifndef NEW_PCI_DMA_MAP
+ control &= ~(SABRE_IOMMUCTRL_TSBSZ);
+ control |= (SABRE_IOMMUCTRL_TBWSZ | SABRE_IOMMUCTRL_ENAB);
switch(tsbsize) {
case 8:
- control |= IOMMU_TSBSZ_8K;
+ control |= SABRE_IOMMU_TSBSZ_8K;
break;
case 16:
- control |= IOMMU_TSBSZ_16K;
+ control |= SABRE_IOMMU_TSBSZ_16K;
break;
case 32:
- control |= IOMMU_TSBSZ_32K;
+ control |= SABRE_IOMMU_TSBSZ_32K;
+ break;
+ default:
+ prom_printf("iommu_init: Illegal TSB size %d\n", tsbsize);
+ prom_halt();
+ break;
+ }
+#else
+ control &= ~(SABRE_IOMMUCTRL_TSBSZ | SABRE_IOMMUCTRL_TBWSZ);
+ control |= SABRE_IOMMUCTRL_ENAB;
+ switch(tsbsize) {
+ case 64:
+ control |= SABRE_IOMMU_TSBSZ_64K;
+ p->iommu.page_table_sz_bits = 16;
+ break;
+ case 128:
+ control |= SABRE_IOMMU_TSBSZ_128K;
+ p->iommu.page_table_sz_bits = 17;
break;
default:
prom_printf("iommu_init: Illegal TSB size %d\n", tsbsize);
prom_halt();
break;
}
+#endif
sabre_write(p->controller_regs + SABRE_IOMMU_CONTROL, control);
}
@@ -1445,6 +1467,7 @@ void __init sabre_init(int pnode)
}
switch(vdma[1]) {
+#ifndef NEW_PCI_DMA_MAP
case 0x20000000:
tsbsize = 8;
break;
@@ -1454,6 +1477,15 @@ void __init sabre_init(int pnode)
case 0x80000000:
tsbsize = 32;
break;
+#else
+ case 0x20000000:
+ tsbsize = 64;
+ break;
+ case 0x40000000:
+ case 0x80000000:
+ tsbsize = 128;
+ break;
+#endif
default:
prom_printf("SABRE: strange virtual-dma size.\n");
prom_halt();
diff --git a/arch/sparc64/kernel/power.c b/arch/sparc64/kernel/power.c
index 831011128..e612d0200 100644
--- a/arch/sparc64/kernel/power.c
+++ b/arch/sparc64/kernel/power.c
@@ -1,4 +1,4 @@
-/* $Id: power.c,v 1.4 1999/08/31 18:22:05 davem Exp $
+/* $Id: power.c,v 1.5 1999/12/19 23:28:00 davem Exp $
* power.c: Power management driver.
*
* Copyright (C) 1999 David S. Miller (davem@redhat.com)
@@ -90,16 +90,18 @@ void __init power_init(void)
return;
found:
- power_reg = edev->resource[0].start;
+ power_reg = (unsigned long)ioremap(edev->resource[0].start, 0x4);
printk("power: Control reg at %016lx ... ", power_reg);
if (kernel_thread(powerd, 0, CLONE_FS) < 0) {
printk("Failed to start power daemon.\n");
return;
}
printk("powerd running.\n");
- if (request_irq(edev->irqs[0],
- power_handler, SA_SHIRQ, "power",
- (void *) power_reg) < 0)
- printk("power: Error, cannot register IRQ handler.\n");
+ if (edev->irqs[0] != 0) {
+ if (request_irq(edev->irqs[0],
+ power_handler, SA_SHIRQ, "power",
+ (void *) power_reg) < 0)
+ printk("power: Error, cannot register IRQ handler.\n");
+ }
}
#endif /* CONFIG_PCI */
diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c
index 20a5534cb..922e74d2e 100644
--- a/arch/sparc64/kernel/process.c
+++ b/arch/sparc64/kernel/process.c
@@ -1,4 +1,4 @@
-/* $Id: process.c,v 1.100 1999/08/31 04:39:39 davem Exp $
+/* $Id: process.c,v 1.102 1999/12/15 22:24:49 davem Exp $
* arch/sparc64/kernel/process.c
*
* Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -33,6 +33,7 @@
#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/page.h>
+#include <asm/pgalloc.h>
#include <asm/pgtable.h>
#include <asm/processor.h>
#include <asm/pstate.h>
@@ -268,7 +269,7 @@ void __show_regs(struct pt_regs * regs)
unsigned long flags;
spin_lock_irqsave(&regdump_lock, flags);
- printk("CPU[%d]: local_irq_count[%ld] global_irq_count[%d]\n",
+ printk("CPU[%d]: local_irq_count[%u] global_irq_count[%d]\n",
smp_processor_id(), local_irq_count,
atomic_read(&global_irq_count));
#endif
@@ -802,35 +803,3 @@ out:
unlock_kernel();
return error;
}
-
-/*
- * These bracket the sleeping functions..
- */
-extern void scheduling_functions_start_here(void);
-extern void scheduling_functions_end_here(void);
-#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 pc, fp, bias = 0;
- unsigned long task_base = (unsigned long) p;
- struct reg_window *rw;
- int count = 0;
- if (!p || p == current || p->state == TASK_RUNNING)
- return 0;
- bias = STACK_BIAS;
- fp = p->thread.ksp + bias;
- do {
- /* Bogus frame pointer? */
- if (fp < (task_base + sizeof(struct task_struct)) ||
- fp >= (task_base + (2 * PAGE_SIZE)))
- break;
- rw = (struct reg_window *) fp;
- pc = rw->ins[7];
- if (pc < first_sched || pc >= last_sched)
- return pc;
- fp = rw->ins[6] + bias;
- } while (++count < 16);
- return 0;
-}
diff --git a/arch/sparc64/kernel/sbus.c b/arch/sparc64/kernel/sbus.c
new file mode 100644
index 000000000..9e24c7bb3
--- /dev/null
+++ b/arch/sparc64/kernel/sbus.c
@@ -0,0 +1,1145 @@
+/* $Id: sbus.c,v 1.6 1999/12/20 14:08:17 jj Exp $
+ * sbus.c: UltraSparc SBUS controller support.
+ *
+ * Copyright (C) 1999 David S. Miller (davem@redhat.com)
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/spinlock.h>
+#include <linux/malloc.h>
+#include <linux/init.h>
+
+#include <asm/page.h>
+#include <asm/sbus.h>
+#include <asm/io.h>
+#include <asm/upa.h>
+#include <asm/cache.h>
+#include <asm/dma.h>
+#include <asm/irq.h>
+
+#include "iommu_common.h"
+
+/* These should be allocated on an SMP_CACHE_BYTES
+ * aligned boundry for optimal performance.
+ *
+ * On SYSIO, using an 8K page size we have 1GB of SBUS
+ * DMA space mapped. We divide this space into equally
+ * sized clusters. Currently we allow clusters up to a
+ * size of 1MB. If anything begins to generate DMA
+ * mapping requests larger than this we will need to
+ * increase things a bit.
+ */
+
+#define NCLUSTERS 8UL
+#define ONE_GIG (1UL * 1024UL * 1024UL * 1024UL)
+#define CLUSTER_SIZE (ONE_GIG / NCLUSTERS)
+#define CLUSTER_MASK (CLUSTER_SIZE - 1)
+#define CLUSTER_NPAGES (CLUSTER_SIZE >> PAGE_SHIFT)
+#define MAP_BASE ((u32)0xc0000000)
+
+struct sbus_iommu {
+/*0x00*/spinlock_t lock;
+
+/*0x08*/iopte_t *page_table;
+/*0x10*/unsigned long strbuf_regs;
+/*0x18*/unsigned long iommu_regs;
+/*0x20*/unsigned long sbus_control_reg;
+
+/*0x28*/volatile unsigned long strbuf_flushflag;
+
+ /* If NCLUSTERS is ever decresed to 4 or lower,
+ * you must increase the size of the type of
+ * these counters. You have been duly warned. -DaveM
+ */
+/*0x30*/u16 lowest_free[NCLUSTERS];
+};
+
+/* Flushing heuristics */
+#define IOMMU_DIAG_LIM 16
+#define STRBUF_DIAG_LIM 32
+
+/* Offsets from iommu_regs */
+#define SYSIO_IOMMUREG_BASE 0x2400UL
+#define IOMMU_CONTROL (0x2400UL - 0x2400UL) /* IOMMU control register */
+#define IOMMU_TSBBASE (0x2408UL - 0x2400UL) /* TSB base address register */
+#define IOMMU_FLUSH (0x2410UL - 0x2400UL) /* IOMMU flush register */
+#define IOMMU_VADIAG (0x4400UL - 0x2400UL) /* SBUS virtual address diagnostic */
+#define IOMMU_TAGCMP (0x4408UL - 0x2400UL) /* TLB tag compare diagnostics */
+#define IOMMU_LRUDIAG (0x4500UL - 0x2400UL) /* IOMMU LRU queue diagnostics */
+#define IOMMU_TAGDIAG (0x4580UL - 0x2400UL) /* TLB tag diagnostics */
+#define IOMMU_DRAMDIAG (0x4600UL - 0x2400UL) /* TLB data RAM diagnostics */
+
+#define IOMMU_DRAM_VALID (1UL << 30UL)
+
+static void __iommu_flush(struct sbus_iommu *iommu, u32 base, unsigned long npages)
+{
+ int hit = 0;
+
+ if (npages <= IOMMU_DIAG_LIM) {
+ while (npages--)
+ upa_writeq(base + (npages << PAGE_SHIFT),
+ iommu->iommu_regs + IOMMU_FLUSH);
+ hit = 1;
+ } else {
+ u32 limit = base + ((npages << PAGE_SHIFT) - 1UL);
+ unsigned long dram = iommu->iommu_regs + IOMMU_DRAMDIAG;
+ unsigned long tag = iommu->iommu_regs + IOMMU_TAGDIAG;
+ int entry;
+
+ for (entry = 0; entry < 16; entry++, dram += 8, tag += 8) {
+ u32 addr = ((u32)upa_readq(tag) << PAGE_SHIFT);
+ if (addr >= base && addr <= limit) {
+ u64 val = upa_readq(dram);
+
+ if (val & IOMMU_DRAM_VALID) {
+ upa_writeq(addr,
+ iommu->iommu_regs + IOMMU_FLUSH);
+ hit = 1;
+ }
+ }
+ }
+ }
+ if (hit != 0)
+ upa_readq(iommu->sbus_control_reg);
+}
+
+/* In an effort to keep latency under control, we special
+ * case single page IOMMU flushes.
+ */
+static __inline__ void iommu_flush(struct sbus_iommu *iommu,
+ u32 base, unsigned long npages)
+{
+ if (npages == 1) {
+ upa_writeq(base, iommu->iommu_regs + IOMMU_FLUSH);
+ upa_readq(iommu->sbus_control_reg);
+ } else
+ __iommu_flush(iommu, base, npages);
+}
+
+/* Offsets from strbuf_regs */
+#define SYSIO_STRBUFREG_BASE 0x2800UL
+#define STRBUF_CONTROL (0x2800UL - 0x2800UL) /* Control */
+#define STRBUF_PFLUSH (0x2808UL - 0x2800UL) /* Page flush/invalidate */
+#define STRBUF_FSYNC (0x2810UL - 0x2800UL) /* Flush synchronization */
+#define STRBUF_DRAMDIAG (0x5000UL - 0x2800UL) /* data RAM diagnostic */
+#define STRBUF_ERRDIAG (0x5400UL - 0x2800UL) /* error status diagnostics */
+#define STRBUF_PTAGDIAG (0x5800UL - 0x2800UL) /* Page tag diagnostics */
+#define STRBUF_LTAGDIAG (0x5900UL - 0x2800UL) /* Line tag diagnostics */
+
+#define STRBUF_TAG_VALID 0x02UL
+
+static void strbuf_flush(struct sbus_iommu *iommu, u32 base, unsigned long npages)
+{
+ int hit = 0;
+
+ iommu->strbuf_flushflag = 0UL;
+ if (npages <= STRBUF_DIAG_LIM) {
+ while (npages--)
+ upa_writeq(base + (npages << PAGE_SHIFT),
+ iommu->strbuf_regs + STRBUF_PFLUSH);
+ hit = 1;
+ } else {
+ u32 limit = base + ((npages << PAGE_SHIFT) - 1UL);
+ unsigned long tag = iommu->strbuf_regs + STRBUF_PTAGDIAG;
+ int entry;
+
+ for (entry = 0; entry < 16; entry++, tag += 8) {
+ u64 val = upa_readq(tag);
+
+ if (val & STRBUF_TAG_VALID) {
+ u32 addr = ((u32)(val & ~3UL)) << (PAGE_SHIFT - 2UL);
+ if (addr >= base && addr <= limit) {
+ upa_writeq(addr,
+ iommu->strbuf_regs + STRBUF_PFLUSH);
+ hit = 1;
+ }
+ }
+ }
+ }
+ if (hit != 0) {
+ /* Whoopee cushion! */
+ upa_writeq(__pa(&iommu->strbuf_flushflag),
+ iommu->strbuf_regs + STRBUF_FSYNC);
+ upa_readq(iommu->sbus_control_reg);
+ while (iommu->strbuf_flushflag == 0UL)
+ membar("#LoadLoad");
+ }
+}
+
+static iopte_t *alloc_streaming_cluster(struct sbus_iommu *iommu, unsigned long npages)
+{
+ iopte_t *iopte;
+ unsigned long cnum, ent;
+
+ cnum = 0;
+ while ((1UL << cnum) < npages)
+ cnum++;
+ iopte = iommu->page_table + (cnum * CLUSTER_NPAGES);
+ iopte += ((ent = iommu->lowest_free[cnum]) << cnum);
+
+ if (iopte_val(iopte[(1UL << cnum)]) == 0UL) {
+ /* Fast path. */
+ iommu->lowest_free[cnum] = ent + 1;
+ } else {
+ unsigned long pte_off = 1;
+
+ ent += 1;
+ do {
+ pte_off++;
+ ent++;
+ } while (iopte_val(iopte[(pte_off << cnum)]) != 0UL);
+ iommu->lowest_free[cnum] = ent;
+ }
+
+ /* I've got your streaming cluster right here buddy boy... */
+ return iopte;
+}
+
+static void free_streaming_cluster(struct sbus_iommu *iommu, u32 base, unsigned long npages)
+{
+ unsigned long cnum, ent;
+ iopte_t *iopte;
+
+ cnum = 0;
+ while ((1UL << cnum) < npages)
+ cnum++;
+ ent = (base & CLUSTER_MASK) >> (PAGE_SHIFT + cnum);
+ iopte = iommu->page_table + ((base - MAP_BASE) >> PAGE_SHIFT);
+ iopte_val(*iopte) = 0UL;
+ if (ent < iommu->lowest_free[cnum])
+ iommu->lowest_free[cnum] = ent;
+}
+
+/* We allocate consistant mappings from the end of cluster zero. */
+static iopte_t *alloc_consistant_cluster(struct sbus_iommu *iommu, unsigned long npages)
+{
+ iopte_t *iopte;
+
+ iopte = iommu->page_table + (1 * CLUSTER_NPAGES);
+ while (iopte > iommu->page_table) {
+ iopte--;
+ if (!(iopte_val(*iopte) & IOPTE_VALID)) {
+ unsigned long tmp = npages;
+
+ while (--tmp) {
+ iopte--;
+ if (iopte_val(*iopte) & IOPTE_VALID)
+ break;
+ }
+ if (tmp == 0)
+ return iopte;
+ }
+ }
+ return NULL;
+}
+
+static void free_consistant_cluster(struct sbus_iommu *iommu, u32 base, unsigned long npages)
+{
+ iopte_t *iopte = iommu->page_table + ((base - MAP_BASE) >> PAGE_SHIFT);
+
+ while (npages--)
+ *iopte++ = __iopte(0UL);
+}
+
+void *sbus_alloc_consistant(struct sbus_dev *sdev, long size, u32 *dvma_addr)
+{
+ unsigned long order, first_page, flags;
+ struct sbus_iommu *iommu;
+ iopte_t *iopte;
+ void *ret;
+ int npages;
+
+ if (size <= 0 || sdev == NULL || dvma_addr == NULL)
+ return NULL;
+
+ size = PAGE_ALIGN(size);
+ for (order = 0; order < 10; order++) {
+ if ((PAGE_SIZE << order) >= size)
+ break;
+ }
+ if (order == 10)
+ return NULL;
+ first_page = __get_free_pages(GFP_KERNEL, order);
+ if (first_page == 0UL)
+ return NULL;
+ memset((char *)first_page, 0, PAGE_SIZE << order);
+
+ iommu = sdev->bus->iommu;
+
+ spin_lock_irqsave(&iommu->lock, flags);
+ iopte = alloc_consistant_cluster(iommu, size >> PAGE_SHIFT);
+ if (iopte == NULL) {
+ spin_unlock_irqrestore(&iommu->lock, flags);
+ free_pages(first_page, order);
+ return NULL;
+ }
+
+ /* Ok, we're committed at this point. */
+ *dvma_addr = MAP_BASE + ((iopte - iommu->page_table) << PAGE_SHIFT);
+ ret = (void *) first_page;
+ npages = size >> PAGE_SHIFT;
+ while (npages--) {
+ *iopte++ = __iopte(IOPTE_VALID | IOPTE_CACHE | IOPTE_WRITE |
+ (__pa(first_page) & IOPTE_PAGE));
+ first_page += PAGE_SIZE;
+ }
+ iommu_flush(iommu, *dvma_addr, size >> PAGE_SHIFT);
+ spin_unlock_irqrestore(&iommu->lock, flags);
+
+ return ret;
+}
+
+void sbus_free_consistant(struct sbus_dev *sdev, long size, void *cpu, u32 dvma)
+{
+ unsigned long order, npages;
+ struct sbus_iommu *iommu;
+
+ if (size <= 0 || sdev == NULL || cpu == NULL)
+ return;
+
+ npages = PAGE_ALIGN(size) >> PAGE_SHIFT;
+ iommu = sdev->bus->iommu;
+
+ spin_lock_irq(&iommu->lock);
+ free_consistant_cluster(iommu, dvma, npages);
+ spin_unlock_irq(&iommu->lock);
+
+ for (order = 0; order < 10; order++) {
+ if ((PAGE_SIZE << order) >= size)
+ break;
+ }
+ if (order < 10)
+ free_pages((unsigned long)cpu, order);
+}
+
+u32 sbus_map_single(struct sbus_dev *sdev, void *ptr, long size)
+{
+ struct sbus_iommu *iommu = sdev->bus->iommu;
+ unsigned long npages, phys_base, flags;
+ iopte_t *iopte;
+ u32 dma_base, offset;
+
+ phys_base = (unsigned long) ptr;
+ offset = (u32) (phys_base & ~PAGE_MASK);
+ size = (PAGE_ALIGN(phys_base + size) - (phys_base & PAGE_MASK));
+ phys_base = (unsigned long) __pa(phys_base & PAGE_MASK);
+
+ spin_lock_irqsave(&iommu->lock, flags);
+ npages = size >> PAGE_SHIFT;
+ iopte = alloc_streaming_cluster(iommu, npages);
+ dma_base = MAP_BASE + ((iopte - iommu->page_table) << PAGE_SHIFT);
+ npages = size >> PAGE_SHIFT;
+ while (npages--) {
+ *iopte++ = __iopte(IOPTE_VALID | IOPTE_STBUF |
+ IOPTE_CACHE | IOPTE_WRITE |
+ (phys_base & IOPTE_PAGE));
+ phys_base += PAGE_SIZE;
+ }
+ npages = size >> PAGE_SHIFT;
+ iommu_flush(iommu, dma_base, npages);
+ spin_unlock_irqrestore(&iommu->lock, flags);
+
+ return (dma_base | offset);
+}
+
+void sbus_unmap_single(struct sbus_dev *sdev, u32 dma_addr, long size)
+{
+ struct sbus_iommu *iommu = sdev->bus->iommu;
+ u32 dma_base = dma_addr & PAGE_MASK;
+ unsigned long flags;
+
+ size = (PAGE_ALIGN(dma_addr + size) - dma_base);
+
+ spin_lock_irqsave(&iommu->lock, flags);
+ free_streaming_cluster(iommu, dma_base, size >> PAGE_SHIFT);
+ strbuf_flush(iommu, dma_base, size >> PAGE_SHIFT);
+ spin_unlock_irqrestore(&iommu->lock, flags);
+}
+
+static inline void fill_sg(iopte_t *iopte, struct scatterlist *sg, int nents)
+{
+ struct scatterlist *dma_sg = sg;
+
+ do {
+ unsigned long pteval = ~0UL;
+ u32 dma_npages;
+
+ dma_npages = ((dma_sg->dvma_address & (PAGE_SIZE - 1UL)) +
+ dma_sg->dvma_length +
+ ((u32)(PAGE_SIZE - 1UL))) >> PAGE_SHIFT;
+ do {
+ unsigned long offset;
+ signed int len;
+
+ /* If we are here, we know we have at least one
+ * more page to map. So walk forward until we
+ * hit a page crossing, and begin creating new
+ * mappings from that spot.
+ */
+ for (;;) {
+ unsigned long tmp;
+
+ tmp = (unsigned long) __pa(sg->address);
+ len = sg->length;
+ if (((tmp ^ pteval) >> PAGE_SHIFT) != 0UL) {
+ pteval = tmp & PAGE_MASK;
+ offset = tmp & (PAGE_SIZE - 1UL);
+ break;
+ }
+ if (((tmp ^ (tmp + len - 1UL)) >> PAGE_SHIFT) != 0UL) {
+ pteval = (tmp + PAGE_SIZE) & PAGE_MASK;
+ offset = 0UL;
+ len -= (PAGE_SIZE - (tmp & (PAGE_SIZE - 1UL)));
+ break;
+ }
+ sg++;
+ }
+
+ pteval = ((pteval & IOPTE_PAGE) |
+ IOPTE_VALID | IOPTE_STBUF |
+ IOPTE_CACHE | IOPTE_WRITE);
+ while (len > 0) {
+ *iopte++ = __iopte(pteval);
+ pteval += PAGE_SIZE;
+ len -= (PAGE_SIZE - offset);
+ offset = 0;
+ dma_npages--;
+ }
+
+ pteval = (pteval & IOPTE_PAGE) + len;
+ sg++;
+
+ /* Skip over any tail mappings we've fully mapped,
+ * adjusting pteval along the way. Stop when we
+ * detect a page crossing event.
+ */
+ while ((pteval << (64 - PAGE_SHIFT)) != 0UL &&
+ pteval == __pa(sg->address) &&
+ ((pteval ^
+ (__pa(sg->address) + sg->length - 1UL)) >> PAGE_SHIFT) == 0UL) {
+ pteval += sg->length;
+ sg++;
+ }
+ if ((pteval << (64 - PAGE_SHIFT)) == 0UL)
+ pteval = ~0UL;
+ } while (dma_npages != 0);
+ dma_sg++;
+ } while (dma_sg->dvma_length != 0);
+}
+
+int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sg, int nents)
+{
+ struct sbus_iommu *iommu = sdev->bus->iommu;
+ unsigned long flags, npages;
+ iopte_t *iopte;
+ u32 dma_base;
+ struct scatterlist *sgtmp;
+ int unused;
+
+ /* Fast path single entry scatterlists. */
+ if (nents == 1) {
+ sg->dvma_address = sbus_map_single(sdev, sg->address, sg->length);
+ sg->dvma_length = sg->length;
+ return 1;
+ }
+
+ npages = prepare_sg(sg, nents);
+
+ spin_lock_irqsave(&iommu->lock, flags);
+ iopte = alloc_streaming_cluster(iommu, npages);
+ dma_base = MAP_BASE + ((iopte - iommu->page_table) << PAGE_SHIFT);
+
+ /* Normalize DVMA addresses. */
+ sgtmp = sg;
+ unused = nents;
+
+ while (unused && sgtmp->dvma_length) {
+ sgtmp->dvma_address += dma_base;
+ sgtmp++;
+ unused--;
+ }
+
+ fill_sg(iopte, sg, nents);
+#ifdef VERIFY_SG
+ verify_sglist(sg, nents, iopte, npages);
+#endif
+ iommu_flush(iommu, dma_base, npages);
+ spin_unlock_irqrestore(&iommu->lock, flags);
+
+ return nents - unused;
+}
+
+void sbus_unmap_sg(struct sbus_dev *sdev, struct scatterlist *sg, int nents)
+{
+ unsigned long size, flags;
+ struct sbus_iommu *iommu;
+ u32 dvma_base;
+ int i;
+
+ /* Fast path single entry scatterlists. */
+ if (nents == 1) {
+ sbus_unmap_single(sdev, sg->dvma_address, sg->dvma_length);
+ return;
+ }
+
+ dvma_base = sg[0].dvma_address & PAGE_MASK;
+ for (i = 0; i < nents; i++) {
+ if (sg[i].dvma_length == 0)
+ break;
+ }
+ i--;
+ size = PAGE_ALIGN(sg[i].dvma_address + sg[i].dvma_length) - dvma_base;
+
+ iommu = sdev->bus->iommu;
+ spin_lock_irqsave(&iommu->lock, flags);
+ free_streaming_cluster(iommu, dvma_base, size >> PAGE_SHIFT);
+ strbuf_flush(iommu, dvma_base, size >> PAGE_SHIFT);
+ spin_unlock_irqrestore(&iommu->lock, flags);
+}
+
+void sbus_dma_sync_single(struct sbus_dev *sdev, u32 base, long size)
+{
+ struct sbus_iommu *iommu = sdev->bus->iommu;
+ unsigned long flags;
+
+ size = (PAGE_ALIGN(base + size) - (base & PAGE_MASK));
+
+ spin_lock_irqsave(&iommu->lock, flags);
+ strbuf_flush(iommu, base & PAGE_MASK, size >> PAGE_SHIFT);
+ spin_unlock_irqrestore(&iommu->lock, flags);
+}
+
+void sbus_dma_sync_sg(struct sbus_dev *sdev, struct scatterlist *sg, int nents)
+{
+ struct sbus_iommu *iommu = sdev->bus->iommu;
+ unsigned long flags, size;
+ u32 base;
+ int i;
+
+ base = sg[0].dvma_address & PAGE_MASK;
+ for (i = 0; i < nents; i++) {
+ if (sg[i].dvma_length == 0)
+ break;
+ }
+ i--;
+ size = PAGE_ALIGN(sg[i].dvma_address + sg[i].dvma_length) - base;
+
+ spin_lock_irqsave(&iommu->lock, flags);
+ strbuf_flush(iommu, base, size >> PAGE_SHIFT);
+ spin_unlock_irqrestore(&iommu->lock, flags);
+}
+
+/* Enable 64-bit DVMA mode for the given device. */
+void sbus_set_sbus64(struct sbus_dev *sdev, int bursts)
+{
+ struct sbus_iommu *iommu = sdev->bus->iommu;
+ int slot = sdev->slot;
+ unsigned long cfg_reg;
+ u64 val;
+
+ cfg_reg = iommu->sbus_control_reg;
+ switch (slot) {
+ case 0:
+ cfg_reg += 0x20UL;
+ break;
+ case 1:
+ cfg_reg += 0x28UL;
+ break;
+ case 2:
+ cfg_reg += 0x30UL;
+ break;
+ case 3:
+ cfg_reg += 0x38UL;
+ break;
+ case 13:
+ cfg_reg += 0x40UL;
+ break;
+ case 14:
+ cfg_reg += 0x48UL;
+ break;
+ case 15:
+ cfg_reg += 0x50UL;
+ break;
+
+ default:
+ return;
+ };
+
+ val = upa_readq(cfg_reg);
+ if (val & (1UL << 14UL)) {
+ /* Extended transfer mode already enabled. */
+ return;
+ }
+
+ val |= (1UL << 14UL);
+
+ if (bursts & DMA_BURST8)
+ val |= (1UL << 1UL);
+ if (bursts & DMA_BURST16)
+ val |= (1UL << 2UL);
+ if (bursts & DMA_BURST32)
+ val |= (1UL << 3UL);
+ if (bursts & DMA_BURST64)
+ val |= (1UL << 4UL);
+ upa_writeq(val, cfg_reg);
+}
+
+/* SBUS SYSIO INO number to Sparc PIL level. */
+static unsigned char sysio_ino_to_pil[] = {
+ 0, 1, 2, 7, 5, 7, 8, 9, /* SBUS slot 0 */
+ 0, 1, 2, 7, 5, 7, 8, 9, /* SBUS slot 1 */
+ 0, 1, 2, 7, 5, 7, 8, 9, /* SBUS slot 2 */
+ 0, 1, 2, 7, 5, 7, 8, 9, /* SBUS slot 3 */
+ 3, /* Onboard SCSI */
+ 5, /* Onboard Ethernet */
+/*XXX*/ 8, /* Onboard BPP */
+ 0, /* Bogon */
+ 13, /* Audio */
+/*XXX*/15, /* PowerFail */
+ 0, /* Bogon */
+ 0, /* Bogon */
+ 12, /* Zilog Serial Channels (incl. Keyboard/Mouse lines) */
+ 11, /* Floppy */
+ 0, /* Spare Hardware (bogon for now) */
+ 0, /* Keyboard (bogon for now) */
+ 0, /* Mouse (bogon for now) */
+ 0, /* Serial (bogon for now) */
+ 0, 0, /* Bogon, Bogon */
+ 10, /* Timer 0 */
+ 11, /* Timer 1 */
+ 0, 0, /* Bogon, Bogon */
+ 15, /* Uncorrectable SBUS Error */
+ 15, /* Correctable SBUS Error */
+ 15, /* SBUS Error */
+/*XXX*/ 0, /* Power Management (bogon for now) */
+};
+
+/* INO number to IMAP register offset for SYSIO external IRQ's.
+ * This should conform to both Sunfire/Wildfire server and Fusion
+ * desktop designs.
+ */
+#define SYSIO_IMAP_SLOT0 0x2c04UL
+#define SYSIO_IMAP_SLOT1 0x2c0cUL
+#define SYSIO_IMAP_SLOT2 0x2c14UL
+#define SYSIO_IMAP_SLOT3 0x2c1cUL
+#define SYSIO_IMAP_SCSI 0x3004UL
+#define SYSIO_IMAP_ETH 0x300cUL
+#define SYSIO_IMAP_BPP 0x3014UL
+#define SYSIO_IMAP_AUDIO 0x301cUL
+#define SYSIO_IMAP_PFAIL 0x3024UL
+#define SYSIO_IMAP_KMS 0x302cUL
+#define SYSIO_IMAP_FLPY 0x3034UL
+#define SYSIO_IMAP_SHW 0x303cUL
+#define SYSIO_IMAP_KBD 0x3044UL
+#define SYSIO_IMAP_MS 0x304cUL
+#define SYSIO_IMAP_SER 0x3054UL
+#define SYSIO_IMAP_TIM0 0x3064UL
+#define SYSIO_IMAP_TIM1 0x306cUL
+#define SYSIO_IMAP_UE 0x3074UL
+#define SYSIO_IMAP_CE 0x307cUL
+#define SYSIO_IMAP_SBERR 0x3084UL
+#define SYSIO_IMAP_PMGMT 0x308cUL
+#define SYSIO_IMAP_GFX 0x3094UL
+#define SYSIO_IMAP_EUPA 0x309cUL
+
+#define bogon ((unsigned long) -1)
+static unsigned long sysio_irq_offsets[] = {
+ /* SBUS Slot 0 --> 3, level 1 --> 7 */
+ SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0,
+ SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0,
+ SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1,
+ SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1,
+ SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2,
+ SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2,
+ SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3,
+ SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3,
+
+ /* Onboard devices (not relevant/used on SunFire). */
+ SYSIO_IMAP_SCSI,
+ SYSIO_IMAP_ETH,
+ SYSIO_IMAP_BPP,
+ bogon,
+ SYSIO_IMAP_AUDIO,
+ SYSIO_IMAP_PFAIL,
+ bogon,
+ bogon,
+ SYSIO_IMAP_KMS,
+ SYSIO_IMAP_FLPY,
+ SYSIO_IMAP_SHW,
+ SYSIO_IMAP_KBD,
+ SYSIO_IMAP_MS,
+ SYSIO_IMAP_SER,
+ bogon,
+ bogon,
+ SYSIO_IMAP_TIM0,
+ SYSIO_IMAP_TIM1,
+ bogon,
+ bogon,
+ SYSIO_IMAP_UE,
+ SYSIO_IMAP_CE,
+ SYSIO_IMAP_SBERR,
+ SYSIO_IMAP_PMGMT,
+};
+
+#undef bogon
+
+#define NUM_SYSIO_OFFSETS (sizeof(sysio_irq_offsets) / sizeof(sysio_irq_offsets[0]))
+
+/* Convert Interrupt Mapping register pointer to assosciated
+ * Interrupt Clear register pointer, SYSIO specific version.
+ */
+#define SYSIO_ICLR_UNUSED0 0x3400UL
+#define SYSIO_ICLR_SLOT0 0x340cUL
+#define SYSIO_ICLR_SLOT1 0x344cUL
+#define SYSIO_ICLR_SLOT2 0x348cUL
+#define SYSIO_ICLR_SLOT3 0x34ccUL
+static unsigned long sysio_imap_to_iclr(unsigned long imap)
+{
+ unsigned long diff = SYSIO_ICLR_UNUSED0 - SYSIO_IMAP_SLOT0;
+ return imap + diff;
+}
+
+unsigned int sbus_build_irq(void *buscookie, unsigned int ino)
+{
+ struct sbus_bus *sbus = (struct sbus_bus *)buscookie;
+ struct sbus_iommu *iommu = sbus->iommu;
+ unsigned long reg_base = iommu->sbus_control_reg - 0x2000UL;
+ unsigned long imap, iclr;
+ int pil, sbus_level = 0;
+
+ pil = sysio_ino_to_pil[ino];
+ if (!pil) {
+ printk("sbus_irq_build: Bad SYSIO INO[%x]\n", ino);
+ panic("Bad SYSIO IRQ translations...");
+ }
+ imap = sysio_irq_offsets[ino];
+ if (imap == ((unsigned long)-1)) {
+ prom_printf("get_irq_translations: Bad SYSIO INO[%x] cpu[%d]\n",
+ ino, pil);
+ prom_halt();
+ }
+ imap += reg_base;
+
+ /* SYSIO inconsistancy. For external SLOTS, we have to select
+ * the right ICLR register based upon the lower SBUS irq level
+ * bits.
+ */
+ if (ino >= 0x20) {
+ iclr = sysio_imap_to_iclr(imap);
+ } else {
+ int sbus_slot = (ino & 0x18)>>3;
+
+ sbus_level = ino & 0x7;
+
+ switch(sbus_slot) {
+ case 0:
+ iclr = reg_base + SYSIO_ICLR_SLOT0;
+ break;
+ case 1:
+ iclr = reg_base + SYSIO_ICLR_SLOT1;
+ break;
+ case 2:
+ iclr = reg_base + SYSIO_ICLR_SLOT2;
+ break;
+ default:
+ case 3:
+ iclr = reg_base + SYSIO_ICLR_SLOT3;
+ break;
+ };
+
+ iclr += ((unsigned long)sbus_level - 1UL) * 8UL;
+ }
+ return build_irq(pil, sbus_level, iclr, imap);
+}
+
+/* Error interrupt handling. */
+#define SYSIO_UE_AFSR 0x0030UL
+#define SYSIO_UE_AFAR 0x0038UL
+#define SYSIO_UEAFSR_PPIO 0x8000000000000000 /* Primary PIO is cause */
+#define SYSIO_UEAFSR_PDRD 0x4000000000000000 /* Primary DVMA read is cause */
+#define SYSIO_UEAFSR_PDWR 0x2000000000000000 /* Primary DVMA write is cause */
+#define SYSIO_UEAFSR_SPIO 0x1000000000000000 /* Secondary PIO is cause */
+#define SYSIO_UEAFSR_SDRD 0x0800000000000000 /* Secondary DVMA read is cause */
+#define SYSIO_UEAFSR_SDWR 0x0400000000000000 /* Secondary DVMA write is cause*/
+#define SYSIO_UEAFSR_RESV1 0x03ff000000000000 /* Reserved */
+#define SYSIO_UEAFSR_DOFF 0x0000e00000000000 /* Doubleword Offset */
+#define SYSIO_UEAFSR_SIZE 0x00001c0000000000 /* Bad transfer size is 2**SIZE */
+#define SYSIO_UEAFSR_MID 0x000003e000000000 /* UPA MID causing the fault */
+#define SYSIO_UEAFSR_RESV2 0x0000001fffffffff /* Reserved */
+static void sysio_ue_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct sbus_bus *sbus = dev_id;
+ struct sbus_iommu *iommu = sbus->iommu;
+ unsigned long reg_base = iommu->sbus_control_reg - 0x2000UL;
+ unsigned long afsr_reg, afar_reg;
+ unsigned long afsr, afar, error_bits;
+ int reported;
+
+ afsr_reg = reg_base + SYSIO_UE_AFSR;
+ afar_reg = reg_base + SYSIO_UE_AFAR;
+
+ /* Latch error status. */
+ afsr = upa_readq(afsr_reg);
+ afar = upa_readq(afar_reg);
+
+ /* Clear primary/secondary error status bits. */
+ error_bits = afsr &
+ (SYSIO_UEAFSR_PPIO | SYSIO_UEAFSR_PDRD | SYSIO_UEAFSR_PDWR |
+ SYSIO_UEAFSR_SPIO | SYSIO_UEAFSR_SDRD | SYSIO_UEAFSR_SDWR);
+ upa_writeq(error_bits, afsr_reg);
+
+ /* Log the error. */
+ printk("SYSIO[%x]: Uncorrectable ECC Error, primary error type[%s]\n",
+ sbus->portid,
+ (((error_bits & SYSIO_UEAFSR_PPIO) ?
+ "PIO" :
+ ((error_bits & SYSIO_UEAFSR_PDRD) ?
+ "DVMA Read" :
+ ((error_bits & SYSIO_UEAFSR_PDWR) ?
+ "DVMA Write" : "???")))));
+ printk("SYSIO[%x]: DOFF[%lx] SIZE[%lx] MID[%lx]\n",
+ sbus->portid,
+ (afsr & SYSIO_UEAFSR_DOFF) >> 45UL,
+ (afsr & SYSIO_UEAFSR_SIZE) >> 42UL,
+ (afsr & SYSIO_UEAFSR_MID) >> 37UL);
+ printk("SYSIO[%x]: AFAR[%016lx]\n", sbus->portid, afar);
+ printk("SYSIO[%x]: Secondary UE errors [", sbus->portid);
+ reported = 0;
+ if (afsr & SYSIO_UEAFSR_SPIO) {
+ reported++;
+ printk("(PIO)");
+ }
+ if (afsr & SYSIO_UEAFSR_SDRD) {
+ reported++;
+ printk("(DVMA Read)");
+ }
+ if (afsr & SYSIO_UEAFSR_SDWR) {
+ reported++;
+ printk("(DVMA Write)");
+ }
+ if (!reported)
+ printk("(none)");
+ printk("]\n");
+}
+
+#define SYSIO_CE_AFSR 0x0040UL
+#define SYSIO_CE_AFAR 0x0048UL
+#define SYSIO_CEAFSR_PPIO 0x8000000000000000 /* Primary PIO is cause */
+#define SYSIO_CEAFSR_PDRD 0x4000000000000000 /* Primary DVMA read is cause */
+#define SYSIO_CEAFSR_PDWR 0x2000000000000000 /* Primary DVMA write is cause */
+#define SYSIO_CEAFSR_SPIO 0x1000000000000000 /* Secondary PIO is cause */
+#define SYSIO_CEAFSR_SDRD 0x0800000000000000 /* Secondary DVMA read is cause */
+#define SYSIO_CEAFSR_SDWR 0x0400000000000000 /* Secondary DVMA write is cause*/
+#define SYSIO_CEAFSR_RESV1 0x0300000000000000 /* Reserved */
+#define SYSIO_CEAFSR_ESYND 0x00ff000000000000 /* Syndrome Bits */
+#define SYSIO_CEAFSR_DOFF 0x0000e00000000000 /* Double Offset */
+#define SYSIO_CEAFSR_SIZE 0x00001c0000000000 /* Bad transfer size is 2**SIZE */
+#define SYSIO_CEAFSR_MID 0x000003e000000000 /* UPA MID causing the fault */
+#define SYSIO_CEAFSR_RESV2 0x0000001fffffffff /* Reserved */
+static void sysio_ce_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct sbus_bus *sbus = dev_id;
+ struct sbus_iommu *iommu = sbus->iommu;
+ unsigned long reg_base = iommu->sbus_control_reg - 0x2000UL;
+ unsigned long afsr_reg, afar_reg;
+ unsigned long afsr, afar, error_bits;
+ int reported;
+
+ afsr_reg = reg_base + SYSIO_CE_AFSR;
+ afar_reg = reg_base + SYSIO_CE_AFAR;
+
+ /* Latch error status. */
+ afsr = upa_readq(afsr_reg);
+ afar = upa_readq(afar_reg);
+
+ /* Clear primary/secondary error status bits. */
+ error_bits = afsr &
+ (SYSIO_CEAFSR_PPIO | SYSIO_CEAFSR_PDRD | SYSIO_CEAFSR_PDWR |
+ SYSIO_CEAFSR_SPIO | SYSIO_CEAFSR_SDRD | SYSIO_CEAFSR_SDWR);
+ upa_writeq(error_bits, afsr_reg);
+
+ printk("SYSIO[%x]: Correctable ECC Error, primary error type[%s]\n",
+ sbus->portid,
+ (((error_bits & SYSIO_CEAFSR_PPIO) ?
+ "PIO" :
+ ((error_bits & SYSIO_CEAFSR_PDRD) ?
+ "DVMA Read" :
+ ((error_bits & SYSIO_CEAFSR_PDWR) ?
+ "DVMA Write" : "???")))));
+
+ /* XXX Use syndrome and afar to print out module string just like
+ * XXX UDB CE trap handler does... -DaveM
+ */
+ printk("SYSIO[%x]: DOFF[%lx] ECC Syndrome[%lx] Size[%lx] MID[%lx]\n",
+ sbus->portid,
+ (afsr & SYSIO_CEAFSR_DOFF) >> 45UL,
+ (afsr & SYSIO_CEAFSR_ESYND) >> 48UL,
+ (afsr & SYSIO_CEAFSR_SIZE) >> 42UL,
+ (afsr & SYSIO_CEAFSR_MID) >> 37UL);
+ printk("SYSIO[%x]: AFAR[%016lx]\n", sbus->portid, afar);
+
+ printk("SYSIO[%x]: Secondary CE errors [", sbus->portid);
+ reported = 0;
+ if (afsr & SYSIO_CEAFSR_SPIO) {
+ reported++;
+ printk("(PIO)");
+ }
+ if (afsr & SYSIO_CEAFSR_SDRD) {
+ reported++;
+ printk("(DVMA Read)");
+ }
+ if (afsr & SYSIO_CEAFSR_SDWR) {
+ reported++;
+ printk("(DVMA Write)");
+ }
+ if (!reported)
+ printk("(none)");
+ printk("]\n");
+}
+
+#define SYSIO_SBUS_AFSR 0x2010UL
+#define SYSIO_SBUS_AFAR 0x2018UL
+#define SYSIO_SBAFSR_PLE 0x8000000000000000 /* Primary Late PIO Error */
+#define SYSIO_SBAFSR_PTO 0x4000000000000000 /* Primary SBUS Timeout */
+#define SYSIO_SBAFSR_PBERR 0x2000000000000000 /* Primary SBUS Error ACK */
+#define SYSIO_SBAFSR_SLE 0x1000000000000000 /* Secondary Late PIO Error */
+#define SYSIO_SBAFSR_STO 0x0800000000000000 /* Secondary SBUS Timeout */
+#define SYSIO_SBAFSR_SBERR 0x0400000000000000 /* Secondary SBUS Error ACK */
+#define SYSIO_SBAFSR_RESV1 0x03ff000000000000 /* Reserved */
+#define SYSIO_SBAFSR_RD 0x0000800000000000 /* Primary was late PIO read */
+#define SYSIO_SBAFSR_RESV2 0x0000600000000000 /* Reserved */
+#define SYSIO_SBAFSR_SIZE 0x00001c0000000000 /* Size of transfer */
+#define SYSIO_SBAFSR_MID 0x000003e000000000 /* MID causing the error */
+#define SYSIO_SBAFSR_RESV3 0x0000001fffffffff /* Reserved */
+static void sysio_sbus_error_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct sbus_bus *sbus = dev_id;
+ struct sbus_iommu *iommu = sbus->iommu;
+ unsigned long afsr_reg, afar_reg, reg_base;
+ unsigned long afsr, afar, error_bits;
+ int reported;
+
+ reg_base = iommu->sbus_control_reg - 0x2000UL;
+ afsr_reg = reg_base + SYSIO_SBUS_AFSR;
+ afar_reg = reg_base + SYSIO_SBUS_AFAR;
+
+ afsr = upa_readq(afsr_reg);
+ afar = upa_readq(afar_reg);
+
+ /* Clear primary/secondary error status bits. */
+ error_bits = afsr &
+ (SYSIO_SBAFSR_PLE | SYSIO_SBAFSR_PTO | SYSIO_SBAFSR_PBERR |
+ SYSIO_SBAFSR_SLE | SYSIO_SBAFSR_STO | SYSIO_SBAFSR_SBERR);
+ upa_writeq(error_bits, afsr_reg);
+
+ /* Log the error. */
+ printk("SYSIO[%x]: SBUS Error, primary error type[%s] read(%d)\n",
+ sbus->portid,
+ (((error_bits & SYSIO_SBAFSR_PLE) ?
+ "Late PIO Error" :
+ ((error_bits & SYSIO_SBAFSR_PTO) ?
+ "Time Out" :
+ ((error_bits & SYSIO_SBAFSR_PBERR) ?
+ "Error Ack" : "???")))),
+ (afsr & SYSIO_SBAFSR_RD) ? 1 : 0);
+ printk("SYSIO[%x]: size[%lx] MID[%lx]\n",
+ sbus->portid,
+ (afsr & SYSIO_SBAFSR_SIZE) >> 42UL,
+ (afsr & SYSIO_SBAFSR_MID) >> 37UL);
+ printk("SYSIO[%x]: AFAR[%016lx]\n", sbus->portid, afar);
+ printk("SYSIO[%x]: Secondary SBUS errors [", sbus->portid);
+ reported = 0;
+ if (afsr & SYSIO_SBAFSR_SLE) {
+ reported++;
+ printk("(Late PIO Error)");
+ }
+ if (afsr & SYSIO_SBAFSR_STO) {
+ reported++;
+ printk("(Time Out)");
+ }
+ if (afsr & SYSIO_SBAFSR_SBERR) {
+ reported++;
+ printk("(Error Ack)");
+ }
+ if (!reported)
+ printk("(none)");
+ printk("]\n");
+
+ /* XXX check iommu/strbuf for further error status XXX */
+}
+
+#define ECC_CONTROL 0x0020UL
+#define SYSIO_ECNTRL_ECCEN 0x8000000000000000 /* Enable ECC Checking */
+#define SYSIO_ECNTRL_UEEN 0x4000000000000000 /* Enable UE Interrupts */
+#define SYSIO_ECNTRL_CEEN 0x2000000000000000 /* Enable CE Interrupts */
+
+#define SYSIO_UE_INO 0x34
+#define SYSIO_CE_INO 0x35
+#define SYSIO_SBUSERR_INO 0x36
+
+static void __init sysio_register_error_handlers(struct sbus_bus *sbus)
+{
+ struct sbus_iommu *iommu = sbus->iommu;
+ unsigned long reg_base = iommu->sbus_control_reg - 0x2000UL;
+ unsigned int irq;
+ u64 control;
+
+ irq = sbus_build_irq(sbus, SYSIO_UE_INO);
+ if (request_irq(irq, sysio_ue_handler,
+ SA_SHIRQ, "SYSIO UE", sbus) < 0) {
+ prom_printf("SYSIO[%x]: Cannot register UE interrupt.\n",
+ sbus->portid);
+ prom_halt();
+ }
+
+ irq = sbus_build_irq(sbus, SYSIO_CE_INO);
+ if (request_irq(irq, sysio_ce_handler,
+ SA_SHIRQ, "SYSIO CE", sbus) < 0) {
+ prom_printf("SYSIO[%x]: Cannot register CE interrupt.\n",
+ sbus->portid);
+ prom_halt();
+ }
+
+ irq = sbus_build_irq(sbus, SYSIO_SBUSERR_INO);
+ if (request_irq(irq, sysio_sbus_error_handler,
+ SA_SHIRQ, "SYSIO SBUS Error", sbus) < 0) {
+ prom_printf("SYSIO[%x]: Cannot register SBUS Error interrupt.\n",
+ sbus->portid);
+ prom_halt();
+ }
+
+ /* Now turn the error interrupts on and also enable ECC checking. */
+ upa_writeq((SYSIO_ECNTRL_ECCEN |
+ SYSIO_ECNTRL_UEEN |
+ SYSIO_ECNTRL_CEEN),
+ reg_base + ECC_CONTROL);
+
+ control = upa_readq(iommu->sbus_control_reg);
+ control |= 0x100UL; /* SBUS Error Interrupt Enable */
+ upa_writeq(control, iommu->sbus_control_reg);
+}
+
+/* Boot time initialization. */
+void __init sbus_iommu_init(int prom_node, struct sbus_bus *sbus)
+{
+ struct linux_prom64_registers rprop;
+ struct sbus_iommu *iommu;
+ unsigned long regs, tsb_base;
+ u64 control;
+ int err, i;
+
+ sbus->portid = prom_getintdefault(sbus->prom_node,
+ "upa-portid", -1);
+
+ err = prom_getproperty(prom_node, "reg",
+ (char *)&rprop, sizeof(rprop));
+ if (err < 0) {
+ prom_printf("sbus_iommu_init: Cannot map SYSIO control registers.\n");
+ prom_halt();
+ }
+ regs = rprop.phys_addr;
+
+ iommu = kmalloc(sizeof(*iommu) + SMP_CACHE_BYTES, GFP_ATOMIC);
+ if (iommu == NULL) {
+ prom_printf("sbus_iommu_init: Fatal error, kmalloc(iommu) failed\n");
+ prom_halt();
+ }
+
+ /* Align on E$ line boundry. */
+ iommu = (struct sbus_iommu *)
+ (((unsigned long)iommu + (SMP_CACHE_BYTES - 1UL)) &
+ ~(SMP_CACHE_BYTES - 1UL));
+
+ memset(iommu, 0, sizeof(*iommu));
+
+ /* Setup spinlock. */
+ spin_lock_init(&iommu->lock);
+
+ /* Init register offsets. */
+ iommu->iommu_regs = regs + SYSIO_IOMMUREG_BASE;
+ iommu->strbuf_regs = regs + SYSIO_STRBUFREG_BASE;
+
+ /* The SYSIO SBUS control register is used for dummy reads
+ * in order to ensure write completion.
+ */
+ iommu->sbus_control_reg = regs + 0x2000UL;
+
+ /* Link into SYSIO software state. */
+ sbus->iommu = iommu;
+
+ printk("SYSIO: UPA portID %x, at %016lx\n",
+ sbus->portid, regs);
+
+ /* Setup for TSB_SIZE=7, TBW_SIZE=0, MMU_DE=1, MMU_EN=1 */
+ control = upa_readq(iommu->iommu_regs + IOMMU_CONTROL);
+ control = ((7UL << 16UL) |
+ (0UL << 2UL) |
+ (1UL << 1UL) |
+ (1UL << 0UL));
+
+ /* Using the above configuration we need 1MB iommu page
+ * table (128K ioptes * 8 bytes per iopte). This is
+ * page order 7 on UltraSparc.
+ */
+ tsb_base = __get_free_pages(GFP_ATOMIC, 7);
+ if (tsb_base == 0UL) {
+ prom_printf("sbus_iommu_init: Fatal error, cannot alloc TSB table.\n");
+ prom_halt();
+ }
+
+ iommu->page_table = (iopte_t *) tsb_base;
+ memset(iommu->page_table, 0, (PAGE_SIZE << 7));
+
+ upa_writeq(control, iommu->iommu_regs + IOMMU_CONTROL);
+
+ /* Clean out any cruft in the IOMMU using
+ * diagnostic accesses.
+ */
+ for (i = 0; i < 16; i++) {
+ unsigned long dram = iommu->iommu_regs + IOMMU_DRAMDIAG;
+
+ dram += (unsigned long)i * 8UL;
+ upa_writeq(0, dram);
+ }
+ upa_readq(iommu->sbus_control_reg);
+
+ /* Give the TSB to SYSIO. */
+ upa_writeq(__pa(tsb_base), iommu->iommu_regs + IOMMU_TSBBASE);
+
+ /* Setup streaming buffer, DE=1 SB_EN=1 */
+ control = (1UL << 1UL) | (1UL << 0UL);
+ upa_writeq(control, iommu->strbuf_regs + STRBUF_CONTROL);
+
+ /* Clear out the tags using diagnostics. */
+ for (i = 0; i < 16; i++) {
+ unsigned long ptag, ltag;
+
+ ptag = iommu->strbuf_regs + STRBUF_PTAGDIAG;
+ ltag = iommu->strbuf_regs + STRBUF_LTAGDIAG;
+ ptag += (unsigned long)i * 8UL;
+ ltag += (unsigned long)i * 8UL;
+
+ upa_writeq(0UL, ptag);
+ upa_writeq(0UL, ltag);
+ }
+
+ /* Enable DVMA arbitration for all devices/slots. */
+ control = upa_readq(iommu->sbus_control_reg);
+ control |= 0x3fUL;
+ upa_writeq(control, iommu->sbus_control_reg);
+
+ /* Now some Xfire specific grot... */
+ {
+ extern void *starfire_hookup(int);
+ extern int this_is_starfire;
+
+ if (this_is_starfire)
+ sbus->starfire_cookie = starfire_hookup(sbus->portid);
+ else
+ sbus->starfire_cookie = NULL;
+ }
+
+ sysio_register_error_handlers(sbus);
+}
diff --git a/arch/sparc64/kernel/semaphore.c b/arch/sparc64/kernel/semaphore.c
index f72aeedd6..88ab813f3 100644
--- a/arch/sparc64/kernel/semaphore.c
+++ b/arch/sparc64/kernel/semaphore.c
@@ -1,4 +1,4 @@
-/* $Id: semaphore.c,v 1.1 1999/08/30 10:00:50 davem Exp $
+/* $Id: semaphore.c,v 1.2 1999/12/23 17:12:03 jj Exp $
* Generic semaphore code. Buyer beware. Do your own
* specific changes in <asm/semaphore-helper.h>
*/
@@ -62,8 +62,7 @@ void __up(struct semaphore *sem)
#define DOWN_VAR \
struct task_struct *tsk = current; \
- wait_queue_t wait; \
- init_waitqueue_entry(&wait, tsk);
+ DECLARE_WAITQUEUE(wait, tsk);
#define DOWN_HEAD(task_state) \
\
@@ -127,3 +126,172 @@ int __down_trylock(struct semaphore * sem)
{
return waking_non_zero_trylock(sem);
}
+
+/* rw mutexes
+ * Implemented by Jakub Jelinek (jakub@redhat.com) based on
+ * i386 implementation by Ben LaHaise (bcrl@redhat.com).
+ */
+
+asm("
+ .text
+ .align 32
+ .globl __down_read_failed
+__down_read_failed:
+ save %sp, -160, %sp
+ membar #StoreStore
+ brz,pt %g5, 3f
+ mov %g7, %l0
+1: call down_read_failed
+ mov %l0, %o0
+2: lduw [%l0], %l1
+ sub %l1, 1, %l2
+ cas [%l0], %l1, %l2
+
+ cmp %l1, %l2
+ bne,pn %icc, 2b
+ membar #StoreStore
+ subcc %l1, 1, %g0
+ bpos,pt %icc, 4f
+ nop
+ bcc,pn %icc, 1b
+ nop
+
+3: call down_read_failed_biased
+ mov %l0, %o0
+4: ret
+ restore
+ .previous
+");
+
+asm("
+ .text
+ .align 32
+ .globl __down_write_failed
+__down_write_failed:
+ save %sp, -160, %sp
+ membar #StoreStore
+ tst %g5
+ bge,pt %icc, 3f
+ mov %g7, %l0
+1: call down_write_failed
+ mov %l0, %o0
+2: lduw [%l0], %l1
+ sethi %hi (" RW_LOCK_BIAS_STR "), %l3
+ sub %l1, %l3, %l2
+ cas [%l0], %l1, %l2
+
+ cmp %l1, %l2
+ bne,pn %icc, 2b
+ membar #StoreStore
+ subcc %l1, %l3, %g0
+ be,pt %icc, 4f
+ nop
+ bcc,pn %icc, 1b
+ nop
+
+3: call down_write_failed_biased
+ mov %l0, %o0
+4: ret
+ restore
+ .previous
+");
+
+void down_read_failed_biased(struct rw_semaphore *sem)
+{
+ DOWN_VAR
+
+ add_wait_queue(&sem->wait, &wait); /* put ourselves at the head of the list */
+
+ for (;;) {
+ if (clear_le_bit(0, &sem->granted))
+ break;
+ set_task_state(tsk, TASK_UNINTERRUPTIBLE);
+ if (!test_le_bit(0, &sem->granted))
+ schedule();
+ }
+
+ remove_wait_queue(&sem->wait, &wait);
+ tsk->state = TASK_RUNNING;
+}
+
+void down_write_failed_biased(struct rw_semaphore *sem)
+{
+ DOWN_VAR
+
+ add_wait_queue_exclusive(&sem->write_bias_wait, &wait); /* put ourselves at the end of the list */
+
+ for (;;) {
+ if (clear_le_bit(1, &sem->granted))
+ break;
+ set_task_state(tsk, TASK_UNINTERRUPTIBLE | TASK_EXCLUSIVE);
+ if (!test_le_bit(1, &sem->granted))
+ schedule();
+ }
+
+ remove_wait_queue(&sem->write_bias_wait, &wait);
+ tsk->state = TASK_RUNNING;
+
+ /* if the lock is currently unbiased, awaken the sleepers
+ * FIXME: this wakes up the readers early in a bit of a
+ * stampede -> bad!
+ */
+ if (sem->count >= 0)
+ wake_up(&sem->wait);
+}
+
+/* Wait for the lock to become unbiased. Readers
+ * are non-exclusive. =)
+ */
+void down_read_failed(struct rw_semaphore *sem)
+{
+ DOWN_VAR
+
+ __up_read(sem); /* this takes care of granting the lock */
+
+ add_wait_queue(&sem->wait, &wait);
+
+ while (sem->count < 0) {
+ set_task_state(tsk, TASK_UNINTERRUPTIBLE);
+ if (sem->count >= 0)
+ break;
+ schedule();
+ }
+
+ remove_wait_queue(&sem->wait, &wait);
+ tsk->state = TASK_RUNNING;
+}
+
+/* Wait for the lock to become unbiased. Since we're
+ * a writer, we'll make ourselves exclusive.
+ */
+void down_write_failed(struct rw_semaphore *sem)
+{
+ DOWN_VAR
+
+ __up_write(sem); /* this takes care of granting the lock */
+
+ add_wait_queue_exclusive(&sem->wait, &wait);
+
+ while (sem->count < 0) {
+ set_task_state(tsk, TASK_UNINTERRUPTIBLE | TASK_EXCLUSIVE);
+ if (sem->count >= 0)
+ break; /* we must attempt to aquire or bias the lock */
+ schedule();
+ }
+
+ remove_wait_queue(&sem->wait, &wait);
+ tsk->state = TASK_RUNNING;
+}
+
+void __rwsem_wake(struct rw_semaphore *sem, unsigned long readers)
+{
+ if (readers) {
+ if (set_le_bit(0, &sem->granted))
+ BUG();
+ wake_up(&sem->wait);
+ } else {
+ if (set_le_bit(1, &sem->granted))
+ BUG();
+ wake_up(&sem->write_bias_wait);
+ }
+}
diff --git a/arch/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c
index 066850108..0f280f818 100644
--- a/arch/sparc64/kernel/setup.c
+++ b/arch/sparc64/kernel/setup.c
@@ -1,4 +1,4 @@
-/* $Id: setup.c,v 1.47 1999/08/31 06:54:55 davem Exp $
+/* $Id: setup.c,v 1.50 1999/12/01 10:44:45 davem Exp $
* linux/arch/sparc64/kernel/setup.c
*
* Copyright (C) 1995,1996 David S. Miller (davem@caip.rutgers.edu)
@@ -279,7 +279,9 @@ unsigned int boot_flags = 0;
#ifdef CONFIG_SUN_CONSOLE
static int console_fb __initdata = 0;
#endif
-static unsigned long memory_size = 0;
+
+/* Exported for mm/init.c:paging_init. */
+unsigned long cmdline_memory_size = 0;
#ifdef PROM_DEBUG_CONSOLE
static struct console prom_debug_console = {
@@ -398,13 +400,13 @@ static void __init boot_flags_init(char *commands)
* "mem=XXX[kKmM]" overrides the PROM-reported
* memory size.
*/
- memory_size = simple_strtoul(commands + 4,
- &commands, 0);
+ cmdline_memory_size = simple_strtoul(commands + 4,
+ &commands, 0);
if (*commands == 'K' || *commands == 'k') {
- memory_size <<= 10;
+ cmdline_memory_size <<= 10;
commands++;
} else if (*commands=='M' || *commands=='m') {
- memory_size <<= 20;
+ cmdline_memory_size <<= 20;
commands++;
}
}
@@ -438,12 +440,22 @@ static struct pt_regs fake_swapper_regs = { { 0, }, 0, 0, 0, 0 };
extern struct consw sun_serial_con;
-void __init setup_arch(char **cmdline_p,
- unsigned long * memory_start_p, unsigned long * memory_end_p)
+void register_prom_callbacks(void)
+{
+ prom_setcallback(prom_callback);
+ prom_feval(": linux-va>tte-data 2 \" va>tte-data\" $callback drop ; "
+ "' linux-va>tte-data to va>tte-data");
+ prom_feval(": linux-.soft1 1 \" .soft1\" $callback 2drop ; "
+ "' linux-.soft1 to .soft1");
+ prom_feval(": linux-.soft2 1 \" .soft2\" $callback 2drop ; "
+ "' linux-.soft2 to .soft2");
+}
+
+void __init setup_arch(char **cmdline_p)
{
extern int serial_console; /* in console.c, of course */
- unsigned long lowest_paddr, end_of_phys_memory = 0;
- int total, i;
+ unsigned long highest_paddr;
+ int i;
/* Initialize PROM console and command line. */
*cmdline_p = prom_getbootargs();
@@ -464,44 +476,23 @@ void __init setup_arch(char **cmdline_p,
boot_flags_init(*cmdline_p);
idprom_init();
- total = prom_probe_memory();
-
- lowest_paddr = 0xffffffffffffffffUL;
- for(i=0; sp_banks[i].num_bytes != 0; i++) {
- if(sp_banks[i].base_addr < lowest_paddr)
- lowest_paddr = sp_banks[i].base_addr;
- end_of_phys_memory = sp_banks[i].base_addr +
- sp_banks[i].num_bytes;
- if (memory_size) {
- if (end_of_phys_memory > memory_size) {
- sp_banks[i].num_bytes -=
- (end_of_phys_memory - memory_size);
- end_of_phys_memory = memory_size;
- sp_banks[++i].base_addr = 0xdeadbeef;
- sp_banks[i].num_bytes = 0;
- }
- }
- }
- prom_setcallback(prom_callback);
- prom_feval(": linux-va>tte-data 2 \" va>tte-data\" $callback drop ; "
- "' linux-va>tte-data to va>tte-data");
- prom_feval(": linux-.soft1 1 \" .soft1\" $callback 2drop ; "
- "' linux-.soft1 to .soft1");
- prom_feval(": linux-.soft2 1 \" .soft2\" $callback 2drop ; "
- "' linux-.soft2 to .soft2");
+ (void) prom_probe_memory();
/* In paging_init() we tip off this value to see if we need
* to change init_mm.pgd to point to the real alias mapping.
*/
- phys_base = lowest_paddr;
-
- *memory_start_p = PAGE_ALIGN(((unsigned long) &end));
- *memory_end_p = (end_of_phys_memory + PAGE_OFFSET);
-
-#ifdef DAVEM_DEBUGGING
- prom_printf("phys_base[%016lx] memory_start[%016lx] memory_end[%016lx]\n",
- phys_base, *memory_start_p, *memory_end_p);
-#endif
+ phys_base = 0xffffffffffffffffUL;
+ highest_paddr = 0UL;
+ for (i = 0; sp_banks[i].num_bytes != 0; i++) {
+ unsigned long top;
+
+ if (sp_banks[i].base_addr < phys_base)
+ phys_base = sp_banks[i].base_addr;
+ top = sp_banks[i].base_addr +
+ sp_banks[i].num_bytes;
+ if (highest_paddr < top)
+ highest_paddr = top;
+ }
if (!root_flags)
root_mountflags &= ~MS_RDONLY;
@@ -512,6 +503,7 @@ void __init setup_arch(char **cmdline_p,
rd_doload = ((ram_flags & RAMDISK_LOAD_FLAG) != 0);
#endif
#ifdef CONFIG_BLK_DEV_INITRD
+// FIXME needs to do the new bootmem alloc stuff
if (sparc_ramdisk_image) {
unsigned long start = 0;
@@ -537,7 +529,7 @@ void __init setup_arch(char **cmdline_p,
/* Due to stack alignment restrictions and assumptions... */
init_mm.mmap->vm_page_prot = PAGE_SHARED;
init_mm.mmap->vm_start = PAGE_OFFSET;
- init_mm.mmap->vm_end = *memory_end_p;
+ init_mm.mmap->vm_end = PAGE_OFFSET + highest_paddr;
init_task.thread.kregs = &fake_swapper_regs;
#ifdef CONFIG_IP_PNP
@@ -643,5 +635,12 @@ int get_cpuinfo(char *buffer)
#ifdef __SMP__
len += smp_info(buffer + len);
#endif
+#undef ZS_LOG
+#ifdef ZS_LOG
+ {
+ extern int zs_dumplog(char *);
+ len += zs_dumplog(buffer + len);
+ }
+#endif
return len;
}
diff --git a/arch/sparc64/kernel/signal.c b/arch/sparc64/kernel/signal.c
index f618ab85c..79db5bc4e 100644
--- a/arch/sparc64/kernel/signal.c
+++ b/arch/sparc64/kernel/signal.c
@@ -1,4 +1,4 @@
-/* $Id: signal.c,v 1.45 1999/09/06 08:21:59 jj Exp $
+/* $Id: signal.c,v 1.48 1999/12/15 22:24:52 davem Exp $
* arch/sparc64/kernel/signal.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
diff --git a/arch/sparc64/kernel/signal32.c b/arch/sparc64/kernel/signal32.c
index 949017da3..66e2b0bbe 100644
--- a/arch/sparc64/kernel/signal32.c
+++ b/arch/sparc64/kernel/signal32.c
@@ -1,4 +1,4 @@
-/* $Id: signal32.c,v 1.50 1999/07/30 09:35:25 davem Exp $
+/* $Id: signal32.c,v 1.56 1999/12/20 01:16:16 davem Exp $
* arch/sparc64/kernel/signal32.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
@@ -663,7 +663,8 @@ static inline void new_setup_frame32(struct k_sigaction *ka, struct pt_regs *reg
goto sigsegv;
if(pte_present(*ptep)) {
- unsigned long page = pte_page(*ptep);
+ unsigned long page = (unsigned long)
+ __va(pte_pagenr(*ptep) << PAGE_SHIFT);
__asm__ __volatile__("
membar #StoreStore
@@ -1033,6 +1034,26 @@ static inline void setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs
err |= __put_user(0, &sf->fpu_save);
}
+ /* Update the siginfo structure. Is this good? */
+ if (info->si_code == 0) {
+ info->si_signo = signr;
+ info->si_errno = 0;
+
+ switch (signr) {
+ case SIGSEGV:
+ case SIGILL:
+ case SIGFPE:
+ case SIGBUS:
+ case SIGEMT:
+ info->si_code = current->thread.sig_desc;
+ info->si_addr = (void *)current->thread.sig_address;
+ info->si_trapno = 0;
+ break;
+ default:
+ break;
+ }
+ }
+
err = __put_user (info->si_signo, &sf->info.si_signo);
err |= __put_user (info->si_errno, &sf->info.si_errno);
err |= __put_user (info->si_code, &sf->info.si_code);
@@ -1084,7 +1105,7 @@ static inline void setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs
case 1: seta.sig[1] = (oldset->sig[0] >> 32);
seta.sig[0] = oldset->sig[0];
}
- err |= __copy_to_user(&sf->mask, &seta, sizeof(sigset_t));
+ err |= __copy_to_user(&sf->mask, &seta, sizeof(sigset_t32));
err |= copy_in_user((u32 *)sf,
(u32 *)(regs->u_regs[UREG_FP]),
@@ -1122,7 +1143,8 @@ static inline void setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs
goto sigsegv;
if(pte_present(*ptep)) {
- unsigned long page = pte_page(*ptep);
+ unsigned long page = (unsigned long)
+ __va(pte_pagenr(*ptep) << PAGE_SHIFT);
__asm__ __volatile__("
membar #StoreStore
@@ -1326,7 +1348,8 @@ asmlinkage int do_signal32(sigset_t *oldset, struct pt_regs * regs,
continue;
case SIGQUIT: case SIGILL: case SIGTRAP:
- case SIGABRT: case SIGFPE: case SIGSEGV: case SIGBUS:
+ case SIGABRT: case SIGFPE: case SIGSEGV:
+ case SIGBUS: case SIGSYS: case SIGXCPU: case SIGXFSZ:
if (do_coredump(signr, regs))
exit_code |= 0x80;
#ifdef DEBUG_SIGNALS
diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c
index d1adeb2c7..2fa4945d8 100644
--- a/arch/sparc64/kernel/smp.c
+++ b/arch/sparc64/kernel/smp.c
@@ -94,7 +94,8 @@ void __init smp_store_cpu_info(int id)
cpu_data[id].udelay_val = loops_per_sec;
cpu_data[id].pgcache_size = 0;
- cpu_data[id].pte_cache = NULL;
+ cpu_data[id].pte_cache[0] = NULL;
+ cpu_data[id].pte_cache[1] = NULL;
cpu_data[id].pgdcache_size = 0;
cpu_data[id].pgd_cache = NULL;
cpu_data[id].idle_volume = 1;
@@ -184,7 +185,7 @@ void cpu_panic(void)
extern struct prom_cpuinfo linux_cpus[64];
-extern unsigned long smp_trampoline;
+extern unsigned long sparc64_cpu_startup;
/* The OBP cpu startup callback truncates the 3rd arg cookie to
* 32-bits (I think) so to be safe we have it read the pointer
@@ -210,15 +211,13 @@ void __init smp_boot_cpus(void)
continue;
if(cpu_present_map & (1UL << i)) {
- unsigned long entry = (unsigned long)(&smp_trampoline);
+ unsigned long entry = (unsigned long)(&sparc64_cpu_startup);
unsigned long cookie = (unsigned long)(&cpu_new_task);
struct task_struct *p;
int timeout;
int no;
- extern unsigned long phys_base;
- entry += phys_base - KERNBASE;
- cookie += phys_base - KERNBASE;
+ prom_printf("Starting CPU %d... ", i);
kernel_thread(start_secondary, NULL, CLONE_PID);
cpucount++;
@@ -247,9 +246,11 @@ void __init smp_boot_cpus(void)
cpu_number_map[i] = cpucount;
__cpu_logical_map[cpucount] = i;
prom_cpu_nodes[i] = linux_cpus[no].prom_node;
+ prom_printf("OK\n");
} else {
cpucount--;
printk("Processor %d is stuck.\n", i);
+ prom_printf("FAILED\n");
}
}
if(!callin_flag) {
@@ -537,14 +538,31 @@ void smp_release(void)
/* Imprisoned penguins run with %pil == 15, but PSTATE_IE set, so they
* can service tlb flush xcalls...
*/
+extern void prom_world(int);
+extern void save_alternate_globals(unsigned long *);
+extern void restore_alternate_globals(unsigned long *);
void smp_penguin_jailcell(void)
{
- flushw_user();
+ unsigned long global_save[24];
+
+ __asm__ __volatile__("flushw");
+ save_alternate_globals(global_save);
+ prom_world(1);
atomic_inc(&smp_capture_registry);
membar("#StoreLoad | #StoreStore");
while(penguins_are_doing_time)
membar("#LoadLoad");
+ restore_alternate_globals(global_save);
atomic_dec(&smp_capture_registry);
+ prom_world(0);
+}
+
+extern unsigned long xcall_promstop;
+
+void smp_promstop_others(void)
+{
+ if (smp_processors_ready)
+ smp_cross_call(&xcall_promstop, 0, 0, 0);
}
static inline void sparc64_do_profile(unsigned long pc, unsigned long g3)
@@ -701,14 +719,13 @@ static inline unsigned long find_flush_base(unsigned long size)
/* Failure. */
if(p >= (mem_map + max_mapnr))
return 0UL;
- if(PageSkip(p)) {
- p = p->next_hash;
- base = page_address(p);
+ if(PageReserved(p)) {
found = size;
+ base = page_address(p);
} else {
found -= PAGE_SIZE;
- p++;
}
+ p++;
}
return base;
}
@@ -718,7 +735,7 @@ cycles_t cacheflush_time;
static void __init smp_tune_scheduling (void)
{
unsigned long flush_base, flags, *p;
- unsigned int ecache_size;
+ unsigned int ecache_size, order;
cycles_t tick1, tick2, raw;
/* Approximate heuristic for SMP scheduling. It is an
@@ -733,18 +750,22 @@ static void __init smp_tune_scheduling (void)
*/
printk("SMP: Calibrating ecache flush... ");
ecache_size = prom_getintdefault(linux_cpus[0].prom_node,
- "ecache-size", (512 *1024));
- flush_base = find_flush_base(ecache_size << 1);
-
- if(flush_base != 0UL) {
+ "ecache-size", (512 * 1024));
+ if (ecache_size > (4 * 1024 * 1024))
+ ecache_size = (4 * 1024 * 1024);
+ for (order = 0UL; (PAGE_SIZE << order) < ecache_size; order++)
+ ;
+ flush_base = __get_free_pages(GFP_KERNEL, order);
+
+ if (flush_base != 0UL) {
__save_and_cli(flags);
/* Scan twice the size once just to get the TLB entries
* loaded and make sure the second scan measures pure misses.
*/
- for(p = (unsigned long *)flush_base;
- ((unsigned long)p) < (flush_base + (ecache_size<<1));
- p += (64 / sizeof(unsigned long)))
+ for (p = (unsigned long *)flush_base;
+ ((unsigned long)p) < (flush_base + (ecache_size<<1));
+ p += (64 / sizeof(unsigned long)))
*((volatile unsigned long *)p);
/* Now the real measurement. */
@@ -775,9 +796,12 @@ static void __init smp_tune_scheduling (void)
* sharing the cache and fitting.
*/
cacheflush_time = (raw - (raw >> 2));
- } else
+
+ free_pages(flush_base, order);
+ } else {
cacheflush_time = ((ecache_size << 2) +
(ecache_size << 1));
+ }
printk("Using heuristic of %d cycles.\n",
(int) cacheflush_time);
diff --git a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c
index 434f22bf8..aa28151c8 100644
--- a/arch/sparc64/kernel/sparc64_ksyms.c
+++ b/arch/sparc64/kernel/sparc64_ksyms.c
@@ -1,4 +1,4 @@
-/* $Id: sparc64_ksyms.c,v 1.64 1999/09/05 09:33:38 ecd Exp $
+/* $Id: sparc64_ksyms.c,v 1.70 2000/01/07 18:15:18 jj Exp $
* arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -55,8 +55,6 @@ struct poll {
extern unsigned prom_cpu_nodes[64];
extern void die_if_kernel(char *str, struct pt_regs *regs);
extern pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
-extern unsigned long sunos_mmap(unsigned long, unsigned long, unsigned long,
- unsigned long, unsigned long, unsigned long);
void _sigpause_common (unsigned int set, struct pt_regs *);
extern void *__bzero(void *, size_t);
extern void *__bzero_noasi(void *, size_t);
@@ -82,6 +80,7 @@ extern int svr4_setcontext(svr4_ucontext_t *uc, struct pt_regs *regs);
extern int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg);
extern int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg);
extern int (*handle_mathemu)(struct pt_regs *, struct fpustate *);
+extern long sparc32_open(const char * filename, int flags, int mode);
extern void bcopy (const char *, char *, int);
extern int __ashrdi3(int, int);
@@ -117,11 +116,18 @@ __attribute__((section("__ksymtab"))) = \
/* used by various drivers */
#ifdef __SMP__
+#ifndef SPIN_LOCK_DEBUG
/* Out of line rw-locking implementation. */
EXPORT_SYMBOL_PRIVATE(read_lock);
EXPORT_SYMBOL_PRIVATE(read_unlock);
EXPORT_SYMBOL_PRIVATE(write_lock);
EXPORT_SYMBOL_PRIVATE(write_unlock);
+#endif
+
+/* rw semaphores */
+EXPORT_SYMBOL_NOVERS(__down_read_failed);
+EXPORT_SYMBOL_NOVERS(__down_write_failed);
+EXPORT_SYMBOL_NOVERS(__rwsem_wake);
/* Kernel wide locking */
EXPORT_SYMBOL(kernel_flag);
@@ -175,23 +181,25 @@ EXPORT_SYMBOL_PRIVATE(flushw_user);
EXPORT_SYMBOL(mstk48t02_regs);
EXPORT_SYMBOL(request_fast_irq);
-EXPORT_SYMBOL(sparc_alloc_io);
-EXPORT_SYMBOL(sparc_free_io);
-EXPORT_SYMBOL(sparc_ultra_unmapioaddr);
-EXPORT_SYMBOL(mmu_get_scsi_sgl);
-EXPORT_SYMBOL(mmu_get_scsi_one);
-EXPORT_SYMBOL(sparc_dvma_malloc);
-EXPORT_SYMBOL(mmu_release_scsi_one);
-EXPORT_SYMBOL(mmu_release_scsi_sgl);
#if CONFIG_SBUS
-EXPORT_SYMBOL(mmu_set_sbus64);
-EXPORT_SYMBOL(SBus_chain);
+EXPORT_SYMBOL(sbus_root);
EXPORT_SYMBOL(dma_chain);
+EXPORT_SYMBOL(sbus_set_sbus64);
+EXPORT_SYMBOL(sbus_alloc_consistant);
+EXPORT_SYMBOL(sbus_free_consistant);
+EXPORT_SYMBOL(sbus_map_single);
+EXPORT_SYMBOL(sbus_unmap_single);
+EXPORT_SYMBOL(sbus_map_sg);
+EXPORT_SYMBOL(sbus_unmap_sg);
+EXPORT_SYMBOL(sbus_dma_sync_single);
+EXPORT_SYMBOL(sbus_dma_sync_sg);
#endif
#if CONFIG_PCI
EXPORT_SYMBOL(ebus_chain);
+#ifndef NEW_PCI_DMA_MAP
EXPORT_SYMBOL(pci_dvma_v2p_hash);
EXPORT_SYMBOL(pci_dvma_p2v_hash);
+#endif
EXPORT_SYMBOL(pci_memspace_mask);
EXPORT_SYMBOL(empty_zero_page);
EXPORT_SYMBOL(outsb);
@@ -204,7 +212,6 @@ EXPORT_SYMBOL(insl);
/* Solaris/SunOS binary compatibility */
EXPORT_SYMBOL(_sigpause_common);
-EXPORT_SYMBOL(sunos_mmap);
/* Should really be in linux/kernel/ksyms.c */
EXPORT_SYMBOL(dump_thread);
@@ -229,10 +236,10 @@ EXPORT_SYMBOL(prom_node_has_property);
EXPORT_SYMBOL(prom_setprop);
EXPORT_SYMBOL(saved_command_line);
EXPORT_SYMBOL(prom_getname);
+EXPORT_SYMBOL(prom_finddevice);
EXPORT_SYMBOL(prom_feval);
EXPORT_SYMBOL(prom_getbool);
EXPORT_SYMBOL(prom_getstring);
-EXPORT_SYMBOL(prom_apply_sbus_ranges);
EXPORT_SYMBOL(prom_getint);
EXPORT_SYMBOL(prom_getintdefault);
EXPORT_SYMBOL(__prom_getchild);
@@ -274,6 +281,7 @@ EXPORT_SYMBOL(svr4_setcontext);
EXPORT_SYMBOL(prom_cpu_nodes);
EXPORT_SYMBOL(sys_ioctl);
EXPORT_SYMBOL(sys32_ioctl);
+EXPORT_SYMBOL(sparc32_open);
EXPORT_SYMBOL(move_addr_to_kernel);
EXPORT_SYMBOL(move_addr_to_user);
#endif
@@ -311,5 +319,3 @@ EXPORT_SYMBOL_NOVERS(memcmp);
EXPORT_SYMBOL_NOVERS(memcpy);
EXPORT_SYMBOL_NOVERS(memset);
EXPORT_SYMBOL_NOVERS(memmove);
-
-EXPORT_SYMBOL(get_wchan);
diff --git a/arch/sparc64/kernel/starfire.c b/arch/sparc64/kernel/starfire.c
index 805dce338..3237b37dc 100644
--- a/arch/sparc64/kernel/starfire.c
+++ b/arch/sparc64/kernel/starfire.c
@@ -1,4 +1,4 @@
-/* $Id: starfire.c,v 1.3 1999/08/30 10:01:13 davem Exp $
+/* $Id: starfire.c,v 1.4 1999/09/21 14:35:25 davem Exp $
* starfire.c: Starfire/E10000 support.
*
* Copyright (C) 1998 David S. Miller (davem@dm.cobaltmicro.com)
@@ -10,6 +10,7 @@
#include <asm/page.h>
#include <asm/oplib.h>
#include <asm/smp.h>
+#include <asm/upa.h>
/* A few places around the kernel check this to see if
* they need to call us to do things in a Starfire specific
@@ -43,7 +44,7 @@ void starfire_check(void)
int starfire_hard_smp_processor_id(void)
{
- return *((volatile unsigned int *) __va(0x1fff40000d0));
+ return upa_readl(0x1fff40000d0UL);
}
/* Each Starfire board has 32 registers which perform translation
@@ -52,8 +53,8 @@ int starfire_hard_smp_processor_id(void)
* bits than in all previous Sun5 systems.
*/
struct starfire_irqinfo {
- volatile unsigned int *imap_slots[32];
- volatile unsigned int *tregs[32];
+ unsigned long imap_slots[32];
+ unsigned long tregs[32];
struct starfire_irqinfo *next;
int upaid, hwmid;
};
@@ -79,8 +80,8 @@ void *starfire_hookup(int upaid)
treg_base += (hwmid << 33UL);
treg_base += 0x200UL;
for(i = 0; i < 32; i++) {
- p->imap_slots[i] = NULL;
- p->tregs[i] = (volatile unsigned int *)__va(treg_base + (i * 0x10));
+ p->imap_slots[i] = 0UL;
+ p->tregs[i] = treg_base + (i * 0x10UL);
}
p->upaid = upaid;
p->next = sflist;
@@ -89,7 +90,7 @@ void *starfire_hookup(int upaid)
return (void *) p;
}
-unsigned int starfire_translate(volatile unsigned int *imap,
+unsigned int starfire_translate(unsigned long imap,
unsigned int upaid)
{
struct starfire_irqinfo *p;
@@ -107,7 +108,7 @@ unsigned int starfire_translate(volatile unsigned int *imap,
}
for(i = 0; i < 32; i++) {
if(p->imap_slots[i] == imap ||
- p->imap_slots[i] == NULL)
+ p->imap_slots[i] == 0UL)
break;
}
if(i == 32) {
@@ -115,7 +116,7 @@ unsigned int starfire_translate(volatile unsigned int *imap,
panic("Lucy in the sky....");
}
p->imap_slots[i] = imap;
- *(p->tregs[i]) = upaid;
+ upa_writel(upaid, p->tregs[i]);
return i;
}
diff --git a/arch/sparc64/kernel/sys32.S b/arch/sparc64/kernel/sys32.S
index fd1ff6a0b..4b461fbee 100644
--- a/arch/sparc64/kernel/sys32.S
+++ b/arch/sparc64/kernel/sys32.S
@@ -1,4 +1,4 @@
-/* $Id: sys32.S,v 1.8 1998/10/28 08:10:37 jj Exp $
+/* $Id: sys32.S,v 1.9 1999/12/21 14:09:18 jj Exp $
* sys32.S: I-cache tricks for 32-bit compatability layer simple
* conversions.
*
@@ -74,3 +74,12 @@ sys32_bdflush:
sethi %hi(sys_bdflush), %g1
jmpl %g1 + %lo(sys_bdflush), %g0
sra %o1, 0, %o1
+
+ .align 32
+ .globl sys32_mmap2
+sys32_mmap2:
+ srl %o4, 0, %o4
+ sethi %hi(sys_mmap), %g1
+ srl %o5, 0, %o5
+ jmpl %g1 + %lo(sys_mmap), %g0
+ sllx %o5, 12, %o5
diff --git a/arch/sparc64/kernel/sys_sparc.c b/arch/sparc64/kernel/sys_sparc.c
index 4e87819d4..486a09d99 100644
--- a/arch/sparc64/kernel/sys_sparc.c
+++ b/arch/sparc64/kernel/sys_sparc.c
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc.c,v 1.29 1999/08/04 07:04:10 jj Exp $
+/* $Id: sys_sparc.c,v 1.32 2000/01/05 01:00:40 davem Exp $
* linux/arch/sparc64/kernel/sys_sparc.c
*
* This file contains various random system calls that
@@ -6,6 +6,7 @@
* platform.
*/
+#include <linux/config.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/sched.h>
@@ -156,15 +157,16 @@ asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len,
struct file * file = NULL;
unsigned long retval = -EBADF;
- down(&current->mm->mmap_sem);
- lock_kernel();
if (!(flags & MAP_ANONYMOUS)) {
file = fget(fd);
if (!file)
goto out;
}
+ flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
retval = -ENOMEM;
len = PAGE_ALIGN(len);
+ down(&current->mm->mmap_sem);
+ lock_kernel();
if(!(flags & MAP_FIXED) && !addr) {
addr = get_unmapped_area(addr, len);
if(!addr)
@@ -187,15 +189,14 @@ asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len,
}
}
- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
retval = do_mmap(file, addr, len, prot, flags, off);
out_putf:
+ unlock_kernel();
+ up(&current->mm->mmap_sem);
if (file)
fput(file);
out:
- unlock_kernel();
- up(&current->mm->mmap_sem);
return retval;
}
@@ -275,6 +276,21 @@ asmlinkage int solaris_syscall(struct pt_regs *regs)
return -ENOSYS;
}
+#ifndef CONFIG_SUNOS_EMUL
+asmlinkage int sunos_syscall(struct pt_regs *regs)
+{
+ static int count = 0;
+ lock_kernel();
+ regs->tpc = regs->tnpc;
+ regs->tnpc += 4;
+ if(++count <= 20)
+ printk ("SunOS binary emulation not compiled in\n");
+ force_sig(SIGSEGV, current);
+ unlock_kernel();
+ return -ENOSYS;
+}
+#endif
+
asmlinkage int sys_utrap_install(utrap_entry_t type, utrap_handler_t new_p,
utrap_handler_t new_d,
utrap_handler_t *old_p, utrap_handler_t *old_d)
diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c
index e394ec35b..f9be1320e 100644
--- a/arch/sparc64/kernel/sys_sparc32.c
+++ b/arch/sparc64/kernel/sys_sparc32.c
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc32.c,v 1.118 1999/08/30 10:01:15 davem Exp $
+/* $Id: sys_sparc32.c,v 1.127 2000/01/04 23:54:41 davem Exp $
* sys_sparc32.c: Conversion between 32bit and 64bit native syscalls.
*
* Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -12,6 +12,7 @@
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/fs.h>
+#include <linux/mm.h>
#include <linux/file.h>
#include <linux/signal.h>
#include <linux/utime.h>
@@ -40,6 +41,8 @@
#include <linux/poll.h>
#include <linux/personality.h>
#include <linux/stat.h>
+#include <linux/filter.h>
+#include <linux/highmem.h>
#include <asm/types.h>
#include <asm/ipc.h>
@@ -712,6 +715,25 @@ asmlinkage int sys32_fstatfs(unsigned int fd, struct statfs32 *buf)
return ret;
}
+extern asmlinkage long sys_truncate(const char * path, unsigned long length);
+extern asmlinkage long sys_ftruncate(unsigned int fd, unsigned long length);
+
+asmlinkage int sys32_truncate64(const char * path, unsigned long high, unsigned long low)
+{
+ if ((int)high < 0)
+ return -EINVAL;
+ else
+ return sys_truncate(path, (high << 32) | low);
+}
+
+asmlinkage int sys32_ftruncate64(unsigned int fd, unsigned long high, unsigned long low)
+{
+ if ((int)high < 0)
+ return -EINVAL;
+ else
+ return sys_ftruncate(fd, (high << 32) | low);
+}
+
extern asmlinkage int sys_utime(char * filename, struct utimbuf * times);
struct utimbuf32 {
@@ -1125,8 +1147,10 @@ asmlinkage int sys32_select(int n, u32 *inp, u32 *outp, u32 *exp, u32 tvp_x)
}
ret = -EINVAL;
- if (n < 0 || n > KFDS_NR)
+ if (n < 0)
goto out_nofds;
+ if (n > current->files->max_fdset)
+ n = current->files->max_fdset;
/*
* We need 6 bitmaps (in/out/ex for both incoming and outgoing),
@@ -1186,84 +1210,157 @@ out_nofds:
return ret;
}
-static inline int putstat(struct stat32 *ubuf, struct stat *kbuf)
+static int cp_new_stat32(struct inode *inode, struct stat32 *statbuf)
{
+ unsigned long ino, blksize, blocks;
+ kdev_t dev, rdev;
+ umode_t mode;
+ nlink_t nlink;
+ uid_t uid;
+ gid_t gid;
+ off_t size;
+ time_t atime, mtime, ctime;
int err;
-
- err = put_user (kbuf->st_dev, &ubuf->st_dev);
- err |= __put_user (kbuf->st_ino, &ubuf->st_ino);
- err |= __put_user (kbuf->st_mode, &ubuf->st_mode);
- err |= __put_user (kbuf->st_nlink, &ubuf->st_nlink);
- err |= __put_user (kbuf->st_uid, &ubuf->st_uid);
- err |= __put_user (kbuf->st_gid, &ubuf->st_gid);
- err |= __put_user (kbuf->st_rdev, &ubuf->st_rdev);
- err |= __put_user (kbuf->st_size, &ubuf->st_size);
- err |= __put_user (kbuf->st_atime, &ubuf->st_atime);
- err |= __put_user (kbuf->st_mtime, &ubuf->st_mtime);
- err |= __put_user (kbuf->st_ctime, &ubuf->st_ctime);
- err |= __put_user (kbuf->st_blksize, &ubuf->st_blksize);
- err |= __put_user (kbuf->st_blocks, &ubuf->st_blocks);
+
+ /* Stream the loads of inode data into the load buffer,
+ * then we push it all into the store buffer below. This
+ * should give optimal cache performance.
+ */
+ ino = inode->i_ino;
+ dev = inode->i_dev;
+ mode = inode->i_mode;
+ nlink = inode->i_nlink;
+ uid = inode->i_uid;
+ gid = inode->i_gid;
+ rdev = inode->i_rdev;
+ size = inode->i_size;
+ atime = inode->i_atime;
+ mtime = inode->i_mtime;
+ ctime = inode->i_ctime;
+ blksize = inode->i_blksize;
+ blocks = inode->i_blocks;
+
+ err = put_user(kdev_t_to_nr(dev), &statbuf->st_dev);
+ err |= put_user(ino, &statbuf->st_ino);
+ err |= put_user(mode, &statbuf->st_mode);
+ err |= put_user(nlink, &statbuf->st_nlink);
+ err |= put_user(uid, &statbuf->st_uid);
+ err |= put_user(gid, &statbuf->st_gid);
+ err |= put_user(kdev_t_to_nr(rdev), &statbuf->st_rdev);
+ err |= put_user(size, &statbuf->st_size);
+ err |= put_user(atime, &statbuf->st_atime);
+ err |= put_user(0, &statbuf->__unused1);
+ err |= put_user(mtime, &statbuf->st_mtime);
+ err |= put_user(0, &statbuf->__unused2);
+ err |= put_user(ctime, &statbuf->st_ctime);
+ err |= put_user(0, &statbuf->__unused3);
+ if (blksize) {
+ err |= put_user(blksize, &statbuf->st_blksize);
+ err |= put_user(blocks, &statbuf->st_blocks);
+ } else {
+ unsigned int tmp_blocks;
+
+#define D_B 7
+#define I_B (BLOCK_SIZE / sizeof(unsigned short))
+ tmp_blocks = (size + BLOCK_SIZE - 1) / BLOCK_SIZE;
+ if (tmp_blocks > D_B) {
+ unsigned int indirect;
+
+ indirect = (tmp_blocks - D_B + I_B - 1) / I_B;
+ tmp_blocks += indirect;
+ if (indirect > 1) {
+ indirect = (indirect - 1 + I_B - 1) / I_B;
+ tmp_blocks += indirect;
+ if (indirect > 1)
+ tmp_blocks++;
+ }
+ }
+ err |= put_user(BLOCK_SIZE, &statbuf->st_blksize);
+ err |= put_user((BLOCK_SIZE / 512) * tmp_blocks, &statbuf->st_blocks);
+#undef D_B
+#undef I_B
+ }
+ err |= put_user(0, &statbuf->__unused4[0]);
+ err |= put_user(0, &statbuf->__unused4[1]);
+
return err;
}
-extern asmlinkage int sys_newstat(char * filename, struct stat * statbuf);
-
asmlinkage int sys32_newstat(char * filename, struct stat32 *statbuf)
{
- int ret;
- struct stat s;
- char *filenam;
- mm_segment_t old_fs = get_fs();
-
- filenam = getname32 (filename);
- ret = PTR_ERR(filenam);
- if (!IS_ERR(filenam)) {
- set_fs (KERNEL_DS);
- ret = sys_newstat(filenam, &s);
- set_fs (old_fs);
- putname (filenam);
- if (putstat (statbuf, &s))
- return -EFAULT;
+ struct dentry *dentry;
+ int error;
+
+ lock_kernel();
+ dentry = namei(filename);
+
+ error = PTR_ERR(dentry);
+ if (!IS_ERR(dentry)) {
+ struct inode *inode = dentry->d_inode;
+
+ if (inode->i_op &&
+ inode->i_op->revalidate)
+ error = inode->i_op->revalidate(dentry);
+ else
+ error = 0;
+ if (!error)
+ error = cp_new_stat32(inode, statbuf);
+
+ dput(dentry);
}
- return ret;
+ unlock_kernel();
+ return error;
}
-extern asmlinkage int sys_newlstat(char * filename, struct stat * statbuf);
-
asmlinkage int sys32_newlstat(char * filename, struct stat32 *statbuf)
{
- int ret;
- struct stat s;
- char *filenam;
- mm_segment_t old_fs = get_fs();
-
- filenam = getname32 (filename);
- ret = PTR_ERR(filenam);
- if (!IS_ERR(filenam)) {
- set_fs (KERNEL_DS);
- ret = sys_newlstat(filenam, &s);
- set_fs (old_fs);
- putname (filenam);
- if (putstat (statbuf, &s))
- return -EFAULT;
+ struct dentry *dentry;
+ int error;
+
+ lock_kernel();
+ dentry = lnamei(filename);
+
+ error = PTR_ERR(dentry);
+ if (!IS_ERR(dentry)) {
+ struct inode *inode = dentry->d_inode;
+
+ if (inode->i_op &&
+ inode->i_op->revalidate)
+ error = inode->i_op->revalidate(dentry);
+ else
+ error = 0;
+ if (!error)
+ error = cp_new_stat32(inode, statbuf);
+
+ dput(dentry);
}
- return ret;
+ unlock_kernel();
+ return error;
}
-extern asmlinkage int sys_newfstat(unsigned int fd, struct stat * statbuf);
-
asmlinkage int sys32_newfstat(unsigned int fd, struct stat32 *statbuf)
{
- int ret;
- struct stat s;
- mm_segment_t old_fs = get_fs();
-
- set_fs (KERNEL_DS);
- ret = sys_newfstat(fd, &s);
- set_fs (old_fs);
- if (putstat (statbuf, &s))
- return -EFAULT;
- return ret;
+ struct file *f;
+ int err = -EBADF;
+
+ lock_kernel();
+ f = fget(fd);
+ if (f) {
+ struct dentry *dentry = f->f_dentry;
+ struct inode *inode = dentry->d_inode;
+
+ if (inode->i_op &&
+ inode->i_op->revalidate)
+ err = inode->i_op->revalidate(dentry);
+ else
+ err = 0;
+ if (!err)
+ err = cp_new_stat32(inode, statbuf);
+
+ fput(f);
+ }
+ unlock_kernel();
+ return err;
}
extern asmlinkage int sys_sysfs(int option, unsigned long arg1, unsigned long arg2);
@@ -1912,8 +2009,8 @@ asmlinkage int sys32_setgroups(int gidsetsize, __kernel_gid_t32 *grouplist)
#define RESOURCE32(x) ((x > RLIM_INFINITY32) ? RLIM_INFINITY32 : x)
struct rlimit32 {
- s32 rlim_cur;
- s32 rlim_max;
+ u32 rlim_cur;
+ u32 rlim_max;
};
extern asmlinkage int sys_getrlimit(unsigned int resource, struct rlimit *rlim);
@@ -2523,6 +2620,48 @@ out:
return len;
}
+extern asmlinkage int sys_setsockopt(int fd, int level, int optname,
+ char *optval, int optlen);
+
+asmlinkage int sys32_setsockopt(int fd, int level, int optname,
+ char *optval, int optlen)
+{
+ if (optname == SO_ATTACH_FILTER) {
+ struct sock_fprog32 {
+ __u16 len;
+ __u32 filter;
+ } *fprog32 = (struct sock_fprog32 *)optval;
+ struct sock_fprog kfprog;
+ struct sock_filter *kfilter;
+ unsigned int fsize;
+ mm_segment_t old_fs;
+ __u32 uptr;
+ int ret;
+
+ if (get_user(kfprog.len, &fprog32->len) ||
+ __get_user(uptr, &fprog32->filter))
+ return -EFAULT;
+ kfprog.filter = (struct sock_filter *)A(uptr);
+ fsize = kfprog.len * sizeof(struct sock_filter);
+ kfilter = (struct sock_filter *)kmalloc(fsize, GFP_KERNEL);
+ if (kfilter == NULL)
+ return -ENOMEM;
+ if (copy_from_user(kfilter, kfprog.filter, fsize)) {
+ kfree(kfilter);
+ return -EFAULT;
+ }
+ kfprog.filter = kfilter;
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+ ret = sys_setsockopt(fd, level, optname,
+ (char *)&kfprog, sizeof(kfprog));
+ set_fs(old_fs);
+ kfree(kfilter);
+ return ret;
+ }
+ return sys_setsockopt(fd, level, optname, optval, optlen);
+}
+
/* Argument list sizes for sys_socketcall */
#define AL(x) ((x) * sizeof(u32))
static unsigned char nargs[18]={AL(0),AL(3),AL(3),AL(3),AL(2),AL(3),
@@ -2541,8 +2680,6 @@ extern asmlinkage int sys32_sendto(int fd, u32 buff, __kernel_size_t32 len,
extern asmlinkage int sys_recv(int fd, void *ubuf, size_t size, unsigned flags);
extern asmlinkage int sys32_recvfrom(int fd, u32 ubuf, __kernel_size_t32 size,
unsigned flags, u32 addr, u32 addr_len);
-extern asmlinkage int sys_setsockopt(int fd, int level, int optname,
- char *optval, int optlen);
extern asmlinkage int sys32_getsockopt(int fd, int level, int optname,
u32 optval, u32 optlen);
@@ -2593,7 +2730,7 @@ asmlinkage int sys32_socketcall(int call, u32 *args)
case SYS_SHUTDOWN:
return sys_shutdown(a0,a1);
case SYS_SETSOCKOPT:
- return sys_setsockopt(a0, a1, a[2], (char *)A(a[3]), a[4]);
+ return sys32_setsockopt(a0, a1, a[2], (char *)A(a[3]), a[4]);
case SYS_GETSOCKOPT:
return sys32_getsockopt(a0, a1, a[2], a[3], a[4]);
case SYS_SENDMSG:
@@ -2727,8 +2864,9 @@ static int copy_strings32(int argc, u32 * argv, struct linux_binprm *bprm)
if (get_user(str, argv + argc) ||
!str ||
- !(len = strlen_user((char *)A(str))))
+ !(len = strnlen_user((char *)A(str), bprm->p)))
return -EFAULT;
+
if (bprm->p < len)
return -E2BIG;
@@ -2736,20 +2874,38 @@ static int copy_strings32(int argc, u32 * argv, struct linux_binprm *bprm)
pos = bprm->p;
while (len) {
- char *pag;
- int offset, bytes_to_copy;
+ char *kaddr;
+ struct page *page;
+ int offset, bytes_to_copy, new, err;
offset = pos % PAGE_SIZE;
- if (!(pag = (char *) bprm->page[pos/PAGE_SIZE]) &&
- !(pag = (char *) bprm->page[pos/PAGE_SIZE] =
- (unsigned long *) get_free_page(GFP_USER)))
- return -ENOMEM;
+ page = bprm->page[pos / PAGE_SIZE];
+ new = 0;
+ if (!page) {
+ page = alloc_page(GFP_USER);
+ bprm->page[pos / PAGE_SIZE] = page;
+ if (!page)
+ return -ENOMEM;
+ new = 1;
+ }
+ kaddr = (char *)kmap(page);
+ if (new && offset)
+ memset(kaddr, 0, offset);
bytes_to_copy = PAGE_SIZE - offset;
- if (bytes_to_copy > len)
+ if (bytes_to_copy > len) {
bytes_to_copy = len;
+ if (new)
+ memset(kaddr+offset+len, 0,
+ PAGE_SIZE-offset-len);
+ }
- if (copy_from_user(pag + offset, (char *)A(str), bytes_to_copy))
+ err = copy_from_user(kaddr + offset, (char *)A(str),
+ bytes_to_copy);
+ flush_page_to_ram(page);
+ kunmap((unsigned long)kaddr);
+
+ if (err)
return -EFAULT;
pos += bytes_to_copy;
@@ -2772,8 +2928,7 @@ do_execve32(char * filename, u32 * argv, u32 * envp, struct pt_regs * regs)
int i;
bprm.p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *);
- for (i=0 ; i<MAX_ARG_PAGES ; i++) /* clear page-table */
- bprm.page[i] = 0;
+ memset(bprm.page, 0, MAX_ARG_PAGES * sizeof(bprm.page[0]));
dentry = open_namei(filename, 0, 0);
retval = PTR_ERR(dentry);
@@ -2822,7 +2977,8 @@ out:
dput(bprm.dentry);
for (i=0 ; i<MAX_ARG_PAGES ; i++)
- free_page(bprm.page[i]);
+ if (bprm.page[i])
+ __free_page(bprm.page[i]);
return retval;
}
@@ -3843,3 +3999,37 @@ asmlinkage int sys32_adjtimex(struct timex32 *utp)
return ret;
}
+
+/* This is just a version for 32-bit applications which does
+ * not force O_LARGEFILE on.
+ */
+
+asmlinkage long sparc32_open(const char * filename, int flags, int mode)
+{
+ char * tmp;
+ int fd, error;
+
+ tmp = getname(filename);
+ fd = PTR_ERR(tmp);
+ if (!IS_ERR(tmp)) {
+ fd = get_unused_fd();
+ if (fd >= 0) {
+ struct file * f;
+ lock_kernel();
+ f = filp_open(tmp, flags, mode);
+ unlock_kernel();
+ error = PTR_ERR(f);
+ if (IS_ERR(f))
+ goto out_error;
+ fd_install(fd, f);
+ }
+out:
+ putname(tmp);
+ }
+ return fd;
+
+out_error:
+ put_unused_fd(fd);
+ fd = error;
+ goto out;
+}
diff --git a/arch/sparc64/kernel/sys_sunos32.c b/arch/sparc64/kernel/sys_sunos32.c
index 0f0c2a536..ffc72b74d 100644
--- a/arch/sparc64/kernel/sys_sunos32.c
+++ b/arch/sparc64/kernel/sys_sunos32.c
@@ -1,4 +1,4 @@
-/* $Id: sys_sunos32.c,v 1.31 1999/08/30 10:01:19 davem Exp $
+/* $Id: sys_sunos32.c,v 1.35 2000/01/06 23:51:50 davem Exp $
* sys_sunos32.c: SunOS binary compatability layer on sparc64.
*
* Copyright (C) 1995, 1996, 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -162,10 +162,10 @@ asmlinkage int sunos_brk(u32 baddr)
* simple, it hopefully works in most obvious cases.. Easy to
* fool it, but this should catch most mistakes.
*/
- freepages = atomic_read(&buffermem) >> PAGE_SHIFT;
+ freepages = atomic_read(&buffermem_pages) >> PAGE_SHIFT;
freepages += atomic_read(&page_cache_size);
freepages >>= 1;
- freepages += nr_free_pages;
+ freepages += nr_free_pages();
freepages += nr_swap_pages;
freepages -= num_physpages >> 4;
freepages -= (newbrk-oldbrk) >> PAGE_SHIFT;
@@ -685,7 +685,7 @@ struct sunos_nfs_mount_args {
char *netname; /* server's netname */
};
-extern int do_mount(kdev_t, const char *, const char *, char *, int, void *);
+extern int do_mount(struct block_device *, const char *, const char *, char *, int, void *);
extern dev_t get_unnamed_dev(void);
extern void put_unnamed_dev(dev_t);
extern asmlinkage int sys_mount(char *, char *, char *, unsigned long, void *);
@@ -762,12 +762,10 @@ static int get_default (int value, int def_value)
/* XXXXXXXXXXXXXXXXXXXX */
asmlinkage int sunos_nfs_mount(char *dir_name, int linux_flags, void *data)
{
- int ret = -ENODEV;
int server_fd;
char *the_name;
struct nfs_mount_data linux_nfs_mount;
struct sunos_nfs_mount_args *sunos_mount = data;
- dev_t dev;
/* Ok, here comes the fun part: Linux's nfs mount needs a
* socket connection to the server, but SunOS mount does not
@@ -809,13 +807,7 @@ asmlinkage int sunos_nfs_mount(char *dir_name, int linux_flags, void *data)
linux_nfs_mount.hostname [255] = 0;
putname (the_name);
- dev = get_unnamed_dev ();
-
- ret = do_mount (dev, "", dir_name, "nfs", linux_flags, &linux_nfs_mount);
- if (ret)
- put_unnamed_dev(dev);
-
- return ret;
+ return do_mount (NULL, "", dir_name, "nfs", linux_flags, &linux_nfs_mount);
}
/* XXXXXXXXXXXXXXXXXXXX */
@@ -1274,15 +1266,14 @@ asmlinkage int sunos_shmsys(int op, u32 arg1, u32 arg2, u32 arg3)
return rval;
}
-asmlinkage int sunos_open(u32 filename, int flags, int mode)
+extern asmlinkage long sparc32_open(const char * filename, int flags, int mode);
+
+asmlinkage int sunos_open(u32 fname, int flags, int mode)
{
- int ret;
+ const char *filename = (const char *)(long)fname;
- lock_kernel();
current->personality |= PER_BSD;
- ret = sys_open ((char *)A(filename), flags, mode);
- unlock_kernel();
- return ret;
+ return sparc32_open(filename, flags, mode);
}
#define SUNOS_EWOULDBLOCK 35
diff --git a/arch/sparc64/kernel/systbls.S b/arch/sparc64/kernel/systbls.S
index 06a827db2..27355da96 100644
--- a/arch/sparc64/kernel/systbls.S
+++ b/arch/sparc64/kernel/systbls.S
@@ -1,4 +1,4 @@
-/* $Id: systbls.S,v 1.56 1999/07/31 00:06:17 davem Exp $
+/* $Id: systbls.S,v 1.62 2000/01/04 23:54:43 davem Exp $
* systbls.S: System call entry point tables for OS compatibility.
* The native Linux system call table lives here also.
*
@@ -10,6 +10,8 @@
* Copyright (C) 1995 Adrian M. Rodriguez (adrian@remus.rutgers.edu)
*/
+#include <linux/config.h>
+
.text
.align 1024
@@ -18,7 +20,7 @@
.globl sys_call_table32
sys_call_table32:
/*0*/ .word sys_nis_syscall, sparc_exit, sys_fork, sys_read, sys_write
-/*5*/ .word sys_open, sys_close, sys32_wait4, sys_creat, sys_link
+/*5*/ .word sparc32_open, sys_close, sys32_wait4, sys_creat, sys_link
/*10*/ .word sys_unlink, sunos_execv, sys_chdir, sys32_chown, sys32_mknod
/*15*/ .word sys32_chmod, sys32_lchown, sparc_brk, sys_perfctr, sys32_lseek
/*20*/ .word sys_getpid, sys_capget, sys_capset, sys_setuid, sys_getuid
@@ -28,12 +30,12 @@ sys_call_table32:
/*40*/ .word sys32_newlstat, sys_dup, sys_pipe, sys32_times, sys_nis_syscall
.word sys_umount, sys_setgid, sys_getgid, sys_signal, sys_geteuid
/*50*/ .word sys_getegid, sys_acct, sys_nis_syscall, sys_nis_syscall, sys32_ioctl
- .word sys_reboot, sys_nis_syscall, sys_symlink, sys_readlink, sys32_execve
-/*60*/ .word sys_umask, sys_chroot, sys32_newfstat, sys_nis_syscall, sys_getpagesize
+ .word sys_reboot, sys32_mmap2, sys_symlink, sys_readlink, sys32_execve
+/*60*/ .word sys_umask, sys_chroot, sys32_newfstat, sys_fstat64, sys_getpagesize
.word sys_msync, sys_vfork, sys32_pread, sys32_pwrite, sys_nis_syscall
/*70*/ .word sys_nis_syscall, sys32_mmap, sys_nis_syscall, sys_munmap, sys_mprotect
- .word sys_nis_syscall, sys_vhangup, sys_nis_syscall, sys_nis_syscall, sys32_getgroups
-/*80*/ .word sys32_setgroups, sys_getpgrp, sys_nis_syscall, sys32_setitimer, sys_nis_syscall
+ .word sys_nis_syscall, sys_vhangup, sys32_truncate64, sys_nis_syscall, sys32_getgroups
+/*80*/ .word sys32_setgroups, sys_getpgrp, sys_nis_syscall, sys32_setitimer, sys32_ftruncate64
.word sys_swapon, sys32_getitimer, sys_nis_syscall, sys_sethostname, sys_nis_syscall
/*90*/ .word sys_dup2, sys_nis_syscall, sys32_fcntl, sys32_select, sys_nis_syscall
.word sys_fsync, sys_setpriority, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
@@ -43,8 +45,8 @@ sys_call_table32:
.word sys_nis_syscall, sys32_gettimeofday, sys32_getrusage, sys_nis_syscall, sys_getcwd
/*120*/ .word sys32_readv, sys32_writev, sys32_settimeofday, sys_fchown, sys_fchmod
.word sys_nis_syscall, sys32_setreuid, sys32_setregid, sys_rename, sys_truncate
-/*130*/ .word sys_ftruncate, sys_flock, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
- .word sys_nis_syscall, sys_mkdir, sys_rmdir, sys32_utimes, sys_nis_syscall
+/*130*/ .word sys_ftruncate, sys_flock, sys_lstat64, sys_nis_syscall, sys_nis_syscall
+ .word sys_nis_syscall, sys_mkdir, sys_rmdir, sys32_utimes, sys_stat64
/*140*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_getrlimit
.word sys32_setrlimit, sys_nis_syscall, sys32_prctl, sys32_pciconfig_read, sys32_pciconfig_write
/*150*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_nis_syscall
@@ -129,6 +131,8 @@ sys_call_table:
/*250*/ .word sys_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl
.word sys_aplib
+#if defined(CONFIG_SUNOS_EMUL) || defined(CONFIG_SOLARIS_EMUL) || \
+ defined(CONFIG_SOLARIS_EMUL_MODULE)
/* Now the 32-bit SunOS syscall table. */
.align 1024
@@ -221,3 +225,5 @@ sunos_sys_table:
.word sunos_nosys, sunos_nosys
/*250*/ .word sunos_nosys, sunos_nosys, sunos_nosys
.word sunos_nosys, sunos_nosys, sys_aplib
+
+#endif
diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c
index 60d5e4a5f..57f5b1622 100644
--- a/arch/sparc64/kernel/time.c
+++ b/arch/sparc64/kernel/time.c
@@ -1,4 +1,4 @@
-/* $Id: time.c,v 1.22 1999/08/30 10:01:22 davem Exp $
+/* $Id: time.c,v 1.23 1999/09/21 14:35:27 davem Exp $
* time.c: UltraSparc timer and TOD clock support.
*
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -268,7 +268,7 @@ void __init clock_probe(void)
int node, busnd = -1, err;
unsigned long flags;
#ifdef CONFIG_PCI
- struct linux_ebus *ebus = 0;
+ struct linux_ebus *ebus = NULL;
#endif
__save_and_cli(flags);
@@ -282,8 +282,8 @@ void __init clock_probe(void)
busnd = ebus->prom_node;
}
#endif
- else {
- busnd = SBus_chain->prom_node;
+ else if (sbus_root != NULL) {
+ busnd = sbus_root->prom_node;
}
if(busnd == -1) {
@@ -304,9 +304,9 @@ void __init clock_probe(void)
if (node)
node = prom_getsibling(node);
#ifdef CONFIG_PCI
- while ((node == 0) && ebus) {
+ while ((node == 0) && ebus != NULL) {
ebus = ebus->next;
- if (ebus) {
+ if (ebus != NULL) {
busnd = ebus->prom_node;
node = prom_getchild(busnd);
}
@@ -327,17 +327,17 @@ void __init clock_probe(void)
}
if(central_bus) {
- prom_apply_fhc_ranges(central_bus->child, clk_reg, 1);
- prom_apply_central_ranges(central_bus, clk_reg, 1);
+ apply_fhc_ranges(central_bus->child, clk_reg, 1);
+ apply_central_ranges(central_bus, clk_reg, 1);
}
#ifdef CONFIG_PCI
- else if (ebus_chain) {
+ else if (ebus_chain != NULL) {
struct linux_ebus_device *edev;
for_each_ebusdev(edev, ebus)
if (edev->prom_node == node)
break;
- if (!edev) {
+ if (edev == NULL) {
prom_printf("%s: Mostek not probed by EBUS\n",
__FUNCTION__);
prom_halt();
@@ -349,9 +349,24 @@ void __init clock_probe(void)
}
#endif
else {
- prom_adjust_regs(clk_reg, 1,
- SBus_chain->sbus_ranges,
- SBus_chain->num_sbus_ranges);
+ if (sbus_root->num_sbus_ranges) {
+ int nranges = sbus_root->num_sbus_ranges;
+ int rngc;
+
+ for (rngc = 0; rngc < nranges; rngc++)
+ if (clk_reg[0].which_io ==
+ sbus_root->sbus_ranges[rngc].ot_child_space)
+ break;
+ if (rngc == nranges) {
+ prom_printf("clock_probe: Cannot find ranges for "
+ "clock regs.\n");
+ prom_halt();
+ }
+ clk_reg[0].which_io =
+ sbus_root->sbus_ranges[rngc].ot_parent_space;
+ clk_reg[0].phys_addr +=
+ sbus_root->sbus_ranges[rngc].ot_parent_base;
+ }
}
if(model[5] == '0' && model[6] == '2') {
diff --git a/arch/sparc64/kernel/trampoline.S b/arch/sparc64/kernel/trampoline.S
index 6efbe1356..4f2606c97 100644
--- a/arch/sparc64/kernel/trampoline.S
+++ b/arch/sparc64/kernel/trampoline.S
@@ -1,4 +1,4 @@
-/* $Id: trampoline.S,v 1.10 1999/09/10 10:40:48 davem Exp $
+/* $Id: trampoline.S,v 1.12 1999/12/15 15:45:12 davem Exp $
* trampoline.S: Jump start slave processors on sparc64.
*
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -14,21 +14,107 @@
#include <asm/asm_offsets.h>
.data
- .align 8
- .globl smp_trampoline
-smp_trampoline: .skip 0x300
+ .align 8
+call_method:
+ .asciz "call-method"
+ .align 8
+itlb_load:
+ .asciz "SUNW,itlb-load"
+ .align 8
+dtlb_load:
+ .asciz "SUNW,dtlb-load"
.text
.align 8
.globl sparc64_cpu_startup, sparc64_cpu_startup_end
sparc64_cpu_startup:
flushw
+
mov (LSU_CONTROL_IC | LSU_CONTROL_DC | LSU_CONTROL_IM | LSU_CONTROL_DM), %g1
stxa %g1, [%g0] ASI_LSU_CONTROL
membar #Sync
- wrpr %g0, (PSTATE_PRIV | PSTATE_PEF | PSTATE_IE), %pstate
- wr %g0, 0, %fprs
+
wrpr %g0, 15, %pil
+ wr %g0, 0, %tick_cmpr
+
+ /* Call OBP by hand to lock KERNBASE into i/d tlbs. */
+ mov %o0, %l0
+
+ sethi %hi(prom_entry_lock), %g2
+1: ldstub [%g2 + %lo(prom_entry_lock)], %g1
+ brnz,pn %g1, 1b
+ membar #StoreLoad | #StoreStore
+
+ sethi %hi(p1275buf), %g2
+ or %g2, %lo(p1275buf), %g2
+ ldx [%g2 + 0x10], %l2
+ mov %sp, %l1
+ add %l2, -(192 + 128), %sp
+ flushw
+
+ sethi %hi(call_method), %g2
+ or %g2, %lo(call_method), %g2
+ stx %g2, [%sp + 2047 + 128 + 0x00]
+ mov 5, %g2
+ stx %g2, [%sp + 2047 + 128 + 0x08]
+ mov 1, %g2
+ stx %g2, [%sp + 2047 + 128 + 0x10]
+ sethi %hi(itlb_load), %g2
+ or %g2, %lo(itlb_load), %g2
+ stx %g2, [%sp + 2047 + 128 + 0x18]
+ sethi %hi(mmu_ihandle_cache), %g2
+ lduw [%g2 + %lo(mmu_ihandle_cache)], %g2
+ stx %g2, [%sp + 2047 + 128 + 0x20]
+ sethi %hi(KERNBASE), %g2
+ stx %g2, [%sp + 2047 + 128 + 0x28]
+ sethi %hi(kern_locked_tte_data), %g2
+ ldx [%g2 + %lo(kern_locked_tte_data)], %g2
+ stx %g2, [%sp + 2047 + 128 + 0x30]
+ mov 63, %g2
+ stx %g2, [%sp + 2047 + 128 + 0x38]
+ sethi %hi(p1275buf), %g2
+ or %g2, %lo(p1275buf), %g2
+ ldx [%g2 + 0x08], %o1
+ call %o1
+ add %sp, (2047 + 128), %o0
+
+ sethi %hi(call_method), %g2
+ or %g2, %lo(call_method), %g2
+ stx %g2, [%sp + 2047 + 128 + 0x00]
+ mov 5, %g2
+ stx %g2, [%sp + 2047 + 128 + 0x08]
+ mov 1, %g2
+ stx %g2, [%sp + 2047 + 128 + 0x10]
+ sethi %hi(dtlb_load), %g2
+ or %g2, %lo(dtlb_load), %g2
+ stx %g2, [%sp + 2047 + 128 + 0x18]
+ sethi %hi(mmu_ihandle_cache), %g2
+ lduw [%g2 + %lo(mmu_ihandle_cache)], %g2
+ stx %g2, [%sp + 2047 + 128 + 0x20]
+ sethi %hi(KERNBASE), %g2
+ stx %g2, [%sp + 2047 + 128 + 0x28]
+ sethi %hi(kern_locked_tte_data), %g2
+ ldx [%g2 + %lo(kern_locked_tte_data)], %g2
+ stx %g2, [%sp + 2047 + 128 + 0x30]
+ mov 63, %g2
+ stx %g2, [%sp + 2047 + 128 + 0x38]
+ sethi %hi(p1275buf), %g2
+ or %g2, %lo(p1275buf), %g2
+ ldx [%g2 + 0x08], %o1
+ call %o1
+ add %sp, (2047 + 128), %o0
+
+ sethi %hi(prom_entry_lock), %g2
+ stb %g0, [%g2 + %lo(prom_entry_lock)]
+ membar #StoreStore | #StoreLoad
+
+ mov %l1, %sp
+ flushw
+
+ mov %l0, %o0
+
+ wrpr %g0, (PSTATE_PRIV | PSTATE_PEF), %pstate
+ wr %g0, 0, %fprs
sethi %uhi(PAGE_OFFSET), %g4
sllx %g4, 32, %g4
@@ -37,99 +123,6 @@ sparc64_cpu_startup:
srl %o0, 0, %o0
ldx [%o0], %g6
- sethi %uhi(_PAGE_VALID | _PAGE_SZ4MB), %g5
- sllx %g5, 32, %g5
- or %g5, (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_L | _PAGE_W | _PAGE_G), %g5
-
- sethi %uhi(_PAGE_PADDR), %g3
- or %g3, %ulo(_PAGE_PADDR), %g3
- sllx %g3, 32, %g3
- sethi %hi(_PAGE_PADDR), %g7
- or %g7, %lo(_PAGE_PADDR), %g7
- or %g3, %g7, %g3
-
- clr %l0
- set 0x1fff, %l2
- rd %pc, %l3
- andn %l3, %l2, %g2
-1: ldxa [%l0] ASI_ITLB_TAG_READ, %g1
- nop
- nop
- nop
- andn %g1, %l2, %g1
- cmp %g1, %g2
- be,a,pn %xcc, 2f
- ldxa [%l0] ASI_ITLB_DATA_ACCESS, %g1
- cmp %l0, (63 << 3)
- blu,pt %xcc, 1b
- add %l0, (1 << 3), %l0
-
-2: nop
- nop
- nop
- and %g1, %g3, %g1
- sub %g1, %g2, %g1
- or %g5, %g1, %g5
- clr %l0
- sethi %hi(KERNBASE), %g3
- sethi %hi(KERNBASE<<1), %g7
- mov TLB_TAG_ACCESS, %l7
-1: ldxa [%l0] ASI_ITLB_TAG_READ, %g1
- nop
- nop
- nop
- andn %g1, %l2, %g1
- cmp %g1, %g3
- blu,pn %xcc, 2f
- cmp %g1, %g7
- bgeu,pn %xcc, 2f
- nop
- stxa %g0, [%l7] ASI_IMMU
- stxa %g0, [%l0] ASI_ITLB_DATA_ACCESS
-2: cmp %l0, (63 << 3)
- blu,pt %xcc, 1b
- add %l0, (1 << 3), %l0
-
- nop
- nop
- nop
- clr %l0
-1: ldxa [%l0] ASI_DTLB_TAG_READ, %g1
- nop
- nop
- nop
- andn %g1, %l2, %g1
- cmp %g1, %g3
- blu,pn %xcc, 2f
- cmp %g1, %g7
- bgeu,pn %xcc, 2f
- nop
- stxa %g0, [%l7] ASI_DMMU
- stxa %g0, [%l0] ASI_DTLB_DATA_ACCESS
-2: cmp %l0, (63 << 3)
- blu,pt %xcc, 1b
- add %l0, (1 << 3), %l0
-
- nop
- nop
- nop
- sethi %hi(KERNBASE), %g3
- mov (63 << 3), %g7
- stxa %g3, [%l7] ASI_DMMU
- stxa %g5, [%g7] ASI_DTLB_DATA_ACCESS
- membar #Sync
- stxa %g3, [%l7] ASI_IMMU
- stxa %g5, [%g7] ASI_ITLB_DATA_ACCESS
- membar #Sync
- flush %g3
- membar #Sync
- b,pt %xcc, 1f
- nop
-1: set bounce, %g2
- jmpl %g2 + %g0, %g0
- nop
-
-bounce:
wr %g0, ASI_P, %asi
mov PRIMARY_CONTEXT, %g7
@@ -139,24 +132,6 @@ bounce:
stxa %g0, [%g7] ASI_DMMU
membar #Sync
- mov TLB_TAG_ACCESS, %g2
- stxa %g3, [%g2] ASI_IMMU
- stxa %g3, [%g2] ASI_DMMU
-
- mov (63 << 3), %g7
- ldxa [%g7] ASI_ITLB_DATA_ACCESS, %g1
- andn %g1, (_PAGE_G), %g1
- stxa %g1, [%g7] ASI_ITLB_DATA_ACCESS
- membar #Sync
-
- ldxa [%g7] ASI_DTLB_DATA_ACCESS, %g1
- andn %g1, (_PAGE_G), %g1
- stxa %g1, [%g7] ASI_DTLB_DATA_ACCESS
- membar #Sync
-
- flush %g3
- membar #Sync
-
mov 1, %g5
sllx %g5, (PAGE_SHIFT + 1), %g5
sub %g5, (REGWIN_SZ + STACK_BIAS), %g5
@@ -169,12 +144,12 @@ bounce:
/* Setup the trap globals, then we can resurface. */
rdpr %pstate, %o1
mov %g6, %o2
- wrpr %o1, (PSTATE_AG | PSTATE_IE), %pstate
+ wrpr %o1, PSTATE_AG, %pstate
sethi %hi(sparc64_ttable_tl0), %g5
wrpr %g5, %tba
mov %o2, %g6
- wrpr %o1, (PSTATE_MG | PSTATE_IE), %pstate
+ wrpr %o1, PSTATE_MG, %pstate
#define KERN_HIGHBITS ((_PAGE_VALID | _PAGE_SZ4MB) ^ 0xfffff80000000000)
#define KERN_LOWBITS (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W)
#ifdef THIS_IS_CHEETAH
@@ -200,7 +175,7 @@ bounce:
#undef VPTE_BASE
/* Setup interrupt globals, we are always SMP. */
- wrpr %o1, (PSTATE_IG | PSTATE_IE), %pstate
+ wrpr %o1, PSTATE_IG, %pstate
/* Get our UPA MID. */
lduw [%o2 + AOFF_task_processor], %g1
@@ -210,12 +185,15 @@ bounce:
/* In theory this is: &(cpu_data[this_upamid].irq_worklists[0]) */
sllx %g1, 7, %g1
add %g5, %g1, %g1
- add %g1, 64, %g1
+ add %g1, 64, %g6
wrpr %g0, 0, %wstate
or %o1, PSTATE_IE, %o1
wrpr %o1, 0, %pstate
+ call prom_set_trap_table
+ sethi %hi(sparc64_ttable_tl0), %o0
+
call smp_callin
nop
call cpu_idle
diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c
index f4f2287df..845809709 100644
--- a/arch/sparc64/kernel/traps.c
+++ b/arch/sparc64/kernel/traps.c
@@ -1,4 +1,4 @@
-/* $Id: traps.c,v 1.62 1999/08/31 19:25:35 davem Exp $
+/* $Id: traps.c,v 1.64 1999/12/19 23:53:13 davem Exp $
* arch/sparc64/kernel/traps.c
*
* Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -26,6 +26,7 @@
#include <asm/uaccess.h>
#include <asm/fpumacro.h>
#include <asm/lsu.h>
+#include <asm/psrcompat.h>
#ifdef CONFIG_KMOD
#include <linux/kmod.h>
#endif
@@ -519,8 +520,22 @@ void do_fpe_common(struct pt_regs *regs)
regs->tpc = regs->tnpc;
regs->tnpc += 4;
} else {
+ unsigned long fsr = current->thread.xfsr[0];
+
current->thread.sig_address = regs->tpc;
current->thread.sig_desc = SUBSIG_FPERROR;
+ if ((fsr & 0x1c000) == (1 << 14)) {
+ if (fsr & 0x01)
+ current->thread.sig_desc = SUBSIG_FPINEXACT;
+ else if (fsr & 0x02)
+ current->thread.sig_desc = SUBSIG_FPDIVZERO;
+ else if (fsr & 0x04)
+ current->thread.sig_desc = SUBSIG_FPUNFLOW;
+ else if (fsr & 0x08)
+ current->thread.sig_desc = SUBSIG_FPOVFLOW;
+ else if (fsr & 0x10)
+ current->thread.sig_desc = SUBSIG_FPINTOVFL;
+ }
send_sig(SIGFPE, current, 1);
}
}
@@ -564,7 +579,9 @@ void do_tof(struct pt_regs *regs)
void do_div0(struct pt_regs *regs)
{
- send_sig(SIGILL, current, 1);
+ current->thread.sig_address = regs->tpc;
+ current->thread.sig_desc = SUBSIG_IDIVZERO;
+ send_sig(SIGFPE, current, 1);
}
void instruction_dump (unsigned int *pc)
@@ -712,10 +729,12 @@ void do_priv_instruction(struct pt_regs *regs, unsigned long pc, unsigned long n
send_sig(SIGILL, current, 1);
}
-void handle_hw_divzero(struct pt_regs *regs, unsigned long pc, unsigned long npc,
- unsigned long psr)
+void handle_hw_divzero(struct pt_regs *regs, unsigned long pc,
+ unsigned long npc, unsigned long psr)
{
- send_sig(SIGILL, current, 1);
+ current->thread.sig_address = regs->tpc;
+ current->thread.sig_desc = SUBSIG_IDIVZERO;
+ send_sig(SIGFPE, current, 1);
}
/* Trap level 1 stuff or other traps we should never see... */
@@ -842,6 +861,13 @@ void cache_flush_trap(struct pt_regs *regs)
}
#endif
+void do_getpsr(struct pt_regs *regs)
+{
+ regs->u_regs[UREG_I0] = tstate_to_psr(regs->tstate);
+ regs->tpc = regs->tnpc;
+ regs->tnpc += 4;
+}
+
void trap_init(void)
{
/* Attach to the address space of init_task. */
diff --git a/arch/sparc64/kernel/ttable.S b/arch/sparc64/kernel/ttable.S
index b378756c0..257d56d6b 100644
--- a/arch/sparc64/kernel/ttable.S
+++ b/arch/sparc64/kernel/ttable.S
@@ -1,4 +1,4 @@
-/* $Id: ttable.S,v 1.29 1999/08/31 19:25:37 davem Exp $
+/* $Id: ttable.S,v 1.30 1999/12/01 23:52:03 davem Exp $
* ttable.S: Sparc V9 Trap Table(s) with SpitFire extensions.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -120,7 +120,8 @@ tl0_resv11c: TRAP_UTRAP(UT_TRAP_INSTRUCTION_28,0x11c) TRAP_UTRAP(UT_TRAP_INSTRUC
tl0_resv11e: TRAP_UTRAP(UT_TRAP_INSTRUCTION_30,0x11e) TRAP_UTRAP(UT_TRAP_INSTRUCTION_31,0x11f)
tl0_getcc: GETCC_TRAP
tl0_setcc: SETCC_TRAP
-tl0_resv122: BTRAP(0x122) BTRAP(0x123) BTRAP(0x124) BTRAP(0x125) BTRAP(0x126)
+tl0_getpsr: TRAP(do_getpsr)
+tl0_resv123: BTRAP(0x123) BTRAP(0x124) BTRAP(0x125) BTRAP(0x126)
tl0_solindir: INDIRECT_SOLARIS_SYSCALL(156)
tl0_resv128: BTRAP(0x128) BTRAP(0x129) BTRAP(0x12a) BTRAP(0x12b) BTRAP(0x12c)
tl0_resv12d: BTRAP(0x12d) BTRAP(0x12e) BTRAP(0x12f) BTRAP(0x130) BTRAP(0x131)
diff --git a/arch/sparc64/lib/VISmemset.S b/arch/sparc64/lib/VISmemset.S
index 7ccd7b818..152723a49 100644
--- a/arch/sparc64/lib/VISmemset.S
+++ b/arch/sparc64/lib/VISmemset.S
@@ -1,9 +1,9 @@
-/* $Id: VISmemset.S,v 1.9 1999/05/25 16:53:01 jj Exp $
+/* $Id: VISmemset.S,v 1.10 1999/12/23 17:02:16 jj Exp $
* VISmemset.S: High speed memset operations utilizing the UltraSparc
* Visual Instruction Set.
*
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
- * Copyright (C) 1996, 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1996, 1997, 1999 Jakub Jelinek (jakub@redhat.com)
*/
#include "VIS.h"
@@ -32,12 +32,7 @@
#endif
#ifdef __KERNEL__
-
#include <asm/visasm.h>
-
-#define RETL clr %o0
-#else
-#define RETL mov %g3, %o0
#endif
/* Well, memset is a lot easier to get right than bcopy... */
@@ -55,8 +50,8 @@ memset:
#ifndef REGS_64BIT
srl %o2, 0, %o2
#endif
- mov %o0, %g3
#endif
+ mov %o0, %o4
cmp %o2, 7
bleu,pn %xcc, 17f
andcc %o0, 3, %g5
@@ -188,19 +183,19 @@ memset:
andcc %o2, 7, %o2
#ifdef __KERNEL__
14: srl %g5, 1, %o3
- sethi %hi(13f), %o4
- sub %o4, %o3, %o4
- jmpl %o4 + %lo(13f), %g0
+ sethi %hi(13f), %g3
+ sub %g3, %o3, %g3
+ jmpl %g3 + %lo(13f), %g0
add %o0, %g5, %o0
#else
-14: rd %pc, %o4
+14: rd %pc, %g3
#ifdef REGS_64BIT
srl %g5, 1, %o3
- sub %o4, %o3, %o4
+ sub %g3, %o3, %g3
#else
- sub %o4, %g5, %o4
+ sub %g3, %g5, %g3
#endif
- jmpl %o4 + (13f - 14b), %g0
+ jmpl %g3 + (13f - 14b), %g0
add %o0, %g5, %o0
#endif
12: SET_BLOCKS(%o0, 0x68, %o1)
@@ -220,14 +215,14 @@ memset:
1: bne,a,pn %xcc, 8f
stb %o1, [%o0]
8: retl
- RETL
+ mov %o4, %o0
17: brz,pn %o2, 0f
8: add %o0, 1, %o0
subcc %o2, 1, %o2
bne,pt %xcc, 8b
stb %o1, [%o0 - 1]
0: retl
- RETL
+ mov %o4, %o0
6:
#ifdef REGS_64BIT
stx %o1, [%o0]
diff --git a/arch/sparc64/lib/blockops.S b/arch/sparc64/lib/blockops.S
index 202b57270..1aa48643c 100644
--- a/arch/sparc64/lib/blockops.S
+++ b/arch/sparc64/lib/blockops.S
@@ -1,4 +1,4 @@
-/* $Id: blockops.S,v 1.18 1999/07/30 09:35:37 davem Exp $
+/* $Id: blockops.S,v 1.19 1999/11/19 05:52:45 davem Exp $
* blockops.S: UltraSparc block zero optimized routines.
*
* Copyright (C) 1996,1998 David S. Miller (davem@caip.rutgers.edu)
@@ -136,19 +136,19 @@ clear_page: /* %o0=dest */
faddd %f0, %f2, %f12 ! FPA Group
fmuld %f0, %f2, %f14 ! FPM
- rd %asi, %g2 ! LSU Group
- wr %g0, ASI_BLK_P, %asi ! LSU Group
membar #StoreLoad | #StoreStore | #LoadStore ! LSU Group
-1: stda %f0, [%o0 + 0x00] %asi ! Store Group
- stda %f0, [%o0 + 0x40] %asi ! Store Group
- stda %f0, [%o0 + 0x80] %asi ! Store Group
- stda %f0, [%o0 + 0xc0] %asi ! Store Group
+1: stda %f0, [%o0 + %g0] ASI_BLK_P ! Store Group
+ add %o0, 0x40, %o0 ! IEU0
+ stda %f0, [%o0 + %g0] ASI_BLK_P ! Store Group
+ add %o0, 0x40, %o0 ! IEU0
+ stda %f0, [%o0 + %g0] ASI_BLK_P ! Store Group
+ add %o0, 0x40, %o0 ! IEU0 Group
+ stda %f0, [%o0 + %g0] ASI_BLK_P ! Store Group
subcc %o1, 1, %o1 ! IEU1
bne,pt %icc, 1b ! CTI
- add %o0, 0x100, %o0 ! IEU0 Group
+ add %o0, 0x40, %o0 ! IEU0 Group
membar #Sync ! LSU Group
- wr %g2, %g0, %asi ! LSU Group
VISExitHalf
stxa %g5, [%o2] ASI_DMMU
diff --git a/arch/sparc64/lib/strlen_user.S b/arch/sparc64/lib/strlen_user.S
index 04d5e53db..4af69a0ad 100644
--- a/arch/sparc64/lib/strlen_user.S
+++ b/arch/sparc64/lib/strlen_user.S
@@ -4,7 +4,7 @@
* or 0 for error
*
* Copyright (C) 1991,1996 Free Software Foundation
- * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1996,1999 David S. Miller (davem@redhat.com)
* Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
*/
@@ -14,8 +14,11 @@
#define HI_MAGIC 0x80808080
.align 4
- .global __strlen_user
+ .global __strlen_user, __strnlen_user
__strlen_user:
+ sethi %hi(32768), %o1
+__strnlen_user:
+ mov %o1, %g1
mov %o0, %o1
andcc %o0, 3, %g0
be,pt %icc, 9f
@@ -42,11 +45,16 @@ __strlen_user:
13: lda [%o0] %asi, %o5
2: sub %o5, %o2, %o4
andcc %o4, %o3, %g0
- be,pt %icc, 13b
+ bne,pn %icc, 82f
add %o0, 4, %o0
+ sub %o0, %o1, %g2
+81: cmp %g2, %g1
+ blu,pt %icc, 13b
+ mov %o0, %o4
+ ba,a,pt %xcc, 1f
/* Check every byte. */
- srl %o5, 24, %g5
+82: srl %o5, 24, %g5
andcc %g5, 0xff, %g0
be,pn %icc, 1f
add %o0, -3, %o4
@@ -59,8 +67,8 @@ __strlen_user:
be,pn %icc, 1f
add %o4, 1, %o4
andcc %o5, 0xff, %g0
- bne,a,pt %icc, 2b
-14: lda [%o0] %asi, %o5
+ bne,pt %icc, 81b
+ sub %o0, %o1, %g2
add %o4, 1, %o4
1: retl
sub %o4, %o1, %o0
@@ -85,4 +93,3 @@ __strlen_user:
.word 12b, 30b
.word 15b, 30b
.word 13b, 30b
- .word 14b, 30b
diff --git a/arch/sparc64/math-emu/math.c b/arch/sparc64/math-emu/math.c
index b23bbf1bb..2a05c0d47 100644
--- a/arch/sparc64/math-emu/math.c
+++ b/arch/sparc64/math-emu/math.c
@@ -1,4 +1,4 @@
-/* $Id: math.c,v 1.10 1999/08/13 16:02:06 jj Exp $
+/* $Id: math.c,v 1.11 1999/12/20 05:02:25 davem Exp $
* arch/sparc64/math-emu/math.c
*
* Copyright (C) 1997,1999 Jakub Jelinek (jj@ultra.linux.cz)
diff --git a/arch/sparc64/math-emu/sfp-util.h b/arch/sparc64/math-emu/sfp-util.h
index 2440b26d2..42dddaaba 100644
--- a/arch/sparc64/math-emu/sfp-util.h
+++ b/arch/sparc64/math-emu/sfp-util.h
@@ -1,4 +1,4 @@
-/* $Id: sfp-util.h,v 1.2 1999/06/07 18:24:15 jj Exp $
+/* $Id: sfp-util.h,v 1.4 1999/09/20 12:14:19 jj Exp $
* arch/sparc64/math-emu/sfp-util.h
*
* Copyright (C) 1999 Jakub Jelinek (jj@ultra.linux.cz)
diff --git a/arch/sparc64/mm/asyncd.c b/arch/sparc64/mm/asyncd.c
index 30272e9b5..a64b09e86 100644
--- a/arch/sparc64/mm/asyncd.c
+++ b/arch/sparc64/mm/asyncd.c
@@ -1,4 +1,4 @@
-/* $Id: asyncd.c,v 1.9 1999/07/30 09:35:43 davem Exp $
+/* $Id: asyncd.c,v 1.10 1999/12/15 22:25:02 davem Exp $
* The asyncd kernel daemon. This handles paging on behalf of
* processes that receive page faults due to remote (async) memory
* accesses.
@@ -25,6 +25,7 @@
#include <asm/system.h> /* for cli()/sti() */
#include <asm/segment.h> /* for memcpy_to/fromfs */
#include <asm/bitops.h>
+#include <asm/pgalloc.h>
#include <asm/pgtable.h>
#define DEBUG 0
diff --git a/arch/sparc64/mm/fault.c b/arch/sparc64/mm/fault.c
index 1a20b399b..1835b874f 100644
--- a/arch/sparc64/mm/fault.c
+++ b/arch/sparc64/mm/fault.c
@@ -1,4 +1,4 @@
-/* $Id: fault.c,v 1.39 1999/08/30 10:07:09 davem Exp $
+/* $Id: fault.c,v 1.40 1999/12/01 10:44:53 davem Exp $
* arch/sparc64/mm/fault.c: Page fault handlers for the 64-bit Sparc.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -113,7 +113,9 @@ static inline u32 get_user_insn(unsigned long tpc)
ptep = pte_offset(pmdp, tpc);
if(!pte_present(*ptep))
return 0;
- insn = *(unsigned int *)(pte_page(*ptep) + (tpc & ~PAGE_MASK));
+ insn = *(unsigned int *)
+ ((unsigned long)__va(pte_pagenr(*ptep) << PAGE_SHIFT) +
+ (tpc & ~PAGE_MASK));
#else
register unsigned long pte asm("l1");
diff --git a/arch/sparc64/mm/generic.c b/arch/sparc64/mm/generic.c
index be999f446..9a1ab1de3 100644
--- a/arch/sparc64/mm/generic.c
+++ b/arch/sparc64/mm/generic.c
@@ -1,4 +1,4 @@
-/* $Id: generic.c,v 1.9 1999/07/23 22:32:01 davem Exp $
+/* $Id: generic.c,v 1.13 1999/12/20 05:02:33 davem Exp $
* generic.c: Generic Sparc mm routines that are not dependent upon
* MMU type but are Sparc specific.
*
@@ -9,46 +9,26 @@
#include <linux/mm.h>
#include <linux/swap.h>
+#include <asm/pgalloc.h>
#include <asm/pgtable.h>
#include <asm/page.h>
-
-/* Allocate a block of RAM which is aligned to its size.
- * This procedure can be used until the call to mem_init().
- */
-void *sparc_init_alloc(unsigned long *kbrk, unsigned long size)
-{
- unsigned long mask = size - 1;
- unsigned long ret;
-
- if(!size)
- return 0x0;
- if(size & mask) {
- prom_printf("panic: sparc_init_alloc botch\n");
- prom_halt();
- }
- ret = (*kbrk + mask) & ~mask;
- *kbrk = ret + size;
- memset((void*) ret, 0, size);
- return (void*) ret;
-}
-
static inline void forget_pte(pte_t page)
{
if (pte_none(page))
return;
if (pte_present(page)) {
- unsigned long addr = pte_page(page);
- if (MAP_NR(addr) >= max_mapnr || PageReserved(mem_map+MAP_NR(addr)))
+ unsigned long nr = pte_pagenr(page);
+ if (nr >= max_mapnr || PageReserved(mem_map+nr))
return;
/*
* free_page() used to be able to clear swap cache
* entries. We may now have to do it manually.
*/
- free_page_and_swap_cache(addr);
+ free_page_and_swap_cache(mem_map+nr);
return;
}
- swap_free(pte_val(page));
+ swap_free(pte_to_swp_entry(page));
}
/* Remap IO memory, the same way as remap_page_range(), but use
diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c
index 6df374b4e..1be2716f5 100644
--- a/arch/sparc64/mm/init.c
+++ b/arch/sparc64/mm/init.c
@@ -1,4 +1,4 @@
-/* $Id: init.c,v 1.135 1999/09/06 22:55:10 ecd Exp $
+/* $Id: init.c,v 1.143 1999/12/16 16:15:14 davem Exp $
* arch/sparc64/mm/init.c
*
* Copyright (C) 1996-1999 David S. Miller (davem@caip.rutgers.edu)
@@ -6,8 +6,11 @@
*/
#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
#include <linux/string.h>
#include <linux/init.h>
+#include <linux/bootmem.h>
#include <linux/mm.h>
#include <linux/malloc.h>
#include <linux/blk.h>
@@ -17,6 +20,7 @@
#include <asm/head.h>
#include <asm/system.h>
#include <asm/page.h>
+#include <asm/pgalloc.h>
#include <asm/pgtable.h>
#include <asm/oplib.h>
#include <asm/iommu.h>
@@ -26,13 +30,8 @@
#include <asm/vaddrs.h>
#include <asm/dma.h>
-/* Turn this off if you suspect some place in some physical memory hole
- might get into page tables (something would be broken very much). */
-
-#define FREE_UNUSED_MEM_MAP
-
extern void show_net_buffers(void);
-extern unsigned long device_scan(unsigned long);
+extern void device_scan(void);
struct sparc_phys_banks sp_banks[SPARC_PHYS_BANKS];
@@ -41,6 +40,8 @@ unsigned long *sparc64_valid_addr_bitmap;
/* Ugly, but necessary... -DaveM */
unsigned long phys_base;
+static unsigned long totalram_pages = 0;
+
/* get_new_mmu_context() uses "cache + 1". */
spinlock_t ctx_alloc_lock = SPIN_LOCK_UNLOCKED;
unsigned long tlb_context_cache = CTX_FIRST_VERSION - 1;
@@ -48,7 +49,7 @@ unsigned long tlb_context_cache = CTX_FIRST_VERSION - 1;
unsigned long mmu_context_bmap[CTX_BMAP_SLOTS];
/* References to section boundaries */
-extern char __init_begin, __init_end, etext, __bss_start;
+extern char __init_begin, __init_end, _start, _end, etext, edata;
int do_check_pgt_cache(int low, int high)
{
@@ -60,8 +61,10 @@ int do_check_pgt_cache(int low, int high)
if(pgd_quicklist)
free_pgd_slow(get_pgd_fast()), freed++;
#endif
- if(pte_quicklist)
- free_pte_slow(get_pte_fast()), freed++;
+ if(pte_quicklist[0])
+ free_pte_slow(get_pte_fast(0)), freed++;
+ if(pte_quicklist[1])
+ free_pte_slow(get_pte_fast(1)), freed++;
} while(pgtable_cache_size > low);
}
#ifndef __SMP__
@@ -110,42 +113,20 @@ int do_check_pgt_cache(int low, int high)
pte_t __bad_page(void)
{
memset((void *) &empty_bad_page, 0, PAGE_SIZE);
- return pte_mkdirty(mk_pte((((unsigned long) &empty_bad_page)
- - ((unsigned long)&empty_zero_page) + phys_base + PAGE_OFFSET),
- PAGE_SHARED));
+ return pte_mkdirty(mk_pte_phys((((unsigned long) &empty_bad_page)
+ - ((unsigned long)&empty_zero_page)
+ + phys_base),
+ PAGE_SHARED));
}
void show_mem(void)
{
- int free = 0,total = 0,reserved = 0;
- int shared = 0, cached = 0;
- struct page *page, *end;
-
- printk("\nMem-info:\n");
+ printk("Mem-info:\n");
show_free_areas();
- printk("Free swap: %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10));
- for (page = mem_map, end = mem_map + max_mapnr;
- page < end; page++) {
- if (PageSkip(page)) {
- if (page->next_hash < page)
- break;
- page = page->next_hash;
- }
- total++;
- if (PageReserved(page))
- reserved++;
- else if (PageSwapCache(page))
- cached++;
- else if (!atomic_read(&page->count))
- free++;
- else
- shared += atomic_read(&page->count) - 1;
- }
- printk("%d pages of RAM\n",total);
- printk("%d free pages\n",free);
- printk("%d reserved pages\n",reserved);
- printk("%d pages shared\n",shared);
- printk("%d pages swap cached\n",cached);
+ printk("Free swap: %6dkB\n",
+ nr_swap_pages << (PAGE_SHIFT-10));
+ printk("%ld pages of RAM\n", totalram_pages);
+ printk("%d free pages\n", nr_free_pages());
printk("%d pages in page table cache\n",pgtable_cache_size);
#ifndef __SMP__
printk("%d entries in page dir cache\n",pgd_cache_size);
@@ -156,508 +137,46 @@ void show_mem(void)
#endif
}
-/* IOMMU support, the ideas are right, the code should be cleaned a bit still... */
-
-/* This keeps track of pages used in sparc_alloc_dvma() invocations. */
-/* NOTE: All of these are inited to 0 in bss, don't need to make data segment bigger */
-#define DVMAIO_SIZE 0x2000000
-static unsigned long dvma_map_pages[DVMAIO_SIZE >> 16];
-static unsigned long dvma_pages_current_offset;
-static int dvma_pages_current_index;
-static unsigned long dvmaiobase = 0;
-static unsigned long dvmaiosz __initdata = 0;
-
-void __init dvmaio_init(void)
-{
- long i;
-
- if (!dvmaiobase) {
- for (i = 0; sp_banks[i].num_bytes != 0; i++)
- if (sp_banks[i].base_addr + sp_banks[i].num_bytes > dvmaiobase)
- dvmaiobase = sp_banks[i].base_addr + sp_banks[i].num_bytes;
-
- /* We map directly phys_base to phys_base+(4GB-DVMAIO_SIZE). */
- dvmaiobase -= phys_base;
-
- dvmaiobase = (dvmaiobase + DVMAIO_SIZE + 0x400000 - 1) & ~(0x400000 - 1);
- for (i = 0; i < 6; i++)
- if (dvmaiobase <= ((1024L * 64 * 1024) << i))
- break;
- dvmaiobase = ((1024L * 64 * 1024) << i) - DVMAIO_SIZE;
- dvmaiosz = i;
- }
-}
-
-void __init iommu_init(int iommu_node, struct linux_sbus *sbus)
-{
- extern int this_is_starfire;
- extern void *starfire_hookup(int);
- struct iommu_struct *iommu;
- struct sysio_regs *sregs;
- struct linux_prom64_registers rprop;
- unsigned long impl, vers;
- unsigned long control, tsbbase;
- unsigned long tsbbases[32];
- unsigned long *iopte;
- int err, i, j;
-
- dvmaio_init();
- err = prom_getproperty(iommu_node, "reg", (char *)&rprop,
- sizeof(rprop));
- if(err == -1) {
- prom_printf("iommu_init: Cannot map SYSIO control registers.\n");
- prom_halt();
- }
- sregs = (struct sysio_regs *) __va(rprop.phys_addr);
-
- if(!sregs) {
- prom_printf("iommu_init: Fatal error, sysio regs not mapped\n");
- prom_halt();
- }
-
- iommu = kmalloc(sizeof(struct iommu_struct), GFP_ATOMIC);
- if (!iommu) {
- prom_printf("iommu_init: Fatal error, kmalloc(iommu) failed\n");
- prom_halt();
- }
-
- spin_lock_init(&iommu->iommu_lock);
- iommu->sysio_regs = sregs;
- sbus->iommu = iommu;
-
- control = sregs->iommu_control;
- impl = (control & IOMMU_CTRL_IMPL) >> 60;
- vers = (control & IOMMU_CTRL_VERS) >> 56;
- printk("IOMMU(SBUS): IMPL[%x] VERS[%x] SYSIO mapped at %016lx\n",
- (unsigned int) impl, (unsigned int)vers, (unsigned long) sregs);
-
- /* Streaming buffer is unreliable on VERS 0 of SYSIO,
- * although such parts were never shipped in production
- * Sun hardware, I check just to be robust. --DaveM
- */
- vers = ((sregs->control & SYSIO_CONTROL_VER) >> 56);
- if (vers == 0)
- iommu->strbuf_enabled = 0;
- else
- iommu->strbuf_enabled = 1;
-
- control &= ~(IOMMU_CTRL_TSBSZ);
- control |= ((IOMMU_TSBSZ_2K * dvmaiosz) | IOMMU_CTRL_TBWSZ | IOMMU_CTRL_ENAB);
-
- /* Use only 64k pages, things are layed out in the 32-bit SBUS
- * address space like this:
- *
- * 0x00000000 ----------------------------------------
- * | Direct physical mappings for most |
- * | DVMA to paddr's within this range |
- * dvmaiobase ----------------------------------------
- * | For mappings requested via |
- * | sparc_alloc_dvma() |
- * dvmaiobase+32M ----------------------------------------
- *
- * NOTE: we need to order 2 contiguous order 5, that's the largest
- * chunk page_alloc will give us. -JJ */
- tsbbase = 0;
- if (dvmaiosz == 6) {
- memset (tsbbases, 0, sizeof(tsbbases));
- for (i = 0; i < 32; i++) {
- tsbbases[i] = __get_free_pages(GFP_DMA, 5);
- for (j = 0; j < i; j++)
- if (tsbbases[j] == tsbbases[i] + 32768*sizeof(iopte_t)) {
- tsbbase = tsbbases[i];
- break;
- } else if (tsbbases[i] == tsbbases[j] + 32768*sizeof(iopte_t)) {
- tsbbase = tsbbases[j];
- break;
- }
- if (tsbbase) {
- tsbbases[i] = 0;
- tsbbases[j] = 0;
- break;
- }
- }
- for (i = 0; i < 32; i++)
- if (tsbbases[i])
- free_pages(tsbbases[i], 5);
- } else
- tsbbase = __get_free_pages(GFP_DMA, dvmaiosz);
- if (!tsbbase) {
- prom_printf("Strange. Could not allocate 512K of contiguous RAM.\n");
- prom_halt();
- }
- iommu->page_table = (iopte_t *) tsbbase;
- iopte = (unsigned long *) tsbbase;
-
- /* Setup aliased mappings... */
- for(i = 0; i < (dvmaiobase >> 16); i++) {
- unsigned long val = ((((unsigned long)i) << 16UL) + phys_base);
-
- val |= IOPTE_VALID | IOPTE_64K | IOPTE_WRITE;
- if (iommu->strbuf_enabled)
- val |= IOPTE_STBUF;
- else
- val |= IOPTE_CACHE;
- *iopte = val;
- iopte++;
- }
-
- /* Clear all sparc_alloc_dvma() maps. */
- for( ; i < ((dvmaiobase + DVMAIO_SIZE) >> 16); i++)
- *iopte++ = 0;
-
- sregs->iommu_tsbbase = __pa(tsbbase);
- sregs->iommu_control = control;
-
- /* Get the streaming buffer going. */
- control = sregs->sbuf_control;
- impl = (control & SYSIO_SBUFCTRL_IMPL) >> 60;
- vers = (control & SYSIO_SBUFCTRL_REV) >> 56;
- printk("IOMMU: Streaming Buffer IMPL[%x] REV[%x] ... ",
- (unsigned int)impl, (unsigned int)vers);
- iommu->flushflag = 0;
-
- if (iommu->strbuf_enabled != 0) {
- sregs->sbuf_control = (control | SYSIO_SBUFCTRL_SB_EN);
- printk("ENABLED\n");
- } else {
- sregs->sbuf_control = (control & ~(SYSIO_SBUFCTRL_SB_EN));
- printk("DISABLED\n");
- }
-
- /* Finally enable DVMA arbitration for all devices, just in case. */
- sregs->sbus_control |= SYSIO_SBCNTRL_AEN;
-
- /* If necessary, hook us up for starfire IRQ translations. */
- sbus->upaid = prom_getintdefault(sbus->prom_node, "upa-portid", -1);
- if(this_is_starfire)
- sbus->starfire_cookie = starfire_hookup(sbus->upaid);
- else
- sbus->starfire_cookie = NULL;
-}
-
-void mmu_map_dma_area(unsigned long addr, int len, __u32 *dvma_addr,
- struct linux_sbus *sbus)
-{
- pgd_t *pgdp;
- pmd_t *pmdp;
- pte_t *ptep;
-
- /* Find out if we need to grab some pages. */
- if(!dvma_map_pages[dvma_pages_current_index] ||
- ((dvma_pages_current_offset + len) > (1 << 16))) {
- struct linux_sbus *sbus;
- unsigned long *iopte;
- unsigned long newpages = __get_free_pages(GFP_KERNEL, 3);
- int i;
-
- if(!newpages)
- panic("AIEEE cannot get DVMA pages.");
-
- memset((char *)newpages, 0, (1 << 16));
-
- if(!dvma_map_pages[dvma_pages_current_index]) {
- dvma_map_pages[dvma_pages_current_index] = newpages;
- i = dvma_pages_current_index;
- } else {
- dvma_map_pages[dvma_pages_current_index + 1] = newpages;
- i = dvma_pages_current_index + 1;
- }
-
- /* Stick it in the IOMMU. */
- i = (dvmaiobase >> 16) + i;
- for_each_sbus(sbus) {
- struct iommu_struct *iommu = sbus->iommu;
- unsigned long flags;
-
- spin_lock_irqsave(&iommu->iommu_lock, flags);
- iopte = (unsigned long *)(iommu->page_table + i);
- *iopte = (IOPTE_VALID | IOPTE_64K | IOPTE_CACHE | IOPTE_WRITE);
- *iopte |= __pa(newpages);
- spin_unlock_irqrestore(&iommu->iommu_lock, flags);
- }
- }
-
- /* Get this out of the way. */
- *dvma_addr = (__u32) ((dvmaiobase) +
- (dvma_pages_current_index << 16) +
- (dvma_pages_current_offset));
-
- while(len > 0) {
- while((len > 0) && (dvma_pages_current_offset < (1 << 16))) {
- pte_t pte;
- unsigned long the_page =
- dvma_map_pages[dvma_pages_current_index] +
- dvma_pages_current_offset;
-
- /* Map the CPU's view. */
- pgdp = pgd_offset(&init_mm, addr);
- pmdp = pmd_alloc_kernel(pgdp, addr);
- ptep = pte_alloc_kernel(pmdp, addr);
- pte = mk_pte(the_page, PAGE_KERNEL);
- set_pte(ptep, pte);
-
- dvma_pages_current_offset += PAGE_SIZE;
- addr += PAGE_SIZE;
- len -= PAGE_SIZE;
- }
- dvma_pages_current_index++;
- dvma_pages_current_offset = 0;
- }
-}
-
-__u32 mmu_get_scsi_one(char *vaddr, unsigned long len, struct linux_sbus *sbus)
-{
- struct iommu_struct *iommu = sbus->iommu;
- struct sysio_regs *sregs = iommu->sysio_regs;
- unsigned long start = (unsigned long) vaddr;
- unsigned long end = PAGE_ALIGN(start + len);
- unsigned long flags, tmp;
- volatile u64 *sbctrl = (volatile u64 *) &sregs->sbus_control;
-
- start &= PAGE_MASK;
- if (end > MAX_DMA_ADDRESS) {
- printk("mmu_get_scsi_one: Bogus DMA buffer address [%016lx:%d]\n",
- (unsigned long) vaddr, (int)len);
- panic("DMA address too large, tell DaveM");
- }
-
- if (iommu->strbuf_enabled) {
- volatile u64 *sbuf_pflush = (volatile u64 *) &sregs->sbuf_pflush;
-
- spin_lock_irqsave(&iommu->iommu_lock, flags);
- iommu->flushflag = 0;
- while(start < end) {
- *sbuf_pflush = start;
- start += PAGE_SIZE;
- }
- sregs->sbuf_fsync = __pa(&(iommu->flushflag));
- tmp = *sbctrl;
- while(iommu->flushflag == 0)
- membar("#LoadLoad");
- spin_unlock_irqrestore(&iommu->iommu_lock, flags);
- }
-
- return sbus_dvma_addr(vaddr);
-}
-
-void mmu_release_scsi_one(u32 vaddr, unsigned long len, struct linux_sbus *sbus)
-{
- struct iommu_struct *iommu = sbus->iommu;
- struct sysio_regs *sregs = iommu->sysio_regs;
- unsigned long start = (unsigned long) vaddr;
- unsigned long end = PAGE_ALIGN(start + len);
- unsigned long flags, tmp;
- volatile u64 *sbctrl = (volatile u64 *) &sregs->sbus_control;
-
- start &= PAGE_MASK;
-
- if (iommu->strbuf_enabled) {
- volatile u64 *sbuf_pflush = (volatile u64 *) &sregs->sbuf_pflush;
-
- spin_lock_irqsave(&iommu->iommu_lock, flags);
-
- /* 1) Clear the flush flag word */
- iommu->flushflag = 0;
-
- /* 2) Tell the streaming buffer which entries
- * we want flushed.
- */
- while(start < end) {
- *sbuf_pflush = start;
- start += PAGE_SIZE;
- }
-
- /* 3) Initiate flush sequence. */
- sregs->sbuf_fsync = __pa(&(iommu->flushflag));
-
- /* 4) Guarentee completion of all previous writes
- * by reading SYSIO's SBUS control register.
- */
- tmp = *sbctrl;
-
- /* 5) Wait for flush flag to get set. */
- while(iommu->flushflag == 0)
- membar("#LoadLoad");
-
- spin_unlock_irqrestore(&iommu->iommu_lock, flags);
- }
-}
-
-void mmu_get_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus)
-{
- struct iommu_struct *iommu = sbus->iommu;
- struct sysio_regs *sregs = iommu->sysio_regs;
- unsigned long flags, tmp;
- volatile u64 *sbctrl = (volatile u64 *) &sregs->sbus_control;
-
- if (iommu->strbuf_enabled) {
- volatile u64 *sbuf_pflush = (volatile u64 *) &sregs->sbuf_pflush;
-
- spin_lock_irqsave(&iommu->iommu_lock, flags);
- iommu->flushflag = 0;
-
- while(sz >= 0) {
- unsigned long start = (unsigned long)sg[sz].addr;
- unsigned long end = PAGE_ALIGN(start + sg[sz].len);
-
- if (end > MAX_DMA_ADDRESS) {
- printk("mmu_get_scsi_sgl: Bogus DMA buffer address "
- "[%016lx:%d]\n", start, (int) sg[sz].len);
- panic("DMA address too large, tell DaveM");
- }
-
- sg[sz--].dvma_addr = sbus_dvma_addr(start);
- start &= PAGE_MASK;
- while(start < end) {
- *sbuf_pflush = start;
- start += PAGE_SIZE;
- }
- }
-
- sregs->sbuf_fsync = __pa(&(iommu->flushflag));
- tmp = *sbctrl;
- while(iommu->flushflag == 0)
- membar("#LoadLoad");
- spin_unlock_irqrestore(&iommu->iommu_lock, flags);
- } else {
- /* Just verify the addresses and fill in the
- * dvma_addr fields in this case.
- */
- while(sz >= 0) {
- unsigned long start = (unsigned long)sg[sz].addr;
- unsigned long end = PAGE_ALIGN(start + sg[sz].len);
- if (end > MAX_DMA_ADDRESS) {
- printk("mmu_get_scsi_sgl: Bogus DMA buffer address "
- "[%016lx:%d]\n", start, (int) sg[sz].len);
- panic("DMA address too large, tell DaveM");
- }
- sg[sz--].dvma_addr = sbus_dvma_addr(start);
- }
- }
-}
-
-void mmu_release_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus)
-{
- struct iommu_struct *iommu = sbus->iommu;
- struct sysio_regs *sregs = iommu->sysio_regs;
- volatile u64 *sbctrl = (volatile u64 *) &sregs->sbus_control;
- unsigned long flags, tmp;
-
- if (iommu->strbuf_enabled) {
- volatile u64 *sbuf_pflush = (volatile u64 *) &sregs->sbuf_pflush;
-
- spin_lock_irqsave(&iommu->iommu_lock, flags);
-
- /* 1) Clear the flush flag word */
- iommu->flushflag = 0;
-
- /* 2) Tell the streaming buffer which entries
- * we want flushed.
- */
- while(sz >= 0) {
- unsigned long start = sg[sz].dvma_addr;
- unsigned long end = PAGE_ALIGN(start + sg[sz].len);
-
- start &= PAGE_MASK;
- while(start < end) {
- *sbuf_pflush = start;
- start += PAGE_SIZE;
- }
- sz--;
- }
-
- /* 3) Initiate flush sequence. */
- sregs->sbuf_fsync = __pa(&(iommu->flushflag));
-
- /* 4) Guarentee completion of previous writes
- * by reading SYSIO's SBUS control register.
- */
- tmp = *sbctrl;
-
- /* 5) Wait for flush flag to get set. */
- while(iommu->flushflag == 0)
- membar("#LoadLoad");
-
- spin_unlock_irqrestore(&iommu->iommu_lock, flags);
- }
-}
-
-void mmu_set_sbus64(struct linux_sbus_device *sdev, int bursts)
-{
- struct linux_sbus *sbus = sdev->my_bus;
- struct sysio_regs *sregs = sbus->iommu->sysio_regs;
- int slot = sdev->slot;
- volatile u64 *cfg;
- u64 tmp;
-
- switch(slot) {
- case 0:
- cfg = &sregs->sbus_s0cfg;
- break;
- case 1:
- cfg = &sregs->sbus_s1cfg;
- break;
- case 2:
- cfg = &sregs->sbus_s2cfg;
- break;
- case 3:
- cfg = &sregs->sbus_s3cfg;
- break;
-
- case 13:
- cfg = &sregs->sbus_s4cfg;
- break;
- case 14:
- cfg = &sregs->sbus_s5cfg;
- break;
- case 15:
- cfg = &sregs->sbus_s6cfg;
- break;
-
- default:
- return;
- };
-
- /* ETM already enabled? If so, we're done. */
- tmp = *cfg;
- if ((tmp & SYSIO_SBSCFG_ETM) != 0)
- return;
-
- /* Set burst bits. */
- if (bursts & DMA_BURST8)
- tmp |= SYSIO_SBSCFG_BA8;
- if (bursts & DMA_BURST16)
- tmp |= SYSIO_SBSCFG_BA16;
- if (bursts & DMA_BURST32)
- tmp |= SYSIO_SBSCFG_BA32;
- if (bursts & DMA_BURST64)
- tmp |= SYSIO_SBSCFG_BA64;
-
- /* Finally turn on ETM and set register. */
- *cfg = (tmp | SYSIO_SBSCFG_ETM);
-}
-
int mmu_info(char *buf)
{
/* We'll do the rest later to make it nice... -DaveM */
+#if 0
+ if (this_is_cheetah)
+ sprintf(buf, "MMU Type\t: One bad ass cpu\n");
+ else
+#endif
return sprintf(buf, "MMU Type\t: Spitfire\n");
}
-static unsigned long mempool;
-
struct linux_prom_translation {
unsigned long virt;
unsigned long size;
unsigned long data;
};
-static inline void inherit_prom_mappings(void)
+extern unsigned long prom_boot_page;
+extern void prom_remap(unsigned long physpage, unsigned long virtpage, int mmu_ihandle);
+extern int prom_get_mmu_ihandle(void);
+extern void register_prom_callbacks(void);
+
+/* Exported for SMP bootup purposes. */
+unsigned long kern_locked_tte_data;
+
+void __init early_pgtable_allocfail(char *type)
+{
+ prom_printf("inherit_prom_mappings: Cannot alloc kernel %s.\n", type);
+ prom_halt();
+}
+
+static void inherit_prom_mappings(void)
{
struct linux_prom_translation *trans;
+ unsigned long phys_page, tte_vaddr, tte_data;
+ void (*remap_func)(unsigned long, unsigned long, int);
pgd_t *pgdp;
pmd_t *pmdp;
pte_t *ptep;
- int node, n, i;
+ int node, n, i, tsz;
node = prom_finddevice("/virtual-memory");
n = prom_getproplen(node, "translations");
@@ -665,11 +184,17 @@ static inline void inherit_prom_mappings(void)
prom_printf("Couldn't get translation property\n");
prom_halt();
}
+ n += 5 * sizeof(struct linux_prom_translation);
+ for (tsz = 1; tsz < n; tsz <<= 1)
+ /* empty */;
+ trans = __alloc_bootmem(tsz, SMP_CACHE_BYTES, 0UL);
+ if (trans == NULL) {
+ prom_printf("inherit_prom_mappings: Cannot alloc translations.\n");
+ prom_halt();
+ }
+ memset(trans, 0, tsz);
- for (i = 1; i < n; i <<= 1) /* empty */;
- trans = sparc_init_alloc(&mempool, i);
-
- if (prom_getproperty(node, "translations", (char *)trans, i) == -1) {
+ if ((n = prom_getproperty(node, "translations", (char *)trans, tsz)) == -1) {
prom_printf("Couldn't get translation property\n");
prom_halt();
}
@@ -684,15 +209,22 @@ static inline void inherit_prom_mappings(void)
vaddr += PAGE_SIZE) {
pgdp = pgd_offset(&init_mm, vaddr);
if (pgd_none(*pgdp)) {
- pmdp = sparc_init_alloc(&mempool,
- PMD_TABLE_SIZE);
- memset(pmdp, 0, PAGE_SIZE);
+ pmdp = __alloc_bootmem(PMD_TABLE_SIZE,
+ PMD_TABLE_SIZE,
+ 0UL);
+ if (pmdp == NULL)
+ early_pgtable_allocfail("pmd");
+ memset(pmdp, 0, PMD_TABLE_SIZE);
pgd_set(pgdp, pmdp);
}
pmdp = pmd_offset(pgdp, vaddr);
if (pmd_none(*pmdp)) {
- ptep = sparc_init_alloc(&mempool,
- PTE_TABLE_SIZE);
+ ptep = __alloc_bootmem(PTE_TABLE_SIZE,
+ PTE_TABLE_SIZE,
+ 0UL);
+ if (ptep == NULL)
+ early_pgtable_allocfail("pte");
+ memset(ptep, 0, PTE_TABLE_SIZE);
pmd_set(pmdp, ptep);
}
ptep = pte_offset(pmdp, vaddr);
@@ -701,6 +233,83 @@ static inline void inherit_prom_mappings(void)
}
}
}
+
+ /* Now fixup OBP's idea about where we really are mapped. */
+ prom_printf("Remapping the kernel... ");
+ phys_page = spitfire_get_dtlb_data(63) & _PAGE_PADDR;
+ phys_page += ((unsigned long)&prom_boot_page -
+ (unsigned long)&empty_zero_page);
+
+ /* Lock this into i/d tlb entry 59 */
+ __asm__ __volatile__(
+ "stxa %%g0, [%2] %3\n\t"
+ "stxa %0, [%1] %4\n\t"
+ "membar #Sync\n\t"
+ "flush %%g6\n\t"
+ "stxa %%g0, [%2] %5\n\t"
+ "stxa %0, [%1] %6\n\t"
+ "membar #Sync\n\t"
+ "flush %%g6"
+ : : "r" (phys_page | _PAGE_VALID | _PAGE_SZ8K | _PAGE_CP |
+ _PAGE_CV | _PAGE_P | _PAGE_L | _PAGE_W),
+ "r" (59 << 3), "r" (TLB_TAG_ACCESS),
+ "i" (ASI_DMMU), "i" (ASI_DTLB_DATA_ACCESS),
+ "i" (ASI_IMMU), "i" (ASI_ITLB_DATA_ACCESS)
+ : "memory");
+
+ tte_vaddr = (unsigned long) &empty_zero_page;
+ kern_locked_tte_data = tte_data = spitfire_get_dtlb_data(63);
+
+ remap_func = (void *) ((unsigned long) &prom_remap -
+ (unsigned long) &prom_boot_page);
+
+ remap_func(spitfire_get_dtlb_data(63) & _PAGE_PADDR,
+ (unsigned long) &empty_zero_page,
+ prom_get_mmu_ihandle());
+
+ /* Flush out that temporary mapping. */
+ spitfire_flush_dtlb_nucleus_page(0x0);
+ spitfire_flush_itlb_nucleus_page(0x0);
+
+ /* Now lock us back into the TLBs via OBP. */
+ prom_dtlb_load(63, tte_data, tte_vaddr);
+ prom_itlb_load(63, tte_data, tte_vaddr);
+
+ /* Re-read translations property. */
+ if ((n = prom_getproperty(node, "translations", (char *)trans, tsz)) == -1) {
+ prom_printf("Couldn't get translation property\n");
+ prom_halt();
+ }
+ n = n / sizeof(*trans);
+
+ for (i = 0; i < n; i++) {
+ unsigned long vaddr = trans[i].virt;
+ unsigned long size = trans[i].size;
+
+ if (vaddr < 0xf0000000UL) {
+ unsigned long avoid_start = (unsigned long) &empty_zero_page;
+ unsigned long avoid_end = avoid_start + (4 * 1024 * 1024);
+
+ if (vaddr < avoid_start) {
+ unsigned long top = vaddr + size;
+
+ if (top > avoid_start)
+ top = avoid_start;
+ prom_unmap(top - vaddr, vaddr);
+ }
+ if ((vaddr + size) > avoid_end) {
+ unsigned long bottom = vaddr;
+
+ if (bottom < avoid_end)
+ bottom = avoid_end;
+ prom_unmap((vaddr + size) - bottom, bottom);
+ }
+ }
+ }
+
+ prom_printf("done.\n");
+
+ register_prom_callbacks();
}
/* The OBP specifications for sun4u mark 0xfffffffc00000000 and
@@ -1020,6 +629,10 @@ out:
struct pgtable_cache_struct pgt_quicklists;
#endif
+/* For PMDs we don't care about the color, writes are
+ * only done via Dcache which is write-thru, so non-Dcache
+ * reads will always see correct data.
+ */
pmd_t *get_pmd_slow(pgd_t *pgd, unsigned long offset)
{
pmd_t *pmd;
@@ -1033,79 +646,55 @@ pmd_t *get_pmd_slow(pgd_t *pgd, unsigned long offset)
return NULL;
}
-pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset)
-{
- pte_t *pte;
-
- pte = (pte_t *) __get_free_page(GFP_KERNEL);
- if(pte) {
- memset(pte, 0, PAGE_SIZE);
- pmd_set(pmd, pte);
- return pte + offset;
- }
- return NULL;
-}
-
-static void __init
-allocate_ptable_skeleton(unsigned long start, unsigned long end)
-{
- pgd_t *pgdp;
- pmd_t *pmdp;
- pte_t *ptep;
-
- while (start < end) {
- pgdp = pgd_offset(&init_mm, start);
- if (pgd_none(*pgdp)) {
- pmdp = sparc_init_alloc(&mempool, PAGE_SIZE);
- memset(pmdp, 0, PAGE_SIZE);
- pgd_set(pgdp, pmdp);
- }
- pmdp = pmd_offset(pgdp, start);
- if (pmd_none(*pmdp)) {
- ptep = sparc_init_alloc(&mempool, PAGE_SIZE);
- memset(ptep, 0, PAGE_SIZE);
- pmd_set(pmdp, ptep);
- }
- start = (start + PMD_SIZE) & PMD_MASK;
- }
-}
-
-/*
- * Create a mapping for an I/O register. Have to make sure the side-effect
- * bit is set.
+/* OK, we have to color these pages because during DTLB
+ * protection faults we set the dirty bit via a non-Dcache
+ * enabled mapping in the VPTE area. The kernel can end
+ * up missing the dirty bit resulting in processes crashing
+ * _iff_ the VPTE mapping of the ptes have a virtual address
+ * bit 13 which is different from bit 13 of the physical address.
+ *
+ * The sequence is:
+ * 1) DTLB protection fault, write dirty bit into pte via VPTE
+ * mappings.
+ * 2) Swapper checks pte, does not see dirty bit, frees page.
+ * 3) Process faults back in the page, the old pre-dirtied copy
+ * is provided and here is the corruption.
*/
-
-void sparc_ultra_mapioaddr(unsigned long physaddr, unsigned long virt_addr,
- int bus, int rdonly)
+pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset, unsigned long color)
{
- pgd_t *pgdp = pgd_offset(&init_mm, virt_addr);
- pmd_t *pmdp = pmd_offset(pgdp, virt_addr);
- pte_t *ptep = pte_offset(pmdp, virt_addr);
- pte_t pte;
+ unsigned long paddr = __get_free_pages(GFP_KERNEL, 1);
- physaddr &= PAGE_MASK;
+ if (paddr) {
+ struct page *page2 = mem_map + MAP_NR(paddr + PAGE_SIZE);
+ unsigned long *to_free;
+ pte_t *pte;
- if(rdonly)
- pte = mk_pte_phys(physaddr, __pgprot(pg_iobits | __PRIV_BITS));
- else
- pte = mk_pte_phys(physaddr, __pgprot(pg_iobits | __DIRTY_BITS | __PRIV_BITS));
+ /* Set count of second page, so we can free it
+ * seperately later on.
+ */
+ atomic_set(&page2->count, 1);
- set_pte(ptep, pte);
-}
+ /* Clear out both pages now. */
+ memset((char *)paddr, 0, (PAGE_SIZE << 1));
-/* XXX no longer used, remove me... -DaveM */
-void sparc_ultra_unmapioaddr(unsigned long virt_addr)
-{
- pgd_t *pgdp;
- pmd_t *pmdp;
- pte_t *ptep;
+ /* Determine which page we give to this request. */
+ if (!color) {
+ pte = (pte_t *) paddr;
+ to_free = (unsigned long *) (paddr + PAGE_SIZE);
+ } else {
+ pte = (pte_t *) (paddr + PAGE_SIZE);
+ to_free = (unsigned long *) paddr;
+ }
- pgdp = pgd_offset(&init_mm, virt_addr);
- pmdp = pmd_offset(pgdp, virt_addr);
- ptep = pte_offset(pmdp, virt_addr);
+ /* Now free the other one up, adjust cache size. */
+ *to_free = (unsigned long) pte_quicklist[color ^ 0x1];
+ pte_quicklist[color ^ 0x1] = to_free;
+ pgtable_cache_size++;
- /* No need to flush uncacheable page. */
- pte_clear(ptep);
+ pmd_set(pmd, pte);
+ return pte + offset;
+ }
+ return NULL;
}
void sparc_ultra_dump_itlb(void)
@@ -1139,21 +728,114 @@ void sparc_ultra_dump_dtlb(void)
}
}
+#undef DEBUG_BOOTMEM
+
+extern unsigned long cmdline_memory_size;
+
+unsigned long __init bootmem_init(void)
+{
+ unsigned long bootmap_size, start_pfn, end_pfn;
+ unsigned long end_of_phys_memory = 0UL;
+ int i;
+
+ /* XXX It is a bit ambiguous here, whether we should
+ * XXX treat the user specified mem=xxx as total wanted
+ * XXX physical memory, or as a limit to the upper
+ * XXX physical address we allow. For now it is the
+ * XXX latter. -DaveM
+ */
+#ifdef DEBUG_BOOTMEM
+ prom_printf("bootmem_init: Scan sp_banks, ");
+#endif
+ for (i = 0; sp_banks[i].num_bytes != 0; i++) {
+ end_of_phys_memory = sp_banks[i].base_addr +
+ sp_banks[i].num_bytes;
+ if (cmdline_memory_size) {
+ if (end_of_phys_memory > cmdline_memory_size) {
+ if (cmdline_memory_size > sp_banks[i].base_addr) {
+ end_of_phys_memory =
+ sp_banks[i-1].base_addr +
+ sp_banks[i-1].num_bytes;
+ sp_banks[i].base_addr = 0xdeadbeef;
+ sp_banks[i].num_bytes = 0;
+ } else {
+ sp_banks[i].num_bytes -=
+ (end_of_phys_memory -
+ cmdline_memory_size);
+ end_of_phys_memory = cmdline_memory_size;
+ sp_banks[++i].base_addr = 0xdeadbeef;
+ sp_banks[i].num_bytes = 0;
+ }
+ break;
+ }
+ }
+ }
+
+ /* Start with page aligned address of last symbol in kernel
+ * image. The kernel is hard mapped below PAGE_OFFSET in a
+ * 4MB locked TLB translation.
+ */
+ start_pfn = PAGE_ALIGN((unsigned long) &_end) -
+ ((unsigned long) &empty_zero_page);
+
+ /* Adjust up to the physical address where the kernel begins. */
+ start_pfn += phys_base;
+
+ /* Now shift down to get the real physical page frame number. */
+ start_pfn >>= PAGE_SHIFT;
+
+ end_pfn = end_of_phys_memory >> PAGE_SHIFT;
+
+ /* Initialize the boot-time allocator. */
+#ifdef DEBUG_BOOTMEM
+ prom_printf("init_bootmem(spfn[%lx],epfn[%lx])\n",
+ start_pfn, end_pfn);
+#endif
+ bootmap_size = init_bootmem(start_pfn, end_pfn);
+
+ /* Now register the available physical memory with the
+ * allocator.
+ */
+ for (i = 0; sp_banks[i].num_bytes != 0; i++) {
+#ifdef DEBUG_BOOTMEM
+ prom_printf("free_bootmem: base[%lx] size[%lx]\n",
+ sp_banks[i].base_addr,
+ sp_banks[i].num_bytes);
+#endif
+ free_bootmem(sp_banks[i].base_addr,
+ sp_banks[i].num_bytes);
+ }
+
+ /* Reserve the kernel text/data/bss and the bootmem bitmap. */
+#ifdef DEBUG_BOOTMEM
+ prom_printf("reserve_bootmem: base[%lx] size[%lx]\n",
+ phys_base,
+ (((start_pfn << PAGE_SHIFT) +
+ bootmap_size) - phys_base));
+#endif
+ reserve_bootmem(phys_base, (((start_pfn << PAGE_SHIFT) +
+ bootmap_size) - phys_base));
+
+#ifdef DEBUG_BOOTMEM
+ prom_printf("init_bootmem: return end_pfn[%lx]\n", end_pfn);
+#endif
+ return end_pfn;
+}
+
/* paging_init() sets up the page tables */
-extern unsigned long free_area_init(unsigned long, unsigned long);
-extern unsigned long sun_serial_setup(unsigned long);
+extern void sun_serial_setup(void);
+
+static unsigned long last_valid_pfn;
-unsigned long __init
-paging_init(unsigned long start_mem, unsigned long end_mem)
+void __init paging_init(void)
{
extern pmd_t swapper_pmd_dir[1024];
extern unsigned int sparc64_vpte_patchme1[1];
extern unsigned int sparc64_vpte_patchme2[1];
unsigned long alias_base = phys_base + PAGE_OFFSET;
unsigned long second_alias_page = 0;
- unsigned long pt;
- unsigned long flags;
+ unsigned long pt, flags, end_pfn;
unsigned long shift = alias_base - ((unsigned long)&empty_zero_page);
set_bit(0, mmu_context_bmap);
@@ -1176,7 +858,7 @@ paging_init(unsigned long start_mem, unsigned long end_mem)
: "r" (TLB_TAG_ACCESS), "r" (alias_base), "r" (pt),
"i" (ASI_DMMU), "i" (ASI_DTLB_DATA_ACCESS), "r" (61 << 3)
: "memory");
- if (start_mem >= KERNBASE + 0x340000) {
+ if (((unsigned long)&_end) >= KERNBASE + 0x340000) {
second_alias_page = alias_base + 0x400000;
__asm__ __volatile__("
stxa %1, [%0] %3
@@ -1203,24 +885,22 @@ paging_init(unsigned long start_mem, unsigned long end_mem)
/* Now can init the kernel/bad page tables. */
pgd_set(&swapper_pg_dir[0], swapper_pmd_dir + (shift / sizeof(pgd_t)));
- sparc64_vpte_patchme1[0] |= (init_mm.pgd[0] >> 10);
- sparc64_vpte_patchme2[0] |= (init_mm.pgd[0] & 0x3ff);
+ sparc64_vpte_patchme1[0] |= (pgd_val(init_mm.pgd[0]) >> 10);
+ sparc64_vpte_patchme2[0] |= (pgd_val(init_mm.pgd[0]) & 0x3ff);
flushi((long)&sparc64_vpte_patchme1[0]);
- /* We use mempool to create page tables, therefore adjust it up
- * such that __pa() macros etc. work.
- */
- mempool = PAGE_ALIGN(start_mem) + shift;
-
+ /* Setup bootmem... */
+ last_valid_pfn = end_pfn = bootmem_init();
+
#ifdef CONFIG_SUN_SERIAL
- /* This does not logically belong here, but is the first place
- we can initialize it at, so that we work in the PAGE_OFFSET+
- address space. */
- mempool = sun_serial_setup(mempool);
+ /* This does not logically belong here, but we need to
+ * call it at the moment we are able to use the bootmem
+ * allocator.
+ */
+ sun_serial_setup();
#endif
- /* Allocate 64M for dynamic DVMA mapping area. */
- allocate_ptable_skeleton(DVMA_VADDR, DVMA_VADDR + 0x4000000);
+ /* Inherit non-locked OBP mappings. */
inherit_prom_mappings();
/* Ok, we can use our TLB miss and window trap handlers safely.
@@ -1231,205 +911,314 @@ paging_init(unsigned long start_mem, unsigned long end_mem)
{
extern void setup_tba(int);
int is_starfire = prom_finddevice("/ssp-serial");
- if(is_starfire != 0 && is_starfire != -1)
+ if (is_starfire != 0 && is_starfire != -1)
is_starfire = 1;
else
is_starfire = 0;
setup_tba(is_starfire);
}
- /* Really paranoid. */
- flushi((long)&empty_zero_page);
- membar("#Sync");
-
- /* Cleanup the extra locked TLB entry we created since we have the
- * nice TLB miss handlers of ours installed now.
- */
+ inherit_locked_prom_mappings(1);
+
/* We only created DTLB mapping of this stuff. */
spitfire_flush_dtlb_nucleus_page(alias_base);
if (second_alias_page)
spitfire_flush_dtlb_nucleus_page(second_alias_page);
- membar("#Sync");
- /* Paranoid */
- flushi((long)&empty_zero_page);
- membar("#Sync");
+ flush_tlb_all();
- inherit_locked_prom_mappings(1);
+ {
+ unsigned int zones_size[MAX_NR_ZONES] = { 0, 0, 0};
- flush_tlb_all();
+ zones_size[ZONE_DMA] = end_pfn;
+ free_area_init(zones_size);
+ }
- start_mem = free_area_init(PAGE_ALIGN(mempool), end_mem);
+ device_scan();
+}
- return device_scan (PAGE_ALIGN (start_mem));
+/* Ok, it seems that the prom can allocate some more memory chunks
+ * as a side effect of some prom calls we perform during the
+ * boot sequence. My most likely theory is that it is from the
+ * prom_set_traptable() call, and OBP is allocating a scratchpad
+ * for saving client program register state etc.
+ */
+void __init sort_memlist(struct linux_mlist_p1275 *thislist)
+{
+ int swapi = 0;
+ int i, mitr;
+ unsigned long tmpaddr, tmpsize;
+ unsigned long lowest;
+
+ for (i = 0; thislist[i].theres_more != 0; i++) {
+ lowest = thislist[i].start_adr;
+ for (mitr = i+1; thislist[mitr-1].theres_more != 0; mitr++)
+ if (thislist[mitr].start_adr < lowest) {
+ lowest = thislist[mitr].start_adr;
+ swapi = mitr;
+ }
+ if (lowest == thislist[i].start_adr)
+ continue;
+ tmpaddr = thislist[swapi].start_adr;
+ tmpsize = thislist[swapi].num_bytes;
+ for (mitr = swapi; mitr > i; mitr--) {
+ thislist[mitr].start_adr = thislist[mitr-1].start_adr;
+ thislist[mitr].num_bytes = thislist[mitr-1].num_bytes;
+ }
+ thislist[i].start_adr = tmpaddr;
+ thislist[i].num_bytes = tmpsize;
+ }
}
-static void __init taint_real_pages(unsigned long start_mem, unsigned long end_mem)
+void __init rescan_sp_banks(void)
{
- unsigned long tmp = 0, paddr, endaddr;
- unsigned long end = __pa(end_mem);
+ struct linux_prom64_registers memlist[64];
+ struct linux_mlist_p1275 avail[64], *mlist;
+ unsigned long bytes, base_paddr;
+ int num_regs, node = prom_finddevice("/memory");
+ int i;
- dvmaio_init();
- for (paddr = __pa(start_mem); paddr < end; ) {
- for (; sp_banks[tmp].num_bytes != 0; tmp++)
- if (sp_banks[tmp].base_addr + sp_banks[tmp].num_bytes > paddr)
- break;
- if (!sp_banks[tmp].num_bytes) {
- mem_map[paddr>>PAGE_SHIFT].flags |= (1<<PG_skip);
- mem_map[paddr>>PAGE_SHIFT].next_hash = mem_map + (phys_base >> PAGE_SHIFT);
- mem_map[(paddr>>PAGE_SHIFT)+1UL].flags |= (1<<PG_skip);
- mem_map[(paddr>>PAGE_SHIFT)+1UL].next_hash = mem_map + (phys_base >> PAGE_SHIFT);
- return;
+ num_regs = prom_getproperty(node, "available",
+ (char *) memlist, sizeof(memlist));
+ num_regs = (num_regs / sizeof(struct linux_prom64_registers));
+ for (i = 0; i < num_regs; i++) {
+ avail[i].start_adr = memlist[i].phys_addr;
+ avail[i].num_bytes = memlist[i].reg_size;
+ avail[i].theres_more = &avail[i + 1];
+ }
+ avail[i - 1].theres_more = NULL;
+ sort_memlist(avail);
+
+ mlist = &avail[0];
+ i = 0;
+ bytes = mlist->num_bytes;
+ base_paddr = mlist->start_adr;
+
+ sp_banks[0].base_addr = base_paddr;
+ sp_banks[0].num_bytes = bytes;
+
+ while (mlist->theres_more != NULL){
+ i++;
+ mlist = mlist->theres_more;
+ bytes = mlist->num_bytes;
+ if (i >= SPARC_PHYS_BANKS-1) {
+ printk ("The machine has more banks than "
+ "this kernel can support\n"
+ "Increase the SPARC_PHYS_BANKS "
+ "setting (currently %d)\n",
+ SPARC_PHYS_BANKS);
+ i = SPARC_PHYS_BANKS-1;
+ break;
}
-
- if (sp_banks[tmp].base_addr > paddr) {
- /* Making a one or two pages PG_skip holes
- * is not necessary. We add one more because
- * we must set the PG_skip flag on the first
- * two mem_map[] entries for the hole. Go and
- * see the mm/filemap.c:shrink_mmap() loop for
- * details. -DaveM
- */
- if (sp_banks[tmp].base_addr - paddr > 3 * PAGE_SIZE) {
- mem_map[paddr>>PAGE_SHIFT].flags |= (1<<PG_skip);
- mem_map[paddr>>PAGE_SHIFT].next_hash = mem_map + (sp_banks[tmp].base_addr >> PAGE_SHIFT);
- mem_map[(paddr>>PAGE_SHIFT)+1UL].flags |= (1<<PG_skip);
- mem_map[(paddr>>PAGE_SHIFT)+1UL].next_hash = mem_map + (sp_banks[tmp].base_addr >> PAGE_SHIFT);
+
+ sp_banks[i].base_addr = mlist->start_adr;
+ sp_banks[i].num_bytes = mlist->num_bytes;
+ }
+
+ i++;
+ sp_banks[i].base_addr = 0xdeadbeefbeefdeadUL;
+ sp_banks[i].num_bytes = 0;
+
+ for (i = 0; sp_banks[i].num_bytes != 0; i++)
+ sp_banks[i].num_bytes &= PAGE_MASK;
+}
+
+static void __init taint_real_pages(void)
+{
+ struct sparc_phys_banks saved_sp_banks[SPARC_PHYS_BANKS];
+ int i;
+
+#ifdef DEBUG_BOOTMEM
+ prom_printf("taint_real_pages: Rescan sp_banks[].\n");
+#endif
+ for (i = 0; i < SPARC_PHYS_BANKS; i++) {
+ saved_sp_banks[i].base_addr =
+ sp_banks[i].base_addr;
+ saved_sp_banks[i].num_bytes =
+ sp_banks[i].num_bytes;
+ }
+
+ rescan_sp_banks();
+
+ /* Find changes discovered in the sp_bank rescan and
+ * reserve the lost portions in the bootmem maps.
+ */
+ for (i = 0; saved_sp_banks[i].num_bytes; i++) {
+ unsigned long old_start, old_end;
+
+ old_start = saved_sp_banks[i].base_addr;
+ old_end = old_start +
+ saved_sp_banks[i].num_bytes;
+ while (old_start < old_end) {
+ int n;
+
+ for (n = 0; sp_banks[n].num_bytes; n++) {
+ unsigned long new_start, new_end;
+
+ new_start = sp_banks[n].base_addr;
+ new_end = new_start + sp_banks[n].num_bytes;
+
+ if (new_start <= old_start &&
+ new_end >= (old_start + PAGE_SIZE)) {
+ set_bit (old_start >> 22,
+ sparc64_valid_addr_bitmap);
+ goto do_next_page;
+ }
}
- paddr = sp_banks[tmp].base_addr;
+#ifdef DEBUG_BOOTMEM
+ prom_printf("taint: Page went away, reserve page %lx.\n",
+ old_start);
+#endif
+ reserve_bootmem(old_start, PAGE_SIZE);
+
+ do_next_page:
+ old_start += PAGE_SIZE;
}
-
- endaddr = sp_banks[tmp].base_addr + sp_banks[tmp].num_bytes;
- while (paddr < endaddr) {
- mem_map[paddr>>PAGE_SHIFT].flags &= ~(1<<PG_reserved);
- set_bit(paddr >> 22, sparc64_valid_addr_bitmap);
- if (paddr >= (MAX_DMA_ADDRESS - PAGE_OFFSET))
- mem_map[paddr>>PAGE_SHIFT].flags &= ~(1<<PG_DMA);
- paddr += PAGE_SIZE;
+ }
+}
+
+void __init free_mem_map_range(struct page *first, struct page *last)
+{
+ first = (struct page *) PAGE_ALIGN((unsigned long)first);
+ last = (struct page *) ((unsigned long)last & PAGE_MASK);
+#ifdef DEBUG_BOOTMEM
+ prom_printf("[%p,%p] ", first, last);
+#endif
+ while (first < last) {
+ ClearPageReserved(mem_map + MAP_NR(first));
+ set_page_count(mem_map + MAP_NR(first), 1);
+ free_page((unsigned long)first);
+ totalram_pages++;
+ num_physpages++;
+
+ first = (struct page *)((unsigned long)first + PAGE_SIZE);
+ }
+}
+
+/* Walk through holes in sp_banks regions, if the mem_map array
+ * areas representing those holes consume a page or more, free
+ * up such pages. This helps a lot on machines where physical
+ * ram is configured such that it begins at some hugh value.
+ *
+ * The sp_banks array is sorted by base address.
+ */
+void __init free_unused_mem_map(void)
+{
+ int i;
+
+#ifdef DEBUG_BOOTMEM
+ prom_printf("free_unused_mem_map: ");
+#endif
+ for (i = 0; sp_banks[i].num_bytes; i++) {
+ if (i == 0) {
+ struct page *first, *last;
+
+ first = mem_map;
+ last = &mem_map[sp_banks[i].base_addr >> PAGE_SHIFT];
+ free_mem_map_range(first, last);
+ } else {
+ struct page *first, *last;
+ unsigned long prev_end;
+
+ prev_end = sp_banks[i-1].base_addr +
+ sp_banks[i-1].num_bytes;
+ prev_end = PAGE_ALIGN(prev_end);
+ first = &mem_map[prev_end >> PAGE_SHIFT];
+ last = &mem_map[sp_banks[i].base_addr >> PAGE_SHIFT];
+
+ free_mem_map_range(first, last);
+
+ if (!sp_banks[i+1].num_bytes) {
+ prev_end = sp_banks[i].base_addr +
+ sp_banks[i].num_bytes;
+ first = &mem_map[prev_end >> PAGE_SHIFT];
+ last = &mem_map[last_valid_pfn];
+ free_mem_map_range(first, last);
+ }
}
}
+#ifdef DEBUG_BOOTMEM
+ prom_printf("\n");
+#endif
}
-void __init mem_init(unsigned long start_mem, unsigned long end_mem)
+void __init mem_init(void)
{
- int codepages = 0;
- int datapages = 0;
- int initpages = 0;
- unsigned long addr;
- unsigned long alias_base = phys_base + PAGE_OFFSET - (long)(&empty_zero_page);
- struct page *page, *end;
+ unsigned long codepages, datapages, initpages;
+ unsigned long addr, last;
int i;
- end_mem &= PAGE_MASK;
- max_mapnr = MAP_NR(end_mem);
- high_memory = (void *) end_mem;
-
- start_mem = ((start_mem + 7UL) & ~7UL);
- sparc64_valid_addr_bitmap = (unsigned long *)start_mem;
- i = max_mapnr >> ((22 - PAGE_SHIFT) + 6);
+ i = last_valid_pfn >> ((22 - PAGE_SHIFT) + 6);
i += 1;
- memset(sparc64_valid_addr_bitmap, 0, i << 3);
- start_mem += i << 3;
-
- start_mem = PAGE_ALIGN(start_mem);
- num_physpages = 0;
-
- if (phys_base) {
- mem_map[0].flags |= (1<<PG_skip) | (1<<PG_reserved);
- mem_map[0].next_hash = mem_map + (phys_base >> PAGE_SHIFT);
- mem_map[1].flags |= (1<<PG_skip) | (1<<PG_reserved);
- mem_map[1].next_hash = mem_map + (phys_base >> PAGE_SHIFT);
+ sparc64_valid_addr_bitmap = (unsigned long *)
+ __alloc_bootmem(i << 3, SMP_CACHE_BYTES, 0UL);
+ if (sparc64_valid_addr_bitmap == NULL) {
+ prom_printf("mem_init: Cannot alloc valid_addr_bitmap.\n");
+ prom_halt();
}
+ memset(sparc64_valid_addr_bitmap, 0, i << 3);
addr = PAGE_OFFSET + phys_base;
- while(addr < start_mem) {
+ last = PAGE_ALIGN((unsigned long)&_end) -
+ ((unsigned long) &empty_zero_page);
+ last += PAGE_OFFSET + phys_base;
+ while (addr < last) {
#ifdef CONFIG_BLK_DEV_INITRD
+// FIXME to use bootmem scheme...
if (initrd_below_start_ok && addr >= initrd_start && addr < initrd_end)
mem_map[MAP_NR(addr)].flags &= ~(1<<PG_reserved);
- else
#endif
- mem_map[MAP_NR(addr)].flags |= (1<<PG_reserved);
set_bit(__pa(addr) >> 22, sparc64_valid_addr_bitmap);
addr += PAGE_SIZE;
}
- taint_real_pages(start_mem, end_mem);
-
-#ifdef FREE_UNUSED_MEM_MAP
- end = mem_map + max_mapnr;
- for (page = mem_map; page < end; page++) {
- if (PageSkip(page)) {
- unsigned long low, high;
-
- /* See taint_real_pages() for why this is done. -DaveM */
- page++;
-
- low = PAGE_ALIGN((unsigned long)(page+1));
- if (page->next_hash < page)
- high = ((unsigned long)end) & PAGE_MASK;
- else
- high = ((unsigned long)page->next_hash) & PAGE_MASK;
- while (low < high) {
- mem_map[MAP_NR(low)].flags &= ~(1<<PG_reserved);
- low += PAGE_SIZE;
- }
- }
- }
+ taint_real_pages();
+
+ max_mapnr = last_valid_pfn;
+ high_memory = __va(last_valid_pfn << PAGE_SHIFT);
+
+#ifdef DEBUG_BOOTMEM
+ prom_printf("mem_init: Calling free_all_bootmem().\n");
#endif
-
- for (addr = PAGE_OFFSET; addr < end_mem; addr += PAGE_SIZE) {
- if (PageSkip(mem_map + MAP_NR(addr))) {
- unsigned long next = mem_map[MAP_NR(addr)].next_hash - mem_map;
-
- next = (next << PAGE_SHIFT) + PAGE_OFFSET;
- if (next < addr || next >= end_mem)
- break;
- addr = next;
- }
- num_physpages++;
- if (PageReserved(mem_map + MAP_NR(addr))) {
- if ((addr < ((unsigned long) &etext) + alias_base) && (addr >= alias_base))
- codepages++;
- else if((addr >= ((unsigned long)&__init_begin) + alias_base)
- && (addr < ((unsigned long)&__init_end) + alias_base))
- initpages++;
- else if((addr < start_mem) && (addr >= alias_base))
- datapages++;
- continue;
- }
- atomic_set(&mem_map[MAP_NR(addr)].count, 1);
-#ifdef CONFIG_BLK_DEV_INITRD
- if (!initrd_start ||
- (addr < initrd_start || addr >= initrd_end))
+ num_physpages = totalram_pages = free_all_bootmem();
+#if 0
+ free_unused_mem_map();
#endif
- free_page(addr);
- }
-
+ codepages = (((unsigned long) &etext) - ((unsigned long)&_start));
+ codepages = PAGE_ALIGN(codepages) >> PAGE_SHIFT;
+ datapages = (((unsigned long) &edata) - ((unsigned long)&etext));
+ datapages = PAGE_ALIGN(datapages) >> PAGE_SHIFT;
+ initpages = (((unsigned long) &__init_end) - ((unsigned long) &__init_begin));
+ initpages = PAGE_ALIGN(initpages) >> PAGE_SHIFT;
+
#ifndef __SMP__
{
/* Put empty_pg_dir on pgd_quicklist */
extern pgd_t empty_pg_dir[1024];
unsigned long addr = (unsigned long)empty_pg_dir;
+ unsigned long alias_base = phys_base + PAGE_OFFSET -
+ (long)(&empty_zero_page);
memset(empty_pg_dir, 0, sizeof(empty_pg_dir));
addr += alias_base;
- mem_map[MAP_NR(addr)].pprev_hash = 0;
free_pgd_fast((pgd_t *)addr);
+ totalram_pages++;
+ num_physpages++;
}
#endif
- printk("Memory: %uk available (%dk kernel code, %dk data, %dk init) [%016lx,%016lx]\n",
- nr_free_pages << (PAGE_SHIFT-10),
+ printk("Memory: %uk available (%ldk kernel code, %ldk data, %ldk init) [%016lx,%016lx]\n",
+ nr_free_pages() << (PAGE_SHIFT-10),
codepages << (PAGE_SHIFT-10),
datapages << (PAGE_SHIFT-10),
initpages << (PAGE_SHIFT-10),
- PAGE_OFFSET, end_mem);
+ PAGE_OFFSET, (last_valid_pfn << PAGE_SHIFT));
/* NOTE NOTE NOTE NOTE
* Please keep track of things and make sure this
* always matches the code in mm/page_alloc.c -DaveM
*/
- i = nr_free_pages >> 7;
+ i = nr_free_pages() >> 7;
if (i < 48)
i = 48;
if (i > 256)
@@ -1442,42 +1231,35 @@ void __init mem_init(unsigned long start_mem, unsigned long end_mem)
void free_initmem (void)
{
unsigned long addr;
-
+
addr = (unsigned long)(&__init_begin);
for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) {
- unsigned long page = addr + (long)__va(phys_base)
- - (long)(&empty_zero_page);
-
- mem_map[MAP_NR(page)].flags &= ~(1 << PG_reserved);
- atomic_set(&mem_map[MAP_NR(page)].count, 1);
- free_page(page);
+ unsigned long page;
+ struct page *p;
+
+ page = (addr +
+ ((unsigned long) __va(phys_base)) -
+ ((unsigned long) &empty_zero_page));
+ p = mem_map + MAP_NR(page);
+
+ ClearPageReserved(p);
+ set_page_count(p, 1);
+ __free_page(p);
+ totalram_pages++;
+ num_physpages++;
}
}
void si_meminfo(struct sysinfo *val)
{
- struct page *page, *end;
-
- val->totalram = 0;
+ val->totalram = totalram_pages;
val->sharedram = 0;
- val->freeram = ((unsigned long)nr_free_pages) << PAGE_SHIFT;
- val->bufferram = atomic_read(&buffermem);
- for (page = mem_map, end = mem_map + max_mapnr;
- page < end; page++) {
- if (PageSkip(page)) {
- if (page->next_hash < page)
- break;
- page = page->next_hash;
- }
- if (PageReserved(page))
- continue;
- val->totalram++;
- if (!atomic_read(&page->count))
- continue;
- val->sharedram += atomic_read(&page->count) - 1;
- }
- val->totalram <<= PAGE_SHIFT;
- val->sharedram <<= PAGE_SHIFT;
- val->totalbig = 0;
- val->freebig = 0;
+ val->freeram = nr_free_pages();
+ val->bufferram = atomic_read(&buffermem_pages);
+
+ /* These are always zero on Sparc64. */
+ val->totalhigh = 0;
+ val->freehigh = 0;
+
+ val->mem_unit = PAGE_SIZE;
}
diff --git a/arch/sparc64/mm/ultra.S b/arch/sparc64/mm/ultra.S
index 638edae1d..cb281a659 100644
--- a/arch/sparc64/mm/ultra.S
+++ b/arch/sparc64/mm/ultra.S
@@ -1,4 +1,4 @@
-/* $Id: ultra.S,v 1.34 1999/09/10 10:40:51 davem Exp $
+/* $Id: ultra.S,v 1.36 1999/12/15 15:45:18 davem Exp $
* ultra.S: Don't expand these all over the place...
*
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -174,10 +174,10 @@ iflush2:stxa %g0, [%o1 + %o2] ASI_IC_TAG
*
* Register usage:
* %g5 mm->context (all tlb flushes)
- * %g6 address arg 1 (tlb page and range flushes)
+ * %g1 address arg 1 (tlb page and range flushes)
* %g7 address arg 2 (tlb range flush only)
*
- * %g1 ivector table, don't touch
+ * %g6 ivector table, don't touch
* %g2 scratch 1
* %g3 scratch 2
* %g4 scratch 3
@@ -188,7 +188,7 @@ iflush2:stxa %g0, [%o1 + %o2] ASI_IC_TAG
.globl xcall_flush_tlb_page, xcall_flush_tlb_mm, xcall_flush_tlb_range
xcall_flush_tlb_page:
mov SECONDARY_CONTEXT, %g2
- or %g6, 0x10, %g4
+ or %g1, 0x10, %g4
ldxa [%g2] ASI_DMMU, %g3
stxa %g5, [%g2] ASI_DMMU
stxa %g0, [%g4] ASI_DMMU_DEMAP
@@ -209,11 +209,11 @@ xcall_flush_tlb_mm:
xcall_flush_tlb_range:
sethi %hi(8192 - 1), %g2
or %g2, %lo(8192 - 1), %g2
- andn %g6, %g2, %g6
+ andn %g1, %g2, %g1
andn %g7, %g2, %g7
- sub %g7, %g6, %g3
+ sub %g7, %g1, %g3
add %g2, 1, %g2
- orcc %g6, 0x10, %g6
+ orcc %g1, 0x10, %g1
srlx %g3, 13, %g4
cmp %g4, 96
@@ -225,8 +225,8 @@ xcall_flush_tlb_range:
nop
nop
-1: stxa %g0, [%g6 + %g3] ASI_DMMU_DEMAP
- stxa %g0, [%g6 + %g3] ASI_IMMU_DEMAP
+1: stxa %g0, [%g1 + %g3] ASI_DMMU_DEMAP
+ stxa %g0, [%g1 + %g3] ASI_IMMU_DEMAP
brnz,pt %g3, 1b
sub %g3, %g2, %g3
stxa %g7, [%g4] ASI_DMMU
@@ -262,6 +262,22 @@ xcall_capture:
b,pt %xcc, rtrap
clr %l6
+ .globl xcall_promstop
+xcall_promstop:
+ rdpr %pstate, %g2
+ wrpr %g2, PSTATE_IG | PSTATE_AG, %pstate
+ rdpr %pil, %g2
+ wrpr %g0, 15, %pil
+ sethi %hi(109f), %g7
+ b,pt %xcc, etrap_irq
+109: or %g7, %lo(109b), %g7
+ flushw
+ call prom_stopself
+ nop
+ /* We should not return, just spin if we do... */
+1: b,a,pt %xcc, 1b
+ nop
+
.globl xcall_receive_signal
xcall_receive_signal:
rdpr %pstate, %g2
@@ -303,7 +319,7 @@ xcall_flush_tlb_all:
cmp %g2, 63
ble,pt %icc, 1b
sll %g2, 3, %g3
- flush %g1
+ flush %g6
retry
.globl xcall_flush_cache_all
@@ -316,6 +332,6 @@ xcall_flush_cache_all:
cmp %g3, %g2
bleu,pt %xcc, 1b
nop
- flush %g1
+ flush %g6
retry
#endif /* __SMP__ */
diff --git a/arch/sparc64/prom/Makefile b/arch/sparc64/prom/Makefile
index 1cec2111e..42906da28 100644
--- a/arch/sparc64/prom/Makefile
+++ b/arch/sparc64/prom/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.2 1997/02/25 12:40:25 jj Exp $
+# $Id: Makefile,v 1.5 1999/12/21 04:02:26 davem Exp $
# Makefile for the Sun Boot PROM interface library under
# Linux.
#
@@ -9,7 +9,7 @@
# Note 2! The CFLAGS definitions are now in the main makefile...
OBJS = bootstr.o devops.o init.o memory.o misc.o \
- ranges.o tree.o console.o printf.o p1275.o
+ tree.o console.o printf.o p1275.o map.o
all: promlib.a
@@ -17,7 +17,13 @@ promlib.a: $(OBJS)
$(AR) rcs promlib.a $(OBJS)
sync
+.S.s:
+ $(CPP) -D__ASSEMBLY__ $(AFLAGS) -ansi $< -o $*.s
+
+.S.o:
+ $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c $< -o $*.o
+
dep:
- $(CPP) -M *.c > .depend
+ $(CPP) $(CPPFLAGS) -M *.c > .depend
include $(TOPDIR)/Rules.make
diff --git a/arch/sparc64/prom/init.c b/arch/sparc64/prom/init.c
index 17166a72c..dad2f8302 100644
--- a/arch/sparc64/prom/init.c
+++ b/arch/sparc64/prom/init.c
@@ -1,4 +1,4 @@
-/* $Id: init.c,v 1.9 1999/08/31 06:55:03 davem Exp $
+/* $Id: init.c,v 1.10 1999/09/21 14:35:59 davem Exp $
* init.c: Initialize internal variables used by the PROM
* library functions.
*
@@ -28,7 +28,6 @@ int prom_chosen_node;
*/
extern void prom_meminit(void);
-extern void prom_ranges_init(void);
extern void prom_cif_init(void *, void *);
void __init prom_init(void *cif_handler, void *cif_stack)
@@ -82,8 +81,6 @@ void __init prom_init(void *cif_handler, void *cif_stack)
prom_meminit();
- prom_ranges_init();
-
/* Initialization successful. */
return;
diff --git a/arch/sparc64/prom/map.S b/arch/sparc64/prom/map.S
new file mode 100644
index 000000000..509f7b4ab
--- /dev/null
+++ b/arch/sparc64/prom/map.S
@@ -0,0 +1,70 @@
+/* $Id: map.S,v 1.2 1999/11/19 05:53:02 davem Exp $
+ * map.S: Tricky coding required to fixup the kernel OBP maps
+ * properly.
+ *
+ * Copyright (C) 1999 David S. Miller (davem@redhat.com)
+ */
+
+ .text
+ .align 8192
+ .globl prom_boot_page
+prom_boot_page:
+call_method:
+ .asciz "call-method"
+ .align 8
+map:
+ .asciz "map"
+ .align 8
+
+ /* When we are invoked, our caller has remapped us to
+ * page zero, therefore we must use PC relative addressing
+ * for everything after we begin performing the unmap/map
+ * calls.
+ */
+ .globl prom_remap
+prom_remap: /* %o0 = physpage, %o1 = virtpage, %o2 = mmu_ihandle */
+ rd %pc, %g1
+ srl %o2, 0, %o2 ! kill sign extension
+ sethi %hi(p1275buf), %g2
+ or %g2, %lo(p1275buf), %g2
+ ldx [%g2 + 0x10], %g3 ! prom_cif_stack
+ save %g3, -(192 + 128), %sp
+ ldx [%g2 + 0x08], %l0 ! prom_cif_handler
+ mov %g6, %i3
+ mov %g4, %i4
+ flushw
+
+ sethi %hi(prom_remap - call_method), %g7
+ or %g7, %lo(prom_remap - call_method), %g7
+ sub %g1, %g7, %l2 ! call-method string
+ sethi %hi(prom_remap - map), %g7
+ or %g7, %lo(prom_remap - map), %g7
+ sub %g1, %g7, %l4 ! map string
+
+ /* OK, map the 4MB region we really live at. */
+ stx %l2, [%sp + 2047 + 128 + 0x00] ! call-method
+ mov 7, %l5
+ stx %l5, [%sp + 2047 + 128 + 0x08] ! num_args
+ mov 1, %l5
+ stx %l5, [%sp + 2047 + 128 + 0x10] ! num_rets
+ stx %l4, [%sp + 2047 + 128 + 0x18] ! map
+ stx %i2, [%sp + 2047 + 128 + 0x20] ! mmu_ihandle
+ mov -1, %l5
+ stx %l5, [%sp + 2047 + 128 + 0x28] ! mode == default
+ sethi %hi(4 * 1024 * 1024), %l5
+ stx %l5, [%sp + 2047 + 128 + 0x30] ! size
+ stx %i1, [%sp + 2047 + 128 + 0x38] ! vaddr
+ stx %g0, [%sp + 2047 + 128 + 0x40] ! filler
+ stx %i0, [%sp + 2047 + 128 + 0x48] ! paddr
+ call %l0
+ add %sp, (2047 + 128), %o0 ! argument array
+
+ /* Restore hard-coded globals. */
+ mov %i3, %g6
+ mov %i4, %g4
+
+ /* Wheee.... we are done. */
+ ret
+ restore
+
+ .align 8192
diff --git a/arch/sparc64/prom/misc.c b/arch/sparc64/prom/misc.c
index 2a45a4bb5..8d6404fea 100644
--- a/arch/sparc64/prom/misc.c
+++ b/arch/sparc64/prom/misc.c
@@ -1,4 +1,4 @@
-/* $Id: misc.c,v 1.15 1999/08/31 19:25:41 davem Exp $
+/* $Id: misc.c,v 1.16 1999/11/19 05:53:04 davem Exp $
* misc.c: Miscellaneous prom functions that don't belong
* anywhere else.
*
@@ -10,6 +10,8 @@
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
#include <asm/openprom.h>
#include <asm/oplib.h>
@@ -37,6 +39,11 @@ extern void (*prom_palette)(int);
extern int serial_console;
#endif
+#ifdef __SMP__
+extern void smp_capture(void);
+extern void smp_release(void);
+#endif
+
/* Drop into the prom, with the chance to continue with the 'go'
* prom command.
*/
@@ -44,26 +51,57 @@ void
prom_cmdline(void)
{
unsigned long flags;
-
+
+ __save_and_cli(flags);
+
#ifdef CONFIG_SUN_CONSOLE
if(!serial_console && prom_palette)
prom_palette (1);
#endif
- __save_and_cli(flags);
+
+ /* We always arrive here via a serial interrupt.
+ * So in order for everything to work reliably, even
+ * on SMP, we need to drop the IRQ locks we hold.
+ */
+#ifdef __SMP__
+ hardirq_exit(smp_processor_id());
+ smp_capture();
+#else
+ local_irq_count--;
+#endif
+
p1275_cmd ("enter", P1275_INOUT(0,0));
- __restore_flags(flags);
+
+#ifdef __SMP__
+ smp_release();
+ hardirq_enter(smp_processor_id());
+ spin_unlock_wait(&global_irq_lock);
+#else
+ local_irq_count++;
+#endif
+
#ifdef CONFIG_SUN_CONSOLE
if(!serial_console && prom_palette)
prom_palette (0);
#endif
+
+ __restore_flags(flags);
}
+#ifdef __SMP__
+extern void smp_promstop_others(void);
+#endif
+
/* Drop into the prom, but completely terminate the program.
* No chance of continuing.
*/
void
prom_halt(void)
{
+#ifdef __SMP__
+ smp_promstop_others();
+ udelay(8000);
+#endif
again:
p1275_cmd ("exit", P1275_INOUT(0,0));
goto again; /* PROM is out to get me -DaveM */
@@ -122,10 +160,10 @@ void prom_set_trap_table(unsigned long tba)
p1275_cmd("SUNW,set-trap-table", P1275_INOUT(1, 0), tba);
}
-/* This is only used internally below. */
-static int prom_get_mmu_ihandle(void)
+int mmu_ihandle_cache = 0;
+
+int prom_get_mmu_ihandle(void)
{
- static int mmu_ihandle_cache = 0;
int node, ret;
if (mmu_ihandle_cache != 0)
@@ -165,7 +203,10 @@ long prom_itlb_load(unsigned long index,
unsigned long vaddr)
{
return p1275_cmd("call-method",
- (P1275_ARG(0, P1275_ARG_IN_BUF) | P1275_INOUT(5, 1)),
+ (P1275_ARG(0, P1275_ARG_IN_STRING) |
+ P1275_ARG(2, P1275_ARG_IN_64B) |
+ P1275_ARG(3, P1275_ARG_IN_64B) |
+ P1275_INOUT(5, 1)),
"SUNW,itlb-load",
prom_get_mmu_ihandle(),
/* And then our actual args are pushed backwards. */
@@ -179,7 +220,10 @@ long prom_dtlb_load(unsigned long index,
unsigned long vaddr)
{
return p1275_cmd("call-method",
- (P1275_ARG(0, P1275_ARG_IN_BUF) | P1275_INOUT(5, 1)),
+ (P1275_ARG(0, P1275_ARG_IN_STRING) |
+ P1275_ARG(2, P1275_ARG_IN_64B) |
+ P1275_ARG(3, P1275_ARG_IN_64B) |
+ P1275_INOUT(5, 1)),
"SUNW,dtlb-load",
prom_get_mmu_ihandle(),
/* And then our actual args are pushed backwards. */
@@ -188,6 +232,41 @@ long prom_dtlb_load(unsigned long index,
index);
}
+int prom_map(int mode, unsigned long size,
+ unsigned long vaddr, unsigned long paddr)
+{
+ int ret = p1275_cmd("call-method",
+ (P1275_ARG(0, P1275_ARG_IN_STRING) |
+ P1275_ARG(3, P1275_ARG_IN_64B) |
+ P1275_ARG(4, P1275_ARG_IN_64B) |
+ P1275_ARG(6, P1275_ARG_IN_64B) |
+ P1275_INOUT(7, 1)),
+ "map",
+ prom_get_mmu_ihandle(),
+ mode,
+ size,
+ vaddr,
+ 0,
+ paddr);
+
+ if (ret == 0)
+ ret = -1;
+ return ret;
+}
+
+void prom_unmap(unsigned long size, unsigned long vaddr)
+{
+ p1275_cmd("call-method",
+ (P1275_ARG(0, P1275_ARG_IN_STRING) |
+ P1275_ARG(2, P1275_ARG_IN_64B) |
+ P1275_ARG(3, P1275_ARG_IN_64B) |
+ P1275_INOUT(4, 0)),
+ "unmap",
+ prom_get_mmu_ihandle(),
+ size,
+ vaddr);
+}
+
/* Set aside physical memory which is not touched or modified
* across soft resets.
*/
@@ -226,7 +305,7 @@ int prom_getunumber(int syndrome_code,
return p1275_cmd("call-method",
(P1275_ARG(0, P1275_ARG_IN_STRING) |
P1275_ARG(3, P1275_ARG_OUT_BUF) |
- P1275_ARG(5, P1275_ARG_IN_64B) |
+ P1275_ARG(6, P1275_ARG_IN_64B) |
P1275_INOUT(8, 2)),
"SUNW,get-unumber", prom_get_memory_ihandle(),
buflen, buf, P1275_SIZE(buflen),
diff --git a/arch/sparc64/prom/p1275.c b/arch/sparc64/prom/p1275.c
index f30bdd3a8..5a4e4b693 100644
--- a/arch/sparc64/prom/p1275.c
+++ b/arch/sparc64/prom/p1275.c
@@ -1,4 +1,4 @@
-/* $Id: p1275.c,v 1.18 1999/09/10 10:40:53 davem Exp $
+/* $Id: p1275.c,v 1.20 1999/11/23 23:47:56 davem Exp $
* p1275.c: Sun IEEE 1275 PROM low level interface routines
*
* Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -252,11 +252,7 @@ void prom_cif_callback(void)
* the counter is needed. -DaveM
*/
static int prom_entry_depth = 0;
-static spinlock_t prom_entry_lock = SPIN_LOCK_UNLOCKED;
-#ifdef __SMP__
-extern void smp_capture(void);
-extern void smp_release(void);
-#endif
+spinlock_t prom_entry_lock = SPIN_LOCK_UNLOCKED;
static __inline__ unsigned long prom_get_lock(void)
{
@@ -270,9 +266,6 @@ static __inline__ unsigned long prom_get_lock(void)
if (prom_entry_depth != 0)
panic("prom_get_lock");
#endif
-#ifdef __SMP__
- smp_capture();
-#endif
}
prom_entry_depth++;
@@ -281,12 +274,9 @@ static __inline__ unsigned long prom_get_lock(void)
static __inline__ void prom_release_lock(unsigned long flags)
{
- if (--prom_entry_depth == 0) {
-#ifdef __SMP__
- smp_release();
-#endif
+ if (--prom_entry_depth == 0)
spin_unlock(&prom_entry_lock);
- }
+
__restore_flags(flags);
}
diff --git a/arch/sparc64/prom/ranges.c b/arch/sparc64/prom/ranges.c
deleted file mode 100644
index 048e3412a..000000000
--- a/arch/sparc64/prom/ranges.c
+++ /dev/null
@@ -1,192 +0,0 @@
-/* $Id: ranges.c,v 1.12 1999/08/31 06:55:05 davem Exp $
- * ranges.c: Handle ranges in newer proms for obio/sbus.
- *
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
- */
-
-#include <linux/config.h>
-#include <linux/init.h>
-#include <asm/openprom.h>
-#include <asm/oplib.h>
-#include <asm/sbus.h>
-#include <asm/fhc.h>
-#include <asm/system.h>
-#ifdef CONFIG_PCI
-#include <asm/pbm.h>
-#include <asm/ebus.h>
-#endif
-
-struct linux_prom_ranges promlib_obio_ranges[PROMREG_MAX];
-int num_obio_ranges;
-
-/* Adjust register values based upon the ranges parameters. */
-inline void
-prom_adjust_regs(struct linux_prom_registers *regp, int nregs,
- struct linux_prom_ranges *rangep, int nranges)
-{
- int regc, rngc;
-
- for(regc=0; regc < nregs; regc++) {
- for(rngc=0; rngc < nranges; rngc++)
- if(regp[regc].which_io == rangep[rngc].ot_child_space)
- break; /* Fount it */
- if(rngc==nranges) /* oops */
- prom_printf("adjust_regs: Could not find range with matching bus type...\n");
- regp[regc].which_io = rangep[rngc].ot_parent_space;
- regp[regc].phys_addr += rangep[rngc].ot_parent_base;
- }
-}
-
-inline void
-prom_adjust_ranges(struct linux_prom_ranges *ranges1, int nranges1,
- struct linux_prom_ranges *ranges2, int nranges2)
-{
- int rng1c, rng2c;
-
- for(rng1c=0; rng1c < nranges1; rng1c++) {
- for(rng2c=0; rng2c < nranges2; rng2c++)
- if(ranges1[rng1c].ot_child_space ==
- ranges2[rng2c].ot_child_space) break;
- if(rng2c == nranges2) /* oops */
- prom_printf("adjust_ranges: Could not find matching bus type...\n");
- ranges1[rng1c].ot_parent_space = ranges2[rng2c].ot_parent_space;
- ranges1[rng1c].ot_parent_base += ranges2[rng2c].ot_parent_base;
- }
-}
-
-/* Apply probed sbus ranges to registers passed, if no ranges return. */
-void prom_apply_sbus_ranges(struct linux_sbus *sbus, struct linux_prom_registers *regs,
- int nregs, struct linux_sbus_device *sdev)
-{
- if(sbus->num_sbus_ranges) {
- if(sdev && (sdev->ranges_applied == 0)) {
- sdev->ranges_applied = 1;
- prom_adjust_regs(regs, nregs, sbus->sbus_ranges,
- sbus->num_sbus_ranges);
- }
- }
-}
-
-/* Apply probed fhc ranges to registers passed, if no ranges return. */
-void prom_apply_fhc_ranges(struct linux_fhc *fhc,
- struct linux_prom_registers *regs,
- int nregs)
-{
- if(fhc->num_fhc_ranges)
- prom_adjust_regs(regs, nregs, fhc->fhc_ranges,
- fhc->num_fhc_ranges);
-}
-
-/* Apply probed central ranges to registers passed, if no ranges return. */
-void prom_apply_central_ranges(struct linux_central *central,
- struct linux_prom_registers *regs, int nregs)
-{
- if(central->num_central_ranges)
- prom_adjust_regs(regs, nregs, central->central_ranges,
- central->num_central_ranges);
-}
-
-void __init prom_ranges_init(void)
-{
-}
-
-void __init prom_sbus_ranges_init(int iommund, struct linux_sbus *sbus)
-{
- int success;
-
- sbus->num_sbus_ranges = 0;
- success = prom_getproperty(sbus->prom_node, "ranges",
- (char *) sbus->sbus_ranges,
- sizeof (sbus->sbus_ranges));
- if (success != -1)
- sbus->num_sbus_ranges = (success/sizeof(struct linux_prom_ranges));
-}
-
-void __init prom_central_ranges_init(int cnode, struct linux_central *central)
-{
- int success;
-
- central->num_central_ranges = 0;
- success = prom_getproperty(central->prom_node, "ranges",
- (char *) central->central_ranges,
- sizeof (central->central_ranges));
- if (success != -1)
- central->num_central_ranges = (success/sizeof(struct linux_prom_ranges));
-}
-
-void __init prom_fhc_ranges_init(int fnode, struct linux_fhc *fhc)
-{
- int success;
-
- fhc->num_fhc_ranges = 0;
- success = prom_getproperty(fhc->prom_node, "ranges",
- (char *) fhc->fhc_ranges,
- sizeof (fhc->fhc_ranges));
- if (success != -1)
- fhc->num_fhc_ranges = (success/sizeof(struct linux_prom_ranges));
-}
-
-#ifdef CONFIG_PCI
-void __init prom_ebus_ranges_init(struct linux_ebus *ebus)
-{
- int success;
-
- ebus->num_ebus_ranges = 0;
- success = prom_getproperty(ebus->prom_node, "ranges",
- (char *)ebus->ebus_ranges,
- sizeof(ebus->ebus_ranges));
- if (success != -1)
- ebus->num_ebus_ranges = (success/sizeof(struct linux_prom_ebus_ranges));
-}
-
-void __init prom_ebus_intmap_init(struct linux_ebus *ebus)
-{
- int success;
-
- ebus->num_ebus_intmap = 0;
- success = prom_getproperty(ebus->prom_node, "interrupt-map",
- (char *)ebus->ebus_intmap,
- sizeof(ebus->ebus_intmap));
- if (success == -1)
- return;
-
- ebus->num_ebus_intmap = (success/sizeof(struct linux_prom_ebus_intmap));
-
- success = prom_getproperty(ebus->prom_node, "interrupt-map-mask",
- (char *)&ebus->ebus_intmask,
- sizeof(ebus->ebus_intmask));
- if (success == -1) {
- prom_printf("%s: can't get interrupt-map-mask\n", __FUNCTION__);
- prom_halt();
- }
-}
-#endif
-
-void
-prom_apply_generic_ranges (int node, int parent, struct linux_prom_registers *regs, int nregs)
-{
- int success;
- int num_ranges;
- struct linux_prom_ranges ranges[PROMREG_MAX];
-
- success = prom_getproperty(node, "ranges",
- (char *) ranges,
- sizeof (ranges));
- if (success != -1) {
- num_ranges = (success/sizeof(struct linux_prom_ranges));
- if (parent) {
- struct linux_prom_ranges parent_ranges[PROMREG_MAX];
- int num_parent_ranges;
-
- success = prom_getproperty(parent, "ranges",
- (char *) parent_ranges,
- sizeof (parent_ranges));
- if (success != -1) {
- num_parent_ranges = (success/sizeof(struct linux_prom_ranges));
- prom_adjust_ranges (ranges, num_ranges, parent_ranges, num_parent_ranges);
- }
- }
- prom_adjust_regs(regs, nregs, ranges, num_ranges);
- }
-}
diff --git a/arch/sparc64/solaris/fs.c b/arch/sparc64/solaris/fs.c
index bf06fc05d..86b0df283 100644
--- a/arch/sparc64/solaris/fs.c
+++ b/arch/sparc64/solaris/fs.c
@@ -1,7 +1,10 @@
-/* $Id: fs.c,v 1.13 1999/05/14 07:24:37 davem Exp $
+/* $Id: fs.c,v 1.15 2000/01/04 23:54:47 davem Exp $
* fs.c: fs related syscall emulation for Solaris
*
* Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ *
+ * 1999-08-19 Implemented solaris F_FREESP (truncate)
+ * fcntl, by Jason Rappleye (rappleye@ccr.buffalo.edu)
*/
#include <linux/types.h>
@@ -572,20 +575,24 @@ out:
return error;
}
-asmlinkage int solaris_open(u32 filename, int flags, u32 mode)
+extern asmlinkage long sparc32_open(const char * filename, int flags, int mode);
+
+asmlinkage int solaris_open(u32 fname, int flags, u32 mode)
{
- int (*sys_open)(const char *,int,int) =
- (int (*)(const char *,int,int))SYS(open);
+ const char *filename = (const char *)(long)fname;
int fl = flags & 0xf;
-/* if (flags & 0x2000) - allow LFS */
+ /* Translate flags first. */
+ if (flags & 0x2000) fl |= O_LARGEFILE;
if (flags & 0x8050) fl |= O_SYNC;
if (flags & 0x80) fl |= O_NONBLOCK;
if (flags & 0x100) fl |= O_CREAT;
if (flags & 0x200) fl |= O_TRUNC;
if (flags & 0x400) fl |= O_EXCL;
if (flags & 0x800) fl |= O_NOCTTY;
- return sys_open((const char *)A(filename), fl, mode);
+ flags = fl;
+
+ return sparc32_open(filename, flags, mode);
}
#define SOL_F_SETLK 6
@@ -661,7 +668,16 @@ asmlinkage int solaris_fcntl(unsigned fd, unsigned cmd, u32 arg)
__put_user_ret (0, &((struct sol_flock *)A(arg))->l_sysid, -EFAULT);
return ret;
}
- }
+ case SOL_F_FREESP:
+ {
+ int length;
+ int (*sys_newftruncate)(unsigned int, unsigned long)=
+ (int (*)(unsigned int, unsigned long))SYS(ftruncate);
+
+ get_user_ret(length, &((struct sol_flock*)A(arg))->l_start, -EFAULT);
+ return sys_newftruncate(fd, length);
+ }
+ };
return -EINVAL;
}
diff --git a/arch/sparc64/solaris/ioctl.c b/arch/sparc64/solaris/ioctl.c
index ac3071b50..18d73e686 100644
--- a/arch/sparc64/solaris/ioctl.c
+++ b/arch/sparc64/solaris/ioctl.c
@@ -1,4 +1,4 @@
-/* $Id: ioctl.c,v 1.13 1999/08/20 00:27:15 davem Exp $
+/* $Id: ioctl.c,v 1.14 1999/09/22 09:28:50 davem Exp $
* ioctl.c: Solaris ioctl emulation.
*
* Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -7,6 +7,9 @@
* Streams & timod emulation based on code
* Copyright (C) 1995, 1996 Mike Jagdis (jaggy@purplet.demon.co.uk)
*
+ * 1999-08-19 Implemented solaris 'm' (mag tape) and
+ * 'O' (openprom) ioctls, by Jason Rappleye
+ * (rappleye@ccr.buffalo.edu)
*/
#include <linux/types.h>
@@ -18,9 +21,12 @@
#include <linux/fs.h>
#include <linux/file.h>
#include <linux/netdevice.h>
+#include <linux/mtio.h>
+#include <linux/time.h>
#include <asm/uaccess.h>
#include <asm/termios.h>
+#include <asm/openpromio.h>
#include "conv.h"
#include "socksys.h"
@@ -678,6 +684,90 @@ static inline int solaris_i(unsigned int fd, unsigned int cmd, u32 arg)
return -ENOSYS;
}
+static int solaris_m(unsigned int fd, unsigned int cmd, u32 arg)
+{
+ int ret;
+
+ switch (cmd & 0xff) {
+ case 1: /* MTIOCTOP */
+ ret = sys_ioctl(fd, MTIOCTOP, (unsigned long)&arg);
+ break;
+ case 2: /* MTIOCGET */
+ ret = sys_ioctl(fd, MTIOCGET, (unsigned long)&arg);
+ break;
+ case 3: /* MTIOCGETDRIVETYPE */
+ case 4: /* MTIOCPERSISTENT */
+ case 5: /* MTIOCPERSISTENTSTATUS */
+ case 6: /* MTIOCLRERR */
+ case 7: /* MTIOCGUARANTEEDORDER */
+ case 8: /* MTIOCRESERVE */
+ case 9: /* MTIOCRELEASE */
+ case 10: /* MTIOCFORCERESERVE */
+ case 13: /* MTIOCSTATE */
+ case 14: /* MTIOCREADIGNOREILI */
+ case 15: /* MTIOCREADIGNOREEOFS */
+ case 16: /* MTIOCSHORTFMK */
+ default:
+ ret = -ENOSYS; /* linux doesn't support these */
+ break;
+ };
+
+ return ret;
+}
+
+static int solaris_O(unsigned int fd, unsigned int cmd, u32 arg)
+{
+ int ret = -EINVAL;
+
+ switch (cmd & 0xff) {
+ case 1: /* OPROMGETOPT */
+ ret = sys_ioctl(fd, OPROMGETOPT, arg);
+ break;
+ case 2: /* OPROMSETOPT */
+ ret = sys_ioctl(fd, OPROMSETOPT, arg);
+ break;
+ case 3: /* OPROMNXTOPT */
+ ret = sys_ioctl(fd, OPROMNXTOPT, arg);
+ break;
+ case 4: /* OPROMSETOPT2 */
+ ret = sys_ioctl(fd, OPROMSETOPT2, arg);
+ break;
+ case 5: /* OPROMNEXT */
+ ret = sys_ioctl(fd, OPROMNEXT, arg);
+ break;
+ case 6: /* OPROMCHILD */
+ ret = sys_ioctl(fd, OPROMCHILD, arg);
+ break;
+ case 7: /* OPROMGETPROP */
+ ret = sys_ioctl(fd, OPROMGETPROP, arg);
+ break;
+ case 8: /* OPROMNXTPROP */
+ ret = sys_ioctl(fd, OPROMNXTPROP, arg);
+ break;
+ case 9: /* OPROMU2P */
+ ret = sys_ioctl(fd, OPROMU2P, arg);
+ break;
+ case 10: /* OPROMGETCONS */
+ ret = sys_ioctl(fd, OPROMGETCONS, arg);
+ break;
+ case 11: /* OPROMGETFBNAME */
+ ret = sys_ioctl(fd, OPROMGETFBNAME, arg);
+ break;
+ case 12: /* OPROMGETBOOTARGS */
+ ret = sys_ioctl(fd, OPROMGETBOOTARGS, arg);
+ break;
+ case 13: /* OPROMGETVERSION */
+ case 14: /* OPROMPATH2DRV */
+ case 15: /* OPROMDEV2PROMNAME */
+ case 16: /* OPROMPROM2DEVNAME */
+ case 17: /* OPROMGETPROPLEN */
+ default:
+ ret = -EINVAL;
+ break;
+ };
+ return ret;
+}
+
/* }}} */
asmlinkage int solaris_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
@@ -699,6 +789,8 @@ asmlinkage int solaris_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
case 's': error = solaris_s(fd, cmd, arg); break;
case 't': error = solaris_t(fd, cmd, arg); break;
case 'f': error = sys_ioctl(fd, cmd, arg); break;
+ case 'm': error = solaris_m(fd, cmd, arg); break;
+ case 'O': error = solaris_O(fd, cmd, arg); break;
default:
error = -ENOSYS;
break;
diff --git a/arch/sparc64/solaris/ipc.c b/arch/sparc64/solaris/ipc.c
index 0c2116e73..3d312b5e1 100644
--- a/arch/sparc64/solaris/ipc.c
+++ b/arch/sparc64/solaris/ipc.c
@@ -1,4 +1,4 @@
-/* $Id: ipc.c,v 1.4 1999/05/13 07:11:37 jj Exp $
+/* $Id: ipc.c,v 1.5 1999/12/09 00:41:00 davem Exp $
* ipc.c: Solaris IPC emulation
*
* Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -8,6 +8,7 @@
#include <linux/types.h>
#include <linux/smp_lock.h>
#include <linux/wait.h>
+#include <linux/mm.h>
#include <linux/shm.h>
#include <linux/sem.h>
#include <linux/msg.h>
diff --git a/arch/sparc64/solaris/misc.c b/arch/sparc64/solaris/misc.c
index c3176ac2c..a07fc7cc2 100644
--- a/arch/sparc64/solaris/misc.c
+++ b/arch/sparc64/solaris/misc.c
@@ -1,4 +1,4 @@
-/* $Id: misc.c,v 1.14 1999/06/25 11:00:53 davem Exp $
+/* $Id: misc.c,v 1.19 1999/12/15 17:51:25 jj Exp $
* misc.c: Miscelaneous syscall emulation for Solaris
*
* Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -476,8 +476,8 @@ asmlinkage int solaris_gettimeofday(u32 tim)
#define RLIMIT_SOL_VMEM 6
struct rlimit32 {
- s32 rlim_cur;
- s32 rlim_max;
+ u32 rlim_cur;
+ u32 rlim_max;
};
asmlinkage int solaris_getrlimit(unsigned int resource, struct rlimit32 *rlim)
@@ -747,11 +747,7 @@ struct exec_domain solaris_exec_domain = {
1, 1, /* PER_SVR4 personality */
solaris_to_linux_signals,
linux_to_solaris_signals,
-#ifdef MODULE
- &__this_module,
-#else
- NULL,
-#endif
+ THIS_MODULE,
NULL
};
diff --git a/arch/sparc64/solaris/socket.c b/arch/sparc64/solaris/socket.c
index 4b3f18fc1..b9db00918 100644
--- a/arch/sparc64/solaris/socket.c
+++ b/arch/sparc64/solaris/socket.c
@@ -1,7 +1,10 @@
-/* $Id: socket.c,v 1.1 1998/10/28 08:12:11 jj Exp $
+/* $Id: socket.c,v 1.2 1999/09/22 09:28:50 davem Exp $
* socket.c: Socket syscall emulation for Solaris 2.6+
*
* Copyright (C) 1998 Jakub Jelinek (jj@ultra.linux.cz)
+ *
+ * 1999-08-19 Fixed socketpair code
+ * Jason Rappleye (rappleye@ccr.buffalo.edu)
*/
#include <linux/types.h>
@@ -25,6 +28,18 @@
#define SOCK_SOL_RDM 5
#define SOCK_SOL_SEQPACKET 6
+#define SOL_SO_SNDLOWAT 0x1003
+#define SOL_SO_RCVLOWAT 0x1004
+#define SOL_SO_SNDTIMEO 0x1005
+#define SOL_SO_RCVTIMEO 0x1006
+#define SOL_SO_STATE 0x2000
+
+#define SOL_SS_NDELAY 0x040
+#define SOL_SS_NONBLOCK 0x080
+#define SOL_SS_ASYNC 0x100
+
+#define SO_STATE 0x000e
+
static int socket_check(int family, int type)
{
if (family != PF_UNIX && family != PF_INET)
@@ -40,6 +55,19 @@ static int socket_check(int family, int type)
return type;
}
+static int solaris_to_linux_sockopt(int optname)
+{
+ switch (optname) {
+ case SOL_SO_SNDLOWAT: optname = SO_SNDLOWAT; break;
+ case SOL_SO_RCVLOWAT: optname = SO_RCVLOWAT; break;
+ case SOL_SO_SNDTIMEO: optname = SO_SNDTIMEO; break;
+ case SOL_SO_RCVTIMEO: optname = SO_RCVTIMEO; break;
+ case SOL_SO_STATE: optname = SO_STATE; break;
+ };
+
+ return optname;
+}
+
asmlinkage int solaris_socket(int family, int type, int protocol)
{
int (*sys_socket)(int, int, int) =
@@ -50,14 +78,19 @@ asmlinkage int solaris_socket(int family, int type, int protocol)
return sys_socket(family, type, protocol);
}
-asmlinkage int solaris_socketpair(int family, int type, int protocol, int *usockvec)
+asmlinkage int solaris_socketpair(int *usockvec)
{
int (*sys_socketpair)(int, int, int, int *) =
(int (*)(int, int, int, int *))SYS(socketpair);
- type = socket_check (family, type);
- if (type < 0) return type;
- return sys_socketpair(family, type, protocol, usockvec);
+ /* solaris socketpair really only takes one arg at the syscall
+ * level, int * usockvec. The libs apparently take care of
+ * making sure that family==AF_UNIX and type==SOCK_STREAM. The
+ * pointer we really want ends up residing in the first (and
+ * supposedly only) argument.
+ */
+
+ return sys_socketpair(AF_UNIX, SOCK_STREAM, 0, (int *)usockvec);
}
asmlinkage int solaris_bind(int fd, struct sockaddr *addr, int addrlen)
@@ -73,6 +106,12 @@ asmlinkage int solaris_setsockopt(int fd, int level, int optname, u32 optval, in
int (*sunos_setsockopt)(int, int, int, u32, int) =
(int (*)(int, int, int, u32, int))SUNOS(105);
+ optname = solaris_to_linux_sockopt(optname);
+ if (optname < 0)
+ return optname;
+ if (optname == SO_STATE)
+ return 0;
+
return sunos_setsockopt(fd, level, optname, optval, optlen);
}
@@ -81,6 +120,13 @@ asmlinkage int solaris_getsockopt(int fd, int level, int optname, u32 optval, u3
int (*sunos_getsockopt)(int, int, int, u32, u32) =
(int (*)(int, int, int, u32, u32))SUNOS(118);
+ optname = solaris_to_linux_sockopt(optname);
+ if (optname < 0)
+ return optname;
+
+ if (optname == SO_STATE)
+ optname = SOL_SO_STATE;
+
return sunos_getsockopt(fd, level, optname, optval, optlen);
}
diff --git a/arch/sparc64/solaris/timod.c b/arch/sparc64/solaris/timod.c
index 050c6e0b3..062e00218 100644
--- a/arch/sparc64/solaris/timod.c
+++ b/arch/sparc64/solaris/timod.c
@@ -1,4 +1,4 @@
-/* $Id: timod.c,v 1.4 1999/09/01 08:07:47 davem Exp $
+/* $Id: timod.c,v 1.5 1999/11/23 08:55:24 davem Exp $
* timod.c: timod emulation.
*
* Copyright (C) 1998 Patrik Rak (prak3264@ss1000.ms.mff.cuni.cz)