text: /*
  // 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 <malloc.h>
  #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 <common/utils/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) {
              ELOGTRACE("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) {
              ELOGTRACE("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) {
          ELOGTRACE("invalid drm fd %d", drmFD);
          return drmFD;
      }
  
      /*init wsbm*/
      ret = wsbmInit(wsbmNullThreadFuncs(), &vNodeFuncs);
      if (ret) {
          ELOGTRACE("failed to initialize Wsbm, error code %d", ret);
          return ret;
      }
  
      VLOGTRACE("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) {
          ELOGTRACE("failed to get device offset, error code %d", ret);
          goto out;
      }
  
      unsigned int ioctl_offset = arg.rep.driver_ioctl_offset;
      ILOGTRACE("ioctl offset %#x", ioctl_offset);
  
      mainPool = wsbmTTMPoolInit(drmFD, arg.rep.driver_ioctl_offset);
      if(!mainPool) {
          ELOGTRACE("failed to initialize TTM Pool");
          ret = -EINVAL;
          goto out;
      }
  
      VLOGTRACE("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;
  
      ALOGTRACE("size %d", align_to(size, 4096));
  
      if(!buf || !user_pt) {
          ELOGTRACE("invalid parameter");
          return -EINVAL;
      }
  
      VLOGTRACE("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) {
          ELOGTRACE("wsbmGenBuffers failed with error code %d", ret);
          return ret;
      }
  
      ret = wsbmBODataUB(wsbmBuf,
                         align_to(size, 4096), NULL, NULL, 0,
                         user_pt, -1);
  
      if(ret) {
          ELOGTRACE("wsbmBOData failed with error code %d", ret);
          /*FIXME: should I unreference this buffer here?*/
          return ret;
      }
  
      *buf = wsbmBuf;
  
      VLOGTRACE("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;
  
      ALOGTRACE("size %d", align_to(size, 4096));
  
      if(!buf) {
          ELOGTRACE("invalid parameter");
          return -EINVAL;
      }
  
      VLOGTRACE("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) {
          ELOGTRACE("wsbmGenBuffers failed with error code %d", ret);
          return ret;
      }
  
      ret = wsbmBOData(wsbmBuf, align_to(size, 4096), NULL, NULL, 0);
      if(ret) {
          ELOGTRACE("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;
  
      VLOGTRACE("ttm buffer allocated. %p", *buf);
      return 0;
  }
  
  int psbWsbmWrapTTMBuffer(uint32_t handle, void **buf)
  {
      int ret = 0;
      struct _WsbmBufferObject *wsbmBuf;
  
      if (!buf) {
          ELOGTRACE("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) {
          ELOGTRACE("wsbmGenBuffers failed with error code %d", ret);
          return ret;
      }
  
      ret = wsbmBOSetReferenced(wsbmBuf, handle);
      if (ret) {
          ELOGTRACE("wsbmBOSetReferenced failed with error code %d", ret);
          return ret;
      }
  
      *buf = (void *)wsbmBuf;
  
      VLOGTRACE("wrap buffer %p for handle %#x", wsbmBuf, handle);
      return 0;
  }
  
  int psbWsbmWrapTTMBuffer2(uint32_t handle, void **buf)
  {
      int ret = 0;
      struct _WsbmBufferObject *wsbmBuf;
  
      if (!buf) {
          ELOGTRACE("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) {
          ELOGTRACE("wsbmGenBuffers failed with error code %d", ret);
          return ret;
      }
  
      *buf = (void *)wsbmBuf;
  
      VLOGTRACE("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) {
          ELOGTRACE("invalid parameter");
          return -EINVAL;
      }
  
      wsbmBuf = (struct _WsbmBufferObject *)buf;
      ret = wsbmBODataUB(wsbmBuf, size, NULL, NULL, 0, vaddr, -1);
      if (ret) {
          ELOGTRACE("wsbmBODataUB failed with error code %d", ret);
          return ret;
      }
  
      return 0;
  }
  
  int psbWsbmUnReference(void *buf)
  {
      struct _WsbmBufferObject *wsbmBuf;
  
      if (!buf) {
          ELOGTRACE("invalid parameter");
          return -EINVAL;
      }
  
      wsbmBuf = (struct _WsbmBufferObject *)buf;
  
      wsbmBOUnreference(&wsbmBuf);
  
      return 0;
  }
  
  int psbWsbmDestroyTTMBuffer(void * buf)
  {
      CTRACE();
  
      if(!buf) {
          ELOGTRACE("invalid ttm buffer");
          return -EINVAL;
      }
  
      /*FIXME: should I unmap this buffer object first?*/
      wsbmBOUnmap((struct _WsbmBufferObject *)buf);
  
      wsbmBOUnreference((struct _WsbmBufferObject **)&buf);
  
      XLOGTRACE();
  
      return 0;
  }
  
  void * psbWsbmGetCPUAddress(void * buf)
  {
      if(!buf) {
          ELOGTRACE("invalid ttm buffer");
          return NULL;
      }
  
      VLOGTRACE("buffer object %p", buf);
  
      void * address = wsbmBOMap((struct _WsbmBufferObject *)buf,
                                  WSBM_ACCESS_READ | WSBM_ACCESS_WRITE);
      if(!address) {
          ELOGTRACE("failed to map buffer object");
          return NULL;
      }
  
      unsigned long buf_size = wsbmBOSize((struct _WsbmBufferObject *)buf);
      VLOGTRACE("mapped successfully. %p, size %ld",
          address, buf_size);
  
      return address;
  }
  
  uint32_t psbWsbmGetGttOffset(void * buf)
  {
      if(!buf) {
          ELOGTRACE("invalid ttm buffer");
          return 0;
      }
  
      VLOGTRACE("buffer object %p", buf);
  
      uint32_t offset =
          wsbmBOOffsetHint((struct _WsbmBufferObject *)buf) - 0x10000000;
  
      uint32_t offset_tmp = offset >> 12;
      VLOGTRACE("offset %#x", offset_tmp);
  
      return offset >> 12;
  }
  
  uint32_t psbWsbmGetKBufHandle(void *buf)
  {
      if (!buf) {
          ELOGTRACE("invalid ttm buffer");
          return 0;
      }
  
      return (wsbmKBufHandle(wsbmKBuf((struct _WsbmBufferObject *)buf)));
  }
  
  uint32_t psbWsbmWaitIdle(void *buf)
  {
      if (!buf) {
          ELOGTRACE("invalid ttm buffer");
          return -EINVAL;
      }
  
      wsbmBOWaitIdle(buf, 0);
      return 0;
  }
  