2019-05-19 15:08:20 +03:00
// SPDX-License-Identifier: GPL-2.0-only
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 */
2017-01-27 12:27:10 +03:00
# include <asm/e820/api.h>
2010-09-17 20:03:43 +04:00
# include <asm/amd_nb.h>
2008-04-08 12:49:03 +04:00
# include <asm/gart.h>
2005-04-17 02:20:36 +04:00
# include "agp.h"
/* 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 ;
2012-01-13 03:02:20 +04:00
static bool __initdata agp_try_unsupported = 1 ;
2008-07-30 23:26:51 +04:00
static int agp_bridges_found ;
2005-04-17 02:20:36 +04:00
static void amd64_tlbflush ( struct agp_memory * temp )
{
2010-10-29 19:14:30 +04:00
amd_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 + + ;
}
2008-03-27 00:10:02 +03:00
if ( ! mem - > is_flushed ) {
2005-04-17 02:20:36 +04:00
global_cache_flush ( ) ;
2008-03-27 00:10:02 +03:00
mem - > is_flushed = true ;
2005-04-17 02:20:36 +04:00
}
for ( i = 0 , j = pg_start ; i < mem - > page_count ; i + + , j + + ) {
tmp = agp_bridge - > driver - > mask_memory ( agp_bridge ,
2009-07-29 13:25:58 +04:00
page_to_phys ( mem - > pages [ i ] ) ,
2009-07-27 13:27:29 +04:00
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 ;
2010-10-29 19:14:31 +04:00
dev = node_to_amd_nb ( 0 ) - > misc ;
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 .
*/
2008-04-08 12:49:03 +04:00
static u64 amd64_configure ( struct pci_dev * hammer , u64 gatt_table )
2005-04-17 02:20:36 +04:00
{
u64 aperturebase ;
u32 tmp ;
2008-04-15 14:43:57 +04:00
u64 aper_base ;
2005-04-17 02:20:36 +04:00
/* Address to map to */
2008-04-15 14:43:57 +04:00
pci_read_config_dword ( hammer , AMD64_GARTAPERTUREBASE , & tmp ) ;
2018-07-05 01:20:41 +03:00
aperturebase = ( u64 ) tmp < < 25 ;
2005-04-17 02:20:36 +04:00
aper_base = ( aperturebase & PCI_BASE_ADDRESS_MEM_MASK ) ;
2008-04-15 14:43:57 +04:00
enable_gart_translation ( hammer , gatt_table ) ;
2005-04-17 02:20:36 +04:00
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 )
{
2009-07-29 13:25:58 +04:00
unsigned long gatt_bus = virt_to_phys ( agp_bridge - > gatt_table_real ) ;
2006-06-26 15:56:40 +04:00
int i ;
2005-04-17 02:20:36 +04:00
2010-10-29 19:14:31 +04:00
if ( ! amd_nb_has_feature ( AMD_NB_GART ) )
2010-09-17 20:02:54 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
/* Configure AGP regs in each x86-64 host bridge. */
2010-10-29 19:14:31 +04:00
for ( i = 0 ; i < amd_nb_num ( ) ; i + + ) {
2005-04-17 02:20:36 +04:00
agp_bridge - > gart_bus_addr =
2010-10-29 19:14:31 +04:00
amd64_configure ( node_to_amd_nb ( i ) - > misc , gatt_bus ) ;
2005-04-17 02:20:36 +04:00
}
2010-10-29 19:14:30 +04:00
amd_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 ;
2010-09-17 20:02:54 +04:00
2010-10-29 19:14:31 +04:00
if ( ! amd_nb_has_feature ( AMD_NB_GART ) )
2010-09-17 20:02:54 +04:00
return ;
2010-10-29 19:14:31 +04:00
for ( i = 0 ; i < amd_nb_num ( ) ; i + + ) {
struct pci_dev * dev = node_to_amd_nb ( i ) - > misc ;
2005-04-17 02:20:36 +04:00
/* disable gart translation */
2008-04-15 14:43:57 +04:00
pci_read_config_dword ( dev , AMD64_GARTAPERTURECTL , & tmp ) ;
2010-09-03 20:39:39 +04:00
tmp & = ~ GARTEN ;
2008-04-15 14:43:57 +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 ,
2010-04-20 19:43:34 +04:00
. needs_scratch_page = true ,
2005-04-17 02:20:36 +04:00
. 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 ,
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
} ;
/* Some basic sanity checks for the aperture. */
2012-12-22 03:12:08 +04:00
static int agp_aperture_valid ( u64 aper , u32 size )
2005-04-17 02:20:36 +04:00
{
2008-05-20 18:27:17 +04:00
if ( ! aperture_valid ( aper , size , 32 * 1024 * 1024 ) )
2005-04-17 02:20:36 +04:00
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 .
*/
2012-12-22 03:12:08 +04:00
static int fix_northbridge ( struct pci_dev * nb , struct pci_dev * agp , u16 cap )
2005-04-17 02:20:36 +04:00
{
u64 aper , nb_aper ;
int order = 0 ;
u32 nb_order , nb_base ;
u16 apsize ;
2008-04-15 14:43:57 +04:00
pci_read_config_dword ( nb , AMD64_GARTAPERTURECTL , & nb_order ) ;
2005-04-17 02:20:36 +04:00
nb_order = ( nb_order > > 1 ) & 7 ;
2008-04-15 14:43:57 +04:00
pci_read_config_dword ( nb , AMD64_GARTAPERTUREBASE , & nb_base ) ;
2018-07-05 01:20:41 +03:00
nb_aper = ( u64 ) nb_base < < 25 ;
2005-04-17 02:20:36 +04:00
/* Northbridge seems to contain crap. Try the AGP bridge. */
pci_read_config_word ( agp , cap + 0x14 , & apsize ) ;
2009-03-10 22:55:50 +03:00
if ( apsize = = 0xffff ) {
if ( agp_aperture_valid ( nb_aper , ( 32 * 1024 * 1024 ) < < nb_order ) )
return 0 ;
2005-04-17 02:20:36 +04:00
return - 1 ;
2009-03-10 22:55:50 +03:00
}
2005-04-17 02:20:36 +04:00
apsize & = 0xfff ;
/* Some BIOS use weird encodings not in the AGPv3 table. */
if ( apsize & 0xff )
apsize | = 0xf00 ;
order = 7 - hweight16 ( apsize ) ;
2014-01-04 05:26:58 +04:00
aper = pci_bus_address ( agp , AGP_APERTURE_BAR ) ;
2008-04-13 12:11:41 +04:00
/*
* On some sick chips APSIZE is 0. This means it wants 4 G
* so let double check that order , and lets trust the AMD NB settings
*/
2008-04-14 05:42:31 +04:00
if ( order > = 0 & & aper + ( 32ULL < < ( 20 + order ) ) > 0x100000000ULL ) {
2008-07-30 23:26:51 +04:00
dev_info ( & agp - > dev , " aperture size %u MB is not right, using settings from NB \n " ,
32 < < order ) ;
2008-04-13 12:11:41 +04:00
order = nb_order ;
}
2009-03-10 22:55:50 +03:00
if ( nb_order > = order ) {
if ( agp_aperture_valid ( nb_aper , ( 32 * 1024 * 1024 ) < < nb_order ) )
return 0 ;
}
2008-07-30 23:26:51 +04:00
dev_info ( & agp - > dev , " aperture from AGP @ %Lx size %u MB \n " ,
aper , 32 < < order ) ;
2008-05-20 18:27:17 +04:00
if ( order < 0 | | ! agp_aperture_valid ( aper , ( 32 * 1024 * 1024 ) < < order ) )
2005-04-17 02:20:36 +04:00
return - 1 ;
2010-09-03 20:39:40 +04:00
gart_set_size_and_enable ( nb , order ) ;
2008-04-15 14:43:57 +04:00
pci_write_config_dword ( nb , AMD64_GARTAPERTUREBASE , aper > > 25 ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2012-12-22 03:12:08 +04:00
static int cache_nbs ( struct pci_dev * pdev , u32 cap_ptr )
2005-04-17 02:20:36 +04:00
{
2006-06-26 15:56:40 +04:00
int i ;
2010-10-29 19:14:31 +04:00
if ( amd_cache_northbridges ( ) < 0 )
2006-06-26 15:56:40 +04:00
return - ENODEV ;
2010-10-29 19:14:31 +04:00
if ( ! amd_nb_has_feature ( AMD_NB_GART ) )
2010-09-17 20:02:54 +04:00
return - ENODEV ;
2006-06-26 15:56:40 +04:00
i = 0 ;
2010-10-29 19:14:31 +04:00
for ( i = 0 ; i < amd_nb_num ( ) ; i + + ) {
struct pci_dev * dev = node_to_amd_nb ( i ) - > misc ;
2006-06-26 15:56:40 +04:00
if ( fix_northbridge ( dev , pdev , cap_ptr ) < 0 ) {
2008-07-30 23:26:51 +04:00
dev_err ( & dev - > dev , " no usable aperture found \n " ) ;
2005-04-17 02:20:36 +04:00
# ifdef __x86_64__
/* should port this to i386 */
2008-07-30 23:26:51 +04:00
dev_err ( & dev - > dev , " consider rebooting with iommu=memaper=2 to get a good aperture \n " ) ;
2005-04-17 02:20:36 +04:00
# 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 */
2012-12-22 03:12:08 +04:00
static void amd8151_init ( struct pci_dev * pdev , struct agp_bridge_data * bridge )
2005-04-17 02:20:36 +04:00
{
char * revstring ;
2007-06-09 02:46:36 +04:00
switch ( pdev - > revision ) {
2005-04-17 02:20:36 +04:00
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 ;
}
2008-07-30 23:26:51 +04:00
dev_info ( & pdev - > dev , " AMD 8151 AGP Bridge rev %s \n " , revstring ) ;
2005-04-17 02:20:36 +04:00
/*
* Work around errata .
* Chips before B2 stepping incorrectly reporting v3 .5
*/
2007-06-09 02:46:36 +04:00
if ( pdev - > revision < 0x13 ) {
2008-07-30 23:26:51 +04:00
dev_info ( & pdev - > dev , " correcting AGP revision (reports 3.5, is really 3.0) \n " ) ;
2005-04-17 02:20:36 +04:00
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 }
} ;
2012-12-22 03:12:08 +04:00
static int uli_agp_init ( struct pci_dev * pdev )
2005-04-17 02:20:36 +04:00
{
u32 httfea , baseaddr , enuscr ;
struct pci_dev * dev1 ;
2010-05-24 23:14:15 +04:00
int i , ret ;
2005-04-17 02:20:36 +04:00
unsigned size = amd64_fetch_size ( ) ;
2008-07-30 23:26:51 +04:00
dev_info ( & pdev - > dev , " 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 ) {
2008-07-30 23:26:51 +04:00
dev_info ( & pdev - > dev , " can't find ULi secondary device \n " ) ;
2005-04-17 02:20:36 +04:00
return - ENODEV ;
}
for ( i = 0 ; i < ARRAY_SIZE ( uli_sizes ) ; i + + )
if ( uli_sizes [ i ] . size = = size )
break ;
if ( i = = ARRAY_SIZE ( uli_sizes ) ) {
2008-07-30 23:26:51 +04:00
dev_info ( & pdev - > dev , " no ULi size found for %d \n " , size ) ;
2010-05-24 23:14:15 +04:00
ret = - ENODEV ;
goto put ;
2005-04-17 02:20:36 +04:00
}
/* shadow x86-64 registers into ULi registers */
2010-10-29 19:14:31 +04:00
pci_read_config_dword ( node_to_amd_nb ( 0 ) - > misc , AMD64_GARTAPERTUREBASE ,
2010-09-17 20:02:54 +04:00
& httfea ) ;
2005-04-17 02:20:36 +04:00
/* if x86-64 aperture base is beyond 4G, exit here */
2010-05-24 23:14:15 +04:00
if ( ( httfea & 0x7fff ) > > ( 32 - 25 ) ) {
ret = - ENODEV ;
goto put ;
}
2005-04-17 02:20:36 +04:00
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 ) ;
2010-05-24 23:14:15 +04:00
ret = 0 ;
put :
2006-09-26 20:56:55 +04:00
pci_dev_put ( dev1 ) ;
2010-05-24 23:14:15 +04:00
return ret ;
2005-04-17 02:20:36 +04:00
}
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 ;
2010-05-24 23:14:15 +04:00
int i , ret ;
2005-04-17 02:20:36 +04:00
unsigned size = amd64_fetch_size ( ) ;
2008-07-30 23:26:51 +04:00
dev_info ( & pdev - > dev , " setting up Nforce3 AGP \n " ) ;
2005-04-17 02:20:36 +04:00
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 ) {
2008-07-30 23:26:51 +04:00
dev_info ( & pdev - > dev , " can't find Nforce3 secondary device \n " ) ;
2005-04-17 02:20:36 +04:00
return - ENODEV ;
}
for ( i = 0 ; i < ARRAY_SIZE ( nforce3_sizes ) ; i + + )
if ( nforce3_sizes [ i ] . size = = size )
break ;
if ( i = = ARRAY_SIZE ( nforce3_sizes ) ) {
2008-07-30 23:26:51 +04:00
dev_info ( & pdev - > dev , " no NForce3 size found for %d \n " , size ) ;
2010-05-24 23:14:15 +04:00
ret = - ENODEV ;
goto put ;
2005-04-17 02:20:36 +04:00
}
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 */
2010-10-29 19:14:31 +04:00
pci_read_config_dword ( node_to_amd_nb ( 0 ) - > misc , AMD64_GARTAPERTUREBASE ,
2010-09-17 20:02:54 +04:00
& 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 ) ) {
2008-07-30 23:26:51 +04:00
dev_info ( & pdev - > dev , " aperture base > 4G \n " ) ;
2010-05-24 23:14:15 +04:00
ret = - ENODEV ;
goto put ;
2006-02-21 02:34:37 +03:00
}
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 ) ;
2010-05-24 23:14:15 +04:00
ret = 0 ;
put :
2006-09-26 20:56:55 +04:00
pci_dev_put ( dev1 ) ;
2010-05-24 23:14:15 +04:00
return ret ;
2005-04-17 02:20:36 +04:00
}
2012-12-22 03:12:08 +04:00
static int agp_amd64_probe ( struct pci_dev * pdev ,
const struct pci_device_id * ent )
2005-04-17 02:20:36 +04:00
{
struct agp_bridge_data * bridge ;
u8 cap_ptr ;
2008-07-30 23:26:51 +04:00
int err ;
2005-04-17 02:20:36 +04:00
2010-03-24 06:36:31 +03:00
/* The Highlander principle */
if ( agp_bridges_found )
return - ENODEV ;
2005-04-17 02:20:36 +04:00
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 {
2008-07-30 23:26:51 +04:00
dev_info ( & pdev - > dev , " AGP bridge [%04x/%04x] \n " ,
pdev - > vendor , pdev - > device ) ;
2005-04-17 02:20:36 +04:00
}
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 ) ;
2008-07-30 23:26:51 +04:00
err = agp_add_bridge ( bridge ) ;
if ( err < 0 )
return err ;
agp_bridges_found + + ;
return 0 ;
2005-04-17 02:20:36 +04:00
}
2012-11-19 22:26:26 +04:00
static void agp_amd64_remove ( struct pci_dev * pdev )
2005-04-17 02:20:36 +04:00
{
struct agp_bridge_data * bridge = pci_get_drvdata ( pdev ) ;
2009-07-29 13:25:58 +04:00
release_mem_region ( virt_to_phys ( 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 ) ;
2010-03-24 06:36:31 +03:00
agp_bridges_found - - ;
2005-04-17 02:20:36 +04:00
}
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 */
2017-08-01 19:01:55 +03:00
static const struct pci_device_id agp_amd64_pci_table [ ] = {
2005-04-17 02:20:36 +04:00
{
. 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 ) ;
2013-12-03 03:03:23 +04:00
static const struct pci_device_id agp_amd64_pci_promisc_table [ ] = {
2010-03-24 06:36:31 +03:00
{ PCI_DEVICE_CLASS ( 0 , 0 ) } ,
{ }
} ;
2005-04-17 02:20:36 +04:00
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 ;
2009-12-28 12:11:56 +03:00
2008-07-30 23:26:51 +04:00
err = pci_register_driver ( & agp_amd64_pci_driver ) ;
if ( err < 0 )
return err ;
if ( agp_bridges_found = = 0 ) {
2005-04-17 02:20:36 +04:00
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
2011-02-08 01:29:31 +03:00
pci_unregister_driver ( & agp_amd64_pci_driver ) ;
2005-04-17 02:20:36 +04:00
return - ENODEV ;
}
/* First check that we have at least one AMD64 NB */
2020-03-16 15:23:21 +03:00
if ( ! amd_nb_num ( ) ) {
2011-02-08 01:29:31 +03:00
pci_unregister_driver ( & agp_amd64_pci_driver ) ;
2005-04-17 02:20:36 +04:00
return - ENODEV ;
2011-02-08 01:29:31 +03:00
}
2005-04-17 02:20:36 +04:00
/* Look for any AGP bridge */
2010-03-24 06:36:31 +03:00
agp_amd64_pci_driver . id_table = agp_amd64_pci_promisc_table ;
err = driver_attach ( & agp_amd64_pci_driver . driver ) ;
2011-02-08 01:29:31 +03:00
if ( err = = 0 & & agp_bridges_found = = 0 ) {
pci_unregister_driver ( & agp_amd64_pci_driver ) ;
2010-03-24 06:36:31 +03:00
err = - ENODEV ;
2011-02-08 01:29:31 +03:00
}
2005-04-17 02:20:36 +04:00
}
return err ;
}
2010-01-25 08:10:47 +03:00
static int __init agp_amd64_mod_init ( void )
{
2010-02-04 08:43:38 +03:00
# ifndef MODULE
2010-01-25 08:10:47 +03:00
if ( gart_iommu_aperture )
return agp_bridges_found ? 0 : - ENODEV ;
2010-02-04 08:43:38 +03:00
# endif
2010-01-25 08:10:47 +03:00
return agp_amd64_init ( ) ;
}
2005-04-17 02:20:36 +04:00
static void __exit agp_amd64_cleanup ( void )
{
2010-02-04 08:43:38 +03:00
# ifndef MODULE
2010-01-04 10:16:23 +03:00
if ( gart_iommu_aperture )
return ;
2010-02-04 08:43:38 +03:00
# endif
2005-04-17 02:20:36 +04:00
if ( aperture_resource )
release_resource ( aperture_resource ) ;
pci_unregister_driver ( & agp_amd64_pci_driver ) ;
}
2010-01-25 08:10:47 +03:00
module_init ( agp_amd64_mod_init ) ;
2005-04-17 02:20:36 +04:00
module_exit ( agp_amd64_cleanup ) ;
2014-12-19 19:23:50 +03:00
MODULE_AUTHOR ( " Dave Jones, Andi Kleen " ) ;
2005-04-17 02:20:36 +04:00
module_param ( agp_try_unsupported , bool , 0 ) ;
MODULE_LICENSE ( " GPL " ) ;