From patchwork Tue Jan 19 13:11:16 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tomasz Nowicki X-Patchwork-Id: 8061621 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 7C7689F859 for ; Tue, 19 Jan 2016 13:13:37 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 479DF20414 for ; Tue, 19 Jan 2016 13:13:36 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 59591203F1 for ; Tue, 19 Jan 2016 13:13:34 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1aLW4s-0003mk-Tx; Tue, 19 Jan 2016 13:12:06 +0000 Received: from mail-wm0-x22d.google.com ([2a00:1450:400c:c09::22d]) by bombadil.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1aLW4a-00038V-VL for linux-arm-kernel@lists.infradead.org; Tue, 19 Jan 2016 13:11:51 +0000 Received: by mail-wm0-x22d.google.com with SMTP id n5so111236000wmn.0 for ; Tue, 19 Jan 2016 05:11:31 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=semihalf-com.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=oPnEiVs6zAHetDwQhdDHhu9CCYCOYayS/U16/0LbgRE=; b=SxoqYPXuZRIQkW1y1PrvbruiEUjfVRunVNV74v5C7XxqyC8+Yq4mqKxOuj4VzMomL3 ROwsigRjH1XrZYMNpwGeFn3M8qCX0HcK8iu+IbSD+RBdRiRuvD678RB7P4c+EoQqCNX7 Cq9pknPr6PY2azJnuQ74Xo6RhQ9qawhOoZpWUd75fRRkrvui3jdvhlgyvt9x8Crav6bu g8/7LW6Cx2ovP/hzK10YQgFmQpYpUjDofZJBAjgPZgBXo+r/XrZ/Tyw4bkvwBbmPV6HV tpwyNqaPAXbJJz0lTDxfpA3RdUZTev0ekOfc81aZx/qq6k8BZUqBWddNRO5gvaGLk5d8 RCIQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=oPnEiVs6zAHetDwQhdDHhu9CCYCOYayS/U16/0LbgRE=; b=QOFVTp4Mwj7J808zXPPazAp5stM1dSoy7WJNoAwOfo/utOeC8jeuIzbCascT9D5g1O T5h13ThBBXBPSE1sxCfXZiF4mQp3xgfqX4OifGw01UGEzFqgCpQDBJMRn1KCIyQktJiC riq69bqBruLo1cWDlxVQ/muBGTONxfhfoEij77Yel2rpI99EAxE0G4+siD36nRlzWwaV TLo0Ar6JNPtC237UKBdLbDdsTldneIawuz+2pSo+DPBNa60kTc4fFHvefP64Oba9uI8e TESAUsIJZaGFQhKISLxZ72NLDd/uIpXD7NFxjD4n+mwyXwKjBwxSEe2fky4uBF1OmFDE Wyjg== X-Gm-Message-State: ALoCoQnLJAmuAD+nwvMYhIP2/FOgeVkpNW1qCC21nF9JYM+5ktwd10tYZ/ExKiUEpGieMSPGHjINhxbLPLVyB0afhRpP0MYxaw== X-Received: by 10.194.23.232 with SMTP id p8mr34923681wjf.80.1453209089993; Tue, 19 Jan 2016 05:11:29 -0800 (PST) Received: from tn-HP-4.semihalf.local ([80.82.22.190]) by smtp.gmail.com with ESMTPSA id w194sm17762623wmd.0.2016.01.19.05.11.28 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 19 Jan 2016 05:11:29 -0800 (PST) From: Tomasz Nowicki To: marc.zyngier@arm.com, tglx@linutronix.de, jason@lakedaemon.net, rjw@rjwysocki.net, lorenzo.pieralisi@arm.com, robert.richter@caviumnetworks.com, shijie.huang@arm.com, guohanjun@huawei.com, Suravee.Suthikulpanit@amd.com Subject: [PATCH V3 03/10] irqchip, GICv3, ACPI: Add redistributor support via GICC structures. Date: Tue, 19 Jan 2016 14:11:16 +0100 Message-Id: <1453209083-3358-4-git-send-email-tn@semihalf.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1453209083-3358-1-git-send-email-tn@semihalf.com> References: <1453209083-3358-1-git-send-email-tn@semihalf.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20160119_051149_248020_1BC4023E X-CRM114-Status: GOOD ( 21.38 ) X-Spam-Score: -2.6 (--) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: graeme.gregory@linaro.org, Catalin.Marinas@arm.com, will.deacon@arm.com, linux-kernel@vger.kernel.org, linux-acpi@vger.kernel.org, hanjun.guo@linaro.org, ddaney.cavm@gmail.com, Tomasz Nowicki , mw@semihalf.com, linux-arm-kernel@lists.infradead.org MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-4.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_MED,RP_MATCHES_RCVD,T_DKIM_INVALID,UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Following ACPI spec: On systems supporting GICv3 and above, GICR Base Address in MADT GICC structure holds the 64-bit physical address of the associated Redistributor. If all of the GIC Redistributors are in the always-on power domain, GICR structures should be used to describe the Redistributors instead, and this field must be set to 0. It means that we have two ways to initialize registirbutors map. 1. via GICD structure which can accommodate many redistributors as a region 2. via GICC which is able to describe single redistributor This patch is going to add support for second option. Considering redistributors, GICD and GICC subtables have be mutually exclusive. While discovering and mapping redistributor, we need to know its size in advance. For the GICC case, redistributor can be in a power-domain that is off, thus we cannot relay on GICR TYPER register. Therefore, we get GIC version from distributor register and map 2xSZ_64K for GICv3 and 4xSZ_64K for GICv4. Signed-off-by: Hanjun Guo Signed-off-by: Tomasz Nowicki Acked-by: Marc Zyngier --- drivers/irqchip/irq-gic-v3.c | 114 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 101 insertions(+), 13 deletions(-) diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index 2cada42..dd16a60 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -40,6 +40,7 @@ struct redist_region { void __iomem *redist_base; phys_addr_t phys_base; + bool single_redist; }; struct gic_chip_data { @@ -436,6 +437,9 @@ static int gic_populate_rdist(void) return 0; } + if (gic_data.redist_regions[i].single_redist) + break; + if (gic_data.redist_stride) { ptr += gic_data.redist_stride; } else { @@ -964,8 +968,21 @@ out_unmap_dist: IRQCHIP_DECLARE(gic_v3, "arm,gic-v3", gic_of_init); #ifdef CONFIG_ACPI +static void __iomem *dist_base; static struct redist_region *redist_regs __initdata; static u32 nr_redist_regions __initdata; +static bool single_redist; + +static void __init +gic_acpi_register_redist(phys_addr_t phys_base, void __iomem *redist_base) +{ + static int count = 0; + + redist_regs[count].phys_base = phys_base; + redist_regs[count].redist_base = redist_base; + redist_regs[count].single_redist = single_redist; + count++; +} static int __init gic_acpi_parse_madt_redist(struct acpi_subtable_header *header, @@ -974,7 +991,6 @@ gic_acpi_parse_madt_redist(struct acpi_subtable_header *header, struct acpi_madt_generic_redistributor *redist = (struct acpi_madt_generic_redistributor *)header; void __iomem *redist_base; - static int count = 0; redist_base = ioremap(redist->base_address, redist->length); if (!redist_base) { @@ -982,12 +998,49 @@ gic_acpi_parse_madt_redist(struct acpi_subtable_header *header, return -ENOMEM; } - redist_regs[count].phys_base = redist->base_address; - redist_regs[count].redist_base = redist_base; - count++; + gic_acpi_register_redist(redist->base_address, redist_base); return 0; } +static int __init +gic_acpi_parse_madt_gicc(struct acpi_subtable_header *header, + const unsigned long end) +{ + struct acpi_madt_generic_interrupt *gicc = + (struct acpi_madt_generic_interrupt *)header; + u32 reg = readl_relaxed(dist_base + GICD_PIDR2) & GIC_PIDR2_ARCH_MASK; + u32 size = reg == GIC_PIDR2_ARCH_GICv4 ? SZ_64K * 4 : SZ_64K * 2; + void __iomem *redist_base; + + redist_base = ioremap(gicc->gicr_base_address, size); + if (!redist_base) + return -ENOMEM; + + gic_acpi_register_redist(gicc->gicr_base_address, redist_base); + return 0; +} + +static int __init gic_acpi_collect_gicr_base(void) +{ + acpi_tbl_entry_handler redist_parser; + enum acpi_madt_type type; + + if (single_redist) { + type = ACPI_MADT_TYPE_GENERIC_INTERRUPT; + redist_parser = gic_acpi_parse_madt_gicc; + } else { + type = ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR; + redist_parser = gic_acpi_parse_madt_redist; + } + + /* Collect redistributor base addresses in GICR entries */ + if (acpi_table_parse_madt(type, redist_parser, 0) > 0) + return 0; + + pr_info("No valid GICR entries exist\n"); + return -ENODEV; +} + static int __init gic_acpi_match_gicr(struct acpi_subtable_header *header, const unsigned long end) { @@ -995,6 +1048,46 @@ static int __init gic_acpi_match_gicr(struct acpi_subtable_header *header, return 0; } +static int __init gic_acpi_match_gicc(struct acpi_subtable_header *header, + const unsigned long end) +{ + struct acpi_madt_generic_interrupt *gicc = + (struct acpi_madt_generic_interrupt *)header; + + /* + * If GICC is enabled and has valid gicr base address, then it means + * GICR base is presented via GICC + */ + if ((gicc->flags & ACPI_MADT_ENABLED) && gicc->gicr_base_address) + return 0; + + return -ENODEV; +} + +static int __init gic_acpi_count_gicr_regions(void) +{ + int count; + + /* + * Count how many redistributor regions we have. It is not allowed + * to mix redistributor description, GICR and GICC subtables have to be + * mutually exclusive. + */ + count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR, + gic_acpi_match_gicr, 0); + if (count > 0) { + single_redist = false; + return count; + } + + count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_INTERRUPT, + gic_acpi_match_gicc, 0); + if (count > 0) + single_redist = true; + + return count; +} + static bool __init acpi_validate_gic_table(struct acpi_subtable_header *header, struct acpi_probe_entry *ape) { @@ -1006,8 +1099,7 @@ static bool __init acpi_validate_gic_table(struct acpi_subtable_header *header, return false; /* We need to do that exercise anyway, the sooner the better */ - count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR, - gic_acpi_match_gicr, 0); + count = gic_acpi_count_gicr_regions(); if (count <= 0) return false; @@ -1022,8 +1114,7 @@ gic_acpi_init(struct acpi_subtable_header *header, const unsigned long end) { struct acpi_madt_generic_distributor *dist; struct fwnode_handle *domain_handle; - void __iomem *dist_base; - int i, err, count; + int i, err; /* Get distributor base address */ dist = (struct acpi_madt_generic_distributor *)header; @@ -1046,12 +1137,9 @@ gic_acpi_init(struct acpi_subtable_header *header, const unsigned long end) goto out_dist_unmap; } - count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR, - gic_acpi_parse_madt_redist, 0); - if (count <= 0) { - err = -ENODEV; + err = gic_acpi_collect_gicr_base(); + if (err) goto out_redist_unmap; - } domain_handle = irq_domain_alloc_fwnode(dist_base); if (!domain_handle) {