ftrace-fix-null-pointer-dereference-in-t_probe_next.patch
ftrace-check-for-successful-allocation-of-hash.patch
ftrace-check-for-empty-hash-and-comment-the-race-with-registering-probes.patch
+usb-storage-add-new-jms567-revision-to-unusual_devs.patch
+usb-cdc-wdm-fix-race-between-write-and-disconnect-due-to-flag-abuse.patch
+usb-chipidea-udc-don-t-do-hardware-access-if-gadget-has-stopped.patch
+usb-host-ohci-fix-a-race-condition-between-shutdown-and-irq.patch
+usb-host-xhci-rcar-fix-typo-in-compatible-string-matching.patch
+usb-storage-ums-realtek-update-module-parameter-description-for-auto_delink_en.patch
+usb-storage-ums-realtek-whitelist-auto-delink-support.patch
--- /dev/null
+From 1426bd2c9f7e3126e2678e7469dca9fd9fc6dd3e Mon Sep 17 00:00:00 2001
+From: Oliver Neukum <oneukum@suse.com>
+Date: Tue, 27 Aug 2019 12:34:36 +0200
+Subject: USB: cdc-wdm: fix race between write and disconnect due to flag abuse
+
+From: Oliver Neukum <oneukum@suse.com>
+
+commit 1426bd2c9f7e3126e2678e7469dca9fd9fc6dd3e upstream.
+
+In case of a disconnect an ongoing flush() has to be made fail.
+Nevertheless we cannot be sure that any pending URB has already
+finished, so although they will never succeed, they still must
+not be touched.
+The clean solution for this is to check for WDM_IN_USE
+and WDM_DISCONNECTED in flush(). There is no point in ever
+clearing WDM_IN_USE, as no further writes make sense.
+
+The issue is as old as the driver.
+
+Fixes: afba937e540c9 ("USB: CDC WDM driver")
+Reported-by: syzbot+d232cca6ec42c2edb3fc@syzkaller.appspotmail.com
+Signed-off-by: Oliver Neukum <oneukum@suse.com>
+Cc: stable <stable@vger.kernel.org>
+Link: https://lore.kernel.org/r/20190827103436.21143-1-oneukum@suse.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/class/cdc-wdm.c | 16 ++++++++++++----
+ 1 file changed, 12 insertions(+), 4 deletions(-)
+
+--- a/drivers/usb/class/cdc-wdm.c
++++ b/drivers/usb/class/cdc-wdm.c
+@@ -584,10 +584,20 @@ static int wdm_flush(struct file *file,
+ {
+ struct wdm_device *desc = file->private_data;
+
+- wait_event(desc->wait, !test_bit(WDM_IN_USE, &desc->flags));
++ wait_event(desc->wait,
++ /*
++ * needs both flags. We cannot do with one
++ * because resetting it would cause a race
++ * with write() yet we need to signal
++ * a disconnect
++ */
++ !test_bit(WDM_IN_USE, &desc->flags) ||
++ test_bit(WDM_DISCONNECTING, &desc->flags));
+
+ /* cannot dereference desc->intf if WDM_DISCONNECTING */
+- if (desc->werr < 0 && !test_bit(WDM_DISCONNECTING, &desc->flags))
++ if (test_bit(WDM_DISCONNECTING, &desc->flags))
++ return -ENODEV;
++ if (desc->werr < 0)
+ dev_err(&desc->intf->dev, "Error in flush path: %d\n",
+ desc->werr);
+
+@@ -955,8 +965,6 @@ static void wdm_disconnect(struct usb_in
+ spin_lock_irqsave(&desc->iuspin, flags);
+ set_bit(WDM_DISCONNECTING, &desc->flags);
+ set_bit(WDM_READ, &desc->flags);
+- /* to terminate pending flushes */
+- clear_bit(WDM_IN_USE, &desc->flags);
+ spin_unlock_irqrestore(&desc->iuspin, flags);
+ wake_up_all(&desc->wait);
+ mutex_lock(&desc->rlock);
--- /dev/null
+From cbe85c88ce80fb92956a0793518d415864dcead8 Mon Sep 17 00:00:00 2001
+From: Peter Chen <peter.chen@nxp.com>
+Date: Tue, 20 Aug 2019 02:07:58 +0000
+Subject: usb: chipidea: udc: don't do hardware access if gadget has stopped
+
+From: Peter Chen <peter.chen@nxp.com>
+
+commit cbe85c88ce80fb92956a0793518d415864dcead8 upstream.
+
+After _gadget_stop_activity is executed, we can consider the hardware
+operation for gadget has finished, and the udc can be stopped and enter
+low power mode. So, any later hardware operations (from usb_ep_ops APIs
+or usb_gadget_ops APIs) should be considered invalid, any deinitializatons
+has been covered at _gadget_stop_activity.
+
+I meet this problem when I plug out usb cable from PC using mass_storage
+gadget, my callstack like: vbus interrupt->.vbus_session->
+composite_disconnect ->pm_runtime_put_sync(&_gadget->dev),
+the composite_disconnect will call fsg_disable, but fsg_disable calls
+usb_ep_disable using async way, there are register accesses for
+usb_ep_disable. So sometimes, I get system hang due to visit register
+without clock, sometimes not.
+
+The Linux Kernel USB maintainer Alan Stern suggests this kinds of solution.
+See: http://marc.info/?l=linux-usb&m=138541769810983&w=2.
+
+Cc: <stable@vger.kernel.org> #v4.9+
+Signed-off-by: Peter Chen <peter.chen@nxp.com>
+Link: https://lore.kernel.org/r/20190820020503.27080-2-peter.chen@nxp.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/chipidea/udc.c | 32 ++++++++++++++++++++++++--------
+ 1 file changed, 24 insertions(+), 8 deletions(-)
+
+--- a/drivers/usb/chipidea/udc.c
++++ b/drivers/usb/chipidea/udc.c
+@@ -711,12 +711,6 @@ static int _gadget_stop_activity(struct
+ struct ci_hdrc *ci = container_of(gadget, struct ci_hdrc, gadget);
+ unsigned long flags;
+
+- spin_lock_irqsave(&ci->lock, flags);
+- ci->gadget.speed = USB_SPEED_UNKNOWN;
+- ci->remote_wakeup = 0;
+- ci->suspended = 0;
+- spin_unlock_irqrestore(&ci->lock, flags);
+-
+ /* flush all endpoints */
+ gadget_for_each_ep(ep, gadget) {
+ usb_ep_fifo_flush(ep);
+@@ -734,6 +728,12 @@ static int _gadget_stop_activity(struct
+ ci->status = NULL;
+ }
+
++ spin_lock_irqsave(&ci->lock, flags);
++ ci->gadget.speed = USB_SPEED_UNKNOWN;
++ ci->remote_wakeup = 0;
++ ci->suspended = 0;
++ spin_unlock_irqrestore(&ci->lock, flags);
++
+ return 0;
+ }
+
+@@ -1305,6 +1305,10 @@ static int ep_disable(struct usb_ep *ep)
+ return -EBUSY;
+
+ spin_lock_irqsave(hwep->lock, flags);
++ if (hwep->ci->gadget.speed == USB_SPEED_UNKNOWN) {
++ spin_unlock_irqrestore(hwep->lock, flags);
++ return 0;
++ }
+
+ /* only internal SW should disable ctrl endpts */
+
+@@ -1394,6 +1398,10 @@ static int ep_queue(struct usb_ep *ep, s
+ return -EINVAL;
+
+ spin_lock_irqsave(hwep->lock, flags);
++ if (hwep->ci->gadget.speed == USB_SPEED_UNKNOWN) {
++ spin_unlock_irqrestore(hwep->lock, flags);
++ return 0;
++ }
+ retval = _ep_queue(ep, req, gfp_flags);
+ spin_unlock_irqrestore(hwep->lock, flags);
+ return retval;
+@@ -1417,8 +1425,8 @@ static int ep_dequeue(struct usb_ep *ep,
+ return -EINVAL;
+
+ spin_lock_irqsave(hwep->lock, flags);
+-
+- hw_ep_flush(hwep->ci, hwep->num, hwep->dir);
++ if (hwep->ci->gadget.speed != USB_SPEED_UNKNOWN)
++ hw_ep_flush(hwep->ci, hwep->num, hwep->dir);
+
+ list_for_each_entry_safe(node, tmpnode, &hwreq->tds, td) {
+ dma_pool_free(hwep->td_pool, node->ptr, node->dma);
+@@ -1489,6 +1497,10 @@ static void ep_fifo_flush(struct usb_ep
+ }
+
+ spin_lock_irqsave(hwep->lock, flags);
++ if (hwep->ci->gadget.speed == USB_SPEED_UNKNOWN) {
++ spin_unlock_irqrestore(hwep->lock, flags);
++ return;
++ }
+
+ hw_ep_flush(hwep->ci, hwep->num, hwep->dir);
+
+@@ -1557,6 +1569,10 @@ static int ci_udc_wakeup(struct usb_gadg
+ int ret = 0;
+
+ spin_lock_irqsave(&ci->lock, flags);
++ if (ci->gadget.speed == USB_SPEED_UNKNOWN) {
++ spin_unlock_irqrestore(&ci->lock, flags);
++ return 0;
++ }
+ if (!ci->remote_wakeup) {
+ ret = -EOPNOTSUPP;
+ goto out;
--- /dev/null
+From a349b95d7ca0cea71be4a7dac29830703de7eb62 Mon Sep 17 00:00:00 2001
+From: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
+Date: Tue, 27 Aug 2019 12:51:50 +0900
+Subject: usb: host: ohci: fix a race condition between shutdown and irq
+
+From: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
+
+commit a349b95d7ca0cea71be4a7dac29830703de7eb62 upstream.
+
+This patch fixes an issue that the following error is
+possible to happen when ohci hardware causes an interruption
+and the system is shutting down at the same time.
+
+[ 34.851754] usb 2-1: USB disconnect, device number 2
+[ 35.166658] irq 156: nobody cared (try booting with the "irqpoll" option)
+[ 35.173445] CPU: 0 PID: 22 Comm: kworker/0:1 Not tainted 5.3.0-rc5 #85
+[ 35.179964] Hardware name: Renesas Salvator-X 2nd version board based on r8a77965 (DT)
+[ 35.187886] Workqueue: usb_hub_wq hub_event
+[ 35.192063] Call trace:
+[ 35.194509] dump_backtrace+0x0/0x150
+[ 35.198165] show_stack+0x14/0x20
+[ 35.201475] dump_stack+0xa0/0xc4
+[ 35.204785] __report_bad_irq+0x34/0xe8
+[ 35.208614] note_interrupt+0x2cc/0x318
+[ 35.212446] handle_irq_event_percpu+0x5c/0x88
+[ 35.216883] handle_irq_event+0x48/0x78
+[ 35.220712] handle_fasteoi_irq+0xb4/0x188
+[ 35.224802] generic_handle_irq+0x24/0x38
+[ 35.228804] __handle_domain_irq+0x5c/0xb0
+[ 35.232893] gic_handle_irq+0x58/0xa8
+[ 35.236548] el1_irq+0xb8/0x180
+[ 35.239681] __do_softirq+0x94/0x23c
+[ 35.243253] irq_exit+0xd0/0xd8
+[ 35.246387] __handle_domain_irq+0x60/0xb0
+[ 35.250475] gic_handle_irq+0x58/0xa8
+[ 35.254130] el1_irq+0xb8/0x180
+[ 35.257268] kernfs_find_ns+0x5c/0x120
+[ 35.261010] kernfs_find_and_get_ns+0x3c/0x60
+[ 35.265361] sysfs_unmerge_group+0x20/0x68
+[ 35.269454] dpm_sysfs_remove+0x2c/0x68
+[ 35.273284] device_del+0x80/0x370
+[ 35.276683] hid_destroy_device+0x28/0x60
+[ 35.280686] usbhid_disconnect+0x4c/0x80
+[ 35.284602] usb_unbind_interface+0x6c/0x268
+[ 35.288867] device_release_driver_internal+0xe4/0x1b0
+[ 35.293998] device_release_driver+0x14/0x20
+[ 35.298261] bus_remove_device+0x110/0x128
+[ 35.302350] device_del+0x148/0x370
+[ 35.305832] usb_disable_device+0x8c/0x1d0
+[ 35.309921] usb_disconnect+0xc8/0x2d0
+[ 35.313663] hub_event+0x6e0/0x1128
+[ 35.317146] process_one_work+0x1e0/0x320
+[ 35.321148] worker_thread+0x40/0x450
+[ 35.324805] kthread+0x124/0x128
+[ 35.328027] ret_from_fork+0x10/0x18
+[ 35.331594] handlers:
+[ 35.333862] [<0000000079300c1d>] usb_hcd_irq
+[ 35.338126] [<0000000079300c1d>] usb_hcd_irq
+[ 35.342389] Disabling IRQ #156
+
+ohci_shutdown() disables all the interrupt and rh_state is set to
+OHCI_RH_HALTED. In other hand, ohci_irq() is possible to enable
+OHCI_INTR_SF and OHCI_INTR_MIE on ohci_irq(). Note that OHCI_INTR_SF
+is possible to be set by start_ed_unlink() which is called:
+ ohci_irq()
+ -> process_done_list()
+ -> takeback_td()
+ -> start_ed_unlink()
+
+So, ohci_irq() has the following condition, the issue happens by
+&ohci->regs->intrenable = OHCI_INTR_MIE | OHCI_INTR_SF and
+ohci->rh_state = OHCI_RH_HALTED:
+
+ /* interrupt for some other device? */
+ if (ints == 0 || unlikely(ohci->rh_state == OHCI_RH_HALTED))
+ return IRQ_NOTMINE;
+
+To fix the issue, ohci_shutdown() holds the spin lock while disabling
+the interruption and changing the rh_state flag to prevent reenable
+the OHCI_INTR_MIE unexpectedly. Note that io_watchdog_func() also
+calls the ohci_shutdown() and it already held the spin lock, so that
+the patch makes a new function as _ohci_shutdown().
+
+This patch is inspired by a Renesas R-Car Gen3 BSP patch
+from Tho Vu.
+
+Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
+Cc: stable <stable@vger.kernel.org>
+Acked-by: Alan Stern <stern@rowland.harvard.edu>
+Link: https://lore.kernel.org/r/1566877910-6020-1-git-send-email-yoshihiro.shimoda.uh@renesas.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/host/ohci-hcd.c | 15 ++++++++++++---
+ 1 file changed, 12 insertions(+), 3 deletions(-)
+
+--- a/drivers/usb/host/ohci-hcd.c
++++ b/drivers/usb/host/ohci-hcd.c
+@@ -417,8 +417,7 @@ static void ohci_usb_reset (struct ohci_
+ * other cases where the next software may expect clean state from the
+ * "firmware". this is bus-neutral, unlike shutdown() methods.
+ */
+-static void
+-ohci_shutdown (struct usb_hcd *hcd)
++static void _ohci_shutdown(struct usb_hcd *hcd)
+ {
+ struct ohci_hcd *ohci;
+
+@@ -434,6 +433,16 @@ ohci_shutdown (struct usb_hcd *hcd)
+ ohci->rh_state = OHCI_RH_HALTED;
+ }
+
++static void ohci_shutdown(struct usb_hcd *hcd)
++{
++ struct ohci_hcd *ohci = hcd_to_ohci(hcd);
++ unsigned long flags;
++
++ spin_lock_irqsave(&ohci->lock, flags);
++ _ohci_shutdown(hcd);
++ spin_unlock_irqrestore(&ohci->lock, flags);
++}
++
+ /*-------------------------------------------------------------------------*
+ * HC functions
+ *-------------------------------------------------------------------------*/
+@@ -752,7 +761,7 @@ static void io_watchdog_func(unsigned lo
+ died:
+ usb_hc_died(ohci_to_hcd(ohci));
+ ohci_dump(ohci);
+- ohci_shutdown(ohci_to_hcd(ohci));
++ _ohci_shutdown(ohci_to_hcd(ohci));
+ goto done;
+ } else {
+ /* No write back because the done queue was empty */
--- /dev/null
+From 636bd02a7ba9025ff851d0cfb92768c8fa865859 Mon Sep 17 00:00:00 2001
+From: Geert Uytterhoeven <geert+renesas@glider.be>
+Date: Tue, 27 Aug 2019 14:51:12 +0200
+Subject: usb: host: xhci: rcar: Fix typo in compatible string matching
+
+From: Geert Uytterhoeven <geert+renesas@glider.be>
+
+commit 636bd02a7ba9025ff851d0cfb92768c8fa865859 upstream.
+
+It's spelled "renesas", not "renensas".
+
+Due to this typo, RZ/G1M and RZ/G1N were not covered by the check.
+
+Fixes: 2dc240a3308b ("usb: host: xhci: rcar: retire use of xhci_plat_type_is()")
+Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
+Cc: stable <stable@vger.kernel.org>
+Reviewed-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
+Link: https://lore.kernel.org/r/20190827125112.12192-1-geert+renesas@glider.be
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/host/xhci-rcar.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/usb/host/xhci-rcar.c
++++ b/drivers/usb/host/xhci-rcar.c
+@@ -113,7 +113,7 @@ static int xhci_rcar_is_gen2(struct devi
+ return of_device_is_compatible(node, "renesas,xhci-r8a7790") ||
+ of_device_is_compatible(node, "renesas,xhci-r8a7791") ||
+ of_device_is_compatible(node, "renesas,xhci-r8a7793") ||
+- of_device_is_compatible(node, "renensas,rcar-gen2-xhci");
++ of_device_is_compatible(node, "renesas,rcar-gen2-xhci");
+ }
+
+ static int xhci_rcar_is_gen3(struct device *dev)
--- /dev/null
+From 08d676d1685c2a29e4d0e1b0242324e564d4589e Mon Sep 17 00:00:00 2001
+From: Henk van der Laan <opensource@henkvdlaan.com>
+Date: Fri, 16 Aug 2019 22:08:47 +0200
+Subject: usb-storage: Add new JMS567 revision to unusual_devs
+
+From: Henk van der Laan <opensource@henkvdlaan.com>
+
+commit 08d676d1685c2a29e4d0e1b0242324e564d4589e upstream.
+
+Revision 0x0117 suffers from an identical issue to earlier revisions,
+therefore it should be added to the quirks list.
+
+Signed-off-by: Henk van der Laan <opensource@henkvdlaan.com>
+Cc: stable <stable@vger.kernel.org>
+Link: https://lore.kernel.org/r/20190816200847.21366-1-opensource@henkvdlaan.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/storage/unusual_devs.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/usb/storage/unusual_devs.h
++++ b/drivers/usb/storage/unusual_devs.h
+@@ -2119,7 +2119,7 @@ UNUSUAL_DEV( 0x14cd, 0x6600, 0x0201, 0x
+ US_FL_IGNORE_RESIDUE ),
+
+ /* Reported by Michael Büsch <m@bues.ch> */
+-UNUSUAL_DEV( 0x152d, 0x0567, 0x0114, 0x0116,
++UNUSUAL_DEV( 0x152d, 0x0567, 0x0114, 0x0117,
+ "JMicron",
+ "USB to ATA/ATAPI Bridge",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
--- /dev/null
+From f6445b6b2f2bb1745080af4a0926049e8bca2617 Mon Sep 17 00:00:00 2001
+From: Kai-Heng Feng <kai.heng.feng@canonical.com>
+Date: Wed, 28 Aug 2019 01:34:49 +0800
+Subject: USB: storage: ums-realtek: Update module parameter description for auto_delink_en
+
+From: Kai-Heng Feng <kai.heng.feng@canonical.com>
+
+commit f6445b6b2f2bb1745080af4a0926049e8bca2617 upstream.
+
+The option named "auto_delink_en" is a bit misleading, as setting it to
+false doesn't really disable auto-delink but let auto-delink be firmware
+controlled.
+
+Update the description to reflect the real usage of this parameter.
+
+Signed-off-by: Kai-Heng Feng <kai.heng.feng@canonical.com>
+Cc: stable <stable@vger.kernel.org>
+Link: https://lore.kernel.org/r/20190827173450.13572-1-kai.heng.feng@canonical.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/storage/realtek_cr.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/usb/storage/realtek_cr.c
++++ b/drivers/usb/storage/realtek_cr.c
+@@ -50,7 +50,7 @@ MODULE_LICENSE("GPL");
+
+ static int auto_delink_en = 1;
+ module_param(auto_delink_en, int, S_IRUGO | S_IWUSR);
+-MODULE_PARM_DESC(auto_delink_en, "enable auto delink");
++MODULE_PARM_DESC(auto_delink_en, "auto delink mode (0=firmware, 1=software [default])");
+
+ #ifdef CONFIG_REALTEK_AUTOPM
+ static int ss_en = 1;
--- /dev/null
+From 1902a01e2bcc3abd7c9a18dc05e78c7ab4a53c54 Mon Sep 17 00:00:00 2001
+From: Kai-Heng Feng <kai.heng.feng@canonical.com>
+Date: Wed, 28 Aug 2019 01:34:50 +0800
+Subject: USB: storage: ums-realtek: Whitelist auto-delink support
+
+From: Kai-Heng Feng <kai.heng.feng@canonical.com>
+
+commit 1902a01e2bcc3abd7c9a18dc05e78c7ab4a53c54 upstream.
+
+Auto-delink requires writing special registers to ums-realtek devices.
+Unconditionally enable auto-delink may break newer devices.
+
+So only enable auto-delink by default for the original three IDs,
+0x0138, 0x0158 and 0x0159.
+
+Realtek is working on a patch to properly support auto-delink for other
+IDs.
+
+BugLink: https://bugs.launchpad.net/bugs/1838886
+Signed-off-by: Kai-Heng Feng <kai.heng.feng@canonical.com>
+Acked-by: Alan Stern <stern@rowland.harvard.edu>
+Cc: stable <stable@vger.kernel.org>
+Link: https://lore.kernel.org/r/20190827173450.13572-2-kai.heng.feng@canonical.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/storage/realtek_cr.c | 13 ++++++++-----
+ 1 file changed, 8 insertions(+), 5 deletions(-)
+
+--- a/drivers/usb/storage/realtek_cr.c
++++ b/drivers/usb/storage/realtek_cr.c
+@@ -1009,12 +1009,15 @@ static int init_realtek_cr(struct us_dat
+ goto INIT_FAIL;
+ }
+
+- if (CHECK_FW_VER(chip, 0x5888) || CHECK_FW_VER(chip, 0x5889) ||
+- CHECK_FW_VER(chip, 0x5901))
+- SET_AUTO_DELINK(chip);
+- if (STATUS_LEN(chip) == 16) {
+- if (SUPPORT_AUTO_DELINK(chip))
++ if (CHECK_PID(chip, 0x0138) || CHECK_PID(chip, 0x0158) ||
++ CHECK_PID(chip, 0x0159)) {
++ if (CHECK_FW_VER(chip, 0x5888) || CHECK_FW_VER(chip, 0x5889) ||
++ CHECK_FW_VER(chip, 0x5901))
+ SET_AUTO_DELINK(chip);
++ if (STATUS_LEN(chip) == 16) {
++ if (SUPPORT_AUTO_DELINK(chip))
++ SET_AUTO_DELINK(chip);
++ }
+ }
+ #ifdef CONFIG_REALTEK_AUTOPM
+ if (ss_en)