aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/ABI/testing/sysfs-module23
-rw-r--r--Documentation/usb/ehci.txt2
-rw-r--r--drivers/usb/host/ehci-hcd.c6
-rw-r--r--drivers/usb/host/ehci-sched.c17
-rw-r--r--drivers/usb/host/ehci-sysfs.c104
-rw-r--r--drivers/usb/host/ehci.h2
6 files changed, 140 insertions, 14 deletions
diff --git a/Documentation/ABI/testing/sysfs-module b/Documentation/ABI/testing/sysfs-module
index cfcec3bffc0a..9489ea8e294c 100644
--- a/Documentation/ABI/testing/sysfs-module
+++ b/Documentation/ABI/testing/sysfs-module
@@ -10,3 +10,26 @@ KernelVersion: 2.6.35
10Contact: masa-korg@dsn.okisemi.com 10Contact: masa-korg@dsn.okisemi.com
11Description: Write/read Option ROM data. 11Description: Write/read Option ROM data.
12 12
13
14What: /sys/module/ehci_hcd/drivers/.../uframe_periodic_max
15Date: July 2011
16KernelVersion: 3.1
17Contact: Kirill Smelkov <kirr@mns.spb.ru>
18Description: Maximum time allowed for periodic transfers per microframe (μs)
19
20 [ USB 2.0 sets maximum allowed time for periodic transfers per
21 microframe to be 80%, that is 100 microseconds out of 125
22 microseconds (full microframe).
23
24 However there are cases, when 80% max isochronous bandwidth is
25 too limiting. For example two video streams could require 110
26 microseconds of isochronous bandwidth per microframe to work
27 together. ]
28
29 Through this setting it is possible to raise the limit so that
30 the host controller would allow allocating more than 100
31 microseconds of periodic bandwidth per microframe.
32
33 Beware, non-standard modes are usually not thoroughly tested by
34 hardware designers, and the hardware can malfunction when this
35 setting differ from default 100.
diff --git a/Documentation/usb/ehci.txt b/Documentation/usb/ehci.txt
index 9dcafa7d930d..160bd6c3ab7b 100644
--- a/Documentation/usb/ehci.txt
+++ b/Documentation/usb/ehci.txt
@@ -210,3 +210,5 @@ TBD: Interrupt and ISO transfer performance issues. Those periodic
210transfers are fully scheduled, so the main issue is likely to be how 210transfers are fully scheduled, so the main issue is likely to be how
211to trigger "high bandwidth" modes. 211to trigger "high bandwidth" modes.
212 212
213TBD: More than standard 80% periodic bandwidth allocation is possible
214through sysfs uframe_periodic_max parameter. Describe that.
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 8306155de9e5..4ee62bef3723 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -572,6 +572,12 @@ static int ehci_init(struct usb_hcd *hcd)
572 hcc_params = ehci_readl(ehci, &ehci->caps->hcc_params); 572 hcc_params = ehci_readl(ehci, &ehci->caps->hcc_params);
573 573
574 /* 574 /*
575 * by default set standard 80% (== 100 usec/uframe) max periodic
576 * bandwidth as required by USB 2.0
577 */
578 ehci->uframe_periodic_max = 100;
579
580 /*
575 * hw default: 1K periodic list heads, one per frame. 581 * hw default: 1K periodic list heads, one per frame.
576 * periodic_size can shrink by USBCMD update if hcc_params allows. 582 * periodic_size can shrink by USBCMD update if hcc_params allows.
577 */ 583 */
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
index 6c9fbe352f73..2abf8543f083 100644
--- a/drivers/usb/host/ehci-sched.c
+++ b/drivers/usb/host/ehci-sched.c
@@ -172,7 +172,7 @@ periodic_usecs (struct ehci_hcd *ehci, unsigned frame, unsigned uframe)
172 } 172 }
173 } 173 }
174#ifdef DEBUG 174#ifdef DEBUG
175 if (usecs > 100) 175 if (usecs > ehci->uframe_periodic_max)
176 ehci_err (ehci, "uframe %d sched overrun: %d usecs\n", 176 ehci_err (ehci, "uframe %d sched overrun: %d usecs\n",
177 frame * 8 + uframe, usecs); 177 frame * 8 + uframe, usecs);
178#endif 178#endif
@@ -709,11 +709,8 @@ static int check_period (
709 if (uframe >= 8) 709 if (uframe >= 8)
710 return 0; 710 return 0;
711 711
712 /* 712 /* convert "usecs we need" to "max already claimed" */
713 * 80% periodic == 100 usec/uframe available 713 usecs = ehci->uframe_periodic_max - usecs;
714 * convert "usecs we need" to "max already claimed"
715 */
716 usecs = 100 - usecs;
717 714
718 /* we "know" 2 and 4 uframe intervals were rejected; so 715 /* we "know" 2 and 4 uframe intervals were rejected; so
719 * for period 0, check _every_ microframe in the schedule. 716 * for period 0, check _every_ microframe in the schedule.
@@ -1286,9 +1283,9 @@ itd_slot_ok (
1286{ 1283{
1287 uframe %= period; 1284 uframe %= period;
1288 do { 1285 do {
1289 /* can't commit more than 80% periodic == 100 usec */ 1286 /* can't commit more than uframe_periodic_max usec */
1290 if (periodic_usecs (ehci, uframe >> 3, uframe & 0x7) 1287 if (periodic_usecs (ehci, uframe >> 3, uframe & 0x7)
1291 > (100 - usecs)) 1288 > (ehci->uframe_periodic_max - usecs))
1292 return 0; 1289 return 0;
1293 1290
1294 /* we know urb->interval is 2^N uframes */ 1291 /* we know urb->interval is 2^N uframes */
@@ -1345,7 +1342,7 @@ sitd_slot_ok (
1345#endif 1342#endif
1346 1343
1347 /* check starts (OUT uses more than one) */ 1344 /* check starts (OUT uses more than one) */
1348 max_used = 100 - stream->usecs; 1345 max_used = ehci->uframe_periodic_max - stream->usecs;
1349 for (tmp = stream->raw_mask & 0xff; tmp; tmp >>= 1, uf++) { 1346 for (tmp = stream->raw_mask & 0xff; tmp; tmp >>= 1, uf++) {
1350 if (periodic_usecs (ehci, frame, uf) > max_used) 1347 if (periodic_usecs (ehci, frame, uf) > max_used)
1351 return 0; 1348 return 0;
@@ -1354,7 +1351,7 @@ sitd_slot_ok (
1354 /* for IN, check CSPLIT */ 1351 /* for IN, check CSPLIT */
1355 if (stream->c_usecs) { 1352 if (stream->c_usecs) {
1356 uf = uframe & 7; 1353 uf = uframe & 7;
1357 max_used = 100 - stream->c_usecs; 1354 max_used = ehci->uframe_periodic_max - stream->c_usecs;
1358 do { 1355 do {
1359 tmp = 1 << uf; 1356 tmp = 1 << uf;
1360 tmp <<= 8; 1357 tmp <<= 8;
diff --git a/drivers/usb/host/ehci-sysfs.c b/drivers/usb/host/ehci-sysfs.c
index 29824a98aec9..14ced00ba220 100644
--- a/drivers/usb/host/ehci-sysfs.c
+++ b/drivers/usb/host/ehci-sysfs.c
@@ -74,21 +74,117 @@ static ssize_t store_companion(struct device *dev,
74} 74}
75static DEVICE_ATTR(companion, 0644, show_companion, store_companion); 75static DEVICE_ATTR(companion, 0644, show_companion, store_companion);
76 76
77
78/*
79 * Display / Set uframe_periodic_max
80 */
81static ssize_t show_uframe_periodic_max(struct device *dev,
82 struct device_attribute *attr,
83 char *buf)
84{
85 struct ehci_hcd *ehci;
86 int n;
87
88 ehci = hcd_to_ehci(bus_to_hcd(dev_get_drvdata(dev)));
89 n = scnprintf(buf, PAGE_SIZE, "%d\n", ehci->uframe_periodic_max);
90 return n;
91}
92
93
94static ssize_t store_uframe_periodic_max(struct device *dev,
95 struct device_attribute *attr,
96 const char *buf, size_t count)
97{
98 struct ehci_hcd *ehci;
99 unsigned uframe_periodic_max;
100 unsigned frame, uframe;
101 unsigned short allocated_max;
102 unsigned long flags;
103 ssize_t ret;
104
105 ehci = hcd_to_ehci(bus_to_hcd(dev_get_drvdata(dev)));
106 if (kstrtouint(buf, 0, &uframe_periodic_max) < 0)
107 return -EINVAL;
108
109 if (uframe_periodic_max < 100 || uframe_periodic_max >= 125) {
110 ehci_info(ehci, "rejecting invalid request for "
111 "uframe_periodic_max=%u\n", uframe_periodic_max);
112 return -EINVAL;
113 }
114
115 ret = -EINVAL;
116
117 /*
118 * lock, so that our checking does not race with possible periodic
119 * bandwidth allocation through submitting new urbs.
120 */
121 spin_lock_irqsave (&ehci->lock, flags);
122
123 /*
124 * for request to decrease max periodic bandwidth, we have to check
125 * every microframe in the schedule to see whether the decrease is
126 * possible.
127 */
128 if (uframe_periodic_max < ehci->uframe_periodic_max) {
129 allocated_max = 0;
130
131 for (frame = 0; frame < ehci->periodic_size; ++frame)
132 for (uframe = 0; uframe < 7; ++uframe)
133 allocated_max = max(allocated_max,
134 periodic_usecs (ehci, frame, uframe));
135
136 if (allocated_max > uframe_periodic_max) {
137 ehci_info(ehci,
138 "cannot decrease uframe_periodic_max becase "
139 "periodic bandwidth is already allocated "
140 "(%u > %u)\n",
141 allocated_max, uframe_periodic_max);
142 goto out_unlock;
143 }
144 }
145
146 /* increasing is always ok */
147
148 ehci_info(ehci, "setting max periodic bandwidth to %u%% "
149 "(== %u usec/uframe)\n",
150 100*uframe_periodic_max/125, uframe_periodic_max);
151
152 if (uframe_periodic_max != 100)
153 ehci_warn(ehci, "max periodic bandwidth set is non-standard\n");
154
155 ehci->uframe_periodic_max = uframe_periodic_max;
156 ret = count;
157
158out_unlock:
159 spin_unlock_irqrestore (&ehci->lock, flags);
160 return ret;
161}
162static DEVICE_ATTR(uframe_periodic_max, 0644, show_uframe_periodic_max, store_uframe_periodic_max);
163
164
77static inline int create_sysfs_files(struct ehci_hcd *ehci) 165static inline int create_sysfs_files(struct ehci_hcd *ehci)
78{ 166{
167 struct device *controller = ehci_to_hcd(ehci)->self.controller;
79 int i = 0; 168 int i = 0;
80 169
81 /* with integrated TT there is no companion! */ 170 /* with integrated TT there is no companion! */
82 if (!ehci_is_TDI(ehci)) 171 if (!ehci_is_TDI(ehci))
83 i = device_create_file(ehci_to_hcd(ehci)->self.controller, 172 i = device_create_file(controller, &dev_attr_companion);
84 &dev_attr_companion); 173 if (i)
174 goto out;
175
176 i = device_create_file(controller, &dev_attr_uframe_periodic_max);
177out:
85 return i; 178 return i;
86} 179}
87 180
88static inline void remove_sysfs_files(struct ehci_hcd *ehci) 181static inline void remove_sysfs_files(struct ehci_hcd *ehci)
89{ 182{
183 struct device *controller = ehci_to_hcd(ehci)->self.controller;
184
90 /* with integrated TT there is no companion! */ 185 /* with integrated TT there is no companion! */
91 if (!ehci_is_TDI(ehci)) 186 if (!ehci_is_TDI(ehci))
92 device_remove_file(ehci_to_hcd(ehci)->self.controller, 187 device_remove_file(controller, &dev_attr_companion);
93 &dev_attr_companion); 188
189 device_remove_file(controller, &dev_attr_uframe_periodic_max);
94} 190}
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index bd6ff489baf9..fa3129fe1ee0 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -87,6 +87,8 @@ struct ehci_hcd { /* one per controller */
87 union ehci_shadow *pshadow; /* mirror hw periodic table */ 87 union ehci_shadow *pshadow; /* mirror hw periodic table */
88 int next_uframe; /* scan periodic, start here */ 88 int next_uframe; /* scan periodic, start here */
89 unsigned periodic_sched; /* periodic activity count */ 89 unsigned periodic_sched; /* periodic activity count */
90 unsigned uframe_periodic_max; /* max periodic time per uframe */
91
90 92
91 /* list of itds & sitds completed while clock_frame was still active */ 93 /* list of itds & sitds completed while clock_frame was still active */
92 struct list_head cached_itd_list; 94 struct list_head cached_itd_list;