Merge "arm64: defconfig: Enable Command DB" into msm-4.8
diff --git a/Documentation/devicetree/bindings/usb/msm-ssusb.txt b/Documentation/devicetree/bindings/usb/msm-ssusb.txt
index f4d1090..1c870ac 100644
--- a/Documentation/devicetree/bindings/usb/msm-ssusb.txt
+++ b/Documentation/devicetree/bindings/usb/msm-ssusb.txt
@@ -39,7 +39,7 @@
  - clocks: a list of phandles to the controller clocks. Use as per
    Documentation/devicetree/bindings/clock/clock-bindings.txt
  - clock-names: Names of the clocks in 1-1 correspondence with the "clocks"
-   property. Optional clocks are "bus_aggr_clk" and "cfg_ahb_clk".
+   property. Optional clocks are "bus_aggr_clk", "noc_aggr_clk" and "cfg_ahb_clk".
 - qcom,charging-disabled: If present then battery charging using USB
   is disabled.
 - vbus_dwc3-supply: phandle to the 5V VBUS supply regulator used for host mode.
@@ -95,12 +95,13 @@
 		clocks = <&clock_gcc clk_gcc_usb30_master_clk>,
 			<&clock_gcc clk_gcc_cfg_noc_usb3_axi_clk>,
 			<&clock_gcc clk_gcc_aggre1_usb3_axi_clk>,
+			<&clock_rpmcc RPM_AGGR2_NOC_CLK>,
 			<&clock_gcc clk_gcc_usb30_mock_utmi_clk>,
 			<&clock_gcc clk_gcc_usb30_sleep_clk>,
 			<&clock_gcc clk_gcc_usb_phy_cfg_ahb2phy_clk>,
 			<&clock_gcc clk_cxo_dwc3_clk>;
 
-		clock-names = "core_clk", "iface_clk", "bus_aggr_clk",
+		clock-names = "core_clk", "iface_clk", "bus_aggr_clk", "noc_aggr_clk",
 				"utmi_clk", "sleep_clk", "cfg_ahb_clk", "xo";
 
 		resets = <&clock_gcc GCC_USB_30_BCR>;
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c
index 2575878..5759847 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c
@@ -624,16 +624,16 @@
 
 	IPADBG("cmd=%x nr=%d\n", cmd, _IOC_NR(cmd));
 
-	if (!ipa3_is_ready()) {
-		IPAERR("IPA not ready, waiting for init completion\n");
-		wait_for_completion(&ipa3_ctx->init_completion_obj);
-	}
-
 	if (_IOC_TYPE(cmd) != IPA_IOC_MAGIC)
 		return -ENOTTY;
 	if (_IOC_NR(cmd) >= IPA_IOCTL_MAX)
 		return -ENOTTY;
 
+	if (!ipa3_is_ready()) {
+		IPAERR("IPA not ready, waiting for init completion\n");
+		wait_for_completion(&ipa3_ctx->init_completion_obj);
+	}
+
 	IPA_ACTIVE_CLIENTS_INC_SIMPLE();
 
 	switch (cmd) {
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index 65fe33b..f4060d9 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -191,6 +191,9 @@
 		return ret;
 	}
 
+	if (dwc->maximum_speed == USB_SPEED_HIGH)
+		goto generic_phy_init;
+
 	ret = usb_phy_init(dwc->usb3_phy);
 	if (ret == -EBUSY) {
 		/*
@@ -203,6 +206,8 @@
 				__func__, ret);
 		return ret;
 	}
+
+generic_phy_init:
 	ret = phy_init(dwc->usb2_generic_phy);
 	if (ret < 0)
 		return ret;
@@ -223,10 +228,13 @@
 static int dwc3_core_reset(struct dwc3 *dwc)
 {
 	int		ret;
+	u32	reg;
 
 	/* Reset PHYs */
 	usb_phy_reset(dwc->usb2_phy);
-	usb_phy_reset(dwc->usb3_phy);
+
+	if (dwc->maximum_speed == USB_SPEED_SUPER)
+		usb_phy_reset(dwc->usb3_phy);
 
 	/* Initialize PHYs */
 	ret = dwc3_init_usb_phys(dwc);
@@ -236,6 +244,10 @@
 		return ret;
 	}
 
+	reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
+	reg &= ~DWC3_GUSB3PIPECTL_DELAYP1TRANS;
+	dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
+
 	dwc3_notify_event(dwc, DWC3_CONTROLLER_RESET_EVENT);
 
 	dwc3_notify_event(dwc, DWC3_CONTROLLER_POST_RESET_EVENT);
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 968237d..246552e 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -1061,7 +1061,7 @@
 
 	/* IRQ timing statistics */
 	int			irq;
-	struct tasklet_struct	bh;
+	unsigned long		ep_cmd_timeout_cnt;
 	unsigned long		irq_cnt;
 	unsigned int		bh_completion_time[MAX_INTR_STATS];
 	unsigned int		bh_handled_evt_cnt[MAX_INTR_STATS];
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index ea36f41..57db6d9 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -44,6 +44,7 @@
 #include <linux/irq.h>
 #include <linux/extcon.h>
 #include <linux/reset.h>
+#include <linux/clk/qcom.h>
 
 #include "power.h"
 #include "core.h"
@@ -157,6 +158,7 @@
 	unsigned int		utmi_clk_rate;
 	struct clk		*utmi_clk_src;
 	struct clk		*bus_aggr_clk;
+	struct clk		*noc_aggr_clk;
 	struct clk		*cfg_ahb_clk;
 	struct reset_control	*core_reset;
 	struct regulator	*dwc3_gdsc;
@@ -1244,6 +1246,7 @@
 	struct usb_gsi_request *request;
 	struct gsi_channel_info *ch_info;
 	bool block_db, f_suspend;
+	unsigned long flags;
 
 	switch (op) {
 	case GSI_EP_OP_PREPARE_TRBS:
@@ -1258,11 +1261,15 @@
 	case GSI_EP_OP_CONFIG:
 		request = (struct usb_gsi_request *)op_data;
 		dev_dbg(mdwc->dev, "EP_OP_CONFIG for %s\n", ep->name);
+		spin_lock_irqsave(&dwc->lock, flags);
 		gsi_configure_ep(ep, request);
+		spin_unlock_irqrestore(&dwc->lock, flags);
 		break;
 	case GSI_EP_OP_STARTXFER:
 		dev_dbg(mdwc->dev, "EP_OP_STARTXFER for %s\n", ep->name);
+		spin_lock_irqsave(&dwc->lock, flags);
 		ret = gsi_startxfer_for_ep(ep);
+		spin_unlock_irqrestore(&dwc->lock, flags);
 		break;
 	case GSI_EP_OP_GET_XFER_IDX:
 		dev_dbg(mdwc->dev, "EP_OP_GET_XFER_IDX for %s\n", ep->name);
@@ -1288,12 +1295,16 @@
 	case GSI_EP_OP_UPDATEXFER:
 		request = (struct usb_gsi_request *)op_data;
 		dev_dbg(mdwc->dev, "EP_OP_UPDATEXFER\n");
+		spin_lock_irqsave(&dwc->lock, flags);
 		ret = gsi_updatexfer_for_ep(ep, request);
+		spin_unlock_irqrestore(&dwc->lock, flags);
 		break;
 	case GSI_EP_OP_ENDXFER:
 		request = (struct usb_gsi_request *)op_data;
 		dev_dbg(mdwc->dev, "EP_OP_ENDXFER for %s\n", ep->name);
+		spin_lock_irqsave(&dwc->lock, flags);
 		gsi_endxfer_for_ep(ep);
+		spin_unlock_irqrestore(&dwc->lock, flags);
 		break;
 	case GSI_EP_OP_SET_CLR_BLOCK_DBL:
 		block_db = *((bool *)op_data);
@@ -1444,11 +1455,10 @@
 		pm_runtime_suspend(mdwc->dev);
 	}
 
+	mdwc->in_restart = false;
 	/* Force reconnect only if cable is still connected */
-	if (mdwc->vbus_active) {
-		mdwc->in_restart = false;
+	if (mdwc->vbus_active)
 		dwc3_resume_work(&mdwc->resume_work);
-	}
 
 	dwc->err_evt_seen = false;
 	flush_delayed_work(&mdwc->sm_work);
@@ -1684,7 +1694,7 @@
 		break;
 	case DWC3_CONTROLLER_RESTART_USB_SESSION:
 		dev_dbg(mdwc->dev, "DWC3_CONTROLLER_RESTART_USB_SESSION received\n");
-		dwc3_restart_usb_work(&mdwc->restart_usb_work);
+		schedule_work(&mdwc->restart_usb_work);
 		break;
 	default:
 		dev_dbg(mdwc->dev, "unknown dwc3 event\n");
