diff options
| -rw-r--r-- | drivers/usb/host/Kconfig | 20 | ||||
| -rw-r--r-- | drivers/usb/host/ehci-sched.c | 216 |
2 files changed, 234 insertions, 2 deletions
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index e27b79a3c05f..c060eb9b3b19 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig | |||
| @@ -47,7 +47,25 @@ config USB_EHCI_ROOT_HUB_TT | |||
| 47 | controller is needed. It's safe to say "y" even if your | 47 | controller is needed. It's safe to say "y" even if your |
| 48 | controller doesn't support this feature. | 48 | controller doesn't support this feature. |
| 49 | 49 | ||
| 50 | This supports the EHCI implementation from TransDimension Inc. | 50 | This supports the EHCI implementation that's originally |
| 51 | from ARC, and has since changed hands a few times. | ||
| 52 | |||
| 53 | config USB_EHCI_TT_NEWSCHED | ||
| 54 | bool "Improved Transaction Translator scheduling (EXPERIMENTAL)" | ||
| 55 | depends on USB_EHCI_HCD && EXPERIMENTAL | ||
| 56 | ---help--- | ||
| 57 | This changes the periodic scheduling code to fill more of the low | ||
| 58 | and full speed bandwidth available from the Transaction Translator | ||
| 59 | (TT) in USB 2.0 hubs. Without this, only one transfer will be | ||
| 60 | issued in each microframe, significantly reducing the number of | ||
| 61 | periodic low/fullspeed transfers possible. | ||
| 62 | |||
| 63 | If you have multiple periodic low/fullspeed devices connected to a | ||
| 64 | highspeed USB hub which is connected to a highspeed USB Host | ||
| 65 | Controller, and some of those devices will not work correctly | ||
| 66 | (possibly due to "ENOSPC" or "-28" errors), say Y. | ||
| 67 | |||
| 68 | If unsure, say N. | ||
| 51 | 69 | ||
| 52 | config USB_ISP116X_HCD | 70 | config USB_ISP116X_HCD |
| 53 | tristate "ISP116X HCD support" | 71 | tristate "ISP116X HCD support" |
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index 5871944e6145..4859900bd135 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c | |||
| @@ -163,6 +163,190 @@ static int same_tt (struct usb_device *dev1, struct usb_device *dev2) | |||
| 163 | return 1; | 163 | return 1; |
| 164 | } | 164 | } |
| 165 | 165 | ||
| 166 | #ifdef CONFIG_USB_EHCI_TT_NEWSCHED | ||
| 167 | |||
| 168 | /* Which uframe does the low/fullspeed transfer start in? | ||
| 169 | * | ||
| 170 | * The parameter is the mask of ssplits in "H-frame" terms | ||
| 171 | * and this returns the transfer start uframe in "B-frame" terms, | ||
| 172 | * which allows both to match, e.g. a ssplit in "H-frame" uframe 0 | ||
| 173 | * will cause a transfer in "B-frame" uframe 0. "B-frames" lag | ||
| 174 | * "H-frames" by 1 uframe. See the EHCI spec sec 4.5 and figure 4.7. | ||
| 175 | */ | ||
| 176 | static inline unsigned char tt_start_uframe(struct ehci_hcd *ehci, __le32 mask) | ||
| 177 | { | ||
| 178 | unsigned char smask = QH_SMASK & le32_to_cpu(mask); | ||
| 179 | if (!smask) { | ||
| 180 | ehci_err(ehci, "invalid empty smask!\n"); | ||
| 181 | /* uframe 7 can't have bw so this will indicate failure */ | ||
| 182 | return 7; | ||
| 183 | } | ||
| 184 | return ffs(smask) - 1; | ||
| 185 | } | ||
| 186 | |||
| 187 | static const unsigned char | ||
| 188 | max_tt_usecs[] = { 125, 125, 125, 125, 125, 125, 30, 0 }; | ||
| 189 | |||
| 190 | /* carryover low/fullspeed bandwidth that crosses uframe boundries */ | ||
| 191 | static inline void carryover_tt_bandwidth(unsigned short tt_usecs[8]) | ||
| 192 | { | ||
| 193 | int i; | ||
| 194 | for (i=0; i<7; i++) { | ||
| 195 | if (max_tt_usecs[i] < tt_usecs[i]) { | ||
| 196 | tt_usecs[i+1] += tt_usecs[i] - max_tt_usecs[i]; | ||
| 197 | tt_usecs[i] = max_tt_usecs[i]; | ||
| 198 | } | ||
| 199 | } | ||
| 200 | } | ||
| 201 | |||
| 202 | /* How many of the tt's periodic downstream 1000 usecs are allocated? | ||
| 203 | * | ||
| 204 | * While this measures the bandwidth in terms of usecs/uframe, | ||
| 205 | * the low/fullspeed bus has no notion of uframes, so any particular | ||
| 206 | * low/fullspeed transfer can "carry over" from one uframe to the next, | ||
| 207 | * since the TT just performs downstream transfers in sequence. | ||
| 208 | * | ||
| 209 | * For example two seperate 100 usec transfers can start in the same uframe, | ||
| 210 | * and the second one would "carry over" 75 usecs into the next uframe. | ||
| 211 | */ | ||
| 212 | static void | ||
| 213 | periodic_tt_usecs ( | ||
| 214 | struct ehci_hcd *ehci, | ||
| 215 | struct usb_device *dev, | ||
| 216 | unsigned frame, | ||
| 217 | unsigned short tt_usecs[8] | ||
| 218 | ) | ||
| 219 | { | ||
| 220 | __le32 *hw_p = &ehci->periodic [frame]; | ||
| 221 | union ehci_shadow *q = &ehci->pshadow [frame]; | ||
| 222 | unsigned char uf; | ||
| 223 | |||
| 224 | memset(tt_usecs, 0, 16); | ||
| 225 | |||
| 226 | while (q->ptr) { | ||
| 227 | switch (Q_NEXT_TYPE(*hw_p)) { | ||
| 228 | case Q_TYPE_ITD: | ||
| 229 | hw_p = &q->itd->hw_next; | ||
| 230 | q = &q->itd->itd_next; | ||
| 231 | continue; | ||
| 232 | case Q_TYPE_QH: | ||
| 233 | if (same_tt(dev, q->qh->dev)) { | ||
| 234 | uf = tt_start_uframe(ehci, q->qh->hw_info2); | ||
| 235 | tt_usecs[uf] += q->qh->tt_usecs; | ||
| 236 | } | ||
| 237 | hw_p = &q->qh->hw_next; | ||
| 238 | q = &q->qh->qh_next; | ||
| 239 | continue; | ||
| 240 | case Q_TYPE_SITD: | ||
| 241 | if (same_tt(dev, q->sitd->urb->dev)) { | ||
| 242 | uf = tt_start_uframe(ehci, q->sitd->hw_uframe); | ||
| 243 | tt_usecs[uf] += q->sitd->stream->tt_usecs; | ||
| 244 | } | ||
| 245 | hw_p = &q->sitd->hw_next; | ||
| 246 | q = &q->sitd->sitd_next; | ||
| 247 | continue; | ||
| 248 | // case Q_TYPE_FSTN: | ||
| 249 | default: | ||
| 250 | ehci_dbg(ehci, | ||
| 251 | "ignoring periodic frame %d FSTN\n", frame); | ||
| 252 | hw_p = &q->fstn->hw_next; | ||
| 253 | q = &q->fstn->fstn_next; | ||
| 254 | } | ||
| 255 | } | ||
| 256 | |||
| 257 | carryover_tt_bandwidth(tt_usecs); | ||
| 258 | |||
| 259 | if (max_tt_usecs[7] < tt_usecs[7]) | ||
| 260 | ehci_err(ehci, "frame %d tt sched overrun: %d usecs\n", | ||
| 261 | frame, tt_usecs[7] - max_tt_usecs[7]); | ||
| 262 | } | ||
| 263 | |||
| 264 | /* | ||
| 265 | * Return true if the device's tt's downstream bus is available for a | ||
| 266 | * periodic transfer of the specified length (usecs), starting at the | ||
| 267 | * specified frame/uframe. Note that (as summarized in section 11.19 | ||
| 268 | * of the usb 2.0 spec) TTs can buffer multiple transactions for each | ||
| 269 | * uframe. | ||
| 270 | * | ||
| 271 | * The uframe parameter is when the fullspeed/lowspeed transfer | ||
| 272 | * should be executed in "B-frame" terms, which is the same as the | ||
| 273 | * highspeed ssplit's uframe (which is in "H-frame" terms). For example | ||
| 274 | * a ssplit in "H-frame" 0 causes a transfer in "B-frame" 0. | ||
| 275 | * See the EHCI spec sec 4.5 and fig 4.7. | ||
| 276 | * | ||
| 277 | * This checks if the full/lowspeed bus, at the specified starting uframe, | ||
| 278 | * has the specified bandwidth available, according to rules listed | ||
| 279 | * in USB 2.0 spec section 11.18.1 fig 11-60. | ||
| 280 | * | ||
| 281 | * This does not check if the transfer would exceed the max ssplit | ||
| 282 | * limit of 16, specified in USB 2.0 spec section 11.18.4 requirement #4, | ||
| 283 | * since proper scheduling limits ssplits to less than 16 per uframe. | ||
| 284 | */ | ||
| 285 | static int tt_available ( | ||
| 286 | struct ehci_hcd *ehci, | ||
| 287 | unsigned period, | ||
| 288 | struct usb_device *dev, | ||
| 289 | unsigned frame, | ||
| 290 | unsigned uframe, | ||
| 291 | u16 usecs | ||
| 292 | ) | ||
| 293 | { | ||
| 294 | if ((period == 0) || (uframe >= 7)) /* error */ | ||
| 295 | return 0; | ||
| 296 | |||
| 297 | for (; frame < ehci->periodic_size; frame += period) { | ||
| 298 | unsigned short tt_usecs[8]; | ||
| 299 | |||
| 300 | periodic_tt_usecs (ehci, dev, frame, tt_usecs); | ||
| 301 | |||
| 302 | ehci_vdbg(ehci, "tt frame %d check %d usecs start uframe %d in" | ||
| 303 | " schedule %d/%d/%d/%d/%d/%d/%d/%d\n", | ||
| 304 | frame, usecs, uframe, | ||
| 305 | tt_usecs[0], tt_usecs[1], tt_usecs[2], tt_usecs[3], | ||
| 306 | tt_usecs[4], tt_usecs[5], tt_usecs[6], tt_usecs[7]); | ||
| 307 | |||
| 308 | if (max_tt_usecs[uframe] <= tt_usecs[uframe]) { | ||
| 309 | ehci_vdbg(ehci, "frame %d uframe %d fully scheduled\n", | ||
| 310 | frame, uframe); | ||
| 311 | return 0; | ||
| 312 | } | ||
| 313 | |||
| 314 | /* special case for isoc transfers larger than 125us: | ||
| 315 | * the first and each subsequent fully used uframe | ||
| 316 | * must be empty, so as to not illegally delay | ||
| 317 | * already scheduled transactions | ||
| 318 | */ | ||
| 319 | if (125 < usecs) { | ||
| 320 | int ufs = (usecs / 125) - 1; | ||
| 321 | int i; | ||
| 322 | for (i = uframe; i < (uframe + ufs) && i < 8; i++) | ||
| 323 | if (0 < tt_usecs[i]) { | ||
| 324 | ehci_vdbg(ehci, | ||
| 325 | "multi-uframe xfer can't fit " | ||
| 326 | "in frame %d uframe %d\n", | ||
| 327 | frame, i); | ||
| 328 | return 0; | ||
| 329 | } | ||
| 330 | } | ||
| 331 | |||
| 332 | tt_usecs[uframe] += usecs; | ||
| 333 | |||
| 334 | carryover_tt_bandwidth(tt_usecs); | ||
| 335 | |||
| 336 | /* fail if the carryover pushed bw past the last uframe's limit */ | ||
| 337 | if (max_tt_usecs[7] < tt_usecs[7]) { | ||
| 338 | ehci_vdbg(ehci, | ||
| 339 | "tt unavailable usecs %d frame %d uframe %d\n", | ||
| 340 | usecs, frame, uframe); | ||
| 341 | return 0; | ||
| 342 | } | ||
| 343 | } | ||
| 344 | |||
| 345 | return 1; | ||
| 346 | } | ||
| 347 | |||
| 348 | #else | ||
| 349 | |||
| 166 | /* return true iff the device's transaction translator is available | 350 | /* return true iff the device's transaction translator is available |
| 167 | * for a periodic transfer starting at the specified frame, using | 351 | * for a periodic transfer starting at the specified frame, using |
| 168 | * all the uframes in the mask. | 352 | * all the uframes in the mask. |
| @@ -237,6 +421,8 @@ static int tt_no_collision ( | |||
| 237 | return 1; | 421 | return 1; |
| 238 | } | 422 | } |
| 239 | 423 | ||
| 424 | #endif /* CONFIG_USB_EHCI_TT_NEWSCHED */ | ||
| 425 | |||
| 240 | /*-------------------------------------------------------------------------*/ | 426 | /*-------------------------------------------------------------------------*/ |
| 241 | 427 | ||
| 242 | static int enable_periodic (struct ehci_hcd *ehci) | 428 | static int enable_periodic (struct ehci_hcd *ehci) |
| @@ -481,7 +667,7 @@ static int check_intr_schedule ( | |||
| 481 | ) | 667 | ) |
| 482 | { | 668 | { |
| 483 | int retval = -ENOSPC; | 669 | int retval = -ENOSPC; |
| 484 | u8 mask; | 670 | u8 mask = 0; |
| 485 | 671 | ||
| 486 | if (qh->c_usecs && uframe >= 6) /* FSTN territory? */ | 672 | if (qh->c_usecs && uframe >= 6) /* FSTN territory? */ |
| 487 | goto done; | 673 | goto done; |
| @@ -494,6 +680,24 @@ static int check_intr_schedule ( | |||
| 494 | goto done; | 680 | goto done; |
| 495 | } | 681 | } |
| 496 | 682 | ||
| 683 | #ifdef CONFIG_USB_EHCI_TT_NEWSCHED | ||
| 684 | if (tt_available (ehci, qh->period, qh->dev, frame, uframe, | ||
| 685 | qh->tt_usecs)) { | ||
| 686 | unsigned i; | ||
| 687 | |||
| 688 | /* TODO : this may need FSTN for SSPLIT in uframe 5. */ | ||
| 689 | for (i=uframe+1; i<8 && i<uframe+4; i++) | ||
| 690 | if (!check_period (ehci, frame, i, | ||
| 691 | qh->period, qh->c_usecs)) | ||
| 692 | goto done; | ||
| 693 | else | ||
| 694 | mask |= 1 << i; | ||
| 695 | |||
| 696 | retval = 0; | ||
| 697 | |||
| 698 | *c_maskp = cpu_to_le32 (mask << 8); | ||
| 699 | } | ||
| 700 | #else | ||
| 497 | /* Make sure this tt's buffer is also available for CSPLITs. | 701 | /* Make sure this tt's buffer is also available for CSPLITs. |
| 498 | * We pessimize a bit; probably the typical full speed case | 702 | * We pessimize a bit; probably the typical full speed case |
| 499 | * doesn't need the second CSPLIT. | 703 | * doesn't need the second CSPLIT. |
| @@ -514,6 +718,7 @@ static int check_intr_schedule ( | |||
| 514 | goto done; | 718 | goto done; |
| 515 | retval = 0; | 719 | retval = 0; |
| 516 | } | 720 | } |
| 721 | #endif | ||
| 517 | done: | 722 | done: |
| 518 | return retval; | 723 | return retval; |
| 519 | } | 724 | } |
| @@ -1047,12 +1252,21 @@ sitd_slot_ok ( | |||
| 1047 | frame = uframe >> 3; | 1252 | frame = uframe >> 3; |
| 1048 | uf = uframe & 7; | 1253 | uf = uframe & 7; |
| 1049 | 1254 | ||
| 1255 | #ifdef CONFIG_USB_EHCI_TT_NEWSCHED | ||
| 1256 | /* The tt's fullspeed bus bandwidth must be available. | ||
| 1257 | * tt_available scheduling guarantees 10+% for control/bulk. | ||
| 1258 | */ | ||
| 1259 | if (!tt_available (ehci, period_uframes << 3, | ||
| 1260 | stream->udev, frame, uf, stream->tt_usecs)) | ||
| 1261 | return 0; | ||
| 1262 | #else | ||
| 1050 | /* tt must be idle for start(s), any gap, and csplit. | 1263 | /* tt must be idle for start(s), any gap, and csplit. |
| 1051 | * assume scheduling slop leaves 10+% for control/bulk. | 1264 | * assume scheduling slop leaves 10+% for control/bulk. |
| 1052 | */ | 1265 | */ |
| 1053 | if (!tt_no_collision (ehci, period_uframes << 3, | 1266 | if (!tt_no_collision (ehci, period_uframes << 3, |
| 1054 | stream->udev, frame, mask)) | 1267 | stream->udev, frame, mask)) |
| 1055 | return 0; | 1268 | return 0; |
| 1269 | #endif | ||
| 1056 | 1270 | ||
| 1057 | /* check starts (OUT uses more than one) */ | 1271 | /* check starts (OUT uses more than one) */ |
| 1058 | max_used = 100 - stream->usecs; | 1272 | max_used = 100 - stream->usecs; |
