18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Nvidia AGPGART routines. 38c2ecf20Sopenharmony_ci * Based upon a 2.4 agpgart diff by the folks from NVIDIA, and hacked up 48c2ecf20Sopenharmony_ci * to work in 2.5 by Dave Jones. 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/module.h> 88c2ecf20Sopenharmony_ci#include <linux/pci.h> 98c2ecf20Sopenharmony_ci#include <linux/init.h> 108c2ecf20Sopenharmony_ci#include <linux/agp_backend.h> 118c2ecf20Sopenharmony_ci#include <linux/page-flags.h> 128c2ecf20Sopenharmony_ci#include <linux/mm.h> 138c2ecf20Sopenharmony_ci#include <linux/jiffies.h> 148c2ecf20Sopenharmony_ci#include "agp.h" 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci/* NVIDIA registers */ 178c2ecf20Sopenharmony_ci#define NVIDIA_0_APSIZE 0x80 188c2ecf20Sopenharmony_ci#define NVIDIA_1_WBC 0xf0 198c2ecf20Sopenharmony_ci#define NVIDIA_2_GARTCTRL 0xd0 208c2ecf20Sopenharmony_ci#define NVIDIA_2_APBASE 0xd8 218c2ecf20Sopenharmony_ci#define NVIDIA_2_APLIMIT 0xdc 228c2ecf20Sopenharmony_ci#define NVIDIA_2_ATTBASE(i) (0xe0 + (i) * 4) 238c2ecf20Sopenharmony_ci#define NVIDIA_3_APBASE 0x50 248c2ecf20Sopenharmony_ci#define NVIDIA_3_APLIMIT 0x54 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_cistatic struct _nvidia_private { 288c2ecf20Sopenharmony_ci struct pci_dev *dev_1; 298c2ecf20Sopenharmony_ci struct pci_dev *dev_2; 308c2ecf20Sopenharmony_ci struct pci_dev *dev_3; 318c2ecf20Sopenharmony_ci volatile u32 __iomem *aperture; 328c2ecf20Sopenharmony_ci int num_active_entries; 338c2ecf20Sopenharmony_ci off_t pg_offset; 348c2ecf20Sopenharmony_ci u32 wbc_mask; 358c2ecf20Sopenharmony_ci} nvidia_private; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_cistatic int nvidia_fetch_size(void) 398c2ecf20Sopenharmony_ci{ 408c2ecf20Sopenharmony_ci int i; 418c2ecf20Sopenharmony_ci u8 size_value; 428c2ecf20Sopenharmony_ci struct aper_size_info_8 *values; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci pci_read_config_byte(agp_bridge->dev, NVIDIA_0_APSIZE, &size_value); 458c2ecf20Sopenharmony_ci size_value &= 0x0f; 468c2ecf20Sopenharmony_ci values = A_SIZE_8(agp_bridge->driver->aperture_sizes); 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci for (i = 0; i < agp_bridge->driver->num_aperture_sizes; i++) { 498c2ecf20Sopenharmony_ci if (size_value == values[i].size_value) { 508c2ecf20Sopenharmony_ci agp_bridge->previous_size = 518c2ecf20Sopenharmony_ci agp_bridge->current_size = (void *) (values + i); 528c2ecf20Sopenharmony_ci agp_bridge->aperture_size_idx = i; 538c2ecf20Sopenharmony_ci return values[i].size; 548c2ecf20Sopenharmony_ci } 558c2ecf20Sopenharmony_ci } 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci return 0; 588c2ecf20Sopenharmony_ci} 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci#define SYSCFG 0xC0010010 618c2ecf20Sopenharmony_ci#define IORR_BASE0 0xC0010016 628c2ecf20Sopenharmony_ci#define IORR_MASK0 0xC0010017 638c2ecf20Sopenharmony_ci#define AMD_K7_NUM_IORR 2 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cistatic int nvidia_init_iorr(u32 base, u32 size) 668c2ecf20Sopenharmony_ci{ 678c2ecf20Sopenharmony_ci u32 base_hi, base_lo; 688c2ecf20Sopenharmony_ci u32 mask_hi, mask_lo; 698c2ecf20Sopenharmony_ci u32 sys_hi, sys_lo; 708c2ecf20Sopenharmony_ci u32 iorr_addr, free_iorr_addr; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci /* Find the iorr that is already used for the base */ 738c2ecf20Sopenharmony_ci /* If not found, determine the uppermost available iorr */ 748c2ecf20Sopenharmony_ci free_iorr_addr = AMD_K7_NUM_IORR; 758c2ecf20Sopenharmony_ci for (iorr_addr = 0; iorr_addr < AMD_K7_NUM_IORR; iorr_addr++) { 768c2ecf20Sopenharmony_ci rdmsr(IORR_BASE0 + 2 * iorr_addr, base_lo, base_hi); 778c2ecf20Sopenharmony_ci rdmsr(IORR_MASK0 + 2 * iorr_addr, mask_lo, mask_hi); 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci if ((base_lo & 0xfffff000) == (base & 0xfffff000)) 808c2ecf20Sopenharmony_ci break; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci if ((mask_lo & 0x00000800) == 0) 838c2ecf20Sopenharmony_ci free_iorr_addr = iorr_addr; 848c2ecf20Sopenharmony_ci } 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci if (iorr_addr >= AMD_K7_NUM_IORR) { 878c2ecf20Sopenharmony_ci iorr_addr = free_iorr_addr; 888c2ecf20Sopenharmony_ci if (iorr_addr >= AMD_K7_NUM_IORR) 898c2ecf20Sopenharmony_ci return -EINVAL; 908c2ecf20Sopenharmony_ci } 918c2ecf20Sopenharmony_ci base_hi = 0x0; 928c2ecf20Sopenharmony_ci base_lo = (base & ~0xfff) | 0x18; 938c2ecf20Sopenharmony_ci mask_hi = 0xf; 948c2ecf20Sopenharmony_ci mask_lo = ((~(size - 1)) & 0xfffff000) | 0x800; 958c2ecf20Sopenharmony_ci wrmsr(IORR_BASE0 + 2 * iorr_addr, base_lo, base_hi); 968c2ecf20Sopenharmony_ci wrmsr(IORR_MASK0 + 2 * iorr_addr, mask_lo, mask_hi); 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci rdmsr(SYSCFG, sys_lo, sys_hi); 998c2ecf20Sopenharmony_ci sys_lo |= 0x00100000; 1008c2ecf20Sopenharmony_ci wrmsr(SYSCFG, sys_lo, sys_hi); 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci return 0; 1038c2ecf20Sopenharmony_ci} 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_cistatic int nvidia_configure(void) 1068c2ecf20Sopenharmony_ci{ 1078c2ecf20Sopenharmony_ci int i, rc, num_dirs; 1088c2ecf20Sopenharmony_ci u32 apbase, aplimit; 1098c2ecf20Sopenharmony_ci phys_addr_t apbase_phys; 1108c2ecf20Sopenharmony_ci struct aper_size_info_8 *current_size; 1118c2ecf20Sopenharmony_ci u32 temp; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci current_size = A_SIZE_8(agp_bridge->current_size); 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci /* aperture size */ 1168c2ecf20Sopenharmony_ci pci_write_config_byte(agp_bridge->dev, NVIDIA_0_APSIZE, 1178c2ecf20Sopenharmony_ci current_size->size_value); 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci /* address to map to */ 1208c2ecf20Sopenharmony_ci apbase = pci_bus_address(agp_bridge->dev, AGP_APERTURE_BAR); 1218c2ecf20Sopenharmony_ci agp_bridge->gart_bus_addr = apbase; 1228c2ecf20Sopenharmony_ci aplimit = apbase + (current_size->size * 1024 * 1024) - 1; 1238c2ecf20Sopenharmony_ci pci_write_config_dword(nvidia_private.dev_2, NVIDIA_2_APBASE, apbase); 1248c2ecf20Sopenharmony_ci pci_write_config_dword(nvidia_private.dev_2, NVIDIA_2_APLIMIT, aplimit); 1258c2ecf20Sopenharmony_ci pci_write_config_dword(nvidia_private.dev_3, NVIDIA_3_APBASE, apbase); 1268c2ecf20Sopenharmony_ci pci_write_config_dword(nvidia_private.dev_3, NVIDIA_3_APLIMIT, aplimit); 1278c2ecf20Sopenharmony_ci if (0 != (rc = nvidia_init_iorr(apbase, current_size->size * 1024 * 1024))) 1288c2ecf20Sopenharmony_ci return rc; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci /* directory size is 64k */ 1318c2ecf20Sopenharmony_ci num_dirs = current_size->size / 64; 1328c2ecf20Sopenharmony_ci nvidia_private.num_active_entries = current_size->num_entries; 1338c2ecf20Sopenharmony_ci nvidia_private.pg_offset = 0; 1348c2ecf20Sopenharmony_ci if (num_dirs == 0) { 1358c2ecf20Sopenharmony_ci num_dirs = 1; 1368c2ecf20Sopenharmony_ci nvidia_private.num_active_entries /= (64 / current_size->size); 1378c2ecf20Sopenharmony_ci nvidia_private.pg_offset = (apbase & (64 * 1024 * 1024 - 1) & 1388c2ecf20Sopenharmony_ci ~(current_size->size * 1024 * 1024 - 1)) / PAGE_SIZE; 1398c2ecf20Sopenharmony_ci } 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci /* attbase */ 1428c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) { 1438c2ecf20Sopenharmony_ci pci_write_config_dword(nvidia_private.dev_2, NVIDIA_2_ATTBASE(i), 1448c2ecf20Sopenharmony_ci (agp_bridge->gatt_bus_addr + (i % num_dirs) * 64 * 1024) | 1); 1458c2ecf20Sopenharmony_ci } 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci /* gtlb control */ 1488c2ecf20Sopenharmony_ci pci_read_config_dword(nvidia_private.dev_2, NVIDIA_2_GARTCTRL, &temp); 1498c2ecf20Sopenharmony_ci pci_write_config_dword(nvidia_private.dev_2, NVIDIA_2_GARTCTRL, temp | 0x11); 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci /* gart control */ 1528c2ecf20Sopenharmony_ci pci_read_config_dword(agp_bridge->dev, NVIDIA_0_APSIZE, &temp); 1538c2ecf20Sopenharmony_ci pci_write_config_dword(agp_bridge->dev, NVIDIA_0_APSIZE, temp | 0x100); 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci /* map aperture */ 1568c2ecf20Sopenharmony_ci apbase_phys = pci_resource_start(agp_bridge->dev, AGP_APERTURE_BAR); 1578c2ecf20Sopenharmony_ci nvidia_private.aperture = 1588c2ecf20Sopenharmony_ci (volatile u32 __iomem *) ioremap(apbase_phys, 33 * PAGE_SIZE); 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci if (!nvidia_private.aperture) 1618c2ecf20Sopenharmony_ci return -ENOMEM; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci return 0; 1648c2ecf20Sopenharmony_ci} 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_cistatic void nvidia_cleanup(void) 1678c2ecf20Sopenharmony_ci{ 1688c2ecf20Sopenharmony_ci struct aper_size_info_8 *previous_size; 1698c2ecf20Sopenharmony_ci u32 temp; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci /* gart control */ 1728c2ecf20Sopenharmony_ci pci_read_config_dword(agp_bridge->dev, NVIDIA_0_APSIZE, &temp); 1738c2ecf20Sopenharmony_ci pci_write_config_dword(agp_bridge->dev, NVIDIA_0_APSIZE, temp & ~(0x100)); 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci /* gtlb control */ 1768c2ecf20Sopenharmony_ci pci_read_config_dword(nvidia_private.dev_2, NVIDIA_2_GARTCTRL, &temp); 1778c2ecf20Sopenharmony_ci pci_write_config_dword(nvidia_private.dev_2, NVIDIA_2_GARTCTRL, temp & ~(0x11)); 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci /* unmap aperture */ 1808c2ecf20Sopenharmony_ci iounmap((void __iomem *) nvidia_private.aperture); 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci /* restore previous aperture size */ 1838c2ecf20Sopenharmony_ci previous_size = A_SIZE_8(agp_bridge->previous_size); 1848c2ecf20Sopenharmony_ci pci_write_config_byte(agp_bridge->dev, NVIDIA_0_APSIZE, 1858c2ecf20Sopenharmony_ci previous_size->size_value); 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci /* restore iorr for previous aperture size */ 1888c2ecf20Sopenharmony_ci nvidia_init_iorr(agp_bridge->gart_bus_addr, 1898c2ecf20Sopenharmony_ci previous_size->size * 1024 * 1024); 1908c2ecf20Sopenharmony_ci} 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci/* 1948c2ecf20Sopenharmony_ci * Note we can't use the generic routines, even though they are 99% the same. 1958c2ecf20Sopenharmony_ci * Aperture sizes <64M still requires a full 64k GART directory, but 1968c2ecf20Sopenharmony_ci * only use the portion of the TLB entries that correspond to the apertures 1978c2ecf20Sopenharmony_ci * alignment inside the surrounding 64M block. 1988c2ecf20Sopenharmony_ci */ 1998c2ecf20Sopenharmony_ciextern int agp_memory_reserved; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_cistatic int nvidia_insert_memory(struct agp_memory *mem, off_t pg_start, int type) 2028c2ecf20Sopenharmony_ci{ 2038c2ecf20Sopenharmony_ci int i, j; 2048c2ecf20Sopenharmony_ci int mask_type; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci mask_type = agp_generic_type_to_mask_type(mem->bridge, type); 2078c2ecf20Sopenharmony_ci if (mask_type != 0 || type != mem->type) 2088c2ecf20Sopenharmony_ci return -EINVAL; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci if (mem->page_count == 0) 2118c2ecf20Sopenharmony_ci return 0; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci if ((pg_start + mem->page_count) > 2148c2ecf20Sopenharmony_ci (nvidia_private.num_active_entries - agp_memory_reserved/PAGE_SIZE)) 2158c2ecf20Sopenharmony_ci return -EINVAL; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci for (j = pg_start; j < (pg_start + mem->page_count); j++) { 2188c2ecf20Sopenharmony_ci if (!PGE_EMPTY(agp_bridge, readl(agp_bridge->gatt_table+nvidia_private.pg_offset+j))) 2198c2ecf20Sopenharmony_ci return -EBUSY; 2208c2ecf20Sopenharmony_ci } 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci if (!mem->is_flushed) { 2238c2ecf20Sopenharmony_ci global_cache_flush(); 2248c2ecf20Sopenharmony_ci mem->is_flushed = true; 2258c2ecf20Sopenharmony_ci } 2268c2ecf20Sopenharmony_ci for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { 2278c2ecf20Sopenharmony_ci writel(agp_bridge->driver->mask_memory(agp_bridge, 2288c2ecf20Sopenharmony_ci page_to_phys(mem->pages[i]), mask_type), 2298c2ecf20Sopenharmony_ci agp_bridge->gatt_table+nvidia_private.pg_offset+j); 2308c2ecf20Sopenharmony_ci } 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci /* PCI Posting. */ 2338c2ecf20Sopenharmony_ci readl(agp_bridge->gatt_table+nvidia_private.pg_offset+j - 1); 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci agp_bridge->driver->tlb_flush(mem); 2368c2ecf20Sopenharmony_ci return 0; 2378c2ecf20Sopenharmony_ci} 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_cistatic int nvidia_remove_memory(struct agp_memory *mem, off_t pg_start, int type) 2418c2ecf20Sopenharmony_ci{ 2428c2ecf20Sopenharmony_ci int i; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci int mask_type; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci mask_type = agp_generic_type_to_mask_type(mem->bridge, type); 2478c2ecf20Sopenharmony_ci if (mask_type != 0 || type != mem->type) 2488c2ecf20Sopenharmony_ci return -EINVAL; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci if (mem->page_count == 0) 2518c2ecf20Sopenharmony_ci return 0; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci for (i = pg_start; i < (mem->page_count + pg_start); i++) 2548c2ecf20Sopenharmony_ci writel(agp_bridge->scratch_page, agp_bridge->gatt_table+nvidia_private.pg_offset+i); 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci agp_bridge->driver->tlb_flush(mem); 2578c2ecf20Sopenharmony_ci return 0; 2588c2ecf20Sopenharmony_ci} 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_cistatic void nvidia_tlbflush(struct agp_memory *mem) 2628c2ecf20Sopenharmony_ci{ 2638c2ecf20Sopenharmony_ci unsigned long end; 2648c2ecf20Sopenharmony_ci u32 wbc_reg, temp; 2658c2ecf20Sopenharmony_ci int i; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci /* flush chipset */ 2688c2ecf20Sopenharmony_ci if (nvidia_private.wbc_mask) { 2698c2ecf20Sopenharmony_ci pci_read_config_dword(nvidia_private.dev_1, NVIDIA_1_WBC, &wbc_reg); 2708c2ecf20Sopenharmony_ci wbc_reg |= nvidia_private.wbc_mask; 2718c2ecf20Sopenharmony_ci pci_write_config_dword(nvidia_private.dev_1, NVIDIA_1_WBC, wbc_reg); 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci end = jiffies + 3*HZ; 2748c2ecf20Sopenharmony_ci do { 2758c2ecf20Sopenharmony_ci pci_read_config_dword(nvidia_private.dev_1, 2768c2ecf20Sopenharmony_ci NVIDIA_1_WBC, &wbc_reg); 2778c2ecf20Sopenharmony_ci if (time_before_eq(end, jiffies)) { 2788c2ecf20Sopenharmony_ci printk(KERN_ERR PFX 2798c2ecf20Sopenharmony_ci "TLB flush took more than 3 seconds.\n"); 2808c2ecf20Sopenharmony_ci } 2818c2ecf20Sopenharmony_ci } while (wbc_reg & nvidia_private.wbc_mask); 2828c2ecf20Sopenharmony_ci } 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci /* flush TLB entries */ 2858c2ecf20Sopenharmony_ci for (i = 0; i < 32 + 1; i++) 2868c2ecf20Sopenharmony_ci temp = readl(nvidia_private.aperture+(i * PAGE_SIZE / sizeof(u32))); 2878c2ecf20Sopenharmony_ci for (i = 0; i < 32 + 1; i++) 2888c2ecf20Sopenharmony_ci temp = readl(nvidia_private.aperture+(i * PAGE_SIZE / sizeof(u32))); 2898c2ecf20Sopenharmony_ci} 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_cistatic const struct aper_size_info_8 nvidia_generic_sizes[5] = 2938c2ecf20Sopenharmony_ci{ 2948c2ecf20Sopenharmony_ci {512, 131072, 7, 0}, 2958c2ecf20Sopenharmony_ci {256, 65536, 6, 8}, 2968c2ecf20Sopenharmony_ci {128, 32768, 5, 12}, 2978c2ecf20Sopenharmony_ci {64, 16384, 4, 14}, 2988c2ecf20Sopenharmony_ci /* The 32M mode still requires a 64k gatt */ 2998c2ecf20Sopenharmony_ci {32, 16384, 4, 15} 3008c2ecf20Sopenharmony_ci}; 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_cistatic const struct gatt_mask nvidia_generic_masks[] = 3048c2ecf20Sopenharmony_ci{ 3058c2ecf20Sopenharmony_ci { .mask = 1, .type = 0} 3068c2ecf20Sopenharmony_ci}; 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_cistatic const struct agp_bridge_driver nvidia_driver = { 3108c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 3118c2ecf20Sopenharmony_ci .aperture_sizes = nvidia_generic_sizes, 3128c2ecf20Sopenharmony_ci .size_type = U8_APER_SIZE, 3138c2ecf20Sopenharmony_ci .num_aperture_sizes = 5, 3148c2ecf20Sopenharmony_ci .needs_scratch_page = true, 3158c2ecf20Sopenharmony_ci .configure = nvidia_configure, 3168c2ecf20Sopenharmony_ci .fetch_size = nvidia_fetch_size, 3178c2ecf20Sopenharmony_ci .cleanup = nvidia_cleanup, 3188c2ecf20Sopenharmony_ci .tlb_flush = nvidia_tlbflush, 3198c2ecf20Sopenharmony_ci .mask_memory = agp_generic_mask_memory, 3208c2ecf20Sopenharmony_ci .masks = nvidia_generic_masks, 3218c2ecf20Sopenharmony_ci .agp_enable = agp_generic_enable, 3228c2ecf20Sopenharmony_ci .cache_flush = global_cache_flush, 3238c2ecf20Sopenharmony_ci .create_gatt_table = agp_generic_create_gatt_table, 3248c2ecf20Sopenharmony_ci .free_gatt_table = agp_generic_free_gatt_table, 3258c2ecf20Sopenharmony_ci .insert_memory = nvidia_insert_memory, 3268c2ecf20Sopenharmony_ci .remove_memory = nvidia_remove_memory, 3278c2ecf20Sopenharmony_ci .alloc_by_type = agp_generic_alloc_by_type, 3288c2ecf20Sopenharmony_ci .free_by_type = agp_generic_free_by_type, 3298c2ecf20Sopenharmony_ci .agp_alloc_page = agp_generic_alloc_page, 3308c2ecf20Sopenharmony_ci .agp_alloc_pages = agp_generic_alloc_pages, 3318c2ecf20Sopenharmony_ci .agp_destroy_page = agp_generic_destroy_page, 3328c2ecf20Sopenharmony_ci .agp_destroy_pages = agp_generic_destroy_pages, 3338c2ecf20Sopenharmony_ci .agp_type_to_mask_type = agp_generic_type_to_mask_type, 3348c2ecf20Sopenharmony_ci}; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_cistatic int agp_nvidia_probe(struct pci_dev *pdev, 3378c2ecf20Sopenharmony_ci const struct pci_device_id *ent) 3388c2ecf20Sopenharmony_ci{ 3398c2ecf20Sopenharmony_ci struct agp_bridge_data *bridge; 3408c2ecf20Sopenharmony_ci u8 cap_ptr; 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci nvidia_private.dev_1 = 3438c2ecf20Sopenharmony_ci pci_get_domain_bus_and_slot(pci_domain_nr(pdev->bus), 3448c2ecf20Sopenharmony_ci (unsigned int)pdev->bus->number, 3458c2ecf20Sopenharmony_ci PCI_DEVFN(0, 1)); 3468c2ecf20Sopenharmony_ci nvidia_private.dev_2 = 3478c2ecf20Sopenharmony_ci pci_get_domain_bus_and_slot(pci_domain_nr(pdev->bus), 3488c2ecf20Sopenharmony_ci (unsigned int)pdev->bus->number, 3498c2ecf20Sopenharmony_ci PCI_DEVFN(0, 2)); 3508c2ecf20Sopenharmony_ci nvidia_private.dev_3 = 3518c2ecf20Sopenharmony_ci pci_get_domain_bus_and_slot(pci_domain_nr(pdev->bus), 3528c2ecf20Sopenharmony_ci (unsigned int)pdev->bus->number, 3538c2ecf20Sopenharmony_ci PCI_DEVFN(30, 0)); 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci if (!nvidia_private.dev_1 || !nvidia_private.dev_2 || !nvidia_private.dev_3) { 3568c2ecf20Sopenharmony_ci printk(KERN_INFO PFX "Detected an NVIDIA nForce/nForce2 " 3578c2ecf20Sopenharmony_ci "chipset, but could not find the secondary devices.\n"); 3588c2ecf20Sopenharmony_ci return -ENODEV; 3598c2ecf20Sopenharmony_ci } 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP); 3628c2ecf20Sopenharmony_ci if (!cap_ptr) 3638c2ecf20Sopenharmony_ci return -ENODEV; 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci switch (pdev->device) { 3668c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_NVIDIA_NFORCE: 3678c2ecf20Sopenharmony_ci printk(KERN_INFO PFX "Detected NVIDIA nForce chipset\n"); 3688c2ecf20Sopenharmony_ci nvidia_private.wbc_mask = 0x00010000; 3698c2ecf20Sopenharmony_ci break; 3708c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_NVIDIA_NFORCE2: 3718c2ecf20Sopenharmony_ci printk(KERN_INFO PFX "Detected NVIDIA nForce2 chipset\n"); 3728c2ecf20Sopenharmony_ci nvidia_private.wbc_mask = 0x80000000; 3738c2ecf20Sopenharmony_ci break; 3748c2ecf20Sopenharmony_ci default: 3758c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "Unsupported NVIDIA chipset (device id: %04x)\n", 3768c2ecf20Sopenharmony_ci pdev->device); 3778c2ecf20Sopenharmony_ci return -ENODEV; 3788c2ecf20Sopenharmony_ci } 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci bridge = agp_alloc_bridge(); 3818c2ecf20Sopenharmony_ci if (!bridge) 3828c2ecf20Sopenharmony_ci return -ENOMEM; 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci bridge->driver = &nvidia_driver; 3858c2ecf20Sopenharmony_ci bridge->dev_private_data = &nvidia_private; 3868c2ecf20Sopenharmony_ci bridge->dev = pdev; 3878c2ecf20Sopenharmony_ci bridge->capndx = cap_ptr; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci /* Fill in the mode register */ 3908c2ecf20Sopenharmony_ci pci_read_config_dword(pdev, 3918c2ecf20Sopenharmony_ci bridge->capndx+PCI_AGP_STATUS, 3928c2ecf20Sopenharmony_ci &bridge->mode); 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, bridge); 3958c2ecf20Sopenharmony_ci return agp_add_bridge(bridge); 3968c2ecf20Sopenharmony_ci} 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_cistatic void agp_nvidia_remove(struct pci_dev *pdev) 3998c2ecf20Sopenharmony_ci{ 4008c2ecf20Sopenharmony_ci struct agp_bridge_data *bridge = pci_get_drvdata(pdev); 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci agp_remove_bridge(bridge); 4038c2ecf20Sopenharmony_ci agp_put_bridge(bridge); 4048c2ecf20Sopenharmony_ci} 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 4078c2ecf20Sopenharmony_cistatic int agp_nvidia_suspend(struct pci_dev *pdev, pm_message_t state) 4088c2ecf20Sopenharmony_ci{ 4098c2ecf20Sopenharmony_ci pci_save_state(pdev); 4108c2ecf20Sopenharmony_ci pci_set_power_state(pdev, PCI_D3hot); 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci return 0; 4138c2ecf20Sopenharmony_ci} 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_cistatic int agp_nvidia_resume(struct pci_dev *pdev) 4168c2ecf20Sopenharmony_ci{ 4178c2ecf20Sopenharmony_ci /* set power state 0 and restore PCI space */ 4188c2ecf20Sopenharmony_ci pci_set_power_state(pdev, PCI_D0); 4198c2ecf20Sopenharmony_ci pci_restore_state(pdev); 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci /* reconfigure AGP hardware again */ 4228c2ecf20Sopenharmony_ci nvidia_configure(); 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci return 0; 4258c2ecf20Sopenharmony_ci} 4268c2ecf20Sopenharmony_ci#endif 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_cistatic const struct pci_device_id agp_nvidia_pci_table[] = { 4308c2ecf20Sopenharmony_ci { 4318c2ecf20Sopenharmony_ci .class = (PCI_CLASS_BRIDGE_HOST << 8), 4328c2ecf20Sopenharmony_ci .class_mask = ~0, 4338c2ecf20Sopenharmony_ci .vendor = PCI_VENDOR_ID_NVIDIA, 4348c2ecf20Sopenharmony_ci .device = PCI_DEVICE_ID_NVIDIA_NFORCE, 4358c2ecf20Sopenharmony_ci .subvendor = PCI_ANY_ID, 4368c2ecf20Sopenharmony_ci .subdevice = PCI_ANY_ID, 4378c2ecf20Sopenharmony_ci }, 4388c2ecf20Sopenharmony_ci { 4398c2ecf20Sopenharmony_ci .class = (PCI_CLASS_BRIDGE_HOST << 8), 4408c2ecf20Sopenharmony_ci .class_mask = ~0, 4418c2ecf20Sopenharmony_ci .vendor = PCI_VENDOR_ID_NVIDIA, 4428c2ecf20Sopenharmony_ci .device = PCI_DEVICE_ID_NVIDIA_NFORCE2, 4438c2ecf20Sopenharmony_ci .subvendor = PCI_ANY_ID, 4448c2ecf20Sopenharmony_ci .subdevice = PCI_ANY_ID, 4458c2ecf20Sopenharmony_ci }, 4468c2ecf20Sopenharmony_ci { } 4478c2ecf20Sopenharmony_ci}; 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, agp_nvidia_pci_table); 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_cistatic struct pci_driver agp_nvidia_pci_driver = { 4528c2ecf20Sopenharmony_ci .name = "agpgart-nvidia", 4538c2ecf20Sopenharmony_ci .id_table = agp_nvidia_pci_table, 4548c2ecf20Sopenharmony_ci .probe = agp_nvidia_probe, 4558c2ecf20Sopenharmony_ci .remove = agp_nvidia_remove, 4568c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 4578c2ecf20Sopenharmony_ci .suspend = agp_nvidia_suspend, 4588c2ecf20Sopenharmony_ci .resume = agp_nvidia_resume, 4598c2ecf20Sopenharmony_ci#endif 4608c2ecf20Sopenharmony_ci}; 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_cistatic int __init agp_nvidia_init(void) 4638c2ecf20Sopenharmony_ci{ 4648c2ecf20Sopenharmony_ci if (agp_off) 4658c2ecf20Sopenharmony_ci return -EINVAL; 4668c2ecf20Sopenharmony_ci return pci_register_driver(&agp_nvidia_pci_driver); 4678c2ecf20Sopenharmony_ci} 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_cistatic void __exit agp_nvidia_cleanup(void) 4708c2ecf20Sopenharmony_ci{ 4718c2ecf20Sopenharmony_ci pci_unregister_driver(&agp_nvidia_pci_driver); 4728c2ecf20Sopenharmony_ci pci_dev_put(nvidia_private.dev_1); 4738c2ecf20Sopenharmony_ci pci_dev_put(nvidia_private.dev_2); 4748c2ecf20Sopenharmony_ci pci_dev_put(nvidia_private.dev_3); 4758c2ecf20Sopenharmony_ci} 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_cimodule_init(agp_nvidia_init); 4788c2ecf20Sopenharmony_cimodule_exit(agp_nvidia_cleanup); 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL and additional rights"); 4818c2ecf20Sopenharmony_ciMODULE_AUTHOR("NVIDIA Corporation"); 4828c2ecf20Sopenharmony_ci 483