aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPratyush Anand <pratyush.anand@st.com>2014-07-14 09:57:49 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-07-17 20:11:09 -0400
commitce21bfe603b3401c258c415456c915634998e133 (patch)
treefae2454865d773104faedf9b9f964fc966979963
parentcaa67a5ec8926188adcbece0df2ae60ceff534ae (diff)
USB: Add LVS Test device driver
OTG3 and EH Compliance Plan 1.0 talks about Super Speed OTG Verification system (SS-OVS) which consists of an excersizer and analyzer. USB Compliance Suite from Lecroy or Ellisys can act as such SS-OVS for Link Layer Validation (LVS). Some modifications are needed for an embedded Linux USB host to pass all these tests. Most of these tests require just Link to be in U0. They do not work with default Linux USB stack since, default stack does port reset and then starts sending setup packet, which is not expected by Link Layer Validation (LVS) device of Lecroy Compliance Suit. Then, There are many Link Layer Tests which need host to generate specific traffic. This patch supports specific traffic generation cases. As of now all the host Lecroy Link Layer-USBIF tests (except TD7.26) passes with this patch for single run using Lecroy USB Compliance Suite Version 1.98 Build 239 and Lecroy USB Protocol Analyzer version 4.80 Build 1603. Therefore patch seems to be a good candidate for inclusion. Further modification can be done on top of it. lvstest driver will not bind to any device by default. It can bind manually to a super speed USB host controller root hub. Therefore, regular hub driver must be unbound before this driver is bound. For example, if 2-0:1.0 is the xhci root hub, then execute following to unbind hub driver. echo 2-0:1.0 > /sys/bus/usb/drivers/hub/unbind Then write Linux Foundation's vendor ID which is used by root hubs and SS root hub's device ID into new_id file. Writing IDs into new_id file will also bind the lvs driver with any available SS root hub interfaces. echo "1D6B 3" > /sys/bus/usb/drivers/lvs/new_id Now connect LVS device with root hub port. Test case specific traffic can be generated as follows whenever needed: 1. To issue "Get Device descriptor" command for TD.7.06: echo > /sys/bus/usb/devices/2-0\:1.0/get_dev_desc 2. To set U1 timeout to 127 for TD.7.18 echo 127 > /sys/bus/usb/devices/2-0\:1.0/u1_timeout 3. To set U2 timeout to 0 for TD.7.18 echo 0 > /sys/bus/usb/devices/2-0\:1.0/u2_timeout 4. To issue "Hot Reset" for TD.7.29 echo > /sys/bus/usb/devices/2-0\:1.0/hot_reset 5. To issue "U3 Entry" for TD.7.35 echo > /sys/bus/usb/devices/2-0\:1.0/u3_entry 6. To issue "U3 Exit" for TD.7.36 echo > /sys/bus/usb/devices/2-0\:1.0/u3_exit Signed-off-by: Pratyush Anand <pratyush.anand@st.com> Acked-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--Documentation/ABI/testing/sysfs-bus-usb-lvstest47
-rw-r--r--drivers/usb/misc/Kconfig7
-rw-r--r--drivers/usb/misc/Makefile1
-rw-r--r--drivers/usb/misc/lvstest.c460
4 files changed, 515 insertions, 0 deletions
diff --git a/Documentation/ABI/testing/sysfs-bus-usb-lvstest b/Documentation/ABI/testing/sysfs-bus-usb-lvstest
new file mode 100644
index 000000000000..aae68fc2d842
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-bus-usb-lvstest
@@ -0,0 +1,47 @@
1Link Layer Validation Device is a standard device for testing of Super
2Speed Link Layer tests. These nodes are available in sysfs only when lvs
3driver is bound with root hub device.
4
5What: /sys/bus/usb/devices/.../get_dev_desc
6Date: March 2014
7Contact: Pratyush Anand <pratyush.anand@st.com>
8Description:
9 Write to this node to issue "Get Device Descriptor"
10 for Link Layer Validation device. It is needed for TD.7.06.
11
12What: /sys/bus/usb/devices/.../u1_timeout
13Date: March 2014
14Contact: Pratyush Anand <pratyush.anand@st.com>
15Description:
16 Set "U1 timeout" for the downstream port where Link Layer
17 Validation device is connected. Timeout value must be between 0
18 and 127. It is needed for TD.7.18, TD.7.19, TD.7.20 and TD.7.21.
19
20What: /sys/bus/usb/devices/.../u2_timeout
21Date: March 2014
22Contact: Pratyush Anand <pratyush.anand@st.com>
23Description:
24 Set "U2 timeout" for the downstream port where Link Layer
25 Validation device is connected. Timeout value must be between 0
26 and 127. It is needed for TD.7.18, TD.7.19, TD.7.20 and TD.7.21.
27
28What: /sys/bus/usb/devices/.../hot_reset
29Date: March 2014
30Contact: Pratyush Anand <pratyush.anand@st.com>
31Description:
32 Write to this node to issue "Reset" for Link Layer Validation
33 device. It is needed for TD.7.29, TD.7.31, TD.7.34 and TD.7.35.
34
35What: /sys/bus/usb/devices/.../u3_entry
36Date: March 2014
37Contact: Pratyush Anand <pratyush.anand@st.com>
38Description:
39 Write to this node to issue "U3 entry" for Link Layer
40 Validation device. It is needed for TD.7.35 and TD.7.36.
41
42What: /sys/bus/usb/devices/.../u3_exit
43Date: March 2014
44Contact: Pratyush Anand <pratyush.anand@st.com>
45Description:
46 Write to this node to issue "U3 exit" for Link Layer
47 Validation device. It is needed for TD.7.36.
diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig
index 1bca274dc3b5..76d77206e011 100644
--- a/drivers/usb/misc/Kconfig
+++ b/drivers/usb/misc/Kconfig
@@ -248,3 +248,10 @@ config USB_HSIC_USB3503
248 select REGMAP_I2C 248 select REGMAP_I2C
249 help 249 help
250 This option enables support for SMSC USB3503 HSIC to USB 2.0 Driver. 250 This option enables support for SMSC USB3503 HSIC to USB 2.0 Driver.
251
252config USB_LINK_LAYER_TEST
253 tristate "USB Link Layer Test driver"
254 help
255 This driver is for generating specific traffic for Super Speed Link
256 Layer Test Device. Say Y only when you want to conduct USB Super Speed
257 Link Layer Test for host controllers.
diff --git a/drivers/usb/misc/Makefile b/drivers/usb/misc/Makefile
index e748fd5dbe94..65b0402c1ca1 100644
--- a/drivers/usb/misc/Makefile
+++ b/drivers/usb/misc/Makefile
@@ -27,3 +27,4 @@ obj-$(CONFIG_USB_YUREX) += yurex.o
27obj-$(CONFIG_USB_HSIC_USB3503) += usb3503.o 27obj-$(CONFIG_USB_HSIC_USB3503) += usb3503.o
28 28
29obj-$(CONFIG_USB_SISUSBVGA) += sisusbvga/ 29obj-$(CONFIG_USB_SISUSBVGA) += sisusbvga/
30obj-$(CONFIG_USB_LINK_LAYER_TEST) += lvstest.o
diff --git a/drivers/usb/misc/lvstest.c b/drivers/usb/misc/lvstest.c
new file mode 100644
index 000000000000..02df9a72b990
--- /dev/null
+++ b/drivers/usb/misc/lvstest.c
@@ -0,0 +1,460 @@
1/*
2 * drivers/usb/misc/lvstest.c
3 *
4 * Test pattern generation for Link Layer Validation System Tests
5 *
6 * Copyright (C) 2014 ST Microelectronics
7 * Pratyush Anand <pratyush.anand@st.com>
8 *
9 * This file is licensed under the terms of the GNU General Public
10 * License version 2. This program is licensed "as is" without any
11 * warranty of any kind, whether express or implied.
12 */
13
14#include <linux/init.h>
15#include <linux/kernel.h>
16#include <linux/module.h>
17#include <linux/platform_device.h>
18#include <linux/slab.h>
19#include <linux/usb.h>
20#include <linux/usb/ch11.h>
21#include <linux/usb/hcd.h>
22#include <linux/usb/phy.h>
23
24struct lvs_rh {
25 /* root hub interface */
26 struct usb_interface *intf;
27 /* if lvs device connected */
28 bool present;
29 /* port no at which lvs device is present */
30 int portnum;
31 /* urb buffer */
32 u8 buffer[8];
33 /* class descriptor */
34 struct usb_hub_descriptor descriptor;
35 /* urb for polling interrupt pipe */
36 struct urb *urb;
37 /* LVS RH work queue */
38 struct workqueue_struct *rh_queue;
39 /* LVH RH work */
40 struct work_struct rh_work;
41 /* RH port status */
42 struct usb_port_status port_status;
43};
44
45static struct usb_device *create_lvs_device(struct usb_interface *intf)
46{
47 struct usb_device *udev, *hdev;
48 struct usb_hcd *hcd;
49 struct lvs_rh *lvs = usb_get_intfdata(intf);
50
51 if (!lvs->present) {
52 dev_err(&intf->dev, "No LVS device is present\n");
53 return NULL;
54 }
55
56 hdev = interface_to_usbdev(intf);
57 hcd = bus_to_hcd(hdev->bus);
58
59 udev = usb_alloc_dev(hdev, hdev->bus, lvs->portnum);
60 if (!udev) {
61 dev_err(&intf->dev, "Could not allocate lvs udev\n");
62 return NULL;
63 }
64 udev->speed = USB_SPEED_SUPER;
65 udev->ep0.desc.wMaxPacketSize = cpu_to_le16(512);
66 usb_set_device_state(udev, USB_STATE_DEFAULT);
67
68 if (hcd->driver->enable_device) {
69 if (hcd->driver->enable_device(hcd, udev) < 0) {
70 dev_err(&intf->dev, "Failed to enable\n");
71 usb_put_dev(udev);
72 return NULL;
73 }
74 }
75
76 return udev;
77}
78
79static void destroy_lvs_device(struct usb_device *udev)
80{
81 struct usb_device *hdev = udev->parent;
82 struct usb_hcd *hcd = bus_to_hcd(hdev->bus);
83
84 if (hcd->driver->free_dev)
85 hcd->driver->free_dev(hcd, udev);
86
87 usb_put_dev(udev);
88}
89
90static int lvs_rh_clear_port_feature(struct usb_device *hdev,
91 int port1, int feature)
92{
93 return usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
94 USB_REQ_CLEAR_FEATURE, USB_RT_PORT, feature, port1,
95 NULL, 0, 1000);
96}
97
98static int lvs_rh_set_port_feature(struct usb_device *hdev,
99 int port1, int feature)
100{
101 return usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
102 USB_REQ_SET_FEATURE, USB_RT_PORT, feature, port1,
103 NULL, 0, 1000);
104}
105
106static ssize_t u3_entry_store(struct device *dev,
107 struct device_attribute *attr, const char *buf, size_t count)
108{
109 struct usb_interface *intf = to_usb_interface(dev);
110 struct usb_device *hdev = interface_to_usbdev(intf);
111 struct lvs_rh *lvs = usb_get_intfdata(intf);
112 struct usb_device *udev;
113 int ret;
114
115 udev = create_lvs_device(intf);
116 if (!udev) {
117 dev_err(dev, "failed to create lvs device\n");
118 return -ENOMEM;
119 }
120
121 ret = lvs_rh_set_port_feature(hdev, lvs->portnum,
122 USB_PORT_FEAT_SUSPEND);
123 if (ret < 0)
124 dev_err(dev, "can't issue U3 entry %d\n", ret);
125
126 destroy_lvs_device(udev);
127
128 if (ret < 0)
129 return ret;
130
131 return count;
132}
133static DEVICE_ATTR_WO(u3_entry);
134
135static ssize_t u3_exit_store(struct device *dev,
136 struct device_attribute *attr, const char *buf, size_t count)
137{
138 struct usb_interface *intf = to_usb_interface(dev);
139 struct usb_device *hdev = interface_to_usbdev(intf);
140 struct lvs_rh *lvs = usb_get_intfdata(intf);
141 struct usb_device *udev;
142 int ret;
143
144 udev = create_lvs_device(intf);
145 if (!udev) {
146 dev_err(dev, "failed to create lvs device\n");
147 return -ENOMEM;
148 }
149
150 ret = lvs_rh_clear_port_feature(hdev, lvs->portnum,
151 USB_PORT_FEAT_SUSPEND);
152 if (ret < 0)
153 dev_err(dev, "can't issue U3 exit %d\n", ret);
154
155 destroy_lvs_device(udev);
156
157 if (ret < 0)
158 return ret;
159
160 return count;
161}
162static DEVICE_ATTR_WO(u3_exit);
163
164static ssize_t hot_reset_store(struct device *dev,
165 struct device_attribute *attr, const char *buf, size_t count)
166{
167 struct usb_interface *intf = to_usb_interface(dev);
168 struct usb_device *hdev = interface_to_usbdev(intf);
169 struct lvs_rh *lvs = usb_get_intfdata(intf);
170 int ret;
171
172 ret = lvs_rh_set_port_feature(hdev, lvs->portnum,
173 USB_PORT_FEAT_RESET);
174 if (ret < 0) {
175 dev_err(dev, "can't issue hot reset %d\n", ret);
176 return ret;
177 }
178
179 return count;
180}
181static DEVICE_ATTR_WO(hot_reset);
182
183static ssize_t u2_timeout_store(struct device *dev,
184 struct device_attribute *attr, const char *buf, size_t count)
185{
186 struct usb_interface *intf = to_usb_interface(dev);
187 struct usb_device *hdev = interface_to_usbdev(intf);
188 struct lvs_rh *lvs = usb_get_intfdata(intf);
189 unsigned long val;
190 int ret;
191
192 ret = kstrtoul(buf, 10, &val);
193 if (ret < 0) {
194 dev_err(dev, "couldn't parse string %d\n", ret);
195 return ret;
196 }
197
198 if (val < 0 || val > 127)
199 return -EINVAL;
200
201 ret = lvs_rh_set_port_feature(hdev, lvs->portnum | (val << 8),
202 USB_PORT_FEAT_U2_TIMEOUT);
203 if (ret < 0) {
204 dev_err(dev, "Error %d while setting U2 timeout %ld\n", ret, val);
205 return ret;
206 }
207
208 return count;
209}
210static DEVICE_ATTR_WO(u2_timeout);
211
212static ssize_t u1_timeout_store(struct device *dev,
213 struct device_attribute *attr, const char *buf, size_t count)
214{
215 struct usb_interface *intf = to_usb_interface(dev);
216 struct usb_device *hdev = interface_to_usbdev(intf);
217 struct lvs_rh *lvs = usb_get_intfdata(intf);
218 unsigned long val;
219 int ret;
220
221 ret = kstrtoul(buf, 10, &val);
222 if (ret < 0) {
223 dev_err(dev, "couldn't parse string %d\n", ret);
224 return ret;
225 }
226
227 if (val < 0 || val > 127)
228 return -EINVAL;
229
230 ret = lvs_rh_set_port_feature(hdev, lvs->portnum | (val << 8),
231 USB_PORT_FEAT_U1_TIMEOUT);
232 if (ret < 0) {
233 dev_err(dev, "Error %d while setting U1 timeout %ld\n", ret, val);
234 return ret;
235 }
236
237 return count;
238}
239static DEVICE_ATTR_WO(u1_timeout);
240
241static ssize_t get_dev_desc_store(struct device *dev,
242 struct device_attribute *attr, const char *buf, size_t count)
243{
244 struct usb_interface *intf = to_usb_interface(dev);
245 struct usb_device *udev;
246 struct usb_device_descriptor *descriptor;
247 int ret;
248
249 descriptor = kmalloc(sizeof(*descriptor), GFP_KERNEL);
250 if (!descriptor) {
251 dev_err(dev, "failed to allocate descriptor memory\n");
252 return -ENOMEM;
253 }
254
255 udev = create_lvs_device(intf);
256 if (!udev) {
257 dev_err(dev, "failed to create lvs device\n");
258 ret = -ENOMEM;
259 goto free_desc;
260 }
261
262 ret = usb_control_msg(udev, (PIPE_CONTROL << 30) | USB_DIR_IN,
263 USB_REQ_GET_DESCRIPTOR, USB_DIR_IN, USB_DT_DEVICE << 8,
264 0, descriptor, sizeof(*descriptor),
265 USB_CTRL_GET_TIMEOUT);
266 if (ret < 0)
267 dev_err(dev, "can't read device descriptor %d\n", ret);
268
269 destroy_lvs_device(udev);
270
271free_desc:
272 kfree(descriptor);
273
274 if (ret < 0)
275 return ret;
276
277 return count;
278}
279static DEVICE_ATTR_WO(get_dev_desc);
280
281static struct attribute *lvs_attributes[] = {
282 &dev_attr_get_dev_desc.attr,
283 &dev_attr_u1_timeout.attr,
284 &dev_attr_u2_timeout.attr,
285 &dev_attr_hot_reset.attr,
286 &dev_attr_u3_entry.attr,
287 &dev_attr_u3_exit.attr,
288 NULL
289};
290
291static const struct attribute_group lvs_attr_group = {
292 .attrs = lvs_attributes,
293};
294
295static void lvs_rh_work(struct work_struct *work)
296{
297 struct lvs_rh *lvs = container_of(work, struct lvs_rh, rh_work);
298 struct usb_interface *intf = lvs->intf;
299 struct usb_device *hdev = interface_to_usbdev(intf);
300 struct usb_hcd *hcd = bus_to_hcd(hdev->bus);
301 struct usb_hub_descriptor *descriptor = &lvs->descriptor;
302 struct usb_port_status *port_status = &lvs->port_status;
303 int i, ret = 0;
304 u16 portchange;
305
306 /* Examine each root port */
307 for (i = 1; i <= descriptor->bNbrPorts; i++) {
308 ret = usb_control_msg(hdev, usb_rcvctrlpipe(hdev, 0),
309 USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_PORT, 0, i,
310 port_status, sizeof(*port_status), 1000);
311 if (ret < 4)
312 continue;
313
314 portchange = port_status->wPortChange;
315
316 if (portchange & USB_PORT_STAT_C_LINK_STATE)
317 lvs_rh_clear_port_feature(hdev, i,
318 USB_PORT_FEAT_C_PORT_LINK_STATE);
319 if (portchange & USB_PORT_STAT_C_ENABLE)
320 lvs_rh_clear_port_feature(hdev, i,
321 USB_PORT_FEAT_C_ENABLE);
322 if (portchange & USB_PORT_STAT_C_RESET)
323 lvs_rh_clear_port_feature(hdev, i,
324 USB_PORT_FEAT_C_RESET);
325 if (portchange & USB_PORT_STAT_C_BH_RESET)
326 lvs_rh_clear_port_feature(hdev, i,
327 USB_PORT_FEAT_C_BH_PORT_RESET);
328 if (portchange & USB_PORT_STAT_C_CONNECTION) {
329 lvs_rh_clear_port_feature(hdev, i,
330 USB_PORT_FEAT_C_CONNECTION);
331
332 if (port_status->wPortStatus &
333 USB_PORT_STAT_CONNECTION) {
334 lvs->present = true;
335 lvs->portnum = i;
336 if (hcd->phy)
337 usb_phy_notify_connect(hcd->phy,
338 USB_SPEED_SUPER);
339 } else {
340 lvs->present = false;
341 if (hcd->phy)
342 usb_phy_notify_disconnect(hcd->phy,
343 USB_SPEED_SUPER);
344 }
345 break;
346 }
347 }
348
349 ret = usb_submit_urb(lvs->urb, GFP_KERNEL);
350 if (ret != 0 && ret != -ENODEV && ret != -EPERM)
351 dev_err(&intf->dev, "urb resubmit error %d\n", ret);
352}
353
354static void lvs_rh_irq(struct urb *urb)
355{
356 struct lvs_rh *lvs = urb->context;
357
358 queue_work(lvs->rh_queue, &lvs->rh_work);
359}
360
361static int lvs_rh_probe(struct usb_interface *intf,
362 const struct usb_device_id *id)
363{
364 struct usb_device *hdev;
365 struct usb_host_interface *desc;
366 struct usb_endpoint_descriptor *endpoint;
367 struct lvs_rh *lvs;
368 unsigned int pipe;
369 int ret, maxp;
370
371 hdev = interface_to_usbdev(intf);
372 desc = intf->cur_altsetting;
373 endpoint = &desc->endpoint[0].desc;
374
375 /* valid only for SS root hub */
376 if (hdev->descriptor.bDeviceProtocol != USB_HUB_PR_SS || hdev->parent) {
377 dev_err(&intf->dev, "Bind LVS driver with SS root Hub only\n");
378 return -EINVAL;
379 }
380
381 lvs = devm_kzalloc(&intf->dev, sizeof(*lvs), GFP_KERNEL);
382 if (!lvs)
383 return -ENOMEM;
384
385 lvs->intf = intf;
386 usb_set_intfdata(intf, lvs);
387
388 /* how many number of ports this root hub has */
389 ret = usb_control_msg(hdev, usb_rcvctrlpipe(hdev, 0),
390 USB_REQ_GET_DESCRIPTOR, USB_DIR_IN | USB_RT_HUB,
391 USB_DT_SS_HUB << 8, 0, &lvs->descriptor,
392 USB_DT_SS_HUB_SIZE, USB_CTRL_GET_TIMEOUT);
393 if (ret < (USB_DT_HUB_NONVAR_SIZE + 2)) {
394 dev_err(&hdev->dev, "wrong root hub descriptor read %d\n", ret);
395 return ret;
396 }
397
398 /* submit urb to poll interrupt endpoint */
399 lvs->urb = usb_alloc_urb(0, GFP_KERNEL);
400 if (!lvs->urb) {
401 dev_err(&intf->dev, "couldn't allocate lvs urb\n");
402 return -ENOMEM;
403 }
404
405 lvs->rh_queue = create_singlethread_workqueue("lvs_rh_queue");
406 if (!lvs->rh_queue) {
407 dev_err(&intf->dev, "couldn't create workqueue\n");
408 ret = -ENOMEM;
409 goto free_urb;
410 }
411
412 INIT_WORK(&lvs->rh_work, lvs_rh_work);
413
414 ret = sysfs_create_group(&intf->dev.kobj, &lvs_attr_group);
415 if (ret < 0) {
416 dev_err(&intf->dev, "Failed to create sysfs node %d\n", ret);
417 goto destroy_queue;
418 }
419
420 pipe = usb_rcvintpipe(hdev, endpoint->bEndpointAddress);
421 maxp = usb_maxpacket(hdev, pipe, usb_pipeout(pipe));
422 usb_fill_int_urb(lvs->urb, hdev, pipe, &lvs->buffer[0], maxp,
423 lvs_rh_irq, lvs, endpoint->bInterval);
424
425 ret = usb_submit_urb(lvs->urb, GFP_KERNEL);
426 if (ret < 0) {
427 dev_err(&intf->dev, "couldn't submit lvs urb %d\n", ret);
428 goto sysfs_remove;
429 }
430
431 return ret;
432
433sysfs_remove:
434 sysfs_remove_group(&intf->dev.kobj, &lvs_attr_group);
435destroy_queue:
436 destroy_workqueue(lvs->rh_queue);
437free_urb:
438 usb_free_urb(lvs->urb);
439 return ret;
440}
441
442static void lvs_rh_disconnect(struct usb_interface *intf)
443{
444 struct lvs_rh *lvs = usb_get_intfdata(intf);
445
446 sysfs_remove_group(&intf->dev.kobj, &lvs_attr_group);
447 destroy_workqueue(lvs->rh_queue);
448 usb_free_urb(lvs->urb);
449}
450
451static struct usb_driver lvs_driver = {
452 .name = "lvs",
453 .probe = lvs_rh_probe,
454 .disconnect = lvs_rh_disconnect,
455};
456
457module_usb_driver(lvs_driver);
458
459MODULE_DESCRIPTION("Link Layer Validation System Driver");
460MODULE_LICENSE("GPL");