--- /dev/null
+From 42c364ace52ae6b4699105b39f2559c256b6cd4c Mon Sep 17 00:00:00 2001
+From: Takashi Iwai <tiwai@suse.de>
+Date: Mon, 21 Jan 2013 16:53:37 +0100
+Subject: ALSA: hda - Add Conexant CX20755/20756/20757 codec IDs
+
+From: Takashi Iwai <tiwai@suse.de>
+
+commit 42c364ace52ae6b4699105b39f2559c256b6cd4c upstream.
+
+These are just compatible with other CX2075x codecs.
+
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ sound/pci/hda/patch_conexant.c | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+--- a/sound/pci/hda/patch_conexant.c
++++ b/sound/pci/hda/patch_conexant.c
+@@ -4580,6 +4580,12 @@ static const struct hda_codec_preset snd
+ .patch = patch_conexant_auto },
+ { .id = 0x14f15111, .name = "CX20753/4",
+ .patch = patch_conexant_auto },
++ { .id = 0x14f15113, .name = "CX20755",
++ .patch = patch_conexant_auto },
++ { .id = 0x14f15114, .name = "CX20756",
++ .patch = patch_conexant_auto },
++ { .id = 0x14f15115, .name = "CX20757",
++ .patch = patch_conexant_auto },
+ {} /* terminator */
+ };
+
+@@ -4603,6 +4609,9 @@ MODULE_ALIAS("snd-hda-codec-id:14f150b9"
+ MODULE_ALIAS("snd-hda-codec-id:14f1510f");
+ MODULE_ALIAS("snd-hda-codec-id:14f15110");
+ MODULE_ALIAS("snd-hda-codec-id:14f15111");
++MODULE_ALIAS("snd-hda-codec-id:14f15113");
++MODULE_ALIAS("snd-hda-codec-id:14f15114");
++MODULE_ALIAS("snd-hda-codec-id:14f15115");
+
+ MODULE_LICENSE("GPL");
+ MODULE_DESCRIPTION("Conexant HD-audio codec");
--- /dev/null
+From e04340375a314166e14519fca9e5b9e9394b2d7a Mon Sep 17 00:00:00 2001
+From: David Henningsson <david.henningsson@canonical.com>
+Date: Fri, 18 Jan 2013 12:00:47 +0100
+Subject: ALSA: hda - Fix mute led for another HP machine
+
+From: David Henningsson <david.henningsson@canonical.com>
+
+commit e04340375a314166e14519fca9e5b9e9394b2d7a upstream.
+
+This machine also has the "HP_Mute_LED_0_A" string in DMI information.
+
+BugLink: https://bugs.launchpad.net/bugs/1096789
+Tested-by: Tammy Yang <tammy.yang@canonical.com>
+Signed-off-by: David Henningsson <david.henningsson@canonical.com>
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ sound/pci/hda/patch_realtek.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/sound/pci/hda/patch_realtek.c
++++ b/sound/pci/hda/patch_realtek.c
+@@ -6211,6 +6211,7 @@ static const struct snd_pci_quirk alc269
+ SND_PCI_QUIRK(0x1025, 0x0349, "Acer AOD260", ALC269_FIXUP_INV_DMIC),
+ SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_MIC2_MUTE_LED),
+ SND_PCI_QUIRK(0x103c, 0x1972, "HP Pavilion 17", ALC269_FIXUP_MIC1_MUTE_LED),
++ SND_PCI_QUIRK(0x103c, 0x1977, "HP Pavilion 14", ALC269_FIXUP_MIC1_MUTE_LED),
+ SND_PCI_QUIRK(0x1043, 0x1427, "Asus Zenbook UX31E", ALC269VB_FIXUP_DMIC),
+ SND_PCI_QUIRK(0x1043, 0x1517, "Asus Zenbook UX31A", ALC269VB_FIXUP_DMIC),
+ SND_PCI_QUIRK(0x1043, 0x1a13, "Asus G73Jw", ALC269_FIXUP_ASUS_G73JW),
--- /dev/null
+From 9cf2b72b25f3f6a5a1a46a4f36037e66de52465c Mon Sep 17 00:00:00 2001
+From: Will Deacon <will.deacon@arm.com>
+Date: Tue, 22 Jan 2013 15:34:40 +0000
+Subject: arm64: elf: fix core dumping to match what glibc expects
+
+From: Will Deacon <will.deacon@arm.com>
+
+commit 9cf2b72b25f3f6a5a1a46a4f36037e66de52465c upstream.
+
+The kernel's internal definition of ELF_NGREG uses struct pt_regs, which
+means that we disagree with userspace on the size of coredumps since
+glibc correctly uses the user-visible struct user_pt_regs.
+
+This patch fixes our ELF_NGREG definition to use struct user_pt_regs
+and introduces our own ELF_CORE_COPY_REGS to convert between the user
+and kernel structure definitions.
+
+Signed-off-by: Will Deacon <will.deacon@arm.com>
+Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ arch/arm64/include/asm/elf.h | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+--- a/arch/arm64/include/asm/elf.h
++++ b/arch/arm64/include/asm/elf.h
+@@ -26,7 +26,10 @@
+
+ typedef unsigned long elf_greg_t;
+
+-#define ELF_NGREG (sizeof (struct pt_regs) / sizeof(elf_greg_t))
++#define ELF_NGREG (sizeof(struct user_pt_regs) / sizeof(elf_greg_t))
++#define ELF_CORE_COPY_REGS(dest, regs) \
++ *(struct user_pt_regs *)&(dest) = (regs)->user_regs;
++
+ typedef elf_greg_t elf_gregset_t[ELF_NGREG];
+ typedef struct user_fpsimd_state elf_fpregset_t;
+
--- /dev/null
+From f1b99392caf120d7533da260318fae0eb5053737 Mon Sep 17 00:00:00 2001
+From: Will Deacon <will.deacon@arm.com>
+Date: Fri, 18 Jan 2013 19:00:47 +0000
+Subject: arm64: makefile: fix uname munging when setting ARCH on native machine
+
+From: Will Deacon <will.deacon@arm.com>
+
+commit f1b99392caf120d7533da260318fae0eb5053737 upstream.
+
+By popular demand, arch/aarch64 is now known as arch/arm64. However,
+uname -m (and indeed the GNU triplet) still use aarch64 as the machine
+string.
+
+This patch fixes native builds of both the kernel and perf tools by
+updating the relevant Makefiles to munge the output of uname -m and
+set the ARCH variable appropriately.
+
+Signed-off-by: Will Deacon <will.deacon@arm.com>
+Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ Makefile | 2 +-
+ tools/perf/Makefile | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+--- a/Makefile
++++ b/Makefile
+@@ -169,7 +169,7 @@ SUBARCH := $(shell uname -m | sed -e s/i
+ -e s/arm.*/arm/ -e s/sa110/arm/ \
+ -e s/s390x/s390/ -e s/parisc64/parisc/ \
+ -e s/ppc.*/powerpc/ -e s/mips.*/mips/ \
+- -e s/sh[234].*/sh/ )
++ -e s/sh[234].*/sh/ -e s/aarch64.*/arm64/ )
+
+ # Cross compiling and selecting different set of gcc/bin-utils
+ # ---------------------------------------------------------------------------
+--- a/tools/perf/Makefile
++++ b/tools/perf/Makefile
+@@ -58,7 +58,7 @@ ARCH ?= $(shell echo $(uname_M) | sed -e
+ -e s/arm.*/arm/ -e s/sa110/arm/ \
+ -e s/s390x/s390/ -e s/parisc64/parisc/ \
+ -e s/ppc.*/powerpc/ -e s/mips.*/mips/ \
+- -e s/sh[234].*/sh/ )
++ -e s/sh[234].*/sh/ -e s/aarch64.*/arm64/ )
+ NO_PERF_REGS := 1
+
+ CC = $(CROSS_COMPILE)gcc
--- /dev/null
+From a82b6af37d20bfe6e99a4d890f1cf1d89059929f Mon Sep 17 00:00:00 2001
+From: Betty Dall <betty.dall@hp.com>
+Date: Sun, 13 Jan 2013 15:46:18 -0700
+Subject: PCI/AER: pci_get_domain_bus_and_slot() call missing required pci_dev_put()
+
+From: Betty Dall <betty.dall@hp.com>
+
+commit a82b6af37d20bfe6e99a4d890f1cf1d89059929f upstream.
+
+The function aer_recover_queue() calls pci_get_domain_bus_and_slot(), which
+requires that the caller decrement the reference count with pci_dev_put().
+This patch adds the missing call to pci_dev_put().
+
+Signed-off-by: Betty Dall <betty.dall@hp.com>
+Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
+Reviewed-by: Shuah Khan <shuah.khan@hp.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/pci/pcie/aer/aerdrv_core.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/pci/pcie/aer/aerdrv_core.c
++++ b/drivers/pci/pcie/aer/aerdrv_core.c
+@@ -616,6 +616,7 @@ static void aer_recover_work_func(struct
+ continue;
+ }
+ do_recovery(pdev, entry.severity);
++ pci_dev_put(pdev);
+ }
+ }
+ #endif
--- /dev/null
+From 9e16721498b0c3d3ebfa0b503c63d35c0a4c0642 Mon Sep 17 00:00:00 2001
+From: Colin Ian King <colin.king@canonical.com>
+Date: Tue, 27 Nov 2012 14:09:40 +0000
+Subject: PCI: Allow pcie_aspm=force even when FADT indicates it is unsupported
+
+From: Colin Ian King <colin.king@canonical.com>
+
+commit 9e16721498b0c3d3ebfa0b503c63d35c0a4c0642 upstream.
+
+Right now using pcie_aspm=force will not enable ASPM if the FADT indicates
+ASPM is unsupported. However, the semantics of force should probably allow
+for this, especially as they did before 3c076351c4 ("PCI: Rework ASPM
+disable code")
+
+This patch just skips the clearing of any ASPM setup that the firmware has
+carried out on this bus if pcie_aspm=force is being used.
+
+Reference: http://bugs.launchpad.net/bugs/962038
+Signed-off-by: Colin Ian King <colin.king@canonical.com>
+Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/pci/pcie/aspm.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/drivers/pci/pcie/aspm.c
++++ b/drivers/pci/pcie/aspm.c
+@@ -773,6 +773,9 @@ void pcie_clear_aspm(struct pci_bus *bus
+ {
+ struct pci_dev *child;
+
++ if (aspm_force)
++ return;
++
+ /*
+ * Clear any ASPM setup that the firmware has carried out on this bus
+ */
--- /dev/null
+From c2be6f93b383c873a4f9d521afa49b1b67d06085 Mon Sep 17 00:00:00 2001
+From: Yijing Wang <wangyijing@huawei.com>
+Date: Fri, 11 Jan 2013 10:15:54 +0800
+Subject: PCI: pciehp: Use per-slot workqueues to avoid deadlock
+
+From: Yijing Wang <wangyijing@huawei.com>
+
+commit c2be6f93b383c873a4f9d521afa49b1b67d06085 upstream.
+
+When we have a hotplug-capable PCIe port with a second hotplug-capable
+PCIe port below it, removing the device below the upstream port causes
+a deadlock.
+
+The deadlock happens because we use the pciehp_wq workqueue to run
+pciehp_power_thread(), which uses pciehp_disable_slot() to remove devices
+below the upstream port. When we remove the downstream PCIe port, we call
+pciehp_remove(), the pciehp driver's .remove() method. That calls
+flush_workqueue(pciehp_wq), which deadlocks because the
+pciehp_power_thread() work item is still running.
+
+This patch avoids the deadlock by creating a workqueue for every PCIe port
+and removing the single shared workqueue.
+
+Here's the call path that leads to the deadlock:
+
+ pciehp_queue_pushbutton_work
+ queue_work(pciehp_wq) # queue pciehp_power_thread
+ ...
+
+ pciehp_power_thread
+ pciehp_disable_slot
+ remove_board
+ pciehp_unconfigure_device
+ pci_stop_and_remove_bus_device
+ ...
+ pciehp_remove # pciehp driver .remove method
+ pciehp_release_ctrl
+ pcie_cleanup_slot
+ flush_workqueue(pciehp_wq)
+
+This is fairly urgent because it can be caused by simply unplugging a
+Thunderbolt adapter, as reported by Daniel below.
+
+[bhelgaas: changelog]
+Reference: http://lkml.kernel.org/r/CAMVG2ssiRgcTD1bej2tkUUfsWmpL5eNtPcNif9va2-Gzb2u8nQ@mail.gmail.com
+Reported-and-tested-by: Daniel J Blueman <daniel@quora.org>
+Reviewed-by: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com>
+Signed-off-by: Yijing Wang <wangyijing@huawei.com>
+Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/pci/hotplug/pciehp.h | 2 +-
+ drivers/pci/hotplug/pciehp_core.c | 11 ++---------
+ drivers/pci/hotplug/pciehp_ctrl.c | 8 ++++----
+ drivers/pci/hotplug/pciehp_hpc.c | 11 ++++++++++-
+ 4 files changed, 17 insertions(+), 15 deletions(-)
+
+--- a/drivers/pci/hotplug/pciehp.h
++++ b/drivers/pci/hotplug/pciehp.h
+@@ -44,7 +44,6 @@ extern bool pciehp_poll_mode;
+ extern int pciehp_poll_time;
+ extern bool pciehp_debug;
+ extern bool pciehp_force;
+-extern struct workqueue_struct *pciehp_wq;
+
+ #define dbg(format, arg...) \
+ do { \
+@@ -78,6 +77,7 @@ struct slot {
+ struct hotplug_slot *hotplug_slot;
+ struct delayed_work work; /* work for button event */
+ struct mutex lock;
++ struct workqueue_struct *wq;
+ };
+
+ struct event_info {
+--- a/drivers/pci/hotplug/pciehp_core.c
++++ b/drivers/pci/hotplug/pciehp_core.c
+@@ -42,7 +42,6 @@ bool pciehp_debug;
+ bool pciehp_poll_mode;
+ int pciehp_poll_time;
+ bool pciehp_force;
+-struct workqueue_struct *pciehp_wq;
+
+ #define DRIVER_VERSION "0.4"
+ #define DRIVER_AUTHOR "Dan Zink <dan.zink@compaq.com>, Greg Kroah-Hartman <greg@kroah.com>, Dely Sy <dely.l.sy@intel.com>"
+@@ -340,18 +339,13 @@ static int __init pcied_init(void)
+ {
+ int retval = 0;
+
+- pciehp_wq = alloc_workqueue("pciehp", 0, 0);
+- if (!pciehp_wq)
+- return -ENOMEM;
+-
+ pciehp_firmware_init();
+ retval = pcie_port_service_register(&hpdriver_portdrv);
+ dbg("pcie_port_service_register = %d\n", retval);
+ info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
+- if (retval) {
+- destroy_workqueue(pciehp_wq);
++ if (retval)
+ dbg("Failure to register service\n");
+- }
++
+ return retval;
+ }
+
+@@ -359,7 +353,6 @@ static void __exit pcied_cleanup(void)
+ {
+ dbg("unload_pciehpd()\n");
+ pcie_port_service_unregister(&hpdriver_portdrv);
+- destroy_workqueue(pciehp_wq);
+ info(DRIVER_DESC " version: " DRIVER_VERSION " unloaded\n");
+ }
+
+--- a/drivers/pci/hotplug/pciehp_ctrl.c
++++ b/drivers/pci/hotplug/pciehp_ctrl.c
+@@ -49,7 +49,7 @@ static int queue_interrupt_event(struct
+ info->p_slot = p_slot;
+ INIT_WORK(&info->work, interrupt_event_handler);
+
+- queue_work(pciehp_wq, &info->work);
++ queue_work(p_slot->wq, &info->work);
+
+ return 0;
+ }
+@@ -344,7 +344,7 @@ void pciehp_queue_pushbutton_work(struct
+ kfree(info);
+ goto out;
+ }
+- queue_work(pciehp_wq, &info->work);
++ queue_work(p_slot->wq, &info->work);
+ out:
+ mutex_unlock(&p_slot->lock);
+ }
+@@ -377,7 +377,7 @@ static void handle_button_press_event(st
+ if (ATTN_LED(ctrl))
+ pciehp_set_attention_status(p_slot, 0);
+
+- queue_delayed_work(pciehp_wq, &p_slot->work, 5*HZ);
++ queue_delayed_work(p_slot->wq, &p_slot->work, 5*HZ);
+ break;
+ case BLINKINGOFF_STATE:
+ case BLINKINGON_STATE:
+@@ -439,7 +439,7 @@ static void handle_surprise_event(struct
+ else
+ p_slot->state = POWERON_STATE;
+
+- queue_work(pciehp_wq, &info->work);
++ queue_work(p_slot->wq, &info->work);
+ }
+
+ static void interrupt_event_handler(struct work_struct *work)
+--- a/drivers/pci/hotplug/pciehp_hpc.c
++++ b/drivers/pci/hotplug/pciehp_hpc.c
+@@ -773,23 +773,32 @@ static void pcie_shutdown_notification(s
+ static int pcie_init_slot(struct controller *ctrl)
+ {
+ struct slot *slot;
++ char name[32];
+
+ slot = kzalloc(sizeof(*slot), GFP_KERNEL);
+ if (!slot)
+ return -ENOMEM;
+
++ snprintf(name, sizeof(name), "pciehp-%u", PSN(ctrl));
++ slot->wq = alloc_workqueue(name, 0, 0);
++ if (!slot->wq)
++ goto abort;
++
+ slot->ctrl = ctrl;
+ mutex_init(&slot->lock);
+ INIT_DELAYED_WORK(&slot->work, pciehp_queue_pushbutton_work);
+ ctrl->slot = slot;
+ return 0;
++abort:
++ kfree(slot);
++ return -ENOMEM;
+ }
+
+ static void pcie_cleanup_slot(struct controller *ctrl)
+ {
+ struct slot *slot = ctrl->slot;
+ cancel_delayed_work(&slot->work);
+- flush_workqueue(pciehp_wq);
++ destroy_workqueue(slot->wq);
+ kfree(slot);
+ }
+
--- /dev/null
+From d347e75847c1fb299c97736638f45e6ea39702d4 Mon Sep 17 00:00:00 2001
+From: Bjorn Helgaas <bhelgaas@google.com>
+Date: Fri, 11 Jan 2013 12:07:22 -0700
+Subject: PCI: shpchp: Handle push button event asynchronously
+
+From: Bjorn Helgaas <bhelgaas@google.com>
+
+commit d347e75847c1fb299c97736638f45e6ea39702d4 upstream.
+
+Use non-ordered workqueue for attention button events.
+
+Attention button events on each slot can be handled asynchronously. So
+we should use non-ordered workqueue. This patch also removes ordered
+workqueue in shpchp as a result.
+
+486b10b9f4 ("PCI: pciehp: Handle push button event asynchronously") made
+the same change to pciehp. I split this out from a patch by Yijing Wang
+<wangyijing@huawei.com> so we fix one thing at a time and to make the
+shpchp history correspond more closely with the pciehp history.
+
+Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
+CC: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/pci/hotplug/shpchp.h | 1 -
+ drivers/pci/hotplug/shpchp_core.c | 10 ----------
+ drivers/pci/hotplug/shpchp_ctrl.c | 2 +-
+ 3 files changed, 1 insertion(+), 12 deletions(-)
+
+--- a/drivers/pci/hotplug/shpchp.h
++++ b/drivers/pci/hotplug/shpchp.h
+@@ -47,7 +47,6 @@ extern bool shpchp_poll_mode;
+ extern int shpchp_poll_time;
+ extern bool shpchp_debug;
+ extern struct workqueue_struct *shpchp_wq;
+-extern struct workqueue_struct *shpchp_ordered_wq;
+
+ #define dbg(format, arg...) \
+ do { \
+--- a/drivers/pci/hotplug/shpchp_core.c
++++ b/drivers/pci/hotplug/shpchp_core.c
+@@ -40,7 +40,6 @@ bool shpchp_debug;
+ bool shpchp_poll_mode;
+ int shpchp_poll_time;
+ struct workqueue_struct *shpchp_wq;
+-struct workqueue_struct *shpchp_ordered_wq;
+
+ #define DRIVER_VERSION "0.4"
+ #define DRIVER_AUTHOR "Dan Zink <dan.zink@compaq.com>, Greg Kroah-Hartman <greg@kroah.com>, Dely Sy <dely.l.sy@intel.com>"
+@@ -181,7 +180,6 @@ void cleanup_slots(struct controller *ct
+ list_del(&slot->slot_list);
+ cancel_delayed_work(&slot->work);
+ flush_workqueue(shpchp_wq);
+- flush_workqueue(shpchp_ordered_wq);
+ pci_hp_deregister(slot->hotplug_slot);
+ }
+ }
+@@ -370,17 +368,10 @@ static int __init shpcd_init(void)
+ if (!shpchp_wq)
+ return -ENOMEM;
+
+- shpchp_ordered_wq = alloc_ordered_workqueue("shpchp_ordered", 0);
+- if (!shpchp_ordered_wq) {
+- destroy_workqueue(shpchp_wq);
+- return -ENOMEM;
+- }
+-
+ retval = pci_register_driver(&shpc_driver);
+ dbg("%s: pci_register_driver = %d\n", __func__, retval);
+ info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
+ if (retval) {
+- destroy_workqueue(shpchp_ordered_wq);
+ destroy_workqueue(shpchp_wq);
+ }
+ return retval;
+@@ -390,7 +381,6 @@ static void __exit shpcd_cleanup(void)
+ {
+ dbg("unload_shpchpd()\n");
+ pci_unregister_driver(&shpc_driver);
+- destroy_workqueue(shpchp_ordered_wq);
+ destroy_workqueue(shpchp_wq);
+ info(DRIVER_DESC " version: " DRIVER_VERSION " unloaded\n");
+ }
+--- a/drivers/pci/hotplug/shpchp_ctrl.c
++++ b/drivers/pci/hotplug/shpchp_ctrl.c
+@@ -453,7 +453,7 @@ void shpchp_queue_pushbutton_work(struct
+ kfree(info);
+ goto out;
+ }
+- queue_work(shpchp_ordered_wq, &info->work);
++ queue_work(shpchp_wq, &info->work);
+ out:
+ mutex_unlock(&p_slot->lock);
+ }
--- /dev/null
+From f652e7d2916fe2fcf9e7d709aa5b7476b431e2dd Mon Sep 17 00:00:00 2001
+From: Bjorn Helgaas <bhelgaas@google.com>
+Date: Fri, 11 Jan 2013 12:21:15 -0700
+Subject: PCI: shpchp: Use per-slot workqueues to avoid deadlock
+
+From: Bjorn Helgaas <bhelgaas@google.com>
+
+commit f652e7d2916fe2fcf9e7d709aa5b7476b431e2dd upstream.
+
+When we have an SHPC-capable bridge with a second SHPC-capable bridge
+below it, pushing the upstream bridge's attention button causes a
+deadlock.
+
+The deadlock happens because we use the shpchp_wq workqueue to run
+shpchp_pushbutton_thread(), which uses shpchp_disable_slot() to remove
+devices below the upstream bridge. When we remove the downstream bridge,
+we call shpc_remove(), the shpchp driver's .remove() method. That calls
+flush_workqueue(shpchp_wq), which deadlocks because the
+shpchp_pushbutton_thread() work item is still running.
+
+This patch avoids the deadlock by creating a workqueue for every slot
+and removing the single shared workqueue.
+
+Here's the call path that leads to the deadlock:
+
+ shpchp_queue_pushbutton_work
+ queue_work(shpchp_wq) # shpchp_pushbutton_thread
+ ...
+
+ shpchp_pushbutton_thread
+ shpchp_disable_slot
+ remove_board
+ shpchp_unconfigure_device
+ pci_stop_and_remove_bus_device
+ ...
+ shpc_remove # shpchp driver .remove method
+ hpc_release_ctlr
+ cleanup_slots
+ flush_workqueue(shpchp_wq)
+
+This change is based on code inspection, since we don't have hardware
+with this topology.
+
+Based-on-patch-by: Yijing Wang <wangyijing@huawei.com>
+Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/pci/hotplug/shpchp.h | 2 +-
+ drivers/pci/hotplug/shpchp_core.c | 25 +++++++++++++------------
+ drivers/pci/hotplug/shpchp_ctrl.c | 6 +++---
+ 3 files changed, 17 insertions(+), 16 deletions(-)
+
+--- a/drivers/pci/hotplug/shpchp.h
++++ b/drivers/pci/hotplug/shpchp.h
+@@ -46,7 +46,6 @@
+ extern bool shpchp_poll_mode;
+ extern int shpchp_poll_time;
+ extern bool shpchp_debug;
+-extern struct workqueue_struct *shpchp_wq;
+
+ #define dbg(format, arg...) \
+ do { \
+@@ -90,6 +89,7 @@ struct slot {
+ struct list_head slot_list;
+ struct delayed_work work; /* work for button event */
+ struct mutex lock;
++ struct workqueue_struct *wq;
+ u8 hp_slot;
+ };
+
+--- a/drivers/pci/hotplug/shpchp_core.c
++++ b/drivers/pci/hotplug/shpchp_core.c
+@@ -39,7 +39,6 @@
+ bool shpchp_debug;
+ bool shpchp_poll_mode;
+ int shpchp_poll_time;
+-struct workqueue_struct *shpchp_wq;
+
+ #define DRIVER_VERSION "0.4"
+ #define DRIVER_AUTHOR "Dan Zink <dan.zink@compaq.com>, Greg Kroah-Hartman <greg@kroah.com>, Dely Sy <dely.l.sy@intel.com>"
+@@ -128,6 +127,14 @@ static int init_slots(struct controller
+ slot->device = ctrl->slot_device_offset + i;
+ slot->hpc_ops = ctrl->hpc_ops;
+ slot->number = ctrl->first_slot + (ctrl->slot_num_inc * i);
++
++ snprintf(name, sizeof(name), "shpchp-%d", slot->number);
++ slot->wq = alloc_workqueue(name, 0, 0);
++ if (!slot->wq) {
++ retval = -ENOMEM;
++ goto error_info;
++ }
++
+ mutex_init(&slot->lock);
+ INIT_DELAYED_WORK(&slot->work, shpchp_queue_pushbutton_work);
+
+@@ -147,7 +154,7 @@ static int init_slots(struct controller
+ if (retval) {
+ ctrl_err(ctrl, "pci_hp_register failed with error %d\n",
+ retval);
+- goto error_info;
++ goto error_slotwq;
+ }
+
+ get_power_status(hotplug_slot, &info->power_status);
+@@ -159,6 +166,8 @@ static int init_slots(struct controller
+ }
+
+ return 0;
++error_slotwq:
++ destroy_workqueue(slot->wq);
+ error_info:
+ kfree(info);
+ error_hpslot:
+@@ -179,7 +188,7 @@ void cleanup_slots(struct controller *ct
+ slot = list_entry(tmp, struct slot, slot_list);
+ list_del(&slot->slot_list);
+ cancel_delayed_work(&slot->work);
+- flush_workqueue(shpchp_wq);
++ destroy_workqueue(slot->wq);
+ pci_hp_deregister(slot->hotplug_slot);
+ }
+ }
+@@ -362,18 +371,11 @@ static struct pci_driver shpc_driver = {
+
+ static int __init shpcd_init(void)
+ {
+- int retval = 0;
+-
+- shpchp_wq = alloc_ordered_workqueue("shpchp", 0);
+- if (!shpchp_wq)
+- return -ENOMEM;
++ int retval;
+
+ retval = pci_register_driver(&shpc_driver);
+ dbg("%s: pci_register_driver = %d\n", __func__, retval);
+ info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
+- if (retval) {
+- destroy_workqueue(shpchp_wq);
+- }
+ return retval;
+ }
+
+@@ -381,7 +383,6 @@ static void __exit shpcd_cleanup(void)
+ {
+ dbg("unload_shpchpd()\n");
+ pci_unregister_driver(&shpc_driver);
+- destroy_workqueue(shpchp_wq);
+ info(DRIVER_DESC " version: " DRIVER_VERSION " unloaded\n");
+ }
+
+--- a/drivers/pci/hotplug/shpchp_ctrl.c
++++ b/drivers/pci/hotplug/shpchp_ctrl.c
+@@ -51,7 +51,7 @@ static int queue_interrupt_event(struct
+ info->p_slot = p_slot;
+ INIT_WORK(&info->work, interrupt_event_handler);
+
+- queue_work(shpchp_wq, &info->work);
++ queue_work(p_slot->wq, &info->work);
+
+ return 0;
+ }
+@@ -453,7 +453,7 @@ void shpchp_queue_pushbutton_work(struct
+ kfree(info);
+ goto out;
+ }
+- queue_work(shpchp_wq, &info->work);
++ queue_work(p_slot->wq, &info->work);
+ out:
+ mutex_unlock(&p_slot->lock);
+ }
+@@ -501,7 +501,7 @@ static void handle_button_press_event(st
+ p_slot->hpc_ops->green_led_blink(p_slot);
+ p_slot->hpc_ops->set_attention_status(p_slot, 0);
+
+- queue_delayed_work(shpchp_wq, &p_slot->work, 5*HZ);
++ queue_delayed_work(p_slot->wq, &p_slot->work, 5*HZ);
+ break;
+ case BLINKINGOFF_STATE:
+ case BLINKINGON_STATE:
ptrace-introduce-signal_wake_up_state-and-ptrace_signal_wake_up.patch
ptrace-ensure-arch_ptrace-ptrace_request-can-never-race-with-sigkill.patch
wake_up_process-should-be-never-used-to-wakeup-a-task_stopped-traced-task.patch
+alsa-hda-fix-mute-led-for-another-hp-machine.patch
+alsa-hda-add-conexant-cx20755-20756-20757-codec-ids.patch
+arm64-makefile-fix-uname-munging-when-setting-arch-on-native-machine.patch
+arm64-elf-fix-core-dumping-to-match-what-glibc-expects.patch
+pci-aer-pci_get_domain_bus_and_slot-call-missing-required-pci_dev_put.patch
+pci-allow-pcie_aspm-force-even-when-fadt-indicates-it-is-unsupported.patch
+pci-pciehp-use-per-slot-workqueues-to-avoid-deadlock.patch
+pci-shpchp-handle-push-button-event-asynchronously.patch
+pci-shpchp-use-per-slot-workqueues-to-avoid-deadlock.patch