162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2012 by Alan Stern 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci/* This file is part of ehci-hcd.c */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci/*-------------------------------------------------------------------------*/ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci/* Set a bit in the USBCMD register */ 1162306a36Sopenharmony_cistatic void ehci_set_command_bit(struct ehci_hcd *ehci, u32 bit) 1262306a36Sopenharmony_ci{ 1362306a36Sopenharmony_ci ehci->command |= bit; 1462306a36Sopenharmony_ci ehci_writel(ehci, ehci->command, &ehci->regs->command); 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci /* unblock posted write */ 1762306a36Sopenharmony_ci ehci_readl(ehci, &ehci->regs->command); 1862306a36Sopenharmony_ci} 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci/* Clear a bit in the USBCMD register */ 2162306a36Sopenharmony_cistatic void ehci_clear_command_bit(struct ehci_hcd *ehci, u32 bit) 2262306a36Sopenharmony_ci{ 2362306a36Sopenharmony_ci ehci->command &= ~bit; 2462306a36Sopenharmony_ci ehci_writel(ehci, ehci->command, &ehci->regs->command); 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci /* unblock posted write */ 2762306a36Sopenharmony_ci ehci_readl(ehci, &ehci->regs->command); 2862306a36Sopenharmony_ci} 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci/*-------------------------------------------------------------------------*/ 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci/* 3362306a36Sopenharmony_ci * EHCI timer support... Now using hrtimers. 3462306a36Sopenharmony_ci * 3562306a36Sopenharmony_ci * Lots of different events are triggered from ehci->hrtimer. Whenever 3662306a36Sopenharmony_ci * the timer routine runs, it checks each possible event; events that are 3762306a36Sopenharmony_ci * currently enabled and whose expiration time has passed get handled. 3862306a36Sopenharmony_ci * The set of enabled events is stored as a collection of bitflags in 3962306a36Sopenharmony_ci * ehci->enabled_hrtimer_events, and they are numbered in order of 4062306a36Sopenharmony_ci * increasing delay values (ranging between 1 ms and 100 ms). 4162306a36Sopenharmony_ci * 4262306a36Sopenharmony_ci * Rather than implementing a sorted list or tree of all pending events, 4362306a36Sopenharmony_ci * we keep track only of the lowest-numbered pending event, in 4462306a36Sopenharmony_ci * ehci->next_hrtimer_event. Whenever ehci->hrtimer gets restarted, its 4562306a36Sopenharmony_ci * expiration time is set to the timeout value for this event. 4662306a36Sopenharmony_ci * 4762306a36Sopenharmony_ci * As a result, events might not get handled right away; the actual delay 4862306a36Sopenharmony_ci * could be anywhere up to twice the requested delay. This doesn't 4962306a36Sopenharmony_ci * matter, because none of the events are especially time-critical. The 5062306a36Sopenharmony_ci * ones that matter most all have a delay of 1 ms, so they will be 5162306a36Sopenharmony_ci * handled after 2 ms at most, which is okay. In addition to this, we 5262306a36Sopenharmony_ci * allow for an expiration range of 1 ms. 5362306a36Sopenharmony_ci */ 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci/* 5662306a36Sopenharmony_ci * Delay lengths for the hrtimer event types. 5762306a36Sopenharmony_ci * Keep this list sorted by delay length, in the same order as 5862306a36Sopenharmony_ci * the event types indexed by enum ehci_hrtimer_event in ehci.h. 5962306a36Sopenharmony_ci */ 6062306a36Sopenharmony_cistatic unsigned event_delays_ns[] = { 6162306a36Sopenharmony_ci 1 * NSEC_PER_MSEC, /* EHCI_HRTIMER_POLL_ASS */ 6262306a36Sopenharmony_ci 1 * NSEC_PER_MSEC, /* EHCI_HRTIMER_POLL_PSS */ 6362306a36Sopenharmony_ci 1 * NSEC_PER_MSEC, /* EHCI_HRTIMER_POLL_DEAD */ 6462306a36Sopenharmony_ci 1125 * NSEC_PER_USEC, /* EHCI_HRTIMER_UNLINK_INTR */ 6562306a36Sopenharmony_ci 2 * NSEC_PER_MSEC, /* EHCI_HRTIMER_FREE_ITDS */ 6662306a36Sopenharmony_ci 2 * NSEC_PER_MSEC, /* EHCI_HRTIMER_ACTIVE_UNLINK */ 6762306a36Sopenharmony_ci 5 * NSEC_PER_MSEC, /* EHCI_HRTIMER_START_UNLINK_INTR */ 6862306a36Sopenharmony_ci 6 * NSEC_PER_MSEC, /* EHCI_HRTIMER_ASYNC_UNLINKS */ 6962306a36Sopenharmony_ci 10 * NSEC_PER_MSEC, /* EHCI_HRTIMER_IAA_WATCHDOG */ 7062306a36Sopenharmony_ci 10 * NSEC_PER_MSEC, /* EHCI_HRTIMER_DISABLE_PERIODIC */ 7162306a36Sopenharmony_ci 15 * NSEC_PER_MSEC, /* EHCI_HRTIMER_DISABLE_ASYNC */ 7262306a36Sopenharmony_ci 100 * NSEC_PER_MSEC, /* EHCI_HRTIMER_IO_WATCHDOG */ 7362306a36Sopenharmony_ci}; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci/* Enable a pending hrtimer event */ 7662306a36Sopenharmony_cistatic void ehci_enable_event(struct ehci_hcd *ehci, unsigned event, 7762306a36Sopenharmony_ci bool resched) 7862306a36Sopenharmony_ci{ 7962306a36Sopenharmony_ci ktime_t *timeout = &ehci->hr_timeouts[event]; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci if (resched) 8262306a36Sopenharmony_ci *timeout = ktime_add(ktime_get(), event_delays_ns[event]); 8362306a36Sopenharmony_ci ehci->enabled_hrtimer_events |= (1 << event); 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci /* Track only the lowest-numbered pending event */ 8662306a36Sopenharmony_ci if (event < ehci->next_hrtimer_event) { 8762306a36Sopenharmony_ci ehci->next_hrtimer_event = event; 8862306a36Sopenharmony_ci hrtimer_start_range_ns(&ehci->hrtimer, *timeout, 8962306a36Sopenharmony_ci NSEC_PER_MSEC, HRTIMER_MODE_ABS); 9062306a36Sopenharmony_ci } 9162306a36Sopenharmony_ci} 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci/* Poll the STS_ASS status bit; see when it agrees with CMD_ASE */ 9562306a36Sopenharmony_cistatic void ehci_poll_ASS(struct ehci_hcd *ehci) 9662306a36Sopenharmony_ci{ 9762306a36Sopenharmony_ci unsigned actual, want; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci /* Don't enable anything if the controller isn't running (e.g., died) */ 10062306a36Sopenharmony_ci if (ehci->rh_state != EHCI_RH_RUNNING) 10162306a36Sopenharmony_ci return; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci want = (ehci->command & CMD_ASE) ? STS_ASS : 0; 10462306a36Sopenharmony_ci actual = ehci_readl(ehci, &ehci->regs->status) & STS_ASS; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci if (want != actual) { 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci /* Poll again later, but give up after about 2-4 ms */ 10962306a36Sopenharmony_ci if (ehci->ASS_poll_count++ < 2) { 11062306a36Sopenharmony_ci ehci_enable_event(ehci, EHCI_HRTIMER_POLL_ASS, true); 11162306a36Sopenharmony_ci return; 11262306a36Sopenharmony_ci } 11362306a36Sopenharmony_ci ehci_dbg(ehci, "Waited too long for the async schedule status (%x/%x), giving up\n", 11462306a36Sopenharmony_ci want, actual); 11562306a36Sopenharmony_ci } 11662306a36Sopenharmony_ci ehci->ASS_poll_count = 0; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci /* The status is up-to-date; restart or stop the schedule as needed */ 11962306a36Sopenharmony_ci if (want == 0) { /* Stopped */ 12062306a36Sopenharmony_ci if (ehci->async_count > 0) 12162306a36Sopenharmony_ci ehci_set_command_bit(ehci, CMD_ASE); 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci } else { /* Running */ 12462306a36Sopenharmony_ci if (ehci->async_count == 0) { 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci /* Turn off the schedule after a while */ 12762306a36Sopenharmony_ci ehci_enable_event(ehci, EHCI_HRTIMER_DISABLE_ASYNC, 12862306a36Sopenharmony_ci true); 12962306a36Sopenharmony_ci } 13062306a36Sopenharmony_ci } 13162306a36Sopenharmony_ci} 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci/* Turn off the async schedule after a brief delay */ 13462306a36Sopenharmony_cistatic void ehci_disable_ASE(struct ehci_hcd *ehci) 13562306a36Sopenharmony_ci{ 13662306a36Sopenharmony_ci ehci_clear_command_bit(ehci, CMD_ASE); 13762306a36Sopenharmony_ci} 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci/* Poll the STS_PSS status bit; see when it agrees with CMD_PSE */ 14162306a36Sopenharmony_cistatic void ehci_poll_PSS(struct ehci_hcd *ehci) 14262306a36Sopenharmony_ci{ 14362306a36Sopenharmony_ci unsigned actual, want; 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci /* Don't do anything if the controller isn't running (e.g., died) */ 14662306a36Sopenharmony_ci if (ehci->rh_state != EHCI_RH_RUNNING) 14762306a36Sopenharmony_ci return; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci want = (ehci->command & CMD_PSE) ? STS_PSS : 0; 15062306a36Sopenharmony_ci actual = ehci_readl(ehci, &ehci->regs->status) & STS_PSS; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci if (want != actual) { 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci /* Poll again later, but give up after about 2-4 ms */ 15562306a36Sopenharmony_ci if (ehci->PSS_poll_count++ < 2) { 15662306a36Sopenharmony_ci ehci_enable_event(ehci, EHCI_HRTIMER_POLL_PSS, true); 15762306a36Sopenharmony_ci return; 15862306a36Sopenharmony_ci } 15962306a36Sopenharmony_ci ehci_dbg(ehci, "Waited too long for the periodic schedule status (%x/%x), giving up\n", 16062306a36Sopenharmony_ci want, actual); 16162306a36Sopenharmony_ci } 16262306a36Sopenharmony_ci ehci->PSS_poll_count = 0; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci /* The status is up-to-date; restart or stop the schedule as needed */ 16562306a36Sopenharmony_ci if (want == 0) { /* Stopped */ 16662306a36Sopenharmony_ci if (ehci->periodic_count > 0) 16762306a36Sopenharmony_ci ehci_set_command_bit(ehci, CMD_PSE); 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci } else { /* Running */ 17062306a36Sopenharmony_ci if (ehci->periodic_count == 0) { 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci /* Turn off the schedule after a while */ 17362306a36Sopenharmony_ci ehci_enable_event(ehci, EHCI_HRTIMER_DISABLE_PERIODIC, 17462306a36Sopenharmony_ci true); 17562306a36Sopenharmony_ci } 17662306a36Sopenharmony_ci } 17762306a36Sopenharmony_ci} 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci/* Turn off the periodic schedule after a brief delay */ 18062306a36Sopenharmony_cistatic void ehci_disable_PSE(struct ehci_hcd *ehci) 18162306a36Sopenharmony_ci{ 18262306a36Sopenharmony_ci ehci_clear_command_bit(ehci, CMD_PSE); 18362306a36Sopenharmony_ci} 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci/* Poll the STS_HALT status bit; see when a dead controller stops */ 18762306a36Sopenharmony_cistatic void ehci_handle_controller_death(struct ehci_hcd *ehci) 18862306a36Sopenharmony_ci{ 18962306a36Sopenharmony_ci if (!(ehci_readl(ehci, &ehci->regs->status) & STS_HALT)) { 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci /* Give up after a few milliseconds */ 19262306a36Sopenharmony_ci if (ehci->died_poll_count++ < 5) { 19362306a36Sopenharmony_ci /* Try again later */ 19462306a36Sopenharmony_ci ehci_enable_event(ehci, EHCI_HRTIMER_POLL_DEAD, true); 19562306a36Sopenharmony_ci return; 19662306a36Sopenharmony_ci } 19762306a36Sopenharmony_ci ehci_warn(ehci, "Waited too long for the controller to stop, giving up\n"); 19862306a36Sopenharmony_ci } 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci /* Clean up the mess */ 20162306a36Sopenharmony_ci ehci->rh_state = EHCI_RH_HALTED; 20262306a36Sopenharmony_ci ehci_writel(ehci, 0, &ehci->regs->configured_flag); 20362306a36Sopenharmony_ci ehci_writel(ehci, 0, &ehci->regs->intr_enable); 20462306a36Sopenharmony_ci ehci_work(ehci); 20562306a36Sopenharmony_ci end_unlink_async(ehci); 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci /* Not in process context, so don't try to reset the controller */ 20862306a36Sopenharmony_ci} 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci/* start to unlink interrupt QHs */ 21162306a36Sopenharmony_cistatic void ehci_handle_start_intr_unlinks(struct ehci_hcd *ehci) 21262306a36Sopenharmony_ci{ 21362306a36Sopenharmony_ci bool stopped = (ehci->rh_state < EHCI_RH_RUNNING); 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci /* 21662306a36Sopenharmony_ci * Process all the QHs on the intr_unlink list that were added 21762306a36Sopenharmony_ci * before the current unlink cycle began. The list is in 21862306a36Sopenharmony_ci * temporal order, so stop when we reach the first entry in the 21962306a36Sopenharmony_ci * current cycle. But if the root hub isn't running then 22062306a36Sopenharmony_ci * process all the QHs on the list. 22162306a36Sopenharmony_ci */ 22262306a36Sopenharmony_ci while (!list_empty(&ehci->intr_unlink_wait)) { 22362306a36Sopenharmony_ci struct ehci_qh *qh; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci qh = list_first_entry(&ehci->intr_unlink_wait, 22662306a36Sopenharmony_ci struct ehci_qh, unlink_node); 22762306a36Sopenharmony_ci if (!stopped && (qh->unlink_cycle == 22862306a36Sopenharmony_ci ehci->intr_unlink_wait_cycle)) 22962306a36Sopenharmony_ci break; 23062306a36Sopenharmony_ci list_del_init(&qh->unlink_node); 23162306a36Sopenharmony_ci qh->unlink_reason |= QH_UNLINK_QUEUE_EMPTY; 23262306a36Sopenharmony_ci start_unlink_intr(ehci, qh); 23362306a36Sopenharmony_ci } 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci /* Handle remaining entries later */ 23662306a36Sopenharmony_ci if (!list_empty(&ehci->intr_unlink_wait)) { 23762306a36Sopenharmony_ci ehci_enable_event(ehci, EHCI_HRTIMER_START_UNLINK_INTR, true); 23862306a36Sopenharmony_ci ++ehci->intr_unlink_wait_cycle; 23962306a36Sopenharmony_ci } 24062306a36Sopenharmony_ci} 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci/* Handle unlinked interrupt QHs once they are gone from the hardware */ 24362306a36Sopenharmony_cistatic void ehci_handle_intr_unlinks(struct ehci_hcd *ehci) 24462306a36Sopenharmony_ci{ 24562306a36Sopenharmony_ci bool stopped = (ehci->rh_state < EHCI_RH_RUNNING); 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci /* 24862306a36Sopenharmony_ci * Process all the QHs on the intr_unlink list that were added 24962306a36Sopenharmony_ci * before the current unlink cycle began. The list is in 25062306a36Sopenharmony_ci * temporal order, so stop when we reach the first entry in the 25162306a36Sopenharmony_ci * current cycle. But if the root hub isn't running then 25262306a36Sopenharmony_ci * process all the QHs on the list. 25362306a36Sopenharmony_ci */ 25462306a36Sopenharmony_ci ehci->intr_unlinking = true; 25562306a36Sopenharmony_ci while (!list_empty(&ehci->intr_unlink)) { 25662306a36Sopenharmony_ci struct ehci_qh *qh; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci qh = list_first_entry(&ehci->intr_unlink, struct ehci_qh, 25962306a36Sopenharmony_ci unlink_node); 26062306a36Sopenharmony_ci if (!stopped && qh->unlink_cycle == ehci->intr_unlink_cycle) 26162306a36Sopenharmony_ci break; 26262306a36Sopenharmony_ci list_del_init(&qh->unlink_node); 26362306a36Sopenharmony_ci end_unlink_intr(ehci, qh); 26462306a36Sopenharmony_ci } 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci /* Handle remaining entries later */ 26762306a36Sopenharmony_ci if (!list_empty(&ehci->intr_unlink)) { 26862306a36Sopenharmony_ci ehci_enable_event(ehci, EHCI_HRTIMER_UNLINK_INTR, true); 26962306a36Sopenharmony_ci ++ehci->intr_unlink_cycle; 27062306a36Sopenharmony_ci } 27162306a36Sopenharmony_ci ehci->intr_unlinking = false; 27262306a36Sopenharmony_ci} 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci/* Start another free-iTDs/siTDs cycle */ 27662306a36Sopenharmony_cistatic void start_free_itds(struct ehci_hcd *ehci) 27762306a36Sopenharmony_ci{ 27862306a36Sopenharmony_ci if (!(ehci->enabled_hrtimer_events & BIT(EHCI_HRTIMER_FREE_ITDS))) { 27962306a36Sopenharmony_ci ehci->last_itd_to_free = list_entry( 28062306a36Sopenharmony_ci ehci->cached_itd_list.prev, 28162306a36Sopenharmony_ci struct ehci_itd, itd_list); 28262306a36Sopenharmony_ci ehci->last_sitd_to_free = list_entry( 28362306a36Sopenharmony_ci ehci->cached_sitd_list.prev, 28462306a36Sopenharmony_ci struct ehci_sitd, sitd_list); 28562306a36Sopenharmony_ci ehci_enable_event(ehci, EHCI_HRTIMER_FREE_ITDS, true); 28662306a36Sopenharmony_ci } 28762306a36Sopenharmony_ci} 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci/* Wait for controller to stop using old iTDs and siTDs */ 29062306a36Sopenharmony_cistatic void end_free_itds(struct ehci_hcd *ehci) 29162306a36Sopenharmony_ci{ 29262306a36Sopenharmony_ci struct ehci_itd *itd, *n; 29362306a36Sopenharmony_ci struct ehci_sitd *sitd, *sn; 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci if (ehci->rh_state < EHCI_RH_RUNNING) { 29662306a36Sopenharmony_ci ehci->last_itd_to_free = NULL; 29762306a36Sopenharmony_ci ehci->last_sitd_to_free = NULL; 29862306a36Sopenharmony_ci } 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci list_for_each_entry_safe(itd, n, &ehci->cached_itd_list, itd_list) { 30162306a36Sopenharmony_ci list_del(&itd->itd_list); 30262306a36Sopenharmony_ci dma_pool_free(ehci->itd_pool, itd, itd->itd_dma); 30362306a36Sopenharmony_ci if (itd == ehci->last_itd_to_free) 30462306a36Sopenharmony_ci break; 30562306a36Sopenharmony_ci } 30662306a36Sopenharmony_ci list_for_each_entry_safe(sitd, sn, &ehci->cached_sitd_list, sitd_list) { 30762306a36Sopenharmony_ci list_del(&sitd->sitd_list); 30862306a36Sopenharmony_ci dma_pool_free(ehci->sitd_pool, sitd, sitd->sitd_dma); 30962306a36Sopenharmony_ci if (sitd == ehci->last_sitd_to_free) 31062306a36Sopenharmony_ci break; 31162306a36Sopenharmony_ci } 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci if (!list_empty(&ehci->cached_itd_list) || 31462306a36Sopenharmony_ci !list_empty(&ehci->cached_sitd_list)) 31562306a36Sopenharmony_ci start_free_itds(ehci); 31662306a36Sopenharmony_ci} 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci/* Handle lost (or very late) IAA interrupts */ 32062306a36Sopenharmony_cistatic void ehci_iaa_watchdog(struct ehci_hcd *ehci) 32162306a36Sopenharmony_ci{ 32262306a36Sopenharmony_ci u32 cmd, status; 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci /* 32562306a36Sopenharmony_ci * Lost IAA irqs wedge things badly; seen first with a vt8235. 32662306a36Sopenharmony_ci * So we need this watchdog, but must protect it against both 32762306a36Sopenharmony_ci * (a) SMP races against real IAA firing and retriggering, and 32862306a36Sopenharmony_ci * (b) clean HC shutdown, when IAA watchdog was pending. 32962306a36Sopenharmony_ci */ 33062306a36Sopenharmony_ci if (!ehci->iaa_in_progress || ehci->rh_state != EHCI_RH_RUNNING) 33162306a36Sopenharmony_ci return; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci /* If we get here, IAA is *REALLY* late. It's barely 33462306a36Sopenharmony_ci * conceivable that the system is so busy that CMD_IAAD 33562306a36Sopenharmony_ci * is still legitimately set, so let's be sure it's 33662306a36Sopenharmony_ci * clear before we read STS_IAA. (The HC should clear 33762306a36Sopenharmony_ci * CMD_IAAD when it sets STS_IAA.) 33862306a36Sopenharmony_ci */ 33962306a36Sopenharmony_ci cmd = ehci_readl(ehci, &ehci->regs->command); 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci /* 34262306a36Sopenharmony_ci * If IAA is set here it either legitimately triggered 34362306a36Sopenharmony_ci * after the watchdog timer expired (_way_ late, so we'll 34462306a36Sopenharmony_ci * still count it as lost) ... or a silicon erratum: 34562306a36Sopenharmony_ci * - VIA seems to set IAA without triggering the IRQ; 34662306a36Sopenharmony_ci * - IAAD potentially cleared without setting IAA. 34762306a36Sopenharmony_ci */ 34862306a36Sopenharmony_ci status = ehci_readl(ehci, &ehci->regs->status); 34962306a36Sopenharmony_ci if ((status & STS_IAA) || !(cmd & CMD_IAAD)) { 35062306a36Sopenharmony_ci INCR(ehci->stats.lost_iaa); 35162306a36Sopenharmony_ci ehci_writel(ehci, STS_IAA, &ehci->regs->status); 35262306a36Sopenharmony_ci } 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci ehci_dbg(ehci, "IAA watchdog: status %x cmd %x\n", status, cmd); 35562306a36Sopenharmony_ci end_iaa_cycle(ehci); 35662306a36Sopenharmony_ci} 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci/* Enable the I/O watchdog, if appropriate */ 36062306a36Sopenharmony_cistatic void turn_on_io_watchdog(struct ehci_hcd *ehci) 36162306a36Sopenharmony_ci{ 36262306a36Sopenharmony_ci /* Not needed if the controller isn't running or it's already enabled */ 36362306a36Sopenharmony_ci if (ehci->rh_state != EHCI_RH_RUNNING || 36462306a36Sopenharmony_ci (ehci->enabled_hrtimer_events & 36562306a36Sopenharmony_ci BIT(EHCI_HRTIMER_IO_WATCHDOG))) 36662306a36Sopenharmony_ci return; 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci /* 36962306a36Sopenharmony_ci * Isochronous transfers always need the watchdog. 37062306a36Sopenharmony_ci * For other sorts we use it only if the flag is set. 37162306a36Sopenharmony_ci */ 37262306a36Sopenharmony_ci if (ehci->isoc_count > 0 || (ehci->need_io_watchdog && 37362306a36Sopenharmony_ci ehci->async_count + ehci->intr_count > 0)) 37462306a36Sopenharmony_ci ehci_enable_event(ehci, EHCI_HRTIMER_IO_WATCHDOG, true); 37562306a36Sopenharmony_ci} 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci/* 37962306a36Sopenharmony_ci * Handler functions for the hrtimer event types. 38062306a36Sopenharmony_ci * Keep this array in the same order as the event types indexed by 38162306a36Sopenharmony_ci * enum ehci_hrtimer_event in ehci.h. 38262306a36Sopenharmony_ci */ 38362306a36Sopenharmony_cistatic void (*event_handlers[])(struct ehci_hcd *) = { 38462306a36Sopenharmony_ci ehci_poll_ASS, /* EHCI_HRTIMER_POLL_ASS */ 38562306a36Sopenharmony_ci ehci_poll_PSS, /* EHCI_HRTIMER_POLL_PSS */ 38662306a36Sopenharmony_ci ehci_handle_controller_death, /* EHCI_HRTIMER_POLL_DEAD */ 38762306a36Sopenharmony_ci ehci_handle_intr_unlinks, /* EHCI_HRTIMER_UNLINK_INTR */ 38862306a36Sopenharmony_ci end_free_itds, /* EHCI_HRTIMER_FREE_ITDS */ 38962306a36Sopenharmony_ci end_unlink_async, /* EHCI_HRTIMER_ACTIVE_UNLINK */ 39062306a36Sopenharmony_ci ehci_handle_start_intr_unlinks, /* EHCI_HRTIMER_START_UNLINK_INTR */ 39162306a36Sopenharmony_ci unlink_empty_async, /* EHCI_HRTIMER_ASYNC_UNLINKS */ 39262306a36Sopenharmony_ci ehci_iaa_watchdog, /* EHCI_HRTIMER_IAA_WATCHDOG */ 39362306a36Sopenharmony_ci ehci_disable_PSE, /* EHCI_HRTIMER_DISABLE_PERIODIC */ 39462306a36Sopenharmony_ci ehci_disable_ASE, /* EHCI_HRTIMER_DISABLE_ASYNC */ 39562306a36Sopenharmony_ci ehci_work, /* EHCI_HRTIMER_IO_WATCHDOG */ 39662306a36Sopenharmony_ci}; 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_cistatic enum hrtimer_restart ehci_hrtimer_func(struct hrtimer *t) 39962306a36Sopenharmony_ci{ 40062306a36Sopenharmony_ci struct ehci_hcd *ehci = container_of(t, struct ehci_hcd, hrtimer); 40162306a36Sopenharmony_ci ktime_t now; 40262306a36Sopenharmony_ci unsigned long events; 40362306a36Sopenharmony_ci unsigned long flags; 40462306a36Sopenharmony_ci unsigned e; 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci spin_lock_irqsave(&ehci->lock, flags); 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci events = ehci->enabled_hrtimer_events; 40962306a36Sopenharmony_ci ehci->enabled_hrtimer_events = 0; 41062306a36Sopenharmony_ci ehci->next_hrtimer_event = EHCI_HRTIMER_NO_EVENT; 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci /* 41362306a36Sopenharmony_ci * Check each pending event. If its time has expired, handle 41462306a36Sopenharmony_ci * the event; otherwise re-enable it. 41562306a36Sopenharmony_ci */ 41662306a36Sopenharmony_ci now = ktime_get(); 41762306a36Sopenharmony_ci for_each_set_bit(e, &events, EHCI_HRTIMER_NUM_EVENTS) { 41862306a36Sopenharmony_ci if (ktime_compare(now, ehci->hr_timeouts[e]) >= 0) 41962306a36Sopenharmony_ci event_handlers[e](ehci); 42062306a36Sopenharmony_ci else 42162306a36Sopenharmony_ci ehci_enable_event(ehci, e, false); 42262306a36Sopenharmony_ci } 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci spin_unlock_irqrestore(&ehci->lock, flags); 42562306a36Sopenharmony_ci return HRTIMER_NORESTART; 42662306a36Sopenharmony_ci} 427