diff options
Diffstat (limited to 'drivers/gpu/drm/gma500')
-rw-r--r-- | drivers/gpu/drm/gma500/framebuffer.c | 52 | ||||
-rw-r--r-- | drivers/gpu/drm/gma500/gem.c | 234 | ||||
-rw-r--r-- | drivers/gpu/drm/gma500/gem.h | 28 | ||||
-rw-r--r-- | drivers/gpu/drm/gma500/gma_display.c | 51 | ||||
-rw-r--r-- | drivers/gpu/drm/gma500/gtt.c | 326 | ||||
-rw-r--r-- | drivers/gpu/drm/gma500/gtt.h | 29 | ||||
-rw-r--r-- | drivers/gpu/drm/gma500/oaktrail_crtc.c | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/gma500/psb_drv.c | 12 | ||||
-rw-r--r-- | drivers/gpu/drm/gma500/psb_intel_display.c | 17 | ||||
-rw-r--r-- | drivers/gpu/drm/gma500/psb_intel_drv.h | 2 |
10 files changed, 337 insertions, 417 deletions
diff --git a/drivers/gpu/drm/gma500/framebuffer.c b/drivers/gpu/drm/gma500/framebuffer.c index 321e416489a9..45df9de22007 100644 --- a/drivers/gpu/drm/gma500/framebuffer.c +++ b/drivers/gpu/drm/gma500/framebuffer.c @@ -25,7 +25,6 @@ #include "framebuffer.h" #include "gem.h" -#include "gtt.h" #include "psb_drv.h" #include "psb_intel_drv.h" #include "psb_intel_reg.h" @@ -82,14 +81,13 @@ static vm_fault_t psbfb_vm_fault(struct vm_fault *vmf) struct drm_framebuffer *fb = vma->vm_private_data; struct drm_device *dev = fb->dev; struct drm_psb_private *dev_priv = to_drm_psb_private(dev); - struct gtt_range *gtt = to_gtt_range(fb->obj[0]); + struct psb_gem_object *pobj = to_psb_gem_object(fb->obj[0]); int page_num; int i; unsigned long address; vm_fault_t ret = VM_FAULT_SIGBUS; unsigned long pfn; - unsigned long phys_addr = (unsigned long)dev_priv->stolen_base + - gtt->offset; + unsigned long phys_addr = (unsigned long)dev_priv->stolen_base + pobj->offset; page_num = vma_pages(vma); address = vmf->address - (vmf->pgoff << PAGE_SHIFT); @@ -226,31 +224,6 @@ static struct drm_framebuffer *psb_framebuffer_create } /** - * psbfb_alloc - allocate frame buffer memory - * @dev: the DRM device - * @aligned_size: space needed - * - * Allocate the frame buffer. In the usual case we get a GTT range that - * is stolen memory backed and life is simple. If there isn't sufficient - * we fail as we don't have the virtual mapping space to really vmap it - * and the kernel console code can't handle non linear framebuffers. - * - * Re-address this as and if the framebuffer layer grows this ability. - */ -static struct gtt_range *psbfb_alloc(struct drm_device *dev, int aligned_size) -{ - struct gtt_range *backing; - /* Begin by trying to use stolen memory backing */ - backing = psb_gtt_alloc_range(dev, aligned_size, "fb", 1, PAGE_SIZE); - if (backing) { - backing->gem.funcs = &psb_gem_object_funcs; - drm_gem_private_object_init(dev, &backing->gem, aligned_size); - return backing; - } - return NULL; -} - -/** * psbfb_create - create a framebuffer * @fb_helper: the framebuffer helper * @sizes: specification of the layout @@ -268,7 +241,8 @@ static int psbfb_create(struct drm_fb_helper *fb_helper, struct drm_mode_fb_cmd2 mode_cmd; int size; int ret; - struct gtt_range *backing; + struct psb_gem_object *backing; + struct drm_gem_object *obj; u32 bpp, depth; mode_cmd.width = sizes->surface_width; @@ -286,24 +260,25 @@ static int psbfb_create(struct drm_fb_helper *fb_helper, size = ALIGN(size, PAGE_SIZE); /* Allocate the framebuffer in the GTT with stolen page backing */ - backing = psbfb_alloc(dev, size); - if (backing == NULL) - return -ENOMEM; + backing = psb_gem_create(dev, size, "fb", true, PAGE_SIZE); + if (IS_ERR(backing)) + return PTR_ERR(backing); + obj = &backing->base; memset(dev_priv->vram_addr + backing->offset, 0, size); info = drm_fb_helper_alloc_fbi(fb_helper); if (IS_ERR(info)) { ret = PTR_ERR(info); - goto out; + goto err_drm_gem_object_put; } mode_cmd.pixel_format = drm_mode_legacy_fb_format(bpp, depth); - fb = psb_framebuffer_create(dev, &mode_cmd, &backing->gem); + fb = psb_framebuffer_create(dev, &mode_cmd, obj); if (IS_ERR(fb)) { ret = PTR_ERR(fb); - goto out; + goto err_drm_gem_object_put; } fb_helper->fb = fb; @@ -334,8 +309,9 @@ static int psbfb_create(struct drm_fb_helper *fb_helper, dev_dbg(dev->dev, "allocated %dx%d fb\n", fb->width, fb->height); return 0; -out: - psb_gtt_free_range(dev, backing); + +err_drm_gem_object_put: + drm_gem_object_put(obj); return ret; } diff --git a/drivers/gpu/drm/gma500/gem.c b/drivers/gpu/drm/gma500/gem.c index 5ae54c9d2819..8d65af80bb08 100644 --- a/drivers/gpu/drm/gma500/gem.c +++ b/drivers/gpu/drm/gma500/gem.c @@ -13,24 +13,105 @@ #include <linux/pagemap.h> +#include <asm/set_memory.h> + #include <drm/drm.h> #include <drm/drm_vma_manager.h> #include "gem.h" #include "psb_drv.h" +int psb_gem_pin(struct psb_gem_object *pobj) +{ + struct drm_gem_object *obj = &pobj->base; + struct drm_device *dev = obj->dev; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + u32 gpu_base = dev_priv->gtt.gatt_start; + struct page **pages; + unsigned int npages; + int ret; + + mutex_lock(&dev_priv->gtt_mutex); + + if (pobj->in_gart || pobj->stolen) + goto out; /* already mapped */ + + pages = drm_gem_get_pages(obj); + if (IS_ERR(pages)) { + ret = PTR_ERR(pages); + goto err_mutex_unlock; + } + + npages = obj->size / PAGE_SIZE; + + set_pages_array_wc(pages, npages); + + psb_gtt_insert_pages(dev_priv, &pobj->resource, pages); + psb_mmu_insert_pages(psb_mmu_get_default_pd(dev_priv->mmu), pages, + (gpu_base + pobj->offset), npages, 0, 0, + PSB_MMU_CACHED_MEMORY); + + pobj->npage = npages; + pobj->pages = pages; + +out: + ++pobj->in_gart; + mutex_unlock(&dev_priv->gtt_mutex); + + return 0; + +err_mutex_unlock: + mutex_unlock(&dev_priv->gtt_mutex); + return ret; +} + +void psb_gem_unpin(struct psb_gem_object *pobj) +{ + struct drm_gem_object *obj = &pobj->base; + struct drm_device *dev = obj->dev; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + u32 gpu_base = dev_priv->gtt.gatt_start; + + mutex_lock(&dev_priv->gtt_mutex); + + WARN_ON(!pobj->in_gart); + + --pobj->in_gart; + + if (pobj->in_gart || pobj->stolen) + goto out; + + psb_mmu_remove_pages(psb_mmu_get_default_pd(dev_priv->mmu), + (gpu_base + pobj->offset), pobj->npage, 0, 0); + psb_gtt_remove_pages(dev_priv, &pobj->resource); + + /* Reset caching flags */ + set_pages_array_wb(pobj->pages, pobj->npage); + + drm_gem_put_pages(obj, pobj->pages, true, false); + pobj->pages = NULL; + pobj->npage = 0; + +out: + mutex_unlock(&dev_priv->gtt_mutex); +} + static vm_fault_t psb_gem_fault(struct vm_fault *vmf); static void psb_gem_free_object(struct drm_gem_object *obj) { - struct gtt_range *gtt = container_of(obj, struct gtt_range, gem); + struct psb_gem_object *pobj = to_psb_gem_object(obj); - /* Remove the list map if one is present */ - drm_gem_free_mmap_offset(obj); drm_gem_object_release(obj); - /* This must occur last as it frees up the memory of the GEM object */ - psb_gtt_free_range(obj->dev, gtt); + /* Undo the mmap pin if we are destroying the object */ + if (pobj->mmapping) + psb_gem_unpin(pobj); + + WARN_ON(pobj->in_gart && !pobj->stolen); + + release_resource(&pobj->resource); + kfree(pobj); } static const struct vm_operations_struct psb_gem_vm_ops = { @@ -39,63 +120,60 @@ static const struct vm_operations_struct psb_gem_vm_ops = { .close = drm_gem_vm_close, }; -const struct drm_gem_object_funcs psb_gem_object_funcs = { +static const struct drm_gem_object_funcs psb_gem_object_funcs = { .free = psb_gem_free_object, .vm_ops = &psb_gem_vm_ops, }; -/** - * psb_gem_create - create a mappable object - * @file: the DRM file of the client - * @dev: our device - * @size: the size requested - * @handlep: returned handle (opaque number) - * @stolen: unused - * @align: unused - * - * Create a GEM object, fill in the boilerplate and attach a handle to - * it so that userspace can speak about it. This does the core work - * for the various methods that do/will create GEM objects for things - */ -int psb_gem_create(struct drm_file *file, struct drm_device *dev, u64 size, - u32 *handlep, int stolen, u32 align) +struct psb_gem_object * +psb_gem_create(struct drm_device *dev, u64 size, const char *name, bool stolen, u32 align) { - struct gtt_range *r; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + struct psb_gem_object *pobj; + struct drm_gem_object *obj; int ret; - u32 handle; size = roundup(size, PAGE_SIZE); - /* Allocate our object - for now a direct gtt range which is not - stolen memory backed */ - r = psb_gtt_alloc_range(dev, size, "gem", 0, PAGE_SIZE); - if (r == NULL) { - dev_err(dev->dev, "no memory for %lld byte GEM object\n", size); - return -ENOSPC; - } - r->gem.funcs = &psb_gem_object_funcs; - /* Initialize the extra goodies GEM needs to do all the hard work */ - if (drm_gem_object_init(dev, &r->gem, size) != 0) { - psb_gtt_free_range(dev, r); - /* GEM doesn't give an error code so use -ENOMEM */ - dev_err(dev->dev, "GEM init failed for %lld\n", size); - return -ENOMEM; + pobj = kzalloc(sizeof(*pobj), GFP_KERNEL); + if (!pobj) + return ERR_PTR(-ENOMEM); + obj = &pobj->base; + + /* GTT resource */ + + ret = psb_gtt_allocate_resource(dev_priv, &pobj->resource, name, size, align, stolen, + &pobj->offset); + if (ret) + goto err_kfree; + + if (stolen) { + pobj->stolen = true; + pobj->in_gart = 1; } - /* Limit the object to 32bit mappings */ - mapping_set_gfp_mask(r->gem.filp->f_mapping, GFP_KERNEL | __GFP_DMA32); - /* Give the object a handle so we can carry it more easily */ - ret = drm_gem_handle_create(file, &r->gem, &handle); - if (ret) { - dev_err(dev->dev, "GEM handle failed for %p, %lld\n", - &r->gem, size); - drm_gem_object_release(&r->gem); - psb_gtt_free_range(dev, r); - return ret; + + /* GEM object */ + + obj->funcs = &psb_gem_object_funcs; + + if (stolen) { + drm_gem_private_object_init(dev, obj, size); + } else { + ret = drm_gem_object_init(dev, obj, size); + if (ret) + goto err_release_resource; + + /* Limit the object to 32-bit mappings */ + mapping_set_gfp_mask(obj->filp->f_mapping, GFP_KERNEL | __GFP_DMA32); } - /* We have the initial and handle reference but need only one now */ - drm_gem_object_put(&r->gem); - *handlep = handle; - return 0; + + return pobj; + +err_release_resource: + release_resource(&pobj->resource); +err_kfree: + kfree(pobj); + return ERR_PTR(ret); } /** @@ -111,10 +189,40 @@ int psb_gem_create(struct drm_file *file, struct drm_device *dev, u64 size, int psb_gem_dumb_create(struct drm_file *file, struct drm_device *dev, struct drm_mode_create_dumb *args) { - args->pitch = ALIGN(args->width * ((args->bpp + 7) / 8), 64); - args->size = args->pitch * args->height; - return psb_gem_create(file, dev, args->size, &args->handle, 0, - PAGE_SIZE); + size_t pitch, size; + struct psb_gem_object *pobj; + struct drm_gem_object *obj; + u32 handle; + int ret; + + pitch = args->width * DIV_ROUND_UP(args->bpp, 8); + pitch = ALIGN(pitch, 64); + + size = pitch * args->height; + size = roundup(size, PAGE_SIZE); + if (!size) + return -EINVAL; + + pobj = psb_gem_create(dev, size, "gem", false, PAGE_SIZE); + if (IS_ERR(pobj)) + return PTR_ERR(pobj); + obj = &pobj->base; + + ret = drm_gem_handle_create(file, obj, &handle); + if (ret) + goto err_drm_gem_object_put; + + drm_gem_object_put(obj); + + args->pitch = pitch; + args->size = size; + args->handle = handle; + + return 0; + +err_drm_gem_object_put: + drm_gem_object_put(obj); + return ret; } /** @@ -137,7 +245,7 @@ static vm_fault_t psb_gem_fault(struct vm_fault *vmf) { struct vm_area_struct *vma = vmf->vma; struct drm_gem_object *obj; - struct gtt_range *r; + struct psb_gem_object *pobj; int err; vm_fault_t ret; unsigned long pfn; @@ -149,7 +257,7 @@ static vm_fault_t psb_gem_fault(struct vm_fault *vmf) dev = obj->dev; dev_priv = to_drm_psb_private(dev); - r = container_of(obj, struct gtt_range, gem); /* Get the gtt range */ + pobj = to_psb_gem_object(obj); /* Make sure we don't parallel update on a fault, nor move or remove something from beneath our feet */ @@ -157,14 +265,14 @@ static vm_fault_t psb_gem_fault(struct vm_fault *vmf) /* For now the mmap pins the object and it stays pinned. As things stand that will do us no harm */ - if (r->mmapping == 0) { - err = psb_gtt_pin(r); + if (pobj->mmapping == 0) { + err = psb_gem_pin(pobj); if (err < 0) { dev_err(dev->dev, "gma500: pin failed: %d\n", err); ret = vmf_error(err); goto fail; } - r->mmapping = 1; + pobj->mmapping = 1; } /* Page relative to the VMA start - we must calculate this ourselves @@ -172,10 +280,10 @@ static vm_fault_t psb_gem_fault(struct vm_fault *vmf) page_offset = (vmf->address - vma->vm_start) >> PAGE_SHIFT; /* CPU view of the page, don't go via the GART for CPU writes */ - if (r->stolen) - pfn = (dev_priv->stolen_base + r->offset) >> PAGE_SHIFT; + if (pobj->stolen) + pfn = (dev_priv->stolen_base + pobj->offset) >> PAGE_SHIFT; else - pfn = page_to_pfn(r->pages[page_offset]); + pfn = page_to_pfn(pobj->pages[page_offset]); ret = vmf_insert_pfn(vma, vmf->address, pfn); fail: mutex_unlock(&dev_priv->mmap_mutex); diff --git a/drivers/gpu/drm/gma500/gem.h b/drivers/gpu/drm/gma500/gem.h index bae6454ead29..79cced40c87f 100644 --- a/drivers/gpu/drm/gma500/gem.h +++ b/drivers/gpu/drm/gma500/gem.h @@ -8,11 +8,33 @@ #ifndef _GEM_H #define _GEM_H +#include <linux/kernel.h> + +#include <drm/drm_gem.h> + struct drm_device; -extern const struct drm_gem_object_funcs psb_gem_object_funcs; +struct psb_gem_object { + struct drm_gem_object base; + + struct resource resource; /* GTT resource for our allocation */ + u32 offset; /* GTT offset of our object */ + int in_gart; /* Currently in the GART (ref ct) */ + bool stolen; /* Backed from stolen RAM */ + bool mmapping; /* Is mmappable */ + struct page **pages; /* Backing pages if present */ + int npage; /* Number of backing pages */ +}; + +static inline struct psb_gem_object *to_psb_gem_object(struct drm_gem_object *obj) +{ + return container_of(obj, struct psb_gem_object, base); +} + +struct psb_gem_object * +psb_gem_create(struct drm_device *dev, u64 size, const char *name, bool stolen, u32 align); -extern int psb_gem_create(struct drm_file *file, struct drm_device *dev, - u64 size, u32 *handlep, int stolen, u32 align); +int psb_gem_pin(struct psb_gem_object *pobj); +void psb_gem_unpin(struct psb_gem_object *pobj); #endif diff --git a/drivers/gpu/drm/gma500/gma_display.c b/drivers/gpu/drm/gma500/gma_display.c index cbcecbaa041b..99da3118131a 100644 --- a/drivers/gpu/drm/gma500/gma_display.c +++ b/drivers/gpu/drm/gma500/gma_display.c @@ -15,6 +15,7 @@ #include <drm/drm_vblank.h> #include "framebuffer.h" +#include "gem.h" #include "gma_display.h" #include "psb_drv.h" #include "psb_intel_drv.h" @@ -54,7 +55,7 @@ int gma_pipe_set_base(struct drm_crtc *crtc, int x, int y, struct drm_psb_private *dev_priv = to_drm_psb_private(dev); struct gma_crtc *gma_crtc = to_gma_crtc(crtc); struct drm_framebuffer *fb = crtc->primary->fb; - struct gtt_range *gtt; + struct psb_gem_object *pobj; int pipe = gma_crtc->pipe; const struct psb_offset *map = &dev_priv->regmap[pipe]; unsigned long start, offset; @@ -70,14 +71,14 @@ int gma_pipe_set_base(struct drm_crtc *crtc, int x, int y, goto gma_pipe_cleaner; } - gtt = to_gtt_range(fb->obj[0]); + pobj = to_psb_gem_object(fb->obj[0]); /* We are displaying this buffer, make sure it is actually loaded into the GTT */ - ret = psb_gtt_pin(gtt); + ret = psb_gem_pin(pobj); if (ret < 0) goto gma_pipe_set_base_exit; - start = gtt->offset; + start = pobj->offset; offset = y * fb->pitches[0] + x * fb->format->cpp[0]; REG_WRITE(map->stride, fb->pitches[0]); @@ -125,7 +126,7 @@ int gma_pipe_set_base(struct drm_crtc *crtc, int x, int y, gma_pipe_cleaner: /* If there was a previous display we can now unpin it */ if (old_fb) - psb_gtt_unpin(to_gtt_range(old_fb->obj[0])); + psb_gem_unpin(to_psb_gem_object(old_fb->obj[0])); gma_pipe_set_base_exit: gma_power_end(dev); @@ -331,8 +332,8 @@ int gma_crtc_cursor_set(struct drm_crtc *crtc, uint32_t base = (pipe == 0) ? CURABASE : CURBBASE; uint32_t temp; size_t addr = 0; - struct gtt_range *gt; - struct gtt_range *cursor_gt = gma_crtc->cursor_gt; + struct psb_gem_object *pobj; + struct psb_gem_object *cursor_pobj = gma_crtc->cursor_pobj; struct drm_gem_object *obj; void *tmp_dst, *tmp_src; int ret = 0, i, cursor_pages; @@ -348,9 +349,8 @@ int gma_crtc_cursor_set(struct drm_crtc *crtc, /* Unpin the old GEM object */ if (gma_crtc->cursor_obj) { - gt = container_of(gma_crtc->cursor_obj, - struct gtt_range, gem); - psb_gtt_unpin(gt); + pobj = to_psb_gem_object(gma_crtc->cursor_obj); + psb_gem_unpin(pobj); drm_gem_object_put(gma_crtc->cursor_obj); gma_crtc->cursor_obj = NULL; } @@ -375,40 +375,40 @@ int gma_crtc_cursor_set(struct drm_crtc *crtc, goto unref_cursor; } - gt = container_of(obj, struct gtt_range, gem); + pobj = to_psb_gem_object(obj); /* Pin the memory into the GTT */ - ret = psb_gtt_pin(gt); + ret = psb_gem_pin(pobj); if (ret) { dev_err(dev->dev, "Can not pin down handle 0x%x\n", handle); goto unref_cursor; } if (dev_priv->ops->cursor_needs_phys) { - if (cursor_gt == NULL) { + if (!cursor_pobj) { dev_err(dev->dev, "No hardware cursor mem available"); ret = -ENOMEM; goto unref_cursor; } /* Prevent overflow */ - if (gt->npage > 4) + if (pobj->npage > 4) cursor_pages = 4; else - cursor_pages = gt->npage; + cursor_pages = pobj->npage; /* Copy the cursor to cursor mem */ - tmp_dst = dev_priv->vram_addr + cursor_gt->offset; + tmp_dst = dev_priv->vram_addr + cursor_pobj->offset; for (i = 0; i < cursor_pages; i++) { - tmp_src = kmap(gt->pages[i]); + tmp_src = kmap(pobj->pages[i]); memcpy(tmp_dst, tmp_src, PAGE_SIZE); - kunmap(gt->pages[i]); + kunmap(pobj->pages[i]); tmp_dst += PAGE_SIZE; } addr = gma_crtc->cursor_addr; } else { - addr = gt->offset; + addr = pobj->offset; gma_crtc->cursor_addr = addr; } @@ -425,8 +425,8 @@ int gma_crtc_cursor_set(struct drm_crtc *crtc, /* unpin the old bo */ if (gma_crtc->cursor_obj) { - gt = container_of(gma_crtc->cursor_obj, struct gtt_range, gem); - psb_gtt_unpin(gt); + pobj = to_psb_gem_object(gma_crtc->cursor_obj); + psb_gem_unpin(pobj); drm_gem_object_put(gma_crtc->cursor_obj); } @@ -483,14 +483,14 @@ void gma_crtc_commit(struct drm_crtc *crtc) void gma_crtc_disable(struct drm_crtc *crtc) { - struct gtt_range *gt; + struct psb_gem_object *pobj; const struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF); if (crtc->primary->fb) { - gt = to_gtt_range(crtc->primary->fb->obj[0]); - psb_gtt_unpin(gt); + pobj = to_psb_gem_object(crtc->primary->fb->obj[0]); + psb_gem_unpin(pobj); } } @@ -498,6 +498,9 @@ void gma_crtc_destroy(struct drm_crtc *crtc) { struct gma_crtc *gma_crtc = to_gma_crtc(crtc); + if (gma_crtc->cursor_pobj) + drm_gem_object_put(&gma_crtc->cursor_pobj->base); + kfree(gma_crtc->crtc_state); drm_crtc_cleanup(crtc); kfree(gma_crtc); diff --git a/drivers/gpu/drm/gma500/gtt.c b/drivers/gpu/drm/gma500/gtt.c index 55a2a6919533..309ffe921bfd 100644 --- a/drivers/gpu/drm/gma500/gtt.c +++ b/drivers/gpu/drm/gma500/gtt.c @@ -7,10 +7,7 @@ * Alan Cox <alan@linux.intel.com> */ -#include <linux/shmem_fs.h> - -#include <asm/set_memory.h> - +#include "gem.h" /* TODO: for struct psb_gem_object, see psb_gtt_restore() */ #include "psb_drv.h" @@ -18,6 +15,33 @@ * GTT resource allocator - manage page mappings in GTT space */ +int psb_gtt_allocate_resource(struct drm_psb_private *pdev, struct resource *res, + const char *name, resource_size_t size, resource_size_t align, + bool stolen, u32 *offset) +{ + struct resource *root = pdev->gtt_mem; + resource_size_t start, end; + int ret; + + if (stolen) { + /* The start of the GTT is backed by stolen pages. */ + start = root->start; + end = root->start + pdev->gtt.stolen_size - 1; + } else { + /* The rest is backed by system pages. */ + start = root->start + pdev->gtt.stolen_size; + end = root->end; + } + + res->name = name; + ret = allocate_resource(root, res, size, start, end, align, NULL, NULL); + if (ret) + return ret; + *offset = res->start - root->start; + + return 0; +} + /** * psb_gtt_mask_pte - generate GTT pte entry * @pfn: page number to encode @@ -43,281 +67,62 @@ static inline uint32_t psb_gtt_mask_pte(uint32_t pfn, int type) return (pfn << PAGE_SHIFT) | mask; } -/** - * psb_gtt_entry - find the GTT entries for a gtt_range - * @dev: our DRM device - * @r: our GTT range - * - * Given a gtt_range object return the GTT offset of the page table - * entries for this gtt_range - */ -static u32 __iomem *psb_gtt_entry(struct drm_device *dev, struct gtt_range *r) +static u32 __iomem *psb_gtt_entry(struct drm_psb_private *pdev, const struct resource *res) { - struct drm_psb_private *dev_priv = to_drm_psb_private(dev); - unsigned long offset; + unsigned long offset = res->start - pdev->gtt_mem->start; - offset = r->resource.start - dev_priv->gtt_mem->start; - - return dev_priv->gtt_map + (offset >> PAGE_SHIFT); + return pdev->gtt_map + (offset >> PAGE_SHIFT); } -/** - * psb_gtt_insert - put an object into the GTT - * @dev: our DRM device - * @r: our GTT range - * @resume: on resume - * - * Take our preallocated GTT range and insert the GEM object into - * the GTT. This is protected via the gtt mutex which the caller - * must hold. +/* + * Take our preallocated GTT range and insert the GEM object into + * the GTT. This is protected via the gtt mutex which the caller + * must hold. */ -static int psb_gtt_insert(struct drm_device *dev, struct gtt_range *r, - int resume) +void psb_gtt_insert_pages(struct drm_psb_private *pdev, const struct resource *res, + struct page **pages) { + resource_size_t npages, i; u32 __iomem *gtt_slot; u32 pte; - struct page **pages; - int i; - if (r->pages == NULL) { - WARN_ON(1); - return -EINVAL; - } - - WARN_ON(r->stolen); /* refcount these maybe ? */ - - gtt_slot = psb_gtt_entry(dev, r); - pages = r->pages; + /* Write our page entries into the GTT itself */ - if (!resume) { - /* Make sure changes are visible to the GPU */ - set_pages_array_wc(pages, r->npage); - } + npages = resource_size(res) >> PAGE_SHIFT; + gtt_slot = psb_gtt_entry(pdev, res); - /* Write our page entries into the GTT itself */ - for (i = 0; i < r->npage; i++) { - pte = psb_gtt_mask_pte(page_to_pfn(r->pages[i]), - PSB_MMU_CACHED_MEMORY); - iowrite32(pte, gtt_slot++); + for (i = 0; i < npages; ++i, ++gtt_slot) { + pte = psb_gtt_mask_pte(page_to_pfn(pages[i]), PSB_MMU_CACHED_MEMORY); + iowrite32(pte, gtt_slot); } /* Make sure all the entries are set before we return */ ioread32(gtt_slot - 1); - - return 0; } -/** - * psb_gtt_remove - remove an object from the GTT - * @dev: our DRM device - * @r: our GTT range - * - * Remove a preallocated GTT range from the GTT. Overwrite all the - * page table entries with the dummy page. This is protected via the gtt - * mutex which the caller must hold. +/* + * Remove a preallocated GTT range from the GTT. Overwrite all the + * page table entries with the dummy page. This is protected via the gtt + * mutex which the caller must hold. */ -static void psb_gtt_remove(struct drm_device *dev, struct gtt_range *r) +void psb_gtt_remove_pages(struct drm_psb_private *pdev, const struct resource *res) { - struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + resource_size_t npages, i; u32 __iomem *gtt_slot; u32 pte; - int i; - - WARN_ON(r->stolen); - - gtt_slot = psb_gtt_entry(dev, r); - pte = psb_gtt_mask_pte(page_to_pfn(dev_priv->scratch_page), - PSB_MMU_CACHED_MEMORY); - - for (i = 0; i < r->npage; i++) - iowrite32(pte, gtt_slot++); - ioread32(gtt_slot - 1); - set_pages_array_wb(r->pages, r->npage); -} - -/** - * psb_gtt_attach_pages - attach and pin GEM pages - * @gt: the gtt range - * - * Pin and build an in kernel list of the pages that back our GEM object. - * While we hold this the pages cannot be swapped out. This is protected - * via the gtt mutex which the caller must hold. - */ -static int psb_gtt_attach_pages(struct gtt_range *gt) -{ - struct page **pages; - - WARN_ON(gt->pages); - - pages = drm_gem_get_pages(>->gem); - if (IS_ERR(pages)) - return PTR_ERR(pages); - - gt->npage = gt->gem.size / PAGE_SIZE; - gt->pages = pages; - - return 0; -} - -/** - * psb_gtt_detach_pages - attach and pin GEM pages - * @gt: the gtt range - * - * Undo the effect of psb_gtt_attach_pages. At this point the pages - * must have been removed from the GTT as they could now be paged out - * and move bus address. This is protected via the gtt mutex which the - * caller must hold. - */ -static void psb_gtt_detach_pages(struct gtt_range *gt) -{ - drm_gem_put_pages(>->gem, gt->pages, true, false); - gt->pages = NULL; -} -/** - * psb_gtt_pin - pin pages into the GTT - * @gt: range to pin - * - * Pin a set of pages into the GTT. The pins are refcounted so that - * multiple pins need multiple unpins to undo. - * - * Non GEM backed objects treat this as a no-op as they are always GTT - * backed objects. - */ -int psb_gtt_pin(struct gtt_range *gt) -{ - int ret = 0; - struct drm_device *dev = gt->gem.dev; - struct drm_psb_private *dev_priv = to_drm_psb_private(dev); - u32 gpu_base = dev_priv->gtt.gatt_start; + /* Install scratch page for the resource */ - mutex_lock(&dev_priv->gtt_mutex); + pte = psb_gtt_mask_pte(page_to_pfn(pdev->scratch_page), PSB_MMU_CACHED_MEMORY); - if (gt->in_gart == 0 && gt->stolen == 0) { - ret = psb_gtt_attach_pages(gt); - if (ret < 0) - goto out; - ret = psb_gtt_insert(dev, gt, 0); - if (ret < 0) { - psb_gtt_detach_pages(gt); - goto out; - } - psb_mmu_insert_pages(psb_mmu_get_default_pd(dev_priv->mmu), - gt->pages, (gpu_base + gt->offset), - gt->npage, 0, 0, PSB_MMU_CACHED_MEMORY); - } - gt->in_gart++; -out: - mutex_unlock(&dev_priv->gtt_mutex); - return ret; -} + npages = resource_size(res) >> PAGE_SHIFT; + gtt_slot = psb_gtt_entry(pdev, res); -/** - * psb_gtt_unpin - Drop a GTT pin requirement - * @gt: range to pin - * - * Undoes the effect of psb_gtt_pin. On the last drop the GEM object - * will be removed from the GTT which will also drop the page references - * and allow the VM to clean up or page stuff. - * - * Non GEM backed objects treat this as a no-op as they are always GTT - * backed objects. - */ -void psb_gtt_unpin(struct gtt_range *gt) -{ - struct drm_device *dev = gt->gem.dev; - struct drm_psb_private *dev_priv = to_drm_psb_private(dev); - u32 gpu_base = dev_priv->gtt.gatt_start; + for (i = 0; i < npages; ++i, ++gtt_slot) + iowrite32(pte, gtt_slot); - mutex_lock(&dev_priv->gtt_mutex); - - WARN_ON(!gt->in_gart); - - gt->in_gart--; - if (gt->in_gart == 0 && gt->stolen == 0) { - psb_mmu_remove_pages(psb_mmu_get_default_pd(dev_priv->mmu), - (gpu_base + gt->offset), gt->npage, 0, 0); - psb_gtt_remove(dev, gt); - psb_gtt_detach_pages(gt); - } - - mutex_unlock(&dev_priv->gtt_mutex); -} - -/* - * GTT resource allocator - allocate and manage GTT address space - */ - -/** - * psb_gtt_alloc_range - allocate GTT address space - * @dev: Our DRM device - * @len: length (bytes) of address space required - * @name: resource name - * @backed: resource should be backed by stolen pages - * @align: requested alignment - * - * Ask the kernel core to find us a suitable range of addresses - * to use for a GTT mapping. - * - * Returns a gtt_range structure describing the object, or NULL on - * error. On successful return the resource is both allocated and marked - * as in use. - */ -struct gtt_range *psb_gtt_alloc_range(struct drm_device *dev, int len, - const char *name, int backed, u32 align) -{ - struct drm_psb_private *dev_priv = to_drm_psb_private(dev); - struct gtt_range *gt; - struct resource *r = dev_priv->gtt_mem; - int ret; - unsigned long start, end; - - if (backed) { - /* The start of the GTT is the stolen pages */ - start = r->start; - end = r->start + dev_priv->gtt.stolen_size - 1; - } else { - /* The rest we will use for GEM backed objects */ - start = r->start + dev_priv->gtt.stolen_size; - end = r->end; - } - - gt = kzalloc(sizeof(struct gtt_range), GFP_KERNEL); - if (gt == NULL) - return NULL; - gt->resource.name = name; - gt->stolen = backed; - gt->in_gart = backed; - /* Ensure this is set for non GEM objects */ - gt->gem.dev = dev; - ret = allocate_resource(dev_priv->gtt_mem, >->resource, - len, start, end, align, NULL, NULL); - if (ret == 0) { - gt->offset = gt->resource.start - r->start; - return gt; - } - kfree(gt); - return NULL; -} - -/** - * psb_gtt_free_range - release GTT address space - * @dev: our DRM device - * @gt: a mapping created with psb_gtt_alloc_range - * - * Release a resource that was allocated with psb_gtt_alloc_range. If the - * object has been pinned by mmap users we clean this up here currently. - */ -void psb_gtt_free_range(struct drm_device *dev, struct gtt_range *gt) -{ - /* Undo the mmap pin if we are destroying the object */ - if (gt->mmapping) { - psb_gtt_unpin(gt); - gt->mmapping = 0; - } - WARN_ON(gt->in_gart && !gt->stolen); - release_resource(>->resource); - kfree(gt); + /* Make sure all the entries are set before we return */ + ioread32(gtt_slot - 1); } static void psb_gtt_alloc(struct drm_device *dev) @@ -498,7 +303,7 @@ int psb_gtt_restore(struct drm_device *dev) { struct drm_psb_private *dev_priv = to_drm_psb_private(dev); struct resource *r = dev_priv->gtt_mem->child; - struct gtt_range *range; + struct psb_gem_object *pobj; unsigned int restored = 0, total = 0, size = 0; /* On resume, the gtt_mutex is already initialized */ @@ -506,10 +311,15 @@ int psb_gtt_restore(struct drm_device *dev) psb_gtt_init(dev, 1); while (r != NULL) { - range = container_of(r, struct gtt_range, resource); - if (range->pages) { - psb_gtt_insert(dev, range, 1); - size += range->resource.end - range->resource.start; + /* + * TODO: GTT restoration needs a refactoring, so that we don't have to touch + * struct psb_gem_object here. The type represents a GEM object and is + * not related to the GTT itself. + */ + pobj = container_of(r, struct psb_gem_object, resource); + if (pobj->pages) { + psb_gtt_insert_pages(dev_priv, &pobj->resource, pobj->pages); + size += pobj->resource.end - pobj->resource.start; restored++; } r = r->sibling; diff --git a/drivers/gpu/drm/gma500/gtt.h b/drivers/gpu/drm/gma500/gtt.h index 2bf165849ebe..ff1dcdd1ff52 100644 --- a/drivers/gpu/drm/gma500/gtt.h +++ b/drivers/gpu/drm/gma500/gtt.h @@ -10,6 +10,8 @@ #include <drm/drm_gem.h> +struct drm_psb_private; + /* This wants cleaning up with respect to the psb_dev and un-needed stuff */ struct psb_gtt { uint32_t gatt_start; @@ -26,27 +28,14 @@ struct psb_gtt { /* Exported functions */ extern int psb_gtt_init(struct drm_device *dev, int resume); extern void psb_gtt_takedown(struct drm_device *dev); +extern int psb_gtt_restore(struct drm_device *dev); -/* Each gtt_range describes an allocation in the GTT area */ -struct gtt_range { - struct resource resource; /* Resource for our allocation */ - u32 offset; /* GTT offset of our object */ - struct drm_gem_object gem; /* GEM high level stuff */ - int in_gart; /* Currently in the GART (ref ct) */ - bool stolen; /* Backed from stolen RAM */ - bool mmapping; /* Is mmappable */ - struct page **pages; /* Backing pages if present */ - int npage; /* Number of backing pages */ -}; +int psb_gtt_allocate_resource(struct drm_psb_private *pdev, struct resource *res, + const char *name, resource_size_t size, resource_size_t align, + bool stolen, u32 *offset); -#define to_gtt_range(x) container_of(x, struct gtt_range, gem) +void psb_gtt_insert_pages(struct drm_psb_private *pdev, const struct resource *res, + struct page **pages); +void psb_gtt_remove_pages(struct drm_psb_private *pdev, const struct resource *res); -extern struct gtt_range *psb_gtt_alloc_range(struct drm_device *dev, int len, - const char *name, int backed, - u32 align); -extern void psb_gtt_kref_put(struct gtt_range *gt); -extern void psb_gtt_free_range(struct drm_device *dev, struct gtt_range *gt); -extern int psb_gtt_pin(struct gtt_range *gt); -extern void psb_gtt_unpin(struct gtt_range *gt); -extern int psb_gtt_restore(struct drm_device *dev); #endif diff --git a/drivers/gpu/drm/gma500/oaktrail_crtc.c b/drivers/gpu/drm/gma500/oaktrail_crtc.c index c6b115954b7d..36c7c2686c90 100644 --- a/drivers/gpu/drm/gma500/oaktrail_crtc.c +++ b/drivers/gpu/drm/gma500/oaktrail_crtc.c @@ -10,6 +10,7 @@ #include <drm/drm_fourcc.h> #include "framebuffer.h" +#include "gem.h" #include "gma_display.h" #include "power.h" #include "psb_drv.h" @@ -608,7 +609,7 @@ static int oaktrail_pipe_set_base(struct drm_crtc *crtc, if (!gma_power_begin(dev, true)) return 0; - start = to_gtt_range(fb->obj[0])->offset; + start = to_psb_gem_object(fb->obj[0])->offset; offset = y * fb->pitches[0] + x * fb->format->cpp[0]; REG_WRITE(map->stride, fb->pitches[0]); diff --git a/drivers/gpu/drm/gma500/psb_drv.c b/drivers/gpu/drm/gma500/psb_drv.c index 7a10bb39ef0b..65cf1c79dd7c 100644 --- a/drivers/gpu/drm/gma500/psb_drv.c +++ b/drivers/gpu/drm/gma500/psb_drv.c @@ -19,6 +19,7 @@ #include <acpi/video.h> #include <drm/drm.h> +#include <drm/drm_aperture.h> #include <drm/drm_drv.h> #include <drm/drm_fb_helper.h> #include <drm/drm_file.h> @@ -448,6 +449,17 @@ static int psb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) struct drm_device *dev; int ret; + /* + * We cannot yet easily find the framebuffer's location in memory. So + * remove all framebuffers here. + * + * TODO: Refactor psb_driver_load() to map vdc_reg earlier. Then we + * might be able to read the framebuffer range from the device. + */ + ret = drm_aperture_remove_framebuffers(true, &driver); + if (ret) + return ret; + ret = pcim_enable_device(pdev); if (ret) return ret; diff --git a/drivers/gpu/drm/gma500/psb_intel_display.c b/drivers/gpu/drm/gma500/psb_intel_display.c index f5f259fde88e..d5f95212934e 100644 --- a/drivers/gpu/drm/gma500/psb_intel_display.c +++ b/drivers/gpu/drm/gma500/psb_intel_display.c @@ -12,6 +12,7 @@ #include <drm/drm_plane_helper.h> #include "framebuffer.h" +#include "gem.h" #include "gma_display.h" #include "power.h" #include "psb_drv.h" @@ -454,23 +455,21 @@ static void psb_intel_cursor_init(struct drm_device *dev, struct drm_psb_private *dev_priv = to_drm_psb_private(dev); u32 control[3] = { CURACNTR, CURBCNTR, CURCCNTR }; u32 base[3] = { CURABASE, CURBBASE, CURCBASE }; - struct gtt_range *cursor_gt; + struct psb_gem_object *cursor_pobj; if (dev_priv->ops->cursor_needs_phys) { /* Allocate 4 pages of stolen mem for a hardware cursor. That * is enough for the 64 x 64 ARGB cursors we support. */ - cursor_gt = psb_gtt_alloc_range(dev, 4 * PAGE_SIZE, "cursor", 1, - PAGE_SIZE); - if (!cursor_gt) { - gma_crtc->cursor_gt = NULL; + cursor_pobj = psb_gem_create(dev, 4 * PAGE_SIZE, "cursor", true, PAGE_SIZE); + if (IS_ERR(cursor_pobj)) { + gma_crtc->cursor_pobj = NULL; goto out; } - gma_crtc->cursor_gt = cursor_gt; - gma_crtc->cursor_addr = dev_priv->stolen_base + - cursor_gt->offset; + gma_crtc->cursor_pobj = cursor_pobj; + gma_crtc->cursor_addr = dev_priv->stolen_base + cursor_pobj->offset; } else { - gma_crtc->cursor_gt = NULL; + gma_crtc->cursor_pobj = NULL; } out: diff --git a/drivers/gpu/drm/gma500/psb_intel_drv.h b/drivers/gpu/drm/gma500/psb_intel_drv.h index 5340225d6997..db3e757328fe 100644 --- a/drivers/gpu/drm/gma500/psb_intel_drv.h +++ b/drivers/gpu/drm/gma500/psb_intel_drv.h @@ -140,7 +140,7 @@ struct gma_crtc { int pipe; int plane; uint32_t cursor_addr; - struct gtt_range *cursor_gt; + struct psb_gem_object *cursor_pobj; u8 lut_adj[256]; struct psb_intel_framebuffer *fbdev_fb; /* a mode_set for fbdev users on this crtc */ |