2008-07-29 22:33:56 -07:00
/*
* SN Platform GRU Driver
*
* FILE OPERATIONS & DRIVER INITIALIZATION
*
* This file supports the user system call for file open , close , mmap , etc .
* This also incudes the driver initialization code .
*
* Copyright ( c ) 2008 Silicon Graphics , Inc . All Rights Reserved .
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
# include <linux/module.h>
# include <linux/kernel.h>
# include <linux/errno.h>
# include <linux/slab.h>
# include <linux/mm.h>
# include <linux/io.h>
# include <linux/spinlock.h>
# include <linux/device.h>
# include <linux/miscdevice.h>
# include <linux/interrupt.h>
# include <linux/proc_fs.h>
# include <linux/uaccess.h>
2009-12-15 16:48:11 -08:00
# ifdef CONFIG_X86_64
# include <asm/uv/uv_irq.h>
# endif
2009-02-09 10:25:20 -06:00
# include <asm/uv/uv.h>
2008-07-29 22:33:56 -07:00
# include "gru.h"
# include "grulib.h"
# include "grutables.h"
# include <asm/uv/uv_hub.h>
# include <asm/uv/uv_mmrs.h>
struct gru_blade_state * gru_base [ GRU_MAX_BLADES ] __read_mostly ;
2009-04-02 16:59:04 -07:00
unsigned long gru_start_paddr __read_mostly ;
2009-06-17 16:28:28 -07:00
void * gru_start_vaddr __read_mostly ;
2009-04-02 16:59:04 -07:00
unsigned long gru_end_paddr __read_mostly ;
2009-04-02 16:59:10 -07:00
unsigned int gru_max_gids __read_mostly ;
2008-07-29 22:33:56 -07:00
struct gru_stats_s gru_stats ;
/* Guaranteed user available resources on each node */
static int max_user_cbrs , max_user_dsr_bytes ;
static struct miscdevice gru_miscdev ;
/*
* gru_vma_close
*
* Called when unmapping a device mapping . Frees all gru resources
* and tables belonging to the vma .
*/
static void gru_vma_close ( struct vm_area_struct * vma )
{
struct gru_vma_data * vdata ;
struct gru_thread_state * gts ;
struct list_head * entry , * next ;
if ( ! vma - > vm_private_data )
return ;
vdata = vma - > vm_private_data ;
vma - > vm_private_data = NULL ;
gru_dbg ( grudev , " vma %p, file %p, vdata %p \n " , vma , vma - > vm_file ,
vdata ) ;
list_for_each_safe ( entry , next , & vdata - > vd_head ) {
gts =
list_entry ( entry , struct gru_thread_state , ts_next ) ;
list_del ( & gts - > ts_next ) ;
mutex_lock ( & gts - > ts_ctxlock ) ;
if ( gts - > ts_gru )
gru_unload_context ( gts , 0 ) ;
mutex_unlock ( & gts - > ts_ctxlock ) ;
gts_drop ( gts ) ;
}
kfree ( vdata ) ;
STAT ( vdata_free ) ;
}
/*
* gru_file_mmap
*
tree-wide: fix assorted typos all over the place
That is "success", "unknown", "through", "performance", "[re|un]mapping"
, "access", "default", "reasonable", "[con]currently", "temperature"
, "channel", "[un]used", "application", "example","hierarchy", "therefore"
, "[over|under]flow", "contiguous", "threshold", "enough" and others.
Signed-off-by: André Goddard Rosa <andre.goddard@gmail.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
2009-11-14 13:09:05 -02:00
* Called when mmapping the device . Initializes the vma with a fault handler
2008-07-29 22:33:56 -07:00
* and private data structure necessary to allocate , track , and free the
* underlying pages .
*/
static int gru_file_mmap ( struct file * file , struct vm_area_struct * vma )
{
if ( ( vma - > vm_flags & ( VM_SHARED | VM_WRITE ) ) ! = ( VM_SHARED | VM_WRITE ) )
return - EPERM ;
2008-07-29 22:34:02 -07:00
if ( vma - > vm_start & ( GRU_GSEG_PAGESIZE - 1 ) | |
2009-04-02 16:59:04 -07:00
vma - > vm_end & ( GRU_GSEG_PAGESIZE - 1 ) )
2008-07-29 22:34:02 -07:00
return - EINVAL ;
2008-07-29 22:33:56 -07:00
vma - > vm_flags | =
( VM_IO | VM_DONTCOPY | VM_LOCKED | VM_DONTEXPAND | VM_PFNMAP |
VM_RESERVED ) ;
vma - > vm_page_prot = PAGE_SHARED ;
vma - > vm_ops = & gru_vm_ops ;
vma - > vm_private_data = gru_alloc_vma_data ( vma , 0 ) ;
if ( ! vma - > vm_private_data )
return - ENOMEM ;
gru_dbg ( grudev , " file %p, vaddr 0x%lx, vma %p, vdata %p \n " ,
file , vma - > vm_start , vma , vma - > vm_private_data ) ;
return 0 ;
}
/*
* Create a new GRU context
*/
static int gru_create_new_context ( unsigned long arg )
{
struct gru_create_context_req req ;
struct vm_area_struct * vma ;
struct gru_vma_data * vdata ;
int ret = - EINVAL ;
if ( copy_from_user ( & req , ( void __user * ) arg , sizeof ( req ) ) )
return - EFAULT ;
2009-06-17 16:28:23 -07:00
if ( req . data_segment_bytes > max_user_dsr_bytes )
2008-07-29 22:33:56 -07:00
return - EINVAL ;
2009-06-17 16:28:23 -07:00
if ( req . control_blocks > max_user_cbrs | | ! req . maximum_thread_count )
2008-07-29 22:33:56 -07:00
return - EINVAL ;
if ( ! ( req . options & GRU_OPT_MISS_MASK ) )
req . options | = GRU_OPT_MISS_FMM_INTR ;
down_write ( & current - > mm - > mmap_sem ) ;
vma = gru_find_vma ( req . gseg ) ;
if ( vma ) {
vdata = vma - > vm_private_data ;
vdata - > vd_user_options = req . options ;
vdata - > vd_dsr_au_count =
GRU_DS_BYTES_TO_AU ( req . data_segment_bytes ) ;
vdata - > vd_cbr_au_count = GRU_CB_COUNT_TO_AU ( req . control_blocks ) ;
ret = 0 ;
}
up_write ( & current - > mm - > mmap_sem ) ;
return ret ;
}
/*
* Get GRU configuration info ( temp - for emulator testing )
*/
static long gru_get_config_info ( unsigned long arg )
{
struct gru_config_info info ;
int nodesperblade ;
if ( num_online_nodes ( ) > 1 & &
( uv_node_to_blade_id ( 1 ) = = uv_node_to_blade_id ( 0 ) ) )
nodesperblade = 2 ;
else
nodesperblade = 1 ;
info . cpus = num_online_cpus ( ) ;
info . nodes = num_online_nodes ( ) ;
info . blades = info . nodes / nodesperblade ;
info . chiplets = GRU_CHIPLETS_PER_BLADE * info . blades ;
if ( copy_to_user ( ( void __user * ) arg , & info , sizeof ( info ) ) )
return - EFAULT ;
return 0 ;
}
/*
* gru_file_unlocked_ioctl
*
* Called to update file attributes via IOCTL calls .
*/
static long gru_file_unlocked_ioctl ( struct file * file , unsigned int req ,
unsigned long arg )
{
int err = - EBADRQC ;
gru_dbg ( grudev , " file %p \n " , file ) ;
switch ( req ) {
case GRU_CREATE_CONTEXT :
err = gru_create_new_context ( arg ) ;
break ;
2009-06-17 16:28:32 -07:00
case GRU_SET_CONTEXT_OPTION :
err = gru_set_context_option ( arg ) ;
2008-07-29 22:33:56 -07:00
break ;
case GRU_USER_GET_EXCEPTION_DETAIL :
err = gru_get_exception_detail ( arg ) ;
break ;
case GRU_USER_UNLOAD_CONTEXT :
err = gru_user_unload_context ( arg ) ;
break ;
case GRU_USER_FLUSH_TLB :
err = gru_user_flush_tlb ( arg ) ;
break ;
case GRU_USER_CALL_OS :
err = gru_handle_user_call_os ( arg ) ;
break ;
2009-06-17 16:28:30 -07:00
case GRU_GET_GSEG_STATISTICS :
err = gru_get_gseg_statistics ( arg ) ;
break ;
2009-06-17 16:28:26 -07:00
case GRU_KTEST :
err = gru_ktest ( arg ) ;
break ;
2008-07-29 22:33:56 -07:00
case GRU_GET_CONFIG_INFO :
err = gru_get_config_info ( arg ) ;
break ;
2009-06-17 16:28:19 -07:00
case GRU_DUMP_CHIPLET_STATE :
err = gru_dump_chiplet_request ( arg ) ;
break ;
2008-07-29 22:33:56 -07:00
}
return err ;
}
/*
* Called at init time to build tables for all GRUs that are present in the
* system .
*/
static void gru_init_chiplet ( struct gru_state * gru , unsigned long paddr ,
2009-12-15 16:48:05 -08:00
void * vaddr , int blade_id , int chiplet_id )
2008-07-29 22:33:56 -07:00
{
spin_lock_init ( & gru - > gs_lock ) ;
spin_lock_init ( & gru - > gs_asid_lock ) ;
gru - > gs_gru_base_paddr = paddr ;
gru - > gs_gru_base_vaddr = vaddr ;
2009-12-15 16:48:05 -08:00
gru - > gs_gid = blade_id * GRU_CHIPLETS_PER_BLADE + chiplet_id ;
gru - > gs_blade = gru_base [ blade_id ] ;
gru - > gs_blade_id = blade_id ;
gru - > gs_chiplet_id = chiplet_id ;
2008-07-29 22:33:56 -07:00
gru - > gs_cbr_map = ( GRU_CBR_AU = = 64 ) ? ~ 0 : ( 1UL < < GRU_CBR_AU ) - 1 ;
gru - > gs_dsr_map = ( 1UL < < GRU_DSR_AU ) - 1 ;
2009-04-02 16:59:08 -07:00
gru - > gs_asid_limit = MAX_ASID ;
2008-07-29 22:33:56 -07:00
gru_tgh_flush_init ( gru ) ;
2009-04-02 16:59:10 -07:00
if ( gru - > gs_gid > = gru_max_gids )
gru_max_gids = gru - > gs_gid + 1 ;
2009-12-15 16:48:05 -08:00
gru_dbg ( grudev , " bid %d, gid %d, vaddr %p (0x%lx) \n " ,
blade_id , gru - > gs_gid , gru - > gs_gru_base_vaddr ,
2008-07-29 22:33:56 -07:00
gru - > gs_gru_base_paddr ) ;
}
static int gru_init_tables ( unsigned long gru_base_paddr , void * gru_base_vaddr )
{
int pnode , nid , bid , chip ;
int cbrs , dsrbytes , n ;
int order = get_order ( sizeof ( struct gru_blade_state ) ) ;
struct page * page ;
struct gru_state * gru ;
unsigned long paddr ;
void * vaddr ;
max_user_cbrs = GRU_NUM_CB ;
max_user_dsr_bytes = GRU_NUM_DSR_BYTES ;
2009-12-15 16:48:01 -08:00
for_each_possible_blade ( bid ) {
pnode = uv_blade_to_pnode ( bid ) ;
2009-12-15 16:48:03 -08:00
nid = uv_blade_to_memory_nid ( bid ) ; /* -1 if no memory on blade */
page = alloc_pages_node ( nid , GFP_KERNEL , order ) ;
2008-07-29 22:33:56 -07:00
if ( ! page )
goto fail ;
gru_base [ bid ] = page_address ( page ) ;
memset ( gru_base [ bid ] , 0 , sizeof ( struct gru_blade_state ) ) ;
gru_base [ bid ] - > bs_lru_gru = & gru_base [ bid ] - > bs_grus [ 0 ] ;
spin_lock_init ( & gru_base [ bid ] - > bs_lock ) ;
2009-06-17 16:28:28 -07:00
init_rwsem ( & gru_base [ bid ] - > bs_kgts_sema ) ;
2008-07-29 22:33:56 -07:00
dsrbytes = 0 ;
cbrs = 0 ;
for ( gru = gru_base [ bid ] - > bs_grus , chip = 0 ;
2009-04-02 16:59:04 -07:00
chip < GRU_CHIPLETS_PER_BLADE ;
2008-07-29 22:33:56 -07:00
chip + + , gru + + ) {
paddr = gru_chiplet_paddr ( gru_base_paddr , pnode , chip ) ;
vaddr = gru_chiplet_vaddr ( gru_base_vaddr , pnode , chip ) ;
2009-12-15 16:48:05 -08:00
gru_init_chiplet ( gru , paddr , vaddr , bid , chip ) ;
2008-07-29 22:33:56 -07:00
n = hweight64 ( gru - > gs_cbr_map ) * GRU_CBR_AU_SIZE ;
cbrs = max ( cbrs , n ) ;
n = hweight64 ( gru - > gs_dsr_map ) * GRU_DSR_AU_BYTES ;
dsrbytes = max ( dsrbytes , n ) ;
}
max_user_cbrs = min ( max_user_cbrs , cbrs ) ;
max_user_dsr_bytes = min ( max_user_dsr_bytes , dsrbytes ) ;
}
return 0 ;
fail :
2009-12-15 16:48:01 -08:00
for ( bid - - ; bid > = 0 ; bid - - )
free_pages ( ( unsigned long ) gru_base [ bid ] , order ) ;
2008-07-29 22:33:56 -07:00
return - ENOMEM ;
}
2009-12-15 16:48:11 -08:00
static void gru_free_tables ( void )
{
int bid ;
int order = get_order ( sizeof ( struct gru_state ) *
GRU_CHIPLETS_PER_BLADE ) ;
2008-07-29 22:33:56 -07:00
2009-12-15 16:48:11 -08:00
for ( bid = 0 ; bid < GRU_MAX_BLADES ; bid + + )
free_pages ( ( unsigned long ) gru_base [ bid ] , order ) ;
}
static unsigned long gru_chiplet_cpu_to_mmr ( int chiplet , int cpu , int * corep )
2008-07-29 22:33:56 -07:00
{
2009-12-15 16:48:11 -08:00
unsigned long mmr = 0 ;
int core ;
/*
* We target the cores of a blade and not the hyperthreads themselves .
* There is a max of 8 cores per socket and 2 sockets per blade ,
* making for a max total of 16 cores ( i . e . , 16 CPUs without
* hyperthreading and 32 CPUs with hyperthreading ) .
*/
core = uv_cpu_core_number ( cpu ) + UV_MAX_INT_CORES * uv_cpu_socket_number ( cpu ) ;
if ( core > = GRU_NUM_TFM | | uv_cpu_ht_number ( cpu ) )
return 0 ;
if ( chiplet = = 0 ) {
mmr = UVH_GR0_TLB_INT0_CONFIG +
core * ( UVH_GR0_TLB_INT1_CONFIG - UVH_GR0_TLB_INT0_CONFIG ) ;
} else if ( chiplet = = 1 ) {
mmr = UVH_GR1_TLB_INT0_CONFIG +
core * ( UVH_GR1_TLB_INT1_CONFIG - UVH_GR1_TLB_INT0_CONFIG ) ;
} else {
BUG ( ) ;
}
* corep = core ;
return mmr ;
2008-07-29 22:33:56 -07:00
}
2009-12-15 16:48:11 -08:00
# ifdef CONFIG_IA64
static int gru_irq_count [ GRU_CHIPLETS_PER_BLADE ] ;
2008-07-29 22:33:56 -07:00
2009-12-15 16:48:11 -08:00
static void gru_noop ( unsigned int irq )
2008-07-29 22:33:56 -07:00
{
}
2009-12-15 16:48:11 -08:00
static struct irq_chip gru_chip [ GRU_CHIPLETS_PER_BLADE ] = {
[ 0 . . . GRU_CHIPLETS_PER_BLADE - 1 ] {
. mask = gru_noop ,
. unmask = gru_noop ,
. ack = gru_noop
}
2008-07-29 22:33:56 -07:00
} ;
2009-12-15 16:48:11 -08:00
static int gru_chiplet_setup_tlb_irq ( int chiplet , char * irq_name ,
irq_handler_t irq_handler , int cpu , int blade )
{
unsigned long mmr ;
int irq = IRQ_GRU + chiplet ;
int ret , core ;
mmr = gru_chiplet_cpu_to_mmr ( chiplet , cpu , & core ) ;
if ( mmr = = 0 )
return 0 ;
if ( gru_irq_count [ chiplet ] = = 0 ) {
gru_chip [ chiplet ] . name = irq_name ;
ret = set_irq_chip ( irq , & gru_chip [ chiplet ] ) ;
if ( ret ) {
printk ( KERN_ERR " %s: set_irq_chip failed, errno=%d \n " ,
GRU_DRIVER_ID_STR , - ret ) ;
return ret ;
}
ret = request_irq ( irq , irq_handler , 0 , irq_name , NULL ) ;
if ( ret ) {
printk ( KERN_ERR " %s: request_irq failed, errno=%d \n " ,
GRU_DRIVER_ID_STR , - ret ) ;
return ret ;
}
}
gru_irq_count [ chiplet ] + + ;
return 0 ;
}
static void gru_chiplet_teardown_tlb_irq ( int chiplet , int cpu , int blade )
{
unsigned long mmr ;
int core , irq = IRQ_GRU + chiplet ;
if ( gru_irq_count [ chiplet ] = = 0 )
return ;
mmr = gru_chiplet_cpu_to_mmr ( chiplet , cpu , & core ) ;
if ( mmr = = 0 )
return ;
if ( - - gru_irq_count [ chiplet ] = = 0 )
free_irq ( irq , NULL ) ;
}
# elif defined CONFIG_X86_64
static int gru_chiplet_setup_tlb_irq ( int chiplet , char * irq_name ,
irq_handler_t irq_handler , int cpu , int blade )
{
unsigned long mmr ;
int irq , core ;
int ret ;
mmr = gru_chiplet_cpu_to_mmr ( chiplet , cpu , & core ) ;
if ( mmr = = 0 )
return 0 ;
irq = uv_setup_irq ( irq_name , cpu , blade , mmr , UV_AFFINITY_CPU ) ;
if ( irq < 0 ) {
printk ( KERN_ERR " %s: uv_setup_irq failed, errno=%d \n " ,
GRU_DRIVER_ID_STR , - irq ) ;
return irq ;
}
ret = request_irq ( irq , irq_handler , 0 , irq_name , NULL ) ;
if ( ret ) {
uv_teardown_irq ( irq ) ;
printk ( KERN_ERR " %s: request_irq failed, errno=%d \n " ,
GRU_DRIVER_ID_STR , - ret ) ;
return ret ;
}
gru_base [ blade ] - > bs_grus [ chiplet ] . gs_irq [ core ] = irq ;
return 0 ;
}
static void gru_chiplet_teardown_tlb_irq ( int chiplet , int cpu , int blade )
2008-07-29 22:33:56 -07:00
{
2009-12-15 16:48:11 -08:00
int irq , core ;
unsigned long mmr ;
mmr = gru_chiplet_cpu_to_mmr ( chiplet , cpu , & core ) ;
if ( mmr ) {
irq = gru_base [ blade ] - > bs_grus [ chiplet ] . gs_irq [ core ] ;
if ( irq ) {
free_irq ( irq , NULL ) ;
uv_teardown_irq ( irq ) ;
}
}
2008-07-29 22:33:56 -07:00
}
2009-12-15 16:48:11 -08:00
2008-07-29 22:33:56 -07:00
# endif
2009-12-15 16:48:11 -08:00
static void gru_teardown_tlb_irqs ( void )
{
int blade ;
int cpu ;
for_each_online_cpu ( cpu ) {
blade = uv_cpu_to_blade_id ( cpu ) ;
gru_chiplet_teardown_tlb_irq ( 0 , cpu , blade ) ;
gru_chiplet_teardown_tlb_irq ( 1 , cpu , blade ) ;
}
for_each_possible_blade ( blade ) {
if ( uv_blade_nr_possible_cpus ( blade ) )
continue ;
gru_chiplet_teardown_tlb_irq ( 0 , 0 , blade ) ;
gru_chiplet_teardown_tlb_irq ( 1 , 0 , blade ) ;
}
}
static int gru_setup_tlb_irqs ( void )
{
int blade ;
int cpu ;
int ret ;
for_each_online_cpu ( cpu ) {
blade = uv_cpu_to_blade_id ( cpu ) ;
ret = gru_chiplet_setup_tlb_irq ( 0 , " GRU0_TLB " , gru0_intr , cpu , blade ) ;
if ( ret ! = 0 )
goto exit1 ;
ret = gru_chiplet_setup_tlb_irq ( 1 , " GRU1_TLB " , gru1_intr , cpu , blade ) ;
if ( ret ! = 0 )
goto exit1 ;
}
for_each_possible_blade ( blade ) {
if ( uv_blade_nr_possible_cpus ( blade ) )
continue ;
ret = gru_chiplet_setup_tlb_irq ( 0 , " GRU0_TLB " , gru_intr_mblade , 0 , blade ) ;
if ( ret ! = 0 )
goto exit1 ;
ret = gru_chiplet_setup_tlb_irq ( 1 , " GRU1_TLB " , gru_intr_mblade , 0 , blade ) ;
if ( ret ! = 0 )
goto exit1 ;
}
return 0 ;
exit1 :
gru_teardown_tlb_irqs ( ) ;
return ret ;
}
2008-07-29 22:33:56 -07:00
/*
* gru_init
*
* Called at boot or module load time to initialize the GRUs .
*/
static int __init gru_init ( void )
{
2009-12-15 16:48:11 -08:00
int ret ;
2008-07-29 22:33:56 -07:00
2009-02-09 10:25:20 -06:00
if ( ! is_uv_system ( ) )
2009-04-21 12:24:53 -07:00
return 0 ;
2008-07-29 22:33:56 -07:00
# if defined CONFIG_IA64
gru_start_paddr = 0xd000000000UL ; /* ZZZZZZZZZZZZZZZZZZZ fixme */
# else
gru_start_paddr = uv_read_local_mmr ( UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR ) &
0x7fffffffffffUL ;
# endif
gru_start_vaddr = __va ( gru_start_paddr ) ;
2009-04-02 16:59:04 -07:00
gru_end_paddr = gru_start_paddr + GRU_MAX_BLADES * GRU_SIZE ;
2008-07-29 22:33:56 -07:00
printk ( KERN_INFO " GRU space: 0x%lx - 0x%lx \n " ,
gru_start_paddr , gru_end_paddr ) ;
ret = misc_register ( & gru_miscdev ) ;
if ( ret ) {
printk ( KERN_ERR " %s: misc_register failed \n " ,
GRU_DRIVER_ID_STR ) ;
2009-12-15 16:48:11 -08:00
goto exit0 ;
2008-07-29 22:33:56 -07:00
}
ret = gru_proc_init ( ) ;
if ( ret ) {
printk ( KERN_ERR " %s: proc init failed \n " , GRU_DRIVER_ID_STR ) ;
2009-12-15 16:48:11 -08:00
goto exit1 ;
2008-07-29 22:33:56 -07:00
}
ret = gru_init_tables ( gru_start_paddr , gru_start_vaddr ) ;
if ( ret ) {
printk ( KERN_ERR " %s: init tables failed \n " , GRU_DRIVER_ID_STR ) ;
2009-12-15 16:48:11 -08:00
goto exit2 ;
2008-07-29 22:33:56 -07:00
}
2009-12-15 16:48:11 -08:00
ret = gru_setup_tlb_irqs ( ) ;
if ( ret ! = 0 )
goto exit3 ;
2009-06-17 16:28:28 -07:00
gru_kservices_init ( ) ;
2008-07-29 22:33:56 -07:00
printk ( KERN_INFO " %s: v%s \n " , GRU_DRIVER_ID_STR ,
GRU_DRIVER_VERSION_STR ) ;
return 0 ;
exit3 :
2009-12-15 16:48:11 -08:00
gru_free_tables ( ) ;
2008-07-29 22:33:56 -07:00
exit2 :
2009-12-15 16:48:11 -08:00
gru_proc_exit ( ) ;
2008-07-29 22:33:56 -07:00
exit1 :
2009-12-15 16:48:11 -08:00
misc_deregister ( & gru_miscdev ) ;
exit0 :
2008-07-29 22:33:56 -07:00
return ret ;
}
static void __exit gru_exit ( void )
{
2009-02-09 10:25:20 -06:00
if ( ! is_uv_system ( ) )
2008-09-13 02:33:22 -07:00
return ;
2009-12-15 16:48:11 -08:00
gru_teardown_tlb_irqs ( ) ;
2009-06-17 16:28:28 -07:00
gru_kservices_exit ( ) ;
2009-12-15 16:48:11 -08:00
gru_free_tables ( ) ;
2008-07-29 22:33:56 -07:00
misc_deregister ( & gru_miscdev ) ;
gru_proc_exit ( ) ;
}
2009-10-01 15:43:56 -07:00
static const struct file_operations gru_fops = {
2008-07-29 22:33:56 -07:00
. owner = THIS_MODULE ,
. unlocked_ioctl = gru_file_unlocked_ioctl ,
. mmap = gru_file_mmap ,
} ;
static struct miscdevice gru_miscdev = {
. minor = MISC_DYNAMIC_MINOR ,
. name = " gru " ,
. fops = & gru_fops ,
} ;
2009-09-27 22:29:37 +04:00
const struct vm_operations_struct gru_vm_ops = {
2008-07-29 22:33:56 -07:00
. close = gru_vma_close ,
. fault = gru_fault ,
} ;
2009-04-02 16:59:04 -07:00
# ifndef MODULE
2008-12-02 08:06:01 -06:00
fs_initcall ( gru_init ) ;
2009-04-02 16:59:04 -07:00
# else
module_init ( gru_init ) ;
# endif
2008-07-29 22:33:56 -07:00
module_exit ( gru_exit ) ;
2008-07-29 22:34:02 -07:00
module_param ( gru_options , ulong , 0644 ) ;
MODULE_PARM_DESC ( gru_options , " Various debug options " ) ;
2008-07-29 22:33:56 -07:00
MODULE_AUTHOR ( " Silicon Graphics, Inc. " ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_DESCRIPTION ( GRU_DRIVER_ID_STR GRU_DRIVER_VERSION_STR ) ;
MODULE_VERSION ( GRU_DRIVER_VERSION_STR ) ;