import mesa-drm git from version 85b9f737db0d2a845e4d7e2bbf9ad12ff9e2227c.

This commit is contained in:
mrg 2009-06-19 03:22:23 +00:00
parent bf40ad8b96
commit d7792ba7fe
99 changed files with 43840 additions and 4906 deletions

View File

@ -25,6 +25,6 @@ AUTOMAKE_OPTIONS = foreign
SUBDIRS = libdrm shared-core tests
pkgconfigdir = @pkgconfigdir@
pkgconfig_DATA = libdrm.pc
pkgconfig_DATA = libdrm.pc libdrm_intel.pc
EXTRA_DIST = libdrm.pc.in
EXTRA_DIST = libdrm.pc.in libdrm_intel.pc.in

View File

@ -3,8 +3,11 @@ DRM README file
There are two main parts to this package: the DRM client library/interface
(libdrm.so) and kernel/hardware-specific device modules (such as i915.ko).
(libdrm.so) and kernel/hardware-specific device modules (such as radeon.ko).
The kernel device modules are not shipped with libdrm releases and should only
be built from the git tree by developers and bleeding-edge testers of
non-Intel hardware. The Intel kernel modules are developed in the Linux
kernel tree.
Compiling
@ -19,7 +22,7 @@ Then,
make install
To build the device-specific kernel modules:
To build the device-specific kernel modules from the git tree:
cd linux-core/
make

View File

@ -62,7 +62,7 @@ int drm_ctxbitmap_next(struct drm_device *dev)
return -1;
DRM_LOCK();
bit = find_first_zero_bit( dev->ctx_bitmap, DRM_MAX_CTXBITMAP );
bit = find_first_zero_bit(dev->ctx_bitmap, DRM_MAX_CTXBITMAP);
if (bit >= DRM_MAX_CTXBITMAP) {
DRM_UNLOCK();
return -1;
@ -77,7 +77,7 @@ int drm_ctxbitmap_next(struct drm_device *dev)
ctx_sareas = realloc(dev->context_sareas,
dev->max_context * sizeof(*dev->context_sareas),
M_DRM, M_NOWAIT);
DRM_MEM_SAREA, M_NOWAIT);
if (ctx_sareas == NULL) {
clear_bit(bit, dev->ctx_bitmap);
DRM_UNLOCK();
@ -88,7 +88,8 @@ int drm_ctxbitmap_next(struct drm_device *dev)
} else {
/* max_context == 1 at this point */
dev->context_sareas = malloc(dev->max_context *
sizeof(*dev->context_sareas), M_DRM, M_NOWAIT);
sizeof(*dev->context_sareas), DRM_MEM_SAREA,
M_NOWAIT);
if (dev->context_sareas == NULL) {
clear_bit(bit, dev->ctx_bitmap);
DRM_UNLOCK();
@ -107,8 +108,9 @@ int drm_ctxbitmap_init(struct drm_device *dev)
int temp;
DRM_LOCK();
dev->ctx_bitmap = malloc(PAGE_SIZE, M_DRM, M_NOWAIT | M_ZERO);
if ( dev->ctx_bitmap == NULL ) {
dev->ctx_bitmap = malloc(PAGE_SIZE, DRM_MEM_CTXBITMAP,
M_NOWAIT | M_ZERO);
if (dev->ctx_bitmap == NULL) {
DRM_UNLOCK();
return ENOMEM;
}
@ -116,9 +118,9 @@ int drm_ctxbitmap_init(struct drm_device *dev)
dev->max_context = -1;
DRM_UNLOCK();
for ( i = 0 ; i < DRM_RESERVED_CONTEXTS ; i++ ) {
for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) {
temp = drm_ctxbitmap_next(dev);
DRM_DEBUG( "drm_ctxbitmap_init : %d\n", temp );
DRM_DEBUG("drm_ctxbitmap_init : %d\n", temp);
}
return 0;
@ -128,8 +130,8 @@ void drm_ctxbitmap_cleanup(struct drm_device *dev)
{
DRM_LOCK();
if (dev->context_sareas != NULL)
free(dev->context_sareas, M_DRM);
free(dev->ctx_bitmap, M_DRM);
free(dev->context_sareas, DRM_MEM_SAREA);
free(dev->ctx_bitmap, DRM_MEM_CTXBITMAP);
DRM_UNLOCK();
}
@ -140,7 +142,7 @@ void drm_ctxbitmap_cleanup(struct drm_device *dev)
int drm_getsareactx(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
drm_ctx_priv_map_t *request = data;
struct drm_ctx_priv_map *request = data;
drm_local_map_t *map;
DRM_LOCK();
@ -161,7 +163,7 @@ int drm_getsareactx(struct drm_device *dev, void *data,
int drm_setsareactx(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
drm_ctx_priv_map_t *request = data;
struct drm_ctx_priv_map *request = data;
drm_local_map_t *map = NULL;
DRM_LOCK();
@ -188,49 +190,49 @@ bad:
int drm_context_switch(struct drm_device *dev, int old, int new)
{
if ( test_and_set_bit( 0, &dev->context_flag ) ) {
DRM_ERROR( "Reentering -- FIXME\n" );
return EBUSY;
}
if (test_and_set_bit(0, &dev->context_flag)) {
DRM_ERROR("Reentering -- FIXME\n");
return EBUSY;
}
DRM_DEBUG( "Context switch from %d to %d\n", old, new );
DRM_DEBUG("Context switch from %d to %d\n", old, new);
if ( new == dev->last_context ) {
clear_bit( 0, &dev->context_flag );
return 0;
}
if (new == dev->last_context) {
clear_bit(0, &dev->context_flag);
return 0;
}
return 0;
return 0;
}
int drm_context_switch_complete(struct drm_device *dev, int new)
{
dev->last_context = new; /* PRE/POST: This is the _only_ writer. */
dev->last_context = new; /* PRE/POST: This is the _only_ writer. */
if ( !_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) ) {
DRM_ERROR( "Lock isn't held after context switch\n" );
}
if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
DRM_ERROR("Lock isn't held after context switch\n");
}
/* If a context switch is ever initiated
when the kernel holds the lock, release
that lock here. */
clear_bit( 0, &dev->context_flag );
/* If a context switch is ever initiated
when the kernel holds the lock, release
that lock here. */
clear_bit(0, &dev->context_flag);
return 0;
return 0;
}
int drm_resctx(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
drm_ctx_res_t *res = data;
drm_ctx_t ctx;
struct drm_ctx_res *res = data;
struct drm_ctx ctx;
int i;
if ( res->count >= DRM_RESERVED_CONTEXTS ) {
if (res->count >= DRM_RESERVED_CONTEXTS) {
bzero(&ctx, sizeof(ctx));
for ( i = 0 ; i < DRM_RESERVED_CONTEXTS ; i++ ) {
for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) {
ctx.handle = i;
if ( DRM_COPY_TO_USER( &res->contexts[i],
&ctx, sizeof(ctx) ) )
if (DRM_COPY_TO_USER(&res->contexts[i],
&ctx, sizeof(ctx)))
return EFAULT;
}
}
@ -241,23 +243,23 @@ int drm_resctx(struct drm_device *dev, void *data, struct drm_file *file_priv)
int drm_addctx(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
drm_ctx_t *ctx = data;
struct drm_ctx *ctx = data;
ctx->handle = drm_ctxbitmap_next(dev);
if ( ctx->handle == DRM_KERNEL_CONTEXT ) {
/* Skip kernel's context and get a new one. */
if (ctx->handle == DRM_KERNEL_CONTEXT) {
/* Skip kernel's context and get a new one. */
ctx->handle = drm_ctxbitmap_next(dev);
}
DRM_DEBUG( "%d\n", ctx->handle );
if ( ctx->handle == -1 ) {
DRM_DEBUG( "Not enough free contexts.\n" );
/* Should this return -EBUSY instead? */
DRM_DEBUG("%d\n", ctx->handle);
if (ctx->handle == -1) {
DRM_DEBUG("Not enough free contexts.\n");
/* Should this return -EBUSY instead? */
return ENOMEM;
}
if (dev->driver.context_ctor && ctx->handle != DRM_KERNEL_CONTEXT) {
if (dev->driver->context_ctor && ctx->handle != DRM_KERNEL_CONTEXT) {
DRM_LOCK();
dev->driver.context_ctor(dev, ctx->handle);
dev->driver->context_ctor(dev, ctx->handle);
DRM_UNLOCK();
}
@ -272,7 +274,7 @@ int drm_modctx(struct drm_device *dev, void *data, struct drm_file *file_priv)
int drm_getctx(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
drm_ctx_t *ctx = data;
struct drm_ctx *ctx = data;
/* This is 0, because we don't handle any context flags */
ctx->flags = 0;
@ -283,17 +285,17 @@ int drm_getctx(struct drm_device *dev, void *data, struct drm_file *file_priv)
int drm_switchctx(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
drm_ctx_t *ctx = data;
struct drm_ctx *ctx = data;
DRM_DEBUG( "%d\n", ctx->handle );
DRM_DEBUG("%d\n", ctx->handle);
return drm_context_switch(dev, dev->last_context, ctx->handle);
}
int drm_newctx(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
drm_ctx_t *ctx = data;
struct drm_ctx *ctx = data;
DRM_DEBUG( "%d\n", ctx->handle );
DRM_DEBUG("%d\n", ctx->handle);
drm_context_switch_complete(dev, ctx->handle);
return 0;
@ -301,13 +303,13 @@ int drm_newctx(struct drm_device *dev, void *data, struct drm_file *file_priv)
int drm_rmctx(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
drm_ctx_t *ctx = data;
struct drm_ctx *ctx = data;
DRM_DEBUG( "%d\n", ctx->handle );
if ( ctx->handle != DRM_KERNEL_CONTEXT ) {
if (dev->driver.context_dtor) {
DRM_DEBUG("%d\n", ctx->handle);
if (ctx->handle != DRM_KERNEL_CONTEXT) {
if (dev->driver->context_dtor) {
DRM_LOCK();
dev->driver.context_dtor(dev, ctx->handle);
dev->driver->context_dtor(dev, ctx->handle);
DRM_UNLOCK();
}

View File

@ -64,8 +64,12 @@ list_del(struct list_head *entry) {
#define list_for_each(entry, head) \
for (entry = (head)->next; entry != head; entry = (entry)->next)
#define list_for_each_prev(entry, head) \
for (entry = (head)->prev; entry != (head); \
entry = entry->prev)
#define list_for_each_safe(entry, temp, head) \
for (entry = (head)->next, temp = (entry)->next; \
temp != head; \
entry = temp, temp = temp->next)
entry != head; \
entry = temp, temp = entry->next)

View File

@ -36,52 +36,84 @@
#include "drmP.h"
#define DEBUG_SCATTER 0
static void drm_sg_alloc_cb(void *arg, bus_dma_segment_t *segs,
int nsegs, int error);
void drm_sg_cleanup(drm_sg_mem_t *entry)
int
drm_sg_alloc(struct drm_device *dev, struct drm_scatter_gather *request)
{
free((void *)entry->handle, M_DRM);
free(entry->busaddr, M_DRM);
free(entry, M_DRM);
}
int drm_sg_alloc(struct drm_device * dev, drm_scatter_gather_t * request)
{
drm_sg_mem_t *entry;
struct drm_sg_mem *entry;
struct drm_dma_handle *dmah;
unsigned long pages;
int i;
int ret;
if ( dev->sg )
if (dev->sg)
return EINVAL;
entry = malloc(sizeof(*entry), M_DRM, M_WAITOK | M_ZERO);
if ( !entry )
entry = malloc(sizeof(*entry), DRM_MEM_SGLISTS, M_WAITOK | M_ZERO);
if (!entry)
return ENOMEM;
pages = round_page(request->size) / PAGE_SIZE;
DRM_DEBUG( "sg size=%ld pages=%ld\n", request->size, pages );
DRM_DEBUG("sg size=%ld pages=%ld\n", request->size, pages);
entry->pages = pages;
entry->busaddr = malloc(pages * sizeof(*entry->busaddr), M_DRM,
entry->busaddr = malloc(pages * sizeof(*entry->busaddr), DRM_MEM_PAGES,
M_WAITOK | M_ZERO);
if ( !entry->busaddr ) {
drm_sg_cleanup(entry);
if (!entry->busaddr) {
free(entry, DRM_MEM_SGLISTS);
return ENOMEM;
}
entry->handle = (long)malloc(pages << PAGE_SHIFT, M_DRM,
M_WAITOK | M_ZERO);
if (entry->handle == 0) {
drm_sg_cleanup(entry);
dmah = malloc(sizeof(struct drm_dma_handle), DRM_MEM_DMA,
M_ZERO | M_NOWAIT);
if (dmah == NULL) {
free(entry->busaddr, DRM_MEM_PAGES);
free(entry, DRM_MEM_SGLISTS);
return ENOMEM;
}
for (i = 0; i < pages; i++) {
entry->busaddr[i] = vtophys(entry->handle + i * PAGE_SIZE);
ret = bus_dma_tag_create(NULL, PAGE_SIZE, 0, /* tag, align, boundary */
BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, /* lowaddr, highaddr */
NULL, NULL, /* filtfunc, filtfuncargs */
request->size, pages, /* maxsize, nsegs */
PAGE_SIZE, 0, /* maxsegsize, flags */
NULL, NULL, /* lockfunc, lockfuncargs */
&dmah->tag);
if (ret != 0) {
free(dmah, DRM_MEM_DMA);
free(entry->busaddr, DRM_MEM_PAGES);
free(entry, DRM_MEM_SGLISTS);
return ENOMEM;
}
DRM_DEBUG( "sg alloc handle = %08lx\n", entry->handle );
ret = bus_dmamem_alloc(dmah->tag, &dmah->vaddr,
BUS_DMA_WAITOK | BUS_DMA_ZERO, &dmah->map);
if (ret != 0) {
bus_dma_tag_destroy(dmah->tag);
free(dmah, DRM_MEM_DMA);
free(entry->busaddr, DRM_MEM_PAGES);
free(entry, DRM_MEM_SGLISTS);
return ENOMEM;
}
ret = bus_dmamap_load(dmah->tag, dmah->map, dmah->vaddr,
request->size, drm_sg_alloc_cb, entry,
BUS_DMA_NOWAIT | BUS_DMA_NOCACHE);
if (ret != 0) {
bus_dmamem_free(dmah->tag, dmah->vaddr, dmah->map);
bus_dma_tag_destroy(dmah->tag);
free(dmah, DRM_MEM_DMA);
free(entry->busaddr, DRM_MEM_PAGES);
free(entry, DRM_MEM_SGLISTS);
return ENOMEM;
}
entry->sg_dmah = dmah;
entry->handle = (unsigned long)dmah->vaddr;
DRM_DEBUG("sg alloc handle = %08lx\n", entry->handle);
entry->virtual = (void *)entry->handle;
request->handle = entry->handle;
@ -98,32 +130,59 @@ int drm_sg_alloc(struct drm_device * dev, drm_scatter_gather_t * request)
return 0;
}
int drm_sg_alloc_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv)
static void
drm_sg_alloc_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
{
drm_scatter_gather_t *request = data;
int ret;
struct drm_sg_mem *entry = arg;
int i;
DRM_DEBUG( "%s\n", __FUNCTION__ );
if (error != 0)
return;
ret = drm_sg_alloc(dev, request);
return ret;
for(i = 0 ; i < nsegs ; i++) {
entry->busaddr[i] = segs[i].ds_addr;
}
}
int drm_sg_free(struct drm_device *dev, void *data, struct drm_file *file_priv)
int
drm_sg_alloc_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
drm_scatter_gather_t *request = data;
drm_sg_mem_t *entry;
struct drm_scatter_gather *request = data;
DRM_DEBUG("\n");
return drm_sg_alloc(dev, request);
}
void
drm_sg_cleanup(struct drm_sg_mem *entry)
{
struct drm_dma_handle *dmah = entry->sg_dmah;
bus_dmamap_unload(dmah->tag, dmah->map);
bus_dmamem_free(dmah->tag, dmah->vaddr, dmah->map);
bus_dma_tag_destroy(dmah->tag);
free(dmah, DRM_MEM_DMA);
free(entry->busaddr, DRM_MEM_PAGES);
free(entry, DRM_MEM_SGLISTS);
}
int
drm_sg_free(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
struct drm_scatter_gather *request = data;
struct drm_sg_mem *entry;
DRM_LOCK();
entry = dev->sg;
dev->sg = NULL;
DRM_UNLOCK();
if ( !entry || entry->handle != request->handle )
if (!entry || entry->handle != request->handle)
return EINVAL;
DRM_DEBUG( "sg free virtual = 0x%lx\n", entry->handle );
DRM_DEBUG("sg free virtual = 0x%lx\n", entry->handle);
drm_sg_cleanup(entry);

View File

@ -0,0 +1,33 @@
# $FreeBSD$
.PATH: ${.CURDIR}/..
KMOD = nouveau
NO_MAN = YES
SRCS = nouveau_drv.c nouveau_state.c nouveau_mem.c nouveau_object.c \
nouveau_sgdma.c nouveau_fifo.c nouveau_notifier.c nouveau_dma.c \
nouveau_irq.c nouveau_swmthd.c \
nv04_timer.c \
nv04_mc.c nv40_mc.c nv50_mc.c \
nv04_fb.c nv10_fb.c nv40_fb.c \
nv04_fifo.c nv10_fifo.c nv40_fifo.c nv50_fifo.c \
nv04_graph.c nv10_graph.c nv20_graph.c \
nv40_graph.c nv50_graph.c \
nv04_instmem.c nv50_instmem.c
# nouveau_bo.c nouveau_fence.c \
SRCS += device_if.h bus_if.h pci_if.h opt_drm.h
CFLAGS += ${DEBUG_FLAGS} -I. -I..
.if defined(DRM_DEBUG)
DRM_DEBUG_OPT= "\#define DRM_DEBUG 1"
.endif
.if !defined(DRM_NOLINUX)
DRM_LINUX_OPT= "\#define DRM_LINUX 1"
.endif
opt_drm.h:
touch opt_drm.h
echo $(DRM_DEBUG_OPT) >> opt_drm.h
echo $(DRM_LINUX_OPT) >> opt_drm.h
.include <bsd.kmod.mk>

View File

@ -0,0 +1,148 @@
/* nouveau_drv.c.c -- nouveau nouveau driver -*- linux-c -*-
* Created: Wed Feb 14 17:10:04 2001 by gareth@valinux.com
*/
/*-
* Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors:
* Gareth Hughes <gareth@valinux.com>
*
*/
#include "drmP.h"
#include "drm.h"
#include "nouveau_drv.h"
#include "drm_pciids.h"
extern struct drm_ioctl_desc nouveau_ioctls[];
extern int nouveau_max_ioctl;
/* drv_PCI_IDs for nouveau is just to match the vendor id */
static struct drm_pci_id_list nouveau_pciidlist[] = {
{0x10DE, 0, 0, "NVidia Display Adapter"}, \
{0, 0, 0, NULL}
};
static void nouveau_configure(struct drm_device *dev)
{
dev->driver->driver_features =
DRIVER_USE_AGP | DRIVER_PCI_DMA | DRIVER_SG | DRIVER_HAVE_IRQ;
dev->driver->buf_priv_size = sizeof(struct drm_nouveau_private);
dev->driver->load = nouveau_load;
dev->driver->unload = nouveau_unload;
dev->driver->firstopen = nouveau_firstopen;
dev->driver->preclose = nouveau_preclose;
dev->driver->lastclose = nouveau_lastclose;
dev->driver->irq_preinstall = nouveau_irq_preinstall;
dev->driver->irq_postinstall = nouveau_irq_postinstall;
dev->driver->irq_uninstall = nouveau_irq_uninstall;
dev->driver->irq_handler = nouveau_irq_handler;
dev->driver->ioctls = nouveau_ioctls;
dev->driver->max_ioctl = nouveau_max_ioctl;
dev->driver->name = DRIVER_NAME;
dev->driver->desc = DRIVER_DESC;
dev->driver->date = DRIVER_DATE;
dev->driver->major = DRIVER_MAJOR;
dev->driver->minor = DRIVER_MINOR;
dev->driver->patchlevel = DRIVER_PATCHLEVEL;
}
static int
nouveau_probe(device_t kdev)
{
int vendor;
if (pci_get_class(kdev) == PCIC_DISPLAY) {
vendor = pci_get_vendor(kdev);
if (vendor == 0x10de) {
const char *ident;
char model[64];
if (pci_get_vpd_ident(kdev, &ident) == 0) {
snprintf(model, 64, "%s", ident);
device_set_desc_copy(kdev, model);
DRM_DEBUG("VPD : %s\n", model);
}
return drm_probe(kdev, nouveau_pciidlist);
}
}
return ENXIO;
}
static int
nouveau_attach(device_t kdev)
{
struct drm_device *dev = device_get_softc(kdev);
dev->driver = malloc(sizeof(struct drm_driver_info), DRM_MEM_DRIVER,
M_WAITOK | M_ZERO);
nouveau_configure(dev);
return drm_attach(kdev, nouveau_pciidlist);
}
static int
nouveau_detach(device_t kdev)
{
struct drm_device *dev = device_get_softc(kdev);
int ret;
ret = drm_detach(kdev);
free(dev->driver, DRM_MEM_DRIVER);
return ret;
}
static device_method_t nouveau_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, nouveau_probe),
DEVMETHOD(device_attach, nouveau_attach),
DEVMETHOD(device_detach, nouveau_detach),
{ 0, 0 }
};
static driver_t nouveau_driver = {
#if __FreeBSD_version >= 700010
"drm",
#else
"drmsub",
#endif
nouveau_methods,
sizeof(struct drm_device)
};
extern devclass_t drm_devclass;
#if __FreeBSD_version >= 700010
DRIVER_MODULE(nouveau, vgapci, nouveau_driver, drm_devclass, 0, 0);
#else
DRIVER_MODULE(nouveau, agp, nouveau_driver, drm_devclass, 0, 0);
#endif
MODULE_DEPEND(nouveau, drm, 1, 1, 1);

View File

@ -0,0 +1,357 @@
#include "drmP.h"
#include "nouveau_drv.h"
#define NV_CTXDMA_PAGE_SHIFT 12
#define NV_CTXDMA_PAGE_SIZE (1 << NV_CTXDMA_PAGE_SHIFT)
#define NV_CTXDMA_PAGE_MASK (NV_CTXDMA_PAGE_SIZE - 1)
#if 0
struct nouveau_sgdma_be {
struct drm_ttm_backend backend;
struct drm_device *dev;
int pages;
int pages_populated;
dma_addr_t *pagelist;
int is_bound;
unsigned int pte_start;
};
static int
nouveau_sgdma_needs_ub_cache_adjust(struct drm_ttm_backend *be)
{
return ((be->flags & DRM_BE_FLAG_BOUND_CACHED) ? 0 : 1);
}
static int
nouveau_sgdma_populate(struct drm_ttm_backend *be, unsigned long num_pages,
struct page **pages, struct page *dummy_read_page)
{
struct nouveau_sgdma_be *nvbe = (struct nouveau_sgdma_be *)be;
int p, d, o;
DRM_DEBUG("num_pages = %ld\n", num_pages);
if (nvbe->pagelist)
return -EINVAL;
nvbe->pages = (num_pages << PAGE_SHIFT) >> NV_CTXDMA_PAGE_SHIFT;
nvbe->pagelist = drm_alloc(nvbe->pages*sizeof(dma_addr_t),
DRM_MEM_PAGES);
nvbe->pages_populated = d = 0;
for (p = 0; p < num_pages; p++) {
for (o = 0; o < PAGE_SIZE; o += NV_CTXDMA_PAGE_SIZE) {
struct page *page = pages[p];
if (!page)
page = dummy_read_page;
#ifdef __linux__
nvbe->pagelist[d] = pci_map_page(nvbe->dev->pdev,
page, o,
NV_CTXDMA_PAGE_SIZE,
PCI_DMA_BIDIRECTIONAL);
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27))
if (pci_dma_mapping_error(nvbe->dev->pdev, nvbe->pagelist[d])) {
#else
if (pci_dma_mapping_error(nvbe->pagelist[d])) {
#endif
be->func->clear(be);
DRM_ERROR("pci_map_page failed\n");
return -EINVAL;
}
#endif
nvbe->pages_populated = ++d;
}
}
return 0;
}
static void
nouveau_sgdma_clear(struct drm_ttm_backend *be)
{
struct nouveau_sgdma_be *nvbe = (struct nouveau_sgdma_be *)be;
#ifdef __linux__
int d;
#endif
DRM_DEBUG("\n");
if (nvbe && nvbe->pagelist) {
if (nvbe->is_bound)
be->func->unbind(be);
#ifdef __linux__
for (d = 0; d < nvbe->pages_populated; d++) {
pci_unmap_page(nvbe->dev->pdev, nvbe->pagelist[d],
NV_CTXDMA_PAGE_SIZE,
PCI_DMA_BIDIRECTIONAL);
}
#endif
drm_free(nvbe->pagelist, nvbe->pages*sizeof(dma_addr_t),
DRM_MEM_PAGES);
}
}
static int
nouveau_sgdma_bind(struct drm_ttm_backend *be, struct drm_bo_mem_reg *mem)
{
struct nouveau_sgdma_be *nvbe = (struct nouveau_sgdma_be *)be;
struct drm_nouveau_private *dev_priv = nvbe->dev->dev_private;
struct nouveau_gpuobj *gpuobj = dev_priv->gart_info.sg_ctxdma;
uint64_t offset = (mem->mm_node->start << PAGE_SHIFT);
uint32_t i;
DRM_DEBUG("pg=0x%lx (0x%llx), cached=%d\n", mem->mm_node->start,
(unsigned long long)offset,
(mem->flags & DRM_BO_FLAG_CACHED) == 1);
if (offset & NV_CTXDMA_PAGE_MASK)
return -EINVAL;
nvbe->pte_start = (offset >> NV_CTXDMA_PAGE_SHIFT);
if (dev_priv->card_type < NV_50)
nvbe->pte_start += 2; /* skip ctxdma header */
for (i = nvbe->pte_start; i < nvbe->pte_start + nvbe->pages; i++) {
uint64_t pteval = nvbe->pagelist[i - nvbe->pte_start];
if (pteval & NV_CTXDMA_PAGE_MASK) {
DRM_ERROR("Bad pteval 0x%llx\n",
(unsigned long long)pteval);
return -EINVAL;
}
if (dev_priv->card_type < NV_50) {
INSTANCE_WR(gpuobj, i, pteval | 3);
} else {
INSTANCE_WR(gpuobj, (i<<1)+0, pteval | 0x21);
INSTANCE_WR(gpuobj, (i<<1)+1, 0x00000000);
}
}
nvbe->is_bound = 1;
return 0;
}
static int
nouveau_sgdma_unbind(struct drm_ttm_backend *be)
{
struct nouveau_sgdma_be *nvbe = (struct nouveau_sgdma_be *)be;
struct drm_nouveau_private *dev_priv = nvbe->dev->dev_private;
DRM_DEBUG("\n");
if (nvbe->is_bound) {
struct nouveau_gpuobj *gpuobj = dev_priv->gart_info.sg_ctxdma;
unsigned int pte;
pte = nvbe->pte_start;
while (pte < (nvbe->pte_start + nvbe->pages)) {
uint64_t pteval = dev_priv->gart_info.sg_dummy_bus;
if (dev_priv->card_type < NV_50) {
INSTANCE_WR(gpuobj, pte, pteval | 3);
} else {
INSTANCE_WR(gpuobj, (pte<<1)+0, pteval | 0x21);
INSTANCE_WR(gpuobj, (pte<<1)+1, 0x00000000);
}
pte++;
}
nvbe->is_bound = 0;
}
return 0;
}
static void
nouveau_sgdma_destroy(struct drm_ttm_backend *be)
{
DRM_DEBUG("\n");
if (be) {
struct nouveau_sgdma_be *nvbe = (struct nouveau_sgdma_be *)be;
if (nvbe) {
if (nvbe->pagelist)
be->func->clear(be);
drm_ctl_free(nvbe, sizeof(*nvbe), DRM_MEM_TTM);
}
}
}
static struct drm_ttm_backend_func nouveau_sgdma_backend = {
.needs_ub_cache_adjust = nouveau_sgdma_needs_ub_cache_adjust,
.populate = nouveau_sgdma_populate,
.clear = nouveau_sgdma_clear,
.bind = nouveau_sgdma_bind,
.unbind = nouveau_sgdma_unbind,
.destroy = nouveau_sgdma_destroy
};
struct drm_ttm_backend *
nouveau_sgdma_init_ttm(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_sgdma_be *nvbe;
if (!dev_priv->gart_info.sg_ctxdma)
return NULL;
nvbe = drm_ctl_calloc(1, sizeof(*nvbe), DRM_MEM_TTM);
if (!nvbe)
return NULL;
nvbe->dev = dev;
nvbe->backend.func = &nouveau_sgdma_backend;
return &nvbe->backend;
}
#endif
int
nouveau_sgdma_init(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_gpuobj *gpuobj = NULL;
uint32_t aper_size, obj_size;
int i, ret;
if (dev_priv->card_type < NV_50) {
aper_size = (64 * 1024 * 1024);
obj_size = (aper_size >> NV_CTXDMA_PAGE_SHIFT) * 4;
obj_size += 8; /* ctxdma header */
} else {
/* 1 entire VM page table */
aper_size = (512 * 1024 * 1024);
obj_size = (aper_size >> NV_CTXDMA_PAGE_SHIFT) * 8;
}
if ((ret = nouveau_gpuobj_new(dev, NULL, obj_size, 16,
NVOBJ_FLAG_ALLOW_NO_REFS |
NVOBJ_FLAG_ZERO_ALLOC |
NVOBJ_FLAG_ZERO_FREE, &gpuobj))) {
DRM_ERROR("Error creating sgdma object: %d\n", ret);
return ret;
}
#ifdef __linux__
dev_priv->gart_info.sg_dummy_page =
alloc_page(GFP_KERNEL|__GFP_DMA32);
set_page_locked(dev_priv->gart_info.sg_dummy_page);
dev_priv->gart_info.sg_dummy_bus =
pci_map_page(dev->pdev, dev_priv->gart_info.sg_dummy_page, 0,
PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
#endif
if (dev_priv->card_type < NV_50) {
/* Maybe use NV_DMA_TARGET_AGP for PCIE? NVIDIA do this, and
* confirmed to work on c51. Perhaps means NV_DMA_TARGET_PCIE
* on those cards? */
INSTANCE_WR(gpuobj, 0, NV_CLASS_DMA_IN_MEMORY |
(1 << 12) /* PT present */ |
(0 << 13) /* PT *not* linear */ |
(NV_DMA_ACCESS_RW << 14) |
(NV_DMA_TARGET_PCI << 16));
INSTANCE_WR(gpuobj, 1, aper_size - 1);
for (i=2; i<2+(aper_size>>12); i++) {
INSTANCE_WR(gpuobj, i,
dev_priv->gart_info.sg_dummy_bus | 3);
}
} else {
for (i=0; i<obj_size; i+=8) {
INSTANCE_WR(gpuobj, (i+0)/4,
dev_priv->gart_info.sg_dummy_bus | 0x21);
INSTANCE_WR(gpuobj, (i+4)/4, 0);
}
}
dev_priv->gart_info.type = NOUVEAU_GART_SGDMA;
dev_priv->gart_info.aper_base = 0;
dev_priv->gart_info.aper_size = aper_size;
dev_priv->gart_info.sg_ctxdma = gpuobj;
return 0;
}
void
nouveau_sgdma_takedown(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
if (dev_priv->gart_info.sg_dummy_page) {
#ifdef __linux__
pci_unmap_page(dev->pdev, dev_priv->gart_info.sg_dummy_bus,
NV_CTXDMA_PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
unlock_page(dev_priv->gart_info.sg_dummy_page);
__free_page(dev_priv->gart_info.sg_dummy_page);
#endif
dev_priv->gart_info.sg_dummy_page = NULL;
dev_priv->gart_info.sg_dummy_bus = 0;
}
nouveau_gpuobj_del(dev, &dev_priv->gart_info.sg_ctxdma);
}
#if 0
int
nouveau_sgdma_nottm_hack_init(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct drm_ttm_backend *be;
struct drm_scatter_gather sgreq;
struct drm_mm_node mm_node;
struct drm_bo_mem_reg mem;
int ret;
dev_priv->gart_info.sg_be = nouveau_sgdma_init_ttm(dev);
if (!dev_priv->gart_info.sg_be)
return -ENOMEM;
be = dev_priv->gart_info.sg_be;
/* Hack the aperture size down to the amount of system memory
* we're going to bind into it.
*/
if (dev_priv->gart_info.aper_size > 32*1024*1024)
dev_priv->gart_info.aper_size = 32*1024*1024;
sgreq.size = dev_priv->gart_info.aper_size;
if ((ret = drm_sg_alloc(dev, &sgreq))) {
DRM_ERROR("drm_sg_alloc failed: %d\n", ret);
return ret;
}
dev_priv->gart_info.sg_handle = sgreq.handle;
if ((ret = be->func->populate(be, dev->sg->pages, dev->sg->pagelist, dev->bm.dummy_read_page))) {
DRM_ERROR("failed populate: %d\n", ret);
return ret;
}
mm_node.start = 0;
mem.mm_node = &mm_node;
if ((ret = be->func->bind(be, &mem))) {
DRM_ERROR("failed bind: %d\n", ret);
return ret;
}
return 0;
}
void
nouveau_sgdma_nottm_hack_takedown(struct drm_device *dev)
{
}
#endif
int
nouveau_sgdma_get_page(struct drm_device *dev, uint32_t offset, uint32_t *page)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_gpuobj *gpuobj = dev_priv->gart_info.sg_ctxdma;
int pte;
pte = (offset >> NV_CTXDMA_PAGE_SHIFT);
if (dev_priv->card_type < NV_50) {
*page = INSTANCE_RD(gpuobj, (pte + 2)) & ~NV_CTXDMA_PAGE_MASK;
return 0;
}
DRM_ERROR("Unimplemented on NV50\n");
return -EINVAL;
}

View File

@ -19,7 +19,7 @@
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
AC_PREREQ(2.57)
AC_INIT([libdrm], 2.3.1, [dri-devel@lists.sourceforge.net], libdrm)
AC_INIT([libdrm], 2.4.11, [dri-devel@lists.sourceforge.net], libdrm)
AC_CONFIG_SRCDIR([Makefile.am])
AM_INIT_AUTOMAKE([dist-bzip2])
@ -32,12 +32,123 @@ AC_PROG_CC
AC_HEADER_STDC
AC_SYS_LARGEFILE
PKG_CHECK_MODULES(PTHREADSTUBS, pthread-stubs)
AC_SUBST(PTHREADSTUBS_CFLAGS)
AC_SUBST(PTHREADSTUBS_LIBS)
pkgconfigdir=${libdir}/pkgconfig
AC_SUBST(pkgconfigdir)
AC_ARG_ENABLE(udev, AS_HELP_STRING([--enable-udev],
[Enable support for using udev instead of mknod (default: disabled)]),
[UDEV=$enableval], [UDEV=no])
AC_ARG_ENABLE(nouveau-experimental-api,
AS_HELP_STRING([--enable-nouveau-experimental-api],
[Enable support for nouveau's experimental API (default: disabled)]),
[NOUVEAU=$enableval], [NOUVEAU=no])
dnl ===========================================================================
dnl check compiler flags
AC_DEFUN([LIBDRM_CC_TRY_FLAG], [
AC_MSG_CHECKING([whether $CC supports $1])
libdrm_save_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $1"
AC_COMPILE_IFELSE([ ], [libdrm_cc_flag=yes], [libdrm_cc_flag=no])
CFLAGS="$libdrm_save_CFLAGS"
if test "x$libdrm_cc_flag" = "xyes"; then
ifelse([$2], , :, [$2])
else
ifelse([$3], , :, [$3])
fi
AC_MSG_RESULT([$libdrm_cc_flag])
])
dnl We use clock_gettime to check for timeouts in drmWaitVBlank
AC_CHECK_FUNCS([clock_gettime], [CLOCK_LIB=],
[AC_CHECK_LIB([rt], [clock_gettime], [CLOCK_LIB=-lrt],
[AC_MSG_ERROR([Couldn't find clock_gettime])])])
AC_SUBST([CLOCK_LIB])
dnl Use lots of warning flags with with gcc and compatible compilers
dnl Note: if you change the following variable, the cache is automatically
dnl skipped and all flags rechecked. So there's no need to do anything
dnl else. If for any reason you need to force a recheck, just change
dnl MAYBE_WARN in an ignorable way (like adding whitespace)
MAYBE_WARN="-Wall -Wextra \
-Wsign-compare -Werror-implicit-function-declaration \
-Wpointer-arith -Wwrite-strings -Wstrict-prototypes \
-Wmissing-prototypes -Wmissing-declarations -Wnested-externs \
-Wpacked -Wswitch-enum -Wmissing-format-attribute \
-Wstrict-aliasing=2 -Winit-self -Wunsafe-loop-optimizations \
-Wdeclaration-after-statement -Wold-style-definition \
-Wno-missing-field-initializers -Wno-unused-parameter \
-Wno-attributes -Wno-long-long -Winline"
# invalidate cached value if MAYBE_WARN has changed
if test "x$libdrm_cv_warn_maybe" != "x$MAYBE_WARN"; then
unset libdrm_cv_warn_cflags
fi
AC_CACHE_CHECK([for supported warning flags], libdrm_cv_warn_cflags, [
echo
WARN_CFLAGS=""
# Some warning options are not supported by all versions of
# gcc, so test all desired options against the current
# compiler.
#
# Note that there are some order dependencies
# here. Specifically, an option that disables a warning will
# have no net effect if a later option then enables that
# warnings, (perhaps implicitly). So we put some grouped
# options (-Wall and -Wextra) up front and the -Wno options
# last.
for W in $MAYBE_WARN; do
LIBDRM_CC_TRY_FLAG([$W], [WARN_CFLAGS="$WARN_CFLAGS $W"])
done
libdrm_cv_warn_cflags=$WARN_CFLAGS
libdrm_cv_warn_maybe=$MAYBE_WARN
AC_MSG_CHECKING([which warning flags were supported])])
WARN_CFLAGS="$libdrm_cv_warn_cflags"
if test "x$UDEV" = xyes; then
AC_DEFINE(UDEV, 1, [Have UDEV support])
fi
AM_CONDITIONAL(HAVE_NOUVEAU, [test "x$NOUVEAU" = xyes])
PKG_CHECK_MODULES(CAIRO, cairo, [HAVE_CAIRO=yes], [HAVE_CAIRO=no])
if test "x$HAVE_CAIRO" = xyes; then
AC_DEFINE(HAVE_CAIRO, 1, [Have cairo support])
fi
AM_CONDITIONAL(HAVE_CAIRO, [test "x$HAVE_CAIRO" = xyes])
# For enumerating devices in test case
PKG_CHECK_MODULES(LIBUDEV, libudev, [HAVE_LIBUDEV=yes], [HAVE_LIBUDEV=no])
if test "x$HAVE_LIBUDEV" = xyes; then
AC_DEFINE(HAVE_LIBUDEV, 1, [Have libudev support])
fi
AM_CONDITIONAL(HAVE_LIBUDEV, [test "x$HAVE_LIBUDEV" = xyes])
AC_SUBST(WARN_CFLAGS)
AC_OUTPUT([
Makefile
libdrm/Makefile
libdrm/intel/Makefile
libdrm/nouveau/Makefile
libdrm/nouveau/libdrm_nouveau.pc
shared-core/Makefile
tests/Makefile
libdrm.pc])
tests/modeprint/Makefile
tests/modetest/Makefile
libdrm.pc
libdrm_intel.pc])

View File

@ -18,14 +18,22 @@
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
if HAVE_NOUVEAU
NOUVEAU_SUBDIR = nouveau
endif
SUBDIRS = . intel $(NOUVEAU_SUBDIR)
libdrm_la_LTLIBRARIES = libdrm.la
libdrm_ladir = $(libdir)
libdrm_la_LDFLAGS = -version-number 2:3:0 -no-undefined
libdrm_la_LDFLAGS = -version-number 2:4:0 -no-undefined
libdrm_la_LIBADD = @CLOCK_LIB@
AM_CFLAGS = -I$(top_srcdir)/shared-core
libdrm_la_SOURCES = xf86drm.c xf86drmHash.c xf86drmRandom.c xf86drmSL.c
libdrm_la_SOURCES = xf86drm.c xf86drmHash.c xf86drmRandom.c xf86drmSL.c \
xf86drmMode.c libdrm_lists.h
libdrmincludedir = ${includedir}
libdrminclude_HEADERS = xf86drm.h xf86mm.h
libdrminclude_HEADERS = xf86drm.h xf86drmMode.h
EXTRA_DIST = ChangeLog TODO

View File

@ -0,0 +1,47 @@
# Copyright © 2008 Intel Corporation
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice (including the next
# paragraph) shall be included in all copies or substantial portions of the
# Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.
#
# Authors:
# Eric Anholt <eric@anholt.net>
AM_CFLAGS = \
$(WARN_CFLAGS) \
-I$(top_srcdir)/libdrm \
-I$(top_srcdir)/libdrm/intel \
$(PTHREADSTUBS_CFLAGS) \
-I$(top_srcdir)/shared-core
libdrm_intel_la_LTLIBRARIES = libdrm_intel.la
libdrm_intel_ladir = $(libdir)
libdrm_intel_la_LDFLAGS = -version-number 1:0:0 -no-undefined
libdrm_intel_la_LIBADD = ../libdrm.la @PTHREADSTUBS_LIBS@
libdrm_intel_la_SOURCES = \
intel_bufmgr.c \
intel_bufmgr_priv.h \
intel_bufmgr_fake.c \
intel_bufmgr_gem.c \
intel_chipset.h \
mm.c \
mm.h
libdrm_intelincludedir = ${includedir}
libdrm_intelinclude_HEADERS = intel_bufmgr.h

View File

@ -0,0 +1,230 @@
/*
* Copyright © 2007 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
* Authors:
* Eric Anholt <eric@anholt.net>
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <assert.h>
#include <errno.h>
#include <drm.h>
#include <i915_drm.h>
#include "intel_bufmgr.h"
#include "intel_bufmgr_priv.h"
/** @file intel_bufmgr.c
*
* Convenience functions for buffer management methods.
*/
drm_intel_bo *
drm_intel_bo_alloc(drm_intel_bufmgr *bufmgr, const char *name,
unsigned long size, unsigned int alignment)
{
return bufmgr->bo_alloc(bufmgr, name, size, alignment);
}
drm_intel_bo *
drm_intel_bo_alloc_for_render(drm_intel_bufmgr *bufmgr, const char *name,
unsigned long size, unsigned int alignment)
{
return bufmgr->bo_alloc_for_render(bufmgr, name, size, alignment);
}
void
drm_intel_bo_reference(drm_intel_bo *bo)
{
bo->bufmgr->bo_reference(bo);
}
void
drm_intel_bo_unreference(drm_intel_bo *bo)
{
if (bo == NULL)
return;
bo->bufmgr->bo_unreference(bo);
}
int
drm_intel_bo_map(drm_intel_bo *buf, int write_enable)
{
return buf->bufmgr->bo_map(buf, write_enable);
}
int
drm_intel_bo_unmap(drm_intel_bo *buf)
{
return buf->bufmgr->bo_unmap(buf);
}
int
drm_intel_bo_subdata(drm_intel_bo *bo, unsigned long offset,
unsigned long size, const void *data)
{
int ret;
if (bo->bufmgr->bo_subdata)
return bo->bufmgr->bo_subdata(bo, offset, size, data);
if (size == 0 || data == NULL)
return 0;
ret = drm_intel_bo_map(bo, 1);
if (ret)
return ret;
memcpy((unsigned char *)bo->virtual + offset, data, size);
drm_intel_bo_unmap(bo);
return 0;
}
int
drm_intel_bo_get_subdata(drm_intel_bo *bo, unsigned long offset,
unsigned long size, void *data)
{
int ret;
if (bo->bufmgr->bo_subdata)
return bo->bufmgr->bo_get_subdata(bo, offset, size, data);
if (size == 0 || data == NULL)
return 0;
ret = drm_intel_bo_map(bo, 0);
if (ret)
return ret;
memcpy(data, (unsigned char *)bo->virtual + offset, size);
drm_intel_bo_unmap(bo);
return 0;
}
void
drm_intel_bo_wait_rendering(drm_intel_bo *bo)
{
bo->bufmgr->bo_wait_rendering(bo);
}
void
drm_intel_bufmgr_destroy(drm_intel_bufmgr *bufmgr)
{
bufmgr->destroy(bufmgr);
}
int
drm_intel_bo_exec(drm_intel_bo *bo, int used,
drm_clip_rect_t *cliprects, int num_cliprects,
int DR4)
{
return bo->bufmgr->bo_exec(bo, used, cliprects, num_cliprects, DR4);
}
void
drm_intel_bufmgr_set_debug(drm_intel_bufmgr *bufmgr, int enable_debug)
{
bufmgr->debug = enable_debug;
}
int
drm_intel_bufmgr_check_aperture_space(drm_intel_bo **bo_array, int count)
{
return bo_array[0]->bufmgr->check_aperture_space(bo_array, count);
}
int
drm_intel_bo_flink(drm_intel_bo *bo, uint32_t *name)
{
if (bo->bufmgr->bo_flink)
return bo->bufmgr->bo_flink(bo, name);
return -ENODEV;
}
int
drm_intel_bo_emit_reloc(drm_intel_bo *bo, uint32_t offset,
drm_intel_bo *target_bo, uint32_t target_offset,
uint32_t read_domains, uint32_t write_domain)
{
return bo->bufmgr->bo_emit_reloc(bo, offset,
target_bo, target_offset,
read_domains, write_domain);
}
int
drm_intel_bo_pin(drm_intel_bo *bo, uint32_t alignment)
{
if (bo->bufmgr->bo_pin)
return bo->bufmgr->bo_pin(bo, alignment);
return -ENODEV;
}
int
drm_intel_bo_unpin(drm_intel_bo *bo)
{
if (bo->bufmgr->bo_unpin)
return bo->bufmgr->bo_unpin(bo);
return -ENODEV;
}
int drm_intel_bo_set_tiling(drm_intel_bo *bo, uint32_t *tiling_mode,
uint32_t stride)
{
if (bo->bufmgr->bo_set_tiling)
return bo->bufmgr->bo_set_tiling(bo, tiling_mode, stride);
*tiling_mode = I915_TILING_NONE;
return 0;
}
int drm_intel_bo_get_tiling(drm_intel_bo *bo, uint32_t *tiling_mode,
uint32_t *swizzle_mode)
{
if (bo->bufmgr->bo_get_tiling)
return bo->bufmgr->bo_get_tiling(bo, tiling_mode, swizzle_mode);
*tiling_mode = I915_TILING_NONE;
*swizzle_mode = I915_BIT_6_SWIZZLE_NONE;
return 0;
}
int drm_intel_bo_disable_reuse(drm_intel_bo *bo)
{
if (bo->bufmgr->bo_disable_reuse)
return bo->bufmgr->bo_disable_reuse(bo);
return 0;
}
int
drm_intel_get_pipe_from_crtc_id (drm_intel_bufmgr *bufmgr, int crtc_id)
{
if (bufmgr->get_pipe_from_crtc_id)
return bufmgr->get_pipe_from_crtc_id(bufmgr, crtc_id);
return -1;
}

View File

@ -0,0 +1,197 @@
/*
* Copyright © 2008 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
* Authors:
* Eric Anholt <eric@anholt.net>
*
*/
/**
* @file intel_bufmgr.h
*
* Public definitions of Intel-specific bufmgr functions.
*/
#ifndef INTEL_BUFMGR_H
#define INTEL_BUFMGR_H
#include <stdint.h>
typedef struct _drm_intel_bufmgr drm_intel_bufmgr;
typedef struct _drm_intel_bo drm_intel_bo;
struct _drm_intel_bo {
/**
* Size in bytes of the buffer object.
*
* The size may be larger than the size originally requested for the
* allocation, such as being aligned to page size.
*/
unsigned long size;
/**
* Alignment requirement for object
*
* Used for GTT mapping & pinning the object.
*/
unsigned long align;
/**
* Card virtual address (offset from the beginning of the aperture) for the
* object. Only valid while validated.
*/
unsigned long offset;
/**
* Virtual address for accessing the buffer data. Only valid while mapped.
*/
void *virtual;
/** Buffer manager context associated with this buffer object */
drm_intel_bufmgr *bufmgr;
/**
* MM-specific handle for accessing object
*/
int handle;
};
drm_intel_bo *drm_intel_bo_alloc(drm_intel_bufmgr *bufmgr, const char *name,
unsigned long size, unsigned int alignment);
drm_intel_bo *drm_intel_bo_alloc_for_render(drm_intel_bufmgr *bufmgr,
const char *name,
unsigned long size,
unsigned int alignment);
void drm_intel_bo_reference(drm_intel_bo *bo);
void drm_intel_bo_unreference(drm_intel_bo *bo);
int drm_intel_bo_map(drm_intel_bo *bo, int write_enable);
int drm_intel_bo_unmap(drm_intel_bo *bo);
int drm_intel_bo_subdata(drm_intel_bo *bo, unsigned long offset,
unsigned long size, const void *data);
int drm_intel_bo_get_subdata(drm_intel_bo *bo, unsigned long offset,
unsigned long size, void *data);
void drm_intel_bo_wait_rendering(drm_intel_bo *bo);
void drm_intel_bufmgr_set_debug(drm_intel_bufmgr *bufmgr, int enable_debug);
void drm_intel_bufmgr_destroy(drm_intel_bufmgr *bufmgr);
int drm_intel_bo_exec(drm_intel_bo *bo, int used,
drm_clip_rect_t *cliprects, int num_cliprects,
int DR4);
int drm_intel_bufmgr_check_aperture_space(drm_intel_bo **bo_array, int count);
int drm_intel_bo_emit_reloc(drm_intel_bo *bo, uint32_t offset,
drm_intel_bo *target_bo, uint32_t target_offset,
uint32_t read_domains, uint32_t write_domain);
int drm_intel_bo_pin(drm_intel_bo *bo, uint32_t alignment);
int drm_intel_bo_unpin(drm_intel_bo *bo);
int drm_intel_bo_set_tiling(drm_intel_bo *bo, uint32_t *tiling_mode,
uint32_t stride);
int drm_intel_bo_get_tiling(drm_intel_bo *bo, uint32_t *tiling_mode,
uint32_t *swizzle_mode);
int drm_intel_bo_flink(drm_intel_bo *bo, uint32_t *name);
int drm_intel_bo_disable_reuse(drm_intel_bo *bo);
/* drm_intel_bufmgr_gem.c */
drm_intel_bufmgr *drm_intel_bufmgr_gem_init(int fd, int batch_size);
drm_intel_bo *drm_intel_bo_gem_create_from_name(drm_intel_bufmgr *bufmgr,
const char *name,
unsigned int handle);
void drm_intel_bufmgr_gem_enable_reuse(drm_intel_bufmgr *bufmgr);
int drm_intel_gem_bo_map_gtt(drm_intel_bo *bo);
int drm_intel_gem_bo_unmap_gtt(drm_intel_bo *bo);
void drm_intel_gem_bo_start_gtt_access(drm_intel_bo *bo, int write_enable);
int drm_intel_get_pipe_from_crtc_id(drm_intel_bufmgr *bufmgr, int crtc_id);
/* drm_intel_bufmgr_fake.c */
drm_intel_bufmgr *drm_intel_bufmgr_fake_init(int fd,
unsigned long low_offset,
void *low_virtual,
unsigned long size,
volatile unsigned int *last_dispatch);
void drm_intel_bufmgr_fake_set_last_dispatch(drm_intel_bufmgr *bufmgr,
volatile unsigned int *last_dispatch);
void drm_intel_bufmgr_fake_set_exec_callback(drm_intel_bufmgr *bufmgr,
int (*exec)(drm_intel_bo *bo,
unsigned int used,
void *priv),
void *priv);
void drm_intel_bufmgr_fake_set_fence_callback(drm_intel_bufmgr *bufmgr,
unsigned int (*emit)(void *priv),
void (*wait)(unsigned int fence,
void *priv),
void *priv);
drm_intel_bo *drm_intel_bo_fake_alloc_static(drm_intel_bufmgr *bufmgr,
const char *name,
unsigned long offset, unsigned long size,
void *virtual);
void drm_intel_bo_fake_disable_backing_store(drm_intel_bo *bo,
void (*invalidate_cb)(drm_intel_bo *bo,
void *ptr),
void *ptr);
void drm_intel_bufmgr_fake_contended_lock_take(drm_intel_bufmgr *bufmgr);
void drm_intel_bufmgr_fake_evict_all(drm_intel_bufmgr *bufmgr);
/** @{ Compatibility defines to keep old code building despite the symbol rename
* from dri_* to drm_intel_*
*/
#define dri_bo drm_intel_bo
#define dri_bufmgr drm_intel_bufmgr
#define dri_bo_alloc drm_intel_bo_alloc
#define dri_bo_reference drm_intel_bo_reference
#define dri_bo_unreference drm_intel_bo_unreference
#define dri_bo_map drm_intel_bo_map
#define dri_bo_unmap drm_intel_bo_unmap
#define dri_bo_subdata drm_intel_bo_subdata
#define dri_bo_get_subdata drm_intel_bo_get_subdata
#define dri_bo_wait_rendering drm_intel_bo_wait_rendering
#define dri_bufmgr_set_debug drm_intel_bufmgr_set_debug
#define dri_bufmgr_destroy drm_intel_bufmgr_destroy
#define dri_bo_exec drm_intel_bo_exec
#define dri_bufmgr_check_aperture_space drm_intel_bufmgr_check_aperture_space
#define dri_bo_emit_reloc(reloc_bo, read, write, target_offset, \
reloc_offset, target_bo) \
drm_intel_bo_emit_reloc(reloc_bo, reloc_offset, \
target_bo, target_offset, \
read, write);
#define dri_bo_pin drm_intel_bo_pin
#define dri_bo_unpin drm_intel_bo_unpin
#define dri_bo_get_tiling drm_intel_bo_get_tiling
#define dri_bo_set_tiling(bo, mode) drm_intel_bo_set_tiling(bo, mode, 0)
#define dri_bo_flink drm_intel_bo_flink
#define intel_bufmgr_gem_init drm_intel_bufmgr_gem_init
#define intel_bo_gem_create_from_name drm_intel_bo_gem_create_from_name
#define intel_bufmgr_gem_enable_reuse drm_intel_bufmgr_gem_enable_reuse
#define intel_bufmgr_fake_init drm_intel_bufmgr_fake_init
#define intel_bufmgr_fake_set_last_dispatch drm_intel_bufmgr_fake_set_last_dispatch
#define intel_bufmgr_fake_set_exec_callback drm_intel_bufmgr_fake_set_exec_callback
#define intel_bufmgr_fake_set_fence_callback drm_intel_bufmgr_fake_set_fence_callback
#define intel_bo_fake_alloc_static drm_intel_bo_fake_alloc_static
#define intel_bo_fake_disable_backing_store drm_intel_bo_fake_disable_backing_store
#define intel_bufmgr_fake_contended_lock_take drm_intel_bufmgr_fake_contended_lock_take
#define intel_bufmgr_fake_evict_all drm_intel_bufmgr_fake_evict_all
/** @{ */
#endif /* INTEL_BUFMGR_H */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,208 @@
/*
* Copyright © 2008 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
* Authors:
* Eric Anholt <eric@anholt.net>
*
*/
/**
* @file intel_bufmgr_priv.h
*
* Private definitions of Intel-specific bufmgr functions and structures.
*/
#ifndef INTEL_BUFMGR_PRIV_H
#define INTEL_BUFMGR_PRIV_H
/**
* Context for a buffer manager instance.
*
* Contains public methods followed by private storage for the buffer manager.
*/
struct _drm_intel_bufmgr {
/**
* Allocate a buffer object.
*
* Buffer objects are not necessarily initially mapped into CPU virtual
* address space or graphics device aperture. They must be mapped using
* bo_map() to be used by the CPU, and validated for use using bo_validate()
* to be used from the graphics device.
*/
drm_intel_bo *(*bo_alloc)(drm_intel_bufmgr *bufmgr, const char *name,
unsigned long size, unsigned int alignment);
/**
* Allocate a buffer object, hinting that it will be used as a render target.
*
* This is otherwise the same as bo_alloc.
*/
drm_intel_bo *(*bo_alloc_for_render)(drm_intel_bufmgr *bufmgr,
const char *name,
unsigned long size,
unsigned int alignment);
/** Takes a reference on a buffer object */
void (*bo_reference)(drm_intel_bo *bo);
/**
* Releases a reference on a buffer object, freeing the data if
* rerefences remain.
*/
void (*bo_unreference)(drm_intel_bo *bo);
/**
* Maps the buffer into userspace.
*
* This function will block waiting for any existing execution on the
* buffer to complete, first. The resulting mapping is available at
* buf->virtual.
*/
int (*bo_map)(drm_intel_bo *bo, int write_enable);
/** Reduces the refcount on the userspace mapping of the buffer object. */
int (*bo_unmap)(drm_intel_bo *bo);
/**
* Write data into an object.
*
* This is an optional function, if missing,
* drm_intel_bo will map/memcpy/unmap.
*/
int (*bo_subdata)(drm_intel_bo *bo, unsigned long offset,
unsigned long size, const void *data);
/**
* Read data from an object
*
* This is an optional function, if missing,
* drm_intel_bo will map/memcpy/unmap.
*/
int (*bo_get_subdata)(drm_intel_bo *bo, unsigned long offset,
unsigned long size, void *data);
/**
* Waits for rendering to an object by the GPU to have completed.
*
* This is not required for any access to the BO by bo_map, bo_subdata, etc.
* It is merely a way for the driver to implement glFinish.
*/
void (*bo_wait_rendering)(drm_intel_bo *bo);
/**
* Tears down the buffer manager instance.
*/
void (*destroy)(drm_intel_bufmgr *bufmgr);
/**
* Add relocation entry in reloc_buf, which will be updated with the
* target buffer's real offset on on command submission.
*
* Relocations remain in place for the lifetime of the buffer object.
*
* \param bo Buffer to write the relocation into.
* \param offset Byte offset within reloc_bo of the pointer to target_bo.
* \param target_bo Buffer whose offset should be written into the
* relocation entry.
* \param target_offset Constant value to be added to target_bo's offset in
* relocation entry.
* \param read_domains GEM read domains which the buffer will be read into
* by the command that this relocation is part of.
* \param write_domains GEM read domains which the buffer will be dirtied
* in by the command that this relocation is part of.
*/
int (*bo_emit_reloc)(drm_intel_bo *bo, uint32_t offset,
drm_intel_bo *target_bo, uint32_t target_offset,
uint32_t read_domains, uint32_t write_domain);
/** Executes the command buffer pointed to by bo. */
int (*bo_exec)(drm_intel_bo *bo, int used,
drm_clip_rect_t *cliprects, int num_cliprects,
int DR4);
/**
* Pin a buffer to the aperture and fix the offset until unpinned
*
* \param buf Buffer to pin
* \param alignment Required alignment for aperture, in bytes
*/
int (*bo_pin)(drm_intel_bo *bo, uint32_t alignment);
/**
* Unpin a buffer from the aperture, allowing it to be removed
*
* \param buf Buffer to unpin
*/
int (*bo_unpin)(drm_intel_bo *bo);
/**
* Ask that the buffer be placed in tiling mode
*
* \param buf Buffer to set tiling mode for
* \param tiling_mode desired, and returned tiling mode
*/
int (*bo_set_tiling)(drm_intel_bo *bo, uint32_t *tiling_mode,
uint32_t stride);
/**
* Get the current tiling (and resulting swizzling) mode for the bo.
*
* \param buf Buffer to get tiling mode for
* \param tiling_mode returned tiling mode
* \param swizzle_mode returned swizzling mode
*/
int (*bo_get_tiling)(drm_intel_bo *bo, uint32_t *tiling_mode,
uint32_t *swizzle_mode);
/**
* Create a visible name for a buffer which can be used by other apps
*
* \param buf Buffer to create a name for
* \param name Returned name
*/
int (*bo_flink)(drm_intel_bo *bo, uint32_t *name);
int (*check_aperture_space)(drm_intel_bo **bo_array, int count);
/**
* Disable buffer reuse for buffers which will be shared in some way,
* as with scanout buffers. When the buffer reference count goes to zero,
* it will be freed and not placed in the reuse list.
*
* \param bo Buffer to disable reuse for
*/
int (*bo_disable_reuse)(drm_intel_bo *bo);
/**
*
* Return the pipe associated with a crtc_id so that vblank
* synchronization can use the correct data in the request.
* This is only supported for KMS and gem at this point, when
* unsupported, this function returns -1 and leaves the decision
* of what to do in that case to the caller
*
* \param bufmgr the associated buffer manager
* \param crtc_id the crtc identifier
*/
int (*get_pipe_from_crtc_id)(drm_intel_bufmgr *bufmgr, int crtc_id);
int debug; /**< Enables verbose debugging printouts */
};
#endif /* INTEL_BUFMGR_PRIV_H */

View File

@ -0,0 +1,71 @@
/*
*
* Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
* IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef _INTEL_CHIPSET_H
#define _INTEL_CHIPSET_H
#define IS_I830(dev) ((dev)->pci_device == 0x3577)
#define IS_845G(dev) ((dev)->pci_device == 0x2562)
#define IS_I85X(dev) ((dev)->pci_device == 0x3582)
#define IS_I855(dev) ((dev)->pci_device == 0x3582)
#define IS_I865G(dev) ((dev)->pci_device == 0x2572)
#define IS_I915G(dev) ((dev)->pci_device == 0x2582 || (dev)->pci_device == 0x258a)
#define IS_I915GM(dev) ((dev)->pci_device == 0x2592)
#define IS_I945G(dev) ((dev)->pci_device == 0x2772)
#define IS_I945GM(dev) ((dev)->pci_device == 0x27A2 ||\
(dev)->pci_device == 0x27AE)
#define IS_I965G(dev) ((dev)->pci_device == 0x2972 || \
(dev)->pci_device == 0x2982 || \
(dev)->pci_device == 0x2992 || \
(dev)->pci_device == 0x29A2 || \
(dev)->pci_device == 0x2A02 || \
(dev)->pci_device == 0x2A12 || \
(dev)->pci_device == 0x2A42 || \
(dev)->pci_device == 0x2E02 || \
(dev)->pci_device == 0x2E12 || \
(dev)->pci_device == 0x2E22)
#define IS_I965GM(dev) ((dev)->pci_device == 0x2A02)
#define IS_GM45(dev) ((dev)->pci_device == 0x2A42)
#define IS_G4X(dev) ((dev)->pci_device == 0x2E02 || \
(dev)->pci_device == 0x2E12 || \
(dev)->pci_device == 0x2E22)
#define IS_G33(dev) ((dev)->pci_device == 0x29C2 || \
(dev)->pci_device == 0x29B2 || \
(dev)->pci_device == 0x29D2)
#define IS_I9XX(dev) (IS_I915G(dev) || IS_I915GM(dev) || IS_I945G(dev) || \
IS_I945GM(dev) || IS_I965G(dev) || IS_G33(dev))
#define IS_MOBILE(dev) (IS_I830(dev) || IS_I85X(dev) || IS_I915GM(dev) || \
IS_I945GM(dev) || IS_I965GM(dev) || IS_GM45(dev))
#endif /* _INTEL_CHIPSET_H */

View File

@ -0,0 +1,281 @@
/*
* GLX Hardware Device Driver common code
* Copyright (C) 1999 Wittawat Yamwong
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* WITTAWAT YAMWONG, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#include <stdlib.h>
#include <assert.h>
#include "xf86drm.h"
#include "mm.h"
void
mmDumpMemInfo(const struct mem_block *heap)
{
drmMsg("Memory heap %p:\n", (void *)heap);
if (heap == 0) {
drmMsg(" heap == 0\n");
} else {
const struct mem_block *p;
for(p = heap->next; p != heap; p = p->next) {
drmMsg(" Offset:%08x, Size:%08x, %c%c\n",p->ofs,p->size,
p->free ? 'F':'.',
p->reserved ? 'R':'.');
}
drmMsg("\nFree list:\n");
for(p = heap->next_free; p != heap; p = p->next_free) {
drmMsg(" FREE Offset:%08x, Size:%08x, %c%c\n",p->ofs,p->size,
p->free ? 'F':'.',
p->reserved ? 'R':'.');
}
}
drmMsg("End of memory blocks\n");
}
struct mem_block *
mmInit(int ofs, int size)
{
struct mem_block *heap, *block;
if (size <= 0)
return NULL;
heap = (struct mem_block *) calloc(1, sizeof(struct mem_block));
if (!heap)
return NULL;
block = (struct mem_block *) calloc(1, sizeof(struct mem_block));
if (!block) {
free(heap);
return NULL;
}
heap->next = block;
heap->prev = block;
heap->next_free = block;
heap->prev_free = block;
block->heap = heap;
block->next = heap;
block->prev = heap;
block->next_free = heap;
block->prev_free = heap;
block->ofs = ofs;
block->size = size;
block->free = 1;
return heap;
}
static struct mem_block *
SliceBlock(struct mem_block *p,
int startofs, int size,
int reserved, int alignment)
{
struct mem_block *newblock;
/* break left [p, newblock, p->next], then p = newblock */
if (startofs > p->ofs) {
newblock = (struct mem_block*) calloc(1, sizeof(struct mem_block));
if (!newblock)
return NULL;
newblock->ofs = startofs;
newblock->size = p->size - (startofs - p->ofs);
newblock->free = 1;
newblock->heap = p->heap;
newblock->next = p->next;
newblock->prev = p;
p->next->prev = newblock;
p->next = newblock;
newblock->next_free = p->next_free;
newblock->prev_free = p;
p->next_free->prev_free = newblock;
p->next_free = newblock;
p->size -= newblock->size;
p = newblock;
}
/* break right, also [p, newblock, p->next] */
if (size < p->size) {
newblock = (struct mem_block*) calloc(1, sizeof(struct mem_block));
if (!newblock)
return NULL;
newblock->ofs = startofs + size;
newblock->size = p->size - size;
newblock->free = 1;
newblock->heap = p->heap;
newblock->next = p->next;
newblock->prev = p;
p->next->prev = newblock;
p->next = newblock;
newblock->next_free = p->next_free;
newblock->prev_free = p;
p->next_free->prev_free = newblock;
p->next_free = newblock;
p->size = size;
}
/* p = middle block */
p->free = 0;
/* Remove p from the free list:
*/
p->next_free->prev_free = p->prev_free;
p->prev_free->next_free = p->next_free;
p->next_free = 0;
p->prev_free = 0;
p->reserved = reserved;
return p;
}
struct mem_block *
mmAllocMem(struct mem_block *heap, int size, int align2, int startSearch)
{
struct mem_block *p;
const int mask = (1 << align2)-1;
int startofs = 0;
int endofs;
if (!heap || align2 < 0 || size <= 0)
return NULL;
for (p = heap->next_free; p != heap; p = p->next_free) {
assert(p->free);
startofs = (p->ofs + mask) & ~mask;
if ( startofs < startSearch ) {
startofs = startSearch;
}
endofs = startofs+size;
if (endofs <= (p->ofs+p->size))
break;
}
if (p == heap)
return NULL;
assert(p->free);
p = SliceBlock(p,startofs,size,0,mask+1);
return p;
}
struct mem_block *
mmFindBlock(struct mem_block *heap, int start)
{
struct mem_block *p;
for (p = heap->next; p != heap; p = p->next) {
if (p->ofs == start)
return p;
}
return NULL;
}
static int
Join2Blocks(struct mem_block *p)
{
/* XXX there should be some assertions here */
/* NOTE: heap->free == 0 */
if (p->free && p->next->free) {
struct mem_block *q = p->next;
assert(p->ofs + p->size == q->ofs);
p->size += q->size;
p->next = q->next;
q->next->prev = p;
q->next_free->prev_free = q->prev_free;
q->prev_free->next_free = q->next_free;
free(q);
return 1;
}
return 0;
}
int
mmFreeMem(struct mem_block *b)
{
if (!b)
return 0;
if (b->free) {
drmMsg("block already free\n");
return -1;
}
if (b->reserved) {
drmMsg("block is reserved\n");
return -1;
}
b->free = 1;
b->next_free = b->heap->next_free;
b->prev_free = b->heap;
b->next_free->prev_free = b;
b->prev_free->next_free = b;
Join2Blocks(b);
if (b->prev != b->heap)
Join2Blocks(b->prev);
return 0;
}
void
mmDestroy(struct mem_block *heap)
{
struct mem_block *p;
if (!heap)
return;
for (p = heap->next; p != heap; ) {
struct mem_block *next = p->next;
free(p);
p = next;
}
free(heap);
}

View File

@ -0,0 +1,96 @@
/*
* GLX Hardware Device Driver common code
* Copyright (C) 1999 Wittawat Yamwong
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* KEITH WHITWELL, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* Memory manager code. Primarily used by device drivers to manage texture
* heaps, etc.
*/
#ifndef MM_H
#define MM_H
struct mem_block {
struct mem_block *next, *prev;
struct mem_block *next_free, *prev_free;
struct mem_block *heap;
int ofs,size;
unsigned int free:1;
unsigned int reserved:1;
};
/* Rename the variables in the drm copy of this code so that it doesn't
* conflict with mesa or whoever else has copied it around.
*/
#define mmInit drm_mmInit
#define mmAllocMem drm_mmAllocMem
#define mmFreeMem drm_mmFreeMem
#define mmFindBlock drm_mmFindBlock
#define mmDestroy drm_mmDestroy
#define mmDumpMemInfo drm_mmDumpMemInfo
/**
* input: total size in bytes
* return: a heap pointer if OK, NULL if error
*/
extern struct mem_block *mmInit(int ofs, int size);
/**
* Allocate 'size' bytes with 2^align2 bytes alignment,
* restrict the search to free memory after 'startSearch'
* depth and back buffers should be in different 4mb banks
* to get better page hits if possible
* input: size = size of block
* align2 = 2^align2 bytes alignment
* startSearch = linear offset from start of heap to begin search
* return: pointer to the allocated block, 0 if error
*/
extern struct mem_block *mmAllocMem(struct mem_block *heap, int size,
int align2, int startSearch);
/**
* Free block starts at offset
* input: pointer to a block
* return: 0 if OK, -1 if error
*/
extern int mmFreeMem(struct mem_block *b);
/**
* Free block starts at offset
* input: pointer to a heap, start offset
* return: pointer to a block
*/
extern struct mem_block *mmFindBlock(struct mem_block *heap, int start);
/**
* destroy MM
*/
extern void mmDestroy(struct mem_block *mmInit);
/**
* For debuging purpose.
*/
extern void mmDumpMemInfo(const struct mem_block *mmInit);
#endif

View File

@ -0,0 +1,89 @@
/**************************************************************************
*
* Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND. USA.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*/
/*
* List macros heavily inspired by the Linux kernel
* list handling. No list looping yet.
*/
#include <stddef.h>
typedef struct _drmMMListHead
{
struct _drmMMListHead *prev;
struct _drmMMListHead *next;
} drmMMListHead;
#define DRMINITLISTHEAD(__item) \
do{ \
(__item)->prev = (__item); \
(__item)->next = (__item); \
} while (0)
#define DRMLISTADD(__item, __list) \
do { \
(__item)->prev = (__list); \
(__item)->next = (__list)->next; \
(__list)->next->prev = (__item); \
(__list)->next = (__item); \
} while (0)
#define DRMLISTADDTAIL(__item, __list) \
do { \
(__item)->next = (__list); \
(__item)->prev = (__list)->prev; \
(__list)->prev->next = (__item); \
(__list)->prev = (__item); \
} while(0)
#define DRMLISTDEL(__item) \
do { \
(__item)->prev->next = (__item)->next; \
(__item)->next->prev = (__item)->prev; \
} while(0)
#define DRMLISTDELINIT(__item) \
do { \
(__item)->prev->next = (__item)->next; \
(__item)->next->prev = (__item)->prev; \
(__item)->next = (__item); \
(__item)->prev = (__item); \
} while(0)
#define DRMLISTENTRY(__type, __item, __field) \
((__type *)(((char *) (__item)) - offsetof(__type, __field)))
#define DRMLISTEMPTY(__item) ((__item)->next == (__item))
#define DRMLISTFOREACHSAFE(__item, __temp, __list) \
for ((__item) = (__list)->next, (__temp) = (__item)->next; \
(__item) != (__list); \
(__item) = (__temp), (__temp) = (__item)->next)
#define DRMLISTFOREACHSAFEREVERSE(__item, __temp, __list) \
for ((__item) = (__list)->prev, (__temp) = (__item)->prev; \
(__item) != (__list); \
(__item) = (__temp), (__temp) = (__item)->prev)

View File

@ -0,0 +1,42 @@
AM_CFLAGS = \
$(WARN_CFLAGS) \
-I$(top_srcdir)/libdrm \
-I$(top_srcdir)/libdrm/nouveau \
$(PTHREADSTUBS_CFLAGS) \
-I$(top_srcdir)/shared-core
libdrm_nouveau_la_LTLIBRARIES = libdrm_nouveau.la
libdrm_nouveau_ladir = $(libdir)
libdrm_nouveau_la_LDFLAGS = -version-number 1:0:0 -no-undefined
libdrm_nouveau_la_LIBADD = ../libdrm.la @PTHREADSTUBS_LIBS@
libdrm_nouveau_la_SOURCES = \
nouveau_device.c \
nouveau_channel.c \
nouveau_pushbuf.c \
nouveau_grobj.c \
nouveau_notifier.c \
nouveau_bo.c \
nouveau_resource.c \
nouveau_dma.c \
nouveau_fence.c \
nouveau_dma.h \
nouveau_private.h
libdrm_nouveaucommonincludedir = ${includedir}/nouveau
libdrm_nouveaucommoninclude_HEADERS = \
nouveau_device.h \
nouveau_channel.h \
nouveau_grobj.h \
nouveau_notifier.h \
nouveau_pushbuf.h \
nouveau_bo.h \
nouveau_resource.h \
nouveau_class.h
libdrm_nouveauincludedir = ${includedir}/drm
libdrm_nouveauinclude_HEADERS = \
nouveau_drmif.h
pkgconfigdir = @pkgconfigdir@
pkgconfig_DATA = libdrm_nouveau.pc

View File

@ -0,0 +1,10 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
Name: libdrm_nouveau
Description: Userspace interface to nouveau kernel DRM services
Version: 0.5
Libs: -L${libdir} -ldrm_nouveau
Cflags: -I${includedir} -I${includedir}/drm -I${includedir}/nouveau

View File

@ -0,0 +1,849 @@
/*
* Copyright 2007 Nouveau Project
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <stdint.h>
#include <stdlib.h>
#include <errno.h>
#include <assert.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include "nouveau_private.h"
int
nouveau_bo_init(struct nouveau_device *dev)
{
return 0;
}
void
nouveau_bo_takedown(struct nouveau_device *dev)
{
}
static int
nouveau_bo_allocated(struct nouveau_bo_priv *nvbo)
{
if (nvbo->sysmem || nvbo->handle || (nvbo->flags & NOUVEAU_BO_PIN))
return 1;
return 0;
}
static int
nouveau_bo_ualloc(struct nouveau_bo_priv *nvbo)
{
if (nvbo->user || nvbo->sysmem) {
assert(nvbo->sysmem);
return 0;
}
nvbo->sysmem = malloc(nvbo->size);
if (!nvbo->sysmem)
return -ENOMEM;
return 0;
}
static void
nouveau_bo_ufree(struct nouveau_bo_priv *nvbo)
{
if (nvbo->sysmem) {
if (!nvbo->user)
free(nvbo->sysmem);
nvbo->sysmem = NULL;
}
}
static void
nouveau_bo_kfree_nomm(struct nouveau_bo_priv *nvbo)
{
struct nouveau_device_priv *nvdev = nouveau_device(nvbo->base.device);
struct drm_nouveau_mem_free req;
if (nvbo->map) {
drmUnmap(nvbo->map, nvbo->size);
nvbo->map = NULL;
}
req.offset = nvbo->offset;
if (nvbo->domain & NOUVEAU_BO_GART)
req.flags = NOUVEAU_MEM_AGP | NOUVEAU_MEM_PCI;
else
if (nvbo->domain & NOUVEAU_BO_VRAM)
req.flags = NOUVEAU_MEM_FB;
drmCommandWrite(nvdev->fd, DRM_NOUVEAU_MEM_FREE, &req, sizeof(req));
nvbo->handle = 0;
}
static void
nouveau_bo_kfree(struct nouveau_bo_priv *nvbo)
{
struct nouveau_device_priv *nvdev = nouveau_device(nvbo->base.device);
struct drm_gem_close req;
if (!nvbo->handle)
return;
if (!nvdev->mm_enabled) {
nouveau_bo_kfree_nomm(nvbo);
return;
}
if (nvbo->map) {
munmap(nvbo->map, nvbo->size);
nvbo->map = NULL;
}
req.handle = nvbo->handle;
nvbo->handle = 0;
ioctl(nvdev->fd, DRM_IOCTL_GEM_CLOSE, &req);
}
static int
nouveau_bo_kalloc_nomm(struct nouveau_bo_priv *nvbo)
{
struct nouveau_device_priv *nvdev = nouveau_device(nvbo->base.device);
struct drm_nouveau_mem_alloc req;
int ret;
if (nvbo->handle)
return 0;
if (!(nvbo->flags & (NOUVEAU_BO_VRAM|NOUVEAU_BO_GART)))
nvbo->flags |= (NOUVEAU_BO_GART | NOUVEAU_BO_VRAM);
req.size = nvbo->size;
req.alignment = nvbo->align;
req.flags = 0;
if (nvbo->flags & NOUVEAU_BO_VRAM)
req.flags |= NOUVEAU_MEM_FB;
if (nvbo->flags & NOUVEAU_BO_GART)
req.flags |= (NOUVEAU_MEM_AGP | NOUVEAU_MEM_PCI);
if (nvbo->flags & NOUVEAU_BO_TILED) {
req.flags |= NOUVEAU_MEM_TILE;
if (nvbo->flags & NOUVEAU_BO_ZTILE)
req.flags |= NOUVEAU_MEM_TILE_ZETA;
}
req.flags |= NOUVEAU_MEM_MAPPED;
ret = drmCommandWriteRead(nvdev->fd, DRM_NOUVEAU_MEM_ALLOC,
&req, sizeof(req));
if (ret)
return ret;
nvbo->handle = req.map_handle;
nvbo->size = req.size;
nvbo->offset = req.offset;
if (req.flags & (NOUVEAU_MEM_AGP | NOUVEAU_MEM_PCI))
nvbo->domain = NOUVEAU_BO_GART;
else
if (req.flags & NOUVEAU_MEM_FB)
nvbo->domain = NOUVEAU_BO_VRAM;
return 0;
}
static int
nouveau_bo_kalloc(struct nouveau_bo_priv *nvbo, struct nouveau_channel *chan)
{
struct nouveau_device_priv *nvdev = nouveau_device(nvbo->base.device);
struct drm_nouveau_gem_new req;
int ret;
if (nvbo->handle || (nvbo->flags & NOUVEAU_BO_PIN))
return 0;
if (!nvdev->mm_enabled)
return nouveau_bo_kalloc_nomm(nvbo);
req.channel_hint = chan ? chan->id : 0;
req.size = nvbo->size;
req.align = nvbo->align;
req.domain = 0;
if (nvbo->flags & NOUVEAU_BO_VRAM)
req.domain |= NOUVEAU_GEM_DOMAIN_VRAM;
if (nvbo->flags & NOUVEAU_BO_GART)
req.domain |= NOUVEAU_GEM_DOMAIN_GART;
if (nvbo->flags & NOUVEAU_BO_TILED) {
req.domain |= NOUVEAU_GEM_DOMAIN_TILE;
if (nvbo->flags & NOUVEAU_BO_ZTILE)
req.domain |= NOUVEAU_GEM_DOMAIN_TILE_ZETA;
}
if (!req.domain) {
req.domain |= (NOUVEAU_GEM_DOMAIN_VRAM |
NOUVEAU_GEM_DOMAIN_GART);
}
ret = drmCommandWriteRead(nvdev->fd, DRM_NOUVEAU_GEM_NEW,
&req, sizeof(req));
if (ret)
return ret;
nvbo->handle = nvbo->base.handle = req.handle;
nvbo->size = req.size;
nvbo->domain = req.domain;
nvbo->offset = req.offset;
return 0;
}
static int
nouveau_bo_kmap_nomm(struct nouveau_bo_priv *nvbo)
{
struct nouveau_device_priv *nvdev = nouveau_device(nvbo->base.device);
int ret;
ret = drmMap(nvdev->fd, nvbo->handle, nvbo->size, &nvbo->map);
if (ret) {
nvbo->map = NULL;
return ret;
}
return 0;
}
static int
nouveau_bo_kmap(struct nouveau_bo_priv *nvbo)
{
struct nouveau_device_priv *nvdev = nouveau_device(nvbo->base.device);
struct drm_nouveau_gem_mmap req;
int ret;
if (nvbo->map)
return 0;
if (!nvbo->handle)
return -EINVAL;
if (!nvdev->mm_enabled)
return nouveau_bo_kmap_nomm(nvbo);
req.handle = nvbo->handle;
ret = drmCommandWriteRead(nvdev->fd, DRM_NOUVEAU_GEM_MMAP,
&req, sizeof(req));
if (ret)
return ret;
nvbo->map = (void *)(unsigned long)req.vaddr;
return 0;
}
int
nouveau_bo_new(struct nouveau_device *dev, uint32_t flags, int align,
int size, struct nouveau_bo **bo)
{
struct nouveau_bo_priv *nvbo;
int ret;
if (!dev || !bo || *bo)
return -EINVAL;
nvbo = calloc(1, sizeof(struct nouveau_bo_priv));
if (!nvbo)
return -ENOMEM;
nvbo->base.device = dev;
nvbo->base.size = size;
nvbo->refcount = 1;
/* Don't set NOUVEAU_BO_PIN here, or nouveau_bo_allocated() will
* decided the buffer's already allocated when it's not. The
* call to nouveau_bo_pin() later will set this flag.
*/
nvbo->flags = (flags & ~NOUVEAU_BO_PIN);
nvbo->size = size;
nvbo->align = align;
/*XXX: murder me violently */
if (flags & NOUVEAU_BO_TILED) {
nvbo->base.tiled = 1;
if (flags & NOUVEAU_BO_ZTILE)
nvbo->base.tiled |= 2;
}
if (flags & NOUVEAU_BO_PIN) {
ret = nouveau_bo_pin((void *)nvbo, nvbo->flags);
if (ret) {
nouveau_bo_ref(NULL, (void *)nvbo);
return ret;
}
}
*bo = &nvbo->base;
return 0;
}
int
nouveau_bo_user(struct nouveau_device *dev, void *ptr, int size,
struct nouveau_bo **bo)
{
struct nouveau_bo_priv *nvbo;
int ret;
ret = nouveau_bo_new(dev, 0, 0, size, bo);
if (ret)
return ret;
nvbo = nouveau_bo(*bo);
nvbo->sysmem = ptr;
nvbo->user = 1;
return 0;
}
int
nouveau_bo_fake(struct nouveau_device *dev, uint64_t offset, uint32_t flags,
uint32_t size, void *map, struct nouveau_bo **bo)
{
struct nouveau_bo_priv *nvbo;
int ret;
ret = nouveau_bo_new(dev, flags & ~NOUVEAU_BO_PIN, 0, size, bo);
if (ret)
return ret;
nvbo = nouveau_bo(*bo);
nvbo->flags = flags | NOUVEAU_BO_PIN;
nvbo->domain = (flags & (NOUVEAU_BO_VRAM|NOUVEAU_BO_GART));
nvbo->offset = offset;
nvbo->size = nvbo->base.size = size;
nvbo->map = map;
nvbo->base.flags = nvbo->flags;
nvbo->base.offset = nvbo->offset;
return 0;
}
int
nouveau_bo_handle_get(struct nouveau_bo *bo, uint32_t *handle)
{
struct nouveau_device_priv *nvdev = nouveau_device(bo->device);
struct nouveau_bo_priv *nvbo = nouveau_bo(bo);
int ret;
if (!bo || !handle)
return -EINVAL;
if (!nvbo->global_handle) {
struct drm_gem_flink req;
ret = nouveau_bo_kalloc(nvbo, NULL);
if (ret)
return ret;
if (nvdev->mm_enabled) {
req.handle = nvbo->handle;
ret = ioctl(nvdev->fd, DRM_IOCTL_GEM_FLINK, &req);
if (ret) {
nouveau_bo_kfree(nvbo);
return ret;
}
nvbo->global_handle = req.name;
} else {
nvbo->global_handle = nvbo->offset;
}
}
*handle = nvbo->global_handle;
return 0;
}
int
nouveau_bo_handle_ref(struct nouveau_device *dev, uint32_t handle,
struct nouveau_bo **bo)
{
struct nouveau_device_priv *nvdev = nouveau_device(dev);
struct nouveau_bo_priv *nvbo;
struct drm_gem_open req;
int ret;
ret = nouveau_bo_new(dev, 0, 0, 0, bo);
if (ret)
return ret;
nvbo = nouveau_bo(*bo);
if (!nvdev->mm_enabled) {
nvbo->handle = 0;
nvbo->offset = handle;
nvbo->domain = NOUVEAU_BO_VRAM;
nvbo->flags = NOUVEAU_BO_VRAM | NOUVEAU_BO_PIN;
nvbo->base.offset = nvbo->offset;
nvbo->base.flags = nvbo->flags;
} else {
req.name = handle;
ret = ioctl(nvdev->fd, DRM_IOCTL_GEM_OPEN, &req);
if (ret) {
nouveau_bo_ref(NULL, bo);
return ret;
}
nvbo->size = req.size;
nvbo->handle = req.handle;
}
nvbo->base.handle = nvbo->handle;
return 0;
}
static void
nouveau_bo_del_cb(void *priv)
{
struct nouveau_bo_priv *nvbo = priv;
nouveau_fence_ref(NULL, &nvbo->fence);
nouveau_fence_ref(NULL, &nvbo->wr_fence);
nouveau_bo_kfree(nvbo);
free(nvbo);
}
static void
nouveau_bo_del(struct nouveau_bo **bo)
{
struct nouveau_bo_priv *nvbo;
if (!bo || !*bo)
return;
nvbo = nouveau_bo(*bo);
*bo = NULL;
if (--nvbo->refcount)
return;
if (nvbo->pending) {
nvbo->pending = NULL;
nouveau_pushbuf_flush(nvbo->pending_channel, 0);
}
nouveau_bo_ufree(nvbo);
if (!nouveau_device(nvbo->base.device)->mm_enabled && nvbo->fence) {
nouveau_fence_flush(nvbo->fence->channel);
if (nouveau_fence(nvbo->fence)->signalled) {
nouveau_bo_del_cb(nvbo);
} else {
nouveau_fence_signal_cb(nvbo->fence,
nouveau_bo_del_cb, nvbo);
}
} else {
nouveau_bo_del_cb(nvbo);
}
}
int
nouveau_bo_ref(struct nouveau_bo *ref, struct nouveau_bo **pbo)
{
if (!pbo)
return -EINVAL;
if (ref)
nouveau_bo(ref)->refcount++;
if (*pbo)
nouveau_bo_del(pbo);
*pbo = ref;
return 0;
}
static int
nouveau_bo_wait_nomm(struct nouveau_bo *bo, int cpu_write)
{
struct nouveau_bo_priv *nvbo = nouveau_bo(bo);
int ret = 0;
if (cpu_write)
ret = nouveau_fence_wait(&nvbo->fence);
else
ret = nouveau_fence_wait(&nvbo->wr_fence);
if (ret)
return ret;
nvbo->write_marker = 0;
return 0;
}
static int
nouveau_bo_wait(struct nouveau_bo *bo, int cpu_write)
{
struct nouveau_device_priv *nvdev = nouveau_device(bo->device);
struct nouveau_bo_priv *nvbo = nouveau_bo(bo);
struct drm_nouveau_gem_cpu_prep req;
int ret;
if (!nvbo->global_handle && !nvbo->write_marker && !cpu_write)
return 0;
if (nvbo->pending &&
(nvbo->pending->write_domains || cpu_write)) {
nvbo->pending = NULL;
nouveau_pushbuf_flush(nvbo->pending_channel, 0);
}
if (!nvdev->mm_enabled)
return nouveau_bo_wait_nomm(bo, cpu_write);
req.handle = nvbo->handle;
ret = drmCommandWrite(nvdev->fd, DRM_NOUVEAU_GEM_CPU_PREP,
&req, sizeof(req));
if (ret)
return ret;
nvbo->write_marker = 0;
return 0;
}
int
nouveau_bo_map(struct nouveau_bo *bo, uint32_t flags)
{
struct nouveau_bo_priv *nvbo = nouveau_bo(bo);
int ret;
if (!nvbo || bo->map)
return -EINVAL;
if (!nouveau_bo_allocated(nvbo)) {
if (nvbo->flags & (NOUVEAU_BO_VRAM | NOUVEAU_BO_GART)) {
ret = nouveau_bo_kalloc(nvbo, NULL);
if (ret)
return ret;
}
if (!nouveau_bo_allocated(nvbo)) {
ret = nouveau_bo_ualloc(nvbo);
if (ret)
return ret;
}
}
if (nvbo->sysmem) {
bo->map = nvbo->sysmem;
} else {
ret = nouveau_bo_kmap(nvbo);
if (ret)
return ret;
ret = nouveau_bo_wait(bo, (flags & NOUVEAU_BO_WR));
if (ret)
return ret;
bo->map = nvbo->map;
}
return 0;
}
void
nouveau_bo_unmap(struct nouveau_bo *bo)
{
struct nouveau_device_priv *nvdev = nouveau_device(bo->device);
struct nouveau_bo_priv *nvbo = nouveau_bo(bo);
if (nvdev->mm_enabled && bo->map && !nvbo->sysmem) {
struct nouveau_device_priv *nvdev = nouveau_device(bo->device);
struct drm_nouveau_gem_cpu_fini req;
req.handle = nvbo->handle;
drmCommandWrite(nvdev->fd, DRM_NOUVEAU_GEM_CPU_FINI,
&req, sizeof(req));
}
bo->map = NULL;
}
int
nouveau_bo_validate_nomm(struct nouveau_bo_priv *nvbo, uint32_t flags)
{
struct nouveau_bo *new = NULL;
uint32_t t_handle, t_domain, t_offset, t_size;
void *t_map;
int ret;
if ((flags & NOUVEAU_BO_VRAM) && nvbo->domain == NOUVEAU_BO_VRAM)
return 0;
if ((flags & NOUVEAU_BO_GART) && nvbo->domain == NOUVEAU_BO_GART)
return 0;
assert(flags & (NOUVEAU_BO_VRAM|NOUVEAU_BO_GART));
/* Keep tiling info */
flags |= (nvbo->flags & (NOUVEAU_BO_TILED|NOUVEAU_BO_ZTILE));
ret = nouveau_bo_new(nvbo->base.device, flags, 0, nvbo->size, &new);
if (ret)
return ret;
ret = nouveau_bo_kalloc(nouveau_bo(new), NULL);
if (ret) {
nouveau_bo_ref(NULL, &new);
return ret;
}
if (nvbo->handle || nvbo->sysmem) {
nouveau_bo_kmap(nouveau_bo(new));
if (!nvbo->base.map) {
nouveau_bo_map(&nvbo->base, NOUVEAU_BO_RD);
memcpy(nouveau_bo(new)->map, nvbo->base.map, nvbo->base.size);
nouveau_bo_unmap(&nvbo->base);
} else {
memcpy(nouveau_bo(new)->map, nvbo->base.map, nvbo->base.size);
}
}
t_handle = nvbo->handle;
t_domain = nvbo->domain;
t_offset = nvbo->offset;
t_size = nvbo->size;
t_map = nvbo->map;
nvbo->handle = nouveau_bo(new)->handle;
nvbo->domain = nouveau_bo(new)->domain;
nvbo->offset = nouveau_bo(new)->offset;
nvbo->size = nouveau_bo(new)->size;
nvbo->map = nouveau_bo(new)->map;
nouveau_bo(new)->handle = t_handle;
nouveau_bo(new)->domain = t_domain;
nouveau_bo(new)->offset = t_offset;
nouveau_bo(new)->size = t_size;
nouveau_bo(new)->map = t_map;
nouveau_bo_ref(NULL, &new);
return 0;
}
static int
nouveau_bo_pin_nomm(struct nouveau_bo *bo, uint32_t flags)
{
struct nouveau_bo_priv *nvbo = nouveau_bo(bo);
int ret;
if (!nvbo->handle) {
if (!(flags & (NOUVEAU_BO_VRAM | NOUVEAU_BO_GART)))
return -EINVAL;
ret = nouveau_bo_validate_nomm(nvbo, flags & ~NOUVEAU_BO_PIN);
if (ret)
return ret;
}
nvbo->pinned = 1;
/* Fill in public nouveau_bo members */
bo->flags = nvbo->domain;
bo->offset = nvbo->offset;
return 0;
}
int
nouveau_bo_pin(struct nouveau_bo *bo, uint32_t flags)
{
struct nouveau_device_priv *nvdev = nouveau_device(bo->device);
struct nouveau_bo_priv *nvbo = nouveau_bo(bo);
struct drm_nouveau_gem_pin req;
int ret;
if (nvbo->pinned)
return 0;
if (!nvdev->mm_enabled)
return nouveau_bo_pin_nomm(bo, flags);
/* Ensure we have a kernel object... */
if (!nvbo->handle) {
if (!(flags & (NOUVEAU_BO_VRAM | NOUVEAU_BO_GART)))
return -EINVAL;
nvbo->flags = flags;
ret = nouveau_bo_kalloc(nvbo, NULL);
if (ret)
return ret;
}
/* Now force it to stay put :) */
req.handle = nvbo->handle;
req.domain = 0;
if (nvbo->flags & NOUVEAU_BO_VRAM)
req.domain |= NOUVEAU_GEM_DOMAIN_VRAM;
if (nvbo->flags & NOUVEAU_BO_GART)
req.domain |= NOUVEAU_GEM_DOMAIN_GART;
ret = drmCommandWriteRead(nvdev->fd, DRM_NOUVEAU_GEM_PIN, &req,
sizeof(struct drm_nouveau_gem_pin));
if (ret)
return ret;
nvbo->offset = req.offset;
nvbo->domain = req.domain;
nvbo->pinned = 1;
nvbo->flags |= NOUVEAU_BO_PIN;
/* Fill in public nouveau_bo members */
if (nvbo->domain & NOUVEAU_GEM_DOMAIN_VRAM)
bo->flags = NOUVEAU_BO_VRAM;
if (nvbo->domain & NOUVEAU_GEM_DOMAIN_GART)
bo->flags = NOUVEAU_BO_GART;
bo->offset = nvbo->offset;
return 0;
}
void
nouveau_bo_unpin(struct nouveau_bo *bo)
{
struct nouveau_device_priv *nvdev = nouveau_device(bo->device);
struct nouveau_bo_priv *nvbo = nouveau_bo(bo);
struct drm_nouveau_gem_unpin req;
if (!nvbo->pinned)
return;
if (nvdev->mm_enabled) {
req.handle = nvbo->handle;
drmCommandWrite(nvdev->fd, DRM_NOUVEAU_GEM_UNPIN,
&req, sizeof(req));
}
nvbo->pinned = bo->offset = bo->flags = 0;
}
int
nouveau_bo_tile(struct nouveau_bo *bo, uint32_t flags, uint32_t delta,
uint32_t size)
{
struct nouveau_device_priv *nvdev = nouveau_device(bo->device);
struct nouveau_bo_priv *nvbo = nouveau_bo(bo);
uint32_t kern_flags = 0;
int ret = 0;
if (flags & NOUVEAU_BO_TILED) {
kern_flags |= NOUVEAU_MEM_TILE;
if (flags & NOUVEAU_BO_ZTILE)
kern_flags |= NOUVEAU_MEM_TILE_ZETA;
}
if (nvdev->mm_enabled) {
struct drm_nouveau_gem_tile req;
req.handle = nvbo->handle;
req.delta = delta;
req.size = size;
req.flags = kern_flags;
ret = drmCommandWrite(nvdev->fd, DRM_NOUVEAU_GEM_TILE,
&req, sizeof(req));
} else {
struct drm_nouveau_mem_tile req;
req.offset = nvbo->offset;
req.delta = delta;
req.size = size;
req.flags = kern_flags;
if (flags & NOUVEAU_BO_VRAM)
req.flags |= NOUVEAU_MEM_FB;
if (flags & NOUVEAU_BO_GART)
req.flags |= NOUVEAU_MEM_AGP;
ret = drmCommandWrite(nvdev->fd, DRM_NOUVEAU_MEM_TILE,
&req, sizeof(req));
}
return 0;
}
int
nouveau_bo_busy(struct nouveau_bo *bo, uint32_t access)
{
struct nouveau_device_priv *nvdev = nouveau_device(bo->device);
struct nouveau_bo_priv *nvbo = nouveau_bo(bo);
if (!nvdev->mm_enabled) {
struct nouveau_fence *fence;
if (nvbo->pending && (nvbo->pending->write_domains ||
(access & NOUVEAU_BO_WR)))
return 1;
if (access & NOUVEAU_BO_WR)
fence = nvbo->fence;
else
fence = nvbo->wr_fence;
return !nouveau_fence(fence)->signalled;
}
return 1;
}
struct drm_nouveau_gem_pushbuf_bo *
nouveau_bo_emit_buffer(struct nouveau_channel *chan, struct nouveau_bo *bo)
{
struct nouveau_pushbuf_priv *nvpb = nouveau_pushbuf(chan->pushbuf);
struct nouveau_bo_priv *nvbo = nouveau_bo(bo);
struct drm_nouveau_gem_pushbuf_bo *pbbo;
struct nouveau_bo *ref = NULL;
int ret;
if (nvbo->pending)
return nvbo->pending;
if (!nvbo->handle) {
ret = nouveau_bo_kalloc(nvbo, chan);
if (ret)
return NULL;
if (nvbo->sysmem) {
void *sysmem_tmp = nvbo->sysmem;
nvbo->sysmem = NULL;
ret = nouveau_bo_map(bo, NOUVEAU_BO_WR);
if (ret)
return NULL;
nvbo->sysmem = sysmem_tmp;
memcpy(bo->map, nvbo->sysmem, nvbo->base.size);
nouveau_bo_unmap(bo);
nouveau_bo_ufree(nvbo);
}
}
if (nvpb->nr_buffers >= NOUVEAU_PUSHBUF_MAX_BUFFERS)
return NULL;
pbbo = nvpb->buffers + nvpb->nr_buffers++;
nvbo->pending = pbbo;
nvbo->pending_channel = chan;
nouveau_bo_ref(bo, &ref);
pbbo->user_priv = (uint64_t)(unsigned long)ref;
pbbo->handle = nvbo->handle;
pbbo->valid_domains = NOUVEAU_GEM_DOMAIN_VRAM | NOUVEAU_GEM_DOMAIN_GART;
pbbo->read_domains = 0;
pbbo->write_domains = 0;
pbbo->presumed_domain = nvbo->domain;
pbbo->presumed_offset = nvbo->offset;
pbbo->presumed_ok = 1;
return pbbo;
}

View File

@ -0,0 +1,97 @@
/*
* Copyright 2007 Nouveau Project
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef __NOUVEAU_BO_H__
#define __NOUVEAU_BO_H__
/* Relocation/Buffer type flags */
#define NOUVEAU_BO_VRAM (1 << 0)
#define NOUVEAU_BO_GART (1 << 1)
#define NOUVEAU_BO_RD (1 << 2)
#define NOUVEAU_BO_WR (1 << 3)
#define NOUVEAU_BO_RDWR (NOUVEAU_BO_RD | NOUVEAU_BO_WR)
#define NOUVEAU_BO_MAP (1 << 4)
#define NOUVEAU_BO_PIN (1 << 5)
#define NOUVEAU_BO_LOW (1 << 6)
#define NOUVEAU_BO_HIGH (1 << 7)
#define NOUVEAU_BO_OR (1 << 8)
#define NOUVEAU_BO_LOCAL (1 << 9)
#define NOUVEAU_BO_TILED (1 << 10)
#define NOUVEAU_BO_ZTILE (1 << 11)
#define NOUVEAU_BO_DUMMY (1 << 31)
struct nouveau_bo {
struct nouveau_device *device;
uint32_t handle;
uint64_t size;
void *map;
int tiled;
/* Available when buffer is pinned *only* */
uint32_t flags;
uint64_t offset;
};
int
nouveau_bo_new(struct nouveau_device *, uint32_t flags, int align, int size,
struct nouveau_bo **);
int
nouveau_bo_user(struct nouveau_device *, void *ptr, int size,
struct nouveau_bo **);
int
nouveau_bo_fake(struct nouveau_device *dev, uint64_t offset, uint32_t flags,
uint32_t size, void *map, struct nouveau_bo **);
int
nouveau_bo_handle_get(struct nouveau_bo *, uint32_t *);
int
nouveau_bo_handle_ref(struct nouveau_device *, uint32_t handle,
struct nouveau_bo **);
int
nouveau_bo_ref(struct nouveau_bo *, struct nouveau_bo **);
int
nouveau_bo_map(struct nouveau_bo *, uint32_t flags);
void
nouveau_bo_unmap(struct nouveau_bo *);
int
nouveau_bo_pin(struct nouveau_bo *, uint32_t flags);
void
nouveau_bo_unpin(struct nouveau_bo *);
int
nouveau_bo_tile(struct nouveau_bo *, uint32_t flags, uint32_t delta,
uint32_t size);
int
nouveau_bo_busy(struct nouveau_bo *, uint32_t access);
#endif

View File

@ -0,0 +1,178 @@
/*
* Copyright 2007 Nouveau Project
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "nouveau_private.h"
int
nouveau_channel_alloc(struct nouveau_device *dev, uint32_t fb_ctxdma,
uint32_t tt_ctxdma, struct nouveau_channel **chan)
{
struct nouveau_device_priv *nvdev = nouveau_device(dev);
struct nouveau_channel_priv *nvchan;
unsigned i;
int ret;
if (!nvdev || !chan || *chan)
return -EINVAL;
nvchan = calloc(1, sizeof(struct nouveau_channel_priv));
if (!nvchan)
return -ENOMEM;
nvchan->base.device = dev;
nvchan->drm.fb_ctxdma_handle = fb_ctxdma;
nvchan->drm.tt_ctxdma_handle = tt_ctxdma;
ret = drmCommandWriteRead(nvdev->fd, DRM_NOUVEAU_CHANNEL_ALLOC,
&nvchan->drm, sizeof(nvchan->drm));
if (ret) {
free(nvchan);
return ret;
}
nvchan->base.id = nvchan->drm.channel;
if (nouveau_grobj_ref(&nvchan->base, nvchan->drm.fb_ctxdma_handle,
&nvchan->base.vram) ||
nouveau_grobj_ref(&nvchan->base, nvchan->drm.tt_ctxdma_handle,
&nvchan->base.gart)) {
nouveau_channel_free((void *)&nvchan);
return -EINVAL;
}
/* Mark all DRM-assigned subchannels as in-use */
for (i = 0; i < nvchan->drm.nr_subchan; i++) {
struct nouveau_grobj_priv *gr = calloc(1, sizeof(*gr));
gr->base.bound = NOUVEAU_GROBJ_BOUND_EXPLICIT;
gr->base.subc = i;
gr->base.handle = nvchan->drm.subchan[i].handle;
gr->base.grclass = nvchan->drm.subchan[i].grclass;
gr->base.channel = &nvchan->base;
nvchan->base.subc[i].gr = &gr->base;
}
ret = drmMap(nvdev->fd, nvchan->drm.notifier, nvchan->drm.notifier_size,
(drmAddressPtr)&nvchan->notifier_block);
if (ret) {
nouveau_channel_free((void *)&nvchan);
return ret;
}
ret = nouveau_grobj_alloc(&nvchan->base, 0x00000000, 0x0030,
&nvchan->base.nullobj);
if (ret) {
nouveau_channel_free((void *)&nvchan);
return ret;
}
if (!nvdev->mm_enabled) {
ret = drmMap(nvdev->fd, nvchan->drm.ctrl, nvchan->drm.ctrl_size,
(void*)&nvchan->user);
if (ret) {
nouveau_channel_free((void *)&nvchan);
return ret;
}
nvchan->put = &nvchan->user[0x40/4];
nvchan->get = &nvchan->user[0x44/4];
nvchan->ref_cnt = &nvchan->user[0x48/4];
ret = drmMap(nvdev->fd, nvchan->drm.cmdbuf,
nvchan->drm.cmdbuf_size, (void*)&nvchan->pushbuf);
if (ret) {
nouveau_channel_free((void *)&nvchan);
return ret;
}
nouveau_dma_channel_init(&nvchan->base);
}
nouveau_pushbuf_init(&nvchan->base);
if (!nvdev->mm_enabled && dev->chipset < 0x10) {
ret = nouveau_grobj_alloc(&nvchan->base, 0xbeef3904, 0x5039,
&nvchan->fence_grobj);
if (ret) {
nouveau_channel_free((void *)&nvchan);
return ret;
}
ret = nouveau_notifier_alloc(&nvchan->base, 0xbeef3905, 1,
&nvchan->fence_ntfy);
if (ret) {
nouveau_channel_free((void *)&nvchan);
return ret;
}
BEGIN_RING(&nvchan->base, nvchan->fence_grobj, 0x0180, 1);
OUT_RING (&nvchan->base, nvchan->fence_ntfy->handle);
nvchan->fence_grobj->bound = NOUVEAU_GROBJ_BOUND_EXPLICIT;
}
*chan = &nvchan->base;
return 0;
}
void
nouveau_channel_free(struct nouveau_channel **chan)
{
struct nouveau_channel_priv *nvchan;
struct nouveau_device_priv *nvdev;
struct drm_nouveau_channel_free cf;
if (!chan || !*chan)
return;
nvchan = nouveau_channel(*chan);
*chan = NULL;
nvdev = nouveau_device(nvchan->base.device);
FIRE_RING(&nvchan->base);
if (!nvdev->mm_enabled) {
struct nouveau_fence *fence = NULL;
/* Make sure all buffer objects on delayed delete queue
* actually get freed.
*/
nouveau_fence_new(&nvchan->base, &fence);
nouveau_fence_emit(fence);
nouveau_fence_wait(&fence);
}
if (nvchan->notifier_block)
drmUnmap(nvchan->notifier_block, nvchan->drm.notifier_size);
nouveau_grobj_free(&nvchan->base.vram);
nouveau_grobj_free(&nvchan->base.gart);
nouveau_grobj_free(&nvchan->base.nullobj);
nouveau_grobj_free(&nvchan->fence_grobj);
nouveau_notifier_free(&nvchan->fence_ntfy);
cf.channel = nvchan->drm.channel;
drmCommandWrite(nvdev->fd, DRM_NOUVEAU_CHANNEL_FREE, &cf, sizeof(cf));
free(nvchan);
}

View File

@ -0,0 +1,56 @@
/*
* Copyright 2007 Nouveau Project
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef __NOUVEAU_CHANNEL_H__
#define __NOUVEAU_CHANNEL_H__
struct nouveau_subchannel {
struct nouveau_grobj *gr;
unsigned sequence;
};
struct nouveau_channel {
struct nouveau_device *device;
int id;
struct nouveau_pushbuf *pushbuf;
struct nouveau_grobj *nullobj;
struct nouveau_grobj *vram;
struct nouveau_grobj *gart;
void *user_private;
void (*hang_notify)(struct nouveau_channel *);
void (*flush_notify)(struct nouveau_channel *);
struct nouveau_subchannel subc[8];
unsigned subc_sequence;
};
int
nouveau_channel_alloc(struct nouveau_device *, uint32_t fb, uint32_t tt,
struct nouveau_channel **);
void
nouveau_channel_free(struct nouveau_channel **);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,202 @@
/*
* Copyright 2007 Nouveau Project
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include "nouveau_private.h"
#if NOUVEAU_DRM_HEADER_PATCHLEVEL != 12
#error nouveau_drm.h does not match expected patchlevel, update libdrm.
#endif
int
nouveau_device_open_existing(struct nouveau_device **dev, int close,
int fd, drm_context_t ctx)
{
struct nouveau_device_priv *nvdev;
drmVersionPtr ver;
uint64_t value;
int ret;
if (!dev || *dev)
return -EINVAL;
ver = drmGetVersion(fd);
if (!ver || ver->version_patchlevel != NOUVEAU_DRM_HEADER_PATCHLEVEL)
return -EINVAL;
drmFreeVersion(ver);
nvdev = calloc(1, sizeof(*nvdev));
if (!nvdev)
return -ENOMEM;
nvdev->fd = fd;
nvdev->ctx = ctx;
nvdev->needs_close = close;
ret = drmCommandNone(nvdev->fd, DRM_NOUVEAU_CARD_INIT);
if (ret) {
nouveau_device_close((void *)&nvdev);
return ret;
}
ret = nouveau_device_get_param(&nvdev->base,
NOUVEAU_GETPARAM_MM_ENABLED, &value);
if (ret) {
nouveau_device_close((void *)&nvdev);
return ret;
}
nvdev->mm_enabled = value;
ret = nouveau_device_get_param(&nvdev->base,
NOUVEAU_GETPARAM_VM_VRAM_BASE, &value);
if (ret) {
nouveau_device_close((void *)&nvdev);
return ret;
}
nvdev->base.vm_vram_base = value;
ret = nouveau_device_get_param(&nvdev->base,
NOUVEAU_GETPARAM_FB_SIZE, &value);
if (ret) {
nouveau_device_close((void *)&nvdev);
return ret;
}
nvdev->vram_aper_size = value;
ret = nouveau_device_get_param(&nvdev->base,
NOUVEAU_GETPARAM_AGP_SIZE, &value);
if (ret) {
nouveau_device_close((void *)&nvdev);
return ret;
}
nvdev->gart_aper_size = value;
ret = nouveau_bo_init(&nvdev->base);
if (ret) {
nouveau_device_close((void *)&nvdev);
return ret;
}
ret = nouveau_device_get_param(&nvdev->base,
NOUVEAU_GETPARAM_CHIPSET_ID, &value);
if (ret) {
nouveau_device_close((void *)&nvdev);
return ret;
}
nvdev->base.chipset = value;
*dev = &nvdev->base;
return 0;
}
int
nouveau_device_open(struct nouveau_device **dev, const char *busid)
{
drm_context_t ctx;
int fd, ret;
if (!dev || *dev)
return -EINVAL;
fd = drmOpen("nouveau", busid);
if (fd < 0)
return -EINVAL;
ret = drmCreateContext(fd, &ctx);
if (ret) {
drmClose(fd);
return ret;
}
ret = nouveau_device_open_existing(dev, 1, fd, ctx);
if (ret) {
drmDestroyContext(fd, ctx);
drmClose(fd);
return ret;
}
return 0;
}
void
nouveau_device_close(struct nouveau_device **dev)
{
struct nouveau_device_priv *nvdev;
if (!dev || !*dev)
return;
nvdev = nouveau_device(*dev);
*dev = NULL;
nouveau_bo_takedown(&nvdev->base);
if (nvdev->needs_close) {
drmDestroyContext(nvdev->fd, nvdev->ctx);
drmClose(nvdev->fd);
}
free(nvdev);
}
int
nouveau_device_get_param(struct nouveau_device *dev,
uint64_t param, uint64_t *value)
{
struct nouveau_device_priv *nvdev = nouveau_device(dev);
struct drm_nouveau_getparam g;
int ret;
if (!nvdev || !value)
return -EINVAL;
g.param = param;
ret = drmCommandWriteRead(nvdev->fd, DRM_NOUVEAU_GETPARAM,
&g, sizeof(g));
if (ret)
return ret;
*value = g.value;
return 0;
}
int
nouveau_device_set_param(struct nouveau_device *dev,
uint64_t param, uint64_t value)
{
struct nouveau_device_priv *nvdev = nouveau_device(dev);
struct drm_nouveau_setparam s;
int ret;
if (!nvdev)
return -EINVAL;
s.param = param;
s.value = value;
ret = drmCommandWriteRead(nvdev->fd, DRM_NOUVEAU_SETPARAM,
&s, sizeof(s));
if (ret)
return ret;
return 0;
}

View File

@ -0,0 +1,31 @@
/*
* Copyright 2007 Nouveau Project
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef __NOUVEAU_DEVICE_H__
#define __NOUVEAU_DEVICE_H__
struct nouveau_device {
unsigned chipset;
uint64_t vm_vram_base;
};
#endif

View File

@ -0,0 +1,217 @@
/*
* Copyright 2007 Nouveau Project
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <stdint.h>
#include <stdio.h>
#include <assert.h>
#include <errno.h>
#include "nouveau_drmif.h"
#include "nouveau_dma.h"
static inline uint32_t
READ_GET(struct nouveau_channel_priv *nvchan)
{
return *nvchan->get;
}
static inline void
WRITE_PUT(struct nouveau_channel_priv *nvchan, uint32_t val)
{
uint32_t put = ((val << 2) + nvchan->dma->base);
volatile int dum;
NOUVEAU_DMA_BARRIER;
dum = nvchan->pushbuf[0];
dum = READ_GET(nvchan);
*nvchan->put = put;
nvchan->dma->put = val;
#ifdef NOUVEAU_DMA_TRACE
printf("WRITE_PUT %d/0x%08x\n", nvchan->drm.channel, put);
#endif
NOUVEAU_DMA_BARRIER;
}
static inline int
LOCAL_GET(struct nouveau_dma_priv *dma, uint32_t *val)
{
uint32_t get = *val;
if (get >= dma->base && get <= (dma->base + (dma->max << 2))) {
*val = (get - dma->base) >> 2;
return 1;
}
return 0;
}
void
nouveau_dma_channel_init(struct nouveau_channel *chan)
{
struct nouveau_channel_priv *nvchan = nouveau_channel(chan);
int i;
nvchan->dma = &nvchan->struct_dma;
nvchan->dma->base = nvchan->drm.put_base;
nvchan->dma->cur = nvchan->dma->put = 0;
nvchan->dma->max = (nvchan->drm.cmdbuf_size >> 2) - 2;
nvchan->dma->free = nvchan->dma->max - nvchan->dma->cur;
RING_SPACE_CH(chan, RING_SKIPS);
for (i = 0; i < RING_SKIPS; i++)
OUT_RING_CH(chan, 0);
}
#define CHECK_TIMEOUT() do { \
if ((NOUVEAU_TIME_MSEC() - t_start) > NOUVEAU_DMA_TIMEOUT) \
return - EBUSY; \
} while(0)
int
nouveau_dma_wait(struct nouveau_channel *chan, unsigned size)
{
struct nouveau_channel_priv *nvchan = nouveau_channel(chan);
struct nouveau_dma_priv *dma = nvchan->dma;
uint32_t get, t_start;
FIRE_RING_CH(chan);
t_start = NOUVEAU_TIME_MSEC();
while (dma->free < size) {
CHECK_TIMEOUT();
get = READ_GET(nvchan);
if (!LOCAL_GET(dma, &get))
continue;
if (dma->put >= get) {
dma->free = dma->max - dma->cur;
if (dma->free < size) {
#ifdef NOUVEAU_DMA_DEBUG
dma->push_free = 1;
#endif
OUT_RING_CH(chan, 0x20000000 | dma->base);
if (get <= RING_SKIPS) {
/*corner case - will be idle*/
if (dma->put <= RING_SKIPS)
WRITE_PUT(nvchan,
RING_SKIPS + 1);
do {
CHECK_TIMEOUT();
get = READ_GET(nvchan);
if (!LOCAL_GET(dma, &get))
get = 0;
} while (get <= RING_SKIPS);
}
WRITE_PUT(nvchan, RING_SKIPS);
dma->cur = dma->put = RING_SKIPS;
dma->free = get - (RING_SKIPS + 1);
}
} else {
dma->free = get - dma->cur - 1;
}
}
return 0;
}
#ifdef NOUVEAU_DMA_DUMP_POSTRELOC_PUSHBUF
static void
nouveau_dma_parse_pushbuf(struct nouveau_channel *chan, int get, int put)
{
struct nouveau_channel_priv *nvchan = nouveau_channel(chan);
unsigned mthd_count = 0;
while (get != put) {
uint32_t gpuget = (get << 2) + nvchan->drm.put_base;
uint32_t data;
if (get < 0 || get >= nvchan->drm.cmdbuf_size)
assert(0);
data = nvchan->pushbuf[get++];
if (mthd_count) {
printf("0x%08x 0x%08x\n", gpuget, data);
mthd_count--;
continue;
}
switch (data & 0x60000000) {
case 0x00000000:
mthd_count = (data >> 18) & 0x7ff;
printf("0x%08x 0x%08x MTHD "
"Sc %d Mthd 0x%04x Size %d\n",
gpuget, data, (data>>13) & 7, data & 0x1ffc,
mthd_count);
break;
case 0x20000000:
get = (data & 0x1ffffffc) >> 2;
printf("0x%08x 0x%08x JUMP 0x%08x\n",
gpuget, data, data & 0x1ffffffc);
continue;
case 0x40000000:
mthd_count = (data >> 18) & 0x7ff;
printf("0x%08x 0x%08x NINC "
"Sc %d Mthd 0x%04x Size %d\n",
gpuget, data, (data>>13) & 7, data & 0x1ffc,
mthd_count);
break;
case 0x60000000:
/* DMA_OPCODE_CALL apparently, doesn't seem to work on
* my NV40 at least..
*/
/* fall-through */
default:
printf("DMA_PUSHER 0x%08x 0x%08x\n", gpuget, data);
assert(0);
}
}
}
#endif
void
nouveau_dma_kickoff(struct nouveau_channel *chan)
{
struct nouveau_channel_priv *nvchan = nouveau_channel(chan);
struct nouveau_dma_priv *dma = nvchan->dma;
if (dma->cur == dma->put)
return;
#ifdef NOUVEAU_DMA_DEBUG
if (dma->push_free) {
printf("Packet incomplete: %d left\n", dma->push_free);
return;
}
#endif
#ifdef NOUVEAU_DMA_DUMP_POSTRELOC_PUSHBUF
nouveau_dma_parse_pushbuf(chan, dma->put, dma->cur);
#endif
WRITE_PUT(nvchan, dma->cur);
}

View File

@ -0,0 +1,154 @@
/*
* Copyright 2007 Nouveau Project
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef __NOUVEAU_DMA_H__
#define __NOUVEAU_DMA_H__
#include <string.h>
#include "nouveau_private.h"
//#define NOUVEAU_DMA_DEBUG
//#define NOUVEAU_DMA_TRACE
//#define NOUVEAU_DMA_DUMP_POSTRELOC_PUSHBUF
#if defined(__amd64__)
#define NOUVEAU_DMA_BARRIER asm volatile("lock; addl $0,0(%%rsp)" ::: "memory")
#elif defined(__i386__)
#define NOUVEAU_DMA_BARRIER asm volatile("lock; addl $0,0(%%esp)" ::: "memory")
#else
#define NOUVEAU_DMA_BARRIER
#endif
#define NOUVEAU_DMA_TIMEOUT 2000
#define NOUVEAU_TIME_MSEC() 0
#define RING_SKIPS 8
extern int nouveau_dma_wait(struct nouveau_channel *chan, unsigned size);
extern void nouveau_dma_subc_bind(struct nouveau_grobj *);
extern void nouveau_dma_channel_init(struct nouveau_channel *);
extern void nouveau_dma_kickoff(struct nouveau_channel *);
#ifdef NOUVEAU_DMA_DEBUG
static char faulty[1024];
#endif
static inline void
nouveau_dma_out(struct nouveau_channel *chan, uint32_t data)
{
struct nouveau_channel_priv *nvchan = nouveau_channel(chan);
struct nouveau_dma_priv *dma = nvchan->dma;
#ifdef NOUVEAU_DMA_DEBUG
if (dma->push_free == 0) {
printf("No space left in packet at %s\n", faulty);
return;
}
dma->push_free--;
#endif
#ifdef NOUVEAU_DMA_TRACE
{
uint32_t offset = (dma->cur << 2) + dma->base;
printf("\tOUT_RING %d/0x%08x -> 0x%08x\n",
nvchan->drm.channel, offset, data);
}
#endif
nvchan->pushbuf[dma->cur + (dma->base - nvchan->drm.put_base)/4] = data;
dma->cur++;
}
static inline void
nouveau_dma_outp(struct nouveau_channel *chan, uint32_t *ptr, int size)
{
struct nouveau_channel_priv *nvchan = nouveau_channel(chan);
struct nouveau_dma_priv *dma = nvchan->dma;
(void)dma;
#ifdef NOUVEAU_DMA_DEBUG
if (dma->push_free < size) {
printf("Packet too small. Free=%d, Need=%d\n",
dma->push_free, size);
return;
}
#endif
#ifdef NOUVEAU_DMA_TRACE
while (size--) {
nouveau_dma_out(chan, *ptr);
ptr++;
}
#else
memcpy(&nvchan->pushbuf[dma->cur], ptr, size << 2);
#ifdef NOUVEAU_DMA_DEBUG
dma->push_free -= size;
#endif
dma->cur += size;
#endif
}
static inline void
nouveau_dma_space(struct nouveau_channel *chan, unsigned size)
{
struct nouveau_channel_priv *nvchan = nouveau_channel(chan);
struct nouveau_dma_priv *dma = nvchan->dma;
if (dma->free < size) {
if (nouveau_dma_wait(chan, size) && chan->hang_notify)
chan->hang_notify(chan);
}
dma->free -= size;
#ifdef NOUVEAU_DMA_DEBUG
dma->push_free = size;
#endif
}
static inline void
nouveau_dma_begin(struct nouveau_channel *chan, struct nouveau_grobj *grobj,
int method, int size, const char* file, int line)
{
struct nouveau_channel_priv *nvchan = nouveau_channel(chan);
struct nouveau_dma_priv *dma = nvchan->dma;
(void)dma;
#ifdef NOUVEAU_DMA_TRACE
printf("BEGIN_RING %d/%08x/%d/0x%04x/%d\n", nvchan->drm.channel,
grobj->handle, grobj->subc, method, size);
#endif
#ifdef NOUVEAU_DMA_DEBUG
if (dma->push_free) {
printf("Previous packet incomplete: %d left at %s\n",
dma->push_free, faulty);
return;
}
sprintf(faulty,"%s:%d",file,line);
#endif
nouveau_dma_space(chan, (size + 1));
nouveau_dma_out(chan, (size << 18) | (grobj->subc << 13) | method);
}
#define RING_SPACE_CH(ch,sz) nouveau_dma_space((ch), (sz))
#define BEGIN_RING_CH(ch,gr,m,sz) nouveau_dma_begin((ch), (gr), (m), (sz), __FUNCTION__, __LINE__ )
#define OUT_RING_CH(ch, data) nouveau_dma_out((ch), (data))
#define OUT_RINGp_CH(ch,ptr,dwords) nouveau_dma_outp((ch), (void*)(ptr), \
(dwords))
#define FIRE_RING_CH(ch) nouveau_dma_kickoff((ch))
#define WAIT_RING_CH(ch,sz) nouveau_dma_wait((ch), (sz))
#endif

View File

@ -0,0 +1,62 @@
/*
* Copyright 2008 Nouveau Project
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef __NOUVEAU_DRMIF_H__
#define __NOUVEAU_DRMIF_H__
#include <stdint.h>
#include <xf86drm.h>
#include "nouveau_device.h"
struct nouveau_device_priv {
struct nouveau_device base;
int fd;
drm_context_t ctx;
drmLock *lock;
int needs_close;
int mm_enabled;
/*XXX: move to nouveau_device when interface gets bumped */
uint64_t vram_aper_size;
uint64_t gart_aper_size;
};
#define nouveau_device(n) ((struct nouveau_device_priv *)(n))
int
nouveau_device_open_existing(struct nouveau_device **, int close,
int fd, drm_context_t ctx);
int
nouveau_device_open(struct nouveau_device **, const char *busid);
void
nouveau_device_close(struct nouveau_device **);
int
nouveau_device_get_param(struct nouveau_device *, uint64_t param, uint64_t *v);
int
nouveau_device_set_param(struct nouveau_device *, uint64_t param, uint64_t val);
#endif

View File

@ -0,0 +1,243 @@
/*
* Copyright 2007 Nouveau Project
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <assert.h>
#include "nouveau_private.h"
#include "nouveau_dma.h"
static void
nouveau_fence_del_unsignalled(struct nouveau_fence *fence)
{
struct nouveau_channel_priv *nvchan = nouveau_channel(fence->channel);
struct nouveau_fence *le;
if (nvchan->fence_head == fence) {
nvchan->fence_head = nouveau_fence(fence)->next;
if (nvchan->fence_head == NULL)
nvchan->fence_tail = NULL;
return;
}
le = nvchan->fence_head;
while (le && nouveau_fence(le)->next != fence)
le = nouveau_fence(le)->next;
assert(le && nouveau_fence(le)->next == fence);
nouveau_fence(le)->next = nouveau_fence(fence)->next;
if (nvchan->fence_tail == fence)
nvchan->fence_tail = le;
}
static void
nouveau_fence_del(struct nouveau_fence **fence)
{
struct nouveau_fence_priv *nvfence;
if (!fence || !*fence)
return;
nvfence = nouveau_fence(*fence);
*fence = NULL;
if (--nvfence->refcount)
return;
if (nvfence->emitted && !nvfence->signalled) {
if (nvfence->signal_cb) {
nvfence->refcount++;
nouveau_fence_wait((void *)&nvfence);
return;
}
nouveau_fence_del_unsignalled(&nvfence->base);
}
free(nvfence);
}
int
nouveau_fence_new(struct nouveau_channel *chan, struct nouveau_fence **fence)
{
struct nouveau_fence_priv *nvfence;
if (!chan || !fence || *fence)
return -EINVAL;
nvfence = calloc(1, sizeof(struct nouveau_fence_priv));
if (!nvfence)
return -ENOMEM;
nvfence->base.channel = chan;
nvfence->refcount = 1;
*fence = &nvfence->base;
return 0;
}
int
nouveau_fence_ref(struct nouveau_fence *ref, struct nouveau_fence **fence)
{
if (!fence)
return -EINVAL;
if (ref)
nouveau_fence(ref)->refcount++;
if (*fence)
nouveau_fence_del(fence);
*fence = ref;
return 0;
}
int
nouveau_fence_signal_cb(struct nouveau_fence *fence, void (*func)(void *),
void *priv)
{
struct nouveau_fence_priv *nvfence = nouveau_fence(fence);
struct nouveau_fence_cb *cb;
if (!nvfence || !func)
return -EINVAL;
cb = malloc(sizeof(struct nouveau_fence_cb));
if (!cb)
return -ENOMEM;
cb->func = func;
cb->priv = priv;
cb->next = nvfence->signal_cb;
nvfence->signal_cb = cb;
return 0;
}
void
nouveau_fence_emit(struct nouveau_fence *fence)
{
struct nouveau_channel_priv *nvchan = nouveau_channel(fence->channel);
struct nouveau_fence_priv *nvfence = nouveau_fence(fence);
nvfence->emitted = 1;
nvfence->sequence = ++nvchan->fence_sequence;
if (nvfence->sequence == 0xffffffff)
printf("AII wrap unhandled\n");
if (!nvchan->fence_ntfy) {
/*XXX: assumes subc 0 is populated */
nouveau_dma_space(fence->channel, 2);
nouveau_dma_out (fence->channel, 0x00040050);
nouveau_dma_out (fence->channel, nvfence->sequence);
}
nouveau_dma_kickoff(fence->channel);
if (nvchan->fence_tail) {
nouveau_fence(nvchan->fence_tail)->next = fence;
} else {
nvchan->fence_head = fence;
}
nvchan->fence_tail = fence;
}
static void
nouveau_fence_flush_seq(struct nouveau_channel *chan, uint32_t sequence)
{
struct nouveau_channel_priv *nvchan = nouveau_channel(chan);
while (nvchan->fence_head) {
struct nouveau_fence_priv *nvfence;
nvfence = nouveau_fence(nvchan->fence_head);
if (nvfence->sequence > sequence)
break;
nouveau_fence_del_unsignalled(&nvfence->base);
nvfence->signalled = 1;
if (nvfence->signal_cb) {
struct nouveau_fence *fence = NULL;
nouveau_fence_ref(&nvfence->base, &fence);
while (nvfence->signal_cb) {
struct nouveau_fence_cb *cb;
cb = nvfence->signal_cb;
nvfence->signal_cb = cb->next;
cb->func(cb->priv);
free(cb);
}
nouveau_fence_ref(NULL, &fence);
}
}
}
void
nouveau_fence_flush(struct nouveau_channel *chan)
{
struct nouveau_channel_priv *nvchan = nouveau_channel(chan);
if (!nvchan->fence_ntfy)
nouveau_fence_flush_seq(chan, *nvchan->ref_cnt);
}
int
nouveau_fence_wait(struct nouveau_fence **fence)
{
struct nouveau_fence_priv *nvfence;
struct nouveau_channel_priv *nvchan;
if (!fence)
return -EINVAL;
nvfence = nouveau_fence(*fence);
if (!nvfence)
return 0;
nvchan = nouveau_channel(nvfence->base.channel);
if (nvfence->emitted) {
if (!nvfence->signalled && nvchan->fence_ntfy) {
struct nouveau_channel *chan = &nvchan->base;
int ret;
/*XXX: NV04/NV05: Full sync + flush all fences */
nouveau_notifier_reset(nvchan->fence_ntfy, 0);
BEGIN_RING(chan, nvchan->fence_grobj, 0x0104, 1);
OUT_RING (chan, 0);
BEGIN_RING(chan, nvchan->fence_grobj, 0x0100, 1);
OUT_RING (chan, 0);
FIRE_RING (chan);
ret = nouveau_notifier_wait_status(nvchan->fence_ntfy,
0, 0, 2.0);
if (ret)
return ret;
nouveau_fence_flush_seq(chan, nvchan->fence_sequence);
}
while (!nvfence->signalled)
nouveau_fence_flush(nvfence->base.channel);
}
nouveau_fence_ref(NULL, fence);
return 0;
}

View File

@ -0,0 +1,138 @@
/*
* Copyright 2007 Nouveau Project
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <stdlib.h>
#include <errno.h>
#include "nouveau_private.h"
int
nouveau_grobj_alloc(struct nouveau_channel *chan, uint32_t handle,
int class, struct nouveau_grobj **grobj)
{
struct nouveau_device_priv *nvdev = nouveau_device(chan->device);
struct nouveau_grobj_priv *nvgrobj;
struct drm_nouveau_grobj_alloc g;
int ret;
if (!nvdev || !grobj || *grobj)
return -EINVAL;
nvgrobj = calloc(1, sizeof(*nvgrobj));
if (!nvgrobj)
return -ENOMEM;
nvgrobj->base.channel = chan;
nvgrobj->base.handle = handle;
nvgrobj->base.grclass = class;
nvgrobj->base.bound = NOUVEAU_GROBJ_UNBOUND;
nvgrobj->base.subc = -1;
g.channel = chan->id;
g.handle = handle;
g.class = class;
ret = drmCommandWrite(nvdev->fd, DRM_NOUVEAU_GROBJ_ALLOC,
&g, sizeof(g));
if (ret) {
nouveau_grobj_free((void *)&nvgrobj);
return ret;
}
*grobj = &nvgrobj->base;
return 0;
}
int
nouveau_grobj_ref(struct nouveau_channel *chan, uint32_t handle,
struct nouveau_grobj **grobj)
{
struct nouveau_grobj_priv *nvgrobj;
if (!chan || !grobj || *grobj)
return -EINVAL;
nvgrobj = calloc(1, sizeof(struct nouveau_grobj_priv));
if (!nvgrobj)
return -ENOMEM;
nvgrobj->base.channel = chan;
nvgrobj->base.handle = handle;
nvgrobj->base.grclass = 0;
*grobj = &nvgrobj->base;
return 0;
}
void
nouveau_grobj_free(struct nouveau_grobj **grobj)
{
struct nouveau_device_priv *nvdev;
struct nouveau_channel_priv *chan;
struct nouveau_grobj_priv *nvgrobj;
if (!grobj || !*grobj)
return;
nvgrobj = nouveau_grobj(*grobj);
*grobj = NULL;
chan = nouveau_channel(nvgrobj->base.channel);
nvdev = nouveau_device(chan->base.device);
if (nvgrobj->base.grclass) {
struct drm_nouveau_gpuobj_free f;
f.channel = chan->drm.channel;
f.handle = nvgrobj->base.handle;
drmCommandWrite(nvdev->fd, DRM_NOUVEAU_GPUOBJ_FREE,
&f, sizeof(f));
}
free(nvgrobj);
}
void
nouveau_grobj_autobind(struct nouveau_grobj *grobj)
{
struct nouveau_subchannel *subc = NULL;
int i;
for (i = 0; i < 8; i++) {
struct nouveau_subchannel *scc = &grobj->channel->subc[i];
if (scc->gr && scc->gr->bound == NOUVEAU_GROBJ_BOUND_EXPLICIT)
continue;
if (!subc || scc->sequence < subc->sequence)
subc = scc;
}
if (subc->gr) {
subc->gr->bound = NOUVEAU_GROBJ_UNBOUND;
subc->gr->subc = -1;
}
subc->gr = grobj;
subc->gr->bound = NOUVEAU_GROBJ_BOUND;
subc->gr->subc = subc - &grobj->channel->subc[0];
BEGIN_RING(grobj->channel, grobj, 0x0000, 1);
OUT_RING (grobj->channel, grobj->handle);
}

View File

@ -0,0 +1,48 @@
/*
* Copyright 2007 Nouveau Project
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef __NOUVEAU_GROBJ_H__
#define __NOUVEAU_GROBJ_H__
#include "nouveau_channel.h"
struct nouveau_grobj {
struct nouveau_channel *channel;
int grclass;
uint32_t handle;
enum {
NOUVEAU_GROBJ_UNBOUND = 0,
NOUVEAU_GROBJ_BOUND = 1,
NOUVEAU_GROBJ_BOUND_EXPLICIT = 2
} bound;
int subc;
};
int nouveau_grobj_alloc(struct nouveau_channel *, uint32_t handle,
int class, struct nouveau_grobj **);
int nouveau_grobj_ref(struct nouveau_channel *, uint32_t handle,
struct nouveau_grobj **);
void nouveau_grobj_free(struct nouveau_grobj **);
void nouveau_grobj_autobind(struct nouveau_grobj *);
#endif

View File

@ -0,0 +1,146 @@
/*
* Copyright 2007 Nouveau Project
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <stdlib.h>
#include <errno.h>
#include <sys/time.h>
#include "nouveau_private.h"
#define NOTIFIER(__v) \
struct nouveau_notifier_priv *nvnotify = nouveau_notifier(notifier); \
volatile uint32_t *__v = (uint32_t *)((char *)nvnotify->map + (id * 32))
int
nouveau_notifier_alloc(struct nouveau_channel *chan, uint32_t handle,
int count, struct nouveau_notifier **notifier)
{
struct nouveau_notifier_priv *nvnotify;
int ret;
if (!chan || !notifier || *notifier)
return -EINVAL;
nvnotify = calloc(1, sizeof(struct nouveau_notifier_priv));
if (!nvnotify)
return -ENOMEM;
nvnotify->base.channel = chan;
nvnotify->base.handle = handle;
nvnotify->drm.channel = chan->id;
nvnotify->drm.handle = handle;
nvnotify->drm.count = count;
if ((ret = drmCommandWriteRead(nouveau_device(chan->device)->fd,
DRM_NOUVEAU_NOTIFIEROBJ_ALLOC,
&nvnotify->drm,
sizeof(nvnotify->drm)))) {
nouveau_notifier_free((void *)&nvnotify);
return ret;
}
nvnotify->map = (char *)nouveau_channel(chan)->notifier_block +
nvnotify->drm.offset;
*notifier = &nvnotify->base;
return 0;
}
void
nouveau_notifier_free(struct nouveau_notifier **notifier)
{
struct nouveau_notifier_priv *nvnotify;
struct nouveau_channel_priv *nvchan;
struct nouveau_device_priv *nvdev;
struct drm_nouveau_gpuobj_free f;
if (!notifier || !*notifier)
return;
nvnotify = nouveau_notifier(*notifier);
*notifier = NULL;
nvchan = nouveau_channel(nvnotify->base.channel);
nvdev = nouveau_device(nvchan->base.device);
f.channel = nvchan->drm.channel;
f.handle = nvnotify->base.handle;
drmCommandWrite(nvdev->fd, DRM_NOUVEAU_GPUOBJ_FREE, &f, sizeof(f));
free(nvnotify);
}
void
nouveau_notifier_reset(struct nouveau_notifier *notifier, int id)
{
NOTIFIER(n);
n[NV_NOTIFY_TIME_0 /4] = 0x00000000;
n[NV_NOTIFY_TIME_1 /4] = 0x00000000;
n[NV_NOTIFY_RETURN_VALUE/4] = 0x00000000;
n[NV_NOTIFY_STATE /4] = (NV_NOTIFY_STATE_STATUS_IN_PROCESS <<
NV_NOTIFY_STATE_STATUS_SHIFT);
}
uint32_t
nouveau_notifier_status(struct nouveau_notifier *notifier, int id)
{
NOTIFIER(n);
return n[NV_NOTIFY_STATE/4] >> NV_NOTIFY_STATE_STATUS_SHIFT;
}
uint32_t
nouveau_notifier_return_val(struct nouveau_notifier *notifier, int id)
{
NOTIFIER(n);
return n[NV_NOTIFY_RETURN_VALUE/4];
}
static inline double
gettime(void)
{
struct timeval tv;
gettimeofday(&tv, NULL);
return (double)tv.tv_sec + tv.tv_usec / 1000000.0;
}
int
nouveau_notifier_wait_status(struct nouveau_notifier *notifier, int id,
uint32_t status, double timeout)
{
NOTIFIER(n);
double time = 0, t_start = gettime();
while (time <= timeout) {
uint32_t v;
v = n[NV_NOTIFY_STATE/4] >> NV_NOTIFY_STATE_STATUS_SHIFT;
if (v == status)
return 0;
if (timeout)
time = gettime() - t_start;
}
return -EBUSY;
}

View File

@ -0,0 +1,63 @@
/*
* Copyright 2007 Nouveau Project
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef __NOUVEAU_NOTIFIER_H__
#define __NOUVEAU_NOTIFIER_H__
#define NV_NOTIFIER_SIZE 32
#define NV_NOTIFY_TIME_0 0x00000000
#define NV_NOTIFY_TIME_1 0x00000004
#define NV_NOTIFY_RETURN_VALUE 0x00000008
#define NV_NOTIFY_STATE 0x0000000C
#define NV_NOTIFY_STATE_STATUS_MASK 0xFF000000
#define NV_NOTIFY_STATE_STATUS_SHIFT 24
#define NV_NOTIFY_STATE_STATUS_COMPLETED 0x00
#define NV_NOTIFY_STATE_STATUS_IN_PROCESS 0x01
#define NV_NOTIFY_STATE_ERROR_CODE_MASK 0x0000FFFF
#define NV_NOTIFY_STATE_ERROR_CODE_SHIFT 0
struct nouveau_notifier {
struct nouveau_channel *channel;
uint32_t handle;
};
int
nouveau_notifier_alloc(struct nouveau_channel *, uint32_t handle, int count,
struct nouveau_notifier **);
void
nouveau_notifier_free(struct nouveau_notifier **);
void
nouveau_notifier_reset(struct nouveau_notifier *, int id);
uint32_t
nouveau_notifier_status(struct nouveau_notifier *, int id);
uint32_t
nouveau_notifier_return_val(struct nouveau_notifier *, int id);
int
nouveau_notifier_wait_status(struct nouveau_notifier *, int id, uint32_t status,
double timeout);
#endif

View File

@ -0,0 +1,203 @@
/*
* Copyright 2007 Nouveau Project
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef __NOUVEAU_PRIVATE_H__
#define __NOUVEAU_PRIVATE_H__
#include <stdint.h>
#include <xf86drm.h>
#include <nouveau_drm.h>
#include "nouveau_drmif.h"
#include "nouveau_device.h"
#include "nouveau_channel.h"
#include "nouveau_grobj.h"
#include "nouveau_notifier.h"
#include "nouveau_bo.h"
#include "nouveau_resource.h"
#include "nouveau_pushbuf.h"
#define NOUVEAU_PUSHBUF_MAX_BUFFERS 1024
#define NOUVEAU_PUSHBUF_MAX_RELOCS 1024
struct nouveau_pushbuf_priv {
struct nouveau_pushbuf base;
int use_cal;
struct nouveau_bo *buffer;
unsigned *pushbuf;
unsigned size;
struct drm_nouveau_gem_pushbuf_bo *buffers;
unsigned nr_buffers;
struct drm_nouveau_gem_pushbuf_reloc *relocs;
unsigned nr_relocs;
/*XXX: nomm */
struct nouveau_fence *fence;
};
#define nouveau_pushbuf(n) ((struct nouveau_pushbuf_priv *)(n))
#define pbbo_to_ptr(o) ((uint64_t)(unsigned long)(o))
#define ptr_to_pbbo(h) ((struct nouveau_pushbuf_bo *)(unsigned long)(h))
#define pbrel_to_ptr(o) ((uint64_t)(unsigned long)(o))
#define ptr_to_pbrel(h) ((struct nouveau_pushbuf_reloc *)(unsigned long)(h))
#define bo_to_ptr(o) ((uint64_t)(unsigned long)(o))
#define ptr_to_bo(h) ((struct nouveau_bo_priv *)(unsigned long)(h))
int
nouveau_pushbuf_init(struct nouveau_channel *);
struct nouveau_dma_priv {
uint32_t base;
uint32_t max;
uint32_t cur;
uint32_t put;
uint32_t free;
int push_free;
} dma;
struct nouveau_channel_priv {
struct nouveau_channel base;
struct drm_nouveau_channel_alloc drm;
void *notifier_block;
struct nouveau_pushbuf_priv pb;
/*XXX: nomm */
volatile uint32_t *user, *put, *get, *ref_cnt;
uint32_t *pushbuf;
struct nouveau_dma_priv struct_dma;
struct nouveau_dma_priv *dma;
struct nouveau_fence *fence_head;
struct nouveau_fence *fence_tail;
uint32_t fence_sequence;
struct nouveau_grobj *fence_grobj;
struct nouveau_notifier *fence_ntfy;
};
#define nouveau_channel(n) ((struct nouveau_channel_priv *)(n))
struct nouveau_fence {
struct nouveau_channel *channel;
};
struct nouveau_fence_cb {
struct nouveau_fence_cb *next;
void (*func)(void *);
void *priv;
};
struct nouveau_fence_priv {
struct nouveau_fence base;
int refcount;
struct nouveau_fence *next;
struct nouveau_fence_cb *signal_cb;
uint32_t sequence;
int emitted;
int signalled;
};
#define nouveau_fence(n) ((struct nouveau_fence_priv *)(n))
int
nouveau_fence_new(struct nouveau_channel *, struct nouveau_fence **);
int
nouveau_fence_ref(struct nouveau_fence *, struct nouveau_fence **);
int
nouveau_fence_signal_cb(struct nouveau_fence *, void (*)(void *), void *);
void
nouveau_fence_emit(struct nouveau_fence *);
int
nouveau_fence_wait(struct nouveau_fence **);
void
nouveau_fence_flush(struct nouveau_channel *);
struct nouveau_grobj_priv {
struct nouveau_grobj base;
};
#define nouveau_grobj(n) ((struct nouveau_grobj_priv *)(n))
struct nouveau_notifier_priv {
struct nouveau_notifier base;
struct drm_nouveau_notifierobj_alloc drm;
volatile void *map;
};
#define nouveau_notifier(n) ((struct nouveau_notifier_priv *)(n))
struct nouveau_bo_priv {
struct nouveau_bo base;
int refcount;
/* Buffer configuration + usage hints */
unsigned flags;
unsigned size;
unsigned align;
int user;
/* Tracking */
struct drm_nouveau_gem_pushbuf_bo *pending;
struct nouveau_channel *pending_channel;
int write_marker;
/* Userspace object */
void *sysmem;
/* Kernel object */
uint32_t global_handle;
drm_handle_t handle;
void *map;
/* Last known information from kernel on buffer status */
int pinned;
uint64_t offset;
uint32_t domain;
/*XXX: nomm stuff */
struct nouveau_fence *fence;
struct nouveau_fence *wr_fence;
};
#define nouveau_bo(n) ((struct nouveau_bo_priv *)(n))
int
nouveau_bo_init(struct nouveau_device *);
void
nouveau_bo_takedown(struct nouveau_device *);
struct drm_nouveau_gem_pushbuf_bo *
nouveau_bo_emit_buffer(struct nouveau_channel *, struct nouveau_bo *);
int
nouveau_bo_validate_nomm(struct nouveau_bo_priv *, uint32_t);
#include "nouveau_dma.h"
#endif

View File

@ -0,0 +1,276 @@
/*
* Copyright 2007 Nouveau Project
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <assert.h>
#include "nouveau_private.h"
#include "nouveau_dma.h"
#define PB_BUFMGR_DWORDS (4096 / 2)
#define PB_MIN_USER_DWORDS 2048
static uint32_t
nouveau_pushbuf_calc_reloc(struct drm_nouveau_gem_pushbuf_bo *pbbo,
struct drm_nouveau_gem_pushbuf_reloc *r,
int mm_enabled)
{
uint32_t push = 0;
const unsigned is_vram = mm_enabled ? NOUVEAU_GEM_DOMAIN_VRAM :
NOUVEAU_BO_VRAM;
if (r->flags & NOUVEAU_GEM_RELOC_LOW)
push = (pbbo->presumed_offset + r->data);
else
if (r->flags & NOUVEAU_GEM_RELOC_HIGH)
push = (pbbo->presumed_offset + r->data) >> 32;
else
push = r->data;
if (r->flags & NOUVEAU_GEM_RELOC_OR) {
if (pbbo->presumed_domain & is_vram)
push |= r->vor;
else
push |= r->tor;
}
return push;
}
int
nouveau_pushbuf_emit_reloc(struct nouveau_channel *chan, void *ptr,
struct nouveau_bo *bo, uint32_t data, uint32_t flags,
uint32_t vor, uint32_t tor)
{
struct nouveau_device_priv *nvdev = nouveau_device(chan->device);
struct nouveau_pushbuf_priv *nvpb = nouveau_pushbuf(chan->pushbuf);
struct drm_nouveau_gem_pushbuf_reloc *r;
struct drm_nouveau_gem_pushbuf_bo *pbbo;
uint32_t domains = 0;
if (nvpb->nr_relocs >= NOUVEAU_PUSHBUF_MAX_RELOCS)
return -ENOMEM;
if (nouveau_bo(bo)->user && (flags & NOUVEAU_BO_WR)) {
fprintf(stderr, "write to user buffer!!\n");
return -EINVAL;
}
pbbo = nouveau_bo_emit_buffer(chan, bo);
if (!pbbo)
return -ENOMEM;
if (flags & NOUVEAU_BO_VRAM)
domains |= NOUVEAU_GEM_DOMAIN_VRAM;
if (flags & NOUVEAU_BO_GART)
domains |= NOUVEAU_GEM_DOMAIN_GART;
pbbo->valid_domains &= domains;
assert(pbbo->valid_domains);
if (!nvdev->mm_enabled) {
struct nouveau_bo_priv *nvbo = nouveau_bo(bo);
nouveau_fence_ref(nvpb->fence, &nvbo->fence);
if (flags & NOUVEAU_BO_WR)
nouveau_fence_ref(nvpb->fence, &nvbo->wr_fence);
}
assert(flags & NOUVEAU_BO_RDWR);
if (flags & NOUVEAU_BO_RD) {
pbbo->read_domains |= domains;
}
if (flags & NOUVEAU_BO_WR) {
pbbo->write_domains |= domains;
nouveau_bo(bo)->write_marker = 1;
}
r = nvpb->relocs + nvpb->nr_relocs++;
r->bo_index = pbbo - nvpb->buffers;
r->reloc_index = (uint32_t *)ptr - nvpb->pushbuf;
r->flags = 0;
if (flags & NOUVEAU_BO_LOW)
r->flags |= NOUVEAU_GEM_RELOC_LOW;
if (flags & NOUVEAU_BO_HIGH)
r->flags |= NOUVEAU_GEM_RELOC_HIGH;
if (flags & NOUVEAU_BO_OR)
r->flags |= NOUVEAU_GEM_RELOC_OR;
r->data = data;
r->vor = vor;
r->tor = tor;
*(uint32_t *)ptr = (flags & NOUVEAU_BO_DUMMY) ? 0 :
nouveau_pushbuf_calc_reloc(pbbo, r, nvdev->mm_enabled);
return 0;
}
static int
nouveau_pushbuf_space(struct nouveau_channel *chan, unsigned min)
{
struct nouveau_channel_priv *nvchan = nouveau_channel(chan);
struct nouveau_pushbuf_priv *nvpb = &nvchan->pb;
if (nvpb->pushbuf) {
free(nvpb->pushbuf);
nvpb->pushbuf = NULL;
}
nvpb->size = min < PB_MIN_USER_DWORDS ? PB_MIN_USER_DWORDS : min;
nvpb->pushbuf = malloc(sizeof(uint32_t) * nvpb->size);
nvpb->base.channel = chan;
nvpb->base.remaining = nvpb->size;
nvpb->base.cur = nvpb->pushbuf;
if (!nouveau_device(chan->device)->mm_enabled) {
nouveau_fence_ref(NULL, &nvpb->fence);
nouveau_fence_new(chan, &nvpb->fence);
}
return 0;
}
int
nouveau_pushbuf_init(struct nouveau_channel *chan)
{
struct nouveau_channel_priv *nvchan = nouveau_channel(chan);
struct nouveau_pushbuf_priv *nvpb = &nvchan->pb;
nouveau_pushbuf_space(chan, 0);
nvpb->buffers = calloc(NOUVEAU_PUSHBUF_MAX_BUFFERS,
sizeof(struct drm_nouveau_gem_pushbuf_bo));
nvpb->relocs = calloc(NOUVEAU_PUSHBUF_MAX_RELOCS,
sizeof(struct drm_nouveau_gem_pushbuf_reloc));
chan->pushbuf = &nvpb->base;
return 0;
}
static int
nouveau_pushbuf_flush_nomm(struct nouveau_channel_priv *nvchan)
{
struct nouveau_pushbuf_priv *nvpb = &nvchan->pb;
struct drm_nouveau_gem_pushbuf_bo *bo = nvpb->buffers;
struct drm_nouveau_gem_pushbuf_reloc *reloc = nvpb->relocs;
unsigned b, r;
int ret;
for (b = 0; b < nvpb->nr_buffers; b++) {
struct nouveau_bo_priv *nvbo =
(void *)(unsigned long)bo[b].user_priv;
uint32_t flags = 0;
if (bo[b].valid_domains & NOUVEAU_GEM_DOMAIN_VRAM)
flags |= NOUVEAU_BO_VRAM;
if (bo[b].valid_domains & NOUVEAU_GEM_DOMAIN_GART)
flags |= NOUVEAU_BO_GART;
ret = nouveau_bo_validate_nomm(nvbo, flags);
if (ret)
return ret;
if (1 || bo[b].presumed_domain != nvbo->domain ||
bo[b].presumed_offset != nvbo->offset) {
bo[b].presumed_ok = 0;
bo[b].presumed_domain = nvbo->domain;
bo[b].presumed_offset = nvbo->offset;
}
}
for (r = 0; r < nvpb->nr_relocs; r++, reloc++) {
uint32_t push;
if (bo[reloc->bo_index].presumed_ok)
continue;
push = nouveau_pushbuf_calc_reloc(&bo[reloc->bo_index], reloc, 0);
nvpb->pushbuf[reloc->reloc_index] = push;
}
nouveau_dma_space(&nvchan->base, nvpb->size);
nouveau_dma_outp (&nvchan->base, nvpb->pushbuf, nvpb->size);
nouveau_fence_emit(nvpb->fence);
return 0;
}
int
nouveau_pushbuf_flush(struct nouveau_channel *chan, unsigned min)
{
struct nouveau_device_priv *nvdev = nouveau_device(chan->device);
struct nouveau_channel_priv *nvchan = nouveau_channel(chan);
struct nouveau_pushbuf_priv *nvpb = &nvchan->pb;
struct drm_nouveau_gem_pushbuf req;
unsigned i;
int ret;
if (nvpb->base.remaining == nvpb->size)
return 0;
nvpb->size -= nvpb->base.remaining;
if (nvdev->mm_enabled) {
req.channel = chan->id;
req.nr_dwords = nvpb->size;
req.dwords = (uint64_t)(unsigned long)nvpb->pushbuf;
req.nr_buffers = nvpb->nr_buffers;
req.buffers = (uint64_t)(unsigned long)nvpb->buffers;
req.nr_relocs = nvpb->nr_relocs;
req.relocs = (uint64_t)(unsigned long)nvpb->relocs;
ret = drmCommandWrite(nvdev->fd, DRM_NOUVEAU_GEM_PUSHBUF,
&req, sizeof(req));
} else {
nouveau_fence_flush(chan);
ret = nouveau_pushbuf_flush_nomm(nvchan);
}
assert(ret == 0);
/* Update presumed offset/domain for any buffers that moved.
* Dereference all buffers on validate list
*/
for (i = 0; i < nvpb->nr_buffers; i++) {
struct drm_nouveau_gem_pushbuf_bo *pbbo = &nvpb->buffers[i];
struct nouveau_bo *bo = (void *)(unsigned long)pbbo->user_priv;
if (pbbo->presumed_ok == 0) {
nouveau_bo(bo)->domain = pbbo->presumed_domain;
nouveau_bo(bo)->offset = pbbo->presumed_offset;
}
nouveau_bo(bo)->pending = NULL;
nouveau_bo_ref(NULL, &bo);
}
nvpb->nr_buffers = 0;
nvpb->nr_relocs = 0;
/* Allocate space for next push buffer */
ret = nouveau_pushbuf_space(chan, min);
assert(!ret);
if (chan->flush_notify)
chan->flush_notify(chan);
return 0;
}

View File

@ -0,0 +1,160 @@
/*
* Copyright 2007 Nouveau Project
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef __NOUVEAU_PUSHBUF_H__
#define __NOUVEAU_PUSHBUF_H__
#include <assert.h>
#include <string.h>
#include "nouveau_bo.h"
#include "nouveau_grobj.h"
struct nouveau_pushbuf {
struct nouveau_channel *channel;
unsigned remaining;
uint32_t *cur;
};
int
nouveau_pushbuf_flush(struct nouveau_channel *, unsigned min);
int
nouveau_pushbuf_emit_reloc(struct nouveau_channel *, void *ptr,
struct nouveau_bo *, uint32_t data, uint32_t flags,
uint32_t vor, uint32_t tor);
/* Push buffer access macros */
static __inline__ void
OUT_RING(struct nouveau_channel *chan, unsigned data)
{
*(chan->pushbuf->cur++) = (data);
}
static __inline__ void
OUT_RINGp(struct nouveau_channel *chan, const void *data, unsigned size)
{
memcpy(chan->pushbuf->cur, data, size * 4);
chan->pushbuf->cur += size;
}
static __inline__ void
OUT_RINGf(struct nouveau_channel *chan, float f)
{
union { uint32_t i; float f; } c;
c.f = f;
OUT_RING(chan, c.i);
}
static __inline__ unsigned
AVAIL_RING(struct nouveau_channel *chan)
{
return chan->pushbuf->remaining;
}
static __inline__ void
WAIT_RING(struct nouveau_channel *chan, unsigned size)
{
if (chan->pushbuf->remaining < size)
nouveau_pushbuf_flush(chan, size);
}
static __inline__ void
BEGIN_RING(struct nouveau_channel *chan, struct nouveau_grobj *gr,
unsigned mthd, unsigned size)
{
if (gr->bound == NOUVEAU_GROBJ_UNBOUND)
nouveau_grobj_autobind(gr);
chan->subc[gr->subc].sequence = chan->subc_sequence++;
WAIT_RING(chan, size + 1);
OUT_RING(chan, (gr->subc << 13) | (size << 18) | mthd);
chan->pushbuf->remaining -= (size + 1);
}
static __inline__ void
FIRE_RING(struct nouveau_channel *chan)
{
nouveau_pushbuf_flush(chan, 0);
}
static __inline__ void
BIND_RING(struct nouveau_channel *chan, struct nouveau_grobj *gr, unsigned sc)
{
struct nouveau_subchannel *subc = &gr->channel->subc[sc];
if (subc->gr) {
if (subc->gr->bound == NOUVEAU_GROBJ_BOUND_EXPLICIT)
assert(0);
subc->gr->bound = NOUVEAU_GROBJ_UNBOUND;
}
subc->gr = gr;
subc->gr->subc = sc;
subc->gr->bound = NOUVEAU_GROBJ_BOUND_EXPLICIT;
BEGIN_RING(chan, gr, 0x0000, 1);
OUT_RING (chan, gr->handle);
}
static __inline__ void
OUT_RELOC(struct nouveau_channel *chan, struct nouveau_bo *bo,
unsigned data, unsigned flags, unsigned vor, unsigned tor)
{
nouveau_pushbuf_emit_reloc(chan, chan->pushbuf->cur++, bo,
data, flags, vor, tor);
}
/* Raw data + flags depending on FB/TT buffer */
static __inline__ void
OUT_RELOCd(struct nouveau_channel *chan, struct nouveau_bo *bo,
unsigned data, unsigned flags, unsigned vor, unsigned tor)
{
OUT_RELOC(chan, bo, data, flags | NOUVEAU_BO_OR, vor, tor);
}
/* FB/TT object handle */
static __inline__ void
OUT_RELOCo(struct nouveau_channel *chan, struct nouveau_bo *bo,
unsigned flags)
{
OUT_RELOC(chan, bo, 0, flags | NOUVEAU_BO_OR,
chan->vram->handle, chan->gart->handle);
}
/* Low 32-bits of offset */
static __inline__ void
OUT_RELOCl(struct nouveau_channel *chan, struct nouveau_bo *bo,
unsigned delta, unsigned flags)
{
OUT_RELOC(chan, bo, delta, flags | NOUVEAU_BO_LOW, 0, 0);
}
/* High 32-bits of offset */
static __inline__ void
OUT_RELOCh(struct nouveau_channel *chan, struct nouveau_bo *bo,
unsigned delta, unsigned flags)
{
OUT_RELOC(chan, bo, delta, flags | NOUVEAU_BO_HIGH, 0, 0);
}
#endif

View File

@ -0,0 +1,115 @@
/*
* Copyright 2007 Nouveau Project
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <stdlib.h>
#include <errno.h>
#include "nouveau_private.h"
int
nouveau_resource_init(struct nouveau_resource **heap,
unsigned start, unsigned size)
{
struct nouveau_resource *r;
r = calloc(1, sizeof(struct nouveau_resource));
if (!r)
return 1;
r->start = start;
r->size = size;
*heap = r;
return 0;
}
int
nouveau_resource_alloc(struct nouveau_resource *heap, unsigned size, void *priv,
struct nouveau_resource **res)
{
struct nouveau_resource *r;
if (!heap || !size || !res || *res)
return 1;
while (heap) {
if (!heap->in_use && heap->size >= size) {
r = calloc(1, sizeof(struct nouveau_resource));
if (!r)
return 1;
r->start = (heap->start + heap->size) - size;
r->size = size;
r->in_use = 1;
r->priv = priv;
heap->size -= size;
r->next = heap->next;
if (heap->next)
heap->next->prev = r;
r->prev = heap;
heap->next = r;
*res = r;
return 0;
}
heap = heap->next;
}
return 1;
}
void
nouveau_resource_free(struct nouveau_resource **res)
{
struct nouveau_resource *r;
if (!res || !*res)
return;
r = *res;
*res = NULL;
r->in_use = 0;
if (r->next && !r->next->in_use) {
struct nouveau_resource *new = r->next;
new->prev = r->prev;
if (r->prev)
r->prev->next = new;
new->size += r->size;
new->start = r->start;
free(r);
r = new;
}
if (r->prev && !r->prev->in_use) {
r->prev->next = r->next;
if (r->next)
r->next->prev = r->prev;
r->prev->size += r->size;
free(r);
}
}

View File

@ -0,0 +1,48 @@
/*
* Copyright 2007 Nouveau Project
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef __NOUVEAU_RESOURCE_H__
#define __NOUVEAU_RESOURCE_H__
struct nouveau_resource {
struct nouveau_resource *prev;
struct nouveau_resource *next;
int in_use;
void *priv;
unsigned int start;
unsigned int size;
};
int
nouveau_resource_init(struct nouveau_resource **heap, unsigned start,
unsigned size);
int
nouveau_resource_alloc(struct nouveau_resource *heap, unsigned size, void *priv,
struct nouveau_resource **);
void
nouveau_resource_free(struct nouveau_resource **);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -49,6 +49,7 @@
#define DRM_DIR_NAME "/dev/dri"
#define DRM_DEV_NAME "%s/card%d"
#define DRM_CONTROL_DEV_NAME "%s/controlD%d"
#define DRM_PROC_NAME "/proc/dri/" /* For backward Linux compatibility */
#define DRM_ERR_NO_DEVICE (-1001)
@ -74,6 +75,7 @@ typedef struct drmHashEntry {
void *tagTable;
} drmHashEntry;
extern int drmIoctl(int fd, unsigned long request, void *arg);
extern void *drmGetHashTable(void);
extern drmHashEntry *drmGetEntry(int fd);
@ -323,28 +325,28 @@ typedef struct _drmSetVersion {
#elif defined(__alpha__)
#define DRM_CAS(lock, old, new, ret) \
do { \
int old32; \
int cur32; \
__asm__ __volatile__( \
" mb\n" \
" zap %4, 0xF0, %0\n" \
" ldl_l %1, %2\n" \
" zap %1, 0xF0, %1\n" \
" cmpeq %0, %1, %1\n" \
" beq %1, 1f\n" \
" bis %5, %5, %1\n" \
" stl_c %1, %2\n" \
"1: xor %1, 1, %1\n" \
" stl %1, %3" \
: "=r" (old32), \
"=&r" (cur32), \
"=m" (__drm_dummy_lock(lock)),\
"=m" (ret) \
: "r" (old), \
"r" (new)); \
} while(0)
#define DRM_CAS(lock, old, new, ret) \
do { \
int tmp, old32; \
__asm__ __volatile__( \
" addl $31, %5, %3\n" \
"1: ldl_l %0, %2\n" \
" cmpeq %0, %3, %1\n" \
" beq %1, 2f\n" \
" mov %4, %0\n" \
" stl_c %0, %2\n" \
" beq %0, 3f\n" \
" mb\n" \
"2: cmpeq %1, 0, %1\n" \
".subsection 2\n" \
"3: br 1b\n" \
".previous" \
: "=&r"(tmp), "=&r"(ret), \
"=m"(__drm_dummy_lock(lock)), \
"=&r"(old32) \
: "r"(new), "r"(old) \
: "memory"); \
} while (0)
#elif defined(__sparc__)
@ -427,7 +429,9 @@ do { register unsigned int __old __asm("o0"); \
#define DRM_CAS(lock,old,new,ret) do { ret=1; } while (0) /* FAST LOCK FAILS */
#endif
#if defined(__alpha__) || defined(__powerpc__)
#if defined(__alpha__)
#define DRM_CAS_RESULT(_result) long _result
#elif defined(__powerpc__)
#define DRM_CAS_RESULT(_result) int _result
#else
#define DRM_CAS_RESULT(_result) char _result
@ -508,6 +512,7 @@ do { register unsigned int __old __asm("o0"); \
/* General user-level programmer's API: unprivileged */
extern int drmAvailable(void);
extern int drmOpen(const char *name, const char *busid);
extern int drmOpenControl(int minor);
extern int drmClose(int fd);
extern drmVersionPtr drmGetVersion(int fd);
extern drmVersionPtr drmGetLibVersion(int fd);
@ -657,7 +662,9 @@ extern int drmSLLookupNeighbors(void *l, unsigned long key,
extern int drmOpenOnce(void *unused, const char *BusID, int *newlyopened);
extern void drmCloseOnce(int fd);
extern void drmMsg(const char *format, ...);
#include "xf86mm.h"
extern int drmSetMaster(int fd);
extern int drmDropMaster(int fd);
#endif

View File

@ -0,0 +1,666 @@
/*
* \file xf86drmMode.c
* Header for DRM modesetting interface.
*
* \author Jakob Bornecrantz <wallbraker@gmail.com>
*
* \par Acknowledgements:
* Feb 2007, Dave Airlie <airlied@linux.ie>
*/
/*
* Copyright (c) 2007-2008 Tungsten Graphics, Inc., Cedar Park, Texas.
* Copyright (c) 2007-2008 Dave Airlie <airlied@linux.ie>
* Copyright (c) 2007-2008 Jakob Bornecrantz <wallbraker@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
/*
* TODO the types we are after are defined in diffrent headers on diffrent
* platforms find which headers to include to get uint32_t
*/
#include <stdint.h>
#include <sys/ioctl.h>
#include <stdio.h>
#include "xf86drmMode.h"
#include "xf86drm.h"
#include <drm.h>
#include <string.h>
#include <dirent.h>
#include <errno.h>
#define U642VOID(x) ((void *)(unsigned long)(x))
#define VOID2U64(x) ((uint64_t)(unsigned long)(x))
/*
* Util functions
*/
void* drmAllocCpy(void *array, int count, int entry_size)
{
char *r;
int i;
if (!count || !array || !entry_size)
return 0;
if (!(r = drmMalloc(count*entry_size)))
return 0;
for (i = 0; i < count; i++)
memcpy(r+(entry_size*i), array+(entry_size*i), entry_size);
return r;
}
/*
* A couple of free functions.
*/
void drmModeFreeModeInfo(drmModeModeInfoPtr ptr)
{
if (!ptr)
return;
drmFree(ptr);
}
void drmModeFreeResources(drmModeResPtr ptr)
{
if (!ptr)
return;
drmFree(ptr);
}
void drmModeFreeFB(drmModeFBPtr ptr)
{
if (!ptr)
return;
/* we might add more frees later. */
drmFree(ptr);
}
void drmModeFreeCrtc(drmModeCrtcPtr ptr)
{
if (!ptr)
return;
drmFree(ptr);
}
void drmModeFreeConnector(drmModeConnectorPtr ptr)
{
if (!ptr)
return;
drmFree(ptr->modes);
drmFree(ptr);
}
void drmModeFreeEncoder(drmModeEncoderPtr ptr)
{
drmFree(ptr);
}
/*
* ModeSetting functions.
*/
drmModeResPtr drmModeGetResources(int fd)
{
struct drm_mode_card_res res;
drmModeResPtr r = 0;
memset(&res, 0, sizeof(struct drm_mode_card_res));
if (drmIoctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res))
return 0;
if (res.count_fbs)
res.fb_id_ptr = VOID2U64(drmMalloc(res.count_fbs*sizeof(uint32_t)));
if (res.count_crtcs)
res.crtc_id_ptr = VOID2U64(drmMalloc(res.count_crtcs*sizeof(uint32_t)));
if (res.count_connectors)
res.connector_id_ptr = VOID2U64(drmMalloc(res.count_connectors*sizeof(uint32_t)));
if (res.count_encoders)
res.encoder_id_ptr = VOID2U64(drmMalloc(res.count_encoders*sizeof(uint32_t)));
if (drmIoctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res)) {
r = NULL;
goto err_allocs;
}
/*
* return
*/
if (!(r = drmMalloc(sizeof(*r))))
return 0;
r->min_width = res.min_width;
r->max_width = res.max_width;
r->min_height = res.min_height;
r->max_height = res.max_height;
r->count_fbs = res.count_fbs;
r->count_crtcs = res.count_crtcs;
r->count_connectors = res.count_connectors;
r->count_encoders = res.count_encoders;
/* TODO we realy should test if these allocs fails. */
r->fbs = drmAllocCpy(U642VOID(res.fb_id_ptr), res.count_fbs, sizeof(uint32_t));
r->crtcs = drmAllocCpy(U642VOID(res.crtc_id_ptr), res.count_crtcs, sizeof(uint32_t));
r->connectors = drmAllocCpy(U642VOID(res.connector_id_ptr), res.count_connectors, sizeof(uint32_t));
r->encoders = drmAllocCpy(U642VOID(res.encoder_id_ptr), res.count_encoders, sizeof(uint32_t));
err_allocs:
drmFree(U642VOID(res.fb_id_ptr));
drmFree(U642VOID(res.crtc_id_ptr));
drmFree(U642VOID(res.connector_id_ptr));
drmFree(U642VOID(res.encoder_id_ptr));
return r;
}
int drmModeAddFB(int fd, uint32_t width, uint32_t height, uint8_t depth,
uint8_t bpp, uint32_t pitch, uint32_t bo_handle,
uint32_t *buf_id)
{
struct drm_mode_fb_cmd f;
int ret;
f.width = width;
f.height = height;
f.pitch = pitch;
f.bpp = bpp;
f.depth = depth;
f.handle = bo_handle;
if ((ret = drmIoctl(fd, DRM_IOCTL_MODE_ADDFB, &f)))
return ret;
*buf_id = f.fb_id;
return 0;
}
int drmModeRmFB(int fd, uint32_t bufferId)
{
return drmIoctl(fd, DRM_IOCTL_MODE_RMFB, &bufferId);
}
drmModeFBPtr drmModeGetFB(int fd, uint32_t buf)
{
struct drm_mode_fb_cmd info;
drmModeFBPtr r;
info.fb_id = buf;
if (drmIoctl(fd, DRM_IOCTL_MODE_GETFB, &info))
return NULL;
if (!(r = drmMalloc(sizeof(*r))))
return NULL;
r->fb_id = info.fb_id;
r->width = info.width;
r->height = info.height;
r->pitch = info.pitch;
r->bpp = info.bpp;
r->handle = info.handle;
r->depth = info.depth;
return r;
}
/*
* Crtc functions
*/
drmModeCrtcPtr drmModeGetCrtc(int fd, uint32_t crtcId)
{
struct drm_mode_crtc crtc;
drmModeCrtcPtr r;
crtc.crtc_id = crtcId;
if (drmIoctl(fd, DRM_IOCTL_MODE_GETCRTC, &crtc))
return 0;
/*
* return
*/
if (!(r = drmMalloc(sizeof(*r))))
return 0;
r->crtc_id = crtc.crtc_id;
r->x = crtc.x;
r->y = crtc.y;
r->mode_valid = crtc.mode_valid;
if (r->mode_valid)
memcpy(&r->mode, &crtc.mode, sizeof(struct drm_mode_modeinfo));
r->buffer_id = crtc.fb_id;
r->gamma_size = crtc.gamma_size;
return r;
}
int drmModeSetCrtc(int fd, uint32_t crtcId, uint32_t bufferId,
uint32_t x, uint32_t y, uint32_t *connectors, int count,
drmModeModeInfoPtr mode)
{
struct drm_mode_crtc crtc;
crtc.x = x;
crtc.y = y;
crtc.crtc_id = crtcId;
crtc.fb_id = bufferId;
crtc.set_connectors_ptr = VOID2U64(connectors);
crtc.count_connectors = count;
if (mode) {
memcpy(&crtc.mode, mode, sizeof(struct drm_mode_modeinfo));
crtc.mode_valid = 1;
} else
crtc.mode_valid = 0;
return drmIoctl(fd, DRM_IOCTL_MODE_SETCRTC, &crtc);
}
/*
* Cursor manipulation
*/
int drmModeSetCursor(int fd, uint32_t crtcId, uint32_t bo_handle, uint32_t width, uint32_t height)
{
struct drm_mode_cursor arg;
arg.flags = DRM_MODE_CURSOR_BO;
arg.crtc_id = crtcId;
arg.width = width;
arg.height = height;
arg.handle = bo_handle;
return drmIoctl(fd, DRM_IOCTL_MODE_CURSOR, &arg);
}
int drmModeMoveCursor(int fd, uint32_t crtcId, int x, int y)
{
struct drm_mode_cursor arg;
arg.flags = DRM_MODE_CURSOR_MOVE;
arg.crtc_id = crtcId;
arg.x = x;
arg.y = y;
return drmIoctl(fd, DRM_IOCTL_MODE_CURSOR, &arg);
}
/*
* Encoder get
*/
drmModeEncoderPtr drmModeGetEncoder(int fd, uint32_t encoder_id)
{
struct drm_mode_get_encoder enc;
drmModeEncoderPtr r = NULL;
enc.encoder_id = encoder_id;
enc.encoder_type = 0;
enc.possible_crtcs = 0;
enc.possible_clones = 0;
if (drmIoctl(fd, DRM_IOCTL_MODE_GETENCODER, &enc))
return 0;
if (!(r = drmMalloc(sizeof(*r))))
return 0;
r->encoder_id = enc.encoder_id;
r->crtc_id = enc.crtc_id;
r->encoder_type = enc.encoder_type;
r->possible_crtcs = enc.possible_crtcs;
r->possible_clones = enc.possible_clones;
return r;
}
/*
* Connector manipulation
*/
drmModeConnectorPtr drmModeGetConnector(int fd, uint32_t connector_id)
{
struct drm_mode_get_connector conn;
drmModeConnectorPtr r = NULL;
conn.connector_id = connector_id;
conn.connector_type_id = 0;
conn.connector_type = 0;
conn.count_modes = 0;
conn.modes_ptr = 0;
conn.count_props = 0;
conn.props_ptr = 0;
conn.prop_values_ptr = 0;
conn.count_encoders = 0;
conn.encoders_ptr = 0;
if (drmIoctl(fd, DRM_IOCTL_MODE_GETCONNECTOR, &conn))
return 0;
if (conn.count_props) {
conn.props_ptr = VOID2U64(drmMalloc(conn.count_props*sizeof(uint32_t)));
conn.prop_values_ptr = VOID2U64(drmMalloc(conn.count_props*sizeof(uint64_t)));
}
if (conn.count_modes)
conn.modes_ptr = VOID2U64(drmMalloc(conn.count_modes*sizeof(struct drm_mode_modeinfo)));
if (conn.count_encoders)
conn.encoders_ptr = VOID2U64(drmMalloc(conn.count_encoders*sizeof(uint32_t)));
if (drmIoctl(fd, DRM_IOCTL_MODE_GETCONNECTOR, &conn))
goto err_allocs;
if(!(r = drmMalloc(sizeof(*r)))) {
goto err_allocs;
}
r->connector_id = conn.connector_id;
r->encoder_id = conn.encoder_id;
r->connection = conn.connection;
r->mmWidth = conn.mm_width;
r->mmHeight = conn.mm_height;
/* convert subpixel from kernel to userspace */
r->subpixel = conn.subpixel + 1;
r->count_modes = conn.count_modes;
/* TODO we should test if these alloc & cpy fails. */
r->count_props = conn.count_props;
r->props = drmAllocCpy(U642VOID(conn.props_ptr), conn.count_props, sizeof(uint32_t));
r->prop_values = drmAllocCpy(U642VOID(conn.prop_values_ptr), conn.count_props, sizeof(uint64_t));
r->modes = drmAllocCpy(U642VOID(conn.modes_ptr), conn.count_modes, sizeof(struct drm_mode_modeinfo));
r->count_encoders = conn.count_encoders;
r->encoders = drmAllocCpy(U642VOID(conn.encoders_ptr), conn.count_encoders, sizeof(uint32_t));
r->connector_type = conn.connector_type;
r->connector_type_id = conn.connector_type_id;
if (!r->props || !r->prop_values || !r->modes || !r->encoders)
goto err_allocs;
err_allocs:
drmFree(U642VOID(conn.prop_values_ptr));
drmFree(U642VOID(conn.props_ptr));
drmFree(U642VOID(conn.modes_ptr));
drmFree(U642VOID(conn.encoders_ptr));
return r;
}
int drmModeAttachMode(int fd, uint32_t connector_id, drmModeModeInfoPtr mode_info)
{
struct drm_mode_mode_cmd res;
memcpy(&res.mode, mode_info, sizeof(struct drm_mode_modeinfo));
res.connector_id = connector_id;
return drmIoctl(fd, DRM_IOCTL_MODE_ATTACHMODE, &res);
}
int drmModeDetachMode(int fd, uint32_t connector_id, drmModeModeInfoPtr mode_info)
{
struct drm_mode_mode_cmd res;
memcpy(&res.mode, mode_info, sizeof(struct drm_mode_modeinfo));
res.connector_id = connector_id;
return drmIoctl(fd, DRM_IOCTL_MODE_DETACHMODE, &res);
}
drmModePropertyPtr drmModeGetProperty(int fd, uint32_t property_id)
{
struct drm_mode_get_property prop;
drmModePropertyPtr r;
prop.prop_id = property_id;
prop.count_enum_blobs = 0;
prop.count_values = 0;
prop.flags = 0;
prop.enum_blob_ptr = 0;
prop.values_ptr = 0;
if (drmIoctl(fd, DRM_IOCTL_MODE_GETPROPERTY, &prop))
return 0;
if (prop.count_values)
prop.values_ptr = VOID2U64(drmMalloc(prop.count_values * sizeof(uint64_t)));
if (prop.count_enum_blobs && (prop.flags & DRM_MODE_PROP_ENUM))
prop.enum_blob_ptr = VOID2U64(drmMalloc(prop.count_enum_blobs * sizeof(struct drm_mode_property_enum)));
if (prop.count_enum_blobs && (prop.flags & DRM_MODE_PROP_BLOB)) {
prop.values_ptr = VOID2U64(drmMalloc(prop.count_enum_blobs * sizeof(uint32_t)));
prop.enum_blob_ptr = VOID2U64(drmMalloc(prop.count_enum_blobs * sizeof(uint32_t)));
}
if (drmIoctl(fd, DRM_IOCTL_MODE_GETPROPERTY, &prop)) {
r = NULL;
goto err_allocs;
}
if (!(r = drmMalloc(sizeof(*r))))
return NULL;
r->prop_id = prop.prop_id;
r->count_values = prop.count_values;
r->flags = prop.flags;
if (prop.count_values)
r->values = drmAllocCpy(U642VOID(prop.values_ptr), prop.count_values, sizeof(uint64_t));
if (prop.flags & DRM_MODE_PROP_ENUM) {
r->count_enums = prop.count_enum_blobs;
r->enums = drmAllocCpy(U642VOID(prop.enum_blob_ptr), prop.count_enum_blobs, sizeof(struct drm_mode_property_enum));
} else if (prop.flags & DRM_MODE_PROP_BLOB) {
r->values = drmAllocCpy(U642VOID(prop.values_ptr), prop.count_enum_blobs, sizeof(uint32_t));
r->blob_ids = drmAllocCpy(U642VOID(prop.enum_blob_ptr), prop.count_enum_blobs, sizeof(uint32_t));
r->count_blobs = prop.count_enum_blobs;
}
strncpy(r->name, prop.name, DRM_PROP_NAME_LEN);
r->name[DRM_PROP_NAME_LEN-1] = 0;
err_allocs:
drmFree(U642VOID(prop.values_ptr));
drmFree(U642VOID(prop.enum_blob_ptr));
return r;
}
void drmModeFreeProperty(drmModePropertyPtr ptr)
{
if (!ptr)
return;
drmFree(ptr->values);
drmFree(ptr->enums);
drmFree(ptr);
}
drmModePropertyBlobPtr drmModeGetPropertyBlob(int fd, uint32_t blob_id)
{
struct drm_mode_get_blob blob;
drmModePropertyBlobPtr r;
blob.length = 0;
blob.data = 0;
blob.blob_id = blob_id;
if (drmIoctl(fd, DRM_IOCTL_MODE_GETPROPBLOB, &blob))
return NULL;
if (blob.length)
blob.data = VOID2U64(drmMalloc(blob.length));
if (drmIoctl(fd, DRM_IOCTL_MODE_GETPROPBLOB, &blob)) {
r = NULL;
goto err_allocs;
}
if (!(r = drmMalloc(sizeof(*r))))
return NULL;
r->id = blob.blob_id;
r->length = blob.length;
r->data = drmAllocCpy(U642VOID(blob.data), 1, blob.length);
err_allocs:
drmFree(U642VOID(blob.data));
return r;
}
void drmModeFreePropertyBlob(drmModePropertyBlobPtr ptr)
{
if (!ptr)
return;
drmFree(ptr->data);
drmFree(ptr);
}
int drmModeConnectorSetProperty(int fd, uint32_t connector_id, uint32_t property_id,
uint64_t value)
{
struct drm_mode_connector_set_property osp;
int ret;
osp.connector_id = connector_id;
osp.prop_id = property_id;
osp.value = value;
if ((ret = drmIoctl(fd, DRM_IOCTL_MODE_SETPROPERTY, &osp)))
return ret;
return 0;
}
/*
* checks if a modesetting capable driver has attached to the pci id
* returns 0 if modesetting supported.
* -EINVAL or invalid bus id
* -ENOSYS if no modesetting support
*/
int drmCheckModesettingSupported(const char *busid)
{
#ifdef __linux__
char pci_dev_dir[1024];
int domain, bus, dev, func;
DIR *sysdir;
struct dirent *dent;
int found = 0, ret;
ret = sscanf(busid, "pci:%04x:%02x:%02x.%d", &domain, &bus, &dev, &func);
if (ret != 4)
return -EINVAL;
sprintf(pci_dev_dir, "/sys/bus/pci/devices/%04x:%02x:%02x.%d/drm",
domain, bus, dev, func);
sysdir = opendir(pci_dev_dir);
if (sysdir) {
dent = readdir(sysdir);
while (dent) {
if (!strncmp(dent->d_name, "controlD", 8)) {
found = 1;
break;
}
dent = readdir(sysdir);
}
closedir(sysdir);
if (found)
return 0;
}
sprintf(pci_dev_dir, "/sys/bus/pci/devices/%04x:%02x:%02x.%d/",
domain, bus, dev, func);
sysdir = opendir(pci_dev_dir);
if (!sysdir)
return -EINVAL;
dent = readdir(sysdir);
while (dent) {
if (!strncmp(dent->d_name, "drm:controlD", 12)) {
found = 1;
break;
}
dent = readdir(sysdir);
}
closedir(sysdir);
if (found)
return 0;
#endif
return -ENOSYS;
}
int drmModeCrtcGetGamma(int fd, uint32_t crtc_id, uint32_t size,
uint16_t *red, uint16_t *green, uint16_t *blue)
{
int ret;
struct drm_mode_crtc_lut l;
l.crtc_id = crtc_id;
l.gamma_size = size;
l.red = VOID2U64(red);
l.green = VOID2U64(green);
l.blue = VOID2U64(blue);
if ((ret = drmIoctl(fd, DRM_IOCTL_MODE_GETGAMMA, &l)))
return ret;
return 0;
}
int drmModeCrtcSetGamma(int fd, uint32_t crtc_id, uint32_t size,
uint16_t *red, uint16_t *green, uint16_t *blue)
{
int ret;
struct drm_mode_crtc_lut l;
l.crtc_id = crtc_id;
l.gamma_size = size;
l.red = VOID2U64(red);
l.green = VOID2U64(green);
l.blue = VOID2U64(blue);
if ((ret = drmIoctl(fd, DRM_IOCTL_MODE_SETGAMMA, &l)))
return ret;
return 0;
}

View File

@ -0,0 +1,364 @@
/*
* \file xf86drmMode.h
* Header for DRM modesetting interface.
*
* \author Jakob Bornecrantz <wallbraker@gmail.com>
*
* \par Acknowledgements:
* Feb 2007, Dave Airlie <airlied@linux.ie>
*/
/*
* Copyright (c) 2007-2008 Tungsten Graphics, Inc., Cedar Park, Texas.
* Copyright (c) 2007-2008 Dave Airlie <airlied@linux.ie>
* Copyright (c) 2007-2008 Jakob Bornecrantz <wallbraker@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#include <drm.h>
/*
* This is the interface for modesetting for drm.
*
* In order to use this interface you must include either <stdint.h> or another
* header defining uint32_t, int32_t and uint16_t.
*
* It aims to provide a randr1.2 compatible interface for modesettings in the
* kernel, the interface is also ment to be used by libraries like EGL.
*
* More information can be found in randrproto.txt which can be found here:
* http://gitweb.freedesktop.org/?p=xorg/proto/randrproto.git
*
* There are some major diffrences to be noted. Unlike the randr1.2 proto you
* need to create the memory object of the framebuffer yourself with the ttm
* buffer object interface. This object needs to be pinned.
*/
/*
* If we pickup an old version of drm.h which doesn't include drm_mode.h
* we should redefine defines. This is so that builds doesn't breaks with
* new libdrm on old kernels.
*/
#ifndef _DRM_MODE_H
#define DRM_DISPLAY_INFO_LEN 32
#define DRM_CONNECTOR_NAME_LEN 32
#define DRM_DISPLAY_MODE_LEN 32
#define DRM_PROP_NAME_LEN 32
#define DRM_MODE_TYPE_BUILTIN (1<<0)
#define DRM_MODE_TYPE_CLOCK_C ((1<<1) | DRM_MODE_TYPE_BUILTIN)
#define DRM_MODE_TYPE_CRTC_C ((1<<2) | DRM_MODE_TYPE_BUILTIN)
#define DRM_MODE_TYPE_PREFERRED (1<<3)
#define DRM_MODE_TYPE_DEFAULT (1<<4)
#define DRM_MODE_TYPE_USERDEF (1<<5)
#define DRM_MODE_TYPE_DRIVER (1<<6)
/* Video mode flags */
/* bit compatible with the xorg definitions. */
#define DRM_MODE_FLAG_PHSYNC (1<<0)
#define DRM_MODE_FLAG_NHSYNC (1<<1)
#define DRM_MODE_FLAG_PVSYNC (1<<2)
#define DRM_MODE_FLAG_NVSYNC (1<<3)
#define DRM_MODE_FLAG_INTERLACE (1<<4)
#define DRM_MODE_FLAG_DBLSCAN (1<<5)
#define DRM_MODE_FLAG_CSYNC (1<<6)
#define DRM_MODE_FLAG_PCSYNC (1<<7)
#define DRM_MODE_FLAG_NCSYNC (1<<8)
#define DRM_MODE_FLAG_HSKEW (1<<9) /* hskew provided */
#define DRM_MODE_FLAG_BCAST (1<<10)
#define DRM_MODE_FLAG_PIXMUX (1<<11)
#define DRM_MODE_FLAG_DBLCLK (1<<12)
#define DRM_MODE_FLAG_CLKDIV2 (1<<13)
/* DPMS flags */
/* bit compatible with the xorg definitions. */
#define DRM_MODE_DPMS_ON 0
#define DRM_MODE_DPMS_STANDBY 1
#define DRM_MODE_DPMS_SUSPEND 2
#define DRM_MODE_DPMS_OFF 3
/* Scaling mode options */
#define DRM_MODE_SCALE_NON_GPU 0
#define DRM_MODE_SCALE_FULLSCREEN 1
#define DRM_MODE_SCALE_NO_SCALE 2
#define DRM_MODE_SCALE_ASPECT 3
/* Dithering mode options */
#define DRM_MODE_DITHERING_OFF 0
#define DRM_MODE_DITHERING_ON 1
#define DRM_MODE_ENCODER_NONE 0
#define DRM_MODE_ENCODER_DAC 1
#define DRM_MODE_ENCODER_TMDS 2
#define DRM_MODE_ENCODER_LVDS 3
#define DRM_MODE_ENCODER_TVDAC 4
#define DRM_MODE_SUBCONNECTOR_Automatic 0
#define DRM_MODE_SUBCONNECTOR_Unknown 0
#define DRM_MODE_SUBCONNECTOR_DVID 3
#define DRM_MODE_SUBCONNECTOR_DVIA 4
#define DRM_MODE_SUBCONNECTOR_Composite 5
#define DRM_MODE_SUBCONNECTOR_SVIDEO 6
#define DRM_MODE_SUBCONNECTOR_Component 8
#define DRM_MODE_CONNECTOR_Unknown 0
#define DRM_MODE_CONNECTOR_VGA 1
#define DRM_MODE_CONNECTOR_DVII 2
#define DRM_MODE_CONNECTOR_DVID 3
#define DRM_MODE_CONNECTOR_DVIA 4
#define DRM_MODE_CONNECTOR_Composite 5
#define DRM_MODE_CONNECTOR_SVIDEO 6
#define DRM_MODE_CONNECTOR_LVDS 7
#define DRM_MODE_CONNECTOR_Component 8
#define DRM_MODE_CONNECTOR_9PinDIN 9
#define DRM_MODE_CONNECTOR_DisplayPort 10
#define DRM_MODE_CONNECTOR_HDMIA 11
#define DRM_MODE_CONNECTOR_HDMIB 12
#define DRM_MODE_PROP_PENDING (1<<0)
#define DRM_MODE_PROP_RANGE (1<<1)
#define DRM_MODE_PROP_IMMUTABLE (1<<2)
#define DRM_MODE_PROP_ENUM (1<<3) /* enumerated type with text strings */
#define DRM_MODE_PROP_BLOB (1<<4)
#define DRM_MODE_CURSOR_BO (1<<0)
#define DRM_MODE_CURSOR_MOVE (1<<1)
#endif /* _DRM_MODE_H */
typedef struct _drmModeRes {
int count_fbs;
uint32_t *fbs;
int count_crtcs;
uint32_t *crtcs;
int count_connectors;
uint32_t *connectors;
int count_encoders;
uint32_t *encoders;
uint32_t min_width, max_width;
uint32_t min_height, max_height;
} drmModeRes, *drmModeResPtr;
typedef struct _drmModeModeInfo {
uint32_t clock;
uint16_t hdisplay, hsync_start, hsync_end, htotal, hskew;
uint16_t vdisplay, vsync_start, vsync_end, vtotal, vscan;
uint32_t vrefresh; /* vertical refresh * 1000 */
uint32_t flags;
uint32_t type;
char name[DRM_DISPLAY_MODE_LEN];
} drmModeModeInfo, *drmModeModeInfoPtr;
typedef struct _drmModeFB {
uint32_t fb_id;
uint32_t width, height;
uint32_t pitch;
uint32_t bpp;
uint32_t depth;
/* driver specific handle */
uint32_t handle;
} drmModeFB, *drmModeFBPtr;
typedef struct _drmModePropertyBlob {
uint32_t id;
uint32_t length;
void *data;
} drmModePropertyBlobRes, *drmModePropertyBlobPtr;
typedef struct _drmModeProperty {
uint32_t prop_id;
uint32_t flags;
char name[DRM_PROP_NAME_LEN];
int count_values;
uint64_t *values; // store the blob lengths
int count_enums;
struct drm_mode_property_enum *enums;
int count_blobs;
uint32_t *blob_ids; // store the blob IDs
} drmModePropertyRes, *drmModePropertyPtr;
typedef struct _drmModeCrtc {
uint32_t crtc_id;
uint32_t buffer_id; /**< FB id to connect to 0 = disconnect */
uint32_t x, y; /**< Position on the framebuffer */
uint32_t width, height;
int mode_valid;
drmModeModeInfo mode;
int gamma_size; /**< Number of gamma stops */
} drmModeCrtc, *drmModeCrtcPtr;
typedef struct _drmModeEncoder {
uint32_t encoder_id;
uint32_t encoder_type;
uint32_t crtc_id;
uint32_t possible_crtcs;
uint32_t possible_clones;
} drmModeEncoder, *drmModeEncoderPtr;
typedef enum {
DRM_MODE_CONNECTED = 1,
DRM_MODE_DISCONNECTED = 2,
DRM_MODE_UNKNOWNCONNECTION = 3
} drmModeConnection;
typedef enum {
DRM_MODE_SUBPIXEL_UNKNOWN = 1,
DRM_MODE_SUBPIXEL_HORIZONTAL_RGB = 2,
DRM_MODE_SUBPIXEL_HORIZONTAL_BGR = 3,
DRM_MODE_SUBPIXEL_VERTICAL_RGB = 4,
DRM_MODE_SUBPIXEL_VERTICAL_BGR = 5,
DRM_MODE_SUBPIXEL_NONE = 6
} drmModeSubPixel;
typedef struct _drmModeConnector {
uint32_t connector_id;
uint32_t encoder_id; /**< Encoder currently connected to */
uint32_t connector_type;
uint32_t connector_type_id;
drmModeConnection connection;
uint32_t mmWidth, mmHeight; /**< HxW in millimeters */
drmModeSubPixel subpixel;
int count_modes;
drmModeModeInfoPtr modes;
int count_props;
uint32_t *props; /**< List of property ids */
uint64_t *prop_values; /**< List of property values */
int count_encoders;
uint32_t *encoders; /**< List of encoder ids */
} drmModeConnector, *drmModeConnectorPtr;
extern void drmModeFreeModeInfo( drmModeModeInfoPtr ptr );
extern void drmModeFreeResources( drmModeResPtr ptr );
extern void drmModeFreeFB( drmModeFBPtr ptr );
extern void drmModeFreeCrtc( drmModeCrtcPtr ptr );
extern void drmModeFreeConnector( drmModeConnectorPtr ptr );
extern void drmModeFreeEncoder( drmModeEncoderPtr ptr );
/**
* Retrives all of the resources associated with a card.
*/
extern drmModeResPtr drmModeGetResources(int fd);
/*
* FrameBuffer manipulation.
*/
/**
* Retrive information about framebuffer bufferId
*/
extern drmModeFBPtr drmModeGetFB(int fd, uint32_t bufferId);
/**
* Creates a new framebuffer with an buffer object as its scanout buffer.
*/
extern int drmModeAddFB(int fd, uint32_t width, uint32_t height, uint8_t depth,
uint8_t bpp, uint32_t pitch, uint32_t bo_handle,
uint32_t *buf_id);
/**
* Destroies the given framebuffer.
*/
extern int drmModeRmFB(int fd, uint32_t bufferId);
/*
* Crtc functions
*/
/**
* Retrive information about the ctrt crtcId
*/
extern drmModeCrtcPtr drmModeGetCrtc(int fd, uint32_t crtcId);
/**
* Set the mode on a crtc crtcId with the given mode modeId.
*/
int drmModeSetCrtc(int fd, uint32_t crtcId, uint32_t bufferId,
uint32_t x, uint32_t y, uint32_t *connectors, int count,
drmModeModeInfoPtr mode);
/*
* Cursor functions
*/
/**
* Set the cursor on crtc
*/
int drmModeSetCursor(int fd, uint32_t crtcId, uint32_t bo_handle, uint32_t width, uint32_t height);
/**
* Move the cursor on crtc
*/
int drmModeMoveCursor(int fd, uint32_t crtcId, int x, int y);
/**
* Encoder functions
*/
drmModeEncoderPtr drmModeGetEncoder(int fd, uint32_t encoder_id);
/*
* Connector manipulation
*/
/**
* Retrive information about the connector connectorId.
*/
extern drmModeConnectorPtr drmModeGetConnector(int fd,
uint32_t connectorId);
/**
* Attaches the given mode to an connector.
*/
extern int drmModeAttachMode(int fd, uint32_t connectorId, drmModeModeInfoPtr mode_info);
/**
* Detaches a mode from the connector
* must be unused, by the given mode.
*/
extern int drmModeDetachMode(int fd, uint32_t connectorId, drmModeModeInfoPtr mode_info);
extern drmModePropertyPtr drmModeGetProperty(int fd, uint32_t propertyId);
extern void drmModeFreeProperty(drmModePropertyPtr ptr);
extern drmModePropertyBlobPtr drmModeGetPropertyBlob(int fd, uint32_t blob_id);
extern void drmModeFreePropertyBlob(drmModePropertyBlobPtr ptr);
extern int drmModeConnectorSetProperty(int fd, uint32_t connector_id, uint32_t property_id,
uint64_t value);
extern int drmCheckModesettingSupported(const char *busid);
extern int drmModeCrtcSetGamma(int fd, uint32_t crtc_id, uint32_t size,
uint16_t *red, uint16_t *green, uint16_t *blue);
extern int drmModeCrtcGetGamma(int fd, uint32_t crtc_id, uint32_t size,
uint16_t *red, uint16_t *green, uint16_t *blue);

View File

@ -94,6 +94,18 @@ typedef struct _drmMMListHead
#define DRMLISTENTRY(__type, __item, __field) \
((__type *)(((char *) (__item)) - offsetof(__type, __field)))
#define DRMLISTEMPTY(__item) ((__item)->next == (__item))
#define DRMLISTFOREACHSAFE(__item, __temp, __list) \
for ((__item) = (__list)->next, (__temp) = (__item)->next; \
(__item) != (__list); \
(__item) = (__temp), (__temp) = (__item)->next)
#define DRMLISTFOREACHSAFEREVERSE(__item, __temp, __list) \
for ((__item) = (__list)->prev, (__temp) = (__item)->prev; \
(__item) != (__list); \
(__item) = (__temp), (__temp) = (__item)->prev)
typedef struct _drmFence
{
unsigned handle;

View File

@ -0,0 +1,58 @@
#! /bin/bash
# script to create a Linux Kernel tree from the DRM tree for diffing etc..
#
# Original author - Dave Airlie (C) 2004 - airlied@linux.ie
# kernel_version to remove below (e.g. 2.6.24)
if [ $# -lt 2 ] ;then
echo usage: $0 output_dir kernel_version
exit 1
fi
if [ ! -d shared-core -o ! -d linux-core ] ;then
echo not in DRM toplevel
exit 1
fi
DRMDIR=$1/drivers/gpu/drm/
HDRDIR=$1/include/drm/
KERNEL_VERS=$2
echo "Copying kernel independent files"
mkdir -p $DRMDIR/.tmp
mkdir -p $HDRDIR/.tmp
( cd linux-core/ ; make drm_pciids.h )
cp shared-core/*.[ch] $DRMDIR/.tmp
cp linux-core/*.[ch] $DRMDIR/.tmp
cp linux-core/Makefile.kernel $DRMDIR/.tmp/Makefile
echo "Copying 2.6 Kernel files"
cp linux-core/Kconfig $DRMDIR/.tmp
./scripts/drm-scripts-gentree.pl $KERNEL_VERS $DRMDIR/.tmp $DRMDIR
mv $DRMDIR/drm*.h $HDRDIR
mv $DRMDIR/*_drm.h $HDRDIR
cd $DRMDIR
rm -rf .tmp
rm via_ds.[ch]
rm sis_ds.[ch]
rm amd*.[ch]
rm radeon_ms*.[ch]
for i in radeon mach64 r128 mga i915 i810 via savage sis xgi nouveau tdfx ffb imagine
do
mkdir ./$i
mv $i*.[ch] $i/
done
mv r300*.[ch] radeon/
mv r600*.[ch] radeon/
mv ObjectID.h radeon/
mv atom*.[ch] radeon/
mv nv*.[ch] nouveau/
mv intel*.[ch] i915/
mv dvo*.[ch] i915/
cd -

View File

@ -25,6 +25,7 @@
klibdrmincludedir = ${includedir}/drm
klibdrminclude_HEADERS = \
drm.h \
drm_mode.h \
drm_sarea.h \
i915_drm.h \
mach64_drm.h \

View File

@ -69,6 +69,12 @@
# define DEPRECATED __attribute__ ((deprecated))
#else
# define DEPRECATED
# ifndef __FUNCTION__
# define __FUNCTION__ __func__ /* C99 */
# endif
# ifndef __volatile__
# define __volatile__ volatile
# endif
#endif
#if defined(__linux__)
@ -236,7 +242,8 @@ enum drm_map_type {
_DRM_AGP = 3, /**< AGP/GART */
_DRM_SCATTER_GATHER = 4, /**< Scatter/gather memory for PCI DMA */
_DRM_CONSISTENT = 5, /**< Consistent memory for PCI DMA */
_DRM_TTM = 6
_DRM_GEM = 6,
_DRM_TTM = 7,
};
/**
@ -959,6 +966,33 @@ struct drm_mm_info_arg {
uint64_t p_size;
};
struct drm_gem_close {
/** Handle of the object to be closed. */
uint32_t handle;
uint32_t pad;
};
struct drm_gem_flink {
/** Handle for the object being named */
uint32_t handle;
/** Returned global name */
uint32_t name;
};
struct drm_gem_open {
/** Name of object being opened */
uint32_t name;
/** Returned handle for the object */
uint32_t handle;
/** Returned size of the object */
uint64_t size;
};
#include "drm_mode.h"
/**
* \name Ioctls Definitions
*/
@ -978,7 +1012,11 @@ struct drm_mm_info_arg {
#define DRM_IOCTL_GET_CLIENT DRM_IOWR(0x05, struct drm_client)
#define DRM_IOCTL_GET_STATS DRM_IOR( 0x06, struct drm_stats)
#define DRM_IOCTL_SET_VERSION DRM_IOWR(0x07, struct drm_set_version)
#define DRM_IOCTL_MODESET_CTL DRM_IOW(0x08, struct drm_modeset_ctl)
#define DRM_IOCTL_MODESET_CTL DRM_IOW(0x08, struct drm_modeset_ctl)
#define DRM_IOCTL_GEM_CLOSE DRM_IOW (0x09, struct drm_gem_close)
#define DRM_IOCTL_GEM_FLINK DRM_IOWR(0x0a, struct drm_gem_flink)
#define DRM_IOCTL_GEM_OPEN DRM_IOWR(0x0b, struct drm_gem_open)
#define DRM_IOCTL_SET_UNIQUE DRM_IOW( 0x10, struct drm_unique)
#define DRM_IOCTL_AUTH_MAGIC DRM_IOW( 0x11, struct drm_auth)
@ -997,6 +1035,9 @@ struct drm_mm_info_arg {
#define DRM_IOCTL_SET_SAREA_CTX DRM_IOW( 0x1c, struct drm_ctx_priv_map)
#define DRM_IOCTL_GET_SAREA_CTX DRM_IOWR(0x1d, struct drm_ctx_priv_map)
#define DRM_IOCTL_SET_MASTER DRM_IO(0x1e)
#define DRM_IOCTL_DROP_MASTER DRM_IO(0x1f)
#define DRM_IOCTL_ADD_CTX DRM_IOWR(0x20, struct drm_ctx)
#define DRM_IOCTL_RM_CTX DRM_IOWR(0x21, struct drm_ctx)
#define DRM_IOCTL_MOD_CTX DRM_IOW( 0x22, struct drm_ctx)
@ -1052,6 +1093,28 @@ struct drm_mm_info_arg {
#define DRM_IOCTL_BO_VERSION DRM_IOR(0xd6, struct drm_bo_version_arg)
#define DRM_IOCTL_MM_INFO DRM_IOWR(0xd7, struct drm_mm_info_arg)
#define DRM_IOCTL_MODE_GETRESOURCES DRM_IOWR(0xA0, struct drm_mode_card_res)
#define DRM_IOCTL_MODE_GETCRTC DRM_IOWR(0xA1, struct drm_mode_crtc)
#define DRM_IOCTL_MODE_SETCRTC DRM_IOWR(0xA2, struct drm_mode_crtc)
#define DRM_IOCTL_MODE_CURSOR DRM_IOWR(0xA3, struct drm_mode_cursor)
#define DRM_IOCTL_MODE_GETGAMMA DRM_IOWR(0xA4, struct drm_mode_crtc_lut)
#define DRM_IOCTL_MODE_SETGAMMA DRM_IOWR(0xA5, struct drm_mode_crtc_lut)
#define DRM_IOCTL_MODE_GETENCODER DRM_IOWR(0xA6, struct drm_mode_get_encoder)
#define DRM_IOCTL_MODE_GETCONNECTOR DRM_IOWR(0xA7, struct drm_mode_get_connector)
#define DRM_IOCTL_MODE_ATTACHMODE DRM_IOWR(0xA8, struct drm_mode_mode_cmd)
#define DRM_IOCTL_MODE_DETACHMODE DRM_IOWR(0xA9, struct drm_mode_mode_cmd)
#define DRM_IOCTL_MODE_GETPROPERTY DRM_IOWR(0xAA, struct drm_mode_get_property)
#define DRM_IOCTL_MODE_SETPROPERTY DRM_IOWR(0xAB, struct drm_mode_connector_set_property)
#define DRM_IOCTL_MODE_GETPROPBLOB DRM_IOWR(0xAC, struct drm_mode_get_blob)
#define DRM_IOCTL_MODE_GETFB DRM_IOWR(0xAD, struct drm_mode_fb_cmd)
#define DRM_IOCTL_MODE_ADDFB DRM_IOWR(0xAE, struct drm_mode_fb_cmd)
#define DRM_IOCTL_MODE_RMFB DRM_IOWR(0xAF, uint32_t)
#define DRM_IOCTL_MODE_REPLACEFB DRM_IOWR(0xB0, struct drm_mode_fb_cmd)
/*@}*/
/**
@ -1066,7 +1129,7 @@ struct drm_mm_info_arg {
#define DRM_COMMAND_END 0xA0
/* typedef area */
#if !defined(__KERNEL__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)
#ifndef __KERNEL__
typedef struct drm_clip_rect drm_clip_rect_t;
typedef struct drm_tex_region drm_tex_region_t;
typedef struct drm_hw_lock drm_hw_lock_t;

View File

@ -0,0 +1,273 @@
/*
* Copyright (c) 2007 Dave Airlie <airlied@linux.ie>
* Copyright (c) 2007 Jakob Bornecrantz <wallbraker@gmail.com>
* Copyright (c) 2008 Red Hat Inc.
* Copyright (c) 2007-2008 Tungsten Graphics, Inc., Cedar Park, TX., USA
* Copyright (c) 2007-2008 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef _DRM_MODE_H
#define _DRM_MODE_H
#ifdef __linux__
#if !defined(__KERNEL__) && !defined(_KERNEL)
#include <stdint.h>
#else
#include <linux/kernel.h>
#endif
#endif
#define DRM_DISPLAY_INFO_LEN 32
#define DRM_CONNECTOR_NAME_LEN 32
#define DRM_DISPLAY_MODE_LEN 32
#define DRM_PROP_NAME_LEN 32
#define DRM_MODE_TYPE_BUILTIN (1<<0)
#define DRM_MODE_TYPE_CLOCK_C ((1<<1) | DRM_MODE_TYPE_BUILTIN)
#define DRM_MODE_TYPE_CRTC_C ((1<<2) | DRM_MODE_TYPE_BUILTIN)
#define DRM_MODE_TYPE_PREFERRED (1<<3)
#define DRM_MODE_TYPE_DEFAULT (1<<4)
#define DRM_MODE_TYPE_USERDEF (1<<5)
#define DRM_MODE_TYPE_DRIVER (1<<6)
/* Video mode flags */
/* bit compatible with the xorg definitions. */
#define DRM_MODE_FLAG_PHSYNC (1<<0)
#define DRM_MODE_FLAG_NHSYNC (1<<1)
#define DRM_MODE_FLAG_PVSYNC (1<<2)
#define DRM_MODE_FLAG_NVSYNC (1<<3)
#define DRM_MODE_FLAG_INTERLACE (1<<4)
#define DRM_MODE_FLAG_DBLSCAN (1<<5)
#define DRM_MODE_FLAG_CSYNC (1<<6)
#define DRM_MODE_FLAG_PCSYNC (1<<7)
#define DRM_MODE_FLAG_NCSYNC (1<<8)
#define DRM_MODE_FLAG_HSKEW (1<<9) /* hskew provided */
#define DRM_MODE_FLAG_BCAST (1<<10)
#define DRM_MODE_FLAG_PIXMUX (1<<11)
#define DRM_MODE_FLAG_DBLCLK (1<<12)
#define DRM_MODE_FLAG_CLKDIV2 (1<<13)
/* DPMS flags */
/* bit compatible with the xorg definitions. */
#define DRM_MODE_DPMS_ON 0
#define DRM_MODE_DPMS_STANDBY 1
#define DRM_MODE_DPMS_SUSPEND 2
#define DRM_MODE_DPMS_OFF 3
/* Scaling mode options */
#define DRM_MODE_SCALE_NON_GPU 0
#define DRM_MODE_SCALE_FULLSCREEN 1
#define DRM_MODE_SCALE_NO_SCALE 2
#define DRM_MODE_SCALE_ASPECT 3
/* Dithering mode options */
#define DRM_MODE_DITHERING_OFF 0
#define DRM_MODE_DITHERING_ON 1
struct drm_mode_modeinfo {
uint32_t clock;
uint16_t hdisplay, hsync_start, hsync_end, htotal, hskew;
uint16_t vdisplay, vsync_start, vsync_end, vtotal, vscan;
uint32_t vrefresh; /* vertical refresh * 1000 */
uint32_t flags;
uint32_t type;
char name[DRM_DISPLAY_MODE_LEN];
};
struct drm_mode_card_res {
uint64_t fb_id_ptr;
uint64_t crtc_id_ptr;
uint64_t connector_id_ptr;
uint64_t encoder_id_ptr;
uint32_t count_fbs;
uint32_t count_crtcs;
uint32_t count_connectors;
uint32_t count_encoders;
uint32_t min_width, max_width;
uint32_t min_height, max_height;
};
struct drm_mode_crtc {
uint64_t set_connectors_ptr;
uint32_t count_connectors;
uint32_t crtc_id; /**< Id */
uint32_t fb_id; /**< Id of framebuffer */
uint32_t x, y; /**< Position on the frameuffer */
uint32_t gamma_size;
uint32_t mode_valid;
struct drm_mode_modeinfo mode;
};
#define DRM_MODE_ENCODER_NONE 0
#define DRM_MODE_ENCODER_DAC 1
#define DRM_MODE_ENCODER_TMDS 2
#define DRM_MODE_ENCODER_LVDS 3
#define DRM_MODE_ENCODER_TVDAC 4
struct drm_mode_get_encoder {
uint32_t encoder_id;
uint32_t encoder_type;
uint32_t crtc_id; /**< Id of crtc */
uint32_t possible_crtcs;
uint32_t possible_clones;
};
/* This is for connectors with multiple signal types. */
/* Try to match DRM_MODE_CONNECTOR_X as closely as possible. */
#define DRM_MODE_SUBCONNECTOR_Automatic 0
#define DRM_MODE_SUBCONNECTOR_Unknown 0
#define DRM_MODE_SUBCONNECTOR_DVID 3
#define DRM_MODE_SUBCONNECTOR_DVIA 4
#define DRM_MODE_SUBCONNECTOR_Composite 5
#define DRM_MODE_SUBCONNECTOR_SVIDEO 6
#define DRM_MODE_SUBCONNECTOR_Component 8
#define DRM_MODE_CONNECTOR_Unknown 0
#define DRM_MODE_CONNECTOR_VGA 1
#define DRM_MODE_CONNECTOR_DVII 2
#define DRM_MODE_CONNECTOR_DVID 3
#define DRM_MODE_CONNECTOR_DVIA 4
#define DRM_MODE_CONNECTOR_Composite 5
#define DRM_MODE_CONNECTOR_SVIDEO 6
#define DRM_MODE_CONNECTOR_LVDS 7
#define DRM_MODE_CONNECTOR_Component 8
#define DRM_MODE_CONNECTOR_9PinDIN 9
#define DRM_MODE_CONNECTOR_DisplayPort 10
#define DRM_MODE_CONNECTOR_HDMIA 11
#define DRM_MODE_CONNECTOR_HDMIB 12
struct drm_mode_get_connector {
uint64_t encoders_ptr;
uint64_t modes_ptr;
uint64_t props_ptr;
uint64_t prop_values_ptr;
uint32_t count_modes;
uint32_t count_props;
uint32_t count_encoders;
uint32_t encoder_id; /**< Current Encoder */
uint32_t connector_id; /**< Id */
uint32_t connector_type;
uint32_t connector_type_id;
uint32_t connection;
uint32_t mm_width, mm_height; /**< HxW in millimeters */
uint32_t subpixel;
};
#define DRM_MODE_PROP_PENDING (1<<0)
#define DRM_MODE_PROP_RANGE (1<<1)
#define DRM_MODE_PROP_IMMUTABLE (1<<2)
#define DRM_MODE_PROP_ENUM (1<<3) /* enumerated type with text strings */
#define DRM_MODE_PROP_BLOB (1<<4)
struct drm_mode_property_enum {
uint64_t value;
char name[DRM_PROP_NAME_LEN];
};
struct drm_mode_get_property {
uint64_t values_ptr; /* values and blob lengths */
uint64_t enum_blob_ptr; /* enum and blob id ptrs */
uint32_t prop_id;
uint32_t flags;
char name[DRM_PROP_NAME_LEN];
uint32_t count_values;
uint32_t count_enum_blobs;
};
struct drm_mode_connector_set_property {
uint64_t value;
uint32_t prop_id;
uint32_t connector_id;
};
struct drm_mode_get_blob {
uint32_t blob_id;
uint32_t length;
uint64_t data;
};
struct drm_mode_fb_cmd {
uint32_t fb_id;
uint32_t width, height;
uint32_t pitch;
uint32_t bpp;
uint32_t depth;
/* driver specific handle */
uint32_t handle;
};
struct drm_mode_mode_cmd {
uint32_t connector_id;
struct drm_mode_modeinfo mode;
};
#define DRM_MODE_CURSOR_BO (1<<0)
#define DRM_MODE_CURSOR_MOVE (1<<1)
/*
* depending on the value in flags diffrent members are used.
*
* CURSOR_BO uses
* crtc
* width
* height
* handle - if 0 turns the cursor of
*
* CURSOR_MOVE uses
* crtc
* x
* y
*/
struct drm_mode_cursor {
uint32_t flags;
uint32_t crtc_id;
int32_t x;
int32_t y;
uint32_t width;
uint32_t height;
/* driver specific handle */
uint32_t handle;
};
struct drm_mode_crtc_lut {
uint32_t crtc_id;
uint32_t gamma_size;
/* pointers to arrays */
uint64_t red;
uint64_t green;
uint64_t blue;
};
#endif

View File

@ -79,18 +79,18 @@
0x1002 0x5460 CHIP_RV380|RADEON_IS_MOBILITY "ATI Radeon Mobility X300 M22"
0x1002 0x5462 CHIP_RV380|RADEON_IS_MOBILITY "ATI Radeon Mobility X600 SE M24C"
0x1002 0x5464 CHIP_RV380|RADEON_IS_MOBILITY "ATI FireGL M22 GL 5464"
0x1002 0x5548 CHIP_R420|RADEON_NEW_MEMMAP "ATI Radeon R423 X800"
0x1002 0x5549 CHIP_R420|RADEON_NEW_MEMMAP "ATI Radeon R423 X800 Pro"
0x1002 0x554A CHIP_R420|RADEON_NEW_MEMMAP "ATI Radeon R423 X800 XT PE"
0x1002 0x554B CHIP_R420|RADEON_NEW_MEMMAP "ATI Radeon R423 X800 SE"
0x1002 0x554C CHIP_R420|RADEON_NEW_MEMMAP "ATI Radeon R430 X800 XTP"
0x1002 0x554D CHIP_R420|RADEON_NEW_MEMMAP "ATI Radeon R430 X800 XL"
0x1002 0x554E CHIP_R420|RADEON_NEW_MEMMAP "ATI Radeon R430 X800 SE"
0x1002 0x554F CHIP_R420|RADEON_NEW_MEMMAP "ATI Radeon R430 X800"
0x1002 0x5550 CHIP_R420|RADEON_NEW_MEMMAP "ATI FireGL V7100 R423"
0x1002 0x5551 CHIP_R420|RADEON_NEW_MEMMAP "ATI FireGL V5100 R423 UQ"
0x1002 0x5552 CHIP_R420|RADEON_NEW_MEMMAP "ATI FireGL unknown R423 UR"
0x1002 0x5554 CHIP_R420|RADEON_NEW_MEMMAP "ATI FireGL unknown R423 UT"
0x1002 0x5548 CHIP_R423|RADEON_NEW_MEMMAP "ATI Radeon R423 X800"
0x1002 0x5549 CHIP_R423|RADEON_NEW_MEMMAP "ATI Radeon R423 X800 Pro"
0x1002 0x554A CHIP_R423|RADEON_NEW_MEMMAP "ATI Radeon R423 X800 XT PE"
0x1002 0x554B CHIP_R423|RADEON_NEW_MEMMAP "ATI Radeon R423 X800 SE"
0x1002 0x554C CHIP_R423|RADEON_NEW_MEMMAP "ATI Radeon R430 X800 XTP"
0x1002 0x554D CHIP_R423|RADEON_NEW_MEMMAP "ATI Radeon R430 X800 XL"
0x1002 0x554E CHIP_R423|RADEON_NEW_MEMMAP "ATI Radeon R430 X800 SE"
0x1002 0x554F CHIP_R423|RADEON_NEW_MEMMAP "ATI Radeon R430 X800"
0x1002 0x5550 CHIP_R423|RADEON_NEW_MEMMAP "ATI FireGL V7100 R423"
0x1002 0x5551 CHIP_R423|RADEON_NEW_MEMMAP "ATI FireGL V5100 R423 UQ"
0x1002 0x5552 CHIP_R423|RADEON_NEW_MEMMAP "ATI FireGL unknown R423 UR"
0x1002 0x5554 CHIP_R423|RADEON_NEW_MEMMAP "ATI FireGL unknown R423 UT"
0x1002 0x564A CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP "ATI Mobility FireGL V5000 M26"
0x1002 0x564B CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP "ATI Mobility FireGL V5000 M26"
0x1002 0x564F CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP "ATI Radeon Mobility X700 XL M26"
@ -120,16 +120,16 @@
0x1002 0x5b65 CHIP_RV380|RADEON_NEW_MEMMAP "ATI FireMV 2200 PCIE (RV370) 5B65"
0x1002 0x5c61 CHIP_RV280|RADEON_IS_MOBILITY "ATI Radeon RV280 Mobility"
0x1002 0x5c63 CHIP_RV280|RADEON_IS_MOBILITY "ATI Radeon RV280 Mobility"
0x1002 0x5d48 CHIP_R420|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP "ATI Mobility Radeon X800 XT M28"
0x1002 0x5d49 CHIP_R420|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP "ATI Mobility FireGL V5100 M28"
0x1002 0x5d4a CHIP_R420|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP "ATI Mobility Radeon X800 M28"
0x1002 0x5d4c CHIP_R420|RADEON_NEW_MEMMAP "ATI Radeon R480 X850"
0x1002 0x5d4d CHIP_R420|RADEON_NEW_MEMMAP "ATI Radeon R480 X850 XT PE"
0x1002 0x5d4e CHIP_R420|RADEON_NEW_MEMMAP "ATI Radeon R480 X850 SE"
0x1002 0x5d4f CHIP_R420|RADEON_NEW_MEMMAP "ATI Radeon R480 X850 Pro"
0x1002 0x5d50 CHIP_R420|RADEON_NEW_MEMMAP "ATI unknown Radeon / FireGL R480"
0x1002 0x5d52 CHIP_R420|RADEON_NEW_MEMMAP "ATI Radeon R480 X850 XT"
0x1002 0x5d57 CHIP_R420|RADEON_NEW_MEMMAP "ATI Radeon R423 X800 XT"
0x1002 0x5d48 CHIP_R423|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP "ATI Mobility Radeon X800 XT M28"
0x1002 0x5d49 CHIP_R423|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP "ATI Mobility FireGL V5100 M28"
0x1002 0x5d4a CHIP_R423|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP "ATI Mobility Radeon X800 M28"
0x1002 0x5d4c CHIP_R423|RADEON_NEW_MEMMAP "ATI Radeon R480 X850"
0x1002 0x5d4d CHIP_R423|RADEON_NEW_MEMMAP "ATI Radeon R480 X850 XT PE"
0x1002 0x5d4e CHIP_R423|RADEON_NEW_MEMMAP "ATI Radeon R480 X850 SE"
0x1002 0x5d4f CHIP_R423|RADEON_NEW_MEMMAP "ATI Radeon R480 X850 Pro"
0x1002 0x5d50 CHIP_R423|RADEON_NEW_MEMMAP "ATI unknown Radeon / FireGL R480"
0x1002 0x5d52 CHIP_R423|RADEON_NEW_MEMMAP "ATI Radeon R480 X850 XT"
0x1002 0x5d57 CHIP_R423|RADEON_NEW_MEMMAP "ATI Radeon R423 X800 XT"
0x1002 0x5e48 CHIP_RV410|RADEON_NEW_MEMMAP "ATI FireGL V5000 RV410"
0x1002 0x5e4a CHIP_RV410|RADEON_NEW_MEMMAP "ATI Radeon RV410 X700 XT"
0x1002 0x5e4b CHIP_RV410|RADEON_NEW_MEMMAP "ATI Radeon RV410 X700 Pro"
@ -235,6 +235,10 @@
0x1002 0x7835 CHIP_RS300|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP "ATI Radeon RS350 Mobility IGP"
0x1002 0x791e CHIP_RS690|RADEON_IS_IGP|RADEON_NEW_MEMMAP|RADEON_IS_IGPGART "ATI Radeon RS690 X1250 IGP"
0x1002 0x791f CHIP_RS690|RADEON_IS_IGP|RADEON_NEW_MEMMAP|RADEON_IS_IGPGART "ATI Radeon RS690 X1270 IGP"
0x1002 0x796c CHIP_RS740|RADEON_IS_IGP|RADEON_NEW_MEMMAP|RADEON_IS_IGPGART "ATI Radeon RS740 HD2100 IGP"
0x1002 0x796d CHIP_RS740|RADEON_IS_IGP|RADEON_NEW_MEMMAP|RADEON_IS_IGPGART "ATI Radeon RS740 HD2100 IGP"
0x1002 0x796e CHIP_RS740|RADEON_IS_IGP|RADEON_NEW_MEMMAP|RADEON_IS_IGPGART "ATI Radeon RS740 HD2100 IGP"
0x1002 0x796f CHIP_RS740|RADEON_IS_IGP|RADEON_NEW_MEMMAP|RADEON_IS_IGPGART "ATI Radeon RS740 HD2100 IGP"
[r128]
0x1002 0x4c45 0 "ATI Rage 128 Mobility LE (PCI)"

File diff suppressed because it is too large Load Diff

View File

@ -111,14 +111,25 @@ typedef struct drm_i915_sarea {
unsigned int rotated_tiled;
unsigned int rotated2_tiled;
int planeA_x;
int planeA_y;
int planeA_w;
int planeA_h;
int planeB_x;
int planeB_y;
int planeB_w;
int planeB_h;
/* compat defines for the period of time when pipeA_* got renamed
* to planeA_*. They mean pipe, really.
*/
#define planeA_x pipeA_x
#define planeA_y pipeA_y
#define planeA_w pipeA_w
#define planeA_h pipeA_h
#define planeB_x pipeB_x
#define planeB_y pipeB_y
#define planeB_w pipeB_w
#define planeB_h pipeB_h
int pipeA_x;
int pipeA_y;
int pipeA_w;
int pipeA_h;
int pipeB_x;
int pipeB_y;
int pipeB_w;
int pipeB_h;
/* Triple buffering */
drm_handle_t third_handle;
@ -176,6 +187,25 @@ typedef struct drm_i915_sarea {
#define DRM_I915_MMIO 0x10
#define DRM_I915_HWS_ADDR 0x11
#define DRM_I915_EXECBUFFER 0x12
#define DRM_I915_GEM_INIT 0x13
#define DRM_I915_GEM_EXECBUFFER 0x14
#define DRM_I915_GEM_PIN 0x15
#define DRM_I915_GEM_UNPIN 0x16
#define DRM_I915_GEM_BUSY 0x17
#define DRM_I915_GEM_THROTTLE 0x18
#define DRM_I915_GEM_ENTERVT 0x19
#define DRM_I915_GEM_LEAVEVT 0x1a
#define DRM_I915_GEM_CREATE 0x1b
#define DRM_I915_GEM_PREAD 0x1c
#define DRM_I915_GEM_PWRITE 0x1d
#define DRM_I915_GEM_MMAP 0x1e
#define DRM_I915_GEM_SET_DOMAIN 0x1f
#define DRM_I915_GEM_SW_FINISH 0x20
#define DRM_I915_GEM_SET_TILING 0x21
#define DRM_I915_GEM_GET_TILING 0x22
#define DRM_I915_GEM_GET_APERTURE 0x23
#define DRM_I915_GEM_MMAP_GTT 0x24
#define DRM_I915_GET_PIPE_FROM_CRTC_ID 0x25
#define DRM_IOCTL_I915_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT, drm_i915_init_t)
#define DRM_IOCTL_I915_FLUSH DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLUSH)
@ -195,6 +225,25 @@ typedef struct drm_i915_sarea {
#define DRM_IOCTL_I915_VBLANK_SWAP DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_VBLANK_SWAP, drm_i915_vblank_swap_t)
#define DRM_IOCTL_I915_MMIO DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_MMIO, drm_i915_mmio)
#define DRM_IOCTL_I915_EXECBUFFER DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_EXECBUFFER, struct drm_i915_execbuffer)
#define DRM_IOCTL_I915_GEM_INIT DRM_IOW(DRM_COMMAND_BASE + DRM_I915_GEM_INIT, struct drm_i915_gem_init)
#define DRM_IOCTL_I915_GEM_EXECBUFFER DRM_IOW(DRM_COMMAND_BASE + DRM_I915_GEM_EXECBUFFER, struct drm_i915_gem_execbuffer)
#define DRM_IOCTL_I915_GEM_PIN DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_PIN, struct drm_i915_gem_pin)
#define DRM_IOCTL_I915_GEM_UNPIN DRM_IOW(DRM_COMMAND_BASE + DRM_I915_GEM_UNPIN, struct drm_i915_gem_unpin)
#define DRM_IOCTL_I915_GEM_BUSY DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_BUSY, struct drm_i915_gem_busy)
#define DRM_IOCTL_I915_GEM_THROTTLE DRM_IO ( DRM_COMMAND_BASE + DRM_I915_GEM_THROTTLE)
#define DRM_IOCTL_I915_GEM_ENTERVT DRM_IO(DRM_COMMAND_BASE + DRM_I915_GEM_ENTERVT)
#define DRM_IOCTL_I915_GEM_LEAVEVT DRM_IO(DRM_COMMAND_BASE + DRM_I915_GEM_LEAVEVT)
#define DRM_IOCTL_I915_GEM_CREATE DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_CREATE, struct drm_i915_gem_create)
#define DRM_IOCTL_I915_GEM_PREAD DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_PREAD, struct drm_i915_gem_pread)
#define DRM_IOCTL_I915_GEM_PWRITE DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_PWRITE, struct drm_i915_gem_pwrite)
#define DRM_IOCTL_I915_GEM_MMAP DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_MMAP, struct drm_i915_gem_mmap)
#define DRM_IOCTL_I915_GEM_MMAP_GTT DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_MMAP_GTT, struct drm_i915_gem_mmap_gtt)
#define DRM_IOCTL_I915_GEM_SET_DOMAIN DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_SET_DOMAIN, struct drm_i915_gem_set_domain)
#define DRM_IOCTL_I915_GEM_SW_FINISH DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_SW_FINISH, struct drm_i915_gem_sw_finish)
#define DRM_IOCTL_I915_GEM_SET_TILING DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GEM_SET_TILING, struct drm_i915_gem_set_tiling)
#define DRM_IOCTL_I915_GEM_GET_TILING DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GEM_GET_TILING, struct drm_i915_gem_get_tiling)
#define DRM_IOCTL_I915_GEM_GET_APERTURE DRM_IOR (DRM_COMMAND_BASE + DRM_I915_GEM_GET_APERTURE, struct drm_i915_gem_get_aperture)
#define DRM_IOCTL_I915_GET_PIPE_FROM_CRTC_ID DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GET_PIPE_FROM_CRTC_ID, struct drm_i915_get_pipe_from_crtc_id)
/* Asynchronous page flipping:
*/
@ -248,6 +297,8 @@ typedef struct drm_i915_irq_wait {
#define I915_PARAM_ALLOW_BATCHBUFFER 2
#define I915_PARAM_LAST_DISPATCH 3
#define I915_PARAM_CHIPSET_ID 4
#define I915_PARAM_HAS_GEM 5
#define I915_PARAM_NUM_FENCES_AVAIL 6
typedef struct drm_i915_getparam {
int param;
@ -259,6 +310,7 @@ typedef struct drm_i915_getparam {
#define I915_SETPARAM_USE_MI_BATCHBUFFER_START 1
#define I915_SETPARAM_TEX_LRU_LOG_GRANULARITY 2
#define I915_SETPARAM_ALLOW_BATCHBUFFER 3
#define I915_SETPARAM_NUM_USED_FENCES 4
typedef struct drm_i915_setparam {
int param;
@ -395,4 +447,336 @@ struct drm_i915_execbuffer {
struct drm_fence_arg fence_arg;
};
struct drm_i915_gem_init {
/**
* Beginning offset in the GTT to be managed by the DRM memory
* manager.
*/
uint64_t gtt_start;
/**
* Ending offset in the GTT to be managed by the DRM memory
* manager.
*/
uint64_t gtt_end;
};
struct drm_i915_gem_create {
/**
* Requested size for the object.
*
* The (page-aligned) allocated size for the object will be returned.
*/
uint64_t size;
/**
* Returned handle for the object.
*
* Object handles are nonzero.
*/
uint32_t handle;
uint32_t pad;
};
struct drm_i915_gem_pread {
/** Handle for the object being read. */
uint32_t handle;
uint32_t pad;
/** Offset into the object to read from */
uint64_t offset;
/** Length of data to read */
uint64_t size;
/**
* Pointer to write the data into.
*
* This is a fixed-size type for 32/64 compatibility.
*/
uint64_t data_ptr;
};
struct drm_i915_gem_pwrite {
/** Handle for the object being written to. */
uint32_t handle;
uint32_t pad;
/** Offset into the object to write to */
uint64_t offset;
/** Length of data to write */
uint64_t size;
/**
* Pointer to read the data from.
*
* This is a fixed-size type for 32/64 compatibility.
*/
uint64_t data_ptr;
};
struct drm_i915_gem_mmap {
/** Handle for the object being mapped. */
uint32_t handle;
uint32_t pad;
/** Offset in the object to map. */
uint64_t offset;
/**
* Length of data to map.
*
* The value will be page-aligned.
*/
uint64_t size;
/**
* Returned pointer the data was mapped at.
*
* This is a fixed-size type for 32/64 compatibility.
*/
uint64_t addr_ptr;
};
struct drm_i915_gem_mmap_gtt {
/** Handle for the object being mapped. */
uint32_t handle;
uint32_t pad;
/**
* Fake offset to use for subsequent mmap call
*
* This is a fixed-size type for 32/64 compatibility.
*/
uint64_t offset;
};
struct drm_i915_gem_set_domain {
/** Handle for the object */
uint32_t handle;
/** New read domains */
uint32_t read_domains;
/** New write domain */
uint32_t write_domain;
};
struct drm_i915_gem_sw_finish {
/** Handle for the object */
uint32_t handle;
};
struct drm_i915_gem_relocation_entry {
/**
* Handle of the buffer being pointed to by this relocation entry.
*
* It's appealing to make this be an index into the mm_validate_entry
* list to refer to the buffer, but this allows the driver to create
* a relocation list for state buffers and not re-write it per
* exec using the buffer.
*/
uint32_t target_handle;
/**
* Value to be added to the offset of the target buffer to make up
* the relocation entry.
*/
uint32_t delta;
/** Offset in the buffer the relocation entry will be written into */
uint64_t offset;
/**
* Offset value of the target buffer that the relocation entry was last
* written as.
*
* If the buffer has the same offset as last time, we can skip syncing
* and writing the relocation. This value is written back out by
* the execbuffer ioctl when the relocation is written.
*/
uint64_t presumed_offset;
/**
* Target memory domains read by this operation.
*/
uint32_t read_domains;
/**
* Target memory domains written by this operation.
*
* Note that only one domain may be written by the whole
* execbuffer operation, so that where there are conflicts,
* the application will get -EINVAL back.
*/
uint32_t write_domain;
};
/** @{
* Intel memory domains
*
* Most of these just align with the various caches in
* the system and are used to flush and invalidate as
* objects end up cached in different domains.
*/
/** CPU cache */
#define I915_GEM_DOMAIN_CPU 0x00000001
/** Render cache, used by 2D and 3D drawing */
#define I915_GEM_DOMAIN_RENDER 0x00000002
/** Sampler cache, used by texture engine */
#define I915_GEM_DOMAIN_SAMPLER 0x00000004
/** Command queue, used to load batch buffers */
#define I915_GEM_DOMAIN_COMMAND 0x00000008
/** Instruction cache, used by shader programs */
#define I915_GEM_DOMAIN_INSTRUCTION 0x00000010
/** Vertex address cache */
#define I915_GEM_DOMAIN_VERTEX 0x00000020
/** GTT domain - aperture and scanout */
#define I915_GEM_DOMAIN_GTT 0x00000040
/** @} */
struct drm_i915_gem_exec_object {
/**
* User's handle for a buffer to be bound into the GTT for this
* operation.
*/
uint32_t handle;
/** Number of relocations to be performed on this buffer */
uint32_t relocation_count;
/**
* Pointer to array of struct drm_i915_gem_relocation_entry containing
* the relocations to be performed in this buffer.
*/
uint64_t relocs_ptr;
/** Required alignment in graphics aperture */
uint64_t alignment;
/**
* Returned value of the updated offset of the object, for future
* presumed_offset writes.
*/
uint64_t offset;
};
struct drm_i915_gem_execbuffer {
/**
* List of buffers to be validated with their relocations to be
* performend on them.
*
* This is a pointer to an array of struct drm_i915_gem_validate_entry.
*
* These buffers must be listed in an order such that all relocations
* a buffer is performing refer to buffers that have already appeared
* in the validate list.
*/
uint64_t buffers_ptr;
uint32_t buffer_count;
/** Offset in the batchbuffer to start execution from. */
uint32_t batch_start_offset;
/** Bytes used in batchbuffer from batch_start_offset */
uint32_t batch_len;
uint32_t DR1;
uint32_t DR4;
uint32_t num_cliprects;
/** This is a struct drm_clip_rect *cliprects */
uint64_t cliprects_ptr;
};
struct drm_i915_gem_pin {
/** Handle of the buffer to be pinned. */
uint32_t handle;
uint32_t pad;
/** alignment required within the aperture */
uint64_t alignment;
/** Returned GTT offset of the buffer. */
uint64_t offset;
};
struct drm_i915_gem_unpin {
/** Handle of the buffer to be unpinned. */
uint32_t handle;
uint32_t pad;
};
struct drm_i915_gem_busy {
/** Handle of the buffer to check for busy */
uint32_t handle;
/** Return busy status (1 if busy, 0 if idle) */
uint32_t busy;
};
#define I915_TILING_NONE 0
#define I915_TILING_X 1
#define I915_TILING_Y 2
#define I915_BIT_6_SWIZZLE_NONE 0
#define I915_BIT_6_SWIZZLE_9 1
#define I915_BIT_6_SWIZZLE_9_10 2
#define I915_BIT_6_SWIZZLE_9_11 3
#define I915_BIT_6_SWIZZLE_9_10_11 4
/* Not seen by userland */
#define I915_BIT_6_SWIZZLE_UNKNOWN 5
struct drm_i915_gem_set_tiling {
/** Handle of the buffer to have its tiling state updated */
uint32_t handle;
/**
* Tiling mode for the object (I915_TILING_NONE, I915_TILING_X,
* I915_TILING_Y).
*
* This value is to be set on request, and will be updated by the
* kernel on successful return with the actual chosen tiling layout.
*
* The tiling mode may be demoted to I915_TILING_NONE when the system
* has bit 6 swizzling that can't be managed correctly by GEM.
*
* Buffer contents become undefined when changing tiling_mode.
*/
uint32_t tiling_mode;
/**
* Stride in bytes for the object when in I915_TILING_X or
* I915_TILING_Y.
*/
uint32_t stride;
/**
* Returned address bit 6 swizzling required for CPU access through
* mmap mapping.
*/
uint32_t swizzle_mode;
};
struct drm_i915_gem_get_tiling {
/** Handle of the buffer to get tiling state for. */
uint32_t handle;
/**
* Current tiling mode for the object (I915_TILING_NONE, I915_TILING_X,
* I915_TILING_Y).
*/
uint32_t tiling_mode;
/**
* Returned address bit 6 swizzling required for CPU access through
* mmap mapping.
*/
uint32_t swizzle_mode;
};
struct drm_i915_gem_get_aperture {
/** Total size of the aperture used by i915_gem_execbuffer, in bytes */
uint64_t aper_size;
/**
* Available space in the aperture used by i915_gem_execbuffer, in
* bytes
*/
uint64_t aper_available_size;
};
struct drm_i915_get_pipe_from_crtc_id {
/** ID of CRTC being requested **/
uint32_t crtc_id;
/** pipe of requested CRTC **/
uint32_t pipe;
};
#endif /* _I915_DRM_H_ */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -834,8 +834,14 @@ static int mach64_bm_dma_test(struct drm_device * dev)
/* FIXME: get a dma buffer from the freelist here */
DRM_DEBUG("Allocating data memory ...\n");
#ifdef __FreeBSD__
DRM_UNLOCK();
#endif
cpu_addr_dmah =
drm_pci_alloc(dev, 0x1000, 0x1000, 0xfffffffful);
#ifdef __FreeBSD__
DRM_LOCK();
#endif
if (!cpu_addr_dmah) {
DRM_INFO("data-memory allocation failed!\n");
return -ENOMEM;

View File

@ -143,7 +143,7 @@ void mach64_driver_irq_preinstall(struct drm_device * dev)
int mach64_driver_irq_postinstall(struct drm_device * dev)
{
return drm_vblank_init(dev, 1);
return 0;
}
void mach64_driver_irq_uninstall(struct drm_device * dev)

View File

@ -396,6 +396,7 @@ int mga_freelist_put(struct drm_device * dev, struct drm_buf * buf)
int mga_driver_load(struct drm_device *dev, unsigned long flags)
{
drm_mga_private_t *dev_priv;
int ret;
dev_priv = drm_alloc(sizeof(drm_mga_private_t), DRM_MEM_DRIVER);
if (!dev_priv)
@ -415,6 +416,13 @@ int mga_driver_load(struct drm_device *dev, unsigned long flags)
dev->types[7] = _DRM_STAT_PRIMARY;
dev->types[8] = _DRM_STAT_SECONDARY;
ret = drm_vblank_init(dev, 1);
if (ret) {
(void) mga_driver_unload(dev);
return ret;
}
return 0;
}

View File

@ -154,11 +154,6 @@ void mga_driver_irq_preinstall(struct drm_device * dev)
int mga_driver_irq_postinstall(struct drm_device * dev)
{
drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
int ret;
ret = drm_vblank_init(dev, 1);
if (ret)
return ret;
DRM_INIT_WAITQUEUE(&dev_priv->fence_queue);

View File

@ -121,6 +121,7 @@ nouveau_dma_channel_takedown(struct drm_device *dev)
DRM_DEBUG("\n");
if (dchan->chan) {
drm_core_ioremapfree(dchan->chan->pushbuf_mem->map, dev);
nouveau_fifo_free(dchan->chan);
dchan->chan = NULL;
}

View File

@ -25,13 +25,26 @@
#ifndef __NOUVEAU_DRM_H__
#define __NOUVEAU_DRM_H__
#define NOUVEAU_DRM_HEADER_PATCHLEVEL 11
#define NOUVEAU_DRM_HEADER_PATCHLEVEL 12
struct drm_nouveau_channel_alloc {
uint32_t fb_ctxdma_handle;
uint32_t tt_ctxdma_handle;
int channel;
/* Notifier memory */
drm_handle_t notifier;
int notifier_size;
/* DRM-enforced subchannel assignments */
struct {
uint32_t handle;
uint32_t grclass;
} subchan[8];
uint32_t nr_subchan;
/* !MM_ENABLED ONLY */
uint32_t put_base;
/* FIFO control regs */
drm_handle_t ctrl;
@ -39,9 +52,6 @@ struct drm_nouveau_channel_alloc {
/* DMA command buffer */
drm_handle_t cmdbuf;
int cmdbuf_size;
/* Notifier memory */
drm_handle_t notifier;
int notifier_size;
};
struct drm_nouveau_channel_free {
@ -126,6 +136,8 @@ struct drm_nouveau_mem_tile {
#define NOUVEAU_GETPARAM_AGP_SIZE 9
#define NOUVEAU_GETPARAM_PCI_PHYSICAL 10
#define NOUVEAU_GETPARAM_CHIPSET_ID 11
#define NOUVEAU_GETPARAM_MM_ENABLED 12
#define NOUVEAU_GETPARAM_VM_VRAM_BASE 13
struct drm_nouveau_getparam {
uint64_t param;
uint64_t value;
@ -138,6 +150,100 @@ struct drm_nouveau_setparam {
uint64_t value;
};
#define NOUVEAU_GEM_DOMAIN_CPU (1 << 0)
#define NOUVEAU_GEM_DOMAIN_VRAM (1 << 1)
#define NOUVEAU_GEM_DOMAIN_GART (1 << 2)
#define NOUVEAU_GEM_DOMAIN_NOMAP (1 << 3)
#define NOUVEAU_GEM_DOMAIN_TILE (1 << 30)
#define NOUVEAU_GEM_DOMAIN_TILE_ZETA (1 << 31)
struct drm_nouveau_gem_new {
uint64_t size;
uint32_t channel_hint;
uint32_t align;
uint32_t handle;
uint32_t domain;
uint32_t offset;
};
struct drm_nouveau_gem_pushbuf_bo {
uint64_t user_priv;
uint32_t handle;
uint32_t read_domains;
uint32_t write_domains;
uint32_t valid_domains;
uint32_t presumed_ok;
uint32_t presumed_domain;
uint64_t presumed_offset;
};
#define NOUVEAU_GEM_RELOC_LOW (1 << 0)
#define NOUVEAU_GEM_RELOC_HIGH (1 << 1)
#define NOUVEAU_GEM_RELOC_OR (1 << 2)
struct drm_nouveau_gem_pushbuf_reloc {
uint32_t bo_index;
uint32_t reloc_index;
uint32_t flags;
uint32_t data;
uint32_t vor;
uint32_t tor;
};
#define NOUVEAU_GEM_MAX_BUFFERS 1024
#define NOUVEAU_GEM_MAX_RELOCS 1024
struct drm_nouveau_gem_pushbuf {
uint32_t channel;
uint32_t nr_dwords;
uint32_t nr_buffers;
uint32_t nr_relocs;
uint64_t dwords;
uint64_t buffers;
uint64_t relocs;
};
struct drm_nouveau_gem_pushbuf_call {
uint32_t channel;
uint32_t handle;
uint32_t offset;
uint32_t nr_buffers;
uint32_t nr_relocs;
uint32_t pad0;
uint64_t buffers;
uint64_t relocs;
};
struct drm_nouveau_gem_pin {
uint32_t handle;
uint32_t domain;
uint64_t offset;
};
struct drm_nouveau_gem_unpin {
uint32_t handle;
};
struct drm_nouveau_gem_mmap {
uint32_t handle;
uint32_t pad;
uint64_t vaddr;
};
struct drm_nouveau_gem_cpu_prep {
uint32_t handle;
};
struct drm_nouveau_gem_cpu_fini {
uint32_t handle;
};
struct drm_nouveau_gem_tile {
uint32_t handle;
uint32_t delta;
uint32_t size;
uint32_t flags;
};
enum nouveau_card_type {
NV_UNKNOWN =0,
NV_04 =4,
@ -178,5 +284,16 @@ struct drm_nouveau_sarea {
#define DRM_NOUVEAU_MEM_ALLOC 0x08
#define DRM_NOUVEAU_MEM_FREE 0x09
#define DRM_NOUVEAU_MEM_TILE 0x0a
#define DRM_NOUVEAU_SUSPEND 0x0b
#define DRM_NOUVEAU_RESUME 0x0c
#define DRM_NOUVEAU_GEM_NEW 0x40
#define DRM_NOUVEAU_GEM_PUSHBUF 0x41
#define DRM_NOUVEAU_GEM_PUSHBUF_CALL 0x42
#define DRM_NOUVEAU_GEM_PIN 0x43
#define DRM_NOUVEAU_GEM_UNPIN 0x44
#define DRM_NOUVEAU_GEM_MMAP 0x45
#define DRM_NOUVEAU_GEM_CPU_PREP 0x46
#define DRM_NOUVEAU_GEM_CPU_FINI 0x47
#define DRM_NOUVEAU_GEM_TILE 0x48
#endif /* __NOUVEAU_DRM_H__ */

View File

@ -34,7 +34,7 @@
#define DRIVER_MAJOR 0
#define DRIVER_MINOR 0
#define DRIVER_PATCHLEVEL 11
#define DRIVER_PATCHLEVEL 12
#define NOUVEAU_FAMILY 0x0000FFFF
#define NOUVEAU_FLAGS 0xFFFF0000
@ -310,6 +310,15 @@ struct drm_nouveau_private {
struct nouveau_config config;
struct list_head gpuobj_list;
struct nouveau_suspend_resume {
uint32_t fifo_mode;
uint32_t graph_ctx_control;
uint32_t graph_state;
uint32_t *ramin_copy;
uint64_t ramin_size;
} susres;
struct backlight_device *backlight;
};
#define NOUVEAU_CHECK_INITIALISED_WITH_RETURN do { \
@ -344,6 +353,10 @@ extern void nouveau_wait_for_idle(struct drm_device *);
extern int nouveau_card_init(struct drm_device *);
extern int nouveau_ioctl_card_init(struct drm_device *, void *data,
struct drm_file *);
extern int nouveau_ioctl_suspend(struct drm_device *, void *data,
struct drm_file *);
extern int nouveau_ioctl_resume(struct drm_device *, void *data,
struct drm_file *);
/* nouveau_mem.c */
extern int nouveau_mem_init_heap(struct mem_block **, uint64_t start,
@ -391,6 +404,7 @@ extern int nouveau_fifo_alloc(struct drm_device *dev,
struct mem_block *pushbuf,
uint32_t fb_ctxdma, uint32_t tt_ctxdma);
extern void nouveau_fifo_free(struct nouveau_channel *);
extern int nouveau_channel_idle(struct nouveau_channel *chan);
/* nouveau_object.c */
extern int nouveau_gpuobj_early_init(struct drm_device *);
@ -455,6 +469,10 @@ extern int nouveau_dma_channel_init(struct drm_device *);
extern void nouveau_dma_channel_takedown(struct drm_device *);
extern int nouveau_dma_wait(struct drm_device *, int size);
/* nouveau_backlight.c */
extern int nouveau_backlight_init(struct drm_device *);
extern void nouveau_backlight_exit(struct drm_device *);
/* nv04_fb.c */
extern int nv04_fb_init(struct drm_device *);
extern void nv04_fb_takedown(struct drm_device *);

View File

@ -131,7 +131,7 @@ int nouveau_fifo_init(struct drm_device *dev)
/* No cmdbuf object */
NV_WRITE(NV04_PFIFO_CACHE1_DMA_INSTANCE, 0x00000000);
NV_WRITE(NV03_PFIFO_CACHE0_PUSH0, 0x00000000);
NV_WRITE(NV03_PFIFO_CACHE0_PULL0, 0x00000000);
NV_WRITE(NV04_PFIFO_CACHE0_PULL0, 0x00000000);
NV_WRITE(NV04_PFIFO_SIZE, 0x0000FFFF);
NV_WRITE(NV04_PFIFO_CACHE1_HASH, 0x0000FFFF);
NV_WRITE(NV04_PFIFO_CACHE0_PULL1, 0x00000001);
@ -362,7 +362,8 @@ nouveau_fifo_alloc(struct drm_device *dev, struct nouveau_channel **chan_ret,
/* If this is the first channel, setup PFIFO ourselves. For any
* other case, the GPU will handle this when it switches contexts.
*/
if (dev_priv->fifo_alloc_count == 1) {
if (dev_priv->card_type < NV_50 &&
dev_priv->fifo_alloc_count == 1) {
ret = engine->fifo.load_context(chan);
if (ret) {
nouveau_fifo_free(chan);
@ -390,7 +391,7 @@ nouveau_fifo_alloc(struct drm_device *dev, struct nouveau_channel **chan_ret,
return 0;
}
static int
int
nouveau_channel_idle(struct nouveau_channel *chan)
{
struct drm_device *dev = chan->dev;
@ -594,6 +595,8 @@ struct drm_ioctl_desc nouveau_ioctls[] = {
DRM_IOCTL_DEF(DRM_NOUVEAU_MEM_ALLOC, nouveau_ioctl_mem_alloc, DRM_AUTH),
DRM_IOCTL_DEF(DRM_NOUVEAU_MEM_FREE, nouveau_ioctl_mem_free, DRM_AUTH),
DRM_IOCTL_DEF(DRM_NOUVEAU_MEM_TILE, nouveau_ioctl_mem_tile, DRM_AUTH),
DRM_IOCTL_DEF(DRM_NOUVEAU_SUSPEND, nouveau_ioctl_suspend, DRM_AUTH),
DRM_IOCTL_DEF(DRM_NOUVEAU_RESUME, nouveau_ioctl_resume, DRM_AUTH),
};
int nouveau_max_ioctl = DRM_ARRAY_SIZE(nouveau_ioctls);

View File

@ -442,9 +442,10 @@ static void
nv50_pgraph_irq_handler(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
uint32_t status;
uint32_t status, nsource;
status = NV_READ(NV03_PGRAPH_INTR);
nsource = NV_READ(NV03_PGRAPH_NSOURCE);
if (status & 0x00000020) {
nouveau_pgraph_intr_error(dev,
@ -463,10 +464,29 @@ nv50_pgraph_irq_handler(struct drm_device *dev)
}
if (status & 0x00200000) {
nouveau_pgraph_intr_error(dev,
int r;
nouveau_pgraph_intr_error(dev, nsource |
NV03_PGRAPH_NSOURCE_PROTECTION_ERROR);
DRM_ERROR("magic set 1:\n");
for (r = 0x408900; r <= 0x408910; r += 4)
DRM_ERROR("\t0x%08x: 0x%08x\n", r, NV_READ(r));
NV_WRITE(0x408900, NV_READ(0x408904) | 0xc0000000);
for (r = 0x408e08; r <= 0x408e24; r += 4)
DRM_ERROR("\t0x%08x: 0x%08x\n", r, NV_READ(r));
NV_WRITE(0x408e08, NV_READ(0x408e08) | 0xc0000000);
DRM_ERROR("magic set 2:\n");
for (r = 0x409900; r <= 0x409910; r += 4)
DRM_ERROR("\t0x%08x: 0x%08x\n", r, NV_READ(r));
NV_WRITE(0x409900, NV_READ(0x409904) | 0xc0000000);
for (r = 0x409e08; r <= 0x409e24; r += 4)
DRM_ERROR("\t0x%08x: 0x%08x\n", r, NV_READ(r));
NV_WRITE(0x409e08, NV_READ(0x409e08) | 0xc0000000);
status &= ~0x00200000;
NV_WRITE(NV03_PGRAPH_NSOURCE, nsource);
NV_WRITE(NV03_PGRAPH_INTR, 0x00200000);
}

View File

@ -231,34 +231,69 @@ void nouveau_mem_close(struct drm_device *dev)
nouveau_mem_takedown(&dev_priv->pci_heap);
}
/*XXX won't work on BSD because of pci_read_config_dword */
/*XXX BSD needs compat functions for pci access
* #define DRM_PCI_DEV struct device
* #define drm_pci_get_bsf pci_get_bsf
* and a small inline to do *val = pci_read_config(pdev->device, where, 4);
* might work
*/
static int nforce_pci_fn_read_config_dword(int devfn, int where, uint32_t *val)
{
#ifdef __linux__
DRM_PCI_DEV *pdev;
if (!(pdev = drm_pci_get_bsf(0, 0, devfn))) {
DRM_ERROR("nForce PCI device function 0x%02x not found\n",
devfn);
return -ENODEV;
}
return drm_pci_read_config_dword(pdev, where, val);
#else
DRM_ERROR("BSD compat for checking IGP memory amount needed\n");
return 0;
#endif
}
static void nouveau_mem_check_nforce_dimms(struct drm_device *dev)
{
uint32_t mem_ctrlr_pciid;
nforce_pci_fn_read_config_dword(3, 0x00, &mem_ctrlr_pciid);
mem_ctrlr_pciid >>= 16;
if (mem_ctrlr_pciid == 0x01a9 || mem_ctrlr_pciid == 0x01ab ||
mem_ctrlr_pciid == 0x01ed) {
uint32_t dimm[3];
int i;
for (i = 0; i < 3; i++) {
nforce_pci_fn_read_config_dword(2, 0x40 + i * 4, &dimm[i]);
dimm[i] = (dimm[i] >> 8) & 0x4f;
}
if (dimm[0] + dimm[1] != dimm[2])
DRM_INFO("Your nForce DIMMs are not arranged in "
"optimal banks!\n");
}
}
static uint32_t
nouveau_mem_fb_amount_igp(struct drm_device *dev)
{
#if defined(__linux__) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19))
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct pci_dev *bridge;
uint32_t mem;
uint32_t mem = 0;
bridge = pci_get_bus_and_slot(0, PCI_DEVFN(0,1));
if (!bridge) {
DRM_ERROR("no bridge device\n");
return 0;
}
if (dev_priv->flags&NV_NFORCE) {
pci_read_config_dword(bridge, 0x7C, &mem);
if (dev_priv->flags & NV_NFORCE) {
nforce_pci_fn_read_config_dword(1, 0x7C, &mem);
return (uint64_t)(((mem >> 6) & 31) + 1)*1024*1024;
} else
if(dev_priv->flags&NV_NFORCE2) {
pci_read_config_dword(bridge, 0x84, &mem);
}
if (dev_priv->flags & NV_NFORCE2) {
nforce_pci_fn_read_config_dword(1, 0x84, &mem);
return (uint64_t)(((mem >> 4) & 127) + 1)*1024*1024;
}
DRM_ERROR("impossible!\n");
#else
DRM_ERROR("Linux kernel >= 2.6.19 required to check for igp memory amount\n");
#endif
return 0;
}
@ -300,9 +335,9 @@ uint64_t nouveau_mem_fb_amount(struct drm_device *dev)
} else {
uint64_t mem;
mem = (NV_READ(NV04_FIFO_DATA) &
NV10_FIFO_DATA_RAM_AMOUNT_MB_MASK) >>
NV10_FIFO_DATA_RAM_AMOUNT_MB_SHIFT;
mem = (NV_READ(NV10_PFB_CSTATUS) &
NV10_PFB_CSTATUS_RAM_AMOUNT_MB_MASK) >>
NV10_PFB_CSTATUS_RAM_AMOUNT_MB_SHIFT;
return mem*1024*1024;
}
break;
@ -472,6 +507,9 @@ int nouveau_mem_init(struct drm_device *dev)
dev_priv->fb_phys = 0;
dev_priv->gart_info.type = NOUVEAU_GART_NONE;
if (dev_priv->flags & (NV_NFORCE | NV_NFORCE2))
nouveau_mem_check_nforce_dimms(dev);
/* setup a mtrr over the FB */
dev_priv->fb_mtrr = drm_mtrr_add(drm_get_resource_start(dev, 1),
nouveau_mem_fb_amount(dev),
@ -485,10 +523,7 @@ int nouveau_mem_init(struct drm_device *dev)
*/
if (dev_priv->card_type >= NV_50 && fb_size > (512 * 1024 * 1024))
fb_size = (512 * 1024 * 1024);
/* On at least NV40, RAMIN is actually at the end of vram.
* We don't want to allocate this... */
if (dev_priv->card_type >= NV_40)
fb_size -= dev_priv->ramin_rsvd_vram;
fb_size -= dev_priv->ramin_rsvd_vram;
dev_priv->fb_available_size = fb_size;
DRM_DEBUG("Available VRAM: %dKiB\n", fb_size>>10);
@ -587,18 +622,21 @@ nouveau_mem_alloc(struct drm_device *dev, int alignment, uint64_t size,
* Make things easier on ourselves: all allocations are page-aligned.
* We need that to map allocated regions into the user space
*/
if (alignment < PAGE_SHIFT)
alignment = PAGE_SHIFT;
if (alignment < PAGE_SIZE)
alignment = PAGE_SIZE;
/* Align allocation sizes to 64KiB blocks on G8x. We use a 64KiB
* page size in the GPU VM.
*/
if (flags & NOUVEAU_MEM_FB && dev_priv->card_type >= NV_50) {
size = (size + 65535) & ~65535;
if (alignment < 16)
alignment = 16;
if (alignment < 65536)
alignment = 65536;
}
/* Further down wants alignment in pages, not bytes */
alignment >>= PAGE_SHIFT;
/*
* Warn about 0 sized allocations, but let it go through. It'll return 1 page
*/
@ -806,11 +844,11 @@ nouveau_ioctl_mem_free(struct drm_device *dev, void *data,
memfree->offset -= 512*1024*1024;
block=NULL;
if (memfree->flags & NOUVEAU_MEM_FB)
if (dev_priv->fb_heap && memfree->flags & NOUVEAU_MEM_FB)
block = find_block(dev_priv->fb_heap, memfree->offset);
else if (memfree->flags & NOUVEAU_MEM_AGP)
else if (dev_priv->agp_heap && memfree->flags & NOUVEAU_MEM_AGP)
block = find_block(dev_priv->agp_heap, memfree->offset);
else if (memfree->flags & NOUVEAU_MEM_PCI)
else if (dev_priv->pci_heap && memfree->flags & NOUVEAU_MEM_PCI)
block = find_block(dev_priv->pci_heap, memfree->offset);
if (!block)
return -EFAULT;

View File

@ -141,13 +141,8 @@ nouveau_ramht_insert(struct drm_device *dev, struct nouveau_gpuobj_ref *ref)
ref->channel, co, INSTANCE_RD(ramht, co/4));
co += 8;
if (co >= dev_priv->ramht_size) {
DRM_INFO("no space left after collision\n");
if (co >= dev_priv->ramht_size)
co = 0;
/* exit as it seems to cause crash with nouveau_demo and
* 0xdead0001 object */
break;
}
} while (co != ho);
DRM_ERROR("RAMHT space exhausted. ch=%d\n", ref->channel);
@ -739,7 +734,12 @@ nouveau_gpuobj_dma_new(struct nouveau_channel *chan, int class,
PAGE_SIZE,
DMA_BIDIRECTIONAL);
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27))
/* Not a 100% sure this is the right kdev in all cases. */
if (dma_mapping_error(&dev->primary->kdev, dev->sg->busaddr[idx])) {
#else
if (dma_mapping_error(dev->sg->busaddr[idx])) {
#endif
return -ENOMEM;
}
}
@ -937,7 +937,7 @@ nouveau_gpuobj_channel_init_pramin(struct nouveau_channel *chan)
/* RAMFC */
size += 0x1000;
/* PGRAPH context */
size += 0x60000;
size += 0x70000;
}
DRM_DEBUG("ch%d PRAMIN size: 0x%08x bytes, base alloc=0x%08x\n",

View File

@ -11,10 +11,6 @@
# define NV04_BOOT_0_RAM_AMOUNT_8MB 0x00000002
# define NV04_BOOT_0_RAM_AMOUNT_16MB 0x00000003
#define NV04_FIFO_DATA 0x0010020c
# define NV10_FIFO_DATA_RAM_AMOUNT_MB_MASK 0xfff00000
# define NV10_FIFO_DATA_RAM_AMOUNT_MB_SHIFT 20
#define NV_RAMIN 0x00700000
#define NV_RAMHT_HANDLE_OFFSET 0
@ -99,6 +95,11 @@
* the card will hang early on in the X init process.
*/
# define NV_PMC_ENABLE_UNK13 (1<<13)
#define NV_PBUS_DEBUG_DUALHEAD_CTL 0x000010F0
#define NV40_PMC_BACKLIGHT 0x000015f0
# define NV40_PMC_BACKLIGHT_MASK 0x001f0000
#define NV40_PMC_1700 0x00001700
#define NV40_PMC_1704 0x00001704
#define NV40_PMC_1708 0x00001708
@ -129,7 +130,9 @@
#define NV04_PFB_CFG0 0x00100200
#define NV04_PFB_CFG1 0x00100204
#define NV40_PFB_020C 0x0010020C
#define NV10_PFB_CSTATUS 0x0010020C
# define NV10_PFB_CSTATUS_RAM_AMOUNT_MB_MASK 0xfff00000
# define NV10_PFB_CSTATUS_RAM_AMOUNT_MB_SHIFT 20
#define NV10_PFB_TILE(i) (0x00100240 + (i*16))
#define NV10_PFB_TILE__SIZE 8
#define NV10_PFB_TLIMIT(i) (0x00100244 + (i*16))
@ -404,6 +407,7 @@
#define NV40_PGRAPH_TSIZE1(i) (0x00406908 + (i*16))
#define NV40_PGRAPH_TSTATUS1(i) (0x0040690C + (i*16))
#define NV_PCRTC_GPIO_EXT 0x0060081C
/* It's a guess that this works on NV03. Confirmed on NV04, though */
#define NV04_PFIFO_DELAY_0 0x00002040
@ -542,6 +546,9 @@
/* This name is a partial guess. */
#define NV50_DISPLAY_SUPERVISOR 0x00610024
#define NV50_PDISPLAY_BACKLIGHT 0x0061c084
# define NV50_PDISPLAY_BACKLIGHT_ENABLE 0x80000000
/* Fifo commands. These are not regs, neither masks */
#define NV03_FIFO_CMD_JUMP 0x20000000
#define NV03_FIFO_CMD_JUMP_OFFSET_MASK 0x1ffffffc
@ -591,3 +598,4 @@
#define NV40_RAMFC_UNK_48 0x48
#define NV40_RAMFC_UNK_4C 0x4C
#define NV40_RAMFC_UNK_50 0x50

View File

@ -1,5 +1,6 @@
/*
* Copyright 2005 Stephane Marchesin
* Copyright 2008 Stuart Bennett
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
@ -244,6 +245,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
case 0x50:
case 0x80: /* gotta love NVIDIA's consistency.. */
case 0x90:
case 0xA0:
engine->instmem.init = nv50_instmem_init;
engine->instmem.takedown= nv50_instmem_takedown;
engine->instmem.populate = nv50_instmem_populate;
@ -361,6 +363,11 @@ nouveau_card_init(struct drm_device *dev)
ret = nouveau_dma_channel_init(dev);
if (ret) return ret;
ret = nouveau_backlight_init(dev);
if (ret)
DRM_ERROR("Error code %d when trying to register backlight\n",
ret);
dev_priv->init_state = NOUVEAU_CARD_INIT_DONE;
return 0;
}
@ -373,6 +380,8 @@ static void nouveau_card_takedown(struct drm_device *dev)
DRM_DEBUG("prev state = %d\n", dev_priv->init_state);
if (dev_priv->init_state != NOUVEAU_CARD_INIT_DOWN) {
nouveau_backlight_exit(dev);
nouveau_dma_channel_takedown(dev);
engine->fifo.takedown(dev);
@ -487,7 +496,7 @@ int nouveau_load(struct drm_device *dev, unsigned long flags)
reg1 = readl(regs+NV03_PMC_BOOT_1);
#if defined(__powerpc__)
if (reg1)
reg0=___swab32(reg0);
reg0=__swab32(reg0);
#endif
/* We're dealing with >=NV10 */
@ -628,6 +637,15 @@ int nouveau_ioctl_getparam(struct drm_device *dev, void *data, struct drm_file *
case NOUVEAU_GETPARAM_AGP_SIZE:
getparam->value=dev_priv->gart_info.aper_size;
break;
case NOUVEAU_GETPARAM_MM_ENABLED:
getparam->value = 0;
break;
case NOUVEAU_GETPARAM_VM_VRAM_BASE:
if (dev_priv->card_type >= NV_50)
getparam->value = 0x20000000;
else
getparam->value = 0;
break;
default:
DRM_ERROR("unknown parameter %lld\n", getparam->param);
return -EINVAL;
@ -698,3 +716,182 @@ void nouveau_wait_for_idle(struct drm_device *dev)
}
}
}
static int nouveau_suspend(struct drm_device *dev)
{
struct mem_block *p;
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_suspend_resume *susres = &dev_priv->susres;
struct nouveau_engine *engine = &dev_priv->Engine;
struct nouveau_channel *current_fifo;
int i;
if (dev_priv->card_type >= NV_50) {
DRM_DEBUG("Suspend not supported for NV50+\n");
return -ENODEV;
}
drm_free(susres->ramin_copy, susres->ramin_size, DRM_MEM_DRIVER);
susres->ramin_size = 0;
list_for_each(p, dev_priv->ramin_heap)
if (p->file_priv && (p->start + p->size) > susres->ramin_size)
susres->ramin_size = p->start + p->size;
if (!(susres->ramin_copy = drm_alloc(susres->ramin_size, DRM_MEM_DRIVER))) {
DRM_ERROR("Couldn't alloc RAMIN backing for suspend\n");
return -ENOMEM;
}
for (i = 0; i < engine->fifo.channels; i++) {
uint64_t t_start = engine->timer.read(dev);
if (dev_priv->fifos[i] == NULL)
continue;
/* Give the channel a chance to idle, wait 2s (hopefully) */
while (!nouveau_channel_idle(dev_priv->fifos[i]))
if (engine->timer.read(dev) - t_start > 2000000000ULL) {
DRM_ERROR("Failed to idle channel %d before"
"suspend.", dev_priv->fifos[i]->id);
return -EBUSY;
}
}
nouveau_wait_for_idle(dev);
NV_WRITE(NV04_PGRAPH_FIFO, 0);
/* disable the fifo caches */
NV_WRITE(NV03_PFIFO_CACHES, 0x00000000);
NV_WRITE(NV04_PFIFO_CACHE1_DMA_PUSH,
NV_READ(NV04_PFIFO_CACHE1_DMA_PUSH) & ~1);
NV_WRITE(NV03_PFIFO_CACHE1_PUSH0, 0x00000000);
NV_WRITE(NV04_PFIFO_CACHE1_PULL0, 0x00000000);
susres->fifo_mode = NV_READ(NV04_PFIFO_MODE);
if (dev_priv->card_type >= NV_10) {
susres->graph_state = NV_READ(NV10_PGRAPH_STATE);
susres->graph_ctx_control = NV_READ(NV10_PGRAPH_CTX_CONTROL);
} else {
susres->graph_state = NV_READ(NV04_PGRAPH_STATE);
susres->graph_ctx_control = NV_READ(NV04_PGRAPH_CTX_CONTROL);
}
current_fifo = dev_priv->fifos[engine->fifo.channel_id(dev)];
/* channel may have been deleted but no replacement yet loaded */
if (current_fifo) {
engine->fifo.save_context(current_fifo);
engine->graph.save_context(current_fifo);
}
nouveau_wait_for_idle(dev);
for (i = 0; i < susres->ramin_size / 4; i++)
susres->ramin_copy[i] = NV_RI32(i << 2);
/* reenable the fifo caches */
NV_WRITE(NV04_PFIFO_CACHE1_DMA_PUSH,
NV_READ(NV04_PFIFO_CACHE1_DMA_PUSH) | 1);
NV_WRITE(NV03_PFIFO_CACHE1_PUSH0, 0x00000001);
NV_WRITE(NV04_PFIFO_CACHE1_PULL0, 0x00000001);
NV_WRITE(NV03_PFIFO_CACHES, 0x00000001);
NV_WRITE(NV04_PGRAPH_FIFO, 1);
return 0;
}
static int nouveau_resume(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_suspend_resume *susres = &dev_priv->susres;
struct nouveau_engine *engine = &dev_priv->Engine;
int i;
if (!susres->ramin_copy)
return -EINVAL;
DRM_DEBUG("Doing resume\n");
if (dev_priv->gart_info.type == NOUVEAU_GART_AGP) {
struct drm_agp_info info;
struct drm_agp_mode mode;
/* agp bridge drivers don't re-enable agp on resume. lame. */
if ((i = drm_agp_info(dev, &info))) {
DRM_ERROR("Unable to get AGP info: %d\n", i);
return i;
}
mode.mode = info.mode;
if ((i = drm_agp_enable(dev, mode))) {
DRM_ERROR("Unable to enable AGP: %d\n", i);
return i;
}
}
for (i = 0; i < susres->ramin_size / 4; i++)
NV_WI32(i << 2, susres->ramin_copy[i]);
engine->mc.init(dev);
engine->timer.init(dev);
engine->fb.init(dev);
engine->graph.init(dev);
engine->fifo.init(dev);
NV_WRITE(NV04_PGRAPH_FIFO, 0);
/* disable the fifo caches */
NV_WRITE(NV03_PFIFO_CACHES, 0x00000000);
NV_WRITE(NV04_PFIFO_CACHE1_DMA_PUSH,
NV_READ(NV04_PFIFO_CACHE1_DMA_PUSH) & ~1);
NV_WRITE(NV03_PFIFO_CACHE1_PUSH0, 0x00000000);
NV_WRITE(NV04_PFIFO_CACHE1_PULL0, 0x00000000);
/* PMC power cycling PFIFO in init clobbers some of the stuff stored in
* PRAMIN (such as NV04_PFIFO_CACHE1_DMA_INSTANCE). this is unhelpful
*/
for (i = 0; i < susres->ramin_size / 4; i++)
NV_WI32(i << 2, susres->ramin_copy[i]);
engine->fifo.load_context(dev_priv->fifos[0]);
NV_WRITE(NV04_PFIFO_MODE, susres->fifo_mode);
engine->graph.load_context(dev_priv->fifos[0]);
nouveau_wait_for_idle(dev);
if (dev_priv->card_type >= NV_10) {
NV_WRITE(NV10_PGRAPH_STATE, susres->graph_state);
NV_WRITE(NV10_PGRAPH_CTX_CONTROL, susres->graph_ctx_control);
} else {
NV_WRITE(NV04_PGRAPH_STATE, susres->graph_state);
NV_WRITE(NV04_PGRAPH_CTX_CONTROL, susres->graph_ctx_control);
}
/* reenable the fifo caches */
NV_WRITE(NV04_PFIFO_CACHE1_DMA_PUSH,
NV_READ(NV04_PFIFO_CACHE1_DMA_PUSH) | 1);
NV_WRITE(NV03_PFIFO_CACHE1_PUSH0, 0x00000001);
NV_WRITE(NV04_PFIFO_CACHE1_PULL0, 0x00000001);
NV_WRITE(NV03_PFIFO_CACHES, 0x00000001);
NV_WRITE(NV04_PGRAPH_FIFO, 0x1);
if (dev->irq_enabled)
nouveau_irq_postinstall(dev);
drm_free(susres->ramin_copy, susres->ramin_size, DRM_MEM_DRIVER);
susres->ramin_copy = NULL;
susres->ramin_size = 0;
return 0;
}
int nouveau_ioctl_suspend(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
NOUVEAU_CHECK_INITIALISED_WITH_RETURN;
return nouveau_suspend(dev);
}
int nouveau_ioctl_resume(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
NOUVEAU_CHECK_INITIALISED_WITH_RETURN;
return nouveau_resume(dev);
}

View File

@ -122,8 +122,8 @@ nv04_fifo_save_context(struct nouveau_channel *chan)
struct drm_nouveau_private *dev_priv = dev->dev_private;
uint32_t tmp;
RAMFC_WR(DMA_PUT, NV04_PFIFO_CACHE1_DMA_PUT);
RAMFC_WR(DMA_GET, NV04_PFIFO_CACHE1_DMA_GET);
RAMFC_WR(DMA_PUT, NV_READ(NV04_PFIFO_CACHE1_DMA_PUT));
RAMFC_WR(DMA_GET, NV_READ(NV04_PFIFO_CACHE1_DMA_GET));
tmp = NV_READ(NV04_PFIFO_CACHE1_DMA_DCOUNT) << 16;
tmp |= NV_READ(NV04_PFIFO_CACHE1_DMA_INSTANCE);

View File

@ -17,8 +17,7 @@ nv04_instmem_determine_amount(struct drm_device *dev)
*/
dev_priv->ramin_rsvd_vram = (1*1024* 1024);
} else {
/*XXX: what *are* the limits on <NV40 cards?, and does RAMIN
* exist in vram on those cards as well?
/*XXX: what *are* the limits on <NV40 cards?
*/
dev_priv->ramin_rsvd_vram = (512*1024);
}
@ -41,7 +40,8 @@ nv04_instmem_configure_fixed_tables(struct drm_device *dev)
*/
dev_priv->ramht_offset = 0x10000;
dev_priv->ramht_bits = 9;
dev_priv->ramht_size = (1 << dev_priv->ramht_bits);
dev_priv->ramht_size = (1 << dev_priv->ramht_bits); /* nr entries */
dev_priv->ramht_size *= 8; /* 2 32-bit values per entry in RAMHT */
DRM_DEBUG("RAMHT offset=0x%x, size=%d\n", dev_priv->ramht_offset,
dev_priv->ramht_size);

View File

@ -694,13 +694,15 @@ int nv20_graph_init(struct drm_device *dev) {
NV_WRITE(NV03_PMC_ENABLE, NV_READ(NV03_PMC_ENABLE) |
NV_PMC_ENABLE_PGRAPH);
/* Create Context Pointer Table */
dev_priv->ctx_table_size = 32 * 4;
if ((ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0,
dev_priv->ctx_table_size, 16,
NVOBJ_FLAG_ZERO_ALLOC,
&dev_priv->ctx_table)))
return ret;
if (!dev_priv->ctx_table) {
/* Create Context Pointer Table */
dev_priv->ctx_table_size = 32 * 4;
if ((ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0,
dev_priv->ctx_table_size, 16,
NVOBJ_FLAG_ZERO_ALLOC,
&dev_priv->ctx_table)))
return ret;
}
NV_WRITE(NV20_PGRAPH_CHANNEL_CTX_TABLE,
dev_priv->ctx_table->instance >> 4);
@ -812,13 +814,15 @@ int nv30_graph_init(struct drm_device *dev)
NV_WRITE(NV03_PMC_ENABLE, NV_READ(NV03_PMC_ENABLE) |
NV_PMC_ENABLE_PGRAPH);
/* Create Context Pointer Table */
dev_priv->ctx_table_size = 32 * 4;
if ((ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0,
dev_priv->ctx_table_size, 16,
NVOBJ_FLAG_ZERO_ALLOC,
&dev_priv->ctx_table)))
return ret;
if (!dev_priv->ctx_table) {
/* Create Context Pointer Table */
dev_priv->ctx_table_size = 32 * 4;
if ((ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0,
dev_priv->ctx_table_size, 16,
NVOBJ_FLAG_ZERO_ALLOC,
&dev_priv->ctx_table)))
return ret;
}
NV_WRITE(NV20_PGRAPH_CHANNEL_CTX_TABLE,
dev_priv->ctx_table->instance >> 4);

View File

@ -1544,6 +1544,8 @@ nv40_graph_transfer_context(struct drm_device *dev, uint32_t inst, int save)
tmp |= NV40_PGRAPH_CTXCTL_0304_XFER_CTX;
NV_WRITE(NV40_PGRAPH_CTXCTL_0304, tmp);
nouveau_wait_for_idle(dev);
for (i = 0; i < tv; i++) {
if (NV_READ(NV40_PGRAPH_CTXCTL_030C) == 0)
break;
@ -1565,9 +1567,7 @@ nv40_graph_transfer_context(struct drm_device *dev, uint32_t inst, int save)
return 0;
}
/* Save current context (from PGRAPH) into the channel's context
*XXX: fails sometimes, not sure why..
*/
/* Save current context (from PGRAPH) into the channel's context */
int
nv40_graph_save_context(struct nouveau_channel *chan)
{
@ -1581,9 +1581,7 @@ nv40_graph_save_context(struct nouveau_channel *chan)
return nv40_graph_transfer_context(dev, inst, 1);
}
/* Restore the context for a specific channel into PGRAPH
* XXX: fails sometimes.. not sure why
*/
/* Restore the context for a specific channel into PGRAPH */
int
nv40_graph_load_context(struct nouveau_channel *chan)
{
@ -1984,20 +1982,17 @@ nv40_graph_init(struct drm_device *dev)
default:
DRM_ERROR("Context program for 0x%02x unavailable\n",
dev_priv->chipset);
ctx_prog = NULL;
break;
return -EINVAL;
}
/* Load the context program onto the card */
if (ctx_prog) {
DRM_DEBUG("Loading context program\n");
i = 0;
DRM_DEBUG("Loading context program\n");
NV_WRITE(NV40_PGRAPH_CTXCTL_UCODE_INDEX, 0);
while (ctx_prog[i] != ~0) {
NV_WRITE(NV40_PGRAPH_CTXCTL_UCODE_DATA, ctx_prog[i]);
i++;
}
i = 0;
NV_WRITE(NV40_PGRAPH_CTXCTL_UCODE_INDEX, 0);
while (ctx_prog[i] != ~0) {
NV_WRITE(NV40_PGRAPH_CTXCTL_UCODE_DATA, ctx_prog[i]);
i++;
}
/* No context present currently */

View File

@ -19,7 +19,7 @@ nv40_mc_init(struct drm_device *dev)
case 0x46: /* G72 */
case 0x4e:
case 0x4c: /* C51_G7X */
tmp = NV_READ(NV40_PFB_020C);
tmp = NV_READ(NV10_PFB_CSTATUS);
NV_WRITE(NV40_PMC_1700, tmp);
NV_WRITE(NV40_PMC_1704, 0);
NV_WRITE(NV40_PMC_1708, 0);

View File

@ -269,7 +269,7 @@ nv50_fifo_create_context(struct nouveau_channel *chan)
if (!IS_G80) {
INSTANCE_WR(chan->ramin->gpuobj, 0, chan->id);
INSTANCE_WR(chan->ramin->gpuobj, 1, chan->ramfc->instance);
INSTANCE_WR(chan->ramin->gpuobj, 1, chan->ramfc->instance >> 8);
INSTANCE_WR(ramfc, 0x88/4, 0x3d520); /* some vram addy >> 10 */
INSTANCE_WR(ramfc, 0x98/4, chan->ramin->instance >> 12);

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -297,6 +297,13 @@ nv50_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
vram += NV50_INSTMEM_PAGE_SIZE;
}
NV_WRITE(0x070000, 0x00000001);
while(NV_READ(0x070000) & 1);
NV_WRITE(0x100c80, 0x00040001);
while(NV_READ(0x100c80) & 1);
NV_WRITE(0x100c80, 0x00060001);
while(NV_READ(0x100c80) & 1);
gpuobj->im_bound = 1;
return 0;
}

View File

@ -159,6 +159,7 @@ extern void r128_driver_irq_preinstall(struct drm_device * dev);
extern int r128_driver_irq_postinstall(struct drm_device * dev);
extern void r128_driver_irq_uninstall(struct drm_device * dev);
extern void r128_driver_lastclose(struct drm_device * dev);
extern int r128_driver_load(struct drm_device * dev, unsigned long flags);
extern void r128_driver_preclose(struct drm_device * dev,
struct drm_file *file_priv);

View File

@ -102,7 +102,7 @@ void r128_driver_irq_preinstall(struct drm_device * dev)
int r128_driver_irq_postinstall(struct drm_device * dev)
{
return drm_vblank_init(dev, 1);
return 0;
}
void r128_driver_irq_uninstall(struct drm_device * dev)

View File

@ -77,6 +77,9 @@ static int r300_emit_cliprects(drm_radeon_private_t *dev_priv,
return -EFAULT;
}
box.x2--; /* Hardware expects inclusive bottom-right corner */
box.y2--;
if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RV515) {
box.x1 = (box.x1) &
R300_CLIPRECT_MASK;
@ -95,8 +98,8 @@ static int r300_emit_cliprects(drm_radeon_private_t *dev_priv,
R300_CLIPRECT_MASK;
box.y2 = (box.y2 + R300_CLIPRECT_OFFSET) &
R300_CLIPRECT_MASK;
}
OUT_RING((box.x1 << R300_CLIPRECT_X_SHIFT) |
(box.y1 << R300_CLIPRECT_Y_SHIFT));
OUT_RING((box.x2 << R300_CLIPRECT_X_SHIFT) |
@ -578,22 +581,23 @@ static __inline__ int r300_emit_bitblt_multi(drm_radeon_private_t *dev_priv,
return 0;
}
static __inline__ int r300_emit_indx_buffer(drm_radeon_private_t *dev_priv,
drm_radeon_kcmd_buffer_t *cmdbuf)
static __inline__ int r300_emit_draw_indx_2(drm_radeon_private_t *dev_priv,
drm_radeon_kcmd_buffer_t *cmdbuf)
{
u32 *cmd = (u32 *) cmdbuf->buf;
int count, ret;
u32 *cmd;
int count;
int expected_count;
RING_LOCALS;
count=(cmd[0]>>16) & 0x3fff;
cmd = (u32 *) cmdbuf->buf;
count = (cmd[0]>>16) & 0x3fff;
expected_count = cmd[1] >> 16;
if (!(cmd[1] & R300_VAP_VF_CNTL__INDEX_SIZE_32bit))
expected_count = (expected_count+1)/2;
if ((cmd[1] & 0x8000ffff) != 0x80000810) {
DRM_ERROR("Invalid indx_buffer reg address %08X\n", cmd[1]);
return -EINVAL;
}
ret = !radeon_check_offset(dev_priv, cmd[2]);
if (ret) {
DRM_ERROR("Invalid indx_buffer offset is %08X\n", cmd[2]);
if (count && count != expected_count) {
DRM_ERROR("3D_DRAW_INDX_2: packet size %i, expected %i\n",
count, expected_count);
return -EINVAL;
}
@ -605,6 +609,50 @@ static __inline__ int r300_emit_indx_buffer(drm_radeon_private_t *dev_priv,
cmdbuf->buf += (count+2)*4;
cmdbuf->bufsz -= (count+2)*4;
if (!count) {
drm_r300_cmd_header_t header;
if (cmdbuf->bufsz < 4*4 + sizeof(header)) {
DRM_ERROR("3D_DRAW_INDX_2: expect subsequent INDX_BUFFER, but stream is too short.\n");
return -EINVAL;
}
header.u = *(unsigned int *)cmdbuf->buf;
cmdbuf->buf += sizeof(header);
cmdbuf->bufsz -= sizeof(header);
cmd = (u32 *) cmdbuf->buf;
if (header.header.cmd_type != R300_CMD_PACKET3 ||
header.packet3.packet != R300_CMD_PACKET3_RAW ||
cmd[0] != CP_PACKET3(RADEON_CP_INDX_BUFFER, 2)) {
DRM_ERROR("3D_DRAW_INDX_2: expect subsequent INDX_BUFFER.\n");
return -EINVAL;
}
if ((cmd[1] & 0x8000ffff) != 0x80000810) {
DRM_ERROR("Invalid indx_buffer reg address %08X\n", cmd[1]);
return -EINVAL;
}
if (!radeon_check_offset(dev_priv, cmd[2])) {
DRM_ERROR("Invalid indx_buffer offset is %08X\n", cmd[2]);
return -EINVAL;
}
if (cmd[3] != expected_count) {
DRM_ERROR("INDX_BUFFER: buffer size %i, expected %i\n",
cmd[3], expected_count);
return -EINVAL;
}
BEGIN_RING(4);
OUT_RING(cmd[0]);
OUT_RING_TABLE((int *)(cmdbuf->buf + 4), 3);
ADVANCE_RING();
cmdbuf->buf += 4*4;
cmdbuf->bufsz -= 4*4;
}
return 0;
}
@ -649,18 +697,21 @@ static __inline__ int r300_emit_raw_packet3(drm_radeon_private_t *dev_priv,
return r300_emit_bitblt_multi(dev_priv, cmdbuf);
case RADEON_CP_INDX_BUFFER:
/* DRAW_INDX_2 without INDX_BUFFER seems to lock up the gpu */
return r300_emit_indx_buffer(dev_priv, cmdbuf);
DRM_ERROR("packet3 INDX_BUFFER without preceding 3D_DRAW_INDX_2 is illegal.\n");
return -EINVAL;
case RADEON_CP_3D_DRAW_IMMD_2:
/* triggers drawing using in-packet vertex data */
case RADEON_CP_3D_DRAW_VBUF_2:
/* triggers drawing of vertex buffers setup elsewhere */
dev_priv->track_flush &= ~(RADEON_FLUSH_EMITED |
RADEON_PURGE_EMITED);
break;
case RADEON_CP_3D_DRAW_INDX_2:
/* triggers drawing using indices to vertex buffer */
/* whenever we send vertex we clear flush & purge */
dev_priv->track_flush &= ~(RADEON_FLUSH_EMITED |
RADEON_PURGE_EMITED);
break;
return r300_emit_draw_indx_2(dev_priv, cmdbuf);
case RADEON_WAIT_FOR_IDLE:
case RADEON_CP_NOP:
/* these packets are safe */
@ -758,7 +809,7 @@ static __inline__ void r300_pacify(drm_radeon_private_t *dev_priv)
{
uint32_t cache_z, cache_3d, cache_2d;
RING_LOCALS;
cache_z = R300_ZC_FLUSH;
cache_2d = R300_RB2D_DC_FLUSH;
cache_3d = R300_RB3D_DC_FLUSH;

View File

@ -44,7 +44,8 @@ void radeon_irq_set_state(struct drm_device *dev, u32 mask, int state)
else
dev_priv->irq_enable_reg &= ~mask;
RADEON_WRITE(RADEON_GEN_INT_CNTL, dev_priv->irq_enable_reg);
if (dev->irq_enabled)
RADEON_WRITE(RADEON_GEN_INT_CNTL, dev_priv->irq_enable_reg);
}
static void r500_vbl_irq_set_state(struct drm_device *dev, u32 mask, int state)
@ -56,7 +57,8 @@ static void r500_vbl_irq_set_state(struct drm_device *dev, u32 mask, int state)
else
dev_priv->r500_disp_irq_reg &= ~mask;
RADEON_WRITE(R500_DxMODE_INT_MASK, dev_priv->r500_disp_irq_reg);
if (dev->irq_enabled)
RADEON_WRITE(R500_DxMODE_INT_MASK, dev_priv->r500_disp_irq_reg);
}
int radeon_enable_vblank(struct drm_device *dev, int crtc)
@ -187,6 +189,7 @@ irqreturn_t radeon_driver_irq_handler(DRM_IRQ_ARGS)
(drm_radeon_private_t *) dev->dev_private;
u32 stat;
u32 r500_disp_int;
u32 tmp;
/* Only consider the bits we're interested in - others could be used
* outside the DRM
@ -213,6 +216,33 @@ irqreturn_t radeon_driver_irq_handler(DRM_IRQ_ARGS)
if (stat & RADEON_CRTC2_VBLANK_STAT)
drm_handle_vblank(dev, 1);
}
if (dev->msi_enabled) {
switch(dev_priv->flags & RADEON_FAMILY_MASK) {
case CHIP_RS400:
case CHIP_RS480:
tmp = RADEON_READ(RADEON_AIC_CNTL) &
~RS400_MSI_REARM;
RADEON_WRITE(RADEON_AIC_CNTL, tmp);
RADEON_WRITE(RADEON_AIC_CNTL,
tmp | RS400_MSI_REARM);
break;
case CHIP_RS690:
case CHIP_RS740:
tmp = RADEON_READ(RADEON_BUS_CNTL) &
~RS600_MSI_REARM;
RADEON_WRITE(RADEON_BUS_CNTL, tmp);
RADEON_WRITE(RADEON_BUS_CNTL, tmp |
RS600_MSI_REARM);
break;
default:
tmp = RADEON_READ(RADEON_MSI_REARM_EN) &
~RV370_MSI_REARM_EN;
RADEON_WRITE(RADEON_MSI_REARM_EN, tmp);
RADEON_WRITE(RADEON_MSI_REARM_EN,
tmp | RV370_MSI_REARM_EN);
break;
}
}
return IRQ_HANDLED;
}
@ -339,15 +369,10 @@ int radeon_driver_irq_postinstall(struct drm_device * dev)
{
drm_radeon_private_t *dev_priv =
(drm_radeon_private_t *) dev->dev_private;
int ret;
atomic_set(&dev_priv->swi_emitted, 0);
DRM_INIT_WAITQUEUE(&dev_priv->swi_queue);
ret = drm_vblank_init(dev, 2);
if (ret)
return ret;
dev->max_vblank_count = 0x001fffff;
radeon_irq_set_state(dev, RADEON_SW_INT_ENABLE, 1);

View File

@ -320,7 +320,6 @@ int via_driver_irq_postinstall(struct drm_device * dev)
if (!dev_priv)
return -EINVAL;
drm_vblank_init(dev, 1);
status = VIA_READ(VIA_REG_INTERRUPT);
VIA_WRITE(VIA_REG_INTERRUPT, status | VIA_IRQ_GLOBAL
| dev_priv->irq_enable_mask);

View File

@ -121,9 +121,19 @@ int via_driver_load(struct drm_device *dev, unsigned long chipset)
ret = drm_sman_init(&dev_priv->sman, 2, 12, 8);
if (ret) {
drm_free(dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER);
return ret;
}
#endif
return ret;
ret = drm_vblank_init(dev, 1);
if (ret) {
drm_sman_takedown(&dev_priv->sman);
drm_free(dev_priv, sizeof(drm_via_private_t), DRM_MEM_DRIVER);
return ret;
}
return 0;
}
int via_driver_unload(struct drm_device *dev)

View File

@ -1,29 +1,50 @@
AM_CFLAGS = \
AM_CPPFLAGS = \
-I $(top_srcdir)/shared-core \
-I $(top_srcdir)/libdrm
LDADD = $(top_builddir)/libdrm/libdrm.la
noinst_PROGRAMS = \
dristat \
drmstat
SUBDIRS = \
modeprint \
modetest
if HAVE_LIBUDEV
EXTRA_LTLIBRARIES = libdrmtest.la
libdrmtest_la_SOURCES = \
drmtest.c \
drmtest.h
libdrmtest_la_LIBADD = \
$(top_builddir)/libdrm/libdrm.la
$(top_builddir)/libdrm/libdrm.la \
$(LIBUDEV_LIBS)
LDADD = libdrmtest.la
LDADD += libdrmtest.la
TESTS = auth \
openclose \
getversion \
getclient \
getstats \
lock \
setversion \
updatedraw
XFAIL_TESTS = \
auth \
lock
TESTS = \
openclose \
getversion \
getclient \
getstats \
setversion \
updatedraw \
gem_basic \
gem_flink \
gem_readwrite \
gem_mmap
EXTRA_PROGRAMS = $(TESTS)
endif
CLEANFILES = $(EXTRA_PROGRAMS) $(EXTRA_LTLIBRARIES)

View File

@ -263,7 +263,7 @@ int main(int argc, char **argv)
for (i = 0; i < 16; i++) if (!minor || i == minor) {
sprintf(buf, DRM_DEV_NAME, DRM_DIR_NAME, i);
fd = drmOpenMinor(i, 1);
fd = drmOpenMinor(i, 1, DRM_NODE_RENDER);
if (fd >= 0) {
printf("%s\n", buf);
if (mask & DRM_BUSID) getbusid(fd);

View File

@ -26,58 +26,103 @@
*/
#include <fcntl.h>
#include <fnmatch.h>
#include <sys/stat.h>
#include "drmtest.h"
/** Open the first DRM device we can find, searching up to 16 device nodes */
int drm_open_any(void)
{
char name[20];
int i, fd;
#define LIBUDEV_I_KNOW_THE_API_IS_SUBJECT_TO_CHANGE
#include <libudev.h>
for (i = 0; i < 16; i++) {
sprintf(name, "/dev/dri/card%d", i);
fd = open(name, O_RDWR);
if (fd != -1)
return fd;
}
abort();
static int is_master(int fd)
{
drm_client_t client;
int ret;
/* Check that we're the only opener and authed. */
client.idx = 0;
ret = ioctl(fd, DRM_IOCTL_GET_CLIENT, &client);
assert (ret == 0);
if (!client.auth)
return 0;
client.idx = 1;
ret = ioctl(fd, DRM_IOCTL_GET_CLIENT, &client);
if (ret != -1 || errno != EINVAL)
return 0;
return 1;
}
/** Open the first DRM device matching the criteria */
int drm_open_matching(const char *pci_glob, int flags)
{
struct udev *udev;
struct udev_enumerate *e;
struct udev_device *device, *parent;
struct udev_list_entry *entry;
const char *pci_id, *path;
int i, fd;
udev = udev_new();
if (udev == NULL) {
fprintf(stderr, "failed to initialize udev context\n");
abort();
}
fd = -1;
e = udev_enumerate_new(udev);
udev_enumerate_add_match_subsystem(e, "drm");
udev_enumerate_scan_devices(e);
udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
path = udev_list_entry_get_name(entry);
device = udev_device_new_from_syspath(udev, path);
parent = udev_device_get_parent(device);
/* Filter out KMS output devices. */
if (strcmp(udev_device_get_subsystem(parent), "pci") != 0)
continue;
pci_id = udev_device_get_property_value(parent, "PCI_ID");
if (fnmatch(pci_glob, pci_id, 0) != 0)
continue;
fd = open(udev_device_get_devnode(device), O_RDWR);
if (fd < 0)
continue;
if ((flags & DRM_TEST_MASTER) && !is_master(fd)) {
close(fd);
fd = -1;
continue;
}
break;
}
udev_enumerate_unref(e);
udev_unref(udev);
return fd;
}
int drm_open_any(void)
{
int fd = drm_open_matching("*:*", 0);
if (fd < 0) {
fprintf(stderr, "failed to open any drm device\n");
abort();
}
return fd;
}
/**
* Open the first DRM device we can find where we end up being the master.
*/
int drm_open_any_master(void)
{
char name[20];
int i, fd;
int fd = drm_open_matching("*:*", DRM_TEST_MASTER);
for (i = 0; i < 16; i++) {
drm_client_t client;
int ret;
sprintf(name, "/dev/dri/card%d", i);
fd = open(name, O_RDWR);
if (fd == -1)
continue;
/* Check that we're the only opener and authed. */
client.idx = 0;
ret = ioctl(fd, DRM_IOCTL_GET_CLIENT, &client);
assert (ret == 0);
if (!client.auth) {
close(fd);
continue;
}
client.idx = 1;
ret = ioctl(fd, DRM_IOCTL_GET_CLIENT, &client);
if (ret != -1 || errno != EINVAL) {
close(fd);
continue;
}
return fd;
if (fd < 0) {
fprintf(stderr, "failed to open any drm device\n");
abort();
}
fprintf(stderr, "Couldn't find an un-controlled DRM device\n");
abort();
}
return fd;
}

View File

@ -33,5 +33,8 @@
#include "xf86drm.h"
#define DRM_TEST_MASTER 0x01
int drm_open_any(void);
int drm_open_any_master(void);
int drm_open_matching(const char *pci_glob, int flags);

View File

@ -0,0 +1,102 @@
/*
* Copyright © 2008 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
* Authors:
* Eric Anholt <eric@anholt.net>
*
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <fcntl.h>
#include <inttypes.h>
#include <errno.h>
#include <sys/stat.h>
#include "drm.h"
#include "i915_drm.h"
static void
test_bad_close(int fd)
{
struct drm_gem_close close;
int ret;
printf("Testing error return on bad close ioctl.\n");
close.handle = 0x10101010;
ret = ioctl(fd, DRM_IOCTL_GEM_CLOSE, &close);
assert(ret == -1 && errno == EINVAL);
}
static void
test_create_close(int fd)
{
struct drm_i915_gem_create create;
struct drm_gem_close close;
int ret;
printf("Testing creating and closing an object.\n");
memset(&create, 0, sizeof(create));
create.size = 16 * 1024;
ret = ioctl(fd, DRM_IOCTL_I915_GEM_CREATE, &create);
assert(ret == 0);
close.handle = create.handle;
ret = ioctl(fd, DRM_IOCTL_GEM_CLOSE, &close);
}
static void
test_create_fd_close(int fd)
{
struct drm_i915_gem_create create;
int ret;
printf("Testing closing with an object allocated.\n");
memset(&create, 0, sizeof(create));
create.size = 16 * 1024;
ret = ioctl(fd, DRM_IOCTL_I915_GEM_CREATE, &create);
assert(ret == 0);
close(fd);
}
int main(int argc, char **argv)
{
int fd;
fd = drm_open_matching("8086:*", 0);
if (fd < 0) {
fprintf(stderr, "failed to open intel drm device\n");
return 0;
}
test_bad_close(fd);
test_create_close(fd);
test_create_fd_close(fd);
return 0;
}

View File

@ -0,0 +1,132 @@
/*
* Copyright © 2008 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
* Authors:
* Eric Anholt <eric@anholt.net>
*
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <fcntl.h>
#include <inttypes.h>
#include <errno.h>
#include <sys/stat.h>
#include "drm.h"
#include "i915_drm.h"
static void
test_flink(int fd)
{
struct drm_i915_gem_create create;
struct drm_gem_flink flink;
struct drm_gem_open open;
int ret;
printf("Testing flink and open.\n");
memset(&create, 0, sizeof(create));
create.size = 16 * 1024;
ret = ioctl(fd, DRM_IOCTL_I915_GEM_CREATE, &create);
assert(ret == 0);
flink.handle = create.handle;
ret = ioctl(fd, DRM_IOCTL_GEM_FLINK, &flink);
assert(ret == 0);
open.name = flink.name;
ret = ioctl(fd, DRM_IOCTL_GEM_OPEN, &open);
assert(ret == 0);
assert(open.handle != 0);
}
static void
test_double_flink(int fd)
{
struct drm_i915_gem_create create;
struct drm_gem_flink flink;
struct drm_gem_flink flink2;
int ret;
printf("Testing repeated flink.\n");
memset(&create, 0, sizeof(create));
create.size = 16 * 1024;
ret = ioctl(fd, DRM_IOCTL_I915_GEM_CREATE, &create);
assert(ret == 0);
flink.handle = create.handle;
ret = ioctl(fd, DRM_IOCTL_GEM_FLINK, &flink);
assert(ret == 0);
flink2.handle = create.handle;
ret = ioctl(fd, DRM_IOCTL_GEM_FLINK, &flink2);
assert(ret == 0);
assert(flink2.name == flink.name);
}
static void
test_bad_flink(int fd)
{
struct drm_gem_flink flink;
int ret;
printf("Testing error return on bad flink ioctl.\n");
flink.handle = 0x10101010;
ret = ioctl(fd, DRM_IOCTL_GEM_FLINK, &flink);
assert(ret == -1 && errno == EBADF);
}
static void
test_bad_open(int fd)
{
struct drm_gem_open open;
int ret;
printf("Testing error return on bad open ioctl.\n");
open.name = 0x10101010;
ret = ioctl(fd, DRM_IOCTL_GEM_OPEN, &open);
assert(ret == -1 && errno == ENOENT);
}
int main(int argc, char **argv)
{
int fd;
fd = drm_open_matching("8086:*", 0);
if (fd < 0) {
fprintf(stderr, "failed to open intel drm device, skipping\n");
return 0;
}
test_flink(fd);
test_double_flink(fd);
test_bad_flink(fd);
test_bad_open(fd);
return 0;
}

View File

@ -0,0 +1,136 @@
/*
* Copyright © 2008 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
* Authors:
* Eric Anholt <eric@anholt.net>
*
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <fcntl.h>
#include <inttypes.h>
#include <errno.h>
#include <sys/stat.h>
#include "drm.h"
#include "i915_drm.h"
#define OBJECT_SIZE 16384
int do_read(int fd, int handle, void *buf, int offset, int size)
{
struct drm_i915_gem_pread read;
/* Ensure that we don't have any convenient data in buf in case
* we fail.
*/
memset(buf, 0xd0, size);
memset(&read, 0, sizeof(read));
read.handle = handle;
read.data_ptr = (uintptr_t)buf;
read.size = size;
read.offset = offset;
return ioctl(fd, DRM_IOCTL_I915_GEM_PREAD, &read);
}
int do_write(int fd, int handle, void *buf, int offset, int size)
{
struct drm_i915_gem_pwrite write;
memset(&write, 0, sizeof(write));
write.handle = handle;
write.data_ptr = (uintptr_t)buf;
write.size = size;
write.offset = offset;
return ioctl(fd, DRM_IOCTL_I915_GEM_PWRITE, &write);
}
int main(int argc, char **argv)
{
int fd;
struct drm_i915_gem_create create;
struct drm_i915_gem_mmap mmap;
struct drm_gem_close unref;
uint8_t expected[OBJECT_SIZE];
uint8_t buf[OBJECT_SIZE];
uint8_t *addr;
int ret;
int handle;
fd = drm_open_matching("8086:*", 0);
if (fd < 0) {
fprintf(stderr, "failed to open intel drm device, skipping\n");
return 0;
}
memset(&mmap, 0, sizeof(mmap));
mmap.handle = 0x10101010;
mmap.offset = 0;
mmap.size = 4096;
printf("Testing mmaping of bad object.\n");
ret = ioctl(fd, DRM_IOCTL_I915_GEM_MMAP, &mmap);
assert(ret == -1 && errno == EBADF);
memset(&create, 0, sizeof(create));
create.size = OBJECT_SIZE;
ret = ioctl(fd, DRM_IOCTL_I915_GEM_CREATE, &create);
assert(ret == 0);
handle = create.handle;
printf("Testing mmaping of newly created object.\n");
mmap.handle = handle;
mmap.offset = 0;
mmap.size = OBJECT_SIZE;
ret = ioctl(fd, DRM_IOCTL_I915_GEM_MMAP, &mmap);
assert(ret == 0);
addr = (uint8_t *)(uintptr_t)mmap.addr_ptr;
printf("Testing contents of newly created object.\n");
memset(expected, 0, sizeof(expected));
assert(memcmp(addr, expected, sizeof(expected)) == 0);
printf("Testing coherency of writes and mmap reads.\n");
memset(buf, 0, sizeof(buf));
memset(buf + 1024, 0x01, 1024);
memset(expected + 1024, 0x01, 1024);
ret = do_write(fd, handle, buf, 0, OBJECT_SIZE);
assert(ret == 0);
assert(memcmp(buf, addr, sizeof(buf)) == 0);
printf("Testing that mapping stays after close\n");
unref.handle = handle;
ret = ioctl(fd, DRM_IOCTL_GEM_CLOSE, &unref);
assert(ret == 0);
assert(memcmp(buf, addr, sizeof(buf)) == 0);
printf("Testing unmapping\n");
munmap(addr, OBJECT_SIZE);
close(fd);
return 0;
}

View File

@ -0,0 +1,139 @@
/*
* Copyright © 2008 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
* Authors:
* Eric Anholt <eric@anholt.net>
*
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <fcntl.h>
#include <inttypes.h>
#include <errno.h>
#include <sys/stat.h>
#include "drm.h"
#include "i915_drm.h"
#define OBJECT_SIZE 16384
int do_read(int fd, int handle, void *buf, int offset, int size)
{
struct drm_i915_gem_pread read;
/* Ensure that we don't have any convenient data in buf in case
* we fail.
*/
memset(buf, 0xd0, size);
memset(&read, 0, sizeof(read));
read.handle = handle;
read.data_ptr = (uintptr_t)buf;
read.size = size;
read.offset = offset;
return ioctl(fd, DRM_IOCTL_I915_GEM_PREAD, &read);
}
int do_write(int fd, int handle, void *buf, int offset, int size)
{
struct drm_i915_gem_pwrite write;
memset(&write, 0, sizeof(write));
write.handle = handle;
write.data_ptr = (uintptr_t)buf;
write.size = size;
write.offset = offset;
return ioctl(fd, DRM_IOCTL_I915_GEM_PWRITE, &write);
}
int main(int argc, char **argv)
{
int fd;
struct drm_i915_gem_create create;
uint8_t expected[OBJECT_SIZE];
uint8_t buf[OBJECT_SIZE];
int ret;
int handle;
fd = drm_open_matching("8086:*", 0);
if (fd < 0) {
fprintf(stderr, "failed to open intel drm device, skipping\n");
return 0;
}
memset(&create, 0, sizeof(create));
create.size = OBJECT_SIZE;
ret = ioctl(fd, DRM_IOCTL_I915_GEM_CREATE, &create);
assert(ret == 0);
handle = create.handle;
printf("Testing contents of newly created object.\n");
ret = do_read(fd, handle, buf, 0, OBJECT_SIZE);
assert(ret == 0);
memset(&expected, 0, sizeof(expected));
assert(memcmp(expected, buf, sizeof(expected)) == 0);
printf("Testing read beyond end of buffer.\n");
ret = do_read(fd, handle, buf, OBJECT_SIZE / 2, OBJECT_SIZE);
printf("%d %d\n", ret, errno);
assert(ret == -1 && errno == EINVAL);
printf("Testing full write of buffer\n");
memset(buf, 0, sizeof(buf));
memset(buf + 1024, 0x01, 1024);
memset(expected + 1024, 0x01, 1024);
ret = do_write(fd, handle, buf, 0, OBJECT_SIZE);
assert(ret == 0);
ret = do_read(fd, handle, buf, 0, OBJECT_SIZE);
assert(ret == 0);
assert(memcmp(buf, expected, sizeof(buf)) == 0);
printf("Testing partial write of buffer\n");
memset(buf + 4096, 0x02, 1024);
memset(expected + 4096, 0x02, 1024);
ret = do_write(fd, handle, buf + 4096, 4096, 1024);
assert(ret == 0);
ret = do_read(fd, handle, buf, 0, OBJECT_SIZE);
assert(ret == 0);
assert(memcmp(buf, expected, sizeof(buf)) == 0);
printf("Testing partial read of buffer\n");
ret = do_read(fd, handle, buf, 512, 1024);
assert(ret == 0);
assert(memcmp(buf, expected + 512, 1024) == 0);
printf("Testing read of bad buffer handle\n");
ret = do_read(fd, 1234, buf, 0, 1024);
assert(ret == -1 && errno == EBADF);
printf("Testing write of bad buffer handle\n");
ret = do_write(fd, 1234, buf, 0, 1024);
assert(ret == -1 && errno == EBADF);
close(fd);
return 0;
}

View File

@ -40,7 +40,8 @@ int main(int argc, char **argv)
assert(strlen(v->name) != 0);
assert(strlen(v->date) != 0);
assert(strlen(v->desc) != 0);
assert(v->version_major >= 1);
if (strcmp(v->name, "i915") == 0)
assert(v->version_major >= 1);
drmFree(v);
close(fd);
return 0;

View File

@ -0,0 +1,13 @@
AM_CFLAGS = \
-I$(top_srcdir)/shared-core \
-I$(top_srcdir)/libdrm/intel/ \
-I$(top_srcdir)/libdrm
noinst_PROGRAMS = \
modeprint
modeprint_SOURCES = \
modeprint.c
modeprint_LDADD = \
$(top_builddir)/libdrm/libdrm.la \
$(top_builddir)/libdrm/intel/libdrm_intel.la

View File

@ -0,0 +1,402 @@
/*
* \file modedemo.c
* Test program to dump DRM kernel mode setting related information.
* Queries the kernel for all available information and dumps it to stdout.
*
* \author Jakob Bornecrantz <wallbraker@gmail.com>
*/
/*
* Copyright (c) 2007-2008 Tungsten Graphics, Inc., Cedar Park, Texas.
* Copyright (c) 2007-2008 Jakob Bornecrantz <wallbraker@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <string.h>
#include "xf86drm.h"
#include "xf86drmMode.h"
int connectors;
int full_props;
int edid;
int modes;
int full_modes;
int encoders;
int crtcs;
int fbs;
char *module_name;
const char* getConnectionText(drmModeConnection conn)
{
switch (conn) {
case DRM_MODE_CONNECTED:
return "connected";
case DRM_MODE_DISCONNECTED:
return "disconnected";
default:
return "unknown";
}
}
int printMode(struct drm_mode_modeinfo *mode)
{
if (full_modes) {
printf("Mode: %s\n", mode->name);
printf("\tclock : %i\n", mode->clock);
printf("\thdisplay : %i\n", mode->hdisplay);
printf("\thsync_start : %i\n", mode->hsync_start);
printf("\thsync_end : %i\n", mode->hsync_end);
printf("\thtotal : %i\n", mode->htotal);
printf("\thskew : %i\n", mode->hskew);
printf("\tvdisplay : %i\n", mode->vdisplay);
printf("\tvsync_start : %i\n", mode->vsync_start);
printf("\tvsync_end : %i\n", mode->vsync_end);
printf("\tvtotal : %i\n", mode->vtotal);
printf("\tvscan : %i\n", mode->vscan);
printf("\tvrefresh : %i\n", mode->vrefresh);
printf("\tflags : %i\n", mode->flags);
} else {
printf("Mode: \"%s\" %ix%i %.0f\n", mode->name,
mode->hdisplay, mode->vdisplay, mode->vrefresh / 1000.0);
}
return 0;
}
int printProperty(int fd, drmModeResPtr res, drmModePropertyPtr props, uint64_t value)
{
const unsigned char *name = NULL;
int j;
printf("Property: %s\n", props->name);
printf("\tid : %i\n", props->prop_id);
printf("\tflags : %i\n", props->flags);
printf("\tcount_values : %d\n", props->count_values);
if (props->count_values) {
printf("\tvalues :");
for (j = 0; j < props->count_values; j++)
printf(" %lld", props->values[j]);
printf("\n");
}
printf("\tcount_enums : %d\n", props->count_enums);
if (props->flags & DRM_MODE_PROP_BLOB) {
drmModePropertyBlobPtr blob;
blob = drmModeGetPropertyBlob(fd, value);
if (blob) {
printf("blob is %d length, %08X\n", blob->length, *(uint32_t *)blob->data);
drmModeFreePropertyBlob(blob);
} else {
printf("error getting blob %lld\n", value);
}
} else {
if (!strncmp(props->name, "DPMS", 4))
;
for (j = 0; j < props->count_enums; j++) {
printf("\t\t%lld = %s\n", props->enums[j].value, props->enums[j].name);
if (props->enums[j].value == value)
name = props->enums[j].name;
}
if (props->count_enums && name) {
printf("\tcon_value : %s\n", name);
} else {
printf("\tcon_value : %lld\n", value);
}
}
return 0;
}
int printConnector(int fd, drmModeResPtr res, drmModeConnectorPtr connector, uint32_t id)
{
int i = 0;
struct drm_mode_modeinfo *mode = NULL;
drmModePropertyPtr props;
printf("Connector: %d-%d\n", connector->connector_type, connector->connector_type_id);
printf("\tid : %i\n", id);
printf("\tencoder id : %i\n", connector->encoder_id);
printf("\tconn : %s\n", getConnectionText(connector->connection));
printf("\tsize : %ix%i (mm)\n", connector->mmWidth, connector->mmHeight);
printf("\tcount_modes : %i\n", connector->count_modes);
printf("\tcount_props : %i\n", connector->count_props);
if (connector->count_props) {
printf("\tprops :");
for (i = 0; i < connector->count_props; i++)
printf(" %i", connector->props[i]);
printf("\n");
}
printf("\tcount_encoders : %i\n", connector->count_encoders);
if (connector->count_encoders) {
printf("\tencoders :");
for (i = 0; i < connector->count_encoders; i++)
printf(" %i", connector->encoders[i]);
printf("\n");
}
if (modes) {
for (i = 0; i < connector->count_modes; i++) {
mode = &connector->modes[i];
printMode(mode);
}
}
if (full_props) {
for (i = 0; i < connector->count_props; i++) {
props = drmModeGetProperty(fd, connector->props[i]);
if (props) {
printProperty(fd, res, props, connector->prop_values[i]);
drmModeFreeProperty(props);
}
}
}
return 0;
}
int printEncoder(int fd, drmModeResPtr res, drmModeEncoderPtr encoder, uint32_t id)
{
printf("Encoder\n");
printf("\tid :%i\n", id);
printf("\tcrtc_id :%d\n", encoder->crtc_id);
printf("\ttype :%d\n", encoder->encoder_type);
printf("\tpossible_crtcs :%d\n", encoder->possible_crtcs);
printf("\tpossible_clones :%d\n", encoder->possible_clones);
return 0;
}
int printCrtc(int fd, drmModeResPtr res, drmModeCrtcPtr crtc, uint32_t id)
{
printf("Crtc\n");
printf("\tid : %i\n", id);
printf("\tx : %i\n", crtc->x);
printf("\ty : %i\n", crtc->y);
printf("\twidth : %i\n", crtc->width);
printf("\theight : %i\n", crtc->height);
printf("\tmode : %p\n", &crtc->mode);
printf("\tgamma size : %d\n", crtc->gamma_size);
return 0;
}
int printFrameBuffer(int fd, drmModeResPtr res, drmModeFBPtr fb)
{
printf("Framebuffer\n");
printf("\thandle : %i\n", fb->handle);
printf("\twidth : %i\n", fb->width);
printf("\theight : %i\n", fb->height);
printf("\tpitch : %i\n", fb->pitch);;
printf("\tbpp : %i\n", fb->bpp);
printf("\tdepth : %i\n", fb->depth);
printf("\tbuffer_id : %i\n", fb->handle);
return 0;
}
int printRes(int fd, drmModeResPtr res)
{
int i;
drmModeFBPtr fb;
drmModeCrtcPtr crtc;
drmModeEncoderPtr encoder;
drmModeConnectorPtr connector;
printf("Resources\n\n");
printf("count_connectors : %i\n", res->count_connectors);
printf("count_encoders : %i\n", res->count_encoders);
printf("count_crtcs : %i\n", res->count_crtcs);
printf("count_fbs : %i\n", res->count_fbs);
printf("\n");
if (connectors) {
for (i = 0; i < res->count_connectors; i++) {
connector = drmModeGetConnector(fd, res->connectors[i]);
if (!connector)
printf("Could not get connector %i\n", res->connectors[i]);
else {
printConnector(fd, res, connector, res->connectors[i]);
drmModeFreeConnector(connector);
}
}
printf("\n");
}
if (encoders) {
for (i = 0; i < res->count_encoders; i++) {
encoder = drmModeGetEncoder(fd, res->encoders[i]);
if (!encoder)
printf("Could not get encoder %i\n", res->encoders[i]);
else {
printEncoder(fd, res, encoder, res->encoders[i]);
drmModeFreeEncoder(encoder);
}
}
printf("\n");
}
if (crtcs) {
for (i = 0; i < res->count_crtcs; i++) {
crtc = drmModeGetCrtc(fd, res->crtcs[i]);
if (!crtc)
printf("Could not get crtc %i\n", res->crtcs[i]);
else {
printCrtc(fd, res, crtc, res->crtcs[i]);
drmModeFreeCrtc(crtc);
}
}
printf("\n");
}
if (fbs) {
for (i = 0; i < res->count_fbs; i++) {
fb = drmModeGetFB(fd, res->fbs[i]);
if (!fb)
printf("Could not get fb %i\n", res->fbs[i]);
else {
printFrameBuffer(fd, res, fb);
drmModeFreeFB(fb);
}
}
}
return 0;
}
void args(int argc, char **argv)
{
int i;
fbs = 0;
edid = 0;
crtcs = 0;
modes = 0;
encoders = 0;
full_modes = 0;
full_props = 0;
connectors = 0;
module_name = argv[1];
for (i = 2; i < argc; i++) {
if (strcmp(argv[i], "-fb") == 0) {
fbs = 1;
} else if (strcmp(argv[i], "-crtcs") == 0) {
crtcs = 1;
} else if (strcmp(argv[i], "-cons") == 0) {
connectors = 1;
modes = 1;
} else if (strcmp(argv[i], "-modes") == 0) {
connectors = 1;
modes = 1;
} else if (strcmp(argv[i], "-full") == 0) {
connectors = 1;
modes = 1;
full_modes = 1;
} else if (strcmp(argv[i], "-props") == 0) {
connectors = 1;
full_props = 1;
} else if (strcmp(argv[i], "-edids") == 0) {
connectors = 1;
edid = 1;
} else if (strcmp(argv[i], "-encoders") == 0) {
encoders = 1;
} else if (strcmp(argv[i], "-v") == 0) {
fbs = 1;
edid = 1;
crtcs = 1;
modes = 1;
encoders = 1;
full_modes = 1;
full_props = 1;
connectors = 1;
}
}
if (argc == 2) {
fbs = 1;
edid = 1;
crtcs = 1;
modes = 1;
encoders = 1;
full_modes = 0;
full_props = 0;
connectors = 1;
}
}
int main(int argc, char **argv)
{
int fd;
drmModeResPtr res;
if (argc == 1) {
printf("Please add modulename as first argument\n");
return 1;
}
args(argc, argv);
printf("Starting test\n");
fd = drmOpen(module_name, NULL);
if (fd < 0) {
printf("Failed to open the card fd (%d)\n",fd);
return 1;
}
res = drmModeGetResources(fd);
if (res == 0) {
printf("Failed to get resources from card\n");
drmClose(fd);
return 1;
}
printRes(fd, res);
drmModeFreeResources(res);
printf("Ok\n");
return 0;
}

View File

@ -0,0 +1,15 @@
AM_CFLAGS = \
-I$(top_srcdir)/shared-core \
-I$(top_srcdir)/libdrm/intel/ \
-I$(top_srcdir)/libdrm \
$(CAIRO_CFLAGS)
noinst_PROGRAMS = \
modetest
modetest_SOURCES = \
modetest.c
modetest_LDADD = \
$(top_builddir)/libdrm/libdrm.la \
$(top_builddir)/libdrm/intel/libdrm_intel.la \
$(CAIRO_LIBS)

View File

@ -0,0 +1,624 @@
/*
* DRM based mode setting test program
* Copyright 2008 Tungsten Graphics
* Jakob Bornecrantz <jakob@tungstengraphics.com>
* Copyright 2008 Intel Corporation
* Jesse Barnes <jesse.barnes@intel.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
/*
* This fairly simple test program dumps output in a similar format to the
* "xrandr" tool everyone knows & loves. It's necessarily slightly different
* since the kernel separates outputs into encoder and connector structures,
* each with their own unique ID. The program also allows test testing of the
* memory management and mode setting APIs by allowing the user to specify a
* connector and mode to use for mode setting. If all works as expected, a
* blue background should be painted on the monitor attached to the specified
* connector after the selected mode is set.
*
* TODO: use cairo to write the mode info on the selected output once
* the mode has been programmed, along with possible test patterns.
*/
#include "config.h"
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include "xf86drm.h"
#include "xf86drmMode.h"
#include "intel_bufmgr.h"
#ifdef HAVE_CAIRO
#include <math.h>
#include <cairo.h>
#endif
drmModeRes *resources;
int fd, modes;
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
struct type_name {
int type;
char *name;
};
#define type_name_fn(res) \
char * res##_str(int type) { \
int i; \
for (i = 0; i < ARRAY_SIZE(res##_names); i++) { \
if (res##_names[i].type == type) \
return res##_names[i].name; \
} \
return "(invalid)"; \
}
struct type_name encoder_type_names[] = {
{ DRM_MODE_ENCODER_NONE, "none" },
{ DRM_MODE_ENCODER_DAC, "DAC" },
{ DRM_MODE_ENCODER_TMDS, "TMDS" },
{ DRM_MODE_ENCODER_LVDS, "LVDS" },
{ DRM_MODE_ENCODER_TVDAC, "TVDAC" },
};
type_name_fn(encoder_type)
struct type_name connector_status_names[] = {
{ DRM_MODE_CONNECTED, "connected" },
{ DRM_MODE_DISCONNECTED, "disconnected" },
{ DRM_MODE_UNKNOWNCONNECTION, "unknown" },
};
type_name_fn(connector_status)
struct type_name connector_type_names[] = {
{ DRM_MODE_CONNECTOR_Unknown, "unknown" },
{ DRM_MODE_CONNECTOR_VGA, "VGA" },
{ DRM_MODE_CONNECTOR_DVII, "DVI-I" },
{ DRM_MODE_CONNECTOR_DVID, "DVI-D" },
{ DRM_MODE_CONNECTOR_DVIA, "DVI-A" },
{ DRM_MODE_CONNECTOR_Composite, "composite" },
{ DRM_MODE_CONNECTOR_SVIDEO, "s-video" },
{ DRM_MODE_CONNECTOR_LVDS, "LVDS" },
{ DRM_MODE_CONNECTOR_Component, "component" },
{ DRM_MODE_CONNECTOR_9PinDIN, "9-pin DIN" },
{ DRM_MODE_CONNECTOR_DisplayPort, "displayport" },
{ DRM_MODE_CONNECTOR_HDMIA, "HDMI-A" },
{ DRM_MODE_CONNECTOR_HDMIB, "HDMI-B" },
};
type_name_fn(connector_type)
void dump_encoders(void)
{
drmModeEncoder *encoder;
int i;
printf("Encoders:\n");
printf("id\tcrtc\ttype\tpossible crtcs\tpossible clones\t\n");
for (i = 0; i < resources->count_encoders; i++) {
encoder = drmModeGetEncoder(fd, resources->encoders[i]);
if (!encoder) {
fprintf(stderr, "could not get encoder %i: %s\n",
resources->encoders[i], strerror(errno));
continue;
}
printf("%d\t%d\t%s\t0x%08x\t0x%08x\n",
encoder->encoder_id,
encoder->crtc_id,
encoder_type_str(encoder->encoder_type),
encoder->possible_crtcs,
encoder->possible_clones);
drmModeFreeEncoder(encoder);
}
printf("\n");
}
void dump_mode(drmModeModeInfo *mode)
{
printf(" %s %.02f %d %d %d %d %d %d %d %d\n",
mode->name,
(float)mode->vrefresh / 1000,
mode->hdisplay,
mode->hsync_start,
mode->hsync_end,
mode->htotal,
mode->vdisplay,
mode->vsync_start,
mode->vsync_end,
mode->vtotal);
}
static void
dump_props(drmModeConnector *connector)
{
drmModePropertyPtr props;
int i;
for (i = 0; i < connector->count_props; i++) {
props = drmModeGetProperty(fd, connector->props[i]);
printf("\t%s, flags %d\n", props->name, props->flags);
drmModeFreeProperty(props);
}
}
void dump_connectors(void)
{
drmModeConnector *connector;
int i, j;
printf("Connectors:\n");
printf("id\tencoder\tstatus\t\ttype\tsize (mm)\tmodes\n");
for (i = 0; i < resources->count_connectors; i++) {
connector = drmModeGetConnector(fd, resources->connectors[i]);
if (!connector) {
fprintf(stderr, "could not get connector %i: %s\n",
resources->connectors[i], strerror(errno));
continue;
}
printf("%d\t%d\t%s\t%s\t%dx%d\t\t%d\n",
connector->connector_id,
connector->encoder_id,
connector_status_str(connector->connection),
connector_type_str(connector->connector_type),
connector->mmWidth, connector->mmHeight,
connector->count_modes);
if (!connector->count_modes)
continue;
printf(" modes:\n");
printf(" name refresh (Hz) hdisp hss hse htot vdisp "
"vss vse vtot)\n");
for (j = 0; j < connector->count_modes; j++)
dump_mode(&connector->modes[j]);
drmModeFreeConnector(connector);
printf(" props:\n");
dump_props(connector);
}
printf("\n");
}
void dump_crtcs(void)
{
drmModeCrtc *crtc;
int i;
printf("CRTCs:\n");
printf("id\tfb\tpos\tsize\n");
for (i = 0; i < resources->count_crtcs; i++) {
crtc = drmModeGetCrtc(fd, resources->crtcs[i]);
if (!crtc) {
fprintf(stderr, "could not get crtc %i: %s\n",
resources->crtcs[i], strerror(errno));
continue;
}
printf("%d\t%d\t(%d,%d)\t(%dx%d)\n",
crtc->crtc_id,
crtc->buffer_id,
crtc->x, crtc->y,
crtc->width, crtc->height);
dump_mode(&crtc->mode);
drmModeFreeCrtc(crtc);
}
printf("\n");
}
void dump_framebuffers(void)
{
drmModeFB *fb;
int i;
printf("Frame buffers:\n");
printf("id\tsize\tpitch\n");
for (i = 0; i < resources->count_fbs; i++) {
fb = drmModeGetFB(fd, resources->fbs[i]);
if (!fb) {
fprintf(stderr, "could not get fb %i: %s\n",
resources->fbs[i], strerror(errno));
continue;
}
printf("%d\t(%dx%d)\t%d\n",
fb->fb_id,
fb->width, fb->height);
drmModeFreeFB(fb);
}
printf("\n");
}
/*
* Mode setting with the kernel interfaces is a bit of a chore.
* First you have to find the connector in question and make sure the
* requested mode is available.
* Then you need to find the encoder attached to that connector so you
* can bind it with a free crtc.
*/
struct connector {
int id;
char mode_str[64];
drmModeModeInfo *mode;
drmModeEncoder *encoder;
int crtc;
};
static void
connector_find_mode(struct connector *c)
{
drmModeConnector *connector;
int i, j, size, ret, width, height;
/* First, find the connector & mode */
c->mode = NULL;
for (i = 0; i < resources->count_connectors; i++) {
connector = drmModeGetConnector(fd, resources->connectors[i]);
if (!connector) {
fprintf(stderr, "could not get connector %i: %s\n",
resources->connectors[i], strerror(errno));
drmModeFreeConnector(connector);
continue;
}
if (!connector->count_modes) {
drmModeFreeConnector(connector);
continue;
}
if (connector->connector_id != c->id) {
drmModeFreeConnector(connector);
continue;
}
for (j = 0; j < connector->count_modes; j++) {
c->mode = &connector->modes[j];
if (!strcmp(c->mode->name, c->mode_str))
break;
}
/* Found it, break out */
if (c->mode)
break;
drmModeFreeConnector(connector);
}
if (!c->mode) {
fprintf(stderr, "failed to find mode \"%s\"\n", c->mode_str);
return;
}
/* Now get the encoder */
for (i = 0; i < resources->count_encoders; i++) {
c->encoder = drmModeGetEncoder(fd, resources->encoders[i]);
if (!c->encoder) {
fprintf(stderr, "could not get encoder %i: %s\n",
resources->encoders[i], strerror(errno));
drmModeFreeEncoder(c->encoder);
continue;
}
if (c->encoder->encoder_id == connector->encoder_id)
break;
drmModeFreeEncoder(c->encoder);
}
if (c->crtc == -1)
c->crtc = c->encoder->crtc_id;
}
#ifdef HAVE_CAIRO
static int
create_test_buffer(drm_intel_bufmgr *bufmgr,
int width, int height, int *stride_out, drm_intel_bo **bo_out)
{
drm_intel_bo *bo;
unsigned int *fb_ptr;
int size, ret, i, stride;
div_t d;
cairo_surface_t *surface;
cairo_t *cr;
char buf[64];
int x, y;
surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
stride = cairo_image_surface_get_stride(surface);
size = stride * height;
fb_ptr = (unsigned int *) cairo_image_surface_get_data(surface);
/* paint the buffer with colored tiles */
for (i = 0; i < width * height; i++) {
d = div(i, width);
fb_ptr[i] = 0x00130502 * (d.quot >> 6) + 0x000a1120 * (d.rem >> 6);
}
cr = cairo_create(surface);
cairo_set_line_cap(cr, CAIRO_LINE_CAP_SQUARE);
for (x = 0; x < width; x += 250)
for (y = 0; y < height; y += 250) {
cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
cairo_move_to(cr, x, y - 20);
cairo_line_to(cr, x, y + 20);
cairo_move_to(cr, x - 20, y);
cairo_line_to(cr, x + 20, y);
cairo_new_sub_path(cr);
cairo_arc(cr, x, y, 10, 0, M_PI * 2);
cairo_set_line_width(cr, 4);
cairo_set_source_rgb(cr, 0, 0, 0);
cairo_stroke_preserve(cr);
cairo_set_source_rgb(cr, 1, 1, 1);
cairo_set_line_width(cr, 2);
cairo_stroke(cr);
snprintf(buf, sizeof buf, "%d, %d", x, y);
cairo_move_to(cr, x + 20, y + 20);
cairo_text_path(cr, buf);
cairo_set_source_rgb(cr, 0, 0, 0);
cairo_stroke_preserve(cr);
cairo_set_source_rgb(cr, 1, 1, 1);
cairo_fill(cr);
}
cairo_destroy(cr);
bo = drm_intel_bo_alloc(bufmgr, "frontbuffer", size, 4096);
if (!bo) {
fprintf(stderr, "failed to alloc buffer: %s\n",
strerror(errno));
return -1;
}
drm_intel_bo_subdata(bo, 0, size, fb_ptr);
cairo_surface_destroy(surface);
*bo_out = bo;
*stride_out = stride;
return 0;
}
#else
static int
create_test_buffer(drm_intel_bufmgr *bufmgr,
int width, int height, int *stride_out, drm_intel_bo **bo_out)
{
drm_intel_bo *bo;
unsigned int *fb_ptr;
int size, ret, i, stride;
div_t d;
/* Mode size at 32 bpp */
stride = width * 4;
size = stride * height;
bo = drm_intel_bo_alloc(bufmgr, "frontbuffer", size, 4096);
if (!bo) {
fprintf(stderr, "failed to alloc buffer: %s\n",
strerror(errno));
return -1;
}
ret = drm_intel_gem_bo_map_gtt(bo);
if (ret) {
fprintf(stderr, "failed to GTT map buffer: %s\n",
strerror(errno));
return -1;
}
fb_ptr = bo->virtual;
/* paint the buffer with colored tiles */
for (i = 0; i < width * height; i++) {
d = div(i, width);
fb_ptr[i] = 0x00130502 * (d.quot >> 6) + 0x000a1120 * (d.rem >> 6);
}
drm_intel_bo_unmap(bo);
*bo_out = bo;
*stride_out = stride;
return 0;
}
#endif
static void
set_mode(struct connector *c, int count)
{
drmModeConnector *connector;
drmModeEncoder *encoder = NULL;
struct drm_mode_modeinfo *mode = NULL;
drm_intel_bufmgr *bufmgr;
drm_intel_bo *bo;
unsigned int fb_id;
int i, j, ret, width, height, x, stride;
width = 0;
height = 0;
for (i = 0; i < count; i++) {
connector_find_mode(&c[i]);
if (c[i].mode == NULL)
continue;
width += c[i].mode->hdisplay;
if (height < c[i].mode->vdisplay)
height = c[i].mode->vdisplay;
}
bufmgr = drm_intel_bufmgr_gem_init(fd, 2<<20);
if (!bufmgr) {
fprintf(stderr, "failed to init bufmgr: %s\n", strerror(errno));
return;
}
if (create_test_buffer(bufmgr, width, height, &stride, &bo))
return;
ret = drmModeAddFB(fd, width, height, 32, 32, stride, bo->handle,
&fb_id);
if (ret) {
fprintf(stderr, "failed to add fb: %s\n", strerror(errno));
return;
}
x = 0;
for (i = 0; i < count; i++) {
int crtc_id;
if (c[i].mode == NULL)
continue;
printf("setting mode %s on connector %d, crtc %d\n",
c[i].mode_str, c[i].id, c[i].crtc);
ret = drmModeSetCrtc(fd, c[i].crtc, fb_id, x, 0,
&c[i].id, 1, c[i].mode);
x += c[i].mode->hdisplay;
if (ret) {
fprintf(stderr, "failed to set mode: %s\n", strerror(errno));
return;
}
}
}
extern char *optarg;
extern int optind, opterr, optopt;
static char optstr[] = "ecpmfs:";
void usage(char *name)
{
fprintf(stderr, "usage: %s [-ecpmf]\n", name);
fprintf(stderr, "\t-e\tlist encoders\n");
fprintf(stderr, "\t-c\tlist connectors\n");
fprintf(stderr, "\t-p\tlist CRTCs (pipes)\n");
fprintf(stderr, "\t-m\tlist modes\n");
fprintf(stderr, "\t-f\tlist framebuffers\n");
fprintf(stderr, "\t-s <connector_id>:<mode>\tset a mode\n");
fprintf(stderr, "\t-s <connector_id>@<crtc_id>:<mode>\tset a mode\n");
fprintf(stderr, "\n\tDefault is to dump all info.\n");
exit(0);
}
#define dump_resource(res) if (res) dump_##res()
int main(int argc, char **argv)
{
int c;
int encoders = 0, connectors = 0, crtcs = 0, framebuffers = 0;
char *modules[] = { "i915", "radeon" };
char *modeset = NULL, *mode, *connector;
int i, connector_id, count = 0;
struct connector con_args[2];
opterr = 0;
while ((c = getopt(argc, argv, optstr)) != -1) {
switch (c) {
case 'e':
encoders = 1;
break;
case 'c':
connectors = 1;
break;
case 'p':
crtcs = 1;
break;
case 'm':
modes = 1;
break;
case 'f':
framebuffers = 1;
break;
case 's':
modeset = strdup(optarg);
con_args[count].crtc = -1;
if (sscanf(optarg, "%d:%64s",
&con_args[count].id,
&con_args[count].mode_str) != 2 &&
sscanf(optarg, "%d@%d:%64s",
&con_args[count].id,
&con_args[count].crtc,
&con_args[count].mode_str) != 3)
usage(argv[0]);
count++;
break;
default:
usage(argv[0]);
break;
}
}
if (argc == 1)
encoders = connectors = crtcs = modes = framebuffers = 1;
for (i = 0; i < ARRAY_SIZE(modules); i++) {
printf("trying to load module %s...", modules[i]);
fd = drmOpen(modules[i], NULL);
if (fd < 0) {
printf("failed.\n");
} else {
printf("success.\n");
break;
}
}
if (i == ARRAY_SIZE(modules)) {
fprintf(stderr, "failed to load any modules, aborting.\n");
return -1;
}
resources = drmModeGetResources(fd);
if (!resources) {
fprintf(stderr, "drmModeGetResources failed: %s\n",
strerror(errno));
drmClose(fd);
return 1;
}
dump_resource(encoders);
dump_resource(connectors);
dump_resource(crtcs);
dump_resource(framebuffers);
if (count > 0) {
set_mode(con_args, count);
getchar();
}
drmModeFreeResources(resources);
return 0;
}

View File

@ -40,6 +40,11 @@ int main(int argc, char **argv)
int fd, ret;
drm_set_version_t sv, version;
if (getuid() != 0) {
fprintf(stderr, "setversion test requires root, skipping\n");
return 0;
}
fd = drm_open_any_master();
/* First, check that we can get the DD/DI versions. */

View File

@ -123,6 +123,11 @@ int main(int argc, char **argv)
{
int fd, ret, d1, d2;
if (getuid() != 0) {
fprintf(stderr, "updatedraw test requires root, skipping\n");
return 0;
}
fd = drm_open_any_master();
d1 = add_drawable(fd);