1191783Srmacklem/*- 2191783Srmacklem * Copyright (c) 2000 Doug Rabson 3191783Srmacklem * All rights reserved. 4191783Srmacklem * 5191783Srmacklem * Redistribution and use in source and binary forms, with or without 6191783Srmacklem * modification, are permitted provided that the following conditions 7191783Srmacklem * are met: 8191783Srmacklem * 1. Redistributions of source code must retain the above copyright 9191783Srmacklem * notice, this list of conditions and the following disclaimer. 10191783Srmacklem * 2. Redistributions in binary form must reproduce the above copyright 11191783Srmacklem * notice, this list of conditions and the following disclaimer in the 12191783Srmacklem * documentation and/or other materials provided with the distribution. 13191783Srmacklem * 14191783Srmacklem * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15191783Srmacklem * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16191783Srmacklem * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17191783Srmacklem * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18191783Srmacklem * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19191783Srmacklem * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20191783Srmacklem * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21191783Srmacklem * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22191783Srmacklem * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23191783Srmacklem * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24191783Srmacklem * SUCH DAMAGE. 25191783Srmacklem */ 26191783Srmacklem 27191783Srmacklem#include <sys/cdefs.h> 28191783Srmacklem__FBSDID("$FreeBSD: releng/10.2/sys/dev/agp/agp.c 275406 2014-12-02 13:46:13Z tijl $"); 29191783Srmacklem 30191783Srmacklem#include "opt_agp.h" 31191783Srmacklem 32191783Srmacklem#include <sys/param.h> 33191783Srmacklem#include <sys/systm.h> 34191783Srmacklem#include <sys/malloc.h> 35191783Srmacklem#include <sys/kernel.h> 36191783Srmacklem#include <sys/module.h> 37191783Srmacklem#include <sys/bus.h> 38191783Srmacklem#include <sys/conf.h> 39191783Srmacklem#include <sys/ioccom.h> 40191783Srmacklem#include <sys/agpio.h> 41191783Srmacklem#include <sys/lock.h> 42191783Srmacklem#include <sys/mutex.h> 43191783Srmacklem#include <sys/proc.h> 44191783Srmacklem#include <sys/rwlock.h> 45191783Srmacklem 46191783Srmacklem#include <dev/agp/agppriv.h> 47191783Srmacklem#include <dev/agp/agpvar.h> 48191783Srmacklem#include <dev/agp/agpreg.h> 49191783Srmacklem#include <dev/pci/pcivar.h> 50191783Srmacklem#include <dev/pci/pcireg.h> 51191783Srmacklem 52191783Srmacklem#include <vm/vm.h> 53191783Srmacklem#include <vm/vm_extern.h> 54191783Srmacklem#include <vm/vm_kern.h> 55191783Srmacklem#include <vm/vm_param.h> 56191783Srmacklem#include <vm/vm_object.h> 57191783Srmacklem#include <vm/vm_page.h> 58191783Srmacklem#include <vm/vm_pageout.h> 59191783Srmacklem#include <vm/pmap.h> 60191783Srmacklem 61191783Srmacklem#include <machine/bus.h> 62191783Srmacklem#include <machine/resource.h> 63191783Srmacklem#include <sys/rman.h> 64191783Srmacklem 65191783SrmacklemMODULE_VERSION(agp, 1); 66191783Srmacklem 67191783SrmacklemMALLOC_DEFINE(M_AGP, "agp", "AGP data structures"); 68191783Srmacklem 69191783Srmacklem /* agp_drv.c */ 70191783Srmacklemstatic d_open_t agp_open; 71191783Srmacklemstatic d_close_t agp_close; 72191783Srmacklemstatic d_ioctl_t agp_ioctl; 73191783Srmacklemstatic d_mmap_t agp_mmap; 74191783Srmacklem 75191783Srmacklemstatic struct cdevsw agp_cdevsw = { 76191783Srmacklem .d_version = D_VERSION, 77191783Srmacklem .d_flags = D_NEEDGIANT, 78191783Srmacklem .d_open = agp_open, 79191783Srmacklem .d_close = agp_close, 80191783Srmacklem .d_ioctl = agp_ioctl, 81191783Srmacklem .d_mmap = agp_mmap, 82191783Srmacklem .d_name = "agp", 83191783Srmacklem}; 84191783Srmacklem 85191783Srmacklemstatic devclass_t agp_devclass; 86191783Srmacklem 87191783Srmacklem/* Helper functions for implementing chipset mini drivers. */ 88191783Srmacklem 89191783Srmacklemu_int8_t 90191783Srmacklemagp_find_caps(device_t dev) 91191783Srmacklem{ 92191783Srmacklem int capreg; 93191783Srmacklem 94191783Srmacklem 95191783Srmacklem if (pci_find_cap(dev, PCIY_AGP, &capreg) != 0) 96191783Srmacklem capreg = 0; 97191783Srmacklem return (capreg); 98191783Srmacklem} 99191783Srmacklem 100191783Srmacklem/* 101191783Srmacklem * Find an AGP display device (if any). 102191783Srmacklem */ 103191783Srmacklemstatic device_t 104191783Srmacklemagp_find_display(void) 105191783Srmacklem{ 106191783Srmacklem devclass_t pci = devclass_find("pci"); 107191783Srmacklem device_t bus, dev = 0; 108191783Srmacklem device_t *kids; 109191783Srmacklem int busnum, numkids, i; 110191783Srmacklem 111191783Srmacklem for (busnum = 0; busnum < devclass_get_maxunit(pci); busnum++) { 112191783Srmacklem bus = devclass_get_device(pci, busnum); 113191783Srmacklem if (!bus) 114191783Srmacklem continue; 115191783Srmacklem if (device_get_children(bus, &kids, &numkids) != 0) 116191783Srmacklem continue; 117191783Srmacklem for (i = 0; i < numkids; i++) { 118191783Srmacklem dev = kids[i]; 119191783Srmacklem if (pci_get_class(dev) == PCIC_DISPLAY 120191783Srmacklem && pci_get_subclass(dev) == PCIS_DISPLAY_VGA) 121191783Srmacklem if (agp_find_caps(dev)) { 122191783Srmacklem free(kids, M_TEMP); 123191783Srmacklem return dev; 124191783Srmacklem } 125191783Srmacklem 126191783Srmacklem } 127191783Srmacklem free(kids, M_TEMP); 128191783Srmacklem } 129191783Srmacklem 130191783Srmacklem return 0; 131191783Srmacklem} 132196332Srmacklem 133196332Srmacklemstruct agp_gatt * 134196332Srmacklemagp_alloc_gatt(device_t dev) 135196332Srmacklem{ 136196332Srmacklem u_int32_t apsize = AGP_GET_APERTURE(dev); 137196332Srmacklem u_int32_t entries = apsize >> AGP_PAGE_SHIFT; 138196332Srmacklem struct agp_gatt *gatt; 139196332Srmacklem 140191783Srmacklem if (bootverbose) 141196332Srmacklem device_printf(dev, 142191783Srmacklem "allocating GATT for aperture of size %dM\n", 143191783Srmacklem apsize / (1024*1024)); 144191783Srmacklem 145191783Srmacklem if (entries == 0) { 146191783Srmacklem device_printf(dev, "bad aperture size\n"); 147191783Srmacklem return NULL; 148196332Srmacklem } 149196332Srmacklem 150196332Srmacklem gatt = malloc(sizeof(struct agp_gatt), M_AGP, M_NOWAIT); 151191783Srmacklem if (!gatt) 152191783Srmacklem return 0; 153191783Srmacklem 154191783Srmacklem gatt->ag_entries = entries; 155191783Srmacklem gatt->ag_virtual = (void *)kmem_alloc_contig(kernel_arena, 156191783Srmacklem entries * sizeof(u_int32_t), M_NOWAIT | M_ZERO, 0, ~0, PAGE_SIZE, 157191783Srmacklem 0, VM_MEMATTR_WRITE_COMBINING); 158191783Srmacklem if (!gatt->ag_virtual) { 159191783Srmacklem if (bootverbose) 160191783Srmacklem device_printf(dev, "contiguous allocation failed\n"); 161191783Srmacklem free(gatt, M_AGP); 162191783Srmacklem return 0; 163191783Srmacklem } 164191783Srmacklem gatt->ag_physical = vtophys((vm_offset_t) gatt->ag_virtual); 165191783Srmacklem 166191783Srmacklem return gatt; 167191783Srmacklem} 168191783Srmacklem 169191783Srmacklemvoid 170191783Srmacklemagp_free_gatt(struct agp_gatt *gatt) 171191783Srmacklem{ 172191783Srmacklem kmem_free(kernel_arena, (vm_offset_t)gatt->ag_virtual, 173191783Srmacklem gatt->ag_entries * sizeof(u_int32_t)); 174191783Srmacklem free(gatt, M_AGP); 175191783Srmacklem} 176191783Srmacklem 177191783Srmacklemstatic u_int agp_max[][2] = { 178191783Srmacklem {0, 0}, 179191783Srmacklem {32, 4}, 180191783Srmacklem {64, 28}, 181191783Srmacklem {128, 96}, 182191783Srmacklem {256, 204}, 183191783Srmacklem {512, 440}, 184191783Srmacklem {1024, 942}, 185191783Srmacklem {2048, 1920}, 186191783Srmacklem {4096, 3932} 187191783Srmacklem}; 188191783Srmacklem#define agp_max_size (sizeof(agp_max) / sizeof(agp_max[0])) 189191783Srmacklem 190191783Srmacklem/** 191191783Srmacklem * Sets the PCI resource which represents the AGP aperture. 192191783Srmacklem * 193191783Srmacklem * If not called, the default AGP aperture resource of AGP_APBASE will 194191783Srmacklem * be used. Must be called before agp_generic_attach(). 195191783Srmacklem */ 196191783Srmacklemvoid 197191783Srmacklemagp_set_aperture_resource(device_t dev, int rid) 198191783Srmacklem{ 199191783Srmacklem struct agp_softc *sc = device_get_softc(dev); 200191783Srmacklem 201191783Srmacklem sc->as_aperture_rid = rid; 202191783Srmacklem} 203191783Srmacklem 204191783Srmacklemint 205191783Srmacklemagp_generic_attach(device_t dev) 206191783Srmacklem{ 207191783Srmacklem struct agp_softc *sc = device_get_softc(dev); 208191783Srmacklem int i; 209191783Srmacklem u_int memsize; 210191783Srmacklem 211191783Srmacklem /* 212191783Srmacklem * Find and map the aperture, RF_SHAREABLE for DRM but not RF_ACTIVE 213191783Srmacklem * because the kernel doesn't need to map it. 214191783Srmacklem */ 215191783Srmacklem 216191783Srmacklem if (sc->as_aperture_rid != -1) { 217191783Srmacklem if (sc->as_aperture_rid == 0) 218191783Srmacklem sc->as_aperture_rid = AGP_APBASE; 219191783Srmacklem 220191783Srmacklem sc->as_aperture = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 221191783Srmacklem &sc->as_aperture_rid, RF_SHAREABLE); 222191783Srmacklem if (!sc->as_aperture) 223191783Srmacklem return ENOMEM; 224191783Srmacklem } 225191783Srmacklem 226191783Srmacklem /* 227191783Srmacklem * Work out an upper bound for agp memory allocation. This 228191783Srmacklem * uses a heurisitc table from the Linux driver. 229191783Srmacklem */ 230191783Srmacklem memsize = ptoa(realmem) >> 20; 231191783Srmacklem for (i = 0; i < agp_max_size; i++) { 232191783Srmacklem if (memsize <= agp_max[i][0]) 233191783Srmacklem break; 234191783Srmacklem } 235191783Srmacklem if (i == agp_max_size) 236191783Srmacklem i = agp_max_size - 1; 237191783Srmacklem sc->as_maxmem = agp_max[i][1] << 20U; 238191783Srmacklem 239191783Srmacklem /* 240191783Srmacklem * The lock is used to prevent re-entry to 241191783Srmacklem * agp_generic_bind_memory() since that function can sleep. 242191783Srmacklem */ 243191783Srmacklem mtx_init(&sc->as_lock, "agp lock", NULL, MTX_DEF); 244191783Srmacklem 245191783Srmacklem /* 246191783Srmacklem * Initialise stuff for the userland device. 247191783Srmacklem */ 248191783Srmacklem agp_devclass = devclass_find("agp"); 249191783Srmacklem TAILQ_INIT(&sc->as_memory); 250191783Srmacklem sc->as_nextid = 1; 251191783Srmacklem 252191783Srmacklem sc->as_devnode = make_dev(&agp_cdevsw, 253191783Srmacklem 0, UID_ROOT, GID_WHEEL, 0600, "agpgart"); 254191783Srmacklem sc->as_devnode->si_drv1 = dev; 255191783Srmacklem 256191783Srmacklem return 0; 257191783Srmacklem} 258191783Srmacklem 259191783Srmacklemvoid 260191783Srmacklemagp_free_cdev(device_t dev) 261191783Srmacklem{ 262191783Srmacklem struct agp_softc *sc = device_get_softc(dev); 263191783Srmacklem 264191783Srmacklem destroy_dev(sc->as_devnode); 265191783Srmacklem} 266191783Srmacklem 267191783Srmacklemvoid 268191783Srmacklemagp_free_res(device_t dev) 269191783Srmacklem{ 270191783Srmacklem struct agp_softc *sc = device_get_softc(dev); 271191783Srmacklem 272191783Srmacklem if (sc->as_aperture != NULL) 273191783Srmacklem bus_release_resource(dev, SYS_RES_MEMORY, sc->as_aperture_rid, 274191783Srmacklem sc->as_aperture); 275191783Srmacklem mtx_destroy(&sc->as_lock); 276191783Srmacklem} 277191783Srmacklem 278191783Srmacklemint 279191783Srmacklemagp_generic_detach(device_t dev) 280191783Srmacklem{ 281191783Srmacklem 282191783Srmacklem agp_free_cdev(dev); 283191783Srmacklem agp_free_res(dev); 284191783Srmacklem return 0; 285191783Srmacklem} 286191783Srmacklem 287191783Srmacklem/** 288191783Srmacklem * Default AGP aperture size detection which simply returns the size of 289191783Srmacklem * the aperture's PCI resource. 290191783Srmacklem */ 291191783Srmacklemu_int32_t 292191783Srmacklemagp_generic_get_aperture(device_t dev) 293191783Srmacklem{ 294191783Srmacklem struct agp_softc *sc = device_get_softc(dev); 295191783Srmacklem 296191783Srmacklem return rman_get_size(sc->as_aperture); 297191783Srmacklem} 298191783Srmacklem 299191783Srmacklem/** 300191783Srmacklem * Default AGP aperture size setting function, which simply doesn't allow 301191783Srmacklem * changes to resource size. 302191783Srmacklem */ 303191783Srmacklemint 304191783Srmacklemagp_generic_set_aperture(device_t dev, u_int32_t aperture) 305191783Srmacklem{ 306191783Srmacklem u_int32_t current_aperture; 307191783Srmacklem 308191783Srmacklem current_aperture = AGP_GET_APERTURE(dev); 309191783Srmacklem if (current_aperture != aperture) 310191783Srmacklem return EINVAL; 311191783Srmacklem else 312191783Srmacklem return 0; 313191783Srmacklem} 314191783Srmacklem 315191783Srmacklem/* 316191783Srmacklem * This does the enable logic for v3, with the same topology 317191783Srmacklem * restrictions as in place for v2 -- one bus, one device on the bus. 318191783Srmacklem */ 319191783Srmacklemstatic int 320191783Srmacklemagp_v3_enable(device_t dev, device_t mdev, u_int32_t mode) 321191783Srmacklem{ 322191783Srmacklem u_int32_t tstatus, mstatus; 323191783Srmacklem u_int32_t command; 324191783Srmacklem int rq, sba, fw, rate, arqsz, cal; 325191783Srmacklem 326191783Srmacklem tstatus = pci_read_config(dev, agp_find_caps(dev) + AGP_STATUS, 4); 327191783Srmacklem mstatus = pci_read_config(mdev, agp_find_caps(mdev) + AGP_STATUS, 4); 328191783Srmacklem 329191783Srmacklem /* Set RQ to the min of mode, tstatus and mstatus */ 330191783Srmacklem rq = AGP_MODE_GET_RQ(mode); 331191783Srmacklem if (AGP_MODE_GET_RQ(tstatus) < rq) 332191783Srmacklem rq = AGP_MODE_GET_RQ(tstatus); 333191783Srmacklem if (AGP_MODE_GET_RQ(mstatus) < rq) 334191783Srmacklem rq = AGP_MODE_GET_RQ(mstatus); 335191783Srmacklem 336191783Srmacklem /* 337191783Srmacklem * ARQSZ - Set the value to the maximum one. 338191783Srmacklem * Don't allow the mode register to override values. 339191783Srmacklem */ 340191783Srmacklem arqsz = AGP_MODE_GET_ARQSZ(mode); 341191783Srmacklem if (AGP_MODE_GET_ARQSZ(tstatus) > rq) 342191783Srmacklem rq = AGP_MODE_GET_ARQSZ(tstatus); 343191783Srmacklem if (AGP_MODE_GET_ARQSZ(mstatus) > rq) 344191783Srmacklem rq = AGP_MODE_GET_ARQSZ(mstatus); 345191783Srmacklem 346191783Srmacklem /* Calibration cycle - don't allow override by mode register */ 347191783Srmacklem cal = AGP_MODE_GET_CAL(tstatus); 348191783Srmacklem if (AGP_MODE_GET_CAL(mstatus) < cal) 349191783Srmacklem cal = AGP_MODE_GET_CAL(mstatus); 350191783Srmacklem 351191783Srmacklem /* SBA must be supported for AGP v3. */ 352191783Srmacklem sba = 1; 353191783Srmacklem 354191783Srmacklem /* Set FW if all three support it. */ 355191783Srmacklem fw = (AGP_MODE_GET_FW(tstatus) 356191783Srmacklem & AGP_MODE_GET_FW(mstatus) 357191783Srmacklem & AGP_MODE_GET_FW(mode)); 358191783Srmacklem 359191783Srmacklem /* Figure out the max rate */ 360191783Srmacklem rate = (AGP_MODE_GET_RATE(tstatus) 361191783Srmacklem & AGP_MODE_GET_RATE(mstatus) 362191783Srmacklem & AGP_MODE_GET_RATE(mode)); 363191783Srmacklem if (rate & AGP_MODE_V3_RATE_8x) 364191783Srmacklem rate = AGP_MODE_V3_RATE_8x; 365191783Srmacklem else 366191783Srmacklem rate = AGP_MODE_V3_RATE_4x; 367191783Srmacklem if (bootverbose) 368191783Srmacklem device_printf(dev, "Setting AGP v3 mode %d\n", rate * 4); 369191783Srmacklem 370191783Srmacklem pci_write_config(dev, agp_find_caps(dev) + AGP_COMMAND, 0, 4); 371191783Srmacklem 372191783Srmacklem /* Construct the new mode word and tell the hardware */ 373191783Srmacklem command = 0; 374191783Srmacklem command = AGP_MODE_SET_RQ(0, rq); 375191783Srmacklem command = AGP_MODE_SET_ARQSZ(command, arqsz); 376191783Srmacklem command = AGP_MODE_SET_CAL(command, cal); 377191783Srmacklem command = AGP_MODE_SET_SBA(command, sba); 378191783Srmacklem command = AGP_MODE_SET_FW(command, fw); 379191783Srmacklem command = AGP_MODE_SET_RATE(command, rate); 380191783Srmacklem command = AGP_MODE_SET_MODE_3(command, 1); 381191783Srmacklem command = AGP_MODE_SET_AGP(command, 1); 382191783Srmacklem pci_write_config(dev, agp_find_caps(dev) + AGP_COMMAND, command, 4); 383191783Srmacklem pci_write_config(mdev, agp_find_caps(mdev) + AGP_COMMAND, command, 4); 384191783Srmacklem 385191783Srmacklem return 0; 386191783Srmacklem} 387191783Srmacklem 388191783Srmacklemstatic int 389191783Srmacklemagp_v2_enable(device_t dev, device_t mdev, u_int32_t mode) 390191783Srmacklem{ 391191783Srmacklem u_int32_t tstatus, mstatus; 392191783Srmacklem u_int32_t command; 393191783Srmacklem int rq, sba, fw, rate; 394191783Srmacklem 395191783Srmacklem tstatus = pci_read_config(dev, agp_find_caps(dev) + AGP_STATUS, 4); 396191783Srmacklem mstatus = pci_read_config(mdev, agp_find_caps(mdev) + AGP_STATUS, 4); 397191783Srmacklem 398191783Srmacklem /* Set RQ to the min of mode, tstatus and mstatus */ 399191783Srmacklem rq = AGP_MODE_GET_RQ(mode); 400 if (AGP_MODE_GET_RQ(tstatus) < rq) 401 rq = AGP_MODE_GET_RQ(tstatus); 402 if (AGP_MODE_GET_RQ(mstatus) < rq) 403 rq = AGP_MODE_GET_RQ(mstatus); 404 405 /* Set SBA if all three can deal with SBA */ 406 sba = (AGP_MODE_GET_SBA(tstatus) 407 & AGP_MODE_GET_SBA(mstatus) 408 & AGP_MODE_GET_SBA(mode)); 409 410 /* Similar for FW */ 411 fw = (AGP_MODE_GET_FW(tstatus) 412 & AGP_MODE_GET_FW(mstatus) 413 & AGP_MODE_GET_FW(mode)); 414 415 /* Figure out the max rate */ 416 rate = (AGP_MODE_GET_RATE(tstatus) 417 & AGP_MODE_GET_RATE(mstatus) 418 & AGP_MODE_GET_RATE(mode)); 419 if (rate & AGP_MODE_V2_RATE_4x) 420 rate = AGP_MODE_V2_RATE_4x; 421 else if (rate & AGP_MODE_V2_RATE_2x) 422 rate = AGP_MODE_V2_RATE_2x; 423 else 424 rate = AGP_MODE_V2_RATE_1x; 425 if (bootverbose) 426 device_printf(dev, "Setting AGP v2 mode %d\n", rate); 427 428 /* Construct the new mode word and tell the hardware */ 429 command = 0; 430 command = AGP_MODE_SET_RQ(0, rq); 431 command = AGP_MODE_SET_SBA(command, sba); 432 command = AGP_MODE_SET_FW(command, fw); 433 command = AGP_MODE_SET_RATE(command, rate); 434 command = AGP_MODE_SET_AGP(command, 1); 435 pci_write_config(dev, agp_find_caps(dev) + AGP_COMMAND, command, 4); 436 pci_write_config(mdev, agp_find_caps(mdev) + AGP_COMMAND, command, 4); 437 438 return 0; 439} 440 441int 442agp_generic_enable(device_t dev, u_int32_t mode) 443{ 444 device_t mdev = agp_find_display(); 445 u_int32_t tstatus, mstatus; 446 447 if (!mdev) { 448 AGP_DPF("can't find display\n"); 449 return ENXIO; 450 } 451 452 tstatus = pci_read_config(dev, agp_find_caps(dev) + AGP_STATUS, 4); 453 mstatus = pci_read_config(mdev, agp_find_caps(mdev) + AGP_STATUS, 4); 454 455 /* 456 * Check display and bridge for AGP v3 support. AGP v3 allows 457 * more variety in topology than v2, e.g. multiple AGP devices 458 * attached to one bridge, or multiple AGP bridges in one 459 * system. This doesn't attempt to address those situations, 460 * but should work fine for a classic single AGP slot system 461 * with AGP v3. 462 */ 463 if (AGP_MODE_GET_MODE_3(mode) && 464 AGP_MODE_GET_MODE_3(tstatus) && 465 AGP_MODE_GET_MODE_3(mstatus)) 466 return (agp_v3_enable(dev, mdev, mode)); 467 else 468 return (agp_v2_enable(dev, mdev, mode)); 469} 470 471struct agp_memory * 472agp_generic_alloc_memory(device_t dev, int type, vm_size_t size) 473{ 474 struct agp_softc *sc = device_get_softc(dev); 475 struct agp_memory *mem; 476 477 if ((size & (AGP_PAGE_SIZE - 1)) != 0) 478 return 0; 479 480 if (size > sc->as_maxmem - sc->as_allocated) 481 return 0; 482 483 if (type != 0) { 484 printf("agp_generic_alloc_memory: unsupported type %d\n", 485 type); 486 return 0; 487 } 488 489 mem = malloc(sizeof *mem, M_AGP, M_WAITOK); 490 mem->am_id = sc->as_nextid++; 491 mem->am_size = size; 492 mem->am_type = 0; 493 mem->am_obj = vm_object_allocate(OBJT_DEFAULT, atop(round_page(size))); 494 mem->am_physical = 0; 495 mem->am_offset = 0; 496 mem->am_is_bound = 0; 497 TAILQ_INSERT_TAIL(&sc->as_memory, mem, am_link); 498 sc->as_allocated += size; 499 500 return mem; 501} 502 503int 504agp_generic_free_memory(device_t dev, struct agp_memory *mem) 505{ 506 struct agp_softc *sc = device_get_softc(dev); 507 508 if (mem->am_is_bound) 509 return EBUSY; 510 511 sc->as_allocated -= mem->am_size; 512 TAILQ_REMOVE(&sc->as_memory, mem, am_link); 513 vm_object_deallocate(mem->am_obj); 514 free(mem, M_AGP); 515 return 0; 516} 517 518int 519agp_generic_bind_memory(device_t dev, struct agp_memory *mem, 520 vm_offset_t offset) 521{ 522 struct agp_softc *sc = device_get_softc(dev); 523 vm_offset_t i, j, k; 524 vm_page_t m; 525 int error; 526 527 /* Do some sanity checks first. */ 528 if ((offset & (AGP_PAGE_SIZE - 1)) != 0 || 529 offset + mem->am_size > AGP_GET_APERTURE(dev)) { 530 device_printf(dev, "binding memory at bad offset %#x\n", 531 (int)offset); 532 return EINVAL; 533 } 534 535 /* 536 * Allocate the pages early, before acquiring the lock, 537 * because vm_page_grab() may sleep and we can't hold a mutex 538 * while sleeping. 539 */ 540 VM_OBJECT_WLOCK(mem->am_obj); 541 for (i = 0; i < mem->am_size; i += PAGE_SIZE) { 542 /* 543 * Find a page from the object and wire it 544 * down. This page will be mapped using one or more 545 * entries in the GATT (assuming that PAGE_SIZE >= 546 * AGP_PAGE_SIZE. If this is the first call to bind, 547 * the pages will be allocated and zeroed. 548 */ 549 m = vm_page_grab(mem->am_obj, OFF_TO_IDX(i), 550 VM_ALLOC_WIRED | VM_ALLOC_ZERO); 551 AGP_DPF("found page pa=%#jx\n", (uintmax_t)VM_PAGE_TO_PHYS(m)); 552 } 553 VM_OBJECT_WUNLOCK(mem->am_obj); 554 555 mtx_lock(&sc->as_lock); 556 557 if (mem->am_is_bound) { 558 device_printf(dev, "memory already bound\n"); 559 error = EINVAL; 560 VM_OBJECT_WLOCK(mem->am_obj); 561 i = 0; 562 goto bad; 563 } 564 565 /* 566 * Bind the individual pages and flush the chipset's 567 * TLB. 568 */ 569 VM_OBJECT_WLOCK(mem->am_obj); 570 for (i = 0; i < mem->am_size; i += PAGE_SIZE) { 571 m = vm_page_lookup(mem->am_obj, OFF_TO_IDX(i)); 572 573 /* 574 * Install entries in the GATT, making sure that if 575 * AGP_PAGE_SIZE < PAGE_SIZE and mem->am_size is not 576 * aligned to PAGE_SIZE, we don't modify too many GATT 577 * entries. 578 */ 579 for (j = 0; j < PAGE_SIZE && i + j < mem->am_size; 580 j += AGP_PAGE_SIZE) { 581 vm_offset_t pa = VM_PAGE_TO_PHYS(m) + j; 582 AGP_DPF("binding offset %#jx to pa %#jx\n", 583 (uintmax_t)offset + i + j, (uintmax_t)pa); 584 error = AGP_BIND_PAGE(dev, offset + i + j, pa); 585 if (error) { 586 /* 587 * Bail out. Reverse all the mappings 588 * and unwire the pages. 589 */ 590 for (k = 0; k < i + j; k += AGP_PAGE_SIZE) 591 AGP_UNBIND_PAGE(dev, offset + k); 592 goto bad; 593 } 594 } 595 vm_page_xunbusy(m); 596 } 597 VM_OBJECT_WUNLOCK(mem->am_obj); 598 599 /* 600 * Make sure the chipset gets the new mappings. 601 */ 602 AGP_FLUSH_TLB(dev); 603 604 mem->am_offset = offset; 605 mem->am_is_bound = 1; 606 607 mtx_unlock(&sc->as_lock); 608 609 return 0; 610bad: 611 mtx_unlock(&sc->as_lock); 612 VM_OBJECT_ASSERT_WLOCKED(mem->am_obj); 613 for (k = 0; k < mem->am_size; k += PAGE_SIZE) { 614 m = vm_page_lookup(mem->am_obj, OFF_TO_IDX(k)); 615 if (k >= i) 616 vm_page_xunbusy(m); 617 vm_page_lock(m); 618 vm_page_unwire(m, 0); 619 vm_page_unlock(m); 620 } 621 VM_OBJECT_WUNLOCK(mem->am_obj); 622 623 return error; 624} 625 626int 627agp_generic_unbind_memory(device_t dev, struct agp_memory *mem) 628{ 629 struct agp_softc *sc = device_get_softc(dev); 630 vm_page_t m; 631 int i; 632 633 mtx_lock(&sc->as_lock); 634 635 if (!mem->am_is_bound) { 636 device_printf(dev, "memory is not bound\n"); 637 mtx_unlock(&sc->as_lock); 638 return EINVAL; 639 } 640 641 642 /* 643 * Unbind the individual pages and flush the chipset's 644 * TLB. Unwire the pages so they can be swapped. 645 */ 646 for (i = 0; i < mem->am_size; i += AGP_PAGE_SIZE) 647 AGP_UNBIND_PAGE(dev, mem->am_offset + i); 648 649 AGP_FLUSH_TLB(dev); 650 651 VM_OBJECT_WLOCK(mem->am_obj); 652 for (i = 0; i < mem->am_size; i += PAGE_SIZE) { 653 m = vm_page_lookup(mem->am_obj, atop(i)); 654 vm_page_lock(m); 655 vm_page_unwire(m, 0); 656 vm_page_unlock(m); 657 } 658 VM_OBJECT_WUNLOCK(mem->am_obj); 659 660 mem->am_offset = 0; 661 mem->am_is_bound = 0; 662 663 mtx_unlock(&sc->as_lock); 664 665 return 0; 666} 667 668/* Helper functions for implementing user/kernel api */ 669 670static int 671agp_acquire_helper(device_t dev, enum agp_acquire_state state) 672{ 673 struct agp_softc *sc = device_get_softc(dev); 674 675 if (sc->as_state != AGP_ACQUIRE_FREE) 676 return EBUSY; 677 sc->as_state = state; 678 679 return 0; 680} 681 682static int 683agp_release_helper(device_t dev, enum agp_acquire_state state) 684{ 685 struct agp_softc *sc = device_get_softc(dev); 686 687 if (sc->as_state == AGP_ACQUIRE_FREE) 688 return 0; 689 690 if (sc->as_state != state) 691 return EBUSY; 692 693 sc->as_state = AGP_ACQUIRE_FREE; 694 return 0; 695} 696 697static struct agp_memory * 698agp_find_memory(device_t dev, int id) 699{ 700 struct agp_softc *sc = device_get_softc(dev); 701 struct agp_memory *mem; 702 703 AGP_DPF("searching for memory block %d\n", id); 704 TAILQ_FOREACH(mem, &sc->as_memory, am_link) { 705 AGP_DPF("considering memory block %d\n", mem->am_id); 706 if (mem->am_id == id) 707 return mem; 708 } 709 return 0; 710} 711 712/* Implementation of the userland ioctl api */ 713 714static int 715agp_info_user(device_t dev, agp_info *info) 716{ 717 struct agp_softc *sc = device_get_softc(dev); 718 719 bzero(info, sizeof *info); 720 info->bridge_id = pci_get_devid(dev); 721 info->agp_mode = 722 pci_read_config(dev, agp_find_caps(dev) + AGP_STATUS, 4); 723 if (sc->as_aperture) 724 info->aper_base = rman_get_start(sc->as_aperture); 725 else 726 info->aper_base = 0; 727 info->aper_size = AGP_GET_APERTURE(dev) >> 20; 728 info->pg_total = info->pg_system = sc->as_maxmem >> AGP_PAGE_SHIFT; 729 info->pg_used = sc->as_allocated >> AGP_PAGE_SHIFT; 730 731 return 0; 732} 733 734static int 735agp_setup_user(device_t dev, agp_setup *setup) 736{ 737 return AGP_ENABLE(dev, setup->agp_mode); 738} 739 740static int 741agp_allocate_user(device_t dev, agp_allocate *alloc) 742{ 743 struct agp_memory *mem; 744 745 mem = AGP_ALLOC_MEMORY(dev, 746 alloc->type, 747 alloc->pg_count << AGP_PAGE_SHIFT); 748 if (mem) { 749 alloc->key = mem->am_id; 750 alloc->physical = mem->am_physical; 751 return 0; 752 } else { 753 return ENOMEM; 754 } 755} 756 757static int 758agp_deallocate_user(device_t dev, int id) 759{ 760 struct agp_memory *mem = agp_find_memory(dev, id); 761 762 if (mem) { 763 AGP_FREE_MEMORY(dev, mem); 764 return 0; 765 } else { 766 return ENOENT; 767 } 768} 769 770static int 771agp_bind_user(device_t dev, agp_bind *bind) 772{ 773 struct agp_memory *mem = agp_find_memory(dev, bind->key); 774 775 if (!mem) 776 return ENOENT; 777 778 return AGP_BIND_MEMORY(dev, mem, bind->pg_start << AGP_PAGE_SHIFT); 779} 780 781static int 782agp_unbind_user(device_t dev, agp_unbind *unbind) 783{ 784 struct agp_memory *mem = agp_find_memory(dev, unbind->key); 785 786 if (!mem) 787 return ENOENT; 788 789 return AGP_UNBIND_MEMORY(dev, mem); 790} 791 792static int 793agp_chipset_flush(device_t dev) 794{ 795 796 return (AGP_CHIPSET_FLUSH(dev)); 797} 798 799static int 800agp_open(struct cdev *kdev, int oflags, int devtype, struct thread *td) 801{ 802 device_t dev = kdev->si_drv1; 803 struct agp_softc *sc = device_get_softc(dev); 804 805 if (!sc->as_isopen) { 806 sc->as_isopen = 1; 807 device_busy(dev); 808 } 809 810 return 0; 811} 812 813static int 814agp_close(struct cdev *kdev, int fflag, int devtype, struct thread *td) 815{ 816 device_t dev = kdev->si_drv1; 817 struct agp_softc *sc = device_get_softc(dev); 818 struct agp_memory *mem; 819 820 /* 821 * Clear the GATT and force release on last close 822 */ 823 while ((mem = TAILQ_FIRST(&sc->as_memory)) != 0) { 824 if (mem->am_is_bound) 825 AGP_UNBIND_MEMORY(dev, mem); 826 AGP_FREE_MEMORY(dev, mem); 827 } 828 if (sc->as_state == AGP_ACQUIRE_USER) 829 agp_release_helper(dev, AGP_ACQUIRE_USER); 830 sc->as_isopen = 0; 831 device_unbusy(dev); 832 833 return 0; 834} 835 836static int 837agp_ioctl(struct cdev *kdev, u_long cmd, caddr_t data, int fflag, struct thread *td) 838{ 839 device_t dev = kdev->si_drv1; 840 841 switch (cmd) { 842 case AGPIOC_INFO: 843 return agp_info_user(dev, (agp_info *) data); 844 845 case AGPIOC_ACQUIRE: 846 return agp_acquire_helper(dev, AGP_ACQUIRE_USER); 847 848 case AGPIOC_RELEASE: 849 return agp_release_helper(dev, AGP_ACQUIRE_USER); 850 851 case AGPIOC_SETUP: 852 return agp_setup_user(dev, (agp_setup *)data); 853 854 case AGPIOC_ALLOCATE: 855 return agp_allocate_user(dev, (agp_allocate *)data); 856 857 case AGPIOC_DEALLOCATE: 858 return agp_deallocate_user(dev, *(int *) data); 859 860 case AGPIOC_BIND: 861 return agp_bind_user(dev, (agp_bind *)data); 862 863 case AGPIOC_UNBIND: 864 return agp_unbind_user(dev, (agp_unbind *)data); 865 866 case AGPIOC_CHIPSET_FLUSH: 867 return agp_chipset_flush(dev); 868 } 869 870 return EINVAL; 871} 872 873static int 874agp_mmap(struct cdev *kdev, vm_ooffset_t offset, vm_paddr_t *paddr, 875 int prot, vm_memattr_t *memattr) 876{ 877 device_t dev = kdev->si_drv1; 878 struct agp_softc *sc = device_get_softc(dev); 879 880 if (offset > AGP_GET_APERTURE(dev)) 881 return -1; 882 if (sc->as_aperture == NULL) 883 return -1; 884 *paddr = rman_get_start(sc->as_aperture) + offset; 885 return 0; 886} 887 888/* Implementation of the kernel api */ 889 890device_t 891agp_find_device() 892{ 893 device_t *children, child; 894 int i, count; 895 896 if (!agp_devclass) 897 return NULL; 898 if (devclass_get_devices(agp_devclass, &children, &count) != 0) 899 return NULL; 900 child = NULL; 901 for (i = 0; i < count; i++) { 902 if (device_is_attached(children[i])) { 903 child = children[i]; 904 break; 905 } 906 } 907 free(children, M_TEMP); 908 return child; 909} 910 911enum agp_acquire_state 912agp_state(device_t dev) 913{ 914 struct agp_softc *sc = device_get_softc(dev); 915 return sc->as_state; 916} 917 918void 919agp_get_info(device_t dev, struct agp_info *info) 920{ 921 struct agp_softc *sc = device_get_softc(dev); 922 923 info->ai_mode = 924 pci_read_config(dev, agp_find_caps(dev) + AGP_STATUS, 4); 925 if (sc->as_aperture != NULL) 926 info->ai_aperture_base = rman_get_start(sc->as_aperture); 927 else 928 info->ai_aperture_base = 0; 929 info->ai_aperture_size = AGP_GET_APERTURE(dev); 930 info->ai_memory_allowed = sc->as_maxmem; 931 info->ai_memory_used = sc->as_allocated; 932} 933 934int 935agp_acquire(device_t dev) 936{ 937 return agp_acquire_helper(dev, AGP_ACQUIRE_KERNEL); 938} 939 940int 941agp_release(device_t dev) 942{ 943 return agp_release_helper(dev, AGP_ACQUIRE_KERNEL); 944} 945 946int 947agp_enable(device_t dev, u_int32_t mode) 948{ 949 return AGP_ENABLE(dev, mode); 950} 951 952void *agp_alloc_memory(device_t dev, int type, vm_size_t bytes) 953{ 954 return (void *) AGP_ALLOC_MEMORY(dev, type, bytes); 955} 956 957void agp_free_memory(device_t dev, void *handle) 958{ 959 struct agp_memory *mem = (struct agp_memory *) handle; 960 AGP_FREE_MEMORY(dev, mem); 961} 962 963int agp_bind_memory(device_t dev, void *handle, vm_offset_t offset) 964{ 965 struct agp_memory *mem = (struct agp_memory *) handle; 966 return AGP_BIND_MEMORY(dev, mem, offset); 967} 968 969int agp_unbind_memory(device_t dev, void *handle) 970{ 971 struct agp_memory *mem = (struct agp_memory *) handle; 972 return AGP_UNBIND_MEMORY(dev, mem); 973} 974 975void agp_memory_info(device_t dev, void *handle, struct 976 agp_memory_info *mi) 977{ 978 struct agp_memory *mem = (struct agp_memory *) handle; 979 980 mi->ami_size = mem->am_size; 981 mi->ami_physical = mem->am_physical; 982 mi->ami_offset = mem->am_offset; 983 mi->ami_is_bound = mem->am_is_bound; 984} 985 986int 987agp_bind_pages(device_t dev, vm_page_t *pages, vm_size_t size, 988 vm_offset_t offset) 989{ 990 struct agp_softc *sc; 991 vm_offset_t i, j, k, pa; 992 vm_page_t m; 993 int error; 994 995 if ((size & (AGP_PAGE_SIZE - 1)) != 0 || 996 (offset & (AGP_PAGE_SIZE - 1)) != 0) 997 return (EINVAL); 998 999 sc = device_get_softc(dev); 1000 1001 mtx_lock(&sc->as_lock); 1002 for (i = 0; i < size; i += PAGE_SIZE) { 1003 m = pages[OFF_TO_IDX(i)]; 1004 KASSERT(m->wire_count > 0, 1005 ("agp_bind_pages: page %p hasn't been wired", m)); 1006 1007 /* 1008 * Install entries in the GATT, making sure that if 1009 * AGP_PAGE_SIZE < PAGE_SIZE and size is not 1010 * aligned to PAGE_SIZE, we don't modify too many GATT 1011 * entries. 1012 */ 1013 for (j = 0; j < PAGE_SIZE && i + j < size; j += AGP_PAGE_SIZE) { 1014 pa = VM_PAGE_TO_PHYS(m) + j; 1015 AGP_DPF("binding offset %#jx to pa %#jx\n", 1016 (uintmax_t)offset + i + j, (uintmax_t)pa); 1017 error = AGP_BIND_PAGE(dev, offset + i + j, pa); 1018 if (error) { 1019 /* 1020 * Bail out. Reverse all the mappings. 1021 */ 1022 for (k = 0; k < i + j; k += AGP_PAGE_SIZE) 1023 AGP_UNBIND_PAGE(dev, offset + k); 1024 1025 mtx_unlock(&sc->as_lock); 1026 return (error); 1027 } 1028 } 1029 } 1030 1031 AGP_FLUSH_TLB(dev); 1032 1033 mtx_unlock(&sc->as_lock); 1034 return (0); 1035} 1036 1037int 1038agp_unbind_pages(device_t dev, vm_size_t size, vm_offset_t offset) 1039{ 1040 struct agp_softc *sc; 1041 vm_offset_t i; 1042 1043 if ((size & (AGP_PAGE_SIZE - 1)) != 0 || 1044 (offset & (AGP_PAGE_SIZE - 1)) != 0) 1045 return (EINVAL); 1046 1047 sc = device_get_softc(dev); 1048 1049 mtx_lock(&sc->as_lock); 1050 for (i = 0; i < size; i += AGP_PAGE_SIZE) 1051 AGP_UNBIND_PAGE(dev, offset + i); 1052 1053 AGP_FLUSH_TLB(dev); 1054 1055 mtx_unlock(&sc->as_lock); 1056 return (0); 1057} 1058