lists.openwall.net | lists / announce owl-users owl-dev john-users john-dev passwdqc-users yescrypt popa3d-users / oss-security kernel-hardening musl sabotage tlsify passwords / crypt-dev xvendor / Bugtraq Full-Disclosure linux-kernel linux-netdev linux-ext4 linux-hardening linux-cve-announce PHC | |
Open Source and information security mailing list archives
| ||
|
Message-ID: <e9fc3199-234e-911e-fff8-734225c3f346@collabora.com> Date: Thu, 26 Jan 2023 17:16:10 +0100 From: AngeloGioacchino Del Regno <angelogioacchino.delregno@...labora.com> To: Nícolas F. R. A. Prado <nfraprado@...labora.com> Cc: thierry.reding@...il.com, u.kleine-koenig@...gutronix.de, matthias.bgg@...il.com, weiqing.kong@...iatek.com, jitao.shi@...iatek.com, linux-pwm@...r.kernel.org, linux-arm-kernel@...ts.infradead.org, linux-mediatek@...ts.infradead.org, linux-kernel@...r.kernel.org, kernel@...labora.com Subject: Re: [PATCH 2/2] pwm: mtk-disp: Configure double buffering before reading in .get_state() Il 26/01/23 17:09, Nícolas F. R. A. Prado ha scritto: > On Thu, Jan 26, 2023 at 04:24:29PM +0100, AngeloGioacchino Del Regno wrote: >> Il 26/01/23 16:19, Nícolas F. R. A. Prado ha scritto: >>> On Mon, Jan 23, 2023 at 05:06:15PM +0100, AngeloGioacchino Del Regno wrote: >>>> The DISP_PWM controller's default behavior is to always use register >>>> double buffering: all reads/writes are then performed on shadow >>>> registers instead of working registers and this becomes an issue >>>> in case our chosen configuration in Linux is different from the >>>> default (or from the one that was pre-applied by the bootloader). >>>> >>>> An example of broken behavior is when the controller is configured >>>> to use shadow registers, but this driver wants to configure it >>>> otherwise: what happens is that the .get_state() callback is called >>>> right after registering the pwmchip and checks whether the PWM is >>>> enabled by reading the DISP_PWM_EN register; >>>> At this point, if shadow registers are enabled but their content >>>> was not committed before booting Linux, we are *not* reading the >>>> current PWM enablement status, leading to the kernel knowing that >>>> the hardware is actually enabled when, in reality, it's not. >>>> >>>> The aforementioned issue emerged since this driver was fixed with >>>> commit 0b5ef3429d8f ("pwm: mtk-disp: Fix the parameters calculated >>>> by the enabled flag of disp_pwm") making it to read the enablement >>>> status from the right register. >>>> >>>> Configure the controller in the .get_state() callback to avoid >>>> this desync issue and get the backlight properly working again. >>>> >>>> Fixes: 3f2b16734914 ("pwm: mtk-disp: Implement atomic API .get_state()") >>>> Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@...labora.com> >>>> --- >>>> drivers/pwm/pwm-mtk-disp.c | 10 ++++++++++ >>>> 1 file changed, 10 insertions(+) >>>> >>>> diff --git a/drivers/pwm/pwm-mtk-disp.c b/drivers/pwm/pwm-mtk-disp.c >>>> index 82b430d881a2..fe9593f968ee 100644 >>>> --- a/drivers/pwm/pwm-mtk-disp.c >>>> +++ b/drivers/pwm/pwm-mtk-disp.c >>>> @@ -196,6 +196,16 @@ static int mtk_disp_pwm_get_state(struct pwm_chip *chip, >>>> return err; >>>> } >>>> + /* >>>> + * Apply DISP_PWM_DEBUG settings to choose whether to enable or disable >>>> + * registers double buffer and manual commit to working register before >>>> + * performing any read/write operation >>>> + */ >>>> + if (mdp->data->bls_debug) >>> >>> I feel like this condition should be the same as in the apply() callback, since >>> they're doing the same write operation, so also have '&& !has_commit'. >>> >> >> The bls_debug register is used to both enable and/or disable various features, >> including the one that I'm targeting in this commit, which is disabling shadow >> registers. >> >> As I explained in the commit message, we don't want to - and cannot - assume that >> the bootloader doesn't *reset* the backlight controller before booting Linux: a >> reset would re-enable the shadow registers, and this function being called as >> first to check the backlight EN status may fail to do so. >> >> This is as well true in the opposite situation where, in the future, we may want >> to set shadow registers ON, while the bootloader sets them OFF before booting: >> adding a (x && !has_commit) check in this branch would defeat that purpose and >> make this commit... well.. partially broken! :-) > > Makes sense, but in that case shouldn't we drop the (&& !has_commit) in the > check of the previous commit too? I get that in the pwm's core current logic, No. The previous commit checks !has_commit to select a register write strategy between "shadow -> commit" and "working registers - no commit necessary". If you drop that check from the previous commit, how can you choose the write strategy to use?! :-) You can't rely on reading the bls_debug register, either, because it may be holding different values compared to what we want due to, for example, a reset and you can't rely on checking bls_debug_mask because in the future this kind of selector may be residing in an entirely different register. > get_state() is run before apply(), but given that we also write the debug > register in apply(), we're not relying on that. So as it currently stands, if in > the future the bootloader sets shadow registers OFF, and we want to set them ON, > and we call apply() before having called get_state(), we'd be back to the broken > behavior. No, because the default BLS_DEBUG register value at IP reset is 0 - where 0 means "do not disable commit, do not disable shadow register read, do not disable shadow register write" :-) Cheers, Angelo > > Thanks, > Nícolas > >> >> Cheers! >> Angelo >> >>> Reviewed-by: Nícolas F. R. A. Prado <nfraprado@...labora.com> >>> Tested-by: Nícolas F. R. A. Prado <nfraprado@...labora.com> >>> >>> On MT8192 Asurada Spherion. >>> >>> Thanks, >>> Nícolas >>> >>>> + mtk_disp_pwm_update_bits(mdp, mdp->data->bls_debug, >>>> + mdp->data->bls_debug_mask, >>>> + mdp->data->bls_debug_mask); >>>> + >>>> rate = clk_get_rate(mdp->clk_main); >>>> con0 = readl(mdp->base + mdp->data->con0); >>>> con1 = readl(mdp->base + mdp->data->con1); >>>> -- >>>> 2.39.0 >>>> >>>> >> >>
Powered by blists - more mailing lists