PMUFW: PM: binding: Fixed bug of not handling multiple simultaneous IPIs

-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 <mirela.simonovic@aggios.com>
Acked-by: Sören Brinkmann <soren.brinkmann@xilinx.com>
Acked-by: Jyotheeswar Reddy Mutthareddyvari <jyothee@xilinx.com>
This commit is contained in:
Mirela Simonovic 2015-05-31 21:13:52 -07:00 committed by Nava kishore Manne
parent 8255c72de3
commit 8fdbe8728d
5 changed files with 31 additions and 10 deletions

View file

@ -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;
}

View file

@ -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);

View file

@ -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;
}

View file

@ -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:

View file

@ -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