From: Greg Kroah-Hartman Date: Wed, 4 Jan 2017 13:29:42 +0000 (+0100) Subject: 4.9-stable patches X-Git-Tag: v4.9.1~9 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=c4221d61f570e85f94b50c6f7d8c31c2844b59c0;p=thirdparty%2Fkernel%2Fstable-queue.git 4.9-stable patches added patches: asoc-intel-fix-crash-at-suspend-resume-without-card-registration.patch blk-mq-do-not-invoke-.queue_rq-for-a-stopped-queue.patch dm-crypt-mark-key-as-invalid-until-properly-loaded.patch dm-flakey-return-einval-on-interval-bounds-error-in-flakey_ctr.patch dm-raid-fix-discard-support-regression.patch dm-rq-fix-a-race-condition-in-rq_completed.patch dm-space-map-metadata-fix-struct-sm_metadata-leak-on-failed-create.patch dm-table-an-all_blk_mq-table-must-be-loaded-for-a-blk-mq-dm-device.patch dm-table-fix-all_blk_mq-inconsistency-when-an-empty-table-is-loaded.patch pm-opp-don-t-use-opp-structure-outside-of-rcu-protected-section.patch pm-opp-pass-opp_table-to-dev_pm_opp_put_regulator.patch --- diff --git a/queue-4.9/asoc-intel-fix-crash-at-suspend-resume-without-card-registration.patch b/queue-4.9/asoc-intel-fix-crash-at-suspend-resume-without-card-registration.patch new file mode 100644 index 00000000000..94e33f274c9 --- /dev/null +++ b/queue-4.9/asoc-intel-fix-crash-at-suspend-resume-without-card-registration.patch @@ -0,0 +1,67 @@ +From 2fc995a87f2efcd803438f07bfecd35cc3d90d32 Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Fri, 25 Nov 2016 16:54:06 +0100 +Subject: ASoC: intel: Fix crash at suspend/resume without card registration + +From: Takashi Iwai + +commit 2fc995a87f2efcd803438f07bfecd35cc3d90d32 upstream. + +When ASoC Intel SST Medfield driver is probed but without codec / card +assigned, it causes an Oops and freezes the kernel at suspend/resume, + + PM: Suspending system (freeze) + Suspending console(s) (use no_console_suspend to debug) + BUG: unable to handle kernel NULL pointer dereference at 0000000000000018 + IP: [] sst_soc_prepare+0x19/0xa0 [snd_soc_sst_mfld_platform] + Oops: 0000 [#1] PREEMPT SMP + CPU: 0 PID: 1552 Comm: systemd-sleep Tainted: G W 4.9.0-rc6-1.g5f5c2ad-default #1 + Call Trace: + [] dpm_prepare+0x209/0x460 + [] dpm_suspend_start+0x11/0x60 + [] suspend_devices_and_enter+0xb2/0x710 + [] pm_suspend+0x30e/0x390 + [] state_store+0x8a/0x90 + [] kobj_attr_store+0xf/0x20 + [] sysfs_kf_write+0x37/0x40 + [] kernfs_fop_write+0x11c/0x1b0 + [] __vfs_write+0x28/0x140 + [] ? apparmor_file_permission+0x18/0x20 + [] ? security_file_permission+0x3b/0xc0 + [] vfs_write+0xb5/0x1a0 + [] SyS_write+0x46/0xa0 + [] entry_SYSCALL_64_fastpath+0x1e/0xad + +Add proper NULL checks in the PM code of mdfld driver. + +Signed-off-by: Takashi Iwai +Acked-by: Vinod Koul +Signed-off-by: Mark Brown +Signed-off-by: Greg Kroah-Hartman + +--- + sound/soc/intel/atom/sst-mfld-platform-pcm.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/sound/soc/intel/atom/sst-mfld-platform-pcm.c ++++ b/sound/soc/intel/atom/sst-mfld-platform-pcm.c +@@ -771,6 +771,9 @@ static int sst_soc_prepare(struct device + struct sst_data *drv = dev_get_drvdata(dev); + struct snd_soc_pcm_runtime *rtd; + ++ if (!drv->soc_card) ++ return 0; ++ + /* suspend all pcms first */ + snd_soc_suspend(drv->soc_card->dev); + snd_soc_poweroff(drv->soc_card->dev); +@@ -793,6 +796,9 @@ static void sst_soc_complete(struct devi + struct sst_data *drv = dev_get_drvdata(dev); + struct snd_soc_pcm_runtime *rtd; + ++ if (!drv->soc_card) ++ return; ++ + /* restart SSPs */ + list_for_each_entry(rtd, &drv->soc_card->rtd_list, list) { + struct snd_soc_dai *dai = rtd->cpu_dai; diff --git a/queue-4.9/blk-mq-do-not-invoke-.queue_rq-for-a-stopped-queue.patch b/queue-4.9/blk-mq-do-not-invoke-.queue_rq-for-a-stopped-queue.patch new file mode 100644 index 00000000000..a77a4c8d779 --- /dev/null +++ b/queue-4.9/blk-mq-do-not-invoke-.queue_rq-for-a-stopped-queue.patch @@ -0,0 +1,42 @@ +From bc27c01b5c46d3bfec42c96537c7a3fae0bb2cc4 Mon Sep 17 00:00:00 2001 +From: Bart Van Assche +Date: Fri, 28 Oct 2016 17:18:48 -0700 +Subject: blk-mq: Do not invoke .queue_rq() for a stopped queue + +From: Bart Van Assche + +commit bc27c01b5c46d3bfec42c96537c7a3fae0bb2cc4 upstream. + +The meaning of the BLK_MQ_S_STOPPED flag is "do not call +.queue_rq()". Hence modify blk_mq_make_request() such that requests +are queued instead of issued if a queue has been stopped. + +Reported-by: Ming Lei +Signed-off-by: Bart Van Assche +Reviewed-by: Christoph Hellwig +Reviewed-by: Ming Lei +Reviewed-by: Hannes Reinecke +Reviewed-by: Johannes Thumshirn +Reviewed-by: Sagi Grimberg +Signed-off-by: Jens Axboe +Signed-off-by: Greg Kroah-Hartman + +--- + block/blk-mq.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- a/block/blk-mq.c ++++ b/block/blk-mq.c +@@ -1332,9 +1332,9 @@ static blk_qc_t blk_mq_make_request(stru + blk_mq_put_ctx(data.ctx); + if (!old_rq) + goto done; +- if (!blk_mq_direct_issue_request(old_rq, &cookie)) +- goto done; +- blk_mq_insert_request(old_rq, false, true, true); ++ if (test_bit(BLK_MQ_S_STOPPED, &data.hctx->state) || ++ blk_mq_direct_issue_request(old_rq, &cookie) != 0) ++ blk_mq_insert_request(old_rq, false, true, true); + goto done; + } + diff --git a/queue-4.9/dm-crypt-mark-key-as-invalid-until-properly-loaded.patch b/queue-4.9/dm-crypt-mark-key-as-invalid-until-properly-loaded.patch new file mode 100644 index 00000000000..0507692bd22 --- /dev/null +++ b/queue-4.9/dm-crypt-mark-key-as-invalid-until-properly-loaded.patch @@ -0,0 +1,43 @@ +From 265e9098bac02bc5e36cda21fdbad34cb5b2f48d Mon Sep 17 00:00:00 2001 +From: Ondrej Kozina +Date: Wed, 2 Nov 2016 15:02:08 +0100 +Subject: dm crypt: mark key as invalid until properly loaded + +From: Ondrej Kozina + +commit 265e9098bac02bc5e36cda21fdbad34cb5b2f48d upstream. + +In crypt_set_key(), if a failure occurs while replacing the old key +(e.g. tfm->setkey() fails) the key must not have DM_CRYPT_KEY_VALID flag +set. Otherwise, the crypto layer would have an invalid key that still +has DM_CRYPT_KEY_VALID flag set. + +Signed-off-by: Ondrej Kozina +Reviewed-by: Mikulas Patocka +Signed-off-by: Mike Snitzer +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/md/dm-crypt.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +--- a/drivers/md/dm-crypt.c ++++ b/drivers/md/dm-crypt.c +@@ -1503,12 +1503,15 @@ static int crypt_set_key(struct crypt_co + if (!cc->key_size && strcmp(key, "-")) + goto out; + ++ /* clear the flag since following operations may invalidate previously valid key */ ++ clear_bit(DM_CRYPT_KEY_VALID, &cc->flags); ++ + if (cc->key_size && crypt_decode_key(cc->key, key, cc->key_size) < 0) + goto out; + +- set_bit(DM_CRYPT_KEY_VALID, &cc->flags); +- + r = crypt_setkey_allcpus(cc); ++ if (!r) ++ set_bit(DM_CRYPT_KEY_VALID, &cc->flags); + + out: + /* Hex key string not needed after here, so wipe it. */ diff --git a/queue-4.9/dm-flakey-return-einval-on-interval-bounds-error-in-flakey_ctr.patch b/queue-4.9/dm-flakey-return-einval-on-interval-bounds-error-in-flakey_ctr.patch new file mode 100644 index 00000000000..f6b3b4bc5cd --- /dev/null +++ b/queue-4.9/dm-flakey-return-einval-on-interval-bounds-error-in-flakey_ctr.patch @@ -0,0 +1,37 @@ +From bff7e067ee518f9ed7e1cbc63e4c9e01670d0b71 Mon Sep 17 00:00:00 2001 +From: Wei Yongjun +Date: Mon, 8 Aug 2016 14:09:27 +0000 +Subject: dm flakey: return -EINVAL on interval bounds error in flakey_ctr() + +From: Wei Yongjun + +commit bff7e067ee518f9ed7e1cbc63e4c9e01670d0b71 upstream. + +Fix to return error code -EINVAL instead of 0, as is done elsewhere in +this function. + +Fixes: e80d1c805a3b ("dm: do not override error code returned from dm_get_device()") +Signed-off-by: Wei Yongjun +Signed-off-by: Mike Snitzer +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/md/dm-flakey.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/md/dm-flakey.c ++++ b/drivers/md/dm-flakey.c +@@ -200,11 +200,13 @@ static int flakey_ctr(struct dm_target * + + if (!(fc->up_interval + fc->down_interval)) { + ti->error = "Total (up + down) interval is zero"; ++ r = -EINVAL; + goto bad; + } + + if (fc->up_interval + fc->down_interval < fc->up_interval) { + ti->error = "Interval overflow"; ++ r = -EINVAL; + goto bad; + } + diff --git a/queue-4.9/dm-raid-fix-discard-support-regression.patch b/queue-4.9/dm-raid-fix-discard-support-regression.patch new file mode 100644 index 00000000000..35bcd34b754 --- /dev/null +++ b/queue-4.9/dm-raid-fix-discard-support-regression.patch @@ -0,0 +1,50 @@ +From 11e2968478edc07a75ee1efb45011b3033c621c2 Mon Sep 17 00:00:00 2001 +From: Heinz Mauelshagen +Date: Tue, 29 Nov 2016 22:37:30 +0100 +Subject: dm raid: fix discard support regression + +From: Heinz Mauelshagen + +commit 11e2968478edc07a75ee1efb45011b3033c621c2 upstream. + +Commit ecbfb9f118 ("dm raid: add raid level takeover support") moved the +configure_discard_support() call from raid_ctr() to raid_preresume(). + +Enabling/disabling discard _must_ happen during table load (through the +.ctr hook). Fix this regression by moving the +configure_discard_support() call back to raid_ctr(). + +Fixes: ecbfb9f118 ("dm raid: add raid level takeover support") +Signed-off-by: Heinz Mauelshagen +Signed-off-by: Mike Snitzer +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/md/dm-raid.c | 9 +++------ + 1 file changed, 3 insertions(+), 6 deletions(-) + +--- a/drivers/md/dm-raid.c ++++ b/drivers/md/dm-raid.c +@@ -2994,6 +2994,9 @@ static int raid_ctr(struct dm_target *ti + } + } + ++ /* Disable/enable discard support on raid set. */ ++ configure_discard_support(rs); ++ + mddev_unlock(&rs->md); + return 0; + +@@ -3580,12 +3583,6 @@ static int raid_preresume(struct dm_targ + if (test_bit(RT_FLAG_UPDATE_SBS, &rs->runtime_flags)) + rs_update_sbs(rs); + +- /* +- * Disable/enable discard support on raid set after any +- * conversion, because devices can have been added +- */ +- configure_discard_support(rs); +- + /* Load the bitmap from disk unless raid0 */ + r = __load_dirty_region_bitmap(rs); + if (r) diff --git a/queue-4.9/dm-rq-fix-a-race-condition-in-rq_completed.patch b/queue-4.9/dm-rq-fix-a-race-condition-in-rq_completed.patch new file mode 100644 index 00000000000..3e1aa466000 --- /dev/null +++ b/queue-4.9/dm-rq-fix-a-race-condition-in-rq_completed.patch @@ -0,0 +1,47 @@ +From d15bb3a6467e102e60d954aadda5fb19ce6fd8ec Mon Sep 17 00:00:00 2001 +From: Bart Van Assche +Date: Fri, 11 Nov 2016 17:05:27 -0800 +Subject: dm rq: fix a race condition in rq_completed() + +From: Bart Van Assche + +commit d15bb3a6467e102e60d954aadda5fb19ce6fd8ec upstream. + +It is required to hold the queue lock when calling blk_run_queue_async() +to avoid that a race between blk_run_queue_async() and +blk_cleanup_queue() is triggered. + +Signed-off-by: Bart Van Assche +Signed-off-by: Mike Snitzer +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/md/dm-rq.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +--- a/drivers/md/dm-rq.c ++++ b/drivers/md/dm-rq.c +@@ -226,6 +226,9 @@ static void rq_end_stats(struct mapped_d + */ + static void rq_completed(struct mapped_device *md, int rw, bool run_queue) + { ++ struct request_queue *q = md->queue; ++ unsigned long flags; ++ + atomic_dec(&md->pending[rw]); + + /* nudge anyone waiting on suspend queue */ +@@ -238,8 +241,11 @@ static void rq_completed(struct mapped_d + * back into ->request_fn() could deadlock attempting to grab the + * queue lock again. + */ +- if (!md->queue->mq_ops && run_queue) +- blk_run_queue_async(md->queue); ++ if (!q->mq_ops && run_queue) { ++ spin_lock_irqsave(q->queue_lock, flags); ++ blk_run_queue_async(q); ++ spin_unlock_irqrestore(q->queue_lock, flags); ++ } + + /* + * dm_put() must be at the end of this function. See the comment above diff --git a/queue-4.9/dm-space-map-metadata-fix-struct-sm_metadata-leak-on-failed-create.patch b/queue-4.9/dm-space-map-metadata-fix-struct-sm_metadata-leak-on-failed-create.patch new file mode 100644 index 00000000000..ca15acff1dd --- /dev/null +++ b/queue-4.9/dm-space-map-metadata-fix-struct-sm_metadata-leak-on-failed-create.patch @@ -0,0 +1,57 @@ +From 314c25c56c1ee5026cf99c570bdfe01847927acb Mon Sep 17 00:00:00 2001 +From: Benjamin Marzinski +Date: Wed, 30 Nov 2016 17:56:14 -0600 +Subject: dm space map metadata: fix 'struct sm_metadata' leak on failed create + +From: Benjamin Marzinski + +commit 314c25c56c1ee5026cf99c570bdfe01847927acb upstream. + +In dm_sm_metadata_create() we temporarily change the dm_space_map +operations from 'ops' (whose .destroy function deallocates the +sm_metadata) to 'bootstrap_ops' (whose .destroy function doesn't). + +If dm_sm_metadata_create() fails in sm_ll_new_metadata() or +sm_ll_extend(), it exits back to dm_tm_create_internal(), which calls +dm_sm_destroy() with the intention of freeing the sm_metadata, but it +doesn't (because the dm_space_map operations is still set to +'bootstrap_ops'). + +Fix this by setting the dm_space_map operations back to 'ops' if +dm_sm_metadata_create() fails when it is set to 'bootstrap_ops'. + +Signed-off-by: Benjamin Marzinski +Acked-by: Joe Thornber +Signed-off-by: Mike Snitzer +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/md/persistent-data/dm-space-map-metadata.c | 14 ++++++-------- + 1 file changed, 6 insertions(+), 8 deletions(-) + +--- a/drivers/md/persistent-data/dm-space-map-metadata.c ++++ b/drivers/md/persistent-data/dm-space-map-metadata.c +@@ -775,17 +775,15 @@ int dm_sm_metadata_create(struct dm_spac + memcpy(&smm->sm, &bootstrap_ops, sizeof(smm->sm)); + + r = sm_ll_new_metadata(&smm->ll, tm); ++ if (!r) { ++ if (nr_blocks > DM_SM_METADATA_MAX_BLOCKS) ++ nr_blocks = DM_SM_METADATA_MAX_BLOCKS; ++ r = sm_ll_extend(&smm->ll, nr_blocks); ++ } ++ memcpy(&smm->sm, &ops, sizeof(smm->sm)); + if (r) + return r; + +- if (nr_blocks > DM_SM_METADATA_MAX_BLOCKS) +- nr_blocks = DM_SM_METADATA_MAX_BLOCKS; +- r = sm_ll_extend(&smm->ll, nr_blocks); +- if (r) +- return r; +- +- memcpy(&smm->sm, &ops, sizeof(smm->sm)); +- + /* + * Now we need to update the newly created data structures with the + * allocated blocks that they were built from. diff --git a/queue-4.9/dm-table-an-all_blk_mq-table-must-be-loaded-for-a-blk-mq-dm-device.patch b/queue-4.9/dm-table-an-all_blk_mq-table-must-be-loaded-for-a-blk-mq-dm-device.patch new file mode 100644 index 00000000000..63f96731d4d --- /dev/null +++ b/queue-4.9/dm-table-an-all_blk_mq-table-must-be-loaded-for-a-blk-mq-dm-device.patch @@ -0,0 +1,37 @@ +From 301fc3f5efb98633115bd887655b19f42c6dfaa8 Mon Sep 17 00:00:00 2001 +From: Bart Van Assche +Date: Wed, 7 Dec 2016 16:56:06 -0800 +Subject: dm table: an 'all_blk_mq' table must be loaded for a blk-mq DM device + +From: Bart Van Assche + +commit 301fc3f5efb98633115bd887655b19f42c6dfaa8 upstream. + +When dm_table_set_type() is used by a target to establish a DM table's +type (e.g. DM_TYPE_MQ_REQUEST_BASED in the case of DM multipath) the +DM core must go on to verify that the devices in the table are +compatible with the established type. + +Fixes: e83068a5 ("dm mpath: add optional "queue_mode" feature") +Signed-off-by: Bart Van Assche +Signed-off-by: Mike Snitzer +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/md/dm-table.c | 5 +++++ + 1 file changed, 5 insertions(+) + +--- a/drivers/md/dm-table.c ++++ b/drivers/md/dm-table.c +@@ -981,6 +981,11 @@ verify_rq_based: + t->all_blk_mq = true; + } + ++ if (t->type == DM_TYPE_MQ_REQUEST_BASED && !t->all_blk_mq) { ++ DMERR("table load rejected: all devices are not blk-mq request-stackable"); ++ return -EINVAL; ++ } ++ + return 0; + } + diff --git a/queue-4.9/dm-table-fix-all_blk_mq-inconsistency-when-an-empty-table-is-loaded.patch b/queue-4.9/dm-table-fix-all_blk_mq-inconsistency-when-an-empty-table-is-loaded.patch new file mode 100644 index 00000000000..01993b38d93 --- /dev/null +++ b/queue-4.9/dm-table-fix-all_blk_mq-inconsistency-when-an-empty-table-is-loaded.patch @@ -0,0 +1,63 @@ +From 6936c12cf809850180b24947271b8f068fdb15e9 Mon Sep 17 00:00:00 2001 +From: Mike Snitzer +Date: Wed, 23 Nov 2016 13:51:09 -0500 +Subject: dm table: fix 'all_blk_mq' inconsistency when an empty table is loaded + +From: Mike Snitzer + +commit 6936c12cf809850180b24947271b8f068fdb15e9 upstream. + +An earlier DM multipath table could have been build ontop of underlying +devices that were all using blk-mq. In that case, if that active +multipath table is replaced with an empty DM multipath table (that +reflects all paths have failed) then it is important that the +'all_blk_mq' state of the active table is transfered to the new empty DM +table. Otherwise dm-rq.c:dm_old_prep_tio() will incorrectly clone a +request that isn't needed by the DM multipath target when it is to issue +IO to an underlying blk-mq device. + +Fixes: e83068a5 ("dm mpath: add optional "queue_mode" feature") +Reported-by: Bart Van Assche +Tested-by: Bart Van Assche +Signed-off-by: Mike Snitzer +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/md/dm-table.c | 19 +++++++++++++------ + 1 file changed, 13 insertions(+), 6 deletions(-) + +--- a/drivers/md/dm-table.c ++++ b/drivers/md/dm-table.c +@@ -924,12 +924,6 @@ static int dm_table_determine_type(struc + + BUG_ON(!request_based); /* No targets in this table */ + +- if (list_empty(devices) && __table_type_request_based(live_md_type)) { +- /* inherit live MD type */ +- t->type = live_md_type; +- return 0; +- } +- + /* + * The only way to establish DM_TYPE_MQ_REQUEST_BASED is by + * having a compatible target use dm_table_set_type. +@@ -948,6 +942,19 @@ verify_rq_based: + return -EINVAL; + } + ++ if (list_empty(devices)) { ++ int srcu_idx; ++ struct dm_table *live_table = dm_get_live_table(t->md, &srcu_idx); ++ ++ /* inherit live table's type and all_blk_mq */ ++ if (live_table) { ++ t->type = live_table->type; ++ t->all_blk_mq = live_table->all_blk_mq; ++ } ++ dm_put_live_table(t->md, srcu_idx); ++ return 0; ++ } ++ + /* Non-request-stackable devices can't be used for request-based dm */ + list_for_each_entry(dd, devices, list) { + struct request_queue *q = bdev_get_queue(dd->dm_dev->bdev); diff --git a/queue-4.9/pm-opp-don-t-use-opp-structure-outside-of-rcu-protected-section.patch b/queue-4.9/pm-opp-don-t-use-opp-structure-outside-of-rcu-protected-section.patch new file mode 100644 index 00000000000..3c856a4b640 --- /dev/null +++ b/queue-4.9/pm-opp-don-t-use-opp-structure-outside-of-rcu-protected-section.patch @@ -0,0 +1,61 @@ +From dc39d06fcd7a4a82d72eae7b71e94e888b96d29e Mon Sep 17 00:00:00 2001 +From: Viresh Kumar +Date: Thu, 1 Dec 2016 16:28:16 +0530 +Subject: PM / OPP: Don't use OPP structure outside of rcu protected section + +From: Viresh Kumar + +commit dc39d06fcd7a4a82d72eae7b71e94e888b96d29e upstream. + +The OPP structure must not be used out of the rcu protected section. +Cache the values to be used in separate variables instead. + +Signed-off-by: Viresh Kumar +Reviewed-by: Stephen Boyd +Tested-by: Dave Gerlach +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/base/power/opp/core.c | 16 +++++++++++++--- + 1 file changed, 13 insertions(+), 3 deletions(-) + +--- a/drivers/base/power/opp/core.c ++++ b/drivers/base/power/opp/core.c +@@ -584,6 +584,7 @@ int dev_pm_opp_set_rate(struct device *d + struct clk *clk; + unsigned long freq, old_freq; + unsigned long u_volt, u_volt_min, u_volt_max; ++ unsigned long old_u_volt, old_u_volt_min, old_u_volt_max; + int ret; + + if (unlikely(!target_freq)) { +@@ -633,6 +634,14 @@ int dev_pm_opp_set_rate(struct device *d + return ret; + } + ++ if (IS_ERR(old_opp)) { ++ old_u_volt = 0; ++ } else { ++ old_u_volt = old_opp->u_volt; ++ old_u_volt_min = old_opp->u_volt_min; ++ old_u_volt_max = old_opp->u_volt_max; ++ } ++ + u_volt = opp->u_volt; + u_volt_min = opp->u_volt_min; + u_volt_max = opp->u_volt_max; +@@ -677,9 +686,10 @@ restore_freq: + __func__, old_freq); + restore_voltage: + /* This shouldn't harm even if the voltages weren't updated earlier */ +- if (!IS_ERR(old_opp)) +- _set_opp_voltage(dev, reg, old_opp->u_volt, +- old_opp->u_volt_min, old_opp->u_volt_max); ++ if (old_u_volt) { ++ _set_opp_voltage(dev, reg, old_u_volt, old_u_volt_min, ++ old_u_volt_max); ++ } + + return ret; + } diff --git a/queue-4.9/pm-opp-pass-opp_table-to-dev_pm_opp_put_regulator.patch b/queue-4.9/pm-opp-pass-opp_table-to-dev_pm_opp_put_regulator.patch new file mode 100644 index 00000000000..7ecf20fe650 --- /dev/null +++ b/queue-4.9/pm-opp-pass-opp_table-to-dev_pm_opp_put_regulator.patch @@ -0,0 +1,198 @@ +From 91291d9ad92faa65a56a9a19d658d8049b78d3d4 Mon Sep 17 00:00:00 2001 +From: Stephen Boyd +Date: Wed, 30 Nov 2016 16:21:25 +0530 +Subject: PM / OPP: Pass opp_table to dev_pm_opp_put_regulator() + +From: Stephen Boyd + +commit 91291d9ad92faa65a56a9a19d658d8049b78d3d4 upstream. + +Joonyoung Shim reported an interesting problem on his ARM octa-core +Odoroid-XU3 platform. During system suspend, dev_pm_opp_put_regulator() +was failing for a struct device for which dev_pm_opp_set_regulator() is +called earlier. + +This happened because an earlier call to +dev_pm_opp_of_cpumask_remove_table() function (from cpufreq-dt.c file) +removed all the entries from opp_table->dev_list apart from the last CPU +device in the cpumask of CPUs sharing the OPP. + +But both dev_pm_opp_set_regulator() and dev_pm_opp_put_regulator() +routines get CPU device for the first CPU in the cpumask. And so the OPP +core failed to find the OPP table for the struct device. + +This patch attempts to fix this problem by returning a pointer to the +opp_table from dev_pm_opp_set_regulator() and using that as the +parameter to dev_pm_opp_put_regulator(). This ensures that the +dev_pm_opp_put_regulator() doesn't fail to find the opp table. + +Note that similar design problem also exists with other +dev_pm_opp_put_*() APIs, but those aren't used currently by anyone and +so we don't need to update them for now. + +Reported-by: Joonyoung Shim +Signed-off-by: Stephen Boyd +Signed-off-by: Viresh Kumar +[ Viresh: Wrote commit log and tested on exynos 5250 ] +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/base/power/opp/core.c | 22 ++++++---------------- + drivers/cpufreq/cpufreq-dt.c | 12 ++++++++---- + include/linux/pm_opp.h | 11 ++++++----- + 3 files changed, 20 insertions(+), 25 deletions(-) + +--- a/drivers/base/power/opp/core.c ++++ b/drivers/base/power/opp/core.c +@@ -1316,7 +1316,7 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_put_prop_na + * that this function is *NOT* called under RCU protection or in contexts where + * mutex cannot be locked. + */ +-int dev_pm_opp_set_regulator(struct device *dev, const char *name) ++struct opp_table *dev_pm_opp_set_regulator(struct device *dev, const char *name) + { + struct opp_table *opp_table; + struct regulator *reg; +@@ -1354,20 +1354,20 @@ int dev_pm_opp_set_regulator(struct devi + opp_table->regulator = reg; + + mutex_unlock(&opp_table_lock); +- return 0; ++ return opp_table; + + err: + _remove_opp_table(opp_table); + unlock: + mutex_unlock(&opp_table_lock); + +- return ret; ++ return ERR_PTR(ret); + } + EXPORT_SYMBOL_GPL(dev_pm_opp_set_regulator); + + /** + * dev_pm_opp_put_regulator() - Releases resources blocked for regulator +- * @dev: Device for which regulator was set. ++ * @opp_table: OPP table returned from dev_pm_opp_set_regulator(). + * + * Locking: The internal opp_table and opp structures are RCU protected. + * Hence this function internally uses RCU updater strategy with mutex locks +@@ -1375,22 +1375,12 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_set_regulat + * that this function is *NOT* called under RCU protection or in contexts where + * mutex cannot be locked. + */ +-void dev_pm_opp_put_regulator(struct device *dev) ++void dev_pm_opp_put_regulator(struct opp_table *opp_table) + { +- struct opp_table *opp_table; +- + mutex_lock(&opp_table_lock); + +- /* Check for existing table for 'dev' first */ +- opp_table = _find_opp_table(dev); +- if (IS_ERR(opp_table)) { +- dev_err(dev, "Failed to find opp_table: %ld\n", +- PTR_ERR(opp_table)); +- goto unlock; +- } +- + if (IS_ERR(opp_table->regulator)) { +- dev_err(dev, "%s: Doesn't have regulator set\n", __func__); ++ pr_err("%s: Doesn't have regulator set\n", __func__); + goto unlock; + } + +--- a/drivers/cpufreq/cpufreq-dt.c ++++ b/drivers/cpufreq/cpufreq-dt.c +@@ -28,6 +28,7 @@ + #include "cpufreq-dt.h" + + struct private_data { ++ struct opp_table *opp_table; + struct device *cpu_dev; + struct thermal_cooling_device *cdev; + const char *reg_name; +@@ -143,6 +144,7 @@ static int resources_available(void) + static int cpufreq_init(struct cpufreq_policy *policy) + { + struct cpufreq_frequency_table *freq_table; ++ struct opp_table *opp_table = NULL; + struct private_data *priv; + struct device *cpu_dev; + struct clk *cpu_clk; +@@ -186,8 +188,9 @@ static int cpufreq_init(struct cpufreq_p + */ + name = find_supply_name(cpu_dev); + if (name) { +- ret = dev_pm_opp_set_regulator(cpu_dev, name); +- if (ret) { ++ opp_table = dev_pm_opp_set_regulator(cpu_dev, name); ++ if (IS_ERR(opp_table)) { ++ ret = PTR_ERR(opp_table); + dev_err(cpu_dev, "Failed to set regulator for cpu%d: %d\n", + policy->cpu, ret); + goto out_put_clk; +@@ -237,6 +240,7 @@ static int cpufreq_init(struct cpufreq_p + } + + priv->reg_name = name; ++ priv->opp_table = opp_table; + + ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table); + if (ret) { +@@ -285,7 +289,7 @@ out_free_priv: + out_free_opp: + dev_pm_opp_of_cpumask_remove_table(policy->cpus); + if (name) +- dev_pm_opp_put_regulator(cpu_dev); ++ dev_pm_opp_put_regulator(opp_table); + out_put_clk: + clk_put(cpu_clk); + +@@ -300,7 +304,7 @@ static int cpufreq_exit(struct cpufreq_p + dev_pm_opp_free_cpufreq_table(priv->cpu_dev, &policy->freq_table); + dev_pm_opp_of_cpumask_remove_table(policy->related_cpus); + if (priv->reg_name) +- dev_pm_opp_put_regulator(priv->cpu_dev); ++ dev_pm_opp_put_regulator(priv->opp_table); + + clk_put(policy->clk); + kfree(priv); +--- a/include/linux/pm_opp.h ++++ b/include/linux/pm_opp.h +@@ -19,6 +19,7 @@ + + struct dev_pm_opp; + struct device; ++struct opp_table; + + enum dev_pm_opp_event { + OPP_EVENT_ADD, OPP_EVENT_REMOVE, OPP_EVENT_ENABLE, OPP_EVENT_DISABLE, +@@ -62,8 +63,8 @@ int dev_pm_opp_set_supported_hw(struct d + void dev_pm_opp_put_supported_hw(struct device *dev); + int dev_pm_opp_set_prop_name(struct device *dev, const char *name); + void dev_pm_opp_put_prop_name(struct device *dev); +-int dev_pm_opp_set_regulator(struct device *dev, const char *name); +-void dev_pm_opp_put_regulator(struct device *dev); ++struct opp_table *dev_pm_opp_set_regulator(struct device *dev, const char *name); ++void dev_pm_opp_put_regulator(struct opp_table *opp_table); + int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq); + int dev_pm_opp_set_sharing_cpus(struct device *cpu_dev, const struct cpumask *cpumask); + int dev_pm_opp_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpumask); +@@ -170,12 +171,12 @@ static inline int dev_pm_opp_set_prop_na + + static inline void dev_pm_opp_put_prop_name(struct device *dev) {} + +-static inline int dev_pm_opp_set_regulator(struct device *dev, const char *name) ++static inline struct opp_table *dev_pm_opp_set_regulator(struct device *dev, const char *name) + { +- return -ENOTSUPP; ++ return ERR_PTR(-ENOTSUPP); + } + +-static inline void dev_pm_opp_put_regulator(struct device *dev) {} ++static inline void dev_pm_opp_put_regulator(struct opp_table *opp_table) {} + + static inline int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq) + { diff --git a/queue-4.9/series b/queue-4.9/series index 09a6f0906f5..ed427ccc2c0 100644 --- a/queue-4.9/series +++ b/queue-4.9/series @@ -53,3 +53,14 @@ nvmet-fix-possible-infinite-loop-triggered-on-hot-namespace-removal.patch mm-vmscan.c-set-correct-defer-count-for-shrinker.patch mm-page_alloc-keep-pcp-count-and-list-contents-in-sync-if-struct-page-is-corrupted.patch usb-gadget-composite-always-set-ep-mult-to-a-sensible-value.patch +pm-opp-pass-opp_table-to-dev_pm_opp_put_regulator.patch +pm-opp-don-t-use-opp-structure-outside-of-rcu-protected-section.patch +blk-mq-do-not-invoke-.queue_rq-for-a-stopped-queue.patch +dm-table-fix-all_blk_mq-inconsistency-when-an-empty-table-is-loaded.patch +dm-table-an-all_blk_mq-table-must-be-loaded-for-a-blk-mq-dm-device.patch +dm-flakey-return-einval-on-interval-bounds-error-in-flakey_ctr.patch +dm-crypt-mark-key-as-invalid-until-properly-loaded.patch +dm-rq-fix-a-race-condition-in-rq_completed.patch +dm-raid-fix-discard-support-regression.patch +dm-space-map-metadata-fix-struct-sm_metadata-leak-on-failed-create.patch +asoc-intel-fix-crash-at-suspend-resume-without-card-registration.patch