2005-04-16 15:20:36 -07:00
/*
* S390 version
*
* Derived from " include/asm-i386/mmu_context.h "
*/
# ifndef __S390_MMU_CONTEXT_H
# define __S390_MMU_CONTEXT_H
2007-02-05 21:18:17 +01:00
# include <asm/pgalloc.h>
2008-02-09 18:24:35 +01:00
# include <asm/uaccess.h>
2010-08-24 09:26:21 +02:00
# include <asm/tlbflush.h>
2012-03-28 18:30:02 +01:00
# include <asm/ctl_reg.h>
2007-05-02 19:27:14 +02:00
2008-01-26 14:10:58 +01:00
static inline int init_new_context ( struct task_struct * tsk ,
struct mm_struct * mm )
{
2010-08-24 09:26:21 +02:00
atomic_set ( & mm - > context . attach_count , 0 ) ;
mm - > context . flush_mm = 0 ;
2008-02-09 18:24:35 +01:00
mm - > context . asce_bits = _ASCE_TABLE_LENGTH | _ASCE_USER_BITS ;
2008-01-26 14:10:58 +01:00
# ifdef CONFIG_64BIT
2008-02-09 18:24:37 +01:00
mm - > context . asce_bits | = _ASCE_TYPE_REGION3 ;
2008-01-26 14:10:58 +01:00
# endif
2013-07-26 15:04:02 +02:00
mm - > context . has_pgste = 0 ;
2008-02-09 18:24:37 +01:00
mm - > context . asce_limit = STACK_TOP_MAX ;
crst_table_init ( ( unsigned long * ) mm - > pgd , pgd_entry_type ( mm ) ) ;
2008-01-26 14:10:58 +01:00
return 0 ;
}
2005-04-16 15:20:36 -07:00
# define destroy_context(mm) do { } while (0)
2012-05-23 16:24:51 +02:00
# ifndef CONFIG_64BIT
2007-02-05 21:18:17 +01:00
# define LCTL_OPCODE "lctl"
# else
# define LCTL_OPCODE "lctlg"
# endif
2014-04-03 13:54:59 +02:00
static inline void update_user_asce ( struct mm_struct * mm )
2005-04-16 15:20:36 -07:00
{
2008-02-09 18:24:35 +01:00
pgd_t * pgd = mm - > pgd ;
S390_lowcore . user_asce = mm - > context . asce_bits | __pa ( pgd ) ;
2013-09-24 09:14:56 +02:00
/* Load primary space page table origin. */
asm volatile ( LCTL_OPCODE " 1,1,%0 \n " : : " m " ( S390_lowcore . user_asce ) ) ;
2008-02-09 18:24:37 +01:00
set_fs ( current - > thread . mm_segment ) ;
2005-04-16 15:20:36 -07:00
}
2014-04-03 13:54:59 +02:00
static inline void clear_user_asce ( struct mm_struct * mm )
{
S390_lowcore . user_asce = S390_lowcore . kernel_asce ;
asm volatile ( LCTL_OPCODE " 1,1,%0 \n " : : " m " ( S390_lowcore . user_asce ) ) ;
asm volatile ( LCTL_OPCODE " 7,7,%0 \n " : : " m " ( S390_lowcore . user_asce ) ) ;
}
2005-04-16 15:20:36 -07:00
static inline void switch_mm ( struct mm_struct * prev , struct mm_struct * next ,
2007-02-05 21:18:17 +01:00
struct task_struct * tsk )
2005-04-16 15:20:36 -07:00
{
2012-09-10 13:00:09 +02:00
int cpu = smp_processor_id ( ) ;
if ( prev = = next )
return ;
if ( atomic_inc_return ( & next - > context . attach_count ) > > 16 ) {
2014-04-03 13:54:59 +02:00
/* Delay update_user_asce until all TLB flushes are done. */
2012-09-10 13:00:09 +02:00
set_tsk_thread_flag ( tsk , TIF_TLB_WAIT ) ;
2014-04-03 13:54:59 +02:00
/* Clear old ASCE by loading the kernel ASCE. */
clear_user_asce ( next ) ;
2012-09-10 13:00:09 +02:00
} else {
cpumask_set_cpu ( cpu , mm_cpumask ( next ) ) ;
2014-04-03 13:54:59 +02:00
update_user_asce ( next ) ;
2012-09-10 13:00:09 +02:00
if ( next - > context . flush_mm )
/* Flush pending TLBs */
__tlb_flush_mm ( next ) ;
}
2010-08-24 09:26:21 +02:00
atomic_dec ( & prev - > context . attach_count ) ;
WARN_ON ( atomic_read ( & prev - > context . attach_count ) < 0 ) ;
2012-09-10 13:00:09 +02:00
}
# define finish_arch_post_lock_switch finish_arch_post_lock_switch
static inline void finish_arch_post_lock_switch ( void )
{
struct task_struct * tsk = current ;
struct mm_struct * mm = tsk - > mm ;
if ( ! test_tsk_thread_flag ( tsk , TIF_TLB_WAIT ) )
return ;
preempt_disable ( ) ;
clear_tsk_thread_flag ( tsk , TIF_TLB_WAIT ) ;
while ( atomic_read ( & mm - > context . attach_count ) > > 16 )
cpu_relax ( ) ;
cpumask_set_cpu ( smp_processor_id ( ) , mm_cpumask ( mm ) ) ;
2014-04-03 13:54:59 +02:00
update_user_asce ( mm ) ;
2012-09-10 13:00:09 +02:00
if ( mm - > context . flush_mm )
__tlb_flush_mm ( mm ) ;
preempt_enable ( ) ;
2005-04-16 15:20:36 -07:00
}
2007-10-22 12:52:47 +02:00
# define enter_lazy_tlb(mm,tsk) do { } while (0)
2005-04-16 15:20:36 -07:00
# define deactivate_mm(tsk,mm) do { } while (0)
2005-11-08 21:34:42 -08:00
static inline void activate_mm ( struct mm_struct * prev ,
2005-04-16 15:20:36 -07:00
struct mm_struct * next )
{
switch_mm ( prev , next , current ) ;
}
2012-07-26 08:53:06 +02:00
static inline void arch_dup_mmap ( struct mm_struct * oldmm ,
struct mm_struct * mm )
{
# ifdef CONFIG_64BIT
if ( oldmm - > context . asce_limit < mm - > context . asce_limit )
crst_table_downgrade ( mm , oldmm - > context . asce_limit ) ;
# endif
}
static inline void arch_exit_mmap ( struct mm_struct * mm )
{
}
2007-02-05 21:18:17 +01:00
# endif /* __S390_MMU_CONTEXT_H */