Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 2998
b: refs/heads/master
c: cebf589
h: refs/heads/master
v: v3
  • Loading branch information
Arnd Bergmann authored and Paul Mackerras committed Jun 22, 2005
1 parent ef74b5c commit ea16ab1
Show file tree
Hide file tree
Showing 9 changed files with 615 additions and 12 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: fef1c772fa154c16e0a54577e9ecb5480f7b937e
refs/heads/master: cebf589c822b5de87098b57644024d16f8dbc1bb
15 changes: 15 additions & 0 deletions trunk/arch/ppc64/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,21 @@ config PPC_OF
bool
default y

config XICS
depends on PPC_PSERIES
bool
default y

config MPIC
depends on PPC_PSERIES || PPC_PMAC || PPC_MAPLE
bool
default y

config BPA_IIC
depends on PPC_BPA
bool
default y

# VMX is pSeries only for now until somebody writes the iSeries
# exception vectors for it
config ALTIVEC
Expand Down
8 changes: 5 additions & 3 deletions trunk/arch/ppc64/kernel/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,13 @@ obj-$(CONFIG_PPC_ISERIES) += HvCall.o HvLpConfig.o LparData.o \
mf.o HvLpEvent.o iSeries_proc.o iSeries_htab.o \
iSeries_iommu.o

obj-$(CONFIG_PPC_MULTIPLATFORM) += nvram.o i8259.o prom_init.o prom.o mpic.o
obj-$(CONFIG_PPC_MULTIPLATFORM) += nvram.o i8259.o prom_init.o prom.o

obj-$(CONFIG_PPC_PSERIES) += pSeries_pci.o pSeries_lpar.o pSeries_hvCall.o \
pSeries_nvram.o rtasd.o ras.o pSeries_reconfig.o \
xics.o pSeries_setup.o pSeries_iommu.o
pSeries_setup.o pSeries_iommu.o

obj-$(CONFIG_PPC_BPA) += bpa_setup.o bpa_nvram.o
obj-$(CONFIG_PPC_BPA) += bpa_setup.o bpa_nvram.o bpa_iic.o spider-pic.o

obj-$(CONFIG_EEH) += eeh.o
obj-$(CONFIG_PROC_FS) += proc_ppc64.o
Expand All @@ -49,6 +49,8 @@ obj-$(CONFIG_HVC_CONSOLE) += hvconsole.o
obj-$(CONFIG_BOOTX_TEXT) += btext.o
obj-$(CONFIG_HVCS) += hvcserver.o
obj-$(CONFIG_IBMVIO) += vio.o
obj-$(CONFIG_XICS) += xics.o
obj-$(CONFIG_MPIC) += mpic.o

