Path: blob/master/arch/powerpc/platforms/powermac/pic.c
10818 views
/*1* Support for the interrupt controllers found on Power Macintosh,2* currently Apple's "Grand Central" interrupt controller in all3* it's incarnations. OpenPIC support used on newer machines is4* in a separate file5*6* Copyright (C) 1997 Paul Mackerras ([email protected])7* Copyright (C) 2005 Benjamin Herrenschmidt ([email protected])8* IBM, Corp.9*10* This program is free software; you can redistribute it and/or11* modify it under the terms of the GNU General Public License12* as published by the Free Software Foundation; either version13* 2 of the License, or (at your option) any later version.14*15*/1617#include <linux/stddef.h>18#include <linux/init.h>19#include <linux/sched.h>20#include <linux/signal.h>21#include <linux/pci.h>22#include <linux/interrupt.h>23#include <linux/syscore_ops.h>24#include <linux/adb.h>25#include <linux/pmu.h>26#include <linux/module.h>2728#include <asm/sections.h>29#include <asm/io.h>30#include <asm/smp.h>31#include <asm/prom.h>32#include <asm/pci-bridge.h>33#include <asm/time.h>34#include <asm/pmac_feature.h>35#include <asm/mpic.h>36#include <asm/xmon.h>3738#include "pmac.h"3940#ifdef CONFIG_PPC3241struct pmac_irq_hw {42unsigned int event;43unsigned int enable;44unsigned int ack;45unsigned int level;46};4748/* Workaround flags for 32bit powermac machines */49unsigned int of_irq_workarounds;50struct device_node *of_irq_dflt_pic;5152/* Default addresses */53static volatile struct pmac_irq_hw __iomem *pmac_irq_hw[4];5455#define GC_LEVEL_MASK 0x3ff0000056#define OHARE_LEVEL_MASK 0x1ff0000057#define HEATHROW_LEVEL_MASK 0x1ff000005859static int max_irqs;60static int max_real_irqs;61static u32 level_mask[4];6263static DEFINE_RAW_SPINLOCK(pmac_pic_lock);6465#define NR_MASK_WORDS ((NR_IRQS + 31) / 32)66static unsigned long ppc_lost_interrupts[NR_MASK_WORDS];67static unsigned long ppc_cached_irq_mask[NR_MASK_WORDS];68static int pmac_irq_cascade = -1;69static struct irq_host *pmac_pic_host;7071static void __pmac_retrigger(unsigned int irq_nr)72{73if (irq_nr >= max_real_irqs && pmac_irq_cascade > 0) {74__set_bit(irq_nr, ppc_lost_interrupts);75irq_nr = pmac_irq_cascade;76mb();77}78if (!__test_and_set_bit(irq_nr, ppc_lost_interrupts)) {79atomic_inc(&ppc_n_lost_interrupts);80set_dec(1);81}82}8384static void pmac_mask_and_ack_irq(struct irq_data *d)85{86unsigned int src = irqd_to_hwirq(d);87unsigned long bit = 1UL << (src & 0x1f);88int i = src >> 5;89unsigned long flags;9091raw_spin_lock_irqsave(&pmac_pic_lock, flags);92__clear_bit(src, ppc_cached_irq_mask);93if (__test_and_clear_bit(src, ppc_lost_interrupts))94atomic_dec(&ppc_n_lost_interrupts);95out_le32(&pmac_irq_hw[i]->enable, ppc_cached_irq_mask[i]);96out_le32(&pmac_irq_hw[i]->ack, bit);97do {98/* make sure ack gets to controller before we enable99interrupts */100mb();101} while((in_le32(&pmac_irq_hw[i]->enable) & bit)102!= (ppc_cached_irq_mask[i] & bit));103raw_spin_unlock_irqrestore(&pmac_pic_lock, flags);104}105106static void pmac_ack_irq(struct irq_data *d)107{108unsigned int src = irqd_to_hwirq(d);109unsigned long bit = 1UL << (src & 0x1f);110int i = src >> 5;111unsigned long flags;112113raw_spin_lock_irqsave(&pmac_pic_lock, flags);114if (__test_and_clear_bit(src, ppc_lost_interrupts))115atomic_dec(&ppc_n_lost_interrupts);116out_le32(&pmac_irq_hw[i]->ack, bit);117(void)in_le32(&pmac_irq_hw[i]->ack);118raw_spin_unlock_irqrestore(&pmac_pic_lock, flags);119}120121static void __pmac_set_irq_mask(unsigned int irq_nr, int nokicklost)122{123unsigned long bit = 1UL << (irq_nr & 0x1f);124int i = irq_nr >> 5;125126if ((unsigned)irq_nr >= max_irqs)127return;128129/* enable unmasked interrupts */130out_le32(&pmac_irq_hw[i]->enable, ppc_cached_irq_mask[i]);131132do {133/* make sure mask gets to controller before we134return to user */135mb();136} while((in_le32(&pmac_irq_hw[i]->enable) & bit)137!= (ppc_cached_irq_mask[i] & bit));138139/*140* Unfortunately, setting the bit in the enable register141* when the device interrupt is already on *doesn't* set142* the bit in the flag register or request another interrupt.143*/144if (bit & ppc_cached_irq_mask[i] & in_le32(&pmac_irq_hw[i]->level))145__pmac_retrigger(irq_nr);146}147148/* When an irq gets requested for the first client, if it's an149* edge interrupt, we clear any previous one on the controller150*/151static unsigned int pmac_startup_irq(struct irq_data *d)152{153unsigned long flags;154unsigned int src = irqd_to_hwirq(d);155unsigned long bit = 1UL << (src & 0x1f);156int i = src >> 5;157158raw_spin_lock_irqsave(&pmac_pic_lock, flags);159if (!irqd_is_level_type(d))160out_le32(&pmac_irq_hw[i]->ack, bit);161__set_bit(src, ppc_cached_irq_mask);162__pmac_set_irq_mask(src, 0);163raw_spin_unlock_irqrestore(&pmac_pic_lock, flags);164165return 0;166}167168static void pmac_mask_irq(struct irq_data *d)169{170unsigned long flags;171unsigned int src = irqd_to_hwirq(d);172173raw_spin_lock_irqsave(&pmac_pic_lock, flags);174__clear_bit(src, ppc_cached_irq_mask);175__pmac_set_irq_mask(src, 1);176raw_spin_unlock_irqrestore(&pmac_pic_lock, flags);177}178179static void pmac_unmask_irq(struct irq_data *d)180{181unsigned long flags;182unsigned int src = irqd_to_hwirq(d);183184raw_spin_lock_irqsave(&pmac_pic_lock, flags);185__set_bit(src, ppc_cached_irq_mask);186__pmac_set_irq_mask(src, 0);187raw_spin_unlock_irqrestore(&pmac_pic_lock, flags);188}189190static int pmac_retrigger(struct irq_data *d)191{192unsigned long flags;193194raw_spin_lock_irqsave(&pmac_pic_lock, flags);195__pmac_retrigger(irqd_to_hwirq(d));196raw_spin_unlock_irqrestore(&pmac_pic_lock, flags);197return 1;198}199200static struct irq_chip pmac_pic = {201.name = "PMAC-PIC",202.irq_startup = pmac_startup_irq,203.irq_mask = pmac_mask_irq,204.irq_ack = pmac_ack_irq,205.irq_mask_ack = pmac_mask_and_ack_irq,206.irq_unmask = pmac_unmask_irq,207.irq_retrigger = pmac_retrigger,208};209210static irqreturn_t gatwick_action(int cpl, void *dev_id)211{212unsigned long flags;213int irq, bits;214int rc = IRQ_NONE;215216raw_spin_lock_irqsave(&pmac_pic_lock, flags);217for (irq = max_irqs; (irq -= 32) >= max_real_irqs; ) {218int i = irq >> 5;219bits = in_le32(&pmac_irq_hw[i]->event) | ppc_lost_interrupts[i];220/* We must read level interrupts from the level register */221bits |= (in_le32(&pmac_irq_hw[i]->level) & level_mask[i]);222bits &= ppc_cached_irq_mask[i];223if (bits == 0)224continue;225irq += __ilog2(bits);226raw_spin_unlock_irqrestore(&pmac_pic_lock, flags);227generic_handle_irq(irq);228raw_spin_lock_irqsave(&pmac_pic_lock, flags);229rc = IRQ_HANDLED;230}231raw_spin_unlock_irqrestore(&pmac_pic_lock, flags);232return rc;233}234235static unsigned int pmac_pic_get_irq(void)236{237int irq;238unsigned long bits = 0;239unsigned long flags;240241#ifdef CONFIG_PPC_PMAC32_PSURGE242/* IPI's are a hack on the powersurge -- Cort */243if (smp_processor_id() != 0) {244return psurge_secondary_virq;245}246#endif /* CONFIG_PPC_PMAC32_PSURGE */247raw_spin_lock_irqsave(&pmac_pic_lock, flags);248for (irq = max_real_irqs; (irq -= 32) >= 0; ) {249int i = irq >> 5;250bits = in_le32(&pmac_irq_hw[i]->event) | ppc_lost_interrupts[i];251/* We must read level interrupts from the level register */252bits |= (in_le32(&pmac_irq_hw[i]->level) & level_mask[i]);253bits &= ppc_cached_irq_mask[i];254if (bits == 0)255continue;256irq += __ilog2(bits);257break;258}259raw_spin_unlock_irqrestore(&pmac_pic_lock, flags);260if (unlikely(irq < 0))261return NO_IRQ;262return irq_linear_revmap(pmac_pic_host, irq);263}264265#ifdef CONFIG_XMON266static struct irqaction xmon_action = {267.handler = xmon_irq,268.flags = 0,269.name = "NMI - XMON"270};271#endif272273static struct irqaction gatwick_cascade_action = {274.handler = gatwick_action,275.flags = IRQF_DISABLED,276.name = "cascade",277};278279static int pmac_pic_host_match(struct irq_host *h, struct device_node *node)280{281/* We match all, we don't always have a node anyway */282return 1;283}284285static int pmac_pic_host_map(struct irq_host *h, unsigned int virq,286irq_hw_number_t hw)287{288int level;289290if (hw >= max_irqs)291return -EINVAL;292293/* Mark level interrupts, set delayed disable for edge ones and set294* handlers295*/296level = !!(level_mask[hw >> 5] & (1UL << (hw & 0x1f)));297if (level)298irq_set_status_flags(virq, IRQ_LEVEL);299irq_set_chip_and_handler(virq, &pmac_pic,300level ? handle_level_irq : handle_edge_irq);301return 0;302}303304static int pmac_pic_host_xlate(struct irq_host *h, struct device_node *ct,305const u32 *intspec, unsigned int intsize,306irq_hw_number_t *out_hwirq,307unsigned int *out_flags)308309{310*out_flags = IRQ_TYPE_NONE;311*out_hwirq = *intspec;312return 0;313}314315static struct irq_host_ops pmac_pic_host_ops = {316.match = pmac_pic_host_match,317.map = pmac_pic_host_map,318.xlate = pmac_pic_host_xlate,319};320321static void __init pmac_pic_probe_oldstyle(void)322{323int i;324struct device_node *master = NULL;325struct device_node *slave = NULL;326u8 __iomem *addr;327struct resource r;328329/* Set our get_irq function */330ppc_md.get_irq = pmac_pic_get_irq;331332/*333* Find the interrupt controller type & node334*/335336if ((master = of_find_node_by_name(NULL, "gc")) != NULL) {337max_irqs = max_real_irqs = 32;338level_mask[0] = GC_LEVEL_MASK;339} else if ((master = of_find_node_by_name(NULL, "ohare")) != NULL) {340max_irqs = max_real_irqs = 32;341level_mask[0] = OHARE_LEVEL_MASK;342343/* We might have a second cascaded ohare */344slave = of_find_node_by_name(NULL, "pci106b,7");345if (slave) {346max_irqs = 64;347level_mask[1] = OHARE_LEVEL_MASK;348}349} else if ((master = of_find_node_by_name(NULL, "mac-io")) != NULL) {350max_irqs = max_real_irqs = 64;351level_mask[0] = HEATHROW_LEVEL_MASK;352level_mask[1] = 0;353354/* We might have a second cascaded heathrow */355slave = of_find_node_by_name(master, "mac-io");356357/* Check ordering of master & slave */358if (of_device_is_compatible(master, "gatwick")) {359struct device_node *tmp;360BUG_ON(slave == NULL);361tmp = master;362master = slave;363slave = tmp;364}365366/* We found a slave */367if (slave) {368max_irqs = 128;369level_mask[2] = HEATHROW_LEVEL_MASK;370level_mask[3] = 0;371}372}373BUG_ON(master == NULL);374375/*376* Allocate an irq host377*/378pmac_pic_host = irq_alloc_host(master, IRQ_HOST_MAP_LINEAR, max_irqs,379&pmac_pic_host_ops,380max_irqs);381BUG_ON(pmac_pic_host == NULL);382irq_set_default_host(pmac_pic_host);383384/* Get addresses of first controller if we have a node for it */385BUG_ON(of_address_to_resource(master, 0, &r));386387/* Map interrupts of primary controller */388addr = (u8 __iomem *) ioremap(r.start, 0x40);389i = 0;390pmac_irq_hw[i++] = (volatile struct pmac_irq_hw __iomem *)391(addr + 0x20);392if (max_real_irqs > 32)393pmac_irq_hw[i++] = (volatile struct pmac_irq_hw __iomem *)394(addr + 0x10);395of_node_put(master);396397printk(KERN_INFO "irq: Found primary Apple PIC %s for %d irqs\n",398master->full_name, max_real_irqs);399400/* Map interrupts of cascaded controller */401if (slave && !of_address_to_resource(slave, 0, &r)) {402addr = (u8 __iomem *)ioremap(r.start, 0x40);403pmac_irq_hw[i++] = (volatile struct pmac_irq_hw __iomem *)404(addr + 0x20);405if (max_irqs > 64)406pmac_irq_hw[i++] =407(volatile struct pmac_irq_hw __iomem *)408(addr + 0x10);409pmac_irq_cascade = irq_of_parse_and_map(slave, 0);410411printk(KERN_INFO "irq: Found slave Apple PIC %s for %d irqs"412" cascade: %d\n", slave->full_name,413max_irqs - max_real_irqs, pmac_irq_cascade);414}415of_node_put(slave);416417/* Disable all interrupts in all controllers */418for (i = 0; i * 32 < max_irqs; ++i)419out_le32(&pmac_irq_hw[i]->enable, 0);420421/* Hookup cascade irq */422if (slave && pmac_irq_cascade != NO_IRQ)423setup_irq(pmac_irq_cascade, &gatwick_cascade_action);424425printk(KERN_INFO "irq: System has %d possible interrupts\n", max_irqs);426#ifdef CONFIG_XMON427setup_irq(irq_create_mapping(NULL, 20), &xmon_action);428#endif429}430431int of_irq_map_oldworld(struct device_node *device, int index,432struct of_irq *out_irq)433{434const u32 *ints = NULL;435int intlen;436437/*438* Old machines just have a list of interrupt numbers439* and no interrupt-controller nodes. We also have dodgy440* cases where the APPL,interrupts property is completely441* missing behind pci-pci bridges and we have to get it442* from the parent (the bridge itself, as apple just wired443* everything together on these)444*/445while (device) {446ints = of_get_property(device, "AAPL,interrupts", &intlen);447if (ints != NULL)448break;449device = device->parent;450if (device && strcmp(device->type, "pci") != 0)451break;452}453if (ints == NULL)454return -EINVAL;455intlen /= sizeof(u32);456457if (index >= intlen)458return -EINVAL;459460out_irq->controller = NULL;461out_irq->specifier[0] = ints[index];462out_irq->size = 1;463464return 0;465}466#endif /* CONFIG_PPC32 */467468static void pmac_u3_cascade(unsigned int irq, struct irq_desc *desc)469{470struct irq_chip *chip = irq_desc_get_chip(desc);471struct mpic *mpic = irq_desc_get_handler_data(desc);472unsigned int cascade_irq = mpic_get_one_irq(mpic);473474if (cascade_irq != NO_IRQ)475generic_handle_irq(cascade_irq);476477chip->irq_eoi(&desc->irq_data);478}479480static void __init pmac_pic_setup_mpic_nmi(struct mpic *mpic)481{482#if defined(CONFIG_XMON) && defined(CONFIG_PPC32)483struct device_node* pswitch;484int nmi_irq;485486pswitch = of_find_node_by_name(NULL, "programmer-switch");487if (pswitch) {488nmi_irq = irq_of_parse_and_map(pswitch, 0);489if (nmi_irq != NO_IRQ) {490mpic_irq_set_priority(nmi_irq, 9);491setup_irq(nmi_irq, &xmon_action);492}493of_node_put(pswitch);494}495#endif /* defined(CONFIG_XMON) && defined(CONFIG_PPC32) */496}497498static struct mpic * __init pmac_setup_one_mpic(struct device_node *np,499int master)500{501const char *name = master ? " MPIC 1 " : " MPIC 2 ";502struct resource r;503struct mpic *mpic;504unsigned int flags = master ? MPIC_PRIMARY : 0;505int rc;506507rc = of_address_to_resource(np, 0, &r);508if (rc)509return NULL;510511pmac_call_feature(PMAC_FTR_ENABLE_MPIC, np, 0, 0);512513flags |= MPIC_WANTS_RESET;514if (of_get_property(np, "big-endian", NULL))515flags |= MPIC_BIG_ENDIAN;516517/* Primary Big Endian means HT interrupts. This is quite dodgy518* but works until I find a better way519*/520if (master && (flags & MPIC_BIG_ENDIAN))521flags |= MPIC_U3_HT_IRQS;522523mpic = mpic_alloc(np, r.start, flags, 0, 0, name);524if (mpic == NULL)525return NULL;526527mpic_init(mpic);528529return mpic;530}531532static int __init pmac_pic_probe_mpic(void)533{534struct mpic *mpic1, *mpic2;535struct device_node *np, *master = NULL, *slave = NULL;536unsigned int cascade;537538/* We can have up to 2 MPICs cascaded */539for (np = NULL; (np = of_find_node_by_type(np, "open-pic"))540!= NULL;) {541if (master == NULL &&542of_get_property(np, "interrupts", NULL) == NULL)543master = of_node_get(np);544else if (slave == NULL)545slave = of_node_get(np);546if (master && slave)547break;548}549550/* Check for bogus setups */551if (master == NULL && slave != NULL) {552master = slave;553slave = NULL;554}555556/* Not found, default to good old pmac pic */557if (master == NULL)558return -ENODEV;559560/* Set master handler */561ppc_md.get_irq = mpic_get_irq;562563/* Setup master */564mpic1 = pmac_setup_one_mpic(master, 1);565BUG_ON(mpic1 == NULL);566567/* Install NMI if any */568pmac_pic_setup_mpic_nmi(mpic1);569570of_node_put(master);571572/* No slave, let's go out */573if (slave == NULL)574return 0;575576/* Get/Map slave interrupt */577cascade = irq_of_parse_and_map(slave, 0);578if (cascade == NO_IRQ) {579printk(KERN_ERR "Failed to map cascade IRQ\n");580return 0;581}582583mpic2 = pmac_setup_one_mpic(slave, 0);584if (mpic2 == NULL) {585printk(KERN_ERR "Failed to setup slave MPIC\n");586of_node_put(slave);587return 0;588}589irq_set_handler_data(cascade, mpic2);590irq_set_chained_handler(cascade, pmac_u3_cascade);591592of_node_put(slave);593return 0;594}595596597void __init pmac_pic_init(void)598{599/* We configure the OF parsing based on our oldworld vs. newworld600* platform type and wether we were booted by BootX.601*/602#ifdef CONFIG_PPC32603if (!pmac_newworld)604of_irq_workarounds |= OF_IMAP_OLDWORLD_MAC;605if (of_get_property(of_chosen, "linux,bootx", NULL) != NULL)606of_irq_workarounds |= OF_IMAP_NO_PHANDLE;607608/* If we don't have phandles on a newworld, then try to locate a609* default interrupt controller (happens when booting with BootX).610* We do a first match here, hopefully, that only ever happens on611* machines with one controller.612*/613if (pmac_newworld && (of_irq_workarounds & OF_IMAP_NO_PHANDLE)) {614struct device_node *np;615616for_each_node_with_property(np, "interrupt-controller") {617/* Skip /chosen/interrupt-controller */618if (strcmp(np->name, "chosen") == 0)619continue;620/* It seems like at least one person wants621* to use BootX on a machine with an AppleKiwi622* controller which happens to pretend to be an623* interrupt controller too. */624if (strcmp(np->name, "AppleKiwi") == 0)625continue;626/* I think we found one ! */627of_irq_dflt_pic = np;628break;629}630}631#endif /* CONFIG_PPC32 */632633/* We first try to detect Apple's new Core99 chipset, since mac-io634* is quite different on those machines and contains an IBM MPIC2.635*/636if (pmac_pic_probe_mpic() == 0)637return;638639#ifdef CONFIG_PPC32640pmac_pic_probe_oldstyle();641#endif642}643644#if defined(CONFIG_PM) && defined(CONFIG_PPC32)645/*646* These procedures are used in implementing sleep on the powerbooks.647* sleep_save_intrs() saves the states of all interrupt enables648* and disables all interrupts except for the nominated one.649* sleep_restore_intrs() restores the states of all interrupt enables.650*/651unsigned long sleep_save_mask[2];652653/* This used to be passed by the PMU driver but that link got654* broken with the new driver model. We use this tweak for now...655* We really want to do things differently though...656*/657static int pmacpic_find_viaint(void)658{659int viaint = -1;660661#ifdef CONFIG_ADB_PMU662struct device_node *np;663664if (pmu_get_model() != PMU_OHARE_BASED)665goto not_found;666np = of_find_node_by_name(NULL, "via-pmu");667if (np == NULL)668goto not_found;669viaint = irq_of_parse_and_map(np, 0);670671not_found:672#endif /* CONFIG_ADB_PMU */673return viaint;674}675676static int pmacpic_suspend(void)677{678int viaint = pmacpic_find_viaint();679680sleep_save_mask[0] = ppc_cached_irq_mask[0];681sleep_save_mask[1] = ppc_cached_irq_mask[1];682ppc_cached_irq_mask[0] = 0;683ppc_cached_irq_mask[1] = 0;684if (viaint > 0)685set_bit(viaint, ppc_cached_irq_mask);686out_le32(&pmac_irq_hw[0]->enable, ppc_cached_irq_mask[0]);687if (max_real_irqs > 32)688out_le32(&pmac_irq_hw[1]->enable, ppc_cached_irq_mask[1]);689(void)in_le32(&pmac_irq_hw[0]->event);690/* make sure mask gets to controller before we return to caller */691mb();692(void)in_le32(&pmac_irq_hw[0]->enable);693694return 0;695}696697static void pmacpic_resume(void)698{699int i;700701out_le32(&pmac_irq_hw[0]->enable, 0);702if (max_real_irqs > 32)703out_le32(&pmac_irq_hw[1]->enable, 0);704mb();705for (i = 0; i < max_real_irqs; ++i)706if (test_bit(i, sleep_save_mask))707pmac_unmask_irq(irq_get_irq_data(i));708}709710static struct syscore_ops pmacpic_syscore_ops = {711.suspend = pmacpic_suspend,712.resume = pmacpic_resume,713};714715static int __init init_pmacpic_syscore(void)716{717if (pmac_irq_hw[0])718register_syscore_ops(&pmacpic_syscore_ops);719return 0;720}721722machine_subsys_initcall(powermac, init_pmacpic_syscore);723724#endif /* CONFIG_PM && CONFIG_PPC32 */725726727