From patchwork Tue Jul 23 03:31:18 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nicolas Pitre X-Patchwork-Id: 18522 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-qa0-f70.google.com (mail-qa0-f70.google.com [209.85.216.70]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id 1E73126EE8 for ; Tue, 23 Jul 2013 03:31:47 +0000 (UTC) Received: by mail-qa0-f70.google.com with SMTP id cd7sf3665749qab.9 for ; Mon, 22 Jul 2013 20:31:46 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=mime-version:x-beenthere:x-forwarded-to:x-forwarded-for :delivered-to:from:to:cc:subject:date:message-id:x-mailer :in-reply-to:references:x-gm-message-state:x-original-sender :x-original-authentication-results:precedence:mailing-list:list-id :x-google-group-id:list-post:list-help:list-archive:list-unsubscribe :content-transfer-encoding; bh=IGtufGgEyofTlep/Wv6HRUmYnm/tUzeJ6iupFkU/1Ug=; b=AW/vG4WAwn04B06TNHhQykpKjlGb5SOnAakaK0tmNGhpGSrhxw7WoOGZ16nPJulvkW KSQTeYxs6yVkRAMe9iQBbDalx3pp61Akeie+Gu3OxyZXZSRnUBjia0eir4h+ydnBk4m6 7YIOanekOZt+puoZ2Vr20XNYVVRRJda/Beu3seZkPMuR9QPQ2M8fmbdKyEdHJ3i+C5mG RuCMwYJlViKx53YkWtLM2PIK9B9IhU0epHxNfxg1l3/gFtuoNVNduVVqEUeslGKYr7o7 9G8QwW8NLxBt2wH9YkyAwvnn502ym07PmYlwF0mP8oqTolh6n8QszvBXz2uHmTBOrLYv hUHQ== X-Received: by 10.236.156.33 with SMTP id l21mr17281741yhk.18.1374550306848; Mon, 22 Jul 2013 20:31:46 -0700 (PDT) MIME-Version: 1.0 X-BeenThere: patchwork-forward@linaro.org Received: by 10.49.116.105 with SMTP id jv9ls2873647qeb.92.gmail; Mon, 22 Jul 2013 20:31:46 -0700 (PDT) X-Received: by 10.220.48.17 with SMTP id p17mr10005731vcf.97.1374550306728; Mon, 22 Jul 2013 20:31:46 -0700 (PDT) Received: from mail-ve0-f171.google.com (mail-ve0-f171.google.com [209.85.128.171]) by mx.google.com with ESMTPS id ex7si7815502vdb.135.2013.07.22.20.31.46 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Mon, 22 Jul 2013 20:31:46 -0700 (PDT) Received-SPF: neutral (google.com: 209.85.128.171 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) client-ip=209.85.128.171; Received: by mail-ve0-f171.google.com with SMTP id b10so5655512vea.2 for ; Mon, 22 Jul 2013 20:31:46 -0700 (PDT) X-Received: by 10.58.119.233 with SMTP id kx9mr10437659veb.3.1374550306630; Mon, 22 Jul 2013 20:31:46 -0700 (PDT) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patches@linaro.org Received: by 10.58.165.8 with SMTP id yu8csp84140veb; Mon, 22 Jul 2013 20:31:46 -0700 (PDT) X-Received: by 10.49.83.37 with SMTP id n5mr35601701qey.57.1374550304737; Mon, 22 Jul 2013 20:31:44 -0700 (PDT) Received: from relais.videotron.ca (relais.videotron.ca. [24.201.245.36]) by mx.google.com with ESMTP id i7si5237393qcu.54.2013.07.22.20.31.44 for ; Mon, 22 Jul 2013 20:31:44 -0700 (PDT) Received-SPF: neutral (google.com: 24.201.245.36 is neither permitted nor denied by best guess record for domain of nicolas.pitre@linaro.org) client-ip=24.201.245.36; Received: from yoda.home ([70.83.209.44]) by VL-VM-MR004.ip.videotron.ca (Oracle Communications Messaging Exchange Server 7u4-22.01 64bit (built Apr 21 2011)) with ESMTP id <0MQD009E8DSV4940@VL-VM-MR004.ip.videotron.ca>; Mon, 22 Jul 2013 23:31:43 -0400 (EDT) Received: from xanadu.home (xanadu.home [192.168.2.2]) by yoda.home (Postfix) with ESMTP id 935FD2DA0547; Mon, 22 Jul 2013 23:31:43 -0400 (EDT) From: Nicolas Pitre To: linux-arm-kernel@lists.infradead.org Cc: dave.martin@linaro.org, lorenzo.pieralisi@arm.com, patches@linaro.org Subject: [PATCH 02/13] ARM: gic: add CPU migration support Date: Mon, 22 Jul 2013 23:31:18 -0400 Message-id: <1374550289-25305-3-git-send-email-nicolas.pitre@linaro.org> X-Mailer: git-send-email 1.8.1.2 In-reply-to: <1374550289-25305-1-git-send-email-nicolas.pitre@linaro.org> References: <1374550289-25305-1-git-send-email-nicolas.pitre@linaro.org> X-Gm-Message-State: ALoCoQljm08RQG7k2RFPx9aV78G1JDLBSUjIgJezA3arc4HPuCddHI5Ky3ZGJDEd/fg7rjNall2C X-Original-Sender: nicolas.pitre@linaro.org X-Original-Authentication-Results: mx.google.com; spf=neutral (google.com: 209.85.128.171 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) smtp.mail=patch+caf_=patchwork-forward=linaro.org@linaro.org Precedence: list Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org List-ID: X-Google-Group-Id: 836684582541 List-Post: , List-Help: , List-Archive: List-Unsubscribe: , Content-transfer-encoding: 7BIT This is required by the big.LITTLE switcher code. The gic_migrate_target() changes the CPU interface mapping for the current CPU to redirect SGIs to the specified interface, and it also updates the target CPU for each interrupts to that CPU interface if they were targeting the current interface. Finally, pending SGIs for the current CPU are forwarded to the new interface. Because Linux does not use it, the SGI source information for the forwarded SGIs is not preserved. Neither is the source information for the SGIs sent by the current CPU to other CPUs adjusted to match the new CPU interface mapping. The required registers are banked so only the target CPU could do it. Signed-off-by: Nicolas Pitre --- drivers/irqchip/irq-gic.c | 81 +++++++++++++++++++++++++++++++++++++++-- include/linux/irqchip/arm-gic.h | 4 ++ 2 files changed, 82 insertions(+), 3 deletions(-) diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index ee7c503120..6bd5a8c1aa 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -253,10 +253,9 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val, if (cpu >= NR_GIC_CPU_IF || cpu >= nr_cpu_ids) return -EINVAL; + raw_spin_lock(&irq_controller_lock); mask = 0xff << shift; bit = gic_cpu_map[cpu] << shift; - - raw_spin_lock(&irq_controller_lock); val = readl_relaxed(reg) & ~mask; writel_relaxed(val | bit, reg); raw_spin_unlock(&irq_controller_lock); @@ -646,7 +645,9 @@ static void __init gic_pm_init(struct gic_chip_data *gic) void gic_raise_softirq(const struct cpumask *mask, unsigned int irq) { int cpu; - unsigned long map = 0; + unsigned long flags, map = 0; + + raw_spin_lock_irqsave(&irq_controller_lock, flags); /* Convert our logical CPU mask into a physical one. */ for_each_cpu(cpu, mask) @@ -660,6 +661,80 @@ void gic_raise_softirq(const struct cpumask *mask, unsigned int irq) /* this always happens on GIC0 */ writel_relaxed(map << 16 | irq, gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT); + + raw_spin_unlock_irqrestore(&irq_controller_lock, flags); +} +#endif + +#ifdef CONFIG_BL_SWITCHER +/* + * gic_migrate_target - migrate IRQs to another PU interface + * + * @new_cpu_id: the CPU target ID to migrate IRQs to + * + * Migrate all peripheral interrupts with a target matching the current CPU + * to the interface corresponding to @new_cpu_id. The CPU interface mapping + * is also updated. Targets to other CPU interfaces are unchanged. + * This must be called with IRQs locally disabled. + */ +void gic_migrate_target(unsigned int new_cpu_id) +{ + unsigned int old_cpu_id, gic_irqs, gic_nr = 0; + void __iomem *dist_base; + int i, ror_val, cpu = smp_processor_id(); + u32 val, old_mask, active_mask; + + if (gic_nr >= MAX_GIC_NR) + BUG(); + + dist_base = gic_data_dist_base(&gic_data[gic_nr]); + if (!dist_base) + return; + gic_irqs = gic_data[gic_nr].gic_irqs; + + old_cpu_id = __ffs(gic_cpu_map[cpu]); + old_mask = 0x01010101 << old_cpu_id; + ror_val = (old_cpu_id - new_cpu_id) & 31; + + raw_spin_lock(&irq_controller_lock); + + gic_cpu_map[cpu] = 1 << new_cpu_id; + + for (i = 8; i < DIV_ROUND_UP(gic_irqs, 4); i++) { + val = readl_relaxed(dist_base + GIC_DIST_TARGET + i * 4); + active_mask = val & old_mask; + if (active_mask) { + val &= ~active_mask; + val |= ror32(active_mask, ror_val); + writel_relaxed(val, dist_base + GIC_DIST_TARGET + i*4); + } + } + + raw_spin_unlock(&irq_controller_lock); + + /* + * Now let's migrate and clear any potential SGIs that might be + * pending for us (old_cpu_id). Since GIC_DIST_SGI_PENDING_SET + * is a banked register, we can only forward the SGI using + * GIC_DIST_SOFTINT. The original SGI source is lost but Linux + * doesn't use that information anyway. + * + * For the same reason we do not adjust SGI source information + * for previously sent SGIs by us to other CPUs either. + */ + for (i = 0; i < 16; i += 4) { + int j; + val = readl_relaxed(dist_base + GIC_DIST_SGI_PENDING_SET + i); + if (!val) + continue; + writel_relaxed(val, dist_base + GIC_DIST_SGI_PENDING_CLEAR + i); + for (j = i; j < i + 4; j++) { + if (val & 0xff) + writel_relaxed((1 << (new_cpu_id + 16)) | j, + dist_base + GIC_DIST_SOFTINT); + val >>= 8; + } + } } #endif diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h index 3e203eb23c..40bfcac959 100644 --- a/include/linux/irqchip/arm-gic.h +++ b/include/linux/irqchip/arm-gic.h @@ -31,6 +31,8 @@ #define GIC_DIST_TARGET 0x800 #define GIC_DIST_CONFIG 0xc00 #define GIC_DIST_SOFTINT 0xf00 +#define GIC_DIST_SGI_PENDING_CLEAR 0xf10 +#define GIC_DIST_SGI_PENDING_SET 0xf20 #define GICH_HCR 0x0 #define GICH_VTR 0x4 @@ -73,6 +75,8 @@ static inline void gic_init(unsigned int nr, int start, gic_init_bases(nr, start, dist, cpu, 0, NULL); } +void gic_migrate_target(unsigned int new_cpu_id); + #endif /* __ASSEMBLY */ #endif