コード例 #1
0
ファイル: ehci-timer.c プロジェクト: AshishNamdev/linux
/* Handle unlinked interrupt QHs once they are gone from the hardware */
static void ehci_handle_intr_unlinks(struct ehci_hcd *ehci)
{
	bool		stopped = (ehci->rh_state < EHCI_RH_RUNNING);

	/*
	 * Process all the QHs on the intr_unlink list that were added
	 * before the current unlink cycle began.  The list is in
	 * temporal order, so stop when we reach the first entry in the
	 * current cycle.  But if the root hub isn't running then
	 * process all the QHs on the list.
	 */
	ehci->intr_unlinking = true;
	while (!list_empty(&ehci->intr_unlink)) {
		struct ehci_qh	*qh;

		qh = list_first_entry(&ehci->intr_unlink, struct ehci_qh,
				unlink_node);
		if (!stopped && qh->unlink_cycle == ehci->intr_unlink_cycle)
			break;
		list_del_init(&qh->unlink_node);
		end_unlink_intr(ehci, qh);
	}

	/* Handle remaining entries later */
	if (!list_empty(&ehci->intr_unlink)) {
		ehci_enable_event(ehci, EHCI_HRTIMER_UNLINK_INTR, true);
		++ehci->intr_unlink_cycle;
	}
	ehci->intr_unlinking = false;
}
コード例 #2
0
ファイル: ehci-timer.c プロジェクト: AshishNamdev/linux
/* Start another free-iTDs/siTDs cycle */
static void start_free_itds(struct ehci_hcd *ehci)
{
	if (!(ehci->enabled_hrtimer_events & BIT(EHCI_HRTIMER_FREE_ITDS))) {
		ehci->last_itd_to_free = list_entry(
				ehci->cached_itd_list.prev,
				struct ehci_itd, itd_list);
		ehci->last_sitd_to_free = list_entry(
				ehci->cached_sitd_list.prev,
				struct ehci_sitd, sitd_list);
		ehci_enable_event(ehci, EHCI_HRTIMER_FREE_ITDS, true);
	}
コード例 #3
0
/* Poll the STS_ASS status bit; see when it agrees with CMD_ASE */
static void ehci_poll_ASS(struct ehci_hcd *ehci)
{
    unsigned	actual, want;

    /* Don't enable anything if the controller isn't running (e.g., died) */
    if (ehci->rh_state != EHCI_RH_RUNNING)
        return;

    want = (ehci->command & CMD_ASE) ? STS_ASS : 0;
    actual = ehci_readl(ehci, &ehci->regs->status) & STS_ASS;

    if (want != actual) {

        /* Poll again later */
        ehci_enable_event(ehci, EHCI_HRTIMER_POLL_ASS, true);
        ++ehci->ASS_poll_count;
        return;
    }

    if (ehci->ASS_poll_count > 20)
        ehci_dbg(ehci, "ASS poll count reached %d\n",
                 ehci->ASS_poll_count);
    ehci->ASS_poll_count = 0;

    /* The status is up-to-date; restart or stop the schedule as needed */
    if (want == 0) {	/* Stopped */
        if (ehci->async_count > 0)
            ehci_set_command_bit(ehci, CMD_ASE);

    } else {		/* Running */
        if (ehci->async_count == 0) {

            /* Turn off the schedule after a while */
            ehci_enable_event(ehci, EHCI_HRTIMER_DISABLE_ASYNC,
                              true);
        }
    }
}
コード例 #4
0
ファイル: ehci-timer.c プロジェクト: AshishNamdev/linux
/* Poll the STS_PSS status bit; see when it agrees with CMD_PSE */
static void ehci_poll_PSS(struct ehci_hcd *ehci)
{
	unsigned	actual, want;

	/* Don't do anything if the controller isn't running (e.g., died) */
	if (ehci->rh_state != EHCI_RH_RUNNING)
		return;

	want = (ehci->command & CMD_PSE) ? STS_PSS : 0;
	actual = ehci_readl(ehci, &ehci->regs->status) & STS_PSS;

	if (want != actual) {

		/* Poll again later, but give up after about 2-4 ms */
		if (ehci->PSS_poll_count++ < 2) {
			ehci_enable_event(ehci, EHCI_HRTIMER_POLL_PSS, true);
			return;
		}
		ehci_dbg(ehci, "Waited too long for the periodic schedule status (%x/%x), giving up\n",
				want, actual);
	}
	ehci->PSS_poll_count = 0;

	/* The status is up-to-date; restart or stop the schedule as needed */
	if (want == 0) {	/* Stopped */
		if (ehci->periodic_count > 0)
			ehci_set_command_bit(ehci, CMD_PSE);

	} else {		/* Running */
		if (ehci->periodic_count == 0) {

			/* Turn off the schedule after a while */
			ehci_enable_event(ehci, EHCI_HRTIMER_DISABLE_PERIODIC,
					true);
		}
	}
}
コード例 #5
0
ファイル: ehci-timer.c プロジェクト: AshishNamdev/linux
/* Poll the STS_HALT status bit; see when a dead controller stops */
static void ehci_handle_controller_death(struct ehci_hcd *ehci)
{
	if (!(ehci_readl(ehci, &ehci->regs->status) & STS_HALT)) {

		/* Give up after a few milliseconds */
		if (ehci->died_poll_count++ < 5) {
			/* Try again later */
			ehci_enable_event(ehci, EHCI_HRTIMER_POLL_DEAD, true);
			return;
		}
		ehci_warn(ehci, "Waited too long for the controller to stop, giving up\n");
	}

	/* Clean up the mess */
	ehci->rh_state = EHCI_RH_HALTED;
	ehci_writel(ehci, 0, &ehci->regs->configured_flag);
	ehci_writel(ehci, 0, &ehci->regs->intr_enable);
	ehci_work(ehci);
	end_unlink_async(ehci);

	/* Not in process context, so don't try to reset the controller */
}