Skip to content

Commit

Permalink
drm/msm: add support for "stolen" mem
Browse files Browse the repository at this point in the history
Add support to use the VRAM carveout (if specified in dtb) for fbdev
scanout buffer.  This allows drm/msm to take over a bootloader splash-
screen, and avoids corruption on screen that results if the kernel uses
memory that is still being scanned out for itself.

Signed-off-by: Rob Clark <[email protected]>
  • Loading branch information
robclark committed Apr 1, 2015
1 parent 5bf9c0b commit 072f1f9
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 11 deletions.
44 changes: 40 additions & 4 deletions drivers/gpu/drm/msm/msm_drv.c
Original file line number Diff line number Diff line change
Expand Up @@ -182,21 +182,57 @@ static int get_mdp_ver(struct platform_device *pdev)
return 4;
}

#include <linux/of_address.h>

static int msm_init_vram(struct drm_device *dev)
{
struct msm_drm_private *priv = dev->dev_private;
unsigned long size = 0;
int ret = 0;

#ifdef CONFIG_OF
/* In the device-tree world, we could have a 'memory-region'
* phandle, which gives us a link to our "vram". Allocating
* is all nicely abstracted behind the dma api, but we need
* to know the entire size to allocate it all in one go. There
* are two cases:
* 1) device with no IOMMU, in which case we need exclusive
* access to a VRAM carveout big enough for all gpu
* buffers
* 2) device with IOMMU, but where the bootloader puts up
* a splash screen. In this case, the VRAM carveout
* need only be large enough for fbdev fb. But we need
* exclusive access to the buffer to avoid the kernel
* using those pages for other purposes (which appears
* as corruption on screen before we have a chance to
* load and do initial modeset)
*/
struct device_node *node;

node = of_parse_phandle(dev->dev->of_node, "memory-region", 0);
if (node) {
struct resource r;
ret = of_address_to_resource(node, 0, &r);
if (ret)
return ret;
size = r.end - r.start;
DRM_INFO("using VRAM carveout: %lx@%08x\n", size, r.start);
} else
#endif

/* if we have no IOMMU, then we need to use carveout allocator.
* Grab the entire CMA chunk carved out in early startup in
* mach-msm:
*/
if (!iommu_present(&platform_bus_type)) {
DRM_INFO("using %s VRAM carveout\n", vram);
size = memparse(vram, NULL);
}

if (size) {
DEFINE_DMA_ATTRS(attrs);
unsigned long size;
void *p;

DBG("using %s VRAM carveout", vram);
size = memparse(vram, NULL);
priv->vram.size = size;

drm_mm_init(&priv->vram.mm, 0, (size >> PAGE_SHIFT) - 1);
Expand All @@ -220,7 +256,7 @@ static int msm_init_vram(struct drm_device *dev)
(uint32_t)(priv->vram.paddr + size));
}

return 0;
return ret;
}

static int msm_load(struct drm_device *dev, unsigned long flags)
Expand Down
3 changes: 2 additions & 1 deletion drivers/gpu/drm/msm/msm_fbdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,8 @@ static int msm_fbdev_create(struct drm_fb_helper *helper,
size = mode_cmd.pitches[0] * mode_cmd.height;
DBG("allocating %d bytes for fb %d", size, dev->primary->index);
mutex_lock(&dev->struct_mutex);
fbdev->bo = msm_gem_new(dev, size, MSM_BO_SCANOUT | MSM_BO_WC);
fbdev->bo = msm_gem_new(dev, size, MSM_BO_SCANOUT |
MSM_BO_WC | MSM_BO_STOLEN);
mutex_unlock(&dev->struct_mutex);
if (IS_ERR(fbdev->bo)) {
ret = PTR_ERR(fbdev->bo);
Expand Down
25 changes: 20 additions & 5 deletions drivers/gpu/drm/msm/msm_gem.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ static dma_addr_t physaddr(struct drm_gem_object *obj)
priv->vram.paddr;
}

static bool use_pages(struct drm_gem_object *obj)
{
struct msm_gem_object *msm_obj = to_msm_bo(obj);
return !msm_obj->vram_node;
}

/* allocate pages from VRAM carveout, used when no IOMMU: */
static struct page **get_pages_vram(struct drm_gem_object *obj,
int npages)
Expand Down Expand Up @@ -72,7 +78,7 @@ static struct page **get_pages(struct drm_gem_object *obj)
struct page **p;
int npages = obj->size >> PAGE_SHIFT;

if (iommu_present(&platform_bus_type))
if (use_pages(obj))
p = drm_gem_get_pages(obj);
else
p = get_pages_vram(obj, npages);
Expand Down Expand Up @@ -116,7 +122,7 @@ static void put_pages(struct drm_gem_object *obj)
sg_free_table(msm_obj->sgt);
kfree(msm_obj->sgt);

if (iommu_present(&platform_bus_type))
if (use_pages(obj))
drm_gem_put_pages(obj, msm_obj->pages, true, false);
else {
drm_mm_remove_node(msm_obj->vram_node);
Expand Down Expand Up @@ -580,6 +586,7 @@ static int msm_gem_new_impl(struct drm_device *dev,
struct msm_drm_private *priv = dev->dev_private;
struct msm_gem_object *msm_obj;
unsigned sz;
bool use_vram = false;

switch (flags & MSM_BO_CACHE_MASK) {
case MSM_BO_UNCACHED:
Expand All @@ -592,15 +599,23 @@ static int msm_gem_new_impl(struct drm_device *dev,
return -EINVAL;
}

sz = sizeof(*msm_obj);
if (!iommu_present(&platform_bus_type))
use_vram = true;
else if ((flags & MSM_BO_STOLEN) && priv->vram.size)
use_vram = true;

if (WARN_ON(use_vram && !priv->vram.size))
return -EINVAL;

sz = sizeof(*msm_obj);
if (use_vram)
sz += sizeof(struct drm_mm_node);

msm_obj = kzalloc(sz, GFP_KERNEL);
if (!msm_obj)
return -ENOMEM;

if (!iommu_present(&platform_bus_type))
if (use_vram)
msm_obj->vram_node = (void *)&msm_obj[1];

msm_obj->flags = flags;
Expand Down Expand Up @@ -630,7 +645,7 @@ struct drm_gem_object *msm_gem_new(struct drm_device *dev,
if (ret)
goto fail;

if (iommu_present(&platform_bus_type)) {
if (use_pages(obj)) {
ret = drm_gem_object_init(dev, obj, size);
if (ret)
goto fail;
Expand Down
5 changes: 4 additions & 1 deletion drivers/gpu/drm/msm/msm_gem.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@
#include <linux/reservation.h>
#include "msm_drv.h"

/* Additional internal-use only BO flags: */
#define MSM_BO_STOLEN 0x10000000 /* try to use stolen/splash memory */

struct msm_gem_object {
struct drm_gem_object base;

Expand Down Expand Up @@ -59,7 +62,7 @@ struct msm_gem_object {
struct reservation_object _resv;

/* For physically contiguous buffers. Used when we don't have
* an IOMMU.
* an IOMMU. Also used for stolen/splashscreen buffer.
*/
struct drm_mm_node *vram_node;
};
Expand Down

0 comments on commit 072f1f9

Please sign in to comment.