diff options
Diffstat (limited to 'src/wsbm_manager.c')
| -rw-r--r-- | src/wsbm_manager.c | 130 |
1 files changed, 130 insertions, 0 deletions
diff --git a/src/wsbm_manager.c b/src/wsbm_manager.c index 1c347c7..a86b894 100644 --- a/src/wsbm_manager.c +++ b/src/wsbm_manager.c @@ -610,6 +610,136 @@ wsbmBOData(struct _WsbmBufferObject *buf, return retval; } +int +wsbmBODataUB(struct _WsbmBufferObject *buf, + unsigned size, const void *data, struct _WsbmBufferPool *newPool, + uint32_t placement, const unsigned long *user_ptr) +{ + int newBuffer; + int retval = 0; + struct _WsbmBufStorage *storage; + int synced = 0; + uint32_t placement_diff; + struct _WsbmBufferPool *curPool; + extern struct _WsbmBufStorage * + ttm_pool_ub_create(struct _WsbmBufferPool *pool, + unsigned long size, uint32_t placement, unsigned alignment, + const unsigned long *user_ptr); + + if (buf->bufferType == WSBM_BUFFER_SIMPLE) + return -EINVAL; + + storage = buf->storage; + + if (newPool == NULL) + newPool = buf->pool; + + if (newPool == NULL) + return -EINVAL; + + newBuffer = (!storage || storage->pool != newPool || + storage->pool->size(storage) < size || + storage->pool->size(storage) > + size + WSBM_BODATA_SIZE_ACCEPT); + + if (!placement) + placement = buf->placement; + + if (newBuffer) { + if (buf->bufferType == WSBM_BUFFER_REF) + return -EINVAL; + + wsbmBufStorageUnref(&buf->storage); + + if (size == 0) { + buf->pool = newPool; + buf->placement = placement; + retval = 0; + goto out; + } + + buf->storage = + ttm_pool_ub_create(newPool, size, placement, buf->alignment, user_ptr); + if (!buf->storage) { + retval = -ENOMEM; + goto out; + } + + buf->placement = placement; + buf->pool = newPool; + } else if (wsbmAtomicRead(&storage->onList) || + 0 != storage->pool->syncforcpu(storage, WSBM_SYNCCPU_WRITE | + WSBM_SYNCCPU_DONT_BLOCK)) { + /* + * Buffer is busy. need to create a new one. + * Actually such case will not be encountered for current ICS implementation + * TODO: maybe need refine the following code when such usage case is required + */ + + struct _WsbmBufStorage *tmp_storage; + + curPool = storage->pool; + + tmp_storage = + ttm_pool_ub_create(curPool, size, placement, buf->alignment, user_ptr); + + if (tmp_storage) { + wsbmBufStorageUnref(&buf->storage); + buf->storage = tmp_storage; + buf->placement = placement; + } else { + retval = curPool->syncforcpu(storage, WSBM_SYNCCPU_WRITE); + if (retval) + goto out; + synced = 1; + } + } else { + synced = 1; + } + + placement_diff = placement ^ buf->placement; + + /* + * We might need to change buffer placement. + */ + + storage = buf->storage; + curPool = storage->pool; + + if (placement_diff) { + assert(curPool->setStatus != NULL); + curPool->releasefromcpu(storage, WSBM_SYNCCPU_WRITE); + retval = curPool->setStatus(storage, + placement_diff & placement, + placement_diff & ~placement); + if (retval) + goto out; + + buf->placement = placement; + } + + if (!synced) { + retval = curPool->syncforcpu(buf->storage, WSBM_SYNCCPU_WRITE); + if (retval) + goto out; + synced = 1; + } + + storage = buf->storage; + curPool = storage->pool; + + if (data) { + memcpy(user_ptr, data, size); + } + + out: + + if (synced) + curPool->releasefromcpu(storage, WSBM_SYNCCPU_WRITE); + + return retval; +} + static struct _WsbmBufStorage * wsbmStorageClone(struct _WsbmBufferObject *buf) { |
