> On Apr 28, 2016, at 7:19 AM, Heyi Guo <heyi....@linaro.org> wrote: > > > > On 04/28/2016 11:17 AM, Andrew Fish wrote: >>> On Apr 27, 2016, at 8:10 PM, Ni, Ruiyu <ruiyu...@intel.com> wrote: >>> >>>> -----Original Message----- >>>> From: edk2-devel [mailto:edk2-devel-boun...@lists.01.org] On Behalf Of >>>> Heyi Guo >>>> Sent: Saturday, April 23, 2016 4:54 PM >>>> To: edk2-devel@lists.01.org >>>> Cc: Kinney, Michael D <michael.d.kin...@intel.com>; Heyi Guo >>>> <heyi....@linaro.org>; Tian, Feng <feng.t...@intel.com>; >>>> Zeng, Star <star.z...@intel.com> >>>> Subject: [edk2] [PATCH] MdeModulePkg/TerminalDxe: Set polling rate by >>>> serial IO mode >>>> >>>> Calculate serial input polling rate according to parameters from >>>> serial IO mode as below, to fix potential input truncation. >>>> >>>> Polling interval (100ns) = >>>> FifoDepth * (StartBit + DataBits + StopBits + ParityBits) * 10,000,000 >>>> / BaudRate >>>> (StopBits is assumed to be 1 and ParityBits is ignored for simplicity. >>>> >>>> However, as the event is time sensitive, we need to align the interval >>>> to timer interrupt period to make sure the event will be triggered at >>>> the expected rate. E.g. if the interval is 2.7ms and timer interrupt >>>> period is 1ms, the event will be triggered by time slice sequence as >>>> below: >>>> 3ms 3ms 2ms 3ms 3ms 2ms... >>>> >>>> In such case we will adjust the polling interval to be 2ms. >>> Heyi, >>> I remember we had a discussion about the polling interval calculation >>> equation a month ago. The equation used in the patch looks good to me. >>> Because the timer handler is called sometimes every 3ms but not 2.7ms >>> resulting the key loss? >>> Just want to confirm with you. >>> >> Is it safe to make assumptions based on an implementation of an AP? Other >> platforms could be using different code? >> >> Thanks, >> >> Andrew Fish > Michael has similar concern and we will try using standard UEFI services or > protocols to achieve the timer interrupt period. >
I know Kinney mentioned not to use PI APIs, but this sounds like you are making assumptions about the implementation. A lot of the EFI APIs are specified as will delay at least X 100 ns, and with no quality of service guarantee. So you need to code to that assumption, not how a specific timer driver works. Thanks, Andrew Fish > Thanks. > > Heyi >> >>> Regards, >>> Ray >>> >>>> Contributed-under: TianoCore Contribution Agreement 1.0 >>>> Signed-off-by: Heyi Guo <heyi....@linaro.org> >>>> Cc: Feng Tian <feng.t...@intel.com> >>>> Cc: Star Zeng <star.z...@intel.com> >>>> Cc: Michael D Kinney <michael.d.kin...@intel.com> >>>> --- >>>> .../Universal/Console/TerminalDxe/Terminal.c | 5 +- >>>> .../Universal/Console/TerminalDxe/Terminal.h | 28 ++++++- >>>> .../Universal/Console/TerminalDxe/TerminalConIn.c | 92 >>>> ++++++++++++++++++++++ >>>> .../Universal/Console/TerminalDxe/TerminalDxe.inf | 1 + >>>> 4 files changed, 123 insertions(+), 3 deletions(-) >>>> >>>> diff --git a/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.c >>>> b/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.c >>>> index 6fde3b2..2944707 100644 >>>> --- a/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.c >>>> +++ b/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.c >>>> @@ -71,6 +71,7 @@ TERMINAL_DEV mTerminalDevTemplate = { >>>> }, >>>> NULL, // TerminalConsoleModeData >>>> 0, // SerialInTimeOut >>>> + 0, // KeyboardTimerInterval >>>> >>>> NULL, // RawFifo >>>> NULL, // UnicodeFiFo >>>> @@ -984,10 +985,12 @@ TerminalDriverBindingStart ( >>>> ); >>>> ASSERT_EFI_ERROR (Status); >>>> >>>> + TerminalDevice->KeyboardTimerInterval = GetKeyboardTimerInterval >>>> (Mode); >>>> + >>>> Status = gBS->SetTimer ( >>>> TerminalDevice->TimerEvent, >>>> TimerPeriodic, >>>> - KEYBOARD_TIMER_INTERVAL >>>> + TerminalDevice->KeyboardTimerInterval >>>> ); >>>> ASSERT_EFI_ERROR (Status); >>>> >>>> diff --git a/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.h >>>> b/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.h >>>> index 269d2ae..a1ff595 100644 >>>> --- a/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.h >>>> +++ b/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.h >>>> @@ -28,6 +28,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, >>>> EITHER EXPRESS OR IMPLIED. >>>> #include <Protocol/DevicePath.h> >>>> #include <Protocol/SimpleTextIn.h> >>>> #include <Protocol/SimpleTextInEx.h> >>>> +#include <Protocol/Timer.h> >>>> >>>> #include <Library/DebugLib.h> >>>> #include <Library/UefiDriverEntryPoint.h> >>>> @@ -68,8 +69,6 @@ typedef struct { >>>> UINTN Rows; >>>> } TERMINAL_CONSOLE_MODE_DATA; >>>> >>>> -#define KEYBOARD_TIMER_INTERVAL 200000 // 0.02s >>>> - >>>> #define TERMINAL_DEV_SIGNATURE SIGNATURE_32 ('t', 'm', 'n', 'l') >>>> >>>> #define TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE SIGNATURE_32 ('t', 'm', >>>> 'e', 'n') >>>> @@ -91,6 +90,7 @@ typedef struct { >>>> EFI_SIMPLE_TEXT_OUTPUT_MODE SimpleTextOutputMode; >>>> TERMINAL_CONSOLE_MODE_DATA *TerminalConsoleModeData; >>>> UINTN SerialInTimeOut; >>>> + UINT64 KeyboardTimerInterval; >>>> RAW_DATA_FIFO *RawFiFo; >>>> UNICODE_FIFO *UnicodeFiFo; >>>> EFI_KEY_FIFO *EfiKeyFiFo; >>>> @@ -1358,4 +1358,28 @@ TerminalConInTimerHandler ( >>>> IN EFI_EVENT Event, >>>> IN VOID *Context >>>> ); >>>> + >>>> +/** >>>> + Calculate input polling timer interval by serial IO mode. >>>> + >>>> + @param Mode Pointer to serial IO mode. >>>> + >>>> + @retval The required polling timer interval in 100ns. >>>> + >>>> +**/ >>>> +UINT64 >>>> +GetKeyboardTimerInterval ( >>>> + IN EFI_SERIAL_IO_MODE *Mode >>>> + ); >>>> + >>>> +/** >>>> + Update period of polling timer event. >>>> + >>>> + @param TerminalDevice The terminal device to update. >>>> +**/ >>>> +VOID >>>> +UpdatePollingRate ( >>>> + IN TERMINAL_DEV *TerminalDevice >>>> + ); >>>> + >>>> #endif >>>> diff --git a/MdeModulePkg/Universal/Console/TerminalDxe/TerminalConIn.c >>>> b/MdeModulePkg/Universal/Console/TerminalDxe/TerminalConIn.c >>>> index 3be877b..e7788a0 100644 >>>> --- a/MdeModulePkg/Universal/Console/TerminalDxe/TerminalConIn.c >>>> +++ b/MdeModulePkg/Universal/Console/TerminalDxe/TerminalConIn.c >>>> @@ -15,6 +15,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, >>>> EITHER EXPRESS OR IMPLIED. >>>> >>>> #include "Terminal.h" >>>> >>>> +EFI_TIMER_ARCH_PROTOCOL *gTimer; >>>> >>>> /** >>>> Reads the next keystroke from the input device. The WaitForKey Event can >>>> @@ -502,6 +503,94 @@ TerminalConInWaitForKey ( >>>> } >>>> >>>> /** >>>> + Calculate input polling timer interval by serial IO mode. >>>> + >>>> + @param Mode Pointer to serial IO mode. >>>> + >>>> + @retval The required polling timer interval in 100ns. >>>> + >>>> +**/ >>>> +UINT64 >>>> +GetKeyboardTimerInterval ( >>>> + IN EFI_SERIAL_IO_MODE *Mode >>>> + ) >>>> +{ >>>> + UINT32 FifoDepth; >>>> + UINT64 BaudRate; >>>> + UINT64 Interval; >>>> + UINT64 TimerPeriod; >>>> + EFI_STATUS Status; >>>> + >>>> + // Make some assumption if the values are not suitable for calculating. >>>> + BaudRate = Mode->BaudRate; >>>> + if (BaudRate == 0) { >>>> + BaudRate = 115200; >>>> + } >>>> + FifoDepth = Mode->ReceiveFifoDepth; >>>> + if (FifoDepth == 0) { >>>> + FifoDepth = 1; >>>> + } >>>> + >>>> + // We assume stop bits to be 1 and ignore parity bit to make it simple >>>> + // and fast enough to poll. >>>> + Interval = DivU64x64Remainder ( >>>> + FifoDepth * (1 + Mode->DataBits + 1) * 10000000, >>>> + Mode->BaudRate, >>>> + NULL >>>> + ); >>>> + >>>> + // As this is a time sensitive event, we still need to align the >>>> + // interval to timer interrupt period. >>>> + if (gTimer == NULL) { >>>> + Status = gBS->LocateProtocol ( >>>> + &gEfiTimerArchProtocolGuid, >>>> + EFI_NATIVE_INTERFACE, >>>> + (VOID **) &gTimer >>>> + ); >>>> + ASSERT_EFI_ERROR (Status); >>>> + } >>>> + >>>> + Status = gTimer->GetTimerPeriod (gTimer, &TimerPeriod); >>>> + ASSERT_EFI_ERROR (Status); >>>> + >>>> + if (Interval <= TimerPeriod) { >>>> + return TimerPeriod; >>>> + } >>>> + return MultU64x64 (DivU64x64Remainder (Interval, TimerPeriod, NULL), >>>> TimerPeriod); >>>> +} >>>> + >>>> + >>>> +/** >>>> + Update period of polling timer event. >>>> + >>>> + @param TerminalDevice The terminal device to update. >>>> +**/ >>>> +VOID >>>> +UpdatePollingRate ( >>>> + IN TERMINAL_DEV *TerminalDevice >>>> + ) >>>> +{ >>>> + UINT64 NewInterval; >>>> + EFI_STATUS Status; >>>> + >>>> + NewInterval = GetKeyboardTimerInterval (TerminalDevice->SerialIo->Mode); >>>> + >>>> + if (TerminalDevice->KeyboardTimerInterval == NewInterval) { >>>> + return; >>>> + } >>>> + >>>> + Status = gBS->SetTimer ( >>>> + TerminalDevice->TimerEvent, >>>> + TimerPeriodic, >>>> + NewInterval >>>> + ); >>>> + ASSERT_EFI_ERROR (Status); >>>> + >>>> + TerminalDevice->KeyboardTimerInterval = NewInterval; >>>> +} >>>> + >>>> + >>>> +/** >>>> Timer handler to poll the key from serial. >>>> >>>> @param Event Indicates the event that invoke this >>>> function. >>>> @@ -560,6 +649,9 @@ TerminalConInTimerHandler ( >>>> TerminalDevice->SerialInTimeOut = SerialInTimeOut; >>>> } >>>> } >>>> + >>>> + UpdatePollingRate (TerminalDevice); >>>> + >>>> // >>>> // Check whether serial buffer is empty. >>>> // Skip the key transfer loop only if the SerialIo protocol instance >>>> diff --git a/MdeModulePkg/Universal/Console/TerminalDxe/TerminalDxe.inf >>>> b/MdeModulePkg/Universal/Console/TerminalDxe/TerminalDxe.inf >>>> index 0780296..dfd5035 100644 >>>> --- a/MdeModulePkg/Universal/Console/TerminalDxe/TerminalDxe.inf >>>> +++ b/MdeModulePkg/Universal/Console/TerminalDxe/TerminalDxe.inf >>>> @@ -84,6 +84,7 @@ >>>> gEfiSimpleTextInProtocolGuid ## BY_START >>>> gEfiSimpleTextInputExProtocolGuid ## BY_START >>>> gEfiSimpleTextOutProtocolGuid ## BY_START >>>> + gEfiTimerArchProtocolGuid ## CONSUMES >>>> >>>> [Pcd] >>>> gEfiMdePkgTokenSpaceGuid.PcdDefaultTerminalType ## >>>> SOMETIMES_CONSUMES >>>> -- >>>> 2.7.0 >>>> >>>> _______________________________________________ >>>> edk2-devel mailing list >>>> edk2-devel@lists.01.org >>>> https://lists.01.org/mailman/listinfo/edk2-devel >>> _______________________________________________ >>> edk2-devel mailing list >>> edk2-devel@lists.01.org >>> https://lists.01.org/mailman/listinfo/edk2-devel > > _______________________________________________ > edk2-devel mailing list > edk2-devel@lists.01.org > https://lists.01.org/mailman/listinfo/edk2-devel _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel