Commit 0ebfff14 authored by Benjamin Herrenschmidt's avatar Benjamin Herrenschmidt Committed by Paul Mackerras

[POWERPC] Add new interrupt mapping core and change platforms to use it

This adds the new irq remapper core and removes the old one.  Because
there are some fundamental conflicts with the old code, like the value
of NO_IRQ which I'm now setting to 0 (as per discussions with Linus),
etc..., this commit also changes the relevant platform and driver code
over to use the new remapper (so as not to cause difficulties later
in bisecting).

This patch removes the old pre-parsing of the open firmware interrupt
tree along with all the bogus assumptions it made to try to renumber
interrupts according to the platform. This is all to be handled by the
new code now.

For the pSeries XICS interrupt controller, a single remapper host is
created for the whole machine regardless of how many interrupt
presentation and source controllers are found, and it's set to match
any device node that isn't a 8259.  That works fine on pSeries and
avoids having to deal with some of the complexities of split source
controllers vs. presentation controllers in the pSeries device trees.

The powerpc i8259 PIC driver now always requests the legacy interrupt
range. It also has the feature of being able to match any device node
(including NULL) if passed no device node as an input. That will help
porting over platforms with broken device-trees like Pegasos who don't
have a proper interrupt tree.
Signed-off-by: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: default avatarPaul Mackerras <paulus@samba.org>
parent f63e115f
...@@ -323,13 +323,11 @@ int ibmebus_request_irq(struct ibmebus_dev *dev, ...@@ -323,13 +323,11 @@ int ibmebus_request_irq(struct ibmebus_dev *dev,
unsigned long irq_flags, const char * devname, unsigned long irq_flags, const char * devname,
void *dev_id) void *dev_id)
{ {
unsigned int irq = virt_irq_create_mapping(ist); unsigned int irq = irq_create_mapping(NULL, ist, 0);
if (irq == NO_IRQ) if (irq == NO_IRQ)
return -EINVAL; return -EINVAL;
irq = irq_offset_up(irq);
return request_irq(irq, handler, return request_irq(irq, handler,
irq_flags, devname, dev_id); irq_flags, devname, dev_id);
} }
...@@ -337,12 +335,9 @@ EXPORT_SYMBOL(ibmebus_request_irq); ...@@ -337,12 +335,9 @@ EXPORT_SYMBOL(ibmebus_request_irq);
void ibmebus_free_irq(struct ibmebus_dev *dev, u32 ist, void *dev_id) void ibmebus_free_irq(struct ibmebus_dev *dev, u32 ist, void *dev_id)
{ {
unsigned int irq = virt_irq_create_mapping(ist); unsigned int irq = irq_find_mapping(NULL, ist);
irq = irq_offset_up(irq);
free_irq(irq, dev_id); free_irq(irq, dev_id);
return;
} }
EXPORT_SYMBOL(ibmebus_free_irq); EXPORT_SYMBOL(ibmebus_free_irq);
......
This diff is collapsed.
...@@ -28,6 +28,7 @@ static struct legacy_serial_info { ...@@ -28,6 +28,7 @@ static struct legacy_serial_info {
struct device_node *np; struct device_node *np;
unsigned int speed; unsigned int speed;
unsigned int clock; unsigned int clock;
int irq_check_parent;
phys_addr_t taddr; phys_addr_t taddr;
} legacy_serial_infos[MAX_LEGACY_SERIAL_PORTS]; } legacy_serial_infos[MAX_LEGACY_SERIAL_PORTS];
static unsigned int legacy_serial_count; static unsigned int legacy_serial_count;
...@@ -36,7 +37,7 @@ static int legacy_serial_console = -1; ...@@ -36,7 +37,7 @@ static int legacy_serial_console = -1;
static int __init add_legacy_port(struct device_node *np, int want_index, static int __init add_legacy_port(struct device_node *np, int want_index,
int iotype, phys_addr_t base, int iotype, phys_addr_t base,
phys_addr_t taddr, unsigned long irq, phys_addr_t taddr, unsigned long irq,
upf_t flags) upf_t flags, int irq_check_parent)
{ {
u32 *clk, *spd, clock = BASE_BAUD * 16; u32 *clk, *spd, clock = BASE_BAUD * 16;
int index; int index;
...@@ -68,7 +69,7 @@ static int __init add_legacy_port(struct device_node *np, int want_index, ...@@ -68,7 +69,7 @@ static int __init add_legacy_port(struct device_node *np, int want_index,
if (legacy_serial_infos[index].np != 0) { if (legacy_serial_infos[index].np != 0) {
/* if we still have some room, move it, else override */ /* if we still have some room, move it, else override */
if (legacy_serial_count < MAX_LEGACY_SERIAL_PORTS) { if (legacy_serial_count < MAX_LEGACY_SERIAL_PORTS) {
printk(KERN_INFO "Moved legacy port %d -> %d\n", printk(KERN_DEBUG "Moved legacy port %d -> %d\n",
index, legacy_serial_count); index, legacy_serial_count);
legacy_serial_ports[legacy_serial_count] = legacy_serial_ports[legacy_serial_count] =
legacy_serial_ports[index]; legacy_serial_ports[index];
...@@ -76,7 +77,7 @@ static int __init add_legacy_port(struct device_node *np, int want_index, ...@@ -76,7 +77,7 @@ static int __init add_legacy_port(struct device_node *np, int want_index,
legacy_serial_infos[index]; legacy_serial_infos[index];
legacy_serial_count++; legacy_serial_count++;
} else { } else {
printk(KERN_INFO "Replacing legacy port %d\n", index); printk(KERN_DEBUG "Replacing legacy port %d\n", index);
} }
} }
...@@ -95,10 +96,11 @@ static int __init add_legacy_port(struct device_node *np, int want_index, ...@@ -95,10 +96,11 @@ static int __init add_legacy_port(struct device_node *np, int want_index,
legacy_serial_infos[index].np = of_node_get(np); legacy_serial_infos[index].np = of_node_get(np);
legacy_serial_infos[index].clock = clock; legacy_serial_infos[index].clock = clock;
legacy_serial_infos[index].speed = spd ? *spd : 0; legacy_serial_infos[index].speed = spd ? *spd : 0;
legacy_serial_infos[index].irq_check_parent = irq_check_parent;
printk(KERN_INFO "Found legacy serial port %d for %s\n", printk(KERN_DEBUG "Found legacy serial port %d for %s\n",
index, np->full_name); index, np->full_name);
printk(KERN_INFO " %s=%llx, taddr=%llx, irq=%lx, clk=%d, speed=%d\n", printk(KERN_DEBUG " %s=%llx, taddr=%llx, irq=%lx, clk=%d, speed=%d\n",
(iotype == UPIO_PORT) ? "port" : "mem", (iotype == UPIO_PORT) ? "port" : "mem",
(unsigned long long)base, (unsigned long long)taddr, irq, (unsigned long long)base, (unsigned long long)taddr, irq,
legacy_serial_ports[index].uartclk, legacy_serial_ports[index].uartclk,
...@@ -132,7 +134,7 @@ static int __init add_legacy_soc_port(struct device_node *np, ...@@ -132,7 +134,7 @@ static int __init add_legacy_soc_port(struct device_node *np,
/* Add port, irq will be dealt with later. We passed a translated /* Add port, irq will be dealt with later. We passed a translated
* IO port value. It will be fixed up later along with the irq * IO port value. It will be fixed up later along with the irq
*/ */
return add_legacy_port(np, -1, UPIO_MEM, addr, addr, NO_IRQ, flags); return add_legacy_port(np, -1, UPIO_MEM, addr, addr, NO_IRQ, flags, 0);
} }
static int __init add_legacy_isa_port(struct device_node *np, static int __init add_legacy_isa_port(struct device_node *np,
...@@ -170,7 +172,7 @@ static int __init add_legacy_isa_port(struct device_node *np, ...@@ -170,7 +172,7 @@ static int __init add_legacy_isa_port(struct device_node *np,
/* Add port, irq will be dealt with later */ /* Add port, irq will be dealt with later */
return add_legacy_port(np, index, UPIO_PORT, reg[1], taddr, return add_legacy_port(np, index, UPIO_PORT, reg[1], taddr,
NO_IRQ, UPF_BOOT_AUTOCONF); NO_IRQ, UPF_BOOT_AUTOCONF, 0);
} }
...@@ -242,7 +244,8 @@ static int __init add_legacy_pci_port(struct device_node *np, ...@@ -242,7 +244,8 @@ static int __init add_legacy_pci_port(struct device_node *np,
/* Add port, irq will be dealt with later. We passed a translated /* Add port, irq will be dealt with later. We passed a translated
* IO port value. It will be fixed up later along with the irq * IO port value. It will be fixed up later along with the irq
*/ */
return add_legacy_port(np, index, iotype, base, addr, NO_IRQ, UPF_BOOT_AUTOCONF); return add_legacy_port(np, index, iotype, base, addr, NO_IRQ,
UPF_BOOT_AUTOCONF, np != pci_dev);
} }
#endif #endif
...@@ -373,27 +376,22 @@ static void __init fixup_port_irq(int index, ...@@ -373,27 +376,22 @@ static void __init fixup_port_irq(int index,
struct device_node *np, struct device_node *np,
struct plat_serial8250_port *port) struct plat_serial8250_port *port)
{ {
unsigned int virq;
DBG("fixup_port_irq(%d)\n", index); DBG("fixup_port_irq(%d)\n", index);
/* Check for interrupts in that node */ virq = irq_of_parse_and_map(np, 0);
if (np->n_intrs > 0) { if (virq == NO_IRQ && legacy_serial_infos[index].irq_check_parent) {
port->irq = np->intrs[0].line; np = of_get_parent(np);
DBG(" port %d (%s), irq=%d\n", if (np == NULL)
index, np->full_name, port->irq); return;
return; virq = irq_of_parse_and_map(np, 0);
of_node_put(np);
} }
if (virq == NO_IRQ)
/* Check for interrupts in the parent */
np = of_get_parent(np);
if (np == NULL)
return; return;
if (np->n_intrs > 0) { port->irq = virq;
port->irq = np->intrs[0].line;
DBG(" port %d (%s), irq=%d\n",
index, np->full_name, port->irq);
}
of_node_put(np);
} }
static void __init fixup_port_pio(int index, static void __init fixup_port_pio(int index,
......
...@@ -1404,6 +1404,43 @@ pcibios_update_irq(struct pci_dev *dev, int irq) ...@@ -1404,6 +1404,43 @@ pcibios_update_irq(struct pci_dev *dev, int irq)
/* XXX FIXME - update OF device tree node interrupt property */ /* XXX FIXME - update OF device tree node interrupt property */
} }
#ifdef CONFIG_PPC_MERGE
/* XXX This is a copy of the ppc64 version. This is temporary until we start
* merging the 2 PCI layers
*/
/*
* Reads the interrupt pin to determine if interrupt is use by card.
* If the interrupt is used, then gets the interrupt line from the
* openfirmware and sets it in the pci_dev and pci_config line.
*/
int pci_read_irq_line(struct pci_dev *pci_dev)
{
struct of_irq oirq;
unsigned int virq;
DBG("Try to map irq for %s...\n", pci_name(pci_dev));
if (of_irq_map_pci(pci_dev, &oirq)) {
DBG(" -> failed !\n");
return -1;
}
DBG(" -> got one, spec %d cells (0x%08x...) on %s\n",
oirq.size, oirq.specifier[0], oirq.controller->full_name);
virq = irq_create_of_mapping(oirq.controller, oirq.specifier, oirq.size);
if(virq == NO_IRQ) {
DBG(" -> failed to map !\n");
return -1;
}
pci_dev->irq = virq;
pci_write_config_byte(pci_dev, PCI_INTERRUPT_LINE, virq);
return 0;
}
EXPORT_SYMBOL(pci_read_irq_line);
#endif /* CONFIG_PPC_MERGE */
int pcibios_enable_device(struct pci_dev *dev, int mask) int pcibios_enable_device(struct pci_dev *dev, int mask)
{ {
u16 cmd, old_cmd; u16 cmd, old_cmd;
......
...@@ -398,12 +398,8 @@ struct pci_dev *of_create_pci_dev(struct device_node *node, ...@@ -398,12 +398,8 @@ struct pci_dev *of_create_pci_dev(struct device_node *node,
} else { } else {
dev->hdr_type = PCI_HEADER_TYPE_NORMAL; dev->hdr_type = PCI_HEADER_TYPE_NORMAL;
dev->rom_base_reg = PCI_ROM_ADDRESS; dev->rom_base_reg = PCI_ROM_ADDRESS;
/* Maybe do a default OF mapping here */
dev->irq = NO_IRQ; dev->irq = NO_IRQ;
if (node->n_intrs > 0) {
dev->irq = node->intrs[0].line;
pci_write_config_byte(dev, PCI_INTERRUPT_LINE,
dev->irq);
}
} }
pci_parse_of_addrs(node, dev); pci_parse_of_addrs(node, dev);
...@@ -1288,23 +1284,26 @@ EXPORT_SYMBOL(pcibios_fixup_bus); ...@@ -1288,23 +1284,26 @@ EXPORT_SYMBOL(pcibios_fixup_bus);
*/ */
int pci_read_irq_line(struct pci_dev *pci_dev) int pci_read_irq_line(struct pci_dev *pci_dev)
{ {
u8 intpin; struct of_irq oirq;
struct device_node *node; unsigned int virq;
pci_read_config_byte(pci_dev, PCI_INTERRUPT_PIN, &intpin);
if (intpin == 0)
return 0;
node = pci_device_to_OF_node(pci_dev); DBG("Try to map irq for %s...\n", pci_name(pci_dev));
if (node == NULL)
return -1;
if (node->n_intrs == 0) if (of_irq_map_pci(pci_dev, &oirq)) {
DBG(" -> failed !\n");
return -1; return -1;
}
pci_dev->irq = node->intrs[0].line; DBG(" -> got one, spec %d cells (0x%08x...) on %s\n",
oirq.size, oirq.specifier[0], oirq.controller->full_name);
pci_write_config_byte(pci_dev, PCI_INTERRUPT_LINE, pci_dev->irq); virq = irq_create_of_mapping(oirq.controller, oirq.specifier, oirq.size);
if(virq == NO_IRQ) {
DBG(" -> failed to map !\n");
return -1;
}
pci_dev->irq = virq;
pci_write_config_byte(pci_dev, PCI_INTERRUPT_LINE, virq);
return 0; return 0;
} }
......
This diff is collapsed.
...@@ -297,19 +297,9 @@ unsigned long __init find_and_init_phbs(void) ...@@ -297,19 +297,9 @@ unsigned long __init find_and_init_phbs(void)
struct device_node *node; struct device_node *node;
struct pci_controller *phb; struct pci_controller *phb;
unsigned int index; unsigned int index;
unsigned int root_size_cells = 0;
unsigned int *opprop = NULL;
struct device_node *root = of_find_node_by_path("/"); struct device_node *root = of_find_node_by_path("/");
if (ppc64_interrupt_controller == IC_OPEN_PIC) {
opprop = (unsigned int *)get_property(root,
"platform-open-pic", NULL);
}
root_size_cells = prom_n_size_cells(root);
index = 0; index = 0;
for (node = of_get_next_child(root, NULL); for (node = of_get_next_child(root, NULL);
node != NULL; node != NULL;
node = of_get_next_child(root, node)) { node = of_get_next_child(root, node)) {
...@@ -324,13 +314,6 @@ unsigned long __init find_and_init_phbs(void) ...@@ -324,13 +314,6 @@ unsigned long __init find_and_init_phbs(void)
setup_phb(node, phb); setup_phb(node, phb);
pci_process_bridge_OF_ranges(phb, node, 0); pci_process_bridge_OF_ranges(phb, node, 0);
pci_setup_phb_io(phb, index == 0); pci_setup_phb_io(phb, index == 0);
#ifdef CONFIG_PPC_PSERIES
/* XXX This code need serious fixing ... --BenH */
if (ppc64_interrupt_controller == IC_OPEN_PIC && pSeries_mpic) {
int addr = root_size_cells * (index + 2) - 1;
mpic_assign_isu(pSeries_mpic, index, opprop[addr]);
}
#endif
index++; index++;
} }
......
...@@ -239,7 +239,6 @@ void __init setup_arch(char **cmdline_p) ...@@ -239,7 +239,6 @@ void __init setup_arch(char **cmdline_p)
ppc_md.init_early(); ppc_md.init_early();
find_legacy_serial_ports(); find_legacy_serial_ports();
finish_device_tree();
smp_setup_cpu_maps(); smp_setup_cpu_maps();
......
...@@ -361,12 +361,15 @@ void __init setup_system(void) ...@@ -361,12 +361,15 @@ void __init setup_system(void)
/* /*
* Fill the ppc64_caches & systemcfg structures with informations * Fill the ppc64_caches & systemcfg structures with informations
* retrieved from the device-tree. Need to be called before * retrieved from the device-tree.
* finish_device_tree() since the later requires some of the
* informations filled up here to properly parse the interrupt tree.
*/ */
initialize_cache_info(); initialize_cache_info();
/*
* Initialize irq remapping subsystem
*/
irq_early_init();
#ifdef CONFIG_PPC_RTAS #ifdef CONFIG_PPC_RTAS
/* /*
* Initialize RTAS if available * Initialize RTAS if available
...@@ -393,12 +396,6 @@ void __init setup_system(void) ...@@ -393,12 +396,6 @@ void __init setup_system(void)
*/ */
find_legacy_serial_ports(); find_legacy_serial_ports();
/*
* "Finish" the device-tree, that is do the actual parsing of
* some of the properties like the interrupt map
*/
finish_device_tree();
/* /*
* Initialize xmon * Initialize xmon
*/ */
...@@ -427,8 +424,6 @@ void __init setup_system(void) ...@@ -427,8 +424,6 @@ void __init setup_system(void)
printk("-----------------------------------------------------\n"); printk("-----------------------------------------------------\n");
printk("ppc64_pft_size = 0x%lx\n", ppc64_pft_size); printk("ppc64_pft_size = 0x%lx\n", ppc64_pft_size);
printk("ppc64_interrupt_controller = 0x%ld\n",
ppc64_interrupt_controller);
printk("physicalMemorySize = 0x%lx\n", lmb_phys_mem_size()); printk("physicalMemorySize = 0x%lx\n", lmb_phys_mem_size());
printk("ppc64_caches.dcache_line_size = 0x%x\n", printk("ppc64_caches.dcache_line_size = 0x%x\n",
ppc64_caches.dline_size); ppc64_caches.dline_size);
......
...@@ -218,7 +218,6 @@ struct vio_dev * __devinit vio_register_device_node(struct device_node *of_node) ...@@ -218,7 +218,6 @@ struct vio_dev * __devinit vio_register_device_node(struct device_node *of_node)
{ {
struct vio_dev *viodev; struct vio_dev *viodev;
unsigned int *unit_address; unsigned int *unit_address;
unsigned int *irq_p;
/* we need the 'device_type' property, in order to match with drivers */ /* we need the 'device_type' property, in order to match with drivers */
if (of_node->type == NULL) { if (of_node->type == NULL) {
...@@ -243,16 +242,7 @@ struct vio_dev * __devinit vio_register_device_node(struct device_node *of_node) ...@@ -243,16 +242,7 @@ struct vio_dev * __devinit vio_register_device_node(struct device_node *of_node)
viodev->dev.platform_data = of_node_get(of_node); viodev->dev.platform_data = of_node_get(of_node);
viodev->irq = NO_IRQ; viodev->irq = irq_of_parse_and_map(of_node, 0);
irq_p = (unsigned int *)get_property(of_node, "interrupts", NULL);
if (irq_p) {
int virq = virt_irq_create_mapping(*irq_p);
if (virq == NO_IRQ) {
printk(KERN_ERR "Unable to allocate interrupt "
"number for %s\n", of_node->full_name);
} else
viodev->irq = irq_offset_up(virq);
}
snprintf(viodev->dev.bus_id, BUS_ID_SIZE, "%x", *unit_address); snprintf(viodev->dev.bus_id, BUS_ID_SIZE, "%x", *unit_address);
viodev->name = of_node->name; viodev->name = of_node->name;
......
This diff is collapsed.
...@@ -37,23 +37,22 @@ ...@@ -37,23 +37,22 @@
*/ */
enum { enum {
IIC_EXT_OFFSET = 0x00, /* Start of south bridge IRQs */ IIC_IRQ_INVALID = 0xff,
IIC_EXT_CASCADE = 0x20, /* There is no interrupt 32 on spider */ IIC_IRQ_MAX = 0x3f,
IIC_NUM_EXT = 0x40, /* Number of south bridge IRQs */ IIC_IRQ_EXT_IOIF0 = 0x20,
IIC_SPE_OFFSET = 0x40, /* Start of SPE interrupts */ IIC_IRQ_EXT_IOIF1 = 0x2b,
IIC_CLASS_STRIDE = 0x10, /* SPE IRQs per class */ IIC_IRQ_IPI0 = 0x40,
IIC_IPI_OFFSET = 0x70, /* Start of IPI IRQs */ IIC_NUM_IPIS = 0x10, /* IRQs reserved for IPI */
IIC_NUM_IPIS = 0x10, /* IRQs reserved for IPI */ IIC_SOURCE_COUNT = 0x50,
IIC_NODE_STRIDE = 0x80, /* Total IRQs per node */
}; };
extern void iic_init_IRQ(void); 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_cause_IPI(int cpu, int mesg);
extern void iic_request_IPIs(void); extern void iic_request_IPIs(void);
extern void iic_setup_cpu(void); extern void iic_setup_cpu(void);
extern u8 iic_get_target_id(int cpu); extern u8 iic_get_target_id(int cpu);
extern struct irq_host *iic_get_irq_host(int node);
extern void spider_init_IRQ(void); extern void spider_init_IRQ(void);
......
...@@ -80,6 +80,14 @@ static void cell_progress(char *s, unsigned short hex) ...@@ -80,6 +80,14 @@ static void cell_progress(char *s, unsigned short hex)
printk("*** %04x : %s\n", hex, s ? s : ""); printk("*** %04x : %s\n", hex, s ? s : "");
} }
static void __init cell_pcibios_fixup(void)
{
struct pci_dev *dev = NULL;
for_each_pci_dev(dev)
pci_read_irq_line(dev);
}
static void __init cell_init_irq(void) static void __init cell_init_irq(void)
{ {
iic_init_IRQ(); iic_init_IRQ();
...@@ -130,8 +138,6 @@ static void __init cell_init_early(void) ...@@ -130,8 +138,6 @@ static void __init cell_init_early(void)
cell_init_iommu(); cell_init_iommu();
ppc64_interrupt_controller = IC_CELL_PIC;
DBG(" <- cell_init_early()\n"); DBG(" <- cell_init_early()\n");
} }
...@@ -178,8 +184,7 @@ define_machine(cell) { ...@@ -178,8 +184,7 @@ define_machine(cell) {
.check_legacy_ioport = cell_check_legacy_ioport, .check_legacy_ioport = cell_check_legacy_ioport,
.progress = cell_progress, .progress = cell_progress,
.init_IRQ = cell_init_irq, .init_IRQ = cell_init_irq,
.get_irq = iic_get_irq, .pcibios_fixup = cell_pcibios_fixup,
#ifdef CONFIG_KEXEC #ifdef CONFIG_KEXEC
.machine_kexec = default_machine_kexec, .machine_kexec = default_machine_kexec,
.machine_kexec_prepare = default_machine_kexec_prepare, .machine_kexec_prepare = default_machine_kexec_prepare,
......
This diff is collapsed.
...@@ -264,51 +264,57 @@ spu_irq_class_2(int irq, void *data, struct pt_regs *regs) ...@@ -264,51 +264,57 @@ spu_irq_class_2(int irq, void *data, struct pt_regs *regs)
return stat ? IRQ_HANDLED : IRQ_NONE; return stat ? IRQ_HANDLED : IRQ_NONE;
} }
static int static int spu_request_irqs(struct spu *spu)
spu_request_irqs(struct spu *spu)
{ {
int ret; int ret = 0;
int irq_base;
irq_base = IIC_NODE_STRIDE * spu->node + IIC_SPE_OFFSET;
snprintf(spu->irq_c0, sizeof (spu->irq_c0), "spe%02d.0", spu->number);
ret = request_irq(irq_base + spu->isrc,
spu_irq_class_0, IRQF_DISABLED, spu->irq_c0, spu);
if (ret)
goto out;
snprintf(spu->irq_c1, sizeof (spu->irq_c1), "spe%02d.1", spu->number);
ret = request_irq(irq_base + IIC_CLASS_STRIDE + spu->isrc,
spu_irq_class_1, IRQF_DISABLED, spu->irq_c1, spu);
if (ret)
goto out1;
snprintf(spu->irq_c2, sizeof (spu->irq_c2), "spe%02d.2", spu->number); if (spu->irqs[0] != NO_IRQ) {
ret = request_irq(irq_base + 2*IIC_CLASS_STRIDE + spu->isrc, snprintf(spu->irq_c0, sizeof (spu->irq_c0), "spe%02d.0",
spu_irq_class_2, IRQF_DISABLED, spu->irq_c2, spu); spu->number);
if (ret) ret = request_irq(spu->irqs[0], spu_irq_class_0,
goto out2; IRQF_DISABLED,
goto out; spu->irq_c0, spu);
if (ret)
goto bail0;
}
if (spu->irqs[1] != NO_IRQ) {
snprintf(spu->irq_c1, sizeof (spu->irq_c1), "spe%02d.1",
spu->number);
ret = request_irq(spu->irqs[1], spu_irq_class_1,
IRQF_DISABLED,
spu->irq_c1, spu);
if (ret)
goto bail1;
}
if (spu->irqs[2] != NO_IRQ) {
snprintf(spu->irq_c2, sizeof (spu->irq_c2), "spe%02d.2",
spu->number);
ret = request_irq(spu->irqs[2], spu_irq_class_2,
IRQF_DISABLED,
spu->irq_c2, spu);
if (ret)
goto bail2;
}
return 0;
out2: bail2:
free_irq(irq_base + IIC_CLASS_STRIDE + spu->isrc, spu); if (spu->irqs[1] != NO_IRQ)
out1: free_irq(spu->irqs[1], spu);
free_irq(irq_base + spu->isrc, spu); bail1:
out: if (spu->irqs[0] != NO_IRQ)
free_irq(spu->irqs[0], spu);
bail0:
return ret; return ret;
} }
static void static void spu_free_irqs(struct spu *spu)
spu_free_irqs(struct spu *spu)
{ {
int irq_base; if (spu->irqs[0] != NO_IRQ)
free_irq(spu->irqs[0], spu);
irq_base = IIC_NODE_STRIDE * spu->node + IIC_SPE_OFFSET; if (spu->irqs[1] != NO_IRQ)
free_irq(spu->irqs[1], spu);
free_irq(irq_base + spu->isrc, spu); if (spu->irqs[2] != NO_IRQ)
free_irq(irq_base + IIC_CLASS_STRIDE + spu->isrc, spu); free_irq(spu->irqs[2], spu);
free_irq(irq_base + 2*IIC_CLASS_STRIDE + spu->isrc, spu);
} }
static LIST_HEAD(spu_list); static LIST_HEAD(spu_list);
...@@ -559,17 +565,38 @@ static void spu_unmap(struct spu *spu) ...@@ -559,17 +565,38 @@ static void spu_unmap(struct spu *spu)
iounmap((u8 __iomem *)spu->local_store); iounmap((u8 __iomem *)spu->local_store);
} }
/* This function shall be abstracted for HV platforms */
static int __init spu_map_interrupts(struct spu *spu, struct device_node *np)
{
struct irq_host *host;
unsigned int isrc;
u32 *tmp;
host = iic_get_irq_host(spu->node);
if (host == NULL)
return -ENODEV;
/* Get the interrupt source from the device-tree */
tmp = (u32 *)get_property(np, "isrc", NULL);
if (!tmp)
return -ENODEV;
spu->isrc = isrc = tmp[0];
/* Now map interrupts of all 3 classes */
spu->irqs[0] = irq_create_mapping(host, 0x00 | isrc, 0);
spu->irqs[1] = irq_create_mapping(host, 0x10 | isrc, 0);
spu->irqs[2] = irq_create_mapping(host, 0x20 | isrc, 0);
/* Right now, we only fail if class 2 failed */
return spu->irqs[2] == NO_IRQ ? -EINVAL : 0;
}
static int __init spu_map_device(struct spu *spu, struct device_node *node) static int __init spu_map_device(struct spu *spu, struct device_node *node)
{ {
char *prop; char *prop;
int ret; int ret;
ret = -ENODEV; ret = -ENODEV;
prop = get_property(node, "isrc", NULL);
if (!prop)
goto out;
spu->isrc = *(unsigned int *)prop;
spu->name = get_property(node, "name", NULL); spu->name = get_property(node, "name", NULL);
if (!spu->name) if (!spu->name)
goto out; goto out;
...@@ -636,7 +663,8 @@ static int spu_create_sysdev(struct spu *spu) ...@@ -636,7 +663,8 @@ static int spu_create_sysdev(struct spu *spu)
return ret; return ret;
} }
sysdev_create_file(&spu->sysdev, &attr_isrc); if (spu->isrc != 0)
sysdev_create_file(&spu->sysdev, &attr_isrc);
sysfs_add_device_to_node(&spu->sysdev, spu->nid); sysfs_add_device_to_node(&spu->sysdev, spu->nid);
return 0; return 0;
...@@ -668,6 +696,9 @@ static int __init create_spu(struct device_node *spe) ...@@ -668,6 +696,9 @@ static int __init create_spu(struct device_node *spe)
spu->nid = of_node_to_nid(spe); spu->nid = of_node_to_nid(spe);
if (spu->nid == -1) if (spu->nid == -1)
spu->nid = 0; spu->nid = 0;
ret = spu_map_interrupts(spu, spe);
if (ret)
goto out_unmap;
spin_lock_init(&spu->register_lock); spin_lock_init(&spu->register_lock);
spu_mfc_sdr_set(spu, mfspr(SPRN_SDR1)); spu_mfc_sdr_set(spu, mfspr(SPRN_SDR1));
spu_mfc_sr1_set(spu, 0x33); spu_mfc_sr1_set(spu, 0x33);
......
...@@ -18,7 +18,6 @@ ...@@ -18,7 +18,6 @@
#include <asm/machdep.h> #include <asm/machdep.h>
#include <asm/sections.h> #include <asm/sections.h>
#include <asm/pci-bridge.h> #include <asm/pci-bridge.h>
#include <asm/open_pic.h>
#include <asm/grackle.h> #include <asm/grackle.h>
#include <asm/rtas.h> #include <asm/rtas.h>
...@@ -161,15 +160,9 @@ void __init ...@@ -161,15 +160,9 @@ void __init
chrp_pcibios_fixup(void) chrp_pcibios_fixup(void)
{ {
struct pci_dev *dev = NULL; struct pci_dev *dev = NULL;
struct device_node *np;
/* PCI interrupts are controlled by the OpenPIC */ for_each_pci_dev(dev)
for_each_pci_dev(dev) { pci_read_irq_line(dev);
np = pci_device_to_OF_node(dev);
if ((np != 0) && (np->n_intrs > 0) && (np->intrs[0].line != 0))
dev->irq = np->intrs[0].line;
pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
}
} }
#define PRG_CL_RESET_VALID 0x00010000 #define PRG_CL_RESET_VALID 0x00010000
......
...@@ -59,7 +59,7 @@ void rtas_indicator_progress(char *, unsigned short); ...@@ -59,7 +59,7 @@ void rtas_indicator_progress(char *, unsigned short);
int _chrp_type; int _chrp_type;
EXPORT_SYMBOL(_chrp_type); EXPORT_SYMBOL(_chrp_type);
struct mpic *chrp_mpic; static struct mpic *chrp_mpic;
/* Used for doing CHRP event-scans */ /* Used for doing CHRP event-scans */
DEFINE_PER_CPU(struct timer_list, heartbeat_timer); DEFINE_PER_CPU(struct timer_list, heartbeat_timer);
...@@ -315,19 +315,13 @@ chrp_event_scan(unsigned long unused) ...@@ -315,19 +315,13 @@ chrp_event_scan(unsigned long unused)
jiffies + event_scan_interval); jiffies + event_scan_interval);
} }
void chrp_8259_cascade(unsigned int irq, struct irq_desc *desc, static void chrp_8259_cascade(unsigned int irq, struct irq_desc *desc,
struct pt_regs *regs) struct pt_regs *regs)
{ {
unsigned int max = 100; unsigned int cascade_irq = i8259_irq(regs);
if (cascade_irq != NO_IRQ)
while(max--) { generic_handle_irq(cascade_irq, regs);
int irq = i8259_irq(regs); desc->chip->eoi(irq);
if (max == 99)
desc->chip->eoi(irq);
if (irq < 0)
break;
generic_handle_irq(irq, regs);
};
} }
/* /*
...@@ -336,18 +330,17 @@ void chrp_8259_cascade(unsigned int irq, struct irq_desc *desc, ...@@ -336,18 +330,17 @@ void chrp_8259_cascade(unsigned int irq, struct irq_desc *desc,
static void __init chrp_find_openpic(void) static void __init chrp_find_openpic(void)
{ {
struct device_node *np, *root; struct device_node *np, *root;
int len, i, j, irq_count; int len, i, j;
int isu_size, idu_size; int isu_size, idu_size;
unsigned int *iranges, *opprop = NULL; unsigned int *iranges, *opprop = NULL;
int oplen = 0; int oplen = 0;
unsigned long opaddr; unsigned long opaddr;
int na = 1; int na = 1;
unsigned char init_senses[NR_IRQS - NUM_8259_INTERRUPTS];
np = find_type_devices("open-pic"); np = of_find_node_by_type(NULL, "open-pic");
if (np == NULL) if (np == NULL)
return; return;
root = find_path_device("/"); root = of_find_node_by_path("/");
if (root) { if (root) {
opprop = (unsigned int *) get_property opprop = (unsigned int *) get_property
(root, "platform-open-pic", &oplen); (root, "platform-open-pic", &oplen);
...@@ -358,19 +351,15 @@ static void __init chrp_find_openpic(void) ...@@ -358,19 +351,15 @@ static void __init chrp_find_openpic(void)
oplen /= na * sizeof(unsigned int); oplen /= na * sizeof(unsigned int);
} else { } else {
struct resource r; struct resource r;
if (of_address_to_resource(np, 0, &r)) if (of_address_to_resource(np, 0, &r)) {
return; goto bail;
}
opaddr = r.start; opaddr = r.start;
oplen = 0; oplen = 0;
} }
printk(KERN_INFO "OpenPIC at %lx\n", opaddr); printk(KERN_INFO "OpenPIC at %lx\n", opaddr);
irq_count = NR_IRQS - NUM_ISA_INTERRUPTS - 4; /* leave room for IPIs */
prom_get_irq_senses(init_senses, NUM_ISA_INTERRUPTS, NR_IRQS - 4);
/* i8259 cascade is always positive level */
init_senses[0] = IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE;
iranges = (unsigned int *) get_property(np, "interrupt-ranges", &len); iranges = (unsigned int *) get_property(np, "interrupt-ranges", &len);
if (iranges == NULL) if (iranges == NULL)
len = 0; /* non-distributed mpic */ len = 0; /* non-distributed mpic */
...@@ -397,15 +386,12 @@ static void __init chrp_find_openpic(void) ...@@ -397,15 +386,12 @@ static void __init chrp_find_openpic(void)
if (len > 1) if (len > 1)
isu_size = iranges[3]; isu_size = iranges[3];
chrp_mpic = mpic_alloc(opaddr, MPIC_PRIMARY, chrp_mpic = mpic_alloc(np, opaddr, MPIC_PRIMARY,
isu_size, NUM_ISA_INTERRUPTS, irq_count, isu_size, 0, " MPIC ");
NR_IRQS - 4, init_senses, irq_count,
" MPIC ");
if (chrp_mpic == NULL) { if (chrp_mpic == NULL) {
printk(KERN_ERR "Failed to allocate MPIC structure\n"); printk(KERN_ERR "Failed to allocate MPIC structure\n");
return; goto bail;
} }
j = na - 1; j = na - 1;
for (i = 1; i < len; ++i) { for (i = 1; i < len; ++i) {
iranges += 2; iranges += 2;
...@@ -417,7 +403,10 @@ static void __init chrp_find_openpic(void) ...@@ -417,7 +403,10 @@ static void __init chrp_find_openpic(void)
} }
mpic_init(chrp_mpic); mpic_init(chrp_mpic);
set_irq_chained_handler(NUM_ISA_INTERRUPTS, chrp_8259_cascade); ppc_md.get_irq = mpic_get_irq;
bail:
of_node_put(root);
of_node_put(np);
} }
#if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(XMON) #if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(XMON)
...@@ -428,14 +417,34 @@ static struct irqaction xmon_irqaction = { ...@@ -428,14 +417,34 @@ static struct irqaction xmon_irqaction = {
}; };
#endif #endif
void __init chrp_init_IRQ(void) static void __init chrp_find_8259(void)
{ {
struct device_node *np; struct device_node *np, *pic = NULL;
unsigned long chrp_int_ack = 0; unsigned long chrp_int_ack = 0;
#if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(XMON) unsigned int cascade_irq;
struct device_node *kbd;
#endif
/* Look for cascade */
for_each_node_by_type(np, "interrupt-controller")
if (device_is_compatible(np, "chrp,iic")) {
pic = np;
break;
}
/* Ok, 8259 wasn't found. We need to handle the case where
* we have a pegasos that claims to be chrp but doesn't have
* a proper interrupt tree
*/
if (pic == NULL && chrp_mpic != NULL) {
printk(KERN_ERR "i8259: Not found in device-tree"
" assuming no legacy interrupts\n");
return;
}
/* Look for intack. In a perfect world, we would look for it on
* the ISA bus that holds the 8259 but heh... Works that way. If
* we ever see a problem, we can try to re-use the pSeries code here.
* Also, Pegasos-type platforms don't have a proper node to start
* from anyway
*/
for (np = find_devices("pci"); np != NULL; np = np->next) { for (np = find_devices("pci"); np != NULL; np = np->next) {
unsigned int *addrp = (unsigned int *) unsigned int *addrp = (unsigned int *)
get_property(np, "8259-interrupt-acknowledge", NULL); get_property(np, "8259-interrupt-acknowledge", NULL);
...@@ -446,11 +455,29 @@ void __init chrp_init_IRQ(void) ...@@ -446,11 +455,29 @@ void __init chrp_init_IRQ(void)
break; break;
} }
if (np == NULL) if (np == NULL)
printk(KERN_ERR "Cannot find PCI interrupt acknowledge address\n"); printk(KERN_WARNING "Cannot find PCI interrupt acknowledge"
" address, polling\n");
i8259_init(pic, chrp_int_ack);
if (ppc_md.get_irq == NULL)
ppc_md.get_irq = i8259_irq;
if (chrp_mpic != NULL) {
cascade_irq = irq_of_parse_and_map(pic, 0);
if (cascade_irq == NO_IRQ)
printk(KERN_ERR "i8259: failed to map cascade irq\n");
else
set_irq_chained_handler(cascade_irq,
chrp_8259_cascade);
}
}
void __init chrp_init_IRQ(void)
{
#if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(XMON)
struct device_node *kbd;
#endif
chrp_find_openpic(); chrp_find_openpic();
chrp_find_8259();
i8259_init(chrp_int_ack, 0);
if (_chrp_type == _CHRP_Pegasos) if (_chrp_type == _CHRP_Pegasos)
ppc_md.get_irq = i8259_irq; ppc_md.get_irq = i8259_irq;
...@@ -535,10 +562,6 @@ static int __init chrp_probe(void) ...@@ -535,10 +562,6 @@ static int __init chrp_probe(void)
DMA_MODE_READ = 0x44; DMA_MODE_READ = 0x44;
DMA_MODE_WRITE = 0x48; DMA_MODE_WRITE = 0x48;
isa_io_base = CHRP_ISA_IO_BASE; /* default value */ isa_io_base = CHRP_ISA_IO_BASE; /* default value */
ppc_do_canonicalize_irqs = 1;
/* Assume we have an 8259... */
__irq_offset_value = NUM_ISA_INTERRUPTS;
return 1; return 1;
} }
...@@ -550,7 +573,6 @@ define_machine(chrp) { ...@@ -550,7 +573,6 @@ define_machine(chrp) {
.init = chrp_init2, .init = chrp_init2,
.show_cpuinfo = chrp_show_cpuinfo, .show_cpuinfo = chrp_show_cpuinfo,
.init_IRQ = chrp_init_IRQ, .init_IRQ = chrp_init_IRQ,
.get_irq = mpic_get_irq,
.pcibios_fixup = chrp_pcibios_fixup, .pcibios_fixup = chrp_pcibios_fixup,
.restart = rtas_restart, .restart = rtas_restart,
.power_off = rtas_power_off, .power_off = rtas_power_off,
......
...@@ -29,7 +29,6 @@ ...@@ -29,7 +29,6 @@
#include <asm/smp.h> #include <asm/smp.h>
#include <asm/residual.h> #include <asm/residual.h>
#include <asm/time.h> #include <asm/time.h>
#include <asm/open_pic.h>
#include <asm/machdep.h> #include <asm/machdep.h>
#include <asm/smp.h> #include <asm/smp.h>
#include <asm/mpic.h> #include <asm/mpic.h>
......
...@@ -162,27 +162,6 @@ static void pci_event_handler(struct HvLpEvent *event, struct pt_regs *regs) ...@@ -162,27 +162,6 @@ static void pci_event_handler(struct HvLpEvent *event, struct pt_regs *regs)
printk(KERN_ERR "pci_event_handler: NULL event received\n"); printk(KERN_ERR "pci_event_handler: NULL event received\n");
} }
/*
* This is called by init_IRQ. set in ppc_md.init_IRQ by iSeries_setup.c
* It must be called before the bus walk.
*/
void __init iSeries_init_IRQ(void)
{
/* Register PCI event handler and open an event path */
int ret;
ret = HvLpEvent_registerHandler(HvLpEvent_Type_PciIo,
&pci_event_handler);
if (ret == 0) {
ret = HvLpEvent_openPath(HvLpEvent_Type_PciIo, 0);
if (ret != 0)
printk(KERN_ERR "iseries_init_IRQ: open event path "
"failed with rc 0x%x\n", ret);
} else
printk(KERN_ERR "iseries_init_IRQ: register handler "
"failed with rc 0x%x\n", ret);
}
#define REAL_IRQ_TO_SUBBUS(irq) (((irq) >> 14) & 0xff) #define REAL_IRQ_TO_SUBBUS(irq) (((irq) >> 14) & 0xff)
#define REAL_IRQ_TO_BUS(irq) ((((irq) >> 6) & 0xff) + 1) #define REAL_IRQ_TO_BUS(irq) ((((irq) >> 6) & 0xff) + 1)
#define REAL_IRQ_TO_IDSEL(irq) ((((irq) >> 3) & 7) + 1) #define REAL_IRQ_TO_IDSEL(irq) ((((irq) >> 3) & 7) + 1)
...@@ -196,7 +175,7 @@ static void iseries_enable_IRQ(unsigned int irq) ...@@ -196,7 +175,7 @@ static void iseries_enable_IRQ(unsigned int irq)
{ {
u32 bus, dev_id, function, mask; u32 bus, dev_id, function, mask;
const u32 sub_bus = 0; const u32 sub_bus = 0;
unsigned int rirq = virt_irq_to_real_map[irq]; unsigned int rirq = (unsigned int)irq_map[irq].hwirq;
/* The IRQ has already been locked by the caller */ /* The IRQ has already been locked by the caller */
bus = REAL_IRQ_TO_BUS(rirq); bus = REAL_IRQ_TO_BUS(rirq);
...@@ -213,7 +192,7 @@ static unsigned int iseries_startup_IRQ(unsigned int irq) ...@@ -213,7 +192,7 @@ static unsigned int iseries_startup_IRQ(unsigned int irq)
{ {
u32 bus, dev_id, function, mask; u32 bus, dev_id, function, mask;
const u32 sub_bus = 0; const u32 sub_bus = 0;
unsigned int rirq = virt_irq_to_real_map[irq]; unsigned int rirq = (unsigned int)irq_map[irq].hwirq;
bus = REAL_IRQ_TO_BUS(rirq); bus = REAL_IRQ_TO_BUS(rirq);
function = REAL_IRQ_TO_FUNC(rirq); function = REAL_IRQ_TO_FUNC(rirq);
...@@ -254,7 +233,7 @@ static void iseries_shutdown_IRQ(unsigned int irq) ...@@ -254,7 +233,7 @@ static void iseries_shutdown_IRQ(unsigned int irq)
{ {
u32 bus, dev_id, function, mask; u32 bus, dev_id, function, mask;
const u32 sub_bus = 0; const u32 sub_bus = 0;
unsigned int rirq = virt_irq_to_real_map[irq]; unsigned int rirq = (unsigned int)irq_map[irq].hwirq;
/* irq should be locked by the caller */ /* irq should be locked by the caller */
bus = REAL_IRQ_TO_BUS(rirq); bus = REAL_IRQ_TO_BUS(rirq);
...@@ -277,7 +256,7 @@ static void iseries_disable_IRQ(unsigned int irq) ...@@ -277,7 +256,7 @@ static void iseries_disable_IRQ(unsigned int irq)
{ {
u32 bus, dev_id, function, mask; u32 bus, dev_id, function, mask;
const u32 sub_bus = 0; const u32 sub_bus = 0;
unsigned int rirq = virt_irq_to_real_map[irq]; unsigned int rirq = (unsigned int)irq_map[irq].hwirq;
/* The IRQ has already been locked by the caller */ /* The IRQ has already been locked by the caller */
bus = REAL_IRQ_TO_BUS(rirq); bus = REAL_IRQ_TO_BUS(rirq);
...@@ -291,7 +270,7 @@ static void iseries_disable_IRQ(unsigned int irq) ...@@ -291,7 +270,7 @@ static void iseries_disable_IRQ(unsigned int irq)
static void iseries_end_IRQ(unsigned int irq) static void iseries_end_IRQ(unsigned int irq)
{ {
unsigned int rirq = virt_irq_to_real_map[irq]; unsigned int rirq = (unsigned int)irq_map[irq].hwirq;
HvCallPci_eoi(REAL_IRQ_TO_BUS(rirq), REAL_IRQ_TO_SUBBUS(rirq), HvCallPci_eoi(REAL_IRQ_TO_BUS(rirq), REAL_IRQ_TO_SUBBUS(rirq),
(REAL_IRQ_TO_IDSEL(rirq) << 4) + REAL_IRQ_TO_FUNC(rirq)); (REAL_IRQ_TO_IDSEL(rirq) << 4) + REAL_IRQ_TO_FUNC(rirq));
...@@ -314,16 +293,14 @@ static struct irq_chip iseries_pic = { ...@@ -314,16 +293,14 @@ static struct irq_chip iseries_pic = {
int __init iSeries_allocate_IRQ(HvBusNumber bus, int __init iSeries_allocate_IRQ(HvBusNumber bus,
HvSubBusNumber sub_bus, u32 bsubbus) HvSubBusNumber sub_bus, u32 bsubbus)
{ {
int virtirq;
unsigned int realirq; unsigned int realirq;
u8 idsel = ISERIES_GET_DEVICE_FROM_SUBBUS(bsubbus); u8 idsel = ISERIES_GET_DEVICE_FROM_SUBBUS(bsubbus);
u8 function = ISERIES_GET_FUNCTION_FROM_SUBBUS(bsubbus); u8 function = ISERIES_GET_FUNCTION_FROM_SUBBUS(bsubbus);
realirq = (((((sub_bus << 8) + (bus - 1)) << 3) + (idsel - 1)) << 3) realirq = (((((sub_bus << 8) + (bus - 1)) << 3) + (idsel - 1)) << 3)
+ function; + function;
virtirq = virt_irq_create_mapping(realirq);
set_irq_chip_and_handler(virtirq, &iseries_pic, handle_fasteoi_irq); return irq_create_mapping(NULL, realirq, IRQ_TYPE_NONE);
return virtirq;
} }
#endif /* CONFIG_PCI */ #endif /* CONFIG_PCI */
...@@ -331,10 +308,9 @@ int __init iSeries_allocate_IRQ(HvBusNumber bus, ...@@ -331,10 +308,9 @@ int __init iSeries_allocate_IRQ(HvBusNumber bus,
/* /*
* Get the next pending IRQ. * Get the next pending IRQ.
*/ */
int iSeries_get_irq(struct pt_regs *regs) unsigned int iSeries_get_irq(struct pt_regs *regs)
{ {
/* -2 means ignore this interrupt */ int irq = NO_IRQ_IGNORE;
int irq = -2;
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
if (get_lppaca()->int_dword.fields.ipi_cnt) { if (get_lppaca()->int_dword.fields.ipi_cnt) {
...@@ -357,9 +333,57 @@ int iSeries_get_irq(struct pt_regs *regs) ...@@ -357,9 +333,57 @@ int iSeries_get_irq(struct pt_regs *regs)
} }
spin_unlock(&pending_irqs_lock); spin_unlock(&pending_irqs_lock);
if (irq >= NR_IRQS) if (irq >= NR_IRQS)
irq = -2; irq = NO_IRQ_IGNORE;
} }
#endif #endif
return irq; return irq;
} }
static int iseries_irq_host_map(struct irq_host *h, unsigned int virq,
irq_hw_number_t hw, unsigned int flags)
{
set_irq_chip_and_handler(virq, &iseries_pic, handle_fasteoi_irq);
return 0;
}
static struct irq_host_ops iseries_irq_host_ops = {
.map = iseries_irq_host_map,
};
/*
* This is called by init_IRQ. set in ppc_md.init_IRQ by iSeries_setup.c
* It must be called before the bus walk.
*/
void __init iSeries_init_IRQ(void)
{
/* Register PCI event handler and open an event path */
struct irq_host *host;
int ret;
/*
* The Hypervisor only allows us up to 256 interrupt
* sources (the irq number is passed in a u8).
*/
irq_set_virq_count(256);
/* Create irq host. No need for a revmap since HV will give us
* back our virtual irq number
*/
host = irq_alloc_host(IRQ_HOST_MAP_NOMAP, 0, &iseries_irq_host_ops, 0);
BUG_ON(host == NULL);
irq_set_default_host(host);
ret = HvLpEvent_registerHandler(HvLpEvent_Type_PciIo,
&pci_event_handler);
if (ret == 0) {
ret = HvLpEvent_openPath(HvLpEvent_Type_PciIo, 0);
if (ret != 0)
printk(KERN_ERR "iseries_init_IRQ: open event path "
"failed with rc 0x%x\n", ret);
} else
printk(KERN_ERR "iseries_init_IRQ: register handler "
"failed with rc 0x%x\n", ret);
}
...@@ -4,6 +4,6 @@ ...@@ -4,6 +4,6 @@
extern void iSeries_init_IRQ(void); extern void iSeries_init_IRQ(void);
extern int iSeries_allocate_IRQ(HvBusNumber, HvSubBusNumber, u32); extern int iSeries_allocate_IRQ(HvBusNumber, HvSubBusNumber, u32);
extern void iSeries_activate_IRQs(void); extern void iSeries_activate_IRQs(void);
extern int iSeries_get_irq(struct pt_regs *); extern unsigned int iSeries_get_irq(struct pt_regs *);
#endif /* _ISERIES_IRQ_H */ #endif /* _ISERIES_IRQ_H */
...@@ -294,8 +294,6 @@ static void __init iSeries_init_early(void) ...@@ -294,8 +294,6 @@ static void __init iSeries_init_early(void)
{ {
DBG(" -> iSeries_init_early()\n"); DBG(" -> iSeries_init_early()\n");
ppc64_interrupt_controller = IC_ISERIES;
#if defined(CONFIG_BLK_DEV_INITRD) #if defined(CONFIG_BLK_DEV_INITRD)
/* /*
* If the init RAM disk has been configured and there is * If the init RAM disk has been configured and there is
...@@ -659,12 +657,6 @@ static int __init iseries_probe(void) ...@@ -659,12 +657,6 @@ static int __init iseries_probe(void)
powerpc_firmware_features |= FW_FEATURE_ISERIES; powerpc_firmware_features |= FW_FEATURE_ISERIES;
powerpc_firmware_features |= FW_FEATURE_LPAR; powerpc_firmware_features |= FW_FEATURE_LPAR;
/*
* The Hypervisor only allows us up to 256 interrupt
* sources (the irq number is passed in a u8).
*/
virt_irq_max = 255;
hpte_init_iSeries(); hpte_init_iSeries();
return 1; return 1;
......
...@@ -443,18 +443,23 @@ void __init maple_pci_init(void) ...@@ -443,18 +443,23 @@ void __init maple_pci_init(void)
int maple_pci_get_legacy_ide_irq(struct pci_dev *pdev, int channel) int maple_pci_get_legacy_ide_irq(struct pci_dev *pdev, int channel)
{ {
struct device_node *np; struct device_node *np;
int irq = channel ? 15 : 14; unsigned int defirq = channel ? 15 : 14;
unsigned int irq;
if (pdev->vendor != PCI_VENDOR_ID_AMD || if (pdev->vendor != PCI_VENDOR_ID_AMD ||
pdev->device != PCI_DEVICE_ID_AMD_8111_IDE) pdev->device != PCI_DEVICE_ID_AMD_8111_IDE)
return irq; return defirq;
np = pci_device_to_OF_node(pdev); np = pci_device_to_OF_node(pdev);
if (np == NULL) if (np == NULL)
return irq; return defirq;
if (np->n_intrs < 2) irq = irq_of_parse_and_map(np, channel & 0x1);
return irq; if (irq == NO_IRQ) {
return np->intrs[channel & 0x1].line; printk("Failed to map onboard IDE interrupt for channel %d\n",
channel);
return defirq;
}
return irq;
} }
/* XXX: To remove once all firmwares are ok */ /* XXX: To remove once all firmwares are ok */
......
...@@ -198,50 +198,81 @@ static void __init maple_init_early(void) ...@@ -198,50 +198,81 @@ static void __init maple_init_early(void)
{ {
DBG(" -> maple_init_early\n"); DBG(" -> maple_init_early\n");
/* Setup interrupt mapping options */
ppc64_interrupt_controller = IC_OPEN_PIC;
iommu_init_early_dart(); iommu_init_early_dart();
DBG(" <- maple_init_early\n"); DBG(" <- maple_init_early\n");
} }
/*
static __init void maple_init_IRQ(void) * This is almost identical to pSeries and CHRP. We need to make that
* code generic at one point, with appropriate bits in the device-tree to
* identify the presence of an HT APIC
*/
static void __init maple_init_IRQ(void)
{ {
struct device_node *root; struct device_node *root, *np, *mpic_node = NULL;
unsigned int *opprop; unsigned int *opprop;
unsigned long opic_addr; unsigned long openpic_addr = 0;
int naddr, n, i, opplen, has_isus = 0;
struct mpic *mpic; struct mpic *mpic;
unsigned char senses[128]; unsigned int flags = MPIC_PRIMARY;
int n;
DBG(" -> maple_init_IRQ\n"); /* Locate MPIC in the device-tree. Note that there is a bug
* in Maple device-tree where the type of the controller is
* open-pic and not interrupt-controller
*/
for_each_node_by_type(np, "open-pic") {
mpic_node = np;
break;
}
if (mpic_node == NULL) {
printk(KERN_ERR
"Failed to locate the MPIC interrupt controller\n");
return;
}
/* XXX: Non standard, replace that with a proper openpic/mpic node /* Find address list in /platform-open-pic */
* in the device-tree. Find the Open PIC if present */
root = of_find_node_by_path("/"); root = of_find_node_by_path("/");
opprop = (unsigned int *) get_property(root, naddr = prom_n_addr_cells(root);
"platform-open-pic", NULL); opprop = (unsigned int *) get_property(root, "platform-open-pic",
if (opprop == 0) &opplen);
panic("OpenPIC not found !\n"); if (opprop != 0) {
openpic_addr = of_read_number(opprop, naddr);
n = prom_n_addr_cells(root); has_isus = (opplen > naddr);
for (opic_addr = 0; n > 0; --n) printk(KERN_DEBUG "OpenPIC addr: %lx, has ISUs: %d\n",
opic_addr = (opic_addr << 32) + *opprop++; openpic_addr, has_isus);
}
of_node_put(root); of_node_put(root);
/* Obtain sense values from device-tree */ BUG_ON(openpic_addr == 0);
prom_get_irq_senses(senses, 0, 128);
mpic = mpic_alloc(opic_addr, /* Check for a big endian MPIC */
MPIC_PRIMARY | MPIC_BIG_ENDIAN | if (get_property(np, "big-endian", NULL) != NULL)
MPIC_BROKEN_U3 | MPIC_WANTS_RESET, flags |= MPIC_BIG_ENDIAN;
0, 0, 128, 128, senses, 128, "U3-MPIC");
/* XXX Maple specific bits */
flags |= MPIC_BROKEN_U3 | MPIC_WANTS_RESET;
/* Setup the openpic driver. More device-tree junks, we hard code no
* ISUs for now. I'll have to revisit some stuffs with the folks doing
* the firmware for those
*/
mpic = mpic_alloc(mpic_node, openpic_addr, flags,
/*has_isus ? 16 :*/ 0, 0, " MPIC ");
BUG_ON(mpic == NULL); BUG_ON(mpic == NULL);
mpic_init(mpic);
DBG(" <- maple_init_IRQ\n"); /* Add ISUs */
opplen /= sizeof(u32);
for (n = 0, i = naddr; i < opplen; i += naddr, n++) {
unsigned long isuaddr = of_read_number(opprop + i, naddr);
mpic_assign_isu(mpic, n, isuaddr);
}
/* All ISUs are setup, complete initialization */
mpic_init(mpic);
ppc_md.get_irq = mpic_get_irq;
of_node_put(mpic_node);
of_node_put(root);
} }
static void __init maple_progress(char *s, unsigned short hex) static void __init maple_progress(char *s, unsigned short hex)
...@@ -279,7 +310,6 @@ define_machine(maple_md) { ...@@ -279,7 +310,6 @@ define_machine(maple_md) {
.setup_arch = maple_setup_arch, .setup_arch = maple_setup_arch,
.init_early = maple_init_early, .init_early = maple_init_early,
.init_IRQ = maple_init_IRQ, .init_IRQ = maple_init_IRQ,
.get_irq = mpic_get_irq,
.pcibios_fixup = maple_pcibios_fixup, .pcibios_fixup = maple_pcibios_fixup,
.pci_get_legacy_ide_irq = maple_pci_get_legacy_ide_irq, .pci_get_legacy_ide_irq = maple_pci_get_legacy_ide_irq,
.restart = maple_restart, .restart = maple_restart,
......
...@@ -162,6 +162,8 @@ static void __init bootx_add_chosen_props(unsigned long base, ...@@ -162,6 +162,8 @@ static void __init bootx_add_chosen_props(unsigned long base,
{ {
u32 val; u32 val;
bootx_dt_add_prop("linux,bootx", NULL, 0, mem_end);
if (bootx_info->kernelParamsOffset) { if (bootx_info->kernelParamsOffset) {
char *args = (char *)((unsigned long)bootx_info) + char *args = (char *)((unsigned long)bootx_info) +
bootx_info->kernelParamsOffset; bootx_info->kernelParamsOffset;
...@@ -228,7 +230,7 @@ static void __init bootx_scan_dt_build_strings(unsigned long base, ...@@ -228,7 +230,7 @@ static void __init bootx_scan_dt_build_strings(unsigned long base,
if (!strcmp(namep, "/chosen")) { if (!strcmp(namep, "/chosen")) {
DBG(" detected /chosen ! adding properties names !\n"); DBG(" detected /chosen ! adding properties names !\n");
bootx_dt_add_string("linux,platform", mem_end); bootx_dt_add_string("linux,bootx", mem_end);
bootx_dt_add_string("linux,stdout-path", mem_end); bootx_dt_add_string("linux,stdout-path", mem_end);
bootx_dt_add_string("linux,initrd-start", mem_end); bootx_dt_add_string("linux,initrd-start", mem_end);
bootx_dt_add_string("linux,initrd-end", mem_end); bootx_dt_add_string("linux,initrd-end", mem_end);
......
...@@ -522,10 +522,11 @@ static struct pmac_i2c_host_kw *__init kw_i2c_host_init(struct device_node *np) ...@@ -522,10 +522,11 @@ static struct pmac_i2c_host_kw *__init kw_i2c_host_init(struct device_node *np)
host->speed = KW_I2C_MODE_25KHZ; host->speed = KW_I2C_MODE_25KHZ;
break; break;
} }
if (np->n_intrs > 0) host->irq = irq_of_parse_and_map(np, 0);
host->irq = np->intrs[0].line; if (host->irq == NO_IRQ)
else printk(KERN_WARNING
host->irq = NO_IRQ; "low_i2c: Failed to map interrupt for %s\n",
np->full_name);
host->base = ioremap((*addrp), 0x1000); host->base = ioremap((*addrp), 0x1000);
if (host->base == NULL) { if (host->base == NULL) {
......
...@@ -29,6 +29,8 @@ ...@@ -29,6 +29,8 @@
#include <asm/machdep.h> #include <asm/machdep.h>
#include <asm/nvram.h> #include <asm/nvram.h>
#include "pmac.h"
#define DEBUG #define DEBUG
#ifdef DEBUG #ifdef DEBUG
...@@ -80,9 +82,6 @@ static int nvram_partitions[3]; ...@@ -80,9 +82,6 @@ static int nvram_partitions[3];
// XXX Turn that into a sem // XXX Turn that into a sem
static DEFINE_SPINLOCK(nv_lock); static DEFINE_SPINLOCK(nv_lock);
extern int pmac_newworld;
extern int system_running;
static int (*core99_write_bank)(int bank, u8* datas); static int (*core99_write_bank)(int bank, u8* datas);
static int (*core99_erase_bank)(int bank); static int (*core99_erase_bank)(int bank);
......
...@@ -46,6 +46,9 @@ static int has_uninorth; ...@@ -46,6 +46,9 @@ static int has_uninorth;
static struct pci_controller *u3_agp; static struct pci_controller *u3_agp;
static struct pci_controller *u4_pcie; static struct pci_controller *u4_pcie;
static struct pci_controller *u3_ht; static struct pci_controller *u3_ht;
#define has_second_ohare 0
#else
static int has_second_ohare;
#endif /* CONFIG_PPC64 */ #endif /* CONFIG_PPC64 */
extern u8 pci_cache_line_size; extern u8 pci_cache_line_size;
...@@ -647,6 +650,33 @@ static void __init init_p2pbridge(void) ...@@ -647,6 +650,33 @@ static void __init init_p2pbridge(void)
early_write_config_word(hose, bus, devfn, PCI_BRIDGE_CONTROL, val); early_write_config_word(hose, bus, devfn, PCI_BRIDGE_CONTROL, val);
} }
static void __init init_second_ohare(void)
{
struct device_node *np = of_find_node_by_name(NULL, "pci106b,7");
unsigned char bus, devfn;
unsigned short cmd;
if (np == NULL)
return;
/* This must run before we initialize the PICs since the second
* ohare hosts a PIC that will be accessed there.
*/
if (pci_device_from_OF_node(np, &bus, &devfn) == 0) {
struct pci_controller* hose =
pci_find_hose_for_OF_device(np);
if (!hose) {
printk(KERN_ERR "Can't find PCI hose for OHare2 !\n");
return;
}
early_read_config_word(hose, bus, devfn, PCI_COMMAND, &cmd);
cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
cmd &= ~PCI_COMMAND_IO;
early_write_config_word(hose, bus, devfn, PCI_COMMAND, cmd);
}
has_second_ohare = 1;
}
/* /*
* Some Apple desktop machines have a NEC PD720100A USB2 controller * Some Apple desktop machines have a NEC PD720100A USB2 controller
* on the motherboard. Open Firmware, on these, will disable the * on the motherboard. Open Firmware, on these, will disable the
...@@ -688,9 +718,6 @@ static void __init fixup_nec_usb2(void) ...@@ -688,9 +718,6 @@ static void __init fixup_nec_usb2(void)
" EHCI, fixing up...\n"); " EHCI, fixing up...\n");
data &= ~1UL; data &= ~1UL;
early_write_config_dword(hose, bus, devfn, 0xe4, data); early_write_config_dword(hose, bus, devfn, 0xe4, data);
early_write_config_byte(hose, bus,
devfn | 2, PCI_INTERRUPT_LINE,
nec->intrs[0].line);
} }
} }
} }
...@@ -958,32 +985,28 @@ static int __init add_bridge(struct device_node *dev) ...@@ -958,32 +985,28 @@ static int __init add_bridge(struct device_node *dev)
return 0; return 0;
} }
static void __init pcibios_fixup_OF_interrupts(void) void __init pmac_pcibios_fixup(void)
{ {
struct pci_dev* dev = NULL; struct pci_dev* dev = NULL;
/*
* Open Firmware often doesn't initialize the
* PCI_INTERRUPT_LINE config register properly, so we
* should find the device node and apply the interrupt
* obtained from the OF device-tree
*/
for_each_pci_dev(dev) { for_each_pci_dev(dev) {
struct device_node *node; /* Read interrupt from the device-tree */
node = pci_device_to_OF_node(dev); pci_read_irq_line(dev);
/* this is the node, see if it has interrupts */
if (node && node->n_intrs > 0) /* Fixup interrupt for the modem/ethernet combo controller.
dev->irq = node->intrs[0].line; * on machines with a second ohare chip.
pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); * The number in the device tree (27) is bogus (correct for
* the ethernet-only board but not the combo ethernet/modem
* board). The real interrupt is 28 on the second controller
* -> 28+32 = 60.
*/
if (has_second_ohare &&
dev->vendor == PCI_VENDOR_ID_DEC &&
dev->device == PCI_DEVICE_ID_DEC_TULIP_PLUS)
dev->irq = irq_create_mapping(NULL, 60, 0);
} }
} }
void __init pmac_pcibios_fixup(void)
{
/* Fixup interrupts according to OF tree */
pcibios_fixup_OF_interrupts();
}
#ifdef CONFIG_PPC64 #ifdef CONFIG_PPC64
static void __init pmac_fixup_phb_resources(void) static void __init pmac_fixup_phb_resources(void)
{ {
...@@ -1071,6 +1094,7 @@ void __init pmac_pci_init(void) ...@@ -1071,6 +1094,7 @@ void __init pmac_pci_init(void)
#else /* CONFIG_PPC64 */ #else /* CONFIG_PPC64 */
init_p2pbridge(); init_p2pbridge();
init_second_ohare();
fixup_nec_usb2(); fixup_nec_usb2();
/* We are still having some issues with the Xserve G4, enabling /* We are still having some issues with the Xserve G4, enabling
......
...@@ -24,19 +24,18 @@ static irqreturn_t macio_gpio_irq(int irq, void *data, struct pt_regs *regs) ...@@ -24,19 +24,18 @@ static irqreturn_t macio_gpio_irq(int irq, void *data, struct pt_regs *regs)
static int macio_do_gpio_irq_enable(struct pmf_function *func) static int macio_do_gpio_irq_enable(struct pmf_function *func)
{ {
if (func->node->n_intrs < 1) unsigned int irq = irq_of_parse_and_map(func->node, 0);
if (irq == NO_IRQ)
return -EINVAL; return -EINVAL;
return request_irq(irq, macio_gpio_irq, 0, func->node->name, func);
return request_irq(func->node->intrs[0].line, macio_gpio_irq, 0,
func->node->name, func);
} }
static int macio_do_gpio_irq_disable(struct pmf_function *func) static int macio_do_gpio_irq_disable(struct pmf_function *func)
{ {
if (func->node->n_intrs < 1) unsigned int irq = irq_of_parse_and_map(func->node, 0);
if (irq == NO_IRQ)
return -EINVAL; return -EINVAL;
free_irq(irq, func);
free_irq(func->node->intrs[0].line, func);
return 0; return 0;
} }
......
This diff is collapsed.
...@@ -12,6 +12,8 @@ ...@@ -12,6 +12,8 @@
struct rtc_time; struct rtc_time;
extern int pmac_newworld;
extern long pmac_time_init(void); extern long pmac_time_init(void);
extern unsigned long pmac_get_boot_time(void); extern unsigned long pmac_get_boot_time(void);
extern void pmac_get_rtc_time(struct rtc_time *); extern void pmac_get_rtc_time(struct rtc_time *);
......
...@@ -613,9 +613,6 @@ static void __init pmac_init_early(void) ...@@ -613,9 +613,6 @@ static void __init pmac_init_early(void)
udbg_adb_init(!!strstr(cmd_line, "btextdbg")); udbg_adb_init(!!strstr(cmd_line, "btextdbg"));
#ifdef CONFIG_PPC64 #ifdef CONFIG_PPC64
/* Setup interrupt mapping options */
ppc64_interrupt_controller = IC_OPEN_PIC;
iommu_init_early_dart(); iommu_init_early_dart();
#endif #endif
} }
......
...@@ -72,32 +72,62 @@ static irqreturn_t ras_error_interrupt(int irq, void *dev_id, ...@@ -72,32 +72,62 @@ static irqreturn_t ras_error_interrupt(int irq, void *dev_id,
/* #define DEBUG */ /* #define DEBUG */
static void request_ras_irqs(struct device_node *np, char *propname,
static void request_ras_irqs(struct device_node *np,
irqreturn_t (*handler)(int, void *, struct pt_regs *), irqreturn_t (*handler)(int, void *, struct pt_regs *),
const char *name) const char *name)
{ {
unsigned int *ireg, len, i; int i, index, count = 0;
int virq, n_intr; struct of_irq oirq;
u32 *opicprop;
ireg = (unsigned int *)get_property(np, propname, &len); unsigned int opicplen;
if (ireg == NULL) unsigned int virqs[16];
return;
n_intr = prom_n_intr_cells(np); /* Check for obsolete "open-pic-interrupt" property. If present, then
len /= n_intr * sizeof(*ireg); * map those interrupts using the default interrupt host and default
* trigger
for (i = 0; i < len; i++) { */
virq = virt_irq_create_mapping(*ireg); opicprop = (u32 *)get_property(np, "open-pic-interrupt", &opicplen);
if (virq == NO_IRQ) { if (opicprop) {
printk(KERN_ERR "Unable to allocate interrupt " opicplen /= sizeof(u32);
"number for %s\n", np->full_name); for (i = 0; i < opicplen; i++) {
return; if (count > 15)
break;
virqs[count] = irq_create_mapping(NULL, *(opicprop++),
IRQ_TYPE_NONE);
if (virqs[count] == NO_IRQ)
printk(KERN_ERR "Unable to allocate interrupt "
"number for %s\n", np->full_name);
else
count++;
} }
if (request_irq(irq_offset_up(virq), handler, 0, name, NULL)) { }
/* Else use normal interrupt tree parsing */
else {
/* First try to do a proper OF tree parsing */
for (index = 0; of_irq_map_one(np, index, &oirq) == 0;
index++) {
if (count > 15)
break;
virqs[count] = irq_create_of_mapping(oirq.controller,
oirq.specifier,
oirq.size);
if (virqs[count] == NO_IRQ)
printk(KERN_ERR "Unable to allocate interrupt "
"number for %s\n", np->full_name);
else
count++;
}
}
/* Now request them */
for (i = 0; i < count; i++) {
if (request_irq(virqs[i], handler, 0, name, NULL)) {
printk(KERN_ERR "Unable to request interrupt %d for " printk(KERN_ERR "Unable to request interrupt %d for "
"%s\n", irq_offset_up(virq), np->full_name); "%s\n", virqs[i], np->full_name);
return; return;
} }
ireg += n_intr;
} }
} }
...@@ -115,20 +145,14 @@ static int __init init_ras_IRQ(void) ...@@ -115,20 +145,14 @@ static int __init init_ras_IRQ(void)
/* Internal Errors */ /* Internal Errors */
np = of_find_node_by_path("/event-sources/internal-errors"); np = of_find_node_by_path("/event-sources/internal-errors");
if (np != NULL) { if (np != NULL) {
request_ras_irqs(np, "open-pic-interrupt", ras_error_interrupt, request_ras_irqs(np, ras_error_interrupt, "RAS_ERROR");
"RAS_ERROR");
request_ras_irqs(np, "interrupts", ras_error_interrupt,
"RAS_ERROR");
of_node_put(np); of_node_put(np);
} }
/* EPOW Events */ /* EPOW Events */
np = of_find_node_by_path("/event-sources/epow-events"); np = of_find_node_by_path("/event-sources/epow-events");
if (np != NULL) { if (np != NULL) {
request_ras_irqs(np, "open-pic-interrupt", ras_epow_interrupt, request_ras_irqs(np, ras_epow_interrupt, "RAS_EPOW");
"RAS_EPOW");
request_ras_irqs(np, "interrupts", ras_epow_interrupt,
"RAS_EPOW");
of_node_put(np); of_node_put(np);
} }
...@@ -162,7 +186,7 @@ ras_epow_interrupt(int irq, void *dev_id, struct pt_regs * regs) ...@@ -162,7 +186,7 @@ ras_epow_interrupt(int irq, void *dev_id, struct pt_regs * regs)
status = rtas_call(ras_check_exception_token, 6, 1, NULL, status = rtas_call(ras_check_exception_token, 6, 1, NULL,
RAS_VECTOR_OFFSET, RAS_VECTOR_OFFSET,
virt_irq_to_real(irq_offset_down(irq)), irq_map[irq].hwirq,
RTAS_EPOW_WARNING | RTAS_POWERMGM_EVENTS, RTAS_EPOW_WARNING | RTAS_POWERMGM_EVENTS,
critical, __pa(&ras_log_buf), critical, __pa(&ras_log_buf),
rtas_get_error_log_max()); rtas_get_error_log_max());
...@@ -198,7 +222,7 @@ ras_error_interrupt(int irq, void *dev_id, struct pt_regs * regs) ...@@ -198,7 +222,7 @@ ras_error_interrupt(int irq, void *dev_id, struct pt_regs * regs)
status = rtas_call(ras_check_exception_token, 6, 1, NULL, status = rtas_call(ras_check_exception_token, 6, 1, NULL,
RAS_VECTOR_OFFSET, RAS_VECTOR_OFFSET,
virt_irq_to_real(irq_offset_down(irq)), irq_map[irq].hwirq,
RTAS_INTERNAL_ERROR, 1 /*Time Critical */, RTAS_INTERNAL_ERROR, 1 /*Time Critical */,
__pa(&ras_log_buf), __pa(&ras_log_buf),
rtas_get_error_log_max()); rtas_get_error_log_max());
......
...@@ -76,6 +76,9 @@ ...@@ -76,6 +76,9 @@
#define DBG(fmt...) #define DBG(fmt...)
#endif #endif
/* move those away to a .h */
extern void smp_init_pseries_mpic(void);
extern void smp_init_pseries_xics(void);
extern void find_udbg_vterm(void); extern void find_udbg_vterm(void);
int fwnmi_active; /* TRUE if an FWNMI handler is present */ int fwnmi_active; /* TRUE if an FWNMI handler is present */
...@@ -83,7 +86,7 @@ int fwnmi_active; /* TRUE if an FWNMI handler is present */ ...@@ -83,7 +86,7 @@ int fwnmi_active; /* TRUE if an FWNMI handler is present */
static void pseries_shared_idle_sleep(void); static void pseries_shared_idle_sleep(void);
static void pseries_dedicated_idle_sleep(void); static void pseries_dedicated_idle_sleep(void);
struct mpic *pSeries_mpic; static struct device_node *pSeries_mpic_node;
static void pSeries_show_cpuinfo(struct seq_file *m) static void pSeries_show_cpuinfo(struct seq_file *m)
{ {
...@@ -118,78 +121,92 @@ static void __init fwnmi_init(void) ...@@ -118,78 +121,92 @@ static void __init fwnmi_init(void)
fwnmi_active = 1; fwnmi_active = 1;
} }
void pSeries_8259_cascade(unsigned int irq, struct irq_desc *desc, void pseries_8259_cascade(unsigned int irq, struct irq_desc *desc,
struct pt_regs *regs) struct pt_regs *regs)
{ {
unsigned int max = 100; unsigned int cascade_irq = i8259_irq(regs);
if (cascade_irq != NO_IRQ)
while(max--) {
int cascade_irq = i8259_irq(regs);
if (max == 99)
desc->chip->eoi(irq);
if (cascade_irq < 0)
break;
generic_handle_irq(cascade_irq, regs); generic_handle_irq(cascade_irq, regs);
}; desc->chip->eoi(irq);
} }
static void __init pSeries_init_mpic(void) static void __init pseries_mpic_init_IRQ(void)
{ {
struct device_node *np, *old, *cascade = NULL;
unsigned int *addrp; unsigned int *addrp;
struct device_node *np;
unsigned long intack = 0; unsigned long intack = 0;
/* All ISUs are setup, complete initialization */
mpic_init(pSeries_mpic);
/* Check what kind of cascade ACK we have */
if (!(np = of_find_node_by_name(NULL, "pci"))
|| !(addrp = (unsigned int *)
get_property(np, "8259-interrupt-acknowledge", NULL)))
printk(KERN_ERR "Cannot find pci to get ack address\n");
else
intack = addrp[prom_n_addr_cells(np)-1];
of_node_put(np);
/* Setup the legacy interrupts & controller */
i8259_init(intack, 0);
/* Hook cascade to mpic */
set_irq_chained_handler(NUM_ISA_INTERRUPTS, pSeries_8259_cascade);
}
static void __init pSeries_setup_mpic(void)
{
unsigned int *opprop; unsigned int *opprop;
unsigned long openpic_addr = 0; unsigned long openpic_addr = 0;
unsigned char senses[NR_IRQS - NUM_ISA_INTERRUPTS]; unsigned int cascade_irq;
struct device_node *root; int naddr, n, i, opplen;
int irq_count; struct mpic *mpic;
/* Find the Open PIC if present */ np = of_find_node_by_path("/");
root = of_find_node_by_path("/"); naddr = prom_n_addr_cells(np);
opprop = (unsigned int *) get_property(root, "platform-open-pic", NULL); opprop = (unsigned int *) get_property(np, "platform-open-pic", &opplen);
if (opprop != 0) { if (opprop != 0) {
int n = prom_n_addr_cells(root); openpic_addr = of_read_number(opprop, naddr);
for (openpic_addr = 0; n > 0; --n)
openpic_addr = (openpic_addr << 32) + *opprop++;
printk(KERN_DEBUG "OpenPIC addr: %lx\n", openpic_addr); printk(KERN_DEBUG "OpenPIC addr: %lx\n", openpic_addr);
} }
of_node_put(root); of_node_put(np);
BUG_ON(openpic_addr == 0); BUG_ON(openpic_addr == 0);
/* Get the sense values from OF */
prom_get_irq_senses(senses, NUM_ISA_INTERRUPTS, NR_IRQS);
/* Setup the openpic driver */ /* Setup the openpic driver */
irq_count = NR_IRQS - NUM_ISA_INTERRUPTS - 4; /* leave room for IPIs */ mpic = mpic_alloc(pSeries_mpic_node, openpic_addr,
pSeries_mpic = mpic_alloc(openpic_addr, MPIC_PRIMARY, MPIC_PRIMARY,
16, 16, irq_count, /* isu size, irq offset, irq count */ 16, 250, /* isu size, irq count */
NR_IRQS - 4, /* ipi offset */ " MPIC ");
senses, irq_count, /* sense & sense size */ BUG_ON(mpic == NULL);
" MPIC ");
/* Add ISUs */
opplen /= sizeof(u32);
for (n = 0, i = naddr; i < opplen; i += naddr, n++) {
unsigned long isuaddr = of_read_number(opprop + i, naddr);
mpic_assign_isu(mpic, n, isuaddr);
}
/* All ISUs are setup, complete initialization */
mpic_init(mpic);
/* Look for cascade */
for_each_node_by_type(np, "interrupt-controller")
if (device_is_compatible(np, "chrp,iic")) {
cascade = np;
break;
}
if (cascade == NULL)
return;
cascade_irq = irq_of_parse_and_map(cascade, 0);
if (cascade == NO_IRQ) {
printk(KERN_ERR "xics: failed to map cascade interrupt");
return;
}
/* Check ACK type */
for (old = of_node_get(cascade); old != NULL ; old = np) {
np = of_get_parent(old);
of_node_put(old);
if (np == NULL)
break;
if (strcmp(np->name, "pci") != 0)
continue;
addrp = (u32 *)get_property(np, "8259-interrupt-acknowledge",
NULL);
if (addrp == NULL)
continue;
naddr = prom_n_addr_cells(np);
intack = addrp[naddr-1];
if (naddr > 1)
intack |= ((unsigned long)addrp[naddr-2]) << 32;
}
if (intack)
printk(KERN_DEBUG "mpic: PCI 8259 intack at 0x%016lx\n",
intack);
i8259_init(cascade, intack);
of_node_put(cascade);
set_irq_chained_handler(cascade_irq, pseries_8259_cascade);
} }
static void pseries_lpar_enable_pmcs(void) static void pseries_lpar_enable_pmcs(void)
...@@ -207,21 +224,67 @@ static void pseries_lpar_enable_pmcs(void) ...@@ -207,21 +224,67 @@ static void pseries_lpar_enable_pmcs(void)
get_lppaca()->pmcregs_in_use = 1; get_lppaca()->pmcregs_in_use = 1;
} }
static void __init pSeries_setup_arch(void) #ifdef CONFIG_KEXEC
static void pseries_kexec_cpu_down_mpic(int crash_shutdown, int secondary)
{ {
/* Fixup ppc_md depending on the type of interrupt controller */ mpic_teardown_this_cpu(secondary);
if (ppc64_interrupt_controller == IC_OPEN_PIC) { }
ppc_md.init_IRQ = pSeries_init_mpic;
ppc_md.get_irq = mpic_get_irq;
/* Allocate the mpic now, so that find_and_init_phbs() can
* fill the ISUs */
pSeries_setup_mpic();
} else
ppc_md.init_IRQ = xics_init_IRQ;
static void pseries_kexec_cpu_down_xics(int crash_shutdown, int secondary)
{
/* Don't risk a hypervisor call if we're crashing */
if (firmware_has_feature(FW_FEATURE_SPLPAR) && !crash_shutdown) {
unsigned long vpa = __pa(get_lppaca());
if (unregister_vpa(hard_smp_processor_id(), vpa)) {
printk("VPA deregistration of cpu %u (hw_cpu_id %d) "
"failed\n", smp_processor_id(),
hard_smp_processor_id());
}
}
xics_teardown_cpu(secondary);
}
#endif /* CONFIG_KEXEC */
static void __init pseries_discover_pic(void)
{
struct device_node *np;
char *typep;
for (np = NULL; (np = of_find_node_by_name(np,
"interrupt-controller"));) {
typep = (char *)get_property(np, "compatible", NULL);
if (strstr(typep, "open-pic")) {
pSeries_mpic_node = of_node_get(np);
ppc_md.init_IRQ = pseries_mpic_init_IRQ;
ppc_md.get_irq = mpic_get_irq;
#ifdef CONFIG_KEXEC
ppc_md.kexec_cpu_down = pseries_kexec_cpu_down_mpic;
#endif
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
smp_init_pSeries(); smp_init_pseries_mpic();
#endif #endif
return;
} else if (strstr(typep, "ppc-xicp")) {
ppc_md.init_IRQ = xics_init_IRQ;
#ifdef CONFIG_KEXEC
ppc_md.kexec_cpu_down = pseries_kexec_cpu_down_xics;
#endif
#ifdef CONFIG_SMP
smp_init_pseries_xics();
#endif
return;
}
}
printk(KERN_ERR "pSeries_discover_pic: failed to recognize"
" interrupt-controller\n");
}
static void __init pSeries_setup_arch(void)
{
/* Discover PIC type and setup ppc_md accordingly */
pseries_discover_pic();
/* openpic global configuration register (64-bit format). */ /* openpic global configuration register (64-bit format). */
/* openpic Interrupt Source Unit pointer (64-bit format). */ /* openpic Interrupt Source Unit pointer (64-bit format). */
/* python0 facility area (mmio) (64-bit format) REAL address. */ /* python0 facility area (mmio) (64-bit format) REAL address. */
...@@ -273,33 +336,6 @@ static int __init pSeries_init_panel(void) ...@@ -273,33 +336,6 @@ static int __init pSeries_init_panel(void)
} }
arch_initcall(pSeries_init_panel); arch_initcall(pSeries_init_panel);
static void __init pSeries_discover_pic(void)
{
struct device_node *np;
char *typep;
/*
* Setup interrupt mapping options that are needed for finish_device_tree
* to properly parse the OF interrupt tree & do the virtual irq mapping
*/
__irq_offset_value = NUM_ISA_INTERRUPTS;
ppc64_interrupt_controller = IC_INVALID;
for (np = NULL; (np = of_find_node_by_name(np, "interrupt-controller"));) {
typep = (char *)get_property(np, "compatible", NULL);
if (strstr(typep, "open-pic")) {
ppc64_interrupt_controller = IC_OPEN_PIC;
break;
} else if (strstr(typep, "ppc-xicp")) {
ppc64_interrupt_controller = IC_PPC_XIC;
break;
}
}
if (ppc64_interrupt_controller == IC_INVALID)
printk("pSeries_discover_pic: failed to recognize"
" interrupt-controller\n");
}
static void pSeries_mach_cpu_die(void) static void pSeries_mach_cpu_die(void)
{ {
local_irq_disable(); local_irq_disable();
...@@ -342,8 +378,6 @@ static void __init pSeries_init_early(void) ...@@ -342,8 +378,6 @@ static void __init pSeries_init_early(void)
iommu_init_early_pSeries(); iommu_init_early_pSeries();
pSeries_discover_pic();
DBG(" <- pSeries_init_early()\n"); DBG(" <- pSeries_init_early()\n");
} }
...@@ -515,27 +549,6 @@ static int pSeries_pci_probe_mode(struct pci_bus *bus) ...@@ -515,27 +549,6 @@ static int pSeries_pci_probe_mode(struct pci_bus *bus)
return PCI_PROBE_NORMAL; return PCI_PROBE_NORMAL;
} }
#ifdef CONFIG_KEXEC
static void pseries_kexec_cpu_down(int crash_shutdown, int secondary)
{
/* Don't risk a hypervisor call if we're crashing */
if (firmware_has_feature(FW_FEATURE_SPLPAR) && !crash_shutdown) {
unsigned long vpa = __pa(get_lppaca());
if (unregister_vpa(hard_smp_processor_id(), vpa)) {
printk("VPA deregistration of cpu %u (hw_cpu_id %d) "
"failed\n", smp_processor_id(),
hard_smp_processor_id());
}
}
if (ppc64_interrupt_controller == IC_OPEN_PIC)
mpic_teardown_this_cpu(secondary);
else
xics_teardown_cpu(secondary);
}
#endif
define_machine(pseries) { define_machine(pseries) {
.name = "pSeries", .name = "pSeries",
.probe = pSeries_probe, .probe = pSeries_probe,
...@@ -560,7 +573,6 @@ define_machine(pseries) { ...@@ -560,7 +573,6 @@ define_machine(pseries) {
.system_reset_exception = pSeries_system_reset_exception, .system_reset_exception = pSeries_system_reset_exception,
.machine_check_exception = pSeries_machine_check_exception, .machine_check_exception = pSeries_machine_check_exception,
#ifdef CONFIG_KEXEC #ifdef CONFIG_KEXEC
.kexec_cpu_down = pseries_kexec_cpu_down,
.machine_kexec = default_machine_kexec, .machine_kexec = default_machine_kexec,
.machine_kexec_prepare = default_machine_kexec_prepare, .machine_kexec_prepare = default_machine_kexec_prepare,
.machine_crash_shutdown = default_machine_crash_shutdown, .machine_crash_shutdown = default_machine_crash_shutdown,
......
...@@ -416,27 +416,12 @@ static struct smp_ops_t pSeries_xics_smp_ops = { ...@@ -416,27 +416,12 @@ static struct smp_ops_t pSeries_xics_smp_ops = {
#endif #endif
/* This is called very early */ /* This is called very early */
void __init smp_init_pSeries(void) static void __init smp_init_pseries(void)
{ {
int i; int i;
DBG(" -> smp_init_pSeries()\n"); DBG(" -> smp_init_pSeries()\n");
switch (ppc64_interrupt_controller) {
#ifdef CONFIG_MPIC
case IC_OPEN_PIC:
smp_ops = &pSeries_mpic_smp_ops;
break;
#endif
#ifdef CONFIG_XICS
case IC_PPC_XIC:
smp_ops = &pSeries_xics_smp_ops;
break;
#endif
default:
panic("Invalid interrupt controller");
}
#ifdef CONFIG_HOTPLUG_CPU #ifdef CONFIG_HOTPLUG_CPU
smp_ops->cpu_disable = pSeries_cpu_disable; smp_ops->cpu_disable = pSeries_cpu_disable;
smp_ops->cpu_die = pSeries_cpu_die; smp_ops->cpu_die = pSeries_cpu_die;
...@@ -471,3 +456,18 @@ void __init smp_init_pSeries(void) ...@@ -471,3 +456,18 @@ void __init smp_init_pSeries(void)
DBG(" <- smp_init_pSeries()\n"); DBG(" <- smp_init_pSeries()\n");
} }
#ifdef CONFIG_MPIC
void __init smp_init_pseries_mpic(void)
{
smp_ops = &pSeries_mpic_smp_ops;
smp_init_pseries();
}
#endif
void __init smp_init_pseries_xics(void)
{
smp_ops = &pSeries_xics_smp_ops;
smp_init_pseries();
}
This diff is collapsed.
...@@ -31,7 +31,7 @@ struct xics_ipi_struct { ...@@ -31,7 +31,7 @@ struct xics_ipi_struct {
extern struct xics_ipi_struct xics_ipi_message[NR_CPUS] __cacheline_aligned; extern struct xics_ipi_struct xics_ipi_message[NR_CPUS] __cacheline_aligned;
struct irq_desc; struct irq_desc;
extern void pSeries_8259_cascade(unsigned int irq, struct irq_desc *desc, extern void pseries_8259_cascade(unsigned int irq, struct irq_desc *desc,
struct pt_regs *regs); struct pt_regs *regs);
#endif /* _POWERPC_KERNEL_XICS_H */ #endif /* _POWERPC_KERNEL_XICS_H */
...@@ -6,11 +6,16 @@ ...@@ -6,11 +6,16 @@
* as published by the Free Software Foundation; either version * as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version. * 2 of the License, or (at your option) any later version.
*/ */
#undef DEBUG
#include <linux/init.h> #include <linux/init.h>
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/i8259.h> #include <asm/i8259.h>
#include <asm/prom.h>
static volatile void __iomem *pci_intack; /* RO, gives us the irq vector */ static volatile void __iomem *pci_intack; /* RO, gives us the irq vector */
...@@ -20,7 +25,8 @@ static unsigned char cached_8259[2] = { 0xff, 0xff }; ...@@ -20,7 +25,8 @@ static unsigned char cached_8259[2] = { 0xff, 0xff };
static DEFINE_SPINLOCK(i8259_lock); static DEFINE_SPINLOCK(i8259_lock);
static int i8259_pic_irq_offset; static struct device_node *i8259_node;
static struct irq_host *i8259_host;
/* /*
* Acknowledge the IRQ using either the PCI host bridge's interrupt * Acknowledge the IRQ using either the PCI host bridge's interrupt
...@@ -28,16 +34,18 @@ static int i8259_pic_irq_offset; ...@@ -28,16 +34,18 @@ static int i8259_pic_irq_offset;
* which is called. It should be noted that polling is broken on some * which is called. It should be noted that polling is broken on some
* IBM and Motorola PReP boxes so we must use the int-ack feature on them. * IBM and Motorola PReP boxes so we must use the int-ack feature on them.
*/ */
int i8259_irq(struct pt_regs *regs) unsigned int i8259_irq(struct pt_regs *regs)
{ {
int irq; int irq;
int lock = 0;
spin_lock(&i8259_lock);
/* Either int-ack or poll for the IRQ */ /* Either int-ack or poll for the IRQ */
if (pci_intack) if (pci_intack)
irq = readb(pci_intack); irq = readb(pci_intack);
else { else {
spin_lock(&i8259_lock);
lock = 1;
/* Perform an interrupt acknowledge cycle on controller 1. */ /* Perform an interrupt acknowledge cycle on controller 1. */
outb(0x0C, 0x20); /* prepare for poll */ outb(0x0C, 0x20); /* prepare for poll */
irq = inb(0x20) & 7; irq = inb(0x20) & 7;
...@@ -62,11 +70,13 @@ int i8259_irq(struct pt_regs *regs) ...@@ -62,11 +70,13 @@ int i8259_irq(struct pt_regs *regs)
if (!pci_intack) if (!pci_intack)
outb(0x0B, 0x20); /* ISR register */ outb(0x0B, 0x20); /* ISR register */
if(~inb(0x20) & 0x80) if(~inb(0x20) & 0x80)
irq = -1; irq = NO_IRQ;
} } else if (irq == 0xff)
irq = NO_IRQ;
spin_unlock(&i8259_lock); if (lock)
return irq + i8259_pic_irq_offset; spin_unlock(&i8259_lock);
return irq;
} }
static void i8259_mask_and_ack_irq(unsigned int irq_nr) static void i8259_mask_and_ack_irq(unsigned int irq_nr)
...@@ -74,7 +84,6 @@ static void i8259_mask_and_ack_irq(unsigned int irq_nr) ...@@ -74,7 +84,6 @@ static void i8259_mask_and_ack_irq(unsigned int irq_nr)
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&i8259_lock, flags); spin_lock_irqsave(&i8259_lock, flags);
irq_nr -= i8259_pic_irq_offset;
if (irq_nr > 7) { if (irq_nr > 7) {
cached_A1 |= 1 << (irq_nr-8); cached_A1 |= 1 << (irq_nr-8);
inb(0xA1); /* DUMMY */ inb(0xA1); /* DUMMY */
...@@ -100,8 +109,9 @@ static void i8259_mask_irq(unsigned int irq_nr) ...@@ -100,8 +109,9 @@ static void i8259_mask_irq(unsigned int irq_nr)
{ {
unsigned long flags; unsigned long flags;
pr_debug("i8259_mask_irq(%d)\n", irq_nr);
spin_lock_irqsave(&i8259_lock, flags); spin_lock_irqsave(&i8259_lock, flags);
irq_nr -= i8259_pic_irq_offset;
if (irq_nr < 8) if (irq_nr < 8)
cached_21 |= 1 << irq_nr; cached_21 |= 1 << irq_nr;
else else
...@@ -114,8 +124,9 @@ static void i8259_unmask_irq(unsigned int irq_nr) ...@@ -114,8 +124,9 @@ static void i8259_unmask_irq(unsigned int irq_nr)
{ {
unsigned long flags; unsigned long flags;
pr_debug("i8259_unmask_irq(%d)\n", irq_nr);
spin_lock_irqsave(&i8259_lock, flags); spin_lock_irqsave(&i8259_lock, flags);
irq_nr -= i8259_pic_irq_offset;
if (irq_nr < 8) if (irq_nr < 8)
cached_21 &= ~(1 << irq_nr); cached_21 &= ~(1 << irq_nr);
else else
...@@ -152,25 +163,84 @@ static struct resource pic_edgectrl_iores = { ...@@ -152,25 +163,84 @@ static struct resource pic_edgectrl_iores = {
.flags = IORESOURCE_BUSY, .flags = IORESOURCE_BUSY,
}; };
static struct irqaction i8259_irqaction = { static int i8259_host_match(struct irq_host *h, struct device_node *node)
.handler = no_action, {
.flags = IRQF_DISABLED, return i8259_node == NULL || i8259_node == node;
.mask = CPU_MASK_NONE, }
.name = "82c59 secondary cascade",
static int i8259_host_map(struct irq_host *h, unsigned int virq,
irq_hw_number_t hw, unsigned int flags)
{
pr_debug("i8259_host_map(%d, 0x%lx)\n", virq, hw);
/* We block the internal cascade */
if (hw == 2)
get_irq_desc(virq)->status |= IRQ_NOREQUEST;
/* We use the level stuff only for now, we might want to
* be more cautious here but that works for now
*/
get_irq_desc(virq)->status |= IRQ_LEVEL;
set_irq_chip_and_handler(virq, &i8259_pic, handle_level_irq);
return 0;
}
static void i8259_host_unmap(struct irq_host *h, unsigned int virq)
{
/* Make sure irq is masked in hardware */
i8259_mask_irq(virq);
/* remove chip and handler */
set_irq_chip_and_handler(virq, NULL, NULL);
/* Make sure it's completed */
synchronize_irq(virq);
}
static int i8259_host_xlate(struct irq_host *h, struct device_node *ct,
u32 *intspec, unsigned int intsize,
irq_hw_number_t *out_hwirq, unsigned int *out_flags)
{
static unsigned char map_isa_senses[4] = {
IRQ_TYPE_LEVEL_LOW,
IRQ_TYPE_LEVEL_HIGH,
IRQ_TYPE_EDGE_FALLING,
IRQ_TYPE_EDGE_RISING,
};
*out_hwirq = intspec[0];
if (intsize > 1 && intspec[1] < 4)
*out_flags = map_isa_senses[intspec[1]];
else
*out_flags = IRQ_TYPE_NONE;
return 0;
}
static struct irq_host_ops i8259_host_ops = {
.match = i8259_host_match,
.map = i8259_host_map,
.unmap = i8259_host_unmap,
.xlate = i8259_host_xlate,
}; };
/* /****
* i8259_init() * i8259_init - Initialize the legacy controller
* intack_addr - PCI interrupt acknowledge (real) address which will return * @node: device node of the legacy PIC (can be NULL, but then, it will match
* the active irq from the 8259 * all interrupts, so beware)
* @intack_addr: PCI interrupt acknowledge (real) address which will return
* the active irq from the 8259
*/ */
void __init i8259_init(unsigned long intack_addr, int offset) void i8259_init(struct device_node *node, unsigned long intack_addr)
{ {
unsigned long flags; unsigned long flags;
int i;
/* initialize the controller */
spin_lock_irqsave(&i8259_lock, flags); spin_lock_irqsave(&i8259_lock, flags);
i8259_pic_irq_offset = offset;
/* Mask all first */
outb(0xff, 0xA1);
outb(0xff, 0x21);
/* init master interrupt controller */ /* init master interrupt controller */
outb(0x11, 0x20); /* Start init sequence */ outb(0x11, 0x20); /* Start init sequence */
...@@ -184,24 +254,36 @@ void __init i8259_init(unsigned long intack_addr, int offset) ...@@ -184,24 +254,36 @@ void __init i8259_init(unsigned long intack_addr, int offset)
outb(0x02, 0xA1); /* edge triggered, Cascade (slave) on IRQ2 */ outb(0x02, 0xA1); /* edge triggered, Cascade (slave) on IRQ2 */
outb(0x01, 0xA1); /* Select 8086 mode */ outb(0x01, 0xA1); /* Select 8086 mode */
/* That thing is slow */
udelay(100);
/* always read ISR */ /* always read ISR */
outb(0x0B, 0x20); outb(0x0B, 0x20);
outb(0x0B, 0xA0); outb(0x0B, 0xA0);
/* Mask all interrupts */ /* Unmask the internal cascade */
cached_21 &= ~(1 << 2);
/* Set interrupt masks */
outb(cached_A1, 0xA1); outb(cached_A1, 0xA1);
outb(cached_21, 0x21); outb(cached_21, 0x21);
spin_unlock_irqrestore(&i8259_lock, flags); spin_unlock_irqrestore(&i8259_lock, flags);
for (i = 0; i < NUM_ISA_INTERRUPTS; ++i) { /* create a legacy host */
set_irq_chip_and_handler(offset + i, &i8259_pic, if (node)
handle_level_irq); i8259_node = of_node_get(node);
irq_desc[offset + i].status |= IRQ_LEVEL; i8259_host = irq_alloc_host(IRQ_HOST_MAP_LEGACY, 0, &i8259_host_ops, 0);
if (i8259_host == NULL) {
printk(KERN_ERR "i8259: failed to allocate irq host !\n");
return;
} }
/* reserve our resources */ /* reserve our resources */
setup_irq(offset + 2, &i8259_irqaction); /* XXX should we continue doing that ? it seems to cause problems
* with further requesting of PCI IO resources for that range...
* need to look into it.
*/
request_resource(&ioport_resource, &pic1_iores); request_resource(&ioport_resource, &pic1_iores);
request_resource(&ioport_resource, &pic2_iores); request_resource(&ioport_resource, &pic2_iores);
request_resource(&ioport_resource, &pic_edgectrl_iores); request_resource(&ioport_resource, &pic_edgectrl_iores);
...@@ -209,4 +291,5 @@ void __init i8259_init(unsigned long intack_addr, int offset) ...@@ -209,4 +291,5 @@ void __init i8259_init(unsigned long intack_addr, int offset)
if (intack_addr != 0) if (intack_addr != 0)
pci_intack = ioremap(intack_addr, 1); pci_intack = ioremap(intack_addr, 1);
printk(KERN_INFO "i8259 legacy interrupt controller initialized\n");
} }
This diff is collapsed.
...@@ -1299,13 +1299,12 @@ static int __init hvsi_console_init(void) ...@@ -1299,13 +1299,12 @@ static int __init hvsi_console_init(void)
hp->inbuf_end = hp->inbuf; hp->inbuf_end = hp->inbuf;
hp->state = HVSI_CLOSED; hp->state = HVSI_CLOSED;
hp->vtermno = *vtermno; hp->vtermno = *vtermno;
hp->virq = virt_irq_create_mapping(irq[0]); hp->virq = irq_create_mapping(NULL, irq[0], 0);
if (hp->virq == NO_IRQ) { if (hp->virq == NO_IRQ) {
printk(KERN_ERR "%s: couldn't create irq mapping for 0x%x\n", printk(KERN_ERR "%s: couldn't create irq mapping for 0x%x\n",
__FUNCTION__, hp->virq); __FUNCTION__, irq[0]);
continue; continue;
} else }
hp->virq = irq_offset_up(hp->virq);
hvsi_count++; hvsi_count++;
} }
......
...@@ -90,22 +90,12 @@ int macio_init(void) ...@@ -90,22 +90,12 @@ int macio_init(void)
{ {
struct device_node *adbs; struct device_node *adbs;
struct resource r; struct resource r;
unsigned int irq;
adbs = find_compatible_devices("adb", "chrp,adb0"); adbs = find_compatible_devices("adb", "chrp,adb0");
if (adbs == 0) if (adbs == 0)
return -ENXIO; return -ENXIO;
#if 0
{ int i = 0;
printk("macio_adb_init: node = %p, addrs =", adbs->node);
while(!of_address_to_resource(adbs, i, &r))
printk(" %x(%x)", r.start, r.end - r.start);
printk(", intrs =");
for (i = 0; i < adbs->n_intrs; ++i)
printk(" %x", adbs->intrs[i].line);
printk("\n"); }
#endif
if (of_address_to_resource(adbs, 0, &r)) if (of_address_to_resource(adbs, 0, &r))
return -ENXIO; return -ENXIO;
adb = ioremap(r.start, sizeof(struct adb_regs)); adb = ioremap(r.start, sizeof(struct adb_regs));
...@@ -117,10 +107,9 @@ int macio_init(void) ...@@ -117,10 +107,9 @@ int macio_init(void)
out_8(&adb->active_lo.r, 0xff); out_8(&adb->active_lo.r, 0xff);
out_8(&adb->autopoll.r, APE); out_8(&adb->autopoll.r, APE);
if (request_irq(adbs->intrs[0].line, macio_adb_interrupt, irq = irq_of_parse_and_map(adbs, 0);
0, "ADB", (void *)0)) { if (request_irq(irq, macio_adb_interrupt, 0, "ADB", (void *)0)) {
printk(KERN_ERR "ADB: can't get irq %d\n", printk(KERN_ERR "ADB: can't get irq %d\n", irq);
adbs->intrs[0].line);
return -EAGAIN; return -EAGAIN;
} }
out_8(&adb->intr_enb.r, DFB | TAG); out_8(&adb->intr_enb.r, DFB | TAG);
......
...@@ -280,75 +280,128 @@ static void macio_release_dev(struct device *dev) ...@@ -280,75 +280,128 @@ static void macio_release_dev(struct device *dev)
static int macio_resource_quirks(struct device_node *np, struct resource *res, static int macio_resource_quirks(struct device_node *np, struct resource *res,
int index) int index)
{ {
if (res->flags & IORESOURCE_MEM) { /* Only quirks for memory resources for now */
/* Grand Central has too large resource 0 on some machines */ if ((res->flags & IORESOURCE_MEM) == 0)
if (index == 0 && !strcmp(np->name, "gc")) return 0;
res->end = res->start + 0x1ffff;
/* Grand Central has too large resource 0 on some machines */
if (index == 0 && !strcmp(np->name, "gc"))
res->end = res->start + 0x1ffff;
/* Airport has bogus resource 2 */ /* Airport has bogus resource 2 */
if (index >= 2 && !strcmp(np->name, "radio")) if (index >= 2 && !strcmp(np->name, "radio"))
return 1; return 1;
#ifndef CONFIG_PPC64 #ifndef CONFIG_PPC64
/* DBDMAs may have bogus sizes */ /* DBDMAs may have bogus sizes */
if ((res->start & 0x0001f000) == 0x00008000) if ((res->start & 0x0001f000) == 0x00008000)
res->end = res->start + 0xff; res->end = res->start + 0xff;
#endif /* CONFIG_PPC64 */ #endif /* CONFIG_PPC64 */
/* ESCC parent eats child resources. We could have added a /* ESCC parent eats child resources. We could have added a
* level of hierarchy, but I don't really feel the need * level of hierarchy, but I don't really feel the need
* for it * for it
*/ */
if (!strcmp(np->name, "escc")) if (!strcmp(np->name, "escc"))
return 1; return 1;
/* ESCC has bogus resources >= 3 */ /* ESCC has bogus resources >= 3 */
if (index >= 3 && !(strcmp(np->name, "ch-a") && if (index >= 3 && !(strcmp(np->name, "ch-a") &&
strcmp(np->name, "ch-b"))) strcmp(np->name, "ch-b")))
return 1; return 1;
/* Media bay has too many resources, keep only first one */ /* Media bay has too many resources, keep only first one */
if (index > 0 && !strcmp(np->name, "media-bay")) if (index > 0 && !strcmp(np->name, "media-bay"))
return 1; return 1;
/* Some older IDE resources have bogus sizes */ /* Some older IDE resources have bogus sizes */
if (!(strcmp(np->name, "IDE") && strcmp(np->name, "ATA") && if (!(strcmp(np->name, "IDE") && strcmp(np->name, "ATA") &&
strcmp(np->type, "ide") && strcmp(np->type, "ata"))) { strcmp(np->type, "ide") && strcmp(np->type, "ata"))) {
if (index == 0 && (res->end - res->start) > 0xfff) if (index == 0 && (res->end - res->start) > 0xfff)
res->end = res->start + 0xfff; res->end = res->start + 0xfff;
if (index == 1 && (res->end - res->start) > 0xff) if (index == 1 && (res->end - res->start) > 0xff)
res->end = res->start + 0xff; res->end = res->start + 0xff;
}
} }
return 0; return 0;
} }
static void macio_create_fixup_irq(struct macio_dev *dev, int index,
unsigned int line)
{
unsigned int irq;
static void macio_setup_interrupts(struct macio_dev *dev) irq = irq_create_mapping(NULL, line, 0);
if (irq != NO_IRQ) {
dev->interrupt[index].start = irq;
dev->interrupt[index].flags = IORESOURCE_IRQ;
dev->interrupt[index].name = dev->ofdev.dev.bus_id;
}
if (dev->n_interrupts <= index)
dev->n_interrupts = index + 1;
}
static void macio_add_missing_resources(struct macio_dev *dev)
{ {
struct device_node *np = dev->ofdev.node; struct device_node *np = dev->ofdev.node;
int i,j; unsigned int irq_base;
/* Gatwick has some missing interrupts on child nodes */
if (dev->bus->chip->type != macio_gatwick)
return;
/* For now, we use pre-parsed entries in the device-tree for /* irq_base is always 64 on gatwick. I have no cleaner way to get
* interrupt routing and addresses, but we should change that * that value from here at this point
* to dynamically parsed entries and so get rid of most of the
* clutter in struct device_node
*/ */
for (i = j = 0; i < np->n_intrs; i++) { irq_base = 64;
/* Fix SCC */
if (strcmp(np->name, "ch-a") == 0) {
macio_create_fixup_irq(dev, 0, 15 + irq_base);
macio_create_fixup_irq(dev, 1, 4 + irq_base);
macio_create_fixup_irq(dev, 2, 5 + irq_base);
printk(KERN_INFO "macio: fixed SCC irqs on gatwick\n");
}
/* Fix media-bay */
if (strcmp(np->name, "media-bay") == 0) {
macio_create_fixup_irq(dev, 0, 29 + irq_base);
printk(KERN_INFO "macio: fixed media-bay irq on gatwick\n");
}
/* Fix left media bay childs */
if (dev->media_bay != NULL && strcmp(np->name, "floppy") == 0) {
macio_create_fixup_irq(dev, 0, 19 + irq_base);
macio_create_fixup_irq(dev, 1, 1 + irq_base);
printk(KERN_INFO "macio: fixed left floppy irqs\n");
}
if (dev->media_bay != NULL && strcasecmp(np->name, "ata4") == 0) {
macio_create_fixup_irq(dev, 0, 14 + irq_base);
macio_create_fixup_irq(dev, 0, 3 + irq_base);
printk(KERN_INFO "macio: fixed left ide irqs\n");
}
}
static void macio_setup_interrupts(struct macio_dev *dev)
{
struct device_node *np = dev->ofdev.node;
unsigned int irq;
int i = 0, j = 0;
for (;;) {
struct resource *res = &dev->interrupt[j]; struct resource *res = &dev->interrupt[j];
if (j >= MACIO_DEV_COUNT_IRQS) if (j >= MACIO_DEV_COUNT_IRQS)
break; break;
res->start = np->intrs[i].line; irq = irq_of_parse_and_map(np, i++);
res->flags = IORESOURCE_IO; if (irq == NO_IRQ)
if (np->intrs[j].sense) break;
res->flags |= IORESOURCE_IRQ_LOWLEVEL; res->start = irq;
else res->flags = IORESOURCE_IRQ;
res->flags |= IORESOURCE_IRQ_HIGHEDGE;
res->name = dev->ofdev.dev.bus_id; res->name = dev->ofdev.dev.bus_id;
if (macio_resource_quirks(np, res, i)) if (macio_resource_quirks(np, res, i - 1)) {
memset(res, 0, sizeof(struct resource)); memset(res, 0, sizeof(struct resource));
else continue;
} else
j++; j++;
} }
dev->n_interrupts = j; dev->n_interrupts = j;
...@@ -445,6 +498,7 @@ static struct macio_dev * macio_add_one_device(struct macio_chip *chip, ...@@ -445,6 +498,7 @@ static struct macio_dev * macio_add_one_device(struct macio_chip *chip,
/* Setup interrupts & resources */ /* Setup interrupts & resources */
macio_setup_interrupts(dev); macio_setup_interrupts(dev);
macio_setup_resources(dev, parent_res); macio_setup_resources(dev, parent_res);
macio_add_missing_resources(dev);
/* Register with core */ /* Register with core */
if (of_device_register(&dev->ofdev) != 0) { if (of_device_register(&dev->ofdev) != 0) {
......
...@@ -497,8 +497,7 @@ int __init smu_init (void) ...@@ -497,8 +497,7 @@ int __init smu_init (void)
smu->doorbell = *data; smu->doorbell = *data;
if (smu->doorbell < 0x50) if (smu->doorbell < 0x50)
smu->doorbell += 0x50; smu->doorbell += 0x50;
if (np->n_intrs > 0) smu->db_irq = irq_of_parse_and_map(np, 0);
smu->db_irq = np->intrs[0].line;
of_node_put(np); of_node_put(np);
...@@ -515,8 +514,7 @@ int __init smu_init (void) ...@@ -515,8 +514,7 @@ int __init smu_init (void)
smu->msg = *data; smu->msg = *data;
if (smu->msg < 0x50) if (smu->msg < 0x50)
smu->msg += 0x50; smu->msg += 0x50;
if (np->n_intrs > 0) smu->msg_irq = irq_of_parse_and_map(np, 0);
smu->msg_irq = np->intrs[0].line;
of_node_put(np); of_node_put(np);
} while(0); } while(0);
......
...@@ -34,13 +34,6 @@ ...@@ -34,13 +34,6 @@
static volatile unsigned char __iomem *via; static volatile unsigned char __iomem *via;
static DEFINE_SPINLOCK(cuda_lock); static DEFINE_SPINLOCK(cuda_lock);
#ifdef CONFIG_MAC
#define CUDA_IRQ IRQ_MAC_ADB
#define eieio()
#else
#define CUDA_IRQ vias->intrs[0].line
#endif
/* VIA registers - spaced 0x200 bytes apart */ /* VIA registers - spaced 0x200 bytes apart */
#define RS 0x200 /* skip between registers */ #define RS 0x200 /* skip between registers */
#define B 0 /* B-side data */ #define B 0 /* B-side data */
...@@ -189,11 +182,24 @@ int __init find_via_cuda(void) ...@@ -189,11 +182,24 @@ int __init find_via_cuda(void)
static int __init via_cuda_start(void) static int __init via_cuda_start(void)
{ {
unsigned int irq;
if (via == NULL) if (via == NULL)
return -ENODEV; return -ENODEV;
if (request_irq(CUDA_IRQ, cuda_interrupt, 0, "ADB", cuda_interrupt)) { #ifdef CONFIG_MAC
printk(KERN_ERR "cuda_init: can't get irq %d\n", CUDA_IRQ); irq = IRQ_MAC_ADB;
#else /* CONFIG_MAC */
irq = irq_of_parse_and_map(vias, 0);
if (irq == NO_IRQ) {
printk(KERN_ERR "via-cuda: can't map interrupts for %s\n",
vias->full_name);
return -ENODEV;
}
#endif /* CONFIG_MAP */
if (request_irq(irq, cuda_interrupt, 0, "ADB", cuda_interrupt)) {
printk(KERN_ERR "via-cuda: can't request irq %d\n", irq);
return -EAGAIN; return -EAGAIN;
} }
......
...@@ -64,10 +64,6 @@ ...@@ -64,10 +64,6 @@
#include <asm/backlight.h> #include <asm/backlight.h>
#endif #endif
#ifdef CONFIG_PPC32
#include <asm/open_pic.h>
#endif
#include "via-pmu-event.h" #include "via-pmu-event.h"
/* Some compile options */ /* Some compile options */
...@@ -151,7 +147,7 @@ static int pmu_fully_inited = 0; ...@@ -151,7 +147,7 @@ static int pmu_fully_inited = 0;
static int pmu_has_adb; static int pmu_has_adb;
static struct device_node *gpio_node; static struct device_node *gpio_node;
static unsigned char __iomem *gpio_reg = NULL; static unsigned char __iomem *gpio_reg = NULL;
static int gpio_irq = -1; static int gpio_irq = NO_IRQ;
static int gpio_irq_enabled = -1; static int gpio_irq_enabled = -1;
static volatile int pmu_suspended = 0; static volatile int pmu_suspended = 0;
static spinlock_t pmu_lock; static spinlock_t pmu_lock;
...@@ -403,22 +399,21 @@ static int __init pmu_init(void) ...@@ -403,22 +399,21 @@ static int __init pmu_init(void)
*/ */
static int __init via_pmu_start(void) static int __init via_pmu_start(void)
{ {
unsigned int irq;
if (vias == NULL) if (vias == NULL)
return -ENODEV; return -ENODEV;
batt_req.complete = 1; batt_req.complete = 1;
#ifndef CONFIG_PPC_MERGE irq = irq_of_parse_and_map(vias, 0);
if (pmu_kind == PMU_KEYLARGO_BASED) if (irq == NO_IRQ) {
openpic_set_irq_priority(vias->intrs[0].line, printk(KERN_ERR "via-pmu: can't map interruptn");
OPENPIC_PRIORITY_DEFAULT + 1); return -ENODEV;
#endif }
if (request_irq(irq, via_pmu_interrupt, 0, "VIA-PMU", (void *)0)) {
if (request_irq(vias->intrs[0].line, via_pmu_interrupt, 0, "VIA-PMU", printk(KERN_ERR "via-pmu: can't request irq %d\n", irq);
(void *)0)) { return -ENODEV;
printk(KERN_ERR "VIA-PMU: can't get irq %d\n",
vias->intrs[0].line);
return -EAGAIN;
} }
if (pmu_kind == PMU_KEYLARGO_BASED) { if (pmu_kind == PMU_KEYLARGO_BASED) {
...@@ -426,10 +421,10 @@ static int __init via_pmu_start(void) ...@@ -426,10 +421,10 @@ static int __init via_pmu_start(void)
if (gpio_node == NULL) if (gpio_node == NULL)
gpio_node = of_find_node_by_name(NULL, gpio_node = of_find_node_by_name(NULL,
"pmu-interrupt"); "pmu-interrupt");
if (gpio_node && gpio_node->n_intrs > 0) if (gpio_node)
gpio_irq = gpio_node->intrs[0].line; gpio_irq = irq_of_parse_and_map(gpio_node, 0);
if (gpio_irq != -1) { if (gpio_irq != NO_IRQ) {
if (request_irq(gpio_irq, gpio1_interrupt, 0, if (request_irq(gpio_irq, gpio1_interrupt, 0,
"GPIO1 ADB", (void *)0)) "GPIO1 ADB", (void *)0))
printk(KERN_ERR "pmu: can't get irq %d" printk(KERN_ERR "pmu: can't get irq %d"
......
...@@ -242,12 +242,12 @@ static int __devinit mace_probe(struct macio_dev *mdev, const struct of_device_i ...@@ -242,12 +242,12 @@ static int __devinit mace_probe(struct macio_dev *mdev, const struct of_device_i
} }
rc = request_irq(mp->tx_dma_intr, mace_txdma_intr, 0, "MACE-txdma", dev); rc = request_irq(mp->tx_dma_intr, mace_txdma_intr, 0, "MACE-txdma", dev);
if (rc) { if (rc) {
printk(KERN_ERR "MACE: can't get irq %d\n", mace->intrs[1].line); printk(KERN_ERR "MACE: can't get irq %d\n", mp->tx_dma_intr);
goto err_free_irq; goto err_free_irq;
} }
rc = request_irq(mp->rx_dma_intr, mace_rxdma_intr, 0, "MACE-rxdma", dev); rc = request_irq(mp->rx_dma_intr, mace_rxdma_intr, 0, "MACE-rxdma", dev);
if (rc) { if (rc) {
printk(KERN_ERR "MACE: can't get irq %d\n", mace->intrs[2].line); printk(KERN_ERR "MACE: can't get irq %d\n", mp->rx_dma_intr);
goto err_free_tx_irq; goto err_free_tx_irq;
} }
......
...@@ -1443,8 +1443,8 @@ static int __init pmz_init_port(struct uart_pmac_port *uap) ...@@ -1443,8 +1443,8 @@ static int __init pmz_init_port(struct uart_pmac_port *uap)
uap->flags &= ~PMACZILOG_FLAG_HAS_DMA; uap->flags &= ~PMACZILOG_FLAG_HAS_DMA;
goto no_dma; goto no_dma;
} }
uap->tx_dma_irq = np->intrs[1].line; uap->tx_dma_irq = irq_of_parse_and_map(np, 1);
uap->rx_dma_irq = np->intrs[2].line; uap->rx_dma_irq = irq_of_parse_and_map(np, 2);
} }
no_dma: no_dma:
...@@ -1491,7 +1491,7 @@ static int __init pmz_init_port(struct uart_pmac_port *uap) ...@@ -1491,7 +1491,7 @@ static int __init pmz_init_port(struct uart_pmac_port *uap)
* Init remaining bits of "port" structure * Init remaining bits of "port" structure
*/ */
uap->port.iotype = UPIO_MEM; uap->port.iotype = UPIO_MEM;
uap->port.irq = np->intrs[0].line; uap->port.irq = irq_of_parse_and_map(np, 0);
uap->port.uartclk = ZS_CLOCK; uap->port.uartclk = ZS_CLOCK;
uap->port.fifosize = 1; uap->port.fifosize = 1;
uap->port.ops = &pmz_pops; uap->port.ops = &pmz_pops;
......
...@@ -4,8 +4,13 @@ ...@@ -4,8 +4,13 @@
#include <linux/irq.h> #include <linux/irq.h>
#ifdef CONFIG_PPC_MERGE
extern void i8259_init(struct device_node *node, unsigned long intack_addr);
extern unsigned int i8259_irq(struct pt_regs *regs);
#else
extern void i8259_init(unsigned long intack_addr, int offset); extern void i8259_init(unsigned long intack_addr, int offset);
extern int i8259_irq(struct pt_regs *regs); extern int i8259_irq(struct pt_regs *regs);
#endif
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_I8259_H */ #endif /* _ASM_POWERPC_I8259_H */
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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