提交 0fd53cfb 编写于 作者: T Thomas Hellstrom

drm/vmwgfx: Use the linux DMA api also for MOBs

Signed-off-by: NThomas Hellstrom <thellstrom@vmware.com>
上级 4b9e45e6
...@@ -272,6 +272,7 @@ void vmw_piter_start(struct vmw_piter *viter, const struct vmw_sg_table *vsgt, ...@@ -272,6 +272,7 @@ void vmw_piter_start(struct vmw_piter *viter, const struct vmw_sg_table *vsgt,
viter->dma_address = &__vmw_piter_dma_addr; viter->dma_address = &__vmw_piter_dma_addr;
viter->page = &__vmw_piter_non_sg_page; viter->page = &__vmw_piter_non_sg_page;
viter->addrs = vsgt->addrs; viter->addrs = vsgt->addrs;
viter->pages = vsgt->pages;
break; break;
case vmw_dma_map_populate: case vmw_dma_map_populate:
case vmw_dma_map_bind: case vmw_dma_map_bind:
...@@ -452,6 +453,63 @@ static void vmw_ttm_unmap_dma(struct vmw_ttm_tt *vmw_tt) ...@@ -452,6 +453,63 @@ static void vmw_ttm_unmap_dma(struct vmw_ttm_tt *vmw_tt)
vmw_tt->mapped = false; vmw_tt->mapped = false;
} }
/**
* vmw_bo_map_dma - Make sure buffer object pages are visible to the device
*
* @bo: Pointer to a struct ttm_buffer_object
*
* Wrapper around vmw_ttm_map_dma, that takes a TTM buffer object pointer
* instead of a pointer to a struct vmw_ttm_backend as argument.
* Note that the buffer object must be either pinned or reserved before
* calling this function.
*/
int vmw_bo_map_dma(struct ttm_buffer_object *bo)
{
struct vmw_ttm_tt *vmw_tt =
container_of(bo->ttm, struct vmw_ttm_tt, dma_ttm.ttm);
return vmw_ttm_map_dma(vmw_tt);
}
/**
* vmw_bo_unmap_dma - Make sure buffer object pages are visible to the device
*
* @bo: Pointer to a struct ttm_buffer_object
*
* Wrapper around vmw_ttm_unmap_dma, that takes a TTM buffer object pointer
* instead of a pointer to a struct vmw_ttm_backend as argument.
*/
void vmw_bo_unmap_dma(struct ttm_buffer_object *bo)
{
struct vmw_ttm_tt *vmw_tt =
container_of(bo->ttm, struct vmw_ttm_tt, dma_ttm.ttm);
vmw_ttm_unmap_dma(vmw_tt);
}
/**
* vmw_bo_sg_table - Return a struct vmw_sg_table object for a
* TTM buffer object
*
* @bo: Pointer to a struct ttm_buffer_object
*
* Returns a pointer to a struct vmw_sg_table object. The object should
* not be freed after use.
* Note that for the device addresses to be valid, the buffer object must
* either be reserved or pinned.
*/
const struct vmw_sg_table *vmw_bo_sg_table(struct ttm_buffer_object *bo)
{
struct vmw_ttm_tt *vmw_tt =
container_of(bo->ttm, struct vmw_ttm_tt, dma_ttm.ttm);
return &vmw_tt->vsgt;
}
static int vmw_ttm_bind(struct ttm_tt *ttm, struct ttm_mem_reg *bo_mem) static int vmw_ttm_bind(struct ttm_tt *ttm, struct ttm_mem_reg *bo_mem)
{ {
struct vmw_ttm_tt *vmw_be = struct vmw_ttm_tt *vmw_be =
...@@ -478,7 +536,7 @@ static int vmw_ttm_bind(struct ttm_tt *ttm, struct ttm_mem_reg *bo_mem) ...@@ -478,7 +536,7 @@ static int vmw_ttm_bind(struct ttm_tt *ttm, struct ttm_mem_reg *bo_mem)
} }
return vmw_mob_bind(vmw_be->dev_priv, vmw_be->mob, return vmw_mob_bind(vmw_be->dev_priv, vmw_be->mob,
ttm->pages, ttm->num_pages, &vmw_be->vsgt, ttm->num_pages,
vmw_be->gmr_id); vmw_be->gmr_id);
default: default:
BUG(); BUG();
...@@ -526,6 +584,7 @@ static void vmw_ttm_destroy(struct ttm_tt *ttm) ...@@ -526,6 +584,7 @@ static void vmw_ttm_destroy(struct ttm_tt *ttm)
kfree(vmw_be); kfree(vmw_be);
} }
static int vmw_ttm_populate(struct ttm_tt *ttm) static int vmw_ttm_populate(struct ttm_tt *ttm)
{ {
struct vmw_ttm_tt *vmw_tt = struct vmw_ttm_tt *vmw_tt =
......
...@@ -708,6 +708,10 @@ extern struct ttm_placement vmw_srf_placement; ...@@ -708,6 +708,10 @@ extern struct ttm_placement vmw_srf_placement;
extern struct ttm_placement vmw_mob_placement; extern struct ttm_placement vmw_mob_placement;
extern struct ttm_bo_driver vmw_bo_driver; extern struct ttm_bo_driver vmw_bo_driver;
extern int vmw_dma_quiescent(struct drm_device *dev); extern int vmw_dma_quiescent(struct drm_device *dev);
extern int vmw_bo_map_dma(struct ttm_buffer_object *bo);
extern void vmw_bo_unmap_dma(struct ttm_buffer_object *bo);
extern const struct vmw_sg_table *
vmw_bo_sg_table(struct ttm_buffer_object *bo);
extern void vmw_piter_start(struct vmw_piter *viter, extern void vmw_piter_start(struct vmw_piter *viter,
const struct vmw_sg_table *vsgt, const struct vmw_sg_table *vsgt,
unsigned long p_offs); unsigned long p_offs);
...@@ -919,8 +923,8 @@ extern int vmw_prime_handle_to_fd(struct drm_device *dev, ...@@ -919,8 +923,8 @@ extern int vmw_prime_handle_to_fd(struct drm_device *dev,
*/ */
struct vmw_mob; struct vmw_mob;
extern int vmw_mob_bind(struct vmw_private *dev_priv, struct vmw_mob *mob, extern int vmw_mob_bind(struct vmw_private *dev_priv, struct vmw_mob *mob,
struct page **data_pages, unsigned long num_data_pages, const struct vmw_sg_table *vsgt,
int32_t mob_id); unsigned long num_data_pages, int32_t mob_id);
extern void vmw_mob_unbind(struct vmw_private *dev_priv, extern void vmw_mob_unbind(struct vmw_private *dev_priv,
struct vmw_mob *mob); struct vmw_mob *mob);
extern void vmw_mob_destroy(struct vmw_mob *mob); extern void vmw_mob_destroy(struct vmw_mob *mob);
......
...@@ -41,13 +41,13 @@ ...@@ -41,13 +41,13 @@
* *
* @num_pages Number of pages that make up the page table. * @num_pages Number of pages that make up the page table.
* @pt_level The indirection level of the page table. 0-2. * @pt_level The indirection level of the page table. 0-2.
* @pt_root_page Pointer to the level 0 page of the page table. * @pt_root_page DMA address of the level 0 page of the page table.
*/ */
struct vmw_mob { struct vmw_mob {
struct ttm_buffer_object *pt_bo; struct ttm_buffer_object *pt_bo;
unsigned long num_pages; unsigned long num_pages;
unsigned pt_level; unsigned pt_level;
struct page *pt_root_page; dma_addr_t pt_root_page;
uint32_t id; uint32_t id;
}; };
...@@ -65,7 +65,7 @@ struct vmw_otable { ...@@ -65,7 +65,7 @@ struct vmw_otable {
static int vmw_mob_pt_populate(struct vmw_private *dev_priv, static int vmw_mob_pt_populate(struct vmw_private *dev_priv,
struct vmw_mob *mob); struct vmw_mob *mob);
static void vmw_mob_pt_setup(struct vmw_mob *mob, static void vmw_mob_pt_setup(struct vmw_mob *mob,
struct page **data_pages, struct vmw_piter data_iter,
unsigned long num_data_pages); unsigned long num_data_pages);
/* /*
...@@ -89,13 +89,17 @@ static int vmw_setup_otable_base(struct vmw_private *dev_priv, ...@@ -89,13 +89,17 @@ static int vmw_setup_otable_base(struct vmw_private *dev_priv,
SVGA3dCmdHeader header; SVGA3dCmdHeader header;
SVGA3dCmdSetOTableBase body; SVGA3dCmdSetOTableBase body;
} *cmd; } *cmd;
struct page **pages = dev_priv->otable_bo->ttm->pages +
(offset >> PAGE_SHIFT);
struct vmw_mob *mob; struct vmw_mob *mob;
const struct vmw_sg_table *vsgt;
struct vmw_piter iter;
int ret; int ret;
BUG_ON(otable->page_table != NULL); BUG_ON(otable->page_table != NULL);
vsgt = vmw_bo_sg_table(dev_priv->otable_bo);
vmw_piter_start(&iter, vsgt, offset >> PAGE_SHIFT);
WARN_ON(!vmw_piter_next(&iter));
mob = vmw_mob_create(otable->size >> PAGE_SHIFT); mob = vmw_mob_create(otable->size >> PAGE_SHIFT);
if (unlikely(mob == NULL)) { if (unlikely(mob == NULL)) {
DRM_ERROR("Failed creating OTable page table.\n"); DRM_ERROR("Failed creating OTable page table.\n");
...@@ -103,15 +107,17 @@ static int vmw_setup_otable_base(struct vmw_private *dev_priv, ...@@ -103,15 +107,17 @@ static int vmw_setup_otable_base(struct vmw_private *dev_priv,
} }
if (otable->size <= PAGE_SIZE) { if (otable->size <= PAGE_SIZE) {
mob->pt_level = 0; mob->pt_level = SVGA3D_MOBFMT_PTDEPTH_0;
mob->pt_root_page = pages[0]; mob->pt_root_page = vmw_piter_dma_addr(&iter);
} else if (vsgt->num_regions == 1) {
mob->pt_level = SVGA3D_MOBFMT_RANGE;
mob->pt_root_page = vmw_piter_dma_addr(&iter);
} else { } else {
ret = vmw_mob_pt_populate(dev_priv, mob); ret = vmw_mob_pt_populate(dev_priv, mob);
if (unlikely(ret != 0)) if (unlikely(ret != 0))
goto out_no_populate; goto out_no_populate;
vmw_mob_pt_setup(mob, pages, vmw_mob_pt_setup(mob, iter, otable->size >> PAGE_SHIFT);
otable->size >> PAGE_SHIFT);
} }
cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd)); cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
...@@ -124,7 +130,7 @@ static int vmw_setup_otable_base(struct vmw_private *dev_priv, ...@@ -124,7 +130,7 @@ static int vmw_setup_otable_base(struct vmw_private *dev_priv,
cmd->header.id = SVGA_3D_CMD_SET_OTABLE_BASE; cmd->header.id = SVGA_3D_CMD_SET_OTABLE_BASE;
cmd->header.size = sizeof(cmd->body); cmd->header.size = sizeof(cmd->body);
cmd->body.type = type; cmd->body.type = type;
cmd->body.baseAddress = page_to_pfn(mob->pt_root_page); cmd->body.baseAddress = mob->pt_root_page >> PAGE_SHIFT;
cmd->body.sizeInBytes = otable->size; cmd->body.sizeInBytes = otable->size;
cmd->body.validSizeInBytes = 0; cmd->body.validSizeInBytes = 0;
cmd->body.ptDepth = mob->pt_level; cmd->body.ptDepth = mob->pt_level;
...@@ -244,9 +250,13 @@ int vmw_otables_setup(struct vmw_private *dev_priv) ...@@ -244,9 +250,13 @@ int vmw_otables_setup(struct vmw_private *dev_priv)
ret = ttm_bo_reserve(dev_priv->otable_bo, false, true, false, false); ret = ttm_bo_reserve(dev_priv->otable_bo, false, true, false, false);
BUG_ON(ret != 0); BUG_ON(ret != 0);
ret = vmw_bo_driver.ttm_tt_populate(dev_priv->otable_bo->ttm); ret = vmw_bo_driver.ttm_tt_populate(dev_priv->otable_bo->ttm);
ttm_bo_unreserve(dev_priv->otable_bo);
if (unlikely(ret != 0)) if (unlikely(ret != 0))
goto out_no_setup; goto out_unreserve;
ret = vmw_bo_map_dma(dev_priv->otable_bo);
if (unlikely(ret != 0))
goto out_unreserve;
ttm_bo_unreserve(dev_priv->otable_bo);
offset = 0; offset = 0;
for (i = 0; i < SVGA_OTABLE_COUNT; ++i) { for (i = 0; i < SVGA_OTABLE_COUNT; ++i) {
...@@ -260,6 +270,8 @@ int vmw_otables_setup(struct vmw_private *dev_priv) ...@@ -260,6 +270,8 @@ int vmw_otables_setup(struct vmw_private *dev_priv)
dev_priv->otables = otables; dev_priv->otables = otables;
return 0; return 0;
out_unreserve:
ttm_bo_unreserve(dev_priv->otable_bo);
out_no_setup: out_no_setup:
for (i = 0; i < SVGA_OTABLE_COUNT; ++i) for (i = 0; i < SVGA_OTABLE_COUNT; ++i)
vmw_takedown_otable_base(dev_priv, i, &otables[i]); vmw_takedown_otable_base(dev_priv, i, &otables[i]);
...@@ -365,9 +377,19 @@ static int vmw_mob_pt_populate(struct vmw_private *dev_priv, ...@@ -365,9 +377,19 @@ static int vmw_mob_pt_populate(struct vmw_private *dev_priv,
BUG_ON(ret != 0); BUG_ON(ret != 0);
ret = vmw_bo_driver.ttm_tt_populate(mob->pt_bo->ttm); ret = vmw_bo_driver.ttm_tt_populate(mob->pt_bo->ttm);
ttm_bo_unreserve(mob->pt_bo);
if (unlikely(ret != 0)) if (unlikely(ret != 0))
ttm_bo_unref(&mob->pt_bo); goto out_unreserve;
ret = vmw_bo_map_dma(mob->pt_bo);
if (unlikely(ret != 0))
goto out_unreserve;
ttm_bo_unreserve(mob->pt_bo);
return 0;
out_unreserve:
ttm_bo_unreserve(mob->pt_bo);
ttm_bo_unref(&mob->pt_bo);
return ret; return ret;
} }
...@@ -376,7 +398,7 @@ static int vmw_mob_pt_populate(struct vmw_private *dev_priv, ...@@ -376,7 +398,7 @@ static int vmw_mob_pt_populate(struct vmw_private *dev_priv,
/* /*
* vmw_mob_build_pt - Build a pagetable * vmw_mob_build_pt - Build a pagetable
* *
* @data_pages: Array of page pointers to the underlying buffer * @data_addr: Array of DMA addresses to the underlying buffer
* object's data pages. * object's data pages.
* @num_data_pages: Number of buffer object data pages. * @num_data_pages: Number of buffer object data pages.
* @pt_pages: Array of page pointers to the page table pages. * @pt_pages: Array of page pointers to the page table pages.
...@@ -384,26 +406,31 @@ static int vmw_mob_pt_populate(struct vmw_private *dev_priv, ...@@ -384,26 +406,31 @@ static int vmw_mob_pt_populate(struct vmw_private *dev_priv,
* Returns the number of page table pages actually used. * Returns the number of page table pages actually used.
* Uses atomic kmaps of highmem pages to avoid TLB thrashing. * Uses atomic kmaps of highmem pages to avoid TLB thrashing.
*/ */
static unsigned long vmw_mob_build_pt(struct page **data_pages, static unsigned long vmw_mob_build_pt(struct vmw_piter *data_iter,
unsigned long num_data_pages, unsigned long num_data_pages,
struct page **pt_pages) struct vmw_piter *pt_iter)
{ {
unsigned long pt_size = num_data_pages * VMW_PPN_SIZE; unsigned long pt_size = num_data_pages * VMW_PPN_SIZE;
unsigned long num_pt_pages = DIV_ROUND_UP(pt_size, PAGE_SIZE); unsigned long num_pt_pages = DIV_ROUND_UP(pt_size, PAGE_SIZE);
unsigned long pt_page, data_page; unsigned long pt_page;
uint32_t *addr, *save_addr; uint32_t *addr, *save_addr;
unsigned long i; unsigned long i;
struct page *page;
data_page = 0;
for (pt_page = 0; pt_page < num_pt_pages; ++pt_page) { for (pt_page = 0; pt_page < num_pt_pages; ++pt_page) {
save_addr = addr = kmap_atomic(pt_pages[pt_page]); page = vmw_piter_page(pt_iter);
save_addr = addr = kmap_atomic(page);
for (i = 0; i < PAGE_SIZE / VMW_PPN_SIZE; ++i) { for (i = 0; i < PAGE_SIZE / VMW_PPN_SIZE; ++i) {
*addr++ = page_to_pfn(data_pages[data_page++]); u32 tmp = vmw_piter_dma_addr(data_iter) >> PAGE_SHIFT;
if (unlikely(data_page >= num_data_pages)) *addr++ = tmp;
if (unlikely(--num_data_pages == 0))
break; break;
WARN_ON(!vmw_piter_next(data_iter));
} }
kunmap_atomic(save_addr); kunmap_atomic(save_addr);
vmw_piter_next(pt_iter);
} }
return num_pt_pages; return num_pt_pages;
...@@ -413,38 +440,41 @@ static unsigned long vmw_mob_build_pt(struct page **data_pages, ...@@ -413,38 +440,41 @@ static unsigned long vmw_mob_build_pt(struct page **data_pages,
* vmw_mob_build_pt - Set up a multilevel mob pagetable * vmw_mob_build_pt - Set up a multilevel mob pagetable
* *
* @mob: Pointer to a mob whose page table needs setting up. * @mob: Pointer to a mob whose page table needs setting up.
* @data_pages Array of page pointers to the buffer object's data * @data_addr Array of DMA addresses to the buffer object's data
* pages. * pages.
* @num_data_pages: Number of buffer object data pages. * @num_data_pages: Number of buffer object data pages.
* *
* Uses tail recursion to set up a multilevel mob page table. * Uses tail recursion to set up a multilevel mob page table.
*/ */
static void vmw_mob_pt_setup(struct vmw_mob *mob, static void vmw_mob_pt_setup(struct vmw_mob *mob,
struct page **data_pages, struct vmw_piter data_iter,
unsigned long num_data_pages) unsigned long num_data_pages)
{ {
struct page **pt_pages;
unsigned long num_pt_pages = 0; unsigned long num_pt_pages = 0;
struct ttm_buffer_object *bo = mob->pt_bo; struct ttm_buffer_object *bo = mob->pt_bo;
struct vmw_piter save_pt_iter;
struct vmw_piter pt_iter;
const struct vmw_sg_table *vsgt;
int ret; int ret;
ret = ttm_bo_reserve(bo, false, true, false, 0); ret = ttm_bo_reserve(bo, false, true, false, 0);
BUG_ON(ret != 0); BUG_ON(ret != 0);
pt_pages = bo->ttm->pages; vsgt = vmw_bo_sg_table(bo);
vmw_piter_start(&pt_iter, vsgt, 0);
BUG_ON(!vmw_piter_next(&pt_iter));
mob->pt_level = 0; mob->pt_level = 0;
while (likely(num_data_pages > 1)) { while (likely(num_data_pages > 1)) {
++mob->pt_level; ++mob->pt_level;
BUG_ON(mob->pt_level > 2); BUG_ON(mob->pt_level > 2);
save_pt_iter = pt_iter;
pt_pages += num_pt_pages; num_pt_pages = vmw_mob_build_pt(&data_iter, num_data_pages,
num_pt_pages = vmw_mob_build_pt(data_pages, num_data_pages, &pt_iter);
pt_pages); data_iter = save_pt_iter;
data_pages = pt_pages;
num_data_pages = num_pt_pages; num_data_pages = num_pt_pages;
} }
mob->pt_root_page = *pt_pages; mob->pt_root_page = vmw_piter_dma_addr(&save_pt_iter);
ttm_bo_unreserve(bo); ttm_bo_unreserve(bo);
} }
...@@ -506,7 +536,7 @@ void vmw_mob_unbind(struct vmw_private *dev_priv, ...@@ -506,7 +536,7 @@ void vmw_mob_unbind(struct vmw_private *dev_priv,
* *
* @dev_priv: Pointer to a device private. * @dev_priv: Pointer to a device private.
* @mob: Pointer to the mob we're making visible. * @mob: Pointer to the mob we're making visible.
* @data_pages: Array of pointers to the data pages of the underlying * @data_addr: Array of DMA addresses to the data pages of the underlying
* buffer object. * buffer object.
* @num_data_pages: Number of data pages of the underlying buffer * @num_data_pages: Number of data pages of the underlying buffer
* object. * object.
...@@ -517,27 +547,35 @@ void vmw_mob_unbind(struct vmw_private *dev_priv, ...@@ -517,27 +547,35 @@ void vmw_mob_unbind(struct vmw_private *dev_priv,
*/ */
int vmw_mob_bind(struct vmw_private *dev_priv, int vmw_mob_bind(struct vmw_private *dev_priv,
struct vmw_mob *mob, struct vmw_mob *mob,
struct page **data_pages, const struct vmw_sg_table *vsgt,
unsigned long num_data_pages, unsigned long num_data_pages,
int32_t mob_id) int32_t mob_id)
{ {
int ret; int ret;
bool pt_set_up = false; bool pt_set_up = false;
struct vmw_piter data_iter;
struct { struct {
SVGA3dCmdHeader header; SVGA3dCmdHeader header;
SVGA3dCmdDefineGBMob body; SVGA3dCmdDefineGBMob body;
} *cmd; } *cmd;
mob->id = mob_id; mob->id = mob_id;
vmw_piter_start(&data_iter, vsgt, 0);
if (unlikely(!vmw_piter_next(&data_iter)))
return 0;
if (likely(num_data_pages == 1)) { if (likely(num_data_pages == 1)) {
mob->pt_level = 0; mob->pt_level = SVGA3D_MOBFMT_PTDEPTH_0;
mob->pt_root_page = *data_pages; mob->pt_root_page = vmw_piter_dma_addr(&data_iter);
} else if (vsgt->num_regions == 1) {
mob->pt_level = SVGA3D_MOBFMT_RANGE;
mob->pt_root_page = vmw_piter_dma_addr(&data_iter);
} else if (unlikely(mob->pt_bo == NULL)) { } else if (unlikely(mob->pt_bo == NULL)) {
ret = vmw_mob_pt_populate(dev_priv, mob); ret = vmw_mob_pt_populate(dev_priv, mob);
if (unlikely(ret != 0)) if (unlikely(ret != 0))
return ret; return ret;
vmw_mob_pt_setup(mob, data_pages, num_data_pages); vmw_mob_pt_setup(mob, data_iter, num_data_pages);
pt_set_up = true; pt_set_up = true;
} }
...@@ -554,7 +592,7 @@ int vmw_mob_bind(struct vmw_private *dev_priv, ...@@ -554,7 +592,7 @@ int vmw_mob_bind(struct vmw_private *dev_priv,
cmd->header.size = sizeof(cmd->body); cmd->header.size = sizeof(cmd->body);
cmd->body.mobid = mob_id; cmd->body.mobid = mob_id;
cmd->body.ptDepth = mob->pt_level; cmd->body.ptDepth = mob->pt_level;
cmd->body.base = page_to_pfn(mob->pt_root_page); cmd->body.base = mob->pt_root_page >> PAGE_SHIFT;
cmd->body.sizeInBytes = num_data_pages * PAGE_SIZE; cmd->body.sizeInBytes = num_data_pages * PAGE_SIZE;
vmw_fifo_commit(dev_priv, sizeof(*cmd)); vmw_fifo_commit(dev_priv, sizeof(*cmd));
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册