Index: Makefile =================================================================== RCS file: /home/dcvs/dfports/x11/nvidia-driver/Makefile,v retrieving revision 1.4 diff -u -r1.4 Makefile --- Makefile 18 Aug 2004 14:20:02 -0000 1.4 +++ Makefile 26 Sep 2004 12:41:30 -0000 @@ -32,12 +32,8 @@ XSERVVERSION!= /usr/sbin/pkg_info -O x11-servers/XFree86-4-Server 2>/dev/null | ${GREP} Server- || true XLIBVERSION!= /usr/sbin/pkg_info -O x11/XFree86-4-libraries 2>/dev/null | ${GREP} libraries- || true -PLIST_SUB= XSERVVERSION=${XSERVVERSION} XLIBVERSION=${XLIBVERSION} \ - LINUXBASE=${LINUXBASE} NVVERSION=${NVVERSION} +PLIST_SUB= XSERVVERSION=${XSERVVERSION} XLIBVERSION=${XLIBVERSION} NVVERSION=${NVVERSION} -.if !defined(WITHOUT_LINUX) -USE_LINUX= yes -.endif pre-everything:: .if !defined(WITH_DRAGONFLY_AGP) @@ -67,10 +63,6 @@ .endif pre-install: -.if defined(WITHOUT_LINUX) - @${MKDIR} ${LINUXBASE}/usr/lib -.endif - -@(kldstat -n linux || kldload linux) -rm -f ${WRKSRC}/src/i386 post-install: Index: files/patch-dfly =================================================================== RCS file: /home/dcvs/dfports/x11/nvidia-driver/files/patch-dfly,v retrieving revision 1.6 diff -u -r1.6 patch-dfly --- files/patch-dfly 18 Aug 2004 14:20:02 -0000 1.6 +++ files/patch-dfly 26 Sep 2004 12:39:12 -0000 @@ -1,6 +1,18 @@ -diff -urN ../../NVIDIA-FreeBSD-x86-1.0-6113/src/Makefile.rej ./src/Makefile.rej ---- ../../NVIDIA-FreeBSD-x86-1.0-6113/src/Makefile.rej 1970-01-01 01:00:00.000000000 +0100 -+++ ./src/Makefile.rej 2004-08-04 21:26:57.000000000 +0200 +diff -urN ./src/Makefile ../../nvidia-patched/src/Makefile +--- ./src/Makefile 2004-08-03 01:27:38.000000000 +0200 ++++ ../../nvidia-patched/src/Makefile 2004-09-26 14:14:10.000000000 +0200 +@@ -10,7 +10,7 @@ + .endif + + SRCS= nvidia_ctl.c nvidia_dev.c nvidia_linux.c nvidia_os.c nvidia_os_pci.c nvidia_os_registry.c nvidia_pci.c nvidia_subr.c nvidia_sysctl.c +-SRCS+= device_if.h bus_if.h pci_if.h vnode_if.h ++SRCS+= device_if.h bus_if.h pci_if.h + CFLAGS+= -I${NVIDIA_ROOT}/src -DNV_MAJOR_VERSION=1 -DNV_MINOR_VERSION=0 -DNV_PATCHLEVEL=6113 -DNVCPU_X86 -DNV_BSD -DNV_INT64_OK -DNV_UNIX + CFLAGS+= -D__KERNEL__ -UDEBUG -U_DEBUG -DNDEBUG -O -fno-common + +diff -urN ./src/Makefile.rej ../../nvidia-patched/src/Makefile.rej +--- ./src/Makefile.rej 1970-01-01 01:00:00.000000000 +0100 ++++ ../../nvidia-patched/src/Makefile.rej 2004-09-26 14:13:39.000000000 +0200 @@ -0,0 +1,17 @@ +*************** +*** 12,18 **** @@ -19,9 +31,9 @@ + + OBJS+= ${RMOBJ} + NOOBJ= true -diff -urN ../../NVIDIA-FreeBSD-x86-1.0-6113/src/nv-dragonfly.h ./src/nv-dragonfly.h ---- ../../NVIDIA-FreeBSD-x86-1.0-6113/src/nv-dragonfly.h 1970-01-01 01:00:00.000000000 +0100 -+++ ./src/nv-dragonfly.h 2004-08-04 21:26:57.000000000 +0200 +diff -urN ./src/nv-dragonfly.h ../../nvidia-patched/src/nv-dragonfly.h +--- ./src/nv-dragonfly.h 1970-01-01 01:00:00.000000000 +0100 ++++ ../../nvidia-patched/src/nv-dragonfly.h 2004-09-26 14:31:37.000000000 +0200 @@ -0,0 +1,360 @@ +/* _NVRM_COPYRIGHT_BEGIN_ + * @@ -169,7 +181,7 @@ + * no need for Linux 3D applications, you can safely unset this flag. + */ + -+#define NV_SUPPORT_LINUX_COMPAT ++#undef NV_SUPPORT_LINUX_COMPAT /* XXX: BROKEN! DO NOT ENABLE! */ + +/* + * Enable/Disable support for ACPI Power Management. This is untested and @@ -242,7 +254,7 @@ + struct sysctl_ctx_list sysctl_ctx; + struct selinfo rsel; + -+ struct callout_handle timer_ch; ++ struct callout timer_ch; + + /* list of allocations */ + SLIST_HEAD(alloc_list, nv_alloc) alloc_list; @@ -383,9 +395,9 @@ + +#endif /* __NV_DRAGONFLY_H */ + -diff -urN ../../NVIDIA-FreeBSD-x86-1.0-6113/src/nvidia_ctl.c ./src/nvidia_ctl.c ---- ../../NVIDIA-FreeBSD-x86-1.0-6113/src/nvidia_ctl.c 2004-08-03 01:27:38.000000000 +0200 -+++ ./src/nvidia_ctl.c 2004-08-04 21:26:57.000000000 +0200 +diff -urN ./src/nvidia_ctl.c ../../nvidia-patched/src/nvidia_ctl.c +--- ./src/nvidia_ctl.c 2004-08-03 01:27:38.000000000 +0200 ++++ ../../nvidia-patched/src/nvidia_ctl.c 2004-09-26 14:13:39.000000000 +0200 @@ -11,7 +11,8 @@ #include "nv-misc.h" #include "os-interface.h" @@ -500,9 +512,9 @@ } return 0; -diff -urN ../../NVIDIA-FreeBSD-x86-1.0-6113/src/nvidia_dev.c ./src/nvidia_dev.c ---- ../../NVIDIA-FreeBSD-x86-1.0-6113/src/nvidia_dev.c 2004-08-03 01:27:38.000000000 +0200 -+++ ./src/nvidia_dev.c 2004-08-04 21:26:57.000000000 +0200 +diff -urN ./src/nvidia_dev.c ../../nvidia-patched/src/nvidia_dev.c +--- ./src/nvidia_dev.c 2004-08-03 01:27:38.000000000 +0200 ++++ ../../nvidia-patched/src/nvidia_dev.c 2004-09-26 14:13:39.000000000 +0200 @@ -11,7 +11,7 @@ #include "nv-misc.h" #include "os-interface.h" @@ -621,9 +633,9 @@ return 0; } -diff -urN ../../NVIDIA-FreeBSD-x86-1.0-6113/src/nvidia_linux.c ./src/nvidia_linux.c ---- ../../NVIDIA-FreeBSD-x86-1.0-6113/src/nvidia_linux.c 2004-08-03 01:27:38.000000000 +0200 -+++ ./src/nvidia_linux.c 2004-08-04 21:26:57.000000000 +0200 +diff -urN ./src/nvidia_linux.c ../../nvidia-patched/src/nvidia_linux.c +--- ./src/nvidia_linux.c 2004-08-03 01:27:38.000000000 +0200 ++++ ../../nvidia-patched/src/nvidia_linux.c 2004-09-26 14:13:39.000000000 +0200 @@ -11,7 +11,7 @@ #include "nv-misc.h" #include "os-interface.h" @@ -642,9 +654,9 @@ } struct linux_ioctl_handler nvidia_handler = { -diff -urN ../../NVIDIA-FreeBSD-x86-1.0-6113/src/nvidia_os.c ./src/nvidia_os.c ---- ../../NVIDIA-FreeBSD-x86-1.0-6113/src/nvidia_os.c 2004-08-03 01:27:38.000000000 +0200 -+++ ./src/nvidia_os.c 2004-08-04 21:27:27.000000000 +0200 +diff -urN ./src/nvidia_os.c ../../nvidia-patched/src/nvidia_os.c +--- ./src/nvidia_os.c 2004-08-03 01:27:38.000000000 +0200 ++++ ../../nvidia-patched/src/nvidia_os.c 2004-09-26 14:13:39.000000000 +0200 @@ -11,13 +11,13 @@ #include "nv-misc.h" #include "os-interface.h" @@ -714,9 +726,9 @@ mtx->refcnt = 1; *semaphore = (void *) mtx; -diff -urN ../../NVIDIA-FreeBSD-x86-1.0-6113/src/nvidia_os_pci.c ./src/nvidia_os_pci.c ---- ../../NVIDIA-FreeBSD-x86-1.0-6113/src/nvidia_os_pci.c 2004-08-03 01:27:38.000000000 +0200 -+++ ./src/nvidia_os_pci.c 2004-08-04 21:26:57.000000000 +0200 +diff -urN ./src/nvidia_os_pci.c ../../nvidia-patched/src/nvidia_os_pci.c +--- ./src/nvidia_os_pci.c 2004-08-03 01:27:38.000000000 +0200 ++++ ../../nvidia-patched/src/nvidia_os_pci.c 2004-09-26 14:13:39.000000000 +0200 @@ -11,7 +11,7 @@ #include "nv-misc.h" #include "os-interface.h" @@ -726,9 +738,9 @@ void* os_pci_init_handle( -diff -urN ../../NVIDIA-FreeBSD-x86-1.0-6113/src/nvidia_os_registry.c ./src/nvidia_os_registry.c ---- ../../NVIDIA-FreeBSD-x86-1.0-6113/src/nvidia_os_registry.c 2004-08-03 01:27:38.000000000 +0200 -+++ ./src/nvidia_os_registry.c 2004-08-04 21:26:57.000000000 +0200 +diff -urN ./src/nvidia_os_registry.c ../../nvidia-patched/src/nvidia_os_registry.c +--- ./src/nvidia_os_registry.c 2004-08-03 01:27:38.000000000 +0200 ++++ ../../nvidia-patched/src/nvidia_os_registry.c 2004-09-26 14:13:39.000000000 +0200 @@ -11,7 +11,7 @@ #include "nv-misc.h" #include "os-interface.h" @@ -738,9 +750,9 @@ /* -diff -urN ../../NVIDIA-FreeBSD-x86-1.0-6113/src/nvidia_pci.c ./src/nvidia_pci.c ---- ../../NVIDIA-FreeBSD-x86-1.0-6113/src/nvidia_pci.c 2004-08-03 01:27:38.000000000 +0200 -+++ ./src/nvidia_pci.c 2004-08-04 21:26:57.000000000 +0200 +diff -urN ./src/nvidia_pci.c ../../nvidia-patched/src/nvidia_pci.c +--- ./src/nvidia_pci.c 2004-08-03 01:27:38.000000000 +0200 ++++ ../../nvidia-patched/src/nvidia_pci.c 2004-09-26 14:13:39.000000000 +0200 @@ -11,7 +11,7 @@ #include "nv-misc.h" #include "os-interface.h" @@ -767,9 +779,9 @@ return 0; -diff -urN ../../NVIDIA-FreeBSD-x86-1.0-6113/src/nvidia_subr.c ./src/nvidia_subr.c ---- ../../NVIDIA-FreeBSD-x86-1.0-6113/src/nvidia_subr.c 2004-08-03 01:27:38.000000000 +0200 -+++ ./src/nvidia_subr.c 2004-08-04 21:34:46.000000000 +0200 +diff -urN ./src/nvidia_subr.c ../../nvidia-patched/src/nvidia_subr.c +--- ./src/nvidia_subr.c 2004-08-03 01:27:38.000000000 +0200 ++++ ../../nvidia-patched/src/nvidia_subr.c 2004-09-26 14:37:35.000000000 +0200 @@ -11,7 +11,7 @@ #include "nv-misc.h" #include "os-interface.h" @@ -788,7 +800,41 @@ nv->os_state = sc; nv->flags = 0; nv->device_number = device_get_unit(dev); -@@ -683,18 +685,6 @@ +@@ -50,6 +52,9 @@ + return status; + + nv_sysctl_init(nv); ++ ++ callout_init(&sc->timer_ch); ++ + return 0; + } + +@@ -59,8 +64,12 @@ + struct nvidia_softc *sc; + + sc = device_get_softc(dev); ++ ++ crit_enter(); ++ callout_stop(&sc->timer_ch); /* just in case */ + nv_sysctl_exit(sc->nv_state); + ++ + status = nvidia_dev_detach(sc); + if (status) { + device_printf(dev, "NVRM: NVIDIA driver DEV detach failed.\n"); +@@ -72,8 +81,9 @@ + device_printf(dev, "NVRM: NVIDIA driver CTL detach failed.\n"); + goto fail; + } +- ++ + fail: ++ crit_exit(); + /* XXX Fix me? (state) */ + return status; + } +@@ -683,18 +693,6 @@ void nv_lock_rm(nv_state_t *nv) { @@ -807,7 +853,7 @@ /* * While SMP configurations are handled with a global kernel lock and * in such a way that only one of the CPUs is executing a process and -@@ -704,28 +694,16 @@ +@@ -704,28 +702,16 @@ * This "lock" thus disables interrupts for the duration of this code * segment's execution. */ @@ -838,1634 +884,37 @@ } -diff -urN ../../NVIDIA-FreeBSD-x86-1.0-6113/src/nvidia_subr.c~ ./src/nvidia_subr.c~ ---- ../../NVIDIA-FreeBSD-x86-1.0-6113/src/nvidia_subr.c~ 1970-01-01 01:00:00.000000000 +0100 -+++ ./src/nvidia_subr.c~ 2004-08-04 21:32:49.000000000 +0200 -@@ -0,0 +1,1621 @@ -+/* _NVRM_COPYRIGHT_BEGIN_ -+ * -+ * Copyright 2001-2002 by NVIDIA Corporation. All rights reserved. All -+ * information contained herein is proprietary and confidential to NVIDIA -+ * Corporation. Any use, reproduction, or disclosure without the written -+ * permission of NVIDIA Corporation is prohibited. -+ * -+ * _NVRM_COPYRIGHT_END_ -+ */ -+ -+#include "nv-misc.h" -+#include "os-interface.h" -+#include "nv.h" -+#include "nv-dragonfly.h" -+ -+ -+devclass_t nvidia_devclass; -+nv_state_t nvidia_ctl_state; -+ -+#define rman_get_extends(x) (rman_get_end(x) - rman_get_start(x) + 1) -+ -+int nvidia_attach(device_t dev) -+{ -+ int status; -+ struct nvidia_softc *sc; -+ nv_state_t *nv; -+ -+ sc = device_get_softc(dev); -+ nv = sc->nv_state; -+ -+ printf("nvidia_attach() called - state %d\n", nv); -+ -+ nv->os_state = sc; -+ nv->flags = 0; -+ nv->device_number = device_get_unit(dev); -+ nv->bus = pci_get_bus(dev); -+ nv->slot = pci_get_slot(dev); -+ nv->vendor_id = pci_get_vendor(dev); -+ nv->device_id = pci_get_device(dev); -+ nv->interrupt_line = pci_get_irq(dev); -+ nv->bar.fb.address = rman_get_start(sc->mem); -+ nv->bar.fb.size = rman_get_extends(sc->mem); -+ nv->bar.fb.map = NULL; -+ nv->bar.regs.address = rman_get_start(sc->reg); -+ nv->bar.regs.size = rman_get_extends(sc->reg); -+ nv->bar.regs.map = NULL; -+ -+ if ((status = nvidia_dev_attach(sc)) != 0) -+ return status; -+ -+ if ((status = nvidia_ctl_attach()) != 0) -+ return status; -+ -+ nv_sysctl_init(nv); -+ return 0; -+} -+ -+int nvidia_detach(device_t dev) -+{ -+ int status; -+ struct nvidia_softc *sc; -+ -+ sc = device_get_softc(dev); -+ nv_sysctl_exit(sc->nv_state); -+ -+ status = nvidia_dev_detach(sc); -+ if (status) { -+ device_printf(dev, "NVRM: NVIDIA driver DEV detach failed.\n"); -+ goto fail; -+ } -+ -+ status = nvidia_ctl_detach(); -+ if (status) { -+ device_printf(dev, "NVRM: NVIDIA driver CTL detach failed.\n"); -+ goto fail; -+ } -+ -+fail: -+ /* XXX Fix me? (state) */ -+ return status; -+} -+ -+ -+#ifdef NV_SUPPORT_ACPI_PM -+int nvidia_suspend(device_t dev) -+{ -+ struct nvidia_softc *sc; -+ nv_state_t *nv; -+ int status = RM_ERROR; -+ -+ /* Only if ACPI is running */ -+ if (devclass_get_softc(devclass_find("ACPI"), 0) == NULL) -+ return ENODEV; -+ -+ sc = device_get_softc(dev); -+ nv = sc->nv_state; -+ -+ NV_PCI_ENABLE_DEVICE(nv); -+ -+ if (nv->pdev != NULL) { -+ /* Only if we have RM state */ -+ status = rm_power_management(nv, 0, NV_PM_ACPI_STANDBY); -+ } -+ -+ return status; -+} -+ -+int nvidia_resume(device_t dev) -+{ -+ struct nvidia_softc *sc; -+ nv_state_t *nv; -+ int status = RM_ERROR; -+ -+ sc = device_get_softc(dev); -+ nv = sc->nv_state; -+ -+ NV_PCI_ENABLE_DEVICE(nv); -+ -+ if (nv->pdev != NULL) { -+ /* Only if we have RM state */ -+ status = rm_power_management(nv, 0, NV_PM_ACPI_RESUME); -+ } -+ -+ return status; -+} -+#endif /* NV_SUPPORT_ACPI_PM */ -+ -+ -+int nvidia_alloc(device_t dev) -+{ -+ int error = 0; -+ struct nvidia_softc *sc; -+ -+ sc = device_get_softc(dev); -+ sc->dev = dev; -+ -+ sc->nv_state = malloc(sizeof(nv_state_t), M_NVIDIA, M_WAITOK | M_ZERO); -+ if (sc->nv_state == NULL) { -+ error = ENOMEM; -+ goto fail; -+ } -+ -+ sc->reg = bus_alloc_resource(dev, SYS_RES_MEMORY, &sc->reg_rid, -+ 0, ~0, 1, 0); -+ if (sc->reg == NULL) { -+ device_printf(dev, "NVRM: NVIDIA REG resource alloc failed.\n"); -+ error = ENXIO; -+ goto fail; -+ } -+ -+ sc->mem = bus_alloc_resource(dev, SYS_RES_MEMORY, &sc->mem_rid, -+ 0, ~0, 1, 0); -+ if (sc->mem == NULL) { -+ device_printf(dev, "NVRM: NVIDIA MEM resource alloc failed.\n"); -+ error = ENXIO; -+ goto fail; -+ } -+ -+ sc->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &sc->irq_rid, -+ 0, ~0, 1, RF_SHAREABLE | RF_ACTIVE); -+ if (sc->irq == NULL) { -+ device_printf(dev, "NVRM: NVIDIA IRQ resource alloc failed.\n"); -+ error = ENXIO; -+ goto fail; -+ } -+ -+fail: -+ return (error); -+} -+ -+void nvidia_free(device_t dev) -+{ -+ struct nvidia_softc *sc; -+ -+ sc = device_get_softc(dev); -+ -+ if (sc->reg != NULL) -+ bus_release_resource(dev, SYS_RES_MEMORY, sc->reg_rid, sc->reg); -+ if (sc->mem != NULL) -+ bus_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid, sc->mem); -+ if (sc->irq != NULL) -+ bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid, sc->irq); -+ if (sc->iop != NULL) -+ bus_release_resource(dev, SYS_RES_IOPORT, sc->iop_rid, sc->iop); -+ -+ if (sc->nv_state != NULL) -+ free(sc->nv_state, M_NVIDIA); -+} -+ -+void nvidia_intr(void *xsc) -+{ -+ struct nvidia_softc *sc; -+ nv_state_t *nv; -+ U032 run_bottom_half = 0; -+ -+ sc = (struct nvidia_softc *) xsc; -+ nv = sc->nv_state; -+ -+ NV_PCI_ENABLE_DEVICE(nv); -+ rm_isr(nv->device_number, &run_bottom_half); -+ -+ if (run_bottom_half) { -+ /* We're not executing in an HW ISR context */ -+ rm_isr_bh(nv->pdev); -+ } -+} -+ -+int nvidia_post_vbios(struct nv_ioctl_post_vbios *pv) -+{ -+ int i; -+ struct nvidia_softc *sc; -+ nv_state_t *nv; -+ -+ for (i = 0; i < NV_MAX_DEVICES; i++) { -+ sc = devclass_get_softc(nvidia_devclass, i); -+ if (!sc) -+ continue; -+ nv = sc->nv_state; -+ -+ if ((nv->bus == pv->bus) && (nv->slot == pv->slot) && -+ (nv->flags & NV_FLAG_WAS_POSTED) == 0) -+ nv->flags |= NV_FLAG_NEEDS_POSTING; -+ } -+ -+ return 0; -+} -+ -+int nvidia_get_api_version(struct nv_ioctl_rm_api_version *av) -+{ -+ av->major = NV_MAJOR_VERSION; -+ av->minor = NV_MINOR_VERSION; -+ av->patch = NV_PATCHLEVEL; -+ av->version = NV_RM_API_VERSION; -+ -+ return 0; -+} -+ -+int nvidia_get_card_info(struct nv_ioctl_card_info *ci) -+{ -+ int i; -+ struct nvidia_softc *sc; -+ nv_state_t *nv; -+ -+ /* -+ * Clients supporting versioning will pass version magic in the first -+ * card information field. -+ */ -+ struct nv_ioctl_rm_api_version *av = (void *) ci; -+ -+ if (av->magic != NV_RM_API_VERSION_MAGIC_REQ || -+ av->version != NV_RM_API_VERSION) { -+ /* -+ * This client either has no versioning support its version isn't -+ * identical to ours. While this is fine most of the time, it can -+ * result in severe problems. -+ */ -+ av->magic = NV_RM_API_VERSION_MAGIC_REP; -+ av->major = NV_MAJOR_VERSION; -+ av->minor = NV_MINOR_VERSION; -+ av->patch = NV_PATCHLEVEL; -+ av->version = NV_RM_API_VERSION; -+ -+ return -EINVAL; -+ } -+ -+ /* clear card information structure */ -+ memset(ci, 0, sizeof(ci)); -+ -+ for (i = 0; i < NV_MAX_DEVICES; i++) { -+ sc = devclass_get_softc(nvidia_devclass, i); -+ if (!sc) -+ continue; -+ nv = sc->nv_state; -+ -+ ci[i].flags = (NV_IOCTL_CARD_INFO_FLAG_PRESENT | -+ NV_IOCTL_CARD_INFO_FLAG_NEED_MSYNC); -+ ci[i].bus = nv->bus; -+ ci[i].slot = nv->slot; -+ ci[i].vendor_id = nv->vendor_id; -+ ci[i].device_id = nv->device_id; -+ ci[i].interrupt_line = nv->interrupt_line; -+ ci[i].fb_address = nv->bar.fb.address; -+ ci[i].fb_size = nv->bar.fb.size; -+ ci[i].reg_address = nv->bar.regs.address; -+ ci[i].reg_size = nv->bar.regs.size; -+ } -+ -+ return 0; -+} -+ -+ -+int nvidia_handle_ioctl( -+ dev_t dev, -+ u_long cmd, -+ caddr_t data, -+ int fflag, -+ d_thread_t *td -+) -+{ -+ struct nvidia_softc *sc; -+ nv_state_t *nv; -+ int unit = minor(dev); -+ -+ if (unit == CDEV_CTL_MINOR) { -+ /* the control device is "special" */ -+ nv = &nvidia_ctl_state; -+ } else { -+ sc = devclass_get_softc(nvidia_devclass, unit); -+ if (!sc) -+ return ENXIO; -+ nv = sc->nv_state; -+ } -+ -+ NV_PCI_ENABLE_DEVICE(nv); -+ -+ if (rm_ioctl(nv, __TD_FDT(td), __NV_IOC_NR(cmd), data)) -+ return 0; -+ -+ return EINVAL; -+} -+ -+ -+int nvidia_open_ctl(void) -+{ -+ struct nvidia_softc *sc; -+ nv_state_t *nv = &nvidia_ctl_state; -+ -+ sc = nv->os_state; -+ sc->refcnt++; -+ -+ nv->device_number = NV_CONTROL_DEVICE_NUMBER; -+ -+ nv->flags |= NV_FLAG_OPEN; -+ nv->flags |= NV_FLAG_CONTROL; -+ -+ nv->flags &= ~NV_FLAG_HOTKEY_OCCURRED; -+ -+ return 0; -+} -+ -+int nvidia_close_ctl( -+ dev_t dev, -+ d_thread_t *td -+) -+{ -+ struct nvidia_softc *sc; -+ nv_state_t *nv = &nvidia_ctl_state; -+ -+ if (__TD_FDT_CNT(td) == 0) -+ rm_free_unused_clients(nv, 0, __TD_FDT(td)); -+ -+ sc = nv->os_state; -+ sc->refcnt--; -+ -+ if (sc->refcnt == 0) { -+ /* -+ * The control device has been released; without physical devices -+ * backing it, we only need to reset the flags. -+ */ -+ nv->flags = 0; -+ } -+ -+ return 0; -+} -+ -+int nvidia_open_dev(struct nvidia_softc *sc) -+{ -+ nv_state_t *nv = sc->nv_state; -+ -+ NV_PCI_ENABLE_DEVICE(nv); -+ -+ if ((nv->flags & NV_FLAG_OPEN) == 0) { -+ /* -+ * The device flags indicate that this device has not been opened -+ * or else shut down previously. There isn't much we can do here, -+ * the core resource manager does the actual work. We update both -+ * the flags and the usage count. -+ */ -+ STAILQ_INIT(&sc->event_queue); -+ -+ if (!rm_init_adapter(nv)) { -+ device_printf(sc->dev, "NVRM: rm_init_adapter() failed!\n"); -+ return EIO; -+ } -+ -+ nv->flags |= NV_FLAG_OPEN; -+ } -+ -+ sc->refcnt++; -+ -+ return 0; -+} -+ -+int nvidia_close_dev( -+ struct nvidia_softc *sc, -+ dev_t dev, -+ d_thread_t *td -+) -+{ -+ nv_state_t *nv = sc->nv_state; -+ nv_os_event_t *et; -+ -+ NV_PCI_ENABLE_DEVICE(nv); -+ -+ if (__TD_FDT_CNT(td) == 0) -+ rm_free_unused_clients(nv, 0, __TD_FDT(td)); -+ -+ sc->refcnt--; -+ -+ if (sc->refcnt == 0) { -+ /* -+ * The usage count for this device has dropped to zero, it can be -+ * safely shut down. We don't need to wait for bottom-halfes like -+ * we do on Linux, they are not run asynchronously on FreeBSD. We -+ * do need to reset certain flags, though. -+ */ -+ rm_disable_adapter(nv); -+ rm_shutdown_adapter(nv); -+ -+ while ((et = STAILQ_FIRST(&sc->event_queue))) { -+ STAILQ_REMOVE(&sc->event_queue, et, nv_os_event, queue); -+ free(et, M_NVIDIA); -+ } -+ -+ nv->flags &= ~NV_FLAG_OPEN; -+ } -+ -+ return 0; -+} -+ -+ -+int nvidia_modevent( -+ module_t mod, -+ int what, -+ void *arg -+) -+{ -+ nv_state_t *nv; -+ struct nvidia_softc *sc; -+ -+ switch (what) { -+ case MOD_LOAD: -+ /* -+ * The module load event. Our KLD has just been loaded and is -+ * ready to initialize. We setup the core resource manager in -+ * this routine, further initialization takes place at attach -+ * time. -+ */ -+ if (!rm_init_rm()) { -+ printf("NVRM: rm_init_rm() failed!\n"); -+ return EIO; -+ } -+ -+ nvidia_sysctl_init(); -+ nvidia_linux_init(); -+ rm_load_registry(nv_parms); -+ -+ break; -+ -+ case MOD_UNLOAD: -+ /* -+ * Check if the control device is still open and reject the -+ * unload request if it is. This event can occur even when the -+ * module usage count is non-zero! -+ */ -+ nv = &nvidia_ctl_state; -+ sc = nv->os_state; -+ -+ if (sc->refcnt != 0) /* XXX Fix me? (refcnt) */ -+ return EBUSY; -+ -+ rm_shutdown_rm(); -+ -+ nvidia_sysctl_exit(); -+ nvidia_linux_exit(); -+ -+ break; -+ -+ default: -+ break; -+ } -+ -+ return 0; -+} -+ -+ -+#ifdef NV_SUPPORT_OS_AGP -+S032 nv_os_agp_init( -+ nv_state_t *nv, -+ void **base, -+ void **linear, -+ U032 *limit -+) -+{ -+ void *bitmap; -+ struct nvidia_softc *sc = nv->os_state; -+ struct agp_info ai; -+ -+ U032 mode = 0; -+ U032 fw = 0; -+ U032 sba = 0; -+ U032 rate = AGP_MODE_RATE_1x | AGP_MODE_RATE_2x | AGP_MODE_RATE_4x; -+ U032 size = 0; -+ -+ sc->agp_dev = agp_find_device(); -+ if (!sc->agp_dev) { -+ printf("NVRM: agp_find_device failed, chipset unsupported?\n"); -+ return -ENODEV; -+ } -+ -+ if (agp_acquire(sc->agp_dev) != 0) -+ return -EBUSY; -+ -+ agp_get_info(sc->agp_dev, &ai); -+ mode = ai.ai_mode; -+ -+ if (os_set_mem_range(ai.ai_aperture_base, ai.ai_aperture_size, -+ NV_MEMORY_WRITECOMBINED) != RM_OK) { -+ /* -+ * Failure to set a write-combining range for the AGP aperture is -+ * not necessarily a fatal error condition; we don't know at this -+ * point, however, and abort to prevent performance and stability -+ * problems that may be hard to track down otherwise. -+ */ -+ agp_release(sc->agp_dev); -+ return -EIO; -+ } -+ -+ rm_read_registry_dword(nv, "NVreg", "ReqAGPRate", &rate); -+ rm_read_registry_dword(nv, "NVreg", "EnableAGPFW", &fw); -+ rm_read_registry_dword(nv, "NVreg", "EnableAGPSBA", &sba); -+ -+ mode = AGP_MODE_SET_RATE(mode, AGP_MODE_GET_RATE(mode) & rate); -+ mode = AGP_MODE_SET_FW(mode, fw); -+ mode = AGP_MODE_SET_SBA(mode, sba); -+ -+ if (agp_enable(sc->agp_dev, mode) != 0) { -+ agp_release(sc->agp_dev); -+ os_unset_mem_range(ai.ai_aperture_base, ai.ai_aperture_size); -+ return -EIO; -+ } -+ -+ size = ai.ai_aperture_size / RM_PAGE_SIZE / 8; -+ -+ if (os_alloc_mem(&bitmap, size) != RM_OK) { -+ agp_release(sc->agp_dev); -+ os_unset_mem_range(ai.ai_aperture_base, ai.ai_aperture_size); -+ return -EIO; -+ } -+ -+ os_mem_set(bitmap, 0xff, size); -+ -+ if (rm_set_agp_bitmap(nv, bitmap) != RM_OK) { -+ agp_release(sc->agp_dev); -+ os_free_mem(bitmap); -+ os_unset_mem_range(ai.ai_aperture_base, ai.ai_aperture_size); -+ return -EIO; -+ } -+ -+ *base = (void *) ai.ai_aperture_base; -+ *linear = (void *) ai.ai_aperture_va; -+ *limit = (U032) ai.ai_aperture_size - 1; -+ -+ return 0; -+} -+ -+S032 nv_os_agp_teardown(nv_state_t *nv) -+{ -+ struct nvidia_softc *sc = nv->os_state; -+ void *bitmap; -+ -+ if (agp_release(sc->agp_dev) != 0) -+ return -EBUSY; -+ -+ rm_clear_agp_bitmap(nv, &bitmap); -+ os_free_mem(bitmap); -+ -+ os_unset_mem_range(nv->agp.address, nv->agp.size); -+ -+ return 0; -+} -+#endif /* NV_SUPPORT_OS_AGP */ -+ -+S032 nv_agp_init( -+ nv_state_t *nv, -+ void **base, -+ void **linear, -+ void *limit, -+ U032 config -+) -+{ -+ if (config == NVOS_AGP_CONFIG_DISABLE_AGP) -+ return 1; -+ -+ if ((config & NVOS_AGP_CONFIG_OSAGP) != 0) { -+#ifndef NV_SUPPORT_OS_AGP -+ /* -+ * Inform the user that the kernel module needs to be built -+ * with FreeBSD AGP GART driver (agp.ko) support. -+ */ -+ /* XXX Fix me? (agp.ko) */ -+ /* printf("NVRM: build nvidia.ko with FreeBSD agp.ko support.\n"); */ -+#else -+ if (nv_os_agp_init(nv, base, linear, limit) == 0) { -+ /* -+ * If the operating system AGP GART driver successfully -+ * configured its backend, apply chipset overrides. -+ */ -+ rm_update_agp_config(nv); -+ nv->agp_config = NVOS_AGP_CONFIG_OSAGP; -+ return 0; -+ } -+#endif /* NV_SUPPORT_OS_AGP */ -+ } -+ -+ if ((config & NVOS_AGP_CONFIG_NVAGP) == 0) -+ goto failed; -+ -+ if (devclass_get_softc(devclass_find("agp"), 0) != NULL) { -+ /* -+ * Make sure we don't try to use the internal GART driver when -+ * the OS AGPGART driver (agp.ko) is attached. While that may -+ * be perfectly fine on most systems, but is known to break on -+ * some. -+ * ------------------------------------------------------------- -+ * DON'T REDISTRIBUTE THE DRIVER WITH THIS SANITY CHECK REMOVED! -+ * ------------------------------------------------------------- -+ */ -+ printf("NVRM: detected agp.ko, aborting NVIDIA AGP setup!\n"); -+ goto failed; -+ } -+ -+ if (rm_init_agp(nv) == RM_OK) { -+ nv->agp_config = NVOS_AGP_CONFIG_NVAGP; -+ return 0; -+ } -+ -+failed: -+ nv->agp_config = NVOS_AGP_CONFIG_DISABLE_AGP; -+ return -EIO; -+} -+ -+S032 nv_agp_teardown(nv_state_t *nv) -+{ -+ S032 status = -EINVAL; -+ -+ switch (nv->agp_config) { /* see above */ -+#ifdef NV_SUPPORT_OS_AGP -+ case NVOS_AGP_CONFIG_OSAGP: -+ /* -+ * Release the backend, the AGP core logic will remain -+ * initialized. This is by design (agp.ko). -+ */ -+ status = nv_os_agp_teardown(nv); -+ break; -+#endif -+ case NVOS_AGP_CONFIG_NVAGP: -+ /* -+ * Shut down the NVIDIA AGP GART driver, clearning all -+ * internal state. -+ */ -+ status = rm_teardown_agp(nv); -+ break; -+ } -+ -+ nv->agp_config = NVOS_AGP_CONFIG_DISABLE_AGP; -+ return status; -+} -+ -+S032 nv_no_incoherent_mappings(void) -+{ -+ /* XXX Fix me! (no_incoherent_mappings) */ -+ return 0; -+} -+ -+void* nv_find_agp_kernel_mapping( -+ nv_state_t *nv, -+ ULONG address -+) -+{ -+ /* XXX Implement me? (kmap lookup) */ -+ return NULL; -+} -+ -+ -+void nv_lock_rm(nv_state_t *nv) -+{ -+ /* -+ * While SMP configurations are handled with a global kernel lock and -+ * in such a way that only one of the CPUs is executing a process and -+ * servicing interrupts at any point in time, it is possible that the -+ * interrupt handlers (th/bh) may interfere with critical code. -+ * -+ * This "lock" thus disables interrupts for the duration of this code -+ * segment's execution. -+ */ -+ crit_enter(); -+} -+ -+void nv_unlock_rm(nv_state_t *nv) -+{ -+ /* -+ * Restore the interrupt mask upon existing the critical code segment -+ * and thus allow interrupt handlers to execute again. -+ */ -+ crit_exit(); -+} -+ -+ -+void nv_lock_api(nv_state_t *nv) -+{ -+ /* -+ * Since it is entirely possible that we involuntarily go to sleep at -+ * certain points in time, we make sure that we execute only a single -+ * of our system calls at a time. -+ */ -+ struct nvidia_softc *sc = nv->os_state; -+ lockmgr(&sc->api_lock, LK_EXCLUSIVE, 0, CURTHREAD); -+} -+ -+void nv_unlock_api(nv_state_t *nv) -+{ -+ /* -+ * Release the API lock and allow a process sleeping on it to execute -+ * its system call. -+ */ -+ struct nvidia_softc *sc = nv->os_state; -+ lockmgr(&sc->api_lock, LK_RELEASE, 0, CURTHREAD); -+} -+ -+ -+void nv_post_event( -+ nv_state_t *nv, -+ nv_event_t *event, -+ U032 hObject, -+ U032 index -+) -+{ -+ struct nvidia_softc *sc; -+ nv_os_event_t *et; -+ -+ if (!(et = malloc(sizeof(nv_os_event_t), M_NVIDIA, M_ZERO))) -+ return; -+ -+ et->event = *event; -+ et->event.hObject = hObject; -+ et->event.index = index; -+ -+ nv_lock_rm(nv); -+ -+ sc = nv->os_state; -+ STAILQ_INSERT_TAIL(&sc->event_queue, et, queue); -+ -+ nv_unlock_rm(nv); -+ -+/* printf("NVRM: nv_post_event()\n"); -+ printf("NVRM: hParent: 0x%08x\n", et->event.hParent); -+ printf("NVRM: hObject: 0x%08x\n", et->event.hObject); */ -+ -+ /* XXX Fix me? (os events) */ -+ selwakeup(&sc->rsel); -+} -+ -+S032 nv_get_event( -+ nv_state_t *nv, -+ void *file, -+ nv_event_t *event, -+ U032 *pending -+) -+{ -+ struct nvidia_softc *sc = nv->os_state; -+ nv_os_event_t *et; -+ -+ nv_lock_rm(nv); -+ -+ if (!(et = STAILQ_FIRST(&sc->event_queue))) { -+ nv_unlock_rm(nv); -+ return RM_ERROR; /* RM polling? */ -+ } -+ -+ *event = et->event; -+ -+ STAILQ_REMOVE_HEAD(&sc->event_queue, queue); -+ free(et, M_NVIDIA); -+ -+/* printf("NVRM: nv_get_event(), %d\n", *pending); -+ printf("NVRM: hParent: 0x%08x\n", event->hParent); -+ printf("NVRM: hObject: 0x%08x\n", event->hObject); */ -+ -+ /* XXX: Fix me? (os events) */ -+ *pending = !(STAILQ_EMPTY(&sc->event_queue)); -+ -+ nv_unlock_rm(nv); -+ -+ return RM_OK; -+} -+ -+void* nv_find_alloc( -+ nv_state_t *nv, -+ vm_offset_t address -+) -+{ -+ nv_alloc_t *at; -+ struct nvidia_softc *sc = nv->os_state; -+ -+ SLIST_FOREACH(at, &sc->alloc_list, list) { -+ /* -+ * XXX Match an incoming address to a known allocation. We -+ * should use type flags here. -+ */ -+ if (at->address == address) -+ return (void *) at; -+ } -+ -+ return NULL; -+} -+ -+void* nv_find_alloc_obj( -+ nv_state_t *nv, -+ vm_offset_t object -+) -+{ -+ nv_alloc_t *at; -+ struct nvidia_softc *sc = nv->os_state; -+ -+ SLIST_FOREACH(at, &sc->alloc_list, list) { -+ /* -+ * XXX Match the incoming object to a known allocation. We -+ * should use type flags here. -+ */ -+ if (at->object == (vm_object_t) object) -+ return (void *) at; -+ } -+ -+ return NULL; -+} -+ -+void* nv_find_nv_mapping( -+ nv_state_t *nv, -+ ULONG address -+) -+{ -+ nv_alloc_t *at; -+ struct nvidia_softc *sc = nv->os_state; -+ vm_offset_t offset, linear; -+ -+ offset = (vm_offset_t) address & PAGE_MASK; -+ address &= ~PAGE_MASK; -+ -+ SLIST_FOREACH(at, &sc->alloc_list, list) { -+ /* -+ * XXX Match an incoming address to a known allocation. We -+ * should use type flags here. -+ */ -+ if (at->address == 0) -+ continue; -+ linear = at->address; -+ do { -+ if (vtophys(linear) == (vm_offset_t) address) -+ return (void *)(linear + offset); -+ linear += PAGE_SIZE; -+ } while (linear < (at->address + at->size)); -+ } -+ -+ return NULL; -+} -+ -+ULONG nv_find_dma_mapping( -+ nv_state_t *nv, -+ ULONG address -+) -+{ -+ /* XXX Fix me? (x86 only, amd64 dma) */ -+ return address; -+} -+ -+S032 nv_agp_translate_address( -+ nv_state_t *nv, -+ void *base, -+ U032 index, -+ U032 *address -+) -+{ -+ nv_alloc_t *at; -+ struct nvidia_softc *sc = nv->os_state; -+ -+ vm_page_t m; -+ -+ SLIST_FOREACH(at, &sc->alloc_list, list) { -+ /* -+ * The purpose of this function is to extract the actual physical -+ * addresses of each page in the allocation with the base address -+ * passed by the caller. -+ */ -+ if (at->object == (vm_object_t) base && -+ at->size > index * PAGE_SIZE) { -+ VM_OBJECT_LOCK(at->object); -+ m = vm_page_lookup(at->object, index); -+ *address = VM_PAGE_TO_PHYS(m); -+ VM_OBJECT_UNLOCK(at->object); -+ return 0; -+ } -+ } -+ -+ return -1; -+} -+ -+S032 nv_alloc_contig_pages( -+ nv_state_t *nv, -+ void **address, -+ U032 count -+) -+{ -+ nv_alloc_t *at; -+ struct nvidia_softc *sc = nv->os_state; -+ U032 size = count * PAGE_SIZE; -+ -+ if (os_alloc_contig_pages(address, size) != RM_OK) -+ return -ENOMEM; -+ -+ at = malloc(sizeof(nv_alloc_t), M_NVIDIA, M_WAITOK | M_ZERO); -+ if (!at) { -+ os_free_contig_pages(*address, size); -+ return -ENOMEM; -+ } -+ -+ at->object = 0; -+ at->size = size; -+ at->address = (vm_offset_t) *address; -+ at->offset = ~0; -+ -+ SLIST_INSERT_HEAD(&sc->alloc_list, at, list); -+ -+ return 0; -+} -+ -+S032 nv_free_contig_pages( -+ nv_state_t *nv, -+ void *address -+) -+{ -+ nv_alloc_t *at; -+ struct nvidia_softc *sc = nv->os_state; -+ U032 size; -+ -+ at = nv_find_alloc(nv, (vm_offset_t) address); -+ if (!at) { -+ os_dbg_breakpoint(); -+ return -EINVAL; -+ } -+ -+ size = at->size; -+ SLIST_REMOVE(&sc->alloc_list, at, nv_alloc, list); -+ -+ free(at, M_NVIDIA); -+ os_free_contig_pages(address, size); -+ -+ return 0; -+} -+ -+S032 nv_alloc_system_pages( -+ nv_state_t *nv, -+ void **address, -+ U032 count -+) -+{ -+ nv_alloc_t *at; -+ struct nvidia_softc *sc = nv->os_state; -+ -+ void *vm; -+ u_int32_t i, size = count * PAGE_SIZE; -+ -+ at = malloc(sizeof(nv_alloc_t), M_NVIDIA, M_WAITOK | M_ZERO); -+ if (!at) { -+ return -ENOMEM; -+ } -+ -+ vm = malloc(size, M_NVIDIA, M_WAITOK | M_ZERO); -+ if (!vm) { -+ free(at, M_NVIDIA); -+ return -ENOMEM; -+ } -+ -+ at->pte = malloc(sizeof(vm_offset_t) * count, M_NVIDIA, M_WAITOK); -+ if (!at->pte) { -+ free(at, M_NVIDIA); -+ free(vm, M_NVIDIA); -+ return -ENOMEM; -+ } -+ -+ for (i = 0; i < count; i++) { -+ at->pte[i] = vtophys((vm_offset_t) vm + (i * PAGE_SIZE)); -+ vm_page_lock_queues(); -+ vm_page_wire(PHYS_TO_VM_PAGE(at->pte[i])); -+ vm_page_unlock_queues(); -+ } -+ -+ at->object = 0; -+ at->size = size; -+ at->address = (vm_offset_t) vm; -+ at->offset = ~0; -+ -+ SLIST_INSERT_HEAD(&sc->alloc_list, at, list); -+ *address = (void *) at->address; -+ -+ return 0; -+} -+ -+S032 nv_free_system_pages( -+ nv_state_t *nv, -+ void *address -+) -+{ -+ nv_alloc_t *at; -+ struct nvidia_softc *sc = nv->os_state; -+ -+ vm_offset_t pa; -+ u_int32_t i, count; -+ -+ at = nv_find_alloc(nv, (vm_offset_t) address); -+ if (!at) { -+ os_dbg_breakpoint(); -+ return -EINVAL; -+ } -+ -+ count = at->size / PAGE_SIZE; -+ SLIST_REMOVE(&sc->alloc_list, at, nv_alloc, list); -+ -+ for (i = 0; i < count; i++) { -+ pa = vtophys(at->address + (i * PAGE_SIZE)); -+ vm_page_lock_queues(); -+ vm_page_unwire(PHYS_TO_VM_PAGE(pa), 0); -+ vm_page_unlock_queues(); -+ } -+ -+ free(at->pte, M_NVIDIA); -+ free(at, M_NVIDIA); -+ free(address, M_NVIDIA); -+ -+ return 0; -+} -+ -+ -+S032 nv_alloc_vm_object( -+ nv_state_t *nv, -+ void **address, -+ U032 count -+) -+{ -+ nv_alloc_t *at; -+ struct nvidia_softc *sc = nv->os_state; -+ -+ u_int32_t i, j; -+ vm_page_t m; -+ vm_object_t object; -+ -+ at = malloc(sizeof(nv_alloc_t), M_NVIDIA, M_WAITOK | M_ZERO); -+ if (!at) { -+ return -ENOMEM; -+ } -+ -+ object = vm_object_allocate(OBJT_DEFAULT, count); -+ -+ for (i = 0; i < count; i++) { -+ /* -+ * Find the individual pages belonging to the allocation from the -+ * VM object; since this is the first time they're accessed, they -+ * will be allocated. -+ */ -+ -+#if __FreeBSD_version >= 500000 -+ /* -+ * Request that this range of pages be wired down to prevent them -+ * from being paged out. This is done below for FreeBSD 4. -+ */ -+ VM_OBJECT_LOCK(object); -+ m = vm_page_grab(object, i, VM_ALLOC_NORMAL | VM_ALLOC_WIRED); -+ VM_OBJECT_UNLOCK(object); -+#else -+ m = vm_page_grab(object, i, VM_ALLOC_NORMAL); -+#endif -+ if (!m) { -+ VM_OBJECT_LOCK(object); -+ for (j = 0; j < i; j++) { -+ m = vm_page_lookup(object, j); -+ vm_page_lock_queues(); -+ vm_page_unwire(m, 0); -+ vm_page_unlock_queues(); -+ } -+ VM_OBJECT_UNLOCK(object); -+ return -ENOMEM; -+ } -+ -+#if __FreeBSD_version < 500000 -+ vm_page_wire(m); -+#endif -+ vm_page_lock_queues(); -+ vm_page_wakeup(m); -+ vm_page_unlock_queues(); -+ } -+ -+ at->object = object; -+ at->offset = ~0; -+ at->size = ptoa(count); -+ at->address = 0; -+ -+ SLIST_INSERT_HEAD(&sc->alloc_list, at, list); -+ *address = (void *) at->object; -+ -+ return 0; -+} -+ -+S032 nv_free_vm_object( -+ nv_state_t *nv, -+ void *address -+) -+{ -+ nv_alloc_t *at; -+ struct nvidia_softc *sc = nv->os_state; -+ -+ vm_page_t m; -+ u_int32_t i, count; -+ -+ at = nv_find_alloc_obj(nv, (vm_offset_t) address); -+ if (!at) { -+ os_dbg_breakpoint(); -+ return -EINVAL; -+ } -+ -+ count = at->size / PAGE_SIZE; -+ SLIST_REMOVE(&sc->alloc_list, at, nv_alloc, list); -+ -+ VM_OBJECT_LOCK(at->object); -+ for (i = 0; i < count; i++) { -+ /* -+ * Release "one wiring" of this page; this may reenable paging as -+ * a result, depending on the total number of "wirings". -+ */ -+ m = vm_page_lookup(at->object, i); -+ vm_page_lock_queues(); -+ vm_page_unwire(m, 0); -+ vm_page_unlock_queues(); -+ } -+ VM_OBJECT_UNLOCK(at->object); -+ -+ vm_object_deallocate(at->object); -+ free(at, M_NVIDIA); -+ -+ return 0; -+} -+ -+ -+#ifdef NV_SUPPORT_OS_AGP -+S032 nv_alloc_agp_pages( -+ nv_state_t *nv, -+ void **address, -+ U032 count, -+ U032 offset, -+ void **private -+) -+{ -+ void *handle; -+ struct nvidia_softc *sc = nv->os_state; -+ -+ handle = agp_alloc_memory(sc->agp_dev, 0, count << PAGE_SHIFT); -+ if (!handle) { -+ /* -+ * This is very unlikely to happen, the system's memory resources -+ * would have to be nearly exhausted. -+ */ -+ return -ENOMEM; -+ } -+ -+ if (agp_bind_memory(sc->agp_dev, handle, offset) != 0) { -+ /* -+ * This shouldn't happen, we claimed the AGP backend and are thus -+ * using it exclusively; the resource manager manages AGP offsets -+ * internally, we wouldn't have been called had we run out of AGP -+ * aperture space. -+ */ -+ os_dbg_breakpoint(); -+ -+ agp_free_memory(sc->agp_dev, handle); -+ return -ENOMEM; -+ } -+ -+ *private = handle; -+ return 0; -+} -+ -+S032 nv_free_agp_pages( -+ nv_state_t *nv, -+ void **address, -+ U032 count, -+ void *handle -+) -+{ -+ struct nvidia_softc *sc = nv->os_state; -+ -+ if (agp_unbind_memory(sc->agp_dev, handle) != 0) { -+ /* -+ * This is the only place where previously bound AGP memory would -+ * be freed. If we fail to unbind this memory now, something very -+ * wrong must have happened. -+ */ -+ os_dbg_breakpoint(); -+ } -+ -+ agp_free_memory(sc->agp_dev, handle); -+ return 0; -+} -+#endif /* NV_SUPPORT_OS_AGP */ -+ -+ -+S032 nv_alloc_pages( -+ nv_state_t *nv, -+ void **address, -+ U032 count, -+ U032 alloc_type_agp, -+ U032 alloc_type_contiguous, -+ U032 cache, -+ U032 alloc_type_kernel, -+ U032 class, -+ void **private -+) -+{ -+ /* XXX Fix me! (cache types) */ -+ U032 alloc_type_cached = (cache != NV_MEMORY_UNCACHED); -+ -+ if (alloc_type_agp) { -+#ifdef NV_SUPPORT_OS_AGP -+ U032 offset; -+ -+ if ((nv->agp_config & NVOS_AGP_CONFIG_OSAGP) == 0) -+ return -EINVAL; -+ -+ if (rm_alloc_agp_bitmap(nv, count, &offset) != RM_OK) { -+ /* -+ * We've run out of AGP aperture space, the requestor will be -+ * forced to fall back to general system memory. -+ */ -+ return -ENOMEM; -+ } -+ -+ if (nv_alloc_agp_pages(nv, address, count, offset << PAGE_SHIFT, -+ private) != 0) { -+ /* -+ * The AGP aperture is managed internally by core resman, the -+ * offset passed to us should work; thus, this shouldn't fail -+ * unless the system memory is exhausted. -+ */ -+ rm_free_agp_bitmap(nv, offset, count); -+ return -ENOMEM; -+ } -+ -+ *address = (void *)(nv->agp.address + (offset << PAGE_SHIFT)); -+ return 0; -+#else -+ nv_alloc_t *at; -+ -+ if ((nv->agp_config & NVOS_AGP_CONFIG_NVAGP) == 0) -+ return -EINVAL; -+ -+ if (nv_alloc_vm_object(nv, address, count) != 0) { -+ /* -+ * Hopefully, this error condition will be much more unlikely -+ * to occur than failure to allocate the same number of pages -+ * with nv_alloc_system_pages. -+ */ -+ return -ENOMEM; -+ } -+ -+ at = nv_find_alloc_obj(nv, (vm_offset_t) *address); -+ if (!at) { -+ os_dbg_breakpoint(); -+ return -ENOMEM; -+ } -+ -+ if (rm_alloc_agp_pages(nv, address, count, class, private, -+ &at->offset) != RM_OK) { -+ /* -+ * In theory, this should only fail if we run out of aperture -+ * space (which is not unlikely). -+ */ -+ nv_free_vm_object(nv, *address); -+ return -ENOMEM; -+ } -+ -+ *address = (void *)(nv->agp.address + (at->offset << PAGE_SHIFT)); -+ return 0; -+#endif /* NV_SUPPORT_OS_AGP */ -+ } else { -+ /* -+ * Save the allocation parameters for use in nv_free_pages, where -+ * we won't have access to all of them (sigh). -+ */ -+ nv_alloc_private_t *ap; -+ vm_offset_t vm; -+ -+ /* XXX Fix me! (PAT) */ -+ if (cache == NV_MEMORY_WRITECOMBINED) -+ return -ENOMEM; -+ -+ ap = malloc(sizeof(nv_alloc_private_t), M_NVIDIA, M_WAITOK | M_ZERO); -+ if (!ap) { -+ return -ENOMEM; -+ } -+ *private = (void *) ap; -+ -+ ap->count = count; -+ ap->alloc_type_contiguous = alloc_type_contiguous; -+ ap->alloc_type_cached = alloc_type_cached; -+ ap->alloc_type_kernel = alloc_type_kernel; -+ ap->class = class; -+ -+ if (alloc_type_kernel && -+ !alloc_type_contiguous && alloc_type_cached) { -+ /* -+ * Obtain general system memory for the resource mananger, it -+ * doesn't need to be contiguous. -+ */ -+ if (nv_alloc_system_pages(nv, address, count)) -+ goto failed; -+ -+ } else if (alloc_type_contiguous || -+ (alloc_type_kernel && !alloc_type_cached)) { -+ /* -+ * Make sure the pages are contiguous in physical memory; the -+ * memory will not be used for DMA push buffers, the returned -+ * linear mapping is expected to be usable as-is. -+ */ -+ if (nv_alloc_contig_pages(nv, address, count)) -+ goto failed; -+ -+ /* XXX Fix me! (uc kernel) */ -+ if (alloc_type_kernel && !alloc_type_cached) -+ /* goto failed */; -+ -+ } else if (!alloc_type_kernel) { -+ /* -+ * Allocate general system memory for DMA push buffers. These -+ * pages may be non-contiguous; the individual addresses must -+ * be retrievable from the mmap(2) implementation. -+ */ -+ if (nv_alloc_system_pages(nv, address, count)) -+ goto failed; -+ -+ vm = ((vm_offset_t) *address) - VM_MIN_KERNEL_ADDRESS; -+ *address = (void *) vm; -+ } -+ -+ return 0; -+ -+failed: -+ free(*private, M_NVIDIA); -+ return -ENOMEM; -+ } -+} -+ -+S032 nv_free_pages( -+ nv_state_t *nv, -+ void **address, -+ U032 count, -+ U032 alloc_type_agp, -+ void *private -+) -+{ -+ U032 offset; -+ offset = ((U032) *address - nv->agp.address) >> PAGE_SHIFT; -+ -+ if (alloc_type_agp) { -+#ifdef NV_SUPPORT_OS_AGP -+ if ((nv->agp_config & NVOS_AGP_CONFIG_OSAGP) == 0) -+ return -EINVAL; -+ -+ if (nv_free_agp_pages(nv, address, count, private) != 0) { -+ /* -+ * The following is a sanity check, this mustn't ever fail in -+ * in real-world scenario. -+ */ -+ os_dbg_breakpoint(); -+ return -EINVAL; -+ } -+ -+ rm_free_agp_bitmap(nv, offset, count); -+#else -+ nv_alloc_t *at; -+ struct nvidia_softc *sc = nv->os_state; -+ -+ if ((nv->agp_config & NVOS_AGP_CONFIG_NVAGP) == 0) -+ return -EINVAL; -+ -+ if (rm_free_agp_pages(nv, address, private) != RM_OK) { -+ /* -+ * Don't free the underlying system memory unless the request -+ * to free the RM AGP resources completes successfully, which -+ * should never actually fail. -+ */ -+ os_dbg_breakpoint(); -+ return -EINVAL; -+ } -+ -+ SLIST_FOREACH(at, &sc->alloc_list, list) { -+ if (at->offset == offset) { -+ nv_free_vm_object(nv, (void *)at->object); -+ break; -+ } -+ } -+#endif /* NV_SUPPORT_OS_AGP */ -+ -+ return 0; -+ } else { -+ nv_alloc_private_t *ap; -+ vm_offset_t vm; -+ -+ ap = (nv_alloc_private_t *) private; -+ if (!ap) { -+ os_dbg_breakpoint(); -+ return -EINVAL; -+ } -+ -+ if (ap->alloc_type_kernel && -+ !ap->alloc_type_contiguous && ap->alloc_type_cached) { -+ /* -+ * Generic system memory used by the resource manager; almost -+ * identical to the user memory case. -+ */ -+ if (nv_free_system_pages(nv, *address)) -+ return -EINVAL; -+ -+ } else if (ap->alloc_type_contiguous || -+ (ap->alloc_type_kernel && !ap->alloc_type_cached)) { -+ /* -+ * Free contigous system memory; this resource is rarely used -+ * and hence managed globally. -+ */ -+ if (nv_free_contig_pages(nv, *address)) -+ return -EINVAL; -+ -+ /* XXX Fix me! (uc kernel) */ -+ if (ap->alloc_type_kernel && !ap->alloc_type_cached) -+ /* return -EINVAL */; -+ -+ } else if (!ap->alloc_type_kernel) { -+ /* -+ * XXX Generic system memory used for DMA push buffers. There -+ * are munmap(2) considerations in this case on Linux, are we -+ * really safe here? -+ */ -+ vm = (vm_offset_t) *address; -+ *address = (void *)(vm + VM_MIN_KERNEL_ADDRESS); -+ -+ if (nv_free_system_pages(nv, *address)) -+ return -EINVAL; -+ } -+ -+ free(ap, M_NVIDIA); -+ return 0; -+ } -+ -+ return -EINVAL; -+} -+ -+ULONG nv_get_kern_phys_address(ULONG address) -+{ -+ vm_offset_t va = (vm_offset_t) address; -+ -+ if (va < VM_MIN_KERNEL_ADDRESS) { -+ os_dbg_breakpoint(); -+ return 0; -+ } -+ -+ return vtophys(va); -+} -+ -+ULONG nv_get_user_phys_address(ULONG address) -+{ -+ struct vmspace *vm; -+ vm_offset_t va = (vm_offset_t) address; -+ -+ if (va >= VM_MIN_KERNEL_ADDRESS) { -+ os_dbg_breakpoint(); -+ return 0; -+ } -+ -+ if (vm_fault_quick((caddr_t) va, VM_PROT_WRITE)) -+ return 0; -+ -+ vm = curproc->p_vmspace; -+ return pmap_extract(vmspace_pmap(vm), va); -+} -+ -+ -+int nvidia_mmap_dev( -+ struct nvidia_softc *sc, -+ vm_offset_t offset, -+ vm_offset_t *physical -+) -+{ -+ nv_alloc_t *at; -+ nv_state_t *nv = sc->nv_state; -+ -+ NV_PCI_ENABLE_DEVICE(nv); -+ -+ /* -+ * Offsets that fall into the frame buffer, registry or AGP apertures -+ * are physical addresses and mapped into user-space directly. We can -+ * only do some basic sanity checking here. -+ */ -+ if (IS_FB_OFFSET(nv, offset, PAGE_SIZE)) { -+ *physical = offset; -+ return 0; -+ } -+ -+ if (IS_REG_OFFSET(nv, offset, PAGE_SIZE)) { -+ *physical = offset; -+ return 0; -+ } -+ -+ if (IS_AGP_OFFSET(nv, offset, PAGE_SIZE)) { -+ *physical = offset; -+ return 0; -+ } -+ -+ offset += VM_MIN_KERNEL_ADDRESS; -+ -+ /* -+ * If the offset does not fall into any of the relevant apertures, we -+ * must assume that it corresponds to a memory allocation. Offsets of -+ * this kind are kernel virtual addresses that fall within one of the -+ * allocated ranges, provided they are valid. These logical addresses -+ * are translated into physical addresses and then mapped. -+ */ -+ SLIST_FOREACH(at, &sc->alloc_list, list) { -+ if (offset >= at->address && -+ offset < at->address + at->size) { -+ *physical = vtophys(offset); -+ return 0; -+ } -+ } -+ -+ return -1; -+} -+ -+ -+int nv_int10h_call( -+ nv_state_t * nv, -+ U032 *eax, -+ U032 *ebx, -+ U032 *ecx, -+ U032 *edx, -+ void *buffer -+) -+{ -+#ifdef NV_USE_OS_VM86_INT10CALL -+ struct vm86frame vmf; -+ -+ vmf.vmf_eax = *eax; -+ vmf.vmf_ebx = *ebx; -+ vmf.vmf_ecx = *ecx; -+ vmf.vmf_edx = *edx; -+ -+ if (vm86_intcall(0x10, &vmf) == 0) { -+ *eax = vmf.vmf_eax; -+ *ebx = vmf.vmf_ebx; -+ *ecx = vmf.vmf_ecx; -+ *edx = vmf.vmf_edx; -+ return RM_OK; -+ } -+#endif /* NV_USE_OS_VM86_INT10CALL */ -+ -+ return RM_ERROR; /* XXX Fixm me? (vm86_intcall) */ -+} -+ -+void nvidia_rc_timer(void *data) -+{ -+ nv_state_t *nv = (nv_state_t *) data; -+ struct nvidia_softc *sc; -+ -+ NV_PCI_ENABLE_DEVICE(nv); +@@ -1608,7 +1594,7 @@ + rm_run_rc_callback(nv); + + sc = nv->os_state; +- sc->timer_ch = timeout(nvidia_rc_timer, (void *) nv, hz); ++ callout_reset(&sc->timer_ch, hz, nvidia_rc_timer, nv); + } + + int nv_start_rc_timer( +@@ -1620,7 +1606,8 @@ + if (nv->rc_timer_enabled != 0) + return -EIO; + +- sc->timer_ch = timeout(nvidia_rc_timer, (void *) nv, hz); ++ callout_reset(&sc->timer_ch, hz, nvidia_rc_timer, nv); + -+ /* -+ * We need this timer to trigger again one second from -+ * now, reset the timeout. -+ */ -+ rm_run_rc_callback(nv); -+ -+ sc = nv->os_state; -+ sc->timer_ch = timeout(nvidia_rc_timer, (void *) nv, hz); -+} -+ -+int nv_start_rc_timer( -+ nv_state_t *nv -+) -+{ -+ struct nvidia_softc *sc = nv->os_state; -+ -+ if (nv->rc_timer_enabled != 0) -+ return -EIO; -+ -+ sc->timer_ch = timeout(nvidia_rc_timer, (void *) nv, hz); -+ nv->rc_timer_enabled = 1; -+ -+ return 0; -+} -+ -+int nv_stop_rc_timer( -+ nv_state_t *nv -+) -+{ -+ struct nvidia_softc *sc = nv->os_state; -+ -+ if (nv->rc_timer_enabled == 0) -+ return -EIO; -+ -+ untimeout(nvidia_rc_timer, (void *) nv, sc->timer_ch); -+ nv->rc_timer_enabled = 0; -+ -+ return 0; -+} -+ -diff -urN ../../NVIDIA-FreeBSD-x86-1.0-6113/src/nvidia_sysctl.c ./src/nvidia_sysctl.c ---- ../../NVIDIA-FreeBSD-x86-1.0-6113/src/nvidia_sysctl.c 2004-08-03 01:27:38.000000000 +0200 -+++ ./src/nvidia_sysctl.c 2004-08-04 21:26:57.000000000 +0200 + nv->rc_timer_enabled = 1; + + return 0; +@@ -1635,7 +1622,7 @@ + if (nv->rc_timer_enabled == 0) + return -EIO; + +- untimeout(nvidia_rc_timer, (void *) nv, sc->timer_ch); ++ callout_stop(&sc->timer_ch); + nv->rc_timer_enabled = 0; + + return 0; +diff -urN ./src/nvidia_sysctl.c ../../nvidia-patched/src/nvidia_sysctl.c +--- ./src/nvidia_sysctl.c 2004-08-03 01:27:38.000000000 +0200 ++++ ../../nvidia-patched/src/nvidia_sysctl.c 2004-09-26 14:13:39.000000000 +0200 @@ -11,7 +11,7 @@ #include "nv-misc.h" #include "os-interface.h"