agp_sis.c revision 79339
161452Sdfr/*- 261452Sdfr * Copyright (c) 2000 Doug Rabson 361452Sdfr * All rights reserved. 461452Sdfr * 561452Sdfr * Redistribution and use in source and binary forms, with or without 661452Sdfr * modification, are permitted provided that the following conditions 761452Sdfr * are met: 861452Sdfr * 1. Redistributions of source code must retain the above copyright 961452Sdfr * notice, this list of conditions and the following disclaimer. 1061452Sdfr * 2. Redistributions in binary form must reproduce the above copyright 1161452Sdfr * notice, this list of conditions and the following disclaimer in the 1261452Sdfr * documentation and/or other materials provided with the distribution. 1361452Sdfr * 1461452Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1561452Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1661452Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1761452Sdfr * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1861452Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1961452Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2061452Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2161452Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2261452Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2361452Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2461452Sdfr * SUCH DAMAGE. 2561452Sdfr * 2661452Sdfr * $FreeBSD: head/sys/dev/agp/agp_sis.c 79339 2001-07-05 21:28:47Z jhb $ 2761452Sdfr */ 2861452Sdfr 2961452Sdfr#include "opt_bus.h" 3061452Sdfr#include "opt_pci.h" 3161452Sdfr 3261452Sdfr#include <sys/param.h> 3361452Sdfr#include <sys/systm.h> 3461452Sdfr#include <sys/malloc.h> 3561452Sdfr#include <sys/kernel.h> 3661452Sdfr#include <sys/bus.h> 3761452Sdfr#include <sys/lock.h> 3876827Salfred#include <sys/mutex.h> 3979339Sjhb#include <sys/proc.h> 4061452Sdfr 4161452Sdfr#include <pci/pcivar.h> 4261452Sdfr#include <pci/pcireg.h> 4361452Sdfr#include <pci/agppriv.h> 4461452Sdfr#include <pci/agpreg.h> 4561452Sdfr 4661452Sdfr#include <vm/vm.h> 4761452Sdfr#include <vm/vm_object.h> 4861452Sdfr#include <vm/pmap.h> 4961452Sdfr 5061452Sdfrstruct agp_sis_softc { 5161452Sdfr struct agp_softc agp; 5261452Sdfr u_int32_t initial_aperture; /* aperture size at startup */ 5361452Sdfr struct agp_gatt *gatt; 5461452Sdfr}; 5561452Sdfr 5661452Sdfrstatic const char* 5761452Sdfragp_sis_match(device_t dev) 5861452Sdfr{ 5961452Sdfr if (pci_get_class(dev) != PCIC_BRIDGE 6061452Sdfr || pci_get_subclass(dev) != PCIS_BRIDGE_HOST) 6161452Sdfr return NULL; 6261452Sdfr 6361452Sdfr if (agp_find_caps(dev) == 0) 6461452Sdfr return NULL; 6561452Sdfr 6661452Sdfr switch (pci_get_devid(dev)) { 6761452Sdfr case 0x00011039: 6861452Sdfr return ("SiS 5591 host to AGP bridge"); 6961452Sdfr }; 7061452Sdfr 7161452Sdfr if (pci_get_vendor(dev) == 0x1039) 7261452Sdfr return ("SIS Generic host to PCI bridge"); 7361452Sdfr 7461452Sdfr return NULL; 7561452Sdfr} 7661452Sdfr 7761452Sdfrstatic int 7861452Sdfragp_sis_probe(device_t dev) 7961452Sdfr{ 8061452Sdfr const char *desc; 8161452Sdfr 8261452Sdfr desc = agp_sis_match(dev); 8361452Sdfr if (desc) { 8461452Sdfr device_verbose(dev); 8561452Sdfr device_set_desc(dev, desc); 8661452Sdfr return 0; 8761452Sdfr } 8861452Sdfr 8961452Sdfr return ENXIO; 9061452Sdfr} 9161452Sdfr 9261452Sdfrstatic int 9361452Sdfragp_sis_attach(device_t dev) 9461452Sdfr{ 9561452Sdfr struct agp_sis_softc *sc = device_get_softc(dev); 9661452Sdfr struct agp_gatt *gatt; 9761452Sdfr int error; 9861452Sdfr 9961452Sdfr error = agp_generic_attach(dev); 10061452Sdfr if (error) 10161452Sdfr return error; 10261452Sdfr 10361452Sdfr sc->initial_aperture = AGP_GET_APERTURE(dev); 10461452Sdfr 10561452Sdfr for (;;) { 10661452Sdfr gatt = agp_alloc_gatt(dev); 10761452Sdfr if (gatt) 10861452Sdfr break; 10961452Sdfr 11061452Sdfr /* 11161452Sdfr * Probably contigmalloc failure. Try reducing the 11261452Sdfr * aperture so that the gatt size reduces. 11361452Sdfr */ 11461452Sdfr if (AGP_SET_APERTURE(dev, AGP_GET_APERTURE(dev) / 2)) { 11561452Sdfr agp_generic_detach(dev); 11661452Sdfr return ENOMEM; 11761452Sdfr } 11861452Sdfr } 11961452Sdfr sc->gatt = gatt; 12061452Sdfr 12161452Sdfr /* Install the gatt. */ 12261452Sdfr pci_write_config(dev, AGP_SIS_ATTBASE, gatt->ag_physical, 4); 12361452Sdfr 12461452Sdfr /* Enable the aperture. */ 12561452Sdfr pci_write_config(dev, AGP_SIS_WINCTRL, 12661452Sdfr pci_read_config(dev, AGP_SIS_WINCTRL, 1) | 3, 1); 12761452Sdfr 12861452Sdfr /* 12961452Sdfr * Enable the TLB and make it automatically invalidate entries 13061452Sdfr * when the GATT is written. 13161452Sdfr */ 13261452Sdfr pci_write_config(dev, AGP_SIS_TLBCTRL, 0x05, 1); 13361452Sdfr 13461452Sdfr return 0; 13561452Sdfr} 13661452Sdfr 13761452Sdfrstatic int 13861452Sdfragp_sis_detach(device_t dev) 13961452Sdfr{ 14061452Sdfr struct agp_sis_softc *sc = device_get_softc(dev); 14161452Sdfr int error; 14261452Sdfr 14361452Sdfr error = agp_generic_detach(dev); 14461452Sdfr if (error) 14561452Sdfr return error; 14661452Sdfr 14761452Sdfr /* Disable the aperture.. */ 14861452Sdfr pci_write_config(dev, AGP_SIS_WINCTRL, 14961452Sdfr pci_read_config(dev, AGP_SIS_WINCTRL, 1) & ~3, 1); 15061452Sdfr 15161452Sdfr /* and the TLB. */ 15261452Sdfr pci_write_config(dev, AGP_SIS_TLBCTRL, 0, 1); 15361452Sdfr 15461452Sdfr /* Put the aperture back the way it started. */ 15561452Sdfr AGP_SET_APERTURE(dev, sc->initial_aperture); 15661452Sdfr 15761452Sdfr agp_free_gatt(sc->gatt); 15861452Sdfr return 0; 15961452Sdfr} 16061452Sdfr 16161452Sdfrstatic u_int32_t 16261452Sdfragp_sis_get_aperture(device_t dev) 16361452Sdfr{ 16461452Sdfr int gws; 16561452Sdfr 16661452Sdfr /* 16761452Sdfr * The aperture size is equal to 4M<<gws. 16861452Sdfr */ 16961452Sdfr gws = (pci_read_config(dev, AGP_SIS_WINCTRL, 1) & 0x70) >> 4; 17061452Sdfr return (4*1024*1024) << gws; 17161452Sdfr} 17261452Sdfr 17361452Sdfrstatic int 17461452Sdfragp_sis_set_aperture(device_t dev, u_int32_t aperture) 17561452Sdfr{ 17661452Sdfr int gws; 17761452Sdfr 17861452Sdfr /* 17961452Sdfr * Check for a power of two and make sure its within the 18061452Sdfr * programmable range. 18161452Sdfr */ 18261452Sdfr if (aperture & (aperture - 1) 18361452Sdfr || aperture < 4*1024*1024 18461452Sdfr || aperture > 256*1024*1024) 18561452Sdfr return EINVAL; 18661452Sdfr 18761452Sdfr gws = ffs(aperture / 4*1024*1024) - 1; 18861452Sdfr 18961452Sdfr pci_write_config(dev, AGP_SIS_WINCTRL, 19061452Sdfr ((pci_read_config(dev, AGP_SIS_WINCTRL, 1) & ~0x70) 19161452Sdfr | gws << 4), 1); 19261452Sdfr 19361452Sdfr return 0; 19461452Sdfr} 19561452Sdfr 19661452Sdfrstatic int 19761452Sdfragp_sis_bind_page(device_t dev, int offset, vm_offset_t physical) 19861452Sdfr{ 19961452Sdfr struct agp_sis_softc *sc = device_get_softc(dev); 20061452Sdfr 20161452Sdfr if (offset < 0 || offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT)) 20261452Sdfr return EINVAL; 20361452Sdfr 20461452Sdfr sc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = physical; 20561452Sdfr return 0; 20661452Sdfr} 20761452Sdfr 20861452Sdfrstatic int 20961452Sdfragp_sis_unbind_page(device_t dev, int offset) 21061452Sdfr{ 21161452Sdfr struct agp_sis_softc *sc = device_get_softc(dev); 21261452Sdfr 21361452Sdfr if (offset < 0 || offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT)) 21461452Sdfr return EINVAL; 21561452Sdfr 21661452Sdfr sc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = 0; 21761452Sdfr return 0; 21861452Sdfr} 21961452Sdfr 22061452Sdfrstatic void 22161452Sdfragp_sis_flush_tlb(device_t dev) 22261452Sdfr{ 22361452Sdfr pci_write_config(dev, AGP_SIS_TLBFLUSH, 0x02, 1); 22461452Sdfr} 22561452Sdfr 22661452Sdfrstatic device_method_t agp_sis_methods[] = { 22761452Sdfr /* Device interface */ 22861452Sdfr DEVMETHOD(device_probe, agp_sis_probe), 22961452Sdfr DEVMETHOD(device_attach, agp_sis_attach), 23061452Sdfr DEVMETHOD(device_detach, agp_sis_detach), 23161452Sdfr DEVMETHOD(device_shutdown, bus_generic_shutdown), 23261452Sdfr DEVMETHOD(device_suspend, bus_generic_suspend), 23361452Sdfr DEVMETHOD(device_resume, bus_generic_resume), 23461452Sdfr 23561452Sdfr /* AGP interface */ 23661452Sdfr DEVMETHOD(agp_get_aperture, agp_sis_get_aperture), 23761452Sdfr DEVMETHOD(agp_set_aperture, agp_sis_set_aperture), 23861452Sdfr DEVMETHOD(agp_bind_page, agp_sis_bind_page), 23961452Sdfr DEVMETHOD(agp_unbind_page, agp_sis_unbind_page), 24061452Sdfr DEVMETHOD(agp_flush_tlb, agp_sis_flush_tlb), 24161452Sdfr DEVMETHOD(agp_enable, agp_generic_enable), 24261452Sdfr DEVMETHOD(agp_alloc_memory, agp_generic_alloc_memory), 24361452Sdfr DEVMETHOD(agp_free_memory, agp_generic_free_memory), 24461452Sdfr DEVMETHOD(agp_bind_memory, agp_generic_bind_memory), 24561452Sdfr DEVMETHOD(agp_unbind_memory, agp_generic_unbind_memory), 24661452Sdfr 24761452Sdfr { 0, 0 } 24861452Sdfr}; 24961452Sdfr 25061452Sdfrstatic driver_t agp_sis_driver = { 25161452Sdfr "agp", 25261452Sdfr agp_sis_methods, 25361452Sdfr sizeof(struct agp_sis_softc), 25461452Sdfr}; 25561452Sdfr 25661452Sdfrstatic devclass_t agp_devclass; 25761452Sdfr 25861452SdfrDRIVER_MODULE(agp_sis, pci, agp_sis_driver, agp_devclass, 0, 0); 259