* Re: [PATCH net v5] failover: allow name change on IFF_UP slave interfaces
From: Stephen Hemminger @ 2019-04-02 21:53 UTC (permalink / raw)
To: Si-Wei Liu
Cc: jiri, mst, kubakici, sridhar.samudrala, alexander.duyck,
virtualization, liran.alon, netdev, boris.ostrovsky, davem
In-Reply-To: <1554159893-29704-1-git-send-email-si-wei.liu@oracle.com>
On Mon, 1 Apr 2019 19:04:53 -0400
Si-Wei Liu <si-wei.liu@oracle.com> wrote:
> + if (dev->flags & IFF_UP &&
> + likely(!(dev->priv_flags & IFF_FAILOVER_SLAVE)))
Why is property limited to failover slave, it would make sense for netvsc
as well. Why not make it a flag like live address change?
^ permalink raw reply
* Re: [PATCH net v5] failover: allow name change on IFF_UP slave interfaces
From: Stephen Hemminger @ 2019-04-03 3:14 UTC (permalink / raw)
To: si-wei liu
Cc: jiri, mst, kubakici, sridhar.samudrala, alexander.duyck,
virtualization, liran.alon, netdev, boris.ostrovsky, davem
In-Reply-To: <d62006dc-d602-7389-cc27-2c1873163ad2@oracle.com>
On Tue, 2 Apr 2019 15:23:29 -0700
si-wei liu <si-wei.liu@oracle.com> wrote:
> On 4/2/2019 2:53 PM, Stephen Hemminger wrote:
> > On Mon, 1 Apr 2019 19:04:53 -0400
> > Si-Wei Liu <si-wei.liu@oracle.com> wrote:
> >
> >> + if (dev->flags & IFF_UP &&
> >> + likely(!(dev->priv_flags & IFF_FAILOVER_SLAVE)))
> > Why is property limited to failover slave, it would make sense for netvsc
> > as well. Why not make it a flag like live address change?
> Well, netvsc today is still taking the delayed approach meaning that it
> is incompatible yet with this live name change flag if need be. ;-)
>
> I thought Sridhar did not like to introduce an additional
> IFF_SLAVE_RENAME_OK flag given that failover slave is the only consumer
> for the time being. Even though I can get it back, patch is needed for
> netvsc to remove the VF takeover delay IMHO.
>
> Sridhar, what do you think we revive the IFF_SLAVE_RENAME_OK flag which
> allows netvsc to be used later on? Or maybe, IFF_LIVE_RENAME_OK for a
> better name?
>
> -Siwei
I would name it IFF_LIVE_NAME_CHANGE to match IFF_LIVE_ADDR_CHANGE
there is no reason its use should be restricted to SLAVE devices.
^ permalink raw reply
* Re: [PATCH net v5] failover: allow name change on IFF_UP slave interfaces
From: Samudrala, Sridhar @ 2019-04-03 5:22 UTC (permalink / raw)
To: Stephen Hemminger, si-wei liu
Cc: jiri, mst, kubakici, netdev, alexander.duyck, virtualization,
liran.alon, boris.ostrovsky, davem
In-Reply-To: <20190402201451.1f6201b8@shemminger-XPS-13-9360>
On 4/2/2019 8:14 PM, Stephen Hemminger wrote:
> On Tue, 2 Apr 2019 15:23:29 -0700
> si-wei liu <si-wei.liu@oracle.com> wrote:
>
>> On 4/2/2019 2:53 PM, Stephen Hemminger wrote:
>>> On Mon, 1 Apr 2019 19:04:53 -0400
>>> Si-Wei Liu <si-wei.liu@oracle.com> wrote:
>>>
>>>> + if (dev->flags & IFF_UP &&
>>>> + likely(!(dev->priv_flags & IFF_FAILOVER_SLAVE)))
>>> Why is property limited to failover slave, it would make sense for netvsc
>>> as well. Why not make it a flag like live address change?
>> Well, netvsc today is still taking the delayed approach meaning that it
>> is incompatible yet with this live name change flag if need be. ;-)
>>
>> I thought Sridhar did not like to introduce an additional
>> IFF_SLAVE_RENAME_OK flag given that failover slave is the only consumer
>> for the time being. Even though I can get it back, patch is needed for
>> netvsc to remove the VF takeover delay IMHO.
>>
>> Sridhar, what do you think we revive the IFF_SLAVE_RENAME_OK flag which
>> allows netvsc to be used later on? Or maybe, IFF_LIVE_RENAME_OK for a
>> better name?
>>
>> -Siwei
>
> I would name it IFF_LIVE_NAME_CHANGE to match IFF_LIVE_ADDR_CHANGE
> there is no reason its use should be restricted to SLAVE devices.
>
Stephen,
May be you should consider moving netvsc to use the net_failover driver now?
^ permalink raw reply
* [PATCH] drm/cirrus: rewrite and modernize driver.
From: Gerd Hoffmann @ 2019-04-03 7:23 UTC (permalink / raw)
To: dri-devel
Cc: David Airlie, open list,
open list:DRM DRIVER FOR QEMU'S CIRRUS DEVICE, Daniel Vetter,
Dave Airlie
Time to kill some bad sample code people are copying from ;)
This is a complete rewrite of the cirrus driver. The cirrus_mode_set()
function is pretty much the only function which is carried over largely
unmodified. Everything else is upside down.
It is a single monster patch. But given that it does some pretty
fundamental changes to the drivers workflow and also reduces the code
size by roughly 70% I think it'll still be alot easier to review than a
longish baby-step patch series.
Changes summary:
- Given the small amout of video memory (4 MB) the cirrus device has
the rewritten driver doesn't try to manage buffers there. Instead
it will blit (memcpy) the active framebuffer to video memory.
- All gem objects are stored in main memory and are manged using the
new shmem helpers. ttm is out.
- Only DRM_FORMAT_RGB565 (depth 16) is supported. The old driver does
that too by default. There was a module parameter which enables 24/32
bpp support and disables higher resolutions (due to cirrus hardware
constrains). That parameter wasn't reimplemented.
- The simple display pipeline is used.
- The generic fbdev emulation is used.
- It's a atomic driver now.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
drivers/gpu/drm/cirrus/cirrus_drv.h | 251 -----------
drivers/gpu/drm/cirrus/cirrus.c | 602 +++++++++++++++++++++++++
drivers/gpu/drm/cirrus/cirrus_drv.c | 161 -------
drivers/gpu/drm/cirrus/cirrus_fbdev.c | 309 -------------
drivers/gpu/drm/cirrus/cirrus_main.c | 328 --------------
drivers/gpu/drm/cirrus/cirrus_mode.c | 617 --------------------------
drivers/gpu/drm/cirrus/cirrus_ttm.c | 343 --------------
drivers/gpu/drm/cirrus/Kconfig | 2 +-
drivers/gpu/drm/cirrus/Makefile | 3 -
9 files changed, 603 insertions(+), 2013 deletions(-)
delete mode 100644 drivers/gpu/drm/cirrus/cirrus_drv.h
create mode 100644 drivers/gpu/drm/cirrus/cirrus.c
delete mode 100644 drivers/gpu/drm/cirrus/cirrus_drv.c
delete mode 100644 drivers/gpu/drm/cirrus/cirrus_fbdev.c
delete mode 100644 drivers/gpu/drm/cirrus/cirrus_main.c
delete mode 100644 drivers/gpu/drm/cirrus/cirrus_mode.c
delete mode 100644 drivers/gpu/drm/cirrus/cirrus_ttm.c
diff --git a/drivers/gpu/drm/cirrus/cirrus_drv.h b/drivers/gpu/drm/cirrus/cirrus_drv.h
deleted file mode 100644
index 828b150cdb20..000000000000
--- a/drivers/gpu/drm/cirrus/cirrus_drv.h
+++ /dev/null
@@ -1,251 +0,0 @@
-/*
- * Copyright 2012 Red Hat
- *
- * This file is subject to the terms and conditions of the GNU General
- * Public License version 2. See the file COPYING in the main
- * directory of this archive for more details.
- *
- * Authors: Matthew Garrett
- * Dave Airlie
- */
-#ifndef __CIRRUS_DRV_H__
-#define __CIRRUS_DRV_H__
-
-#include <video/vga.h>
-
-#include <drm/drm_encoder.h>
-#include <drm/drm_fb_helper.h>
-
-#include <drm/ttm/ttm_bo_api.h>
-#include <drm/ttm/ttm_bo_driver.h>
-#include <drm/ttm/ttm_placement.h>
-#include <drm/ttm/ttm_memory.h>
-#include <drm/ttm/ttm_module.h>
-
-#include <drm/drm_gem.h>
-
-#define DRIVER_AUTHOR "Matthew Garrett"
-
-#define DRIVER_NAME "cirrus"
-#define DRIVER_DESC "qemu Cirrus emulation"
-#define DRIVER_DATE "20110418"
-
-#define DRIVER_MAJOR 1
-#define DRIVER_MINOR 0
-#define DRIVER_PATCHLEVEL 0
-
-#define CIRRUSFB_CONN_LIMIT 1
-
-#define RREG8(reg) ioread8(((void __iomem *)cdev->rmmio) + (reg))
-#define WREG8(reg, v) iowrite8(v, ((void __iomem *)cdev->rmmio) + (reg))
-#define RREG32(reg) ioread32(((void __iomem *)cdev->rmmio) + (reg))
-#define WREG32(reg, v) iowrite32(v, ((void __iomem *)cdev->rmmio) + (reg))
-
-#define SEQ_INDEX 4
-#define SEQ_DATA 5
-
-#define WREG_SEQ(reg, v) \
- do { \
- WREG8(SEQ_INDEX, reg); \
- WREG8(SEQ_DATA, v); \
- } while (0) \
-
-#define CRT_INDEX 0x14
-#define CRT_DATA 0x15
-
-#define WREG_CRT(reg, v) \
- do { \
- WREG8(CRT_INDEX, reg); \
- WREG8(CRT_DATA, v); \
- } while (0) \
-
-#define GFX_INDEX 0xe
-#define GFX_DATA 0xf
-
-#define WREG_GFX(reg, v) \
- do { \
- WREG8(GFX_INDEX, reg); \
- WREG8(GFX_DATA, v); \
- } while (0) \
-
-/*
- * Cirrus has a "hidden" DAC register that can be accessed by writing to
- * the pixel mask register to reset the state, then reading from the register
- * four times. The next write will then pass to the DAC
- */
-#define VGA_DAC_MASK 0x6
-
-#define WREG_HDR(v) \
- do { \
- RREG8(VGA_DAC_MASK); \
- RREG8(VGA_DAC_MASK); \
- RREG8(VGA_DAC_MASK); \
- RREG8(VGA_DAC_MASK); \
- WREG8(VGA_DAC_MASK, v); \
- } while (0) \
-
-
-#define CIRRUS_MAX_FB_HEIGHT 4096
-#define CIRRUS_MAX_FB_WIDTH 4096
-
-#define CIRRUS_DPMS_CLEARED (-1)
-
-#define to_cirrus_crtc(x) container_of(x, struct cirrus_crtc, base)
-#define to_cirrus_encoder(x) container_of(x, struct cirrus_encoder, base)
-
-struct cirrus_crtc {
- struct drm_crtc base;
- int last_dpms;
- bool enabled;
-};
-
-struct cirrus_fbdev;
-struct cirrus_mode_info {
- struct cirrus_crtc *crtc;
- /* pointer to fbdev info structure */
- struct cirrus_fbdev *gfbdev;
-};
-
-struct cirrus_encoder {
- struct drm_encoder base;
- int last_dpms;
-};
-
-struct cirrus_connector {
- struct drm_connector base;
-};
-
-struct cirrus_mc {
- resource_size_t vram_size;
- resource_size_t vram_base;
-};
-
-struct cirrus_device {
- struct drm_device *dev;
- unsigned long flags;
-
- resource_size_t rmmio_base;
- resource_size_t rmmio_size;
- void __iomem *rmmio;
-
- struct cirrus_mc mc;
- struct cirrus_mode_info mode_info;
-
- int num_crtc;
- int fb_mtrr;
-
- struct {
- struct ttm_bo_device bdev;
- } ttm;
- bool mm_inited;
-};
-
-
-struct cirrus_fbdev {
- struct drm_fb_helper helper; /* must be first */
- struct drm_framebuffer *gfb;
- void *sysram;
- int size;
- int x1, y1, x2, y2; /* dirty rect */
- spinlock_t dirty_lock;
-};
-
-struct cirrus_bo {
- struct ttm_buffer_object bo;
- struct ttm_placement placement;
- struct ttm_bo_kmap_obj kmap;
- struct drm_gem_object gem;
- struct ttm_place placements[3];
- int pin_count;
-};
-#define gem_to_cirrus_bo(gobj) container_of((gobj), struct cirrus_bo, gem)
-
-static inline struct cirrus_bo *
-cirrus_bo(struct ttm_buffer_object *bo)
-{
- return container_of(bo, struct cirrus_bo, bo);
-}
-
-
-#define to_cirrus_obj(x) container_of(x, struct cirrus_gem_object, base)
-#define DRM_FILE_PAGE_OFFSET (0x100000000ULL >> PAGE_SHIFT)
-
- /* cirrus_main.c */
-int cirrus_device_init(struct cirrus_device *cdev,
- struct drm_device *ddev,
- struct pci_dev *pdev,
- uint32_t flags);
-void cirrus_device_fini(struct cirrus_device *cdev);
-void cirrus_gem_free_object(struct drm_gem_object *obj);
-int cirrus_dumb_mmap_offset(struct drm_file *file,
- struct drm_device *dev,
- uint32_t handle,
- uint64_t *offset);
-int cirrus_gem_create(struct drm_device *dev,
- u32 size, bool iskernel,
- struct drm_gem_object **obj);
-int cirrus_dumb_create(struct drm_file *file,
- struct drm_device *dev,
- struct drm_mode_create_dumb *args);
-
-int cirrus_framebuffer_init(struct drm_device *dev,
- struct drm_framebuffer *gfb,
- const struct drm_mode_fb_cmd2 *mode_cmd,
- struct drm_gem_object *obj);
-
-bool cirrus_check_framebuffer(struct cirrus_device *cdev, int width, int height,
- int bpp, int pitch);
-
- /* cirrus_display.c */
-int cirrus_modeset_init(struct cirrus_device *cdev);
-void cirrus_modeset_fini(struct cirrus_device *cdev);
-
- /* cirrus_fbdev.c */
-int cirrus_fbdev_init(struct cirrus_device *cdev);
-void cirrus_fbdev_fini(struct cirrus_device *cdev);
-
-
-
- /* cirrus_irq.c */
-void cirrus_driver_irq_preinstall(struct drm_device *dev);
-int cirrus_driver_irq_postinstall(struct drm_device *dev);
-void cirrus_driver_irq_uninstall(struct drm_device *dev);
-irqreturn_t cirrus_driver_irq_handler(int irq, void *arg);
-
- /* cirrus_kms.c */
-int cirrus_driver_load(struct drm_device *dev, unsigned long flags);
-void cirrus_driver_unload(struct drm_device *dev);
-extern struct drm_ioctl_desc cirrus_ioctls[];
-extern int cirrus_max_ioctl;
-
-int cirrus_mm_init(struct cirrus_device *cirrus);
-void cirrus_mm_fini(struct cirrus_device *cirrus);
-void cirrus_ttm_placement(struct cirrus_bo *bo, int domain);
-int cirrus_bo_create(struct drm_device *dev, int size, int align,
- uint32_t flags, struct cirrus_bo **pcirrusbo);
-int cirrus_mmap(struct file *filp, struct vm_area_struct *vma);
-
-static inline int cirrus_bo_reserve(struct cirrus_bo *bo, bool no_wait)
-{
- int ret;
-
- ret = ttm_bo_reserve(&bo->bo, true, no_wait, NULL);
- if (ret) {
- if (ret != -ERESTARTSYS && ret != -EBUSY)
- DRM_ERROR("reserve failed %p\n", bo);
- return ret;
- }
- return 0;
-}
-
-static inline void cirrus_bo_unreserve(struct cirrus_bo *bo)
-{
- ttm_bo_unreserve(&bo->bo);
-}
-
-int cirrus_bo_push_sysram(struct cirrus_bo *bo);
-int cirrus_bo_pin(struct cirrus_bo *bo, u32 pl_flag, u64 *gpu_addr);
-
-extern int cirrus_bpp;
-
-#endif /* __CIRRUS_DRV_H__ */
diff --git a/drivers/gpu/drm/cirrus/cirrus.c b/drivers/gpu/drm/cirrus/cirrus.c
new file mode 100644
index 000000000000..e27bb13fc777
--- /dev/null
+++ b/drivers/gpu/drm/cirrus/cirrus.c
@@ -0,0 +1,602 @@
+/*
+ * Copyright 2012-2019 Red Hat
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License version 2. See the file COPYING in the main
+ * directory of this archive for more details.
+ *
+ * Authors: Matthew Garrett
+ * Dave Airlie
+ * Gerd Hoffmann
+ *
+ * Portions of this code derived from cirrusfb.c:
+ * drivers/video/cirrusfb.c - driver for Cirrus Logic chipsets
+ *
+ * Copyright 1999-2001 Jeff Garzik <jgarzik@pobox.com>
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/console.h>
+
+#include <video/vga.h>
+#include <video/cirrus.h>
+
+#include <drm/drm_drv.h>
+#include <drm/drm_file.h>
+#include <drm/drm_ioctl.h>
+#include <drm/drm_vblank.h>
+#include <drm/drm_connector.h>
+
+#include <drm/drm_fb_helper.h>
+#include <drm/drm_probe_helper.h>
+#include <drm/drm_simple_kms_helper.h>
+#include <drm/drm_gem_shmem_helper.h>
+#include <drm/drm_gem_framebuffer_helper.h>
+#include <drm/drm_modeset_helper_vtables.h>
+#include <drm/drm_damage_helper.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_atomic_state_helper.h>
+
+#define DRIVER_NAME "cirrus"
+#define DRIVER_DESC "qemu cirrus vga"
+#define DRIVER_DATE "2019"
+#define DRIVER_MAJOR 2
+#define DRIVER_MINOR 0
+
+struct cirrus_device {
+ struct drm_device *dev;
+ struct drm_simple_display_pipe pipe;
+ struct drm_connector conn;
+ unsigned int bpp;
+ unsigned int pitch;
+ void __iomem *vram;
+ void __iomem *mmio;
+};
+
+/* ------------------------------------------------------------------ */
+/*
+ * The meat of this driver. The core passes us a mode and we have to program
+ * it. The modesetting here is the bare minimum required to satisfy the qemu
+ * emulation of this hardware, and running this against a real device is
+ * likely to result in an inadequately programmed mode. We've already had
+ * the opportunity to modify the mode, so whatever we receive here should
+ * be something that can be correctly programmed and displayed
+ */
+
+#define RREG8(reg) ioread8(((void __iomem *)cirrus->mmio) + (reg))
+#define WREG8(reg, v) iowrite8(v, ((void __iomem *)cirrus->mmio) + (reg))
+#define RREG32(reg) ioread32(((void __iomem *)cirrus->mmio) + (reg))
+#define WREG32(reg, v) iowrite32(v, ((void __iomem *)cirrus->mmio) + (reg))
+
+#define SEQ_INDEX 4
+#define SEQ_DATA 5
+
+#define WREG_SEQ(reg, v) \
+ do { \
+ WREG8(SEQ_INDEX, reg); \
+ WREG8(SEQ_DATA, v); \
+ } while (0) \
+
+#define CRT_INDEX 0x14
+#define CRT_DATA 0x15
+
+#define WREG_CRT(reg, v) \
+ do { \
+ WREG8(CRT_INDEX, reg); \
+ WREG8(CRT_DATA, v); \
+ } while (0) \
+
+#define GFX_INDEX 0xe
+#define GFX_DATA 0xf
+
+#define WREG_GFX(reg, v) \
+ do { \
+ WREG8(GFX_INDEX, reg); \
+ WREG8(GFX_DATA, v); \
+ } while (0) \
+
+#define VGA_DAC_MASK 0x6
+
+#define WREG_HDR(v) \
+ do { \
+ RREG8(VGA_DAC_MASK); \
+ RREG8(VGA_DAC_MASK); \
+ RREG8(VGA_DAC_MASK); \
+ RREG8(VGA_DAC_MASK); \
+ WREG8(VGA_DAC_MASK, v); \
+ } while (0) \
+
+
+static int cirrus_mode_set(struct cirrus_device *cirrus,
+ struct drm_crtc_state *crtc_state)
+{
+ struct drm_display_mode *mode = &crtc_state->mode;
+ int hsyncstart, hsyncend, htotal, hdispend;
+ int vtotal, vdispend;
+ int tmp;
+ int sr07 = 0, hdr = 0;
+
+ htotal = mode->htotal / 8;
+ hsyncend = mode->hsync_end / 8;
+ hsyncstart = mode->hsync_start / 8;
+ hdispend = mode->hdisplay / 8;
+
+ vtotal = mode->vtotal;
+ vdispend = mode->vdisplay;
+
+ vdispend -= 1;
+ vtotal -= 2;
+
+ htotal -= 5;
+ hdispend -= 1;
+ hsyncstart += 1;
+ hsyncend += 1;
+
+ WREG_CRT(VGA_CRTC_V_SYNC_END, 0x20);
+ WREG_CRT(VGA_CRTC_H_TOTAL, htotal);
+ WREG_CRT(VGA_CRTC_H_DISP, hdispend);
+ WREG_CRT(VGA_CRTC_H_SYNC_START, hsyncstart);
+ WREG_CRT(VGA_CRTC_H_SYNC_END, hsyncend);
+ WREG_CRT(VGA_CRTC_V_TOTAL, vtotal & 0xff);
+ WREG_CRT(VGA_CRTC_V_DISP_END, vdispend & 0xff);
+
+ tmp = 0x40;
+ if ((vdispend + 1) & 512)
+ tmp |= 0x20;
+ WREG_CRT(VGA_CRTC_MAX_SCAN, tmp);
+
+ /*
+ * Overflow bits for values that don't fit in the standard registers
+ */
+ tmp = 16;
+ if (vtotal & 256)
+ tmp |= 1;
+ if (vdispend & 256)
+ tmp |= 2;
+ if ((vdispend + 1) & 256)
+ tmp |= 8;
+ if (vtotal & 512)
+ tmp |= 32;
+ if (vdispend & 512)
+ tmp |= 64;
+ WREG_CRT(VGA_CRTC_OVERFLOW, tmp);
+
+ tmp = 0;
+
+ /* More overflow bits */
+
+ if ((htotal + 5) & 64)
+ tmp |= 16;
+ if ((htotal + 5) & 128)
+ tmp |= 32;
+ if (vtotal & 256)
+ tmp |= 64;
+ if (vtotal & 512)
+ tmp |= 128;
+
+ WREG_CRT(CL_CRT1A, tmp);
+
+ /* Disable Hercules/CGA compatibility */
+ WREG_CRT(VGA_CRTC_MODE, 0x03);
+
+ WREG8(SEQ_INDEX, 0x7);
+ sr07 = RREG8(SEQ_DATA);
+ sr07 &= 0xe0;
+ hdr = 0;
+
+ cirrus->bpp = cirrus->dev->mode_config.preferred_depth;
+ switch (cirrus->bpp) {
+ case 8:
+ sr07 |= 0x11;
+ break;
+ case 16:
+ sr07 |= 0x17;
+ hdr = 0xc1;
+ break;
+ case 24:
+ sr07 |= 0x15;
+ hdr = 0xc5;
+ break;
+ case 32:
+ sr07 |= 0x19;
+ hdr = 0xc5;
+ break;
+ default:
+ return -1;
+ }
+
+ WREG_SEQ(0x7, sr07);
+
+ /* Program the pitch */
+ cirrus->pitch = mode->hdisplay * cirrus->bpp / 8;
+ tmp = cirrus->pitch / 8;
+ WREG_CRT(VGA_CRTC_OFFSET, tmp);
+
+ /* Enable extended blanking and pitch bits, and enable full memory */
+ tmp = 0x22;
+ tmp |= (cirrus->pitch >> 7) & 0x10;
+ tmp |= (cirrus->pitch >> 6) & 0x40;
+ WREG_CRT(0x1b, tmp);
+
+ /* Enable high-colour modes */
+ WREG_GFX(VGA_GFX_MODE, 0x40);
+
+ /* And set graphics mode */
+ WREG_GFX(VGA_GFX_MISC, 0x01);
+
+ WREG_HDR(hdr);
+ /* cirrus_crtc_do_set_base(crtc, old_fb, x, y, 0); */
+
+ /* Unblank (needed on S3 resume, vgabios doesn't do it then) */
+ outb(0x20, 0x3c0);
+ return 0;
+}
+
+static int cirrus_fb_blit_clips(struct drm_framebuffer *fb,
+ struct drm_clip_rect *clips,
+ unsigned int num_clips)
+{
+ struct cirrus_device *cirrus = fb->dev->dev_private;
+ unsigned i, y, xoff, xlen, src, dst;
+ void *vmap;
+
+ vmap = drm_gem_shmem_vmap(fb->obj[0]);
+ if (!vmap)
+ return -ENOMEM;
+
+ for (i = 0; i < num_clips; i++) {
+ xoff = clips[i].x1 * cirrus->bpp / 8;
+ xlen = (clips[i].x2 - clips[i].x1) * cirrus->bpp / 8;
+ for (y = clips[i].y1; y < clips[i].y2; y++) {
+ src = xoff + y * fb->pitches[0];
+ dst = xoff + y * cirrus->pitch;
+ memcpy_toio(cirrus->vram + dst, vmap + src, xlen);
+ }
+ }
+
+ drm_gem_shmem_vunmap(fb->obj[0], vmap);
+ return 0;
+}
+
+static int cirrus_fb_blit_rect(struct drm_framebuffer *fb,
+ struct drm_rect *rect)
+{
+ struct drm_clip_rect clip_rect = {
+ .x1 = rect->x1,
+ .x2 = rect->x2,
+ .y1 = rect->y1,
+ .y2 = rect->y2,
+ };
+ return cirrus_fb_blit_clips(fb, &clip_rect, 1);
+}
+
+static int cirrus_fb_blit_fullscreen(struct drm_framebuffer *fb)
+{
+ struct drm_clip_rect fullscreen = {
+ .x1 = 0,
+ .x2 = fb->width,
+ .y1 = 0,
+ .y2 = fb->height,
+ };
+ return cirrus_fb_blit_clips(fb, &fullscreen, 1);
+}
+
+static int cirrus_check_size(int width, int height)
+{
+ static const int max_pitch = 0x1FF << 3; /* (4096 - 1) & ~111b bytes */
+ static const int max_size = 4 * 1024 * 1024; /* 4 MB */
+ int bytes_pp = 2; /* depth 16 */
+
+ if (width * bytes_pp > max_pitch)
+ return -EINVAL;
+ if (width * height * bytes_pp > max_size)
+ return -EINVAL;
+ return 0;
+}
+
+/* ------------------------------------------------------------------ */
+/* cirrus connector */
+
+static int cirrus_conn_get_modes(struct drm_connector *conn)
+{
+ int count;
+
+ count = drm_add_modes_noedid(conn,
+ conn->dev->mode_config.max_width,
+ conn->dev->mode_config.max_height);
+ drm_set_preferred_mode(conn, 1024, 768);
+ return count;
+}
+
+static const struct drm_connector_helper_funcs cirrus_conn_helper_funcs = {
+ .get_modes = cirrus_conn_get_modes,
+};
+
+static const struct drm_connector_funcs cirrus_conn_funcs = {
+ .fill_modes = drm_helper_probe_single_connector_modes,
+ .destroy = drm_connector_cleanup,
+ .reset = drm_atomic_helper_connector_reset,
+ .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+static int cirrus_conn_init(struct cirrus_device *cirrus)
+{
+ drm_connector_helper_add(&cirrus->conn, &cirrus_conn_helper_funcs);
+ return drm_connector_init(cirrus->dev, &cirrus->conn,
+ &cirrus_conn_funcs, DRM_MODE_CONNECTOR_VGA);
+
+}
+
+/* ------------------------------------------------------------------ */
+/* cirrus (simple) display pipe */
+
+enum drm_mode_status cirrus_pipe_mode_valid(struct drm_crtc *crtc,
+ const struct drm_display_mode *mode)
+{
+ if (cirrus_check_size(mode->hdisplay, mode->vdisplay) < 0)
+ return MODE_BAD;
+ return MODE_OK;
+}
+
+int cirrus_pipe_check(struct drm_simple_display_pipe *pipe,
+ struct drm_plane_state *plane_state,
+ struct drm_crtc_state *crtc_state)
+{
+ struct drm_framebuffer *fb = plane_state->fb;
+
+ if (!fb)
+ return 0;
+ return cirrus_check_size(fb->width, fb->height);
+}
+
+void cirrus_pipe_enable(struct drm_simple_display_pipe *pipe,
+ struct drm_crtc_state *crtc_state,
+ struct drm_plane_state *plane_state)
+{
+ struct cirrus_device *cirrus = pipe->crtc.dev->dev_private;
+
+ cirrus_mode_set(cirrus, crtc_state);
+ cirrus_fb_blit_fullscreen(plane_state->fb);
+}
+
+void cirrus_pipe_update(struct drm_simple_display_pipe *pipe,
+ struct drm_plane_state *old_state)
+{
+ struct drm_plane_state *state = pipe->plane.state;
+ struct drm_crtc *crtc = &pipe->crtc;
+ struct drm_rect rect;
+
+ if (drm_atomic_helper_damage_merged(old_state, state, &rect))
+ cirrus_fb_blit_rect(pipe->plane.state->fb, &rect);
+
+ if (crtc->state->event) {
+ spin_lock_irq(&crtc->dev->event_lock);
+ drm_crtc_send_vblank_event(crtc, crtc->state->event);
+ spin_unlock_irq(&crtc->dev->event_lock);
+ crtc->state->event = NULL;
+ }
+}
+
+static const struct drm_simple_display_pipe_funcs cirrus_pipe_funcs = {
+ .mode_valid = cirrus_pipe_mode_valid,
+ .check = cirrus_pipe_check,
+ .enable = cirrus_pipe_enable,
+ .update = cirrus_pipe_update,
+};
+
+static const uint32_t cirrus_formats[] = {
+ DRM_FORMAT_RGB565,
+};
+
+static int cirrus_pipe_init(struct cirrus_device *cirrus)
+{
+ return drm_simple_display_pipe_init(cirrus->dev,
+ &cirrus->pipe,
+ &cirrus_pipe_funcs,
+ cirrus_formats,
+ ARRAY_SIZE(cirrus_formats),
+ NULL,
+ &cirrus->conn);
+}
+
+/* ------------------------------------------------------------------ */
+/* cirrus framebuffers & mode config */
+
+static int cirrus_fb_dirty(struct drm_framebuffer *fb,
+ struct drm_file *file_priv,
+ unsigned int flags, unsigned int color,
+ struct drm_clip_rect *clips,
+ unsigned int num_clips)
+{
+ struct cirrus_device *cirrus = fb->dev->dev_private;
+
+ if (cirrus->pipe.plane.state->fb != fb)
+ return 0;
+
+ if (num_clips)
+ cirrus_fb_blit_clips(fb, clips, num_clips);
+ else
+ cirrus_fb_blit_fullscreen(fb);
+ return 0;
+}
+
+static const struct drm_framebuffer_funcs cirrus_fb_funcs = {
+ .destroy = drm_gem_fb_destroy,
+ .create_handle = drm_gem_fb_create_handle,
+ .dirty = cirrus_fb_dirty,
+};
+
+static struct drm_framebuffer*
+cirrus_fb_create(struct drm_device *dev, struct drm_file *file_priv,
+ const struct drm_mode_fb_cmd2 *mode_cmd)
+{
+ if (mode_cmd->pixel_format != DRM_FORMAT_RGB565)
+ return ERR_PTR(-EINVAL);
+ if (cirrus_check_size(mode_cmd->width, mode_cmd->height) < 0)
+ return ERR_PTR(-EINVAL);
+ return drm_gem_fb_create_with_funcs(dev, file_priv, mode_cmd,
+ &cirrus_fb_funcs);
+}
+
+static const struct drm_mode_config_funcs cirrus_mode_config_funcs = {
+ .fb_create = cirrus_fb_create,
+ .atomic_check = drm_atomic_helper_check,
+ .atomic_commit = drm_atomic_helper_commit,
+};
+
+static void cirrus_mode_config_init(struct cirrus_device *cirrus)
+{
+ struct drm_device *dev = cirrus->dev;
+
+ drm_mode_config_init(dev);
+ dev->mode_config.min_width = 0;
+ dev->mode_config.min_height = 0;
+ dev->mode_config.max_width = 1600;
+ dev->mode_config.max_height = 1024;
+ dev->mode_config.preferred_depth = 16;
+ dev->mode_config.prefer_shadow = 0;
+ dev->mode_config.funcs = &cirrus_mode_config_funcs;
+}
+
+/* ------------------------------------------------------------------ */
+
+DEFINE_DRM_GEM_SHMEM_FOPS(cirrus_fops);
+
+static struct drm_driver cirrus_driver = {
+ .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC | DRIVER_PRIME,
+
+ .name = DRIVER_NAME,
+ .desc = DRIVER_DESC,
+ .date = DRIVER_DATE,
+ .major = DRIVER_MAJOR,
+ .minor = DRIVER_MINOR,
+
+ .fops = &cirrus_fops,
+ DRM_GEM_SHMEM_DRIVER_OPS,
+};
+
+static int cirrus_pci_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ struct drm_device *dev;
+ struct cirrus_device *cirrus;
+ int ret;
+
+ ret = drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, 0, "cirrusdrmfb");
+ if (ret)
+ return ret;
+
+ dev = drm_dev_alloc(&cirrus_driver, &pdev->dev);
+ if (IS_ERR(dev))
+ return PTR_ERR(dev);
+
+ ret = pci_enable_device(pdev);
+ if (ret)
+ goto err_free_dev;
+
+ ret = pci_request_regions(pdev, DRIVER_NAME);
+ if (ret)
+ goto err_free_dev;
+
+ ret = -ENOMEM;
+ cirrus = kzalloc(sizeof(*cirrus), GFP_KERNEL);
+ if (cirrus == NULL)
+ goto err_pci_release;
+ dev->dev_private = cirrus;
+ cirrus->dev = dev;
+
+ cirrus->vram = ioremap(pci_resource_start(pdev, 0),
+ pci_resource_len(pdev, 0));
+ if (cirrus->vram == NULL)
+ goto err_free_cirrus;
+
+ cirrus->mmio = ioremap(pci_resource_start(pdev, 1),
+ pci_resource_len(pdev, 1));
+ if (cirrus->mmio == NULL)
+ goto err_unmap_vram;
+
+ cirrus_mode_config_init(cirrus);
+
+ ret = cirrus_conn_init(cirrus);
+ if (ret < 0)
+ goto err_cleanup;
+
+ ret = cirrus_pipe_init(cirrus);
+ if (ret < 0)
+ goto err_cleanup;
+
+ drm_mode_config_reset(dev);
+
+ dev->pdev = pdev;
+ pci_set_drvdata(pdev, dev);
+ ret = drm_dev_register(dev, 0);
+ if (ret)
+ goto err_cleanup;
+
+ drm_fbdev_generic_setup(dev, dev->mode_config.preferred_depth);
+ return 0;
+
+err_cleanup:
+ drm_mode_config_cleanup(dev);
+ iounmap(cirrus->mmio);
+err_unmap_vram:
+ iounmap(cirrus->vram);
+err_free_cirrus:
+ kfree(cirrus);
+err_pci_release:
+ pci_release_regions(pdev);
+err_free_dev:
+ drm_dev_put(dev);
+ return ret;
+}
+
+static void cirrus_pci_remove(struct pci_dev *pdev)
+{
+ struct drm_device *dev = pci_get_drvdata(pdev);
+ struct cirrus_device *cirrus = dev->dev_private;
+
+ drm_dev_unregister(dev);
+ drm_mode_config_cleanup(dev);
+ iounmap(cirrus->mmio);
+ iounmap(cirrus->vram);
+ kfree(cirrus);
+ pci_release_regions(pdev);
+ drm_dev_put(dev);
+}
+
+/* only bind to the cirrus chip in qemu */
+static const struct pci_device_id pciidlist[] = {
+ { PCI_VENDOR_ID_CIRRUS, PCI_DEVICE_ID_CIRRUS_5446,
+ PCI_SUBVENDOR_ID_REDHAT_QUMRANET, PCI_SUBDEVICE_ID_QEMU,
+ 0, 0, 0 },
+ { PCI_VENDOR_ID_CIRRUS, PCI_DEVICE_ID_CIRRUS_5446,
+ PCI_VENDOR_ID_XEN, 0x0001,
+ 0, 0, 0 },
+ { /* end if list */}
+};
+static struct pci_driver cirrus_pci_driver = {
+ .name = DRIVER_NAME,
+ .id_table = pciidlist,
+ .probe = cirrus_pci_probe,
+ .remove = cirrus_pci_remove,
+};
+
+static int __init cirrus_init(void)
+{
+ if (vgacon_text_force())
+ return -EINVAL;
+ return pci_register_driver(&cirrus_pci_driver);
+}
+
+static void __exit cirrus_exit(void)
+{
+ pci_unregister_driver(&cirrus_pci_driver);
+}
+
+module_init(cirrus_init);
+module_exit(cirrus_exit);
+
+MODULE_DEVICE_TABLE(pci, pciidlist);
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/cirrus/cirrus_drv.c b/drivers/gpu/drm/cirrus/cirrus_drv.c
deleted file mode 100644
index 8ec880f3a322..000000000000
--- a/drivers/gpu/drm/cirrus/cirrus_drv.c
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Copyright 2012 Red Hat <mjg@redhat.com>
- *
- * This file is subject to the terms and conditions of the GNU General
- * Public License version 2. See the file COPYING in the main
- * directory of this archive for more details.
- *
- * Authors: Matthew Garrett
- * Dave Airlie
- */
-#include <linux/module.h>
-#include <linux/console.h>
-#include <drm/drmP.h>
-#include <drm/drm_crtc_helper.h>
-#include <drm/drm_probe_helper.h>
-
-#include "cirrus_drv.h"
-
-int cirrus_modeset = -1;
-int cirrus_bpp = 16;
-
-MODULE_PARM_DESC(modeset, "Disable/Enable modesetting");
-module_param_named(modeset, cirrus_modeset, int, 0400);
-MODULE_PARM_DESC(bpp, "Max bits-per-pixel (default:16)");
-module_param_named(bpp, cirrus_bpp, int, 0400);
-
-/*
- * This is the generic driver code. This binds the driver to the drm core,
- * which then performs further device association and calls our graphics init
- * functions
- */
-
-static struct drm_driver driver;
-
-/* only bind to the cirrus chip in qemu */
-static const struct pci_device_id pciidlist[] = {
- { PCI_VENDOR_ID_CIRRUS, PCI_DEVICE_ID_CIRRUS_5446,
- PCI_SUBVENDOR_ID_REDHAT_QUMRANET, PCI_SUBDEVICE_ID_QEMU,
- 0, 0, 0 },
- { PCI_VENDOR_ID_CIRRUS, PCI_DEVICE_ID_CIRRUS_5446, PCI_VENDOR_ID_XEN,
- 0x0001, 0, 0, 0 },
- {0,}
-};
-
-
-static int cirrus_pci_probe(struct pci_dev *pdev,
- const struct pci_device_id *ent)
-{
- int ret;
-
- ret = drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, 0, "cirrusdrmfb");
- if (ret)
- return ret;
-
- return drm_get_pci_dev(pdev, ent, &driver);
-}
-
-static void cirrus_pci_remove(struct pci_dev *pdev)
-{
- struct drm_device *dev = pci_get_drvdata(pdev);
-
- drm_put_dev(dev);
-}
-
-#ifdef CONFIG_PM_SLEEP
-static int cirrus_pm_suspend(struct device *dev)
-{
- struct pci_dev *pdev = to_pci_dev(dev);
- struct drm_device *drm_dev = pci_get_drvdata(pdev);
- struct cirrus_device *cdev = drm_dev->dev_private;
-
- drm_kms_helper_poll_disable(drm_dev);
-
- if (cdev->mode_info.gfbdev) {
- console_lock();
- drm_fb_helper_set_suspend(&cdev->mode_info.gfbdev->helper, 1);
- console_unlock();
- }
-
- return 0;
-}
-
-static int cirrus_pm_resume(struct device *dev)
-{
- struct pci_dev *pdev = to_pci_dev(dev);
- struct drm_device *drm_dev = pci_get_drvdata(pdev);
- struct cirrus_device *cdev = drm_dev->dev_private;
-
- drm_helper_resume_force_mode(drm_dev);
-
- if (cdev->mode_info.gfbdev) {
- console_lock();
- drm_fb_helper_set_suspend(&cdev->mode_info.gfbdev->helper, 0);
- console_unlock();
- }
-
- drm_kms_helper_poll_enable(drm_dev);
- return 0;
-}
-#endif
-
-static const struct file_operations cirrus_driver_fops = {
- .owner = THIS_MODULE,
- .open = drm_open,
- .release = drm_release,
- .unlocked_ioctl = drm_ioctl,
- .mmap = cirrus_mmap,
- .poll = drm_poll,
- .compat_ioctl = drm_compat_ioctl,
-};
-static struct drm_driver driver = {
- .driver_features = DRIVER_MODESET | DRIVER_GEM,
- .load = cirrus_driver_load,
- .unload = cirrus_driver_unload,
- .fops = &cirrus_driver_fops,
- .name = DRIVER_NAME,
- .desc = DRIVER_DESC,
- .date = DRIVER_DATE,
- .major = DRIVER_MAJOR,
- .minor = DRIVER_MINOR,
- .patchlevel = DRIVER_PATCHLEVEL,
- .gem_free_object_unlocked = cirrus_gem_free_object,
- .dumb_create = cirrus_dumb_create,
- .dumb_map_offset = cirrus_dumb_mmap_offset,
-};
-
-static const struct dev_pm_ops cirrus_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(cirrus_pm_suspend,
- cirrus_pm_resume)
-};
-
-static struct pci_driver cirrus_pci_driver = {
- .name = DRIVER_NAME,
- .id_table = pciidlist,
- .probe = cirrus_pci_probe,
- .remove = cirrus_pci_remove,
- .driver.pm = &cirrus_pm_ops,
-};
-
-static int __init cirrus_init(void)
-{
- if (vgacon_text_force() && cirrus_modeset == -1)
- return -EINVAL;
-
- if (cirrus_modeset == 0)
- return -EINVAL;
- return pci_register_driver(&cirrus_pci_driver);
-}
-
-static void __exit cirrus_exit(void)
-{
- pci_unregister_driver(&cirrus_pci_driver);
-}
-
-module_init(cirrus_init);
-module_exit(cirrus_exit);
-
-MODULE_DEVICE_TABLE(pci, pciidlist);
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/cirrus/cirrus_fbdev.c b/drivers/gpu/drm/cirrus/cirrus_fbdev.c
deleted file mode 100644
index 2e6128069fc3..000000000000
--- a/drivers/gpu/drm/cirrus/cirrus_fbdev.c
+++ /dev/null
@@ -1,309 +0,0 @@
-/*
- * Copyright 2012 Red Hat
- *
- * This file is subject to the terms and conditions of the GNU General
- * Public License version 2. See the file COPYING in the main
- * directory of this archive for more details.
- *
- * Authors: Matthew Garrett
- * Dave Airlie
- */
-#include <linux/module.h>
-#include <drm/drmP.h>
-#include <drm/drm_util.h>
-#include <drm/drm_fb_helper.h>
-#include <drm/drm_crtc_helper.h>
-
-#include "cirrus_drv.h"
-
-static void cirrus_dirty_update(struct cirrus_fbdev *afbdev,
- int x, int y, int width, int height)
-{
- int i;
- struct drm_gem_object *obj;
- struct cirrus_bo *bo;
- int src_offset, dst_offset;
- int bpp = afbdev->gfb->format->cpp[0];
- int ret = -EBUSY;
- bool unmap = false;
- bool store_for_later = false;
- int x2, y2;
- unsigned long flags;
-
- obj = afbdev->gfb->obj[0];
- bo = gem_to_cirrus_bo(obj);
-
- /*
- * try and reserve the BO, if we fail with busy
- * then the BO is being moved and we should
- * store up the damage until later.
- */
- if (drm_can_sleep())
- ret = cirrus_bo_reserve(bo, true);
- if (ret) {
- if (ret != -EBUSY)
- return;
- store_for_later = true;
- }
-
- x2 = x + width - 1;
- y2 = y + height - 1;
- spin_lock_irqsave(&afbdev->dirty_lock, flags);
-
- if (afbdev->y1 < y)
- y = afbdev->y1;
- if (afbdev->y2 > y2)
- y2 = afbdev->y2;
- if (afbdev->x1 < x)
- x = afbdev->x1;
- if (afbdev->x2 > x2)
- x2 = afbdev->x2;
-
- if (store_for_later) {
- afbdev->x1 = x;
- afbdev->x2 = x2;
- afbdev->y1 = y;
- afbdev->y2 = y2;
- spin_unlock_irqrestore(&afbdev->dirty_lock, flags);
- return;
- }
-
- afbdev->x1 = afbdev->y1 = INT_MAX;
- afbdev->x2 = afbdev->y2 = 0;
- spin_unlock_irqrestore(&afbdev->dirty_lock, flags);
-
- if (!bo->kmap.virtual) {
- ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap);
- if (ret) {
- DRM_ERROR("failed to kmap fb updates\n");
- cirrus_bo_unreserve(bo);
- return;
- }
- unmap = true;
- }
- for (i = y; i < y + height; i++) {
- /* assume equal stride for now */
- src_offset = dst_offset = i * afbdev->gfb->pitches[0] + (x * bpp);
- memcpy_toio(bo->kmap.virtual + src_offset, afbdev->sysram + src_offset, width * bpp);
-
- }
- if (unmap)
- ttm_bo_kunmap(&bo->kmap);
-
- cirrus_bo_unreserve(bo);
-}
-
-static void cirrus_fillrect(struct fb_info *info,
- const struct fb_fillrect *rect)
-{
- struct cirrus_fbdev *afbdev = info->par;
- drm_fb_helper_sys_fillrect(info, rect);
- cirrus_dirty_update(afbdev, rect->dx, rect->dy, rect->width,
- rect->height);
-}
-
-static void cirrus_copyarea(struct fb_info *info,
- const struct fb_copyarea *area)
-{
- struct cirrus_fbdev *afbdev = info->par;
- drm_fb_helper_sys_copyarea(info, area);
- cirrus_dirty_update(afbdev, area->dx, area->dy, area->width,
- area->height);
-}
-
-static void cirrus_imageblit(struct fb_info *info,
- const struct fb_image *image)
-{
- struct cirrus_fbdev *afbdev = info->par;
- drm_fb_helper_sys_imageblit(info, image);
- cirrus_dirty_update(afbdev, image->dx, image->dy, image->width,
- image->height);
-}
-
-
-static struct fb_ops cirrusfb_ops = {
- .owner = THIS_MODULE,
- .fb_check_var = drm_fb_helper_check_var,
- .fb_set_par = drm_fb_helper_set_par,
- .fb_fillrect = cirrus_fillrect,
- .fb_copyarea = cirrus_copyarea,
- .fb_imageblit = cirrus_imageblit,
- .fb_pan_display = drm_fb_helper_pan_display,
- .fb_blank = drm_fb_helper_blank,
- .fb_setcmap = drm_fb_helper_setcmap,
-};
-
-static int cirrusfb_create_object(struct cirrus_fbdev *afbdev,
- const struct drm_mode_fb_cmd2 *mode_cmd,
- struct drm_gem_object **gobj_p)
-{
- struct drm_device *dev = afbdev->helper.dev;
- struct cirrus_device *cdev = dev->dev_private;
- u32 bpp;
- u32 size;
- struct drm_gem_object *gobj;
- int ret = 0;
-
- bpp = drm_format_plane_cpp(mode_cmd->pixel_format, 0) * 8;
-
- if (!cirrus_check_framebuffer(cdev, mode_cmd->width, mode_cmd->height,
- bpp, mode_cmd->pitches[0]))
- return -EINVAL;
-
- size = mode_cmd->pitches[0] * mode_cmd->height;
- ret = cirrus_gem_create(dev, size, true, &gobj);
- if (ret)
- return ret;
-
- *gobj_p = gobj;
- return ret;
-}
-
-static int cirrusfb_create(struct drm_fb_helper *helper,
- struct drm_fb_helper_surface_size *sizes)
-{
- struct cirrus_fbdev *gfbdev =
- container_of(helper, struct cirrus_fbdev, helper);
- struct cirrus_device *cdev = gfbdev->helper.dev->dev_private;
- struct fb_info *info;
- struct drm_framebuffer *fb;
- struct drm_mode_fb_cmd2 mode_cmd;
- void *sysram;
- struct drm_gem_object *gobj = NULL;
- int size, ret;
-
- mode_cmd.width = sizes->surface_width;
- mode_cmd.height = sizes->surface_height;
- mode_cmd.pitches[0] = mode_cmd.width * ((sizes->surface_bpp + 7) / 8);
- mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
- sizes->surface_depth);
- size = mode_cmd.pitches[0] * mode_cmd.height;
-
- ret = cirrusfb_create_object(gfbdev, &mode_cmd, &gobj);
- if (ret) {
- DRM_ERROR("failed to create fbcon backing object %d\n", ret);
- return ret;
- }
-
- sysram = vmalloc(size);
- if (!sysram)
- return -ENOMEM;
-
- info = drm_fb_helper_alloc_fbi(helper);
- if (IS_ERR(info)) {
- ret = PTR_ERR(info);
- goto err_vfree;
- }
-
- fb = kzalloc(sizeof(*fb), GFP_KERNEL);
- if (!fb) {
- ret = -ENOMEM;
- goto err_drm_gem_object_put_unlocked;
- }
-
- ret = cirrus_framebuffer_init(cdev->dev, fb, &mode_cmd, gobj);
- if (ret)
- goto err_kfree;
-
- gfbdev->sysram = sysram;
- gfbdev->size = size;
- gfbdev->gfb = fb;
-
- /* setup helper */
- gfbdev->helper.fb = fb;
-
- info->fbops = &cirrusfb_ops;
-
- drm_fb_helper_fill_info(info, &gfbdev->helper, sizes);
-
- /* setup aperture base/size for vesafb takeover */
- info->apertures->ranges[0].base = cdev->dev->mode_config.fb_base;
- info->apertures->ranges[0].size = cdev->mc.vram_size;
-
- info->fix.smem_start = cdev->dev->mode_config.fb_base;
- info->fix.smem_len = cdev->mc.vram_size;
-
- info->screen_base = sysram;
- info->screen_size = size;
-
- info->fix.mmio_start = 0;
- info->fix.mmio_len = 0;
-
- DRM_INFO("fb mappable at 0x%lX\n", info->fix.smem_start);
- DRM_INFO("vram aper at 0x%lX\n", (unsigned long)info->fix.smem_start);
- DRM_INFO("size %lu\n", (unsigned long)info->fix.smem_len);
- DRM_INFO("fb depth is %d\n", fb->format->depth);
- DRM_INFO(" pitch is %d\n", fb->pitches[0]);
-
- return 0;
-
-err_kfree:
- kfree(fb);
-err_drm_gem_object_put_unlocked:
- drm_gem_object_put_unlocked(gobj);
-err_vfree:
- vfree(sysram);
- return ret;
-}
-
-static int cirrus_fbdev_destroy(struct drm_device *dev,
- struct cirrus_fbdev *gfbdev)
-{
- struct drm_framebuffer *gfb = gfbdev->gfb;
-
- drm_helper_force_disable_all(dev);
-
- drm_fb_helper_unregister_fbi(&gfbdev->helper);
-
- vfree(gfbdev->sysram);
- drm_fb_helper_fini(&gfbdev->helper);
- if (gfb)
- drm_framebuffer_put(gfb);
-
- return 0;
-}
-
-static const struct drm_fb_helper_funcs cirrus_fb_helper_funcs = {
- .fb_probe = cirrusfb_create,
-};
-
-int cirrus_fbdev_init(struct cirrus_device *cdev)
-{
- struct cirrus_fbdev *gfbdev;
- int ret;
-
- /*bpp_sel = 8;*/
- gfbdev = kzalloc(sizeof(struct cirrus_fbdev), GFP_KERNEL);
- if (!gfbdev)
- return -ENOMEM;
-
- cdev->mode_info.gfbdev = gfbdev;
- spin_lock_init(&gfbdev->dirty_lock);
-
- drm_fb_helper_prepare(cdev->dev, &gfbdev->helper,
- &cirrus_fb_helper_funcs);
-
- ret = drm_fb_helper_init(cdev->dev, &gfbdev->helper,
- CIRRUSFB_CONN_LIMIT);
- if (ret)
- return ret;
-
- ret = drm_fb_helper_single_add_all_connectors(&gfbdev->helper);
- if (ret)
- return ret;
-
- /* disable all the possible outputs/crtcs before entering KMS mode */
- drm_helper_disable_unused_functions(cdev->dev);
-
- return drm_fb_helper_initial_config(&gfbdev->helper, cirrus_bpp);
-}
-
-void cirrus_fbdev_fini(struct cirrus_device *cdev)
-{
- if (!cdev->mode_info.gfbdev)
- return;
-
- cirrus_fbdev_destroy(cdev->dev, cdev->mode_info.gfbdev);
- kfree(cdev->mode_info.gfbdev);
- cdev->mode_info.gfbdev = NULL;
-}
diff --git a/drivers/gpu/drm/cirrus/cirrus_main.c b/drivers/gpu/drm/cirrus/cirrus_main.c
deleted file mode 100644
index 57f8fe6d020b..000000000000
--- a/drivers/gpu/drm/cirrus/cirrus_main.c
+++ /dev/null
@@ -1,328 +0,0 @@
-/*
- * Copyright 2012 Red Hat
- *
- * This file is subject to the terms and conditions of the GNU General
- * Public License version 2. See the file COPYING in the main
- * directory of this archive for more details.
- *
- * Authors: Matthew Garrett
- * Dave Airlie
- */
-#include <drm/drmP.h>
-#include <drm/drm_crtc_helper.h>
-#include <drm/drm_gem_framebuffer_helper.h>
-
-#include "cirrus_drv.h"
-
-static const struct drm_framebuffer_funcs cirrus_fb_funcs = {
- .create_handle = drm_gem_fb_create_handle,
- .destroy = drm_gem_fb_destroy,
-};
-
-int cirrus_framebuffer_init(struct drm_device *dev,
- struct drm_framebuffer *gfb,
- const struct drm_mode_fb_cmd2 *mode_cmd,
- struct drm_gem_object *obj)
-{
- int ret;
-
- drm_helper_mode_fill_fb_struct(dev, gfb, mode_cmd);
- gfb->obj[0] = obj;
- ret = drm_framebuffer_init(dev, gfb, &cirrus_fb_funcs);
- if (ret) {
- DRM_ERROR("drm_framebuffer_init failed: %d\n", ret);
- return ret;
- }
- return 0;
-}
-
-static struct drm_framebuffer *
-cirrus_user_framebuffer_create(struct drm_device *dev,
- struct drm_file *filp,
- const struct drm_mode_fb_cmd2 *mode_cmd)
-{
- struct cirrus_device *cdev = dev->dev_private;
- struct drm_gem_object *obj;
- struct drm_framebuffer *fb;
- u32 bpp;
- int ret;
-
- bpp = drm_format_plane_cpp(mode_cmd->pixel_format, 0) * 8;
-
- if (!cirrus_check_framebuffer(cdev, mode_cmd->width, mode_cmd->height,
- bpp, mode_cmd->pitches[0]))
- return ERR_PTR(-EINVAL);
-
- obj = drm_gem_object_lookup(filp, mode_cmd->handles[0]);
- if (obj == NULL)
- return ERR_PTR(-ENOENT);
-
- fb = kzalloc(sizeof(*fb), GFP_KERNEL);
- if (!fb) {
- drm_gem_object_put_unlocked(obj);
- return ERR_PTR(-ENOMEM);
- }
-
- ret = cirrus_framebuffer_init(dev, fb, mode_cmd, obj);
- if (ret) {
- drm_gem_object_put_unlocked(obj);
- kfree(fb);
- return ERR_PTR(ret);
- }
- return fb;
-}
-
-static const struct drm_mode_config_funcs cirrus_mode_funcs = {
- .fb_create = cirrus_user_framebuffer_create,
-};
-
-/* Unmap the framebuffer from the core and release the memory */
-static void cirrus_vram_fini(struct cirrus_device *cdev)
-{
- iounmap(cdev->rmmio);
- cdev->rmmio = NULL;
- if (cdev->mc.vram_base)
- release_mem_region(cdev->mc.vram_base, cdev->mc.vram_size);
-}
-
-/* Map the framebuffer from the card and configure the core */
-static int cirrus_vram_init(struct cirrus_device *cdev)
-{
- /* BAR 0 is VRAM */
- cdev->mc.vram_base = pci_resource_start(cdev->dev->pdev, 0);
- cdev->mc.vram_size = pci_resource_len(cdev->dev->pdev, 0);
-
- if (!request_mem_region(cdev->mc.vram_base, cdev->mc.vram_size,
- "cirrusdrmfb_vram")) {
- DRM_ERROR("can't reserve VRAM\n");
- return -ENXIO;
- }
-
- return 0;
-}
-
-/*
- * Our emulated hardware has two sets of memory. One is video RAM and can
- * simply be used as a linear framebuffer - the other provides mmio access
- * to the display registers. The latter can also be accessed via IO port
- * access, but we map the range and use mmio to program them instead
- */
-
-int cirrus_device_init(struct cirrus_device *cdev,
- struct drm_device *ddev,
- struct pci_dev *pdev, uint32_t flags)
-{
- int ret;
-
- cdev->dev = ddev;
- cdev->flags = flags;
-
- /* Hardcode the number of CRTCs to 1 */
- cdev->num_crtc = 1;
-
- /* BAR 0 is the framebuffer, BAR 1 contains registers */
- cdev->rmmio_base = pci_resource_start(cdev->dev->pdev, 1);
- cdev->rmmio_size = pci_resource_len(cdev->dev->pdev, 1);
-
- if (!request_mem_region(cdev->rmmio_base, cdev->rmmio_size,
- "cirrusdrmfb_mmio")) {
- DRM_ERROR("can't reserve mmio registers\n");
- return -ENOMEM;
- }
-
- cdev->rmmio = ioremap(cdev->rmmio_base, cdev->rmmio_size);
-
- if (cdev->rmmio == NULL)
- return -ENOMEM;
-
- ret = cirrus_vram_init(cdev);
- if (ret) {
- release_mem_region(cdev->rmmio_base, cdev->rmmio_size);
- return ret;
- }
-
- return 0;
-}
-
-void cirrus_device_fini(struct cirrus_device *cdev)
-{
- release_mem_region(cdev->rmmio_base, cdev->rmmio_size);
- cirrus_vram_fini(cdev);
-}
-
-/*
- * Functions here will be called by the core once it's bound the driver to
- * a PCI device
- */
-
-int cirrus_driver_load(struct drm_device *dev, unsigned long flags)
-{
- struct cirrus_device *cdev;
- int r;
-
- cdev = kzalloc(sizeof(struct cirrus_device), GFP_KERNEL);
- if (cdev == NULL)
- return -ENOMEM;
- dev->dev_private = (void *)cdev;
-
- r = cirrus_device_init(cdev, dev, dev->pdev, flags);
- if (r) {
- dev_err(&dev->pdev->dev, "Fatal error during GPU init: %d\n", r);
- goto out;
- }
-
- r = cirrus_mm_init(cdev);
- if (r) {
- dev_err(&dev->pdev->dev, "fatal err on mm init\n");
- goto out;
- }
-
- /*
- * cirrus_modeset_init() is initializing/registering the emulated fbdev
- * and DRM internals can access/test some of the fields in
- * mode_config->funcs as part of the fbdev registration process.
- * Make sure dev->mode_config.funcs is properly set to avoid
- * dereferencing a NULL pointer.
- * FIXME: mode_config.funcs assignment should probably be done in
- * cirrus_modeset_init() (that's a common pattern seen in other DRM
- * drivers).
- */
- dev->mode_config.funcs = &cirrus_mode_funcs;
- r = cirrus_modeset_init(cdev);
- if (r) {
- dev_err(&dev->pdev->dev, "Fatal error during modeset init: %d\n", r);
- goto out;
- }
-
- return 0;
-out:
- cirrus_driver_unload(dev);
- return r;
-}
-
-void cirrus_driver_unload(struct drm_device *dev)
-{
- struct cirrus_device *cdev = dev->dev_private;
-
- if (cdev == NULL)
- return;
- cirrus_modeset_fini(cdev);
- cirrus_mm_fini(cdev);
- cirrus_device_fini(cdev);
- kfree(cdev);
- dev->dev_private = NULL;
-}
-
-int cirrus_gem_create(struct drm_device *dev,
- u32 size, bool iskernel,
- struct drm_gem_object **obj)
-{
- struct cirrus_bo *cirrusbo;
- int ret;
-
- *obj = NULL;
-
- size = roundup(size, PAGE_SIZE);
- if (size == 0)
- return -EINVAL;
-
- ret = cirrus_bo_create(dev, size, 0, 0, &cirrusbo);
- if (ret) {
- if (ret != -ERESTARTSYS)
- DRM_ERROR("failed to allocate GEM object\n");
- return ret;
- }
- *obj = &cirrusbo->gem;
- return 0;
-}
-
-int cirrus_dumb_create(struct drm_file *file,
- struct drm_device *dev,
- struct drm_mode_create_dumb *args)
-{
- int ret;
- struct drm_gem_object *gobj;
- u32 handle;
-
- args->pitch = args->width * ((args->bpp + 7) / 8);
- args->size = args->pitch * args->height;
-
- ret = cirrus_gem_create(dev, args->size, false,
- &gobj);
- if (ret)
- return ret;
-
- ret = drm_gem_handle_create(file, gobj, &handle);
- drm_gem_object_put_unlocked(gobj);
- if (ret)
- return ret;
-
- args->handle = handle;
- return 0;
-}
-
-static void cirrus_bo_unref(struct cirrus_bo **bo)
-{
- struct ttm_buffer_object *tbo;
-
- if ((*bo) == NULL)
- return;
-
- tbo = &((*bo)->bo);
- ttm_bo_put(tbo);
- *bo = NULL;
-}
-
-void cirrus_gem_free_object(struct drm_gem_object *obj)
-{
- struct cirrus_bo *cirrus_bo = gem_to_cirrus_bo(obj);
-
- cirrus_bo_unref(&cirrus_bo);
-}
-
-
-static inline u64 cirrus_bo_mmap_offset(struct cirrus_bo *bo)
-{
- return drm_vma_node_offset_addr(&bo->bo.vma_node);
-}
-
-int
-cirrus_dumb_mmap_offset(struct drm_file *file,
- struct drm_device *dev,
- uint32_t handle,
- uint64_t *offset)
-{
- struct drm_gem_object *obj;
- struct cirrus_bo *bo;
-
- obj = drm_gem_object_lookup(file, handle);
- if (obj == NULL)
- return -ENOENT;
-
- bo = gem_to_cirrus_bo(obj);
- *offset = cirrus_bo_mmap_offset(bo);
-
- drm_gem_object_put_unlocked(obj);
-
- return 0;
-}
-
-bool cirrus_check_framebuffer(struct cirrus_device *cdev, int width, int height,
- int bpp, int pitch)
-{
- const int max_pitch = 0x1FF << 3; /* (4096 - 1) & ~111b bytes */
- const int max_size = cdev->mc.vram_size;
-
- if (bpp > cirrus_bpp)
- return false;
- if (bpp > 32)
- return false;
-
- if (pitch > max_pitch)
- return false;
-
- if (pitch * height > max_size)
- return false;
-
- return true;
-}
diff --git a/drivers/gpu/drm/cirrus/cirrus_mode.c b/drivers/gpu/drm/cirrus/cirrus_mode.c
deleted file mode 100644
index b109cd71426f..000000000000
--- a/drivers/gpu/drm/cirrus/cirrus_mode.c
+++ /dev/null
@@ -1,617 +0,0 @@
-
-/*
- * Copyright 2012 Red Hat
- *
- * This file is subject to the terms and conditions of the GNU General
- * Public License version 2. See the file COPYING in the main
- * directory of this archive for more details.
- *
- * Authors: Matthew Garrett
- * Dave Airlie
- *
- * Portions of this code derived from cirrusfb.c:
- * drivers/video/cirrusfb.c - driver for Cirrus Logic chipsets
- *
- * Copyright 1999-2001 Jeff Garzik <jgarzik@pobox.com>
- */
-#include <drm/drmP.h>
-#include <drm/drm_crtc_helper.h>
-#include <drm/drm_plane_helper.h>
-#include <drm/drm_probe_helper.h>
-
-#include <video/cirrus.h>
-
-#include "cirrus_drv.h"
-
-#define CIRRUS_LUT_SIZE 256
-
-#define PALETTE_INDEX 0x8
-#define PALETTE_DATA 0x9
-
-/*
- * This file contains setup code for the CRTC.
- */
-
-/*
- * The DRM core requires DPMS functions, but they make little sense in our
- * case and so are just stubs
- */
-
-static void cirrus_crtc_dpms(struct drm_crtc *crtc, int mode)
-{
- struct drm_device *dev = crtc->dev;
- struct cirrus_device *cdev = dev->dev_private;
- u8 sr01, gr0e;
-
- switch (mode) {
- case DRM_MODE_DPMS_ON:
- sr01 = 0x00;
- gr0e = 0x00;
- break;
- case DRM_MODE_DPMS_STANDBY:
- sr01 = 0x20;
- gr0e = 0x02;
- break;
- case DRM_MODE_DPMS_SUSPEND:
- sr01 = 0x20;
- gr0e = 0x04;
- break;
- case DRM_MODE_DPMS_OFF:
- sr01 = 0x20;
- gr0e = 0x06;
- break;
- default:
- return;
- }
-
- WREG8(SEQ_INDEX, 0x1);
- sr01 |= RREG8(SEQ_DATA) & ~0x20;
- WREG_SEQ(0x1, sr01);
-
- WREG8(GFX_INDEX, 0xe);
- gr0e |= RREG8(GFX_DATA) & ~0x06;
- WREG_GFX(0xe, gr0e);
-}
-
-static void cirrus_set_start_address(struct drm_crtc *crtc, unsigned offset)
-{
- struct cirrus_device *cdev = crtc->dev->dev_private;
- u32 addr;
- u8 tmp;
-
- addr = offset >> 2;
- WREG_CRT(0x0c, (u8)((addr >> 8) & 0xff));
- WREG_CRT(0x0d, (u8)(addr & 0xff));
-
- WREG8(CRT_INDEX, 0x1b);
- tmp = RREG8(CRT_DATA);
- tmp &= 0xf2;
- tmp |= (addr >> 16) & 0x01;
- tmp |= (addr >> 15) & 0x0c;
- WREG_CRT(0x1b, tmp);
- WREG8(CRT_INDEX, 0x1d);
- tmp = RREG8(CRT_DATA);
- tmp &= 0x7f;
- tmp |= (addr >> 12) & 0x80;
- WREG_CRT(0x1d, tmp);
-}
-
-/* cirrus is different - we will force move buffers out of VRAM */
-static int cirrus_crtc_do_set_base(struct drm_crtc *crtc,
- struct drm_framebuffer *fb,
- int x, int y, int atomic)
-{
- struct cirrus_device *cdev = crtc->dev->dev_private;
- struct cirrus_bo *bo;
- int ret;
- u64 gpu_addr;
-
- /* push the previous fb to system ram */
- if (!atomic && fb) {
- bo = gem_to_cirrus_bo(fb->obj[0]);
- ret = cirrus_bo_reserve(bo, false);
- if (ret)
- return ret;
- cirrus_bo_push_sysram(bo);
- cirrus_bo_unreserve(bo);
- }
-
- bo = gem_to_cirrus_bo(crtc->primary->fb->obj[0]);
-
- ret = cirrus_bo_reserve(bo, false);
- if (ret)
- return ret;
-
- ret = cirrus_bo_pin(bo, TTM_PL_FLAG_VRAM, &gpu_addr);
- if (ret) {
- cirrus_bo_unreserve(bo);
- return ret;
- }
-
- if (cdev->mode_info.gfbdev->gfb == crtc->primary->fb) {
- /* if pushing console in kmap it */
- ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap);
- if (ret)
- DRM_ERROR("failed to kmap fbcon\n");
- }
- cirrus_bo_unreserve(bo);
-
- cirrus_set_start_address(crtc, (u32)gpu_addr);
- return 0;
-}
-
-static int cirrus_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
- struct drm_framebuffer *old_fb)
-{
- return cirrus_crtc_do_set_base(crtc, old_fb, x, y, 0);
-}
-
-/*
- * The meat of this driver. The core passes us a mode and we have to program
- * it. The modesetting here is the bare minimum required to satisfy the qemu
- * emulation of this hardware, and running this against a real device is
- * likely to result in an inadequately programmed mode. We've already had
- * the opportunity to modify the mode, so whatever we receive here should
- * be something that can be correctly programmed and displayed
- */
-static int cirrus_crtc_mode_set(struct drm_crtc *crtc,
- struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode,
- int x, int y, struct drm_framebuffer *old_fb)
-{
- struct drm_device *dev = crtc->dev;
- struct cirrus_device *cdev = dev->dev_private;
- const struct drm_framebuffer *fb = crtc->primary->fb;
- int hsyncstart, hsyncend, htotal, hdispend;
- int vtotal, vdispend;
- int tmp;
- int sr07 = 0, hdr = 0;
-
- htotal = mode->htotal / 8;
- hsyncend = mode->hsync_end / 8;
- hsyncstart = mode->hsync_start / 8;
- hdispend = mode->hdisplay / 8;
-
- vtotal = mode->vtotal;
- vdispend = mode->vdisplay;
-
- vdispend -= 1;
- vtotal -= 2;
-
- htotal -= 5;
- hdispend -= 1;
- hsyncstart += 1;
- hsyncend += 1;
-
- WREG_CRT(VGA_CRTC_V_SYNC_END, 0x20);
- WREG_CRT(VGA_CRTC_H_TOTAL, htotal);
- WREG_CRT(VGA_CRTC_H_DISP, hdispend);
- WREG_CRT(VGA_CRTC_H_SYNC_START, hsyncstart);
- WREG_CRT(VGA_CRTC_H_SYNC_END, hsyncend);
- WREG_CRT(VGA_CRTC_V_TOTAL, vtotal & 0xff);
- WREG_CRT(VGA_CRTC_V_DISP_END, vdispend & 0xff);
-
- tmp = 0x40;
- if ((vdispend + 1) & 512)
- tmp |= 0x20;
- WREG_CRT(VGA_CRTC_MAX_SCAN, tmp);
-
- /*
- * Overflow bits for values that don't fit in the standard registers
- */
- tmp = 16;
- if (vtotal & 256)
- tmp |= 1;
- if (vdispend & 256)
- tmp |= 2;
- if ((vdispend + 1) & 256)
- tmp |= 8;
- if (vtotal & 512)
- tmp |= 32;
- if (vdispend & 512)
- tmp |= 64;
- WREG_CRT(VGA_CRTC_OVERFLOW, tmp);
-
- tmp = 0;
-
- /* More overflow bits */
-
- if ((htotal + 5) & 64)
- tmp |= 16;
- if ((htotal + 5) & 128)
- tmp |= 32;
- if (vtotal & 256)
- tmp |= 64;
- if (vtotal & 512)
- tmp |= 128;
-
- WREG_CRT(CL_CRT1A, tmp);
-
- /* Disable Hercules/CGA compatibility */
- WREG_CRT(VGA_CRTC_MODE, 0x03);
-
- WREG8(SEQ_INDEX, 0x7);
- sr07 = RREG8(SEQ_DATA);
- sr07 &= 0xe0;
- hdr = 0;
- switch (fb->format->cpp[0] * 8) {
- case 8:
- sr07 |= 0x11;
- break;
- case 16:
- sr07 |= 0x17;
- hdr = 0xc1;
- break;
- case 24:
- sr07 |= 0x15;
- hdr = 0xc5;
- break;
- case 32:
- sr07 |= 0x19;
- hdr = 0xc5;
- break;
- default:
- return -1;
- }
-
- WREG_SEQ(0x7, sr07);
-
- /* Program the pitch */
- tmp = fb->pitches[0] / 8;
- WREG_CRT(VGA_CRTC_OFFSET, tmp);
-
- /* Enable extended blanking and pitch bits, and enable full memory */
- tmp = 0x22;
- tmp |= (fb->pitches[0] >> 7) & 0x10;
- tmp |= (fb->pitches[0] >> 6) & 0x40;
- WREG_CRT(0x1b, tmp);
-
- /* Enable high-colour modes */
- WREG_GFX(VGA_GFX_MODE, 0x40);
-
- /* And set graphics mode */
- WREG_GFX(VGA_GFX_MISC, 0x01);
-
- WREG_HDR(hdr);
- cirrus_crtc_do_set_base(crtc, old_fb, x, y, 0);
-
- /* Unblank (needed on S3 resume, vgabios doesn't do it then) */
- outb(0x20, 0x3c0);
- return 0;
-}
-
-/*
- * This is called before a mode is programmed. A typical use might be to
- * enable DPMS during the programming to avoid seeing intermediate stages,
- * but that's not relevant to us
- */
-static void cirrus_crtc_prepare(struct drm_crtc *crtc)
-{
-}
-
-static void cirrus_crtc_load_lut(struct drm_crtc *crtc)
-{
- struct drm_device *dev = crtc->dev;
- struct cirrus_device *cdev = dev->dev_private;
- u16 *r, *g, *b;
- int i;
-
- if (!crtc->enabled)
- return;
-
- r = crtc->gamma_store;
- g = r + crtc->gamma_size;
- b = g + crtc->gamma_size;
-
- for (i = 0; i < CIRRUS_LUT_SIZE; i++) {
- /* VGA registers */
- WREG8(PALETTE_INDEX, i);
- WREG8(PALETTE_DATA, *r++ >> 8);
- WREG8(PALETTE_DATA, *g++ >> 8);
- WREG8(PALETTE_DATA, *b++ >> 8);
- }
-}
-
-/*
- * This is called after a mode is programmed. It should reverse anything done
- * by the prepare function
- */
-static void cirrus_crtc_commit(struct drm_crtc *crtc)
-{
- cirrus_crtc_load_lut(crtc);
-}
-
-/*
- * The core can pass us a set of gamma values to program. We actually only
- * use this for 8-bit mode so can't perform smooth fades on deeper modes,
- * but it's a requirement that we provide the function
- */
-static int cirrus_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green,
- u16 *blue, uint32_t size,
- struct drm_modeset_acquire_ctx *ctx)
-{
- cirrus_crtc_load_lut(crtc);
-
- return 0;
-}
-
-/* Simple cleanup function */
-static void cirrus_crtc_destroy(struct drm_crtc *crtc)
-{
- struct cirrus_crtc *cirrus_crtc = to_cirrus_crtc(crtc);
-
- drm_crtc_cleanup(crtc);
- kfree(cirrus_crtc);
-}
-
-/* These provide the minimum set of functions required to handle a CRTC */
-static const struct drm_crtc_funcs cirrus_crtc_funcs = {
- .gamma_set = cirrus_crtc_gamma_set,
- .set_config = drm_crtc_helper_set_config,
- .destroy = cirrus_crtc_destroy,
-};
-
-static const struct drm_crtc_helper_funcs cirrus_helper_funcs = {
- .dpms = cirrus_crtc_dpms,
- .mode_set = cirrus_crtc_mode_set,
- .mode_set_base = cirrus_crtc_mode_set_base,
- .prepare = cirrus_crtc_prepare,
- .commit = cirrus_crtc_commit,
-};
-
-/* CRTC setup */
-static const uint32_t cirrus_formats_16[] = {
- DRM_FORMAT_RGB565,
-};
-
-static const uint32_t cirrus_formats_24[] = {
- DRM_FORMAT_RGB888,
- DRM_FORMAT_RGB565,
-};
-
-static const uint32_t cirrus_formats_32[] = {
- DRM_FORMAT_XRGB8888,
- DRM_FORMAT_ARGB8888,
- DRM_FORMAT_RGB888,
- DRM_FORMAT_RGB565,
-};
-
-static struct drm_plane *cirrus_primary_plane(struct drm_device *dev)
-{
- const uint32_t *formats;
- uint32_t nformats;
- struct drm_plane *primary;
- int ret;
-
- switch (cirrus_bpp) {
- case 16:
- formats = cirrus_formats_16;
- nformats = ARRAY_SIZE(cirrus_formats_16);
- break;
- case 24:
- formats = cirrus_formats_24;
- nformats = ARRAY_SIZE(cirrus_formats_24);
- break;
- case 32:
- formats = cirrus_formats_32;
- nformats = ARRAY_SIZE(cirrus_formats_32);
- break;
- default:
- return NULL;
- }
-
- primary = kzalloc(sizeof(*primary), GFP_KERNEL);
- if (primary == NULL) {
- DRM_DEBUG_KMS("Failed to allocate primary plane\n");
- return NULL;
- }
-
- ret = drm_universal_plane_init(dev, primary, 0,
- &drm_primary_helper_funcs,
- formats, nformats,
- NULL,
- DRM_PLANE_TYPE_PRIMARY, NULL);
- if (ret) {
- kfree(primary);
- primary = NULL;
- }
-
- return primary;
-}
-
-static void cirrus_crtc_init(struct drm_device *dev)
-{
- struct cirrus_device *cdev = dev->dev_private;
- struct cirrus_crtc *cirrus_crtc;
- struct drm_plane *primary;
-
- cirrus_crtc = kzalloc(sizeof(struct cirrus_crtc) +
- (CIRRUSFB_CONN_LIMIT * sizeof(struct drm_connector *)),
- GFP_KERNEL);
-
- if (cirrus_crtc == NULL)
- return;
-
- primary = cirrus_primary_plane(dev);
- if (primary == NULL) {
- kfree(cirrus_crtc);
- return;
- }
-
- drm_crtc_init_with_planes(dev, &cirrus_crtc->base,
- primary, NULL,
- &cirrus_crtc_funcs, NULL);
-
- drm_mode_crtc_set_gamma_size(&cirrus_crtc->base, CIRRUS_LUT_SIZE);
- cdev->mode_info.crtc = cirrus_crtc;
-
- drm_crtc_helper_add(&cirrus_crtc->base, &cirrus_helper_funcs);
-}
-
-static void cirrus_encoder_mode_set(struct drm_encoder *encoder,
- struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode)
-{
-}
-
-static void cirrus_encoder_dpms(struct drm_encoder *encoder, int state)
-{
- return;
-}
-
-static void cirrus_encoder_prepare(struct drm_encoder *encoder)
-{
-}
-
-static void cirrus_encoder_commit(struct drm_encoder *encoder)
-{
-}
-
-static void cirrus_encoder_destroy(struct drm_encoder *encoder)
-{
- struct cirrus_encoder *cirrus_encoder = to_cirrus_encoder(encoder);
- drm_encoder_cleanup(encoder);
- kfree(cirrus_encoder);
-}
-
-static const struct drm_encoder_helper_funcs cirrus_encoder_helper_funcs = {
- .dpms = cirrus_encoder_dpms,
- .mode_set = cirrus_encoder_mode_set,
- .prepare = cirrus_encoder_prepare,
- .commit = cirrus_encoder_commit,
-};
-
-static const struct drm_encoder_funcs cirrus_encoder_encoder_funcs = {
- .destroy = cirrus_encoder_destroy,
-};
-
-static struct drm_encoder *cirrus_encoder_init(struct drm_device *dev)
-{
- struct drm_encoder *encoder;
- struct cirrus_encoder *cirrus_encoder;
-
- cirrus_encoder = kzalloc(sizeof(struct cirrus_encoder), GFP_KERNEL);
- if (!cirrus_encoder)
- return NULL;
-
- encoder = &cirrus_encoder->base;
- encoder->possible_crtcs = 0x1;
-
- drm_encoder_init(dev, encoder, &cirrus_encoder_encoder_funcs,
- DRM_MODE_ENCODER_DAC, NULL);
- drm_encoder_helper_add(encoder, &cirrus_encoder_helper_funcs);
-
- return encoder;
-}
-
-
-static int cirrus_vga_get_modes(struct drm_connector *connector)
-{
- int count;
-
- /* Just add a static list of modes */
- if (cirrus_bpp <= 24) {
- count = drm_add_modes_noedid(connector, 1280, 1024);
- drm_set_preferred_mode(connector, 1024, 768);
- } else {
- count = drm_add_modes_noedid(connector, 800, 600);
- drm_set_preferred_mode(connector, 800, 600);
- }
- return count;
-}
-
-static struct drm_encoder *cirrus_connector_best_encoder(struct drm_connector
- *connector)
-{
- int enc_id = connector->encoder_ids[0];
- /* pick the encoder ids */
- if (enc_id)
- return drm_encoder_find(connector->dev, NULL, enc_id);
- return NULL;
-}
-
-static void cirrus_connector_destroy(struct drm_connector *connector)
-{
- drm_connector_cleanup(connector);
- kfree(connector);
-}
-
-static const struct drm_connector_helper_funcs cirrus_vga_connector_helper_funcs = {
- .get_modes = cirrus_vga_get_modes,
- .best_encoder = cirrus_connector_best_encoder,
-};
-
-static const struct drm_connector_funcs cirrus_vga_connector_funcs = {
- .dpms = drm_helper_connector_dpms,
- .fill_modes = drm_helper_probe_single_connector_modes,
- .destroy = cirrus_connector_destroy,
-};
-
-static struct drm_connector *cirrus_vga_init(struct drm_device *dev)
-{
- struct drm_connector *connector;
- struct cirrus_connector *cirrus_connector;
-
- cirrus_connector = kzalloc(sizeof(struct cirrus_connector), GFP_KERNEL);
- if (!cirrus_connector)
- return NULL;
-
- connector = &cirrus_connector->base;
-
- drm_connector_init(dev, connector,
- &cirrus_vga_connector_funcs, DRM_MODE_CONNECTOR_VGA);
-
- drm_connector_helper_add(connector, &cirrus_vga_connector_helper_funcs);
-
- drm_connector_register(connector);
- return connector;
-}
-
-
-int cirrus_modeset_init(struct cirrus_device *cdev)
-{
- struct drm_encoder *encoder;
- struct drm_connector *connector;
- int ret;
-
- drm_mode_config_init(cdev->dev);
-
- cdev->dev->mode_config.max_width = CIRRUS_MAX_FB_WIDTH;
- cdev->dev->mode_config.max_height = CIRRUS_MAX_FB_HEIGHT;
-
- cdev->dev->mode_config.fb_base = cdev->mc.vram_base;
- cdev->dev->mode_config.preferred_depth = cirrus_bpp;
- /* don't prefer a shadow on virt GPU */
- cdev->dev->mode_config.prefer_shadow = 0;
-
- cirrus_crtc_init(cdev->dev);
-
- encoder = cirrus_encoder_init(cdev->dev);
- if (!encoder) {
- DRM_ERROR("cirrus_encoder_init failed\n");
- return -1;
- }
-
- connector = cirrus_vga_init(cdev->dev);
- if (!connector) {
- DRM_ERROR("cirrus_vga_init failed\n");
- return -1;
- }
-
- drm_connector_attach_encoder(connector, encoder);
-
- ret = cirrus_fbdev_init(cdev);
- if (ret) {
- DRM_ERROR("cirrus_fbdev_init failed\n");
- return ret;
- }
-
- return 0;
-}
-
-void cirrus_modeset_fini(struct cirrus_device *cdev)
-{
- cirrus_fbdev_fini(cdev);
- drm_helper_force_disable_all(cdev->dev);
- drm_mode_config_cleanup(cdev->dev);
-}
diff --git a/drivers/gpu/drm/cirrus/cirrus_ttm.c b/drivers/gpu/drm/cirrus/cirrus_ttm.c
deleted file mode 100644
index e075810b4bd4..000000000000
--- a/drivers/gpu/drm/cirrus/cirrus_ttm.c
+++ /dev/null
@@ -1,343 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sub license, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
- * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
- * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
- * USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial portions
- * of the Software.
- *
- */
-/*
- * Authors: Dave Airlie <airlied@redhat.com>
- */
-#include <drm/drmP.h>
-#include <drm/ttm/ttm_page_alloc.h>
-
-#include "cirrus_drv.h"
-
-static inline struct cirrus_device *
-cirrus_bdev(struct ttm_bo_device *bd)
-{
- return container_of(bd, struct cirrus_device, ttm.bdev);
-}
-
-static void cirrus_bo_ttm_destroy(struct ttm_buffer_object *tbo)
-{
- struct cirrus_bo *bo;
-
- bo = container_of(tbo, struct cirrus_bo, bo);
-
- drm_gem_object_release(&bo->gem);
- kfree(bo);
-}
-
-static bool cirrus_ttm_bo_is_cirrus_bo(struct ttm_buffer_object *bo)
-{
- if (bo->destroy == &cirrus_bo_ttm_destroy)
- return true;
- return false;
-}
-
-static int
-cirrus_bo_init_mem_type(struct ttm_bo_device *bdev, uint32_t type,
- struct ttm_mem_type_manager *man)
-{
- switch (type) {
- case TTM_PL_SYSTEM:
- man->flags = TTM_MEMTYPE_FLAG_MAPPABLE;
- man->available_caching = TTM_PL_MASK_CACHING;
- man->default_caching = TTM_PL_FLAG_CACHED;
- break;
- case TTM_PL_VRAM:
- man->func = &ttm_bo_manager_func;
- man->flags = TTM_MEMTYPE_FLAG_FIXED |
- TTM_MEMTYPE_FLAG_MAPPABLE;
- man->available_caching = TTM_PL_FLAG_UNCACHED |
- TTM_PL_FLAG_WC;
- man->default_caching = TTM_PL_FLAG_WC;
- break;
- default:
- DRM_ERROR("Unsupported memory type %u\n", (unsigned)type);
- return -EINVAL;
- }
- return 0;
-}
-
-static void
-cirrus_bo_evict_flags(struct ttm_buffer_object *bo, struct ttm_placement *pl)
-{
- struct cirrus_bo *cirrusbo = cirrus_bo(bo);
-
- if (!cirrus_ttm_bo_is_cirrus_bo(bo))
- return;
-
- cirrus_ttm_placement(cirrusbo, TTM_PL_FLAG_SYSTEM);
- *pl = cirrusbo->placement;
-}
-
-static int cirrus_bo_verify_access(struct ttm_buffer_object *bo, struct file *filp)
-{
- struct cirrus_bo *cirrusbo = cirrus_bo(bo);
-
- return drm_vma_node_verify_access(&cirrusbo->gem.vma_node,
- filp->private_data);
-}
-
-static int cirrus_ttm_io_mem_reserve(struct ttm_bo_device *bdev,
- struct ttm_mem_reg *mem)
-{
- struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type];
- struct cirrus_device *cirrus = cirrus_bdev(bdev);
-
- mem->bus.addr = NULL;
- mem->bus.offset = 0;
- mem->bus.size = mem->num_pages << PAGE_SHIFT;
- mem->bus.base = 0;
- mem->bus.is_iomem = false;
- if (!(man->flags & TTM_MEMTYPE_FLAG_MAPPABLE))
- return -EINVAL;
- switch (mem->mem_type) {
- case TTM_PL_SYSTEM:
- /* system memory */
- return 0;
- case TTM_PL_VRAM:
- mem->bus.offset = mem->start << PAGE_SHIFT;
- mem->bus.base = pci_resource_start(cirrus->dev->pdev, 0);
- mem->bus.is_iomem = true;
- break;
- default:
- return -EINVAL;
- break;
- }
- return 0;
-}
-
-static void cirrus_ttm_io_mem_free(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem)
-{
-}
-
-static void cirrus_ttm_backend_destroy(struct ttm_tt *tt)
-{
- ttm_tt_fini(tt);
- kfree(tt);
-}
-
-static struct ttm_backend_func cirrus_tt_backend_func = {
- .destroy = &cirrus_ttm_backend_destroy,
-};
-
-
-static struct ttm_tt *cirrus_ttm_tt_create(struct ttm_buffer_object *bo,
- uint32_t page_flags)
-{
- struct ttm_tt *tt;
-
- tt = kzalloc(sizeof(struct ttm_tt), GFP_KERNEL);
- if (tt == NULL)
- return NULL;
- tt->func = &cirrus_tt_backend_func;
- if (ttm_tt_init(tt, bo, page_flags)) {
- kfree(tt);
- return NULL;
- }
- return tt;
-}
-
-struct ttm_bo_driver cirrus_bo_driver = {
- .ttm_tt_create = cirrus_ttm_tt_create,
- .init_mem_type = cirrus_bo_init_mem_type,
- .eviction_valuable = ttm_bo_eviction_valuable,
- .evict_flags = cirrus_bo_evict_flags,
- .move = NULL,
- .verify_access = cirrus_bo_verify_access,
- .io_mem_reserve = &cirrus_ttm_io_mem_reserve,
- .io_mem_free = &cirrus_ttm_io_mem_free,
-};
-
-int cirrus_mm_init(struct cirrus_device *cirrus)
-{
- int ret;
- struct drm_device *dev = cirrus->dev;
- struct ttm_bo_device *bdev = &cirrus->ttm.bdev;
-
- ret = ttm_bo_device_init(&cirrus->ttm.bdev,
- &cirrus_bo_driver,
- dev->anon_inode->i_mapping,
- DRM_FILE_PAGE_OFFSET,
- true);
- if (ret) {
- DRM_ERROR("Error initialising bo driver; %d\n", ret);
- return ret;
- }
-
- ret = ttm_bo_init_mm(bdev, TTM_PL_VRAM,
- cirrus->mc.vram_size >> PAGE_SHIFT);
- if (ret) {
- DRM_ERROR("Failed ttm VRAM init: %d\n", ret);
- return ret;
- }
-
- arch_io_reserve_memtype_wc(pci_resource_start(dev->pdev, 0),
- pci_resource_len(dev->pdev, 0));
-
- cirrus->fb_mtrr = arch_phys_wc_add(pci_resource_start(dev->pdev, 0),
- pci_resource_len(dev->pdev, 0));
-
- cirrus->mm_inited = true;
- return 0;
-}
-
-void cirrus_mm_fini(struct cirrus_device *cirrus)
-{
- struct drm_device *dev = cirrus->dev;
-
- if (!cirrus->mm_inited)
- return;
-
- ttm_bo_device_release(&cirrus->ttm.bdev);
-
- arch_phys_wc_del(cirrus->fb_mtrr);
- cirrus->fb_mtrr = 0;
- arch_io_free_memtype_wc(pci_resource_start(dev->pdev, 0),
- pci_resource_len(dev->pdev, 0));
-}
-
-void cirrus_ttm_placement(struct cirrus_bo *bo, int domain)
-{
- u32 c = 0;
- unsigned i;
- bo->placement.placement = bo->placements;
- bo->placement.busy_placement = bo->placements;
- if (domain & TTM_PL_FLAG_VRAM)
- bo->placements[c++].flags = TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_VRAM;
- if (domain & TTM_PL_FLAG_SYSTEM)
- bo->placements[c++].flags = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM;
- if (!c)
- bo->placements[c++].flags = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM;
- bo->placement.num_placement = c;
- bo->placement.num_busy_placement = c;
- for (i = 0; i < c; ++i) {
- bo->placements[i].fpfn = 0;
- bo->placements[i].lpfn = 0;
- }
-}
-
-int cirrus_bo_create(struct drm_device *dev, int size, int align,
- uint32_t flags, struct cirrus_bo **pcirrusbo)
-{
- struct cirrus_device *cirrus = dev->dev_private;
- struct cirrus_bo *cirrusbo;
- size_t acc_size;
- int ret;
-
- cirrusbo = kzalloc(sizeof(struct cirrus_bo), GFP_KERNEL);
- if (!cirrusbo)
- return -ENOMEM;
-
- ret = drm_gem_object_init(dev, &cirrusbo->gem, size);
- if (ret) {
- kfree(cirrusbo);
- return ret;
- }
-
- cirrusbo->bo.bdev = &cirrus->ttm.bdev;
-
- cirrus_ttm_placement(cirrusbo, TTM_PL_FLAG_VRAM | TTM_PL_FLAG_SYSTEM);
-
- acc_size = ttm_bo_dma_acc_size(&cirrus->ttm.bdev, size,
- sizeof(struct cirrus_bo));
-
- ret = ttm_bo_init(&cirrus->ttm.bdev, &cirrusbo->bo, size,
- ttm_bo_type_device, &cirrusbo->placement,
- align >> PAGE_SHIFT, false, acc_size,
- NULL, NULL, cirrus_bo_ttm_destroy);
- if (ret)
- return ret;
-
- *pcirrusbo = cirrusbo;
- return 0;
-}
-
-static inline u64 cirrus_bo_gpu_offset(struct cirrus_bo *bo)
-{
- return bo->bo.offset;
-}
-
-int cirrus_bo_pin(struct cirrus_bo *bo, u32 pl_flag, u64 *gpu_addr)
-{
- struct ttm_operation_ctx ctx = { false, false };
- int i, ret;
-
- if (bo->pin_count) {
- bo->pin_count++;
- if (gpu_addr)
- *gpu_addr = cirrus_bo_gpu_offset(bo);
- }
-
- cirrus_ttm_placement(bo, pl_flag);
- for (i = 0; i < bo->placement.num_placement; i++)
- bo->placements[i].flags |= TTM_PL_FLAG_NO_EVICT;
- ret = ttm_bo_validate(&bo->bo, &bo->placement, &ctx);
- if (ret)
- return ret;
-
- bo->pin_count = 1;
- if (gpu_addr)
- *gpu_addr = cirrus_bo_gpu_offset(bo);
- return 0;
-}
-
-int cirrus_bo_push_sysram(struct cirrus_bo *bo)
-{
- struct ttm_operation_ctx ctx = { false, false };
- int i, ret;
- if (!bo->pin_count) {
- DRM_ERROR("unpin bad %p\n", bo);
- return 0;
- }
- bo->pin_count--;
- if (bo->pin_count)
- return 0;
-
- if (bo->kmap.virtual)
- ttm_bo_kunmap(&bo->kmap);
-
- cirrus_ttm_placement(bo, TTM_PL_FLAG_SYSTEM);
- for (i = 0; i < bo->placement.num_placement ; i++)
- bo->placements[i].flags |= TTM_PL_FLAG_NO_EVICT;
-
- ret = ttm_bo_validate(&bo->bo, &bo->placement, &ctx);
- if (ret) {
- DRM_ERROR("pushing to VRAM failed\n");
- return ret;
- }
- return 0;
-}
-
-int cirrus_mmap(struct file *filp, struct vm_area_struct *vma)
-{
- struct drm_file *file_priv;
- struct cirrus_device *cirrus;
-
- if (unlikely(vma->vm_pgoff < DRM_FILE_PAGE_OFFSET))
- return -EINVAL;
-
- file_priv = filp->private_data;
- cirrus = file_priv->minor->dev->dev_private;
- return ttm_bo_mmap(filp, vma, &cirrus->ttm.bdev);
-}
diff --git a/drivers/gpu/drm/cirrus/Kconfig b/drivers/gpu/drm/cirrus/Kconfig
index fc78c90ee931..dd4f52a0bc1c 100644
--- a/drivers/gpu/drm/cirrus/Kconfig
+++ b/drivers/gpu/drm/cirrus/Kconfig
@@ -2,7 +2,7 @@ config DRM_CIRRUS_QEMU
tristate "Cirrus driver for QEMU emulated device"
depends on DRM && PCI && MMU
select DRM_KMS_HELPER
- select DRM_TTM
+ select DRM_GEM_SHMEM_HELPER
help
This is a KMS driver for emulated cirrus device in qemu.
It is *NOT* intended for real cirrus devices. This requires
diff --git a/drivers/gpu/drm/cirrus/Makefile b/drivers/gpu/drm/cirrus/Makefile
index 919c0a336c97..acf8971d37a1 100644
--- a/drivers/gpu/drm/cirrus/Makefile
+++ b/drivers/gpu/drm/cirrus/Makefile
@@ -1,4 +1 @@
-cirrus-y := cirrus_main.o cirrus_mode.o \
- cirrus_drv.o cirrus_fbdev.o cirrus_ttm.o
-
obj-$(CONFIG_DRM_CIRRUS_QEMU) += cirrus.o
--
2.18.1
^ permalink raw reply related
* Re: [PATCH] drm/cirrus: rewrite and modernize driver.
From: Daniel Vetter @ 2019-04-03 7:47 UTC (permalink / raw)
To: Gerd Hoffmann
Cc: David Airlie, Dave Airlie, open list, dri-devel,
open list:DRM DRIVER FOR QEMU'S CIRRUS DEVICE
In-Reply-To: <20190403072318.31507-1-kraxel@redhat.com>
On Wed, Apr 3, 2019 at 9:23 AM Gerd Hoffmann <kraxel@redhat.com> wrote:
>
> Time to kill some bad sample code people are copying from ;)
>
> This is a complete rewrite of the cirrus driver. The cirrus_mode_set()
> function is pretty much the only function which is carried over largely
> unmodified. Everything else is upside down.
>
> It is a single monster patch. But given that it does some pretty
> fundamental changes to the drivers workflow and also reduces the code
> size by roughly 70% I think it'll still be alot easier to review than a
> longish baby-step patch series.
>
> Changes summary:
> - Given the small amout of video memory (4 MB) the cirrus device has
> the rewritten driver doesn't try to manage buffers there. Instead
> it will blit (memcpy) the active framebuffer to video memory.
> - All gem objects are stored in main memory and are manged using the
> new shmem helpers. ttm is out.
> - Only DRM_FORMAT_RGB565 (depth 16) is supported. The old driver does
> that too by default. There was a module parameter which enables 24/32
> bpp support and disables higher resolutions (due to cirrus hardware
> constrains). That parameter wasn't reimplemented.
> - The simple display pipeline is used.
> - The generic fbdev emulation is used.
> - It's a atomic driver now.
Sounds all awesome. Some tiny comments below, with those addressed
looks all good and gets my
Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
-Daniel
> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
> ---
> drivers/gpu/drm/cirrus/cirrus_drv.h | 251 -----------
> drivers/gpu/drm/cirrus/cirrus.c | 602 +++++++++++++++++++++++++
> drivers/gpu/drm/cirrus/cirrus_drv.c | 161 -------
> drivers/gpu/drm/cirrus/cirrus_fbdev.c | 309 -------------
> drivers/gpu/drm/cirrus/cirrus_main.c | 328 --------------
> drivers/gpu/drm/cirrus/cirrus_mode.c | 617 --------------------------
> drivers/gpu/drm/cirrus/cirrus_ttm.c | 343 --------------
> drivers/gpu/drm/cirrus/Kconfig | 2 +-
> drivers/gpu/drm/cirrus/Makefile | 3 -
> 9 files changed, 603 insertions(+), 2013 deletions(-)
> delete mode 100644 drivers/gpu/drm/cirrus/cirrus_drv.h
> create mode 100644 drivers/gpu/drm/cirrus/cirrus.c
> delete mode 100644 drivers/gpu/drm/cirrus/cirrus_drv.c
> delete mode 100644 drivers/gpu/drm/cirrus/cirrus_fbdev.c
> delete mode 100644 drivers/gpu/drm/cirrus/cirrus_main.c
> delete mode 100644 drivers/gpu/drm/cirrus/cirrus_mode.c
> delete mode 100644 drivers/gpu/drm/cirrus/cirrus_ttm.c
>
> diff --git a/drivers/gpu/drm/cirrus/cirrus_drv.h b/drivers/gpu/drm/cirrus/cirrus_drv.h
> deleted file mode 100644
> index 828b150cdb20..000000000000
> --- a/drivers/gpu/drm/cirrus/cirrus_drv.h
> +++ /dev/null
> @@ -1,251 +0,0 @@
> -/*
> - * Copyright 2012 Red Hat
> - *
> - * This file is subject to the terms and conditions of the GNU General
> - * Public License version 2. See the file COPYING in the main
> - * directory of this archive for more details.
> - *
> - * Authors: Matthew Garrett
> - * Dave Airlie
> - */
> -#ifndef __CIRRUS_DRV_H__
> -#define __CIRRUS_DRV_H__
> -
> -#include <video/vga.h>
> -
> -#include <drm/drm_encoder.h>
> -#include <drm/drm_fb_helper.h>
> -
> -#include <drm/ttm/ttm_bo_api.h>
> -#include <drm/ttm/ttm_bo_driver.h>
> -#include <drm/ttm/ttm_placement.h>
> -#include <drm/ttm/ttm_memory.h>
> -#include <drm/ttm/ttm_module.h>
> -
> -#include <drm/drm_gem.h>
> -
> -#define DRIVER_AUTHOR "Matthew Garrett"
> -
> -#define DRIVER_NAME "cirrus"
> -#define DRIVER_DESC "qemu Cirrus emulation"
> -#define DRIVER_DATE "20110418"
> -
> -#define DRIVER_MAJOR 1
> -#define DRIVER_MINOR 0
> -#define DRIVER_PATCHLEVEL 0
> -
> -#define CIRRUSFB_CONN_LIMIT 1
> -
> -#define RREG8(reg) ioread8(((void __iomem *)cdev->rmmio) + (reg))
> -#define WREG8(reg, v) iowrite8(v, ((void __iomem *)cdev->rmmio) + (reg))
> -#define RREG32(reg) ioread32(((void __iomem *)cdev->rmmio) + (reg))
> -#define WREG32(reg, v) iowrite32(v, ((void __iomem *)cdev->rmmio) + (reg))
> -
> -#define SEQ_INDEX 4
> -#define SEQ_DATA 5
> -
> -#define WREG_SEQ(reg, v) \
> - do { \
> - WREG8(SEQ_INDEX, reg); \
> - WREG8(SEQ_DATA, v); \
> - } while (0) \
> -
> -#define CRT_INDEX 0x14
> -#define CRT_DATA 0x15
> -
> -#define WREG_CRT(reg, v) \
> - do { \
> - WREG8(CRT_INDEX, reg); \
> - WREG8(CRT_DATA, v); \
> - } while (0) \
> -
> -#define GFX_INDEX 0xe
> -#define GFX_DATA 0xf
> -
> -#define WREG_GFX(reg, v) \
> - do { \
> - WREG8(GFX_INDEX, reg); \
> - WREG8(GFX_DATA, v); \
> - } while (0) \
> -
> -/*
> - * Cirrus has a "hidden" DAC register that can be accessed by writing to
> - * the pixel mask register to reset the state, then reading from the register
> - * four times. The next write will then pass to the DAC
> - */
> -#define VGA_DAC_MASK 0x6
> -
> -#define WREG_HDR(v) \
> - do { \
> - RREG8(VGA_DAC_MASK); \
> - RREG8(VGA_DAC_MASK); \
> - RREG8(VGA_DAC_MASK); \
> - RREG8(VGA_DAC_MASK); \
> - WREG8(VGA_DAC_MASK, v); \
> - } while (0) \
> -
> -
> -#define CIRRUS_MAX_FB_HEIGHT 4096
> -#define CIRRUS_MAX_FB_WIDTH 4096
> -
> -#define CIRRUS_DPMS_CLEARED (-1)
> -
> -#define to_cirrus_crtc(x) container_of(x, struct cirrus_crtc, base)
> -#define to_cirrus_encoder(x) container_of(x, struct cirrus_encoder, base)
> -
> -struct cirrus_crtc {
> - struct drm_crtc base;
> - int last_dpms;
> - bool enabled;
> -};
> -
> -struct cirrus_fbdev;
> -struct cirrus_mode_info {
> - struct cirrus_crtc *crtc;
> - /* pointer to fbdev info structure */
> - struct cirrus_fbdev *gfbdev;
> -};
> -
> -struct cirrus_encoder {
> - struct drm_encoder base;
> - int last_dpms;
> -};
> -
> -struct cirrus_connector {
> - struct drm_connector base;
> -};
> -
> -struct cirrus_mc {
> - resource_size_t vram_size;
> - resource_size_t vram_base;
> -};
> -
> -struct cirrus_device {
> - struct drm_device *dev;
> - unsigned long flags;
> -
> - resource_size_t rmmio_base;
> - resource_size_t rmmio_size;
> - void __iomem *rmmio;
> -
> - struct cirrus_mc mc;
> - struct cirrus_mode_info mode_info;
> -
> - int num_crtc;
> - int fb_mtrr;
> -
> - struct {
> - struct ttm_bo_device bdev;
> - } ttm;
> - bool mm_inited;
> -};
> -
> -
> -struct cirrus_fbdev {
> - struct drm_fb_helper helper; /* must be first */
> - struct drm_framebuffer *gfb;
> - void *sysram;
> - int size;
> - int x1, y1, x2, y2; /* dirty rect */
> - spinlock_t dirty_lock;
> -};
> -
> -struct cirrus_bo {
> - struct ttm_buffer_object bo;
> - struct ttm_placement placement;
> - struct ttm_bo_kmap_obj kmap;
> - struct drm_gem_object gem;
> - struct ttm_place placements[3];
> - int pin_count;
> -};
> -#define gem_to_cirrus_bo(gobj) container_of((gobj), struct cirrus_bo, gem)
> -
> -static inline struct cirrus_bo *
> -cirrus_bo(struct ttm_buffer_object *bo)
> -{
> - return container_of(bo, struct cirrus_bo, bo);
> -}
> -
> -
> -#define to_cirrus_obj(x) container_of(x, struct cirrus_gem_object, base)
> -#define DRM_FILE_PAGE_OFFSET (0x100000000ULL >> PAGE_SHIFT)
> -
> - /* cirrus_main.c */
> -int cirrus_device_init(struct cirrus_device *cdev,
> - struct drm_device *ddev,
> - struct pci_dev *pdev,
> - uint32_t flags);
> -void cirrus_device_fini(struct cirrus_device *cdev);
> -void cirrus_gem_free_object(struct drm_gem_object *obj);
> -int cirrus_dumb_mmap_offset(struct drm_file *file,
> - struct drm_device *dev,
> - uint32_t handle,
> - uint64_t *offset);
> -int cirrus_gem_create(struct drm_device *dev,
> - u32 size, bool iskernel,
> - struct drm_gem_object **obj);
> -int cirrus_dumb_create(struct drm_file *file,
> - struct drm_device *dev,
> - struct drm_mode_create_dumb *args);
> -
> -int cirrus_framebuffer_init(struct drm_device *dev,
> - struct drm_framebuffer *gfb,
> - const struct drm_mode_fb_cmd2 *mode_cmd,
> - struct drm_gem_object *obj);
> -
> -bool cirrus_check_framebuffer(struct cirrus_device *cdev, int width, int height,
> - int bpp, int pitch);
> -
> - /* cirrus_display.c */
> -int cirrus_modeset_init(struct cirrus_device *cdev);
> -void cirrus_modeset_fini(struct cirrus_device *cdev);
> -
> - /* cirrus_fbdev.c */
> -int cirrus_fbdev_init(struct cirrus_device *cdev);
> -void cirrus_fbdev_fini(struct cirrus_device *cdev);
> -
> -
> -
> - /* cirrus_irq.c */
> -void cirrus_driver_irq_preinstall(struct drm_device *dev);
> -int cirrus_driver_irq_postinstall(struct drm_device *dev);
> -void cirrus_driver_irq_uninstall(struct drm_device *dev);
> -irqreturn_t cirrus_driver_irq_handler(int irq, void *arg);
> -
> - /* cirrus_kms.c */
> -int cirrus_driver_load(struct drm_device *dev, unsigned long flags);
> -void cirrus_driver_unload(struct drm_device *dev);
> -extern struct drm_ioctl_desc cirrus_ioctls[];
> -extern int cirrus_max_ioctl;
> -
> -int cirrus_mm_init(struct cirrus_device *cirrus);
> -void cirrus_mm_fini(struct cirrus_device *cirrus);
> -void cirrus_ttm_placement(struct cirrus_bo *bo, int domain);
> -int cirrus_bo_create(struct drm_device *dev, int size, int align,
> - uint32_t flags, struct cirrus_bo **pcirrusbo);
> -int cirrus_mmap(struct file *filp, struct vm_area_struct *vma);
> -
> -static inline int cirrus_bo_reserve(struct cirrus_bo *bo, bool no_wait)
> -{
> - int ret;
> -
> - ret = ttm_bo_reserve(&bo->bo, true, no_wait, NULL);
> - if (ret) {
> - if (ret != -ERESTARTSYS && ret != -EBUSY)
> - DRM_ERROR("reserve failed %p\n", bo);
> - return ret;
> - }
> - return 0;
> -}
> -
> -static inline void cirrus_bo_unreserve(struct cirrus_bo *bo)
> -{
> - ttm_bo_unreserve(&bo->bo);
> -}
> -
> -int cirrus_bo_push_sysram(struct cirrus_bo *bo);
> -int cirrus_bo_pin(struct cirrus_bo *bo, u32 pl_flag, u64 *gpu_addr);
> -
> -extern int cirrus_bpp;
> -
> -#endif /* __CIRRUS_DRV_H__ */
> diff --git a/drivers/gpu/drm/cirrus/cirrus.c b/drivers/gpu/drm/cirrus/cirrus.c
> new file mode 100644
> index 000000000000..e27bb13fc777
> --- /dev/null
> +++ b/drivers/gpu/drm/cirrus/cirrus.c
> @@ -0,0 +1,602 @@
> +/*
> + * Copyright 2012-2019 Red Hat
> + *
> + * This file is subject to the terms and conditions of the GNU General
> + * Public License version 2. See the file COPYING in the main
> + * directory of this archive for more details.
> + *
> + * Authors: Matthew Garrett
> + * Dave Airlie
> + * Gerd Hoffmann
> + *
> + * Portions of this code derived from cirrusfb.c:
> + * drivers/video/cirrusfb.c - driver for Cirrus Logic chipsets
> + *
> + * Copyright 1999-2001 Jeff Garzik <jgarzik@pobox.com>
> + */
> +
> +#include <linux/module.h>
> +#include <linux/pci.h>
> +#include <linux/console.h>
> +
> +#include <video/vga.h>
> +#include <video/cirrus.h>
> +
> +#include <drm/drm_drv.h>
> +#include <drm/drm_file.h>
> +#include <drm/drm_ioctl.h>
> +#include <drm/drm_vblank.h>
> +#include <drm/drm_connector.h>
> +
> +#include <drm/drm_fb_helper.h>
> +#include <drm/drm_probe_helper.h>
> +#include <drm/drm_simple_kms_helper.h>
> +#include <drm/drm_gem_shmem_helper.h>
> +#include <drm/drm_gem_framebuffer_helper.h>
> +#include <drm/drm_modeset_helper_vtables.h>
> +#include <drm/drm_damage_helper.h>
> +#include <drm/drm_atomic_helper.h>
> +#include <drm/drm_atomic_state_helper.h>
> +
> +#define DRIVER_NAME "cirrus"
> +#define DRIVER_DESC "qemu cirrus vga"
> +#define DRIVER_DATE "2019"
> +#define DRIVER_MAJOR 2
> +#define DRIVER_MINOR 0
> +
> +struct cirrus_device {
> + struct drm_device *dev;
Why not embed drm_device? It's the latest rage :-)
> + struct drm_simple_display_pipe pipe;
> + struct drm_connector conn;
> + unsigned int bpp;
> + unsigned int pitch;
> + void __iomem *vram;
> + void __iomem *mmio;
> +};
> +
> +/* ------------------------------------------------------------------ */
> +/*
> + * The meat of this driver. The core passes us a mode and we have to program
> + * it. The modesetting here is the bare minimum required to satisfy the qemu
> + * emulation of this hardware, and running this against a real device is
> + * likely to result in an inadequately programmed mode. We've already had
> + * the opportunity to modify the mode, so whatever we receive here should
> + * be something that can be correctly programmed and displayed
> + */
> +
> +#define RREG8(reg) ioread8(((void __iomem *)cirrus->mmio) + (reg))
> +#define WREG8(reg, v) iowrite8(v, ((void __iomem *)cirrus->mmio) + (reg))
> +#define RREG32(reg) ioread32(((void __iomem *)cirrus->mmio) + (reg))
> +#define WREG32(reg, v) iowrite32(v, ((void __iomem *)cirrus->mmio) + (reg))
> +
> +#define SEQ_INDEX 4
> +#define SEQ_DATA 5
> +
> +#define WREG_SEQ(reg, v) \
> + do { \
> + WREG8(SEQ_INDEX, reg); \
> + WREG8(SEQ_DATA, v); \
> + } while (0) \
> +
> +#define CRT_INDEX 0x14
> +#define CRT_DATA 0x15
> +
> +#define WREG_CRT(reg, v) \
> + do { \
> + WREG8(CRT_INDEX, reg); \
> + WREG8(CRT_DATA, v); \
> + } while (0) \
> +
> +#define GFX_INDEX 0xe
> +#define GFX_DATA 0xf
> +
> +#define WREG_GFX(reg, v) \
> + do { \
> + WREG8(GFX_INDEX, reg); \
> + WREG8(GFX_DATA, v); \
> + } while (0) \
> +
> +#define VGA_DAC_MASK 0x6
> +
> +#define WREG_HDR(v) \
> + do { \
> + RREG8(VGA_DAC_MASK); \
> + RREG8(VGA_DAC_MASK); \
> + RREG8(VGA_DAC_MASK); \
> + RREG8(VGA_DAC_MASK); \
> + WREG8(VGA_DAC_MASK, v); \
> + } while (0) \
> +
> +
> +static int cirrus_mode_set(struct cirrus_device *cirrus,
> + struct drm_crtc_state *crtc_state)
> +{
> + struct drm_display_mode *mode = &crtc_state->mode;
> + int hsyncstart, hsyncend, htotal, hdispend;
> + int vtotal, vdispend;
> + int tmp;
> + int sr07 = 0, hdr = 0;
> +
> + htotal = mode->htotal / 8;
> + hsyncend = mode->hsync_end / 8;
> + hsyncstart = mode->hsync_start / 8;
> + hdispend = mode->hdisplay / 8;
> +
> + vtotal = mode->vtotal;
> + vdispend = mode->vdisplay;
> +
> + vdispend -= 1;
> + vtotal -= 2;
> +
> + htotal -= 5;
> + hdispend -= 1;
> + hsyncstart += 1;
> + hsyncend += 1;
> +
> + WREG_CRT(VGA_CRTC_V_SYNC_END, 0x20);
> + WREG_CRT(VGA_CRTC_H_TOTAL, htotal);
> + WREG_CRT(VGA_CRTC_H_DISP, hdispend);
> + WREG_CRT(VGA_CRTC_H_SYNC_START, hsyncstart);
> + WREG_CRT(VGA_CRTC_H_SYNC_END, hsyncend);
> + WREG_CRT(VGA_CRTC_V_TOTAL, vtotal & 0xff);
> + WREG_CRT(VGA_CRTC_V_DISP_END, vdispend & 0xff);
> +
> + tmp = 0x40;
> + if ((vdispend + 1) & 512)
> + tmp |= 0x20;
> + WREG_CRT(VGA_CRTC_MAX_SCAN, tmp);
> +
> + /*
> + * Overflow bits for values that don't fit in the standard registers
> + */
> + tmp = 16;
> + if (vtotal & 256)
> + tmp |= 1;
> + if (vdispend & 256)
> + tmp |= 2;
> + if ((vdispend + 1) & 256)
> + tmp |= 8;
> + if (vtotal & 512)
> + tmp |= 32;
> + if (vdispend & 512)
> + tmp |= 64;
> + WREG_CRT(VGA_CRTC_OVERFLOW, tmp);
> +
> + tmp = 0;
> +
> + /* More overflow bits */
> +
> + if ((htotal + 5) & 64)
> + tmp |= 16;
> + if ((htotal + 5) & 128)
> + tmp |= 32;
> + if (vtotal & 256)
> + tmp |= 64;
> + if (vtotal & 512)
> + tmp |= 128;
> +
> + WREG_CRT(CL_CRT1A, tmp);
> +
> + /* Disable Hercules/CGA compatibility */
> + WREG_CRT(VGA_CRTC_MODE, 0x03);
> +
> + WREG8(SEQ_INDEX, 0x7);
> + sr07 = RREG8(SEQ_DATA);
> + sr07 &= 0xe0;
> + hdr = 0;
> +
> + cirrus->bpp = cirrus->dev->mode_config.preferred_depth;
> + switch (cirrus->bpp) {
> + case 8:
> + sr07 |= 0x11;
> + break;
> + case 16:
> + sr07 |= 0x17;
> + hdr = 0xc1;
> + break;
> + case 24:
> + sr07 |= 0x15;
> + hdr = 0xc5;
> + break;
> + case 32:
> + sr07 |= 0x19;
> + hdr = 0xc5;
> + break;
> + default:
> + return -1;
> + }
> +
> + WREG_SEQ(0x7, sr07);
> +
> + /* Program the pitch */
> + cirrus->pitch = mode->hdisplay * cirrus->bpp / 8;
> + tmp = cirrus->pitch / 8;
> + WREG_CRT(VGA_CRTC_OFFSET, tmp);
> +
> + /* Enable extended blanking and pitch bits, and enable full memory */
> + tmp = 0x22;
> + tmp |= (cirrus->pitch >> 7) & 0x10;
> + tmp |= (cirrus->pitch >> 6) & 0x40;
> + WREG_CRT(0x1b, tmp);
> +
> + /* Enable high-colour modes */
> + WREG_GFX(VGA_GFX_MODE, 0x40);
> +
> + /* And set graphics mode */
> + WREG_GFX(VGA_GFX_MISC, 0x01);
> +
> + WREG_HDR(hdr);
> + /* cirrus_crtc_do_set_base(crtc, old_fb, x, y, 0); */
> +
> + /* Unblank (needed on S3 resume, vgabios doesn't do it then) */
> + outb(0x20, 0x3c0);
> + return 0;
> +}
> +
> +static int cirrus_fb_blit_clips(struct drm_framebuffer *fb,
> + struct drm_clip_rect *clips,
> + unsigned int num_clips)
> +{
> + struct cirrus_device *cirrus = fb->dev->dev_private;
> + unsigned i, y, xoff, xlen, src, dst;
> + void *vmap;
> +
> + vmap = drm_gem_shmem_vmap(fb->obj[0]);
> + if (!vmap)
> + return -ENOMEM;
> +
> + for (i = 0; i < num_clips; i++) {
> + xoff = clips[i].x1 * cirrus->bpp / 8;
> + xlen = (clips[i].x2 - clips[i].x1) * cirrus->bpp / 8;
> + for (y = clips[i].y1; y < clips[i].y2; y++) {
> + src = xoff + y * fb->pitches[0];
> + dst = xoff + y * cirrus->pitch;
> + memcpy_toio(cirrus->vram + dst, vmap + src, xlen);
> + }
> + }
> +
> + drm_gem_shmem_vunmap(fb->obj[0], vmap);
> + return 0;
> +}
> +
> +static int cirrus_fb_blit_rect(struct drm_framebuffer *fb,
> + struct drm_rect *rect)
> +{
> + struct drm_clip_rect clip_rect = {
> + .x1 = rect->x1,
> + .x2 = rect->x2,
> + .y1 = rect->y1,
> + .y2 = rect->y2,
> + };
> + return cirrus_fb_blit_clips(fb, &clip_rect, 1);
> +}
> +
> +static int cirrus_fb_blit_fullscreen(struct drm_framebuffer *fb)
> +{
> + struct drm_clip_rect fullscreen = {
> + .x1 = 0,
> + .x2 = fb->width,
> + .y1 = 0,
> + .y2 = fb->height,
> + };
> + return cirrus_fb_blit_clips(fb, &fullscreen, 1);
> +}
> +
> +static int cirrus_check_size(int width, int height)
> +{
> + static const int max_pitch = 0x1FF << 3; /* (4096 - 1) & ~111b bytes */
> + static const int max_size = 4 * 1024 * 1024; /* 4 MB */
> + int bytes_pp = 2; /* depth 16 */
> +
> + if (width * bytes_pp > max_pitch)
> + return -EINVAL;
> + if (width * height * bytes_pp > max_size)
> + return -EINVAL;
> + return 0;
> +}
> +
> +/* ------------------------------------------------------------------ */
> +/* cirrus connector */
> +
> +static int cirrus_conn_get_modes(struct drm_connector *conn)
> +{
> + int count;
> +
> + count = drm_add_modes_noedid(conn,
> + conn->dev->mode_config.max_width,
> + conn->dev->mode_config.max_height);
> + drm_set_preferred_mode(conn, 1024, 768);
> + return count;
> +}
> +
> +static const struct drm_connector_helper_funcs cirrus_conn_helper_funcs = {
> + .get_modes = cirrus_conn_get_modes,
> +};
> +
> +static const struct drm_connector_funcs cirrus_conn_funcs = {
> + .fill_modes = drm_helper_probe_single_connector_modes,
> + .destroy = drm_connector_cleanup,
> + .reset = drm_atomic_helper_connector_reset,
> + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
> + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
> +};
> +
> +static int cirrus_conn_init(struct cirrus_device *cirrus)
> +{
> + drm_connector_helper_add(&cirrus->conn, &cirrus_conn_helper_funcs);
> + return drm_connector_init(cirrus->dev, &cirrus->conn,
> + &cirrus_conn_funcs, DRM_MODE_CONNECTOR_VGA);
> +
> +}
> +
> +/* ------------------------------------------------------------------ */
> +/* cirrus (simple) display pipe */
> +
> +enum drm_mode_status cirrus_pipe_mode_valid(struct drm_crtc *crtc,
> + const struct drm_display_mode *mode)
> +{
> + if (cirrus_check_size(mode->hdisplay, mode->vdisplay) < 0)
> + return MODE_BAD;
> + return MODE_OK;
> +}
> +
> +int cirrus_pipe_check(struct drm_simple_display_pipe *pipe,
> + struct drm_plane_state *plane_state,
> + struct drm_crtc_state *crtc_state)
> +{
> + struct drm_framebuffer *fb = plane_state->fb;
> +
> + if (!fb)
> + return 0;
> + return cirrus_check_size(fb->width, fb->height);
> +}
> +
> +void cirrus_pipe_enable(struct drm_simple_display_pipe *pipe,
> + struct drm_crtc_state *crtc_state,
> + struct drm_plane_state *plane_state)
> +{
> + struct cirrus_device *cirrus = pipe->crtc.dev->dev_private;
> +
> + cirrus_mode_set(cirrus, crtc_state);
> + cirrus_fb_blit_fullscreen(plane_state->fb);
> +}
> +
> +void cirrus_pipe_update(struct drm_simple_display_pipe *pipe,
> + struct drm_plane_state *old_state)
> +{
> + struct drm_plane_state *state = pipe->plane.state;
> + struct drm_crtc *crtc = &pipe->crtc;
> + struct drm_rect rect;
> +
> + if (drm_atomic_helper_damage_merged(old_state, state, &rect))
> + cirrus_fb_blit_rect(pipe->plane.state->fb, &rect);
> +
> + if (crtc->state->event) {
> + spin_lock_irq(&crtc->dev->event_lock);
> + drm_crtc_send_vblank_event(crtc, crtc->state->event);
> + spin_unlock_irq(&crtc->dev->event_lock);
> + crtc->state->event = NULL;
> + }
> +}
> +
> +static const struct drm_simple_display_pipe_funcs cirrus_pipe_funcs = {
> + .mode_valid = cirrus_pipe_mode_valid,
> + .check = cirrus_pipe_check,
> + .enable = cirrus_pipe_enable,
> + .update = cirrus_pipe_update,
> +};
> +
> +static const uint32_t cirrus_formats[] = {
> + DRM_FORMAT_RGB565,
> +};
> +
> +static int cirrus_pipe_init(struct cirrus_device *cirrus)
> +{
> + return drm_simple_display_pipe_init(cirrus->dev,
> + &cirrus->pipe,
> + &cirrus_pipe_funcs,
> + cirrus_formats,
> + ARRAY_SIZE(cirrus_formats),
> + NULL,
> + &cirrus->conn);
> +}
> +
> +/* ------------------------------------------------------------------ */
> +/* cirrus framebuffers & mode config */
> +
> +static int cirrus_fb_dirty(struct drm_framebuffer *fb,
> + struct drm_file *file_priv,
> + unsigned int flags, unsigned int color,
> + struct drm_clip_rect *clips,
> + unsigned int num_clips)
> +{
> + struct cirrus_device *cirrus = fb->dev->dev_private;
> +
> + if (cirrus->pipe.plane.state->fb != fb)
> + return 0;
> +
> + if (num_clips)
> + cirrus_fb_blit_clips(fb, clips, num_clips);
> + else
> + cirrus_fb_blit_fullscreen(fb);
> + return 0;
> +}
Why not use the dirty helpers and implement dirty rect support in your
main plane update function? Would be nice since then cirrus would be a
really nice template for old fbdev drivers. And you already have all
the dirty rect upload code anyway.
> +static const struct drm_framebuffer_funcs cirrus_fb_funcs = {
> + .destroy = drm_gem_fb_destroy,
> + .create_handle = drm_gem_fb_create_handle,
> + .dirty = cirrus_fb_dirty,
> +};
> +
> +static struct drm_framebuffer*
> +cirrus_fb_create(struct drm_device *dev, struct drm_file *file_priv,
> + const struct drm_mode_fb_cmd2 *mode_cmd)
> +{
> + if (mode_cmd->pixel_format != DRM_FORMAT_RGB565)
> + return ERR_PTR(-EINVAL);
> + if (cirrus_check_size(mode_cmd->width, mode_cmd->height) < 0)
> + return ERR_PTR(-EINVAL);
> + return drm_gem_fb_create_with_funcs(dev, file_priv, mode_cmd,
> + &cirrus_fb_funcs);
> +}
> +
> +static const struct drm_mode_config_funcs cirrus_mode_config_funcs = {
> + .fb_create = cirrus_fb_create,
> + .atomic_check = drm_atomic_helper_check,
> + .atomic_commit = drm_atomic_helper_commit,
> +};
> +
> +static void cirrus_mode_config_init(struct cirrus_device *cirrus)
> +{
> + struct drm_device *dev = cirrus->dev;
> +
> + drm_mode_config_init(dev);
> + dev->mode_config.min_width = 0;
> + dev->mode_config.min_height = 0;
> + dev->mode_config.max_width = 1600;
> + dev->mode_config.max_height = 1024;
> + dev->mode_config.preferred_depth = 16;
> + dev->mode_config.prefer_shadow = 0;
> + dev->mode_config.funcs = &cirrus_mode_config_funcs;
> +}
> +
> +/* ------------------------------------------------------------------ */
> +
> +DEFINE_DRM_GEM_SHMEM_FOPS(cirrus_fops);
> +
> +static struct drm_driver cirrus_driver = {
> + .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC | DRIVER_PRIME,
> +
> + .name = DRIVER_NAME,
> + .desc = DRIVER_DESC,
> + .date = DRIVER_DATE,
> + .major = DRIVER_MAJOR,
> + .minor = DRIVER_MINOR,
> +
> + .fops = &cirrus_fops,
> + DRM_GEM_SHMEM_DRIVER_OPS,
> +};
> +
> +static int cirrus_pci_probe(struct pci_dev *pdev,
> + const struct pci_device_id *ent)
> +{
> + struct drm_device *dev;
> + struct cirrus_device *cirrus;
> + int ret;
> +
> + ret = drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, 0, "cirrusdrmfb");
> + if (ret)
> + return ret;
> +
> + dev = drm_dev_alloc(&cirrus_driver, &pdev->dev);
> + if (IS_ERR(dev))
> + return PTR_ERR(dev);
> +
> + ret = pci_enable_device(pdev);
> + if (ret)
> + goto err_free_dev;
> +
> + ret = pci_request_regions(pdev, DRIVER_NAME);
> + if (ret)
> + goto err_free_dev;
> +
> + ret = -ENOMEM;
> + cirrus = kzalloc(sizeof(*cirrus), GFP_KERNEL);
> + if (cirrus == NULL)
> + goto err_pci_release;
> + dev->dev_private = cirrus;
> + cirrus->dev = dev;
> +
> + cirrus->vram = ioremap(pci_resource_start(pdev, 0),
> + pci_resource_len(pdev, 0));
> + if (cirrus->vram == NULL)
> + goto err_free_cirrus;
> +
> + cirrus->mmio = ioremap(pci_resource_start(pdev, 1),
> + pci_resource_len(pdev, 1));
> + if (cirrus->mmio == NULL)
> + goto err_unmap_vram;
> +
> + cirrus_mode_config_init(cirrus);
> +
> + ret = cirrus_conn_init(cirrus);
> + if (ret < 0)
> + goto err_cleanup;
> +
> + ret = cirrus_pipe_init(cirrus);
> + if (ret < 0)
> + goto err_cleanup;
> +
> + drm_mode_config_reset(dev);
> +
> + dev->pdev = pdev;
> + pci_set_drvdata(pdev, dev);
> + ret = drm_dev_register(dev, 0);
> + if (ret)
> + goto err_cleanup;
> +
> + drm_fbdev_generic_setup(dev, dev->mode_config.preferred_depth);
> + return 0;
> +
> +err_cleanup:
> + drm_mode_config_cleanup(dev);
> + iounmap(cirrus->mmio);
> +err_unmap_vram:
> + iounmap(cirrus->vram);
> +err_free_cirrus:
> + kfree(cirrus);
> +err_pci_release:
> + pci_release_regions(pdev);
> +err_free_dev:
> + drm_dev_put(dev);
> + return ret;
> +}
> +
> +static void cirrus_pci_remove(struct pci_dev *pdev)
> +{
> + struct drm_device *dev = pci_get_drvdata(pdev);
> + struct cirrus_device *cirrus = dev->dev_private;
> +
> + drm_dev_unregister(dev);
> + drm_mode_config_cleanup(dev);
> + iounmap(cirrus->mmio);
> + iounmap(cirrus->vram);
> + kfree(cirrus);
> + pci_release_regions(pdev);
> + drm_dev_put(dev);
> +}
> +
> +/* only bind to the cirrus chip in qemu */
> +static const struct pci_device_id pciidlist[] = {
> + { PCI_VENDOR_ID_CIRRUS, PCI_DEVICE_ID_CIRRUS_5446,
> + PCI_SUBVENDOR_ID_REDHAT_QUMRANET, PCI_SUBDEVICE_ID_QEMU,
> + 0, 0, 0 },
> + { PCI_VENDOR_ID_CIRRUS, PCI_DEVICE_ID_CIRRUS_5446,
> + PCI_VENDOR_ID_XEN, 0x0001,
> + 0, 0, 0 },
> + { /* end if list */}
> +};
> +static struct pci_driver cirrus_pci_driver = {
> + .name = DRIVER_NAME,
> + .id_table = pciidlist,
> + .probe = cirrus_pci_probe,
> + .remove = cirrus_pci_remove,
> +};
> +
> +static int __init cirrus_init(void)
> +{
> + if (vgacon_text_force())
> + return -EINVAL;
> + return pci_register_driver(&cirrus_pci_driver);
> +}
> +
> +static void __exit cirrus_exit(void)
> +{
> + pci_unregister_driver(&cirrus_pci_driver);
> +}
> +
> +module_init(cirrus_init);
> +module_exit(cirrus_exit);
> +
> +MODULE_DEVICE_TABLE(pci, pciidlist);
> +MODULE_LICENSE("GPL");
> diff --git a/drivers/gpu/drm/cirrus/cirrus_drv.c b/drivers/gpu/drm/cirrus/cirrus_drv.c
> deleted file mode 100644
> index 8ec880f3a322..000000000000
> --- a/drivers/gpu/drm/cirrus/cirrus_drv.c
> +++ /dev/null
> @@ -1,161 +0,0 @@
> -/*
> - * Copyright 2012 Red Hat <mjg@redhat.com>
> - *
> - * This file is subject to the terms and conditions of the GNU General
> - * Public License version 2. See the file COPYING in the main
> - * directory of this archive for more details.
> - *
> - * Authors: Matthew Garrett
> - * Dave Airlie
> - */
> -#include <linux/module.h>
> -#include <linux/console.h>
> -#include <drm/drmP.h>
> -#include <drm/drm_crtc_helper.h>
> -#include <drm/drm_probe_helper.h>
> -
> -#include "cirrus_drv.h"
> -
> -int cirrus_modeset = -1;
> -int cirrus_bpp = 16;
> -
> -MODULE_PARM_DESC(modeset, "Disable/Enable modesetting");
> -module_param_named(modeset, cirrus_modeset, int, 0400);
> -MODULE_PARM_DESC(bpp, "Max bits-per-pixel (default:16)");
> -module_param_named(bpp, cirrus_bpp, int, 0400);
> -
> -/*
> - * This is the generic driver code. This binds the driver to the drm core,
> - * which then performs further device association and calls our graphics init
> - * functions
> - */
> -
> -static struct drm_driver driver;
> -
> -/* only bind to the cirrus chip in qemu */
> -static const struct pci_device_id pciidlist[] = {
> - { PCI_VENDOR_ID_CIRRUS, PCI_DEVICE_ID_CIRRUS_5446,
> - PCI_SUBVENDOR_ID_REDHAT_QUMRANET, PCI_SUBDEVICE_ID_QEMU,
> - 0, 0, 0 },
> - { PCI_VENDOR_ID_CIRRUS, PCI_DEVICE_ID_CIRRUS_5446, PCI_VENDOR_ID_XEN,
> - 0x0001, 0, 0, 0 },
> - {0,}
> -};
> -
> -
> -static int cirrus_pci_probe(struct pci_dev *pdev,
> - const struct pci_device_id *ent)
> -{
> - int ret;
> -
> - ret = drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, 0, "cirrusdrmfb");
> - if (ret)
> - return ret;
> -
> - return drm_get_pci_dev(pdev, ent, &driver);
> -}
> -
> -static void cirrus_pci_remove(struct pci_dev *pdev)
> -{
> - struct drm_device *dev = pci_get_drvdata(pdev);
> -
> - drm_put_dev(dev);
> -}
> -
> -#ifdef CONFIG_PM_SLEEP
> -static int cirrus_pm_suspend(struct device *dev)
> -{
> - struct pci_dev *pdev = to_pci_dev(dev);
> - struct drm_device *drm_dev = pci_get_drvdata(pdev);
> - struct cirrus_device *cdev = drm_dev->dev_private;
> -
> - drm_kms_helper_poll_disable(drm_dev);
> -
> - if (cdev->mode_info.gfbdev) {
> - console_lock();
> - drm_fb_helper_set_suspend(&cdev->mode_info.gfbdev->helper, 1);
> - console_unlock();
> - }
> -
> - return 0;
> -}
> -
> -static int cirrus_pm_resume(struct device *dev)
> -{
> - struct pci_dev *pdev = to_pci_dev(dev);
> - struct drm_device *drm_dev = pci_get_drvdata(pdev);
> - struct cirrus_device *cdev = drm_dev->dev_private;
> -
> - drm_helper_resume_force_mode(drm_dev);
> -
> - if (cdev->mode_info.gfbdev) {
> - console_lock();
> - drm_fb_helper_set_suspend(&cdev->mode_info.gfbdev->helper, 0);
> - console_unlock();
> - }
> -
> - drm_kms_helper_poll_enable(drm_dev);
> - return 0;
> -}
> -#endif
> -
> -static const struct file_operations cirrus_driver_fops = {
> - .owner = THIS_MODULE,
> - .open = drm_open,
> - .release = drm_release,
> - .unlocked_ioctl = drm_ioctl,
> - .mmap = cirrus_mmap,
> - .poll = drm_poll,
> - .compat_ioctl = drm_compat_ioctl,
> -};
> -static struct drm_driver driver = {
> - .driver_features = DRIVER_MODESET | DRIVER_GEM,
> - .load = cirrus_driver_load,
> - .unload = cirrus_driver_unload,
> - .fops = &cirrus_driver_fops,
> - .name = DRIVER_NAME,
> - .desc = DRIVER_DESC,
> - .date = DRIVER_DATE,
> - .major = DRIVER_MAJOR,
> - .minor = DRIVER_MINOR,
> - .patchlevel = DRIVER_PATCHLEVEL,
> - .gem_free_object_unlocked = cirrus_gem_free_object,
> - .dumb_create = cirrus_dumb_create,
> - .dumb_map_offset = cirrus_dumb_mmap_offset,
> -};
> -
> -static const struct dev_pm_ops cirrus_pm_ops = {
> - SET_SYSTEM_SLEEP_PM_OPS(cirrus_pm_suspend,
> - cirrus_pm_resume)
> -};
> -
> -static struct pci_driver cirrus_pci_driver = {
> - .name = DRIVER_NAME,
> - .id_table = pciidlist,
> - .probe = cirrus_pci_probe,
> - .remove = cirrus_pci_remove,
> - .driver.pm = &cirrus_pm_ops,
> -};
> -
> -static int __init cirrus_init(void)
> -{
> - if (vgacon_text_force() && cirrus_modeset == -1)
> - return -EINVAL;
> -
> - if (cirrus_modeset == 0)
> - return -EINVAL;
> - return pci_register_driver(&cirrus_pci_driver);
> -}
> -
> -static void __exit cirrus_exit(void)
> -{
> - pci_unregister_driver(&cirrus_pci_driver);
> -}
> -
> -module_init(cirrus_init);
> -module_exit(cirrus_exit);
> -
> -MODULE_DEVICE_TABLE(pci, pciidlist);
> -MODULE_AUTHOR(DRIVER_AUTHOR);
> -MODULE_DESCRIPTION(DRIVER_DESC);
> -MODULE_LICENSE("GPL");
> diff --git a/drivers/gpu/drm/cirrus/cirrus_fbdev.c b/drivers/gpu/drm/cirrus/cirrus_fbdev.c
> deleted file mode 100644
> index 2e6128069fc3..000000000000
> --- a/drivers/gpu/drm/cirrus/cirrus_fbdev.c
> +++ /dev/null
> @@ -1,309 +0,0 @@
> -/*
> - * Copyright 2012 Red Hat
> - *
> - * This file is subject to the terms and conditions of the GNU General
> - * Public License version 2. See the file COPYING in the main
> - * directory of this archive for more details.
> - *
> - * Authors: Matthew Garrett
> - * Dave Airlie
> - */
> -#include <linux/module.h>
> -#include <drm/drmP.h>
> -#include <drm/drm_util.h>
> -#include <drm/drm_fb_helper.h>
> -#include <drm/drm_crtc_helper.h>
> -
> -#include "cirrus_drv.h"
> -
> -static void cirrus_dirty_update(struct cirrus_fbdev *afbdev,
> - int x, int y, int width, int height)
> -{
> - int i;
> - struct drm_gem_object *obj;
> - struct cirrus_bo *bo;
> - int src_offset, dst_offset;
> - int bpp = afbdev->gfb->format->cpp[0];
> - int ret = -EBUSY;
> - bool unmap = false;
> - bool store_for_later = false;
> - int x2, y2;
> - unsigned long flags;
> -
> - obj = afbdev->gfb->obj[0];
> - bo = gem_to_cirrus_bo(obj);
> -
> - /*
> - * try and reserve the BO, if we fail with busy
> - * then the BO is being moved and we should
> - * store up the damage until later.
> - */
> - if (drm_can_sleep())
> - ret = cirrus_bo_reserve(bo, true);
> - if (ret) {
> - if (ret != -EBUSY)
> - return;
> - store_for_later = true;
> - }
> -
> - x2 = x + width - 1;
> - y2 = y + height - 1;
> - spin_lock_irqsave(&afbdev->dirty_lock, flags);
> -
> - if (afbdev->y1 < y)
> - y = afbdev->y1;
> - if (afbdev->y2 > y2)
> - y2 = afbdev->y2;
> - if (afbdev->x1 < x)
> - x = afbdev->x1;
> - if (afbdev->x2 > x2)
> - x2 = afbdev->x2;
> -
> - if (store_for_later) {
> - afbdev->x1 = x;
> - afbdev->x2 = x2;
> - afbdev->y1 = y;
> - afbdev->y2 = y2;
> - spin_unlock_irqrestore(&afbdev->dirty_lock, flags);
> - return;
> - }
> -
> - afbdev->x1 = afbdev->y1 = INT_MAX;
> - afbdev->x2 = afbdev->y2 = 0;
> - spin_unlock_irqrestore(&afbdev->dirty_lock, flags);
> -
> - if (!bo->kmap.virtual) {
> - ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap);
> - if (ret) {
> - DRM_ERROR("failed to kmap fb updates\n");
> - cirrus_bo_unreserve(bo);
> - return;
> - }
> - unmap = true;
> - }
> - for (i = y; i < y + height; i++) {
> - /* assume equal stride for now */
> - src_offset = dst_offset = i * afbdev->gfb->pitches[0] + (x * bpp);
> - memcpy_toio(bo->kmap.virtual + src_offset, afbdev->sysram + src_offset, width * bpp);
> -
> - }
> - if (unmap)
> - ttm_bo_kunmap(&bo->kmap);
> -
> - cirrus_bo_unreserve(bo);
> -}
> -
> -static void cirrus_fillrect(struct fb_info *info,
> - const struct fb_fillrect *rect)
> -{
> - struct cirrus_fbdev *afbdev = info->par;
> - drm_fb_helper_sys_fillrect(info, rect);
> - cirrus_dirty_update(afbdev, rect->dx, rect->dy, rect->width,
> - rect->height);
> -}
> -
> -static void cirrus_copyarea(struct fb_info *info,
> - const struct fb_copyarea *area)
> -{
> - struct cirrus_fbdev *afbdev = info->par;
> - drm_fb_helper_sys_copyarea(info, area);
> - cirrus_dirty_update(afbdev, area->dx, area->dy, area->width,
> - area->height);
> -}
> -
> -static void cirrus_imageblit(struct fb_info *info,
> - const struct fb_image *image)
> -{
> - struct cirrus_fbdev *afbdev = info->par;
> - drm_fb_helper_sys_imageblit(info, image);
> - cirrus_dirty_update(afbdev, image->dx, image->dy, image->width,
> - image->height);
> -}
> -
> -
> -static struct fb_ops cirrusfb_ops = {
> - .owner = THIS_MODULE,
> - .fb_check_var = drm_fb_helper_check_var,
> - .fb_set_par = drm_fb_helper_set_par,
> - .fb_fillrect = cirrus_fillrect,
> - .fb_copyarea = cirrus_copyarea,
> - .fb_imageblit = cirrus_imageblit,
> - .fb_pan_display = drm_fb_helper_pan_display,
> - .fb_blank = drm_fb_helper_blank,
> - .fb_setcmap = drm_fb_helper_setcmap,
> -};
> -
> -static int cirrusfb_create_object(struct cirrus_fbdev *afbdev,
> - const struct drm_mode_fb_cmd2 *mode_cmd,
> - struct drm_gem_object **gobj_p)
> -{
> - struct drm_device *dev = afbdev->helper.dev;
> - struct cirrus_device *cdev = dev->dev_private;
> - u32 bpp;
> - u32 size;
> - struct drm_gem_object *gobj;
> - int ret = 0;
> -
> - bpp = drm_format_plane_cpp(mode_cmd->pixel_format, 0) * 8;
> -
> - if (!cirrus_check_framebuffer(cdev, mode_cmd->width, mode_cmd->height,
> - bpp, mode_cmd->pitches[0]))
> - return -EINVAL;
> -
> - size = mode_cmd->pitches[0] * mode_cmd->height;
> - ret = cirrus_gem_create(dev, size, true, &gobj);
> - if (ret)
> - return ret;
> -
> - *gobj_p = gobj;
> - return ret;
> -}
> -
> -static int cirrusfb_create(struct drm_fb_helper *helper,
> - struct drm_fb_helper_surface_size *sizes)
> -{
> - struct cirrus_fbdev *gfbdev =
> - container_of(helper, struct cirrus_fbdev, helper);
> - struct cirrus_device *cdev = gfbdev->helper.dev->dev_private;
> - struct fb_info *info;
> - struct drm_framebuffer *fb;
> - struct drm_mode_fb_cmd2 mode_cmd;
> - void *sysram;
> - struct drm_gem_object *gobj = NULL;
> - int size, ret;
> -
> - mode_cmd.width = sizes->surface_width;
> - mode_cmd.height = sizes->surface_height;
> - mode_cmd.pitches[0] = mode_cmd.width * ((sizes->surface_bpp + 7) / 8);
> - mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
> - sizes->surface_depth);
> - size = mode_cmd.pitches[0] * mode_cmd.height;
> -
> - ret = cirrusfb_create_object(gfbdev, &mode_cmd, &gobj);
> - if (ret) {
> - DRM_ERROR("failed to create fbcon backing object %d\n", ret);
> - return ret;
> - }
> -
> - sysram = vmalloc(size);
> - if (!sysram)
> - return -ENOMEM;
> -
> - info = drm_fb_helper_alloc_fbi(helper);
> - if (IS_ERR(info)) {
> - ret = PTR_ERR(info);
> - goto err_vfree;
> - }
> -
> - fb = kzalloc(sizeof(*fb), GFP_KERNEL);
> - if (!fb) {
> - ret = -ENOMEM;
> - goto err_drm_gem_object_put_unlocked;
> - }
> -
> - ret = cirrus_framebuffer_init(cdev->dev, fb, &mode_cmd, gobj);
> - if (ret)
> - goto err_kfree;
> -
> - gfbdev->sysram = sysram;
> - gfbdev->size = size;
> - gfbdev->gfb = fb;
> -
> - /* setup helper */
> - gfbdev->helper.fb = fb;
> -
> - info->fbops = &cirrusfb_ops;
> -
> - drm_fb_helper_fill_info(info, &gfbdev->helper, sizes);
> -
> - /* setup aperture base/size for vesafb takeover */
> - info->apertures->ranges[0].base = cdev->dev->mode_config.fb_base;
> - info->apertures->ranges[0].size = cdev->mc.vram_size;
> -
> - info->fix.smem_start = cdev->dev->mode_config.fb_base;
> - info->fix.smem_len = cdev->mc.vram_size;
> -
> - info->screen_base = sysram;
> - info->screen_size = size;
> -
> - info->fix.mmio_start = 0;
> - info->fix.mmio_len = 0;
> -
> - DRM_INFO("fb mappable at 0x%lX\n", info->fix.smem_start);
> - DRM_INFO("vram aper at 0x%lX\n", (unsigned long)info->fix.smem_start);
> - DRM_INFO("size %lu\n", (unsigned long)info->fix.smem_len);
> - DRM_INFO("fb depth is %d\n", fb->format->depth);
> - DRM_INFO(" pitch is %d\n", fb->pitches[0]);
> -
> - return 0;
> -
> -err_kfree:
> - kfree(fb);
> -err_drm_gem_object_put_unlocked:
> - drm_gem_object_put_unlocked(gobj);
> -err_vfree:
> - vfree(sysram);
> - return ret;
> -}
> -
> -static int cirrus_fbdev_destroy(struct drm_device *dev,
> - struct cirrus_fbdev *gfbdev)
> -{
> - struct drm_framebuffer *gfb = gfbdev->gfb;
> -
> - drm_helper_force_disable_all(dev);
> -
> - drm_fb_helper_unregister_fbi(&gfbdev->helper);
> -
> - vfree(gfbdev->sysram);
> - drm_fb_helper_fini(&gfbdev->helper);
> - if (gfb)
> - drm_framebuffer_put(gfb);
> -
> - return 0;
> -}
> -
> -static const struct drm_fb_helper_funcs cirrus_fb_helper_funcs = {
> - .fb_probe = cirrusfb_create,
> -};
> -
> -int cirrus_fbdev_init(struct cirrus_device *cdev)
> -{
> - struct cirrus_fbdev *gfbdev;
> - int ret;
> -
> - /*bpp_sel = 8;*/
> - gfbdev = kzalloc(sizeof(struct cirrus_fbdev), GFP_KERNEL);
> - if (!gfbdev)
> - return -ENOMEM;
> -
> - cdev->mode_info.gfbdev = gfbdev;
> - spin_lock_init(&gfbdev->dirty_lock);
> -
> - drm_fb_helper_prepare(cdev->dev, &gfbdev->helper,
> - &cirrus_fb_helper_funcs);
> -
> - ret = drm_fb_helper_init(cdev->dev, &gfbdev->helper,
> - CIRRUSFB_CONN_LIMIT);
> - if (ret)
> - return ret;
> -
> - ret = drm_fb_helper_single_add_all_connectors(&gfbdev->helper);
> - if (ret)
> - return ret;
> -
> - /* disable all the possible outputs/crtcs before entering KMS mode */
> - drm_helper_disable_unused_functions(cdev->dev);
> -
> - return drm_fb_helper_initial_config(&gfbdev->helper, cirrus_bpp);
> -}
> -
> -void cirrus_fbdev_fini(struct cirrus_device *cdev)
> -{
> - if (!cdev->mode_info.gfbdev)
> - return;
> -
> - cirrus_fbdev_destroy(cdev->dev, cdev->mode_info.gfbdev);
> - kfree(cdev->mode_info.gfbdev);
> - cdev->mode_info.gfbdev = NULL;
> -}
> diff --git a/drivers/gpu/drm/cirrus/cirrus_main.c b/drivers/gpu/drm/cirrus/cirrus_main.c
> deleted file mode 100644
> index 57f8fe6d020b..000000000000
> --- a/drivers/gpu/drm/cirrus/cirrus_main.c
> +++ /dev/null
> @@ -1,328 +0,0 @@
> -/*
> - * Copyright 2012 Red Hat
> - *
> - * This file is subject to the terms and conditions of the GNU General
> - * Public License version 2. See the file COPYING in the main
> - * directory of this archive for more details.
> - *
> - * Authors: Matthew Garrett
> - * Dave Airlie
> - */
> -#include <drm/drmP.h>
> -#include <drm/drm_crtc_helper.h>
> -#include <drm/drm_gem_framebuffer_helper.h>
> -
> -#include "cirrus_drv.h"
> -
> -static const struct drm_framebuffer_funcs cirrus_fb_funcs = {
> - .create_handle = drm_gem_fb_create_handle,
> - .destroy = drm_gem_fb_destroy,
> -};
> -
> -int cirrus_framebuffer_init(struct drm_device *dev,
> - struct drm_framebuffer *gfb,
> - const struct drm_mode_fb_cmd2 *mode_cmd,
> - struct drm_gem_object *obj)
> -{
> - int ret;
> -
> - drm_helper_mode_fill_fb_struct(dev, gfb, mode_cmd);
> - gfb->obj[0] = obj;
> - ret = drm_framebuffer_init(dev, gfb, &cirrus_fb_funcs);
> - if (ret) {
> - DRM_ERROR("drm_framebuffer_init failed: %d\n", ret);
> - return ret;
> - }
> - return 0;
> -}
> -
> -static struct drm_framebuffer *
> -cirrus_user_framebuffer_create(struct drm_device *dev,
> - struct drm_file *filp,
> - const struct drm_mode_fb_cmd2 *mode_cmd)
> -{
> - struct cirrus_device *cdev = dev->dev_private;
> - struct drm_gem_object *obj;
> - struct drm_framebuffer *fb;
> - u32 bpp;
> - int ret;
> -
> - bpp = drm_format_plane_cpp(mode_cmd->pixel_format, 0) * 8;
> -
> - if (!cirrus_check_framebuffer(cdev, mode_cmd->width, mode_cmd->height,
> - bpp, mode_cmd->pitches[0]))
> - return ERR_PTR(-EINVAL);
> -
> - obj = drm_gem_object_lookup(filp, mode_cmd->handles[0]);
> - if (obj == NULL)
> - return ERR_PTR(-ENOENT);
> -
> - fb = kzalloc(sizeof(*fb), GFP_KERNEL);
> - if (!fb) {
> - drm_gem_object_put_unlocked(obj);
> - return ERR_PTR(-ENOMEM);
> - }
> -
> - ret = cirrus_framebuffer_init(dev, fb, mode_cmd, obj);
> - if (ret) {
> - drm_gem_object_put_unlocked(obj);
> - kfree(fb);
> - return ERR_PTR(ret);
> - }
> - return fb;
> -}
> -
> -static const struct drm_mode_config_funcs cirrus_mode_funcs = {
> - .fb_create = cirrus_user_framebuffer_create,
> -};
> -
> -/* Unmap the framebuffer from the core and release the memory */
> -static void cirrus_vram_fini(struct cirrus_device *cdev)
> -{
> - iounmap(cdev->rmmio);
> - cdev->rmmio = NULL;
> - if (cdev->mc.vram_base)
> - release_mem_region(cdev->mc.vram_base, cdev->mc.vram_size);
> -}
> -
> -/* Map the framebuffer from the card and configure the core */
> -static int cirrus_vram_init(struct cirrus_device *cdev)
> -{
> - /* BAR 0 is VRAM */
> - cdev->mc.vram_base = pci_resource_start(cdev->dev->pdev, 0);
> - cdev->mc.vram_size = pci_resource_len(cdev->dev->pdev, 0);
> -
> - if (!request_mem_region(cdev->mc.vram_base, cdev->mc.vram_size,
> - "cirrusdrmfb_vram")) {
> - DRM_ERROR("can't reserve VRAM\n");
> - return -ENXIO;
> - }
> -
> - return 0;
> -}
> -
> -/*
> - * Our emulated hardware has two sets of memory. One is video RAM and can
> - * simply be used as a linear framebuffer - the other provides mmio access
> - * to the display registers. The latter can also be accessed via IO port
> - * access, but we map the range and use mmio to program them instead
> - */
> -
> -int cirrus_device_init(struct cirrus_device *cdev,
> - struct drm_device *ddev,
> - struct pci_dev *pdev, uint32_t flags)
> -{
> - int ret;
> -
> - cdev->dev = ddev;
> - cdev->flags = flags;
> -
> - /* Hardcode the number of CRTCs to 1 */
> - cdev->num_crtc = 1;
> -
> - /* BAR 0 is the framebuffer, BAR 1 contains registers */
> - cdev->rmmio_base = pci_resource_start(cdev->dev->pdev, 1);
> - cdev->rmmio_size = pci_resource_len(cdev->dev->pdev, 1);
> -
> - if (!request_mem_region(cdev->rmmio_base, cdev->rmmio_size,
> - "cirrusdrmfb_mmio")) {
> - DRM_ERROR("can't reserve mmio registers\n");
> - return -ENOMEM;
> - }
> -
> - cdev->rmmio = ioremap(cdev->rmmio_base, cdev->rmmio_size);
> -
> - if (cdev->rmmio == NULL)
> - return -ENOMEM;
> -
> - ret = cirrus_vram_init(cdev);
> - if (ret) {
> - release_mem_region(cdev->rmmio_base, cdev->rmmio_size);
> - return ret;
> - }
> -
> - return 0;
> -}
> -
> -void cirrus_device_fini(struct cirrus_device *cdev)
> -{
> - release_mem_region(cdev->rmmio_base, cdev->rmmio_size);
> - cirrus_vram_fini(cdev);
> -}
> -
> -/*
> - * Functions here will be called by the core once it's bound the driver to
> - * a PCI device
> - */
> -
> -int cirrus_driver_load(struct drm_device *dev, unsigned long flags)
> -{
> - struct cirrus_device *cdev;
> - int r;
> -
> - cdev = kzalloc(sizeof(struct cirrus_device), GFP_KERNEL);
> - if (cdev == NULL)
> - return -ENOMEM;
> - dev->dev_private = (void *)cdev;
> -
> - r = cirrus_device_init(cdev, dev, dev->pdev, flags);
> - if (r) {
> - dev_err(&dev->pdev->dev, "Fatal error during GPU init: %d\n", r);
> - goto out;
> - }
> -
> - r = cirrus_mm_init(cdev);
> - if (r) {
> - dev_err(&dev->pdev->dev, "fatal err on mm init\n");
> - goto out;
> - }
> -
> - /*
> - * cirrus_modeset_init() is initializing/registering the emulated fbdev
> - * and DRM internals can access/test some of the fields in
> - * mode_config->funcs as part of the fbdev registration process.
> - * Make sure dev->mode_config.funcs is properly set to avoid
> - * dereferencing a NULL pointer.
> - * FIXME: mode_config.funcs assignment should probably be done in
> - * cirrus_modeset_init() (that's a common pattern seen in other DRM
> - * drivers).
> - */
> - dev->mode_config.funcs = &cirrus_mode_funcs;
> - r = cirrus_modeset_init(cdev);
> - if (r) {
> - dev_err(&dev->pdev->dev, "Fatal error during modeset init: %d\n", r);
> - goto out;
> - }
> -
> - return 0;
> -out:
> - cirrus_driver_unload(dev);
> - return r;
> -}
> -
> -void cirrus_driver_unload(struct drm_device *dev)
> -{
> - struct cirrus_device *cdev = dev->dev_private;
> -
> - if (cdev == NULL)
> - return;
> - cirrus_modeset_fini(cdev);
> - cirrus_mm_fini(cdev);
> - cirrus_device_fini(cdev);
> - kfree(cdev);
> - dev->dev_private = NULL;
> -}
> -
> -int cirrus_gem_create(struct drm_device *dev,
> - u32 size, bool iskernel,
> - struct drm_gem_object **obj)
> -{
> - struct cirrus_bo *cirrusbo;
> - int ret;
> -
> - *obj = NULL;
> -
> - size = roundup(size, PAGE_SIZE);
> - if (size == 0)
> - return -EINVAL;
> -
> - ret = cirrus_bo_create(dev, size, 0, 0, &cirrusbo);
> - if (ret) {
> - if (ret != -ERESTARTSYS)
> - DRM_ERROR("failed to allocate GEM object\n");
> - return ret;
> - }
> - *obj = &cirrusbo->gem;
> - return 0;
> -}
> -
> -int cirrus_dumb_create(struct drm_file *file,
> - struct drm_device *dev,
> - struct drm_mode_create_dumb *args)
> -{
> - int ret;
> - struct drm_gem_object *gobj;
> - u32 handle;
> -
> - args->pitch = args->width * ((args->bpp + 7) / 8);
> - args->size = args->pitch * args->height;
> -
> - ret = cirrus_gem_create(dev, args->size, false,
> - &gobj);
> - if (ret)
> - return ret;
> -
> - ret = drm_gem_handle_create(file, gobj, &handle);
> - drm_gem_object_put_unlocked(gobj);
> - if (ret)
> - return ret;
> -
> - args->handle = handle;
> - return 0;
> -}
> -
> -static void cirrus_bo_unref(struct cirrus_bo **bo)
> -{
> - struct ttm_buffer_object *tbo;
> -
> - if ((*bo) == NULL)
> - return;
> -
> - tbo = &((*bo)->bo);
> - ttm_bo_put(tbo);
> - *bo = NULL;
> -}
> -
> -void cirrus_gem_free_object(struct drm_gem_object *obj)
> -{
> - struct cirrus_bo *cirrus_bo = gem_to_cirrus_bo(obj);
> -
> - cirrus_bo_unref(&cirrus_bo);
> -}
> -
> -
> -static inline u64 cirrus_bo_mmap_offset(struct cirrus_bo *bo)
> -{
> - return drm_vma_node_offset_addr(&bo->bo.vma_node);
> -}
> -
> -int
> -cirrus_dumb_mmap_offset(struct drm_file *file,
> - struct drm_device *dev,
> - uint32_t handle,
> - uint64_t *offset)
> -{
> - struct drm_gem_object *obj;
> - struct cirrus_bo *bo;
> -
> - obj = drm_gem_object_lookup(file, handle);
> - if (obj == NULL)
> - return -ENOENT;
> -
> - bo = gem_to_cirrus_bo(obj);
> - *offset = cirrus_bo_mmap_offset(bo);
> -
> - drm_gem_object_put_unlocked(obj);
> -
> - return 0;
> -}
> -
> -bool cirrus_check_framebuffer(struct cirrus_device *cdev, int width, int height,
> - int bpp, int pitch)
> -{
> - const int max_pitch = 0x1FF << 3; /* (4096 - 1) & ~111b bytes */
> - const int max_size = cdev->mc.vram_size;
> -
> - if (bpp > cirrus_bpp)
> - return false;
> - if (bpp > 32)
> - return false;
> -
> - if (pitch > max_pitch)
> - return false;
> -
> - if (pitch * height > max_size)
> - return false;
> -
> - return true;
> -}
> diff --git a/drivers/gpu/drm/cirrus/cirrus_mode.c b/drivers/gpu/drm/cirrus/cirrus_mode.c
> deleted file mode 100644
> index b109cd71426f..000000000000
> --- a/drivers/gpu/drm/cirrus/cirrus_mode.c
> +++ /dev/null
> @@ -1,617 +0,0 @@
> -
> -/*
> - * Copyright 2012 Red Hat
> - *
> - * This file is subject to the terms and conditions of the GNU General
> - * Public License version 2. See the file COPYING in the main
> - * directory of this archive for more details.
> - *
> - * Authors: Matthew Garrett
> - * Dave Airlie
> - *
> - * Portions of this code derived from cirrusfb.c:
> - * drivers/video/cirrusfb.c - driver for Cirrus Logic chipsets
> - *
> - * Copyright 1999-2001 Jeff Garzik <jgarzik@pobox.com>
> - */
> -#include <drm/drmP.h>
> -#include <drm/drm_crtc_helper.h>
> -#include <drm/drm_plane_helper.h>
> -#include <drm/drm_probe_helper.h>
> -
> -#include <video/cirrus.h>
> -
> -#include "cirrus_drv.h"
> -
> -#define CIRRUS_LUT_SIZE 256
> -
> -#define PALETTE_INDEX 0x8
> -#define PALETTE_DATA 0x9
> -
> -/*
> - * This file contains setup code for the CRTC.
> - */
> -
> -/*
> - * The DRM core requires DPMS functions, but they make little sense in our
> - * case and so are just stubs
> - */
> -
> -static void cirrus_crtc_dpms(struct drm_crtc *crtc, int mode)
> -{
> - struct drm_device *dev = crtc->dev;
> - struct cirrus_device *cdev = dev->dev_private;
> - u8 sr01, gr0e;
> -
> - switch (mode) {
> - case DRM_MODE_DPMS_ON:
> - sr01 = 0x00;
> - gr0e = 0x00;
> - break;
> - case DRM_MODE_DPMS_STANDBY:
> - sr01 = 0x20;
> - gr0e = 0x02;
> - break;
> - case DRM_MODE_DPMS_SUSPEND:
> - sr01 = 0x20;
> - gr0e = 0x04;
> - break;
> - case DRM_MODE_DPMS_OFF:
> - sr01 = 0x20;
> - gr0e = 0x06;
> - break;
> - default:
> - return;
> - }
> -
> - WREG8(SEQ_INDEX, 0x1);
> - sr01 |= RREG8(SEQ_DATA) & ~0x20;
> - WREG_SEQ(0x1, sr01);
> -
> - WREG8(GFX_INDEX, 0xe);
> - gr0e |= RREG8(GFX_DATA) & ~0x06;
> - WREG_GFX(0xe, gr0e);
> -}
> -
> -static void cirrus_set_start_address(struct drm_crtc *crtc, unsigned offset)
> -{
> - struct cirrus_device *cdev = crtc->dev->dev_private;
> - u32 addr;
> - u8 tmp;
> -
> - addr = offset >> 2;
> - WREG_CRT(0x0c, (u8)((addr >> 8) & 0xff));
> - WREG_CRT(0x0d, (u8)(addr & 0xff));
> -
> - WREG8(CRT_INDEX, 0x1b);
> - tmp = RREG8(CRT_DATA);
> - tmp &= 0xf2;
> - tmp |= (addr >> 16) & 0x01;
> - tmp |= (addr >> 15) & 0x0c;
> - WREG_CRT(0x1b, tmp);
> - WREG8(CRT_INDEX, 0x1d);
> - tmp = RREG8(CRT_DATA);
> - tmp &= 0x7f;
> - tmp |= (addr >> 12) & 0x80;
> - WREG_CRT(0x1d, tmp);
> -}
> -
> -/* cirrus is different - we will force move buffers out of VRAM */
> -static int cirrus_crtc_do_set_base(struct drm_crtc *crtc,
> - struct drm_framebuffer *fb,
> - int x, int y, int atomic)
> -{
> - struct cirrus_device *cdev = crtc->dev->dev_private;
> - struct cirrus_bo *bo;
> - int ret;
> - u64 gpu_addr;
> -
> - /* push the previous fb to system ram */
> - if (!atomic && fb) {
> - bo = gem_to_cirrus_bo(fb->obj[0]);
> - ret = cirrus_bo_reserve(bo, false);
> - if (ret)
> - return ret;
> - cirrus_bo_push_sysram(bo);
> - cirrus_bo_unreserve(bo);
> - }
> -
> - bo = gem_to_cirrus_bo(crtc->primary->fb->obj[0]);
> -
> - ret = cirrus_bo_reserve(bo, false);
> - if (ret)
> - return ret;
> -
> - ret = cirrus_bo_pin(bo, TTM_PL_FLAG_VRAM, &gpu_addr);
> - if (ret) {
> - cirrus_bo_unreserve(bo);
> - return ret;
> - }
> -
> - if (cdev->mode_info.gfbdev->gfb == crtc->primary->fb) {
> - /* if pushing console in kmap it */
> - ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap);
> - if (ret)
> - DRM_ERROR("failed to kmap fbcon\n");
> - }
> - cirrus_bo_unreserve(bo);
> -
> - cirrus_set_start_address(crtc, (u32)gpu_addr);
> - return 0;
> -}
> -
> -static int cirrus_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
> - struct drm_framebuffer *old_fb)
> -{
> - return cirrus_crtc_do_set_base(crtc, old_fb, x, y, 0);
> -}
> -
> -/*
> - * The meat of this driver. The core passes us a mode and we have to program
> - * it. The modesetting here is the bare minimum required to satisfy the qemu
> - * emulation of this hardware, and running this against a real device is
> - * likely to result in an inadequately programmed mode. We've already had
> - * the opportunity to modify the mode, so whatever we receive here should
> - * be something that can be correctly programmed and displayed
> - */
> -static int cirrus_crtc_mode_set(struct drm_crtc *crtc,
> - struct drm_display_mode *mode,
> - struct drm_display_mode *adjusted_mode,
> - int x, int y, struct drm_framebuffer *old_fb)
> -{
> - struct drm_device *dev = crtc->dev;
> - struct cirrus_device *cdev = dev->dev_private;
> - const struct drm_framebuffer *fb = crtc->primary->fb;
> - int hsyncstart, hsyncend, htotal, hdispend;
> - int vtotal, vdispend;
> - int tmp;
> - int sr07 = 0, hdr = 0;
> -
> - htotal = mode->htotal / 8;
> - hsyncend = mode->hsync_end / 8;
> - hsyncstart = mode->hsync_start / 8;
> - hdispend = mode->hdisplay / 8;
> -
> - vtotal = mode->vtotal;
> - vdispend = mode->vdisplay;
> -
> - vdispend -= 1;
> - vtotal -= 2;
> -
> - htotal -= 5;
> - hdispend -= 1;
> - hsyncstart += 1;
> - hsyncend += 1;
> -
> - WREG_CRT(VGA_CRTC_V_SYNC_END, 0x20);
> - WREG_CRT(VGA_CRTC_H_TOTAL, htotal);
> - WREG_CRT(VGA_CRTC_H_DISP, hdispend);
> - WREG_CRT(VGA_CRTC_H_SYNC_START, hsyncstart);
> - WREG_CRT(VGA_CRTC_H_SYNC_END, hsyncend);
> - WREG_CRT(VGA_CRTC_V_TOTAL, vtotal & 0xff);
> - WREG_CRT(VGA_CRTC_V_DISP_END, vdispend & 0xff);
> -
> - tmp = 0x40;
> - if ((vdispend + 1) & 512)
> - tmp |= 0x20;
> - WREG_CRT(VGA_CRTC_MAX_SCAN, tmp);
> -
> - /*
> - * Overflow bits for values that don't fit in the standard registers
> - */
> - tmp = 16;
> - if (vtotal & 256)
> - tmp |= 1;
> - if (vdispend & 256)
> - tmp |= 2;
> - if ((vdispend + 1) & 256)
> - tmp |= 8;
> - if (vtotal & 512)
> - tmp |= 32;
> - if (vdispend & 512)
> - tmp |= 64;
> - WREG_CRT(VGA_CRTC_OVERFLOW, tmp);
> -
> - tmp = 0;
> -
> - /* More overflow bits */
> -
> - if ((htotal + 5) & 64)
> - tmp |= 16;
> - if ((htotal + 5) & 128)
> - tmp |= 32;
> - if (vtotal & 256)
> - tmp |= 64;
> - if (vtotal & 512)
> - tmp |= 128;
> -
> - WREG_CRT(CL_CRT1A, tmp);
> -
> - /* Disable Hercules/CGA compatibility */
> - WREG_CRT(VGA_CRTC_MODE, 0x03);
> -
> - WREG8(SEQ_INDEX, 0x7);
> - sr07 = RREG8(SEQ_DATA);
> - sr07 &= 0xe0;
> - hdr = 0;
> - switch (fb->format->cpp[0] * 8) {
> - case 8:
> - sr07 |= 0x11;
> - break;
> - case 16:
> - sr07 |= 0x17;
> - hdr = 0xc1;
> - break;
> - case 24:
> - sr07 |= 0x15;
> - hdr = 0xc5;
> - break;
> - case 32:
> - sr07 |= 0x19;
> - hdr = 0xc5;
> - break;
> - default:
> - return -1;
> - }
> -
> - WREG_SEQ(0x7, sr07);
> -
> - /* Program the pitch */
> - tmp = fb->pitches[0] / 8;
> - WREG_CRT(VGA_CRTC_OFFSET, tmp);
> -
> - /* Enable extended blanking and pitch bits, and enable full memory */
> - tmp = 0x22;
> - tmp |= (fb->pitches[0] >> 7) & 0x10;
> - tmp |= (fb->pitches[0] >> 6) & 0x40;
> - WREG_CRT(0x1b, tmp);
> -
> - /* Enable high-colour modes */
> - WREG_GFX(VGA_GFX_MODE, 0x40);
> -
> - /* And set graphics mode */
> - WREG_GFX(VGA_GFX_MISC, 0x01);
> -
> - WREG_HDR(hdr);
> - cirrus_crtc_do_set_base(crtc, old_fb, x, y, 0);
> -
> - /* Unblank (needed on S3 resume, vgabios doesn't do it then) */
> - outb(0x20, 0x3c0);
> - return 0;
> -}
> -
> -/*
> - * This is called before a mode is programmed. A typical use might be to
> - * enable DPMS during the programming to avoid seeing intermediate stages,
> - * but that's not relevant to us
> - */
> -static void cirrus_crtc_prepare(struct drm_crtc *crtc)
> -{
> -}
> -
> -static void cirrus_crtc_load_lut(struct drm_crtc *crtc)
> -{
> - struct drm_device *dev = crtc->dev;
> - struct cirrus_device *cdev = dev->dev_private;
> - u16 *r, *g, *b;
> - int i;
> -
> - if (!crtc->enabled)
> - return;
> -
> - r = crtc->gamma_store;
> - g = r + crtc->gamma_size;
> - b = g + crtc->gamma_size;
> -
> - for (i = 0; i < CIRRUS_LUT_SIZE; i++) {
> - /* VGA registers */
> - WREG8(PALETTE_INDEX, i);
> - WREG8(PALETTE_DATA, *r++ >> 8);
> - WREG8(PALETTE_DATA, *g++ >> 8);
> - WREG8(PALETTE_DATA, *b++ >> 8);
> - }
> -}
> -
> -/*
> - * This is called after a mode is programmed. It should reverse anything done
> - * by the prepare function
> - */
> -static void cirrus_crtc_commit(struct drm_crtc *crtc)
> -{
> - cirrus_crtc_load_lut(crtc);
> -}
> -
> -/*
> - * The core can pass us a set of gamma values to program. We actually only
> - * use this for 8-bit mode so can't perform smooth fades on deeper modes,
> - * but it's a requirement that we provide the function
> - */
> -static int cirrus_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green,
> - u16 *blue, uint32_t size,
> - struct drm_modeset_acquire_ctx *ctx)
> -{
> - cirrus_crtc_load_lut(crtc);
> -
> - return 0;
> -}
> -
> -/* Simple cleanup function */
> -static void cirrus_crtc_destroy(struct drm_crtc *crtc)
> -{
> - struct cirrus_crtc *cirrus_crtc = to_cirrus_crtc(crtc);
> -
> - drm_crtc_cleanup(crtc);
> - kfree(cirrus_crtc);
> -}
> -
> -/* These provide the minimum set of functions required to handle a CRTC */
> -static const struct drm_crtc_funcs cirrus_crtc_funcs = {
> - .gamma_set = cirrus_crtc_gamma_set,
> - .set_config = drm_crtc_helper_set_config,
> - .destroy = cirrus_crtc_destroy,
> -};
> -
> -static const struct drm_crtc_helper_funcs cirrus_helper_funcs = {
> - .dpms = cirrus_crtc_dpms,
> - .mode_set = cirrus_crtc_mode_set,
> - .mode_set_base = cirrus_crtc_mode_set_base,
> - .prepare = cirrus_crtc_prepare,
> - .commit = cirrus_crtc_commit,
> -};
> -
> -/* CRTC setup */
> -static const uint32_t cirrus_formats_16[] = {
> - DRM_FORMAT_RGB565,
> -};
> -
> -static const uint32_t cirrus_formats_24[] = {
> - DRM_FORMAT_RGB888,
> - DRM_FORMAT_RGB565,
> -};
> -
> -static const uint32_t cirrus_formats_32[] = {
> - DRM_FORMAT_XRGB8888,
> - DRM_FORMAT_ARGB8888,
> - DRM_FORMAT_RGB888,
> - DRM_FORMAT_RGB565,
> -};
> -
> -static struct drm_plane *cirrus_primary_plane(struct drm_device *dev)
> -{
> - const uint32_t *formats;
> - uint32_t nformats;
> - struct drm_plane *primary;
> - int ret;
> -
> - switch (cirrus_bpp) {
> - case 16:
> - formats = cirrus_formats_16;
> - nformats = ARRAY_SIZE(cirrus_formats_16);
> - break;
> - case 24:
> - formats = cirrus_formats_24;
> - nformats = ARRAY_SIZE(cirrus_formats_24);
> - break;
> - case 32:
> - formats = cirrus_formats_32;
> - nformats = ARRAY_SIZE(cirrus_formats_32);
> - break;
> - default:
> - return NULL;
> - }
> -
> - primary = kzalloc(sizeof(*primary), GFP_KERNEL);
> - if (primary == NULL) {
> - DRM_DEBUG_KMS("Failed to allocate primary plane\n");
> - return NULL;
> - }
> -
> - ret = drm_universal_plane_init(dev, primary, 0,
> - &drm_primary_helper_funcs,
> - formats, nformats,
> - NULL,
> - DRM_PLANE_TYPE_PRIMARY, NULL);
> - if (ret) {
> - kfree(primary);
> - primary = NULL;
> - }
> -
> - return primary;
> -}
> -
> -static void cirrus_crtc_init(struct drm_device *dev)
> -{
> - struct cirrus_device *cdev = dev->dev_private;
> - struct cirrus_crtc *cirrus_crtc;
> - struct drm_plane *primary;
> -
> - cirrus_crtc = kzalloc(sizeof(struct cirrus_crtc) +
> - (CIRRUSFB_CONN_LIMIT * sizeof(struct drm_connector *)),
> - GFP_KERNEL);
> -
> - if (cirrus_crtc == NULL)
> - return;
> -
> - primary = cirrus_primary_plane(dev);
> - if (primary == NULL) {
> - kfree(cirrus_crtc);
> - return;
> - }
> -
> - drm_crtc_init_with_planes(dev, &cirrus_crtc->base,
> - primary, NULL,
> - &cirrus_crtc_funcs, NULL);
> -
> - drm_mode_crtc_set_gamma_size(&cirrus_crtc->base, CIRRUS_LUT_SIZE);
> - cdev->mode_info.crtc = cirrus_crtc;
> -
> - drm_crtc_helper_add(&cirrus_crtc->base, &cirrus_helper_funcs);
> -}
> -
> -static void cirrus_encoder_mode_set(struct drm_encoder *encoder,
> - struct drm_display_mode *mode,
> - struct drm_display_mode *adjusted_mode)
> -{
> -}
> -
> -static void cirrus_encoder_dpms(struct drm_encoder *encoder, int state)
> -{
> - return;
> -}
> -
> -static void cirrus_encoder_prepare(struct drm_encoder *encoder)
> -{
> -}
> -
> -static void cirrus_encoder_commit(struct drm_encoder *encoder)
> -{
> -}
> -
> -static void cirrus_encoder_destroy(struct drm_encoder *encoder)
> -{
> - struct cirrus_encoder *cirrus_encoder = to_cirrus_encoder(encoder);
> - drm_encoder_cleanup(encoder);
> - kfree(cirrus_encoder);
> -}
> -
> -static const struct drm_encoder_helper_funcs cirrus_encoder_helper_funcs = {
> - .dpms = cirrus_encoder_dpms,
> - .mode_set = cirrus_encoder_mode_set,
> - .prepare = cirrus_encoder_prepare,
> - .commit = cirrus_encoder_commit,
> -};
> -
> -static const struct drm_encoder_funcs cirrus_encoder_encoder_funcs = {
> - .destroy = cirrus_encoder_destroy,
> -};
> -
> -static struct drm_encoder *cirrus_encoder_init(struct drm_device *dev)
> -{
> - struct drm_encoder *encoder;
> - struct cirrus_encoder *cirrus_encoder;
> -
> - cirrus_encoder = kzalloc(sizeof(struct cirrus_encoder), GFP_KERNEL);
> - if (!cirrus_encoder)
> - return NULL;
> -
> - encoder = &cirrus_encoder->base;
> - encoder->possible_crtcs = 0x1;
> -
> - drm_encoder_init(dev, encoder, &cirrus_encoder_encoder_funcs,
> - DRM_MODE_ENCODER_DAC, NULL);
> - drm_encoder_helper_add(encoder, &cirrus_encoder_helper_funcs);
> -
> - return encoder;
> -}
> -
> -
> -static int cirrus_vga_get_modes(struct drm_connector *connector)
> -{
> - int count;
> -
> - /* Just add a static list of modes */
> - if (cirrus_bpp <= 24) {
> - count = drm_add_modes_noedid(connector, 1280, 1024);
> - drm_set_preferred_mode(connector, 1024, 768);
> - } else {
> - count = drm_add_modes_noedid(connector, 800, 600);
> - drm_set_preferred_mode(connector, 800, 600);
> - }
> - return count;
> -}
> -
> -static struct drm_encoder *cirrus_connector_best_encoder(struct drm_connector
> - *connector)
> -{
> - int enc_id = connector->encoder_ids[0];
> - /* pick the encoder ids */
> - if (enc_id)
> - return drm_encoder_find(connector->dev, NULL, enc_id);
> - return NULL;
> -}
> -
> -static void cirrus_connector_destroy(struct drm_connector *connector)
> -{
> - drm_connector_cleanup(connector);
> - kfree(connector);
> -}
> -
> -static const struct drm_connector_helper_funcs cirrus_vga_connector_helper_funcs = {
> - .get_modes = cirrus_vga_get_modes,
> - .best_encoder = cirrus_connector_best_encoder,
> -};
> -
> -static const struct drm_connector_funcs cirrus_vga_connector_funcs = {
> - .dpms = drm_helper_connector_dpms,
> - .fill_modes = drm_helper_probe_single_connector_modes,
> - .destroy = cirrus_connector_destroy,
> -};
> -
> -static struct drm_connector *cirrus_vga_init(struct drm_device *dev)
> -{
> - struct drm_connector *connector;
> - struct cirrus_connector *cirrus_connector;
> -
> - cirrus_connector = kzalloc(sizeof(struct cirrus_connector), GFP_KERNEL);
> - if (!cirrus_connector)
> - return NULL;
> -
> - connector = &cirrus_connector->base;
> -
> - drm_connector_init(dev, connector,
> - &cirrus_vga_connector_funcs, DRM_MODE_CONNECTOR_VGA);
> -
> - drm_connector_helper_add(connector, &cirrus_vga_connector_helper_funcs);
> -
> - drm_connector_register(connector);
> - return connector;
> -}
> -
> -
> -int cirrus_modeset_init(struct cirrus_device *cdev)
> -{
> - struct drm_encoder *encoder;
> - struct drm_connector *connector;
> - int ret;
> -
> - drm_mode_config_init(cdev->dev);
> -
> - cdev->dev->mode_config.max_width = CIRRUS_MAX_FB_WIDTH;
> - cdev->dev->mode_config.max_height = CIRRUS_MAX_FB_HEIGHT;
> -
> - cdev->dev->mode_config.fb_base = cdev->mc.vram_base;
> - cdev->dev->mode_config.preferred_depth = cirrus_bpp;
> - /* don't prefer a shadow on virt GPU */
> - cdev->dev->mode_config.prefer_shadow = 0;
> -
> - cirrus_crtc_init(cdev->dev);
> -
> - encoder = cirrus_encoder_init(cdev->dev);
> - if (!encoder) {
> - DRM_ERROR("cirrus_encoder_init failed\n");
> - return -1;
> - }
> -
> - connector = cirrus_vga_init(cdev->dev);
> - if (!connector) {
> - DRM_ERROR("cirrus_vga_init failed\n");
> - return -1;
> - }
> -
> - drm_connector_attach_encoder(connector, encoder);
> -
> - ret = cirrus_fbdev_init(cdev);
> - if (ret) {
> - DRM_ERROR("cirrus_fbdev_init failed\n");
> - return ret;
> - }
> -
> - return 0;
> -}
> -
> -void cirrus_modeset_fini(struct cirrus_device *cdev)
> -{
> - cirrus_fbdev_fini(cdev);
> - drm_helper_force_disable_all(cdev->dev);
> - drm_mode_config_cleanup(cdev->dev);
> -}
> diff --git a/drivers/gpu/drm/cirrus/cirrus_ttm.c b/drivers/gpu/drm/cirrus/cirrus_ttm.c
> deleted file mode 100644
> index e075810b4bd4..000000000000
> --- a/drivers/gpu/drm/cirrus/cirrus_ttm.c
> +++ /dev/null
> @@ -1,343 +0,0 @@
> -/*
> - * Copyright 2012 Red Hat Inc.
> - *
> - * Permission is hereby granted, free of charge, to any person obtaining a
> - * copy of this software and associated documentation files (the
> - * "Software"), to deal in the Software without restriction, including
> - * without limitation the rights to use, copy, modify, merge, publish,
> - * distribute, sub license, and/or sell copies of the Software, and to
> - * permit persons to whom the Software is furnished to do so, subject to
> - * the following conditions:
> - *
> - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
> - * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
> - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
> - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
> - * USE OR OTHER DEALINGS IN THE SOFTWARE.
> - *
> - * The above copyright notice and this permission notice (including the
> - * next paragraph) shall be included in all copies or substantial portions
> - * of the Software.
> - *
> - */
> -/*
> - * Authors: Dave Airlie <airlied@redhat.com>
> - */
> -#include <drm/drmP.h>
> -#include <drm/ttm/ttm_page_alloc.h>
> -
> -#include "cirrus_drv.h"
> -
> -static inline struct cirrus_device *
> -cirrus_bdev(struct ttm_bo_device *bd)
> -{
> - return container_of(bd, struct cirrus_device, ttm.bdev);
> -}
> -
> -static void cirrus_bo_ttm_destroy(struct ttm_buffer_object *tbo)
> -{
> - struct cirrus_bo *bo;
> -
> - bo = container_of(tbo, struct cirrus_bo, bo);
> -
> - drm_gem_object_release(&bo->gem);
> - kfree(bo);
> -}
> -
> -static bool cirrus_ttm_bo_is_cirrus_bo(struct ttm_buffer_object *bo)
> -{
> - if (bo->destroy == &cirrus_bo_ttm_destroy)
> - return true;
> - return false;
> -}
> -
> -static int
> -cirrus_bo_init_mem_type(struct ttm_bo_device *bdev, uint32_t type,
> - struct ttm_mem_type_manager *man)
> -{
> - switch (type) {
> - case TTM_PL_SYSTEM:
> - man->flags = TTM_MEMTYPE_FLAG_MAPPABLE;
> - man->available_caching = TTM_PL_MASK_CACHING;
> - man->default_caching = TTM_PL_FLAG_CACHED;
> - break;
> - case TTM_PL_VRAM:
> - man->func = &ttm_bo_manager_func;
> - man->flags = TTM_MEMTYPE_FLAG_FIXED |
> - TTM_MEMTYPE_FLAG_MAPPABLE;
> - man->available_caching = TTM_PL_FLAG_UNCACHED |
> - TTM_PL_FLAG_WC;
> - man->default_caching = TTM_PL_FLAG_WC;
> - break;
> - default:
> - DRM_ERROR("Unsupported memory type %u\n", (unsigned)type);
> - return -EINVAL;
> - }
> - return 0;
> -}
> -
> -static void
> -cirrus_bo_evict_flags(struct ttm_buffer_object *bo, struct ttm_placement *pl)
> -{
> - struct cirrus_bo *cirrusbo = cirrus_bo(bo);
> -
> - if (!cirrus_ttm_bo_is_cirrus_bo(bo))
> - return;
> -
> - cirrus_ttm_placement(cirrusbo, TTM_PL_FLAG_SYSTEM);
> - *pl = cirrusbo->placement;
> -}
> -
> -static int cirrus_bo_verify_access(struct ttm_buffer_object *bo, struct file *filp)
> -{
> - struct cirrus_bo *cirrusbo = cirrus_bo(bo);
> -
> - return drm_vma_node_verify_access(&cirrusbo->gem.vma_node,
> - filp->private_data);
> -}
> -
> -static int cirrus_ttm_io_mem_reserve(struct ttm_bo_device *bdev,
> - struct ttm_mem_reg *mem)
> -{
> - struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type];
> - struct cirrus_device *cirrus = cirrus_bdev(bdev);
> -
> - mem->bus.addr = NULL;
> - mem->bus.offset = 0;
> - mem->bus.size = mem->num_pages << PAGE_SHIFT;
> - mem->bus.base = 0;
> - mem->bus.is_iomem = false;
> - if (!(man->flags & TTM_MEMTYPE_FLAG_MAPPABLE))
> - return -EINVAL;
> - switch (mem->mem_type) {
> - case TTM_PL_SYSTEM:
> - /* system memory */
> - return 0;
> - case TTM_PL_VRAM:
> - mem->bus.offset = mem->start << PAGE_SHIFT;
> - mem->bus.base = pci_resource_start(cirrus->dev->pdev, 0);
> - mem->bus.is_iomem = true;
> - break;
> - default:
> - return -EINVAL;
> - break;
> - }
> - return 0;
> -}
> -
> -static void cirrus_ttm_io_mem_free(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem)
> -{
> -}
> -
> -static void cirrus_ttm_backend_destroy(struct ttm_tt *tt)
> -{
> - ttm_tt_fini(tt);
> - kfree(tt);
> -}
> -
> -static struct ttm_backend_func cirrus_tt_backend_func = {
> - .destroy = &cirrus_ttm_backend_destroy,
> -};
> -
> -
> -static struct ttm_tt *cirrus_ttm_tt_create(struct ttm_buffer_object *bo,
> - uint32_t page_flags)
> -{
> - struct ttm_tt *tt;
> -
> - tt = kzalloc(sizeof(struct ttm_tt), GFP_KERNEL);
> - if (tt == NULL)
> - return NULL;
> - tt->func = &cirrus_tt_backend_func;
> - if (ttm_tt_init(tt, bo, page_flags)) {
> - kfree(tt);
> - return NULL;
> - }
> - return tt;
> -}
> -
> -struct ttm_bo_driver cirrus_bo_driver = {
> - .ttm_tt_create = cirrus_ttm_tt_create,
> - .init_mem_type = cirrus_bo_init_mem_type,
> - .eviction_valuable = ttm_bo_eviction_valuable,
> - .evict_flags = cirrus_bo_evict_flags,
> - .move = NULL,
> - .verify_access = cirrus_bo_verify_access,
> - .io_mem_reserve = &cirrus_ttm_io_mem_reserve,
> - .io_mem_free = &cirrus_ttm_io_mem_free,
> -};
> -
> -int cirrus_mm_init(struct cirrus_device *cirrus)
> -{
> - int ret;
> - struct drm_device *dev = cirrus->dev;
> - struct ttm_bo_device *bdev = &cirrus->ttm.bdev;
> -
> - ret = ttm_bo_device_init(&cirrus->ttm.bdev,
> - &cirrus_bo_driver,
> - dev->anon_inode->i_mapping,
> - DRM_FILE_PAGE_OFFSET,
> - true);
> - if (ret) {
> - DRM_ERROR("Error initialising bo driver; %d\n", ret);
> - return ret;
> - }
> -
> - ret = ttm_bo_init_mm(bdev, TTM_PL_VRAM,
> - cirrus->mc.vram_size >> PAGE_SHIFT);
> - if (ret) {
> - DRM_ERROR("Failed ttm VRAM init: %d\n", ret);
> - return ret;
> - }
> -
> - arch_io_reserve_memtype_wc(pci_resource_start(dev->pdev, 0),
> - pci_resource_len(dev->pdev, 0));
> -
> - cirrus->fb_mtrr = arch_phys_wc_add(pci_resource_start(dev->pdev, 0),
> - pci_resource_len(dev->pdev, 0));
> -
> - cirrus->mm_inited = true;
> - return 0;
> -}
> -
> -void cirrus_mm_fini(struct cirrus_device *cirrus)
> -{
> - struct drm_device *dev = cirrus->dev;
> -
> - if (!cirrus->mm_inited)
> - return;
> -
> - ttm_bo_device_release(&cirrus->ttm.bdev);
> -
> - arch_phys_wc_del(cirrus->fb_mtrr);
> - cirrus->fb_mtrr = 0;
> - arch_io_free_memtype_wc(pci_resource_start(dev->pdev, 0),
> - pci_resource_len(dev->pdev, 0));
> -}
> -
> -void cirrus_ttm_placement(struct cirrus_bo *bo, int domain)
> -{
> - u32 c = 0;
> - unsigned i;
> - bo->placement.placement = bo->placements;
> - bo->placement.busy_placement = bo->placements;
> - if (domain & TTM_PL_FLAG_VRAM)
> - bo->placements[c++].flags = TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_VRAM;
> - if (domain & TTM_PL_FLAG_SYSTEM)
> - bo->placements[c++].flags = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM;
> - if (!c)
> - bo->placements[c++].flags = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM;
> - bo->placement.num_placement = c;
> - bo->placement.num_busy_placement = c;
> - for (i = 0; i < c; ++i) {
> - bo->placements[i].fpfn = 0;
> - bo->placements[i].lpfn = 0;
> - }
> -}
> -
> -int cirrus_bo_create(struct drm_device *dev, int size, int align,
> - uint32_t flags, struct cirrus_bo **pcirrusbo)
> -{
> - struct cirrus_device *cirrus = dev->dev_private;
> - struct cirrus_bo *cirrusbo;
> - size_t acc_size;
> - int ret;
> -
> - cirrusbo = kzalloc(sizeof(struct cirrus_bo), GFP_KERNEL);
> - if (!cirrusbo)
> - return -ENOMEM;
> -
> - ret = drm_gem_object_init(dev, &cirrusbo->gem, size);
> - if (ret) {
> - kfree(cirrusbo);
> - return ret;
> - }
> -
> - cirrusbo->bo.bdev = &cirrus->ttm.bdev;
> -
> - cirrus_ttm_placement(cirrusbo, TTM_PL_FLAG_VRAM | TTM_PL_FLAG_SYSTEM);
> -
> - acc_size = ttm_bo_dma_acc_size(&cirrus->ttm.bdev, size,
> - sizeof(struct cirrus_bo));
> -
> - ret = ttm_bo_init(&cirrus->ttm.bdev, &cirrusbo->bo, size,
> - ttm_bo_type_device, &cirrusbo->placement,
> - align >> PAGE_SHIFT, false, acc_size,
> - NULL, NULL, cirrus_bo_ttm_destroy);
> - if (ret)
> - return ret;
> -
> - *pcirrusbo = cirrusbo;
> - return 0;
> -}
> -
> -static inline u64 cirrus_bo_gpu_offset(struct cirrus_bo *bo)
> -{
> - return bo->bo.offset;
> -}
> -
> -int cirrus_bo_pin(struct cirrus_bo *bo, u32 pl_flag, u64 *gpu_addr)
> -{
> - struct ttm_operation_ctx ctx = { false, false };
> - int i, ret;
> -
> - if (bo->pin_count) {
> - bo->pin_count++;
> - if (gpu_addr)
> - *gpu_addr = cirrus_bo_gpu_offset(bo);
> - }
> -
> - cirrus_ttm_placement(bo, pl_flag);
> - for (i = 0; i < bo->placement.num_placement; i++)
> - bo->placements[i].flags |= TTM_PL_FLAG_NO_EVICT;
> - ret = ttm_bo_validate(&bo->bo, &bo->placement, &ctx);
> - if (ret)
> - return ret;
> -
> - bo->pin_count = 1;
> - if (gpu_addr)
> - *gpu_addr = cirrus_bo_gpu_offset(bo);
> - return 0;
> -}
> -
> -int cirrus_bo_push_sysram(struct cirrus_bo *bo)
> -{
> - struct ttm_operation_ctx ctx = { false, false };
> - int i, ret;
> - if (!bo->pin_count) {
> - DRM_ERROR("unpin bad %p\n", bo);
> - return 0;
> - }
> - bo->pin_count--;
> - if (bo->pin_count)
> - return 0;
> -
> - if (bo->kmap.virtual)
> - ttm_bo_kunmap(&bo->kmap);
> -
> - cirrus_ttm_placement(bo, TTM_PL_FLAG_SYSTEM);
> - for (i = 0; i < bo->placement.num_placement ; i++)
> - bo->placements[i].flags |= TTM_PL_FLAG_NO_EVICT;
> -
> - ret = ttm_bo_validate(&bo->bo, &bo->placement, &ctx);
> - if (ret) {
> - DRM_ERROR("pushing to VRAM failed\n");
> - return ret;
> - }
> - return 0;
> -}
> -
> -int cirrus_mmap(struct file *filp, struct vm_area_struct *vma)
> -{
> - struct drm_file *file_priv;
> - struct cirrus_device *cirrus;
> -
> - if (unlikely(vma->vm_pgoff < DRM_FILE_PAGE_OFFSET))
> - return -EINVAL;
> -
> - file_priv = filp->private_data;
> - cirrus = file_priv->minor->dev->dev_private;
> - return ttm_bo_mmap(filp, vma, &cirrus->ttm.bdev);
> -}
> diff --git a/drivers/gpu/drm/cirrus/Kconfig b/drivers/gpu/drm/cirrus/Kconfig
> index fc78c90ee931..dd4f52a0bc1c 100644
> --- a/drivers/gpu/drm/cirrus/Kconfig
> +++ b/drivers/gpu/drm/cirrus/Kconfig
> @@ -2,7 +2,7 @@ config DRM_CIRRUS_QEMU
> tristate "Cirrus driver for QEMU emulated device"
> depends on DRM && PCI && MMU
> select DRM_KMS_HELPER
> - select DRM_TTM
> + select DRM_GEM_SHMEM_HELPER
> help
> This is a KMS driver for emulated cirrus device in qemu.
> It is *NOT* intended for real cirrus devices. This requires
> diff --git a/drivers/gpu/drm/cirrus/Makefile b/drivers/gpu/drm/cirrus/Makefile
> index 919c0a336c97..acf8971d37a1 100644
> --- a/drivers/gpu/drm/cirrus/Makefile
> +++ b/drivers/gpu/drm/cirrus/Makefile
> @@ -1,4 +1 @@
> -cirrus-y := cirrus_main.o cirrus_mode.o \
> - cirrus_drv.o cirrus_fbdev.o cirrus_ttm.o
> -
> obj-$(CONFIG_DRM_CIRRUS_QEMU) += cirrus.o
> --
> 2.18.1
>
--
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
^ permalink raw reply
* [PATCH] virtio-net: Remove inclusion of pci.h
From: Yuval Shaia @ 2019-04-03 8:20 UTC (permalink / raw)
To: mst, jasowang, davem, virtualization, netdev; +Cc: Yuval Shaia
This header is not in use - remove it.
Signed-off-by: Yuval Shaia <yuval.shaia@oracle.com>
---
drivers/net/virtio_net.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 7eb38ea9ba56..07c1e81087b2 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -31,7 +31,6 @@
#include <linux/average.h>
#include <linux/filter.h>
#include <linux/kernel.h>
-#include <linux/pci.h>
#include <net/route.h>
#include <net/xdp.h>
#include <net/net_failover.h>
--
2.19.1
^ permalink raw reply related
* Re: [PATCH] drm/cirrus: rewrite and modernize driver.
From: Gerd Hoffmann @ 2019-04-03 8:53 UTC (permalink / raw)
To: Daniel Vetter
Cc: David Airlie, Dave Airlie, open list, dri-devel,
open list:DRM DRIVER FOR QEMU'S CIRRUS DEVICE
In-Reply-To: <CAKMK7uGWh02L9n4etQC3V-RX3aWovJLpadNFe08LdWXRNz2yuw@mail.gmail.com>
> > +struct cirrus_device {
> > + struct drm_device *dev;
>
> Why not embed drm_device? It's the latest rage :-)
Sure, can do that.
> > +void cirrus_pipe_update(struct drm_simple_display_pipe *pipe,
> > + struct drm_plane_state *old_state)
> > +{
> > + struct drm_plane_state *state = pipe->plane.state;
> > + struct drm_crtc *crtc = &pipe->crtc;
> > + struct drm_rect rect;
> > +
> > + if (drm_atomic_helper_damage_merged(old_state, state, &rect))
> > + cirrus_fb_blit_rect(pipe->plane.state->fb, &rect);
> > +
> > + if (crtc->state->event) {
> > + spin_lock_irq(&crtc->dev->event_lock);
> > + drm_crtc_send_vblank_event(crtc, crtc->state->event);
> > + spin_unlock_irq(&crtc->dev->event_lock);
> > + crtc->state->event = NULL;
> > + }
> > +}
> > +static int cirrus_fb_dirty(struct drm_framebuffer *fb,
> > + struct drm_file *file_priv,
> > + unsigned int flags, unsigned int color,
> > + struct drm_clip_rect *clips,
> > + unsigned int num_clips)
> > +{
> > + struct cirrus_device *cirrus = fb->dev->dev_private;
> > +
> > + if (cirrus->pipe.plane.state->fb != fb)
> > + return 0;
> > +
> > + if (num_clips)
> > + cirrus_fb_blit_clips(fb, clips, num_clips);
> > + else
> > + cirrus_fb_blit_fullscreen(fb);
> > + return 0;
> > +}
>
> Why not use the dirty helpers and implement dirty rect support in your
> main plane update function?
Dirty rect support is already there, see above.
So I can just remove cirrus_fb_dirty() and hook up
drm_atomic_helper_dirtyfb() instead. Easy ;)
cheers,
Gerd
^ permalink raw reply
* [PATCH] virtio-net: Fix some minor formatting errors
From: Yuval Shaia @ 2019-04-03 9:10 UTC (permalink / raw)
To: mst, jasowang, davem, virtualization, netdev; +Cc: Yuval Shaia
Signed-off-by: Yuval Shaia <yuval.shaia@oracle.com>
---
drivers/net/virtio_net.c | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 07c1e81087b2..be1188815c72 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -1587,7 +1587,8 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
dev->stats.tx_fifo_errors++;
if (net_ratelimit())
dev_warn(&dev->dev,
- "Unexpected TXQ (%d) queue failure: %d\n", qnum, err);
+ "Unexpected TXQ (%d) queue failure: %d\n",
+ qnum, err);
dev->stats.tx_dropped++;
dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
@@ -2383,7 +2384,7 @@ static int virtnet_set_guest_offloads(struct virtnet_info *vi, u64 offloads)
if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_GUEST_OFFLOADS,
VIRTIO_NET_CTRL_GUEST_OFFLOADS_SET, &sg)) {
- dev_warn(&vi->dev->dev, "Fail to set guest offload. \n");
+ dev_warn(&vi->dev->dev, "Fail to set guest offload.\n");
return -EINVAL;
}
@@ -3114,8 +3115,9 @@ static int virtnet_probe(struct virtio_device *vdev)
/* Should never trigger: MTU was previously validated
* in virtnet_validate.
*/
- dev_err(&vdev->dev, "device MTU appears to have changed "
- "it is now %d < %d", mtu, dev->min_mtu);
+ dev_err(&vdev->dev,
+ "device MTU appears to have changed it is now %d < %d",
+ mtu, dev->min_mtu);
goto free;
}
--
2.19.1
^ permalink raw reply related
* Re: [PATCH] drm/cirrus: rewrite and modernize driver.
From: Noralf Trønnes @ 2019-04-03 9:58 UTC (permalink / raw)
To: Gerd Hoffmann, Daniel Vetter
Cc: David Airlie, Dave Airlie, open list, dri-devel,
open list:DRM DRIVER FOR QEMU'S CIRRUS DEVICE
In-Reply-To: <20190403085341.2cxdgxqrjlwecx3n@sirius.home.kraxel.org>
Den 03.04.2019 10.53, skrev Gerd Hoffmann:
>>> +struct cirrus_device {
>>> + struct drm_device *dev;
>>
>> Why not embed drm_device? It's the latest rage :-)
>
> Sure, can do that.
>
>>> +void cirrus_pipe_update(struct drm_simple_display_pipe *pipe,
>>> + struct drm_plane_state *old_state)
>>> +{
>>> + struct drm_plane_state *state = pipe->plane.state;
>>> + struct drm_crtc *crtc = &pipe->crtc;
>>> + struct drm_rect rect;
>>> +
>>> + if (drm_atomic_helper_damage_merged(old_state, state, &rect))
>>> + cirrus_fb_blit_rect(pipe->plane.state->fb, &rect);
>>> +
>>> + if (crtc->state->event) {
>>> + spin_lock_irq(&crtc->dev->event_lock);
>>> + drm_crtc_send_vblank_event(crtc, crtc->state->event);
>>> + spin_unlock_irq(&crtc->dev->event_lock);
>>> + crtc->state->event = NULL;
>>> + }
>>> +}
>
>>> +static int cirrus_fb_dirty(struct drm_framebuffer *fb,
>>> + struct drm_file *file_priv,
>>> + unsigned int flags, unsigned int color,
>>> + struct drm_clip_rect *clips,
>>> + unsigned int num_clips)
>>> +{
>>> + struct cirrus_device *cirrus = fb->dev->dev_private;
>>> +
>>> + if (cirrus->pipe.plane.state->fb != fb)
>>> + return 0;
>>> +
>>> + if (num_clips)
>>> + cirrus_fb_blit_clips(fb, clips, num_clips);
>>> + else
>>> + cirrus_fb_blit_fullscreen(fb);
>>> + return 0;
>>> +}
>>
>> Why not use the dirty helpers and implement dirty rect support in your
>> main plane update function?
>
> Dirty rect support is already there, see above.
>
> So I can just remove cirrus_fb_dirty() and hook up
> drm_atomic_helper_dirtyfb() instead. Easy ;)
>
You can even use drm_gem_fb_create_with_dirty() instead of
drm_gem_fb_create_with_funcs().
Noralf.
> cheers,
> Gerd
>
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel
>
^ permalink raw reply
* Re: [PATCH] drm/cirrus: rewrite and modernize driver.
From: Gerd Hoffmann @ 2019-04-03 10:27 UTC (permalink / raw)
To: Noralf Trønnes
Cc: David Airlie, open list, dri-devel,
open list:DRM DRIVER FOR QEMU'S CIRRUS DEVICE, Daniel Vetter,
Dave Airlie
In-Reply-To: <0c959f3a-15e9-8295-dc11-2f6b9a4229ac@tronnes.org>
Hi,
> > So I can just remove cirrus_fb_dirty() and hook up
> > drm_atomic_helper_dirtyfb() instead. Easy ;)
>
> You can even use drm_gem_fb_create_with_dirty() instead of
> drm_gem_fb_create_with_funcs().
Ah, cool. /me happily continues removing code lines.
thanks,
Gerd
PS: incremental fixups are at
https://git.kraxel.org/cgit/linux/log/?h=drm-rewrite-cirrus
^ permalink raw reply
* [PATCH v4 0/5] virtio pmem driver
From: Pankaj Gupta @ 2019-04-03 10:40 UTC (permalink / raw)
To: linux-nvdimm, linux-kernel, virtualization, kvm, linux-fsdevel,
linux-acpi, qemu-devel, linux-ext4, linux-xfs
Cc: pagupta, jack, mst, david, lcapitulino, adilger.kernel, zwisler,
aarcange, dave.jiang, darrick.wong, vishal.l.verma, willy, hch,
jmoyer, nilal, lenb, riel, stefanha, dan.j.williams, tytso,
xiaoguangrong.eric, cohuck, rjw, imammedo
This patch series has implementation for "virtio pmem".
"virtio pmem" is fake persistent memory(nvdimm) in guest
which allows to bypass the guest page cache. This also
implements a VIRTIO based asynchronous flush mechanism.
Sharing guest kernel driver in this patchset with the
changes suggested in v3. Tested with Qemu side device
emulation [6] for virtio-pmem.
We have incorporated all the suggestions in V3. Documented
the impact of possible page cache side channel attacks with
suggested countermeasures.
Details of project idea for 'virtio pmem' flushing interface
is shared [3] & [4].
Implementation is divided into two parts:
New virtio pmem guest driver and qemu code changes for new
virtio pmem paravirtualized device.
1. Guest virtio-pmem kernel driver
---------------------------------
- Reads persistent memory range from paravirt device and
registers with 'nvdimm_bus'.
- 'nvdimm/pmem' driver uses this information to allocate
persistent memory region and setup filesystem operations
to the allocated memory.
- virtio pmem driver implements asynchronous flushing
interface to flush from guest to host.
2. Qemu virtio-pmem device
---------------------------------
- Creates virtio pmem device and exposes a memory range to
KVM guest.
- At host side this is file backed memory which acts as
persistent memory.
- Qemu side flush uses aio thread pool API's and virtio
for asynchronous guest multi request handling.
David Hildenbrand CCed also posted a modified version[7] of
qemu virtio-pmem code based on updated Qemu memory device API.
Virtio-pmem security implications and countermeasures:
-----------------------------------------------------
In previous posting of kernel driver, there was discussion [9]
on possible implications of page cache side channel attacks with
virtio pmem. After thorough analysis of details of known side
channel attacks, below are the suggestions:
- Depends entirely on how host backing image file is mapped
into guest address space.
- virtio-pmem device emulation, by default shared mapping is used
to map host backing file. It is recommended to use separate
backing file at host side for every guest. This will prevent
any possibility of executing common code from multiple guests
and any chance of inferring guest local data based based on
execution time.
- If backing file is required to be shared among multiple guests
it is recommended to don't support host page cache eviction
commands from the guest driver. This will avoid any possibility
of inferring guest local data or host data from another guest.
- Proposed device specification [8] for virtio-pmem device with
details of possible security implications and suggested
countermeasures for device emulation.
Virtio-pmem errors handling:
----------------------------------------
Checked behaviour of virtio-pmem for below types of errors
Need suggestions on expected behaviour for handling these errors?
- Hardware Errors: Uncorrectable recoverable Errors:
a] virtio-pmem:
- As per current logic if error page belongs to Qemu process,
host MCE handler isolates(hwpoison) that page and send SIGBUS.
Qemu SIGBUS handler injects exception to KVM guest.
- KVM guest then isolates the page and send SIGBUS to guest
userspace process which has mapped the page.
b] Existing implementation for ACPI pmem driver:
- Handles such errors with MCE notifier and creates a list
of bad blocks. Read/direct access DAX operation return EIO
if accessed memory page fall in bad block list.
- It also starts backgound scrubbing.
- Similar functionality can be reused in virtio-pmem with MCE
notifier but without scrubbing(no ACPI/ARS)? Need inputs to
confirm if this behaviour is ok or needs any change?
Changes from PATCH v3: [1]
- Use generic dax_synchronous() helper to check for DAXDEV_SYNC
flag - [Dan, Darrick, Jan]
- Add 'is_nvdimm_async' function
- Document page cache side channel attacks implications &
countermeasures - [Dave Chinner, Michael]
Changes from PATCH v2: [2]
- Disable MAP_SYNC for ext4 & XFS filesystems - [Dan]
- Use name 'virtio pmem' in place of 'fake dax'
Changes from PATCH v1:
- 0-day build test for build dependency on libnvdimm
Changes suggested by - [Dan Williams]
- Split the driver into two parts virtio & pmem
- Move queuing of async block request to block layer
- Add "sync" parameter in nvdimm_flush function
- Use indirect call for nvdimm_flush
- Don’t move declarations to common global header e.g nd.h
- nvdimm_flush() return 0 or -EIO if it fails
- Teach nsio_rw_bytes() that the flush can fail
- Rename nvdimm_flush() to generic_nvdimm_flush()
- Use 'nd_region->provider_data' for long dereferencing
- Remove virtio_pmem_freeze/restore functions
- Remove BSD license text with SPDX license text
- Add might_sleep() in virtio_pmem_flush - [Luiz]
- Make spin_lock_irqsave() narrow
Changes from RFC v3
- Rebase to latest upstream - Luiz
- Call ndregion->flush in place of nvdimm_flush- Luiz
- kmalloc return check - Luiz
- virtqueue full handling - Stefan
- Don't map entire virtio_pmem_req to device - Stefan
- request leak, correct sizeof req- Stefan
- Move declaration to virtio_pmem.c
Changes from RFC v2:
- Add flush function in the nd_region in place of switching
on a flag - Dan & Stefan
- Add flush completion function with proper locking and wait
for host side flush completion - Stefan & Dan
- Keep userspace API in uapi header file - Stefan, MST
- Use LE fields & New device id - MST
- Indentation & spacing suggestions - MST & Eric
- Remove extra header files & add licensing - Stefan
Changes from RFC v1:
- Reuse existing 'pmem' code for registering persistent
memory and other operations instead of creating an entirely
new block driver.
- Use VIRTIO driver to register memory information with
nvdimm_bus and create region_type accordingly.
- Call VIRTIO flush from existing pmem driver.
Pankaj Gupta (5):
libnvdimm: nd_region flush callback support
virtio-pmem: Add virtio-pmem guest driver
libnvdimm: add nd_region buffered dax_dev flag
ext4: disable map_sync for virtio pmem
xfs: disable map_sync for virtio pmem
[1] https://lkml.org/lkml/2019/1/9/471
[2] https://lkml.org/lkml/2018/10/13/117
[3] https://www.spinics.net/lists/kvm/msg149761.html
[4] https://www.spinics.net/lists/kvm/msg153095.html
[5] https://lkml.org/lkml/2018/8/31/413
[6] https://marc.info/?l=linux-kernel&m=153572228719237&w=2
[7] https://marc.info/?l=qemu-devel&m=153555721901824&w=2
[8] https://lists.oasis-open.org/archives/virtio-dev/201903/msg00083.html
_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization
^ permalink raw reply
* [PATCH v4 1/5] ibnvdimm: nd_region flush callback support
From: Pankaj Gupta @ 2019-04-03 10:40 UTC (permalink / raw)
To: linux-nvdimm, linux-kernel, virtualization, kvm, linux-fsdevel,
linux-acpi, qemu-devel, linux-ext4, linux-xfs
Cc: pagupta, jack, mst, david, lcapitulino, adilger.kernel, zwisler,
aarcange, dave.jiang, darrick.wong, vishal.l.verma, willy, hch,
jmoyer, nilal, lenb, riel, stefanha, dan.j.williams, tytso,
xiaoguangrong.eric, cohuck, rjw, imammedo
In-Reply-To: <20190403104018.23947-1-pagupta@redhat.com>
This patch adds functionality to perform flush from guest
to host over VIRTIO. We are registering a callback based
on 'nd_region' type. virtio_pmem driver requires this special
flush function. For rest of the region types we are registering
existing flush function. Report error returned by host fsync
failure to userspace.
This also handles asynchronous flush requests from the block layer
by creating a child bio and chaining it with parent bio.
Signed-off-by: Pankaj Gupta <pagupta@redhat.com>
---
drivers/acpi/nfit/core.c | 4 ++--
drivers/nvdimm/claim.c | 6 ++++--
drivers/nvdimm/nd.h | 1 +
drivers/nvdimm/pmem.c | 14 ++++++++-----
drivers/nvdimm/region_devs.c | 38 ++++++++++++++++++++++++++++++++++--
include/linux/libnvdimm.h | 8 +++++++-
6 files changed, 59 insertions(+), 12 deletions(-)
diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c
index 5a389a4f4f65..567017a2190e 100644
--- a/drivers/acpi/nfit/core.c
+++ b/drivers/acpi/nfit/core.c
@@ -2434,7 +2434,7 @@ static void write_blk_ctl(struct nfit_blk *nfit_blk, unsigned int bw,
offset = to_interleave_offset(offset, mmio);
writeq(cmd, mmio->addr.base + offset);
- nvdimm_flush(nfit_blk->nd_region);
+ nvdimm_flush(nfit_blk->nd_region, NULL, false);
if (nfit_blk->dimm_flags & NFIT_BLK_DCR_LATCH)
readq(mmio->addr.base + offset);
@@ -2483,7 +2483,7 @@ static int acpi_nfit_blk_single_io(struct nfit_blk *nfit_blk,
}
if (rw)
- nvdimm_flush(nfit_blk->nd_region);
+ nvdimm_flush(nfit_blk->nd_region, NULL, false);
rc = read_blk_stat(nfit_blk, lane) ? -EIO : 0;
return rc;
diff --git a/drivers/nvdimm/claim.c b/drivers/nvdimm/claim.c
index fb667bf469c7..a1dfa066786b 100644
--- a/drivers/nvdimm/claim.c
+++ b/drivers/nvdimm/claim.c
@@ -263,7 +263,7 @@ static int nsio_rw_bytes(struct nd_namespace_common *ndns,
struct nd_namespace_io *nsio = to_nd_namespace_io(&ndns->dev);
unsigned int sz_align = ALIGN(size + (offset & (512 - 1)), 512);
sector_t sector = offset >> 9;
- int rc = 0;
+ int rc = 0, ret = 0;
if (unlikely(!size))
return 0;
@@ -301,7 +301,9 @@ static int nsio_rw_bytes(struct nd_namespace_common *ndns,
}
memcpy_flushcache(nsio->addr + offset, buf, size);
- nvdimm_flush(to_nd_region(ndns->dev.parent));
+ ret = nvdimm_flush(to_nd_region(ndns->dev.parent), NULL, false);
+ if (ret)
+ rc = ret;
return rc;
}
diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h
index a5ac3b240293..916cd6c5451a 100644
--- a/drivers/nvdimm/nd.h
+++ b/drivers/nvdimm/nd.h
@@ -159,6 +159,7 @@ struct nd_region {
struct badblocks bb;
struct nd_interleave_set *nd_set;
struct nd_percpu_lane __percpu *lane;
+ int (*flush)(struct nd_region *nd_region);
struct nd_mapping mapping[0];
};
diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c
index bc2f700feef8..5a5b3ea4d073 100644
--- a/drivers/nvdimm/pmem.c
+++ b/drivers/nvdimm/pmem.c
@@ -192,6 +192,7 @@ static blk_status_t pmem_do_bvec(struct pmem_device *pmem, struct page *page,
static blk_qc_t pmem_make_request(struct request_queue *q, struct bio *bio)
{
+ int ret = 0;
blk_status_t rc = 0;
bool do_acct;
unsigned long start;
@@ -201,7 +202,7 @@ static blk_qc_t pmem_make_request(struct request_queue *q, struct bio *bio)
struct nd_region *nd_region = to_region(pmem);
if (bio->bi_opf & REQ_PREFLUSH)
- nvdimm_flush(nd_region);
+ ret = nvdimm_flush(nd_region, bio, true);
do_acct = nd_iostat_start(bio, &start);
bio_for_each_segment(bvec, bio, iter) {
@@ -216,7 +217,10 @@ static blk_qc_t pmem_make_request(struct request_queue *q, struct bio *bio)
nd_iostat_end(bio, start);
if (bio->bi_opf & REQ_FUA)
- nvdimm_flush(nd_region);
+ ret = nvdimm_flush(nd_region, bio, true);
+
+ if (ret)
+ bio->bi_status = errno_to_blk_status(ret);
bio_endio(bio);
return BLK_QC_T_NONE;
@@ -463,13 +467,13 @@ static int pmem_attach_disk(struct device *dev,
disk->bb = &pmem->bb;
dax_dev = alloc_dax(pmem, disk->disk_name, &pmem_dax_ops);
+
if (!dax_dev) {
put_disk(disk);
return -ENOMEM;
}
dax_write_cache(dax_dev, nvdimm_has_cache(nd_region));
pmem->dax_dev = dax_dev;
-
gendev = disk_to_dev(disk);
gendev->groups = pmem_attribute_groups;
@@ -527,14 +531,14 @@ static int nd_pmem_remove(struct device *dev)
sysfs_put(pmem->bb_state);
pmem->bb_state = NULL;
}
- nvdimm_flush(to_nd_region(dev->parent));
+ nvdimm_flush(to_nd_region(dev->parent), NULL, false);
return 0;
}
static void nd_pmem_shutdown(struct device *dev)
{
- nvdimm_flush(to_nd_region(dev->parent));
+ nvdimm_flush(to_nd_region(dev->parent), NULL, false);
}
static void nd_pmem_notify(struct device *dev, enum nvdimm_event event)
diff --git a/drivers/nvdimm/region_devs.c b/drivers/nvdimm/region_devs.c
index b4ef7d9ff22e..fb1041ab32a6 100644
--- a/drivers/nvdimm/region_devs.c
+++ b/drivers/nvdimm/region_devs.c
@@ -295,7 +295,9 @@ static ssize_t deep_flush_store(struct device *dev, struct device_attribute *att
return rc;
if (!flush)
return -EINVAL;
- nvdimm_flush(nd_region);
+ rc = nvdimm_flush(nd_region, NULL, false);
+ if (rc)
+ return rc;
return len;
}
@@ -1085,6 +1087,11 @@ static struct nd_region *nd_region_create(struct nvdimm_bus *nvdimm_bus,
dev->of_node = ndr_desc->of_node;
nd_region->ndr_size = resource_size(ndr_desc->res);
nd_region->ndr_start = ndr_desc->res->start;
+ if (ndr_desc->flush)
+ nd_region->flush = ndr_desc->flush;
+ else
+ nd_region->flush = generic_nvdimm_flush;
+
nd_device_register(dev);
return nd_region;
@@ -1125,11 +1132,36 @@ struct nd_region *nvdimm_volatile_region_create(struct nvdimm_bus *nvdimm_bus,
}
EXPORT_SYMBOL_GPL(nvdimm_volatile_region_create);
+int nvdimm_flush(struct nd_region *nd_region, struct bio *bio, bool async)
+{
+ int rc = 0;
+
+ /* Create child bio for asynchronous flush and chain with
+ * parent bio. Otherwise directly call nd_region flush.
+ */
+ if (async && bio->bi_iter.bi_sector != -1) {
+
+ struct bio *child = bio_alloc(GFP_ATOMIC, 0);
+
+ if (!child)
+ return -ENOMEM;
+ bio_copy_dev(child, bio);
+ child->bi_opf = REQ_PREFLUSH;
+ child->bi_iter.bi_sector = -1;
+ bio_chain(child, bio);
+ submit_bio(child);
+ } else {
+ if (nd_region->flush(nd_region))
+ rc = -EIO;
+ }
+
+ return rc;
+}
/**
* nvdimm_flush - flush any posted write queues between the cpu and pmem media
* @nd_region: blk or interleaved pmem region
*/
-void nvdimm_flush(struct nd_region *nd_region)
+int generic_nvdimm_flush(struct nd_region *nd_region)
{
struct nd_region_data *ndrd = dev_get_drvdata(&nd_region->dev);
int i, idx;
@@ -1153,6 +1185,8 @@ void nvdimm_flush(struct nd_region *nd_region)
if (ndrd_get_flush_wpq(ndrd, i, 0))
writeq(1, ndrd_get_flush_wpq(ndrd, i, idx));
wmb();
+
+ return 0;
}
EXPORT_SYMBOL_GPL(nvdimm_flush);
diff --git a/include/linux/libnvdimm.h b/include/linux/libnvdimm.h
index feb342d026f2..d9d2ab8a6e64 100644
--- a/include/linux/libnvdimm.h
+++ b/include/linux/libnvdimm.h
@@ -65,6 +65,9 @@ enum {
*/
ND_REGION_PERSIST_MEMCTRL = 2,
+ /* Platform provides asynchronous flush mechanism */
+ ND_REGION_ASYNC = 3,
+
/* mark newly adjusted resources as requiring a label update */
DPA_RESOURCE_ADJUSTED = 1 << 0,
};
@@ -121,6 +124,7 @@ struct nd_mapping_desc {
int position;
};
+struct nd_region;
struct nd_region_desc {
struct resource *res;
struct nd_mapping_desc *mapping;
@@ -133,6 +137,7 @@ struct nd_region_desc {
int target_node;
unsigned long flags;
struct device_node *of_node;
+ int (*flush)(struct nd_region *nd_region);
};
struct device;
@@ -260,7 +265,8 @@ unsigned long nd_blk_memremap_flags(struct nd_blk_region *ndbr);
unsigned int nd_region_acquire_lane(struct nd_region *nd_region);
void nd_region_release_lane(struct nd_region *nd_region, unsigned int lane);
u64 nd_fletcher64(void *addr, size_t len, bool le);
-void nvdimm_flush(struct nd_region *nd_region);
+int nvdimm_flush(struct nd_region *nd_region, struct bio *bio, bool async);
+int generic_nvdimm_flush(struct nd_region *nd_region);
int nvdimm_has_flush(struct nd_region *nd_region);
int nvdimm_has_cache(struct nd_region *nd_region);
int nvdimm_in_overwrite(struct nvdimm *nvdimm);
--
2.20.1
^ permalink raw reply related
* [PATCH v4 2/5] virtio-pmem: Add virtio pmem driver
From: Pankaj Gupta @ 2019-04-03 10:40 UTC (permalink / raw)
To: linux-nvdimm, linux-kernel, virtualization, kvm, linux-fsdevel,
linux-acpi, qemu-devel, linux-ext4, linux-xfs
Cc: pagupta, jack, mst, david, lcapitulino, adilger.kernel, zwisler,
aarcange, dave.jiang, darrick.wong, vishal.l.verma, willy, hch,
jmoyer, nilal, lenb, riel, stefanha, dan.j.williams, tytso,
xiaoguangrong.eric, cohuck, rjw, imammedo
In-Reply-To: <20190403104018.23947-1-pagupta@redhat.com>
This patch adds virtio-pmem driver for KVM guest.
Guest reads the persistent memory range information from
Qemu over VIRTIO and registers it on nvdimm_bus. It also
creates a nd_region object with the persistent memory
range information so that existing 'nvdimm/pmem' driver
can reserve this into system memory map. This way
'virtio-pmem' driver uses existing functionality of pmem
driver to register persistent memory compatible for DAX
capable filesystems.
This also provides function to perform guest flush over
VIRTIO from 'pmem' driver when userspace performs flush
on DAX memory range.
Signed-off-by: Pankaj Gupta <pagupta@redhat.com>
---
drivers/nvdimm/virtio_pmem.c | 84 +++++++++++++++++++++
drivers/virtio/Kconfig | 10 +++
drivers/virtio/Makefile | 1 +
drivers/virtio/pmem.c | 125 +++++++++++++++++++++++++++++++
include/linux/virtio_pmem.h | 60 +++++++++++++++
include/uapi/linux/virtio_ids.h | 1 +
include/uapi/linux/virtio_pmem.h | 10 +++
7 files changed, 291 insertions(+)
create mode 100644 drivers/nvdimm/virtio_pmem.c
create mode 100644 drivers/virtio/pmem.c
create mode 100644 include/linux/virtio_pmem.h
create mode 100644 include/uapi/linux/virtio_pmem.h
diff --git a/drivers/nvdimm/virtio_pmem.c b/drivers/nvdimm/virtio_pmem.c
new file mode 100644
index 000000000000..2a1b1ba2c1ff
--- /dev/null
+++ b/drivers/nvdimm/virtio_pmem.c
@@ -0,0 +1,84 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * virtio_pmem.c: Virtio pmem Driver
+ *
+ * Discovers persistent memory range information
+ * from host and provides a virtio based flushing
+ * interface.
+ */
+#include <linux/virtio_pmem.h>
+#include "nd.h"
+
+ /* The interrupt handler */
+void host_ack(struct virtqueue *vq)
+{
+ unsigned int len;
+ unsigned long flags;
+ struct virtio_pmem_request *req, *req_buf;
+ struct virtio_pmem *vpmem = vq->vdev->priv;
+
+ spin_lock_irqsave(&vpmem->pmem_lock, flags);
+ while ((req = virtqueue_get_buf(vq, &len)) != NULL) {
+ req->done = true;
+ wake_up(&req->host_acked);
+
+ if (!list_empty(&vpmem->req_list)) {
+ req_buf = list_first_entry(&vpmem->req_list,
+ struct virtio_pmem_request, list);
+ list_del(&vpmem->req_list);
+ req_buf->wq_buf_avail = true;
+ wake_up(&req_buf->wq_buf);
+ }
+ }
+ spin_unlock_irqrestore(&vpmem->pmem_lock, flags);
+}
+EXPORT_SYMBOL_GPL(host_ack);
+
+ /* The request submission function */
+int virtio_pmem_flush(struct nd_region *nd_region)
+{
+ int err;
+ unsigned long flags;
+ struct scatterlist *sgs[2], sg, ret;
+ struct virtio_device *vdev = nd_region->provider_data;
+ struct virtio_pmem *vpmem = vdev->priv;
+ struct virtio_pmem_request *req;
+
+ might_sleep();
+ req = kmalloc(sizeof(*req), GFP_KERNEL);
+ if (!req)
+ return -ENOMEM;
+
+ req->done = req->wq_buf_avail = false;
+ strcpy(req->name, "FLUSH");
+ init_waitqueue_head(&req->host_acked);
+ init_waitqueue_head(&req->wq_buf);
+ sg_init_one(&sg, req->name, strlen(req->name));
+ sgs[0] = &sg;
+ sg_init_one(&ret, &req->ret, sizeof(req->ret));
+ sgs[1] = &ret;
+
+ spin_lock_irqsave(&vpmem->pmem_lock, flags);
+ err = virtqueue_add_sgs(vpmem->req_vq, sgs, 1, 1, req, GFP_ATOMIC);
+ if (err) {
+ dev_err(&vdev->dev, "failed to send command to virtio pmem device\n");
+
+ list_add_tail(&vpmem->req_list, &req->list);
+ spin_unlock_irqrestore(&vpmem->pmem_lock, flags);
+
+ /* When host has read buffer, this completes via host_ack */
+ wait_event(req->wq_buf, req->wq_buf_avail);
+ spin_lock_irqsave(&vpmem->pmem_lock, flags);
+ }
+ virtqueue_kick(vpmem->req_vq);
+ spin_unlock_irqrestore(&vpmem->pmem_lock, flags);
+
+ /* When host has read buffer, this completes via host_ack */
+ wait_event(req->host_acked, req->done);
+ err = req->ret;
+ kfree(req);
+
+ return err;
+};
+EXPORT_SYMBOL_GPL(virtio_pmem_flush);
+MODULE_LICENSE("GPL");
diff --git a/drivers/virtio/Kconfig b/drivers/virtio/Kconfig
index 35897649c24f..9f634a2ed638 100644
--- a/drivers/virtio/Kconfig
+++ b/drivers/virtio/Kconfig
@@ -42,6 +42,16 @@ config VIRTIO_PCI_LEGACY
If unsure, say Y.
+config VIRTIO_PMEM
+ tristate "Support for virtio pmem driver"
+ depends on VIRTIO
+ depends on LIBNVDIMM
+ help
+ This driver provides support for virtio based flushing interface
+ for persistent memory range.
+
+ If unsure, say M.
+
config VIRTIO_BALLOON
tristate "Virtio balloon driver"
depends on VIRTIO
diff --git a/drivers/virtio/Makefile b/drivers/virtio/Makefile
index 3a2b5c5dcf46..143ce91eabe9 100644
--- a/drivers/virtio/Makefile
+++ b/drivers/virtio/Makefile
@@ -6,3 +6,4 @@ virtio_pci-y := virtio_pci_modern.o virtio_pci_common.o
virtio_pci-$(CONFIG_VIRTIO_PCI_LEGACY) += virtio_pci_legacy.o
obj-$(CONFIG_VIRTIO_BALLOON) += virtio_balloon.o
obj-$(CONFIG_VIRTIO_INPUT) += virtio_input.o
+obj-$(CONFIG_VIRTIO_PMEM) += pmem.o ../nvdimm/virtio_pmem.o
diff --git a/drivers/virtio/pmem.c b/drivers/virtio/pmem.c
new file mode 100644
index 000000000000..52f74064f67e
--- /dev/null
+++ b/drivers/virtio/pmem.c
@@ -0,0 +1,125 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * virtio_pmem.c: Virtio pmem Driver
+ *
+ * Discovers persistent memory range information
+ * from host and registers the virtual pmem device
+ * with libnvdimm core.
+ */
+#include <linux/virtio_pmem.h>
+#include <../../drivers/nvdimm/nd.h>
+
+static struct virtio_device_id id_table[] = {
+ { VIRTIO_ID_PMEM, VIRTIO_DEV_ANY_ID },
+ { 0 },
+};
+
+ /* Initialize virt queue */
+static int init_vq(struct virtio_pmem *vpmem)
+{
+ struct virtqueue *vq;
+
+ /* single vq */
+ vpmem->req_vq = vq = virtio_find_single_vq(vpmem->vdev,
+ host_ack, "flush_queue");
+ if (IS_ERR(vq))
+ return PTR_ERR(vq);
+
+ spin_lock_init(&vpmem->pmem_lock);
+ INIT_LIST_HEAD(&vpmem->req_list);
+
+ return 0;
+};
+
+static int virtio_pmem_probe(struct virtio_device *vdev)
+{
+ int err = 0;
+ struct resource res;
+ struct virtio_pmem *vpmem;
+ struct nvdimm_bus *nvdimm_bus;
+ struct nd_region_desc ndr_desc;
+ int nid = dev_to_node(&vdev->dev);
+ struct nd_region *nd_region;
+
+ if (!vdev->config->get) {
+ dev_err(&vdev->dev, "%s failure: config disabled\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ vdev->priv = vpmem = devm_kzalloc(&vdev->dev, sizeof(*vpmem),
+ GFP_KERNEL);
+ if (!vpmem) {
+ err = -ENOMEM;
+ goto out_err;
+ }
+
+ vpmem->vdev = vdev;
+ err = init_vq(vpmem);
+ if (err)
+ goto out_err;
+
+ virtio_cread(vpmem->vdev, struct virtio_pmem_config,
+ start, &vpmem->start);
+ virtio_cread(vpmem->vdev, struct virtio_pmem_config,
+ size, &vpmem->size);
+
+ res.start = vpmem->start;
+ res.end = vpmem->start + vpmem->size-1;
+ vpmem->nd_desc.provider_name = "virtio-pmem";
+ vpmem->nd_desc.module = THIS_MODULE;
+
+ vpmem->nvdimm_bus = nvdimm_bus = nvdimm_bus_register(&vdev->dev,
+ &vpmem->nd_desc);
+ if (!nvdimm_bus)
+ goto out_vq;
+
+ dev_set_drvdata(&vdev->dev, nvdimm_bus);
+ memset(&ndr_desc, 0, sizeof(ndr_desc));
+
+ ndr_desc.res = &res;
+ ndr_desc.numa_node = nid;
+ ndr_desc.flush = virtio_pmem_flush;
+ set_bit(ND_REGION_PAGEMAP, &ndr_desc.flags);
+ set_bit(ND_REGION_ASYNC, &ndr_desc.flags);
+ nd_region = nvdimm_pmem_region_create(nvdimm_bus, &ndr_desc);
+ nd_region->provider_data = dev_to_virtio
+ (nd_region->dev.parent->parent);
+
+ if (!nd_region)
+ goto out_nd;
+
+ //virtio_device_ready(vdev);
+ return 0;
+out_nd:
+ err = -ENXIO;
+ nvdimm_bus_unregister(nvdimm_bus);
+out_vq:
+ vdev->config->del_vqs(vdev);
+out_err:
+ dev_err(&vdev->dev, "failed to register virtio pmem memory\n");
+ return err;
+}
+
+static void virtio_pmem_remove(struct virtio_device *vdev)
+{
+ struct virtio_pmem *vpmem = vdev->priv;
+ struct nvdimm_bus *nvdimm_bus = dev_get_drvdata(&vdev->dev);
+
+ nvdimm_bus_unregister(nvdimm_bus);
+ vdev->config->del_vqs(vdev);
+ kfree(vpmem);
+}
+
+static struct virtio_driver virtio_pmem_driver = {
+ .driver.name = KBUILD_MODNAME,
+ .driver.owner = THIS_MODULE,
+ .id_table = id_table,
+ .probe = virtio_pmem_probe,
+ .remove = virtio_pmem_remove,
+};
+
+module_virtio_driver(virtio_pmem_driver);
+MODULE_DEVICE_TABLE(virtio, id_table);
+MODULE_DESCRIPTION("Virtio pmem driver");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/virtio_pmem.h b/include/linux/virtio_pmem.h
new file mode 100644
index 000000000000..224f9d934be6
--- /dev/null
+++ b/include/linux/virtio_pmem.h
@@ -0,0 +1,60 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * virtio_pmem.h: virtio pmem Driver
+ *
+ * Discovers persistent memory range information
+ * from host and provides a virtio based flushing
+ * interface.
+ **/
+
+#ifndef _LINUX_VIRTIO_PMEM_H
+#define _LINUX_VIRTIO_PMEM_H
+
+#include <linux/virtio_ids.h>
+#include <linux/module.h>
+#include <linux/virtio_config.h>
+#include <uapi/linux/virtio_pmem.h>
+#include <linux/libnvdimm.h>
+#include <linux/spinlock.h>
+
+struct virtio_pmem_request {
+ /* Host return status corresponding to flush request */
+ int ret;
+
+ /* command name*/
+ char name[16];
+
+ /* Wait queue to process deferred work after ack from host */
+ wait_queue_head_t host_acked;
+ bool done;
+
+ /* Wait queue to process deferred work after virt queue buffer avail */
+ wait_queue_head_t wq_buf;
+ bool wq_buf_avail;
+ struct list_head list;
+};
+
+struct virtio_pmem {
+ struct virtio_device *vdev;
+
+ /* Virtio pmem request queue */
+ struct virtqueue *req_vq;
+
+ /* nvdimm bus registers virtio pmem device */
+ struct nvdimm_bus *nvdimm_bus;
+ struct nvdimm_bus_descriptor nd_desc;
+
+ /* List to store deferred work if virtqueue is full */
+ struct list_head req_list;
+
+ /* Synchronize virtqueue data */
+ spinlock_t pmem_lock;
+
+ /* Memory region information */
+ uint64_t start;
+ uint64_t size;
+};
+
+void host_ack(struct virtqueue *vq);
+int virtio_pmem_flush(struct nd_region *nd_region);
+#endif
diff --git a/include/uapi/linux/virtio_ids.h b/include/uapi/linux/virtio_ids.h
index 6d5c3b2d4f4d..346389565ac1 100644
--- a/include/uapi/linux/virtio_ids.h
+++ b/include/uapi/linux/virtio_ids.h
@@ -43,5 +43,6 @@
#define VIRTIO_ID_INPUT 18 /* virtio input */
#define VIRTIO_ID_VSOCK 19 /* virtio vsock transport */
#define VIRTIO_ID_CRYPTO 20 /* virtio crypto */
+#define VIRTIO_ID_PMEM 25 /* virtio pmem */
#endif /* _LINUX_VIRTIO_IDS_H */
diff --git a/include/uapi/linux/virtio_pmem.h b/include/uapi/linux/virtio_pmem.h
new file mode 100644
index 000000000000..fa3f7d52717a
--- /dev/null
+++ b/include/uapi/linux/virtio_pmem.h
@@ -0,0 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef _UAPI_LINUX_VIRTIO_PMEM_H
+#define _UAPI_LINUX_VIRTIO_PMEM_H
+
+struct virtio_pmem_config {
+ __le64 start;
+ __le64 size;
+};
+#endif
--
2.20.1
^ permalink raw reply related
* [PATCH v4 3/5] libnvdimm: add dax_dev sync flag
From: Pankaj Gupta @ 2019-04-03 10:40 UTC (permalink / raw)
To: linux-nvdimm, linux-kernel, virtualization, kvm, linux-fsdevel,
linux-acpi, qemu-devel, linux-ext4, linux-xfs
Cc: pagupta, jack, mst, david, lcapitulino, adilger.kernel, zwisler,
aarcange, dave.jiang, darrick.wong, vishal.l.verma, willy, hch,
jmoyer, nilal, lenb, riel, stefanha, dan.j.williams, tytso,
xiaoguangrong.eric, cohuck, rjw, imammedo
In-Reply-To: <20190403104018.23947-1-pagupta@redhat.com>
This patch adds 'DAXDEV_SYNC' flag which is set
for nd_region doing synchronous flush. This later
is used to disable MAP_SYNC functionality for
ext4 & xfs filesystem for devices don't support
synchronous flush.
Signed-off-by: Pankaj Gupta <pagupta@redhat.com>
---
drivers/dax/bus.c | 2 +-
drivers/dax/super.c | 13 ++++++++++++-
drivers/md/dm.c | 2 +-
drivers/nvdimm/pmem.c | 3 ++-
drivers/nvdimm/region_devs.c | 7 +++++++
include/linux/dax.h | 9 +++++++--
include/linux/libnvdimm.h | 1 +
7 files changed, 31 insertions(+), 6 deletions(-)
diff --git a/drivers/dax/bus.c b/drivers/dax/bus.c
index 2109cfe80219..431bf7d2a7f9 100644
--- a/drivers/dax/bus.c
+++ b/drivers/dax/bus.c
@@ -388,7 +388,7 @@ struct dev_dax *__devm_create_dev_dax(struct dax_region *dax_region, int id,
* No 'host' or dax_operations since there is no access to this
* device outside of mmap of the resulting character device.
*/
- dax_dev = alloc_dax(dev_dax, NULL, NULL);
+ dax_dev = alloc_dax(dev_dax, NULL, NULL, true);
if (!dax_dev)
goto err;
diff --git a/drivers/dax/super.c b/drivers/dax/super.c
index 0a339b85133e..bd6509308d05 100644
--- a/drivers/dax/super.c
+++ b/drivers/dax/super.c
@@ -186,6 +186,8 @@ enum dax_device_flags {
DAXDEV_ALIVE,
/* gate whether dax_flush() calls the low level flush routine */
DAXDEV_WRITE_CACHE,
+ /* flag to check if device supports synchronous flush */
+ DAXDEV_SYNC,
};
/**
@@ -354,6 +356,12 @@ bool dax_write_cache_enabled(struct dax_device *dax_dev)
}
EXPORT_SYMBOL_GPL(dax_write_cache_enabled);
+bool dax_synchronous(struct dax_device *dax_dev)
+{
+ return test_bit(DAXDEV_SYNC, &dax_dev->flags);
+}
+EXPORT_SYMBOL_GPL(dax_synchronous);
+
bool dax_alive(struct dax_device *dax_dev)
{
lockdep_assert_held(&dax_srcu);
@@ -511,7 +519,7 @@ static void dax_add_host(struct dax_device *dax_dev, const char *host)
}
struct dax_device *alloc_dax(void *private, const char *__host,
- const struct dax_operations *ops)
+ const struct dax_operations *ops, bool sync)
{
struct dax_device *dax_dev;
const char *host;
@@ -534,6 +542,9 @@ struct dax_device *alloc_dax(void *private, const char *__host,
dax_add_host(dax_dev, host);
dax_dev->ops = ops;
dax_dev->private = private;
+ if (sync)
+ set_bit(DAXDEV_SYNC, &dax_dev->flags);
+
return dax_dev;
err_dev:
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index 68d24056d0b1..534e12ca6329 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -1965,7 +1965,7 @@ static struct mapped_device *alloc_dev(int minor)
sprintf(md->disk->disk_name, "dm-%d", minor);
if (IS_ENABLED(CONFIG_DAX_DRIVER)) {
- dax_dev = alloc_dax(md, md->disk->disk_name, &dm_dax_ops);
+ dax_dev = alloc_dax(md, md->disk->disk_name, &dm_dax_ops, true);
if (!dax_dev)
goto bad;
}
diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c
index 5a5b3ea4d073..78f71ba0e7cf 100644
--- a/drivers/nvdimm/pmem.c
+++ b/drivers/nvdimm/pmem.c
@@ -466,7 +466,8 @@ static int pmem_attach_disk(struct device *dev,
nvdimm_badblocks_populate(nd_region, &pmem->bb, &bb_res);
disk->bb = &pmem->bb;
- dax_dev = alloc_dax(pmem, disk->disk_name, &pmem_dax_ops);
+ dax_dev = alloc_dax(pmem, disk->disk_name, &pmem_dax_ops,
+ is_nvdimm_sync(nd_region));
if (!dax_dev) {
put_disk(disk);
diff --git a/drivers/nvdimm/region_devs.c b/drivers/nvdimm/region_devs.c
index fb1041ab32a6..8c7aa047fe2b 100644
--- a/drivers/nvdimm/region_devs.c
+++ b/drivers/nvdimm/region_devs.c
@@ -1231,6 +1231,13 @@ int nvdimm_has_cache(struct nd_region *nd_region)
}
EXPORT_SYMBOL_GPL(nvdimm_has_cache);
+bool is_nvdimm_sync(struct nd_region *nd_region)
+{
+ return is_nd_pmem(&nd_region->dev) &&
+ !test_bit(ND_REGION_ASYNC, &nd_region->flags);
+}
+EXPORT_SYMBOL_GPL(is_nvdimm_sync);
+
struct conflict_context {
struct nd_region *nd_region;
resource_size_t start, size;
diff --git a/include/linux/dax.h b/include/linux/dax.h
index 0dd316a74a29..9bdd50d06ef6 100644
--- a/include/linux/dax.h
+++ b/include/linux/dax.h
@@ -32,18 +32,19 @@ extern struct attribute_group dax_attribute_group;
#if IS_ENABLED(CONFIG_DAX)
struct dax_device *dax_get_by_host(const char *host);
struct dax_device *alloc_dax(void *private, const char *host,
- const struct dax_operations *ops);
+ const struct dax_operations *ops, bool sync);
void put_dax(struct dax_device *dax_dev);
void kill_dax(struct dax_device *dax_dev);
void dax_write_cache(struct dax_device *dax_dev, bool wc);
bool dax_write_cache_enabled(struct dax_device *dax_dev);
+bool dax_synchronous(struct dax_device *dax_dev);
#else
static inline struct dax_device *dax_get_by_host(const char *host)
{
return NULL;
}
static inline struct dax_device *alloc_dax(void *private, const char *host,
- const struct dax_operations *ops)
+ const struct dax_operations *ops, bool sync)
{
/*
* Callers should check IS_ENABLED(CONFIG_DAX) to know if this
@@ -64,6 +65,10 @@ static inline bool dax_write_cache_enabled(struct dax_device *dax_dev)
{
return false;
}
+static inline bool dax_synchronous(struct dax_device *dax_dev)
+{
+ return false;
+}
#endif
struct writeback_control;
diff --git a/include/linux/libnvdimm.h b/include/linux/libnvdimm.h
index d9d2ab8a6e64..9a8aea370cbc 100644
--- a/include/linux/libnvdimm.h
+++ b/include/linux/libnvdimm.h
@@ -270,6 +270,7 @@ int generic_nvdimm_flush(struct nd_region *nd_region);
int nvdimm_has_flush(struct nd_region *nd_region);
int nvdimm_has_cache(struct nd_region *nd_region);
int nvdimm_in_overwrite(struct nvdimm *nvdimm);
+bool is_nvdimm_sync(struct nd_region *nd_region);
static inline int nvdimm_ctl(struct nvdimm *nvdimm, unsigned int cmd, void *buf,
unsigned int buf_len, int *cmd_rc)
--
2.20.1
^ permalink raw reply related
* [PATCH v4 4/5] ext4: disable map_sync for async flush
From: Pankaj Gupta @ 2019-04-03 10:40 UTC (permalink / raw)
To: linux-nvdimm, linux-kernel, virtualization, kvm, linux-fsdevel,
linux-acpi, qemu-devel, linux-ext4, linux-xfs
Cc: pagupta, jack, mst, david, lcapitulino, adilger.kernel, zwisler,
aarcange, dave.jiang, darrick.wong, vishal.l.verma, willy, hch,
jmoyer, nilal, lenb, riel, stefanha, dan.j.williams, tytso,
xiaoguangrong.eric, cohuck, rjw, imammedo
In-Reply-To: <20190403104018.23947-1-pagupta@redhat.com>
Virtio pmem provides asynchronous host page cache flush
mechanism. We don't support 'MAP_SYNC' with virtio pmem
and ext4.
Signed-off-by: Pankaj Gupta <pagupta@redhat.com>
---
fs/ext4/file.c | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/fs/ext4/file.c b/fs/ext4/file.c
index 69d65d49837b..86e4bf464320 100644
--- a/fs/ext4/file.c
+++ b/fs/ext4/file.c
@@ -360,8 +360,10 @@ static const struct vm_operations_struct ext4_file_vm_ops = {
static int ext4_file_mmap(struct file *file, struct vm_area_struct *vma)
{
struct inode *inode = file->f_mapping->host;
+ struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
+ struct dax_device *dax_dev = sbi->s_daxdev;
- if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb))))
+ if (unlikely(ext4_forced_shutdown(sbi)))
return -EIO;
/*
@@ -371,6 +373,13 @@ static int ext4_file_mmap(struct file *file, struct vm_area_struct *vma)
if (!IS_DAX(file_inode(file)) && (vma->vm_flags & VM_SYNC))
return -EOPNOTSUPP;
+ /* We don't support synchronous mappings with DAX files if
+ * dax_device is not synchronous.
+ */
+ if (IS_DAX(file_inode(file)) && !dax_synchronous(dax_dev)
+ && (vma->vm_flags & VM_SYNC))
+ return -EOPNOTSUPP;
+
file_accessed(file);
if (IS_DAX(file_inode(file))) {
vma->vm_ops = &ext4_dax_vm_ops;
--
2.20.1
^ permalink raw reply related
* [PATCH v4 5/5] xfs: disable map_sync for async flush
From: Pankaj Gupta @ 2019-04-03 10:40 UTC (permalink / raw)
To: linux-nvdimm, linux-kernel, virtualization, kvm, linux-fsdevel,
linux-acpi, qemu-devel, linux-ext4, linux-xfs
Cc: pagupta, jack, mst, david, lcapitulino, adilger.kernel, zwisler,
aarcange, dave.jiang, darrick.wong, vishal.l.verma, willy, hch,
jmoyer, nilal, lenb, riel, stefanha, dan.j.williams, tytso,
xiaoguangrong.eric, cohuck, rjw, imammedo
In-Reply-To: <20190403104018.23947-1-pagupta@redhat.com>
Virtio pmem provides asynchronous host page cache flush
mechanism. we don't support 'MAP_SYNC' with virtio pmem
and xfs.
Signed-off-by: Pankaj Gupta <pagupta@redhat.com>
---
fs/xfs/xfs_file.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c
index 1f2e2845eb76..dced2eb8c91a 100644
--- a/fs/xfs/xfs_file.c
+++ b/fs/xfs/xfs_file.c
@@ -1203,6 +1203,14 @@ xfs_file_mmap(
if (!IS_DAX(file_inode(filp)) && (vma->vm_flags & VM_SYNC))
return -EOPNOTSUPP;
+ /* We don't support synchronous mappings with DAX files if
+ * dax_device is not synchronous.
+ */
+ if (IS_DAX(file_inode(filp)) && !dax_synchronous(
+ xfs_find_daxdev_for_inode(file_inode(filp))) &&
+ (vma->vm_flags & VM_SYNC))
+ return -EOPNOTSUPP;
+
file_accessed(filp);
vma->vm_ops = &xfs_file_vm_ops;
if (IS_DAX(file_inode(filp)))
--
2.20.1
^ permalink raw reply related
* Re: [PATCH v4 4/5] ext4: disable map_sync for async flush
From: Jan Kara @ 2019-04-03 11:30 UTC (permalink / raw)
To: Pankaj Gupta
Cc: cohuck, jack, kvm, mst, david, qemu-devel, virtualization,
adilger.kernel, zwisler, aarcange, dave.jiang, linux-nvdimm,
vishal.l.verma, willy, hch, linux-acpi, jmoyer, linux-ext4, lenb,
riel, stefanha, dan.j.williams, lcapitulino, nilal, tytso,
xiaoguangrong.eric, darrick.wong, rjw, linux-kernel, linux-xfs,
linux-fsdevel, imammedo
In-Reply-To: <20190403104018.23947-5-pagupta@redhat.com>
On Wed 03-04-19 16:10:17, Pankaj Gupta wrote:
> Virtio pmem provides asynchronous host page cache flush
> mechanism. We don't support 'MAP_SYNC' with virtio pmem
> and ext4.
>
> Signed-off-by: Pankaj Gupta <pagupta@redhat.com>
The patch looks good to me. You can add:
Reviewed-by: Jan Kara <jack@suse.cz>
Honza
> ---
> fs/ext4/file.c | 11 ++++++++++-
> 1 file changed, 10 insertions(+), 1 deletion(-)
>
> diff --git a/fs/ext4/file.c b/fs/ext4/file.c
> index 69d65d49837b..86e4bf464320 100644
> --- a/fs/ext4/file.c
> +++ b/fs/ext4/file.c
> @@ -360,8 +360,10 @@ static const struct vm_operations_struct ext4_file_vm_ops = {
> static int ext4_file_mmap(struct file *file, struct vm_area_struct *vma)
> {
> struct inode *inode = file->f_mapping->host;
> + struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
> + struct dax_device *dax_dev = sbi->s_daxdev;
>
> - if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb))))
> + if (unlikely(ext4_forced_shutdown(sbi)))
> return -EIO;
>
> /*
> @@ -371,6 +373,13 @@ static int ext4_file_mmap(struct file *file, struct vm_area_struct *vma)
> if (!IS_DAX(file_inode(file)) && (vma->vm_flags & VM_SYNC))
> return -EOPNOTSUPP;
>
> + /* We don't support synchronous mappings with DAX files if
> + * dax_device is not synchronous.
> + */
> + if (IS_DAX(file_inode(file)) && !dax_synchronous(dax_dev)
> + && (vma->vm_flags & VM_SYNC))
> + return -EOPNOTSUPP;
> +
> file_accessed(file);
> if (IS_DAX(file_inode(file))) {
> vma->vm_ops = &ext4_dax_vm_ops;
> --
> 2.20.1
>
--
Jan Kara <jack@suse.com>
SUSE Labs, CR
^ permalink raw reply
* Re: [Qemu-devel] [PATCH v4 2/5] virtio-pmem: Add virtio pmem driver
From: Yuval Shaia @ 2019-04-03 11:43 UTC (permalink / raw)
To: Pankaj Gupta
Cc: cohuck, jack, kvm, mst, david, qemu-devel, virtualization,
adilger.kernel, zwisler, aarcange, dave.jiang, linux-nvdimm,
vishal.l.verma, willy, hch, linux-acpi, jmoyer, linux-ext4, lenb,
riel, stefanha, dan.j.williams, lcapitulino, nilal, tytso,
xiaoguangrong.eric, darrick.wong, rjw, linux-kernel, linux-xfs,
linux-fsdevel, imammedo
In-Reply-To: <20190403104018.23947-3-pagupta@redhat.com>
On Wed, Apr 03, 2019 at 04:10:15PM +0530, Pankaj Gupta wrote:
> This patch adds virtio-pmem driver for KVM guest.
>
> Guest reads the persistent memory range information from
> Qemu over VIRTIO and registers it on nvdimm_bus. It also
> creates a nd_region object with the persistent memory
> range information so that existing 'nvdimm/pmem' driver
> can reserve this into system memory map. This way
> 'virtio-pmem' driver uses existing functionality of pmem
> driver to register persistent memory compatible for DAX
> capable filesystems.
>
> This also provides function to perform guest flush over
> VIRTIO from 'pmem' driver when userspace performs flush
> on DAX memory range.
>
> Signed-off-by: Pankaj Gupta <pagupta@redhat.com>
> ---
> drivers/nvdimm/virtio_pmem.c | 84 +++++++++++++++++++++
> drivers/virtio/Kconfig | 10 +++
> drivers/virtio/Makefile | 1 +
> drivers/virtio/pmem.c | 125 +++++++++++++++++++++++++++++++
> include/linux/virtio_pmem.h | 60 +++++++++++++++
> include/uapi/linux/virtio_ids.h | 1 +
> include/uapi/linux/virtio_pmem.h | 10 +++
> 7 files changed, 291 insertions(+)
> create mode 100644 drivers/nvdimm/virtio_pmem.c
> create mode 100644 drivers/virtio/pmem.c
> create mode 100644 include/linux/virtio_pmem.h
> create mode 100644 include/uapi/linux/virtio_pmem.h
>
> diff --git a/drivers/nvdimm/virtio_pmem.c b/drivers/nvdimm/virtio_pmem.c
> new file mode 100644
> index 000000000000..2a1b1ba2c1ff
> --- /dev/null
> +++ b/drivers/nvdimm/virtio_pmem.c
> @@ -0,0 +1,84 @@
> +// SPDX-License-Identifier: GPL-2.0
Is this comment stile (//) acceptable?
> +/*
> + * virtio_pmem.c: Virtio pmem Driver
> + *
> + * Discovers persistent memory range information
> + * from host and provides a virtio based flushing
> + * interface.
> + */
> +#include <linux/virtio_pmem.h>
> +#include "nd.h"
> +
> + /* The interrupt handler */
> +void host_ack(struct virtqueue *vq)
> +{
> + unsigned int len;
> + unsigned long flags;
> + struct virtio_pmem_request *req, *req_buf;
> + struct virtio_pmem *vpmem = vq->vdev->priv;
> +
> + spin_lock_irqsave(&vpmem->pmem_lock, flags);
> + while ((req = virtqueue_get_buf(vq, &len)) != NULL) {
> + req->done = true;
> + wake_up(&req->host_acked);
> +
> + if (!list_empty(&vpmem->req_list)) {
> + req_buf = list_first_entry(&vpmem->req_list,
> + struct virtio_pmem_request, list);
> + list_del(&vpmem->req_list);
> + req_buf->wq_buf_avail = true;
> + wake_up(&req_buf->wq_buf);
> + }
> + }
> + spin_unlock_irqrestore(&vpmem->pmem_lock, flags);
> +}
> +EXPORT_SYMBOL_GPL(host_ack);
> +
> + /* The request submission function */
> +int virtio_pmem_flush(struct nd_region *nd_region)
> +{
> + int err;
> + unsigned long flags;
> + struct scatterlist *sgs[2], sg, ret;
> + struct virtio_device *vdev = nd_region->provider_data;
> + struct virtio_pmem *vpmem = vdev->priv;
> + struct virtio_pmem_request *req;
> +
> + might_sleep();
[1]
> + req = kmalloc(sizeof(*req), GFP_KERNEL);
> + if (!req)
> + return -ENOMEM;
> +
> + req->done = req->wq_buf_avail = false;
> + strcpy(req->name, "FLUSH");
> + init_waitqueue_head(&req->host_acked);
> + init_waitqueue_head(&req->wq_buf);
> + sg_init_one(&sg, req->name, strlen(req->name));
> + sgs[0] = &sg;
> + sg_init_one(&ret, &req->ret, sizeof(req->ret));
> + sgs[1] = &ret;
> +
> + spin_lock_irqsave(&vpmem->pmem_lock, flags);
> + err = virtqueue_add_sgs(vpmem->req_vq, sgs, 1, 1, req, GFP_ATOMIC);
Is it okay to use GFP_ATOMIC in a might-sleep ([1]) function?
> + if (err) {
> + dev_err(&vdev->dev, "failed to send command to virtio pmem device\n");
> +
> + list_add_tail(&vpmem->req_list, &req->list);
> + spin_unlock_irqrestore(&vpmem->pmem_lock, flags);
> +
> + /* When host has read buffer, this completes via host_ack */
> + wait_event(req->wq_buf, req->wq_buf_avail);
> + spin_lock_irqsave(&vpmem->pmem_lock, flags);
> + }
> + virtqueue_kick(vpmem->req_vq);
You probably want to check return value here.
> + spin_unlock_irqrestore(&vpmem->pmem_lock, flags);
> +
> + /* When host has read buffer, this completes via host_ack */
> + wait_event(req->host_acked, req->done);
> + err = req->ret;
> + kfree(req);
> +
> + return err;
> +};
> +EXPORT_SYMBOL_GPL(virtio_pmem_flush);
> +MODULE_LICENSE("GPL");
> diff --git a/drivers/virtio/Kconfig b/drivers/virtio/Kconfig
> index 35897649c24f..9f634a2ed638 100644
> --- a/drivers/virtio/Kconfig
> +++ b/drivers/virtio/Kconfig
> @@ -42,6 +42,16 @@ config VIRTIO_PCI_LEGACY
>
> If unsure, say Y.
>
> +config VIRTIO_PMEM
> + tristate "Support for virtio pmem driver"
> + depends on VIRTIO
> + depends on LIBNVDIMM
> + help
> + This driver provides support for virtio based flushing interface
> + for persistent memory range.
> +
> + If unsure, say M.
> +
> config VIRTIO_BALLOON
> tristate "Virtio balloon driver"
> depends on VIRTIO
> diff --git a/drivers/virtio/Makefile b/drivers/virtio/Makefile
> index 3a2b5c5dcf46..143ce91eabe9 100644
> --- a/drivers/virtio/Makefile
> +++ b/drivers/virtio/Makefile
> @@ -6,3 +6,4 @@ virtio_pci-y := virtio_pci_modern.o virtio_pci_common.o
> virtio_pci-$(CONFIG_VIRTIO_PCI_LEGACY) += virtio_pci_legacy.o
> obj-$(CONFIG_VIRTIO_BALLOON) += virtio_balloon.o
> obj-$(CONFIG_VIRTIO_INPUT) += virtio_input.o
> +obj-$(CONFIG_VIRTIO_PMEM) += pmem.o ../nvdimm/virtio_pmem.o
> diff --git a/drivers/virtio/pmem.c b/drivers/virtio/pmem.c
> new file mode 100644
> index 000000000000..52f74064f67e
> --- /dev/null
> +++ b/drivers/virtio/pmem.c
> @@ -0,0 +1,125 @@
> +// SPDX-License-Identifier: GPL-2.0
Ditto
> +/*
> + * virtio_pmem.c: Virtio pmem Driver
> + *
> + * Discovers persistent memory range information
> + * from host and registers the virtual pmem device
> + * with libnvdimm core.
> + */
> +#include <linux/virtio_pmem.h>
> +#include <../../drivers/nvdimm/nd.h>
Should this file be moved to include/ directory?
> +
> +static struct virtio_device_id id_table[] = {
> + { VIRTIO_ID_PMEM, VIRTIO_DEV_ANY_ID },
> + { 0 },
> +};
> +
> + /* Initialize virt queue */
> +static int init_vq(struct virtio_pmem *vpmem)
> +{
> + struct virtqueue *vq;
> +
> + /* single vq */
> + vpmem->req_vq = vq = virtio_find_single_vq(vpmem->vdev,
> + host_ack, "flush_queue");
> + if (IS_ERR(vq))
> + return PTR_ERR(vq);
> +
> + spin_lock_init(&vpmem->pmem_lock);
> + INIT_LIST_HEAD(&vpmem->req_list);
> +
> + return 0;
> +};
> +
> +static int virtio_pmem_probe(struct virtio_device *vdev)
> +{
> + int err = 0;
> + struct resource res;
> + struct virtio_pmem *vpmem;
> + struct nvdimm_bus *nvdimm_bus;
> + struct nd_region_desc ndr_desc;
> + int nid = dev_to_node(&vdev->dev);
> + struct nd_region *nd_region;
> +
> + if (!vdev->config->get) {
> + dev_err(&vdev->dev, "%s failure: config disabled\n",
> + __func__);
> + return -EINVAL;
> + }
> +
> + vdev->priv = vpmem = devm_kzalloc(&vdev->dev, sizeof(*vpmem),
> + GFP_KERNEL);
Suggesting to indent it right so it will be under &vdev
> + if (!vpmem) {
> + err = -ENOMEM;
> + goto out_err;
> + }
> +
> + vpmem->vdev = vdev;
> + err = init_vq(vpmem);
> + if (err)
> + goto out_err;
No need to free vpmem here?
> +
> + virtio_cread(vpmem->vdev, struct virtio_pmem_config,
> + start, &vpmem->start);
> + virtio_cread(vpmem->vdev, struct virtio_pmem_config,
> + size, &vpmem->size);
> +
> + res.start = vpmem->start;
> + res.end = vpmem->start + vpmem->size-1;
> + vpmem->nd_desc.provider_name = "virtio-pmem";
> + vpmem->nd_desc.module = THIS_MODULE;
> +
> + vpmem->nvdimm_bus = nvdimm_bus = nvdimm_bus_register(&vdev->dev,
> + &vpmem->nd_desc);
> + if (!nvdimm_bus)
> + goto out_vq;
Ditto (i'm probably missing something here)
> +
> + dev_set_drvdata(&vdev->dev, nvdimm_bus);
> + memset(&ndr_desc, 0, sizeof(ndr_desc));
Any reason not to use compiler initialization?
i.e.
struct nd_region_desc ndr_desc = {};
> +
> + ndr_desc.res = &res;
> + ndr_desc.numa_node = nid;
> + ndr_desc.flush = virtio_pmem_flush;
> + set_bit(ND_REGION_PAGEMAP, &ndr_desc.flags);
> + set_bit(ND_REGION_ASYNC, &ndr_desc.flags);
> + nd_region = nvdimm_pmem_region_create(nvdimm_bus, &ndr_desc);
> + nd_region->provider_data = dev_to_virtio
> + (nd_region->dev.parent->parent);
> +
> + if (!nd_region)
> + goto out_nd;
> +
> + //virtio_device_ready(vdev);
Left over
> + return 0;
> +out_nd:
> + err = -ENXIO;
> + nvdimm_bus_unregister(nvdimm_bus);
> +out_vq:
> + vdev->config->del_vqs(vdev);
> +out_err:
> + dev_err(&vdev->dev, "failed to register virtio pmem memory\n");
> + return err;
> +}
> +
> +static void virtio_pmem_remove(struct virtio_device *vdev)
> +{
> + struct virtio_pmem *vpmem = vdev->priv;
> + struct nvdimm_bus *nvdimm_bus = dev_get_drvdata(&vdev->dev);
> +
> + nvdimm_bus_unregister(nvdimm_bus);
> + vdev->config->del_vqs(vdev);
I think you should also call vdev->config->reset
> + kfree(vpmem);
> +}
> +
> +static struct virtio_driver virtio_pmem_driver = {
> + .driver.name = KBUILD_MODNAME,
> + .driver.owner = THIS_MODULE,
> + .id_table = id_table,
> + .probe = virtio_pmem_probe,
> + .remove = virtio_pmem_remove,
> +};
> +
> +module_virtio_driver(virtio_pmem_driver);
> +MODULE_DEVICE_TABLE(virtio, id_table);
> +MODULE_DESCRIPTION("Virtio pmem driver");
> +MODULE_LICENSE("GPL");
> diff --git a/include/linux/virtio_pmem.h b/include/linux/virtio_pmem.h
> new file mode 100644
> index 000000000000..224f9d934be6
> --- /dev/null
> +++ b/include/linux/virtio_pmem.h
> @@ -0,0 +1,60 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * virtio_pmem.h: virtio pmem Driver
> + *
> + * Discovers persistent memory range information
> + * from host and provides a virtio based flushing
> + * interface.
> + **/
> +
> +#ifndef _LINUX_VIRTIO_PMEM_H
> +#define _LINUX_VIRTIO_PMEM_H
> +
> +#include <linux/virtio_ids.h>
> +#include <linux/module.h>
> +#include <linux/virtio_config.h>
> +#include <uapi/linux/virtio_pmem.h>
> +#include <linux/libnvdimm.h>
> +#include <linux/spinlock.h>
> +
> +struct virtio_pmem_request {
> + /* Host return status corresponding to flush request */
> + int ret;
> +
> + /* command name*/
> + char name[16];
> +
> + /* Wait queue to process deferred work after ack from host */
> + wait_queue_head_t host_acked;
> + bool done;
> +
> + /* Wait queue to process deferred work after virt queue buffer avail */
> + wait_queue_head_t wq_buf;
> + bool wq_buf_avail;
> + struct list_head list;
> +};
> +
> +struct virtio_pmem {
> + struct virtio_device *vdev;
> +
> + /* Virtio pmem request queue */
> + struct virtqueue *req_vq;
> +
> + /* nvdimm bus registers virtio pmem device */
> + struct nvdimm_bus *nvdimm_bus;
> + struct nvdimm_bus_descriptor nd_desc;
> +
> + /* List to store deferred work if virtqueue is full */
> + struct list_head req_list;
> +
> + /* Synchronize virtqueue data */
> + spinlock_t pmem_lock;
> +
> + /* Memory region information */
> + uint64_t start;
> + uint64_t size;
> +};
> +
> +void host_ack(struct virtqueue *vq);
> +int virtio_pmem_flush(struct nd_region *nd_region);
> +#endif
> diff --git a/include/uapi/linux/virtio_ids.h b/include/uapi/linux/virtio_ids.h
> index 6d5c3b2d4f4d..346389565ac1 100644
> --- a/include/uapi/linux/virtio_ids.h
> +++ b/include/uapi/linux/virtio_ids.h
> @@ -43,5 +43,6 @@
> #define VIRTIO_ID_INPUT 18 /* virtio input */
> #define VIRTIO_ID_VSOCK 19 /* virtio vsock transport */
> #define VIRTIO_ID_CRYPTO 20 /* virtio crypto */
> +#define VIRTIO_ID_PMEM 25 /* virtio pmem */
Any reason for the jump here? are 21 to 24 already taken or you just
want to be on the safe side?
>
> #endif /* _LINUX_VIRTIO_IDS_H */
> diff --git a/include/uapi/linux/virtio_pmem.h b/include/uapi/linux/virtio_pmem.h
> new file mode 100644
> index 000000000000..fa3f7d52717a
> --- /dev/null
> +++ b/include/uapi/linux/virtio_pmem.h
> @@ -0,0 +1,10 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +
> +#ifndef _UAPI_LINUX_VIRTIO_PMEM_H
> +#define _UAPI_LINUX_VIRTIO_PMEM_H
> +
> +struct virtio_pmem_config {
> + __le64 start;
> + __le64 size;
> +};
> +#endif
> --
> 2.20.1
>
>
^ permalink raw reply
* Re: [Qemu-devel] [PATCH v4 2/5] virtio-pmem: Add virtio pmem driver
From: Pankaj Gupta @ 2019-04-03 12:40 UTC (permalink / raw)
To: Yuval Shaia
Cc: jack, kvm, mst, david, qemu-devel, virtualization, adilger kernel,
zwisler, aarcange, dave jiang, linux-nvdimm, vishal l verma,
willy, hch, linux-acpi, jmoyer, linux-ext4, lenb, riel, stefanha,
dan j williams, lcapitulino, nilal, tytso, xiaoguangrong eric,
cohuck, rjw, linux-kernel, linux-xfs, linux-fsdevel, imammedo,
darrick wong
In-Reply-To: <20190403114328.GA17696@lap1>
> Subject: Re: [Qemu-devel] [PATCH v4 2/5] virtio-pmem: Add virtio pmem driver
>
> On Wed, Apr 03, 2019 at 04:10:15PM +0530, Pankaj Gupta wrote:
> > This patch adds virtio-pmem driver for KVM guest.
> >
> > Guest reads the persistent memory range information from
> > Qemu over VIRTIO and registers it on nvdimm_bus. It also
> > creates a nd_region object with the persistent memory
> > range information so that existing 'nvdimm/pmem' driver
> > can reserve this into system memory map. This way
> > 'virtio-pmem' driver uses existing functionality of pmem
> > driver to register persistent memory compatible for DAX
> > capable filesystems.
> >
> > This also provides function to perform guest flush over
> > VIRTIO from 'pmem' driver when userspace performs flush
> > on DAX memory range.
> >
> > Signed-off-by: Pankaj Gupta <pagupta@redhat.com>
> > ---
> > drivers/nvdimm/virtio_pmem.c | 84 +++++++++++++++++++++
> > drivers/virtio/Kconfig | 10 +++
> > drivers/virtio/Makefile | 1 +
> > drivers/virtio/pmem.c | 125 +++++++++++++++++++++++++++++++
> > include/linux/virtio_pmem.h | 60 +++++++++++++++
> > include/uapi/linux/virtio_ids.h | 1 +
> > include/uapi/linux/virtio_pmem.h | 10 +++
> > 7 files changed, 291 insertions(+)
> > create mode 100644 drivers/nvdimm/virtio_pmem.c
> > create mode 100644 drivers/virtio/pmem.c
> > create mode 100644 include/linux/virtio_pmem.h
> > create mode 100644 include/uapi/linux/virtio_pmem.h
> >
> > diff --git a/drivers/nvdimm/virtio_pmem.c b/drivers/nvdimm/virtio_pmem.c
> > new file mode 100644
> > index 000000000000..2a1b1ba2c1ff
> > --- /dev/null
> > +++ b/drivers/nvdimm/virtio_pmem.c
> > @@ -0,0 +1,84 @@
> > +// SPDX-License-Identifier: GPL-2.0
>
> Is this comment stile (//) acceptable?
In existing code, i can see same comment
pattern for license at some places.
>
> > +/*
> > + * virtio_pmem.c: Virtio pmem Driver
> > + *
> > + * Discovers persistent memory range information
> > + * from host and provides a virtio based flushing
> > + * interface.
> > + */
> > +#include <linux/virtio_pmem.h>
> > +#include "nd.h"
> > +
> > + /* The interrupt handler */
> > +void host_ack(struct virtqueue *vq)
> > +{
> > + unsigned int len;
> > + unsigned long flags;
> > + struct virtio_pmem_request *req, *req_buf;
> > + struct virtio_pmem *vpmem = vq->vdev->priv;
> > +
> > + spin_lock_irqsave(&vpmem->pmem_lock, flags);
> > + while ((req = virtqueue_get_buf(vq, &len)) != NULL) {
> > + req->done = true;
> > + wake_up(&req->host_acked);
> > +
> > + if (!list_empty(&vpmem->req_list)) {
> > + req_buf = list_first_entry(&vpmem->req_list,
> > + struct virtio_pmem_request, list);
> > + list_del(&vpmem->req_list);
> > + req_buf->wq_buf_avail = true;
> > + wake_up(&req_buf->wq_buf);
> > + }
> > + }
> > + spin_unlock_irqrestore(&vpmem->pmem_lock, flags);
> > +}
> > +EXPORT_SYMBOL_GPL(host_ack);
> > +
> > + /* The request submission function */
> > +int virtio_pmem_flush(struct nd_region *nd_region)
> > +{
> > + int err;
> > + unsigned long flags;
> > + struct scatterlist *sgs[2], sg, ret;
> > + struct virtio_device *vdev = nd_region->provider_data;
> > + struct virtio_pmem *vpmem = vdev->priv;
> > + struct virtio_pmem_request *req;
> > +
> > + might_sleep();
>
> [1]
>
> > + req = kmalloc(sizeof(*req), GFP_KERNEL);
> > + if (!req)
> > + return -ENOMEM;
> > +
> > + req->done = req->wq_buf_avail = false;
> > + strcpy(req->name, "FLUSH");
> > + init_waitqueue_head(&req->host_acked);
> > + init_waitqueue_head(&req->wq_buf);
> > + sg_init_one(&sg, req->name, strlen(req->name));
> > + sgs[0] = &sg;
> > + sg_init_one(&ret, &req->ret, sizeof(req->ret));
> > + sgs[1] = &ret;
> > +
> > + spin_lock_irqsave(&vpmem->pmem_lock, flags);
> > + err = virtqueue_add_sgs(vpmem->req_vq, sgs, 1, 1, req, GFP_ATOMIC);
>
> Is it okay to use GFP_ATOMIC in a might-sleep ([1]) function?
might sleep will give us a warning if we try to sleep from non-sleepable
context.
We are doing it other way, i.e might_sleep is not inside GFP_ATOMIC.
>
> > + if (err) {
> > + dev_err(&vdev->dev, "failed to send command to virtio pmem device\n");
> > +
> > + list_add_tail(&vpmem->req_list, &req->list);
> > + spin_unlock_irqrestore(&vpmem->pmem_lock, flags);
> > +
> > + /* When host has read buffer, this completes via host_ack */
> > + wait_event(req->wq_buf, req->wq_buf_avail);
> > + spin_lock_irqsave(&vpmem->pmem_lock, flags);
> > + }
> > + virtqueue_kick(vpmem->req_vq);
>
> You probably want to check return value here.
Don't think it will matter in this case?
>
> > + spin_unlock_irqrestore(&vpmem->pmem_lock, flags);
> > +
> > + /* When host has read buffer, this completes via host_ack */
> > + wait_event(req->host_acked, req->done);
> > + err = req->ret;
> > + kfree(req);
> > +
> > + return err;
> > +};
> > +EXPORT_SYMBOL_GPL(virtio_pmem_flush);
> > +MODULE_LICENSE("GPL");
> > diff --git a/drivers/virtio/Kconfig b/drivers/virtio/Kconfig
> > index 35897649c24f..9f634a2ed638 100644
> > --- a/drivers/virtio/Kconfig
> > +++ b/drivers/virtio/Kconfig
> > @@ -42,6 +42,16 @@ config VIRTIO_PCI_LEGACY
> >
> > If unsure, say Y.
> >
> > +config VIRTIO_PMEM
> > + tristate "Support for virtio pmem driver"
> > + depends on VIRTIO
> > + depends on LIBNVDIMM
> > + help
> > + This driver provides support for virtio based flushing interface
> > + for persistent memory range.
> > +
> > + If unsure, say M.
> > +
> > config VIRTIO_BALLOON
> > tristate "Virtio balloon driver"
> > depends on VIRTIO
> > diff --git a/drivers/virtio/Makefile b/drivers/virtio/Makefile
> > index 3a2b5c5dcf46..143ce91eabe9 100644
> > --- a/drivers/virtio/Makefile
> > +++ b/drivers/virtio/Makefile
> > @@ -6,3 +6,4 @@ virtio_pci-y := virtio_pci_modern.o virtio_pci_common.o
> > virtio_pci-$(CONFIG_VIRTIO_PCI_LEGACY) += virtio_pci_legacy.o
> > obj-$(CONFIG_VIRTIO_BALLOON) += virtio_balloon.o
> > obj-$(CONFIG_VIRTIO_INPUT) += virtio_input.o
> > +obj-$(CONFIG_VIRTIO_PMEM) += pmem.o ../nvdimm/virtio_pmem.o
> > diff --git a/drivers/virtio/pmem.c b/drivers/virtio/pmem.c
> > new file mode 100644
> > index 000000000000..52f74064f67e
> > --- /dev/null
> > +++ b/drivers/virtio/pmem.c
> > @@ -0,0 +1,125 @@
> > +// SPDX-License-Identifier: GPL-2.0
>
> Ditto
>
> > +/*
> > + * virtio_pmem.c: Virtio pmem Driver
> > + *
> > + * Discovers persistent memory range information
> > + * from host and registers the virtual pmem device
> > + * with libnvdimm core.
> > + */
> > +#include <linux/virtio_pmem.h>
> > +#include <../../drivers/nvdimm/nd.h>
>
> Should this file be moved to include/ directory?
We are not touching the directory structure of nd & nd_pmem
kernel driver.
>
> > +
> > +static struct virtio_device_id id_table[] = {
> > + { VIRTIO_ID_PMEM, VIRTIO_DEV_ANY_ID },
> > + { 0 },
> > +};
> > +
> > + /* Initialize virt queue */
> > +static int init_vq(struct virtio_pmem *vpmem)
> > +{
> > + struct virtqueue *vq;
> > +
> > + /* single vq */
> > + vpmem->req_vq = vq = virtio_find_single_vq(vpmem->vdev,
> > + host_ack, "flush_queue");
> > + if (IS_ERR(vq))
> > + return PTR_ERR(vq);
> > +
> > + spin_lock_init(&vpmem->pmem_lock);
> > + INIT_LIST_HEAD(&vpmem->req_list);
> > +
> > + return 0;
> > +};
> > +
> > +static int virtio_pmem_probe(struct virtio_device *vdev)
> > +{
> > + int err = 0;
> > + struct resource res;
> > + struct virtio_pmem *vpmem;
> > + struct nvdimm_bus *nvdimm_bus;
> > + struct nd_region_desc ndr_desc;
> > + int nid = dev_to_node(&vdev->dev);
> > + struct nd_region *nd_region;
> > +
> > + if (!vdev->config->get) {
> > + dev_err(&vdev->dev, "%s failure: config disabled\n",
> > + __func__);
> > + return -EINVAL;
> > + }
> > +
> > + vdev->priv = vpmem = devm_kzalloc(&vdev->dev, sizeof(*vpmem),
> > + GFP_KERNEL);
>
> Suggesting to indent it right so it will be under &vdev
o.k
>
> > + if (!vpmem) {
> > + err = -ENOMEM;
> > + goto out_err;
> > + }
> > +
> > + vpmem->vdev = vdev;
> > + err = init_vq(vpmem);
> > + if (err)
> > + goto out_err;
>
> No need to free vpmem here?
No. devm_kzalloc will take care of it.
>
> > +
> > + virtio_cread(vpmem->vdev, struct virtio_pmem_config,
> > + start, &vpmem->start);
> > + virtio_cread(vpmem->vdev, struct virtio_pmem_config,
> > + size, &vpmem->size);
> > +
> > + res.start = vpmem->start;
> > + res.end = vpmem->start + vpmem->size-1;
> > + vpmem->nd_desc.provider_name = "virtio-pmem";
> > + vpmem->nd_desc.module = THIS_MODULE;
> > +
> > + vpmem->nvdimm_bus = nvdimm_bus = nvdimm_bus_register(&vdev->dev,
> > + &vpmem->nd_desc);
> > + if (!nvdimm_bus)
> > + goto out_vq;
>
> Ditto (i'm probably missing something here)
>
> > +
> > + dev_set_drvdata(&vdev->dev, nvdimm_bus);
> > + memset(&ndr_desc, 0, sizeof(ndr_desc));
>
> Any reason not to use compiler initialization?
> i.e.
> struct nd_region_desc ndr_desc = {};
will change.
>
> > +
> > + ndr_desc.res = &res;
> > + ndr_desc.numa_node = nid;
> > + ndr_desc.flush = virtio_pmem_flush;
> > + set_bit(ND_REGION_PAGEMAP, &ndr_desc.flags);
> > + set_bit(ND_REGION_ASYNC, &ndr_desc.flags);
> > + nd_region = nvdimm_pmem_region_create(nvdimm_bus, &ndr_desc);
> > + nd_region->provider_data = dev_to_virtio
> > + (nd_region->dev.parent->parent);
> > +
> > + if (!nd_region)
> > + goto out_nd;
> > +
> > + //virtio_device_ready(vdev);
>
> Left over
o.k
>
> > + return 0;
> > +out_nd:
> > + err = -ENXIO;
> > + nvdimm_bus_unregister(nvdimm_bus);
> > +out_vq:
> > + vdev->config->del_vqs(vdev);
> > +out_err:
> > + dev_err(&vdev->dev, "failed to register virtio pmem memory\n");
> > + return err;
> > +}
> > +
> > +static void virtio_pmem_remove(struct virtio_device *vdev)
> > +{
> > + struct virtio_pmem *vpmem = vdev->priv;
> > + struct nvdimm_bus *nvdimm_bus = dev_get_drvdata(&vdev->dev);
> > +
> > + nvdimm_bus_unregister(nvdimm_bus);
> > + vdev->config->del_vqs(vdev);
>
> I think you should also call vdev->config->reset
o.k. Here device will be removed completely, still its required?
>
> > + kfree(vpmem);
> > +}
> > +
> > +static struct virtio_driver virtio_pmem_driver = {
> > + .driver.name = KBUILD_MODNAME,
> > + .driver.owner = THIS_MODULE,
> > + .id_table = id_table,
> > + .probe = virtio_pmem_probe,
> > + .remove = virtio_pmem_remove,
> > +};
> > +
> > +module_virtio_driver(virtio_pmem_driver);
> > +MODULE_DEVICE_TABLE(virtio, id_table);
> > +MODULE_DESCRIPTION("Virtio pmem driver");
> > +MODULE_LICENSE("GPL");
> > diff --git a/include/linux/virtio_pmem.h b/include/linux/virtio_pmem.h
> > new file mode 100644
> > index 000000000000..224f9d934be6
> > --- /dev/null
> > +++ b/include/linux/virtio_pmem.h
> > @@ -0,0 +1,60 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +/*
> > + * virtio_pmem.h: virtio pmem Driver
> > + *
> > + * Discovers persistent memory range information
> > + * from host and provides a virtio based flushing
> > + * interface.
> > + **/
> > +
> > +#ifndef _LINUX_VIRTIO_PMEM_H
> > +#define _LINUX_VIRTIO_PMEM_H
> > +
> > +#include <linux/virtio_ids.h>
> > +#include <linux/module.h>
> > +#include <linux/virtio_config.h>
> > +#include <uapi/linux/virtio_pmem.h>
> > +#include <linux/libnvdimm.h>
> > +#include <linux/spinlock.h>
> > +
> > +struct virtio_pmem_request {
> > + /* Host return status corresponding to flush request */
> > + int ret;
> > +
> > + /* command name*/
> > + char name[16];
> > +
> > + /* Wait queue to process deferred work after ack from host */
> > + wait_queue_head_t host_acked;
> > + bool done;
> > +
> > + /* Wait queue to process deferred work after virt queue buffer avail */
> > + wait_queue_head_t wq_buf;
> > + bool wq_buf_avail;
> > + struct list_head list;
> > +};
> > +
> > +struct virtio_pmem {
> > + struct virtio_device *vdev;
> > +
> > + /* Virtio pmem request queue */
> > + struct virtqueue *req_vq;
> > +
> > + /* nvdimm bus registers virtio pmem device */
> > + struct nvdimm_bus *nvdimm_bus;
> > + struct nvdimm_bus_descriptor nd_desc;
> > +
> > + /* List to store deferred work if virtqueue is full */
> > + struct list_head req_list;
> > +
> > + /* Synchronize virtqueue data */
> > + spinlock_t pmem_lock;
> > +
> > + /* Memory region information */
> > + uint64_t start;
> > + uint64_t size;
> > +};
> > +
> > +void host_ack(struct virtqueue *vq);
> > +int virtio_pmem_flush(struct nd_region *nd_region);
> > +#endif
> > diff --git a/include/uapi/linux/virtio_ids.h
> > b/include/uapi/linux/virtio_ids.h
> > index 6d5c3b2d4f4d..346389565ac1 100644
> > --- a/include/uapi/linux/virtio_ids.h
> > +++ b/include/uapi/linux/virtio_ids.h
> > @@ -43,5 +43,6 @@
> > #define VIRTIO_ID_INPUT 18 /* virtio input */
> > #define VIRTIO_ID_VSOCK 19 /* virtio vsock transport */
> > #define VIRTIO_ID_CRYPTO 20 /* virtio crypto */
> > +#define VIRTIO_ID_PMEM 25 /* virtio pmem */
>
> Any reason for the jump here? are 21 to 24 already taken or you just
> want to be on the safe side?
They are already reserved.
Thanks,
Pankaj
>
> >
> > #endif /* _LINUX_VIRTIO_IDS_H */
> > diff --git a/include/uapi/linux/virtio_pmem.h
> > b/include/uapi/linux/virtio_pmem.h
> > new file mode 100644
> > index 000000000000..fa3f7d52717a
> > --- /dev/null
> > +++ b/include/uapi/linux/virtio_pmem.h
> > @@ -0,0 +1,10 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +
> > +#ifndef _UAPI_LINUX_VIRTIO_PMEM_H
> > +#define _UAPI_LINUX_VIRTIO_PMEM_H
> > +
> > +struct virtio_pmem_config {
> > + __le64 start;
> > + __le64 size;
> > +};
> > +#endif
> > --
> > 2.20.1
> >
> >
>
>
^ permalink raw reply
* [PATCH] virtio: Fix indentation of VIRTIO_MMIO
From: Fabrizio Castro @ 2019-04-03 15:04 UTC (permalink / raw)
To: Michael S. Tsirkin, Jason Wang
Cc: Fabrizio Castro, linux-kernel, virtualization
VIRTIO_MMIO config option block starts with a space, fix that.
Signed-off-by: Fabrizio Castro <fabrizio.castro@bp.renesas.com>
---
drivers/virtio/Kconfig | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/virtio/Kconfig b/drivers/virtio/Kconfig
index 3589764..1b5c9f0 100644
--- a/drivers/virtio/Kconfig
+++ b/drivers/virtio/Kconfig
@@ -62,12 +62,12 @@ config VIRTIO_INPUT
If unsure, say M.
- config VIRTIO_MMIO
+config VIRTIO_MMIO
tristate "Platform bus driver for memory mapped virtio devices"
depends on HAS_IOMEM && HAS_DMA
- select VIRTIO
- ---help---
- This drivers provides support for memory mapped virtio
+ select VIRTIO
+ ---help---
+ This drivers provides support for memory mapped virtio
platform device driver.
If unsure, say N.
--
2.7.4
^ permalink raw reply related
* Re: [PATCH] drm/cirrus: rewrite and modernize driver.
From: Daniel Stone @ 2019-04-03 15:15 UTC (permalink / raw)
To: Adam Jackson
Cc: David Airlie, open list, dri-devel,
open list:DRM DRIVER FOR QEMU'S CIRRUS DEVICE, Dave Airlie
In-Reply-To: <85ba308177f4e9ddee336d5110cb6df7a447cebf.camel@redhat.com>
On Wed, 3 Apr 2019 at 16:12, Adam Jackson <ajax@redhat.com> wrote:
> On Wed, 2019-04-03 at 09:23 +0200, Gerd Hoffmann wrote:
> > - Only DRM_FORMAT_RGB565 (depth 16) is supported. The old driver does
> > that too by default. There was a module parameter which enables 24/32
> > bpp support and disables higher resolutions (due to cirrus hardware
> > constrains). That parameter wasn't reimplemented.
>
> One slightly annoying aspect of this (well, initially of the patch to
> clamp the default to 16bpp, but this too) is that we only have a way to
> ask the driver which format it prefers, not which ones it supports at
> all. For X's modesetting driver (and yes some of this is because X is
> awful) this creates the following failure mode:
>
> 1: user sets up xorg.conf for depth 24
> 2: user upgrades kernel, reboots
> 3: X driver detects that depth 16 is preferred, but
> 4: X core respects user's xorg.conf and tries depth 24, which
> 5: throws -EINVAL and X won't start.
>
> Possibly X should work around this by transparently setting up a shadow
> framebuffer at the user's requested depth. The problem there is, if 565
> is preferred but 8888 works, you're adding a format-conversion blit in
> the middle for no reason. If I could ask the kernel for the entire list
> of supported formats, I could only set up the shadow if it was
> necessary.
There's already a list of supported formats for each DRM plane, which
you can get via drmModeGetPlane (being careful to enable universal
planes so you can discover the primary plane). The same information is
present in the 'IN_FORMATS' property, which is more difficult to parse
but also tells you about modifiers.
modesetting already pulls all this out (at least in the atomic path)
so we can reason about acceptable modifiers.
Cheers,
Daniel
^ permalink raw reply
* Re: [PATCH net v5] failover: allow name change on IFF_UP slave interfaces
From: Stephen Hemminger @ 2019-04-03 15:46 UTC (permalink / raw)
To: Samudrala, Sridhar
Cc: jiri, mst, kubakici, netdev, alexander.duyck, virtualization,
liran.alon, si-wei liu, boris.ostrovsky, davem
In-Reply-To: <d034f2f1-592c-7ce3-6bb3-05c53d195678@intel.com>
On Tue, 2 Apr 2019 22:22:18 -0700
"Samudrala, Sridhar" <sridhar.samudrala@intel.com> wrote:
> On 4/2/2019 8:14 PM, Stephen Hemminger wrote:
> > On Tue, 2 Apr 2019 15:23:29 -0700
> > si-wei liu <si-wei.liu@oracle.com> wrote:
> >
> >> On 4/2/2019 2:53 PM, Stephen Hemminger wrote:
> >>> On Mon, 1 Apr 2019 19:04:53 -0400
> >>> Si-Wei Liu <si-wei.liu@oracle.com> wrote:
> >>>
> >>>> + if (dev->flags & IFF_UP &&
> >>>> + likely(!(dev->priv_flags & IFF_FAILOVER_SLAVE)))
> >>> Why is property limited to failover slave, it would make sense for netvsc
> >>> as well. Why not make it a flag like live address change?
> >> Well, netvsc today is still taking the delayed approach meaning that it
> >> is incompatible yet with this live name change flag if need be. ;-)
> >>
> >> I thought Sridhar did not like to introduce an additional
> >> IFF_SLAVE_RENAME_OK flag given that failover slave is the only consumer
> >> for the time being. Even though I can get it back, patch is needed for
> >> netvsc to remove the VF takeover delay IMHO.
> >>
> >> Sridhar, what do you think we revive the IFF_SLAVE_RENAME_OK flag which
> >> allows netvsc to be used later on? Or maybe, IFF_LIVE_RENAME_OK for a
> >> better name?
> >>
> >> -Siwei
> >
> > I would name it IFF_LIVE_NAME_CHANGE to match IFF_LIVE_ADDR_CHANGE
> > there is no reason its use should be restricted to SLAVE devices.
> >
> Stephen,
> May be you should consider moving netvsc to use the net_failover driver now?
>
NO
Why would I waste time doing that when there is a working and cleaner solution
that is working across 4 OS's and three versions of five major distributions?
^ permalink raw reply
* CfP VHPC19: HPC Virtualization-Containers: Paper due May 1, 2019 (extended)
From: VHPC 19 @ 2019-04-03 16:12 UTC (permalink / raw)
To: virtualization
====================================================================
CALL FOR PAPERS
14th Workshop on Virtualization in High-Performance Cloud Computing
(VHPC '19) held in conjunction with the International Supercomputing
Conference - High Performance, June 16-20, 2019, Frankfurt, Germany.
(Springer LNCS Proceedings)
====================================================================
Date: June 20, 2019
Workshop URL: http://vhpc.org
Paper Submission Deadline: May 1, 2019 (extended)
Springer LNCS, rolling abstract submission
Abstract/Paper Submission Link: https://edas.info/newPaper.php?c=25685
Call for Papers
Containers and virtualization technologies constitute key enabling
factors for flexible resource management in modern data centers, and
particularly in cloud environments. Cloud providers need to manage
complex infrastructures in a seamless fashion to support the highly
dynamic and heterogeneous workloads and hosted applications customers
deploy. Similarly, HPC environments have been increasingly adopting
techniques that enable flexible management of vast computing and
networking resources, close to marginal provisioning cost, which is
unprecedented in the history of scientific and commercial computing.
Various virtualization-containerization technologies contribute to the
overall picture in different ways: machine virtualization, with its
capability to enable consolidation of multiple underutilized servers
with heterogeneous software and operating systems (OSes), and its
capability to live-migrate a fully operating virtual machine (VM)
with a very short downtime, enables novel and dynamic ways to manage
physical servers; OS-level virtualization (i.e., containerization),
with its capability to isolate multiple user-space environments and
to allow for their coexistence within the same OS kernel, promises to
provide many of the advantages of machine virtualization with high
levels of responsiveness and performance; lastly, unikernels provide
for many virtualization benefits with a minimized OS/library surface.
I/O Virtualization in turn allows physical network interfaces to take
traffic from multiple VMs or containers; network virtualization, with
its capability to create logical network overlays that are independent
of the underlying physical topology is furthermore enabling
virtualization of HPC infrastructures.
Publication
Accepted papers will be published in a Springer LNCS proceedings volume.
Topics of Interest
The VHPC program committee solicits original, high-quality submissions
related to virtualization across the entire software stack with a
special focus on the intersection of HPC, containers-virtualization
and the cloud.
Major Topics:
- HPC on Containers and VMs
- Containerized applications with OS-level virtualization
- Lightweight applications with Unikernels
- HP-as-a-Service
each major topic encompassing design/architecture, management,
performance management, modeling and configuration/tooling:
Design / Architecture:
- Containers and OS-level virtualization (LXC, Docker, rkt,
Singularity, Shifter, i.a.)
- Hypervisor support for heterogeneous resources (GPUs, co-processors,
FPGAs, etc.)
- Hypervisor extensions to mitigate side-channel attacks
([micro-]architectural timing attacks, privilege escalation)
- VM & Container trust and security models
- Multi-environment coupling, system software supporting in-situ
analysis with HPC simulation
- Cloud reliability, fault-tolerance and high-availability
- Energy-efficient and power-aware virtualization
- Containers inside VMs with hypervisor isolation
- Virtualization support for emerging memory technologies
- Lightweight/specialized operating systems in conjunction with
virtual machines
- Hypervisor support for heterogeneous resources (GPUs, co-processors,
FPGAs, etc.)
- Novel unikernels and use cases for virtualized HPC environments
- ARM-based hypervisors, ARM virtualization extensions
Management:
- Container and VM management for HPC and cloud environments
- HPC services integration, services to support HPC
- Service and on-demand scheduling & resource management
- Dedicated workload management with VMs or containers
- Workflow coupling with VMs and containers
- Unikernel, lightweight VM application management
- Environments and tools for operating containerized environments
(batch, orchestration)
- Novel models for non-HPC workload provisioning on HPC resources
Performance Measurements and Modeling:
- Performance improvements for or driven by unikernels
- Optimizations of virtual machine monitor platforms and hypervisors
- Scalability analysis of VMs and/or containers at large scale
- Performance measurement, modeling and monitoring of
virtualized/cloud workloads
- Virtualization in supercomputing environments, HPC clusters, HPC in
the cloud
Configuration / Tooling:
- Tool support for unikernels: configuration/build environments,
debuggers, profilers
- Job scheduling/control/policy and container placement in virtualized
environments
- Operating MPI in containers/VMs and Unikernels
- Software defined networks and network virtualization
- GPU virtualization operationalization
The Workshop on Virtualization in High-Performance Cloud Computing
(VHPC) aims to bring together researchers and industrial practitioners
facing the challenges posed by virtualization in order to foster
discussion, collaboration, mutual exchange of knowledge and
experience, enabling research to ultimately provide novel solutions
for virtualized computing systems of tomorrow.
The workshop will be one day in length, composed of 20 min paper
presentations, each followed by 10 min discussion sections, plus
lightning talks that are limited to 5 minutes. Presentations may be
accompanied by interactive demonstrations.
Important Dates
May 1, 2019 - Abstract/Paper extended submission deadline
(Springer LNCS)
May 20, 2019 - Acceptance notification
June 20th, 2019 - Workshop Day
July 10th, 2019 - Camera-ready version due
Chair
Michael Alexander (chair), University of Vienna, Austria
Anastassios Nanos (co-chair), SunLight.io, UK
Andrew Younge (co-chair), Sandia National Laboratories
Program committee
Stergios Anastasiadis, University of Ioannina, Greece
Jakob Blomer, CERN, Europe
Eduardo César, Universidad Autonoma de Barcelona, Spain
Taylor Childers, Argonne National Laboratory, USA
Stephen Crago, USC ISI, USA
Tommaso Cucinotta, St. Anna School of Advanced Studies, Italy
Christoffer Dall, Columbia University, USA
François Diakhaté, CEA, France
Patrick Dreher, MIT, USA
Kyle Hale, Northwestern University, USA
Bob Killen, University of Michigan, USA
Brian Kocoloski, Washington University, USA
John Lange, University of Pittsburgh, USA
Giuseppe Lettieri, University of Pisa, Italy
Qing Liu, Oak Ridge National Laboratory, USA
Nikos Parlavantzas, IRISA, France
Kevin Pedretti, Sandia National Laboratories, USA
Amer Qouneh, Western New England University, USA
Carlos Reaño, Queen’s University Belfast, UK
Borja Sotomayor, University of Chicago, USA
Jonathan Sparks, Cray, USA
Joe Stubbs, Texas Advanced Computing Center, USA
Anata Tiwari, San Diego Supercomputer Center, USA
Kurt Tutschku, Blekinge Institute of Technology, Sweden
John Walters, USC ISI, USA
Yasuhiro Watashiba, Osaka University, Japan
Chao-Tung Yang, Tunghai University, Taiwan
Na Zhang, VMware, USA
Paper Submission-Publication
Papers submitted to the workshop will be reviewed by at least two members of
the program committee and external reviewers. Submissions should include
abstract, keywords, the e-mail address of the corresponding author, and must
not exceed 10 pages, including tables and figures at a main font size no
smaller than 11 point. Submission of a paper should be regarded as a commitment
that, should the paper be accepted, at least one of the authors will register
and attend the conference to present the work. Accepted papers will be
published in a Springer LNCS volume.
The format must be according to the Springer LNCS Style. Initial submissions
are in PDF; authors of accepted papers will be requested to provide source
files.
Format Guidelines:
ftp://ftp.springernature.com/cs-proceeding/llncs/llncs2e.zip
Abstract, Paper Submission Link:
https://edas.info/newPaper.php?c=25685
Lightning Talks
Lightning Talks are non-paper track, synoptical in nature and are strictly
limited to 5 minutes. They can be used to gain early feedback on ongoing
research, for demonstrations, to present research results, early research
ideas, perspectives and positions of interest to the community. Submit abstract
via the main submission link.
General Information
The workshop is one day in length and will be held in conjunction with the
International Supercomputing Conference - High Performance (ISC) 2019, June
16-20, Frankfurt, Germany.
_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization
^ permalink raw reply
* Re: [PATCH v4 5/5] xfs: disable map_sync for async flush
From: Dave Chinner @ 2019-04-03 22:09 UTC (permalink / raw)
To: Pankaj Gupta
Cc: cohuck, jack, kvm, mst, qemu-devel, virtualization,
adilger.kernel, zwisler, aarcange, dave.jiang, linux-nvdimm,
vishal.l.verma, willy, hch, linux-acpi, jmoyer, linux-ext4, lenb,
riel, stefanha, dan.j.williams, lcapitulino, nilal, tytso,
xiaoguangrong.eric, darrick.wong, rjw, linux-kernel, linux-xfs,
linux-fsdevel, imammedo
In-Reply-To: <20190403104018.23947-6-pagupta@redhat.com>
On Wed, Apr 03, 2019 at 04:10:18PM +0530, Pankaj Gupta wrote:
> Virtio pmem provides asynchronous host page cache flush
> mechanism. we don't support 'MAP_SYNC' with virtio pmem
> and xfs.
>
> Signed-off-by: Pankaj Gupta <pagupta@redhat.com>
> ---
> fs/xfs/xfs_file.c | 8 ++++++++
> 1 file changed, 8 insertions(+)
>
> diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c
> index 1f2e2845eb76..dced2eb8c91a 100644
> --- a/fs/xfs/xfs_file.c
> +++ b/fs/xfs/xfs_file.c
> @@ -1203,6 +1203,14 @@ xfs_file_mmap(
> if (!IS_DAX(file_inode(filp)) && (vma->vm_flags & VM_SYNC))
> return -EOPNOTSUPP;
>
> + /* We don't support synchronous mappings with DAX files if
> + * dax_device is not synchronous.
> + */
> + if (IS_DAX(file_inode(filp)) && !dax_synchronous(
> + xfs_find_daxdev_for_inode(file_inode(filp))) &&
> + (vma->vm_flags & VM_SYNC))
> + return -EOPNOTSUPP;
> +
> file_accessed(filp);
> vma->vm_ops = &xfs_file_vm_ops;
> if (IS_DAX(file_inode(filp)))
All this ad hoc IS_DAX conditional logic is getting pretty nasty.
xfs_file_mmap(
....
{
struct inode *inode = file_inode(filp);
if (vma->vm_flags & VM_SYNC) {
if (!IS_DAX(inode))
return -EOPNOTSUPP;
if (!dax_synchronous(xfs_find_daxdev_for_inode(inode))
return -EOPNOTSUPP;
}
file_accessed(filp);
vma->vm_ops = &xfs_file_vm_ops;
if (IS_DAX(inode))
vma->vm_flags |= VM_HUGEPAGE;
return 0;
}
Even better, factor out all the "MAP_SYNC supported" checks into a
helper so that the filesystem code just doesn't have to care about
the details of checking for DAX+MAP_SYNC support....
Cheers,
Dave.
--
Dave Chinner
david@fromorbit.com
^ permalink raw reply
* Re: [PATCH v4 5/5] xfs: disable map_sync for async flush
From: Darrick J. Wong @ 2019-04-03 22:39 UTC (permalink / raw)
To: Dave Chinner
Cc: Pankaj Gupta, jack, kvm, mst, qemu-devel, virtualization,
adilger.kernel, zwisler, aarcange, dave.jiang, linux-nvdimm,
vishal.l.verma, willy, hch, linux-acpi, jmoyer, linux-ext4, lenb,
riel, stefanha, dan.j.williams, lcapitulino, nilal, tytso,
xiaoguangrong.eric, cohuck, rjw, linux-kernel, linux-xfs,
linux-fsdevel, imammedo
In-Reply-To: <20190403220912.GB26298@dastard>
On Thu, Apr 04, 2019 at 09:09:12AM +1100, Dave Chinner wrote:
> On Wed, Apr 03, 2019 at 04:10:18PM +0530, Pankaj Gupta wrote:
> > Virtio pmem provides asynchronous host page cache flush
> > mechanism. we don't support 'MAP_SYNC' with virtio pmem
> > and xfs.
> >
> > Signed-off-by: Pankaj Gupta <pagupta@redhat.com>
> > ---
> > fs/xfs/xfs_file.c | 8 ++++++++
> > 1 file changed, 8 insertions(+)
> >
> > diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c
> > index 1f2e2845eb76..dced2eb8c91a 100644
> > --- a/fs/xfs/xfs_file.c
> > +++ b/fs/xfs/xfs_file.c
> > @@ -1203,6 +1203,14 @@ xfs_file_mmap(
> > if (!IS_DAX(file_inode(filp)) && (vma->vm_flags & VM_SYNC))
> > return -EOPNOTSUPP;
> >
> > + /* We don't support synchronous mappings with DAX files if
> > + * dax_device is not synchronous.
> > + */
> > + if (IS_DAX(file_inode(filp)) && !dax_synchronous(
> > + xfs_find_daxdev_for_inode(file_inode(filp))) &&
> > + (vma->vm_flags & VM_SYNC))
> > + return -EOPNOTSUPP;
> > +
> > file_accessed(filp);
> > vma->vm_ops = &xfs_file_vm_ops;
> > if (IS_DAX(file_inode(filp)))
>
> All this ad hoc IS_DAX conditional logic is getting pretty nasty.
>
> xfs_file_mmap(
> ....
> {
> struct inode *inode = file_inode(filp);
>
> if (vma->vm_flags & VM_SYNC) {
> if (!IS_DAX(inode))
> return -EOPNOTSUPP;
> if (!dax_synchronous(xfs_find_daxdev_for_inode(inode))
> return -EOPNOTSUPP;
> }
>
> file_accessed(filp);
> vma->vm_ops = &xfs_file_vm_ops;
> if (IS_DAX(inode))
> vma->vm_flags |= VM_HUGEPAGE;
> return 0;
> }
>
>
> Even better, factor out all the "MAP_SYNC supported" checks into a
> helper so that the filesystem code just doesn't have to care about
> the details of checking for DAX+MAP_SYNC support....
Seconded, since ext4 has nearly the same flag validation logic.
--D
>
> Cheers,
>
> Dave.
> --
> Dave Chinner
> david@fromorbit.com
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox