Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6b8d7402 authored by Kyle Yan's avatar Kyle Yan Committed by Gerrit - the friendly Code Review server
Browse files

Merge "f_gsi: Don't send end xfer command when USB is into U3 state" into msm-4.8

parents 0fd07948 ccdfd448
Loading
Loading
Loading
Loading
+71 −116
Original line number Diff line number Diff line
@@ -43,7 +43,6 @@ MODULE_PARM_DESC(qti_packet_debug, "Print QTI Packet's Raw Data");

static struct workqueue_struct *ipa_usb_wq;

static void gsi_rndis_ipa_reset_trigger(struct f_gsi *rndis);
static void ipa_disconnect_handler(struct gsi_data_port *d_port);
static int gsi_ctrl_send_notification(struct f_gsi *gsi);
static int gsi_alloc_trb_buffer(struct f_gsi *gsi);
@@ -51,6 +50,20 @@ static void gsi_free_trb_buffer(struct f_gsi *gsi);
static struct gsi_ctrl_pkt *gsi_ctrl_pkt_alloc(unsigned int len, gfp_t flags);
static void gsi_ctrl_pkt_free(struct gsi_ctrl_pkt *pkt);

static inline bool usb_gsi_remote_wakeup_allowed(struct usb_function *f)
{
	bool remote_wakeup_allowed;

	if (f->config->cdev->gadget->speed == USB_SPEED_SUPER)
		remote_wakeup_allowed = f->func_wakeup_allowed;
	else
		remote_wakeup_allowed = f->config->cdev->gadget->remote_wakeup;

	log_event_dbg("%s: remote_wakeup_allowed:%s", __func__,
			remote_wakeup_allowed ? "true" : "false");
	return remote_wakeup_allowed;
}

static void post_event(struct gsi_data_port *port, u8 event)
{
	unsigned long flags;
@@ -478,16 +491,22 @@ static void ipa_disconnect_handler(struct gsi_data_port *d_port)

	log_event_dbg("%s: EP Disable for data", __func__);

	/* Block doorbell to GSI to avoid USB wrapper from
	 * ringing doorbell in case IPA clocks are OFF
	if (gsi->d_port.in_ep) {
		/*
		 * Block doorbell to GSI to avoid USB wrapper from
		 * ringing doorbell in case IPA clocks are OFF.
		 */
		usb_gsi_ep_op(d_port->in_ep, (void *)&block_db,
				GSI_EP_OP_SET_CLR_BLOCK_DBL);

		gsi->in_ep_desc_backup = gsi->d_port.in_ep->desc;
		usb_gsi_ep_op(gsi->d_port.in_ep, NULL, GSI_EP_OP_DISABLE);
	}

	if (gsi->d_port.out_ep)
	if (gsi->d_port.out_ep) {
		gsi->out_ep_desc_backup = gsi->d_port.out_ep->desc;
		usb_gsi_ep_op(gsi->d_port.out_ep, NULL, GSI_EP_OP_DISABLE);
	}

	gsi->d_port.net_ready_trigger = false;
}

@@ -524,17 +543,21 @@ static int ipa_suspend_work_handler(struct gsi_data_port *d_port)
	int ret = 0;
	bool block_db, f_suspend;
	struct f_gsi *gsi = d_port_to_gsi(d_port);
	struct usb_function *f = &gsi->function;

	f_suspend = f->func_wakeup_allowed;
	log_event_dbg("%s: f_suspend:%d", __func__, f_suspend);

	f_suspend = gsi->function.func_wakeup_allowed;
	if (!usb_gsi_ep_op(gsi->d_port.in_ep, (void *) &f_suspend,
				GSI_EP_OP_CHECK_FOR_SUSPEND)) {
		ret = -EFAULT;
		goto done;
	}
	log_event_dbg("%s: Calling xdci_suspend", __func__);

	log_event_dbg("%s: Calling xdci_suspend", __func__);
	ret = ipa_usb_xdci_suspend(gsi->d_port.out_channel_handle,
			gsi->d_port.in_channel_handle, gsi->prot_id, true);
				gsi->d_port.in_channel_handle, gsi->prot_id,
				usb_gsi_remote_wakeup_allowed(f));
	if (!ret) {
		d_port->sm_state = STATE_SUSPENDED;
		log_event_dbg("%s: STATE SUSPENDED", __func__);
@@ -552,10 +575,8 @@ static int ipa_suspend_work_handler(struct gsi_data_port *d_port)
		log_event_err("%s: Error %d for %d", __func__, ret,
							gsi->prot_id);
	}

	log_event_dbg("%s: xdci_suspend ret %d", __func__, ret);