@@ -1757,7 +1767,7 @@
 	u32 reg = 0;
 
 	if ((mdwc->in_host_mode || mdwc->vbus_active)
-			&& dwc3_msm_is_superspeed(mdwc)) {
+			&& dwc3_msm_is_superspeed(mdwc) && !mdwc->in_restart) {
 		if (!atomic_read(&mdwc->in_p3)) {
 			dev_err(mdwc->dev, "Not in P3,aborting LPM sequence\n");
 			return -EBUSY;
@@ -1903,7 +1913,7 @@
 	usb_phy_set_suspend(mdwc->hs_phy, 1);
 
 	/* Suspend SS PHY */
-	if (can_suspend_ssphy) {
+	if (dwc->maximum_speed == USB_SPEED_SUPER && can_suspend_ssphy) {
 		/* indicate phy about SS mode */
 		if (dwc3_msm_is_superspeed(mdwc))
 			mdwc->ss_phy->flags |= DEVICE_IN_SS_MODE;
@@ -1919,8 +1929,16 @@
 		clk_disable_unprepare(mdwc->bus_aggr_clk);
 	clk_disable_unprepare(mdwc->utmi_clk);
 
+	/* Memory core: OFF, Memory periphery: OFF */
+	if (!mdwc->in_host_mode && !mdwc->vbus_active) {
+		clk_set_flags(mdwc->core_clk, CLKFLAG_NORETAIN_MEM);
+		clk_set_flags(mdwc->core_clk, CLKFLAG_NORETAIN_PERIPH);
+	}
+
 	clk_set_rate(mdwc->core_clk, 19200000);
 	clk_disable_unprepare(mdwc->core_clk);
+	if (mdwc->noc_aggr_clk)
+		clk_disable_unprepare(mdwc->noc_aggr_clk);
 	/*
 	 * Disable iface_clk only after core_clk as core_clk has FSM
 	 * depedency on iface_clk. Hence iface_clk should be turned off
@@ -2035,14 +2053,22 @@
 	 * Turned ON iface_clk before core_clk due to FSM depedency.
 	 */
 	clk_prepare_enable(mdwc->iface_clk);
+	if (mdwc->noc_aggr_clk)
+		clk_prepare_enable(mdwc->noc_aggr_clk);
 	clk_set_rate(mdwc->core_clk, mdwc->core_clk_rate);
 	clk_prepare_enable(mdwc->core_clk);
+
+	/* set Memory core: ON, Memory periphery: ON */
+	clk_set_flags(mdwc->core_clk, CLKFLAG_RETAIN_MEM);
+	clk_set_flags(mdwc->core_clk, CLKFLAG_RETAIN_PERIPH);
+
 	clk_prepare_enable(mdwc->utmi_clk);
 	if (mdwc->bus_aggr_clk)
 		clk_prepare_enable(mdwc->bus_aggr_clk);
 
 	/* Resume SS PHY */
-	if (mdwc->lpm_flags & MDWC3_SS_PHY_SUSPEND) {
+	if (dwc->maximum_speed == USB_SPEED_SUPER &&
+			mdwc->lpm_flags & MDWC3_SS_PHY_SUSPEND) {
 		mdwc->ss_phy->flags &= ~(PHY_LANE_A | PHY_LANE_B);
 		if (mdwc->typec_orientation == ORIENTATION_CC1)
 			mdwc->ss_phy->flags |= PHY_LANE_A;
@@ -2376,6 +2402,10 @@
 	if (IS_ERR(mdwc->bus_aggr_clk))
 		mdwc->bus_aggr_clk = NULL;
 
+	mdwc->noc_aggr_clk = devm_clk_get(mdwc->dev, "noc_aggr_clk");
+	if (IS_ERR(mdwc->noc_aggr_clk))
+		mdwc->noc_aggr_clk = NULL;
+
 	if (of_property_match_string(mdwc->dev->of_node,
 				"clock-names", "cfg_ahb_clk") >= 0) {
 		mdwc->cfg_ahb_clk = devm_clk_get(mdwc->dev, "cfg_ahb_clk");
@@ -2397,9 +2427,11 @@
 	unsigned long event, void *ptr)
 {
 	struct dwc3_msm *mdwc = container_of(nb, struct dwc3_msm, id_nb);
+	struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3);
 	struct extcon_dev *edev = ptr;
 	enum dwc3_id_state id;
 	int cc_state;
+	int speed;
 
 	if (!edev) {
 		dev_err(mdwc->dev, "%s: edev null\n", __func__);
@@ -2417,6 +2449,11 @@
 		mdwc->typec_orientation =
 			cc_state ? ORIENTATION_CC2 : ORIENTATION_CC1;
 
+	dev_dbg(mdwc->dev, "cc_state:%d", mdwc->typec_orientation);
+
+	speed = extcon_get_cable_state_(edev, EXTCON_USB_SPEED);
+	dwc->maximum_speed = (speed == 0) ? USB_SPEED_HIGH : USB_SPEED_SUPER;
+
 	if (mdwc->id_state != id) {
 		mdwc->id_state = id;
 		queue_work(mdwc->dwc3_wq, &mdwc->resume_work);
@@ -2433,6 +2470,7 @@
 	struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3);
 	struct extcon_dev *edev = ptr;
 	int cc_state;
+	int speed;
 
 	if (!edev) {
 		dev_err(mdwc->dev, "%s: edev null\n", __func__);
@@ -2451,6 +2489,11 @@
 		mdwc->typec_orientation =
 			cc_state ? ORIENTATION_CC2 : ORIENTATION_CC1;
 
+	dev_dbg(mdwc->dev, "cc_state:%d", mdwc->typec_orientation);
+
+	speed = extcon_get_cable_state_(edev, EXTCON_USB_SPEED);
+	dwc->maximum_speed = (speed == 0) ? USB_SPEED_HIGH : USB_SPEED_SUPER;
+
 	mdwc->vbus_active = event;
 	if (dwc->is_drd && !mdwc->in_restart)
 		queue_work(mdwc->dwc3_wq, &mdwc->resume_work);
@@ -2908,6 +2951,8 @@
 	if (ret_pm < 0) {
 		dev_err(mdwc->dev,
 			"pm_runtime_get_sync failed with %d\n", ret_pm);
+		if (mdwc->noc_aggr_clk)
+			clk_prepare_enable(mdwc->noc_aggr_clk);
 		clk_prepare_enable(mdwc->utmi_clk);
 		clk_prepare_enable(mdwc->core_clk);
 		clk_prepare_enable(mdwc->iface_clk);
@@ -2993,9 +3038,11 @@
 	if (on) {
 		dev_dbg(mdwc->dev, "%s: turn on host\n", __func__);
 
-		pm_runtime_get_sync(mdwc->dev);
 		mdwc->hs_phy->flags |= PHY_HOST_MODE;
-		mdwc->ss_phy->flags |= PHY_HOST_MODE;
+		if (dwc->maximum_speed == USB_SPEED_SUPER)
+			mdwc->ss_phy->flags |= PHY_HOST_MODE;
+
+		pm_runtime_get_sync(mdwc->dev);
 		usb_phy_notify_connect(mdwc->hs_phy, USB_SPEED_HIGH);
 		if (!IS_ERR(mdwc->vbus_reg))
 			ret = regulator_enable(mdwc->vbus_reg);
@@ -3147,7 +3194,8 @@
 
 static int dwc3_msm_gadget_vbus_draw(struct dwc3_msm *mdwc, unsigned int mA)
 {
-	union power_supply_propval pval = {0,};
+	union power_supply_propval pval = {0};
+	int ret;
 
 	if (mdwc->charging_disabled)
 		return 0;
@@ -3163,44 +3211,23 @@
 		}
 	}
 
-	dev_info(mdwc->dev, "Avail curr from USB = %u\n", mA);
+	power_supply_get_property(mdwc->usb_psy, POWER_SUPPLY_PROP_TYPE, &pval);
+	if (pval.intval != POWER_SUPPLY_TYPE_USB)
+		return 0;
 
-	if (mdwc->max_power <= 2 && mA > 2) {
-		/* Enable Charging */
-		pval.intval = true;
-		if (power_supply_set_property(mdwc->usb_psy,
-					POWER_SUPPLY_PROP_ONLINE, &pval))
-			goto psy_error;
-		pval.intval = 1000 * mA;
-		if (power_supply_set_property(mdwc->usb_psy,
-					POWER_SUPPLY_PROP_CURRENT_MAX, &pval))
-			goto psy_error;
-	} else if (mdwc->max_power > 0 && (mA == 0 || mA == 2)) {
-		/* Disable charging */
-		pval.intval = false;
-		if (power_supply_set_property(mdwc->usb_psy,
-					POWER_SUPPLY_PROP_ONLINE, &pval))
-			goto psy_error;
-	} else {
-		/* Enable charging */
-		pval.intval = true;
-		if (power_supply_set_property(mdwc->usb_psy,
-					POWER_SUPPLY_PROP_ONLINE, &pval))
-			goto psy_error;
-	}
+	dev_info(mdwc->dev, "Avail curr from USB = %u\n", mA);
 
 	/* Set max current limit in uA */
 	pval.intval = 1000 * mA;
-	if (power_supply_set_property(mdwc->usb_psy,
-				POWER_SUPPLY_PROP_CURRENT_MAX, &pval))
-		goto psy_error;
+	ret = power_supply_set_property(mdwc->usb_psy,
+				POWER_SUPPLY_PROP_CURRENT_MAX, &pval);
+	if (ret) {
+		dev_dbg(mdwc->dev, "power supply error when setting property\n");
+		return ret;
+	}
 
 	mdwc->max_power = mA;
 	return 0;
-
-psy_error:
-	dev_dbg(mdwc->dev, "power supply error when setting property\n");
-	return -ENXIO;
 }
 
 
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index a9789cc..b8fc012 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -238,7 +238,7 @@
 		struct dwc3_gadget_ep_cmd_params *params)
 {
 	struct dwc3		*dwc = dep->dwc;
-	u32			timeout = 1500;
+	u32			timeout = 3000;
 	u32			reg;
 
 	int			cmd_status = 0;
@@ -320,6 +320,11 @@
 		dwc3_trace(trace_dwc3_gadget, "Command Timed Out");
 		dev_err(dwc->dev, "%s command timeout for %s\n",
 			dwc3_gadget_ep_cmd_string(cmd), dep->name);
+		if (!(cmd & DWC3_DEPCMD_ENDTRANSFER)) {
+			dwc->ep_cmd_timeout_cnt++;
+			dwc3_notify_event(dwc,
+				DWC3_CONTROLLER_RESTART_USB_SESSION);
+		}
 		cmd_status = -ETIMEDOUT;
 	}
 
@@ -386,7 +391,16 @@
 	if (dep->endpoint.ep_type == EP_TYPE_GSI)
 		return;
 
-	if (dep->trb_pool && dep->trb_pool_dma) {
+	/*
+	 * Clean up ep ring to avoid getting xferInProgress due to stale trbs
+	 * with HWO bit set from previous composition when update transfer cmd
+	 * is issued.
+	 */
+	if (dep->number > 1 && dep->trb_pool && dep->trb_pool_dma) {
+		memset(&dep->trb_pool[0], 0,
+			sizeof(struct dwc3_trb) * dep->num_trbs);
+		dev_dbg(dwc->dev, "Clr_TRB ring of %s\n", dep->name);
+
 		dma_free_coherent(dwc->dev,
 				sizeof(struct dwc3_trb) * DWC3_TRB_NUM,
 				dep->trb_pool, dep->trb_pool_dma);
@@ -671,15 +685,6 @@
 			(dep->number & 1) ? "in" : "out");
 	}
 
-	/*
-	 * Clean up ep ring of non-control endpoint to avoid getting
-	 * xferInProgress due to stale trbs with HWO bit set from previous
-	 * composition when update transfer cmd is issued.
-	 */
-	if (dep->number > 1 && dep->trb_pool)
-		memset(&dep->trb_pool[0], 0,
-			sizeof(struct dwc3_trb) * dep->num_trbs);
-
 	return 0;
 }
 
@@ -2078,17 +2083,10 @@
 	struct dwc3	*dwc = gadget_to_dwc(g);
 	unsigned long	flags;
 
-	pm_runtime_get_sync(dwc->dev);
-	tasklet_kill(&dwc->bh);
-
 	spin_lock_irqsave(&dwc->lock, flags);
-	__dwc3_gadget_stop(dwc);
 	dwc->gadget_driver = NULL;
 	spin_unlock_irqrestore(&dwc->lock, flags);
 
-	pm_runtime_mark_last_busy(dwc->dev);
-	pm_runtime_put_autosuspend(dwc->dev);
-
 	return 0;
 }
 
@@ -2752,7 +2750,7 @@
 	dwc3_notify_event(dwc, DWC3_CONTROLLER_NOTIFY_OTG_EVENT);
 
 	dwc3_usb3_phy_suspend(dwc, false);
-	usb_gadget_vbus_draw(&dwc->gadget, 0);
+	usb_gadget_vbus_draw(&dwc->gadget, 100);
 
 	dwc3_reset_gadget(dwc);
 
@@ -3276,15 +3274,6 @@
 	return ret;
 }
 
-static void dwc3_interrupt_bh(unsigned long param)
-{
-	struct dwc3 *dwc = (struct dwc3 *) param;
-
-	pm_runtime_get(dwc->dev);
-	dwc3_thread_interrupt(dwc->irq, dwc);
-	enable_irq(dwc->irq);
-}
-
 static irqreturn_t dwc3_thread_interrupt(int irq, void *_dwc)
 {
 	struct dwc3 *dwc = _dwc;
@@ -3306,7 +3295,6 @@
 	dwc->bh_completion_time[dwc->bh_dbg_index] = temp_time;
 	dwc->bh_dbg_index = (dwc->bh_dbg_index + 1) % 10;
 
-	pm_runtime_put(dwc->dev);
 	return ret;
 }
 
@@ -3366,10 +3354,8 @@
 	dwc->irq_event_count[dwc->irq_dbg_index] = temp_cnt / 4;
 	dwc->irq_dbg_index = (dwc->irq_dbg_index + 1) % MAX_INTR_STATS;
 
-	if (ret == IRQ_WAKE_THREAD) {
-		disable_irq_nosync(irq);
-		tasklet_schedule(&dwc->bh);
-	}
+	if (ret == IRQ_WAKE_THREAD)
+		dwc3_thread_interrupt(dwc->irq, dwc);
 
 	return IRQ_HANDLED;
 }
@@ -3449,9 +3435,6 @@
 		goto err4;
 	}
 
-	dwc->bh.func = dwc3_interrupt_bh;
-	dwc->bh.data = (unsigned long)dwc;
-
 	dwc->gadget.ops			= &dwc3_gadget_ops;
 	dwc->gadget.speed		= USB_SPEED_UNKNOWN;
 	dwc->gadget.sg_supported	= true;
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 1d369eb..a354f76 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -418,6 +418,114 @@
 }
 EXPORT_SYMBOL_GPL(usb_interface_id);
 
+/**
+ * usb_get_func_interface_id() - Find the interface ID of a function
+ * @function: the function for which want to find the interface ID
+ * Context: single threaded
+ *
+ * Returns the interface ID of the function or -ENODEV if this function
+ * is not part of this configuration
+ */
+int usb_get_func_interface_id(struct usb_function *func)
+{
+	int id;
+	struct usb_configuration *config;
+
+	if (!func)
+		return -EINVAL;
+
+	config = func->config;
+
+	for (id = 0; id < MAX_CONFIG_INTERFACES; id++) {
+		if (config->interface[id] == func)
+			return id;
+	}
+	return -ENODEV;
+}
+
+int usb_func_wakeup(struct usb_function *func)
+{
+	int ret;
+	unsigned int interface_id;
+	struct usb_gadget *gadget;
+
+	pr_debug("%s function wakeup\n",
+		func->name ? func->name : "");
+
+	if (!func || !func->config || !func->config->cdev ||
+		!func->config->cdev->gadget)
+		return -EINVAL;
+
+	gadget = func->config->cdev->gadget;
+	if ((gadget->speed != USB_SPEED_SUPER) || !func->func_wakeup_allowed) {
+		DBG(func->config->cdev,
+			"Function Wakeup is not possible. speed=%u, func_wakeup_allowed=%u\n",
+			gadget->speed,
+			func->func_wakeup_allowed);
+
+		return -ENOTSUPP;
+	}
+
+	ret = usb_get_func_interface_id(func);
+	if (ret < 0) {
+		ERROR(func->config->cdev,
+			"Function %s - Unknown interface id. Canceling USB request. ret=%d\n",
+			func->name ? func->name : "", ret);
+		return ret;
+	}
+
+	interface_id = ret;
+	ret = usb_gadget_func_wakeup(gadget, interface_id);
+	if (ret) {
+		if (ret == -EAGAIN) {
+			DBG(func->config->cdev,
+				"Function wakeup for %s could not be complete. Retry is needed.\n",
+				func->name ? func->name : "");
+		} else {
+			ERROR(func->config->cdev,
+				"Failed to wake function %s from suspend state. interface id: %d, ret=%d. Canceling USB request.\n",
+				func->name ? func->name : "",
+				interface_id, ret);
+		}
+		return ret;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(usb_func_wakeup);
+
+int usb_func_ep_queue(struct usb_function *func, struct usb_ep *ep,
+			       struct usb_request *req, gfp_t gfp_flags)
+{
+	int ret;
+	struct usb_gadget *gadget;
+
+	if (!func || !ep || !req) {
+		pr_err("Invalid argument. func=%p, ep=%p, req=%p\n",
+			func, ep, req);
+		return -EINVAL;
+	}
+
+	pr_debug("Function %s queueing new data into ep %u\n",
+		func->name ? func->name : "", ep->address);
+
+	gadget = func->config->cdev->gadget;
+	if ((gadget->speed == USB_SPEED_SUPER) && func->func_is_suspended) {
+		ret = usb_func_wakeup(func);
+		if (ret) {
+			if (ret != -EAGAIN)
+				pr_err("Failed to send function wake up notification. func name:%s, ep:%u\n",
+					func->name ? func->name : "",
+					ep->address);
+			return ret;
+		}
+	}
+
+	ret = usb_ep_queue(ep, req, gfp_flags);
+	return ret;
+}
+EXPORT_SYMBOL(usb_func_ep_queue);
+
 static u8 encode_bMaxPower(enum usb_device_speed speed,
 		struct usb_configuration *c)
 {
@@ -730,6 +838,10 @@
 		if (f->disable)
 			f->disable(f);
 
+		/* USB 3.0 addition */
+		f->func_is_suspended = false;
+		f->func_wakeup_allowed = false;
+
 		bitmap_zero(f->endpoints, 32);
 	}
 	cdev->config = NULL;
@@ -1780,8 +1892,13 @@
 			if (!f)
 				break;
 			value = 0;
-			if (f->func_suspend)
-				value = f->func_suspend(f, w_index >> 8);
+			if (f->func_suspend) {
+				const u8 suspend_opt = w_index >> 8;
+
+				value = f->func_suspend(f, suspend_opt);
+				DBG(cdev, "%s function: FUNCTION_SUSPEND(%u)",
+					f->name ? f->name : "", suspend_opt);
+			}
 			if (value < 0) {
 				ERROR(cdev,
 				      "func_suspend() returned error %d\n",
@@ -1997,6 +2114,10 @@
 		reset_config(cdev);
 	if (cdev->driver->disconnect)
 		cdev->driver->disconnect(cdev);
+	if (cdev->delayed_status != 0) {
+		INFO(cdev, "delayed status mismatch..resetting\n");
+		cdev->delayed_status = 0;
+	}
 	spin_unlock_irqrestore(&cdev->lock, flags);
 }
 
diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c
index 30fdab0..d942be9 100644
--- a/drivers/usb/gadget/epautoconf.c
+++ b/drivers/usb/gadget/epautoconf.c
@@ -209,3 +209,41 @@
 	gadget->out_epnum = 0;
 }
 EXPORT_SYMBOL_GPL(usb_ep_autoconfig_reset);
+
+/**
+ * usb_ep_autoconfig_by_name - Used to pick the endpoint by name. eg ep1in-gsi
+ * @gadget: The device to which the endpoint must belong.
+ * @desc: Endpoint descriptor, with endpoint direction and transfer mode
+ *	initialized.
+ * @ep_name: EP name that is to be searched.
+ *
+ */
+struct usb_ep *usb_ep_autoconfig_by_name(
+			struct usb_gadget		*gadget,
+			struct usb_endpoint_descriptor	*desc,
+			const char			*ep_name
+)
+{
+	struct usb_ep	*ep;
+	bool ep_found = false;
+
+	list_for_each_entry(ep, &gadget->ep_list, ep_list)
+		if (strcmp(ep->name, ep_name) == 0 && !ep->driver_data) {
+			ep_found = true;
+			break;
+		}
+
+	if (ep_found) {
+		desc->bEndpointAddress &= USB_DIR_IN;
+		desc->bEndpointAddress |= ep->ep_num;
+		ep->address = desc->bEndpointAddress;
+		pr_debug("Allocating ep address:%x\n", ep->address);
+		ep->desc = NULL;
+		ep->comp_desc = NULL;
+		return ep;
+	}
+
+	pr_err("%s:error finding ep %s\n", __func__, ep_name);
+	return NULL;
+}
+EXPORT_SYMBOL(usb_ep_autoconfig_by_name);
diff --git a/drivers/usb/gadget/function/f_rndis.c b/drivers/usb/gadget/function/f_rndis.c
index b899ced..41e1b47 100644
--- a/drivers/usb/gadget/function/f_rndis.c
+++ b/drivers/usb/gadget/function/f_rndis.c
@@ -1020,7 +1020,7 @@
 	rndis->port.func.disable = rndis_disable;
 	rndis->port.func.free_func = rndis_free;
 
-	params = rndis_register(rndis_response_available, rndis);
+	params = rndis_register(rndis_response_available, rndis, NULL);
 	if (IS_ERR(params)) {
 		kfree(rndis);
 		return ERR_CAST(params);
diff --git a/drivers/usb/gadget/function/rndis.c b/drivers/usb/gadget/function/rndis.c
index 418a2fd..ed93f9d 100644
--- a/drivers/usb/gadget/function/rndis.c
+++ b/drivers/usb/gadget/function/rndis.c
@@ -595,7 +595,7 @@
 		+ sizeof(struct ethhdr)
 		+ sizeof(struct rndis_packet_msg_type)
 		+ 22));
-	resp->PacketAlignmentFactor = cpu_to_le32(0);
+	resp->PacketAlignmentFactor = cpu_to_le32(params->pkt_alignment_factor);
 	resp->AFListOffset = cpu_to_le32(0);
 	resp->AFListSize = cpu_to_le32(0);
 
@@ -830,10 +830,16 @@
 	case RNDIS_MSG_HALT:
 		pr_debug("%s: RNDIS_MSG_HALT\n",
 			__func__);
-		params->state = RNDIS_UNINITIALIZED;
-		if (params->dev) {
-			netif_carrier_off(params->dev);
-			netif_stop_queue(params->dev);
+		if (params->state == RNDIS_DATA_INITIALIZED) {
+			if (params->flow_ctrl_enable) {
+				params->flow_ctrl_enable(true, params);
+			} else {
+				if (params->dev) {
+					netif_carrier_off(params->dev);
+					netif_stop_queue(params->dev);
+				}
+			}
+			params->state = RNDIS_UNINITIALIZED;
 		}
 		return 0;
 
@@ -885,7 +891,8 @@
 	ida_simple_remove(&rndis_ida, nr);
 }
 
-struct rndis_params *rndis_register(void (*resp_avail)(void *v), void *v)
+struct rndis_params *rndis_register(void (*resp_avail)(void *v), void *v,
+	void (*flow_ctrl_enable)(bool enable, struct rndis_params *params))
 {
 	struct rndis_params *params;
 	int i;
@@ -929,6 +936,7 @@
 	params->state = RNDIS_UNINITIALIZED;
 	params->media_state = RNDIS_MEDIA_STATE_DISCONNECTED;
 	params->resp_avail = resp_avail;
+	params->flow_ctrl_enable = flow_ctrl_enable;
 	params->v = v;
 	INIT_LIST_HEAD(&params->resp_queue);
 	pr_debug("%s: configNr = %d\n", __func__, i);
@@ -1014,6 +1022,49 @@
 	params->max_pkt_per_xfer = max_pkt_per_xfer;
 }
 
+/**
+ * rndis_flow_control: enable/disable flow control with USB RNDIS interface
+ * params - RNDIS network parameter
+ * enable_flow_control - true: perform flow control, false: disable flow control
+ *
+ * In hw accelerated mode, this function triggers functionality to start/stop
+ * endless transfers, otherwise it enables/disables RNDIS network interface.
+ */
+void rndis_flow_control(struct rndis_params *params, bool enable_flow_control)
+{
+	if (!params) {
+		pr_err("%s: failed, params NULL\n", __func__);
+		return;
+	}
+
+	pr_debug("%s(): params->state:%x\n", __func__, params->state);
+
+	if (enable_flow_control) {
+		if (params->state == RNDIS_DATA_INITIALIZED) {
+			if (params->flow_ctrl_enable) {
+				params->flow_ctrl_enable(enable_flow_control,
+								params);
+			} else {
+				netif_carrier_off(params->dev);
+				netif_stop_queue(params->dev);
+			}
+		}
+		params->state = RNDIS_INITIALIZED;
+	} else {
+		if (params->state != RNDIS_DATA_INITIALIZED) {
+			if (params->flow_ctrl_enable) {
+				params->flow_ctrl_enable(enable_flow_control,
+								params);
+			} else {
+				netif_carrier_on(params->dev);
+				if (netif_running(params->dev))
+					netif_wake_queue(params->dev);
+			}
+		}
+		params->state = RNDIS_DATA_INITIALIZED;
+	}
+}
+
 void rndis_add_hdr(struct sk_buff *skb)
 {
 	struct rndis_packet_msg_type *header;
@@ -1153,6 +1204,19 @@
 }
 EXPORT_SYMBOL_GPL(rndis_rm_hdr);
 
+void rndis_set_pkt_alignment_factor(struct rndis_params *params,
+		u8 pkt_alignment_factor)
+{
+	pr_debug("%s:\n", __func__);
+
+	if (!params) {
+		pr_err("%s: failed, params NULL\n", __func__);
+		return;
+	}
+
+	params->pkt_alignment_factor = pkt_alignment_factor;
+}
+
 #ifdef CONFIG_USB_GADGET_DEBUG_FILES
 
 static int rndis_proc_show(struct seq_file *m, void *v)
diff --git a/drivers/usb/gadget/function/rndis.h b/drivers/usb/gadget/function/rndis.h
index 310cac3..939c3be 100644
--- a/drivers/usb/gadget/function/rndis.h
+++ b/drivers/usb/gadget/function/rndis.h
@@ -192,14 +192,19 @@
 	u32			vendorID;
 	u8			max_pkt_per_xfer;
 	const char		*vendorDescr;
+	u8			pkt_alignment_factor;
 	void			(*resp_avail)(void *v);
+	void			(*flow_ctrl_enable)(bool enable,
+			struct rndis_params *params);
+
 	void			*v;
 	struct list_head	resp_queue;
 } rndis_params;
 
 /* RNDIS Message parser and other useless functions */
 int  rndis_msg_parser(struct rndis_params *params, u8 *buf);
-struct rndis_params *rndis_register(void (*resp_avail)(void *v), void *v);
+struct rndis_params *rndis_register(void (*resp_avail)(void *v), void *v,
+	void (*flow_ctrl_enable)(bool enable, struct rndis_params *params));
 void rndis_deregister(struct rndis_params *params);
 int  rndis_set_param_dev(struct rndis_params *params, struct net_device *dev,
 			 u16 *cdc_filter);
@@ -219,5 +224,8 @@
 int  rndis_signal_disconnect(struct rndis_params *params);
 int  rndis_state(struct rndis_params *params);
 extern void rndis_set_host_mac(struct rndis_params *params, const u8 *addr);
+void rndis_flow_control(struct rndis_params *params, bool enable_flow_control);
+void rndis_set_pkt_alignment_factor(struct rndis_params *params,
+		u8 pkt_alignment_factor);
 
 #endif  /* _LINUX_RNDIS_H */
diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h
index 93f0253..2f713f5 100644
--- a/include/linux/usb/composite.h
+++ b/include/linux/usb/composite.h
@@ -41,6 +41,10 @@
 #include <linux/log2.h>
 #include <linux/configfs.h>
 
+/* FUNCTION_SUSPEND: suspend options from usb 3.0 spec Table 9-7 */
+#define FUNC_SUSPEND_OPT_SUSP_MASK BIT(0)
+#define FUNC_SUSPEND_OPT_RW_EN_MASK BIT(1)
+
 /*
  * USB function drivers should return USB_GADGET_DELAYED_STATUS if they
  * wish to delay the data/status stages of the control transfer till they
@@ -158,7 +162,11 @@
  * @get_status: Returns function status as a reply to
  *	GetStatus() request when the recipient is Interface.
  * @func_suspend: callback to be called when
- *	SetFeature(FUNCTION_SUSPEND) is reseived
+ *	SetFeature(FUNCTION_SUSPEND) is received
+ * @func_is_suspended: Tells whether the function is currently in
+ *	Function Suspend state (used in Super Speed mode only).
+ * @func_wakeup_allowed: Tells whether Function Remote Wakeup has been allowed
+ *	by the USB host (used in Super Speed mode only).
  *
  * A single USB function uses one or more interfaces, and should in most
  * cases support operation at both full and high speeds.  Each function is
@@ -229,6 +237,8 @@
 	int			(*get_status)(struct usb_function *);
 	int			(*func_suspend)(struct usb_function *,
 						u8 suspend_opt);
+	unsigned		func_is_suspended:1;
+	unsigned		func_wakeup_allowed:1;
 	/* private: */
 	/* internals */
 	struct list_head		list;
@@ -244,6 +254,9 @@
 int usb_function_activate(struct usb_function *);
 
 int usb_interface_id(struct usb_configuration *, struct usb_function *);
+int usb_func_wakeup(struct usb_function *func);
+
+int usb_get_func_interface_id(struct usb_function *func);
 
 int config_ep_by_speed(struct usb_gadget *g, struct usb_function *f,
 			struct usb_ep *_ep);
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
index a625a7b..9cd86ff 100644
--- a/include/linux/usb/gadget.h
+++ b/include/linux/usb/gadget.h
@@ -24,6 +24,7 @@
 #include <linux/types.h>
 #include <linux/workqueue.h>
 #include <linux/usb/ch9.h>
+#include <linux/pm_runtime.h>
 
 #define UDC_TRACE_STR_MAX	512
 
@@ -297,6 +298,7 @@
  * @comp_desc: In case of SuperSpeed support, this is the endpoint companion
  *	descriptor that is used to configure the endpoint
  * @ep_type: Used to specify type of EP eg. normal vs h/w accelerated.
+ * @ep_num: Used EP number
  * @ep_intr_num: Interrupter number for EP.
  *
  * the bus controller driver lists all the general purpose endpoints in
@@ -322,6 +324,7 @@
 	const struct usb_endpoint_descriptor	*desc;
 	const struct usb_ss_ep_comp_descriptor	*comp_desc;
 	enum ep_type		ep_type;
+	u8			ep_num;
 	u8			ep_intr_num;
 };
 
