USB: wusb: add wusb_phy_rate sysfs file to host controllers
Add the wusb_phy_rate sysfs file to Wireless USB host controllers. This
sets the maximum PHY rate that will be used for all connected devices.
Signed-off-by: David Vrabel <david.vrabel@csr.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
diff --git a/drivers/usb/host/whci/qset.c b/drivers/usb/host/whci/qset.c
index 0828086..39e855a 100644
--- a/drivers/usb/host/whci/qset.c
+++ b/drivers/usb/host/whci/qset.c
@@ -49,11 +49,13 @@
* state
* @urb: an urb for a transfer to this endpoint
*/
-static void qset_fill_qh(struct whc_qset *qset, struct urb *urb)
+static void qset_fill_qh(struct whc *whc, struct whc_qset *qset, struct urb *urb)
{
struct usb_device *usb_dev = urb->dev;
+ struct wusb_dev *wusb_dev = usb_dev->wusb_dev;
struct usb_wireless_ep_comp_descriptor *epcd;
bool is_out;
+ uint8_t phy_rate;
is_out = usb_pipeout(urb->pipe);
@@ -68,6 +70,22 @@
qset->max_burst = 1;
}
+ /*
+ * Initial PHY rate is 53.3 Mbit/s for control endpoints or
+ * the maximum supported by the device for other endpoints
+ * (unless limited by the user).
+ */
+ if (usb_pipecontrol(urb->pipe))
+ phy_rate = UWB_PHY_RATE_53;
+ else {
+ uint16_t phy_rates;
+
+ phy_rates = le16_to_cpu(wusb_dev->wusb_cap_descr->wPHYRates);
+ phy_rate = fls(phy_rates) - 1;
+ if (phy_rate > whc->wusbhc.phy_rate)
+ phy_rate = whc->wusbhc.phy_rate;
+ }
+
qset->qh.info1 = cpu_to_le32(
QH_INFO1_EP(usb_pipeendpoint(urb->pipe))
| (is_out ? QH_INFO1_DIR_OUT : QH_INFO1_DIR_IN)
@@ -87,7 +105,7 @@
* strength and can presumably guess the Tx power required
* from that? */
qset->qh.info3 = cpu_to_le32(
- QH_INFO3_TX_RATE_53_3
+ QH_INFO3_TX_RATE(phy_rate)
| QH_INFO3_TX_PWR(0) /* 0 == max power */
);
@@ -149,7 +167,7 @@
qset->ep = urb->ep;
urb->ep->hcpriv = qset;
- qset_fill_qh(qset, urb);
+ qset_fill_qh(whc, qset, urb);
}
return qset;
}
diff --git a/drivers/usb/host/whci/whci-hc.h b/drivers/usb/host/whci/whci-hc.h
index d5e5c3a..4d4cbc0 100644
--- a/drivers/usb/host/whci/whci-hc.h
+++ b/drivers/usb/host/whci/whci-hc.h
@@ -172,14 +172,7 @@
#define QH_INFO3_MAX_DELAY(d) ((d) << 0) /* maximum stream delay in 125 us units (isoc only) */
#define QH_INFO3_INTERVAL(i) ((i) << 16) /* segment interval in 125 us units (isoc only) */
-#define QH_INFO3_TX_RATE_53_3 (0 << 24)
-#define QH_INFO3_TX_RATE_80 (1 << 24)
-#define QH_INFO3_TX_RATE_106_7 (2 << 24)
-#define QH_INFO3_TX_RATE_160 (3 << 24)
-#define QH_INFO3_TX_RATE_200 (4 << 24)
-#define QH_INFO3_TX_RATE_320 (5 << 24)
-#define QH_INFO3_TX_RATE_400 (6 << 24)
-#define QH_INFO3_TX_RATE_480 (7 << 24)
+#define QH_INFO3_TX_RATE(r) ((r) << 24) /* PHY rate (see [ECMA-368] section 10.3.1.1) */
#define QH_INFO3_TX_PWR(p) ((p) << 29) /* transmit power (see [WUSB] section 5.2.1.2) */
#define QH_STATUS_FLOW_CTRL (1 << 15)
diff --git a/drivers/usb/wusbcore/wusbhc.c b/drivers/usb/wusbcore/wusbhc.c
index ee6256f..eab86e4 100644
--- a/drivers/usb/wusbcore/wusbhc.c
+++ b/drivers/usb/wusbcore/wusbhc.c
@@ -147,10 +147,40 @@
}
static DEVICE_ATTR(wusb_chid, 0644, wusb_chid_show, wusb_chid_store);
+
+static ssize_t wusb_phy_rate_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev);
+
+ return sprintf(buf, "%d\n", wusbhc->phy_rate);
+}
+
+static ssize_t wusb_phy_rate_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev);
+ uint8_t phy_rate;
+ ssize_t result;
+
+ result = sscanf(buf, "%hhu", &phy_rate);
+ if (result != 1)
+ return -EINVAL;
+ if (phy_rate >= UWB_PHY_RATE_INVALID)
+ return -EINVAL;
+
+ wusbhc->phy_rate = phy_rate;
+ return size;
+}
+static DEVICE_ATTR(wusb_phy_rate, 0644, wusb_phy_rate_show, wusb_phy_rate_store);
+
/* Group all the WUSBHC attributes */
static struct attribute *wusbhc_attrs[] = {
&dev_attr_wusb_trust_timeout.attr,
&dev_attr_wusb_chid.attr,
+ &dev_attr_wusb_phy_rate.attr,
NULL,
};
@@ -177,6 +207,8 @@
int result = 0;
wusbhc->trust_timeout = WUSB_TRUST_TIMEOUT_MS;
+ wusbhc->phy_rate = UWB_PHY_RATE_INVALID - 1;
+
mutex_init(&wusbhc->mutex);
result = wusbhc_mmcie_create(wusbhc);
if (result < 0)
diff --git a/drivers/usb/wusbcore/wusbhc.h b/drivers/usb/wusbcore/wusbhc.h
index 797c245..fd2fd4e 100644
--- a/drivers/usb/wusbcore/wusbhc.h
+++ b/drivers/usb/wusbcore/wusbhc.h
@@ -253,6 +253,7 @@
unsigned trust_timeout; /* in jiffies */
struct wusb_ckhdid chid;
+ uint8_t phy_rate;
struct wuie_host_info *wuie_host_info;
struct mutex mutex; /* locks everything else */