From patchwork Wed Jan 11 14:31:35 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andy Shevchenko X-Patchwork-Id: 9510165 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 0AE8C60762 for ; Wed, 11 Jan 2017 14:31:49 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id F378928648 for ; Wed, 11 Jan 2017 14:31:48 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id E854C28659; Wed, 11 Jan 2017 14:31:48 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 4B61C28648 for ; Wed, 11 Jan 2017 14:31:48 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1763546AbdAKObo (ORCPT ); Wed, 11 Jan 2017 09:31:44 -0500 Received: from mga14.intel.com ([192.55.52.115]:48636 "EHLO mga14.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1763538AbdAKObm (ORCPT ); Wed, 11 Jan 2017 09:31:42 -0500 Received: from fmsmga002.fm.intel.com ([10.253.24.26]) by fmsmga103.fm.intel.com with ESMTP; 11 Jan 2017 06:31:40 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.33,346,1477983600"; d="scan'208";a="1111089913" Received: from black.fi.intel.com ([10.237.72.28]) by fmsmga002.fm.intel.com with ESMTP; 11 Jan 2017 06:31:38 -0800 Received: by black.fi.intel.com (Postfix, from userid 1003) id 7EF12220; Wed, 11 Jan 2017 16:31:37 +0200 (EET) From: Andy Shevchenko To: Greg Kroah-Hartman , linux-serial@vger.kernel.org, Vinod Koul , dmaengine@vger.kernel.org, Jan Kiszka Cc: Andy Shevchenko Subject: [PATCH v3 1/3] serial: 8250_mid: handle interrupt correctly in DMA case Date: Wed, 11 Jan 2017 16:31:35 +0200 Message-Id: <20170111143137.151407-2-andriy.shevchenko@linux.intel.com> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20170111143137.151407-1-andriy.shevchenko@linux.intel.com> References: <20170111143137.151407-1-andriy.shevchenko@linux.intel.com> Sender: dmaengine-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: dmaengine@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Starting from Tangier B0 and continuing on Anniedale the HSU DMA interrupt line is actually shared with UART. Handling them independently is racy and quite often comes with the following traceback. irq 54: nobody cared (try booting with the "irqpoll" option) CPU: 0 PID: 0 Comm: swapper/0 Not tainted 4.9.0-rc6-edison64-86244934+ #1 Hardware name: Intel Corporation Merrifield/BODEGA BAY, BIOS 542 2015.01.21:18.19.48 ffff88003f203eb0 ffffffff8130e718 ffff880032627000 ffff88003262709c ffff88003f203ed8 ffffffff810a3960 ffff880032627000 0000000000000000 ffff880032627000 ffff88003f203f10 ffffffff810a3cc7 ffff880032627000 Call Trace: [] dump_stack+0x4d/0x65 [] __report_bad_irq+0x30/0xc0 [] note_interrupt+0x227/0x270 [] handle_irq_event_percpu+0x40/0x50 [] handle_irq_event+0x27/0x50 [] handle_fasteoi_irq+0x85/0x150 [] handle_irq+0x6e/0x120 [] ? _local_bh_enable+0x1c/0x50 [] do_IRQ+0x46/0xd0 [] common_interrupt+0x7f/0x7f [] ? mwait_idle+0x7d/0x140 [] arch_cpu_idle+0xa/0x10 [] default_idle_call+0x20/0x30 [] cpu_startup_entry+0x16d/0x1d0 [] rest_init+0x6d/0x70 [] start_kernel+0x3e2/0x3ef [] x86_64_start_reservations+0x38/0x3a [] x86_64_start_kernel+0xea/0xed handlers: [] serial8250_interrupt Disabling IRQ #54 Fix this by handling interrupt only in one place. The issue is discussed here: https://github.com/andy-shev/linux/issues/5 Moreover this also fixes another bug when Rx DMA returns wrong residue and we can't rely on it. Reviewed-by: Heikki Krogerus Signed-off-by: Andy Shevchenko Acked-by: Vinod Koul --- drivers/dma/hsu/pci.c | 17 +++++++++++++++-- drivers/tty/serial/8250/8250_mid.c | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/drivers/dma/hsu/pci.c b/drivers/dma/hsu/pci.c index 4875fa428e81..ad45cd344bba 100644 --- a/drivers/dma/hsu/pci.c +++ b/drivers/dma/hsu/pci.c @@ -23,15 +23,28 @@ #define HSU_PCI_CHAN_OFFSET 0x100 +#define PCI_DEVICE_ID_INTEL_MFLD_HSU_DMA 0x081e +#define PCI_DEVICE_ID_INTEL_MRFLD_HSU_DMA 0x1192 + static irqreturn_t hsu_pci_irq(int irq, void *dev) { struct hsu_dma_chip *chip = dev; + struct pci_dev *pdev = to_pci_dev(chip->dev); u32 dmaisr; u32 status; unsigned short i; int ret = 0; int err; + /* + * On Intel Tangier B0 and Anniedale the interrupt line, disregarding + * to have different numbers, is shared between HSU DMA and UART IPs. + * Thus on such SoCs we are expecting that IRQ handler is called in + * UART driver only. + */ + if (pdev->device == PCI_DEVICE_ID_INTEL_MRFLD_HSU_DMA) + return IRQ_HANDLED; + dmaisr = readl(chip->regs + HSU_PCI_DMAISR); for (i = 0; i < chip->hsu->nr_channels; i++) { if (dmaisr & 0x1) { @@ -113,8 +126,8 @@ static void hsu_pci_remove(struct pci_dev *pdev) } static const struct pci_device_id hsu_pci_id_table[] = { - { PCI_VDEVICE(INTEL, 0x081e), 0 }, - { PCI_VDEVICE(INTEL, 0x1192), 0 }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_MFLD_HSU_DMA), 0 }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_MRFLD_HSU_DMA), 0 }, { } }; MODULE_DEVICE_TABLE(pci, hsu_pci_id_table); diff --git a/drivers/tty/serial/8250/8250_mid.c b/drivers/tty/serial/8250/8250_mid.c index ac013edf4992..6730d9eef81e 100644 --- a/drivers/tty/serial/8250/8250_mid.c +++ b/drivers/tty/serial/8250/8250_mid.c @@ -75,6 +75,37 @@ static int pnw_setup(struct mid8250 *mid, struct uart_port *p) return 0; } +static int tng_handle_irq(struct uart_port *p) +{ + struct mid8250 *mid = p->private_data; + struct uart_8250_port *up = up_to_u8250p(p); + struct hsu_dma_chip *chip; + u32 status; + int ret = 0; + int err; + + chip = pci_get_drvdata(mid->dma_dev); + + /* Rx DMA */ + err = hsu_dma_get_status(chip, mid->dma_index * 2 + 1, &status); + if (err > 0) { + serial8250_rx_dma_flush(up); + ret |= 1; + } else if (err == 0) + ret |= hsu_dma_do_irq(chip, mid->dma_index * 2 + 1, status); + + /* Tx DMA */ + err = hsu_dma_get_status(chip, mid->dma_index * 2, &status); + if (err > 0) + ret |= 1; + else if (err == 0) + ret |= hsu_dma_do_irq(chip, mid->dma_index * 2, status); + + /* UART */ + ret |= serial8250_handle_irq(p, serial_port_in(p, UART_IIR)); + return IRQ_RETVAL(ret); +} + static int tng_setup(struct mid8250 *mid, struct uart_port *p) { struct pci_dev *pdev = to_pci_dev(p->dev); @@ -90,6 +121,8 @@ static int tng_setup(struct mid8250 *mid, struct uart_port *p) mid->dma_index = index; mid->dma_dev = pci_get_slot(pdev->bus, PCI_DEVFN(5, 0)); + + p->handle_irq = tng_handle_irq; return 0; }