18c2ecf20Sopenharmony_ci#include <linux/module.h> 28c2ecf20Sopenharmony_ci#include <linux/pci.h> 38c2ecf20Sopenharmony_ci#include <linux/init.h> 48c2ecf20Sopenharmony_ci#include <linux/agp_backend.h> 58c2ecf20Sopenharmony_ci#include <linux/mm.h> 68c2ecf20Sopenharmony_ci#include <linux/slab.h> 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <asm/machvec.h> 98c2ecf20Sopenharmony_ci#include <asm/agp_backend.h> 108c2ecf20Sopenharmony_ci#include "../../../arch/alpha/kernel/pci_impl.h" 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include "agp.h" 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_cistatic vm_fault_t alpha_core_agp_vm_fault(struct vm_fault *vmf) 158c2ecf20Sopenharmony_ci{ 168c2ecf20Sopenharmony_ci alpha_agp_info *agp = agp_bridge->dev_private_data; 178c2ecf20Sopenharmony_ci dma_addr_t dma_addr; 188c2ecf20Sopenharmony_ci unsigned long pa; 198c2ecf20Sopenharmony_ci struct page *page; 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci dma_addr = vmf->address - vmf->vma->vm_start + agp->aperture.bus_base; 228c2ecf20Sopenharmony_ci pa = agp->ops->translate(agp, dma_addr); 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci if (pa == (unsigned long)-EINVAL) 258c2ecf20Sopenharmony_ci return VM_FAULT_SIGBUS; /* no translation */ 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci /* 288c2ecf20Sopenharmony_ci * Get the page, inc the use count, and return it 298c2ecf20Sopenharmony_ci */ 308c2ecf20Sopenharmony_ci page = virt_to_page(__va(pa)); 318c2ecf20Sopenharmony_ci get_page(page); 328c2ecf20Sopenharmony_ci vmf->page = page; 338c2ecf20Sopenharmony_ci return 0; 348c2ecf20Sopenharmony_ci} 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_cistatic struct aper_size_info_fixed alpha_core_agp_sizes[] = 378c2ecf20Sopenharmony_ci{ 388c2ecf20Sopenharmony_ci { 0, 0, 0 }, /* filled in by alpha_core_agp_setup */ 398c2ecf20Sopenharmony_ci}; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_cistatic const struct vm_operations_struct alpha_core_agp_vm_ops = { 428c2ecf20Sopenharmony_ci .fault = alpha_core_agp_vm_fault, 438c2ecf20Sopenharmony_ci}; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_cistatic int alpha_core_agp_fetch_size(void) 478c2ecf20Sopenharmony_ci{ 488c2ecf20Sopenharmony_ci return alpha_core_agp_sizes[0].size; 498c2ecf20Sopenharmony_ci} 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_cistatic int alpha_core_agp_configure(void) 528c2ecf20Sopenharmony_ci{ 538c2ecf20Sopenharmony_ci alpha_agp_info *agp = agp_bridge->dev_private_data; 548c2ecf20Sopenharmony_ci agp_bridge->gart_bus_addr = agp->aperture.bus_base; 558c2ecf20Sopenharmony_ci return 0; 568c2ecf20Sopenharmony_ci} 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_cistatic void alpha_core_agp_cleanup(void) 598c2ecf20Sopenharmony_ci{ 608c2ecf20Sopenharmony_ci alpha_agp_info *agp = agp_bridge->dev_private_data; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci agp->ops->cleanup(agp); 638c2ecf20Sopenharmony_ci} 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cistatic void alpha_core_agp_tlbflush(struct agp_memory *mem) 668c2ecf20Sopenharmony_ci{ 678c2ecf20Sopenharmony_ci alpha_agp_info *agp = agp_bridge->dev_private_data; 688c2ecf20Sopenharmony_ci alpha_mv.mv_pci_tbi(agp->hose, 0, -1); 698c2ecf20Sopenharmony_ci} 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_cistatic void alpha_core_agp_enable(struct agp_bridge_data *bridge, u32 mode) 728c2ecf20Sopenharmony_ci{ 738c2ecf20Sopenharmony_ci alpha_agp_info *agp = bridge->dev_private_data; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci agp->mode.lw = agp_collect_device_status(bridge, mode, 768c2ecf20Sopenharmony_ci agp->capability.lw); 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci agp->mode.bits.enable = 1; 798c2ecf20Sopenharmony_ci agp->ops->configure(agp); 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci agp_device_command(agp->mode.lw, false); 828c2ecf20Sopenharmony_ci} 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cistatic int alpha_core_agp_insert_memory(struct agp_memory *mem, off_t pg_start, 858c2ecf20Sopenharmony_ci int type) 868c2ecf20Sopenharmony_ci{ 878c2ecf20Sopenharmony_ci alpha_agp_info *agp = agp_bridge->dev_private_data; 888c2ecf20Sopenharmony_ci int num_entries, status; 898c2ecf20Sopenharmony_ci void *temp; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci if (type >= AGP_USER_TYPES || mem->type >= AGP_USER_TYPES) 928c2ecf20Sopenharmony_ci return -EINVAL; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci temp = agp_bridge->current_size; 958c2ecf20Sopenharmony_ci num_entries = A_SIZE_FIX(temp)->num_entries; 968c2ecf20Sopenharmony_ci if ((pg_start + mem->page_count) > num_entries) 978c2ecf20Sopenharmony_ci return -EINVAL; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci status = agp->ops->bind(agp, pg_start, mem); 1008c2ecf20Sopenharmony_ci mb(); 1018c2ecf20Sopenharmony_ci alpha_core_agp_tlbflush(mem); 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci return status; 1048c2ecf20Sopenharmony_ci} 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_cistatic int alpha_core_agp_remove_memory(struct agp_memory *mem, off_t pg_start, 1078c2ecf20Sopenharmony_ci int type) 1088c2ecf20Sopenharmony_ci{ 1098c2ecf20Sopenharmony_ci alpha_agp_info *agp = agp_bridge->dev_private_data; 1108c2ecf20Sopenharmony_ci int status; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci status = agp->ops->unbind(agp, pg_start, mem); 1138c2ecf20Sopenharmony_ci alpha_core_agp_tlbflush(mem); 1148c2ecf20Sopenharmony_ci return status; 1158c2ecf20Sopenharmony_ci} 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_cistatic int alpha_core_agp_create_free_gatt_table(struct agp_bridge_data *a) 1188c2ecf20Sopenharmony_ci{ 1198c2ecf20Sopenharmony_ci return 0; 1208c2ecf20Sopenharmony_ci} 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_cistruct agp_bridge_driver alpha_core_agp_driver = { 1238c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 1248c2ecf20Sopenharmony_ci .aperture_sizes = alpha_core_agp_sizes, 1258c2ecf20Sopenharmony_ci .num_aperture_sizes = 1, 1268c2ecf20Sopenharmony_ci .size_type = FIXED_APER_SIZE, 1278c2ecf20Sopenharmony_ci .cant_use_aperture = true, 1288c2ecf20Sopenharmony_ci .masks = NULL, 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci .fetch_size = alpha_core_agp_fetch_size, 1318c2ecf20Sopenharmony_ci .configure = alpha_core_agp_configure, 1328c2ecf20Sopenharmony_ci .agp_enable = alpha_core_agp_enable, 1338c2ecf20Sopenharmony_ci .cleanup = alpha_core_agp_cleanup, 1348c2ecf20Sopenharmony_ci .tlb_flush = alpha_core_agp_tlbflush, 1358c2ecf20Sopenharmony_ci .mask_memory = agp_generic_mask_memory, 1368c2ecf20Sopenharmony_ci .cache_flush = global_cache_flush, 1378c2ecf20Sopenharmony_ci .create_gatt_table = alpha_core_agp_create_free_gatt_table, 1388c2ecf20Sopenharmony_ci .free_gatt_table = alpha_core_agp_create_free_gatt_table, 1398c2ecf20Sopenharmony_ci .insert_memory = alpha_core_agp_insert_memory, 1408c2ecf20Sopenharmony_ci .remove_memory = alpha_core_agp_remove_memory, 1418c2ecf20Sopenharmony_ci .alloc_by_type = agp_generic_alloc_by_type, 1428c2ecf20Sopenharmony_ci .free_by_type = agp_generic_free_by_type, 1438c2ecf20Sopenharmony_ci .agp_alloc_page = agp_generic_alloc_page, 1448c2ecf20Sopenharmony_ci .agp_alloc_pages = agp_generic_alloc_pages, 1458c2ecf20Sopenharmony_ci .agp_destroy_page = agp_generic_destroy_page, 1468c2ecf20Sopenharmony_ci .agp_destroy_pages = agp_generic_destroy_pages, 1478c2ecf20Sopenharmony_ci .agp_type_to_mask_type = agp_generic_type_to_mask_type, 1488c2ecf20Sopenharmony_ci}; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_cistruct agp_bridge_data *alpha_bridge; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ciint __init 1538c2ecf20Sopenharmony_cialpha_core_agp_setup(void) 1548c2ecf20Sopenharmony_ci{ 1558c2ecf20Sopenharmony_ci alpha_agp_info *agp = alpha_mv.agp_info(); 1568c2ecf20Sopenharmony_ci struct pci_dev *pdev; /* faked */ 1578c2ecf20Sopenharmony_ci struct aper_size_info_fixed *aper_size; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci if (!agp) 1608c2ecf20Sopenharmony_ci return -ENODEV; 1618c2ecf20Sopenharmony_ci if (agp->ops->setup(agp)) 1628c2ecf20Sopenharmony_ci return -ENODEV; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci /* 1658c2ecf20Sopenharmony_ci * Build the aperture size descriptor 1668c2ecf20Sopenharmony_ci */ 1678c2ecf20Sopenharmony_ci aper_size = alpha_core_agp_sizes; 1688c2ecf20Sopenharmony_ci aper_size->size = agp->aperture.size / (1024 * 1024); 1698c2ecf20Sopenharmony_ci aper_size->num_entries = agp->aperture.size / PAGE_SIZE; 1708c2ecf20Sopenharmony_ci aper_size->page_order = __ffs(aper_size->num_entries / 1024); 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci /* 1738c2ecf20Sopenharmony_ci * Build a fake pci_dev struct 1748c2ecf20Sopenharmony_ci */ 1758c2ecf20Sopenharmony_ci pdev = pci_alloc_dev(NULL); 1768c2ecf20Sopenharmony_ci if (!pdev) 1778c2ecf20Sopenharmony_ci return -ENOMEM; 1788c2ecf20Sopenharmony_ci pdev->vendor = 0xffff; 1798c2ecf20Sopenharmony_ci pdev->device = 0xffff; 1808c2ecf20Sopenharmony_ci pdev->sysdata = agp->hose; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci alpha_bridge = agp_alloc_bridge(); 1838c2ecf20Sopenharmony_ci if (!alpha_bridge) 1848c2ecf20Sopenharmony_ci goto fail; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci alpha_bridge->driver = &alpha_core_agp_driver; 1878c2ecf20Sopenharmony_ci alpha_bridge->vm_ops = &alpha_core_agp_vm_ops; 1888c2ecf20Sopenharmony_ci alpha_bridge->current_size = aper_size; /* only 1 size */ 1898c2ecf20Sopenharmony_ci alpha_bridge->dev_private_data = agp; 1908c2ecf20Sopenharmony_ci alpha_bridge->dev = pdev; 1918c2ecf20Sopenharmony_ci alpha_bridge->mode = agp->capability.lw; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci printk(KERN_INFO PFX "Detected AGP on hose %d\n", agp->hose->index); 1948c2ecf20Sopenharmony_ci return agp_add_bridge(alpha_bridge); 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci fail: 1978c2ecf20Sopenharmony_ci kfree(pdev); 1988c2ecf20Sopenharmony_ci return -ENOMEM; 1998c2ecf20Sopenharmony_ci} 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_cistatic int __init agp_alpha_core_init(void) 2028c2ecf20Sopenharmony_ci{ 2038c2ecf20Sopenharmony_ci if (agp_off) 2048c2ecf20Sopenharmony_ci return -EINVAL; 2058c2ecf20Sopenharmony_ci if (alpha_mv.agp_info) 2068c2ecf20Sopenharmony_ci return alpha_core_agp_setup(); 2078c2ecf20Sopenharmony_ci return -ENODEV; 2088c2ecf20Sopenharmony_ci} 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_cistatic void __exit agp_alpha_core_cleanup(void) 2118c2ecf20Sopenharmony_ci{ 2128c2ecf20Sopenharmony_ci agp_remove_bridge(alpha_bridge); 2138c2ecf20Sopenharmony_ci agp_put_bridge(alpha_bridge); 2148c2ecf20Sopenharmony_ci} 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_cimodule_init(agp_alpha_core_init); 2178c2ecf20Sopenharmony_cimodule_exit(agp_alpha_core_cleanup); 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ciMODULE_AUTHOR("Jeff Wiedemeier <Jeff.Wiedemeier@hp.com>"); 2208c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL and additional rights"); 221