Path: blob/master/arch/powerpc/platforms/wsp/ics.c
10818 views
/*1* Copyright 2008-2011 IBM Corporation.2*3* This program is free software; you can redistribute it and/or4* modify it under the terms of the GNU General Public License5* as published by the Free Software Foundation; either version6* 2 of the License, or (at your option) any later version.7*/89#include <linux/cpu.h>10#include <linux/init.h>11#include <linux/interrupt.h>12#include <linux/irq.h>13#include <linux/kernel.h>14#include <linux/msi.h>15#include <linux/of.h>16#include <linux/slab.h>17#include <linux/smp.h>18#include <linux/spinlock.h>19#include <linux/types.h>2021#include <asm/io.h>22#include <asm/irq.h>23#include <asm/xics.h>2425#include "wsp.h"26#include "ics.h"272829/* WSP ICS */3031struct wsp_ics {32struct ics ics;33struct device_node *dn;34void __iomem *regs;35spinlock_t lock;36unsigned long *bitmap;37u32 chip_id;38u32 lsi_base;39u32 lsi_count;40u64 hwirq_start;41u64 count;42#ifdef CONFIG_SMP43int *hwirq_cpu_map;44#endif45};4647#define to_wsp_ics(ics) container_of(ics, struct wsp_ics, ics)4849#define INT_SRC_LAYER_BUID_REG(base) ((base) + 0x00)50#define IODA_TBL_ADDR_REG(base) ((base) + 0x18)51#define IODA_TBL_DATA_REG(base) ((base) + 0x20)52#define XIVE_UPDATE_REG(base) ((base) + 0x28)53#define ICS_INT_CAPS_REG(base) ((base) + 0x30)5455#define TBL_AUTO_INCREMENT ((1UL << 63) | (1UL << 15))56#define TBL_SELECT_XIST (1UL << 48)57#define TBL_SELECT_XIVT (1UL << 49)5859#define IODA_IRQ(irq) ((irq) & (0x7FFULL)) /* HRM 5.1.3.4 */6061#define XIST_REQUIRED 0x862#define XIST_REJECTED 0x463#define XIST_PRESENTED 0x264#define XIST_PENDING 0x16566#define XIVE_SERVER_SHIFT 4267#define XIVE_SERVER_MASK 0xFFFFULL68#define XIVE_PRIORITY_MASK 0xFFULL69#define XIVE_PRIORITY_SHIFT 3270#define XIVE_WRITE_ENABLE (1ULL << 63)7172/*73* The docs refer to a 6 bit field called ChipID, which consists of a74* 3 bit NodeID and a 3 bit ChipID. On WSP the ChipID is always zero75* so we ignore it, and every where we use "chip id" in this code we76* mean the NodeID.77*/78#define WSP_ICS_CHIP_SHIFT 17798081static struct wsp_ics *ics_list;82static int num_ics;8384/* ICS Source controller accessors */8586static u64 wsp_ics_get_xive(struct wsp_ics *ics, unsigned int irq)87{88unsigned long flags;89u64 xive;9091spin_lock_irqsave(&ics->lock, flags);92out_be64(IODA_TBL_ADDR_REG(ics->regs), TBL_SELECT_XIVT | IODA_IRQ(irq));93xive = in_be64(IODA_TBL_DATA_REG(ics->regs));94spin_unlock_irqrestore(&ics->lock, flags);9596return xive;97}9899static void wsp_ics_set_xive(struct wsp_ics *ics, unsigned int irq, u64 xive)100{101xive &= ~XIVE_ADDR_MASK;102xive |= (irq & XIVE_ADDR_MASK);103xive |= XIVE_WRITE_ENABLE;104105out_be64(XIVE_UPDATE_REG(ics->regs), xive);106}107108static u64 xive_set_server(u64 xive, unsigned int server)109{110u64 mask = ~(XIVE_SERVER_MASK << XIVE_SERVER_SHIFT);111112xive &= mask;113xive |= (server & XIVE_SERVER_MASK) << XIVE_SERVER_SHIFT;114115return xive;116}117118static u64 xive_set_priority(u64 xive, unsigned int priority)119{120u64 mask = ~(XIVE_PRIORITY_MASK << XIVE_PRIORITY_SHIFT);121122xive &= mask;123xive |= (priority & XIVE_PRIORITY_MASK) << XIVE_PRIORITY_SHIFT;124125return xive;126}127128129#ifdef CONFIG_SMP130/* Find logical CPUs within mask on a given chip and store result in ret */131void cpus_on_chip(int chip_id, cpumask_t *mask, cpumask_t *ret)132{133int cpu, chip;134struct device_node *cpu_dn, *dn;135const u32 *prop;136137cpumask_clear(ret);138for_each_cpu(cpu, mask) {139cpu_dn = of_get_cpu_node(cpu, NULL);140if (!cpu_dn)141continue;142143prop = of_get_property(cpu_dn, "at-node", NULL);144if (!prop) {145of_node_put(cpu_dn);146continue;147}148149dn = of_find_node_by_phandle(*prop);150of_node_put(cpu_dn);151152chip = wsp_get_chip_id(dn);153if (chip == chip_id)154cpumask_set_cpu(cpu, ret);155156of_node_put(dn);157}158}159160/* Store a suitable CPU to handle a hwirq in the ics->hwirq_cpu_map cache */161static int cache_hwirq_map(struct wsp_ics *ics, unsigned int hwirq,162const cpumask_t *affinity)163{164cpumask_var_t avail, newmask;165int ret = -ENOMEM, cpu, cpu_rover = 0, target;166int index = hwirq - ics->hwirq_start;167unsigned int nodeid;168169BUG_ON(index < 0 || index >= ics->count);170171if (!ics->hwirq_cpu_map)172return -ENOMEM;173174if (!distribute_irqs) {175ics->hwirq_cpu_map[hwirq - ics->hwirq_start] = xics_default_server;176return 0;177}178179/* Allocate needed CPU masks */180if (!alloc_cpumask_var(&avail, GFP_KERNEL))181goto ret;182if (!alloc_cpumask_var(&newmask, GFP_KERNEL))183goto freeavail;184185/* Find PBus attached to the source of this IRQ */186nodeid = (hwirq >> WSP_ICS_CHIP_SHIFT) & 0x3; /* 12:14 */187188/* Find CPUs that could handle this IRQ */189if (affinity)190cpumask_and(avail, cpu_online_mask, affinity);191else192cpumask_copy(avail, cpu_online_mask);193194/* Narrow selection down to logical CPUs on the same chip */195cpus_on_chip(nodeid, avail, newmask);196197/* Ensure we haven't narrowed it down to 0 */198if (unlikely(cpumask_empty(newmask))) {199if (unlikely(cpumask_empty(avail))) {200ret = -1;201goto out;202}203cpumask_copy(newmask, avail);204}205206/* Choose a CPU out of those we narrowed it down to in round robin */207target = hwirq % cpumask_weight(newmask);208for_each_cpu(cpu, newmask) {209if (cpu_rover++ >= target) {210ics->hwirq_cpu_map[index] = get_hard_smp_processor_id(cpu);211ret = 0;212goto out;213}214}215216/* Shouldn't happen */217WARN_ON(1);218219out:220free_cpumask_var(newmask);221freeavail:222free_cpumask_var(avail);223ret:224if (ret < 0) {225ics->hwirq_cpu_map[index] = cpumask_first(cpu_online_mask);226pr_warning("Error, falling hwirq 0x%x routing back to CPU %i\n",227hwirq, ics->hwirq_cpu_map[index]);228}229return ret;230}231232static void alloc_irq_map(struct wsp_ics *ics)233{234int i;235236ics->hwirq_cpu_map = kmalloc(sizeof(int) * ics->count, GFP_KERNEL);237if (!ics->hwirq_cpu_map) {238pr_warning("Allocate hwirq_cpu_map failed, "239"IRQ balancing disabled\n");240return;241}242243for (i=0; i < ics->count; i++)244ics->hwirq_cpu_map[i] = xics_default_server;245}246247static int get_irq_server(struct wsp_ics *ics, unsigned int hwirq)248{249int index = hwirq - ics->hwirq_start;250251BUG_ON(index < 0 || index >= ics->count);252253if (!ics->hwirq_cpu_map)254return xics_default_server;255256return ics->hwirq_cpu_map[index];257}258#else /* !CONFIG_SMP */259static int cache_hwirq_map(struct wsp_ics *ics, unsigned int hwirq,260const cpumask_t *affinity)261{262return 0;263}264265static int get_irq_server(struct wsp_ics *ics, unsigned int hwirq)266{267return xics_default_server;268}269270static void alloc_irq_map(struct wsp_ics *ics) { }271#endif272273static void wsp_chip_unmask_irq(struct irq_data *d)274{275unsigned int hw_irq = (unsigned int)irqd_to_hwirq(d);276struct wsp_ics *ics;277int server;278u64 xive;279280if (hw_irq == XICS_IPI || hw_irq == XICS_IRQ_SPURIOUS)281return;282283ics = d->chip_data;284if (WARN_ON(!ics))285return;286287server = get_irq_server(ics, hw_irq);288289xive = wsp_ics_get_xive(ics, hw_irq);290xive = xive_set_server(xive, server);291xive = xive_set_priority(xive, DEFAULT_PRIORITY);292wsp_ics_set_xive(ics, hw_irq, xive);293}294295static unsigned int wsp_chip_startup(struct irq_data *d)296{297/* unmask it */298wsp_chip_unmask_irq(d);299return 0;300}301302static void wsp_mask_real_irq(unsigned int hw_irq, struct wsp_ics *ics)303{304u64 xive;305306if (hw_irq == XICS_IPI)307return;308309if (WARN_ON(!ics))310return;311xive = wsp_ics_get_xive(ics, hw_irq);312xive = xive_set_server(xive, xics_default_server);313xive = xive_set_priority(xive, LOWEST_PRIORITY);314wsp_ics_set_xive(ics, hw_irq, xive);315}316317static void wsp_chip_mask_irq(struct irq_data *d)318{319unsigned int hw_irq = (unsigned int)irqd_to_hwirq(d);320struct wsp_ics *ics = d->chip_data;321322if (hw_irq == XICS_IPI || hw_irq == XICS_IRQ_SPURIOUS)323return;324325wsp_mask_real_irq(hw_irq, ics);326}327328static int wsp_chip_set_affinity(struct irq_data *d,329const struct cpumask *cpumask, bool force)330{331unsigned int hw_irq = (unsigned int)irqd_to_hwirq(d);332struct wsp_ics *ics;333int ret;334u64 xive;335336if (hw_irq == XICS_IPI || hw_irq == XICS_IRQ_SPURIOUS)337return -1;338339ics = d->chip_data;340if (WARN_ON(!ics))341return -1;342xive = wsp_ics_get_xive(ics, hw_irq);343344/*345* For the moment only implement delivery to all cpus or one cpu.346* Get current irq_server for the given irq347*/348ret = cache_hwirq_map(ics, d->irq, cpumask);349if (ret == -1) {350char cpulist[128];351cpumask_scnprintf(cpulist, sizeof(cpulist), cpumask);352pr_warning("%s: No online cpus in the mask %s for irq %d\n",353__func__, cpulist, d->irq);354return -1;355} else if (ret == -ENOMEM) {356pr_warning("%s: Out of memory\n", __func__);357return -1;358}359360xive = xive_set_server(xive, get_irq_server(ics, hw_irq));361wsp_ics_set_xive(ics, hw_irq, xive);362363return 0;364}365366static struct irq_chip wsp_irq_chip = {367.name = "WSP ICS",368.irq_startup = wsp_chip_startup,369.irq_mask = wsp_chip_mask_irq,370.irq_unmask = wsp_chip_unmask_irq,371.irq_set_affinity = wsp_chip_set_affinity372};373374static int wsp_ics_host_match(struct ics *ics, struct device_node *dn)375{376/* All ICSs in the system implement a global irq number space,377* so match against them all. */378return of_device_is_compatible(dn, "ibm,ppc-xics");379}380381static int wsp_ics_match_hwirq(struct wsp_ics *wsp_ics, unsigned int hwirq)382{383if (hwirq >= wsp_ics->hwirq_start &&384hwirq < wsp_ics->hwirq_start + wsp_ics->count)385return 1;386387return 0;388}389390static int wsp_ics_map(struct ics *ics, unsigned int virq)391{392struct wsp_ics *wsp_ics = to_wsp_ics(ics);393unsigned int hw_irq = virq_to_hw(virq);394unsigned long flags;395396if (!wsp_ics_match_hwirq(wsp_ics, hw_irq))397return -ENOENT;398399irq_set_chip_and_handler(virq, &wsp_irq_chip, handle_fasteoi_irq);400401irq_set_chip_data(virq, wsp_ics);402403spin_lock_irqsave(&wsp_ics->lock, flags);404bitmap_allocate_region(wsp_ics->bitmap, hw_irq - wsp_ics->hwirq_start, 0);405spin_unlock_irqrestore(&wsp_ics->lock, flags);406407return 0;408}409410static void wsp_ics_mask_unknown(struct ics *ics, unsigned long hw_irq)411{412struct wsp_ics *wsp_ics = to_wsp_ics(ics);413414if (!wsp_ics_match_hwirq(wsp_ics, hw_irq))415return;416417pr_err("%s: IRQ %lu (real) is invalid, disabling it.\n", __func__, hw_irq);418wsp_mask_real_irq(hw_irq, wsp_ics);419}420421static long wsp_ics_get_server(struct ics *ics, unsigned long hw_irq)422{423struct wsp_ics *wsp_ics = to_wsp_ics(ics);424425if (!wsp_ics_match_hwirq(wsp_ics, hw_irq))426return -ENOENT;427428return get_irq_server(wsp_ics, hw_irq);429}430431/* HW Number allocation API */432433static struct wsp_ics *wsp_ics_find_dn_ics(struct device_node *dn)434{435struct device_node *iparent;436int i;437438iparent = of_irq_find_parent(dn);439if (!iparent) {440pr_err("wsp_ics: Failed to find interrupt parent!\n");441return NULL;442}443444for(i = 0; i < num_ics; i++) {445if(ics_list[i].dn == iparent)446break;447}448449if (i >= num_ics) {450pr_err("wsp_ics: Unable to find parent bitmap!\n");451return NULL;452}453454return &ics_list[i];455}456457int wsp_ics_alloc_irq(struct device_node *dn, int num)458{459struct wsp_ics *ics;460int order, offset;461462ics = wsp_ics_find_dn_ics(dn);463if (!ics)464return -ENODEV;465466/* Fast, but overly strict if num isn't a power of two */467order = get_count_order(num);468469spin_lock_irq(&ics->lock);470offset = bitmap_find_free_region(ics->bitmap, ics->count, order);471spin_unlock_irq(&ics->lock);472473if (offset < 0)474return offset;475476return offset + ics->hwirq_start;477}478479void wsp_ics_free_irq(struct device_node *dn, unsigned int irq)480{481struct wsp_ics *ics;482483ics = wsp_ics_find_dn_ics(dn);484if (WARN_ON(!ics))485return;486487spin_lock_irq(&ics->lock);488bitmap_release_region(ics->bitmap, irq, 0);489spin_unlock_irq(&ics->lock);490}491492/* Initialisation */493494static int __init wsp_ics_bitmap_setup(struct wsp_ics *ics,495struct device_node *dn)496{497int len, i, j, size;498u32 start, count;499const u32 *p;500501size = BITS_TO_LONGS(ics->count) * sizeof(long);502ics->bitmap = kzalloc(size, GFP_KERNEL);503if (!ics->bitmap) {504pr_err("wsp_ics: ENOMEM allocating IRQ bitmap!\n");505return -ENOMEM;506}507508spin_lock_init(&ics->lock);509510p = of_get_property(dn, "available-ranges", &len);511if (!p || !len) {512/* FIXME this should be a WARN() once mambo is updated */513pr_err("wsp_ics: No available-ranges defined for %s\n",514dn->full_name);515return 0;516}517518if (len % (2 * sizeof(u32)) != 0) {519/* FIXME this should be a WARN() once mambo is updated */520pr_err("wsp_ics: Invalid available-ranges for %s\n",521dn->full_name);522return 0;523}524525bitmap_fill(ics->bitmap, ics->count);526527for (i = 0; i < len / sizeof(u32); i += 2) {528start = of_read_number(p + i, 1);529count = of_read_number(p + i + 1, 1);530531pr_devel("%s: start: %d count: %d\n", __func__, start, count);532533if ((start + count) > (ics->hwirq_start + ics->count) ||534start < ics->hwirq_start) {535pr_err("wsp_ics: Invalid range! -> %d to %d\n",536start, start + count);537break;538}539540for (j = 0; j < count; j++)541bitmap_release_region(ics->bitmap,542(start + j) - ics->hwirq_start, 0);543}544545/* Ensure LSIs are not available for allocation */546bitmap_allocate_region(ics->bitmap, ics->lsi_base,547get_count_order(ics->lsi_count));548549return 0;550}551552static int __init wsp_ics_setup(struct wsp_ics *ics, struct device_node *dn)553{554u32 lsi_buid, msi_buid, msi_base, msi_count;555void __iomem *regs;556const u32 *p;557int rc, len, i;558u64 caps, buid;559560p = of_get_property(dn, "interrupt-ranges", &len);561if (!p || len < (2 * sizeof(u32))) {562pr_err("wsp_ics: No/bad interrupt-ranges found on %s\n",563dn->full_name);564return -ENOENT;565}566567if (len > (2 * sizeof(u32))) {568pr_err("wsp_ics: Multiple ics ranges not supported.\n");569return -EINVAL;570}571572regs = of_iomap(dn, 0);573if (!regs) {574pr_err("wsp_ics: of_iomap(%s) failed\n", dn->full_name);575return -ENXIO;576}577578ics->hwirq_start = of_read_number(p, 1);579ics->count = of_read_number(p + 1, 1);580ics->regs = regs;581582ics->chip_id = wsp_get_chip_id(dn);583if (WARN_ON(ics->chip_id < 0))584ics->chip_id = 0;585586/* Get some informations about the critter */587caps = in_be64(ICS_INT_CAPS_REG(ics->regs));588buid = in_be64(INT_SRC_LAYER_BUID_REG(ics->regs));589ics->lsi_count = caps >> 56;590msi_count = (caps >> 44) & 0x7ff;591592/* Note: LSI BUID is 9 bits, but really only 3 are BUID and the593* rest is mixed in the interrupt number. We store the whole594* thing though595*/596lsi_buid = (buid >> 48) & 0x1ff;597ics->lsi_base = (ics->chip_id << WSP_ICS_CHIP_SHIFT) | lsi_buid << 5;598msi_buid = (buid >> 37) & 0x7;599msi_base = (ics->chip_id << WSP_ICS_CHIP_SHIFT) | msi_buid << 11;600601pr_info("wsp_ics: Found %s\n", dn->full_name);602pr_info("wsp_ics: irq range : 0x%06llx..0x%06llx\n",603ics->hwirq_start, ics->hwirq_start + ics->count - 1);604pr_info("wsp_ics: %4d LSIs : 0x%06x..0x%06x\n",605ics->lsi_count, ics->lsi_base,606ics->lsi_base + ics->lsi_count - 1);607pr_info("wsp_ics: %4d MSIs : 0x%06x..0x%06x\n",608msi_count, msi_base,609msi_base + msi_count - 1);610611/* Let's check the HW config is sane */612if (ics->lsi_base < ics->hwirq_start ||613(ics->lsi_base + ics->lsi_count) > (ics->hwirq_start + ics->count))614pr_warning("wsp_ics: WARNING ! LSIs out of interrupt-ranges !\n");615if (msi_base < ics->hwirq_start ||616(msi_base + msi_count) > (ics->hwirq_start + ics->count))617pr_warning("wsp_ics: WARNING ! MSIs out of interrupt-ranges !\n");618619/* We don't check for overlap between LSI and MSI, which will happen620* if we use the same BUID, I'm not sure yet how legit that is.621*/622623rc = wsp_ics_bitmap_setup(ics, dn);624if (rc) {625iounmap(regs);626return rc;627}628629ics->dn = of_node_get(dn);630alloc_irq_map(ics);631632for(i = 0; i < ics->count; i++)633wsp_mask_real_irq(ics->hwirq_start + i, ics);634635ics->ics.map = wsp_ics_map;636ics->ics.mask_unknown = wsp_ics_mask_unknown;637ics->ics.get_server = wsp_ics_get_server;638ics->ics.host_match = wsp_ics_host_match;639640xics_register_ics(&ics->ics);641642return 0;643}644645static void __init wsp_ics_set_default_server(void)646{647struct device_node *np;648u32 hwid;649650/* Find the server number for the boot cpu. */651np = of_get_cpu_node(boot_cpuid, NULL);652BUG_ON(!np);653654hwid = get_hard_smp_processor_id(boot_cpuid);655656pr_info("wsp_ics: default server is %#x, CPU %s\n", hwid, np->full_name);657xics_default_server = hwid;658659of_node_put(np);660}661662static int __init wsp_ics_init(void)663{664struct device_node *dn;665struct wsp_ics *ics;666int rc, found;667668wsp_ics_set_default_server();669670found = 0;671for_each_compatible_node(dn, NULL, "ibm,ppc-xics")672found++;673674if (found == 0) {675pr_err("wsp_ics: No ICS's found!\n");676return -ENODEV;677}678679ics_list = kmalloc(sizeof(*ics) * found, GFP_KERNEL);680if (!ics_list) {681pr_err("wsp_ics: No memory for structs.\n");682return -ENOMEM;683}684685num_ics = 0;686ics = ics_list;687for_each_compatible_node(dn, NULL, "ibm,wsp-xics") {688rc = wsp_ics_setup(ics, dn);689if (rc == 0) {690ics++;691num_ics++;692}693}694695if (found != num_ics) {696pr_err("wsp_ics: Failed setting up %d ICS's\n",697found - num_ics);698return -1;699}700701return 0;702}703704void __init wsp_init_irq(void)705{706wsp_ics_init();707xics_init();708709/* We need to patch our irq chip's EOI to point to the right ICP */710wsp_irq_chip.irq_eoi = icp_ops->eoi;711}712713714