2.4: preempt-kernel for PPC
PATCH 1/1 2.4: preempt-kernel for PPC
Attached patch provides preemptive kernel support for the PPC architecture. This patch is against kernel 2.4.19-pre9 and is meant to be applied on top of the standard preempt-kernel patch available from:
ftp://ftp.kernel.org/pub/linux/kernel/people/rml/preempt-kernel
If all goes well I will integrate this into the next release of the preempt-kernel patch.
Much thanks to MontaVista for providing this work to the community.
Enjoy,
Robert Love
arch/ppc/config.in +2 -0
@@ -109,6 +109,8 @@ bool ' Distribute interrupts on all CPUs by default' CONFIG_IRQ_ALL_CPUS fi +bool 'Preemptible kernel support' CONFIG_PREEMPT + if [ "$CONFIG_6xx" = "y" -a "$CONFIG_8260" = "n" ];then bool 'AltiVec Support' CONFIG_ALTIVEC bool 'Thermal Management Support' CONFIG_TAU
arch/ppc/kernel/entry.S +35 -0
@@ -277,6 +277,41 @@ */ cmpi 0,r3,0 beq restore +#ifdef CONFIG_PREEMPT + lwz r3,PREEMPT_COUNT(r2) + cmpi 0,r3,1 + bge ret_from_except + lwz r5,_MSR(r1) + andi. r5,r5,MSR_PR + bne do_signal_ret + lwz r5,NEED_RESCHED(r2) + cmpi 0,r5,0 + beq ret_from_except + lis r3,irq_stat@h + ori r3,r3,irq_stat@l + lwz r5,4(r3) + lwz r3,8(r3) + add r3,r3,r5 + cmpi 0,r3,0 + bne ret_from_except + lwz r3,PREEMPT_COUNT(r2) + addi r3,r3,1 + stw r3,PREEMPT_COUNT(r2) + mfmsr r0 + ori r0,r0,MSR_EE + mtmsr r0 + sync + bl preempt_schedule + mfmsr r0 + rlwinm r0,r0,0,17,15 + mtmsr r0 + sync + lwz r3,PREEMPT_COUNT(r2) + subi r3,r3,1 + stw r3,PREEMPT_COUNT(r2) + li r3,1 + b ret_from_intercept +#endif /* CONFIG_PREEMPT */ .globl ret_from_except ret_from_except: lwz r3,_MSR(r1) /* Returning to user mode? */
arch/ppc/kernel/irq.c +28 -0
@@ -568,6 +568,34 @@return 1 ;/* lets ret_from_int know we can do checks */ } +#ifdef CONFIG_PREEMPT +int +preempt_intercept (struct pt_regs *regs) +{ +int ret; + +preempt_disable (); + +switch (regs->trap) { +case 0x500 : + ret =do_IRQ (regs); +break ; +#ifndef CONFIG_4xx +case 0x900 : +#else +case 0x1000 : +#endif + ret =timer_interrupt (regs); +break ; +default : +BUG (); + } + +preempt_enable (); +return ret; +} +#endif /* CONFIG_PREEMPT */ +unsigned long probe_irq_on (void ) {return 0 ;
arch/ppc/kernel/mk_defs.c +3 -0
@@ -42,6 +42,9 @@DEFINE (SIGPENDING , offsetof(struct task_struct , sigpending));DEFINE (THREAD , offsetof(struct task_struct , thread));DEFINE (MM , offsetof(struct task_struct , mm)); +#ifdef CONFIG_PREEMPT +DEFINE (PREEMPT_COUNT , offsetof(struct task_struct , preempt_count)); +#endif DEFINE (ACTIVE_MM , offsetof(struct task_struct , active_mm));DEFINE (TASK_STRUCT_SIZE ,sizeof (struct task_struct ));DEFINE (KSP , offsetof(struct thread_struct , ksp));
arch/ppc/kernel/setup.c +14 -0
@@ -504,6 +504,20 @@parse_bootinfo (); +#ifdef CONFIG_PREEMPT +/* Override the irq routines for external & timer interrupts here, +* as the MMU has only been minimally setup at this point and +* there are no protections on page zero. +*/ + { +extern int preempt_intercept (struct pt_regs *); + + do_IRQ_intercept = (unsigned long ) &preempt_intercept; + timer_interrupt_intercept = (unsigned long ) &preempt_intercept; + + } +#endif /* CONFIG_PREEMPT */ +platform_init (r3, r4, r5, r6, r7);if (ppc_md.progress)
arch/ppc/lib/dec_and_lock.c +1 -0
@@ -1,4 +1,5 @@#include <linux/module.h> +#include <linux/sched.h> #include <linux/spinlock.h> #include <asm/atomic.h> #include <asm/system.h>
include/asm-ppc/dma.h +1 -0
@@ -14,6 +14,7 @@#include <linux/config.h> #include <asm/io.h> #include <linux/spinlock.h> +#include <linux/sched.h> #include <asm/system.h> /*
include/asm-ppc/hardirq.h +1 -0
@@ -44,6 +44,7 @@#define hardirq_exit (cpu) (local_irq_count(cpu)--)#define synchronize_irq () do { } while (0) +#define release_irqlock (cpu) do { } while (0)#else /* CONFIG_SMP */
include/asm-ppc/highmem.h +5 -1
@@ -84,6 +84,7 @@unsigned int idx;unsigned long vaddr; +preempt_disable ();if (page < highmem_start_page)return page_address (page);
@@ -105,8 +106,10 @@unsigned long vaddr = (unsigned long ) kvaddr;unsigned int idx = type +KM_TYPE_NR *smp_processor_id (); -if (vaddr <KMAP_FIX_BEGIN )// FIXME +if (vaddr <KMAP_FIX_BEGIN ) {// FIXME +preempt_enable ();return ; + }if (vaddr !=KMAP_FIX_BEGIN + idx *PAGE_SIZE )BUG ();
@@ -118,6 +121,7 @@pte_clear (kmap_pte+idx);flush_tlb_page (0 , vaddr);#endif + preempt_enable(); }#endif /* __KERNEL__ */
include/asm-ppc/mmu_context.h +4 -0
@@ -158,6 +158,10 @@static inline void switch_mm (struct mm_struct *prev,struct mm_struct *next,struct task_struct *tsk,int cpu) { +#ifdef CONFIG_PREEMPT +if (preempt_get_count () ==0 ) +BUG (); +#endif tsk->thread.pgdir = next->pgd;get_mmu_context (next);set_context (next->context, next->pgd);
include/asm-ppc/pgalloc.h +9 -0
@@ -68,20 +68,25 @@ {unsigned long *ret; +preempt_disable ();if ((ret = pgd_quicklist) !=NULL ) { pgd_quicklist = (unsigned long *)(*ret); ret[0 ] =0 ; pgtable_cache_size--; +preempt_enable (); }else +preempt_enable (); ret = (unsigned long *)get_pgd_slow ();return (pgd_t *)ret; }extern __inline__void free_pgd_fast (pgd_t *pgd) { +preempt_disable (); *(unsigned long **)pgd = pgd_quicklist; pgd_quicklist = (unsigned long *) pgd; pgtable_cache_size++; +preempt_enable (); }extern __inline__void free_pgd_slow (pgd_t *pgd)
@@ -120,19 +125,23 @@ {unsigned long *ret; +preempt_disable ();if ((ret = pte_quicklist) !=NULL ) { pte_quicklist = (unsigned long *)(*ret); ret[0 ] =0 ; pgtable_cache_size--; } +preempt_enable ();return (pte_t *)ret; }extern __inline__void pte_free_fast (pte_t *pte) { +preempt_disable (); *(unsigned long **)pte = pte_quicklist; pte_quicklist = (unsigned long *) pte; pgtable_cache_size++; +preempt_enable (); }extern __inline__void pte_free_slow (pte_t *pte)
include/asm-ppc/smplock.h +14 -0
@@ -15,7 +15,15 @@extern spinlock_t kernel_flag; +#ifdef CONFIG_SMP #define kernel_locked () spin_is_locked(&kernel_flag) +#else +#ifdef CONFIG_PREEMPT +#define kernel_locked () preempt_get_count() +#else +#define kernel_locked () 1 +#endif +#endif /* * Release global kernel lock and global interrupt lock
@@ -47,8 +55,14 @@*/ static __inline__void lock_kernel (void ) { +#ifdef CONFIG_PREEMPT +if (current->lock_depth ==-1 ) +spin_lock (&kernel_flag); + ++current->lock_depth; +#else if (!++current->lock_depth)spin_lock (&kernel_flag); +#endif }static __inline__void unlock_kernel (void )
include/asm-ppc/softirq.h +9 -1
@@ -10,6 +10,7 @@#define local_bh_disable () \ do { \ + preempt_disable(); \ local_bh_count(smp_processor_id())++; \ barrier(); \ } while (0)
@@ -18,9 +19,10 @@do { \barrier (); \local_bh_count (smp_processor_id ())--; \ +preempt_enable (); \ } while (0) -#define local_bh_enable () \ +#define _local_bh_enable () \ do { \ if (!--local_bh_count(smp_processor_id()) \ && softirq_pending(smp_processor_id())) { \
@@ -28,6 +30,12 @@ } \ } while (0) +#define local_bh_enable () \ +do { \ + _local_bh_enable(); \ + preempt_enable(); \ +} while (0) +#define in_softirq () (local_bh_count(smp_processor_id()) != 0)#endif /* __ASM_SOFTIRQ_H */