diff --git a/arch/m68k/68000/entry.S b/arch/m68k/68000/entry.S
index 72e95663b62ffd54..1f79deb91da4dcbb 100644
--- a/arch/m68k/68000/entry.S
+++ b/arch/m68k/68000/entry.S
@@ -87,6 +87,21 @@ ret_from_exception:
 	btst	#5,%sp@(PT_OFF_SR)	/* check if returning to kernel*/
 	jeq	Luser_return		/* if so, skip resched, signals*/
 
+#ifdef CONFIG_PREEMPTION
+	movel	%sp,%d1			/* get thread_info pointer */
+	andl	#-THREAD_SIZE,%d1	/* at base of kernel stack */
+	movel	%d1,%a0
+	movel	%a0@(TINFO_FLAGS),%d1	/* get thread_info->flags */
+	btst	#TIF_NEED_RESCHED,%d1
+	jeq	Lkernel_return
+
+	movel	%a0@(TINFO_PREEMPT),%d1
+	jne	Lkernel_return
+
+	pea	Lkernel_return
+	jmp	preempt_schedule_irq	/* preempt the kernel */
+#endif /* CONFIG_PREEMPTION */
+
 Lkernel_return:
 	RESTORE_ALL
 
diff --git a/arch/m68k/Kconfig b/arch/m68k/Kconfig
index 3e96486d9528cafc..4fd188c2a9ad092b 100644
--- a/arch/m68k/Kconfig
+++ b/arch/m68k/Kconfig
@@ -10,7 +10,6 @@ config M68K
 	select ARCH_HAS_SYNC_DMA_FOR_DEVICE if HAS_DMA
 	select ARCH_HAVE_NMI_SAFE_CMPXCHG if RMW_INSNS
 	select ARCH_MIGHT_HAVE_PC_PARPORT if ISA
-	select ARCH_NO_PREEMPT if !COLDFIRE
 	select ARCH_USE_MEMTEST if MMU_MOTOROLA
 	select ARCH_WANT_IPC_PARSE_VERSION
 	select BINFMT_FLAT_ARGVP_ENVP_ON_STACK
diff --git a/arch/m68k/coldfire/cache.c b/arch/m68k/coldfire/cache.c
index 98ee89b87439cdc4..592fd1d579bef348 100644
--- a/arch/m68k/coldfire/cache.c
+++ b/arch/m68k/coldfire/cache.c
@@ -10,6 +10,8 @@
 /***************************************************************************/
 
 #include <linux/kernel.h>
+#include <linux/preempt.h>
+
 #include <asm/coldfire.h>
 #include <asm/mcfsim.h>
 
@@ -25,6 +27,8 @@
 
 void mcf_cache_push(void)
 {
+	preempt_disable();
+
 	__asm__ __volatile__ (
 		"clrl	%%d0\n\t"
 		"1:\n\t"
@@ -42,6 +46,8 @@ void mcf_cache_push(void)
 		  "i" (DCACHE_SIZE / CACHE_WAYS),
 		  "i" (CACHE_WAYS)
 		: "d0", "a0" );
+
+	preempt_enable();
 }
 
 /***************************************************************************/
diff --git a/arch/m68k/include/asm/cacheflush_mm.h b/arch/m68k/include/asm/cacheflush_mm.h
index ed12358c4783b468..d58aa237bd91a139 100644
--- a/arch/m68k/include/asm/cacheflush_mm.h
+++ b/arch/m68k/include/asm/cacheflush_mm.h
@@ -3,6 +3,8 @@
 #define _M68K_CACHEFLUSH_H
 
 #include <linux/mm.h>
+#include <linux/preempt.h>
+
 #ifdef CONFIG_COLDFIRE
 #include <asm/mcfsim.h>
 #endif
