Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 330353
b: refs/heads/master
c: 0a40816
h: refs/heads/master
i:
  330351: 7dd6e73
v: v3
  • Loading branch information
Varun Sethi authored and Kumar Gala committed Sep 12, 2012
1 parent 1d1d1b6 commit 77cb4de
Show file tree
Hide file tree
Showing 6 changed files with 230 additions and 3 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 688ba1dbee8a49a2efe507cd9ae69634d92bb640
refs/heads/master: 0a4081641d722d3dee140505a86330ecf44db0fe
14 changes: 14 additions & 0 deletions trunk/arch/powerpc/include/asm/mpic.h
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,9 @@
#define MPIC_MAX_CPUS 32
#define MPIC_MAX_ISU 32

#define MPIC_MAX_ERR 32
#define MPIC_FSL_ERR_INT 16

/*
* Tsi108 implementation of MPIC has many differences from the original one
*/
Expand Down Expand Up @@ -270,6 +273,7 @@ struct mpic
struct irq_chip hc_ipi;
#endif
struct irq_chip hc_tm;
struct irq_chip hc_err;
const char *name;
/* Flags */
unsigned int flags;
Expand All @@ -283,6 +287,8 @@ struct mpic
/* vector numbers used for internal sources (ipi/timers) */
unsigned int ipi_vecs[4];
unsigned int timer_vecs[8];
/* vector numbers used for FSL MPIC error interrupts */
unsigned int err_int_vecs[MPIC_MAX_ERR];

/* Spurious vector to program into unused sources */
unsigned int spurious_vec;
Expand All @@ -306,6 +312,9 @@ struct mpic
struct mpic_reg_bank cpuregs[MPIC_MAX_CPUS];
struct mpic_reg_bank isus[MPIC_MAX_ISU];

/* ioremap'ed base for error interrupt registers */
u32 __iomem *err_regs;

/* Protected sources */
unsigned long *protected;

Expand Down Expand Up @@ -370,6 +379,11 @@ struct mpic
#define MPIC_NO_RESET 0x00004000
/* Freescale MPIC (compatible includes "fsl,mpic") */
#define MPIC_FSL 0x00008000
/* Freescale MPIC supports EIMR (error interrupt mask register).
* This flag is set for MPIC version >= 4.1 (version determined
* from the BRR1 register).
*/
#define MPIC_FSL_HAS_EIMR 0x00010000

/* MPIC HW modification ID */
#define MPIC_REGSET_MASK 0xf0000000
Expand Down
2 changes: 1 addition & 1 deletion trunk/arch/powerpc/sysdev/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ obj-$(CONFIG_PPC_DCR_NATIVE) += dcr-low.o
obj-$(CONFIG_PPC_PMI) += pmi.o
obj-$(CONFIG_U3_DART) += dart_iommu.o
obj-$(CONFIG_MMIO_NVRAM) += mmio_nvram.o
obj-$(CONFIG_FSL_SOC) += fsl_soc.o
obj-$(CONFIG_FSL_SOC) += fsl_soc.o fsl_mpic_err.o
obj-$(CONFIG_FSL_PCI) += fsl_pci.o $(fsl-msi-obj-y)
obj-$(CONFIG_FSL_PMC) += fsl_pmc.o
obj-$(CONFIG_FSL_LBC) += fsl_lbc.o
Expand Down
149 changes: 149 additions & 0 deletions trunk/arch/powerpc/sysdev/fsl_mpic_err.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
/*
* Copyright (C) 2012 Freescale Semiconductor, Inc.
*
* Author: Varun Sethi <varun.sethi@freescale.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; version 2 of the
* License.
*
*/

#include <linux/irq.h>
#include <linux/smp.h>
#include <linux/interrupt.h>

#include <asm/io.h>
#include <asm/irq.h>
#include <asm/mpic.h>

#include "mpic.h"

#define MPIC_ERR_INT_BASE 0x3900
#define MPIC_ERR_INT_EISR 0x0000
#define MPIC_ERR_INT_EIMR 0x0010

static inline u32 mpic_fsl_err_read(u32 __iomem *base, unsigned int err_reg)
{
return in_be32(base + (err_reg >> 2));
}

