diff options
-rw-r--r-- | 0001-HID-input-ignore-System-Control-application-usages-i.patch | 75 | ||||
-rw-r--r-- | bcm283x-vc4-fixes.patch | 311 | ||||
-rw-r--r-- | drm_i915_skl_Backport_watermark_fixes_for_4.8.y.patch | 1247 | ||||
-rw-r--r-- | i8042-skip-selftest-asus-laptops.patch | 373 | ||||
-rw-r--r-- | kernel.spec | 25 | ||||
-rw-r--r-- | sources | 2 | ||||
-rw-r--r-- | v3-vfio-pci-Fix-integer-overflows-bitmask-check.patch | 102 |
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 @@ -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; + |