done:
	log_event_dbg("%s: xdci_suspend ret %d", __func__, ret);
	return ret;
}

@@ -590,7 +611,6 @@ static void ipa_work_handler(struct work_struct *w)
	struct device *dev;
	struct device *gad_dev;
	struct f_gsi *gsi;
	bool block_db;

	event = read_event(d_port);

@@ -652,6 +672,27 @@ static void ipa_work_handler(struct work_struct *w)
								__func__);
				break;
			}

			if (d_port->out_ep && !d_port->out_ep->desc &&
					gsi->out_ep_desc_backup) {
				d_port->out_ep->desc = gsi->out_ep_desc_backup;
				d_port->out_ep->ep_intr_num = 1;
			}

			if (d_port->in_ep && !d_port->in_ep->desc &&
					gsi->in_ep_desc_backup) {
				d_port->in_ep->desc = gsi->in_ep_desc_backup;
				d_port->in_ep->ep_intr_num = 2;
			}

			if (d_port->out_ep)
				usb_gsi_ep_op(d_port->out_ep,
					&d_port->out_request, GSI_EP_OP_CONFIG);

			if (d_port->in_ep)
				usb_gsi_ep_op(d_port->in_ep,
					&d_port->in_request, GSI_EP_OP_CONFIG);

			ipa_connect_channels(d_port);
			ipa_data_path_enable(d_port);
			d_port->sm_state = STATE_CONNECTED;
@@ -713,15 +754,7 @@ static void ipa_work_handler(struct work_struct *w)
			if (event == EVT_HOST_NRDY) {
				log_event_dbg("%s: ST_CON_HOST_NRDY\n",
								__func__);
				block_db = true;
				/* stop USB ringing doorbell to GSI(OUT_EP) */
				usb_gsi_ep_op(d_port->in_ep, (void *)&block_db,
						GSI_EP_OP_SET_CLR_BLOCK_DBL);
				gsi_rndis_ipa_reset_trigger(gsi);
				usb_gsi_ep_op(d_port->in_ep, NULL,
						GSI_EP_OP_ENDXFER);
				usb_gsi_ep_op(d_port->out_ep, NULL,
						GSI_EP_OP_ENDXFER);
				ipa_disconnect_handler(d_port);
			}

			ipa_disconnect_work_handler(d_port);
@@ -1344,26 +1377,6 @@ static void gsi_rndis_open(struct f_gsi *rndis)
	rndis_signal_connect(rndis->params);
}

static void gsi_rndis_ipa_reset_trigger(struct f_gsi *rndis)
{
	unsigned long flags;

	if (!rndis) {
		log_event_err("%s: gsi prot ctx is %p", __func__, rndis);
		return;
	}

	spin_lock_irqsave(&rndis->d_port.lock, flags);
	if (!rndis) {
		log_event_err("%s: No RNDIS instance", __func__);
		spin_unlock_irqrestore(&rndis->d_port.lock, flags);
		return;
	}

	rndis->d_port.net_ready_trigger = false;
	spin_unlock_irqrestore(&rndis->d_port.lock, flags);
}

