/Documentation/virtual/

href='or' title='litmus-rt-imx6.git Git repository'/>
aboutsummaryrefslogblamecommitdiffstats
path: root/mm/percpu.c
blob: c76ef3891e0da1c71ac3d1b2d4b1db0abdfe8b9f (plain) (tree)
1
2
3
4
5
6
7
8
9
  
                                        






                                                                    


                                                                  


                                                                  
                                                         







                                                                        



                                                                 
  

                                                                     










                                                                      

                                                                       


                                                             
                                                                      

                                                                  
  

                                                                      



                          
                      
                       
                       




                         
                       
                           
                          
                            

                           
                         
                         
                   
 


                                                                               


                                                                              


                                                                         


                                                                         


                                                                         

      

                                                                               

                                                                              
                                                                                


                                                                                
                                                                
                                                                               
                                                                      

  

                                         
                                       
                                        

                                                   
 



                                                      
                                                                             
                                   

                                  

                                                                                
 




                                                             













                                                                    
                                              

                                     
  


                                                                    


                                                                    


                                                                      



                                                                      








                                                                      
   

                                                                              
 
                                                                        
 



                                                                         














                                                                          
                                        
 
                                                              


                                                          






                                         







                                                                               












                                                                           
 
                                                               

 

                                                                    
 
                                                                         
                                         

 

                                                                     




                                                             

                                                                   




















                                                                             
   

                                   
  


                                                                 
  


                              
           
                                                             
   
                                        
 


                                               








                                                 
 








                                                                      
                              
                           
            
                           








                                                                      

                                                                   


             




                                                                    
                                                             






                                                                        
   

                                                                              
  

                                                               
  
           
             
  
           

                                                                
   
                                                        

                      
 






                                                    























                                                                        
                               
 




                                                          
 
                                                            


                                   
 

                                     











                                                                    



                 


                                       

                                       








                                                                     
                                                                   


             
   

                                                             

                                       
 
                                                              
 
                                  











                                                               




                                                    
                              





                                                                  

                                                 


             
           

                                                                   






                                                                         







































                                                                                
                                                               

























                                                                                

                                                                       









                                                                      


             


































                                                                              



                                                
                                                       


























                                                                                













                                                                                
   





                                                                               
 


                             
                      
      

   























                                                                        
                                                            


   
                                    
                                           
                                            
                                                           
  



                                                         



                                                                    
                                                                          
 
                                   
                                 
                        
                                 
                            
 
                                                                                




                                                                   
                                      
                                             
 


                                                                             


                                                                 
                                         
                 









                                                                                    


                                                          
 
                                                         
                                 

         
        
                                          



                                                                            
 













                                                                          

                         


                                                                  



                                                       
                                                  
 
                                    

                                                     
                                       
         
 
                                             
                                       
                     

           
                                                  
 

                                                    
                                                     
                                           
                                           
                                 

         

                                        

                                                          

            
                                                  

                                        






                                                                            
                    
 








                                                                


                              


                                                                    
                                                        


                                              

                                  








                                                                      


                              


                                                                    
                                                                 



                                             




                                                               


                     

                                                  
 



                                                               

                                      







                                                                             


                                               
                                    

                                                            
                                                                
                                          
         

                                        





                                 



                                     
   
                                    
 
                   
                                 
                            




                       

                                       
                                             

                                             
                                      


                                   
                                                                               


                                                 
                                                                             
                                           
                                                                  



                                      
                                                  


                               
   

























                                                                                












                                                                              

























                                                                                





                                                                   
                                                             

 
   























































                                                                              
                                                            
                                                               

                                                                          
  


                                                                     
  




                                                                      

           

                                                                  
   

                                                                      

                                                                          



                                                                   
                                        

                                                                             
                                     
                               

                                   
 

                                                        
                                                
 


                                                                                

                                                          

                                                                    
                                                                  


                                                                      

                                                                    
                                                       











                                                                     
                                                                          


                                                                            
                                                                      




                                                













                                                                          
                                                             





                                                                              
                                                            











                                                                































                                                                      
 

                                                    


                                                                  
         
                                 
 
                  

 








                                                                     
 
                                                  
                                      






                                                              
 
                                
                       

                                                                       
 


                                                        
 


                                                                             
 







                                                                      
                                             









                                                                      
                 


                     
 
   
                                                             
                                                               
                             


                                                                     
              
  





                                                                    






                                                                    


                                                                      
  


                                                                      
  

                                                                   
  








                                                                     
  

                                                                  
  






                                                                      
           
                                   
   

                                                                   
 
                                              

                                                               

                                                                         
                                                  

                                     
                                
                         

                           
 










                                                                         
                           





                                                              
                                                                    
                                                          
 


                                                                                
                                                                   
                                                                   
 
                                              
                                         
                                      
 

                                                                              
 


                                                                  



                                                    
 


                                                                     
 
                                                 

                                                                            

                                                           
                                                 
                 
         


                                  




                                                                              
 


                                           
                                 
                                     

                                        
                                                      
                                                       
                                       

                                                                       
 




                                                                 



                                                                        






                                                                     

                                                       
                                      

                                             
                                 
                                                        
 

                                                      
                                             
                                                                                



                                                                          
                                                
 
                                                           


                                                                    

                                             
                                                               
                                              
                                              

                                                     
                                         
                                                                





                                                                             
                                     

                                                  

                        
                                   
                 
 
 



                                                    
  
 
                                                      
 











                                               

                                                                            
 
                 
 
                                                
 

                                                       

                                                                     
                                                            
                                                               



                                                                          




                                                                      









                                                                      
  
                                                     

                                                                   
                                                 

           
                                   
   
                                                                        



                                                                            
 

                                       
                                   
                                                  
                         
 

                                                                      

                                   
 
                                                                      
                                                               
 

                                                  
                             
                              
         
 
















                                                                             
 











                                                                          
         
 
                                                                     

                                                         
                                                                    

                                                                    




                                                                           
                                                                              







                                                                      
 
                                                                           

                                                                             
 
                                              






                                                                    
                                 

                                                      
                  
 

                                                  
 
                                           
   
                                                                    




                                                                            

                                                                      




                                                                
                                   
   



                                                                           
 
                                   
                                   
                           
                       
                          
                            
                           
 

                                                                        
                                                                      





                                                              

                                                                         

                                                                 
                                          
 
                            
              
                                                          
                                                  
                                                                       

                                  
                                                                  
                                   

                                                                                

                                            
                                                       

                 

                                                                  
                                                      

                                               
                                                            
                                         
                                                                      
 
                                                


                                                                         



                                                                           
 








                                                                      
                                                                           


                                 
                                                               

                                                                
 
                                                 



                         
                                                           
                     
            
                                              
                                 
                  
 
                                                 
 
  














                                                                      




                                                                           
 




                                                           

                                     

                            
               




                                                                   
                                                          

                                                                            
                   



                                                                               
                                                                       
 
                                           





























                                                                                
/*
 * mm/percpu.c - percpu memory allocator
 *
 * Copyright (C) 2009		SUSE Linux Products GmbH
 * Copyright (C) 2009		Tejun Heo <tj@kernel.org>
 *
 * This file is released under the GPLv2.
 *
 * This is percpu allocator which can handle both static and dynamic
 * areas.  Percpu areas are allocated in chunks.  Each chunk is
 * consisted of boot-time determined number of units and the first
 * chunk is used for static percpu variables in the kernel image
 * (special boot time alloc/init handling necessary as these areas
 * need to be brought up before allocation services are running).
 * Unit grows as necessary and all units grow or shrink in unison.
 * When a chunk is filled up, another chunk is allocated.
 *
 *  c0                           c1                         c2
 *  -------------------          -------------------        ------------
 * | u0 | u1 | u2 | u3 |        | u0 | u1 | u2 | u3 |      | u0 | u1 | u
 *  -------------------  ......  -------------------  ....  ------------
 *
 * Allocation is done in offset-size areas of single unit space.  Ie,
 * an area of 512 bytes at 6k in c1 occupies 512 bytes at 6k of c1:u0,
 * c1:u1, c1:u2 and c1:u3.  On UMA, units corresponds directly to
 * cpus.  On NUMA, the mapping can be non-linear and even sparse.
 * Percpu access can be done by configuring percpu base registers
 * according to cpu to unit mapping and pcpu_unit_size.
 *
 * There are usually many small percpu allocations many of them being
 * as small as 4 bytes.  The allocator organizes chunks into lists
 * according to free size and tries to allocate from the fullest one.
 * Each chunk keeps the maximum contiguous area size hint which is
 * guaranteed to be eqaul to or larger than the maximum contiguous
 * area in the chunk.  This helps the allocator not to iterate the
 * chunk maps unnecessarily.
 *
 * Allocation state in each chunk is kept using an array of integers
 * on chunk->map.  A positive value in the map represents a free
 * region and negative allocated.  Allocation inside a chunk is done
 * by scanning this map sequentially and serving the first matching
 * entry.  This is mostly copied from the percpu_modalloc() allocator.
 * Chunks can be determined from the address using the index field
 * in the page struct. The index field contains a pointer to the chunk.
 *
 * To use this allocator, arch code should do the followings.
 *
 * - define __addr_to_pcpu_ptr() and __pcpu_ptr_to_addr() to translate
 *   regular address to percpu pointer and back if they need to be
 *   different from the default
 *
 * - use pcpu_setup_first_chunk() during percpu area initialization to
 *   setup the first chunk containing the kernel static percpu area
 */