obj-$(CONFIG_PPC_PMAC) += pmac_setup.o pmac_feature.o pmac_pci.o \
pmac_time.o pmac_nvram.o pmac_low_i2c.o
Expand Down
270 changes: 270 additions & 0 deletions trunk/arch/ppc64/kernel/bpa_iic.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,270 @@
/*
* BPA Internal Interrupt Controller
*
* (C) Copyright IBM Deutschland Entwicklung GmbH 2005
*
* Author: Arnd Bergmann <arndb@de.ibm.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; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include <linux/config.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/percpu.h>
#include <linux/types.h>

#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/prom.h>
#include <asm/ptrace.h>

#include "bpa_iic.h"

struct iic_pending_bits {
u32 data;
u8 flags;
u8 class;
u8 source;
u8 prio;
};

enum iic_pending_flags {
IIC_VALID = 0x80,
IIC_IPI = 0x40,
};

struct iic_regs {
struct iic_pending_bits pending;
struct iic_pending_bits pending_destr;
u64 generate;
u64 prio;
};

struct iic {
struct iic_regs __iomem *regs;
};

static DEFINE_PER_CPU(struct iic, iic);

void iic_local_enable(void)
{
out_be64(&__get_cpu_var(iic).regs->prio, 0xff);
}

void iic_local_disable(void)
{
out_be64(&__get_cpu_var(iic).regs->prio, 0x0);
}

static unsigned int iic_startup(unsigned int irq)
{
return 0;
}

static void iic_enable(unsigned int irq)
{
iic_local_enable();
}

static void iic_disable(unsigned int irq)
{
}

static void iic_end(unsigned int irq)
{
iic_local_enable();
}

static struct hw_interrupt_type iic_pic = {
.typename = " BPA-IIC ",
.startup = iic_startup,
.enable = iic_enable,
.disable = iic_disable,
.end = iic_end,
};

static int iic_external_get_irq(struct iic_pending_bits pending)
{
int irq;
unsigned char node, unit;

node = pending.source >> 4;
unit = pending.source & 0xf;
irq = -1;

/*
* This mapping is specific to the Broadband
* Engine. We might need to get the numbers
* from the device tree to support future CPUs.
*/
switch (unit) {
case 0x00:
case 0x0b:
/*
* One of these units can be connected
* to an external interrupt controller.
*/
if (pending.prio > 0x3f ||
pending.class != 2)
break;
irq = IIC_EXT_OFFSET
+ spider_get_irq(pending.prio + node * IIC_NODE_STRIDE)
+ node * IIC_NODE_STRIDE;
break;
case 0x01 ... 0x04:
case 0x07 ... 0x0a:
/*
* These units are connected to the SPEs
*/
if (pending.class > 2)
break;
irq = IIC_SPE_OFFSET
+ pending.class * IIC_CLASS_STRIDE
+ node * IIC_NODE_STRIDE
+ unit;
break;
}
if (irq == -1)
printk(KERN_WARNING "Unexpected interrupt class %02x, "
"source %02x, prio %02x, cpu %02x\n", pending.class,
pending.source, pending.prio, smp_processor_id());
return irq;
}

/* Get an IRQ number from the pending state register of the IIC */
int iic_get_irq(struct pt_regs *regs)
{
struct iic *iic;
int irq;
struct iic_pending_bits pending;

iic = &__get_cpu_var(iic);
*(unsigned long *) &pending =
in_be64((unsigned long __iomem *) &iic->regs->pending_destr);

irq = -1;
if (pending.flags & IIC_VALID) {
if (pending.flags & IIC_IPI) {
irq = IIC_IPI_OFFSET + (pending.prio >> 4);
/*
if (irq > 0x80)
printk(KERN_WARNING "Unexpected IPI prio %02x"
"on CPU %02x\n", pending.prio,
smp_processor_id());
*/
} else {
irq = iic_external_get_irq(pending);
}
}
return irq;
}

static struct iic_regs __iomem *find_iic(int cpu)
{
struct device_node *np;
int nodeid = cpu / 2;
unsigned long regs;
struct iic_regs __iomem *iic_regs;

for (np = of_find_node_by_type(NULL, "cpu");
np;
np = of_find_node_by_type(np, "cpu")) {
if (nodeid == *(int *)get_property(np, "node-id", NULL))
break;
}

if (!np) {
printk(KERN_WARNING "IIC: CPU %d not found\n", cpu);
iic_regs = NULL;
} else {
regs = *(long *)get_property(np, "iic", NULL);

/* hack until we have decided on the devtree info */
regs += 0x400;
if (cpu & 1)
regs += 0x20;

printk(KERN_DEBUG "IIC for CPU %d at %lx\n", cpu, regs);
iic_regs = __ioremap(regs, sizeof(struct iic_regs),
_PAGE_NO_CACHE);
}
return iic_regs;
}

#ifdef CONFIG_SMP
void iic_setup_cpu(void)
{
out_be64(&__get_cpu_var(iic).regs->prio, 0xff);
}

void iic_cause_IPI(int cpu, int mesg)
{
out_be64(&per_cpu(iic, cpu).regs->generate, mesg);
}

static irqreturn_t iic_ipi_action(int irq, void *dev_id, struct pt_regs *regs)
{

smp_message_recv(irq - IIC_IPI_OFFSET, regs);
return IRQ_HANDLED;
}

static void iic_request_ipi(int irq, const char *name)
{
/* IPIs are marked SA_INTERRUPT as they must run with irqs
* disabled */
get_irq_desc(irq)->handler = &iic_pic;
get_irq_desc(irq)->status |= IRQ_PER_CPU;
request_irq(irq, iic_ipi_action, SA_INTERRUPT, name, NULL);
}

