162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * HP Quicksilver AGP GART routines 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2006, Kyle McMartin <kyle@parisc-linux.org> 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Based on drivers/char/agpgart/hp-agp.c which is 862306a36Sopenharmony_ci * (c) Copyright 2002, 2003 Hewlett-Packard Development Company, L.P. 962306a36Sopenharmony_ci * Bjorn Helgaas <bjorn.helgaas@hp.com> 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/klist.h> 1662306a36Sopenharmony_ci#include <linux/agp_backend.h> 1762306a36Sopenharmony_ci#include <linux/log2.h> 1862306a36Sopenharmony_ci#include <linux/slab.h> 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#include <asm/parisc-device.h> 2162306a36Sopenharmony_ci#include <asm/ropes.h> 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#include "agp.h" 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#define DRVNAME "quicksilver" 2662306a36Sopenharmony_ci#define DRVPFX DRVNAME ": " 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci#define AGP8X_MODE_BIT 3 2962306a36Sopenharmony_ci#define AGP8X_MODE (1 << AGP8X_MODE_BIT) 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_cistatic unsigned long 3262306a36Sopenharmony_ciparisc_agp_mask_memory(struct agp_bridge_data *bridge, dma_addr_t addr, 3362306a36Sopenharmony_ci int type); 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_cistatic struct _parisc_agp_info { 3662306a36Sopenharmony_ci void __iomem *ioc_regs; 3762306a36Sopenharmony_ci void __iomem *lba_regs; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci int lba_cap_offset; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci __le64 *gatt; 4262306a36Sopenharmony_ci u64 gatt_entries; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci u64 gart_base; 4562306a36Sopenharmony_ci u64 gart_size; 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci int io_page_size; 4862306a36Sopenharmony_ci int io_pages_per_kpage; 4962306a36Sopenharmony_ci} parisc_agp_info; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_cistatic struct gatt_mask parisc_agp_masks[] = 5262306a36Sopenharmony_ci{ 5362306a36Sopenharmony_ci { 5462306a36Sopenharmony_ci .mask = SBA_PDIR_VALID_BIT, 5562306a36Sopenharmony_ci .type = 0 5662306a36Sopenharmony_ci } 5762306a36Sopenharmony_ci}; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_cistatic struct aper_size_info_fixed parisc_agp_sizes[] = 6062306a36Sopenharmony_ci{ 6162306a36Sopenharmony_ci {0, 0, 0}, /* filled in by parisc_agp_fetch_size() */ 6262306a36Sopenharmony_ci}; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cistatic int 6562306a36Sopenharmony_ciparisc_agp_fetch_size(void) 6662306a36Sopenharmony_ci{ 6762306a36Sopenharmony_ci int size; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci size = parisc_agp_info.gart_size / MB(1); 7062306a36Sopenharmony_ci parisc_agp_sizes[0].size = size; 7162306a36Sopenharmony_ci agp_bridge->current_size = (void *) &parisc_agp_sizes[0]; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci return size; 7462306a36Sopenharmony_ci} 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_cistatic int 7762306a36Sopenharmony_ciparisc_agp_configure(void) 7862306a36Sopenharmony_ci{ 7962306a36Sopenharmony_ci struct _parisc_agp_info *info = &parisc_agp_info; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci agp_bridge->gart_bus_addr = info->gart_base; 8262306a36Sopenharmony_ci agp_bridge->capndx = info->lba_cap_offset; 8362306a36Sopenharmony_ci agp_bridge->mode = readl(info->lba_regs+info->lba_cap_offset+PCI_AGP_STATUS); 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci return 0; 8662306a36Sopenharmony_ci} 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_cistatic void 8962306a36Sopenharmony_ciparisc_agp_tlbflush(struct agp_memory *mem) 9062306a36Sopenharmony_ci{ 9162306a36Sopenharmony_ci struct _parisc_agp_info *info = &parisc_agp_info; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci /* force fdc ops to be visible to IOMMU */ 9462306a36Sopenharmony_ci asm_io_sync(); 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci writeq(info->gart_base | ilog2(info->gart_size), info->ioc_regs+IOC_PCOM); 9762306a36Sopenharmony_ci readq(info->ioc_regs+IOC_PCOM); /* flush */ 9862306a36Sopenharmony_ci} 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_cistatic int 10162306a36Sopenharmony_ciparisc_agp_create_gatt_table(struct agp_bridge_data *bridge) 10262306a36Sopenharmony_ci{ 10362306a36Sopenharmony_ci struct _parisc_agp_info *info = &parisc_agp_info; 10462306a36Sopenharmony_ci int i; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci for (i = 0; i < info->gatt_entries; i++) { 10762306a36Sopenharmony_ci info->gatt[i] = cpu_to_le64(agp_bridge->scratch_page); 10862306a36Sopenharmony_ci } 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci return 0; 11162306a36Sopenharmony_ci} 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_cistatic int 11462306a36Sopenharmony_ciparisc_agp_free_gatt_table(struct agp_bridge_data *bridge) 11562306a36Sopenharmony_ci{ 11662306a36Sopenharmony_ci struct _parisc_agp_info *info = &parisc_agp_info; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci info->gatt[0] = SBA_AGPGART_COOKIE; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci return 0; 12162306a36Sopenharmony_ci} 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_cistatic int 12462306a36Sopenharmony_ciparisc_agp_insert_memory(struct agp_memory *mem, off_t pg_start, int type) 12562306a36Sopenharmony_ci{ 12662306a36Sopenharmony_ci struct _parisc_agp_info *info = &parisc_agp_info; 12762306a36Sopenharmony_ci int i, k; 12862306a36Sopenharmony_ci off_t j, io_pg_start; 12962306a36Sopenharmony_ci int io_pg_count; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci if (type != mem->type || 13262306a36Sopenharmony_ci agp_bridge->driver->agp_type_to_mask_type(agp_bridge, type)) { 13362306a36Sopenharmony_ci return -EINVAL; 13462306a36Sopenharmony_ci } 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci io_pg_start = info->io_pages_per_kpage * pg_start; 13762306a36Sopenharmony_ci io_pg_count = info->io_pages_per_kpage * mem->page_count; 13862306a36Sopenharmony_ci if ((io_pg_start + io_pg_count) > info->gatt_entries) { 13962306a36Sopenharmony_ci return -EINVAL; 14062306a36Sopenharmony_ci } 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci j = io_pg_start; 14362306a36Sopenharmony_ci while (j < (io_pg_start + io_pg_count)) { 14462306a36Sopenharmony_ci if (info->gatt[j]) 14562306a36Sopenharmony_ci return -EBUSY; 14662306a36Sopenharmony_ci j++; 14762306a36Sopenharmony_ci } 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci if (!mem->is_flushed) { 15062306a36Sopenharmony_ci global_cache_flush(); 15162306a36Sopenharmony_ci mem->is_flushed = true; 15262306a36Sopenharmony_ci } 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci for (i = 0, j = io_pg_start; i < mem->page_count; i++) { 15562306a36Sopenharmony_ci unsigned long paddr; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci paddr = page_to_phys(mem->pages[i]); 15862306a36Sopenharmony_ci for (k = 0; 15962306a36Sopenharmony_ci k < info->io_pages_per_kpage; 16062306a36Sopenharmony_ci k++, j++, paddr += info->io_page_size) { 16162306a36Sopenharmony_ci info->gatt[j] = cpu_to_le64( 16262306a36Sopenharmony_ci parisc_agp_mask_memory(agp_bridge, 16362306a36Sopenharmony_ci paddr, type)); 16462306a36Sopenharmony_ci asm_io_fdc(&info->gatt[j]); 16562306a36Sopenharmony_ci } 16662306a36Sopenharmony_ci } 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci agp_bridge->driver->tlb_flush(mem); 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci return 0; 17162306a36Sopenharmony_ci} 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_cistatic int 17462306a36Sopenharmony_ciparisc_agp_remove_memory(struct agp_memory *mem, off_t pg_start, int type) 17562306a36Sopenharmony_ci{ 17662306a36Sopenharmony_ci struct _parisc_agp_info *info = &parisc_agp_info; 17762306a36Sopenharmony_ci int i, io_pg_start, io_pg_count; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci if (type != mem->type || 18062306a36Sopenharmony_ci agp_bridge->driver->agp_type_to_mask_type(agp_bridge, type)) { 18162306a36Sopenharmony_ci return -EINVAL; 18262306a36Sopenharmony_ci } 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci io_pg_start = info->io_pages_per_kpage * pg_start; 18562306a36Sopenharmony_ci io_pg_count = info->io_pages_per_kpage * mem->page_count; 18662306a36Sopenharmony_ci for (i = io_pg_start; i < io_pg_count + io_pg_start; i++) { 18762306a36Sopenharmony_ci info->gatt[i] = cpu_to_le64(agp_bridge->scratch_page); 18862306a36Sopenharmony_ci } 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci agp_bridge->driver->tlb_flush(mem); 19162306a36Sopenharmony_ci return 0; 19262306a36Sopenharmony_ci} 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_cistatic unsigned long 19562306a36Sopenharmony_ciparisc_agp_mask_memory(struct agp_bridge_data *bridge, dma_addr_t addr, 19662306a36Sopenharmony_ci int type) 19762306a36Sopenharmony_ci{ 19862306a36Sopenharmony_ci unsigned ci; /* coherent index */ 19962306a36Sopenharmony_ci dma_addr_t pa; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci pa = addr & IOVP_MASK; 20262306a36Sopenharmony_ci asm("lci 0(%1), %0" : "=r" (ci) : "r" (phys_to_virt(pa))); 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci pa |= (ci >> PAGE_SHIFT) & 0xff;/* move CI (8 bits) into lowest byte */ 20562306a36Sopenharmony_ci pa |= SBA_PDIR_VALID_BIT; /* set "valid" bit */ 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci /* return native (big-endian) PDIR entry */ 20862306a36Sopenharmony_ci return pa; 20962306a36Sopenharmony_ci} 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_cistatic void 21262306a36Sopenharmony_ciparisc_agp_enable(struct agp_bridge_data *bridge, u32 mode) 21362306a36Sopenharmony_ci{ 21462306a36Sopenharmony_ci struct _parisc_agp_info *info = &parisc_agp_info; 21562306a36Sopenharmony_ci u32 command; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci command = readl(info->lba_regs + info->lba_cap_offset + PCI_AGP_STATUS); 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci command = agp_collect_device_status(bridge, mode, command); 22062306a36Sopenharmony_ci command |= 0x00000100; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci writel(command, info->lba_regs + info->lba_cap_offset + PCI_AGP_COMMAND); 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci agp_device_command(command, (mode & AGP8X_MODE) != 0); 22562306a36Sopenharmony_ci} 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_cistatic const struct agp_bridge_driver parisc_agp_driver = { 22862306a36Sopenharmony_ci .owner = THIS_MODULE, 22962306a36Sopenharmony_ci .size_type = FIXED_APER_SIZE, 23062306a36Sopenharmony_ci .configure = parisc_agp_configure, 23162306a36Sopenharmony_ci .fetch_size = parisc_agp_fetch_size, 23262306a36Sopenharmony_ci .tlb_flush = parisc_agp_tlbflush, 23362306a36Sopenharmony_ci .mask_memory = parisc_agp_mask_memory, 23462306a36Sopenharmony_ci .masks = parisc_agp_masks, 23562306a36Sopenharmony_ci .agp_enable = parisc_agp_enable, 23662306a36Sopenharmony_ci .cache_flush = global_cache_flush, 23762306a36Sopenharmony_ci .create_gatt_table = parisc_agp_create_gatt_table, 23862306a36Sopenharmony_ci .free_gatt_table = parisc_agp_free_gatt_table, 23962306a36Sopenharmony_ci .insert_memory = parisc_agp_insert_memory, 24062306a36Sopenharmony_ci .remove_memory = parisc_agp_remove_memory, 24162306a36Sopenharmony_ci .alloc_by_type = agp_generic_alloc_by_type, 24262306a36Sopenharmony_ci .free_by_type = agp_generic_free_by_type, 24362306a36Sopenharmony_ci .agp_alloc_page = agp_generic_alloc_page, 24462306a36Sopenharmony_ci .agp_alloc_pages = agp_generic_alloc_pages, 24562306a36Sopenharmony_ci .agp_destroy_page = agp_generic_destroy_page, 24662306a36Sopenharmony_ci .agp_destroy_pages = agp_generic_destroy_pages, 24762306a36Sopenharmony_ci .agp_type_to_mask_type = agp_generic_type_to_mask_type, 24862306a36Sopenharmony_ci .cant_use_aperture = true, 24962306a36Sopenharmony_ci}; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_cistatic int __init 25262306a36Sopenharmony_ciagp_ioc_init(void __iomem *ioc_regs) 25362306a36Sopenharmony_ci{ 25462306a36Sopenharmony_ci struct _parisc_agp_info *info = &parisc_agp_info; 25562306a36Sopenharmony_ci u64 iova_base, io_tlb_ps; 25662306a36Sopenharmony_ci __le64 *io_pdir; 25762306a36Sopenharmony_ci int io_tlb_shift; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci printk(KERN_INFO DRVPFX "IO PDIR shared with sba_iommu\n"); 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci info->ioc_regs = ioc_regs; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci io_tlb_ps = readq(info->ioc_regs+IOC_TCNFG); 26462306a36Sopenharmony_ci switch (io_tlb_ps) { 26562306a36Sopenharmony_ci case 0: io_tlb_shift = 12; break; 26662306a36Sopenharmony_ci case 1: io_tlb_shift = 13; break; 26762306a36Sopenharmony_ci case 2: io_tlb_shift = 14; break; 26862306a36Sopenharmony_ci case 3: io_tlb_shift = 16; break; 26962306a36Sopenharmony_ci default: 27062306a36Sopenharmony_ci printk(KERN_ERR DRVPFX "Invalid IOTLB page size " 27162306a36Sopenharmony_ci "configuration 0x%llx\n", io_tlb_ps); 27262306a36Sopenharmony_ci info->gatt = NULL; 27362306a36Sopenharmony_ci info->gatt_entries = 0; 27462306a36Sopenharmony_ci return -ENODEV; 27562306a36Sopenharmony_ci } 27662306a36Sopenharmony_ci info->io_page_size = 1 << io_tlb_shift; 27762306a36Sopenharmony_ci info->io_pages_per_kpage = PAGE_SIZE / info->io_page_size; 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci iova_base = readq(info->ioc_regs+IOC_IBASE) & ~0x1; 28062306a36Sopenharmony_ci info->gart_base = iova_base + PLUTO_IOVA_SIZE - PLUTO_GART_SIZE; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci info->gart_size = PLUTO_GART_SIZE; 28362306a36Sopenharmony_ci info->gatt_entries = info->gart_size / info->io_page_size; 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci io_pdir = phys_to_virt(readq(info->ioc_regs+IOC_PDIR_BASE)); 28662306a36Sopenharmony_ci info->gatt = &io_pdir[(PLUTO_IOVA_SIZE/2) >> PAGE_SHIFT]; 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci if (info->gatt[0] != SBA_AGPGART_COOKIE) { 28962306a36Sopenharmony_ci info->gatt = NULL; 29062306a36Sopenharmony_ci info->gatt_entries = 0; 29162306a36Sopenharmony_ci printk(KERN_ERR DRVPFX "No reserved IO PDIR entry found; " 29262306a36Sopenharmony_ci "GART disabled\n"); 29362306a36Sopenharmony_ci return -ENODEV; 29462306a36Sopenharmony_ci } 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci return 0; 29762306a36Sopenharmony_ci} 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_cistatic int __init 30062306a36Sopenharmony_cilba_find_capability(int cap) 30162306a36Sopenharmony_ci{ 30262306a36Sopenharmony_ci struct _parisc_agp_info *info = &parisc_agp_info; 30362306a36Sopenharmony_ci u16 status; 30462306a36Sopenharmony_ci u8 pos, id; 30562306a36Sopenharmony_ci int ttl = 48; 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci status = readw(info->lba_regs + PCI_STATUS); 30862306a36Sopenharmony_ci if (!(status & PCI_STATUS_CAP_LIST)) 30962306a36Sopenharmony_ci return 0; 31062306a36Sopenharmony_ci pos = readb(info->lba_regs + PCI_CAPABILITY_LIST); 31162306a36Sopenharmony_ci while (ttl-- && pos >= 0x40) { 31262306a36Sopenharmony_ci pos &= ~3; 31362306a36Sopenharmony_ci id = readb(info->lba_regs + pos + PCI_CAP_LIST_ID); 31462306a36Sopenharmony_ci if (id == 0xff) 31562306a36Sopenharmony_ci break; 31662306a36Sopenharmony_ci if (id == cap) 31762306a36Sopenharmony_ci return pos; 31862306a36Sopenharmony_ci pos = readb(info->lba_regs + pos + PCI_CAP_LIST_NEXT); 31962306a36Sopenharmony_ci } 32062306a36Sopenharmony_ci return 0; 32162306a36Sopenharmony_ci} 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_cistatic int __init 32462306a36Sopenharmony_ciagp_lba_init(void __iomem *lba_hpa) 32562306a36Sopenharmony_ci{ 32662306a36Sopenharmony_ci struct _parisc_agp_info *info = &parisc_agp_info; 32762306a36Sopenharmony_ci int cap; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci info->lba_regs = lba_hpa; 33062306a36Sopenharmony_ci info->lba_cap_offset = lba_find_capability(PCI_CAP_ID_AGP); 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci cap = readl(lba_hpa + info->lba_cap_offset) & 0xff; 33362306a36Sopenharmony_ci if (cap != PCI_CAP_ID_AGP) { 33462306a36Sopenharmony_ci printk(KERN_ERR DRVPFX "Invalid capability ID 0x%02x at 0x%x\n", 33562306a36Sopenharmony_ci cap, info->lba_cap_offset); 33662306a36Sopenharmony_ci return -ENODEV; 33762306a36Sopenharmony_ci } 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci return 0; 34062306a36Sopenharmony_ci} 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_cistatic int __init 34362306a36Sopenharmony_ciparisc_agp_setup(void __iomem *ioc_hpa, void __iomem *lba_hpa) 34462306a36Sopenharmony_ci{ 34562306a36Sopenharmony_ci struct pci_dev *fake_bridge_dev = NULL; 34662306a36Sopenharmony_ci struct agp_bridge_data *bridge; 34762306a36Sopenharmony_ci int error = 0; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci fake_bridge_dev = pci_alloc_dev(NULL); 35062306a36Sopenharmony_ci if (!fake_bridge_dev) { 35162306a36Sopenharmony_ci error = -ENOMEM; 35262306a36Sopenharmony_ci goto fail; 35362306a36Sopenharmony_ci } 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci error = agp_ioc_init(ioc_hpa); 35662306a36Sopenharmony_ci if (error) 35762306a36Sopenharmony_ci goto fail; 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci error = agp_lba_init(lba_hpa); 36062306a36Sopenharmony_ci if (error) 36162306a36Sopenharmony_ci goto fail; 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci bridge = agp_alloc_bridge(); 36462306a36Sopenharmony_ci if (!bridge) { 36562306a36Sopenharmony_ci error = -ENOMEM; 36662306a36Sopenharmony_ci goto fail; 36762306a36Sopenharmony_ci } 36862306a36Sopenharmony_ci bridge->driver = &parisc_agp_driver; 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci fake_bridge_dev->vendor = PCI_VENDOR_ID_HP; 37162306a36Sopenharmony_ci fake_bridge_dev->device = PCI_DEVICE_ID_HP_PCIX_LBA; 37262306a36Sopenharmony_ci bridge->dev = fake_bridge_dev; 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci error = agp_add_bridge(bridge); 37562306a36Sopenharmony_ci if (error) 37662306a36Sopenharmony_ci goto fail; 37762306a36Sopenharmony_ci return 0; 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_cifail: 38062306a36Sopenharmony_ci kfree(fake_bridge_dev); 38162306a36Sopenharmony_ci return error; 38262306a36Sopenharmony_ci} 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_cistatic int __init 38562306a36Sopenharmony_cifind_quicksilver(struct device *dev, void *data) 38662306a36Sopenharmony_ci{ 38762306a36Sopenharmony_ci struct parisc_device **lba = data; 38862306a36Sopenharmony_ci struct parisc_device *padev = to_parisc_device(dev); 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci if (IS_QUICKSILVER(padev)) 39162306a36Sopenharmony_ci *lba = padev; 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci return 0; 39462306a36Sopenharmony_ci} 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_cistatic int __init 39762306a36Sopenharmony_ciparisc_agp_init(void) 39862306a36Sopenharmony_ci{ 39962306a36Sopenharmony_ci int err = -1; 40062306a36Sopenharmony_ci struct parisc_device *sba = NULL, *lba = NULL; 40162306a36Sopenharmony_ci struct lba_device *lbadev = NULL; 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci if (!sba_list) 40462306a36Sopenharmony_ci goto out; 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci /* Find our parent Pluto */ 40762306a36Sopenharmony_ci sba = sba_list->dev; 40862306a36Sopenharmony_ci if (!IS_PLUTO(sba)) { 40962306a36Sopenharmony_ci printk(KERN_INFO DRVPFX "No Pluto found, so no AGPGART for you.\n"); 41062306a36Sopenharmony_ci goto out; 41162306a36Sopenharmony_ci } 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci /* Now search our Pluto for our precious AGP device... */ 41462306a36Sopenharmony_ci device_for_each_child(&sba->dev, &lba, find_quicksilver); 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci if (!lba) { 41762306a36Sopenharmony_ci printk(KERN_INFO DRVPFX "No AGP devices found.\n"); 41862306a36Sopenharmony_ci goto out; 41962306a36Sopenharmony_ci } 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci lbadev = parisc_get_drvdata(lba); 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci /* w00t, let's go find our cookies... */ 42462306a36Sopenharmony_ci parisc_agp_setup(sba_list->ioc[0].ioc_hpa, lbadev->hba.base_addr); 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci return 0; 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ciout: 42962306a36Sopenharmony_ci return err; 43062306a36Sopenharmony_ci} 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_cimodule_init(parisc_agp_init); 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ciMODULE_AUTHOR("Kyle McMartin <kyle@parisc-linux.org>"); 43562306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 436