summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThorsten Leemhuis <fedora@leemhuis.info>2016-10-29 09:55:28 +0200
committerThorsten Leemhuis <fedora@leemhuis.info>2016-10-29 09:55:28 +0200
commitaa4ca391b76ea754ea66262e2e6316fd018f2c03 (patch)
tree979953d8e1595290306952688b655c0aaffd6768
parent4c58d35e51eed200456a782486863d857023c2de (diff)
parent1fb17f8293b0dfdfcd5ca5b3839ddddc077e6b6e (diff)
downloadkernel-4.8.5-300.vanilla.knurd.1.fc23.tar.gz
kernel-4.8.5-300.vanilla.knurd.1.fc23.tar.xz
kernel-4.8.5-300.vanilla.knurd.1.fc23.zip
Merge remote-tracking branch 'origin/f25' into f25-user-thl-vanilla-fedorakernel-4.8.5-300.vanilla.knurd.1.fc25kernel-4.8.5-300.vanilla.knurd.1.fc23
-rw-r--r--0001-HID-input-ignore-System-Control-application-usages-i.patch75
-rw-r--r--bcm283x-vc4-fixes.patch311
-rw-r--r--drm_i915_skl_Backport_watermark_fixes_for_4.8.y.patch1247
-rw-r--r--i8042-skip-selftest-asus-laptops.patch373
-rw-r--r--kernel.spec25
-rw-r--r--sources2
-rw-r--r--v3-vfio-pci-Fix-integer-overflows-bitmask-check.patch102
7 files changed, 1758 insertions, 377 deletions
diff --git a/0001-HID-input-ignore-System-Control-application-usages-i.patch b/0001-HID-input-ignore-System-Control-application-usages-i.patch
new file mode 100644
index 000000000..9920598c2
--- /dev/null
+++ b/0001-HID-input-ignore-System-Control-application-usages-i.patch
@@ -0,0 +1,75 @@
+From 1989dada7ce07848196991c9ebf25ff9c5f14d4e Mon Sep 17 00:00:00 2001
+From: Benjamin Tissoires <benjamin.tissoires@redhat.com>
+Date: Tue, 13 Sep 2016 11:52:37 +0200
+Subject: [PATCH] HID: input: ignore System Control application usages if not
+ System Controls
+
+Microsoft is reusing its report descriptor again and again, and part of it
+looks like this:
+
+0x05, 0x01, // Usage Page (Generic Desktop) 299
+0x09, 0x80, // Usage (System Control) 301
+0xa1, 0x01, // Collection (Application) 303
+0x85, 0x03, // Report ID (3) 305
+0x19, 0x00, // Usage Minimum (0) 307
+0x29, 0xff, // Usage Maximum (255) 309
+0x15, 0x00, // Logical Minimum (0) 311
+0x26, 0xff, 0x00, // Logical Maximum (255) 313
+0x81, 0x00, // Input (Data,Arr,Abs) 316
+0xc0, // End Collection 318
+
+While there is nothing wrong in term of processing, we do however blindly
+map the full usage range (it's an array) from 0x00 to 0xff, which creates
+some interesting axis, like ABS_X|Y, and a bunch of ABS_MISC + n.
+
+While libinput and other stacks don't care that much (we can detect them),
+joydev is very happy and attaches itself to the mouse or keyboard.
+
+The problem is that joydev now handles the device as a joystick, but given
+that we have a HID array, it sets all the ABS_* values to 0. And in its
+world, 0 means -32767 (minimum value), which sends spurious events to games
+(think Steam).
+
+It looks like hid-microsoft tries to tackle the very same problem with its
+.report_fixup callback. But fixing the report descriptor is an endless task
+and is quite obfuscated.
+
+So take the hammer, and decide that if the application is meant to be
+System Control, any other usage not in the System Control range should
+be ignored.
+
+Link: https://bugzilla.redhat.com/show_bug.cgi?id=1325354
+Link: https://bugzilla.kernel.org/show_bug.cgi?id=28912
+Link: https://github.com/ValveSoftware/steam-for-linux/issues/3384
+Link: https://bugzilla.redhat.com/show_bug.cgi?id=1325354
+Link: https://bugzilla.kernel.org/show_bug.cgi?id=37982
+
+Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
+Signed-off-by: Jiri Kosina <jkosina@suse.cz>
+---
+ drivers/hid/hid-input.c | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
+index bcfaf32..058919d 100644
+--- a/drivers/hid/hid-input.c
++++ b/drivers/hid/hid-input.c
+@@ -604,6 +604,15 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
+ break;
+ }
+
++ /*
++ * Some lazy vendors declare 255 usages for System Control,
++ * leading to the creation of ABS_X|Y axis and too many others.
++ * It wouldn't be a problem if joydev doesn't consider the
++ * device as a joystick then.
++ */
++ if (field->application == HID_GD_SYSTEM_CONTROL)
++ goto ignore;
++
+ if ((usage->hid & 0xf0) == 0x90) { /* D-pad */
+ switch (usage->hid) {
+ case HID_GD_UP: usage->hat_dir = 1; break;
+--
+2.7.4
+
diff --git a/bcm283x-vc4-fixes.patch b/bcm283x-vc4-fixes.patch
index 89793b62b..afde6e2f2 100644
--- a/bcm283x-vc4-fixes.patch
+++ b/bcm283x-vc4-fixes.patch
@@ -634,3 +634,314 @@ index 9ecd6ff..a4b5370 100644
--
2.9.3
+From c4e634ce412d97f0e61223b2a5b3f8f9600cd4dc Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Fri, 30 Sep 2016 10:07:27 -0700
+Subject: clk: bcm2835: Clamp the PLL's requested rate to the hardware limits.
+
+Fixes setting low-resolution video modes on HDMI. Now the PLLH_PIX
+divider adjusts itself until the PLLH is within bounds.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
+---
+ drivers/clk/bcm/clk-bcm2835.c | 11 ++++-------
+ 1 file changed, 4 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
+index b68bf57..8c7763f 100644
+--- a/drivers/clk/bcm/clk-bcm2835.c
++++ b/drivers/clk/bcm/clk-bcm2835.c
+@@ -502,8 +502,12 @@ static long bcm2835_pll_rate_from_divisors(unsigned long parent_rate,
+ static long bcm2835_pll_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *parent_rate)
+ {
++ struct bcm2835_pll *pll = container_of(hw, struct bcm2835_pll, hw);
++ const struct bcm2835_pll_data *data = pll->data;
+ u32 ndiv, fdiv;
+
++ rate = clamp(rate, data->min_rate, data->max_rate);
++
+ bcm2835_pll_choose_ndiv_and_fdiv(rate, *parent_rate, &ndiv, &fdiv);
+
+ return bcm2835_pll_rate_from_divisors(*parent_rate, ndiv, fdiv, 1);
+@@ -608,13 +612,6 @@ static int bcm2835_pll_set_rate(struct clk_hw *hw,
+ u32 ana[4];
+ int i;
+
+- if (rate < data->min_rate || rate > data->max_rate) {
+- dev_err(cprman->dev, "%s: rate out of spec: %lu vs (%lu, %lu)\n",
+- clk_hw_get_name(hw), rate,
+- data->min_rate, data->max_rate);
+- return -EINVAL;
+- }
+-
+ if (rate > data->max_fb_rate) {
+ use_fb_prediv = true;
+ rate /= 2;
+--
+cgit v0.12
+
+From e69fdcca836f0b81a2260b69429c8622a80ea891 Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Wed, 1 Jun 2016 12:05:33 -0700
+Subject: clk: bcm2835: Mark the VPU clock as critical
+
+The VPU clock is also the clock for our AXI bus, so we really can't
+disable it. This might have happened during boot if, for example,
+uart1 (aux_uart clock) probed and was then disabled before the other
+consumers of the VPU clock had probed.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+Acked-by: Martin Sperl <kernel@martin.sperl.org>
+Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
+---
+ drivers/clk/bcm/clk-bcm2835.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
+index 7a79708..d9db03c 100644
+--- a/drivers/clk/bcm/clk-bcm2835.c
++++ b/drivers/clk/bcm/clk-bcm2835.c
+@@ -443,6 +443,8 @@ struct bcm2835_clock_data {
+ /* Number of fractional bits in the divider */
+ u32 frac_bits;
+
++ u32 flags;
++
+ bool is_vpu_clock;
+ bool is_mash_clock;
+ };
+@@ -1230,7 +1232,7 @@ static struct clk *bcm2835_register_clock(struct bcm2835_cprman *cprman,
+ init.parent_names = parents;
+ init.num_parents = data->num_mux_parents;
+ init.name = data->name;
+- init.flags = CLK_IGNORE_UNUSED;
++ init.flags = data->flags | CLK_IGNORE_UNUSED;
+
+ if (data->is_vpu_clock) {
+ init.ops = &bcm2835_vpu_clock_clk_ops;
+@@ -1649,6 +1651,7 @@ static const struct bcm2835_clk_desc clk_desc_array[] = {
+ .div_reg = CM_VPUDIV,
+ .int_bits = 12,
+ .frac_bits = 8,
++ .flags = CLK_IS_CRITICAL,
+ .is_vpu_clock = true),
+
+ /* clocks with per parent mux */
+--
+cgit v0.12
+
+From eddcbe8398fc7103fccd22aa6df6917caf0123bf Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Wed, 1 Jun 2016 12:05:34 -0700
+Subject: clk: bcm2835: Mark GPIO clocks enabled at boot as critical
+
+These divide off of PLLD_PER and are used for the ethernet and wifi
+PHYs source PLLs. Neither of them is currently represented by a phy
+device that would grab the clock for us.
+
+This keeps other drivers from killing the networking PHYs when they
+disable their own clocks and trigger PLLD_PER's refcount going to 0.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+Acked-by: Martin Sperl <kernel@martin.sperl.org>
+Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
+---
+ drivers/clk/bcm/clk-bcm2835.c | 10 +++++++++-
+ 1 file changed, 9 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
+index d9db03c..400615b 100644
+--- a/drivers/clk/bcm/clk-bcm2835.c
++++ b/drivers/clk/bcm/clk-bcm2835.c
+@@ -1239,6 +1239,12 @@ static struct clk *bcm2835_register_clock(struct bcm2835_cprman *cprman,
+ } else {
+ init.ops = &bcm2835_clock_clk_ops;
+ init.flags |= CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE;
++
++ /* If the clock wasn't actually enabled at boot, it's not
++ * critical.
++ */
++ if (!(cprman_read(cprman, data->ctl_reg) & CM_ENABLE))
++ init.flags &= ~CLK_IS_CRITICAL;
+ }
+
+ clock = devm_kzalloc(cprman->dev, sizeof(*clock), GFP_KERNEL);
+@@ -1708,13 +1714,15 @@ static const struct bcm2835_clk_desc clk_desc_array[] = {
+ .div_reg = CM_GP1DIV,
+ .int_bits = 12,
+ .frac_bits = 12,
++ .flags = CLK_IS_CRITICAL,
+ .is_mash_clock = true),
+ [BCM2835_CLOCK_GP2] = REGISTER_PER_CLK(
+ .name = "gp2",
+ .ctl_reg = CM_GP2CTL,
+ .div_reg = CM_GP2DIV,
+ .int_bits = 12,
+- .frac_bits = 12),
++ .frac_bits = 12,
++ .flags = CLK_IS_CRITICAL),
+
+ /* HDMI state machine */
+ [BCM2835_CLOCK_HSM] = REGISTER_PER_CLK(
+--
+cgit v0.12
+
+From 9e400c5cc5c105e35216ac59a346f20cdd7613be Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Wed, 1 Jun 2016 12:05:35 -0700
+Subject: clk: bcm2835: Mark the CM SDRAM clock's parent as critical
+
+While the SDRAM is being driven by its dedicated PLL most of the time,
+there is a little loop running in the firmware that periodically turns
+on the CM SDRAM clock (using its pre-initialized parent) and switches
+SDRAM to using the CM clock to do PVT recalibration.
+
+This avoids system hangs if we choose SDRAM's parent for some other
+clock, then disable that clock.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+Acked-by: Martin Sperl <kernel@martin.sperl.org>
+Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
+---
+ drivers/clk/bcm/clk-bcm2835.c | 25 +++++++++++++++++++++++++
+ 1 file changed, 25 insertions(+)
+
+diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
+index 400615b..c6420b3 100644
+--- a/drivers/clk/bcm/clk-bcm2835.c
++++ b/drivers/clk/bcm/clk-bcm2835.c
+@@ -36,6 +36,7 @@
+
+ #include <linux/clk-provider.h>
+ #include <linux/clkdev.h>
++#include <linux/clk.h>
+ #include <linux/clk/bcm2835.h>
+ #include <linux/debugfs.h>
+ #include <linux/module.h>
+@@ -1801,6 +1802,25 @@ static const struct bcm2835_clk_desc clk_desc_array[] = {
+ .ctl_reg = CM_PERIICTL),
+ };
+
++/*
++ * Permanently take a reference on the parent of the SDRAM clock.
++ *
++ * While the SDRAM is being driven by its dedicated PLL most of the
++ * time, there is a little loop running in the firmware that
++ * periodically switches the SDRAM to using our CM clock to do PVT
++ * recalibration, with the assumption that the previously configured
++ * SDRAM parent is still enabled and running.
++ */
++static int bcm2835_mark_sdc_parent_critical(struct clk *sdc)
++{
++ struct clk *parent = clk_get_parent(sdc);
++
++ if (IS_ERR(parent))
++ return PTR_ERR(parent);
++
++ return clk_prepare_enable(parent);
++}
++
+ static int bcm2835_clk_probe(struct platform_device *pdev)
+ {
+ struct device *dev = &pdev->dev;
+@@ -1810,6 +1830,7 @@ static int bcm2835_clk_probe(struct platform_device *pdev)
+ const struct bcm2835_clk_desc *desc;
+ const size_t asize = ARRAY_SIZE(clk_desc_array);
+ size_t i;
++ int ret;
+
+ cprman = devm_kzalloc(dev,
+ sizeof(*cprman) + asize * sizeof(*clks),
+@@ -1840,6 +1861,10 @@ static int bcm2835_clk_probe(struct platform_device *pdev)
+ clks[i] = desc->clk_register(cprman, desc->data);
+ }
+
++ ret = bcm2835_mark_sdc_parent_critical(clks[BCM2835_CLOCK_SDRAM]);
++ if (ret)
++ return ret;
++
+ return of_clk_add_provider(dev->of_node, of_clk_src_onecell_get,
+ &cprman->onecell);
+ }
+--
+cgit v0.12
+
+From 67615c588a059b731df9d019edc3c561d8006ec9 Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Wed, 1 Jun 2016 12:05:36 -0700
+Subject: clk: bcm2835: Skip PLLC clocks when deciding on a new clock parent
+
+If the firmware had set up a clock to source from PLLC, go along with
+it. But if we're looking for a new parent, we don't want to switch it
+to PLLC because the firmware will force PLLC (and thus the AXI bus
+clock) to different frequencies during over-temp/under-voltage,
+without notification to Linux.
+
+On my system, this moves the Linux-enabled HDMI state machine and DSI1
+escape clock over to plld_per from pllc_per. EMMC still ends up on
+pllc_per, because the firmware had set it up to use that.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+Fixes: 41691b8862e2 ("clk: bcm2835: Add support for programming the audio domain clocks")
+Acked-by: Martin Sperl <kernel@martin.sperl.org>
+Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
+---
+ drivers/clk/bcm/clk-bcm2835.c | 23 +++++++++++++++++++++++
+ 1 file changed, 23 insertions(+)
+
+diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
+index c6420b3..e8a9646a 100644
+--- a/drivers/clk/bcm/clk-bcm2835.c
++++ b/drivers/clk/bcm/clk-bcm2835.c
+@@ -1009,16 +1009,28 @@ static int bcm2835_clock_set_rate(struct clk_hw *hw,
+ return 0;
+ }
+
++static bool
++bcm2835_clk_is_pllc(struct clk_hw *hw)
++{
++ if (!hw)
++ return false;
++
++ return strncmp(clk_hw_get_name(hw), "pllc", 4) == 0;
++}
++
+ static int bcm2835_clock_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
+ {
+ struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
+ struct clk_hw *parent, *best_parent = NULL;
++ bool current_parent_is_pllc;
+ unsigned long rate, best_rate = 0;
+ unsigned long prate, best_prate = 0;
+ size_t i;
+ u32 div;
+
++ current_parent_is_pllc = bcm2835_clk_is_pllc(clk_hw_get_parent(hw));
++
+ /*
+ * Select parent clock that results in the closest but lower rate
+ */
+@@ -1026,6 +1038,17 @@ static int bcm2835_clock_determine_rate(struct clk_hw *hw,
+ parent = clk_hw_get_parent_by_index(hw, i);
+ if (!parent)
+ continue;
++
++ /*
++ * Don't choose a PLLC-derived clock as our parent
++ * unless it had been manually set that way. PLLC's
++ * frequency gets adjusted by the firmware due to
++ * over-temp or under-voltage conditions, without
++ * prior notification to our clock consumer.
++ */
++ if (bcm2835_clk_is_pllc(parent) && !current_parent_is_pllc)
++ continue;
++
+ prate = clk_hw_get_rate(parent);
+ div = bcm2835_clock_choose_div(hw, req->rate, prate, true);
+ rate = bcm2835_clock_rate_from_divisor(clock, prate, div);
+--
+cgit v0.12
+
diff --git a/drm_i915_skl_Backport_watermark_fixes_for_4.8.y.patch b/drm_i915_skl_Backport_watermark_fixes_for_4.8.y.patch
new file mode 100644
index 000000000..cf2a7dfef
--- /dev/null
+++ b/drm_i915_skl_Backport_watermark_fixes_for_4.8.y.patch
@@ -0,0 +1,1247 @@
+From: Lyude <lyude@redhat.com>
+To: kernel@lists.fedoraproject.org
+Subject: [PATCH 0/5] drm/i915/skl: Backport watermark fixes for 4.8.y
+Date: Thu, 27 Oct 2016 10:49:34 -0400
+
+Hey! Hans de Geode requested that I also send this patch series to you guys.
+These are the fixes for most (maybe even all) of the issues with display
+flickering that users have been seeing on Skylake systems. They've already been
+submitted for inclusion in 4.8.y.
+
+ Original message
+
+Now that these have finally made it into 4.9, it's time to finally backport
+these fixes. Skylake has been a mess in multi-monitor setups for a while now
+because up until recently we've been updating the watermarks on Skylake just
+like we would for previous generations of Intel GPUs. This means updating
+attributes for each plane, and then only after they've been updated writing
+their new watermark values.
+
+The problem with this approach is Skylake has double buffered watermark
+registers that are flipped at the same time as the rest of the plane registers.
+This means that the original approach will leave planes active with new
+attributes but without the required watermark programming that would ensure the
+display pipe reads enough data from each plane. As a result, pipes start to
+underrun and the user's displays starts to flicker heavily. Usually in response
+to plugging in new monitors, or moving cursors from one screen to another
+(which triggers a plane and watermark update).
+
+Additionally, issues were found with the original code for configuring ddb,
+display data buffer, allocations between display planes on Skylake. On Skylake
+all planes have space allocated to them in the ddb, and the hardware requires
+that these allocations never overlap at any point in time. Because ddb
+allocations were not updated alongside plane attributes despite also being
+double buffered registers armed by plane updates, planes were likely to get
+stuck momentarily with ddb allocations that overlapped one another. This would
+also lead to pipe underruns and display flickering.
+
+The new approach fixes this problem by making sure that on Skylake, attributes
+for display planes are always updated at the same time as the watermarks, and
+pipes are updated in an order that ensures their ddb allocations don't
+overlap at any point between plane updates. This ensures the display pipes are
+always programmed correctly, and dramatically reduces the chance of display
+flickering.
+
+(note: my e-mail has changed since these patches were upstreamed, and I updated
+the e-mails in these patches to reflect this. if this is wrong I will be happy
+to update and resend the patches).
+
+Lyude (4):
+ drm/i915/skl: Update plane watermarks atomically during plane updates
+ drm/i915: Move CRTC updating in atomic_commit into it's own hook
+ drm/i915/skl: Update DDB values atomically with wms/plane attrs
+ drm/i915/skl: Don't try to update plane watermarks if they haven't
+ changed
+
+Paulo Zanoni (1):
+ drm/i915/gen9: only add the planes actually affected by ddb changes
+
+ drivers/gpu/drm/i915/i915_drv.h | 2 +
+ drivers/gpu/drm/i915/intel_display.c | 189 +++++++++++++++++++-----
+ drivers/gpu/drm/i915/intel_drv.h | 12 ++
+ drivers/gpu/drm/i915/intel_pm.c | 271 ++++++++++++++---------------------
+ drivers/gpu/drm/i915/intel_sprite.c | 14 ++
+ 5 files changed, 289 insertions(+), 199 deletions(-)
+
+--
+2.7.4
+_______________________________________________
+kernel mailing list -- kernel@lists.fedoraproject.org
+To unsubscribe send an email to kernel-leave@lists.fedoraproject.org
+
+From: Lyude <lyude@redhat.com>
+To: kernel@lists.fedoraproject.org
+Subject: [PATCH 1/5] drm/i915/skl: Update plane watermarks atomically
+ during plane updates
+Date: Thu, 27 Oct 2016 10:49:35 -0400
+
+commit c145d3be1c313184be71d2629fd575561b7e38d4 upstream
+
+Thanks to Ville for suggesting this as a potential solution to pipe
+underruns on Skylake.
+
+On Skylake all of the registers for configuring planes, including the
+registers for configuring their watermarks, are double buffered. New
+values written to them won't take effect until said registers are
+"armed", which is done by writing to the PLANE_SURF (or in the case of
+cursor planes, the CURBASE register) register.
+
+With this in mind, up until now we've been updating watermarks on skl
+like this:
+
+ non-modeset {
+ - calculate (during atomic check phase)
+ - finish_atomic_commit:
+ - intel_pre_plane_update:
+ - intel_update_watermarks()
+ - {vblank happens; new watermarks + old plane values => underrun }
+ - drm_atomic_helper_commit_planes_on_crtc:
+ - start vblank evasion
+ - write new plane registers
+ - end vblank evasion
+ }
+
+ or
+
+ modeset {
+ - calculate (during atomic check phase)
+ - finish_atomic_commit:
+ - crtc_enable:
+ - intel_update_watermarks()
+ - {vblank happens; new watermarks + old plane values => underrun }
+ - drm_atomic_helper_commit_planes_on_crtc:
+ - start vblank evasion
+ - write new plane registers
+ - end vblank evasion
+ }
+
+Now we update watermarks atomically like this:
+
+ non-modeset {
+ - calculate (during atomic check phase)
+ - finish_atomic_commit:
+ - intel_pre_plane_update:
+ - intel_update_watermarks() (wm values aren't written yet)
+ - drm_atomic_helper_commit_planes_on_crtc:
+ - start vblank evasion
+ - write new plane registers
+ - write new wm values
+ - end vblank evasion
+ }
+
+ modeset {
+ - calculate (during atomic check phase)
+ - finish_atomic_commit:
+ - crtc_enable:
+ - intel_update_watermarks() (actual wm values aren't written
+ yet)
+ - drm_atomic_helper_commit_planes_on_crtc:
+ - start vblank evasion
+ - write new plane registers
+ - write new wm values
+ - end vblank evasion
+ }
+
+So this patch moves all of the watermark writes into the right place;
+inside of the vblank evasion where we update all of the registers for
+each plane. While this patch doesn't fix everything, it does allow us to
+update the watermark values in the way the hardware expects us to.
+
+Changes since original patch series:
+ - Remove mutex_lock/mutex_unlock since they don't do anything and we're
+ not touching global state
+ - Move skl_write_cursor_wm/skl_write_plane_wm functions into
+ intel_pm.c, make externally visible
+ - Add skl_write_plane_wm calls to skl_update_plane
+ - Fix conditional for for loop in skl_write_plane_wm (level < max_level
+ should be level <= max_level)
+ - Make diagram in commit more accurate to what's actually happening
+ - Add Fixes:
+
+Changes since v1:
+ - Use IS_GEN9() instead of IS_SKYLAKE() since these fixes apply to more
+ then just Skylake
+ - Update description to make it clear this patch doesn't fix everything
+ - Check if pipes were actually changed before writing watermarks
+
+Changes since v2:
+ - Write PIPE_WM_LINETIME during vblank evasion
+
+Changes since v3:
+ - Rebase against new SAGV patch changes
+
+Changes since v4:
+ - Add a parameter to choose what skl_wm_values struct to use when
+ writing new plane watermarks
+
+Changes since v5:
+ - Remove cursor ddb entry write in skl_write_cursor_wm(), defer until
+ patch 6
+ - Write WM_LINETIME in intel_begin_crtc_commit()
+
+Changes since v6:
+ - Remove redundant dirty_pipes check in skl_write_plane_wm (we check
+ this in all places where we call this function, and it was supposed
+ to have been removed earlier anyway)
+ - In i9xx_update_cursor(), use dev_priv->info.gen >= 9 instead of
+ IS_GEN9(dev_priv). We do this everywhere else and I'd imagine this
+ needs to be done for gen10 as well
+
+Changes since v7:
+ - Fix rebase fail (unused variable obj)
+ - Make struct skl_wm_values *wm const
+ - Fix indenting
+ - Use INTEL_GEN() instead of dev_priv->info.gen
+
+Changes since v8:
+ - Don't forget calls to skl_write_plane_wm() when disabling planes
+ - Use INTEL_GEN(), not INTEL_INFO()->gen in intel_begin_crtc_commit()
+
+Fixes: 2d41c0b59afc ("drm/i915/skl: SKL Watermark Computation")
+Signed-off-by: Lyude <lyude@redhat.com>
+Reviewed-by: Matt Roper <matthew.d.roper@intel.com>
+Cc: stable@vger.kernel.org
+Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
+Cc: Daniel Vetter <daniel.vetter@intel.com>
+Cc: Radhakrishna Sripada <radhakrishna.sripada@intel.com>
+Cc: Hans de Goede <hdegoede@redhat.com>
+Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
+Link: http://patchwork.freedesktop.org/patch/msgid/1471884608-10671-1-git-send-email-cpaul@redhat.com
+Link: http://patchwork.freedesktop.org/patch/msgid/1471884608-10671-1-git-send-email-cpaul@redhat.com
+---
+ drivers/gpu/drm/i915/intel_display.c | 21 +++++++++++++--
+ drivers/gpu/drm/i915/intel_drv.h | 5 ++++
+ drivers/gpu/drm/i915/intel_pm.c | 50 ++++++++++++++++++++++++------------
+ drivers/gpu/drm/i915/intel_sprite.c | 6 +++++
+ 4 files changed, 64 insertions(+), 18 deletions(-)
+
+diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
+index 175595f..1ae587f 100644
+--- a/drivers/gpu/drm/i915/intel_display.c
++++ b/drivers/gpu/drm/i915/intel_display.c
+@@ -2980,6 +2980,7 @@ static void skylake_update_primary_plane(struct drm_plane *plane,
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->base.crtc);
+ struct drm_framebuffer *fb = plane_state->base.fb;
+ struct drm_i915_gem_object *obj = intel_fb_obj(fb);
++ const struct skl_wm_values *wm = &dev_priv->wm.skl_results;
+ int pipe = intel_crtc->pipe;
+ u32 plane_ctl, stride_div, stride;
+ u32 tile_height, plane_offset, plane_size;
+@@ -3031,6 +3032,9 @@ static void skylake_update_primary_plane(struct drm_plane *plane,
+ intel_crtc->adjusted_x = x_offset;
+ intel_crtc->adjusted_y = y_offset;
+
++ if (wm->dirty_pipes & drm_crtc_mask(&intel_crtc->base))
++ skl_write_plane_wm(intel_crtc, wm, 0);
++
+ I915_WRITE(PLANE_CTL(pipe, 0), plane_ctl);
+ I915_WRITE(PLANE_OFFSET(pipe, 0), plane_offset);
+ I915_WRITE(PLANE_SIZE(pipe, 0), plane_size);
+@@ -3061,7 +3065,10 @@ static void skylake_disable_primary_plane(struct drm_plane *primary,
+ {
+ struct drm_device *dev = crtc->dev;
+ struct drm_i915_private *dev_priv = to_i915(dev);
+- int pipe = to_intel_crtc(crtc)->pipe;
++ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
++ int pipe = intel_crtc->pipe;
++
++ skl_write_plane_wm(intel_crtc, &dev_priv->wm.skl_results, 0);
+
+ I915_WRITE(PLANE_CTL(pipe, 0), 0);
+ I915_WRITE(PLANE_SURF(pipe, 0), 0);
+@@ -10306,9 +10313,13 @@ static void i9xx_update_cursor(struct drm_crtc *crtc, u32 base,
+ struct drm_device *dev = crtc->dev;
+ struct drm_i915_private *dev_priv = to_i915(dev);
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
++ const struct skl_wm_values *wm = &dev_priv->wm.skl_results;
+ int pipe = intel_crtc->pipe;
+ uint32_t cntl = 0;
+
++ if (INTEL_GEN(dev_priv) >= 9 && wm->dirty_pipes & drm_crtc_mask(crtc))
++ skl_write_cursor_wm(intel_crtc, wm);
++
+ if (plane_state && plane_state->visible) {
+ cntl = MCURSOR_GAMMA_ENABLE;
+ switch (plane_state->base.crtc_w) {
+@@ -14221,10 +14232,12 @@ static void intel_begin_crtc_commit(struct drm_crtc *crtc,
+ struct drm_crtc_state *old_crtc_state)
+ {
+ struct drm_device *dev = crtc->dev;
++ struct drm_i915_private *dev_priv = to_i915(dev);
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ struct intel_crtc_state *old_intel_state =
+ to_intel_crtc_state(old_crtc_state);
+ bool modeset = needs_modeset(crtc->state);
++ enum pipe pipe = intel_crtc->pipe;
+
+ /* Perform vblank evasion around commit operation */
+ intel_pipe_update_start(intel_crtc);
+@@ -14239,8 +14252,12 @@ static void intel_begin_crtc_commit(struct drm_crtc *crtc,
+
+ if (to_intel_crtc_state(crtc->state)->update_pipe)
+ intel_update_pipe_config(intel_crtc, old_intel_state);
+- else if (INTEL_INFO(dev)->gen >= 9)
++ else if (INTEL_GEN(dev_priv) >= 9) {
+ skl_detach_scalers(intel_crtc);
++
++ I915_WRITE(PIPE_WM_LINETIME(pipe),
++ dev_priv->wm.skl_hw.wm_linetime[pipe]);
++ }
+ }
+
+ static void intel_finish_crtc_commit(struct drm_crtc *crtc,
+diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
+index ff399b9..58a8152 100644
+--- a/drivers/gpu/drm/i915/intel_drv.h
++++ b/drivers/gpu/drm/i915/intel_drv.h
+@@ -1719,6 +1719,11 @@ void skl_ddb_get_hw_state(struct drm_i915_private *dev_priv,
+ bool skl_can_enable_sagv(struct drm_atomic_state *state);
+ int skl_enable_sagv(struct drm_i915_private *dev_priv);
+ int skl_disable_sagv(struct drm_i915_private *dev_priv);
++void skl_write_cursor_wm(struct intel_crtc *intel_crtc,
++ const struct skl_wm_values *wm);
++void skl_write_plane_wm(struct intel_crtc *intel_crtc,
++ const struct skl_wm_values *wm,
++ int plane);
+ uint32_t ilk_pipe_pixel_rate(const struct intel_crtc_state *pipe_config);
+ bool ilk_disable_lp_wm(struct drm_device *dev);
+ int sanitize_rc6_option(struct drm_i915_private *dev_priv, int enable_rc6);
+diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
+index 2d24813..29bed77 100644
+--- a/drivers/gpu/drm/i915/intel_pm.c
++++ b/drivers/gpu/drm/i915/intel_pm.c
+@@ -3828,6 +3828,39 @@ static void skl_ddb_entry_write(struct drm_i915_private *dev_priv,
+ I915_WRITE(reg, 0);
+ }
+
++void skl_write_plane_wm(struct intel_crtc *intel_crtc,
++ const struct skl_wm_values *wm,
++ int plane)
++{
++ struct drm_crtc *crtc = &intel_crtc->base;
++ struct drm_device *dev = crtc->dev;
++ struct drm_i915_private *dev_priv = to_i915(dev);
++ int level, max_level = ilk_wm_max_level(dev);
++ enum pipe pipe = intel_crtc->pipe;
++
++ for (level = 0; level <= max_level; level++) {
++ I915_WRITE(PLANE_WM(pipe, plane, level),
++ wm->plane[pipe][plane][level]);
++ }
++ I915_WRITE(PLANE_WM_TRANS(pipe, plane), wm->plane_trans[pipe][plane]);
++}
++
++void skl_write_cursor_wm(struct intel_crtc *intel_crtc,
++ const struct skl_wm_values *wm)
++{
++ struct drm_crtc *crtc = &intel_crtc->base;
++ struct drm_device *dev = crtc->dev;
++ struct drm_i915_private *dev_priv = to_i915(dev);
++ int level, max_level = ilk_wm_max_level(dev);
++ enum pipe pipe = intel_crtc->pipe;
++
++ for (level = 0; level <= max_level; level++) {
++ I915_WRITE(CUR_WM(pipe, level),
++ wm->plane[pipe][PLANE_CURSOR][level]);
++ }
++ I915_WRITE(CUR_WM_TRANS(pipe), wm->plane_trans[pipe][PLANE_CURSOR]);
++}
++
+ static void skl_write_wm_values(struct drm_i915_private *dev_priv,
+ const struct skl_wm_values *new)
+ {
+@@ -3835,7 +3868,7 @@ static void skl_write_wm_values(struct drm_i915_private *dev_priv,
+ struct intel_crtc *crtc;
+
+ for_each_intel_crtc(dev, crtc) {
+- int i, level, max_level = ilk_wm_max_level(dev);
++ int i;
+ enum pipe pipe = crtc->pipe;
+
+ if ((new->dirty_pipes & drm_crtc_mask(&crtc->base)) == 0)
+@@ -3843,21 +3876,6 @@ static void skl_write_wm_values(struct drm_i915_private *dev_priv,
+ if (!crtc->active)
+ continue;
+
+- I915_WRITE(PIPE_WM_LINETIME(pipe), new->wm_linetime[pipe]);
+-
+- for (level = 0; level <= max_level; level++) {
+- for (i = 0; i < intel_num_planes(crtc); i++)
+- I915_WRITE(PLANE_WM(pipe, i, level),
+- new->plane[pipe][i][level]);
+- I915_WRITE(CUR_WM(pipe, level),
+- new->plane[pipe][PLANE_CURSOR][level]);
+- }
+- for (i = 0; i < intel_num_planes(crtc); i++)
+- I915_WRITE(PLANE_WM_TRANS(pipe, i),
+- new->plane_trans[pipe][i]);
+- I915_WRITE(CUR_WM_TRANS(pipe),
+- new->plane_trans[pipe][PLANE_CURSOR]);
+-
+ for (i = 0; i < intel_num_planes(crtc); i++) {
+ skl_ddb_entry_write(dev_priv,
+ PLANE_BUF_CFG(pipe, i),
+diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c
+index 7c08e4f..d8bfff1 100644
+--- a/drivers/gpu/drm/i915/intel_sprite.c
++++ b/drivers/gpu/drm/i915/intel_sprite.c
+@@ -203,6 +203,9 @@ skl_update_plane(struct drm_plane *drm_plane,
+ struct intel_plane *intel_plane = to_intel_plane(drm_plane);
+ struct drm_framebuffer *fb = plane_state->base.fb;
+ struct drm_i915_gem_object *obj = intel_fb_obj(fb);
++ const struct skl_wm_values *wm = &dev_priv->wm.skl_results;
++ struct drm_crtc *crtc = crtc_state->base.crtc;
++ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ const int pipe = intel_plane->pipe;
+ const int plane = intel_plane->plane + 1;
+ u32 plane_ctl, stride_div, stride;
+@@ -238,6 +241,9 @@ skl_update_plane(struct drm_plane *drm_plane,
+ crtc_w--;
+ crtc_h--;
+
++ if (wm->dirty_pipes & drm_crtc_mask(crtc))
++ skl_write_plane_wm(intel_crtc, wm, plane);
++
+ if (key->flags) {
+ I915_WRITE(PLANE_KEYVAL(pipe, plane), key->min_value);
+ I915_WRITE(PLANE_KEYMAX(pipe, plane), key->max_value);
+--
+2.7.4
+_______________________________________________
+kernel mailing list -- kernel@lists.fedoraproject.org
+To unsubscribe send an email to kernel-leave@lists.fedoraproject.org
+
+From: Lyude <lyude@redhat.com>
+To: kernel@lists.fedoraproject.org
+Subject: [PATCH 2/5] drm/i915: Move CRTC updating in atomic_commit into
+ it's own hook
+Date: Thu, 27 Oct 2016 10:49:36 -0400
+
+commit 896e5bb022bce64e29ce2e1b2fc2a7476d311a15 upstream
+
+Since we have to write ddb allocations at the same time as we do other
+plane updates, we're going to need to be able to control the order in
+which we execute modesets on each pipe. The easiest way to do this is to
+just factor this section of intel_atomic_commit_tail()
+(intel_atomic_commit() for stable branches) into it's own function, and
+add an appropriate display function hook for it.
+
+Based off of Matt Rope's suggestions
+
+Changes since v1:
+ - Drop pipe_config->base.active check in intel_update_crtcs() since we
+ check that before calling the function
+
+Signed-off-by: Lyude <cpaul@redhat.com>
+Reviewed-by: Matt Roper <matthew.d.roper@intel.com>
+Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
+Cc: Daniel Vetter <daniel.vetter@intel.com>
+Cc: Radhakrishna Sripada <radhakrishna.sripada@intel.com>
+Cc: Hans de Goede <hdegoede@redhat.com>
+
+Signed-off-by: Lyude <lyude@redhat.com>
+Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
+Link: http://patchwork.freedesktop.org/patch/msgid/1471961565-28540-1-git-send-email-cpaul@redhat.com
+---
+ drivers/gpu/drm/i915/i915_drv.h | 2 +
+ drivers/gpu/drm/i915/intel_display.c | 74 +++++++++++++++++++++++++-----------
+ 2 files changed, 54 insertions(+), 22 deletions(-)
+
+diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
+index f68c789..ad75dbd 100644
+--- a/drivers/gpu/drm/i915/i915_drv.h
++++ b/drivers/gpu/drm/i915/i915_drv.h
+@@ -631,6 +631,8 @@ struct drm_i915_display_funcs {
+ struct intel_crtc_state *crtc_state);
+ void (*crtc_enable)(struct drm_crtc *crtc);
+ void (*crtc_disable)(struct drm_crtc *crtc);
++ void (*update_crtcs)(struct drm_atomic_state *state,
++ unsigned int *crtc_vblank_mask);
+ void (*audio_codec_enable)(struct drm_connector *connector,
+ struct intel_encoder *encoder,
+ const struct drm_display_mode *adjusted_mode);
+diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
+index 1ae587f..e2c46eb 100644
+--- a/drivers/gpu/drm/i915/intel_display.c
++++ b/drivers/gpu/drm/i915/intel_display.c
+@@ -13682,6 +13682,52 @@ static bool needs_vblank_wait(struct intel_crtc_state *crtc_state)
+ return false;
+ }
+
++static void intel_update_crtc(struct drm_crtc *crtc,
++ struct drm_atomic_state *state,
++ struct drm_crtc_state *old_crtc_state,
++ unsigned int *crtc_vblank_mask)
++{
++ struct drm_device *dev = crtc->dev;
++ struct drm_i915_private *dev_priv = to_i915(dev);
++ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
++ struct intel_crtc_state *pipe_config = to_intel_crtc_state(crtc->state);
++ bool modeset = needs_modeset(crtc->state);
++
++ if (modeset) {
++ update_scanline_offset(intel_crtc);
++ dev_priv->display.crtc_enable(crtc);
++ } else {
++ intel_pre_plane_update(to_intel_crtc_state(old_crtc_state));
++ }
++
++ if (drm_atomic_get_existing_plane_state(state, crtc->primary)) {
++ intel_fbc_enable(
++ intel_crtc, pipe_config,
++ to_intel_plane_state(crtc->primary->state));
++ }
++
++ drm_atomic_helper_commit_planes_on_crtc(old_crtc_state);
++
++ if (needs_vblank_wait(pipe_config))
++ *crtc_vblank_mask |= drm_crtc_mask(crtc);
++}
++
++static void intel_update_crtcs(struct drm_atomic_state *state,
++ unsigned int *crtc_vblank_mask)
++{
++ struct drm_crtc *crtc;
++ struct drm_crtc_state *old_crtc_state;
++ int i;
++
++ for_each_crtc_in_state(state, crtc, old_crtc_state, i) {
++ if (!crtc->state->active)
++ continue;
++
++ intel_update_crtc(crtc, state, old_crtc_state,
++ crtc_vblank_mask);
++ }
++}
++
+ static void intel_atomic_commit_tail(struct drm_atomic_state *state)
+ {
+ struct drm_device *dev = state->dev;
+@@ -13780,17 +13826,9 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state)
+ intel_modeset_verify_disabled(dev);
+ }
+
+- /* Now enable the clocks, plane, pipe, and connectors that we set up. */
++ /* Complete the events for pipes that have now been disabled */
+ for_each_crtc_in_state(state, crtc, old_crtc_state, i) {
+- struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ bool modeset = needs_modeset(crtc->state);
+- struct intel_crtc_state *pipe_config =
+- to_intel_crtc_state(crtc->state);
+-
+- if (modeset && crtc->state->active) {
+- update_scanline_offset(to_intel_crtc(crtc));
+- dev_priv->display.crtc_enable(crtc);
+- }
+
+ /* Complete events for now disable pipes here. */
+ if (modeset && !crtc->state->active && crtc->state->event) {
+@@ -13800,21 +13838,11 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state)
+
+ crtc->state->event = NULL;
+ }
+-
+- if (!modeset)
+- intel_pre_plane_update(to_intel_crtc_state(old_crtc_state));
+-
+- if (crtc->state->active &&
+- drm_atomic_get_existing_plane_state(state, crtc->primary))
+- intel_fbc_enable(intel_crtc, pipe_config, to_intel_plane_state(crtc->primary->state));
+-
+- if (crtc->state->active)
+- drm_atomic_helper_commit_planes_on_crtc(old_crtc_state);
+-
+- if (pipe_config->base.active && needs_vblank_wait(pipe_config))
+- crtc_vblank_mask |= 1 << i;
+ }
+
++ /* Now enable the clocks, plane, pipe, and connectors that we set up. */
++ dev_priv->display.update_crtcs(state, &crtc_vblank_mask);
++
+ /* FIXME: We should call drm_atomic_helper_commit_hw_done() here
+ * already, but still need the state for the delayed optimization. To
+ * fix this:
+@@ -15275,6 +15303,8 @@ void intel_init_display_hooks(struct drm_i915_private *dev_priv)
+ dev_priv->display.crtc_disable = i9xx_crtc_disable;
+ }
+
++ dev_priv->display.update_crtcs = intel_update_crtcs;
++
+ /* Returns the core display clock speed */
+ if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv))
+ dev_priv->display.get_display_clock_speed =
+--
+2.7.4
+_______________________________________________
+kernel mailing list -- kernel@lists.fedoraproject.org
+To unsubscribe send an email to kernel-leave@lists.fedoraproject.org
+
+From: Lyude <lyude@redhat.com>
+To: kernel@lists.fedoraproject.org
+Subject: [PATCH 3/5] drm/i915/skl: Update DDB values atomically with
+ wms/plane attrs
+Date: Thu, 27 Oct 2016 10:49:37 -0400
+
+commit 27082493e9c6371b05370a619ab9d2877c5f4726 upstream
+
+Now that we can hook into update_crtcs and control the order in which we
+update CRTCs at each modeset, we can finish the final step of fixing
+Skylake's watermark handling by performing DDB updates at the same time
+as plane updates and watermark updates.
+
+The first major change in this patch is skl_update_crtcs(), which
+handles ensuring that we order each CRTC update in our atomic commits
+properly so that they honor the DDB flush order.
+
+The second major change in this patch is the order in which we flush the
+pipes. While the previous order may have worked, it can't be used in
+this approach since it no longer will do the right thing. For example,
+using the old ddb flush order:
+
+We have pipes A, B, and C enabled, and we're disabling C. Initial ddb
+allocation looks like this:
+
+| A | B |xxxxxxx|
+
+Since we're performing the ddb updates after performing any CRTC
+disablements in intel_atomic_commit_tail(), the space to the right of
+pipe B is unallocated.
+
+1. Flush pipes with new allocation contained into old space. None
+ apply, so we skip this
+2. Flush pipes having their allocation reduced, but overlapping with a
+ previous allocation. None apply, so we also skip this
+3. Flush pipes that got more space allocated. This applies to A and B,
+ giving us the following update order: A, B
+
+This is wrong, since updating pipe A first will cause it to overlap with
+B and potentially burst into flames. Our new order (see the code
+comments for details) would update the pipes in the proper order: B, A.
+
+As well, we calculate the order for each DDB update during the check
+phase, and reference it later in the commit phase when we hit
+skl_update_crtcs().
+
+This long overdue patch fixes the rest of the underruns on Skylake.
+
+Changes since v1:
+ - Add skl_ddb_entry_write() for cursor into skl_write_cursor_wm()
+Changes since v2:
+ - Use the method for updating CRTCs that Ville suggested
+ - In skl_update_wm(), only copy the watermarks for the crtc that was
+ passed to us
+Changes since v3:
+ - Small comment fix in skl_ddb_allocation_overlaps()
+Changes since v4:
+ - Remove the second loop in intel_update_crtcs() and use Ville's
+ suggestion for updating the ddb allocations in the right order
+ - Get rid of the second loop and just use the ddb state as it updates
+ to determine what order to update everything in (thanks for the
+ suggestion Ville)
+ - Simplify skl_ddb_allocation_overlaps()
+ - Split actual overlap checking into it's own helper
+
+Fixes: 0e8fb7ba7ca5 ("drm/i915/skl: Flush the WM configuration")
+Fixes: 8211bd5bdf5e ("drm/i915/skl: Program the DDB allocation")
+[omitting CC for stable, since this patch will need to be changed for
+such backports first]
+
+Testcase: kms_cursor_legacy
+Testcase: plane-all-modeset-transition
+Signed-off-by: Lyude <lyude@redhat.com>
+Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
+Cc: Daniel Vetter <daniel.vetter@intel.com>
+Cc: Radhakrishna Sripada <radhakrishna.sripada@intel.com>
+Cc: Hans de Goede <hdegoede@redhat.com>
+Cc: Matt Roper <matthew.d.roper@intel.com>
+Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
+Link: http://patchwork.freedesktop.org/patch/msgid/1471961565-28540-2-git-send-email-cpaul@redhat.com
+---
+ drivers/gpu/drm/i915/intel_display.c | 93 +++++++++++++---
+ drivers/gpu/drm/i915/intel_drv.h | 7 ++
+ drivers/gpu/drm/i915/intel_pm.c | 200 ++++++++---------------------------
+ 3 files changed, 132 insertions(+), 168 deletions(-)
+
+diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
+index e2c46eb..8086e62 100644
+--- a/drivers/gpu/drm/i915/intel_display.c
++++ b/drivers/gpu/drm/i915/intel_display.c
+@@ -12967,16 +12967,23 @@ static void verify_wm_state(struct drm_crtc *crtc,
+ hw_entry->start, hw_entry->end);
+ }
+
+- /* cursor */
+- hw_entry = &hw_ddb.plane[pipe][PLANE_CURSOR];
+- sw_entry = &sw_ddb->plane[pipe][PLANE_CURSOR];
+-
+- if (!skl_ddb_entry_equal(hw_entry, sw_entry)) {
+- DRM_ERROR("mismatch in DDB state pipe %c cursor "
+- "(expected (%u,%u), found (%u,%u))\n",
+- pipe_name(pipe),
+- sw_entry->start, sw_entry->end,
+- hw_entry->start, hw_entry->end);
++ /*
++ * cursor
++ * If the cursor plane isn't active, we may not have updated it's ddb
++ * allocation. In that case since the ddb allocation will be updated
++ * once the plane becomes visible, we can skip this check
++ */
++ if (intel_crtc->cursor_addr) {
++ hw_entry = &hw_ddb.plane[pipe][PLANE_CURSOR];
++ sw_entry = &sw_ddb->plane[pipe][PLANE_CURSOR];
++
++ if (!skl_ddb_entry_equal(hw_entry, sw_entry)) {
++ DRM_ERROR("mismatch in DDB state pipe %c cursor "
++ "(expected (%u,%u), found (%u,%u))\n",
++ pipe_name(pipe),
++ sw_entry->start, sw_entry->end,
++ hw_entry->start, hw_entry->end);
++ }
+ }
+ }
+
+@@ -13728,6 +13735,65 @@ static void intel_update_crtcs(struct drm_atomic_state *state,
+ }
+ }
+
++static void skl_update_crtcs(struct drm_atomic_state *state,
++ unsigned int *crtc_vblank_mask)
++{
++ struct drm_device *dev = state->dev;
++ struct drm_i915_private *dev_priv = to_i915(dev);
++ struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
++ struct drm_crtc *crtc;
++ struct drm_crtc_state *old_crtc_state;
++ struct skl_ddb_allocation *new_ddb = &intel_state->wm_results.ddb;
++ struct skl_ddb_allocation *cur_ddb = &dev_priv->wm.skl_hw.ddb;
++ unsigned int updated = 0;
++ bool progress;
++ enum pipe pipe;
++
++ /*
++ * Whenever the number of active pipes changes, we need to make sure we
++ * update the pipes in the right order so that their ddb allocations
++ * never overlap with eachother inbetween CRTC updates. Otherwise we'll
++ * cause pipe underruns and other bad stuff.
++ */
++ do {
++ int i;
++ progress = false;
++
++ for_each_crtc_in_state(state, crtc, old_crtc_state, i) {
++ bool vbl_wait = false;
++ unsigned int cmask = drm_crtc_mask(crtc);
++ pipe = to_intel_crtc(crtc)->pipe;
++
++ if (updated & cmask || !crtc->state->active)
++ continue;
++ if (skl_ddb_allocation_overlaps(state, cur_ddb, new_ddb,
++ pipe))
++ continue;
++
++ updated |= cmask;
++
++ /*
++ * If this is an already active pipe, it's DDB changed,
++ * and this isn't the last pipe that needs updating
++ * then we need to wait for a vblank to pass for the
++ * new ddb allocation to take effect.
++ */
++ if (!skl_ddb_allocation_equals(cur_ddb, new_ddb, pipe) &&
++ !crtc->state->active_changed &&
++ intel_state->wm_results.dirty_pipes != updated)
++ vbl_wait = true;
++
++ intel_update_crtc(crtc, state, old_crtc_state,
++ crtc_vblank_mask);
++
++ if (vbl_wait)
++ intel_wait_for_vblank(dev, pipe);
++
++ progress = true;
++ }
++ } while (progress);
++}
++
+ static void intel_atomic_commit_tail(struct drm_atomic_state *state)
+ {
+ struct drm_device *dev = state->dev;
+@@ -15303,8 +15369,6 @@ void intel_init_display_hooks(struct drm_i915_private *dev_priv)
+ dev_priv->display.crtc_disable = i9xx_crtc_disable;
+ }
+
+- dev_priv->display.update_crtcs = intel_update_crtcs;
+-
+ /* Returns the core display clock speed */
+ if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv))
+ dev_priv->display.get_display_clock_speed =
+@@ -15394,6 +15458,11 @@ void intel_init_display_hooks(struct drm_i915_private *dev_priv)
+ skl_modeset_calc_cdclk;
+ }
+
++ if (dev_priv->info.gen >= 9)
++ dev_priv->display.update_crtcs = skl_update_crtcs;
++ else
++ dev_priv->display.update_crtcs = intel_update_crtcs;
++
+ switch (INTEL_INFO(dev_priv)->gen) {
+ case 2:
+ dev_priv->display.queue_flip = intel_gen2_queue_flip;
+diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
+index 58a8152..83674c6 100644
+--- a/drivers/gpu/drm/i915/intel_drv.h
++++ b/drivers/gpu/drm/i915/intel_drv.h
+@@ -1719,6 +1719,13 @@ void skl_ddb_get_hw_state(struct drm_i915_private *dev_priv,
+ bool skl_can_enable_sagv(struct drm_atomic_state *state);
+ int skl_enable_sagv(struct drm_i915_private *dev_priv);
+ int skl_disable_sagv(struct drm_i915_private *dev_priv);
++bool skl_ddb_allocation_equals(const struct skl_ddb_allocation *old,
++ const struct skl_ddb_allocation *new,
++ enum pipe pipe);
++bool skl_ddb_allocation_overlaps(struct drm_atomic_state *state,
++ const struct skl_ddb_allocation *old,
++ const struct skl_ddb_allocation *new,
++ enum pipe pipe);
+ void skl_write_cursor_wm(struct intel_crtc *intel_crtc,
+ const struct skl_wm_values *wm);
+ void skl_write_plane_wm(struct intel_crtc *intel_crtc,
+diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
+index 29bed77..a0c5c4e 100644
+--- a/drivers/gpu/drm/i915/intel_pm.c
++++ b/drivers/gpu/drm/i915/intel_pm.c
+@@ -3843,6 +3843,11 @@ void skl_write_plane_wm(struct intel_crtc *intel_crtc,
+ wm->plane[pipe][plane][level]);
+ }
+ I915_WRITE(PLANE_WM_TRANS(pipe, plane), wm->plane_trans[pipe][plane]);
++
++ skl_ddb_entry_write(dev_priv, PLANE_BUF_CFG(pipe, plane),
++ &wm->ddb.plane[pipe][plane]);
++ skl_ddb_entry_write(dev_priv, PLANE_NV12_BUF_CFG(pipe, plane),
++ &wm->ddb.y_plane[pipe][plane]);
+ }
+
+ void skl_write_cursor_wm(struct intel_crtc *intel_crtc,
+@@ -3859,170 +3864,46 @@ void skl_write_cursor_wm(struct intel_crtc *intel_crtc,
+ wm->plane[pipe][PLANE_CURSOR][level]);
+ }
+ I915_WRITE(CUR_WM_TRANS(pipe), wm->plane_trans[pipe][PLANE_CURSOR]);
+-}
+-
+-static void skl_write_wm_values(struct drm_i915_private *dev_priv,
+- const struct skl_wm_values *new)
+-{
+- struct drm_device *dev = &dev_priv->drm;
+- struct intel_crtc *crtc;
+-
+- for_each_intel_crtc(dev, crtc) {
+- int i;
+- enum pipe pipe = crtc->pipe;
+-
+- if ((new->dirty_pipes & drm_crtc_mask(&crtc->base)) == 0)
+- continue;
+- if (!crtc->active)
+- continue;
+-
+- for (i = 0; i < intel_num_planes(crtc); i++) {
+- skl_ddb_entry_write(dev_priv,
+- PLANE_BUF_CFG(pipe, i),
+- &new->ddb.plane[pipe][i]);
+- skl_ddb_entry_write(dev_priv,
+- PLANE_NV12_BUF_CFG(pipe, i),
+- &new->ddb.y_plane[pipe][i]);
+- }
+
+- skl_ddb_entry_write(dev_priv, CUR_BUF_CFG(pipe),
+- &new->ddb.plane[pipe][PLANE_CURSOR]);
+- }
++ skl_ddb_entry_write(dev_priv, CUR_BUF_CFG(pipe),
++ &wm->ddb.plane[pipe][PLANE_CURSOR]);
+ }
+
+-/*
+- * When setting up a new DDB allocation arrangement, we need to correctly
+- * sequence the times at which the new allocations for the pipes are taken into
+- * account or we'll have pipes fetching from space previously allocated to
+- * another pipe.
+- *
+- * Roughly the sequence looks like:
+- * 1. re-allocate the pipe(s) with the allocation being reduced and not
+- * overlapping with a previous light-up pipe (another way to put it is:
+- * pipes with their new allocation strickly included into their old ones).
+- * 2. re-allocate the other pipes that get their allocation reduced
+- * 3. allocate the pipes having their allocation increased
+- *
+- * Steps 1. and 2. are here to take care of the following case:
+- * - Initially DDB looks like this:
+- * | B | C |
+- * - enable pipe A.
+- * - pipe B has a reduced DDB allocation that overlaps with the old pipe C
+- * allocation
+- * | A | B | C |
+- *
+- * We need to sequence the re-allocation: C, B, A (and not B, C, A).
+- */
+-
+-static void
+-skl_wm_flush_pipe(struct drm_i915_private *dev_priv, enum pipe pipe, int pass)
++bool skl_ddb_allocation_equals(const struct skl_ddb_allocation *old,
++ const struct skl_ddb_allocation *new,
++ enum pipe pipe)
+ {
+- int plane;
+-
+- DRM_DEBUG_KMS("flush pipe %c (pass %d)\n", pipe_name(pipe), pass);
+-
+- for_each_plane(dev_priv, pipe, plane) {
+- I915_WRITE(PLANE_SURF(pipe, plane),
+- I915_READ(PLANE_SURF(pipe, plane)));
+- }
+- I915_WRITE(CURBASE(pipe), I915_READ(CURBASE(pipe)));
++ return new->pipe[pipe].start == old->pipe[pipe].start &&
++ new->pipe[pipe].end == old->pipe[pipe].end;
+ }
+
+-static bool
+-skl_ddb_allocation_included(const struct skl_ddb_allocation *old,
+- const struct skl_ddb_allocation *new,
+- enum pipe pipe)
++static inline bool skl_ddb_entries_overlap(const struct skl_ddb_entry *a,
++ const struct skl_ddb_entry *b)
+ {
+- uint16_t old_size, new_size;
+-
+- old_size = skl_ddb_entry_size(&old->pipe[pipe]);
+- new_size = skl_ddb_entry_size(&new->pipe[pipe]);
+-
+- return old_size != new_size &&
+- new->pipe[pipe].start >= old->pipe[pipe].start &&
+- new->pipe[pipe].end <= old->pipe[pipe].end;
++ return a->start < b->end && b->start < a->end;
+ }
+
+-static void skl_flush_wm_values(struct drm_i915_private *dev_priv,
+- struct skl_wm_values *new_values)
++bool skl_ddb_allocation_overlaps(struct drm_atomic_state *state,
++ const struct skl_ddb_allocation *old,
++ const struct skl_ddb_allocation *new,
++ enum pipe pipe)
+ {
+- struct drm_device *dev = &dev_priv->drm;
+- struct skl_ddb_allocation *cur_ddb, *new_ddb;
+- bool reallocated[I915_MAX_PIPES] = {};
+- struct intel_crtc *crtc;
+- enum pipe pipe;
+-
+- new_ddb = &new_values->ddb;
+- cur_ddb = &dev_priv->wm.skl_hw.ddb;
+-
+- /*
+- * First pass: flush the pipes with the new allocation contained into
+- * the old space.
+- *
+- * We'll wait for the vblank on those pipes to ensure we can safely
+- * re-allocate the freed space without this pipe fetching from it.
+- */
+- for_each_intel_crtc(dev, crtc) {
+- if (!crtc->active)
+- continue;
+-
+- pipe = crtc->pipe;
+-
+- if (!skl_ddb_allocation_included(cur_ddb, new_ddb, pipe))
+- continue;
+-
+- skl_wm_flush_pipe(dev_priv, pipe, 1);
+- intel_wait_for_vblank(dev, pipe);
+-
+- reallocated[pipe] = true;
+- }
+-
+-
+- /*
+- * Second pass: flush the pipes that are having their allocation
+- * reduced, but overlapping with a previous allocation.
+- *
+- * Here as well we need to wait for the vblank to make sure the freed
+- * space is not used anymore.
+- */
+- for_each_intel_crtc(dev, crtc) {
+- if (!crtc->active)
+- continue;
++ struct drm_device *dev = state->dev;
++ struct intel_crtc *intel_crtc;
++ enum pipe otherp;
+
+- pipe = crtc->pipe;
++ for_each_intel_crtc(dev, intel_crtc) {
++ otherp = intel_crtc->pipe;
+
+- if (reallocated[pipe])
++ if (otherp == pipe)
+ continue;
+
+- if (skl_ddb_entry_size(&new_ddb->pipe[pipe]) <
+- skl_ddb_entry_size(&cur_ddb->pipe[pipe])) {
+- skl_wm_flush_pipe(dev_priv, pipe, 2);
+- intel_wait_for_vblank(dev, pipe);
+- reallocated[pipe] = true;
+- }
++ if (skl_ddb_entries_overlap(&new->pipe[pipe],
++ &old->pipe[otherp]))
++ return true;
+ }
+
+- /*
+- * Third pass: flush the pipes that got more space allocated.
+- *
+- * We don't need to actively wait for the update here, next vblank
+- * will just get more DDB space with the correct WM values.
+- */
+- for_each_intel_crtc(dev, crtc) {
+- if (!crtc->active)
+- continue;
+-
+- pipe = crtc->pipe;
+-
+- /*
+- * At this point, only the pipes more space than before are
+- * left to re-allocate.
+- */
+- if (reallocated[pipe])
+- continue;
+-
+- skl_wm_flush_pipe(dev_priv, pipe, 3);
+- }
++ return false;
+ }
+
+ static int skl_update_pipe_wm(struct drm_crtc_state *cstate,
+@@ -4224,7 +4105,7 @@ static void skl_update_wm(struct drm_crtc *crtc)
+ struct skl_wm_values *hw_vals = &dev_priv->wm.skl_hw;
+ struct intel_crtc_state *cstate = to_intel_crtc_state(crtc->state);
+ struct skl_pipe_wm *pipe_wm = &cstate->wm.skl.optimal;
+- int pipe;
++ enum pipe pipe = intel_crtc->pipe;
+
+ if ((results->dirty_pipes & drm_crtc_mask(crtc)) == 0)
+ return;
+@@ -4233,15 +4114,22 @@ static void skl_update_wm(struct drm_crtc *crtc)
+
+ mutex_lock(&dev_priv->wm.wm_mutex);
+
+- skl_write_wm_values(dev_priv, results);
+- skl_flush_wm_values(dev_priv, results);
+-
+ /*
+- * Store the new configuration (but only for the pipes that have
+- * changed; the other values weren't recomputed).
++ * If this pipe isn't active already, we're going to be enabling it
++ * very soon. Since it's safe to update a pipe's ddb allocation while
++ * the pipe's shut off, just do so here. Already active pipes will have
++ * their watermarks updated once we update their planes.
+ */
+- for_each_pipe_masked(dev_priv, pipe, results->dirty_pipes)
+- skl_copy_wm_for_pipe(hw_vals, results, pipe);
++ if (crtc->state->active_changed) {
++ int plane;
++
++ for (plane = 0; plane < intel_num_planes(intel_crtc); plane++)
++ skl_write_plane_wm(intel_crtc, results, plane);
++
++ skl_write_cursor_wm(intel_crtc, results);
++ }
++
++ skl_copy_wm_for_pipe(hw_vals, results, pipe);
+
+ mutex_unlock(&dev_priv->wm.wm_mutex);
+ }
+--
+2.7.4
+_______________________________________________
+kernel mailing list -- kernel@lists.fedoraproject.org
+To unsubscribe send an email to kernel-leave@lists.fedoraproject.org
+
+From: Lyude <lyude@redhat.com>
+To: kernel@lists.fedoraproject.org
+Subject: [PATCH 4/5] drm/i915/skl: Don't try to update plane watermarks if
+ they haven't changed
+Date: Thu, 27 Oct 2016 10:49:38 -0400
+
+commit ccebc23b57c313229526dc76383ce82f5e0b9001 upstream
+
+i915 sometimes needs to disable planes in the middle of an atomic
+commit, and then reenable them later in the same commit. Because of
+this, we can't make the assumption that the state of the plane actually
+changed. Since the state of the plane hasn't actually changed, neither
+have it's watermarks. And if the watermarks hasn't changed then we
+haven't populated skl_results with anything, which means we'll end up
+zeroing out a plane's watermarks in the middle of the atomic commit
+without restoring them later.
+
+Simple reproduction recipe:
+ - Get a SKL laptop, launch any kind of X session
+ - Get two extra monitors
+ - Keep hotplugging both displays (so that the display configuration
+ jumps from 1 active pipe to 3 active pipes and back)
+ - Eventually underrun
+
+Changes since v1:
+ - Fix incorrect use of "it's"
+Changes since v2:
+ - Add reproduction recipe
+
+Signed-off-by: Lyude <lyude@redhat.com>
+Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
+Fixes: 62e0fb880123 ("drm/i915/skl: Update plane watermarks atomically during plane updates")
+Testcase: kms_plane
+Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
+Link: http://patchwork.freedesktop.org/patch/msgid/1472488288-27280-1-git-send-email-cpaul@redhat.com
+Cc: drm-intel-fixes@lists.freedesktop.org
+---
+ drivers/gpu/drm/i915/intel_display.c | 7 ++++++-
+ drivers/gpu/drm/i915/intel_sprite.c | 8 ++++++++
+ 2 files changed, 14 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
+index 8086e62..85d161a 100644
+--- a/drivers/gpu/drm/i915/intel_display.c
++++ b/drivers/gpu/drm/i915/intel_display.c
+@@ -3068,7 +3068,12 @@ static void skylake_disable_primary_plane(struct drm_plane *primary,
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ int pipe = intel_crtc->pipe;
+
+- skl_write_plane_wm(intel_crtc, &dev_priv->wm.skl_results, 0);
++ /*
++ * We only populate skl_results on watermark updates, and if the
++ * plane's visiblity isn't actually changing neither is its watermarks.
++ */
++ if (!to_intel_plane_state(crtc->primary->state)->visible)
++ skl_write_plane_wm(intel_crtc, &dev_priv->wm.skl_results, 0);
+
+ I915_WRITE(PLANE_CTL(pipe, 0), 0);
+ I915_WRITE(PLANE_SURF(pipe, 0), 0);
+diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c
+index d8bfff1..4178849 100644
+--- a/drivers/gpu/drm/i915/intel_sprite.c
++++ b/drivers/gpu/drm/i915/intel_sprite.c
+@@ -314,6 +314,14 @@ skl_disable_plane(struct drm_plane *dplane, struct drm_crtc *crtc)
+ const int pipe = intel_plane->pipe;
+ const int plane = intel_plane->plane + 1;
+
++ /*
++ * We only populate skl_results on watermark updates, and if the
++ * plane's visiblity isn't actually changing neither is its watermarks.
++ */
++ if (!to_intel_plane_state(dplane->state)->visible)
++ skl_write_plane_wm(to_intel_crtc(crtc),
++ &dev_priv->wm.skl_results, plane);
++
+ I915_WRITE(PLANE_CTL(pipe, plane), 0);
+
+ I915_WRITE(PLANE_SURF(pipe, plane), 0);
+--
+2.7.4
+_______________________________________________
+kernel mailing list -- kernel@lists.fedoraproject.org
+To unsubscribe send an email to kernel-leave@lists.fedoraproject.org
+
+From: Lyude <lyude@redhat.com>
+To: kernel@lists.fedoraproject.org
+Subject: [PATCH 5/5] drm/i915/gen9: only add the planes actually affected
+ by ddb changes
+Date: Thu, 27 Oct 2016 10:49:39 -0400
+
+From: Paulo Zanoni <paulo.r.zanoni@intel.com>
+
+commit be5c571b2ff3a164d2e14ccc100cb5b2b3d3fb7c upstream
+
+We were previously adding all the planes owned by the CRTC even when
+the ddb partitioning didn't change for them. As a consequence, a lot
+of functions were being called when we were just moving the cursor
+around the screen, such as skylake_update_primary_plane().
+
+This was causing flickering on the primary plane when moving the
+cursor. I'm not 100% sure which operation caused the flickering, but
+we were writing to a lot of registers, so it could be any of these
+writes. With this patch, just moving the mouse won't add the primary
+plane to the commit since it won't trigger a change in DDB
+partitioning.
+
+v2: Use skl_ddb_entry_equal() (Lyude).
+v3: Change Reported-and-bisected-by: to Reported-by: for checkpatch
+
+Fixes: 05a76d3d6ad1 ("drm/i915/skl: Ensure pipes with changed wms get added to the state")
+Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=97888
+Cc: Mike Lothian <mike@fireburn.co.uk>
+Cc: stable@vger.kernel.org
+Reported-by: Mike Lothian <mike@fireburn.co.uk>
+Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
+Signed-off-by: Lyude <lyude@redhat.com>
+Link: http://patchwork.freedesktop.org/patch/msgid/1475177808-29955-1-git-send-email-paulo.r.zanoni@intel.com
+(cherry picked from commit 7f60e200e254cd53ad1bd74a56bdd23e813ac4b7)
+Signed-off-by: Jani Nikula <jani.nikula@intel.com>
+---
+ drivers/gpu/drm/i915/intel_pm.c | 37 ++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 36 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
+index a0c5c4e..5f763f4 100644
+--- a/drivers/gpu/drm/i915/intel_pm.c
++++ b/drivers/gpu/drm/i915/intel_pm.c
+@@ -3940,6 +3940,41 @@ pipes_modified(struct drm_atomic_state *state)
+ return ret;
+ }
+
++int
++skl_ddb_add_affected_planes(struct intel_crtc_state *cstate)
++{
++ struct drm_atomic_state *state = cstate->base.state;
++ struct drm_device *dev = state->dev;
++ struct drm_crtc *crtc = cstate->base.crtc;
++ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
++ struct drm_i915_private *dev_priv = to_i915(dev);
++ struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
++ struct skl_ddb_allocation *new_ddb = &intel_state->wm_results.ddb;
++ struct skl_ddb_allocation *cur_ddb = &dev_priv->wm.skl_hw.ddb;
++ struct drm_plane_state *plane_state;
++ struct drm_plane *plane;
++ enum pipe pipe = intel_crtc->pipe;
++ int id;
++
++ WARN_ON(!drm_atomic_get_existing_crtc_state(state, crtc));
++
++ drm_for_each_plane_mask(plane, dev, crtc->state->plane_mask) {
++ id = skl_wm_plane_id(to_intel_plane(plane));
++
++ if (skl_ddb_entry_equal(&cur_ddb->plane[pipe][id],
++ &new_ddb->plane[pipe][id]) &&
++ skl_ddb_entry_equal(&cur_ddb->y_plane[pipe][id],
++ &new_ddb->y_plane[pipe][id]))
++ continue;
++
++ plane_state = drm_atomic_get_plane_state(state, plane);
++ if (IS_ERR(plane_state))
++ return PTR_ERR(plane_state);
++ }
++
++ return 0;
++}
++
+ static int
+ skl_compute_ddb(struct drm_atomic_state *state)
+ {
+@@ -4004,7 +4039,7 @@ skl_compute_ddb(struct drm_atomic_state *state)
+ if (ret)
+ return ret;
+
+- ret = drm_atomic_add_affected_planes(state, &intel_crtc->base);
++ ret = skl_ddb_add_affected_planes(cstate);
+ if (ret)
+ return ret;
+ }
+--
+2.7.4
+_______________________________________________
+kernel mailing list -- kernel@lists.fedoraproject.org
+To unsubscribe send an email to kernel-leave@lists.fedoraproject.org
+
diff --git a/i8042-skip-selftest-asus-laptops.patch b/i8042-skip-selftest-asus-laptops.patch
deleted file mode 100644
index 351556e04..000000000
--- a/i8042-skip-selftest-asus-laptops.patch
+++ /dev/null
@@ -1,373 +0,0 @@
-From 930e19248e9b61da36c967687ca79c4d5f977919 Mon Sep 17 00:00:00 2001
-From: Marcos Paulo de Souza <marcos.souza.org@gmail.com>
-Date: Sat, 1 Oct 2016 12:07:35 -0700
-Subject: Input: i8042 - skip selftest on ASUS laptops
-
-On suspend/resume cycle, selftest is executed to reset i8042 controller.
-But when this is done in Asus devices, subsequent calls to detect/init
-functions to elantech driver fails. Skipping selftest fixes this problem.
-
-An easier step to reproduce this problem is adding i8042.reset=1 as a
-kernel parameter. On Asus laptops, it'll make the system to start with the
-touchpad already stuck, since psmouse_probe forcibly calls the selftest
-function.
-
-This patch was inspired by John Hiesey's change[1], but, since this problem
-affects a lot of models of Asus, let's avoid running selftests on them.
-
-All models affected by this problem:
-A455LD
-K401LB
-K501LB
-K501LX
-R409L
-V502LX
-X302LA
-X450LCP
-X450LD
-X455LAB
-X455LDB
-X455LF
-Z450LA
-
-[1]: https://marc.info/?l=linux-input&m=144312209020616&w=2
-
-Fixes: "ETPS/2 Elantech Touchpad dies after resume from suspend"
-(https://bugzilla.kernel.org/show_bug.cgi?id=107971)
-
-Signed-off-by: Marcos Paulo de Souza <marcos.souza.org@gmail.com>
-Cc: stable@vger.kernel.org
-Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
----
- Documentation/kernel-parameters.txt | 9 +++-
- drivers/input/serio/i8042-io.h | 2 +-
- drivers/input/serio/i8042-ip22io.h | 2 +-
- drivers/input/serio/i8042-ppcio.h | 2 +-
- drivers/input/serio/i8042-sparcio.h | 2 +-
- drivers/input/serio/i8042-unicore32io.h | 2 +-
- drivers/input/serio/i8042-x86ia64io.h | 96 +++++++++++++++++++++++++++++++--
- drivers/input/serio/i8042.c | 55 +++++++++++++++----
- 8 files changed, 150 insertions(+), 20 deletions(-)
-
-diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
-index 0b3de80..3475b32 100644
---- a/Documentation/kernel-parameters.txt
-+++ b/Documentation/kernel-parameters.txt
-@@ -1409,7 +1409,14 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
- i8042.nopnp [HW] Don't use ACPIPnP / PnPBIOS to discover KBD/AUX
- controllers
- i8042.notimeout [HW] Ignore timeout condition signalled by controller
-- i8042.reset [HW] Reset the controller during init and cleanup
-+ i8042.reset [HW] Reset the controller during init, cleanup and
-+ suspend-to-ram transitions, only during s2r
-+ transitions, or never reset
-+ Format: { 1 | Y | y | 0 | N | n }
-+ 1, Y, y: always reset controller
-+ 0, N, n: don't ever reset controller
-+ Default: only on s2r transitions on x86; most other
-+ architectures force reset to be always executed
- i8042.unlock [HW] Unlock (ignore) the keylock
- i8042.kbdreset [HW] Reset device connected to KBD port
-
-diff --git a/drivers/input/serio/i8042-io.h b/drivers/input/serio/i8042-io.h
-index a5eed2a..34da81c 100644
---- a/drivers/input/serio/i8042-io.h
-+++ b/drivers/input/serio/i8042-io.h
-@@ -81,7 +81,7 @@ static inline int i8042_platform_init(void)
- return -EBUSY;
- #endif
-
-- i8042_reset = 1;
-+ i8042_reset = I8042_RESET_ALWAYS;
- return 0;
- }
-
-diff --git a/drivers/input/serio/i8042-ip22io.h b/drivers/input/serio/i8042-ip22io.h
-index ee1ad27..08a1c10 100644
---- a/drivers/input/serio/i8042-ip22io.h
-+++ b/drivers/input/serio/i8042-ip22io.h
-@@ -61,7 +61,7 @@ static inline int i8042_platform_init(void)
- return -EBUSY;
- #endif
-
-- i8042_reset = 1;
-+ i8042_reset = I8042_RESET_ALWAYS;
-
- return 0;
- }
-diff --git a/drivers/input/serio/i8042-ppcio.h b/drivers/input/serio/i8042-ppcio.h
-index f708c75..1aabea4 100644
---- a/drivers/input/serio/i8042-ppcio.h
-+++ b/drivers/input/serio/i8042-ppcio.h
-@@ -44,7 +44,7 @@ static inline void i8042_write_command(int val)
-
- static inline int i8042_platform_init(void)
- {
-- i8042_reset = 1;
-+ i8042_reset = I8042_RESET_ALWAYS;
- return 0;
- }
-
-diff --git a/drivers/input/serio/i8042-sparcio.h b/drivers/input/serio/i8042-sparcio.h
-index afcd1c1..6231d63 100644
---- a/drivers/input/serio/i8042-sparcio.h
-+++ b/drivers/input/serio/i8042-sparcio.h
-@@ -130,7 +130,7 @@ static int __init i8042_platform_init(void)
- }
- }
-
-- i8042_reset = 1;
-+ i8042_reset = I8042_RESET_ALWAYS;
-
- return 0;
- }
-diff --git a/drivers/input/serio/i8042-unicore32io.h b/drivers/input/serio/i8042-unicore32io.h
-index 73f5cc1..4557475 100644
---- a/drivers/input/serio/i8042-unicore32io.h
-+++ b/drivers/input/serio/i8042-unicore32io.h
-@@ -61,7 +61,7 @@ static inline int i8042_platform_init(void)
- if (!request_mem_region(I8042_REGION_START, I8042_REGION_SIZE, "i8042"))
- return -EBUSY;
-
-- i8042_reset = 1;
-+ i8042_reset = I8042_RESET_ALWAYS;
- return 0;
- }
-
-diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h
-index 68f5f4a..f4bfb4b 100644
---- a/drivers/input/serio/i8042-x86ia64io.h
-+++ b/drivers/input/serio/i8042-x86ia64io.h
-@@ -510,6 +510,90 @@ static const struct dmi_system_id __initconst i8042_dmi_nomux_table[] = {
- { }
- };
-
-+/*
-+ * On some Asus laptops, just running self tests cause problems.
-+ */
-+static const struct dmi_system_id i8042_dmi_noselftest_table[] = {
-+ {
-+ .matches = {
-+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
-+ DMI_MATCH(DMI_PRODUCT_NAME, "A455LD"),
-+ },
-+ },
-+ {
-+ .matches = {
-+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
-+ DMI_MATCH(DMI_PRODUCT_NAME, "K401LB"),
-+ },
-+ },
-+ {
-+ .matches = {
-+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
-+ DMI_MATCH(DMI_PRODUCT_NAME, "K501LB"),
-+ },
-+ },
-+ {
-+ .matches = {
-+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
-+ DMI_MATCH(DMI_PRODUCT_NAME, "K501LX"),
-+ },
-+ },
-+ {
-+ .matches = {
-+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
-+ DMI_MATCH(DMI_PRODUCT_NAME, "R409L"),
-+ },
-+ },
-+ {
-+ .matches = {
-+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
-+ DMI_MATCH(DMI_PRODUCT_NAME, "V502LX"),
-+ },
-+ },
-+ {
-+ .matches = {
-+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
-+ DMI_MATCH(DMI_PRODUCT_NAME, "X302LA"),
-+ },
-+ },
-+ {
-+ .matches = {
-+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
-+ DMI_MATCH(DMI_PRODUCT_NAME, "X450LCP"),
-+ },
-+ },
-+ {
-+ .matches = {
-+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
-+ DMI_MATCH(DMI_PRODUCT_NAME, "X450LD"),
-+ },
-+ },
-+ {
-+ .matches = {
-+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
-+ DMI_MATCH(DMI_PRODUCT_NAME, "X455LAB"),
-+ },
-+ },
-+ {
-+ .matches = {
-+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
-+ DMI_MATCH(DMI_PRODUCT_NAME, "X455LDB"),
-+ },
-+ },
-+ {
-+ .matches = {
-+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
-+ DMI_MATCH(DMI_PRODUCT_NAME, "X455LF"),
-+ },
-+ },
-+ {
-+ .matches = {
-+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
-+ DMI_MATCH(DMI_PRODUCT_NAME, "Z450LA"),
-+ },
-+ },
-+ { }
-+};
- static const struct dmi_system_id __initconst i8042_dmi_reset_table[] = {
- {
- /* MSI Wind U-100 */
-@@ -1072,12 +1156,18 @@ static int __init i8042_platform_init(void)
- return retval;
-
- #if defined(__ia64__)
-- i8042_reset = true;
-+ i8042_reset = I8042_RESET_ALWAYS;
- #endif
-
- #ifdef CONFIG_X86
-- if (dmi_check_system(i8042_dmi_reset_table))
-- i8042_reset = true;
-+ /* Honor module parameter when value is not default */
-+ if (i8042_reset == I8042_RESET_DEFAULT) {
-+ if (dmi_check_system(i8042_dmi_reset_table))
-+ i8042_reset = I8042_RESET_ALWAYS;
-+
-+ if (dmi_check_system(i8042_dmi_noselftest_table))
-+ i8042_reset = I8042_RESET_NEVER;
-+ }
-
- if (dmi_check_system(i8042_dmi_noloop_table))
- i8042_noloop = true;
-diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c
-index b4d3408..674a760 100644
---- a/drivers/input/serio/i8042.c
-+++ b/drivers/input/serio/i8042.c
-@@ -48,9 +48,39 @@ static bool i8042_unlock;
- module_param_named(unlock, i8042_unlock, bool, 0);
- MODULE_PARM_DESC(unlock, "Ignore keyboard lock.");
-
--static bool i8042_reset;
--module_param_named(reset, i8042_reset, bool, 0);
--MODULE_PARM_DESC(reset, "Reset controller during init and cleanup.");
-+enum i8042_controller_reset_mode {
-+ I8042_RESET_NEVER,
-+ I8042_RESET_ALWAYS,
-+ I8042_RESET_ON_S2RAM,
-+#define I8042_RESET_DEFAULT I8042_RESET_ON_S2RAM
-+};
-+static enum i8042_controller_reset_mode i8042_reset = I8042_RESET_DEFAULT;
-+static int i8042_set_reset(const char *val, const struct kernel_param *kp)
-+{
-+ enum i8042_controller_reset_mode *arg = kp->arg;
-+ int error;
-+ bool reset;
-+
-+ if (val) {
-+ error = kstrtobool(val, &reset);
-+ if (error)
-+ return error;
-+ } else {
-+ reset = true;
-+ }
-+
-+ *arg = reset ? I8042_RESET_ALWAYS : I8042_RESET_NEVER;
-+ return 0;
-+}
-+
-+static const struct kernel_param_ops param_ops_reset_param = {
-+ .flags = KERNEL_PARAM_OPS_FL_NOARG,
-+ .set = i8042_set_reset,
-+};
-+#define param_check_reset_param(name, p) \
-+ __param_check(name, p, enum i8042_controller_reset_mode)
-+module_param_named(reset, i8042_reset, reset_param, 0);
-+MODULE_PARM_DESC(reset, "Reset controller on resume, cleanup or both");
-
- static bool i8042_direct;
- module_param_named(direct, i8042_direct, bool, 0);
-@@ -1019,7 +1049,7 @@ static int i8042_controller_init(void)
- * Reset the controller and reset CRT to the original value set by BIOS.
- */
-
--static void i8042_controller_reset(bool force_reset)
-+static void i8042_controller_reset(bool s2r_wants_reset)
- {
- i8042_flush();
-
-@@ -1044,8 +1074,10 @@ static void i8042_controller_reset(bool force_reset)
- * Reset the controller if requested.
- */
-
-- if (i8042_reset || force_reset)
-+ if (i8042_reset == I8042_RESET_ALWAYS ||
-+ (i8042_reset == I8042_RESET_ON_S2RAM && s2r_wants_reset)) {
- i8042_controller_selftest();
-+ }
-
- /*
- * Restore the original control register setting.
-@@ -1110,7 +1142,7 @@ static void i8042_dritek_enable(void)
- * before suspending.
- */
-
--static int i8042_controller_resume(bool force_reset)
-+static int i8042_controller_resume(bool s2r_wants_reset)
- {
- int error;
-
-@@ -1118,7 +1150,8 @@ static int i8042_controller_resume(bool force_reset)
- if (error)
- return error;
-
-- if (i8042_reset || force_reset) {
-+ if (i8042_reset == I8042_RESET_ALWAYS ||
-+ (i8042_reset == I8042_RESET_ON_S2RAM && s2r_wants_reset)) {
- error = i8042_controller_selftest();
- if (error)
- return error;
-@@ -1195,7 +1228,7 @@ static int i8042_pm_resume_noirq(struct device *dev)
-
- static int i8042_pm_resume(struct device *dev)
- {
-- bool force_reset;
-+ bool want_reset;
- int i;
-
- for (i = 0; i < I8042_NUM_PORTS; i++) {
-@@ -1218,9 +1251,9 @@ static int i8042_pm_resume(struct device *dev)
- * off control to the platform firmware, otherwise we can simply restore
- * the mode.
- */
-- force_reset = pm_resume_via_firmware();
-+ want_reset = pm_resume_via_firmware();
-
-- return i8042_controller_resume(force_reset);
-+ return i8042_controller_resume(want_reset);
- }
-
- static int i8042_pm_thaw(struct device *dev)
-@@ -1481,7 +1514,7 @@ static int __init i8042_probe(struct platform_device *dev)
-
- i8042_platform_device = dev;
-
-- if (i8042_reset) {
-+ if (i8042_reset == I8042_RESET_ALWAYS) {
- error = i8042_controller_selftest();
- if (error)
- return error;
---
-cgit v0.12
-
diff --git a/kernel.spec b/kernel.spec
index d51cc2a69..902ac2a84 100644
--- a/kernel.spec
+++ b/kernel.spec
@@ -58,7 +58,7 @@ Summary: The Linux kernel
%define stable_rc 0
# Do we have a -stable update to apply?
-%define stable_update 4
+%define stable_update 5
# Set rpm version accordingly
%if 0%{?stable_update}
%define stablerev %{stable_update}
@@ -617,8 +617,6 @@ Patch502: firmware-Drop-WARN-from-usermodehelper_read_trylock-.patch
# Patch503: drm-i915-turn-off-wc-mmaps.patch
-Patch504: i8042-skip-selftest-asus-laptops.patch
-
Patch508: kexec-uefi-copy-secure_boot-flag-in-boot-params.patch
#CVE-2016-3134 rhbz 1317383 1317384
@@ -642,6 +640,15 @@ Patch848: 0001-cpupower-Correct-return-type-of-cpu_power_is_cpu_onl.patch
#ongoing complaint, full discussion delayed until ksummit/plumbers
Patch849: 0001-iio-Use-event-header-from-kernel-tree.patch
+# CVE-2016-9083 CVE-2016-9084 rhbz 1389258 1389259 1389285
+Patch850: v3-vfio-pci-Fix-integer-overflows-bitmask-check.patch
+
+# Skylake i915 fixes from 4.9
+Patch851: drm_i915_skl_Backport_watermark_fixes_for_4.8.y.patch
+
+#rhbz 1325354
+Patch852: 0001-HID-input-ignore-System-Control-application-usages-i.patch
+
# END OF PATCH DEFINITIONS
%endif
@@ -2181,6 +2188,18 @@ fi
#
#
%changelog
+* Fri Oct 28 2016 Justin M. Forbes <jforbes@fedoraproject.org> - 4.8.5-300
+- Linux v4.8.5
+
+* Thu Oct 27 2016 Justin M. Forbes <jforbes@fedoraproject.org>
+- CVE-2016-9083 CVE-2016-9084 vfio multiple flaws (rhbz 1389258 1389259 1389285)
+- Skylake i915 fixes from 4.9
+- Fix MS input devices identified as joysticks (rhbz 1325354)
+
+* Mon Oct 24 2016 Peter Robinson <pbrobinson@fedoraproject.org> 4.8.4-301
+- Upstream fix for Raspberry Pi to fix setting low-resolution video modes on HDMI
+- A collection of other clock fixes in -next for the RPi
+
* Mon Oct 24 2016 Justin M. Forbes <jforbes@fedoraproject.org> - 4.8.4-300
- Linux v4.8.4
diff --git a/sources b/sources
index 1c4346db9..bfe1e002b 100644
--- a/sources
+++ b/sources
@@ -1,3 +1,3 @@
c1af0afbd3df35c1ccdc7a5118cd2d07 linux-4.8.tar.xz
0dad03f586e835d538d3e0d2cbdb9a28 perf-man-4.8.tar.gz
-4d85e2c59ec33dd7766e18d079e75114 patch-4.8.4.xz
+3b00c3fcfbe05e3cb7702e8db6fee28b patch-4.8.5.xz
diff --git a/v3-vfio-pci-Fix-integer-overflows-bitmask-check.patch b/v3-vfio-pci-Fix-integer-overflows-bitmask-check.patch
new file mode 100644
index 000000000..5278d4486
--- /dev/null
+++ b/v3-vfio-pci-Fix-integer-overflows-bitmask-check.patch
@@ -0,0 +1,102 @@
+From patchwork Wed Oct 12 16:51:24 2016
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+Subject: [v3] vfio/pci: Fix integer overflows, bitmask check
+From: Vlad Tsyrklevich <vlad@tsyrklevich.net>
+X-Patchwork-Id: 9373631
+Message-Id: <1476291084-50737-1-git-send-email-vlad@tsyrklevich.net>
+To: kvm@vger.kernel.org
+Cc: alex.williamson@redhat.com, Vlad Tsyrklevich <vlad@tsyrklevich.net>
+Date: Wed, 12 Oct 2016 18:51:24 +0200
+
+The VFIO_DEVICE_SET_IRQS ioctl did not sufficiently sanitize
+user-supplied integers, potentially allowing memory corruption. This
+patch adds appropriate integer overflow checks, checks the range bounds
+for VFIO_IRQ_SET_DATA_NONE, and also verifies that only single element
+in the VFIO_IRQ_SET_DATA_TYPE_MASK bitmask is set.
+VFIO_IRQ_SET_ACTION_TYPE_MASK is already correctly checked later in
+vfio_pci_set_irqs_ioctl().
+
+Furthermore, a kzalloc is changed to a kcalloc because the use of a
+kzalloc with an integer multiplication allowed an integer overflow
+condition to be reached without this patch. kcalloc checks for overflow
+and should prevent a similar occurrence.
+
+Signed-off-by: Vlad Tsyrklevich <vlad@tsyrklevich.net>
+---
+ drivers/vfio/pci/vfio_pci.c | 33 +++++++++++++++++++++------------
+ drivers/vfio/pci/vfio_pci_intrs.c | 2 +-
+ 2 files changed, 22 insertions(+), 13 deletions(-)
+
+diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c
+index d624a52..031bc08 100644
+--- a/drivers/vfio/pci/vfio_pci.c
++++ b/drivers/vfio/pci/vfio_pci.c
+@@ -829,8 +829,9 @@ static long vfio_pci_ioctl(void *device_data,
+
+ } else if (cmd == VFIO_DEVICE_SET_IRQS) {
+ struct vfio_irq_set hdr;
++ size_t size;
+ u8 *data = NULL;
+- int ret = 0;
++ int max, ret = 0;
+
+ minsz = offsetofend(struct vfio_irq_set, count);
+
+@@ -838,23 +839,31 @@ static long vfio_pci_ioctl(void *device_data,
+ return -EFAULT;
+
+ if (hdr.argsz < minsz || hdr.index >= VFIO_PCI_NUM_IRQS ||
++ hdr.count >= (U32_MAX - hdr.start) ||
+ hdr.flags & ~(VFIO_IRQ_SET_DATA_TYPE_MASK |
+ VFIO_IRQ_SET_ACTION_TYPE_MASK))
+ return -EINVAL;
+
+- if (!(hdr.flags & VFIO_IRQ_SET_DATA_NONE)) {
+- size_t size;
+- int max = vfio_pci_get_irq_count(vdev, hdr.index);
++ max = vfio_pci_get_irq_count(vdev, hdr.index);
++ if (hdr.start >= max || hdr.start + hdr.count > max)
++ return -EINVAL;
+
+- if (hdr.flags & VFIO_IRQ_SET_DATA_BOOL)
+- size = sizeof(uint8_t);
+- else if (hdr.flags & VFIO_IRQ_SET_DATA_EVENTFD)
+- size = sizeof(int32_t);
+- else
+- return -EINVAL;
++ switch (hdr.flags & VFIO_IRQ_SET_DATA_TYPE_MASK) {
++ case VFIO_IRQ_SET_DATA_NONE:
++ size = 0;
++ break;
++ case VFIO_IRQ_SET_DATA_BOOL:
++ size = sizeof(uint8_t);
++ break;
++ case VFIO_IRQ_SET_DATA_EVENTFD:
++ size = sizeof(int32_t);
++ break;
++ default:
++ return -EINVAL;
++ }
+
+- if (hdr.argsz - minsz < hdr.count * size ||
+- hdr.start >= max || hdr.start + hdr.count > max)
++ if (size) {
++ if (hdr.argsz - minsz < hdr.count * size)
+ return -EINVAL;
+
+ data = memdup_user((void __user *)(arg + minsz),
+diff --git a/drivers/vfio/pci/vfio_pci_intrs.c b/drivers/vfio/pci/vfio_pci_intrs.c
+index c2e6089..1c46045 100644
+--- a/drivers/vfio/pci/vfio_pci_intrs.c
++++ b/drivers/vfio/pci/vfio_pci_intrs.c
+@@ -256,7 +256,7 @@ static int vfio_msi_enable(struct vfio_pci_device *vdev, int nvec, bool msix)
+ if (!is_irq_none(vdev))
+ return -EINVAL;
+
+- vdev->ctx = kzalloc(nvec * sizeof(struct vfio_pci_irq_ctx), GFP_KERNEL);
++ vdev->ctx = kcalloc(nvec, sizeof(struct vfio_pci_irq_ctx), GFP_KERNEL);
+ if (!vdev->ctx)
+ return -ENOMEM;
+