Commit 7c6ca304 authored by Dave Airlie's avatar Dave Airlie

Merge branch 'qxl-next' of git://people.freedesktop.org/~airlied/linux into drm-next

Adds 3 features that UMS had to the KMS driver.
dynamic resizing - resizing remote-viewer makes guest resize
multiple crtcs - remote-viewer can access > 1 crtc.
suspend/resume/hibernate: guests can do suspend/resume/hibernate now.

* 'qxl-next' of git://people.freedesktop.org/~airlied/linux:
  qxl: use drm helper hotplug support
  qxl: add suspend/resume/hibernate support.
  qxl: add fb and ttm entry points for use by suspend/resume.
  qxl: add ring prep code for s/r
  qxl: prepare memslot code for suspend/resume
  qxl: split monitors_config object creation out.
  drm/qxl: set time on drawables from userspace
  drm/qxl: add support for > 1 output
  drm/qxl: make dynamic resizing work properly.
parents 69163ea8 5ff91e44
...@@ -49,6 +49,11 @@ void qxl_ring_free(struct qxl_ring *ring) ...@@ -49,6 +49,11 @@ void qxl_ring_free(struct qxl_ring *ring)
kfree(ring); kfree(ring);
} }
void qxl_ring_init_hdr(struct qxl_ring *ring)
{
ring->ring->header.notify_on_prod = ring->n_elements;
}
struct qxl_ring * struct qxl_ring *
qxl_ring_create(struct qxl_ring_header *header, qxl_ring_create(struct qxl_ring_header *header,
int element_size, int element_size,
...@@ -69,7 +74,7 @@ qxl_ring_create(struct qxl_ring_header *header, ...@@ -69,7 +74,7 @@ qxl_ring_create(struct qxl_ring_header *header,
ring->prod_notify = prod_notify; ring->prod_notify = prod_notify;
ring->push_event = push_event; ring->push_event = push_event;
if (set_prod_notify) if (set_prod_notify)
header->notify_on_prod = ring->n_elements; qxl_ring_init_hdr(ring);
spin_lock_init(&ring->lock); spin_lock_init(&ring->lock);
return ring; return ring;
} }
...@@ -87,7 +92,7 @@ static int qxl_check_header(struct qxl_ring *ring) ...@@ -87,7 +92,7 @@ static int qxl_check_header(struct qxl_ring *ring)
return ret; return ret;
} }
static int qxl_check_idle(struct qxl_ring *ring) int qxl_check_idle(struct qxl_ring *ring)
{ {
int ret; int ret;
struct qxl_ring_header *header = &(ring->ring->header); struct qxl_ring_header *header = &(ring->ring->header);
...@@ -375,8 +380,8 @@ void qxl_io_destroy_primary(struct qxl_device *qdev) ...@@ -375,8 +380,8 @@ void qxl_io_destroy_primary(struct qxl_device *qdev)
wait_for_io_cmd(qdev, 0, QXL_IO_DESTROY_PRIMARY_ASYNC); wait_for_io_cmd(qdev, 0, QXL_IO_DESTROY_PRIMARY_ASYNC);
} }
void qxl_io_create_primary(struct qxl_device *qdev, unsigned width, void qxl_io_create_primary(struct qxl_device *qdev,
unsigned height, unsigned offset, struct qxl_bo *bo) unsigned offset, struct qxl_bo *bo)
{ {
struct qxl_surface_create *create; struct qxl_surface_create *create;
...@@ -384,8 +389,8 @@ void qxl_io_create_primary(struct qxl_device *qdev, unsigned width, ...@@ -384,8 +389,8 @@ void qxl_io_create_primary(struct qxl_device *qdev, unsigned width,
qdev->ram_header); qdev->ram_header);
create = &qdev->ram_header->create_surface; create = &qdev->ram_header->create_surface;
create->format = bo->surf.format; create->format = bo->surf.format;
create->width = width; create->width = bo->surf.width;
create->height = height; create->height = bo->surf.height;
create->stride = bo->surf.stride; create->stride = bo->surf.stride;
create->mem = qxl_bo_physical_address(qdev, bo, offset); create->mem = qxl_bo_physical_address(qdev, bo, offset);
......
This diff is collapsed.
...@@ -33,8 +33,9 @@ ...@@ -33,8 +33,9 @@
#include "drmP.h" #include "drmP.h"
#include "drm/drm.h" #include "drm/drm.h"
#include "drm_crtc_helper.h"
#include "qxl_drv.h" #include "qxl_drv.h"
#include "qxl_object.h"
extern int qxl_max_ioctls; extern int qxl_max_ioctls;
static DEFINE_PCI_DEVICE_TABLE(pciidlist) = { static DEFINE_PCI_DEVICE_TABLE(pciidlist) = {
...@@ -47,10 +48,14 @@ static DEFINE_PCI_DEVICE_TABLE(pciidlist) = { ...@@ -47,10 +48,14 @@ static DEFINE_PCI_DEVICE_TABLE(pciidlist) = {
MODULE_DEVICE_TABLE(pci, pciidlist); MODULE_DEVICE_TABLE(pci, pciidlist);
static int qxl_modeset = -1; static int qxl_modeset = -1;
int qxl_num_crtc = 4;
MODULE_PARM_DESC(modeset, "Disable/Enable modesetting"); MODULE_PARM_DESC(modeset, "Disable/Enable modesetting");
module_param_named(modeset, qxl_modeset, int, 0400); module_param_named(modeset, qxl_modeset, int, 0400);
MODULE_PARM_DESC(num_heads, "Number of virtual crtcs to expose (default 4)");
module_param_named(num_heads, qxl_num_crtc, int, 0400);
static struct drm_driver qxl_driver; static struct drm_driver qxl_driver;
static struct pci_driver qxl_pci_driver; static struct pci_driver qxl_pci_driver;
...@@ -73,13 +78,6 @@ qxl_pci_remove(struct pci_dev *pdev) ...@@ -73,13 +78,6 @@ qxl_pci_remove(struct pci_dev *pdev)
drm_put_dev(dev); drm_put_dev(dev);
} }
static struct pci_driver qxl_pci_driver = {
.name = DRIVER_NAME,
.id_table = pciidlist,
.probe = qxl_pci_probe,
.remove = qxl_pci_remove,
};
static const struct file_operations qxl_fops = { static const struct file_operations qxl_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.open = drm_open, .open = drm_open,
...@@ -90,6 +88,130 @@ static const struct file_operations qxl_fops = { ...@@ -90,6 +88,130 @@ static const struct file_operations qxl_fops = {
.mmap = qxl_mmap, .mmap = qxl_mmap,
}; };
static int qxl_drm_freeze(struct drm_device *dev)
{
struct pci_dev *pdev = dev->pdev;
struct qxl_device *qdev = dev->dev_private;
struct drm_crtc *crtc;
drm_kms_helper_poll_disable(dev);
console_lock();
qxl_fbdev_set_suspend(qdev, 1);
console_unlock();
/* unpin the front buffers */
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
if (crtc->enabled)
(*crtc_funcs->disable)(crtc);
}
qxl_destroy_monitors_object(qdev);
qxl_surf_evict(qdev);
qxl_vram_evict(qdev);
while (!qxl_check_idle(qdev->command_ring));
while (!qxl_check_idle(qdev->release_ring))
qxl_queue_garbage_collect(qdev, 1);
pci_save_state(pdev);
return 0;
}
static int qxl_drm_resume(struct drm_device *dev, bool thaw)
{
struct qxl_device *qdev = dev->dev_private;
qdev->ram_header->int_mask = QXL_INTERRUPT_MASK;
if (!thaw) {
qxl_reinit_memslots(qdev);
qxl_ring_init_hdr(qdev->release_ring);
}
qxl_create_monitors_object(qdev);
drm_helper_resume_force_mode(dev);
console_lock();
qxl_fbdev_set_suspend(qdev, 0);
console_unlock();
drm_kms_helper_poll_enable(dev);
return 0;
}
static int qxl_pm_suspend(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
struct drm_device *drm_dev = pci_get_drvdata(pdev);
int error;
error = qxl_drm_freeze(drm_dev);
if (error)
return error;
pci_disable_device(pdev);
pci_set_power_state(pdev, PCI_D3hot);
return 0;
}
static int qxl_pm_resume(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
struct drm_device *drm_dev = pci_get_drvdata(pdev);
pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);
if (pci_enable_device(pdev)) {
return -EIO;
}
return qxl_drm_resume(drm_dev, false);
}
static int qxl_pm_thaw(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
struct drm_device *drm_dev = pci_get_drvdata(pdev);
return qxl_drm_resume(drm_dev, true);
}
static int qxl_pm_freeze(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
struct drm_device *drm_dev = pci_get_drvdata(pdev);
return qxl_drm_freeze(drm_dev);
}
static int qxl_pm_restore(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
struct drm_device *drm_dev = pci_get_drvdata(pdev);
struct qxl_device *qdev = drm_dev->dev_private;
qxl_io_reset(qdev);
return qxl_drm_resume(drm_dev, false);
}
static const struct dev_pm_ops qxl_pm_ops = {
.suspend = qxl_pm_suspend,
.resume = qxl_pm_resume,
.freeze = qxl_pm_freeze,
.thaw = qxl_pm_thaw,
.poweroff = qxl_pm_freeze,
.restore = qxl_pm_restore,
};
static struct pci_driver qxl_pci_driver = {
.name = DRIVER_NAME,
.id_table = pciidlist,
.probe = qxl_pci_probe,
.remove = qxl_pci_remove,
.driver.pm = &qxl_pm_ops,
};
static struct drm_driver qxl_driver = { static struct drm_driver qxl_driver = {
.driver_features = DRIVER_GEM | DRIVER_MODESET | .driver_features = DRIVER_GEM | DRIVER_MODESET |
DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED, DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED,
......
...@@ -55,11 +55,10 @@ ...@@ -55,11 +55,10 @@
#define DRIVER_MINOR 1 #define DRIVER_MINOR 1
#define DRIVER_PATCHLEVEL 0 #define DRIVER_PATCHLEVEL 0
#define QXL_NUM_OUTPUTS 1
#define QXL_DEBUGFS_MAX_COMPONENTS 32 #define QXL_DEBUGFS_MAX_COMPONENTS 32
extern int qxl_log_level; extern int qxl_log_level;
extern int qxl_num_crtc;
enum { enum {
QXL_INFO_LEVEL = 1, QXL_INFO_LEVEL = 1,
...@@ -139,6 +138,7 @@ struct qxl_reloc_list { ...@@ -139,6 +138,7 @@ struct qxl_reloc_list {
struct qxl_crtc { struct qxl_crtc {
struct drm_crtc base; struct drm_crtc base;
int index;
int cur_x; int cur_x;
int cur_y; int cur_y;
}; };
...@@ -156,7 +156,7 @@ struct qxl_framebuffer { ...@@ -156,7 +156,7 @@ struct qxl_framebuffer {
#define to_qxl_crtc(x) container_of(x, struct qxl_crtc, base) #define to_qxl_crtc(x) container_of(x, struct qxl_crtc, base)
#define drm_connector_to_qxl_output(x) container_of(x, struct qxl_output, base) #define drm_connector_to_qxl_output(x) container_of(x, struct qxl_output, base)
#define drm_encoder_to_qxl_output(x) container_of(x, struct qxl_output, base) #define drm_encoder_to_qxl_output(x) container_of(x, struct qxl_output, enc)
#define to_qxl_framebuffer(x) container_of(x, struct qxl_framebuffer, base) #define to_qxl_framebuffer(x) container_of(x, struct qxl_framebuffer, base)
struct qxl_mman { struct qxl_mman {
...@@ -331,6 +331,10 @@ void qxl_modeset_fini(struct qxl_device *qdev); ...@@ -331,6 +331,10 @@ void qxl_modeset_fini(struct qxl_device *qdev);
int qxl_bo_init(struct qxl_device *qdev); int qxl_bo_init(struct qxl_device *qdev);
void qxl_bo_fini(struct qxl_device *qdev); void qxl_bo_fini(struct qxl_device *qdev);
void qxl_reinit_memslots(struct qxl_device *qdev);
int qxl_surf_evict(struct qxl_device *qdev);
int qxl_vram_evict(struct qxl_device *qdev);
struct qxl_ring *qxl_ring_create(struct qxl_ring_header *header, struct qxl_ring *qxl_ring_create(struct qxl_ring_header *header,
int element_size, int element_size,
int n_elements, int n_elements,
...@@ -338,6 +342,8 @@ struct qxl_ring *qxl_ring_create(struct qxl_ring_header *header, ...@@ -338,6 +342,8 @@ struct qxl_ring *qxl_ring_create(struct qxl_ring_header *header,
bool set_prod_notify, bool set_prod_notify,
wait_queue_head_t *push_event); wait_queue_head_t *push_event);
void qxl_ring_free(struct qxl_ring *ring); void qxl_ring_free(struct qxl_ring *ring);
void qxl_ring_init_hdr(struct qxl_ring *ring);
int qxl_check_idle(struct qxl_ring *ring);
static inline void * static inline void *
qxl_fb_virtual_address(struct qxl_device *qdev, unsigned long physical) qxl_fb_virtual_address(struct qxl_device *qdev, unsigned long physical)
...@@ -365,6 +371,7 @@ void qxl_fbdev_fini(struct qxl_device *qdev); ...@@ -365,6 +371,7 @@ void qxl_fbdev_fini(struct qxl_device *qdev);
int qxl_get_handle_for_primary_fb(struct qxl_device *qdev, int qxl_get_handle_for_primary_fb(struct qxl_device *qdev,
struct drm_file *file_priv, struct drm_file *file_priv,
uint32_t *handle); uint32_t *handle);
void qxl_fbdev_set_suspend(struct qxl_device *qdev, int state);
/* qxl_display.c */ /* qxl_display.c */
int int
...@@ -374,6 +381,8 @@ qxl_framebuffer_init(struct drm_device *dev, ...@@ -374,6 +381,8 @@ qxl_framebuffer_init(struct drm_device *dev,
struct drm_gem_object *obj); struct drm_gem_object *obj);
void qxl_display_read_client_monitors_config(struct qxl_device *qdev); void qxl_display_read_client_monitors_config(struct qxl_device *qdev);
void qxl_send_monitors_config(struct qxl_device *qdev); void qxl_send_monitors_config(struct qxl_device *qdev);
int qxl_create_monitors_object(struct qxl_device *qdev);
int qxl_destroy_monitors_object(struct qxl_device *qdev);
/* used by qxl_debugfs only */ /* used by qxl_debugfs only */
void qxl_crtc_set_from_monitors_config(struct qxl_device *qdev); void qxl_crtc_set_from_monitors_config(struct qxl_device *qdev);
...@@ -435,7 +444,7 @@ void qxl_update_screen(struct qxl_device *qxl); ...@@ -435,7 +444,7 @@ void qxl_update_screen(struct qxl_device *qxl);
/* qxl io operations (qxl_cmd.c) */ /* qxl io operations (qxl_cmd.c) */
void qxl_io_create_primary(struct qxl_device *qdev, void qxl_io_create_primary(struct qxl_device *qdev,
unsigned width, unsigned height, unsigned offset, unsigned offset,
struct qxl_bo *bo); struct qxl_bo *bo);
void qxl_io_destroy_primary(struct qxl_device *qdev); void qxl_io_destroy_primary(struct qxl_device *qdev);
void qxl_io_memslot_add(struct qxl_device *qdev, uint8_t id); void qxl_io_memslot_add(struct qxl_device *qdev, uint8_t id);
...@@ -528,6 +537,7 @@ irqreturn_t qxl_irq_handler(DRM_IRQ_ARGS); ...@@ -528,6 +537,7 @@ irqreturn_t qxl_irq_handler(DRM_IRQ_ARGS);
/* qxl_fb.c */ /* qxl_fb.c */
int qxl_fb_init(struct qxl_device *qdev); int qxl_fb_init(struct qxl_device *qdev);
bool qxl_fbdev_qobj_is_fb(struct qxl_device *qdev, struct qxl_bo *qobj);
int qxl_debugfs_add_files(struct qxl_device *qdev, int qxl_debugfs_add_files(struct qxl_device *qdev,
struct drm_info_list *files, struct drm_info_list *files,
......
...@@ -538,7 +538,7 @@ int qxl_fbdev_init(struct qxl_device *qdev) ...@@ -538,7 +538,7 @@ int qxl_fbdev_init(struct qxl_device *qdev)
qfbdev->helper.funcs = &qxl_fb_helper_funcs; qfbdev->helper.funcs = &qxl_fb_helper_funcs;
ret = drm_fb_helper_init(qdev->ddev, &qfbdev->helper, ret = drm_fb_helper_init(qdev->ddev, &qfbdev->helper,
1 /* num_crtc - QXL supports just 1 */, qxl_num_crtc /* num_crtc - QXL supports just 1 */,
QXLFB_CONN_LIMIT); QXLFB_CONN_LIMIT);
if (ret) { if (ret) {
kfree(qfbdev); kfree(qfbdev);
...@@ -560,4 +560,14 @@ void qxl_fbdev_fini(struct qxl_device *qdev) ...@@ -560,4 +560,14 @@ void qxl_fbdev_fini(struct qxl_device *qdev)
qdev->mode_info.qfbdev = NULL; qdev->mode_info.qfbdev = NULL;
} }
void qxl_fbdev_set_suspend(struct qxl_device *qdev, int state)
{
fb_set_suspend(qdev->mode_info.qfbdev->helper.fbdev, state);
}
bool qxl_fbdev_qobj_is_fb(struct qxl_device *qdev, struct qxl_bo *qobj)
{
if (qobj == gem_to_qxl_bo(qdev->mode_info.qfbdev->qfb.obj))
return true;
return false;
}
...@@ -183,6 +183,12 @@ static int qxl_execbuffer_ioctl(struct drm_device *dev, void *data, ...@@ -183,6 +183,12 @@ static int qxl_execbuffer_ioctl(struct drm_device *dev, void *data,
/* TODO copy slow path code from i915 */ /* TODO copy slow path code from i915 */
fb_cmd = qxl_bo_kmap_atomic_page(qdev, cmd_bo, (release->release_offset & PAGE_SIZE)); fb_cmd = qxl_bo_kmap_atomic_page(qdev, cmd_bo, (release->release_offset & PAGE_SIZE));
unwritten = __copy_from_user_inatomic_nocache(fb_cmd + sizeof(union qxl_release_info) + (release->release_offset & ~PAGE_SIZE), (void *)(unsigned long)user_cmd.command, user_cmd.command_size); unwritten = __copy_from_user_inatomic_nocache(fb_cmd + sizeof(union qxl_release_info) + (release->release_offset & ~PAGE_SIZE), (void *)(unsigned long)user_cmd.command, user_cmd.command_size);
{
struct qxl_drawable *draw = fb_cmd;
draw->mm_time = qdev->rom->mm_clock;
}
qxl_bo_kunmap_atomic_page(qdev, cmd_bo, fb_cmd); qxl_bo_kunmap_atomic_page(qdev, cmd_bo, fb_cmd);
if (unwritten) { if (unwritten) {
DRM_ERROR("got unwritten %d\n", unwritten); DRM_ERROR("got unwritten %d\n", unwritten);
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include "qxl_drv.h" #include "qxl_drv.h"
#include "qxl_object.h" #include "qxl_object.h"
#include <drm/drm_crtc_helper.h>
#include <linux/io-mapping.h> #include <linux/io-mapping.h>
int qxl_log_level; int qxl_log_level;
...@@ -72,21 +73,28 @@ static bool qxl_check_device(struct qxl_device *qdev) ...@@ -72,21 +73,28 @@ static bool qxl_check_device(struct qxl_device *qdev)
return true; return true;
} }
static void setup_hw_slot(struct qxl_device *qdev, int slot_index,
struct qxl_memslot *slot)
{
qdev->ram_header->mem_slot.mem_start = slot->start_phys_addr;
qdev->ram_header->mem_slot.mem_end = slot->end_phys_addr;
qxl_io_memslot_add(qdev, slot_index);
}
static uint8_t setup_slot(struct qxl_device *qdev, uint8_t slot_index_offset, static uint8_t setup_slot(struct qxl_device *qdev, uint8_t slot_index_offset,
unsigned long start_phys_addr, unsigned long end_phys_addr) unsigned long start_phys_addr, unsigned long end_phys_addr)
{ {
uint64_t high_bits; uint64_t high_bits;
struct qxl_memslot *slot; struct qxl_memslot *slot;
uint8_t slot_index; uint8_t slot_index;
struct qxl_ram_header *ram_header = qdev->ram_header;
slot_index = qdev->rom->slots_start + slot_index_offset; slot_index = qdev->rom->slots_start + slot_index_offset;
slot = &qdev->mem_slots[slot_index]; slot = &qdev->mem_slots[slot_index];
slot->start_phys_addr = start_phys_addr; slot->start_phys_addr = start_phys_addr;
slot->end_phys_addr = end_phys_addr; slot->end_phys_addr = end_phys_addr;
ram_header->mem_slot.mem_start = slot->start_phys_addr;
ram_header->mem_slot.mem_end = slot->end_phys_addr; setup_hw_slot(qdev, slot_index, slot);
qxl_io_memslot_add(qdev, slot_index);
slot->generation = qdev->rom->slot_generation; slot->generation = qdev->rom->slot_generation;
high_bits = slot_index << qdev->slot_gen_bits; high_bits = slot_index << qdev->slot_gen_bits;
high_bits |= slot->generation; high_bits |= slot->generation;
...@@ -95,6 +103,12 @@ static uint8_t setup_slot(struct qxl_device *qdev, uint8_t slot_index_offset, ...@@ -95,6 +103,12 @@ static uint8_t setup_slot(struct qxl_device *qdev, uint8_t slot_index_offset,
return slot_index; return slot_index;
} }
void qxl_reinit_memslots(struct qxl_device *qdev)
{
setup_hw_slot(qdev, qdev->main_mem_slot, &qdev->mem_slots[qdev->main_mem_slot]);
setup_hw_slot(qdev, qdev->surfaces_mem_slot, &qdev->mem_slots[qdev->surfaces_mem_slot]);
}
static void qxl_gc_work(struct work_struct *work) static void qxl_gc_work(struct work_struct *work)
{ {
struct qxl_device *qdev = container_of(work, struct qxl_device, gc_work); struct qxl_device *qdev = container_of(work, struct qxl_device, gc_work);
...@@ -294,6 +308,8 @@ int qxl_driver_load(struct drm_device *dev, unsigned long flags) ...@@ -294,6 +308,8 @@ int qxl_driver_load(struct drm_device *dev, unsigned long flags)
goto out; goto out;
} }
drm_kms_helper_poll_init(qdev->ddev);
return 0; return 0;
out: out:
kfree(qdev); kfree(qdev);
......
...@@ -363,3 +363,13 @@ int qxl_bo_list_add(struct qxl_reloc_list *reloc_list, struct qxl_bo *bo) ...@@ -363,3 +363,13 @@ int qxl_bo_list_add(struct qxl_reloc_list *reloc_list, struct qxl_bo *bo)
return ret; return ret;
return 0; return 0;
} }
int qxl_surf_evict(struct qxl_device *qdev)
{
return ttm_bo_evict_mm(&qdev->mman.bdev, TTM_PL_PRIV0);
}
int qxl_vram_evict(struct qxl_device *qdev)
{
return ttm_bo_evict_mm(&qdev->mman.bdev, TTM_PL_VRAM);
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment