C++程序  |  403行  |  9.2 KB

/*
// Copyright (c) 2014 Intel Corporation 
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
*/

#include <string.h>
#include <wsbm_pool.h>
#include <wsbm_driver.h>
#include <wsbm_manager.h>
#include <wsbm_util.h>
#include <drm/ttm/ttm_placement.h>
#include <linux/psb_drm.h>
#include <xf86drm.h>
#include <HwcTrace.h>

struct _WsbmBufferPool * mainPool = NULL;

struct PsbWsbmValidateNode
{
    struct  _ValidateNode base;
    struct psb_validate_arg arg;
};

static inline uint32_t align_to(uint32_t arg, uint32_t align)
{
    return ((arg + (align - 1)) & (~(align - 1)));
}

static struct _ValidateNode * pvrAlloc(struct _WsbmVNodeFuncs * func,
                                       int typeId)
{
    CTRACE();
    if(typeId == 0) {
        struct PsbWsbmValidateNode * vNode = malloc(sizeof(*vNode));
        if(!vNode) {
            ETRACE("failed to allocate memory");
            return NULL;
        }

        vNode->base.func = func;
        vNode->base.type_id = 0;
        return &vNode->base;
    } else {
        struct _ValidateNode * node = malloc(sizeof(*node));
        if(!node) {
            ETRACE("failed to allocate node");
            return NULL;
        }

        node->func = func;
        node->type_id = 1;
        return node;
    }
}

static void pvrFree(struct _ValidateNode * node)
{
    CTRACE();
    if(node->type_id == 0) {
        free(containerOf(node, struct PsbWsbmValidateNode, base));
    } else {
        free(node);
    }
}

static void pvrClear(struct _ValidateNode * node)
{
    CTRACE();
    if(node->type_id == 0) {
        struct PsbWsbmValidateNode * vNode =
            containerOf(node, struct PsbWsbmValidateNode, base);
        memset(&vNode->arg.d.req, 0, sizeof(vNode->arg.d.req));
    }
}

static struct _WsbmVNodeFuncs vNodeFuncs = {
    .alloc  = pvrAlloc,
    .free   = pvrFree,
    .clear  = pvrClear,
};

void psbWsbmTakedown()
{
    CTRACE();

    if (mainPool) {
        wsbmPoolTakeDown(mainPool);
        mainPool = NULL;
    }

    if (wsbmIsInitialized()) {
        wsbmTakedown();
    }
}

int psbWsbmInitialize(int drmFD)
{
    union drm_psb_extension_arg arg;
    const char drmExt[] = "psb_ttm_placement_alphadrop";
    int ret = 0;

    CTRACE();

    if (drmFD <= 0) {
        ETRACE("invalid drm fd %d", drmFD);
        return drmFD;
    }

    /*init wsbm*/
    ret = wsbmInit(wsbmNullThreadFuncs(), &vNodeFuncs);
    if (ret) {
        ETRACE("failed to initialize Wsbm, error code %d", ret);
        return ret;
    }

    VTRACE("DRM_PSB_EXTENSION %d", DRM_PSB_EXTENSION);

    /*get devOffset via drm IOCTL*/
    strncpy(arg.extension, drmExt, sizeof(drmExt));

    ret = drmCommandWriteRead(drmFD, 6/*DRM_PSB_EXTENSION*/, &arg, sizeof(arg));
    if(ret || !arg.rep.exists) {
        ETRACE("failed to get device offset, error code %d", ret);
        goto out;
    }

    VTRACE("ioctl offset %#x", arg.rep.driver_ioctl_offset);

    mainPool = wsbmTTMPoolInit(drmFD, arg.rep.driver_ioctl_offset);
    if(!mainPool) {
        ETRACE("failed to initialize TTM Pool");
        ret = -EINVAL;
        goto out;
    }

    VTRACE("Wsbm initialization succeeded. mainPool %p", mainPool);

    return 0;

out:
    psbWsbmTakedown();
    return ret;
}

int psbWsbmAllocateFromUB(uint32_t size, uint32_t align, void ** buf, void *user_pt)
{
    struct _WsbmBufferObject * wsbmBuf = NULL;
    int ret = 0;
    int offset = 0;

    ATRACE("size %d", align_to(size, 4096));

    if(!buf || !user_pt) {
        ETRACE("invalid parameter");
        return -EINVAL;
    }

    VTRACE("mainPool %p", mainPool);

    ret = wsbmGenBuffers(mainPool, 1, &wsbmBuf, align,
                        DRM_PSB_FLAG_MEM_MMU | WSBM_PL_FLAG_CACHED |
                        WSBM_PL_FLAG_NO_EVICT | WSBM_PL_FLAG_SHARED);
    if(ret) {
        ETRACE("wsbmGenBuffers failed with error code %d", ret);
        return ret;
    }

    ret = wsbmBODataUB(wsbmBuf,
                       align_to(size, 4096), NULL, NULL, 0,
                       user_pt, -1);

    if(ret) {
        ETRACE("wsbmBOData failed with error code %d", ret);
        /*FIXME: should I unreference this buffer here?*/
        return ret;
    }

    *buf = wsbmBuf;

    VTRACE("ttm UB buffer allocated. %p", *buf);
    return 0;
}

