Received: by 2002:ad5:474a:0:0:0:0:0 with SMTP id i10csp1794166imu; Thu, 24 Jan 2019 01:56:32 -0800 (PST) X-Google-Smtp-Source: ALg8bN7siCurL2Rps4+gxGOfxzg7OJfpPB4IZi6cmxxwHggpaYW8hRVnn9q64ybROunDqQvR7YSB X-Received: by 2002:a17:902:32c3:: with SMTP id z61mr5902654plb.114.1548323792721; Thu, 24 Jan 2019 01:56:32 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1548323792; cv=none; d=google.com; s=arc-20160816; b=FWK+KSW/5TOX1KUJVpfqD5f3uhH6HQlbxWWcyzj6sRlNrY2DYh8VKdIMU3dXmfoa3t W1Ax1Bzy/QP37EQYv0m7EKKQwxekdwS+BPUNORv8Zm018linivZmgmoVC6qxE1t5zava YCFuBqO68fFiAwWuccLR6VytpOf7VZB/kSrNEQ1XA11ssdHBlT8gZGw4kgoKa4eVVvJN 6LKqmBFn3DNN7tBeXyrHGL8E0Fj8rMXKPlFAw6xqZXmGogkPLJ8e3uttVmriBnm1/k1m uwrWBIYHgteFVCXjdw8E9ncWUvLr7mHAbqau/EIpC1dfleMAumS4vfhQbACgbbrmD9vn iQEw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:mime-version:organization:user-agent :references:in-reply-to:subject:cc:to:from:message-id:date; bh=Dt7rsYWS5XzPK/G3jSydSgBogicLox+3ecKnZqFvPNY=; b=WV5p7N/DGVOqLC+QJej029U70Ir6ePgtE5JPLqtIN8mJ6BO+nX9slqwr9aNmCk8grJ R+FyeOizj/x8l/j2eDog4NhqJCJRpGNNYivhMWgeUzoHbR+ee/hsbpcQg+fYQkdpyCLk LBmNZwZ5G6PgN3B9fZY6cC+Tvl0NzPUVDE9xolYqaxG1m8ehbjSjnQ0BTwauAwTaz9aE 2mIpxR8jn3LvLTfrsj+kh9riha3Ly6Kxi0HNWZNA4mY5brHqJ689JVzPN38cIYwdZBmA gGOkRIymmQuHEUtqRn2HHUFC7D98ZXVXOday/ELxd/qGeCUW7lbF88fO93j4oUzMfifM 0TWQ== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id 3si21535427plv.258.2019.01.24.01.56.16; Thu, 24 Jan 2019 01:56:32 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727126AbfAXJyu (ORCPT + 99 others); Thu, 24 Jan 2019 04:54:50 -0500 Received: from foss.arm.com ([217.140.101.70]:53400 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726053AbfAXJyu (ORCPT ); Thu, 24 Jan 2019 04:54:50 -0500 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.72.51.249]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id D75A0A78; Thu, 24 Jan 2019 01:54:49 -0800 (PST) Received: from big-swifty.misterjones.org (big-swifty.copenhagen.arm.com [10.32.148.139]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id CED093F5C1; Thu, 24 Jan 2019 01:54:38 -0800 (PST) Date: Thu, 24 Jan 2019 09:54:32 +0000 Message-ID: <86pnsm8jon.wl-marc.zyngier@arm.com> From: Marc Zyngier To: Jiaxun Yang Cc: linux-mips@vger.kernel.org, tglx@linutronix.de, jason@lakedaemon.net, robh+dt@kernel.org, mark.rutland@arm.com, linux-kernel@vger.kernel.org, devicetree@vger.kernel.org Subject: Re: [PATCH v3 1/2] irqchip: Add driver for Loongson-1 interrupt controller In-Reply-To: <20190124032730.18237-2-jiaxun.yang@flygoat.com> References: <20190122154557.22689-1-jiaxun.yang@flygoat.com> <20190124032730.18237-1-jiaxun.yang@flygoat.com> <20190124032730.18237-2-jiaxun.yang@flygoat.com> User-Agent: Wanderlust/2.15.9 (Almost Unreal) SEMI-EPG/1.14.7 (Harue) FLIM/1.14.9 (=?UTF-8?B?R29qxY0=?=) APEL/10.8 EasyPG/1.0.0 Emacs/25.1 (aarch64-unknown-linux-gnu) MULE/6.0 (HANACHIRUSATO) Organization: ARM Ltd MIME-Version: 1.0 (generated by SEMI-EPG 1.14.7 - "Harue") Content-Type: text/plain; charset=US-ASCII Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On Thu, 24 Jan 2019 03:27:29 +0000, Jiaxun Yang wrote: > > This controller appeared on Loongson-1 family MCUs > including Loongson-1B and Loongson-1C. > > Signed-off-by: Jiaxun Yang > --- > drivers/irqchip/Kconfig | 9 ++ > drivers/irqchip/Makefile | 1 + > drivers/irqchip/irq-ls1x.c | 176 +++++++++++++++++++++++++++++++++++++ > 3 files changed, 186 insertions(+) > create mode 100644 drivers/irqchip/irq-ls1x.c > > diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig > index 3d1e60779078..5dcb5456cd14 100644 > --- a/drivers/irqchip/Kconfig > +++ b/drivers/irqchip/Kconfig > @@ -406,6 +406,15 @@ config IMX_IRQSTEER > help > Support for the i.MX IRQSTEER interrupt multiplexer/remapper. > > +config LS1X_IRQ > + bool "Loongson-1 Interrupt Controller" > + depends on MACH_LOONGSON32 > + default y > + select IRQ_DOMAIN > + select GENERIC_IRQ_CHIP > + help > + Support for the Loongson-1 platform Interrupt Controller. > + > endmenu > > config SIFIVE_PLIC > diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile > index c93713d24b86..7acd0e36d0b4 100644 > --- a/drivers/irqchip/Makefile > +++ b/drivers/irqchip/Makefile > @@ -94,3 +94,4 @@ obj-$(CONFIG_CSKY_APB_INTC) += irq-csky-apb-intc.o > obj-$(CONFIG_SIFIVE_PLIC) += irq-sifive-plic.o > obj-$(CONFIG_IMX_IRQSTEER) += irq-imx-irqsteer.o > obj-$(CONFIG_MADERA_IRQ) += irq-madera.o > +obj-$(CONFIG_LS1X_IRQ) += irq-ls1x.o > diff --git a/drivers/irqchip/irq-ls1x.c b/drivers/irqchip/irq-ls1x.c > new file mode 100644 > index 000000000000..de92ca04cf9f > --- /dev/null > +++ b/drivers/irqchip/irq-ls1x.c > @@ -0,0 +1,176 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Copyright (C) 2019, Jiaxun Yang > + * Loongson-1 platform IRQ support > + */ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include > + > + > +#define MAX_CHIPS 5 > +#define LS_REG_INTC_STATUS 0x00 > +#define LS_REG_INTC_EN 0x04 > +#define LS_REG_INTC_SET 0x08 > +#define LS_REG_INTC_CLR 0x0c > +#define LS_REG_INTC_POL 0x10 > +#define LS_REG_INTC_EDGE 0x14 > +#define CHIP_SIZE 0x18 > + > +static void ls_chained_handle_irq(struct irq_desc *desc) > +{ > + struct irq_chip_generic *gc = irq_desc_get_handler_data(desc); > + struct irq_chip *chip = irq_desc_get_chip(desc); > + u32 pending; > + > + chained_irq_enter(chip, desc); > + pending = readl(gc->reg_base + LS_REG_INTC_STATUS) & > + readl(gc->reg_base + LS_REG_INTC_EN); > + > + if (!pending) { > + spurious_interrupt(); > + chained_irq_exit(chip, desc); > + return; > + } Given the context, this is the same as writing: if (!pending) spurious_interrupt(); and let it go through. > + > + while (pending) { > + int bit = __ffs(pending); > + > + generic_handle_irq(gc->irq_base + bit); > + pending &= ~BIT(bit); > + } > + > + chained_irq_exit(chip, desc); > +} > + > +static void ls_intc_set_bit(struct irq_chip_generic *gc, > + unsigned int offset, > + u32 mask, bool set) > +{ > + if (set) > + writel(readl(gc->reg_base + offset) | mask, > + gc->reg_base + offset); > + else > + writel(readl(gc->reg_base + offset) & ~mask, > + gc->reg_base + offset); > +} > + > +static int ls_intc_set_type(struct irq_data *data, unsigned int type) > +{ > + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data); > + u32 mask = data->mask; > + > + switch (type) { > + case IRQ_TYPE_LEVEL_HIGH: > + ls_intc_set_bit(gc, LS_REG_INTC_EDGE, mask, false); > + ls_intc_set_bit(gc, LS_REG_INTC_POL, mask, true); > + break; > + case IRQ_TYPE_LEVEL_LOW: > + ls_intc_set_bit(gc, LS_REG_INTC_EDGE, mask, false); > + ls_intc_set_bit(gc, LS_REG_INTC_POL, mask, false); > + break; > + case IRQ_TYPE_EDGE_RISING: > + ls_intc_set_bit(gc, LS_REG_INTC_EDGE, mask, true); > + ls_intc_set_bit(gc, LS_REG_INTC_POL, mask, true); > + break; > + case IRQ_TYPE_EDGE_FALLING: > + ls_intc_set_bit(gc, LS_REG_INTC_EDGE, mask, true); > + ls_intc_set_bit(gc, LS_REG_INTC_POL, mask, false); > + break; > + case IRQ_TYPE_NONE: > + break; > + default: > + return -EINVAL; > + } I just realised that in your DT binding, you define the interrupt specifier as having a single cell. Which means that you never describe the interrupt trigger there. Why? Does it mean that all the drivers have to configure their interrupt trigger themselves, and cannot rely on DT to do it? This seems quite backward. > + > + return 0; > +} > + > + > +static int __init ls_intc_of_init(struct device_node *node, > + struct device_node *parent) > +{ > + struct irq_chip_generic *gc[MAX_CHIPS]; > + struct irq_chip_type *ct; > + struct irq_domain *domain; > + void __iomem *base; > + int parent_irq[MAX_CHIPS], err = 0; > + unsigned int i = 0; > + > + unsigned int num_chips = of_irq_count(node); > + > + base = of_iomap(node, 0); > + if (!base) > + return -ENODEV; > + > + for (i = 0; i < num_chips; i++) { > + /* Mask all irqs */ > + writel(0x0, base + (i * CHIP_SIZE) + > + LS_REG_INTC_EN); > + > + /* Set all irqs to high level triggered */ > + writel(0xffffffff, base + (i * CHIP_SIZE) + > + LS_REG_INTC_POL); > + > + parent_irq[i] = irq_of_parse_and_map(node, i); > + > + if (!parent_irq[i]) { > + pr_warn("unable to get parent irq for irqchip %u\n", i); > + goto out_err; > + } > + > + gc[i] = irq_alloc_generic_chip("INTC", 1, > + LS1X_IRQ_BASE + (i * 32), > + base + (i * CHIP_SIZE), > + handle_level_irq); > + > + ct = gc[i]->chip_types; > + ct->regs.mask = LS_REG_INTC_EN; > + ct->regs.ack = LS_REG_INTC_CLR; > + ct->chip.irq_unmask = irq_gc_mask_set_bit; > + ct->chip.irq_mask = irq_gc_mask_clr_bit; > + ct->chip.irq_ack = irq_gc_ack_set_bit; > + ct->chip.irq_set_type = ls_intc_set_type; > + > + irq_setup_generic_chip(gc[i], IRQ_MSK(32), 0, 0, > + IRQ_NOPROBE | IRQ_LEVEL); > + } > + > + domain = irq_domain_add_legacy(node, num_chips * 32, LS1X_IRQ_BASE, 0, > + &irq_domain_simple_ops, NULL); Why a legacy domain? This is usually reserved to old drivers that are converted to a new infrastructure, while needing some form of platform hacks. I don't see this being the case here. It is also worrying that although you have up to 5 irqchips, they all share a single domain. What does this mean? each irqchip is expected to have its own domain. > + if (!domain) { > + pr_warn("unable to register IRQ domain\n"); > + err = -EINVAL; > + goto out_err; > + } > + > + for (i = 0; i < num_chips; i++) > + irq_set_chained_handler_and_data(parent_irq[i], > + ls_chained_handle_irq, gc[i]); > + > + pr_info("ls1x-irq: %u chips registered\n", num_chips); > + > + return 0; > + > +out_err: > + for (i = 0; i < MAX_CHIPS; i++) { > + if (gc[i]) But you've never initialised gc[], nor parent_irq[]. So you'll get whatever the stack had at this point. Not great. > + irq_destroy_generic_chip(gc[i], IRQ_MSK(32), > + IRQ_NOPROBE | IRQ_LEVEL, 0); > + if (parent_irq[i]) > + irq_dispose_mapping(parent_irq[i]); > + } > + return err; > +} > + > +IRQCHIP_DECLARE(ls1x_intc, "loongson,ls1x-intc", ls_intc_of_init); > -- > 2.20.1 > Thanks, M. -- Jazz is not dead, it just smell funny.