From: Greg Kroah-Hartman Date: Fri, 13 Jan 2017 10:57:27 +0000 (+0100) Subject: 4.9-stable patches X-Git-Tag: v4.4.43~1 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=fdec6181d7cf1d101b6b168829faf4226eee01cf;p=thirdparty%2Fkernel%2Fstable-queue.git 4.9-stable patches added patches: alsa-usb-audio-add-a-quirk-for-plantronics-bt600.patch drm-i915-gen9-fix-pcode-polling-during-cdclk-change-notification.patch rtlwifi-fix-enter-exit-power_save.patch rtlwifi-rtl_usb-fix-missing-entry-in-usb-driver-s-private-data.patch --- diff --git a/queue-4.9/alsa-usb-audio-add-a-quirk-for-plantronics-bt600.patch b/queue-4.9/alsa-usb-audio-add-a-quirk-for-plantronics-bt600.patch new file mode 100644 index 00000000000..d2290d7724d --- /dev/null +++ b/queue-4.9/alsa-usb-audio-add-a-quirk-for-plantronics-bt600.patch @@ -0,0 +1,32 @@ +From 2e40795c3bf344cfb5220d94566205796e3ef19a Mon Sep 17 00:00:00 2001 +From: Dennis Kadioglu +Date: Mon, 9 Jan 2017 17:10:46 +0100 +Subject: ALSA: usb-audio: Add a quirk for Plantronics BT600 + +From: Dennis Kadioglu + +commit 2e40795c3bf344cfb5220d94566205796e3ef19a upstream. + +Plantronics BT600 does not support reading the sample rate which leads +to many lines of "cannot get freq at ep 0x1" and "cannot get freq at +ep 0x82". This patch adds the USB ID of the BT600 to quirks.c and +avoids those error messages. + +Signed-off-by: Dennis Kadioglu +Signed-off-by: Takashi Iwai +Signed-off-by: Greg Kroah-Hartman + +--- + sound/usb/quirks.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/sound/usb/quirks.c ++++ b/sound/usb/quirks.c +@@ -1135,6 +1135,7 @@ bool snd_usb_get_sample_rate_quirk(struc + case USB_ID(0x045E, 0x076F): /* MS Lifecam HD-6000 */ + case USB_ID(0x045E, 0x0772): /* MS Lifecam Studio */ + case USB_ID(0x045E, 0x0779): /* MS Lifecam HD-3000 */ ++ case USB_ID(0x047F, 0x02F7): /* Plantronics BT-600 */ + case USB_ID(0x047F, 0x0415): /* Plantronics BT-300 */ + case USB_ID(0x047F, 0xAA05): /* Plantronics DA45 */ + case USB_ID(0x04D8, 0xFEEA): /* Benchmark DAC1 Pre */ diff --git a/queue-4.9/drm-i915-gen9-fix-pcode-polling-during-cdclk-change-notification.patch b/queue-4.9/drm-i915-gen9-fix-pcode-polling-during-cdclk-change-notification.patch new file mode 100644 index 00000000000..8d041ef9c80 --- /dev/null +++ b/queue-4.9/drm-i915-gen9-fix-pcode-polling-during-cdclk-change-notification.patch @@ -0,0 +1,222 @@ +From 2c7d0602c815277f7cb7c932b091288710d8aba7 Mon Sep 17 00:00:00 2001 +From: Imre Deak +Date: Mon, 5 Dec 2016 18:27:37 +0200 +Subject: drm/i915/gen9: Fix PCODE polling during CDCLK change notification +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Imre Deak + +commit 2c7d0602c815277f7cb7c932b091288710d8aba7 upstream. + +commit 848496e5902833600f7992f4faa82dc1546051ba +Author: Ville Syrjälä +Date: Wed Jul 13 16:32:03 2016 +0300 + + drm/i915: Wait up to 3ms for the pcu to ack the cdclk change request on SKL + +increased the timeout to match the spec, but we still see a timeout on +at least one SKL. A CDCLK change request following the failed one will +succeed nevertheless. + +I could reproduce this problem easily by running kms_pipe_crc_basic in a +loop. In all failure cases _wait_for() was pre-empted for >3ms and so in +the worst case - when the pre-emption happened right after calculating +timeout__ in _wait_for() - we called skl_cdclk_wait_for_pcu_ready() only +once which failed and so _wait_for() timed out. As opposed to this the +spec says to keep retrying the request for at most a 3ms period. + +To fix this send the first request explicitly to guarantee that there is +3ms between the first and last request. Though this matches the spec, I +noticed that in rare cases this can still time out if we sent only a few +requests (in the worst case 2) _and_ PCODE is busy for some reason even +after a previous request and a 3ms delay. To work around this retry the +polling with pre-emption disabled to maximize the number of requests. +Also increase the timeout to 10ms to account for interrupts that could +reduce the number of requests. With this change I couldn't trigger +the problem. + +v2: +- Use 1ms poll period instead of 10us. (Chris) +v3: +- Poll with pre-emption disabled to increase the number of request + attempts. (Ville, Chris) +- Factor out a helper to poll, it's also needed by the next patch. +v4: +- Pass reply_mask, reply to skl_pcode_request(), instead of assuming the + reply is generic. (Ville) +v5: +- List the request specific timeout values as code comment. (Ville) +v6: +- Try the poll first with preemption enabled. +- Add code comment about first request being queued by PCODE. (Art) +- Add timeout_base_ms argument. (Ville) +v7: +- Clarify code comment about first queued request. (Chris) + +Cc: Ville Syrjälä +Cc: Chris Wilson +Cc: Art Runyan +Cc: # v4.2- : 3b2c171 : drm/i915: Wait up to 3ms +Cc: # v4.2- +Fixes: 5d96d8afcfbb ("drm/i915/skl: Deinit/init the display at suspend/resume") +Reference: https://bugs.freedesktop.org/show_bug.cgi?id=97929 +Testcase: igt/kms_pipe_crc_basic/suspend-read-crc-pipe-B +Signed-off-by: Imre Deak +Reviewed-by: Chris Wilson +Link: http://patchwork.freedesktop.org/patch/msgid/1480955258-26311-1-git-send-email-imre.deak@intel.com +(cherry picked from commit a0b8a1fe34430c3a82258e8cb45f5968bdf31afd) +Signed-off-by: Jani Nikula +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/gpu/drm/i915/i915_drv.h | 2 + drivers/gpu/drm/i915/intel_display.c | 31 ++++---------- + drivers/gpu/drm/i915/intel_pm.c | 75 +++++++++++++++++++++++++++++++++++ + 3 files changed, 87 insertions(+), 21 deletions(-) + +--- a/drivers/gpu/drm/i915/i915_drv.h ++++ b/drivers/gpu/drm/i915/i915_drv.h +@@ -3684,6 +3684,8 @@ extern void intel_display_print_error_st + + int sandybridge_pcode_read(struct drm_i915_private *dev_priv, u32 mbox, u32 *val); + int sandybridge_pcode_write(struct drm_i915_private *dev_priv, u32 mbox, u32 val); ++int skl_pcode_request(struct drm_i915_private *dev_priv, u32 mbox, u32 request, ++ u32 reply_mask, u32 reply, int timeout_base_ms); + + /* intel_sideband.c */ + u32 vlv_punit_read(struct drm_i915_private *dev_priv, u32 addr); +--- a/drivers/gpu/drm/i915/intel_display.c ++++ b/drivers/gpu/drm/i915/intel_display.c +@@ -6262,36 +6262,25 @@ skl_dpll0_disable(struct drm_i915_privat + dev_priv->cdclk_pll.vco = 0; + } + +-static bool skl_cdclk_pcu_ready(struct drm_i915_private *dev_priv) +-{ +- int ret; +- u32 val; +- +- /* inform PCU we want to change CDCLK */ +- val = SKL_CDCLK_PREPARE_FOR_CHANGE; +- mutex_lock(&dev_priv->rps.hw_lock); +- ret = sandybridge_pcode_read(dev_priv, SKL_PCODE_CDCLK_CONTROL, &val); +- mutex_unlock(&dev_priv->rps.hw_lock); +- +- return ret == 0 && (val & SKL_CDCLK_READY_FOR_CHANGE); +-} +- +-static bool skl_cdclk_wait_for_pcu_ready(struct drm_i915_private *dev_priv) +-{ +- return _wait_for(skl_cdclk_pcu_ready(dev_priv), 3000, 10) == 0; +-} +- + static void skl_set_cdclk(struct drm_i915_private *dev_priv, int cdclk, int vco) + { + struct drm_device *dev = &dev_priv->drm; + u32 freq_select, pcu_ack; ++ int ret; + + WARN_ON((cdclk == 24000) != (vco == 0)); + + DRM_DEBUG_DRIVER("Changing CDCLK to %d kHz (VCO %d kHz)\n", cdclk, vco); + +- if (!skl_cdclk_wait_for_pcu_ready(dev_priv)) { +- DRM_ERROR("failed to inform PCU about cdclk change\n"); ++ mutex_lock(&dev_priv->rps.hw_lock); ++ ret = skl_pcode_request(dev_priv, SKL_PCODE_CDCLK_CONTROL, ++ SKL_CDCLK_PREPARE_FOR_CHANGE, ++ SKL_CDCLK_READY_FOR_CHANGE, ++ SKL_CDCLK_READY_FOR_CHANGE, 3); ++ mutex_unlock(&dev_priv->rps.hw_lock); ++ if (ret) { ++ DRM_ERROR("Failed to inform PCU about cdclk change (%d)\n", ++ ret); + return; + } + +--- a/drivers/gpu/drm/i915/intel_pm.c ++++ b/drivers/gpu/drm/i915/intel_pm.c +@@ -7955,6 +7955,81 @@ int sandybridge_pcode_write(struct drm_i + return 0; + } + ++static bool skl_pcode_try_request(struct drm_i915_private *dev_priv, u32 mbox, ++ u32 request, u32 reply_mask, u32 reply, ++ u32 *status) ++{ ++ u32 val = request; ++ ++ *status = sandybridge_pcode_read(dev_priv, mbox, &val); ++ ++ return *status || ((val & reply_mask) == reply); ++} ++ ++/** ++ * skl_pcode_request - send PCODE request until acknowledgment ++ * @dev_priv: device private ++ * @mbox: PCODE mailbox ID the request is targeted for ++ * @request: request ID ++ * @reply_mask: mask used to check for request acknowledgment ++ * @reply: value used to check for request acknowledgment ++ * @timeout_base_ms: timeout for polling with preemption enabled ++ * ++ * Keep resending the @request to @mbox until PCODE acknowledges it, PCODE ++ * reports an error or an overall timeout of @timeout_base_ms+10 ms expires. ++ * The request is acknowledged once the PCODE reply dword equals @reply after ++ * applying @reply_mask. Polling is first attempted with preemption enabled ++ * for @timeout_base_ms and if this times out for another 10 ms with ++ * preemption disabled. ++ * ++ * Returns 0 on success, %-ETIMEDOUT in case of a timeout, <0 in case of some ++ * other error as reported by PCODE. ++ */ ++int skl_pcode_request(struct drm_i915_private *dev_priv, u32 mbox, u32 request, ++ u32 reply_mask, u32 reply, int timeout_base_ms) ++{ ++ u32 status; ++ int ret; ++ ++ WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock)); ++ ++#define COND skl_pcode_try_request(dev_priv, mbox, request, reply_mask, reply, \ ++ &status) ++ ++ /* ++ * Prime the PCODE by doing a request first. Normally it guarantees ++ * that a subsequent request, at most @timeout_base_ms later, succeeds. ++ * _wait_for() doesn't guarantee when its passed condition is evaluated ++ * first, so send the first request explicitly. ++ */ ++ if (COND) { ++ ret = 0; ++ goto out; ++ } ++ ret = _wait_for(COND, timeout_base_ms * 1000, 10); ++ if (!ret) ++ goto out; ++ ++ /* ++ * The above can time out if the number of requests was low (2 in the ++ * worst case) _and_ PCODE was busy for some reason even after a ++ * (queued) request and @timeout_base_ms delay. As a workaround retry ++ * the poll with preemption disabled to maximize the number of ++ * requests. Increase the timeout from @timeout_base_ms to 50ms to ++ * account for interrupts that could reduce the number of these ++ * requests. ++ */ ++ DRM_DEBUG_KMS("PCODE timeout, retrying with preemption disabled\n"); ++ WARN_ON_ONCE(timeout_base_ms > 3); ++ preempt_disable(); ++ ret = wait_for_atomic(COND, 50); ++ preempt_enable(); ++ ++out: ++ return ret ? ret : status; ++#undef COND ++} ++ + static int byt_gpu_freq(struct drm_i915_private *dev_priv, int val) + { + /* diff --git a/queue-4.9/rtlwifi-fix-enter-exit-power_save.patch b/queue-4.9/rtlwifi-fix-enter-exit-power_save.patch new file mode 100644 index 00000000000..1f32fc7602b --- /dev/null +++ b/queue-4.9/rtlwifi-fix-enter-exit-power_save.patch @@ -0,0 +1,186 @@ +From ba9f93f82abafe2552eac942ebb11c2df4f8dd7f Mon Sep 17 00:00:00 2001 +From: Larry Finger +Date: Sat, 26 Nov 2016 14:43:35 -0600 +Subject: rtlwifi: Fix enter/exit power_save + +From: Larry Finger + +commit ba9f93f82abafe2552eac942ebb11c2df4f8dd7f upstream. + +In commit a5ffbe0a1993 ("rtlwifi: Fix scheduling while atomic bug") and +commit a269913c52ad ("rtlwifi: Rework rtl_lps_leave() and rtl_lps_enter() +to use work queue"), an error was introduced in the power-save routines +due to the fact that leaving PS was delayed by the use of a work queue. + +This problem is fixed by detecting if the enter or leave routines are +in interrupt mode. If so, the workqueue is used to place the request. +If in normal mode, the enter or leave routines are called directly. + +Fixes: a269913c52ad ("rtlwifi: Rework rtl_lps_leave() and rtl_lps_enter() to use work queue") +Reported-by: Ping-Ke Shih +Signed-off-by: Larry Finger +Cc: Stable +Signed-off-by: Kalle Valo +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/net/wireless/realtek/rtlwifi/base.c | 8 +++--- + drivers/net/wireless/realtek/rtlwifi/core.c | 9 ++----- + drivers/net/wireless/realtek/rtlwifi/pci.c | 14 +++------- + drivers/net/wireless/realtek/rtlwifi/ps.c | 36 +++++++++++++++++++++------- + 4 files changed, 40 insertions(+), 27 deletions(-) + +--- a/drivers/net/wireless/realtek/rtlwifi/base.c ++++ b/drivers/net/wireless/realtek/rtlwifi/base.c +@@ -1303,12 +1303,13 @@ EXPORT_SYMBOL_GPL(rtl_action_proc); + + static void setup_arp_tx(struct rtl_priv *rtlpriv, struct rtl_ps_ctl *ppsc) + { ++ struct ieee80211_hw *hw = rtlpriv->hw; ++ + rtlpriv->ra.is_special_data = true; + if (rtlpriv->cfg->ops->get_btc_status()) + rtlpriv->btcoexist.btc_ops->btc_special_packet_notify( + rtlpriv, 1); +- rtlpriv->enter_ps = false; +- schedule_work(&rtlpriv->works.lps_change_work); ++ rtl_lps_leave(hw); + ppsc->last_delaylps_stamp_jiffies = jiffies; + } + +@@ -1381,8 +1382,7 @@ u8 rtl_is_special_data(struct ieee80211_ + + if (is_tx) { + rtlpriv->ra.is_special_data = true; +- rtlpriv->enter_ps = false; +- schedule_work(&rtlpriv->works.lps_change_work); ++ rtl_lps_leave(hw); + ppsc->last_delaylps_stamp_jiffies = jiffies; + } + +--- a/drivers/net/wireless/realtek/rtlwifi/core.c ++++ b/drivers/net/wireless/realtek/rtlwifi/core.c +@@ -1150,10 +1150,8 @@ static void rtl_op_bss_info_changed(stru + } else { + mstatus = RT_MEDIA_DISCONNECT; + +- if (mac->link_state == MAC80211_LINKED) { +- rtlpriv->enter_ps = false; +- schedule_work(&rtlpriv->works.lps_change_work); +- } ++ if (mac->link_state == MAC80211_LINKED) ++ rtl_lps_leave(hw); + if (ppsc->p2p_ps_info.p2p_ps_mode > P2P_PS_NONE) + rtl_p2p_ps_cmd(hw, P2P_PS_DISABLE); + mac->link_state = MAC80211_NOLINK; +@@ -1431,8 +1429,7 @@ static void rtl_op_sw_scan_start(struct + } + + if (mac->link_state == MAC80211_LINKED) { +- rtlpriv->enter_ps = false; +- schedule_work(&rtlpriv->works.lps_change_work); ++ rtl_lps_leave(hw); + mac->link_state = MAC80211_LINKED_SCANNING; + } else { + rtl_ips_nic_on(hw); +--- a/drivers/net/wireless/realtek/rtlwifi/pci.c ++++ b/drivers/net/wireless/realtek/rtlwifi/pci.c +@@ -663,11 +663,9 @@ tx_status_ok: + } + + if (((rtlpriv->link_info.num_rx_inperiod + +- rtlpriv->link_info.num_tx_inperiod) > 8) || +- (rtlpriv->link_info.num_rx_inperiod > 2)) { +- rtlpriv->enter_ps = false; +- schedule_work(&rtlpriv->works.lps_change_work); +- } ++ rtlpriv->link_info.num_tx_inperiod) > 8) || ++ (rtlpriv->link_info.num_rx_inperiod > 2)) ++ rtl_lps_leave(hw); + } + + static int _rtl_pci_init_one_rxdesc(struct ieee80211_hw *hw, +@@ -918,10 +916,8 @@ new_trx_end: + } + if (((rtlpriv->link_info.num_rx_inperiod + + rtlpriv->link_info.num_tx_inperiod) > 8) || +- (rtlpriv->link_info.num_rx_inperiod > 2)) { +- rtlpriv->enter_ps = false; +- schedule_work(&rtlpriv->works.lps_change_work); +- } ++ (rtlpriv->link_info.num_rx_inperiod > 2)) ++ rtl_lps_leave(hw); + skb = new_skb; + no_new: + if (rtlpriv->use_new_trx_flow) { +--- a/drivers/net/wireless/realtek/rtlwifi/ps.c ++++ b/drivers/net/wireless/realtek/rtlwifi/ps.c +@@ -407,8 +407,8 @@ void rtl_lps_set_psmode(struct ieee80211 + } + } + +-/*Enter the leisure power save mode.*/ +-void rtl_lps_enter(struct ieee80211_hw *hw) ++/* Interrupt safe routine to enter the leisure power save mode.*/ ++static void rtl_lps_enter_core(struct ieee80211_hw *hw) + { + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); +@@ -444,10 +444,9 @@ void rtl_lps_enter(struct ieee80211_hw * + + spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag); + } +-EXPORT_SYMBOL(rtl_lps_enter); + +-/*Leave the leisure power save mode.*/ +-void rtl_lps_leave(struct ieee80211_hw *hw) ++/* Interrupt safe routine to leave the leisure power save mode.*/ ++static void rtl_lps_leave_core(struct ieee80211_hw *hw) + { + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); +@@ -477,7 +476,6 @@ void rtl_lps_leave(struct ieee80211_hw * + } + spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag); + } +-EXPORT_SYMBOL(rtl_lps_leave); + + /* For sw LPS*/ + void rtl_swlps_beacon(struct ieee80211_hw *hw, void *data, unsigned int len) +@@ -670,12 +668,34 @@ void rtl_lps_change_work_callback(struct + struct rtl_priv *rtlpriv = rtl_priv(hw); + + if (rtlpriv->enter_ps) +- rtl_lps_enter(hw); ++ rtl_lps_enter_core(hw); + else +- rtl_lps_leave(hw); ++ rtl_lps_leave_core(hw); + } + EXPORT_SYMBOL_GPL(rtl_lps_change_work_callback); + ++void rtl_lps_enter(struct ieee80211_hw *hw) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ ++ if (!in_interrupt()) ++ return rtl_lps_enter_core(hw); ++ rtlpriv->enter_ps = true; ++ schedule_work(&rtlpriv->works.lps_change_work); ++} ++EXPORT_SYMBOL_GPL(rtl_lps_enter); ++ ++void rtl_lps_leave(struct ieee80211_hw *hw) ++{ ++ struct rtl_priv *rtlpriv = rtl_priv(hw); ++ ++ if (!in_interrupt()) ++ return rtl_lps_leave_core(hw); ++ rtlpriv->enter_ps = false; ++ schedule_work(&rtlpriv->works.lps_change_work); ++} ++EXPORT_SYMBOL_GPL(rtl_lps_leave); ++ + void rtl_swlps_wq_callback(void *data) + { + struct rtl_works *rtlworks = container_of_dwork_rtl(data, diff --git a/queue-4.9/rtlwifi-rtl_usb-fix-missing-entry-in-usb-driver-s-private-data.patch b/queue-4.9/rtlwifi-rtl_usb-fix-missing-entry-in-usb-driver-s-private-data.patch new file mode 100644 index 00000000000..dd12b1c4456 --- /dev/null +++ b/queue-4.9/rtlwifi-rtl_usb-fix-missing-entry-in-usb-driver-s-private-data.patch @@ -0,0 +1,34 @@ +From 60f59ce0278557f7896d5158ae6d12a4855a72cc Mon Sep 17 00:00:00 2001 +From: Larry Finger +Date: Wed, 21 Dec 2016 11:18:55 -0600 +Subject: rtlwifi: rtl_usb: Fix missing entry in USB driver's private data + +From: Larry Finger + +commit 60f59ce0278557f7896d5158ae6d12a4855a72cc upstream. + +These drivers need to be able to reference "struct ieee80211_hw" from +the driver's private data, and vice versa. The USB driver failed to +store the address of ieee80211_hw in the private data. Although this +bug has been present for a long time, it was not exposed until +commit ba9f93f82aba ("rtlwifi: Fix enter/exit power_save"). + +Fixes: ba9f93f82aba ("rtlwifi: Fix enter/exit power_save") +Signed-off-by: Larry Finger +Signed-off-by: Kalle Valo +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/net/wireless/realtek/rtlwifi/usb.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/net/wireless/realtek/rtlwifi/usb.c ++++ b/drivers/net/wireless/realtek/rtlwifi/usb.c +@@ -1067,6 +1067,7 @@ int rtl_usb_probe(struct usb_interface * + return -ENOMEM; + } + rtlpriv = hw->priv; ++ rtlpriv->hw = hw; + rtlpriv->usb_data = kzalloc(RTL_USB_MAX_RX_COUNT * sizeof(u32), + GFP_KERNEL); + if (!rtlpriv->usb_data) diff --git a/queue-4.9/series b/queue-4.9/series index 8750e311212..956937e1fb2 100644 --- a/queue-4.9/series +++ b/queue-4.9/series @@ -53,3 +53,7 @@ arm-omap4-fix-bad-fallthrough-for-cpuidle.patch arm-8631-1-clkdev-detect-errors-in-clk_hw_register_clkdev-for-mass-registration.patch arm-omap2-am437x-rollback-to-use-omap3_gptimer_timer_init.patch spi-mvebu-fix-baudrate-calculation-for-armada-variant.patch +alsa-usb-audio-add-a-quirk-for-plantronics-bt600.patch +drm-i915-gen9-fix-pcode-polling-during-cdclk-change-notification.patch +rtlwifi-fix-enter-exit-power_save.patch +rtlwifi-rtl_usb-fix-missing-entry-in-usb-driver-s-private-data.patch