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

Commit 4d2bea4c authored by David Vrabel's avatar David Vrabel
Browse files

wusb: do a proper channel stop



When stopping the WUSB channel the host should send Channel Stop IEs giving
the WUSB Channel Time of the last MMC.  Both WHCI and HWA hosts provide a
channel stop command for this.

Signed-off-by: default avatarDavid Vrabel <david.vrabel@csr.com>
parent d409f3bf
Loading
Loading
Loading
Loading
+48 −54
Original line number Diff line number Diff line
@@ -171,11 +171,6 @@ static int hwahc_op_start(struct usb_hcd *usb_hcd)
	if (result < 0)
		goto error_set_cluster_id;

	result = wa_nep_arm(&hwahc->wa, GFP_KERNEL);
	if (result < 0) {
		dev_err(dev, "cannot listen to notifications: %d\n", result);
		goto error_stop;
	}
	usb_hcd->uses_new_polling = 1;
	usb_hcd->poll_rh = 1;
	usb_hcd->state = HC_STATE_RUNNING;
@@ -185,8 +180,6 @@ static int hwahc_op_start(struct usb_hcd *usb_hcd)
	d_fnend(4, dev, "(hwahc %p) = %d\n", hwahc, result);
	return result;

error_stop:
	__wa_stop(&hwahc->wa);
error_set_cluster_id:
	wusb_cluster_id_put(wusbhc->cluster_id);
error_cluster_id_get:
@@ -194,39 +187,6 @@ static int hwahc_op_start(struct usb_hcd *usb_hcd)

}

/*
 * FIXME: break this function up
 */
static int __hwahc_op_wusbhc_start(struct wusbhc *wusbhc)
{
	int result;
	struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
	struct device *dev = &hwahc->wa.usb_iface->dev;

	/* Set up a Host Info WUSB Information Element */
	d_fnstart(4, dev, "(hwahc %p)\n", hwahc);
	result = -ENOSPC;

	result = __wa_set_feature(&hwahc->wa, WA_ENABLE);
	if (result < 0) {
		dev_err(dev, "error commanding HC to start: %d\n", result);
		goto error_stop;
	}
	result = __wa_wait_status(&hwahc->wa, WA_ENABLE, WA_ENABLE);
	if (result < 0) {
		dev_err(dev, "error waiting for HC to start: %d\n", result);
		goto error_stop;
	}
	result = 0;
out:
	d_fnend(4, dev, "(hwahc %p) = %d\n", hwahc, result);
	return result;

error_stop:
	result = __wa_clear_feature(&hwahc->wa, WA_ENABLE);
	goto out;
}

static int hwahc_op_suspend(struct usb_hcd *usb_hcd, pm_message_t msg)
{
	struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
@@ -246,18 +206,6 @@ static int hwahc_op_resume(struct usb_hcd *usb_hcd)
	return -ENOSYS;
}

static void __hwahc_op_wusbhc_stop(struct wusbhc *wusbhc)
{
	int result;
	struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
	struct device *dev = &hwahc->wa.usb_iface->dev;

	d_fnstart(4, dev, "(hwahc %p)\n", hwahc);
	/* Nothing for now */
	d_fnend(4, dev, "(hwahc %p) = %d\n", hwahc, result);
	return;
}

/*
 * No need to abort pipes, as when this is called, all the children
 * has been disconnected and that has done it [through
@@ -275,8 +223,6 @@ static void hwahc_op_stop(struct usb_hcd *usb_hcd)
	d_fnstart(4, dev, "(hwahc %p)\n", hwahc);
	mutex_lock(&wusbhc->mutex);
	wusbhc_stop(wusbhc);
	wa_nep_disarm(&hwahc->wa);
	result = __wa_stop(&hwahc->wa);
	wusb_cluster_id_put(wusbhc->cluster_id);
	mutex_unlock(&wusbhc->mutex);
	d_fnend(4, dev, "(hwahc %p) = %d\n", hwahc, result);
@@ -325,6 +271,54 @@ static void hwahc_op_endpoint_disable(struct usb_hcd *usb_hcd,
	rpipe_ep_disable(&hwahc->wa, ep);
}

static int __hwahc_op_wusbhc_start(struct wusbhc *wusbhc)
{
	int result;
	struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
	struct device *dev = &hwahc->wa.usb_iface->dev;

	result = __wa_set_feature(&hwahc->wa, WA_ENABLE);
	if (result < 0) {
		dev_err(dev, "error commanding HC to start: %d\n", result);
		goto error_stop;
	}
	result = __wa_wait_status(&hwahc->wa, WA_ENABLE, WA_ENABLE);
	if (result < 0) {
		dev_err(dev, "error waiting for HC to start: %d\n", result);
		goto error_stop;
	}
	result = wa_nep_arm(&hwahc->wa, GFP_KERNEL);
	if (result < 0) {
		dev_err(dev, "cannot listen to notifications: %d\n", result);
		goto error_stop;
	}
	return result;

error_stop:
	__wa_clear_feature(&hwahc->wa, WA_ENABLE);
	return result;
}

static void __hwahc_op_wusbhc_stop(struct wusbhc *wusbhc, int delay)
{
	struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
	struct wahc *wa = &hwahc->wa;
	u8 iface_no = wa->usb_iface->cur_altsetting->desc.bInterfaceNumber;
	int ret;

	ret = usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
			      WUSB_REQ_CHAN_STOP,
			      USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
			      delay * 1000,
			      iface_no,
			      NULL, 0, 1000 /* FIXME: arbitrary */);
	if (ret == 0)
		msleep(delay);

	wa_nep_disarm(&hwahc->wa);
	__wa_stop(&hwahc->wa);
}

