mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-11-25 04:40:53 +07:00
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: David Vrabel <david.vrabel@csr.com>
This commit is contained in:
parent
d409f3bf47
commit
4d2bea4ca0
@ -171,11 +171,6 @@ static int hwahc_op_start(struct usb_hcd *usb_hcd)
|
|||||||
if (result < 0)
|
if (result < 0)
|
||||||
goto error_set_cluster_id;
|
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->uses_new_polling = 1;
|
||||||
usb_hcd->poll_rh = 1;
|
usb_hcd->poll_rh = 1;
|
||||||
usb_hcd->state = HC_STATE_RUNNING;
|
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);
|
d_fnend(4, dev, "(hwahc %p) = %d\n", hwahc, result);
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
error_stop:
|
|
||||||
__wa_stop(&hwahc->wa);
|
|
||||||
error_set_cluster_id:
|
error_set_cluster_id:
|
||||||
wusb_cluster_id_put(wusbhc->cluster_id);
|
wusb_cluster_id_put(wusbhc->cluster_id);
|
||||||
error_cluster_id_get:
|
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)
|
static int hwahc_op_suspend(struct usb_hcd *usb_hcd, pm_message_t msg)
|
||||||
{
|
{
|
||||||
struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
|
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;
|
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
|
* No need to abort pipes, as when this is called, all the children
|
||||||
* has been disconnected and that has done it [through
|
* 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);
|
d_fnstart(4, dev, "(hwahc %p)\n", hwahc);
|
||||||
mutex_lock(&wusbhc->mutex);
|
mutex_lock(&wusbhc->mutex);
|
||||||
wusbhc_stop(wusbhc);
|
wusbhc_stop(wusbhc);
|
||||||
wa_nep_disarm(&hwahc->wa);
|
|
||||||
result = __wa_stop(&hwahc->wa);
|
|
||||||
wusb_cluster_id_put(wusbhc->cluster_id);
|
wusb_cluster_id_put(wusbhc->cluster_id);
|
||||||
mutex_unlock(&wusbhc->mutex);
|
mutex_unlock(&wusbhc->mutex);
|
||||||
d_fnend(4, dev, "(hwahc %p) = %d\n", hwahc, result);
|
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);
|
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
|
* Set the UWB MAS allocation for the WUSB cluster
|
||||||
*
|
*
|
||||||
|
@ -136,7 +136,7 @@ int whc_do_gencmd(struct whc *whc, u32 cmd, u32 params, void *addr, size_t len);
|
|||||||
|
|
||||||
/* wusb.c */
|
/* wusb.c */
|
||||||
int whc_wusbhc_start(struct wusbhc *wusbhc);
|
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,
|
int whc_mmcie_add(struct wusbhc *wusbhc, u8 interval, u8 repeat_cnt,
|
||||||
u8 handle, struct wuie_hdr *wuie);
|
u8 handle, struct wuie_hdr *wuie);
|
||||||
int whc_mmcie_rm(struct wusbhc *wusbhc, u8 handle);
|
int whc_mmcie_rm(struct wusbhc *wusbhc, u8 handle);
|
||||||
|
@ -410,6 +410,8 @@ struct dn_buf_entry {
|
|||||||
# define WUSBDNTSCTRL_SLOTS(s) ((s) << 0)
|
# define WUSBDNTSCTRL_SLOTS(s) ((s) << 0)
|
||||||
|
|
||||||
#define WUSBTIME 0x68
|
#define WUSBTIME 0x68
|
||||||
|
# define WUSBTIME_CHANNEL_TIME_MASK 0x00ffffff
|
||||||
|
|
||||||
#define WUSBBPST 0x6c
|
#define WUSBBPST 0x6c
|
||||||
#define WUSBDIBUPDATED 0x70
|
#define WUSBDIBUPDATED 0x70
|
||||||
|
|
||||||
|
@ -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
|
* WHCI starts MMCs based on there being a valid GTK so these need
|
||||||
* these need only start/stop the asynchronous and periodic schedules.
|
* only start/stop the asynchronous and periodic schedules and send a
|
||||||
|
* channel stop command.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int whc_wusbhc_start(struct wusbhc *wusbhc)
|
int whc_wusbhc_start(struct wusbhc *wusbhc)
|
||||||
@ -78,12 +79,20 @@ int whc_wusbhc_start(struct wusbhc *wusbhc)
|
|||||||
return 0;
|
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);
|
struct whc *whc = wusbhc_to_whc(wusbhc);
|
||||||
|
u32 stop_time, now_time;
|
||||||
|
int ret;
|
||||||
|
|
||||||
pzl_stop(whc);
|
pzl_stop(whc);
|
||||||
asl_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,
|
int whc_mmcie_add(struct wusbhc *wusbhc, u8 interval, u8 repeat_cnt,
|
||||||
|
@ -250,18 +250,14 @@ static int __wusbhc_host_disconnect_ie(struct wusbhc *wusbhc)
|
|||||||
* wusbhc_stop - stop transmitting MMCs
|
* wusbhc_stop - stop transmitting MMCs
|
||||||
* @wusbhc: the HC to stop
|
* @wusbhc: the HC to stop
|
||||||
*
|
*
|
||||||
* Send a Host Disconnect IE, wait, remove all the MMCs (stop sending MMCs).
|
* Stops the WUSB channel and removes the cluster reservation.
|
||||||
*
|
|
||||||
* If we can't allocate a Host Stop IE, screw it, we don't notify the
|
|
||||||
* devices we are disconnecting...
|
|
||||||
*/
|
*/
|
||||||
void wusbhc_stop(struct wusbhc *wusbhc)
|
void wusbhc_stop(struct wusbhc *wusbhc)
|
||||||
{
|
{
|
||||||
if (wusbhc->active) {
|
if (wusbhc->active) {
|
||||||
wusbhc->active = 0;
|
wusbhc->active = 0;
|
||||||
wusbhc->stop(wusbhc);
|
wusbhc->stop(wusbhc, WUSB_CHANNEL_STOP_DELAY_MS);
|
||||||
wusbhc_sec_stop(wusbhc);
|
wusbhc_sec_stop(wusbhc);
|
||||||
__wusbhc_host_disconnect_ie(wusbhc);
|
|
||||||
wusbhc_devconnect_stop(wusbhc);
|
wusbhc_devconnect_stop(wusbhc);
|
||||||
wusbhc_rsv_terminate(wusbhc);
|
wusbhc_rsv_terminate(wusbhc);
|
||||||
}
|
}
|
||||||
|
@ -64,6 +64,13 @@
|
|||||||
#include <linux/uwb.h>
|
#include <linux/uwb.h>
|
||||||
#include <linux/usb/wusb.h>
|
#include <linux/usb/wusb.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Time from a WUSB channel stop request to the last transmitted MMC.
|
||||||
|
*
|
||||||
|
* This needs to be > 4.096 ms in case no MMCs can be transmitted in
|
||||||
|
* zone 0.
|
||||||
|
*/
|
||||||
|
#define WUSB_CHANNEL_STOP_DELAY_MS 8
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wireless USB device
|
* Wireless USB device
|
||||||
@ -198,21 +205,18 @@ struct wusb_port {
|
|||||||
* @mmcies_max Max number of Information Elements this HC can send
|
* @mmcies_max Max number of Information Elements this HC can send
|
||||||
* in its MMC. Read-only.
|
* in its MMC. Read-only.
|
||||||
*
|
*
|
||||||
|
* @start Start the WUSB channel.
|
||||||
|
*
|
||||||
|
* @stop Stop the WUSB channel after the specified number of
|
||||||
|
* milliseconds. Channel Stop IEs should be transmitted
|
||||||
|
* as required by [WUSB] 4.16.2.1.
|
||||||
|
*
|
||||||
* @mmcie_add HC specific operation (WHCI or HWA) for adding an
|
* @mmcie_add HC specific operation (WHCI or HWA) for adding an
|
||||||
* MMCIE.
|
* MMCIE.
|
||||||
*
|
*
|
||||||
* @mmcie_rm HC specific operation (WHCI or HWA) for removing an
|
* @mmcie_rm HC specific operation (WHCI or HWA) for removing an
|
||||||
* MMCIE.
|
* MMCIE.
|
||||||
*
|
*
|
||||||
* @enc_types Array which describes the encryptions methods
|
|
||||||
* supported by the host as described in WUSB1.0 --
|
|
||||||
* one entry per supported method. As of WUSB1.0 there
|
|
||||||
* is only four methods, we make space for eight just in
|
|
||||||
* case they decide to add some more (and pray they do
|
|
||||||
* it in sequential order). if 'enc_types[enc_method]
|
|
||||||
* != 0', then it is supported by the host. enc_method
|
|
||||||
* is USB_ENC_TYPE*.
|
|
||||||
*
|
|
||||||
* @set_ptk: Set the PTK and enable encryption for a device. Or, if
|
* @set_ptk: Set the PTK and enable encryption for a device. Or, if
|
||||||
* the supplied key is NULL, disable encryption for that
|
* the supplied key is NULL, disable encryption for that
|
||||||
* device.
|
* device.
|
||||||
@ -269,7 +273,7 @@ struct wusbhc {
|
|||||||
u8 mmcies_max;
|
u8 mmcies_max;
|
||||||
/* FIXME: make wusbhc_ops? */
|
/* FIXME: make wusbhc_ops? */
|
||||||
int (*start)(struct wusbhc *wusbhc);
|
int (*start)(struct wusbhc *wusbhc);
|
||||||
void (*stop)(struct wusbhc *wusbhc);
|
void (*stop)(struct wusbhc *wusbhc, int delay);
|
||||||
int (*mmcie_add)(struct wusbhc *wusbhc, u8 interval, u8 repeat_cnt,
|
int (*mmcie_add)(struct wusbhc *wusbhc, u8 interval, u8 repeat_cnt,
|
||||||
u8 handle, struct wuie_hdr *wuie);
|
u8 handle, struct wuie_hdr *wuie);
|
||||||
int (*mmcie_rm)(struct wusbhc *wusbhc, u8 handle);
|
int (*mmcie_rm)(struct wusbhc *wusbhc, u8 handle);
|
||||||
|
@ -51,6 +51,7 @@ enum {
|
|||||||
WUSB_REQ_GET_TIME = 25,
|
WUSB_REQ_GET_TIME = 25,
|
||||||
WUSB_REQ_SET_STREAM_IDX = 26,
|
WUSB_REQ_SET_STREAM_IDX = 26,
|
||||||
WUSB_REQ_SET_WUSB_MAS = 27,
|
WUSB_REQ_SET_WUSB_MAS = 27,
|
||||||
|
WUSB_REQ_CHAN_STOP = 28,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user