A driver for programming the AGP hardware. This is only very lightly
tested on Intel BX chipsets only. The other agp minidrivers are totally untested. The programming api is a subset of the Linux api and is only intended to be enough for the X server to use. There is also an in-kernel api for the use of other kernel modules such as the 3D DRI.
This commit is contained in:
parent
fe0cef0780
commit
ab33dfac01
790
sys/dev/agp/agp.c
Normal file
790
sys/dev/agp/agp.c
Normal file
@ -0,0 +1,790 @@
|
||||
/*-
|
||||
* Copyright (c) 2000 Doug Rabson
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#include "opt_bus.h"
|
||||
#include "opt_pci.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/conf.h>
|
||||
#include <sys/ioccom.h>
|
||||
#include <sys/agpio.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/proc.h>
|
||||
|
||||
#include <pci/pcivar.h>
|
||||
#include <pci/pcireg.h>
|
||||
#include <pci/agppriv.h>
|
||||
#include <pci/agpvar.h>
|
||||
#include <pci/agpreg.h>
|
||||
|
||||
#include <vm/vm.h>
|
||||
#include <vm/vm_object.h>
|
||||
#include <vm/vm_page.h>
|
||||
#include <vm/vm_pageout.h>
|
||||
#include <vm/pmap.h>
|
||||
|
||||
#include <machine/md_var.h>
|
||||
#include <machine/bus.h>
|
||||
#include <machine/resource.h>
|
||||
#include <sys/rman.h>
|
||||
|
||||
MODULE_VERSION(agp, 1);
|
||||
|
||||
MALLOC_DEFINE(M_AGP, "agp", "AGP data structures");
|
||||
|
||||
#define CDEV_MAJOR 148
|
||||
/* agp_drv.c */
|
||||
static d_open_t agp_open;
|
||||
static d_close_t agp_close;
|
||||
static d_ioctl_t agp_ioctl;
|
||||
static d_mmap_t agp_mmap;
|
||||
|
||||
static struct cdevsw agp_cdevsw = {
|
||||
/* open */ agp_open,
|
||||
/* close */ agp_close,
|
||||
/* read */ noread,
|
||||
/* write */ nowrite,
|
||||
/* ioctl */ agp_ioctl,
|
||||
/* poll */ nopoll,
|
||||
/* mmap */ agp_mmap,
|
||||
/* strategy */ nostrategy,
|
||||
/* name */ "agp",
|
||||
/* maj */ CDEV_MAJOR,
|
||||
/* dump */ nodump,
|
||||
/* psize */ nopsize,
|
||||
/* flags */ D_TTY,
|
||||
/* bmaj */ -1
|
||||
};
|
||||
|
||||
static devclass_t agp_devclass;
|
||||
#define KDEV2DEV(kdev) devclass_get_device(agp_devclass, minor(kdev))
|
||||
|
||||
/* Helper functions for implementing chipset mini drivers. */
|
||||
|
||||
#ifdef __i386__
|
||||
#define agp_flush_cache() wbinvd()
|
||||
#endif
|
||||
|
||||
u_int8_t
|
||||
agp_find_caps(device_t dev)
|
||||
{
|
||||
u_int32_t status;
|
||||
u_int8_t ptr, next;
|
||||
|
||||
/*
|
||||
* Check the CAP_LIST bit of the PCI status register first.
|
||||
*/
|
||||
status = pci_read_config(dev, PCIR_STATUS, 2);
|
||||
if (!(status & 0x10))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Traverse the capabilities list.
|
||||
*/
|
||||
for (ptr = pci_read_config(dev, AGP_CAPPTR, 1);
|
||||
ptr != 0;
|
||||
ptr = next) {
|
||||
u_int32_t capid = pci_read_config(dev, ptr, 4);
|
||||
next = AGP_CAPID_GET_NEXT_PTR(capid);
|
||||
|
||||
/*
|
||||
* If this capability entry ID is 2, then we are done.
|
||||
*/
|
||||
if (AGP_CAPID_GET_CAP_ID(capid) == 2)
|
||||
return ptr;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find an AGP display device (if any).
|
||||
*/
|
||||
static device_t
|
||||
agp_find_display(void)
|
||||
{
|
||||
devclass_t pci = devclass_find("pci");
|
||||
device_t bus, dev = 0;
|
||||
device_t *kids;
|
||||
int busnum, numkids, i;
|
||||
|
||||
for (busnum = 0; busnum < devclass_get_maxunit(pci); busnum++) {
|
||||
bus = devclass_get_device(pci, busnum);
|
||||
if (!bus)
|
||||
continue;
|
||||
device_get_children(bus, &kids, &numkids);
|
||||
for (i = 0; i < numkids; i++) {
|
||||
dev = kids[i];
|
||||
if (pci_get_class(dev) == PCIC_DISPLAY
|
||||
&& pci_get_subclass(dev) == PCIS_DISPLAY_VGA)
|
||||
if (agp_find_caps(dev)) {
|
||||
free(kids, M_TEMP);
|
||||
return dev;
|
||||
}
|
||||
|
||||
}
|
||||
free(kids, M_TEMP);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct agp_gatt *
|
||||
agp_alloc_gatt(device_t dev)
|
||||
{
|
||||
u_int32_t apsize = AGP_GET_APERTURE(dev);
|
||||
u_int32_t entries = apsize >> AGP_PAGE_SHIFT;
|
||||
struct agp_gatt *gatt;
|
||||
|
||||
if (bootverbose)
|
||||
device_printf(dev,
|
||||
"allocating GATT for aperture of size %dM\n",
|
||||
apsize / (1024*1024));
|
||||
|
||||
gatt = malloc(sizeof(struct agp_gatt), M_AGP, M_NOWAIT);
|
||||
if (!gatt)
|
||||
return 0;
|
||||
|
||||
gatt->ag_entries = entries;
|
||||
gatt->ag_virtual = contigmalloc(entries * sizeof(u_int32_t), M_AGP, 0,
|
||||
0, ~0, PAGE_SIZE, 0);
|
||||
if (!gatt->ag_virtual) {
|
||||
if (bootverbose)
|
||||
device_printf(dev, "contiguous allocation failed\n");
|
||||
free(gatt, M_AGP);
|
||||
return 0;
|
||||
}
|
||||
bzero(gatt->ag_virtual, entries * sizeof(u_int32_t));
|
||||
gatt->ag_physical = vtophys((vm_offset_t) gatt->ag_virtual);
|
||||
agp_flush_cache();
|
||||
|
||||
return gatt;
|
||||
}
|
||||
|
||||
void
|
||||
agp_free_gatt(struct agp_gatt *gatt)
|
||||
{
|
||||
contigfree(gatt->ag_virtual,
|
||||
gatt->ag_entries * sizeof(u_int32_t), M_AGP);
|
||||
free(gatt, M_AGP);
|
||||
}
|
||||
|
||||
static int agp_max[][2] = {
|
||||
{0, 0},
|
||||
{32, 4},
|
||||
{64, 28},
|
||||
{128, 96},
|
||||
{256, 204},
|
||||
{512, 440},
|
||||
{1024, 942},
|
||||
{2048, 1920},
|
||||
{4096, 3932}
|
||||
};
|
||||
#define agp_max_size (sizeof(agp_max) / sizeof(agp_max[0]))
|
||||
|
||||
int
|
||||
agp_generic_attach(device_t dev)
|
||||
{
|
||||
struct agp_softc *sc = device_get_softc(dev);
|
||||
int rid, memsize, i;
|
||||
|
||||
/*
|
||||
* Find and map the aperture.
|
||||
*/
|
||||
rid = AGP_APBASE;
|
||||
sc->as_aperture = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid,
|
||||
0, ~0, 1, RF_ACTIVE);
|
||||
if (!sc->as_aperture)
|
||||
return ENOMEM;
|
||||
|
||||
/*
|
||||
* Work out an upper bound for agp memory allocation. This
|
||||
* uses a heurisitc table from the Linux driver.
|
||||
*/
|
||||
memsize = ptoa(Maxmem) >> 20;
|
||||
for (i = 0; i < agp_max_size; i++) {
|
||||
if (memsize <= agp_max[i][0])
|
||||
break;
|
||||
}
|
||||
if (i == agp_max_size) i = agp_max_size - 1;
|
||||
sc->as_maxmem = agp_max[i][1] << 20U;
|
||||
|
||||
/*
|
||||
* The lock is used to prevent re-entry to
|
||||
* agp_generic_bind_memory() since that function can sleep.
|
||||
*/
|
||||
lockinit(&sc->as_lock, PZERO|PCATCH, "agplk", 0, 0);
|
||||
|
||||
/*
|
||||
* Initialise stuff for the userland device.
|
||||
*/
|
||||
agp_devclass = devclass_find("agp");
|
||||
TAILQ_INIT(&sc->as_memory);
|
||||
sc->as_nextid = 1;
|
||||
|
||||
sc->as_devnode = make_dev(&agp_cdevsw,
|
||||
device_get_unit(dev),
|
||||
UID_ROOT,
|
||||
GID_WHEEL,
|
||||
0600,
|
||||
"agpgart");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
agp_generic_detach(device_t dev)
|
||||
{
|
||||
struct agp_softc *sc = device_get_softc(dev);
|
||||
bus_release_resource(dev, SYS_RES_MEMORY, AGP_APBASE, sc->as_aperture);
|
||||
lockmgr(&sc->as_lock, LK_DRAIN, 0, curproc);
|
||||
destroy_dev(sc->as_devnode);
|
||||
agp_flush_cache();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
agp_generic_enable(device_t dev, u_int32_t mode)
|
||||
{
|
||||
device_t mdev = agp_find_display();
|
||||
u_int32_t tstatus, mstatus;
|
||||
u_int32_t command;
|
||||
int rq, sba, fw, rate;;
|
||||
|
||||
if (!mdev) {
|
||||
AGP_DPF("can't find display\n");
|
||||
return ENXIO;
|
||||
}
|
||||
|
||||
tstatus = pci_read_config(dev, agp_find_caps(dev) + AGP_STATUS, 4);
|
||||
mstatus = pci_read_config(mdev, agp_find_caps(mdev) + AGP_STATUS, 4);
|
||||
|
||||
/* Set RQ to the min of mode, tstatus and mstatus */
|
||||
rq = AGP_MODE_GET_RQ(mode);
|
||||
if (AGP_MODE_GET_RQ(tstatus) < rq)
|
||||
rq = AGP_MODE_GET_RQ(tstatus);
|
||||
if (AGP_MODE_GET_RQ(mstatus) < rq)
|
||||
rq = AGP_MODE_GET_RQ(mstatus);
|
||||
|
||||
/* Set SBA if all three can deal with SBA */
|
||||
sba = (AGP_MODE_GET_SBA(tstatus)
|
||||
& AGP_MODE_GET_SBA(mstatus)
|
||||
& AGP_MODE_GET_SBA(mode));
|
||||
|
||||
/* Similar for FW */
|
||||
fw = (AGP_MODE_GET_FW(tstatus)
|
||||
& AGP_MODE_GET_FW(mstatus)
|
||||
& AGP_MODE_GET_FW(mode));
|
||||
|
||||
/* Figure out the max rate */
|
||||
rate = (AGP_MODE_GET_RATE(tstatus)
|
||||
& AGP_MODE_GET_RATE(mstatus)
|
||||
& AGP_MODE_GET_RATE(mode));
|
||||
if (rate & AGP_MODE_RATE_4x)
|
||||
rate = AGP_MODE_RATE_4x;
|
||||
else if (rate & AGP_MODE_RATE_2x)
|
||||
rate = AGP_MODE_RATE_2x;
|
||||
else
|
||||
rate = AGP_MODE_RATE_1x;
|
||||
|
||||
/* Construct the new mode word and tell the hardware */
|
||||
command = AGP_MODE_SET_RQ(0, rq);
|
||||
command = AGP_MODE_SET_SBA(command, sba);
|
||||
command = AGP_MODE_SET_FW(command, fw);
|
||||
command = AGP_MODE_SET_RATE(command, rate);
|
||||
command = AGP_MODE_SET_AGP(command, 1);
|
||||
pci_write_config(dev, agp_find_caps(dev) + AGP_COMMAND, command, 4);
|
||||
pci_write_config(mdev, agp_find_caps(mdev) + AGP_COMMAND, command, 4);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct agp_memory *
|
||||
agp_generic_alloc_memory(device_t dev, int type, vm_size_t size)
|
||||
{
|
||||
struct agp_softc *sc = device_get_softc(dev);
|
||||
struct agp_memory *mem;
|
||||
|
||||
if ((size & (AGP_PAGE_SIZE - 1)) != 0)
|
||||
return 0;
|
||||
|
||||
if (sc->as_allocated + size > sc->as_maxmem)
|
||||
return 0;
|
||||
|
||||
mem = malloc(sizeof *mem, M_AGP, M_WAITOK);
|
||||
mem->am_id = sc->as_nextid++;
|
||||
mem->am_size = size;
|
||||
mem->am_obj = vm_object_allocate(OBJT_DEFAULT, atop(round_page(size)));
|
||||
mem->am_physical = 0;
|
||||
mem->am_offset = 0;
|
||||
mem->am_is_bound = 0;
|
||||
TAILQ_INSERT_TAIL(&sc->as_memory, mem, am_link);
|
||||
sc->as_allocated += size;
|
||||
|
||||
return mem;
|
||||
}
|
||||
|
||||
int
|
||||
agp_generic_free_memory(device_t dev, struct agp_memory *mem)
|
||||
{
|
||||
struct agp_softc *sc = device_get_softc(dev);
|
||||
|
||||
if (mem->am_is_bound)
|
||||
return EBUSY;
|
||||
|
||||
sc->as_allocated -= mem->am_size;
|
||||
TAILQ_REMOVE(&sc->as_memory, mem, am_link);
|
||||
vm_object_deallocate(mem->am_obj);
|
||||
free(mem, M_AGP);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
agp_generic_bind_memory(device_t dev, struct agp_memory *mem,
|
||||
vm_offset_t offset)
|
||||
{
|
||||
struct agp_softc *sc = device_get_softc(dev);
|
||||
vm_offset_t i, j, k;
|
||||
vm_page_t m;
|
||||
int error;
|
||||
|
||||
lockmgr(&sc->as_lock, LK_EXCLUSIVE, 0, curproc);
|
||||
|
||||
if (mem->am_is_bound) {
|
||||
device_printf(dev, "memory already bound\n");
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
if (offset < 0
|
||||
|| (offset & (AGP_PAGE_SIZE - 1)) != 0
|
||||
|| offset + mem->am_size > AGP_GET_APERTURE(dev)) {
|
||||
device_printf(dev, "binding memory at bad offset %#x\n",
|
||||
(int) offset);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Bind the individual pages and flush the chipset's
|
||||
* TLB.
|
||||
*
|
||||
* XXX Presumably, this needs to be the pci address on alpha
|
||||
* (i.e. use alpha_XXX_dmamap()). I don't have access to any
|
||||
* alpha AGP hardware to check.
|
||||
*/
|
||||
for (i = 0; i < mem->am_size; i += PAGE_SIZE) {
|
||||
/*
|
||||
* Find a page from the object and wire it
|
||||
* down. This page will be mapped using one or more
|
||||
* entries in the GATT (assuming that PAGE_SIZE >=
|
||||
* AGP_PAGE_SIZE. If this is the first call to bind,
|
||||
* the pages will be allocated and zeroed.
|
||||
*/
|
||||
m = vm_page_grab(mem->am_obj, OFF_TO_IDX(i),
|
||||
VM_ALLOC_ZERO | VM_ALLOC_RETRY);
|
||||
AGP_DPF("found page pa=%#x\n", VM_PAGE_TO_PHYS(m));
|
||||
vm_page_wire(m);
|
||||
|
||||
/*
|
||||
* Install entries in the GATT, making sure that if
|
||||
* AGP_PAGE_SIZE < PAGE_SIZE and mem->am_size is not
|
||||
* aligned to PAGE_SIZE, we don't modify too many GATT
|
||||
* entries.
|
||||
*/
|
||||
for (j = 0; j < PAGE_SIZE && i + j < mem->am_size;
|
||||
j += AGP_PAGE_SIZE) {
|
||||
vm_offset_t pa = VM_PAGE_TO_PHYS(m) + j;
|
||||
AGP_DPF("binding offset %#x to pa %#x\n",
|
||||
offset + i + j, pa);
|
||||
error = AGP_BIND_PAGE(dev, offset + i + j, pa);
|
||||
if (error) {
|
||||
/*
|
||||
* Bail out. Reverse all the mappings
|
||||
* and unwire the pages.
|
||||
*/
|
||||
vm_page_wakeup(m);
|
||||
for (k = 0; k < i + j; k += AGP_PAGE_SIZE)
|
||||
AGP_UNBIND_PAGE(dev, offset + k);
|
||||
for (k = 0; k <= i; k += PAGE_SIZE) {
|
||||
m = vm_page_lookup(mem->am_obj,
|
||||
OFF_TO_IDX(k));
|
||||
vm_page_unwire(m, 0);
|
||||
}
|
||||
lockmgr(&sc->as_lock, LK_RELEASE, 0, curproc);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
vm_page_wakeup(m);
|
||||
}
|
||||
|
||||
/*
|
||||
* Flush the cpu cache since we are providing a new mapping
|
||||
* for these pages.
|
||||
*/
|
||||
agp_flush_cache();
|
||||
|
||||
/*
|
||||
* Make sure the chipset gets the new mappings.
|
||||
*/
|
||||
AGP_FLUSH_TLB(dev);
|
||||
|
||||
mem->am_offset = offset;
|
||||
mem->am_is_bound = 1;
|
||||
|
||||
lockmgr(&sc->as_lock, LK_RELEASE, 0, curproc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
agp_generic_unbind_memory(device_t dev, struct agp_memory *mem)
|
||||
{
|
||||
struct agp_softc *sc = device_get_softc(dev);
|
||||
vm_page_t m;
|
||||
int i;
|
||||
|
||||
lockmgr(&sc->as_lock, LK_EXCLUSIVE, 0, curproc);
|
||||
|
||||
if (!mem->am_is_bound) {
|
||||
device_printf(dev, "memory is not bound\n");
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Unbind the individual pages and flush the chipset's
|
||||
* TLB. Unwire the pages so they can be swapped.
|
||||
*/
|
||||
for (i = 0; i < mem->am_size; i += AGP_PAGE_SIZE)
|
||||
AGP_UNBIND_PAGE(dev, mem->am_offset + i);
|
||||
for (i = 0; i < mem->am_size; i += PAGE_SIZE) {
|
||||
m = vm_page_lookup(mem->am_obj, atop(i));
|
||||
vm_page_unwire(m, 0);
|
||||
}
|
||||
|
||||
agp_flush_cache();
|
||||
AGP_FLUSH_TLB(dev);
|
||||
|
||||
mem->am_offset = 0;
|
||||
mem->am_is_bound = 0;
|
||||
|
||||
lockmgr(&sc->as_lock, LK_RELEASE, 0, curproc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Helper functions for implementing user/kernel api */
|
||||
|
||||
static int
|
||||
agp_acquire_helper(device_t dev, enum agp_acquire_state state)
|
||||
{
|
||||
struct agp_softc *sc = device_get_softc(dev);
|
||||
|
||||
if (sc->as_state != AGP_ACQUIRE_FREE)
|
||||
return EBUSY;
|
||||
sc->as_state = state;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
agp_release_helper(device_t dev, enum agp_acquire_state state)
|
||||
{
|
||||
struct agp_softc *sc = device_get_softc(dev);
|
||||
struct agp_memory *mem;
|
||||
|
||||
if (sc->as_state == AGP_ACQUIRE_FREE)
|
||||
return 0;
|
||||
|
||||
if (sc->as_state != state)
|
||||
return EBUSY;
|
||||
|
||||
/*
|
||||
* Clear out the aperture and free any outstanding memory blocks.
|
||||
*/
|
||||
while ((mem = TAILQ_FIRST(&sc->as_memory)) != 0) {
|
||||
if (mem->am_is_bound)
|
||||
AGP_UNBIND_MEMORY(dev, mem);
|
||||
AGP_FREE_MEMORY(dev, mem);
|
||||
}
|
||||
|
||||
sc->as_state = AGP_ACQUIRE_FREE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct agp_memory *
|
||||
agp_find_memory(device_t dev, int id)
|
||||
{
|
||||
struct agp_softc *sc = device_get_softc(dev);
|
||||
struct agp_memory *mem;
|
||||
|
||||
AGP_DPF("searching for memory block %d\n", id);
|
||||
TAILQ_FOREACH(mem, &sc->as_memory, am_link) {
|
||||
AGP_DPF("considering memory block %d\n", mem->am_id);
|
||||
if (mem->am_id == id)
|
||||
return mem;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Implementation of the userland ioctl api */
|
||||
|
||||
static int
|
||||
agp_info_user(device_t dev, agp_info *info)
|
||||
{
|
||||
struct agp_softc *sc = device_get_softc(dev);
|
||||
|
||||
bzero(info, sizeof *info);
|
||||
info->bridge_id = pci_get_devid(dev);
|
||||
info->agp_mode =
|
||||
pci_read_config(dev, agp_find_caps(dev) + AGP_STATUS, 4);
|
||||
info->aper_base = rman_get_start(sc->as_aperture);
|
||||
info->aper_size = AGP_GET_APERTURE(dev) >> 20;
|
||||
info->pg_total = info->pg_system = sc->as_maxmem >> AGP_PAGE_SHIFT;
|
||||
info->pg_used = sc->as_allocated >> AGP_PAGE_SHIFT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
agp_setup_user(device_t dev, agp_setup *setup)
|
||||
{
|
||||
return AGP_ENABLE(dev, setup->agp_mode);
|
||||
}
|
||||
|
||||
static int
|
||||
agp_allocate_user(device_t dev, agp_allocate *alloc)
|
||||
{
|
||||
struct agp_memory *mem;
|
||||
|
||||
mem = AGP_ALLOC_MEMORY(dev,
|
||||
alloc->type,
|
||||
alloc->pg_count << AGP_PAGE_SHIFT);
|
||||
alloc->key = mem->am_id;
|
||||
alloc->physical = mem->am_physical;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
agp_deallocate_user(device_t dev, int id)
|
||||
{
|
||||
struct agp_memory *mem = agp_find_memory(dev, id);;
|
||||
|
||||
if (mem) {
|
||||
AGP_FREE_MEMORY(dev, mem);
|
||||
return 0;
|
||||
} else {
|
||||
return ENOENT;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
agp_bind_user(device_t dev, agp_bind *bind)
|
||||
{
|
||||
struct agp_memory *mem = agp_find_memory(dev, bind->key);
|
||||
|
||||
if (!mem)
|
||||
return ENOENT;
|
||||
|
||||
return AGP_BIND_MEMORY(dev, mem, bind->pg_start << AGP_PAGE_SHIFT);
|
||||
}
|
||||
|
||||
static int
|
||||
agp_unbind_user(device_t dev, agp_unbind *unbind)
|
||||
{
|
||||
struct agp_memory *mem = agp_find_memory(dev, unbind->key);
|
||||
|
||||
if (!mem)
|
||||
return ENOENT;
|
||||
|
||||
return AGP_UNBIND_MEMORY(dev, mem);
|
||||
}
|
||||
|
||||
static int
|
||||
agp_open(dev_t kdev, int oflags, int devtype, struct proc *p)
|
||||
{
|
||||
device_t dev = KDEV2DEV(kdev);
|
||||
struct agp_softc *sc = device_get_softc(dev);
|
||||
|
||||
if (!sc->as_isopen) {
|
||||
sc->as_isopen = 1;
|
||||
device_busy(dev);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
agp_close(dev_t kdev, int fflag, int devtype, struct proc *p)
|
||||
{
|
||||
device_t dev = KDEV2DEV(kdev);
|
||||
struct agp_softc *sc = device_get_softc(dev);
|
||||
|
||||
/*
|
||||
* Clear the GATT and force release on last close
|
||||
*/
|
||||
if (sc->as_state == AGP_ACQUIRE_USER)
|
||||
agp_release_helper(dev, AGP_ACQUIRE_USER);
|
||||
sc->as_isopen = 0;
|
||||
device_unbusy(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
agp_ioctl(dev_t kdev, u_long cmd, caddr_t data, int fflag, struct proc *p)
|
||||
{
|
||||
device_t dev = KDEV2DEV(kdev);
|
||||
|
||||
switch (cmd) {
|
||||
case AGPIOC_INFO:
|
||||
return agp_info_user(dev, (agp_info *) data);
|
||||
|
||||
case AGPIOC_ACQUIRE:
|
||||
return agp_acquire_helper(dev, AGP_ACQUIRE_USER);
|
||||
|
||||
case AGPIOC_RELEASE:
|
||||
return agp_release_helper(dev, AGP_ACQUIRE_USER);
|
||||
|
||||
case AGPIOC_SETUP:
|
||||
return agp_setup_user(dev, (agp_setup *)data);
|
||||
|
||||
case AGPIOC_ALLOCATE:
|
||||
return agp_allocate_user(dev, (agp_allocate *)data);
|
||||
|
||||
case AGPIOC_DEALLOCATE:
|
||||
return agp_deallocate_user(dev, *(int *) data);
|
||||
|
||||
case AGPIOC_BIND:
|
||||
return agp_bind_user(dev, (agp_bind *)data);
|
||||
|
||||
case AGPIOC_UNBIND:
|
||||
return agp_unbind_user(dev, (agp_unbind *)data);
|
||||
|
||||
}
|
||||
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
static int
|
||||
agp_mmap(dev_t kdev, vm_offset_t offset, int prot)
|
||||
{
|
||||
device_t dev = KDEV2DEV(kdev);
|
||||
struct agp_softc *sc = device_get_softc(dev);
|
||||
|
||||
if (offset > AGP_GET_APERTURE(dev))
|
||||
return -1;
|
||||
return atop(rman_get_start(sc->as_aperture) + offset);
|
||||
}
|
||||
|
||||
/* Implementation of the kernel api */
|
||||
|
||||
device_t
|
||||
agp_find_device()
|
||||
{
|
||||
if (!agp_devclass)
|
||||
return 0;
|
||||
return devclass_get_device(agp_devclass, 0);
|
||||
}
|
||||
|
||||
enum agp_acquire_state
|
||||
agp_state(device_t dev)
|
||||
{
|
||||
struct agp_softc *sc = device_get_softc(dev);
|
||||
return sc->as_state;
|
||||
}
|
||||
|
||||
void
|
||||
agp_get_info(device_t dev, struct agp_info *info)
|
||||
{
|
||||
struct agp_softc *sc = device_get_softc(dev);
|
||||
|
||||
info->ai_mode =
|
||||
pci_read_config(dev, agp_find_caps(dev) + AGP_STATUS, 4);
|
||||
info->ai_aperture_base = rman_get_start(sc->as_aperture);
|
||||
info->ai_aperture_size = (rman_get_end(sc->as_aperture)
|
||||
- rman_get_start(sc->as_aperture)) + 1;
|
||||
info->ai_memory_allowed = sc->as_maxmem;
|
||||
info->ai_memory_used = sc->as_allocated;
|
||||
}
|
||||
|
||||
int
|
||||
agp_acquire(device_t dev)
|
||||
{
|
||||
return agp_acquire_helper(dev, AGP_ACQUIRE_KERNEL);
|
||||
}
|
||||
|
||||
int
|
||||
agp_release(device_t dev)
|
||||
{
|
||||
return agp_release_helper(dev, AGP_ACQUIRE_KERNEL);
|
||||
}
|
||||
|
||||
int
|
||||
agp_enable(device_t dev, u_int32_t mode)
|
||||
{
|
||||
return AGP_ENABLE(dev, mode);
|
||||
}
|
||||
|
||||
void *agp_alloc_memory(device_t dev, int type, vm_size_t bytes)
|
||||
{
|
||||
return (void *) AGP_ALLOC_MEMORY(dev, type, bytes);
|
||||
}
|
||||
|
||||
void agp_free_memory(device_t dev, void *handle)
|
||||
{
|
||||
struct agp_memory *mem = (struct agp_memory *) handle;
|
||||
AGP_FREE_MEMORY(dev, mem);
|
||||
}
|
||||
|
||||
int agp_bind_memory(device_t dev, void *handle, vm_offset_t offset)
|
||||
{
|
||||
struct agp_memory *mem = (struct agp_memory *) handle;
|
||||
return AGP_BIND_MEMORY(dev, mem, offset);
|
||||
}
|
||||
|
||||
int agp_unbind_memory(device_t dev, void *handle)
|
||||
{
|
||||
struct agp_memory *mem = (struct agp_memory *) handle;
|
||||
return AGP_UNBIND_MEMORY(dev, mem);
|
||||
}
|
||||
|
||||
void agp_memory_info(device_t dev, void *handle, struct
|
||||
agp_memory_info *mi)
|
||||
{
|
||||
struct agp_memory *mem = (struct agp_memory *) handle;
|
||||
|
||||
mi->ami_size = mem->am_size;
|
||||
mi->ami_physical = mem->am_physical;
|
||||
mi->ami_offset = mem->am_offset;
|
||||
mi->ami_is_bound = mem->am_is_bound;
|
||||
}
|
264
sys/dev/agp/agp_ali.c
Normal file
264
sys/dev/agp/agp_ali.c
Normal file
@ -0,0 +1,264 @@
|
||||
/*-
|
||||
* Copyright (c) 2000 Doug Rabson
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#include "opt_bus.h"
|
||||
#include "opt_pci.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/lock.h>
|
||||
|
||||
#include <pci/pcivar.h>
|
||||
#include <pci/pcireg.h>
|
||||
#include <pci/agppriv.h>
|
||||
#include <pci/agpreg.h>
|
||||
|
||||
#include <vm/vm.h>
|
||||
#include <vm/vm_object.h>
|
||||
#include <vm/pmap.h>
|
||||
|
||||
struct agp_ali_softc {
|
||||
struct agp_softc agp;
|
||||
u_int32_t initial_aperture; /* aperture size at startup */
|
||||
struct agp_gatt *gatt;
|
||||
};
|
||||
|
||||
static const char*
|
||||
agp_ali_match(device_t dev)
|
||||
{
|
||||
if (pci_get_class(dev) != PCIC_BRIDGE
|
||||
|| pci_get_subclass(dev) != PCIS_BRIDGE_HOST)
|
||||
return NULL;
|
||||
|
||||
if (agp_find_caps(dev) == 0)
|
||||
return NULL;
|
||||
|
||||
switch (pci_get_devid(dev)) {
|
||||
case 0x154110b9:
|
||||
return ("Ali M1541 host to AGP bridge");
|
||||
};
|
||||
|
||||
if (pci_get_vendor(dev) == 0x10b9)
|
||||
return ("Ali Generic host to PCI bridge");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
agp_ali_probe(device_t dev)
|
||||
{
|
||||
const char *desc;
|
||||
|
||||
desc = agp_ali_match(dev);
|
||||
if (desc) {
|
||||
device_verbose(dev);
|
||||
device_set_desc(dev, desc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ENXIO;
|
||||
}
|
||||
|
||||
static int
|
||||
agp_ali_attach(device_t dev)
|
||||
{
|
||||
struct agp_ali_softc *sc = device_get_softc(dev);
|
||||
struct agp_gatt *gatt;
|
||||
int error;
|
||||
|
||||
error = agp_generic_attach(dev);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
sc->initial_aperture = AGP_GET_APERTURE(dev);
|
||||
|
||||
for (;;) {
|
||||
gatt = agp_alloc_gatt(dev);
|
||||
if (gatt)
|
||||
break;
|
||||
|
||||
/*
|
||||
* Probably contigmalloc failure. Try reducing the
|
||||
* aperture so that the gatt size reduces.
|
||||
*/
|
||||
if (AGP_SET_APERTURE(dev, AGP_GET_APERTURE(dev) / 2)) {
|
||||
agp_generic_detach(dev);
|
||||
return ENOMEM;
|
||||
}
|
||||
}
|
||||
sc->gatt = gatt;
|
||||
|
||||
/* Install the gatt. */
|
||||
pci_write_config(dev, AGP_ALI_ATTBASE,
|
||||
(gatt->ag_physical
|
||||
| (pci_read_config(dev, AGP_ALI_ATTBASE, 4) & 0xff)),
|
||||
4);
|
||||
|
||||
/* Enable the TLB. */
|
||||
pci_write_config(dev, AGP_ALI_TLBCTRL, 0x10, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
agp_ali_detach(device_t dev)
|
||||
{
|
||||
struct agp_ali_softc *sc = device_get_softc(dev);
|
||||
int error;
|
||||
|
||||
error = agp_generic_detach(dev);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
/* Disable the TLB.. */
|
||||
pci_write_config(dev, AGP_ALI_TLBCTRL, 0x90, 1);
|
||||
|
||||
/* Put the aperture back the way it started. */
|
||||
AGP_SET_APERTURE(dev, sc->initial_aperture);
|
||||
pci_write_config(dev, AGP_ALI_ATTBASE,
|
||||
pci_read_config(dev, AGP_ALI_ATTBASE, 4) & 0xff,
|
||||
4);
|
||||
|
||||
agp_free_gatt(sc->gatt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define M 1024*1024
|
||||
|
||||
static u_int32_t agp_ali_table[] = {
|
||||
0, /* 0 - invalid */
|
||||
1, /* 1 - invalid */
|
||||
2, /* 2 - invalid */
|
||||
4*M, /* 3 - invalid */
|
||||
8*M, /* 4 - invalid */
|
||||
0, /* 5 - invalid */
|
||||
16*M, /* 6 - invalid */
|
||||
32*M, /* 7 - invalid */
|
||||
64*M, /* 8 - invalid */
|
||||
128*M, /* 9 - invalid */
|
||||
256*M, /* 10 - invalid */
|
||||
};
|
||||
#define agp_ali_table_size (sizeof(agp_ali_table) / sizeof(agp_ali_table[0]))
|
||||
|
||||
static u_int32_t
|
||||
agp_ali_get_aperture(device_t dev)
|
||||
{
|
||||
/*
|
||||
* The aperture size is derived from the low bits of attbase.
|
||||
* I'm not sure this is correct..
|
||||
*/
|
||||
int i = pci_read_config(dev, AGP_ALI_ATTBASE, 4) & 0xff;
|
||||
if (i >= agp_ali_table_size)
|
||||
return 0;
|
||||
return agp_ali_table[i];
|
||||
}
|
||||
|
||||
static int
|
||||
agp_ali_set_aperture(device_t dev, u_int32_t aperture)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < agp_ali_table_size; i++)
|
||||
if (agp_ali_table[i] == aperture)
|
||||
break;
|
||||
if (i == agp_ali_table_size)
|
||||
return EINVAL;
|
||||
|
||||
pci_write_config(dev, AGP_ALI_ATTBASE,
|
||||
((pci_read_config(dev, AGP_ALI_ATTBASE, 4) & ~0xff)
|
||||
| i), 4);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
agp_ali_bind_page(device_t dev, int offset, vm_offset_t physical)
|
||||
{
|
||||
struct agp_ali_softc *sc = device_get_softc(dev);
|
||||
|
||||
if (offset < 0 || offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT))
|
||||
return EINVAL;
|
||||
|
||||
sc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = physical;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
agp_ali_unbind_page(device_t dev, int offset)
|
||||
{
|
||||
struct agp_ali_softc *sc = device_get_softc(dev);
|
||||
|
||||
if (offset < 0 || offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT))
|
||||
return EINVAL;
|
||||
|
||||
sc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
agp_ali_flush_tlb(device_t dev)
|
||||
{
|
||||
pci_write_config(dev, AGP_ALI_TLBCTRL, 0x90, 1);
|
||||
pci_write_config(dev, AGP_ALI_TLBCTRL, 0x10, 1);
|
||||
}
|
||||
|
||||
static device_method_t agp_ali_methods[] = {
|
||||
/* Device interface */
|
||||
DEVMETHOD(device_probe, agp_ali_probe),
|
||||
DEVMETHOD(device_attach, agp_ali_attach),
|
||||
DEVMETHOD(device_detach, agp_ali_detach),
|
||||
DEVMETHOD(device_shutdown, bus_generic_shutdown),
|
||||
DEVMETHOD(device_suspend, bus_generic_suspend),
|
||||
DEVMETHOD(device_resume, bus_generic_resume),
|
||||
|
||||
/* AGP interface */
|
||||
DEVMETHOD(agp_get_aperture, agp_ali_get_aperture),
|
||||
DEVMETHOD(agp_set_aperture, agp_ali_set_aperture),
|
||||
DEVMETHOD(agp_bind_page, agp_ali_bind_page),
|
||||
DEVMETHOD(agp_unbind_page, agp_ali_unbind_page),
|
||||
DEVMETHOD(agp_flush_tlb, agp_ali_flush_tlb),
|
||||
DEVMETHOD(agp_enable, agp_generic_enable),
|
||||
DEVMETHOD(agp_alloc_memory, agp_generic_alloc_memory),
|
||||
DEVMETHOD(agp_free_memory, agp_generic_free_memory),
|
||||
DEVMETHOD(agp_bind_memory, agp_generic_bind_memory),
|
||||
DEVMETHOD(agp_unbind_memory, agp_generic_unbind_memory),
|
||||
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
static driver_t agp_ali_driver = {
|
||||
"agp",
|
||||
agp_ali_methods,
|
||||
sizeof(struct agp_ali_softc),
|
||||
};
|
||||
|
||||
static devclass_t agp_devclass;
|
||||
|
||||
DRIVER_MODULE(agp_ali, pci, agp_ali_driver, agp_devclass, 0, 0);
|
276
sys/dev/agp/agp_amd.c
Normal file
276
sys/dev/agp/agp_amd.c
Normal file
@ -0,0 +1,276 @@
|
||||
/*-
|
||||
* Copyright (c) 2000 Doug Rabson
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#include "opt_bus.h"
|
||||
#include "opt_pci.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/lock.h>
|
||||
|
||||
#include <pci/pcivar.h>
|
||||
#include <pci/pcireg.h>
|
||||
#include <pci/agppriv.h>
|
||||
#include <pci/agpreg.h>
|
||||
|
||||
#include <vm/vm.h>
|
||||
#include <vm/vm_object.h>
|
||||
#include <vm/pmap.h>
|
||||
#include <machine/clock.h>
|
||||
#include <machine/bus.h>
|
||||
#include <machine/resource.h>
|
||||
#include <sys/rman.h>
|
||||
|
||||
#define READ2(off) bus_space_read_2(sc->bst, sc->bsh, off)
|
||||
#define READ4(off) bus_space_read_4(sc->bst, sc->bsh, off)
|
||||
#define WRITE2(off,v) bus_space_write_2(sc->bst, sc->bsh, off, v)
|
||||
#define WRITE4(off,v) bus_space_write_4(sc->bst, sc->bsh, off, v)
|
||||
|
||||
struct agp_amd_softc {
|
||||
struct agp_softc agp;
|
||||
struct resource *regs; /* memory mapped control registers */
|
||||
bus_space_tag_t bst; /* bus_space tag */
|
||||
bus_space_handle_t bsh; /* bus_space handle */
|
||||
u_int32_t initial_aperture; /* aperture size at startup */
|
||||
struct agp_gatt *gatt;
|
||||
};
|
||||
|
||||
static const char*
|
||||
agp_amd_match(device_t dev)
|
||||
{
|
||||
if (pci_get_class(dev) != PCIC_BRIDGE
|
||||
|| pci_get_subclass(dev) != PCIS_BRIDGE_HOST)
|
||||
return NULL;
|
||||
|
||||
if (agp_find_caps(dev) == 0)
|
||||
return NULL;
|
||||
|
||||
switch (pci_get_devid(dev)) {
|
||||
case 0x70061022:
|
||||
return ("AMD 751 host to AGP bridge");
|
||||
};
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
agp_amd_probe(device_t dev)
|
||||
{
|
||||
const char *desc;
|
||||
|
||||
desc = agp_amd_match(dev);
|
||||
if (desc) {
|
||||
device_verbose(dev);
|
||||
device_set_desc(dev, desc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ENXIO;
|
||||
}
|
||||
|
||||
static int
|
||||
agp_amd_attach(device_t dev)
|
||||
{
|
||||
struct agp_amd_softc *sc = device_get_softc(dev);
|
||||
struct agp_gatt *gatt;
|
||||
int error, rid;
|
||||
|
||||
error = agp_generic_attach(dev);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
rid = AGP_AMD751_REGISTERS;
|
||||
sc->regs = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid,
|
||||
0, ~0, 1, RF_ACTIVE);
|
||||
if (!sc->regs) {
|
||||
agp_generic_detach(dev);
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
sc->bst = rman_get_bustag(sc->regs);
|
||||
sc->bsh = rman_get_bushandle(sc->regs);
|
||||
|
||||
sc->initial_aperture = AGP_GET_APERTURE(dev);
|
||||
|
||||
for (;;) {
|
||||
gatt = agp_alloc_gatt(dev);
|
||||
if (gatt)
|
||||
break;
|
||||
|
||||
/*
|
||||
* Probably contigmalloc failure. Try reducing the
|
||||
* aperture so that the gatt size reduces.
|
||||
*/
|
||||
if (AGP_SET_APERTURE(dev, AGP_GET_APERTURE(dev) / 2))
|
||||
return ENOMEM;
|
||||
}
|
||||
sc->gatt = gatt;
|
||||
|
||||
/* Install the gatt. */
|
||||
WRITE4(AGP_AMD751_ATTBASE, gatt->ag_physical);
|
||||
|
||||
/* Enable synchronisation between host and agp. */
|
||||
pci_write_config(dev, AGP_AMD751_MODECTRL, 0x80, 1);
|
||||
|
||||
/* Enable the TLB and flush */
|
||||
WRITE2(AGP_AMD751_STATUS,
|
||||
READ2(AGP_AMD751_STATUS) | AGP_AMD751_STATUS_GCE);
|
||||
AGP_FLUSH_TLB(dev);
|
||||
|
||||
return agp_generic_attach(dev);
|
||||
}
|
||||
|
||||
static int
|
||||
agp_amd_detach(device_t dev)
|
||||
{
|
||||
struct agp_amd_softc *sc = device_get_softc(dev);
|
||||
|
||||
/* Disable the TLB.. */
|
||||
WRITE2(AGP_AMD751_STATUS,
|
||||
READ2(AGP_AMD751_STATUS) & ~AGP_AMD751_STATUS_GCE);
|
||||
|
||||
/* Disable host-agp sync */
|
||||
pci_write_config(dev, AGP_AMD751_MODECTRL, 0x00, 1);
|
||||
|
||||
/* Clear the GATT base */
|
||||
WRITE4(AGP_AMD751_ATTBASE, 0);
|
||||
|
||||
/* Put the aperture back the way it started. */
|
||||
AGP_SET_APERTURE(dev, sc->initial_aperture);
|
||||
|
||||
agp_free_gatt(sc->gatt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u_int32_t
|
||||
agp_amd_get_aperture(device_t dev)
|
||||
{
|
||||
int vas;
|
||||
|
||||
/*
|
||||
* The aperture size is equal to 32M<<vas.
|
||||
*/
|
||||
vas = (pci_read_config(dev, AGP_AMD751_APCTRL, 1) & 0x06) >> 1;
|
||||
return (32*1024*1024) << vas;
|
||||
}
|
||||
|
||||
static int
|
||||
agp_amd_set_aperture(device_t dev, u_int32_t aperture)
|
||||
{
|
||||
int vas;
|
||||
|
||||
/*
|
||||
* Check for a power of two and make sure its within the
|
||||
* programmable range.
|
||||
*/
|
||||
if (aperture & (aperture - 1)
|
||||
|| aperture < 32*1024*1024
|
||||
|| aperture > 2U*1024*1024*1024)
|
||||
return EINVAL;
|
||||
|
||||
vas = ffs(aperture / 32*1024*1024) - 1;
|
||||
|
||||
pci_write_config(dev, AGP_AMD751_APCTRL,
|
||||
((pci_read_config(dev, AGP_AMD751_APCTRL, 1) & ~0x06)
|
||||
| vas << 1), 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
agp_amd_bind_page(device_t dev, int offset, vm_offset_t physical)
|
||||
{
|
||||
struct agp_amd_softc *sc = device_get_softc(dev);
|
||||
|
||||
if (offset < 0 || offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT))
|
||||
return EINVAL;
|
||||
|
||||
sc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = physical | 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
agp_amd_unbind_page(device_t dev, int offset)
|
||||
{
|
||||
struct agp_amd_softc *sc = device_get_softc(dev);
|
||||
|
||||
if (offset < 0 || offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT))
|
||||
return EINVAL;
|
||||
|
||||
sc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
agp_amd_flush_tlb(device_t dev)
|
||||
{
|
||||
struct agp_amd_softc *sc = device_get_softc(dev);
|
||||
|
||||
/* Set the cache invalidate bit and wait for the chipset to clear */
|
||||
WRITE4(AGP_AMD751_TLBCTRL, 1);
|
||||
do {
|
||||
DELAY(1);
|
||||
} while (READ4(AGP_AMD751_TLBCTRL));
|
||||
}
|
||||
|
||||
static device_method_t agp_amd_methods[] = {
|
||||
/* Device interface */
|
||||
DEVMETHOD(device_probe, agp_amd_probe),
|
||||
DEVMETHOD(device_attach, agp_amd_attach),
|
||||
DEVMETHOD(device_detach, agp_amd_detach),
|
||||
DEVMETHOD(device_shutdown, bus_generic_shutdown),
|
||||
DEVMETHOD(device_suspend, bus_generic_suspend),
|
||||
DEVMETHOD(device_resume, bus_generic_resume),
|
||||
|
||||
/* AGP interface */
|
||||
DEVMETHOD(agp_get_aperture, agp_amd_get_aperture),
|
||||
DEVMETHOD(agp_set_aperture, agp_amd_set_aperture),
|
||||
DEVMETHOD(agp_bind_page, agp_amd_bind_page),
|
||||
DEVMETHOD(agp_unbind_page, agp_amd_unbind_page),
|
||||
DEVMETHOD(agp_flush_tlb, agp_amd_flush_tlb),
|
||||
DEVMETHOD(agp_enable, agp_generic_enable),
|
||||
DEVMETHOD(agp_alloc_memory, agp_generic_alloc_memory),
|
||||
DEVMETHOD(agp_free_memory, agp_generic_free_memory),
|
||||
DEVMETHOD(agp_bind_memory, agp_generic_bind_memory),
|
||||
DEVMETHOD(agp_unbind_memory, agp_generic_unbind_memory),
|
||||
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
static driver_t agp_amd_driver = {
|
||||
"agp",
|
||||
agp_amd_methods,
|
||||
sizeof(struct agp_amd_softc),
|
||||
};
|
||||
|
||||
static devclass_t agp_devclass;
|
||||
|
||||
DRIVER_MODULE(agp_amd, pci, agp_amd_driver, agp_devclass, 0, 0);
|
134
sys/dev/agp/agp_if.m
Normal file
134
sys/dev/agp/agp_if.m
Normal file
@ -0,0 +1,134 @@
|
||||
#
|
||||
# Copyright (c) 2000 Doug Rabson
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
# SUCH DAMAGE.
|
||||
#
|
||||
# $FreeBSD$
|
||||
#
|
||||
|
||||
#include <sys/bus.h>
|
||||
|
||||
#
|
||||
# The AGP interface is used internally to the agp driver to isolate the
|
||||
# differences between various AGP chipsets into chipset mini drivers. It
|
||||
# should not be used outside the AGP driver. The kernel api for accessing
|
||||
# AGP functionality is described in <pci/agpvar,h>
|
||||
#
|
||||
INTERFACE agp;
|
||||
|
||||
#
|
||||
# Return the current aperture size.
|
||||
#
|
||||
METHOD u_int32_t get_aperture {
|
||||
device_t dev;
|
||||
};
|
||||
|
||||
#
|
||||
# Set the size of the aperture. Return EINVAL on error or 0 on success.
|
||||
#
|
||||
METHOD int set_aperture {
|
||||
device_t dev;
|
||||
u_int32_t aperture;
|
||||
};
|
||||
|
||||
#
|
||||
# Bind a single page in the AGP aperture to a given physical address.
|
||||
# The offset is a byte offset within the aperture which must be
|
||||
# aligned to an AGP page boundary.
|
||||
#
|
||||
METHOD int bind_page {
|
||||
device_t dev;
|
||||
vm_offset_t offset;
|
||||
vm_offset_t physical;
|
||||
};
|
||||
|
||||
#
|
||||
# Unbind a single page in the AGP aperture.
|
||||
#
|
||||
METHOD int unbind_page {
|
||||
device_t dev;
|
||||
vm_offset_t offset;
|
||||
};
|
||||
|
||||
#
|
||||
# Flush the GATT TLB. This is used after a call to bind_page to
|
||||
# ensure that any mappings cached in the chipset are discarded.
|
||||
#
|
||||
METHOD void flush_tlb {
|
||||
device_t dev;
|
||||
};
|
||||
|
||||
#
|
||||
# Enable the agp hardware with the relavent mode. The mode bits are
|
||||
# defined in <pci/agpreg.h>
|
||||
#
|
||||
METHOD int enable {
|
||||
device_t dev;
|
||||
u_int32_t mode;
|
||||
};
|
||||
|
||||
#
|
||||
# Allocate memory of a given type. The type is a chipset-specific
|
||||
# code which is used by certain integrated agp graphics chips
|
||||
# (basically just the i810 for now) to access special features of
|
||||
# the chipset. An opaque handle representing the memory region is
|
||||
# returned and can be used as an argument to free_memory, bind_memory
|
||||
# and unbind_memory.
|
||||
#
|
||||
# The size is specified in bytes but must be a multiple of the AGP
|
||||
# page size.
|
||||
#
|
||||
METHOD struct agp_memory * alloc_memory {
|
||||
device_t dev;
|
||||
int type;
|
||||
vm_size_t size;
|
||||
};
|
||||
|
||||
#
|
||||
# Free a memory region previously allocated with alloc_memory. Return
|
||||
# EBUSY if the memory is bound.
|
||||
#
|
||||
METHOD int free_memory {
|
||||
device_t dev;
|
||||
struct agp_memory *mem;
|
||||
};
|
||||
|
||||
#
|
||||
# Bind a memory region to a specific byte offset within the chipset's
|
||||
# AGP aperture. This effectively defines a range of contiguous
|
||||
# physical address which alias the (possibly uncontiguous) pages in
|
||||
# the memory region.
|
||||
#
|
||||
METHOD int bind_memory {
|
||||
device_t dev;
|
||||
struct agp_memory *mem;
|
||||
vm_offset_t offset;
|
||||
};
|
||||
|
||||
#
|
||||
# Unbind a memory region bound with bind_memory.
|
||||
#
|
||||
METHOD int unbind_memory {
|
||||
device_t dev;
|
||||
struct agp_memory *handle;
|
||||
};
|
266
sys/dev/agp/agp_intel.c
Normal file
266
sys/dev/agp/agp_intel.c
Normal file
@ -0,0 +1,266 @@
|
||||
/*-
|
||||
* Copyright (c) 2000 Doug Rabson
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#include "opt_bus.h"
|
||||
#include "opt_pci.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/lock.h>
|
||||
|
||||
#include <pci/pcivar.h>
|
||||
#include <pci/pcireg.h>
|
||||
#include <pci/agppriv.h>
|
||||
#include <pci/agpreg.h>
|
||||
|
||||
#include <vm/vm.h>
|
||||
#include <vm/vm_object.h>
|
||||
#include <vm/pmap.h>
|
||||
|
||||
struct agp_intel_softc {
|
||||
struct agp_softc agp;
|
||||
u_int32_t initial_aperture; /* aperture size at startup */
|
||||
struct agp_gatt *gatt;
|
||||
};
|
||||
|
||||
static const char*
|
||||
agp_intel_match(device_t dev)
|
||||
{
|
||||
if (pci_get_class(dev) != PCIC_BRIDGE
|
||||
|| pci_get_subclass(dev) != PCIS_BRIDGE_HOST)
|
||||
return NULL;
|
||||
|
||||
if (agp_find_caps(dev) == 0)
|
||||
return NULL;
|
||||
|
||||
switch (pci_get_devid(dev)) {
|
||||
/* Intel -- vendor 0x8086 */
|
||||
case 0x71808086:
|
||||
return ("Intel 82443LX (440 LX) host to PCI bridge");
|
||||
|
||||
case 0x71908086:
|
||||
return ("Intel 82443BX (440 BX) host to PCI bridge");
|
||||
|
||||
case 0x71a08086:
|
||||
return ("Intel 82443GX host to PCI bridge");
|
||||
|
||||
case 0x71a18086:
|
||||
return ("Intel 82443GX host to AGP bridge");
|
||||
};
|
||||
|
||||
if (pci_get_vendor(dev) == 0x8086)
|
||||
return ("Intel Generic host to PCI bridge");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
agp_intel_probe(device_t dev)
|
||||
{
|
||||
const char *desc;
|
||||
|
||||
desc = agp_intel_match(dev);
|
||||
if (desc) {
|
||||
device_verbose(dev);
|
||||
device_set_desc(dev, desc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ENXIO;
|
||||
}
|
||||
|
||||
static int
|
||||
agp_intel_attach(device_t dev)
|
||||
{
|
||||
struct agp_intel_softc *sc = device_get_softc(dev);
|
||||
struct agp_gatt *gatt;
|
||||
int error;
|
||||
|
||||
error = agp_generic_attach(dev);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
sc->initial_aperture = AGP_GET_APERTURE(dev);
|
||||
|
||||
for (;;) {
|
||||
gatt = agp_alloc_gatt(dev);
|
||||
if (gatt)
|
||||
break;
|
||||
|
||||
/*
|
||||
* Probably contigmalloc failure. Try reducing the
|
||||
* aperture so that the gatt size reduces.
|
||||
*/
|
||||
if (AGP_SET_APERTURE(dev, AGP_GET_APERTURE(dev) / 2)) {
|
||||
agp_generic_detach(dev);
|
||||
return ENOMEM;
|
||||
}
|
||||
}
|
||||
sc->gatt = gatt;
|
||||
|
||||
/* Install the gatt. */
|
||||
pci_write_config(dev, AGP_INTEL_ATTBASE, gatt->ag_physical, 4);
|
||||
|
||||
/* Enable things, clear errors etc. */
|
||||
pci_write_config(dev, AGP_INTEL_AGPCTRL, 0x2280, 4);
|
||||
pci_write_config(dev, AGP_INTEL_NBXCFG,
|
||||
(pci_read_config(dev, AGP_INTEL_NBXCFG, 4)
|
||||
& ~(1 << 10)) | (1 << 9), 4);
|
||||
pci_write_config(dev, AGP_INTEL_ERRSTS + 1, 7, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
agp_intel_detach(device_t dev)
|
||||
{
|
||||
struct agp_intel_softc *sc = device_get_softc(dev);
|
||||
int error;
|
||||
|
||||
error = agp_generic_detach(dev);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
printf("%s: set NBXCFG to %x\n", __FUNCTION__,
|
||||
(pci_read_config(dev, AGP_INTEL_NBXCFG, 4)
|
||||
& ~(1 << 9)));
|
||||
pci_write_config(dev, AGP_INTEL_NBXCFG,
|
||||
(pci_read_config(dev, AGP_INTEL_NBXCFG, 4)
|
||||
& ~(1 << 9)), 4);
|
||||
pci_write_config(dev, AGP_INTEL_ATTBASE, 0, 4);
|
||||
AGP_SET_APERTURE(dev, sc->initial_aperture);
|
||||
agp_free_gatt(sc->gatt);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u_int32_t
|
||||
agp_intel_get_aperture(device_t dev)
|
||||
{
|
||||
u_int32_t apsize;
|
||||
|
||||
apsize = pci_read_config(dev, AGP_INTEL_APSIZE, 1) & 0x1f;
|
||||
|
||||
/*
|
||||
* The size is determined by the number of low bits of
|
||||
* register APBASE which are forced to zero. The low 22 bits
|
||||
* are always forced to zero and each zero bit in the apsize
|
||||
* field just read forces the corresponding bit in the 27:22
|
||||
* to be zero. We calculate the aperture size accordingly.
|
||||
*/
|
||||
return (((apsize ^ 0x1f) << 22) | ((1 << 22) - 1)) + 1;
|
||||
}
|
||||
|
||||
static int
|
||||
agp_intel_set_aperture(device_t dev, u_int32_t aperture)
|
||||
{
|
||||
u_int32_t apsize;
|
||||
|
||||
/*
|
||||
* Reverse the magic from get_aperture.
|
||||
*/
|
||||
apsize = ((aperture - 1) >> 22) ^ 0x1f;
|
||||
|
||||
/*
|
||||
* Double check for sanity.
|
||||
*/
|
||||
if ((((apsize ^ 0x1f) << 22) | ((1 << 22) - 1)) + 1 != aperture)
|
||||
return EINVAL;
|
||||
|
||||
pci_write_config(dev, AGP_INTEL_APSIZE, apsize, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
agp_intel_bind_page(device_t dev, int offset, vm_offset_t physical)
|
||||
{
|
||||
struct agp_intel_softc *sc = device_get_softc(dev);
|
||||
|
||||
if (offset < 0 || offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT))
|
||||
return EINVAL;
|
||||
|
||||
sc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = physical | 0x17;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
agp_intel_unbind_page(device_t dev, int offset)
|
||||
{
|
||||
struct agp_intel_softc *sc = device_get_softc(dev);
|
||||
|
||||
if (offset < 0 || offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT))
|
||||
return EINVAL;
|
||||
|
||||
sc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
agp_intel_flush_tlb(device_t dev)
|
||||
{
|
||||
pci_write_config(dev, AGP_INTEL_AGPCTRL, 0x2200, 4);
|
||||
pci_write_config(dev, AGP_INTEL_AGPCTRL, 0x2280, 4);
|
||||
}
|
||||
|
||||
static device_method_t agp_intel_methods[] = {
|
||||
/* Device interface */
|
||||
DEVMETHOD(device_probe, agp_intel_probe),
|
||||
DEVMETHOD(device_attach, agp_intel_attach),
|
||||
DEVMETHOD(device_detach, agp_intel_detach),
|
||||
DEVMETHOD(device_shutdown, bus_generic_shutdown),
|
||||
DEVMETHOD(device_suspend, bus_generic_suspend),
|
||||
DEVMETHOD(device_resume, bus_generic_resume),
|
||||
|
||||
/* AGP interface */
|
||||
DEVMETHOD(agp_get_aperture, agp_intel_get_aperture),
|
||||
DEVMETHOD(agp_set_aperture, agp_intel_set_aperture),
|
||||
DEVMETHOD(agp_bind_page, agp_intel_bind_page),
|
||||
DEVMETHOD(agp_unbind_page, agp_intel_unbind_page),
|
||||
DEVMETHOD(agp_flush_tlb, agp_intel_flush_tlb),
|
||||
DEVMETHOD(agp_enable, agp_generic_enable),
|
||||
DEVMETHOD(agp_alloc_memory, agp_generic_alloc_memory),
|
||||
DEVMETHOD(agp_free_memory, agp_generic_free_memory),
|
||||
DEVMETHOD(agp_bind_memory, agp_generic_bind_memory),
|
||||
DEVMETHOD(agp_unbind_memory, agp_generic_unbind_memory),
|
||||
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
static driver_t agp_intel_driver = {
|
||||
"agp",
|
||||
agp_intel_methods,
|
||||
sizeof(struct agp_intel_softc),
|
||||
};
|
||||
|
||||
static devclass_t agp_devclass;
|
||||
|
||||
DRIVER_MODULE(agp_intel, pci, agp_intel_driver, agp_devclass, 0, 0);
|
256
sys/dev/agp/agp_sis.c
Normal file
256
sys/dev/agp/agp_sis.c
Normal file
@ -0,0 +1,256 @@
|
||||
/*-
|
||||
* Copyright (c) 2000 Doug Rabson
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#include "opt_bus.h"
|
||||
#include "opt_pci.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/lock.h>
|
||||
|
||||
#include <pci/pcivar.h>
|
||||
#include <pci/pcireg.h>
|
||||
#include <pci/agppriv.h>
|
||||
#include <pci/agpreg.h>
|
||||
|
||||
#include <vm/vm.h>
|
||||
#include <vm/vm_object.h>
|
||||
#include <vm/pmap.h>
|
||||
|
||||
struct agp_sis_softc {
|
||||
struct agp_softc agp;
|
||||
u_int32_t initial_aperture; /* aperture size at startup */
|
||||
struct agp_gatt *gatt;
|
||||
};
|
||||
|
||||
static const char*
|
||||
agp_sis_match(device_t dev)
|
||||
{
|
||||
if (pci_get_class(dev) != PCIC_BRIDGE
|
||||
|| pci_get_subclass(dev) != PCIS_BRIDGE_HOST)
|
||||
return NULL;
|
||||
|
||||
if (agp_find_caps(dev) == 0)
|
||||
return NULL;
|
||||
|
||||
switch (pci_get_devid(dev)) {
|
||||
case 0x00011039:
|
||||
return ("SiS 5591 host to AGP bridge");
|
||||
};
|
||||
|
||||
if (pci_get_vendor(dev) == 0x1039)
|
||||
return ("SIS Generic host to PCI bridge");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
agp_sis_probe(device_t dev)
|
||||
{
|
||||
const char *desc;
|
||||
|
||||
desc = agp_sis_match(dev);
|
||||
if (desc) {
|
||||
device_verbose(dev);
|
||||
device_set_desc(dev, desc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ENXIO;
|
||||
}
|
||||
|
||||
static int
|
||||
agp_sis_attach(device_t dev)
|
||||
{
|
||||
struct agp_sis_softc *sc = device_get_softc(dev);
|
||||
struct agp_gatt *gatt;
|
||||
int error;
|
||||
|
||||
error = agp_generic_attach(dev);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
sc->initial_aperture = AGP_GET_APERTURE(dev);
|
||||
|
||||
for (;;) {
|
||||
gatt = agp_alloc_gatt(dev);
|
||||
if (gatt)
|
||||
break;
|
||||
|
||||
/*
|
||||
* Probably contigmalloc failure. Try reducing the
|
||||
* aperture so that the gatt size reduces.
|
||||
*/
|
||||
if (AGP_SET_APERTURE(dev, AGP_GET_APERTURE(dev) / 2)) {
|
||||
agp_generic_detach(dev);
|
||||
return ENOMEM;
|
||||
}
|
||||
}
|
||||
sc->gatt = gatt;
|
||||
|
||||
/* Install the gatt. */
|
||||
pci_write_config(dev, AGP_SIS_ATTBASE, gatt->ag_physical, 4);
|
||||
|
||||
/* Enable the aperture. */
|
||||
pci_write_config(dev, AGP_SIS_WINCTRL,
|
||||
pci_read_config(dev, AGP_SIS_WINCTRL, 1) | 3, 1);
|
||||
|
||||
/*
|
||||
* Enable the TLB and make it automatically invalidate entries
|
||||
* when the GATT is written.
|
||||
*/
|
||||
pci_write_config(dev, AGP_SIS_TLBCTRL, 0x05, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
agp_sis_detach(device_t dev)
|
||||
{
|
||||
struct agp_sis_softc *sc = device_get_softc(dev);
|
||||
int error;
|
||||
|
||||
error = agp_generic_detach(dev);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
/* Disable the aperture.. */
|
||||
pci_write_config(dev, AGP_SIS_WINCTRL,
|
||||
pci_read_config(dev, AGP_SIS_WINCTRL, 1) & ~3, 1);
|
||||
|
||||
/* and the TLB. */
|
||||
pci_write_config(dev, AGP_SIS_TLBCTRL, 0, 1);
|
||||
|
||||
/* Put the aperture back the way it started. */
|
||||
AGP_SET_APERTURE(dev, sc->initial_aperture);
|
||||
|
||||
agp_free_gatt(sc->gatt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u_int32_t
|
||||
agp_sis_get_aperture(device_t dev)
|
||||
{
|
||||
int gws;
|
||||
|
||||
/*
|
||||
* The aperture size is equal to 4M<<gws.
|
||||
*/
|
||||
gws = (pci_read_config(dev, AGP_SIS_WINCTRL, 1) & 0x70) >> 4;
|
||||
return (4*1024*1024) << gws;
|
||||
}
|
||||
|
||||
static int
|
||||
agp_sis_set_aperture(device_t dev, u_int32_t aperture)
|
||||
{
|
||||
int gws;
|
||||
|
||||
/*
|
||||
* Check for a power of two and make sure its within the
|
||||
* programmable range.
|
||||
*/
|
||||
if (aperture & (aperture - 1)
|
||||
|| aperture < 4*1024*1024
|
||||
|| aperture > 256*1024*1024)
|
||||
return EINVAL;
|
||||
|
||||
gws = ffs(aperture / 4*1024*1024) - 1;
|
||||
|
||||
pci_write_config(dev, AGP_SIS_WINCTRL,
|
||||
((pci_read_config(dev, AGP_SIS_WINCTRL, 1) & ~0x70)
|
||||
| gws << 4), 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
agp_sis_bind_page(device_t dev, int offset, vm_offset_t physical)
|
||||
{
|
||||
struct agp_sis_softc *sc = device_get_softc(dev);
|
||||
|
||||
if (offset < 0 || offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT))
|
||||
return EINVAL;
|
||||
|
||||
sc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = physical;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
agp_sis_unbind_page(device_t dev, int offset)
|
||||
{
|
||||
struct agp_sis_softc *sc = device_get_softc(dev);
|
||||
|
||||
if (offset < 0 || offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT))
|
||||
return EINVAL;
|
||||
|
||||
sc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
agp_sis_flush_tlb(device_t dev)
|
||||
{
|
||||
pci_write_config(dev, AGP_SIS_TLBFLUSH, 0x02, 1);
|
||||
}
|
||||
|
||||
static device_method_t agp_sis_methods[] = {
|
||||
/* Device interface */
|
||||
DEVMETHOD(device_probe, agp_sis_probe),
|
||||
DEVMETHOD(device_attach, agp_sis_attach),
|
||||
DEVMETHOD(device_detach, agp_sis_detach),
|
||||
DEVMETHOD(device_shutdown, bus_generic_shutdown),
|
||||
DEVMETHOD(device_suspend, bus_generic_suspend),
|
||||
DEVMETHOD(device_resume, bus_generic_resume),
|
||||
|
||||
/* AGP interface */
|
||||
DEVMETHOD(agp_get_aperture, agp_sis_get_aperture),
|
||||
DEVMETHOD(agp_set_aperture, agp_sis_set_aperture),
|
||||
DEVMETHOD(agp_bind_page, agp_sis_bind_page),
|
||||
DEVMETHOD(agp_unbind_page, agp_sis_unbind_page),
|
||||
DEVMETHOD(agp_flush_tlb, agp_sis_flush_tlb),
|
||||
DEVMETHOD(agp_enable, agp_generic_enable),
|
||||
DEVMETHOD(agp_alloc_memory, agp_generic_alloc_memory),
|
||||
DEVMETHOD(agp_free_memory, agp_generic_free_memory),
|
||||
DEVMETHOD(agp_bind_memory, agp_generic_bind_memory),
|
||||
DEVMETHOD(agp_unbind_memory, agp_generic_unbind_memory),
|
||||
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
static driver_t agp_sis_driver = {
|
||||
"agp",
|
||||
agp_sis_methods,
|
||||
sizeof(struct agp_sis_softc),
|
||||
};
|
||||
|
||||
static devclass_t agp_devclass;
|
||||
|
||||
DRIVER_MODULE(agp_sis, pci, agp_sis_driver, agp_devclass, 0, 0);
|
253
sys/dev/agp/agp_via.c
Normal file
253
sys/dev/agp/agp_via.c
Normal file
@ -0,0 +1,253 @@
|
||||
/*-
|
||||
* Copyright (c) 2000 Doug Rabson
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#include "opt_bus.h"
|
||||
#include "opt_pci.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/lock.h>
|
||||
|
||||
#include <pci/pcivar.h>
|
||||
#include <pci/pcireg.h>
|
||||
#include <pci/agppriv.h>
|
||||
#include <pci/agpreg.h>
|
||||
|
||||
#include <vm/vm.h>
|
||||
#include <vm/vm_object.h>
|
||||
#include <vm/pmap.h>
|
||||
|
||||
struct agp_via_softc {
|
||||
struct agp_softc agp;
|
||||
u_int32_t initial_aperture; /* aperture size at startup */
|
||||
struct agp_gatt *gatt;
|
||||
};
|
||||
|
||||
static const char*
|
||||
agp_via_match(device_t dev)
|
||||
{
|
||||
if (pci_get_class(dev) != PCIC_BRIDGE
|
||||
|| pci_get_subclass(dev) != PCIS_BRIDGE_HOST)
|
||||
return NULL;
|
||||
|
||||
if (agp_find_caps(dev) == 0)
|
||||
return NULL;
|
||||
|
||||
switch (pci_get_devid(dev)) {
|
||||
case 0x05011106:
|
||||
return ("VIA 8501 (Apollo MVP4) host to PCI bridge");
|
||||
case 0x05971106:
|
||||
return ("VIA 82C597 (Apollo VP3) host to PCI bridge");
|
||||
case 0x05981106:
|
||||
return ("VIA 82C598 (Apollo MVP3) host to PCI bridge");
|
||||
case 0x06911106:
|
||||
return ("VIA 82C691 (Apollo Pro) host to PCI bridge");
|
||||
};
|
||||
|
||||
if (pci_get_vendor(dev) == 0x1106)
|
||||
return ("VIA Generic host to PCI bridge");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
agp_via_probe(device_t dev)
|
||||
{
|
||||
const char *desc;
|
||||
|
||||
desc = agp_via_match(dev);
|
||||
if (desc) {
|
||||
device_verbose(dev);
|
||||
device_set_desc(dev, desc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ENXIO;
|
||||
}
|
||||
|
||||
static int
|
||||
agp_via_attach(device_t dev)
|
||||
{
|
||||
struct agp_via_softc *sc = device_get_softc(dev);
|
||||
struct agp_gatt *gatt;
|
||||
int error;
|
||||
|
||||
error = agp_generic_attach(dev);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
sc->initial_aperture = AGP_GET_APERTURE(dev);
|
||||
|
||||
for (;;) {
|
||||
gatt = agp_alloc_gatt(dev);
|
||||
if (gatt)
|
||||
break;
|
||||
|
||||
/*
|
||||
* Probably contigmalloc failure. Try reducing the
|
||||
* aperture so that the gatt size reduces.
|
||||
*/
|
||||
if (AGP_SET_APERTURE(dev, AGP_GET_APERTURE(dev) / 2)) {
|
||||
agp_generic_detach(dev);
|
||||
return ENOMEM;
|
||||
}
|
||||
}
|
||||
sc->gatt = gatt;
|
||||
|
||||
/* Install the gatt. */
|
||||
pci_write_config(dev, AGP_VIA_ATTBASE, gatt->ag_physical | 3, 4);
|
||||
|
||||
/* Enable the aperture. */
|
||||
pci_write_config(dev, AGP_VIA_GARTCTRL, 0x0f, 4);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
agp_via_detach(device_t dev)
|
||||
{
|
||||
struct agp_via_softc *sc = device_get_softc(dev);
|
||||
int error;
|
||||
|
||||
error = agp_generic_detach(dev);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
pci_write_config(dev, AGP_VIA_GARTCTRL, 0, 4);
|
||||
pci_write_config(dev, AGP_VIA_ATTBASE, 0, 4);
|
||||
AGP_SET_APERTURE(dev, sc->initial_aperture);
|
||||
agp_free_gatt(sc->gatt);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u_int32_t
|
||||
agp_via_get_aperture(device_t dev)
|
||||
{
|
||||
u_int32_t apsize;
|
||||
|
||||
apsize = pci_read_config(dev, AGP_VIA_APSIZE, 1) & 0x1f;
|
||||
|
||||
/*
|
||||
* The size is determined by the number of low bits of
|
||||
* register APBASE which are forced to zero. The low 20 bits
|
||||
* are always forced to zero and each zero bit in the apsize
|
||||
* field just read forces the corresponding bit in the 27:20
|
||||
* to be zero. We calculate the aperture size accordingly.
|
||||
*/
|
||||
return (((apsize ^ 0xff) << 20) | ((1 << 20) - 1)) + 1;
|
||||
}
|
||||
|
||||
static int
|
||||
agp_via_set_aperture(device_t dev, u_int32_t aperture)
|
||||
{
|
||||
u_int32_t apsize;
|
||||
|
||||
/*
|
||||
* Reverse the magic from get_aperture.
|
||||
*/
|
||||
apsize = ((aperture - 1) >> 20) ^ 0xff;
|
||||
|
||||
/*
|
||||
* Double check for sanity.
|
||||
*/
|
||||
if ((((apsize ^ 0xff) << 20) | ((1 << 20) - 1)) + 1 != aperture)
|
||||
return EINVAL;
|
||||
|
||||
pci_write_config(dev, AGP_VIA_APSIZE, apsize, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
agp_via_bind_page(device_t dev, int offset, vm_offset_t physical)
|
||||
{
|
||||
struct agp_via_softc *sc = device_get_softc(dev);
|
||||
|
||||
if (offset < 0 || offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT))
|
||||
return EINVAL;
|
||||
|
||||
sc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = physical;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
agp_via_unbind_page(device_t dev, int offset)
|
||||
{
|
||||
struct agp_via_softc *sc = device_get_softc(dev);
|
||||
|
||||
if (offset < 0 || offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT))
|
||||
return EINVAL;
|
||||
|
||||
sc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
agp_via_flush_tlb(device_t dev)
|
||||
{
|
||||
pci_write_config(dev, AGP_VIA_GARTCTRL, 0x8f, 4);
|
||||
pci_write_config(dev, AGP_VIA_GARTCTRL, 0x0f, 4);
|
||||
}
|
||||
|
||||
static device_method_t agp_via_methods[] = {
|
||||
/* Device interface */
|
||||
DEVMETHOD(device_probe, agp_via_probe),
|
||||
DEVMETHOD(device_attach, agp_via_attach),
|
||||
DEVMETHOD(device_detach, agp_via_detach),
|
||||
DEVMETHOD(device_shutdown, bus_generic_shutdown),
|
||||
DEVMETHOD(device_suspend, bus_generic_suspend),
|
||||
DEVMETHOD(device_resume, bus_generic_resume),
|
||||
|
||||
/* AGP interface */
|
||||
DEVMETHOD(agp_get_aperture, agp_via_get_aperture),
|
||||
DEVMETHOD(agp_set_aperture, agp_via_set_aperture),
|
||||
DEVMETHOD(agp_bind_page, agp_via_bind_page),
|
||||
DEVMETHOD(agp_unbind_page, agp_via_unbind_page),
|
||||
DEVMETHOD(agp_flush_tlb, agp_via_flush_tlb),
|
||||
DEVMETHOD(agp_enable, agp_generic_enable),
|
||||
DEVMETHOD(agp_alloc_memory, agp_generic_alloc_memory),
|
||||
DEVMETHOD(agp_free_memory, agp_generic_free_memory),
|
||||
DEVMETHOD(agp_bind_memory, agp_generic_bind_memory),
|
||||
DEVMETHOD(agp_unbind_memory, agp_generic_unbind_memory),
|
||||
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
static driver_t agp_via_driver = {
|
||||
"agp",
|
||||
agp_via_methods,
|
||||
sizeof(struct agp_via_softc),
|
||||
};
|
||||
|
||||
static devclass_t agp_devclass;
|
||||
|
||||
DRIVER_MODULE(agp_via, pci, agp_via_driver, agp_devclass, 0, 0);
|
103
sys/dev/agp/agppriv.h
Normal file
103
sys/dev/agp/agppriv.h
Normal file
@ -0,0 +1,103 @@
|
||||
/*-
|
||||
* Copyright (c) 2000 Doug Rabson
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _PCI_AGPPRIV_H_
|
||||
#define _PCI_AGPPRIV_H_
|
||||
|
||||
/*
|
||||
* This file *must not* be included by code outside the agp driver itself.
|
||||
*/
|
||||
|
||||
#include <sys/agpio.h>
|
||||
#include <pci/agpvar.h>
|
||||
|
||||
#define AGP_DEBUGxx
|
||||
|
||||
#ifdef AGP_DEBUG
|
||||
#define AGP_DPF(x...) do { \
|
||||
printf("agp: "); \
|
||||
printf(##x); \
|
||||
} while (0)
|
||||
#else
|
||||
#define AGP_DPF(x...) do {} while (0)
|
||||
#endif
|
||||
|
||||
#include "agp_if.h"
|
||||
|
||||
/*
|
||||
* Data structure to describe an AGP memory allocation.
|
||||
*/
|
||||
TAILQ_HEAD(agp_memory_list, agp_memory);
|
||||
struct agp_memory {
|
||||
TAILQ_ENTRY(agp_memory) am_link; /* wiring for the tailq */
|
||||
int am_id; /* unique id for block */
|
||||
vm_size_t am_size; /* number of bytes allocated */
|
||||
struct vm_object *am_obj; /* VM object owning pages */
|
||||
vm_offset_t am_physical; /* bogus hack for i810 */
|
||||
vm_offset_t am_offset; /* page offset if bound */
|
||||
int am_is_bound; /* non-zero if bound */
|
||||
};
|
||||
|
||||
/*
|
||||
* All chipset drivers must have this at the start of their softc.
|
||||
*/
|
||||
struct agp_softc {
|
||||
struct resource *as_aperture; /* location of aperture */
|
||||
u_int32_t as_maxmem; /* allocation upper bound */
|
||||
u_int32_t as_allocated; /* amount allocated */
|
||||
enum agp_acquire_state as_state;
|
||||
struct agp_memory_list as_memory; /* list of allocated memory */
|
||||
int as_nextid; /* next memory block id */
|
||||
int as_isopen; /* user device is open */
|
||||
dev_t as_devnode; /* from make_dev */
|
||||
struct lock as_lock; /* lock for access to GATT */
|
||||
};
|
||||
|
||||
struct agp_gatt {
|
||||
u_int32_t ag_entries;
|
||||
u_int32_t *ag_virtual;
|
||||
vm_offset_t ag_physical;
|
||||
};
|
||||
|
||||
u_int8_t agp_find_caps(device_t dev);
|
||||
struct agp_gatt *agp_alloc_gatt(device_t dev);
|
||||
void agp_free_gatt(struct agp_gatt *gatt);
|
||||
int agp_generic_attach(device_t dev);
|
||||
int agp_generic_detach(device_t dev);
|
||||
int agp_generic_enable(device_t dev, u_int32_t mode);
|
||||
struct agp_memory *agp_generic_alloc_memory(device_t dev, int type,
|
||||
vm_size_t size);
|
||||
int agp_generic_free_memory(device_t dev,
|
||||
struct agp_memory *mem);
|
||||
int agp_generic_bind_memory(device_t dev,
|
||||
struct agp_memory *mem,
|
||||
vm_offset_t offset);
|
||||
int agp_generic_unbind_memory(device_t dev,
|
||||
struct agp_memory *mem);
|
||||
|
||||
#endif /* !_PCI_AGPPRIV_H_ */
|
109
sys/dev/agp/agpreg.h
Normal file
109
sys/dev/agp/agpreg.h
Normal file
@ -0,0 +1,109 @@
|
||||
/*-
|
||||
* Copyright (c) 2000 Doug Rabson
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _PCI_AGPREG_H_
|
||||
#define _PCI_AGPREG_H_
|
||||
|
||||
/*
|
||||
* Offsets for various AGP configuration registers.
|
||||
*/
|
||||
#define AGP_APBASE 0x10
|
||||
#define AGP_CAPPTR 0x34
|
||||
|
||||
/*
|
||||
* Offsets from the AGP Capability pointer.
|
||||
*/
|
||||
#define AGP_CAPID 0x0
|
||||
#define AGP_CAPID_GET_MAJOR(x) (((x) & 0x00f00000U) >> 20)
|
||||
#define AGP_CAPID_GET_MINOR(x) (((x) & 0x000f0000U) >> 16)
|
||||
#define AGP_CAPID_GET_NEXT_PTR(x) (((x) & 0x0000ff00U) >> 8)
|
||||
#define AGP_CAPID_GET_CAP_ID(x) (((x) & 0x000000ffU) >> 0)
|
||||
|
||||
#define AGP_STATUS 0x4
|
||||
#define AGP_COMMAND 0x8
|
||||
|
||||
/*
|
||||
* Config offsets for Intel AGP chipsets.
|
||||
*/
|
||||
#define AGP_INTEL_NBXCFG 0x50
|
||||
#define AGP_INTEL_ERRSTS 0x91
|
||||
#define AGP_INTEL_AGPCTRL 0xb0
|
||||
#define AGP_INTEL_APSIZE 0xb4
|
||||
#define AGP_INTEL_ATTBASE 0xb8
|
||||
|
||||
/*
|
||||
* Config offsets for VIA AGP chipsets.
|
||||
*/
|
||||
#define AGP_VIA_GARTCTRL 0x80
|
||||
#define AGP_VIA_APSIZE 0x84
|
||||
#define AGP_VIA_ATTBASE 0x88
|
||||
|
||||
/*
|
||||
* Config offsets for SiS AGP chipsets.
|
||||
*/
|
||||
#define AGP_SIS_ATTBASE 0x90
|
||||
#define AGP_SIS_WINCTRL 0x94
|
||||
#define AGP_SIS_TLBCTRL 0x97
|
||||
#define AGP_SIS_TLBFLUSH 0x98
|
||||
|
||||
/*
|
||||
* Config offsets for Ali AGP chipsets.
|
||||
*/
|
||||
#define AGP_ALI_AGPCTRL 0xb8
|
||||
#define AGP_ALI_ATTBASE 0xbc
|
||||
#define AGP_ALI_TLBCTRL 0xc0
|
||||
|
||||
/*
|
||||
* Config offsets for the AMD 751 chipset.
|
||||
*/
|
||||
#define AGP_AMD751_REGISTERS 0x14
|
||||
#define AGP_AMD751_APCTRL 0xac
|
||||
#define AGP_AMD751_MODECTRL 0xb0
|
||||
|
||||
/*
|
||||
* Memory mapped register offsets for AMD 751 chipset.
|
||||
*/
|
||||
#define AGP_AMD751_CAPS 0x00
|
||||
#define AGP_AMD751_CAPS_EHI 0x0800
|
||||
#define AGP_AMD751_CAPS_P2P 0x0400
|
||||
#define AGP_AMD751_CAPS_MPC 0x0200
|
||||
#define AGP_AMD751_CAPS_VBE 0x0100
|
||||
#define AGP_AMD751_CAPS_REV 0x00ff
|
||||
#define AGP_AMD751_STATUS 0x02
|
||||
#define AGP_AMD751_STATUS_P2PS 0x0800
|
||||
#define AGP_AMD751_STATUS_GCS 0x0400
|
||||
#define AGP_AMD751_STATUS_MPS 0x0200
|
||||
#define AGP_AMD751_STATUS_VBES 0x0100
|
||||
#define AGP_AMD751_STATUS_P2PE 0x0008
|
||||
#define AGP_AMD751_STATUS_GCE 0x0004
|
||||
#define AGP_AMD751_STATUS_VBEE 0x0001
|
||||
#define AGP_AMD751_ATTBASE 0x04
|
||||
#define AGP_AMD751_TLBCTRL 0x0c
|
||||
|
||||
|
||||
#endif /* !_PCI_AGPREG_H_ */
|
125
sys/dev/agp/agpvar.h
Normal file
125
sys/dev/agp/agpvar.h
Normal file
@ -0,0 +1,125 @@
|
||||
/*-
|
||||
* Copyright (c) 2000 Doug Rabson
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _PCI_AGPVAR_H_
|
||||
#define _PCI_AGPVAR_H_
|
||||
|
||||
/*
|
||||
* The AGP chipset can be acquired by user or kernel code. If the
|
||||
* chipset has already been acquired, it cannot be acquired by another
|
||||
* user until the previous user has released it.
|
||||
*/
|
||||
enum agp_acquire_state {
|
||||
AGP_ACQUIRE_FREE,
|
||||
AGP_ACQUIRE_USER,
|
||||
AGP_ACQUIRE_KERNEL
|
||||
};
|
||||
|
||||
/*
|
||||
* This structure is used to query the state of the AGP system.
|
||||
*/
|
||||
struct agp_info {
|
||||
u_int32_t ai_mode;
|
||||
vm_offset_t ai_aperture_base;
|
||||
vm_size_t ai_aperture_size;
|
||||
vm_size_t ai_memory_allowed;
|
||||
vm_size_t ai_memory_used;
|
||||
u_int32_t ai_devid;
|
||||
};
|
||||
|
||||
struct agp_memory_info {
|
||||
vm_size_t ami_size; /* size in bytes */
|
||||
vm_offset_t ami_physical; /* bogus hack for i810 */
|
||||
vm_offset_t ami_offset; /* page offset if bound */
|
||||
int ami_is_bound; /* non-zero if bound */
|
||||
};
|
||||
|
||||
/*
|
||||
* Find the AGP device and return it.
|
||||
*/
|
||||
device_t agp_find_device(void);
|
||||
|
||||
/*
|
||||
* Return the current owner of the AGP chipset.
|
||||
*/
|
||||
enum agp_acquire_state agp_state(device_t dev);
|
||||
|
||||
/*
|
||||
* Query the state of the AGP system.
|
||||
*/
|
||||
void agp_get_info(device_t dev, struct agp_info *info);
|
||||
|
||||
/*
|
||||
* Acquire the AGP chipset for use by the kernel. Returns EBUSY if the
|
||||
* AGP chipset is already acquired by another user.
|
||||
*/
|
||||
int agp_acquire(device_t dev);
|
||||
|
||||
/*
|
||||
* Release the AGP chipset.
|
||||
*/
|
||||
int agp_release(device_t dev);
|
||||
|
||||
/*
|
||||
* Enable the agp hardware with the relavent mode. The mode bits are
|
||||
* defined in <pci/agpreg.h>
|
||||
*/
|
||||
int agp_enable(device_t dev, u_int32_t mode);
|
||||
|
||||
/*
|
||||
* Allocate physical memory suitable for mapping into the AGP
|
||||
* aperture. The value returned is an opaque handle which can be
|
||||
* passed to agp_bind(), agp_unbind() or agp_deallocate().
|
||||
*/
|
||||
void *agp_alloc_memory(device_t dev, int type, vm_size_t bytes);
|
||||
|
||||
/*
|
||||
* Free memory which was allocated with agp_allocate().
|
||||
*/
|
||||
void agp_free_memory(device_t dev, void *handle);
|
||||
|
||||
/*
|
||||
* Bind memory allocated with agp_allocate() at a given offset within
|
||||
* the AGP aperture. Returns EINVAL if the memory is already bound or
|
||||
* the offset is not at an AGP page boundary.
|
||||
*/
|
||||
int agp_bind_memory(device_t dev, void *handle, vm_offset_t offset);
|
||||
|
||||
/*
|
||||
* Unbind memory from the AGP aperture. Returns EINVAL if the memory
|
||||
* is not bound.
|
||||
*/
|
||||
int agp_unbind_memory(device_t dev, void *handle);
|
||||
|
||||
/*
|
||||
* Retrieve information about a memory block allocated with
|
||||
* agp_alloc_memory().
|
||||
*/
|
||||
void agp_memory_info(device_t dev, void *handle, struct agp_memory_info *mi);
|
||||
|
||||
#endif /* !_PCI_AGPVAR_H_ */
|
790
sys/pci/agp.c
Normal file
790
sys/pci/agp.c
Normal file
@ -0,0 +1,790 @@
|
||||
/*-
|
||||
* Copyright (c) 2000 Doug Rabson
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#include "opt_bus.h"
|
||||
#include "opt_pci.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/conf.h>
|
||||
#include <sys/ioccom.h>
|
||||
#include <sys/agpio.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/proc.h>
|
||||
|
||||
#include <pci/pcivar.h>
|
||||
#include <pci/pcireg.h>
|
||||
#include <pci/agppriv.h>
|
||||
#include <pci/agpvar.h>
|
||||
#include <pci/agpreg.h>
|
||||
|
||||
#include <vm/vm.h>
|
||||
#include <vm/vm_object.h>
|
||||
#include <vm/vm_page.h>
|
||||
#include <vm/vm_pageout.h>
|
||||
#include <vm/pmap.h>
|
||||
|
||||
#include <machine/md_var.h>
|
||||
#include <machine/bus.h>
|
||||
#include <machine/resource.h>
|
||||
#include <sys/rman.h>
|
||||
|
||||
MODULE_VERSION(agp, 1);
|
||||
|
||||
MALLOC_DEFINE(M_AGP, "agp", "AGP data structures");
|
||||
|
||||
#define CDEV_MAJOR 148
|
||||
/* agp_drv.c */
|
||||
static d_open_t agp_open;
|
||||
static d_close_t agp_close;
|
||||
static d_ioctl_t agp_ioctl;
|
||||
static d_mmap_t agp_mmap;
|
||||
|
||||
static struct cdevsw agp_cdevsw = {
|
||||
/* open */ agp_open,
|
||||
/* close */ agp_close,
|
||||
/* read */ noread,
|
||||
/* write */ nowrite,
|
||||
/* ioctl */ agp_ioctl,
|
||||
/* poll */ nopoll,
|
||||
/* mmap */ agp_mmap,
|
||||
/* strategy */ nostrategy,
|
||||
/* name */ "agp",
|
||||
/* maj */ CDEV_MAJOR,
|
||||
/* dump */ nodump,
|
||||
/* psize */ nopsize,
|
||||
/* flags */ D_TTY,
|
||||
/* bmaj */ -1
|
||||
};
|
||||
|
||||
static devclass_t agp_devclass;
|
||||
#define KDEV2DEV(kdev) devclass_get_device(agp_devclass, minor(kdev))
|
||||
|
||||
/* Helper functions for implementing chipset mini drivers. */
|
||||
|
||||
#ifdef __i386__
|
||||
#define agp_flush_cache() wbinvd()
|
||||
#endif
|
||||
|
||||
u_int8_t
|
||||
agp_find_caps(device_t dev)
|
||||
{
|
||||
u_int32_t status;
|
||||
u_int8_t ptr, next;
|
||||
|
||||
/*
|
||||
* Check the CAP_LIST bit of the PCI status register first.
|
||||
*/
|
||||
status = pci_read_config(dev, PCIR_STATUS, 2);
|
||||
if (!(status & 0x10))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Traverse the capabilities list.
|
||||
*/
|
||||
for (ptr = pci_read_config(dev, AGP_CAPPTR, 1);
|
||||
ptr != 0;
|
||||
ptr = next) {
|
||||
u_int32_t capid = pci_read_config(dev, ptr, 4);
|
||||
next = AGP_CAPID_GET_NEXT_PTR(capid);
|
||||
|
||||
/*
|
||||
* If this capability entry ID is 2, then we are done.
|
||||
*/
|
||||
if (AGP_CAPID_GET_CAP_ID(capid) == 2)
|
||||
return ptr;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find an AGP display device (if any).
|
||||
*/
|
||||
static device_t
|
||||
agp_find_display(void)
|
||||
{
|
||||
devclass_t pci = devclass_find("pci");
|
||||
device_t bus, dev = 0;
|
||||
device_t *kids;
|
||||
int busnum, numkids, i;
|
||||
|
||||
for (busnum = 0; busnum < devclass_get_maxunit(pci); busnum++) {
|
||||
bus = devclass_get_device(pci, busnum);
|
||||
if (!bus)
|
||||
continue;
|
||||
device_get_children(bus, &kids, &numkids);
|
||||
for (i = 0; i < numkids; i++) {
|
||||
dev = kids[i];
|
||||
if (pci_get_class(dev) == PCIC_DISPLAY
|
||||
&& pci_get_subclass(dev) == PCIS_DISPLAY_VGA)
|
||||
if (agp_find_caps(dev)) {
|
||||
free(kids, M_TEMP);
|
||||
return dev;
|
||||
}
|
||||
|
||||
}
|
||||
free(kids, M_TEMP);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct agp_gatt *
|
||||
agp_alloc_gatt(device_t dev)
|
||||
{
|
||||
u_int32_t apsize = AGP_GET_APERTURE(dev);
|
||||
u_int32_t entries = apsize >> AGP_PAGE_SHIFT;
|
||||
struct agp_gatt *gatt;
|
||||
|
||||
if (bootverbose)
|
||||
device_printf(dev,
|
||||
"allocating GATT for aperture of size %dM\n",
|
||||
apsize / (1024*1024));
|
||||
|
||||
gatt = malloc(sizeof(struct agp_gatt), M_AGP, M_NOWAIT);
|
||||
if (!gatt)
|
||||
return 0;
|
||||
|
||||
gatt->ag_entries = entries;
|
||||
gatt->ag_virtual = contigmalloc(entries * sizeof(u_int32_t), M_AGP, 0,
|
||||
0, ~0, PAGE_SIZE, 0);
|
||||
if (!gatt->ag_virtual) {
|
||||
if (bootverbose)
|
||||
device_printf(dev, "contiguous allocation failed\n");
|
||||
free(gatt, M_AGP);
|
||||
return 0;
|
||||
}
|
||||
bzero(gatt->ag_virtual, entries * sizeof(u_int32_t));
|
||||
gatt->ag_physical = vtophys((vm_offset_t) gatt->ag_virtual);
|
||||
agp_flush_cache();
|
||||
|
||||
return gatt;
|
||||
}
|
||||
|
||||
void
|
||||
agp_free_gatt(struct agp_gatt *gatt)
|
||||
{
|
||||
contigfree(gatt->ag_virtual,
|
||||
gatt->ag_entries * sizeof(u_int32_t), M_AGP);
|
||||
free(gatt, M_AGP);
|
||||
}
|
||||
|
||||
static int agp_max[][2] = {
|
||||
{0, 0},
|
||||
{32, 4},
|
||||
{64, 28},
|
||||
{128, 96},
|
||||
{256, 204},
|
||||
{512, 440},
|
||||
{1024, 942},
|
||||
{2048, 1920},
|
||||
{4096, 3932}
|
||||
};
|
||||
#define agp_max_size (sizeof(agp_max) / sizeof(agp_max[0]))
|
||||
|
||||
int
|
||||
agp_generic_attach(device_t dev)
|
||||
{
|
||||
struct agp_softc *sc = device_get_softc(dev);
|
||||
int rid, memsize, i;
|
||||
|
||||
/*
|
||||
* Find and map the aperture.
|
||||
*/
|
||||
rid = AGP_APBASE;
|
||||
sc->as_aperture = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid,
|
||||
0, ~0, 1, RF_ACTIVE);
|
||||
if (!sc->as_aperture)
|
||||
return ENOMEM;
|
||||
|
||||
/*
|
||||
* Work out an upper bound for agp memory allocation. This
|
||||
* uses a heurisitc table from the Linux driver.
|
||||
*/
|
||||
memsize = ptoa(Maxmem) >> 20;
|
||||
for (i = 0; i < agp_max_size; i++) {
|
||||
if (memsize <= agp_max[i][0])
|
||||
break;
|
||||
}
|
||||
if (i == agp_max_size) i = agp_max_size - 1;
|
||||
sc->as_maxmem = agp_max[i][1] << 20U;
|
||||
|
||||
/*
|
||||
* The lock is used to prevent re-entry to
|
||||
* agp_generic_bind_memory() since that function can sleep.
|
||||
*/
|
||||
lockinit(&sc->as_lock, PZERO|PCATCH, "agplk", 0, 0);
|
||||
|
||||
/*
|
||||
* Initialise stuff for the userland device.
|
||||
*/
|
||||
agp_devclass = devclass_find("agp");
|
||||
TAILQ_INIT(&sc->as_memory);
|
||||
sc->as_nextid = 1;
|
||||
|
||||
sc->as_devnode = make_dev(&agp_cdevsw,
|
||||
device_get_unit(dev),
|
||||
UID_ROOT,
|
||||
GID_WHEEL,
|
||||
0600,
|
||||
"agpgart");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
agp_generic_detach(device_t dev)
|
||||
{
|
||||
struct agp_softc *sc = device_get_softc(dev);
|
||||
bus_release_resource(dev, SYS_RES_MEMORY, AGP_APBASE, sc->as_aperture);
|
||||
lockmgr(&sc->as_lock, LK_DRAIN, 0, curproc);
|
||||
destroy_dev(sc->as_devnode);
|
||||
agp_flush_cache();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
agp_generic_enable(device_t dev, u_int32_t mode)
|
||||
{
|
||||
device_t mdev = agp_find_display();
|
||||
u_int32_t tstatus, mstatus;
|
||||
u_int32_t command;
|
||||
int rq, sba, fw, rate;;
|
||||
|
||||
if (!mdev) {
|
||||
AGP_DPF("can't find display\n");
|
||||
return ENXIO;
|
||||
}
|
||||
|
||||
tstatus = pci_read_config(dev, agp_find_caps(dev) + AGP_STATUS, 4);
|
||||
mstatus = pci_read_config(mdev, agp_find_caps(mdev) + AGP_STATUS, 4);
|
||||
|
||||
/* Set RQ to the min of mode, tstatus and mstatus */
|
||||
rq = AGP_MODE_GET_RQ(mode);
|
||||
if (AGP_MODE_GET_RQ(tstatus) < rq)
|
||||
rq = AGP_MODE_GET_RQ(tstatus);
|
||||
if (AGP_MODE_GET_RQ(mstatus) < rq)
|
||||
rq = AGP_MODE_GET_RQ(mstatus);
|
||||
|
||||
/* Set SBA if all three can deal with SBA */
|
||||
sba = (AGP_MODE_GET_SBA(tstatus)
|
||||
& AGP_MODE_GET_SBA(mstatus)
|
||||
& AGP_MODE_GET_SBA(mode));
|
||||
|
||||
/* Similar for FW */
|
||||
fw = (AGP_MODE_GET_FW(tstatus)
|
||||
& AGP_MODE_GET_FW(mstatus)
|
||||
& AGP_MODE_GET_FW(mode));
|
||||
|
||||
/* Figure out the max rate */
|
||||
rate = (AGP_MODE_GET_RATE(tstatus)
|
||||
& AGP_MODE_GET_RATE(mstatus)
|
||||
& AGP_MODE_GET_RATE(mode));
|
||||
if (rate & AGP_MODE_RATE_4x)
|
||||
rate = AGP_MODE_RATE_4x;
|
||||
else if (rate & AGP_MODE_RATE_2x)
|
||||
rate = AGP_MODE_RATE_2x;
|
||||
else
|
||||
rate = AGP_MODE_RATE_1x;
|
||||
|
||||
/* Construct the new mode word and tell the hardware */
|
||||
command = AGP_MODE_SET_RQ(0, rq);
|
||||
command = AGP_MODE_SET_SBA(command, sba);
|
||||
command = AGP_MODE_SET_FW(command, fw);
|
||||
command = AGP_MODE_SET_RATE(command, rate);
|
||||
command = AGP_MODE_SET_AGP(command, 1);
|
||||
pci_write_config(dev, agp_find_caps(dev) + AGP_COMMAND, command, 4);
|
||||
pci_write_config(mdev, agp_find_caps(mdev) + AGP_COMMAND, command, 4);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct agp_memory *
|
||||
agp_generic_alloc_memory(device_t dev, int type, vm_size_t size)
|
||||
{
|
||||
struct agp_softc *sc = device_get_softc(dev);
|
||||
struct agp_memory *mem;
|
||||
|
||||
if ((size & (AGP_PAGE_SIZE - 1)) != 0)
|
||||
return 0;
|
||||
|
||||
if (sc->as_allocated + size > sc->as_maxmem)
|
||||
return 0;
|
||||
|
||||
mem = malloc(sizeof *mem, M_AGP, M_WAITOK);
|
||||
mem->am_id = sc->as_nextid++;
|
||||
mem->am_size = size;
|
||||
mem->am_obj = vm_object_allocate(OBJT_DEFAULT, atop(round_page(size)));
|
||||
mem->am_physical = 0;
|
||||
mem->am_offset = 0;
|
||||
mem->am_is_bound = 0;
|
||||
TAILQ_INSERT_TAIL(&sc->as_memory, mem, am_link);
|
||||
sc->as_allocated += size;
|
||||
|
||||
return mem;
|
||||
}
|
||||
|
||||
int
|
||||
agp_generic_free_memory(device_t dev, struct agp_memory *mem)
|
||||
{
|
||||
struct agp_softc *sc = device_get_softc(dev);
|
||||
|
||||
if (mem->am_is_bound)
|
||||
return EBUSY;
|
||||
|
||||
sc->as_allocated -= mem->am_size;
|
||||
TAILQ_REMOVE(&sc->as_memory, mem, am_link);
|
||||
vm_object_deallocate(mem->am_obj);
|
||||
free(mem, M_AGP);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
agp_generic_bind_memory(device_t dev, struct agp_memory *mem,
|
||||
vm_offset_t offset)
|
||||
{
|
||||
struct agp_softc *sc = device_get_softc(dev);
|
||||
vm_offset_t i, j, k;
|
||||
vm_page_t m;
|
||||
int error;
|
||||
|
||||
lockmgr(&sc->as_lock, LK_EXCLUSIVE, 0, curproc);
|
||||
|
||||
if (mem->am_is_bound) {
|
||||
device_printf(dev, "memory already bound\n");
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
if (offset < 0
|
||||
|| (offset & (AGP_PAGE_SIZE - 1)) != 0
|
||||
|| offset + mem->am_size > AGP_GET_APERTURE(dev)) {
|
||||
device_printf(dev, "binding memory at bad offset %#x\n",
|
||||
(int) offset);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Bind the individual pages and flush the chipset's
|
||||
* TLB.
|
||||
*
|
||||
* XXX Presumably, this needs to be the pci address on alpha
|
||||
* (i.e. use alpha_XXX_dmamap()). I don't have access to any
|
||||
* alpha AGP hardware to check.
|
||||
*/
|
||||
for (i = 0; i < mem->am_size; i += PAGE_SIZE) {
|
||||
/*
|
||||
* Find a page from the object and wire it
|
||||
* down. This page will be mapped using one or more
|
||||
* entries in the GATT (assuming that PAGE_SIZE >=
|
||||
* AGP_PAGE_SIZE. If this is the first call to bind,
|
||||
* the pages will be allocated and zeroed.
|
||||
*/
|
||||
m = vm_page_grab(mem->am_obj, OFF_TO_IDX(i),
|
||||
VM_ALLOC_ZERO | VM_ALLOC_RETRY);
|
||||
AGP_DPF("found page pa=%#x\n", VM_PAGE_TO_PHYS(m));
|
||||
vm_page_wire(m);
|
||||
|
||||
/*
|
||||
* Install entries in the GATT, making sure that if
|
||||
* AGP_PAGE_SIZE < PAGE_SIZE and mem->am_size is not
|
||||
* aligned to PAGE_SIZE, we don't modify too many GATT
|
||||
* entries.
|
||||
*/
|
||||
for (j = 0; j < PAGE_SIZE && i + j < mem->am_size;
|
||||
j += AGP_PAGE_SIZE) {
|
||||
vm_offset_t pa = VM_PAGE_TO_PHYS(m) + j;
|
||||
AGP_DPF("binding offset %#x to pa %#x\n",
|
||||
offset + i + j, pa);
|
||||
error = AGP_BIND_PAGE(dev, offset + i + j, pa);
|
||||
if (error) {
|
||||
/*
|
||||
* Bail out. Reverse all the mappings
|
||||
* and unwire the pages.
|
||||
*/
|
||||
vm_page_wakeup(m);
|
||||
for (k = 0; k < i + j; k += AGP_PAGE_SIZE)
|
||||
AGP_UNBIND_PAGE(dev, offset + k);
|
||||
for (k = 0; k <= i; k += PAGE_SIZE) {
|
||||
m = vm_page_lookup(mem->am_obj,
|
||||
OFF_TO_IDX(k));
|
||||
vm_page_unwire(m, 0);
|
||||
}
|
||||
lockmgr(&sc->as_lock, LK_RELEASE, 0, curproc);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
vm_page_wakeup(m);
|
||||
}
|
||||
|
||||
/*
|
||||
* Flush the cpu cache since we are providing a new mapping
|
||||
* for these pages.
|
||||
*/
|
||||
agp_flush_cache();
|
||||
|
||||
/*
|
||||
* Make sure the chipset gets the new mappings.
|
||||
*/
|
||||
AGP_FLUSH_TLB(dev);
|
||||
|
||||
mem->am_offset = offset;
|
||||
mem->am_is_bound = 1;
|
||||
|
||||
lockmgr(&sc->as_lock, LK_RELEASE, 0, curproc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
agp_generic_unbind_memory(device_t dev, struct agp_memory *mem)
|
||||
{
|
||||
struct agp_softc *sc = device_get_softc(dev);
|
||||
vm_page_t m;
|
||||
int i;
|
||||
|
||||
lockmgr(&sc->as_lock, LK_EXCLUSIVE, 0, curproc);
|
||||
|
||||
if (!mem->am_is_bound) {
|
||||
device_printf(dev, "memory is not bound\n");
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Unbind the individual pages and flush the chipset's
|
||||
* TLB. Unwire the pages so they can be swapped.
|
||||
*/
|
||||
for (i = 0; i < mem->am_size; i += AGP_PAGE_SIZE)
|
||||
AGP_UNBIND_PAGE(dev, mem->am_offset + i);
|
||||
for (i = 0; i < mem->am_size; i += PAGE_SIZE) {
|
||||
m = vm_page_lookup(mem->am_obj, atop(i));
|
||||
vm_page_unwire(m, 0);
|
||||
}
|
||||
|
||||
agp_flush_cache();
|
||||
AGP_FLUSH_TLB(dev);
|
||||
|
||||
mem->am_offset = 0;
|
||||
mem->am_is_bound = 0;
|
||||
|
||||
lockmgr(&sc->as_lock, LK_RELEASE, 0, curproc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Helper functions for implementing user/kernel api */
|
||||
|
||||
static int
|
||||
agp_acquire_helper(device_t dev, enum agp_acquire_state state)
|
||||
{
|
||||
struct agp_softc *sc = device_get_softc(dev);
|
||||
|
||||
if (sc->as_state != AGP_ACQUIRE_FREE)
|
||||
return EBUSY;
|
||||
sc->as_state = state;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
agp_release_helper(device_t dev, enum agp_acquire_state state)
|
||||
{
|
||||
struct agp_softc *sc = device_get_softc(dev);
|
||||
struct agp_memory *mem;
|
||||
|
||||
if (sc->as_state == AGP_ACQUIRE_FREE)
|
||||
return 0;
|
||||
|
||||
if (sc->as_state != state)
|
||||
return EBUSY;
|
||||
|
||||
/*
|
||||
* Clear out the aperture and free any outstanding memory blocks.
|
||||
*/
|
||||
while ((mem = TAILQ_FIRST(&sc->as_memory)) != 0) {
|
||||
if (mem->am_is_bound)
|
||||
AGP_UNBIND_MEMORY(dev, mem);
|
||||
AGP_FREE_MEMORY(dev, mem);
|
||||
}
|
||||
|
||||
sc->as_state = AGP_ACQUIRE_FREE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct agp_memory *
|
||||
agp_find_memory(device_t dev, int id)
|
||||
{
|
||||
struct agp_softc *sc = device_get_softc(dev);
|
||||
struct agp_memory *mem;
|
||||
|
||||
AGP_DPF("searching for memory block %d\n", id);
|
||||
TAILQ_FOREACH(mem, &sc->as_memory, am_link) {
|
||||
AGP_DPF("considering memory block %d\n", mem->am_id);
|
||||
if (mem->am_id == id)
|
||||
return mem;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Implementation of the userland ioctl api */
|
||||
|
||||
static int
|
||||
agp_info_user(device_t dev, agp_info *info)
|
||||
{
|
||||
struct agp_softc *sc = device_get_softc(dev);
|
||||
|
||||
bzero(info, sizeof *info);
|
||||
info->bridge_id = pci_get_devid(dev);
|
||||
info->agp_mode =
|
||||
pci_read_config(dev, agp_find_caps(dev) + AGP_STATUS, 4);
|
||||
info->aper_base = rman_get_start(sc->as_aperture);
|
||||
info->aper_size = AGP_GET_APERTURE(dev) >> 20;
|
||||
info->pg_total = info->pg_system = sc->as_maxmem >> AGP_PAGE_SHIFT;
|
||||
info->pg_used = sc->as_allocated >> AGP_PAGE_SHIFT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
agp_setup_user(device_t dev, agp_setup *setup)
|
||||
{
|
||||
return AGP_ENABLE(dev, setup->agp_mode);
|
||||
}
|
||||
|
||||
static int
|
||||
agp_allocate_user(device_t dev, agp_allocate *alloc)
|
||||
{
|
||||
struct agp_memory *mem;
|
||||
|
||||
mem = AGP_ALLOC_MEMORY(dev,
|
||||
alloc->type,
|
||||
alloc->pg_count << AGP_PAGE_SHIFT);
|
||||
alloc->key = mem->am_id;
|
||||
alloc->physical = mem->am_physical;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
agp_deallocate_user(device_t dev, int id)
|
||||
{
|
||||
struct agp_memory *mem = agp_find_memory(dev, id);;
|
||||
|
||||
if (mem) {
|
||||
AGP_FREE_MEMORY(dev, mem);
|
||||
return 0;
|
||||
} else {
|
||||
return ENOENT;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
agp_bind_user(device_t dev, agp_bind *bind)
|
||||
{
|
||||
struct agp_memory *mem = agp_find_memory(dev, bind->key);
|
||||
|
||||
if (!mem)
|
||||
return ENOENT;
|
||||
|
||||
return AGP_BIND_MEMORY(dev, mem, bind->pg_start << AGP_PAGE_SHIFT);
|
||||
}
|
||||
|
||||
static int
|
||||
agp_unbind_user(device_t dev, agp_unbind *unbind)
|
||||
{
|
||||
struct agp_memory *mem = agp_find_memory(dev, unbind->key);
|
||||
|
||||
if (!mem)
|
||||
return ENOENT;
|
||||
|
||||
return AGP_UNBIND_MEMORY(dev, mem);
|
||||
}
|
||||
|
||||
static int
|
||||
agp_open(dev_t kdev, int oflags, int devtype, struct proc *p)
|
||||
{
|
||||
device_t dev = KDEV2DEV(kdev);
|
||||
struct agp_softc *sc = device_get_softc(dev);
|
||||
|
||||
if (!sc->as_isopen) {
|
||||
sc->as_isopen = 1;
|
||||
device_busy(dev);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
agp_close(dev_t kdev, int fflag, int devtype, struct proc *p)
|
||||
{
|
||||
device_t dev = KDEV2DEV(kdev);
|
||||
struct agp_softc *sc = device_get_softc(dev);
|
||||
|
||||
/*
|
||||
* Clear the GATT and force release on last close
|
||||
*/
|
||||
if (sc->as_state == AGP_ACQUIRE_USER)
|
||||
agp_release_helper(dev, AGP_ACQUIRE_USER);
|
||||
sc->as_isopen = 0;
|
||||
device_unbusy(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
agp_ioctl(dev_t kdev, u_long cmd, caddr_t data, int fflag, struct proc *p)
|
||||
{
|
||||
device_t dev = KDEV2DEV(kdev);
|
||||
|
||||
switch (cmd) {
|
||||
case AGPIOC_INFO:
|
||||
return agp_info_user(dev, (agp_info *) data);
|
||||
|
||||
case AGPIOC_ACQUIRE:
|
||||
return agp_acquire_helper(dev, AGP_ACQUIRE_USER);
|
||||
|
||||
case AGPIOC_RELEASE:
|
||||
return agp_release_helper(dev, AGP_ACQUIRE_USER);
|
||||
|
||||
case AGPIOC_SETUP:
|
||||
return agp_setup_user(dev, (agp_setup *)data);
|
||||
|
||||
case AGPIOC_ALLOCATE:
|
||||
return agp_allocate_user(dev, (agp_allocate *)data);
|
||||
|
||||
case AGPIOC_DEALLOCATE:
|
||||
return agp_deallocate_user(dev, *(int *) data);
|
||||
|
||||
case AGPIOC_BIND:
|
||||
return agp_bind_user(dev, (agp_bind *)data);
|
||||
|
||||
case AGPIOC_UNBIND:
|
||||
return agp_unbind_user(dev, (agp_unbind *)data);
|
||||
|
||||
}
|
||||
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
static int
|
||||
agp_mmap(dev_t kdev, vm_offset_t offset, int prot)
|
||||
{
|
||||
device_t dev = KDEV2DEV(kdev);
|
||||
struct agp_softc *sc = device_get_softc(dev);
|
||||
|
||||
if (offset > AGP_GET_APERTURE(dev))
|
||||
return -1;
|
||||
return atop(rman_get_start(sc->as_aperture) + offset);
|
||||
}
|
||||
|
||||
/* Implementation of the kernel api */
|
||||
|
||||
device_t
|
||||
agp_find_device()
|
||||
{
|
||||
if (!agp_devclass)
|
||||
return 0;
|
||||
return devclass_get_device(agp_devclass, 0);
|
||||
}
|
||||
|
||||
enum agp_acquire_state
|
||||
agp_state(device_t dev)
|
||||
{
|
||||
struct agp_softc *sc = device_get_softc(dev);
|
||||
return sc->as_state;
|
||||
}
|
||||
|
||||
void
|
||||
agp_get_info(device_t dev, struct agp_info *info)
|
||||
{
|
||||
struct agp_softc *sc = device_get_softc(dev);
|
||||
|
||||
info->ai_mode =
|
||||
pci_read_config(dev, agp_find_caps(dev) + AGP_STATUS, 4);
|
||||
info->ai_aperture_base = rman_get_start(sc->as_aperture);
|
||||
info->ai_aperture_size = (rman_get_end(sc->as_aperture)
|
||||
- rman_get_start(sc->as_aperture)) + 1;
|
||||
info->ai_memory_allowed = sc->as_maxmem;
|
||||
info->ai_memory_used = sc->as_allocated;
|
||||
}
|
||||
|
||||
int
|
||||
agp_acquire(device_t dev)
|
||||
{
|
||||
return agp_acquire_helper(dev, AGP_ACQUIRE_KERNEL);
|
||||
}
|
||||
|
||||
int
|
||||
agp_release(device_t dev)
|
||||
{
|
||||
return agp_release_helper(dev, AGP_ACQUIRE_KERNEL);
|
||||
}
|
||||
|
||||
int
|
||||
agp_enable(device_t dev, u_int32_t mode)
|
||||
{
|
||||
return AGP_ENABLE(dev, mode);
|
||||
}
|
||||
|
||||
void *agp_alloc_memory(device_t dev, int type, vm_size_t bytes)
|
||||
{
|
||||
return (void *) AGP_ALLOC_MEMORY(dev, type, bytes);
|
||||
}
|
||||
|
||||
void agp_free_memory(device_t dev, void *handle)
|
||||
{
|
||||
struct agp_memory *mem = (struct agp_memory *) handle;
|
||||
AGP_FREE_MEMORY(dev, mem);
|
||||
}
|
||||
|
||||
int agp_bind_memory(device_t dev, void *handle, vm_offset_t offset)
|
||||
{
|
||||
struct agp_memory *mem = (struct agp_memory *) handle;
|
||||
return AGP_BIND_MEMORY(dev, mem, offset);
|
||||
}
|
||||
|
||||
int agp_unbind_memory(device_t dev, void *handle)
|
||||
{
|
||||
struct agp_memory *mem = (struct agp_memory *) handle;
|
||||
return AGP_UNBIND_MEMORY(dev, mem);
|
||||
}
|
||||
|
||||
void agp_memory_info(device_t dev, void *handle, struct
|
||||
agp_memory_info *mi)
|
||||
{
|
||||
struct agp_memory *mem = (struct agp_memory *) handle;
|
||||
|
||||
mi->ami_size = mem->am_size;
|
||||
mi->ami_physical = mem->am_physical;
|
||||
mi->ami_offset = mem->am_offset;
|
||||
mi->ami_is_bound = mem->am_is_bound;
|
||||
}
|
264
sys/pci/agp_ali.c
Normal file
264
sys/pci/agp_ali.c
Normal file
@ -0,0 +1,264 @@
|
||||
/*-
|
||||
* Copyright (c) 2000 Doug Rabson
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#include "opt_bus.h"
|
||||
#include "opt_pci.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/lock.h>
|
||||
|
||||
#include <pci/pcivar.h>
|
||||
#include <pci/pcireg.h>
|
||||
#include <pci/agppriv.h>
|
||||
#include <pci/agpreg.h>
|
||||
|
||||
#include <vm/vm.h>
|
||||
#include <vm/vm_object.h>
|
||||
#include <vm/pmap.h>
|
||||
|
||||
struct agp_ali_softc {
|
||||
struct agp_softc agp;
|
||||
u_int32_t initial_aperture; /* aperture size at startup */
|
||||
struct agp_gatt *gatt;
|
||||
};
|
||||
|
||||
static const char*
|
||||
agp_ali_match(device_t dev)
|
||||
{
|
||||
if (pci_get_class(dev) != PCIC_BRIDGE
|
||||
|| pci_get_subclass(dev) != PCIS_BRIDGE_HOST)
|
||||
return NULL;
|
||||
|
||||
if (agp_find_caps(dev) == 0)
|
||||
return NULL;
|
||||
|
||||
switch (pci_get_devid(dev)) {
|
||||
case 0x154110b9:
|
||||
return ("Ali M1541 host to AGP bridge");
|
||||
};
|
||||
|
||||
if (pci_get_vendor(dev) == 0x10b9)
|
||||
return ("Ali Generic host to PCI bridge");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
agp_ali_probe(device_t dev)
|
||||
{
|
||||
const char *desc;
|
||||
|
||||
desc = agp_ali_match(dev);
|
||||
if (desc) {
|
||||
device_verbose(dev);
|
||||
device_set_desc(dev, desc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ENXIO;
|
||||
}
|
||||
|
||||
static int
|
||||
agp_ali_attach(device_t dev)
|
||||
{
|
||||
struct agp_ali_softc *sc = device_get_softc(dev);
|
||||
struct agp_gatt *gatt;
|
||||
int error;
|
||||
|
||||
error = agp_generic_attach(dev);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
sc->initial_aperture = AGP_GET_APERTURE(dev);
|
||||
|
||||
for (;;) {
|
||||
gatt = agp_alloc_gatt(dev);
|
||||
if (gatt)
|
||||
break;
|
||||
|
||||
/*
|
||||
* Probably contigmalloc failure. Try reducing the
|
||||
* aperture so that the gatt size reduces.
|
||||
*/
|
||||
if (AGP_SET_APERTURE(dev, AGP_GET_APERTURE(dev) / 2)) {
|
||||
agp_generic_detach(dev);
|
||||
return ENOMEM;
|
||||
}
|
||||
}
|
||||
sc->gatt = gatt;
|
||||
|
||||
/* Install the gatt. */
|
||||
pci_write_config(dev, AGP_ALI_ATTBASE,
|
||||
(gatt->ag_physical
|
||||
| (pci_read_config(dev, AGP_ALI_ATTBASE, 4) & 0xff)),
|
||||
4);
|
||||
|
||||
/* Enable the TLB. */
|
||||
pci_write_config(dev, AGP_ALI_TLBCTRL, 0x10, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
agp_ali_detach(device_t dev)
|
||||
{
|
||||
struct agp_ali_softc *sc = device_get_softc(dev);
|
||||
int error;
|
||||
|
||||
error = agp_generic_detach(dev);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
/* Disable the TLB.. */
|
||||
pci_write_config(dev, AGP_ALI_TLBCTRL, 0x90, 1);
|
||||
|
||||
/* Put the aperture back the way it started. */
|
||||
AGP_SET_APERTURE(dev, sc->initial_aperture);
|
||||
pci_write_config(dev, AGP_ALI_ATTBASE,
|
||||
pci_read_config(dev, AGP_ALI_ATTBASE, 4) & 0xff,
|
||||
4);
|
||||
|
||||
agp_free_gatt(sc->gatt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define M 1024*1024
|
||||
|
||||
static u_int32_t agp_ali_table[] = {
|
||||
0, /* 0 - invalid */
|
||||
1, /* 1 - invalid */
|
||||
2, /* 2 - invalid */
|
||||
4*M, /* 3 - invalid */
|
||||
8*M, /* 4 - invalid */
|
||||
0, /* 5 - invalid */
|
||||
16*M, /* 6 - invalid */
|
||||
32*M, /* 7 - invalid */
|
||||
64*M, /* 8 - invalid */
|
||||
128*M, /* 9 - invalid */
|
||||
256*M, /* 10 - invalid */
|
||||
};
|
||||
#define agp_ali_table_size (sizeof(agp_ali_table) / sizeof(agp_ali_table[0]))
|
||||
|
||||
static u_int32_t
|
||||
agp_ali_get_aperture(device_t dev)
|
||||
{
|
||||
/*
|
||||
* The aperture size is derived from the low bits of attbase.
|
||||
* I'm not sure this is correct..
|
||||
*/
|
||||
int i = pci_read_config(dev, AGP_ALI_ATTBASE, 4) & 0xff;
|
||||
if (i >= agp_ali_table_size)
|
||||
return 0;
|
||||
return agp_ali_table[i];
|
||||
}
|
||||
|
||||
static int
|
||||
agp_ali_set_aperture(device_t dev, u_int32_t aperture)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < agp_ali_table_size; i++)
|
||||
if (agp_ali_table[i] == aperture)
|
||||
break;
|
||||
if (i == agp_ali_table_size)
|
||||
return EINVAL;
|
||||
|
||||
pci_write_config(dev, AGP_ALI_ATTBASE,
|
||||
((pci_read_config(dev, AGP_ALI_ATTBASE, 4) & ~0xff)
|
||||
| i), 4);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
agp_ali_bind_page(device_t dev, int offset, vm_offset_t physical)
|
||||
{
|
||||
struct agp_ali_softc *sc = device_get_softc(dev);
|
||||
|
||||
if (offset < 0 || offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT))
|
||||
return EINVAL;
|
||||
|
||||
sc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = physical;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
agp_ali_unbind_page(device_t dev, int offset)
|
||||
{
|
||||
struct agp_ali_softc *sc = device_get_softc(dev);
|
||||
|
||||
if (offset < 0 || offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT))
|
||||
return EINVAL;
|
||||
|
||||
sc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
agp_ali_flush_tlb(device_t dev)
|
||||
{
|
||||
pci_write_config(dev, AGP_ALI_TLBCTRL, 0x90, 1);
|
||||
pci_write_config(dev, AGP_ALI_TLBCTRL, 0x10, 1);
|
||||
}
|
||||
|
||||
static device_method_t agp_ali_methods[] = {
|
||||
/* Device interface */
|
||||
DEVMETHOD(device_probe, agp_ali_probe),
|
||||
DEVMETHOD(device_attach, agp_ali_attach),
|
||||
DEVMETHOD(device_detach, agp_ali_detach),
|
||||
DEVMETHOD(device_shutdown, bus_generic_shutdown),
|
||||
DEVMETHOD(device_suspend, bus_generic_suspend),
|
||||
DEVMETHOD(device_resume, bus_generic_resume),
|
||||
|
||||
/* AGP interface */
|
||||
DEVMETHOD(agp_get_aperture, agp_ali_get_aperture),
|
||||
DEVMETHOD(agp_set_aperture, agp_ali_set_aperture),
|
||||
DEVMETHOD(agp_bind_page, agp_ali_bind_page),
|
||||
DEVMETHOD(agp_unbind_page, agp_ali_unbind_page),
|
||||
DEVMETHOD(agp_flush_tlb, agp_ali_flush_tlb),
|
||||
DEVMETHOD(agp_enable, agp_generic_enable),
|
||||
DEVMETHOD(agp_alloc_memory, agp_generic_alloc_memory),
|
||||
DEVMETHOD(agp_free_memory, agp_generic_free_memory),
|
||||
DEVMETHOD(agp_bind_memory, agp_generic_bind_memory),
|
||||
DEVMETHOD(agp_unbind_memory, agp_generic_unbind_memory),
|
||||
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
static driver_t agp_ali_driver = {
|
||||
"agp",
|
||||
agp_ali_methods,
|
||||
sizeof(struct agp_ali_softc),
|
||||
};
|
||||
|
||||
static devclass_t agp_devclass;
|
||||
|
||||
DRIVER_MODULE(agp_ali, pci, agp_ali_driver, agp_devclass, 0, 0);
|
276
sys/pci/agp_amd.c
Normal file
276
sys/pci/agp_amd.c
Normal file
@ -0,0 +1,276 @@
|
||||
/*-
|
||||
* Copyright (c) 2000 Doug Rabson
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#include "opt_bus.h"
|
||||
#include "opt_pci.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/lock.h>
|
||||
|
||||
#include <pci/pcivar.h>
|
||||
#include <pci/pcireg.h>
|
||||
#include <pci/agppriv.h>
|
||||
#include <pci/agpreg.h>
|
||||
|
||||
#include <vm/vm.h>
|
||||
#include <vm/vm_object.h>
|
||||
#include <vm/pmap.h>
|
||||
#include <machine/clock.h>
|
||||
#include <machine/bus.h>
|
||||
#include <machine/resource.h>
|
||||
#include <sys/rman.h>
|
||||
|
||||
#define READ2(off) bus_space_read_2(sc->bst, sc->bsh, off)
|
||||
#define READ4(off) bus_space_read_4(sc->bst, sc->bsh, off)
|
||||
#define WRITE2(off,v) bus_space_write_2(sc->bst, sc->bsh, off, v)
|
||||
#define WRITE4(off,v) bus_space_write_4(sc->bst, sc->bsh, off, v)
|
||||
|
||||
struct agp_amd_softc {
|
||||
struct agp_softc agp;
|
||||
struct resource *regs; /* memory mapped control registers */
|
||||
bus_space_tag_t bst; /* bus_space tag */
|
||||
bus_space_handle_t bsh; /* bus_space handle */
|
||||
u_int32_t initial_aperture; /* aperture size at startup */
|
||||
struct agp_gatt *gatt;
|
||||
};
|
||||
|
||||
static const char*
|
||||
agp_amd_match(device_t dev)
|
||||
{
|
||||
if (pci_get_class(dev) != PCIC_BRIDGE
|
||||
|| pci_get_subclass(dev) != PCIS_BRIDGE_HOST)
|
||||
return NULL;
|
||||
|
||||
if (agp_find_caps(dev) == 0)
|
||||
return NULL;
|
||||
|
||||
switch (pci_get_devid(dev)) {
|
||||
case 0x70061022:
|
||||
return ("AMD 751 host to AGP bridge");
|
||||
};
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
agp_amd_probe(device_t dev)
|
||||
{
|
||||
const char *desc;
|
||||
|
||||
desc = agp_amd_match(dev);
|
||||
if (desc) {
|
||||
device_verbose(dev);
|
||||
device_set_desc(dev, desc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ENXIO;
|
||||
}
|
||||
|
||||
static int
|
||||
agp_amd_attach(device_t dev)
|
||||
{
|
||||
struct agp_amd_softc *sc = device_get_softc(dev);
|
||||
struct agp_gatt *gatt;
|
||||
int error, rid;
|
||||
|
||||
error = agp_generic_attach(dev);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
rid = AGP_AMD751_REGISTERS;
|
||||
sc->regs = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid,
|
||||
0, ~0, 1, RF_ACTIVE);
|
||||
if (!sc->regs) {
|
||||
agp_generic_detach(dev);
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
sc->bst = rman_get_bustag(sc->regs);
|
||||
sc->bsh = rman_get_bushandle(sc->regs);
|
||||
|
||||
sc->initial_aperture = AGP_GET_APERTURE(dev);
|
||||
|
||||
for (;;) {
|
||||
gatt = agp_alloc_gatt(dev);
|
||||
if (gatt)
|
||||
break;
|
||||
|
||||
/*
|
||||
* Probably contigmalloc failure. Try reducing the
|
||||
* aperture so that the gatt size reduces.
|
||||
*/
|
||||
if (AGP_SET_APERTURE(dev, AGP_GET_APERTURE(dev) / 2))
|
||||
return ENOMEM;
|
||||
}
|
||||
sc->gatt = gatt;
|
||||
|
||||
/* Install the gatt. */
|
||||
WRITE4(AGP_AMD751_ATTBASE, gatt->ag_physical);
|
||||
|
||||
/* Enable synchronisation between host and agp. */
|
||||
pci_write_config(dev, AGP_AMD751_MODECTRL, 0x80, 1);
|
||||
|
||||
/* Enable the TLB and flush */
|
||||
WRITE2(AGP_AMD751_STATUS,
|
||||
READ2(AGP_AMD751_STATUS) | AGP_AMD751_STATUS_GCE);
|
||||
AGP_FLUSH_TLB(dev);
|
||||
|
||||
return agp_generic_attach(dev);
|
||||
}
|
||||
|
||||
static int
|
||||
agp_amd_detach(device_t dev)
|
||||
{
|
||||
struct agp_amd_softc *sc = device_get_softc(dev);
|
||||
|
||||
/* Disable the TLB.. */
|
||||
WRITE2(AGP_AMD751_STATUS,
|
||||
READ2(AGP_AMD751_STATUS) & ~AGP_AMD751_STATUS_GCE);
|
||||
|
||||
/* Disable host-agp sync */
|
||||
pci_write_config(dev, AGP_AMD751_MODECTRL, 0x00, 1);
|
||||
|
||||
/* Clear the GATT base */
|
||||
WRITE4(AGP_AMD751_ATTBASE, 0);
|
||||
|
||||
/* Put the aperture back the way it started. */
|
||||
AGP_SET_APERTURE(dev, sc->initial_aperture);
|
||||
|
||||
agp_free_gatt(sc->gatt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u_int32_t
|
||||
agp_amd_get_aperture(device_t dev)
|
||||
{
|
||||
int vas;
|
||||
|
||||
/*
|
||||
* The aperture size is equal to 32M<<vas.
|
||||
*/
|
||||
vas = (pci_read_config(dev, AGP_AMD751_APCTRL, 1) & 0x06) >> 1;
|
||||
return (32*1024*1024) << vas;
|
||||
}
|
||||
|
||||
static int
|
||||
agp_amd_set_aperture(device_t dev, u_int32_t aperture)
|
||||
{
|
||||
int vas;
|
||||
|
||||
/*
|
||||
* Check for a power of two and make sure its within the
|
||||
* programmable range.
|
||||
*/
|
||||
if (aperture & (aperture - 1)
|
||||
|| aperture < 32*1024*1024
|
||||
|| aperture > 2U*1024*1024*1024)
|
||||
return EINVAL;
|
||||
|
||||
vas = ffs(aperture / 32*1024*1024) - 1;
|
||||
|
||||
pci_write_config(dev, AGP_AMD751_APCTRL,
|
||||
((pci_read_config(dev, AGP_AMD751_APCTRL, 1) & ~0x06)
|
||||
| vas << 1), 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
agp_amd_bind_page(device_t dev, int offset, vm_offset_t physical)
|
||||
{
|
||||
struct agp_amd_softc *sc = device_get_softc(dev);
|
||||
|
||||
if (offset < 0 || offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT))
|
||||
return EINVAL;
|
||||
|
||||
sc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = physical | 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
agp_amd_unbind_page(device_t dev, int offset)
|
||||
{
|
||||
struct agp_amd_softc *sc = device_get_softc(dev);
|
||||
|
||||
if (offset < 0 || offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT))
|
||||
return EINVAL;
|
||||
|
||||
sc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
agp_amd_flush_tlb(device_t dev)
|
||||
{
|
||||
struct agp_amd_softc *sc = device_get_softc(dev);
|
||||
|
||||
/* Set the cache invalidate bit and wait for the chipset to clear */
|
||||
WRITE4(AGP_AMD751_TLBCTRL, 1);
|
||||
do {
|
||||
DELAY(1);
|
||||
} while (READ4(AGP_AMD751_TLBCTRL));
|
||||
}
|
||||
|
||||
static device_method_t agp_amd_methods[] = {
|
||||
/* Device interface */
|
||||
DEVMETHOD(device_probe, agp_amd_probe),
|
||||
DEVMETHOD(device_attach, agp_amd_attach),
|
||||
DEVMETHOD(device_detach, agp_amd_detach),
|
||||
DEVMETHOD(device_shutdown, bus_generic_shutdown),
|
||||
DEVMETHOD(device_suspend, bus_generic_suspend),
|
||||
DEVMETHOD(device_resume, bus_generic_resume),
|
||||
|
||||
/* AGP interface */
|
||||
DEVMETHOD(agp_get_aperture, agp_amd_get_aperture),
|
||||
DEVMETHOD(agp_set_aperture, agp_amd_set_aperture),
|
||||
DEVMETHOD(agp_bind_page, agp_amd_bind_page),
|
||||
DEVMETHOD(agp_unbind_page, agp_amd_unbind_page),
|
||||
DEVMETHOD(agp_flush_tlb, agp_amd_flush_tlb),
|
||||
DEVMETHOD(agp_enable, agp_generic_enable),
|
||||
DEVMETHOD(agp_alloc_memory, agp_generic_alloc_memory),
|
||||
DEVMETHOD(agp_free_memory, agp_generic_free_memory),
|
||||
DEVMETHOD(agp_bind_memory, agp_generic_bind_memory),
|
||||
DEVMETHOD(agp_unbind_memory, agp_generic_unbind_memory),
|
||||
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
static driver_t agp_amd_driver = {
|
||||
"agp",
|
||||
agp_amd_methods,
|
||||
sizeof(struct agp_amd_softc),
|
||||
};
|
||||
|
||||
static devclass_t agp_devclass;
|
||||
|
||||
DRIVER_MODULE(agp_amd, pci, agp_amd_driver, agp_devclass, 0, 0);
|
134
sys/pci/agp_if.m
Normal file
134
sys/pci/agp_if.m
Normal file
@ -0,0 +1,134 @@
|
||||
#
|
||||
# Copyright (c) 2000 Doug Rabson
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
# SUCH DAMAGE.
|
||||
#
|
||||
# $FreeBSD$
|
||||
#
|
||||
|
||||
#include <sys/bus.h>
|
||||
|
||||
#
|
||||
# The AGP interface is used internally to the agp driver to isolate the
|
||||
# differences between various AGP chipsets into chipset mini drivers. It
|
||||
# should not be used outside the AGP driver. The kernel api for accessing
|
||||
# AGP functionality is described in <pci/agpvar,h>
|
||||
#
|
||||
INTERFACE agp;
|
||||
|
||||
#
|
||||
# Return the current aperture size.
|
||||
#
|
||||
METHOD u_int32_t get_aperture {
|
||||
device_t dev;
|
||||
};
|
||||
|
||||
#
|
||||
# Set the size of the aperture. Return EINVAL on error or 0 on success.
|
||||
#
|
||||
METHOD int set_aperture {
|
||||
device_t dev;
|
||||
u_int32_t aperture;
|
||||
};
|
||||
|
||||
#
|
||||
# Bind a single page in the AGP aperture to a given physical address.
|
||||
# The offset is a byte offset within the aperture which must be
|
||||
# aligned to an AGP page boundary.
|
||||
#
|
||||
METHOD int bind_page {
|
||||
device_t dev;
|
||||
vm_offset_t offset;
|
||||
vm_offset_t physical;
|
||||
};
|
||||
|
||||
#
|
||||
# Unbind a single page in the AGP aperture.
|
||||
#
|
||||
METHOD int unbind_page {
|
||||
device_t dev;
|
||||
vm_offset_t offset;
|
||||
};
|
||||
|
||||
#
|
||||
# Flush the GATT TLB. This is used after a call to bind_page to
|
||||
# ensure that any mappings cached in the chipset are discarded.
|
||||
#
|
||||
METHOD void flush_tlb {
|
||||
device_t dev;
|
||||
};
|
||||
|
||||
#
|
||||
# Enable the agp hardware with the relavent mode. The mode bits are
|
||||
# defined in <pci/agpreg.h>
|
||||
#
|
||||
METHOD int enable {
|
||||
device_t dev;
|
||||
u_int32_t mode;
|
||||
};
|
||||
|
||||
#
|
||||
# Allocate memory of a given type. The type is a chipset-specific
|
||||
# code which is used by certain integrated agp graphics chips
|
||||
# (basically just the i810 for now) to access special features of
|
||||
# the chipset. An opaque handle representing the memory region is
|
||||
# returned and can be used as an argument to free_memory, bind_memory
|
||||
# and unbind_memory.
|
||||
#
|
||||
# The size is specified in bytes but must be a multiple of the AGP
|
||||
# page size.
|
||||
#
|
||||
METHOD struct agp_memory * alloc_memory {
|
||||
device_t dev;
|
||||
int type;
|
||||
vm_size_t size;
|
||||
};
|
||||
|
||||
#
|
||||
# Free a memory region previously allocated with alloc_memory. Return
|
||||
# EBUSY if the memory is bound.
|
||||
#
|
||||
METHOD int free_memory {
|
||||
device_t dev;
|
||||
struct agp_memory *mem;
|
||||
};
|
||||
|
||||
#
|
||||
# Bind a memory region to a specific byte offset within the chipset's
|
||||
# AGP aperture. This effectively defines a range of contiguous
|
||||
# physical address which alias the (possibly uncontiguous) pages in
|
||||
# the memory region.
|
||||
#
|
||||
METHOD int bind_memory {
|
||||
device_t dev;
|
||||
struct agp_memory *mem;
|
||||
vm_offset_t offset;
|
||||
};
|
||||
|
||||
#
|
||||
# Unbind a memory region bound with bind_memory.
|
||||
#
|
||||
METHOD int unbind_memory {
|
||||
device_t dev;
|
||||
struct agp_memory *handle;
|
||||
};
|
266
sys/pci/agp_intel.c
Normal file
266
sys/pci/agp_intel.c
Normal file
@ -0,0 +1,266 @@
|
||||
/*-
|
||||
* Copyright (c) 2000 Doug Rabson
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#include "opt_bus.h"
|
||||
#include "opt_pci.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/lock.h>
|
||||
|
||||
#include <pci/pcivar.h>
|
||||
#include <pci/pcireg.h>
|
||||
#include <pci/agppriv.h>
|
||||
#include <pci/agpreg.h>
|
||||
|
||||
#include <vm/vm.h>
|
||||
#include <vm/vm_object.h>
|
||||
#include <vm/pmap.h>
|
||||
|
||||
struct agp_intel_softc {
|
||||
struct agp_softc agp;
|
||||
u_int32_t initial_aperture; /* aperture size at startup */
|
||||
struct agp_gatt *gatt;
|
||||
};
|
||||
|
||||
static const char*
|
||||
agp_intel_match(device_t dev)
|
||||
{
|
||||
if (pci_get_class(dev) != PCIC_BRIDGE
|
||||
|| pci_get_subclass(dev) != PCIS_BRIDGE_HOST)
|
||||
return NULL;
|
||||
|
||||
if (agp_find_caps(dev) == 0)
|
||||
return NULL;
|
||||
|
||||
switch (pci_get_devid(dev)) {
|
||||
/* Intel -- vendor 0x8086 */
|
||||
case 0x71808086:
|
||||
return ("Intel 82443LX (440 LX) host to PCI bridge");
|
||||
|
||||
case 0x71908086:
|
||||
return ("Intel 82443BX (440 BX) host to PCI bridge");
|
||||
|
||||
case 0x71a08086:
|
||||
return ("Intel 82443GX host to PCI bridge");
|
||||
|
||||
case 0x71a18086:
|
||||
return ("Intel 82443GX host to AGP bridge");
|
||||
};
|
||||
|
||||
if (pci_get_vendor(dev) == 0x8086)
|
||||
return ("Intel Generic host to PCI bridge");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
agp_intel_probe(device_t dev)
|
||||
{
|
||||
const char *desc;
|
||||
|
||||
desc = agp_intel_match(dev);
|
||||
if (desc) {
|
||||
device_verbose(dev);
|
||||
device_set_desc(dev, desc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ENXIO;
|
||||
}
|
||||
|
||||
static int
|
||||
agp_intel_attach(device_t dev)
|
||||
{
|
||||
struct agp_intel_softc *sc = device_get_softc(dev);
|
||||
struct agp_gatt *gatt;
|
||||
int error;
|
||||
|
||||
error = agp_generic_attach(dev);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
sc->initial_aperture = AGP_GET_APERTURE(dev);
|
||||
|
||||
for (;;) {
|
||||
gatt = agp_alloc_gatt(dev);
|
||||
if (gatt)
|
||||
break;
|
||||
|
||||
/*
|
||||
* Probably contigmalloc failure. Try reducing the
|
||||
* aperture so that the gatt size reduces.
|
||||
*/
|
||||
if (AGP_SET_APERTURE(dev, AGP_GET_APERTURE(dev) / 2)) {
|
||||
agp_generic_detach(dev);
|
||||
return ENOMEM;
|
||||
}
|
||||
}
|
||||
sc->gatt = gatt;
|
||||
|
||||
/* Install the gatt. */
|
||||
pci_write_config(dev, AGP_INTEL_ATTBASE, gatt->ag_physical, 4);
|
||||
|
||||
/* Enable things, clear errors etc. */
|
||||
pci_write_config(dev, AGP_INTEL_AGPCTRL, 0x2280, 4);
|
||||
pci_write_config(dev, AGP_INTEL_NBXCFG,
|
||||
(pci_read_config(dev, AGP_INTEL_NBXCFG, 4)
|
||||
& ~(1 << 10)) | (1 << 9), 4);
|
||||
pci_write_config(dev, AGP_INTEL_ERRSTS + 1, 7, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
agp_intel_detach(device_t dev)
|
||||
{
|
||||
struct agp_intel_softc *sc = device_get_softc(dev);
|
||||
int error;
|
||||
|
||||
error = agp_generic_detach(dev);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
printf("%s: set NBXCFG to %x\n", __FUNCTION__,
|
||||
(pci_read_config(dev, AGP_INTEL_NBXCFG, 4)
|
||||
& ~(1 << 9)));
|
||||
pci_write_config(dev, AGP_INTEL_NBXCFG,
|
||||
(pci_read_config(dev, AGP_INTEL_NBXCFG, 4)
|
||||
& ~(1 << 9)), 4);
|
||||
pci_write_config(dev, AGP_INTEL_ATTBASE, 0, 4);
|
||||
AGP_SET_APERTURE(dev, sc->initial_aperture);
|
||||
agp_free_gatt(sc->gatt);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u_int32_t
|
||||
agp_intel_get_aperture(device_t dev)
|
||||
{
|
||||
u_int32_t apsize;
|
||||
|
||||
apsize = pci_read_config(dev, AGP_INTEL_APSIZE, 1) & 0x1f;
|
||||
|
||||
/*
|
||||
* The size is determined by the number of low bits of
|
||||
* register APBASE which are forced to zero. The low 22 bits
|
||||
* are always forced to zero and each zero bit in the apsize
|
||||
* field just read forces the corresponding bit in the 27:22
|
||||
* to be zero. We calculate the aperture size accordingly.
|
||||
*/
|
||||
return (((apsize ^ 0x1f) << 22) | ((1 << 22) - 1)) + 1;
|
||||
}
|
||||
|
||||
static int
|
||||
agp_intel_set_aperture(device_t dev, u_int32_t aperture)
|
||||
{
|
||||
u_int32_t apsize;
|
||||
|
||||
/*
|
||||
* Reverse the magic from get_aperture.
|
||||
*/
|
||||
apsize = ((aperture - 1) >> 22) ^ 0x1f;
|
||||
|
||||
/*
|
||||
* Double check for sanity.
|
||||
*/
|
||||
if ((((apsize ^ 0x1f) << 22) | ((1 << 22) - 1)) + 1 != aperture)
|
||||
return EINVAL;
|
||||
|
||||
pci_write_config(dev, AGP_INTEL_APSIZE, apsize, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
agp_intel_bind_page(device_t dev, int offset, vm_offset_t physical)
|
||||
{
|
||||
struct agp_intel_softc *sc = device_get_softc(dev);
|
||||
|
||||
if (offset < 0 || offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT))
|
||||
return EINVAL;
|
||||
|
||||
sc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = physical | 0x17;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
agp_intel_unbind_page(device_t dev, int offset)
|
||||
{
|
||||
struct agp_intel_softc *sc = device_get_softc(dev);
|
||||
|
||||
if (offset < 0 || offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT))
|
||||
return EINVAL;
|
||||
|
||||
sc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
agp_intel_flush_tlb(device_t dev)
|
||||
{
|
||||
pci_write_config(dev, AGP_INTEL_AGPCTRL, 0x2200, 4);
|
||||
pci_write_config(dev, AGP_INTEL_AGPCTRL, 0x2280, 4);
|
||||
}
|
||||
|
||||
static device_method_t agp_intel_methods[] = {
|
||||
/* Device interface */
|
||||
DEVMETHOD(device_probe, agp_intel_probe),
|
||||
DEVMETHOD(device_attach, agp_intel_attach),
|
||||
DEVMETHOD(device_detach, agp_intel_detach),
|
||||
DEVMETHOD(device_shutdown, bus_generic_shutdown),
|
||||
DEVMETHOD(device_suspend, bus_generic_suspend),
|
||||
DEVMETHOD(device_resume, bus_generic_resume),
|
||||
|
||||
/* AGP interface */
|
||||
DEVMETHOD(agp_get_aperture, agp_intel_get_aperture),
|
||||
DEVMETHOD(agp_set_aperture, agp_intel_set_aperture),
|
||||
DEVMETHOD(agp_bind_page, agp_intel_bind_page),
|
||||
DEVMETHOD(agp_unbind_page, agp_intel_unbind_page),
|
||||
DEVMETHOD(agp_flush_tlb, agp_intel_flush_tlb),
|
||||
DEVMETHOD(agp_enable, agp_generic_enable),
|
||||
DEVMETHOD(agp_alloc_memory, agp_generic_alloc_memory),
|
||||
DEVMETHOD(agp_free_memory, agp_generic_free_memory),
|
||||
DEVMETHOD(agp_bind_memory, agp_generic_bind_memory),
|
||||
DEVMETHOD(agp_unbind_memory, agp_generic_unbind_memory),
|
||||
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
static driver_t agp_intel_driver = {
|
||||
"agp",
|
||||
agp_intel_methods,
|
||||
sizeof(struct agp_intel_softc),
|
||||
};
|
||||
|
||||
static devclass_t agp_devclass;
|
||||
|
||||
DRIVER_MODULE(agp_intel, pci, agp_intel_driver, agp_devclass, 0, 0);
|
256
sys/pci/agp_sis.c
Normal file
256
sys/pci/agp_sis.c
Normal file
@ -0,0 +1,256 @@
|
||||
/*-
|
||||
* Copyright (c) 2000 Doug Rabson
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#include "opt_bus.h"
|
||||
#include "opt_pci.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/lock.h>
|
||||
|
||||
#include <pci/pcivar.h>
|
||||
#include <pci/pcireg.h>
|
||||
#include <pci/agppriv.h>
|
||||
#include <pci/agpreg.h>
|
||||
|
||||
#include <vm/vm.h>
|
||||
#include <vm/vm_object.h>
|
||||
#include <vm/pmap.h>
|
||||
|
||||
struct agp_sis_softc {
|
||||
struct agp_softc agp;
|
||||
u_int32_t initial_aperture; /* aperture size at startup */
|
||||
struct agp_gatt *gatt;
|
||||
};
|
||||
|
||||
static const char*
|
||||
agp_sis_match(device_t dev)
|
||||
{
|
||||
if (pci_get_class(dev) != PCIC_BRIDGE
|
||||
|| pci_get_subclass(dev) != PCIS_BRIDGE_HOST)
|
||||
return NULL;
|
||||
|
||||
if (agp_find_caps(dev) == 0)
|
||||
return NULL;
|
||||
|
||||
switch (pci_get_devid(dev)) {
|
||||
case 0x00011039:
|
||||
return ("SiS 5591 host to AGP bridge");
|
||||
};
|
||||
|
||||
if (pci_get_vendor(dev) == 0x1039)
|
||||
return ("SIS Generic host to PCI bridge");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
agp_sis_probe(device_t dev)
|
||||
{
|
||||
const char *desc;
|
||||
|
||||
desc = agp_sis_match(dev);
|
||||
if (desc) {
|
||||
device_verbose(dev);
|
||||
device_set_desc(dev, desc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ENXIO;
|
||||
}
|
||||
|
||||
static int
|
||||
agp_sis_attach(device_t dev)
|
||||
{
|
||||
struct agp_sis_softc *sc = device_get_softc(dev);
|
||||
struct agp_gatt *gatt;
|
||||
int error;
|
||||
|
||||
error = agp_generic_attach(dev);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
sc->initial_aperture = AGP_GET_APERTURE(dev);
|
||||
|
||||
for (;;) {
|
||||
gatt = agp_alloc_gatt(dev);
|
||||
if (gatt)
|
||||
break;
|
||||
|
||||
/*
|
||||
* Probably contigmalloc failure. Try reducing the
|
||||
* aperture so that the gatt size reduces.
|
||||
*/
|
||||
if (AGP_SET_APERTURE(dev, AGP_GET_APERTURE(dev) / 2)) {
|
||||
agp_generic_detach(dev);
|
||||
return ENOMEM;
|
||||
}
|
||||
}
|
||||
sc->gatt = gatt;
|
||||
|
||||
/* Install the gatt. */
|
||||
pci_write_config(dev, AGP_SIS_ATTBASE, gatt->ag_physical, 4);
|
||||
|
||||
/* Enable the aperture. */
|
||||
pci_write_config(dev, AGP_SIS_WINCTRL,
|
||||
pci_read_config(dev, AGP_SIS_WINCTRL, 1) | 3, 1);
|
||||
|
||||
/*
|
||||
* Enable the TLB and make it automatically invalidate entries
|
||||
* when the GATT is written.
|
||||
*/
|
||||
pci_write_config(dev, AGP_SIS_TLBCTRL, 0x05, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
agp_sis_detach(device_t dev)
|
||||
{
|
||||
struct agp_sis_softc *sc = device_get_softc(dev);
|
||||
int error;
|
||||
|
||||
error = agp_generic_detach(dev);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
/* Disable the aperture.. */
|
||||
pci_write_config(dev, AGP_SIS_WINCTRL,
|
||||
pci_read_config(dev, AGP_SIS_WINCTRL, 1) & ~3, 1);
|
||||
|
||||
/* and the TLB. */
|
||||
pci_write_config(dev, AGP_SIS_TLBCTRL, 0, 1);
|
||||
|
||||
/* Put the aperture back the way it started. */
|
||||
AGP_SET_APERTURE(dev, sc->initial_aperture);
|
||||
|
||||
agp_free_gatt(sc->gatt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u_int32_t
|
||||
agp_sis_get_aperture(device_t dev)
|
||||
{
|
||||
int gws;
|
||||
|
||||
/*
|
||||
* The aperture size is equal to 4M<<gws.
|
||||
*/
|
||||
gws = (pci_read_config(dev, AGP_SIS_WINCTRL, 1) & 0x70) >> 4;
|
||||
return (4*1024*1024) << gws;
|
||||
}
|
||||
|
||||
static int
|
||||
agp_sis_set_aperture(device_t dev, u_int32_t aperture)
|
||||
{
|
||||
int gws;
|
||||
|
||||
/*
|
||||
* Check for a power of two and make sure its within the
|
||||
* programmable range.
|
||||
*/
|
||||
if (aperture & (aperture - 1)
|
||||
|| aperture < 4*1024*1024
|
||||
|| aperture > 256*1024*1024)
|
||||
return EINVAL;
|
||||
|
||||
gws = ffs(aperture / 4*1024*1024) - 1;
|
||||
|
||||
pci_write_config(dev, AGP_SIS_WINCTRL,
|
||||
((pci_read_config(dev, AGP_SIS_WINCTRL, 1) & ~0x70)
|
||||
| gws << 4), 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
agp_sis_bind_page(device_t dev, int offset, vm_offset_t physical)
|
||||
{
|
||||
struct agp_sis_softc *sc = device_get_softc(dev);
|
||||
|
||||
if (offset < 0 || offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT))
|
||||
return EINVAL;
|
||||
|
||||
sc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = physical;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
agp_sis_unbind_page(device_t dev, int offset)
|
||||
{
|
||||
struct agp_sis_softc *sc = device_get_softc(dev);
|
||||
|
||||
if (offset < 0 || offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT))
|
||||
return EINVAL;
|
||||
|
||||
sc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
agp_sis_flush_tlb(device_t dev)
|
||||
{
|
||||
pci_write_config(dev, AGP_SIS_TLBFLUSH, 0x02, 1);
|
||||
}
|
||||
|
||||
static device_method_t agp_sis_methods[] = {
|
||||
/* Device interface */
|
||||
DEVMETHOD(device_probe, agp_sis_probe),
|
||||
DEVMETHOD(device_attach, agp_sis_attach),
|
||||
DEVMETHOD(device_detach, agp_sis_detach),
|
||||
DEVMETHOD(device_shutdown, bus_generic_shutdown),
|
||||
DEVMETHOD(device_suspend, bus_generic_suspend),
|
||||
DEVMETHOD(device_resume, bus_generic_resume),
|
||||
|
||||
/* AGP interface */
|
||||
DEVMETHOD(agp_get_aperture, agp_sis_get_aperture),
|
||||
DEVMETHOD(agp_set_aperture, agp_sis_set_aperture),
|
||||
DEVMETHOD(agp_bind_page, agp_sis_bind_page),
|
||||
DEVMETHOD(agp_unbind_page, agp_sis_unbind_page),
|
||||
DEVMETHOD(agp_flush_tlb, agp_sis_flush_tlb),
|
||||
DEVMETHOD(agp_enable, agp_generic_enable),
|
||||
DEVMETHOD(agp_alloc_memory, agp_generic_alloc_memory),
|
||||
DEVMETHOD(agp_free_memory, agp_generic_free_memory),
|
||||
DEVMETHOD(agp_bind_memory, agp_generic_bind_memory),
|
||||
DEVMETHOD(agp_unbind_memory, agp_generic_unbind_memory),
|
||||
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
static driver_t agp_sis_driver = {
|
||||
"agp",
|
||||
agp_sis_methods,
|
||||
sizeof(struct agp_sis_softc),
|
||||
};
|
||||
|
||||
static devclass_t agp_devclass;
|
||||
|
||||
DRIVER_MODULE(agp_sis, pci, agp_sis_driver, agp_devclass, 0, 0);
|
253
sys/pci/agp_via.c
Normal file
253
sys/pci/agp_via.c
Normal file
@ -0,0 +1,253 @@
|
||||
/*-
|
||||
* Copyright (c) 2000 Doug Rabson
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#include "opt_bus.h"
|
||||
#include "opt_pci.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/lock.h>
|
||||
|
||||
#include <pci/pcivar.h>
|
||||
#include <pci/pcireg.h>
|
||||
#include <pci/agppriv.h>
|
||||
#include <pci/agpreg.h>
|
||||
|
||||
#include <vm/vm.h>
|
||||
#include <vm/vm_object.h>
|
||||
#include <vm/pmap.h>
|
||||
|
||||
struct agp_via_softc {
|
||||
struct agp_softc agp;
|
||||
u_int32_t initial_aperture; /* aperture size at startup */
|
||||
struct agp_gatt *gatt;
|
||||
};
|
||||
|
||||
static const char*
|
||||
agp_via_match(device_t dev)
|
||||
{
|
||||
if (pci_get_class(dev) != PCIC_BRIDGE
|
||||
|| pci_get_subclass(dev) != PCIS_BRIDGE_HOST)
|
||||
return NULL;
|
||||
|
||||
if (agp_find_caps(dev) == 0)
|
||||
return NULL;
|
||||
|
||||
switch (pci_get_devid(dev)) {
|
||||
case 0x05011106:
|
||||
return ("VIA 8501 (Apollo MVP4) host to PCI bridge");
|
||||
case 0x05971106:
|
||||
return ("VIA 82C597 (Apollo VP3) host to PCI bridge");
|
||||
case 0x05981106:
|
||||
return ("VIA 82C598 (Apollo MVP3) host to PCI bridge");
|
||||
case 0x06911106:
|
||||
return ("VIA 82C691 (Apollo Pro) host to PCI bridge");
|
||||
};
|
||||
|
||||
if (pci_get_vendor(dev) == 0x1106)
|
||||
return ("VIA Generic host to PCI bridge");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
agp_via_probe(device_t dev)
|
||||
{
|
||||
const char *desc;
|
||||
|
||||
desc = agp_via_match(dev);
|
||||
if (desc) {
|
||||
device_verbose(dev);
|
||||
device_set_desc(dev, desc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ENXIO;
|
||||
}
|
||||
|
||||
static int
|
||||
agp_via_attach(device_t dev)
|
||||
{
|
||||
struct agp_via_softc *sc = device_get_softc(dev);
|
||||
struct agp_gatt *gatt;
|
||||
int error;
|
||||
|
||||
error = agp_generic_attach(dev);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
sc->initial_aperture = AGP_GET_APERTURE(dev);
|
||||
|
||||
for (;;) {
|
||||
gatt = agp_alloc_gatt(dev);
|
||||
if (gatt)
|
||||
break;
|
||||
|
||||
/*
|
||||
* Probably contigmalloc failure. Try reducing the
|
||||
* aperture so that the gatt size reduces.
|
||||
*/
|
||||
if (AGP_SET_APERTURE(dev, AGP_GET_APERTURE(dev) / 2)) {
|
||||
agp_generic_detach(dev);
|
||||
return ENOMEM;
|
||||
}
|
||||
}
|
||||
sc->gatt = gatt;
|
||||
|
||||
/* Install the gatt. */
|
||||
pci_write_config(dev, AGP_VIA_ATTBASE, gatt->ag_physical | 3, 4);
|
||||
|
||||
/* Enable the aperture. */
|
||||
pci_write_config(dev, AGP_VIA_GARTCTRL, 0x0f, 4);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
agp_via_detach(device_t dev)
|
||||
{
|
||||
struct agp_via_softc *sc = device_get_softc(dev);
|
||||
int error;
|
||||
|
||||
error = agp_generic_detach(dev);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
pci_write_config(dev, AGP_VIA_GARTCTRL, 0, 4);
|
||||
pci_write_config(dev, AGP_VIA_ATTBASE, 0, 4);
|
||||
AGP_SET_APERTURE(dev, sc->initial_aperture);
|
||||
agp_free_gatt(sc->gatt);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u_int32_t
|
||||
agp_via_get_aperture(device_t dev)
|
||||
{
|
||||
u_int32_t apsize;
|
||||
|
||||
apsize = pci_read_config(dev, AGP_VIA_APSIZE, 1) & 0x1f;
|
||||
|
||||
/*
|
||||
* The size is determined by the number of low bits of
|
||||
* register APBASE which are forced to zero. The low 20 bits
|
||||
* are always forced to zero and each zero bit in the apsize
|
||||
* field just read forces the corresponding bit in the 27:20
|
||||
* to be zero. We calculate the aperture size accordingly.
|
||||
*/
|
||||
return (((apsize ^ 0xff) << 20) | ((1 << 20) - 1)) + 1;
|
||||
}
|
||||
|
||||
static int
|
||||
agp_via_set_aperture(device_t dev, u_int32_t aperture)
|
||||
{
|
||||
u_int32_t apsize;
|
||||
|
||||
/*
|
||||
* Reverse the magic from get_aperture.
|
||||
*/
|
||||
apsize = ((aperture - 1) >> 20) ^ 0xff;
|
||||
|
||||
/*
|
||||
* Double check for sanity.
|
||||
*/
|
||||
if ((((apsize ^ 0xff) << 20) | ((1 << 20) - 1)) + 1 != aperture)
|
||||
return EINVAL;
|
||||
|
||||
pci_write_config(dev, AGP_VIA_APSIZE, apsize, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
agp_via_bind_page(device_t dev, int offset, vm_offset_t physical)
|
||||
{
|
||||
struct agp_via_softc *sc = device_get_softc(dev);
|
||||
|
||||
if (offset < 0 || offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT))
|
||||
return EINVAL;
|
||||
|
||||
sc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = physical;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
agp_via_unbind_page(device_t dev, int offset)
|
||||
{
|
||||
struct agp_via_softc *sc = device_get_softc(dev);
|
||||
|
||||
if (offset < 0 || offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT))
|
||||
return EINVAL;
|
||||
|
||||
sc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
agp_via_flush_tlb(device_t dev)
|
||||
{
|
||||
pci_write_config(dev, AGP_VIA_GARTCTRL, 0x8f, 4);
|
||||
pci_write_config(dev, AGP_VIA_GARTCTRL, 0x0f, 4);
|
||||
}
|
||||
|
||||
static device_method_t agp_via_methods[] = {
|
||||
/* Device interface */
|
||||
DEVMETHOD(device_probe, agp_via_probe),
|
||||
DEVMETHOD(device_attach, agp_via_attach),
|
||||
DEVMETHOD(device_detach, agp_via_detach),
|
||||
DEVMETHOD(device_shutdown, bus_generic_shutdown),
|
||||
DEVMETHOD(device_suspend, bus_generic_suspend),
|
||||
DEVMETHOD(device_resume, bus_generic_resume),
|
||||
|
||||
/* AGP interface */
|
||||
DEVMETHOD(agp_get_aperture, agp_via_get_aperture),
|
||||
DEVMETHOD(agp_set_aperture, agp_via_set_aperture),
|
||||
DEVMETHOD(agp_bind_page, agp_via_bind_page),
|
||||
DEVMETHOD(agp_unbind_page, agp_via_unbind_page),
|
||||
DEVMETHOD(agp_flush_tlb, agp_via_flush_tlb),
|
||||
DEVMETHOD(agp_enable, agp_generic_enable),
|
||||
DEVMETHOD(agp_alloc_memory, agp_generic_alloc_memory),
|
||||
DEVMETHOD(agp_free_memory, agp_generic_free_memory),
|
||||
DEVMETHOD(agp_bind_memory, agp_generic_bind_memory),
|
||||
DEVMETHOD(agp_unbind_memory, agp_generic_unbind_memory),
|
||||
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
static driver_t agp_via_driver = {
|
||||
"agp",
|
||||
agp_via_methods,
|
||||
sizeof(struct agp_via_softc),
|
||||
};
|
||||
|
||||
static devclass_t agp_devclass;
|
||||
|
||||
DRIVER_MODULE(agp_via, pci, agp_via_driver, agp_devclass, 0, 0);
|
103
sys/pci/agppriv.h
Normal file
103
sys/pci/agppriv.h
Normal file
@ -0,0 +1,103 @@
|
||||
/*-
|
||||
* Copyright (c) 2000 Doug Rabson
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _PCI_AGPPRIV_H_
|
||||
#define _PCI_AGPPRIV_H_
|
||||
|
||||
/*
|
||||
* This file *must not* be included by code outside the agp driver itself.
|
||||
*/
|
||||
|
||||
#include <sys/agpio.h>
|
||||
#include <pci/agpvar.h>
|
||||
|
||||
#define AGP_DEBUGxx
|
||||
|
||||
#ifdef AGP_DEBUG
|
||||
#define AGP_DPF(x...) do { \
|
||||
printf("agp: "); \
|
||||
printf(##x); \
|
||||
} while (0)
|
||||
#else
|
||||
#define AGP_DPF(x...) do {} while (0)
|
||||
#endif
|
||||
|
||||
#include "agp_if.h"
|
||||
|
||||
/*
|
||||
* Data structure to describe an AGP memory allocation.
|
||||
*/
|
||||
TAILQ_HEAD(agp_memory_list, agp_memory);
|
||||
struct agp_memory {
|
||||
TAILQ_ENTRY(agp_memory) am_link; /* wiring for the tailq */
|
||||
int am_id; /* unique id for block */
|
||||
vm_size_t am_size; /* number of bytes allocated */
|
||||
struct vm_object *am_obj; /* VM object owning pages */
|
||||
vm_offset_t am_physical; /* bogus hack for i810 */
|
||||
vm_offset_t am_offset; /* page offset if bound */
|
||||
int am_is_bound; /* non-zero if bound */
|
||||
};
|
||||
|
||||
/*
|
||||
* All chipset drivers must have this at the start of their softc.
|
||||
*/
|
||||
struct agp_softc {
|
||||
struct resource *as_aperture; /* location of aperture */
|
||||
u_int32_t as_maxmem; /* allocation upper bound */
|
||||
u_int32_t as_allocated; /* amount allocated */
|
||||
enum agp_acquire_state as_state;
|
||||
struct agp_memory_list as_memory; /* list of allocated memory */
|
||||
int as_nextid; /* next memory block id */
|
||||
int as_isopen; /* user device is open */
|
||||
dev_t as_devnode; /* from make_dev */
|
||||
struct lock as_lock; /* lock for access to GATT */
|
||||
};
|
||||
|
||||
struct agp_gatt {
|
||||
u_int32_t ag_entries;
|
||||
u_int32_t *ag_virtual;
|
||||
vm_offset_t ag_physical;
|
||||
};
|
||||
|
||||
u_int8_t agp_find_caps(device_t dev);
|
||||
struct agp_gatt *agp_alloc_gatt(device_t dev);
|
||||
void agp_free_gatt(struct agp_gatt *gatt);
|
||||
int agp_generic_attach(device_t dev);
|
||||
int agp_generic_detach(device_t dev);
|
||||
int agp_generic_enable(device_t dev, u_int32_t mode);
|
||||
struct agp_memory *agp_generic_alloc_memory(device_t dev, int type,
|
||||
vm_size_t size);
|
||||
int agp_generic_free_memory(device_t dev,
|
||||
struct agp_memory *mem);
|
||||
int agp_generic_bind_memory(device_t dev,
|
||||
struct agp_memory *mem,
|
||||
vm_offset_t offset);
|
||||
int agp_generic_unbind_memory(device_t dev,
|
||||
struct agp_memory *mem);
|
||||
|
||||
#endif /* !_PCI_AGPPRIV_H_ */
|
109
sys/pci/agpreg.h
Normal file
109
sys/pci/agpreg.h
Normal file
@ -0,0 +1,109 @@
|
||||
/*-
|
||||
* Copyright (c) 2000 Doug Rabson
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _PCI_AGPREG_H_
|
||||
#define _PCI_AGPREG_H_
|
||||
|
||||
/*
|
||||
* Offsets for various AGP configuration registers.
|
||||
*/
|
||||
#define AGP_APBASE 0x10
|
||||
#define AGP_CAPPTR 0x34
|
||||
|
||||
/*
|
||||
* Offsets from the AGP Capability pointer.
|
||||
*/
|
||||
#define AGP_CAPID 0x0
|
||||
#define AGP_CAPID_GET_MAJOR(x) (((x) & 0x00f00000U) >> 20)
|
||||
#define AGP_CAPID_GET_MINOR(x) (((x) & 0x000f0000U) >> 16)
|
||||
#define AGP_CAPID_GET_NEXT_PTR(x) (((x) & 0x0000ff00U) >> 8)
|
||||
#define AGP_CAPID_GET_CAP_ID(x) (((x) & 0x000000ffU) >> 0)
|
||||
|
||||
#define AGP_STATUS 0x4
|
||||
#define AGP_COMMAND 0x8
|
||||
|
||||
/*
|
||||
* Config offsets for Intel AGP chipsets.
|
||||
*/
|
||||
#define AGP_INTEL_NBXCFG 0x50
|
||||
#define AGP_INTEL_ERRSTS 0x91
|
||||
#define AGP_INTEL_AGPCTRL 0xb0
|
||||
#define AGP_INTEL_APSIZE 0xb4
|
||||
#define AGP_INTEL_ATTBASE 0xb8
|
||||
|
||||
/*
|
||||
* Config offsets for VIA AGP chipsets.
|
||||
*/
|
||||
#define AGP_VIA_GARTCTRL 0x80
|
||||
#define AGP_VIA_APSIZE 0x84
|
||||
#define AGP_VIA_ATTBASE 0x88
|
||||
|
||||
/*
|
||||
* Config offsets for SiS AGP chipsets.
|
||||
*/
|
||||
#define AGP_SIS_ATTBASE 0x90
|
||||
#define AGP_SIS_WINCTRL 0x94
|
||||
#define AGP_SIS_TLBCTRL 0x97
|
||||
#define AGP_SIS_TLBFLUSH 0x98
|
||||
|
||||
/*
|
||||
* Config offsets for Ali AGP chipsets.
|
||||
*/
|
||||
#define AGP_ALI_AGPCTRL 0xb8
|
||||
#define AGP_ALI_ATTBASE 0xbc
|
||||
#define AGP_ALI_TLBCTRL 0xc0
|
||||
|
||||
/*
|
||||
* Config offsets for the AMD 751 chipset.
|
||||
*/
|
||||
#define AGP_AMD751_REGISTERS 0x14
|
||||
#define AGP_AMD751_APCTRL 0xac
|
||||
#define AGP_AMD751_MODECTRL 0xb0
|
||||
|
||||
/*
|
||||
* Memory mapped register offsets for AMD 751 chipset.
|
||||
*/
|
||||
#define AGP_AMD751_CAPS 0x00
|
||||
#define AGP_AMD751_CAPS_EHI 0x0800
|
||||
#define AGP_AMD751_CAPS_P2P 0x0400
|
||||
#define AGP_AMD751_CAPS_MPC 0x0200
|
||||
#define AGP_AMD751_CAPS_VBE 0x0100
|
||||
#define AGP_AMD751_CAPS_REV 0x00ff
|
||||
#define AGP_AMD751_STATUS 0x02
|
||||
#define AGP_AMD751_STATUS_P2PS 0x0800
|
||||
#define AGP_AMD751_STATUS_GCS 0x0400
|
||||
#define AGP_AMD751_STATUS_MPS 0x0200
|
||||
#define AGP_AMD751_STATUS_VBES 0x0100
|
||||
#define AGP_AMD751_STATUS_P2PE 0x0008
|
||||
#define AGP_AMD751_STATUS_GCE 0x0004
|
||||
#define AGP_AMD751_STATUS_VBEE 0x0001
|
||||
#define AGP_AMD751_ATTBASE 0x04
|
||||
#define AGP_AMD751_TLBCTRL 0x0c
|
||||
|
||||
|
||||
#endif /* !_PCI_AGPREG_H_ */
|
125
sys/pci/agpvar.h
Normal file
125
sys/pci/agpvar.h
Normal file
@ -0,0 +1,125 @@
|
||||
/*-
|
||||
* Copyright (c) 2000 Doug Rabson
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _PCI_AGPVAR_H_
|
||||
#define _PCI_AGPVAR_H_
|
||||
|
||||
/*
|
||||
* The AGP chipset can be acquired by user or kernel code. If the
|
||||
* chipset has already been acquired, it cannot be acquired by another
|
||||
* user until the previous user has released it.
|
||||
*/
|
||||
enum agp_acquire_state {
|
||||
AGP_ACQUIRE_FREE,
|
||||
AGP_ACQUIRE_USER,
|
||||
AGP_ACQUIRE_KERNEL
|
||||
};
|
||||
|
||||
/*
|
||||
* This structure is used to query the state of the AGP system.
|
||||
*/
|
||||
struct agp_info {
|
||||
u_int32_t ai_mode;
|
||||
vm_offset_t ai_aperture_base;
|
||||
vm_size_t ai_aperture_size;
|
||||
vm_size_t ai_memory_allowed;
|
||||
vm_size_t ai_memory_used;
|
||||
u_int32_t ai_devid;
|
||||
};
|
||||
|
||||
struct agp_memory_info {
|
||||
vm_size_t ami_size; /* size in bytes */
|
||||
vm_offset_t ami_physical; /* bogus hack for i810 */
|
||||
vm_offset_t ami_offset; /* page offset if bound */
|
||||
int ami_is_bound; /* non-zero if bound */
|
||||
};
|
||||
|
||||
/*
|
||||
* Find the AGP device and return it.
|
||||
*/
|
||||
device_t agp_find_device(void);
|
||||
|
||||
/*
|
||||
* Return the current owner of the AGP chipset.
|
||||
*/
|
||||
enum agp_acquire_state agp_state(device_t dev);
|
||||
|
||||
/*
|
||||
* Query the state of the AGP system.
|
||||
*/
|
||||
void agp_get_info(device_t dev, struct agp_info *info);
|
||||
|
||||
/*
|
||||
* Acquire the AGP chipset for use by the kernel. Returns EBUSY if the
|
||||
* AGP chipset is already acquired by another user.
|
||||
*/
|
||||
int agp_acquire(device_t dev);
|
||||
|
||||
/*
|
||||
* Release the AGP chipset.
|
||||
*/
|
||||
int agp_release(device_t dev);
|
||||
|
||||
/*
|
||||
* Enable the agp hardware with the relavent mode. The mode bits are
|
||||
* defined in <pci/agpreg.h>
|
||||
*/
|
||||
int agp_enable(device_t dev, u_int32_t mode);
|
||||
|
||||
/*
|
||||
* Allocate physical memory suitable for mapping into the AGP
|
||||
* aperture. The value returned is an opaque handle which can be
|
||||
* passed to agp_bind(), agp_unbind() or agp_deallocate().
|
||||
*/
|
||||
void *agp_alloc_memory(device_t dev, int type, vm_size_t bytes);
|
||||
|
||||
/*
|
||||
* Free memory which was allocated with agp_allocate().
|
||||
*/
|
||||
void agp_free_memory(device_t dev, void *handle);
|
||||
|
||||
/*
|
||||
* Bind memory allocated with agp_allocate() at a given offset within
|
||||
* the AGP aperture. Returns EINVAL if the memory is already bound or
|
||||
* the offset is not at an AGP page boundary.
|
||||
*/
|
||||
int agp_bind_memory(device_t dev, void *handle, vm_offset_t offset);
|
||||
|
||||
/*
|
||||
* Unbind memory from the AGP aperture. Returns EINVAL if the memory
|
||||
* is not bound.
|
||||
*/
|
||||
int agp_unbind_memory(device_t dev, void *handle);
|
||||
|
||||
/*
|
||||
* Retrieve information about a memory block allocated with
|
||||
* agp_alloc_memory().
|
||||
*/
|
||||
void agp_memory_info(device_t dev, void *handle, struct agp_memory_info *mi);
|
||||
|
||||
#endif /* !_PCI_AGPVAR_H_ */
|
128
sys/sys/agpio.h
Normal file
128
sys/sys/agpio.h
Normal file
@ -0,0 +1,128 @@
|
||||
/*-
|
||||
* Copyright (c) 2000 Doug Rabson
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _SYS_AGPIO_H_
|
||||
#define _SYS_AGPIO_H_
|
||||
|
||||
/*
|
||||
* The AGP gatt uses 4k pages irrespective of the host page size.
|
||||
*/
|
||||
#define AGP_PAGE_SIZE 4096
|
||||
#define AGP_PAGE_SHIFT 12
|
||||
|
||||
/*
|
||||
* Macros to manipulate AGP mode words.
|
||||
*/
|
||||
#define AGP_MODE_GET_RQ(x) (((x) & 0xff000000U) >> 24)
|
||||
#define AGP_MODE_GET_SBA(x) (((x) & 0x00000200U) >> 9)
|
||||
#define AGP_MODE_GET_AGP(x) (((x) & 0x00000100U) >> 8)
|
||||
#define AGP_MODE_GET_4G(x) (((x) & 0x00000020U) >> 5)
|
||||
#define AGP_MODE_GET_FW(x) (((x) & 0x00000010U) >> 4)
|
||||
#define AGP_MODE_GET_RATE(x) ((x) & 0x00000003U)
|
||||
#define AGP_MODE_SET_RQ(x,v) (((x) & ~0xff000000U) | ((v) << 24))
|
||||
#define AGP_MODE_SET_SBA(x,v) (((x) & ~0x00000200U) | ((v) << 9))
|
||||
#define AGP_MODE_SET_AGP(x,v) (((x) & ~0x00000100U) | ((v) << 8))
|
||||
#define AGP_MODE_SET_4G(x,v) (((x) & ~0x00000020U) | ((v) << 5))
|
||||
#define AGP_MODE_SET_FW(x,v) (((x) & ~0x00000010U) | ((v) << 4))
|
||||
#define AGP_MODE_SET_RATE(x,v) (((x) & ~0x00000003U) | (v))
|
||||
#define AGP_MODE_RATE_1x 0x00000001
|
||||
#define AGP_MODE_RATE_2x 0x00000002
|
||||
#define AGP_MODE_RATE_4x 0x00000004
|
||||
|
||||
#define AGPIOC_BASE 'A'
|
||||
#define AGPIOC_INFO _IOR (AGPIOC_BASE, 0, agp_info)
|
||||
#define AGPIOC_ACQUIRE _IO (AGPIOC_BASE, 1)
|
||||
#define AGPIOC_RELEASE _IO (AGPIOC_BASE, 2)
|
||||
#define AGPIOC_SETUP _IOW (AGPIOC_BASE, 3, agp_setup)
|
||||
#if 0
|
||||
#define AGPIOC_RESERVE _IOW (AGPIOC_BASE, 4, agp_region)
|
||||
#define AGPIOC_PROTECT _IOW (AGPIOC_BASE, 5, agp_region)
|
||||
#endif
|
||||
#define AGPIOC_ALLOCATE _IOWR(AGPIOC_BASE, 6, agp_allocate)
|
||||
#define AGPIOC_DEALLOCATE _IOW (AGPIOC_BASE, 7, int)
|
||||
#define AGPIOC_BIND _IOW (AGPIOC_BASE, 8, agp_bind)
|
||||
#define AGPIOC_UNBIND _IOW (AGPIOC_BASE, 9, agp_unbind)
|
||||
|
||||
typedef struct _agp_version {
|
||||
u_int16_t major;
|
||||
u_int16_t minor;
|
||||
} agp_version;
|
||||
|
||||
typedef struct _agp_info {
|
||||
agp_version version; /* version of the driver */
|
||||
u_int32_t bridge_id; /* bridge vendor/device */
|
||||
u_int32_t agp_mode; /* mode info of bridge */
|
||||
off_t aper_base; /* base of aperture */
|
||||
size_t aper_size; /* size of aperture */
|
||||
size_t pg_total; /* max pages (swap + system) */
|
||||
size_t pg_system; /* max pages (system) */
|
||||
size_t pg_used; /* current pages used */
|
||||
} agp_info;
|
||||
|
||||
typedef struct _agp_setup {
|
||||
u_int32_t agp_mode; /* mode info of bridge */
|
||||
} agp_setup;
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* The "prot" down below needs still a "sleep" flag somehow ...
|
||||
*/
|
||||
typedef struct _agp_segment {
|
||||
off_t pg_start; /* starting page to populate */
|
||||
size_t pg_count; /* number of pages */
|
||||
int prot; /* prot flags for mmap */
|
||||
} agp_segment;
|
||||
|
||||
typedef struct _agp_region {
|
||||
pid_t pid; /* pid of process */
|
||||
size_t seg_count; /* number of segments */
|
||||
struct _agp_segment *seg_list;
|
||||
} agp_region;
|
||||
#endif
|
||||
|
||||
typedef struct _agp_allocate {
|
||||
int key; /* tag of allocation */
|
||||
size_t pg_count; /* number of pages */
|
||||
u_int32_t type; /* 0 == normal, other devspec */
|
||||
u_int32_t physical; /* device specific (some devices
|
||||
* need a phys address of the
|
||||
* actual page behind the gatt
|
||||
* table) */
|
||||
} agp_allocate;
|
||||
|
||||
typedef struct _agp_bind {
|
||||
int key; /* tag of allocation */
|
||||
off_t pg_start; /* starting page to populate */
|
||||
} agp_bind;
|
||||
|
||||
typedef struct _agp_unbind {
|
||||
int key; /* tag of allocation */
|
||||
u_int32_t priority; /* priority for paging out */
|
||||
} agp_unbind;
|
||||
|
||||
#endif /* !_SYS_AGPIO_H_ */
|
Loading…
Reference in New Issue
Block a user