diff options
| author | Raymond Chen <Raymond.Chen@Sun.COM> | 2010-06-30 17:40:22 +0800 |
|---|---|---|
| committer | Raymond Chen <Raymond.Chen@Sun.COM> | 2010-06-30 17:40:22 +0800 |
| commit | dfbb3a42fe4d6d7c50b9f750f514f8c7b66e4ed9 (patch) | |
| tree | 18a2848401ac6a7dd2ebb0a7d696d967bc66b533 /usr/src | |
| parent | c9d8e919f508a150163a68f1be46ba15fffebb7c (diff) | |
| download | illumos-joyent-dfbb3a42fe4d6d7c50b9f750f514f8c7b66e4ed9.tar.gz | |
6948314 DMA activities from USB host controller throttle some processor's package C-state
Diffstat (limited to 'usr/src')
| -rw-r--r-- | usr/src/uts/common/io/usb/hcd/ehci/ehci_isoch_util.c | 11 | ||||
| -rw-r--r-- | usr/src/uts/common/io/usb/hcd/ehci/ehci_util.c | 74 | ||||
| -rw-r--r-- | usr/src/uts/common/io/usb/hcd/ehci/ehci_xfer.c | 25 | ||||
| -rw-r--r-- | usr/src/uts/common/sys/usb/hcd/ehci/ehcid.h | 7 |
4 files changed, 96 insertions, 21 deletions
diff --git a/usr/src/uts/common/io/usb/hcd/ehci/ehci_isoch_util.c b/usr/src/uts/common/io/usb/hcd/ehci/ehci_isoch_util.c index b79aa032bc..fa1968cd0e 100644 --- a/usr/src/uts/common/io/usb/hcd/ehci/ehci_isoch_util.c +++ b/usr/src/uts/common/io/usb/hcd/ehci/ehci_isoch_util.c @@ -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 --git a/usr/src/uts/common/io/usb/hcd/ehci/ehci_util.c b/usr/src/uts/common/io/usb/hcd/ehci/ehci_util.c index 76f333ccf6..81ac127138 100644 --- a/usr/src/uts/common/io/usb/hcd/ehci/ehci_util.c +++ b/usr/src/uts/common/io/usb/hcd/ehci/ehci_util.c @@ -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 *ehcip) { * 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. + * 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. */ - Set_OpReg(ehci_async_list_addr, - ehci_qh_cpu_to_iommu(ehcip, - ehcip->ehci_head_of_async_sched_list)); + 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 *ehcip) { "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 *ehcip) { 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 *ehcip) { */ 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 *ehcip) { /* 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 --git a/usr/src/uts/common/io/usb/hcd/ehci/ehci_xfer.c b/usr/src/uts/common/io/usb/hcd/ehci/ehci_xfer.c index a6afec8afd..da080b6235 100644 --- a/usr/src/uts/common/io/usb/hcd/ehci/ehci_xfer.c +++ b/usr/src/uts/common/io/usb/hcd/ehci/ehci_xfer.c @@ -18,12 +18,11 @@ * * 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 --git a/usr/src/uts/common/sys/usb/hcd/ehci/ehcid.h b/usr/src/uts/common/sys/usb/hcd/ehci/ehcid.h index aae58e2c66..74b1f12971 100644 --- a/usr/src/uts/common/sys/usb/hcd/ehci/ehcid.h +++ b/usr/src/uts/common/sys/usb/hcd/ehci/ehcid.h @@ -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 * |
