From 8fdbe8728d8392acf2152089eab353d493a96bbb Mon Sep 17 00:00:00 2001 From: Mirela Simonovic Date: Sun, 31 May 2015 21:13:52 -0700 Subject: [PATCH] PMUFW: PM: binding: Fixed bug of not handling multiple simultaneous IPIs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit -There was a bug in pmu-fw/pm binding through IPIs, because of which in case of multiple IPI interrupts generated simultaneously only first interrupt was handled, other interrupts were lost -The bug existed because PM handles one request in each XPfw_PmIpiHandler invocation, and pmu-fw clears all bitfields in ISR register after PM handles request. Therefore, if multiple bits were set in ISR register (simultaneous IPI interrupts), only first one was handled and other bits were just cleared -XPfw_PmIpiHandler now returns status and through an argument pointer an IPI mask of master whose request has been handled -In xpfw_user_startup.c/PmIpiHandler, return of XPfw_PmIpiHandler is checked. If PM successfully handled IPI, only the bitfield of master whose request is handled is set (only that IPI interrupt is cleared). If something went wrong in PmIpiHandler/IPI0 case, we clear all bits set in ISR register, to avoid system hanging on this interrupt handler -In pm_master, a check whether the master owns given mask was performed by using '==' instead '&'. Therefore, when 2 masters generated interrupt at the same time, PM function that checks whether the IPI is PM related returned that the ISR value does not match any master. This bug is fixed Signed-off-by: Mirela Simonovic Acked-by: Sören Brinkmann Acked-by: Jyotheeswar Reddy Mutthareddyvari --- lib/sw_apps/zynqmp_pmufw/src/pm_binding.c | 16 ++++++++++++---- lib/sw_apps/zynqmp_pmufw/src/pm_binding.h | 2 +- lib/sw_apps/zynqmp_pmufw/src/pm_master.c | 2 +- .../zynqmp_pmufw/src/xpfw_user_startup.c | 19 ++++++++++++++++--- lib/sw_apps/zynqmp_pmufw/src/xpfw_version.h | 2 +- 5 files changed, 31 insertions(+), 10 deletions(-) diff --git a/lib/sw_apps/zynqmp_pmufw/src/pm_binding.c b/lib/sw_apps/zynqmp_pmufw/src/pm_binding.c index 5597e65c..e92b0dc7 100644 --- a/lib/sw_apps/zynqmp_pmufw/src/pm_binding.c +++ b/lib/sw_apps/zynqmp_pmufw/src/pm_binding.c @@ -64,6 +64,9 @@ void XPfw_PmInit(void) * XPfw_PmIpiHandler() - Call from IPI interrupt handler to process PM API call * @isrMask IPI's ISR register value. Needed to determine buffer holding the * payload + * @isrClr Pointer to a variable in which PM returns an ISR mask of the master + * whose request is handled (mask to write in ISR register to clear + * interrupt) * @apiId PM API id that was read from master's IPI buffer and validated as * existing * @@ -86,8 +89,7 @@ void XPfw_PmInit(void) * be cleared after this function returns to make PM API call * atomic. */ -int XPfw_PmIpiHandler(const u32 isrMask, - const u32 apiId) +int XPfw_PmIpiHandler(const u32 isrMask, const u32 apiId, u32* const isrClr) { int status = XST_SUCCESS; u32 i; @@ -96,8 +98,8 @@ int XPfw_PmIpiHandler(const u32 isrMask, u32 offset = 0U; const PmMaster* master = PmGetMasterByIpiMask(isrMask); - if (NULL == master) { - /* Never happens if IPI interrupt routine is implemented correctly */ + if ((NULL == isrClr) || (NULL == master)) { + /* Never happens if IPI irq handler is implemented correctly */ PmDbg("ERROR: IPI source not supported %d\n", isrMask); status = XST_INVALID_PARAM; goto done; @@ -113,6 +115,12 @@ int XPfw_PmIpiHandler(const u32 isrMask, PmProcessRequest(master, payload); + /* + * Master's bitfield in isr register will be cleared based on isrClr + * variable value (master's request is handled) + */ + *isrClr = master->ipiMask; + done: return status; } diff --git a/lib/sw_apps/zynqmp_pmufw/src/pm_binding.h b/lib/sw_apps/zynqmp_pmufw/src/pm_binding.h index b2811fa4..7fa25a73 100644 --- a/lib/sw_apps/zynqmp_pmufw/src/pm_binding.h +++ b/lib/sw_apps/zynqmp_pmufw/src/pm_binding.h @@ -58,7 +58,7 @@ void XPfw_PmInit(void); XPfw_PmIpiStatus XPfw_PmCheckIpiRequest(const u32 isrVal, u32* const apiId); /* Call from IPI interrupt routine to handle PM API request */ -int XPfw_PmIpiHandler(const u32 isrMask, const u32 apiId); +int XPfw_PmIpiHandler(const u32 isrMask, const u32 apiId, u32* const isrClr); /* Call from GPI2 interrupt routine to handle processor sleep request */ int XPfw_PmWfiHandler(const u32 srcMask); diff --git a/lib/sw_apps/zynqmp_pmufw/src/pm_master.c b/lib/sw_apps/zynqmp_pmufw/src/pm_master.c index d363fe5a..222cbc71 100644 --- a/lib/sw_apps/zynqmp_pmufw/src/pm_master.c +++ b/lib/sw_apps/zynqmp_pmufw/src/pm_master.c @@ -530,7 +530,7 @@ const PmMaster* PmGetMasterByIpiMask(const u32 mask) const PmMaster *mst = NULL; for (i = 0U; i < ARRAY_SIZE(pmAllMasters); i++) { - if (mask == pmAllMasters[i]->ipiMask) { + if (mask & pmAllMasters[i]->ipiMask) { mst = pmAllMasters[i]; break; } diff --git a/lib/sw_apps/zynqmp_pmufw/src/xpfw_user_startup.c b/lib/sw_apps/zynqmp_pmufw/src/xpfw_user_startup.c index e09c38d4..e9adf05e 100644 --- a/lib/sw_apps/zynqmp_pmufw/src/xpfw_user_startup.c +++ b/lib/sw_apps/zynqmp_pmufw/src/xpfw_user_startup.c @@ -46,8 +46,9 @@ #ifdef ENABLE_PM static void PmIpiHandler(const XPfw_Module_t *ModPtr, u32 IpiNum, u32 SrcMask) { - u32 isrVal, apiId; + u32 isrVal, isrClr, apiId; XPfw_PmIpiStatus ipiStatus; + XStatus status; switch (IpiNum) { case 0: @@ -56,12 +57,24 @@ static void PmIpiHandler(const XPfw_Module_t *ModPtr, u32 IpiNum, u32 SrcMask) ipiStatus = XPfw_PmCheckIpiRequest(isrVal, &apiId); if (XPFW_PM_IPI_IS_PM_CALL == ipiStatus) { /* Power management API processing */ - XPfw_PmIpiHandler(isrVal, apiId); + status = XPfw_PmIpiHandler(isrVal, apiId, &isrClr); + if (XST_SUCCESS == status) { + /* Clear only irq for handled PM request */ + XPfw_Write32(IPI_PMU_0_ISR, isrClr); + } } else { + status = XST_NO_FEATURE; fw_printf("MOD-%d: Non-PM IPI-%d call received\r\n", ModPtr->ModId, IpiNum); } - XPfw_Write32(IPI_PMU_0_ISR, isrVal); + if (XST_SUCCESS != status) { + /* + * Clear all irqs if something went wrong, to avoid + * system looping in interrupt handler because of error + */ + XPfw_Write32(IPI_PMU_0_ISR, isrVal); + fw_printf("ERROR #%d : IPI-%d\r\n", status, IpiNum); + } break; case 1: diff --git a/lib/sw_apps/zynqmp_pmufw/src/xpfw_version.h b/lib/sw_apps/zynqmp_pmufw/src/xpfw_version.h index 29571a21..b6aa7d60 100644 --- a/lib/sw_apps/zynqmp_pmufw/src/xpfw_version.h +++ b/lib/sw_apps/zynqmp_pmufw/src/xpfw_version.h @@ -1,4 +1,4 @@ #ifndef ZYNQMP_XPFW_VERSION__H_ #define ZYNQMP_XPFW_VERSION__H_ - #define ZYNQMP_XPFW_VERSION "2015.1-swbeta2-36-gccb91daa0515" + #define ZYNQMP_XPFW_VERSION "2015.1-swbeta2-37-g79629747082f" #endif