EHCI: HSIC: Increase IAA watchdog timeout to 100ms
In order to remove queue heads(QH) from Asynchronous Schedule Interrupt on Async Advance(IAA) bit is used in USBCMD as doorbell by ehci driver to handshake with host controller. When the host controller has evicted all appropriate cached schedule states, then the host controller will assert an interrupt which indicates ehci driver that it is safe to modify a removed queue head from the asynchronous list. EHCI driver walks through the asynchronous schedule list to search for the QH(say QH1) which needs to be unlinked from HW. It removes QH1 from the list, sets ehci->reclaim points to QH1 and starts iaa watchdog timer after setting IAAD bit in USBCMD register. Before getting IAAD interrupt for QH1, rest of other interface drives can also issue unlinking of their QHs which get added to the list of QHs to be removed and pointed by ehci->reclaim. It is possible that IAAD interrupt gets delayed for more than current watchdog timeout value. This causes watchdog handler to finish the unlinking process of QH1 with ehci lock held. Unlinking process ends by setting QH1's next pointer to NULL, ehci->reclaim pointing to next QH to be unlinked(say QH2) and calling qh_completions() to retire all the transfer descriptor associated with QH1. qh_completions() releases ehci->lock in ehci_urb_done(). There is a possibility of controller asserting IAAD interrupt during this time on other core. After ehci lock is released, ehci irq handler gets a chance to acquire ehci lock and execute which results in premature unlinking of QH2, since ehci->reclaim now points to QH2. QH2 is not yet removed from the asynchronous list and ehci driver has not initiated IAAD handshake for QH2. Similarly unlinking ends for QH2 by setting QH2's next qh pointer to NULL, since QH2 is not yet removed from asynchronous list, this breaks the list. Due to this racing between IAAD interrupt and watchdog timer interrupt ehci driver loses track of which IAAD interrupt triggered for which QH. This results in NULL pointer dereference while searching for subsequent QHs to be unlinked, in already broken asynchronous list. Hence increase the IAA watchdog timeout value from 10ms to a higher value of 100ms. Higher timeout value avoids the race between IAAD interrupt and IAA watchdog handler and allows IAAD interrupt to finish the unlinking of QH. Watchdog handler is still be used to take care of scenarios when controller does not generate IAAD interrupt for some reason (which is rare, but possible). CRs-Fixed: 396250 Change-Id: Id1deccf834ca1108121c6533e016b9b3f5fc0ff2 Signed-off-by:Hemant Kumar <hemantk@codeaurora.org> (cherry picked from commit 8a657de16d301e1bfab7ba69349446720d4a70e3) Signed-off-by:
Sudhir Sharma <sudsha@codeaurora.org>
Loading
Please sign in to comment