Mercurial > illumos > illumos-gate
changeset 12898:2e278bf762e0
6968282 panic with assertion failed: status & EHCI_QH_STS_HALTED
author | Raymond Chen <Raymond.Chen@Sun.COM> |
---|---|
date | Thu, 22 Jul 2010 10:15:06 +0800 |
parents | dc96b005136b |
children | 5abbd90da85a |
files | usr/src/uts/common/io/usb/hcd/ehci/ehci_util.c usr/src/uts/common/io/usb/hcd/ehci/ehci_xfer.c usr/src/uts/common/sys/usb/hcd/ehci/ehci_util.h |
diffstat | 3 files changed, 104 insertions(+), 2 deletions(-) [+] |
line wrap: on
line diff
--- a/usr/src/uts/common/io/usb/hcd/ehci/ehci_util.c Wed Jul 21 16:49:10 2010 -0700 +++ b/usr/src/uts/common/io/usb/hcd/ehci/ehci_util.c Thu Jul 22 10:15:06 2010 +0800 @@ -4001,6 +4001,104 @@ return (USB_SUCCESS); } +/* + * Toggle the async/periodic schedule based on opened pipe count. + * During pipe cleanup(in pipe reset case), the pipe's QH is temporarily + * disabled. But the TW on the pipe is not freed. In this case, we need + * to disable async/periodic schedule for some non-compatible hardware. + * Otherwise, the hardware will overwrite software's configuration of + * the QH. + */ +void +ehci_toggle_scheduler_on_pipe(ehci_state_t *ehcip) +{ + uint_t temp_reg, cmd_reg; + + cmd_reg = Get_OpReg(ehci_command); + temp_reg = cmd_reg; + + /* + * Enable/Disable asynchronous scheduler, and + * turn on/off async list door bell + */ + if (ehcip->ehci_open_async_count) { + if ((ehcip->ehci_async_req_count > 0) && + ((cmd_reg & EHCI_CMD_ASYNC_SCHED_ENABLE) == 0)) { + /* + * 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)); + + /* + * For some reason this register might get nulled out by + * the Uli M1575 Southbridge. To workaround the HW + * problem, check the value after write and retry if the + * last write fails. + * + * If the ASYNCLISTADDR remains "stuck" after + * EHCI_MAX_RETRY retries, then the M1575 is broken + * and is stuck in an inconsistent state and is about + * to crash the machine with a trn_oor panic when it + * does a DMA read from 0x0. It is better to panic + * now rather than wait for the trn_oor crash; this + * way Customer Service will have a clean signature + * that indicts the M1575 chip rather than a + * mysterious and hard-to-diagnose trn_oor panic. + */ + if ((ehcip->ehci_vendor_id == PCI_VENDOR_ULi_M1575) && + (ehcip->ehci_device_id == PCI_DEVICE_ULi_M1575) && + (ehci_qh_cpu_to_iommu(ehcip, + ehcip->ehci_head_of_async_sched_list) != + Get_OpReg(ehci_async_list_addr))) { + int retry = 0; + + Set_OpRegRetry(ehci_async_list_addr, + ehci_qh_cpu_to_iommu(ehcip, + ehcip->ehci_head_of_async_sched_list), + retry); + if (retry >= EHCI_MAX_RETRY) + cmn_err(CE_PANIC, + "ehci_toggle_scheduler_on_pipe: " + "ASYNCLISTADDR write failed."); + + USB_DPRINTF_L2(PRINT_MASK_ATTA, + ehcip->ehci_log_hdl, + "ehci_toggle_scheduler_on_pipe:" + " ASYNCLISTADDR write failed, retry=%d", + retry); + } + + cmd_reg |= EHCI_CMD_ASYNC_SCHED_ENABLE; + } + } else { + cmd_reg &= ~EHCI_CMD_ASYNC_SCHED_ENABLE; + } + + if (ehcip->ehci_open_periodic_count) { + if ((ehcip->ehci_periodic_req_count > 0) && + ((cmd_reg & EHCI_CMD_PERIODIC_SCHED_ENABLE) == 0)) { + /* + * For some reason this address get's nulled out by + * the ehci chip. Set it here just in case it is null. + */ + Set_OpReg(ehci_periodic_list_base, + (uint32_t)(ehcip->ehci_pflt_cookie.dmac_address & + 0xFFFFF000)); + cmd_reg |= EHCI_CMD_PERIODIC_SCHED_ENABLE; + } + } else { + cmd_reg &= ~EHCI_CMD_PERIODIC_SCHED_ENABLE; + } + + /* Just an optimization */ + if (temp_reg != cmd_reg) { + Set_OpReg(ehci_command, cmd_reg); + } +} + /* * ehci_toggle_scheduler:
--- a/usr/src/uts/common/io/usb/hcd/ehci/ehci_xfer.c Wed Jul 21 16:49:10 2010 -0700 +++ b/usr/src/uts/common/io/usb/hcd/ehci/ehci_xfer.c Thu Jul 22 10:15:06 2010 +0800 @@ -854,6 +854,7 @@ /* Remove this qh from the HCD's view, but do not reclaim it */ ehci_remove_qh(ehcip, pp, B_FALSE); + ehci_toggle_scheduler_on_pipe(ehcip); /* * Wait for atleast one SOF, just in case the HCD is in the @@ -871,6 +872,7 @@ /* Insert this QH back into the HCD's view */ ehci_insert_qh(ehcip, ph); + ehci_toggle_scheduler_on_pipe(ehcip); } @@ -894,6 +896,7 @@ /* Remove this qh from the HCD's view, but do not reclaim it */ ehci_remove_qh(ehcip, pp, B_FALSE); + ehci_toggle_scheduler_on_pipe(ehcip); /* * Wait for atleast one SOF, just in case the HCD is in the @@ -921,6 +924,7 @@ /* Insert this QH back into the HCD's view */ ehci_insert_qh(ehcip, ph); + ehci_toggle_scheduler_on_pipe(ehcip); }
--- a/usr/src/uts/common/sys/usb/hcd/ehci/ehci_util.h Wed Jul 21 16:49:10 2010 -0700 +++ b/usr/src/uts/common/sys/usb/hcd/ehci/ehci_util.h Thu Jul 22 10:15:06 2010 +0800 @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 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_EHCI_UTIL_H @@ -102,6 +101,7 @@ ehci_state_t *ehcip); extern void ehci_toggle_scheduler( ehci_state_t *ehcip); +extern void ehci_toggle_scheduler_on_pipe(ehci_state_t *ehcip); extern void ehci_print_caps(ehci_state_t *ehcip); extern void ehci_print_regs(ehci_state_t *ehcip);