@@ -402,6 +405,7 @@
 struct usb_gadget_ops {
 	int	(*get_frame)(struct usb_gadget *);
 	int	(*wakeup)(struct usb_gadget *);
+	int	(*func_wakeup)(struct usb_gadget *, int interface_id);
 	int	(*set_selfpowered) (struct usb_gadget *, int is_selfpowered);
 	int	(*vbus_session) (struct usb_gadget *, int is_active);
 	int	(*vbus_draw) (struct usb_gadget *, unsigned mA);
@@ -415,7 +419,6 @@
 	struct usb_ep *(*match_ep)(struct usb_gadget *,
 			struct usb_endpoint_descriptor *,
 			struct usb_ss_ep_comp_descriptor *);
-	int	(*func_wakeup)(struct usb_gadget *, int interface_id);
 	int	(*restart)(struct usb_gadget *);
 };
 
@@ -777,8 +780,6 @@
 	unsigned                match_existing_only:1;
 };
 
-
-
 /*-------------------------------------------------------------------------*/
 
 /* driver modules register and unregister, as usual.
@@ -899,6 +900,24 @@
 		struct usb_descriptor_header *otg_desc);
 /*-------------------------------------------------------------------------*/
 
+/**
+ * usb_func_ep_queue - queues (submits) an I/O request to a function endpoint.
+ * This function is similar to the usb_ep_queue function, but in addition it
+ * also checks whether the function is in Super Speed USB Function Suspend
+ * state, and if so a Function Wake notification is sent to the host
+ * (USB 3.0 spec, section 9.2.5.2).
+ * @func: the function which issues the USB I/O request.
+ * @ep:the endpoint associated with the request
+ * @req:the request being submitted
+ * @gfp_flags: GFP_* flags to use in case the lower level driver couldn't
+ *	pre-allocate all necessary memory with the request.
+ *
+ */
+int usb_func_ep_queue(struct usb_function *func, struct usb_ep *ep,
+				struct usb_request *req, gfp_t gfp_flags);
+
+/*-------------------------------------------------------------------------*/
+
 /* utility to simplify map/unmap of usb_requests to/from DMA */
 
 extern int usb_gadget_map_request_by_dev(struct device *dev,
@@ -951,6 +970,129 @@
 /* utility to update vbus status for udc core, it may be scheduled */
 extern void usb_udc_vbus_handler(struct usb_gadget *gadget, bool status);
 
+/**
+ * usb_gadget_autopm_get - increment PM-usage counter of usb gadget's parent
+ * device.
+ * @gadget: usb gadget whose parent device counter is incremented
+ *
+ * This routine should be called by function driver when it wants to use
+ * gadget's parent device and needs to guarantee that it is not suspended. In
+ * addition, the routine prevents subsequent autosuspends of gadget's parent
+ * device. However if the autoresume fails then the counter is re-decremented.
+ *
+ * This routine can run only in process context.
+ */
+static inline int usb_gadget_autopm_get(struct usb_gadget *gadget)
+{
+	int status = -ENODEV;
+
+	if (!gadget || !gadget->dev.parent)
+		return status;
+
+	status = pm_runtime_get_sync(gadget->dev.parent);
+	if (status < 0)
+		pm_runtime_put_sync(gadget->dev.parent);
+
+	if (status > 0)
+		status = 0;
+	return status;
+}
+
+/**
+ * usb_gadget_autopm_get_async - increment PM-usage counter of usb gadget's
+ * parent device.
+ * @gadget: usb gadget whose parent device counter is incremented
+ *
+ * This routine increments @gadget parent device PM usage counter and queue an
+ * autoresume request if the device is suspended. It does not autoresume device
+ * directly (it only queues a request). After a successful call, the device may
+ * not yet be resumed.
+ *
+ * This routine can run in atomic context.
+ */
+static inline int usb_gadget_autopm_get_async(struct usb_gadget *gadget)
+{
+	int status = -ENODEV;
+
+	if (!gadget || !gadget->dev.parent)
+		return status;
+
+	status = pm_runtime_get(gadget->dev.parent);
+	if (status < 0 && status != -EINPROGRESS)
+		pm_runtime_put_noidle(gadget->dev.parent);
+
+	if (status > 0 || status == -EINPROGRESS)
+		status = 0;
+	return status;
+}
+
+/**
+ * usb_gadget_autopm_get_noresume - increment PM-usage counter of usb gadget's
+ * parent device.
+ * @gadget: usb gadget whose parent device counter is incremented
+ *
+ * This routine increments PM-usage count of @gadget parent device but does not
+ * carry out an autoresume.
+ *
+ * This routine can run in atomic context.
+ */
+static inline void usb_gadget_autopm_get_noresume(struct usb_gadget *gadget)
+{
+	if (gadget && gadget->dev.parent)
+		pm_runtime_get_noresume(gadget->dev.parent);
+}
+
+/**
+ * usb_gadget_autopm_put - decrement PM-usage counter of usb gadget's parent
+ * device.
+ * @gadget: usb gadget whose parent device counter is decremented.
+ *
+ * This routine should be called by function driver when it is finished using
+ * @gadget parent device and wants to allow it to autosuspend. It decrements
+ * PM-usage counter of @gadget parent device, when the counter reaches 0, a
+ * delayed autosuspend request is attempted.
+ *
+ * This routine can run only in process context.
+ */
+static inline void usb_gadget_autopm_put(struct usb_gadget *gadget)
+{
+	if (gadget && gadget->dev.parent)
+		pm_runtime_put_sync(gadget->dev.parent);
+}
+
+/**
+ * usb_gadget_autopm_put_async - decrement PM-usage counter of usb gadget's
+ * parent device.
+ * @gadget: usb gadget whose parent device counter is decremented.
+ *
+ * This routine decrements PM-usage counter of @gadget parent device and
+ * schedules a delayed autosuspend request if the counter is <= 0.
+ *
+ * This routine can run in atomic context.
+ */
+static inline void usb_gadget_autopm_put_async(struct usb_gadget *gadget)
+{
+	if (gadget && gadget->dev.parent)
+		pm_runtime_put(gadget->dev.parent);
+}
+
+/**
+ * usb_gadget_autopm_put_no_suspend - decrement PM-usage counter of usb gadget
+'s
+ * parent device.
+ * @gadget: usb gadget whose parent device counter is decremented.
+ *
+ * This routine decrements PM-usage counter of @gadget parent device but does
+ * not carry out an autosuspend.
+ *
+ * This routine can run in atomic context.
+ */
+static inline void usb_gadget_autopm_put_no_suspend(struct usb_gadget *gadget)
+{
+	if (gadget && gadget->dev.parent)
+		pm_runtime_put_noidle(gadget->dev.parent);
+}
+
 /*-------------------------------------------------------------------------*/
 
 /* utility wrapping a simple endpoint selection policy */
@@ -966,6 +1108,9 @@
 extern void usb_ep_autoconfig_release(struct usb_ep *);
 
 extern void usb_ep_autoconfig_reset(struct usb_gadget *);
+extern struct usb_ep *usb_ep_autoconfig_by_name(struct usb_gadget *gadget,
+			struct usb_endpoint_descriptor *desc,
+			const char *ep_name);
 
 #ifdef CONFIG_USB_DWC3_MSM
 int msm_ep_config(struct usb_ep *ep);