int psbWsbmAllocateTTMBuffer(uint32_t size, uint32_t align, void ** buf)
{
    struct _WsbmBufferObject * wsbmBuf = NULL;
    int ret = 0;
    int offset = 0;

    ATRACE("size %d", align_to(size, 4096));

    if(!buf) {
        ETRACE("invalid parameter");
        return -EINVAL;
    }

    VTRACE("mainPool %p", mainPool);

    ret = wsbmGenBuffers(mainPool, 1, &wsbmBuf, align,
                        (WSBM_PL_FLAG_VRAM | WSBM_PL_FLAG_TT |
                         WSBM_PL_FLAG_SHARED | WSBM_PL_FLAG_NO_EVICT));
    if(ret) {
        ETRACE("wsbmGenBuffers failed with error code %d", ret);
        return ret;
    }

    ret = wsbmBOData(wsbmBuf, align_to(size, 4096), NULL, NULL, 0);
    if(ret) {
        ETRACE("wsbmBOData failed with error code %d", ret);
        /*FIXME: should I unreference this buffer here?*/
        return ret;
    }

    /* wsbmBOReference(wsbmBuf); */ /* no need to add reference */

    *buf = wsbmBuf;

    VTRACE("ttm buffer allocated. %p", *buf);
    return 0;
}

int psbWsbmWrapTTMBuffer(uint64_t handle, void **buf)
{
    int ret = 0;
    struct _WsbmBufferObject *wsbmBuf;

    if (!buf) {
        ETRACE("invalid parameter");
        return -EINVAL;
    }

    ret = wsbmGenBuffers(mainPool, 1, &wsbmBuf, 0,
                        (WSBM_PL_FLAG_VRAM | WSBM_PL_FLAG_TT |
                        /*WSBM_PL_FLAG_NO_EVICT |*/ WSBM_PL_FLAG_SHARED));

    if (ret) {
        ETRACE("wsbmGenBuffers failed with error code %d", ret);
        return ret;
    }

    ret = wsbmBOSetReferenced(wsbmBuf, handle);
    if (ret) {
        ETRACE("wsbmBOSetReferenced failed with error code %d", ret);
        return ret;
    }

    *buf = (void *)wsbmBuf;

    VTRACE("wrap buffer %p for handle %#x", wsbmBuf, handle);
    return 0;
}

int psbWsbmWrapTTMBuffer2(uint64_t handle, void **buf)
{
    int ret = 0;
    struct _WsbmBufferObject *wsbmBuf;

    if (!buf) {
        ETRACE("invalid parameter");
        return -EINVAL;
    }

    ret = wsbmGenBuffers(mainPool, 1, &wsbmBuf, 4096,
            (WSBM_PL_FLAG_SHARED | DRM_PSB_FLAG_MEM_MMU | WSBM_PL_FLAG_UNCACHED));

    if (ret) {
        ETRACE("wsbmGenBuffers failed with error code %d", ret);
        return ret;
    }

    *buf = (void *)wsbmBuf;

    VTRACE("wrap buffer %p for handle %#x", wsbmBuf, handle);
    return 0;
}


int psbWsbmCreateFromUB(void *buf, uint32_t size, void *vaddr)
{
    int ret = 0;
    struct _WsbmBufferObject *wsbmBuf;

    if (!buf || !vaddr) {
        ETRACE("invalid parameter");
        return -EINVAL;
    }

    wsbmBuf = (struct _WsbmBufferObject *)buf;
    ret = wsbmBODataUB(wsbmBuf, size, NULL, NULL, 0, vaddr, -1);
    if (ret) {
        ETRACE("wsbmBODataUB failed with error code %d", ret);
        return ret;
    }

    return 0;
}

int psbWsbmUnReference(void *buf)
{
    struct _WsbmBufferObject *wsbmBuf;

    if (!buf) {
        ETRACE("invalid parameter");
        return -EINVAL;
    }

    wsbmBuf = (struct _WsbmBufferObject *)buf;

    wsbmBOUnreference(&wsbmBuf);

    return 0;
}

int psbWsbmDestroyTTMBuffer(void * buf)
{
    CTRACE();

    if(!buf) {
        ETRACE("invalid ttm buffer");
        return -EINVAL;
    }

    /*FIXME: should I unmap this buffer object first?*/
    wsbmBOUnmap((struct _WsbmBufferObject *)buf);

    wsbmBOUnreference((struct _WsbmBufferObject **)&buf);

    XTRACE();

    return 0;
}

void * psbWsbmGetCPUAddress(void * buf)
{
    if(!buf) {
        ETRACE("invalid ttm buffer");
        return NULL;
    }

    VTRACE("buffer object %p", buf);

    void * address = wsbmBOMap((struct _WsbmBufferObject *)buf,
                                WSBM_ACCESS_READ | WSBM_ACCESS_WRITE);
    if(!address) {
        ETRACE("failed to map buffer object");
        return NULL;
    }

    VTRACE("mapped successfully. %p, size %ld",
        address, wsbmBOSize((struct _WsbmBufferObject *)buf));

    return address;
}

uint32_t psbWsbmGetGttOffset(void * buf)
{
    if(!buf) {
        ETRACE("invalid ttm buffer");
        return 0;
    }

    VTRACE("buffer object %p", buf);

    uint32_t offset =
        wsbmBOOffsetHint((struct _WsbmBufferObject *)buf) - 0x10000000;

    VTRACE("offset %#x", offset >> 12);

    return offset >> 12;
}

uint32_t psbWsbmGetKBufHandle(void *buf)
{
    if (!buf) {
        ETRACE("invalid ttm buffer");
        return 0;
    }

    return (wsbmKBufHandle(wsbmKBuf((struct _WsbmBufferObject *)buf)));
}

uint32_t psbWsbmWaitIdle(void *buf)
{
    if (!buf) {
        ETRACE("invalid ttm buffer");
        return -EINVAL;
    }

    wsbmBOWaitIdle(buf, 0);
    return 0;
}