From patchwork Thu Mar 3 20:58:31 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Thomas Zimmermann X-Patchwork-Id: 547953 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id F0FD1C433EF for ; Thu, 3 Mar 2022 20:58:45 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231549AbiCCU7a (ORCPT ); Thu, 3 Mar 2022 15:59:30 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58790 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236384AbiCCU73 (ORCPT ); Thu, 3 Mar 2022 15:59:29 -0500 Received: from smtp-out1.suse.de (smtp-out1.suse.de [195.135.220.28]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2154A42EE3 for ; Thu, 3 Mar 2022 12:58:43 -0800 (PST) Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out1.suse.de (Postfix) with ESMTPS id AA9A9218BB; Thu, 3 Mar 2022 20:58:41 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1646341121; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=YKy18Jmuwa8ZvhW6hqDriQe/CWvhmG9VTTVexi6InC8=; b=RbMnhIx4xdbKEjMJ0RJBreTcz15soxeIqwSj4khO+pyKscAdUp2fz9ZfZIwnR/5zPpO+P6 9dZQsP10My6TRD7GYoX6T0G/H6mbMyH0DDvL6OiqLnpW0SGPMVrDj361pIGhXYZsewqAlG KI6hycOj1m3DjBt6fybgTIc3FTvUPaw= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1646341121; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=YKy18Jmuwa8ZvhW6hqDriQe/CWvhmG9VTTVexi6InC8=; b=wXsuaROdXnVH1Jaw02NFbN3ceeebgacfaVo99+APG6zHbSQpd1nch4cuZyaAnkbzkEcjSw FAJM/FNBqiyANACg== Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap2.suse-dmz.suse.de (Postfix) with ESMTPS id 782A113AEE; Thu, 3 Mar 2022 20:58:41 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id EN9dHAEsIWJoHAAAMHmgww (envelope-from ); Thu, 03 Mar 2022 20:58:41 +0000 From: Thomas Zimmermann To: daniel@ffwll.ch, airlied@linux.ie, mripard@kernel.org, maarten.lankhorst@linux.intel.com, deller@gmx.de, javierm@redhat.com Cc: dri-devel@lists.freedesktop.org, linux-fbdev@vger.kernel.org, Thomas Zimmermann Subject: [PATCH 1/9] drm/simpledrm: Use fbdev defaults for shadow buffering Date: Thu, 3 Mar 2022 21:58:31 +0100 Message-Id: <20220303205839.28484-2-tzimmermann@suse.de> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220303205839.28484-1-tzimmermann@suse.de> References: <20220303205839.28484-1-tzimmermann@suse.de> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fbdev@vger.kernel.org Don't select shadow buffering for the fbdev console explicitly. The fbdev emulation's heuristic will enable it for any framebuffer with .dirty callback. Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas --- drivers/gpu/drm/tiny/simpledrm.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/tiny/simpledrm.c b/drivers/gpu/drm/tiny/simpledrm.c index f5b8e864a5cd..768242a78e2b 100644 --- a/drivers/gpu/drm/tiny/simpledrm.c +++ b/drivers/gpu/drm/tiny/simpledrm.c @@ -801,7 +801,6 @@ static int simpledrm_device_init_modeset(struct simpledrm_device *sdev) dev->mode_config.max_width = max_width; dev->mode_config.min_height = mode->vdisplay; dev->mode_config.max_height = max_height; - dev->mode_config.prefer_shadow_fbdev = true; dev->mode_config.preferred_depth = sdev->format->cpp[0] * 8; dev->mode_config.funcs = &simpledrm_mode_config_funcs; From patchwork Thu Mar 3 20:58:32 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Thomas Zimmermann X-Patchwork-Id: 549512 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 10A86C4332F for ; Thu, 3 Mar 2022 20:58:47 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236396AbiCCU7b (ORCPT ); Thu, 3 Mar 2022 15:59:31 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58836 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236371AbiCCU7a (ORCPT ); Thu, 3 Mar 2022 15:59:30 -0500 Received: from smtp-out1.suse.de (smtp-out1.suse.de [195.135.220.28]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 55EFD43ECE for ; Thu, 3 Mar 2022 12:58:43 -0800 (PST) Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out1.suse.de (Postfix) with ESMTPS id E3C75218D9; Thu, 3 Mar 2022 20:58:41 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1646341121; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=vTpeCqYs3LvzLMXvyo/gYF/QEXjQg1Ay9sWjS0CBM4M=; b=Jo1QkPb+U6du7DJCbcvcEbKXSfplWh69hBHXLv4A9Yr/SMCDxxmDXwB6RBm6pLdxBg1irj DdJ2BwZiHrZY8zZJplcx3n8EI5q5KT0/uJm3eNNSW44e3WtSgZFT+1Rwu840AwzTWpKx1+ 4BzB/epiKRiejJHkj33gOggUPA4i6P4= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1646341121; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=vTpeCqYs3LvzLMXvyo/gYF/QEXjQg1Ay9sWjS0CBM4M=; b=y4aEeh8947XHH/4K4QyPn3OG6cZSb6MZBu1uqaVwxGrcysq+S24WLO+uSwvuDPtvOU6/qb LD6M/KYx2PpOS8CQ== Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap2.suse-dmz.suse.de (Postfix) with ESMTPS id AF3F4139B5; Thu, 3 Mar 2022 20:58:41 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id KIrYKQEsIWJoHAAAMHmgww (envelope-from ); Thu, 03 Mar 2022 20:58:41 +0000 From: Thomas Zimmermann To: daniel@ffwll.ch, airlied@linux.ie, mripard@kernel.org, maarten.lankhorst@linux.intel.com, deller@gmx.de, javierm@redhat.com Cc: dri-devel@lists.freedesktop.org, linux-fbdev@vger.kernel.org, Thomas Zimmermann Subject: [PATCH 2/9] fbdev: Put mmap for deferred I/O into drivers Date: Thu, 3 Mar 2022 21:58:32 +0100 Message-Id: <20220303205839.28484-3-tzimmermann@suse.de> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220303205839.28484-1-tzimmermann@suse.de> References: <20220303205839.28484-1-tzimmermann@suse.de> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fbdev@vger.kernel.org The fbdev mmap function fb_mmap() unconditionally overrides the driver's implementation if deferred I/O has been activated. This makes it hard to implement mmap with anything but a vmalloc()'ed software buffer. That is specifically a problem for DRM, where video memory is maintained by a memory manager. Leave the mmap handling to drivers and expect them to call the helper for deferred I/O by thmeselves. Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas --- drivers/gpu/drm/drm_fb_helper.c | 4 +++- drivers/gpu/drm/vmwgfx/vmwgfx_fb.c | 1 + drivers/hid/hid-picolcd_fb.c | 1 + drivers/staging/fbtft/fbtft-core.c | 1 + drivers/video/fbdev/broadsheetfb.c | 1 + drivers/video/fbdev/core/fb_defio.c | 1 + drivers/video/fbdev/core/fbmem.c | 19 +++++++++---------- drivers/video/fbdev/hecubafb.c | 1 + drivers/video/fbdev/hyperv_fb.c | 1 + drivers/video/fbdev/metronomefb.c | 1 + drivers/video/fbdev/sh_mobile_lcdcfb.c | 6 ++++++ drivers/video/fbdev/smscufx.c | 3 +++ drivers/video/fbdev/ssd1307fb.c | 1 + drivers/video/fbdev/udlfb.c | 3 +++ drivers/video/fbdev/xen-fbfront.c | 1 + 15 files changed, 34 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index d265a73313c9..d06ce0e92d66 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -2118,7 +2118,9 @@ static int drm_fbdev_fb_mmap(struct fb_info *info, struct vm_area_struct *vma) { struct drm_fb_helper *fb_helper = info->par; - if (fb_helper->dev->driver->gem_prime_mmap) + if (drm_fbdev_use_shadow_fb(fb_helper)) + return fb_deferred_io_mmap(info, vma); + else if (fb_helper->dev->driver->gem_prime_mmap) return fb_helper->dev->driver->gem_prime_mmap(fb_helper->buffer->gem, vma); else return -ENODEV; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c index 8ee34576c7d0..33f355907fbb 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c @@ -619,6 +619,7 @@ static const struct fb_ops vmw_fb_ops = { .fb_imageblit = vmw_fb_imageblit, .fb_pan_display = vmw_fb_pan_display, .fb_blank = vmw_fb_blank, + .fb_mmap = fb_deferred_io_mmap, }; int vmw_fb_init(struct vmw_private *vmw_priv) diff --git a/drivers/hid/hid-picolcd_fb.c b/drivers/hid/hid-picolcd_fb.c index 33c102a60992..78515e6bacf0 100644 --- a/drivers/hid/hid-picolcd_fb.c +++ b/drivers/hid/hid-picolcd_fb.c @@ -428,6 +428,7 @@ static const struct fb_ops picolcdfb_ops = { .fb_imageblit = picolcd_fb_imageblit, .fb_check_var = picolcd_fb_check_var, .fb_set_par = picolcd_set_par, + .fb_mmap = fb_deferred_io_mmap, }; diff --git a/drivers/staging/fbtft/fbtft-core.c b/drivers/staging/fbtft/fbtft-core.c index 4a35347b3020..60c55451e414 100644 --- a/drivers/staging/fbtft/fbtft-core.c +++ b/drivers/staging/fbtft/fbtft-core.c @@ -652,6 +652,7 @@ struct fb_info *fbtft_framebuffer_alloc(struct fbtft_display *display, fbops->fb_imageblit = fbtft_fb_imageblit; fbops->fb_setcolreg = fbtft_fb_setcolreg; fbops->fb_blank = fbtft_fb_blank; + fbops->fb_mmap = fb_deferred_io_mmap; fbdefio->delay = HZ / fps; fbdefio->sort_pagelist = true; diff --git a/drivers/video/fbdev/broadsheetfb.c b/drivers/video/fbdev/broadsheetfb.c index b9054f658838..528bc0902338 100644 --- a/drivers/video/fbdev/broadsheetfb.c +++ b/drivers/video/fbdev/broadsheetfb.c @@ -1055,6 +1055,7 @@ static const struct fb_ops broadsheetfb_ops = { .fb_fillrect = broadsheetfb_fillrect, .fb_copyarea = broadsheetfb_copyarea, .fb_imageblit = broadsheetfb_imageblit, + .fb_mmap = fb_deferred_io_mmap, }; static struct fb_deferred_io broadsheetfb_defio = { diff --git a/drivers/video/fbdev/core/fb_defio.c b/drivers/video/fbdev/core/fb_defio.c index 98b0f23bf5e2..662bb5d2b872 100644 --- a/drivers/video/fbdev/core/fb_defio.c +++ b/drivers/video/fbdev/core/fb_defio.c @@ -189,6 +189,7 @@ int fb_deferred_io_mmap(struct fb_info *info, struct vm_area_struct *vma) vma->vm_private_data = info; return 0; } +EXPORT_SYMBOL_GPL(fb_deferred_io_mmap); /* workqueue callback */ static void fb_deferred_io_work(struct work_struct *work) diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c index ad9aac06427a..6d89e65592a8 100644 --- a/drivers/video/fbdev/core/fbmem.c +++ b/drivers/video/fbdev/core/fbmem.c @@ -1338,7 +1338,6 @@ static int fb_mmap(struct file *file, struct vm_area_struct * vma) { struct fb_info *info = file_fb_info(file); - int (*fb_mmap_fn)(struct fb_info *info, struct vm_area_struct *vma); unsigned long mmio_pgoff; unsigned long start; u32 len; @@ -1347,14 +1346,7 @@ fb_mmap(struct file *file, struct vm_area_struct * vma) return -ENODEV; mutex_lock(&info->mm_lock); - fb_mmap_fn = info->fbops->fb_mmap; - -#if IS_ENABLED(CONFIG_FB_DEFERRED_IO) - if (info->fbdefio) - fb_mmap_fn = fb_deferred_io_mmap; -#endif - - if (fb_mmap_fn) { + if (info->fbops->fb_mmap) { int res; /* @@ -1362,11 +1354,18 @@ fb_mmap(struct file *file, struct vm_area_struct * vma) * SME protection is removed ahead of the call */ vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot); - res = fb_mmap_fn(info, vma); + res = info->fbops->fb_mmap(info, vma); mutex_unlock(&info->mm_lock); return res; } + /* + * FB deferred I/O want you to handle mmap in your drivers. At a + * minimum, point struct fb_ops.fb_mmap to fb_deferred_io_mmap(). + */ + if (WARN_ON_ONCE(info->fbdefio)) + return -ENODEV; + /* * Ugh. This can be either the frame buffer mapping, or * if pgoff points past it, the mmio mapping. diff --git a/drivers/video/fbdev/hecubafb.c b/drivers/video/fbdev/hecubafb.c index 00d77105161a..2c483e2cf9ec 100644 --- a/drivers/video/fbdev/hecubafb.c +++ b/drivers/video/fbdev/hecubafb.c @@ -204,6 +204,7 @@ static const struct fb_ops hecubafb_ops = { .fb_fillrect = hecubafb_fillrect, .fb_copyarea = hecubafb_copyarea, .fb_imageblit = hecubafb_imageblit, + .fb_mmap = fb_deferred_io_mmap, }; static struct fb_deferred_io hecubafb_defio = { diff --git a/drivers/video/fbdev/hyperv_fb.c b/drivers/video/fbdev/hyperv_fb.c index c8e0ea27caf1..d7f6abf827b9 100644 --- a/drivers/video/fbdev/hyperv_fb.c +++ b/drivers/video/fbdev/hyperv_fb.c @@ -909,6 +909,7 @@ static const struct fb_ops hvfb_ops = { .fb_copyarea = hvfb_cfb_copyarea, .fb_imageblit = hvfb_cfb_imageblit, .fb_blank = hvfb_blank, + .fb_mmap = fb_deferred_io_mmap, }; diff --git a/drivers/video/fbdev/metronomefb.c b/drivers/video/fbdev/metronomefb.c index af858dd23ea6..2541f2fe065b 100644 --- a/drivers/video/fbdev/metronomefb.c +++ b/drivers/video/fbdev/metronomefb.c @@ -564,6 +564,7 @@ static const struct fb_ops metronomefb_ops = { .fb_fillrect = metronomefb_fillrect, .fb_copyarea = metronomefb_copyarea, .fb_imageblit = metronomefb_imageblit, + .fb_mmap = fb_deferred_io_mmap, }; static struct fb_deferred_io metronomefb_defio = { diff --git a/drivers/video/fbdev/sh_mobile_lcdcfb.c b/drivers/video/fbdev/sh_mobile_lcdcfb.c index aa4ebe3192ec..1dc5079e4518 100644 --- a/drivers/video/fbdev/sh_mobile_lcdcfb.c +++ b/drivers/video/fbdev/sh_mobile_lcdcfb.c @@ -1483,6 +1483,9 @@ sh_mobile_lcdc_overlay_mmap(struct fb_info *info, struct vm_area_struct *vma) { struct sh_mobile_lcdc_overlay *ovl = info->par; + if (info->fbdefio) + return fb_deferred_io_mmap(info, vma); + return dma_mmap_coherent(ovl->channel->lcdc->dev, vma, ovl->fb_mem, ovl->dma_handle, ovl->fb_size); } @@ -1957,6 +1960,9 @@ sh_mobile_lcdc_mmap(struct fb_info *info, struct vm_area_struct *vma) { struct sh_mobile_lcdc_chan *ch = info->par; + if (info->fbdefio) + return fb_deferred_io_mmap(info, vma); + return dma_mmap_coherent(ch->lcdc->dev, vma, ch->fb_mem, ch->dma_handle, ch->fb_size); } diff --git a/drivers/video/fbdev/smscufx.c b/drivers/video/fbdev/smscufx.c index bfac3ee4a642..10eb56feff0a 100644 --- a/drivers/video/fbdev/smscufx.c +++ b/drivers/video/fbdev/smscufx.c @@ -779,6 +779,9 @@ static int ufx_ops_mmap(struct fb_info *info, struct vm_area_struct *vma) unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; unsigned long page, pos; + if (info->fbdefio) + return fb_deferred_io_mmap(info, vma); + if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) return -EINVAL; if (size > info->fix.smem_len) diff --git a/drivers/video/fbdev/ssd1307fb.c b/drivers/video/fbdev/ssd1307fb.c index 1e2f71c2f8a8..5eed08bb165b 100644 --- a/drivers/video/fbdev/ssd1307fb.c +++ b/drivers/video/fbdev/ssd1307fb.c @@ -368,6 +368,7 @@ static const struct fb_ops ssd1307fb_ops = { .fb_fillrect = ssd1307fb_fillrect, .fb_copyarea = ssd1307fb_copyarea, .fb_imageblit = ssd1307fb_imageblit, + .fb_mmap = fb_deferred_io_mmap, }; static void ssd1307fb_deferred_io(struct fb_info *info, diff --git a/drivers/video/fbdev/udlfb.c b/drivers/video/fbdev/udlfb.c index 184bb8433b78..d7f02b935eb2 100644 --- a/drivers/video/fbdev/udlfb.c +++ b/drivers/video/fbdev/udlfb.c @@ -326,6 +326,9 @@ static int dlfb_ops_mmap(struct fb_info *info, struct vm_area_struct *vma) unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; unsigned long page, pos; + if (info->fbdefio) + return fb_deferred_io_mmap(info, vma); + if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) return -EINVAL; if (size > info->fix.smem_len) diff --git a/drivers/video/fbdev/xen-fbfront.c b/drivers/video/fbdev/xen-fbfront.c index 6826f986da43..6c8846eba2fb 100644 --- a/drivers/video/fbdev/xen-fbfront.c +++ b/drivers/video/fbdev/xen-fbfront.c @@ -338,6 +338,7 @@ static const struct fb_ops xenfb_fb_ops = { .fb_imageblit = xenfb_imageblit, .fb_check_var = xenfb_check_var, .fb_set_par = xenfb_set_par, + .fb_mmap = fb_deferred_io_mmap, }; static irqreturn_t xenfb_event_handler(int rq, void *dev_id) From patchwork Thu Mar 3 20:58:33 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Thomas Zimmermann X-Patchwork-Id: 547951 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id E1877C4321E for ; Thu, 3 Mar 2022 20:58:47 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236389AbiCCU7c (ORCPT ); Thu, 3 Mar 2022 15:59:32 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58914 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236368AbiCCU7a (ORCPT ); Thu, 3 Mar 2022 15:59:30 -0500 Received: from smtp-out2.suse.de (smtp-out2.suse.de [195.135.220.29]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D17633FD9F for ; Thu, 3 Mar 2022 12:58:43 -0800 (PST) Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out2.suse.de (Postfix) with ESMTPS id 316621F382; Thu, 3 Mar 2022 20:58:42 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1646341122; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=pfEpk50UyT3t2wwY9lhdn3YpUW2SV41uStI58pIzNqU=; b=al74VehcdlZHORvrbqQF/Tr1udMVAKRTJoLCTnm/1L3q7uZbfeBwKBbv08DPFcoynMURXe PNiqcEq0i9RSUaZ5XZ4hinDKOtRMOI3m4tQ9YgXbiMsRdTiPFVPxWIhQZNjR6HS0alY3kz TehrIQiEow3w7lI6fc9OsJfKy52p7vU= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1646341122; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=pfEpk50UyT3t2wwY9lhdn3YpUW2SV41uStI58pIzNqU=; b=YX1bb7vvHYjN65pkussmAq+cpI9E1X6CT3+CWhIY8WMRJuPoIxNndj0aIr24tIRxzuRqyQ fkXmUXbX6KrC4XBg== Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap2.suse-dmz.suse.de (Postfix) with ESMTPS id E8D9713AEE; Thu, 3 Mar 2022 20:58:41 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id 6BLmNwEsIWJoHAAAMHmgww (envelope-from ); Thu, 03 Mar 2022 20:58:41 +0000 From: Thomas Zimmermann To: daniel@ffwll.ch, airlied@linux.ie, mripard@kernel.org, maarten.lankhorst@linux.intel.com, deller@gmx.de, javierm@redhat.com Cc: dri-devel@lists.freedesktop.org, linux-fbdev@vger.kernel.org, Thomas Zimmermann Subject: [PATCH 3/9] fbdev: Track deferred-I/O pages in pageref struct Date: Thu, 3 Mar 2022 21:58:33 +0100 Message-Id: <20220303205839.28484-4-tzimmermann@suse.de> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220303205839.28484-1-tzimmermann@suse.de> References: <20220303205839.28484-1-tzimmermann@suse.de> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fbdev@vger.kernel.org Store the per-page state for fbdev's deferred I/O in struct fb_deferred_io_pageref. Maintain a list of pagerefs for the pages that have to be flushed out to video memory. Update all affected drivers. Like with pages before, fbdev acquires a pageref when an mmaped page of the framebuffer is being written to. It holds the pageref in a list of all currently written pagerefs until it flushes the written pages to video memory. Writeback occurs periodically. After writeback fbdev releases all pagerefs and builds up a new dirty list until the next writeback occurs. Using pagerefs has a number of benefits. For pages of the framebuffer, the deferred I/O code used struct page.lru as an entry into the list of dirty pages. The lru field is owned by the page cache, which makes deferred I/O incompatible with some memory pages (e.g., most notably DRM's GEM SHMEM allocator). struct fb_deferred_io_pageref now provides an entry into a list of dirty framebuffer pages, free'ing lru for use with the page cache. Drivers also assumed that struct page.index is the page offset into the framebuffer. This is not true for DRM buffers, which are located at various offset within a mapped area. struct fb_deferred_io_pageref explicitly stores an offset into the framebuffer. struct page.index is now only the page offset into the mapped area. These changes will allow DRM to use fbdev deferred I/O without an intermediate shadow buffer. Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas --- drivers/gpu/drm/drm_fb_helper.c | 6 +- drivers/gpu/drm/vmwgfx/vmwgfx_fb.c | 5 +- drivers/staging/fbtft/fbtft-core.c | 5 +- drivers/video/fbdev/broadsheetfb.c | 5 +- drivers/video/fbdev/core/fb_defio.c | 153 +++++++++++++++++-------- drivers/video/fbdev/hyperv_fb.c | 5 +- drivers/video/fbdev/metronomefb.c | 5 +- drivers/video/fbdev/sh_mobile_lcdcfb.c | 6 +- drivers/video/fbdev/smscufx.c | 5 +- drivers/video/fbdev/udlfb.c | 5 +- drivers/video/fbdev/xen-fbfront.c | 5 +- include/linux/fb.h | 11 +- 12 files changed, 147 insertions(+), 69 deletions(-) diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index d06ce0e92d66..dd1d72d58b35 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -717,13 +717,13 @@ void drm_fb_helper_deferred_io(struct fb_info *info, struct list_head *pagelist) { unsigned long start, end, min, max; - struct page *page; + struct fb_deferred_io_pageref *pageref; struct drm_rect damage_area; min = ULONG_MAX; max = 0; - list_for_each_entry(page, pagelist, lru) { - start = page->index << PAGE_SHIFT; + list_for_each_entry(pageref, pagelist, list) { + start = pageref->offset; end = start + PAGE_SIZE; min = min(min, start); max = max(max, end); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c index 33f355907fbb..a35f695727c9 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c @@ -322,12 +322,13 @@ static void vmw_deferred_io(struct fb_info *info, struct vmw_fb_par *par = info->par; unsigned long start, end, min, max; unsigned long flags; - struct page *page; + struct fb_deferred_io_pageref *pageref; int y1, y2; min = ULONG_MAX; max = 0; - list_for_each_entry(page, pagelist, lru) { + list_for_each_entry(pageref, pagelist, list) { + struct page *page = pageref->page; start = page->index << PAGE_SHIFT; end = start + PAGE_SIZE - 1; min = min(min, start); diff --git a/drivers/staging/fbtft/fbtft-core.c b/drivers/staging/fbtft/fbtft-core.c index 60c55451e414..8c596c7948f5 100644 --- a/drivers/staging/fbtft/fbtft-core.c +++ b/drivers/staging/fbtft/fbtft-core.c @@ -326,7 +326,7 @@ static void fbtft_deferred_io(struct fb_info *info, struct list_head *pagelist) { struct fbtft_par *par = info->par; unsigned int dirty_lines_start, dirty_lines_end; - struct page *page; + struct fb_deferred_io_pageref *pageref; unsigned long index; unsigned int y_low = 0, y_high = 0; int count = 0; @@ -340,7 +340,8 @@ static void fbtft_deferred_io(struct fb_info *info, struct list_head *pagelist) spin_unlock(&par->dirty_lock); /* Mark display lines as dirty */ - list_for_each_entry(page, pagelist, lru) { + list_for_each_entry(pageref, pagelist, list) { + struct page *page = pageref->page; count++; index = page->index << PAGE_SHIFT; y_low = index / info->fix.line_length; diff --git a/drivers/video/fbdev/broadsheetfb.c b/drivers/video/fbdev/broadsheetfb.c index 528bc0902338..6afc6ef4cb5e 100644 --- a/drivers/video/fbdev/broadsheetfb.c +++ b/drivers/video/fbdev/broadsheetfb.c @@ -934,7 +934,7 @@ static void broadsheetfb_dpy_deferred_io(struct fb_info *info, { u16 y1 = 0, h = 0; int prev_index = -1; - struct page *cur; + struct fb_deferred_io_pageref *pageref; struct fb_deferred_io *fbdefio = info->fbdefio; int h_inc; u16 yres = info->var.yres; @@ -944,7 +944,8 @@ static void broadsheetfb_dpy_deferred_io(struct fb_info *info, h_inc = DIV_ROUND_UP(PAGE_SIZE , xres); /* walk the written page list and swizzle the data */ - list_for_each_entry(cur, &fbdefio->pagelist, lru) { + list_for_each_entry(pageref, &fbdefio->pagelist, list) { + struct page *cur = pageref->page; if (prev_index < 0) { /* just starting so assign first page */ y1 = (cur->index << PAGE_SHIFT) / xres; diff --git a/drivers/video/fbdev/core/fb_defio.c b/drivers/video/fbdev/core/fb_defio.c index 662bb5d2b872..20c6eb94a685 100644 --- a/drivers/video/fbdev/core/fb_defio.c +++ b/drivers/video/fbdev/core/fb_defio.c @@ -36,6 +36,60 @@ static struct page *fb_deferred_io_page(struct fb_info *info, unsigned long offs return page; } +static struct fb_deferred_io_pageref *fb_deferred_io_pageref_get(struct fb_info *info, + unsigned long offset, + struct page *page) +{ + struct fb_deferred_io *fbdefio = info->fbdefio; + struct list_head *pos = &fbdefio->pagelist; + unsigned long pgoff = offset >> PAGE_SHIFT; + struct fb_deferred_io_pageref *pageref, *cur; + + if (WARN_ON_ONCE(pgoff >= info->npagerefs)) + return NULL; /* incorrect allocation size */ + + /* 1:1 mapping between pageref and page offset */ + pageref = &info->pagerefs[pgoff]; + + /* + * This check is to catch the case where a new process could start + * writing to the same page through a new PTE. This new access + * can cause a call to .page_mkwrite even if the original process' + * PTE is marked writable. + */ + if (!list_empty(&pageref->list)) + goto pageref_already_added; + + pageref->page = page; + pageref->offset = pgoff << PAGE_SHIFT; + + if (unlikely(fbdefio->sort_pagelist)) { + /* + * We loop through the list of pagerefs before adding, in + * order to keep the pagerefs sorted. This has significant + * overhead of O(n^2) with n being the number of written + * pages. If possible, drivers should try to work with + * unsorted page lists instead. + */ + list_for_each_entry(cur, &info->fbdefio->pagelist, list) { + if (cur > pageref) + break; + } + pos = &cur->list; + } + + list_add_tail(&pageref->list, pos); + +pageref_already_added: + return pageref; +} + +static void fb_deferred_io_pageref_put(struct fb_deferred_io_pageref *pageref, + struct fb_info *info) +{ + list_del_init(&pageref->list); +} + /* this is to find and return the vmalloc-ed fb pages */ static vm_fault_t fb_deferred_io_fault(struct vm_fault *vmf) { @@ -59,8 +113,7 @@ static vm_fault_t fb_deferred_io_fault(struct vm_fault *vmf) printk(KERN_ERR "no mapping available\n"); BUG_ON(!page->mapping); - INIT_LIST_HEAD(&page->lru); - page->index = vmf->pgoff; + page->index = vmf->pgoff; /* for page_mkclean() */ vmf->page = page; return 0; @@ -96,7 +149,11 @@ static vm_fault_t fb_deferred_io_mkwrite(struct vm_fault *vmf) struct page *page = vmf->page; struct fb_info *info = vmf->vma->vm_private_data; struct fb_deferred_io *fbdefio = info->fbdefio; - struct list_head *pos = &fbdefio->pagelist; + struct fb_deferred_io_pageref *pageref; + unsigned long offset; + vm_fault_t ret; + + offset = (vmf->address - vmf->vma->vm_start); /* this is a callback we get when userspace first tries to write to the page. we schedule a workqueue. that workqueue @@ -113,6 +170,12 @@ static vm_fault_t fb_deferred_io_mkwrite(struct vm_fault *vmf) if (fbdefio->first_io && list_empty(&fbdefio->pagelist)) fbdefio->first_io(info); + pageref = fb_deferred_io_pageref_get(info, offset, page); + if (WARN_ON_ONCE(!pageref)) { + ret = VM_FAULT_OOM; + goto err_mutex_unlock; + } + /* * We want the page to remain locked from ->page_mkwrite until * the PTE is marked dirty to avoid page_mkclean() being called @@ -121,47 +184,17 @@ static vm_fault_t fb_deferred_io_mkwrite(struct vm_fault *vmf) * Do this by locking the page here and informing the caller * about it with VM_FAULT_LOCKED. */ - lock_page(page); - - /* - * This check is to catch the case where a new process could start - * writing to the same page through a new PTE. This new access - * can cause a call to .page_mkwrite even if the original process' - * PTE is marked writable. - * - * TODO: The lru field is owned by the page cache; hence the name. - * We dequeue in fb_deferred_io_work() after flushing the - * page's content into video memory. Instead of lru, fbdefio - * should have it's own field. - */ - if (!list_empty(&page->lru)) - goto page_already_added; - - if (unlikely(fbdefio->sort_pagelist)) { - /* - * We loop through the pagelist before adding in order to - * keep the pagelist sorted. This has significant overhead - * of O(n^2) with n being the number of written pages. If - * possible, drivers should try to work with unsorted page - * lists instead. - */ - struct page *cur; - - list_for_each_entry(cur, &fbdefio->pagelist, lru) { - if (cur->index > page->index) - break; - } - pos = &cur->lru; - } - - list_add_tail(&page->lru, pos); + lock_page(pageref->page); -page_already_added: mutex_unlock(&fbdefio->lock); /* come back after delay to process the deferred IO */ schedule_delayed_work(&info->deferred_work, fbdefio->delay); return VM_FAULT_LOCKED; + +err_mutex_unlock: + mutex_unlock(&fbdefio->lock); + return ret; } static const struct vm_operations_struct fb_deferred_io_vm_ops = { @@ -194,15 +227,14 @@ EXPORT_SYMBOL_GPL(fb_deferred_io_mmap); /* workqueue callback */ static void fb_deferred_io_work(struct work_struct *work) { - struct fb_info *info = container_of(work, struct fb_info, - deferred_work.work); - struct list_head *node, *next; - struct page *cur; + struct fb_info *info = container_of(work, struct fb_info, deferred_work.work); + struct fb_deferred_io_pageref *pageref, *next; struct fb_deferred_io *fbdefio = info->fbdefio; /* here we mkclean the pages, then do all deferred IO */ mutex_lock(&fbdefio->lock); - list_for_each_entry(cur, &fbdefio->pagelist, lru) { + list_for_each_entry(pageref, &fbdefio->pagelist, list) { + struct page *cur = pageref->page; lock_page(cur); page_mkclean(cur); unlock_page(cur); @@ -212,22 +244,48 @@ static void fb_deferred_io_work(struct work_struct *work) fbdefio->deferred_io(info, &fbdefio->pagelist); /* clear the list */ - list_for_each_safe(node, next, &fbdefio->pagelist) { - list_del_init(node); - } + list_for_each_entry_safe(pageref, next, &fbdefio->pagelist, list) + fb_deferred_io_pageref_put(pageref, info); + mutex_unlock(&fbdefio->lock); } -void fb_deferred_io_init(struct fb_info *info) +int fb_deferred_io_init(struct fb_info *info) { struct fb_deferred_io *fbdefio = info->fbdefio; + struct fb_deferred_io_pageref *pagerefs; + unsigned long npagerefs, i; + int ret; BUG_ON(!fbdefio); + + if (WARN_ON(!info->fix.smem_len)) + return -EINVAL; + mutex_init(&fbdefio->lock); INIT_DELAYED_WORK(&info->deferred_work, fb_deferred_io_work); INIT_LIST_HEAD(&fbdefio->pagelist); if (fbdefio->delay == 0) /* set a default of 1 s */ fbdefio->delay = HZ; + + npagerefs = DIV_ROUND_UP(info->fix.smem_len, PAGE_SIZE); + + /* alloc a page ref for each page of the display memory */ + pagerefs = kvcalloc(npagerefs, sizeof(*pagerefs), GFP_KERNEL); + if (!pagerefs) { + ret = -ENOMEM; + goto err; + } + for (i = 0; i < npagerefs; ++i) + INIT_LIST_HEAD(&pagerefs[i].list); + info->npagerefs = npagerefs; + info->pagerefs = pagerefs; + + return 0; + +err: + mutex_destroy(&fbdefio->lock); + return ret; } EXPORT_SYMBOL_GPL(fb_deferred_io_init); @@ -254,6 +312,7 @@ void fb_deferred_io_cleanup(struct fb_info *info) page->mapping = NULL; } + kvfree(info->pagerefs); mutex_destroy(&fbdefio->lock); } EXPORT_SYMBOL_GPL(fb_deferred_io_cleanup); diff --git a/drivers/video/fbdev/hyperv_fb.c b/drivers/video/fbdev/hyperv_fb.c index d7f6abf827b9..51eb57ea68f7 100644 --- a/drivers/video/fbdev/hyperv_fb.c +++ b/drivers/video/fbdev/hyperv_fb.c @@ -424,7 +424,7 @@ static void synthvid_deferred_io(struct fb_info *p, struct list_head *pagelist) { struct hvfb_par *par = p->par; - struct page *page; + struct fb_deferred_io_pageref *pageref; unsigned long start, end; int y1, y2, miny, maxy; @@ -437,7 +437,8 @@ static void synthvid_deferred_io(struct fb_info *p, * in synthvid_update function by clamping the y2 * value to yres. */ - list_for_each_entry(page, pagelist, lru) { + list_for_each_entry(pageref, pagelist, list) { + struct page *page = pageref->page; start = page->index << PAGE_SHIFT; end = start + PAGE_SIZE - 1; y1 = start / p->fix.line_length; diff --git a/drivers/video/fbdev/metronomefb.c b/drivers/video/fbdev/metronomefb.c index 2541f2fe065b..8352fa3f4cef 100644 --- a/drivers/video/fbdev/metronomefb.c +++ b/drivers/video/fbdev/metronomefb.c @@ -469,12 +469,13 @@ static void metronomefb_dpy_deferred_io(struct fb_info *info, struct list_head *pagelist) { u16 cksum; - struct page *cur; + struct fb_deferred_io_pageref *pageref; struct fb_deferred_io *fbdefio = info->fbdefio; struct metronomefb_par *par = info->par; /* walk the written page list and swizzle the data */ - list_for_each_entry(cur, &fbdefio->pagelist, lru) { + list_for_each_entry(pageref, &fbdefio->pagelist, list) { + struct page *cur = pageref->page; cksum = metronomefb_dpy_update_page(par, (cur->index << PAGE_SHIFT)); par->metromem_img_csum -= par->csum_table[cur->index]; diff --git a/drivers/video/fbdev/sh_mobile_lcdcfb.c b/drivers/video/fbdev/sh_mobile_lcdcfb.c index 1dc5079e4518..7fcc85352033 100644 --- a/drivers/video/fbdev/sh_mobile_lcdcfb.c +++ b/drivers/video/fbdev/sh_mobile_lcdcfb.c @@ -440,13 +440,15 @@ static int sh_mobile_lcdc_sginit(struct fb_info *info, { struct sh_mobile_lcdc_chan *ch = info->par; unsigned int nr_pages_max = ch->fb_size >> PAGE_SHIFT; - struct page *page; + struct fb_deferred_io_pageref *pageref; int nr_pages = 0; sg_init_table(ch->sglist, nr_pages_max); - list_for_each_entry(page, pagelist, lru) + list_for_each_entry(pageref, pagelist, list) { + struct page *page = pageref->page; sg_set_page(&ch->sglist[nr_pages++], page, PAGE_SIZE, 0); + } return nr_pages; } diff --git a/drivers/video/fbdev/smscufx.c b/drivers/video/fbdev/smscufx.c index 10eb56feff0a..cabc3d03897c 100644 --- a/drivers/video/fbdev/smscufx.c +++ b/drivers/video/fbdev/smscufx.c @@ -958,7 +958,7 @@ static void ufx_ops_fillrect(struct fb_info *info, static void ufx_dpy_deferred_io(struct fb_info *info, struct list_head *pagelist) { - struct page *cur; + struct fb_deferred_io_pageref *pageref; struct fb_deferred_io *fbdefio = info->fbdefio; struct ufx_data *dev = info->par; @@ -969,9 +969,10 @@ static void ufx_dpy_deferred_io(struct fb_info *info, return; /* walk the written page list and render each to device */ - list_for_each_entry(cur, &fbdefio->pagelist, lru) { + list_for_each_entry(pageref, &fbdefio->pagelist, list) { /* create a rectangle of full screen width that encloses the * entire dirty framebuffer page */ + struct page *cur = pageref->page; const int x = 0; const int width = dev->info->var.xres; const int y = (cur->index << PAGE_SHIFT) / (width * 2); diff --git a/drivers/video/fbdev/udlfb.c b/drivers/video/fbdev/udlfb.c index d7f02b935eb2..2d971c45bd93 100644 --- a/drivers/video/fbdev/udlfb.c +++ b/drivers/video/fbdev/udlfb.c @@ -784,7 +784,7 @@ static void dlfb_ops_fillrect(struct fb_info *info, static void dlfb_dpy_deferred_io(struct fb_info *info, struct list_head *pagelist) { - struct page *cur; + struct fb_deferred_io_pageref *pageref; struct fb_deferred_io *fbdefio = info->fbdefio; struct dlfb_data *dlfb = info->par; struct urb *urb; @@ -811,7 +811,8 @@ static void dlfb_dpy_deferred_io(struct fb_info *info, cmd = urb->transfer_buffer; /* walk the written page list and render each to device */ - list_for_each_entry(cur, &fbdefio->pagelist, lru) { + list_for_each_entry(pageref, &fbdefio->pagelist, list) { + struct page *cur = pageref->page; if (dlfb_render_hline(dlfb, &urb, (char *) info->fix.smem_start, &cmd, cur->index << PAGE_SHIFT, diff --git a/drivers/video/fbdev/xen-fbfront.c b/drivers/video/fbdev/xen-fbfront.c index 6c8846eba2fb..608fcde767d3 100644 --- a/drivers/video/fbdev/xen-fbfront.c +++ b/drivers/video/fbdev/xen-fbfront.c @@ -185,13 +185,14 @@ static void xenfb_deferred_io(struct fb_info *fb_info, struct list_head *pagelist) { struct xenfb_info *info = fb_info->par; - struct page *page; + struct fb_deferred_io_pageref *pageref; unsigned long beg, end; int y1, y2, miny, maxy; miny = INT_MAX; maxy = 0; - list_for_each_entry(page, pagelist, lru) { + list_for_each_entry(pageref, pagelist, list) { + struct page *page = pageref->page; beg = page->index << PAGE_SHIFT; end = beg + PAGE_SIZE - 1; y1 = beg / fb_info->fix.line_length; diff --git a/include/linux/fb.h b/include/linux/fb.h index 9a77ab615c36..768de6534a82 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h @@ -201,6 +201,13 @@ struct fb_pixmap { }; #ifdef CONFIG_FB_DEFERRED_IO +struct fb_deferred_io_pageref { + struct page *page; + unsigned long offset; + /* private */ + struct list_head list; +}; + struct fb_deferred_io { /* delay between mkwrite and deferred handler */ unsigned long delay; @@ -469,6 +476,8 @@ struct fb_info { #endif #ifdef CONFIG_FB_DEFERRED_IO struct delayed_work deferred_work; + unsigned long npagerefs; + struct fb_deferred_io_pageref *pagerefs; struct fb_deferred_io *fbdefio; #endif @@ -662,7 +671,7 @@ static inline void __fb_pad_aligned_buffer(u8 *dst, u32 d_pitch, /* drivers/video/fb_defio.c */ int fb_deferred_io_mmap(struct fb_info *info, struct vm_area_struct *vma); -extern void fb_deferred_io_init(struct fb_info *info); +extern int fb_deferred_io_init(struct fb_info *info); extern void fb_deferred_io_open(struct fb_info *info, struct inode *inode, struct file *file); From patchwork Thu Mar 3 20:58:34 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Thomas Zimmermann X-Patchwork-Id: 547952 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id B0219C433FE for ; Thu, 3 Mar 2022 20:58:46 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236384AbiCCU7b (ORCPT ); Thu, 3 Mar 2022 15:59:31 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58840 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236378AbiCCU7a (ORCPT ); Thu, 3 Mar 2022 15:59:30 -0500 Received: from smtp-out1.suse.de (smtp-out1.suse.de [195.135.220.28]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D1CAB45AC0 for ; Thu, 3 Mar 2022 12:58:43 -0800 (PST) Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out1.suse.de (Postfix) with ESMTPS id 656C8218DF; Thu, 3 Mar 2022 20:58:42 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1646341122; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=2ZtguNSgg1NDddm00GNZoC9vZyrOz7spcYQMWL43ODc=; b=PuEJIpxoROvq+bRS7uWsQbRtB2OJunOblB+Ls7ey5o7JHNsJiN8AAcXIi6pqhJqDwyaIfB D/XNqecVqmF8yuhAn1Q3ftQ8DVe8kior7SIc0O8VTpJ3A4A/UXMBGw0EnwZMxTWUVDCJj5 WO0dBKfSgB/IKwDpV3uhVk99XMXDc/Q= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1646341122; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=2ZtguNSgg1NDddm00GNZoC9vZyrOz7spcYQMWL43ODc=; b=KnrPv3pEeHNUVwoOoUNGqigtiie3T29tWUVxyr/z09kq5hD/IbU+Ql7Z4aSg0lSP5KOWka yW26wce+QabDTZCw== Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap2.suse-dmz.suse.de (Postfix) with ESMTPS id 35293139B5; Thu, 3 Mar 2022 20:58:42 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id GPIMDAIsIWJoHAAAMHmgww (envelope-from ); Thu, 03 Mar 2022 20:58:42 +0000 From: Thomas Zimmermann To: daniel@ffwll.ch, airlied@linux.ie, mripard@kernel.org, maarten.lankhorst@linux.intel.com, deller@gmx.de, javierm@redhat.com Cc: dri-devel@lists.freedesktop.org, linux-fbdev@vger.kernel.org, Thomas Zimmermann Subject: [PATCH 4/9] fbdev: Export helper for implementing page_mkwrite Date: Thu, 3 Mar 2022 21:58:34 +0100 Message-Id: <20220303205839.28484-5-tzimmermann@suse.de> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220303205839.28484-1-tzimmermann@suse.de> References: <20220303205839.28484-1-tzimmermann@suse.de> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fbdev@vger.kernel.org Refactor the page-write handler and export it as helper function fb_deferred_io_page_mkwrite(). Drivers that implement struct vm_operations_struct.page_mkwrite for deferred I/O should use the function to let fbdev track written pages of mmap'ed framebuffer memory. Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas --- drivers/video/fbdev/core/fb_defio.c | 69 ++++++++++++++++++++--------- include/linux/fb.h | 1 + 2 files changed, 50 insertions(+), 20 deletions(-) diff --git a/drivers/video/fbdev/core/fb_defio.c b/drivers/video/fbdev/core/fb_defio.c index 20c6eb94a685..8cd40b1714d4 100644 --- a/drivers/video/fbdev/core/fb_defio.c +++ b/drivers/video/fbdev/core/fb_defio.c @@ -143,29 +143,18 @@ int fb_deferred_io_fsync(struct file *file, loff_t start, loff_t end, int datasy } EXPORT_SYMBOL_GPL(fb_deferred_io_fsync); -/* vm_ops->page_mkwrite handler */ -static vm_fault_t fb_deferred_io_mkwrite(struct vm_fault *vmf) +/* + * Adds a page to the dirty list. Requires caller to hold + * struct fb_deferred_io.lock. Call this from struct + * vm_operations_struct.page_mkwrite. + */ +static vm_fault_t __fb_deferred_io_track_page(struct fb_info *info, unsigned long offset, + struct page *page) { - struct page *page = vmf->page; - struct fb_info *info = vmf->vma->vm_private_data; struct fb_deferred_io *fbdefio = info->fbdefio; struct fb_deferred_io_pageref *pageref; - unsigned long offset; vm_fault_t ret; - offset = (vmf->address - vmf->vma->vm_start); - - /* this is a callback we get when userspace first tries to - write to the page. we schedule a workqueue. that workqueue - will eventually mkclean the touched pages and execute the - deferred framebuffer IO. then if userspace touches a page - again, we repeat the same scheme */ - - file_update_time(vmf->vma->vm_file); - - /* protect against the workqueue changing the page list */ - mutex_lock(&fbdefio->lock); - /* first write in this cycle, notify the driver */ if (fbdefio->first_io && list_empty(&fbdefio->pagelist)) fbdefio->first_io(info); @@ -186,8 +175,6 @@ static vm_fault_t fb_deferred_io_mkwrite(struct vm_fault *vmf) */ lock_page(pageref->page); - mutex_unlock(&fbdefio->lock); - /* come back after delay to process the deferred IO */ schedule_delayed_work(&info->deferred_work, fbdefio->delay); return VM_FAULT_LOCKED; @@ -197,6 +184,48 @@ static vm_fault_t fb_deferred_io_mkwrite(struct vm_fault *vmf) return ret; } +/** + * fb_deferred_io_page_mkwrite - Mark a page as written for deferred I/O + * @fb_info: The fbdev info structure + * @vmf: The VM fault + * + * This is a callback we get when userspace first tries to + * write to the page. We schedule a workqueue. That workqueue + * will eventually mkclean the touched pages and execute the + * deferred framebuffer IO. Then if userspace touches a page + * again, we repeat the same scheme. + * + * Returns: + * VM_FAULT_LOCKED on success, or a VM_FAULT error otherwise. + */ +vm_fault_t fb_deferred_io_page_mkwrite(struct fb_info *info, struct vm_fault *vmf) +{ + struct page *page = vmf->page; + struct fb_deferred_io *fbdefio = info->fbdefio; + unsigned long offset; + vm_fault_t ret; + + offset = (vmf->address - vmf->vma->vm_start); + + file_update_time(vmf->vma->vm_file); + + /* protect against the workqueue changing the page list */ + mutex_lock(&fbdefio->lock); + ret = __fb_deferred_io_track_page(info, offset, page); + mutex_unlock(&fbdefio->lock); + + return ret; +} +EXPORT_SYMBOL_GPL(fb_deferred_io_page_mkwrite); + +/* vm_ops->page_mkwrite handler */ +static vm_fault_t fb_deferred_io_mkwrite(struct vm_fault *vmf) +{ + struct fb_info *info = vmf->vma->vm_private_data; + + return fb_deferred_io_page_mkwrite(info, vmf); +} + static const struct vm_operations_struct fb_deferred_io_vm_ops = { .fault = fb_deferred_io_fault, .page_mkwrite = fb_deferred_io_mkwrite, diff --git a/include/linux/fb.h b/include/linux/fb.h index 768de6534a82..631a1d0cb193 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h @@ -670,6 +670,7 @@ static inline void __fb_pad_aligned_buffer(u8 *dst, u32 d_pitch, } /* drivers/video/fb_defio.c */ +vm_fault_t fb_deferred_io_page_mkwrite(struct fb_info *info, struct vm_fault *vmf); int fb_deferred_io_mmap(struct fb_info *info, struct vm_area_struct *vma); extern int fb_deferred_io_init(struct fb_info *info); extern void fb_deferred_io_open(struct fb_info *info, From patchwork Thu Mar 3 20:58:35 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Thomas Zimmermann X-Patchwork-Id: 549513 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 51318C43217 for ; Thu, 3 Mar 2022 20:58:47 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236371AbiCCU7c (ORCPT ); Thu, 3 Mar 2022 15:59:32 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58874 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236389AbiCCU7a (ORCPT ); Thu, 3 Mar 2022 15:59:30 -0500 Received: from smtp-out2.suse.de (smtp-out2.suse.de [195.135.220.29]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 0CB6E10B8 for ; Thu, 3 Mar 2022 12:58:44 -0800 (PST) Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out2.suse.de (Postfix) with ESMTPS id 9BA461F384; Thu, 3 Mar 2022 20:58:42 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1646341122; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=xz+EWuGOcCKlWNC8BpC4SVb2gqsU7CykcjXYw0GYeHs=; b=UDnc5xL2HKjxfEO/VBwFEuv2e7tXEFGXbB6waE86361jRzfW9/eN0cbICa6zUMm4vO0hcY a0fbvqCzCXOBUbo6pPLmYwDCxr2f9k783gPrd3JK5SB1G8PGhCld29IP9vpYrB8qxiKvYv 2xoRA9o6n4+odN2GY+2QH+ZuLz+EhUU= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1646341122; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=xz+EWuGOcCKlWNC8BpC4SVb2gqsU7CykcjXYw0GYeHs=; b=1D9IW2gnLLzIifygDyWQGH6khUFAfSpjtmYjp44afBSulpPiCpMQnJOpm3pc7MBKkna69F x8xFghfciN/yZVAA== Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap2.suse-dmz.suse.de (Postfix) with ESMTPS id 69D1513AEE; Thu, 3 Mar 2022 20:58:42 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id 8ErUGAIsIWJoHAAAMHmgww (envelope-from ); Thu, 03 Mar 2022 20:58:42 +0000 From: Thomas Zimmermann To: daniel@ffwll.ch, airlied@linux.ie, mripard@kernel.org, maarten.lankhorst@linux.intel.com, deller@gmx.de, javierm@redhat.com Cc: dri-devel@lists.freedesktop.org, linux-fbdev@vger.kernel.org, Thomas Zimmermann Subject: [PATCH 5/9] drm/fb-helper: Separate deferred I/O from shadow buffers Date: Thu, 3 Mar 2022 21:58:35 +0100 Message-Id: <20220303205839.28484-6-tzimmermann@suse.de> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220303205839.28484-1-tzimmermann@suse.de> References: <20220303205839.28484-1-tzimmermann@suse.de> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fbdev@vger.kernel.org DRM drivers will be able to handle deferred I/O by themselves. So a driver will be able to use deferred I/O without an intermediate shadow buffer. Prepare fbdev emulation by separating shadow buffers and deferred I/O from each other. Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas --- drivers/gpu/drm/drm_fb_helper.c | 35 ++++++++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index dd1d72d58b35..660ec5038c4e 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -660,6 +660,19 @@ static bool drm_fbdev_use_shadow_fb(struct drm_fb_helper *fb_helper) fb->funcs->dirty; } +static bool drm_fbdev_use_deferred_io(struct drm_fb_helper *fb_helper) +{ + struct drm_framebuffer *fb = fb_helper->fb; + + /* + * Any driver with damage handling requires deferred I/O to + * keep track of the updated screen areas. Drivers with shadow + * buffers need deferred I/O to forward screen updates to the + * buffer object. + */ + return fb->funcs->dirty || drm_fbdev_use_shadow_fb(fb_helper); +} + static void drm_fb_helper_damage(struct fb_info *info, u32 x, u32 y, u32 width, u32 height) { @@ -667,7 +680,7 @@ static void drm_fb_helper_damage(struct fb_info *info, u32 x, u32 y, struct drm_clip_rect *clip = &helper->damage_clip; unsigned long flags; - if (!drm_fbdev_use_shadow_fb(helper)) + if (!drm_fbdev_use_deferred_io(helper)) return; spin_lock_irqsave(&helper->damage_lock, flags); @@ -2119,8 +2132,16 @@ static int drm_fbdev_fb_mmap(struct fb_info *info, struct vm_area_struct *vma) struct drm_fb_helper *fb_helper = info->par; if (drm_fbdev_use_shadow_fb(fb_helper)) + /* + * Drivers with shadow buffer use fbdev's implementation of + * deferred I/O. + */ return fb_deferred_io_mmap(info, vma); else if (fb_helper->dev->driver->gem_prime_mmap) + /* + * Either directly mmap'ed or with deferred I/O; drivers + * without shadow buffer handle mmap themselves. + */ return fb_helper->dev->driver->gem_prime_mmap(fb_helper->buffer->gem, vma); else return -ENODEV; @@ -2131,7 +2152,9 @@ static bool drm_fbdev_use_iomem(struct fb_info *info) struct drm_fb_helper *fb_helper = info->par; struct drm_client_buffer *buffer = fb_helper->buffer; - return !drm_fbdev_use_shadow_fb(fb_helper) && buffer->map.is_iomem; + if (drm_fbdev_use_shadow_fb(fb_helper)) + return false; + return buffer->map.is_iomem; } static ssize_t fb_read_screen_base(struct fb_info *info, char __user *buf, size_t count, @@ -2396,9 +2419,6 @@ static int drm_fb_helper_generic_probe(struct drm_fb_helper *fb_helper, if (!fbi->screen_buffer) return -ENOMEM; fbi->flags |= FBINFO_VIRTFB | FBINFO_READS_FAST; - - fbi->fbdefio = &drm_fbdev_defio; - fb_deferred_io_init(fbi); } else { /* buffer is mapped for HW framebuffer */ ret = drm_client_buffer_vmap(fb_helper->buffer, &map); @@ -2424,6 +2444,11 @@ static int drm_fb_helper_generic_probe(struct drm_fb_helper *fb_helper, #endif } + if (drm_fbdev_use_deferred_io(fb_helper)) { + fbi->fbdefio = &drm_fbdev_defio; + fb_deferred_io_init(fbi); + } + return 0; } From patchwork Thu Mar 3 20:58:36 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Thomas Zimmermann X-Patchwork-Id: 547950 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 2AD77C433EF for ; Thu, 3 Mar 2022 20:58:48 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236397AbiCCU7c (ORCPT ); Thu, 3 Mar 2022 15:59:32 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58916 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236392AbiCCU7a (ORCPT ); Thu, 3 Mar 2022 15:59:30 -0500 Received: from smtp-out1.suse.de (smtp-out1.suse.de [195.135.220.28]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 3DC2241F9C for ; Thu, 3 Mar 2022 12:58:44 -0800 (PST) Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out1.suse.de (Postfix) with ESMTPS id D559C218E6; Thu, 3 Mar 2022 20:58:42 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1646341122; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=L3e+1ciDGqD2s/iqm/ZtOxkRig2RHyQsLRvyc+Ijx30=; b=z2VZ8HWreTEYHvlzpcGMD2MLYq3WzmHOzU3FnYwvKlaQ+Cd13YetqnfrFNLvCHD8FIzYOC dfQnvBWqc8KGzSj/4NrxOqD391n3IxishT48IUR/1b06Z3+PMbtf4GJ++CXBbF4TgyIyd2 Py54C3DwApmX98A4U+XAZ+98m8Y94fE= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1646341122; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=L3e+1ciDGqD2s/iqm/ZtOxkRig2RHyQsLRvyc+Ijx30=; b=Q2BtL3LikJJbwh6KdXF9cU4EkHc+PB58UjQaBJL1nohl/OwogX9cApznDnpoEVJLdQtzJj 9ePCNPm4IWyxi6AQ== Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap2.suse-dmz.suse.de (Postfix) with ESMTPS id A15DD139B5; Thu, 3 Mar 2022 20:58:42 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id uBNoJgIsIWJoHAAAMHmgww (envelope-from ); Thu, 03 Mar 2022 20:58:42 +0000 From: Thomas Zimmermann To: daniel@ffwll.ch, airlied@linux.ie, mripard@kernel.org, maarten.lankhorst@linux.intel.com, deller@gmx.de, javierm@redhat.com Cc: dri-devel@lists.freedesktop.org, linux-fbdev@vger.kernel.org, Thomas Zimmermann Subject: [PATCH 6/9] drm/fb-helper: Provide callback to create fbdev dumb buffers Date: Thu, 3 Mar 2022 21:58:36 +0100 Message-Id: <20220303205839.28484-7-tzimmermann@suse.de> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220303205839.28484-1-tzimmermann@suse.de> References: <20220303205839.28484-1-tzimmermann@suse.de> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fbdev@vger.kernel.org Provide struct drm_driver.dumb_create_fbdev, a callback hook for fbdev dumb buffers. Wire up fbdev and client helpers to use the new interface, if present. This acknowledges the fact that fbdev buffers are different. The most significant difference to regular GEM BOs is in mmap semantics. Fbdev userspace treats the pages as video memory, which makes it impossible to ever move the mmap'ed buffer. Hence, drivers ussually have to pin the BO permanently or install an intermediate shadow buffer for mmap. So far, fbdev memory came from dumb buffers and DRM drivers had no means of detecting this without reimplementing a good part of the fbdev code. With the new callback, drivers can perma-pin fbdev buffer objects if needed. Several drivers also require damage handling, which fbdev implements with its deferred I/O helpers. The new callback allows a driver's memory manager to set up a suitable mmap. Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas --- drivers/gpu/drm/drm_client.c | 14 +++++++---- drivers/gpu/drm/drm_crtc_internal.h | 3 +++ drivers/gpu/drm/drm_dumb_buffers.c | 36 +++++++++++++++++++++++++---- drivers/gpu/drm/drm_fb_helper.c | 26 +++++++++++++++++---- include/drm/drm_client.h | 3 ++- include/drm/drm_drv.h | 17 ++++++++++++++ 6 files changed, 84 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/drm_client.c b/drivers/gpu/drm/drm_client.c index af3b7395bf69..c964064651d5 100644 --- a/drivers/gpu/drm/drm_client.c +++ b/drivers/gpu/drm/drm_client.c @@ -247,7 +247,8 @@ static void drm_client_buffer_delete(struct drm_client_buffer *buffer) } static struct drm_client_buffer * -drm_client_buffer_create(struct drm_client_dev *client, u32 width, u32 height, u32 format) +drm_client_buffer_create(struct drm_client_dev *client, u32 width, u32 height, u32 format, + bool fbdev) { const struct drm_format_info *info = drm_format_info(format); struct drm_mode_create_dumb dumb_args = { }; @@ -265,7 +266,10 @@ drm_client_buffer_create(struct drm_client_dev *client, u32 width, u32 height, u dumb_args.width = width; dumb_args.height = height; dumb_args.bpp = info->cpp[0] * 8; - ret = drm_mode_create_dumb(dev, &dumb_args, client->file); + if (fbdev) + ret = drm_mode_create_dumb_fbdev(dev, &dumb_args, client->file); + else + ret = drm_mode_create_dumb(dev, &dumb_args, client->file); if (ret) goto err_delete; @@ -402,6 +406,7 @@ static int drm_client_buffer_addfb(struct drm_client_buffer *buffer, * @width: Framebuffer width * @height: Framebuffer height * @format: Buffer format + * @fbdev: True if the client provides an fbdev device, or false otherwise * * This function creates a &drm_client_buffer which consists of a * &drm_framebuffer backed by a dumb buffer. @@ -411,12 +416,13 @@ static int drm_client_buffer_addfb(struct drm_client_buffer *buffer, * Pointer to a client buffer or an error pointer on failure. */ struct drm_client_buffer * -drm_client_framebuffer_create(struct drm_client_dev *client, u32 width, u32 height, u32 format) +drm_client_framebuffer_create(struct drm_client_dev *client, u32 width, u32 height, u32 format, + bool fbdev) { struct drm_client_buffer *buffer; int ret; - buffer = drm_client_buffer_create(client, width, height, format); + buffer = drm_client_buffer_create(client, width, height, format, fbdev); if (IS_ERR(buffer)) return buffer; diff --git a/drivers/gpu/drm/drm_crtc_internal.h b/drivers/gpu/drm/drm_crtc_internal.h index 63279e984342..34e532953b5a 100644 --- a/drivers/gpu/drm/drm_crtc_internal.h +++ b/drivers/gpu/drm/drm_crtc_internal.h @@ -101,6 +101,9 @@ int drm_mode_getresources(struct drm_device *dev, int drm_mode_create_dumb(struct drm_device *dev, struct drm_mode_create_dumb *args, struct drm_file *file_priv); +int drm_mode_create_dumb_fbdev(struct drm_device *dev, + struct drm_mode_create_dumb *args, + struct drm_file *file_priv); int drm_mode_destroy_dumb(struct drm_device *dev, u32 handle, struct drm_file *file_priv); diff --git a/drivers/gpu/drm/drm_dumb_buffers.c b/drivers/gpu/drm/drm_dumb_buffers.c index ad17fa21cebb..a605b4c4e4a3 100644 --- a/drivers/gpu/drm/drm_dumb_buffers.c +++ b/drivers/gpu/drm/drm_dumb_buffers.c @@ -57,14 +57,10 @@ * a hardware-specific ioctl to allocate suitable buffer objects. */ -int drm_mode_create_dumb(struct drm_device *dev, - struct drm_mode_create_dumb *args, - struct drm_file *file_priv) +static int drm_mode_sanitize_args(struct drm_mode_create_dumb *args) { u32 cpp, stride, size; - if (!dev->driver->dumb_create) - return -ENOSYS; if (!args->width || !args->height || !args->bpp) return -EINVAL; @@ -93,6 +89,21 @@ int drm_mode_create_dumb(struct drm_device *dev, args->pitch = 0; args->size = 0; + return 0; +} + +int drm_mode_create_dumb(struct drm_device *dev, + struct drm_mode_create_dumb *args, + struct drm_file *file_priv) +{ + int ret; + + if (!dev->driver->dumb_create) + return -ENOSYS; + ret = drm_mode_sanitize_args(args); + if (ret) + return ret; + return dev->driver->dumb_create(file_priv, dev, args); } @@ -102,6 +113,21 @@ int drm_mode_create_dumb_ioctl(struct drm_device *dev, return drm_mode_create_dumb(dev, data, file_priv); } +int drm_mode_create_dumb_fbdev(struct drm_device *dev, + struct drm_mode_create_dumb *args, + struct drm_file *file_priv) +{ + int ret; + + if (!dev->driver->dumb_create_fbdev) + return -ENOSYS; + ret = drm_mode_sanitize_args(args); + if (ret) + return ret; + + return dev->driver->dumb_create_fbdev(file_priv, dev, args); +} + /** * drm_mode_mmap_dumb_ioctl - create an mmap offset for a dumb backing storage buffer * @dev: DRM device diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 660ec5038c4e..9d1140a789f4 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -655,6 +655,15 @@ static bool drm_fbdev_use_shadow_fb(struct drm_fb_helper *fb_helper) struct drm_device *dev = fb_helper->dev; struct drm_framebuffer *fb = fb_helper->fb; + /* + * If the driver provides an fbdev create function, it is expected + * to provide its own implementation of deferred I/O. Shadow + * buffering can still be enabled with the prefer_shadow_fbdev + * flag. + */ + if (dev->driver->dumb_create_fbdev) + return dev->mode_config.prefer_shadow_fbdev; + return dev->mode_config.prefer_shadow_fbdev || dev->mode_config.prefer_shadow || fb->funcs->dirty; @@ -2130,6 +2139,7 @@ static void drm_fbdev_fb_destroy(struct fb_info *info) static int drm_fbdev_fb_mmap(struct fb_info *info, struct vm_area_struct *vma) { struct drm_fb_helper *fb_helper = info->par; + struct drm_device *dev = fb_helper->dev; if (drm_fbdev_use_shadow_fb(fb_helper)) /* @@ -2137,14 +2147,20 @@ static int drm_fbdev_fb_mmap(struct fb_info *info, struct vm_area_struct *vma) * deferred I/O. */ return fb_deferred_io_mmap(info, vma); - else if (fb_helper->dev->driver->gem_prime_mmap) + else if (!dev->driver->dumb_create_fbdev && drm_fbdev_use_deferred_io(fb_helper)) + /* + * Drivers without fbdev dumb-create helper rely on fbdev's + * deferred I/O. + */ + return fb_deferred_io_mmap(info, vma); + else if (dev->driver->gem_prime_mmap) /* * Either directly mmap'ed or with deferred I/O; drivers * without shadow buffer handle mmap themselves. */ - return fb_helper->dev->driver->gem_prime_mmap(fb_helper->buffer->gem, vma); - else - return -ENODEV; + return dev->driver->gem_prime_mmap(fb_helper->buffer->gem, vma); + + return -ENODEV; } static bool drm_fbdev_use_iomem(struct fb_info *info) @@ -2395,7 +2411,7 @@ static int drm_fb_helper_generic_probe(struct drm_fb_helper *fb_helper, format = drm_mode_legacy_fb_format(sizes->surface_bpp, sizes->surface_depth); buffer = drm_client_framebuffer_create(client, sizes->surface_width, - sizes->surface_height, format); + sizes->surface_height, format, true); if (IS_ERR(buffer)) return PTR_ERR(buffer); diff --git a/include/drm/drm_client.h b/include/drm/drm_client.h index 4fc8018eddda..8d80d5594bea 100644 --- a/include/drm/drm_client.h +++ b/include/drm/drm_client.h @@ -153,7 +153,8 @@ struct drm_client_buffer { }; struct drm_client_buffer * -drm_client_framebuffer_create(struct drm_client_dev *client, u32 width, u32 height, u32 format); +drm_client_framebuffer_create(struct drm_client_dev *client, u32 width, u32 height, u32 format, + bool fbdev); void drm_client_framebuffer_delete(struct drm_client_buffer *buffer); int drm_client_framebuffer_flush(struct drm_client_buffer *buffer, struct drm_rect *rect); int drm_client_buffer_vmap(struct drm_client_buffer *buffer, diff --git a/include/drm/drm_drv.h b/include/drm/drm_drv.h index f6159acb8856..da4a095de1e7 100644 --- a/include/drm/drm_drv.h +++ b/include/drm/drm_drv.h @@ -379,6 +379,23 @@ struct drm_driver { int (*dumb_create)(struct drm_file *file_priv, struct drm_device *dev, struct drm_mode_create_dumb *args); + /** + * @dumb_create_fbdev: + * + * This creates a new dumb buffer for use with DRM fbdev clients and + * returns the resulting buffer handle. This handle can then be wrapped + * up into a framebuffer modeset object. + * + * This is an interface for kernel clients and never called via ioctl. + * + * See @dumb_create for more information. + * + * Returns: + * Zero on success, negative errno on failure. + */ + int (*dumb_create_fbdev)(struct drm_file *file_priv, + struct drm_device *dev, + struct drm_mode_create_dumb *args); /** * @dumb_map_offset: * From patchwork Thu Mar 3 20:58:37 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Thomas Zimmermann X-Patchwork-Id: 549510 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 14387C43217 for ; Thu, 3 Mar 2022 20:58:50 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236393AbiCCU7e (ORCPT ); Thu, 3 Mar 2022 15:59:34 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58944 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236394AbiCCU7b (ORCPT ); Thu, 3 Mar 2022 15:59:31 -0500 Received: from smtp-out1.suse.de (smtp-out1.suse.de [195.135.220.28]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 56FDA46B20 for ; Thu, 3 Mar 2022 12:58:45 -0800 (PST) Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out1.suse.de (Postfix) with ESMTPS id 1A552218EA; Thu, 3 Mar 2022 20:58:43 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1646341123; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=1DCmDk81nbdNEgBW4F9PrKTQOw7SN+B56i/UU6XlrFc=; b=XsjlJ8bQ9pVWTFSVfM3s7T7wTNoCLnwzZQQZbgXH3cYdIA27AmYeHD6fQpJwB7KGyrqsz+ M0y+5nBARcs+DDtVc+0RLr/3H4g5nhq1gErGxmHlAlg5c5DsjUffk+xRbIr0hGFZRHqFTi smjA8d4VV3Y/lCQLkK5iRM2dXRUauOQ= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1646341123; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=1DCmDk81nbdNEgBW4F9PrKTQOw7SN+B56i/UU6XlrFc=; b=UZ7amyrYsEKBNszCR62lXM2CmlWGySWq5lMaqsr4gvQ+nVbmmcDXQlLCLU319PbqPov9Sz N/hVsevNa1KDibCQ== Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap2.suse-dmz.suse.de (Postfix) with ESMTPS id D9AFC13AEE; Thu, 3 Mar 2022 20:58:42 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id KDU8NAIsIWJoHAAAMHmgww (envelope-from ); Thu, 03 Mar 2022 20:58:42 +0000 From: Thomas Zimmermann To: daniel@ffwll.ch, airlied@linux.ie, mripard@kernel.org, maarten.lankhorst@linux.intel.com, deller@gmx.de, javierm@redhat.com Cc: dri-devel@lists.freedesktop.org, linux-fbdev@vger.kernel.org, Thomas Zimmermann Subject: [PATCH 7/9] drm/fb-helper: Provide fbdev deferred-I/O helpers Date: Thu, 3 Mar 2022 21:58:37 +0100 Message-Id: <20220303205839.28484-8-tzimmermann@suse.de> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220303205839.28484-1-tzimmermann@suse.de> References: <20220303205839.28484-1-tzimmermann@suse.de> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fbdev@vger.kernel.org Add drm_fb_helper_vm_page_mkwrite(), a helper to track pages written by fbdev userspace. DRM drivers should use this function to implement fbdev deferred I/O. Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas --- drivers/gpu/drm/drm_fb_helper.c | 10 ++++++++++ include/drm/drm_fb_helper.h | 9 +++++++++ 2 files changed, 19 insertions(+) diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 9d1140a789f4..6203f5ab33af 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -760,6 +760,16 @@ void drm_fb_helper_deferred_io(struct fb_info *info, } EXPORT_SYMBOL(drm_fb_helper_deferred_io); +vm_fault_t drm_fb_helper_vm_page_mkwrite(struct drm_fb_helper *fb_helper, struct vm_fault *vmf) +{ + struct fb_info *info = fb_helper->fbdev; + + if (!info->fbdefio) + return 0; + return fb_deferred_io_page_mkwrite(info, vmf); +} +EXPORT_SYMBOL(drm_fb_helper_vm_page_mkwrite); + /** * drm_fb_helper_sys_read - wrapper around fb_sys_read * @info: fb_info struct pointer diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h index 3af4624368d8..8994c65f0b5a 100644 --- a/include/drm/drm_fb_helper.h +++ b/include/drm/drm_fb_helper.h @@ -232,6 +232,9 @@ void drm_fb_helper_fill_info(struct fb_info *info, void drm_fb_helper_deferred_io(struct fb_info *info, struct list_head *pagelist); +vm_fault_t drm_fb_helper_vm_page_mkwrite(struct drm_fb_helper *fb_helper, + struct vm_fault *vmf); + ssize_t drm_fb_helper_sys_read(struct fb_info *info, char __user *buf, size_t count, loff_t *ppos); ssize_t drm_fb_helper_sys_write(struct fb_info *info, const char __user *buf, @@ -355,6 +358,12 @@ static inline void drm_fb_helper_deferred_io(struct fb_info *info, { } +static inline vm_fault_t drm_fb_helper_vm_page_mkwrite(struct drm_fb_helper *fb_helper, + struct vm_fault *vmf) +{ + return 0; +} + static inline int drm_fb_helper_defio_init(struct drm_fb_helper *fb_helper) { return -ENODEV; From patchwork Thu Mar 3 20:58:38 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Thomas Zimmermann X-Patchwork-Id: 547949 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 7F508C4332F for ; Thu, 3 Mar 2022 20:58:50 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236394AbiCCU7e (ORCPT ); Thu, 3 Mar 2022 15:59:34 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58964 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236378AbiCCU7b (ORCPT ); Thu, 3 Mar 2022 15:59:31 -0500 Received: from smtp-out2.suse.de (smtp-out2.suse.de [195.135.220.29]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id B449842A2D for ; Thu, 3 Mar 2022 12:58:44 -0800 (PST) Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out2.suse.de (Postfix) with ESMTPS id 5AAA91F386; Thu, 3 Mar 2022 20:58:43 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1646341123; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=pHr5544ROJhBojHHXpax9c0eRTjBslUEweLX/2Wuka8=; b=h31R2g0opHQRtiNxzQJ4h1xbA83FuI/rpRYQwjxavjHgbDVoMbYoGr5CyAtp88CYHY6amk rT3VaqMh2MnGJr0t6CxAA0ORf3G3pd1VCJ0f+9zwfZArzbwcnF/oAAu3G/W7QHqaL43HQ4 8T3V1eafPycHxZf1+rrRCj8M+NSy2TE= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1646341123; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=pHr5544ROJhBojHHXpax9c0eRTjBslUEweLX/2Wuka8=; b=1I0Mpdbc70c8rdPSSVacoJpDztDJc0IijqlKSxrUDi+kKBhDN62/iCsKgUbHyENNohtH10 djXCYhpPqXMfDZDg== Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap2.suse-dmz.suse.de (Postfix) with ESMTPS id 207BA139B5; Thu, 3 Mar 2022 20:58:43 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id UDIDBwMsIWJoHAAAMHmgww (envelope-from ); Thu, 03 Mar 2022 20:58:43 +0000 From: Thomas Zimmermann To: daniel@ffwll.ch, airlied@linux.ie, mripard@kernel.org, maarten.lankhorst@linux.intel.com, deller@gmx.de, javierm@redhat.com Cc: dri-devel@lists.freedesktop.org, linux-fbdev@vger.kernel.org, Thomas Zimmermann Subject: [PATCH 8/9] drm/gem-shmem: Implement fbdev dumb buffer and mmap helpers Date: Thu, 3 Mar 2022 21:58:38 +0100 Message-Id: <20220303205839.28484-9-tzimmermann@suse.de> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220303205839.28484-1-tzimmermann@suse.de> References: <20220303205839.28484-1-tzimmermann@suse.de> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fbdev@vger.kernel.org Implement struct drm_driver.dumb_create_fbdev for GEM SHMEM. The created buffer object returned by this function implements deferred I/O for its mmap operation. Add this feature to a number of drivers that use GEM SHMEM helpers as shadow planes over their regular video memory. The new macro DRM_GEM_SHMEM_DRIVER_OPS_WITH_SHADOW_PLANES sets the regular GEM functions and dumb_create_fbdev in struct drm_driver. Fbdev emulation on these drivers will now mmap the GEM SHMEM pages directly with deferred I/O without an intermediate shadow buffer. Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas --- drivers/gpu/drm/drm_gem_shmem_helper.c | 197 +++++++++++++++++++++--- drivers/gpu/drm/gud/gud_drv.c | 2 +- drivers/gpu/drm/hyperv/hyperv_drm_drv.c | 2 +- drivers/gpu/drm/mgag200/mgag200_drv.c | 2 +- drivers/gpu/drm/tiny/cirrus.c | 2 +- drivers/gpu/drm/tiny/gm12u320.c | 2 +- drivers/gpu/drm/tiny/simpledrm.c | 2 +- drivers/gpu/drm/udl/udl_drv.c | 2 +- drivers/gpu/drm/vkms/vkms_drv.c | 2 +- include/drm/drm_gem_shmem_helper.h | 63 +++++++- 10 files changed, 240 insertions(+), 36 deletions(-) diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c index 8ad0e02991ca..ab7cb7d896c3 100644 --- a/drivers/gpu/drm/drm_gem_shmem_helper.c +++ b/drivers/gpu/drm/drm_gem_shmem_helper.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -49,8 +50,20 @@ static const struct drm_gem_object_funcs drm_gem_shmem_funcs = { .vm_ops = &drm_gem_shmem_vm_ops, }; +static const struct drm_gem_object_funcs drm_gem_shmem_funcs_fbdev = { + .free = drm_gem_shmem_object_free, + .print_info = drm_gem_shmem_object_print_info, + .pin = drm_gem_shmem_object_pin, + .unpin = drm_gem_shmem_object_unpin, + .get_sg_table = drm_gem_shmem_object_get_sg_table, + .vmap = drm_gem_shmem_object_vmap, + .vunmap = drm_gem_shmem_object_vunmap, + .mmap = drm_gem_shmem_object_mmap_fbdev, + .vm_ops = &drm_gem_shmem_vm_ops_fbdev, +}; + static struct drm_gem_shmem_object * -__drm_gem_shmem_create(struct drm_device *dev, size_t size, bool private) +__drm_gem_shmem_create(struct drm_device *dev, size_t size, bool private, bool fbdev) { struct drm_gem_shmem_object *shmem; struct drm_gem_object *obj; @@ -70,8 +83,12 @@ __drm_gem_shmem_create(struct drm_device *dev, size_t size, bool private) obj = &shmem->base; } - if (!obj->funcs) - obj->funcs = &drm_gem_shmem_funcs; + if (!obj->funcs) { + if (fbdev) + obj->funcs = &drm_gem_shmem_funcs_fbdev; + else + obj->funcs = &drm_gem_shmem_funcs; + } if (private) { drm_gem_private_object_init(dev, obj, size); @@ -124,7 +141,7 @@ __drm_gem_shmem_create(struct drm_device *dev, size_t size, bool private) */ struct drm_gem_shmem_object *drm_gem_shmem_create(struct drm_device *dev, size_t size) { - return __drm_gem_shmem_create(dev, size, false); + return __drm_gem_shmem_create(dev, size, false, false); } EXPORT_SYMBOL_GPL(drm_gem_shmem_create); @@ -415,12 +432,12 @@ EXPORT_SYMBOL(drm_gem_shmem_vunmap); static struct drm_gem_shmem_object * drm_gem_shmem_create_with_handle(struct drm_file *file_priv, struct drm_device *dev, size_t size, - uint32_t *handle) + bool fbdev, uint32_t *handle) { struct drm_gem_shmem_object *shmem; int ret; - shmem = drm_gem_shmem_create(dev, size); + shmem = __drm_gem_shmem_create(dev, size, false, fbdev); if (IS_ERR(shmem)) return shmem; @@ -496,6 +513,29 @@ bool drm_gem_shmem_purge(struct drm_gem_shmem_object *shmem) } EXPORT_SYMBOL(drm_gem_shmem_purge); +static int __drm_gem_shmem_dumb_create(struct drm_file *file, struct drm_device *dev, + bool fbdev, struct drm_mode_create_dumb *args) +{ + u32 min_pitch = DIV_ROUND_UP(args->width * args->bpp, 8); + struct drm_gem_shmem_object *shmem; + + if (!args->pitch || !args->size) { + args->pitch = min_pitch; + args->size = PAGE_ALIGN(args->pitch * args->height); + } else { + /* ensure sane minimum values */ + if (args->pitch < min_pitch) + args->pitch = min_pitch; + if (args->size < args->pitch * args->height) + args->size = PAGE_ALIGN(args->pitch * args->height); + } + + shmem = drm_gem_shmem_create_with_handle(file, dev, args->size, fbdev, + &args->handle); + + return PTR_ERR_OR_ZERO(shmem); +} + /** * drm_gem_shmem_dumb_create - Create a dumb shmem buffer object * @file: DRM file structure to create the dumb buffer for @@ -516,26 +556,38 @@ EXPORT_SYMBOL(drm_gem_shmem_purge); int drm_gem_shmem_dumb_create(struct drm_file *file, struct drm_device *dev, struct drm_mode_create_dumb *args) { - u32 min_pitch = DIV_ROUND_UP(args->width * args->bpp, 8); - struct drm_gem_shmem_object *shmem; - - if (!args->pitch || !args->size) { - args->pitch = min_pitch; - args->size = PAGE_ALIGN(args->pitch * args->height); - } else { - /* ensure sane minimum values */ - if (args->pitch < min_pitch) - args->pitch = min_pitch; - if (args->size < args->pitch * args->height) - args->size = PAGE_ALIGN(args->pitch * args->height); - } - - shmem = drm_gem_shmem_create_with_handle(file, dev, args->size, &args->handle); - - return PTR_ERR_OR_ZERO(shmem); + return __drm_gem_shmem_dumb_create(file, dev, false, args); } EXPORT_SYMBOL_GPL(drm_gem_shmem_dumb_create); +/** + * drm_gem_shmem_dumb_create_fbdev - Create a dumb shmem buffer object for fbdev + * @file: DRM file structure to create the dumb buffer for + * @dev: DRM device + * @args: IOCTL data + * + * This function computes the pitch of the dumb buffer and rounds it up to an + * integer number of bytes per pixel. Drivers for hardware that doesn't have + * any additional restrictions on the pitch can directly use this function as + * their &drm_driver.dumb_create_fbdev callback. + * + * For hardware with additional restrictions, drivers can adjust the fields + * set up by userspace before calling into this function. + * + * Returns: + * 0 on success or a negative error code on failure. + */ +int drm_gem_shmem_dumb_create_fbdev(struct drm_file *file, struct drm_device *dev, + struct drm_mode_create_dumb *args) +{ +#if defined(CONFIG_DRM_FBDEV_EMULATION) + return __drm_gem_shmem_dumb_create(file, dev, true, args); +#else + return -ENOSYS; +#endif +} +EXPORT_SYMBOL_GPL(drm_gem_shmem_dumb_create_fbdev); + static vm_fault_t drm_gem_shmem_fault(struct vm_fault *vmf) { struct vm_area_struct *vma = vmf->vma; @@ -635,6 +687,103 @@ int drm_gem_shmem_mmap(struct drm_gem_shmem_object *shmem, struct vm_area_struct } EXPORT_SYMBOL_GPL(drm_gem_shmem_mmap); +#if defined(CONFIG_DRM_FBDEV_EMULATION) +static vm_fault_t drm_gem_shmem_fault_fbdev(struct vm_fault *vmf) +{ + struct vm_area_struct *vma = vmf->vma; + struct drm_gem_object *obj = vma->vm_private_data; + struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj); + loff_t num_pages = obj->size >> PAGE_SHIFT; + struct drm_device *dev = obj->dev; + vm_fault_t ret; + struct page *page; + pgoff_t page_offset; + + /* We don't use vmf->pgoff since that has the fake offset */ + page_offset = (vmf->address - vma->vm_start) >> PAGE_SHIFT; + + mutex_lock(&shmem->pages_lock); + + if (page_offset >= num_pages || WARN_ON_ONCE(!shmem->pages) || shmem->madv < 0) { + ret = VM_FAULT_SIGBUS; + goto err_mutex_unlock; + } + + page = shmem->pages[page_offset]; + + get_page(page); + + if (vmf->vma->vm_file) + page->mapping = vmf->vma->vm_file->f_mapping; + else + drm_err(dev, "no mapping available\n"); + + if (drm_WARN_ON_ONCE(dev, !page->mapping)) { + ret = VM_FAULT_SIGBUS; + goto err_put_page; + } + + /* for page_mkclean(); include the fake offset in the page index */ + page->index = vmf->pgoff; + + vmf->page = page; + + mutex_unlock(&shmem->pages_lock); + + return 0; + +err_put_page: + put_page(page); +err_mutex_unlock: + mutex_unlock(&shmem->pages_lock); + return ret; +} + +static vm_fault_t drm_gem_shmem_vm_page_mkwrite_fbdev(struct vm_fault *vmf) +{ + struct drm_gem_object *obj = vmf->vma->vm_private_data; + + return drm_fb_helper_vm_page_mkwrite(obj->dev->fb_helper, vmf); +} + +const struct vm_operations_struct drm_gem_shmem_vm_ops_fbdev = { + .open = drm_gem_shmem_vm_open, + .close = drm_gem_shmem_vm_close, + .fault = drm_gem_shmem_fault_fbdev, + .page_mkwrite = drm_gem_shmem_vm_page_mkwrite_fbdev, +}; +EXPORT_SYMBOL_GPL(drm_gem_shmem_vm_ops_fbdev); + +int drm_gem_shmem_mmap_fbdev(struct drm_gem_shmem_object *shmem, struct vm_area_struct *vma) +{ + struct drm_gem_object *obj = &shmem->base; + int ret; + + if (obj->import_attach) { + /* Drop the reference drm_gem_mmap_obj() acquired.*/ + drm_gem_object_put(obj); + vma->vm_private_data = NULL; + + return dma_buf_mmap(obj->dma_buf, vma, 0); + } + + ret = drm_gem_shmem_get_pages(shmem); + if (ret) { + drm_gem_vm_close(vma); + return ret; + } + + vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP; + vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); + vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot); + if (shmem->map_wc) + vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); + + return 0; +} +EXPORT_SYMBOL_GPL(drm_gem_shmem_mmap_fbdev); +#endif + /** * drm_gem_shmem_print_info() - Print &drm_gem_shmem_object info for debugfs * @shmem: shmem GEM object @@ -751,7 +900,7 @@ drm_gem_shmem_prime_import_sg_table(struct drm_device *dev, size_t size = PAGE_ALIGN(attach->dmabuf->size); struct drm_gem_shmem_object *shmem; - shmem = __drm_gem_shmem_create(dev, size, true); + shmem = __drm_gem_shmem_create(dev, size, true, false); if (IS_ERR(shmem)) return ERR_CAST(shmem); diff --git a/drivers/gpu/drm/gud/gud_drv.c b/drivers/gpu/drm/gud/gud_drv.c index 3f9d4b9a1e3d..1ac1ff1b2f81 100644 --- a/drivers/gpu/drm/gud/gud_drv.c +++ b/drivers/gpu/drm/gud/gud_drv.c @@ -382,7 +382,7 @@ DEFINE_DRM_GEM_FOPS(gud_fops); static const struct drm_driver gud_drm_driver = { .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC, .fops = &gud_fops, - DRM_GEM_SHMEM_DRIVER_OPS, + DRM_GEM_SHMEM_DRIVER_OPS_WITH_SHADOW_PLANES, .gem_prime_import = gud_gem_prime_import, .debugfs_init = gud_debugfs_init, diff --git a/drivers/gpu/drm/hyperv/hyperv_drm_drv.c b/drivers/gpu/drm/hyperv/hyperv_drm_drv.c index 4a8941fa0815..2701664c127b 100644 --- a/drivers/gpu/drm/hyperv/hyperv_drm_drv.c +++ b/drivers/gpu/drm/hyperv/hyperv_drm_drv.c @@ -38,7 +38,7 @@ static struct drm_driver hyperv_driver = { .minor = DRIVER_MINOR, .fops = &hv_fops, - DRM_GEM_SHMEM_DRIVER_OPS, + DRM_GEM_SHMEM_DRIVER_OPS_WITH_SHADOW_PLANES, }; static int hyperv_pci_probe(struct pci_dev *pdev, diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.c b/drivers/gpu/drm/mgag200/mgag200_drv.c index 217844d71ab5..57dd5511e118 100644 --- a/drivers/gpu/drm/mgag200/mgag200_drv.c +++ b/drivers/gpu/drm/mgag200/mgag200_drv.c @@ -38,7 +38,7 @@ static const struct drm_driver mgag200_driver = { .major = DRIVER_MAJOR, .minor = DRIVER_MINOR, .patchlevel = DRIVER_PATCHLEVEL, - DRM_GEM_SHMEM_DRIVER_OPS, + DRM_GEM_SHMEM_DRIVER_OPS_WITH_SHADOW_PLANES, }; /* diff --git a/drivers/gpu/drm/tiny/cirrus.c b/drivers/gpu/drm/tiny/cirrus.c index c8e791840862..17d8ca07af94 100644 --- a/drivers/gpu/drm/tiny/cirrus.c +++ b/drivers/gpu/drm/tiny/cirrus.c @@ -542,7 +542,7 @@ static const struct drm_driver cirrus_driver = { .minor = DRIVER_MINOR, .fops = &cirrus_fops, - DRM_GEM_SHMEM_DRIVER_OPS, + DRM_GEM_SHMEM_DRIVER_OPS_WITH_SHADOW_PLANES, }; static int cirrus_pci_probe(struct pci_dev *pdev, diff --git a/drivers/gpu/drm/tiny/gm12u320.c b/drivers/gpu/drm/tiny/gm12u320.c index 648e585d40a8..97946f0637f3 100644 --- a/drivers/gpu/drm/tiny/gm12u320.c +++ b/drivers/gpu/drm/tiny/gm12u320.c @@ -620,7 +620,7 @@ static const struct drm_driver gm12u320_drm_driver = { .minor = DRIVER_MINOR, .fops = &gm12u320_fops, - DRM_GEM_SHMEM_DRIVER_OPS, + DRM_GEM_SHMEM_DRIVER_OPS_WITH_SHADOW_PLANES, .gem_prime_import = gm12u320_gem_prime_import, }; diff --git a/drivers/gpu/drm/tiny/simpledrm.c b/drivers/gpu/drm/tiny/simpledrm.c index 768242a78e2b..562d09627330 100644 --- a/drivers/gpu/drm/tiny/simpledrm.c +++ b/drivers/gpu/drm/tiny/simpledrm.c @@ -871,7 +871,7 @@ simpledrm_device_create(struct drm_driver *drv, struct platform_device *pdev) DEFINE_DRM_GEM_FOPS(simpledrm_fops); static struct drm_driver simpledrm_driver = { - DRM_GEM_SHMEM_DRIVER_OPS, + DRM_GEM_SHMEM_DRIVER_OPS_WITH_SHADOW_PLANES, .name = DRIVER_NAME, .desc = DRIVER_DESC, .date = DRIVER_DATE, diff --git a/drivers/gpu/drm/udl/udl_drv.c b/drivers/gpu/drm/udl/udl_drv.c index 5703277c6f52..87f7648e73a5 100644 --- a/drivers/gpu/drm/udl/udl_drv.c +++ b/drivers/gpu/drm/udl/udl_drv.c @@ -55,7 +55,7 @@ static const struct drm_driver driver = { /* GEM hooks */ .fops = &udl_driver_fops, - DRM_GEM_SHMEM_DRIVER_OPS, + DRM_GEM_SHMEM_DRIVER_OPS_WITH_SHADOW_PLANES, .gem_prime_import = udl_driver_gem_prime_import, .name = DRIVER_NAME, diff --git a/drivers/gpu/drm/vkms/vkms_drv.c b/drivers/gpu/drm/vkms/vkms_drv.c index 0ffe5f0e33f7..645b92149b8b 100644 --- a/drivers/gpu/drm/vkms/vkms_drv.c +++ b/drivers/gpu/drm/vkms/vkms_drv.c @@ -116,7 +116,7 @@ static const struct drm_driver vkms_driver = { .driver_features = DRIVER_MODESET | DRIVER_ATOMIC | DRIVER_GEM, .release = vkms_release, .fops = &vkms_driver_fops, - DRM_GEM_SHMEM_DRIVER_OPS, + DRM_GEM_SHMEM_DRIVER_OPS_WITH_SHADOW_PLANES, .debugfs_init = vkms_config_debugfs_init, diff --git a/include/drm/drm_gem_shmem_helper.h b/include/drm/drm_gem_shmem_helper.h index d0a57853c188..16b0f4b60d33 100644 --- a/include/drm/drm_gem_shmem_helper.h +++ b/include/drm/drm_gem_shmem_helper.h @@ -139,6 +139,11 @@ void drm_gem_shmem_print_info(const struct drm_gem_shmem_object *shmem, extern const struct vm_operations_struct drm_gem_shmem_vm_ops; +#if defined(CONFIG_DRM_FBDEV_EMULATION) +extern const struct vm_operations_struct drm_gem_shmem_vm_ops_fbdev; +int drm_gem_shmem_mmap_fbdev(struct drm_gem_shmem_object *shmem, struct vm_area_struct *vma); +#endif + /* * GEM object functions */ @@ -272,6 +277,27 @@ static inline int drm_gem_shmem_object_mmap(struct drm_gem_object *obj, struct v return drm_gem_shmem_mmap(shmem, vma); } +#if defined(CONFIG_DRM_FBDEV_EMULATION) +/** + * drm_gem_shmem_object_mmap_fbdev - GEM object function for drm_gem_shmem_mmap_fbdev() + * @obj: GEM object + * @vma: VMA for the area to be mapped + * + * This function wraps drm_gem_shmem_mmap(). Drivers that employ the shmem helpers should + * use it as their &drm_gem_object_funcs.mmap handler. + * + * Returns: + * 0 on success or a negative error code on failure. + */ +static inline int drm_gem_shmem_object_mmap_fbdev(struct drm_gem_object *obj, + struct vm_area_struct *vma) +{ + struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj); + + return drm_gem_shmem_mmap_fbdev(shmem, vma); +} +#endif + /* * Driver ops */ @@ -282,18 +308,47 @@ drm_gem_shmem_prime_import_sg_table(struct drm_device *dev, struct sg_table *sgt); int drm_gem_shmem_dumb_create(struct drm_file *file, struct drm_device *dev, struct drm_mode_create_dumb *args); +int drm_gem_shmem_dumb_create_fbdev(struct drm_file *file, struct drm_device *dev, + struct drm_mode_create_dumb *args); /** - * DRM_GEM_SHMEM_DRIVER_OPS - Default shmem GEM operations + * DRM_GEM_SHMEM_DRIVER_OPS_WITH_DUMB_CREATE - Default shmem GEM operations + * @dumb_create_func: callback function for .dumb_create + * @dumb_create_fbdev_func: callback function for .dumb_create_fbdev * * This macro provides a shortcut for setting the shmem GEM operations in - * the &drm_driver structure. + * the &drm_driver structure. The callbacks for creating dumb buffers are + * given as parameters. Use DRM_GEM_SHMEM_DRIVER_OPS or + * DRM_GEM_SHMEM_OPS_WITH_SHADOW_PLANES if possible. */ -#define DRM_GEM_SHMEM_DRIVER_OPS \ +#define DRM_GEM_SHMEM_DRIVER_OPS_WITH_DUMB_CREATE(dumb_create_func, dumb_create_fbdev_func) \ .prime_handle_to_fd = drm_gem_prime_handle_to_fd, \ .prime_fd_to_handle = drm_gem_prime_fd_to_handle, \ .gem_prime_import_sg_table = drm_gem_shmem_prime_import_sg_table, \ .gem_prime_mmap = drm_gem_prime_mmap, \ - .dumb_create = drm_gem_shmem_dumb_create + .dumb_create = dumb_create_func, \ + .dumb_create_fbdev = dumb_create_fbdev_func + +/** + * DRM_GEM_SHMEM_DRIVER_OPS - Default shmem GEM operations + * + * This macro provides a shortcut for setting the shmem GEM operations in + * the &drm_driver structure. + */ +#define DRM_GEM_SHMEM_DRIVER_OPS \ + DRM_GEM_SHMEM_DRIVER_OPS_WITH_DUMB_CREATE(drm_gem_shmem_dumb_create, NULL) + +/** + * DRM_GEM_SHMEM_DRIVER_OPS_WITH_SHADOW_PLANES - Default shmem GEM operations + * for drivers that use shadow + * planes + * + * This macro provides a shortcut for setting the shmem GEM operations in + * the &drm_driver structure. Drivers that employ shmem GEM for shadow + * buffering should use this macro. + */ +#define DRM_GEM_SHMEM_DRIVER_OPS_WITH_SHADOW_PLANES \ + DRM_GEM_SHMEM_DRIVER_OPS_WITH_DUMB_CREATE(drm_gem_shmem_dumb_create, \ + drm_gem_shmem_dumb_create_fbdev) #endif /* __DRM_GEM_SHMEM_HELPER_H__ */ From patchwork Thu Mar 3 20:58:39 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Thomas Zimmermann X-Patchwork-Id: 549511 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 15D9EC433F5 for ; Thu, 3 Mar 2022 20:58:49 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236368AbiCCU7d (ORCPT ); Thu, 3 Mar 2022 15:59:33 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58952 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236395AbiCCU7b (ORCPT ); Thu, 3 Mar 2022 15:59:31 -0500 Received: from smtp-out2.suse.de (smtp-out2.suse.de [195.135.220.29]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 1300342EE3 for ; Thu, 3 Mar 2022 12:58:45 -0800 (PST) Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out2.suse.de (Postfix) with ESMTPS id 92ACF1F387; Thu, 3 Mar 2022 20:58:43 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1646341123; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=UGKPWdswBenK67eQjyzqzCZAIpf0aWbVZ9VytjJasTw=; b=u5ehuTqRLSvIpHum2nwBwBaKqq+xFxMDx7RiR8Ny5v2Y50i5Z8asdG70yJMb5HGmb9zlsx ZvtSmDXulMJXYnzTDeJsHkMqAvBYnN66dxtESSYO+oZrqawICWGDuWA2FvpDYCjTPv9yU5 GouRFKZDasJSxqhK+KY3gSBuukJA3R4= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1646341123; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=UGKPWdswBenK67eQjyzqzCZAIpf0aWbVZ9VytjJasTw=; b=r61MdzQz4lpwo78o/VqXJ878NqMVOZUueoFBSDJZgwLBrXo5BofSAWM4WPg6c1eqqZGdjv Pv1lLE5wDG3eHGBQ== Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap2.suse-dmz.suse.de (Postfix) with ESMTPS id 5F4D613AEE; Thu, 3 Mar 2022 20:58:43 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id EGpWFgMsIWJoHAAAMHmgww (envelope-from ); Thu, 03 Mar 2022 20:58:43 +0000 From: Thomas Zimmermann To: daniel@ffwll.ch, airlied@linux.ie, mripard@kernel.org, maarten.lankhorst@linux.intel.com, deller@gmx.de, javierm@redhat.com Cc: dri-devel@lists.freedesktop.org, linux-fbdev@vger.kernel.org, Thomas Zimmermann Subject: [PATCH 9/9] drm/virtio: Implement dumb_create_fbdev with GEM SHMEM helpers Date: Thu, 3 Mar 2022 21:58:39 +0100 Message-Id: <20220303205839.28484-10-tzimmermann@suse.de> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220303205839.28484-1-tzimmermann@suse.de> References: <20220303205839.28484-1-tzimmermann@suse.de> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fbdev@vger.kernel.org Implement struct drm_driver.dumb_create_fbdev with the helpers provided by GEM SHMEM. Fbdev deferred I/O will now work without an intermediate shadow buffer for mmap. As the virtio driver replaces several of the regular GEM SHMEM functions with its own implementation, some additional code is necessary make fbdev optimization work. Especially, the driver has to provide buffer-object functions for fbdev. Add the hook struct drm_driver.gem_create_object_fbdev, which is similar to struct drm_driver.gem_create_object and allows for the creation of dedicated fbdev buffer objects. Wire things up within GEM SHMEM. Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas --- drivers/gpu/drm/drm_gem_shmem_helper.c | 7 +++- drivers/gpu/drm/virtio/virtgpu_drv.c | 2 + drivers/gpu/drm/virtio/virtgpu_drv.h | 2 + drivers/gpu/drm/virtio/virtgpu_object.c | 54 +++++++++++++++++++++++-- include/drm/drm_drv.h | 10 +++++ 5 files changed, 71 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c index ab7cb7d896c3..225aa17895bd 100644 --- a/drivers/gpu/drm/drm_gem_shmem_helper.c +++ b/drivers/gpu/drm/drm_gem_shmem_helper.c @@ -71,7 +71,12 @@ __drm_gem_shmem_create(struct drm_device *dev, size_t size, bool private, bool f size = PAGE_ALIGN(size); - if (dev->driver->gem_create_object) { + if (dev->driver->gem_create_object_fbdev && fbdev) { + obj = dev->driver->gem_create_object_fbdev(dev, size); + if (IS_ERR(obj)) + return ERR_CAST(obj); + shmem = to_drm_gem_shmem_obj(obj); + } else if (dev->driver->gem_create_object) { obj = dev->driver->gem_create_object(dev, size); if (IS_ERR(obj)) return ERR_CAST(obj); diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.c b/drivers/gpu/drm/virtio/virtgpu_drv.c index 5f25a8d15464..ee414f6e785a 100644 --- a/drivers/gpu/drm/virtio/virtgpu_drv.c +++ b/drivers/gpu/drm/virtio/virtgpu_drv.c @@ -203,6 +203,7 @@ static const struct drm_driver driver = { .postclose = virtio_gpu_driver_postclose, .dumb_create = virtio_gpu_mode_dumb_create, + .dumb_create_fbdev = virtio_gpu_mode_dumb_create, // same as dumb_create .dumb_map_offset = virtio_gpu_mode_dumb_mmap, #if defined(CONFIG_DEBUG_FS) @@ -215,6 +216,7 @@ static const struct drm_driver driver = { .gem_prime_import_sg_table = virtgpu_gem_prime_import_sg_table, .gem_create_object = virtio_gpu_create_object, + .gem_create_object_fbdev = virtio_gpu_create_object_fbdev, .fops = &virtio_gpu_driver_fops, .ioctls = virtio_gpu_ioctls, diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.h b/drivers/gpu/drm/virtio/virtgpu_drv.h index 0a194aaad419..71556c21c029 100644 --- a/drivers/gpu/drm/virtio/virtgpu_drv.h +++ b/drivers/gpu/drm/virtio/virtgpu_drv.h @@ -449,6 +449,8 @@ void virtio_gpu_fence_event_process(struct virtio_gpu_device *vdev, void virtio_gpu_cleanup_object(struct virtio_gpu_object *bo); struct drm_gem_object *virtio_gpu_create_object(struct drm_device *dev, size_t size); +struct drm_gem_object *virtio_gpu_create_object_fbdev(struct drm_device *dev, + size_t size); int virtio_gpu_object_create(struct virtio_gpu_device *vgdev, struct virtio_gpu_object_params *params, struct virtio_gpu_object **bo_ptr, diff --git a/drivers/gpu/drm/virtio/virtgpu_object.c b/drivers/gpu/drm/virtio/virtgpu_object.c index f293e6ad52da..255f2d650451 100644 --- a/drivers/gpu/drm/virtio/virtgpu_object.c +++ b/drivers/gpu/drm/virtio/virtgpu_object.c @@ -132,8 +132,8 @@ bool virtio_gpu_is_shmem(struct virtio_gpu_object *bo) return bo->base.base.funcs == &virtio_gpu_shmem_funcs; } -struct drm_gem_object *virtio_gpu_create_object(struct drm_device *dev, - size_t size) +static struct drm_gem_object *__virtio_gpu_create_object(struct drm_device *dev, + size_t size) { struct virtio_gpu_object_shmem *shmem; struct drm_gem_shmem_object *dshmem; @@ -143,10 +143,58 @@ struct drm_gem_object *virtio_gpu_create_object(struct drm_device *dev, return ERR_PTR(-ENOMEM); dshmem = &shmem->base.base; - dshmem->base.funcs = &virtio_gpu_shmem_funcs; return &dshmem->base; } +struct drm_gem_object *virtio_gpu_create_object(struct drm_device *dev, + size_t size) +{ + struct drm_gem_object *obj; + + obj = __virtio_gpu_create_object(dev, size); + if (IS_ERR(obj)) + return obj; + obj->funcs = &virtio_gpu_shmem_funcs; + + return obj; +} + +#if defined(CONFIG_DRM_FBDEV_EMULATION) +static const struct drm_gem_object_funcs virtio_gpu_shmem_funcs_fbdev = { + .free = virtio_gpu_free_object, + .open = virtio_gpu_gem_object_open, + .close = virtio_gpu_gem_object_close, + .print_info = drm_gem_shmem_object_print_info, + .export = virtgpu_gem_prime_export, + .pin = drm_gem_shmem_object_pin, + .unpin = drm_gem_shmem_object_unpin, + .get_sg_table = drm_gem_shmem_object_get_sg_table, + .vmap = drm_gem_shmem_object_vmap, + .vunmap = drm_gem_shmem_object_vunmap, + .mmap = drm_gem_shmem_object_mmap_fbdev, + .vm_ops = &drm_gem_shmem_vm_ops_fbdev, +}; + +struct drm_gem_object *virtio_gpu_create_object_fbdev(struct drm_device *dev, + size_t size) +{ + struct drm_gem_object *obj; + + obj = __virtio_gpu_create_object(dev, size); + if (IS_ERR(obj)) + return obj; + obj->funcs = &virtio_gpu_shmem_funcs_fbdev; + + return obj; +} +#else +struct drm_gem_object *virtio_gpu_create_object_fbdev(struct drm_device *dev, + size_t size) +{ + return ERR_PTR(-ENOSYS); +} +#endif + static int virtio_gpu_object_shmem_init(struct virtio_gpu_device *vgdev, struct virtio_gpu_object *bo, struct virtio_gpu_mem_entry **ents, diff --git a/include/drm/drm_drv.h b/include/drm/drm_drv.h index da4a095de1e7..9081281c1f39 100644 --- a/include/drm/drm_drv.h +++ b/include/drm/drm_drv.h @@ -298,6 +298,16 @@ struct drm_driver { struct drm_gem_object *(*gem_create_object)(struct drm_device *dev, size_t size); + /** + * @gem_create_object_fbdev: constructor for gem objects that back fbdev + * + * Hook for allocating the GEM object struct, for use by the CMA + * and SHMEM GEM helpers. Returns a GEM object on success, or an + * ERR_PTR()-encoded error code otherwise. + */ + struct drm_gem_object *(*gem_create_object_fbdev)(struct drm_device *dev, + size_t size); + /** * @prime_handle_to_fd: *