2005-04-17 02:20:36 +04:00
# include <linux/module.h>
# include <linux/pci.h>
# include <linux/init.h>
# include <linux/agp_backend.h>
# include <linux/mm.h>
# include <linux/slab.h>
# include <asm/machvec.h>
# include <asm/agp_backend.h>
# include "../../../arch/alpha/kernel/pci_impl.h"
# include "agp.h"
2008-02-05 09:30:04 +03:00
static int alpha_core_agp_vm_fault ( struct vm_area_struct * vma ,
struct vm_fault * vmf )
2005-04-17 02:20:36 +04:00
{
alpha_agp_info * agp = agp_bridge - > dev_private_data ;
dma_addr_t dma_addr ;
unsigned long pa ;
struct page * page ;
2008-02-05 09:30:04 +03:00
dma_addr = ( unsigned long ) vmf - > virtual_address - vma - > vm_start
+ agp - > aperture . bus_base ;
2005-04-17 02:20:36 +04:00
pa = agp - > ops - > translate ( agp , dma_addr ) ;
2006-02-28 08:54:25 +03:00
if ( pa = = ( unsigned long ) - EINVAL )
2008-02-05 09:30:04 +03:00
return VM_FAULT_SIGBUS ; /* no translation */
2006-02-28 08:54:25 +03:00
2005-04-17 02:20:36 +04:00
/*
* Get the page , inc the use count , and return it
*/
page = virt_to_page ( __va ( pa ) ) ;
get_page ( page ) ;
2008-02-05 09:30:04 +03:00
vmf - > page = page ;
return 0 ;
2005-04-17 02:20:36 +04:00
}
static struct aper_size_info_fixed alpha_core_agp_sizes [ ] =
{
{ 0 , 0 , 0 } , /* filled in by alpha_core_agp_setup */
} ;
2009-09-27 22:29:37 +04:00
static const struct vm_operations_struct alpha_core_agp_vm_ops = {
2008-02-05 09:30:04 +03:00
. fault = alpha_core_agp_vm_fault ,
2005-04-17 02:20:36 +04:00
} ;
static int alpha_core_agp_fetch_size ( void )
{
return alpha_core_agp_sizes [ 0 ] . size ;
}
static int alpha_core_agp_configure ( void )
{
alpha_agp_info * agp = agp_bridge - > dev_private_data ;
agp_bridge - > gart_bus_addr = agp - > aperture . bus_base ;
return 0 ;
}
static void alpha_core_agp_cleanup ( void )
{
alpha_agp_info * agp = agp_bridge - > dev_private_data ;
agp - > ops - > cleanup ( agp ) ;
}
static void alpha_core_agp_tlbflush ( struct agp_memory * mem )
{
alpha_agp_info * agp = agp_bridge - > dev_private_data ;
alpha_mv . mv_pci_tbi ( agp - > hose , 0 , - 1 ) ;
}
static void alpha_core_agp_enable ( struct agp_bridge_data * bridge , u32 mode )
{
alpha_agp_info * agp = bridge - > dev_private_data ;
agp - > mode . lw = agp_collect_device_status ( bridge , mode ,
agp - > capability . lw ) ;
agp - > mode . bits . enable = 1 ;
agp - > ops - > configure ( agp ) ;
2008-03-27 00:10:02 +03:00
agp_device_command ( agp - > mode . lw , false ) ;
2005-04-17 02:20:36 +04:00
}
2006-02-28 08:54:25 +03:00
static int alpha_core_agp_insert_memory ( struct agp_memory * mem , off_t pg_start ,
2005-04-17 02:20:36 +04:00
int type )
{
alpha_agp_info * agp = agp_bridge - > dev_private_data ;
int num_entries , status ;
void * temp ;
2007-01-23 12:33:43 +03:00
if ( type > = AGP_USER_TYPES | | mem - > type > = AGP_USER_TYPES )
return - EINVAL ;
2005-04-17 02:20:36 +04:00
temp = agp_bridge - > current_size ;
num_entries = A_SIZE_FIX ( temp ) - > num_entries ;
2006-02-28 08:54:25 +03:00
if ( ( pg_start + mem - > page_count ) > num_entries )
return - EINVAL ;
2005-04-17 02:20:36 +04:00
status = agp - > ops - > bind ( agp , pg_start , mem ) ;
mb ( ) ;
alpha_core_agp_tlbflush ( mem ) ;
return status ;
}
2006-02-28 08:54:25 +03:00
static int alpha_core_agp_remove_memory ( struct agp_memory * mem , off_t pg_start ,
2005-04-17 02:20:36 +04:00
int type )
{
alpha_agp_info * agp = agp_bridge - > dev_private_data ;
int status ;
status = agp - > ops - > unbind ( agp , pg_start , mem ) ;
alpha_core_agp_tlbflush ( mem ) ;
return status ;
}
2006-06-02 07:19:36 +04:00
static int alpha_core_agp_create_free_gatt_table ( struct agp_bridge_data * a )
{
return 0 ;
}
2005-04-17 02:20:36 +04:00
struct agp_bridge_driver alpha_core_agp_driver = {
. owner = THIS_MODULE ,
. aperture_sizes = alpha_core_agp_sizes ,
. num_aperture_sizes = 1 ,
. size_type = FIXED_APER_SIZE ,
2008-03-27 00:10:02 +03:00
. cant_use_aperture = true ,
2005-04-17 02:20:36 +04:00
. masks = NULL ,
2006-02-28 08:54:25 +03:00
2005-04-17 02:20:36 +04:00
. fetch_size = alpha_core_agp_fetch_size ,
. configure = alpha_core_agp_configure ,
. agp_enable = alpha_core_agp_enable ,
. cleanup = alpha_core_agp_cleanup ,
. tlb_flush = alpha_core_agp_tlbflush ,
. mask_memory = agp_generic_mask_memory ,
. cache_flush = global_cache_flush ,
2006-06-02 07:19:36 +04:00
. create_gatt_table = alpha_core_agp_create_free_gatt_table ,
. free_gatt_table = alpha_core_agp_create_free_gatt_table ,
2005-04-17 02:20:36 +04:00
. insert_memory = alpha_core_agp_insert_memory ,
. remove_memory = alpha_core_agp_remove_memory ,
. alloc_by_type = agp_generic_alloc_by_type ,
. free_by_type = agp_generic_free_by_type ,
. agp_alloc_page = agp_generic_alloc_page ,
2008-08-21 21:15:46 +04:00
. agp_alloc_pages = agp_generic_alloc_pages ,
2005-04-17 02:20:36 +04:00
. agp_destroy_page = agp_generic_destroy_page ,
2008-08-21 21:15:46 +04:00
. agp_destroy_pages = agp_generic_destroy_pages ,
2007-01-23 12:33:43 +03:00
. agp_type_to_mask_type = agp_generic_type_to_mask_type ,
2005-04-17 02:20:36 +04:00
} ;
struct agp_bridge_data * alpha_bridge ;
int __init
alpha_core_agp_setup ( void )
{
alpha_agp_info * agp = alpha_mv . agp_info ( ) ;
struct pci_dev * pdev ; /* faked */
struct aper_size_info_fixed * aper_size ;
if ( ! agp )
return - ENODEV ;
if ( agp - > ops - > setup ( agp ) )
return - ENODEV ;
/*
* Build the aperture size descriptor
*/
aper_size = alpha_core_agp_sizes ;
aper_size - > size = agp - > aperture . size / ( 1024 * 1024 ) ;
aper_size - > num_entries = agp - > aperture . size / PAGE_SIZE ;
aper_size - > page_order = __ffs ( aper_size - > num_entries / 1024 ) ;
/*
* Build a fake pci_dev struct
*/
2007-04-05 11:19:09 +04:00
pdev = alloc_pci_dev ( ) ;
2005-04-17 02:20:36 +04:00
if ( ! pdev )
return - ENOMEM ;
pdev - > vendor = 0xffff ;
pdev - > device = 0xffff ;
pdev - > sysdata = agp - > hose ;
alpha_bridge = agp_alloc_bridge ( ) ;
if ( ! alpha_bridge )
goto fail ;
alpha_bridge - > driver = & alpha_core_agp_driver ;
alpha_bridge - > vm_ops = & alpha_core_agp_vm_ops ;
alpha_bridge - > current_size = aper_size ; /* only 1 size */
alpha_bridge - > dev_private_data = agp ;
alpha_bridge - > dev = pdev ;
alpha_bridge - > mode = agp - > capability . lw ;
printk ( KERN_INFO PFX " Detected AGP on hose %d \n " , agp - > hose - > index ) ;
return agp_add_bridge ( alpha_bridge ) ;
fail :
kfree ( pdev ) ;
return - ENOMEM ;
}
static int __init agp_alpha_core_init ( void )
{
if ( agp_off )
return - EINVAL ;
if ( alpha_mv . agp_info )
return alpha_core_agp_setup ( ) ;
return - ENODEV ;
}
static void __exit agp_alpha_core_cleanup ( void )
{
agp_remove_bridge ( alpha_bridge ) ;
agp_put_bridge ( alpha_bridge ) ;
}
module_init ( agp_alpha_core_init ) ;
module_exit ( agp_alpha_core_cleanup ) ;
MODULE_AUTHOR ( " Jeff Wiedemeier <Jeff.Wiedemeier@hp.com> " ) ;
MODULE_LICENSE ( " GPL and additional rights " ) ;