mirror of
https://github.com/torvalds/linux.git
synced 2024-11-17 17:41:44 +00:00
[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: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Paul Mackerras <paulus@samba.org>
This commit is contained in:
parent
1be3770aa9
commit
fbf0274e43
@ -147,33 +147,51 @@ static u32 mpic_infos[][MPIC_IDX_END] = {
|
||||
*/
|
||||
|
||||
|
||||
static inline u32 _mpic_read(unsigned int be, volatile u32 __iomem *base,
|
||||
unsigned int reg)
|
||||
static inline u32 _mpic_read(enum mpic_reg_type type,
|
||||
struct mpic_reg_bank *rb,
|
||||
unsigned int reg)
|
||||
{
|
||||
if (be)
|
||||
return in_be32(base + (reg >> 2));
|
||||
else
|
||||
return in_le32(base + (reg >> 2));
|
||||
switch(type) {
|
||||
#ifdef CONFIG_PPC_DCR
|
||||
case mpic_access_dcr:
|
||||
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,
|
||||
unsigned int reg, u32 value)
|
||||
static inline void _mpic_write(enum mpic_reg_type type,
|
||||
struct mpic_reg_bank *rb,
|
||||
unsigned int reg, u32 value)
|
||||
{
|
||||
if (be)
|
||||
out_be32(base + (reg >> 2), value);
|
||||
else
|
||||
out_le32(base + (reg >> 2), value);
|
||||
switch(type) {
|
||||
#ifdef CONFIG_PPC_DCR
|
||||
case mpic_access_dcr:
|
||||
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)
|
||||
{
|
||||
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) +
|
||||
(ipi * MPIC_INFO(GREG_IPI_STRIDE));
|
||||
|
||||
if (mpic->flags & MPIC_BROKEN_IPI)
|
||||
be = !be;
|
||||
return _mpic_read(be, mpic->gregs, offset);
|
||||
if ((mpic->flags & MPIC_BROKEN_IPI) && type == mpic_access_mmio_le)
|
||||
type = mpic_access_mmio_be;
|
||||
return _mpic_read(type, &mpic->gregs, offset);
|
||||
}
|
||||
|
||||
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
|
||||
unsigned int offset = MPIC_INFO(GREG_IPI_VECTOR_PRI_0) +
|
||||
(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)
|
||||
@ -190,8 +208,7 @@ static inline u32 _mpic_cpu_read(struct mpic *mpic, unsigned int reg)
|
||||
|
||||
if (mpic->flags & MPIC_PRIMARY)
|
||||
cpu = hard_smp_processor_id();
|
||||
return _mpic_read(mpic->flags & MPIC_BIG_ENDIAN,
|
||||
mpic->cpuregs[cpu], reg);
|
||||
return _mpic_read(mpic->reg_type, &mpic->cpuregs[cpu], reg);
|
||||
}
|
||||
|
||||
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
|
||||
if (mpic->flags & MPIC_PRIMARY)
|
||||
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)
|
||||
@ -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 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)));
|
||||
}
|
||||
|
||||
@ -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 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);
|
||||
}
|
||||
|
||||
#define mpic_read(b,r) _mpic_read(mpic->flags & MPIC_BIG_ENDIAN,(b),(r))
|
||||
#define mpic_write(b,r,v) _mpic_write(mpic->flags & MPIC_BIG_ENDIAN,(b),(r),(v))
|
||||
#define mpic_read(b,r) _mpic_read(mpic->reg_type,&(b),(r))
|
||||
#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_write(i,v) _mpic_ipi_write(mpic,(i),(v))
|
||||
#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,
|
||||
*/
|
||||
|
||||
|
||||
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
|
||||
* reads from IPI registers
|
||||
@ -883,6 +932,7 @@ struct mpic * __init mpic_alloc(struct device_node *node,
|
||||
if (flags & MPIC_PRIMARY)
|
||||
mpic->hc_ht_irq.set_affinity = mpic_set_affinity;
|
||||
#endif /* CONFIG_MPIC_BROKEN_U3 */
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
mpic->hc_ipi = mpic_ipi_chip;
|
||||
mpic->hc_ipi.typename = name;
|
||||
@ -897,11 +947,26 @@ struct mpic * __init mpic_alloc(struct device_node *node,
|
||||
mpic->hw_set = mpic_infos[MPIC_GET_REGSET(flags)];
|
||||
#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 */
|
||||
mpic->gregs = ioremap(phys_addr + MPIC_INFO(GREG_BASE), 0x1000);
|
||||
mpic->tmregs = mpic->gregs +
|
||||
((MPIC_INFO(TIMER_BASE) - MPIC_INFO(GREG_BASE)) >> 2);
|
||||
BUG_ON(mpic->gregs == NULL);
|
||||
mpic_map(mpic, phys_addr, &mpic->gregs, MPIC_INFO(GREG_BASE), 0x1000);
|
||||
mpic_map(mpic, phys_addr, &mpic->tmregs, MPIC_INFO(TIMER_BASE), 0x1000);
|
||||
|
||||
/* Reset */
|
||||
if (flags & MPIC_WANTS_RESET) {
|
||||
@ -926,17 +991,16 @@ struct mpic * __init mpic_alloc(struct device_node *node,
|
||||
|
||||
/* Map the per-CPU registers */
|
||||
for (i = 0; i < mpic->num_cpus; i++) {
|
||||
mpic->cpuregs[i] = ioremap(phys_addr + MPIC_INFO(CPU_BASE) +
|
||||
i * MPIC_INFO(CPU_STRIDE), 0x1000);
|
||||
BUG_ON(mpic->cpuregs[i] == NULL);
|
||||
mpic_map(mpic, phys_addr, &mpic->cpuregs[i],
|
||||
MPIC_INFO(CPU_BASE) + i * MPIC_INFO(CPU_STRIDE),
|
||||
0x1000);
|
||||
}
|
||||
|
||||
/* Initialize main ISU if none provided */
|
||||
if (mpic->isu_size == 0) {
|
||||
mpic->isu_size = mpic->num_sources;
|
||||
mpic->isus[0] = ioremap(phys_addr + MPIC_INFO(IRQ_BASE),
|
||||
MPIC_INFO(IRQ_STRIDE) * mpic->isu_size);
|
||||
BUG_ON(mpic->isus[0] == NULL);
|
||||
mpic_map(mpic, phys_addr, &mpic->isus[0],
|
||||
MPIC_INFO(IRQ_BASE), MPIC_INFO(IRQ_STRIDE) * mpic->isu_size);
|
||||
}
|
||||
mpic->isu_shift = 1 + __ilog2(mpic->isu_size - 1);
|
||||
mpic->isu_mask = (1 << mpic->isu_shift) - 1;
|
||||
@ -979,8 +1043,8 @@ void __init mpic_assign_isu(struct mpic *mpic, unsigned int isu_num,
|
||||
|
||||
BUG_ON(isu_num >= MPIC_MAX_ISU);
|
||||
|
||||
mpic->isus[isu_num] = ioremap(phys_addr,
|
||||
MPIC_INFO(IRQ_STRIDE) * mpic->isu_size);
|
||||
mpic_map(mpic, phys_addr, &mpic->isus[isu_num], 0,
|
||||
MPIC_INFO(IRQ_STRIDE) * mpic->isu_size);
|
||||
if ((isu_first + mpic->isu_size) > mpic->num_sources)
|
||||
mpic->num_sources = isu_first + mpic->isu_size;
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
#ifdef __KERNEL__
|
||||
|
||||
#include <linux/irq.h>
|
||||
#include <asm/dcr.h>
|
||||
|
||||
/*
|
||||
* Global registers
|
||||
@ -225,6 +226,23 @@ struct mpic_irq_fixup
|
||||
#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 */
|
||||
struct mpic
|
||||
{
|
||||
@ -264,11 +282,18 @@ struct mpic
|
||||
spinlock_t fixup_lock;
|
||||
#endif
|
||||
|
||||
/* Register access method */
|
||||
enum mpic_reg_type reg_type;
|
||||
|
||||
/* The various ioremap'ed bases */
|
||||
volatile u32 __iomem *gregs;
|
||||
volatile u32 __iomem *tmregs;
|
||||
volatile u32 __iomem *cpuregs[MPIC_MAX_CPUS];
|
||||
volatile u32 __iomem *isus[MPIC_MAX_ISU];
|
||||
struct mpic_reg_bank gregs;
|
||||
struct mpic_reg_bank tmregs;
|
||||
struct mpic_reg_bank cpuregs[MPIC_MAX_CPUS];
|
||||
struct mpic_reg_bank isus[MPIC_MAX_ISU];
|
||||
|
||||
#ifdef CONFIG_PPC_DCR
|
||||
unsigned int dcr_base;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MPIC_WEIRD
|
||||
/* Pointer to HW info array */
|
||||
@ -305,6 +330,8 @@ struct mpic
|
||||
#define MPIC_SPV_EOI 0x00000020
|
||||
/* No passthrough disable */
|
||||
#define MPIC_NO_PTHROU_DIS 0x00000040
|
||||
/* DCR based MPIC */
|
||||
#define MPIC_USES_DCR 0x00000080
|
||||
|
||||
/* MPIC HW modification ID */
|
||||
#define MPIC_REGSET_MASK 0xf0000000
|
||||
|
Loading…
Reference in New Issue
Block a user