diff options
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/host/xhci-hub.c | 126 | ||||
-rw-r--r-- | drivers/usb/host/xhci-ring.c | 22 |
2 files changed, 95 insertions, 53 deletions
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index 847b071b6fc..89ff025b41b 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c | |||
@@ -288,10 +288,18 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, | |||
288 | unsigned long flags; | 288 | unsigned long flags; |
289 | u32 temp, temp1, status; | 289 | u32 temp, temp1, status; |
290 | int retval = 0; | 290 | int retval = 0; |
291 | u32 __iomem *addr; | 291 | u32 __iomem *port_array[15 + USB_MAXCHILDREN]; |
292 | int i; | ||
292 | int slot_id; | 293 | int slot_id; |
293 | 294 | ||
294 | ports = HCS_MAX_PORTS(xhci->hcs_params1); | 295 | ports = HCS_MAX_PORTS(xhci->hcs_params1); |
296 | for (i = 0; i < ports; i++) { | ||
297 | if (i < xhci->num_usb3_ports) | ||
298 | port_array[i] = xhci->usb3_ports[i]; | ||
299 | else | ||
300 | port_array[i] = | ||
301 | xhci->usb2_ports[i - xhci->num_usb3_ports]; | ||
302 | } | ||
295 | 303 | ||
296 | spin_lock_irqsave(&xhci->lock, flags); | 304 | spin_lock_irqsave(&xhci->lock, flags); |
297 | switch (typeReq) { | 305 | switch (typeReq) { |
@@ -307,8 +315,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, | |||
307 | goto error; | 315 | goto error; |
308 | wIndex--; | 316 | wIndex--; |
309 | status = 0; | 317 | status = 0; |
310 | addr = &xhci->op_regs->port_status_base + NUM_PORT_REGS*(wIndex & 0xff); | 318 | temp = xhci_readl(xhci, port_array[wIndex]); |
311 | temp = xhci_readl(xhci, addr); | ||
312 | xhci_dbg(xhci, "get port status, actual port %d status = 0x%x\n", wIndex, temp); | 319 | xhci_dbg(xhci, "get port status, actual port %d status = 0x%x\n", wIndex, temp); |
313 | 320 | ||
314 | /* wPortChange bits */ | 321 | /* wPortChange bits */ |
@@ -336,7 +343,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, | |||
336 | temp1 = xhci_port_state_to_neutral(temp); | 343 | temp1 = xhci_port_state_to_neutral(temp); |
337 | temp1 &= ~PORT_PLS_MASK; | 344 | temp1 &= ~PORT_PLS_MASK; |
338 | temp1 |= PORT_LINK_STROBE | XDEV_U0; | 345 | temp1 |= PORT_LINK_STROBE | XDEV_U0; |
339 | xhci_writel(xhci, temp1, addr); | 346 | xhci_writel(xhci, temp1, port_array[wIndex]); |
340 | 347 | ||
341 | xhci_dbg(xhci, "set port %d resume\n", | 348 | xhci_dbg(xhci, "set port %d resume\n", |
342 | wIndex + 1); | 349 | wIndex + 1); |
@@ -379,12 +386,11 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, | |||
379 | if (!wIndex || wIndex > ports) | 386 | if (!wIndex || wIndex > ports) |
380 | goto error; | 387 | goto error; |
381 | wIndex--; | 388 | wIndex--; |
382 | addr = &xhci->op_regs->port_status_base + NUM_PORT_REGS*(wIndex & 0xff); | 389 | temp = xhci_readl(xhci, port_array[wIndex]); |
383 | temp = xhci_readl(xhci, addr); | ||
384 | temp = xhci_port_state_to_neutral(temp); | 390 | temp = xhci_port_state_to_neutral(temp); |
385 | switch (wValue) { | 391 | switch (wValue) { |
386 | case USB_PORT_FEAT_SUSPEND: | 392 | case USB_PORT_FEAT_SUSPEND: |
387 | temp = xhci_readl(xhci, addr); | 393 | temp = xhci_readl(xhci, port_array[wIndex]); |
388 | /* In spec software should not attempt to suspend | 394 | /* In spec software should not attempt to suspend |
389 | * a port unless the port reports that it is in the | 395 | * a port unless the port reports that it is in the |
390 | * enabled (PED = ‘1’,PLS < ‘3’) state. | 396 | * enabled (PED = ‘1’,PLS < ‘3’) state. |
@@ -409,13 +415,13 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, | |||
409 | temp = xhci_port_state_to_neutral(temp); | 415 | temp = xhci_port_state_to_neutral(temp); |
410 | temp &= ~PORT_PLS_MASK; | 416 | temp &= ~PORT_PLS_MASK; |
411 | temp |= PORT_LINK_STROBE | XDEV_U3; | 417 | temp |= PORT_LINK_STROBE | XDEV_U3; |
412 | xhci_writel(xhci, temp, addr); | 418 | xhci_writel(xhci, temp, port_array[wIndex]); |
413 | 419 | ||
414 | spin_unlock_irqrestore(&xhci->lock, flags); | 420 | spin_unlock_irqrestore(&xhci->lock, flags); |
415 | msleep(10); /* wait device to enter */ | 421 | msleep(10); /* wait device to enter */ |
416 | spin_lock_irqsave(&xhci->lock, flags); | 422 | spin_lock_irqsave(&xhci->lock, flags); |
417 | 423 | ||
418 | temp = xhci_readl(xhci, addr); | 424 | temp = xhci_readl(xhci, port_array[wIndex]); |
419 | xhci->suspended_ports |= 1 << wIndex; | 425 | xhci->suspended_ports |= 1 << wIndex; |
420 | break; | 426 | break; |
421 | case USB_PORT_FEAT_POWER: | 427 | case USB_PORT_FEAT_POWER: |
@@ -425,34 +431,34 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, | |||
425 | * However, khubd will ignore the roothub events until | 431 | * However, khubd will ignore the roothub events until |
426 | * the roothub is registered. | 432 | * the roothub is registered. |
427 | */ | 433 | */ |
428 | xhci_writel(xhci, temp | PORT_POWER, addr); | 434 | xhci_writel(xhci, temp | PORT_POWER, |
435 | port_array[wIndex]); | ||
429 | 436 | ||
430 | temp = xhci_readl(xhci, addr); | 437 | temp = xhci_readl(xhci, port_array[wIndex]); |
431 | xhci_dbg(xhci, "set port power, actual port %d status = 0x%x\n", wIndex, temp); | 438 | xhci_dbg(xhci, "set port power, actual port %d status = 0x%x\n", wIndex, temp); |
432 | break; | 439 | break; |
433 | case USB_PORT_FEAT_RESET: | 440 | case USB_PORT_FEAT_RESET: |
434 | temp = (temp | PORT_RESET); | 441 | temp = (temp | PORT_RESET); |
435 | xhci_writel(xhci, temp, addr); | 442 | xhci_writel(xhci, temp, port_array[wIndex]); |
436 | 443 | ||
437 | temp = xhci_readl(xhci, addr); | 444 | temp = xhci_readl(xhci, port_array[wIndex]); |
438 | xhci_dbg(xhci, "set port reset, actual port %d status = 0x%x\n", wIndex, temp); | 445 | xhci_dbg(xhci, "set port reset, actual port %d status = 0x%x\n", wIndex, temp); |
439 | break; | 446 | break; |
440 | default: | 447 | default: |
441 | goto error; | 448 | goto error; |
442 | } | 449 | } |
443 | temp = xhci_readl(xhci, addr); /* unblock any posted writes */ | 450 | /* unblock any posted writes */ |
451 | temp = xhci_readl(xhci, port_array[wIndex]); | ||
444 | break; | 452 | break; |
445 | case ClearPortFeature: | 453 | case ClearPortFeature: |
446 | if (!wIndex || wIndex > ports) | 454 | if (!wIndex || wIndex > ports) |
447 | goto error; | 455 | goto error; |
448 | wIndex--; | 456 | wIndex--; |
449 | addr = &xhci->op_regs->port_status_base + | 457 | temp = xhci_readl(xhci, port_array[wIndex]); |
450 | NUM_PORT_REGS*(wIndex & 0xff); | ||
451 | temp = xhci_readl(xhci, addr); | ||
452 | temp = xhci_port_state_to_neutral(temp); | 458 | temp = xhci_port_state_to_neutral(temp); |
453 | switch (wValue) { | 459 | switch (wValue) { |
454 | case USB_PORT_FEAT_SUSPEND: | 460 | case USB_PORT_FEAT_SUSPEND: |
455 | temp = xhci_readl(xhci, addr); | 461 | temp = xhci_readl(xhci, port_array[wIndex]); |
456 | xhci_dbg(xhci, "clear USB_PORT_FEAT_SUSPEND\n"); | 462 | xhci_dbg(xhci, "clear USB_PORT_FEAT_SUSPEND\n"); |
457 | xhci_dbg(xhci, "PORTSC %04x\n", temp); | 463 | xhci_dbg(xhci, "PORTSC %04x\n", temp); |
458 | if (temp & PORT_RESET) | 464 | if (temp & PORT_RESET) |
@@ -464,24 +470,28 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, | |||
464 | temp = xhci_port_state_to_neutral(temp); | 470 | temp = xhci_port_state_to_neutral(temp); |
465 | temp &= ~PORT_PLS_MASK; | 471 | temp &= ~PORT_PLS_MASK; |
466 | temp |= PORT_LINK_STROBE | XDEV_U0; | 472 | temp |= PORT_LINK_STROBE | XDEV_U0; |
467 | xhci_writel(xhci, temp, addr); | 473 | xhci_writel(xhci, temp, |
468 | xhci_readl(xhci, addr); | 474 | port_array[wIndex]); |
475 | xhci_readl(xhci, port_array[wIndex]); | ||
469 | } else { | 476 | } else { |
470 | temp = xhci_port_state_to_neutral(temp); | 477 | temp = xhci_port_state_to_neutral(temp); |
471 | temp &= ~PORT_PLS_MASK; | 478 | temp &= ~PORT_PLS_MASK; |
472 | temp |= PORT_LINK_STROBE | XDEV_RESUME; | 479 | temp |= PORT_LINK_STROBE | XDEV_RESUME; |
473 | xhci_writel(xhci, temp, addr); | 480 | xhci_writel(xhci, temp, |
481 | port_array[wIndex]); | ||
474 | 482 | ||
475 | spin_unlock_irqrestore(&xhci->lock, | 483 | spin_unlock_irqrestore(&xhci->lock, |
476 | flags); | 484 | flags); |
477 | msleep(20); | 485 | msleep(20); |
478 | spin_lock_irqsave(&xhci->lock, flags); | 486 | spin_lock_irqsave(&xhci->lock, flags); |
479 | 487 | ||
480 | temp = xhci_readl(xhci, addr); | 488 | temp = xhci_readl(xhci, |
489 | port_array[wIndex]); | ||
481 | temp = xhci_port_state_to_neutral(temp); | 490 | temp = xhci_port_state_to_neutral(temp); |
482 | temp &= ~PORT_PLS_MASK; | 491 | temp &= ~PORT_PLS_MASK; |
483 | temp |= PORT_LINK_STROBE | XDEV_U0; | 492 | temp |= PORT_LINK_STROBE | XDEV_U0; |
484 | xhci_writel(xhci, temp, addr); | 493 | xhci_writel(xhci, temp, |
494 | port_array[wIndex]); | ||
485 | } | 495 | } |
486 | xhci->port_c_suspend |= 1 << wIndex; | 496 | xhci->port_c_suspend |= 1 << wIndex; |
487 | } | 497 | } |
@@ -500,10 +510,11 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, | |||
500 | case USB_PORT_FEAT_C_OVER_CURRENT: | 510 | case USB_PORT_FEAT_C_OVER_CURRENT: |
501 | case USB_PORT_FEAT_C_ENABLE: | 511 | case USB_PORT_FEAT_C_ENABLE: |
502 | xhci_clear_port_change_bit(xhci, wValue, wIndex, | 512 | xhci_clear_port_change_bit(xhci, wValue, wIndex, |
503 | addr, temp); | 513 | port_array[wIndex], temp); |
504 | break; | 514 | break; |
505 | case USB_PORT_FEAT_ENABLE: | 515 | case USB_PORT_FEAT_ENABLE: |
506 | xhci_disable_port(xhci, wIndex, addr, temp); | 516 | xhci_disable_port(xhci, wIndex, |
517 | port_array[wIndex], temp); | ||
507 | break; | 518 | break; |
508 | default: | 519 | default: |
509 | goto error; | 520 | goto error; |
@@ -534,9 +545,16 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf) | |||
534 | int i, retval; | 545 | int i, retval; |
535 | struct xhci_hcd *xhci = hcd_to_xhci(hcd); | 546 | struct xhci_hcd *xhci = hcd_to_xhci(hcd); |
536 | int ports; | 547 | int ports; |
537 | u32 __iomem *addr; | 548 | u32 __iomem *port_array[15 + USB_MAXCHILDREN]; |
538 | 549 | ||
539 | ports = HCS_MAX_PORTS(xhci->hcs_params1); | 550 | ports = HCS_MAX_PORTS(xhci->hcs_params1); |
551 | for (i = 0; i < ports; i++) { | ||
552 | if (i < xhci->num_usb3_ports) | ||
553 | port_array[i] = xhci->usb3_ports[i]; | ||
554 | else | ||
555 | port_array[i] = | ||
556 | xhci->usb2_ports[i - xhci->num_usb3_ports]; | ||
557 | } | ||
540 | 558 | ||
541 | /* Initial status is no changes */ | 559 | /* Initial status is no changes */ |
542 | retval = (ports + 8) / 8; | 560 | retval = (ports + 8) / 8; |
@@ -548,9 +566,7 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf) | |||
548 | spin_lock_irqsave(&xhci->lock, flags); | 566 | spin_lock_irqsave(&xhci->lock, flags); |
549 | /* For each port, did anything change? If so, set that bit in buf. */ | 567 | /* For each port, did anything change? If so, set that bit in buf. */ |
550 | for (i = 0; i < ports; i++) { | 568 | for (i = 0; i < ports; i++) { |
551 | addr = &xhci->op_regs->port_status_base + | 569 | temp = xhci_readl(xhci, port_array[i]); |
552 | NUM_PORT_REGS*i; | ||
553 | temp = xhci_readl(xhci, addr); | ||
554 | if ((temp & mask) != 0 || | 570 | if ((temp & mask) != 0 || |
555 | (xhci->port_c_suspend & 1 << i) || | 571 | (xhci->port_c_suspend & 1 << i) || |
556 | (xhci->resume_done[i] && time_after_eq( | 572 | (xhci->resume_done[i] && time_after_eq( |
@@ -569,10 +585,19 @@ int xhci_bus_suspend(struct usb_hcd *hcd) | |||
569 | { | 585 | { |
570 | struct xhci_hcd *xhci = hcd_to_xhci(hcd); | 586 | struct xhci_hcd *xhci = hcd_to_xhci(hcd); |
571 | int max_ports, port_index; | 587 | int max_ports, port_index; |
588 | u32 __iomem *port_array[15 + USB_MAXCHILDREN]; | ||
589 | int i; | ||
572 | unsigned long flags; | 590 | unsigned long flags; |
573 | 591 | ||
574 | xhci_dbg(xhci, "suspend root hub\n"); | 592 | xhci_dbg(xhci, "suspend root hub\n"); |
575 | max_ports = HCS_MAX_PORTS(xhci->hcs_params1); | 593 | max_ports = HCS_MAX_PORTS(xhci->hcs_params1); |
594 | for (i = 0; i < max_ports; i++) { | ||
595 | if (i < xhci->num_usb3_ports) | ||
596 | port_array[i] = xhci->usb3_ports[i]; | ||
597 | else | ||
598 | port_array[i] = | ||
599 | xhci->usb2_ports[i - xhci->num_usb3_ports]; | ||
600 | } | ||
576 | 601 | ||
577 | spin_lock_irqsave(&xhci->lock, flags); | 602 | spin_lock_irqsave(&xhci->lock, flags); |
578 | 603 | ||
@@ -593,13 +618,10 @@ int xhci_bus_suspend(struct usb_hcd *hcd) | |||
593 | xhci->bus_suspended = 0; | 618 | xhci->bus_suspended = 0; |
594 | while (port_index--) { | 619 | while (port_index--) { |
595 | /* suspend the port if the port is not suspended */ | 620 | /* suspend the port if the port is not suspended */ |
596 | u32 __iomem *addr; | ||
597 | u32 t1, t2; | 621 | u32 t1, t2; |
598 | int slot_id; | 622 | int slot_id; |
599 | 623 | ||
600 | addr = &xhci->op_regs->port_status_base + | 624 | t1 = xhci_readl(xhci, port_array[port_index]); |
601 | NUM_PORT_REGS * (port_index & 0xff); | ||
602 | t1 = xhci_readl(xhci, addr); | ||
603 | t2 = xhci_port_state_to_neutral(t1); | 625 | t2 = xhci_port_state_to_neutral(t1); |
604 | 626 | ||
605 | if ((t1 & PORT_PE) && !(t1 & PORT_PLS_MASK)) { | 627 | if ((t1 & PORT_PE) && !(t1 & PORT_PLS_MASK)) { |
@@ -628,15 +650,17 @@ int xhci_bus_suspend(struct usb_hcd *hcd) | |||
628 | 650 | ||
629 | t1 = xhci_port_state_to_neutral(t1); | 651 | t1 = xhci_port_state_to_neutral(t1); |
630 | if (t1 != t2) | 652 | if (t1 != t2) |
631 | xhci_writel(xhci, t2, addr); | 653 | xhci_writel(xhci, t2, port_array[port_index]); |
632 | 654 | ||
633 | if (DEV_HIGHSPEED(t1)) { | 655 | if (DEV_HIGHSPEED(t1)) { |
634 | /* enable remote wake up for USB 2.0 */ | 656 | /* enable remote wake up for USB 2.0 */ |
635 | u32 __iomem *addr; | 657 | u32 __iomem *addr; |
636 | u32 tmp; | 658 | u32 tmp; |
637 | 659 | ||
638 | addr = &xhci->op_regs->port_power_base + | 660 | /* Add one to the port status register address to get |
639 | NUM_PORT_REGS * (port_index & 0xff); | 661 | * the port power control register address. |
662 | */ | ||
663 | addr = port_array[port_index] + 1; | ||
640 | tmp = xhci_readl(xhci, addr); | 664 | tmp = xhci_readl(xhci, addr); |
641 | tmp |= PORT_RWE; | 665 | tmp |= PORT_RWE; |
642 | xhci_writel(xhci, tmp, addr); | 666 | xhci_writel(xhci, tmp, addr); |
@@ -652,11 +676,20 @@ int xhci_bus_resume(struct usb_hcd *hcd) | |||
652 | { | 676 | { |
653 | struct xhci_hcd *xhci = hcd_to_xhci(hcd); | 677 | struct xhci_hcd *xhci = hcd_to_xhci(hcd); |
654 | int max_ports, port_index; | 678 | int max_ports, port_index; |
679 | u32 __iomem *port_array[15 + USB_MAXCHILDREN]; | ||
680 | int i; | ||
655 | u32 temp; | 681 | u32 temp; |
656 | unsigned long flags; | 682 | unsigned long flags; |
657 | 683 | ||
658 | xhci_dbg(xhci, "resume root hub\n"); | 684 | xhci_dbg(xhci, "resume root hub\n"); |
659 | max_ports = HCS_MAX_PORTS(xhci->hcs_params1); | 685 | max_ports = HCS_MAX_PORTS(xhci->hcs_params1); |
686 | for (i = 0; i < max_ports; i++) { | ||
687 | if (i < xhci->num_usb3_ports) | ||
688 | port_array[i] = xhci->usb3_ports[i]; | ||
689 | else | ||
690 | port_array[i] = | ||
691 | xhci->usb2_ports[i - xhci->num_usb3_ports]; | ||
692 | } | ||
660 | 693 | ||
661 | if (time_before(jiffies, xhci->next_statechange)) | 694 | if (time_before(jiffies, xhci->next_statechange)) |
662 | msleep(5); | 695 | msleep(5); |
@@ -676,13 +709,10 @@ int xhci_bus_resume(struct usb_hcd *hcd) | |||
676 | while (port_index--) { | 709 | while (port_index--) { |
677 | /* Check whether need resume ports. If needed | 710 | /* Check whether need resume ports. If needed |
678 | resume port and disable remote wakeup */ | 711 | resume port and disable remote wakeup */ |
679 | u32 __iomem *addr; | ||
680 | u32 temp; | 712 | u32 temp; |
681 | int slot_id; | 713 | int slot_id; |
682 | 714 | ||
683 | addr = &xhci->op_regs->port_status_base + | 715 | temp = xhci_readl(xhci, port_array[port_index]); |
684 | NUM_PORT_REGS * (port_index & 0xff); | ||
685 | temp = xhci_readl(xhci, addr); | ||
686 | if (DEV_SUPERSPEED(temp)) | 716 | if (DEV_SUPERSPEED(temp)) |
687 | temp &= ~(PORT_RWC_BITS | PORT_CEC | PORT_WAKE_BITS); | 717 | temp &= ~(PORT_RWC_BITS | PORT_CEC | PORT_WAKE_BITS); |
688 | else | 718 | else |
@@ -693,36 +723,38 @@ int xhci_bus_resume(struct usb_hcd *hcd) | |||
693 | temp = xhci_port_state_to_neutral(temp); | 723 | temp = xhci_port_state_to_neutral(temp); |
694 | temp &= ~PORT_PLS_MASK; | 724 | temp &= ~PORT_PLS_MASK; |
695 | temp |= PORT_LINK_STROBE | XDEV_U0; | 725 | temp |= PORT_LINK_STROBE | XDEV_U0; |
696 | xhci_writel(xhci, temp, addr); | 726 | xhci_writel(xhci, temp, port_array[port_index]); |
697 | } else { | 727 | } else { |
698 | temp = xhci_port_state_to_neutral(temp); | 728 | temp = xhci_port_state_to_neutral(temp); |
699 | temp &= ~PORT_PLS_MASK; | 729 | temp &= ~PORT_PLS_MASK; |
700 | temp |= PORT_LINK_STROBE | XDEV_RESUME; | 730 | temp |= PORT_LINK_STROBE | XDEV_RESUME; |
701 | xhci_writel(xhci, temp, addr); | 731 | xhci_writel(xhci, temp, port_array[port_index]); |
702 | 732 | ||
703 | spin_unlock_irqrestore(&xhci->lock, flags); | 733 | spin_unlock_irqrestore(&xhci->lock, flags); |
704 | msleep(20); | 734 | msleep(20); |
705 | spin_lock_irqsave(&xhci->lock, flags); | 735 | spin_lock_irqsave(&xhci->lock, flags); |
706 | 736 | ||
707 | temp = xhci_readl(xhci, addr); | 737 | temp = xhci_readl(xhci, port_array[port_index]); |
708 | temp = xhci_port_state_to_neutral(temp); | 738 | temp = xhci_port_state_to_neutral(temp); |
709 | temp &= ~PORT_PLS_MASK; | 739 | temp &= ~PORT_PLS_MASK; |
710 | temp |= PORT_LINK_STROBE | XDEV_U0; | 740 | temp |= PORT_LINK_STROBE | XDEV_U0; |
711 | xhci_writel(xhci, temp, addr); | 741 | xhci_writel(xhci, temp, port_array[port_index]); |
712 | } | 742 | } |
713 | slot_id = xhci_find_slot_id_by_port(xhci, port_index + 1); | 743 | slot_id = xhci_find_slot_id_by_port(xhci, port_index + 1); |
714 | if (slot_id) | 744 | if (slot_id) |
715 | xhci_ring_device(xhci, slot_id); | 745 | xhci_ring_device(xhci, slot_id); |
716 | } else | 746 | } else |
717 | xhci_writel(xhci, temp, addr); | 747 | xhci_writel(xhci, temp, port_array[port_index]); |
718 | 748 | ||
719 | if (DEV_HIGHSPEED(temp)) { | 749 | if (DEV_HIGHSPEED(temp)) { |
720 | /* disable remote wake up for USB 2.0 */ | 750 | /* disable remote wake up for USB 2.0 */ |
721 | u32 __iomem *addr; | 751 | u32 __iomem *addr; |
722 | u32 tmp; | 752 | u32 tmp; |
723 | 753 | ||
724 | addr = &xhci->op_regs->port_power_base + | 754 | /* Add one to the port status register address to get |
725 | NUM_PORT_REGS * (port_index & 0xff); | 755 | * the port power control register address. |
756 | */ | ||
757 | addr = port_array[port_index] + 1; | ||
726 | tmp = xhci_readl(xhci, addr); | 758 | tmp = xhci_readl(xhci, addr); |
727 | tmp &= ~PORT_RWE; | 759 | tmp &= ~PORT_RWE; |
728 | xhci_writel(xhci, tmp, addr); | 760 | xhci_writel(xhci, tmp, addr); |
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 47763bed378..582537689eb 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c | |||
@@ -1161,9 +1161,11 @@ static void handle_port_status(struct xhci_hcd *xhci, | |||
1161 | struct usb_hcd *hcd = xhci_to_hcd(xhci); | 1161 | struct usb_hcd *hcd = xhci_to_hcd(xhci); |
1162 | u32 port_id; | 1162 | u32 port_id; |
1163 | u32 temp, temp1; | 1163 | u32 temp, temp1; |
1164 | u32 __iomem *addr; | ||
1165 | int max_ports; | 1164 | int max_ports; |
1166 | int slot_id; | 1165 | int slot_id; |
1166 | unsigned int faked_port_index; | ||
1167 | u32 __iomem *port_array[15 + USB_MAXCHILDREN]; | ||
1168 | int i; | ||
1167 | 1169 | ||
1168 | /* Port status change events always have a successful completion code */ | 1170 | /* Port status change events always have a successful completion code */ |
1169 | if (GET_COMP_CODE(event->generic.field[2]) != COMP_SUCCESS) { | 1171 | if (GET_COMP_CODE(event->generic.field[2]) != COMP_SUCCESS) { |
@@ -1179,8 +1181,16 @@ static void handle_port_status(struct xhci_hcd *xhci, | |||
1179 | goto cleanup; | 1181 | goto cleanup; |
1180 | } | 1182 | } |
1181 | 1183 | ||
1182 | addr = &xhci->op_regs->port_status_base + NUM_PORT_REGS * (port_id - 1); | 1184 | for (i = 0; i < max_ports; i++) { |
1183 | temp = xhci_readl(xhci, addr); | 1185 | if (i < xhci->num_usb3_ports) |
1186 | port_array[i] = xhci->usb3_ports[i]; | ||
1187 | else | ||
1188 | port_array[i] = | ||
1189 | xhci->usb2_ports[i - xhci->num_usb3_ports]; | ||
1190 | } | ||
1191 | |||
1192 | faked_port_index = port_id; | ||
1193 | temp = xhci_readl(xhci, port_array[faked_port_index]); | ||
1184 | if (hcd->state == HC_STATE_SUSPENDED) { | 1194 | if (hcd->state == HC_STATE_SUSPENDED) { |
1185 | xhci_dbg(xhci, "resume root hub\n"); | 1195 | xhci_dbg(xhci, "resume root hub\n"); |
1186 | usb_hcd_resume_root_hub(hcd); | 1196 | usb_hcd_resume_root_hub(hcd); |
@@ -1200,7 +1210,7 @@ static void handle_port_status(struct xhci_hcd *xhci, | |||
1200 | temp = xhci_port_state_to_neutral(temp); | 1210 | temp = xhci_port_state_to_neutral(temp); |
1201 | temp &= ~PORT_PLS_MASK; | 1211 | temp &= ~PORT_PLS_MASK; |
1202 | temp |= PORT_LINK_STROBE | XDEV_U0; | 1212 | temp |= PORT_LINK_STROBE | XDEV_U0; |
1203 | xhci_writel(xhci, temp, addr); | 1213 | xhci_writel(xhci, temp, port_array[faked_port_index]); |
1204 | slot_id = xhci_find_slot_id_by_port(xhci, port_id); | 1214 | slot_id = xhci_find_slot_id_by_port(xhci, port_id); |
1205 | if (!slot_id) { | 1215 | if (!slot_id) { |
1206 | xhci_dbg(xhci, "slot_id is zero\n"); | 1216 | xhci_dbg(xhci, "slot_id is zero\n"); |
@@ -1209,10 +1219,10 @@ static void handle_port_status(struct xhci_hcd *xhci, | |||
1209 | xhci_ring_device(xhci, slot_id); | 1219 | xhci_ring_device(xhci, slot_id); |
1210 | xhci_dbg(xhci, "resume SS port %d finished\n", port_id); | 1220 | xhci_dbg(xhci, "resume SS port %d finished\n", port_id); |
1211 | /* Clear PORT_PLC */ | 1221 | /* Clear PORT_PLC */ |
1212 | temp = xhci_readl(xhci, addr); | 1222 | temp = xhci_readl(xhci, port_array[faked_port_index]); |
1213 | temp = xhci_port_state_to_neutral(temp); | 1223 | temp = xhci_port_state_to_neutral(temp); |
1214 | temp |= PORT_PLC; | 1224 | temp |= PORT_PLC; |
1215 | xhci_writel(xhci, temp, addr); | 1225 | xhci_writel(xhci, temp, port_array[faked_port_index]); |
1216 | } else { | 1226 | } else { |
1217 | xhci_dbg(xhci, "resume HS port %d\n", port_id); | 1227 | xhci_dbg(xhci, "resume HS port %d\n", port_id); |
1218 | xhci->resume_done[port_id - 1] = jiffies + | 1228 | xhci->resume_done[port_id - 1] = jiffies + |