#include <linux/bitmap.h>
#include <linux/bootmem.h>
#include <linux/err.h>
#include <linux/list.h>
#include <linux/log2.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/percpu.h>
#include <linux/pfn.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/vmalloc.h>
#include <linux/workqueue.h>

#include <asm/cacheflush.h>
#include <asm/sections.h>
#include <asm/tlbflush.h>
#include <asm/io.h>

#define PCPU_SLOT_BASE_SHIFT		5	/* 1-31 shares the same slot */
#define PCPU_DFL_MAP_ALLOC		16	/* start a map with 16 ents */

/* default addr <-> pcpu_ptr mapping, override in asm/percpu.h if necessary */
#ifndef __addr_to_pcpu_ptr
#define __addr_to_pcpu_ptr(addr)					\
	(void __percpu *)((unsigned long)(addr) -			\
			  (unsigned long)pcpu_base_addr	+		\
			  (unsigned long)__per_cpu_start)
#endif
#ifndef __pcpu_ptr_to_addr
#define __pcpu_ptr_to_addr(ptr)						\
	(void __force *)((unsigned long)(ptr) +				\
			 (unsigned long)pcpu_base_addr -		\
			 (unsigned long)__per_cpu_start)
#endif

struct pcpu_chunk {
	struct list_head	list;		/* linked to pcpu_slot lists */
	int			free_size;	/* free bytes in the chunk */
	int			contig_hint;	/* max contiguous size hint */
	void			*base_addr;	/* base address of this chunk */
	int			map_used;	/* # of map entries used */
	int			map_alloc;	/* # of map entries allocated */
	int			*map;		/* allocation map */
	void			*data;		/* chunk data */
	bool			immutable;	/* no [de]population allowed */
	unsigned long		populated[];	/* populated bitmap */
};