@@ -63,6 +65,8 @@ static inline void flush_cf_icache(unsigned long start, unsigned long end)
 {
 	unsigned long set;
 
+	preempt_disable();
+
 	for (set = start; set <= end; set += (0x10 - 3)) {
 		__asm__ __volatile__ (
 			"cpushl %%ic,(%0)\n\t"
@@ -75,12 +79,16 @@ static inline void flush_cf_icache(unsigned long start, unsigned long end)
 			: "=a" (set)
 			: "a" (set));
 	}
+
+	preempt_enable();
 }
 
 static inline void flush_cf_dcache(unsigned long start, unsigned long end)
 {
 	unsigned long set;
 
+	preempt_disable();
+
 	for (set = start; set <= end; set += (0x10 - 3)) {
 		__asm__ __volatile__ (
 			"cpushl %%dc,(%0)\n\t"
@@ -93,12 +101,16 @@ static inline void flush_cf_dcache(unsigned long start, unsigned long end)
 			: "=a" (set)
 			: "a" (set));
 	}
+
+	preempt_enable();
 }
 
 static inline void flush_cf_bcache(unsigned long start, unsigned long end)
 {
 	unsigned long set;
 
+	preempt_disable();
+
 	for (set = start; set <= end; set += (0x10 - 3)) {
 		__asm__ __volatile__ (
 			"cpushl %%bc,(%0)\n\t"
@@ -111,6 +123,8 @@ static inline void flush_cf_bcache(unsigned long start, unsigned long end)
 			: "=a" (set)
 			: "a" (set));
 	}
+
+	preempt_enable();
 }
 
 /*
@@ -227,14 +241,21 @@ static inline void __flush_pages_to_ram(void *vaddr, unsigned int nr)
 		addr = ((unsigned long) vaddr) & ~(PAGE_SIZE - 1);
 		start = addr & ICACHE_SET_MASK;
 		end = (addr + nr * PAGE_SIZE - 1) & ICACHE_SET_MASK;
+
+		preempt_disable();
+
 		if (start > end) {
 			flush_cf_bcache(0, end);
 			end = ICACHE_MAX_ADDR;
 		}
 		flush_cf_bcache(start, end);
+
+		preempt_enable();
 	} else if (CPU_IS_040_OR_060) {
 		unsigned long paddr = __pa(vaddr);
 
+		preempt_disable();
+
 		do {
 			__asm__ __volatile__("nop\n\t"
 					     ".chip 68040\n\t"
@@ -243,6 +264,8 @@ static inline void __flush_pages_to_ram(void *vaddr, unsigned int nr)
 					     : : "a" (paddr));
 			paddr += PAGE_SIZE;
 		} while (--nr);
+
+		preempt_enable();
 	} else {
 		unsigned long _tmp;
 		__asm__ __volatile__("movec %%cacr,%0\n\t"
diff --git a/arch/m68k/include/asm/tlbflush.h b/arch/m68k/include/asm/tlbflush.h
index 6d42e2906887931b..f95a8e9c9912a3e8 100644
--- a/arch/m68k/include/asm/tlbflush.h
+++ b/arch/m68k/include/asm/tlbflush.h
@@ -101,6 +101,7 @@ static inline void flush_tlb_kernel_range(unsigned long start, unsigned long end
 
 #else
 
+#include <linux/preempt.h>
 
 /* Reserved PMEGs. */
 extern char sun3_reserved_pmeg[SUN3_PMEGS_NUM];
@@ -115,6 +116,8 @@ static inline void flush_tlb_all(void)
 	unsigned long addr;
 	unsigned char ctx, oldctx;
 
+	preempt_disable();
+
 	oldctx = sun3_get_context();
 	for (addr = 0x00000000; addr < TASK_SIZE; addr += SUN3_PMEG_SIZE) {
 		for (ctx = 0; ctx < 8; ctx++) {
@@ -133,6 +136,8 @@ static inline void flush_tlb_all(void)
 			pmeg_vaddr[addr] = 0;
 		}
 	}
+
+	preempt_enable();
 }
 
 /* Clear user TLB entries within the context named in mm */
@@ -142,6 +147,8 @@ static inline void flush_tlb_mm (struct mm_struct *mm)
 	unsigned char seg;
 	unsigned long i;
 
+	preempt_disable();
+
 	oldctx = sun3_get_context();
 	sun3_put_context(mm->context);
 
@@ -157,6 +164,8 @@ static inline void flush_tlb_mm (struct mm_struct *mm)
 	}
 
 	sun3_put_context(oldctx);
+
+	preempt_enable();
 }
 
 /* Flush a single TLB page. In this case, we're limited to flushing a
@@ -167,6 +176,8 @@ static inline void flush_tlb_page (struct vm_area_struct *vma,
 	unsigned char oldctx;
 	unsigned char i;
 
+	preempt_disable();
+
 	oldctx = sun3_get_context();
 	sun3_put_context(vma->vm_mm->context);
 	addr &= ~SUN3_PMEG_MASK;
@@ -179,6 +190,7 @@ static inline void flush_tlb_page (struct vm_area_struct *vma,
 	}
 	sun3_put_context(oldctx);
 
+	preempt_enable();
 }
 /* Flush a range of pages from TLB. */
 
