2005-04-17 02:20:36 +04:00
/*
* Copyright 2001 - 2003 SuSE Labs .
* Distributed under the GNU public license , v2 .
*
* This is a GART driver for the AMD Opteron / Athlon64 on - CPU northbridge .
* It also includes support for the AMD 8151 AGP bridge ,
* although it doesn ' t actually do much , as all the real
* work is done in the northbridge ( s ) .
*/
# include <linux/module.h>
# include <linux/pci.h>
# include <linux/init.h>
# include <linux/agp_backend.h>
2005-11-07 11:59:43 +03:00
# include <linux/mmzone.h>
2005-10-31 02:03:48 +03:00
# include <asm/page.h> /* PAGE_SIZE */
2006-06-26 15:56:40 +04:00
# include <asm/k8.h>
2005-04-17 02:20:36 +04:00
# include "agp.h"
/* PTE bits. */
# define GPTE_VALID 1
# define GPTE_COHERENT 2
/* Aperture control register bits. */
# define GARTEN (1<<0)
# define DISGARTCPU (1<<4)
# define DISGARTIO (1<<5)
/* GART cache control register bits. */
# define INVGART (1<<0)
# define GARTPTEERR (1<<1)
/* K8 On-cpu GART registers */
# define AMD64_GARTAPERTURECTL 0x90
# define AMD64_GARTAPERTUREBASE 0x94
# define AMD64_GARTTABLEBASE 0x98
# define AMD64_GARTCACHECTL 0x9c
# define AMD64_GARTEN (1<<0)
/* NVIDIA K8 registers */
# define NVIDIA_X86_64_0_APBASE 0x10
# define NVIDIA_X86_64_1_APBASE1 0x50
# define NVIDIA_X86_64_1_APLIMIT1 0x54
# define NVIDIA_X86_64_1_APSIZE 0xa8
# define NVIDIA_X86_64_1_APBASE2 0xd8
# define NVIDIA_X86_64_1_APLIMIT2 0xdc
/* ULi K8 registers */
# define ULI_X86_64_BASE_ADDR 0x10
# define ULI_X86_64_HTT_FEA_REG 0x50
# define ULI_X86_64_ENU_SCR_REG 0x54
static struct resource * aperture_resource ;
2005-11-05 19:25:54 +03:00
static int __initdata agp_try_unsupported = 1 ;
2005-04-17 02:20:36 +04:00
static void amd64_tlbflush ( struct agp_memory * temp )
{
2006-06-26 15:56:40 +04:00
k8_flush_garts ( ) ;
2005-04-17 02:20:36 +04:00
}
static int amd64_insert_memory ( struct agp_memory * mem , off_t pg_start , int type )
{
int i , j , num_entries ;
long long tmp ;
2007-01-23 12:33:43 +03:00
int mask_type ;
struct agp_bridge_data * bridge = mem - > bridge ;
2005-04-17 02:20:36 +04:00
u32 pte ;
num_entries = agp_num_entries ( ) ;
2007-01-23 12:33:43 +03:00
if ( type ! = mem - > type )
2005-04-17 02:20:36 +04:00
return - EINVAL ;
2007-01-23 12:33:43 +03:00
mask_type = bridge - > driver - > agp_type_to_mask_type ( bridge , type ) ;
if ( mask_type ! = 0 )
return - EINVAL ;
2005-04-17 02:20:36 +04:00
/* Make sure we can fit the range in the gatt table. */
/* FIXME: could wrap */
if ( ( ( unsigned long ) pg_start + mem - > page_count ) > num_entries )
return - EINVAL ;
j = pg_start ;
/* gatt table should be empty. */
while ( j < ( pg_start + mem - > page_count ) ) {
if ( ! PGE_EMPTY ( agp_bridge , readl ( agp_bridge - > gatt_table + j ) ) )
return - EBUSY ;
j + + ;
}
if ( mem - > is_flushed = = FALSE ) {
global_cache_flush ( ) ;
mem - > is_flushed = TRUE ;
}
for ( i = 0 , j = pg_start ; i < mem - > page_count ; i + + , j + + ) {
tmp = agp_bridge - > driver - > mask_memory ( agp_bridge ,
2007-01-23 12:33:43 +03:00
mem - > memory [ i ] , mask_type ) ;
2005-04-17 02:20:36 +04:00
BUG_ON ( tmp & 0xffffff0000000ffcULL ) ;
pte = ( tmp & 0x000000ff00000000ULL ) > > 28 ;
pte | = ( tmp & 0x00000000fffff000ULL ) ;
pte | = GPTE_VALID | GPTE_COHERENT ;
writel ( pte , agp_bridge - > gatt_table + j ) ;
readl ( agp_bridge - > gatt_table + j ) ; /* PCI Posting. */
}
amd64_tlbflush ( mem ) ;
return 0 ;
}
/*
* This hack alters the order element according
* to the size of a long . It sucks . I totally disown this , even
* though it does appear to work for the most part .
*/
static struct aper_size_info_32 amd64_aperture_sizes [ 7 ] =
{
{ 32 , 8192 , 3 + ( sizeof ( long ) / 8 ) , 0 } ,
{ 64 , 16384 , 4 + ( sizeof ( long ) / 8 ) , 1 < < 1 } ,
{ 128 , 32768 , 5 + ( sizeof ( long ) / 8 ) , 1 < < 2 } ,
{ 256 , 65536 , 6 + ( sizeof ( long ) / 8 ) , 1 < < 1 | 1 < < 2 } ,
{ 512 , 131072 , 7 + ( sizeof ( long ) / 8 ) , 1 < < 3 } ,
{ 1024 , 262144 , 8 + ( sizeof ( long ) / 8 ) , 1 < < 1 | 1 < < 3 } ,
{ 2048 , 524288 , 9 + ( sizeof ( long ) / 8 ) , 1 < < 2 | 1 < < 3 }
} ;
/*
* Get the current Aperture size from the x86 - 64.
* Note , that there may be multiple x86 - 64 ' s , but we just return
* the value from the first one we find . The set_size functions
* keep the rest coherent anyway . Or at least should do .
*/
static int amd64_fetch_size ( void )
{
struct pci_dev * dev ;
int i ;
u32 temp ;
struct aper_size_info_32 * values ;
2006-06-26 15:56:40 +04:00
dev = k8_northbridges [ 0 ] ;
2005-04-17 02:20:36 +04:00
if ( dev = = NULL )
return 0 ;
pci_read_config_dword ( dev , AMD64_GARTAPERTURECTL , & temp ) ;
temp = ( temp & 0xe ) ;
values = A_SIZE_32 ( amd64_aperture_sizes ) ;
for ( i = 0 ; i < agp_bridge - > driver - > num_aperture_sizes ; i + + ) {
if ( temp = = values [ i ] . size_value ) {
agp_bridge - > previous_size =
agp_bridge - > current_size = ( void * ) ( values + i ) ;
agp_bridge - > aperture_size_idx = i ;
return values [ i ] . size ;
}
}
return 0 ;
}
/*
* In a multiprocessor x86 - 64 system , this function gets
* called once for each CPU .
*/
static u64 amd64_configure ( struct pci_dev * hammer , u64 gatt_table )
{
u64 aperturebase ;
u32 tmp ;
u64 addr , aper_base ;
/* Address to map to */
pci_read_config_dword ( hammer , AMD64_GARTAPERTUREBASE , & tmp ) ;
aperturebase = tmp < < 25 ;
aper_base = ( aperturebase & PCI_BASE_ADDRESS_MEM_MASK ) ;
/* address of the mappings table */
addr = ( u64 ) gatt_table ;
addr > > = 12 ;
tmp = ( u32 ) addr < < 4 ;
tmp & = ~ 0xf ;
pci_write_config_dword ( hammer , AMD64_GARTTABLEBASE , tmp ) ;
/* Enable GART translation for this hammer. */
pci_read_config_dword ( hammer , AMD64_GARTAPERTURECTL , & tmp ) ;
tmp | = GARTEN ;
tmp & = ~ ( DISGARTCPU | DISGARTIO ) ;
pci_write_config_dword ( hammer , AMD64_GARTAPERTURECTL , tmp ) ;
return aper_base ;
}
2007-02-23 02:41:28 +03:00
static const struct aper_size_info_32 amd_8151_sizes [ 7 ] =
2005-04-17 02:20:36 +04:00
{
{ 2048 , 524288 , 9 , 0x00000000 } , /* 0 0 0 0 0 0 */
{ 1024 , 262144 , 8 , 0x00000400 } , /* 1 0 0 0 0 0 */
{ 512 , 131072 , 7 , 0x00000600 } , /* 1 1 0 0 0 0 */
{ 256 , 65536 , 6 , 0x00000700 } , /* 1 1 1 0 0 0 */
{ 128 , 32768 , 5 , 0x00000720 } , /* 1 1 1 1 0 0 */
{ 64 , 16384 , 4 , 0x00000730 } , /* 1 1 1 1 1 0 */
2006-02-28 08:54:25 +03:00
{ 32 , 8192 , 3 , 0x00000738 } /* 1 1 1 1 1 1 */
2005-04-17 02:20:36 +04:00
} ;
static int amd_8151_configure ( void )
{
2005-03-31 01:17:04 +04:00
unsigned long gatt_bus = virt_to_gart ( agp_bridge - > gatt_table_real ) ;
2006-06-26 15:56:40 +04:00
int i ;
2005-04-17 02:20:36 +04:00
/* Configure AGP regs in each x86-64 host bridge. */
2006-06-26 15:56:40 +04:00
for ( i = 0 ; i < num_k8_northbridges ; i + + ) {
2005-04-17 02:20:36 +04:00
agp_bridge - > gart_bus_addr =
2006-06-26 15:56:40 +04:00
amd64_configure ( k8_northbridges [ i ] , gatt_bus ) ;
2005-04-17 02:20:36 +04:00
}
2006-06-26 15:56:40 +04:00
k8_flush_garts ( ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
static void amd64_cleanup ( void )
{
u32 tmp ;
2006-06-26 15:56:40 +04:00
int i ;
for ( i = 0 ; i < num_k8_northbridges ; i + + ) {
struct pci_dev * dev = k8_northbridges [ i ] ;
2005-04-17 02:20:36 +04:00
/* disable gart translation */
2006-06-26 15:56:40 +04:00
pci_read_config_dword ( dev , AMD64_GARTAPERTURECTL , & tmp ) ;
2005-04-17 02:20:36 +04:00
tmp & = ~ AMD64_GARTEN ;
2006-06-26 15:56:40 +04:00
pci_write_config_dword ( dev , AMD64_GARTAPERTURECTL , tmp ) ;
2005-04-17 02:20:36 +04:00
}
}
2007-02-23 02:41:28 +03:00
static const struct agp_bridge_driver amd_8151_driver = {
2005-04-17 02:20:36 +04:00
. owner = THIS_MODULE ,
. aperture_sizes = amd_8151_sizes ,
. size_type = U32_APER_SIZE ,
. num_aperture_sizes = 7 ,
. configure = amd_8151_configure ,
. fetch_size = amd64_fetch_size ,
. cleanup = amd64_cleanup ,
. tlb_flush = amd64_tlbflush ,
. mask_memory = agp_generic_mask_memory ,
. masks = NULL ,
. agp_enable = agp_generic_enable ,
. cache_flush = global_cache_flush ,
. create_gatt_table = agp_generic_create_gatt_table ,
. free_gatt_table = agp_generic_free_gatt_table ,
. insert_memory = amd64_insert_memory ,
. remove_memory = agp_generic_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 ,
. agp_destroy_page = agp_generic_destroy_page ,
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
} ;
/* Some basic sanity checks for the aperture. */
static int __devinit aperture_valid ( u64 aper , u32 size )
{
u32 pfn , c ;
if ( aper = = 0 ) {
printk ( KERN_ERR PFX " No aperture \n " ) ;
return 0 ;
}
if ( size < 32 * 1024 * 1024 ) {
printk ( KERN_ERR PFX " Aperture too small (%d MB) \n " , size > > 20 ) ;
return 0 ;
}
if ( aper + size > 0xffffffff ) {
printk ( KERN_ERR PFX " Aperture out of bounds \n " ) ;
return 0 ;
}
pfn = aper > > PAGE_SHIFT ;
for ( c = 0 ; c < size / PAGE_SIZE ; c + + ) {
if ( ! pfn_valid ( pfn + c ) )
break ;
if ( ! PageReserved ( pfn_to_page ( pfn + c ) ) ) {
printk ( KERN_ERR PFX " Aperture pointing to RAM \n " ) ;
return 0 ;
}
}
/* Request the Aperture. This catches cases when someone else
already put a mapping in there - happens with some very broken BIOS
Maybe better to use pci_assign_resource / pci_enable_device instead
trusting the bridges ? */
if ( ! aperture_resource & &
! ( aperture_resource = request_mem_region ( aper , size , " aperture " ) ) ) {
printk ( KERN_ERR PFX " Aperture conflicts with PCI mapping. \n " ) ;
return 0 ;
}
return 1 ;
}
/*
* W * s centric BIOS sometimes only set up the aperture in the AGP
* bridge , not the northbridge . On AMD64 this is handled early
2006-06-26 15:57:22 +04:00
* in aperture . c , but when IOMMU is not enabled or we run
2005-04-17 02:20:36 +04:00
* on a 32 bit kernel this needs to be redone .
* Unfortunately it is impossible to fix the aperture here because it ' s too late
* to allocate that much memory . But at least error out cleanly instead of
* crashing .
*/
static __devinit int fix_northbridge ( struct pci_dev * nb , struct pci_dev * agp ,
u16 cap )
{
u32 aper_low , aper_hi ;
u64 aper , nb_aper ;
int order = 0 ;
u32 nb_order , nb_base ;
u16 apsize ;
pci_read_config_dword ( nb , 0x90 , & nb_order ) ;
nb_order = ( nb_order > > 1 ) & 7 ;
pci_read_config_dword ( nb , 0x94 , & nb_base ) ;
nb_aper = nb_base < < 25 ;
if ( aperture_valid ( nb_aper , ( 32 * 1024 * 1024 ) < < nb_order ) ) {
return 0 ;
}
/* Northbridge seems to contain crap. Try the AGP bridge. */
pci_read_config_word ( agp , cap + 0x14 , & apsize ) ;
if ( apsize = = 0xffff )
return - 1 ;
apsize & = 0xfff ;
/* Some BIOS use weird encodings not in the AGPv3 table. */
if ( apsize & 0xff )
apsize | = 0xf00 ;
order = 7 - hweight16 ( apsize ) ;
pci_read_config_dword ( agp , 0x10 , & aper_low ) ;
pci_read_config_dword ( agp , 0x14 , & aper_hi ) ;
aper = ( aper_low & ~ ( ( 1 < < 22 ) - 1 ) ) | ( ( u64 ) aper_hi < < 32 ) ;
printk ( KERN_INFO PFX " Aperture from AGP @ %Lx size %u MB \n " , aper , 32 < < order ) ;
if ( order < 0 | | ! aperture_valid ( aper , ( 32 * 1024 * 1024 ) < < order ) )
return - 1 ;
pci_write_config_dword ( nb , 0x90 , order < < 1 ) ;
pci_write_config_dword ( nb , 0x94 , aper > > 25 ) ;
return 0 ;
}
static __devinit int cache_nbs ( struct pci_dev * pdev , u32 cap_ptr )
{
2006-06-26 15:56:40 +04:00
int i ;
if ( cache_k8_northbridges ( ) < 0 )
return - ENODEV ;
i = 0 ;
for ( i = 0 ; i < num_k8_northbridges ; i + + ) {
struct pci_dev * dev = k8_northbridges [ i ] ;
if ( fix_northbridge ( dev , pdev , cap_ptr ) < 0 ) {
2005-04-17 02:20:36 +04:00
printk ( KERN_ERR PFX " No usable aperture found. \n " ) ;
# ifdef __x86_64__
/* should port this to i386 */
printk ( KERN_ERR PFX " Consider rebooting with iommu=memaper=2 to get a good aperture. \n " ) ;
# endif
return - 1 ;
}
}
2006-06-26 15:56:40 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
/* Handle AMD 8151 quirks */
static void __devinit amd8151_init ( struct pci_dev * pdev , struct agp_bridge_data * bridge )
{
char * revstring ;
u8 rev_id ;
pci_read_config_byte ( pdev , PCI_REVISION_ID , & rev_id ) ;
switch ( rev_id ) {
case 0x01 : revstring = " A0 " ; break ;
case 0x02 : revstring = " A1 " ; break ;
case 0x11 : revstring = " B0 " ; break ;
case 0x12 : revstring = " B1 " ; break ;
case 0x13 : revstring = " B2 " ; break ;
case 0x14 : revstring = " B3 " ; break ;
default : revstring = " ?? " ; break ;
}
printk ( KERN_INFO PFX " Detected AMD 8151 AGP Bridge rev %s \n " , revstring ) ;
/*
* Work around errata .
* Chips before B2 stepping incorrectly reporting v3 .5
*/
if ( rev_id < 0x13 ) {
printk ( KERN_INFO PFX " Correcting AGP revision (reports 3.5, is really 3.0) \n " ) ;
bridge - > major_version = 3 ;
bridge - > minor_version = 0 ;
}
}
2005-11-17 03:07:02 +03:00
static const struct aper_size_info_32 uli_sizes [ 7 ] =
2005-04-17 02:20:36 +04:00
{
{ 256 , 65536 , 6 , 10 } ,
{ 128 , 32768 , 5 , 9 } ,
{ 64 , 16384 , 4 , 8 } ,
{ 32 , 8192 , 3 , 7 } ,
{ 16 , 4096 , 2 , 6 } ,
{ 8 , 2048 , 1 , 4 } ,
{ 4 , 1024 , 0 , 3 }
} ;
static int __devinit uli_agp_init ( struct pci_dev * pdev )
{
u32 httfea , baseaddr , enuscr ;
struct pci_dev * dev1 ;
int i ;
unsigned size = amd64_fetch_size ( ) ;
2005-09-01 21:50:13 +04:00
printk ( KERN_INFO " Setting up ULi AGP. \n " ) ;
2006-09-26 20:56:55 +04:00
dev1 = pci_get_slot ( pdev - > bus , PCI_DEVFN ( 0 , 0 ) ) ;
2005-04-17 02:20:36 +04:00
if ( dev1 = = NULL ) {
printk ( KERN_INFO PFX " Detected a ULi chipset, "
" but could not fine the secondary device. \n " ) ;
return - ENODEV ;
}
for ( i = 0 ; i < ARRAY_SIZE ( uli_sizes ) ; i + + )
if ( uli_sizes [ i ] . size = = size )
break ;
if ( i = = ARRAY_SIZE ( uli_sizes ) ) {
printk ( KERN_INFO PFX " No ULi size found for %d \n " , size ) ;
return - ENODEV ;
}
/* shadow x86-64 registers into ULi registers */
2006-06-26 15:56:40 +04:00
pci_read_config_dword ( k8_northbridges [ 0 ] , AMD64_GARTAPERTUREBASE , & httfea ) ;
2005-04-17 02:20:36 +04:00
/* if x86-64 aperture base is beyond 4G, exit here */
if ( ( httfea & 0x7fff ) > > ( 32 - 25 ) )
return - ENODEV ;
httfea = ( httfea & 0x7fff ) < < 25 ;
pci_read_config_dword ( pdev , ULI_X86_64_BASE_ADDR , & baseaddr ) ;
baseaddr & = ~ PCI_BASE_ADDRESS_MEM_MASK ;
baseaddr | = httfea ;
pci_write_config_dword ( pdev , ULI_X86_64_BASE_ADDR , baseaddr ) ;
enuscr = httfea + ( size * 1024 * 1024 ) - 1 ;
pci_write_config_dword ( dev1 , ULI_X86_64_HTT_FEA_REG , httfea ) ;
pci_write_config_dword ( dev1 , ULI_X86_64_ENU_SCR_REG , enuscr ) ;
2006-09-26 20:56:55 +04:00
pci_dev_put ( dev1 ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2005-11-17 03:07:02 +03:00
static const struct aper_size_info_32 nforce3_sizes [ 5 ] =
2005-04-17 02:20:36 +04:00
{
{ 512 , 131072 , 7 , 0x00000000 } ,
{ 256 , 65536 , 6 , 0x00000008 } ,
{ 128 , 32768 , 5 , 0x0000000C } ,
{ 64 , 16384 , 4 , 0x0000000E } ,
{ 32 , 8192 , 3 , 0x0000000F }
} ;
/* Handle shadow device of the Nvidia NForce3 */
/* CHECK-ME original 2.4 version set up some IORRs. Check if that is needed. */
2006-12-07 07:38:35 +03:00
static int nforce3_agp_init ( struct pci_dev * pdev )
2005-04-17 02:20:36 +04:00
{
u32 tmp , apbase , apbar , aplimit ;
struct pci_dev * dev1 ;
int i ;
unsigned size = amd64_fetch_size ( ) ;
printk ( KERN_INFO PFX " Setting up Nforce3 AGP. \n " ) ;
2006-09-26 20:56:55 +04:00
dev1 = pci_get_slot ( pdev - > bus , PCI_DEVFN ( 11 , 0 ) ) ;
2005-04-17 02:20:36 +04:00
if ( dev1 = = NULL ) {
printk ( KERN_INFO PFX " agpgart: Detected an NVIDIA "
" nForce3 chipset, but could not find "
" the secondary device. \n " ) ;
return - ENODEV ;
}
for ( i = 0 ; i < ARRAY_SIZE ( nforce3_sizes ) ; i + + )
if ( nforce3_sizes [ i ] . size = = size )
break ;
if ( i = = ARRAY_SIZE ( nforce3_sizes ) ) {
printk ( KERN_INFO PFX " No NForce3 size found for %d \n " , size ) ;
return - ENODEV ;
}
pci_read_config_dword ( dev1 , NVIDIA_X86_64_1_APSIZE , & tmp ) ;
tmp & = ~ ( 0xf ) ;
tmp | = nforce3_sizes [ i ] . size_value ;
pci_write_config_dword ( dev1 , NVIDIA_X86_64_1_APSIZE , tmp ) ;
/* shadow x86-64 registers into NVIDIA registers */
2006-06-26 15:56:40 +04:00
pci_read_config_dword ( k8_northbridges [ 0 ] , AMD64_GARTAPERTUREBASE , & apbase ) ;
2005-04-17 02:20:36 +04:00
/* if x86-64 aperture base is beyond 4G, exit here */
2006-02-21 02:34:37 +03:00
if ( ( apbase & 0x7fff ) > > ( 32 - 25 ) ) {
printk ( KERN_INFO PFX " aperture base > 4G \n " ) ;
return - ENODEV ;
}
2005-04-17 02:20:36 +04:00
apbase = ( apbase & 0x7fff ) < < 25 ;
pci_read_config_dword ( pdev , NVIDIA_X86_64_0_APBASE , & apbar ) ;
apbar & = ~ PCI_BASE_ADDRESS_MEM_MASK ;
apbar | = apbase ;
pci_write_config_dword ( pdev , NVIDIA_X86_64_0_APBASE , apbar ) ;
aplimit = apbase + ( size * 1024 * 1024 ) - 1 ;
pci_write_config_dword ( dev1 , NVIDIA_X86_64_1_APBASE1 , apbase ) ;
pci_write_config_dword ( dev1 , NVIDIA_X86_64_1_APLIMIT1 , aplimit ) ;
pci_write_config_dword ( dev1 , NVIDIA_X86_64_1_APBASE2 , apbase ) ;
pci_write_config_dword ( dev1 , NVIDIA_X86_64_1_APLIMIT2 , aplimit ) ;
2006-09-26 20:56:55 +04:00
pci_dev_put ( dev1 ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
static int __devinit agp_amd64_probe ( struct pci_dev * pdev ,
const struct pci_device_id * ent )
{
struct agp_bridge_data * bridge ;
u8 cap_ptr ;
cap_ptr = pci_find_capability ( pdev , PCI_CAP_ID_AGP ) ;
if ( ! cap_ptr )
return - ENODEV ;
/* Could check for AGPv3 here */
bridge = agp_alloc_bridge ( ) ;
if ( ! bridge )
return - ENOMEM ;
if ( pdev - > vendor = = PCI_VENDOR_ID_AMD & &
pdev - > device = = PCI_DEVICE_ID_AMD_8151_0 ) {
amd8151_init ( pdev , bridge ) ;
} else {
printk ( KERN_INFO PFX " Detected AGP bridge %x \n " , pdev - > devfn ) ;
}
bridge - > driver = & amd_8151_driver ;
bridge - > dev = pdev ;
bridge - > capndx = cap_ptr ;
/* Fill in the mode register */
pci_read_config_dword ( pdev , bridge - > capndx + PCI_AGP_STATUS , & bridge - > mode ) ;
if ( cache_nbs ( pdev , cap_ptr ) = = - 1 ) {
agp_put_bridge ( bridge ) ;
return - ENODEV ;
}
if ( pdev - > vendor = = PCI_VENDOR_ID_NVIDIA ) {
int ret = nforce3_agp_init ( pdev ) ;
if ( ret ) {
agp_put_bridge ( bridge ) ;
return ret ;
}
}
if ( pdev - > vendor = = PCI_VENDOR_ID_AL ) {
int ret = uli_agp_init ( pdev ) ;
if ( ret ) {
agp_put_bridge ( bridge ) ;
return ret ;
}
}
pci_set_drvdata ( pdev , bridge ) ;
return agp_add_bridge ( bridge ) ;
}
static void __devexit agp_amd64_remove ( struct pci_dev * pdev )
{
struct agp_bridge_data * bridge = pci_get_drvdata ( pdev ) ;
2005-03-31 01:17:04 +04:00
release_mem_region ( virt_to_gart ( bridge - > gatt_table_real ) ,
2005-04-17 02:20:36 +04:00
amd64_aperture_sizes [ bridge - > aperture_size_idx ] . size ) ;
agp_remove_bridge ( bridge ) ;
agp_put_bridge ( bridge ) ;
}
2006-01-04 10:00:10 +03:00
# ifdef CONFIG_PM
static int agp_amd64_suspend ( struct pci_dev * pdev , pm_message_t state )
{
pci_save_state ( pdev ) ;
pci_set_power_state ( pdev , pci_choose_state ( pdev , state ) ) ;
return 0 ;
}
static int agp_amd64_resume ( struct pci_dev * pdev )
{
pci_set_power_state ( pdev , PCI_D0 ) ;
pci_restore_state ( pdev ) ;
2006-05-22 01:11:42 +04:00
if ( pdev - > vendor = = PCI_VENDOR_ID_NVIDIA )
nforce3_agp_init ( pdev ) ;
2006-01-04 10:00:10 +03:00
return amd_8151_configure ( ) ;
}
# endif /* CONFIG_PM */
2005-04-17 02:20:36 +04:00
static struct pci_device_id agp_amd64_pci_table [ ] = {
{
. class = ( PCI_CLASS_BRIDGE_HOST < < 8 ) ,
. class_mask = ~ 0 ,
. vendor = PCI_VENDOR_ID_AMD ,
. device = PCI_DEVICE_ID_AMD_8151_0 ,
. subvendor = PCI_ANY_ID ,
. subdevice = PCI_ANY_ID ,
} ,
/* ULi M1689 */
{
. class = ( PCI_CLASS_BRIDGE_HOST < < 8 ) ,
. class_mask = ~ 0 ,
. vendor = PCI_VENDOR_ID_AL ,
. device = PCI_DEVICE_ID_AL_M1689 ,
. subvendor = PCI_ANY_ID ,
. subdevice = PCI_ANY_ID ,
} ,
/* VIA K8T800Pro */
{
. class = ( PCI_CLASS_BRIDGE_HOST < < 8 ) ,
. class_mask = ~ 0 ,
. vendor = PCI_VENDOR_ID_VIA ,
. device = PCI_DEVICE_ID_VIA_K8T800PRO_0 ,
. subvendor = PCI_ANY_ID ,
. subdevice = PCI_ANY_ID ,
} ,
/* VIA K8T800 */
{
. class = ( PCI_CLASS_BRIDGE_HOST < < 8 ) ,
. class_mask = ~ 0 ,
. vendor = PCI_VENDOR_ID_VIA ,
. device = PCI_DEVICE_ID_VIA_8385_0 ,
. subvendor = PCI_ANY_ID ,
. subdevice = PCI_ANY_ID ,
} ,
/* VIA K8M800 / K8N800 */
{
. class = ( PCI_CLASS_BRIDGE_HOST < < 8 ) ,
. class_mask = ~ 0 ,
. vendor = PCI_VENDOR_ID_VIA ,
. device = PCI_DEVICE_ID_VIA_8380_0 ,
. subvendor = PCI_ANY_ID ,
. subdevice = PCI_ANY_ID ,
} ,
2006-12-17 02:24:27 +03:00
/* VIA K8M890 / K8N890 */
{
. class = ( PCI_CLASS_BRIDGE_HOST < < 8 ) ,
. class_mask = ~ 0 ,
. vendor = PCI_VENDOR_ID_VIA ,
2007-01-29 01:58:33 +03:00
. device = PCI_DEVICE_ID_VIA_VT3336 ,
2006-12-17 02:24:27 +03:00
. subvendor = PCI_ANY_ID ,
. subdevice = PCI_ANY_ID ,
} ,
2005-04-17 02:20:36 +04:00
/* VIA K8T890 */
{
. class = ( PCI_CLASS_BRIDGE_HOST < < 8 ) ,
. class_mask = ~ 0 ,
. vendor = PCI_VENDOR_ID_VIA ,
. device = PCI_DEVICE_ID_VIA_3238_0 ,
. subvendor = PCI_ANY_ID ,
. subdevice = PCI_ANY_ID ,
} ,
/* VIA K8T800/K8M800/K8N800 */
{
. class = ( PCI_CLASS_BRIDGE_HOST < < 8 ) ,
. class_mask = ~ 0 ,
. vendor = PCI_VENDOR_ID_VIA ,
. device = PCI_DEVICE_ID_VIA_838X_1 ,
. subvendor = PCI_ANY_ID ,
. subdevice = PCI_ANY_ID ,
} ,
/* NForce3 */
{
. class = ( PCI_CLASS_BRIDGE_HOST < < 8 ) ,
. class_mask = ~ 0 ,
. vendor = PCI_VENDOR_ID_NVIDIA ,
. device = PCI_DEVICE_ID_NVIDIA_NFORCE3 ,
. subvendor = PCI_ANY_ID ,
. subdevice = PCI_ANY_ID ,
} ,
{
. class = ( PCI_CLASS_BRIDGE_HOST < < 8 ) ,
. class_mask = ~ 0 ,
. vendor = PCI_VENDOR_ID_NVIDIA ,
. device = PCI_DEVICE_ID_NVIDIA_NFORCE3S ,
. subvendor = PCI_ANY_ID ,
. subdevice = PCI_ANY_ID ,
} ,
/* SIS 755 */
{
. class = ( PCI_CLASS_BRIDGE_HOST < < 8 ) ,
. class_mask = ~ 0 ,
. vendor = PCI_VENDOR_ID_SI ,
. device = PCI_DEVICE_ID_SI_755 ,
. subvendor = PCI_ANY_ID ,
. subdevice = PCI_ANY_ID ,
} ,
2005-06-29 04:08:29 +04:00
/* SIS 760 */
{
. class = ( PCI_CLASS_BRIDGE_HOST < < 8 ) ,
. class_mask = ~ 0 ,
. vendor = PCI_VENDOR_ID_SI ,
. device = PCI_DEVICE_ID_SI_760 ,
. subvendor = PCI_ANY_ID ,
. subdevice = PCI_ANY_ID ,
} ,
2005-11-05 19:25:54 +03:00
/* ALI/ULI M1695 */
{
. class = ( PCI_CLASS_BRIDGE_HOST < < 8 ) ,
. class_mask = ~ 0 ,
. vendor = PCI_VENDOR_ID_AL ,
2006-03-23 23:29:19 +03:00
. device = 0x1695 ,
2005-11-05 19:25:54 +03:00
. subvendor = PCI_ANY_ID ,
. subdevice = PCI_ANY_ID ,
} ,
2005-04-17 02:20:36 +04:00
{ }
} ;
MODULE_DEVICE_TABLE ( pci , agp_amd64_pci_table ) ;
static struct pci_driver agp_amd64_pci_driver = {
. name = " agpgart-amd64 " ,
. id_table = agp_amd64_pci_table ,
. probe = agp_amd64_probe ,
. remove = agp_amd64_remove ,
2006-01-04 10:00:10 +03:00
# ifdef CONFIG_PM
. suspend = agp_amd64_suspend ,
. resume = agp_amd64_resume ,
# endif
2005-04-17 02:20:36 +04:00
} ;
/* Not static due to IOMMU code calling it early. */
int __init agp_amd64_init ( void )
{
int err = 0 ;
if ( agp_off )
return - EINVAL ;
2006-06-22 01:36:24 +04:00
if ( pci_register_driver ( & agp_amd64_pci_driver ) < 0 ) {
2005-04-17 02:20:36 +04:00
struct pci_dev * dev ;
if ( ! agp_try_unsupported & & ! agp_try_unsupported_boot ) {
printk ( KERN_INFO PFX " No supported AGP bridge found. \n " ) ;
# ifdef MODULE
printk ( KERN_INFO PFX " You can try agp_try_unsupported=1 \n " ) ;
# else
printk ( KERN_INFO PFX " You can boot with agp=try_unsupported \n " ) ;
# endif
return - ENODEV ;
}
/* First check that we have at least one AMD64 NB */
2006-06-26 15:56:40 +04:00
if ( ! pci_dev_present ( k8_nb_ids ) )
2005-04-17 02:20:36 +04:00
return - ENODEV ;
/* Look for any AGP bridge */
dev = NULL ;
err = - ENODEV ;
for_each_pci_dev ( dev ) {
if ( ! pci_find_capability ( dev , PCI_CAP_ID_AGP ) )
continue ;
/* Only one bridge supported right now */
if ( agp_amd64_probe ( dev , NULL ) = = 0 ) {
err = 0 ;
break ;
}
}
}
return err ;
}
static void __exit agp_amd64_cleanup ( void )
{
if ( aperture_resource )
release_resource ( aperture_resource ) ;
pci_unregister_driver ( & agp_amd64_pci_driver ) ;
}
/* On AMD64 the PCI driver needs to initialize this driver early
for the IOMMU , so it has to be called via a backdoor . */
2006-06-26 15:57:22 +04:00
# ifndef CONFIG_IOMMU
2005-04-17 02:20:36 +04:00
module_init ( agp_amd64_init ) ;
module_exit ( agp_amd64_cleanup ) ;
# endif
MODULE_AUTHOR ( " Dave Jones <davej@codemonkey.org.uk>, Andi Kleen " ) ;
module_param ( agp_try_unsupported , bool , 0 ) ;
MODULE_LICENSE ( " GPL " ) ;