From: Rob Clark <hidden> Date: 2017-07-11 13:38:19
The first patch I've already sent to list and plan to include in a
v4.13-fixes pull request, but I'm resending as part of this patchset
since 3/3 depends on it.
The 2nd patch exports get_fb_info()/put_fb_info() so that in the 3rd
patch we can iterate over the registered fb's (before kicking out fw
fb) and find the stolen memory from bootloader display.
Note that the firmware fb might either be efifb or simplefb, depending
on EFI boot or not. So a devicetree based solution to this is not
useful.
This is prep-work for a larger patchset for drm/msm to readback and
take over display setup by bootloader (although that also requires
some CCF and other changes.. RFC patchset coming soon). In the RFC
patchset, drm/msm will wrap the stolen mem in a GEM object and use
that to create a drm_framebuffer object for the read-back plane state
(and if the drm fbdev emulation layer is enabled, it will try to re-
use this for the fbdev scanout buffer).
If no objections to the 2nd patch, I guess it is probably easiest if
it is merged via msm-next for 4.14.
Rob Clark (3):
drm/msm: kick out firmware framebuffer
fbdev: fbmem: export get/put_fb_info()
drm/msm: hijack firmware fb's memory
drivers/gpu/drm/msm/msm_drv.c | 102 ++++++++++++++++++++++++++++++++-------
drivers/gpu/drm/msm/msm_drv.h | 2 +
drivers/gpu/drm/msm/msm_fbdev.c | 2 +-
drivers/video/fbdev/core/fbmem.c | 6 ++-
include/linux/fb.h | 2 +
5 files changed, 93 insertions(+), 21 deletions(-)
--
2.13.0
From: Rob Clark <hidden> Date: 2017-07-11 13:38:22
If we are kicking out efifb or simplefb then we want to hijack the
outgoing fb's memory and wrap it in a gem object so that it can
be allocated for use by fbdev helpers. This way we keep the same
scanout buffer that the display is already using.
This is prep-work for enabling drm/msm to take over a display that
is enabled already by the bootloader.
Signed-off-by: Rob Clark <redacted>
---
drivers/gpu/drm/msm/msm_drv.c | 82 +++++++++++++++++++++++++++++++++----------
1 file changed, 64 insertions(+), 18 deletions(-)
@@ -304,6 +304,45 @@ static void kick_out_firmware_fb(void)kfree(ap);}+staticunsignedlonghijack_firmware_fb(structdrm_device*dev)+{+structmsm_drm_private*priv=dev->dev_private;+unsignedlongsize;+inti;++/* if we have simplefb/efifb, find it's aperture and hijack+*thatbeforewekickoutthefirmwarefb's.+*+*TODOweprobablyshouldholdregistration_lock+*/+for(i=0;i<FB_MAX;i++){+structfb_info*fb=get_fb_info(i);++if(IS_ERR_OR_NULL(fb))+continue;++if(!fb->apertures->count)+continue;++/* if we find efifb or simplefb, we are about to+*kickthemout,sohijacktheirmemory:+*/+if((strcmp(fb->fix.id,"EFI VGA")=0)||+(strcmp(fb->fix.id,"simple")=0)){++priv->vram.paddr=fb->apertures->ranges[0].base;+size=fb->apertures->ranges[0].size;+}++put_fb_info(fb);++if(size)+returnsize;+}++return0;+}+staticintmsm_init_vram(structdrm_device*dev){structmsm_drm_private*priv=dev->dev_private;
@@ -335,39 +374,46 @@ static int msm_init_vram(struct drm_device *dev)of_node_put(node);if(ret)returnret;-size=r.end-r.start;+size=r.end-r.start-1;DRM_INFO("using VRAM carveout: %lx@%pa\n",size,&r.start);+}elseif((size=hijack_firmware_fb(dev))){+DRM_INFO("hijacking VRAM carveout: %lx@%pa\n",+size,&priv->vram.paddr);+}elseif(!iommu_present(&platform_bus_type)){/* if we have no IOMMU, then we need to use carveout allocator.*GrabtheentireCMAchunkcarvedoutinearlystartupin*mach-msm:*/-}elseif(!iommu_present(&platform_bus_type)){DRM_INFO("using %s VRAM carveout\n",vram);size=memparse(vram,NULL);}if(size){-unsignedlongattrs=0;-void*p;-priv->vram.size=size;-drm_mm_init(&priv->vram.mm,0,(size>>PAGE_SHIFT)-1);+drm_mm_init(&priv->vram.mm,0,(size>>PAGE_SHIFT));spin_lock_init(&priv->vram.lock);-attrs|=DMA_ATTR_NO_KERNEL_MAPPING;-attrs|=DMA_ATTR_WRITE_COMBINE;--/* note that for no-kernel-mapping, the vaddr returned-*isbogus,butnon-nullifallocationsucceeded:-*/-p=dma_alloc_attrs(dev->dev,size,-&priv->vram.paddr,GFP_KERNEL,attrs);-if(!p){-dev_err(dev->dev,"failed to allocate VRAM\n");-priv->vram.paddr=0;-return-ENOMEM;+if(!priv->vram.paddr){+unsignedlongattrs=0;+void*p;++attrs|=DMA_ATTR_NO_KERNEL_MAPPING;+attrs|=DMA_ATTR_WRITE_COMBINE;++/* note that for no-kernel-mapping, the vaddr returned+*isbogus,butnon-nullifallocationsucceeded:+*/+p=dma_alloc_attrs(dev->dev,size,+&priv->vram.paddr,GFP_KERNEL,attrs);+if(!p){+dev_err(dev->dev,"failed to allocate VRAM\n");+priv->vram.paddr=0;+return-ENOMEM;+}+}else{+request_region(priv->vram.paddr,size,"stolen");}dev_info(dev->dev,"VRAM: %08x->%08x\n",
From: Rob Clark <hidden> Date: 2017-07-11 13:38:34
Fixes a problem with console not appearing when booting with EFI that
has GOP support, because fb0 would end up being efifb, even after drm
has taken over the display.
Signed-off-by: Rob Clark <redacted>
---
drivers/gpu/drm/msm/msm_drv.c | 20 ++++++++++++++++++++
drivers/gpu/drm/msm/msm_drv.h | 2 ++
drivers/gpu/drm/msm/msm_fbdev.c | 2 +-
3 files changed, 23 insertions(+), 1 deletion(-)
@@ -286,6 +286,24 @@ static int get_mdp_ver(struct platform_device *pdev)#include<linux/of_address.h>+staticvoidkick_out_firmware_fb(void)+{+structapertures_struct*ap;++ap=alloc_apertures(1);+if(!ap)+return;++/* Since msm is a UMA device, the simplefb or efifb node may+*havebeenlocatedanywhereinmemory.+*/+ap->ranges[0].base=0;+ap->ranges[0].size=MAX_RESOURCE;++drm_fb_helper_remove_conflicting_framebuffers(ap,FB_NAME,false);+kfree(ap);+}+staticintmsm_init_vram(structdrm_device*dev){structmsm_drm_private*priv=dev->dev_private;
@@ -55,6 +55,8 @@ struct msm_fence_cb;structmsm_gem_address_space;structmsm_gem_vma;+#define FB_NAME "msm"+structmsm_file_private{/* currently we don't do anything useful with this.. but when*per-contextaddressspacesaresupportedwe'dkeeptrackof
From: Daniel Vetter <hidden> Date: 2017-07-11 14:03:13
On Tue, Jul 11, 2017 at 3:38 PM, Rob Clark [off-list ref] wrote:
+static unsigned long hijack_firmware_fb(struct drm_device *dev)
+{
+ struct msm_drm_private *priv = dev->dev_private;
+ unsigned long size;
+ int i;
+
+ /* if we have simplefb/efifb, find it's aperture and hijack
+ * that before we kick out the firmware fb's.
+ *
+ * TODO we probably should hold registration_lock
+ */
+ for (i = 0; i < FB_MAX; i++) {
+ struct fb_info *fb = get_fb_info(i);
+
+ if (IS_ERR_OR_NULL(fb))
+ continue;
+
+ if (!fb->apertures->count)
+ continue;
+
+ /* if we find efifb or simplefb, we are about to
+ * kick them out, so hijack their memory:
+ */
+ if ((strcmp(fb->fix.id, "EFI VGA") = 0) ||
+ (strcmp(fb->fix.id, "simple") = 0)) {
+
+ priv->vram.paddr = fb->apertures->ranges[0].base;
+ size = fb->apertures->ranges[0].size;
+ }
+
+ put_fb_info(fb);
+
+ if (size)
+ return size;
+ }
+
+ return 0;
+}
I think this should be a helper function in at least drm_fb_helper.c,
which would then fill in both base&size in a passed-in struct. But
yeah this seems a lot better than the old one.
In the future we could then also extend this with kicking out other
firmware fb things.
-Daniel
--
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
From: Chris Wilson <hidden> Date: 2017-07-11 14:17:30
Quoting Rob Clark (2017-07-11 14:38:22)
+static unsigned long hijack_firmware_fb(struct drm_device *dev)
+{
+ struct msm_drm_private *priv = dev->dev_private;
+ unsigned long size;
+ int i;
+
+ /* if we have simplefb/efifb, find it's aperture and hijack
+ * that before we kick out the firmware fb's.
+ *
+ * TODO we probably should hold registration_lock
+ */
+ for (i = 0; i < FB_MAX; i++) {
+ struct fb_info *fb = get_fb_info(i);
+
+ if (IS_ERR_OR_NULL(fb))
+ continue;
+
+ if (!fb->apertures->count)
Does get_fb_info() not return a reference if its apertures->count=0?
+ continue;
+
+ /* if we find efifb or simplefb, we are about to
+ * kick them out, so hijack their memory:
+ */
+ if ((strcmp(fb->fix.id, "EFI VGA") = 0) ||
+ (strcmp(fb->fix.id, "simple") = 0)) {
+
+ priv->vram.paddr = fb->apertures->ranges[0].base;
+ size = fb->apertures->ranges[0].size;
+ }
+
+ put_fb_info(fb);
+
+ if (size)
+ return size;
size is never initialised to 0. Perhaps just return the reference to the
matching fb? Hopefully sidestepping a few of the worries about it
disappearing during the probe.
-Chris
From: Rob Clark <hidden> Date: 2017-07-11 14:31:42
On Tue, Jul 11, 2017 at 10:03 AM, Daniel Vetter [off-list ref] wrote:
On Tue, Jul 11, 2017 at 3:38 PM, Rob Clark [off-list ref] wrote:
quoted
+static unsigned long hijack_firmware_fb(struct drm_device *dev)
+{
+ struct msm_drm_private *priv = dev->dev_private;
+ unsigned long size;
+ int i;
+
+ /* if we have simplefb/efifb, find it's aperture and hijack
+ * that before we kick out the firmware fb's.
+ *
+ * TODO we probably should hold registration_lock
+ */
+ for (i = 0; i < FB_MAX; i++) {
+ struct fb_info *fb = get_fb_info(i);
+
+ if (IS_ERR_OR_NULL(fb))
+ continue;
+
+ if (!fb->apertures->count)
+ continue;
+
+ /* if we find efifb or simplefb, we are about to
+ * kick them out, so hijack their memory:
+ */
+ if ((strcmp(fb->fix.id, "EFI VGA") = 0) ||
+ (strcmp(fb->fix.id, "simple") = 0)) {
+
+ priv->vram.paddr = fb->apertures->ranges[0].base;
+ size = fb->apertures->ranges[0].size;
+ }
+
+ put_fb_info(fb);
+
+ if (size)
+ return size;
+ }
+
+ return 0;
+}
I think this should be a helper function in at least drm_fb_helper.c,
which would then fill in both base&size in a passed-in struct. But
yeah this seems a lot better than the old one.
Yeah, I guess we could do that.. but probably not in drm_fb_helper.c
since that is compile-time optional. Better suggestions about where
it should live? If you have fbdev but not DRM_FBDEV_EMULATION you
still want to do this, I think. Otherwise we can't completely take
over the display setup by firmware (ie. no way to create
plane->state->fb).
BR,
-R
In the future we could then also extend this with kicking out other
firmware fb things.
-Daniel
--
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
From: Rob Clark <hidden> Date: 2017-07-11 14:34:28
On Tue, Jul 11, 2017 at 10:17 AM, Chris Wilson [off-list ref] wrote:
Quoting Rob Clark (2017-07-11 14:38:22)
quoted
+static unsigned long hijack_firmware_fb(struct drm_device *dev)
+{
+ struct msm_drm_private *priv = dev->dev_private;
+ unsigned long size;
+ int i;
+
+ /* if we have simplefb/efifb, find it's aperture and hijack
+ * that before we kick out the firmware fb's.
+ *
+ * TODO we probably should hold registration_lock
+ */
+ for (i = 0; i < FB_MAX; i++) {
+ struct fb_info *fb = get_fb_info(i);
+
+ if (IS_ERR_OR_NULL(fb))
+ continue;
+
+ if (!fb->apertures->count)
Does get_fb_info() not return a reference if its apertures->count=0?
yeah, you are right.. overlooked that when converting from iterating
registered_fb[] table directly without taking a reference..
quoted
+ continue;
+
+ /* if we find efifb or simplefb, we are about to
+ * kick them out, so hijack their memory:
+ */
+ if ((strcmp(fb->fix.id, "EFI VGA") = 0) ||
+ (strcmp(fb->fix.id, "simple") = 0)) {
+
+ priv->vram.paddr = fb->apertures->ranges[0].base;
+ size = fb->apertures->ranges[0].size;
+ }
+
+ put_fb_info(fb);
+
+ if (size)
+ return size;
size is never initialised to 0. Perhaps just return the reference to the
matching fb? Hopefully sidestepping a few of the worries about it
disappearing during the probe.
I guess that would be a useful approach if I wanted a single helper
that did both this and kicking out firmware fb's..
BR,
-R
From: Daniel Vetter <hidden> Date: 2017-07-11 14:42:18
On Tue, Jul 11, 2017 at 4:31 PM, Rob Clark [off-list ref] wrote:
On Tue, Jul 11, 2017 at 10:03 AM, Daniel Vetter [off-list ref] wrote:
quoted
On Tue, Jul 11, 2017 at 3:38 PM, Rob Clark [off-list ref] wrote:
quoted
+static unsigned long hijack_firmware_fb(struct drm_device *dev)
+{
+ struct msm_drm_private *priv = dev->dev_private;
+ unsigned long size;
+ int i;
+
+ /* if we have simplefb/efifb, find it's aperture and hijack
+ * that before we kick out the firmware fb's.
+ *
+ * TODO we probably should hold registration_lock
+ */
+ for (i = 0; i < FB_MAX; i++) {
+ struct fb_info *fb = get_fb_info(i);
+
+ if (IS_ERR_OR_NULL(fb))
+ continue;
+
+ if (!fb->apertures->count)
+ continue;
+
+ /* if we find efifb or simplefb, we are about to
+ * kick them out, so hijack their memory:
+ */
+ if ((strcmp(fb->fix.id, "EFI VGA") = 0) ||
+ (strcmp(fb->fix.id, "simple") = 0)) {
+
+ priv->vram.paddr = fb->apertures->ranges[0].base;
+ size = fb->apertures->ranges[0].size;
+ }
+
+ put_fb_info(fb);
+
+ if (size)
+ return size;
+ }
+
+ return 0;
+}
I think this should be a helper function in at least drm_fb_helper.c,
which would then fill in both base&size in a passed-in struct. But
yeah this seems a lot better than the old one.
Yeah, I guess we could do that.. but probably not in drm_fb_helper.c
since that is compile-time optional. Better suggestions about where
it should live? If you have fbdev but not DRM_FBDEV_EMULATION you
still want to do this, I think. Otherwise we can't completely take
over the display setup by firmware (ie. no way to create
plane->state->fb).
Hm right, maybe add a drm_fwfb_helper.c or so. If you look at
i915_kick_out_vgacon(), that might be another candidate for that file.
Putting it into fbdev itself seems like a bad idea, because
maintenance pains.
-Daniel
--
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
From: Rob Clark <hidden> Date: 2017-07-11 19:53:05
On Tue, Jul 11, 2017 at 10:42 AM, Daniel Vetter [off-list ref] wrote:
On Tue, Jul 11, 2017 at 4:31 PM, Rob Clark [off-list ref] wrote:
quoted
On Tue, Jul 11, 2017 at 10:03 AM, Daniel Vetter [off-list ref] wrote:
quoted
On Tue, Jul 11, 2017 at 3:38 PM, Rob Clark [off-list ref] wrote:
quoted
+static unsigned long hijack_firmware_fb(struct drm_device *dev)
+{
+ struct msm_drm_private *priv = dev->dev_private;
+ unsigned long size;
+ int i;
+
+ /* if we have simplefb/efifb, find it's aperture and hijack
+ * that before we kick out the firmware fb's.
+ *
+ * TODO we probably should hold registration_lock
+ */
+ for (i = 0; i < FB_MAX; i++) {
+ struct fb_info *fb = get_fb_info(i);
+
+ if (IS_ERR_OR_NULL(fb))
+ continue;
+
+ if (!fb->apertures->count)
+ continue;
+
+ /* if we find efifb or simplefb, we are about to
+ * kick them out, so hijack their memory:
+ */
+ if ((strcmp(fb->fix.id, "EFI VGA") = 0) ||
+ (strcmp(fb->fix.id, "simple") = 0)) {
+
+ priv->vram.paddr = fb->apertures->ranges[0].base;
+ size = fb->apertures->ranges[0].size;
+ }
+
+ put_fb_info(fb);
+
+ if (size)
+ return size;
+ }
+
+ return 0;
+}
I think this should be a helper function in at least drm_fb_helper.c,
which would then fill in both base&size in a passed-in struct. But
yeah this seems a lot better than the old one.
Yeah, I guess we could do that.. but probably not in drm_fb_helper.c
since that is compile-time optional. Better suggestions about where
it should live? If you have fbdev but not DRM_FBDEV_EMULATION you
still want to do this, I think. Otherwise we can't completely take
over the display setup by firmware (ie. no way to create
plane->state->fb).
Hm right, maybe add a drm_fwfb_helper.c or so. If you look at
i915_kick_out_vgacon(), that might be another candidate for that file.
Putting it into fbdev itself seems like a bad idea, because
maintenance pains.
Hmm, would it be weird to have an:
obj-$(CONFIG_FB) += drm_fbfw_helper.o
in drm/Makefile? Or is there a better way to do that?
I'm also wondering a bit about the CONFIG_FB=n case.. you might still
have CONFIG_EFI, so maybe we should fall back to pulling this out of
screen_info and looking for a simple-framebuffer node in the CONFIG_OF
case?
(also maybe worth noting that on ARM/ARM64 we don't have
CONFIG_VGA_CONSOLE.. so there are a lot of fun permutations..)
BR,
-R
From: Daniel Vetter <hidden> Date: 2017-07-11 20:37:53
On Tue, Jul 11, 2017 at 9:53 PM, Rob Clark [off-list ref] wrote:
On Tue, Jul 11, 2017 at 10:42 AM, Daniel Vetter [off-list ref] wrote:
quoted
On Tue, Jul 11, 2017 at 4:31 PM, Rob Clark [off-list ref] wrote:
quoted
On Tue, Jul 11, 2017 at 10:03 AM, Daniel Vetter [off-list ref] wrote:
quoted
On Tue, Jul 11, 2017 at 3:38 PM, Rob Clark [off-list ref] wrote:
quoted
+static unsigned long hijack_firmware_fb(struct drm_device *dev)
+{
+ struct msm_drm_private *priv = dev->dev_private;
+ unsigned long size;
+ int i;
+
+ /* if we have simplefb/efifb, find it's aperture and hijack
+ * that before we kick out the firmware fb's.
+ *
+ * TODO we probably should hold registration_lock
+ */
+ for (i = 0; i < FB_MAX; i++) {
+ struct fb_info *fb = get_fb_info(i);
+
+ if (IS_ERR_OR_NULL(fb))
+ continue;
+
+ if (!fb->apertures->count)
+ continue;
+
+ /* if we find efifb or simplefb, we are about to
+ * kick them out, so hijack their memory:
+ */
+ if ((strcmp(fb->fix.id, "EFI VGA") = 0) ||
+ (strcmp(fb->fix.id, "simple") = 0)) {
+
+ priv->vram.paddr = fb->apertures->ranges[0].base;
+ size = fb->apertures->ranges[0].size;
+ }
+
+ put_fb_info(fb);
+
+ if (size)
+ return size;
+ }
+
+ return 0;
+}
I think this should be a helper function in at least drm_fb_helper.c,
which would then fill in both base&size in a passed-in struct. But
yeah this seems a lot better than the old one.
Yeah, I guess we could do that.. but probably not in drm_fb_helper.c
since that is compile-time optional. Better suggestions about where
it should live? If you have fbdev but not DRM_FBDEV_EMULATION you
still want to do this, I think. Otherwise we can't completely take
over the display setup by firmware (ie. no way to create
plane->state->fb).
Hm right, maybe add a drm_fwfb_helper.c or so. If you look at
i915_kick_out_vgacon(), that might be another candidate for that file.
Putting it into fbdev itself seems like a bad idea, because
maintenance pains.
Hmm, would it be weird to have an:
obj-$(CONFIG_FB) += drm_fbfw_helper.o
in drm/Makefile? Or is there a better way to do that?
I'm also wondering a bit about the CONFIG_FB=n case.. you might still
have CONFIG_EFI, so maybe we should fall back to pulling this out of
screen_info and looking for a simple-framebuffer node in the CONFIG_OF
case?
(also maybe worth noting that on ARM/ARM64 we don't have
CONFIG_VGA_CONSOLE.. so there are a lot of fun permutations..)
I'd include the source always (because of the above, e.g. kicking
vgacon doesn't depend on CONFIG_FB), and then we'll probably have to
sprinkle a pile of ugly #ifdef all over that file. Still better to
have these hacks in one place only at least.
-Daniel
--
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch