From edcaa01d217ce9a2a198cf537ca063acab13ef7f Mon Sep 17 00:00:00 2001 From: Yicong Yang Date: Mon, 13 Mar 2023 15:45:51 +0800 Subject: [PATCH 1/3] i2c: hisi: Avoid redundant interrupts mainline inclusion from mainline-v6.3-rc4 commit cc9812a3096d1986caca9a23bee99effc45c08df category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I8QL7I CVE: NA Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=cc9812a3096d1986caca9a23bee99effc45c08df ---------------------------------------------------------------------- After issuing all the messages we can disable the TX_EMPTY interrupts to avoid handling redundant interrupts. For doing a sinlge bus detection (i2cdetect -y -r 0) we can reduce ~97% interrupts (before ~12000 after ~400). Signed-off-by: Sheng Feng Signed-off-by: Yicong Yang Signed-off-by: Wolfram Sang Signed-off-by: lujunhua Signed-off-by: YunYi Yang --- drivers/i2c/busses/i2c-hisi.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/i2c/busses/i2c-hisi.c b/drivers/i2c/busses/i2c-hisi.c index 0b513064316e..4b67cb8baf23 100644 --- a/drivers/i2c/busses/i2c-hisi.c +++ b/drivers/i2c/busses/i2c-hisi.c @@ -320,6 +320,13 @@ static void hisi_i2c_xfer_msg(struct hisi_i2c_controller *ctlr) max_write == 0) break; } + + /* + * Disable the TX_EMPTY interrupt after finishing all the messages to + * avoid overwhelming the CPU. + */ + if (ctlr->msg_tx_idx == ctlr->msg_num) + hisi_i2c_disable_int(ctlr, HISI_I2C_INT_TX_EMPTY); } static irqreturn_t hisi_i2c_irq(int irq, void *context) -- Gitee From d9d9e7a3e1eb24a786c2669c4a2e66e95cd2c299 Mon Sep 17 00:00:00 2001 From: Yicong Yang Date: Mon, 13 Mar 2023 15:45:52 +0800 Subject: [PATCH 2/3] i2c: hisi: Only use the completion interrupt to finish the transfer mainline inclusion from mainline-v6.3-rc4 commit d98263512684a47e81bcb72a5408958ecd1e60b0 category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I8QL7I CVE: NA Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=d98263512684a47e81bcb72a5408958ecd1e60b0 ---------------------------------------------------------------------- The controller will always generate a completion interrupt when the transfer is finished normally or not. Currently we use either error or completion interrupt to finish, this may result the completion interrupt unhandled and corrupt the next transfer, especially at low speed mode. Since on error case, the error interrupt will come first then is the completion interrupt. So only use the completion interrupt to finish the whole transfer process. Fixes: d62fbdb99a85 ("i2c: add support for HiSilicon I2C controller") Reported-by: Sheng Feng Signed-off-by: Sheng Feng Signed-off-by: Yicong Yang Signed-off-by: Wolfram Sang Signed-off-by: lujunhua Signed-off-by: YunYi Yang --- drivers/i2c/busses/i2c-hisi.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-hisi.c b/drivers/i2c/busses/i2c-hisi.c index 4b67cb8baf23..55cee74fc3ac 100644 --- a/drivers/i2c/busses/i2c-hisi.c +++ b/drivers/i2c/busses/i2c-hisi.c @@ -352,7 +352,11 @@ static irqreturn_t hisi_i2c_irq(int irq, void *context) hisi_i2c_read_rx_fifo(ctlr); out: - if (int_stat & HISI_I2C_INT_TRANS_CPLT || ctlr->xfer_err) { + /* + * Only use TRANS_CPLT to indicate the completion. On error cases we'll + * get two interrupts, INT_ERR first then TRANS_CPLT. + */ + if (int_stat & HISI_I2C_INT_TRANS_CPLT) { hisi_i2c_disable_int(ctlr, HISI_I2C_INT_ALL); hisi_i2c_clear_int(ctlr, HISI_I2C_INT_ALL); complete(ctlr->completion); -- Gitee From 6e276f5595126a59429ea5e139bd2a78f2f9ef9f Mon Sep 17 00:00:00 2001 From: Yicong Yang Date: Tue, 1 Aug 2023 20:46:25 +0800 Subject: [PATCH 3/3] i2c: hisi: Only handle the interrupt of the driver's transfer mainline inclusion from mainline-v6.5-rc7 commit fff67c1b17ee093947bdcbac6f64d072e644159a category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I8QL7I CVE: NA Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=fff67c1b17ee ---------------------------------------------------------------------- The controller may be shared with other port, for example the firmware. Handle the interrupt from other sources will cause crash since some data are not initialized. So only handle the interrupt of the driver's transfer and discard others. Fixes: d62fbdb99a85 ("i2c: add support for HiSilicon I2C controller") Signed-off-by: Yicong Yang Reviewed-by: Andi Shyti Link: https://lore.kernel.org/r/20230801124625.63587-1-yangyicong@huawei.com Signed-off-by: Wolfram Sang Signed-off-by: Juan Zhou Signed-off-by: YunYi Yang --- drivers/i2c/busses/i2c-hisi.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/i2c/busses/i2c-hisi.c b/drivers/i2c/busses/i2c-hisi.c index 55cee74fc3ac..e6e40236e6ec 100644 --- a/drivers/i2c/busses/i2c-hisi.c +++ b/drivers/i2c/busses/i2c-hisi.c @@ -334,6 +334,14 @@ static irqreturn_t hisi_i2c_irq(int irq, void *context) struct hisi_i2c_controller *ctlr = context; u32 int_stat; + /* + * Don't handle the interrupt if cltr->completion is NULL. We may + * reach here because the interrupt is spurious or the transfer is + * started by another port (e.g. firmware) rather than us. + */ + if (!ctlr->completion) + return IRQ_NONE; + int_stat = readl(ctlr->iobase + HISI_I2C_INT_MSTAT); hisi_i2c_clear_int(ctlr, int_stat); if (!(int_stat & HISI_I2C_INT_ALL)) -- Gitee