static inline void mpic_fsl_err_write(u32 __iomem *base, u32 value)
{
out_be32(base + (MPIC_ERR_INT_EIMR >> 2), value);
}

static void fsl_mpic_mask_err(struct irq_data *d)
{
u32 eimr;
struct mpic *mpic = irq_data_get_irq_chip_data(d);
unsigned int src = virq_to_hw(d->irq) - mpic->err_int_vecs[0];

eimr = mpic_fsl_err_read(mpic->err_regs, MPIC_ERR_INT_EIMR);
eimr |= (1 << (31 - src));
mpic_fsl_err_write(mpic->err_regs, eimr);
}

static void fsl_mpic_unmask_err(struct irq_data *d)
{
u32 eimr;
struct mpic *mpic = irq_data_get_irq_chip_data(d);
unsigned int src = virq_to_hw(d->irq) - mpic->err_int_vecs[0];

eimr = mpic_fsl_err_read(mpic->err_regs, MPIC_ERR_INT_EIMR);
eimr &= ~(1 << (31 - src));
mpic_fsl_err_write(mpic->err_regs, eimr);
}

static struct irq_chip fsl_mpic_err_chip = {
.irq_disable = fsl_mpic_mask_err,
.irq_mask = fsl_mpic_mask_err,
.irq_unmask = fsl_mpic_unmask_err,
};

int mpic_setup_error_int(struct mpic *mpic, int intvec)
{
int i;

mpic->err_regs = ioremap(mpic->paddr + MPIC_ERR_INT_BASE, 0x1000);
if (!mpic->err_regs) {
pr_err("could not map mpic error registers\n");
return -ENOMEM;
}
mpic->hc_err = fsl_mpic_err_chip;
mpic->hc_err.name = mpic->name;
mpic->flags |= MPIC_FSL_HAS_EIMR;
/* allocate interrupt vectors for error interrupts */
for (i = MPIC_MAX_ERR - 1; i >= 0; i--)
mpic->err_int_vecs[i] = --intvec;

return 0;
}

int mpic_map_error_int(struct mpic *mpic, unsigned int virq, irq_hw_number_t hw)
{
if ((mpic->flags & MPIC_FSL_HAS_EIMR) &&
(hw >= mpic->err_int_vecs[0] &&
hw <= mpic->err_int_vecs[MPIC_MAX_ERR - 1])) {
WARN_ON(mpic->flags & MPIC_SECONDARY);

pr_debug("mpic: mapping as Error Interrupt\n");
irq_set_chip_data(virq, mpic);
irq_set_chip_and_handler(virq, &mpic->hc_err,
handle_level_irq);
return 1;
}

return 0;
}

static irqreturn_t fsl_error_int_handler(int irq, void *data)
{
struct mpic *mpic = (struct mpic *) data;
u32 eisr, eimr;
int errint;
unsigned int cascade_irq;

eisr = mpic_fsl_err_read(mpic->err_regs, MPIC_ERR_INT_EISR);
eimr = mpic_fsl_err_read(mpic->err_regs, MPIC_ERR_INT_EIMR);

if (!(eisr & ~eimr))
return IRQ_NONE;

while (eisr) {
errint = __builtin_clz(eisr);
cascade_irq = irq_linear_revmap(mpic->irqhost,
mpic->err_int_vecs[errint]);
WARN_ON(cascade_irq == NO_IRQ);
if (cascade_irq != NO_IRQ) {
generic_handle_irq(cascade_irq);
} else {
eimr |= 1 << (31 - errint);
mpic_fsl_err_write(mpic->err_regs, eimr);
}
eisr &= ~(1 << (31 - errint));
}

return IRQ_HANDLED;
}

void mpic_err_int_init(struct mpic *mpic, irq_hw_number_t irqnum)
{
unsigned int virq;
int ret;

virq = irq_create_mapping(mpic->irqhost, irqnum);
if (virq == NO_IRQ) {
pr_err("Error interrupt setup failed\n");
return;
}

/* Mask all error interrupts */
mpic_fsl_err_write(mpic->err_regs, ~0);

ret = request_irq(virq, fsl_error_int_handler, IRQF_NO_THREAD,
"mpic-error-int", mpic);
if (ret)
pr_err("Failed to register error interrupt handler\n");
}
44 changes: 43 additions & 1 deletion trunk/arch/powerpc/sysdev/mpic.c
Original file line number Diff line number Diff line change
Expand Up @@ -1026,6 +1026,9 @@ static int mpic_host_map(struct irq_domain *h, unsigned int virq,
return 0;
}

