162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright 2001-2003 SuSE Labs. 462306a36Sopenharmony_ci * Distributed under the GNU public license, v2. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * This is a GART driver for the AMD Opteron/Athlon64 on-CPU northbridge. 762306a36Sopenharmony_ci * It also includes support for the AMD 8151 AGP bridge, 862306a36Sopenharmony_ci * although it doesn't actually do much, as all the real 962306a36Sopenharmony_ci * work is done in the northbridge(s). 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <linux/module.h> 1362306a36Sopenharmony_ci#include <linux/pci.h> 1462306a36Sopenharmony_ci#include <linux/init.h> 1562306a36Sopenharmony_ci#include <linux/agp_backend.h> 1662306a36Sopenharmony_ci#include <linux/mmzone.h> 1762306a36Sopenharmony_ci#include <asm/page.h> /* PAGE_SIZE */ 1862306a36Sopenharmony_ci#include <asm/e820/api.h> 1962306a36Sopenharmony_ci#include <asm/amd_nb.h> 2062306a36Sopenharmony_ci#include <asm/gart.h> 2162306a36Sopenharmony_ci#include "agp.h" 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci/* NVIDIA K8 registers */ 2462306a36Sopenharmony_ci#define NVIDIA_X86_64_0_APBASE 0x10 2562306a36Sopenharmony_ci#define NVIDIA_X86_64_1_APBASE1 0x50 2662306a36Sopenharmony_ci#define NVIDIA_X86_64_1_APLIMIT1 0x54 2762306a36Sopenharmony_ci#define NVIDIA_X86_64_1_APSIZE 0xa8 2862306a36Sopenharmony_ci#define NVIDIA_X86_64_1_APBASE2 0xd8 2962306a36Sopenharmony_ci#define NVIDIA_X86_64_1_APLIMIT2 0xdc 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci/* ULi K8 registers */ 3262306a36Sopenharmony_ci#define ULI_X86_64_BASE_ADDR 0x10 3362306a36Sopenharmony_ci#define ULI_X86_64_HTT_FEA_REG 0x50 3462306a36Sopenharmony_ci#define ULI_X86_64_ENU_SCR_REG 0x54 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_cistatic struct resource *aperture_resource; 3762306a36Sopenharmony_cistatic bool __initdata agp_try_unsupported = 1; 3862306a36Sopenharmony_cistatic int agp_bridges_found; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_cistatic void amd64_tlbflush(struct agp_memory *temp) 4162306a36Sopenharmony_ci{ 4262306a36Sopenharmony_ci amd_flush_garts(); 4362306a36Sopenharmony_ci} 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_cistatic int amd64_insert_memory(struct agp_memory *mem, off_t pg_start, int type) 4662306a36Sopenharmony_ci{ 4762306a36Sopenharmony_ci int i, j, num_entries; 4862306a36Sopenharmony_ci long long tmp; 4962306a36Sopenharmony_ci int mask_type; 5062306a36Sopenharmony_ci struct agp_bridge_data *bridge = mem->bridge; 5162306a36Sopenharmony_ci u32 pte; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci num_entries = agp_num_entries(); 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci if (type != mem->type) 5662306a36Sopenharmony_ci return -EINVAL; 5762306a36Sopenharmony_ci mask_type = bridge->driver->agp_type_to_mask_type(bridge, type); 5862306a36Sopenharmony_ci if (mask_type != 0) 5962306a36Sopenharmony_ci return -EINVAL; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci /* Make sure we can fit the range in the gatt table. */ 6362306a36Sopenharmony_ci /* FIXME: could wrap */ 6462306a36Sopenharmony_ci if (((unsigned long)pg_start + mem->page_count) > num_entries) 6562306a36Sopenharmony_ci return -EINVAL; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci j = pg_start; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci /* gatt table should be empty. */ 7062306a36Sopenharmony_ci while (j < (pg_start + mem->page_count)) { 7162306a36Sopenharmony_ci if (!PGE_EMPTY(agp_bridge, readl(agp_bridge->gatt_table+j))) 7262306a36Sopenharmony_ci return -EBUSY; 7362306a36Sopenharmony_ci j++; 7462306a36Sopenharmony_ci } 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci if (!mem->is_flushed) { 7762306a36Sopenharmony_ci global_cache_flush(); 7862306a36Sopenharmony_ci mem->is_flushed = true; 7962306a36Sopenharmony_ci } 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { 8262306a36Sopenharmony_ci tmp = agp_bridge->driver->mask_memory(agp_bridge, 8362306a36Sopenharmony_ci page_to_phys(mem->pages[i]), 8462306a36Sopenharmony_ci mask_type); 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci BUG_ON(tmp & 0xffffff0000000ffcULL); 8762306a36Sopenharmony_ci pte = (tmp & 0x000000ff00000000ULL) >> 28; 8862306a36Sopenharmony_ci pte |=(tmp & 0x00000000fffff000ULL); 8962306a36Sopenharmony_ci pte |= GPTE_VALID | GPTE_COHERENT; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci writel(pte, agp_bridge->gatt_table+j); 9262306a36Sopenharmony_ci readl(agp_bridge->gatt_table+j); /* PCI Posting. */ 9362306a36Sopenharmony_ci } 9462306a36Sopenharmony_ci amd64_tlbflush(mem); 9562306a36Sopenharmony_ci return 0; 9662306a36Sopenharmony_ci} 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci/* 9962306a36Sopenharmony_ci * This hack alters the order element according 10062306a36Sopenharmony_ci * to the size of a long. It sucks. I totally disown this, even 10162306a36Sopenharmony_ci * though it does appear to work for the most part. 10262306a36Sopenharmony_ci */ 10362306a36Sopenharmony_cistatic struct aper_size_info_32 amd64_aperture_sizes[7] = 10462306a36Sopenharmony_ci{ 10562306a36Sopenharmony_ci {32, 8192, 3+(sizeof(long)/8), 0 }, 10662306a36Sopenharmony_ci {64, 16384, 4+(sizeof(long)/8), 1<<1 }, 10762306a36Sopenharmony_ci {128, 32768, 5+(sizeof(long)/8), 1<<2 }, 10862306a36Sopenharmony_ci {256, 65536, 6+(sizeof(long)/8), 1<<1 | 1<<2 }, 10962306a36Sopenharmony_ci {512, 131072, 7+(sizeof(long)/8), 1<<3 }, 11062306a36Sopenharmony_ci {1024, 262144, 8+(sizeof(long)/8), 1<<1 | 1<<3}, 11162306a36Sopenharmony_ci {2048, 524288, 9+(sizeof(long)/8), 1<<2 | 1<<3} 11262306a36Sopenharmony_ci}; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci/* 11662306a36Sopenharmony_ci * Get the current Aperture size from the x86-64. 11762306a36Sopenharmony_ci * Note, that there may be multiple x86-64's, but we just return 11862306a36Sopenharmony_ci * the value from the first one we find. The set_size functions 11962306a36Sopenharmony_ci * keep the rest coherent anyway. Or at least should do. 12062306a36Sopenharmony_ci */ 12162306a36Sopenharmony_cistatic int amd64_fetch_size(void) 12262306a36Sopenharmony_ci{ 12362306a36Sopenharmony_ci struct pci_dev *dev; 12462306a36Sopenharmony_ci int i; 12562306a36Sopenharmony_ci u32 temp; 12662306a36Sopenharmony_ci struct aper_size_info_32 *values; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci dev = node_to_amd_nb(0)->misc; 12962306a36Sopenharmony_ci if (dev==NULL) 13062306a36Sopenharmony_ci return 0; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci pci_read_config_dword(dev, AMD64_GARTAPERTURECTL, &temp); 13362306a36Sopenharmony_ci temp = (temp & 0xe); 13462306a36Sopenharmony_ci values = A_SIZE_32(amd64_aperture_sizes); 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci for (i = 0; i < agp_bridge->driver->num_aperture_sizes; i++) { 13762306a36Sopenharmony_ci if (temp == values[i].size_value) { 13862306a36Sopenharmony_ci agp_bridge->previous_size = 13962306a36Sopenharmony_ci agp_bridge->current_size = (void *) (values + i); 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci agp_bridge->aperture_size_idx = i; 14262306a36Sopenharmony_ci return values[i].size; 14362306a36Sopenharmony_ci } 14462306a36Sopenharmony_ci } 14562306a36Sopenharmony_ci return 0; 14662306a36Sopenharmony_ci} 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci/* 14962306a36Sopenharmony_ci * In a multiprocessor x86-64 system, this function gets 15062306a36Sopenharmony_ci * called once for each CPU. 15162306a36Sopenharmony_ci */ 15262306a36Sopenharmony_cistatic u64 amd64_configure(struct pci_dev *hammer, u64 gatt_table) 15362306a36Sopenharmony_ci{ 15462306a36Sopenharmony_ci u64 aperturebase; 15562306a36Sopenharmony_ci u32 tmp; 15662306a36Sopenharmony_ci u64 aper_base; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci /* Address to map to */ 15962306a36Sopenharmony_ci pci_read_config_dword(hammer, AMD64_GARTAPERTUREBASE, &tmp); 16062306a36Sopenharmony_ci aperturebase = (u64)tmp << 25; 16162306a36Sopenharmony_ci aper_base = (aperturebase & PCI_BASE_ADDRESS_MEM_MASK); 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci enable_gart_translation(hammer, gatt_table); 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci return aper_base; 16662306a36Sopenharmony_ci} 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_cistatic const struct aper_size_info_32 amd_8151_sizes[7] = 17062306a36Sopenharmony_ci{ 17162306a36Sopenharmony_ci {2048, 524288, 9, 0x00000000 }, /* 0 0 0 0 0 0 */ 17262306a36Sopenharmony_ci {1024, 262144, 8, 0x00000400 }, /* 1 0 0 0 0 0 */ 17362306a36Sopenharmony_ci {512, 131072, 7, 0x00000600 }, /* 1 1 0 0 0 0 */ 17462306a36Sopenharmony_ci {256, 65536, 6, 0x00000700 }, /* 1 1 1 0 0 0 */ 17562306a36Sopenharmony_ci {128, 32768, 5, 0x00000720 }, /* 1 1 1 1 0 0 */ 17662306a36Sopenharmony_ci {64, 16384, 4, 0x00000730 }, /* 1 1 1 1 1 0 */ 17762306a36Sopenharmony_ci {32, 8192, 3, 0x00000738 } /* 1 1 1 1 1 1 */ 17862306a36Sopenharmony_ci}; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_cistatic int amd_8151_configure(void) 18162306a36Sopenharmony_ci{ 18262306a36Sopenharmony_ci unsigned long gatt_bus = virt_to_phys(agp_bridge->gatt_table_real); 18362306a36Sopenharmony_ci int i; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci if (!amd_nb_has_feature(AMD_NB_GART)) 18662306a36Sopenharmony_ci return 0; 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci /* Configure AGP regs in each x86-64 host bridge. */ 18962306a36Sopenharmony_ci for (i = 0; i < amd_nb_num(); i++) { 19062306a36Sopenharmony_ci agp_bridge->gart_bus_addr = 19162306a36Sopenharmony_ci amd64_configure(node_to_amd_nb(i)->misc, gatt_bus); 19262306a36Sopenharmony_ci } 19362306a36Sopenharmony_ci amd_flush_garts(); 19462306a36Sopenharmony_ci return 0; 19562306a36Sopenharmony_ci} 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_cistatic void amd64_cleanup(void) 19962306a36Sopenharmony_ci{ 20062306a36Sopenharmony_ci u32 tmp; 20162306a36Sopenharmony_ci int i; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci if (!amd_nb_has_feature(AMD_NB_GART)) 20462306a36Sopenharmony_ci return; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci for (i = 0; i < amd_nb_num(); i++) { 20762306a36Sopenharmony_ci struct pci_dev *dev = node_to_amd_nb(i)->misc; 20862306a36Sopenharmony_ci /* disable gart translation */ 20962306a36Sopenharmony_ci pci_read_config_dword(dev, AMD64_GARTAPERTURECTL, &tmp); 21062306a36Sopenharmony_ci tmp &= ~GARTEN; 21162306a36Sopenharmony_ci pci_write_config_dword(dev, AMD64_GARTAPERTURECTL, tmp); 21262306a36Sopenharmony_ci } 21362306a36Sopenharmony_ci} 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_cistatic const struct agp_bridge_driver amd_8151_driver = { 21762306a36Sopenharmony_ci .owner = THIS_MODULE, 21862306a36Sopenharmony_ci .aperture_sizes = amd_8151_sizes, 21962306a36Sopenharmony_ci .size_type = U32_APER_SIZE, 22062306a36Sopenharmony_ci .num_aperture_sizes = 7, 22162306a36Sopenharmony_ci .needs_scratch_page = true, 22262306a36Sopenharmony_ci .configure = amd_8151_configure, 22362306a36Sopenharmony_ci .fetch_size = amd64_fetch_size, 22462306a36Sopenharmony_ci .cleanup = amd64_cleanup, 22562306a36Sopenharmony_ci .tlb_flush = amd64_tlbflush, 22662306a36Sopenharmony_ci .mask_memory = agp_generic_mask_memory, 22762306a36Sopenharmony_ci .masks = NULL, 22862306a36Sopenharmony_ci .agp_enable = agp_generic_enable, 22962306a36Sopenharmony_ci .cache_flush = global_cache_flush, 23062306a36Sopenharmony_ci .create_gatt_table = agp_generic_create_gatt_table, 23162306a36Sopenharmony_ci .free_gatt_table = agp_generic_free_gatt_table, 23262306a36Sopenharmony_ci .insert_memory = amd64_insert_memory, 23362306a36Sopenharmony_ci .remove_memory = agp_generic_remove_memory, 23462306a36Sopenharmony_ci .alloc_by_type = agp_generic_alloc_by_type, 23562306a36Sopenharmony_ci .free_by_type = agp_generic_free_by_type, 23662306a36Sopenharmony_ci .agp_alloc_page = agp_generic_alloc_page, 23762306a36Sopenharmony_ci .agp_alloc_pages = agp_generic_alloc_pages, 23862306a36Sopenharmony_ci .agp_destroy_page = agp_generic_destroy_page, 23962306a36Sopenharmony_ci .agp_destroy_pages = agp_generic_destroy_pages, 24062306a36Sopenharmony_ci .agp_type_to_mask_type = agp_generic_type_to_mask_type, 24162306a36Sopenharmony_ci}; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci/* Some basic sanity checks for the aperture. */ 24462306a36Sopenharmony_cistatic int agp_aperture_valid(u64 aper, u32 size) 24562306a36Sopenharmony_ci{ 24662306a36Sopenharmony_ci if (!aperture_valid(aper, size, 32*1024*1024)) 24762306a36Sopenharmony_ci return 0; 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci /* Request the Aperture. This catches cases when someone else 25062306a36Sopenharmony_ci already put a mapping in there - happens with some very broken BIOS 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci Maybe better to use pci_assign_resource/pci_enable_device instead 25362306a36Sopenharmony_ci trusting the bridges? */ 25462306a36Sopenharmony_ci if (!aperture_resource && 25562306a36Sopenharmony_ci !(aperture_resource = request_mem_region(aper, size, "aperture"))) { 25662306a36Sopenharmony_ci printk(KERN_ERR PFX "Aperture conflicts with PCI mapping.\n"); 25762306a36Sopenharmony_ci return 0; 25862306a36Sopenharmony_ci } 25962306a36Sopenharmony_ci return 1; 26062306a36Sopenharmony_ci} 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci/* 26362306a36Sopenharmony_ci * W*s centric BIOS sometimes only set up the aperture in the AGP 26462306a36Sopenharmony_ci * bridge, not the northbridge. On AMD64 this is handled early 26562306a36Sopenharmony_ci * in aperture.c, but when IOMMU is not enabled or we run 26662306a36Sopenharmony_ci * on a 32bit kernel this needs to be redone. 26762306a36Sopenharmony_ci * Unfortunately it is impossible to fix the aperture here because it's too late 26862306a36Sopenharmony_ci * to allocate that much memory. But at least error out cleanly instead of 26962306a36Sopenharmony_ci * crashing. 27062306a36Sopenharmony_ci */ 27162306a36Sopenharmony_cistatic int fix_northbridge(struct pci_dev *nb, struct pci_dev *agp, u16 cap) 27262306a36Sopenharmony_ci{ 27362306a36Sopenharmony_ci u64 aper, nb_aper; 27462306a36Sopenharmony_ci int order = 0; 27562306a36Sopenharmony_ci u32 nb_order, nb_base; 27662306a36Sopenharmony_ci u16 apsize; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci pci_read_config_dword(nb, AMD64_GARTAPERTURECTL, &nb_order); 27962306a36Sopenharmony_ci nb_order = (nb_order >> 1) & 7; 28062306a36Sopenharmony_ci pci_read_config_dword(nb, AMD64_GARTAPERTUREBASE, &nb_base); 28162306a36Sopenharmony_ci nb_aper = (u64)nb_base << 25; 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci /* Northbridge seems to contain crap. Try the AGP bridge. */ 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci pci_read_config_word(agp, cap+0x14, &apsize); 28662306a36Sopenharmony_ci if (apsize == 0xffff) { 28762306a36Sopenharmony_ci if (agp_aperture_valid(nb_aper, (32*1024*1024)<<nb_order)) 28862306a36Sopenharmony_ci return 0; 28962306a36Sopenharmony_ci return -1; 29062306a36Sopenharmony_ci } 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci apsize &= 0xfff; 29362306a36Sopenharmony_ci /* Some BIOS use weird encodings not in the AGPv3 table. */ 29462306a36Sopenharmony_ci if (apsize & 0xff) 29562306a36Sopenharmony_ci apsize |= 0xf00; 29662306a36Sopenharmony_ci order = 7 - hweight16(apsize); 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci aper = pci_bus_address(agp, AGP_APERTURE_BAR); 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci /* 30162306a36Sopenharmony_ci * On some sick chips APSIZE is 0. This means it wants 4G 30262306a36Sopenharmony_ci * so let double check that order, and lets trust the AMD NB settings 30362306a36Sopenharmony_ci */ 30462306a36Sopenharmony_ci if (order >=0 && aper + (32ULL<<(20 + order)) > 0x100000000ULL) { 30562306a36Sopenharmony_ci dev_info(&agp->dev, "aperture size %u MB is not right, using settings from NB\n", 30662306a36Sopenharmony_ci 32 << order); 30762306a36Sopenharmony_ci order = nb_order; 30862306a36Sopenharmony_ci } 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci if (nb_order >= order) { 31162306a36Sopenharmony_ci if (agp_aperture_valid(nb_aper, (32*1024*1024)<<nb_order)) 31262306a36Sopenharmony_ci return 0; 31362306a36Sopenharmony_ci } 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci dev_info(&agp->dev, "aperture from AGP @ %Lx size %u MB\n", 31662306a36Sopenharmony_ci aper, 32 << order); 31762306a36Sopenharmony_ci if (order < 0 || !agp_aperture_valid(aper, (32*1024*1024)<<order)) 31862306a36Sopenharmony_ci return -1; 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci gart_set_size_and_enable(nb, order); 32162306a36Sopenharmony_ci pci_write_config_dword(nb, AMD64_GARTAPERTUREBASE, aper >> 25); 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci return 0; 32462306a36Sopenharmony_ci} 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_cistatic int cache_nbs(struct pci_dev *pdev, u32 cap_ptr) 32762306a36Sopenharmony_ci{ 32862306a36Sopenharmony_ci int i; 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci if (!amd_nb_num()) 33162306a36Sopenharmony_ci return -ENODEV; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci if (!amd_nb_has_feature(AMD_NB_GART)) 33462306a36Sopenharmony_ci return -ENODEV; 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci i = 0; 33762306a36Sopenharmony_ci for (i = 0; i < amd_nb_num(); i++) { 33862306a36Sopenharmony_ci struct pci_dev *dev = node_to_amd_nb(i)->misc; 33962306a36Sopenharmony_ci if (fix_northbridge(dev, pdev, cap_ptr) < 0) { 34062306a36Sopenharmony_ci dev_err(&dev->dev, "no usable aperture found\n"); 34162306a36Sopenharmony_ci#ifdef __x86_64__ 34262306a36Sopenharmony_ci /* should port this to i386 */ 34362306a36Sopenharmony_ci dev_err(&dev->dev, "consider rebooting with iommu=memaper=2 to get a good aperture\n"); 34462306a36Sopenharmony_ci#endif 34562306a36Sopenharmony_ci return -1; 34662306a36Sopenharmony_ci } 34762306a36Sopenharmony_ci } 34862306a36Sopenharmony_ci return 0; 34962306a36Sopenharmony_ci} 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci/* Handle AMD 8151 quirks */ 35262306a36Sopenharmony_cistatic void amd8151_init(struct pci_dev *pdev, struct agp_bridge_data *bridge) 35362306a36Sopenharmony_ci{ 35462306a36Sopenharmony_ci char *revstring; 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci switch (pdev->revision) { 35762306a36Sopenharmony_ci case 0x01: revstring="A0"; break; 35862306a36Sopenharmony_ci case 0x02: revstring="A1"; break; 35962306a36Sopenharmony_ci case 0x11: revstring="B0"; break; 36062306a36Sopenharmony_ci case 0x12: revstring="B1"; break; 36162306a36Sopenharmony_ci case 0x13: revstring="B2"; break; 36262306a36Sopenharmony_ci case 0x14: revstring="B3"; break; 36362306a36Sopenharmony_ci default: revstring="??"; break; 36462306a36Sopenharmony_ci } 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci dev_info(&pdev->dev, "AMD 8151 AGP Bridge rev %s\n", revstring); 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci /* 36962306a36Sopenharmony_ci * Work around errata. 37062306a36Sopenharmony_ci * Chips before B2 stepping incorrectly reporting v3.5 37162306a36Sopenharmony_ci */ 37262306a36Sopenharmony_ci if (pdev->revision < 0x13) { 37362306a36Sopenharmony_ci dev_info(&pdev->dev, "correcting AGP revision (reports 3.5, is really 3.0)\n"); 37462306a36Sopenharmony_ci bridge->major_version = 3; 37562306a36Sopenharmony_ci bridge->minor_version = 0; 37662306a36Sopenharmony_ci } 37762306a36Sopenharmony_ci} 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_cistatic const struct aper_size_info_32 uli_sizes[7] = 38162306a36Sopenharmony_ci{ 38262306a36Sopenharmony_ci {256, 65536, 6, 10}, 38362306a36Sopenharmony_ci {128, 32768, 5, 9}, 38462306a36Sopenharmony_ci {64, 16384, 4, 8}, 38562306a36Sopenharmony_ci {32, 8192, 3, 7}, 38662306a36Sopenharmony_ci {16, 4096, 2, 6}, 38762306a36Sopenharmony_ci {8, 2048, 1, 4}, 38862306a36Sopenharmony_ci {4, 1024, 0, 3} 38962306a36Sopenharmony_ci}; 39062306a36Sopenharmony_cistatic int uli_agp_init(struct pci_dev *pdev) 39162306a36Sopenharmony_ci{ 39262306a36Sopenharmony_ci u32 httfea,baseaddr,enuscr; 39362306a36Sopenharmony_ci struct pci_dev *dev1; 39462306a36Sopenharmony_ci int i, ret; 39562306a36Sopenharmony_ci unsigned size = amd64_fetch_size(); 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci dev_info(&pdev->dev, "setting up ULi AGP\n"); 39862306a36Sopenharmony_ci dev1 = pci_get_slot (pdev->bus,PCI_DEVFN(0,0)); 39962306a36Sopenharmony_ci if (dev1 == NULL) { 40062306a36Sopenharmony_ci dev_info(&pdev->dev, "can't find ULi secondary device\n"); 40162306a36Sopenharmony_ci return -ENODEV; 40262306a36Sopenharmony_ci } 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(uli_sizes); i++) 40562306a36Sopenharmony_ci if (uli_sizes[i].size == size) 40662306a36Sopenharmony_ci break; 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci if (i == ARRAY_SIZE(uli_sizes)) { 40962306a36Sopenharmony_ci dev_info(&pdev->dev, "no ULi size found for %d\n", size); 41062306a36Sopenharmony_ci ret = -ENODEV; 41162306a36Sopenharmony_ci goto put; 41262306a36Sopenharmony_ci } 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci /* shadow x86-64 registers into ULi registers */ 41562306a36Sopenharmony_ci pci_read_config_dword (node_to_amd_nb(0)->misc, AMD64_GARTAPERTUREBASE, 41662306a36Sopenharmony_ci &httfea); 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci /* if x86-64 aperture base is beyond 4G, exit here */ 41962306a36Sopenharmony_ci if ((httfea & 0x7fff) >> (32 - 25)) { 42062306a36Sopenharmony_ci ret = -ENODEV; 42162306a36Sopenharmony_ci goto put; 42262306a36Sopenharmony_ci } 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci httfea = (httfea& 0x7fff) << 25; 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci pci_read_config_dword(pdev, ULI_X86_64_BASE_ADDR, &baseaddr); 42762306a36Sopenharmony_ci baseaddr&= ~PCI_BASE_ADDRESS_MEM_MASK; 42862306a36Sopenharmony_ci baseaddr|= httfea; 42962306a36Sopenharmony_ci pci_write_config_dword(pdev, ULI_X86_64_BASE_ADDR, baseaddr); 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci enuscr= httfea+ (size * 1024 * 1024) - 1; 43262306a36Sopenharmony_ci pci_write_config_dword(dev1, ULI_X86_64_HTT_FEA_REG, httfea); 43362306a36Sopenharmony_ci pci_write_config_dword(dev1, ULI_X86_64_ENU_SCR_REG, enuscr); 43462306a36Sopenharmony_ci ret = 0; 43562306a36Sopenharmony_ciput: 43662306a36Sopenharmony_ci pci_dev_put(dev1); 43762306a36Sopenharmony_ci return ret; 43862306a36Sopenharmony_ci} 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_cistatic const struct aper_size_info_32 nforce3_sizes[5] = 44262306a36Sopenharmony_ci{ 44362306a36Sopenharmony_ci {512, 131072, 7, 0x00000000 }, 44462306a36Sopenharmony_ci {256, 65536, 6, 0x00000008 }, 44562306a36Sopenharmony_ci {128, 32768, 5, 0x0000000C }, 44662306a36Sopenharmony_ci {64, 16384, 4, 0x0000000E }, 44762306a36Sopenharmony_ci {32, 8192, 3, 0x0000000F } 44862306a36Sopenharmony_ci}; 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci/* Handle shadow device of the Nvidia NForce3 */ 45162306a36Sopenharmony_ci/* CHECK-ME original 2.4 version set up some IORRs. Check if that is needed. */ 45262306a36Sopenharmony_cistatic int nforce3_agp_init(struct pci_dev *pdev) 45362306a36Sopenharmony_ci{ 45462306a36Sopenharmony_ci u32 tmp, apbase, apbar, aplimit; 45562306a36Sopenharmony_ci struct pci_dev *dev1; 45662306a36Sopenharmony_ci int i, ret; 45762306a36Sopenharmony_ci unsigned size = amd64_fetch_size(); 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci dev_info(&pdev->dev, "setting up Nforce3 AGP\n"); 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci dev1 = pci_get_slot(pdev->bus, PCI_DEVFN(11, 0)); 46262306a36Sopenharmony_ci if (dev1 == NULL) { 46362306a36Sopenharmony_ci dev_info(&pdev->dev, "can't find Nforce3 secondary device\n"); 46462306a36Sopenharmony_ci return -ENODEV; 46562306a36Sopenharmony_ci } 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(nforce3_sizes); i++) 46862306a36Sopenharmony_ci if (nforce3_sizes[i].size == size) 46962306a36Sopenharmony_ci break; 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci if (i == ARRAY_SIZE(nforce3_sizes)) { 47262306a36Sopenharmony_ci dev_info(&pdev->dev, "no NForce3 size found for %d\n", size); 47362306a36Sopenharmony_ci ret = -ENODEV; 47462306a36Sopenharmony_ci goto put; 47562306a36Sopenharmony_ci } 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci pci_read_config_dword(dev1, NVIDIA_X86_64_1_APSIZE, &tmp); 47862306a36Sopenharmony_ci tmp &= ~(0xf); 47962306a36Sopenharmony_ci tmp |= nforce3_sizes[i].size_value; 48062306a36Sopenharmony_ci pci_write_config_dword(dev1, NVIDIA_X86_64_1_APSIZE, tmp); 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci /* shadow x86-64 registers into NVIDIA registers */ 48362306a36Sopenharmony_ci pci_read_config_dword (node_to_amd_nb(0)->misc, AMD64_GARTAPERTUREBASE, 48462306a36Sopenharmony_ci &apbase); 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci /* if x86-64 aperture base is beyond 4G, exit here */ 48762306a36Sopenharmony_ci if ( (apbase & 0x7fff) >> (32 - 25) ) { 48862306a36Sopenharmony_ci dev_info(&pdev->dev, "aperture base > 4G\n"); 48962306a36Sopenharmony_ci ret = -ENODEV; 49062306a36Sopenharmony_ci goto put; 49162306a36Sopenharmony_ci } 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci apbase = (apbase & 0x7fff) << 25; 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci pci_read_config_dword(pdev, NVIDIA_X86_64_0_APBASE, &apbar); 49662306a36Sopenharmony_ci apbar &= ~PCI_BASE_ADDRESS_MEM_MASK; 49762306a36Sopenharmony_ci apbar |= apbase; 49862306a36Sopenharmony_ci pci_write_config_dword(pdev, NVIDIA_X86_64_0_APBASE, apbar); 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci aplimit = apbase + (size * 1024 * 1024) - 1; 50162306a36Sopenharmony_ci pci_write_config_dword(dev1, NVIDIA_X86_64_1_APBASE1, apbase); 50262306a36Sopenharmony_ci pci_write_config_dword(dev1, NVIDIA_X86_64_1_APLIMIT1, aplimit); 50362306a36Sopenharmony_ci pci_write_config_dword(dev1, NVIDIA_X86_64_1_APBASE2, apbase); 50462306a36Sopenharmony_ci pci_write_config_dword(dev1, NVIDIA_X86_64_1_APLIMIT2, aplimit); 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci ret = 0; 50762306a36Sopenharmony_ciput: 50862306a36Sopenharmony_ci pci_dev_put(dev1); 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci return ret; 51162306a36Sopenharmony_ci} 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_cistatic int agp_amd64_probe(struct pci_dev *pdev, 51462306a36Sopenharmony_ci const struct pci_device_id *ent) 51562306a36Sopenharmony_ci{ 51662306a36Sopenharmony_ci struct agp_bridge_data *bridge; 51762306a36Sopenharmony_ci u8 cap_ptr; 51862306a36Sopenharmony_ci int err; 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci /* The Highlander principle */ 52162306a36Sopenharmony_ci if (agp_bridges_found) 52262306a36Sopenharmony_ci return -ENODEV; 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP); 52562306a36Sopenharmony_ci if (!cap_ptr) 52662306a36Sopenharmony_ci return -ENODEV; 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci /* Could check for AGPv3 here */ 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci bridge = agp_alloc_bridge(); 53162306a36Sopenharmony_ci if (!bridge) 53262306a36Sopenharmony_ci return -ENOMEM; 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci if (pdev->vendor == PCI_VENDOR_ID_AMD && 53562306a36Sopenharmony_ci pdev->device == PCI_DEVICE_ID_AMD_8151_0) { 53662306a36Sopenharmony_ci amd8151_init(pdev, bridge); 53762306a36Sopenharmony_ci } else { 53862306a36Sopenharmony_ci dev_info(&pdev->dev, "AGP bridge [%04x/%04x]\n", 53962306a36Sopenharmony_ci pdev->vendor, pdev->device); 54062306a36Sopenharmony_ci } 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci bridge->driver = &amd_8151_driver; 54362306a36Sopenharmony_ci bridge->dev = pdev; 54462306a36Sopenharmony_ci bridge->capndx = cap_ptr; 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci /* Fill in the mode register */ 54762306a36Sopenharmony_ci pci_read_config_dword(pdev, bridge->capndx+PCI_AGP_STATUS, &bridge->mode); 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci if (cache_nbs(pdev, cap_ptr) == -1) { 55062306a36Sopenharmony_ci agp_put_bridge(bridge); 55162306a36Sopenharmony_ci return -ENODEV; 55262306a36Sopenharmony_ci } 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci if (pdev->vendor == PCI_VENDOR_ID_NVIDIA) { 55562306a36Sopenharmony_ci int ret = nforce3_agp_init(pdev); 55662306a36Sopenharmony_ci if (ret) { 55762306a36Sopenharmony_ci agp_put_bridge(bridge); 55862306a36Sopenharmony_ci return ret; 55962306a36Sopenharmony_ci } 56062306a36Sopenharmony_ci } 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci if (pdev->vendor == PCI_VENDOR_ID_AL) { 56362306a36Sopenharmony_ci int ret = uli_agp_init(pdev); 56462306a36Sopenharmony_ci if (ret) { 56562306a36Sopenharmony_ci agp_put_bridge(bridge); 56662306a36Sopenharmony_ci return ret; 56762306a36Sopenharmony_ci } 56862306a36Sopenharmony_ci } 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci pci_set_drvdata(pdev, bridge); 57162306a36Sopenharmony_ci err = agp_add_bridge(bridge); 57262306a36Sopenharmony_ci if (err < 0) 57362306a36Sopenharmony_ci return err; 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci agp_bridges_found++; 57662306a36Sopenharmony_ci return 0; 57762306a36Sopenharmony_ci} 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_cistatic void agp_amd64_remove(struct pci_dev *pdev) 58062306a36Sopenharmony_ci{ 58162306a36Sopenharmony_ci struct agp_bridge_data *bridge = pci_get_drvdata(pdev); 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci release_mem_region(virt_to_phys(bridge->gatt_table_real), 58462306a36Sopenharmony_ci amd64_aperture_sizes[bridge->aperture_size_idx].size); 58562306a36Sopenharmony_ci agp_remove_bridge(bridge); 58662306a36Sopenharmony_ci agp_put_bridge(bridge); 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci agp_bridges_found--; 58962306a36Sopenharmony_ci} 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_cistatic int agp_amd64_resume(struct device *dev) 59262306a36Sopenharmony_ci{ 59362306a36Sopenharmony_ci struct pci_dev *pdev = to_pci_dev(dev); 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci if (pdev->vendor == PCI_VENDOR_ID_NVIDIA) 59662306a36Sopenharmony_ci nforce3_agp_init(pdev); 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci return amd_8151_configure(); 59962306a36Sopenharmony_ci} 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_cistatic const struct pci_device_id agp_amd64_pci_table[] = { 60262306a36Sopenharmony_ci { 60362306a36Sopenharmony_ci .class = (PCI_CLASS_BRIDGE_HOST << 8), 60462306a36Sopenharmony_ci .class_mask = ~0, 60562306a36Sopenharmony_ci .vendor = PCI_VENDOR_ID_AMD, 60662306a36Sopenharmony_ci .device = PCI_DEVICE_ID_AMD_8151_0, 60762306a36Sopenharmony_ci .subvendor = PCI_ANY_ID, 60862306a36Sopenharmony_ci .subdevice = PCI_ANY_ID, 60962306a36Sopenharmony_ci }, 61062306a36Sopenharmony_ci /* ULi M1689 */ 61162306a36Sopenharmony_ci { 61262306a36Sopenharmony_ci .class = (PCI_CLASS_BRIDGE_HOST << 8), 61362306a36Sopenharmony_ci .class_mask = ~0, 61462306a36Sopenharmony_ci .vendor = PCI_VENDOR_ID_AL, 61562306a36Sopenharmony_ci .device = PCI_DEVICE_ID_AL_M1689, 61662306a36Sopenharmony_ci .subvendor = PCI_ANY_ID, 61762306a36Sopenharmony_ci .subdevice = PCI_ANY_ID, 61862306a36Sopenharmony_ci }, 61962306a36Sopenharmony_ci /* VIA K8T800Pro */ 62062306a36Sopenharmony_ci { 62162306a36Sopenharmony_ci .class = (PCI_CLASS_BRIDGE_HOST << 8), 62262306a36Sopenharmony_ci .class_mask = ~0, 62362306a36Sopenharmony_ci .vendor = PCI_VENDOR_ID_VIA, 62462306a36Sopenharmony_ci .device = PCI_DEVICE_ID_VIA_K8T800PRO_0, 62562306a36Sopenharmony_ci .subvendor = PCI_ANY_ID, 62662306a36Sopenharmony_ci .subdevice = PCI_ANY_ID, 62762306a36Sopenharmony_ci }, 62862306a36Sopenharmony_ci /* VIA K8T800 */ 62962306a36Sopenharmony_ci { 63062306a36Sopenharmony_ci .class = (PCI_CLASS_BRIDGE_HOST << 8), 63162306a36Sopenharmony_ci .class_mask = ~0, 63262306a36Sopenharmony_ci .vendor = PCI_VENDOR_ID_VIA, 63362306a36Sopenharmony_ci .device = PCI_DEVICE_ID_VIA_8385_0, 63462306a36Sopenharmony_ci .subvendor = PCI_ANY_ID, 63562306a36Sopenharmony_ci .subdevice = PCI_ANY_ID, 63662306a36Sopenharmony_ci }, 63762306a36Sopenharmony_ci /* VIA K8M800 / K8N800 */ 63862306a36Sopenharmony_ci { 63962306a36Sopenharmony_ci .class = (PCI_CLASS_BRIDGE_HOST << 8), 64062306a36Sopenharmony_ci .class_mask = ~0, 64162306a36Sopenharmony_ci .vendor = PCI_VENDOR_ID_VIA, 64262306a36Sopenharmony_ci .device = PCI_DEVICE_ID_VIA_8380_0, 64362306a36Sopenharmony_ci .subvendor = PCI_ANY_ID, 64462306a36Sopenharmony_ci .subdevice = PCI_ANY_ID, 64562306a36Sopenharmony_ci }, 64662306a36Sopenharmony_ci /* VIA K8M890 / K8N890 */ 64762306a36Sopenharmony_ci { 64862306a36Sopenharmony_ci .class = (PCI_CLASS_BRIDGE_HOST << 8), 64962306a36Sopenharmony_ci .class_mask = ~0, 65062306a36Sopenharmony_ci .vendor = PCI_VENDOR_ID_VIA, 65162306a36Sopenharmony_ci .device = PCI_DEVICE_ID_VIA_VT3336, 65262306a36Sopenharmony_ci .subvendor = PCI_ANY_ID, 65362306a36Sopenharmony_ci .subdevice = PCI_ANY_ID, 65462306a36Sopenharmony_ci }, 65562306a36Sopenharmony_ci /* VIA K8T890 */ 65662306a36Sopenharmony_ci { 65762306a36Sopenharmony_ci .class = (PCI_CLASS_BRIDGE_HOST << 8), 65862306a36Sopenharmony_ci .class_mask = ~0, 65962306a36Sopenharmony_ci .vendor = PCI_VENDOR_ID_VIA, 66062306a36Sopenharmony_ci .device = PCI_DEVICE_ID_VIA_3238_0, 66162306a36Sopenharmony_ci .subvendor = PCI_ANY_ID, 66262306a36Sopenharmony_ci .subdevice = PCI_ANY_ID, 66362306a36Sopenharmony_ci }, 66462306a36Sopenharmony_ci /* VIA K8T800/K8M800/K8N800 */ 66562306a36Sopenharmony_ci { 66662306a36Sopenharmony_ci .class = (PCI_CLASS_BRIDGE_HOST << 8), 66762306a36Sopenharmony_ci .class_mask = ~0, 66862306a36Sopenharmony_ci .vendor = PCI_VENDOR_ID_VIA, 66962306a36Sopenharmony_ci .device = PCI_DEVICE_ID_VIA_838X_1, 67062306a36Sopenharmony_ci .subvendor = PCI_ANY_ID, 67162306a36Sopenharmony_ci .subdevice = PCI_ANY_ID, 67262306a36Sopenharmony_ci }, 67362306a36Sopenharmony_ci /* NForce3 */ 67462306a36Sopenharmony_ci { 67562306a36Sopenharmony_ci .class = (PCI_CLASS_BRIDGE_HOST << 8), 67662306a36Sopenharmony_ci .class_mask = ~0, 67762306a36Sopenharmony_ci .vendor = PCI_VENDOR_ID_NVIDIA, 67862306a36Sopenharmony_ci .device = PCI_DEVICE_ID_NVIDIA_NFORCE3, 67962306a36Sopenharmony_ci .subvendor = PCI_ANY_ID, 68062306a36Sopenharmony_ci .subdevice = PCI_ANY_ID, 68162306a36Sopenharmony_ci }, 68262306a36Sopenharmony_ci { 68362306a36Sopenharmony_ci .class = (PCI_CLASS_BRIDGE_HOST << 8), 68462306a36Sopenharmony_ci .class_mask = ~0, 68562306a36Sopenharmony_ci .vendor = PCI_VENDOR_ID_NVIDIA, 68662306a36Sopenharmony_ci .device = PCI_DEVICE_ID_NVIDIA_NFORCE3S, 68762306a36Sopenharmony_ci .subvendor = PCI_ANY_ID, 68862306a36Sopenharmony_ci .subdevice = PCI_ANY_ID, 68962306a36Sopenharmony_ci }, 69062306a36Sopenharmony_ci /* SIS 755 */ 69162306a36Sopenharmony_ci { 69262306a36Sopenharmony_ci .class = (PCI_CLASS_BRIDGE_HOST << 8), 69362306a36Sopenharmony_ci .class_mask = ~0, 69462306a36Sopenharmony_ci .vendor = PCI_VENDOR_ID_SI, 69562306a36Sopenharmony_ci .device = PCI_DEVICE_ID_SI_755, 69662306a36Sopenharmony_ci .subvendor = PCI_ANY_ID, 69762306a36Sopenharmony_ci .subdevice = PCI_ANY_ID, 69862306a36Sopenharmony_ci }, 69962306a36Sopenharmony_ci /* SIS 760 */ 70062306a36Sopenharmony_ci { 70162306a36Sopenharmony_ci .class = (PCI_CLASS_BRIDGE_HOST << 8), 70262306a36Sopenharmony_ci .class_mask = ~0, 70362306a36Sopenharmony_ci .vendor = PCI_VENDOR_ID_SI, 70462306a36Sopenharmony_ci .device = PCI_DEVICE_ID_SI_760, 70562306a36Sopenharmony_ci .subvendor = PCI_ANY_ID, 70662306a36Sopenharmony_ci .subdevice = PCI_ANY_ID, 70762306a36Sopenharmony_ci }, 70862306a36Sopenharmony_ci /* ALI/ULI M1695 */ 70962306a36Sopenharmony_ci { 71062306a36Sopenharmony_ci .class = (PCI_CLASS_BRIDGE_HOST << 8), 71162306a36Sopenharmony_ci .class_mask = ~0, 71262306a36Sopenharmony_ci .vendor = PCI_VENDOR_ID_AL, 71362306a36Sopenharmony_ci .device = 0x1695, 71462306a36Sopenharmony_ci .subvendor = PCI_ANY_ID, 71562306a36Sopenharmony_ci .subdevice = PCI_ANY_ID, 71662306a36Sopenharmony_ci }, 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci { } 71962306a36Sopenharmony_ci}; 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, agp_amd64_pci_table); 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_cistatic const struct pci_device_id agp_amd64_pci_promisc_table[] = { 72462306a36Sopenharmony_ci { PCI_DEVICE_CLASS(0, 0) }, 72562306a36Sopenharmony_ci { } 72662306a36Sopenharmony_ci}; 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_cistatic DEFINE_SIMPLE_DEV_PM_OPS(agp_amd64_pm_ops, NULL, agp_amd64_resume); 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_cistatic struct pci_driver agp_amd64_pci_driver = { 73162306a36Sopenharmony_ci .name = "agpgart-amd64", 73262306a36Sopenharmony_ci .id_table = agp_amd64_pci_table, 73362306a36Sopenharmony_ci .probe = agp_amd64_probe, 73462306a36Sopenharmony_ci .remove = agp_amd64_remove, 73562306a36Sopenharmony_ci .driver.pm = &agp_amd64_pm_ops, 73662306a36Sopenharmony_ci}; 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci/* Not static due to IOMMU code calling it early. */ 74062306a36Sopenharmony_ciint __init agp_amd64_init(void) 74162306a36Sopenharmony_ci{ 74262306a36Sopenharmony_ci int err = 0; 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci if (agp_off) 74562306a36Sopenharmony_ci return -EINVAL; 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ci err = pci_register_driver(&agp_amd64_pci_driver); 74862306a36Sopenharmony_ci if (err < 0) 74962306a36Sopenharmony_ci return err; 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci if (agp_bridges_found == 0) { 75262306a36Sopenharmony_ci if (!agp_try_unsupported && !agp_try_unsupported_boot) { 75362306a36Sopenharmony_ci printk(KERN_INFO PFX "No supported AGP bridge found.\n"); 75462306a36Sopenharmony_ci#ifdef MODULE 75562306a36Sopenharmony_ci printk(KERN_INFO PFX "You can try agp_try_unsupported=1\n"); 75662306a36Sopenharmony_ci#else 75762306a36Sopenharmony_ci printk(KERN_INFO PFX "You can boot with agp=try_unsupported\n"); 75862306a36Sopenharmony_ci#endif 75962306a36Sopenharmony_ci pci_unregister_driver(&agp_amd64_pci_driver); 76062306a36Sopenharmony_ci return -ENODEV; 76162306a36Sopenharmony_ci } 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci /* First check that we have at least one AMD64 NB */ 76462306a36Sopenharmony_ci if (!amd_nb_num()) { 76562306a36Sopenharmony_ci pci_unregister_driver(&agp_amd64_pci_driver); 76662306a36Sopenharmony_ci return -ENODEV; 76762306a36Sopenharmony_ci } 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci /* Look for any AGP bridge */ 77062306a36Sopenharmony_ci agp_amd64_pci_driver.id_table = agp_amd64_pci_promisc_table; 77162306a36Sopenharmony_ci err = driver_attach(&agp_amd64_pci_driver.driver); 77262306a36Sopenharmony_ci if (err == 0 && agp_bridges_found == 0) { 77362306a36Sopenharmony_ci pci_unregister_driver(&agp_amd64_pci_driver); 77462306a36Sopenharmony_ci err = -ENODEV; 77562306a36Sopenharmony_ci } 77662306a36Sopenharmony_ci } 77762306a36Sopenharmony_ci return err; 77862306a36Sopenharmony_ci} 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_cistatic int __init agp_amd64_mod_init(void) 78162306a36Sopenharmony_ci{ 78262306a36Sopenharmony_ci#ifndef MODULE 78362306a36Sopenharmony_ci if (gart_iommu_aperture) 78462306a36Sopenharmony_ci return agp_bridges_found ? 0 : -ENODEV; 78562306a36Sopenharmony_ci#endif 78662306a36Sopenharmony_ci return agp_amd64_init(); 78762306a36Sopenharmony_ci} 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_cistatic void __exit agp_amd64_cleanup(void) 79062306a36Sopenharmony_ci{ 79162306a36Sopenharmony_ci#ifndef MODULE 79262306a36Sopenharmony_ci if (gart_iommu_aperture) 79362306a36Sopenharmony_ci return; 79462306a36Sopenharmony_ci#endif 79562306a36Sopenharmony_ci if (aperture_resource) 79662306a36Sopenharmony_ci release_resource(aperture_resource); 79762306a36Sopenharmony_ci pci_unregister_driver(&agp_amd64_pci_driver); 79862306a36Sopenharmony_ci} 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_cimodule_init(agp_amd64_mod_init); 80162306a36Sopenharmony_cimodule_exit(agp_amd64_cleanup); 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ciMODULE_AUTHOR("Dave Jones, Andi Kleen"); 80462306a36Sopenharmony_cimodule_param(agp_try_unsupported, bool, 0); 80562306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 806