19bd392adSmrg/**************************************************************************
29bd392adSmrg *
39bd392adSmrg * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, TX., USA
49bd392adSmrg * All Rights Reserved.
59bd392adSmrg *
69bd392adSmrg * Permission is hereby granted, free of charge, to any person obtaining a
79bd392adSmrg * copy of this software and associated documentation files (the
89bd392adSmrg * "Software"), to deal in the Software without restriction, including
99bd392adSmrg * without limitation the rights to use, copy, modify, merge, publish,
109bd392adSmrg * distribute, sub license, and/or sell copies of the Software, and to
119bd392adSmrg * permit persons to whom the Software is furnished to do so, subject to
129bd392adSmrg * the following conditions:
139bd392adSmrg *
149bd392adSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
159bd392adSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
169bd392adSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
179bd392adSmrg * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
189bd392adSmrg * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
199bd392adSmrg * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
209bd392adSmrg * USE OR OTHER DEALINGS IN THE SOFTWARE.
219bd392adSmrg *
229bd392adSmrg * The above copyright notice and this permission notice (including the
239bd392adSmrg * next paragraph) shall be included in all copies or substantial portions
249bd392adSmrg * of the Software.
259bd392adSmrg *
269bd392adSmrg *
279bd392adSmrg **************************************************************************/
289bd392adSmrg/*
299bd392adSmrg * Authors: Thomas Hellstr�m <thomas-at-tungstengraphics-dot-com>
309bd392adSmrg */
319bd392adSmrg
329bd392adSmrg#ifdef HAVE_CONFIG_H
339bd392adSmrg#include "config.h"
349bd392adSmrg#endif
359bd392adSmrg
369bd392adSmrg#include <X11/Xlib.h>
379bd392adSmrg#include <X11/Xutil.h>
389bd392adSmrg#include <stdint.h>
399bd392adSmrg#include <drm/drm.h>
409bd392adSmrg#include "xf86dri.h"
419bd392adSmrg#include "xf86drm.h"
429bd392adSmrg#include "stdio.h"
439bd392adSmrg#include "sys/types.h"
449bd392adSmrg#include <unistd.h>
459bd392adSmrg#include <string.h>
469bd392adSmrg#include <errno.h>
479bd392adSmrg#include <stdlib.h>
489bd392adSmrg#include "sys/mman.h"
499bd392adSmrg
509bd392adSmrgtypedef struct
519bd392adSmrg{
529bd392adSmrg    enum
539bd392adSmrg    {
549bd392adSmrg	haveNothing,
559bd392adSmrg	haveDisplay,
569bd392adSmrg	haveConnection,
579bd392adSmrg	haveDriverName,
589bd392adSmrg	haveDeviceInfo,
599bd392adSmrg	haveDRM,
609bd392adSmrg	haveContext
619bd392adSmrg    }
629bd392adSmrg    state;
639bd392adSmrg
649bd392adSmrg    Display *display;
659bd392adSmrg    int screen;
669bd392adSmrg    drm_handle_t sAreaOffset;
679bd392adSmrg    char *curBusID;
689bd392adSmrg    char *driverName;
699bd392adSmrg    int drmFD;
709bd392adSmrg    XVisualInfo visualInfo;
719bd392adSmrg    XID id;
729bd392adSmrg    drm_context_t hwContext;
739bd392adSmrg    void *driPriv;
749bd392adSmrg    int driPrivSize;
759bd392adSmrg    int fbSize;
769bd392adSmrg    int fbOrigin;
779bd392adSmrg    int fbStride;
789bd392adSmrg    drm_handle_t fbHandle;
799bd392adSmrg    int ddxDriverMajor;
809bd392adSmrg    int ddxDriverMinor;
819bd392adSmrg    int ddxDriverPatch;
829bd392adSmrg} TinyDRIContext;
839bd392adSmrg
849bd392adSmrg#ifndef __x86_64__
859bd392adSmrgstatic unsigned
869bd392adSmrgfastrdtsc(void)
879bd392adSmrg{
889bd392adSmrg    unsigned eax;
899bd392adSmrg    __asm__ volatile ("\t"
909bd392adSmrg	"pushl  %%ebx\n\t"
919bd392adSmrg	"cpuid\n\t" ".byte 0x0f, 0x31\n\t" "popl %%ebx\n":"=a" (eax)
929bd392adSmrg	:"0"(0)
939bd392adSmrg	:"ecx", "edx", "cc");
949bd392adSmrg
959bd392adSmrg    return eax;
969bd392adSmrg}
979bd392adSmrg#else
989bd392adSmrgstatic unsigned
999bd392adSmrgfastrdtsc(void)
1009bd392adSmrg{
1019bd392adSmrg    unsigned eax;
1029bd392adSmrg    __asm__ volatile ("\t" "cpuid\n\t" ".byte 0x0f, 0x31\n\t":"=a" (eax)
1039bd392adSmrg	:"0"(0)
1049bd392adSmrg	:"ecx", "edx", "ebx", "cc");
1059bd392adSmrg
1069bd392adSmrg    return eax;
1079bd392adSmrg}
1089bd392adSmrg#endif
1099bd392adSmrg
1109bd392adSmrgvoid
1119bd392adSmrgbmError(int val, const char *file, const char *function, int line)
1129bd392adSmrg{
1139bd392adSmrg    fprintf(stderr, "Fatal video memory manager error \"%s\".\n"
1149bd392adSmrg	"Check kernel logs or set the LIBGL_DEBUG\n"
1159bd392adSmrg	"environment variable to \"verbose\" for more info.\n"
1169bd392adSmrg	"Detected in file %s, line %d, function %s.\n",
1179bd392adSmrg	strerror(-val), file, line, function);
1189bd392adSmrg    abort();
1199bd392adSmrg}
1209bd392adSmrg
1219bd392adSmrg#define BM_CKFATAL(val)					       \
1229bd392adSmrg  do{							       \
1239bd392adSmrg    int tstVal = (val);					       \
1249bd392adSmrg    if (tstVal) 					       \
1259bd392adSmrg      bmError(tstVal, __FILE__, __FUNCTION__, __LINE__);       \
1269bd392adSmrg  } while(0);
1279bd392adSmrg
1289bd392adSmrgstatic unsigned
1299bd392adSmrgtime_diff(unsigned t, unsigned t2)
1309bd392adSmrg{
1319bd392adSmrg    return ((t < t2) ? t2 - t : 0xFFFFFFFFU - (t - t2 - 1));
1329bd392adSmrg}
1339bd392adSmrg
1349bd392adSmrgstatic int
1359bd392adSmrgreleaseContext(TinyDRIContext * ctx)
1369bd392adSmrg{
1379bd392adSmrg    switch (ctx->state) {
1389bd392adSmrg    case haveContext:
1399bd392adSmrg	uniDRIDestroyContext(ctx->display, ctx->screen, ctx->id);
1409bd392adSmrg    case haveDRM:
1419bd392adSmrg	drmClose(ctx->drmFD);
1429bd392adSmrg    case haveDeviceInfo:
1439bd392adSmrg	XFree(ctx->driPriv);
1449bd392adSmrg    case haveDriverName:
1459bd392adSmrg	XFree(ctx->driverName);
1469bd392adSmrg    case haveConnection:
1479bd392adSmrg	XFree(ctx->curBusID);
1489bd392adSmrg	uniDRICloseConnection(ctx->display, ctx->screen);
1499bd392adSmrg    case haveDisplay:
1509bd392adSmrg	XCloseDisplay(ctx->display);
1519bd392adSmrg    default:
1529bd392adSmrg	break;
1539bd392adSmrg    }
1549bd392adSmrg    return -1;
1559bd392adSmrg}
1569bd392adSmrg
1579bd392adSmrgstatic void
1589bd392adSmrgreadBuf(void *buf, unsigned long size)
1599bd392adSmrg{
1609bd392adSmrg    volatile unsigned *buf32 = (unsigned *)buf;
1619bd392adSmrg    unsigned *end = (unsigned *)buf32 + size / sizeof(*buf32);
1629bd392adSmrg
1639bd392adSmrg    while (buf32 < end) {
1649bd392adSmrg	(void)*buf32++;
1659bd392adSmrg    }
1669bd392adSmrg}
1679bd392adSmrg
1689bd392adSmrgstatic int
1699bd392adSmrgbenchmarkBuffer(TinyDRIContext * ctx, unsigned long size,
1709bd392adSmrg    unsigned long *ticks)
1719bd392adSmrg{
1729bd392adSmrg    unsigned long curTime, oldTime;
1739bd392adSmrg    int ret;
1749bd392adSmrg    drmBO buf;
1759bd392adSmrg    void *virtual;
1769bd392adSmrg
1779bd392adSmrg    /*
1789bd392adSmrg     * Test system memory objects.
1799bd392adSmrg     */
1809bd392adSmrg    oldTime = fastrdtsc();
1819bd392adSmrg    BM_CKFATAL(drmBOCreate(ctx->drmFD, size, 0, NULL,
1829bd392adSmrg			   DRM_BO_FLAG_READ |
1839bd392adSmrg			   DRM_BO_FLAG_WRITE |
1849bd392adSmrg			   DRM_BO_FLAG_MEM_LOCAL, 0, &buf));
1859bd392adSmrg    curTime = fastrdtsc();
1869bd392adSmrg    *ticks++ = time_diff(oldTime, curTime);
1879bd392adSmrg
1889bd392adSmrg    oldTime = fastrdtsc();
1899bd392adSmrg    BM_CKFATAL(drmBOMap(ctx->drmFD, &buf,
1909bd392adSmrg	    DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE, 0, &virtual));
1919bd392adSmrg    curTime = fastrdtsc();
1929bd392adSmrg    *ticks++ = time_diff(oldTime, curTime);
1939bd392adSmrg
1949bd392adSmrg    oldTime = fastrdtsc();
1959bd392adSmrg    memset(virtual, 0xF0, buf.size);
1969bd392adSmrg    curTime = fastrdtsc();
1979bd392adSmrg    *ticks++ = time_diff(oldTime, curTime);
1989bd392adSmrg
1999bd392adSmrg    oldTime = fastrdtsc();
2009bd392adSmrg    memset(virtual, 0x0F, buf.size);
2019bd392adSmrg    curTime = fastrdtsc();
2029bd392adSmrg    *ticks++ = time_diff(oldTime, curTime);
2039bd392adSmrg
2049bd392adSmrg    oldTime = fastrdtsc();
2059bd392adSmrg    readBuf(virtual, buf.size);
2069bd392adSmrg    curTime = fastrdtsc();
2079bd392adSmrg    *ticks++ = time_diff(oldTime, curTime);
2089bd392adSmrg
2099bd392adSmrg    oldTime = fastrdtsc();
2109bd392adSmrg    BM_CKFATAL(drmBOUnmap(ctx->drmFD, &buf));
2119bd392adSmrg    curTime = fastrdtsc();
2129bd392adSmrg    *ticks++ = time_diff(oldTime, curTime);
2139bd392adSmrg
2149bd392adSmrg    /*
2159bd392adSmrg     * Test TT bound buffer objects.
2169bd392adSmrg     */
2179bd392adSmrg
2189bd392adSmrg    oldTime = fastrdtsc();
2199bd392adSmrg    BM_CKFATAL(drmBOSetStatus(ctx->drmFD, &buf,
2209bd392adSmrg			     DRM_BO_FLAG_MEM_TT,
2219bd392adSmrg			     DRM_BO_MASK_MEM,
2229bd392adSmrg			      0,0,0));
2239bd392adSmrg    curTime = fastrdtsc();
2249bd392adSmrg    *ticks++ = time_diff(oldTime, curTime);
2259bd392adSmrg
2269bd392adSmrg    oldTime = fastrdtsc();
2279bd392adSmrg    BM_CKFATAL(drmBOMap(ctx->drmFD, &buf,
2289bd392adSmrg	    DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE, 0, &virtual));
2299bd392adSmrg    curTime = fastrdtsc();
2309bd392adSmrg    *ticks++ = time_diff(oldTime, curTime);
2319bd392adSmrg
2329bd392adSmrg    oldTime = fastrdtsc();
2339bd392adSmrg    memset(virtual, 0xF0, buf.size);
2349bd392adSmrg    curTime = fastrdtsc();
2359bd392adSmrg    *ticks++ = time_diff(oldTime, curTime);
2369bd392adSmrg
2379bd392adSmrg    oldTime = fastrdtsc();
2389bd392adSmrg    memset(virtual, 0x0F, buf.size);
2399bd392adSmrg    curTime = fastrdtsc();
2409bd392adSmrg    *ticks++ = time_diff(oldTime, curTime);
2419bd392adSmrg
2429bd392adSmrg    oldTime = fastrdtsc();
2439bd392adSmrg    readBuf(virtual, buf.size);
2449bd392adSmrg    curTime = fastrdtsc();
2459bd392adSmrg    *ticks++ = time_diff(oldTime, curTime);
2469bd392adSmrg
2479bd392adSmrg    BM_CKFATAL(drmBOUnmap(ctx->drmFD, &buf));
2489bd392adSmrg
2499bd392adSmrg    oldTime = fastrdtsc();
2509bd392adSmrg    BM_CKFATAL(drmBOSetStatus(ctx->drmFD, &buf,
2519bd392adSmrg			     DRM_BO_FLAG_MEM_LOCAL, DRM_BO_MASK_MEM, 0, 0,0));
2529bd392adSmrg    curTime = fastrdtsc();
2539bd392adSmrg    *ticks++ = time_diff(oldTime, curTime);
2549bd392adSmrg
2559bd392adSmrg    /*
2569bd392adSmrg     * Test cached buffers objects.
2579bd392adSmrg     */
2589bd392adSmrg
2599bd392adSmrg    oldTime = fastrdtsc();
2609bd392adSmrg    ret = drmBOSetStatus(ctx->drmFD, &buf,
2619bd392adSmrg			 DRM_BO_FLAG_MEM_TT |
2629bd392adSmrg			 DRM_BO_FLAG_CACHED |
2639bd392adSmrg			 DRM_BO_FLAG_FORCE_CACHING,
2649bd392adSmrg			 DRM_BO_MASK_MEMTYPE |
2659bd392adSmrg			 DRM_BO_FLAG_FORCE_CACHING,
2669bd392adSmrg			 0, 0, 0);
2679bd392adSmrg    curTime = fastrdtsc();
2689bd392adSmrg
2699bd392adSmrg    if (ret) {
2709bd392adSmrg	printf("Couldn't bind cached. Probably no support\n");
2719bd392adSmrg	BM_CKFATAL(drmBOUnreference(ctx->drmFD, &buf));
2729bd392adSmrg	return 1;
2739bd392adSmrg    }
2749bd392adSmrg    *ticks++ = time_diff(oldTime, curTime);
2759bd392adSmrg
2769bd392adSmrg    oldTime = fastrdtsc();
2779bd392adSmrg    BM_CKFATAL(drmBOMap(ctx->drmFD, &buf,
2789bd392adSmrg	    DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE, 0, &virtual));
2799bd392adSmrg
2809bd392adSmrg    curTime = fastrdtsc();
2819bd392adSmrg    *ticks++ = time_diff(oldTime, curTime);
2829bd392adSmrg
2839bd392adSmrg    oldTime = fastrdtsc();
2849bd392adSmrg    memset(virtual, 0xF0, buf.size);
2859bd392adSmrg    curTime = fastrdtsc();
2869bd392adSmrg    *ticks++ = time_diff(oldTime, curTime);
2879bd392adSmrg
2889bd392adSmrg    oldTime = fastrdtsc();
2899bd392adSmrg    memset(virtual, 0x0F, buf.size);
2909bd392adSmrg    curTime = fastrdtsc();
2919bd392adSmrg    *ticks++ = time_diff(oldTime, curTime);
2929bd392adSmrg
2939bd392adSmrg    oldTime = fastrdtsc();
2949bd392adSmrg    readBuf(virtual, buf.size);
2959bd392adSmrg    curTime = fastrdtsc();
2969bd392adSmrg    *ticks++ = time_diff(oldTime, curTime);
2979bd392adSmrg
2989bd392adSmrg    BM_CKFATAL(drmBOUnmap(ctx->drmFD, &buf));
2999bd392adSmrg    BM_CKFATAL(drmBOUnreference(ctx->drmFD, &buf));
3009bd392adSmrg
3019bd392adSmrg    return 0;
3029bd392adSmrg}
3039bd392adSmrg
3049bd392adSmrgstatic void
3059bd392adSmrgtestAGP(TinyDRIContext * ctx)
3069bd392adSmrg{
3079bd392adSmrg    unsigned long ticks[128], *pTicks;
3089bd392adSmrg    unsigned long size = 8 * 1024;
3099bd392adSmrg    int ret;
3109bd392adSmrg
3119bd392adSmrg    ret = benchmarkBuffer(ctx, size, ticks);
3129bd392adSmrg    if (ret < 0) {
3139bd392adSmrg	fprintf(stderr, "Buffer error %s\n", strerror(-ret));
3149bd392adSmrg	return;
3159bd392adSmrg    }
3169bd392adSmrg    pTicks = ticks;
3179bd392adSmrg
3189bd392adSmrg    printf("Buffer size %d bytes\n", size);
3199bd392adSmrg    printf("System memory timings ********************************\n");
3209bd392adSmrg    printf("Creation took            %12lu ticks\n", *pTicks++);
3219bd392adSmrg    printf("Mapping took             %12lu ticks\n", *pTicks++);
3229bd392adSmrg    printf("Writing took             %12lu ticks\n", *pTicks++);
3239bd392adSmrg    printf("Writing Again took       %12lu ticks\n", *pTicks++);
3249bd392adSmrg    printf("Reading took             %12lu ticks\n", *pTicks++);
3259bd392adSmrg    printf("Unmapping took           %12lu ticks\n", *pTicks++);
3269bd392adSmrg
3279bd392adSmrg    printf("\nTT Memory timings ************************************\n");
3289bd392adSmrg    printf("Moving to TT took        %12lu ticks\n", *pTicks++);
3299bd392adSmrg    printf("Mapping in TT took       %12lu ticks\n", *pTicks++);
3309bd392adSmrg    printf("Writing to TT took       %12lu ticks\n", *pTicks++);
3319bd392adSmrg    printf("Writing again to TT took %12lu ticks\n", *pTicks++);
3329bd392adSmrg    printf("Reading from TT took     %12lu ticks\n", *pTicks++);
3339bd392adSmrg    printf("Moving to system took    %12lu ticks\n", *pTicks++);
3349bd392adSmrg
3359bd392adSmrg    if (ret == 1)
3369bd392adSmrg	return;
3379bd392adSmrg
3389bd392adSmrg    printf("\nCached TT Memory timings *****************************\n");
3399bd392adSmrg    printf("Moving to CTT took       %12lu ticks\n", *pTicks++);
3409bd392adSmrg    printf("Mapping in CTT took      %12lu ticks\n", *pTicks++);
3419bd392adSmrg    printf("Writing to CTT took      %12lu ticks\n", *pTicks++);
3429bd392adSmrg    printf("Re-writing to CTT took   %12lu ticks\n", *pTicks++);
3439bd392adSmrg    printf("Reading from CTT took    %12lu ticks\n", *pTicks++);
3449bd392adSmrg    printf("\n\n");
3459bd392adSmrg}
3469bd392adSmrg
3479bd392adSmrgint
3489bd392adSmrgmain()
3499bd392adSmrg{
3509bd392adSmrg    int ret, screen, isCapable;
3519bd392adSmrg    char *displayName = ":0";
3529bd392adSmrg    TinyDRIContext ctx;
3539bd392adSmrg    unsigned magic;
3549bd392adSmrg
3559bd392adSmrg    ctx.screen = 0;
3569bd392adSmrg    ctx.state = haveNothing;
3579bd392adSmrg    ctx.display = XOpenDisplay(displayName);
3589bd392adSmrg    if (!ctx.display) {
3599bd392adSmrg	fprintf(stderr, "Could not open display\n");
3609bd392adSmrg	return releaseContext(&ctx);
3619bd392adSmrg    }
3629bd392adSmrg    ctx.state = haveDisplay;
3639bd392adSmrg
3649bd392adSmrg    ret =
3659bd392adSmrg	uniDRIQueryDirectRenderingCapable(ctx.display, ctx.screen,
3669bd392adSmrg	&isCapable);
3679bd392adSmrg    if (!ret || !isCapable) {
3689bd392adSmrg	fprintf(stderr, "No DRI on this display:sceen\n");
3699bd392adSmrg	return releaseContext(&ctx);
3709bd392adSmrg    }
3719bd392adSmrg
3729bd392adSmrg    if (!uniDRIOpenConnection(ctx.display, ctx.screen, &ctx.sAreaOffset,
3739bd392adSmrg	    &ctx.curBusID)) {
3749bd392adSmrg	fprintf(stderr, "Could not open DRI connection.\n");
3759bd392adSmrg	return releaseContext(&ctx);
3769bd392adSmrg    }
3779bd392adSmrg    ctx.state = haveConnection;
3789bd392adSmrg
3799bd392adSmrg    if (!uniDRIGetClientDriverName(ctx.display, ctx.screen,
3809bd392adSmrg	    &ctx.ddxDriverMajor, &ctx.ddxDriverMinor,
3819bd392adSmrg	    &ctx.ddxDriverPatch, &ctx.driverName)) {
3829bd392adSmrg	fprintf(stderr, "Could not get DRI driver name.\n");
3839bd392adSmrg	return releaseContext(&ctx);
3849bd392adSmrg    }
3859bd392adSmrg    ctx.state = haveDriverName;
3869bd392adSmrg
3879bd392adSmrg    if (!uniDRIGetDeviceInfo(ctx.display, ctx.screen,
3889bd392adSmrg	    &ctx.fbHandle, &ctx.fbOrigin, &ctx.fbSize,
3899bd392adSmrg	    &ctx.fbStride, &ctx.driPrivSize, &ctx.driPriv)) {
3909bd392adSmrg	fprintf(stderr, "Could not get DRI device info.\n");
3919bd392adSmrg	return releaseContext(&ctx);
3929bd392adSmrg    }
3939bd392adSmrg    ctx.state = haveDriverName;
3949bd392adSmrg
3959bd392adSmrg    if ((ctx.drmFD = drmOpen(NULL, ctx.curBusID)) < 0) {
3969bd392adSmrg	perror("DRM Device could not be opened");
3979bd392adSmrg	return releaseContext(&ctx);
3989bd392adSmrg    }
3999bd392adSmrg    ctx.state = haveDRM;
4009bd392adSmrg
4019bd392adSmrg    drmGetMagic(ctx.drmFD, &magic);
4029bd392adSmrg    if (!uniDRIAuthConnection(ctx.display, ctx.screen, magic)) {
4039bd392adSmrg	fprintf(stderr, "Could not get X server to authenticate us.\n");
4049bd392adSmrg	return releaseContext(&ctx);
4059bd392adSmrg    }
4069bd392adSmrg
4079bd392adSmrg    ret = XMatchVisualInfo(ctx.display, ctx.screen, 24, TrueColor,
4089bd392adSmrg	&ctx.visualInfo);
4099bd392adSmrg    if (!ret) {
4109bd392adSmrg	ret = XMatchVisualInfo(ctx.display, ctx.screen, 16, TrueColor,
4119bd392adSmrg	    &ctx.visualInfo);
4129bd392adSmrg	if (!ret) {
4139bd392adSmrg	    fprintf(stderr, "Could not find a matching visual.\n");
4149bd392adSmrg	    return releaseContext(&ctx);
4159bd392adSmrg	}
4169bd392adSmrg    }
4179bd392adSmrg
4189bd392adSmrg    if (!uniDRICreateContext(ctx.display, ctx.screen, ctx.visualInfo.visual,
4199bd392adSmrg	    &ctx.id, &ctx.hwContext)) {
4209bd392adSmrg	fprintf(stderr, "Could not create DRI context.\n");
4219bd392adSmrg	return releaseContext(&ctx);
4229bd392adSmrg    }
4239bd392adSmrg    ctx.state = haveContext;
4249bd392adSmrg
4259bd392adSmrg    testAGP(&ctx);
4269bd392adSmrg
4279bd392adSmrg    releaseContext(&ctx);
4289bd392adSmrg    printf("Terminating normally\n");
4299bd392adSmrg    return 0;
4309bd392adSmrg}
431