@@ -190,6 +202,8 @@ static inline void flush_tlb_range (struct vm_area_struct *vma,
 
 	start &= ~SUN3_PMEG_MASK;
 
+	preempt_disable();
+
 	oldctx = sun3_get_context();
 	sun3_put_context(mm->context);
 
@@ -207,6 +221,8 @@ static inline void flush_tlb_range (struct vm_area_struct *vma,
 		start += SUN3_PMEG_SIZE;
 	}
 	sun3_put_context(oldctx);
+
+	preempt_enable();
 }
 
 static inline void flush_tlb_kernel_range(unsigned long start, unsigned long end)
diff --git a/arch/m68k/kernel/entry.S b/arch/m68k/kernel/entry.S
index 3bcdd32a6b36613d..9933679ea28b44ab 100644
--- a/arch/m68k/kernel/entry.S
+++ b/arch/m68k/kernel/entry.S
@@ -241,7 +241,23 @@ syscall_exit_work:
 ENTRY(ret_from_exception)
 .Lret_from_exception:
 	btst	#5,%sp@(PT_OFF_SR)	| check if returning to kernel
+#ifdef CONFIG_PREEMPTION
+	jeq	2f
+
+	movel   %curptr@(TASK_STACK),%a0
+	tstb	%a0@(TINFO_FLAGS+3)	| check TIF_NEED_RESCHED
+	jpl	1f
+
+	movel	%a0@(TINFO_PREEMPT),%d1
+	jne	1f
+
+	pea	1f
+	jmp	preempt_schedule_irq	| preempt the kernel
+#else /* !CONFIG_PREEMPTION */
 	bnes	1f			| if so, skip resched, signals
+#endif /* !CONFIG_PREEMPTION */
+
+2:
 	| only allow interrupts when we are really the last one on the
 	| kernel stack, otherwise stack overflow can occur during
 	| heavy interrupt load
diff --git a/arch/m68k/mm/cache.c b/arch/m68k/mm/cache.c
index dde978e66f14fb31..d23958bc2a815ea7 100644
--- a/arch/m68k/mm/cache.c
+++ b/arch/m68k/mm/cache.c
@@ -8,6 +8,8 @@
  */
 
 #include <linux/module.h>
+#include <linux/preempt.h>
+
 #include <asm/cacheflush.h>
 #include <asm/traps.h>
 
@@ -62,14 +64,21 @@ void flush_icache_user_range(unsigned long address, unsigned long endaddr)
 		unsigned long start, end;
 		start = address & ICACHE_SET_MASK;
 		end = endaddr & ICACHE_SET_MASK;
+
+		preempt_disable();
+
 		if (start > end) {
 			flush_cf_icache(0, end);
 			end = ICACHE_MAX_ADDR;
 		}
 		flush_cf_icache(start, end);
+
+		preempt_enable();
 	} else if (CPU_IS_040_OR_060) {
 		address &= PAGE_MASK;
 
+		preempt_disable();
+
 		do {
 			asm volatile ("nop\n\t"
 				      ".chip 68040\n\t"
@@ -78,6 +87,8 @@ void flush_icache_user_range(unsigned long address, unsigned long endaddr)
 				      : : "a" (virt_to_phys_slow(address)));
 			address += PAGE_SIZE;
 		} while (address < endaddr);
+
+		preempt_enable();
 	} else {
 		unsigned long tmp;
 		asm volatile ("movec %%cacr,%0\n\t"
@@ -103,12 +114,16 @@ void flush_icache_user_page(struct vm_area_struct *vma, struct page *page,
 		unsigned long start, end;
 		start = addr & ICACHE_SET_MASK;
 		end = (addr + len) & ICACHE_SET_MASK;
+
+		preempt_disable();
+
 		if (start > end) {
 			flush_cf_icache(0, end);
 			end = ICACHE_MAX_ADDR;
 		}
 		flush_cf_icache(start, end);
 
+		preempt_enable();
 	} else if (CPU_IS_040_OR_060) {
 		asm volatile ("nop\n\t"
 			      ".chip 68040\n\t"