void iic_request_IPIs(void)
{
iic_request_ipi(IIC_IPI_OFFSET + PPC_MSG_CALL_FUNCTION, "IPI-call");
iic_request_ipi(IIC_IPI_OFFSET + PPC_MSG_RESCHEDULE, "IPI-resched");
#ifdef CONFIG_DEBUGGER
iic_request_ipi(IIC_IPI_OFFSET + PPC_MSG_DEBUGGER_BREAK, "IPI-debug");
#endif /* CONFIG_DEBUGGER */
}
#endif /* CONFIG_SMP */

static void iic_setup_spe_handlers(void)
{
int be, isrc;

/* Assume two threads per BE are present */
for (be=0; be < num_present_cpus() / 2; be++) {
for (isrc = 0; isrc < IIC_CLASS_STRIDE * 3; isrc++) {
int irq = IIC_NODE_STRIDE * be + IIC_SPE_OFFSET + isrc;
get_irq_desc(irq)->handler = &iic_pic;
}
}
}

void iic_init_IRQ(void)
{
int cpu, irq_offset;
struct iic *iic;

irq_offset = 0;
for_each_cpu(cpu) {
iic = &per_cpu(iic, cpu);
iic->regs = find_iic(cpu);
if (iic->regs)
out_be64(&iic->regs->prio, 0xff);
}
iic_setup_spe_handlers();
}
62 changes: 62 additions & 0 deletions trunk/arch/ppc64/kernel/bpa_iic.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#ifndef ASM_BPA_IIC_H
#define ASM_BPA_IIC_H
#ifdef __KERNEL__
/*
* Mapping of IIC pending bits into per-node
* interrupt numbers.
*
* IRQ FF CC SS PP FF CC SS PP Description
*
* 00-3f 80 02 +0 00 - 80 02 +0 3f South Bridge
* 00-3f 80 02 +b 00 - 80 02 +b 3f South Bridge
* 41-4a 80 00 +1 ** - 80 00 +a ** SPU Class 0
* 51-5a 80 01 +1 ** - 80 01 +a ** SPU Class 1
* 61-6a 80 02 +1 ** - 80 02 +a ** SPU Class 2
* 70-7f C0 ** ** 00 - C0 ** ** 0f IPI
*
* F flags
* C class
* S source
* P Priority
* + node number
* * don't care
*
* A node consists of a Broadband Engine and an optional
* south bridge device providing a maximum of 64 IRQs.
* The south bridge may be connected to either IOIF0
* or IOIF1.
* Each SPE is represented as three IRQ lines, one per
* interrupt class.
* 16 IRQ numbers are reserved for inter processor
* interruptions, although these are only used in the
* range of the first node.
*
* This scheme needs 128 IRQ numbers per BIF node ID,
* which means that with the total of 512 lines
* available, we can have a maximum of four nodes.
*/

enum {
IIC_EXT_OFFSET = 0x00, /* Start of south bridge IRQs */
IIC_NUM_EXT = 0x40, /* Number of south bridge IRQs */
IIC_SPE_OFFSET = 0x40, /* Start of SPE interrupts */
IIC_CLASS_STRIDE = 0x10, /* SPE IRQs per class */
IIC_IPI_OFFSET = 0x70, /* Start of IPI IRQs */
IIC_NUM_IPIS = 0x10, /* IRQs reserved for IPI */
IIC_NODE_STRIDE = 0x80, /* Total IRQs per node */
};

extern void iic_init_IRQ(void);
extern int iic_get_irq(struct pt_regs *regs);
extern void iic_cause_IPI(int cpu, int mesg);
extern void iic_request_IPIs(void);
extern void iic_setup_cpu(void);
extern void iic_local_enable(void);
extern void iic_local_disable(void);


extern void spider_init_IRQ(void);
extern int spider_get_irq(unsigned long int_pending);

#endif
#endif /* ASM_BPA_IIC_H */
Loading

0 comments on commit ea16ab1

Please sign in to comment.