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 27116192Sobrien#include <sys/cdefs.h> 28116192Sobrien__FBSDID("$FreeBSD$"); 29116192Sobrien 30188247Swkoszek#include "opt_agp.h" 3161452Sdfr 3261452Sdfr#include <sys/param.h> 3361452Sdfr#include <sys/systm.h> 3461452Sdfr#include <sys/malloc.h> 3561452Sdfr#include <sys/kernel.h> 36129878Sphk#include <sys/module.h> 3761452Sdfr#include <sys/bus.h> 3861452Sdfr#include <sys/conf.h> 3961452Sdfr#include <sys/ioccom.h> 4061452Sdfr#include <sys/agpio.h> 4161452Sdfr#include <sys/lock.h> 4276827Salfred#include <sys/mutex.h> 4369927Sjhb#include <sys/proc.h> 44248084Sattilio#include <sys/rwlock.h> 4561452Sdfr 46173573Sjhb#include <dev/agp/agppriv.h> 47173573Sjhb#include <dev/agp/agpvar.h> 48173573Sjhb#include <dev/agp/agpreg.h> 49119288Simp#include <dev/pci/pcivar.h> 50119288Simp#include <dev/pci/pcireg.h> 5161452Sdfr 5261452Sdfr#include <vm/vm.h> 53275406Stijl#include <vm/vm_extern.h> 54275406Stijl#include <vm/vm_kern.h> 55239065Skib#include <vm/vm_param.h> 5661452Sdfr#include <vm/vm_object.h> 5761452Sdfr#include <vm/vm_page.h> 5861452Sdfr#include <vm/vm_pageout.h> 5961452Sdfr#include <vm/pmap.h> 6061452Sdfr 6161452Sdfr#include <machine/bus.h> 6261452Sdfr#include <machine/resource.h> 6361452Sdfr#include <sys/rman.h> 6461452Sdfr 6561452SdfrMODULE_VERSION(agp, 1); 6661452Sdfr 6770185SassarMALLOC_DEFINE(M_AGP, "agp", "AGP data structures"); 6861452Sdfr 6961452Sdfr /* agp_drv.c */ 7061452Sdfrstatic d_open_t agp_open; 7161452Sdfrstatic d_close_t agp_close; 7261452Sdfrstatic d_ioctl_t agp_ioctl; 7361452Sdfrstatic d_mmap_t agp_mmap; 7461452Sdfr 7561452Sdfrstatic struct cdevsw agp_cdevsw = { 76126080Sphk .d_version = D_VERSION, 77126080Sphk .d_flags = D_NEEDGIANT, 78111815Sphk .d_open = agp_open, 79111815Sphk .d_close = agp_close, 80111815Sphk .d_ioctl = agp_ioctl, 81111815Sphk .d_mmap = agp_mmap, 82111815Sphk .d_name = "agp", 8361452Sdfr}; 8461452Sdfr 8561452Sdfrstatic devclass_t agp_devclass; 8661452Sdfr 8761452Sdfr/* Helper functions for implementing chipset mini drivers. */ 8861452Sdfr 8961452Sdfru_int8_t 9061452Sdfragp_find_caps(device_t dev) 9161452Sdfr{ 92153561Sjhb int capreg; 9361452Sdfr 9461452Sdfr 95219902Sjhb if (pci_find_cap(dev, PCIY_AGP, &capreg) != 0) 96153561Sjhb capreg = 0; 97153561Sjhb return (capreg); 9861452Sdfr} 9961452Sdfr 10061452Sdfr/* 10161452Sdfr * Find an AGP display device (if any). 10261452Sdfr */ 10361452Sdfrstatic device_t 10461452Sdfragp_find_display(void) 10561452Sdfr{ 10661452Sdfr devclass_t pci = devclass_find("pci"); 10761452Sdfr device_t bus, dev = 0; 10861452Sdfr device_t *kids; 10961452Sdfr int busnum, numkids, i; 11061452Sdfr 11161452Sdfr for (busnum = 0; busnum < devclass_get_maxunit(pci); busnum++) { 11261452Sdfr bus = devclass_get_device(pci, busnum); 11361452Sdfr if (!bus) 11461452Sdfr continue; 115182068Simp if (device_get_children(bus, &kids, &numkids) != 0) 116182068Simp continue; 11761452Sdfr for (i = 0; i < numkids; i++) { 11861452Sdfr dev = kids[i]; 11961452Sdfr if (pci_get_class(dev) == PCIC_DISPLAY 12061452Sdfr && pci_get_subclass(dev) == PCIS_DISPLAY_VGA) 12161452Sdfr if (agp_find_caps(dev)) { 12261452Sdfr free(kids, M_TEMP); 12361452Sdfr return dev; 12461452Sdfr } 12561452Sdfr 12661452Sdfr } 12761452Sdfr free(kids, M_TEMP); 12861452Sdfr } 12961452Sdfr 13061452Sdfr return 0; 13161452Sdfr} 13261452Sdfr 13361452Sdfrstruct agp_gatt * 13461452Sdfragp_alloc_gatt(device_t dev) 13561452Sdfr{ 13661452Sdfr u_int32_t apsize = AGP_GET_APERTURE(dev); 13761452Sdfr u_int32_t entries = apsize >> AGP_PAGE_SHIFT; 13861452Sdfr struct agp_gatt *gatt; 13961452Sdfr 14061452Sdfr if (bootverbose) 14161452Sdfr device_printf(dev, 14261452Sdfr "allocating GATT for aperture of size %dM\n", 14361452Sdfr apsize / (1024*1024)); 14461452Sdfr 145122513Sanholt if (entries == 0) { 146122513Sanholt device_printf(dev, "bad aperture size\n"); 147122513Sanholt return NULL; 148122513Sanholt } 149122513Sanholt 15061452Sdfr gatt = malloc(sizeof(struct agp_gatt), M_AGP, M_NOWAIT); 15161452Sdfr if (!gatt) 15261452Sdfr return 0; 15361452Sdfr 15461452Sdfr gatt->ag_entries = entries; 155275406Stijl gatt->ag_virtual = (void *)kmem_alloc_contig(kernel_arena, 156275406Stijl entries * sizeof(u_int32_t), M_NOWAIT | M_ZERO, 0, ~0, PAGE_SIZE, 157275406Stijl 0, VM_MEMATTR_WRITE_COMBINING); 15861452Sdfr if (!gatt->ag_virtual) { 15961452Sdfr if (bootverbose) 16061452Sdfr device_printf(dev, "contiguous allocation failed\n"); 16161452Sdfr free(gatt, M_AGP); 16261452Sdfr return 0; 16361452Sdfr } 16461452Sdfr gatt->ag_physical = vtophys((vm_offset_t) gatt->ag_virtual); 16561452Sdfr 16661452Sdfr return gatt; 16761452Sdfr} 16861452Sdfr 16961452Sdfrvoid 17061452Sdfragp_free_gatt(struct agp_gatt *gatt) 17161452Sdfr{ 172275406Stijl kmem_free(kernel_arena, (vm_offset_t)gatt->ag_virtual, 173275406Stijl gatt->ag_entries * sizeof(u_int32_t)); 17461452Sdfr free(gatt, M_AGP); 17561452Sdfr} 17661452Sdfr 177163362Stanimurastatic u_int agp_max[][2] = { 17861452Sdfr {0, 0}, 17961452Sdfr {32, 4}, 18061452Sdfr {64, 28}, 18161452Sdfr {128, 96}, 18261452Sdfr {256, 204}, 18361452Sdfr {512, 440}, 18461452Sdfr {1024, 942}, 18561452Sdfr {2048, 1920}, 18661452Sdfr {4096, 3932} 18761452Sdfr}; 18861452Sdfr#define agp_max_size (sizeof(agp_max) / sizeof(agp_max[0])) 18961452Sdfr 190171433Sanholt/** 191171433Sanholt * Sets the PCI resource which represents the AGP aperture. 192171433Sanholt * 193171433Sanholt * If not called, the default AGP aperture resource of AGP_APBASE will 194171433Sanholt * be used. Must be called before agp_generic_attach(). 195171433Sanholt */ 196171433Sanholtvoid 197171433Sanholtagp_set_aperture_resource(device_t dev, int rid) 198171433Sanholt{ 199171433Sanholt struct agp_softc *sc = device_get_softc(dev); 200171433Sanholt 201171433Sanholt sc->as_aperture_rid = rid; 202171433Sanholt} 203171433Sanholt 20461452Sdfrint 20561452Sdfragp_generic_attach(device_t dev) 20661452Sdfr{ 20761452Sdfr struct agp_softc *sc = device_get_softc(dev); 208171433Sanholt int i; 209163362Stanimura u_int memsize; 21061452Sdfr 21161452Sdfr /* 212171433Sanholt * Find and map the aperture, RF_SHAREABLE for DRM but not RF_ACTIVE 213171433Sanholt * because the kernel doesn't need to map it. 21461452Sdfr */ 215171433Sanholt 216214603Snwhitehorn if (sc->as_aperture_rid != -1) { 217214603Snwhitehorn if (sc->as_aperture_rid == 0) 218214603Snwhitehorn sc->as_aperture_rid = AGP_APBASE; 21961452Sdfr 220214603Snwhitehorn sc->as_aperture = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 221214603Snwhitehorn &sc->as_aperture_rid, RF_SHAREABLE); 222214603Snwhitehorn if (!sc->as_aperture) 223214603Snwhitehorn return ENOMEM; 224214603Snwhitehorn } 225214603Snwhitehorn 22661452Sdfr /* 22761452Sdfr * Work out an upper bound for agp memory allocation. This 22861452Sdfr * uses a heurisitc table from the Linux driver. 22961452Sdfr */ 230238172Smarcel memsize = ptoa(realmem) >> 20; 23161452Sdfr for (i = 0; i < agp_max_size; i++) { 23261452Sdfr if (memsize <= agp_max[i][0]) 23361452Sdfr break; 23461452Sdfr } 235235782Skib if (i == agp_max_size) 236235782Skib i = agp_max_size - 1; 23761452Sdfr sc->as_maxmem = agp_max[i][1] << 20U; 23861452Sdfr 23961452Sdfr /* 24061452Sdfr * The lock is used to prevent re-entry to 24161452Sdfr * agp_generic_bind_memory() since that function can sleep. 24261452Sdfr */ 243129579Smux mtx_init(&sc->as_lock, "agp lock", NULL, MTX_DEF); 24461452Sdfr 24561452Sdfr /* 24661452Sdfr * Initialise stuff for the userland device. 24761452Sdfr */ 24861452Sdfr agp_devclass = devclass_find("agp"); 24961452Sdfr TAILQ_INIT(&sc->as_memory); 25061452Sdfr sc->as_nextid = 1; 25161452Sdfr 25261452Sdfr sc->as_devnode = make_dev(&agp_cdevsw, 253191057Sed 0, UID_ROOT, GID_WHEEL, 0600, "agpgart"); 254191057Sed sc->as_devnode->si_drv1 = dev; 25561452Sdfr 25661452Sdfr return 0; 25761452Sdfr} 25861452Sdfr 259173203Sjhbvoid 260173203Sjhbagp_free_cdev(device_t dev) 26161452Sdfr{ 26261452Sdfr struct agp_softc *sc = device_get_softc(dev); 263153562Sjhb 264153562Sjhb destroy_dev(sc->as_devnode); 265173203Sjhb} 266173203Sjhb 267173203Sjhbvoid 268173203Sjhbagp_free_res(device_t dev) 269173203Sjhb{ 270173203Sjhb struct agp_softc *sc = device_get_softc(dev); 271173203Sjhb 272214603Snwhitehorn if (sc->as_aperture != NULL) 273214603Snwhitehorn bus_release_resource(dev, SYS_RES_MEMORY, sc->as_aperture_rid, 274214603Snwhitehorn sc->as_aperture); 275129579Smux mtx_destroy(&sc->as_lock); 276173203Sjhb} 277173203Sjhb 278173203Sjhbint 279173203Sjhbagp_generic_detach(device_t dev) 280173203Sjhb{ 281173203Sjhb 282173203Sjhb agp_free_cdev(dev); 283173203Sjhb agp_free_res(dev); 28461452Sdfr return 0; 28561452Sdfr} 28661452Sdfr 287171433Sanholt/** 288171433Sanholt * Default AGP aperture size detection which simply returns the size of 289171433Sanholt * the aperture's PCI resource. 290171433Sanholt */ 291189578Simpu_int32_t 292171433Sanholtagp_generic_get_aperture(device_t dev) 293171433Sanholt{ 294171433Sanholt struct agp_softc *sc = device_get_softc(dev); 295171433Sanholt 296171433Sanholt return rman_get_size(sc->as_aperture); 297171433Sanholt} 298171433Sanholt 299171433Sanholt/** 300171433Sanholt * Default AGP aperture size setting function, which simply doesn't allow 301171433Sanholt * changes to resource size. 302171433Sanholt */ 303171433Sanholtint 304171433Sanholtagp_generic_set_aperture(device_t dev, u_int32_t aperture) 305171433Sanholt{ 306171433Sanholt u_int32_t current_aperture; 307171433Sanholt 308171433Sanholt current_aperture = AGP_GET_APERTURE(dev); 309171433Sanholt if (current_aperture != aperture) 310171433Sanholt return EINVAL; 311171433Sanholt else 312171433Sanholt return 0; 313171433Sanholt} 314171433Sanholt 315121440Sjhb/* 316121440Sjhb * This does the enable logic for v3, with the same topology 317121440Sjhb * restrictions as in place for v2 -- one bus, one device on the bus. 318121440Sjhb */ 319121440Sjhbstatic int 320121440Sjhbagp_v3_enable(device_t dev, device_t mdev, u_int32_t mode) 32161452Sdfr{ 32261452Sdfr u_int32_t tstatus, mstatus; 32361452Sdfr u_int32_t command; 324121440Sjhb int rq, sba, fw, rate, arqsz, cal; 32561452Sdfr 326121440Sjhb tstatus = pci_read_config(dev, agp_find_caps(dev) + AGP_STATUS, 4); 327121440Sjhb mstatus = pci_read_config(mdev, agp_find_caps(mdev) + AGP_STATUS, 4); 32861452Sdfr 329121440Sjhb /* Set RQ to the min of mode, tstatus and mstatus */ 330121440Sjhb rq = AGP_MODE_GET_RQ(mode); 331121440Sjhb if (AGP_MODE_GET_RQ(tstatus) < rq) 332121440Sjhb rq = AGP_MODE_GET_RQ(tstatus); 333121440Sjhb if (AGP_MODE_GET_RQ(mstatus) < rq) 334121440Sjhb rq = AGP_MODE_GET_RQ(mstatus); 335121440Sjhb 336121440Sjhb /* 337121440Sjhb * ARQSZ - Set the value to the maximum one. 338121440Sjhb * Don't allow the mode register to override values. 339121440Sjhb */ 340121440Sjhb arqsz = AGP_MODE_GET_ARQSZ(mode); 341121440Sjhb if (AGP_MODE_GET_ARQSZ(tstatus) > rq) 342121440Sjhb rq = AGP_MODE_GET_ARQSZ(tstatus); 343121440Sjhb if (AGP_MODE_GET_ARQSZ(mstatus) > rq) 344121440Sjhb rq = AGP_MODE_GET_ARQSZ(mstatus); 345121440Sjhb 346121440Sjhb /* Calibration cycle - don't allow override by mode register */ 347121440Sjhb cal = AGP_MODE_GET_CAL(tstatus); 348121440Sjhb if (AGP_MODE_GET_CAL(mstatus) < cal) 349121440Sjhb cal = AGP_MODE_GET_CAL(mstatus); 350121440Sjhb 351121440Sjhb /* SBA must be supported for AGP v3. */ 352121440Sjhb sba = 1; 353121440Sjhb 354121440Sjhb /* Set FW if all three support it. */ 355121440Sjhb fw = (AGP_MODE_GET_FW(tstatus) 356121440Sjhb & AGP_MODE_GET_FW(mstatus) 357121440Sjhb & AGP_MODE_GET_FW(mode)); 358121440Sjhb 359121440Sjhb /* Figure out the max rate */ 360121440Sjhb rate = (AGP_MODE_GET_RATE(tstatus) 361121440Sjhb & AGP_MODE_GET_RATE(mstatus) 362121440Sjhb & AGP_MODE_GET_RATE(mode)); 363121440Sjhb if (rate & AGP_MODE_V3_RATE_8x) 364121440Sjhb rate = AGP_MODE_V3_RATE_8x; 365121440Sjhb else 366121440Sjhb rate = AGP_MODE_V3_RATE_4x; 367121440Sjhb if (bootverbose) 368121440Sjhb device_printf(dev, "Setting AGP v3 mode %d\n", rate * 4); 369121440Sjhb 370121440Sjhb pci_write_config(dev, agp_find_caps(dev) + AGP_COMMAND, 0, 4); 371121440Sjhb 372121440Sjhb /* Construct the new mode word and tell the hardware */ 373161222Sjkim command = 0; 374121440Sjhb command = AGP_MODE_SET_RQ(0, rq); 375121440Sjhb command = AGP_MODE_SET_ARQSZ(command, arqsz); 376121440Sjhb command = AGP_MODE_SET_CAL(command, cal); 377121440Sjhb command = AGP_MODE_SET_SBA(command, sba); 378121440Sjhb command = AGP_MODE_SET_FW(command, fw); 379121440Sjhb command = AGP_MODE_SET_RATE(command, rate); 380161222Sjkim command = AGP_MODE_SET_MODE_3(command, 1); 381121440Sjhb command = AGP_MODE_SET_AGP(command, 1); 382121440Sjhb pci_write_config(dev, agp_find_caps(dev) + AGP_COMMAND, command, 4); 383121440Sjhb pci_write_config(mdev, agp_find_caps(mdev) + AGP_COMMAND, command, 4); 384121440Sjhb 385121440Sjhb return 0; 386121440Sjhb} 387121440Sjhb 388121440Sjhbstatic int 389121440Sjhbagp_v2_enable(device_t dev, device_t mdev, u_int32_t mode) 390121440Sjhb{ 391121440Sjhb u_int32_t tstatus, mstatus; 392121440Sjhb u_int32_t command; 393121440Sjhb int rq, sba, fw, rate; 394121440Sjhb 39561452Sdfr tstatus = pci_read_config(dev, agp_find_caps(dev) + AGP_STATUS, 4); 39661452Sdfr mstatus = pci_read_config(mdev, agp_find_caps(mdev) + AGP_STATUS, 4); 39761452Sdfr 39861452Sdfr /* Set RQ to the min of mode, tstatus and mstatus */ 39961452Sdfr rq = AGP_MODE_GET_RQ(mode); 40061452Sdfr if (AGP_MODE_GET_RQ(tstatus) < rq) 40161452Sdfr rq = AGP_MODE_GET_RQ(tstatus); 40261452Sdfr if (AGP_MODE_GET_RQ(mstatus) < rq) 40361452Sdfr rq = AGP_MODE_GET_RQ(mstatus); 40461452Sdfr 40561452Sdfr /* Set SBA if all three can deal with SBA */ 40661452Sdfr sba = (AGP_MODE_GET_SBA(tstatus) 40761452Sdfr & AGP_MODE_GET_SBA(mstatus) 40861452Sdfr & AGP_MODE_GET_SBA(mode)); 40961452Sdfr 41061452Sdfr /* Similar for FW */ 41161452Sdfr fw = (AGP_MODE_GET_FW(tstatus) 41261452Sdfr & AGP_MODE_GET_FW(mstatus) 41361452Sdfr & AGP_MODE_GET_FW(mode)); 41461452Sdfr 41561452Sdfr /* Figure out the max rate */ 41661452Sdfr rate = (AGP_MODE_GET_RATE(tstatus) 41761452Sdfr & AGP_MODE_GET_RATE(mstatus) 41861452Sdfr & AGP_MODE_GET_RATE(mode)); 419121440Sjhb if (rate & AGP_MODE_V2_RATE_4x) 420121440Sjhb rate = AGP_MODE_V2_RATE_4x; 421121440Sjhb else if (rate & AGP_MODE_V2_RATE_2x) 422121440Sjhb rate = AGP_MODE_V2_RATE_2x; 42361452Sdfr else 424121440Sjhb rate = AGP_MODE_V2_RATE_1x; 425121440Sjhb if (bootverbose) 426121440Sjhb device_printf(dev, "Setting AGP v2 mode %d\n", rate); 42761452Sdfr 42861452Sdfr /* Construct the new mode word and tell the hardware */ 429161222Sjkim command = 0; 43061452Sdfr command = AGP_MODE_SET_RQ(0, rq); 43161452Sdfr command = AGP_MODE_SET_SBA(command, sba); 43261452Sdfr command = AGP_MODE_SET_FW(command, fw); 43361452Sdfr command = AGP_MODE_SET_RATE(command, rate); 43461452Sdfr command = AGP_MODE_SET_AGP(command, 1); 43561452Sdfr pci_write_config(dev, agp_find_caps(dev) + AGP_COMMAND, command, 4); 43661452Sdfr pci_write_config(mdev, agp_find_caps(mdev) + AGP_COMMAND, command, 4); 43761452Sdfr 43861452Sdfr return 0; 43961452Sdfr} 44061452Sdfr 441121440Sjhbint 442121440Sjhbagp_generic_enable(device_t dev, u_int32_t mode) 443121440Sjhb{ 444121440Sjhb device_t mdev = agp_find_display(); 445121440Sjhb u_int32_t tstatus, mstatus; 446121440Sjhb 447121440Sjhb if (!mdev) { 448121440Sjhb AGP_DPF("can't find display\n"); 449121440Sjhb return ENXIO; 450121440Sjhb } 451121440Sjhb 452121440Sjhb tstatus = pci_read_config(dev, agp_find_caps(dev) + AGP_STATUS, 4); 453121440Sjhb mstatus = pci_read_config(mdev, agp_find_caps(mdev) + AGP_STATUS, 4); 454121440Sjhb 455121440Sjhb /* 456121440Sjhb * Check display and bridge for AGP v3 support. AGP v3 allows 457121440Sjhb * more variety in topology than v2, e.g. multiple AGP devices 458121440Sjhb * attached to one bridge, or multiple AGP bridges in one 459121440Sjhb * system. This doesn't attempt to address those situations, 460121440Sjhb * but should work fine for a classic single AGP slot system 461121440Sjhb * with AGP v3. 462121440Sjhb */ 463161222Sjkim if (AGP_MODE_GET_MODE_3(mode) && 464161222Sjkim AGP_MODE_GET_MODE_3(tstatus) && 465161222Sjkim AGP_MODE_GET_MODE_3(mstatus)) 466121440Sjhb return (agp_v3_enable(dev, mdev, mode)); 467121440Sjhb else 468121440Sjhb return (agp_v2_enable(dev, mdev, mode)); 469121440Sjhb} 470121440Sjhb 47161452Sdfrstruct agp_memory * 47261452Sdfragp_generic_alloc_memory(device_t dev, int type, vm_size_t size) 47361452Sdfr{ 47461452Sdfr struct agp_softc *sc = device_get_softc(dev); 47561452Sdfr struct agp_memory *mem; 47661452Sdfr 47761452Sdfr if ((size & (AGP_PAGE_SIZE - 1)) != 0) 47861452Sdfr return 0; 47961452Sdfr 480275406Stijl if (size > sc->as_maxmem - sc->as_allocated) 48161452Sdfr return 0; 48261452Sdfr 48363010Sdfr if (type != 0) { 48463010Sdfr printf("agp_generic_alloc_memory: unsupported type %d\n", 48563010Sdfr type); 48663010Sdfr return 0; 48763010Sdfr } 48863010Sdfr 489111119Simp mem = malloc(sizeof *mem, M_AGP, M_WAITOK); 49061452Sdfr mem->am_id = sc->as_nextid++; 49161452Sdfr mem->am_size = size; 49263010Sdfr mem->am_type = 0; 49361452Sdfr mem->am_obj = vm_object_allocate(OBJT_DEFAULT, atop(round_page(size))); 49461452Sdfr mem->am_physical = 0; 49561452Sdfr mem->am_offset = 0; 49661452Sdfr mem->am_is_bound = 0; 49761452Sdfr TAILQ_INSERT_TAIL(&sc->as_memory, mem, am_link); 49861452Sdfr sc->as_allocated += size; 49961452Sdfr 50061452Sdfr return mem; 50161452Sdfr} 50261452Sdfr 50361452Sdfrint 50461452Sdfragp_generic_free_memory(device_t dev, struct agp_memory *mem) 50561452Sdfr{ 50661452Sdfr struct agp_softc *sc = device_get_softc(dev); 50761452Sdfr 50861452Sdfr if (mem->am_is_bound) 50961452Sdfr return EBUSY; 51061452Sdfr 51161452Sdfr sc->as_allocated -= mem->am_size; 51261452Sdfr TAILQ_REMOVE(&sc->as_memory, mem, am_link); 51361452Sdfr vm_object_deallocate(mem->am_obj); 51461452Sdfr free(mem, M_AGP); 51561452Sdfr return 0; 51661452Sdfr} 51761452Sdfr 51861452Sdfrint 51961452Sdfragp_generic_bind_memory(device_t dev, struct agp_memory *mem, 52061452Sdfr vm_offset_t offset) 52161452Sdfr{ 52261452Sdfr struct agp_softc *sc = device_get_softc(dev); 52361452Sdfr vm_offset_t i, j, k; 52461452Sdfr vm_page_t m; 52561452Sdfr int error; 52661452Sdfr 527129601Smux /* Do some sanity checks first. */ 528190169Srnoland if ((offset & (AGP_PAGE_SIZE - 1)) != 0 || 529129601Smux offset + mem->am_size > AGP_GET_APERTURE(dev)) { 53061452Sdfr device_printf(dev, "binding memory at bad offset %#x\n", 531129601Smux (int)offset); 53261452Sdfr return EINVAL; 53361452Sdfr } 53461452Sdfr 53561452Sdfr /* 536129601Smux * Allocate the pages early, before acquiring the lock, 537209793Skib * because vm_page_grab() may sleep and we can't hold a mutex 538209793Skib * while sleeping. 53961452Sdfr */ 540248084Sattilio VM_OBJECT_WLOCK(mem->am_obj); 54161452Sdfr for (i = 0; i < mem->am_size; i += PAGE_SIZE) { 54261452Sdfr /* 54361452Sdfr * Find a page from the object and wire it 54461452Sdfr * down. This page will be mapped using one or more 54561452Sdfr * entries in the GATT (assuming that PAGE_SIZE >= 54661452Sdfr * AGP_PAGE_SIZE. If this is the first call to bind, 54761452Sdfr * the pages will be allocated and zeroed. 54861452Sdfr */ 54961452Sdfr m = vm_page_grab(mem->am_obj, OFF_TO_IDX(i), 550254649Skib VM_ALLOC_WIRED | VM_ALLOC_ZERO); 551188247Swkoszek AGP_DPF("found page pa=%#jx\n", (uintmax_t)VM_PAGE_TO_PHYS(m)); 552129601Smux } 553248084Sattilio VM_OBJECT_WUNLOCK(mem->am_obj); 55461452Sdfr 555129601Smux mtx_lock(&sc->as_lock); 556129601Smux 557129601Smux if (mem->am_is_bound) { 558129601Smux device_printf(dev, "memory already bound\n"); 559129601Smux error = EINVAL; 560248084Sattilio VM_OBJECT_WLOCK(mem->am_obj); 561186433Skib i = 0; 562129601Smux goto bad; 563129601Smux } 564129601Smux 565129601Smux /* 566129601Smux * Bind the individual pages and flush the chipset's 567129601Smux * TLB. 568129601Smux */ 569248084Sattilio VM_OBJECT_WLOCK(mem->am_obj); 570129601Smux for (i = 0; i < mem->am_size; i += PAGE_SIZE) { 571129601Smux m = vm_page_lookup(mem->am_obj, OFF_TO_IDX(i)); 572129601Smux 57361452Sdfr /* 57461452Sdfr * Install entries in the GATT, making sure that if 57561452Sdfr * AGP_PAGE_SIZE < PAGE_SIZE and mem->am_size is not 57661452Sdfr * aligned to PAGE_SIZE, we don't modify too many GATT 57761452Sdfr * entries. 57861452Sdfr */ 57961452Sdfr for (j = 0; j < PAGE_SIZE && i + j < mem->am_size; 58061452Sdfr j += AGP_PAGE_SIZE) { 58161452Sdfr vm_offset_t pa = VM_PAGE_TO_PHYS(m) + j; 582188247Swkoszek AGP_DPF("binding offset %#jx to pa %#jx\n", 583188247Swkoszek (uintmax_t)offset + i + j, (uintmax_t)pa); 58461452Sdfr error = AGP_BIND_PAGE(dev, offset + i + j, pa); 58561452Sdfr if (error) { 58661452Sdfr /* 58761452Sdfr * Bail out. Reverse all the mappings 58861452Sdfr * and unwire the pages. 58961452Sdfr */ 59061452Sdfr for (k = 0; k < i + j; k += AGP_PAGE_SIZE) 59161452Sdfr AGP_UNBIND_PAGE(dev, offset + k); 592129601Smux goto bad; 59361452Sdfr } 59461452Sdfr } 595254138Sattilio vm_page_xunbusy(m); 59661452Sdfr } 597248084Sattilio VM_OBJECT_WUNLOCK(mem->am_obj); 59861452Sdfr 59961452Sdfr /* 60061452Sdfr * Make sure the chipset gets the new mappings. 60161452Sdfr */ 60261452Sdfr AGP_FLUSH_TLB(dev); 60361452Sdfr 60461452Sdfr mem->am_offset = offset; 60561452Sdfr mem->am_is_bound = 1; 60661452Sdfr 607129579Smux mtx_unlock(&sc->as_lock); 60861452Sdfr 60961452Sdfr return 0; 610129601Smuxbad: 611129601Smux mtx_unlock(&sc->as_lock); 612248084Sattilio VM_OBJECT_ASSERT_WLOCKED(mem->am_obj); 613186433Skib for (k = 0; k < mem->am_size; k += PAGE_SIZE) { 614186433Skib m = vm_page_lookup(mem->am_obj, OFF_TO_IDX(k)); 615186433Skib if (k >= i) 616254138Sattilio vm_page_xunbusy(m); 617207574Salc vm_page_lock(m); 618129601Smux vm_page_unwire(m, 0); 619207574Salc vm_page_unlock(m); 620129601Smux } 621248084Sattilio VM_OBJECT_WUNLOCK(mem->am_obj); 622129601Smux 623129601Smux return error; 62461452Sdfr} 62561452Sdfr 62661452Sdfrint 62761452Sdfragp_generic_unbind_memory(device_t dev, struct agp_memory *mem) 62861452Sdfr{ 62961452Sdfr struct agp_softc *sc = device_get_softc(dev); 63061452Sdfr vm_page_t m; 63161452Sdfr int i; 63261452Sdfr 633129579Smux mtx_lock(&sc->as_lock); 63461452Sdfr 63561452Sdfr if (!mem->am_is_bound) { 63661452Sdfr device_printf(dev, "memory is not bound\n"); 637129579Smux mtx_unlock(&sc->as_lock); 63861452Sdfr return EINVAL; 63961452Sdfr } 64061452Sdfr 64161452Sdfr 64261452Sdfr /* 64361452Sdfr * Unbind the individual pages and flush the chipset's 64461452Sdfr * TLB. Unwire the pages so they can be swapped. 64561452Sdfr */ 64661452Sdfr for (i = 0; i < mem->am_size; i += AGP_PAGE_SIZE) 64761452Sdfr AGP_UNBIND_PAGE(dev, mem->am_offset + i); 648275406Stijl 649275406Stijl AGP_FLUSH_TLB(dev); 650275406Stijl 651248084Sattilio VM_OBJECT_WLOCK(mem->am_obj); 65261452Sdfr for (i = 0; i < mem->am_size; i += PAGE_SIZE) { 65361452Sdfr m = vm_page_lookup(mem->am_obj, atop(i)); 654207574Salc vm_page_lock(m); 65561452Sdfr vm_page_unwire(m, 0); 656207574Salc vm_page_unlock(m); 65761452Sdfr } 658248084Sattilio VM_OBJECT_WUNLOCK(mem->am_obj); 65961452Sdfr 66061452Sdfr mem->am_offset = 0; 66161452Sdfr mem->am_is_bound = 0; 66261452Sdfr 663129579Smux mtx_unlock(&sc->as_lock); 66461452Sdfr 66561452Sdfr return 0; 66661452Sdfr} 66761452Sdfr 66861452Sdfr/* Helper functions for implementing user/kernel api */ 66961452Sdfr 67061452Sdfrstatic int 67161452Sdfragp_acquire_helper(device_t dev, enum agp_acquire_state state) 67261452Sdfr{ 67361452Sdfr struct agp_softc *sc = device_get_softc(dev); 67461452Sdfr 67561452Sdfr if (sc->as_state != AGP_ACQUIRE_FREE) 67661452Sdfr return EBUSY; 67761452Sdfr sc->as_state = state; 67861452Sdfr 67961452Sdfr return 0; 68061452Sdfr} 68161452Sdfr 68261452Sdfrstatic int 68361452Sdfragp_release_helper(device_t dev, enum agp_acquire_state state) 68461452Sdfr{ 68561452Sdfr struct agp_softc *sc = device_get_softc(dev); 68661452Sdfr 68761452Sdfr if (sc->as_state == AGP_ACQUIRE_FREE) 68861452Sdfr return 0; 68961452Sdfr 69061452Sdfr if (sc->as_state != state) 69161452Sdfr return EBUSY; 69261452Sdfr 69361452Sdfr sc->as_state = AGP_ACQUIRE_FREE; 69461452Sdfr return 0; 69561452Sdfr} 69661452Sdfr 69761452Sdfrstatic struct agp_memory * 69861452Sdfragp_find_memory(device_t dev, int id) 69961452Sdfr{ 70061452Sdfr struct agp_softc *sc = device_get_softc(dev); 70161452Sdfr struct agp_memory *mem; 70261452Sdfr 70361452Sdfr AGP_DPF("searching for memory block %d\n", id); 70461452Sdfr TAILQ_FOREACH(mem, &sc->as_memory, am_link) { 70561452Sdfr AGP_DPF("considering memory block %d\n", mem->am_id); 70661452Sdfr if (mem->am_id == id) 70761452Sdfr return mem; 70861452Sdfr } 70961452Sdfr return 0; 71061452Sdfr} 71161452Sdfr 71261452Sdfr/* Implementation of the userland ioctl api */ 71361452Sdfr 71461452Sdfrstatic int 71561452Sdfragp_info_user(device_t dev, agp_info *info) 71661452Sdfr{ 71761452Sdfr struct agp_softc *sc = device_get_softc(dev); 71861452Sdfr 71961452Sdfr bzero(info, sizeof *info); 72061452Sdfr info->bridge_id = pci_get_devid(dev); 72161452Sdfr info->agp_mode = 72261452Sdfr pci_read_config(dev, agp_find_caps(dev) + AGP_STATUS, 4); 723214603Snwhitehorn if (sc->as_aperture) 724214603Snwhitehorn info->aper_base = rman_get_start(sc->as_aperture); 725214603Snwhitehorn else 726214603Snwhitehorn info->aper_base = 0; 72761452Sdfr info->aper_size = AGP_GET_APERTURE(dev) >> 20; 72861452Sdfr info->pg_total = info->pg_system = sc->as_maxmem >> AGP_PAGE_SHIFT; 72961452Sdfr info->pg_used = sc->as_allocated >> AGP_PAGE_SHIFT; 73061452Sdfr 73161452Sdfr return 0; 73261452Sdfr} 73361452Sdfr 73461452Sdfrstatic int 73561452Sdfragp_setup_user(device_t dev, agp_setup *setup) 73661452Sdfr{ 73761452Sdfr return AGP_ENABLE(dev, setup->agp_mode); 73861452Sdfr} 73961452Sdfr 74061452Sdfrstatic int 74161452Sdfragp_allocate_user(device_t dev, agp_allocate *alloc) 74261452Sdfr{ 74361452Sdfr struct agp_memory *mem; 74461452Sdfr 74561452Sdfr mem = AGP_ALLOC_MEMORY(dev, 74661452Sdfr alloc->type, 74761452Sdfr alloc->pg_count << AGP_PAGE_SHIFT); 74863010Sdfr if (mem) { 74963010Sdfr alloc->key = mem->am_id; 75063010Sdfr alloc->physical = mem->am_physical; 75163010Sdfr return 0; 75263010Sdfr } else { 75363010Sdfr return ENOMEM; 75463010Sdfr } 75561452Sdfr} 75661452Sdfr 75761452Sdfrstatic int 75861452Sdfragp_deallocate_user(device_t dev, int id) 75961452Sdfr{ 760201758Smbr struct agp_memory *mem = agp_find_memory(dev, id); 76161452Sdfr 76261452Sdfr if (mem) { 76361452Sdfr AGP_FREE_MEMORY(dev, mem); 76461452Sdfr return 0; 76561452Sdfr } else { 76661452Sdfr return ENOENT; 76761452Sdfr } 76861452Sdfr} 76961452Sdfr 77061452Sdfrstatic int 77161452Sdfragp_bind_user(device_t dev, agp_bind *bind) 77261452Sdfr{ 77361452Sdfr struct agp_memory *mem = agp_find_memory(dev, bind->key); 77461452Sdfr 77561452Sdfr if (!mem) 77661452Sdfr return ENOENT; 77761452Sdfr 77861452Sdfr return AGP_BIND_MEMORY(dev, mem, bind->pg_start << AGP_PAGE_SHIFT); 77961452Sdfr} 78061452Sdfr 78161452Sdfrstatic int 78261452Sdfragp_unbind_user(device_t dev, agp_unbind *unbind) 78361452Sdfr{ 78461452Sdfr struct agp_memory *mem = agp_find_memory(dev, unbind->key); 78561452Sdfr 78661452Sdfr if (!mem) 78761452Sdfr return ENOENT; 78861452Sdfr 78961452Sdfr return AGP_UNBIND_MEMORY(dev, mem); 79061452Sdfr} 79161452Sdfr 79261452Sdfrstatic int 793235782Skibagp_chipset_flush(device_t dev) 794235782Skib{ 795235782Skib 796235782Skib return (AGP_CHIPSET_FLUSH(dev)); 797235782Skib} 798235782Skib 799235782Skibstatic int 800130585Sphkagp_open(struct cdev *kdev, int oflags, int devtype, struct thread *td) 80161452Sdfr{ 802191057Sed device_t dev = kdev->si_drv1; 80361452Sdfr struct agp_softc *sc = device_get_softc(dev); 80461452Sdfr 80561452Sdfr if (!sc->as_isopen) { 80661452Sdfr sc->as_isopen = 1; 80761452Sdfr device_busy(dev); 80861452Sdfr } 80961452Sdfr 81061452Sdfr return 0; 81161452Sdfr} 81261452Sdfr 81361452Sdfrstatic int 814130585Sphkagp_close(struct cdev *kdev, int fflag, int devtype, struct thread *td) 81561452Sdfr{ 816191057Sed device_t dev = kdev->si_drv1; 81761452Sdfr struct agp_softc *sc = device_get_softc(dev); 81886976Sru struct agp_memory *mem; 81961452Sdfr 82061452Sdfr /* 82161452Sdfr * Clear the GATT and force release on last close 82261452Sdfr */ 82386976Sru while ((mem = TAILQ_FIRST(&sc->as_memory)) != 0) { 82486976Sru if (mem->am_is_bound) 82586976Sru AGP_UNBIND_MEMORY(dev, mem); 82686976Sru AGP_FREE_MEMORY(dev, mem); 82786976Sru } 82861452Sdfr if (sc->as_state == AGP_ACQUIRE_USER) 82961452Sdfr agp_release_helper(dev, AGP_ACQUIRE_USER); 83061452Sdfr sc->as_isopen = 0; 83161452Sdfr device_unbusy(dev); 83261452Sdfr 83361452Sdfr return 0; 83461452Sdfr} 83561452Sdfr 83661452Sdfrstatic int 837130585Sphkagp_ioctl(struct cdev *kdev, u_long cmd, caddr_t data, int fflag, struct thread *td) 83861452Sdfr{ 839191057Sed device_t dev = kdev->si_drv1; 84061452Sdfr 84161452Sdfr switch (cmd) { 84261452Sdfr case AGPIOC_INFO: 84361452Sdfr return agp_info_user(dev, (agp_info *) data); 84461452Sdfr 84561452Sdfr case AGPIOC_ACQUIRE: 84661452Sdfr return agp_acquire_helper(dev, AGP_ACQUIRE_USER); 84761452Sdfr 84861452Sdfr case AGPIOC_RELEASE: 84961452Sdfr return agp_release_helper(dev, AGP_ACQUIRE_USER); 85061452Sdfr 85161452Sdfr case AGPIOC_SETUP: 85261452Sdfr return agp_setup_user(dev, (agp_setup *)data); 85361452Sdfr 85461452Sdfr case AGPIOC_ALLOCATE: 85561452Sdfr return agp_allocate_user(dev, (agp_allocate *)data); 85661452Sdfr 85761452Sdfr case AGPIOC_DEALLOCATE: 85861452Sdfr return agp_deallocate_user(dev, *(int *) data); 85961452Sdfr 86061452Sdfr case AGPIOC_BIND: 86161452Sdfr return agp_bind_user(dev, (agp_bind *)data); 86261452Sdfr 86361452Sdfr case AGPIOC_UNBIND: 86461452Sdfr return agp_unbind_user(dev, (agp_unbind *)data); 86561452Sdfr 866235782Skib case AGPIOC_CHIPSET_FLUSH: 867235782Skib return agp_chipset_flush(dev); 86861452Sdfr } 86961452Sdfr 87061452Sdfr return EINVAL; 87161452Sdfr} 87261452Sdfr 87361452Sdfrstatic int 874201223Srnolandagp_mmap(struct cdev *kdev, vm_ooffset_t offset, vm_paddr_t *paddr, 875201223Srnoland int prot, vm_memattr_t *memattr) 87661452Sdfr{ 877191057Sed device_t dev = kdev->si_drv1; 87861452Sdfr struct agp_softc *sc = device_get_softc(dev); 87961452Sdfr 88061452Sdfr if (offset > AGP_GET_APERTURE(dev)) 88161452Sdfr return -1; 882214603Snwhitehorn if (sc->as_aperture == NULL) 883214603Snwhitehorn return -1; 884111462Smux *paddr = rman_get_start(sc->as_aperture) + offset; 885111462Smux return 0; 88661452Sdfr} 88761452Sdfr 88861452Sdfr/* Implementation of the kernel api */ 88961452Sdfr 89061452Sdfrdevice_t 89161452Sdfragp_find_device() 89261452Sdfr{ 893154486Sjhb device_t *children, child; 894153568Sjhb int i, count; 895153568Sjhb 89661452Sdfr if (!agp_devclass) 897153568Sjhb return NULL; 898153568Sjhb if (devclass_get_devices(agp_devclass, &children, &count) != 0) 899153568Sjhb return NULL; 900154486Sjhb child = NULL; 901153568Sjhb for (i = 0; i < count; i++) { 902154486Sjhb if (device_is_attached(children[i])) { 903154486Sjhb child = children[i]; 904154486Sjhb break; 905154486Sjhb } 906153568Sjhb } 907154486Sjhb free(children, M_TEMP); 908154486Sjhb return child; 90961452Sdfr} 91061452Sdfr 91161452Sdfrenum agp_acquire_state 91261452Sdfragp_state(device_t dev) 91361452Sdfr{ 91461452Sdfr struct agp_softc *sc = device_get_softc(dev); 91561452Sdfr return sc->as_state; 91661452Sdfr} 91761452Sdfr 91861452Sdfrvoid 91961452Sdfragp_get_info(device_t dev, struct agp_info *info) 92061452Sdfr{ 92161452Sdfr struct agp_softc *sc = device_get_softc(dev); 92261452Sdfr 92361452Sdfr info->ai_mode = 92461452Sdfr pci_read_config(dev, agp_find_caps(dev) + AGP_STATUS, 4); 925214603Snwhitehorn if (sc->as_aperture != NULL) 926214603Snwhitehorn info->ai_aperture_base = rman_get_start(sc->as_aperture); 927214603Snwhitehorn else 928214603Snwhitehorn info->ai_aperture_base = 0; 929214603Snwhitehorn info->ai_aperture_size = AGP_GET_APERTURE(dev); 93061452Sdfr info->ai_memory_allowed = sc->as_maxmem; 93161452Sdfr info->ai_memory_used = sc->as_allocated; 93261452Sdfr} 93361452Sdfr 93461452Sdfrint 93561452Sdfragp_acquire(device_t dev) 93661452Sdfr{ 93761452Sdfr return agp_acquire_helper(dev, AGP_ACQUIRE_KERNEL); 93861452Sdfr} 93961452Sdfr 94061452Sdfrint 94161452Sdfragp_release(device_t dev) 94261452Sdfr{ 94361452Sdfr return agp_release_helper(dev, AGP_ACQUIRE_KERNEL); 94461452Sdfr} 94561452Sdfr 94661452Sdfrint 94761452Sdfragp_enable(device_t dev, u_int32_t mode) 94861452Sdfr{ 94961452Sdfr return AGP_ENABLE(dev, mode); 95061452Sdfr} 95161452Sdfr 95261452Sdfrvoid *agp_alloc_memory(device_t dev, int type, vm_size_t bytes) 95361452Sdfr{ 95461452Sdfr return (void *) AGP_ALLOC_MEMORY(dev, type, bytes); 95561452Sdfr} 95661452Sdfr 95761452Sdfrvoid agp_free_memory(device_t dev, void *handle) 95861452Sdfr{ 95961452Sdfr struct agp_memory *mem = (struct agp_memory *) handle; 96061452Sdfr AGP_FREE_MEMORY(dev, mem); 96161452Sdfr} 96261452Sdfr 96361452Sdfrint agp_bind_memory(device_t dev, void *handle, vm_offset_t offset) 96461452Sdfr{ 96561452Sdfr struct agp_memory *mem = (struct agp_memory *) handle; 96661452Sdfr return AGP_BIND_MEMORY(dev, mem, offset); 96761452Sdfr} 96861452Sdfr 96961452Sdfrint agp_unbind_memory(device_t dev, void *handle) 97061452Sdfr{ 97161452Sdfr struct agp_memory *mem = (struct agp_memory *) handle; 97261452Sdfr return AGP_UNBIND_MEMORY(dev, mem); 97361452Sdfr} 97461452Sdfr 97561452Sdfrvoid agp_memory_info(device_t dev, void *handle, struct 97661452Sdfr agp_memory_info *mi) 97761452Sdfr{ 97861452Sdfr struct agp_memory *mem = (struct agp_memory *) handle; 97961452Sdfr 98061452Sdfr mi->ami_size = mem->am_size; 98161452Sdfr mi->ami_physical = mem->am_physical; 98261452Sdfr mi->ami_offset = mem->am_offset; 98361452Sdfr mi->ami_is_bound = mem->am_is_bound; 98461452Sdfr} 985275406Stijl 986275406Stijlint 987275406Stijlagp_bind_pages(device_t dev, vm_page_t *pages, vm_size_t size, 988275406Stijl vm_offset_t offset) 989275406Stijl{ 990275406Stijl struct agp_softc *sc; 991275406Stijl vm_offset_t i, j, k, pa; 992275406Stijl vm_page_t m; 993275406Stijl int error; 994275406Stijl 995275406Stijl if ((size & (AGP_PAGE_SIZE - 1)) != 0 || 996275406Stijl (offset & (AGP_PAGE_SIZE - 1)) != 0) 997275406Stijl return (EINVAL); 998275406Stijl 999275406Stijl sc = device_get_softc(dev); 1000275406Stijl 1001275406Stijl mtx_lock(&sc->as_lock); 1002275406Stijl for (i = 0; i < size; i += PAGE_SIZE) { 1003275406Stijl m = pages[OFF_TO_IDX(i)]; 1004275406Stijl KASSERT(m->wire_count > 0, 1005275406Stijl ("agp_bind_pages: page %p hasn't been wired", m)); 1006275406Stijl 1007275406Stijl /* 1008275406Stijl * Install entries in the GATT, making sure that if 1009275406Stijl * AGP_PAGE_SIZE < PAGE_SIZE and size is not 1010275406Stijl * aligned to PAGE_SIZE, we don't modify too many GATT 1011275406Stijl * entries. 1012275406Stijl */ 1013275406Stijl for (j = 0; j < PAGE_SIZE && i + j < size; j += AGP_PAGE_SIZE) { 1014275406Stijl pa = VM_PAGE_TO_PHYS(m) + j; 1015275406Stijl AGP_DPF("binding offset %#jx to pa %#jx\n", 1016275406Stijl (uintmax_t)offset + i + j, (uintmax_t)pa); 1017275406Stijl error = AGP_BIND_PAGE(dev, offset + i + j, pa); 1018275406Stijl if (error) { 1019275406Stijl /* 1020275406Stijl * Bail out. Reverse all the mappings. 1021275406Stijl */ 1022275406Stijl for (k = 0; k < i + j; k += AGP_PAGE_SIZE) 1023275406Stijl AGP_UNBIND_PAGE(dev, offset + k); 1024275406Stijl 1025275406Stijl mtx_unlock(&sc->as_lock); 1026275406Stijl return (error); 1027275406Stijl } 1028275406Stijl } 1029275406Stijl } 1030275406Stijl 1031275406Stijl AGP_FLUSH_TLB(dev); 1032275406Stijl 1033275406Stijl mtx_unlock(&sc->as_lock); 1034275406Stijl return (0); 1035275406Stijl} 1036275406Stijl 1037275406Stijlint 1038275406Stijlagp_unbind_pages(device_t dev, vm_size_t size, vm_offset_t offset) 1039275406Stijl{ 1040275406Stijl struct agp_softc *sc; 1041275406Stijl vm_offset_t i; 1042275406Stijl 1043275406Stijl if ((size & (AGP_PAGE_SIZE - 1)) != 0 || 1044275406Stijl (offset & (AGP_PAGE_SIZE - 1)) != 0) 1045275406Stijl return (EINVAL); 1046275406Stijl 1047275406Stijl sc = device_get_softc(dev); 1048275406Stijl 1049275406Stijl mtx_lock(&sc->as_lock); 1050275406Stijl for (i = 0; i < size; i += AGP_PAGE_SIZE) 1051275406Stijl AGP_UNBIND_PAGE(dev, offset + i); 1052275406Stijl 1053275406Stijl AGP_FLUSH_TLB(dev); 1054275406Stijl 1055275406Stijl mtx_unlock(&sc->as_lock); 1056275406Stijl return (0); 1057275406Stijl} 1058