void gsi_rndis_flow_ctrl_enable(bool enable, struct rndis_params *param)
{
	struct f_gsi *rndis = param->v;
@@ -2115,7 +2128,6 @@ static void gsi_suspend(struct usb_function *f)
{
	bool block_db;
	struct f_gsi *gsi = func_to_gsi(f);
	bool remote_wakeup_allowed;

	/* Check if function is already suspended in gsi_func_suspend() */
	if (f->func_is_suspended) {
@@ -2123,49 +2135,17 @@ static void gsi_suspend(struct usb_function *f)
		return;
	}

	if (f->config->cdev->gadget->speed == USB_SPEED_SUPER)
		remote_wakeup_allowed = f->func_wakeup_allowed;
	else
		remote_wakeup_allowed = f->config->cdev->gadget->remote_wakeup;

	log_event_info("%s: remote_wakeup_allowed %d",
					__func__, remote_wakeup_allowed);

	if (!remote_wakeup_allowed) {
		if (gsi->prot_id == IPA_USB_RNDIS)
			rndis_flow_control(gsi->params, true);
		/*
		 * When remote wakeup is disabled, IPA is disconnected
		 * because it cannot send new data until the USB bus is
		 * resumed. Endpoint descriptors info is saved before it
		 * gets reset by the BAM disconnect API. This lets us
		 * restore this info when the USB bus is resumed.
		 */
		if (gsi->d_port.in_ep)
			gsi->in_ep_desc_backup = gsi->d_port.in_ep->desc;
		if (gsi->d_port.out_ep)
			gsi->out_ep_desc_backup = gsi->d_port.out_ep->desc;

		ipa_disconnect_handler(&gsi->d_port);

		post_event(&gsi->d_port, EVT_DISCONNECTED);
		queue_work(gsi->d_port.ipa_usb_wq, &gsi->d_port.usb_ipa_w);
		log_event_dbg("%s: Disconnecting", __func__);
	} else {
	block_db = true;
	usb_gsi_ep_op(gsi->d_port.in_ep, (void *)&block_db,
			GSI_EP_OP_SET_CLR_BLOCK_DBL);
	post_event(&gsi->d_port, EVT_SUSPEND);
	queue_work(gsi->d_port.ipa_usb_wq, &gsi->d_port.usb_ipa_w);
	}

	log_event_dbg("gsi suspended");
}

static void gsi_resume(struct usb_function *f)
{
	struct f_gsi *gsi = func_to_gsi(f);
	bool remote_wakeup_allowed;
	struct usb_composite_dev *cdev = f->config->cdev;

	log_event_dbg("%s", __func__);
@@ -2178,49 +2158,24 @@ static void gsi_resume(struct usb_function *f)
		f->func_is_suspended)
		return;

	if (f->config->cdev->gadget->speed == USB_SPEED_SUPER)
		remote_wakeup_allowed = f->func_wakeup_allowed;
	else
		remote_wakeup_allowed = f->config->cdev->gadget->remote_wakeup;

	if (gsi->c_port.notify && !gsi->c_port.notify->desc)
		config_ep_by_speed(cdev->gadget, f, gsi->c_port.notify);

	/* Check any pending cpkt, and queue immediately on resume */
	gsi_ctrl_send_notification(gsi);

	if (!remote_wakeup_allowed) {

		/* Configure EPs for GSI */
		if (gsi->d_port.out_ep) {
			gsi->d_port.out_ep->desc = gsi->out_ep_desc_backup;
			gsi->d_port.out_ep->ep_intr_num = 1;
			usb_gsi_ep_op(gsi->d_port.out_ep,
				&gsi->d_port.out_request, GSI_EP_OP_CONFIG);
		}
		gsi->d_port.in_ep->desc = gsi->in_ep_desc_backup;
		if (gsi->prot_id != IPA_USB_DIAG)
			gsi->d_port.in_ep->ep_intr_num = 2;
		else
			gsi->d_port.in_ep->ep_intr_num = 3;

		usb_gsi_ep_op(gsi->d_port.in_ep, &gsi->d_port.in_request,
				GSI_EP_OP_CONFIG);
		post_event(&gsi->d_port, EVT_CONNECT_IN_PROGRESS);

	/*
	 * Linux host does not send RNDIS_MSG_INIT or non-zero
	 * RNDIS_MESSAGE_PACKET_FILTER after performing bus resume.
	 * Trigger state machine explicitly on resume.
	 */
		if (gsi->prot_id == IPA_USB_RNDIS)
	if (gsi->prot_id == IPA_USB_RNDIS &&
			!usb_gsi_remote_wakeup_allowed(f))
		rndis_flow_control(gsi->params, false);
	} else
		post_event(&gsi->d_port, EVT_RESUMED);

	post_event(&gsi->d_port, EVT_RESUMED);
	queue_work(gsi->d_port.ipa_usb_wq, &gsi->d_port.usb_ipa_w);


	log_event_dbg("%s: completed", __func__);
}