summaryrefslogtreecommitdiffstats
path: root/arch/m68k
diff options
context:
space:
mode:
Diffstat (limited to 'arch/m68k')
-rw-r--r--arch/m68k/Makefile12
-rw-r--r--arch/m68k/amiga/amiints.c4
-rw-r--r--arch/m68k/amiga/config.c2
-rw-r--r--arch/m68k/amiga/pcmcia.c3
-rw-r--r--arch/m68k/apollo/dn_ints.c2
-rw-r--r--arch/m68k/atari/atakeyb.c7
-rw-r--r--arch/m68k/atari/config.c2
-rw-r--r--arch/m68k/bvme6000/bvmeints.c9
-rw-r--r--arch/m68k/bvme6000/config.c9
-rw-r--r--arch/m68k/config.in42
-rw-r--r--arch/m68k/defconfig34
-rw-r--r--arch/m68k/fpsp040/skeleton.S7
-rw-r--r--arch/m68k/hp300/config.c6
-rw-r--r--arch/m68k/ifpsp060/iskeleton.S7
-rw-r--r--arch/m68k/kernel/Makefile9
-rw-r--r--arch/m68k/kernel/entry.S101
-rw-r--r--arch/m68k/kernel/head.S3855
-rw-r--r--arch/m68k/kernel/m68k_defs.c72
-rw-r--r--arch/m68k/kernel/m68k_defs.h6
-rw-r--r--arch/m68k/kernel/m68k_ksyms.c7
-rw-r--r--arch/m68k/kernel/process.c69
-rw-r--r--arch/m68k/kernel/ptrace.c13
-rw-r--r--arch/m68k/kernel/setup.c8
-rw-r--r--arch/m68k/kernel/signal.c4
-rw-r--r--arch/m68k/kernel/sys_m68k.c85
-rw-r--r--arch/m68k/kernel/time.c51
-rw-r--r--arch/m68k/mac/config.c49
-rw-r--r--arch/m68k/mac/debug.c156
-rw-r--r--arch/m68k/mac/macboing.c357
-rw-r--r--arch/m68k/mac/macints.c203
-rw-r--r--arch/m68k/mac/mackeyb.c75
-rw-r--r--arch/m68k/mac/via6522.c23
-rw-r--r--arch/m68k/mm/fault.c47
-rw-r--r--arch/m68k/mm/init.c287
-rw-r--r--arch/m68k/mm/kmap.c696
-rw-r--r--arch/m68k/mm/memory.c136
-rw-r--r--arch/m68k/mvme16x/16xints.c9
-rw-r--r--arch/m68k/vmlinux.lds3
38 files changed, 4316 insertions, 2151 deletions
diff --git a/arch/m68k/Makefile b/arch/m68k/Makefile
index 9cd2d1838..cb60ea268 100644
--- a/arch/m68k/Makefile
+++ b/arch/m68k/Makefile
@@ -29,14 +29,21 @@ LINKFLAGS = -T $(TOPDIR)/arch/m68k/vmlinux.lds
# without -fno-strength-reduce the 53c7xx.c driver fails ;-(
CFLAGS += -pipe -fno-strength-reduce -ffixed-a2
-ifdef CONFIG_OPTIMIZE_040
+# enable processor switch if compiled only for a single cpu
+ifndef CONFIG_M68020
+ifndef CONFIG_M68030
+
+ifndef CONFIG_M68060
CFLAGS := $(CFLAGS) -m68040
endif
-ifdef CONFIG_OPTIMIZE_060
+ifndef CONFIG_M68040
CFLAGS := $(CFLAGS) -m68060
endif
+endif
+endif
+
ifdef CONFIG_KGDB
# If configured for kgdb support, include debugging infos and keep the
# frame pointer
@@ -116,6 +123,7 @@ endif
archclean:
rm -f vmlinux.gz
+ rm -f arch/m68k/kernel/m68k_defs.h arch/m68k/kernel/m68k_defs.d
archmrproper:
diff --git a/arch/m68k/amiga/amiints.c b/arch/m68k/amiga/amiints.c
index 25955213e..4fb886456 100644
--- a/arch/m68k/amiga/amiints.c
+++ b/arch/m68k/amiga/amiints.c
@@ -15,7 +15,7 @@
* - IRQ_FLG_SLOW: handler is inserted at bottom of list and before
* they're executed irq level is set to the previous
* one, but handlers don't need to be reentrant, if
- * reentrance occured, slow handlers will be just
+ * reentrance occurred, slow handlers will be just
* called again.
* The whole interrupt handling for CIAs is moved to cia.c
* /Roman Zippel
@@ -367,7 +367,7 @@ void amiga_do_irq_list(int irq, struct pt_regs *fp, struct irq_server *server)
for (;;) {
for (; node; node = node->next)
node->handler(irq, node->dev_id, fp);
- /* if reentrance occured, serve slow handlers again */
+ /* if reentrance occurred, serve slow handlers again */
custom.intena = ami_intena_vals[irq];
if (!server->reentrance) {
server->count--;
diff --git a/arch/m68k/amiga/config.c b/arch/m68k/amiga/config.c
index 63cb5265c..37b5bde3c 100644
--- a/arch/m68k/amiga/config.c
+++ b/arch/m68k/amiga/config.c
@@ -52,7 +52,6 @@ static void amiga_sched_init(void (*handler)(int, void *, struct pt_regs *));
/* amiga specific keyboard functions */
extern int amiga_keyb_init(void);
extern int amiga_kbdrate (struct kbd_repeat *);
-extern void amiga_kbd_reset_setup(char*, int);
/* amiga specific irq functions */
extern void amiga_init_IRQ (void);
extern void (*amiga_default_handler[]) (int, void *, struct pt_regs *);
@@ -343,7 +342,6 @@ __initfunc(void config_amiga(void))
mach_sched_init = amiga_sched_init;
mach_keyb_init = amiga_keyb_init;
mach_kbdrate = amiga_kbdrate;
- kbd_reset_setup = amiga_kbd_reset_setup;
mach_init_IRQ = amiga_init_IRQ;
mach_default_handler = &amiga_default_handler;
mach_request_irq = amiga_request_irq;
diff --git a/arch/m68k/amiga/pcmcia.c b/arch/m68k/amiga/pcmcia.c
index 3faac7eda..e1b29387a 100644
--- a/arch/m68k/amiga/pcmcia.c
+++ b/arch/m68k/amiga/pcmcia.c
@@ -14,6 +14,7 @@
#include <linux/types.h>
#include <linux/sched.h>
+#include <linux/timer.h>
#include <asm/amigayle.h>
#include <asm/amipcmcia.h>
@@ -26,7 +27,7 @@ void pcmcia_reset(void)
unsigned char b;
gayle_reset = 0x00;
- while (jiffies - reset_start_time < 1*HZ/100);
+ while (time_before(jiffies, reset_start_time + 1*HZ/100));
b = gayle_reset;
}
diff --git a/arch/m68k/apollo/dn_ints.c b/arch/m68k/apollo/dn_ints.c
index c4cffcdf9..18e29814e 100644
--- a/arch/m68k/apollo/dn_ints.c
+++ b/arch/m68k/apollo/dn_ints.c
@@ -30,7 +30,7 @@ void dn_process_int(int irq, struct pt_regs *fp) {
dn_irqs[irq-160].handler(irq,dn_irqs[irq-160].dev_id,fp);
}
else {
- printk("spurious irq %d occured\n",irq);
+ printk("spurious irq %d occurred\n",irq);
}
#if 0
diff --git a/arch/m68k/atari/atakeyb.c b/arch/m68k/atari/atakeyb.c
index e6535f6ff..79ef5f9fd 100644
--- a/arch/m68k/atari/atakeyb.c
+++ b/arch/m68k/atari/atakeyb.c
@@ -825,7 +825,7 @@ __initfunc(int atari_keyb_init(void))
/* wait for a period of inactivity (here: 0.25s), then assume the IKBD's
* self-test is finished */
self_test_last_rcv = jiffies;
- while( jiffies < self_test_last_rcv + HZ/4 )
+ while (time_before(jiffies, self_test_last_rcv + HZ/4))
barrier();
/* if not incremented: no 0xf1 received */
if (ikbd_self_test == 1)
@@ -861,8 +861,3 @@ int atari_kbdrate( struct kbd_repeat *k )
return( 0 );
}
-
-/* for "kbd-reset" cmdline param */
-__initfunc(void atari_kbd_reset_setup(char *str, int *ints))
-{
-}
diff --git a/arch/m68k/atari/config.c b/arch/m68k/atari/config.c
index 8db027ab4..5be79acaf 100644
--- a/arch/m68k/atari/config.c
+++ b/arch/m68k/atari/config.c
@@ -60,7 +60,6 @@ static int atari_get_hardware_list(char *buffer);
extern int atari_keyb_init(void);
extern int atari_kbdrate (struct kbd_repeat *);
extern void atari_kbd_leds (unsigned int);
-extern void atari_kbd_reset_setup(char*, int);
/* atari specific irq functions */
extern void atari_init_IRQ (void);
extern int atari_request_irq (unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
@@ -251,7 +250,6 @@ __initfunc(void config_atari(void))
mach_keyb_init = atari_keyb_init;
mach_kbdrate = atari_kbdrate;
mach_kbd_leds = atari_kbd_leds;
- kbd_reset_setup = atari_kbd_reset_setup;
mach_init_IRQ = atari_init_IRQ;
mach_request_irq = atari_request_irq;
mach_free_irq = atari_free_irq;
diff --git a/arch/m68k/bvme6000/bvmeints.c b/arch/m68k/bvme6000/bvmeints.c
index a79f5555d..04633375f 100644
--- a/arch/m68k/bvme6000/bvmeints.c
+++ b/arch/m68k/bvme6000/bvmeints.c
@@ -119,9 +119,12 @@ void bvme6000_free_irq(unsigned int irq, void *dev_id)
void bvme6000_process_int (unsigned long vec, struct pt_regs *fp)
{
if (vec > 255)
- panic ("bvme6000_process_int: Illegal vector %ld", vec);
- irq_tab[vec].count++;
- irq_tab[vec].handler(vec, irq_tab[vec].dev_id, fp);
+ printk ("bvme6000_process_int: Illegal vector %ld", vec);
+ else
+ {
+ irq_tab[vec].count++;
+ irq_tab[vec].handler(vec, irq_tab[vec].dev_id, fp);
+ }
}
int bvme6000_get_irq_list (char *buf)
diff --git a/arch/m68k/bvme6000/config.c b/arch/m68k/bvme6000/config.c
index 74d15e995..543b04c74 100644
--- a/arch/m68k/bvme6000/config.c
+++ b/arch/m68k/bvme6000/config.c
@@ -91,8 +91,7 @@ void bvme6000_reset()
static void bvme6000_get_model(char *model)
{
- /* XXX Need to detect if BVME4000 or BVME6000 */
- sprintf(model, "BVME6000");
+ sprintf(model, "BVME%d000", m68k_cputype == CPU_68060 ? 6 : 4);
}
@@ -152,13 +151,17 @@ __initfunc(void config_bvme6000(void))
pit->pbddr = 0xf3; /* Mostly outputs */
pit->pcdr = 0x01; /* PA transceiver disabled */
pit->pcddr = 0x03; /* WDOG disable */
+
+ /* Disable snooping for Ethernet and VME accesses */
+
+ bvme_acr_addrctl = 0;
}
void bvme6000_abort_int (int irq, void *dev_id, struct pt_regs *fp)
{
unsigned long *new = (unsigned long *)vectors;
- unsigned long *old = (unsigned long *)0xf8000000;;
+ unsigned long *old = (unsigned long *)0xf8000000;
/* Wait for button release */
while (*config_reg_ptr & BVME_ABORT_STATUS)
diff --git a/arch/m68k/config.in b/arch/m68k/config.in
index 8fe84aecd..a67227d60 100644
--- a/arch/m68k/config.in
+++ b/arch/m68k/config.in
@@ -44,6 +44,7 @@ bool 'HP9000/300 support' CONFIG_HP300
if [ "$CONFIG_HP300" = "y" ]; then
bool 'DIO bus support' CONFIG_DIO
fi
+define_bool CONFIG_SUN3 n
if [ "$CONFIG_PCI" = "y" ]; then
bool 'Backward-compatible /proc/pci' CONFIG_PCI_OLD_PROC
fi
@@ -53,22 +54,11 @@ bool '68020 support' CONFIG_M68020
bool '68030 support' CONFIG_M68030
bool '68040 support' CONFIG_M68040
bool '68060 support' CONFIG_M68060
-if [ "$CONFIG_M68020" = "n" -a "$CONFIG_M68030" = "n" ]; then
- if [ "$CONFIG_M68040" = "y" -a "$CONFIG_M68060" = "n" ]; then
- bool 'Use 68040 specific optimizations' CONFIG_OPTIMIZE_040
- fi
- if [ "$CONFIG_M68040" = "n" -a "$CONFIG_M68060" = "y" ]; then
- bool 'Use 68060 specific optimizations' CONFIG_OPTIMIZE_060
- fi
-fi
-if [ "$CONFIG_VME" = "y" -a "$CONFIG_M68060" = "y" ]; then
- define_bool CONFIG_060_WRITETHROUGH y
-fi
bool 'Advanced configuration options' CONFIG_ADVANCED
if [ "$CONFIG_ADVANCED" = "y" ]; then
bool 'Use read-modify-write instructions' CONFIG_RMW_INSNS
bool 'Use one physical chunk of memory only' CONFIG_SINGLE_MEMORY_CHUNK
- if [ "$CONFIG_M68060" = "y" -a "$CONFIG_VME" = "n" ]; then
+ if [ "$CONFIG_M68060" = "y" ]; then
bool 'Use write-through caching for 68060 supervisor accesses' CONFIG_060_WRITETHROUGH
fi
fi
@@ -140,19 +130,19 @@ mainmenu_option next_comment
comment 'SCSI low-level drivers'
if [ "$CONFIG_AMIGA" = "y" ]; then
- tristate 'A3000 WD33C93A support' CONFIG_A3000_SCSI
+ dep_tristate 'A3000 WD33C93A support' CONFIG_A3000_SCSI $CONFIG_SCSI
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
bool 'A4000T SCSI support' CONFIG_A4000T_SCSI
fi
fi
if [ "$CONFIG_ZORRO" = "y" ]; then
- tristate 'A2091 WD33C93A support' CONFIG_A2091_SCSI
- tristate 'GVP Series II WD33C93A support' CONFIG_GVP11_SCSI
- bool 'CyberStorm SCSI support' CONFIG_CYBERSTORM_SCSI
- bool 'CyberStorm Mk II SCSI support' CONFIG_CYBERSTORMII_SCSI
- bool 'Blizzard 2060 SCSI support' CONFIG_BLZ2060_SCSI
- bool 'Blizzard 1230IV/1260 SCSI support' CONFIG_BLZ1230_SCSI
- bool 'Fastlane SCSI support' CONFIG_FASTLANE_SCSI
+ dep_tristate 'A2091 WD33C93A support' CONFIG_A2091_SCSI $CONFIG_SCSI
+ dep_tristate 'GVP Series II WD33C93A support' CONFIG_GVP11_SCSI $CONFIG_SCSI
+ dep_tristate 'CyberStorm SCSI support' CONFIG_CYBERSTORM_SCSI $CONFIG_SCSI
+ dep_tristate 'CyberStorm Mk II SCSI support' CONFIG_CYBERSTORMII_SCSI $CONFIG_SCSI
+ dep_tristate 'Blizzard 2060 SCSI support' CONFIG_BLZ2060_SCSI $CONFIG_SCSI
+ dep_tristate 'Blizzard 1230IV/1260 SCSI support' CONFIG_BLZ1230_SCSI $CONFIG_SCSI
+ dep_tristate 'Fastlane SCSI support' CONFIG_FASTLANE_SCSI $CONFIG_SCSI
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
bool 'A4091 SCSI support' CONFIG_A4091_SCSI
bool 'WarpEngine SCSI support' CONFIG_WARPENGINE_SCSI
@@ -173,7 +163,7 @@ if [ "$CONFIG_ATARI" = "y" ]; then
fi
if [ "$CONFIG_MAC" = "y" ]; then
bool 'MAC NCR5380 SCSI' CONFIG_MAC_SCSI
- bool 'MAC NCR53c9[46] SCSI' CONFIG_SCSI_MAC_ESP
+ dep_tristate 'MAC NCR53c9[46] SCSI' CONFIG_SCSI_MAC_ESP $CONFIG_SCSI
fi
#dep_tristate 'SCSI debugging host adapter' CONFIG_SCSI_DEBUG $CONFIG_SCSI
@@ -226,14 +216,14 @@ if [ "$CONFIG_APOLLO" = "y" ] ; then
fi
if [ "$CONFIG_MAC" = "y" ]; then
bool 'Mac NS 8390 based ethernet cards' CONFIG_DAYNAPORT
- bool 'AV Macintosh onboard MACE ethernet' CONFIG_MACMACE
- bool 'Macintosh onboard SONIC ethernet' CONFIG_MACSONIC
+# bool 'Macintosh (AV) onboard MACE ethernet' CONFIG_MACMACE
+ bool 'Macintosh (Quadra) onboard SONIC ethernet' CONFIG_MACSONIC
fi
if [ "$CONFIG_VME" = "y" -a "$CONFIG_MVME16x" = "y" ]; then
- bool 'MVME16x Ethernet support' CONFIG_MVME16x_NET
+ tristate 'MVME16x Ethernet support' CONFIG_MVME16x_NET
fi
if [ "$CONFIG_VME" = "y" -a "$CONFIG_BVME6000" = "y" ]; then
- bool 'BVME6000 Ethernet support' CONFIG_BVME6000_NET
+ tristate 'BVME6000 Ethernet support' CONFIG_BVME6000_NET
fi
if [ "$CONFIG_ATARI" = "y" ]; then
tristate 'Atari Lance support' CONFIG_ATARILANCE
@@ -367,8 +357,6 @@ if [ "$CONFIG_VME" = "n" ]; then
endmenu
fi
-source fs/nls/Config.in
-
mainmenu_option next_comment
comment 'Kernel hacking'
diff --git a/arch/m68k/defconfig b/arch/m68k/defconfig
index 5a9f39e52..ab9152f5d 100644
--- a/arch/m68k/defconfig
+++ b/arch/m68k/defconfig
@@ -28,8 +28,6 @@ CONFIG_M68020=y
CONFIG_M68030=y
CONFIG_M68040=y
# CONFIG_M68060 is not set
-# CONFIG_OPTIMIZE_040 is not set
-# CONFIG_OPTIMIZE_060 is not set
# CONFIG_ADVANCED is not set
# CONFIG_SINGLE_MEMORY_CHUNK is not set
# CONFIG_RMW_INSNS is not set
@@ -77,21 +75,26 @@ CONFIG_BLK_DEV_INITRD=y
#
# Networking options
#
+CONFIG_PACKET=y
# CONFIG_NETLINK is not set
# CONFIG_FIREWALL is not set
# CONFIG_NET_ALIAS is not set
+# CONFIG_FILTER is not set
+CONFIG_UNIX=y
CONFIG_INET=y
# CONFIG_IP_MULTICAST is not set
-# CONFIG_IP_ACCT is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+# CONFIG_IP_PNP is not set
# CONFIG_IP_ROUTER is not set
# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_ALIAS is not set
+# CONFIG_SYN_COOKIES is not set
#
# (it is safe to leave these untouched)
#
-# CONFIG_INET_PCTCP is not set
# CONFIG_INET_RARP is not set
-CONFIG_PATH_MTU_DISCOVERY=y
CONFIG_IP_NOSR=y
# CONFIG_SKB_LARGE is not set
# CONFIG_IPV6 is not set
@@ -101,8 +104,20 @@ CONFIG_IP_NOSR=y
#
# CONFIG_IPX is not set
# CONFIG_ATALK is not set
-# CONFIG_AX25 is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
# CONFIG_BRIDGE is not set
+# CONFIG_LLC is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+# CONFIG_CPU_IS_SLOW is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
#
# SCSI support
@@ -115,12 +130,15 @@ CONFIG_SCSI=y
CONFIG_BLK_DEV_SD=y
CONFIG_CHR_DEV_ST=y
CONFIG_BLK_DEV_SR=y
+# CONFIG_BLK_DEV_SR_VENDOR is not set
# CONFIG_CHR_DEV_SG is not set
#
# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
#
# CONFIG_SCSI_MULTI_LUN is not set
+CONFIG_SCSI_CONSTANTS=y
+# CONFIG_SCSI_LOGGING is not set
#
# SCSI low-level drivers
@@ -149,6 +167,7 @@ CONFIG_NETDEVICES=y
# CONFIG_SLIP is not set
# CONFIG_PPP is not set
# CONFIG_ARIADNE is not set
+# CONFIG_ARIADNE2 is not set
# CONFIG_A2065 is not set
# CONFIG_HYDRA is not set
# CONFIG_APNE is not set
@@ -186,7 +205,10 @@ CONFIG_FB_AMIGA_OCS=y
CONFIG_FB_AMIGA_ECS=y
CONFIG_FB_AMIGA_AGA=y
# CONFIG_FB_CYBER is not set
+# CONFIG_FB_VIRGE is not set
+# CONFIG_FB_CVPPC is not set
# CONFIG_FB_RETINAZ3 is not set
+# CONFIG_FB_CLGEN is not set
# CONFIG_FB_ATARI is not set
# CONFIG_FB_VIRTUAL is not set
# CONFIG_FBCON_ADVANCED is not set
diff --git a/arch/m68k/fpsp040/skeleton.S b/arch/m68k/fpsp040/skeleton.S
index 1e4d0cf72..06d22b7b7 100644
--- a/arch/m68k/fpsp040/skeleton.S
+++ b/arch/m68k/fpsp040/skeleton.S
@@ -40,6 +40,7 @@
#include <linux/linkage.h>
#include <asm/entry.h>
+#include "../kernel/m68k_defs.h"
|SKELETON idnt 2,1 | Motorola 040 Floating Point Software Package
@@ -375,12 +376,12 @@ fpsp_fmt_error:
.global fpsp_done
fpsp_done:
btst #0x5,%sp@ | supervisor bit set in saved SR?
- beq Lnotkern
+ beq .Lnotkern
rte
-Lnotkern:
+.Lnotkern:
SAVE_ALL_INT
GET_CURRENT(%d0)
- tstl %curptr@(LTASK_NEEDRESCHED)
+ tstl %curptr@(TASK_NEEDRESCHED)
jne SYMBOL_NAME(ret_from_exception) | deliver signals,
| reschedule etc..
RESTORE_ALL
diff --git a/arch/m68k/hp300/config.c b/arch/m68k/hp300/config.c
index 97fb6e480..6808de799 100644
--- a/arch/m68k/hp300/config.c
+++ b/arch/m68k/hp300/config.c
@@ -55,11 +55,6 @@ static void hp300_kbd_leds(unsigned int leds)
{
}
-/* for "kbd-reset" cmdline param */
-__initfunc(void hp300_kbd_reset_setup(char *str, int i))
-{
-}
-
static void hp300_get_model(char *model)
{
strcpy(model, "HP9000/300");
@@ -74,7 +69,6 @@ __initfunc(void config_hp300(void))
mach_init_IRQ = hp300_init_IRQ;
mach_request_irq = hp300_request_irq;
mach_free_irq = hp300_free_irq;
- kbd_reset_setup = hp300_kbd_reset_setup;
mach_get_model = hp300_get_model;
mach_get_irq_list = hp300_get_irq_list;
mach_gettimeoffset = hp300_gettimeoffset;
diff --git a/arch/m68k/ifpsp060/iskeleton.S b/arch/m68k/ifpsp060/iskeleton.S
index cde14e120..859ba3dd3 100644
--- a/arch/m68k/ifpsp060/iskeleton.S
+++ b/arch/m68k/ifpsp060/iskeleton.S
@@ -36,6 +36,7 @@
#include <linux/linkage.h>
#include <asm/entry.h>
+#include "../kernel/m68k_defs.h"
|################################
@@ -69,12 +70,12 @@
.global _060_isp_done
_060_isp_done:
btst #0x5,%sp@ | supervisor bit set in saved SR?
- beq Lnotkern
+ beq .Lnotkern
rte
-Lnotkern:
+.Lnotkern:
SAVE_ALL_INT
GET_CURRENT(%d0)
- tstl %curptr@(LTASK_NEEDRESCHED)
+ tstl %curptr@(TASK_NEEDRESCHED)
jne SYMBOL_NAME(ret_from_exception) | deliver signals,
| reschedule etc..
RESTORE_ALL
diff --git a/arch/m68k/kernel/Makefile b/arch/m68k/kernel/Makefile
index 977120c1e..280a5b450 100644
--- a/arch/m68k/kernel/Makefile
+++ b/arch/m68k/kernel/Makefile
@@ -26,10 +26,13 @@ endif
head.o: head.S m68k_defs.h
-m68k_defs.h: m68k_defs.c m68k_defs.head $(TOPDIR)/include/linux/sched.h
- $(CC) ${CFLAGS} -S m68k_defs.c
+m68k_defs.h: m68k_defs.c m68k_defs.head
+ rm -f m68k_defs.d
+ SUNPRO_DEPENDENCIES="m68k_defs.d m68k_defs.h" \
+ $(CC) $(filter-out -MD,$(CFLAGS)) -S m68k_defs.c
cp m68k_defs.head m68k_defs.h
- sed -n < m68k_defs.s >> m68k_defs.h '/^#define/s/ #/ /p'
+ grep '^#define' m68k_defs.s >> m68k_defs.h
rm m68k_defs.s
+-include m68k_defs.d
include $(TOPDIR)/Rules.make
diff --git a/arch/m68k/kernel/entry.S b/arch/m68k/kernel/entry.S
index b3e15387c..e21e4b21c 100644
--- a/arch/m68k/kernel/entry.S
+++ b/arch/m68k/kernel/entry.S
@@ -34,8 +34,10 @@
#include <linux/config.h>
#include <linux/linkage.h>
#include <asm/entry.h>
+#include <asm/errno.h>
#include <asm/setup.h>
#include <asm/segment.h>
+#include <asm/traps.h>
#include "m68k_defs.h"
@@ -43,7 +45,7 @@
.globl SYMBOL_NAME(resume), SYMBOL_NAME(ret_from_exception)
.globl SYMBOL_NAME(ret_from_signal)
.globl SYMBOL_NAME(inthandler), SYMBOL_NAME(sys_call_table)
-.globl SYMBOL_NAME(sys_fork), SYMBOL_NAME(sys_clone)
+.globl SYMBOL_NAME(sys_fork), SYMBOL_NAME(sys_clone), SYMBOL_NAME(sys_vfork)
.globl SYMBOL_NAME(ret_from_interrupt), SYMBOL_NAME(bad_interrupt)
.text
@@ -65,24 +67,24 @@ ENTRY(trap)
ENTRY(reschedule)
| save top of frame
- movel %sp,%curptr@(TS_ESP0)
+ movel %sp,%curptr@(TASK_TSS+TSS_ESP0)
pea SYMBOL_NAME(ret_from_exception)
jmp SYMBOL_NAME(schedule)
badsys:
- movel #-LENOSYS,LPT_OFF_D0(%sp)
+ movel #-ENOSYS,PT_D0(%sp)
jra SYMBOL_NAME(ret_from_exception)
do_trace:
- movel #-LENOSYS,LPT_OFF_D0(%sp) | needed for strace
+ movel #-ENOSYS,PT_D0(%sp) | needed for strace
subql #4,%sp
SAVE_SWITCH_STACK
jbsr SYMBOL_NAME(syscall_trace)
RESTORE_SWITCH_STACK
addql #4,%sp
jbsr @(SYMBOL_NAME(sys_call_table),%d2:l:4)@(0)
- movel %d0,%sp@(LPT_OFF_D0) | save the return value
+ movel %d0,%sp@(PT_D0) | save the return value
subql #4,%sp | dummy return address
SAVE_SWITCH_STACK
jbsr SYMBOL_NAME(syscall_trace)
@@ -98,34 +100,34 @@ ENTRY(system_call)
GET_CURRENT(%d0)
| save top of frame
- movel %sp,%curptr@(TS_ESP0)
+ movel %sp,%curptr@(TASK_TSS+TSS_ESP0)
cmpl #NR_syscalls,%d2
jcc badsys
- btst #LPF_TRACESYS_BIT,%curptr@(LTASK_FLAGS+LPF_TRACESYS_OFF)
+ btst #PF_TRACESYS_BIT,%curptr@(TASK_FLAGS+PF_TRACESYS_OFF)
jne do_trace
jbsr @(SYMBOL_NAME(sys_call_table),%d2:l:4)@(0)
- movel %d0,%sp@(LPT_OFF_D0) | save the return value
+ movel %d0,%sp@(PT_D0) | save the return value
SYMBOL_NAME_LABEL(ret_from_exception)
- btst #5,%sp@(LPT_OFF_SR) | check if returning to kernel
+ btst #5,%sp@(PT_SR) | check if returning to kernel
bnes 2f | if so, skip resched, signals
| only allow interrupts when we are really the last one on the
| kernel stack, otherwise stack overflow can occur during
| heavy interupt load
andw #ALLOWINT,%sr
- tstl %curptr@(LTASK_NEEDRESCHED)
+ tstl %curptr@(TASK_NEEDRESCHED)
jne SYMBOL_NAME(reschedule)
cmpl #SYMBOL_NAME(task),%curptr | task[0] cannot have signals
jeq 2f
| check for delayed trace
- bclr #LPF_DTRACE_BIT,%curptr@(LTASK_FLAGS+LPF_DTRACE_OFF)
+ bclr #PF_DTRACE_BIT,%curptr@(TASK_FLAGS+PF_DTRACE_OFF)
jne do_delayed_trace
5:
- tstl %curptr@(LTASK_STATE) | state
+ tstl %curptr@(TASK_STATE) | state
jne SYMBOL_NAME(reschedule)
- tstl %curptr@(LTASK_SIGPENDING)
+ tstl %curptr@(TASK_SIGPENDING)
jne Lsignal_return
2: RESTORE_ALL
@@ -141,7 +143,7 @@ Lsignal_return:
RESTORE_ALL
do_delayed_trace:
- bclr #7,%sp@(LPT_OFF_SR) | clear trace bit in SR
+ bclr #7,%sp@(PT_SR) | clear trace bit in SR
pea 1 | send SIGTRAP
movel %curptr,%sp@-
pea LSIGTRAP
@@ -158,7 +160,7 @@ SYMBOL_NAME_LABEL(inthandler)
GET_CURRENT(%d0)
addql #1,SYMBOL_NAME(local_irq_count)
| put exception # in d0
- bfextu %sp@(LPT_OFF_FORMATVEC){#4,#10},%d0
+ bfextu %sp@(PT_VECTOR){#4,#10},%d0
movel %sp,%sp@-
movel %d0,%sp@- | put vector # on stack
@@ -172,7 +174,7 @@ SYMBOL_NAME_LABEL(ret_from_interrupt)
RESTORE_ALL
1:
#if 1
- bfextu %sp@(LPT_OFF_SR){#5,#3},%d0 | Check for nested interrupt.
+ bfextu %sp@(PT_SR){#5,#3},%d0 | Check for nested interrupt.
#if MAX_NOINT_IPL > 0
cmpiw #MAX_NOINT_IPL,%d0
#endif
@@ -210,6 +212,14 @@ ENTRY(sys_clone)
RESTORE_SWITCH_STACK
rts
+ENTRY(sys_vfork)
+ SAVE_SWITCH_STACK
+ pea %sp@(SWITCH_STACK_SIZE)
+ jbsr SYMBOL_NAME(m68k_vfork)
+ addql #4,%sp
+ RESTORE_SWITCH_STACK
+ rts
+
ENTRY(sys_sigsuspend)
SAVE_SWITCH_STACK
pea %sp@(SWITCH_STACK_SIZE)
@@ -240,37 +250,31 @@ ENTRY(sys_rt_sigreturn)
SYMBOL_NAME_LABEL(resume)
/*
- * Beware - when entering resume, offset of tss is in d1,
- * prev (the current task) is in a0, next (the new task)
- * is in a1 and d2.b is non-zero if the mm structure is
- * shared between the tasks, so don't change these
+ * Beware - when entering resume, prev (the current task) is
+ * in a0, next (the new task) is in a1,so don't change these
* registers until their contents are no longer needed.
*/
- /* offset of tss struct (processor state) from beginning
- of task struct */
- addl %d1,%a0
-
/* save sr */
- movew %sr,%a0@(LTSS_SR)
+ movew %sr,%a0@(TASK_TSS+TSS_SR)
/* save fs (sfc,%dfc) (may be pointing to kernel memory) */
movec %sfc,%d0
- movew %d0,%a0@(LTSS_FS)
+ movew %d0,%a0@(TASK_TSS+TSS_FS)
/* save usp */
/* it is better to use a movel here instead of a movew 8*) */
movec %usp,%d0
- movel %d0,%a0@(LTSS_USP)
+ movel %d0,%a0@(TASK_TSS+TSS_USP)
/* save non-scratch registers on stack */
SAVE_SWITCH_STACK
/* save current kernel stack pointer */
- movel %sp,%a0@(LTSS_KSP)
+ movel %sp,%a0@(TASK_TSS+TSS_KSP)
/* save floating point context */
- fsave %a0@(LTSS_FPCTXT+27*4)
+ fsave %a0@(TASK_TSS+TSS_FPSTATE)
#if defined(CONFIG_M68060)
#if !defined(CPU_M68060_ONLY)
@@ -278,27 +282,27 @@ SYMBOL_NAME_LABEL(resume)
beqs 1f
#endif
/* The 060 FPU keeps status in bits 15-8 of the first longword */
- tstb %a0@(LTSS_FPCTXT+27*4+2)
+ tstb %a0@(TASK_TSS+TSS_FPSTATE+2)
jeq 3f
#if !defined(CPU_M68060_ONLY)
jra 2f
#endif
#endif /* CONFIG_M68060 */
#if !defined(CPU_M68060_ONLY)
-1: tstb %a0@(LTSS_FPCTXT+27*4)
+1: tstb %a0@(TASK_TSS+TSS_FPSTATE)
jeq 3f
#endif
-2: fmovemx %fp0-%fp7,%a0@(LTSS_FPCTXT)
- fmoveml %fpcr/%fpsr/%fpiar,%a0@(LTSS_FPCTXT+24*4)
+2: fmovemx %fp0-%fp7,%a0@(TASK_TSS+TSS_FPREG)
+ fmoveml %fpcr/%fpsr/%fpiar,%a0@(TASK_TSS+TSS_FPCNTL)
3:
- /* get pointer to tss struct (a1 contains new task) */
+ /* switch to new task (a1 contains new task) */
movel %a1,%curptr
- addl %d1,%a1
/* Skip address space switching if they are the same. */
- tstb %d2
- jne 4f
+ movel %a0@(TASK_MM),%d0
+ cmpl %a1@(TASK_MM),%d0
+ jeq 4f
#if defined(CPU_M68020_OR_M68030) && defined(CPU_M68040_OR_M68060)
/* 68040 or 68060 ? */
@@ -316,7 +320,7 @@ SYMBOL_NAME_LABEL(resume)
movec %d0,%cacr
/* switch the root pointer */
- pmove %a1@(LTSS_CRP),%crp
+ pmove %a1@(TASK_TSS+TSS_CRP),%crp
#endif
#if defined(CPU_M68020_OR_M68030) && defined(CPU_M68040_OR_M68060)
@@ -333,7 +337,7 @@ SYMBOL_NAME_LABEL(resume)
pflushan
/* switch the root pointer */
- movel %a1@(LTSS_CRP+4),%d0
+ movel %a1@(TASK_TSS+TSS_CRP+4),%d0
movec %d0,%urp
#if defined (CONFIG_M68060)
@@ -359,37 +363,37 @@ SYMBOL_NAME_LABEL(resume)
beqs 1f
#endif
/* The 060 FPU keeps status in bits 15-8 of the first longword */
- tstb %a1@(LTSS_FPCTXT+27*4+2)
+ tstb %a1@(TASK_TSS+TSS_FPSTATE+2)
jeq 3f
#if !defined(CPU_M68060_ONLY)
jra 2f
#endif
#endif /* CONFIG_M68060 */
#if !defined(CPU_M68060_ONLY)
-1: tstb %a1@(LTSS_FPCTXT+27*4)
+1: tstb %a1@(TASK_TSS+TSS_FPSTATE)
jeq 3f
#endif
-2: fmovemx %a1@(LTSS_FPCTXT),%fp0-%fp7
- fmoveml %a1@(LTSS_FPCTXT+24*4),%fpcr/%fpsr/%fpiar
-3: frestore %a1@(LTSS_FPCTXT+27*4)
+2: fmovemx %a1@(TASK_TSS+TSS_FPREG),%fp0-%fp7
+ fmoveml %a1@(TASK_TSS+TSS_FPCNTL),%fpcr/%fpsr/%fpiar
+3: frestore %a1@(TASK_TSS+TSS_FPSTATE)
/* restore the kernel stack pointer */
- movel %a1@(LTSS_KSP),%sp
+ movel %a1@(TASK_TSS+TSS_KSP),%sp
/* restore non-scratch registers */
RESTORE_SWITCH_STACK
/* restore user stack pointer */
- movel %a1@(LTSS_USP),%a0
+ movel %a1@(TASK_TSS+TSS_USP),%a0
movel %a0,%usp
/* restore fs (sfc,%dfc) */
- movew %a1@(LTSS_FS),%a0
+ movew %a1@(TASK_TSS+TSS_FS),%a0
movec %a0,%sfc
movec %a0,%dfc
/* restore status register */
- movew %a1@(LTSS_SR),%sr
+ movew %a1@(TASK_TSS+TSS_SR),%sr
rts
@@ -586,6 +590,7 @@ SYMBOL_NAME_LABEL(sys_call_table)
.long SYMBOL_NAME(sys_sendfile)
.long SYMBOL_NAME(sys_ni_syscall) /* streams1 */
.long SYMBOL_NAME(sys_ni_syscall) /* streams2 */
+ .long SYMBOL_NAME(sys_vfork) /* 190 */
.rept NR_syscalls-(.-SYMBOL_NAME(sys_call_table))/4
.long SYMBOL_NAME(sys_ni_syscall)
diff --git a/arch/m68k/kernel/head.S b/arch/m68k/kernel/head.S
index e98f39fa8..482c15f50 100644
--- a/arch/m68k/kernel/head.S
+++ b/arch/m68k/kernel/head.S
@@ -7,9 +7,12 @@
**
** 68040 fixes by Michael Rausch
** 68060 fixes by Roman Hodek
+** MMU cleanup by Randy Thelen
+** Final MMU cleanup by Roman Zippel
**
** Atari support by Andreas Schwab, using ideas of Robert de Vries
** and Bjoern Brauel
+** VME Support by Richard Hirst
**
** 94/11/14 Andreas Schwab: put kernel at PAGESIZE
** 94/11/18 Andreas Schwab: remove identity mapping of STRAM for Atari
@@ -18,6 +21,8 @@
** 96/04/26 Guenther Kelleter: fixed identity mapping for Falcon with
** Magnum- and FX-alternate ram
** 98/04/25 Phil Blundell: added HP300 support
+** 1998/08/30 David Kilzer: Added support for fbcon_font_desc structures
+** for linux-2.1.115
**
** This file is subject to the terms and conditions of the GNU General Public
** License. See the file README.legal in the main directory of this archive
@@ -34,69 +39,275 @@
* Put us in supervisor state.
*
* The kernel setup code takes the following steps:
- * Raise interrupt level
- * Set up initial kernel memory mapping.
- * This sets up a mapping of the 4M of memory the kernel
- * is located in. It also does a mapping of any initial
- * machine specific areas.
- * Note that the kernel is located at virtual address 0x1000 == _start
- * Enable cache memories
- * Jump to kernel startup
- *
- * Register d6 contains the CPU flags and d4 the machine type
- * from the boot_info information for most of this file.
- * The upper word of d6 contains a bit for '040 or '060, since these two
- * are quite similar for initial mm setup. Another bit in d6 allows
- * distinction of the '060. The lower word of d6 contains the cache mode
- * that should be applied to pages containing descriptors. This mode is
- * non-cached/non-serialized for the '040 and cacheable/write-through for
- * the '060.
- *
- * General register usage:
- * a6 - start of unused memory
- * new pages can be allocated from here
- * a5 - mmu root table
- * a4 - mmu pointer table
- * a3 - mmu page tables
- * a2 - points to the page table entry for a6
- * cache status can be changed (used for '0[46]0)
- * you must increase a2 if alloc a new page
- * d7 - used for debug output and some macros
- * d6 - cpu type and cache mode
- * d5 - physical start address of kernel
- * d4 - machine type
+ * . Raise interrupt level
+ * . Set up initial kernel memory mapping.
+ * . This sets up a mapping of the 4M of memory the kernel is located in.
+ * . It also does a mapping of any initial machine specific areas.
+ * . Enable the MMU
+ * . Enable cache memories
+ * . Jump to kernel startup
+ *
+ * Much of the file restructuring was to accomplish:
+ * 1) Remove register dependency through-out the file.
+ * 2) Increase use of subroutines to perform functions
+ * 3) Increase readability of the code
+ *
+ * Of course, readability is a subjective issue, so it will never be
+ * argued that that goal was accomplished. It was merely a goal.
+ * A key way to help make code more readable is to give good
+ * documentation. So, the first thing you will find is exaustive
+ * write-ups on the structure of the file, and the features of the
+ * functional subroutines.
+ *
+ * General Structure:
+ * ------------------
+ * Without a doubt the single largest chunk of head.S is spent
+ * mapping the kernel and I/O physical space into the logical range
+ * for the kernel.
+ * There are new subroutines and data structures to make MMU
+ * support cleaner and easier to understand.
+ * First, you will find a routine call "mmu_map" which maps
+ * a logical to a physical region for some length given a cache
+ * type on behalf of the caller. This routine makes writing the
+ * actual per-machine specific code very simple.
+ * A central part of the code, but not a subroutine in itself,
+ * is the mmu_init code which is broken down into mapping the kernel
+ * (the same for all machines) and mapping machine-specific I/O
+ * regions.
+ * Also, there will be a description of engaging the MMU and
+ * caches.
+ * You will notice that there is a chunk of code which
+ * can emit the entire MMU mapping of the machine. This is present
+ * only in debug modes and can be very helpful.
+ * Further, there is a new console driver in head.S that is
+ * also only engaged in debug mode. Currently, it's only supported
+ * on the Macintosh class of machines. However, it is hoped that
+ * others will plug-in support for specific machines.
+ *
+ * ######################################################################
+ *
+ * mmu_map
+ * -------
+ * mmu_map was written for two key reasons. First, it was clear
+ * that it was very difficult to read the previous code for mapping
+ * regions of memory. Second, the Macintosh required such extensive
+ * memory allocations that it didn't make sense to propogate the
+ * existing code any further.
+ * mmu_map requires some parameters:
+ *
+ * mmu_map (logical, physical, length, cache_type)
+ *
+ * While this essentially describes the function in the abstract, you'll
+ * find more indepth description of other parameters at the implementation site.
+ *
+ * mmu_get_root_table_entry
+ * ------------------------
+ * mmu_get_ptr_table_entry
+ * -----------------------
+ * mmu_get_page_table_entry
+ * ------------------------
+ *
+ * These routines are used by other mmu routines to get a pointer into
+ * a table, if necessary a new table is allocated. These routines are working
+ * basically like pmd_alloc() and pte_alloc() in <asm/pgtable.h>. The root
+ * table needs of course only to be allocated once in mmu_get_root_table_entry,
+ * so that here also some mmu specific initialization is done. The second page
+ * at the start of the kernel (the first page is unmapped later) is used for
+ * the kernel_pg_dir. It must be at a position known at link time (as it's used
+ * to initialize the init task struct) and since it needs special cache
+ * settings, it's the easiest to use this page, the rest of the page is used
+ * for further pointer tables.
+ * mmu_get_page_table_entry allocates always a whole page for page tables, this
+ * means 1024 pages and so 4MB of memory can be mapped. It doesn't make sense
+ * to manage page tables in smaller pieces as nearly all mappings have that
+ * size.
+ *
+ * ######################################################################
+ *
+ *
+ * ######################################################################
+ *
+ * mmu_engage
+ * ----------
+ * Thanks to a small helping routine enabling the mmu got quiet simple
+ * and there is only one way left. mmu_engage makes a complete a new mapping
+ * that only includes the absolute necessary to be able to jump to the final
+ * postion and to restore the original mapping.
+ * As this code doesn't need a transparent translation register anymore this
+ * means all registers are free to be used by machines that needs them for
+ * other purposes.
+ *
+ * ######################################################################
+ *
+ * mmu_print
+ * ---------
+ * This algorithm will print out the page tables of the system as
+ * appropriate for an 030 or an 040. This is useful for debugging purposes
+ * and as such is enclosed in #ifdef MMU_PRINT/#endif clauses.
+ *
+ * ######################################################################
+ *
+ * console_init
+ * ------------
+ * The console is also able to be turned off. The console in head.S
+ * is specifically for debugging and can be very useful. It is surrounded by
+ * #ifdef CONSOLE/#endif clauses so it doesn't have to ship in known-good
+ * kernels. It's basic algorithm is to determine the size of the screen
+ * (in height/width and bit depth) and then use that information for
+ * displaying an 8x8 font or an 8x16 (widthxheight). I prefer the 8x8 for
+ * debugging so I can see more good data. But it was trivial to add support
+ * for both fonts, so I included it.
+ * Also, the algorithm for plotting pixels is abstracted so that in
+ * theory other platforms could add support for different kinds of frame
+ * buffers. This could be very useful.
+ *
+ * console_put_penguin
+ * -------------------
+ * An important part of any Linux bring up is the penguin and there's
+ * nothing like getting the Penguin on the screen! This algorithm will work
+ * on any machine for which there is a console_plot_pixel.
+ *
+ * console_scroll
+ * --------------
+ * My hope is that the scroll algorithm does the right thing on the
+ * various platforms, but it wouldn't be hard to add the test conditions
+ * and new code if it doesn't.
+ *
+ * console_putc
+ * -------------
+ *
+ * ######################################################################
+ *
+ * Register usage has greatly simplified within head.S. Every subroutine
+ * saves and restores all registers that it modifies (except it returns a
+ * value in there of course). So the only register that needs to be initialized
+ * is the stack pointer.
+ * All other init code and data is now placed in the init section, so it will
+ * be automatically freed at the end of the kernel initialization.
+ *
+ * ######################################################################
+ *
+ * options
+ * -------
+ * There are many options availble in a build of this file. I've
+ * taken the time to describe them here to save you the time of searching
+ * for them and trying to understand what they mean.
+ *
+ * CONFIG_xxx: These are the obvious machine configuration defines created
+ * during configuration. These are defined in include/linux/autoconf.h.
+ *
+ * CONSOLE: There is support for head.S console in this file. This
+ * console can talk to a Mac frame buffer, but could easily be extrapolated
+ * to extend it to support other platforms.
+ *
+ * TEST_MMU: This is a test harness for running on any given machine but
+ * getting an MMU dump for another class of machine. The classes of machines
+ * that can be tested are any of the makes (Atari, Amiga, Mac, VME, etc.)
+ * and any of the models (030, 040, 060, etc.).
+ *
+ * NOTE: TEST_MMU is NOT permanent! It is scheduled to be removed
+ * When head.S boots on Atari, Amiga, Macintosh, and VME
+ * machines. At that point the underlying logic will be
+ * believed to be solid enough to be trusted, and TEST_MMU
+ * can be dropped. Do note that that will clean up the
+ * head.S code significantly as large blocks of #if/#else
+ * clauses can be removed.
+ *
+ * MMU_NOCACHE_KERNEL: On the Macintosh platform there was an inquiry into
+ * determing why devices don't appear to work. A test case was to remove
+ * the cacheability of the kernel bits.
+ *
+ * MMU_PRINT: There is a routine built into head.S that can display the
+ * MMU data structures. It outputs its result through the serial_putc
+ * interface. So where ever that winds up driving data, that's where the
+ * mmu struct will appear. On the Macintosh that's typically the console.
+ *
+ * SERIAL_DEBUG: There are a series of putc() macro statements
+ * scattered through out the code to give progress of status to the
+ * person sitting at the console. This constant determines whether those
+ * are used.
+ *
+ * DEBUG: This is the standard DEBUG flag that can be set for building
+ * the kernel. It has the effect adding additional tests into
+ * the code.
+ *
+ * FONT_6x11:
+ * FONT_8x8:
+ * FONT_8x16:
+ * In theory these could be determined at run time or handed
+ * over by the booter. But, let's be real, it's a fine hard
+ * coded value. (But, you will notice the code is run-time
+ * flexible!) A pointer to the font's struct fbcon_font_desc
+ * is kept locally in Lconsole_font. It is used to determine
+ * font size information dynamically.
+ *
+ * Atari constants:
+ * USE_PRINTER: Use the printer port for serial debug.
+ * USE_SCC_B: Use the SCC port A (Serial2) for serial debug.
+ * USE_SCC_A: Use the SCC port B (Modem2) for serial debug.
+ * USE_MFP: Use the ST-MFP port (Modem1) for serial debug.
+ *
+ * Macintosh constants:
+ * MAC_SERIAL_DEBUG: Turns on serial debug output for the Macintosh.
+ * MAC_USE_SCC_A: Use the SCC port A (modem) for serial debug.
+ * MAC_USE_SCC_B: Use the SCC port B (printer) for serial debug (default).
*/
#include <linux/config.h>
#include <linux/linkage.h>
+#include <linux/init.h>
#include <asm/bootinfo.h>
#include <asm/setup.h>
#include <asm/pgtable.h>
+#include "m68k_defs.h"
-.globl SYMBOL_NAME(kernel_pg_dir), SYMBOL_NAME(kpt)
-.globl SYMBOL_NAME(availmem)
-.globl SYMBOL_NAME(m68k_pgtable_cachemode)
-.globl SYMBOL_NAME(kernel_pmd_table), SYMBOL_NAME(swapper_pg_dir)
+#ifdef CONFIG_MAC
-#if defined(CONFIG_MVME16x)
-.globl SYMBOL_NAME(mvme_bdid_ptr)
-#endif
+#include <asm/machw.h>
/*
- * Added m68k_supervisor_cachemode for 68060 boards where some drivers
- * need writethrough caching for supervisor accesses. Drivers known to
- * be effected are 53c7xx.c and apricot.c (when used on VME boards).
- * Richard Hirst.
+ * Macintosh console support
*/
-#ifdef CONFIG_060_WRITETHROUGH
+#define CONSOLE
+
+/*
+ * Macintosh serial debug support; outputs boot info to the printer
+ * and/or modem serial ports
+ */
+#undef MAC_SERIAL_DEBUG
+
+/*
+ * Macintosh serial debug port selection; define one or both;
+ * requires MAC_SERIAL_DEBUG to be defined
+ */
+#define MAC_USE_SCC_A /* Macintosh modem serial port */
+#define MAC_USE_SCC_B /* Macintosh printer serial port */
+
+#endif /* CONFIG_MAC */
+
+#undef MMU_PRINT
+#undef MMU_NOCACHE_KERNEL
+#define SERIAL_DEBUG
+#undef DEBUG
+
+/*
+ * For the head.S console, there are three supported fonts, 6x11, 8x16 and 8x8.
+ * The 8x8 font is harder to read but fits more on the screen.
+ */
+#define FONT_8x8 /* default */
+/* #define FONT_8x16 */ /* 2nd choice */
+/* #define FONT_6x11 */ /* 3rd choice */
+
+.globl SYMBOL_NAME(kernel_pg_dir)
+.globl SYMBOL_NAME(availmem)
+.globl SYMBOL_NAME(m68k_pgtable_cachemode)
.globl SYMBOL_NAME(m68k_supervisor_cachemode)
-#endif
-D6B_0460 = 16 /* indicates 680[46]0 in d6 */
-D6B_060 = 17 /* indicates 68060 in d6 */
-D6F_040 = 1<<D6B_0460
-D6F_060 = (1<<D6B_0460)+(1<<D6B_060)
+CPUTYPE_040 = 1 /* indicates an 040 */
+CPUTYPE_060 = 2 /* indicates an 060 */
+CPUTYPE_0460 = 3 /* if either above are set, this is set */
+CPUTYPE_020 = 4 /* indicates an 020 */
/* Translation control register */
TC_ENABLE = 0x8000
@@ -144,6 +355,7 @@ CC3_ENABLE_I = 0x00000001 /* enable instruction cache (68030) */
/* Miscellaneous definitions */
PAGESIZE = 4096
+PAGESHIFT = 12
ROOT_TABLE_SIZE = 128
PTR_TABLE_SIZE = 128
@@ -152,32 +364,182 @@ ROOT_INDEX_SHIFT = 25
PTR_INDEX_SHIFT = 18
PAGE_INDEX_SHIFT = 12
-TABLENR_4MB = 16 /* # of page tables needed to page 4 MB */
-TABLENR_16MB = 64 /* same for 16 MB */
+#ifdef DEBUG
+/* When debugging use readable names for labels */
+#ifdef __STDC__
+#define L(name) .head.S.##name
+#else
+#define L(name) .head.S./**/name
+#endif
+#else
+#ifdef __STDC__
+#define L(name) .L##name
+#else
+#define L(name) .L/**/name
+#endif
+#endif
-#define putc(ch) moveq &ch,%d7; jbsr Lserial_putc
-#define putr() putc(13); putc(10)
-#define putn(nr) movel nr,%d7; jbsr Lserial_putnum
+/* Several macros to make the writing of subroutines easier:
+ * - func_start marks the beginning of the routine which setups the frame
+ * register and saves the registers, it also defines another macro
+ * to automatically restore the registers again.
+ * - func_return marks the end of the routine and simply calls the prepared
+ * macro to restore registers and jump back to the caller.
+ * - func_define generates another macro to automatically put arguments
+ * onto the stack call the subroutine and cleanup the stack again.
+ */
-#define is_not_amiga(lab) moveq &MACH_AMIGA,%d7; cmpl %d4,%d7; jne lab
-#define is_not_atari(lab) moveq &MACH_ATARI,%d7; cmpl %d4,%d7; jne lab
-#define is_not_mvme16x(lab) moveq &MACH_MVME16x,%d7; cmpl %d4,%d7; jne lab
-#define is_not_bvme6000(lab) moveq &MACH_BVME6000,%d7; cmpl %d4,%d7; jne lab
-#define is_not_hp300(lab) moveq &MACH_HP300,%d7 ; cmpl %d4,%d7; jne lab
+/* Within subroutines these macros can be used to access the arguments
+ * on the stack. With STACK some allocated memory on the stack can be
+ * accessed and ARG0 points to the return address (used by mmu_engage).
+ */
+#define STACK %a6@(stackstart)
+#define ARG0 %a6@(4)
+#define ARG1 %a6@(8)
+#define ARG2 %a6@(12)
+#define ARG3 %a6@(16)
+#define ARG4 %a6@(20)
+
+.macro func_start name,saveregs,stack=0
+L(\name):
+ linkw %a6,#-\stack
+ moveml \saveregs,%sp@-
+.set stackstart,-\stack
+
+.macro func_return_\name
+ moveml %sp@+,\saveregs
+ unlk %a6
+ rts
+.endm
+.endm
+
+.macro func_return name
+ func_return_\name
+.endm
+
+.macro func_call name
+ jbsr L(\name)
+.endm
+
+.macro move_stack nr,arg1,arg2,arg3,arg4
+.if \nr
+ move_stack "(\nr-1)",\arg2,\arg3,\arg4
+ movel \arg1,%sp@-
+.endif
+.endm
+
+.macro func_define name,nr=0
+.macro \name arg1,arg2,arg3,arg4
+ move_stack \nr,\arg1,\arg2,\arg3,\arg4
+ func_call \name
+.if \nr
+ lea %sp@(\nr*4),%sp
+.endif
+.endm
+.endm
+
+func_define mmu_map,4
+func_define mmu_map_tt,4
+func_define mmu_fixup_page_mmu_cache,1
+func_define mmu_temp_map,2
+func_define mmu_engage
+func_define mmu_get_root_table_entry,1
+func_define mmu_get_ptr_table_entry,2
+func_define mmu_get_page_table_entry,2
+func_define mmu_print
+func_define get_new_page
+#ifdef CONFIG_HP300
+func_define set_leds
+#endif
+
+.macro mmu_map_eq arg1,arg2,arg3
+ mmu_map \arg1,\arg1,\arg2,\arg3
+.endm
+
+.macro get_bi_record record
+ pea \record
+ func_call get_bi_record
+ addql #4,%sp
+.endm
+
+func_define serial_putc,1
+func_define console_putc,1
+
+.macro putc ch
+#if defined(CONSOLE) || defined(SERIAL_DEBUG)
+ pea \ch
+#endif
+#ifdef CONSOLE
+ func_call console_putc
+#endif
+#ifdef SERIAL_DEBUG
+ func_call serial_putc
+#endif
+#if defined(CONSOLE) || defined(SERIAL_DEBUG)
+ addql #4,%sp
+#endif
+.endm
+
+.macro dputc ch
+#ifdef DEBUG
+ putc \ch
+#endif
+.endm
+
+func_define putn,1
+
+.macro dputn nr
+#ifdef DEBUG
+ putn \nr
+#endif
+.endm
+
+.macro puts string
+#if defined(CONSOLE) || defined(SERIAL_DEBUG)
+ __INITDATA
+.Lstr\@:
+ .string "\string"
+ __FINIT
+ pea %pc@(.Lstr\@)
+ func_call puts
+ addql #4,%sp
+#endif
+.endm
+
+.macro dputs string
+#ifdef DEBUG
+ puts "\string"
+#endif
+.endm
-#define is_040_or_060(lab) btst &D6B_0460,%d6; jne lab
-#define is_not_040_or_060(lab) btst &D6B_0460,%d6; jeq lab
-#define is_060(lab) btst &D6B_060,%d6; jne lab
-#define is_not_060(lab) btst &D6B_060,%d6; jeq lab
+
+#define is_not_amiga(lab) cmpl &MACH_AMIGA,%pc@(m68k_machtype); jne lab
+#define is_not_atari(lab) cmpl &MACH_ATARI,%pc@(m68k_machtype); jne lab
+#define is_not_mac(lab) cmpl &MACH_MAC,%pc@(m68k_machtype); jne lab
+#define is_not_mvme16x(lab) cmpl &MACH_MVME16x,%pc@(m68k_machtype); jne lab
+#define is_not_bvme6000(lab) cmpl &MACH_BVME6000,%pc@(m68k_machtype); jne lab
+#define is_not_hp300(lab) cmpl &MACH_HP300,%pc@(m68k_machtype); jne lab
+
+#define is_040_or_060(lab) btst &CPUTYPE_0460,%pc@(L(cputype)+3); jne lab
+#define is_not_040_or_060(lab) btst &CPUTYPE_0460,%pc@(L(cputype)+3); jeq lab
+#define is_040(lab) btst &CPUTYPE_040,%pc@(L(cputype)+3); jne lab
+#define is_060(lab) btst &CPUTYPE_060,%pc@(L(cputype)+3); jne lab
+#define is_not_060(lab) btst &CPUTYPE_060,%pc@(L(cputype)+3); jeq lab
+#define is_020(lab) btst &CPUTYPE_020,%pc@(L(cputype)+3); jne lab
+#define is_not_020(lab) btst &CPUTYPE_020,%pc@(L(cputype)+3); jeq lab
/* On the HP300 we use the on-board LEDs for debug output before
the console is running. Writing a 1 bit turns the corresponding LED
_off_ - on the 340 bit 7 is towards the back panel of the machine. */
+.macro leds mask
#ifdef CONFIG_HP300
-#define leds(x) is_not_hp300(42f) ; moveb #(x),%d7 ; jbsr Lset_leds; 42:
-#else
-#define leds(x)
+ is_not_hp300(.Lled\@)
+ pea \mask
+ func_call set_leds
+ addql #4,%sp
+.Lled\@:
#endif
+.endm
.text
ENTRY(_stext)
@@ -192,81 +554,193 @@ ENTRY(_stext)
.long MACH_ATARI, ATARI_BOOTI_VERSION
.long MACH_MVME16x, MVME16x_BOOTI_VERSION
.long MACH_BVME6000, BVME6000_BOOTI_VERSION
+ .long MACH_MAC, MAC_BOOTI_VERSION
.long 0
-1: jra SYMBOL_NAME(_start)
+1: jra SYMBOL_NAME(__start)
-.equ SYMBOL_NAME(kernel_pmd_table),SYMBOL_NAME(_stext)
-.equ SYMBOL_NAME(kernel_pg_dir),SYMBOL_NAME(kernel_pmd_table)
-.equ SYMBOL_NAME(swapper_pg_dir),SYMBOL_NAME(kernel_pg_dir)+(ROOT_TABLE_SIZE<<2)
-.equ Lavail_pmd_table,SYMBOL_NAME(swapper_pg_dir)+(ROOT_TABLE_SIZE<<2)
+.equ SYMBOL_NAME(kernel_pg_dir),SYMBOL_NAME(_stext)
.equ .,SYMBOL_NAME(_stext)+PAGESIZE
ENTRY(_start)
+ jra SYMBOL_NAME(__start)
+__INIT
+ENTRY(__start)
/*
* Setup initial stack pointer
*/
- lea %pc@(SYMBOL_NAME(_stext):w),%sp
+ lea %pc@(SYMBOL_NAME(_stext)),%sp
/*
* Record the CPU and machine type.
*/
- movew #BI_MACHTYPE,%d0
- jbsr Lget_bi_record
- movel %a0@,%d4
- lea %pc@(SYMBOL_NAME(m68k_machtype)),%a0
- movel %d4,%a0@
- movew #BI_FPUTYPE,%d0
- jbsr Lget_bi_record
- movel %a0@,%d0
- lea %pc@(SYMBOL_NAME(m68k_fputype)),%a0
- movel %d0,%a0@
- movew #BI_MMUTYPE,%d0
- jbsr Lget_bi_record
- movel %a0@,%d0
- lea %pc@(SYMBOL_NAME(m68k_mmutype)),%a0
- movel %d0,%a0@
- movew #BI_CPUTYPE,%d0
- jbsr Lget_bi_record
+ get_bi_record BI_MACHTYPE
+ lea %pc@(SYMBOL_NAME(m68k_machtype)),%a1
+ movel %a0@,%a1@
+
+ get_bi_record BI_FPUTYPE
+ lea %pc@(SYMBOL_NAME(m68k_fputype)),%a1
+ movel %a0@,%a1@
+
+ get_bi_record BI_MMUTYPE
+ lea %pc@(SYMBOL_NAME(m68k_mmutype)),%a1
+ movel %a0@,%a1@
+
+ get_bi_record BI_CPUTYPE
+ lea %pc@(SYMBOL_NAME(m68k_cputype)),%a1
+ movel %a0@,%a1@
+
+#ifdef CONFIG_MAC
+/*
+ * For Macintosh, we need to determine the display parameters early (at least
+ * while debugging it).
+ */
+
+ is_not_mac(L(test_notmac))
+
+ get_bi_record BI_MAC_VADDR
+ lea %pc@(L(mac_videobase)),%a1
+ movel %a0@,%a1@
+
+ get_bi_record BI_MAC_VDEPTH
+ lea %pc@(L(mac_videodepth)),%a1
+ movel %a0@,%a1@
+
+ get_bi_record BI_MAC_VDIM
+ lea %pc@(L(mac_dimensions)),%a1
+ movel %a0@,%a1@
+
+ get_bi_record BI_MAC_VROW
+ lea %pc@(L(mac_rowbytes)),%a1
+ movel %a0@,%a1@
+
+#ifdef MAC_SERIAL_DEBUG
+ get_bi_record BI_MAC_SCCBASE
+ lea %pc@(L(mac_sccbase)),%a1
+ movel %a0@,%a1@
+#endif /* MAC_SERIAL_DEBUG */
+
+#if 0
+ /*
+ * Clear the screen
+ */
+ lea %pc@(L(mac_videobase)),%a0
+ movel %a0@,%a1
+ lea %pc@(L(mac_dimensions)),%a0
+ movel %a0@,%d1
+ swap %d1 /* #rows is high bytes */
+ andl #0xFFFF,%d1 /* rows */
+ subl #10,%d1
+ lea %pc@(L(mac_rowbytes)),%a0
+loopy2:
movel %a0@,%d0
- lea %pc@(SYMBOL_NAME(m68k_cputype)),%a0
- movel %d0,%a0@
+ subql #1,%d0
+loopx2:
+ moveb #0x55, %a1@+
+ dbra %d0,loopx2
+ dbra %d1,loopy2
+#endif
+
+L(test_notmac):
+#endif /* CONFIG_MAC */
+
+/*
+ * There are ultimately two pieces of information we want for all kinds of
+ * processors CpuType and CacheBits. The CPUTYPE was passed in from booter
+ * and is converted here from a booter type definition to a separate bit
+ * number which allows for the standard is_0x0 macro tests.
+ */
+ movel %pc@(SYMBOL_NAME(m68k_cputype)),%d0
+ /*
+ * Assume it's an 030
+ */
+ clrl %d1
+
+ /*
+ * Test the BootInfo cputype for 060
+ */
btst #CPUB_68060,%d0
jeq 1f
- /* '060: d6 := BIT0460|BIT060, cache mode 0x60 (no-cache/non-ser) */
- movel #D6F_060+_PAGE_CACHE040W,%d6
- jra 2f
-1: btst #CPUB_68040,%d0
- jeq 1f
- /* '040: d6 := BIT0460, cache mode 0x00 (write-through) */
- movel #D6F_040+_PAGE_CACHE040W,%d6
- jra 2f
-1: /* '020 or '030: d6 := no CPU bit, cache mode unused */
- moveq #0,%d6
+ bset #CPUTYPE_060,%d1
+ bset #CPUTYPE_0460,%d1
+ jra 3f
+1:
+ /*
+ * Test the BootInfo cputype for 040
+ */
+ btst #CPUB_68040,%d0
+ jeq 2f
+ bset #CPUTYPE_040,%d1
+ bset #CPUTYPE_0460,%d1
+ jra 3f
+2:
+ /*
+ * Test the BootInfo cputype for 020
+ */
+ btst #CPUB_68020,%d0
+ jeq 3f
+ bset #CPUTYPE_020,%d1
+ jra 3f
+3:
+ /*
+ * Record the cpu type
+ */
+ lea %pc@(L(cputype)),%a0
+ movel %d1,%a0@
-2: lea %pc@(SYMBOL_NAME(m68k_pgtable_cachemode)),%a0
- moveq #0,%d0
- movew %d6,%d0
- movel %d0,%a0@ /* save cache mode for page tables */
+ /*
+ * NOTE:
+ *
+ * Now the macros are valid:
+ * is_040_or_060
+ * is_not_040_or_060
+ * is_040
+ * is_060
+ * is_not_060
+ */
+
+ /*
+ * Determine the cache mode for pages holding MMU tables
+ * and for supervisor mode, unused for '020 and '030
+ */
+ clrl %d0
+ clrl %d1
+ is_not_040_or_060(L(save_cachetype))
+
+ /*
+ * '040 or '060
+ * d1 := cacheable write-through
+ * NOTE: The 68040 manual strongly recommends non-cached for MMU tables,
+ * but we have been using write-through since at least 2.0.29 so I
+ * guess it is OK.
+ */
+#ifdef CONFIG_060_WRITETHROUGH
/*
* If this is a 68060 board using drivers with cache coherency
* problems, then supervisor memory accesses need to be write-through
- * also; otherwise, we want copyback.
+ * also; otherwise, we want copyback.
*/
-#if defined(CONFIG_060_WRITETHROUGH)
- is_not_060(Lset_norm)
- jra 1f
-Lset_norm:
- move.w #_PAGE_CACHE040,%d0
+ is_not_060(1f)
+ movel #_PAGE_CACHE040W,%d0
+ jra L(save_cachetype)
+#endif /* CONFIG_060_WRITETHROUGH */
1:
- lea %pc@(SYMBOL_NAME(m68k_supervisor_cachemode)),%a0
+ movew #_PAGE_CACHE040,%d0
+
+ movel #_PAGE_CACHE040W,%d1
+
+L(save_cachetype):
+ /* Save cache mode for supervisor mode and page tables
+ */
+ lea %pc@(SYMBOL_NAME(m68k_supervisor_cachemode)),%a0
movel %d0,%a0@
-#endif
+ lea %pc@(SYMBOL_NAME(m68k_pgtable_cachemode)),%a0
+ movel %d1,%a0@
/*
* raise interrupt level
@@ -293,288 +767,120 @@ Lset_norm:
*/
#ifdef CONFIG_ATARI
- is_not_atari(Lnotypetest)
+ is_not_atari(L(notypetest))
/* get special machine type (Medusa/Hades/AB40) */
moveq #0,%d3 /* default if tag doesn't exist */
- movew #BI_ATARI_MCH_TYPE,%d0
- jbsr Lget_bi_record
+ get_bi_record BI_ATARI_MCH_TYPE
tstl %d0
jbmi 1f
movel %a0@,%d3
-1:
- /* %d3 is not clobbered until Atari page tables are set up,
- * where it is used again. */
-
+ lea %pc@(SYMBOL_NAME(atari_mch_type)),%a0
+ movel %d3,%a0@
+1:
/* On the Hades, the iobase must be set up before opening the
* serial port. There are no I/O regs at 0x00ffxxxx at all. */
moveq #0,%d0
cmpl #ATARI_MACH_HADES,%d3
jbne 1f
movel #0xff000000,%d0 /* Hades I/O base addr: 0xff000000 */
-1: lea %pc@(Liobase),%a0
+1: lea %pc@(L(iobase)),%a0
movel %d0,%a0@
-Lnotypetest:
+
+L(notypetest):
#endif
/*
* Initialize serial port
*/
-
- jbsr Lserial_init
-
- putr()
- putc('A')
+ jbsr L(serial_init)
/*
- * Get address at end of bootinfo and mask off at a page boundary.
+ * Initialize console
*/
- moveq #0,%d0
- jbsr Lget_bi_record
- addw #PAGESIZE-1,%a0
- movel %a0,%d0
- andl #-PAGESIZE,%d0
- movel %d0,%a6
-
- putc('B')
+#ifdef CONFIG_MAC
+ is_not_mac(L(nocon))
+#ifdef CONSOLE
+ jbsr L(console_init)
+#ifdef CONSOLE_PENGUIN
+ jbsr L(console_put_penguin)
+#endif /* CONSOLE_PENGUIN */
+ jbsr L(console_put_stats)
+#endif /* CONSOLE */
+L(nocon):
+#endif /* CONFIG_MAC */
+
+
+ putc '\n'
+ putc 'A'
+ dputn %pc@(L(cputype))
+ dputn %pc@(SYMBOL_NAME(m68k_supervisor_cachemode))
+ dputn %pc@(SYMBOL_NAME(m68k_pgtable_cachemode))
+ dputc '\n'
/*
* Save physical start address of kernel
*/
- lea %pc@(SYMBOL_NAME(_stext)-PAGESIZE:w),%a0
- movel %a0,%d5
-
-/*
- * initialize the kernel root table.
- */
- lea %pc@(SYMBOL_NAME(kernel_pg_dir):w),%a5
- movel %a5,%a0
- moveq #ROOT_TABLE_SIZE-1,%d1
-1: clrl %a0@+
- dbra %d1,1b
-
- /*
- * Initialize root table descriptor pointing to the kernel pointer
- * table.
- */
- lea %pc@(Lavail_pmd_table:w),%a4
- moveq #_PAGE_TABLE,%d0
- addl %a4,%d0
- movel %d0,%a5@
-
- putc('C')
-
-/*
- * Initialize the pointer tables referred to above. They either point
- * to page tables in the case of the 680[46]0 or contain early
- * termination page descriptors in the case of the 68851 or 68030.
- *
- * Each pointer table entry points to a 64 entry page table. 16 of these
- * page tables are grouped to form a single 1024 entry page table which
- * fits in a single 4096 byte page.
- *
- * Some register usages:
- * a0 -> pointer table descriptor address
- * a1 -> pointer table descriptor
- * d1 -> counter
- * d2 -> pointer table descriptor increment (varies according to CPU)
- */
-
- /* clear the kernel pointer table */
- movel %a4,%a0
- moveq #PTR_TABLE_SIZE-1,%d1
-1: clrl %a0@+
- dbra %d1,1b
+ lea %pc@(L(phys_kernel_start)),%a0
+ lea %pc@(SYMBOL_NAME(_stext)),%a1
+ subl #SYMBOL_NAME(_stext),%a1
+ movel %a1,%a0@
- movel %a4,%a0
- moveq #15,%d1
+ putc 'B'
- /*
- * base value of pointer table descriptor is either
- * the address of the first page table (680[46]0)
- * or the base address of physical memory (68030).
- */
- is_040_or_060(1f)
-
- /* 680[23]0 */
- movel %d5,%a1 /* base address */
- addql #_PAGE_PRESENT,%a1 /* descriptor type */
- movel #PAGE_TABLE_SIZE*PAGESIZE,%d2 /* increment */
- jra 2f
-
-1: /* 680[46]0 */
- movel %a6,%a3 /* base address */
- addw #PAGESIZE,%a6 /* allocate page for 16 page tables */
- lea %pc@(SYMBOL_NAME(kpt)),%a1
- movel %a3,%a1@ /* save address of page table */
- movel %a3,%a1
- addw #_PAGE_TABLE+_PAGE_ACCESSED,%a1 /* descriptor type */
- movel #PAGE_TABLE_SIZE<<2,%d2 /* increment */
-
-2: movel %a1,%a0@+
- addl %d2,%a1
- dbra %d1,2b
-
- putc('D')
+ leds 0x4
/*
- * If we are running on a 680[46]0, we have a kernel page table and
- * must initialize it. Make the entries point to the first
- * 4M of physical memory (the memory we are residing in).
- * Set the cache mode bits to Cacheable, Copyback. Set the Global bits
- * in the descriptors also.
+ * mmu_init
+ *
+ * This block of code does what's necessary to map in the various kinds
+ * of machines for execution of Linux.
+ * First map the first 4 MB of kernel code & data
*/
- is_not_040_or_060(Lnot040)
- putc('F')
-
- movel %a3,%a0
- movel %d5,%a1
-#if defined(CONFIG_060_WRITETHROUGH)
- addw #_PAGE_GLOBAL040+_PAGE_PRESENT+_PAGE_ACCESSED,%a1
- addl m68k_supervisor_cachemode,%a1
-#else
- addw #_PAGE_GLOBAL040+_PAGE_CACHE040+_PAGE_PRESENT+_PAGE_ACCESSED,%a1
-#endif
- movew #(PAGE_TABLE_SIZE*TABLENR_4MB)-1,%d1
- movel #PAGESIZE,%d2
-1: movel %a1,%a0@+
- addl %d2,%a1
- dbra %d1,1b
-
- /*
- * on the 68040, pages used to hold mmu tables should
- * be initialized as noncachable; the '060 allows write-through.
- * Do this for the root table page (which also contains
- * all pointer tables utilized thus far) and the
- * kernel page table.
- */
- movel %a5,%d0
- subl %d5,%d0
- moveq #PAGE_INDEX_SHIFT,%d2
- lsrl %d2,%d0
- lea %a3@(%d0:l:4),%a2
- movel %a2@,%d1
- andw #_CACHEMASK040,%d1
- orw %d6,%d1
- movel %d1,%a2@
+ mmu_map #0,%pc@(L(phys_kernel_start)),#4*1024*1024,\
+ %pc@(SYMBOL_NAME(m68k_supervisor_cachemode))
- movel %a3,%d0
- subl %d5,%d0
- lsrl %d2,%d0
- lea %a3@(%d0:l:4),%a2
- movel %a2@,%d1
- andw #_CACHEMASK040,%d1
- orw %d6,%d1
- movel %d1,%a2@+
- /*
- * %a2 points now to the page table entry for available pages at %a6,
- * hence caching modes for new pages can easily set unless increasing
- * of %a2 are forgotten.
- */
-Lnot040:
+ putc 'C'
- leds(0x4)
-
-/*
- * Do any machine specific page table initializations.
- */
#ifdef CONFIG_AMIGA
- is_not_amiga(Lnotami)
+L(mmu_init_amiga):
+
+ is_not_amiga(L(mmu_init_not_amiga))
/*
- * Setup a mapping of the first 16M of physical address space at virtual
- * address 0x80000000, using early termination page descriptors for the
- * 68030, and proper page tables for the 680[46]0. Set this area as
- * non-cacheable.
+ * mmu_init_amiga
*/
- putc('H')
+ putc 'D'
- is_040_or_060(Lspami68040)
+ is_not_040_or_060(1f)
/*
- * for the 68030, just setup a translation to map in the first
- * 32M of physical address space at virtual address 0x80000000
- * using an early termination page descriptor.
+ * 040: Map the 16Meg range physical 0x0 upto logical 0x8000.0000
*/
+ mmu_map #0x80000000,#0,#0x01000000,#_PAGE_NOCACHE_S
- putc('I')
-
- movel #_PAGE_NOCACHE030+_PAGE_PRESENT+_PAGE_ACCESSED,%d0
- movel %d0,%a5@(0x40<<2)
-
- jra Lmapphys
-
-Lspami68040:
-
- /*
- * for the 680[46]0, use another pointer table, and allocate 4 more
- * page tables. Initialize the pointer table to point to the
- * page tables. Then initialize the page tables to point to
- * the first 16M of memory, with no caching (noncachable/serialized).
- */
-
- /* clear the amiga pointer table */
- lea %a4@(PTR_TABLE_SIZE<<2),%a4
- moveq #PTR_TABLE_SIZE-1,%d1
-1: clrl %a0@+
- dbra %d1,1b
-
- /* allocate 4 pages for 64 page tables */
- movel %a6,%a3
- addw #4*PAGESIZE,%a6
-
- /* initialize the pointer table */
- movel %a4,%a0
- movel %a3,%a1
- addw #_PAGE_TABLE+_PAGE_ACCESSED,%a1 /* base descriptor */
- movel #PAGE_TABLE_SIZE<<2,%d2 /* increment */
- moveq #TABLENR_16MB-1,%d1
-
-1: movel %a1,%a0@+
- addl %d2,%a1
- dbra %d1,1b
-
- /* ensure that the root table points to the pointer table */
- movel %a4,%a0
- addw #_PAGE_TABLE+_PAGE_ACCESSED,%a0
- movel %a0,%a5@(0x40<<2)
+ jbra L(mmu_init_done)
+1:
/*
- * initialize the page tables
- * descriptor bits include noncachable/serialized and global bits.
+ * 030: Map the 32Meg range physical 0x0 upto logical 0x8000.0000
*/
- movel %a3,%a0
- movew #_PAGE_GLOBAL040+_PAGE_NOCACHE_S+_PAGE_PRESENT+_PAGE_ACCESSED,%a1
- movel #PAGESIZE,%d2
- movew #(PAGE_TABLE_SIZE*TABLENR_16MB)-1,%d1
+ mmu_map #0x80000000,#0,#0x02000000,#_PAGE_NOCACHE030
-1: movel %a1,%a0@+
- addl %d2,%a1
- dbra %d1,1b
+ jbra L(mmu_init_done)
- /*
- * Finally, since we just allocated 4 page tables, make sure that
- * the virtual mapping of the 4 page tables indicates
- * noncachable/serialized.
- */
- moveq #3,%d0
-1: movel %a2@,%d1 /* a2 already points to root table offset */
- andw #_CACHEMASK040,%d1
- orw %d6,%d1
- movel %d1,%a2@+
- dbra %d0,1b
-
- jra Lmapphys
-
-Lnotami:
+L(mmu_init_not_amiga):
#endif
#ifdef CONFIG_ATARI
- is_not_atari(Lnotatari)
- move.w #PAGESIZE,%sp
+L(mmu_init_atari):
+
+ is_not_atari(L(mmu_init_not_atari))
+
+ putc 'E'
/* On the Atari, we map the I/O region (phys. 0x00ffxxxx) by mapping
the last 16 MB of virtual address space to the first 16 MB (i.e.
@@ -591,103 +897,57 @@ Lnotami:
/* I/O base addr for non-Medusa, non-Hades: 0x00000000 */
moveq #0,%d0
+ movel %pc@(SYMBOL_NAME(atari_mch_type)),%d3
cmpl #ATARI_MACH_MEDUSA,%d3
jbeq 2f
cmpl #ATARI_MACH_HADES,%d3
jbne 1f
2: movel #0xff000000,%d0 /* Medusa/Hades base addr: 0xff000000 */
1: movel %d0,%d3
-
- /* Let the root table point to the new pointer table */
- lea %a4@(PTR_TABLE_SIZE<<2),%a4
- movel %a4,%a0
- addw #_PAGE_TABLE+_PAGE_ACCESSED,%a0
- movel %a0,%a5@(0x7f<<2) /* 0xFE000000 - 0xFFFFFFFF */
-
- /* clear lower half of the pointer table (0xfexxxxxx) */
- movel %a4,%a0
- movel #(PTR_TABLE_SIZE/2)-1,%d2
-1: clrl %a0@+
- dbra %d2,1b
-
- is_040_or_060(Lspata68040)
-
-/* Mapping of the last 16M of virtual address space to the first 16M
- for efficient addressing of hardware registers */
- movel #PAGE_TABLE_SIZE*PAGESIZE,%d1
- movel #(PTR_TABLE_SIZE/2)-1,%d2
- movel %d3,%d0
- orw #_PAGE_PRESENT+_PAGE_ACCESSED,%d0
-1: movel %d0,%a0@+
- addl %d1,%d0
- dbra %d2,1b
- moveq #_PAGE_NOCACHE030,%d0 /* make non-cachable */
- addl %d0,%a4@(0x7f<<2) /* 0xFFFC0000-0xFFFFFFFF (I/O space) */
-/* GK: 0xFFF00000-0xFFF3FFFF (IDE-bus) has to be non-cachable too */
- addl %d0,%a4@(0x7c<<2)
-
- jra Lmapphys
-
-Lspata68040:
- /* allocate 4 page tables */
- movel %a6,%a3
- addw #4*PAGESIZE,%a6
-
- /* Initialize the upper half of the pointer table (a0 is still valid) */
- movel %a3,%a1
- addw #_PAGE_TABLE+_PAGE_ACCESSED,%a1
- movel #PAGE_TABLE_SIZE<<2,%d2
- moveq #TABLENR_16MB-1,%d1
-1: movel %a1,%a0@+
- addl %d2,%a1
- dbra %d1,1b
-
- /* Initialize the page tables as noncacheable/serialized! */
- movel %a3,%a0
- movel %d3,%a1
- addw #_PAGE_GLOBAL040+_PAGE_NOCACHE_S+_PAGE_PRESENT+_PAGE_ACCESSED,%a1
- movel #PAGESIZE,%d2
- movew #(PAGE_TABLE_SIZE*TABLENR_16MB)-1,%d1
-1: movel %a1,%a0@+
- addl %d2,%a1
- dbra %d1,1b
- /*
- * Finally, since we just allocated 4 page tables, make sure that
- * the virtual mapping of the 4 page tables indicates
- * noncachable or write-through.
- */
- moveq #3,%d0
-1: movel %a2@,%d1 /* a2 already points to root table offset */
- andw #_CACHEMASK040,%d1
- orw %d6,%d1
- movel %d1,%a2@+
- dbra %d0,1b
+ is_040_or_060(L(spata68040))
+
+ /* Map everything non-cacheable, though not all parts really
+ * need to disable caches (crucial only for 0xff8000..0xffffff
+ * (standard I/O) and 0xf00000..0xf3ffff (IDE)). The remainder
+ * isn't really used, except for sometimes peeking into the
+ * ROMs (mirror at phys. 0x0), so caching isn't necessary for
+ * this. */
+ mmu_map #0xff000000,%d3,#0x01000000,#_PAGE_NOCACHE030
+
+ jbra L(mmu_init_done)
+
+L(spata68040):
+
+ mmu_map #0xff000000,%d3,#0x01000000,#_PAGE_NOCACHE_S
+
+ jbra L(mmu_init_done)
-Lnotatari:
+L(mmu_init_not_atari):
#endif
#ifdef CONFIG_HP300
- is_not_hp300(Lnothp300)
+ is_not_hp300(L(nothp300))
/* On the HP300, we map the ROM, INTIO and DIO regions (phys. 0x00xxxxxx)
- by mapping 32MB from 0xf0xxxxxx -> 0x00xxxxxx) using an 030 early
- termination page descriptor. The ROM mapping is needed because the LEDs
+ by mapping 32MB from 0xf0xxxxxx -> 0x00xxxxxx) using an 030 early
+ termination page descriptor. The ROM mapping is needed because the LEDs
are mapped there too. */
- movel #_PAGE_NOCACHE030+_PAGE_PRESENT+_PAGE_ACCESSED,%d0
- movel %d0,%a5@(0x78<<2)
+ mmu_map #0xf0000000,#0,#0x02000000,#_PAGE_NOCACHE030
+
+L(nothp300):
-Lnothp300:
-
#endif
-#if defined(CONFIG_MVME16x)
- is_not_mvme16x(Lnot16x)
+#ifdef CONFIG_MVME16x
+
+ is_not_mvme16x(L(not16x))
/* Get pointer to board ID data */
movel %d2,%sp@-
- .long 0x4e4f0070 /* trap 0x70 - .BRD_ID */
+ trap #15
+ .word 0x70 /* trap 0x70 - .BRD_ID */
movel %sp@+,%d2
lea %pc@(SYMBOL_NAME(mvme_bdid_ptr)),%a0
movel %d2,%a0@
@@ -696,392 +956,330 @@ Lnothp300:
* On MVME16x we have already created kernel page tables for
* 4MB of RAM at address 0, so now need to do a transparent
* mapping of the top of memory space. Make it 0.5GByte for now.
+ * Supervisor only access, so transparent mapping doesn't
+ * clash with User code virtual address space.
+ * this covers IO devices, PROM and SRAM. The PROM and SRAM
+ * mapping is needed to allow 167Bug to run.
+ * IO is in the range 0xfff00000 to 0xfffeffff.
+ * PROM is 0xff800000->0xffbfffff and SRAM is
+ * 0xffe00000->0xffe1ffff.
*/
- movel #0xe01f0000,%d2 /* logical address base */
- orw #0xa040,%d2 /* add in magic bits */
- .long 0x4e7b2005 /* movec d2,ittr1 */
- .long 0x4e7b2007 /* movec d2,dttr1 */
+ mmu_map_tt 1,#0xe0000000,#0x20000000,#_PAGE_NOCACHE_S
-Lnot16x:
-#endif
+ jbra L(mmu_init_done)
+
+L(not16x):
+#endif /* CONFIG_MVME162 | CONFIG_MVME167 */
+
+#ifdef CONFIG_BVME6000
-#if defined(CONFIG_BVME6000)
- is_not_bvme6000(Lnotbvm)
+ is_not_bvme6000(L(not6000))
/*
* On BVME6000 we have already created kernel page tables for
* 4MB of RAM at address 0, so now need to do a transparent
- * mapping of the top of memory space. Make it 0.5GByte for now.
+ * mapping of the top of memory space. Make it 0.5GByte for now,
+ * so we can access on-board i/o areas.
+ * Supervisor only access, so transparent mapping doesn't
+ * clash with User code virtual address space.
*/
- movel #0xe01f0000,%d2 /* logical address base */
- orw #0xa040,%d2 /* add in magic bits */
- .long 0x4e7b2005 /* movec d2,ittr1 */
- .long 0x4e7b2007 /* movec d2,dttr1 */
- .long 0x4e7b2004 /* movec d2,ittr0 */
- .long 0x4e7b2006 /* movec d2,dttr0 */
+ mmu_map_tt 1,#0xe0000000,#0x20000000,#_PAGE_NOCACHE_S
-Lnotbvm:
-#endif
+ jbra L(mmu_init_done)
+
+L(not6000):
+#endif /* CONFIG_BVME6000 */
/*
- * Setup a transparent mapping of the physical memory we are executing in.
+ * mmu_init_mac
+ *
+ * The Macintosh mappings are less clear.
*
- * Only do this if the physical memory is not in the first 16M Meg, or not on
- * an Amiga since the first 16M is already identity mapped on the Amiga.
+ * Even as of this writing, it is unclear how the
+ * Macintosh mappings will be done. However, as
+ * the first author of this code I'm proposing the
+ * following model:
+ *
+ * Map the kernel (that's already done),
+ * Map the I/O (on most machines that's the
+ * 0x5000.0000 ... 0x5200.0000 range,
+ * Map the video frame buffer using as few pages
+ * as absolutely (this requirement mostly stems from
+ * the fact that when the frame buffer is at
+ * 0x0000.0000 then we know there is valid RAM just
+ * above the screen that we don't want to waste!).
+ *
+ * By the way, if the frame buffer is at 0x0000.0000
+ * then the Macintosh is known as an RBV based Mac.
+ *
+ * By the way 2, the code currently maps in a bunch of
+ * regions. But I'd like to cut that out. (And move most
+ * of the mappings up into the kernel proper ... or only
+ * map what's necessary.)
*/
-Lmapphys:
- putc('J')
- leds(0x8)
-#ifdef CONFIG_AMIGA
- is_not_amiga(Lmapphysnotamiga)
+#ifdef CONFIG_MAC
-/*
- * The virtual address of the start of the kernel is 0x1000. We transparently
- * translate the memory where we running in and can enable then the MMU. Hence
- * we have now two locations of the kernel in memory and can jump to the final
- * place. Except if the physical location is in the first 16MB, translation
- * will overlap later virtual location, but as we already mapped the first
- * 16MB to 0x80000000, we can jump there after translation and MMU is enabled
- * and then we can switch off translation and go to the final place.
- * On 020/030 we must emulate transparant translation, since 020 doesn't know
- * it, but due to early termination pointer this is easy to do.
- * When MMU is enabled, stack pointer and Lcustom will become again valid and
- * stack points to the unused first page.
- */
+L(mmu_init_mac):
-/*
- * Setup Supervisor Root Pointer register to point to page directory,
- * setup translation register contents and enable translation.
- */
- putc('K')
+ is_not_mac(L(mmu_init_not_mac))
- movew #PAGESIZE,%sp
+ putc 'F'
- /* fixup the Amiga custom register location before printing */
- lea %pc@(Lcustom),%a0
- movel #0x80000000,%a0@
+ lea %pc@(L(mac_videobase)),%a0
+ lea %pc@(L(console_video_virtual)),%a1
+ movel %a0@,%a1@
- is_040_or_060(Lamimmu68040)
+ is_not_040_or_060(1f)
- moveq #ROOT_INDEX_SHIFT,%d2
- movel %d5,%d0
- lsrl %d2,%d0
- movel %d0,%d1
- lsll %d2,%d1
- orw #_PAGE_PRESENT+_PAGE_ACCESSED,%d1
- lsll #2,%d0
- movel %a5@(%d0:w),%d2
- movel %d1,%a5@(%d0:w)
- lea %pc@(Lmmu),%a3
- /* no limit, 4byte descriptors */
- movel #0x80000002,%a3@
- movel %a5,%a3@(4)
- pmove %a3@,%srp
- pmove %a3@,%crp
- pflusha
+ moveq #_PAGE_NOCACHE_S,%d3
+ jbra 2f
+1:
+ moveq #_PAGE_NOCACHE030,%d3
+2:
/*
- * enable,super root enable,4096 byte pages,7 bit root index,
- * 7 bit pointer index, 6 bit page table index.
+ * Mac Note: screen address of logical 0xF000.0000 -> <screen physical>
+ * we simply map the 4MB that contains the videomem
*/
- movel #0x82c07760,%a3@
- pmove %a3@,%tc /* enable the MMU */
- tstl %d0
- jne 1f
- jmp %pc@(2f+0x80000000)
-1: jmp 2f:w
-2: movel %d2,%a5@(%d0:w)
- pflusha
- jmp LdoneMMUenable:w
-Lamimmu68040:
+ movel #VIDEOMEMMASK,%d0
+ andl L(mac_videobase),%d0
- .chip 68040
- lea 2f:w,%a0
- movel %d5,%d0
- andl #0xff000000,%d0
- jne 1f
- lea %pc@(2f+0x80000000),%a0
-1: orw #TTR_ENABLE+TTR_KERNELMODE+_PAGE_NOCACHE_S,%d0
- movec %d0,%itt0
- movec %a5,%urp
- movec %a5,%srp
- pflusha
- movel #TC_ENABLE+TC_PAGE4K,%d0
- /*
- * this value is also ok for the 68060, we don`t use the cache
- * mode/protection defaults
- */
- movec %d0,%tc /* enable the MMU */
- jmp %a0@
-2: moveq #0,%d0
- movec %d0,%itt0
- jmp LdoneMMUenable:w
- .chip 68k
+ mmu_map #VIDEOMEMBASE,%d0,#VIDEOMEMSIZE,%d3
+ mmu_map_eq #0x40800000,#0x02000000,%d3 /* rom ? */
+ mmu_map_eq #0x50000000,#0x02000000,%d3
+ mmu_map_eq #0x60000000,#0x00400000,%d3
+ mmu_map_eq #0x9c000000,#0x00400000,%d3
+ mmu_map_tt 1,#0xf8000000,#0x08000000,%d3
-Lmapphysnotamiga:
+ jbra L(mmu_init_done)
+
+L(mmu_init_not_mac):
#endif
-#ifdef CONFIG_ATARI
- is_not_atari(Lmapphysnotatari)
+L(mmu_init_done):
+
+ putc 'G'
+ leds 0x8
/*
- * If the kernel physical address is different from its virtual address, we
- * will temporarily set up an identity mapping of the 16MB chunk with
- * transparent translation where the kernel is executing.
+ * mmu_fixup
+ *
+ * On the 040 class machines, all pages that are used for the
+ * mmu have to be fixed up. According to Motorola, pages holding mmu
+ * tables should be non-cacheable on a '040 and write-through on a
+ * '060. But analysis of the reasons for this, and practical
+ * experience, showed that write-through also works on a '040.
+ *
+ * Allocated memory so far goes from kernel_end to memory_start that
+ * is used for all kind of tables, for that the cache attributes
+ * are now fixed.
*/
- putc('L')
-
- /* fixup the Atari iobase register location before printing */
- lea %pc@(Liobase),%a0
- movel #0xff000000,%a0@
+L(mmu_fixup):
- is_040_or_060(Latarimmu68040)
+ is_not_040_or_060(L(mmu_fixup_done))
- .chip 68030
- lea %pc@(Lmmu),%a3
- movel %d5,%d0
- jne 1f
- lea LdoneMMUenable:w,%a0
- jra 3f
-1: lea 4f:w,%a0
- andl #0xff000000,%d0 /* logical address base */
- jeq 2f
- orw #TTR_ENABLE+TTR_CI+TTR_RWM+TTR_FCB2+TTR_FCM1+TTR_FCM0,%d0
- movel %d0,%a3@
- pmove %a3@,%tt0
- jra 3f
- /* tt0 doesn't work if physical and virtual address of kernel is in
- * the same 16M area (Falcon with Magnum/FX, kernel in alternate ram)
- * Transparent translation through kernel pointer table
- * Requires that this code until after MMU enabling lies in
- * the 256K page around %d5
- */
-2: movel %a5@,%d1
- andw #0xfff0,%d1
- movel %d1,%a1
- movel %d5,%d1
- moveq #PTR_INDEX_SHIFT,%d0
- lsrl %d0,%d1
- lea %a1@(%d1:l:4),%a1
- movel %d5,%d1
- orw #_PAGE_PRESENT+_PAGE_ACCESSED,%d1
- movel %a1@,%d2
- movel %d1,%a1@
- lea 5f:w,%a0
- /* no limit, 4byte descriptors */
-3: movel #0x80000002,%a3@
- movel %a5,%a3@(4)
- pmove %a3@,%srp
- pmove %a3@,%crp
- pflusha
- /*
- * enable,super root enable,4096 byte pages,7 bit root index,
- * 7 bit pointer index, 6 bit page table index.
- */
- movel #0x82c07760,%a3@
- pmove %a3@,%tc /* enable the MMU */
- jmp %a0@
-4: clrl %a3@
- pmove %a3@,%tt0
- jra LdoneMMUenable
-5: movel %d2,%a1@
- jra LdoneMMUenable
- .chip 68k
-
-Latarimmu68040:
- .chip 68040
- movel %d5,%d0
- jne 1f
- lea LdoneMMUenable:w,%a0
- jra 2f
-1: lea 3f:w,%a0
- andl #0xff000000,%d0 /* logical address base */
- orw #TTR_ENABLE+TTR_KERNELMODE+_PAGE_NOCACHE_S,%d0
- movec %d0,%itt0
-2: nop
- pflusha
- movec %a5,%srp
- movec %a5,%urp
- movel #TC_ENABLE+TC_PAGE4K,%d0
- /*
- * this value is also ok for the 68060, we don`t use the cache
- * mode/protection defaults
- */
- movec %d0,%tc /* enable the MMU */
- jmp %a0@
-3: moveq #0,%d0
- movec %d0,%itt0
- jra LdoneMMUenable
- .chip 68k
-
-Lmapphysnotatari:
+#ifdef MMU_NOCACHE_KERNEL
+ jbra L(mmu_fixup_done)
#endif
-#if defined(CONFIG_MVME16x)
- is_not_mvme16x(Lmapphysnot16x)
- /*
- * save physaddr of phys mem in register a3
+ /* first fix the page at the start of the kernel, that
+ * contains also kernel_pg_dir.
*/
- moveq #'L',%d7
- jbsr Lserial_putc
-
- .word 0xf4d8 /* CINVA I/D */
- .word 0xf518 /* pflusha */
- .long 0x4e7bd807 /* movec a5,srp */
- .long 0x4e7bd806 /* movec a5,urp */
- movel #(TC_ENABLE+TC_PAGE4K),%d0
- .long 0x4e7b0003 /* movec d0,tc (enable the MMU) */
- jra LdoneMMUenable /* branch to continuation of startup */
+ movel %pc@(L(phys_kernel_start)),%d0
+ lea %pc@(SYMBOL_NAME(_stext)),%a0
+ subl %d0,%a0
+ mmu_fixup_page_mmu_cache %a0
+
+ movel %pc@(L(kernel_end)),%a0
+ subl %d0,%a0
+ movel %pc@(L(memory_start)),%a1
+ subl %d0,%a1
+ bra 2f
+1:
+ mmu_fixup_page_mmu_cache %a0
+ addw #PAGESIZE,%a0
+2:
+ cmpl %a0,%a1
+ jgt 1b
-Lmapphysnot16x:
+L(mmu_fixup_done):
+#ifdef MMU_PRINT
+ mmu_print
#endif
-#if defined(CONFIG_HP300)
- is_not_hp300(Lmapphysnothp300)
-
/*
- * Physical RAM is at 0xff000000. We want to map the kernel at 0x00000000.
- * In order to avoid disaster when we enable the MMU we need to make a
- * transparent mapping of the RAM we're executing out of as well.
+ * mmu_engage
+ *
+ * This chunk of code performs the gruesome task of engaging the MMU.
+ * The reason its gruesome is because when the MMU becomes engaged it
+ * maps logical addresses to physical addresses. The Program Counter
+ * register is then passed through the MMU before the next instruction
+ * is fetched (the instruction following the engage MMU instruction).
+ * This may mean one of two things:
+ * 1. The Program Counter falls within the logical address space of
+ * the kernel of which there are two sub-possibilities:
+ * A. The PC maps to the correct instruction (logical PC == physical
+ * code location), or
+ * B. The PC does not map through and the processor will read some
+ * data (or instruction) which is not the logically next instr.
+ * As you can imagine, A is good and B is bad.
+ * Alternatively,
+ * 2. The Program Counter does not map through the MMU. The processor
+ * will take a Bus Error.
+ * Clearly, 2 is bad.
+ * It doesn't take a wiz kid to figure you want 1.A.
+ * This code creates that possibility.
+ * There are two possible 1.A. states (we now ignore the other above states):
+ * A. The kernel is located at physical memory addressed the same as
+ * the logical memory for the kernel, i.e., 0x01000.
+ * B. The kernel is located some where else. e.g., 0x0400.0000
+ *
+ * Under some conditions the Macintosh can look like A or B.
+ * [A friend and I once noted that Apple hardware engineers should be
+ * wacked twice each day: once when they show up at work (as in, Whack!,
+ * "This is for the screwy hardware we know you're going to design today."),
+ * and also at the end of the day (as in, Whack! "I don't know what
+ * you designed today, but I'm sure it wasn't good."). -- rst]
+ *
+ * This code works on the following premise:
+ * If the kernel start (%d5) is within the first 16 Meg of RAM,
+ * then create a mapping for the kernel at logical 0x8000.0000 to
+ * the physical location of the pc. And, create a transparent
+ * translation register for the first 16 Meg. Then, after the MMU
+ * is engaged, the PC can be moved up into the 0x8000.0000 range
+ * and then the transparent translation can be turned off and then
+ * the PC can jump to the correct logical location and it will be
+ * home (finally). This is essentially the code that the Amiga used
+ * to use. Now, it's generalized for all processors. Which means
+ * that a fresh (but temporary) mapping has to be created. The mapping
+ * is made in page 0 (an as of yet unused location -- except for the
+ * stack!). This temporary mapping will only require 1 pointer table
+ * and a single page table (it can map 256K).
+ *
+ * OK, alternatively, imagine that the Program Counter is not within
+ * the first 16 Meg. Then, just use Transparent Translation registers
+ * to do the right thing.
+ *
+ * Last, if _start is already at 0x01000, then there's nothing special
+ * to do (in other words, in a degenerate case of the first case above,
+ * do nothing).
+ *
+ * Let's do it.
+ *
+ *
*/
- /*
- * save physaddr of phys mem in register a3
- */
- .chip 68030
- lea %pc@(Lmmu),%a3
- movel %d5,%d0
- andl #0xff000000,%d0 /* logical address base */
- orw #TTR_ENABLE+TTR_CI+TTR_RWM+TTR_FCB2+TTR_FCM1+TTR_FCM0,%d0
- movel %d0,%a3@
- pmove %a3@,%tt0
- /* no limit, 4byte descriptors */
- movel #0x80000002,%a3@
- movel %a5,%a3@(4)
- pmove %a3@,%srp
- pmove %a3@,%crp
- pflusha
- /*
- * enable,super root enable,4096 byte pages,7 bit root index,
- * 7 bit pointer index, 6 bit page table index.
- */
- movel #0x82c07760,%a3@
- pmove %a3@,%tc /* enable the MMU */
- jmp 1f
-1:
- .chip 68k
+ putc 'H'
- /*
- * Fix up the custom register to point to the new location of the LEDs.
- */
- lea %pc@(Lcustom),%a1
- movel #0xf0000000,%a1@
+ mmu_engage
- /*
- * Energise the FPU and caches.
- */
- orl #0x64, 0xf05f400c
-
-Lmapphysnothp300:
+#ifdef CONFIG_AMIGA
+ is_not_amiga(1f)
+ /* fixup the Amiga custom register location before printing */
+ clrl L(custom)
+1:
+#endif
+
+#ifdef CONFIG_ATARI
+ is_not_atari(1f)
+ /* fixup the Atari iobase register location before printing */
+ movel #0xff000000,L(iobase)
+1:
+#endif
+#ifdef CONFIG_MAC
+ is_not_mac(1f)
+ movel #~VIDEOMEMMASK,%d0
+ andl L(mac_videobase),%d0
+ addl #VIDEOMEMBASE,%d0
+ movel %d0,L(mac_videobase)
+1:
#endif
-#if defined(CONFIG_BVME6000)
- is_not_bvme6000(Lmapphysnotbvm)
+#ifdef CONFIG_HP300
+ is_not_hp300(1f)
/*
- * save physaddr of phys mem in register a3
+ * Fix up the custom register to point to the new location of the LEDs.
*/
- moveq #'L',%d7
- jbsr Lserial_putc
+ movel #0xf0000000,L(custom)
- .word 0xf4d8 /* CINVA I/D */
- .word 0xf518 /* pflusha */
- .long 0x4e7bd807 /* movec a5,srp */
- .long 0x4e7bd806 /* movec a5,urp */
- movel #(TC_ENABLE+TC_PAGE4K),%d0
/*
- * this value is also ok for the 68060, we don`t use the cache
- * mode/protection defaults
+ * Energise the FPU and caches.
*/
- .long 0x4e7b0003 /* movec d0,tc (enable the MMU) */
- jra LdoneMMUenable /* branch to continuation of startup */
-
-Lmapphysnotbvm:
-
+ movel #0x60,0xf05f400c
+1:
#endif
-LdoneMMUenable:
-
/*
* Fixup the addresses for the kernel pointer table and availmem.
* Convert them from physical addresses to virtual addresses.
*/
- putc('M')
- leds(0x10)
-
- /*
- * d5 contains physaddr of kernel start
- */
- subl %d5,SYMBOL_NAME(kpt)
+ putc 'I'
+ leds 0x10
- /*
- * do the same conversion on the first available memory
+ /* do the same conversion on the first available memory
* address (in a6).
*/
- subl %d5,%a6
- movel %a6,SYMBOL_NAME(availmem) /* first available memory address */
-
- putc('N')
+ movel L(memory_start),%d0
+ movel %d0,SYMBOL_NAME(availmem)
/*
* Enable caches
*/
- is_040_or_060(Lcache680460)
- movel #CC3_ENABLE_DB+CC3_CLR_D+CC3_ENABLE_D+CC3_ENABLE_IB+CC3_CLR_I+CC3_ENABLE_I,%d0
- movec %d0,%cacr
- jra 1f
+ is_not_040_or_060(L(cache_not_680460))
-Lcache680460:
+L(cache680460):
.chip 68040
+ nop
cpusha %bc
- .chip 68k
+ nop
- is_060(Lcache68060)
+ is_060(L(cache68060))
movel #CC6_ENABLE_D+CC6_ENABLE_I,%d0
/* MMU stuff works in copyback mode now, so enable the cache */
movec %d0,%cacr
- jra 1f
+ jra L(cache_done)
-Lcache68060:
- .chip 68060
+L(cache68060):
movel #CC6_ENABLE_D+CC6_ENABLE_I+CC6_ENABLE_SB+CC6_PUSH_DPI+CC6_ENABLE_B+CC6_CLRA_B,%d0
/* MMU stuff works in copyback mode now, so enable the cache */
movec %d0,%cacr
/* enable superscalar dispatch in PCR */
moveq #1,%d0
+ .chip 68060
movec %d0,%pcr
+
+ jbra L(cache_done)
+L(cache_not_680460):
+L(cache68030):
+ .chip 68030
+ movel #CC3_ENABLE_DB+CC3_CLR_D+CC3_ENABLE_D+CC3_ENABLE_IB+CC3_CLR_I+CC3_ENABLE_I,%d0
+ movec %d0,%cacr
+
+ jra L(cache_done)
.chip 68k
-1:
+L(cache_done):
+
+ putc 'J'
/*
* Setup initial stack pointer
- * We need to get current loaded up with our first task...
*/
lea SYMBOL_NAME(init_task_union),%a2
- lea 8192(%a2),%sp
+ lea 0x2000(%a2),%sp
/* jump to the kernel start */
- putr()
- leds(0x55)
+ putc '\n'
+ leds 0x55
- subl %a6,%a6 /* clear a6 for gdb */
+ subl %a6,%a6 /* clear a6 for gdb */
jbsr SYMBOL_NAME(start_kernel)
/*
@@ -1090,33 +1288,1260 @@ Lcache68060:
* Returns: d0: size (-1 if not found)
* a0: data pointer (end-of-records if not found)
*/
-Lget_bi_record:
+func_start get_bi_record,%d1
+
+ movel ARG1,%d0
lea %pc@(SYMBOL_NAME(_end)),%a0
-1: tstw %a0@(BIR_tag)
+1: tstw %a0@(BIR_TAG)
jeq 3f
- cmpw %a0@(BIR_tag),%d0
+ cmpw %a0@(BIR_TAG),%d0
jeq 2f
- addw %a0@(BIR_size),%a0
+ addw %a0@(BIR_SIZE),%a0
jra 1b
2: moveq #0,%d0
- movew %a0@(BIR_size),%d0
- lea %a0@(BIR_data),%a0
- rts
+ movew %a0@(BIR_SIZE),%d0
+ lea %a0@(BIR_DATA),%a0
+ jra 4f
3: moveq #-1,%d0
- lea %a0@(BIR_size),%a0
+ lea %a0@(BIR_SIZE),%a0
+4:
+func_return get_bi_record
+
+
+/*
+ * MMU Initialization Begins Here
+ *
+ * The structure of the MMU tables on the 68k machines
+ * is thus:
+ * Root Table
+ * Logical addresses are translated through
+ * a hierarchical translation mechanism where the high-order
+ * seven bits of the logical address (LA) are used as an
+ * index into the "root table." Each entry in the root
+ * table has a bit which specifies if it's a valid pointer to a
+ * pointer table. Each entry defines a 32KMeg range of memory.
+ * If an entry is invalid then that logical range of 32M is
+ * invalid and references to that range of memory (when the MMU
+ * is enabled) will fault. If the entry is valid, then it does
+ * one of two things. On 040/060 class machines, it points to
+ * a pointer table which then describes more finely the memory
+ * within that 32M range. On 020/030 class machines, a technique
+ * called "early terminating descriptors" are used. This technique
+ * allows an entire 32Meg to be described by a single entry in the
+ * root table. Thus, this entry in the root table, contains the
+ * physical address of the memory or I/O at the logical address
+ * which the entry represents and it also contains the necessary
+ * cache bits for this region.
+ *
+ * Pointer Tables
+ * Per the Root Table, there will be one or more
+ * pointer tables. Each pointer table defines a 32M range.
+ * Not all of the 32M range need be defined. Again, the next
+ * seven bits of the logical address are used an index into
+ * the pointer table to point to page tables (if the pointer
+ * is valid). There will undoubtedly be more than one
+ * pointer table for the kernel because each pointer table
+ * defines a range of only 32M. Valid pointer table entries
+ * point to page tables, or are early terminating entries
+ * themselves.
+ *
+ * Page Tables
+ * Per the Pointer Tables, each page table entry points
+ * to the physical page in memory that supports the logical
+ * address that translates to the particular index.
+ *
+ * In short, the Logical Address gets translated as follows:
+ * bits 31..26 - index into the Root Table
+ * bits 25..18 - index into the Pointer Table
+ * bits 17..12 - index into the Page Table
+ * bits 11..0 - offset into a particular 4K page
+ *
+ * The algorithms which follows do one thing: they abstract
+ * the MMU hardware. For example, there are three kinds of
+ * cache settings that are relevant. Either, memory is
+ * being mapped in which case it is either Kernel Code (or
+ * the RamDisk) or it is MMU data. On the 030, the MMU data
+ * option also describes the kernel. Or, I/O is being mapped
+ * in which case it has its own kind of cache bits. There
+ * are constants which abstract these notions from the code that
+ * actually makes the call to map some range of memory.
+ *
+ *
+ *
+ */
+
+#ifdef MMU_PRINT
+/*
+ * mmu_print
+ *
+ * This algorithm will print out the current MMU mappings.
+ *
+ * Input:
+ * %a5 points to the root table. Everything else is calculated
+ * from this.
+ */
+
+#define mmu_next_valid 0
+#define mmu_start_logical 4
+#define mmu_next_logical 8
+#define mmu_start_physical 12
+#define mmu_next_physical 16
+
+#define MMU_PRINT_INVALID -1
+#define MMU_PRINT_VALID 1
+#define MMU_PRINT_UNINITED 0
+
+#define putZc(z,n) jbne 1f; putc z; jbra 2f; 1: putc n; 2:
+
+func_start mmu_print,%a0-%a6/%d0-%d7
+
+ movel %pc@(L(kernel_pgdir_ptr)),%a5
+ lea %pc@(L(mmu_print_data)),%a0
+ movel #MMU_PRINT_UNINITED,%a0@(mmu_next_valid)
+
+ is_not_040_or_060(mmu_030_print)
+
+mmu_040_print:
+ puts "\nMMU040\n"
+ puts "rp:"
+ putn %a5
+ putc '\n'
+#if 0
+ /*
+ * The following #if/#endif block is a tight algorithm for dumping the 040
+ * MMU Map in gory detail. It really isn't that practical unless the
+ * MMU Map algorithm appears to go awry and you need to debug it at the
+ * entry per entry level.
+ */
+ movel #ROOT_TABLE_SIZE,%d5
+#if 0
+ movel %a5@+,%d7 | Burn an entry to skip the kernel mappings,
+ subql #1,%d5 | they (might) work
+#endif
+1: tstl %d5
+ jbeq mmu_print_done
+ subq #1,%d5
+ movel %a5@+,%d7
+ btst #1,%d7
+ jbeq 1b
+
+2: putn %d7
+ andil #0xFFFFFE00,%d7
+ movel %d7,%a4
+ movel #PTR_TABLE_SIZE,%d4
+ putc ' '
+3: tstl %d4
+ jbeq 11f
+ subq #1,%d4
+ movel %a4@+,%d7
+ btst #1,%d7
+ jbeq 3b
+
+4: putn %d7
+ andil #0xFFFFFF00,%d7
+ movel %d7,%a3
+ movel #PAGE_TABLE_SIZE,%d3
+5: movel #8,%d2
+6: tstl %d3
+ jbeq 31f
+ subq #1,%d3
+ movel %a3@+,%d6
+ btst #0,%d6
+ jbeq 6b
+7: tstl %d2
+ jbeq 8f
+ subq #1,%d2
+ putc ' '
+ jbra 91f
+8: putc '\n'
+ movel #8+1+8+1+1,%d2
+9: putc ' '
+ dbra %d2,9b
+ movel #7,%d2
+91: putn %d6
+ jbra 6b
+
+31: putc '\n'
+ movel #8+1,%d2
+32: putc ' '
+ dbra %d2,32b
+ jbra 3b
+
+11: putc '\n'
+ jbra 1b
+#endif /* MMU 040 Dumping code that's gory and detailed */
+
+ lea %pc@(SYMBOL_NAME(kernel_pg_dir)),%a5
+ movel %a5,%a0 /* a0 has the address of the root table ptr */
+ movel #0x00000000,%a4 /* logical address */
+ moveql #0,%d0
+40:
+ /* Increment the logical address and preserve in d5 */
+ movel %a4,%d5
+ addil #PAGESIZE<<13,%d5
+ movel %a0@+,%d6
+ btst #1,%d6
+ jbne 41f
+ jbsr mmu_print_tuple_invalidate
+ jbra 48f
+41:
+ movel #0,%d1
+ andil #0xfffffe00,%d6
+ movel %d6,%a1
+42:
+ movel %a4,%d5
+ addil #PAGESIZE<<6,%d5
+ movel %a1@+,%d6
+ btst #1,%d6
+ jbne 43f
+ jbsr mmu_print_tuple_invalidate
+ jbra 47f
+43:
+ movel #0,%d2
+ andil #0xffffff00,%d6
+ movel %d6,%a2
+44:
+ movel %a4,%d5
+ addil #PAGESIZE,%d5
+ movel %a2@+,%d6
+ btst #0,%d6
+ jbne 45f
+ jbsr mmu_print_tuple_invalidate
+ jbra 46f
+45:
+ moveml %d0-%d1,%sp@-
+ movel %a4,%d0
+ movel %d6,%d1
+ andil #0xfffff4e0,%d1
+ lea %pc@(mmu_040_print_flags),%a6
+ jbsr mmu_print_tuple
+ moveml %sp@+,%d0-%d1
+46:
+ movel %d5,%a4
+ addq #1,%d2
+ cmpib #64,%d2
+ jbne 44b
+47:
+ movel %d5,%a4
+ addq #1,%d1
+ cmpib #128,%d1
+ jbne 42b
+48:
+ movel %d5,%a4 /* move to the next logical address */
+ addq #1,%d0
+ cmpib #128,%d0
+ jbne 40b
+
+ .chip 68040
+ movec %dtt1,%d0
+ movel %d0,%d1
+ andiw #0x8000,%d1 /* is it valid ? */
+ jbeq 1f /* No, bail out */
+
+ movel %d0,%d1
+ andil #0xff000000,%d1 /* Get the address */
+ putn %d1
+ puts "=="
+ putn %d1
+
+ movel %d0,%d6
+ jbsr mmu_040_print_flags_tt
+1:
+ movec %dtt0,%d0
+ movel %d0,%d1
+ andiw #0x8000,%d1 /* is it valid ? */
+ jbeq 1f /* No, bail out */
+
+ movel %d0,%d1
+ andil #0xff000000,%d1 /* Get the address */
+ putn %d1
+ puts "=="
+ putn %d1
+
+ movel %d0,%d6
+ jbsr mmu_040_print_flags_tt
+1:
+ .chip 68k
+
+ jbra mmu_print_done
+
+mmu_040_print_flags:
+ btstl #10,%d6
+ putZc(' ','G') /* global bit */
+ btstl #7,%d6
+ putZc(' ','S') /* supervisor bit */
+mmu_040_print_flags_tt:
+ btstl #6,%d6
+ jbne 3f
+ putc 'C'
+ btstl #5,%d6
+ putZc('w','c') /* write through or copy-back */
+ jbra 4f
+3:
+ putc 'N'
+ btstl #5,%d6
+ putZc('s',' ') /* serialized non-cacheable, or non-cacheable */
+4:
+ rts
+
+mmu_030_print_flags:
+ btstl #6,%d6
+ putZc('C','I') /* write through or copy-back */
+ rts
+
+mmu_030_print:
+ puts "\nMMU030\n"
+ puts "\nrp:"
+ putn %a5
+ putc '\n'
+ movel %a5,%d0
+ andil #0xfffffff0,%d0
+ movel %d0,%a0
+ movel #0x00000000,%a4 /* logical address */
+ movel #0,%d0
+30:
+ movel %a4,%d5
+ addil #PAGESIZE<<13,%d5
+ movel %a0@+,%d6
+ btst #1,%d6 /* is it a ptr? */
+ jbne 31f /* yes */
+ btst #0,%d6 /* is it early terminating? */
+ jbeq 1f /* no */
+ jbsr mmu_030_print_helper
+ jbra 38f
+1:
+ jbsr mmu_print_tuple_invalidate
+ jbra 38f
+31:
+ movel #0,%d1
+ andil #0xfffffff0,%d6
+ movel %d6,%a1
+32:
+ movel %a4,%d5
+ addil #PAGESIZE<<6,%d5
+ movel %a1@+,%d6
+ btst #1,%d6
+ jbne 33f
+ btst #0,%d6
+ jbeq 1f /* no */
+ jbsr mmu_030_print_helper
+ jbra 37f
+1:
+ jbsr mmu_print_tuple_invalidate
+ jbra 37f
+33:
+ movel #0,%d2
+ andil #0xfffffff0,%d6
+ movel %d6,%a2
+34:
+ movel %a4,%d5
+ addil #PAGESIZE,%d5
+ movel %a2@+,%d6
+ btst #0,%d6
+ jbne 35f
+ jbsr mmu_print_tuple_invalidate
+ jbra 36f
+35:
+ jbsr mmu_030_print_helper
+36:
+ movel %d5,%a4
+ addq #1,%d2
+ cmpib #64,%d2
+ jbne 34b
+37:
+ movel %d5,%a4
+ addq #1,%d1
+ cmpib #128,%d1
+ jbne 32b
+38:
+ movel %d5,%a4 /* move to the next logical address */
+ addq #1,%d0
+ cmpib #128,%d0
+ jbne 30b
+
+mmu_print_done:
+ puts "\n\n"
+
+func_return mmu_print
+
+
+mmu_030_print_helper:
+ moveml %d0-%d1,%sp@-
+ movel %a4,%d0
+ movel %d6,%d1
+ lea %pc@(mmu_030_print_flags),%a6
+ jbsr mmu_print_tuple
+ moveml %sp@+,%d0-%d1
+ rts
+
+mmu_print_tuple_invalidate:
+ moveml %a0/%d7,%sp@-
+
+ lea %pc@(L(mmu_print_data)),%a0
+ tstl %a0@(mmu_next_valid)
+ jbmi mmu_print_tuple_invalidate_exit
+
+ movel #MMU_PRINT_INVALID,%a0@(mmu_next_valid)
+
+ putn %a4
+
+ puts "##\n"
+
+mmu_print_tuple_invalidate_exit:
+ moveml %sp@+,%a0/%d7
+ rts
+
+
+mmu_print_tuple:
+ moveml %d0-%d7/%a0,%sp@-
+
+ lea %pc@(L(mmu_print_data)),%a0
+
+ tstl %a0@(mmu_next_valid)
+ jble mmu_print_tuple_print
+
+ cmpl %a0@(mmu_next_physical),%d1
+ jbeq mmu_print_tuple_increment
+
+mmu_print_tuple_print:
+ putn %d0
+ puts "->"
+ putn %d1
+
+ movel %d1,%d6
+ jbsr %a6@
+
+mmu_print_tuple_record:
+ movel #MMU_PRINT_VALID,%a0@(mmu_next_valid)
+
+ movel %d1,%a0@(mmu_next_physical)
+
+mmu_print_tuple_increment:
+ movel %d5,%d7
+ subl %a4,%d7
+ addl %d7,%a0@(mmu_next_physical)
+
+mmu_print_tuple_exit:
+ moveml %sp@+,%d0-%d7/%a0
rts
+mmu_print_machine_cpu_types:
+ puts "machine: "
+
+ is_not_amiga(1f)
+ puts "amiga"
+ jbra 9f
+1:
+ is_not_atari(2f)
+ puts "atari"
+ jbra 9f
+2:
+ is_not_mac(3f)
+ puts "macintosh"
+ jbra 9f
+3: puts "unknown"
+9: putc '\n'
+
+ puts "cputype: 0"
+ is_not_060(1f)
+ putc '6'
+ jbra 9f
+1:
+ is_not_040_or_060(2f)
+ putc '4'
+ jbra 9f
+2: putc '3'
+9: putc '0'
+ putc '\n'
+
+ rts
+#endif /* MMU_PRINT */
+
+/*
+ * mmu_map_tt
+ *
+ * This is a specific function which works on all 680x0 machines.
+ * On 030, 040 & 060 it will attempt to use Transparent Translation
+ * registers (tt1).
+ * On 020 it will call the standard mmu_map which will use early
+ * terminating descriptors.
+ */
+func_start mmu_map_tt,%d0/%d1/%a0,4
+
+ dputs "mmu_map_tt:"
+ dputn ARG1
+ dputn ARG2
+ dputn ARG3
+ dputn ARG4
+ dputc '\n'
+
+ is_020(L(do_map))
+
+ /* Extract the highest bit set
+ */
+ bfffo ARG3{#0,#32},%d1
+ cmpw #8,%d0
+ jcc L(do_map)
+
+ /* And get the mask
+ */
+ moveq #-1,%d0
+ lsrl %d1,%d0
+ lsrl #1,%d0
+
+ /* Mask the address
+ */
+ movel %d0,%d1
+ notl %d1
+ andl ARG2,%d1
+
+ /* Generate the upper 16bit of the tt register
+ */
+ lsrl #8,%d0
+ orl %d0,%d1
+ clrw %d1
+
+ is_040_or_060(L(mmu_map_tt_040))
+
+ /* set 030 specific bits (read/write access for supervisor mode
+ * (highest function code set, lower two bits masked))
+ */
+ orw #TTR_ENABLE+TTR_RWM+TTR_FCB2+TTR_FCM1+TTR_FCM0,%d1
+ movel ARG4,%d0
+ btst #6,%d0
+ jeq 1f
+ orw #TTR_CI,%d1
+
+1: lea STACK,%a0
+ dputn %d1
+ movel %d1,%a0@
+ .chip 68030
+ tstl ARG1
+ jne 1f
+ pmove %a0@,%tt0
+ jra 2f
+1: pmove %a0@,%tt1
+2: .chip 68k
+ jra L(mmu_map_tt_done)
+
+ /* set 040 specific bits
+ */
+L(mmu_map_tt_040):
+ orw #TTR_ENABLE+TTR_KERNELMODE,%d1
+ orl ARG4,%d1
+ dputn %d1
+
+ .chip 68040
+ tstl ARG1
+ jne 1f
+ movec %d1,%itt0
+ movec %d1,%dtt0
+ jra 2f
+1: movec %d1,%itt1
+ movec %d1,%dtt1
+2: .chip 68k
+
+ jra L(mmu_map_tt_done)
+
+L(do_map):
+ mmu_map_eq ARG2,ARG3,ARG4
+
+L(mmu_map_tt_done):
+
+func_return mmu_map_tt
+
+/*
+ * mmu_map
+ *
+ * This routine will map a range of memory using a pointer
+ * table and allocating the pages on the fly from the kernel.
+ * The pointer table does not have to be already linked into
+ * the root table, this routine will do that if necessary.
+ *
+ * NOTE
+ * This routine will assert failure and use the serial_putc
+ * routines in the case of a run-time error. For example,
+ * if the address is already mapped.
+ *
+ * NOTE-2
+ * This routine will use early terminating descriptors
+ * where possible for the 68020+68851 and 68030 type
+ * processors.
+ */
+func_start mmu_map,%d0-%d4/%a0-%a4
+
+ dputs "\nmmu_map:"
+ dputn ARG1
+ dputn ARG2
+ dputn ARG3
+ dputn ARG4
+ dputc '\n'
+
+ /* Get logical address and round it down to 256KB
+ */
+ movel ARG1,%d0
+ andl #-(PAGESIZE*PAGE_TABLE_SIZE),%d0
+ movel %d0,%a3
+
+ /* Get the end address
+ */
+ movel ARG1,%a4
+ addl ARG3,%a4
+ subql #1,%a4
+
+ /* Get physical address and round it down to 256KB
+ */
+ movel ARG2,%d0
+ andl #-(PAGESIZE*PAGE_TABLE_SIZE),%d0
+ movel %d0,%a2
+
+ /* Add page attributes to the physical address
+ */
+ movel ARG4,%d0
+ orw #_PAGE_PRESENT+_PAGE_ACCESSED+_PAGE_DIRTY,%d0
+ addw %d0,%a2
+
+ dputn %a2
+ dputn %a3
+ dputn %a4
+
+ is_not_040_or_060(L(mmu_map_030))
+
+ addw #_PAGE_GLOBAL040,%a2
+/*
+ * MMU 040 & 060 Support
+ *
+ * The MMU usage for the 040 and 060 is different enough from
+ * the 030 and 68851 that there is separate code. This comment
+ * block describes the data structures and algorithms built by
+ * this code.
+ *
+ * The 040 does not support early terminating descriptors, as
+ * the 030 does. Therefore, a third level of table is needed
+ * for the 040, and that would be the page table. In Linux,
+ * page tables are allocated directly from the memory above the
+ * kernel.
+ *
+ */
+
+L(mmu_map_040):
+ /* Calculate the offset into the root table
+ */
+ movel %a3,%d0
+ moveq #ROOT_INDEX_SHIFT,%d1
+ lsrl %d1,%d0
+ mmu_get_root_table_entry %d0
+
+ /* Calculate the offset into the pointer table
+ */
+ movel %a3,%d0
+ moveq #PTR_INDEX_SHIFT,%d1
+ lsrl %d1,%d0
+ andl #PTR_TABLE_SIZE-1,%d0
+ mmu_get_ptr_table_entry %a0,%d0
+
+ /* Calculate the offset into the page table
+ */
+ movel %a3,%d0
+ moveq #PAGE_INDEX_SHIFT,%d1
+ lsrl %d1,%d0
+ andl #PAGE_TABLE_SIZE-1,%d0
+ mmu_get_page_table_entry %a0,%d0
+
+ /* The page table entry must not no be busy
+ */
+ tstl %a0@
+ jne L(mmu_map_error)
+
+ /* Do the mapping and advance the pointers
+ */
+ movel %a2,%a0@
+2:
+ addw #PAGESIZE,%a2
+ addw #PAGESIZE,%a3
+
+ /* Ready with mapping?
+ */
+ lea %a3@(-1),%a0
+ cmpl %a0,%a4
+ jhi L(mmu_map_040)
+ jra L(mmu_map_done)
+
+L(mmu_map_030):
+ /* Calculate the offset into the root table
+ */
+ movel %a3,%d0
+ moveq #ROOT_INDEX_SHIFT,%d1
+ lsrl %d1,%d0
+ mmu_get_root_table_entry %d0
+
+ /* Check if logical address 32MB aligned,
+ * so we can try to map it once
+ */
+ movel %a3,%d0
+ andl #(PTR_TABLE_SIZE*PAGE_TABLE_SIZE*PAGESIZE-1)&(-ROOT_TABLE_SIZE),%d0
+ jne 1f
+
+ /* Is there enough to map for 32MB at once
+ */
+ lea %a3@(PTR_TABLE_SIZE*PAGE_TABLE_SIZE*PAGESIZE-1),%a1
+ cmpl %a1,%a4
+ jcs 1f
+
+ addql #1,%a1
+
+ /* The root table entry must not no be busy
+ */
+ tstl %a0@
+ jne L(mmu_map_error)
+
+ /* Do the mapping and advance the pointers
+ */
+ dputs "early term1"
+ dputn %a2
+ dputn %a3
+ dputn %a1
+ dputc '\n'
+ movel %a2,%a0@
+
+ movel %a1,%a3
+ lea %a2@(PTR_TABLE_SIZE*PAGE_TABLE_SIZE*PAGESIZE),%a2
+ jra L(mmu_mapnext_030)
+1:
+ /* Calculate the offset into the pointer table
+ */
+ movel %a3,%d0
+ moveq #PTR_INDEX_SHIFT,%d1
+ lsrl %d1,%d0
+ andl #PTR_TABLE_SIZE-1,%d0
+ mmu_get_ptr_table_entry %a0,%d0
+
+ /* The pointer table entry must not no be busy
+ */
+ tstl %a0@
+ jne L(mmu_map_error)
+
+ /* Do the mapping and advance the pointers
+ */
+ dputs "early term2"
+ dputn %a2
+ dputn %a3
+ dputc '\n'
+ movel %a2,%a0@
+
+ addl #PAGE_TABLE_SIZE*PAGESIZE,%a2
+ addl #PAGE_TABLE_SIZE*PAGESIZE,%a3
+
+L(mmu_mapnext_030):
+ /* Ready with mapping?
+ */
+ lea %a3@(-1),%a0
+ cmpl %a0,%a4
+ jhi L(mmu_map_030)
+ jra L(mmu_map_done)
+
+L(mmu_map_error):
+
+ dputs "mmu_map error:"
+ dputn %a2
+ dputn %a3
+ dputc '\n'
+
+L(mmu_map_done):
+
+func_return mmu_map
+
+/*
+ * mmu_fixup
+ *
+ * On the 040 class machines, all pages that are used for the
+ * mmu have to be fixed up.
+ */
+
+func_start mmu_fixup_page_mmu_cache,%d0/%a0
+
+ dputs "mmu_fixup_page_mmu_cache"
+ dputn ARG1
+
+ /* Calculate the offset into the root table
+ */
+ movel ARG1,%d0
+ moveq #ROOT_INDEX_SHIFT,%d1
+ lsrl %d1,%d0
+ mmu_get_root_table_entry %d0
+
+ /* Calculate the offset into the pointer table
+ */
+ movel ARG1,%d0
+ moveq #PTR_INDEX_SHIFT,%d1
+ lsrl %d1,%d0
+ andl #PTR_TABLE_SIZE-1,%d0
+ mmu_get_ptr_table_entry %a0,%d0
+
+ /* Calculate the offset into the page table
+ */
+ movel ARG1,%d0
+ moveq #PAGE_INDEX_SHIFT,%d1
+ lsrl %d1,%d0
+ andl #PAGE_TABLE_SIZE-1,%d0
+ mmu_get_page_table_entry %a0,%d0
+
+ movel %a0@,%d0
+ andil #_CACHEMASK040,%d0
+ orl %pc@(SYMBOL_NAME(m68k_pgtable_cachemode)),%d0
+ movel %d0,%a0@
+
+ dputc '\n'
+
+func_return mmu_fixup_page_mmu_cache
+
+/*
+ * mmu_temp_map
+ *
+ * create a temporary mapping to enable the mmu,
+ * this we don't need any transparation translation tricks.
+ */
+
+func_start mmu_temp_map,%d0/%d1/%a0/%a1
+
+ dputs "mmu_temp_map"
+ dputn ARG1
+ dputn ARG2
+ dputc '\n'
+
+ lea %pc@(L(temp_mmap_mem)),%a1
+
+ /* Calculate the offset in the root table
+ */
+ movel ARG2,%d0
+ moveq #ROOT_INDEX_SHIFT,%d1
+ lsrl %d1,%d0
+ mmu_get_root_table_entry %d0
+
+ /* Check if the table is temporary allocated, so we have to reuse it
+ */
+ movel %a0@,%d0
+ cmpl %pc@(L(memory_start)),%d0
+ jcc 1f
+
+ /* Temporary allocate a ptr table and insert it into the root table
+ */
+ movel %a1@,%d0
+ addl #PTR_TABLE_SIZE*4,%a1@
+ orw #_PAGE_TABLE+_PAGE_ACCESSED,%d0
+ movel %d0,%a0@
+ dputs " (new)"
+1:
+ dputn %d0
+ /* Mask the root table entry for the ptr table
+ */
+ andw #-ROOT_TABLE_SIZE,%d0
+ movel %d0,%a0
+
+ /* Calculate the offset into the pointer table
+ */
+ movel ARG2,%d0
+ moveq #PTR_INDEX_SHIFT,%d1
+ lsrl %d1,%d0
+ andl #PTR_TABLE_SIZE-1,%d0
+ lea %a0@(%d0*4),%a0
+ dputn %a0
+
+ /* Check if a temporary page table is already allocated
+ */
+ movel %a0@,%d0
+ jne 1f
+
+ /* Temporary allocate a page table and insert it into the ptr table
+ */
+ movel %a1@,%d0
+ addl #PTR_TABLE_SIZE*4,%a1@
+ orw #_PAGE_TABLE+_PAGE_ACCESSED,%d0
+ movel %d0,%a0@
+ dputs " (new)"
+1:
+ dputn %d0
+ /* Mask the ptr table entry for the page table
+ */
+ andw #-PTR_TABLE_SIZE,%d0
+ movel %d0,%a0
+
+ /* Calculate the offset into the page table
+ */
+ movel ARG2,%d0
+ moveq #PAGE_INDEX_SHIFT,%d1
+ lsrl %d1,%d0
+ andl #PAGE_TABLE_SIZE-1,%d0
+ lea %a0@(%d0*4),%a0
+ dputn %a0
+
+ /* Insert the address into the page table
+ */
+ movel ARG1,%d0
+ andw #-PAGESIZE,%d0
+ orw #_PAGE_PRESENT+_PAGE_ACCESSED+_PAGE_DIRTY,%d0
+ movel %d0,%a0@
+ dputn %d0
+
+ dputc '\n'
+
+func_return mmu_temp_map
+
+func_start mmu_engage,%d0-%d2/%a0-%a3
+
+ moveq #ROOT_TABLE_SIZE-1,%d0
+ /* Temporarily use a different root table. */
+ lea %pc@(L(kernel_pgdir_ptr)),%a0
+ movel %a0@,%a2
+ movel %pc@(L(memory_start)),%a1
+ movel %a1,%a0@
+ movel %a2,%a0
+1:
+ movel %a0@+,%a1@+
+ dbra %d0,1b
+
+ lea %pc@(L(temp_mmap_mem)),%a0
+ movel %a1,%a0@
+
+ movew #PAGESIZE-1,%d0
+1:
+ clrl %a1@+
+ dbra %d0,1b
+
+ lea %pc@(1b),%a0
+ movel #1b,%a1
+ /* Skip temp mappings if phys == virt */
+ cmpl %a0,%a1
+ jeq 1f
+
+ mmu_temp_map %a0,%a0
+ mmu_temp_map %a0,%a1
+
+ addw #PAGESIZE,%a0
+ addw #PAGESIZE,%a1
+ mmu_temp_map %a0,%a0
+ mmu_temp_map %a0,%a1
+1:
+ movel %pc@(L(memory_start)),%a3
+ movel %pc@(L(phys_kernel_start)),%d2
+
+ is_not_040_or_060(L(mmu_engage_030))
+
+L(mmu_engage_040):
+ .chip 68040
+ nop
+ cinva %bc
+ nop
+ pflusha
+ nop
+ movec %a3,%srp
+ movel #TC_ENABLE+TC_PAGE4K,%d0
+ movec %d0,%tc /* enable the MMU */
+ jmp 1f:l
+1: nop
+ movec %a2,%srp
+ nop
+ cinva %bc
+ nop
+ pflusha
+ .chip 68k
+ jra L(mmu_engage_cleanup)
+
+L(mmu_engage_030_temp):
+ .space 12
+L(mmu_engage_030):
+ .chip 68030
+ lea %pc@(L(mmu_engage_030_temp)),%a0
+ movel #0x80000002,%a0@
+ movel %a3,%a0@(4)
+ movel #0x0808,%d0
+ movec %d0,%cacr
+ pmove %a0@,%srp
+ pflusha
+ /*
+ * enable,super root enable,4096 byte pages,7 bit root index,
+ * 7 bit pointer index, 6 bit page table index.
+ */
+ movel #0x82c07760,%a0@(8)
+ pmove %a0@(8),%tc /* enable the MMU */
+ jmp 1f:l
+1: movel %a2,%a0@(4)
+ movel #0x0808,%d0
+ movec %d0,%cacr
+ pmove %a0@,%srp
+ pflusha
+ .chip 68k
+
+L(mmu_engage_cleanup):
+ subl %d2,%a2
+ movel %a2,L(kernel_pgdir_ptr)
+ subl %d2,%fp
+ subl %d2,%sp
+ subl %d2,ARG0
+ subl %d2,L(memory_start)
+
+func_return mmu_engage
+
+func_start mmu_get_root_table_entry,%d0/%a1
+
+#if 0
+ dputs "mmu_get_root_table_entry:"
+ dputn ARG1
+ dputs " ="
+#endif
+
+ movel %pc@(L(kernel_pgdir_ptr)),%a0
+ tstl %a0
+ jne 2f
+
+ dputs "\nmmu_init:"
+
+ /* Find the start of free memory, get_bi_record does this for us,
+ * as the bootinfo structure is located directly behind the kernel
+ * and and we simply search for the last entry.
+ */
+ get_bi_record BI_LAST
+ addw #PAGESIZE-1,%a0
+ movel %a0,%d0
+ andw #-PAGESIZE,%d0
+
+ dputn %d0
+
+ lea %pc@(L(memory_start)),%a0
+ movel %d0,%a0@
+ lea %pc@(L(kernel_end)),%a0
+ movel %d0,%a0@
+
+ /* we have to return the first page at _stext since the init code
+ * in mm/init.c simply expects kernel_pg_dir there, the rest of
+ * page is used for further ptr tables in get_ptr_table.
+ */
+ lea %pc@(SYMBOL_NAME(_stext)),%a0
+ lea %pc@(L(mmu_cached_pointer_tables)),%a1
+ movel %a0,%a1@
+ addl #ROOT_TABLE_SIZE*4,%a1@
+
+ lea %pc@(L(mmu_num_pointer_tables)),%a1
+ addql #1,%a1@
+
+ /* clear the page
+ */
+ movel %a0,%a1
+ movew #PAGESIZE/4-1,%d0
+1:
+ clrl %a1@+
+ dbra %d0,1b
+
+ lea %pc@(L(kernel_pgdir_ptr)),%a1
+ movel %a0,%a1@
+
+ dputn %a0
+ dputc '\n'
+2:
+ movel ARG1,%d0
+ lea %a0@(%d0*4),%a0
+
+#if 0
+ dputn %a0
+ dputc '\n'
+#endif
+
+func_return mmu_get_root_table_entry
+
+
+
+func_start mmu_get_ptr_table_entry,%d0/%a1
+
+#if 0
+ dputs "mmu_get_ptr_table_entry:"
+ dputn ARG1
+ dputn ARG2
+ dputs " ="
+#endif
+
+ movel ARG1,%a0
+ movel %a0@,%d0
+ jne 2f
+
+ /* Keep track of the number of pointer tables we use
+ */
+ dputs "\nmmu_get_new_ptr_table:"
+ lea %pc@(L(mmu_num_pointer_tables)),%a0
+ movel %a0@,%d0
+ addql #1,%a0@
+
+ /* See if there is a free pointer table in our cache of pointer tables
+ */
+ lea %pc@(L(mmu_cached_pointer_tables)),%a1
+ andw #7,%d0
+ jne 1f
+
+ /* Get a new pointer table page from above the kernel memory
+ */
+ get_new_page
+ movel %a0,%a1@
+1:
+ /* There is an unused pointer table in our cache... use it
+ */
+ movel %a1@,%d0
+ addl #PTR_TABLE_SIZE*4,%a1@
+
+ dputn %d0
+ dputc '\n'
+
+ /* Insert the new pointer table into the root table
+ */
+ movel ARG1,%a0
+ orw #_PAGE_TABLE+_PAGE_ACCESSED,%d0
+ movel %d0,%a0@
+2:
+ /* Extract the pointer table entry
+ */
+ andw #-PTR_TABLE_SIZE,%d0
+ movel %d0,%a0
+ movel ARG2,%d0
+ lea %a0@(%d0*4),%a0
+
+#if 0
+ dputn %a0
+ dputc '\n'
+#endif
+
+func_return mmu_get_ptr_table_entry
+
+
+func_start mmu_get_page_table_entry,%d0/%a1
+
+#if 0
+ dputs "mmu_get_page_table_entry:"
+ dputn ARG1
+ dputn ARG2
+ dputs " ="
+#endif
+
+ movel ARG1,%a0
+ movel %a0@,%d0
+ jne 2f
+
+ /* If the page table entry doesn't exist, we allocate a complete new
+ * page and use it as one continues big page table which can cover
+ * 4MB of memory, nearly almost all mappings have that alignment.
+ */
+ get_new_page
+ addw #_PAGE_TABLE+_PAGE_ACCESSED,%a0
+
+ /* align pointer table entry for a page of page tables
+ */
+ movel ARG1,%d0
+ andw #-(PAGESIZE/PAGE_TABLE_SIZE),%d0
+ movel %d0,%a1
+
+ /* Insert the page tables into the pointer entries
+ */
+ moveq #PAGESIZE/PAGE_TABLE_SIZE/4-1,%d0
+1:
+ movel %a0,%a1@+
+ lea %a0@(PAGE_TABLE_SIZE*4),%a0
+ dbra %d0,1b
+
+ /* Now we can get the initialized pointer table entry
+ */
+ movel ARG1,%a0
+ movel %a0@,%d0
+2:
+ /* Extract the page table entry
+ */
+ andw #-PAGE_TABLE_SIZE,%d0
+ movel %d0,%a0
+ movel ARG2,%d0
+ lea %a0@(%d0*4),%a0
+
+#if 0
+ dputn %a0
+ dputc '\n'
+#endif
+
+func_return mmu_get_page_table_entry
+
+/*
+ * get_new_page
+ *
+ * Return a new page from the memory start and clear it.
+ */
+func_start get_new_page,%d0/%a1
+
+ dputs "\nget_new_page:"
+
+ /* allocate the page and adjust memory_start
+ */
+ lea %pc@(L(memory_start)),%a0
+ movel %a0@,%a1
+ addl #PAGESIZE,%a0@
+
+ /* clear the new page
+ */
+ movel %a1,%a0
+ movew #PAGESIZE/4-1,%d0
+1:
+ clrl %a1@+
+ dbra %d0,1b
+
+ dputn %a0
+ dputc '\n'
+
+func_return get_new_page
+
+
+
/*
* Debug output support
* Atarians have a choice between the parallel port, the serial port
* from the MFP or a serial port of the SCC
*/
+#ifdef CONFIG_MAC
+
+L(scc_initable_mac):
+ .byte 9,12 /* Reset */
+ .byte 4,0x44 /* x16, 1 stopbit, no parity */
+ .byte 3,0xc0 /* receiver: 8 bpc */
+ .byte 5,0xe2 /* transmitter: 8 bpc, assert dtr/rts */
+ .byte 9,0 /* no interrupts */
+ .byte 10,0 /* NRZ */
+ .byte 11,0x50 /* use baud rate generator */
+ .byte 12,10,13,0 /* 9600 baud */
+ .byte 14,1 /* Baud rate generator enable */
+ .byte 3,0xc1 /* enable receiver */
+ .byte 5,0xea /* enable transmitter */
+ .byte -1
+ .even
+#endif
+
#ifdef CONFIG_ATARI
/* #define USE_PRINTER */
-/* #define USE_SCC */
+/* #define USE_SCC_B */
+/* #define USE_SCC_A */
#define USE_MFP
+#if defined(USE_SCC_A) || defined(USE_SCC_B)
+#define USE_SCC
+/* Initialisation table for SCC */
+L(scc_initable):
+ .byte 9,12 /* Reset */
+ .byte 4,0x44 /* x16, 1 stopbit, no parity */
+ .byte 3,0xc0 /* receiver: 8 bpc */
+ .byte 5,0xe2 /* transmitter: 8 bpc, assert dtr/rts */
+ .byte 9,0 /* no interrupts */
+ .byte 10,0 /* NRZ */
+ .byte 11,0x50 /* use baud rate generator */
+ .byte 12,24,13,0 /* 9600 baud */
+ .byte 14,2,14,3 /* use master clock for BRG, enable */
+ .byte 3,0xc1 /* enable receiver */
+ .byte 5,0xea /* enable transmitter */
+ .byte -1
+ .even
+#endif
+
#ifdef USE_PRINTER
LPSG_SELECT = 0xff8800
@@ -1129,13 +2554,18 @@ LSTMFP_GPIP = 0xfffa01
LSTMFP_DDR = 0xfffa05
LSTMFP_IERB = 0xfffa09
-#elif defined(USE_SCC)
-
-LSCC_CTRL_B = 0xff8c85
-LSCC_DATA_B = 0xff8c87
+#elif defined(USE_SCC_B)
+
+LSCC_CTRL = 0xff8c85
+LSCC_DATA = 0xff8c87
+
+#elif defined(USE_SCC_A)
+
+LSCC_CTRL = 0xff8c81
+LSCC_DATA = 0xff8c83
/* Initialisation table for SCC */
-scc_initable:
+L(scc_initable):
.byte 9,12 /* Reset */
.byte 4,0x44 /* x16, 1 stopbit, no parity */
.byte 3,0xc0 /* receiver: 8 bpc */
@@ -1159,45 +2589,48 @@ LMFP_TSR = 0xfffa2d
LMFP_UDR = 0xfffa2f
#endif
-#endif
-
-#if defined (CONFIG_BVME6000)
-BVME_SCC_CTRL_A = 0xffb0000b
-BVME_SCC_DATA_A = 0xffb0000f
-#endif
+#endif /* CONFIG_ATARI */
/*
* Serial port output support.
*/
-LSERPER = 0xdff032
-LSERDAT = 0xdff030
-LSERDATR = 0xdff018
-LSERIAL_CNTRL = 0xbfd000
-LSERIAL_DTR = 7
/*
* Initialize serial port hardware for 9600/8/1
- * a0 thrashed
- * Amiga d0 trashed
- * Atari d0 trashed (a1 in case of SCC)
*/
- .even
-Lserial_init:
+func_start serial_init,%d0/%d1/%a0/%a1
+ /*
+ * Some of the register usage that follows
+ * CONFIG_AMIGA
+ * a0 = pointer to boot info record
+ * d0 = boot info offset
+ * CONFIG_ATARI
+ * a0 = address of SCC
+ * a1 = Liobase address/address of scc_initable
+ * d0 = init data for serial port
+ * CONFIG_MAC
+ * a0 = address of SCC
+ * a1 = address of scc_initable_mac
+ * d0 = init data for serial port
+ */
+
#ifdef CONFIG_AMIGA
- cmpil #MACH_AMIGA,%d4
- jne 1f
- bclr #LSERIAL_DTR,LSERIAL_CNTRL
- movew #BI_AMIGA_SERPER,%d0
- jbsr Lget_bi_record
- movew %a0@,LSERPER
- jra 9f
+#define SERIAL_DTR 7
+#define SERIAL_CNTRL CIABBASE+C_PRA
+
+ is_not_amiga(1f)
+ lea %pc@(L(custom)),%a0
+ movel #-ZTWOBASE,%a0@
+ bclr #SERIAL_DTR,SERIAL_CNTRL-ZTWOBASE
+ get_bi_record BI_AMIGA_SERPER
+ movew %a0@,CUSTOMBASE+C_SERPER-ZTWOBASE
+| movew #61,CUSTOMBASE+C_SERPER-ZTWOBASE
1:
#endif
#ifdef CONFIG_ATARI
- cmpil #MACH_ATARI,%d4
- jne 4f
- movel %pc@(Liobase),%a1
-#ifdef USE_PRINTER
+ is_not_atari(4f)
+ movel %pc@(L(iobase)),%a1
+#if defined(USE_PRINTER)
bclr #0,%a1@(LSTMFP_IERB)
bclr #0,%a1@(LSTMFP_DDR)
moveb #LPSG_CONTROL,%a1@(LPSG_SELECT)
@@ -1209,8 +2642,8 @@ Lserial_init:
bset #5,%d0
moveb %d0,%a1@(LPSG_WRITE)
#elif defined(USE_SCC)
- lea %a1@(LSCC_CTRL_B),%a0
- lea %pc@(scc_initable:w),%a1
+ lea %a1@(LSCC_CTRL),%a0
+ lea %pc@(L(scc_initable)),%a1
2: moveb %a1@+,%d0
jmi 3f
moveb %d0,%a0@
@@ -1225,174 +2658,854 @@ Lserial_init:
orb #1,%a1@(LMFP_TDCDR)
bset #1,%a1@(LMFP_TSR)
#endif
+ jra L(serial_init_done)
4:
#endif
-9:
- rts
-
-#ifdef CONFIG_HP300
-/* Set LEDs to %d7 */
- .even
-Lset_leds:
- moveml %a0/%a1,%sp@-
- movel %pc@(Lcustom),%a1
- moveb %d7,%a1@(0x1ffff)
- moveml %sp@+,%a0/%a1
- rts
+#ifdef CONFIG_MAC
+ is_not_mac(L(serial_init_not_mac))
+#ifdef MAC_SERIAL_DEBUG
+#if !defined(MAC_USE_SCC_A) && !defined(MAC_USE_SCC_B)
+#define MAC_USE_SCC_B
#endif
-
+#define mac_scc_cha_b_ctrl_offset 0x0
+#define mac_scc_cha_a_ctrl_offset 0x2
+#define mac_scc_cha_b_data_offset 0x4
+#define mac_scc_cha_a_data_offset 0x6
+
+#ifdef MAC_USE_SCC_A
+ /* Initialize channel A */
+ movel %pc@(L(mac_sccbase)),%a0
+ lea %pc@(L(scc_initable_mac)),%a1
+5: moveb %a1@+,%d0
+ jmi 6f
+ moveb %d0,%a0@(mac_scc_cha_a_ctrl_offset)
+ moveb %a1@+,%a0@(mac_scc_cha_a_ctrl_offset)
+ jra 5b
+6:
+#endif /* MAC_USE_SCC_A */
+
+#ifdef MAC_USE_SCC_B
+ /* Initialize channel B */
+#ifndef MAC_USE_SCC_A /* Load mac_sccbase only if needed */
+ movel %pc@(L(mac_sccbase)),%a0
+#endif /* MAC_USE_SCC_A */
+ lea %pc@(L(scc_initable_mac)),%a1
+7: moveb %a1@+,%d0
+ jmi 8f
+ moveb %d0,%a0@(mac_scc_cha_b_ctrl_offset)
+ moveb %a1@+,%a0@(mac_scc_cha_b_ctrl_offset)
+ jra 7b
+8:
+#endif /* MAC_USE_SCC_B */
+#endif /* MAC_SERIAL_DEBUG */
+
+ jra L(serial_init_done)
+L(serial_init_not_mac):
+#endif /* CONFIG_MAC */
+
+L(serial_init_done):
+func_return serial_init
+
/*
- * Output character in d7 on serial port.
- * d7 thrashed.
+ * Output character on serial port.
*/
-Lserial_putc:
- moveml %a0/%a1,%sp@-
-#if defined(CONFIG_MVME16x)
- cmpil #MACH_MVME16x,%d4
- jne 2f
- moveb %d7,%sp@-
- .long 0x4e4f0020
- jra 9f
-2:
-#endif
-#ifdef CONFIG_BVME6000
- cmpil #MACH_BVME6000,%d4
- jne 2f
-1: btst #2,BVME_SCC_CTRL_A
- jeq 1b
- moveb %d7,BVME_SCC_DATA_A
- jra 9f
-2:
-#endif
+func_start serial_putc,%d0/%d1/%a0/%a1
+
+ movel ARG1,%d0
+ cmpib #'\n',%d0
+ jbne 1f
+
+ /* A little safe recursion is good for the soul */
+ serial_putc #'\r'
+1:
+
#ifdef CONFIG_AMIGA
- cmpil #MACH_AMIGA,%d4
- jne 2f
- andw #0x00ff,%d7
- oriw #0x0100,%d7
- movel %pc@(Lcustom),%a1
- movew %d7,%a1@(LSERDAT)
-1: movew %a1@(LSERDATR),%d7
- andw #0x2000,%d7
+ is_not_amiga(2f)
+ andw #0x00ff,%d0
+ oriw #0x0100,%d0
+ movel %pc@(L(custom)),%a0
+ movew %d0,%a0@(CUSTOMBASE+C_SERDAT)
+1: movew %a0@(CUSTOMBASE+C_SERDATR),%d0
+ andw #0x2000,%d0
jeq 1b
- jra 9f
+ jra L(serial_putc_done)
2:
#endif
+
+#ifdef CONFIG_MAC
+ is_not_mac(5f)
+
+#ifdef CONSOLE
+ console_putc %d0
+#endif /* CONSOLE */
+
+#ifdef MAC_SERIAL_DEBUG
+
+#ifdef MAC_USE_SCC_A
+ movel %pc@(L(mac_sccbase)),%a1
+3: btst #2,%a1@(mac_scc_cha_a_ctrl_offset)
+ jeq 3b
+ moveb %d0,%a1@(mac_scc_cha_a_data_offset)
+#endif /* MAC_USE_SCC_A */
+
+#ifdef MAC_USE_SCC_B
+#ifndef MAC_USE_SCC_A /* Load mac_sccbase only if needed */
+ movel %pc@(L(mac_sccbase)),%a1
+#endif /* MAC_USE_SCC_A */
+4: btst #2,%a1@(mac_scc_cha_b_ctrl_offset)
+ jeq 4b
+ moveb %d0,%a1@(mac_scc_cha_b_data_offset)
+#endif /* MAC_USE_SCC_B */
+
+#endif /* MAC_SERIAL_DEBUG */
+
+ jra L(serial_putc_done)
+5:
+#endif /* CONFIG_MAC */
+
#ifdef CONFIG_ATARI
- cmpil #MACH_ATARI,%d4
- jne 4f
- movel %pc@(Liobase),%a1
-#ifdef USE_PRINTER
+ is_not_atari(4f)
+ movel %pc@(L(iobase)),%a1
+#if defined(USE_PRINTER)
3: btst #0,%a1@(LSTMFP_GPIP)
jne 3b
moveb #LPSG_IO_B,%a1@(LPSG_SELECT)
- moveb %d7,%a1@(LPSG_WRITE)
+ moveb %d0,%a1@(LPSG_WRITE)
moveb #LPSG_IO_A,%a1@(LPSG_SELECT)
- moveb %a1@(LPSG_READ),%d7
- bclr #5,%d7
- moveb %d7,%a1@(LPSG_WRITE)
+ moveb %a1@(LPSG_READ),%d0
+ bclr #5,%d0
+ moveb %d0,%a1@(LPSG_WRITE)
nop
nop
- bset #5,%d7
- moveb %d7,%a1@(LPSG_WRITE)
+ bset #5,%d0
+ moveb %d0,%a1@(LPSG_WRITE)
#elif defined(USE_SCC)
-3: btst #2,%a1@(LSCC_CTRL_B)
+3: btst #2,%a1@(LSCC_CTRL)
jeq 3b
- moveb %d7,%a1@(LSCC_DATA_B)
+ moveb %d0,%a1@(LSCC_DATA)
#elif defined(USE_MFP)
3: btst #7,%a1@(LMFP_TSR)
jeq 3b
- moveb %d7,%a1@(LMFP_UDR)
+ moveb %d0,%a1@(LMFP_UDR)
#endif
+ jra L(serial_putc_done)
4:
+#endif /* CONFIG_ATARI */
+
+#ifdef CONFIG_MVME16x
+ is_not_mvme16x(2f)
+ /*
+ * The VME 16x class has PROM support for serial output
+ * of some kind; the TRAP table is still valid.
+ */
+ moveml %d0-%d7/%a2-%a6,%sp@-
+ moveb %d0,%sp@-
+ trap #15
+ .word 0x0020 /* TRAP 0x020 */
+ moveml %sp@+,%d0-%d7/%a2-%a6
+ jbra L(serial_putc_done)
+2:
+#endif CONFIG_MVME162 | CONFIG_MVME167
+
+#ifdef CONFIG_BVME6000
+ is_not_bvme6000(2f)
+ /*
+ * The BVME6000 machine has a serial port ...
+ */
+1: btst #2,BVME_SCC_CTRL_A
+ jeq 1b
+ moveb %d0,BVME_SCC_DATA_A
+ jbra L(serial_putc_done)
+2:
+#endif
+
+L(serial_putc_done):
+func_return serial_putc
+
+/*
+ * Output a string.
+ */
+func_start puts,%d0/%a0
+
+ movel ARG1,%a0
+ jra 2f
+1:
+#ifdef CONSOLE
+ console_putc %d0
+#endif
+#ifdef SERIAL_DEBUG
+ serial_putc %d0
+#endif
+2: moveb %a0@+,%d0
+ jne 1b
+
+func_return puts
+
+/*
+ * Output number in hex notation.
+ */
+
+func_start putn,%d0-%d2
+
+ putc ' '
+
+ movel ARG1,%d0
+ moveq #7,%d1
+1: roll #4,%d0
+ move %d0,%d2
+ andb #0x0f,%d2
+ addb #'0',%d2
+ cmpb #'9',%d2
+ jls 2f
+ addb #'A'-('9'+1),%d2
+2:
+#ifdef CONSOLE
+ console_putc %d2
+#endif
+#ifdef SERIAL_DEBUG
+ serial_putc %d2
#endif
-9:
- moveml %sp@+,%a0/%a1
+ dbra %d1,1b
+
+func_return putn
+
+#ifdef CONFIG_MAC
+/*
+ * mac_serial_print
+ *
+ * This routine takes its parameters on the stack. It then
+ * turns around and calls the internal routine. This routine
+ * is used until the Linux console driver initializes itself.
+ *
+ * The calling parameters are:
+ * void mac_serial_print(const char *str);
+ *
+ * This routine does NOT understand variable arguments only
+ * simple strings!
+ */
+ENTRY(mac_serial_print)
+ moveml %d0/%a0,%sp@-
+#if 1
+ move %sr,%sp@-
+ ori #0x0700,%sr
+#endif
+ movel %sp@(10),%a0 /* fetch parameter */
+ jra 2f
+1: serial_putc %d0
+2: moveb %a0@+,%d0
+ jne 1b
+#if 1
+ move %sp@+,%sr
+#endif
+ moveml %sp@+,%d0/%a0
rts
+#endif /* CONFIG_MAC */
+
+#ifdef CONFIG_HP300
+func_start set_leds,%d0/%a0
+ movel ARG1,%d0
+ movel %pc@(Lcustom),%a0
+ moveb %d0,%a0@(0x1ffff)
+func_return set_leds
+#endif
+#ifdef CONSOLE
/*
- * Output string pointed to by a0 to serial port.
- * a0 trashed.
+ * For continuity, see the data alignment
+ * to which this structure is tied.
*/
-Lserial_puts:
- movel %d7,%sp@-
-1: moveb %a0@+,%d7
- jeq 2f
- jbsr Lserial_putc
- jra 1b
-2: movel %sp@+,%d7
+#define Lconsole_struct_cur_column 0
+#define Lconsole_struct_cur_row 4
+#define Lconsole_struct_num_columns 8
+#define Lconsole_struct_num_rows 12
+#define Lconsole_struct_left_edge 16
+#define Lconsole_struct_penguin_putc 20
+
+L(console_init):
+ /*
+ * Some of the register usage that follows
+ * a0 = pointer to boot_info
+ * a1 = pointer to screen
+ * a2 = pointer to Lconsole_globals
+ * d3 = pixel width of screen
+ * d4 = pixel height of screen
+ * (d3,d4) ~= (x,y) of a point just below
+ * and to the right of the screen
+ * NOT on the screen!
+ * d5 = number of bytes per scan line
+ * d6 = number of bytes on the entire screen
+ */
+ moveml %a0-%a4/%d0-%d7,%sp@-
+
+ lea %pc@(L(console_globals)),%a2
+ lea %pc@(L(mac_videobase)),%a0
+ movel %a0@,%a1
+ lea %pc@(L(mac_rowbytes)),%a0
+ movel %a0@,%d5
+ lea %pc@(L(mac_dimensions)),%a0
+ movel %a0@,%d3 /* -> low byte */
+ movel %d3,%d4
+ swap %d4 /* -> high byte */
+ andl #0xffff,%d3 /* d3 = screen width in pixels */
+ andl #0xffff,%d4 /* d4 = screen height in pixels */
+
+ movel %d5,%d6
+ subl #20,%d6
+ mulul %d4,%d6 /* scan line bytes x num scan lines */
+ divul #8,%d6 /* we'll clear 8 bytes at a time */
+ subq #1,%d6
+
+console_clear_loop:
+ movel #0xffffffff,%a1@+ /* Mac_black */
+ movel #0xffffffff,%a1@+ /* Mac_black */
+ dbra %d6,console_clear_loop
+
+ /* Calculate font size */
+
+#if defined(FONT_8x8)
+ lea %pc@(SYMBOL_NAME(font_vga_8x8)), %a0
+#elif defined(FONT_8x16)
+ lea %pc@(SYMBOL_NAME(font_vga_8x16)),%a0
+#elif defined(FONT_6x11)
+ lea %pc@(SYMBOL_NAME(font_vga_6x11)),%a0
+#else /* (FONT_8x8) default */
+ lea %pc@(SYMBOL_NAME(font_vga_8x8)), %a0
+#endif
+
+ /*
+ * At this point we make a shift in register usage
+ * a1 = address of Lconsole_font pointer
+ */
+ lea %pc@(L(console_font)),%a1
+ movel %a0,%a1@ /* store pointer to struct fbcon_font_desc in Lconsole_font */
+
+ /*
+ * Calculate global maxs
+ * Note - we can use either an
+ * 8 x 16 or 8 x 8 character font
+ * 6 x 11 also supported
+ */
+ /* ASSERT: a0 = contents of Lconsole_font */
+ movel %d3,%d0 /* screen width in pixels */
+ divul %a0@(FBCON_FONT_DESC_WIDTH),%d0 /* d0 = max num chars per row */
+
+ movel %d4,%d1 /* screen height in pixels */
+ divul %a0@(FBCON_FONT_DESC_HEIGHT),%d1 /* d1 = max num rows */
+
+ movel %d0,%a2@(Lconsole_struct_num_columns)
+ movel %d1,%a2@(Lconsole_struct_num_rows)
+
+ /*
+ * Clear the current row and column
+ */
+ clrl %a2@(Lconsole_struct_cur_column)
+ clrl %a2@(Lconsole_struct_cur_row)
+ clrl %a2@(Lconsole_struct_left_edge)
+
+ /*
+ * Initialization is complete
+ */
+ moveml %sp@+,%a0-%a4/%d0-%d7
+ rts
+
+L(console_put_stats):
+ /*
+ * Some of the register usage that follows
+ * a0 = pointer to boot_info
+ * d7 = value of boot_info fields
+ */
+ moveml %a0/%d7,%sp@-
+
+ puts "\nMacLinux\n\n"
+
+#ifdef SERIAL_DEBUG
+ puts " vidaddr:"
+ putn %pc@(L(mac_videobase)) /* video addr. */
+
+ puts "\n _stext:"
+ lea %pc@(SYMBOL_NAME(_stext)),%a0
+ putn %a0
+
+ puts "\nbootinfo:"
+ lea %pc@(SYMBOL_NAME(_end)),%a0
+ putn %a0
+
+ puts "\ncpuid:"
+ putn %pc@(L(cputype))
+ putc '\n'
+
+# if defined(MMU_PRINT)
+ jbsr mmu_print_machine_cpu_types
+# endif /* MMU_PRINT */
+#endif /* SERIAL_DEBUG */
+
+ moveml %sp@+,%a0/%d7
+ rts
+
+#ifdef CONSOLE_PENGUIN
+L(console_put_penguin):
+ /*
+ * Get 'that_penguin' onto the screen in the upper right corner
+ * penguin is 64 x 74 pixels, align against right edge of screen
+ */
+ moveml %a0-%a1/%d0-%d7,%sp@-
+
+ lea %pc@(L(mac_dimensions)),%a0
+ movel %a0@,%d0
+ andil #0xffff,%d0
+ subil #64,%d0 /* snug up against the right edge */
+ clrl %d1 /* start at the top */
+ movel #73,%d7
+ lea %pc@(SYMBOL_NAME(that_penguin)),%a1
+console_penguin_row:
+ movel #31,%d6
+console_penguin_pixel_pair:
+ moveb %a1@,%d2
+ lsrb #4,%d2
+ jbsr console_plot_pixel
+ addq #1,%d0
+ moveb %a1@+,%d2
+ jbsr console_plot_pixel
+ addq #1,%d0
+ dbra %d6,console_penguin_pixel_pair
+
+ subil #64,%d0
+ addq #1,%d1
+ dbra %d7,console_penguin_row
+
+ moveml %sp@+,%a0-%a1/%d0-%d7
+ rts
+#endif
+
+console_scroll:
+ moveml %a0-%a4/%d0-%d7,%sp@-
+
+ /*
+ * Calculate source and destination addresses
+ * output a1 = dest
+ * a2 = source
+ */
+ lea %pc@(L(mac_videobase)),%a0
+ movel %a0@,%a1
+ movel %a1,%a2
+ lea %pc@(L(mac_rowbytes)),%a0
+ movel %a0@,%d5
+ movel %pc@(L(console_font)),%a0
+ mulul %a0@(FBCON_FONT_DESC_HEIGHT),%d5 /* account for # scan lines per character */
+ addal %d5,%a2
+
+ /*
+ * Get dimensions
+ */
+ lea %pc@(L(mac_dimensions)),%a0
+ movel %a0@,%d3
+ movel %d3,%d4
+ swap %d4
+ andl #0xffff,%d3 /* d3 = screen width in pixels */
+ andl #0xffff,%d4 /* d4 = screen height in pixels */
+
+ /*
+ * Calculate number of bytes to move
+ */
+ lea %pc@(L(mac_rowbytes)),%a0
+ movel %a0@,%d6
+ movel %pc@(L(console_font)),%a0
+ subl %a0@(FBCON_FONT_DESC_HEIGHT),%d4 /* we're not scrolling the top row! */
+ mulul %d4,%d6 /* scan line bytes x num scan lines */
+ divul #32,%d6 /* we'll move 8 longs at a time */
+ subq #1,%d6
+
+console_scroll_loop:
+ movel %a2@+,%a1@+
+ movel %a2@+,%a1@+
+ movel %a2@+,%a1@+
+ movel %a2@+,%a1@+
+ movel %a2@+,%a1@+
+ movel %a2@+,%a1@+
+ movel %a2@+,%a1@+
+ movel %a2@+,%a1@+
+ dbra %d6,console_scroll_loop
+
+ lea %pc@(L(mac_rowbytes)),%a0
+ movel %a0@,%d6
+ movel %pc@(L(console_font)),%a0
+ mulul %a0@(FBCON_FONT_DESC_HEIGHT),%d6 /* scan line bytes x font height */
+ divul #32,%d6 /* we'll move 8 words at a time */
+ subq #1,%d6
+
+ moveq #-1,%d0
+console_scroll_clear_loop:
+ movel %d0,%a1@+
+ movel %d0,%a1@+
+ movel %d0,%a1@+
+ movel %d0,%a1@+
+ movel %d0,%a1@+
+ movel %d0,%a1@+
+ movel %d0,%a1@+
+ movel %d0,%a1@+
+ dbra %d6,console_scroll_clear_loop
+
+ moveml %sp@+,%a0-%a4/%d0-%d7
rts
+
+func_start console_putc,%a0/%a1/%d0-%d7
+
+ is_not_mac(console_exit)
+
+ /* Output character in d7 on console.
+ */
+ movel ARG1,%d7
+ cmpib #'\n',%d7
+ jbne 1f
+
+ /* A little safe recursion is good for the soul */
+ console_putc #'\r'
+1:
+ lea %pc@(L(console_globals)),%a0
+
+ cmpib #10,%d7
+ jne console_not_lf
+ movel %a0@(Lconsole_struct_cur_row),%d0
+ addil #1,%d0
+ movel %d0,%a0@(Lconsole_struct_cur_row)
+ movel %a0@(Lconsole_struct_num_rows),%d1
+ cmpl %d1,%d0
+ jcs 1f
+ subil #1,%d0
+ movel %d0,%a0@(Lconsole_struct_cur_row)
+ jbsr console_scroll
+1:
+ jra console_exit
+
+console_not_lf:
+ cmpib #13,%d7
+ jne console_not_cr
+ clrl %a0@(Lconsole_struct_cur_column)
+ jra console_exit
+
+console_not_cr:
+ cmpib #1,%d7
+ jne console_not_home
+ clrl %a0@(Lconsole_struct_cur_row)
+ clrl %a0@(Lconsole_struct_cur_column)
+ jra console_exit
+
/*
- * Output number in d7 in hex notation on serial port.
+ * At this point we know that the %d7 character is going to be
+ * rendered on the screen. Register usage is -
+ * a0 = pointer to console globals
+ * a1 = font data
+ * d0 = cursor column
+ * d1 = cursor row to draw the character
+ * d7 = character number
*/
+console_not_home:
+ movel %a0@(Lconsole_struct_cur_column),%d0
+ addil #1,%a0@(Lconsole_struct_cur_column)
+ movel %a0@(Lconsole_struct_num_columns),%d1
+ cmpl %d1,%d0
+ jcs 1f
+ putc '\n' /* recursion is OK! */
+1:
+ movel %a0@(Lconsole_struct_cur_row),%d1
-Lserial_putnum:
- moveml %d0-%d2/%d7,%sp@-
- movel %d7,%d1
- moveq #4,%d0
- moveq #7,%d2
-L1: roll %d0,%d1
- moveb %d1,%d7
- andb #0x0f,%d7
- cmpb #0x0a,%d7
- jcc 1f
- addb #'0',%d7
- jra 2f
-1: addb #'A'-10,%d7
-2: jbsr Lserial_putc
- dbra %d2,L1
- moveq #32,%d7
- jbsr Lserial_putc
- moveml %sp@+,%d0-%d2/%d7
+ /*
+ * At this point we make a shift in register usage
+ * a0 = address of pointer to font data (fbcon_font_desc)
+ */
+ movel %pc@(L(console_font)),%a0
+ movel %a0@(FBCON_FONT_DESC_DATA),%a1 /* Load fbcon_font_desc.data into a1 */
+ andl #0x000000ff,%d7
+ /* ASSERT: a0 = contents of Lconsole_font */
+ mulul %a0@(FBCON_FONT_DESC_HEIGHT),%d7 /* d7 = index into font data */
+ addl %d7,%a1 /* a1 = points to char image */
+
+ /*
+ * At this point we make a shift in register usage
+ * d0 = pixel coordinate, x
+ * d1 = pixel coordinate, y
+ * d2 = (bit 0) 1/0 for white/black (!) pixel on screen
+ * d3 = font scan line data (8 pixels)
+ * d6 = count down for the font's pixel width (8)
+ * d7 = count down for the font's pixel count in height
+ */
+ /* ASSERT: a0 = contents of Lconsole_font */
+ mulul %a0@(FBCON_FONT_DESC_WIDTH),%d0
+ mulul %a0@(FBCON_FONT_DESC_HEIGHT),%d1
+ movel %a0@(FBCON_FONT_DESC_HEIGHT),%d7 /* Load fbcon_font_desc.height into d7 */
+ subq #1,%d7
+console_read_char_scanline:
+ moveb %a1@+,%d3
+
+ /* ASSERT: a0 = contents of Lconsole_font */
+ movel %a0@(FBCON_FONT_DESC_WIDTH),%d6 /* Load fbcon_font_desc.width into d6 */
+ subql #1,%d6
+
+console_do_font_scanline:
+ lslb #1,%d3
+ scsb %d2 /* convert 1 bit into a byte */
+ jbsr console_plot_pixel
+ addq #1,%d0
+ dbra %d6,console_do_font_scanline
+
+ /* ASSERT: a0 = contents of Lconsole_font */
+ subl %a0@(FBCON_FONT_DESC_WIDTH),%d0
+ addq #1,%d1
+ dbra %d7,console_read_char_scanline
+
+console_exit:
+
+func_return console_putc
+
+console_plot_pixel:
+ /*
+ * Input:
+ * d0 = x coordinate
+ * d1 = y coordinate
+ * d2 = (bit 0) 1/0 for white/black (!)
+ * All registers are preserved
+ */
+ moveml %a0-%a1/%d0-%d4,%sp@-
+
+ lea %pc@(L(mac_videobase)),%a0
+ movel %a0@,%a1
+ lea %pc@(L(mac_videodepth)),%a0
+ movel %a0@,%d3
+ lea %pc@(L(mac_rowbytes)),%a0
+ mulul %a0@,%d1
+
+ /*
+ * Register usage:
+ * d0 = x coord becomes byte offset into frame buffer
+ * d1 = y coord
+ * d2 = black or white (0/1)
+ * d3 = video depth
+ * d4 = temp of x (d0) for many bit depths
+ * d5 = unused
+ * d6 = unused
+ * d7 = unused
+ */
+test_1bit:
+ cmpb #1,%d3
+ jbne test_2bit
+ movel %d0,%d4 /* we need the low order 3 bits! */
+ divul #8,%d0
+ addal %d0,%a1
+ addal %d1,%a1
+ andb #7,%d4
+ eorb #7,%d4 /* reverse the x-coordinate w/ screen-bit # */
+ andb #1,%d2
+ jbne white_1
+ bsetb %d4,%a1@
+ jbra console_plot_pixel_exit
+white_1:
+ bclrb %d4,%a1@
+ jbra console_plot_pixel_exit
+
+test_2bit:
+ cmpb #2,%d3
+ jbne test_4bit
+ movel %d0,%d4 /* we need the low order 2 bits! */
+ divul #4,%d0
+ addal %d0,%a1
+ addal %d1,%a1
+ andb #3,%d4
+ eorb #3,%d4 /* reverse the x-coordinate w/ screen-bit # */
+ lsll #1,%d4 /* ! */
+ andb #1,%d2
+ jbne white_2
+ bsetb %d4,%a1@
+ addq #1,%d4
+ bsetb %d4,%a1@
+ jbra console_plot_pixel_exit
+white_2:
+ bclrb %d4,%a1@
+ addq #1,%d4
+ bclrb %d4,%a1@
+ jbra console_plot_pixel_exit
+
+test_4bit:
+ cmpb #4,%d3
+ jbne test_8bit
+ movel %d0,%d4 /* we need the low order bit! */
+ divul #2,%d0
+ addal %d0,%a1
+ addal %d1,%a1
+ andb #1,%d4
+ eorb #1,%d4
+ lsll #2,%d4 /* ! */
+ andb #1,%d2
+ jbne white_4
+ bsetb %d4,%a1@
+ addq #1,%d4
+ bsetb %d4,%a1@
+ addq #1,%d4
+ bsetb %d4,%a1@
+ addq #1,%d4
+ bsetb %d4,%a1@
+ jbra console_plot_pixel_exit
+white_4:
+ bclrb %d4,%a1@
+ addq #1,%d4
+ bclrb %d4,%a1@
+ addq #1,%d4
+ bclrb %d4,%a1@
+ addq #1,%d4
+ bclrb %d4,%a1@
+ jbra console_plot_pixel_exit
+
+test_8bit:
+ cmpb #8,%d3
+ jbne test_16bit
+ addal %d0,%a1
+ addal %d1,%a1
+ andb #1,%d2
+ jbne white_8
+ moveb #0xff,%a1@
+ jbra console_plot_pixel_exit
+white_8:
+ clrb %a1@
+ jbra console_plot_pixel_exit
+
+test_16bit:
+ cmpb #16,%d3
+ jbne console_plot_pixel_exit
+ addal %d0,%a1
+ addal %d0,%a1
+ addal %d1,%a1
+ andb #1,%d2
+ jbne white_16
+ clrw %a1@
+ jbra console_plot_pixel_exit
+white_16:
+ movew #0x0fff,%a1@
+ jbra console_plot_pixel_exit
+
+console_plot_pixel_exit:
+ moveml %sp@+,%a0-%a1/%d0-%d4
rts
+#endif /* CONSOLE */
#if 0
-Lshowtest:
+/*
+ * This is some old code lying around. I don't believe
+ * it's used or important anymore. My guess is it contributed
+ * to getting to this point, but it's done for now.
+ * It was still in the 2.1.77 head.S, so it's still here.
+ * (And still not used!)
+ */
+L(showtest):
moveml %a0/%d7,%sp@-
- putc('A')
- putc('=')
- putn(%a1)
+ puts "A="
+ putn %a1
- ptestr #5,%a1@,#7,%a0
+ .long 0xf0119f15 | ptestr #5,%a1@,#7,%a0
- putc('D')
- putc('A')
- putc('=')
- putn(%a0)
+ puts "DA="
+ putn %a0
- putc('D')
- putc('=')
- putn(%a0@)
+ puts "D="
+ putn %a0@
- putc('S')
- putc('=')
- lea %pc@(Lmmu),%a0
- pmove %psr,%a0@
+ puts "S="
+ lea %pc@(L(mmu)),%a0
+ .long 0xf0106200 | pmove %psr,%a0@
clrl %d7
movew %a0@,%d7
- jbsr Lserial_putnum
+ putn %d7
- putr()
+ putc '\n'
moveml %sp@+,%a0/%d7
rts
+#endif /* 0 */
+
+__INITDATA
+ .align 4
+
+#if defined(CONFIG_ATARI) || defined(CONFIG_AMIGA) || defined(CONFIG_HP300)
+L(custom):
+L(iobase):
+ .long 0
+#endif
+
+#ifdef CONFIG_MAC
+L(console_video_virtual):
+ .long 0
+#endif /* CONFIG_MAC */
+
+#if defined(CONSOLE)
+L(console_globals):
+ .long 0 /* cursor column */
+ .long 0 /* cursor row */
+ .long 0 /* max num columns */
+ .long 0 /* max num rows */
+ .long 0 /* left edge */
+ .long 0 /* mac putc */
+L(console_font):
+ .long 0 /* pointer to console font (struct fbcon_font_desc) */
+#endif /* CONSOLE */
+
+#if defined(MMU_PRINT)
+L(mmu_print_data):
+ .long 0 /* valid flag */
+ .long 0 /* start logical */
+ .long 0 /* next logical */
+ .long 0 /* start physical */
+ .long 0 /* next physical */
+#endif /* MMU_PRINT */
+
+L(cputype):
+ .long 0
+L(mmu_cached_pointer_tables):
+ .long 0
+L(mmu_num_pointer_tables):
+ .long 0
+L(phys_kernel_start):
+ .long 0
+L(kernel_end):
+ .long 0
+L(memory_start):
+ .long 0
+L(kernel_pgdir_ptr):
+ .long 0
+L(temp_mmap_mem):
+ .long 0
+
+
+#if defined (CONFIG_BVME6000)
+BVME_SCC_CTRL_A = 0xffb0000b
+BVME_SCC_DATA_A = 0xffb0000f
+#endif
+
+#if defined(CONFIG_MAC)
+L(mac_booter_data):
+ .long 0
+L(mac_videobase):
+ .long 0
+L(mac_videodepth):
+ .long 0
+L(mac_dimensions):
+ .long 0
+L(mac_rowbytes):
+ .long 0
+#ifdef MAC_SERIAL_DEBUG
+L(mac_sccbase):
+ .long 0
+#endif /* MAC_SERIAL_DEBUG */
#endif
+
+__FINIT
.data
- .even
-Lcustom:
-Liobase:
- .long 0
-Lmmu: .quad 0
-SYMBOL_NAME_LABEL(kpt)
- .long 0
+ .align 4
+
SYMBOL_NAME_LABEL(availmem)
- .long 0
+ .long 0
SYMBOL_NAME_LABEL(m68k_pgtable_cachemode)
- .long 0
-#ifdef CONFIG_060_WRITETHROUGH
+ .long 0
SYMBOL_NAME_LABEL(m68k_supervisor_cachemode)
- .long 0
-#endif
+ .long 0
#if defined(CONFIG_MVME16x)
SYMBOL_NAME_LABEL(mvme_bdid_ptr)
- .long 0
+ .long 0
#endif
diff --git a/arch/m68k/kernel/m68k_defs.c b/arch/m68k/kernel/m68k_defs.c
index 122bf63be..e2e6715e7 100644
--- a/arch/m68k/kernel/m68k_defs.c
+++ b/arch/m68k/kernel/m68k_defs.c
@@ -10,14 +10,78 @@
#include <linux/stddef.h>
#include <linux/sched.h>
+#include <linux/kernel_stat.h>
+#include <asm/bootinfo.h>
+#include <asm/irq.h>
+#include <asm/amigahw.h>
+#include <video/font.h>
#define DEFINE(sym, val) \
- asm volatile("\n#define " #sym " %0" : : "i" (val))
+ asm volatile("\n#define " #sym " %c0" : : "i" (val))
int main(void)
{
- DEFINE(TS_TSS, offsetof(struct task_struct, tss));
- DEFINE(TS_ESP0, offsetof(struct task_struct, tss.esp0));
- DEFINE(TS_FPU, offsetof(struct task_struct, tss.fp));
+ /* offsets into the task struct */
+ DEFINE(TASK_STATE, offsetof(struct task_struct, state));
+ DEFINE(TASK_FLAGS, offsetof(struct task_struct, flags));
+ DEFINE(TASK_SIGPENDING, offsetof(struct task_struct, sigpending));
+ DEFINE(TASK_NEEDRESCHED, offsetof(struct task_struct, need_resched));
+ DEFINE(TASK_TSS, offsetof(struct task_struct, tss));
+ DEFINE(TASK_MM, offsetof(struct task_struct, mm));
+
+ /* offsets into the thread struct */
+ DEFINE(TSS_KSP, offsetof(struct thread_struct, ksp));
+ DEFINE(TSS_USP, offsetof(struct thread_struct, usp));
+ DEFINE(TSS_SR, offsetof(struct thread_struct, sr));
+ DEFINE(TSS_FS, offsetof(struct thread_struct, fs));
+ DEFINE(TSS_CRP, offsetof(struct thread_struct, crp));
+ DEFINE(TSS_ESP0, offsetof(struct thread_struct, esp0));
+ DEFINE(TSS_FPREG, offsetof(struct thread_struct, fp));
+ DEFINE(TSS_FPCNTL, offsetof(struct thread_struct, fpcntl));
+ DEFINE(TSS_FPSTATE, offsetof(struct thread_struct, fpstate));
+
+ /* offsets into the pt_regs */
+ DEFINE(PT_D0, offsetof(struct pt_regs, d0));
+ DEFINE(PT_ORIG_D0, offsetof(struct pt_regs, orig_d0));
+ DEFINE(PT_SR, offsetof(struct pt_regs, sr));
+
+ /* bitfields are a bit difficult */
+ DEFINE(PT_VECTOR, offsetof(struct pt_regs, pc) + 4);
+
+ /* offsets into the irq_handler struct */
+ DEFINE(IRQ_HANDLER, offsetof(struct irq_node, handler));
+ DEFINE(IRQ_DEVID, offsetof(struct irq_node, dev_id));
+ DEFINE(IRQ_NEXT, offsetof(struct irq_node, next));
+
+ /* offsets into the kernel_stat struct */
+ DEFINE(STAT_IRQ, offsetof(struct kernel_stat, irqs));
+
+ /* offsets into the bi_record struct */
+ DEFINE(BIR_TAG, offsetof(struct bi_record, tag));
+ DEFINE(BIR_SIZE, offsetof(struct bi_record, size));
+ DEFINE(BIR_DATA, offsetof(struct bi_record, data));
+
+ /* offsets into fbcon_font_desc (video/font.h) */
+ DEFINE(FBCON_FONT_DESC_IDX, offsetof(struct fbcon_font_desc, idx));
+ DEFINE(FBCON_FONT_DESC_NAME, offsetof(struct fbcon_font_desc, name));
+ DEFINE(FBCON_FONT_DESC_WIDTH, offsetof(struct fbcon_font_desc, width));
+ DEFINE(FBCON_FONT_DESC_HEIGHT, offsetof(struct fbcon_font_desc, height));
+ DEFINE(FBCON_FONT_DESC_DATA, offsetof(struct fbcon_font_desc, data));
+ DEFINE(FBCON_FONT_DESC_PREF, offsetof(struct fbcon_font_desc, pref));
+
+ /* offsets into the custom struct */
+ DEFINE(CUSTOMBASE, &custom);
+ DEFINE(C_INTENAR, offsetof(struct CUSTOM, intenar));
+ DEFINE(C_INTREQR, offsetof(struct CUSTOM, intreqr));
+ DEFINE(C_INTENA, offsetof(struct CUSTOM, intena));
+ DEFINE(C_INTREQ, offsetof(struct CUSTOM, intreq));
+ DEFINE(C_SERDATR, offsetof(struct CUSTOM, serdatr));
+ DEFINE(C_SERDAT, offsetof(struct CUSTOM, serdat));
+ DEFINE(C_SERPER, offsetof(struct CUSTOM, serper));
+ DEFINE(CIAABASE, &ciaa);
+ DEFINE(CIABBASE, &ciab);
+ DEFINE(C_PRA, offsetof(struct CIA, pra));
+ DEFINE(ZTWOBASE, zTwoBase);
+
return 0;
}
diff --git a/arch/m68k/kernel/m68k_defs.h b/arch/m68k/kernel/m68k_defs.h
index 992d390c7..b32e6a1c9 100644
--- a/arch/m68k/kernel/m68k_defs.h
+++ b/arch/m68k/kernel/m68k_defs.h
@@ -3,6 +3,6 @@
*/
#define TS_MAGICKEY 0x5a5a5a5a
-#define TS_TSS 478
-#define TS_ESP0 498
-#define TS_FPU 502
+#define TS_TSS 482
+#define TS_ESP0 502
+#define TS_FPU 506
diff --git a/arch/m68k/kernel/m68k_ksyms.c b/arch/m68k/kernel/m68k_ksyms.c
index 40b692e0c..793ca6ec7 100644
--- a/arch/m68k/kernel/m68k_ksyms.c
+++ b/arch/m68k/kernel/m68k_ksyms.c
@@ -13,6 +13,7 @@
#include <asm/machdep.h>
#include <asm/pgtable.h>
#include <asm/irq.h>
+#include <asm/io.h>
#include <asm/semaphore.h>
#include <asm/checksum.h>
#include <asm/hardirq.h>
@@ -37,8 +38,10 @@ EXPORT_SYMBOL(mm_ptov);
EXPORT_SYMBOL(mm_end_of_chunk);
#endif
EXPORT_SYMBOL(mm_vtop_fallback);
+EXPORT_SYMBOL(m68k_realnum_memory);
EXPORT_SYMBOL(m68k_memory);
-EXPORT_SYMBOL(kernel_map);
+EXPORT_SYMBOL(__ioremap);
+EXPORT_SYMBOL(iounmap);
EXPORT_SYMBOL(m68k_debug_device);
EXPORT_SYMBOL(dump_fpu);
EXPORT_SYMBOL(dump_thread);
@@ -49,6 +52,8 @@ EXPORT_SYMBOL(local_irq_count);
EXPORT_SYMBOL(local_bh_count);
EXPORT_SYMBOL(enable_irq);
EXPORT_SYMBOL(disable_irq);
+EXPORT_SYMBOL(kernel_set_cachemode);
+EXPORT_SYMBOL(kernel_thread);
/* Networking helper routines. */
EXPORT_SYMBOL(csum_partial_copy);
diff --git a/arch/m68k/kernel/process.c b/arch/m68k/kernel/process.c
index fb9bac400..c7c3f458e 100644
--- a/arch/m68k/kernel/process.c
+++ b/arch/m68k/kernel/process.c
@@ -56,16 +56,13 @@ asmlinkage void ret_from_exception(void);
*/
asmlinkage int sys_idle(void)
{
- int ret = -EPERM;
-
- lock_kernel();
if (current->pid != 0)
- goto out;
+ return -EPERM;
/* endless idle loop with no priority at all */
- current->priority = -100;
+ current->priority = 0;
current->counter = -100;
- for (;;){
+ for (;;) {
if (!current->need_resched)
#if defined(CONFIG_ATARI) && !defined(CONFIG_AMIGA) && !defined(CONFIG_MAC)
/* block out HSYNC on the atari (falcon) */
@@ -73,14 +70,9 @@ asmlinkage int sys_idle(void)
#else /* portable version */
__asm__("stop #0x2000" : : : "cc");
#endif /* machine compilation types */
- check_pgt_cache();
- run_task_queue(&tq_scheduler);
schedule();
+ check_pgt_cache();
}
- ret = 0;
-out:
- unlock_kernel();
- return ret;
}
void machine_restart(char * __unused)
@@ -115,6 +107,44 @@ void show_regs(struct pt_regs * regs)
printk("USP: %08lx\n", rdusp());
}
+/*
+ * Create a kernel thread
+ */
+int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
+{
+ int pid;
+ mm_segment_t fs;
+
+ fs = get_fs();
+ set_fs (KERNEL_DS);
+
+ {
+ register long retval __asm__ ("d0");
+ register long clone_arg __asm__ ("d1") = flags | CLONE_VM;
+
+ __asm__ __volatile__
+ ("clrl %%d2\n\t"
+ "trap #0\n\t" /* Linux/m68k system call */
+ "tstl %0\n\t" /* child or parent */
+ "jne 1f\n\t" /* parent - jump */
+ "lea %%sp@(-8192),%6\n\t" /* reload current */
+ "movel %3,%%sp@-\n\t" /* push argument */
+ "jsr %4@\n\t" /* call fn */
+ "movel %0,%%d1\n\t" /* pass exit value */
+ "movel %2,%0\n\t" /* exit */
+ "trap #0\n"
+ "1:"
+ : "=d" (retval)
+ : "0" (__NR_clone), "i" (__NR_exit),
+ "r" (arg), "a" (fn), "d" (clone_arg), "r" (current)
+ : "d0", "d2");
+ pid = retval;
+ }
+
+ set_fs (fs);
+ return pid;
+}
+
void flush_thread(void)
{
unsigned long zero = 0;
@@ -137,6 +167,19 @@ asmlinkage int m68k_fork(struct pt_regs *regs)
return do_fork(SIGCHLD, rdusp(), regs);
}
+asmlinkage int m68k_vfork(struct pt_regs *regs)
+{
+ int child;
+ struct semaphore sem = MUTEX_LOCKED;
+
+ child = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs);
+
+ if (child > 0)
+ down(&sem);
+
+ return child;
+}
+
asmlinkage int m68k_clone(struct pt_regs *regs)
{
unsigned long clone_flags;
@@ -147,7 +190,7 @@ asmlinkage int m68k_clone(struct pt_regs *regs)
newsp = regs->d2;
if (!newsp)
newsp = rdusp();
- return do_fork(clone_flags, newsp, regs);
+ return do_fork(clone_flags & ~CLONE_VFORK, newsp, regs);
}
int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
diff --git a/arch/m68k/kernel/ptrace.c b/arch/m68k/kernel/ptrace.c
index 9888d83c1..5aeb2534b 100644
--- a/arch/m68k/kernel/ptrace.c
+++ b/arch/m68k/kernel/ptrace.c
@@ -325,12 +325,15 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
ret = 0;
goto out;
}
- if (pid == 1) /* you may not mess with init */
- goto out;
ret = -ESRCH;
- if (!(child = find_task_by_pid(pid)))
+ read_lock(&tasklist_lock);
+ child = find_task_by_pid(pid);
+ read_unlock(&tasklist_lock); /* FIXME!!! */
+ if (!child)
goto out;
ret = -EPERM;
+ if (pid == 1) /* you may not mess with init */
+ goto out;
if (request == PTRACE_ATTACH) {
if (child == current)
goto out;
@@ -375,7 +378,9 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
case PTRACE_PEEKDATA: {
unsigned long tmp;
+ down(&child->mm->mmap_sem);
ret = read_long(child, addr, &tmp);
+ up(&child->mm->mmap_sem);
if (ret >= 0)
ret = put_user(tmp, (unsigned long *) data);
goto out;
@@ -408,7 +413,9 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
/* when I and D space are separate, this will have to be fixed. */
case PTRACE_POKETEXT: /* write the word at location addr. */
case PTRACE_POKEDATA:
+ down(&child->mm->mmap_sem);
ret = write_long(child,addr,data);
+ up(&child->mm->mmap_sem);
goto out;
case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
diff --git a/arch/m68k/kernel/setup.c b/arch/m68k/kernel/setup.c
index e12786344..ade12c46d 100644
--- a/arch/m68k/kernel/setup.c
+++ b/arch/m68k/kernel/setup.c
@@ -48,6 +48,7 @@ extern int end;
extern unsigned long availmem;
int m68k_num_memory = 0;
+int m68k_realnum_memory = 0;
struct mem_info m68k_memory[NUM_MEMINFO];
static struct mem_info m68k_ramdisk = { 0, 0 };
@@ -62,8 +63,6 @@ void (*mach_sched_init) (void (*handler)(int, void *, struct pt_regs *)) __initd
int (*mach_keyb_init) (void) __initdata;
int (*mach_kbdrate) (struct kbd_repeat *) = NULL;
void (*mach_kbd_leds) (unsigned int) = NULL;
-/* machine dependent "kbd-reset" setup function */
-void (*kbd_reset_setup) (char *, int) __initdata = NULL;
/* machine dependent irq functions */
void (*mach_init_IRQ) (void) __initdata;
void (*(*mach_default_handler)[]) (int, void *, struct pt_regs *) = NULL;
@@ -159,6 +158,7 @@ __initfunc(static void m68k_parse_bootinfo(const struct bi_record *record))
record = (struct bi_record *)((u_long)record+record->size);
}
+ m68k_realnum_memory = m68k_num_memory;
#ifdef CONFIG_SINGLE_MEMORY_CHUNK
if (m68k_num_memory > 1) {
printk("Ignoring last %i chunks of physical memory\n",
@@ -398,9 +398,9 @@ void floppy_eject(void)
}
#endif
-__initfunc(unsigned long arch_kbd_init(void))
+/* for "kbd-reset" cmdline param */
+void __init kbd_reset_setup(char *str, int *ints)
{
- return mach_keyb_init();
}
void arch_gettod(int *year, int *mon, int *day, int *hour,
diff --git a/arch/m68k/kernel/signal.c b/arch/m68k/kernel/signal.c
index af5af69b6..a2b9ce1d4 100644
--- a/arch/m68k/kernel/signal.c
+++ b/arch/m68k/kernel/signal.c
@@ -361,7 +361,7 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext *usc, void *fp,
: "a0");
#undef frame_offset
/*
- * If we ever get here an exception occured while
+ * If we ever get here an exception occurred while
* building the above stack-frame.
*/
goto badframe;
@@ -460,7 +460,7 @@ rt_restore_ucontext(struct pt_regs *regs, struct switch_stack *sw,
: "a0");
#undef frame_offset
/*
- * If we ever get here an exception occured while
+ * If we ever get here an exception occurred while
* building the above stack-frame.
*/
goto badframe;
diff --git a/arch/m68k/kernel/sys_m68k.c b/arch/m68k/kernel/sys_m68k.c
index 75da52541..a85da4e10 100644
--- a/arch/m68k/kernel/sys_m68k.c
+++ b/arch/m68k/kernel/sys_m68k.c
@@ -112,7 +112,8 @@ asmlinkage int old_select(struct sel_arg_struct *arg)
*
* This is really horribly ugly.
*/
-asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr, long fifth)
+asmlinkage int sys_ipc (uint call, int first, int second,
+ int third, void *ptr, long fifth)
{
int version, ret;
@@ -122,88 +123,76 @@ asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr,
if (call <= SEMCTL)
switch (call) {
case SEMOP:
- ret = sys_semop (first, (struct sembuf *)ptr, second);
- goto out;
+ return sys_semop (first, (struct sembuf *)ptr, second);
case SEMGET:
- ret = sys_semget (first, second, third);
- goto out;
+ return sys_semget (first, second, third);
case SEMCTL: {
union semun fourth;
- ret = -EINVAL;
if (!ptr)
- goto out;
- if ((ret = get_user(fourth.__pad, (void **) ptr)))
- goto out;
- ret = sys_semctl (first, second, third, fourth);
- goto out;
+ return -EINVAL;
+ if (get_user(fourth.__pad, (void **) ptr))
+ return -EFAULT;
+ return sys_semctl (first, second, third, fourth);
}
default:
- ret = -EINVAL;
- goto out;
+ return -EINVAL;
}
if (call <= MSGCTL)
switch (call) {
case MSGSND:
- ret = sys_msgsnd (first, (struct msgbuf *) ptr,
+ return sys_msgsnd (first, (struct msgbuf *) ptr,
second, third);
- goto out;
case MSGRCV:
switch (version) {
case 0: {
struct ipc_kludge tmp;
- ret = -EINVAL;
if (!ptr)
- goto out;
- ret = -EFAULT;
- if (copy_from_user (&tmp, ptr, sizeof (tmp)))
- goto out;
- ret = sys_msgrcv (first, tmp.msgp, second, tmp.msgtyp, third);
- goto out;
+ return -EINVAL;
+ if (copy_from_user (&tmp,
+ (struct ipc_kludge *)ptr,
+ sizeof (tmp)))
+ return -EFAULT;
+ return sys_msgrcv (first, tmp.msgp, second,
+ tmp.msgtyp, third);
}
- case 1: default:
- ret = sys_msgrcv (first, (struct msgbuf *) ptr, second, fifth, third);
- goto out;
+ default:
+ return sys_msgrcv (first,
+ (struct msgbuf *) ptr,
+ second, fifth, third);
}
case MSGGET:
- ret = sys_msgget ((key_t) first, second);
- goto out;
+ return sys_msgget ((key_t) first, second);
case MSGCTL:
- ret = sys_msgctl (first, second, (struct msqid_ds *) ptr);
- goto out;
+ return sys_msgctl (first, second,
+ (struct msqid_ds *) ptr);
default:
- ret = -EINVAL;
- goto out;
+ return -EINVAL;
}
if (call <= SHMCTL)
switch (call) {
case SHMAT:
switch (version) {
- case 0: default: {
+ default: {
ulong raddr;
- ret = sys_shmat (first, (char *) ptr, second, &raddr);
+ ret = sys_shmat (first, (char *) ptr,
+ second, &raddr);
if (ret)
- goto out;
- ret = put_user (raddr, (ulong *) third);
- goto out;
+ return ret;
+ return put_user (raddr, (ulong *) third);
}
}
case SHMDT:
- ret = sys_shmdt ((char *)ptr);
- goto out;
+ return sys_shmdt ((char *)ptr);
case SHMGET:
- ret = sys_shmget (first, second, third);
- goto out;
+ return sys_shmget (first, second, third);
case SHMCTL:
- ret = sys_shmctl (first, second, (struct shmid_ds *) ptr);
- goto out;
+ return sys_shmctl (first, second,
+ (struct shmid_ds *) ptr);
default:
- ret = -EINVAL;
- goto out;
+ return -EINVAL;
}
- ret = -EINVAL;
-out:
- unlock_kernel();
- return ret;
+
+ return -EINVAL;
}
asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on)
diff --git a/arch/m68k/kernel/time.c b/arch/m68k/kernel/time.c
index 8f11a00d8..107d0de7f 100644
--- a/arch/m68k/kernel/time.c
+++ b/arch/m68k/kernel/time.c
@@ -5,6 +5,9 @@
*
* This file contains the m68k-specific time handling details.
* Most of the stuff is located in the machine specific files.
+ *
+ * 1997-09-10 Updated NTP code according to technical memorandum Jan '96
+ * "A Kernel Model for Precision Timekeeping" by Dave Mills
*/
#include <linux/config.h> /* CONFIG_HEARTBEAT */
@@ -65,9 +68,10 @@ static void timer_interrupt(int irq, void *dummy, struct pt_regs * regs)
* CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
* called as close as possible to 500 ms before the new second starts.
*/
- if (time_state != TIME_BAD && xtime.tv_sec > last_rtc_update + 660 &&
- xtime.tv_usec > 500000 - (tick >> 1) &&
- xtime.tv_usec < 500000 + (tick >> 1)) {
+ if ((time_status & STA_UNSYNC) == 0 &&
+ xtime.tv_sec > last_rtc_update + 660 &&
+ xtime.tv_usec >= 500000 - ((unsigned) tick) / 2 &&
+ xtime.tv_usec <= 500000 + ((unsigned) tick) / 2) {
if (set_rtc_mmss(xtime.tv_sec) == 0)
last_rtc_update = xtime.tv_sec;
else
@@ -146,27 +150,38 @@ void time_init(void)
mach_sched_init(timer_interrupt);
}
+extern rwlock_t xtime_lock;
+
/*
* This version of gettimeofday has near microsecond resolution.
*/
void do_gettimeofday(struct timeval *tv)
{
+ extern volatile unsigned long lost_ticks;
unsigned long flags;
-
- save_flags(flags);
- cli();
- *tv = xtime;
- tv->tv_usec += mach_gettimeoffset();
- if (tv->tv_usec >= 1000000) {
- tv->tv_usec -= 1000000;
- tv->tv_sec++;
+ unsigned long usec, sec, lost;
+
+ read_lock_irqsave(&xtime_lock, flags);
+ usec = mach_gettimeoffset();
+ lost = lost_ticks;
+ if (lost)
+ usec += lost * (1000000/HZ);
+ sec = xtime.tv_sec;
+ usec += xtime.tv_usec;
+ read_unlock_irqrestore(&xtime_lock, flags);
+
+ while (usec >= 1000000) {
+ usec -= 1000000;
+ sec++;
}
- restore_flags(flags);
+
+ tv->tv_sec = sec;
+ tv->tv_usec = usec;
}
void do_settimeofday(struct timeval *tv)
{
- cli();
+ write_lock_irq(&xtime_lock);
/* This is revolting. We need to set the xtime.tv_usec
* correctly. However, the value in this location is
* is value at the last tick.
@@ -175,14 +190,16 @@ void do_settimeofday(struct timeval *tv)
*/
tv->tv_usec -= mach_gettimeoffset();
- if (tv->tv_usec < 0) {
+ while (tv->tv_usec < 0) {
tv->tv_usec += 1000000;
tv->tv_sec--;
}
xtime = *tv;
- time_state = TIME_BAD;
- time_maxerror = MAXPHASE;
- time_esterror = MAXPHASE;
+ time_adjust = 0; /* stop active adjtime() */
+ time_status |= STA_UNSYNC;
+ time_state = TIME_ERROR; /* p. 24, (a) */
+ time_maxerror = NTP_PHASE_LIMIT;
+ time_esterror = NTP_PHASE_LIMIT;
sti();
}
diff --git a/arch/m68k/mac/config.c b/arch/m68k/mac/config.c
index f410182e0..8e902d0bd 100644
--- a/arch/m68k/mac/config.c
+++ b/arch/m68k/mac/config.c
@@ -55,9 +55,6 @@ extern char m68k_command_line[CL_SIZE];
void *mac_env; /* Loaded by the boot asm */
-/* The logical video addr. determined by head.S - testing */
-extern unsigned long mac_videobase;
-
/* The phys. video addr. - might be bogus on some machines */
unsigned long mac_orig_videoaddr;
@@ -65,7 +62,6 @@ unsigned long mac_orig_videoaddr;
extern int mac_keyb_init(void);
extern int mac_kbdrate(struct kbd_repeat *k);
extern void mac_kbd_leds(unsigned int leds);
-extern void mac_kbd_reset_setup(char*, int);
/* Mac specific irq functions */
extern void mac_init_IRQ (void);
@@ -100,17 +96,15 @@ extern void mac_debug_init(void);
extern void mac_debugging_long(int, long);
#ifdef CONFIG_MAGIC_SYSRQ
-
-/* XXX FIXME: Atari scancodes still */
static char mac_sysrq_xlate[128] =
- "\000\0331234567890-=\177\t" /* 0x00 - 0x0f */
- "qwertyuiop[]\r\000as" /* 0x10 - 0x1f */
- "dfghjkl;'`\000\\zxcv" /* 0x20 - 0x2f */
- "bnm,./\000\000\000 \000\201\202\203\204\205" /* 0x30 - 0x3f */
- "\206\207\210\211\212\000\000\000\000\000-\000\000\000+\000"/* 0x40 - 0x4f */
- "\000\000\000\177\000\000\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */
- "\000\000\000()/*789456123" /* 0x60 - 0x6f */
- "0.\r\000\000\000\000\000\000\000\000\000\000\000\000\000"; /* 0x70 - 0x7f */
+ "\000sdfghzxcv\000bqwer" /* 0x00 - 0x0f */
+ "yt123465=97-80)o" /* 0x10 - 0x1f */
+ "u(ip\rlj'k;\\,/nm." /* 0x20 - 0x2f */
+ "\t `\000\033\000\000\000\000\000\000\000\000\000\000\000" /* 0x30 - 0x3f */
+ "\000.\000*\000+\000\000\000\000\000/\r\000-\000" /* 0x40 - 0x4f */
+ "\000\00001234567a89\000\000\000" /* 0x50 - 0x5f */
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" /* 0x60 - 0x6f */
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"; /* 0x70 - 0x7f */
#endif
extern void (*kd_mksound)(unsigned int, unsigned int);
@@ -243,9 +237,7 @@ __initfunc(int mac_parse_bootinfo(const struct bi_record *record))
mac_bi_data.id = *data;
break;
case BI_MAC_VADDR:
- /* save booter supplied videobase; use the one mapped in head.S! */
- mac_orig_videoaddr = *data;
- mac_bi_data.videoaddr = mac_videobase;
+ mac_bi_data.videoaddr = VIDEOMEMBASE + (*data & ~VIDEOMEMMASK);
break;
case BI_MAC_VDEPTH:
mac_bi_data.videodepth = *data;
@@ -309,7 +301,6 @@ __initfunc(void config_mac(void))
mach_keyb_init = mac_keyb_init;
mach_kbdrate = mac_kbdrate;
mach_kbd_leds = mac_kbd_leds;
- kbd_reset_setup = mac_kbd_reset_setup;
mach_init_IRQ = mac_init_IRQ;
mach_request_irq = mac_request_irq;
mach_free_irq = mac_free_irq;
@@ -336,7 +327,7 @@ __initfunc(void config_mac(void))
#endif
kd_mksound = mac_mksound;
#ifdef CONFIG_MAGIC_SYSRQ
- mach_sysrq_key = 98; /* HELP */
+ mach_sysrq_key = 114; /* HELP */
mach_sysrq_shift_state = 8; /* Alt */
mach_sysrq_shift_mask = 0xff; /* all modifiers except CapsLock */
mach_sysrq_xlate = mac_sysrq_xlate;
@@ -399,10 +390,10 @@ static struct mac_model mac_data_table[]=
*
*/
- { MAC_MODEL_II, "II", MAC_ADB_II, MAC_VIA_II, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_NUBUS},
- { MAC_MODEL_IIX, "IIx", MAC_ADB_II, MAC_VIA_II, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_NUBUS},
- { MAC_MODEL_IICX, "IIcx", MAC_ADB_II, MAC_VIA_II, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_NUBUS},
- { MAC_MODEL_SE30, "SE/30", MAC_ADB_II, MAC_VIA_II, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_NUBUS},
+ { MAC_MODEL_II, "II", MAC_ADB_II, MAC_VIA_II, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
+ { MAC_MODEL_IIX, "IIx", MAC_ADB_II, MAC_VIA_II, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
+ { MAC_MODEL_IICX, "IIcx", MAC_ADB_II, MAC_VIA_II, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
+ { MAC_MODEL_SE30, "SE/30", MAC_ADB_II, MAC_VIA_II, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
/*
* Weirdified MacII hardware - all subtley different. Gee thanks
@@ -425,7 +416,7 @@ static struct mac_model mac_data_table[]=
*/
{ MAC_MODEL_CLII, "Classic II", MAC_ADB_IISI, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
- { MAC_MODEL_CCL, "Color Classic", MAC_ADB_IISI, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
+ { MAC_MODEL_CCL, "Color Classic", MAC_ADB_CUDA, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
/*
* Some Mac LC machines. Basically the same as the IIci, ADB like IIsi
@@ -461,11 +452,11 @@ static struct mac_model mac_data_table[]=
* Performa - more LC type machines
*/
- { MAC_MODEL_P460, "Performa 460", MAC_ADB_IISI, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
+ { MAC_MODEL_P460, "Performa 460", MAC_ADB_IISI, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
{ MAC_MODEL_P475, "Performa 475", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
{ MAC_MODEL_P475F, "Performa 475", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
{ MAC_MODEL_P520, "Performa 520", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
- { MAC_MODEL_P550, "Performa 550", MAC_ADB_CUDA, MAC_VIA_IIci, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
+ { MAC_MODEL_P550, "Performa 550", MAC_ADB_CUDA, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
{ MAC_MODEL_P575, "Performa 575", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
{ MAC_MODEL_P588, "Performa 588", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
{ MAC_MODEL_TV, "TV", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
@@ -477,8 +468,8 @@ static struct mac_model mac_data_table[]=
* Centris - just guessing again; maybe like Quadra
*/
- { MAC_MODEL_C610, "Centris 610", MAC_ADB_II, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS},
- { MAC_MODEL_C650, "Centris 650", MAC_ADB_II, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS},
+ { MAC_MODEL_C610, "Centris 610", MAC_ADB_II, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_SONIC, MAC_NUBUS},
+ { MAC_MODEL_C650, "Centris 650", MAC_ADB_II, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_SONIC, MAC_NUBUS},
{ MAC_MODEL_C660, "Centris 660AV", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA3, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS},
/*
@@ -551,7 +542,7 @@ void mac_identify(void)
m++;
}
if(m->ident==-1)
- mac_boom(5);
+ panic("mac model config data corrupt!\n");
}
/*
diff --git a/arch/m68k/mac/debug.c b/arch/m68k/mac/debug.c
index 62a8a6187..5aa7ce6cf 100644
--- a/arch/m68k/mac/debug.c
+++ b/arch/m68k/mac/debug.c
@@ -36,7 +36,10 @@ extern unsigned long mac_videobase;
extern unsigned long mac_videodepth;
extern unsigned long mac_rowbytes;
-#define DEBUG_SCREEN
+extern void mac_serial_print(char *);
+
+#define DEBUG_HEADS
+#undef DEBUG_SCREEN
#define DEBUG_SERIAL
/*
@@ -129,121 +132,6 @@ void mac_debugging_long(int pos, long addr)
#endif
}
-/*
- * Penguin - used by head.S console; obsolete
- */
-char that_penguin[]={
-#include "that_penguin.h"
-};
-
-#ifdef DEBUG_SCREEN
-/*
- * B/W version of penguin, unfinished - any takers??
- */
-static char bw_penguin[]={
-#include "bw_penguin.h"
-};
-#endif
-
-void mac_debugging_penguin(int peng)
-{
-#ifdef DEBUG_SCREEN
- unsigned char *pengoffset;
- unsigned char *pptr;
- unsigned char *bwpdptr=bw_penguin;
- int i;
-#endif
-
-#ifdef DEBUG_SERIAL
- printk("Penguin: #%d !\n", peng);
-#endif
-
-#ifdef DEBUG_SCREEN
- if (!MACH_IS_MAC)
- return;
-
- if (mac_videodepth ==1)
- pengoffset=(unsigned char *)(mac_videobase+80*mac_rowbytes)
- +5*peng;
- else
- pengoffset=(unsigned char *)(mac_videobase+80*mac_rowbytes)
- +20*peng;
-
- pptr=pengoffset;
-
- for(i=0;i<36;i++)
- {
- memcpy(pptr,bwpdptr,4);
- bwpdptr+=4;
- pptr+=mac_rowbytes;
- }
-#endif
-}
-
-#ifdef DEBUG_SCREEN
-/*
- * B/W version of flaming Mac, unfinished (see above).
- */
-static char bw_kaboom_map[]={
-#include "bw_mac.h"
-};
-#endif
-
-#ifdef DEBUG_SCREEN
-static void mac_boom_boom(void)
-{
- static unsigned char *boomoffset=NULL;
- unsigned char *pptr;
- unsigned char *bwpdptr=bw_kaboom_map;
- int i;
-
-#ifdef DEBUG_SERIAL
- printk("BOOM !\n");
-#endif
-
- if (!MACH_IS_MAC)
- return;
-
- if(!boomoffset)
- if (mac_videodepth == 1) {
- boomoffset=(unsigned char *)(mac_videobase+160*mac_rowbytes);
- } else {
- boomoffset=(unsigned char *)(mac_videobase+256*mac_rowbytes);
- }
- else
- if (mac_videodepth == 1)
- boomoffset+=5;
- else
- boomoffset+=32;
-
- pptr=boomoffset;
-
- for(i=0;i<36;i++)
- {
- memcpy(pptr,bwpdptr,4);
- bwpdptr+=4;
- pptr+=mac_rowbytes;
- }
-}
-#endif
-
-void mac_boom(int booms)
-{
-#ifdef DEBUG_SCREEN
- int i;
-#endif
-
- if (!MACH_IS_MAC)
- return;
-
-#ifdef DEBUG_SCREEN
- for(i=0;i<booms;i++)
- mac_boom_boom();
- while(1);
-#endif
-}
-
-
#ifdef DEBUG_SERIAL
/*
* TODO: serial debug code
@@ -284,6 +172,29 @@ static struct console mac_console_driver = {
NULL
};
+/*
+ * Crude hack to get console output to the screen before the framebuffer
+ * is initialized (happens a lot later in 2.1!).
+ * We just use the console routines declared in head.S, this will interfere
+ * with regular framebuffer console output and should be used exclusively
+ * to debug kernel problems manifesting before framebuffer init (aka WSOD)
+ *
+ * To keep this hack from interfering with the regular console driver, either
+ * deregister this driver before/on framebuffer console init, or silence this
+ * function after the fbcon driver is running (will lose console messages!?).
+ * To debug real early bugs, need to write a 'mac_register_console_hack()'
+ * that is called from start_kernel() before setup_arch() and just registers
+ * this driver if Mac.
+ */
+
+void mac_debug_console_write (struct console *co, const char *str,
+ unsigned int count)
+{
+ mac_serial_print(str);
+}
+
+
+
/* Mac: loops_per_sec min. 1900000 ^= .5 us; MFPDELAY was 0.6 us*/
#define uSEC 1
@@ -486,19 +397,30 @@ __initfunc(void mac_debug_init(void))
/* Mac modem port */
mac_init_scc_port( B9600|CS8, 0 );
mac_console_driver.write = mac_scca_console_write;
+#ifdef CONFIG_SERIAL_CONSOLE
mac_console_driver.wait_key = mac_scca_console_wait_key;
+#endif
scc_port = 0;
}
else if (!strcmp( m68k_debug_device, "ser2" )) {
/* Mac printer port */
mac_init_scc_port( B9600|CS8, 1 );
mac_console_driver.write = mac_sccb_console_write;
+#ifdef CONFIG_SERIAL_CONSOLE
mac_console_driver.wait_key = mac_sccb_console_wait_key;
+#endif
scc_port = 1;
}
+#endif
+#ifdef DEBUG_HEADS
+ if ( !strcmp( m68k_debug_device, "scn" )
+ || !strcmp( m68k_debug_device, "con" )) {
+ /* display, using head.S console routines */
+ mac_console_driver.write = mac_debug_console_write;
+ }
+#endif
if (mac_console_driver.write)
register_console(&mac_console_driver);
-#endif
}
/*
diff --git a/arch/m68k/mac/macboing.c b/arch/m68k/mac/macboing.c
index 95078a384..1731c929c 100644
--- a/arch/m68k/mac/macboing.c
+++ b/arch/m68k/mac/macboing.c
@@ -1,6 +1,12 @@
/*
* Mac bong noise generator. Note - we ought to put a boingy noise
* here 8)
+ *
+ * ----------------------------------------------------------------------
+ * 16.11.98:
+ * rewrote some functions, added support for Enhanced ASC (Quadras)
+ * after the NetBSD asc.c console bell patch by Colin Wood/Frederick Bruck
+ * Juergen Mellinger (juergen.mellinger@t-online.de)
*/
#include <linux/sched.h>
@@ -9,124 +15,281 @@
#include <asm/macintosh.h>
#include <asm/mac_asc.h>
+static int mac_asc_inited = 0;
+/*
+ * dumb triangular wave table
+ */
+static __u8 mac_asc_wave_tab[ 0x800 ];
+
+/*
+ * Alan's original sine table; needs interpolating to 0x800
+ * (hint: interpolate or hardwire [0 -> Pi/2[, it's symmetric)
+ */
static const signed char sine_data[] = {
0, 39, 75, 103, 121, 127, 121, 103, 75, 39,
0, -39, -75, -103, -121, -127, -121, -103, -75, -39
};
-#define DATA_SIZE (sizeof(sine_data)/sizeof(sine_data[0]))
-static void nosound( unsigned long ignored );
-static struct timer_list sound_timer = { NULL, NULL, 0, 0, nosound };
+/*
+ * where the ASC hides ...
+ */
+static volatile __u8* mac_asc_regs = ( void* )0x50F14000;
-static volatile unsigned char *asc_base=(void *)0x50F14000;
+/*
+ * sample rate; is this a good default value?
+ */
+static unsigned long mac_asc_samplespersec = 11050;
+static int mac_bell_duration = 0;
+static unsigned long mac_bell_phase; /* 0..2*Pi -> 0..0x800 (wavetable size) */
+static unsigned long mac_bell_phasepersample;
+
+/*
+ * some function protos
+ */
+static void mac_init_asc( void );
+static void mac_nosound( unsigned long );
+static void mac_quadra_start_bell( unsigned int, unsigned int, unsigned int );
+static void mac_quadra_ring_bell( unsigned long );
+static void mac_av_start_bell( unsigned int, unsigned int, unsigned int );
+static void ( *mac_special_bell )( unsigned int, unsigned int, unsigned int ) = NULL;
+/*
+ * our timer to start/continue/stop the bell
+ */
+static struct timer_list mac_sound_timer = { NULL, NULL, 0, 0, mac_nosound };
-void mac_mksound( unsigned int hz, unsigned int ticks )
+/*
+ * Sort of initialize the sound chip (called from mac_mksound on the first
+ * beep).
+ */
+static void mac_init_asc( void )
{
- static int inited = 0;
- unsigned long flags;
- int samples=512;
+ int i;
- if (macintosh_config->ident == MAC_MODEL_C660
- || macintosh_config->ident == MAC_MODEL_Q840)
+ /*
+ * do some machine specific initialization
+ * BTW:
+ * the NetBSD Quadra patch identifies the Enhanced Apple Sound Chip via
+ * mac_asc_regs[ 0x800 ] & 0xF0 != 0
+ * this makes no sense here, because we have to set the default sample
+ * rate anyway if we want correct frequencies
+ */
+ switch ( macintosh_config->ident )
{
- /*
- * The Quadra 660AV and 840AV use the "Singer" custom ASIC for sound I/O.
- * It appears to be similar to the "AWACS" custom ASIC in the Power Mac
- * [678]100. Because Singer and AWACS may have a similar hardware
- * interface, this would imply that the code in drivers/sound/dmasound.c
- * for AWACS could be used as a basis for Singer support. All we have to
- * do is figure out how to do DMA on the 660AV/840AV through the PSC and
- * figure out where the Singer hardware sits in memory. (I'd look in the
- * vicinity of the AWACS location in a Power Mac [678]100 first, or the
- * current location of the Apple Sound Chip--ASC--in other Macs.) The
- * Power Mac [678]100 info can be found in MkLinux Mach kernel sources.
- *
- * Quoted from Apple's Tech Info Library, article number 16405:
- * "Among desktop Macintosh computers, only the 660AV, 840AV, and Power
- * Macintosh models have 16-bit audio input and output capability
- * because of the AT&T DSP3210 hardware circuitry and the 16-bit Singer
- * codec circuitry in the AVs. The Audio Waveform Amplifier and
- * Converter (AWAC) chip in the Power Macintosh performs the same
- * 16-bit I/O functionality. The PowerBook 500 series computers
- * support 16-bit stereo output, but only mono input."
- *
- * http://til.info.apple.com/techinfo.nsf/artnum/n16405
- *
- * --David Kilzer
- */
+ case MAC_MODEL_IIFX:
+ /*
+ * The IIfx is always special ...
+ */
+ mac_asc_regs = ( void* )0x50010000;
+ break;
+ /*
+ * not sure about how correct this list is
+ * machines with the EASC enhanced apple sound chip
+ */
+ case MAC_MODEL_Q630:
+ case MAC_MODEL_P475:
+ mac_special_bell = mac_quadra_start_bell;
+ mac_asc_samplespersec = 22150;
+ break;
+ case MAC_MODEL_Q650:
+ case MAC_MODEL_Q700:
+ case MAC_MODEL_Q800:
+ case MAC_MODEL_Q900:
+ case MAC_MODEL_Q950:
+ /*
+ * Currently not implemented!
+ */
+ /*
+ * The Quadra 660AV and 840AV use the "Singer" custom ASIC for sound I/O.
+ * It appears to be similar to the "AWACS" custom ASIC in the Power Mac
+ * [678]100. Because Singer and AWACS may have a similar hardware
+ * interface, this would imply that the code in drivers/sound/dmasound.c
+ * for AWACS could be used as a basis for Singer support. All we have to
+ * do is figure out how to do DMA on the 660AV/840AV through the PSC and
+ * figure out where the Singer hardware sits in memory. (I'd look in the
+ * vicinity of the AWACS location in a Power Mac [678]100 first, or the
+ * current location of the Apple Sound Chip--ASC--in other Macs.) The
+ * Power Mac [678]100 info can be found in MkLinux Mach kernel sources.
+ *
+ * Quoted from Apple's Tech Info Library, article number 16405:
+ * "Among desktop Macintosh computers, only the 660AV, 840AV, and Power
+ * Macintosh models have 16-bit audio input and output capability
+ * because of the AT&T DSP3210 hardware circuitry and the 16-bit Singer
+ * codec circuitry in the AVs. The Audio Waveform Amplifier and
+ * Converter (AWAC) chip in the Power Macintosh performs the same
+ * 16-bit I/O functionality. The PowerBook 500 series computers
+ * support 16-bit stereo output, but only mono input."
+ *
+ * http://til.info.apple.com/techinfo.nsf/artnum/n16405
+ *
+ * --David Kilzer
+ */
+ mac_special_bell = mac_av_start_bell;
+ break;
+ }
+
+ /*
+ * init the wave table with a simple triangular wave
+ * A sine wave would sure be nicer here ...
+ */
+ for ( i = 0; i < 0x400; i++ )
+ {
+ mac_asc_wave_tab[ i ] = i / 4;
+ mac_asc_wave_tab[ i + 0x400 ] = 0xFF - i / 4;
+ }
+ mac_asc_inited = 1;
+}
+/*
+ * Called to make noise; current single entry to the boing driver.
+ * Does the job for simple ASC, calls other routines else.
+ * XXX Fixme:
+ * Should be split into asc_mksound, easc_mksound, av_mksound and
+ * function pointer set in mac_init_asc which would be called at
+ * init time.
+ * _This_ is rather ugly ...
+ */
+void mac_mksound( unsigned int freq, unsigned int length )
+{
+ __u32 cfreq = ( freq << 5 ) / 468;
+ __u32 flags;
+ int i;
+
+ if ( !mac_asc_inited )
+ mac_init_asc();
+
+ if ( mac_special_bell )
+ {
+ mac_special_bell( freq, length, 128 );
return;
}
-
- if(!inited)
+
+ if ( freq < 20 || freq > 20000 || length == 0 )
{
- int i=0;
- int j=0;
- int k=0;
- int l=0;
-
- /*
- * The IIfx strikes again!
- */
-
- if(macintosh_config->ident==MAC_MODEL_IIFX)
- asc_base=(void *)0x50010000;
-
- for(i=0;i<samples;i++)
- {
- asc_base[i]=sine_data[j];
- asc_base[i+512]=sine_data[j];
- asc_base[i+1024]=sine_data[j];
- asc_base[i+1536]=sine_data[j];
- j++;
- if(j==DATA_SIZE)
- j=0;
- if(i&1)
- k++;
- if(k==DATA_SIZE)
- k=0;
- if((i&3)==3)
- l++;
- if(l==DATA_SIZE)
- l=0;
- }
- inited=1;
+ mac_nosound( 0 );
+ return;
}
- save_flags(flags);
+
+ save_flags( flags );
cli();
- del_timer( &sound_timer );
- if (hz > 20 && hz < 32767) {
- int i;
- u_long asc_pulses=((hz<<5)*samples)/468;
- for(i=0;i<4;i++)
+ del_timer( &mac_sound_timer );
+
+ for ( i = 0; i < 0x800; i++ )
+ mac_asc_regs[ i ] = 0;
+ for ( i = 0; i < 0x800; i++ )
+ mac_asc_regs[ i ] = mac_asc_wave_tab[ i ];
+
+ for ( i = 0; i < 8; i++ )
+ *( __u32* )( ( __u32 )mac_asc_regs + ASC_CONTROL + 0x814 + 8 * i ) = cfreq;
+
+ mac_asc_regs[ 0x807 ] = 0;
+ mac_asc_regs[ ASC_VOLUME ] = 128;
+ mac_asc_regs[ 0x805 ] = 0;
+ mac_asc_regs[ 0x80F ] = 0;
+ mac_asc_regs[ ASC_MODE ] = ASC_MODE_SAMPLE;
+ mac_asc_regs[ ASC_ENABLE ] = ASC_ENABLE_SAMPLE;
+
+ mac_sound_timer.expires = jiffies + length;
+ add_timer( &mac_sound_timer );
+
+ restore_flags( flags );
+}
+
+/*
+ * regular ASC: stop whining ..
+ */
+static void mac_nosound( unsigned long ignored )
+{
+ mac_asc_regs[ ASC_ENABLE ] = 0;
+}
+
+/*
+ * EASC entry; init EASC, don't load wavetable, schedule 'start whining'.
+ */
+static void mac_quadra_start_bell( unsigned int freq, unsigned int length, unsigned int volume )
+{
+ __u32 flags;
+
+ /* if the bell is already ringing, ring longer */
+ if ( mac_bell_duration > 0 )
+ {
+ mac_bell_duration += length;
+ return;
+ }
+
+ mac_bell_duration = length;
+ mac_bell_phase = 0;
+ mac_bell_phasepersample = ( freq * sizeof( mac_asc_wave_tab ) ) / mac_asc_samplespersec;
+ /* this is reasonably big for small frequencies */
+
+ save_flags( flags );
+ cli();
+
+ /* set the volume */
+ mac_asc_regs[ 0x806 ] = volume;
+
+ /* set up the ASC registers */
+ if ( mac_asc_regs[ 0x801 ] != 1 )
+ {
+ /* select mono mode */
+ mac_asc_regs[ 0x807 ] = 0;
+ /* select sampled sound mode */
+ mac_asc_regs[ 0x802 ] = 0;
+ /* ??? */
+ mac_asc_regs[ 0x801 ] = 1;
+ mac_asc_regs[ 0x803 ] |= 0x80;
+ mac_asc_regs[ 0x803 ] &= 0x7F;
+ }
+
+ mac_sound_timer.function = mac_quadra_ring_bell;
+ mac_sound_timer.expires = jiffies + 1;
+ add_timer( &mac_sound_timer );
+
+ restore_flags( flags );
+}
+
+/*
+ * EASC 'start/continue whining'; I'm not sure why the above function didn't
+ * already load the wave table, or at least call this one...
+ * This piece keeps reloading the wave table until done.
+ */
+static void mac_quadra_ring_bell( unsigned long ignored )
+{
+ int i, count = mac_asc_samplespersec / HZ;
+ __u32 flags;
+
+ /*
+ * we neither want a sound buffer overflow nor underflow, so we need to match
+ * the number of samples per timer interrupt as exactly as possible.
+ * using the asc interrupt will give better results in the future
+ * ...and the possibility to use a real sample (a boingy noise, maybe...)
+ */
+
+ save_flags( flags );
+ cli();
+
+ del_timer( &mac_sound_timer );
+
+ if ( mac_bell_duration-- > 0 )
+ {
+ for ( i = 0; i < count; i++ )
{
- asc_base[ASC_FREQ(i,0)]=0x00;
- asc_base[ASC_FREQ(i,1)]=20;
- asc_base[ASC_FREQ(i,2)]=0x00;
- asc_base[ASC_FREQ(i,3)]=20;
- asc_base[ASC_FREQ(i,4)]=(asc_pulses>>24)&0xFF;
- asc_base[ASC_FREQ(i,5)]=(asc_pulses>>16)&0xFF;
- asc_base[ASC_FREQ(i,6)]=(asc_pulses>>8)&0xFF;
- asc_base[ASC_FREQ(i,7)]=(asc_pulses>>0)&0xFF;
+ mac_bell_phase += mac_bell_phasepersample;
+ mac_asc_regs[ 0 ] = mac_asc_wave_tab[ mac_bell_phase & ( sizeof( mac_asc_wave_tab ) - 1 ) ];
}
- asc_base[ASC_CHAN]=0x03;
- asc_base[ASC_VOLUME]=128;
- asc_base[ASC_MODE]=ASC_MODE_SAMPLE;
- asc_base[ASC_ENABLE]=ASC_ENABLE_SAMPLE;
- if (ticks) {
- sound_timer.expires = jiffies + ticks;
- add_timer( &sound_timer );
- }
- } else {
- nosound( 0 );
+ mac_sound_timer.expires = jiffies + 1;
+ add_timer( &mac_sound_timer );
}
- restore_flags(flags);
+ else
+ mac_asc_regs[ 0x801 ] = 0;
+
+ restore_flags( flags );
}
-
-static void nosound( unsigned long ignored )
+/*
+ * AV code - please fill in.
+ */
+static void mac_av_start_bell( unsigned int freq, unsigned int length, unsigned int volume )
{
- asc_base[ASC_ENABLE]=0;
-}
+}
diff --git a/arch/m68k/mac/macints.c b/arch/m68k/mac/macints.c
index b703cb275..87e6692d4 100644
--- a/arch/m68k/mac/macints.c
+++ b/arch/m68k/mac/macints.c
@@ -163,7 +163,14 @@ static unsigned long nubus_irqs[8];
static unsigned long *mac_irqs[8];
/*
- * VIA2 / RBV register base pointers
+ * Some special nutcases ...
+ */
+
+static unsigned long mac_ide_irqs = 0;
+static unsigned long nubus_stuck_events = 0;
+
+/*
+ * VIA/RBV/OSS/PSC register base pointers
*/
volatile unsigned char *via2_regp=(volatile unsigned char *)VIA2_BAS;
@@ -217,9 +224,13 @@ void mac_debug_handler(int irq, void *dev_id, struct pt_regs *regs);
static void via_do_nubus(int slot, void *via, struct pt_regs *regs);
/* #define DEBUG_MACINTS */
-/* #define DEBUG_NUBUS_INT */
+
+#define DEBUG_SPURIOUS
+#define DEBUG_NUBUS_SPURIOUS
+#define DEBUG_NUBUS_INT
+
/* #define DEBUG_VIA */
-/* #define DEBUG_VIA_NUBUS */
+#define DEBUG_VIA_NUBUS
void mac_init_IRQ(void)
{
@@ -247,7 +258,7 @@ void mac_init_IRQ(void)
/* yes, this is messy - the IIfx deserves a class of his own */
if (macintosh_config->ident == MAC_MODEL_IIFX) {
- /* no real VIA2, the OSS seems _very_different */
+ /* no real VIA2, the OSS seems _very_ different */
via2_is_oss = 1;
/* IIfx has OSS, at a different base address than RBV */
rbv_regp = (unsigned char *) OSS_BAS;
@@ -351,6 +362,12 @@ void mac_init_IRQ(void)
mac_irqs[7] = &nubus_irqs[0];
/*
+ * Nubus Macs: turn off the Nubus dispatch interrupt for now
+ */
+
+ mac_turnoff_irq(IRQ_MAC_NUBUS);
+
+ /*
* AV Macs: shutup the PSC ints
*/
if (macintosh_config->ident == MAC_MODEL_C660
@@ -430,8 +447,10 @@ int mac_request_irq (unsigned int irq, void (*handler)(int, void *, struct pt_re
return 0;
}
- /* add similar hack for Nubus pseudo-irq here - hide nubus_request_irq */
-
+ /*
+ * code below: only for VIA irqs currently
+ * add similar hack for Nubus pseudo-irq here - hide nubus_request_irq
+ */
via = (volatile unsigned char *) via_table[srcidx];
if (!via)
return -EINVAL;
@@ -459,7 +478,7 @@ int mac_request_irq (unsigned int irq, void (*handler)(int, void *, struct pt_re
if (irq == IRQ_IDX(IRQ_MAC_SCSI)) {
/*
* Set vPCR for SCSI interrupts. (what about RBV here?)
- * 980429 MS: RBV is ok, OSS seems to be differentt
+ * 980429 MS: RBV is ok, OSS seems to be different
*/
if (!via2_is_oss)
if (macintosh_config->scsi_type == MAC_SCSI_OLD) {
@@ -602,7 +621,10 @@ void mac_disable_irq (unsigned int irq)
/*
* In opposite to {en,dis}able_irq, requests between turn{off,on}_irq are not
- * "stored". This is done with the VIA interrupt enable register
+ * "stored". This is done with the VIA interrupt enable register on VIAs.
+ *
+ * Note: Using these functions on non-VIA/OSS/PSC ints will panic, or at least
+ * have undesired side effects.
*/
void mac_turnon_irq( unsigned int irq )
@@ -615,14 +637,14 @@ void mac_turnon_irq( unsigned int irq )
if (!via)
return;
- if (srcidx == SRC_VIA2 && via2_is_rbv)
+ if (srcidx == SRC_VIA2 && via2_is_rbv) /* RBV as VIA2 */
via_write(via, rIER, via_read(via, rIER)|0x80|(1<<(irqidx)));
- else if (srcidx == SRC_VIA2 && via2_is_oss)
+ else if (srcidx == SRC_VIA2 && via2_is_oss) /* OSS */
via_write(oss_regp, oss_map[irqidx]+8, 2);
- else if (srcidx > SRC_VIA2)
+ else if (srcidx > SRC_VIA2) /* hope AVs have VIA2 */
via_write(via, (0x104 + 0x10*srcidx),
via_read(via, (0x104 + 0x10*srcidx))|0x80|(1<<(irqidx)));
- else
+ else /* VIA1+2 */
via_write(via, vIER, via_read(via, vIER)|0x80|(1<<(irqidx)));
}
@@ -637,9 +659,9 @@ void mac_turnoff_irq( unsigned int irq )
if (!via)
return;
- if (srcidx == SRC_VIA2 && via2_is_rbv)
+ if (srcidx == SRC_VIA2 && via2_is_rbv) /* RBV as VIA2 */
via_write(via, rIER, (via_read(via, rIER)&(1<<irqidx)));
- else if (srcidx == SRC_VIA2 && via2_is_oss)
+ else if (srcidx == SRC_VIA2 && via2_is_oss) /* OSS */
via_write(oss_regp, oss_map[irqidx]+8, 0);
/*
* VIA2 is fixed. The stuff above VIA2 is for later
@@ -648,7 +670,7 @@ void mac_turnoff_irq( unsigned int irq )
else if (srcidx > SRC_VIA2)
via_write(via, (0x104 + 0x10*srcidx),
via_read(via, (0x104 + 0x10*srcidx))|(1<<(irqidx)));
- else
+ else /* VIA1+2 */
via_write(via, vIER, (via_read(via, vIER)&(1<<irqidx)));
}
@@ -694,12 +716,18 @@ int mac_irq_pending( unsigned int irq )
return (pending);
}
+/*
+ * for /proc/interrupts: log interrupt stats broken down by
+ * autovector int first, then by actual interrupt source.
+ */
+
int mac_get_irq_list (char *buf)
{
int i, len = 0;
int srcidx, irqidx;
for (i = VIA1_SOURCE_BASE; i < NUM_MAC_SOURCES+8; ++i) {
+ /* XXX fixme: IRQ_SRC_MASK should cover VIA1 - Nubus */
srcidx = ((i & IRQ_SRC_MASK)>>3) - 1;
irqidx = (i & IRQ_IDX_MASK);
@@ -764,6 +792,32 @@ int mac_get_irq_list (char *buf)
}
if (num_spurious)
len += sprintf(buf+len, "spurio.: %10u\n", num_spurious);
+
+ /*
+ * XXX Fixme: Nubus sources are never logged above ...
+ */
+
+ len += sprintf(buf+len, "Nubus interrupts:\n");
+
+ for (i = 0; i < 7; i++) {
+ if (nubus_handler[i].handler == nubus_wtf)
+ continue;
+ len += sprintf(buf+len, "nubus %01X: %10lu ",
+ i+9,
+ nubus_irqs[i]);
+ len += sprintf(buf+len, "%s\n",
+ nubus_param[i].devname);
+
+ }
+ len += sprintf(buf+len, "nubus spurious ints: %10lu\n",
+ nubus_irqs[7]);
+ len += sprintf(buf+len, "nubus stuck events : %10lu\n",
+ nubus_stuck_events);
+#ifdef CONFIG_BLK_DEV_IDE
+ len += sprintf(buf+len, "nubus/IDE interrupt: %10lu\n",
+ mac_ide_irqs);
+#endif
+
return len;
}
@@ -784,8 +838,9 @@ void via_scsi_clear(void)
void mac_default_handler(int irq, void *dev_id, struct pt_regs *regs)
{
-#ifdef DEBUG_VIA
- printk("Unexpected IRQ %d\n", irq);
+#ifdef DEBUG_SPURIOUS
+ if (console_loglevel > 6)
+ printk("Unexpected IRQ %d on device %p\n", irq, dev_id);
#endif
}
@@ -861,6 +916,18 @@ void mac_nmi_handler(int irq, void *dev_id, struct pt_regs *fp)
}
/*
+ * Unexpected via interrupt
+ */
+
+void via_wtf(int slot, void *via, struct pt_regs *regs)
+{
+#ifdef DEBUG_SPURIOUS
+ if (console_loglevel > 6)
+ printk("Unexpected nubus event %d on via %p\n",slot,via);
+#endif
+}
+
+/*
* The generic VIA interrupt routines (shamelessly stolen from Alan Cox's
* via6522.c :-), disable/pending masks added.
* The int *viaidx etc. is just to keep the prototype happy ...
@@ -1115,17 +1182,6 @@ void rbv_irq(int irq, void *dev_id, struct pt_regs *regs)
}
/*
- * Unexpected via interrupt
- */
-
-void via_wtf(int slot, void *via, struct pt_regs *regs)
-{
-#ifdef DEBUG_VIA
- printk("Unexpected event %d on via %p\n",slot,via);
-#endif
-}
-
-/*
* Nubus / SCSI interrupts; OSS style
* The OSS is even more different than the RBV. OSS appears to stand for
* Obscenely Screwed Silicon ...
@@ -1264,8 +1320,9 @@ void oss_irq(int irq, void *dev_id, struct pt_regs *regs)
void nubus_wtf(int slot, void *via, struct pt_regs *regs)
{
-#ifdef DEBUG_VIA_NUBUS
- printk("Unexpected interrupt on nubus slot %d\n",slot);
+#ifdef DEBUG_NUBUS_SPURIOUS
+ if (console_loglevel > 6)
+ printk("Unexpected interrupt on nubus slot %d\n",slot);
#endif
}
@@ -1279,9 +1336,10 @@ void mac_SCC_handler(int irq, void *dev_id, struct pt_regs *regs)
int i;
/* 1+2: compatibility with PSC ! */
for (i = 1; i < 3; i++) /* currently only these two used */
- if (scc_handler[i].handler != mac_default_handler)
+ if (scc_handler[i].handler != mac_default_handler) {
(scc_handler[i].handler)(i, scc_handler[i].dev_id, regs);
-
+ scc_irqs[i]++;
+ }
}
/*
@@ -1310,7 +1368,7 @@ void psc_irq(int irq, void *dev_id, struct pt_regs *regs)
if(events==0)
{
#ifdef DEBUG_VIA
- printk("rbv_irq: nothing pending, flags %x mask %x!\n",
+ printk("psc_irq: nothing pending, flags %x mask %x!\n",
via_read(via, pIFR), via_read(via,pIER));
#endif
mac_irqs[srcidx][7]++;
@@ -1319,7 +1377,7 @@ void psc_irq(int irq, void *dev_id, struct pt_regs *regs)
#ifdef DEBUG_VIA
/*
- * limited verbosity for RBV interrupts (add more if needed)
+ * limited verbosity for PSC interrupts (add more if needed)
*/
if ( srcidx == 1 && events != 1<<3 && events != 1<<1 ) /* SCSI IRQ */
printk("psc_irq: irq %d srcidx+1 %d events %x !\n", irq, srcidx+1, events);
@@ -1423,6 +1481,7 @@ int nubus_request_irq(int slot, void *dev_id, void (*handler)(int,void *,struct
if (!nubus_active && !via2_is_oss) {
request_irq(IRQ_MAC_NUBUS, via_do_nubus, IRQ_FLG_LOCK,
"nubus dispatch", via_do_nubus);
+ mac_turnon_irq(IRQ_MAC_NUBUS);
}
nubus_active|=1<<slot;
@@ -1472,6 +1531,7 @@ int nubus_free_irq(int slot)
* IDE interrupt hook
*/
extern void (*mac_ide_intr_hook)(int, void *, struct pt_regs *);
+extern int (*mac_ide_irq_p_hook)(void);
#endif
/*
@@ -1479,13 +1539,13 @@ extern void (*mac_ide_intr_hook)(int, void *, struct pt_regs *);
*/
static void via_do_nubus(int slot, void *via, struct pt_regs *regs)
{
- unsigned char map;
+ unsigned char map, allints;
int i;
int ct=0;
-
-/* printk("nubus interrupt\n");*/
+ int ide_pending = 0;
/* lock the nubus interrupt */
+ /* That's just 'clear Nubus IRQ bit in VIA2' BTW. Pretty obsolete ? */
if (via2_is_rbv)
via_write(rbv_regp, rIFR, 0x82);
else
@@ -1493,36 +1553,69 @@ static void via_do_nubus(int slot, void *via, struct pt_regs *regs)
#ifdef CONFIG_BLK_DEV_MAC_IDE
/* IDE hack */
- if (mac_ide_intr_hook)
+ if (mac_ide_intr_hook) {
/* 'slot' is lacking the machspec bit in 2.0 */
/* need to pass proper dev_id = hwgroup here */
mac_ide_intr_hook(IRQ_MAC_NUBUS, via, regs);
+ mac_ide_irqs++;
+ }
#endif
while(1)
{
if (via2_is_rbv)
- map = ~via_read(rbv_regp, rBufA);
+ allints = ~via_read(rbv_regp, rBufA);
else
- map = ~via_read(via2_regp, vBufA);
+ allints = ~via_read(via2_regp, vBufA);
- if( (map = (map&nubus_active)) ==0 ) {
-#ifdef DEBUG_NUBUS_INT
- printk("nubus_irq: nothing pending, map %x mask %x\n",
- map, nubus_active);
+#ifdef CONFIG_BLK_DEV_MAC_IDE
+ if (mac_ide_irq_p_hook)
+ ide_pending = mac_ide_irq_p_hook();
+#endif
+
+ if ( (map = (allints&nubus_active)) == 0
+#ifdef CONFIG_BLK_DEV_MAC_IDE
+ && !ide_pending
#endif
- nubus_irqs[7]++;
+ )
+ {
+ if (ct == 0) {
+#ifdef DEBUG_VIA_NUBUS
+ if (console_loglevel > 5)
+ printk("nubus_irq: nothing pending, map %x mask %x active %x\n",
+ allints, nubus_active, map);
+#endif
+ nubus_irqs[7]++;
+ }
+ /* clear it */
+ if (allints)
+ if (via2_is_rbv)
+ via_write(rbv_regp, rIFR, 0x02);
+ else
+ via_write(via2_regp, vIFR, 0x02);
break;
}
-#ifdef DEBUG_NUBUS_INT
- printk("nubus_irq: map %x mask %x\n", map, nubus_active);
+
+#ifdef DEBUG_VIA_NUBUS
+ if (console_loglevel > 6)
+ printk("nubus_irq: map %x mask %x active %x\n",
+ allints, nubus_active, map);
+#endif
+
+#ifdef CONFIG_BLK_DEV_MAC_IDE
+ if (mac_ide_intr_hook && ide_pending) {
+ mac_ide_intr_hook(IRQ_MAC_NUBUS, via, regs);
+ mac_ide_irqs++;
+ }
#endif
if(ct++>2)
{
-#ifdef DEBUG_NUBUS_INT
- printk("nubus stuck events - %d/%d\n", map, nubus_active);
-#endif
+ if (console_loglevel > 5)
+ printk("nubus stuck events - %x/%x/%x ide %x\n",
+ allints, nubus_active, map, ide_pending);
+ nubus_stuck_events++;
+
return;
}
@@ -1579,12 +1672,14 @@ static void oss_do_nubus(int slot, void *via, struct pt_regs *regs)
printk("nubus_irq: map %x mask %x\n", map, nubus_active);
#endif
if( (map = (map&nubus_active)) ==0 ) {
+ if (ct == 0) {
#ifdef CONFIG_BLK_DEV_MAC_IDE
- if (!mac_ide_intr_hook)
- printk("nubus_irq: nothing pending, map %x mask %x\n",
- map, nubus_active);
+ if (!mac_ide_intr_hook)
+ printk("nubus_irq: nothing pending, map %x mask %x\n",
+ map, nubus_active);
#endif
- nubus_irqs[7]++;
+ nubus_irqs[7]++;
+ }
break;
}
diff --git a/arch/m68k/mac/mackeyb.c b/arch/m68k/mac/mackeyb.c
index 64cd5e1f8..5a6ae7c75 100644
--- a/arch/m68k/mac/mackeyb.c
+++ b/arch/m68k/mac/mackeyb.c
@@ -1,5 +1,12 @@
/*
- * linux/arch/m68k/mac/mackeyb.c
+ * linux/arch/m68k/mac/mackeyb.c
+ *
+ * Keyboard driver for Macintosh computers.
+ *
+ * Adapted from drivers/macintosh/key_mac.c and arch/m68k/atari/akakeyb.c
+ * (see that file for its authors and contributors).
+ *
+ * Copyright (C) 1997 Michael Schmitz.
*
* 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
@@ -10,6 +17,7 @@
* misc. keyboard stuff (everything not in adb-bus.c or keyb_m68k.c)
*/
+#include <linux/config.h>
#include <linux/types.h>
#include <linux/mm.h>
#include <linux/kd.h>
@@ -59,8 +67,15 @@ extern void put_queue(int);
static void mac_leds_done(struct adb_request *);
static void keyboard_input(unsigned char *, int, struct pt_regs *);
static void mouse_input(unsigned char *, int, struct pt_regs *);
-/* Hook for mouse driver */
-void (*adb_mouse_interrupt_hook) (char *, int);
+
+#ifdef CONFIG_ADBMOUSE
+/* XXX: Hook for mouse driver */
+void (*adb_mouse_interrupt_hook)(unsigned char *, int);
+int adb_emulate_buttons = 0;
+int adb_button2_keycode = 0x7d; /* right control key */
+int adb_button3_keycode = 0x7c; /* right option key */
+#endif
+
/* The mouse driver - for debugging */
extern void adb_mouse_interrupt(char *, int);
/* end keyb */
@@ -275,9 +290,11 @@ input_keycode(int keycode, int repeat)
kbd = kbd_table + fg_console;
up_flag = (keycode & 0x80);
keycode &= 0x7f;
+
if (!repeat)
del_timer(&repeat_timer);
+#ifdef CONFIG_ADBMOUSE
/*
* XXX: Add mouse button 2+3 fake codes here if mouse open.
* As we only report up/down events, keep track of faked buttons.
@@ -289,7 +306,8 @@ input_keycode(int keycode, int repeat)
* (wanted: command and alt/option, or KP= and KP( ...)
* Debug version; might be rewritten to be faster on normal keys.
*/
- if (adb_mouse_interrupt_hook || console_loglevel >= 8) {
+ if (adb_emulate_buttons
+ && (adb_mouse_interrupt_hook || console_loglevel >= 8)) {
unsigned char button, button2, button3, fake_event;
static unsigned char button2state=0, button3state=0; /* up */
/* faked ADB packet */
@@ -297,21 +315,20 @@ input_keycode(int keycode, int repeat)
button = 0;
fake_event = 0;
- switch (keycode) { /* which 'button' ? */
- case 0x7c: /* R-option */
- button2 = (!up_flag); /* new state */
- if (button2 != button2state) /* change ? */
- button = 2;
- button2state = button2; /* save state */
- fake_event = 2;
- break;
- case 0x7d: /* R-control */
- button3 = (!up_flag); /* new state */
- if (button3 != button3state) /* change ? */
- button = 3;
- button3state = button3; /* save state */
- fake_event = 3;
- break;
+ if (keycode == adb_button2_keycode) { /* which 'button' ? */
+ /* R-option */
+ button2 = (!up_flag); /* new state */
+ if (button2 != button2state) /* change ? */
+ button = 2;
+ button2state = button2; /* save state */
+ fake_event = 2;
+ } else if (keycode == adb_button3_keycode) {
+ /* R-control */
+ button3 = (!up_flag); /* new state */
+ if (button3 != button3state) /* change ? */
+ button = 3;
+ button3state = button3; /* save state */
+ fake_event = 3;
}
#ifdef DEBUG_ADBMOUSE
if (fake_event && console_loglevel >= 8)
@@ -340,6 +357,7 @@ input_keycode(int keycode, int repeat)
if (fake_event)
return;
}
+#endif /* CONFIG_ADBMOUSE */
/*
* Convert R-shift/control/option to L version.
@@ -365,16 +383,18 @@ input_keycode(int keycode, int repeat)
* transition into a key-down transition.
* MSch: need to turn each caps-lock event into a down-up
* double event (keyboard code assumes caps-lock is a toggle)
+ * 981127: fix LED behavior (kudos atong!)
*/
-#if 0
- if (keycode == 0x39 && up_flag && vc_kbd_led(kbd, VC_CAPSLOCK))
- up_flag = 0;
-#else
- if (keycode == 0x39) {
+ switch (keycode) {
+ case 0x39:
handle_scancode(keycode); /* down */
up_flag = 0x80; /* see below ... */
+ mark_bh(KEYBOARD_BH);
+ break;
+ case 0x47:
+ mark_bh(KEYBOARD_BH);
+ break;
}
-#endif
}
handle_scancode(keycode + up_flag);
@@ -740,8 +760,3 @@ __initfunc(int mac_keyb_init(void))
return 0;
}
-
-/* for "kbd-reset" cmdline param */
-__initfunc(void mac_kbd_reset_setup(char *str, int *ints))
-{
-}
diff --git a/arch/m68k/mac/via6522.c b/arch/m68k/mac/via6522.c
index 08ca49071..05e6f44e4 100644
--- a/arch/m68k/mac/via6522.c
+++ b/arch/m68k/mac/via6522.c
@@ -304,10 +304,11 @@ void mac_reset(void)
unsigned long flags;
unsigned long *reset_hook;
- save_flags(flags);
- cli();
-
/* need ROMBASE in booter */
+ /* indeed, plus need to MAP THE ROM !! */
+
+ if (mac_bi_data.rombase == 0)
+ mac_bi_data.rombase = 0x40800000;
/* works on some */
rom_reset = (void *) (mac_bi_data.rombase + 0xa);
@@ -318,12 +319,22 @@ void mac_reset(void)
printk("ROM reset hook: %p\n", *reset_hook);
rom_reset = *reset_hook;
#endif
+ if (macintosh_config->ident == MAC_MODEL_SE30) {
+ /*
+ * MSch: Machines known to crash on ROM reset ...
+ */
+ printk("System halted.\n");
+ while(1);
+ } else {
+ save_flags(flags);
+ cli();
- rom_reset();
+ rom_reset();
- restore_flags(flags);
+ restore_flags(flags);
+ }
- /* We never make it this far... */
+ /* We never make it this far... it usually panics above. */
printk ("Restart failed. Please restart manually.\n");
/* XXX - delay do we need to spin here ? */
diff --git a/arch/m68k/mm/fault.c b/arch/m68k/mm/fault.c
index 62129782b..ef1b855bd 100644
--- a/arch/m68k/mm/fault.c
+++ b/arch/m68k/mm/fault.c
@@ -8,6 +8,7 @@
#include <linux/mm.h>
#include <linux/kernel.h>
#include <linux/ptrace.h>
+#include <linux/interrupt.h>
#include <asm/setup.h>
#include <asm/traps.h>
@@ -32,8 +33,7 @@ extern const int frame_extra_sizes[]; /* in m68k/kernel/signal.c */
asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address,
unsigned long error_code)
{
- struct task_struct *tsk = current;
- struct mm_struct *mm = tsk->mm;
+ struct mm_struct *mm = current->mm;
struct vm_area_struct * vma;
unsigned long fixup;
int write;
@@ -41,9 +41,17 @@ asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address,
#ifdef DEBUG
printk ("regs->sr=%#x, regs->pc=%#lx, address=%#lx, %ld, %p\n",
regs->sr, regs->pc, address, error_code,
- tsk->mm->pgd);
+ current->mm->pgd);
#endif
+
+ /*
+ * If we're in an interrupt or have no user
+ * context, we must not take the fault..
+ */
+ if (in_interrupt() || mm == &init_mm)
+ goto no_context;
+
down(&mm->mmap_sem);
vma = find_vma(mm, address);
@@ -86,7 +94,14 @@ good_area:
if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
goto bad_area;
}
- handle_mm_fault(current, vma, address, write);
+
+ /*
+ * If for any reason at all we couldn't handle the fault,
+ * make sure we exit gracefully rather than endlessly redo
+ * the fault.
+ */
+ if (!handle_mm_fault(current, vma, address, write))
+ goto do_sigbus;
/* There seems to be a missing invalidate somewhere in do_no_page.
* Until I found it, this one cures the problem and makes
@@ -106,10 +121,15 @@ bad_area:
/* User mode accesses just cause a SIGSEGV */
if (user_mode(regs)) {
- force_sig (SIGSEGV, tsk);
+ siginfo_t info;
+ info.si_signo = SIGSEGV;
+ info.si_code = SEGV_MAPERR;
+ info.si_addr = (void *)address;
+ force_sig_info(SIGSEGV, &info, current);
return 1;
}
+no_context:
/* Are we prepared to handle this kernel fault? */
if ((fixup = search_exception_table(regs->pc)) != 0) {
struct pt_regs *tregs;
@@ -136,5 +156,22 @@ bad_area:
die_if_kernel("Oops", regs, error_code);
do_exit(SIGKILL);
+/*
+ * We ran out of memory, or some other thing happened to us that made
+ * us unable to handle the page fault gracefully.
+ */
+do_sigbus:
+ up(&mm->mmap_sem);
+
+ /*
+ * Send a sigbus, regardless of whether we were in kernel
+ * or user mode.
+ */
+ force_sig(SIGBUS, current);
+
+ /* Kernel mode? Handle exceptions or die */
+ if (!user_mode(regs))
+ goto no_context;
+
return 1;
}
diff --git a/arch/m68k/mm/init.c b/arch/m68k/mm/init.c
index 395fb41b6..8e520702f 100644
--- a/arch/m68k/mm/init.c
+++ b/arch/m68k/mm/init.c
@@ -28,8 +28,9 @@
#include <asm/atari_stram.h>
#endif
+#undef DEBUG
+
extern void die_if_kernel(char *,struct pt_regs *,long);
-extern void init_kpointer_table(void);
extern void show_net_buffers(void);
int do_check_pgt_cache(int low, int high)
@@ -122,17 +123,14 @@ void show_mem(void)
unsigned long mm_cachebits = 0;
#endif
-pte_t *kernel_page_table (unsigned long *memavailp)
+static pte_t *__init kernel_page_table(unsigned long *memavailp)
{
pte_t *ptablep;
- if (memavailp) {
- ptablep = (pte_t *)*memavailp;
- *memavailp += PAGE_SIZE;
- }
- else
- ptablep = (pte_t *)__get_free_page(GFP_KERNEL);
+ ptablep = (pte_t *)*memavailp;
+ *memavailp += PAGE_SIZE;
+ clear_page((unsigned long)ptablep);
flush_page_to_ram((unsigned long) ptablep);
flush_tlb_kernel_page((unsigned long) ptablep);
nocache_page ((unsigned long)ptablep);
@@ -140,199 +138,164 @@ pte_t *kernel_page_table (unsigned long *memavailp)
return ptablep;
}
-__initfunc(static unsigned long
-map_chunk (unsigned long addr, unsigned long size, unsigned long *memavailp))
-{
-#define ONEMEG (1024*1024)
-#define L3TREESIZE (256*1024)
+static pmd_t *last_pgtable __initdata = NULL;
- static unsigned long mem_mapped = 0;
- static unsigned long virtaddr = 0;
- static pte_t *ktablep = NULL;
- unsigned long *kpointerp;
- unsigned long physaddr;
- extern pte_t *kpt;
- int pindex; /* index into pointer table */
- pgd_t *page_dir = pgd_offset_k (virtaddr);
-
- if (!pgd_present (*page_dir)) {
- /* we need a new pointer table */
- kpointerp = (unsigned long *) get_kpointer_table ();
- pgd_set (page_dir, (pmd_t *) kpointerp);
- memset (kpointerp, 0, PTRS_PER_PMD * sizeof (pmd_t));
- }
- else
- kpointerp = (unsigned long *) pgd_page (*page_dir);
+static pmd_t *__init kernel_ptr_table(unsigned long *memavailp)
+{
+ if (!last_pgtable) {
+ unsigned long pmd, last;
+ int i;
- /*
- * pindex is the offset into the pointer table for the
- * descriptors for the current virtual address being mapped.
- */
- pindex = (virtaddr >> 18) & 0x7f;
+ last = (unsigned long)kernel_pg_dir;
+ for (i = 0; i < PTRS_PER_PGD; i++) {
+ if (!pgd_val(kernel_pg_dir[i]))
+ continue;
+ pmd = pgd_page(kernel_pg_dir[i]);
+ if (pmd > last)
+ last = pmd;
+ }
+ last_pgtable = (pmd_t *)last;
#ifdef DEBUG
- printk ("mm=%ld, kernel_pg_dir=%p, kpointerp=%p, pindex=%d\n",
- mem_mapped, kernel_pg_dir, kpointerp, pindex);
+ printk("kernel_ptr_init: %p\n", last_pgtable);
#endif
+ }
- /*
- * if this is running on an '040, we already allocated a page
- * table for the first 4M. The address is stored in kpt by
- * arch/head.S
- *
- */
- if (CPU_IS_040_OR_060 && mem_mapped == 0)
- ktablep = kpt;
-
- for (physaddr = addr;
- physaddr < addr + size;
- mem_mapped += L3TREESIZE, virtaddr += L3TREESIZE) {
-
-#ifdef DEBUG
- printk ("pa=%#lx va=%#lx ", physaddr, virtaddr);
-#endif
+ if (((unsigned long)(last_pgtable + PTRS_PER_PMD) & ~PAGE_MASK) == 0) {
+ last_pgtable = (pmd_t *)*memavailp;
+ *memavailp += PAGE_SIZE;
- if (pindex > 127 && mem_mapped >= 32*ONEMEG) {
- /* we need a new pointer table every 32M */
-#ifdef DEBUG
- printk ("[new pointer]");
-#endif
+ clear_page((unsigned long)last_pgtable);
+ flush_page_to_ram((unsigned long)last_pgtable);
+ flush_tlb_kernel_page((unsigned long)last_pgtable);
+ nocache_page((unsigned long)last_pgtable);
+ } else
+ last_pgtable += PTRS_PER_PMD;
- kpointerp = (unsigned long *)get_kpointer_table ();
- pgd_set(pgd_offset_k(virtaddr), (pmd_t *)kpointerp);
- pindex = 0;
- }
+ return last_pgtable;
+}
- if (CPU_IS_040_OR_060) {
- int i;
- unsigned long ktable;
+static unsigned long __init
+map_chunk (unsigned long addr, long size, unsigned long *memavailp)
+{
+#define PTRTREESIZE (256*1024)
+#define ROOTTREESIZE (32*1024*1024)
+ static unsigned long virtaddr = 0;
+ unsigned long physaddr;
+ pgd_t *pgd_dir;
+ pmd_t *pmd_dir;
+ pte_t *pte_dir;
- /* Don't map the first 4 MB again. The pagetables
- * for this range have already been initialized
- * in boot/head.S. Otherwise the pages used for
- * tables would be reinitialized to copyback mode.
- */
+ physaddr = (addr | m68k_supervisor_cachemode |
+ _PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_DIRTY);
+ if (CPU_IS_040_OR_060)
+ physaddr |= _PAGE_GLOBAL040;
- if (mem_mapped < 4 * ONEMEG)
- {
+ while (size > 0) {
+#ifdef DEBUG
+ if (!(virtaddr & (PTRTREESIZE-1)))
+ printk ("\npa=%#lx va=%#lx ", physaddr & PAGE_MASK,
+ virtaddr);
+#endif
+ pgd_dir = pgd_offset_k(virtaddr);
+ if (virtaddr && CPU_IS_020_OR_030) {
+ if (!(virtaddr & (ROOTTREESIZE-1)) &&
+ size >= ROOTTREESIZE) {
#ifdef DEBUG
- printk ("Already initialized\n");
+ printk ("[very early term]");
#endif
- physaddr += L3TREESIZE;
- pindex++;
+ pgd_val(*pgd_dir) = physaddr;
+ size -= ROOTTREESIZE;
+ virtaddr += ROOTTREESIZE;
+ physaddr += ROOTTREESIZE;
continue;
}
+ }
+ if (!pgd_present(*pgd_dir)) {
+ pmd_dir = kernel_ptr_table(memavailp);
#ifdef DEBUG
- printk ("[setup table]");
+ printk ("[new pointer %p]", pmd_dir);
#endif
+ pgd_set(pgd_dir, pmd_dir);
+ } else
+ pmd_dir = pmd_offset(pgd_dir, virtaddr);
- /*
- * 68040, use page tables pointed to by the
- * kernel pointer table.
- */
-
- if ((pindex & 15) == 0) {
- /* Need new page table every 4M on the '040 */
+ if (CPU_IS_020_OR_030) {
+ if (virtaddr) {
#ifdef DEBUG
- printk ("[new table]");
+ printk ("[early term]");
#endif
- ktablep = kernel_page_table (memavailp);
- }
-
- ktable = virt_to_phys(ktablep);
-
- /*
- * initialize section of the page table mapping
- * this 256K portion.
- */
- for (i = 0; i < 64; i++) {
- pte_val(ktablep[i]) = physaddr | _PAGE_PRESENT
- | m68k_supervisor_cachemode | _PAGE_GLOBAL040
- | _PAGE_ACCESSED;
+ pmd_dir->pmd[(virtaddr/PTRTREESIZE) & 15] = physaddr;
+ physaddr += PTRTREESIZE;
+ } else {
+ int i;
+#ifdef DEBUG
+ printk ("[zero map]");
+#endif
+ pte_dir = (pte_t *)kernel_ptr_table(memavailp);
+ pmd_dir->pmd[0] = virt_to_phys(pte_dir) |
+ _PAGE_TABLE | _PAGE_ACCESSED;
+ pte_val(*pte_dir++) = 0;
physaddr += PAGE_SIZE;
+ for (i = 1; i < 64; physaddr += PAGE_SIZE, i++)
+ pte_val(*pte_dir++) = physaddr;
}
- ktablep += 64;
-
- /*
- * make the kernel pointer table point to the
- * kernel page table. Each entries point to a
- * 64 entry section of the page table.
- */
-
- kpointerp[pindex++] = ktable | _PAGE_TABLE | _PAGE_ACCESSED;
+ size -= PTRTREESIZE;
+ virtaddr += PTRTREESIZE;
} else {
- /*
- * 68030, use early termination page descriptors.
- * Each one points to 64 pages (256K).
- */
-#ifdef DEBUG
- printk ("[early term] ");
-#endif
- if (virtaddr == 0UL) {
- /* map the first 256K using a 64 entry
- * 3rd level page table.
- * UNMAP the first entry to trap
- * zero page (NULL pointer) references
- */
- int i;
- unsigned long *tbl;
-
- tbl = (unsigned long *)get_kpointer_table();
-
- kpointerp[pindex++] = virt_to_phys(tbl) | _PAGE_TABLE |_PAGE_ACCESSED;
-
- for (i = 0; i < 64; i++, physaddr += PAGE_SIZE)
- tbl[i] = physaddr | _PAGE_PRESENT | _PAGE_ACCESSED;
-
- /* unmap the zero page */
- tbl[0] = 0;
- } else {
- /* not the first 256K */
- kpointerp[pindex++] = physaddr | _PAGE_PRESENT | _PAGE_ACCESSED;
+ if (!pmd_present(*pmd_dir)) {
#ifdef DEBUG
- printk ("%lx=%lx ", virt_to_phys(&kpointerp[pindex-1]),
- kpointerp[pindex-1]);
+ printk ("[new table]");
#endif
- physaddr += 64 * PAGE_SIZE;
+ pte_dir = kernel_page_table(memavailp);
+ pmd_set(pmd_dir, pte_dir);
}
+ pte_dir = pte_offset(pmd_dir, virtaddr);
+
+ if (virtaddr) {
+ if (!pte_present(*pte_dir))
+ pte_val(*pte_dir) = physaddr;
+ } else
+ pte_val(*pte_dir) = 0;
+ size -= PAGE_SIZE;
+ virtaddr += PAGE_SIZE;
+ physaddr += PAGE_SIZE;
}
+
+ }
#ifdef DEBUG
- printk ("\n");
+ printk("\n");
#endif
- }
- return mem_mapped;
+ return virtaddr;
}
extern unsigned long free_area_init(unsigned long, unsigned long);
+extern void init_pointer_table(unsigned long ptable);
/* References to section boundaries */
extern char _text, _etext, _edata, __bss_start, _end;
extern char __init_begin, __init_end;
-extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
-
/*
* paging_init() continues the virtual memory environment setup which
* was begun by the code in arch/head.S.
*/
-__initfunc(unsigned long paging_init(unsigned long start_mem,
- unsigned long end_mem))
+unsigned long __init paging_init(unsigned long start_mem,
+ unsigned long end_mem)
{
int chunk;
unsigned long mem_avail = 0;
#ifdef DEBUG
{
- extern pte_t *kpt;
- printk ("start of paging_init (%p, %p, %lx, %lx, %lx)\n",
- kernel_pg_dir, kpt, availmem, start_mem, end_mem);
+ extern unsigned long availmem;
+ printk ("start of paging_init (%p, %lx, %lx, %lx)\n",
+ kernel_pg_dir, availmem, start_mem, end_mem);
}
#endif
- init_kpointer_table();
-
/* Fix the cache mode in the page descriptors for the 680[46]0. */
if (CPU_IS_040_OR_060) {
int i;
@@ -366,6 +329,7 @@ __initfunc(unsigned long paging_init(unsigned long start_mem,
m68k_memory[chunk].size, &start_mem);
}
+
flush_tlb_all();
#ifdef DEBUG
printk ("memory available is %ldKB\n", mem_avail >> 10);
@@ -385,21 +349,16 @@ __initfunc(unsigned long paging_init(unsigned long start_mem,
start_mem += PAGE_SIZE;
memset((void *)empty_zero_page, 0, PAGE_SIZE);
-#if 0
/*
* allocate the "swapper" page directory and
* record in task 0 (swapper) tss
*/
- swapper_pg_dir = (pgd_t *)get_kpointer_table();
-
- init_mm.pgd = swapper_pg_dir;
-#endif
-
- memset (swapper_pg_dir, 0, sizeof(pgd_t)*PTRS_PER_PGD);
+ init_mm.pgd = (pgd_t *)kernel_ptr_table(&start_mem);
+ memset (init_mm.pgd, 0, sizeof(pgd_t)*PTRS_PER_PGD);
/* setup CPU root pointer for swapper task */
task[0]->tss.crp[0] = 0x80000000 | _PAGE_TABLE;
- task[0]->tss.crp[1] = virt_to_phys (swapper_pg_dir);
+ task[0]->tss.crp[1] = virt_to_phys(init_mm.pgd);
#ifdef DEBUG
printk ("task 0 pagedir at %p virt, %#lx phys\n",
@@ -430,16 +389,16 @@ __initfunc(unsigned long paging_init(unsigned long start_mem,
#ifdef DEBUG
printk ("before free_area_init\n");
#endif
-
- return PAGE_ALIGN(free_area_init (start_mem, end_mem));
+ return PAGE_ALIGN(free_area_init(start_mem, end_mem));
}
-__initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem))
+void __init mem_init(unsigned long start_mem, unsigned long end_mem)
{
int codepages = 0;
int datapages = 0;
int initpages = 0;
unsigned long tmp;
+ int i;
end_mem &= PAGE_MASK;
high_memory = (void *) end_mem;
@@ -480,6 +439,14 @@ __initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem))
#endif
free_page(tmp);
}
+
+ /* insert pointer tables allocated so far into the tablelist */
+ init_pointer_table((unsigned long)kernel_pg_dir);
+ for (i = 0; i < PTRS_PER_PGD; i++) {
+ if (pgd_val(kernel_pg_dir[i]))
+ init_pointer_table(pgd_page(kernel_pg_dir[i]));
+ }
+
printk("Memory: %luk/%luk available (%dk kernel code, %dk data, %dk init)\n",
(unsigned long) nr_free_pages << (PAGE_SHIFT-10),
max_mapnr << (PAGE_SHIFT-10),
diff --git a/arch/m68k/mm/kmap.c b/arch/m68k/mm/kmap.c
index 802771ab4..d2cd29011 100644
--- a/arch/m68k/mm/kmap.c
+++ b/arch/m68k/mm/kmap.c
@@ -2,6 +2,9 @@
* linux/arch/m68k/mm/kmap.c
*
* Copyright (C) 1997 Roman Hodek
+ *
+ * 10/01/99 cleaned up the code and changing to the same interface
+ * used by other architectures /Roman Zippel
*/
#include <linux/mm.h>
@@ -9,250 +12,88 @@
#include <linux/string.h>
#include <linux/types.h>
#include <linux/malloc.h>
+#include <linux/vmalloc.h>
#include <asm/setup.h>
#include <asm/segment.h>
#include <asm/page.h>
#include <asm/pgtable.h>
+#include <asm/io.h>
#include <asm/system.h>
+#undef DEBUG
-extern pte_t *kernel_page_table (unsigned long *memavailp);
-
-/* Granularity of kernel_map() allocations */
-#define KMAP_STEP (256*1024)
-
-/* Size of pool of KMAP structures; that is needed, because kernel_map() can
- * be called at times where kmalloc() isn't initialized yet. */
-#define KMAP_POOL_SIZE 16
-
-/* structure for maintainance of kmap regions */
-typedef struct kmap {
- struct kmap *next, *prev; /* linking of list */
- unsigned long addr; /* start address of region */
- unsigned long mapaddr; /* address returned to user */
- unsigned long size; /* size of region */
- unsigned free : 1; /* flag whether free or allocated */
- unsigned kmalloced : 1; /* flag whether got this from kmalloc() */
- unsigned pool_alloc : 1; /* flag whether got this is alloced in pool */
-} KMAP;
-
-KMAP kmap_pool[KMAP_POOL_SIZE] = {
- { NULL, NULL, KMAP_START, KMAP_START, KMAP_END-KMAP_START, 1, 0, 1 },
- { NULL, NULL, 0, 0, 0, 0, 0, 0 },
-};
+#define PTRTREESIZE (256*1024)
/*
- * anchor of kmap region list
- *
- * The list is always ordered by addresses, and regions are always adjacent,
- * i.e. there must be no holes between them!
+ * For 040/060 we can use the virtual memory area like other architectures,
+ * but for 020/030 we want to use early termination page descriptor and we
+ * can't mix this with normal page descriptors, so we have to copy that code
+ * (mm/vmalloc.c) and return appriorate aligned addresses.
*/
-KMAP *kmap_regions = &kmap_pool[0];
-
-/* for protecting the kmap_regions list against races */
-static struct semaphore kmap_sem = MUTEX;
+#ifdef CPU_M68040_OR_M68060_ONLY
+#define IO_SIZE PAGE_SIZE
-/*
- * Low-level allocation and freeing of KMAP structures
- */
-static KMAP *alloc_kmap( int use_kmalloc )
+static inline struct vm_struct *get_io_area(unsigned long size)
{
- KMAP *p;
- int i;
-
- /* first try to get from the pool if possible */
- for( i = 0; i < KMAP_POOL_SIZE; ++i ) {
- if (!kmap_pool[i].pool_alloc) {
- kmap_pool[i].kmalloced = 0;
- kmap_pool[i].pool_alloc = 1;
- return( &kmap_pool[i] );
- }
- }
-
- if (use_kmalloc && (p = (KMAP *)kmalloc( sizeof(KMAP), GFP_KERNEL ))) {
- p->kmalloced = 1;
- return( p );
- }
-
- return( NULL );
-}
-
-static void free_kmap( KMAP *p )
-{
- if (p->kmalloced)
- kfree( p );
- else
- p->pool_alloc = 0;
+ return get_vm_area(size);
}
-/*
- * Get a free region from the kmap address range
- */
-static KMAP *kmap_get_region( unsigned long size, int use_kmalloc )
+static inline void free_io_area(void *addr)
{
- KMAP *p, *q;
-
- /* look for a suitable free region */
- for( p = kmap_regions; p; p = p->next )
- if (p->free && p->size >= size)
- break;
- if (!p) {
- printk( KERN_ERR "kernel_map: address space for "
- "allocations exhausted\n" );
- return( NULL );
- }
-
- if (p->size > size) {
- /* if free region is bigger than we need, split off the rear free part
- * into a new region */
- if (!(q = alloc_kmap( use_kmalloc ))) {
- printk( KERN_ERR "kernel_map: out of memory\n" );
- return( NULL );
- }
- q->addr = p->addr + size;
- q->size = p->size - size;
- p->size = size;
- q->free = 1;
-
- q->prev = p;
- q->next = p->next;
- p->next = q;
- if (q->next) q->next->prev = q;
- }
-
- p->free = 0;
- return( p );
+ return vfree((void *)(PAGE_MASK & (unsigned long)addr));
}
+#else
-/*
- * Free a kernel_map region again
- */
-static void kmap_put_region( KMAP *p )
-{
- KMAP *q;
-
- p->free = 1;
+#define IO_SIZE (256*1024)
- /* merge with previous region if possible */
- q = p->prev;
- if (q && q->free) {
- if (q->addr + q->size != p->addr) {
- printk( KERN_ERR "kernel_malloc: allocation list destroyed\n" );
- return;
- }
- q->size += p->size;
- q->next = p->next;
- if (p->next) p->next->prev = q;
- free_kmap( p );
- p = q;
- }
-
- /* merge with following region if possible */
- q = p->next;
- if (q && q->free) {
- if (p->addr + p->size != q->addr) {
- printk( KERN_ERR "kernel_malloc: allocation list destroyed\n" );
- return;
- }
- p->size += q->size;
- p->next = q->next;
- if (q->next) q->next->prev = p;
- free_kmap( q );
- }
-}
+static struct vm_struct *iolist = NULL;
-
-/*
- * kernel_map() helpers
- */
-static inline pte_t *
-pte_alloc_kernel_map(pmd_t *pmd, unsigned long address,
- unsigned long *memavailp)
+static struct vm_struct *get_io_area(unsigned long size)
{
- address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
- if (pmd_none(*pmd)) {
- pte_t *page = kernel_page_table(memavailp);
- if (pmd_none(*pmd)) {
- if (page) {
- pmd_set(pmd, page);
- memset( page, 0, PAGE_SIZE );
- return page + address;
- }
- pmd_set(pmd, BAD_PAGETABLE);
- return NULL;
- }
- if (memavailp)
- panic("kernel_map: slept during init?!?");
- cache_page((unsigned long) page);
- free_page((unsigned long) page);
- }
- if (pmd_bad(*pmd)) {
- printk( KERN_ERR "Bad pmd in pte_alloc_kernel_map: %08lx\n",
- pmd_val(*pmd));
- pmd_set(pmd, BAD_PAGETABLE);
+ unsigned long addr;
+ struct vm_struct **p, *tmp, *area;
+
+ area = (struct vm_struct *)kmalloc(sizeof(*area), GFP_KERNEL);
+ if (!area)
return NULL;
+ addr = KMAP_START;
+ for (p = &iolist; (tmp = *p) ; p = &tmp->next) {
+ if (size + addr < (unsigned long)tmp->addr)
+ break;
+ if (addr > KMAP_END-size)
+ return NULL;
+ addr = tmp->size + (unsigned long)tmp->addr;
}
- return (pte_t *) pmd_page(*pmd) + address;
-}
-
-static inline void
-kernel_map_pte(pte_t *pte, unsigned long address, unsigned long size,
- unsigned long phys_addr, pgprot_t prot)
-{
- unsigned long end;
-
- address &= ~PMD_MASK;
- end = address + size;
- if (end > PMD_SIZE)
- end = PMD_SIZE;
- do {
- pte_val(*pte) = phys_addr + pgprot_val(prot);
- address += PAGE_SIZE;
- phys_addr += PAGE_SIZE;
- pte++;
- } while (address < end);
+ area->addr = (void *)addr;
+ area->size = size + IO_SIZE;
+ area->next = *p;
+ *p = area;
+ return area;
}
-static inline int
-kernel_map_pmd (pmd_t *pmd, unsigned long address, unsigned long size,
- unsigned long phys_addr, pgprot_t prot,
- unsigned long *memavailp)
+static inline void free_io_area(void *addr)
{
- unsigned long end;
+ struct vm_struct **p, *tmp;
- address &= ~PGDIR_MASK;
- end = address + size;
- if (end > PGDIR_SIZE)
- end = PGDIR_SIZE;
- phys_addr -= address;
-
- if (CPU_IS_040_OR_060) {
- do {
- pte_t *pte = pte_alloc_kernel_map(pmd, address, memavailp);
- if (!pte)
- return -ENOMEM;
- kernel_map_pte(pte, address, end - address,
- address + phys_addr, prot);
- address = (address + PMD_SIZE) & PMD_MASK;
- pmd++;
- } while (address < end);
- } else {
- /* On the 68030 we use early termination page descriptors.
- Each one points to 64 pages (256K). */
- int i = (address >> (PMD_SHIFT-4)) & 15;
- do {
- (&pmd_val(*pmd))[i++] = (address + phys_addr) | pgprot_val(prot);
- address += PMD_SIZE / 16;
- } while (address < end);
+ if (!addr)
+ return;
+ addr = (void *)((unsigned long)addr & -IO_SIZE);
+ for (p = &iolist ; (tmp = *p) ; p = &tmp->next) {
+ if (tmp->addr == addr) {
+ *p = tmp->next;
+ __iounmap(tmp->addr, tmp->size);
+ kfree(tmp);
+ return;
+ }
}
- return 0;
}
+#endif
/*
* Map some physical address range into the kernel address space. The
@@ -260,304 +101,245 @@ kernel_map_pmd (pmd_t *pmd, unsigned long address, unsigned long size,
*/
/* Rewritten by Andreas Schwab to remove all races. */
-unsigned long kernel_map(unsigned long phys_addr, unsigned long size,
- int cacheflag, unsigned long *memavailp)
+void *__ioremap(unsigned long physaddr, unsigned long size, int cacheflag)
{
- unsigned long retaddr, from, end;
- pgd_t *dir;
- pgprot_t prot;
- KMAP *kmap;
-
- /* Round down 'phys_addr' to 256 KB and adjust size */
- retaddr = phys_addr & (KMAP_STEP-1);
- size += retaddr;
- phys_addr &= ~(KMAP_STEP-1);
- /* Round up the size to 256 KB. It doesn't hurt if too much is
- mapped... */
- size = (size + KMAP_STEP - 1) & ~(KMAP_STEP-1);
-
- down( &kmap_sem );
- kmap = kmap_get_region(size, memavailp == NULL);
- if (!kmap) {
- up(&kmap_sem);
- return 0;
- }
- from = kmap->addr;
- retaddr += from;
- kmap->mapaddr = retaddr;
- end = from + size;
- up( &kmap_sem );
+ struct vm_struct *area;
+ unsigned long virtaddr, retaddr;
+ long offset;
+ pgd_t *pgd_dir;
+ pmd_t *pmd_dir;
+ pte_t *pte_dir;
+
+ /*
+ * Don't allow mappings that wrap..
+ */
+ if (!size || size > physaddr + size)
+ return NULL;
+#ifdef DEBUG
+ printk("ioremap: 0x%lx,0x%lx(%d) - ", physaddr, size, cacheflag);
+#endif
+ /*
+ * Mappings have to be aligned
+ */
+ offset = physaddr & (IO_SIZE - 1);
+ physaddr &= -IO_SIZE;
+ size = (size + offset + IO_SIZE - 1) & -IO_SIZE;
+
+ /*
+ * Ok, go for it..
+ */
+ area = get_io_area(size);
+ if (!area)
+ return NULL;
+
+ virtaddr = (unsigned long)area->addr;
+ retaddr = virtaddr + offset;
+#ifdef DEBUG
+ printk("0x%lx,0x%lx,0x%lx", physaddr, virtaddr, retaddr);
+#endif
+
+ /*
+ * add cache and table flags to physical address
+ */
if (CPU_IS_040_OR_060) {
- pgprot_val(prot) = (_PAGE_PRESENT | _PAGE_GLOBAL040 |
- _PAGE_ACCESSED | _PAGE_DIRTY);
+ physaddr |= (_PAGE_PRESENT | _PAGE_GLOBAL040 |
+ _PAGE_ACCESSED | _PAGE_DIRTY);
switch (cacheflag) {
- case KERNELMAP_FULL_CACHING:
- pgprot_val(prot) |= _PAGE_CACHE040;
+ case IOMAP_FULL_CACHING:
+ physaddr |= _PAGE_CACHE040;
break;
- case KERNELMAP_NOCACHE_SER:
+ case IOMAP_NOCACHE_SER:
default:
- pgprot_val(prot) |= _PAGE_NOCACHE_S;
+ physaddr |= _PAGE_NOCACHE_S;
break;
- case KERNELMAP_NOCACHE_NONSER:
- pgprot_val(prot) |= _PAGE_NOCACHE;
+ case IOMAP_NOCACHE_NONSER:
+ physaddr |= _PAGE_NOCACHE;
break;
- case KERNELMAP_NO_COPYBACK:
- pgprot_val(prot) |= _PAGE_CACHE040W;
+ case IOMAP_WRITETHROUGH:
+ physaddr |= _PAGE_CACHE040W;
break;
}
- } else
- pgprot_val(prot) = (_PAGE_PRESENT | _PAGE_ACCESSED |
- _PAGE_DIRTY |
- ((cacheflag == KERNELMAP_FULL_CACHING ||
- cacheflag == KERNELMAP_NO_COPYBACK)
- ? 0 : _PAGE_NOCACHE030));
-
- phys_addr -= from;
- dir = pgd_offset_k(from);
- while (from < end) {
- pmd_t *pmd = pmd_alloc_kernel(dir, from);
-
- if (kernel_map_pmd(pmd, from, end - from, phys_addr + from,
- prot, memavailp)) {
- printk( KERN_ERR "kernel_map: out of memory\n" );
- return 0UL;
+ } else {
+ physaddr |= (_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_DIRTY);
+ switch (cacheflag) {
+ case IOMAP_NOCACHE_SER:
+ case IOMAP_NOCACHE_NONSER:
+ default:
+ physaddr |= _PAGE_NOCACHE030;
+ break;
+ case IOMAP_FULL_CACHING:
+ case IOMAP_WRITETHROUGH:
+ break;
}
- from = (from + PGDIR_SIZE) & PGDIR_MASK;
- dir++;
}
- return retaddr;
-}
-
+ while (size > 0) {
+#ifdef DEBUG
+ if (!(virtaddr & (PTRTREESIZE-1)))
+ printk ("\npa=%#lx va=%#lx ", physaddr, virtaddr);
+#endif
+ pgd_dir = pgd_offset_k(virtaddr);
+ pmd_dir = pmd_alloc_kernel(pgd_dir, virtaddr);
+ if (!pmd_dir) {
+ printk("ioremap: no mem for pmd_dir\n");
+ return NULL;
+ }
-/*
- * kernel_unmap() helpers
- */
-static inline void pte_free_kernel_unmap( pmd_t *pmd )
-{
- unsigned long page = pmd_page(*pmd);
- mem_map_t *pagemap = &mem_map[MAP_NR(page)];
-
- pmd_clear(pmd);
- cache_page(page);
-
- if (PageReserved( pagemap )) {
- /* need to unreserve pages that were allocated with memavailp != NULL;
- * this works only if 'page' is page-aligned */
- if (page & ~PAGE_MASK)
- return;
- clear_bit( PG_reserved, &pagemap->flags );
- atomic_set( &pagemap->count, 1 );
- }
- free_page( page );
-}
+ if (CPU_IS_020_OR_030) {
+ pmd_dir->pmd[(virtaddr/PTRTREESIZE)&-16] = physaddr;
+ physaddr += PTRTREESIZE;
+ virtaddr += PTRTREESIZE;
+ size -= PTRTREESIZE;
+ } else {
+ pte_dir = pte_alloc_kernel(pmd_dir, virtaddr);
+ if (!pte_dir) {
+ printk("ioremap: no mem for pte_dir\n");
+ return NULL;
+ }
-/*
- * This not only unmaps the requested region, but also loops over the whole
- * pmd to determine whether the other pte's are clear (so that the page can be
- * freed.) If so, it returns 1, 0 otherwise.
- */
-static inline int
-kernel_unmap_pte_range(pmd_t * pmd, unsigned long address, unsigned long size)
-{
- pte_t *pte;
- unsigned long addr2, end, end2;
- int all_clear = 1;
-
- if (pmd_none(*pmd))
- return( 0 );
- if (pmd_bad(*pmd)) {
- printk( KERN_ERR "kernel_unmap_pte_range: bad pmd (%08lx)\n",
- pmd_val(*pmd) );
- pmd_clear(pmd);
- return( 0 );
- }
- address &= ~PMD_MASK;
- addr2 = 0;
- pte = pte_offset(pmd, addr2);
- end = address + size;
- if (end > PMD_SIZE)
- end = PMD_SIZE;
- end2 = addr2 + PMD_SIZE;
- while( addr2 < end2 ) {
- if (!pte_none(*pte)) {
- if (address <= addr2 && addr2 < end)
- pte_clear(pte);
- else
- all_clear = 0;
+ pte_val(*pte_dir) = physaddr;
+ virtaddr += PAGE_SIZE;
+ physaddr += PAGE_SIZE;
+ size -= PAGE_SIZE;
}
- ++pte;
- addr2 += PAGE_SIZE;
}
- return( all_clear );
-}
-
-static inline void
-kernel_unmap_pmd_range(pgd_t * dir, unsigned long address, unsigned long size)
-{
- pmd_t * pmd;
- unsigned long end;
+#ifdef DEBUG
+ printk("\n");
+#endif
+ flush_tlb_all();
- if (pgd_none(*dir))
- return;
- if (pgd_bad(*dir)) {
- printk( KERN_ERR "kernel_unmap_pmd_range: bad pgd (%08lx)\n",
- pgd_val(*dir) );
- pgd_clear(dir);
- return;
- }
- pmd = pmd_offset(dir, address);
- address &= ~PGDIR_MASK;
- end = address + size;
- if (end > PGDIR_SIZE)
- end = PGDIR_SIZE;
-
- if (CPU_IS_040_OR_060) {
- do {
- if (kernel_unmap_pte_range(pmd, address, end - address))
- pte_free_kernel_unmap( pmd );
- address = (address + PMD_SIZE) & PMD_MASK;
- pmd++;
- } while (address < end);
- } else {
- /* On the 68030 clear the early termination descriptors */
- int i = (address >> (PMD_SHIFT-4)) & 15;
- do {
- (&pmd_val(*pmd))[i++] = 0;
- address += PMD_SIZE / 16;
- } while (address < end);
- }
+ return (void *)retaddr;
}
/*
- * Unmap a kernel_map()ed region again
+ * Unmap a ioremap()ed region again
*/
-void kernel_unmap( unsigned long addr )
+void iounmap(void *addr)
{
- unsigned long end;
- pgd_t *dir;
- KMAP *p;
-
- down( &kmap_sem );
-
- /* find region for 'addr' in list; must search for mapaddr! */
- for( p = kmap_regions; p; p = p->next )
- if (!p->free && p->mapaddr == addr)
- break;
- if (!p) {
- printk( KERN_ERR "kernel_unmap: trying to free invalid region\n" );
- return;
- }
- addr = p->addr;
- end = addr + p->size;
- kmap_put_region( p );
-
- dir = pgd_offset_k( addr );
- while( addr < end ) {
- kernel_unmap_pmd_range( dir, addr, end - addr );
- addr = (addr + PGDIR_SIZE) & PGDIR_MASK;
- dir++;
- }
-
- up( &kmap_sem );
- /* flushing for a range would do, but there's no such function for kernel
- * address space... */
- flush_tlb_all();
+ free_io_area(addr);
}
-
/*
- * kernel_set_cachemode() helpers
+ * __iounmap unmaps nearly everything, so be careful
+ * it doesn't free currently pointer/page tables anymore but it
+ * wans't used anyway and might be added later.
*/
-static inline void set_cmode_pte( pmd_t *pmd, unsigned long address,
- unsigned long size, unsigned cmode )
-{ pte_t *pte;
- unsigned long end;
-
- if (pmd_none(*pmd))
- return;
-
- pte = pte_offset( pmd, address );
- address &= ~PMD_MASK;
- end = address + size;
- if (end >= PMD_SIZE)
- end = PMD_SIZE;
-
- for( ; address < end; pte++ ) {
- pte_val(*pte) = (pte_val(*pte) & ~_PAGE_NOCACHE) | cmode;
- address += PAGE_SIZE;
- }
-}
-
-
-static inline void set_cmode_pmd( pgd_t *dir, unsigned long address,
- unsigned long size, unsigned cmode )
+void __iounmap(void *addr, unsigned long size)
{
- pmd_t *pmd;
- unsigned long end;
+ unsigned long virtaddr = (unsigned long)addr;
+ pgd_t *pgd_dir;
+ pmd_t *pmd_dir;
+ pte_t *pte_dir;
+
+ while (size > 0) {
+ pgd_dir = pgd_offset_k(virtaddr);
+ if (pgd_bad(*pgd_dir)) {
+ printk("iounmap: bad pgd(%08lx)\n", pgd_val(*pgd_dir));
+ pgd_clear(pgd_dir);
+ return;
+ }
+ pmd_dir = pmd_offset(pgd_dir, virtaddr);
- if (pgd_none(*dir))
- return;
+ if (CPU_IS_020_OR_030) {
+ int pmd_off = (virtaddr/PTRTREESIZE) & -16;
- pmd = pmd_offset( dir, address );
- address &= ~PGDIR_MASK;
- end = address + size;
- if (end > PGDIR_SIZE)
- end = PGDIR_SIZE;
+ if ((pmd_dir->pmd[pmd_off] & _DESCTYPE_MASK) == _PAGE_PRESENT) {
+ pmd_dir->pmd[pmd_off] = 0;
+ virtaddr += PTRTREESIZE;
+ size -= PTRTREESIZE;
+ continue;
+ }
+ }
- if ((pmd_val(*pmd) & _DESCTYPE_MASK) == _PAGE_PRESENT) {
- /* 68030 early termination descriptor */
- pmd_val(*pmd) = (pmd_val(*pmd) & ~_PAGE_NOCACHE) | cmode;
- return;
- }
- else {
- /* "normal" tables */
- for( ; address < end; pmd++ ) {
- set_cmode_pte( pmd, address, end - address, cmode );
- address = (address + PMD_SIZE) & PMD_MASK;
+ if (pmd_bad(*pmd_dir)) {
+ printk("iounmap: bad pmd (%08lx)\n", pmd_val(*pmd_dir));
+ pmd_clear(pmd_dir);
+ return;
}
+ pte_dir = pte_offset(pmd_dir, virtaddr);
+
+ pte_val(*pte_dir) = 0;
+ virtaddr += PAGE_SIZE;
+ size -= PAGE_SIZE;
}
-}
+ flush_tlb_all();
+}
/*
* Set new cache mode for some kernel address space.
* The caller must push data for that range itself, if such data may already
* be in the cache.
*/
-void kernel_set_cachemode( unsigned long address, unsigned long size,
- unsigned cmode )
+void kernel_set_cachemode(void *addr, unsigned long size, int cmode)
{
- pgd_t *dir = pgd_offset_k( address );
- unsigned long end = address + size;
-
+ unsigned long virtaddr = (unsigned long)addr;
+ pgd_t *pgd_dir;
+ pmd_t *pmd_dir;
+ pte_t *pte_dir;
+
if (CPU_IS_040_OR_060) {
- switch( cmode ) {
- case KERNELMAP_FULL_CACHING:
+ switch (cmode) {
+ case IOMAP_FULL_CACHING:
cmode = _PAGE_CACHE040;
break;
- case KERNELMAP_NOCACHE_SER:
- default:
+ case IOMAP_NOCACHE_SER:
+ default:
cmode = _PAGE_NOCACHE_S;
break;
- case KERNELMAP_NOCACHE_NONSER:
+ case IOMAP_NOCACHE_NONSER:
cmode = _PAGE_NOCACHE;
break;
- case KERNELMAP_NO_COPYBACK:
+ case IOMAP_WRITETHROUGH:
cmode = _PAGE_CACHE040W;
break;
}
- } else
- cmode = ((cmode == KERNELMAP_FULL_CACHING ||
- cmode == KERNELMAP_NO_COPYBACK) ?
- 0 : _PAGE_NOCACHE030);
-
- for( ; address < end; dir++ ) {
- set_cmode_pmd( dir, address, end - address, cmode );
- address = (address + PGDIR_SIZE) & PGDIR_MASK;
+ } else {
+ switch (cmode) {
+ case IOMAP_NOCACHE_SER:
+ case IOMAP_NOCACHE_NONSER:
+ default:
+ cmode = _PAGE_NOCACHE030;
+ break;
+ case IOMAP_FULL_CACHING:
+ case IOMAP_WRITETHROUGH:
+ cmode = 0;
+ }
+ }
+
+ while (size > 0) {
+ pgd_dir = pgd_offset_k(virtaddr);
+ if (pgd_bad(*pgd_dir)) {
+ printk("iocachemode: bad pgd(%08lx)\n", pgd_val(*pgd_dir));
+ pgd_clear(pgd_dir);
+ return;
+ }
+ pmd_dir = pmd_offset(pgd_dir, virtaddr);
+
+ if (CPU_IS_020_OR_030) {
+ int pmd_off = (virtaddr/PTRTREESIZE) & -16;
+
+ if ((pmd_dir->pmd[pmd_off] & _DESCTYPE_MASK) == _PAGE_PRESENT) {
+ pmd_dir->pmd[pmd_off] = (pmd_dir->pmd[pmd_off] &
+ _CACHEMASK040) | cmode;
+ virtaddr += PTRTREESIZE;
+ size -= PTRTREESIZE;
+ continue;
+ }
+ }
+
+ if (pmd_bad(*pmd_dir)) {
+ printk("iocachemode: bad pmd (%08lx)\n", pmd_val(*pmd_dir));
+ pmd_clear(pmd_dir);
+ return;
+ }
+ pte_dir = pte_offset(pmd_dir, virtaddr);
+
+ pte_val(*pte_dir) = (pte_val(*pte_dir) & _CACHEMASK040) | cmode;
+ virtaddr += PAGE_SIZE;
+ size -= PAGE_SIZE;
}
- /* flushing for a range would do, but there's no such function for kernel
- * address space... */
+
flush_tlb_all();
}
diff --git a/arch/m68k/mm/memory.c b/arch/m68k/mm/memory.c
index 39cc1d1a9..a97578ec2 100644
--- a/arch/m68k/mm/memory.c
+++ b/arch/m68k/mm/memory.c
@@ -10,6 +10,7 @@
#include <linux/string.h>
#include <linux/types.h>
#include <linux/malloc.h>
+#include <linux/init.h>
#include <asm/setup.h>
#include <asm/segment.h>
@@ -97,6 +98,31 @@ static ptable_desc ptable_list = { &ptable_list, &ptable_list };
#define PTABLE_SIZE (PTRS_PER_PMD * sizeof(pmd_t))
+void __init init_pointer_table(unsigned long ptable)
+{
+ ptable_desc *dp;
+ unsigned long page = ptable & PAGE_MASK;
+ unsigned char mask = 1 << ((ptable - page)/PTABLE_SIZE);
+
+ dp = PAGE_PD(page);
+ if (!(PD_MARKBITS(dp) & mask)) {
+ PD_MARKBITS(dp) = 0xff;
+ (dp->prev = ptable_list.prev)->next = dp;
+ (dp->next = &ptable_list)->prev = dp;
+ }
+
+ PD_MARKBITS(dp) &= ~mask;
+#ifdef DEBUG
+ printk("init_pointer_table: %lx, %x\n", ptable, PD_MARKBITS(dp));
+#endif
+
+ /* unreserve the page so it's possible to free that page */
+ dp->flags &= ~(1 << PG_reserved);
+ atomic_set(&dp->count, 1);
+
+ return;
+}
+
pmd_t *get_pointer_table (void)
{
ptable_desc *dp = ptable_list.next;
@@ -176,103 +202,6 @@ int free_pointer_table (pmd_t *ptable)
return 0;
}
-/* maximum pages used for kpointer tables */
-#define KPTR_PAGES 4
-/* # of reserved slots */
-#define RESERVED_KPTR 4
-extern pmd_tablepage kernel_pmd_table; /* reserved in head.S */
-
-static struct kpointer_pages {
- pmd_tablepage *page[KPTR_PAGES];
- u_char alloced[KPTR_PAGES];
-} kptr_pages;
-
-void init_kpointer_table(void) {
- short i = KPTR_PAGES-1;
-
- /* first page is reserved in head.S */
- kptr_pages.page[i] = &kernel_pmd_table;
- kptr_pages.alloced[i] = ~(0xff>>RESERVED_KPTR);
- for (i--; i>=0; i--) {
- kptr_pages.page[i] = NULL;
- kptr_pages.alloced[i] = 0;
- }
-}
-
-pmd_t *get_kpointer_table (void)
-{
- /* For pointer tables for the kernel virtual address space,
- * use the page that is reserved in head.S that can hold up to
- * 8 pointer tables. 3 of these tables are always reserved
- * (kernel_pg_dir, swapper_pg_dir and kernel pointer table for
- * the first 16 MB of RAM). In addition, the 4th pointer table
- * in this page is reserved. On Amiga and Atari, it is used to
- * map in the hardware registers. It may be used for other
- * purposes on other 68k machines. This leaves 4 pointer tables
- * available for use by the kernel. 1 of them are usually used
- * for the vmalloc tables. This allows mapping of 3 * 32 = 96 MB
- * of physical memory. But these pointer tables are also used
- * for other purposes, like kernel_map(), so further pages can
- * now be allocated.
- */
- pmd_tablepage *page;
- pmd_table *table;
- long nr, offset = -8;
- short i;
-
- for (i=KPTR_PAGES-1; i>=0; i--) {
- asm volatile("bfffo %1{%2,#8},%0"
- : "=d" (nr)
- : "d" ((u_char)~kptr_pages.alloced[i]), "d" (offset));
- if (nr)
- break;
- }
- if (i < 0) {
- printk("No space for kernel pointer table!\n");
- return NULL;
- }
- if (!(page = kptr_pages.page[i])) {
- if (!(page = (pmd_tablepage *)get_free_page(GFP_KERNEL))) {
- printk("No space for kernel pointer table!\n");
- return NULL;
- }
- flush_tlb_kernel_page((unsigned long) page);
- nocache_page((u_long)(kptr_pages.page[i] = page));
- }
- asm volatile("bfset %0@{%1,#1}"
- : /* no output */
- : "a" (&kptr_pages.alloced[i]), "d" (nr-offset));
- table = &(*page)[nr-offset];
- memset(table, 0, sizeof(pmd_table));
- return ((pmd_t *)table);
-}
-
-void free_kpointer_table (pmd_t *pmdp)
-{
- pmd_table *table = (pmd_table *)pmdp;
- pmd_tablepage *page = (pmd_tablepage *)((u_long)table & PAGE_MASK);
- long nr;
- short i;
-
- for (i=KPTR_PAGES-1; i>=0; i--) {
- if (kptr_pages.page[i] == page)
- break;
- }
- nr = ((u_long)table - (u_long)page) / sizeof(pmd_table);
- if (!table || i < 0 || (i == KPTR_PAGES-1 && nr < RESERVED_KPTR)) {
- printk("Attempt to free invalid kernel pointer table: %p\n", table);
- return;
- }
- asm volatile("bfclr %0@{%1,#1}"
- : /* no output */
- : "a" (&kptr_pages.alloced[i]), "d" (nr));
- if (!kptr_pages.alloced[i]) {
- kptr_pages.page[i] = 0;
- cache_page ((u_long)page);
- free_page ((u_long)page);
- }
-}
-
static unsigned long transp_transl_matches( unsigned long regval,
unsigned long vaddr )
{
@@ -308,7 +237,6 @@ static unsigned long transp_transl_matches( unsigned long regval,
*/
unsigned long mm_vtop (unsigned long vaddr)
{
-#ifndef CONFIG_SINGLE_MEMORY_CHUNK
int i=0;
unsigned long voff = vaddr;
unsigned long offset = 0;
@@ -324,10 +252,6 @@ unsigned long mm_vtop (unsigned long vaddr)
offset += m68k_memory[i].size;
i++;
}while (i < m68k_num_memory);
-#else
- if (vaddr < m68k_memory[0].size)
- return m68k_memory[0].addr + vaddr;
-#endif
return mm_vtop_fallback(vaddr);
}
@@ -449,7 +373,6 @@ unsigned long mm_vtop_fallback (unsigned long vaddr)
#ifndef CONFIG_SINGLE_MEMORY_CHUNK
unsigned long mm_ptov (unsigned long paddr)
{
-#ifndef CONFIG_SINGLE_MEMORY_CHUNK
int i = 0;
unsigned long offset = 0;
@@ -466,11 +389,6 @@ unsigned long mm_ptov (unsigned long paddr)
offset += m68k_memory[i].size;
i++;
}while (i < m68k_num_memory);
-#else
- unsigned long base = m68k_memory[0].addr;
- if (paddr >= base && paddr < (base + m68k_memory[0].size))
- return (paddr - base);
-#endif
/*
* assume that the kernel virtual address is the same as the
@@ -560,7 +478,7 @@ unsigned long mm_ptov (unsigned long paddr)
* Jes was worried about performance (urhh ???) so its optional
*/
-extern void (*mach_l2_flush)(int) = NULL;
+void (*mach_l2_flush)(int) = NULL;
#endif
/*
diff --git a/arch/m68k/mvme16x/16xints.c b/arch/m68k/mvme16x/16xints.c
index fbb370a07..9cc0d39d1 100644
--- a/arch/m68k/mvme16x/16xints.c
+++ b/arch/m68k/mvme16x/16xints.c
@@ -106,9 +106,12 @@ void mvme16x_free_irq(unsigned int irq, void *dev_id)
void mvme16x_process_int (unsigned long vec, struct pt_regs *fp)
{
if (vec < 64 || vec > 255)
- panic ("mvme16x_process_int: Illegal vector %ld", vec);
- irq_tab[vec-64].count++;
- irq_tab[vec-64].handler(vec, irq_tab[vec-64].dev_id, fp);
+ printk ("mvme16x_process_int: Illegal vector %ld", vec);
+ else
+ {
+ irq_tab[vec-64].count++;
+ irq_tab[vec-64].handler(vec, irq_tab[vec-64].dev_id, fp);
+ }
}
int mvme16x_get_irq_list (char *buf)
diff --git a/arch/m68k/vmlinux.lds b/arch/m68k/vmlinux.lds
index 88ee16b66..b79c9dd87 100644
--- a/arch/m68k/vmlinux.lds
+++ b/arch/m68k/vmlinux.lds
@@ -35,6 +35,9 @@ SECTIONS
_edata = .; /* End of data section */
+ . = ALIGN(16);
+ .data.cacheline_aligned : { *(.data.cacheline_aligned) }
+
. = ALIGN(4096); /* Init code and data */
__init_begin = .;
.text.init : { *(.text.init) }