diff options
-rw-r--r-- | drivers/usb/host/ehci-hcd.c | 16 | ||||
-rw-r--r-- | drivers/usb/host/ehci-hub.c | 1 | ||||
-rw-r--r-- | drivers/usb/host/ehci-q.c | 78 | ||||
-rw-r--r-- | drivers/usb/host/ehci-timer.c | 2 | ||||
-rw-r--r-- | drivers/usb/host/ehci.h | 4 |
5 files changed, 59 insertions, 42 deletions
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 86e8ee169c67..74ffd20edff8 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c | |||
@@ -94,8 +94,6 @@ static const char hcd_name [] = "ehci_hcd"; | |||
94 | #define EHCI_TUNE_FLS 1 /* (medium) 512-frame schedule */ | 94 | #define EHCI_TUNE_FLS 1 /* (medium) 512-frame schedule */ |
95 | 95 | ||
96 | #define EHCI_IO_JIFFIES (HZ/10) /* io watchdog > irq_thresh */ | 96 | #define EHCI_IO_JIFFIES (HZ/10) /* io watchdog > irq_thresh */ |
97 | #define EHCI_SHRINK_JIFFIES (DIV_ROUND_UP(HZ, 200) + 1) | ||
98 | /* 5-ms async qh unlink delay */ | ||
99 | 97 | ||
100 | /* Initial IRQ latency: faster than hw default */ | 98 | /* Initial IRQ latency: faster than hw default */ |
101 | static int log2_irq_thresh = 0; // 0 to 6 | 99 | static int log2_irq_thresh = 0; // 0 to 6 |
@@ -130,15 +128,6 @@ MODULE_PARM_DESC(hird, "host initiated resume duration, +1 for each 75us"); | |||
130 | static void | 128 | static void |
131 | timer_action(struct ehci_hcd *ehci, enum ehci_timer_action action) | 129 | timer_action(struct ehci_hcd *ehci, enum ehci_timer_action action) |
132 | { | 130 | { |
133 | /* Don't override timeouts which shrink or (later) disable | ||
134 | * the async ring; just the I/O watchdog. Note that if a | ||
135 | * SHRINK were pending, OFF would never be requested. | ||
136 | */ | ||
137 | if (timer_pending(&ehci->watchdog) | ||
138 | && (BIT(TIMER_ASYNC_SHRINK) | ||
139 | & ehci->actions)) | ||
140 | return; | ||
141 | |||
142 | if (!test_and_set_bit(action, &ehci->actions)) { | 131 | if (!test_and_set_bit(action, &ehci->actions)) { |
143 | unsigned long t; | 132 | unsigned long t; |
144 | 133 | ||
@@ -148,10 +137,6 @@ timer_action(struct ehci_hcd *ehci, enum ehci_timer_action action) | |||
148 | return; | 137 | return; |
149 | t = EHCI_IO_JIFFIES; | 138 | t = EHCI_IO_JIFFIES; |
150 | break; | 139 | break; |
151 | /* case TIMER_ASYNC_SHRINK: */ | ||
152 | default: | ||
153 | t = EHCI_SHRINK_JIFFIES; | ||
154 | break; | ||
155 | } | 140 | } |
156 | mod_timer(&ehci->watchdog, t + jiffies); | 141 | mod_timer(&ehci->watchdog, t + jiffies); |
157 | } | 142 | } |
@@ -307,6 +292,7 @@ static void ehci_quiesce (struct ehci_hcd *ehci) | |||
307 | /*-------------------------------------------------------------------------*/ | 292 | /*-------------------------------------------------------------------------*/ |
308 | 293 | ||
309 | static void end_unlink_async(struct ehci_hcd *ehci); | 294 | static void end_unlink_async(struct ehci_hcd *ehci); |
295 | static void unlink_empty_async(struct ehci_hcd *ehci); | ||
310 | static void ehci_work(struct ehci_hcd *ehci); | 296 | static void ehci_work(struct ehci_hcd *ehci); |
311 | static void start_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh); | 297 | static void start_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh); |
312 | static void end_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh); | 298 | static void end_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh); |
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index a3822700e496..5d84562e2716 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c | |||
@@ -300,6 +300,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd) | |||
300 | ehci->rh_state = EHCI_RH_SUSPENDED; | 300 | ehci->rh_state = EHCI_RH_SUSPENDED; |
301 | 301 | ||
302 | end_unlink_async(ehci); | 302 | end_unlink_async(ehci); |
303 | unlink_empty_async(ehci); | ||
303 | ehci_handle_intr_unlinks(ehci); | 304 | ehci_handle_intr_unlinks(ehci); |
304 | end_free_itds(ehci); | 305 | end_free_itds(ehci); |
305 | 306 | ||
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index 181832921c53..bae931767825 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c | |||
@@ -1205,7 +1205,7 @@ static void start_iaa_cycle(struct ehci_hcd *ehci, bool nested) | |||
1205 | end_unlink_async(ehci); | 1205 | end_unlink_async(ehci); |
1206 | 1206 | ||
1207 | /* Otherwise start a new IAA cycle */ | 1207 | /* Otherwise start a new IAA cycle */ |
1208 | } else { | 1208 | } else if (likely(ehci->rh_state == EHCI_RH_RUNNING)) { |
1209 | /* Make sure the unlinks are all visible to the hardware */ | 1209 | /* Make sure the unlinks are all visible to the hardware */ |
1210 | wmb(); | 1210 | wmb(); |
1211 | 1211 | ||
@@ -1253,6 +1253,39 @@ static void end_unlink_async(struct ehci_hcd *ehci) | |||
1253 | } | 1253 | } |
1254 | } | 1254 | } |
1255 | 1255 | ||
1256 | static void unlink_empty_async(struct ehci_hcd *ehci) | ||
1257 | { | ||
1258 | struct ehci_qh *qh, *next; | ||
1259 | bool stopped = (ehci->rh_state < EHCI_RH_RUNNING); | ||
1260 | bool check_unlinks_later = false; | ||
1261 | |||
1262 | /* Unlink all the async QHs that have been empty for a timer cycle */ | ||
1263 | next = ehci->async->qh_next.qh; | ||
1264 | while (next) { | ||
1265 | qh = next; | ||
1266 | next = qh->qh_next.qh; | ||
1267 | |||
1268 | if (list_empty(&qh->qtd_list) && | ||
1269 | qh->qh_state == QH_STATE_LINKED) { | ||
1270 | if (!stopped && qh->unlink_cycle == | ||
1271 | ehci->async_unlink_cycle) | ||
1272 | check_unlinks_later = true; | ||
1273 | else | ||
1274 | single_unlink_async(ehci, qh); | ||
1275 | } | ||
1276 | } | ||
1277 | |||
1278 | /* Start a new IAA cycle if any QHs are waiting for it */ | ||
1279 | if (ehci->async_unlink) | ||
1280 | start_iaa_cycle(ehci, false); | ||
1281 | |||
1282 | /* QHs that haven't been empty for long enough will be handled later */ | ||
1283 | if (check_unlinks_later) { | ||
1284 | ehci_enable_event(ehci, EHCI_HRTIMER_ASYNC_UNLINKS, true); | ||
1285 | ++ehci->async_unlink_cycle; | ||
1286 | } | ||
1287 | } | ||
1288 | |||
1256 | /* makes sure the async qh will become idle */ | 1289 | /* makes sure the async qh will become idle */ |
1257 | /* caller must own ehci->lock */ | 1290 | /* caller must own ehci->lock */ |
1258 | 1291 | ||
@@ -1277,12 +1310,8 @@ static void start_unlink_async(struct ehci_hcd *ehci, struct ehci_qh *qh) | |||
1277 | 1310 | ||
1278 | static void scan_async (struct ehci_hcd *ehci) | 1311 | static void scan_async (struct ehci_hcd *ehci) |
1279 | { | 1312 | { |
1280 | bool stopped; | ||
1281 | struct ehci_qh *qh; | 1313 | struct ehci_qh *qh; |
1282 | enum ehci_timer_action action = TIMER_IO_WATCHDOG; | 1314 | bool check_unlinks_later = false; |
1283 | |||
1284 | timer_action_done (ehci, TIMER_ASYNC_SHRINK); | ||
1285 | stopped = (ehci->rh_state < EHCI_RH_RUNNING); | ||
1286 | 1315 | ||
1287 | ehci->qh_scan_next = ehci->async->qh_next.qh; | 1316 | ehci->qh_scan_next = ehci->async->qh_next.qh; |
1288 | while (ehci->qh_scan_next) { | 1317 | while (ehci->qh_scan_next) { |
@@ -1301,28 +1330,27 @@ static void scan_async (struct ehci_hcd *ehci) | |||
1301 | * in single_unlink_async(). | 1330 | * in single_unlink_async(). |
1302 | */ | 1331 | */ |
1303 | temp = qh_completions(ehci, qh); | 1332 | temp = qh_completions(ehci, qh); |
1304 | if (qh->needs_rescan) | 1333 | if (qh->needs_rescan) { |
1305 | start_unlink_async(ehci, qh); | 1334 | start_unlink_async(ehci, qh); |
1306 | qh->unlink_time = jiffies + EHCI_SHRINK_JIFFIES; | 1335 | } else if (list_empty(&qh->qtd_list) |
1307 | if (temp != 0) | 1336 | && qh->qh_state == QH_STATE_LINKED) { |
1337 | qh->unlink_cycle = ehci->async_unlink_cycle; | ||
1338 | check_unlinks_later = true; | ||
1339 | } else if (temp != 0) | ||
1308 | goto rescan; | 1340 | goto rescan; |
1309 | } | 1341 | } |
1342 | } | ||
1310 | 1343 | ||
1311 | /* unlink idle entries, reducing DMA usage as well | 1344 | /* |
1312 | * as HCD schedule-scanning costs. delay for any qh | 1345 | * Unlink empty entries, reducing DMA usage as well |
1313 | * we just scanned, there's a not-unusual case that it | 1346 | * as HCD schedule-scanning costs. Delay for any qh |
1314 | * doesn't stay idle for long. | 1347 | * we just scanned, there's a not-unusual case that it |
1315 | * (plus, avoids some kind of re-activation race.) | 1348 | * doesn't stay idle for long. |
1316 | */ | 1349 | */ |
1317 | if (list_empty(&qh->qtd_list) | 1350 | if (check_unlinks_later && ehci->rh_state == EHCI_RH_RUNNING && |
1318 | && qh->qh_state == QH_STATE_LINKED) { | 1351 | !(ehci->enabled_hrtimer_events & |
1319 | if (!ehci->async_unlink && (stopped || | 1352 | BIT(EHCI_HRTIMER_ASYNC_UNLINKS))) { |
1320 | time_after_eq(jiffies, qh->unlink_time))) | 1353 | ehci_enable_event(ehci, EHCI_HRTIMER_ASYNC_UNLINKS, true); |
1321 | start_unlink_async(ehci, qh); | 1354 | ++ehci->async_unlink_cycle; |
1322 | else | ||
1323 | action = TIMER_ASYNC_SHRINK; | ||
1324 | } | ||
1325 | } | 1355 | } |
1326 | if (action == TIMER_ASYNC_SHRINK) | ||
1327 | timer_action (ehci, TIMER_ASYNC_SHRINK); | ||
1328 | } | 1356 | } |
diff --git a/drivers/usb/host/ehci-timer.c b/drivers/usb/host/ehci-timer.c index 8ca5f152f5bd..a823290b5139 100644 --- a/drivers/usb/host/ehci-timer.c +++ b/drivers/usb/host/ehci-timer.c | |||
@@ -72,6 +72,7 @@ static unsigned event_delays_ns[] = { | |||
72 | 1 * NSEC_PER_MSEC, /* EHCI_HRTIMER_POLL_DEAD */ | 72 | 1 * NSEC_PER_MSEC, /* EHCI_HRTIMER_POLL_DEAD */ |
73 | 1125 * NSEC_PER_USEC, /* EHCI_HRTIMER_UNLINK_INTR */ | 73 | 1125 * NSEC_PER_USEC, /* EHCI_HRTIMER_UNLINK_INTR */ |
74 | 2 * NSEC_PER_MSEC, /* EHCI_HRTIMER_FREE_ITDS */ | 74 | 2 * NSEC_PER_MSEC, /* EHCI_HRTIMER_FREE_ITDS */ |
75 | 6 * NSEC_PER_MSEC, /* EHCI_HRTIMER_ASYNC_UNLINKS */ | ||
75 | 10 * NSEC_PER_MSEC, /* EHCI_HRTIMER_IAA_WATCHDOG */ | 76 | 10 * NSEC_PER_MSEC, /* EHCI_HRTIMER_IAA_WATCHDOG */ |
76 | 10 * NSEC_PER_MSEC, /* EHCI_HRTIMER_DISABLE_PERIODIC */ | 77 | 10 * NSEC_PER_MSEC, /* EHCI_HRTIMER_DISABLE_PERIODIC */ |
77 | 15 * NSEC_PER_MSEC, /* EHCI_HRTIMER_DISABLE_ASYNC */ | 78 | 15 * NSEC_PER_MSEC, /* EHCI_HRTIMER_DISABLE_ASYNC */ |
@@ -347,6 +348,7 @@ static void (*event_handlers[])(struct ehci_hcd *) = { | |||
347 | ehci_handle_controller_death, /* EHCI_HRTIMER_POLL_DEAD */ | 348 | ehci_handle_controller_death, /* EHCI_HRTIMER_POLL_DEAD */ |
348 | ehci_handle_intr_unlinks, /* EHCI_HRTIMER_UNLINK_INTR */ | 349 | ehci_handle_intr_unlinks, /* EHCI_HRTIMER_UNLINK_INTR */ |
349 | end_free_itds, /* EHCI_HRTIMER_FREE_ITDS */ | 350 | end_free_itds, /* EHCI_HRTIMER_FREE_ITDS */ |
351 | unlink_empty_async, /* EHCI_HRTIMER_ASYNC_UNLINKS */ | ||
350 | ehci_iaa_watchdog, /* EHCI_HRTIMER_IAA_WATCHDOG */ | 352 | ehci_iaa_watchdog, /* EHCI_HRTIMER_IAA_WATCHDOG */ |
351 | ehci_disable_PSE, /* EHCI_HRTIMER_DISABLE_PERIODIC */ | 353 | ehci_disable_PSE, /* EHCI_HRTIMER_DISABLE_PERIODIC */ |
352 | ehci_disable_ASE, /* EHCI_HRTIMER_DISABLE_ASYNC */ | 354 | ehci_disable_ASE, /* EHCI_HRTIMER_DISABLE_ASYNC */ |
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index 1a782775881b..303c36cc99c9 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h | |||
@@ -84,6 +84,7 @@ enum ehci_hrtimer_event { | |||
84 | EHCI_HRTIMER_POLL_DEAD, /* Wait for dead controller to stop */ | 84 | EHCI_HRTIMER_POLL_DEAD, /* Wait for dead controller to stop */ |
85 | EHCI_HRTIMER_UNLINK_INTR, /* Wait for interrupt QH unlink */ | 85 | EHCI_HRTIMER_UNLINK_INTR, /* Wait for interrupt QH unlink */ |
86 | EHCI_HRTIMER_FREE_ITDS, /* Wait for unused iTDs and siTDs */ | 86 | EHCI_HRTIMER_FREE_ITDS, /* Wait for unused iTDs and siTDs */ |
87 | EHCI_HRTIMER_ASYNC_UNLINKS, /* Unlink empty async QHs */ | ||
87 | EHCI_HRTIMER_IAA_WATCHDOG, /* Handle lost IAA interrupts */ | 88 | EHCI_HRTIMER_IAA_WATCHDOG, /* Handle lost IAA interrupts */ |
88 | EHCI_HRTIMER_DISABLE_PERIODIC, /* Wait to disable periodic sched */ | 89 | EHCI_HRTIMER_DISABLE_PERIODIC, /* Wait to disable periodic sched */ |
89 | EHCI_HRTIMER_DISABLE_ASYNC, /* Wait to disable async sched */ | 90 | EHCI_HRTIMER_DISABLE_ASYNC, /* Wait to disable async sched */ |
@@ -123,6 +124,7 @@ struct ehci_hcd { /* one per controller */ | |||
123 | struct ehci_qh *async_unlink_last; | 124 | struct ehci_qh *async_unlink_last; |
124 | struct ehci_qh *async_iaa; | 125 | struct ehci_qh *async_iaa; |
125 | struct ehci_qh *qh_scan_next; | 126 | struct ehci_qh *qh_scan_next; |
127 | unsigned async_unlink_cycle; | ||
126 | unsigned async_count; /* async activity count */ | 128 | unsigned async_count; /* async activity count */ |
127 | 129 | ||
128 | /* periodic schedule support */ | 130 | /* periodic schedule support */ |
@@ -232,7 +234,6 @@ static inline struct usb_hcd *ehci_to_hcd (struct ehci_hcd *ehci) | |||
232 | 234 | ||
233 | enum ehci_timer_action { | 235 | enum ehci_timer_action { |
234 | TIMER_IO_WATCHDOG, | 236 | TIMER_IO_WATCHDOG, |
235 | TIMER_ASYNC_SHRINK, | ||
236 | }; | 237 | }; |
237 | 238 | ||
238 | static inline void | 239 | static inline void |
@@ -382,7 +383,6 @@ struct ehci_qh { | |||
382 | struct ehci_qtd *dummy; | 383 | struct ehci_qtd *dummy; |
383 | struct ehci_qh *unlink_next; /* next on unlink list */ | 384 | struct ehci_qh *unlink_next; /* next on unlink list */ |
384 | 385 | ||
385 | unsigned long unlink_time; | ||
386 | unsigned unlink_cycle; | 386 | unsigned unlink_cycle; |
387 | unsigned stamp; | 387 | unsigned stamp; |
388 | 388 | ||