/*
 * Set the UWB MAS allocation for the WUSB cluster
 *
+1 −1
Original line number Diff line number Diff line
@@ -136,7 +136,7 @@ int whc_do_gencmd(struct whc *whc, u32 cmd, u32 params, void *addr, size_t len);

/* wusb.c */
int whc_wusbhc_start(struct wusbhc *wusbhc);
void whc_wusbhc_stop(struct wusbhc *wusbhc);
void whc_wusbhc_stop(struct wusbhc *wusbhc, int delay);
int whc_mmcie_add(struct wusbhc *wusbhc, u8 interval, u8 repeat_cnt,
		  u8 handle, struct wuie_hdr *wuie);
int whc_mmcie_rm(struct wusbhc *wusbhc, u8 handle);
+2 −0
Original line number Diff line number Diff line
@@ -410,6 +410,8 @@ struct dn_buf_entry {
#  define WUSBDNTSCTRL_SLOTS(s)    ((s) << 0)

#define WUSBTIME             0x68
#  define WUSBTIME_CHANNEL_TIME_MASK 0x00ffffff

#define WUSBBPST             0x6c
#define WUSBDIBUPDATED       0x70

+12 −3
Original line number Diff line number Diff line
@@ -64,8 +64,9 @@ static int whc_update_di(struct whc *whc, int idx)
}

/*
 * WHCI starts and stops MMCs based on there being a valid GTK so
 * these need only start/stop the asynchronous and periodic schedules.
 * WHCI starts MMCs based on there being a valid GTK so these need
 * only start/stop the asynchronous and periodic schedules and send a
 * channel stop command.
 */

int whc_wusbhc_start(struct wusbhc *wusbhc)
@@ -78,12 +79,20 @@ int whc_wusbhc_start(struct wusbhc *wusbhc)
	return 0;
}

void whc_wusbhc_stop(struct wusbhc *wusbhc)
void whc_wusbhc_stop(struct wusbhc *wusbhc, int delay)
{
	struct whc *whc = wusbhc_to_whc(wusbhc);
	u32 stop_time, now_time;
	int ret;

	pzl_stop(whc);
	asl_stop(whc);

	now_time = le_readl(whc->base + WUSBTIME) & WUSBTIME_CHANNEL_TIME_MASK;
	stop_time = (now_time + ((delay * 8) << 7)) & 0x00ffffff;
	ret = whc_do_gencmd(whc, WUSBGENCMDSTS_CHAN_STOP, stop_time, NULL, 0);
	if (ret == 0)
		msleep(delay);
}

int whc_mmcie_add(struct wusbhc *wusbhc, u8 interval, u8 repeat_cnt,
+2 −6
Original line number Diff line number Diff line
@@ -250,18 +250,14 @@ static int __wusbhc_host_disconnect_ie(struct wusbhc *wusbhc)
 * wusbhc_stop - stop transmitting MMCs
 * @wusbhc: the HC to stop
 *
 * Send a Host Disconnect IE, wait, remove all the MMCs (stop sending MMCs).
 *
 * If we can't allocate a Host Stop IE, screw it, we don't notify the
 * devices we are disconnecting...
 * Stops the WUSB channel and removes the cluster reservation.
 */
void wusbhc_stop(struct wusbhc *wusbhc)
{
	if (wusbhc->active) {
		wusbhc->active = 0;
		wusbhc->stop(wusbhc);
		wusbhc->stop(wusbhc, WUSB_CHANNEL_STOP_DELAY_MS);
		wusbhc_sec_stop(wusbhc);
		__wusbhc_host_disconnect_ie(wusbhc);
		wusbhc_devconnect_stop(wusbhc);
		wusbhc_rsv_terminate(wusbhc);
	}
Loading