static int pcpu_unit_pages __read_mostly;
static int pcpu_unit_size __read_mostly;
static int pcpu_nr_units __read_mostly;
static int pcpu_atom_size __read_mostly;
static int pcpu_nr_slots __read_mostly;
static size_t pcpu_chunk_struct_size __read_mostly;

/* cpus with the lowest and highest unit numbers */
static unsigned int pcpu_first_unit_cpu __read_mostly;
static unsigned int pcpu_last_unit_cpu __read_mostly;

/* the address of the first chunk which starts with the kernel static area */
void *pcpu_base_addr __read_mostly;
EXPORT_SYMBOL_GPL(pcpu_base_addr);

static const int *pcpu_unit_map __read_mostly;		/* cpu -> unit */
const unsigned long *pcpu_unit_offsets __read_mostly;	/* cpu -> unit offset */

/* group information, used for vm allocation */
static int pcpu_nr_groups __read_mostly;
static const unsigned long *pcpu_group_offsets __read_mostly;
static const size_t *pcpu_group_sizes __read_mostly;

/*
 * The first chunk which always exists.  Note that unlike other
 * chunks, this one can be allocated and mapped in several different
 * ways and thus often doesn't live in the vmalloc area.
 */
static struct pcpu_chunk *pcpu_first_chunk;

/*
 * Optional reserved chunk.  This chunk reserves part of the first
 * chunk and serves it for reserved allocations.  The amount of
 * reserved offset is in pcpu_reserved_chunk_limit.  When reserved
 * area doesn't exist, the following variables contain NULL and 0
 * respectively.
 */
static struct pcpu_chunk *pcpu_reserved_chunk;
static int pcpu_reserved_chunk_limit;

/*
 * Synchronization rules.
 *
 * There are two locks - pcpu_alloc_mutex and pcpu_lock.  The former
 * protects allocation/reclaim paths, chunks, populated bitmap and
 * vmalloc mapping.  The latter is a spinlock and protects the index
 * data structures - chunk slots, chunks and area maps in chunks.
 *
 * During allocation, pcpu_alloc_mutex is kept locked all the time and
 * pcpu_lock is grabbed and released as necessary.  All actual memory
 * allocations are done using GFP_KERNEL with pcpu_lock released.  In
 * general, percpu memory can't be allocated with irq off but
 * irqsave/restore are still used in alloc path so that it can be used
 * from early init path - sched_init() specifically.
 *
 * Free path accesses and alters only the index data structures, so it
 * can be safely called from atomic context.  When memory needs to be
 * returned to the system, free path schedules reclaim_work which
 * grabs both pcpu_alloc_mutex and pcpu_lock, unlinks chunks to be
 * reclaimed, release both locks and frees the chunks.  Note that it's
 * necessary to grab both locks to remove a chunk from circulation as
 * allocation path might be referencing the chunk with only
 * pcpu_alloc_mutex locked.
 */
static DEFINE_MUTEX(pcpu_alloc_mutex);	/* protects whole alloc and reclaim */
static DEFINE_SPINLOCK(pcpu_lock);	/* protects index data structures */

static struct list_head *pcpu_slot __read_mostly; /* chunk list slots */

/* reclaim work to release fully free chunks, scheduled from free path */
static void pcpu_reclaim(struct work_struct *work);
static DECLARE_WORK(pcpu_reclaim_work, pcpu_reclaim);

static bool pcpu_addr_in_first_chunk(void *addr)
{
	void *first_start = pcpu_first_chunk->base_addr;

	return addr >= first_start && addr < first_start + pcpu_unit_size;
}

static bool pcpu_addr_in_reserved_chunk(void *addr)
{
	void *first_start = pcpu_first_chunk->base_addr;

	return addr >= first_start &&
		addr < first_start + pcpu_reserved_chunk_limit;
}

static int __pcpu_size_to_slot(int size)
{
	int highbit = fls(size);	/* size is in bytes */