From: Laszlo Ersek <lersek@redhat.com>
To: "Zeng, Star" <star.zeng@intel.com>,
edk2-devel-01 <edk2-devel@lists.01.org>
Cc: Gerd Hoffmann <kraxel@redhat.com>,
"Wang, Jian J" <jian.j.wang@intel.com>,
"Ni, Ruiyu" <ruiyu.ni@intel.com>,
"Shi, Steven" <steven.shi@intel.com>
Subject: Re: [PATCH] MdeModulePkg/EhciDxe: fix host controller reset condition in BindingStart
Date: Wed, 5 Sep 2018 12:13:50 +0200 [thread overview]
Message-ID: <cb0f5949-3297-72c1-3382-1205556c212d@redhat.com> (raw)
In-Reply-To: <0C09AFA07DD0434D9E2A0C6AEB0483103BBB55E8@shsmsx102.ccr.corp.intel.com>
On 09/05/18 11:55, Zeng, Star wrote:
> I agree to commit this patch first. Reviewed-by: Star Zeng <star.zeng@intel.com> to this patch.
Thanks!
Steven, can you confirm the patch fixes the issue you saw?
> To further enhance with an abstracted function, how about like below?
>
> BOOLEAN
> EhcIsDebugPortInUse (
> IN CONST USB2_HC_DEV *Ehc,
> IN UINT8 *PortNumber OPTIONAL
> )
Yes, that works too; I had thought of this. I didn't suggest it because
in case the programmer wants to pass a known constant for PortNumber,
they need a separate variable, which is a bit inconvenient. But, I agree
that given the current source code, that won't happen. I'll post another
patch for this.
Thanks!
Laszlo
>
> Thanks,
> Star
> -----Original Message-----
> From: Laszlo Ersek [mailto:lersek@redhat.com]
> Sent: Tuesday, September 4, 2018 6:38 PM
> To: Zeng, Star <star.zeng@intel.com>; edk2-devel-01 <edk2-devel@lists.01.org>
> Cc: Gerd Hoffmann <kraxel@redhat.com>; Wang, Jian J <jian.j.wang@intel.com>; Ni, Ruiyu <ruiyu.ni@intel.com>; Shi, Steven <steven.shi@intel.com>
> Subject: Re: [PATCH] MdeModulePkg/EhciDxe: fix host controller reset condition in BindingStart
>
> On 09/04/18 03:27, Zeng, Star wrote:
>> Oh, yes. Got the point, the patch is correct indeed. :) Thanks for the
>> explanation.
>>
>> Maybe, an abstracted function will make the logic more clear, like
>> EhcIsDebugPortInUse().
>> What do you think?
>
> Haha, I thought of almost exactly the same name (just "IsDebugPortInUse()", and making it STATIC) :) Ultimately however, I didn't propose it, for the following reason:
>
> There is another conditional hunk added by commit 09943f5ecc0f, namely in the EhcGetRootHubPortStatus() function. In the Bugzilla, I wrote:
>
>> - in the EhcGetRootHubPortStatus() function, if the status request
>> refers to the debug port, and the debug port is in use, then we
>> don't actually fetch the status of the port, we just report
>> status=0, status_change=0.
>
> and the code goes like this:
>
>> if ((Ehc->DebugPortNum != 0) && (PortNumber == (Ehc->DebugPortNum - 1))) {
>> DbgCtrlStatus = EhcReadDbgRegister(Ehc, 0);
>> if ((DbgCtrlStatus & (USB_DEBUG_PORT_IN_USE | USB_DEBUG_PORT_OWNER)) == (USB_DEBUG_PORT_IN_USE | USB_DEBUG_PORT_OWNER)) {
>> goto ON_EXIT;
>> }
>> }
>
> In this case, we not only check whether the host controller has a debug port (*any* port) and that port is in use, we also check whether the status request refers specifically to that port.
>
> This additional restriction is not easy to express with EhcIsDebugPortInUse(). If we wrote
>
> if (EhcIsDebugPortInUse () && (PortNumber == (Ehc->DebugPortNum - 1))) {
> goto ON_EXIT;
> }
>
> then that wouldn't be 100% the same, because in this reformulated condition, we could access the MMIO debug status register *before* we decided that the root hub port status request refers to *another* port.
>
> How about the following function:
>
>> /**
>> Check whether the host controller has an in-use debug port.
>>
>> @param[in] Ehc The Enhanced Host Controller to query.
>>
>> @param[in] PortNumber If PortNumber is in [0, MAX_UINT8], then query whether
>> PortNumber on Ehc is an in-use debug port. Otherwise,
>> query whether Ehc has any in-use debug port.
>>
>> @retval TRUE PortNumber on Ehc is an in-use debug port (if PortNumber is in
>> [0, MAX_UINT8]), or some port on Ehc is an in-use debug port
>> (otherwise).
>>
>> @retval FALSE PortNumber on Ehc is not an in-use debug port (if PortNumber
>> is in [0, MAX_UINT8]), or no port on Ehc is an in-use debug
>> port (otherwise).
>> **/
>> BOOLEAN
>> EhcIsDebugPortInUse (
>> IN CONST USB2_HC_DEV *Ehc,
>> IN INT16 PortNumber
>> )
>> {
>> UINT32 State;
>> UINT32 Mask;
>>
>> if (Ehc->DebugPortNum == 0) {
>> return FALSE;
>> }
>>
>> if (PortNumber >= 0 && PortNumber <= MAX_UINT8 &&
>> (UINT8)PortNumber != Ehc->DebugPortNum - 1) {
>> return FALSE;
>> }
>>
>> State = EhcReadDbgRegister(Ehc, 0);
>> Mask = USB_DEBUG_PORT_IN_USE | USB_DEBUG_PORT_OWNER;
>> return (State & Mask) == Mask;
>> }
>
> Then we can call
>
> EhcIsDebugPortInUse (Ehc, -1)
>
> in EhcReset() and EhcDriverBindingStart(), and we can call
>
> EhcIsDebugPortInUse (Ehc, PortNumber)
>
> in EhcGetRootHubPortStatus().
>
> What do you think?
>
> ... Anyway, I would like to append such a patch separately to the series
> -- I'd like to keep the bugfix and the refactoring separate.
>
> Thanks,
> Laszlo
>
>> -----Original Message-----
>> From: Laszlo Ersek [mailto:lersek@redhat.com]
>> Sent: Monday, September 3, 2018 7:46 PM
>> To: Zeng, Star <star.zeng@intel.com>; edk2-devel-01
>> <edk2-devel@lists.01.org>
>> Cc: Gerd Hoffmann <kraxel@redhat.com>; Wang, Jian J
>> <jian.j.wang@intel.com>; Ni, Ruiyu <ruiyu.ni@intel.com>; Shi, Steven
>> <steven.shi@intel.com>
>> Subject: Re: [PATCH] MdeModulePkg/EhciDxe: fix host controller reset
>> condition in BindingStart
>>
>> Hi Star,
>>
>> On 09/03/18 10:35, Zeng, Star wrote:
>>> Good finding.
>>>
>>> There is another place at
>>> https://github.com/tianocore/edk2/blob/master/MdeModulePkg/Bus/Pci/Eh
>>> c
>>> iDxe/Ehci.c#L150 which has similar logic, please update it also.
>>
>> I audited all the "DebugPortNum" checks that were added by commit 09943f5ecc0f, here:
>>
>> https://bugzilla.tianocore.org/show_bug.cgi?id=1129#c16
>>
>> The location that you mention is in the EhcReset() function. It is covered in my analysis linked above, and it needs no update, because it is correct.
>>
>> Namely, in EhcReset(), the condition captures when the reset must be
>> *skipped*. For that, the condition is,
>>
>> one of the USB ports on the host controller is a debug port, AND
>> the debug port is in use
>>
>> When this condition holds, we set Status to EFI_SUCCESS, and jump to
>> ON_EXIT (that is, we skip the re-set and return success without doing
>> anything). This is written in C as
>>
>>> if (Ehc->DebugPortNum != 0) {
>>> DbgCtrlStatus = EhcReadDbgRegister(Ehc, 0);
>>> if ((DbgCtrlStatus & (USB_DEBUG_PORT_IN_USE | USB_DEBUG_PORT_OWNER)) == (USB_DEBUG_PORT_IN_USE | USB_DEBUG_PORT_OWNER)) {
>>> Status = EFI_SUCCESS;
>>> goto ON_EXIT;
>>> }
>>> }
>>
>> However, at the location that the patch modifies, the condition refers to the *opposite* case, that is, when the reset must *not* be skipped.
>> For that, we have to negate the condition seen above.
>>
>> For the negation, we use De Morgan's Laws, that is:
>>
>> !(A && B) == (!A || !B)
>>
>> That is:
>>
>> *no* USB port on the host controller is a debug port, *OR*
>> the debug port is *not* in use
>>
>> And this is written, in C, as
>>
>>> if (Ehc->DebugPortNum == 0) {
>>> EhcResetHC (Ehc, EHC_RESET_TIMEOUT);
>>> } else {
>>> State = EhcReadDbgRegister(Ehc, 0);
>>> if ((State & (USB_DEBUG_PORT_IN_USE | USB_DEBUG_PORT_OWNER)) != (USB_DEBUG_PORT_IN_USE | USB_DEBUG_PORT_OWNER)) {
>>> EhcResetHC (Ehc, EHC_RESET_TIMEOUT);
>>> }
>>> }
>>
>> The original commit (09943f5ecc0f) got the EhcReset() modification right (that is, the condition is already correct); what it got wrong was the negation of the condition, for EhcDriverBindingStart(). That's the only thing we have to correct in this patch.
>>
>> Thanks,
>> Laszlo
>>
>>
>>>
>>>
>>> Thanks,
>>> Star
>>> -----Original Message-----
>>> From: Laszlo Ersek [mailto:lersek@redhat.com]
>>> Sent: Friday, August 31, 2018 10:04 PM
>>> To: edk2-devel-01 <edk2-devel@lists.01.org>
>>> Cc: Gerd Hoffmann <kraxel@redhat.com>; Wang, Jian J
>>> <jian.j.wang@intel.com>; Ni, Ruiyu <ruiyu.ni@intel.com>; Zeng, Star
>>> <star.zeng@intel.com>; Shi, Steven <steven.shi@intel.com>
>>> Subject: [PATCH] MdeModulePkg/EhciDxe: fix host controller reset
>>> condition in BindingStart
>>>
>>> Commit 09943f5ecc0f ("MdeModulePkg: Skip to manage usb debug port in
>>> EDKII EHCI driver if it's used by usb debug port driver", 2012-04-28)
>>> made the host controller reset in EhcDriverBindingStart() conditional.
>>> The intent was to avoid the reset when
>>> - one of the USB ports on the host controller was a Debug Port, AND
>>> - the Debug Port was in use.
>>>
>>> This translates to the following positive condition: reset the controller only if:
>>> - no USB port on the host controller is a Debug Port, OR
>>> - the Debug Port is not in use.
>>>
>>> Commit 09943f5ecc0f failed to implement the first subcondition, and thus the result is too strict now (for resetting the host controller). Relax it to the correct condition.
>>>
>>> This issue was found by Steven Shi on QEMU. QEMU's EHCI device model does not have a Debug Port. In repeated disconnect / connect cycles, the controller is never reset in EhcDriverBindingStart(), therefore the devices on the controller are never re-enumerated after a disconnect.
>>>
>>> Cc: Gerd Hoffmann <kraxel@redhat.com>
>>> Cc: Jian J Wang <jian.j.wang@intel.com>
>>> Cc: Ruiyu Ni <ruiyu.ni@intel.com>
>>> Cc: Star Zeng <star.zeng@intel.com>
>>> Cc: Steven Shi <steven.shi@intel.com>
>>> Reported-by: Steven Shi <steven.shi@intel.com>
>>> Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=1129
>>> Fixes: 09943f5ecc0fbc0c98c511c82703a0ba3b2b5819
>>> Contributed-under: TianoCore Contribution Agreement 1.1
>>> Signed-off-by: Laszlo Ersek <lersek@redhat.com>
>>> ---
>>>
>>> Notes:
>>> Repo: https://github.com/lersek/edk2.git
>>> Branch: ehci_start_reset_1129
>>>
>>> MdeModulePkg/Bus/Pci/EhciDxe/Ehci.c | 4 +++-
>>> 1 file changed, 3 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/MdeModulePkg/Bus/Pci/EhciDxe/Ehci.c
>>> b/MdeModulePkg/Bus/Pci/EhciDxe/Ehci.c
>>> index 30ad2b2ffeef..89ed034b9093 100644
>>> --- a/MdeModulePkg/Bus/Pci/EhciDxe/Ehci.c
>>> +++ b/MdeModulePkg/Bus/Pci/EhciDxe/Ehci.c
>>> @@ -1916,11 +1916,13 @@ EhcDriverBindingStart (
>>> //
>>> if (FeaturePcdGet (PcdTurnOffUsbLegacySupport)) {
>>> EhcClearLegacySupport (Ehc);
>>> }
>>>
>>> - if (Ehc->DebugPortNum != 0) {
>>> + if (Ehc->DebugPortNum == 0) {
>>> + EhcResetHC (Ehc, EHC_RESET_TIMEOUT); } else {
>>> State = EhcReadDbgRegister(Ehc, 0);
>>> if ((State & (USB_DEBUG_PORT_IN_USE | USB_DEBUG_PORT_OWNER)) != (USB_DEBUG_PORT_IN_USE | USB_DEBUG_PORT_OWNER)) {
>>> EhcResetHC (Ehc, EHC_RESET_TIMEOUT);
>>> }
>>> }
>>> --
>>> 2.14.1.3.gb7cf6e02401b
>>>
>>
>
next prev parent reply other threads:[~2018-09-05 10:13 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-08-31 14:03 [PATCH] MdeModulePkg/EhciDxe: fix host controller reset condition in BindingStart Laszlo Ersek
2018-09-03 8:35 ` Zeng, Star
2018-09-03 11:45 ` Laszlo Ersek
2018-09-04 1:27 ` Zeng, Star
2018-09-04 10:38 ` Laszlo Ersek
2018-09-05 9:55 ` Zeng, Star
2018-09-05 10:13 ` Laszlo Ersek [this message]
2018-09-05 10:55 ` Shi, Steven
2018-09-05 12:03 ` Laszlo Ersek
2018-09-05 12:18 ` Laszlo Ersek
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-list from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=cb0f5949-3297-72c1-3382-1205556c212d@redhat.com \
--to=devel@edk2.groups.io \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox