From mboxrd@z Thu Jan 1 00:00:00 1970 From: Yadi Hu Subject: [PATCH] i2c-eg20t: fix race between i2c init and interrupt enable Date: Mon, 29 Aug 2016 10:56:55 +0800 Message-ID: <1472439415-4024-1-git-send-email-yadi.hu@windriver.com> Mime-Version: 1.0 Content-Type: text/plain Return-path: Received: from mail5.windriver.com ([192.103.53.11]:42328 "EHLO mail5.wrs.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1756190AbcH2C5g (ORCPT ); Sun, 28 Aug 2016 22:57:36 -0400 Sender: linux-i2c-owner@vger.kernel.org List-Id: linux-i2c@vger.kernel.org To: yadi.hu@windriver.com, jdelvare@suse.de, wsa@the-dreams.de Cc: linux-i2c@vger.kernel.org From: "Yadi.hu" the driver executes request_irq() function before the base address of i2c registers is remapped in kernel space. If i2c controller shares an interrupt line with other devices,it is possible that an interrupt arrives immediately after request_irq() is called. Since the interrupt handler pch_i2c_handler() is active, it will read its own register to determine if this interrupt was from its own device. At this moment, base address of i2c registers is not remapped in kernel space yet,so the INT handler access a unknown address and a error occurs. Bad IO access at port 0x18 (return inl(port)) Call Trace: [] warn_slowpath_common+0x73/0xa0 [] ? bad_io_access+0x45/0x50 [] ? bad_io_access+0x45/0x50 [] warn_slowpath_fmt+0x34/0x40 [] bad_io_access+0x45/0x50 [] ioread32+0x22/0x40 [] pch_i2c_handler+0x3b/0x120 [] handle_irq_event_percpu+0x64/0x330 [] handle_irq_event+0x3b/0x60 [] ? unmask_irq+0x30/0x30 [] handle_fasteoi_irq+0x50/0xe0 [] ? do_IRQ+0x48/0xc0 [] ? smp_apic_timer_interrupt+0x7f/0x17a [] ? common_interrupt+0x29/0x30 [] ? mwait_idle+0x8b/0x2c0 [] ? cpu_idle+0x9e/0xc0 [] ? rest_init+0x6c/0x74 [] ? start_kernel+0x311/0x318 [] ? repair_env_string+0x51/0x51 [] ? i386_start_kernel+0x78/0x7d ---[ end trace eb3a1028f468a140 ]--- i2c_eg20t 0000:05:0c.2: pch_i2c_handler :I2C-3 mode(0) is not supported Signed-off-by: Yadi.hu --- drivers/i2c/busses/i2c-eg20t.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/i2c/busses/i2c-eg20t.c b/drivers/i2c/busses/i2c-eg20t.c index 137125b..48483a5 100644 --- a/drivers/i2c/busses/i2c-eg20t.c +++ b/drivers/i2c/busses/i2c-eg20t.c @@ -773,13 +773,6 @@ static int pch_i2c_probe(struct pci_dev *pdev, /* Set the number of I2C channel instance */ adap_info->ch_num = id->driver_data; - ret = request_irq(pdev->irq, pch_i2c_handler, IRQF_SHARED, - KBUILD_MODNAME, adap_info); - if (ret) { - pch_pci_err(pdev, "request_irq FAILED\n"); - goto err_request_irq; - } - for (i = 0; i < adap_info->ch_num; i++) { pch_adap = &adap_info->pch_data[i].pch_adapter; adap_info->pch_i2c_suspended = false; @@ -808,16 +801,23 @@ static int pch_i2c_probe(struct pci_dev *pdev, } } + ret = request_irq(pdev->irq, pch_i2c_handler, IRQF_SHARED, + KBUILD_MODNAME, adap_info); + if (ret) { + pch_pci_err(pdev, "request_irq FAILED\n"); + goto err_request_irq; + } + pci_set_drvdata(pdev, adap_info); pch_pci_dbg(pdev, "returns %d.\n", ret); return 0; +err_request_irq: + pci_iounmap(pdev, base_addr); err_add_adapter: for (j = 0; j < i; j++) i2c_del_adapter(&adap_info->pch_data[j].pch_adapter); free_irq(pdev->irq, adap_info); -err_request_irq: - pci_iounmap(pdev, base_addr); err_pci_iomap: pci_release_regions(pdev); err_pci_req: -- 2.7.4