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