if (mpic_map_error_int(mpic, virq, hw))
return 0;

if (hw >= mpic->num_sources)
return -EINVAL;

Expand Down Expand Up @@ -1085,7 +1088,16 @@ static int mpic_host_xlate(struct irq_domain *h, struct device_node *ct,
*/
switch (intspec[2]) {
case 0:
case 1: /* no EISR/EIMR support for now, treat as shared IRQ */
break;
case 1:
if (!(mpic->flags & MPIC_FSL_HAS_EIMR))
break;

if (intspec[3] >= ARRAY_SIZE(mpic->err_int_vecs))
return -EINVAL;

*out_hwirq = mpic->err_int_vecs[intspec[3]];

break;
case 2:
if (intspec[0] >= ARRAY_SIZE(mpic->ipi_vecs))
Expand Down Expand Up @@ -1302,13 +1314,39 @@ struct mpic * __init mpic_alloc(struct device_node *node,
mpic_map(mpic, mpic->paddr, &mpic->tmregs, MPIC_INFO(TIMER_BASE), 0x1000);

if (mpic->flags & MPIC_FSL) {
u32 brr1, version;
int ret;

/*
* Yes, Freescale really did put global registers in the
* magic per-cpu area -- and they don't even show up in the
* non-magic per-cpu copies that this driver normally uses.
*/
mpic_map(mpic, mpic->paddr, &mpic->thiscpuregs,
MPIC_CPU_THISBASE, 0x1000);

brr1 = _mpic_read(mpic->reg_type, &mpic->thiscpuregs,
MPIC_FSL_BRR1);
version = brr1 & MPIC_FSL_BRR1_VER;

/* Error interrupt mask register (EIMR) is required for
* handling individual device error interrupts. EIMR
* was added in MPIC version 4.1.
*
* Over here we reserve vector number space for error
* interrupt vectors. This space is stolen from the
* global vector number space, as in case of ipis
* and timer interrupts.
*
* Available vector space = intvec_top - 12, where 12
* is the number of vectors which have been consumed by
* ipis and timer interrupts.
*/
if (version >= 0x401) {
ret = mpic_setup_error_int(mpic, intvec_top - 12);
if (ret)
return NULL;
}
}

/* Reset */
Expand Down Expand Up @@ -1474,6 +1512,10 @@ void __init mpic_init(struct mpic *mpic)
num_timers = 8;
}

/* FSL mpic error interrupt intialization */
if (mpic->flags & MPIC_FSL_HAS_EIMR)
mpic_err_int_init(mpic, MPIC_FSL_ERR_INT);

/* Initialize timers to our reserved vectors and mask them for now */
for (i = 0; i < num_timers; i++) {
unsigned int offset = mpic_tm_offset(mpic, i);
Expand Down
22 changes: 22 additions & 0 deletions trunk/arch/powerpc/sysdev/mpic.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,26 @@ extern int mpic_set_affinity(struct irq_data *d,
const struct cpumask *cpumask, bool force);
extern void mpic_reset_core(int cpu);

#ifdef CONFIG_FSL_SOC
extern int mpic_map_error_int(struct mpic *mpic, unsigned int virq, irq_hw_number_t hw);
extern void mpic_err_int_init(struct mpic *mpic, irq_hw_number_t irqnum);
extern int mpic_setup_error_int(struct mpic *mpic, int intvec);
#else
static inline int mpic_map_error_int(struct mpic *mpic, unsigned int virq, irq_hw_number_t hw)
{
return 0;
}


static inline void mpic_err_int_init(struct mpic *mpic, irq_hw_number_t irqnum)
{
return;
}

static inline int mpic_setup_error_int(struct mpic *mpic, int intvec)
{
return -1;
}
#endif

#endif /* _POWERPC_SYSDEV_MPIC_H */

0 comments on commit 77cb4de

Please sign in to comment.