This is a great job, the putback fixed the Solaris EHCI idle power problem and
hence filled the ~30W idle power gap between other OSes.

Cheers,
-Aubrey

> http://opensolaris-hg-server.bj.intel.com:8000/onnv-gate/rev/bcfc9c7baa2e
> changeset: 12733:bcfc9c7baa2e
> user:      Raymond Chen <[email protected]>
> date:      Wed Jun 30 17:40:22 2010 +0800
> description:
> 6948314 DMA activities from USB host controller throttle some processor's
> package C-state
> 
> diffstat:
> 
> 4 files changed, 100 insertions(+), 25 deletions(-)
> usr/src/uts/common/io/usb/hcd/ehci/ehci_isoch_util.c |   11 +-
> usr/src/uts/common/io/usb/hcd/ehci/ehci_util.c       |   78
> +++++++++++++++---
> usr/src/uts/common/io/usb/hcd/ehci/ehci_xfer.c       |   29 +++++-
> usr/src/uts/common/sys/usb/hcd/ehci/ehcid.h          |    7 +
> 
> diffs (288 lines):
> 
> diff -r 6031bb35a0c5 -r bcfc9c7baa2e
> usr/src/uts/common/io/usb/hcd/ehci/ehci_isoch_util.c
> --- a/usr/src/uts/common/io/usb/hcd/ehci/ehci_isoch_util.c    Wed Jun 30
> 10:31:31 2010 +0800
> +++ b/usr/src/uts/common/io/usb/hcd/ehci/ehci_isoch_util.c    Wed Jun 30
> 17:40:22 2010 +0800
> @@ -18,12 +18,11 @@
>   *
>   * CDDL HEADER END
>   */
> +
>  /*
> - * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
> - * Use is subject to license terms.
> + * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights 
> reserved.
>   */
> 
> -
>  /*
>   * EHCI Host Controller Driver (EHCI)
>   *
> @@ -493,6 +492,9 @@ ehci_allocate_itw(
>           "ehci_create_itw: itw = 0x%p real_length = 0x%lx",
>           (void *)itw, real_length);
> 
> +     ehcip->ehci_periodic_req_count++;
> +     ehci_toggle_scheduler(ehcip);
> +
>       return (itw);
>  }
> 
> @@ -563,6 +565,9 @@ ehci_deallocate_itw(
> 
>       /* Free this iTWs dma resources */
>       ehci_free_itw_dma(ehcip, pp, itw);
> +
> +     ehcip->ehci_periodic_req_count--;
> +     ehci_toggle_scheduler(ehcip);
>  }
> 
> 
> diff -r 6031bb35a0c5 -r bcfc9c7baa2e
> usr/src/uts/common/io/usb/hcd/ehci/ehci_util.c
> --- a/usr/src/uts/common/io/usb/hcd/ehci/ehci_util.c  Wed Jun 30 10:31:31
> 2010 +0800
> +++ b/usr/src/uts/common/io/usb/hcd/ehci/ehci_util.c  Wed Jun 30
> 17:40:22 2010 +0800
> @@ -18,9 +18,9 @@
>   *
>   * CDDL HEADER END
>   */
> -/*
> - * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
> - * Use is subject to license terms.
> +
> +/*
> + * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights 
> reserved.
>   */
> 
> 
> @@ -1095,6 +1095,7 @@ ehci_init_hardware(ehci_state_t *ehcip)
> 
>                       ehcip->ehci_head_of_async_sched_list = dummy_async_qh;
>                       ehcip->ehci_open_async_count++;
> +                     ehcip->ehci_async_req_count++;
>               }
>       }
> 
> @@ -4013,9 +4014,32 @@ ehci_wait_for_sof(ehci_state_t *ehcip)
>   * Turn scheduler based on pipe open count.
>   */
>  void
> -ehci_toggle_scheduler(ehci_state_t *ehcip) {
> +ehci_toggle_scheduler(ehci_state_t *ehcip)
> +{
>       uint_t  temp_reg, cmd_reg;
> 
> +     /*
> +      * For performance optimization, we need to change the bits
> +      * if (async == 1||async == 0) OR (periodic == 1||periodic == 0)
> +      *
> +      * Related bits already enabled if
> +      *      async and periodic req counts are > 1
> +      *      OR async req count > 1 & no periodic pipe
> +      *      OR periodic req count > 1 & no async pipe
> +      */
> +     if (((ehcip->ehci_async_req_count > 1) &&
> +         (ehcip->ehci_periodic_req_count > 1)) ||
> +         ((ehcip->ehci_async_req_count > 1) &&
> +         (ehcip->ehci_open_periodic_count == 0)) ||
> +         ((ehcip->ehci_periodic_req_count > 1) &&
> +         (ehcip->ehci_open_async_count == 0))) {
> +             USB_DPRINTF_L4(PRINT_MASK_ATTA,
> +                 ehcip->ehci_log_hdl, "ehci_toggle_scheduler:"
> +                 "async/periodic bits no need to change");
> +
> +             return;
> +     }
> +
>       cmd_reg = Get_OpReg(ehci_command);
>       temp_reg = cmd_reg;
> 
> @@ -4023,15 +4047,25 @@ ehci_toggle_scheduler(ehci_state_t *ehci
>        * Enable/Disable asynchronous scheduler, and
>        * turn on/off async list door bell
>        */
> -     if (ehcip->ehci_open_async_count) {
> +     if (ehcip->ehci_async_req_count > 1) {
> +             /* we already enable the async bit */
> +             USB_DPRINTF_L4(PRINT_MASK_ATTA,
> +                 ehcip->ehci_log_hdl, "ehci_toggle_scheduler:"
> +                 "async bit already enabled: cmd_reg=0x%x", cmd_reg);
> +     } else if (ehcip->ehci_async_req_count == 1) {
>               if (!(cmd_reg & EHCI_CMD_ASYNC_SCHED_ENABLE)) {
>                       /*
>                        * For some reason this address might get nulled out by
>                        * the ehci chip. Set it here just in case it is null.
> -                      */
> -                     Set_OpReg(ehci_async_list_addr,
> -                         ehci_qh_cpu_to_iommu(ehcip,
> -                             ehcip->ehci_head_of_async_sched_list));
> +                      * If it's not null, we should not reset the
> +                      * ASYNCLISTADDR, because it's updated by hardware to
> +                      * point to the next queue head to be executed.
> +                      */
> +                     if (!Get_OpReg(ehci_async_list_addr)) {
> +                             Set_OpReg(ehci_async_list_addr,
> +                                 ehci_qh_cpu_to_iommu(ehcip,
> +                                 ehcip->ehci_head_of_async_sched_list));
> +                     }
> 
>                       /*
>                        * For some reason this register might get nulled out by
> @@ -4065,10 +4099,10 @@ ehci_toggle_scheduler(ehci_state_t *ehci
>                                           "ehci_toggle_scheduler: "
>                                           "ASYNCLISTADDR write failed.");
> 
> -                             USB_DPRINTF_L2(PRINT_MASK_ATTA,
> +                             USB_DPRINTF_L3(PRINT_MASK_ATTA,
>                                   ehcip->ehci_log_hdl,
>                                   "ehci_toggle_scheduler: ASYNCLISTADDR "
> -                                     "write failed, retry=%d", retry);
> +                                 "write failed, retry=%d", retry);
>                       }
>               }
>               cmd_reg |= EHCI_CMD_ASYNC_SCHED_ENABLE;
> @@ -4076,7 +4110,12 @@ ehci_toggle_scheduler(ehci_state_t *ehci
>               cmd_reg &= ~EHCI_CMD_ASYNC_SCHED_ENABLE;
>       }
> 
> -     if (ehcip->ehci_open_periodic_count) {
> +     if (ehcip->ehci_periodic_req_count > 1) {
> +             /* we already enable the periodic bit. */
> +             USB_DPRINTF_L4(PRINT_MASK_ATTA,
> +                 ehcip->ehci_log_hdl, "ehci_toggle_scheduler:"
> +                 "periodic bit already enabled: cmd_reg=0x%x", cmd_reg);
> +     } else if (ehcip->ehci_periodic_req_count == 1) {
>               if (!(cmd_reg & EHCI_CMD_PERIODIC_SCHED_ENABLE)) {
>                       /*
>                        * For some reason this address get's nulled out by
> @@ -4084,7 +4123,7 @@ ehci_toggle_scheduler(ehci_state_t *ehci
>                        */
>                       Set_OpReg(ehci_periodic_list_base,
>                           (uint32_t)(ehcip->ehci_pflt_cookie.dmac_address &
> -                             0xFFFFF000));
> +                         0xFFFFF000));
>               }
>               cmd_reg |= EHCI_CMD_PERIODIC_SCHED_ENABLE;
>       } else {
> @@ -4094,6 +4133,19 @@ ehci_toggle_scheduler(ehci_state_t *ehci
>       /* Just an optimization */
>       if (temp_reg != cmd_reg) {
>               Set_OpReg(ehci_command, cmd_reg);
> +
> +             /* To make sure the command register is updated correctly */
> +             if ((ehcip->ehci_vendor_id == PCI_VENDOR_ULi_M1575) &&
> +                 (ehcip->ehci_device_id == PCI_DEVICE_ULi_M1575)) {
> +                     int retry = 0;
> +
> +                     Set_OpRegRetry(ehci_command, cmd_reg, retry);
> +                     USB_DPRINTF_L3(PRINT_MASK_ATTA,
> +                         ehcip->ehci_log_hdl,
> +                         "ehci_toggle_scheduler: CMD write failed, retry=%d",
> +                         retry);
> +             }
> +
>       }
>  }
> 
> diff -r 6031bb35a0c5 -r bcfc9c7baa2e
> usr/src/uts/common/io/usb/hcd/ehci/ehci_xfer.c
> --- a/usr/src/uts/common/io/usb/hcd/ehci/ehci_xfer.c  Wed Jun 30 10:31:31
> 2010 +0800
> +++ b/usr/src/uts/common/io/usb/hcd/ehci/ehci_xfer.c  Wed Jun 30
> 17:40:22 2010 +0800
> @@ -18,11 +18,10 @@
>   *
>   * CDDL HEADER END
>   */
> -/*
> - * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
> - * Use is subject to license terms.
> - */
> -
> +
> +/*
> + * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights 
> reserved.
> + */
> 
>  /*
>   * EHCI Host Controller Driver (EHCI)
> @@ -557,7 +556,6 @@ ehci_insert_qh(
>               ehcip->ehci_open_periodic_count++;
>               break;
>       }
> -     ehci_toggle_scheduler(ehcip);
>  }
> 
> 
> @@ -1142,7 +1140,6 @@ ehci_remove_qh(
>               ehcip->ehci_open_periodic_count--;
>               break;
>       }
> -     ehci_toggle_scheduler(ehcip);
>  }
> 
> 
> @@ -2991,6 +2988,7 @@ ehci_create_transfer_wrapper(
>       ehci_trans_wrapper_t    *tw;
>       int                     kmem_flag;
>       int                     (*dmamem_wait)(caddr_t);
> +     usb_ep_descr_t          *eptd = &pp->pp_pipe_handle->p_ep;
> 
>       USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
>           "ehci_create_transfer_wrapper: length = 0x%lx flags = 0x%x",
> @@ -3104,6 +3102,14 @@ dmadone:
> 
>       ASSERT(tw->tw_id != NULL);
> 
> +     /* isoc ep will not come here */
> +     if (EHCI_INTR_ENDPOINT(eptd)) {
> +             ehcip->ehci_periodic_req_count++;
> +     } else {
> +             ehcip->ehci_async_req_count++;
> +     }
> +     ehci_toggle_scheduler(ehcip);
> +
>       USB_DPRINTF_L4(PRINT_MASK_ALLOC, ehcip->ehci_log_hdl,
>           "ehci_create_transfer_wrapper: tw = 0x%p, ncookies = %u",
>           (void *)tw, tw->tw_ncookies);
> @@ -3515,6 +3521,7 @@ ehci_free_tw(
>       ehci_trans_wrapper_t    *tw)
>  {
>       int     rval;
> +     usb_ep_descr_t  *eptd = &pp->pp_pipe_handle->p_ep;
> 
>       USB_DPRINTF_L4(PRINT_MASK_ALLOC, ehcip->ehci_log_hdl,
>           "ehci_free_tw: tw = 0x%p", (void *)tw);
> @@ -3533,6 +3540,14 @@ ehci_free_tw(
>               ddi_dma_free_handle(&tw->tw_dmahandle);
>       }
> 
> +     /* interrupt ep will come to this point */
> +     if (EHCI_INTR_ENDPOINT(eptd)) {
> +             ehcip->ehci_periodic_req_count--;
> +     } else {
> +             ehcip->ehci_async_req_count--;
> +     }
> +     ehci_toggle_scheduler(ehcip);
> +
>       /* Free transfer wrapper */
>       kmem_free(tw, sizeof (ehci_trans_wrapper_t));
>  }
> diff -r 6031bb35a0c5 -r bcfc9c7baa2e
> usr/src/uts/common/sys/usb/hcd/ehci/ehcid.h
> --- a/usr/src/uts/common/sys/usb/hcd/ehci/ehcid.h     Wed Jun 30 10:31:31
> 2010 +0800
> +++ b/usr/src/uts/common/sys/usb/hcd/ehci/ehcid.h     Wed Jun 30 17:40:22
> 2010 +0800
> @@ -19,8 +19,7 @@
>   * CDDL HEADER END
>   */
>  /*
> - * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
> - * Use is subject to license terms.
> + * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights 
> reserved.
>   */
> 
>  #ifndef _SYS_USB_EHCID_H
> @@ -166,6 +165,10 @@ typedef struct ehci_state {
>       uint_t                  ehci_open_async_count;
>       uint_t                  ehci_open_periodic_count;
> 
> +     /* No. of async and periodic requests */
> +     uint_t                  ehci_async_req_count;
> +     uint_t                  ehci_periodic_req_count;
> +
>       /*
>        * Endpoint Reclamation List
>        *
_______________________________________________
pm-discuss mailing list
[email protected]
http://mail.opensolaris.org/mailman/listinfo/pm-discuss

Reply via email to