From 13acd6e2d31fd4ef560c782beeea78bf4810d3d6 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 24 Jul 2017 17:04:49 -0700 Subject: [PATCH] 4.12-stable patches added patches: hid-multitouch-do-not-blindly-set-ev_key-or-ev_abs-bits.patch md-don-t-use-flush_signals-in-userspace-processes.patch md-fix-deadlock-between-mddev_suspend-and-md_write_start.patch mxl111sf-fix-driver-to-use-heap-allocate-buffers-for-usb-messages.patch pci-msi-ignore-affinity-if-pre-post-vector-count-is-more-than-min_vecs.patch pci-pm-restore-the-status-of-pci-devices-across-hibernation.patch pci-rockchip-use-normal-register-bank-for-config-accessors.patch pci-vmd-move-srcu-cleanup-after-bus-child-device-removal.patch pci-work-around-poweroff-suspend-to-ram-issue-on-macbook-pro-11.patch usb-cdc-acm-add-device-id-for-quirky-printer.patch usb-renesas_usbhs-fix-usbhsc_resume-for-usbhsf_runtime_pwctrl.patch usb-renesas_usbhs-gadget-disable-all-eps-when-the-driver-stops.patch usb-storage-return-on-error-to-avoid-a-null-pointer-dereference.patch usb-xhci-fix-spinlock-recursion-for-usb2-test-mode.patch xen-x86-fix-cpu-hotplug.patch xhci-bad-ethernet-performance-plugged-in-asm1042a-host.patch xhci-fix-20000ms-port-resume-timeout.patch xhci-fix-memleak-in-xhci_run.patch xhci-fix-null-pointer-dereference-when-cleaning-up-streams-for-removed-host.patch --- ...ot-blindly-set-ev_key-or-ev_abs-bits.patch | 61 +++ ...flush_signals-in-userspace-processes.patch | 72 +++ ...een-mddev_suspend-and-md_write_start.patch | 420 ++++++++++++++++++ ...ap-allocate-buffers-for-usb-messages.patch | 167 +++++++ ...t-vector-count-is-more-than-min_vecs.patch | 123 +++++ ...us-of-pci-devices-across-hibernation.patch | 93 ++++ ...l-register-bank-for-config-accessors.patch | 87 ++++ ...eanup-after-bus-child-device-removal.patch | 36 ++ ...spend-to-ram-issue-on-macbook-pro-11.patch | 84 ++++ queue-4.12/series | 19 + ...acm-add-device-id-for-quirky-printer.patch | 33 ++ ...hsc_resume-for-usbhsf_runtime_pwctrl.patch | 37 ++ ...isable-all-eps-when-the-driver-stops.patch | 121 +++++ ...-to-avoid-a-null-pointer-dereference.patch | 44 ++ ...pinlock-recursion-for-usb2-test-mode.patch | 39 ++ queue-4.12/xen-x86-fix-cpu-hotplug.patch | 47 ++ ...performance-plugged-in-asm1042a-host.patch | 172 +++++++ ...xhci-fix-20000ms-port-resume-timeout.patch | 41 ++ queue-4.12/xhci-fix-memleak-in-xhci_run.patch | 54 +++ ...cleaning-up-streams-for-removed-host.patch | 51 +++ 20 files changed, 1801 insertions(+) create mode 100644 queue-4.12/hid-multitouch-do-not-blindly-set-ev_key-or-ev_abs-bits.patch create mode 100644 queue-4.12/md-don-t-use-flush_signals-in-userspace-processes.patch create mode 100644 queue-4.12/md-fix-deadlock-between-mddev_suspend-and-md_write_start.patch create mode 100644 queue-4.12/mxl111sf-fix-driver-to-use-heap-allocate-buffers-for-usb-messages.patch create mode 100644 queue-4.12/pci-msi-ignore-affinity-if-pre-post-vector-count-is-more-than-min_vecs.patch create mode 100644 queue-4.12/pci-pm-restore-the-status-of-pci-devices-across-hibernation.patch create mode 100644 queue-4.12/pci-rockchip-use-normal-register-bank-for-config-accessors.patch create mode 100644 queue-4.12/pci-vmd-move-srcu-cleanup-after-bus-child-device-removal.patch create mode 100644 queue-4.12/pci-work-around-poweroff-suspend-to-ram-issue-on-macbook-pro-11.patch create mode 100644 queue-4.12/usb-cdc-acm-add-device-id-for-quirky-printer.patch create mode 100644 queue-4.12/usb-renesas_usbhs-fix-usbhsc_resume-for-usbhsf_runtime_pwctrl.patch create mode 100644 queue-4.12/usb-renesas_usbhs-gadget-disable-all-eps-when-the-driver-stops.patch create mode 100644 queue-4.12/usb-storage-return-on-error-to-avoid-a-null-pointer-dereference.patch create mode 100644 queue-4.12/usb-xhci-fix-spinlock-recursion-for-usb2-test-mode.patch create mode 100644 queue-4.12/xen-x86-fix-cpu-hotplug.patch create mode 100644 queue-4.12/xhci-bad-ethernet-performance-plugged-in-asm1042a-host.patch create mode 100644 queue-4.12/xhci-fix-20000ms-port-resume-timeout.patch create mode 100644 queue-4.12/xhci-fix-memleak-in-xhci_run.patch create mode 100644 queue-4.12/xhci-fix-null-pointer-dereference-when-cleaning-up-streams-for-removed-host.patch diff --git a/queue-4.12/hid-multitouch-do-not-blindly-set-ev_key-or-ev_abs-bits.patch b/queue-4.12/hid-multitouch-do-not-blindly-set-ev_key-or-ev_abs-bits.patch new file mode 100644 index 00000000000..4c68cd1952c --- /dev/null +++ b/queue-4.12/hid-multitouch-do-not-blindly-set-ev_key-or-ev_abs-bits.patch @@ -0,0 +1,61 @@ +From 4cf56a89c696e66d10612b43b7e95852611e76c2 Mon Sep 17 00:00:00 2001 +From: Dmitry Torokhov +Date: Tue, 11 Jul 2017 10:02:18 -0700 +Subject: HID: multitouch: do not blindly set EV_KEY or EV_ABS bits + +From: Dmitry Torokhov + +commit 4cf56a89c696e66d10612b43b7e95852611e76c2 upstream. + +Now that input core insists on having dev->absinfo when device claims to +generate EV_ABS in its dev->evbit, we should not be blindly setting that +bit. + +The code in question might have been needed before input_set_abs_params() +started setting EV_ABS in device's evbit, but not anymore, and is now +breaking devices such as SMART SPNL-6075 Touchscreen. + +Fixes: 6ecfe51b4082 ("Input: refuse to register absolute devices ...") +Reported-by: Matthias Fend +Tested-by: Matthias Fend +Reviewed-by: Benjamin Tissoires +Signed-off-by: Dmitry Torokhov +Signed-off-by: Jiri Kosina +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/hid/hid-multitouch.c | 16 ++++------------ + 1 file changed, 4 insertions(+), 12 deletions(-) + +--- a/drivers/hid/hid-multitouch.c ++++ b/drivers/hid/hid-multitouch.c +@@ -595,16 +595,6 @@ static int mt_touch_input_mapping(struct + return 0; + } + +-static int mt_touch_input_mapped(struct hid_device *hdev, struct hid_input *hi, +- struct hid_field *field, struct hid_usage *usage, +- unsigned long **bit, int *max) +-{ +- if (usage->type == EV_KEY || usage->type == EV_ABS) +- set_bit(usage->type, hi->input->evbit); +- +- return -1; +-} +- + static int mt_compute_slot(struct mt_device *td, struct input_dev *input) + { + __s32 quirks = td->mtclass.quirks; +@@ -905,8 +895,10 @@ static int mt_input_mapped(struct hid_de + return 0; + + if (field->application == HID_DG_TOUCHSCREEN || +- field->application == HID_DG_TOUCHPAD) +- return mt_touch_input_mapped(hdev, hi, field, usage, bit, max); ++ field->application == HID_DG_TOUCHPAD) { ++ /* We own these mappings, tell hid-input to ignore them */ ++ return -1; ++ } + + /* let hid-core decide for the others */ + return 0; diff --git a/queue-4.12/md-don-t-use-flush_signals-in-userspace-processes.patch b/queue-4.12/md-don-t-use-flush_signals-in-userspace-processes.patch new file mode 100644 index 00000000000..184d855618d --- /dev/null +++ b/queue-4.12/md-don-t-use-flush_signals-in-userspace-processes.patch @@ -0,0 +1,72 @@ +From f9c79bc05a2a91f4fba8bfd653579e066714b1ec Mon Sep 17 00:00:00 2001 +From: Mikulas Patocka +Date: Wed, 7 Jun 2017 19:05:31 -0400 +Subject: md: don't use flush_signals in userspace processes + +From: Mikulas Patocka + +commit f9c79bc05a2a91f4fba8bfd653579e066714b1ec upstream. + +The function flush_signals clears all pending signals for the process. It +may be used by kernel threads when we need to prepare a kernel thread for +responding to signals. However using this function for an userspaces +processes is incorrect - clearing signals without the program expecting it +can cause misbehavior. + +The raid1 and raid5 code uses flush_signals in its request routine because +it wants to prepare for an interruptible wait. This patch drops +flush_signals and uses sigprocmask instead to block all signals (including +SIGKILL) around the schedule() call. The signals are not lost, but the +schedule() call won't respond to them. + +Signed-off-by: Mikulas Patocka +Acked-by: NeilBrown +Signed-off-by: Shaohua Li +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/md/raid1.c | 5 ++++- + drivers/md/raid5.c | 5 ++++- + 2 files changed, 8 insertions(+), 2 deletions(-) + +--- a/drivers/md/raid1.c ++++ b/drivers/md/raid1.c +@@ -1335,7 +1335,7 @@ static void raid1_write_request(struct m + */ + DEFINE_WAIT(w); + for (;;) { +- flush_signals(current); ++ sigset_t full, old; + prepare_to_wait(&conf->wait_barrier, + &w, TASK_INTERRUPTIBLE); + if (bio_end_sector(bio) <= mddev->suspend_lo || +@@ -1345,7 +1345,10 @@ static void raid1_write_request(struct m + bio->bi_iter.bi_sector, + bio_end_sector(bio)))) + break; ++ sigfillset(&full); ++ sigprocmask(SIG_BLOCK, &full, &old); + schedule(); ++ sigprocmask(SIG_SETMASK, &old, NULL); + } + finish_wait(&conf->wait_barrier, &w); + } +--- a/drivers/md/raid5.c ++++ b/drivers/md/raid5.c +@@ -5693,12 +5693,15 @@ static void raid5_make_request(struct md + * userspace, we want an interruptible + * wait. + */ +- flush_signals(current); + prepare_to_wait(&conf->wait_for_overlap, + &w, TASK_INTERRUPTIBLE); + if (logical_sector >= mddev->suspend_lo && + logical_sector < mddev->suspend_hi) { ++ sigset_t full, old; ++ sigfillset(&full); ++ sigprocmask(SIG_BLOCK, &full, &old); + schedule(); ++ sigprocmask(SIG_SETMASK, &old, NULL); + do_prepare = true; + } + goto retry; diff --git a/queue-4.12/md-fix-deadlock-between-mddev_suspend-and-md_write_start.patch b/queue-4.12/md-fix-deadlock-between-mddev_suspend-and-md_write_start.patch new file mode 100644 index 00000000000..8ce32abd3e9 --- /dev/null +++ b/queue-4.12/md-fix-deadlock-between-mddev_suspend-and-md_write_start.patch @@ -0,0 +1,420 @@ +From cc27b0c78c79680d128dbac79de0d40556d041bb Mon Sep 17 00:00:00 2001 +From: NeilBrown +Date: Mon, 5 Jun 2017 16:49:39 +1000 +Subject: md: fix deadlock between mddev_suspend() and md_write_start() + +From: NeilBrown + +commit cc27b0c78c79680d128dbac79de0d40556d041bb upstream. + +If mddev_suspend() races with md_write_start() we can deadlock +with mddev_suspend() waiting for the request that is currently +in md_write_start() to complete the ->make_request() call, +and md_write_start() waiting for the metadata to be updated +to mark the array as 'dirty'. +As metadata updates done by md_check_recovery() only happen then +the mddev_lock() can be claimed, and as mddev_suspend() is often +called with the lock held, these threads wait indefinitely for each +other. + +We fix this by having md_write_start() abort if mddev_suspend() +is happening, and ->make_request() aborts if md_write_start() +aborted. +md_make_request() can detect this abort, decrease the ->active_io +count, and wait for mddev_suspend(). + +Reported-by: Nix +Fix: 68866e425be2(MD: no sync IO while suspended) +Signed-off-by: NeilBrown +Signed-off-by: Shaohua Li +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/md/faulty.c | 5 +++-- + drivers/md/linear.c | 7 ++++--- + drivers/md/md.c | 22 +++++++++++++++++----- + drivers/md/md.h | 4 ++-- + drivers/md/multipath.c | 8 ++++---- + drivers/md/raid0.c | 7 ++++--- + drivers/md/raid1.c | 11 +++++++---- + drivers/md/raid10.c | 10 ++++++---- + drivers/md/raid5.c | 17 +++++++++-------- + 9 files changed, 56 insertions(+), 35 deletions(-) + +--- a/drivers/md/faulty.c ++++ b/drivers/md/faulty.c +@@ -170,7 +170,7 @@ static void add_sector(struct faulty_con + conf->nfaults = n+1; + } + +-static void faulty_make_request(struct mddev *mddev, struct bio *bio) ++static bool faulty_make_request(struct mddev *mddev, struct bio *bio) + { + struct faulty_conf *conf = mddev->private; + int failit = 0; +@@ -182,7 +182,7 @@ static void faulty_make_request(struct m + * just fail immediately + */ + bio_io_error(bio); +- return; ++ return true; + } + + if (check_sector(conf, bio->bi_iter.bi_sector, +@@ -224,6 +224,7 @@ static void faulty_make_request(struct m + bio->bi_bdev = conf->rdev->bdev; + + generic_make_request(bio); ++ return true; + } + + static void faulty_status(struct seq_file *seq, struct mddev *mddev) +--- a/drivers/md/linear.c ++++ b/drivers/md/linear.c +@@ -245,7 +245,7 @@ static void linear_free(struct mddev *md + kfree(conf); + } + +-static void linear_make_request(struct mddev *mddev, struct bio *bio) ++static bool linear_make_request(struct mddev *mddev, struct bio *bio) + { + char b[BDEVNAME_SIZE]; + struct dev_info *tmp_dev; +@@ -254,7 +254,7 @@ static void linear_make_request(struct m + + if (unlikely(bio->bi_opf & REQ_PREFLUSH)) { + md_flush_request(mddev, bio); +- return; ++ return true; + } + + tmp_dev = which_dev(mddev, bio_sector); +@@ -292,7 +292,7 @@ static void linear_make_request(struct m + mddev_check_write_zeroes(mddev, bio); + generic_make_request(bio); + } +- return; ++ return true; + + out_of_bounds: + pr_err("md/linear:%s: make_request: Sector %llu out of bounds on dev %s: %llu sectors, offset %llu\n", +@@ -302,6 +302,7 @@ out_of_bounds: + (unsigned long long)tmp_dev->rdev->sectors, + (unsigned long long)start_sector); + bio_io_error(bio); ++ return true; + } + + static void linear_status (struct seq_file *seq, struct mddev *mddev) +--- a/drivers/md/md.c ++++ b/drivers/md/md.c +@@ -277,7 +277,7 @@ static blk_qc_t md_make_request(struct r + bio_endio(bio); + return BLK_QC_T_NONE; + } +- smp_rmb(); /* Ensure implications of 'active' are visible */ ++check_suspended: + rcu_read_lock(); + if (mddev->suspended) { + DEFINE_WAIT(__wait); +@@ -302,7 +302,11 @@ static blk_qc_t md_make_request(struct r + sectors = bio_sectors(bio); + /* bio could be mergeable after passing to underlayer */ + bio->bi_opf &= ~REQ_NOMERGE; +- mddev->pers->make_request(mddev, bio); ++ if (!mddev->pers->make_request(mddev, bio)) { ++ atomic_dec(&mddev->active_io); ++ wake_up(&mddev->sb_wait); ++ goto check_suspended; ++ } + + cpu = part_stat_lock(); + part_stat_inc(cpu, &mddev->gendisk->part0, ios[rw]); +@@ -327,6 +331,7 @@ void mddev_suspend(struct mddev *mddev) + if (mddev->suspended++) + return; + synchronize_rcu(); ++ wake_up(&mddev->sb_wait); + wait_event(mddev->sb_wait, atomic_read(&mddev->active_io) == 0); + mddev->pers->quiesce(mddev, 1); + +@@ -7950,12 +7955,14 @@ EXPORT_SYMBOL(md_done_sync); + * If we need to update some array metadata (e.g. 'active' flag + * in superblock) before writing, schedule a superblock update + * and wait for it to complete. ++ * A return value of 'false' means that the write wasn't recorded ++ * and cannot proceed as the array is being suspend. + */ +-void md_write_start(struct mddev *mddev, struct bio *bi) ++bool md_write_start(struct mddev *mddev, struct bio *bi) + { + int did_change = 0; + if (bio_data_dir(bi) != WRITE) +- return; ++ return true; + + BUG_ON(mddev->ro == 1); + if (mddev->ro == 2) { +@@ -7987,7 +7994,12 @@ void md_write_start(struct mddev *mddev, + if (did_change) + sysfs_notify_dirent_safe(mddev->sysfs_state); + wait_event(mddev->sb_wait, +- !test_bit(MD_SB_CHANGE_PENDING, &mddev->sb_flags)); ++ !test_bit(MD_SB_CHANGE_PENDING, &mddev->sb_flags) && !mddev->suspended); ++ if (test_bit(MD_SB_CHANGE_PENDING, &mddev->sb_flags)) { ++ percpu_ref_put(&mddev->writes_pending); ++ return false; ++ } ++ return true; + } + EXPORT_SYMBOL(md_write_start); + +--- a/drivers/md/md.h ++++ b/drivers/md/md.h +@@ -510,7 +510,7 @@ struct md_personality + int level; + struct list_head list; + struct module *owner; +- void (*make_request)(struct mddev *mddev, struct bio *bio); ++ bool (*make_request)(struct mddev *mddev, struct bio *bio); + int (*run)(struct mddev *mddev); + void (*free)(struct mddev *mddev, void *priv); + void (*status)(struct seq_file *seq, struct mddev *mddev); +@@ -649,7 +649,7 @@ extern void md_wakeup_thread(struct md_t + extern void md_check_recovery(struct mddev *mddev); + extern void md_reap_sync_thread(struct mddev *mddev); + extern int mddev_init_writes_pending(struct mddev *mddev); +-extern void md_write_start(struct mddev *mddev, struct bio *bi); ++extern bool md_write_start(struct mddev *mddev, struct bio *bi); + extern void md_write_inc(struct mddev *mddev, struct bio *bi); + extern void md_write_end(struct mddev *mddev); + extern void md_done_sync(struct mddev *mddev, int blocks, int ok); +--- a/drivers/md/multipath.c ++++ b/drivers/md/multipath.c +@@ -106,7 +106,7 @@ static void multipath_end_request(struct + rdev_dec_pending(rdev, conf->mddev); + } + +-static void multipath_make_request(struct mddev *mddev, struct bio * bio) ++static bool multipath_make_request(struct mddev *mddev, struct bio * bio) + { + struct mpconf *conf = mddev->private; + struct multipath_bh * mp_bh; +@@ -114,7 +114,7 @@ static void multipath_make_request(struc + + if (unlikely(bio->bi_opf & REQ_PREFLUSH)) { + md_flush_request(mddev, bio); +- return; ++ return true; + } + + mp_bh = mempool_alloc(conf->pool, GFP_NOIO); +@@ -126,7 +126,7 @@ static void multipath_make_request(struc + if (mp_bh->path < 0) { + bio_io_error(bio); + mempool_free(mp_bh, conf->pool); +- return; ++ return true; + } + multipath = conf->multipaths + mp_bh->path; + +@@ -141,7 +141,7 @@ static void multipath_make_request(struc + mddev_check_writesame(mddev, &mp_bh->bio); + mddev_check_write_zeroes(mddev, &mp_bh->bio); + generic_make_request(&mp_bh->bio); +- return; ++ return true; + } + + static void multipath_status(struct seq_file *seq, struct mddev *mddev) +--- a/drivers/md/raid0.c ++++ b/drivers/md/raid0.c +@@ -548,7 +548,7 @@ static void raid0_handle_discard(struct + bio_endio(bio); + } + +-static void raid0_make_request(struct mddev *mddev, struct bio *bio) ++static bool raid0_make_request(struct mddev *mddev, struct bio *bio) + { + struct strip_zone *zone; + struct md_rdev *tmp_dev; +@@ -559,12 +559,12 @@ static void raid0_make_request(struct md + + if (unlikely(bio->bi_opf & REQ_PREFLUSH)) { + md_flush_request(mddev, bio); +- return; ++ return true; + } + + if (unlikely((bio_op(bio) == REQ_OP_DISCARD))) { + raid0_handle_discard(mddev, bio); +- return; ++ return true; + } + + bio_sector = bio->bi_iter.bi_sector; +@@ -599,6 +599,7 @@ static void raid0_make_request(struct md + mddev_check_writesame(mddev, bio); + mddev_check_write_zeroes(mddev, bio); + generic_make_request(bio); ++ return true; + } + + static void raid0_status(struct seq_file *seq, struct mddev *mddev) +--- a/drivers/md/raid1.c ++++ b/drivers/md/raid1.c +@@ -1321,7 +1321,6 @@ static void raid1_write_request(struct m + * Continue immediately if no resync is active currently. + */ + +- md_write_start(mddev, bio); /* wait on superblock update early */ + + if ((bio_end_sector(bio) > mddev->suspend_lo && + bio->bi_iter.bi_sector < mddev->suspend_hi) || +@@ -1553,13 +1552,13 @@ static void raid1_write_request(struct m + wake_up(&conf->wait_barrier); + } + +-static void raid1_make_request(struct mddev *mddev, struct bio *bio) ++static bool raid1_make_request(struct mddev *mddev, struct bio *bio) + { + sector_t sectors; + + if (unlikely(bio->bi_opf & REQ_PREFLUSH)) { + md_flush_request(mddev, bio); +- return; ++ return true; + } + + /* +@@ -1574,8 +1573,12 @@ static void raid1_make_request(struct md + + if (bio_data_dir(bio) == READ) + raid1_read_request(mddev, bio, sectors, NULL); +- else ++ else { ++ if (!md_write_start(mddev,bio)) ++ return false; + raid1_write_request(mddev, bio, sectors); ++ } ++ return true; + } + + static void raid1_status(struct seq_file *seq, struct mddev *mddev) +--- a/drivers/md/raid10.c ++++ b/drivers/md/raid10.c +@@ -1303,8 +1303,6 @@ static void raid10_write_request(struct + sector_t sectors; + int max_sectors; + +- md_write_start(mddev, bio); +- + /* + * Register the new request and wait if the reconstruction + * thread has put up a bar for new requests. +@@ -1525,7 +1523,7 @@ static void __make_request(struct mddev + raid10_write_request(mddev, bio, r10_bio); + } + +-static void raid10_make_request(struct mddev *mddev, struct bio *bio) ++static bool raid10_make_request(struct mddev *mddev, struct bio *bio) + { + struct r10conf *conf = mddev->private; + sector_t chunk_mask = (conf->geo.chunk_mask & conf->prev.chunk_mask); +@@ -1534,9 +1532,12 @@ static void raid10_make_request(struct m + + if (unlikely(bio->bi_opf & REQ_PREFLUSH)) { + md_flush_request(mddev, bio); +- return; ++ return true; + } + ++ if (!md_write_start(mddev, bio)) ++ return false; ++ + /* + * If this request crosses a chunk boundary, we need to split + * it. +@@ -1553,6 +1554,7 @@ static void raid10_make_request(struct m + + /* In case raid10d snuck in to freeze_array */ + wake_up(&conf->wait_barrier); ++ return true; + } + + static void raid10_status(struct seq_file *seq, struct mddev *mddev) +--- a/drivers/md/raid5.c ++++ b/drivers/md/raid5.c +@@ -5479,7 +5479,6 @@ static void make_discard_request(struct + last_sector = bi->bi_iter.bi_sector + (bi->bi_iter.bi_size>>9); + + bi->bi_next = NULL; +- md_write_start(mddev, bi); + + stripe_sectors = conf->chunk_sectors * + (conf->raid_disks - conf->max_degraded); +@@ -5549,11 +5548,10 @@ static void make_discard_request(struct + release_stripe_plug(mddev, sh); + } + +- md_write_end(mddev); + bio_endio(bi); + } + +-static void raid5_make_request(struct mddev *mddev, struct bio * bi) ++static bool raid5_make_request(struct mddev *mddev, struct bio * bi) + { + struct r5conf *conf = mddev->private; + int dd_idx; +@@ -5569,10 +5567,10 @@ static void raid5_make_request(struct md + int ret = r5l_handle_flush_request(conf->log, bi); + + if (ret == 0) +- return; ++ return true; + if (ret == -ENODEV) { + md_flush_request(mddev, bi); +- return; ++ return true; + } + /* ret == -EAGAIN, fallback */ + /* +@@ -5582,6 +5580,8 @@ static void raid5_make_request(struct md + do_flush = bi->bi_opf & REQ_PREFLUSH; + } + ++ if (!md_write_start(mddev, bi)) ++ return false; + /* + * If array is degraded, better not do chunk aligned read because + * later we might have to read it again in order to reconstruct +@@ -5591,18 +5591,18 @@ static void raid5_make_request(struct md + mddev->reshape_position == MaxSector) { + bi = chunk_aligned_read(mddev, bi); + if (!bi) +- return; ++ return true; + } + + if (unlikely(bio_op(bi) == REQ_OP_DISCARD)) { + make_discard_request(mddev, bi); +- return; ++ md_write_end(mddev); ++ return true; + } + + logical_sector = bi->bi_iter.bi_sector & ~((sector_t)STRIPE_SECTORS-1); + last_sector = bio_end_sector(bi); + bi->bi_next = NULL; +- md_write_start(mddev, bi); + + prepare_to_wait(&conf->wait_for_overlap, &w, TASK_UNINTERRUPTIBLE); + for (;logical_sector < last_sector; logical_sector += STRIPE_SECTORS) { +@@ -5743,6 +5743,7 @@ static void raid5_make_request(struct md + if (rw == WRITE) + md_write_end(mddev); + bio_endio(bi); ++ return true; + } + + static sector_t raid5_size(struct mddev *mddev, sector_t sectors, int raid_disks); diff --git a/queue-4.12/mxl111sf-fix-driver-to-use-heap-allocate-buffers-for-usb-messages.patch b/queue-4.12/mxl111sf-fix-driver-to-use-heap-allocate-buffers-for-usb-messages.patch new file mode 100644 index 00000000000..d8707e396a7 --- /dev/null +++ b/queue-4.12/mxl111sf-fix-driver-to-use-heap-allocate-buffers-for-usb-messages.patch @@ -0,0 +1,167 @@ +From d90b336f3f652ff0441e631a06236f785581c8f7 Mon Sep 17 00:00:00 2001 +From: Devin Heitmueller +Date: Fri, 21 Apr 2017 13:28:37 -0300 +Subject: [media] mxl111sf: Fix driver to use heap allocate buffers for USB messages + +From: Devin Heitmueller + +commit d90b336f3f652ff0441e631a06236f785581c8f7 upstream. + +The recent changes in 4.9 to mandate USB buffers be heap allocated +broke this driver, which was allocating the buffers on the stack. +This resulted in the device failing at initialization. + +Introduce dedicated send/receive buffers as part of the state +structure, and add a mutex to protect access to them. + +Note: we also had to tweak the API to mxl111sf_ctrl_msg to pass +the pointer to the state struct rather than the device, since +we need it inside the function to access the buffers and the +mutex. This patch adjusts the callers to match the API change. + +Signed-off-by: Devin Heitmueller +Reported-by: Doug Lung +Cc: Michael Ira Krufky +Signed-off-by: Hans Verkuil +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.c | 4 +-- + drivers/media/usb/dvb-usb-v2/mxl111sf.c | 32 ++++++++++++++++------------ + drivers/media/usb/dvb-usb-v2/mxl111sf.h | 8 ++++++- + 3 files changed, 28 insertions(+), 16 deletions(-) + +--- a/drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.c ++++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.c +@@ -316,7 +316,7 @@ fail: + static int mxl111sf_i2c_send_data(struct mxl111sf_state *state, + u8 index, u8 *wdata) + { +- int ret = mxl111sf_ctrl_msg(state->d, wdata[0], ++ int ret = mxl111sf_ctrl_msg(state, wdata[0], + &wdata[1], 25, NULL, 0); + mxl_fail(ret); + +@@ -326,7 +326,7 @@ static int mxl111sf_i2c_send_data(struct + static int mxl111sf_i2c_get_data(struct mxl111sf_state *state, + u8 index, u8 *wdata, u8 *rdata) + { +- int ret = mxl111sf_ctrl_msg(state->d, wdata[0], ++ int ret = mxl111sf_ctrl_msg(state, wdata[0], + &wdata[1], 25, rdata, 24); + mxl_fail(ret); + +--- a/drivers/media/usb/dvb-usb-v2/mxl111sf.c ++++ b/drivers/media/usb/dvb-usb-v2/mxl111sf.c +@@ -24,9 +24,6 @@ + #include "lgdt3305.h" + #include "lg2160.h" + +-/* Max transfer size done by I2C transfer functions */ +-#define MAX_XFER_SIZE 64 +- + int dvb_usb_mxl111sf_debug; + module_param_named(debug, dvb_usb_mxl111sf_debug, int, 0644); + MODULE_PARM_DESC(debug, "set debugging level (1=info, 2=xfer, 4=i2c, 8=reg, 16=adv (or-able))."); +@@ -55,27 +52,34 @@ MODULE_PARM_DESC(rfswitch, "force rf swi + + DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +-int mxl111sf_ctrl_msg(struct dvb_usb_device *d, ++int mxl111sf_ctrl_msg(struct mxl111sf_state *state, + u8 cmd, u8 *wbuf, int wlen, u8 *rbuf, int rlen) + { ++ struct dvb_usb_device *d = state->d; + int wo = (rbuf == NULL || rlen == 0); /* write-only */ + int ret; +- u8 sndbuf[MAX_XFER_SIZE]; + +- if (1 + wlen > sizeof(sndbuf)) { ++ if (1 + wlen > MXL_MAX_XFER_SIZE) { + pr_warn("%s: len=%d is too big!\n", __func__, wlen); + return -EOPNOTSUPP; + } + + pr_debug("%s(wlen = %d, rlen = %d)\n", __func__, wlen, rlen); + +- memset(sndbuf, 0, 1+wlen); ++ mutex_lock(&state->msg_lock); ++ memset(state->sndbuf, 0, 1+wlen); ++ memset(state->rcvbuf, 0, rlen); ++ ++ state->sndbuf[0] = cmd; ++ memcpy(&state->sndbuf[1], wbuf, wlen); ++ ++ ret = (wo) ? dvb_usbv2_generic_write(d, state->sndbuf, 1+wlen) : ++ dvb_usbv2_generic_rw(d, state->sndbuf, 1+wlen, state->rcvbuf, ++ rlen); + +- sndbuf[0] = cmd; +- memcpy(&sndbuf[1], wbuf, wlen); ++ memcpy(rbuf, state->rcvbuf, rlen); ++ mutex_unlock(&state->msg_lock); + +- ret = (wo) ? dvb_usbv2_generic_write(d, sndbuf, 1+wlen) : +- dvb_usbv2_generic_rw(d, sndbuf, 1+wlen, rbuf, rlen); + mxl_fail(ret); + + return ret; +@@ -91,7 +95,7 @@ int mxl111sf_read_reg(struct mxl111sf_st + u8 buf[2]; + int ret; + +- ret = mxl111sf_ctrl_msg(state->d, MXL_CMD_REG_READ, &addr, 1, buf, 2); ++ ret = mxl111sf_ctrl_msg(state, MXL_CMD_REG_READ, &addr, 1, buf, 2); + if (mxl_fail(ret)) { + mxl_debug("error reading reg: 0x%02x", addr); + goto fail; +@@ -117,7 +121,7 @@ int mxl111sf_write_reg(struct mxl111sf_s + + pr_debug("W: (0x%02x, 0x%02x)\n", addr, data); + +- ret = mxl111sf_ctrl_msg(state->d, MXL_CMD_REG_WRITE, buf, 2, NULL, 0); ++ ret = mxl111sf_ctrl_msg(state, MXL_CMD_REG_WRITE, buf, 2, NULL, 0); + if (mxl_fail(ret)) + pr_err("error writing reg: 0x%02x, val: 0x%02x", addr, data); + return ret; +@@ -926,6 +930,8 @@ static int mxl111sf_init(struct dvb_usb_ + .len = sizeof(eeprom), .buf = eeprom }, + }; + ++ mutex_init(&state->msg_lock); ++ + ret = get_chip_info(state); + if (mxl_fail(ret)) + pr_err("failed to get chip info during probe"); +--- a/drivers/media/usb/dvb-usb-v2/mxl111sf.h ++++ b/drivers/media/usb/dvb-usb-v2/mxl111sf.h +@@ -19,6 +19,9 @@ + #include + #include + ++/* Max transfer size done by I2C transfer functions */ ++#define MXL_MAX_XFER_SIZE 64 ++ + #define MXL_EP1_REG_READ 1 + #define MXL_EP2_REG_WRITE 2 + #define MXL_EP3_INTERRUPT 3 +@@ -86,6 +89,9 @@ struct mxl111sf_state { + struct mutex fe_lock; + u8 num_frontends; + struct mxl111sf_adap_state adap_state[3]; ++ u8 sndbuf[MXL_MAX_XFER_SIZE]; ++ u8 rcvbuf[MXL_MAX_XFER_SIZE]; ++ struct mutex msg_lock; + #ifdef CONFIG_MEDIA_CONTROLLER_DVB + struct media_entity tuner; + struct media_pad tuner_pads[2]; +@@ -108,7 +114,7 @@ int mxl111sf_ctrl_program_regs(struct mx + + /* needed for hardware i2c functions in mxl111sf-i2c.c: + * mxl111sf_i2c_send_data / mxl111sf_i2c_get_data */ +-int mxl111sf_ctrl_msg(struct dvb_usb_device *d, ++int mxl111sf_ctrl_msg(struct mxl111sf_state *state, + u8 cmd, u8 *wbuf, int wlen, u8 *rbuf, int rlen); + + #define mxl_printk(kern, fmt, arg...) \ diff --git a/queue-4.12/pci-msi-ignore-affinity-if-pre-post-vector-count-is-more-than-min_vecs.patch b/queue-4.12/pci-msi-ignore-affinity-if-pre-post-vector-count-is-more-than-min_vecs.patch new file mode 100644 index 00000000000..5ffd646afb1 --- /dev/null +++ b/queue-4.12/pci-msi-ignore-affinity-if-pre-post-vector-count-is-more-than-min_vecs.patch @@ -0,0 +1,123 @@ +From 6f9a22bc5775d231ab8fbe2c2f3c88e45e3e7c28 Mon Sep 17 00:00:00 2001 +From: Michael Hernandez +Date: Thu, 18 May 2017 10:47:47 -0700 +Subject: PCI/MSI: Ignore affinity if pre/post vector count is more than min_vecs + +From: Michael Hernandez + +commit 6f9a22bc5775d231ab8fbe2c2f3c88e45e3e7c28 upstream. + +min_vecs is the minimum amount of vectors needed to operate in MSI-X mode +which may just include the vectors that don't need affinity. + +Disabling affinity settings causes the qla2xxx driver scsi_add_host() to fail +when blk_mq is enabled as the blk_mq_pci_map_queues() expects affinity masks +on each vector. + +Fixes: dfef358bd1be ("PCI/MSI: Don't apply affinity if there aren't enough vectors left") +Signed-off-by: Michael Hernandez +Signed-off-by: Himanshu Madhani +Signed-off-by: Bjorn Helgaas +Reviewed-by: Christoph Hellwig +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/pci/msi.c | 14 ++------------ + include/linux/interrupt.h | 4 ++-- + kernel/irq/affinity.c | 13 ++++++++++++- + 3 files changed, 16 insertions(+), 15 deletions(-) + +--- a/drivers/pci/msi.c ++++ b/drivers/pci/msi.c +@@ -1058,7 +1058,7 @@ static int __pci_enable_msi_range(struct + + for (;;) { + if (affd) { +- nvec = irq_calc_affinity_vectors(nvec, affd); ++ nvec = irq_calc_affinity_vectors(minvec, nvec, affd); + if (nvec < minvec) + return -ENOSPC; + } +@@ -1097,7 +1097,7 @@ static int __pci_enable_msix_range(struc + + for (;;) { + if (affd) { +- nvec = irq_calc_affinity_vectors(nvec, affd); ++ nvec = irq_calc_affinity_vectors(minvec, nvec, affd); + if (nvec < minvec) + return -ENOSPC; + } +@@ -1165,16 +1165,6 @@ int pci_alloc_irq_vectors_affinity(struc + if (flags & PCI_IRQ_AFFINITY) { + if (!affd) + affd = &msi_default_affd; +- +- if (affd->pre_vectors + affd->post_vectors > min_vecs) +- return -EINVAL; +- +- /* +- * If there aren't any vectors left after applying the pre/post +- * vectors don't bother with assigning affinity. +- */ +- if (affd->pre_vectors + affd->post_vectors == min_vecs) +- affd = NULL; + } else { + if (WARN_ON(affd)) + affd = NULL; +--- a/include/linux/interrupt.h ++++ b/include/linux/interrupt.h +@@ -291,7 +291,7 @@ extern int + irq_set_affinity_notifier(unsigned int irq, struct irq_affinity_notify *notify); + + struct cpumask *irq_create_affinity_masks(int nvec, const struct irq_affinity *affd); +-int irq_calc_affinity_vectors(int maxvec, const struct irq_affinity *affd); ++int irq_calc_affinity_vectors(int minvec, int maxvec, const struct irq_affinity *affd); + + #else /* CONFIG_SMP */ + +@@ -331,7 +331,7 @@ irq_create_affinity_masks(int nvec, cons + } + + static inline int +-irq_calc_affinity_vectors(int maxvec, const struct irq_affinity *affd) ++irq_calc_affinity_vectors(int minvec, int maxvec, const struct irq_affinity *affd) + { + return maxvec; + } +--- a/kernel/irq/affinity.c ++++ b/kernel/irq/affinity.c +@@ -66,6 +66,13 @@ irq_create_affinity_masks(int nvecs, con + struct cpumask *masks; + cpumask_var_t nmsk; + ++ /* ++ * If there aren't any vectors left after applying the pre/post ++ * vectors don't bother with assigning affinity. ++ */ ++ if (!affv) ++ return NULL; ++ + if (!zalloc_cpumask_var(&nmsk, GFP_KERNEL)) + return NULL; + +@@ -140,15 +147,19 @@ out: + + /** + * irq_calc_affinity_vectors - Calculate the optimal number of vectors ++ * @minvec: The minimum number of vectors available + * @maxvec: The maximum number of vectors available + * @affd: Description of the affinity requirements + */ +-int irq_calc_affinity_vectors(int maxvec, const struct irq_affinity *affd) ++int irq_calc_affinity_vectors(int minvec, int maxvec, const struct irq_affinity *affd) + { + int resv = affd->pre_vectors + affd->post_vectors; + int vecs = maxvec - resv; + int cpus; + ++ if (resv > minvec) ++ return 0; ++ + /* Stabilize the cpumasks */ + get_online_cpus(); + cpus = cpumask_weight(cpu_online_mask); diff --git a/queue-4.12/pci-pm-restore-the-status-of-pci-devices-across-hibernation.patch b/queue-4.12/pci-pm-restore-the-status-of-pci-devices-across-hibernation.patch new file mode 100644 index 00000000000..6e0054f3589 --- /dev/null +++ b/queue-4.12/pci-pm-restore-the-status-of-pci-devices-across-hibernation.patch @@ -0,0 +1,93 @@ +From e60514bd4485c0c7c5a7cf779b200ce0b95c70d6 Mon Sep 17 00:00:00 2001 +From: Chen Yu +Date: Thu, 25 May 2017 16:49:07 +0800 +Subject: PCI/PM: Restore the status of PCI devices across hibernation + +From: Chen Yu + +commit e60514bd4485c0c7c5a7cf779b200ce0b95c70d6 upstream. + +Currently we saw a lot of "No irq handler" errors during hibernation, which +caused the system hang finally: + + ata4.00: qc timeout (cmd 0xec) + ata4.00: failed to IDENTIFY (I/O error, err_mask=0x4) + ata4.00: revalidation failed (errno=-5) + ata4: SATA link up 6.0 Gbps (SStatus 133 SControl 300) + do_IRQ: 31.151 No irq handler for vector + +According to above logs, there is an interrupt triggered and it is +dispatched to CPU31 with a vector number 151, but there is no handler for +it, thus this IRQ will not get acked and will cause an IRQ flood which +kills the system. To be more specific, the 31.151 is an interrupt from the +AHCI host controller. + +After some investigation, the reason why this issue is triggered is because +the thaw_noirq() function does not restore the MSI/MSI-X settings across +hibernation. + +The scenario is illustrated below: + + 1. Before hibernation, IRQ 34 is the handler for the AHCI device, which + is bound to CPU31. + + 2. Hibernation starts, the AHCI device is put into low power state. + + 3. All the nonboot CPUs are put offline, so IRQ 34 has to be migrated to + the last alive one - CPU0. + + 4. After the snapshot has been created, all the nonboot CPUs are brought + up again; IRQ 34 remains bound to CPU0. + + 5. AHCI devices are put into D0. + + 6. The snapshot is written to the disk. + +The issue is triggered in step 6. The AHCI interrupt should be delivered +to CPU0, however it is delivered to the original CPU31 instead, which +causes the "No irq handler" issue. + +Ying Huang has provided a clue that, in step 3 it is possible that writing +to the register might not take effect as the PCI devices have been +suspended. + +In step 3, the IRQ 34 affinity should be modified from CPU31 to CPU0, but +in fact it is not. In __pci_write_msi_msg(), if the device is already in +low power state, the low level MSI message entry will not be updated but +cached. During the device restore process after a normal suspend/resume, +pci_restore_msi_state() writes the cached MSI back to the hardware. + +But this is not the case for hibernation. pci_restore_msi_state() is not +currently called in pci_pm_thaw_noirq(), although pci_save_state() has +saved the necessary PCI cached information in pci_pm_freeze_noirq(). + +Restore the PCI status for the device during hibernation. Otherwise the +status might be lost across hibernation (for example, settings for MSI, +MSI-X, ATS, ACS, IOV, etc.), which might cause problems during hibernation. + +Suggested-by: Ying Huang +Suggested-by: Rafael J. Wysocki +Signed-off-by: Chen Yu +[bhelgaas: changelog] +Signed-off-by: Bjorn Helgaas +Reviewed-by: Rafael J. Wysocki +Cc: Len Brown +Cc: Dan Williams +Cc: Rui Zhang +Cc: Ying Huang +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/pci/pci-driver.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/pci/pci-driver.c ++++ b/drivers/pci/pci-driver.c +@@ -964,6 +964,7 @@ static int pci_pm_thaw_noirq(struct devi + return pci_legacy_resume_early(dev); + + pci_update_current_state(pci_dev, PCI_D0); ++ pci_restore_state(pci_dev); + + if (drv && drv->pm && drv->pm->thaw_noirq) + error = drv->pm->thaw_noirq(dev); diff --git a/queue-4.12/pci-rockchip-use-normal-register-bank-for-config-accessors.patch b/queue-4.12/pci-rockchip-use-normal-register-bank-for-config-accessors.patch new file mode 100644 index 00000000000..12a2b466663 --- /dev/null +++ b/queue-4.12/pci-rockchip-use-normal-register-bank-for-config-accessors.patch @@ -0,0 +1,87 @@ +From dc8cca5ef25ac4cb0dfc37467521a759767ff361 Mon Sep 17 00:00:00 2001 +From: Shawn Lin +Date: Mon, 3 Jul 2017 17:21:02 +0800 +Subject: PCI: rockchip: Use normal register bank for config accessors + +From: Shawn Lin + +commit dc8cca5ef25ac4cb0dfc37467521a759767ff361 upstream. + +Rockchip's RC has two banks of registers for the root port: a normal bank +that is strictly compatible with the PCIe spec, and a privileged bank that +can be used to change RO bits of root port registers. + +When probing the RC driver, we use the privileged bank to do some basic +setup work as some RO bits are hw-inited to wrong value. But we didn't +change to the normal bank after probing the driver. + +This leads to a serious problem when the PME code tries to clear the PME +status by writing PCI_EXP_RTSTA_PME to the register of PCI_EXP_RTSTA. Per +PCIe 3.0 spec, section 7.8.14, the PME status bit is RW1C. So the PME code +is doing the right thing to clear the PME status but we find the RC doesn't +clear it but actually setting it to one. So finally the system trap in +pcie_pme_work_fn() as PCI_EXP_RTSTA_PME is true now forever. This issue +can be reproduced by booting kernel with pci=nomsi. + +Use the normal register bank for the PCI config accessors. The privileged +bank is used only internally by this driver. + +Fixes: e77f847d ("PCI: rockchip: Add Rockchip PCIe controller support") +Signed-off-by: Shawn Lin +Signed-off-by: Bjorn Helgaas +Cc: Jeffy Chen +Cc: Brian Norris +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/pci/host/pcie-rockchip.c | 13 +++++++++---- + 1 file changed, 9 insertions(+), 4 deletions(-) + +--- a/drivers/pci/host/pcie-rockchip.c ++++ b/drivers/pci/host/pcie-rockchip.c +@@ -139,6 +139,7 @@ + PCIE_CORE_INT_CT | PCIE_CORE_INT_UTC | \ + PCIE_CORE_INT_MMVC) + ++#define PCIE_RC_CONFIG_NORMAL_BASE 0x800000 + #define PCIE_RC_CONFIG_BASE 0xa00000 + #define PCIE_RC_CONFIG_RID_CCR (PCIE_RC_CONFIG_BASE + 0x08) + #define PCIE_RC_CONFIG_SCC_SHIFT 16 +@@ -295,7 +296,9 @@ static int rockchip_pcie_valid_device(st + static int rockchip_pcie_rd_own_conf(struct rockchip_pcie *rockchip, + int where, int size, u32 *val) + { +- void __iomem *addr = rockchip->apb_base + PCIE_RC_CONFIG_BASE + where; ++ void __iomem *addr; ++ ++ addr = rockchip->apb_base + PCIE_RC_CONFIG_NORMAL_BASE + where; + + if (!IS_ALIGNED((uintptr_t)addr, size)) { + *val = 0; +@@ -319,11 +322,13 @@ static int rockchip_pcie_wr_own_conf(str + int where, int size, u32 val) + { + u32 mask, tmp, offset; ++ void __iomem *addr; + + offset = where & ~0x3; ++ addr = rockchip->apb_base + PCIE_RC_CONFIG_NORMAL_BASE + offset; + + if (size == 4) { +- writel(val, rockchip->apb_base + PCIE_RC_CONFIG_BASE + offset); ++ writel(val, addr); + return PCIBIOS_SUCCESSFUL; + } + +@@ -334,9 +339,9 @@ static int rockchip_pcie_wr_own_conf(str + * corrupt RW1C bits in adjacent registers. But the hardware + * doesn't support smaller writes. + */ +- tmp = readl(rockchip->apb_base + PCIE_RC_CONFIG_BASE + offset) & mask; ++ tmp = readl(addr) & mask; + tmp |= val << ((where & 0x3) * 8); +- writel(tmp, rockchip->apb_base + PCIE_RC_CONFIG_BASE + offset); ++ writel(tmp, addr); + + return PCIBIOS_SUCCESSFUL; + } diff --git a/queue-4.12/pci-vmd-move-srcu-cleanup-after-bus-child-device-removal.patch b/queue-4.12/pci-vmd-move-srcu-cleanup-after-bus-child-device-removal.patch new file mode 100644 index 00000000000..87fb25f1149 --- /dev/null +++ b/queue-4.12/pci-vmd-move-srcu-cleanup-after-bus-child-device-removal.patch @@ -0,0 +1,36 @@ +From 0cb259c47a4df466d641c1f07ae3eccaa9ba3ccb Mon Sep 17 00:00:00 2001 +From: Jon Derrick +Date: Thu, 22 Jun 2017 09:15:42 -0600 +Subject: PCI: vmd: Move SRCU cleanup after bus, child device removal + +From: Jon Derrick + +commit 0cb259c47a4df466d641c1f07ae3eccaa9ba3ccb upstream. + +Recent __call_srcu() changes have exposed that we need to cleanup SRCU +structures after pci_stop_root_bus() calls into vmd_msi_free(). + +Fixes: 3906b91844d6 ("PCI: vmd: Use SRCU as a local RCU to prevent delaying global RCU") +Signed-off-by: Jon Derrick +Signed-off-by: Bjorn Helgaas +Acked-by: Keith Busch +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/pci/host/vmd.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/pci/host/vmd.c ++++ b/drivers/pci/host/vmd.c +@@ -733,10 +733,10 @@ static void vmd_remove(struct pci_dev *d + struct vmd_dev *vmd = pci_get_drvdata(dev); + + vmd_detach_resources(vmd); +- vmd_cleanup_srcu(vmd); + sysfs_remove_link(&vmd->dev->dev.kobj, "domain"); + pci_stop_root_bus(vmd->bus); + pci_remove_root_bus(vmd->bus); ++ vmd_cleanup_srcu(vmd); + vmd_teardown_dma_ops(vmd); + irq_domain_remove(vmd->irq_domain); + } diff --git a/queue-4.12/pci-work-around-poweroff-suspend-to-ram-issue-on-macbook-pro-11.patch b/queue-4.12/pci-work-around-poweroff-suspend-to-ram-issue-on-macbook-pro-11.patch new file mode 100644 index 00000000000..20c918217b8 --- /dev/null +++ b/queue-4.12/pci-work-around-poweroff-suspend-to-ram-issue-on-macbook-pro-11.patch @@ -0,0 +1,84 @@ +From 13cfc732160f7bc7e596128ce34cda361c556966 Mon Sep 17 00:00:00 2001 +From: Bjorn Helgaas +Date: Fri, 19 Aug 2016 16:30:25 +0800 +Subject: PCI: Work around poweroff & suspend-to-RAM issue on Macbook Pro 11 + +From: Bjorn Helgaas + +commit 13cfc732160f7bc7e596128ce34cda361c556966 upstream. + +Neither soft poweroff (transition to ACPI power state S5) nor +suspend-to-RAM (transition to state S3) works on the Macbook Pro 11,4 and +11,5. + +The problem is related to the [mem 0x7fa00000-0x7fbfffff] space. When we +use that space, e.g., by assigning it to the 00:1c.0 Root Port, the ACPI +Power Management 1 Control Register (PM1_CNT) at [io 0x1804] doesn't work +anymore. + +Linux does a soft poweroff (transition to S5) by writing to PM1_CNT. The +theory about why this doesn't work is: + + - The write to PM1_CNT causes an SMI + - The BIOS SMI handler depends on something in + [mem 0x7fa00000-0x7fbfffff] + - When Linux assigns [mem 0x7fa00000-0x7fbfffff] to the 00:1c.0 Port, it + covers up whatever the SMI handler uses, so the SMI handler no longer + works correctly + +Reserve the [mem 0x7fa00000-0x7fbfffff] space so we don't assign it to +anything. + +This is voodoo programming, since we don't know what the real conflict is, +but we've failed to find the root cause. + +Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=103211 +Tested-by: thejoe@gmail.com +Signed-off-by: Bjorn Helgaas +Cc: Rafael J. Wysocki +Cc: Lukas Wunner +Cc: Chen Yu +Signed-off-by: Greg Kroah-Hartman + +--- + arch/x86/pci/fixup.c | 32 ++++++++++++++++++++++++++++++++ + 1 file changed, 32 insertions(+) + +--- a/arch/x86/pci/fixup.c ++++ b/arch/x86/pci/fixup.c +@@ -571,3 +571,35 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_IN + DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x6f60, pci_invalid_bar); + DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x6fa0, pci_invalid_bar); + DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x6fc0, pci_invalid_bar); ++ ++/* ++ * Apple MacBook Pro: Avoid [mem 0x7fa00000-0x7fbfffff] ++ * ++ * Using the [mem 0x7fa00000-0x7fbfffff] region, e.g., by assigning it to ++ * the 00:1c.0 Root Port, causes a conflict with [io 0x1804], which is used ++ * for soft poweroff and suspend-to-RAM. ++ * ++ * As far as we know, this is related to the address space, not to the Root ++ * Port itself. Attaching the quirk to the Root Port is a convenience, but ++ * it could probably also be a standalone DMI quirk. ++ * ++ * https://bugzilla.kernel.org/show_bug.cgi?id=103211 ++ */ ++static void quirk_apple_mbp_poweroff(struct pci_dev *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct resource *res; ++ ++ if ((!dmi_match(DMI_PRODUCT_NAME, "MacBookPro11,4") && ++ !dmi_match(DMI_PRODUCT_NAME, "MacBookPro11,5")) || ++ pdev->bus->number != 0 || pdev->devfn != PCI_DEVFN(0x1c, 0)) ++ return; ++ ++ res = request_mem_region(0x7fa00000, 0x200000, ++ "MacBook Pro poweroff workaround"); ++ if (res) ++ dev_info(dev, "claimed %s %pR\n", res->name, res); ++ else ++ dev_info(dev, "can't work around MacBook Pro poweroff issue\n"); ++} ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x8c10, quirk_apple_mbp_poweroff); diff --git a/queue-4.12/series b/queue-4.12/series index 9e9a9c3698f..331ab058473 100644 --- a/queue-4.12/series +++ b/queue-4.12/series @@ -55,3 +55,22 @@ powerpc-fix-emulation-of-mfocrf-in-emulate_step.patch powerpc-asm-mark-cr0-as-clobbered-in-mftb.patch powerpc-mm-radix-properly-clear-process-table-entry.patch powerpc-perf-fix-sdar_mode-value-for-continous-sampling-on-power9.patch +xen-x86-fix-cpu-hotplug.patch +pci-vmd-move-srcu-cleanup-after-bus-child-device-removal.patch +pci-work-around-poweroff-suspend-to-ram-issue-on-macbook-pro-11.patch +pci-rockchip-use-normal-register-bank-for-config-accessors.patch +pci-pm-restore-the-status-of-pci-devices-across-hibernation.patch +pci-msi-ignore-affinity-if-pre-post-vector-count-is-more-than-min_vecs.patch +usb-xhci-fix-spinlock-recursion-for-usb2-test-mode.patch +xhci-fix-memleak-in-xhci_run.patch +xhci-fix-20000ms-port-resume-timeout.patch +xhci-fix-null-pointer-dereference-when-cleaning-up-streams-for-removed-host.patch +xhci-bad-ethernet-performance-plugged-in-asm1042a-host.patch +mxl111sf-fix-driver-to-use-heap-allocate-buffers-for-usb-messages.patch +usb-storage-return-on-error-to-avoid-a-null-pointer-dereference.patch +usb-cdc-acm-add-device-id-for-quirky-printer.patch +usb-renesas_usbhs-fix-usbhsc_resume-for-usbhsf_runtime_pwctrl.patch +usb-renesas_usbhs-gadget-disable-all-eps-when-the-driver-stops.patch +hid-multitouch-do-not-blindly-set-ev_key-or-ev_abs-bits.patch +md-don-t-use-flush_signals-in-userspace-processes.patch +md-fix-deadlock-between-mddev_suspend-and-md_write_start.patch diff --git a/queue-4.12/usb-cdc-acm-add-device-id-for-quirky-printer.patch b/queue-4.12/usb-cdc-acm-add-device-id-for-quirky-printer.patch new file mode 100644 index 00000000000..b18a7bd2a86 --- /dev/null +++ b/queue-4.12/usb-cdc-acm-add-device-id-for-quirky-printer.patch @@ -0,0 +1,33 @@ +From fe855789d605590e57f9cd968d85ecce46f5c3fd Mon Sep 17 00:00:00 2001 +From: Johan Hovold +Date: Wed, 12 Jul 2017 15:08:39 +0200 +Subject: USB: cdc-acm: add device-id for quirky printer + +From: Johan Hovold + +commit fe855789d605590e57f9cd968d85ecce46f5c3fd upstream. + +Add device-id entry for DATECS FP-2000 fiscal printer needing the +NO_UNION_NORMAL quirk. + +Reported-by: Anton Avramov +Signed-off-by: Johan Hovold +Acked-by: Oliver Neukum +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/class/cdc-acm.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/usb/class/cdc-acm.c ++++ b/drivers/usb/class/cdc-acm.c +@@ -1829,6 +1829,9 @@ static const struct usb_device_id acm_id + { USB_DEVICE(0x1576, 0x03b1), /* Maretron USB100 */ + .driver_info = NO_UNION_NORMAL, /* reports zero length descriptor */ + }, ++ { USB_DEVICE(0xfff0, 0x0100), /* DATECS FP-2000 */ ++ .driver_info = NO_UNION_NORMAL, /* reports zero length descriptor */ ++ }, + + { USB_DEVICE(0x2912, 0x0001), /* ATOL FPrint */ + .driver_info = CLEAR_HALT_CONDITIONS, diff --git a/queue-4.12/usb-renesas_usbhs-fix-usbhsc_resume-for-usbhsf_runtime_pwctrl.patch b/queue-4.12/usb-renesas_usbhs-fix-usbhsc_resume-for-usbhsf_runtime_pwctrl.patch new file mode 100644 index 00000000000..92053b4ef34 --- /dev/null +++ b/queue-4.12/usb-renesas_usbhs-fix-usbhsc_resume-for-usbhsf_runtime_pwctrl.patch @@ -0,0 +1,37 @@ +From 59a0879a0e17b2e43ecdc5e3299da85b8410d7ce Mon Sep 17 00:00:00 2001 +From: Yoshihiro Shimoda +Date: Wed, 19 Jul 2017 16:16:54 +0900 +Subject: usb: renesas_usbhs: fix usbhsc_resume() for !USBHSF_RUNTIME_PWCTRL + +From: Yoshihiro Shimoda + +commit 59a0879a0e17b2e43ecdc5e3299da85b8410d7ce upstream. + +This patch fixes an issue that some registers may be not initialized +after resume if the USBHSF_RUNTIME_PWCTRL is not set. Otherwise, +if a cable is not connected, the driver will not enable INTENB0.VBSE +after resume. And then, the driver cannot detect the VBUS. + +Fixes: ca8a282a5373 ("usb: gadget: renesas_usbhs: add suspend/resume support") +Signed-off-by: Yoshihiro Shimoda +Signed-off-by: Felipe Balbi +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/renesas_usbhs/common.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/drivers/usb/renesas_usbhs/common.c ++++ b/drivers/usb/renesas_usbhs/common.c +@@ -752,8 +752,10 @@ static int usbhsc_resume(struct device * + struct usbhs_priv *priv = dev_get_drvdata(dev); + struct platform_device *pdev = usbhs_priv_to_pdev(priv); + +- if (!usbhsc_flags_has(priv, USBHSF_RUNTIME_PWCTRL)) ++ if (!usbhsc_flags_has(priv, USBHSF_RUNTIME_PWCTRL)) { + usbhsc_power_ctrl(priv, 1); ++ usbhs_mod_autonomy_mode(priv); ++ } + + usbhs_platform_call(priv, phy_reset, pdev); + diff --git a/queue-4.12/usb-renesas_usbhs-gadget-disable-all-eps-when-the-driver-stops.patch b/queue-4.12/usb-renesas_usbhs-gadget-disable-all-eps-when-the-driver-stops.patch new file mode 100644 index 00000000000..06ec1a8d930 --- /dev/null +++ b/queue-4.12/usb-renesas_usbhs-gadget-disable-all-eps-when-the-driver-stops.patch @@ -0,0 +1,121 @@ +From b8b9c974afee685789fcbb191b52d1790be3608c Mon Sep 17 00:00:00 2001 +From: Yoshihiro Shimoda +Date: Wed, 19 Jul 2017 16:16:55 +0900 +Subject: usb: renesas_usbhs: gadget: disable all eps when the driver stops + +From: Yoshihiro Shimoda + +commit b8b9c974afee685789fcbb191b52d1790be3608c upstream. + +A gadget driver will not disable eps immediately when ->disconnect() +is called. But, since this driver assumes all eps stop after +the ->disconnect(), unexpected behavior happens (especially in system +suspend). +So, this patch disables all eps in usbhsg_try_stop(). After disabling +eps by renesas_usbhs driver, since some functions will be called by +both a gadget and renesas_usbhs driver, renesas_usbhs driver should +protect uep->pipe. To protect uep->pipe easily, this patch adds a new +lock in struct usbhsg_uep. + +Fixes: 2f98382dc ("usb: renesas_usbhs: Add Renesas USBHS Gadget") +Signed-off-by: Yoshihiro Shimoda +Signed-off-by: Felipe Balbi +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/renesas_usbhs/mod_gadget.c | 31 ++++++++++++++++++++++++------- + 1 file changed, 24 insertions(+), 7 deletions(-) + +--- a/drivers/usb/renesas_usbhs/mod_gadget.c ++++ b/drivers/usb/renesas_usbhs/mod_gadget.c +@@ -37,6 +37,7 @@ struct usbhsg_gpriv; + struct usbhsg_uep { + struct usb_ep ep; + struct usbhs_pipe *pipe; ++ spinlock_t lock; /* protect the pipe */ + + char ep_name[EP_NAME_SIZE]; + +@@ -636,10 +637,16 @@ usbhsg_ep_enable_end: + static int usbhsg_ep_disable(struct usb_ep *ep) + { + struct usbhsg_uep *uep = usbhsg_ep_to_uep(ep); +- struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep); ++ struct usbhs_pipe *pipe; ++ unsigned long flags; ++ int ret = 0; + +- if (!pipe) +- return -EINVAL; ++ spin_lock_irqsave(&uep->lock, flags); ++ pipe = usbhsg_uep_to_pipe(uep); ++ if (!pipe) { ++ ret = -EINVAL; ++ goto out; ++ } + + usbhsg_pipe_disable(uep); + usbhs_pipe_free(pipe); +@@ -647,6 +654,9 @@ static int usbhsg_ep_disable(struct usb_ + uep->pipe->mod_private = NULL; + uep->pipe = NULL; + ++out: ++ spin_unlock_irqrestore(&uep->lock, flags); ++ + return 0; + } + +@@ -696,8 +706,11 @@ static int usbhsg_ep_dequeue(struct usb_ + { + struct usbhsg_uep *uep = usbhsg_ep_to_uep(ep); + struct usbhsg_request *ureq = usbhsg_req_to_ureq(req); +- struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep); ++ struct usbhs_pipe *pipe; ++ unsigned long flags; + ++ spin_lock_irqsave(&uep->lock, flags); ++ pipe = usbhsg_uep_to_pipe(uep); + if (pipe) + usbhs_pkt_pop(pipe, usbhsg_ureq_to_pkt(ureq)); + +@@ -706,6 +719,7 @@ static int usbhsg_ep_dequeue(struct usb_ + * even if the pipe is NULL. + */ + usbhsg_queue_pop(uep, ureq, -ECONNRESET); ++ spin_unlock_irqrestore(&uep->lock, flags); + + return 0; + } +@@ -852,10 +866,10 @@ static int usbhsg_try_stop(struct usbhs_ + { + struct usbhsg_gpriv *gpriv = usbhsg_priv_to_gpriv(priv); + struct usbhs_mod *mod = usbhs_mod_get_current(priv); +- struct usbhsg_uep *dcp = usbhsg_gpriv_to_dcp(gpriv); ++ struct usbhsg_uep *uep; + struct device *dev = usbhs_priv_to_dev(priv); + unsigned long flags; +- int ret = 0; ++ int ret = 0, i; + + /******************** spin lock ********************/ + usbhs_lock(priv, flags); +@@ -887,7 +901,9 @@ static int usbhsg_try_stop(struct usbhs_ + usbhs_sys_set_test_mode(priv, 0); + usbhs_sys_function_ctrl(priv, 0); + +- usbhsg_ep_disable(&dcp->ep); ++ /* disable all eps */ ++ usbhsg_for_each_uep_with_dcp(uep, gpriv, i) ++ usbhsg_ep_disable(&uep->ep); + + dev_dbg(dev, "stop gadget\n"); + +@@ -1069,6 +1085,7 @@ int usbhs_mod_gadget_probe(struct usbhs_ + ret = -ENOMEM; + goto usbhs_mod_gadget_probe_err_gpriv; + } ++ spin_lock_init(&uep->lock); + + gpriv->transceiver = usb_get_phy(USB_PHY_TYPE_UNDEFINED); + dev_info(dev, "%stransceiver found\n", diff --git a/queue-4.12/usb-storage-return-on-error-to-avoid-a-null-pointer-dereference.patch b/queue-4.12/usb-storage-return-on-error-to-avoid-a-null-pointer-dereference.patch new file mode 100644 index 00000000000..43fc569153f --- /dev/null +++ b/queue-4.12/usb-storage-return-on-error-to-avoid-a-null-pointer-dereference.patch @@ -0,0 +1,44 @@ +From 446230f52a5bef593554510302465eabab45a372 Mon Sep 17 00:00:00 2001 +From: Colin Ian King +Date: Thu, 6 Jul 2017 16:06:32 +0100 +Subject: usb: storage: return on error to avoid a null pointer dereference + +From: Colin Ian King + +commit 446230f52a5bef593554510302465eabab45a372 upstream. + +When us->extra is null the driver is not initialized, however, a +later call to osd200_scsi_to_ata is made that dereferences +us->extra, causing a null pointer dereference. The code +currently detects and reports that the driver is not initialized; +add a return to avoid the subsequent dereference issue in this +check. + +Thanks to Alan Stern for pointing out that srb->result needs setting +to DID_ERROR << 16 + +Detected by CoverityScan, CID#100308 ("Dereference after null check") + +Signed-off-by: Colin Ian King +Acked-by: Alan Stern +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/storage/isd200.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +--- a/drivers/usb/storage/isd200.c ++++ b/drivers/usb/storage/isd200.c +@@ -1529,8 +1529,11 @@ static void isd200_ata_command(struct sc + + /* Make sure driver was initialized */ + +- if (us->extra == NULL) ++ if (us->extra == NULL) { + usb_stor_dbg(us, "ERROR Driver not initialized\n"); ++ srb->result = DID_ERROR << 16; ++ return; ++ } + + scsi_set_resid(srb, 0); + /* scsi_bufflen might change in protocol translation to ata */ diff --git a/queue-4.12/usb-xhci-fix-spinlock-recursion-for-usb2-test-mode.patch b/queue-4.12/usb-xhci-fix-spinlock-recursion-for-usb2-test-mode.patch new file mode 100644 index 00000000000..421328478c3 --- /dev/null +++ b/queue-4.12/usb-xhci-fix-spinlock-recursion-for-usb2-test-mode.patch @@ -0,0 +1,39 @@ +From 576d55460e7f209139545a348746c2fcadf61bc3 Mon Sep 17 00:00:00 2001 +From: Peter Chen +Date: Thu, 20 Jul 2017 14:48:30 +0300 +Subject: usb: xhci: fix spinlock recursion for USB2 test mode + +From: Peter Chen + +commit 576d55460e7f209139545a348746c2fcadf61bc3 upstream. + +Both xhci_hub_control and xhci_disable_slot tries to hold spinlock, the +spinlock recursion occurs when enters USB2 test mode. Fix it by unlock +spinlock before calling xhci_disable_slot. + +Fixes: 0f1d832ed1fb ("usb: xhci: Add port test modes support for usb2") +Signed-off-by: Peter Chen +Signed-off-by: Mathias Nyman +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/host/xhci-hub.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/usb/host/xhci-hub.c ++++ b/drivers/usb/host/xhci-hub.c +@@ -603,12 +603,14 @@ static int xhci_enter_test_mode(struct x + + /* Disable all Device Slots */ + xhci_dbg(xhci, "Disable all slots\n"); ++ spin_unlock_irqrestore(&xhci->lock, *flags); + for (i = 1; i <= HCS_MAX_SLOTS(xhci->hcs_params1); i++) { + retval = xhci_disable_slot(xhci, NULL, i); + if (retval) + xhci_err(xhci, "Failed to disable slot %d, %d. Enter test mode anyway\n", + i, retval); + } ++ spin_lock_irqsave(&xhci->lock, *flags); + /* Put all ports to the Disable state by clear PP */ + xhci_dbg(xhci, "Disable all port (PP = 0)\n"); + /* Power off USB3 ports*/ diff --git a/queue-4.12/xen-x86-fix-cpu-hotplug.patch b/queue-4.12/xen-x86-fix-cpu-hotplug.patch new file mode 100644 index 00000000000..d0e94dc54a1 --- /dev/null +++ b/queue-4.12/xen-x86-fix-cpu-hotplug.patch @@ -0,0 +1,47 @@ +From c185ddec54657c145a0c2055e4b87918da24974f Mon Sep 17 00:00:00 2001 +From: Juergen Gross +Date: Wed, 5 Jul 2017 16:05:20 +0200 +Subject: xen/x86: fix cpu hotplug + +From: Juergen Gross + +commit c185ddec54657c145a0c2055e4b87918da24974f upstream. + +Commit dc6416f1d711eb4c1726e845d653235dcaae12e1 ("xen/x86: Call +cpu_startup_entry(CPUHP_AP_ONLINE_IDLE) from xen_play_dead()") +introduced an error leading to a stack overflow of the idle task when +a cpu was brought offline/online many times: by calling +cpu_startup_entry() instead of returning at the end of xen_play_dead() +do_idle() would be entered again and again. + +Don't use cpu_startup_entry(), but cpuhp_online_idle() instead allowing +to return from xen_play_dead(). + +Signed-off-by: Juergen Gross +Reviewed-by: Boris Ostrovsky +Signed-off-by: Juergen Gross +Signed-off-by: Greg Kroah-Hartman + +--- + arch/x86/xen/smp_pv.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/arch/x86/xen/smp_pv.c ++++ b/arch/x86/xen/smp_pv.c +@@ -19,6 +19,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -417,7 +418,7 @@ static void xen_pv_play_dead(void) /* us + */ + tick_nohz_idle_enter(); + +- cpu_startup_entry(CPUHP_AP_ONLINE_IDLE); ++ cpuhp_online_idle(CPUHP_AP_ONLINE_IDLE); + } + + #else /* !CONFIG_HOTPLUG_CPU */ diff --git a/queue-4.12/xhci-bad-ethernet-performance-plugged-in-asm1042a-host.patch b/queue-4.12/xhci-bad-ethernet-performance-plugged-in-asm1042a-host.patch new file mode 100644 index 00000000000..c4b58b4ec08 --- /dev/null +++ b/queue-4.12/xhci-bad-ethernet-performance-plugged-in-asm1042a-host.patch @@ -0,0 +1,172 @@ +From 9da5a1092b13468839b1a864b126cacfb72ad016 Mon Sep 17 00:00:00 2001 +From: Jiahau Chang +Date: Thu, 20 Jul 2017 14:48:27 +0300 +Subject: xhci: Bad Ethernet performance plugged in ASM1042A host + +From: Jiahau Chang + +commit 9da5a1092b13468839b1a864b126cacfb72ad016 upstream. + +When USB Ethernet is plugged in ASMEDIA ASM1042A xHCI host, bad +performance was manifesting in Web browser use (like download +large file such as ISO image). It is known limitation of +ASM1042A that is not compatible with driver scheduling, +As a workaround we can modify flow control handling of ASM1042A. +The register we modify is changes the behavior + +[use quirk bit 28, usleep_range 40-60us, empty non-pci function -Mathias] +Signed-off-by: Jiahau Chang +Signed-off-by: Ian Pilcher +Signed-off-by: Mathias Nyman +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/host/pci-quirks.c | 54 ++++++++++++++++++++++++++++++++++++++++++ + drivers/usb/host/pci-quirks.h | 2 + + drivers/usb/host/xhci-pci.c | 6 ++++ + drivers/usb/host/xhci.c | 6 ++++ + drivers/usb/host/xhci.h | 1 + 5 files changed, 69 insertions(+) + +--- a/drivers/usb/host/pci-quirks.c ++++ b/drivers/usb/host/pci-quirks.c +@@ -77,6 +77,16 @@ + #define USB_INTEL_USB3_PSSEN 0xD8 + #define USB_INTEL_USB3PRM 0xDC + ++/* ASMEDIA quirk use */ ++#define ASMT_DATA_WRITE0_REG 0xF8 ++#define ASMT_DATA_WRITE1_REG 0xFC ++#define ASMT_CONTROL_REG 0xE0 ++#define ASMT_CONTROL_WRITE_BIT 0x02 ++#define ASMT_WRITEREG_CMD 0x10423 ++#define ASMT_FLOWCTL_ADDR 0xFA30 ++#define ASMT_FLOWCTL_DATA 0xBA ++#define ASMT_PSEUDO_DATA 0 ++ + /* + * amd_chipset_gen values represent AMD different chipset generations + */ +@@ -412,6 +422,50 @@ void usb_amd_quirk_pll_disable(void) + } + EXPORT_SYMBOL_GPL(usb_amd_quirk_pll_disable); + ++static int usb_asmedia_wait_write(struct pci_dev *pdev) ++{ ++ unsigned long retry_count; ++ unsigned char value; ++ ++ for (retry_count = 1000; retry_count > 0; --retry_count) { ++ ++ pci_read_config_byte(pdev, ASMT_CONTROL_REG, &value); ++ ++ if (value == 0xff) { ++ dev_err(&pdev->dev, "%s: check_ready ERROR", __func__); ++ return -EIO; ++ } ++ ++ if ((value & ASMT_CONTROL_WRITE_BIT) == 0) ++ return 0; ++ ++ usleep_range(40, 60); ++ } ++ ++ dev_warn(&pdev->dev, "%s: check_write_ready timeout", __func__); ++ return -ETIMEDOUT; ++} ++ ++void usb_asmedia_modifyflowcontrol(struct pci_dev *pdev) ++{ ++ if (usb_asmedia_wait_write(pdev) != 0) ++ return; ++ ++ /* send command and address to device */ ++ pci_write_config_dword(pdev, ASMT_DATA_WRITE0_REG, ASMT_WRITEREG_CMD); ++ pci_write_config_dword(pdev, ASMT_DATA_WRITE1_REG, ASMT_FLOWCTL_ADDR); ++ pci_write_config_byte(pdev, ASMT_CONTROL_REG, ASMT_CONTROL_WRITE_BIT); ++ ++ if (usb_asmedia_wait_write(pdev) != 0) ++ return; ++ ++ /* send data to device */ ++ pci_write_config_dword(pdev, ASMT_DATA_WRITE0_REG, ASMT_FLOWCTL_DATA); ++ pci_write_config_dword(pdev, ASMT_DATA_WRITE1_REG, ASMT_PSEUDO_DATA); ++ pci_write_config_byte(pdev, ASMT_CONTROL_REG, ASMT_CONTROL_WRITE_BIT); ++} ++EXPORT_SYMBOL_GPL(usb_asmedia_modifyflowcontrol); ++ + void usb_amd_quirk_pll_enable(void) + { + usb_amd_quirk_pll(0); +--- a/drivers/usb/host/pci-quirks.h ++++ b/drivers/usb/host/pci-quirks.h +@@ -11,6 +11,7 @@ bool usb_amd_prefetch_quirk(void); + void usb_amd_dev_put(void); + void usb_amd_quirk_pll_disable(void); + void usb_amd_quirk_pll_enable(void); ++void usb_asmedia_modifyflowcontrol(struct pci_dev *pdev); + void usb_enable_intel_xhci_ports(struct pci_dev *xhci_pdev); + void usb_disable_xhci_ports(struct pci_dev *xhci_pdev); + void sb800_prefetch(struct device *dev, int on); +@@ -18,6 +19,7 @@ void sb800_prefetch(struct device *dev, + struct pci_dev; + static inline void usb_amd_quirk_pll_disable(void) {} + static inline void usb_amd_quirk_pll_enable(void) {} ++static inline void usb_asmedia_modifyflowcontrol(struct pci_dev *pdev) {} + static inline void usb_amd_dev_put(void) {} + static inline void usb_disable_xhci_ports(struct pci_dev *xhci_pdev) {} + static inline void sb800_prefetch(struct device *dev, int on) {} +--- a/drivers/usb/host/xhci-pci.c ++++ b/drivers/usb/host/xhci-pci.c +@@ -59,6 +59,8 @@ + #define PCI_DEVICE_ID_AMD_PROMONTORYA_2 0x43bb + #define PCI_DEVICE_ID_AMD_PROMONTORYA_1 0x43bc + ++#define PCI_DEVICE_ID_ASMEDIA_1042A_XHCI 0x1142 ++ + static const char hcd_name[] = "xhci_hcd"; + + static struct hc_driver __read_mostly xhci_pci_hc_driver; +@@ -217,6 +219,10 @@ static void xhci_pci_quirks(struct devic + pdev->device == 0x1142) + xhci->quirks |= XHCI_TRUST_TX_LENGTH; + ++ if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA && ++ pdev->device == PCI_DEVICE_ID_ASMEDIA_1042A_XHCI) ++ xhci->quirks |= XHCI_ASMEDIA_MODIFY_FLOWCONTROL; ++ + if (pdev->vendor == PCI_VENDOR_ID_TI && pdev->device == 0x8241) + xhci->quirks |= XHCI_LIMIT_ENDPOINT_INTERVAL_7; + +--- a/drivers/usb/host/xhci.c ++++ b/drivers/usb/host/xhci.c +@@ -198,6 +198,9 @@ int xhci_reset(struct xhci_hcd *xhci) + if (ret) + return ret; + ++ if (xhci->quirks & XHCI_ASMEDIA_MODIFY_FLOWCONTROL) ++ usb_asmedia_modifyflowcontrol(to_pci_dev(xhci_to_hcd(xhci)->self.controller)); ++ + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "Wait for controller to be ready for doorbell rings"); + /* +@@ -1087,6 +1090,9 @@ int xhci_resume(struct xhci_hcd *xhci, b + if ((xhci->quirks & XHCI_COMP_MODE_QUIRK) && !comp_timer_running) + compliance_mode_recovery_timer_init(xhci); + ++ if (xhci->quirks & XHCI_ASMEDIA_MODIFY_FLOWCONTROL) ++ usb_asmedia_modifyflowcontrol(to_pci_dev(hcd->self.controller)); ++ + /* Re-enable port polling. */ + xhci_dbg(xhci, "%s: starting port polling.\n", __func__); + set_bit(HCD_FLAG_POLL_RH, &xhci->shared_hcd->flags); +--- a/drivers/usb/host/xhci.h ++++ b/drivers/usb/host/xhci.h +@@ -1820,6 +1820,7 @@ struct xhci_hcd { + #define XHCI_BROKEN_PORT_PED (1 << 25) + #define XHCI_LIMIT_ENDPOINT_INTERVAL_7 (1 << 26) + #define XHCI_U2_DISABLE_WAKE (1 << 27) ++#define XHCI_ASMEDIA_MODIFY_FLOWCONTROL (1 << 28) + + unsigned int num_active_eps; + unsigned int limit_active_eps; diff --git a/queue-4.12/xhci-fix-20000ms-port-resume-timeout.patch b/queue-4.12/xhci-fix-20000ms-port-resume-timeout.patch new file mode 100644 index 00000000000..7b987f7c442 --- /dev/null +++ b/queue-4.12/xhci-fix-20000ms-port-resume-timeout.patch @@ -0,0 +1,41 @@ +From a54408d0a004757789863d74e29c2297edae0b4d Mon Sep 17 00:00:00 2001 +From: Mathias Nyman +Date: Thu, 20 Jul 2017 14:48:29 +0300 +Subject: xhci: fix 20000ms port resume timeout + +From: Mathias Nyman + +commit a54408d0a004757789863d74e29c2297edae0b4d upstream. + +A uncleared PLC (port link change) bit will prevent furuther port event +interrupts for that port. Leaving it uncleared caused get_port_status() +to timeout after 20000ms while waiting to get the final port event +interrupt for resume -> U0 state change. + +This is a targeted fix for a specific case where we get a port resume event +racing with xhci resume. The port event interrupt handler notices xHC is +not yet running and bails out early, leaving PLC uncleared. + +The whole xhci port resuming needs more attention, but while working on it +it anyways makes sense to always ensure PLC is cleared in get_port_status +before setting a new link state and waiting for its completion. + +Signed-off-by: Mathias Nyman +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/host/xhci-hub.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/usb/host/xhci-hub.c ++++ b/drivers/usb/host/xhci-hub.c +@@ -899,6 +899,9 @@ static u32 xhci_get_port_status(struct u + clear_bit(wIndex, &bus_state->resuming_ports); + + set_bit(wIndex, &bus_state->rexit_ports); ++ ++ xhci_test_and_clear_bit(xhci, port_array, wIndex, ++ PORT_PLC); + xhci_set_link_state(xhci, port_array, wIndex, + XDEV_U0); + diff --git a/queue-4.12/xhci-fix-memleak-in-xhci_run.patch b/queue-4.12/xhci-fix-memleak-in-xhci_run.patch new file mode 100644 index 00000000000..fc3d42185cc --- /dev/null +++ b/queue-4.12/xhci-fix-memleak-in-xhci_run.patch @@ -0,0 +1,54 @@ +From d6f5f071f1e13cadecf8aef1faa7e5d6fbc9f33b Mon Sep 17 00:00:00 2001 +From: Shu Wang +Date: Thu, 20 Jul 2017 14:48:31 +0300 +Subject: xhci: fix memleak in xhci_run() + +From: Shu Wang + +commit d6f5f071f1e13cadecf8aef1faa7e5d6fbc9f33b upstream. + +Found this issue by kmemleak. +xhci_run() did not check return val and free command for +xhci_queue_vendor_command() + +unreferenced object 0xffff88011c0be500 (size 64): + comm "kworker/0:1", pid 58, jiffies 4294670908 (age 50.420s) + hex dump (first 32 bytes): + backtrace: + [] kmemleak_alloc+0x4a/0xa0 + [] kmem_cache_alloc_trace+0xca/0x1d0 + [] xhci_alloc_command+0x44/0x130 + [] xhci_run+0x4cc/0x630 + [] usb_add_hcd+0x3bb/0x950 + [] usb_hcd_pci_probe+0x188/0x500 + [] xhci_pci_probe+0x2c/0x220 + [] local_pci_probe+0x45/0xa0 + [] work_for_cpu_fn+0x14/0x20 + [] process_one_work+0x149/0x360 + [] worker_thread+0x1d8/0x3c0 + [] kthread+0x109/0x140 + [] ret_from_fork+0x25/0x30 + [] 0xffffffffffffffff + +Signed-off-by: Shu Wang +Signed-off-by: Mathias Nyman +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/host/xhci.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/drivers/usb/host/xhci.c ++++ b/drivers/usb/host/xhci.c +@@ -622,8 +622,10 @@ int xhci_run(struct usb_hcd *hcd) + if (!command) + return -ENOMEM; + +- xhci_queue_vendor_command(xhci, command, 0, 0, 0, ++ ret = xhci_queue_vendor_command(xhci, command, 0, 0, 0, + TRB_TYPE(TRB_NEC_GET_FW)); ++ if (ret) ++ xhci_free_command(xhci, command); + } + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "Finished xhci_run for USB2 roothub"); diff --git a/queue-4.12/xhci-fix-null-pointer-dereference-when-cleaning-up-streams-for-removed-host.patch b/queue-4.12/xhci-fix-null-pointer-dereference-when-cleaning-up-streams-for-removed-host.patch new file mode 100644 index 00000000000..c9094dd52bd --- /dev/null +++ b/queue-4.12/xhci-fix-null-pointer-dereference-when-cleaning-up-streams-for-removed-host.patch @@ -0,0 +1,51 @@ +From 4b895868bb2da60a386a17cde3bf9ecbc70c79f4 Mon Sep 17 00:00:00 2001 +From: Mathias Nyman +Date: Thu, 20 Jul 2017 14:48:26 +0300 +Subject: xhci: Fix NULL pointer dereference when cleaning up streams for removed host + +From: Mathias Nyman + +commit 4b895868bb2da60a386a17cde3bf9ecbc70c79f4 upstream. + +This off by one in stream_id indexing caused NULL pointer dereference and +soft lockup on machines with USB attached SCSI devices connected to a +hotpluggable xhci controller. + +The code that cleans up pending URBs for dead hosts tried to dereference +a stream ring at the invalid stream_id 0. +ep->stream_info->stream_rings[0] doesn't point to a ring. + +Start looping stream_id from 1 like in all the other places in the driver, +and check that the ring exists before trying to kill URBs on it. + +Reported-by: rocko r +Signed-off-by: Mathias Nyman +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/host/xhci-ring.c | 11 +++++++---- + 1 file changed, 7 insertions(+), 4 deletions(-) + +--- a/drivers/usb/host/xhci-ring.c ++++ b/drivers/usb/host/xhci-ring.c +@@ -845,13 +845,16 @@ static void xhci_kill_endpoint_urbs(stru + (ep->ep_state & EP_GETTING_NO_STREAMS)) { + int stream_id; + +- for (stream_id = 0; stream_id < ep->stream_info->num_streams; ++ for (stream_id = 1; stream_id < ep->stream_info->num_streams; + stream_id++) { ++ ring = ep->stream_info->stream_rings[stream_id]; ++ if (!ring) ++ continue; ++ + xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb, + "Killing URBs for slot ID %u, ep index %u, stream %u", +- slot_id, ep_index, stream_id + 1); +- xhci_kill_ring_urbs(xhci, +- ep->stream_info->stream_rings[stream_id]); ++ slot_id, ep_index, stream_id); ++ xhci_kill_ring_urbs(xhci, ring); + } + } else { + ring = ep->ring; -- 2.47.3