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

Commit fc37b40a authored by Linux Build Service Account's avatar Linux Build Service Account 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"

parents cd5e4e0f dbca823c
Loading
Loading
Loading
Loading
+70 −117
Original line number Diff line number Diff line
@@ -58,7 +58,6 @@ struct usb_gsi_debugfs {

static struct usb_gsi_debugfs debugfs;

static void gsi_rndis_ipa_reset_trigger(void);
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);
@@ -66,6 +65,20 @@ static void gsi_free_trb_buffer(struct f_gsi *gsi);
static struct gsi_ctrl_pkt *gsi_ctrl_pkt_alloc(unsigned 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;
}

void post_event(struct gsi_data_port *port, u8 event)
{
	unsigned long flags;
@@ -884,16 +897,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_ep_disable(gsi->d_port.in_ep);
	}

	if (gsi->d_port.out_ep)
	if (gsi->d_port.out_ep) {
		gsi->out_ep_desc_backup = gsi->d_port.out_ep->desc;
		usb_ep_disable(gsi->d_port.out_ep);
	}

	gsi->d_port.net_ready_trigger = false;
}

@@ -930,18 +949,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);
				usb_gsi_remote_wakeup_allowed(f));

	if (!ret) {
		d_port->sm_state = STATE_SUSPENDED;
@@ -960,10 +982,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;
}

@@ -998,7 +1018,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);

@@ -1060,6 +1079,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;
@@ -1121,15 +1161,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();
				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);
@@ -1743,27 +1775,6 @@ static void gsi_rndis_open(struct f_gsi *rndis)
	rndis_signal_connect(rndis->config);
}

static void gsi_rndis_ipa_reset_trigger(void)
{
	struct f_gsi *rndis = gsi_prot_ctx[IPA_USB_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 f_gsi *rndis = gsi_prot_ctx[IPA_USB_RNDIS];
@@ -2573,7 +2584,6 @@ static void gsi_suspend(struct usb_function *f)
{
	bool block_db;
	struct f_gsi *gsi = func_to_gsi(f);
	bool remote_wakeup_allowed;

	if (!gsi->data_interface_up) {
		log_event_dbg("%s: Data interface not up\n", __func__);
@@ -2586,49 +2596,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->config, 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__);
@@ -2646,49 +2624,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->config, 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__);
}