diff --git a/VMX-x86-handle-host-TSC-calibration-failure.patch b/VMX-x86-handle-host-TSC-calibration-failure.patch deleted file mode 100644 index 6b6ddd2..0000000 --- a/VMX-x86-handle-host-TSC-calibration-failure.patch +++ /dev/null @@ -1,58 +0,0 @@ -@@ -, +, @@ - VMX: x86: handle host TSC calibration failure - - If the host TSC calibration fails, tsc_khz is zero (see tsc_init.c). - Handle such case properly in KVM (instead of dividing by zero). - - https://bugzilla.redhat.com/show_bug.cgi?id=859282 - - Signed-off-by: Marcelo Tosatti - Signed-off-by: Gleb Natapov ---- a/arch/x86/kvm/x86.c -+++ a/arch/x86/kvm/x86.c -@@ -1079,6 +1079,10 @@ static void kvm_set_tsc_khz(struct kvm_vcpu *vcpu, u32 this_tsc_khz) - u32 thresh_lo, thresh_hi; - int use_scaling = 0; - -+ /* tsc_khz can be zero if TSC calibration fails */ -+ if (this_tsc_khz == 0) -+ return; -+ - /* Compute a scale to convert nanoseconds in TSC cycles */ - kvm_get_time_scale(this_tsc_khz, NSEC_PER_SEC / 1000, - &vcpu->arch.virtual_tsc_shift, -@@ -1156,20 +1160,23 @@ void kvm_write_tsc(struct kvm_vcpu *vcpu, struct msr_data *msr) - ns = get_kernel_ns(); - elapsed = ns - kvm->arch.last_tsc_nsec; - -- /* n.b - signed multiplication and division required */ -- usdiff = data - kvm->arch.last_tsc_write; -+ if (vcpu->arch.virtual_tsc_khz) { -+ /* n.b - signed multiplication and division required */ -+ usdiff = data - kvm->arch.last_tsc_write; - #ifdef CONFIG_X86_64 -- usdiff = (usdiff * 1000) / vcpu->arch.virtual_tsc_khz; -+ usdiff = (usdiff * 1000) / vcpu->arch.virtual_tsc_khz; - #else -- /* do_div() only does unsigned */ -- asm("idivl %2; xor %%edx, %%edx" -- : "=A"(usdiff) -- : "A"(usdiff * 1000), "rm"(vcpu->arch.virtual_tsc_khz)); -+ /* do_div() only does unsigned */ -+ asm("idivl %2; xor %%edx, %%edx" -+ : "=A"(usdiff) -+ : "A"(usdiff * 1000), "rm"(vcpu->arch.virtual_tsc_khz)); - #endif -- do_div(elapsed, 1000); -- usdiff -= elapsed; -- if (usdiff < 0) -- usdiff = -usdiff; -+ do_div(elapsed, 1000); -+ usdiff -= elapsed; -+ if (usdiff < 0) -+ usdiff = -usdiff; -+ } else -+ usdiff = USEC_PER_SEC; /* disable TSC match window below */ - - /* - * Special case: TSC write with a small delta (1 second) of virtual diff --git a/af_key-fix-info-leaks-in-notify-messages.patch b/af_key-fix-info-leaks-in-notify-messages.patch deleted file mode 100644 index 9d20aec..0000000 --- a/af_key-fix-info-leaks-in-notify-messages.patch +++ /dev/null @@ -1,37 +0,0 @@ -From a5cc68f3d63306d0d288f31edfc2ae6ef8ecd887 Mon Sep 17 00:00:00 2001 -From: Mathias Krause -Date: Wed, 26 Jun 2013 21:52:30 +0000 -Subject: af_key: fix info leaks in notify messages - -key_notify_sa_flush() and key_notify_policy_flush() miss to initialize -the sadb_msg_reserved member of the broadcasted message and thereby -leak 2 bytes of heap memory to listeners. Fix that. - -Signed-off-by: Mathias Krause -Cc: Steffen Klassert -Cc: "David S. Miller" -Cc: Herbert Xu -Signed-off-by: David S. Miller ---- -diff --git a/net/key/af_key.c b/net/key/af_key.c -index c5fbd75..9da8620 100644 ---- a/net/key/af_key.c -+++ b/net/key/af_key.c -@@ -1710,6 +1710,7 @@ static int key_notify_sa_flush(const struct km_event *c) - hdr->sadb_msg_version = PF_KEY_V2; - hdr->sadb_msg_errno = (uint8_t) 0; - hdr->sadb_msg_len = (sizeof(struct sadb_msg) / sizeof(uint64_t)); -+ hdr->sadb_msg_reserved = 0; - - pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_ALL, NULL, c->net); - -@@ -2699,6 +2700,7 @@ static int key_notify_policy_flush(const struct km_event *c) - hdr->sadb_msg_errno = (uint8_t) 0; - hdr->sadb_msg_satype = SADB_SATYPE_UNSPEC; - hdr->sadb_msg_len = (sizeof(struct sadb_msg) / sizeof(uint64_t)); -+ hdr->sadb_msg_reserved = 0; - pfkey_broadcast(skb_out, GFP_ATOMIC, BROADCAST_ALL, NULL, c->net); - return 0; - --- -cgit v0.9.2 diff --git a/arm-omap-ehci-fix.patch b/arm-omap-ehci-fix.patch deleted file mode 100644 index f6fc0a9..0000000 --- a/arm-omap-ehci-fix.patch +++ /dev/null @@ -1,190 +0,0 @@ -From 54a419668b0f27b7982807fb2376d237e0a0ce05 Mon Sep 17 00:00:00 2001 -From: Alan Stern -Date: Tue, 12 Mar 2013 10:44:39 +0000 -Subject: USB: EHCI: split ehci-omap out to a separate driver - -This patch (as1645) converts ehci-omap over to the new "ehci-hcd is a -library" approach, so that it can coexist peacefully with other EHCI -platform drivers and can make use of the private area allocated at -the end of struct ehci_hcd. - -Signed-off-by: Alan Stern -Signed-off-by: Greg Kroah-Hartman ---- -diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig -index c59a112..62f4e9a 100644 ---- a/drivers/usb/host/Kconfig -+++ b/drivers/usb/host/Kconfig -@@ -155,7 +155,7 @@ config USB_EHCI_MXC - Variation of ARC USB block used in some Freescale chips. - - config USB_EHCI_HCD_OMAP -- bool "EHCI support for OMAP3 and later chips" -+ tristate "EHCI support for OMAP3 and later chips" - depends on USB_EHCI_HCD && ARCH_OMAP - default y - ---help--- -diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile -index 001fbff..56de410 100644 ---- a/drivers/usb/host/Makefile -+++ b/drivers/usb/host/Makefile -@@ -27,6 +27,7 @@ obj-$(CONFIG_USB_EHCI_HCD) += ehci-hcd.o - obj-$(CONFIG_USB_EHCI_PCI) += ehci-pci.o - obj-$(CONFIG_USB_EHCI_HCD_PLATFORM) += ehci-platform.o - obj-$(CONFIG_USB_EHCI_MXC) += ehci-mxc.o -+obj-$(CONFIG_USB_EHCI_HCD_OMAP) += ehci-omap.o - - obj-$(CONFIG_USB_OXU210HP_HCD) += oxu210hp-hcd.o - obj-$(CONFIG_USB_ISP116X_HCD) += isp116x-hcd.o -diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c -index b416a3f..303b022 100644 ---- a/drivers/usb/host/ehci-hcd.c -+++ b/drivers/usb/host/ehci-hcd.c -@@ -1252,11 +1252,6 @@ MODULE_LICENSE ("GPL"); - #define PLATFORM_DRIVER ehci_hcd_sh_driver - #endif - --#ifdef CONFIG_USB_EHCI_HCD_OMAP --#include "ehci-omap.c" --#define PLATFORM_DRIVER ehci_hcd_omap_driver --#endif -- - #ifdef CONFIG_PPC_PS3 - #include "ehci-ps3.c" - #define PS3_SYSTEM_BUS_DRIVER ps3_ehci_driver -@@ -1346,6 +1341,7 @@ MODULE_LICENSE ("GPL"); - !IS_ENABLED(CONFIG_USB_EHCI_HCD_PLATFORM) && \ - !IS_ENABLED(CONFIG_USB_CHIPIDEA_HOST) && \ - !IS_ENABLED(CONFIG_USB_EHCI_MXC) && \ -+ !IS_ENABLED(CONFIG_USB_EHCI_HCD_OMAP) && \ - !defined(PLATFORM_DRIVER) && \ - !defined(PS3_SYSTEM_BUS_DRIVER) && \ - !defined(OF_PLATFORM_DRIVER) && \ -diff --git a/drivers/usb/host/ehci-omap.c b/drivers/usb/host/ehci-omap.c -index 0555ee4..fa66757 100644 ---- a/drivers/usb/host/ehci-omap.c -+++ b/drivers/usb/host/ehci-omap.c -@@ -36,6 +36,9 @@ - * - convert to use hwmod and runtime PM - */ - -+#include -+#include -+#include - #include - #include - #include -@@ -43,6 +46,10 @@ - #include - #include - #include -+#include -+#include -+ -+#include "ehci.h" - - #include - -@@ -57,9 +64,11 @@ - #define EHCI_INSNREG05_ULPI_EXTREGADD_SHIFT 8 - #define EHCI_INSNREG05_ULPI_WRDATA_SHIFT 0 - --/*-------------------------------------------------------------------------*/ -+#define DRIVER_DESC "OMAP-EHCI Host Controller driver" - --static const struct hc_driver ehci_omap_hc_driver; -+static const char hcd_name[] = "ehci-omap"; -+ -+/*-------------------------------------------------------------------------*/ - - - static inline void ehci_write(void __iomem *base, u32 reg, u32 val) -@@ -166,6 +175,12 @@ static void disable_put_regulator( - /* configure so an HC device and id are always provided */ - /* always called with process context; sleeping is OK */ - -+static struct hc_driver __read_mostly ehci_omap_hc_driver; -+ -+static const struct ehci_driver_overrides ehci_omap_overrides __initdata = { -+ .reset = omap_ehci_init, -+}; -+ - /** - * ehci_hcd_omap_probe - initialize TI-based HCDs - * -@@ -315,56 +330,33 @@ static struct platform_driver ehci_hcd_omap_driver = { - /*.suspend = ehci_hcd_omap_suspend, */ - /*.resume = ehci_hcd_omap_resume, */ - .driver = { -- .name = "ehci-omap", -+ .name = hcd_name, - } - }; - - /*-------------------------------------------------------------------------*/ - --static const struct hc_driver ehci_omap_hc_driver = { -- .description = hcd_name, -- .product_desc = "OMAP-EHCI Host Controller", -- .hcd_priv_size = sizeof(struct ehci_hcd), -- -- /* -- * generic hardware linkage -- */ -- .irq = ehci_irq, -- .flags = HCD_MEMORY | HCD_USB2, -- -- /* -- * basic lifecycle operations -- */ -- .reset = omap_ehci_init, -- .start = ehci_run, -- .stop = ehci_stop, -- .shutdown = ehci_shutdown, -- -- /* -- * managing i/o requests and associated device resources -- */ -- .urb_enqueue = ehci_urb_enqueue, -- .urb_dequeue = ehci_urb_dequeue, -- .endpoint_disable = ehci_endpoint_disable, -- .endpoint_reset = ehci_endpoint_reset, -+static int __init ehci_omap_init(void) -+{ -+ if (usb_disabled()) -+ return -ENODEV; - -- /* -- * scheduling support -- */ -- .get_frame_number = ehci_get_frame, -+ pr_info("%s: " DRIVER_DESC "\n", hcd_name); - -- /* -- * root hub support -- */ -- .hub_status_data = ehci_hub_status_data, -- .hub_control = ehci_hub_control, -- .bus_suspend = ehci_bus_suspend, -- .bus_resume = ehci_bus_resume, -+ ehci_init_driver(&ehci_omap_hc_driver, &ehci_omap_overrides); -+ return platform_driver_register(&ehci_hcd_omap_driver); -+} -+module_init(ehci_omap_init); - -- .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, --}; -+static void __exit ehci_omap_cleanup(void) -+{ -+ platform_driver_unregister(&ehci_hcd_omap_driver); -+} -+module_exit(ehci_omap_cleanup); - - MODULE_ALIAS("platform:ehci-omap"); - MODULE_AUTHOR("Texas Instruments, Inc."); - MODULE_AUTHOR("Felipe Balbi "); - -+MODULE_DESCRIPTION(DRIVER_DESC); -+MODULE_LICENSE("GPL"); --- -cgit v0.9.1 diff --git a/arm-omap-fixdrm.patch b/arm-omap-fixdrm.patch deleted file mode 100644 index e0eec80..0000000 --- a/arm-omap-fixdrm.patch +++ /dev/null @@ -1,19 +0,0 @@ -diff --git a/drivers/gpu/drm/omapdrm/omap_plane.c b/drivers/gpu/drm/omapdrm/omap_plane.c -index 2882cda..8d225d7 100644 ---- a/drivers/gpu/drm/omapdrm/omap_plane.c -+++ b/drivers/gpu/drm/omapdrm/omap_plane.c -@@ -247,6 +247,12 @@ static int omap_plane_update(struct drm_plane *plane, - { - struct omap_plane *omap_plane = to_omap_plane(plane); - omap_plane->enabled = true; -+ -+ if (plane->fb) -+ drm_framebuffer_unreference(plane->fb); -+ -+ drm_framebuffer_reference(fb); -+ - return omap_plane_mode_set(plane, crtc, fb, - crtc_x, crtc_y, crtc_w, crtc_h, - src_x, src_y, src_w, src_h, - - diff --git a/block-do-not-pass-disk-names-as-format-strings.patch b/block-do-not-pass-disk-names-as-format-strings.patch deleted file mode 100644 index 496111d..0000000 --- a/block-do-not-pass-disk-names-as-format-strings.patch +++ /dev/null @@ -1,64 +0,0 @@ -Disk names may contain arbitrary strings, so they must not be interpreted -as format strings. It seems that only md allows arbitrary strings to be -used for disk names, but this could allow for a local memory corruption -from uid 0 into ring 0. - -CVE-2013-2851 - -Signed-off-by: Kees Cook -Cc: stable@vger.kernel.org -Cc: Jens Axboe ---- - block/genhd.c | 2 +- - drivers/block/nbd.c | 3 ++- - drivers/scsi/osd/osd_uld.c | 2 +- - 3 files changed, 4 insertions(+), 3 deletions(-) - -diff --git a/block/genhd.c b/block/genhd.c -index 20625ee..cdeb527 100644 ---- a/block/genhd.c -+++ b/block/genhd.c -@@ -512,7 +512,7 @@ static void register_disk(struct gendisk *disk) - - ddev->parent = disk->driverfs_dev; - -- dev_set_name(ddev, disk->disk_name); -+ dev_set_name(ddev, "%s", disk->disk_name); - - /* delay uevents, until we scanned partition table */ - dev_set_uevent_suppress(ddev, 1); -diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c -index 037288e..46b35f7 100644 ---- a/drivers/block/nbd.c -+++ b/drivers/block/nbd.c -@@ -714,7 +714,8 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *nbd, - else - blk_queue_flush(nbd->disk->queue, 0); - -- thread = kthread_create(nbd_thread, nbd, nbd->disk->disk_name); -+ thread = kthread_create(nbd_thread, nbd, "%s", -+ nbd->disk->disk_name); - if (IS_ERR(thread)) { - mutex_lock(&nbd->tx_lock); - return PTR_ERR(thread); -diff --git a/drivers/scsi/osd/osd_uld.c b/drivers/scsi/osd/osd_uld.c -index 0fab6b5..9d86947 100644 ---- a/drivers/scsi/osd/osd_uld.c -+++ b/drivers/scsi/osd/osd_uld.c -@@ -485,7 +485,7 @@ static int osd_probe(struct device *dev) - oud->class_dev.class = &osd_uld_class; - oud->class_dev.parent = dev; - oud->class_dev.release = __remove; -- error = dev_set_name(&oud->class_dev, disk->disk_name); -+ error = dev_set_name(&oud->class_dev, "%s", disk->disk_name); - if (error) { - OSD_ERR("dev_set_name failed => %d\n", error); - goto err_put_cdev; --- -1.7.9.5 - --- -To unsubscribe from this list: send the line "unsubscribe linux-kernel" in -the body of a message to majordomo@vger.kernel.org -More majordomo info at http://vger.kernel.org/majordomo-info.html -Please read the FAQ at http://www.tux.org/lkml/ \ No newline at end of file diff --git a/cdrom-use-kzalloc-for-failing-hardware.patch b/cdrom-use-kzalloc-for-failing-hardware.patch deleted file mode 100644 index 6afb6c4..0000000 --- a/cdrom-use-kzalloc-for-failing-hardware.patch +++ /dev/null @@ -1,45 +0,0 @@ -From 050e4b8fb7cdd7096c987a9cd556029c622c7fe2 Mon Sep 17 00:00:00 2001 -From: Jonathan Salwan -Date: Thu, 06 Jun 2013 00:39:39 +0000 -Subject: drivers/cdrom/cdrom.c: use kzalloc() for failing hardware - -In drivers/cdrom/cdrom.c mmc_ioctl_cdrom_read_data() allocates a memory -area with kmalloc in line 2885. - -2885 cgc->buffer = kmalloc(blocksize, GFP_KERNEL); -2886 if (cgc->buffer == NULL) -2887 return -ENOMEM; - -In line 2908 we can find the copy_to_user function: - -2908 if (!ret && copy_to_user(arg, cgc->buffer, blocksize)) - -The cgc->buffer is never cleaned and initialized before this function. If -ret = 0 with the previous basic block, it's possible to display some -memory bytes in kernel space from userspace. - -When we read a block from the disk it normally fills the ->buffer but if -the drive is malfunctioning there is a chance that it would only be -partially filled. The result is an leak information to userspace. - -Signed-off-by: Dan Carpenter -Cc: Jens Axboe -Signed-off-by: Andrew Morton ---- -(limited to 'drivers/cdrom/cdrom.c') - -diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c -index d620b44..8a3aff7 100644 ---- a/drivers/cdrom/cdrom.c -+++ b/drivers/cdrom/cdrom.c -@@ -2882,7 +2882,7 @@ static noinline int mmc_ioctl_cdrom_read_data(struct cdrom_device_info *cdi, - if (lba < 0) - return -EINVAL; - -- cgc->buffer = kmalloc(blocksize, GFP_KERNEL); -+ cgc->buffer = kzalloc(blocksize, GFP_KERNEL); - if (cgc->buffer == NULL) - return -ENOMEM; - --- -cgit v0.9.2 diff --git a/config-debug b/config-debug index ad06116..e7f7ce1 100644 --- a/config-debug +++ b/config-debug @@ -117,3 +117,7 @@ CONFIG_MAC80211_MESSAGE_TRACING=y CONFIG_EDAC_DEBUG=y CONFIG_LATENCYTOP=y CONFIG_SCHEDSTATS=y + +CONFIG_TEST_STRING_HELPERS=m +CONFIG_XFS_WARN=y + diff --git a/config-generic b/config-generic index f00a437..46ba526 100644 --- a/config-generic +++ b/config-generic @@ -4713,3 +4713,60 @@ CONFIG_IOMMU_SUPPORT=y # CONFIG_CRYPTO_KEY_TYPE is not set # CONFIG_PGP_LIBRARY is not set # CONFIG_PGP_PRELOAD is not set + + +# F19 3.10 rebase options below + +# CONFIG_ATH6KL_TRACING is not set +CONFIG_BATMAN_ADV_NC=y +# CONFIG_BCACHE_CLOSURES_DEBUG is not set +# CONFIG_BCACHE_DEBUG is not set +# CONFIG_BCACHE_EDEBUG is not set +CONFIG_BCACHE=m +CONFIG_BINFMT_SCRIPT=y +CONFIG_BOUNCE=y +# CONFIG_BTRFS_DEBUG is not set +# CONFIG_BTRFS_FS_RUN_SANITY_TESTS is not set +CONFIG_CRYPTO_CMAC=m +# CONFIG_DUMMY_IRQ is not set +# CONFIG_FB_SIMPLE is not set +# CONFIG_GPIO_GRGPIO is not set +CONFIG_HID_APPLEIR=m +# CONFIG_INPUT_IMS_PCU is not set +CONFIG_LEDS_LP5562=m +CONFIG_LEDS_TRIGGER_CAMERA=m +# CONFIG_MFD_CROS_EC is not set +# CONFIG_MFD_SI476X_CORE is not set +CONFIG_NETLINK_DIAG=m +CONFIG_NETLINK_MMAP=y +CONFIG_NET_TEAM_MODE_RANDOM=m +# CONFIG_RCU_USER_QS is not set +# CONFIG_RESET_CONTROLLER is not set +# CONFIG_RING_BUFFER_STARTUP_TEST is not set +CONFIG_RT2800USB_RT55XX=y +# CONFIG_SCSI_UFSHCD_PLATFORM is not set +CONFIG_SENSORS_ADT7310=m +CONFIG_SENSORS_LM95234=m +CONFIG_SENSORS_NCT6775=m +# CONFIG_SERIO_APBPS2 is not set +# CONFIG_SMS_SIANO_DEBUGFS is not set +# CONFIG_SRAM is not set +# CONFIG_SSBI is not set +# CONFIG_TRACER_SNAPSHOT_PER_CPU_SWAP is not set +CONFIG_USB_DEFAULT_PERSIST=y +CONFIG_USB_PHY=y +CONFIG_USB_RTL8152=m +# CONFIG_USB_SERIAL_WISHBONE is not set +# CONFIG_W1_SLAVE_DS2408_READBACK is not set +# CONFIG_SAMSUNG_USB2PHY is not set +# CONFIG_SAMSUNG_USB3PHY is not set +CONFIG_ALX=m +CONFIG_INFINIBAND_ISERT=m +CONFIG_QLCNIC_SRIOV=y +CONFIG_RTL8188EE=m +# CONFIG_SAMSUNG_USBPHY is not set +# CONFIG_TIPC_MEDIA_IB is not set +# CONFIG_USB_DWC2 is not set +CONFIG_VHOST_SCSI=m +# CONFIG_MFD_TPS65912 is not set +# CONFIG_MFD_SYSCON is not set diff --git a/config-nodebug b/config-nodebug index 6db2dde..12ecfcc 100644 --- a/config-nodebug +++ b/config-nodebug @@ -119,3 +119,7 @@ CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y # CONFIG_SPI_DEBUG is not set # CONFIG_LATENCYTOP is not set # CONFIG_SCHEDSTATS is not set + +# CONFIG_TEST_STRING_HELPERS is not set +# CONFIG_XFS_WARN is not set + diff --git a/config-powerpc-generic b/config-powerpc-generic index b6df88e..e861723 100644 --- a/config-powerpc-generic +++ b/config-powerpc-generic @@ -392,3 +392,5 @@ CONFIG_BACKLIGHT_PWM=m CONFIG_CPU_IDLE_MULTIPLE_DRIVERS=n CONFIG_XZ_DEC_POWERPC=y + +# CONFIG_POWERNV_MSI is not set diff --git a/config-powerpc64 b/config-powerpc64 index d0e0aab..02a44d8 100644 --- a/config-powerpc64 +++ b/config-powerpc64 @@ -181,3 +181,6 @@ CONFIG_BPF_JIT=y # CONFIG_PPC_TRANSACTIONAL_MEM is not set # CONFIG_SND_HDA_INTEL is not set CONFIG_BLK_DEV_RSXX=m + +CONFIG_POWERNV_MSI=y +CONFIG_KVM_XICS=y diff --git a/config-powerpc64p7 b/config-powerpc64p7 index 285d9ff..ff44710 100644 --- a/config-powerpc64p7 +++ b/config-powerpc64p7 @@ -171,3 +171,6 @@ CONFIG_BPF_JIT=y # CONFIG_PCIEPORTBUS is not set # CONFIG_SND_HDA_INTEL is not set CONFIG_BLK_DEV_RSXX=m + +CONFIG_POWERNV_MSI=y +CONFIG_KVM_XICS=y diff --git a/config-x86-generic b/config-x86-generic index 6804135..f00827c 100644 --- a/config-x86-generic +++ b/config-x86-generic @@ -459,3 +459,14 @@ CONFIG_MODULE_SIG_UEFI=y CONFIG_VMXNET3=m CONFIG_VFIO_PCI_VGA=y + +CONFIG_EFIVAR_FS=y +CONFIG_HYPERVISOR_GUEST=y +CONFIG_KVM_DEVICE_ASSIGNMENT=y +CONFIG_NFC_MEI_PHY=m +CONFIG_PVPANIC=m +CONFIG_X86_AMD_FREQ_SENSITIVITY=m +CONFIG_FB_HYPERV=m +CONFIG_NFC_MICROREAD_MEI=m +CONFIG_NFC_PN544_MEI=m + diff --git a/config-x86_64-generic b/config-x86_64-generic index 92f2830..65e6a68 100644 --- a/config-x86_64-generic +++ b/config-x86_64-generic @@ -157,3 +157,8 @@ CONFIG_SFC_MTD=y CONFIG_MTD_CHAR=m CONFIG_MTD_BLOCK=m +CONFIG_CRYPTO_CAMELLIA_AESNI_AVX2_X86_64=m +CONFIG_CRYPTO_SERPENT_AVX2_X86_64=m +CONFIG_CRYPTO_SHA256_SSSE3=m +CONFIG_CRYPTO_SHA512_SSSE3=m + diff --git a/debug-bad-pte-dmi.patch b/debug-bad-pte-dmi.patch deleted file mode 100644 index eddd595..0000000 --- a/debug-bad-pte-dmi.patch +++ /dev/null @@ -1,66 +0,0 @@ ---- linux.orig/include/asm-generic/bug.h -+++ linux/include/asm-generic/bug.h -@@ -55,6 +55,8 @@ struct bug_entry { - #define BUG_ON(condition) do { if (unlikely(condition)) BUG(); } while(0) - #endif - -+void print_hardware_dmi_name(void); -+ - /* - * WARN(), WARN_ON(), WARN_ON_ONCE, and so on can be used to report - * significant issues that need prompt attention if they should ever ---- linux.orig/kernel/panic.c -+++ linux/kernel/panic.c -@@ -391,6 +391,15 @@ void oops_exit(void) - kmsg_dump(KMSG_DUMP_OOPS); - } - -+void print_hardware_dmi_name(void) -+{ -+ const char *board; -+ -+ board = dmi_get_system_info(DMI_PRODUCT_NAME); -+ if (board) -+ printk(KERN_WARNING "Hardware name: %s\n", board); -+} -+ - #ifdef WANT_WARN_ON_SLOWPATH - struct slowpath_args { - const char *fmt; -@@ -400,13 +409,10 @@ struct slowpath_args { - static void warn_slowpath_common(const char *file, int line, void *caller, - unsigned taint, struct slowpath_args *args) - { -- const char *board; -- - printk(KERN_WARNING "------------[ cut here ]------------\n"); - printk(KERN_WARNING "WARNING: at %s:%d %pS()\n", file, line, caller); -- board = dmi_get_system_info(DMI_PRODUCT_NAME); -- if (board) -- printk(KERN_WARNING "Hardware name: %s\n", board); -+ -+ print_hardware_dmi_name(); - - if (args) - vprintk(args->fmt, args->args); ---- linux.orig/mm/memory.c -+++ linux/mm/memory.c -@@ -706,6 +706,8 @@ static void print_bad_pte(struct vm_area - "BUG: Bad page map in process %s pte:%08llx pmd:%08llx\n", - current->comm, - (long long)pte_val(pte), (long long)pmd_val(*pmd)); -+ print_hardware_dmi_name(); -+ - if (page) - dump_page(page); - printk(KERN_ALERT ---- linux.orig/mm/page_alloc.c -+++ linux/mm/page_alloc.c -@@ -321,6 +321,7 @@ static void bad_page(struct page *page) - current->comm, page_to_pfn(page)); - dump_page(page); - -+ print_hardware_dmi_name(); - print_modules(); - dump_stack(); - out: diff --git a/debug-bad-pte-modules.patch b/debug-bad-pte-modules.patch deleted file mode 100644 index 88ca280..0000000 --- a/debug-bad-pte-modules.patch +++ /dev/null @@ -1,20 +0,0 @@ -diff -durpN '--exclude-from=/home/davej/.exclude' /home/davej/src/kernel/git-trees/linux/mm/memory.c linux-dj/mm/memory.c ---- /home/davej/src/kernel/git-trees/linux/mm/memory.c 2013-02-26 14:41:18.591116577 -0500 -+++ linux-dj/mm/memory.c 2013-02-28 20:04:37.678304092 -0500 -@@ -57,6 +57,7 @@ - #include - #include - #include -+#include - #include - #include - -@@ -719,6 +722,7 @@ static void print_bad_pte(struct vm_area - if (vma->vm_file && vma->vm_file->f_op) - print_symbol(KERN_ALERT "vma->vm_file->f_op->mmap: %s\n", - (unsigned long)vma->vm_file->f_op->mmap); -+ print_modules(); - dump_stack(); - add_taint(TAINT_BAD_PAGE, LOCKDEP_NOW_UNRELIABLE); - } - diff --git a/drm-i915-dp-stfu.patch b/drm-i915-dp-stfu.patch index 78fb5fe..fb2e58e 100644 --- a/drm-i915-dp-stfu.patch +++ b/drm-i915-dp-stfu.patch @@ -1,17 +1,17 @@ diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c -index f61cb79..64a24c0 100644 +index fb2fbc1..0aaf67d 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c -@@ -315,7 +315,7 @@ intel_dp_check_edp(struct intel_dp *intel_dp) - if (!is_edp(intel_dp)) - return; +@@ -283,7 +283,7 @@ intel_dp_check_edp(struct intel_dp *intel_dp) + pp_ctrl_reg = IS_VALLEYVIEW(dev) ? PIPEA_PP_CONTROL : PCH_PP_CONTROL; + if (!ironlake_edp_have_panel_power(intel_dp) && !ironlake_edp_have_panel_vdd(intel_dp)) { - WARN(1, "eDP powered off while attempting aux channel communication.\n"); + DRM_ERROR("eDP powered off while attempting aux channel communication.\n"); DRM_DEBUG_KMS("Status 0x%08x Control 0x%08x\n", - I915_READ(PCH_PP_STATUS), - I915_READ(PCH_PP_CONTROL)); -@@ -446,7 +446,7 @@ intel_dp_aux_ch(struct intel_dp *intel_dp, + I915_READ(pp_stat_reg), + I915_READ(pp_ctrl_reg)); +@@ -376,7 +376,7 @@ intel_dp_aux_ch(struct intel_dp *intel_dp, } if (try == 3) { @@ -20,7 +20,7 @@ index f61cb79..64a24c0 100644 I915_READ(ch_ctl)); ret = -EBUSY; goto out; -@@ -1083,8 +1083,8 @@ void ironlake_edp_panel_vdd_on(struct intel_dp *intel_dp) +@@ -995,8 +995,8 @@ void ironlake_edp_panel_vdd_on(struct intel_dp *intel_dp) return; DRM_DEBUG_KMS("Turn eDP VDD on\n"); @@ -31,7 +31,7 @@ index f61cb79..64a24c0 100644 intel_dp->want_panel_vdd = true; -@@ -1151,7 +1151,8 @@ void ironlake_edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync) +@@ -1070,7 +1070,8 @@ void ironlake_edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync) return; DRM_DEBUG_KMS("Turn eDP VDD off %d\n", intel_dp->want_panel_vdd); @@ -41,7 +41,7 @@ index f61cb79..64a24c0 100644 intel_dp->want_panel_vdd = false; -@@ -1221,7 +1222,8 @@ void ironlake_edp_panel_off(struct intel_dp *intel_dp) +@@ -1144,7 +1145,8 @@ void ironlake_edp_panel_off(struct intel_dp *intel_dp) DRM_DEBUG_KMS("Turn eDP power off\n"); @@ -49,5 +49,5 @@ index f61cb79..64a24c0 100644 + if (!intel_dp->want_panel_vdd) + DRM_ERROR("Need VDD to turn off panel\n"); - pp = ironlake_get_pp_control(dev_priv); + pp = ironlake_get_pp_control(intel_dp); /* We need to switch off panel power _and_ force vdd, for otherwise some diff --git a/drm-qxl-3.10-rc7-diff.patch b/drm-qxl-3.10-rc7-diff.patch deleted file mode 100644 index 3aa53f6..0000000 --- a/drm-qxl-3.10-rc7-diff.patch +++ /dev/null @@ -1,593 +0,0 @@ -From be71369a5b4297776fb9988e6274595136294588 Mon Sep 17 00:00:00 2001 -From: Dave Airlie -Date: Tue, 16 Apr 2013 13:24:25 +1000 -Subject: [PATCH 4/5] drm/qxl 3.10-rc7 diff - -drm/qxl: make lots of things static. -drm/qxl: fix smatch warnings -drm/qxl: fix build with debugfs turned off. -drivers, drm: fix qxl build error when debugfs is disabled -drm/qxl: fix ioport interactions for kernel submitted commands. -qxl: drop unused variable. -drm/qxl: drop active_user_framebuffer as its unneeded -qxl: fix bug with object eviction and update area -qxl: fix Kconfig deps - select FB_DEFERRED_IO -drm/qxl: fix build warnings on 32-bit - -Signed-off-by: Dave Airlie ---- - drivers/gpu/drm/qxl/Kconfig | 1 + - drivers/gpu/drm/qxl/qxl_cmd.c | 52 +++++++++++++++++---------------------- - drivers/gpu/drm/qxl/qxl_debugfs.c | 6 +++++ - drivers/gpu/drm/qxl/qxl_display.c | 36 +++++++++++---------------- - drivers/gpu/drm/qxl/qxl_drv.c | 2 +- - drivers/gpu/drm/qxl/qxl_drv.h | 7 ------ - drivers/gpu/drm/qxl/qxl_fb.c | 2 +- - drivers/gpu/drm/qxl/qxl_gem.c | 29 ---------------------- - drivers/gpu/drm/qxl/qxl_ioctl.c | 29 +++++++++++----------- - drivers/gpu/drm/qxl/qxl_kms.c | 11 +++++---- - drivers/gpu/drm/qxl/qxl_object.c | 6 ++--- - drivers/gpu/drm/qxl/qxl_release.c | 4 +-- - drivers/gpu/drm/qxl/qxl_ttm.c | 10 +++++--- - 13 files changed, 78 insertions(+), 117 deletions(-) - -diff --git a/drivers/gpu/drm/qxl/Kconfig b/drivers/gpu/drm/qxl/Kconfig -index 2f1a57e..d6c1279 100644 ---- a/drivers/gpu/drm/qxl/Kconfig -+++ b/drivers/gpu/drm/qxl/Kconfig -@@ -4,6 +4,7 @@ config DRM_QXL - select FB_SYS_FILLRECT - select FB_SYS_COPYAREA - select FB_SYS_IMAGEBLIT -+ select FB_DEFERRED_IO - select DRM_KMS_HELPER - select DRM_TTM - help -diff --git a/drivers/gpu/drm/qxl/qxl_cmd.c b/drivers/gpu/drm/qxl/qxl_cmd.c -index 804b411..02befd9 100644 ---- a/drivers/gpu/drm/qxl/qxl_cmd.c -+++ b/drivers/gpu/drm/qxl/qxl_cmd.c -@@ -144,8 +144,8 @@ int qxl_ring_push(struct qxl_ring *ring, - return 0; - } - --bool qxl_ring_pop(struct qxl_ring *ring, -- void *element) -+static bool qxl_ring_pop(struct qxl_ring *ring, -+ void *element) - { - volatile struct qxl_ring_header *header = &(ring->ring->header); - volatile uint8_t *ring_elt; -@@ -169,23 +169,6 @@ bool qxl_ring_pop(struct qxl_ring *ring, - return true; - } - --void qxl_ring_wait_idle(struct qxl_ring *ring) --{ -- struct qxl_ring_header *header = &(ring->ring->header); -- unsigned long flags; -- -- spin_lock_irqsave(&ring->lock, flags); -- if (ring->ring->header.cons < ring->ring->header.prod) { -- header->notify_on_cons = header->prod; -- mb(); -- spin_unlock_irqrestore(&ring->lock, flags); -- wait_event_interruptible(*ring->push_event, -- qxl_check_idle(ring)); -- spin_lock_irqsave(&ring->lock, flags); -- } -- spin_unlock_irqrestore(&ring->lock, flags); --} -- - int - qxl_push_command_ring_release(struct qxl_device *qdev, struct qxl_release *release, - uint32_t type, bool interruptible) -@@ -294,7 +277,7 @@ out_unref: - return 0; - } - --static int wait_for_io_cmd_user(struct qxl_device *qdev, uint8_t val, long port) -+static int wait_for_io_cmd_user(struct qxl_device *qdev, uint8_t val, long port, bool intr) - { - int irq_num; - long addr = qdev->io_base + port; -@@ -302,20 +285,29 @@ static int wait_for_io_cmd_user(struct qxl_device *qdev, uint8_t val, long port) - - mutex_lock(&qdev->async_io_mutex); - irq_num = atomic_read(&qdev->irq_received_io_cmd); -- -- - if (qdev->last_sent_io_cmd > irq_num) { -- ret = wait_event_interruptible(qdev->io_cmd_event, -- atomic_read(&qdev->irq_received_io_cmd) > irq_num); -- if (ret) -+ if (intr) -+ ret = wait_event_interruptible_timeout(qdev->io_cmd_event, -+ atomic_read(&qdev->irq_received_io_cmd) > irq_num, 5*HZ); -+ else -+ ret = wait_event_timeout(qdev->io_cmd_event, -+ atomic_read(&qdev->irq_received_io_cmd) > irq_num, 5*HZ); -+ /* 0 is timeout, just bail the "hw" has gone away */ -+ if (ret <= 0) - goto out; - irq_num = atomic_read(&qdev->irq_received_io_cmd); - } - outb(val, addr); - qdev->last_sent_io_cmd = irq_num + 1; -- ret = wait_event_interruptible(qdev->io_cmd_event, -- atomic_read(&qdev->irq_received_io_cmd) > irq_num); -+ if (intr) -+ ret = wait_event_interruptible_timeout(qdev->io_cmd_event, -+ atomic_read(&qdev->irq_received_io_cmd) > irq_num, 5*HZ); -+ else -+ ret = wait_event_timeout(qdev->io_cmd_event, -+ atomic_read(&qdev->irq_received_io_cmd) > irq_num, 5*HZ); - out: -+ if (ret > 0) -+ ret = 0; - mutex_unlock(&qdev->async_io_mutex); - return ret; - } -@@ -325,7 +317,7 @@ static void wait_for_io_cmd(struct qxl_device *qdev, uint8_t val, long port) - int ret; - - restart: -- ret = wait_for_io_cmd_user(qdev, val, port); -+ ret = wait_for_io_cmd_user(qdev, val, port, false); - if (ret == -ERESTARTSYS) - goto restart; - } -@@ -357,7 +349,7 @@ int qxl_io_update_area(struct qxl_device *qdev, struct qxl_bo *surf, - mutex_lock(&qdev->update_area_mutex); - qdev->ram_header->update_area = *area; - qdev->ram_header->update_surface = surface_id; -- ret = wait_for_io_cmd_user(qdev, 0, QXL_IO_UPDATE_AREA_ASYNC); -+ ret = wait_for_io_cmd_user(qdev, 0, QXL_IO_UPDATE_AREA_ASYNC, true); - mutex_unlock(&qdev->update_area_mutex); - return ret; - } -@@ -609,7 +601,7 @@ retry: - return ret; - } - --void qxl_surface_evict_locked(struct qxl_device *qdev, struct qxl_bo *surf, bool do_update_area) -+static void qxl_surface_evict_locked(struct qxl_device *qdev, struct qxl_bo *surf, bool do_update_area) - { - /* no need to update area if we are just freeing the surface normally */ - if (do_update_area) -diff --git a/drivers/gpu/drm/qxl/qxl_debugfs.c b/drivers/gpu/drm/qxl/qxl_debugfs.c -index c630152..c3c2bbd 100644 ---- a/drivers/gpu/drm/qxl/qxl_debugfs.c -+++ b/drivers/gpu/drm/qxl/qxl_debugfs.c -@@ -35,6 +35,7 @@ - #include "qxl_object.h" - - -+#if defined(CONFIG_DEBUG_FS) - static int - qxl_debugfs_irq_received(struct seq_file *m, void *data) - { -@@ -69,20 +70,25 @@ static struct drm_info_list qxl_debugfs_list[] = { - { "qxl_buffers", qxl_debugfs_buffers_info, 0, NULL }, - }; - #define QXL_DEBUGFS_ENTRIES ARRAY_SIZE(qxl_debugfs_list) -+#endif - - int - qxl_debugfs_init(struct drm_minor *minor) - { -+#if defined(CONFIG_DEBUG_FS) - drm_debugfs_create_files(qxl_debugfs_list, QXL_DEBUGFS_ENTRIES, - minor->debugfs_root, minor); -+#endif - return 0; - } - - void - qxl_debugfs_takedown(struct drm_minor *minor) - { -+#if defined(CONFIG_DEBUG_FS) - drm_debugfs_remove_files(qxl_debugfs_list, QXL_DEBUGFS_ENTRIES, - minor); -+#endif - } - - int qxl_debugfs_add_files(struct qxl_device *qdev, -diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c -index c80ddfe..823d29e 100644 ---- a/drivers/gpu/drm/qxl/qxl_display.c -+++ b/drivers/gpu/drm/qxl/qxl_display.c -@@ -84,6 +84,7 @@ void qxl_alloc_client_monitors_config(struct qxl_device *qdev, unsigned count) - if (qdev->client_monitors_config && - count > qdev->client_monitors_config->count) { - kfree(qdev->client_monitors_config); -+ qdev->client_monitors_config = NULL; - } - if (!qdev->client_monitors_config) { - qdev->client_monitors_config = kzalloc( -@@ -413,11 +414,11 @@ static void qxl_user_framebuffer_destroy(struct drm_framebuffer *fb) - kfree(qxl_fb); - } - --int qxl_framebuffer_surface_dirty(struct drm_framebuffer *fb, -- struct drm_file *file_priv, -- unsigned flags, unsigned color, -- struct drm_clip_rect *clips, -- unsigned num_clips) -+static int qxl_framebuffer_surface_dirty(struct drm_framebuffer *fb, -+ struct drm_file *file_priv, -+ unsigned flags, unsigned color, -+ struct drm_clip_rect *clips, -+ unsigned num_clips) - { - /* TODO: vmwgfx where this was cribbed from had locking. Why? */ - struct qxl_framebuffer *qxl_fb = to_qxl_framebuffer(fb); -@@ -427,10 +428,10 @@ int qxl_framebuffer_surface_dirty(struct drm_framebuffer *fb, - int inc = 1; - - qobj = gem_to_qxl_bo(qxl_fb->obj); -- if (qxl_fb != qdev->active_user_framebuffer) { -- DRM_INFO("%s: qxl_fb 0x%p != qdev->active_user_framebuffer 0x%p\n", -- __func__, qxl_fb, qdev->active_user_framebuffer); -- } -+ /* if we aren't primary surface ignore this */ -+ if (!qobj->is_primary) -+ return 0; -+ - if (!num_clips) { - num_clips = 1; - clips = &norect; -@@ -603,7 +604,6 @@ static int qxl_crtc_mode_set(struct drm_crtc *crtc, - mode->hdisplay, - mode->vdisplay); - } -- qdev->mode_set = true; - return 0; - } - -@@ -619,7 +619,7 @@ static void qxl_crtc_commit(struct drm_crtc *crtc) - DRM_DEBUG("\n"); - } - --void qxl_crtc_load_lut(struct drm_crtc *crtc) -+static void qxl_crtc_load_lut(struct drm_crtc *crtc) - { - DRM_DEBUG("\n"); - } -@@ -633,7 +633,7 @@ static const struct drm_crtc_helper_funcs qxl_crtc_helper_funcs = { - .load_lut = qxl_crtc_load_lut, - }; - --int qdev_crtc_init(struct drm_device *dev, int num_crtc) -+static int qdev_crtc_init(struct drm_device *dev, int num_crtc) - { - struct qxl_crtc *qxl_crtc; - -@@ -764,7 +764,7 @@ static int qxl_conn_mode_valid(struct drm_connector *connector, - return MODE_OK; - } - --struct drm_encoder *qxl_best_encoder(struct drm_connector *connector) -+static struct drm_encoder *qxl_best_encoder(struct drm_connector *connector) - { - struct qxl_output *qxl_output = - drm_connector_to_qxl_output(connector); -@@ -855,7 +855,7 @@ static const struct drm_encoder_funcs qxl_enc_funcs = { - .destroy = qxl_enc_destroy, - }; - --int qdev_output_init(struct drm_device *dev, int num_output) -+static int qdev_output_init(struct drm_device *dev, int num_output) - { - struct qxl_output *qxl_output; - struct drm_connector *connector; -@@ -892,7 +892,6 @@ qxl_user_framebuffer_create(struct drm_device *dev, - { - struct drm_gem_object *obj; - struct qxl_framebuffer *qxl_fb; -- struct qxl_device *qdev = dev->dev_private; - int ret; - - obj = drm_gem_object_lookup(dev, file_priv, mode_cmd->handles[0]); -@@ -908,13 +907,6 @@ qxl_user_framebuffer_create(struct drm_device *dev, - return NULL; - } - -- if (qdev->active_user_framebuffer) { -- DRM_INFO("%s: active_user_framebuffer %p -> %p\n", -- __func__, -- qdev->active_user_framebuffer, qxl_fb); -- } -- qdev->active_user_framebuffer = qxl_fb; -- - return &qxl_fb->base; - } - -diff --git a/drivers/gpu/drm/qxl/qxl_drv.c b/drivers/gpu/drm/qxl/qxl_drv.c -index d337da0..aa291d8 100644 ---- a/drivers/gpu/drm/qxl/qxl_drv.c -+++ b/drivers/gpu/drm/qxl/qxl_drv.c -@@ -46,7 +46,7 @@ static DEFINE_PCI_DEVICE_TABLE(pciidlist) = { - }; - MODULE_DEVICE_TABLE(pci, pciidlist); - --int qxl_modeset = -1; -+static int qxl_modeset = -1; - - MODULE_PARM_DESC(modeset, "Disable/Enable modesetting"); - module_param_named(modeset, qxl_modeset, int, 0400); -diff --git a/drivers/gpu/drm/qxl/qxl_drv.h b/drivers/gpu/drm/qxl/qxl_drv.h -index 52b582c..43d06ab 100644 ---- a/drivers/gpu/drm/qxl/qxl_drv.h -+++ b/drivers/gpu/drm/qxl/qxl_drv.h -@@ -255,12 +255,6 @@ struct qxl_device { - struct qxl_gem gem; - struct qxl_mode_info mode_info; - -- /* -- * last created framebuffer with fb_create -- * only used by debugfs dumbppm -- */ -- struct qxl_framebuffer *active_user_framebuffer; -- - struct fb_info *fbdev_info; - struct qxl_framebuffer *fbdev_qfb; - void *ram_physical; -@@ -270,7 +264,6 @@ struct qxl_device { - struct qxl_ring *cursor_ring; - - struct qxl_ram_header *ram_header; -- bool mode_set; - - bool primary_created; - -diff --git a/drivers/gpu/drm/qxl/qxl_fb.c b/drivers/gpu/drm/qxl/qxl_fb.c -index 232b52b..b3c5127 100644 ---- a/drivers/gpu/drm/qxl/qxl_fb.c -+++ b/drivers/gpu/drm/qxl/qxl_fb.c -@@ -159,7 +159,7 @@ static void qxl_deferred_io(struct fb_info *info, - }; - - --struct fb_deferred_io qxl_defio = { -+static struct fb_deferred_io qxl_defio = { - .delay = QXL_DIRTY_DELAY, - .deferred_io = qxl_deferred_io, - }; -diff --git a/drivers/gpu/drm/qxl/qxl_gem.c b/drivers/gpu/drm/qxl/qxl_gem.c -index adc1ee2..a235693 100644 ---- a/drivers/gpu/drm/qxl/qxl_gem.c -+++ b/drivers/gpu/drm/qxl/qxl_gem.c -@@ -127,35 +127,6 @@ void qxl_gem_object_unpin(struct drm_gem_object *obj) - } - } - --int qxl_gem_set_domain(struct drm_gem_object *gobj, -- uint32_t rdomain, uint32_t wdomain) --{ -- struct qxl_bo *qobj; -- uint32_t domain; -- int r; -- -- /* FIXME: reeimplement */ -- qobj = gobj->driver_private; -- /* work out where to validate the buffer to */ -- domain = wdomain; -- if (!domain) -- domain = rdomain; -- if (!domain) { -- /* Do nothings */ -- pr_warn("Set domain withou domain !\n"); -- return 0; -- } -- if (domain == QXL_GEM_DOMAIN_CPU) { -- /* Asking for cpu access wait for object idle */ -- r = qxl_bo_wait(qobj, NULL, false); -- if (r) { -- pr_err("Failed to wait for object !\n"); -- return r; -- } -- } -- return 0; --} -- - int qxl_gem_object_open(struct drm_gem_object *obj, struct drm_file *file_priv) - { - return 0; -diff --git a/drivers/gpu/drm/qxl/qxl_ioctl.c b/drivers/gpu/drm/qxl/qxl_ioctl.c -index 83ca4f7..a4b71b2 100644 ---- a/drivers/gpu/drm/qxl/qxl_ioctl.c -+++ b/drivers/gpu/drm/qxl/qxl_ioctl.c -@@ -30,8 +30,8 @@ - * TODO: allocating a new gem(in qxl_bo) for each request. - * This is wasteful since bo's are page aligned. - */ --int qxl_alloc_ioctl(struct drm_device *dev, void *data, -- struct drm_file *file_priv) -+static int qxl_alloc_ioctl(struct drm_device *dev, void *data, -+ struct drm_file *file_priv) - { - struct qxl_device *qdev = dev->dev_private; - struct drm_qxl_alloc *qxl_alloc = data; -@@ -58,8 +58,8 @@ int qxl_alloc_ioctl(struct drm_device *dev, void *data, - return 0; - } - --int qxl_map_ioctl(struct drm_device *dev, void *data, -- struct drm_file *file_priv) -+static int qxl_map_ioctl(struct drm_device *dev, void *data, -+ struct drm_file *file_priv) - { - struct qxl_device *qdev = dev->dev_private; - struct drm_qxl_map *qxl_map = data; -@@ -101,9 +101,9 @@ apply_surf_reloc(struct qxl_device *qdev, struct qxl_bo *dst, uint64_t dst_off, - } - - /* return holding the reference to this object */ --struct qxl_bo *qxlhw_handle_to_bo(struct qxl_device *qdev, -- struct drm_file *file_priv, uint64_t handle, -- struct qxl_reloc_list *reloc_list) -+static struct qxl_bo *qxlhw_handle_to_bo(struct qxl_device *qdev, -+ struct drm_file *file_priv, uint64_t handle, -+ struct qxl_reloc_list *reloc_list) - { - struct drm_gem_object *gobj; - struct qxl_bo *qobj; -@@ -129,8 +129,8 @@ struct qxl_bo *qxlhw_handle_to_bo(struct qxl_device *qdev, - * However, the command as passed from user space must *not* contain the initial - * QXLReleaseInfo struct (first XXX bytes) - */ --int qxl_execbuffer_ioctl(struct drm_device *dev, void *data, -- struct drm_file *file_priv) -+static int qxl_execbuffer_ioctl(struct drm_device *dev, void *data, -+ struct drm_file *file_priv) - { - struct qxl_device *qdev = dev->dev_private; - struct drm_qxl_execbuffer *execbuffer = data; -@@ -151,7 +151,7 @@ int qxl_execbuffer_ioctl(struct drm_device *dev, void *data, - struct qxl_bo *cmd_bo; - int release_type; - struct drm_qxl_command *commands = -- (struct drm_qxl_command *)execbuffer->commands; -+ (struct drm_qxl_command *)(uintptr_t)execbuffer->commands; - - if (DRM_COPY_FROM_USER(&user_cmd, &commands[cmd_num], - sizeof(user_cmd))) -@@ -193,7 +193,7 @@ int qxl_execbuffer_ioctl(struct drm_device *dev, void *data, - - for (i = 0 ; i < user_cmd.relocs_num; ++i) { - if (DRM_COPY_FROM_USER(&reloc, -- &((struct drm_qxl_reloc *)user_cmd.relocs)[i], -+ &((struct drm_qxl_reloc *)(uintptr_t)user_cmd.relocs)[i], - sizeof(reloc))) { - qxl_bo_list_unreserve(&reloc_list, true); - qxl_release_unreserve(qdev, release); -@@ -266,8 +266,8 @@ int qxl_execbuffer_ioctl(struct drm_device *dev, void *data, - return 0; - } - --int qxl_update_area_ioctl(struct drm_device *dev, void *data, -- struct drm_file *file) -+static int qxl_update_area_ioctl(struct drm_device *dev, void *data, -+ struct drm_file *file) - { - struct qxl_device *qdev = dev->dev_private; - struct drm_qxl_update_area *update_area = data; -@@ -294,6 +294,7 @@ int qxl_update_area_ioctl(struct drm_device *dev, void *data, - goto out; - - if (!qobj->pin_count) { -+ qxl_ttm_placement_from_domain(qobj, qobj->type); - ret = ttm_bo_validate(&qobj->tbo, &qobj->placement, - true, false); - if (unlikely(ret)) -@@ -347,7 +348,7 @@ static int qxl_clientcap_ioctl(struct drm_device *dev, void *data, - if (qdev->pdev->revision < 4) - return -ENOSYS; - -- if (byte > 58) -+ if (byte >= 58) - return -ENOSYS; - - if (qdev->rom->client_capabilities[byte] & (1 << idx)) -diff --git a/drivers/gpu/drm/qxl/qxl_kms.c b/drivers/gpu/drm/qxl/qxl_kms.c -index 036e0de..e27ce2a 100644 ---- a/drivers/gpu/drm/qxl/qxl_kms.c -+++ b/drivers/gpu/drm/qxl/qxl_kms.c -@@ -128,12 +128,13 @@ int qxl_device_init(struct qxl_device *qdev, - - qdev->vram_mapping = io_mapping_create_wc(qdev->vram_base, pci_resource_len(pdev, 0)); - qdev->surface_mapping = io_mapping_create_wc(qdev->surfaceram_base, qdev->surfaceram_size); -- DRM_DEBUG_KMS("qxl: vram %p-%p(%dM %dk), surface %p-%p(%dM %dk)\n", -- (void *)qdev->vram_base, (void *)pci_resource_end(pdev, 0), -+ DRM_DEBUG_KMS("qxl: vram %llx-%llx(%dM %dk), surface %llx-%llx(%dM %dk)\n", -+ (unsigned long long)qdev->vram_base, -+ (unsigned long long)pci_resource_end(pdev, 0), - (int)pci_resource_len(pdev, 0) / 1024 / 1024, - (int)pci_resource_len(pdev, 0) / 1024, -- (void *)qdev->surfaceram_base, -- (void *)pci_resource_end(pdev, 1), -+ (unsigned long long)qdev->surfaceram_base, -+ (unsigned long long)pci_resource_end(pdev, 1), - (int)qdev->surfaceram_size / 1024 / 1024, - (int)qdev->surfaceram_size / 1024); - -@@ -230,7 +231,7 @@ int qxl_device_init(struct qxl_device *qdev, - return 0; - } - --void qxl_device_fini(struct qxl_device *qdev) -+static void qxl_device_fini(struct qxl_device *qdev) - { - if (qdev->current_release_bo[0]) - qxl_bo_unref(&qdev->current_release_bo[0]); -diff --git a/drivers/gpu/drm/qxl/qxl_object.c b/drivers/gpu/drm/qxl/qxl_object.c -index 51efb94..d9b12e7 100644 ---- a/drivers/gpu/drm/qxl/qxl_object.c -+++ b/drivers/gpu/drm/qxl/qxl_object.c -@@ -59,11 +59,11 @@ void qxl_ttm_placement_from_domain(struct qxl_bo *qbo, u32 domain) - qbo->placement.lpfn = 0; - qbo->placement.placement = qbo->placements; - qbo->placement.busy_placement = qbo->placements; -- if (domain & QXL_GEM_DOMAIN_VRAM) -+ if (domain == QXL_GEM_DOMAIN_VRAM) - qbo->placements[c++] = TTM_PL_FLAG_CACHED | TTM_PL_FLAG_VRAM; -- if (domain & QXL_GEM_DOMAIN_SURFACE) -+ if (domain == QXL_GEM_DOMAIN_SURFACE) - qbo->placements[c++] = TTM_PL_FLAG_CACHED | TTM_PL_FLAG_PRIV0; -- if (domain & QXL_GEM_DOMAIN_CPU) -+ if (domain == QXL_GEM_DOMAIN_CPU) - qbo->placements[c++] = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM; - if (!c) - qbo->placements[c++] = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM; -diff --git a/drivers/gpu/drm/qxl/qxl_release.c b/drivers/gpu/drm/qxl/qxl_release.c -index 1600781..c4267c7 100644 ---- a/drivers/gpu/drm/qxl/qxl_release.c -+++ b/drivers/gpu/drm/qxl/qxl_release.c -@@ -117,8 +117,8 @@ qxl_release_add_res(struct qxl_device *qdev, struct qxl_release *release, - release->bos[release->bo_count++] = qxl_bo_ref(bo); - } - --int qxl_release_bo_alloc(struct qxl_device *qdev, -- struct qxl_bo **bo) -+static int qxl_release_bo_alloc(struct qxl_device *qdev, -+ struct qxl_bo **bo) - { - int ret; - ret = qxl_bo_create(qdev, PAGE_SIZE, false, QXL_GEM_DOMAIN_VRAM, NULL, -diff --git a/drivers/gpu/drm/qxl/qxl_ttm.c b/drivers/gpu/drm/qxl/qxl_ttm.c -index aa9fb9a..489cb8c 100644 ---- a/drivers/gpu/drm/qxl/qxl_ttm.c -+++ b/drivers/gpu/drm/qxl/qxl_ttm.c -@@ -315,9 +315,9 @@ static void qxl_ttm_tt_unpopulate(struct ttm_tt *ttm) - ttm_pool_unpopulate(ttm); - } - --struct ttm_tt *qxl_ttm_tt_create(struct ttm_bo_device *bdev, -- unsigned long size, uint32_t page_flags, -- struct page *dummy_read_page) -+static struct ttm_tt *qxl_ttm_tt_create(struct ttm_bo_device *bdev, -+ unsigned long size, uint32_t page_flags, -+ struct page *dummy_read_page) - { - struct qxl_device *qdev; - struct qxl_ttm_tt *gtt; -@@ -555,6 +555,7 @@ static int qxl_mm_dump_table(struct seq_file *m, void *data) - - static int qxl_ttm_debugfs_init(struct qxl_device *qdev) - { -+#if defined(CONFIG_DEBUG_FS) - static struct drm_info_list qxl_mem_types_list[QXL_DEBUGFS_MEM_TYPES]; - static char qxl_mem_types_names[QXL_DEBUGFS_MEM_TYPES][32]; - unsigned i; -@@ -574,4 +575,7 @@ static int qxl_ttm_debugfs_init(struct qxl_device *qdev) - - } - return qxl_debugfs_add_files(qdev, qxl_mem_types_list, i); -+#else -+ return 0; -+#endif - } --- -1.8.3.1 - diff --git a/drm-qxl-access-fix.patch b/drm-qxl-access-fix.patch deleted file mode 100644 index e40a14d..0000000 --- a/drm-qxl-access-fix.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 18097b91aaff215e843f04b84ec2c686270bb55f Mon Sep 17 00:00:00 2001 -From: Dave Airlie -Date: Fri, 28 Jun 2013 13:27:40 +1000 -Subject: [PATCH] drm/qxl: add missing access check for execbuffer ioctl - -Reported-by: Mathieu Desnoyers -Signed-off-by: Dave Airlie ---- - drivers/gpu/drm/qxl/qxl_ioctl.c | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/drivers/gpu/drm/qxl/qxl_ioctl.c b/drivers/gpu/drm/qxl/qxl_ioctl.c -index a4b71b2..a30f294 100644 ---- a/drivers/gpu/drm/qxl/qxl_ioctl.c -+++ b/drivers/gpu/drm/qxl/qxl_ioctl.c -@@ -171,6 +171,11 @@ static int qxl_execbuffer_ioctl(struct drm_device *dev, void *data, - if (user_cmd.command_size > PAGE_SIZE - sizeof(union qxl_release_info)) - return -EINVAL; - -+ if (!access_ok(VERIFY_READ, -+ (void *)(unsigned long)user_cmd.command, -+ user_cmd.command_size)) -+ return -EFAULT; -+ - ret = qxl_alloc_release_reserved(qdev, - sizeof(union qxl_release_info) + - user_cmd.command_size, --- -1.8.1.2 - diff --git a/drm-qxl-driver.patch b/drm-qxl-driver.patch deleted file mode 100644 index 72341a8..0000000 --- a/drm-qxl-driver.patch +++ /dev/null @@ -1,7507 +0,0 @@ -From bb57317d5f86a60fd5dd98b3f82241c47ae2cc5d Mon Sep 17 00:00:00 2001 -From: Dave Airlie -Date: Mon, 25 Feb 2013 14:47:55 +1000 -Subject: [PATCH] drm: add new QXL driver. (v1.4) - -QXL is a paravirtual graphics device used by the Spice virtual desktop -interface. - -The drivers uses GEM and TTM to manage memory, the qxl hw fencing however -is quite different than normal TTM expects, we have to keep track of a number -of non-linear fence ids per bo that we need to have released by the hardware. - -The releases are freed from a workqueue that wakes up and processes the -release ring. - -releases are suballocated from a BO, there are 3 release categories, drawables, -surfaces and cursor cmds. The hw also has 3 rings for commands, cursor and release handling. - -The hardware also have a surface id tracking mechnaism and the driver encapsulates it completely inside the kernel, userspace never sees the actual hw surface -ids. - -This requires a newer version of the QXL userspace driver, so shouldn't be -enabled until that has been placed into your distro of choice. - -Authors: Dave Airlie, Alon Levy - -v1.1: fixup some issues in the ioctl interface with padding -v1.2: add module device table -v1.3: fix nomodeset, fbcon leak, dumb bo create, release ring irq, - don't try flush release ring (broken hw), fix -modesetting. -v1.4: fbcon cpu usage reduction + suitable accel flags. - -Signed-off-by: Alon Levy -Signed-off-by: Dave Airlie ---- - drivers/gpu/drm/Kconfig | 2 + - drivers/gpu/drm/Makefile | 1 + - drivers/gpu/drm/qxl/Kconfig | 10 + - drivers/gpu/drm/qxl/Makefile | 9 + - drivers/gpu/drm/qxl/qxl_cmd.c | 707 +++++++++++++++++++++++++++ - drivers/gpu/drm/qxl/qxl_debugfs.c | 135 ++++++ - drivers/gpu/drm/qxl/qxl_dev.h | 879 ++++++++++++++++++++++++++++++++++ - drivers/gpu/drm/qxl/qxl_display.c | 981 ++++++++++++++++++++++++++++++++++++++ - drivers/gpu/drm/qxl/qxl_draw.c | 390 +++++++++++++++ - drivers/gpu/drm/qxl/qxl_drv.c | 145 ++++++ - drivers/gpu/drm/qxl/qxl_drv.h | 566 ++++++++++++++++++++++ - drivers/gpu/drm/qxl/qxl_dumb.c | 93 ++++ - drivers/gpu/drm/qxl/qxl_fb.c | 567 ++++++++++++++++++++++ - drivers/gpu/drm/qxl/qxl_fence.c | 97 ++++ - drivers/gpu/drm/qxl/qxl_gem.c | 178 +++++++ - drivers/gpu/drm/qxl/qxl_image.c | 176 +++++++ - drivers/gpu/drm/qxl/qxl_ioctl.c | 411 ++++++++++++++++ - drivers/gpu/drm/qxl/qxl_irq.c | 97 ++++ - drivers/gpu/drm/qxl/qxl_kms.c | 302 ++++++++++++ - drivers/gpu/drm/qxl/qxl_object.c | 365 ++++++++++++++ - drivers/gpu/drm/qxl/qxl_object.h | 112 +++++ - drivers/gpu/drm/qxl/qxl_release.c | 307 ++++++++++++ - drivers/gpu/drm/qxl/qxl_ttm.c | 577 ++++++++++++++++++++++ - include/uapi/drm/Kbuild | 1 + - include/uapi/drm/qxl_drm.h | 152 ++++++ - 25 files changed, 7260 insertions(+) - create mode 100644 drivers/gpu/drm/qxl/Kconfig - create mode 100644 drivers/gpu/drm/qxl/Makefile - create mode 100644 drivers/gpu/drm/qxl/qxl_cmd.c - create mode 100644 drivers/gpu/drm/qxl/qxl_debugfs.c - create mode 100644 drivers/gpu/drm/qxl/qxl_dev.h - create mode 100644 drivers/gpu/drm/qxl/qxl_display.c - create mode 100644 drivers/gpu/drm/qxl/qxl_draw.c - create mode 100644 drivers/gpu/drm/qxl/qxl_drv.c - create mode 100644 drivers/gpu/drm/qxl/qxl_drv.h - create mode 100644 drivers/gpu/drm/qxl/qxl_dumb.c - create mode 100644 drivers/gpu/drm/qxl/qxl_fb.c - create mode 100644 drivers/gpu/drm/qxl/qxl_fence.c - create mode 100644 drivers/gpu/drm/qxl/qxl_gem.c - create mode 100644 drivers/gpu/drm/qxl/qxl_image.c - create mode 100644 drivers/gpu/drm/qxl/qxl_ioctl.c - create mode 100644 drivers/gpu/drm/qxl/qxl_irq.c - create mode 100644 drivers/gpu/drm/qxl/qxl_kms.c - create mode 100644 drivers/gpu/drm/qxl/qxl_object.c - create mode 100644 drivers/gpu/drm/qxl/qxl_object.h - create mode 100644 drivers/gpu/drm/qxl/qxl_release.c - create mode 100644 drivers/gpu/drm/qxl/qxl_ttm.c - create mode 100644 include/uapi/drm/qxl_drm.h - -diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig -index 1e82882..19b8e0d 100644 ---- a/drivers/gpu/drm/Kconfig -+++ b/drivers/gpu/drm/Kconfig -@@ -220,3 +220,5 @@ source "drivers/gpu/drm/tegra/Kconfig" - source "drivers/gpu/drm/omapdrm/Kconfig" - - source "drivers/gpu/drm/tilcdc/Kconfig" -+ -+source "drivers/gpu/drm/qxl/Kconfig" -diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile -index 0d59b24..6a42115 100644 ---- a/drivers/gpu/drm/Makefile -+++ b/drivers/gpu/drm/Makefile -@@ -52,4 +52,5 @@ obj-$(CONFIG_DRM_SHMOBILE) +=shmobile/ - obj-$(CONFIG_DRM_TEGRA) += tegra/ - obj-$(CONFIG_DRM_OMAP) += omapdrm/ - obj-$(CONFIG_DRM_TILCDC) += tilcdc/ -+obj-$(CONFIG_DRM_QXL) += qxl/ - obj-y += i2c/ -diff --git a/drivers/gpu/drm/qxl/Kconfig b/drivers/gpu/drm/qxl/Kconfig -new file mode 100644 -index 0000000..2f1a57e ---- /dev/null -+++ b/drivers/gpu/drm/qxl/Kconfig -@@ -0,0 +1,10 @@ -+config DRM_QXL -+ tristate "QXL virtual GPU" -+ depends on DRM && PCI -+ select FB_SYS_FILLRECT -+ select FB_SYS_COPYAREA -+ select FB_SYS_IMAGEBLIT -+ select DRM_KMS_HELPER -+ select DRM_TTM -+ help -+ QXL virtual GPU for Spice virtualization desktop integration. Do not enable this driver unless your distro ships a corresponding X.org QXL driver that can handle kernel modesetting. -diff --git a/drivers/gpu/drm/qxl/Makefile b/drivers/gpu/drm/qxl/Makefile -new file mode 100644 -index 0000000..ea046ba ---- /dev/null -+++ b/drivers/gpu/drm/qxl/Makefile -@@ -0,0 +1,9 @@ -+# -+# Makefile for the drm device driver. This driver provides support for the -+# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. -+ -+ccflags-y := -Iinclude/drm -+ -+qxl-y := qxl_drv.o qxl_kms.o qxl_display.o qxl_ttm.o qxl_fb.o qxl_object.o qxl_gem.o qxl_cmd.o qxl_image.o qxl_draw.o qxl_debugfs.o qxl_irq.o qxl_dumb.o qxl_ioctl.o qxl_fence.o qxl_release.o -+ -+obj-$(CONFIG_DRM_QXL)+= qxl.o -diff --git a/drivers/gpu/drm/qxl/qxl_cmd.c b/drivers/gpu/drm/qxl/qxl_cmd.c -new file mode 100644 -index 0000000..804b411 ---- /dev/null -+++ b/drivers/gpu/drm/qxl/qxl_cmd.c -@@ -0,0 +1,707 @@ -+/* -+ * Copyright 2013 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, sublicense, -+ * 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 above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * 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 NONINFRINGEMENT. IN NO EVENT SHALL -+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. -+ * -+ * Authors: Dave Airlie -+ * Alon Levy -+ */ -+ -+/* QXL cmd/ring handling */ -+ -+#include "qxl_drv.h" -+#include "qxl_object.h" -+ -+static int qxl_reap_surface_id(struct qxl_device *qdev, int max_to_reap); -+ -+struct ring { -+ struct qxl_ring_header header; -+ uint8_t elements[0]; -+}; -+ -+struct qxl_ring { -+ struct ring *ring; -+ int element_size; -+ int n_elements; -+ int prod_notify; -+ wait_queue_head_t *push_event; -+ spinlock_t lock; -+}; -+ -+void qxl_ring_free(struct qxl_ring *ring) -+{ -+ kfree(ring); -+} -+ -+struct qxl_ring * -+qxl_ring_create(struct qxl_ring_header *header, -+ int element_size, -+ int n_elements, -+ int prod_notify, -+ bool set_prod_notify, -+ wait_queue_head_t *push_event) -+{ -+ struct qxl_ring *ring; -+ -+ ring = kmalloc(sizeof(*ring), GFP_KERNEL); -+ if (!ring) -+ return NULL; -+ -+ ring->ring = (struct ring *)header; -+ ring->element_size = element_size; -+ ring->n_elements = n_elements; -+ ring->prod_notify = prod_notify; -+ ring->push_event = push_event; -+ if (set_prod_notify) -+ header->notify_on_prod = ring->n_elements; -+ spin_lock_init(&ring->lock); -+ return ring; -+} -+ -+static int qxl_check_header(struct qxl_ring *ring) -+{ -+ int ret; -+ struct qxl_ring_header *header = &(ring->ring->header); -+ unsigned long flags; -+ spin_lock_irqsave(&ring->lock, flags); -+ ret = header->prod - header->cons < header->num_items; -+ if (ret == 0) -+ header->notify_on_cons = header->cons + 1; -+ spin_unlock_irqrestore(&ring->lock, flags); -+ return ret; -+} -+ -+static int qxl_check_idle(struct qxl_ring *ring) -+{ -+ int ret; -+ struct qxl_ring_header *header = &(ring->ring->header); -+ unsigned long flags; -+ spin_lock_irqsave(&ring->lock, flags); -+ ret = header->prod == header->cons; -+ spin_unlock_irqrestore(&ring->lock, flags); -+ return ret; -+} -+ -+int qxl_ring_push(struct qxl_ring *ring, -+ const void *new_elt, bool interruptible) -+{ -+ struct qxl_ring_header *header = &(ring->ring->header); -+ uint8_t *elt; -+ int idx, ret; -+ unsigned long flags; -+ spin_lock_irqsave(&ring->lock, flags); -+ if (header->prod - header->cons == header->num_items) { -+ header->notify_on_cons = header->cons + 1; -+ mb(); -+ spin_unlock_irqrestore(&ring->lock, flags); -+ if (!drm_can_sleep()) { -+ while (!qxl_check_header(ring)) -+ udelay(1); -+ } else { -+ if (interruptible) { -+ ret = wait_event_interruptible(*ring->push_event, -+ qxl_check_header(ring)); -+ if (ret) -+ return ret; -+ } else { -+ wait_event(*ring->push_event, -+ qxl_check_header(ring)); -+ } -+ -+ } -+ spin_lock_irqsave(&ring->lock, flags); -+ } -+ -+ idx = header->prod & (ring->n_elements - 1); -+ elt = ring->ring->elements + idx * ring->element_size; -+ -+ memcpy((void *)elt, new_elt, ring->element_size); -+ -+ header->prod++; -+ -+ mb(); -+ -+ if (header->prod == header->notify_on_prod) -+ outb(0, ring->prod_notify); -+ -+ spin_unlock_irqrestore(&ring->lock, flags); -+ return 0; -+} -+ -+bool qxl_ring_pop(struct qxl_ring *ring, -+ void *element) -+{ -+ volatile struct qxl_ring_header *header = &(ring->ring->header); -+ volatile uint8_t *ring_elt; -+ int idx; -+ unsigned long flags; -+ spin_lock_irqsave(&ring->lock, flags); -+ if (header->cons == header->prod) { -+ header->notify_on_prod = header->cons + 1; -+ spin_unlock_irqrestore(&ring->lock, flags); -+ return false; -+ } -+ -+ idx = header->cons & (ring->n_elements - 1); -+ ring_elt = ring->ring->elements + idx * ring->element_size; -+ -+ memcpy(element, (void *)ring_elt, ring->element_size); -+ -+ header->cons++; -+ -+ spin_unlock_irqrestore(&ring->lock, flags); -+ return true; -+} -+ -+void qxl_ring_wait_idle(struct qxl_ring *ring) -+{ -+ struct qxl_ring_header *header = &(ring->ring->header); -+ unsigned long flags; -+ -+ spin_lock_irqsave(&ring->lock, flags); -+ if (ring->ring->header.cons < ring->ring->header.prod) { -+ header->notify_on_cons = header->prod; -+ mb(); -+ spin_unlock_irqrestore(&ring->lock, flags); -+ wait_event_interruptible(*ring->push_event, -+ qxl_check_idle(ring)); -+ spin_lock_irqsave(&ring->lock, flags); -+ } -+ spin_unlock_irqrestore(&ring->lock, flags); -+} -+ -+int -+qxl_push_command_ring_release(struct qxl_device *qdev, struct qxl_release *release, -+ uint32_t type, bool interruptible) -+{ -+ struct qxl_command cmd; -+ -+ cmd.type = type; -+ cmd.data = qxl_bo_physical_address(qdev, release->bos[0], release->release_offset); -+ -+ return qxl_ring_push(qdev->command_ring, &cmd, interruptible); -+} -+ -+int -+qxl_push_cursor_ring_release(struct qxl_device *qdev, struct qxl_release *release, -+ uint32_t type, bool interruptible) -+{ -+ struct qxl_command cmd; -+ -+ cmd.type = type; -+ cmd.data = qxl_bo_physical_address(qdev, release->bos[0], release->release_offset); -+ -+ return qxl_ring_push(qdev->cursor_ring, &cmd, interruptible); -+} -+ -+bool qxl_queue_garbage_collect(struct qxl_device *qdev, bool flush) -+{ -+ if (!qxl_check_idle(qdev->release_ring)) { -+ queue_work(qdev->gc_queue, &qdev->gc_work); -+ if (flush) -+ flush_work(&qdev->gc_work); -+ return true; -+ } -+ return false; -+} -+ -+int qxl_garbage_collect(struct qxl_device *qdev) -+{ -+ struct qxl_release *release; -+ uint64_t id, next_id; -+ int i = 0; -+ int ret; -+ union qxl_release_info *info; -+ -+ while (qxl_ring_pop(qdev->release_ring, &id)) { -+ QXL_INFO(qdev, "popped %lld\n", id); -+ while (id) { -+ release = qxl_release_from_id_locked(qdev, id); -+ if (release == NULL) -+ break; -+ -+ ret = qxl_release_reserve(qdev, release, false); -+ if (ret) { -+ qxl_io_log(qdev, "failed to reserve release on garbage collect %lld\n", id); -+ DRM_ERROR("failed to reserve release %lld\n", id); -+ } -+ -+ info = qxl_release_map(qdev, release); -+ next_id = info->next; -+ qxl_release_unmap(qdev, release, info); -+ -+ qxl_release_unreserve(qdev, release); -+ QXL_INFO(qdev, "popped %lld, next %lld\n", id, -+ next_id); -+ -+ switch (release->type) { -+ case QXL_RELEASE_DRAWABLE: -+ case QXL_RELEASE_SURFACE_CMD: -+ case QXL_RELEASE_CURSOR_CMD: -+ break; -+ default: -+ DRM_ERROR("unexpected release type\n"); -+ break; -+ } -+ id = next_id; -+ -+ qxl_release_free(qdev, release); -+ ++i; -+ } -+ } -+ -+ QXL_INFO(qdev, "%s: %lld\n", __func__, i); -+ -+ return i; -+} -+ -+int qxl_alloc_bo_reserved(struct qxl_device *qdev, unsigned long size, -+ struct qxl_bo **_bo) -+{ -+ struct qxl_bo *bo; -+ int ret; -+ -+ ret = qxl_bo_create(qdev, size, false /* not kernel - device */, -+ QXL_GEM_DOMAIN_VRAM, NULL, &bo); -+ if (ret) { -+ DRM_ERROR("failed to allocate VRAM BO\n"); -+ return ret; -+ } -+ ret = qxl_bo_reserve(bo, false); -+ if (unlikely(ret != 0)) -+ goto out_unref; -+ -+ *_bo = bo; -+ return 0; -+out_unref: -+ qxl_bo_unref(&bo); -+ return 0; -+} -+ -+static int wait_for_io_cmd_user(struct qxl_device *qdev, uint8_t val, long port) -+{ -+ int irq_num; -+ long addr = qdev->io_base + port; -+ int ret; -+ -+ mutex_lock(&qdev->async_io_mutex); -+ irq_num = atomic_read(&qdev->irq_received_io_cmd); -+ -+ -+ if (qdev->last_sent_io_cmd > irq_num) { -+ ret = wait_event_interruptible(qdev->io_cmd_event, -+ atomic_read(&qdev->irq_received_io_cmd) > irq_num); -+ if (ret) -+ goto out; -+ irq_num = atomic_read(&qdev->irq_received_io_cmd); -+ } -+ outb(val, addr); -+ qdev->last_sent_io_cmd = irq_num + 1; -+ ret = wait_event_interruptible(qdev->io_cmd_event, -+ atomic_read(&qdev->irq_received_io_cmd) > irq_num); -+out: -+ mutex_unlock(&qdev->async_io_mutex); -+ return ret; -+} -+ -+static void wait_for_io_cmd(struct qxl_device *qdev, uint8_t val, long port) -+{ -+ int ret; -+ -+restart: -+ ret = wait_for_io_cmd_user(qdev, val, port); -+ if (ret == -ERESTARTSYS) -+ goto restart; -+} -+ -+int qxl_io_update_area(struct qxl_device *qdev, struct qxl_bo *surf, -+ const struct qxl_rect *area) -+{ -+ int surface_id; -+ uint32_t surface_width, surface_height; -+ int ret; -+ -+ if (!surf->hw_surf_alloc) -+ DRM_ERROR("got io update area with no hw surface\n"); -+ -+ if (surf->is_primary) -+ surface_id = 0; -+ else -+ surface_id = surf->surface_id; -+ surface_width = surf->surf.width; -+ surface_height = surf->surf.height; -+ -+ if (area->left < 0 || area->top < 0 || -+ area->right > surface_width || area->bottom > surface_height) { -+ qxl_io_log(qdev, "%s: not doing area update for " -+ "%d, (%d,%d,%d,%d) (%d,%d)\n", __func__, surface_id, area->left, -+ area->top, area->right, area->bottom, surface_width, surface_height); -+ return -EINVAL; -+ } -+ mutex_lock(&qdev->update_area_mutex); -+ qdev->ram_header->update_area = *area; -+ qdev->ram_header->update_surface = surface_id; -+ ret = wait_for_io_cmd_user(qdev, 0, QXL_IO_UPDATE_AREA_ASYNC); -+ mutex_unlock(&qdev->update_area_mutex); -+ return ret; -+} -+ -+void qxl_io_notify_oom(struct qxl_device *qdev) -+{ -+ outb(0, qdev->io_base + QXL_IO_NOTIFY_OOM); -+} -+ -+void qxl_io_flush_release(struct qxl_device *qdev) -+{ -+ outb(0, qdev->io_base + QXL_IO_FLUSH_RELEASE); -+} -+ -+void qxl_io_flush_surfaces(struct qxl_device *qdev) -+{ -+ wait_for_io_cmd(qdev, 0, QXL_IO_FLUSH_SURFACES_ASYNC); -+} -+ -+ -+void qxl_io_destroy_primary(struct qxl_device *qdev) -+{ -+ wait_for_io_cmd(qdev, 0, QXL_IO_DESTROY_PRIMARY_ASYNC); -+} -+ -+void qxl_io_create_primary(struct qxl_device *qdev, unsigned width, -+ unsigned height, unsigned offset, struct qxl_bo *bo) -+{ -+ struct qxl_surface_create *create; -+ -+ QXL_INFO(qdev, "%s: qdev %p, ram_header %p\n", __func__, qdev, -+ qdev->ram_header); -+ create = &qdev->ram_header->create_surface; -+ create->format = bo->surf.format; -+ create->width = width; -+ create->height = height; -+ create->stride = bo->surf.stride; -+ create->mem = qxl_bo_physical_address(qdev, bo, offset); -+ -+ QXL_INFO(qdev, "%s: mem = %llx, from %p\n", __func__, create->mem, -+ bo->kptr); -+ -+ create->flags = QXL_SURF_FLAG_KEEP_DATA; -+ create->type = QXL_SURF_TYPE_PRIMARY; -+ -+ wait_for_io_cmd(qdev, 0, QXL_IO_CREATE_PRIMARY_ASYNC); -+} -+ -+void qxl_io_memslot_add(struct qxl_device *qdev, uint8_t id) -+{ -+ QXL_INFO(qdev, "qxl_memslot_add %d\n", id); -+ wait_for_io_cmd(qdev, id, QXL_IO_MEMSLOT_ADD_ASYNC); -+} -+ -+void qxl_io_log(struct qxl_device *qdev, const char *fmt, ...) -+{ -+ va_list args; -+ -+ va_start(args, fmt); -+ vsnprintf(qdev->ram_header->log_buf, QXL_LOG_BUF_SIZE, fmt, args); -+ va_end(args); -+ /* -+ * DO not do a DRM output here - this will call printk, which will -+ * call back into qxl for rendering (qxl_fb) -+ */ -+ outb(0, qdev->io_base + QXL_IO_LOG); -+} -+ -+void qxl_io_reset(struct qxl_device *qdev) -+{ -+ outb(0, qdev->io_base + QXL_IO_RESET); -+} -+ -+void qxl_io_monitors_config(struct qxl_device *qdev) -+{ -+ qxl_io_log(qdev, "%s: %d [%dx%d+%d+%d]\n", __func__, -+ qdev->monitors_config ? -+ qdev->monitors_config->count : -1, -+ qdev->monitors_config && qdev->monitors_config->count ? -+ qdev->monitors_config->heads[0].width : -1, -+ qdev->monitors_config && qdev->monitors_config->count ? -+ qdev->monitors_config->heads[0].height : -1, -+ qdev->monitors_config && qdev->monitors_config->count ? -+ qdev->monitors_config->heads[0].x : -1, -+ qdev->monitors_config && qdev->monitors_config->count ? -+ qdev->monitors_config->heads[0].y : -1 -+ ); -+ -+ wait_for_io_cmd(qdev, 0, QXL_IO_MONITORS_CONFIG_ASYNC); -+} -+ -+int qxl_surface_id_alloc(struct qxl_device *qdev, -+ struct qxl_bo *surf) -+{ -+ uint32_t handle = -ENOMEM; -+ int idr_ret; -+ int count = 0; -+again: -+ if (idr_pre_get(&qdev->surf_id_idr, GFP_ATOMIC) == 0) { -+ DRM_ERROR("Out of memory for surf idr\n"); -+ kfree(surf); -+ goto alloc_fail; -+ } -+ -+ spin_lock(&qdev->surf_id_idr_lock); -+ idr_ret = idr_get_new_above(&qdev->surf_id_idr, NULL, 1, &handle); -+ spin_unlock(&qdev->surf_id_idr_lock); -+ -+ if (idr_ret == -EAGAIN) -+ goto again; -+ -+ if (handle >= qdev->rom->n_surfaces) { -+ count++; -+ spin_lock(&qdev->surf_id_idr_lock); -+ idr_remove(&qdev->surf_id_idr, handle); -+ spin_unlock(&qdev->surf_id_idr_lock); -+ qxl_reap_surface_id(qdev, 2); -+ goto again; -+ } -+ surf->surface_id = handle; -+ -+ spin_lock(&qdev->surf_id_idr_lock); -+ qdev->last_alloced_surf_id = handle; -+ spin_unlock(&qdev->surf_id_idr_lock); -+ alloc_fail: -+ return 0; -+} -+ -+void qxl_surface_id_dealloc(struct qxl_device *qdev, -+ uint32_t surface_id) -+{ -+ spin_lock(&qdev->surf_id_idr_lock); -+ idr_remove(&qdev->surf_id_idr, surface_id); -+ spin_unlock(&qdev->surf_id_idr_lock); -+} -+ -+int qxl_hw_surface_alloc(struct qxl_device *qdev, -+ struct qxl_bo *surf, -+ struct ttm_mem_reg *new_mem) -+{ -+ struct qxl_surface_cmd *cmd; -+ struct qxl_release *release; -+ int ret; -+ -+ if (surf->hw_surf_alloc) -+ return 0; -+ -+ ret = qxl_alloc_surface_release_reserved(qdev, QXL_SURFACE_CMD_CREATE, -+ NULL, -+ &release); -+ if (ret) -+ return ret; -+ -+ cmd = (struct qxl_surface_cmd *)qxl_release_map(qdev, release); -+ cmd->type = QXL_SURFACE_CMD_CREATE; -+ cmd->u.surface_create.format = surf->surf.format; -+ cmd->u.surface_create.width = surf->surf.width; -+ cmd->u.surface_create.height = surf->surf.height; -+ cmd->u.surface_create.stride = surf->surf.stride; -+ if (new_mem) { -+ int slot_id = surf->type == QXL_GEM_DOMAIN_VRAM ? qdev->main_mem_slot : qdev->surfaces_mem_slot; -+ struct qxl_memslot *slot = &(qdev->mem_slots[slot_id]); -+ -+ /* TODO - need to hold one of the locks to read tbo.offset */ -+ cmd->u.surface_create.data = slot->high_bits; -+ -+ cmd->u.surface_create.data |= (new_mem->start << PAGE_SHIFT) + surf->tbo.bdev->man[new_mem->mem_type].gpu_offset; -+ } else -+ cmd->u.surface_create.data = qxl_bo_physical_address(qdev, surf, 0); -+ cmd->surface_id = surf->surface_id; -+ qxl_release_unmap(qdev, release, &cmd->release_info); -+ -+ surf->surf_create = release; -+ -+ /* no need to add a release to the fence for this bo, -+ since it is only released when we ask to destroy the surface -+ and it would never signal otherwise */ -+ qxl_fence_releaseable(qdev, release); -+ -+ qxl_push_command_ring_release(qdev, release, QXL_CMD_SURFACE, false); -+ -+ qxl_release_unreserve(qdev, release); -+ -+ surf->hw_surf_alloc = true; -+ spin_lock(&qdev->surf_id_idr_lock); -+ idr_replace(&qdev->surf_id_idr, surf, surf->surface_id); -+ spin_unlock(&qdev->surf_id_idr_lock); -+ return 0; -+} -+ -+int qxl_hw_surface_dealloc(struct qxl_device *qdev, -+ struct qxl_bo *surf) -+{ -+ struct qxl_surface_cmd *cmd; -+ struct qxl_release *release; -+ int ret; -+ int id; -+ -+ if (!surf->hw_surf_alloc) -+ return 0; -+ -+ ret = qxl_alloc_surface_release_reserved(qdev, QXL_SURFACE_CMD_DESTROY, -+ surf->surf_create, -+ &release); -+ if (ret) -+ return ret; -+ -+ surf->surf_create = NULL; -+ /* remove the surface from the idr, but not the surface id yet */ -+ spin_lock(&qdev->surf_id_idr_lock); -+ idr_replace(&qdev->surf_id_idr, NULL, surf->surface_id); -+ spin_unlock(&qdev->surf_id_idr_lock); -+ surf->hw_surf_alloc = false; -+ -+ id = surf->surface_id; -+ surf->surface_id = 0; -+ -+ release->surface_release_id = id; -+ cmd = (struct qxl_surface_cmd *)qxl_release_map(qdev, release); -+ cmd->type = QXL_SURFACE_CMD_DESTROY; -+ cmd->surface_id = id; -+ qxl_release_unmap(qdev, release, &cmd->release_info); -+ -+ qxl_fence_releaseable(qdev, release); -+ -+ qxl_push_command_ring_release(qdev, release, QXL_CMD_SURFACE, false); -+ -+ qxl_release_unreserve(qdev, release); -+ -+ -+ return 0; -+} -+ -+int qxl_update_surface(struct qxl_device *qdev, struct qxl_bo *surf) -+{ -+ struct qxl_rect rect; -+ int ret; -+ -+ /* if we are evicting, we need to make sure the surface is up -+ to date */ -+ rect.left = 0; -+ rect.right = surf->surf.width; -+ rect.top = 0; -+ rect.bottom = surf->surf.height; -+retry: -+ ret = qxl_io_update_area(qdev, surf, &rect); -+ if (ret == -ERESTARTSYS) -+ goto retry; -+ return ret; -+} -+ -+void qxl_surface_evict_locked(struct qxl_device *qdev, struct qxl_bo *surf, bool do_update_area) -+{ -+ /* no need to update area if we are just freeing the surface normally */ -+ if (do_update_area) -+ qxl_update_surface(qdev, surf); -+ -+ /* nuke the surface id at the hw */ -+ qxl_hw_surface_dealloc(qdev, surf); -+} -+ -+void qxl_surface_evict(struct qxl_device *qdev, struct qxl_bo *surf, bool do_update_area) -+{ -+ mutex_lock(&qdev->surf_evict_mutex); -+ qxl_surface_evict_locked(qdev, surf, do_update_area); -+ mutex_unlock(&qdev->surf_evict_mutex); -+} -+ -+static int qxl_reap_surf(struct qxl_device *qdev, struct qxl_bo *surf, bool stall) -+{ -+ int ret; -+ -+ ret = qxl_bo_reserve(surf, false); -+ if (ret == -EBUSY) -+ return -EBUSY; -+ -+ if (surf->fence.num_active_releases > 0 && stall == false) { -+ qxl_bo_unreserve(surf); -+ return -EBUSY; -+ } -+ -+ if (stall) -+ mutex_unlock(&qdev->surf_evict_mutex); -+ -+ spin_lock(&surf->tbo.bdev->fence_lock); -+ ret = ttm_bo_wait(&surf->tbo, true, true, !stall); -+ spin_unlock(&surf->tbo.bdev->fence_lock); -+ -+ if (stall) -+ mutex_lock(&qdev->surf_evict_mutex); -+ if (ret == -EBUSY) { -+ qxl_bo_unreserve(surf); -+ return -EBUSY; -+ } -+ -+ qxl_surface_evict_locked(qdev, surf, true); -+ qxl_bo_unreserve(surf); -+ return 0; -+} -+ -+static int qxl_reap_surface_id(struct qxl_device *qdev, int max_to_reap) -+{ -+ int num_reaped = 0; -+ int i, ret; -+ bool stall = false; -+ int start = 0; -+ -+ mutex_lock(&qdev->surf_evict_mutex); -+again: -+ -+ spin_lock(&qdev->surf_id_idr_lock); -+ start = qdev->last_alloced_surf_id + 1; -+ spin_unlock(&qdev->surf_id_idr_lock); -+ -+ for (i = start; i < start + qdev->rom->n_surfaces; i++) { -+ void *objptr; -+ int surfid = i % qdev->rom->n_surfaces; -+ -+ /* this avoids the case where the objects is in the -+ idr but has been evicted half way - its makes -+ the idr lookup atomic with the eviction */ -+ spin_lock(&qdev->surf_id_idr_lock); -+ objptr = idr_find(&qdev->surf_id_idr, surfid); -+ spin_unlock(&qdev->surf_id_idr_lock); -+ -+ if (!objptr) -+ continue; -+ -+ ret = qxl_reap_surf(qdev, objptr, stall); -+ if (ret == 0) -+ num_reaped++; -+ if (num_reaped >= max_to_reap) -+ break; -+ } -+ if (num_reaped == 0 && stall == false) { -+ stall = true; -+ goto again; -+ } -+ -+ mutex_unlock(&qdev->surf_evict_mutex); -+ if (num_reaped) { -+ usleep_range(500, 1000); -+ qxl_queue_garbage_collect(qdev, true); -+ } -+ -+ return 0; -+} -diff --git a/drivers/gpu/drm/qxl/qxl_debugfs.c b/drivers/gpu/drm/qxl/qxl_debugfs.c -new file mode 100644 -index 0000000..c630152 ---- /dev/null -+++ b/drivers/gpu/drm/qxl/qxl_debugfs.c -@@ -0,0 +1,135 @@ -+/* -+ * Copyright (C) 2009 Red Hat -+ * -+ * 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, sublicense, 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 above copyright notice and this permission notice (including the -+ * next paragraph) shall be included in all copies or substantial -+ * portions of the Software. -+ * -+ * 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 NONINFRINGEMENT. -+ * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) 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. -+ * -+ */ -+ -+/* -+ * Authors: -+ * Alon Levy -+ */ -+ -+#include -+ -+#include "drmP.h" -+#include "qxl_drv.h" -+#include "qxl_object.h" -+ -+ -+static int -+qxl_debugfs_irq_received(struct seq_file *m, void *data) -+{ -+ struct drm_info_node *node = (struct drm_info_node *) m->private; -+ struct qxl_device *qdev = node->minor->dev->dev_private; -+ -+ seq_printf(m, "%d\n", atomic_read(&qdev->irq_received)); -+ seq_printf(m, "%d\n", atomic_read(&qdev->irq_received_display)); -+ seq_printf(m, "%d\n", atomic_read(&qdev->irq_received_cursor)); -+ seq_printf(m, "%d\n", atomic_read(&qdev->irq_received_io_cmd)); -+ seq_printf(m, "%d\n", qdev->irq_received_error); -+ return 0; -+} -+ -+static int -+qxl_debugfs_buffers_info(struct seq_file *m, void *data) -+{ -+ struct drm_info_node *node = (struct drm_info_node *) m->private; -+ struct qxl_device *qdev = node->minor->dev->dev_private; -+ struct qxl_bo *bo; -+ -+ list_for_each_entry(bo, &qdev->gem.objects, list) { -+ seq_printf(m, "size %ld, pc %d, sync obj %p, num releases %d\n", -+ (unsigned long)bo->gem_base.size, bo->pin_count, -+ bo->tbo.sync_obj, bo->fence.num_active_releases); -+ } -+ return 0; -+} -+ -+static struct drm_info_list qxl_debugfs_list[] = { -+ { "irq_received", qxl_debugfs_irq_received, 0, NULL }, -+ { "qxl_buffers", qxl_debugfs_buffers_info, 0, NULL }, -+}; -+#define QXL_DEBUGFS_ENTRIES ARRAY_SIZE(qxl_debugfs_list) -+ -+int -+qxl_debugfs_init(struct drm_minor *minor) -+{ -+ drm_debugfs_create_files(qxl_debugfs_list, QXL_DEBUGFS_ENTRIES, -+ minor->debugfs_root, minor); -+ return 0; -+} -+ -+void -+qxl_debugfs_takedown(struct drm_minor *minor) -+{ -+ drm_debugfs_remove_files(qxl_debugfs_list, QXL_DEBUGFS_ENTRIES, -+ minor); -+} -+ -+int qxl_debugfs_add_files(struct qxl_device *qdev, -+ struct drm_info_list *files, -+ unsigned nfiles) -+{ -+ unsigned i; -+ -+ for (i = 0; i < qdev->debugfs_count; i++) { -+ if (qdev->debugfs[i].files == files) { -+ /* Already registered */ -+ return 0; -+ } -+ } -+ -+ i = qdev->debugfs_count + 1; -+ if (i > QXL_DEBUGFS_MAX_COMPONENTS) { -+ DRM_ERROR("Reached maximum number of debugfs components.\n"); -+ DRM_ERROR("Report so we increase QXL_DEBUGFS_MAX_COMPONENTS.\n"); -+ return -EINVAL; -+ } -+ qdev->debugfs[qdev->debugfs_count].files = files; -+ qdev->debugfs[qdev->debugfs_count].num_files = nfiles; -+ qdev->debugfs_count = i; -+#if defined(CONFIG_DEBUG_FS) -+ drm_debugfs_create_files(files, nfiles, -+ qdev->ddev->control->debugfs_root, -+ qdev->ddev->control); -+ drm_debugfs_create_files(files, nfiles, -+ qdev->ddev->primary->debugfs_root, -+ qdev->ddev->primary); -+#endif -+ return 0; -+} -+ -+void qxl_debugfs_remove_files(struct qxl_device *qdev) -+{ -+#if defined(CONFIG_DEBUG_FS) -+ unsigned i; -+ -+ for (i = 0; i < qdev->debugfs_count; i++) { -+ drm_debugfs_remove_files(qdev->debugfs[i].files, -+ qdev->debugfs[i].num_files, -+ qdev->ddev->control); -+ drm_debugfs_remove_files(qdev->debugfs[i].files, -+ qdev->debugfs[i].num_files, -+ qdev->ddev->primary); -+ } -+#endif -+} -diff --git a/drivers/gpu/drm/qxl/qxl_dev.h b/drivers/gpu/drm/qxl/qxl_dev.h -new file mode 100644 -index 0000000..94c5aec ---- /dev/null -+++ b/drivers/gpu/drm/qxl/qxl_dev.h -@@ -0,0 +1,879 @@ -+/* -+ Copyright (C) 2009 Red Hat, Inc. -+ -+ Redistribution and use in source and binary forms, with or without -+ modification, are permitted provided that the following conditions are -+ met: -+ -+ * Redistributions of source code must retain the above copyright -+ notice, this list of conditions and the following disclaimer. -+ * Redistributions in binary form must reproduce the above copyright -+ notice, this list of conditions and the following disclaimer in -+ the documentation and/or other materials provided with the -+ distribution. -+ * Neither the name of the copyright holder nor the names of its -+ contributors may be used to endorse or promote products derived -+ from this software without specific prior written permission. -+ -+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS -+ IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED -+ TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -+ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -+ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+*/ -+ -+ -+#ifndef H_QXL_DEV -+#define H_QXL_DEV -+ -+#include -+ -+/* -+ * from spice-protocol -+ * Release 0.10.0 -+ */ -+ -+/* enums.h */ -+ -+enum SpiceImageType { -+ SPICE_IMAGE_TYPE_BITMAP, -+ SPICE_IMAGE_TYPE_QUIC, -+ SPICE_IMAGE_TYPE_RESERVED, -+ SPICE_IMAGE_TYPE_LZ_PLT = 100, -+ SPICE_IMAGE_TYPE_LZ_RGB, -+ SPICE_IMAGE_TYPE_GLZ_RGB, -+ SPICE_IMAGE_TYPE_FROM_CACHE, -+ SPICE_IMAGE_TYPE_SURFACE, -+ SPICE_IMAGE_TYPE_JPEG, -+ SPICE_IMAGE_TYPE_FROM_CACHE_LOSSLESS, -+ SPICE_IMAGE_TYPE_ZLIB_GLZ_RGB, -+ SPICE_IMAGE_TYPE_JPEG_ALPHA, -+ -+ SPICE_IMAGE_TYPE_ENUM_END -+}; -+ -+enum SpiceBitmapFmt { -+ SPICE_BITMAP_FMT_INVALID, -+ SPICE_BITMAP_FMT_1BIT_LE, -+ SPICE_BITMAP_FMT_1BIT_BE, -+ SPICE_BITMAP_FMT_4BIT_LE, -+ SPICE_BITMAP_FMT_4BIT_BE, -+ SPICE_BITMAP_FMT_8BIT, -+ SPICE_BITMAP_FMT_16BIT, -+ SPICE_BITMAP_FMT_24BIT, -+ SPICE_BITMAP_FMT_32BIT, -+ SPICE_BITMAP_FMT_RGBA, -+ -+ SPICE_BITMAP_FMT_ENUM_END -+}; -+ -+enum SpiceSurfaceFmt { -+ SPICE_SURFACE_FMT_INVALID, -+ SPICE_SURFACE_FMT_1_A, -+ SPICE_SURFACE_FMT_8_A = 8, -+ SPICE_SURFACE_FMT_16_555 = 16, -+ SPICE_SURFACE_FMT_32_xRGB = 32, -+ SPICE_SURFACE_FMT_16_565 = 80, -+ SPICE_SURFACE_FMT_32_ARGB = 96, -+ -+ SPICE_SURFACE_FMT_ENUM_END -+}; -+ -+enum SpiceClipType { -+ SPICE_CLIP_TYPE_NONE, -+ SPICE_CLIP_TYPE_RECTS, -+ -+ SPICE_CLIP_TYPE_ENUM_END -+}; -+ -+enum SpiceRopd { -+ SPICE_ROPD_INVERS_SRC = (1 << 0), -+ SPICE_ROPD_INVERS_BRUSH = (1 << 1), -+ SPICE_ROPD_INVERS_DEST = (1 << 2), -+ SPICE_ROPD_OP_PUT = (1 << 3), -+ SPICE_ROPD_OP_OR = (1 << 4), -+ SPICE_ROPD_OP_AND = (1 << 5), -+ SPICE_ROPD_OP_XOR = (1 << 6), -+ SPICE_ROPD_OP_BLACKNESS = (1 << 7), -+ SPICE_ROPD_OP_WHITENESS = (1 << 8), -+ SPICE_ROPD_OP_INVERS = (1 << 9), -+ SPICE_ROPD_INVERS_RES = (1 << 10), -+ -+ SPICE_ROPD_MASK = 0x7ff -+}; -+ -+enum SpiceBrushType { -+ SPICE_BRUSH_TYPE_NONE, -+ SPICE_BRUSH_TYPE_SOLID, -+ SPICE_BRUSH_TYPE_PATTERN, -+ -+ SPICE_BRUSH_TYPE_ENUM_END -+}; -+ -+enum SpiceCursorType { -+ SPICE_CURSOR_TYPE_ALPHA, -+ SPICE_CURSOR_TYPE_MONO, -+ SPICE_CURSOR_TYPE_COLOR4, -+ SPICE_CURSOR_TYPE_COLOR8, -+ SPICE_CURSOR_TYPE_COLOR16, -+ SPICE_CURSOR_TYPE_COLOR24, -+ SPICE_CURSOR_TYPE_COLOR32, -+ -+ SPICE_CURSOR_TYPE_ENUM_END -+}; -+ -+/* qxl_dev.h */ -+ -+#pragma pack(push, 1) -+ -+#define REDHAT_PCI_VENDOR_ID 0x1b36 -+ -+/* 0x100-0x11f reserved for spice, 0x1ff used for unstable work */ -+#define QXL_DEVICE_ID_STABLE 0x0100 -+ -+enum { -+ QXL_REVISION_STABLE_V04 = 0x01, -+ QXL_REVISION_STABLE_V06 = 0x02, -+ QXL_REVISION_STABLE_V10 = 0x03, -+ QXL_REVISION_STABLE_V12 = 0x04, -+}; -+ -+#define QXL_DEVICE_ID_DEVEL 0x01ff -+#define QXL_REVISION_DEVEL 0x01 -+ -+#define QXL_ROM_MAGIC (*(uint32_t *)"QXRO") -+#define QXL_RAM_MAGIC (*(uint32_t *)"QXRA") -+ -+enum { -+ QXL_RAM_RANGE_INDEX, -+ QXL_VRAM_RANGE_INDEX, -+ QXL_ROM_RANGE_INDEX, -+ QXL_IO_RANGE_INDEX, -+ -+ QXL_PCI_RANGES -+}; -+ -+/* qxl-1 compat: append only */ -+enum { -+ QXL_IO_NOTIFY_CMD, -+ QXL_IO_NOTIFY_CURSOR, -+ QXL_IO_UPDATE_AREA, -+ QXL_IO_UPDATE_IRQ, -+ QXL_IO_NOTIFY_OOM, -+ QXL_IO_RESET, -+ QXL_IO_SET_MODE, /* qxl-1 */ -+ QXL_IO_LOG, -+ /* appended for qxl-2 */ -+ QXL_IO_MEMSLOT_ADD, -+ QXL_IO_MEMSLOT_DEL, -+ QXL_IO_DETACH_PRIMARY, -+ QXL_IO_ATTACH_PRIMARY, -+ QXL_IO_CREATE_PRIMARY, -+ QXL_IO_DESTROY_PRIMARY, -+ QXL_IO_DESTROY_SURFACE_WAIT, -+ QXL_IO_DESTROY_ALL_SURFACES, -+ /* appended for qxl-3 */ -+ QXL_IO_UPDATE_AREA_ASYNC, -+ QXL_IO_MEMSLOT_ADD_ASYNC, -+ QXL_IO_CREATE_PRIMARY_ASYNC, -+ QXL_IO_DESTROY_PRIMARY_ASYNC, -+ QXL_IO_DESTROY_SURFACE_ASYNC, -+ QXL_IO_DESTROY_ALL_SURFACES_ASYNC, -+ QXL_IO_FLUSH_SURFACES_ASYNC, -+ QXL_IO_FLUSH_RELEASE, -+ /* appended for qxl-4 */ -+ QXL_IO_MONITORS_CONFIG_ASYNC, -+ -+ QXL_IO_RANGE_SIZE -+}; -+ -+typedef uint64_t QXLPHYSICAL; -+typedef int32_t QXLFIXED; /* fixed 28.4 */ -+ -+struct qxl_point_fix { -+ QXLFIXED x; -+ QXLFIXED y; -+}; -+ -+struct qxl_point { -+ int32_t x; -+ int32_t y; -+}; -+ -+struct qxl_point_1_6 { -+ int16_t x; -+ int16_t y; -+}; -+ -+struct qxl_rect { -+ int32_t top; -+ int32_t left; -+ int32_t bottom; -+ int32_t right; -+}; -+ -+struct qxl_urect { -+ uint32_t top; -+ uint32_t left; -+ uint32_t bottom; -+ uint32_t right; -+}; -+ -+/* qxl-1 compat: append only */ -+struct qxl_rom { -+ uint32_t magic; -+ uint32_t id; -+ uint32_t update_id; -+ uint32_t compression_level; -+ uint32_t log_level; -+ uint32_t mode; /* qxl-1 */ -+ uint32_t modes_offset; -+ uint32_t num_io_pages; -+ uint32_t pages_offset; /* qxl-1 */ -+ uint32_t draw_area_offset; /* qxl-1 */ -+ uint32_t surface0_area_size; /* qxl-1 name: draw_area_size */ -+ uint32_t ram_header_offset; -+ uint32_t mm_clock; -+ /* appended for qxl-2 */ -+ uint32_t n_surfaces; -+ uint64_t flags; -+ uint8_t slots_start; -+ uint8_t slots_end; -+ uint8_t slot_gen_bits; -+ uint8_t slot_id_bits; -+ uint8_t slot_generation; -+ /* appended for qxl-4 */ -+ uint8_t client_present; -+ uint8_t client_capabilities[58]; -+ uint32_t client_monitors_config_crc; -+ struct { -+ uint16_t count; -+ uint16_t padding; -+ struct qxl_urect heads[64]; -+ } client_monitors_config; -+}; -+ -+/* qxl-1 compat: fixed */ -+struct qxl_mode { -+ uint32_t id; -+ uint32_t x_res; -+ uint32_t y_res; -+ uint32_t bits; -+ uint32_t stride; -+ uint32_t x_mili; -+ uint32_t y_mili; -+ uint32_t orientation; -+}; -+ -+/* qxl-1 compat: fixed */ -+struct qxl_modes { -+ uint32_t n_modes; -+ struct qxl_mode modes[0]; -+}; -+ -+/* qxl-1 compat: append only */ -+enum qxl_cmd_type { -+ QXL_CMD_NOP, -+ QXL_CMD_DRAW, -+ QXL_CMD_UPDATE, -+ QXL_CMD_CURSOR, -+ QXL_CMD_MESSAGE, -+ QXL_CMD_SURFACE, -+}; -+ -+/* qxl-1 compat: fixed */ -+struct qxl_command { -+ QXLPHYSICAL data; -+ uint32_t type; -+ uint32_t padding; -+}; -+ -+#define QXL_COMMAND_FLAG_COMPAT (1<<0) -+#define QXL_COMMAND_FLAG_COMPAT_16BPP (2<<0) -+ -+struct qxl_command_ext { -+ struct qxl_command cmd; -+ uint32_t group_id; -+ uint32_t flags; -+}; -+ -+struct qxl_mem_slot { -+ uint64_t mem_start; -+ uint64_t mem_end; -+}; -+ -+#define QXL_SURF_TYPE_PRIMARY 0 -+ -+#define QXL_SURF_FLAG_KEEP_DATA (1 << 0) -+ -+struct qxl_surface_create { -+ uint32_t width; -+ uint32_t height; -+ int32_t stride; -+ uint32_t format; -+ uint32_t position; -+ uint32_t mouse_mode; -+ uint32_t flags; -+ uint32_t type; -+ QXLPHYSICAL mem; -+}; -+ -+#define QXL_COMMAND_RING_SIZE 32 -+#define QXL_CURSOR_RING_SIZE 32 -+#define QXL_RELEASE_RING_SIZE 8 -+ -+#define QXL_LOG_BUF_SIZE 4096 -+ -+#define QXL_INTERRUPT_DISPLAY (1 << 0) -+#define QXL_INTERRUPT_CURSOR (1 << 1) -+#define QXL_INTERRUPT_IO_CMD (1 << 2) -+#define QXL_INTERRUPT_ERROR (1 << 3) -+#define QXL_INTERRUPT_CLIENT (1 << 4) -+#define QXL_INTERRUPT_CLIENT_MONITORS_CONFIG (1 << 5) -+ -+struct qxl_ring_header { -+ uint32_t num_items; -+ uint32_t prod; -+ uint32_t notify_on_prod; -+ uint32_t cons; -+ uint32_t notify_on_cons; -+}; -+ -+/* qxl-1 compat: append only */ -+struct qxl_ram_header { -+ uint32_t magic; -+ uint32_t int_pending; -+ uint32_t int_mask; -+ uint8_t log_buf[QXL_LOG_BUF_SIZE]; -+ struct qxl_ring_header cmd_ring_hdr; -+ struct qxl_command cmd_ring[QXL_COMMAND_RING_SIZE]; -+ struct qxl_ring_header cursor_ring_hdr; -+ struct qxl_command cursor_ring[QXL_CURSOR_RING_SIZE]; -+ struct qxl_ring_header release_ring_hdr; -+ uint64_t release_ring[QXL_RELEASE_RING_SIZE]; -+ struct qxl_rect update_area; -+ /* appended for qxl-2 */ -+ uint32_t update_surface; -+ struct qxl_mem_slot mem_slot; -+ struct qxl_surface_create create_surface; -+ uint64_t flags; -+ -+ /* appended for qxl-4 */ -+ -+ /* used by QXL_IO_MONITORS_CONFIG_ASYNC */ -+ QXLPHYSICAL monitors_config; -+ uint8_t guest_capabilities[64]; -+}; -+ -+union qxl_release_info { -+ uint64_t id; /* in */ -+ uint64_t next; /* out */ -+}; -+ -+struct qxl_release_info_ext { -+ union qxl_release_info *info; -+ uint32_t group_id; -+}; -+ -+struct qxl_data_chunk { -+ uint32_t data_size; -+ QXLPHYSICAL prev_chunk; -+ QXLPHYSICAL next_chunk; -+ uint8_t data[0]; -+}; -+ -+struct qxl_message { -+ union qxl_release_info release_info; -+ uint8_t data[0]; -+}; -+ -+struct qxl_compat_update_cmd { -+ union qxl_release_info release_info; -+ struct qxl_rect area; -+ uint32_t update_id; -+}; -+ -+struct qxl_update_cmd { -+ union qxl_release_info release_info; -+ struct qxl_rect area; -+ uint32_t update_id; -+ uint32_t surface_id; -+}; -+ -+struct qxl_cursor_header { -+ uint64_t unique; -+ uint16_t type; -+ uint16_t width; -+ uint16_t height; -+ uint16_t hot_spot_x; -+ uint16_t hot_spot_y; -+}; -+ -+struct qxl_cursor { -+ struct qxl_cursor_header header; -+ uint32_t data_size; -+ struct qxl_data_chunk chunk; -+}; -+ -+enum { -+ QXL_CURSOR_SET, -+ QXL_CURSOR_MOVE, -+ QXL_CURSOR_HIDE, -+ QXL_CURSOR_TRAIL, -+}; -+ -+#define QXL_CURSOR_DEVICE_DATA_SIZE 128 -+ -+struct qxl_cursor_cmd { -+ union qxl_release_info release_info; -+ uint8_t type; -+ union { -+ struct { -+ struct qxl_point_1_6 position; -+ uint8_t visible; -+ QXLPHYSICAL shape; -+ } set; -+ struct { -+ uint16_t length; -+ uint16_t frequency; -+ } trail; -+ struct qxl_point_1_6 position; -+ } u; -+ /* todo: dynamic size from rom */ -+ uint8_t device_data[QXL_CURSOR_DEVICE_DATA_SIZE]; -+}; -+ -+enum { -+ QXL_DRAW_NOP, -+ QXL_DRAW_FILL, -+ QXL_DRAW_OPAQUE, -+ QXL_DRAW_COPY, -+ QXL_COPY_BITS, -+ QXL_DRAW_BLEND, -+ QXL_DRAW_BLACKNESS, -+ QXL_DRAW_WHITENESS, -+ QXL_DRAW_INVERS, -+ QXL_DRAW_ROP3, -+ QXL_DRAW_STROKE, -+ QXL_DRAW_TEXT, -+ QXL_DRAW_TRANSPARENT, -+ QXL_DRAW_ALPHA_BLEND, -+ QXL_DRAW_COMPOSITE -+}; -+ -+struct qxl_raster_glyph { -+ struct qxl_point render_pos; -+ struct qxl_point glyph_origin; -+ uint16_t width; -+ uint16_t height; -+ uint8_t data[0]; -+}; -+ -+struct qxl_string { -+ uint32_t data_size; -+ uint16_t length; -+ uint16_t flags; -+ struct qxl_data_chunk chunk; -+}; -+ -+struct qxl_copy_bits { -+ struct qxl_point src_pos; -+}; -+ -+enum qxl_effect_type { -+ QXL_EFFECT_BLEND = 0, -+ QXL_EFFECT_OPAQUE = 1, -+ QXL_EFFECT_REVERT_ON_DUP = 2, -+ QXL_EFFECT_BLACKNESS_ON_DUP = 3, -+ QXL_EFFECT_WHITENESS_ON_DUP = 4, -+ QXL_EFFECT_NOP_ON_DUP = 5, -+ QXL_EFFECT_NOP = 6, -+ QXL_EFFECT_OPAQUE_BRUSH = 7 -+}; -+ -+struct qxl_pattern { -+ QXLPHYSICAL pat; -+ struct qxl_point pos; -+}; -+ -+struct qxl_brush { -+ uint32_t type; -+ union { -+ uint32_t color; -+ struct qxl_pattern pattern; -+ } u; -+}; -+ -+struct qxl_q_mask { -+ uint8_t flags; -+ struct qxl_point pos; -+ QXLPHYSICAL bitmap; -+}; -+ -+struct qxl_fill { -+ struct qxl_brush brush; -+ uint16_t rop_descriptor; -+ struct qxl_q_mask mask; -+}; -+ -+struct qxl_opaque { -+ QXLPHYSICAL src_bitmap; -+ struct qxl_rect src_area; -+ struct qxl_brush brush; -+ uint16_t rop_descriptor; -+ uint8_t scale_mode; -+ struct qxl_q_mask mask; -+}; -+ -+struct qxl_copy { -+ QXLPHYSICAL src_bitmap; -+ struct qxl_rect src_area; -+ uint16_t rop_descriptor; -+ uint8_t scale_mode; -+ struct qxl_q_mask mask; -+}; -+ -+struct qxl_transparent { -+ QXLPHYSICAL src_bitmap; -+ struct qxl_rect src_area; -+ uint32_t src_color; -+ uint32_t true_color; -+}; -+ -+struct qxl_alpha_blend { -+ uint16_t alpha_flags; -+ uint8_t alpha; -+ QXLPHYSICAL src_bitmap; -+ struct qxl_rect src_area; -+}; -+ -+struct qxl_compat_alpha_blend { -+ uint8_t alpha; -+ QXLPHYSICAL src_bitmap; -+ struct qxl_rect src_area; -+}; -+ -+struct qxl_rop_3 { -+ QXLPHYSICAL src_bitmap; -+ struct qxl_rect src_area; -+ struct qxl_brush brush; -+ uint8_t rop3; -+ uint8_t scale_mode; -+ struct qxl_q_mask mask; -+}; -+ -+struct qxl_line_attr { -+ uint8_t flags; -+ uint8_t join_style; -+ uint8_t end_style; -+ uint8_t style_nseg; -+ QXLFIXED width; -+ QXLFIXED miter_limit; -+ QXLPHYSICAL style; -+}; -+ -+struct qxl_stroke { -+ QXLPHYSICAL path; -+ struct qxl_line_attr attr; -+ struct qxl_brush brush; -+ uint16_t fore_mode; -+ uint16_t back_mode; -+}; -+ -+struct qxl_text { -+ QXLPHYSICAL str; -+ struct qxl_rect back_area; -+ struct qxl_brush fore_brush; -+ struct qxl_brush back_brush; -+ uint16_t fore_mode; -+ uint16_t back_mode; -+}; -+ -+struct qxl_mask { -+ struct qxl_q_mask mask; -+}; -+ -+struct qxl_clip { -+ uint32_t type; -+ QXLPHYSICAL data; -+}; -+ -+enum qxl_operator { -+ QXL_OP_CLEAR = 0x00, -+ QXL_OP_SOURCE = 0x01, -+ QXL_OP_DST = 0x02, -+ QXL_OP_OVER = 0x03, -+ QXL_OP_OVER_REVERSE = 0x04, -+ QXL_OP_IN = 0x05, -+ QXL_OP_IN_REVERSE = 0x06, -+ QXL_OP_OUT = 0x07, -+ QXL_OP_OUT_REVERSE = 0x08, -+ QXL_OP_ATOP = 0x09, -+ QXL_OP_ATOP_REVERSE = 0x0a, -+ QXL_OP_XOR = 0x0b, -+ QXL_OP_ADD = 0x0c, -+ QXL_OP_SATURATE = 0x0d, -+ /* Note the jump here from 0x0d to 0x30 */ -+ QXL_OP_MULTIPLY = 0x30, -+ QXL_OP_SCREEN = 0x31, -+ QXL_OP_OVERLAY = 0x32, -+ QXL_OP_DARKEN = 0x33, -+ QXL_OP_LIGHTEN = 0x34, -+ QXL_OP_COLOR_DODGE = 0x35, -+ QXL_OP_COLOR_BURN = 0x36, -+ QXL_OP_HARD_LIGHT = 0x37, -+ QXL_OP_SOFT_LIGHT = 0x38, -+ QXL_OP_DIFFERENCE = 0x39, -+ QXL_OP_EXCLUSION = 0x3a, -+ QXL_OP_HSL_HUE = 0x3b, -+ QXL_OP_HSL_SATURATION = 0x3c, -+ QXL_OP_HSL_COLOR = 0x3d, -+ QXL_OP_HSL_LUMINOSITY = 0x3e -+}; -+ -+struct qxl_transform { -+ uint32_t t00; -+ uint32_t t01; -+ uint32_t t02; -+ uint32_t t10; -+ uint32_t t11; -+ uint32_t t12; -+}; -+ -+/* The flags field has the following bit fields: -+ * -+ * operator: [ 0 - 7 ] -+ * src_filter: [ 8 - 10 ] -+ * mask_filter: [ 11 - 13 ] -+ * src_repeat: [ 14 - 15 ] -+ * mask_repeat: [ 16 - 17 ] -+ * component_alpha: [ 18 - 18 ] -+ * reserved: [ 19 - 31 ] -+ * -+ * The repeat and filter values are those of pixman: -+ * REPEAT_NONE = 0 -+ * REPEAT_NORMAL = 1 -+ * REPEAT_PAD = 2 -+ * REPEAT_REFLECT = 3 -+ * -+ * The filter values are: -+ * FILTER_NEAREST = 0 -+ * FILTER_BILINEAR = 1 -+ */ -+struct qxl_composite { -+ uint32_t flags; -+ -+ QXLPHYSICAL src; -+ QXLPHYSICAL src_transform; /* May be NULL */ -+ QXLPHYSICAL mask; /* May be NULL */ -+ QXLPHYSICAL mask_transform; /* May be NULL */ -+ struct qxl_point_1_6 src_origin; -+ struct qxl_point_1_6 mask_origin; -+}; -+ -+struct qxl_compat_drawable { -+ union qxl_release_info release_info; -+ uint8_t effect; -+ uint8_t type; -+ uint16_t bitmap_offset; -+ struct qxl_rect bitmap_area; -+ struct qxl_rect bbox; -+ struct qxl_clip clip; -+ uint32_t mm_time; -+ union { -+ struct qxl_fill fill; -+ struct qxl_opaque opaque; -+ struct qxl_copy copy; -+ struct qxl_transparent transparent; -+ struct qxl_compat_alpha_blend alpha_blend; -+ struct qxl_copy_bits copy_bits; -+ struct qxl_copy blend; -+ struct qxl_rop_3 rop3; -+ struct qxl_stroke stroke; -+ struct qxl_text text; -+ struct qxl_mask blackness; -+ struct qxl_mask invers; -+ struct qxl_mask whiteness; -+ } u; -+}; -+ -+struct qxl_drawable { -+ union qxl_release_info release_info; -+ uint32_t surface_id; -+ uint8_t effect; -+ uint8_t type; -+ uint8_t self_bitmap; -+ struct qxl_rect self_bitmap_area; -+ struct qxl_rect bbox; -+ struct qxl_clip clip; -+ uint32_t mm_time; -+ int32_t surfaces_dest[3]; -+ struct qxl_rect surfaces_rects[3]; -+ union { -+ struct qxl_fill fill; -+ struct qxl_opaque opaque; -+ struct qxl_copy copy; -+ struct qxl_transparent transparent; -+ struct qxl_alpha_blend alpha_blend; -+ struct qxl_copy_bits copy_bits; -+ struct qxl_copy blend; -+ struct qxl_rop_3 rop3; -+ struct qxl_stroke stroke; -+ struct qxl_text text; -+ struct qxl_mask blackness; -+ struct qxl_mask invers; -+ struct qxl_mask whiteness; -+ struct qxl_composite composite; -+ } u; -+}; -+ -+enum qxl_surface_cmd_type { -+ QXL_SURFACE_CMD_CREATE, -+ QXL_SURFACE_CMD_DESTROY, -+}; -+ -+struct qxl_surface { -+ uint32_t format; -+ uint32_t width; -+ uint32_t height; -+ int32_t stride; -+ QXLPHYSICAL data; -+}; -+ -+struct qxl_surface_cmd { -+ union qxl_release_info release_info; -+ uint32_t surface_id; -+ uint8_t type; -+ uint32_t flags; -+ union { -+ struct qxl_surface surface_create; -+ } u; -+}; -+ -+struct qxl_clip_rects { -+ uint32_t num_rects; -+ struct qxl_data_chunk chunk; -+}; -+ -+enum { -+ QXL_PATH_BEGIN = (1 << 0), -+ QXL_PATH_END = (1 << 1), -+ QXL_PATH_CLOSE = (1 << 3), -+ QXL_PATH_BEZIER = (1 << 4), -+}; -+ -+struct qxl_path_seg { -+ uint32_t flags; -+ uint32_t count; -+ struct qxl_point_fix points[0]; -+}; -+ -+struct qxl_path { -+ uint32_t data_size; -+ struct qxl_data_chunk chunk; -+}; -+ -+enum { -+ QXL_IMAGE_GROUP_DRIVER, -+ QXL_IMAGE_GROUP_DEVICE, -+ QXL_IMAGE_GROUP_RED, -+ QXL_IMAGE_GROUP_DRIVER_DONT_CACHE, -+}; -+ -+struct qxl_image_id { -+ uint32_t group; -+ uint32_t unique; -+}; -+ -+union qxl_image_id_union { -+ struct qxl_image_id id; -+ uint64_t value; -+}; -+ -+enum qxl_image_flags { -+ QXL_IMAGE_CACHE = (1 << 0), -+ QXL_IMAGE_HIGH_BITS_SET = (1 << 1), -+}; -+ -+enum qxl_bitmap_flags { -+ QXL_BITMAP_DIRECT = (1 << 0), -+ QXL_BITMAP_UNSTABLE = (1 << 1), -+ QXL_BITMAP_TOP_DOWN = (1 << 2), /* == SPICE_BITMAP_FLAGS_TOP_DOWN */ -+}; -+ -+#define QXL_SET_IMAGE_ID(image, _group, _unique) { \ -+ (image)->descriptor.id = (((uint64_t)_unique) << 32) | _group; \ -+} -+ -+struct qxl_image_descriptor { -+ uint64_t id; -+ uint8_t type; -+ uint8_t flags; -+ uint32_t width; -+ uint32_t height; -+}; -+ -+struct qxl_palette { -+ uint64_t unique; -+ uint16_t num_ents; -+ uint32_t ents[0]; -+}; -+ -+struct qxl_bitmap { -+ uint8_t format; -+ uint8_t flags; -+ uint32_t x; -+ uint32_t y; -+ uint32_t stride; -+ QXLPHYSICAL palette; -+ QXLPHYSICAL data; /* data[0] ? */ -+}; -+ -+struct qxl_surface_id { -+ uint32_t surface_id; -+}; -+ -+struct qxl_encoder_data { -+ uint32_t data_size; -+ uint8_t data[0]; -+}; -+ -+struct qxl_image { -+ struct qxl_image_descriptor descriptor; -+ union { /* variable length */ -+ struct qxl_bitmap bitmap; -+ struct qxl_encoder_data quic; -+ struct qxl_surface_id surface_image; -+ } u; -+}; -+ -+/* A QXLHead is a single monitor output backed by a QXLSurface. -+ * x and y offsets are unsigned since they are used in relation to -+ * the given surface, not the same as the x, y coordinates in the guest -+ * screen reference frame. */ -+struct qxl_head { -+ uint32_t id; -+ uint32_t surface_id; -+ uint32_t width; -+ uint32_t height; -+ uint32_t x; -+ uint32_t y; -+ uint32_t flags; -+}; -+ -+struct qxl_monitors_config { -+ uint16_t count; -+ uint16_t max_allowed; /* If it is 0 no fixed limit is given by the -+ driver */ -+ struct qxl_head heads[0]; -+}; -+ -+#pragma pack(pop) -+ -+#endif /* _H_QXL_DEV */ -diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c -new file mode 100644 -index 0000000..c80ddfe ---- /dev/null -+++ b/drivers/gpu/drm/qxl/qxl_display.c -@@ -0,0 +1,981 @@ -+/* -+ * Copyright 2013 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, sublicense, -+ * 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 above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * 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 NONINFRINGEMENT. IN NO EVENT SHALL -+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. -+ * -+ * Authors: Dave Airlie -+ * Alon Levy -+ */ -+ -+ -+#include "linux/crc32.h" -+ -+#include "qxl_drv.h" -+#include "qxl_object.h" -+#include "drm_crtc_helper.h" -+ -+static void qxl_crtc_set_to_mode(struct qxl_device *qdev, -+ struct drm_connector *connector, -+ struct qxl_head *head) -+{ -+ struct drm_device *dev = connector->dev; -+ struct drm_display_mode *mode, *t; -+ int width = head->width; -+ int height = head->height; -+ -+ if (width < 320 || height < 240) { -+ qxl_io_log(qdev, "%s: bad head: %dx%d", width, height); -+ width = 1024; -+ height = 768; -+ } -+ if (width * height * 4 > 16*1024*1024) { -+ width = 1024; -+ height = 768; -+ } -+ /* TODO: go over regular modes and removed preferred? */ -+ list_for_each_entry_safe(mode, t, &connector->probed_modes, head) -+ drm_mode_remove(connector, mode); -+ mode = drm_cvt_mode(dev, width, height, 60, false, false, false); -+ mode->type |= DRM_MODE_TYPE_PREFERRED; -+ mode->status = MODE_OK; -+ drm_mode_probed_add(connector, mode); -+ qxl_io_log(qdev, "%s: %d x %d\n", __func__, width, height); -+} -+ -+void qxl_crtc_set_from_monitors_config(struct qxl_device *qdev) -+{ -+ struct drm_connector *connector; -+ int i; -+ struct drm_device *dev = qdev->ddev; -+ -+ i = 0; -+ qxl_io_log(qdev, "%s: %d, %d\n", __func__, -+ dev->mode_config.num_connector, -+ qdev->monitors_config->count); -+ list_for_each_entry(connector, &dev->mode_config.connector_list, head) { -+ if (i > qdev->monitors_config->count) { -+ /* crtc will be reported as disabled */ -+ continue; -+ } -+ qxl_crtc_set_to_mode(qdev, connector, -+ &qdev->monitors_config->heads[i]); -+ ++i; -+ } -+} -+ -+void qxl_alloc_client_monitors_config(struct qxl_device *qdev, unsigned count) -+{ -+ if (qdev->client_monitors_config && -+ count > qdev->client_monitors_config->count) { -+ kfree(qdev->client_monitors_config); -+ } -+ if (!qdev->client_monitors_config) { -+ qdev->client_monitors_config = kzalloc( -+ sizeof(struct qxl_monitors_config) + -+ sizeof(struct qxl_head) * count, GFP_KERNEL); -+ if (!qdev->client_monitors_config) { -+ qxl_io_log(qdev, -+ "%s: allocation failure for %u heads\n", -+ __func__, count); -+ return; -+ } -+ } -+ qdev->client_monitors_config->count = count; -+} -+ -+static int qxl_display_copy_rom_client_monitors_config(struct qxl_device *qdev) -+{ -+ int i; -+ int num_monitors; -+ uint32_t crc; -+ -+ BUG_ON(!qdev->monitors_config); -+ num_monitors = qdev->rom->client_monitors_config.count; -+ crc = crc32(0, (const uint8_t *)&qdev->rom->client_monitors_config, -+ sizeof(qdev->rom->client_monitors_config)); -+ if (crc != qdev->rom->client_monitors_config_crc) { -+ qxl_io_log(qdev, "crc mismatch: have %X (%d) != %X\n", crc, -+ sizeof(qdev->rom->client_monitors_config), -+ qdev->rom->client_monitors_config_crc); -+ return 1; -+ } -+ if (num_monitors > qdev->monitors_config->max_allowed) { -+ DRM_INFO("client monitors list will be truncated: %d < %d\n", -+ qdev->monitors_config->max_allowed, num_monitors); -+ num_monitors = qdev->monitors_config->max_allowed; -+ } else { -+ num_monitors = qdev->rom->client_monitors_config.count; -+ } -+ qxl_alloc_client_monitors_config(qdev, num_monitors); -+ /* we copy max from the client but it isn't used */ -+ qdev->client_monitors_config->max_allowed = -+ qdev->monitors_config->max_allowed; -+ for (i = 0 ; i < qdev->client_monitors_config->count ; ++i) { -+ struct qxl_urect *c_rect = -+ &qdev->rom->client_monitors_config.heads[i]; -+ struct qxl_head *client_head = -+ &qdev->client_monitors_config->heads[i]; -+ struct qxl_head *head = &qdev->monitors_config->heads[i]; -+ client_head->x = head->x = c_rect->left; -+ client_head->y = head->y = c_rect->top; -+ client_head->width = head->width = -+ c_rect->right - c_rect->left; -+ client_head->height = head->height = -+ c_rect->bottom - c_rect->top; -+ client_head->surface_id = head->surface_id = 0; -+ client_head->id = head->id = i; -+ client_head->flags = head->flags = 0; -+ QXL_DEBUG(qdev, "read %dx%d+%d+%d\n", head->width, head->height, -+ head->x, head->y); -+ } -+ return 0; -+} -+ -+void qxl_display_read_client_monitors_config(struct qxl_device *qdev) -+{ -+ -+ while (qxl_display_copy_rom_client_monitors_config(qdev)) { -+ qxl_io_log(qdev, "failed crc check for client_monitors_config," -+ " retrying\n"); -+ } -+ qxl_crtc_set_from_monitors_config(qdev); -+ /* fire off a uevent and let userspace tell us what to do */ -+ qxl_io_log(qdev, "calling drm_sysfs_hotplug_event\n"); -+ drm_sysfs_hotplug_event(qdev->ddev); -+} -+ -+static int qxl_add_monitors_config_modes(struct drm_connector *connector) -+{ -+ struct drm_device *dev = connector->dev; -+ struct qxl_device *qdev = dev->dev_private; -+ struct qxl_output *output = drm_connector_to_qxl_output(connector); -+ int h = output->index; -+ struct drm_display_mode *mode = NULL; -+ struct qxl_head *head; -+ -+ if (!qdev->monitors_config) -+ return 0; -+ head = &qdev->monitors_config->heads[h]; -+ -+ mode = drm_cvt_mode(dev, head->width, head->height, 60, false, false, -+ false); -+ mode->type |= DRM_MODE_TYPE_PREFERRED; -+ drm_mode_probed_add(connector, mode); -+ return 1; -+} -+ -+static int qxl_add_common_modes(struct drm_connector *connector) -+{ -+ struct drm_device *dev = connector->dev; -+ struct drm_display_mode *mode = NULL; -+ int i; -+ struct mode_size { -+ int w; -+ int h; -+ } common_modes[] = { -+ { 640, 480}, -+ { 720, 480}, -+ { 800, 600}, -+ { 848, 480}, -+ {1024, 768}, -+ {1152, 768}, -+ {1280, 720}, -+ {1280, 800}, -+ {1280, 854}, -+ {1280, 960}, -+ {1280, 1024}, -+ {1440, 900}, -+ {1400, 1050}, -+ {1680, 1050}, -+ {1600, 1200}, -+ {1920, 1080}, -+ {1920, 1200} -+ }; -+ -+ for (i = 0; i < ARRAY_SIZE(common_modes); i++) { -+ if (common_modes[i].w < 320 || common_modes[i].h < 200) -+ continue; -+ -+ mode = drm_cvt_mode(dev, common_modes[i].w, common_modes[i].h, -+ 60, false, false, false); -+ if (common_modes[i].w == 1024 && common_modes[i].h == 768) -+ mode->type |= DRM_MODE_TYPE_PREFERRED; -+ drm_mode_probed_add(connector, mode); -+ } -+ return i - 1; -+} -+ -+static void qxl_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, -+ u16 *blue, uint32_t start, uint32_t size) -+{ -+ /* TODO */ -+} -+ -+static void qxl_crtc_destroy(struct drm_crtc *crtc) -+{ -+ struct qxl_crtc *qxl_crtc = to_qxl_crtc(crtc); -+ -+ drm_crtc_cleanup(crtc); -+ kfree(qxl_crtc); -+} -+ -+static void -+qxl_hide_cursor(struct qxl_device *qdev) -+{ -+ struct qxl_release *release; -+ struct qxl_cursor_cmd *cmd; -+ int ret; -+ -+ ret = qxl_alloc_release_reserved(qdev, sizeof(*cmd), QXL_RELEASE_CURSOR_CMD, -+ &release, NULL); -+ -+ cmd = (struct qxl_cursor_cmd *)qxl_release_map(qdev, release); -+ cmd->type = QXL_CURSOR_HIDE; -+ qxl_release_unmap(qdev, release, &cmd->release_info); -+ -+ qxl_fence_releaseable(qdev, release); -+ qxl_push_cursor_ring_release(qdev, release, QXL_CMD_CURSOR, false); -+ qxl_release_unreserve(qdev, release); -+} -+ -+static int qxl_crtc_cursor_set(struct drm_crtc *crtc, -+ struct drm_file *file_priv, -+ uint32_t handle, -+ uint32_t width, -+ uint32_t height) -+{ -+ struct drm_device *dev = crtc->dev; -+ struct qxl_device *qdev = dev->dev_private; -+ struct qxl_crtc *qcrtc = to_qxl_crtc(crtc); -+ struct drm_gem_object *obj; -+ struct qxl_cursor *cursor; -+ struct qxl_cursor_cmd *cmd; -+ struct qxl_bo *cursor_bo, *user_bo; -+ struct qxl_release *release; -+ void *user_ptr; -+ -+ int size = 64*64*4; -+ int ret = 0; -+ if (!handle) { -+ qxl_hide_cursor(qdev); -+ return 0; -+ } -+ -+ obj = drm_gem_object_lookup(crtc->dev, file_priv, handle); -+ if (!obj) { -+ DRM_ERROR("cannot find cursor object\n"); -+ return -ENOENT; -+ } -+ -+ user_bo = gem_to_qxl_bo(obj); -+ -+ ret = qxl_bo_reserve(user_bo, false); -+ if (ret) -+ goto out_unref; -+ -+ ret = qxl_bo_pin(user_bo, QXL_GEM_DOMAIN_CPU, NULL); -+ if (ret) -+ goto out_unreserve; -+ -+ ret = qxl_bo_kmap(user_bo, &user_ptr); -+ if (ret) -+ goto out_unpin; -+ -+ ret = qxl_alloc_release_reserved(qdev, sizeof(*cmd), -+ QXL_RELEASE_CURSOR_CMD, -+ &release, NULL); -+ if (ret) -+ goto out_kunmap; -+ ret = qxl_alloc_bo_reserved(qdev, sizeof(struct qxl_cursor) + size, -+ &cursor_bo); -+ if (ret) -+ goto out_free_release; -+ ret = qxl_bo_kmap(cursor_bo, (void **)&cursor); -+ if (ret) -+ goto out_free_bo; -+ -+ cursor->header.unique = 0; -+ cursor->header.type = SPICE_CURSOR_TYPE_ALPHA; -+ cursor->header.width = 64; -+ cursor->header.height = 64; -+ cursor->header.hot_spot_x = 0; -+ cursor->header.hot_spot_y = 0; -+ cursor->data_size = size; -+ cursor->chunk.next_chunk = 0; -+ cursor->chunk.prev_chunk = 0; -+ cursor->chunk.data_size = size; -+ -+ memcpy(cursor->chunk.data, user_ptr, size); -+ -+ qxl_bo_kunmap(cursor_bo); -+ -+ /* finish with the userspace bo */ -+ qxl_bo_kunmap(user_bo); -+ qxl_bo_unpin(user_bo); -+ qxl_bo_unreserve(user_bo); -+ drm_gem_object_unreference_unlocked(obj); -+ -+ cmd = (struct qxl_cursor_cmd *)qxl_release_map(qdev, release); -+ cmd->type = QXL_CURSOR_SET; -+ cmd->u.set.position.x = qcrtc->cur_x; -+ cmd->u.set.position.y = qcrtc->cur_y; -+ -+ cmd->u.set.shape = qxl_bo_physical_address(qdev, cursor_bo, 0); -+ qxl_release_add_res(qdev, release, cursor_bo); -+ -+ cmd->u.set.visible = 1; -+ qxl_release_unmap(qdev, release, &cmd->release_info); -+ -+ qxl_fence_releaseable(qdev, release); -+ qxl_push_cursor_ring_release(qdev, release, QXL_CMD_CURSOR, false); -+ qxl_release_unreserve(qdev, release); -+ -+ qxl_bo_unreserve(cursor_bo); -+ qxl_bo_unref(&cursor_bo); -+ -+ return ret; -+out_free_bo: -+ qxl_bo_unref(&cursor_bo); -+out_free_release: -+ qxl_release_unreserve(qdev, release); -+ qxl_release_free(qdev, release); -+out_kunmap: -+ qxl_bo_kunmap(user_bo); -+out_unpin: -+ qxl_bo_unpin(user_bo); -+out_unreserve: -+ qxl_bo_unreserve(user_bo); -+out_unref: -+ drm_gem_object_unreference_unlocked(obj); -+ return ret; -+} -+ -+static int qxl_crtc_cursor_move(struct drm_crtc *crtc, -+ int x, int y) -+{ -+ struct drm_device *dev = crtc->dev; -+ struct qxl_device *qdev = dev->dev_private; -+ struct qxl_crtc *qcrtc = to_qxl_crtc(crtc); -+ struct qxl_release *release; -+ struct qxl_cursor_cmd *cmd; -+ int ret; -+ -+ ret = qxl_alloc_release_reserved(qdev, sizeof(*cmd), QXL_RELEASE_CURSOR_CMD, -+ &release, NULL); -+ -+ qcrtc->cur_x = x; -+ qcrtc->cur_y = y; -+ -+ cmd = (struct qxl_cursor_cmd *)qxl_release_map(qdev, release); -+ cmd->type = QXL_CURSOR_MOVE; -+ cmd->u.position.x = qcrtc->cur_x; -+ cmd->u.position.y = qcrtc->cur_y; -+ qxl_release_unmap(qdev, release, &cmd->release_info); -+ -+ qxl_fence_releaseable(qdev, release); -+ qxl_push_cursor_ring_release(qdev, release, QXL_CMD_CURSOR, false); -+ qxl_release_unreserve(qdev, release); -+ return 0; -+} -+ -+ -+static const struct drm_crtc_funcs qxl_crtc_funcs = { -+ .cursor_set = qxl_crtc_cursor_set, -+ .cursor_move = qxl_crtc_cursor_move, -+ .gamma_set = qxl_crtc_gamma_set, -+ .set_config = drm_crtc_helper_set_config, -+ .destroy = qxl_crtc_destroy, -+}; -+ -+static void qxl_user_framebuffer_destroy(struct drm_framebuffer *fb) -+{ -+ struct qxl_framebuffer *qxl_fb = to_qxl_framebuffer(fb); -+ -+ if (qxl_fb->obj) -+ drm_gem_object_unreference_unlocked(qxl_fb->obj); -+ drm_framebuffer_cleanup(fb); -+ kfree(qxl_fb); -+} -+ -+int qxl_framebuffer_surface_dirty(struct drm_framebuffer *fb, -+ struct drm_file *file_priv, -+ unsigned flags, unsigned color, -+ struct drm_clip_rect *clips, -+ unsigned num_clips) -+{ -+ /* TODO: vmwgfx where this was cribbed from had locking. Why? */ -+ struct qxl_framebuffer *qxl_fb = to_qxl_framebuffer(fb); -+ struct qxl_device *qdev = qxl_fb->base.dev->dev_private; -+ struct drm_clip_rect norect; -+ struct qxl_bo *qobj; -+ int inc = 1; -+ -+ qobj = gem_to_qxl_bo(qxl_fb->obj); -+ if (qxl_fb != qdev->active_user_framebuffer) { -+ DRM_INFO("%s: qxl_fb 0x%p != qdev->active_user_framebuffer 0x%p\n", -+ __func__, qxl_fb, qdev->active_user_framebuffer); -+ } -+ if (!num_clips) { -+ num_clips = 1; -+ clips = &norect; -+ norect.x1 = norect.y1 = 0; -+ norect.x2 = fb->width; -+ norect.y2 = fb->height; -+ } else if (flags & DRM_MODE_FB_DIRTY_ANNOTATE_COPY) { -+ num_clips /= 2; -+ inc = 2; /* skip source rects */ -+ } -+ -+ qxl_draw_dirty_fb(qdev, qxl_fb, qobj, flags, color, -+ clips, num_clips, inc); -+ return 0; -+} -+ -+static const struct drm_framebuffer_funcs qxl_fb_funcs = { -+ .destroy = qxl_user_framebuffer_destroy, -+ .dirty = qxl_framebuffer_surface_dirty, -+/* TODO? -+ * .create_handle = qxl_user_framebuffer_create_handle, */ -+}; -+ -+int -+qxl_framebuffer_init(struct drm_device *dev, -+ struct qxl_framebuffer *qfb, -+ struct drm_mode_fb_cmd2 *mode_cmd, -+ struct drm_gem_object *obj) -+{ -+ int ret; -+ -+ qfb->obj = obj; -+ ret = drm_framebuffer_init(dev, &qfb->base, &qxl_fb_funcs); -+ if (ret) { -+ qfb->obj = NULL; -+ return ret; -+ } -+ drm_helper_mode_fill_fb_struct(&qfb->base, mode_cmd); -+ return 0; -+} -+ -+static void qxl_crtc_dpms(struct drm_crtc *crtc, int mode) -+{ -+} -+ -+static bool qxl_crtc_mode_fixup(struct drm_crtc *crtc, -+ const struct drm_display_mode *mode, -+ struct drm_display_mode *adjusted_mode) -+{ -+ struct drm_device *dev = crtc->dev; -+ struct qxl_device *qdev = dev->dev_private; -+ -+ qxl_io_log(qdev, "%s: (%d,%d) => (%d,%d)\n", -+ __func__, -+ mode->hdisplay, mode->vdisplay, -+ adjusted_mode->hdisplay, -+ adjusted_mode->vdisplay); -+ return true; -+} -+ -+void -+qxl_send_monitors_config(struct qxl_device *qdev) -+{ -+ int i; -+ -+ BUG_ON(!qdev->ram_header->monitors_config); -+ -+ if (qdev->monitors_config->count == 0) { -+ qxl_io_log(qdev, "%s: 0 monitors??\n", __func__); -+ return; -+ } -+ for (i = 0 ; i < qdev->monitors_config->count ; ++i) { -+ struct qxl_head *head = &qdev->monitors_config->heads[i]; -+ -+ if (head->y > 8192 || head->y < head->x || -+ head->width > 8192 || head->height > 8192) { -+ DRM_ERROR("head %d wrong: %dx%d+%d+%d\n", -+ i, head->width, head->height, -+ head->x, head->y); -+ return; -+ } -+ } -+ qxl_io_monitors_config(qdev); -+} -+ -+static void qxl_monitors_config_set_single(struct qxl_device *qdev, -+ unsigned x, unsigned y, -+ unsigned width, unsigned height) -+{ -+ DRM_DEBUG("%dx%d+%d+%d\n", width, height, x, y); -+ qdev->monitors_config->count = 1; -+ qdev->monitors_config->heads[0].x = x; -+ qdev->monitors_config->heads[0].y = y; -+ qdev->monitors_config->heads[0].width = width; -+ qdev->monitors_config->heads[0].height = height; -+} -+ -+static int qxl_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 qxl_device *qdev = dev->dev_private; -+ struct qxl_mode *m = (void *)mode->private; -+ struct qxl_framebuffer *qfb; -+ struct qxl_bo *bo, *old_bo = NULL; -+ uint32_t width, height, base_offset; -+ bool recreate_primary = false; -+ int ret; -+ -+ if (!crtc->fb) { -+ DRM_DEBUG_KMS("No FB bound\n"); -+ return 0; -+ } -+ -+ if (old_fb) { -+ qfb = to_qxl_framebuffer(old_fb); -+ old_bo = gem_to_qxl_bo(qfb->obj); -+ } -+ qfb = to_qxl_framebuffer(crtc->fb); -+ bo = gem_to_qxl_bo(qfb->obj); -+ if (!m) -+ /* and do we care? */ -+ DRM_DEBUG("%dx%d: not a native mode\n", x, y); -+ else -+ DRM_DEBUG("%dx%d: qxl id %d\n", -+ mode->hdisplay, mode->vdisplay, m->id); -+ DRM_DEBUG("+%d+%d (%d,%d) => (%d,%d)\n", -+ x, y, -+ mode->hdisplay, mode->vdisplay, -+ adjusted_mode->hdisplay, -+ adjusted_mode->vdisplay); -+ -+ recreate_primary = true; -+ -+ width = mode->hdisplay; -+ height = mode->vdisplay; -+ base_offset = 0; -+ -+ ret = qxl_bo_reserve(bo, false); -+ if (ret != 0) -+ return ret; -+ ret = qxl_bo_pin(bo, bo->type, NULL); -+ if (ret != 0) { -+ qxl_bo_unreserve(bo); -+ return -EINVAL; -+ } -+ qxl_bo_unreserve(bo); -+ if (recreate_primary) { -+ qxl_io_destroy_primary(qdev); -+ qxl_io_log(qdev, -+ "recreate primary: %dx%d (was %dx%d,%d,%d)\n", -+ width, height, bo->surf.width, -+ bo->surf.height, bo->surf.stride, bo->surf.format); -+ qxl_io_create_primary(qdev, width, height, base_offset, bo); -+ bo->is_primary = true; -+ } -+ -+ if (old_bo && old_bo != bo) { -+ old_bo->is_primary = false; -+ ret = qxl_bo_reserve(old_bo, false); -+ qxl_bo_unpin(old_bo); -+ qxl_bo_unreserve(old_bo); -+ } -+ -+ if (qdev->monitors_config->count == 0) { -+ qxl_monitors_config_set_single(qdev, x, y, -+ mode->hdisplay, -+ mode->vdisplay); -+ } -+ qdev->mode_set = true; -+ return 0; -+} -+ -+static void qxl_crtc_prepare(struct drm_crtc *crtc) -+{ -+ DRM_DEBUG("current: %dx%d+%d+%d (%d).\n", -+ crtc->mode.hdisplay, crtc->mode.vdisplay, -+ crtc->x, crtc->y, crtc->enabled); -+} -+ -+static void qxl_crtc_commit(struct drm_crtc *crtc) -+{ -+ DRM_DEBUG("\n"); -+} -+ -+void qxl_crtc_load_lut(struct drm_crtc *crtc) -+{ -+ DRM_DEBUG("\n"); -+} -+ -+static const struct drm_crtc_helper_funcs qxl_crtc_helper_funcs = { -+ .dpms = qxl_crtc_dpms, -+ .mode_fixup = qxl_crtc_mode_fixup, -+ .mode_set = qxl_crtc_mode_set, -+ .prepare = qxl_crtc_prepare, -+ .commit = qxl_crtc_commit, -+ .load_lut = qxl_crtc_load_lut, -+}; -+ -+int qdev_crtc_init(struct drm_device *dev, int num_crtc) -+{ -+ struct qxl_crtc *qxl_crtc; -+ -+ qxl_crtc = kzalloc(sizeof(struct qxl_crtc), GFP_KERNEL); -+ if (!qxl_crtc) -+ return -ENOMEM; -+ -+ drm_crtc_init(dev, &qxl_crtc->base, &qxl_crtc_funcs); -+ -+ drm_mode_crtc_set_gamma_size(&qxl_crtc->base, 256); -+ drm_crtc_helper_add(&qxl_crtc->base, &qxl_crtc_helper_funcs); -+ return 0; -+} -+ -+static void qxl_enc_dpms(struct drm_encoder *encoder, int mode) -+{ -+ DRM_DEBUG("\n"); -+} -+ -+static bool qxl_enc_mode_fixup(struct drm_encoder *encoder, -+ const struct drm_display_mode *mode, -+ struct drm_display_mode *adjusted_mode) -+{ -+ DRM_DEBUG("\n"); -+ return true; -+} -+ -+static void qxl_enc_prepare(struct drm_encoder *encoder) -+{ -+ DRM_DEBUG("\n"); -+} -+ -+static void qxl_write_monitors_config_for_encoder(struct qxl_device *qdev, -+ struct drm_encoder *encoder) -+{ -+ int i; -+ struct qxl_head *head; -+ struct drm_display_mode *mode; -+ -+ BUG_ON(!encoder); -+ /* TODO: ugly, do better */ -+ for (i = 0 ; (encoder->possible_crtcs != (1 << i)) && i < 32; ++i) -+ ; -+ if (encoder->possible_crtcs != (1 << i)) { -+ DRM_ERROR("encoder has wrong possible_crtcs: %x\n", -+ encoder->possible_crtcs); -+ return; -+ } -+ if (!qdev->monitors_config || -+ qdev->monitors_config->max_allowed <= i) { -+ DRM_ERROR( -+ "head number too large or missing monitors config: %p, %d", -+ qdev->monitors_config, -+ qdev->monitors_config ? -+ qdev->monitors_config->max_allowed : -1); -+ return; -+ } -+ if (!encoder->crtc) { -+ DRM_ERROR("missing crtc on encoder %p\n", encoder); -+ return; -+ } -+ if (i != 0) -+ DRM_DEBUG("missing for multiple monitors: no head holes\n"); -+ head = &qdev->monitors_config->heads[i]; -+ head->id = i; -+ head->surface_id = 0; -+ if (encoder->crtc->enabled) { -+ mode = &encoder->crtc->mode; -+ head->width = mode->hdisplay; -+ head->height = mode->vdisplay; -+ head->x = encoder->crtc->x; -+ head->y = encoder->crtc->y; -+ if (qdev->monitors_config->count < i + 1) -+ qdev->monitors_config->count = i + 1; -+ } else { -+ head->width = 0; -+ head->height = 0; -+ head->x = 0; -+ head->y = 0; -+ } -+ DRM_DEBUG("setting head %d to +%d+%d %dx%d\n", -+ i, head->x, head->y, head->width, head->height); -+ head->flags = 0; -+ /* TODO - somewhere else to call this for multiple monitors -+ * (config_commit?) */ -+ qxl_send_monitors_config(qdev); -+} -+ -+static void qxl_enc_commit(struct drm_encoder *encoder) -+{ -+ struct qxl_device *qdev = encoder->dev->dev_private; -+ -+ qxl_write_monitors_config_for_encoder(qdev, encoder); -+ DRM_DEBUG("\n"); -+} -+ -+static void qxl_enc_mode_set(struct drm_encoder *encoder, -+ struct drm_display_mode *mode, -+ struct drm_display_mode *adjusted_mode) -+{ -+ DRM_DEBUG("\n"); -+} -+ -+static int qxl_conn_get_modes(struct drm_connector *connector) -+{ -+ int ret = 0; -+ struct qxl_device *qdev = connector->dev->dev_private; -+ -+ DRM_DEBUG_KMS("monitors_config=%p\n", qdev->monitors_config); -+ /* TODO: what should we do here? only show the configured modes for the -+ * device, or allow the full list, or both? */ -+ if (qdev->monitors_config && qdev->monitors_config->count) { -+ ret = qxl_add_monitors_config_modes(connector); -+ if (ret < 0) -+ return ret; -+ } -+ ret += qxl_add_common_modes(connector); -+ return ret; -+} -+ -+static int qxl_conn_mode_valid(struct drm_connector *connector, -+ struct drm_display_mode *mode) -+{ -+ /* TODO: is this called for user defined modes? (xrandr --add-mode) -+ * TODO: check that the mode fits in the framebuffer */ -+ DRM_DEBUG("%s: %dx%d status=%d\n", mode->name, mode->hdisplay, -+ mode->vdisplay, mode->status); -+ return MODE_OK; -+} -+ -+struct drm_encoder *qxl_best_encoder(struct drm_connector *connector) -+{ -+ struct qxl_output *qxl_output = -+ drm_connector_to_qxl_output(connector); -+ -+ DRM_DEBUG("\n"); -+ return &qxl_output->enc; -+} -+ -+ -+static const struct drm_encoder_helper_funcs qxl_enc_helper_funcs = { -+ .dpms = qxl_enc_dpms, -+ .mode_fixup = qxl_enc_mode_fixup, -+ .prepare = qxl_enc_prepare, -+ .mode_set = qxl_enc_mode_set, -+ .commit = qxl_enc_commit, -+}; -+ -+static const struct drm_connector_helper_funcs qxl_connector_helper_funcs = { -+ .get_modes = qxl_conn_get_modes, -+ .mode_valid = qxl_conn_mode_valid, -+ .best_encoder = qxl_best_encoder, -+}; -+ -+static void qxl_conn_save(struct drm_connector *connector) -+{ -+ DRM_DEBUG("\n"); -+} -+ -+static void qxl_conn_restore(struct drm_connector *connector) -+{ -+ DRM_DEBUG("\n"); -+} -+ -+static enum drm_connector_status qxl_conn_detect( -+ struct drm_connector *connector, -+ bool force) -+{ -+ struct qxl_output *output = -+ drm_connector_to_qxl_output(connector); -+ struct drm_device *ddev = connector->dev; -+ struct qxl_device *qdev = ddev->dev_private; -+ int connected; -+ -+ /* The first monitor is always connected */ -+ connected = (output->index == 0) || -+ (qdev->monitors_config && -+ qdev->monitors_config->count > output->index); -+ -+ DRM_DEBUG("\n"); -+ return connected ? connector_status_connected -+ : connector_status_disconnected; -+} -+ -+static int qxl_conn_set_property(struct drm_connector *connector, -+ struct drm_property *property, -+ uint64_t value) -+{ -+ DRM_DEBUG("\n"); -+ return 0; -+} -+ -+static void qxl_conn_destroy(struct drm_connector *connector) -+{ -+ struct qxl_output *qxl_output = -+ drm_connector_to_qxl_output(connector); -+ -+ drm_sysfs_connector_remove(connector); -+ drm_connector_cleanup(connector); -+ kfree(qxl_output); -+} -+ -+static const struct drm_connector_funcs qxl_connector_funcs = { -+ .dpms = drm_helper_connector_dpms, -+ .save = qxl_conn_save, -+ .restore = qxl_conn_restore, -+ .detect = qxl_conn_detect, -+ .fill_modes = drm_helper_probe_single_connector_modes, -+ .set_property = qxl_conn_set_property, -+ .destroy = qxl_conn_destroy, -+}; -+ -+static void qxl_enc_destroy(struct drm_encoder *encoder) -+{ -+ drm_encoder_cleanup(encoder); -+} -+ -+static const struct drm_encoder_funcs qxl_enc_funcs = { -+ .destroy = qxl_enc_destroy, -+}; -+ -+int qdev_output_init(struct drm_device *dev, int num_output) -+{ -+ struct qxl_output *qxl_output; -+ struct drm_connector *connector; -+ struct drm_encoder *encoder; -+ -+ qxl_output = kzalloc(sizeof(struct qxl_output), GFP_KERNEL); -+ if (!qxl_output) -+ return -ENOMEM; -+ -+ qxl_output->index = num_output; -+ -+ connector = &qxl_output->base; -+ encoder = &qxl_output->enc; -+ drm_connector_init(dev, &qxl_output->base, -+ &qxl_connector_funcs, DRM_MODE_CONNECTOR_VIRTUAL); -+ -+ drm_encoder_init(dev, &qxl_output->enc, &qxl_enc_funcs, -+ DRM_MODE_ENCODER_VIRTUAL); -+ -+ encoder->possible_crtcs = 1 << num_output; -+ drm_mode_connector_attach_encoder(&qxl_output->base, -+ &qxl_output->enc); -+ drm_encoder_helper_add(encoder, &qxl_enc_helper_funcs); -+ drm_connector_helper_add(connector, &qxl_connector_helper_funcs); -+ -+ drm_sysfs_connector_add(connector); -+ return 0; -+} -+ -+static struct drm_framebuffer * -+qxl_user_framebuffer_create(struct drm_device *dev, -+ struct drm_file *file_priv, -+ struct drm_mode_fb_cmd2 *mode_cmd) -+{ -+ struct drm_gem_object *obj; -+ struct qxl_framebuffer *qxl_fb; -+ struct qxl_device *qdev = dev->dev_private; -+ int ret; -+ -+ obj = drm_gem_object_lookup(dev, file_priv, mode_cmd->handles[0]); -+ -+ qxl_fb = kzalloc(sizeof(*qxl_fb), GFP_KERNEL); -+ if (qxl_fb == NULL) -+ return NULL; -+ -+ ret = qxl_framebuffer_init(dev, qxl_fb, mode_cmd, obj); -+ if (ret) { -+ kfree(qxl_fb); -+ drm_gem_object_unreference_unlocked(obj); -+ return NULL; -+ } -+ -+ if (qdev->active_user_framebuffer) { -+ DRM_INFO("%s: active_user_framebuffer %p -> %p\n", -+ __func__, -+ qdev->active_user_framebuffer, qxl_fb); -+ } -+ qdev->active_user_framebuffer = qxl_fb; -+ -+ return &qxl_fb->base; -+} -+ -+static const struct drm_mode_config_funcs qxl_mode_funcs = { -+ .fb_create = qxl_user_framebuffer_create, -+}; -+ -+int qxl_modeset_init(struct qxl_device *qdev) -+{ -+ int i; -+ int ret; -+ struct drm_gem_object *gobj; -+ int max_allowed = QXL_NUM_OUTPUTS; -+ int monitors_config_size = sizeof(struct qxl_monitors_config) + -+ max_allowed * sizeof(struct qxl_head); -+ -+ drm_mode_config_init(qdev->ddev); -+ ret = qxl_gem_object_create(qdev, monitors_config_size, 0, -+ QXL_GEM_DOMAIN_VRAM, -+ false, false, NULL, &gobj); -+ if (ret) { -+ DRM_ERROR("%s: failed to create gem ret=%d\n", __func__, ret); -+ return -ENOMEM; -+ } -+ qdev->monitors_config_bo = gem_to_qxl_bo(gobj); -+ qxl_bo_kmap(qdev->monitors_config_bo, NULL); -+ qdev->monitors_config = qdev->monitors_config_bo->kptr; -+ qdev->ram_header->monitors_config = -+ qxl_bo_physical_address(qdev, qdev->monitors_config_bo, 0); -+ -+ memset(qdev->monitors_config, 0, monitors_config_size); -+ qdev->monitors_config->max_allowed = max_allowed; -+ -+ qdev->ddev->mode_config.funcs = (void *)&qxl_mode_funcs; -+ -+ /* modes will be validated against the framebuffer size */ -+ qdev->ddev->mode_config.min_width = 320; -+ qdev->ddev->mode_config.min_height = 200; -+ qdev->ddev->mode_config.max_width = 8192; -+ qdev->ddev->mode_config.max_height = 8192; -+ -+ qdev->ddev->mode_config.fb_base = qdev->vram_base; -+ for (i = 0 ; i < QXL_NUM_OUTPUTS; ++i) { -+ qdev_crtc_init(qdev->ddev, i); -+ qdev_output_init(qdev->ddev, i); -+ } -+ -+ qdev->mode_info.mode_config_initialized = true; -+ -+ /* primary surface must be created by this point, to allow -+ * issuing command queue commands and having them read by -+ * spice server. */ -+ qxl_fbdev_init(qdev); -+ return 0; -+} -+ -+void qxl_modeset_fini(struct qxl_device *qdev) -+{ -+ qxl_fbdev_fini(qdev); -+ if (qdev->mode_info.mode_config_initialized) { -+ drm_mode_config_cleanup(qdev->ddev); -+ qdev->mode_info.mode_config_initialized = false; -+ } -+} -diff --git a/drivers/gpu/drm/qxl/qxl_draw.c b/drivers/gpu/drm/qxl/qxl_draw.c -new file mode 100644 -index 0000000..3c8c3db ---- /dev/null -+++ b/drivers/gpu/drm/qxl/qxl_draw.c -@@ -0,0 +1,390 @@ -+/* -+ * Copyright 2011 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 -+ * on 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 above copyright notice and this permission notice (including the next -+ * paragraph) shall be included in all copies or substantial portions of the -+ * Software. -+ * -+ * 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 AUTHORS 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. -+ */ -+ -+#include "qxl_drv.h" -+#include "qxl_object.h" -+ -+/* returns a pointer to the already allocated qxl_rect array inside -+ * the qxl_clip_rects. This is *not* the same as the memory allocated -+ * on the device, it is offset to qxl_clip_rects.chunk.data */ -+static struct qxl_rect *drawable_set_clipping(struct qxl_device *qdev, -+ struct qxl_drawable *drawable, -+ unsigned num_clips, -+ struct qxl_bo **clips_bo, -+ struct qxl_release *release) -+{ -+ struct qxl_clip_rects *dev_clips; -+ int ret; -+ int size = sizeof(*dev_clips) + sizeof(struct qxl_rect) * num_clips; -+ ret = qxl_alloc_bo_reserved(qdev, size, clips_bo); -+ if (ret) -+ return NULL; -+ -+ ret = qxl_bo_kmap(*clips_bo, (void **)&dev_clips); -+ if (ret) { -+ qxl_bo_unref(clips_bo); -+ return NULL; -+ } -+ dev_clips->num_rects = num_clips; -+ dev_clips->chunk.next_chunk = 0; -+ dev_clips->chunk.prev_chunk = 0; -+ dev_clips->chunk.data_size = sizeof(struct qxl_rect) * num_clips; -+ return (struct qxl_rect *)dev_clips->chunk.data; -+} -+ -+static int -+make_drawable(struct qxl_device *qdev, int surface, uint8_t type, -+ const struct qxl_rect *rect, -+ struct qxl_release **release) -+{ -+ struct qxl_drawable *drawable; -+ int i, ret; -+ -+ ret = qxl_alloc_release_reserved(qdev, sizeof(*drawable), -+ QXL_RELEASE_DRAWABLE, release, -+ NULL); -+ if (ret) -+ return ret; -+ -+ drawable = (struct qxl_drawable *)qxl_release_map(qdev, *release); -+ drawable->type = type; -+ -+ drawable->surface_id = surface; /* Only primary for now */ -+ drawable->effect = QXL_EFFECT_OPAQUE; -+ drawable->self_bitmap = 0; -+ drawable->self_bitmap_area.top = 0; -+ drawable->self_bitmap_area.left = 0; -+ drawable->self_bitmap_area.bottom = 0; -+ drawable->self_bitmap_area.right = 0; -+ /* FIXME: add clipping */ -+ drawable->clip.type = SPICE_CLIP_TYPE_NONE; -+ -+ /* -+ * surfaces_dest[i] should apparently be filled out with the -+ * surfaces that we depend on, and surface_rects should be -+ * filled with the rectangles of those surfaces that we -+ * are going to use. -+ */ -+ for (i = 0; i < 3; ++i) -+ drawable->surfaces_dest[i] = -1; -+ -+ if (rect) -+ drawable->bbox = *rect; -+ -+ drawable->mm_time = qdev->rom->mm_clock; -+ qxl_release_unmap(qdev, *release, &drawable->release_info); -+ return 0; -+} -+ -+static int qxl_palette_create_1bit(struct qxl_bo **palette_bo, -+ const struct qxl_fb_image *qxl_fb_image) -+{ -+ struct qxl_device *qdev = qxl_fb_image->qdev; -+ const struct fb_image *fb_image = &qxl_fb_image->fb_image; -+ uint32_t visual = qxl_fb_image->visual; -+ const uint32_t *pseudo_palette = qxl_fb_image->pseudo_palette; -+ struct qxl_palette *pal; -+ int ret; -+ uint32_t fgcolor, bgcolor; -+ static uint64_t unique; /* we make no attempt to actually set this -+ * correctly globaly, since that would require -+ * tracking all of our palettes. */ -+ -+ ret = qxl_alloc_bo_reserved(qdev, -+ sizeof(struct qxl_palette) + sizeof(uint32_t) * 2, -+ palette_bo); -+ -+ ret = qxl_bo_kmap(*palette_bo, (void **)&pal); -+ pal->num_ents = 2; -+ pal->unique = unique++; -+ if (visual == FB_VISUAL_TRUECOLOR || visual == FB_VISUAL_DIRECTCOLOR) { -+ /* NB: this is the only used branch currently. */ -+ fgcolor = pseudo_palette[fb_image->fg_color]; -+ bgcolor = pseudo_palette[fb_image->bg_color]; -+ } else { -+ fgcolor = fb_image->fg_color; -+ bgcolor = fb_image->bg_color; -+ } -+ pal->ents[0] = bgcolor; -+ pal->ents[1] = fgcolor; -+ qxl_bo_kunmap(*palette_bo); -+ return 0; -+} -+ -+void qxl_draw_opaque_fb(const struct qxl_fb_image *qxl_fb_image, -+ int stride /* filled in if 0 */) -+{ -+ struct qxl_device *qdev = qxl_fb_image->qdev; -+ struct qxl_drawable *drawable; -+ struct qxl_rect rect; -+ const struct fb_image *fb_image = &qxl_fb_image->fb_image; -+ int x = fb_image->dx; -+ int y = fb_image->dy; -+ int width = fb_image->width; -+ int height = fb_image->height; -+ const char *src = fb_image->data; -+ int depth = fb_image->depth; -+ struct qxl_release *release; -+ struct qxl_bo *image_bo; -+ struct qxl_image *image; -+ int ret; -+ -+ if (stride == 0) -+ stride = depth * width / 8; -+ -+ rect.left = x; -+ rect.right = x + width; -+ rect.top = y; -+ rect.bottom = y + height; -+ -+ ret = make_drawable(qdev, 0, QXL_DRAW_COPY, &rect, &release); -+ if (ret) -+ return; -+ -+ ret = qxl_image_create(qdev, release, &image_bo, -+ (const uint8_t *)src, 0, 0, -+ width, height, depth, stride); -+ if (ret) { -+ qxl_release_unreserve(qdev, release); -+ qxl_release_free(qdev, release); -+ return; -+ } -+ -+ if (depth == 1) { -+ struct qxl_bo *palette_bo; -+ void *ptr; -+ ret = qxl_palette_create_1bit(&palette_bo, qxl_fb_image); -+ qxl_release_add_res(qdev, release, palette_bo); -+ -+ ptr = qxl_bo_kmap_atomic_page(qdev, image_bo, 0); -+ image = ptr; -+ image->u.bitmap.palette = -+ qxl_bo_physical_address(qdev, palette_bo, 0); -+ qxl_bo_kunmap_atomic_page(qdev, image_bo, ptr); -+ qxl_bo_unreserve(palette_bo); -+ qxl_bo_unref(&palette_bo); -+ } -+ -+ drawable = (struct qxl_drawable *)qxl_release_map(qdev, release); -+ -+ drawable->u.copy.src_area.top = 0; -+ drawable->u.copy.src_area.bottom = height; -+ drawable->u.copy.src_area.left = 0; -+ drawable->u.copy.src_area.right = width; -+ -+ drawable->u.copy.rop_descriptor = SPICE_ROPD_OP_PUT; -+ drawable->u.copy.scale_mode = 0; -+ drawable->u.copy.mask.flags = 0; -+ drawable->u.copy.mask.pos.x = 0; -+ drawable->u.copy.mask.pos.y = 0; -+ drawable->u.copy.mask.bitmap = 0; -+ -+ drawable->u.copy.src_bitmap = -+ qxl_bo_physical_address(qdev, image_bo, 0); -+ qxl_release_unmap(qdev, release, &drawable->release_info); -+ -+ qxl_release_add_res(qdev, release, image_bo); -+ qxl_bo_unreserve(image_bo); -+ qxl_bo_unref(&image_bo); -+ -+ qxl_fence_releaseable(qdev, release); -+ qxl_push_command_ring_release(qdev, release, QXL_CMD_DRAW, false); -+ qxl_release_unreserve(qdev, release); -+} -+ -+/* push a draw command using the given clipping rectangles as -+ * the sources from the shadow framebuffer. -+ * -+ * Right now implementing with a single draw and a clip list. Clip -+ * lists are known to be a problem performance wise, this can be solved -+ * by treating them differently in the server. -+ */ -+void qxl_draw_dirty_fb(struct qxl_device *qdev, -+ struct qxl_framebuffer *qxl_fb, -+ struct qxl_bo *bo, -+ unsigned flags, unsigned color, -+ struct drm_clip_rect *clips, -+ unsigned num_clips, int inc) -+{ -+ /* -+ * TODO: if flags & DRM_MODE_FB_DIRTY_ANNOTATE_FILL then we should -+ * send a fill command instead, much cheaper. -+ * -+ * See include/drm/drm_mode.h -+ */ -+ struct drm_clip_rect *clips_ptr; -+ int i; -+ int left, right, top, bottom; -+ int width, height; -+ struct qxl_drawable *drawable; -+ struct qxl_rect drawable_rect; -+ struct qxl_rect *rects; -+ int stride = qxl_fb->base.pitches[0]; -+ /* depth is not actually interesting, we don't mask with it */ -+ int depth = qxl_fb->base.bits_per_pixel; -+ uint8_t *surface_base; -+ struct qxl_release *release; -+ struct qxl_bo *image_bo; -+ struct qxl_bo *clips_bo; -+ int ret; -+ -+ left = clips->x1; -+ right = clips->x2; -+ top = clips->y1; -+ bottom = clips->y2; -+ -+ /* skip the first clip rect */ -+ for (i = 1, clips_ptr = clips + inc; -+ i < num_clips; i++, clips_ptr += inc) { -+ left = min_t(int, left, (int)clips_ptr->x1); -+ right = max_t(int, right, (int)clips_ptr->x2); -+ top = min_t(int, top, (int)clips_ptr->y1); -+ bottom = max_t(int, bottom, (int)clips_ptr->y2); -+ } -+ -+ width = right - left; -+ height = bottom - top; -+ drawable_rect.left = left; -+ drawable_rect.right = right; -+ drawable_rect.top = top; -+ drawable_rect.bottom = bottom; -+ ret = make_drawable(qdev, 0, QXL_DRAW_COPY, &drawable_rect, -+ &release); -+ if (ret) -+ return; -+ -+ ret = qxl_bo_kmap(bo, (void **)&surface_base); -+ if (ret) -+ goto out_unref; -+ -+ ret = qxl_image_create(qdev, release, &image_bo, surface_base, -+ left, top, width, height, depth, stride); -+ qxl_bo_kunmap(bo); -+ if (ret) -+ goto out_unref; -+ -+ rects = drawable_set_clipping(qdev, drawable, num_clips, &clips_bo, release); -+ if (!rects) { -+ qxl_bo_unref(&image_bo); -+ goto out_unref; -+ } -+ drawable = (struct qxl_drawable *)qxl_release_map(qdev, release); -+ -+ drawable->clip.type = SPICE_CLIP_TYPE_RECTS; -+ drawable->clip.data = qxl_bo_physical_address(qdev, -+ clips_bo, 0); -+ qxl_release_add_res(qdev, release, clips_bo); -+ -+ drawable->u.copy.src_area.top = 0; -+ drawable->u.copy.src_area.bottom = height; -+ drawable->u.copy.src_area.left = 0; -+ drawable->u.copy.src_area.right = width; -+ -+ drawable->u.copy.rop_descriptor = SPICE_ROPD_OP_PUT; -+ drawable->u.copy.scale_mode = 0; -+ drawable->u.copy.mask.flags = 0; -+ drawable->u.copy.mask.pos.x = 0; -+ drawable->u.copy.mask.pos.y = 0; -+ drawable->u.copy.mask.bitmap = 0; -+ -+ drawable->u.copy.src_bitmap = qxl_bo_physical_address(qdev, image_bo, 0); -+ qxl_release_unmap(qdev, release, &drawable->release_info); -+ qxl_release_add_res(qdev, release, image_bo); -+ qxl_bo_unreserve(image_bo); -+ qxl_bo_unref(&image_bo); -+ clips_ptr = clips; -+ for (i = 0; i < num_clips; i++, clips_ptr += inc) { -+ rects[i].left = clips_ptr->x1; -+ rects[i].right = clips_ptr->x2; -+ rects[i].top = clips_ptr->y1; -+ rects[i].bottom = clips_ptr->y2; -+ } -+ qxl_bo_kunmap(clips_bo); -+ qxl_bo_unreserve(clips_bo); -+ qxl_bo_unref(&clips_bo); -+ -+ qxl_fence_releaseable(qdev, release); -+ qxl_push_command_ring_release(qdev, release, QXL_CMD_DRAW, false); -+ qxl_release_unreserve(qdev, release); -+ return; -+ -+out_unref: -+ qxl_release_unreserve(qdev, release); -+ qxl_release_free(qdev, release); -+} -+ -+void qxl_draw_copyarea(struct qxl_device *qdev, -+ u32 width, u32 height, -+ u32 sx, u32 sy, -+ u32 dx, u32 dy) -+{ -+ struct qxl_drawable *drawable; -+ struct qxl_rect rect; -+ struct qxl_release *release; -+ int ret; -+ -+ rect.left = dx; -+ rect.top = dy; -+ rect.right = dx + width; -+ rect.bottom = dy + height; -+ ret = make_drawable(qdev, 0, QXL_COPY_BITS, &rect, &release); -+ if (ret) -+ return; -+ -+ drawable = (struct qxl_drawable *)qxl_release_map(qdev, release); -+ drawable->u.copy_bits.src_pos.x = sx; -+ drawable->u.copy_bits.src_pos.y = sy; -+ -+ qxl_release_unmap(qdev, release, &drawable->release_info); -+ qxl_fence_releaseable(qdev, release); -+ qxl_push_command_ring_release(qdev, release, QXL_CMD_DRAW, false); -+ qxl_release_unreserve(qdev, release); -+} -+ -+void qxl_draw_fill(struct qxl_draw_fill *qxl_draw_fill_rec) -+{ -+ struct qxl_device *qdev = qxl_draw_fill_rec->qdev; -+ struct qxl_rect rect = qxl_draw_fill_rec->rect; -+ uint32_t color = qxl_draw_fill_rec->color; -+ uint16_t rop = qxl_draw_fill_rec->rop; -+ struct qxl_drawable *drawable; -+ struct qxl_release *release; -+ int ret; -+ -+ ret = make_drawable(qdev, 0, QXL_DRAW_FILL, &rect, &release); -+ if (ret) -+ return; -+ -+ drawable = (struct qxl_drawable *)qxl_release_map(qdev, release); -+ drawable->u.fill.brush.type = SPICE_BRUSH_TYPE_SOLID; -+ drawable->u.fill.brush.u.color = color; -+ drawable->u.fill.rop_descriptor = rop; -+ drawable->u.fill.mask.flags = 0; -+ drawable->u.fill.mask.pos.x = 0; -+ drawable->u.fill.mask.pos.y = 0; -+ drawable->u.fill.mask.bitmap = 0; -+ -+ qxl_release_unmap(qdev, release, &drawable->release_info); -+ qxl_fence_releaseable(qdev, release); -+ qxl_push_command_ring_release(qdev, release, QXL_CMD_DRAW, false); -+ qxl_release_unreserve(qdev, release); -+} -diff --git a/drivers/gpu/drm/qxl/qxl_drv.c b/drivers/gpu/drm/qxl/qxl_drv.c -new file mode 100644 -index 0000000..d337da0 ---- /dev/null -+++ b/drivers/gpu/drm/qxl/qxl_drv.c -@@ -0,0 +1,145 @@ -+/* vim: set ts=8 sw=8 tw=78 ai noexpandtab */ -+/* qxl_drv.c -- QXL driver -*- linux-c -*- -+ * -+ * Copyright 2011 Red Hat, Inc. -+ * All Rights Reserved. -+ * -+ * 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, sublicense, -+ * 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 above copyright notice and this permission notice (including the next -+ * paragraph) shall be included in all copies or substantial portions of the -+ * Software. -+ * -+ * 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 NONINFRINGEMENT. IN NO EVENT SHALL -+ * VA LINUX SYSTEMS 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. -+ * -+ * Authors: -+ * Dave Airlie -+ * Alon Levy -+ */ -+ -+#include -+#include -+ -+#include "drmP.h" -+#include "drm/drm.h" -+ -+#include "qxl_drv.h" -+ -+extern int qxl_max_ioctls; -+static DEFINE_PCI_DEVICE_TABLE(pciidlist) = { -+ { 0x1b36, 0x100, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, -+ 0xffff00, 0 }, -+ { 0x1b36, 0x100, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_OTHER << 8, -+ 0xffff00, 0 }, -+ { 0, 0, 0 }, -+}; -+MODULE_DEVICE_TABLE(pci, pciidlist); -+ -+int qxl_modeset = -1; -+ -+MODULE_PARM_DESC(modeset, "Disable/Enable modesetting"); -+module_param_named(modeset, qxl_modeset, int, 0400); -+ -+static struct drm_driver qxl_driver; -+static struct pci_driver qxl_pci_driver; -+ -+static int -+qxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) -+{ -+ if (pdev->revision < 4) { -+ DRM_ERROR("qxl too old, doesn't support client_monitors_config," -+ " use xf86-video-qxl in user mode"); -+ return -EINVAL; /* TODO: ENODEV ? */ -+ } -+ return drm_get_pci_dev(pdev, ent, &qxl_driver); -+} -+ -+static void -+qxl_pci_remove(struct pci_dev *pdev) -+{ -+ struct drm_device *dev = pci_get_drvdata(pdev); -+ -+ 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 = { -+ .owner = THIS_MODULE, -+ .open = drm_open, -+ .release = drm_release, -+ .unlocked_ioctl = drm_ioctl, -+ .poll = drm_poll, -+ .fasync = drm_fasync, -+ .mmap = qxl_mmap, -+}; -+ -+static struct drm_driver qxl_driver = { -+ .driver_features = DRIVER_GEM | DRIVER_MODESET | -+ DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED, -+ .dev_priv_size = 0, -+ .load = qxl_driver_load, -+ .unload = qxl_driver_unload, -+ -+ .dumb_create = qxl_mode_dumb_create, -+ .dumb_map_offset = qxl_mode_dumb_mmap, -+ .dumb_destroy = qxl_mode_dumb_destroy, -+#if defined(CONFIG_DEBUG_FS) -+ .debugfs_init = qxl_debugfs_init, -+ .debugfs_cleanup = qxl_debugfs_takedown, -+#endif -+ .gem_init_object = qxl_gem_object_init, -+ .gem_free_object = qxl_gem_object_free, -+ .gem_open_object = qxl_gem_object_open, -+ .gem_close_object = qxl_gem_object_close, -+ .fops = &qxl_fops, -+ .ioctls = qxl_ioctls, -+ .irq_handler = qxl_irq_handler, -+ .name = DRIVER_NAME, -+ .desc = DRIVER_DESC, -+ .date = DRIVER_DATE, -+ .major = 0, -+ .minor = 1, -+ .patchlevel = 0, -+}; -+ -+static int __init qxl_init(void) -+{ -+#ifdef CONFIG_VGA_CONSOLE -+ if (vgacon_text_force() && qxl_modeset == -1) -+ return -EINVAL; -+#endif -+ -+ if (qxl_modeset == 0) -+ return -EINVAL; -+ qxl_driver.num_ioctls = qxl_max_ioctls; -+ return drm_pci_init(&qxl_driver, &qxl_pci_driver); -+} -+ -+static void __exit qxl_exit(void) -+{ -+ drm_pci_exit(&qxl_driver, &qxl_pci_driver); -+} -+ -+module_init(qxl_init); -+module_exit(qxl_exit); -+ -+MODULE_AUTHOR(DRIVER_AUTHOR); -+MODULE_DESCRIPTION(DRIVER_DESC); -+MODULE_LICENSE("GPL and additional rights"); -diff --git a/drivers/gpu/drm/qxl/qxl_drv.h b/drivers/gpu/drm/qxl/qxl_drv.h -new file mode 100644 -index 0000000..52b582c ---- /dev/null -+++ b/drivers/gpu/drm/qxl/qxl_drv.h -@@ -0,0 +1,566 @@ -+/* -+ * Copyright 2013 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, sublicense, -+ * 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 above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * 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 NONINFRINGEMENT. IN NO EVENT SHALL -+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. -+ * -+ * Authors: Dave Airlie -+ * Alon Levy -+ */ -+ -+ -+#ifndef QXL_DRV_H -+#define QXL_DRV_H -+ -+/* -+ * Definitions taken from spice-protocol, plus kernel driver specific bits. -+ */ -+ -+#include -+#include -+#include -+ -+#include "drmP.h" -+#include "drm_crtc.h" -+#include -+#include -+#include -+#include -+ -+#include -+#include "qxl_dev.h" -+ -+#define DRIVER_AUTHOR "Dave Airlie" -+ -+#define DRIVER_NAME "qxl" -+#define DRIVER_DESC "RH QXL" -+#define DRIVER_DATE "20120117" -+ -+#define DRIVER_MAJOR 0 -+#define DRIVER_MINOR 1 -+#define DRIVER_PATCHLEVEL 0 -+ -+#define QXL_NUM_OUTPUTS 1 -+ -+#define QXL_DEBUGFS_MAX_COMPONENTS 32 -+ -+extern int qxl_log_level; -+ -+enum { -+ QXL_INFO_LEVEL = 1, -+ QXL_DEBUG_LEVEL = 2, -+}; -+ -+#define QXL_INFO(qdev, fmt, ...) do { \ -+ if (qxl_log_level >= QXL_INFO_LEVEL) { \ -+ qxl_io_log(qdev, fmt, __VA_ARGS__); \ -+ } \ -+ } while (0) -+#define QXL_DEBUG(qdev, fmt, ...) do { \ -+ if (qxl_log_level >= QXL_DEBUG_LEVEL) { \ -+ qxl_io_log(qdev, fmt, __VA_ARGS__); \ -+ } \ -+ } while (0) -+#define QXL_INFO_ONCE(qdev, fmt, ...) do { \ -+ static int done; \ -+ if (!done) { \ -+ done = 1; \ -+ QXL_INFO(qdev, fmt, __VA_ARGS__); \ -+ } \ -+ } while (0) -+ -+#define DRM_FILE_OFFSET 0x100000000ULL -+#define DRM_FILE_PAGE_OFFSET (DRM_FILE_OFFSET >> PAGE_SHIFT) -+ -+#define QXL_INTERRUPT_MASK (\ -+ QXL_INTERRUPT_DISPLAY |\ -+ QXL_INTERRUPT_CURSOR |\ -+ QXL_INTERRUPT_IO_CMD |\ -+ QXL_INTERRUPT_CLIENT_MONITORS_CONFIG) -+ -+struct qxl_fence { -+ struct qxl_device *qdev; -+ uint32_t num_active_releases; -+ uint32_t *release_ids; -+ struct radix_tree_root tree; -+}; -+ -+struct qxl_bo { -+ /* Protected by gem.mutex */ -+ struct list_head list; -+ /* Protected by tbo.reserved */ -+ u32 placements[3]; -+ struct ttm_placement placement; -+ struct ttm_buffer_object tbo; -+ struct ttm_bo_kmap_obj kmap; -+ unsigned pin_count; -+ void *kptr; -+ int type; -+ /* Constant after initialization */ -+ struct drm_gem_object gem_base; -+ bool is_primary; /* is this now a primary surface */ -+ bool hw_surf_alloc; -+ struct qxl_surface surf; -+ uint32_t surface_id; -+ struct qxl_fence fence; /* per bo fence - list of releases */ -+ struct qxl_release *surf_create; -+ atomic_t reserve_count; -+}; -+#define gem_to_qxl_bo(gobj) container_of((gobj), struct qxl_bo, gem_base) -+ -+struct qxl_gem { -+ struct mutex mutex; -+ struct list_head objects; -+}; -+ -+struct qxl_bo_list { -+ struct list_head lhead; -+ struct qxl_bo *bo; -+}; -+ -+struct qxl_reloc_list { -+ struct list_head bos; -+}; -+ -+struct qxl_crtc { -+ struct drm_crtc base; -+ int cur_x; -+ int cur_y; -+}; -+ -+struct qxl_output { -+ int index; -+ struct drm_connector base; -+ struct drm_encoder enc; -+}; -+ -+struct qxl_framebuffer { -+ struct drm_framebuffer base; -+ struct drm_gem_object *obj; -+}; -+ -+#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_encoder_to_qxl_output(x) container_of(x, struct qxl_output, base) -+#define to_qxl_framebuffer(x) container_of(x, struct qxl_framebuffer, base) -+ -+struct qxl_mman { -+ struct ttm_bo_global_ref bo_global_ref; -+ struct drm_global_reference mem_global_ref; -+ bool mem_global_referenced; -+ struct ttm_bo_device bdev; -+}; -+ -+struct qxl_mode_info { -+ int num_modes; -+ struct qxl_mode *modes; -+ bool mode_config_initialized; -+ -+ /* pointer to fbdev info structure */ -+ struct qxl_fbdev *qfbdev; -+}; -+ -+ -+struct qxl_memslot { -+ uint8_t generation; -+ uint64_t start_phys_addr; -+ uint64_t end_phys_addr; -+ uint64_t high_bits; -+}; -+ -+enum { -+ QXL_RELEASE_DRAWABLE, -+ QXL_RELEASE_SURFACE_CMD, -+ QXL_RELEASE_CURSOR_CMD, -+}; -+ -+/* drm_ prefix to differentiate from qxl_release_info in -+ * spice-protocol/qxl_dev.h */ -+#define QXL_MAX_RES 96 -+struct qxl_release { -+ int id; -+ int type; -+ int bo_count; -+ uint32_t release_offset; -+ uint32_t surface_release_id; -+ struct qxl_bo *bos[QXL_MAX_RES]; -+}; -+ -+struct qxl_fb_image { -+ struct qxl_device *qdev; -+ uint32_t pseudo_palette[16]; -+ struct fb_image fb_image; -+ uint32_t visual; -+}; -+ -+struct qxl_draw_fill { -+ struct qxl_device *qdev; -+ struct qxl_rect rect; -+ uint32_t color; -+ uint16_t rop; -+}; -+ -+/* -+ * Debugfs -+ */ -+struct qxl_debugfs { -+ struct drm_info_list *files; -+ unsigned num_files; -+}; -+ -+int qxl_debugfs_add_files(struct qxl_device *rdev, -+ struct drm_info_list *files, -+ unsigned nfiles); -+int qxl_debugfs_fence_init(struct qxl_device *rdev); -+void qxl_debugfs_remove_files(struct qxl_device *qdev); -+ -+struct qxl_device; -+ -+struct qxl_device { -+ struct device *dev; -+ struct drm_device *ddev; -+ struct pci_dev *pdev; -+ unsigned long flags; -+ -+ resource_size_t vram_base, vram_size; -+ resource_size_t surfaceram_base, surfaceram_size; -+ resource_size_t rom_base, rom_size; -+ struct qxl_rom *rom; -+ -+ struct qxl_mode *modes; -+ struct qxl_bo *monitors_config_bo; -+ struct qxl_monitors_config *monitors_config; -+ -+ /* last received client_monitors_config */ -+ struct qxl_monitors_config *client_monitors_config; -+ -+ int io_base; -+ void *ram; -+ struct qxl_mman mman; -+ struct qxl_gem gem; -+ struct qxl_mode_info mode_info; -+ -+ /* -+ * last created framebuffer with fb_create -+ * only used by debugfs dumbppm -+ */ -+ struct qxl_framebuffer *active_user_framebuffer; -+ -+ struct fb_info *fbdev_info; -+ struct qxl_framebuffer *fbdev_qfb; -+ void *ram_physical; -+ -+ struct qxl_ring *release_ring; -+ struct qxl_ring *command_ring; -+ struct qxl_ring *cursor_ring; -+ -+ struct qxl_ram_header *ram_header; -+ bool mode_set; -+ -+ bool primary_created; -+ -+ struct qxl_memslot *mem_slots; -+ uint8_t n_mem_slots; -+ -+ uint8_t main_mem_slot; -+ uint8_t surfaces_mem_slot; -+ uint8_t slot_id_bits; -+ uint8_t slot_gen_bits; -+ uint64_t va_slot_mask; -+ -+ struct idr release_idr; -+ spinlock_t release_idr_lock; -+ struct mutex async_io_mutex; -+ unsigned int last_sent_io_cmd; -+ -+ /* interrupt handling */ -+ atomic_t irq_received; -+ atomic_t irq_received_display; -+ atomic_t irq_received_cursor; -+ atomic_t irq_received_io_cmd; -+ unsigned irq_received_error; -+ wait_queue_head_t display_event; -+ wait_queue_head_t cursor_event; -+ wait_queue_head_t io_cmd_event; -+ struct work_struct client_monitors_config_work; -+ -+ /* debugfs */ -+ struct qxl_debugfs debugfs[QXL_DEBUGFS_MAX_COMPONENTS]; -+ unsigned debugfs_count; -+ -+ struct mutex update_area_mutex; -+ -+ struct idr surf_id_idr; -+ spinlock_t surf_id_idr_lock; -+ int last_alloced_surf_id; -+ -+ struct mutex surf_evict_mutex; -+ struct io_mapping *vram_mapping; -+ struct io_mapping *surface_mapping; -+ -+ /* */ -+ struct mutex release_mutex; -+ struct qxl_bo *current_release_bo[3]; -+ int current_release_bo_offset[3]; -+ -+ struct workqueue_struct *gc_queue; -+ struct work_struct gc_work; -+ -+}; -+ -+/* forward declaration for QXL_INFO_IO */ -+void qxl_io_log(struct qxl_device *qdev, const char *fmt, ...); -+ -+extern struct drm_ioctl_desc qxl_ioctls[]; -+extern int qxl_max_ioctl; -+ -+int qxl_driver_load(struct drm_device *dev, unsigned long flags); -+int qxl_driver_unload(struct drm_device *dev); -+ -+int qxl_modeset_init(struct qxl_device *qdev); -+void qxl_modeset_fini(struct qxl_device *qdev); -+ -+int qxl_bo_init(struct qxl_device *qdev); -+void qxl_bo_fini(struct qxl_device *qdev); -+ -+struct qxl_ring *qxl_ring_create(struct qxl_ring_header *header, -+ int element_size, -+ int n_elements, -+ int prod_notify, -+ bool set_prod_notify, -+ wait_queue_head_t *push_event); -+void qxl_ring_free(struct qxl_ring *ring); -+ -+static inline void * -+qxl_fb_virtual_address(struct qxl_device *qdev, unsigned long physical) -+{ -+ QXL_INFO(qdev, "not implemented (%lu)\n", physical); -+ return 0; -+} -+ -+static inline uint64_t -+qxl_bo_physical_address(struct qxl_device *qdev, struct qxl_bo *bo, -+ unsigned long offset) -+{ -+ int slot_id = bo->type == QXL_GEM_DOMAIN_VRAM ? qdev->main_mem_slot : qdev->surfaces_mem_slot; -+ struct qxl_memslot *slot = &(qdev->mem_slots[slot_id]); -+ -+ /* TODO - need to hold one of the locks to read tbo.offset */ -+ return slot->high_bits | (bo->tbo.offset + offset); -+} -+ -+/* qxl_fb.c */ -+#define QXLFB_CONN_LIMIT 1 -+ -+int qxl_fbdev_init(struct qxl_device *qdev); -+void qxl_fbdev_fini(struct qxl_device *qdev); -+int qxl_get_handle_for_primary_fb(struct qxl_device *qdev, -+ struct drm_file *file_priv, -+ uint32_t *handle); -+ -+/* qxl_display.c */ -+int -+qxl_framebuffer_init(struct drm_device *dev, -+ struct qxl_framebuffer *rfb, -+ struct drm_mode_fb_cmd2 *mode_cmd, -+ struct drm_gem_object *obj); -+void qxl_display_read_client_monitors_config(struct qxl_device *qdev); -+void qxl_send_monitors_config(struct qxl_device *qdev); -+ -+/* used by qxl_debugfs only */ -+void qxl_crtc_set_from_monitors_config(struct qxl_device *qdev); -+void qxl_alloc_client_monitors_config(struct qxl_device *qdev, unsigned count); -+ -+/* qxl_gem.c */ -+int qxl_gem_init(struct qxl_device *qdev); -+void qxl_gem_fini(struct qxl_device *qdev); -+int qxl_gem_object_create(struct qxl_device *qdev, int size, -+ int alignment, int initial_domain, -+ bool discardable, bool kernel, -+ struct qxl_surface *surf, -+ struct drm_gem_object **obj); -+int qxl_gem_object_pin(struct drm_gem_object *obj, uint32_t pin_domain, -+ uint64_t *gpu_addr); -+void qxl_gem_object_unpin(struct drm_gem_object *obj); -+int qxl_gem_object_create_with_handle(struct qxl_device *qdev, -+ struct drm_file *file_priv, -+ u32 domain, -+ size_t size, -+ struct qxl_surface *surf, -+ struct qxl_bo **qobj, -+ uint32_t *handle); -+int qxl_gem_object_init(struct drm_gem_object *obj); -+void qxl_gem_object_free(struct drm_gem_object *gobj); -+int qxl_gem_object_open(struct drm_gem_object *obj, struct drm_file *file_priv); -+void qxl_gem_object_close(struct drm_gem_object *obj, -+ struct drm_file *file_priv); -+void qxl_bo_force_delete(struct qxl_device *qdev); -+int qxl_bo_kmap(struct qxl_bo *bo, void **ptr); -+ -+/* qxl_dumb.c */ -+int qxl_mode_dumb_create(struct drm_file *file_priv, -+ struct drm_device *dev, -+ struct drm_mode_create_dumb *args); -+int qxl_mode_dumb_destroy(struct drm_file *file_priv, -+ struct drm_device *dev, -+ uint32_t handle); -+int qxl_mode_dumb_mmap(struct drm_file *filp, -+ struct drm_device *dev, -+ uint32_t handle, uint64_t *offset_p); -+ -+ -+/* qxl ttm */ -+int qxl_ttm_init(struct qxl_device *qdev); -+void qxl_ttm_fini(struct qxl_device *qdev); -+int qxl_mmap(struct file *filp, struct vm_area_struct *vma); -+ -+/* qxl image */ -+ -+int qxl_image_create(struct qxl_device *qdev, -+ struct qxl_release *release, -+ struct qxl_bo **image_bo, -+ const uint8_t *data, -+ int x, int y, int width, int height, -+ int depth, int stride); -+void qxl_update_screen(struct qxl_device *qxl); -+ -+/* qxl io operations (qxl_cmd.c) */ -+ -+void qxl_io_create_primary(struct qxl_device *qdev, -+ unsigned width, unsigned height, unsigned offset, -+ struct qxl_bo *bo); -+void qxl_io_destroy_primary(struct qxl_device *qdev); -+void qxl_io_memslot_add(struct qxl_device *qdev, uint8_t id); -+void qxl_io_notify_oom(struct qxl_device *qdev); -+ -+int qxl_io_update_area(struct qxl_device *qdev, struct qxl_bo *surf, -+ const struct qxl_rect *area); -+ -+void qxl_io_reset(struct qxl_device *qdev); -+void qxl_io_monitors_config(struct qxl_device *qdev); -+int qxl_ring_push(struct qxl_ring *ring, const void *new_elt, bool interruptible); -+void qxl_io_flush_release(struct qxl_device *qdev); -+void qxl_io_flush_surfaces(struct qxl_device *qdev); -+ -+int qxl_release_reserve(struct qxl_device *qdev, -+ struct qxl_release *release, bool no_wait); -+void qxl_release_unreserve(struct qxl_device *qdev, -+ struct qxl_release *release); -+union qxl_release_info *qxl_release_map(struct qxl_device *qdev, -+ struct qxl_release *release); -+void qxl_release_unmap(struct qxl_device *qdev, -+ struct qxl_release *release, -+ union qxl_release_info *info); -+/* -+ * qxl_bo_add_resource. -+ * -+ */ -+void qxl_bo_add_resource(struct qxl_bo *main_bo, struct qxl_bo *resource); -+ -+int qxl_alloc_surface_release_reserved(struct qxl_device *qdev, -+ enum qxl_surface_cmd_type surface_cmd_type, -+ struct qxl_release *create_rel, -+ struct qxl_release **release); -+int qxl_alloc_release_reserved(struct qxl_device *qdev, unsigned long size, -+ int type, struct qxl_release **release, -+ struct qxl_bo **rbo); -+int qxl_fence_releaseable(struct qxl_device *qdev, -+ struct qxl_release *release); -+int -+qxl_push_command_ring_release(struct qxl_device *qdev, struct qxl_release *release, -+ uint32_t type, bool interruptible); -+int -+qxl_push_cursor_ring_release(struct qxl_device *qdev, struct qxl_release *release, -+ uint32_t type, bool interruptible); -+int qxl_alloc_bo_reserved(struct qxl_device *qdev, unsigned long size, -+ struct qxl_bo **_bo); -+/* qxl drawing commands */ -+ -+void qxl_draw_opaque_fb(const struct qxl_fb_image *qxl_fb_image, -+ int stride /* filled in if 0 */); -+ -+void qxl_draw_dirty_fb(struct qxl_device *qdev, -+ struct qxl_framebuffer *qxl_fb, -+ struct qxl_bo *bo, -+ unsigned flags, unsigned color, -+ struct drm_clip_rect *clips, -+ unsigned num_clips, int inc); -+ -+void qxl_draw_fill(struct qxl_draw_fill *qxl_draw_fill_rec); -+ -+void qxl_draw_copyarea(struct qxl_device *qdev, -+ u32 width, u32 height, -+ u32 sx, u32 sy, -+ u32 dx, u32 dy); -+ -+uint64_t -+qxl_release_alloc(struct qxl_device *qdev, int type, -+ struct qxl_release **ret); -+ -+void qxl_release_free(struct qxl_device *qdev, -+ struct qxl_release *release); -+void qxl_release_add_res(struct qxl_device *qdev, -+ struct qxl_release *release, -+ struct qxl_bo *bo); -+/* used by qxl_debugfs_release */ -+struct qxl_release *qxl_release_from_id_locked(struct qxl_device *qdev, -+ uint64_t id); -+ -+bool qxl_queue_garbage_collect(struct qxl_device *qdev, bool flush); -+int qxl_garbage_collect(struct qxl_device *qdev); -+ -+/* debugfs */ -+ -+int qxl_debugfs_init(struct drm_minor *minor); -+void qxl_debugfs_takedown(struct drm_minor *minor); -+ -+/* qxl_irq.c */ -+int qxl_irq_init(struct qxl_device *qdev); -+irqreturn_t qxl_irq_handler(DRM_IRQ_ARGS); -+ -+/* qxl_fb.c */ -+int qxl_fb_init(struct qxl_device *qdev); -+ -+int qxl_debugfs_add_files(struct qxl_device *qdev, -+ struct drm_info_list *files, -+ unsigned nfiles); -+ -+int qxl_surface_id_alloc(struct qxl_device *qdev, -+ struct qxl_bo *surf); -+void qxl_surface_id_dealloc(struct qxl_device *qdev, -+ uint32_t surface_id); -+int qxl_hw_surface_alloc(struct qxl_device *qdev, -+ struct qxl_bo *surf, -+ struct ttm_mem_reg *mem); -+int qxl_hw_surface_dealloc(struct qxl_device *qdev, -+ struct qxl_bo *surf); -+ -+int qxl_bo_check_id(struct qxl_device *qdev, struct qxl_bo *bo); -+ -+struct qxl_drv_surface * -+qxl_surface_lookup(struct drm_device *dev, int surface_id); -+void qxl_surface_evict(struct qxl_device *qdev, struct qxl_bo *surf, bool freeing); -+int qxl_update_surface(struct qxl_device *qdev, struct qxl_bo *surf); -+ -+/* qxl_fence.c */ -+int qxl_fence_add_release(struct qxl_fence *qfence, uint32_t rel_id); -+int qxl_fence_remove_release(struct qxl_fence *qfence, uint32_t rel_id); -+int qxl_fence_init(struct qxl_device *qdev, struct qxl_fence *qfence); -+void qxl_fence_fini(struct qxl_fence *qfence); -+ -+#endif -diff --git a/drivers/gpu/drm/qxl/qxl_dumb.c b/drivers/gpu/drm/qxl/qxl_dumb.c -new file mode 100644 -index 0000000..847c4ee ---- /dev/null -+++ b/drivers/gpu/drm/qxl/qxl_dumb.c -@@ -0,0 +1,93 @@ -+/* -+ * Copyright 2013 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, sublicense, -+ * 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 above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * 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 NONINFRINGEMENT. IN NO EVENT SHALL -+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. -+ * -+ * Authors: Dave Airlie -+ * Alon Levy -+ */ -+ -+#include "qxl_drv.h" -+#include "qxl_object.h" -+ -+/* dumb ioctls implementation */ -+ -+int qxl_mode_dumb_create(struct drm_file *file_priv, -+ struct drm_device *dev, -+ struct drm_mode_create_dumb *args) -+{ -+ struct qxl_device *qdev = dev->dev_private; -+ struct qxl_bo *qobj; -+ uint32_t handle; -+ int r; -+ struct qxl_surface surf; -+ uint32_t pitch, format; -+ pitch = args->width * ((args->bpp + 1) / 8); -+ args->size = pitch * args->height; -+ args->size = ALIGN(args->size, PAGE_SIZE); -+ -+ switch (args->bpp) { -+ case 16: -+ format = SPICE_SURFACE_FMT_16_565; -+ break; -+ case 32: -+ format = SPICE_SURFACE_FMT_32_xRGB; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ surf.width = args->width; -+ surf.height = args->height; -+ surf.stride = pitch; -+ surf.format = format; -+ r = qxl_gem_object_create_with_handle(qdev, file_priv, -+ QXL_GEM_DOMAIN_VRAM, -+ args->size, &surf, &qobj, -+ &handle); -+ if (r) -+ return r; -+ args->pitch = pitch; -+ args->handle = handle; -+ return 0; -+} -+ -+int qxl_mode_dumb_destroy(struct drm_file *file_priv, -+ struct drm_device *dev, -+ uint32_t handle) -+{ -+ return drm_gem_handle_delete(file_priv, handle); -+} -+ -+int qxl_mode_dumb_mmap(struct drm_file *file_priv, -+ struct drm_device *dev, -+ uint32_t handle, uint64_t *offset_p) -+{ -+ struct drm_gem_object *gobj; -+ struct qxl_bo *qobj; -+ -+ BUG_ON(!offset_p); -+ gobj = drm_gem_object_lookup(dev, file_priv, handle); -+ if (gobj == NULL) -+ return -ENOENT; -+ qobj = gem_to_qxl_bo(gobj); -+ *offset_p = qxl_bo_mmap_offset(qobj); -+ drm_gem_object_unreference_unlocked(gobj); -+ return 0; -+} -diff --git a/drivers/gpu/drm/qxl/qxl_fb.c b/drivers/gpu/drm/qxl/qxl_fb.c -new file mode 100644 -index 0000000..232b52b ---- /dev/null -+++ b/drivers/gpu/drm/qxl/qxl_fb.c -@@ -0,0 +1,567 @@ -+/* -+ * Copyright © 2013 Red Hat -+ * -+ * 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, sublicense, -+ * 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 above copyright notice and this permission notice (including the next -+ * paragraph) shall be included in all copies or substantial portions of the -+ * Software. -+ * -+ * 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 NONINFRINGEMENT. IN NO EVENT SHALL -+ * THE AUTHORS OR COPYRIGHT HOLDERS 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. -+ * -+ * Authors: -+ * David Airlie -+ */ -+#include -+#include -+ -+#include "drmP.h" -+#include "drm/drm.h" -+#include "drm/drm_crtc.h" -+#include "drm/drm_crtc_helper.h" -+#include "qxl_drv.h" -+ -+#include "qxl_object.h" -+#include "drm_fb_helper.h" -+ -+#define QXL_DIRTY_DELAY (HZ / 30) -+ -+struct qxl_fbdev { -+ struct drm_fb_helper helper; -+ struct qxl_framebuffer qfb; -+ struct list_head fbdev_list; -+ struct qxl_device *qdev; -+ -+ void *shadow; -+ int size; -+ -+ /* dirty memory logging */ -+ struct { -+ spinlock_t lock; -+ bool active; -+ unsigned x1; -+ unsigned y1; -+ unsigned x2; -+ unsigned y2; -+ } dirty; -+}; -+ -+static void qxl_fb_image_init(struct qxl_fb_image *qxl_fb_image, -+ struct qxl_device *qdev, struct fb_info *info, -+ const struct fb_image *image) -+{ -+ qxl_fb_image->qdev = qdev; -+ if (info) { -+ qxl_fb_image->visual = info->fix.visual; -+ if (qxl_fb_image->visual == FB_VISUAL_TRUECOLOR || -+ qxl_fb_image->visual == FB_VISUAL_DIRECTCOLOR) -+ memcpy(&qxl_fb_image->pseudo_palette, -+ info->pseudo_palette, -+ sizeof(qxl_fb_image->pseudo_palette)); -+ } else { -+ /* fallback */ -+ if (image->depth == 1) -+ qxl_fb_image->visual = FB_VISUAL_MONO10; -+ else -+ qxl_fb_image->visual = FB_VISUAL_DIRECTCOLOR; -+ } -+ if (image) { -+ memcpy(&qxl_fb_image->fb_image, image, -+ sizeof(qxl_fb_image->fb_image)); -+ } -+} -+ -+static void qxl_fb_dirty_flush(struct fb_info *info) -+{ -+ struct qxl_fbdev *qfbdev = info->par; -+ struct qxl_device *qdev = qfbdev->qdev; -+ struct qxl_fb_image qxl_fb_image; -+ struct fb_image *image = &qxl_fb_image.fb_image; -+ u32 x1, x2, y1, y2; -+ -+ /* TODO: hard coding 32 bpp */ -+ int stride = qfbdev->qfb.base.pitches[0] * 4; -+ -+ x1 = qfbdev->dirty.x1; -+ x2 = qfbdev->dirty.x2; -+ y1 = qfbdev->dirty.y1; -+ y2 = qfbdev->dirty.y2; -+ /* -+ * we are using a shadow draw buffer, at qdev->surface0_shadow -+ */ -+ qxl_io_log(qdev, "dirty x[%d, %d], y[%d, %d]", x1, x2, y1, y2); -+ image->dx = x1; -+ image->dy = y1; -+ image->width = x2 - x1; -+ image->height = y2 - y1; -+ image->fg_color = 0xffffffff; /* unused, just to avoid uninitialized -+ warnings */ -+ image->bg_color = 0; -+ image->depth = 32; /* TODO: take from somewhere? */ -+ image->cmap.start = 0; -+ image->cmap.len = 0; -+ image->cmap.red = NULL; -+ image->cmap.green = NULL; -+ image->cmap.blue = NULL; -+ image->cmap.transp = NULL; -+ image->data = qfbdev->shadow + (x1 * 4) + (stride * y1); -+ -+ qxl_fb_image_init(&qxl_fb_image, qdev, info, NULL); -+ qxl_draw_opaque_fb(&qxl_fb_image, stride); -+ qfbdev->dirty.x1 = 0; -+ qfbdev->dirty.x2 = 0; -+ qfbdev->dirty.y1 = 0; -+ qfbdev->dirty.y2 = 0; -+} -+ -+static void qxl_deferred_io(struct fb_info *info, -+ struct list_head *pagelist) -+{ -+ struct qxl_fbdev *qfbdev = info->par; -+ unsigned long start, end, min, max; -+ struct page *page; -+ int y1, y2; -+ -+ min = ULONG_MAX; -+ max = 0; -+ list_for_each_entry(page, pagelist, lru) { -+ start = page->index << PAGE_SHIFT; -+ end = start + PAGE_SIZE - 1; -+ min = min(min, start); -+ max = max(max, end); -+ } -+ -+ if (min < max) { -+ y1 = min / info->fix.line_length; -+ y2 = (max / info->fix.line_length) + 1; -+ -+ /* TODO: add spin lock? */ -+ /* spin_lock_irqsave(&qfbdev->dirty.lock, flags); */ -+ qfbdev->dirty.x1 = 0; -+ qfbdev->dirty.y1 = y1; -+ qfbdev->dirty.x2 = info->var.xres; -+ qfbdev->dirty.y2 = y2; -+ /* spin_unlock_irqrestore(&qfbdev->dirty.lock, flags); */ -+ } -+ -+ qxl_fb_dirty_flush(info); -+}; -+ -+ -+struct fb_deferred_io qxl_defio = { -+ .delay = QXL_DIRTY_DELAY, -+ .deferred_io = qxl_deferred_io, -+}; -+ -+static void qxl_fb_fillrect(struct fb_info *info, -+ const struct fb_fillrect *fb_rect) -+{ -+ struct qxl_fbdev *qfbdev = info->par; -+ struct qxl_device *qdev = qfbdev->qdev; -+ struct qxl_rect rect; -+ uint32_t color; -+ int x = fb_rect->dx; -+ int y = fb_rect->dy; -+ int width = fb_rect->width; -+ int height = fb_rect->height; -+ uint16_t rop; -+ struct qxl_draw_fill qxl_draw_fill_rec; -+ -+ if (info->fix.visual == FB_VISUAL_TRUECOLOR || -+ info->fix.visual == FB_VISUAL_DIRECTCOLOR) -+ color = ((u32 *) (info->pseudo_palette))[fb_rect->color]; -+ else -+ color = fb_rect->color; -+ rect.left = x; -+ rect.right = x + width; -+ rect.top = y; -+ rect.bottom = y + height; -+ switch (fb_rect->rop) { -+ case ROP_XOR: -+ rop = SPICE_ROPD_OP_XOR; -+ break; -+ case ROP_COPY: -+ rop = SPICE_ROPD_OP_PUT; -+ break; -+ default: -+ pr_err("qxl_fb_fillrect(): unknown rop, " -+ "defaulting to SPICE_ROPD_OP_PUT\n"); -+ rop = SPICE_ROPD_OP_PUT; -+ } -+ qxl_draw_fill_rec.qdev = qdev; -+ qxl_draw_fill_rec.rect = rect; -+ qxl_draw_fill_rec.color = color; -+ qxl_draw_fill_rec.rop = rop; -+ if (!drm_can_sleep()) { -+ qxl_io_log(qdev, -+ "%s: TODO use RCU, mysterious locks with spin_lock\n", -+ __func__); -+ return; -+ } -+ qxl_draw_fill(&qxl_draw_fill_rec); -+} -+ -+static void qxl_fb_copyarea(struct fb_info *info, -+ const struct fb_copyarea *region) -+{ -+ struct qxl_fbdev *qfbdev = info->par; -+ -+ qxl_draw_copyarea(qfbdev->qdev, -+ region->width, region->height, -+ region->sx, region->sy, -+ region->dx, region->dy); -+} -+ -+static void qxl_fb_imageblit_safe(struct qxl_fb_image *qxl_fb_image) -+{ -+ qxl_draw_opaque_fb(qxl_fb_image, 0); -+} -+ -+static void qxl_fb_imageblit(struct fb_info *info, -+ const struct fb_image *image) -+{ -+ struct qxl_fbdev *qfbdev = info->par; -+ struct qxl_device *qdev = qfbdev->qdev; -+ struct qxl_fb_image qxl_fb_image; -+ -+ if (!drm_can_sleep()) { -+ /* we cannot do any ttm_bo allocation since that will fail on -+ * ioremap_wc..__get_vm_area_node, so queue the work item -+ * instead This can happen from printk inside an interrupt -+ * context, i.e.: smp_apic_timer_interrupt..check_cpu_stall */ -+ qxl_io_log(qdev, -+ "%s: TODO use RCU, mysterious locks with spin_lock\n", -+ __func__); -+ return; -+ } -+ -+ /* ensure proper order of rendering operations - TODO: must do this -+ * for everything. */ -+ qxl_fb_image_init(&qxl_fb_image, qfbdev->qdev, info, image); -+ qxl_fb_imageblit_safe(&qxl_fb_image); -+} -+ -+int qxl_fb_init(struct qxl_device *qdev) -+{ -+ return 0; -+} -+ -+static struct fb_ops qxlfb_ops = { -+ .owner = THIS_MODULE, -+ .fb_check_var = drm_fb_helper_check_var, -+ .fb_set_par = drm_fb_helper_set_par, /* TODO: copy vmwgfx */ -+ .fb_fillrect = qxl_fb_fillrect, -+ .fb_copyarea = qxl_fb_copyarea, -+ .fb_imageblit = qxl_fb_imageblit, -+ .fb_pan_display = drm_fb_helper_pan_display, -+ .fb_blank = drm_fb_helper_blank, -+ .fb_setcmap = drm_fb_helper_setcmap, -+ .fb_debug_enter = drm_fb_helper_debug_enter, -+ .fb_debug_leave = drm_fb_helper_debug_leave, -+}; -+ -+static void qxlfb_destroy_pinned_object(struct drm_gem_object *gobj) -+{ -+ struct qxl_bo *qbo = gem_to_qxl_bo(gobj); -+ int ret; -+ -+ ret = qxl_bo_reserve(qbo, false); -+ if (likely(ret == 0)) { -+ qxl_bo_kunmap(qbo); -+ qxl_bo_unpin(qbo); -+ qxl_bo_unreserve(qbo); -+ } -+ drm_gem_object_unreference_unlocked(gobj); -+} -+ -+int qxl_get_handle_for_primary_fb(struct qxl_device *qdev, -+ struct drm_file *file_priv, -+ uint32_t *handle) -+{ -+ int r; -+ struct drm_gem_object *gobj = qdev->fbdev_qfb->obj; -+ -+ BUG_ON(!gobj); -+ /* drm_get_handle_create adds a reference - good */ -+ r = drm_gem_handle_create(file_priv, gobj, handle); -+ if (r) -+ return r; -+ return 0; -+} -+ -+static int qxlfb_create_pinned_object(struct qxl_fbdev *qfbdev, -+ struct drm_mode_fb_cmd2 *mode_cmd, -+ struct drm_gem_object **gobj_p) -+{ -+ struct qxl_device *qdev = qfbdev->qdev; -+ struct drm_gem_object *gobj = NULL; -+ struct qxl_bo *qbo = NULL; -+ int ret; -+ int aligned_size, size; -+ int height = mode_cmd->height; -+ int bpp; -+ int depth; -+ -+ drm_fb_get_bpp_depth(mode_cmd->pixel_format, &bpp, &depth); -+ -+ size = mode_cmd->pitches[0] * height; -+ aligned_size = ALIGN(size, PAGE_SIZE); -+ /* TODO: unallocate and reallocate surface0 for real. Hack to just -+ * have a large enough surface0 for 1024x768 Xorg 32bpp mode */ -+ ret = qxl_gem_object_create(qdev, aligned_size, 0, -+ QXL_GEM_DOMAIN_SURFACE, -+ false, /* is discardable */ -+ false, /* is kernel (false means device) */ -+ NULL, -+ &gobj); -+ if (ret) { -+ pr_err("failed to allocate framebuffer (%d)\n", -+ aligned_size); -+ return -ENOMEM; -+ } -+ qbo = gem_to_qxl_bo(gobj); -+ -+ qbo->surf.width = mode_cmd->width; -+ qbo->surf.height = mode_cmd->height; -+ qbo->surf.stride = mode_cmd->pitches[0]; -+ qbo->surf.format = SPICE_SURFACE_FMT_32_xRGB; -+ ret = qxl_bo_reserve(qbo, false); -+ if (unlikely(ret != 0)) -+ goto out_unref; -+ ret = qxl_bo_pin(qbo, QXL_GEM_DOMAIN_SURFACE, NULL); -+ if (ret) { -+ qxl_bo_unreserve(qbo); -+ goto out_unref; -+ } -+ ret = qxl_bo_kmap(qbo, NULL); -+ qxl_bo_unreserve(qbo); /* unreserve, will be mmaped */ -+ if (ret) -+ goto out_unref; -+ -+ *gobj_p = gobj; -+ return 0; -+out_unref: -+ qxlfb_destroy_pinned_object(gobj); -+ *gobj_p = NULL; -+ return ret; -+} -+ -+static int qxlfb_create(struct qxl_fbdev *qfbdev, -+ struct drm_fb_helper_surface_size *sizes) -+{ -+ struct qxl_device *qdev = qfbdev->qdev; -+ struct fb_info *info; -+ struct drm_framebuffer *fb = NULL; -+ struct drm_mode_fb_cmd2 mode_cmd; -+ struct drm_gem_object *gobj = NULL; -+ struct qxl_bo *qbo = NULL; -+ struct device *device = &qdev->pdev->dev; -+ int ret; -+ int size; -+ int bpp = sizes->surface_bpp; -+ int depth = sizes->surface_depth; -+ void *shadow; -+ -+ mode_cmd.width = sizes->surface_width; -+ mode_cmd.height = sizes->surface_height; -+ -+ mode_cmd.pitches[0] = ALIGN(mode_cmd.width * ((bpp + 1) / 8), 64); -+ mode_cmd.pixel_format = drm_mode_legacy_fb_format(bpp, depth); -+ -+ ret = qxlfb_create_pinned_object(qfbdev, &mode_cmd, &gobj); -+ qbo = gem_to_qxl_bo(gobj); -+ QXL_INFO(qdev, "%s: %dx%d %d\n", __func__, mode_cmd.width, -+ mode_cmd.height, mode_cmd.pitches[0]); -+ -+ shadow = vmalloc(mode_cmd.pitches[0] * mode_cmd.height); -+ /* TODO: what's the usual response to memory allocation errors? */ -+ BUG_ON(!shadow); -+ QXL_INFO(qdev, -+ "surface0 at gpu offset %lld, mmap_offset %lld (virt %p, shadow %p)\n", -+ qxl_bo_gpu_offset(qbo), -+ qxl_bo_mmap_offset(qbo), -+ qbo->kptr, -+ shadow); -+ size = mode_cmd.pitches[0] * mode_cmd.height; -+ -+ info = framebuffer_alloc(0, device); -+ if (info == NULL) { -+ ret = -ENOMEM; -+ goto out_unref; -+ } -+ -+ info->par = qfbdev; -+ -+ qxl_framebuffer_init(qdev->ddev, &qfbdev->qfb, &mode_cmd, gobj); -+ -+ fb = &qfbdev->qfb.base; -+ -+ /* setup helper with fb data */ -+ qfbdev->helper.fb = fb; -+ qfbdev->helper.fbdev = info; -+ qfbdev->shadow = shadow; -+ strcpy(info->fix.id, "qxldrmfb"); -+ -+ drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth); -+ -+ info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT; -+ info->fbops = &qxlfb_ops; -+ -+ /* -+ * TODO: using gobj->size in various places in this function. Not sure -+ * what the difference between the different sizes is. -+ */ -+ info->fix.smem_start = qdev->vram_base; /* TODO - correct? */ -+ info->fix.smem_len = gobj->size; -+ info->screen_base = qfbdev->shadow; -+ info->screen_size = gobj->size; -+ -+ drm_fb_helper_fill_var(info, &qfbdev->helper, sizes->fb_width, -+ sizes->fb_height); -+ -+ /* setup aperture base/size for vesafb takeover */ -+ info->apertures = alloc_apertures(1); -+ if (!info->apertures) { -+ ret = -ENOMEM; -+ goto out_unref; -+ } -+ info->apertures->ranges[0].base = qdev->ddev->mode_config.fb_base; -+ info->apertures->ranges[0].size = qdev->vram_size; -+ -+ info->fix.mmio_start = 0; -+ info->fix.mmio_len = 0; -+ -+ if (info->screen_base == NULL) { -+ ret = -ENOSPC; -+ goto out_unref; -+ } -+ -+ ret = fb_alloc_cmap(&info->cmap, 256, 0); -+ if (ret) { -+ ret = -ENOMEM; -+ goto out_unref; -+ } -+ -+ info->fbdefio = &qxl_defio; -+ fb_deferred_io_init(info); -+ -+ qdev->fbdev_info = info; -+ qdev->fbdev_qfb = &qfbdev->qfb; -+ DRM_INFO("fb mappable at 0x%lX, size %lu\n", info->fix.smem_start, (unsigned long)info->screen_size); -+ DRM_INFO("fb: depth %d, pitch %d, width %d, height %d\n", fb->depth, fb->pitches[0], fb->width, fb->height); -+ return 0; -+ -+out_unref: -+ if (qbo) { -+ ret = qxl_bo_reserve(qbo, false); -+ if (likely(ret == 0)) { -+ qxl_bo_kunmap(qbo); -+ qxl_bo_unpin(qbo); -+ qxl_bo_unreserve(qbo); -+ } -+ } -+ if (fb && ret) { -+ drm_gem_object_unreference(gobj); -+ drm_framebuffer_cleanup(fb); -+ kfree(fb); -+ } -+ drm_gem_object_unreference(gobj); -+ return ret; -+} -+ -+static int qxl_fb_find_or_create_single( -+ struct drm_fb_helper *helper, -+ struct drm_fb_helper_surface_size *sizes) -+{ -+ struct qxl_fbdev *qfbdev = (struct qxl_fbdev *)helper; -+ int new_fb = 0; -+ int ret; -+ -+ if (!helper->fb) { -+ ret = qxlfb_create(qfbdev, sizes); -+ if (ret) -+ return ret; -+ new_fb = 1; -+ } -+ return new_fb; -+} -+ -+static int qxl_fbdev_destroy(struct drm_device *dev, struct qxl_fbdev *qfbdev) -+{ -+ struct fb_info *info; -+ struct qxl_framebuffer *qfb = &qfbdev->qfb; -+ -+ if (qfbdev->helper.fbdev) { -+ info = qfbdev->helper.fbdev; -+ -+ unregister_framebuffer(info); -+ framebuffer_release(info); -+ } -+ if (qfb->obj) { -+ qxlfb_destroy_pinned_object(qfb->obj); -+ qfb->obj = NULL; -+ } -+ drm_fb_helper_fini(&qfbdev->helper); -+ vfree(qfbdev->shadow); -+ drm_framebuffer_cleanup(&qfb->base); -+ -+ return 0; -+} -+ -+static struct drm_fb_helper_funcs qxl_fb_helper_funcs = { -+ /* TODO -+ .gamma_set = qxl_crtc_fb_gamma_set, -+ .gamma_get = qxl_crtc_fb_gamma_get, -+ */ -+ .fb_probe = qxl_fb_find_or_create_single, -+}; -+ -+int qxl_fbdev_init(struct qxl_device *qdev) -+{ -+ struct qxl_fbdev *qfbdev; -+ int bpp_sel = 32; /* TODO: parameter from somewhere? */ -+ int ret; -+ -+ qfbdev = kzalloc(sizeof(struct qxl_fbdev), GFP_KERNEL); -+ if (!qfbdev) -+ return -ENOMEM; -+ -+ qfbdev->qdev = qdev; -+ qdev->mode_info.qfbdev = qfbdev; -+ qfbdev->helper.funcs = &qxl_fb_helper_funcs; -+ -+ ret = drm_fb_helper_init(qdev->ddev, &qfbdev->helper, -+ 1 /* num_crtc - QXL supports just 1 */, -+ QXLFB_CONN_LIMIT); -+ if (ret) { -+ kfree(qfbdev); -+ return ret; -+ } -+ -+ drm_fb_helper_single_add_all_connectors(&qfbdev->helper); -+ drm_fb_helper_initial_config(&qfbdev->helper, bpp_sel); -+ return 0; -+} -+ -+void qxl_fbdev_fini(struct qxl_device *qdev) -+{ -+ if (!qdev->mode_info.qfbdev) -+ return; -+ -+ qxl_fbdev_destroy(qdev->ddev, qdev->mode_info.qfbdev); -+ kfree(qdev->mode_info.qfbdev); -+ qdev->mode_info.qfbdev = NULL; -+} -+ -+ -diff --git a/drivers/gpu/drm/qxl/qxl_fence.c b/drivers/gpu/drm/qxl/qxl_fence.c -new file mode 100644 -index 0000000..63c6715 ---- /dev/null -+++ b/drivers/gpu/drm/qxl/qxl_fence.c -@@ -0,0 +1,97 @@ -+/* -+ * Copyright 2013 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, sublicense, -+ * 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 above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * 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 NONINFRINGEMENT. IN NO EVENT SHALL -+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. -+ * -+ * Authors: Dave Airlie -+ * Alon Levy -+ */ -+ -+ -+#include "qxl_drv.h" -+ -+/* QXL fencing- -+ -+ When we submit operations to the GPU we pass a release reference to the GPU -+ with them, the release reference is then added to the release ring when -+ the GPU is finished with that particular operation and has removed it from -+ its tree. -+ -+ So we have can have multiple outstanding non linear fences per object. -+ -+ From a TTM POV we only care if the object has any outstanding releases on -+ it. -+ -+ we wait until all outstanding releases are processeed. -+ -+ sync object is just a list of release ids that represent that fence on -+ that buffer. -+ -+ we just add new releases onto the sync object attached to the object. -+ -+ This currently uses a radix tree to store the list of release ids. -+ -+ For some reason every so often qxl hw fails to release, things go wrong. -+*/ -+ -+ -+int qxl_fence_add_release(struct qxl_fence *qfence, uint32_t rel_id) -+{ -+ struct qxl_bo *bo = container_of(qfence, struct qxl_bo, fence); -+ -+ spin_lock(&bo->tbo.bdev->fence_lock); -+ radix_tree_insert(&qfence->tree, rel_id, qfence); -+ qfence->num_active_releases++; -+ spin_unlock(&bo->tbo.bdev->fence_lock); -+ return 0; -+} -+ -+int qxl_fence_remove_release(struct qxl_fence *qfence, uint32_t rel_id) -+{ -+ void *ret; -+ int retval = 0; -+ struct qxl_bo *bo = container_of(qfence, struct qxl_bo, fence); -+ -+ spin_lock(&bo->tbo.bdev->fence_lock); -+ -+ ret = radix_tree_delete(&qfence->tree, rel_id); -+ if (ret == qfence) -+ qfence->num_active_releases--; -+ else { -+ DRM_DEBUG("didn't find fence in radix tree for %d\n", rel_id); -+ retval = -ENOENT; -+ } -+ spin_unlock(&bo->tbo.bdev->fence_lock); -+ return retval; -+} -+ -+ -+int qxl_fence_init(struct qxl_device *qdev, struct qxl_fence *qfence) -+{ -+ qfence->qdev = qdev; -+ qfence->num_active_releases = 0; -+ INIT_RADIX_TREE(&qfence->tree, GFP_ATOMIC); -+ return 0; -+} -+ -+void qxl_fence_fini(struct qxl_fence *qfence) -+{ -+ kfree(qfence->release_ids); -+ qfence->num_active_releases = 0; -+} -diff --git a/drivers/gpu/drm/qxl/qxl_gem.c b/drivers/gpu/drm/qxl/qxl_gem.c -new file mode 100644 -index 0000000..adc1ee2 ---- /dev/null -+++ b/drivers/gpu/drm/qxl/qxl_gem.c -@@ -0,0 +1,178 @@ -+/* -+ * Copyright 2013 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, sublicense, -+ * 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 above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * 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 NONINFRINGEMENT. IN NO EVENT SHALL -+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. -+ * -+ * Authors: Dave Airlie -+ * Alon Levy -+ */ -+ -+#include "drmP.h" -+#include "drm/drm.h" -+#include "qxl_drv.h" -+#include "qxl_object.h" -+ -+int qxl_gem_object_init(struct drm_gem_object *obj) -+{ -+ /* we do nothings here */ -+ return 0; -+} -+ -+void qxl_gem_object_free(struct drm_gem_object *gobj) -+{ -+ struct qxl_bo *qobj = gem_to_qxl_bo(gobj); -+ -+ if (qobj) -+ qxl_bo_unref(&qobj); -+} -+ -+int qxl_gem_object_create(struct qxl_device *qdev, int size, -+ int alignment, int initial_domain, -+ bool discardable, bool kernel, -+ struct qxl_surface *surf, -+ struct drm_gem_object **obj) -+{ -+ struct qxl_bo *qbo; -+ int r; -+ -+ *obj = NULL; -+ /* At least align on page size */ -+ if (alignment < PAGE_SIZE) -+ alignment = PAGE_SIZE; -+ r = qxl_bo_create(qdev, size, kernel, initial_domain, surf, &qbo); -+ if (r) { -+ if (r != -ERESTARTSYS) -+ DRM_ERROR( -+ "Failed to allocate GEM object (%d, %d, %u, %d)\n", -+ size, initial_domain, alignment, r); -+ return r; -+ } -+ *obj = &qbo->gem_base; -+ -+ mutex_lock(&qdev->gem.mutex); -+ list_add_tail(&qbo->list, &qdev->gem.objects); -+ mutex_unlock(&qdev->gem.mutex); -+ -+ return 0; -+} -+ -+int qxl_gem_object_create_with_handle(struct qxl_device *qdev, -+ struct drm_file *file_priv, -+ u32 domain, -+ size_t size, -+ struct qxl_surface *surf, -+ struct qxl_bo **qobj, -+ uint32_t *handle) -+{ -+ struct drm_gem_object *gobj; -+ int r; -+ -+ BUG_ON(!qobj); -+ BUG_ON(!handle); -+ -+ r = qxl_gem_object_create(qdev, size, 0, -+ domain, -+ false, false, surf, -+ &gobj); -+ if (r) -+ return -ENOMEM; -+ r = drm_gem_handle_create(file_priv, gobj, handle); -+ if (r) -+ return r; -+ /* drop reference from allocate - handle holds it now */ -+ *qobj = gem_to_qxl_bo(gobj); -+ drm_gem_object_unreference_unlocked(gobj); -+ return 0; -+} -+ -+int qxl_gem_object_pin(struct drm_gem_object *obj, uint32_t pin_domain, -+ uint64_t *gpu_addr) -+{ -+ struct qxl_bo *qobj = obj->driver_private; -+ int r; -+ -+ r = qxl_bo_reserve(qobj, false); -+ if (unlikely(r != 0)) -+ return r; -+ r = qxl_bo_pin(qobj, pin_domain, gpu_addr); -+ qxl_bo_unreserve(qobj); -+ return r; -+} -+ -+void qxl_gem_object_unpin(struct drm_gem_object *obj) -+{ -+ struct qxl_bo *qobj = obj->driver_private; -+ int r; -+ -+ r = qxl_bo_reserve(qobj, false); -+ if (likely(r == 0)) { -+ qxl_bo_unpin(qobj); -+ qxl_bo_unreserve(qobj); -+ } -+} -+ -+int qxl_gem_set_domain(struct drm_gem_object *gobj, -+ uint32_t rdomain, uint32_t wdomain) -+{ -+ struct qxl_bo *qobj; -+ uint32_t domain; -+ int r; -+ -+ /* FIXME: reeimplement */ -+ qobj = gobj->driver_private; -+ /* work out where to validate the buffer to */ -+ domain = wdomain; -+ if (!domain) -+ domain = rdomain; -+ if (!domain) { -+ /* Do nothings */ -+ pr_warn("Set domain withou domain !\n"); -+ return 0; -+ } -+ if (domain == QXL_GEM_DOMAIN_CPU) { -+ /* Asking for cpu access wait for object idle */ -+ r = qxl_bo_wait(qobj, NULL, false); -+ if (r) { -+ pr_err("Failed to wait for object !\n"); -+ return r; -+ } -+ } -+ return 0; -+} -+ -+int qxl_gem_object_open(struct drm_gem_object *obj, struct drm_file *file_priv) -+{ -+ return 0; -+} -+ -+void qxl_gem_object_close(struct drm_gem_object *obj, -+ struct drm_file *file_priv) -+{ -+} -+ -+int qxl_gem_init(struct qxl_device *qdev) -+{ -+ INIT_LIST_HEAD(&qdev->gem.objects); -+ return 0; -+} -+ -+void qxl_gem_fini(struct qxl_device *qdev) -+{ -+ qxl_bo_force_delete(qdev); -+} -diff --git a/drivers/gpu/drm/qxl/qxl_image.c b/drivers/gpu/drm/qxl/qxl_image.c -new file mode 100644 -index 0000000..cf85620 ---- /dev/null -+++ b/drivers/gpu/drm/qxl/qxl_image.c -@@ -0,0 +1,176 @@ -+/* -+ * Copyright 2013 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, sublicense, -+ * 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 above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * 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 NONINFRINGEMENT. IN NO EVENT SHALL -+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. -+ * -+ * Authors: Dave Airlie -+ * Alon Levy -+ */ -+ -+#include -+#include -+ -+#include "qxl_drv.h" -+#include "qxl_object.h" -+ -+static int -+qxl_image_create_helper(struct qxl_device *qdev, -+ struct qxl_release *release, -+ struct qxl_bo **image_bo, -+ const uint8_t *data, -+ int width, int height, -+ int depth, unsigned int hash, -+ int stride) -+{ -+ struct qxl_image *image; -+ struct qxl_data_chunk *chunk; -+ int i; -+ int chunk_stride; -+ int linesize = width * depth / 8; -+ struct qxl_bo *chunk_bo; -+ int ret; -+ void *ptr; -+ /* Chunk */ -+ /* FIXME: Check integer overflow */ -+ /* TODO: variable number of chunks */ -+ chunk_stride = stride; /* TODO: should use linesize, but it renders -+ wrong (check the bitmaps are sent correctly -+ first) */ -+ ret = qxl_alloc_bo_reserved(qdev, sizeof(*chunk) + height * chunk_stride, -+ &chunk_bo); -+ -+ ptr = qxl_bo_kmap_atomic_page(qdev, chunk_bo, 0); -+ chunk = ptr; -+ chunk->data_size = height * chunk_stride; -+ chunk->prev_chunk = 0; -+ chunk->next_chunk = 0; -+ qxl_bo_kunmap_atomic_page(qdev, chunk_bo, ptr); -+ -+ { -+ void *k_data, *i_data; -+ int remain; -+ int page; -+ int size; -+ if (stride == linesize && chunk_stride == stride) { -+ remain = linesize * height; -+ page = 0; -+ i_data = (void *)data; -+ -+ while (remain > 0) { -+ ptr = qxl_bo_kmap_atomic_page(qdev, chunk_bo, page << PAGE_SHIFT); -+ -+ if (page == 0) { -+ chunk = ptr; -+ k_data = chunk->data; -+ size = PAGE_SIZE - offsetof(struct qxl_data_chunk, data); -+ } else { -+ k_data = ptr; -+ size = PAGE_SIZE; -+ } -+ size = min(size, remain); -+ -+ memcpy(k_data, i_data, size); -+ -+ qxl_bo_kunmap_atomic_page(qdev, chunk_bo, ptr); -+ i_data += size; -+ remain -= size; -+ page++; -+ } -+ } else { -+ unsigned page_base, page_offset, out_offset; -+ for (i = 0 ; i < height ; ++i) { -+ i_data = (void *)data + i * stride; -+ remain = linesize; -+ out_offset = offsetof(struct qxl_data_chunk, data) + i * chunk_stride; -+ -+ while (remain > 0) { -+ page_base = out_offset & PAGE_MASK; -+ page_offset = offset_in_page(out_offset); -+ -+ size = min((int)(PAGE_SIZE - page_offset), remain); -+ -+ ptr = qxl_bo_kmap_atomic_page(qdev, chunk_bo, page_base); -+ k_data = ptr + page_offset; -+ memcpy(k_data, i_data, size); -+ qxl_bo_kunmap_atomic_page(qdev, chunk_bo, ptr); -+ remain -= size; -+ i_data += size; -+ out_offset += size; -+ } -+ } -+ } -+ } -+ -+ -+ qxl_bo_kunmap(chunk_bo); -+ -+ /* Image */ -+ ret = qxl_alloc_bo_reserved(qdev, sizeof(*image), image_bo); -+ -+ ptr = qxl_bo_kmap_atomic_page(qdev, *image_bo, 0); -+ image = ptr; -+ -+ image->descriptor.id = 0; -+ image->descriptor.type = SPICE_IMAGE_TYPE_BITMAP; -+ -+ image->descriptor.flags = 0; -+ image->descriptor.width = width; -+ image->descriptor.height = height; -+ -+ switch (depth) { -+ case 1: -+ /* TODO: BE? check by arch? */ -+ image->u.bitmap.format = SPICE_BITMAP_FMT_1BIT_BE; -+ break; -+ case 24: -+ image->u.bitmap.format = SPICE_BITMAP_FMT_24BIT; -+ break; -+ case 32: -+ image->u.bitmap.format = SPICE_BITMAP_FMT_32BIT; -+ break; -+ default: -+ DRM_ERROR("unsupported image bit depth\n"); -+ return -EINVAL; /* TODO: cleanup */ -+ } -+ image->u.bitmap.flags = QXL_BITMAP_TOP_DOWN; -+ image->u.bitmap.x = width; -+ image->u.bitmap.y = height; -+ image->u.bitmap.stride = chunk_stride; -+ image->u.bitmap.palette = 0; -+ image->u.bitmap.data = qxl_bo_physical_address(qdev, chunk_bo, 0); -+ qxl_release_add_res(qdev, release, chunk_bo); -+ qxl_bo_unreserve(chunk_bo); -+ qxl_bo_unref(&chunk_bo); -+ -+ qxl_bo_kunmap_atomic_page(qdev, *image_bo, ptr); -+ -+ return 0; -+} -+ -+int qxl_image_create(struct qxl_device *qdev, -+ struct qxl_release *release, -+ struct qxl_bo **image_bo, -+ const uint8_t *data, -+ int x, int y, int width, int height, -+ int depth, int stride) -+{ -+ data += y * stride + x * (depth / 8); -+ return qxl_image_create_helper(qdev, release, image_bo, data, -+ width, height, depth, 0, stride); -+} -diff --git a/drivers/gpu/drm/qxl/qxl_ioctl.c b/drivers/gpu/drm/qxl/qxl_ioctl.c -new file mode 100644 -index 0000000..83ca4f7 ---- /dev/null -+++ b/drivers/gpu/drm/qxl/qxl_ioctl.c -@@ -0,0 +1,411 @@ -+/* -+ * Copyright 2013 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, sublicense, -+ * 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 above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * 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 NONINFRINGEMENT. IN NO EVENT SHALL -+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. -+ * -+ * Authors: Dave Airlie -+ * Alon Levy -+ */ -+ -+#include "qxl_drv.h" -+#include "qxl_object.h" -+ -+/* -+ * TODO: allocating a new gem(in qxl_bo) for each request. -+ * This is wasteful since bo's are page aligned. -+ */ -+int qxl_alloc_ioctl(struct drm_device *dev, void *data, -+ struct drm_file *file_priv) -+{ -+ struct qxl_device *qdev = dev->dev_private; -+ struct drm_qxl_alloc *qxl_alloc = data; -+ int ret; -+ struct qxl_bo *qobj; -+ uint32_t handle; -+ u32 domain = QXL_GEM_DOMAIN_VRAM; -+ -+ if (qxl_alloc->size == 0) { -+ DRM_ERROR("invalid size %d\n", qxl_alloc->size); -+ return -EINVAL; -+ } -+ ret = qxl_gem_object_create_with_handle(qdev, file_priv, -+ domain, -+ qxl_alloc->size, -+ NULL, -+ &qobj, &handle); -+ if (ret) { -+ DRM_ERROR("%s: failed to create gem ret=%d\n", -+ __func__, ret); -+ return -ENOMEM; -+ } -+ qxl_alloc->handle = handle; -+ return 0; -+} -+ -+int qxl_map_ioctl(struct drm_device *dev, void *data, -+ struct drm_file *file_priv) -+{ -+ struct qxl_device *qdev = dev->dev_private; -+ struct drm_qxl_map *qxl_map = data; -+ -+ return qxl_mode_dumb_mmap(file_priv, qdev->ddev, qxl_map->handle, -+ &qxl_map->offset); -+} -+ -+/* -+ * dst must be validated, i.e. whole bo on vram/surfacesram (right now all bo's -+ * are on vram). -+ * *(dst + dst_off) = qxl_bo_physical_address(src, src_off) -+ */ -+static void -+apply_reloc(struct qxl_device *qdev, struct qxl_bo *dst, uint64_t dst_off, -+ struct qxl_bo *src, uint64_t src_off) -+{ -+ void *reloc_page; -+ -+ reloc_page = qxl_bo_kmap_atomic_page(qdev, dst, dst_off & PAGE_MASK); -+ *(uint64_t *)(reloc_page + (dst_off & ~PAGE_MASK)) = qxl_bo_physical_address(qdev, -+ src, src_off); -+ qxl_bo_kunmap_atomic_page(qdev, dst, reloc_page); -+} -+ -+static void -+apply_surf_reloc(struct qxl_device *qdev, struct qxl_bo *dst, uint64_t dst_off, -+ struct qxl_bo *src) -+{ -+ uint32_t id = 0; -+ void *reloc_page; -+ -+ if (src && !src->is_primary) -+ id = src->surface_id; -+ -+ reloc_page = qxl_bo_kmap_atomic_page(qdev, dst, dst_off & PAGE_MASK); -+ *(uint32_t *)(reloc_page + (dst_off & ~PAGE_MASK)) = id; -+ qxl_bo_kunmap_atomic_page(qdev, dst, reloc_page); -+} -+ -+/* return holding the reference to this object */ -+struct qxl_bo *qxlhw_handle_to_bo(struct qxl_device *qdev, -+ struct drm_file *file_priv, uint64_t handle, -+ struct qxl_reloc_list *reloc_list) -+{ -+ struct drm_gem_object *gobj; -+ struct qxl_bo *qobj; -+ int ret; -+ -+ gobj = drm_gem_object_lookup(qdev->ddev, file_priv, handle); -+ if (!gobj) { -+ DRM_ERROR("bad bo handle %lld\n", handle); -+ return NULL; -+ } -+ qobj = gem_to_qxl_bo(gobj); -+ -+ ret = qxl_bo_list_add(reloc_list, qobj); -+ if (ret) -+ return NULL; -+ -+ return qobj; -+} -+ -+/* -+ * Usage of execbuffer: -+ * Relocations need to take into account the full QXLDrawable size. -+ * However, the command as passed from user space must *not* contain the initial -+ * QXLReleaseInfo struct (first XXX bytes) -+ */ -+int qxl_execbuffer_ioctl(struct drm_device *dev, void *data, -+ struct drm_file *file_priv) -+{ -+ struct qxl_device *qdev = dev->dev_private; -+ struct drm_qxl_execbuffer *execbuffer = data; -+ struct drm_qxl_command user_cmd; -+ int cmd_num; -+ struct qxl_bo *reloc_src_bo; -+ struct qxl_bo *reloc_dst_bo; -+ struct drm_qxl_reloc reloc; -+ void *fb_cmd; -+ int i, ret; -+ struct qxl_reloc_list reloc_list; -+ int unwritten; -+ uint32_t reloc_dst_offset; -+ INIT_LIST_HEAD(&reloc_list.bos); -+ -+ for (cmd_num = 0; cmd_num < execbuffer->commands_num; ++cmd_num) { -+ struct qxl_release *release; -+ struct qxl_bo *cmd_bo; -+ int release_type; -+ struct drm_qxl_command *commands = -+ (struct drm_qxl_command *)execbuffer->commands; -+ -+ if (DRM_COPY_FROM_USER(&user_cmd, &commands[cmd_num], -+ sizeof(user_cmd))) -+ return -EFAULT; -+ switch (user_cmd.type) { -+ case QXL_CMD_DRAW: -+ release_type = QXL_RELEASE_DRAWABLE; -+ break; -+ case QXL_CMD_SURFACE: -+ case QXL_CMD_CURSOR: -+ default: -+ DRM_DEBUG("Only draw commands in execbuffers\n"); -+ return -EINVAL; -+ break; -+ } -+ -+ if (user_cmd.command_size > PAGE_SIZE - sizeof(union qxl_release_info)) -+ return -EINVAL; -+ -+ ret = qxl_alloc_release_reserved(qdev, -+ sizeof(union qxl_release_info) + -+ user_cmd.command_size, -+ release_type, -+ &release, -+ &cmd_bo); -+ if (ret) -+ return ret; -+ -+ /* TODO copy slow path code from i915 */ -+ 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); -+ qxl_bo_kunmap_atomic_page(qdev, cmd_bo, fb_cmd); -+ if (unwritten) { -+ DRM_ERROR("got unwritten %d\n", unwritten); -+ qxl_release_unreserve(qdev, release); -+ qxl_release_free(qdev, release); -+ return -EFAULT; -+ } -+ -+ for (i = 0 ; i < user_cmd.relocs_num; ++i) { -+ if (DRM_COPY_FROM_USER(&reloc, -+ &((struct drm_qxl_reloc *)user_cmd.relocs)[i], -+ sizeof(reloc))) { -+ qxl_bo_list_unreserve(&reloc_list, true); -+ qxl_release_unreserve(qdev, release); -+ qxl_release_free(qdev, release); -+ return -EFAULT; -+ } -+ -+ /* add the bos to the list of bos to validate - -+ need to validate first then process relocs? */ -+ if (reloc.dst_handle) { -+ reloc_dst_bo = qxlhw_handle_to_bo(qdev, file_priv, -+ reloc.dst_handle, &reloc_list); -+ if (!reloc_dst_bo) { -+ qxl_bo_list_unreserve(&reloc_list, true); -+ qxl_release_unreserve(qdev, release); -+ qxl_release_free(qdev, release); -+ return -EINVAL; -+ } -+ reloc_dst_offset = 0; -+ } else { -+ reloc_dst_bo = cmd_bo; -+ reloc_dst_offset = release->release_offset; -+ } -+ -+ /* reserve and validate the reloc dst bo */ -+ if (reloc.reloc_type == QXL_RELOC_TYPE_BO || reloc.src_handle > 0) { -+ reloc_src_bo = -+ qxlhw_handle_to_bo(qdev, file_priv, -+ reloc.src_handle, &reloc_list); -+ if (!reloc_src_bo) { -+ if (reloc_dst_bo != cmd_bo) -+ drm_gem_object_unreference_unlocked(&reloc_dst_bo->gem_base); -+ qxl_bo_list_unreserve(&reloc_list, true); -+ qxl_release_unreserve(qdev, release); -+ qxl_release_free(qdev, release); -+ return -EINVAL; -+ } -+ } else -+ reloc_src_bo = NULL; -+ if (reloc.reloc_type == QXL_RELOC_TYPE_BO) { -+ apply_reloc(qdev, reloc_dst_bo, reloc_dst_offset + reloc.dst_offset, -+ reloc_src_bo, reloc.src_offset); -+ } else if (reloc.reloc_type == QXL_RELOC_TYPE_SURF) { -+ apply_surf_reloc(qdev, reloc_dst_bo, reloc_dst_offset + reloc.dst_offset, reloc_src_bo); -+ } else { -+ DRM_ERROR("unknown reloc type %d\n", reloc.reloc_type); -+ return -EINVAL; -+ } -+ -+ if (reloc_src_bo && reloc_src_bo != cmd_bo) { -+ qxl_release_add_res(qdev, release, reloc_src_bo); -+ drm_gem_object_unreference_unlocked(&reloc_src_bo->gem_base); -+ } -+ -+ if (reloc_dst_bo != cmd_bo) -+ drm_gem_object_unreference_unlocked(&reloc_dst_bo->gem_base); -+ } -+ qxl_fence_releaseable(qdev, release); -+ -+ ret = qxl_push_command_ring_release(qdev, release, user_cmd.type, true); -+ if (ret == -ERESTARTSYS) { -+ qxl_release_unreserve(qdev, release); -+ qxl_release_free(qdev, release); -+ qxl_bo_list_unreserve(&reloc_list, true); -+ return ret; -+ } -+ qxl_release_unreserve(qdev, release); -+ } -+ qxl_bo_list_unreserve(&reloc_list, 0); -+ return 0; -+} -+ -+int qxl_update_area_ioctl(struct drm_device *dev, void *data, -+ struct drm_file *file) -+{ -+ struct qxl_device *qdev = dev->dev_private; -+ struct drm_qxl_update_area *update_area = data; -+ struct qxl_rect area = {.left = update_area->left, -+ .top = update_area->top, -+ .right = update_area->right, -+ .bottom = update_area->bottom}; -+ int ret; -+ struct drm_gem_object *gobj = NULL; -+ struct qxl_bo *qobj = NULL; -+ -+ if (update_area->left >= update_area->right || -+ update_area->top >= update_area->bottom) -+ return -EINVAL; -+ -+ gobj = drm_gem_object_lookup(dev, file, update_area->handle); -+ if (gobj == NULL) -+ return -ENOENT; -+ -+ qobj = gem_to_qxl_bo(gobj); -+ -+ ret = qxl_bo_reserve(qobj, false); -+ if (ret) -+ goto out; -+ -+ if (!qobj->pin_count) { -+ ret = ttm_bo_validate(&qobj->tbo, &qobj->placement, -+ true, false); -+ if (unlikely(ret)) -+ goto out; -+ } -+ -+ ret = qxl_bo_check_id(qdev, qobj); -+ if (ret) -+ goto out2; -+ if (!qobj->surface_id) -+ DRM_ERROR("got update area for surface with no id %d\n", update_area->handle); -+ ret = qxl_io_update_area(qdev, qobj, &area); -+ -+out2: -+ qxl_bo_unreserve(qobj); -+ -+out: -+ drm_gem_object_unreference_unlocked(gobj); -+ return ret; -+} -+ -+static int qxl_getparam_ioctl(struct drm_device *dev, void *data, -+ struct drm_file *file_priv) -+{ -+ struct qxl_device *qdev = dev->dev_private; -+ struct drm_qxl_getparam *param = data; -+ -+ switch (param->param) { -+ case QXL_PARAM_NUM_SURFACES: -+ param->value = qdev->rom->n_surfaces; -+ break; -+ case QXL_PARAM_MAX_RELOCS: -+ param->value = QXL_MAX_RES; -+ break; -+ default: -+ return -EINVAL; -+ } -+ return 0; -+} -+ -+static int qxl_clientcap_ioctl(struct drm_device *dev, void *data, -+ struct drm_file *file_priv) -+{ -+ struct qxl_device *qdev = dev->dev_private; -+ struct drm_qxl_clientcap *param = data; -+ int byte, idx; -+ -+ byte = param->index / 8; -+ idx = param->index % 8; -+ -+ if (qdev->pdev->revision < 4) -+ return -ENOSYS; -+ -+ if (byte > 58) -+ return -ENOSYS; -+ -+ if (qdev->rom->client_capabilities[byte] & (1 << idx)) -+ return 0; -+ return -ENOSYS; -+} -+ -+static int qxl_alloc_surf_ioctl(struct drm_device *dev, void *data, -+ struct drm_file *file) -+{ -+ struct qxl_device *qdev = dev->dev_private; -+ struct drm_qxl_alloc_surf *param = data; -+ struct qxl_bo *qobj; -+ int handle; -+ int ret; -+ int size, actual_stride; -+ struct qxl_surface surf; -+ -+ /* work out size allocate bo with handle */ -+ actual_stride = param->stride < 0 ? -param->stride : param->stride; -+ size = actual_stride * param->height + actual_stride; -+ -+ surf.format = param->format; -+ surf.width = param->width; -+ surf.height = param->height; -+ surf.stride = param->stride; -+ surf.data = 0; -+ -+ ret = qxl_gem_object_create_with_handle(qdev, file, -+ QXL_GEM_DOMAIN_SURFACE, -+ size, -+ &surf, -+ &qobj, &handle); -+ if (ret) { -+ DRM_ERROR("%s: failed to create gem ret=%d\n", -+ __func__, ret); -+ return -ENOMEM; -+ } else -+ param->handle = handle; -+ return ret; -+} -+ -+struct drm_ioctl_desc qxl_ioctls[] = { -+ DRM_IOCTL_DEF_DRV(QXL_ALLOC, qxl_alloc_ioctl, DRM_AUTH|DRM_UNLOCKED), -+ -+ DRM_IOCTL_DEF_DRV(QXL_MAP, qxl_map_ioctl, DRM_AUTH|DRM_UNLOCKED), -+ -+ DRM_IOCTL_DEF_DRV(QXL_EXECBUFFER, qxl_execbuffer_ioctl, -+ DRM_AUTH|DRM_UNLOCKED), -+ DRM_IOCTL_DEF_DRV(QXL_UPDATE_AREA, qxl_update_area_ioctl, -+ DRM_AUTH|DRM_UNLOCKED), -+ DRM_IOCTL_DEF_DRV(QXL_GETPARAM, qxl_getparam_ioctl, -+ DRM_AUTH|DRM_UNLOCKED), -+ DRM_IOCTL_DEF_DRV(QXL_CLIENTCAP, qxl_clientcap_ioctl, -+ DRM_AUTH|DRM_UNLOCKED), -+ -+ DRM_IOCTL_DEF_DRV(QXL_ALLOC_SURF, qxl_alloc_surf_ioctl, -+ DRM_AUTH|DRM_UNLOCKED), -+}; -+ -+int qxl_max_ioctls = DRM_ARRAY_SIZE(qxl_ioctls); -diff --git a/drivers/gpu/drm/qxl/qxl_irq.c b/drivers/gpu/drm/qxl/qxl_irq.c -new file mode 100644 -index 0000000..21393dc ---- /dev/null -+++ b/drivers/gpu/drm/qxl/qxl_irq.c -@@ -0,0 +1,97 @@ -+/* -+ * Copyright 2013 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, sublicense, -+ * 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 above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * 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 NONINFRINGEMENT. IN NO EVENT SHALL -+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. -+ * -+ * Authors: Dave Airlie -+ * Alon Levy -+ */ -+ -+#include "qxl_drv.h" -+ -+irqreturn_t qxl_irq_handler(DRM_IRQ_ARGS) -+{ -+ struct drm_device *dev = (struct drm_device *) arg; -+ struct qxl_device *qdev = (struct qxl_device *)dev->dev_private; -+ uint32_t pending; -+ -+ pending = xchg(&qdev->ram_header->int_pending, 0); -+ -+ atomic_inc(&qdev->irq_received); -+ -+ if (pending & QXL_INTERRUPT_DISPLAY) { -+ atomic_inc(&qdev->irq_received_display); -+ wake_up_all(&qdev->display_event); -+ qxl_queue_garbage_collect(qdev, false); -+ } -+ if (pending & QXL_INTERRUPT_CURSOR) { -+ atomic_inc(&qdev->irq_received_cursor); -+ wake_up_all(&qdev->cursor_event); -+ } -+ if (pending & QXL_INTERRUPT_IO_CMD) { -+ atomic_inc(&qdev->irq_received_io_cmd); -+ wake_up_all(&qdev->io_cmd_event); -+ } -+ if (pending & QXL_INTERRUPT_ERROR) { -+ /* TODO: log it, reset device (only way to exit this condition) -+ * (do it a certain number of times, afterwards admit defeat, -+ * to avoid endless loops). -+ */ -+ qdev->irq_received_error++; -+ qxl_io_log(qdev, "%s: driver is in bug mode.\n", __func__); -+ } -+ if (pending & QXL_INTERRUPT_CLIENT_MONITORS_CONFIG) { -+ qxl_io_log(qdev, "QXL_INTERRUPT_CLIENT_MONITORS_CONFIG\n"); -+ schedule_work(&qdev->client_monitors_config_work); -+ } -+ qdev->ram_header->int_mask = QXL_INTERRUPT_MASK; -+ outb(0, qdev->io_base + QXL_IO_UPDATE_IRQ); -+ return IRQ_HANDLED; -+} -+ -+static void qxl_client_monitors_config_work_func(struct work_struct *work) -+{ -+ struct qxl_device *qdev = container_of(work, struct qxl_device, -+ client_monitors_config_work); -+ -+ qxl_display_read_client_monitors_config(qdev); -+} -+ -+int qxl_irq_init(struct qxl_device *qdev) -+{ -+ int ret; -+ -+ init_waitqueue_head(&qdev->display_event); -+ init_waitqueue_head(&qdev->cursor_event); -+ init_waitqueue_head(&qdev->io_cmd_event); -+ INIT_WORK(&qdev->client_monitors_config_work, -+ qxl_client_monitors_config_work_func); -+ atomic_set(&qdev->irq_received, 0); -+ atomic_set(&qdev->irq_received_display, 0); -+ atomic_set(&qdev->irq_received_cursor, 0); -+ atomic_set(&qdev->irq_received_io_cmd, 0); -+ qdev->irq_received_error = 0; -+ ret = drm_irq_install(qdev->ddev); -+ qdev->ram_header->int_mask = QXL_INTERRUPT_MASK; -+ if (unlikely(ret != 0)) { -+ DRM_ERROR("Failed installing irq: %d\n", ret); -+ return 1; -+ } -+ return 0; -+} -diff --git a/drivers/gpu/drm/qxl/qxl_kms.c b/drivers/gpu/drm/qxl/qxl_kms.c -new file mode 100644 -index 0000000..036e0de ---- /dev/null -+++ b/drivers/gpu/drm/qxl/qxl_kms.c -@@ -0,0 +1,302 @@ -+/* -+ * Copyright 2013 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, sublicense, -+ * 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 above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * 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 NONINFRINGEMENT. IN NO EVENT SHALL -+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. -+ * -+ * Authors: Dave Airlie -+ * Alon Levy -+ */ -+ -+#include "qxl_drv.h" -+#include "qxl_object.h" -+ -+#include -+ -+int qxl_log_level; -+ -+static void qxl_dump_mode(struct qxl_device *qdev, void *p) -+{ -+ struct qxl_mode *m = p; -+ DRM_DEBUG_KMS("%d: %dx%d %d bits, stride %d, %dmm x %dmm, orientation %d\n", -+ m->id, m->x_res, m->y_res, m->bits, m->stride, m->x_mili, -+ m->y_mili, m->orientation); -+} -+ -+static bool qxl_check_device(struct qxl_device *qdev) -+{ -+ struct qxl_rom *rom = qdev->rom; -+ int mode_offset; -+ int i; -+ -+ if (rom->magic != 0x4f525851) { -+ DRM_ERROR("bad rom signature %x\n", rom->magic); -+ return false; -+ } -+ -+ DRM_INFO("Device Version %d.%d\n", rom->id, rom->update_id); -+ DRM_INFO("Compression level %d log level %d\n", rom->compression_level, -+ rom->log_level); -+ DRM_INFO("Currently using mode #%d, list at 0x%x\n", -+ rom->mode, rom->modes_offset); -+ DRM_INFO("%d io pages at offset 0x%x\n", -+ rom->num_io_pages, rom->pages_offset); -+ DRM_INFO("%d byte draw area at offset 0x%x\n", -+ rom->surface0_area_size, rom->draw_area_offset); -+ -+ qdev->vram_size = rom->surface0_area_size; -+ DRM_INFO("RAM header offset: 0x%x\n", rom->ram_header_offset); -+ -+ mode_offset = rom->modes_offset / 4; -+ qdev->mode_info.num_modes = ((u32 *)rom)[mode_offset]; -+ DRM_INFO("rom modes offset 0x%x for %d modes\n", rom->modes_offset, -+ qdev->mode_info.num_modes); -+ qdev->mode_info.modes = (void *)((uint32_t *)rom + mode_offset + 1); -+ for (i = 0; i < qdev->mode_info.num_modes; i++) -+ qxl_dump_mode(qdev, qdev->mode_info.modes + i); -+ return true; -+} -+ -+static uint8_t setup_slot(struct qxl_device *qdev, uint8_t slot_index_offset, -+ unsigned long start_phys_addr, unsigned long end_phys_addr) -+{ -+ uint64_t high_bits; -+ struct qxl_memslot *slot; -+ uint8_t slot_index; -+ struct qxl_ram_header *ram_header = qdev->ram_header; -+ -+ slot_index = qdev->rom->slots_start + slot_index_offset; -+ slot = &qdev->mem_slots[slot_index]; -+ slot->start_phys_addr = start_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; -+ qxl_io_memslot_add(qdev, slot_index); -+ slot->generation = qdev->rom->slot_generation; -+ high_bits = slot_index << qdev->slot_gen_bits; -+ high_bits |= slot->generation; -+ high_bits <<= (64 - (qdev->slot_gen_bits + qdev->slot_id_bits)); -+ slot->high_bits = high_bits; -+ return slot_index; -+} -+ -+static void qxl_gc_work(struct work_struct *work) -+{ -+ struct qxl_device *qdev = container_of(work, struct qxl_device, gc_work); -+ qxl_garbage_collect(qdev); -+} -+ -+int qxl_device_init(struct qxl_device *qdev, -+ struct drm_device *ddev, -+ struct pci_dev *pdev, -+ unsigned long flags) -+{ -+ int r; -+ -+ qdev->dev = &pdev->dev; -+ qdev->ddev = ddev; -+ qdev->pdev = pdev; -+ qdev->flags = flags; -+ -+ mutex_init(&qdev->gem.mutex); -+ mutex_init(&qdev->update_area_mutex); -+ mutex_init(&qdev->release_mutex); -+ mutex_init(&qdev->surf_evict_mutex); -+ INIT_LIST_HEAD(&qdev->gem.objects); -+ -+ qdev->rom_base = pci_resource_start(pdev, 2); -+ qdev->rom_size = pci_resource_len(pdev, 2); -+ qdev->vram_base = pci_resource_start(pdev, 0); -+ qdev->surfaceram_base = pci_resource_start(pdev, 1); -+ qdev->surfaceram_size = pci_resource_len(pdev, 1); -+ qdev->io_base = pci_resource_start(pdev, 3); -+ -+ qdev->vram_mapping = io_mapping_create_wc(qdev->vram_base, pci_resource_len(pdev, 0)); -+ qdev->surface_mapping = io_mapping_create_wc(qdev->surfaceram_base, qdev->surfaceram_size); -+ DRM_DEBUG_KMS("qxl: vram %p-%p(%dM %dk), surface %p-%p(%dM %dk)\n", -+ (void *)qdev->vram_base, (void *)pci_resource_end(pdev, 0), -+ (int)pci_resource_len(pdev, 0) / 1024 / 1024, -+ (int)pci_resource_len(pdev, 0) / 1024, -+ (void *)qdev->surfaceram_base, -+ (void *)pci_resource_end(pdev, 1), -+ (int)qdev->surfaceram_size / 1024 / 1024, -+ (int)qdev->surfaceram_size / 1024); -+ -+ qdev->rom = ioremap(qdev->rom_base, qdev->rom_size); -+ if (!qdev->rom) { -+ pr_err("Unable to ioremap ROM\n"); -+ return -ENOMEM; -+ } -+ -+ qxl_check_device(qdev); -+ -+ r = qxl_bo_init(qdev); -+ if (r) { -+ DRM_ERROR("bo init failed %d\n", r); -+ return r; -+ } -+ -+ qdev->ram_header = ioremap(qdev->vram_base + -+ qdev->rom->ram_header_offset, -+ sizeof(*qdev->ram_header)); -+ -+ qdev->command_ring = qxl_ring_create(&(qdev->ram_header->cmd_ring_hdr), -+ sizeof(struct qxl_command), -+ QXL_COMMAND_RING_SIZE, -+ qdev->io_base + QXL_IO_NOTIFY_CMD, -+ false, -+ &qdev->display_event); -+ -+ qdev->cursor_ring = qxl_ring_create( -+ &(qdev->ram_header->cursor_ring_hdr), -+ sizeof(struct qxl_command), -+ QXL_CURSOR_RING_SIZE, -+ qdev->io_base + QXL_IO_NOTIFY_CMD, -+ false, -+ &qdev->cursor_event); -+ -+ qdev->release_ring = qxl_ring_create( -+ &(qdev->ram_header->release_ring_hdr), -+ sizeof(uint64_t), -+ QXL_RELEASE_RING_SIZE, 0, true, -+ NULL); -+ -+ /* TODO - slot initialization should happen on reset. where is our -+ * reset handler? */ -+ qdev->n_mem_slots = qdev->rom->slots_end; -+ qdev->slot_gen_bits = qdev->rom->slot_gen_bits; -+ qdev->slot_id_bits = qdev->rom->slot_id_bits; -+ qdev->va_slot_mask = -+ (~(uint64_t)0) >> (qdev->slot_id_bits + qdev->slot_gen_bits); -+ -+ qdev->mem_slots = -+ kmalloc(qdev->n_mem_slots * sizeof(struct qxl_memslot), -+ GFP_KERNEL); -+ -+ idr_init(&qdev->release_idr); -+ spin_lock_init(&qdev->release_idr_lock); -+ -+ idr_init(&qdev->surf_id_idr); -+ spin_lock_init(&qdev->surf_id_idr_lock); -+ -+ mutex_init(&qdev->async_io_mutex); -+ -+ /* reset the device into a known state - no memslots, no primary -+ * created, no surfaces. */ -+ qxl_io_reset(qdev); -+ -+ /* must initialize irq before first async io - slot creation */ -+ r = qxl_irq_init(qdev); -+ if (r) -+ return r; -+ -+ /* -+ * Note that virtual is surface0. We rely on the single ioremap done -+ * before. -+ */ -+ qdev->main_mem_slot = setup_slot(qdev, 0, -+ (unsigned long)qdev->vram_base, -+ (unsigned long)qdev->vram_base + qdev->rom->ram_header_offset); -+ qdev->surfaces_mem_slot = setup_slot(qdev, 1, -+ (unsigned long)qdev->surfaceram_base, -+ (unsigned long)qdev->surfaceram_base + qdev->surfaceram_size); -+ DRM_INFO("main mem slot %d [%lx,%x)\n", -+ qdev->main_mem_slot, -+ (unsigned long)qdev->vram_base, qdev->rom->ram_header_offset); -+ -+ -+ qdev->gc_queue = create_singlethread_workqueue("qxl_gc"); -+ INIT_WORK(&qdev->gc_work, qxl_gc_work); -+ -+ r = qxl_fb_init(qdev); -+ if (r) -+ return r; -+ -+ return 0; -+} -+ -+void qxl_device_fini(struct qxl_device *qdev) -+{ -+ if (qdev->current_release_bo[0]) -+ qxl_bo_unref(&qdev->current_release_bo[0]); -+ if (qdev->current_release_bo[1]) -+ qxl_bo_unref(&qdev->current_release_bo[1]); -+ flush_workqueue(qdev->gc_queue); -+ destroy_workqueue(qdev->gc_queue); -+ qdev->gc_queue = NULL; -+ -+ qxl_ring_free(qdev->command_ring); -+ qxl_ring_free(qdev->cursor_ring); -+ qxl_ring_free(qdev->release_ring); -+ qxl_bo_fini(qdev); -+ io_mapping_free(qdev->surface_mapping); -+ io_mapping_free(qdev->vram_mapping); -+ iounmap(qdev->ram_header); -+ iounmap(qdev->rom); -+ qdev->rom = NULL; -+ qdev->mode_info.modes = NULL; -+ qdev->mode_info.num_modes = 0; -+ qxl_debugfs_remove_files(qdev); -+} -+ -+int qxl_driver_unload(struct drm_device *dev) -+{ -+ struct qxl_device *qdev = dev->dev_private; -+ -+ if (qdev == NULL) -+ return 0; -+ qxl_modeset_fini(qdev); -+ qxl_device_fini(qdev); -+ -+ kfree(qdev); -+ dev->dev_private = NULL; -+ return 0; -+} -+ -+int qxl_driver_load(struct drm_device *dev, unsigned long flags) -+{ -+ struct qxl_device *qdev; -+ int r; -+ -+ /* require kms */ -+ if (!drm_core_check_feature(dev, DRIVER_MODESET)) -+ return -ENODEV; -+ -+ qdev = kzalloc(sizeof(struct qxl_device), GFP_KERNEL); -+ if (qdev == NULL) -+ return -ENOMEM; -+ -+ dev->dev_private = qdev; -+ -+ r = qxl_device_init(qdev, dev, dev->pdev, flags); -+ if (r) -+ goto out; -+ -+ r = qxl_modeset_init(qdev); -+ if (r) { -+ qxl_driver_unload(dev); -+ goto out; -+ } -+ -+ return 0; -+out: -+ kfree(qdev); -+ return r; -+} -+ -+ -diff --git a/drivers/gpu/drm/qxl/qxl_object.c b/drivers/gpu/drm/qxl/qxl_object.c -new file mode 100644 -index 0000000..51efb94 ---- /dev/null -+++ b/drivers/gpu/drm/qxl/qxl_object.c -@@ -0,0 +1,365 @@ -+/* -+ * Copyright 2013 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, sublicense, -+ * 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 above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * 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 NONINFRINGEMENT. IN NO EVENT SHALL -+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. -+ * -+ * Authors: Dave Airlie -+ * Alon Levy -+ */ -+ -+#include "qxl_drv.h" -+#include "qxl_object.h" -+ -+#include -+static void qxl_ttm_bo_destroy(struct ttm_buffer_object *tbo) -+{ -+ struct qxl_bo *bo; -+ struct qxl_device *qdev; -+ -+ bo = container_of(tbo, struct qxl_bo, tbo); -+ qdev = (struct qxl_device *)bo->gem_base.dev->dev_private; -+ -+ qxl_surface_evict(qdev, bo, false); -+ qxl_fence_fini(&bo->fence); -+ mutex_lock(&qdev->gem.mutex); -+ list_del_init(&bo->list); -+ mutex_unlock(&qdev->gem.mutex); -+ drm_gem_object_release(&bo->gem_base); -+ kfree(bo); -+} -+ -+bool qxl_ttm_bo_is_qxl_bo(struct ttm_buffer_object *bo) -+{ -+ if (bo->destroy == &qxl_ttm_bo_destroy) -+ return true; -+ return false; -+} -+ -+void qxl_ttm_placement_from_domain(struct qxl_bo *qbo, u32 domain) -+{ -+ u32 c = 0; -+ -+ qbo->placement.fpfn = 0; -+ qbo->placement.lpfn = 0; -+ qbo->placement.placement = qbo->placements; -+ qbo->placement.busy_placement = qbo->placements; -+ if (domain & QXL_GEM_DOMAIN_VRAM) -+ qbo->placements[c++] = TTM_PL_FLAG_CACHED | TTM_PL_FLAG_VRAM; -+ if (domain & QXL_GEM_DOMAIN_SURFACE) -+ qbo->placements[c++] = TTM_PL_FLAG_CACHED | TTM_PL_FLAG_PRIV0; -+ if (domain & QXL_GEM_DOMAIN_CPU) -+ qbo->placements[c++] = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM; -+ if (!c) -+ qbo->placements[c++] = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM; -+ qbo->placement.num_placement = c; -+ qbo->placement.num_busy_placement = c; -+} -+ -+ -+int qxl_bo_create(struct qxl_device *qdev, -+ unsigned long size, bool kernel, u32 domain, -+ struct qxl_surface *surf, -+ struct qxl_bo **bo_ptr) -+{ -+ struct qxl_bo *bo; -+ enum ttm_bo_type type; -+ int r; -+ -+ if (unlikely(qdev->mman.bdev.dev_mapping == NULL)) -+ qdev->mman.bdev.dev_mapping = qdev->ddev->dev_mapping; -+ if (kernel) -+ type = ttm_bo_type_kernel; -+ else -+ type = ttm_bo_type_device; -+ *bo_ptr = NULL; -+ bo = kzalloc(sizeof(struct qxl_bo), GFP_KERNEL); -+ if (bo == NULL) -+ return -ENOMEM; -+ size = roundup(size, PAGE_SIZE); -+ r = drm_gem_object_init(qdev->ddev, &bo->gem_base, size); -+ if (unlikely(r)) { -+ kfree(bo); -+ return r; -+ } -+ bo->gem_base.driver_private = NULL; -+ bo->type = domain; -+ bo->pin_count = 0; -+ bo->surface_id = 0; -+ qxl_fence_init(qdev, &bo->fence); -+ INIT_LIST_HEAD(&bo->list); -+ atomic_set(&bo->reserve_count, 0); -+ if (surf) -+ bo->surf = *surf; -+ -+ qxl_ttm_placement_from_domain(bo, domain); -+ -+ r = ttm_bo_init(&qdev->mman.bdev, &bo->tbo, size, type, -+ &bo->placement, 0, !kernel, NULL, size, -+ NULL, &qxl_ttm_bo_destroy); -+ if (unlikely(r != 0)) { -+ if (r != -ERESTARTSYS) -+ dev_err(qdev->dev, -+ "object_init failed for (%lu, 0x%08X)\n", -+ size, domain); -+ return r; -+ } -+ *bo_ptr = bo; -+ return 0; -+} -+ -+int qxl_bo_kmap(struct qxl_bo *bo, void **ptr) -+{ -+ bool is_iomem; -+ int r; -+ -+ if (bo->kptr) { -+ if (ptr) -+ *ptr = bo->kptr; -+ return 0; -+ } -+ r = ttm_bo_kmap(&bo->tbo, 0, bo->tbo.num_pages, &bo->kmap); -+ if (r) -+ return r; -+ bo->kptr = ttm_kmap_obj_virtual(&bo->kmap, &is_iomem); -+ if (ptr) -+ *ptr = bo->kptr; -+ return 0; -+} -+ -+void *qxl_bo_kmap_atomic_page(struct qxl_device *qdev, -+ struct qxl_bo *bo, int page_offset) -+{ -+ struct ttm_mem_type_manager *man = &bo->tbo.bdev->man[bo->tbo.mem.mem_type]; -+ void *rptr; -+ int ret; -+ struct io_mapping *map; -+ -+ if (bo->tbo.mem.mem_type == TTM_PL_VRAM) -+ map = qdev->vram_mapping; -+ else if (bo->tbo.mem.mem_type == TTM_PL_PRIV0) -+ map = qdev->surface_mapping; -+ else -+ goto fallback; -+ -+ (void) ttm_mem_io_lock(man, false); -+ ret = ttm_mem_io_reserve(bo->tbo.bdev, &bo->tbo.mem); -+ ttm_mem_io_unlock(man); -+ -+ return io_mapping_map_atomic_wc(map, bo->tbo.mem.bus.offset + page_offset); -+fallback: -+ if (bo->kptr) { -+ rptr = bo->kptr + (page_offset * PAGE_SIZE); -+ return rptr; -+ } -+ -+ ret = qxl_bo_kmap(bo, &rptr); -+ if (ret) -+ return NULL; -+ -+ rptr += page_offset * PAGE_SIZE; -+ return rptr; -+} -+ -+void qxl_bo_kunmap(struct qxl_bo *bo) -+{ -+ if (bo->kptr == NULL) -+ return; -+ bo->kptr = NULL; -+ ttm_bo_kunmap(&bo->kmap); -+} -+ -+void qxl_bo_kunmap_atomic_page(struct qxl_device *qdev, -+ struct qxl_bo *bo, void *pmap) -+{ -+ struct ttm_mem_type_manager *man = &bo->tbo.bdev->man[bo->tbo.mem.mem_type]; -+ struct io_mapping *map; -+ -+ if (bo->tbo.mem.mem_type == TTM_PL_VRAM) -+ map = qdev->vram_mapping; -+ else if (bo->tbo.mem.mem_type == TTM_PL_PRIV0) -+ map = qdev->surface_mapping; -+ else -+ goto fallback; -+ -+ io_mapping_unmap_atomic(pmap); -+ -+ (void) ttm_mem_io_lock(man, false); -+ ttm_mem_io_free(bo->tbo.bdev, &bo->tbo.mem); -+ ttm_mem_io_unlock(man); -+ return ; -+ fallback: -+ qxl_bo_kunmap(bo); -+} -+ -+void qxl_bo_unref(struct qxl_bo **bo) -+{ -+ struct ttm_buffer_object *tbo; -+ -+ if ((*bo) == NULL) -+ return; -+ tbo = &((*bo)->tbo); -+ ttm_bo_unref(&tbo); -+ if (tbo == NULL) -+ *bo = NULL; -+} -+ -+struct qxl_bo *qxl_bo_ref(struct qxl_bo *bo) -+{ -+ ttm_bo_reference(&bo->tbo); -+ return bo; -+} -+ -+int qxl_bo_pin(struct qxl_bo *bo, u32 domain, u64 *gpu_addr) -+{ -+ struct qxl_device *qdev = (struct qxl_device *)bo->gem_base.dev->dev_private; -+ int r, i; -+ -+ if (bo->pin_count) { -+ bo->pin_count++; -+ if (gpu_addr) -+ *gpu_addr = qxl_bo_gpu_offset(bo); -+ return 0; -+ } -+ qxl_ttm_placement_from_domain(bo, domain); -+ for (i = 0; i < bo->placement.num_placement; i++) -+ bo->placements[i] |= TTM_PL_FLAG_NO_EVICT; -+ r = ttm_bo_validate(&bo->tbo, &bo->placement, false, false); -+ if (likely(r == 0)) { -+ bo->pin_count = 1; -+ if (gpu_addr != NULL) -+ *gpu_addr = qxl_bo_gpu_offset(bo); -+ } -+ if (unlikely(r != 0)) -+ dev_err(qdev->dev, "%p pin failed\n", bo); -+ return r; -+} -+ -+int qxl_bo_unpin(struct qxl_bo *bo) -+{ -+ struct qxl_device *qdev = (struct qxl_device *)bo->gem_base.dev->dev_private; -+ int r, i; -+ -+ if (!bo->pin_count) { -+ dev_warn(qdev->dev, "%p unpin not necessary\n", bo); -+ return 0; -+ } -+ bo->pin_count--; -+ if (bo->pin_count) -+ return 0; -+ for (i = 0; i < bo->placement.num_placement; i++) -+ bo->placements[i] &= ~TTM_PL_FLAG_NO_EVICT; -+ r = ttm_bo_validate(&bo->tbo, &bo->placement, false, false); -+ if (unlikely(r != 0)) -+ dev_err(qdev->dev, "%p validate failed for unpin\n", bo); -+ return r; -+} -+ -+void qxl_bo_force_delete(struct qxl_device *qdev) -+{ -+ struct qxl_bo *bo, *n; -+ -+ if (list_empty(&qdev->gem.objects)) -+ return; -+ dev_err(qdev->dev, "Userspace still has active objects !\n"); -+ list_for_each_entry_safe(bo, n, &qdev->gem.objects, list) { -+ mutex_lock(&qdev->ddev->struct_mutex); -+ dev_err(qdev->dev, "%p %p %lu %lu force free\n", -+ &bo->gem_base, bo, (unsigned long)bo->gem_base.size, -+ *((unsigned long *)&bo->gem_base.refcount)); -+ mutex_lock(&qdev->gem.mutex); -+ list_del_init(&bo->list); -+ mutex_unlock(&qdev->gem.mutex); -+ /* this should unref the ttm bo */ -+ drm_gem_object_unreference(&bo->gem_base); -+ mutex_unlock(&qdev->ddev->struct_mutex); -+ } -+} -+ -+int qxl_bo_init(struct qxl_device *qdev) -+{ -+ return qxl_ttm_init(qdev); -+} -+ -+void qxl_bo_fini(struct qxl_device *qdev) -+{ -+ qxl_ttm_fini(qdev); -+} -+ -+int qxl_bo_check_id(struct qxl_device *qdev, struct qxl_bo *bo) -+{ -+ int ret; -+ if (bo->type == QXL_GEM_DOMAIN_SURFACE && bo->surface_id == 0) { -+ /* allocate a surface id for this surface now */ -+ ret = qxl_surface_id_alloc(qdev, bo); -+ if (ret) -+ return ret; -+ -+ ret = qxl_hw_surface_alloc(qdev, bo, NULL); -+ if (ret) -+ return ret; -+ } -+ return 0; -+} -+ -+void qxl_bo_list_unreserve(struct qxl_reloc_list *reloc_list, bool failed) -+{ -+ struct qxl_bo_list *entry, *sf; -+ -+ list_for_each_entry_safe(entry, sf, &reloc_list->bos, lhead) { -+ qxl_bo_unreserve(entry->bo); -+ list_del(&entry->lhead); -+ kfree(entry); -+ } -+} -+ -+int qxl_bo_list_add(struct qxl_reloc_list *reloc_list, struct qxl_bo *bo) -+{ -+ struct qxl_bo_list *entry; -+ int ret; -+ -+ list_for_each_entry(entry, &reloc_list->bos, lhead) { -+ if (entry->bo == bo) -+ return 0; -+ } -+ -+ entry = kmalloc(sizeof(struct qxl_bo_list), GFP_KERNEL); -+ if (!entry) -+ return -ENOMEM; -+ -+ entry->bo = bo; -+ list_add(&entry->lhead, &reloc_list->bos); -+ -+ ret = qxl_bo_reserve(bo, false); -+ if (ret) -+ return ret; -+ -+ if (!bo->pin_count) { -+ qxl_ttm_placement_from_domain(bo, bo->type); -+ ret = ttm_bo_validate(&bo->tbo, &bo->placement, -+ true, false); -+ if (ret) -+ return ret; -+ } -+ -+ /* allocate a surface for reserved + validated buffers */ -+ ret = qxl_bo_check_id(bo->gem_base.dev->dev_private, bo); -+ if (ret) -+ return ret; -+ return 0; -+} -diff --git a/drivers/gpu/drm/qxl/qxl_object.h b/drivers/gpu/drm/qxl/qxl_object.h -new file mode 100644 -index 0000000..b4fd89f ---- /dev/null -+++ b/drivers/gpu/drm/qxl/qxl_object.h -@@ -0,0 +1,112 @@ -+/* -+ * Copyright 2013 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, sublicense, -+ * 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 above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * 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 NONINFRINGEMENT. IN NO EVENT SHALL -+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. -+ * -+ * Authors: Dave Airlie -+ * Alon Levy -+ */ -+#ifndef QXL_OBJECT_H -+#define QXL_OBJECT_H -+ -+#include "qxl_drv.h" -+ -+static inline int qxl_bo_reserve(struct qxl_bo *bo, bool no_wait) -+{ -+ int r; -+ -+ r = ttm_bo_reserve(&bo->tbo, true, no_wait, false, 0); -+ if (unlikely(r != 0)) { -+ if (r != -ERESTARTSYS) { -+ struct qxl_device *qdev = (struct qxl_device *)bo->gem_base.dev->dev_private; -+ dev_err(qdev->dev, "%p reserve failed\n", bo); -+ } -+ return r; -+ } -+ return 0; -+} -+ -+static inline void qxl_bo_unreserve(struct qxl_bo *bo) -+{ -+ ttm_bo_unreserve(&bo->tbo); -+} -+ -+static inline u64 qxl_bo_gpu_offset(struct qxl_bo *bo) -+{ -+ return bo->tbo.offset; -+} -+ -+static inline unsigned long qxl_bo_size(struct qxl_bo *bo) -+{ -+ return bo->tbo.num_pages << PAGE_SHIFT; -+} -+ -+static inline bool qxl_bo_is_reserved(struct qxl_bo *bo) -+{ -+ return !!atomic_read(&bo->tbo.reserved); -+} -+ -+static inline u64 qxl_bo_mmap_offset(struct qxl_bo *bo) -+{ -+ return bo->tbo.addr_space_offset; -+} -+ -+static inline int qxl_bo_wait(struct qxl_bo *bo, u32 *mem_type, -+ bool no_wait) -+{ -+ int r; -+ -+ r = ttm_bo_reserve(&bo->tbo, true, no_wait, false, 0); -+ if (unlikely(r != 0)) { -+ if (r != -ERESTARTSYS) { -+ struct qxl_device *qdev = (struct qxl_device *)bo->gem_base.dev->dev_private; -+ dev_err(qdev->dev, "%p reserve failed for wait\n", -+ bo); -+ } -+ return r; -+ } -+ spin_lock(&bo->tbo.bdev->fence_lock); -+ if (mem_type) -+ *mem_type = bo->tbo.mem.mem_type; -+ if (bo->tbo.sync_obj) -+ r = ttm_bo_wait(&bo->tbo, true, true, no_wait); -+ spin_unlock(&bo->tbo.bdev->fence_lock); -+ ttm_bo_unreserve(&bo->tbo); -+ return r; -+} -+ -+extern int qxl_bo_create(struct qxl_device *qdev, -+ unsigned long size, -+ bool kernel, u32 domain, -+ struct qxl_surface *surf, -+ struct qxl_bo **bo_ptr); -+extern int qxl_bo_kmap(struct qxl_bo *bo, void **ptr); -+extern void qxl_bo_kunmap(struct qxl_bo *bo); -+void *qxl_bo_kmap_atomic_page(struct qxl_device *qdev, struct qxl_bo *bo, int page_offset); -+void qxl_bo_kunmap_atomic_page(struct qxl_device *qdev, struct qxl_bo *bo, void *map); -+extern struct qxl_bo *qxl_bo_ref(struct qxl_bo *bo); -+extern void qxl_bo_unref(struct qxl_bo **bo); -+extern int qxl_bo_pin(struct qxl_bo *bo, u32 domain, u64 *gpu_addr); -+extern int qxl_bo_unpin(struct qxl_bo *bo); -+extern void qxl_ttm_placement_from_domain(struct qxl_bo *qbo, u32 domain); -+extern bool qxl_ttm_bo_is_qxl_bo(struct ttm_buffer_object *bo); -+ -+extern int qxl_bo_list_add(struct qxl_reloc_list *reloc_list, struct qxl_bo *bo); -+extern void qxl_bo_list_unreserve(struct qxl_reloc_list *reloc_list, bool failed); -+#endif -diff --git a/drivers/gpu/drm/qxl/qxl_release.c b/drivers/gpu/drm/qxl/qxl_release.c -new file mode 100644 -index 0000000..1600781 ---- /dev/null -+++ b/drivers/gpu/drm/qxl/qxl_release.c -@@ -0,0 +1,307 @@ -+/* -+ * Copyright 2011 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 -+ * on 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 above copyright notice and this permission notice (including the next -+ * paragraph) shall be included in all copies or substantial portions of the -+ * Software. -+ * -+ * 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 AUTHORS 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. -+ */ -+#include "qxl_drv.h" -+#include "qxl_object.h" -+ -+/* -+ * drawable cmd cache - allocate a bunch of VRAM pages, suballocate -+ * into 256 byte chunks for now - gives 16 cmds per page. -+ * -+ * use an ida to index into the chunks? -+ */ -+/* manage releaseables */ -+/* stack them 16 high for now -drawable object is 191 */ -+#define RELEASE_SIZE 256 -+#define RELEASES_PER_BO (4096 / RELEASE_SIZE) -+/* put an alloc/dealloc surface cmd into one bo and round up to 128 */ -+#define SURFACE_RELEASE_SIZE 128 -+#define SURFACE_RELEASES_PER_BO (4096 / SURFACE_RELEASE_SIZE) -+ -+static const int release_size_per_bo[] = { RELEASE_SIZE, SURFACE_RELEASE_SIZE, RELEASE_SIZE }; -+static const int releases_per_bo[] = { RELEASES_PER_BO, SURFACE_RELEASES_PER_BO, RELEASES_PER_BO }; -+uint64_t -+qxl_release_alloc(struct qxl_device *qdev, int type, -+ struct qxl_release **ret) -+{ -+ struct qxl_release *release; -+ int handle = 0; -+ size_t size = sizeof(*release); -+ int idr_ret; -+ -+ release = kmalloc(size, GFP_KERNEL); -+ if (!release) { -+ DRM_ERROR("Out of memory\n"); -+ return 0; -+ } -+ release->type = type; -+ release->bo_count = 0; -+ release->release_offset = 0; -+ release->surface_release_id = 0; -+again: -+ if (idr_pre_get(&qdev->release_idr, GFP_KERNEL) == 0) { -+ DRM_ERROR("Out of memory for release idr\n"); -+ kfree(release); -+ goto release_fail; -+ } -+ spin_lock(&qdev->release_idr_lock); -+ idr_ret = idr_get_new_above(&qdev->release_idr, release, 1, &handle); -+ spin_unlock(&qdev->release_idr_lock); -+ if (idr_ret == -EAGAIN) -+ goto again; -+ if (ret) -+ *ret = release; -+ QXL_INFO(qdev, "allocated release %lld\n", handle); -+ release->id = handle; -+release_fail: -+ -+ return handle; -+} -+ -+void -+qxl_release_free(struct qxl_device *qdev, -+ struct qxl_release *release) -+{ -+ int i; -+ -+ QXL_INFO(qdev, "release %d, type %d, %d bos\n", release->id, -+ release->type, release->bo_count); -+ -+ if (release->surface_release_id) -+ qxl_surface_id_dealloc(qdev, release->surface_release_id); -+ -+ for (i = 0 ; i < release->bo_count; ++i) { -+ QXL_INFO(qdev, "release %llx\n", -+ release->bos[i]->tbo.addr_space_offset -+ - DRM_FILE_OFFSET); -+ qxl_fence_remove_release(&release->bos[i]->fence, release->id); -+ qxl_bo_unref(&release->bos[i]); -+ } -+ spin_lock(&qdev->release_idr_lock); -+ idr_remove(&qdev->release_idr, release->id); -+ spin_unlock(&qdev->release_idr_lock); -+ kfree(release); -+} -+ -+void -+qxl_release_add_res(struct qxl_device *qdev, struct qxl_release *release, -+ struct qxl_bo *bo) -+{ -+ int i; -+ for (i = 0; i < release->bo_count; i++) -+ if (release->bos[i] == bo) -+ return; -+ -+ if (release->bo_count >= QXL_MAX_RES) { -+ DRM_ERROR("exceeded max resource on a qxl_release item\n"); -+ return; -+ } -+ release->bos[release->bo_count++] = qxl_bo_ref(bo); -+} -+ -+int qxl_release_bo_alloc(struct qxl_device *qdev, -+ struct qxl_bo **bo) -+{ -+ int ret; -+ ret = qxl_bo_create(qdev, PAGE_SIZE, false, QXL_GEM_DOMAIN_VRAM, NULL, -+ bo); -+ return ret; -+} -+ -+int qxl_release_reserve(struct qxl_device *qdev, -+ struct qxl_release *release, bool no_wait) -+{ -+ int ret; -+ if (atomic_inc_return(&release->bos[0]->reserve_count) == 1) { -+ ret = qxl_bo_reserve(release->bos[0], no_wait); -+ if (ret) -+ return ret; -+ } -+ return 0; -+} -+ -+void qxl_release_unreserve(struct qxl_device *qdev, -+ struct qxl_release *release) -+{ -+ if (atomic_dec_and_test(&release->bos[0]->reserve_count)) -+ qxl_bo_unreserve(release->bos[0]); -+} -+ -+int qxl_alloc_surface_release_reserved(struct qxl_device *qdev, -+ enum qxl_surface_cmd_type surface_cmd_type, -+ struct qxl_release *create_rel, -+ struct qxl_release **release) -+{ -+ int ret; -+ -+ if (surface_cmd_type == QXL_SURFACE_CMD_DESTROY && create_rel) { -+ int idr_ret; -+ struct qxl_bo *bo; -+ union qxl_release_info *info; -+ -+ /* stash the release after the create command */ -+ idr_ret = qxl_release_alloc(qdev, QXL_RELEASE_SURFACE_CMD, release); -+ bo = qxl_bo_ref(create_rel->bos[0]); -+ -+ (*release)->release_offset = create_rel->release_offset + 64; -+ -+ qxl_release_add_res(qdev, *release, bo); -+ -+ ret = qxl_release_reserve(qdev, *release, false); -+ if (ret) { -+ DRM_ERROR("release reserve failed\n"); -+ goto out_unref; -+ } -+ info = qxl_release_map(qdev, *release); -+ info->id = idr_ret; -+ qxl_release_unmap(qdev, *release, info); -+ -+ -+out_unref: -+ qxl_bo_unref(&bo); -+ return ret; -+ } -+ -+ return qxl_alloc_release_reserved(qdev, sizeof(struct qxl_surface_cmd), -+ QXL_RELEASE_SURFACE_CMD, release, NULL); -+} -+ -+int qxl_alloc_release_reserved(struct qxl_device *qdev, unsigned long size, -+ int type, struct qxl_release **release, -+ struct qxl_bo **rbo) -+{ -+ struct qxl_bo *bo; -+ int idr_ret; -+ int ret; -+ union qxl_release_info *info; -+ int cur_idx; -+ -+ if (type == QXL_RELEASE_DRAWABLE) -+ cur_idx = 0; -+ else if (type == QXL_RELEASE_SURFACE_CMD) -+ cur_idx = 1; -+ else if (type == QXL_RELEASE_CURSOR_CMD) -+ cur_idx = 2; -+ else { -+ DRM_ERROR("got illegal type: %d\n", type); -+ return -EINVAL; -+ } -+ -+ idr_ret = qxl_release_alloc(qdev, type, release); -+ -+ mutex_lock(&qdev->release_mutex); -+ if (qdev->current_release_bo_offset[cur_idx] + 1 >= releases_per_bo[cur_idx]) { -+ qxl_bo_unref(&qdev->current_release_bo[cur_idx]); -+ qdev->current_release_bo_offset[cur_idx] = 0; -+ qdev->current_release_bo[cur_idx] = NULL; -+ } -+ if (!qdev->current_release_bo[cur_idx]) { -+ ret = qxl_release_bo_alloc(qdev, &qdev->current_release_bo[cur_idx]); -+ if (ret) { -+ mutex_unlock(&qdev->release_mutex); -+ return ret; -+ } -+ -+ /* pin releases bo's they are too messy to evict */ -+ ret = qxl_bo_reserve(qdev->current_release_bo[cur_idx], false); -+ qxl_bo_pin(qdev->current_release_bo[cur_idx], QXL_GEM_DOMAIN_VRAM, NULL); -+ qxl_bo_unreserve(qdev->current_release_bo[cur_idx]); -+ } -+ -+ bo = qxl_bo_ref(qdev->current_release_bo[cur_idx]); -+ -+ (*release)->release_offset = qdev->current_release_bo_offset[cur_idx] * release_size_per_bo[cur_idx]; -+ qdev->current_release_bo_offset[cur_idx]++; -+ -+ if (rbo) -+ *rbo = bo; -+ -+ qxl_release_add_res(qdev, *release, bo); -+ -+ ret = qxl_release_reserve(qdev, *release, false); -+ mutex_unlock(&qdev->release_mutex); -+ if (ret) -+ goto out_unref; -+ -+ info = qxl_release_map(qdev, *release); -+ info->id = idr_ret; -+ qxl_release_unmap(qdev, *release, info); -+ -+out_unref: -+ qxl_bo_unref(&bo); -+ return ret; -+} -+ -+int qxl_fence_releaseable(struct qxl_device *qdev, -+ struct qxl_release *release) -+{ -+ int i, ret; -+ for (i = 0; i < release->bo_count; i++) { -+ if (!release->bos[i]->tbo.sync_obj) -+ release->bos[i]->tbo.sync_obj = &release->bos[i]->fence; -+ ret = qxl_fence_add_release(&release->bos[i]->fence, release->id); -+ if (ret) -+ return ret; -+ } -+ return 0; -+} -+ -+struct qxl_release *qxl_release_from_id_locked(struct qxl_device *qdev, -+ uint64_t id) -+{ -+ struct qxl_release *release; -+ -+ spin_lock(&qdev->release_idr_lock); -+ release = idr_find(&qdev->release_idr, id); -+ spin_unlock(&qdev->release_idr_lock); -+ if (!release) { -+ DRM_ERROR("failed to find id in release_idr\n"); -+ return NULL; -+ } -+ if (release->bo_count < 1) { -+ DRM_ERROR("read a released resource with 0 bos\n"); -+ return NULL; -+ } -+ return release; -+} -+ -+union qxl_release_info *qxl_release_map(struct qxl_device *qdev, -+ struct qxl_release *release) -+{ -+ void *ptr; -+ union qxl_release_info *info; -+ struct qxl_bo *bo = release->bos[0]; -+ -+ ptr = qxl_bo_kmap_atomic_page(qdev, bo, release->release_offset & PAGE_SIZE); -+ info = ptr + (release->release_offset & ~PAGE_SIZE); -+ return info; -+} -+ -+void qxl_release_unmap(struct qxl_device *qdev, -+ struct qxl_release *release, -+ union qxl_release_info *info) -+{ -+ struct qxl_bo *bo = release->bos[0]; -+ void *ptr; -+ -+ ptr = ((void *)info) - (release->release_offset & ~PAGE_SIZE); -+ qxl_bo_kunmap_atomic_page(qdev, bo, ptr); -+} -diff --git a/drivers/gpu/drm/qxl/qxl_ttm.c b/drivers/gpu/drm/qxl/qxl_ttm.c -new file mode 100644 -index 0000000..aa9fb9a ---- /dev/null -+++ b/drivers/gpu/drm/qxl/qxl_ttm.c -@@ -0,0 +1,577 @@ -+/* -+ * Copyright 2013 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, sublicense, -+ * 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 above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * 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 NONINFRINGEMENT. IN NO EVENT SHALL -+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. -+ * -+ * Authors: Dave Airlie -+ * Alon Levy -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "qxl_drv.h" -+#include "qxl_object.h" -+ -+#include -+static int qxl_ttm_debugfs_init(struct qxl_device *qdev); -+ -+static struct qxl_device *qxl_get_qdev(struct ttm_bo_device *bdev) -+{ -+ struct qxl_mman *mman; -+ struct qxl_device *qdev; -+ -+ mman = container_of(bdev, struct qxl_mman, bdev); -+ qdev = container_of(mman, struct qxl_device, mman); -+ return qdev; -+} -+ -+static int qxl_ttm_mem_global_init(struct drm_global_reference *ref) -+{ -+ return ttm_mem_global_init(ref->object); -+} -+ -+static void qxl_ttm_mem_global_release(struct drm_global_reference *ref) -+{ -+ ttm_mem_global_release(ref->object); -+} -+ -+static int qxl_ttm_global_init(struct qxl_device *qdev) -+{ -+ struct drm_global_reference *global_ref; -+ int r; -+ -+ qdev->mman.mem_global_referenced = false; -+ global_ref = &qdev->mman.mem_global_ref; -+ global_ref->global_type = DRM_GLOBAL_TTM_MEM; -+ global_ref->size = sizeof(struct ttm_mem_global); -+ global_ref->init = &qxl_ttm_mem_global_init; -+ global_ref->release = &qxl_ttm_mem_global_release; -+ -+ r = drm_global_item_ref(global_ref); -+ if (r != 0) { -+ DRM_ERROR("Failed setting up TTM memory accounting " -+ "subsystem.\n"); -+ return r; -+ } -+ -+ qdev->mman.bo_global_ref.mem_glob = -+ qdev->mman.mem_global_ref.object; -+ global_ref = &qdev->mman.bo_global_ref.ref; -+ global_ref->global_type = DRM_GLOBAL_TTM_BO; -+ global_ref->size = sizeof(struct ttm_bo_global); -+ global_ref->init = &ttm_bo_global_init; -+ global_ref->release = &ttm_bo_global_release; -+ r = drm_global_item_ref(global_ref); -+ if (r != 0) { -+ DRM_ERROR("Failed setting up TTM BO subsystem.\n"); -+ drm_global_item_unref(&qdev->mman.mem_global_ref); -+ return r; -+ } -+ -+ qdev->mman.mem_global_referenced = true; -+ return 0; -+} -+ -+static void qxl_ttm_global_fini(struct qxl_device *qdev) -+{ -+ if (qdev->mman.mem_global_referenced) { -+ drm_global_item_unref(&qdev->mman.bo_global_ref.ref); -+ drm_global_item_unref(&qdev->mman.mem_global_ref); -+ qdev->mman.mem_global_referenced = false; -+ } -+} -+ -+static struct vm_operations_struct qxl_ttm_vm_ops; -+static const struct vm_operations_struct *ttm_vm_ops; -+ -+static int qxl_ttm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) -+{ -+ struct ttm_buffer_object *bo; -+ struct qxl_device *qdev; -+ int r; -+ -+ bo = (struct ttm_buffer_object *)vma->vm_private_data; -+ if (bo == NULL) -+ return VM_FAULT_NOPAGE; -+ qdev = qxl_get_qdev(bo->bdev); -+ r = ttm_vm_ops->fault(vma, vmf); -+ return r; -+} -+ -+int qxl_mmap(struct file *filp, struct vm_area_struct *vma) -+{ -+ struct drm_file *file_priv; -+ struct qxl_device *qdev; -+ int r; -+ -+ if (unlikely(vma->vm_pgoff < DRM_FILE_PAGE_OFFSET)) { -+ pr_info("%s: vma->vm_pgoff (%ld) < DRM_FILE_PAGE_OFFSET\n", -+ __func__, vma->vm_pgoff); -+ return drm_mmap(filp, vma); -+ } -+ -+ file_priv = filp->private_data; -+ qdev = file_priv->minor->dev->dev_private; -+ if (qdev == NULL) { -+ DRM_ERROR( -+ "filp->private_data->minor->dev->dev_private == NULL\n"); -+ return -EINVAL; -+ } -+ QXL_INFO(qdev, "%s: filp->private_data = 0x%p, vma->vm_pgoff = %lx\n", -+ __func__, filp->private_data, vma->vm_pgoff); -+ -+ r = ttm_bo_mmap(filp, vma, &qdev->mman.bdev); -+ if (unlikely(r != 0)) -+ return r; -+ if (unlikely(ttm_vm_ops == NULL)) { -+ ttm_vm_ops = vma->vm_ops; -+ qxl_ttm_vm_ops = *ttm_vm_ops; -+ qxl_ttm_vm_ops.fault = &qxl_ttm_fault; -+ } -+ vma->vm_ops = &qxl_ttm_vm_ops; -+ return 0; -+} -+ -+static int qxl_invalidate_caches(struct ttm_bo_device *bdev, uint32_t flags) -+{ -+ return 0; -+} -+ -+static int qxl_init_mem_type(struct ttm_bo_device *bdev, uint32_t type, -+ struct ttm_mem_type_manager *man) -+{ -+ struct qxl_device *qdev; -+ -+ qdev = qxl_get_qdev(bdev); -+ -+ switch (type) { -+ case TTM_PL_SYSTEM: -+ /* System memory */ -+ 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: -+ case TTM_PL_PRIV0: -+ /* "On-card" video ram */ -+ man->func = &ttm_bo_manager_func; -+ man->gpu_offset = 0; -+ man->flags = TTM_MEMTYPE_FLAG_FIXED | -+ TTM_MEMTYPE_FLAG_MAPPABLE; -+ man->available_caching = TTM_PL_MASK_CACHING; -+ man->default_caching = TTM_PL_FLAG_CACHED; -+ break; -+ default: -+ DRM_ERROR("Unsupported memory type %u\n", (unsigned)type); -+ return -EINVAL; -+ } -+ return 0; -+} -+ -+static void qxl_evict_flags(struct ttm_buffer_object *bo, -+ struct ttm_placement *placement) -+{ -+ struct qxl_bo *qbo; -+ static u32 placements = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM; -+ -+ if (!qxl_ttm_bo_is_qxl_bo(bo)) { -+ placement->fpfn = 0; -+ placement->lpfn = 0; -+ placement->placement = &placements; -+ placement->busy_placement = &placements; -+ placement->num_placement = 1; -+ placement->num_busy_placement = 1; -+ return; -+ } -+ qbo = container_of(bo, struct qxl_bo, tbo); -+ qxl_ttm_placement_from_domain(qbo, QXL_GEM_DOMAIN_CPU); -+ *placement = qbo->placement; -+} -+ -+static int qxl_verify_access(struct ttm_buffer_object *bo, struct file *filp) -+{ -+ return 0; -+} -+ -+static int qxl_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 qxl_device *qdev = qxl_get_qdev(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.is_iomem = true; -+ mem->bus.base = qdev->vram_base; -+ mem->bus.offset = mem->start << PAGE_SHIFT; -+ break; -+ case TTM_PL_PRIV0: -+ mem->bus.is_iomem = true; -+ mem->bus.base = qdev->surfaceram_base; -+ mem->bus.offset = mem->start << PAGE_SHIFT; -+ break; -+ default: -+ return -EINVAL; -+ } -+ return 0; -+} -+ -+static void qxl_ttm_io_mem_free(struct ttm_bo_device *bdev, -+ struct ttm_mem_reg *mem) -+{ -+} -+ -+/* -+ * TTM backend functions. -+ */ -+struct qxl_ttm_tt { -+ struct ttm_dma_tt ttm; -+ struct qxl_device *qdev; -+ u64 offset; -+}; -+ -+static int qxl_ttm_backend_bind(struct ttm_tt *ttm, -+ struct ttm_mem_reg *bo_mem) -+{ -+ struct qxl_ttm_tt *gtt = (void *)ttm; -+ -+ gtt->offset = (unsigned long)(bo_mem->start << PAGE_SHIFT); -+ if (!ttm->num_pages) { -+ WARN(1, "nothing to bind %lu pages for mreg %p back %p!\n", -+ ttm->num_pages, bo_mem, ttm); -+ } -+ /* Not implemented */ -+ return -1; -+} -+ -+static int qxl_ttm_backend_unbind(struct ttm_tt *ttm) -+{ -+ /* Not implemented */ -+ return -1; -+} -+ -+static void qxl_ttm_backend_destroy(struct ttm_tt *ttm) -+{ -+ struct qxl_ttm_tt *gtt = (void *)ttm; -+ -+ ttm_dma_tt_fini(>t->ttm); -+ kfree(gtt); -+} -+ -+static struct ttm_backend_func qxl_backend_func = { -+ .bind = &qxl_ttm_backend_bind, -+ .unbind = &qxl_ttm_backend_unbind, -+ .destroy = &qxl_ttm_backend_destroy, -+}; -+ -+static int qxl_ttm_tt_populate(struct ttm_tt *ttm) -+{ -+ int r; -+ -+ if (ttm->state != tt_unpopulated) -+ return 0; -+ -+ r = ttm_pool_populate(ttm); -+ if (r) -+ return r; -+ -+ return 0; -+} -+ -+static void qxl_ttm_tt_unpopulate(struct ttm_tt *ttm) -+{ -+ ttm_pool_unpopulate(ttm); -+} -+ -+struct ttm_tt *qxl_ttm_tt_create(struct ttm_bo_device *bdev, -+ unsigned long size, uint32_t page_flags, -+ struct page *dummy_read_page) -+{ -+ struct qxl_device *qdev; -+ struct qxl_ttm_tt *gtt; -+ -+ qdev = qxl_get_qdev(bdev); -+ gtt = kzalloc(sizeof(struct qxl_ttm_tt), GFP_KERNEL); -+ if (gtt == NULL) -+ return NULL; -+ gtt->ttm.ttm.func = &qxl_backend_func; -+ gtt->qdev = qdev; -+ if (ttm_dma_tt_init(>t->ttm, bdev, size, page_flags, -+ dummy_read_page)) { -+ kfree(gtt); -+ return NULL; -+ } -+ return >t->ttm.ttm; -+} -+ -+static void qxl_move_null(struct ttm_buffer_object *bo, -+ struct ttm_mem_reg *new_mem) -+{ -+ struct ttm_mem_reg *old_mem = &bo->mem; -+ -+ BUG_ON(old_mem->mm_node != NULL); -+ *old_mem = *new_mem; -+ new_mem->mm_node = NULL; -+} -+ -+static int qxl_bo_move(struct ttm_buffer_object *bo, -+ bool evict, bool interruptible, -+ bool no_wait_gpu, -+ struct ttm_mem_reg *new_mem) -+{ -+ struct ttm_mem_reg *old_mem = &bo->mem; -+ if (old_mem->mem_type == TTM_PL_SYSTEM && bo->ttm == NULL) { -+ qxl_move_null(bo, new_mem); -+ return 0; -+ } -+ return ttm_bo_move_memcpy(bo, evict, no_wait_gpu, new_mem); -+} -+ -+ -+static int qxl_sync_obj_wait(void *sync_obj, -+ bool lazy, bool interruptible) -+{ -+ struct qxl_fence *qfence = (struct qxl_fence *)sync_obj; -+ int count = 0, sc = 0; -+ struct qxl_bo *bo = container_of(qfence, struct qxl_bo, fence); -+ -+ if (qfence->num_active_releases == 0) -+ return 0; -+ -+retry: -+ if (sc == 0) { -+ if (bo->type == QXL_GEM_DOMAIN_SURFACE) -+ qxl_update_surface(qfence->qdev, bo); -+ } else if (sc >= 1) { -+ qxl_io_notify_oom(qfence->qdev); -+ } -+ -+ sc++; -+ -+ for (count = 0; count < 10; count++) { -+ bool ret; -+ ret = qxl_queue_garbage_collect(qfence->qdev, true); -+ if (ret == false) -+ break; -+ -+ if (qfence->num_active_releases == 0) -+ return 0; -+ } -+ -+ if (qfence->num_active_releases) { -+ bool have_drawable_releases = false; -+ void **slot; -+ struct radix_tree_iter iter; -+ int release_id; -+ -+ radix_tree_for_each_slot(slot, &qfence->tree, &iter, 0) { -+ struct qxl_release *release; -+ -+ release_id = iter.index; -+ release = qxl_release_from_id_locked(qfence->qdev, release_id); -+ if (release == NULL) -+ continue; -+ -+ if (release->type == QXL_RELEASE_DRAWABLE) -+ have_drawable_releases = true; -+ } -+ -+ qxl_queue_garbage_collect(qfence->qdev, true); -+ -+ if (have_drawable_releases || sc < 4) { -+ if (sc > 2) -+ /* back off */ -+ usleep_range(500, 1000); -+ if (have_drawable_releases && sc > 300) { -+ WARN(1, "sync obj %d still has outstanding releases %d %d %d %ld %d\n", sc, bo->surface_id, bo->is_primary, bo->pin_count, (unsigned long)bo->gem_base.size, qfence->num_active_releases); -+ return -EBUSY; -+ } -+ goto retry; -+ } -+ } -+ return 0; -+} -+ -+static int qxl_sync_obj_flush(void *sync_obj) -+{ -+ return 0; -+} -+ -+static void qxl_sync_obj_unref(void **sync_obj) -+{ -+} -+ -+static void *qxl_sync_obj_ref(void *sync_obj) -+{ -+ return sync_obj; -+} -+ -+static bool qxl_sync_obj_signaled(void *sync_obj) -+{ -+ struct qxl_fence *qfence = (struct qxl_fence *)sync_obj; -+ return (qfence->num_active_releases == 0); -+} -+ -+static void qxl_bo_move_notify(struct ttm_buffer_object *bo, -+ struct ttm_mem_reg *new_mem) -+{ -+ struct qxl_bo *qbo; -+ struct qxl_device *qdev; -+ -+ if (!qxl_ttm_bo_is_qxl_bo(bo)) -+ return; -+ qbo = container_of(bo, struct qxl_bo, tbo); -+ qdev = qbo->gem_base.dev->dev_private; -+ -+ if (bo->mem.mem_type == TTM_PL_PRIV0 && qbo->surface_id) -+ qxl_surface_evict(qdev, qbo, new_mem ? true : false); -+} -+ -+static struct ttm_bo_driver qxl_bo_driver = { -+ .ttm_tt_create = &qxl_ttm_tt_create, -+ .ttm_tt_populate = &qxl_ttm_tt_populate, -+ .ttm_tt_unpopulate = &qxl_ttm_tt_unpopulate, -+ .invalidate_caches = &qxl_invalidate_caches, -+ .init_mem_type = &qxl_init_mem_type, -+ .evict_flags = &qxl_evict_flags, -+ .move = &qxl_bo_move, -+ .verify_access = &qxl_verify_access, -+ .io_mem_reserve = &qxl_ttm_io_mem_reserve, -+ .io_mem_free = &qxl_ttm_io_mem_free, -+ .sync_obj_signaled = &qxl_sync_obj_signaled, -+ .sync_obj_wait = &qxl_sync_obj_wait, -+ .sync_obj_flush = &qxl_sync_obj_flush, -+ .sync_obj_unref = &qxl_sync_obj_unref, -+ .sync_obj_ref = &qxl_sync_obj_ref, -+ .move_notify = &qxl_bo_move_notify, -+}; -+ -+ -+ -+int qxl_ttm_init(struct qxl_device *qdev) -+{ -+ int r; -+ int num_io_pages; /* != rom->num_io_pages, we include surface0 */ -+ -+ r = qxl_ttm_global_init(qdev); -+ if (r) -+ return r; -+ /* No others user of address space so set it to 0 */ -+ r = ttm_bo_device_init(&qdev->mman.bdev, -+ qdev->mman.bo_global_ref.ref.object, -+ &qxl_bo_driver, DRM_FILE_PAGE_OFFSET, 0); -+ if (r) { -+ DRM_ERROR("failed initializing buffer object driver(%d).\n", r); -+ return r; -+ } -+ /* NOTE: this includes the framebuffer (aka surface 0) */ -+ num_io_pages = qdev->rom->ram_header_offset / PAGE_SIZE; -+ r = ttm_bo_init_mm(&qdev->mman.bdev, TTM_PL_VRAM, -+ num_io_pages); -+ if (r) { -+ DRM_ERROR("Failed initializing VRAM heap.\n"); -+ return r; -+ } -+ r = ttm_bo_init_mm(&qdev->mman.bdev, TTM_PL_PRIV0, -+ qdev->surfaceram_size / PAGE_SIZE); -+ if (r) { -+ DRM_ERROR("Failed initializing Surfaces heap.\n"); -+ return r; -+ } -+ DRM_INFO("qxl: %uM of VRAM memory size\n", -+ (unsigned)qdev->vram_size / (1024 * 1024)); -+ DRM_INFO("qxl: %luM of IO pages memory ready (VRAM domain)\n", -+ ((unsigned)num_io_pages * PAGE_SIZE) / (1024 * 1024)); -+ if (unlikely(qdev->mman.bdev.dev_mapping == NULL)) -+ qdev->mman.bdev.dev_mapping = qdev->ddev->dev_mapping; -+ r = qxl_ttm_debugfs_init(qdev); -+ if (r) { -+ DRM_ERROR("Failed to init debugfs\n"); -+ return r; -+ } -+ return 0; -+} -+ -+void qxl_ttm_fini(struct qxl_device *qdev) -+{ -+ ttm_bo_clean_mm(&qdev->mman.bdev, TTM_PL_VRAM); -+ ttm_bo_clean_mm(&qdev->mman.bdev, TTM_PL_PRIV0); -+ ttm_bo_device_release(&qdev->mman.bdev); -+ qxl_ttm_global_fini(qdev); -+ DRM_INFO("qxl: ttm finalized\n"); -+} -+ -+ -+#define QXL_DEBUGFS_MEM_TYPES 2 -+ -+#if defined(CONFIG_DEBUG_FS) -+static int qxl_mm_dump_table(struct seq_file *m, void *data) -+{ -+ struct drm_info_node *node = (struct drm_info_node *)m->private; -+ struct drm_mm *mm = (struct drm_mm *)node->info_ent->data; -+ struct drm_device *dev = node->minor->dev; -+ struct qxl_device *rdev = dev->dev_private; -+ int ret; -+ struct ttm_bo_global *glob = rdev->mman.bdev.glob; -+ -+ spin_lock(&glob->lru_lock); -+ ret = drm_mm_dump_table(m, mm); -+ spin_unlock(&glob->lru_lock); -+ return ret; -+} -+#endif -+ -+static int qxl_ttm_debugfs_init(struct qxl_device *qdev) -+{ -+ static struct drm_info_list qxl_mem_types_list[QXL_DEBUGFS_MEM_TYPES]; -+ static char qxl_mem_types_names[QXL_DEBUGFS_MEM_TYPES][32]; -+ unsigned i; -+ -+ for (i = 0; i < QXL_DEBUGFS_MEM_TYPES; i++) { -+ if (i == 0) -+ sprintf(qxl_mem_types_names[i], "qxl_mem_mm"); -+ else -+ sprintf(qxl_mem_types_names[i], "qxl_surf_mm"); -+ qxl_mem_types_list[i].name = qxl_mem_types_names[i]; -+ qxl_mem_types_list[i].show = &qxl_mm_dump_table; -+ qxl_mem_types_list[i].driver_features = 0; -+ if (i == 0) -+ qxl_mem_types_list[i].data = qdev->mman.bdev.man[TTM_PL_VRAM].priv; -+ else -+ qxl_mem_types_list[i].data = qdev->mman.bdev.man[TTM_PL_PRIV0].priv; -+ -+ } -+ return qxl_debugfs_add_files(qdev, qxl_mem_types_list, i); -+} -diff --git a/include/uapi/drm/Kbuild b/include/uapi/drm/Kbuild -index ba99ce3..a042a95 100644 ---- a/include/uapi/drm/Kbuild -+++ b/include/uapi/drm/Kbuild -@@ -8,6 +8,7 @@ header-y += i810_drm.h - header-y += i915_drm.h - header-y += mga_drm.h - header-y += nouveau_drm.h -+header-y += qxl_drm.h - header-y += r128_drm.h - header-y += radeon_drm.h - header-y += savage_drm.h -diff --git a/include/uapi/drm/qxl_drm.h b/include/uapi/drm/qxl_drm.h -new file mode 100644 -index 0000000..ebebd36 ---- /dev/null -+++ b/include/uapi/drm/qxl_drm.h -@@ -0,0 +1,152 @@ -+/* -+ * Copyright 2013 Red Hat -+ * All Rights Reserved. -+ * -+ * 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, sublicense, -+ * 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 above copyright notice and this permission notice (including the next -+ * paragraph) shall be included in all copies or substantial portions of the -+ * Software. -+ * -+ * 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 NONINFRINGEMENT. IN NO EVENT SHALL -+ * THE 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. -+ */ -+#ifndef QXL_DRM_H -+#define QXL_DRM_H -+ -+#include -+#include "drm/drm.h" -+ -+/* Please note that modifications to all structs defined here are -+ * subject to backwards-compatibility constraints. -+ * -+ * Do not use pointers, use uint64_t instead for 32 bit / 64 bit user/kernel -+ * compatibility Keep fields aligned to their size -+ */ -+ -+#define QXL_GEM_DOMAIN_CPU 0 -+#define QXL_GEM_DOMAIN_VRAM 1 -+#define QXL_GEM_DOMAIN_SURFACE 2 -+ -+#define DRM_QXL_ALLOC 0x00 -+#define DRM_QXL_MAP 0x01 -+#define DRM_QXL_EXECBUFFER 0x02 -+#define DRM_QXL_UPDATE_AREA 0x03 -+#define DRM_QXL_GETPARAM 0x04 -+#define DRM_QXL_CLIENTCAP 0x05 -+ -+#define DRM_QXL_ALLOC_SURF 0x06 -+ -+struct drm_qxl_alloc { -+ uint32_t size; -+ uint32_t handle; /* 0 is an invalid handle */ -+}; -+ -+struct drm_qxl_map { -+ uint64_t offset; /* use for mmap system call */ -+ uint32_t handle; -+ uint32_t pad; -+}; -+ -+/* -+ * dest is the bo we are writing the relocation into -+ * src is bo we are relocating. -+ * *(dest_handle.base_addr + dest_offset) = physical_address(src_handle.addr + -+ * src_offset) -+ */ -+#define QXL_RELOC_TYPE_BO 1 -+#define QXL_RELOC_TYPE_SURF 2 -+ -+struct drm_qxl_reloc { -+ uint64_t src_offset; /* offset into src_handle or src buffer */ -+ uint64_t dst_offset; /* offset in dest handle */ -+ uint32_t src_handle; /* dest handle to compute address from */ -+ uint32_t dst_handle; /* 0 if to command buffer */ -+ uint32_t reloc_type; -+ uint32_t pad; -+}; -+ -+struct drm_qxl_command { -+ uint64_t __user command; /* void* */ -+ uint64_t __user relocs; /* struct drm_qxl_reloc* */ -+ uint32_t type; -+ uint32_t command_size; -+ uint32_t relocs_num; -+ uint32_t pad; -+}; -+ -+/* XXX: call it drm_qxl_commands? */ -+struct drm_qxl_execbuffer { -+ uint32_t flags; /* for future use */ -+ uint32_t commands_num; -+ uint64_t __user commands; /* struct drm_qxl_command* */ -+}; -+ -+struct drm_qxl_update_area { -+ uint32_t handle; -+ uint32_t top; -+ uint32_t left; -+ uint32_t bottom; -+ uint32_t right; -+ uint32_t pad; -+}; -+ -+#define QXL_PARAM_NUM_SURFACES 1 /* rom->n_surfaces */ -+#define QXL_PARAM_MAX_RELOCS 2 -+struct drm_qxl_getparam { -+ uint64_t param; -+ uint64_t value; -+}; -+ -+/* these are one bit values */ -+struct drm_qxl_clientcap { -+ uint32_t index; -+ uint32_t pad; -+}; -+ -+struct drm_qxl_alloc_surf { -+ uint32_t format; -+ uint32_t width; -+ uint32_t height; -+ int32_t stride; -+ uint32_t handle; -+ uint32_t pad; -+}; -+ -+#define DRM_IOCTL_QXL_ALLOC \ -+ DRM_IOWR(DRM_COMMAND_BASE + DRM_QXL_ALLOC, struct drm_qxl_alloc) -+ -+#define DRM_IOCTL_QXL_MAP \ -+ DRM_IOWR(DRM_COMMAND_BASE + DRM_QXL_MAP, struct drm_qxl_map) -+ -+#define DRM_IOCTL_QXL_EXECBUFFER \ -+ DRM_IOW(DRM_COMMAND_BASE + DRM_QXL_EXECBUFFER,\ -+ struct drm_qxl_execbuffer) -+ -+#define DRM_IOCTL_QXL_UPDATE_AREA \ -+ DRM_IOW(DRM_COMMAND_BASE + DRM_QXL_UPDATE_AREA,\ -+ struct drm_qxl_update_area) -+ -+#define DRM_IOCTL_QXL_GETPARAM \ -+ DRM_IOWR(DRM_COMMAND_BASE + DRM_QXL_GETPARAM,\ -+ struct drm_qxl_getparam) -+ -+#define DRM_IOCTL_QXL_CLIENTCAP \ -+ DRM_IOW(DRM_COMMAND_BASE + DRM_QXL_CLIENTCAP,\ -+ struct drm_qxl_clientcap) -+ -+#define DRM_IOCTL_QXL_ALLOC_SURF \ -+ DRM_IOWR(DRM_COMMAND_BASE + DRM_QXL_ALLOC_SURF,\ -+ struct drm_qxl_alloc_surf) -+ -+#endif --- -1.8.1.4 - diff --git a/drm-ttm-exports-for-qxl.patch b/drm-ttm-exports-for-qxl.patch deleted file mode 100644 index 6134b51..0000000 --- a/drm-ttm-exports-for-qxl.patch +++ /dev/null @@ -1,86 +0,0 @@ -From b538d2921b8aaaa1d7abf1bf0ba3ab9330b0b0c8 Mon Sep 17 00:00:00 2001 -From: Dave Airlie -Date: Tue, 22 Jan 2013 13:56:04 +1000 -Subject: [PATCH 1/2] ttm: export functions to allow qxl do its own iomapping - -qxl wants to use io mapping like i915 gem does, for now -just export the symbols so the driver can implement atomic -page maps using io mapping. - -Signed-off-by: Dave Airlie ---- - drivers/gpu/drm/ttm/ttm_bo_util.c | 13 +++++++++---- - include/drm/ttm/ttm_bo_driver.h | 4 ++++ - 2 files changed, 13 insertions(+), 4 deletions(-) - -diff --git a/drivers/gpu/drm/ttm/ttm_bo_util.c b/drivers/gpu/drm/ttm/ttm_bo_util.c -index 44420fc..aaf6f47 100644 ---- a/drivers/gpu/drm/ttm/ttm_bo_util.c -+++ b/drivers/gpu/drm/ttm/ttm_bo_util.c -@@ -86,6 +86,7 @@ int ttm_mem_io_lock(struct ttm_mem_type_manager *man, bool interruptible) - mutex_lock(&man->io_reserve_mutex); - return 0; - } -+EXPORT_SYMBOL(ttm_mem_io_lock); - - void ttm_mem_io_unlock(struct ttm_mem_type_manager *man) - { -@@ -94,6 +95,7 @@ void ttm_mem_io_unlock(struct ttm_mem_type_manager *man) - - mutex_unlock(&man->io_reserve_mutex); - } -+EXPORT_SYMBOL(ttm_mem_io_unlock); - - static int ttm_mem_io_evict(struct ttm_mem_type_manager *man) - { -@@ -111,8 +113,9 @@ static int ttm_mem_io_evict(struct ttm_mem_type_manager *man) - return 0; - } - --static int ttm_mem_io_reserve(struct ttm_bo_device *bdev, -- struct ttm_mem_reg *mem) -+ -+int ttm_mem_io_reserve(struct ttm_bo_device *bdev, -+ struct ttm_mem_reg *mem) - { - struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type]; - int ret = 0; -@@ -134,9 +137,10 @@ retry: - } - return ret; - } -+EXPORT_SYMBOL(ttm_mem_io_reserve); - --static void ttm_mem_io_free(struct ttm_bo_device *bdev, -- struct ttm_mem_reg *mem) -+void ttm_mem_io_free(struct ttm_bo_device *bdev, -+ struct ttm_mem_reg *mem) - { - struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type]; - -@@ -149,6 +153,7 @@ static void ttm_mem_io_free(struct ttm_bo_device *bdev, - bdev->driver->io_mem_free(bdev, mem); - - } -+EXPORT_SYMBOL(ttm_mem_io_free); - - int ttm_mem_io_reserve_vm(struct ttm_buffer_object *bo) - { -diff --git a/include/drm/ttm/ttm_bo_driver.h b/include/drm/ttm/ttm_bo_driver.h -index 0fbd046..9c8dca7 100644 ---- a/include/drm/ttm/ttm_bo_driver.h -+++ b/include/drm/ttm/ttm_bo_driver.h -@@ -902,6 +902,10 @@ extern void ttm_bo_unreserve_locked(struct ttm_buffer_object *bo); - * ttm_bo_util.c - */ - -+int ttm_mem_io_reserve(struct ttm_bo_device *bdev, -+ struct ttm_mem_reg *mem); -+void ttm_mem_io_free(struct ttm_bo_device *bdev, -+ struct ttm_mem_reg *mem); - /** - * ttm_bo_move_ttm - * --- -1.8.1.4 - diff --git a/forcedeth-dma-error-check.patch b/forcedeth-dma-error-check.patch deleted file mode 100644 index 563fe87..0000000 --- a/forcedeth-dma-error-check.patch +++ /dev/null @@ -1,134 +0,0 @@ -From e33f52b67b45dd95b973260c54c6ef207ee44f84 Mon Sep 17 00:00:00 2001 -From: Neil Horman -Date: Tue, 26 Mar 2013 14:36:56 -0400 -Subject: [PATCH] forcedeth: Do a dma_mapping_error check after - skb_frag_dma_map - -This backtrace was recently reported on a 3.9 kernel: - -Actual results: from syslog /var/log/messsages: -kernel: [17539.340285] ------------[ cut here ]------------ -kernel: [17539.341012] WARNING: at lib/dma-debug.c:937 check_unmap+0x493/0x960() -kernel: [17539.341012] Hardware name: MS-7125 -kernel: [17539.341012] forcedeth 0000:00:0a.0: DMA-API: device driver failed to -check map error[device address=0x0000000013c88000] [size=544 bytes] [mapped as -page] -kernel: [17539.341012] Modules linked in: fuse ebtable_nat ipt_MASQUERADE -nf_conntrack_netbios_ns nf_conntrack_broadcast ip6table_nat nf_nat_ipv6 -ip6table_mangle ip6t_REJECT nf_conntrack_ipv6 nf_defrag_ipv6 iptable_nat -nf_nat_ipv4 nf_nat iptable_mangle nf_conntrack_ipv4 nf_defrag_ipv4 xt_conntrack -nf_conntrack bnep bluetooth rfkill ebtable_filter ebtables ip6table_filter -ip6_tables snd_hda_codec_hdmi snd_cmipci snd_mpu401_uart snd_hda_intel -snd_intel8x0 snd_opl3_lib snd_ac97_codec gameport snd_hda_codec snd_rawmidi -ac97_bus snd_hwdep snd_seq snd_seq_device snd_pcm snd_page_alloc snd_timer snd -k8temp soundcore serio_raw i2c_nforce2 forcedeth ata_generic pata_acpi nouveau -video mxm_wmi wmi i2c_algo_bit drm_kms_helper ttm drm i2c_core sata_sil pata_amd -sata_nv uinput -kernel: [17539.341012] Pid: 17340, comm: sshd Not tainted -3.9.0-0.rc4.git0.1.fc19.i686.PAE #1 -kernel: [17539.341012] Call Trace: -kernel: [17539.341012] [] warn_slowpath_common+0x6c/0xa0 -kernel: [17539.341012] [] ? check_unmap+0x493/0x960 -kernel: [17539.341012] [] ? check_unmap+0x493/0x960 -kernel: [17539.341012] [] warn_slowpath_fmt+0x33/0x40 -kernel: [17539.341012] [] check_unmap+0x493/0x960 -kernel: [17539.341012] [] ? sched_clock_cpu+0xdf/0x150 -kernel: [17539.341012] [] debug_dma_unmap_page+0x67/0x70 -kernel: [17539.341012] [] nv_unmap_txskb.isra.32+0x92/0x100 - -Its pretty plainly the result of an skb fragment getting unmapped without having -its initial mapping operation checked for errors. This patch corrects that - -Signed-off-by: Neil Horman -CC: "David S. Miller" ---- - drivers/net/ethernet/nvidia/forcedeth.c | 41 ++++++++++++++++++++++++++++++++- - 1 file changed, 40 insertions(+), 1 deletion(-) - -diff --git a/drivers/net/ethernet/nvidia/forcedeth.c b/drivers/net/ethernet/nvidia/forcedeth.c -index b62262c..5ae1247 100644 ---- a/drivers/net/ethernet/nvidia/forcedeth.c -+++ b/drivers/net/ethernet/nvidia/forcedeth.c -@@ -2200,6 +2200,7 @@ static netdev_tx_t nv_start_xmit(struct sk_buff *skb, struct net_device *dev) - struct ring_desc *start_tx; - struct ring_desc *prev_tx; - struct nv_skb_map *prev_tx_ctx; -+ struct nv_skb_map *tmp_tx_ctx = NULL, *start_tx_ctx = NULL; - unsigned long flags; - - /* add fragments to entries count */ -@@ -2261,12 +2262,31 @@ static netdev_tx_t nv_start_xmit(struct sk_buff *skb, struct net_device *dev) - do { - prev_tx = put_tx; - prev_tx_ctx = np->put_tx_ctx; -+ if (!start_tx_ctx) -+ start_tx_ctx = tmp_tx_ctx = np->put_tx_ctx; -+ - bcnt = (frag_size > NV_TX2_TSO_MAX_SIZE) ? NV_TX2_TSO_MAX_SIZE : frag_size; - np->put_tx_ctx->dma = skb_frag_dma_map( - &np->pci_dev->dev, - frag, offset, - bcnt, - DMA_TO_DEVICE); -+ if (dma_mapping_error(&np->pci_dev->dev, np->put_tx_ctx->dma)) { -+ -+ /* Unwind the mapped fragments */ -+ do { -+ nv_unmap_txskb(np, start_tx_ctx); -+ if (unlikely(tmp_tx_ctx++ == np->last_tx_ctx)) -+ tmp_tx_ctx = np->first_tx_ctx; -+ } while (tmp_tx_ctx != np->put_tx_ctx); -+ kfree_skb(skb); -+ np->put_tx_ctx = start_tx_ctx; -+ u64_stats_update_begin(&np->swstats_tx_syncp); -+ np->stat_tx_dropped++; -+ u64_stats_update_end(&np->swstats_tx_syncp); -+ return NETDEV_TX_OK; -+ } -+ - np->put_tx_ctx->dma_len = bcnt; - np->put_tx_ctx->dma_single = 0; - put_tx->buf = cpu_to_le32(np->put_tx_ctx->dma); -@@ -2327,7 +2347,8 @@ static netdev_tx_t nv_start_xmit_optimized(struct sk_buff *skb, - struct ring_desc_ex *start_tx; - struct ring_desc_ex *prev_tx; - struct nv_skb_map *prev_tx_ctx; -- struct nv_skb_map *start_tx_ctx; -+ struct nv_skb_map *start_tx_ctx = NULL; -+ struct nv_skb_map *tmp_tx_ctx = NULL; - unsigned long flags; - - /* add fragments to entries count */ -@@ -2392,11 +2413,29 @@ static netdev_tx_t nv_start_xmit_optimized(struct sk_buff *skb, - prev_tx = put_tx; - prev_tx_ctx = np->put_tx_ctx; - bcnt = (frag_size > NV_TX2_TSO_MAX_SIZE) ? NV_TX2_TSO_MAX_SIZE : frag_size; -+ if (!start_tx_ctx) -+ start_tx_ctx = tmp_tx_ctx = np->put_tx_ctx; - np->put_tx_ctx->dma = skb_frag_dma_map( - &np->pci_dev->dev, - frag, offset, - bcnt, - DMA_TO_DEVICE); -+ -+ if (dma_mapping_error(&np->pci_dev->dev, np->put_tx_ctx->dma)) { -+ -+ /* Unwind the mapped fragments */ -+ do { -+ nv_unmap_txskb(np, start_tx_ctx); -+ if (unlikely(tmp_tx_ctx++ == np->last_tx_ctx)) -+ tmp_tx_ctx = np->first_tx_ctx; -+ } while (tmp_tx_ctx != np->put_tx_ctx); -+ kfree_skb(skb); -+ np->put_tx_ctx = start_tx_ctx; -+ u64_stats_update_begin(&np->swstats_tx_syncp); -+ np->stat_tx_dropped++; -+ u64_stats_update_end(&np->swstats_tx_syncp); -+ return NETDEV_TX_OK; -+ } - np->put_tx_ctx->dma_len = bcnt; - np->put_tx_ctx->dma_single = 0; - put_tx->bufhigh = cpu_to_le32(dma_high(np->put_tx_ctx->dma)); --- -1.7.11.7 - diff --git a/ipv6-ip6_sk_dst_check-must-not-assume-ipv6-dst.patch b/ipv6-ip6_sk_dst_check-must-not-assume-ipv6-dst.patch deleted file mode 100644 index 8f6c41d..0000000 --- a/ipv6-ip6_sk_dst_check-must-not-assume-ipv6-dst.patch +++ /dev/null @@ -1,52 +0,0 @@ -From a963a37d384d71ad43b3e9e79d68d42fbe0901f3 Mon Sep 17 00:00:00 2001 -From: Eric Dumazet -Date: Wed, 26 Jun 2013 04:15:07 -0700 -Subject: [PATCH] ipv6: ip6_sk_dst_check() must not assume ipv6 dst - -It's possible to use AF_INET6 sockets and to connect to an IPv4 -destination. After this, socket dst cache is a pointer to a rtable, -not rt6_info. - -ip6_sk_dst_check() should check the socket dst cache is IPv6, or else -various corruptions/crashes can happen. - -Dave Jones can reproduce immediate crash with -trinity -q -l off -n -c sendmsg -c connect - -With help from Hannes Frederic Sowa - -Reported-by: Dave Jones -Reported-by: Hannes Frederic Sowa -Signed-off-by: Eric Dumazet -Acked-by: Hannes Frederic Sowa -Signed-off-by: David S. Miller ---- - net/ipv6/ip6_output.c | 8 +++++++- - 1 file changed, 7 insertions(+), 1 deletion(-) - -diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c -index 95703ba..d5d20cd 100644 ---- a/net/ipv6/ip6_output.c -+++ b/net/ipv6/ip6_output.c -@@ -821,11 +821,17 @@ static struct dst_entry *ip6_sk_dst_check(struct sock *sk, - const struct flowi6 *fl6) - { - struct ipv6_pinfo *np = inet6_sk(sk); -- struct rt6_info *rt = (struct rt6_info *)dst; -+ struct rt6_info *rt; - - if (!dst) - goto out; - -+ if (dst->ops->family != AF_INET6) { -+ dst_release(dst); -+ return NULL; -+ } -+ -+ rt = (struct rt6_info *)dst; - /* Yes, checking route validity in not connected - * case is not very simple. Take into account, - * that we do not support routing by source, TOS, --- -1.8.2.1 - diff --git a/kernel.spec b/kernel.spec index 397bbbd..95da260 100644 --- a/kernel.spec +++ b/kernel.spec @@ -62,19 +62,19 @@ Summary: The Linux kernel # For non-released -rc kernels, this will be appended after the rcX and # gitX tags, so a 3 here would become part of release "0.rcX.gitX.3" # -%global baserelease 304 +%global baserelease 300 %global fedora_build %{baserelease} # base_sublevel is the kernel version we're starting with and patching # on top of -- for example, 3.1-rc7-git1 starts with a 3.0 base, # which yields a base_sublevel of 0. -%define base_sublevel 9 +%define base_sublevel 10 ## If this is a released kernel ## %if 0%{?released_kernel} # Do we have a -stable update to apply? -%define stable_update 9 +%define stable_update 1 # Is it a -stable RC? %define stable_rc 0 # Set rpm version accordingly @@ -639,9 +639,6 @@ Patch100: taint-vbox.patch Patch110: vmbugon-warnon.patch -Patch200: debug-bad-pte-dmi.patch -Patch201: debug-bad-pte-modules.patch - Patch390: defaults-acpi-video.patch Patch391: acpi-video-dos.patch Patch396: acpi-sony-nonvs-blacklist.patch @@ -668,11 +665,7 @@ Patch1000: devel-pekey-secure-boot-20130306.patch # DRM #atch1700: drm-edid-try-harder-to-fix-up-broken-headers.patch #Patch1800: drm-vgem.patch -Patch1700: drm-ttm-exports-for-qxl.patch Patch1701: drm-hotspot-cursor-backport.patch -Patch1702: drm-qxl-driver.patch -Patch1703: drm-qxl-3.10-rc7-diff.patch -Patch1704: drm-qxl-access-fix.patch Patch1705: drm-qxl-post-3.10-feature-fixes.patch Patch1706: drm-qxl-post-3.10-features-part-2.patch # nouveau + drm fixes @@ -712,10 +705,7 @@ Patch21000: arm-export-read_current_timer.patch Patch21001: arm-lpae-ax88796.patch # ARM omap -Patch21002: arm-omap-ehci-fix.patch Patch21003: arm-omap-load-tfp410.patch -# https://patchwork.kernel.org/patch/2414881/ -Patch21004: arm-omap-fixdrm.patch # ARM tegra Patch21005: arm-tegra-usb-no-reset-linux33.patch @@ -737,9 +727,6 @@ Patch21247: ath9k_rx_dma_stop_check.patch Patch21273: cfg80211-mac80211-disconnect-on-suspend.patch Patch21274: mac80211_fixes_for_ieee80211_do_stop_while_suspend_v3.9.patch -#rhbz 859282 -Patch21275: VMX-x86-handle-host-TSC-calibration-failure.patch - Patch22000: weird-root-dentry-name-debug.patch Patch22010: debug-idle-sched-warn-once.patch @@ -749,9 +736,6 @@ Patch22001: selinux-apply-different-permission-to-ptrace-child.patch #rhbz 927469 Patch23006: fix-child-thread-introspection.patch -#rhbz 928024 -Patch23008: forcedeth-dma-error-check.patch - #rhbz 948262 Patch25024: intel_iommu-Downgrade-the-warning-if-enabling-irq-remapping-fails.patch @@ -767,27 +751,14 @@ Patch25032: cve-2013-2147-ciss-info-leak.patch #CVE-2013-2148 rhbz 971258 971261 Patch25033: fanotify-info-leak-in-copy_event_to_user.patch -#CVE-2013-2851 rhbz 969515 971662 -Patch25035: block-do-not-pass-disk-names-as-format-strings.patch - #rhbz 954252 Patch25036: scsi-ipr-possible-irq-lock-inversion-dependency-detected.patch -#CVE-2013-2164 rhbz 973100 973109 -Patch25038: cdrom-use-kzalloc-for-failing-hardware.patch - -#rhbz 967230 -Patch25043: vfio-Set-container-device-mode.patch -Patch25044: vfio-fix-crash-on-rmmod.patch - #rhbz 969644 Patch25046: KVM-x86-handle-idiv-overflow-at-kvm_write_tsc.patch Patch25047: drm-radeon-Disable-writeback-by-default-on-ppc.patch -#rhbz 956732 -Patch25048: tulip-dma-debug-error.patch - Patch25050: iwlwifi-pcie-fix-race-in-queue-unmapping.patch Patch25051: iwlwifi-pcie-wake-the-queue-if-stopped-when-being-unmapped.patch @@ -807,15 +778,9 @@ Patch25055: ath3k-dont-use-stack-memory-for-DMA.patch Patch25056: iwl3945-better-skb-management-in-rx-path.patch Patch25057: iwl4965-better-skb-management-in-rx-path.patch -#CVE-2013-2234 rhbz 980995 981007 -Patch25058: af_key-fix-info-leaks-in-notify-messages.patch - #CVE-2013-1059 rhbz 977356 980341 Patch25059: ceph-fix.patch -#CVE-2013-2232 rhbz 981552 981564 -Patch25060: ipv6-ip6_sk_dst_check-must-not-assume-ipv6-dst.patch - #rhbz 976789 980643 Patch25062: vhost-net-fix-use-after-free-in-vhost_net_flush.patch @@ -1374,9 +1339,6 @@ ApplyPatch taint-vbox.patch ApplyPatch vmbugon-warnon.patch -ApplyPatch debug-bad-pte-dmi.patch -ApplyPatch debug-bad-pte-modules.patch - # Architecture patches # x86(-64) @@ -1385,11 +1347,9 @@ ApplyPatch debug-bad-pte-modules.patch # ApplyPatch arm-export-read_current_timer.patch ApplyPatch arm-lpae-ax88796.patch -ApplyPatch arm-omap-ehci-fix.patch ApplyPatch arm-omap-load-tfp410.patch -ApplyPatch arm-omap-fixdrm.patch ApplyPatch arm-tegra-usb-no-reset-linux33.patch -ApplyPatch arm-tegra-fixclk.patch +#ApplyPatch arm-tegra-fixclk.patch # # bugfixes to drivers and filesystems @@ -1460,11 +1420,7 @@ ApplyPatch devel-pekey-secure-boot-20130306.patch # Assorted Virt Fixes # DRM core -ApplyPatch drm-ttm-exports-for-qxl.patch ApplyPatch drm-hotspot-cursor-backport.patch -ApplyPatch drm-qxl-driver.patch -ApplyPatch drm-qxl-3.10-rc7-diff.patch -ApplyPatch drm-qxl-access-fix.patch ApplyPatch drm-qxl-post-3.10-feature-fixes.patch ApplyPatch drm-qxl-post-3.10-features-part-2.patch #ApplyPatch drm-edid-try-harder-to-fix-up-broken-headers.patch @@ -1517,23 +1473,17 @@ ApplyPatch criu-no-expert.patch ApplyPatch ath9k_rx_dma_stop_check.patch #rhbz 856863 892599 -ApplyPatch cfg80211-mac80211-disconnect-on-suspend.patch -ApplyPatch mac80211_fixes_for_ieee80211_do_stop_while_suspend_v3.9.patch - -#rhbz 859282 -ApplyPatch VMX-x86-handle-host-TSC-calibration-failure.patch +#ApplyPatch cfg80211-mac80211-disconnect-on-suspend.patch +#ApplyPatch mac80211_fixes_for_ieee80211_do_stop_while_suspend_v3.9.patch #rhbz 927469 ApplyPatch fix-child-thread-introspection.patch -#rhbz 928024 -ApplyPatch forcedeth-dma-error-check.patch - #rhbz 948262 ApplyPatch intel_iommu-Downgrade-the-warning-if-enabling-irq-remapping-fails.patch # Needed for F19 gssproxy feature -ApplyPatch gssproxy-backport.patch +#ApplyPatch gssproxy-backport.patch #CVE-2013-2140 rhbz 971146 971148 ApplyPatch xen-blkback-Check-device-permissions-before-allowing.patch @@ -1544,27 +1494,14 @@ ApplyPatch cve-2013-2147-ciss-info-leak.patch #CVE-2013-2148 rhbz 971258 971261 ApplyPatch fanotify-info-leak-in-copy_event_to_user.patch -#CVE-2013-2851 rhbz 969515 971662 -ApplyPatch block-do-not-pass-disk-names-as-format-strings.patch - #rhbz 954252 ApplyPatch scsi-ipr-possible-irq-lock-inversion-dependency-detected.patch -#CVE-2013-2164 rhbz 973100 973109 -ApplyPatch cdrom-use-kzalloc-for-failing-hardware.patch - -#rhbz 967230 -ApplyPatch vfio-Set-container-device-mode.patch -ApplyPatch vfio-fix-crash-on-rmmod.patch - #rhbz 969644 ApplyPatch KVM-x86-handle-idiv-overflow-at-kvm_write_tsc.patch ApplyPatch drm-radeon-Disable-writeback-by-default-on-ppc.patch -#rhbz 956732 -ApplyPatch tulip-dma-debug-error.patch - ApplyPatch iwlwifi-pcie-fix-race-in-queue-unmapping.patch ApplyPatch iwlwifi-pcie-wake-the-queue-if-stopped-when-being-unmapped.patch @@ -1583,17 +1520,11 @@ ApplyPatch ath3k-dont-use-stack-memory-for-DMA.patch ApplyPatch iwl3945-better-skb-management-in-rx-path.patch ApplyPatch iwl4965-better-skb-management-in-rx-path.patch -#CVE-2013-2234 rhbz 980995 981007 -ApplyPatch af_key-fix-info-leaks-in-notify-messages.patch - #CVE-2013-1059 rhbz 977356 980341 -ApplyPatch ceph-fix.patch - -#CVE-2013-2232 rhbz 981552 981564 -ApplyPatch ipv6-ip6_sk_dst_check-must-not-assume-ipv6-dst.patch +#ApplyPatch ceph-fix.patch #rhbz 976789 980643 -ApplyPatch vhost-net-fix-use-after-free-in-vhost_net_flush.patch +#ApplyPatch vhost-net-fix-use-after-free-in-vhost_net_flush.patch #rhbz 959721 ApplyPatch HID-kye-Add-report-fixup-for-Genius-Gila-Gaming-mouse.patch @@ -1624,6 +1555,9 @@ mkdir configs rm -f kernel-%{version}-*debug.config %endif +# FIXME: ARM needs fixing. +rm -f kernel*arm*.config + # now run oldconfig over all the config files for i in *.config do @@ -2420,6 +2354,35 @@ fi # and build. %changelog +* Wed Jul 17 2013 Dave Jones +- Rebase to 3.10.1 + dropped: + debug-bad-pte-dmi.patch + debug-bad-pte-modules.patch + arm-omap-ehci-fix.patch + arm-omap-fixdrm.patch + drm-ttm-exports-for-qxl.patch + drm-qxl-driver.patch + drm-qxl-3.10-rc7-diff.patch + drm-qxl-access-fix.patch + VMX-x86-handle-host-TSC-calibration-failure.patch + forcedeth-dma-error-check.patch + block-do-not-pass-disk-names-as-format-strings.patch + cdrom-use-kzalloc-for-failing-hardware.patch + vfio-Set-container-device-mode.patch + vfio-fix-crash-on-rmmod.patch + tulip-dma-debug-error.patch + af_key-fix-info-leaks-in-notify-messages.patch + ipv6-ip6_sk_dst_check-must-not-assume-ipv6-dst.patch + needs fixing: + arm-tegra-fixclk.patch + cfg80211-mac80211-disconnect-on-suspend.patch + mac80211_fixes_for_ieee80211_do_stop_while_suspend_v3.9.patch + gssproxy-backport.patch + ceph-fix.patch + vhost-net-fix-use-after-free-in-vhost_net_flush.patch + ARM currently disabled, requires config changes. (See line 1558) + * Fri Jul 12 2013 Dave Jones - 3.9.9-304 - Disable LATENCYTOP/SCHEDSTATS in non-debug builds. diff --git a/sources b/sources index 372d198..c68e1b2 100644 --- a/sources +++ b/sources @@ -1,2 +1,2 @@ -4348c9b6b2eb3144d601e87c19d5d909 linux-3.9.tar.xz -41f350c2fd6aa14414bf39f173a8e6a3 patch-3.9.9.xz +4f25cd5bec5f8d5a7d935b3f2ccb8481 linux-3.10.tar.xz +0e7f2a767ef3b3643856c96af3409af3 patch-3.10.1.xz diff --git a/tulip-dma-debug-error.patch b/tulip-dma-debug-error.patch deleted file mode 100644 index 0ac631f..0000000 --- a/tulip-dma-debug-error.patch +++ /dev/null @@ -1,32 +0,0 @@ -commit 2087ac1fc6fd9bbb1f7e16889e984e0af0510b4b -Author: Neil Horman -Date: Thu Jun 13 15:25:45 2013 -0400 - - tulip: Properly check dma mapping result - - Tulip throws an error when dma debugging is enabled, as it doesn't properly - check dma mapping results with dma_mapping_error() durring tx ring refills. - - Easy fix, just add it in, and drop the frame if the mapping is bad - - Signed-off-by: Neil Horman - CC: Grant Grundler - CC: "David S. Miller" - -diff --git a/drivers/net/ethernet/dec/tulip/interrupt.c b/drivers/net/ethernet/dec/tulip/interrupt.c -index 28a5e42..92306b3 100644 ---- a/drivers/net/ethernet/dec/tulip/interrupt.c -+++ b/drivers/net/ethernet/dec/tulip/interrupt.c -@@ -76,6 +76,12 @@ int tulip_refill_rx(struct net_device *dev) - - mapping = pci_map_single(tp->pdev, skb->data, PKT_BUF_SZ, - PCI_DMA_FROMDEVICE); -+ if (dma_mapping_error(&tp->pdev->dev, mapping)) { -+ dev_kfree_skb(skb); -+ tp->rx_buffers[entry].skb = NULL; -+ break; -+ } -+ - tp->rx_buffers[entry].mapping = mapping; - - tp->rx_ring[entry].buffer1 = cpu_to_le32(mapping); diff --git a/vfio-Set-container-device-mode.patch b/vfio-Set-container-device-mode.patch deleted file mode 100644 index 68e825a..0000000 --- a/vfio-Set-container-device-mode.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 664e9386bd05dbdfecfb28d6cf2fde983aabc65c Mon Sep 17 00:00:00 2001 -From: Alex Williamson -Date: Tue, 30 Apr 2013 15:42:28 -0600 -Subject: [PATCH] vfio: Set container device mode - -Minor 0 is the VFIO container device (/dev/vfio/vfio). On it's own -the container does not provide a user with any privileged access. It -only supports API version check and extension check ioctls. Only by -attaching a VFIO group to the container does it gain any access. Set -the mode of the container to allow access. - -Signed-off-by: Alex Williamson ---- - drivers/vfio/vfio.c | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/drivers/vfio/vfio.c b/drivers/vfio/vfio.c -index ac7423b..acb7121 100644 ---- a/drivers/vfio/vfio.c -+++ b/drivers/vfio/vfio.c -@@ -27,6 +27,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -1359,6 +1360,9 @@ static const struct file_operations vfio_device_fops = { - */ - static char *vfio_devnode(struct device *dev, umode_t *mode) - { -+ if (MINOR(dev->devt) == 0) -+ *mode = S_IRUGO | S_IWUGO; -+ - return kasprintf(GFP_KERNEL, "vfio/%s", dev_name(dev)); - } - --- -1.8.1.4 - diff --git a/vfio-fix-crash-on-rmmod.patch b/vfio-fix-crash-on-rmmod.patch deleted file mode 100644 index 9f89b4d..0000000 --- a/vfio-fix-crash-on-rmmod.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 9a6aa279d3d17af73a029fa40654e92f4e75e8bb Mon Sep 17 00:00:00 2001 -From: Alexey Kardashevskiy -Date: Wed, 5 Jun 2013 08:54:16 -0600 -Subject: [PATCH] vfio: fix crash on rmmod - -devtmpfs_delete_node() calls devnode() callback with mode==NULL but -vfio still tries to write there. - -The patch fixes this. - -Signed-off-by: Alexey Kardashevskiy -Signed-off-by: Alex Williamson ---- - drivers/vfio/vfio.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/drivers/vfio/vfio.c b/drivers/vfio/vfio.c -index acb7121..6d78736 100644 ---- a/drivers/vfio/vfio.c -+++ b/drivers/vfio/vfio.c -@@ -1360,7 +1360,7 @@ static const struct file_operations vfio_device_fops = { - */ - static char *vfio_devnode(struct device *dev, umode_t *mode) - { -- if (MINOR(dev->devt) == 0) -+ if (mode && (MINOR(dev->devt) == 0)) - *mode = S_IRUGO | S_IWUGO; - - return kasprintf(GFP_KERNEL, "vfio/%s", dev_name(dev)); --- -1.8.1.4 -