Commit fbf0274e authored by Benjamin Herrenschmidt's avatar Benjamin Herrenschmidt Committed by Paul Mackerras

[POWERPC] Support for DCR based MPIC

This patch implements support for DCR based MPIC implementations. Such
implementations have the MPIC_USES_DCR flag set and don't use the phys_addr
argument of mpic_alloc (they require a valid dcr mapping in the device node)

This version of the patch can use a little bif of cleanup still (I can
probably consolidate rb->dbase/doff, at least once I'm sure on how the
hardware is actually supposed to work vs. possible simulator issues) and
it should be possible to build a DCR-only version of the driver. I need
to cleanup a bit the CONFIG_* handling for that and probably introduce
CONFIG_MPIC_MMIO and CONFIG_MPIC_DCR.
Signed-off-by: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: default avatarPaul Mackerras <paulus@samba.org>
parent 1be3770a
...@@ -147,33 +147,51 @@ static u32 mpic_infos[][MPIC_IDX_END] = { ...@@ -147,33 +147,51 @@ static u32 mpic_infos[][MPIC_IDX_END] = {
*/ */
static inline u32 _mpic_read(unsigned int be, volatile u32 __iomem *base, static inline u32 _mpic_read(enum mpic_reg_type type,
struct mpic_reg_bank *rb,
unsigned int reg) unsigned int reg)
{ {
if (be) switch(type) {
return in_be32(base + (reg >> 2)); #ifdef CONFIG_PPC_DCR
else case mpic_access_dcr:
return in_le32(base + (reg >> 2)); return dcr_read(rb->dhost,
rb->dbase + reg + rb->doff);
#endif
case mpic_access_mmio_be:
return in_be32(rb->base + (reg >> 2));
case mpic_access_mmio_le:
default:
return in_le32(rb->base + (reg >> 2));
}
} }
static inline void _mpic_write(unsigned int be, volatile u32 __iomem *base, static inline void _mpic_write(enum mpic_reg_type type,
struct mpic_reg_bank *rb,
unsigned int reg, u32 value) unsigned int reg, u32 value)
{ {
if (be) switch(type) {
out_be32(base + (reg >> 2), value); #ifdef CONFIG_PPC_DCR
else case mpic_access_dcr:
out_le32(base + (reg >> 2), value); return dcr_write(rb->dhost,
rb->dbase + reg + rb->doff, value);
#endif
case mpic_access_mmio_be:
return out_be32(rb->base + (reg >> 2), value);
case mpic_access_mmio_le:
default:
return out_le32(rb->base + (reg >> 2), value);
}
} }
static inline u32 _mpic_ipi_read(struct mpic *mpic, unsigned int ipi) static inline u32 _mpic_ipi_read(struct mpic *mpic, unsigned int ipi)
{ {
unsigned int be = (mpic->flags & MPIC_BIG_ENDIAN) != 0; enum mpic_reg_type type = mpic->reg_type;
unsigned int offset = MPIC_INFO(GREG_IPI_VECTOR_PRI_0) + unsigned int offset = MPIC_INFO(GREG_IPI_VECTOR_PRI_0) +
(ipi * MPIC_INFO(GREG_IPI_STRIDE)); (ipi * MPIC_INFO(GREG_IPI_STRIDE));
if (mpic->flags & MPIC_BROKEN_IPI) if ((mpic->flags & MPIC_BROKEN_IPI) && type == mpic_access_mmio_le)
be = !be; type = mpic_access_mmio_be;
return _mpic_read(be, mpic->gregs, offset); return _mpic_read(type, &mpic->gregs, offset);
} }
static inline void _mpic_ipi_write(struct mpic *mpic, unsigned int ipi, u32 value) static inline void _mpic_ipi_write(struct mpic *mpic, unsigned int ipi, u32 value)
...@@ -181,7 +199,7 @@ static inline void _mpic_ipi_write(struct mpic *mpic, unsigned int ipi, u32 valu ...@@ -181,7 +199,7 @@ static inline void _mpic_ipi_write(struct mpic *mpic, unsigned int ipi, u32 valu
unsigned int offset = MPIC_INFO(GREG_IPI_VECTOR_PRI_0) + unsigned int offset = MPIC_INFO(GREG_IPI_VECTOR_PRI_0) +
(ipi * MPIC_INFO(GREG_IPI_STRIDE)); (ipi * MPIC_INFO(GREG_IPI_STRIDE));
_mpic_write(mpic->flags & MPIC_BIG_ENDIAN, mpic->gregs, offset, value); _mpic_write(mpic->reg_type, &mpic->gregs, offset, value);
} }
static inline u32 _mpic_cpu_read(struct mpic *mpic, unsigned int reg) static inline u32 _mpic_cpu_read(struct mpic *mpic, unsigned int reg)
...@@ -190,8 +208,7 @@ static inline u32 _mpic_cpu_read(struct mpic *mpic, unsigned int reg) ...@@ -190,8 +208,7 @@ static inline u32 _mpic_cpu_read(struct mpic *mpic, unsigned int reg)
if (mpic->flags & MPIC_PRIMARY) if (mpic->flags & MPIC_PRIMARY)
cpu = hard_smp_processor_id(); cpu = hard_smp_processor_id();
return _mpic_read(mpic->flags & MPIC_BIG_ENDIAN, return _mpic_read(mpic->reg_type, &mpic->cpuregs[cpu], reg);
mpic->cpuregs[cpu], reg);
} }
static inline void _mpic_cpu_write(struct mpic *mpic, unsigned int reg, u32 value) static inline void _mpic_cpu_write(struct mpic *mpic, unsigned int reg, u32 value)
...@@ -201,7 +218,7 @@ static inline void _mpic_cpu_write(struct mpic *mpic, unsigned int reg, u32 valu ...@@ -201,7 +218,7 @@ static inline void _mpic_cpu_write(struct mpic *mpic, unsigned int reg, u32 valu
if (mpic->flags & MPIC_PRIMARY) if (mpic->flags & MPIC_PRIMARY)
cpu = hard_smp_processor_id(); cpu = hard_smp_processor_id();
_mpic_write(mpic->flags & MPIC_BIG_ENDIAN, mpic->cpuregs[cpu], reg, value); _mpic_write(mpic->reg_type, &mpic->cpuregs[cpu], reg, value);
} }
static inline u32 _mpic_irq_read(struct mpic *mpic, unsigned int src_no, unsigned int reg) static inline u32 _mpic_irq_read(struct mpic *mpic, unsigned int src_no, unsigned int reg)
...@@ -209,7 +226,7 @@ static inline u32 _mpic_irq_read(struct mpic *mpic, unsigned int src_no, unsigne ...@@ -209,7 +226,7 @@ static inline u32 _mpic_irq_read(struct mpic *mpic, unsigned int src_no, unsigne
unsigned int isu = src_no >> mpic->isu_shift; unsigned int isu = src_no >> mpic->isu_shift;
unsigned int idx = src_no & mpic->isu_mask; unsigned int idx = src_no & mpic->isu_mask;
return _mpic_read(mpic->flags & MPIC_BIG_ENDIAN, mpic->isus[isu], return _mpic_read(mpic->reg_type, &mpic->isus[isu],
reg + (idx * MPIC_INFO(IRQ_STRIDE))); reg + (idx * MPIC_INFO(IRQ_STRIDE)));
} }
...@@ -219,12 +236,12 @@ static inline void _mpic_irq_write(struct mpic *mpic, unsigned int src_no, ...@@ -219,12 +236,12 @@ static inline void _mpic_irq_write(struct mpic *mpic, unsigned int src_no,
unsigned int isu = src_no >> mpic->isu_shift; unsigned int isu = src_no >> mpic->isu_shift;
unsigned int idx = src_no & mpic->isu_mask; unsigned int idx = src_no & mpic->isu_mask;
_mpic_write(mpic->flags & MPIC_BIG_ENDIAN, mpic->isus[isu], _mpic_write(mpic->reg_type, &mpic->isus[isu],
reg + (idx * MPIC_INFO(IRQ_STRIDE)), value); reg + (idx * MPIC_INFO(IRQ_STRIDE)), value);
} }
#define mpic_read(b,r) _mpic_read(mpic->flags & MPIC_BIG_ENDIAN,(b),(r)) #define mpic_read(b,r) _mpic_read(mpic->reg_type,&(b),(r))
#define mpic_write(b,r,v) _mpic_write(mpic->flags & MPIC_BIG_ENDIAN,(b),(r),(v)) #define mpic_write(b,r,v) _mpic_write(mpic->reg_type,&(b),(r),(v))
#define mpic_ipi_read(i) _mpic_ipi_read(mpic,(i)) #define mpic_ipi_read(i) _mpic_ipi_read(mpic,(i))
#define mpic_ipi_write(i,v) _mpic_ipi_write(mpic,(i),(v)) #define mpic_ipi_write(i,v) _mpic_ipi_write(mpic,(i),(v))
#define mpic_cpu_read(i) _mpic_cpu_read(mpic,(i)) #define mpic_cpu_read(i) _mpic_cpu_read(mpic,(i))
...@@ -238,6 +255,38 @@ static inline void _mpic_irq_write(struct mpic *mpic, unsigned int src_no, ...@@ -238,6 +255,38 @@ static inline void _mpic_irq_write(struct mpic *mpic, unsigned int src_no,
*/ */
static void _mpic_map_mmio(struct mpic *mpic, unsigned long phys_addr,
struct mpic_reg_bank *rb, unsigned int offset,
unsigned int size)
{
rb->base = ioremap(phys_addr + offset, size);
BUG_ON(rb->base == NULL);
}
#ifdef CONFIG_PPC_DCR
static void _mpic_map_dcr(struct mpic *mpic, struct mpic_reg_bank *rb,
unsigned int offset, unsigned int size)
{
rb->dbase = mpic->dcr_base;
rb->doff = offset;
rb->dhost = dcr_map(mpic->of_node, rb->dbase + rb->doff, size);
BUG_ON(!DCR_MAP_OK(rb->dhost));
}
static inline void mpic_map(struct mpic *mpic, unsigned long phys_addr,
struct mpic_reg_bank *rb, unsigned int offset,
unsigned int size)
{
if (mpic->flags & MPIC_USES_DCR)
_mpic_map_dcr(mpic, rb, offset, size);
else
_mpic_map_mmio(mpic, phys_addr, rb, offset, size);
}
#else /* CONFIG_PPC_DCR */
#define mpic_map(m,p,b,o,s) _mpic_map_mmio(m,p,b,o,s)
#endif /* !CONFIG_PPC_DCR */
/* Check if we have one of those nice broken MPICs with a flipped endian on /* Check if we have one of those nice broken MPICs with a flipped endian on
* reads from IPI registers * reads from IPI registers
...@@ -883,6 +932,7 @@ struct mpic * __init mpic_alloc(struct device_node *node, ...@@ -883,6 +932,7 @@ struct mpic * __init mpic_alloc(struct device_node *node,
if (flags & MPIC_PRIMARY) if (flags & MPIC_PRIMARY)
mpic->hc_ht_irq.set_affinity = mpic_set_affinity; mpic->hc_ht_irq.set_affinity = mpic_set_affinity;
#endif /* CONFIG_MPIC_BROKEN_U3 */ #endif /* CONFIG_MPIC_BROKEN_U3 */
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
mpic->hc_ipi = mpic_ipi_chip; mpic->hc_ipi = mpic_ipi_chip;
mpic->hc_ipi.typename = name; mpic->hc_ipi.typename = name;
...@@ -897,11 +947,26 @@ struct mpic * __init mpic_alloc(struct device_node *node, ...@@ -897,11 +947,26 @@ struct mpic * __init mpic_alloc(struct device_node *node,
mpic->hw_set = mpic_infos[MPIC_GET_REGSET(flags)]; mpic->hw_set = mpic_infos[MPIC_GET_REGSET(flags)];
#endif #endif
/* default register type */
mpic->reg_type = (flags & MPIC_BIG_ENDIAN) ?
mpic_access_mmio_be : mpic_access_mmio_le;
#ifdef CONFIG_PPC_DCR
if (mpic->flags & MPIC_USES_DCR) {
const u32 *dbasep;
BUG_ON(mpic->of_node == NULL);
dbasep = get_property(mpic->of_node, "dcr-reg", NULL);
BUG_ON(dbasep == NULL);
mpic->dcr_base = *dbasep;
mpic->reg_type = mpic_access_dcr;
}
#else
BUG_ON (mpic->flags & MPIC_USES_DCR);
#endif /* CONFIG_PPC_DCR */
/* Map the global registers */ /* Map the global registers */
mpic->gregs = ioremap(phys_addr + MPIC_INFO(GREG_BASE), 0x1000); mpic_map(mpic, phys_addr, &mpic->gregs, MPIC_INFO(GREG_BASE), 0x1000);
mpic->tmregs = mpic->gregs + mpic_map(mpic, phys_addr, &mpic->tmregs, MPIC_INFO(TIMER_BASE), 0x1000);
((MPIC_INFO(TIMER_BASE) - MPIC_INFO(GREG_BASE)) >> 2);
BUG_ON(mpic->gregs == NULL);
/* Reset */ /* Reset */
if (flags & MPIC_WANTS_RESET) { if (flags & MPIC_WANTS_RESET) {
...@@ -926,17 +991,16 @@ struct mpic * __init mpic_alloc(struct device_node *node, ...@@ -926,17 +991,16 @@ struct mpic * __init mpic_alloc(struct device_node *node,
/* Map the per-CPU registers */ /* Map the per-CPU registers */
for (i = 0; i < mpic->num_cpus; i++) { for (i = 0; i < mpic->num_cpus; i++) {
mpic->cpuregs[i] = ioremap(phys_addr + MPIC_INFO(CPU_BASE) + mpic_map(mpic, phys_addr, &mpic->cpuregs[i],
i * MPIC_INFO(CPU_STRIDE), 0x1000); MPIC_INFO(CPU_BASE) + i * MPIC_INFO(CPU_STRIDE),
BUG_ON(mpic->cpuregs[i] == NULL); 0x1000);
} }
/* Initialize main ISU if none provided */ /* Initialize main ISU if none provided */
if (mpic->isu_size == 0) { if (mpic->isu_size == 0) {
mpic->isu_size = mpic->num_sources; mpic->isu_size = mpic->num_sources;
mpic->isus[0] = ioremap(phys_addr + MPIC_INFO(IRQ_BASE), mpic_map(mpic, phys_addr, &mpic->isus[0],
MPIC_INFO(IRQ_STRIDE) * mpic->isu_size); MPIC_INFO(IRQ_BASE), MPIC_INFO(IRQ_STRIDE) * mpic->isu_size);
BUG_ON(mpic->isus[0] == NULL);
} }
mpic->isu_shift = 1 + __ilog2(mpic->isu_size - 1); mpic->isu_shift = 1 + __ilog2(mpic->isu_size - 1);
mpic->isu_mask = (1 << mpic->isu_shift) - 1; mpic->isu_mask = (1 << mpic->isu_shift) - 1;
...@@ -979,7 +1043,7 @@ void __init mpic_assign_isu(struct mpic *mpic, unsigned int isu_num, ...@@ -979,7 +1043,7 @@ void __init mpic_assign_isu(struct mpic *mpic, unsigned int isu_num,
BUG_ON(isu_num >= MPIC_MAX_ISU); BUG_ON(isu_num >= MPIC_MAX_ISU);
mpic->isus[isu_num] = ioremap(phys_addr, mpic_map(mpic, phys_addr, &mpic->isus[isu_num], 0,
MPIC_INFO(IRQ_STRIDE) * mpic->isu_size); MPIC_INFO(IRQ_STRIDE) * mpic->isu_size);
if ((isu_first + mpic->isu_size) > mpic->num_sources) if ((isu_first + mpic->isu_size) > mpic->num_sources)
mpic->num_sources = isu_first + mpic->isu_size; mpic->num_sources = isu_first + mpic->isu_size;
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
#ifdef __KERNEL__ #ifdef __KERNEL__
#include <linux/irq.h> #include <linux/irq.h>
#include <asm/dcr.h>
/* /*
* Global registers * Global registers
...@@ -225,6 +226,23 @@ struct mpic_irq_fixup ...@@ -225,6 +226,23 @@ struct mpic_irq_fixup
#endif /* CONFIG_MPIC_BROKEN_U3 */ #endif /* CONFIG_MPIC_BROKEN_U3 */
enum mpic_reg_type {
mpic_access_mmio_le,
mpic_access_mmio_be,
#ifdef CONFIG_PPC_DCR
mpic_access_dcr
#endif
};
struct mpic_reg_bank {
u32 __iomem *base;
#ifdef CONFIG_PPC_DCR
dcr_host_t dhost;
unsigned int dbase;
unsigned int doff;
#endif /* CONFIG_PPC_DCR */
};
/* The instance data of a given MPIC */ /* The instance data of a given MPIC */
struct mpic struct mpic
{ {
...@@ -264,11 +282,18 @@ struct mpic ...@@ -264,11 +282,18 @@ struct mpic
spinlock_t fixup_lock; spinlock_t fixup_lock;
#endif #endif
/* Register access method */
enum mpic_reg_type reg_type;
/* The various ioremap'ed bases */ /* The various ioremap'ed bases */
volatile u32 __iomem *gregs; struct mpic_reg_bank gregs;
volatile u32 __iomem *tmregs; struct mpic_reg_bank tmregs;
volatile u32 __iomem *cpuregs[MPIC_MAX_CPUS]; struct mpic_reg_bank cpuregs[MPIC_MAX_CPUS];
volatile u32 __iomem *isus[MPIC_MAX_ISU]; struct mpic_reg_bank isus[MPIC_MAX_ISU];
#ifdef CONFIG_PPC_DCR
unsigned int dcr_base;
#endif
#ifdef CONFIG_MPIC_WEIRD #ifdef CONFIG_MPIC_WEIRD
/* Pointer to HW info array */ /* Pointer to HW info array */
...@@ -305,6 +330,8 @@ struct mpic ...@@ -305,6 +330,8 @@ struct mpic
#define MPIC_SPV_EOI 0x00000020 #define MPIC_SPV_EOI 0x00000020
/* No passthrough disable */ /* No passthrough disable */
#define MPIC_NO_PTHROU_DIS 0x00000040 #define MPIC_NO_PTHROU_DIS 0x00000040
/* DCR based MPIC */
#define MPIC_USES_DCR 0x00000080
/* MPIC HW modification ID */ /* MPIC HW modification ID */
#define MPIC_REGSET_MASK 0xf0000000 #define MPIC_REGSET_MASK 0xf0000000
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment