162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Transmeta's Efficeon AGPGART driver. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Based upon a diff by Linus around November '02. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Ported to the 2.6 kernel by Carlos Puchol <cpglinux@puchol.com> 762306a36Sopenharmony_ci * and H. Peter Anvin <hpa@transmeta.com>. 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci/* 1162306a36Sopenharmony_ci * NOTE-cpg-040217: 1262306a36Sopenharmony_ci * 1362306a36Sopenharmony_ci * - when compiled as a module, after loading the module, 1462306a36Sopenharmony_ci * it will refuse to unload, indicating it is in use, 1562306a36Sopenharmony_ci * when it is not. 1662306a36Sopenharmony_ci * - no s3 (suspend to ram) testing. 1762306a36Sopenharmony_ci * - tested on the efficeon integrated nothbridge for tens 1862306a36Sopenharmony_ci * of iterations of starting x and glxgears. 1962306a36Sopenharmony_ci * - tested with radeon 9000 and radeon mobility m9 cards 2062306a36Sopenharmony_ci * - tested with c3/c4 enabled (with the mobility m9 card) 2162306a36Sopenharmony_ci */ 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#include <linux/module.h> 2462306a36Sopenharmony_ci#include <linux/pci.h> 2562306a36Sopenharmony_ci#include <linux/init.h> 2662306a36Sopenharmony_ci#include <linux/agp_backend.h> 2762306a36Sopenharmony_ci#include <linux/gfp.h> 2862306a36Sopenharmony_ci#include <linux/page-flags.h> 2962306a36Sopenharmony_ci#include <linux/mm.h> 3062306a36Sopenharmony_ci#include "agp.h" 3162306a36Sopenharmony_ci#include "intel-agp.h" 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci/* 3462306a36Sopenharmony_ci * The real differences to the generic AGP code is 3562306a36Sopenharmony_ci * in the GART mappings - a two-level setup with the 3662306a36Sopenharmony_ci * first level being an on-chip 64-entry table. 3762306a36Sopenharmony_ci * 3862306a36Sopenharmony_ci * The page array is filled through the ATTPAGE register 3962306a36Sopenharmony_ci * (Aperture Translation Table Page Register) at 0xB8. Bits: 4062306a36Sopenharmony_ci * 31:20: physical page address 4162306a36Sopenharmony_ci * 11:9: Page Attribute Table Index (PATI) 4262306a36Sopenharmony_ci * must match the PAT index for the 4362306a36Sopenharmony_ci * mapped pages (the 2nd level page table pages 4462306a36Sopenharmony_ci * themselves should be just regular WB-cacheable, 4562306a36Sopenharmony_ci * so this is normally zero.) 4662306a36Sopenharmony_ci * 8: Present 4762306a36Sopenharmony_ci * 7:6: reserved, write as zero 4862306a36Sopenharmony_ci * 5:0: GATT directory index: which 1st-level entry 4962306a36Sopenharmony_ci * 5062306a36Sopenharmony_ci * The Efficeon AGP spec requires pages to be WB-cacheable 5162306a36Sopenharmony_ci * but to be explicitly CLFLUSH'd after any changes. 5262306a36Sopenharmony_ci */ 5362306a36Sopenharmony_ci#define EFFICEON_ATTPAGE 0xb8 5462306a36Sopenharmony_ci#define EFFICEON_L1_SIZE 64 /* Number of PDE pages */ 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci#define EFFICEON_PATI (0 << 9) 5762306a36Sopenharmony_ci#define EFFICEON_PRESENT (1 << 8) 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_cistatic struct _efficeon_private { 6062306a36Sopenharmony_ci unsigned long l1_table[EFFICEON_L1_SIZE]; 6162306a36Sopenharmony_ci} efficeon_private; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_cistatic const struct gatt_mask efficeon_generic_masks[] = 6462306a36Sopenharmony_ci{ 6562306a36Sopenharmony_ci {.mask = 0x00000001, .type = 0} 6662306a36Sopenharmony_ci}; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci/* This function does the same thing as mask_memory() for this chipset... */ 6962306a36Sopenharmony_cistatic inline unsigned long efficeon_mask_memory(struct page *page) 7062306a36Sopenharmony_ci{ 7162306a36Sopenharmony_ci unsigned long addr = page_to_phys(page); 7262306a36Sopenharmony_ci return addr | 0x00000001; 7362306a36Sopenharmony_ci} 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_cistatic const struct aper_size_info_lvl2 efficeon_generic_sizes[4] = 7662306a36Sopenharmony_ci{ 7762306a36Sopenharmony_ci {256, 65536, 0}, 7862306a36Sopenharmony_ci {128, 32768, 32}, 7962306a36Sopenharmony_ci {64, 16384, 48}, 8062306a36Sopenharmony_ci {32, 8192, 56} 8162306a36Sopenharmony_ci}; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci/* 8462306a36Sopenharmony_ci * Control interfaces are largely identical to 8562306a36Sopenharmony_ci * the legacy Intel 440BX.. 8662306a36Sopenharmony_ci */ 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_cistatic int efficeon_fetch_size(void) 8962306a36Sopenharmony_ci{ 9062306a36Sopenharmony_ci int i; 9162306a36Sopenharmony_ci u16 temp; 9262306a36Sopenharmony_ci struct aper_size_info_lvl2 *values; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci pci_read_config_word(agp_bridge->dev, INTEL_APSIZE, &temp); 9562306a36Sopenharmony_ci values = A_SIZE_LVL2(agp_bridge->driver->aperture_sizes); 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci for (i = 0; i < agp_bridge->driver->num_aperture_sizes; i++) { 9862306a36Sopenharmony_ci if (temp == values[i].size_value) { 9962306a36Sopenharmony_ci agp_bridge->previous_size = 10062306a36Sopenharmony_ci agp_bridge->current_size = (void *) (values + i); 10162306a36Sopenharmony_ci agp_bridge->aperture_size_idx = i; 10262306a36Sopenharmony_ci return values[i].size; 10362306a36Sopenharmony_ci } 10462306a36Sopenharmony_ci } 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci return 0; 10762306a36Sopenharmony_ci} 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_cistatic void efficeon_tlbflush(struct agp_memory * mem) 11062306a36Sopenharmony_ci{ 11162306a36Sopenharmony_ci printk(KERN_DEBUG PFX "efficeon_tlbflush()\n"); 11262306a36Sopenharmony_ci pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, 0x2200); 11362306a36Sopenharmony_ci pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, 0x2280); 11462306a36Sopenharmony_ci} 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_cistatic void efficeon_cleanup(void) 11762306a36Sopenharmony_ci{ 11862306a36Sopenharmony_ci u16 temp; 11962306a36Sopenharmony_ci struct aper_size_info_lvl2 *previous_size; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci printk(KERN_DEBUG PFX "efficeon_cleanup()\n"); 12262306a36Sopenharmony_ci previous_size = A_SIZE_LVL2(agp_bridge->previous_size); 12362306a36Sopenharmony_ci pci_read_config_word(agp_bridge->dev, INTEL_NBXCFG, &temp); 12462306a36Sopenharmony_ci pci_write_config_word(agp_bridge->dev, INTEL_NBXCFG, temp & ~(1 << 9)); 12562306a36Sopenharmony_ci pci_write_config_word(agp_bridge->dev, INTEL_APSIZE, 12662306a36Sopenharmony_ci previous_size->size_value); 12762306a36Sopenharmony_ci} 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_cistatic int efficeon_configure(void) 13062306a36Sopenharmony_ci{ 13162306a36Sopenharmony_ci u16 temp2; 13262306a36Sopenharmony_ci struct aper_size_info_lvl2 *current_size; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci printk(KERN_DEBUG PFX "efficeon_configure()\n"); 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci current_size = A_SIZE_LVL2(agp_bridge->current_size); 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci /* aperture size */ 13962306a36Sopenharmony_ci pci_write_config_word(agp_bridge->dev, INTEL_APSIZE, 14062306a36Sopenharmony_ci current_size->size_value); 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci /* address to map to */ 14362306a36Sopenharmony_ci agp_bridge->gart_bus_addr = pci_bus_address(agp_bridge->dev, 14462306a36Sopenharmony_ci AGP_APERTURE_BAR); 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci /* agpctrl */ 14762306a36Sopenharmony_ci pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, 0x2280); 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci /* paccfg/nbxcfg */ 15062306a36Sopenharmony_ci pci_read_config_word(agp_bridge->dev, INTEL_NBXCFG, &temp2); 15162306a36Sopenharmony_ci pci_write_config_word(agp_bridge->dev, INTEL_NBXCFG, 15262306a36Sopenharmony_ci (temp2 & ~(1 << 10)) | (1 << 9) | (1 << 11)); 15362306a36Sopenharmony_ci /* clear any possible error conditions */ 15462306a36Sopenharmony_ci pci_write_config_byte(agp_bridge->dev, INTEL_ERRSTS + 1, 7); 15562306a36Sopenharmony_ci return 0; 15662306a36Sopenharmony_ci} 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_cistatic int efficeon_free_gatt_table(struct agp_bridge_data *bridge) 15962306a36Sopenharmony_ci{ 16062306a36Sopenharmony_ci int index, freed = 0; 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci for (index = 0; index < EFFICEON_L1_SIZE; index++) { 16362306a36Sopenharmony_ci unsigned long page = efficeon_private.l1_table[index]; 16462306a36Sopenharmony_ci if (page) { 16562306a36Sopenharmony_ci efficeon_private.l1_table[index] = 0; 16662306a36Sopenharmony_ci free_page(page); 16762306a36Sopenharmony_ci freed++; 16862306a36Sopenharmony_ci } 16962306a36Sopenharmony_ci printk(KERN_DEBUG PFX "efficeon_free_gatt_table(%p, %02x, %08x)\n", 17062306a36Sopenharmony_ci agp_bridge->dev, EFFICEON_ATTPAGE, index); 17162306a36Sopenharmony_ci pci_write_config_dword(agp_bridge->dev, 17262306a36Sopenharmony_ci EFFICEON_ATTPAGE, index); 17362306a36Sopenharmony_ci } 17462306a36Sopenharmony_ci printk(KERN_DEBUG PFX "efficeon_free_gatt_table() freed %d pages\n", freed); 17562306a36Sopenharmony_ci return 0; 17662306a36Sopenharmony_ci} 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci/* 18062306a36Sopenharmony_ci * Since we don't need contiguous memory we just try 18162306a36Sopenharmony_ci * to get the gatt table once 18262306a36Sopenharmony_ci */ 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci#define GET_PAGE_DIR_OFF(addr) (addr >> 22) 18562306a36Sopenharmony_ci#define GET_PAGE_DIR_IDX(addr) (GET_PAGE_DIR_OFF(addr) - \ 18662306a36Sopenharmony_ci GET_PAGE_DIR_OFF(agp_bridge->gart_bus_addr)) 18762306a36Sopenharmony_ci#define GET_GATT_OFF(addr) ((addr & 0x003ff000) >> 12) 18862306a36Sopenharmony_ci#undef GET_GATT 18962306a36Sopenharmony_ci#define GET_GATT(addr) (efficeon_private.gatt_pages[\ 19062306a36Sopenharmony_ci GET_PAGE_DIR_IDX(addr)]->remapped) 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_cistatic int efficeon_create_gatt_table(struct agp_bridge_data *bridge) 19362306a36Sopenharmony_ci{ 19462306a36Sopenharmony_ci int index; 19562306a36Sopenharmony_ci const int pati = EFFICEON_PATI; 19662306a36Sopenharmony_ci const int present = EFFICEON_PRESENT; 19762306a36Sopenharmony_ci const int clflush_chunk = ((cpuid_ebx(1) >> 8) & 0xff) << 3; 19862306a36Sopenharmony_ci int num_entries, l1_pages; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci num_entries = A_SIZE_LVL2(agp_bridge->current_size)->num_entries; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci printk(KERN_DEBUG PFX "efficeon_create_gatt_table(%d)\n", num_entries); 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci /* There are 2^10 PTE pages per PDE page */ 20562306a36Sopenharmony_ci BUG_ON(num_entries & 0x3ff); 20662306a36Sopenharmony_ci l1_pages = num_entries >> 10; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci for (index = 0 ; index < l1_pages ; index++) { 20962306a36Sopenharmony_ci int offset; 21062306a36Sopenharmony_ci unsigned long page; 21162306a36Sopenharmony_ci unsigned long value; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci page = efficeon_private.l1_table[index]; 21462306a36Sopenharmony_ci BUG_ON(page); 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci page = get_zeroed_page(GFP_KERNEL); 21762306a36Sopenharmony_ci if (!page) { 21862306a36Sopenharmony_ci efficeon_free_gatt_table(agp_bridge); 21962306a36Sopenharmony_ci return -ENOMEM; 22062306a36Sopenharmony_ci } 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci for (offset = 0; offset < PAGE_SIZE; offset += clflush_chunk) 22362306a36Sopenharmony_ci clflush((char *)page+offset); 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci efficeon_private.l1_table[index] = page; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci value = virt_to_phys((unsigned long *)page) | pati | present | index; 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci pci_write_config_dword(agp_bridge->dev, 23062306a36Sopenharmony_ci EFFICEON_ATTPAGE, value); 23162306a36Sopenharmony_ci } 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci return 0; 23462306a36Sopenharmony_ci} 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_cistatic int efficeon_insert_memory(struct agp_memory * mem, off_t pg_start, int type) 23762306a36Sopenharmony_ci{ 23862306a36Sopenharmony_ci int i, count = mem->page_count, num_entries; 23962306a36Sopenharmony_ci unsigned int *page, *last_page; 24062306a36Sopenharmony_ci const int clflush_chunk = ((cpuid_ebx(1) >> 8) & 0xff) << 3; 24162306a36Sopenharmony_ci const unsigned long clflush_mask = ~(clflush_chunk-1); 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci printk(KERN_DEBUG PFX "efficeon_insert_memory(%lx, %d)\n", pg_start, count); 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci num_entries = A_SIZE_LVL2(agp_bridge->current_size)->num_entries; 24662306a36Sopenharmony_ci if ((pg_start + mem->page_count) > num_entries) 24762306a36Sopenharmony_ci return -EINVAL; 24862306a36Sopenharmony_ci if (type != 0 || mem->type != 0) 24962306a36Sopenharmony_ci return -EINVAL; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci if (!mem->is_flushed) { 25262306a36Sopenharmony_ci global_cache_flush(); 25362306a36Sopenharmony_ci mem->is_flushed = true; 25462306a36Sopenharmony_ci } 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci last_page = NULL; 25762306a36Sopenharmony_ci for (i = 0; i < count; i++) { 25862306a36Sopenharmony_ci int index = pg_start + i; 25962306a36Sopenharmony_ci unsigned long insert = efficeon_mask_memory(mem->pages[i]); 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci page = (unsigned int *) efficeon_private.l1_table[index >> 10]; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci if (!page) 26462306a36Sopenharmony_ci continue; 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci page += (index & 0x3ff); 26762306a36Sopenharmony_ci *page = insert; 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci /* clflush is slow, so don't clflush until we have to */ 27062306a36Sopenharmony_ci if (last_page && 27162306a36Sopenharmony_ci (((unsigned long)page^(unsigned long)last_page) & 27262306a36Sopenharmony_ci clflush_mask)) 27362306a36Sopenharmony_ci clflush(last_page); 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci last_page = page; 27662306a36Sopenharmony_ci } 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci if ( last_page ) 27962306a36Sopenharmony_ci clflush(last_page); 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci agp_bridge->driver->tlb_flush(mem); 28262306a36Sopenharmony_ci return 0; 28362306a36Sopenharmony_ci} 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_cistatic int efficeon_remove_memory(struct agp_memory * mem, off_t pg_start, int type) 28662306a36Sopenharmony_ci{ 28762306a36Sopenharmony_ci int i, count = mem->page_count, num_entries; 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci printk(KERN_DEBUG PFX "efficeon_remove_memory(%lx, %d)\n", pg_start, count); 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci num_entries = A_SIZE_LVL2(agp_bridge->current_size)->num_entries; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci if ((pg_start + mem->page_count) > num_entries) 29462306a36Sopenharmony_ci return -EINVAL; 29562306a36Sopenharmony_ci if (type != 0 || mem->type != 0) 29662306a36Sopenharmony_ci return -EINVAL; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci for (i = 0; i < count; i++) { 29962306a36Sopenharmony_ci int index = pg_start + i; 30062306a36Sopenharmony_ci unsigned int *page = (unsigned int *) efficeon_private.l1_table[index >> 10]; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci if (!page) 30362306a36Sopenharmony_ci continue; 30462306a36Sopenharmony_ci page += (index & 0x3ff); 30562306a36Sopenharmony_ci *page = 0; 30662306a36Sopenharmony_ci } 30762306a36Sopenharmony_ci agp_bridge->driver->tlb_flush(mem); 30862306a36Sopenharmony_ci return 0; 30962306a36Sopenharmony_ci} 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_cistatic const struct agp_bridge_driver efficeon_driver = { 31362306a36Sopenharmony_ci .owner = THIS_MODULE, 31462306a36Sopenharmony_ci .aperture_sizes = efficeon_generic_sizes, 31562306a36Sopenharmony_ci .size_type = LVL2_APER_SIZE, 31662306a36Sopenharmony_ci .num_aperture_sizes = 4, 31762306a36Sopenharmony_ci .configure = efficeon_configure, 31862306a36Sopenharmony_ci .fetch_size = efficeon_fetch_size, 31962306a36Sopenharmony_ci .cleanup = efficeon_cleanup, 32062306a36Sopenharmony_ci .tlb_flush = efficeon_tlbflush, 32162306a36Sopenharmony_ci .mask_memory = agp_generic_mask_memory, 32262306a36Sopenharmony_ci .masks = efficeon_generic_masks, 32362306a36Sopenharmony_ci .agp_enable = agp_generic_enable, 32462306a36Sopenharmony_ci .cache_flush = global_cache_flush, 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci // Efficeon-specific GATT table setup / populate / teardown 32762306a36Sopenharmony_ci .create_gatt_table = efficeon_create_gatt_table, 32862306a36Sopenharmony_ci .free_gatt_table = efficeon_free_gatt_table, 32962306a36Sopenharmony_ci .insert_memory = efficeon_insert_memory, 33062306a36Sopenharmony_ci .remove_memory = efficeon_remove_memory, 33162306a36Sopenharmony_ci .cant_use_aperture = false, // true might be faster? 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci // Generic 33462306a36Sopenharmony_ci .alloc_by_type = agp_generic_alloc_by_type, 33562306a36Sopenharmony_ci .free_by_type = agp_generic_free_by_type, 33662306a36Sopenharmony_ci .agp_alloc_page = agp_generic_alloc_page, 33762306a36Sopenharmony_ci .agp_alloc_pages = agp_generic_alloc_pages, 33862306a36Sopenharmony_ci .agp_destroy_page = agp_generic_destroy_page, 33962306a36Sopenharmony_ci .agp_destroy_pages = agp_generic_destroy_pages, 34062306a36Sopenharmony_ci .agp_type_to_mask_type = agp_generic_type_to_mask_type, 34162306a36Sopenharmony_ci}; 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_cistatic int agp_efficeon_probe(struct pci_dev *pdev, 34462306a36Sopenharmony_ci const struct pci_device_id *ent) 34562306a36Sopenharmony_ci{ 34662306a36Sopenharmony_ci struct agp_bridge_data *bridge; 34762306a36Sopenharmony_ci u8 cap_ptr; 34862306a36Sopenharmony_ci struct resource *r; 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP); 35162306a36Sopenharmony_ci if (!cap_ptr) 35262306a36Sopenharmony_ci return -ENODEV; 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci /* Probe for Efficeon controller */ 35562306a36Sopenharmony_ci if (pdev->device != PCI_DEVICE_ID_EFFICEON) { 35662306a36Sopenharmony_ci printk(KERN_ERR PFX "Unsupported Efficeon chipset (device id: %04x)\n", 35762306a36Sopenharmony_ci pdev->device); 35862306a36Sopenharmony_ci return -ENODEV; 35962306a36Sopenharmony_ci } 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci printk(KERN_INFO PFX "Detected Transmeta Efficeon TM8000 series chipset\n"); 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci bridge = agp_alloc_bridge(); 36462306a36Sopenharmony_ci if (!bridge) 36562306a36Sopenharmony_ci return -ENOMEM; 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci bridge->driver = &efficeon_driver; 36862306a36Sopenharmony_ci bridge->dev = pdev; 36962306a36Sopenharmony_ci bridge->capndx = cap_ptr; 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci /* 37262306a36Sopenharmony_ci * If the device has not been properly setup, the following will catch 37362306a36Sopenharmony_ci * the problem and should stop the system from crashing. 37462306a36Sopenharmony_ci * 20030610 - hamish@zot.org 37562306a36Sopenharmony_ci */ 37662306a36Sopenharmony_ci if (pci_enable_device(pdev)) { 37762306a36Sopenharmony_ci printk(KERN_ERR PFX "Unable to Enable PCI device\n"); 37862306a36Sopenharmony_ci agp_put_bridge(bridge); 37962306a36Sopenharmony_ci return -ENODEV; 38062306a36Sopenharmony_ci } 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci /* 38362306a36Sopenharmony_ci * The following fixes the case where the BIOS has "forgotten" to 38462306a36Sopenharmony_ci * provide an address range for the GART. 38562306a36Sopenharmony_ci * 20030610 - hamish@zot.org 38662306a36Sopenharmony_ci */ 38762306a36Sopenharmony_ci r = &pdev->resource[0]; 38862306a36Sopenharmony_ci if (!r->start && r->end) { 38962306a36Sopenharmony_ci if (pci_assign_resource(pdev, 0)) { 39062306a36Sopenharmony_ci printk(KERN_ERR PFX "could not assign resource 0\n"); 39162306a36Sopenharmony_ci agp_put_bridge(bridge); 39262306a36Sopenharmony_ci return -ENODEV; 39362306a36Sopenharmony_ci } 39462306a36Sopenharmony_ci } 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci /* Fill in the mode register */ 39762306a36Sopenharmony_ci if (cap_ptr) { 39862306a36Sopenharmony_ci pci_read_config_dword(pdev, 39962306a36Sopenharmony_ci bridge->capndx+PCI_AGP_STATUS, 40062306a36Sopenharmony_ci &bridge->mode); 40162306a36Sopenharmony_ci } 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci pci_set_drvdata(pdev, bridge); 40462306a36Sopenharmony_ci return agp_add_bridge(bridge); 40562306a36Sopenharmony_ci} 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_cistatic void agp_efficeon_remove(struct pci_dev *pdev) 40862306a36Sopenharmony_ci{ 40962306a36Sopenharmony_ci struct agp_bridge_data *bridge = pci_get_drvdata(pdev); 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci agp_remove_bridge(bridge); 41262306a36Sopenharmony_ci agp_put_bridge(bridge); 41362306a36Sopenharmony_ci} 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_cistatic int agp_efficeon_resume(struct device *dev) 41662306a36Sopenharmony_ci{ 41762306a36Sopenharmony_ci printk(KERN_DEBUG PFX "agp_efficeon_resume()\n"); 41862306a36Sopenharmony_ci return efficeon_configure(); 41962306a36Sopenharmony_ci} 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_cistatic const struct pci_device_id agp_efficeon_pci_table[] = { 42262306a36Sopenharmony_ci { 42362306a36Sopenharmony_ci .class = (PCI_CLASS_BRIDGE_HOST << 8), 42462306a36Sopenharmony_ci .class_mask = ~0, 42562306a36Sopenharmony_ci .vendor = PCI_VENDOR_ID_TRANSMETA, 42662306a36Sopenharmony_ci .device = PCI_ANY_ID, 42762306a36Sopenharmony_ci .subvendor = PCI_ANY_ID, 42862306a36Sopenharmony_ci .subdevice = PCI_ANY_ID, 42962306a36Sopenharmony_ci }, 43062306a36Sopenharmony_ci { } 43162306a36Sopenharmony_ci}; 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_cistatic DEFINE_SIMPLE_DEV_PM_OPS(agp_efficeon_pm_ops, NULL, agp_efficeon_resume); 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, agp_efficeon_pci_table); 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_cistatic struct pci_driver agp_efficeon_pci_driver = { 43862306a36Sopenharmony_ci .name = "agpgart-efficeon", 43962306a36Sopenharmony_ci .id_table = agp_efficeon_pci_table, 44062306a36Sopenharmony_ci .probe = agp_efficeon_probe, 44162306a36Sopenharmony_ci .remove = agp_efficeon_remove, 44262306a36Sopenharmony_ci .driver.pm = &agp_efficeon_pm_ops, 44362306a36Sopenharmony_ci}; 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_cistatic int __init agp_efficeon_init(void) 44662306a36Sopenharmony_ci{ 44762306a36Sopenharmony_ci static int agp_initialised=0; 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci if (agp_off) 45062306a36Sopenharmony_ci return -EINVAL; 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci if (agp_initialised == 1) 45362306a36Sopenharmony_ci return 0; 45462306a36Sopenharmony_ci agp_initialised=1; 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci return pci_register_driver(&agp_efficeon_pci_driver); 45762306a36Sopenharmony_ci} 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_cistatic void __exit agp_efficeon_cleanup(void) 46062306a36Sopenharmony_ci{ 46162306a36Sopenharmony_ci pci_unregister_driver(&agp_efficeon_pci_driver); 46262306a36Sopenharmony_ci} 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_cimodule_init(agp_efficeon_init); 46562306a36Sopenharmony_cimodule_exit(agp_efficeon_cleanup); 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ciMODULE_AUTHOR("Carlos Puchol <cpglinux@puchol.com>"); 46862306a36Sopenharmony_ciMODULE_LICENSE("GPL and additional rights"); 469