2017-04-05 07:54:50 +00:00
|
|
|
/*
|
|
|
|
* Copyright 2016,2017 IBM Corporation.
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version
|
|
|
|
* 2 of the License, or (at your option) any later version.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define pr_fmt(fmt) "xive: " fmt
|
|
|
|
|
|
|
|
#include <linux/types.h>
|
|
|
|
#include <linux/threads.h>
|
|
|
|
#include <linux/kernel.h>
|
|
|
|
#include <linux/irq.h>
|
|
|
|
#include <linux/debugfs.h>
|
|
|
|
#include <linux/smp.h>
|
|
|
|
#include <linux/interrupt.h>
|
|
|
|
#include <linux/seq_file.h>
|
|
|
|
#include <linux/init.h>
|
|
|
|
#include <linux/cpu.h>
|
|
|
|
#include <linux/of.h>
|
|
|
|
#include <linux/slab.h>
|
|
|
|
#include <linux/spinlock.h>
|
|
|
|
#include <linux/msi.h>
|
|
|
|
|
|
|
|
#include <asm/prom.h>
|
|
|
|
#include <asm/io.h>
|
|
|
|
#include <asm/smp.h>
|
|
|
|
#include <asm/machdep.h>
|
|
|
|
#include <asm/irq.h>
|
|
|
|
#include <asm/errno.h>
|
|
|
|
#include <asm/xive.h>
|
|
|
|
#include <asm/xive-regs.h>
|
|
|
|
#include <asm/xmon.h>
|
|
|
|
|
|
|
|
#include "xive-internal.h"
|
|
|
|
|
|
|
|
#undef DEBUG_FLUSH
|
|
|
|
#undef DEBUG_ALL
|
|
|
|
|
|
|
|
#ifdef DEBUG_ALL
|
2017-08-30 19:46:17 +00:00
|
|
|
#define DBG_VERBOSE(fmt, ...) pr_devel("cpu %d - " fmt, \
|
|
|
|
smp_processor_id(), ## __VA_ARGS__)
|
2017-04-05 07:54:50 +00:00
|
|
|
#else
|
|
|
|
#define DBG_VERBOSE(fmt...) do { } while(0)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
bool __xive_enabled;
|
2017-04-05 07:54:56 +00:00
|
|
|
EXPORT_SYMBOL_GPL(__xive_enabled);
|
2017-04-05 07:54:50 +00:00
|
|
|
bool xive_cmdline_disabled;
|
|
|
|
|
|
|
|
/* We use only one priority for now */
|
|
|
|
static u8 xive_irq_priority;
|
|
|
|
|
2017-04-05 07:54:56 +00:00
|
|
|
/* TIMA exported to KVM */
|
2017-04-05 07:54:50 +00:00
|
|
|
void __iomem *xive_tima;
|
2017-04-05 07:54:56 +00:00
|
|
|
EXPORT_SYMBOL_GPL(xive_tima);
|
2017-04-05 07:54:50 +00:00
|
|
|
u32 xive_tima_offset;
|
|
|
|
|
|
|
|
/* Backend ops */
|
|
|
|
static const struct xive_ops *xive_ops;
|
|
|
|
|
|
|
|
/* Our global interrupt domain */
|
|
|
|
static struct irq_domain *xive_irq_domain;
|
|
|
|
|
|
|
|
#ifdef CONFIG_SMP
|
|
|
|
/* The IPIs all use the same logical irq number */
|
|
|
|
static u32 xive_ipi_irq;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Xive state for each CPU */
|
|
|
|
static DEFINE_PER_CPU(struct xive_cpu *, xive_cpu);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* A "disabled" interrupt should never fire, to catch problems
|
|
|
|
* we set its logical number to this
|
|
|
|
*/
|
|
|
|
#define XIVE_BAD_IRQ 0x7fffffff
|
|
|
|
#define XIVE_MAX_IRQ (XIVE_BAD_IRQ - 1)
|
|
|
|
|
|
|
|
/* An invalid CPU target */
|
|
|
|
#define XIVE_INVALID_TARGET (-1)
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Read the next entry in a queue, return its content if it's valid
|
|
|
|
* or 0 if there is no new entry.
|
|
|
|
*
|
|
|
|
* The queue pointer is moved forward unless "just_peek" is set
|
|
|
|
*/
|
|
|
|
static u32 xive_read_eq(struct xive_q *q, bool just_peek)
|
|
|
|
{
|
|
|
|
u32 cur;
|
|
|
|
|
|
|
|
if (!q->qpage)
|
|
|
|
return 0;
|
|
|
|
cur = be32_to_cpup(q->qpage + q->idx);
|
|
|
|
|
|
|
|
/* Check valid bit (31) vs current toggle polarity */
|
|
|
|
if ((cur >> 31) == q->toggle)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* If consuming from the queue ... */
|
|
|
|
if (!just_peek) {
|
|
|
|
/* Next entry */
|
|
|
|
q->idx = (q->idx + 1) & q->msk;
|
|
|
|
|
|
|
|
/* Wrap around: flip valid toggle */
|
|
|
|
if (q->idx == 0)
|
|
|
|
q->toggle ^= 1;
|
|
|
|
}
|
|
|
|
/* Mask out the valid bit (31) */
|
|
|
|
return cur & 0x7fffffff;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Scans all the queue that may have interrupts in them
|
|
|
|
* (based on "pending_prio") in priority order until an
|
|
|
|
* interrupt is found or all the queues are empty.
|
|
|
|
*
|
|
|
|
* Then updates the CPPR (Current Processor Priority
|
|
|
|
* Register) based on the most favored interrupt found
|
|
|
|
* (0xff if none) and return what was found (0 if none).
|
|
|
|
*
|
|
|
|
* If just_peek is set, return the most favored pending
|
|
|
|
* interrupt if any but don't update the queue pointers.
|
|
|
|
*
|
|
|
|
* Note: This function can operate generically on any number
|
|
|
|
* of queues (up to 8). The current implementation of the XIVE
|
|
|
|
* driver only uses a single queue however.
|
|
|
|
*
|
|
|
|
* Note2: This will also "flush" "the pending_count" of a queue
|
|
|
|
* into the "count" when that queue is observed to be empty.
|
|
|
|
* This is used to keep track of the amount of interrupts
|
|
|
|
* targetting a queue. When an interrupt is moved away from
|
|
|
|
* a queue, we only decrement that queue count once the queue
|
|
|
|
* has been observed empty to avoid races.
|
|
|
|
*/
|
|
|
|
static u32 xive_scan_interrupts(struct xive_cpu *xc, bool just_peek)
|
|
|
|
{
|
|
|
|
u32 irq = 0;
|
|
|
|
u8 prio;
|
|
|
|
|
|
|
|
/* Find highest pending priority */
|
|
|
|
while (xc->pending_prio != 0) {
|
|
|
|
struct xive_q *q;
|
|
|
|
|
|
|
|
prio = ffs(xc->pending_prio) - 1;
|
|
|
|
DBG_VERBOSE("scan_irq: trying prio %d\n", prio);
|
|
|
|
|
|
|
|
/* Try to fetch */
|
|
|
|
irq = xive_read_eq(&xc->queue[prio], just_peek);
|
|
|
|
|
|
|
|
/* Found something ? That's it */
|
|
|
|
if (irq)
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* Clear pending bits */
|
|
|
|
xc->pending_prio &= ~(1 << prio);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check if the queue count needs adjusting due to
|
|
|
|
* interrupts being moved away. See description of
|
|
|
|
* xive_dec_target_count()
|
|
|
|
*/
|
|
|
|
q = &xc->queue[prio];
|
|
|
|
if (atomic_read(&q->pending_count)) {
|
|
|
|
int p = atomic_xchg(&q->pending_count, 0);
|
|
|
|
if (p) {
|
|
|
|
WARN_ON(p > atomic_read(&q->count));
|
|
|
|
atomic_sub(p, &q->count);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If nothing was found, set CPPR to 0xff */
|
|
|
|
if (irq == 0)
|
|
|
|
prio = 0xff;
|
|
|
|
|
|
|
|
/* Update HW CPPR to match if necessary */
|
|
|
|
if (prio != xc->cppr) {
|
|
|
|
DBG_VERBOSE("scan_irq: adjusting CPPR to %d\n", prio);
|
|
|
|
xc->cppr = prio;
|
|
|
|
out_8(xive_tima + xive_tima_offset + TM_CPPR, prio);
|
|
|
|
}
|
|
|
|
|
|
|
|
return irq;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This is used to perform the magic loads from an ESB
|
|
|
|
* described in xive.h
|
|
|
|
*/
|
2017-08-30 19:46:12 +00:00
|
|
|
static notrace u8 xive_esb_read(struct xive_irq_data *xd, u32 offset)
|
2017-04-05 07:54:50 +00:00
|
|
|
{
|
|
|
|
u64 val;
|
|
|
|
|
|
|
|
/* Handle HW errata */
|
|
|
|
if (xd->flags & XIVE_IRQ_FLAG_SHIFT_BUG)
|
|
|
|
offset |= offset << 4;
|
|
|
|
|
2017-08-30 19:46:15 +00:00
|
|
|
if ((xd->flags & XIVE_IRQ_FLAG_H_INT_ESB) && xive_ops->esb_rw)
|
|
|
|
val = xive_ops->esb_rw(xd->hw_irq, offset, 0, 0);
|
|
|
|
else
|
|
|
|
val = in_be64(xd->eoi_mmio + offset);
|
2017-04-05 07:54:50 +00:00
|
|
|
|
|
|
|
return (u8)val;
|
|
|
|
}
|
|
|
|
|
2017-08-30 19:46:13 +00:00
|
|
|
static void xive_esb_write(struct xive_irq_data *xd, u32 offset, u64 data)
|
|
|
|
{
|
|
|
|
/* Handle HW errata */
|
|
|
|
if (xd->flags & XIVE_IRQ_FLAG_SHIFT_BUG)
|
|
|
|
offset |= offset << 4;
|
|
|
|
|
2017-08-30 19:46:15 +00:00
|
|
|
if ((xd->flags & XIVE_IRQ_FLAG_H_INT_ESB) && xive_ops->esb_rw)
|
|
|
|
xive_ops->esb_rw(xd->hw_irq, offset, data, 1);
|
|
|
|
else
|
|
|
|
out_be64(xd->eoi_mmio + offset, data);
|
2017-08-30 19:46:13 +00:00
|
|
|
}
|
|
|
|
|
2017-04-05 07:54:50 +00:00
|
|
|
#ifdef CONFIG_XMON
|
2017-08-02 18:25:38 +00:00
|
|
|
static notrace void xive_dump_eq(const char *name, struct xive_q *q)
|
2017-04-05 07:54:50 +00:00
|
|
|
{
|
|
|
|
u32 i0, i1, idx;
|
|
|
|
|
|
|
|
if (!q->qpage)
|
|
|
|
return;
|
|
|
|
idx = q->idx;
|
|
|
|
i0 = be32_to_cpup(q->qpage + idx);
|
|
|
|
idx = (idx + 1) & q->msk;
|
|
|
|
i1 = be32_to_cpup(q->qpage + idx);
|
|
|
|
xmon_printf(" %s Q T=%d %08x %08x ...\n", name,
|
|
|
|
q->toggle, i0, i1);
|
|
|
|
}
|
|
|
|
|
2017-08-02 18:25:38 +00:00
|
|
|
notrace void xmon_xive_do_dump(int cpu)
|
2017-04-05 07:54:50 +00:00
|
|
|
{
|
|
|
|
struct xive_cpu *xc = per_cpu(xive_cpu, cpu);
|
|
|
|
|
|
|
|
xmon_printf("XIVE state for CPU %d:\n", cpu);
|
|
|
|
xmon_printf(" pp=%02x cppr=%02x\n", xc->pending_prio, xc->cppr);
|
|
|
|
xive_dump_eq("IRQ", &xc->queue[xive_irq_priority]);
|
|
|
|
#ifdef CONFIG_SMP
|
|
|
|
{
|
2017-08-30 19:46:12 +00:00
|
|
|
u64 val = xive_esb_read(&xc->ipi_data, XIVE_ESB_GET);
|
2017-04-05 07:54:50 +00:00
|
|
|
xmon_printf(" IPI state: %x:%c%c\n", xc->hw_ipi,
|
|
|
|
val & XIVE_ESB_VAL_P ? 'P' : 'p',
|
|
|
|
val & XIVE_ESB_VAL_P ? 'Q' : 'q');
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_XMON */
|
|
|
|
|
|
|
|
static unsigned int xive_get_irq(void)
|
|
|
|
{
|
|
|
|
struct xive_cpu *xc = __this_cpu_read(xive_cpu);
|
|
|
|
u32 irq;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This can be called either as a result of a HW interrupt or
|
|
|
|
* as a "replay" because EOI decided there was still something
|
|
|
|
* in one of the queues.
|
|
|
|
*
|
|
|
|
* First we perform an ACK cycle in order to update our mask
|
|
|
|
* of pending priorities. This will also have the effect of
|
|
|
|
* updating the CPPR to the most favored pending interrupts.
|
|
|
|
*
|
|
|
|
* In the future, if we have a way to differenciate a first
|
|
|
|
* entry (on HW interrupt) from a replay triggered by EOI,
|
|
|
|
* we could skip this on replays unless we soft-mask tells us
|
|
|
|
* that a new HW interrupt occurred.
|
|
|
|
*/
|
|
|
|
xive_ops->update_pending(xc);
|
|
|
|
|
|
|
|
DBG_VERBOSE("get_irq: pending=%02x\n", xc->pending_prio);
|
|
|
|
|
|
|
|
/* Scan our queue(s) for interrupts */
|
|
|
|
irq = xive_scan_interrupts(xc, false);
|
|
|
|
|
|
|
|
DBG_VERBOSE("get_irq: got irq 0x%x, new pending=0x%02x\n",
|
|
|
|
irq, xc->pending_prio);
|
|
|
|
|
|
|
|
/* Return pending interrupt if any */
|
|
|
|
if (irq == XIVE_BAD_IRQ)
|
|
|
|
return 0;
|
|
|
|
return irq;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* After EOI'ing an interrupt, we need to re-check the queue
|
|
|
|
* to see if another interrupt is pending since multiple
|
|
|
|
* interrupts can coalesce into a single notification to the
|
|
|
|
* CPU.
|
|
|
|
*
|
|
|
|
* If we find that there is indeed more in there, we call
|
|
|
|
* force_external_irq_replay() to make Linux synthetize an
|
|
|
|
* external interrupt on the next call to local_irq_restore().
|
|
|
|
*/
|
|
|
|
static void xive_do_queue_eoi(struct xive_cpu *xc)
|
|
|
|
{
|
|
|
|
if (xive_scan_interrupts(xc, true) != 0) {
|
|
|
|
DBG_VERBOSE("eoi: pending=0x%02x\n", xc->pending_prio);
|
|
|
|
force_external_irq_replay();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* EOI an interrupt at the source. There are several methods
|
|
|
|
* to do this depending on the HW version and source type
|
|
|
|
*/
|
|
|
|
void xive_do_source_eoi(u32 hw_irq, struct xive_irq_data *xd)
|
|
|
|
{
|
|
|
|
/* If the XIVE supports the new "store EOI facility, use it */
|
|
|
|
if (xd->flags & XIVE_IRQ_FLAG_STORE_EOI)
|
2017-08-30 19:46:13 +00:00
|
|
|
xive_esb_write(xd, XIVE_ESB_STORE_EOI, 0);
|
2017-04-05 07:54:50 +00:00
|
|
|
else if (hw_irq && xd->flags & XIVE_IRQ_FLAG_EOI_FW) {
|
|
|
|
/*
|
|
|
|
* The FW told us to call it. This happens for some
|
|
|
|
* interrupt sources that need additional HW whacking
|
|
|
|
* beyond the ESB manipulation. For example LPC interrupts
|
|
|
|
* on P9 DD1.0 need a latch to be clared in the LPC bridge
|
|
|
|
* itself. The Firmware will take care of it.
|
|
|
|
*/
|
|
|
|
if (WARN_ON_ONCE(!xive_ops->eoi))
|
|
|
|
return;
|
|
|
|
xive_ops->eoi(hw_irq);
|
|
|
|
} else {
|
|
|
|
u8 eoi_val;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Otherwise for EOI, we use the special MMIO that does
|
|
|
|
* a clear of both P and Q and returns the old Q,
|
|
|
|
* except for LSIs where we use the "EOI cycle" special
|
|
|
|
* load.
|
|
|
|
*
|
|
|
|
* This allows us to then do a re-trigger if Q was set
|
|
|
|
* rather than synthesizing an interrupt in software
|
|
|
|
*
|
|
|
|
* For LSIs, using the HW EOI cycle works around a problem
|
|
|
|
* on P9 DD1 PHBs where the other ESB accesses don't work
|
|
|
|
* properly.
|
|
|
|
*/
|
|
|
|
if (xd->flags & XIVE_IRQ_FLAG_LSI)
|
2017-08-30 19:46:12 +00:00
|
|
|
xive_esb_read(xd, XIVE_ESB_LOAD_EOI);
|
2017-04-05 07:54:50 +00:00
|
|
|
else {
|
2017-08-30 19:46:12 +00:00
|
|
|
eoi_val = xive_esb_read(xd, XIVE_ESB_SET_PQ_00);
|
2017-08-30 19:46:17 +00:00
|
|
|
DBG_VERBOSE("eoi_val=%x\n", eoi_val);
|
2017-04-05 07:54:50 +00:00
|
|
|
|
|
|
|
/* Re-trigger if needed */
|
|
|
|
if ((eoi_val & XIVE_ESB_VAL_Q) && xd->trig_mmio)
|
|
|
|
out_be64(xd->trig_mmio, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* irq_chip eoi callback */
|
|
|
|
static void xive_irq_eoi(struct irq_data *d)
|
|
|
|
{
|
|
|
|
struct xive_irq_data *xd = irq_data_get_irq_handler_data(d);
|
|
|
|
struct xive_cpu *xc = __this_cpu_read(xive_cpu);
|
|
|
|
|
|
|
|
DBG_VERBOSE("eoi_irq: irq=%d [0x%lx] pending=%02x\n",
|
|
|
|
d->irq, irqd_to_hwirq(d), xc->pending_prio);
|
|
|
|
|
2017-04-05 07:54:56 +00:00
|
|
|
/*
|
|
|
|
* EOI the source if it hasn't been disabled and hasn't
|
|
|
|
* been passed-through to a KVM guest
|
|
|
|
*/
|
2018-01-12 02:39:28 +00:00
|
|
|
if (!irqd_irq_disabled(d) && !irqd_is_forwarded_to_vcpu(d) &&
|
|
|
|
!(xd->flags & XIVE_IRQ_NO_EOI))
|
2017-04-05 07:54:50 +00:00
|
|
|
xive_do_source_eoi(irqd_to_hwirq(d), xd);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Clear saved_p to indicate that it's no longer occupying
|
|
|
|
* a queue slot on the target queue
|
|
|
|
*/
|
|
|
|
xd->saved_p = false;
|
|
|
|
|
|
|
|
/* Check for more work in the queue */
|
|
|
|
xive_do_queue_eoi(xc);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Helper used to mask and unmask an interrupt source. This
|
|
|
|
* is only called for normal interrupts that do not require
|
|
|
|
* masking/unmasking via firmware.
|
|
|
|
*/
|
|
|
|
static void xive_do_source_set_mask(struct xive_irq_data *xd,
|
|
|
|
bool mask)
|
|
|
|
{
|
|
|
|
u64 val;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If the interrupt had P set, it may be in a queue.
|
|
|
|
*
|
|
|
|
* We need to make sure we don't re-enable it until it
|
|
|
|
* has been fetched from that queue and EOId. We keep
|
|
|
|
* a copy of that P state and use it to restore the
|
|
|
|
* ESB accordingly on unmask.
|
|
|
|
*/
|
|
|
|
if (mask) {
|
2017-08-30 19:46:12 +00:00
|
|
|
val = xive_esb_read(xd, XIVE_ESB_SET_PQ_01);
|
2017-04-05 07:54:50 +00:00
|
|
|
xd->saved_p = !!(val & XIVE_ESB_VAL_P);
|
|
|
|
} else if (xd->saved_p)
|
2017-08-30 19:46:12 +00:00
|
|
|
xive_esb_read(xd, XIVE_ESB_SET_PQ_10);
|
2017-04-05 07:54:50 +00:00
|
|
|
else
|
2017-08-30 19:46:12 +00:00
|
|
|
xive_esb_read(xd, XIVE_ESB_SET_PQ_00);
|
2017-04-05 07:54:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Try to chose "cpu" as a new interrupt target. Increments
|
|
|
|
* the queue accounting for that target if it's not already
|
|
|
|
* full.
|
|
|
|
*/
|
|
|
|
static bool xive_try_pick_target(int cpu)
|
|
|
|
{
|
|
|
|
struct xive_cpu *xc = per_cpu(xive_cpu, cpu);
|
|
|
|
struct xive_q *q = &xc->queue[xive_irq_priority];
|
|
|
|
int max;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Calculate max number of interrupts in that queue.
|
|
|
|
*
|
|
|
|
* We leave a gap of 1 just in case...
|
|
|
|
*/
|
|
|
|
max = (q->msk + 1) - 1;
|
|
|
|
return !!atomic_add_unless(&q->count, 1, max);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Un-account an interrupt for a target CPU. We don't directly
|
|
|
|
* decrement q->count since the interrupt might still be present
|
|
|
|
* in the queue.
|
|
|
|
*
|
|
|
|
* Instead increment a separate counter "pending_count" which
|
|
|
|
* will be substracted from "count" later when that CPU observes
|
|
|
|
* the queue to be empty.
|
|
|
|
*/
|
|
|
|
static void xive_dec_target_count(int cpu)
|
|
|
|
{
|
|
|
|
struct xive_cpu *xc = per_cpu(xive_cpu, cpu);
|
|
|
|
struct xive_q *q = &xc->queue[xive_irq_priority];
|
|
|
|
|
|
|
|
if (unlikely(WARN_ON(cpu < 0 || !xc))) {
|
|
|
|
pr_err("%s: cpu=%d xc=%p\n", __func__, cpu, xc);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We increment the "pending count" which will be used
|
|
|
|
* to decrement the target queue count whenever it's next
|
|
|
|
* processed and found empty. This ensure that we don't
|
|
|
|
* decrement while we still have the interrupt there
|
|
|
|
* occupying a slot.
|
|
|
|
*/
|
|
|
|
atomic_inc(&q->pending_count);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Find a tentative CPU target in a CPU mask */
|
|
|
|
static int xive_find_target_in_mask(const struct cpumask *mask,
|
|
|
|
unsigned int fuzz)
|
|
|
|
{
|
|
|
|
int cpu, first, num, i;
|
|
|
|
|
|
|
|
/* Pick up a starting point CPU in the mask based on fuzz */
|
2017-08-08 09:02:49 +00:00
|
|
|
num = min_t(int, cpumask_weight(mask), nr_cpu_ids);
|
2017-04-05 07:54:50 +00:00
|
|
|
first = fuzz % num;
|
|
|
|
|
|
|
|
/* Locate it */
|
|
|
|
cpu = cpumask_first(mask);
|
|
|
|
for (i = 0; i < first && cpu < nr_cpu_ids; i++)
|
|
|
|
cpu = cpumask_next(cpu, mask);
|
|
|
|
|
|
|
|
/* Sanity check */
|
|
|
|
if (WARN_ON(cpu >= nr_cpu_ids))
|
|
|
|
cpu = cpumask_first(cpu_online_mask);
|
|
|
|
|
|
|
|
/* Remember first one to handle wrap-around */
|
|
|
|
first = cpu;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Now go through the entire mask until we find a valid
|
|
|
|
* target.
|
|
|
|
*/
|
|
|
|
for (;;) {
|
|
|
|
/*
|
|
|
|
* We re-check online as the fallback case passes us
|
|
|
|
* an untested affinity mask
|
|
|
|
*/
|
|
|
|
if (cpu_online(cpu) && xive_try_pick_target(cpu))
|
|
|
|
return cpu;
|
|
|
|
cpu = cpumask_next(cpu, mask);
|
|
|
|
if (cpu == first)
|
|
|
|
break;
|
|
|
|
/* Wrap around */
|
|
|
|
if (cpu >= nr_cpu_ids)
|
|
|
|
cpu = cpumask_first(mask);
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Pick a target CPU for an interrupt. This is done at
|
|
|
|
* startup or if the affinity is changed in a way that
|
|
|
|
* invalidates the current target.
|
|
|
|
*/
|
|
|
|
static int xive_pick_irq_target(struct irq_data *d,
|
|
|
|
const struct cpumask *affinity)
|
|
|
|
{
|
|
|
|
static unsigned int fuzz;
|
|
|
|
struct xive_irq_data *xd = irq_data_get_irq_handler_data(d);
|
|
|
|
cpumask_var_t mask;
|
|
|
|
int cpu = -1;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If we have chip IDs, first we try to build a mask of
|
|
|
|
* CPUs matching the CPU and find a target in there
|
|
|
|
*/
|
|
|
|
if (xd->src_chip != XIVE_INVALID_CHIP_ID &&
|
|
|
|
zalloc_cpumask_var(&mask, GFP_ATOMIC)) {
|
|
|
|
/* Build a mask of matching chip IDs */
|
|
|
|
for_each_cpu_and(cpu, affinity, cpu_online_mask) {
|
|
|
|
struct xive_cpu *xc = per_cpu(xive_cpu, cpu);
|
|
|
|
if (xc->chip_id == xd->src_chip)
|
|
|
|
cpumask_set_cpu(cpu, mask);
|
|
|
|
}
|
|
|
|
/* Try to find a target */
|
|
|
|
if (cpumask_empty(mask))
|
|
|
|
cpu = -1;
|
|
|
|
else
|
|
|
|
cpu = xive_find_target_in_mask(mask, fuzz++);
|
|
|
|
free_cpumask_var(mask);
|
|
|
|
if (cpu >= 0)
|
|
|
|
return cpu;
|
|
|
|
fuzz--;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* No chip IDs, fallback to using the affinity mask */
|
|
|
|
return xive_find_target_in_mask(affinity, fuzz++);
|
|
|
|
}
|
|
|
|
|
|
|
|
static unsigned int xive_irq_startup(struct irq_data *d)
|
|
|
|
{
|
|
|
|
struct xive_irq_data *xd = irq_data_get_irq_handler_data(d);
|
|
|
|
unsigned int hw_irq = (unsigned int)irqd_to_hwirq(d);
|
|
|
|
int target, rc;
|
|
|
|
|
|
|
|
pr_devel("xive_irq_startup: irq %d [0x%x] data @%p\n",
|
|
|
|
d->irq, hw_irq, d);
|
|
|
|
|
|
|
|
#ifdef CONFIG_PCI_MSI
|
|
|
|
/*
|
|
|
|
* The generic MSI code returns with the interrupt disabled on the
|
|
|
|
* card, using the MSI mask bits. Firmware doesn't appear to unmask
|
|
|
|
* at that level, so we do it here by hand.
|
|
|
|
*/
|
|
|
|
if (irq_data_get_msi_desc(d))
|
|
|
|
pci_msi_unmask_irq(d);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Pick a target */
|
|
|
|
target = xive_pick_irq_target(d, irq_data_get_affinity_mask(d));
|
|
|
|
if (target == XIVE_INVALID_TARGET) {
|
|
|
|
/* Try again breaking affinity */
|
|
|
|
target = xive_pick_irq_target(d, cpu_online_mask);
|
|
|
|
if (target == XIVE_INVALID_TARGET)
|
|
|
|
return -ENXIO;
|
|
|
|
pr_warn("irq %d started with broken affinity\n", d->irq);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Sanity check */
|
|
|
|
if (WARN_ON(target == XIVE_INVALID_TARGET ||
|
|
|
|
target >= nr_cpu_ids))
|
|
|
|
target = smp_processor_id();
|
|
|
|
|
|
|
|
xd->target = target;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Configure the logical number to be the Linux IRQ number
|
|
|
|
* and set the target queue
|
|
|
|
*/
|
|
|
|
rc = xive_ops->configure_irq(hw_irq,
|
|
|
|
get_hard_smp_processor_id(target),
|
|
|
|
xive_irq_priority, d->irq);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
/* Unmask the ESB */
|
|
|
|
xive_do_source_set_mask(xd, false);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void xive_irq_shutdown(struct irq_data *d)
|
|
|
|
{
|
|
|
|
struct xive_irq_data *xd = irq_data_get_irq_handler_data(d);
|
|
|
|
unsigned int hw_irq = (unsigned int)irqd_to_hwirq(d);
|
|
|
|
|
|
|
|
pr_devel("xive_irq_shutdown: irq %d [0x%x] data @%p\n",
|
|
|
|
d->irq, hw_irq, d);
|
|
|
|
|
|
|
|
if (WARN_ON(xd->target == XIVE_INVALID_TARGET))
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* Mask the interrupt at the source */
|
|
|
|
xive_do_source_set_mask(xd, true);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The above may have set saved_p. We clear it otherwise it
|
|
|
|
* will prevent re-enabling later on. It is ok to forget the
|
|
|
|
* fact that the interrupt might be in a queue because we are
|
|
|
|
* accounting that already in xive_dec_target_count() and will
|
|
|
|
* be re-routing it to a new queue with proper accounting when
|
|
|
|
* it's started up again
|
|
|
|
*/
|
|
|
|
xd->saved_p = false;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Mask the interrupt in HW in the IVT/EAS and set the number
|
|
|
|
* to be the "bad" IRQ number
|
|
|
|
*/
|
|
|
|
xive_ops->configure_irq(hw_irq,
|
|
|
|
get_hard_smp_processor_id(xd->target),
|
|
|
|
0xff, XIVE_BAD_IRQ);
|
|
|
|
|
|
|
|
xive_dec_target_count(xd->target);
|
|
|
|
xd->target = XIVE_INVALID_TARGET;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void xive_irq_unmask(struct irq_data *d)
|
|
|
|
{
|
|
|
|
struct xive_irq_data *xd = irq_data_get_irq_handler_data(d);
|
|
|
|
|
|
|
|
pr_devel("xive_irq_unmask: irq %d data @%p\n", d->irq, xd);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This is a workaround for PCI LSI problems on P9, for
|
|
|
|
* these, we call FW to set the mask. The problems might
|
|
|
|
* be fixed by P9 DD2.0, if that is the case, firmware
|
|
|
|
* will no longer set that flag.
|
|
|
|
*/
|
|
|
|
if (xd->flags & XIVE_IRQ_FLAG_MASK_FW) {
|
|
|
|
unsigned int hw_irq = (unsigned int)irqd_to_hwirq(d);
|
|
|
|
xive_ops->configure_irq(hw_irq,
|
|
|
|
get_hard_smp_processor_id(xd->target),
|
|
|
|
xive_irq_priority, d->irq);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
xive_do_source_set_mask(xd, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void xive_irq_mask(struct irq_data *d)
|
|
|
|
{
|
|
|
|
struct xive_irq_data *xd = irq_data_get_irq_handler_data(d);
|
|
|
|
|
|
|
|
pr_devel("xive_irq_mask: irq %d data @%p\n", d->irq, xd);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This is a workaround for PCI LSI problems on P9, for
|
|
|
|
* these, we call OPAL to set the mask. The problems might
|
|
|
|
* be fixed by P9 DD2.0, if that is the case, firmware
|
|
|
|
* will no longer set that flag.
|
|
|
|
*/
|
|
|
|
if (xd->flags & XIVE_IRQ_FLAG_MASK_FW) {
|
|
|
|
unsigned int hw_irq = (unsigned int)irqd_to_hwirq(d);
|
|
|
|
xive_ops->configure_irq(hw_irq,
|
|
|
|
get_hard_smp_processor_id(xd->target),
|
|
|
|
0xff, d->irq);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
xive_do_source_set_mask(xd, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int xive_irq_set_affinity(struct irq_data *d,
|
|
|
|
const struct cpumask *cpumask,
|
|
|
|
bool force)
|
|
|
|
{
|
|
|
|
struct xive_irq_data *xd = irq_data_get_irq_handler_data(d);
|
|
|
|
unsigned int hw_irq = (unsigned int)irqd_to_hwirq(d);
|
|
|
|
u32 target, old_target;
|
|
|
|
int rc = 0;
|
|
|
|
|
|
|
|
pr_devel("xive_irq_set_affinity: irq %d\n", d->irq);
|
|
|
|
|
|
|
|
/* Is this valid ? */
|
|
|
|
if (cpumask_any_and(cpumask, cpu_online_mask) >= nr_cpu_ids)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2017-08-02 01:54:41 +00:00
|
|
|
/* Don't do anything if the interrupt isn't started */
|
|
|
|
if (!irqd_is_started(d))
|
|
|
|
return IRQ_SET_MASK_OK;
|
|
|
|
|
2017-04-05 07:54:50 +00:00
|
|
|
/*
|
|
|
|
* If existing target is already in the new mask, and is
|
|
|
|
* online then do nothing.
|
|
|
|
*/
|
|
|
|
if (xd->target != XIVE_INVALID_TARGET &&
|
|
|
|
cpu_online(xd->target) &&
|
|
|
|
cpumask_test_cpu(xd->target, cpumask))
|
|
|
|
return IRQ_SET_MASK_OK;
|
|
|
|
|
|
|
|
/* Pick a new target */
|
|
|
|
target = xive_pick_irq_target(d, cpumask);
|
|
|
|
|
|
|
|
/* No target found */
|
|
|
|
if (target == XIVE_INVALID_TARGET)
|
|
|
|
return -ENXIO;
|
|
|
|
|
|
|
|
/* Sanity check */
|
|
|
|
if (WARN_ON(target >= nr_cpu_ids))
|
|
|
|
target = smp_processor_id();
|
|
|
|
|
|
|
|
old_target = xd->target;
|
|
|
|
|
2017-04-05 07:54:56 +00:00
|
|
|
/*
|
|
|
|
* Only configure the irq if it's not currently passed-through to
|
|
|
|
* a KVM guest
|
|
|
|
*/
|
|
|
|
if (!irqd_is_forwarded_to_vcpu(d))
|
|
|
|
rc = xive_ops->configure_irq(hw_irq,
|
|
|
|
get_hard_smp_processor_id(target),
|
|
|
|
xive_irq_priority, d->irq);
|
2017-04-05 07:54:50 +00:00
|
|
|
if (rc < 0) {
|
|
|
|
pr_err("Error %d reconfiguring irq %d\n", rc, d->irq);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
pr_devel(" target: 0x%x\n", target);
|
|
|
|
xd->target = target;
|
|
|
|
|
|
|
|
/* Give up previous target */
|
|
|
|
if (old_target != XIVE_INVALID_TARGET)
|
|
|
|
xive_dec_target_count(old_target);
|
|
|
|
|
|
|
|
return IRQ_SET_MASK_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int xive_irq_set_type(struct irq_data *d, unsigned int flow_type)
|
|
|
|
{
|
|
|
|
struct xive_irq_data *xd = irq_data_get_irq_handler_data(d);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We only support these. This has really no effect other than setting
|
|
|
|
* the corresponding descriptor bits mind you but those will in turn
|
|
|
|
* affect the resend function when re-enabling an edge interrupt.
|
|
|
|
*
|
|
|
|
* Set set the default to edge as explained in map().
|
|
|
|
*/
|
|
|
|
if (flow_type == IRQ_TYPE_DEFAULT || flow_type == IRQ_TYPE_NONE)
|
|
|
|
flow_type = IRQ_TYPE_EDGE_RISING;
|
|
|
|
|
|
|
|
if (flow_type != IRQ_TYPE_EDGE_RISING &&
|
|
|
|
flow_type != IRQ_TYPE_LEVEL_LOW)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
irqd_set_trigger_type(d, flow_type);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Double check it matches what the FW thinks
|
|
|
|
*
|
|
|
|
* NOTE: We don't know yet if the PAPR interface will provide
|
|
|
|
* the LSI vs MSI information apart from the device-tree so
|
|
|
|
* this check might have to move into an optional backend call
|
|
|
|
* that is specific to the native backend
|
|
|
|
*/
|
|
|
|
if ((flow_type == IRQ_TYPE_LEVEL_LOW) !=
|
|
|
|
!!(xd->flags & XIVE_IRQ_FLAG_LSI)) {
|
|
|
|
pr_warn("Interrupt %d (HW 0x%x) type mismatch, Linux says %s, FW says %s\n",
|
|
|
|
d->irq, (u32)irqd_to_hwirq(d),
|
|
|
|
(flow_type == IRQ_TYPE_LEVEL_LOW) ? "Level" : "Edge",
|
|
|
|
(xd->flags & XIVE_IRQ_FLAG_LSI) ? "Level" : "Edge");
|
|
|
|
}
|
|
|
|
|
|
|
|
return IRQ_SET_MASK_OK_NOCOPY;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int xive_irq_retrigger(struct irq_data *d)
|
|
|
|
{
|
|
|
|
struct xive_irq_data *xd = irq_data_get_irq_handler_data(d);
|
|
|
|
|
|
|
|
/* This should be only for MSIs */
|
|
|
|
if (WARN_ON(xd->flags & XIVE_IRQ_FLAG_LSI))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* To perform a retrigger, we first set the PQ bits to
|
|
|
|
* 11, then perform an EOI.
|
|
|
|
*/
|
2017-08-30 19:46:12 +00:00
|
|
|
xive_esb_read(xd, XIVE_ESB_SET_PQ_11);
|
2017-04-05 07:54:50 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Note: We pass "0" to the hw_irq argument in order to
|
|
|
|
* avoid calling into the backend EOI code which we don't
|
|
|
|
* want to do in the case of a re-trigger. Backends typically
|
|
|
|
* only do EOI for LSIs anyway.
|
|
|
|
*/
|
|
|
|
xive_do_source_eoi(0, xd);
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2017-04-05 07:54:56 +00:00
|
|
|
static int xive_irq_set_vcpu_affinity(struct irq_data *d, void *state)
|
|
|
|
{
|
|
|
|
struct xive_irq_data *xd = irq_data_get_irq_handler_data(d);
|
|
|
|
unsigned int hw_irq = (unsigned int)irqd_to_hwirq(d);
|
|
|
|
int rc;
|
|
|
|
u8 pq;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We only support this on interrupts that do not require
|
|
|
|
* firmware calls for masking and unmasking
|
|
|
|
*/
|
|
|
|
if (xd->flags & XIVE_IRQ_FLAG_MASK_FW)
|
|
|
|
return -EIO;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This is called by KVM with state non-NULL for enabling
|
|
|
|
* pass-through or NULL for disabling it
|
|
|
|
*/
|
|
|
|
if (state) {
|
|
|
|
irqd_set_forwarded_to_vcpu(d);
|
|
|
|
|
|
|
|
/* Set it to PQ=10 state to prevent further sends */
|
2017-08-30 19:46:12 +00:00
|
|
|
pq = xive_esb_read(xd, XIVE_ESB_SET_PQ_10);
|
2017-04-05 07:54:56 +00:00
|
|
|
|
|
|
|
/* No target ? nothing to do */
|
|
|
|
if (xd->target == XIVE_INVALID_TARGET) {
|
|
|
|
/*
|
|
|
|
* An untargetted interrupt should have been
|
|
|
|
* also masked at the source
|
|
|
|
*/
|
|
|
|
WARN_ON(pq & 2);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If P was set, adjust state to PQ=11 to indicate
|
|
|
|
* that a resend is needed for the interrupt to reach
|
|
|
|
* the guest. Also remember the value of P.
|
|
|
|
*
|
|
|
|
* This also tells us that it's in flight to a host queue
|
|
|
|
* or has already been fetched but hasn't been EOIed yet
|
|
|
|
* by the host. This it's potentially using up a host
|
|
|
|
* queue slot. This is important to know because as long
|
|
|
|
* as this is the case, we must not hard-unmask it when
|
|
|
|
* "returning" that interrupt to the host.
|
|
|
|
*
|
|
|
|
* This saved_p is cleared by the host EOI, when we know
|
|
|
|
* for sure the queue slot is no longer in use.
|
|
|
|
*/
|
|
|
|
if (pq & 2) {
|
2017-08-30 19:46:12 +00:00
|
|
|
pq = xive_esb_read(xd, XIVE_ESB_SET_PQ_11);
|
2017-04-05 07:54:56 +00:00
|
|
|
xd->saved_p = true;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Sync the XIVE source HW to ensure the interrupt
|
|
|
|
* has gone through the EAS before we change its
|
|
|
|
* target to the guest. That should guarantee us
|
|
|
|
* that we *will* eventually get an EOI for it on
|
|
|
|
* the host. Otherwise there would be a small window
|
|
|
|
* for P to be seen here but the interrupt going
|
|
|
|
* to the guest queue.
|
|
|
|
*/
|
|
|
|
if (xive_ops->sync_source)
|
|
|
|
xive_ops->sync_source(hw_irq);
|
|
|
|
} else
|
|
|
|
xd->saved_p = false;
|
|
|
|
} else {
|
|
|
|
irqd_clr_forwarded_to_vcpu(d);
|
|
|
|
|
|
|
|
/* No host target ? hard mask and return */
|
|
|
|
if (xd->target == XIVE_INVALID_TARGET) {
|
|
|
|
xive_do_source_set_mask(xd, true);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Sync the XIVE source HW to ensure the interrupt
|
|
|
|
* has gone through the EAS before we change its
|
|
|
|
* target to the host.
|
|
|
|
*/
|
|
|
|
if (xive_ops->sync_source)
|
|
|
|
xive_ops->sync_source(hw_irq);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* By convention we are called with the interrupt in
|
|
|
|
* a PQ=10 or PQ=11 state, ie, it won't fire and will
|
|
|
|
* have latched in Q whether there's a pending HW
|
|
|
|
* interrupt or not.
|
|
|
|
*
|
|
|
|
* First reconfigure the target.
|
|
|
|
*/
|
|
|
|
rc = xive_ops->configure_irq(hw_irq,
|
|
|
|
get_hard_smp_processor_id(xd->target),
|
|
|
|
xive_irq_priority, d->irq);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Then if saved_p is not set, effectively re-enable the
|
|
|
|
* interrupt with an EOI. If it is set, we know there is
|
|
|
|
* still a message in a host queue somewhere that will be
|
|
|
|
* EOId eventually.
|
|
|
|
*
|
|
|
|
* Note: We don't check irqd_irq_disabled(). Effectively,
|
|
|
|
* we *will* let the irq get through even if masked if the
|
|
|
|
* HW is still firing it in order to deal with the whole
|
|
|
|
* saved_p business properly. If the interrupt triggers
|
|
|
|
* while masked, the generic code will re-mask it anyway.
|
|
|
|
*/
|
|
|
|
if (!xd->saved_p)
|
|
|
|
xive_do_source_eoi(hw_irq, xd);
|
|
|
|
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-04-05 07:54:50 +00:00
|
|
|
static struct irq_chip xive_irq_chip = {
|
|
|
|
.name = "XIVE-IRQ",
|
|
|
|
.irq_startup = xive_irq_startup,
|
|
|
|
.irq_shutdown = xive_irq_shutdown,
|
|
|
|
.irq_eoi = xive_irq_eoi,
|
|
|
|
.irq_mask = xive_irq_mask,
|
|
|
|
.irq_unmask = xive_irq_unmask,
|
|
|
|
.irq_set_affinity = xive_irq_set_affinity,
|
|
|
|
.irq_set_type = xive_irq_set_type,
|
|
|
|
.irq_retrigger = xive_irq_retrigger,
|
2017-04-05 07:54:56 +00:00
|
|
|
.irq_set_vcpu_affinity = xive_irq_set_vcpu_affinity,
|
2017-04-05 07:54:50 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
bool is_xive_irq(struct irq_chip *chip)
|
|
|
|
{
|
|
|
|
return chip == &xive_irq_chip;
|
|
|
|
}
|
2017-04-05 07:54:56 +00:00
|
|
|
EXPORT_SYMBOL_GPL(is_xive_irq);
|
2017-04-05 07:54:50 +00:00
|
|
|
|
|
|
|
void xive_cleanup_irq_data(struct xive_irq_data *xd)
|
|
|
|
{
|
|
|
|
if (xd->eoi_mmio) {
|
|
|
|
iounmap(xd->eoi_mmio);
|
|
|
|
if (xd->eoi_mmio == xd->trig_mmio)
|
|
|
|
xd->trig_mmio = NULL;
|
|
|
|
xd->eoi_mmio = NULL;
|
|
|
|
}
|
|
|
|
if (xd->trig_mmio) {
|
|
|
|
iounmap(xd->trig_mmio);
|
|
|
|
xd->trig_mmio = NULL;
|
|
|
|
}
|
|
|
|
}
|
2017-04-05 07:54:56 +00:00
|
|
|
EXPORT_SYMBOL_GPL(xive_cleanup_irq_data);
|
2017-04-05 07:54:50 +00:00
|
|
|
|
|
|
|
static int xive_irq_alloc_data(unsigned int virq, irq_hw_number_t hw)
|
|
|
|
{
|
|
|
|
struct xive_irq_data *xd;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
xd = kzalloc(sizeof(struct xive_irq_data), GFP_KERNEL);
|
|
|
|
if (!xd)
|
|
|
|
return -ENOMEM;
|
|
|
|
rc = xive_ops->populate_irq_data(hw, xd);
|
|
|
|
if (rc) {
|
|
|
|
kfree(xd);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
xd->target = XIVE_INVALID_TARGET;
|
|
|
|
irq_set_handler_data(virq, xd);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void xive_irq_free_data(unsigned int virq)
|
|
|
|
{
|
|
|
|
struct xive_irq_data *xd = irq_get_handler_data(virq);
|
|
|
|
|
|
|
|
if (!xd)
|
|
|
|
return;
|
|
|
|
irq_set_handler_data(virq, NULL);
|
|
|
|
xive_cleanup_irq_data(xd);
|
|
|
|
kfree(xd);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef CONFIG_SMP
|
|
|
|
|
2017-04-13 10:16:21 +00:00
|
|
|
static void xive_cause_ipi(int cpu)
|
2017-04-05 07:54:50 +00:00
|
|
|
{
|
|
|
|
struct xive_cpu *xc;
|
|
|
|
struct xive_irq_data *xd;
|
|
|
|
|
|
|
|
xc = per_cpu(xive_cpu, cpu);
|
|
|
|
|
2017-04-13 10:16:21 +00:00
|
|
|
DBG_VERBOSE("IPI CPU %d -> %d (HW IRQ 0x%x)\n",
|
|
|
|
smp_processor_id(), cpu, xc->hw_ipi);
|
2017-04-05 07:54:50 +00:00
|
|
|
|
|
|
|
xd = &xc->ipi_data;
|
|
|
|
if (WARN_ON(!xd->trig_mmio))
|
|
|
|
return;
|
|
|
|
out_be64(xd->trig_mmio, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static irqreturn_t xive_muxed_ipi_action(int irq, void *dev_id)
|
|
|
|
{
|
|
|
|
return smp_ipi_demux();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void xive_ipi_eoi(struct irq_data *d)
|
|
|
|
{
|
|
|
|
struct xive_cpu *xc = __this_cpu_read(xive_cpu);
|
|
|
|
|
2017-08-30 19:46:17 +00:00
|
|
|
DBG_VERBOSE("IPI eoi: irq=%d [0x%lx] (HW IRQ 0x%x) pending=%02x\n",
|
|
|
|
d->irq, irqd_to_hwirq(d), xc->hw_ipi, xc->pending_prio);
|
|
|
|
|
2017-04-05 07:54:50 +00:00
|
|
|
/* Handle possible race with unplug and drop stale IPIs */
|
|
|
|
if (!xc)
|
|
|
|
return;
|
|
|
|
xive_do_source_eoi(xc->hw_ipi, &xc->ipi_data);
|
|
|
|
xive_do_queue_eoi(xc);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void xive_ipi_do_nothing(struct irq_data *d)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Nothing to do, we never mask/unmask IPIs, but the callback
|
|
|
|
* has to exist for the struct irq_chip.
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct irq_chip xive_ipi_chip = {
|
|
|
|
.name = "XIVE-IPI",
|
|
|
|
.irq_eoi = xive_ipi_eoi,
|
|
|
|
.irq_mask = xive_ipi_do_nothing,
|
|
|
|
.irq_unmask = xive_ipi_do_nothing,
|
|
|
|
};
|
|
|
|
|
|
|
|
static void __init xive_request_ipi(void)
|
|
|
|
{
|
|
|
|
unsigned int virq;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Initialization failed, move on, we might manage to
|
|
|
|
* reach the point where we display our errors before
|
|
|
|
* the system falls appart
|
|
|
|
*/
|
|
|
|
if (!xive_irq_domain)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* Initialize it */
|
|
|
|
virq = irq_create_mapping(xive_irq_domain, 0);
|
|
|
|
xive_ipi_irq = virq;
|
|
|
|
|
|
|
|
WARN_ON(request_irq(virq, xive_muxed_ipi_action,
|
|
|
|
IRQF_PERCPU | IRQF_NO_THREAD, "IPI", NULL));
|
|
|
|
}
|
|
|
|
|
|
|
|
static int xive_setup_cpu_ipi(unsigned int cpu)
|
|
|
|
{
|
|
|
|
struct xive_cpu *xc;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
pr_debug("Setting up IPI for CPU %d\n", cpu);
|
|
|
|
|
|
|
|
xc = per_cpu(xive_cpu, cpu);
|
|
|
|
|
|
|
|
/* Check if we are already setup */
|
|
|
|
if (xc->hw_ipi != 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* Grab an IPI from the backend, this will populate xc->hw_ipi */
|
|
|
|
if (xive_ops->get_ipi(cpu, xc))
|
|
|
|
return -EIO;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Populate the IRQ data in the xive_cpu structure and
|
|
|
|
* configure the HW / enable the IPIs.
|
|
|
|
*/
|
|
|
|
rc = xive_ops->populate_irq_data(xc->hw_ipi, &xc->ipi_data);
|
|
|
|
if (rc) {
|
|
|
|
pr_err("Failed to populate IPI data on CPU %d\n", cpu);
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
rc = xive_ops->configure_irq(xc->hw_ipi,
|
|
|
|
get_hard_smp_processor_id(cpu),
|
|
|
|
xive_irq_priority, xive_ipi_irq);
|
|
|
|
if (rc) {
|
|
|
|
pr_err("Failed to map IPI CPU %d\n", cpu);
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
pr_devel("CPU %d HW IPI %x, virq %d, trig_mmio=%p\n", cpu,
|
|
|
|
xc->hw_ipi, xive_ipi_irq, xc->ipi_data.trig_mmio);
|
|
|
|
|
|
|
|
/* Unmask it */
|
|
|
|
xive_do_source_set_mask(&xc->ipi_data, false);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void xive_cleanup_cpu_ipi(unsigned int cpu, struct xive_cpu *xc)
|
|
|
|
{
|
|
|
|
/* Disable the IPI and free the IRQ data */
|
|
|
|
|
|
|
|
/* Already cleaned up ? */
|
|
|
|
if (xc->hw_ipi == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* Mask the IPI */
|
|
|
|
xive_do_source_set_mask(&xc->ipi_data, true);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Note: We don't call xive_cleanup_irq_data() to free
|
|
|
|
* the mappings as this is called from an IPI on kexec
|
|
|
|
* which is not a safe environment to call iounmap()
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* Deconfigure/mask in the backend */
|
|
|
|
xive_ops->configure_irq(xc->hw_ipi, hard_smp_processor_id(),
|
|
|
|
0xff, xive_ipi_irq);
|
|
|
|
|
|
|
|
/* Free the IPIs in the backend */
|
|
|
|
xive_ops->put_ipi(cpu, xc);
|
|
|
|
}
|
|
|
|
|
|
|
|
void __init xive_smp_probe(void)
|
|
|
|
{
|
|
|
|
smp_ops->cause_ipi = xive_cause_ipi;
|
|
|
|
|
|
|
|
/* Register the IPI */
|
|
|
|
xive_request_ipi();
|
|
|
|
|
|
|
|
/* Allocate and setup IPI for the boot CPU */
|
|
|
|
xive_setup_cpu_ipi(smp_processor_id());
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* CONFIG_SMP */
|
|
|
|
|
|
|
|
static int xive_irq_domain_map(struct irq_domain *h, unsigned int virq,
|
|
|
|
irq_hw_number_t hw)
|
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Mark interrupts as edge sensitive by default so that resend
|
|
|
|
* actually works. Will fix that up below if needed.
|
|
|
|
*/
|
|
|
|
irq_clear_status_flags(virq, IRQ_LEVEL);
|
|
|
|
|
|
|
|
#ifdef CONFIG_SMP
|
|
|
|
/* IPIs are special and come up with HW number 0 */
|
|
|
|
if (hw == 0) {
|
|
|
|
/*
|
|
|
|
* IPIs are marked per-cpu. We use separate HW interrupts under
|
|
|
|
* the hood but associated with the same "linux" interrupt
|
|
|
|
*/
|
|
|
|
irq_set_chip_and_handler(virq, &xive_ipi_chip,
|
|
|
|
handle_percpu_irq);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
rc = xive_irq_alloc_data(virq, hw);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
irq_set_chip_and_handler(virq, &xive_irq_chip, handle_fasteoi_irq);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void xive_irq_domain_unmap(struct irq_domain *d, unsigned int virq)
|
|
|
|
{
|
|
|
|
struct irq_data *data = irq_get_irq_data(virq);
|
|
|
|
unsigned int hw_irq;
|
|
|
|
|
|
|
|
/* XXX Assign BAD number */
|
|
|
|
if (!data)
|
|
|
|
return;
|
|
|
|
hw_irq = (unsigned int)irqd_to_hwirq(data);
|
|
|
|
if (hw_irq)
|
|
|
|
xive_irq_free_data(virq);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int xive_irq_domain_xlate(struct irq_domain *h, struct device_node *ct,
|
|
|
|
const u32 *intspec, unsigned int intsize,
|
|
|
|
irq_hw_number_t *out_hwirq, unsigned int *out_flags)
|
|
|
|
|
|
|
|
{
|
|
|
|
*out_hwirq = intspec[0];
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If intsize is at least 2, we look for the type in the second cell,
|
|
|
|
* we assume the LSB indicates a level interrupt.
|
|
|
|
*/
|
|
|
|
if (intsize > 1) {
|
|
|
|
if (intspec[1] & 1)
|
|
|
|
*out_flags = IRQ_TYPE_LEVEL_LOW;
|
|
|
|
else
|
|
|
|
*out_flags = IRQ_TYPE_EDGE_RISING;
|
|
|
|
} else
|
|
|
|
*out_flags = IRQ_TYPE_LEVEL_LOW;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int xive_irq_domain_match(struct irq_domain *h, struct device_node *node,
|
|
|
|
enum irq_domain_bus_token bus_token)
|
|
|
|
{
|
|
|
|
return xive_ops->match(node);
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct irq_domain_ops xive_irq_domain_ops = {
|
|
|
|
.match = xive_irq_domain_match,
|
|
|
|
.map = xive_irq_domain_map,
|
|
|
|
.unmap = xive_irq_domain_unmap,
|
|
|
|
.xlate = xive_irq_domain_xlate,
|
|
|
|
};
|
|
|
|
|
|
|
|
static void __init xive_init_host(void)
|
|
|
|
{
|
|
|
|
xive_irq_domain = irq_domain_add_nomap(NULL, XIVE_MAX_IRQ,
|
|
|
|
&xive_irq_domain_ops, NULL);
|
|
|
|
if (WARN_ON(xive_irq_domain == NULL))
|
|
|
|
return;
|
|
|
|
irq_set_default_host(xive_irq_domain);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void xive_cleanup_cpu_queues(unsigned int cpu, struct xive_cpu *xc)
|
|
|
|
{
|
|
|
|
if (xc->queue[xive_irq_priority].qpage)
|
|
|
|
xive_ops->cleanup_queue(cpu, xc, xive_irq_priority);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int xive_setup_cpu_queues(unsigned int cpu, struct xive_cpu *xc)
|
|
|
|
{
|
|
|
|
int rc = 0;
|
|
|
|
|
|
|
|
/* We setup 1 queues for now with a 64k page */
|
|
|
|
if (!xc->queue[xive_irq_priority].qpage)
|
|
|
|
rc = xive_ops->setup_queue(cpu, xc, xive_irq_priority);
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int xive_prepare_cpu(unsigned int cpu)
|
|
|
|
{
|
|
|
|
struct xive_cpu *xc;
|
|
|
|
|
|
|
|
xc = per_cpu(xive_cpu, cpu);
|
|
|
|
if (!xc) {
|
|
|
|
struct device_node *np;
|
|
|
|
|
|
|
|
xc = kzalloc_node(sizeof(struct xive_cpu),
|
|
|
|
GFP_KERNEL, cpu_to_node(cpu));
|
|
|
|
if (!xc)
|
|
|
|
return -ENOMEM;
|
|
|
|
np = of_get_cpu_node(cpu, NULL);
|
|
|
|
if (np)
|
|
|
|
xc->chip_id = of_get_ibm_chip_id(np);
|
|
|
|
of_node_put(np);
|
|
|
|
|
|
|
|
per_cpu(xive_cpu, cpu) = xc;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Setup EQs if not already */
|
|
|
|
return xive_setup_cpu_queues(cpu, xc);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void xive_setup_cpu(void)
|
|
|
|
{
|
|
|
|
struct xive_cpu *xc = __this_cpu_read(xive_cpu);
|
|
|
|
|
|
|
|
/* The backend might have additional things to do */
|
|
|
|
if (xive_ops->setup_cpu)
|
|
|
|
xive_ops->setup_cpu(smp_processor_id(), xc);
|
|
|
|
|
|
|
|
/* Set CPPR to 0xff to enable flow of interrupts */
|
|
|
|
xc->cppr = 0xff;
|
|
|
|
out_8(xive_tima + xive_tima_offset + TM_CPPR, 0xff);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef CONFIG_SMP
|
|
|
|
void xive_smp_setup_cpu(void)
|
|
|
|
{
|
|
|
|
pr_devel("SMP setup CPU %d\n", smp_processor_id());
|
|
|
|
|
|
|
|
/* This will have already been done on the boot CPU */
|
|
|
|
if (smp_processor_id() != boot_cpuid)
|
|
|
|
xive_setup_cpu();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
int xive_smp_prepare_cpu(unsigned int cpu)
|
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
/* Allocate per-CPU data and queues */
|
|
|
|
rc = xive_prepare_cpu(cpu);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
/* Allocate and setup IPI for the new CPU */
|
|
|
|
return xive_setup_cpu_ipi(cpu);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef CONFIG_HOTPLUG_CPU
|
|
|
|
static void xive_flush_cpu_queue(unsigned int cpu, struct xive_cpu *xc)
|
|
|
|
{
|
|
|
|
u32 irq;
|
|
|
|
|
|
|
|
/* We assume local irqs are disabled */
|
|
|
|
WARN_ON(!irqs_disabled());
|
|
|
|
|
|
|
|
/* Check what's already in the CPU queue */
|
|
|
|
while ((irq = xive_scan_interrupts(xc, false)) != 0) {
|
|
|
|
/*
|
|
|
|
* We need to re-route that interrupt to its new destination.
|
|
|
|
* First get and lock the descriptor
|
|
|
|
*/
|
|
|
|
struct irq_desc *desc = irq_to_desc(irq);
|
|
|
|
struct irq_data *d = irq_desc_get_irq_data(desc);
|
|
|
|
struct xive_irq_data *xd;
|
|
|
|
unsigned int hw_irq = (unsigned int)irqd_to_hwirq(d);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Ignore anything that isn't a XIVE irq and ignore
|
|
|
|
* IPIs, so can just be dropped.
|
|
|
|
*/
|
|
|
|
if (d->domain != xive_irq_domain || hw_irq == 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The IRQ should have already been re-routed, it's just a
|
|
|
|
* stale in the old queue, so re-trigger it in order to make
|
|
|
|
* it reach is new destination.
|
|
|
|
*/
|
|
|
|
#ifdef DEBUG_FLUSH
|
|
|
|
pr_info("CPU %d: Got irq %d while offline, re-sending...\n",
|
|
|
|
cpu, irq);
|
|
|
|
#endif
|
|
|
|
raw_spin_lock(&desc->lock);
|
|
|
|
xd = irq_desc_get_handler_data(desc);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* For LSIs, we EOI, this will cause a resend if it's
|
|
|
|
* still asserted. Otherwise do an MSI retrigger.
|
|
|
|
*/
|
|
|
|
if (xd->flags & XIVE_IRQ_FLAG_LSI)
|
|
|
|
xive_do_source_eoi(irqd_to_hwirq(d), xd);
|
|
|
|
else
|
|
|
|
xive_irq_retrigger(d);
|
|
|
|
|
|
|
|
raw_spin_unlock(&desc->lock);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void xive_smp_disable_cpu(void)
|
|
|
|
{
|
|
|
|
struct xive_cpu *xc = __this_cpu_read(xive_cpu);
|
|
|
|
unsigned int cpu = smp_processor_id();
|
|
|
|
|
|
|
|
/* Migrate interrupts away from the CPU */
|
|
|
|
irq_migrate_all_off_this_cpu();
|
|
|
|
|
|
|
|
/* Set CPPR to 0 to disable flow of interrupts */
|
|
|
|
xc->cppr = 0;
|
|
|
|
out_8(xive_tima + xive_tima_offset + TM_CPPR, 0);
|
|
|
|
|
|
|
|
/* Flush everything still in the queue */
|
|
|
|
xive_flush_cpu_queue(cpu, xc);
|
|
|
|
|
|
|
|
/* Re-enable CPPR */
|
|
|
|
xc->cppr = 0xff;
|
|
|
|
out_8(xive_tima + xive_tima_offset + TM_CPPR, 0xff);
|
|
|
|
}
|
|
|
|
|
|
|
|
void xive_flush_interrupt(void)
|
|
|
|
{
|
|
|
|
struct xive_cpu *xc = __this_cpu_read(xive_cpu);
|
|
|
|
unsigned int cpu = smp_processor_id();
|
|
|
|
|
|
|
|
/* Called if an interrupt occurs while the CPU is hot unplugged */
|
|
|
|
xive_flush_cpu_queue(cpu, xc);
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* CONFIG_HOTPLUG_CPU */
|
|
|
|
|
|
|
|
#endif /* CONFIG_SMP */
|
|
|
|
|
powerpc/xive: guest exploitation of the XIVE interrupt controller
This is the framework for using XIVE in a PowerVM guest. The support
is very similar to the native one in a much simpler form.
Each source is associated with an Event State Buffer (ESB). This is a
two bit state machine which is used to trigger events. The bits are
named "P" (pending) and "Q" (queued) and can be controlled by MMIO.
The Guest OS registers event (or notifications) queues on which the HW
will post event data for a target to notify.
Instead of OPAL calls, a set of Hypervisors call are used to configure
the interrupt sources and the event/notification queues of the guest:
- H_INT_GET_SOURCE_INFO
used to obtain the address of the MMIO page of the Event State
Buffer (PQ bits) entry associated with the source.
- H_INT_SET_SOURCE_CONFIG
assigns a source to a "target".
- H_INT_GET_SOURCE_CONFIG
determines to which "target" and "priority" is assigned to a source
- H_INT_GET_QUEUE_INFO
returns the address of the notification management page associated
with the specified "target" and "priority".
- H_INT_SET_QUEUE_CONFIG
sets or resets the event queue for a given "target" and "priority".
It is also used to set the notification config associated with the
queue, only unconditional notification for the moment. Reset is
performed with a queue size of 0 and queueing is disabled in that
case.
- H_INT_GET_QUEUE_CONFIG
returns the queue settings for a given "target" and "priority".
- H_INT_RESET
resets all of the partition's interrupt exploitation structures to
their initial state, losing all configuration set via the hcalls
H_INT_SET_SOURCE_CONFIG and H_INT_SET_QUEUE_CONFIG.
- H_INT_SYNC
issue a synchronisation on a source to make sure sure all
notifications have reached their queue.
As for XICS, the XIVE interface for the guest is described in the
device tree under the "interrupt-controller" node. A couple of new
properties are specific to XIVE :
- "reg"
contains the base address and size of the thread interrupt
managnement areas (TIMA), also called rings, for the User level and
for the Guest OS level. Only the Guest OS level is taken into
account today.
- "ibm,xive-eq-sizes"
the size of the event queues. One cell per size supported, contains
log2 of size, in ascending order.
- "ibm,xive-lisn-ranges"
the interrupt numbers ranges assigned to the guest. These are
allocated using a simple bitmap.
and also :
- "/ibm,plat-res-int-priorities"
contains a list of priorities that the hypervisor has reserved for
its own use.
Tested with a QEMU XIVE model for pseries and with the Power hypervisor.
Signed-off-by: Cédric Le Goater <clg@kaod.org>
Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
2017-08-30 19:46:11 +00:00
|
|
|
void xive_teardown_cpu(void)
|
|
|
|
{
|
|
|
|
struct xive_cpu *xc = __this_cpu_read(xive_cpu);
|
|
|
|
unsigned int cpu = smp_processor_id();
|
|
|
|
|
|
|
|
/* Set CPPR to 0 to disable flow of interrupts */
|
|
|
|
xc->cppr = 0;
|
|
|
|
out_8(xive_tima + xive_tima_offset + TM_CPPR, 0);
|
|
|
|
|
|
|
|
if (xive_ops->teardown_cpu)
|
|
|
|
xive_ops->teardown_cpu(cpu, xc);
|
2017-10-04 09:15:05 +00:00
|
|
|
|
|
|
|
#ifdef CONFIG_SMP
|
|
|
|
/* Get rid of IPI */
|
|
|
|
xive_cleanup_cpu_ipi(cpu, xc);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Disable and free the queues */
|
|
|
|
xive_cleanup_cpu_queues(cpu, xc);
|
powerpc/xive: guest exploitation of the XIVE interrupt controller
This is the framework for using XIVE in a PowerVM guest. The support
is very similar to the native one in a much simpler form.
Each source is associated with an Event State Buffer (ESB). This is a
two bit state machine which is used to trigger events. The bits are
named "P" (pending) and "Q" (queued) and can be controlled by MMIO.
The Guest OS registers event (or notifications) queues on which the HW
will post event data for a target to notify.
Instead of OPAL calls, a set of Hypervisors call are used to configure
the interrupt sources and the event/notification queues of the guest:
- H_INT_GET_SOURCE_INFO
used to obtain the address of the MMIO page of the Event State
Buffer (PQ bits) entry associated with the source.
- H_INT_SET_SOURCE_CONFIG
assigns a source to a "target".
- H_INT_GET_SOURCE_CONFIG
determines to which "target" and "priority" is assigned to a source
- H_INT_GET_QUEUE_INFO
returns the address of the notification management page associated
with the specified "target" and "priority".
- H_INT_SET_QUEUE_CONFIG
sets or resets the event queue for a given "target" and "priority".
It is also used to set the notification config associated with the
queue, only unconditional notification for the moment. Reset is
performed with a queue size of 0 and queueing is disabled in that
case.
- H_INT_GET_QUEUE_CONFIG
returns the queue settings for a given "target" and "priority".
- H_INT_RESET
resets all of the partition's interrupt exploitation structures to
their initial state, losing all configuration set via the hcalls
H_INT_SET_SOURCE_CONFIG and H_INT_SET_QUEUE_CONFIG.
- H_INT_SYNC
issue a synchronisation on a source to make sure sure all
notifications have reached their queue.
As for XICS, the XIVE interface for the guest is described in the
device tree under the "interrupt-controller" node. A couple of new
properties are specific to XIVE :
- "reg"
contains the base address and size of the thread interrupt
managnement areas (TIMA), also called rings, for the User level and
for the Guest OS level. Only the Guest OS level is taken into
account today.
- "ibm,xive-eq-sizes"
the size of the event queues. One cell per size supported, contains
log2 of size, in ascending order.
- "ibm,xive-lisn-ranges"
the interrupt numbers ranges assigned to the guest. These are
allocated using a simple bitmap.
and also :
- "/ibm,plat-res-int-priorities"
contains a list of priorities that the hypervisor has reserved for
its own use.
Tested with a QEMU XIVE model for pseries and with the Power hypervisor.
Signed-off-by: Cédric Le Goater <clg@kaod.org>
Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
2017-08-30 19:46:11 +00:00
|
|
|
}
|
|
|
|
|
2017-04-05 07:54:50 +00:00
|
|
|
void xive_kexec_teardown_cpu(int secondary)
|
|
|
|
{
|
|
|
|
struct xive_cpu *xc = __this_cpu_read(xive_cpu);
|
|
|
|
unsigned int cpu = smp_processor_id();
|
|
|
|
|
|
|
|
/* Set CPPR to 0 to disable flow of interrupts */
|
|
|
|
xc->cppr = 0;
|
|
|
|
out_8(xive_tima + xive_tima_offset + TM_CPPR, 0);
|
|
|
|
|
|
|
|
/* Backend cleanup if any */
|
|
|
|
if (xive_ops->teardown_cpu)
|
|
|
|
xive_ops->teardown_cpu(cpu, xc);
|
|
|
|
|
|
|
|
#ifdef CONFIG_SMP
|
|
|
|
/* Get rid of IPI */
|
|
|
|
xive_cleanup_cpu_ipi(cpu, xc);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Disable and free the queues */
|
|
|
|
xive_cleanup_cpu_queues(cpu, xc);
|
|
|
|
}
|
|
|
|
|
|
|
|
void xive_shutdown(void)
|
|
|
|
{
|
|
|
|
xive_ops->shutdown();
|
|
|
|
}
|
|
|
|
|
2017-08-08 11:44:14 +00:00
|
|
|
bool __init xive_core_init(const struct xive_ops *ops, void __iomem *area, u32 offset,
|
|
|
|
u8 max_prio)
|
2017-04-05 07:54:50 +00:00
|
|
|
{
|
|
|
|
xive_tima = area;
|
|
|
|
xive_tima_offset = offset;
|
|
|
|
xive_ops = ops;
|
|
|
|
xive_irq_priority = max_prio;
|
|
|
|
|
|
|
|
ppc_md.get_irq = xive_get_irq;
|
|
|
|
__xive_enabled = true;
|
|
|
|
|
|
|
|
pr_devel("Initializing host..\n");
|
|
|
|
xive_init_host();
|
|
|
|
|
|
|
|
pr_devel("Initializing boot CPU..\n");
|
|
|
|
|
|
|
|
/* Allocate per-CPU data and queues */
|
|
|
|
xive_prepare_cpu(smp_processor_id());
|
|
|
|
|
|
|
|
/* Get ready for interrupts */
|
|
|
|
xive_setup_cpu();
|
|
|
|
|
2017-06-05 06:49:12 +00:00
|
|
|
pr_info("Interrupt handling initialized with %s backend\n",
|
2017-04-05 07:54:50 +00:00
|
|
|
xive_ops->name);
|
|
|
|
pr_info("Using priority %d for all interrupts\n", max_prio);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-08-30 19:46:10 +00:00
|
|
|
__be32 *xive_queue_page_alloc(unsigned int cpu, u32 queue_shift)
|
|
|
|
{
|
|
|
|
unsigned int alloc_order;
|
|
|
|
struct page *pages;
|
|
|
|
__be32 *qpage;
|
|
|
|
|
|
|
|
alloc_order = xive_alloc_order(queue_shift);
|
|
|
|
pages = alloc_pages_node(cpu_to_node(cpu), GFP_KERNEL, alloc_order);
|
|
|
|
if (!pages)
|
|
|
|
return ERR_PTR(-ENOMEM);
|
|
|
|
qpage = (__be32 *)page_address(pages);
|
|
|
|
memset(qpage, 0, 1 << queue_shift);
|
|
|
|
|
|
|
|
return qpage;
|
|
|
|
}
|
|
|
|
|
2017-04-05 07:54:50 +00:00
|
|
|
static int __init xive_off(char *arg)
|
|
|
|
{
|
|
|
|
xive_cmdline_disabled = true;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
__setup("xive=off", xive_off);
|