Commit 4a907dec authored by David S. Miller's avatar David S. Miller

[SPARC64]: Wire up cookie based sun4v interrupt registry.

This will be used for logical domain channel interrupts.
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent a0e1d1d0
/* $Id: irq.c,v 1.114 2002/01/11 08:45:38 davem Exp $
* irq.c: UltraSparc IRQ handling/init/registry.
/* irq.c: UltraSparc IRQ handling/init/registry.
*
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
* Copyright (C) 1997, 2007 David S. Miller (davem@davemloft.net)
* Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be)
* Copyright (C) 1998 Jakub Jelinek (jj@ultra.linux.cz)
*/
......@@ -43,6 +42,7 @@
#include <asm/cpudata.h>
#include <asm/auxio.h>
#include <asm/head.h>
#include <asm/hypervisor.h>
/* UPA nodes send interrupt packet to UltraSparc with first data reg
* value low 5 (7 on Starfire) bits holding the IRQ identifier being
......@@ -380,6 +380,76 @@ static void sun4v_irq_end(unsigned int virt_irq)
}
}
static void sun4v_virq_enable(unsigned int virt_irq)
{
struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
unsigned int ino = bucket - &ivector_table[0];
if (likely(bucket)) {
unsigned long cpuid, dev_handle, dev_ino;
int err;
cpuid = irq_choose_cpu(virt_irq);
dev_handle = ino & IMAP_IGN;
dev_ino = ino & IMAP_INO;
err = sun4v_vintr_set_target(dev_handle, dev_ino, cpuid);
if (err != HV_EOK)
printk("sun4v_vintr_set_target(%lx,%lx,%lu): "
"err(%d)\n",
dev_handle, dev_ino, cpuid, err);
err = sun4v_vintr_set_state(dev_handle, dev_ino,
HV_INTR_ENABLED);
if (err != HV_EOK)
printk("sun4v_vintr_set_state(%lx,%lx,"
"HV_INTR_ENABLED): err(%d)\n",
dev_handle, dev_ino, err);
}
}
static void sun4v_virq_disable(unsigned int virt_irq)
{
struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
unsigned int ino = bucket - &ivector_table[0];
if (likely(bucket)) {
unsigned long dev_handle, dev_ino;
int err;
dev_handle = ino & IMAP_IGN;
dev_ino = ino & IMAP_INO;
err = sun4v_vintr_set_state(dev_handle, dev_ino,
HV_INTR_DISABLED);
if (err != HV_EOK)
printk("sun4v_vintr_set_state(%lx,%lx,"
"HV_INTR_DISABLED): err(%d)\n",
dev_handle, dev_ino, err);
}
}
static void sun4v_virq_end(unsigned int virt_irq)
{
struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
unsigned int ino = bucket - &ivector_table[0];
if (likely(bucket)) {
unsigned long dev_handle, dev_ino;
int err;
dev_handle = ino & IMAP_IGN;
dev_ino = ino & IMAP_INO;
err = sun4v_vintr_set_state(dev_handle, dev_ino,
HV_INTR_STATE_IDLE);
if (err != HV_EOK)
printk("sun4v_vintr_set_state(%lx,%lx,"
"HV_INTR_STATE_IDLE): err(%d)\n",
dev_handle, dev_ino, err);
}
}
static void run_pre_handler(unsigned int virt_irq)
{
struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
......@@ -434,6 +504,21 @@ static struct irq_chip sun4v_msi = {
};
#endif
static struct irq_chip sun4v_virq = {
.typename = "vsun4v",
.enable = sun4v_virq_enable,
.disable = sun4v_virq_disable,
.end = sun4v_virq_end,
};
static struct irq_chip sun4v_virq_ack = {
.typename = "vsun4v+ack",
.enable = sun4v_virq_enable,
.disable = sun4v_virq_disable,
.ack = run_pre_handler,
.end = sun4v_virq_end,
};
void irq_install_pre_handler(int virt_irq,
void (*func)(unsigned int, void *, void *),
void *arg1, void *arg2)
......@@ -447,7 +532,8 @@ void irq_install_pre_handler(int virt_irq,
chip = get_irq_chip(virt_irq);
if (chip == &sun4u_irq_ack ||
chip == &sun4v_irq_ack
chip == &sun4v_irq_ack ||
chip == &sun4v_virq_ack
#ifdef CONFIG_PCI_MSI
|| chip == &sun4v_msi
#endif
......@@ -455,7 +541,9 @@ void irq_install_pre_handler(int virt_irq,
return;
chip = (chip == &sun4u_irq ?
&sun4u_irq_ack : &sun4v_irq_ack);
&sun4u_irq_ack :
(chip == &sun4v_irq ?
&sun4v_irq_ack : &sun4v_virq_ack));
set_irq_chip(virt_irq, chip);
}
......@@ -492,19 +580,18 @@ unsigned int build_irq(int inofixup, unsigned long iclr, unsigned long imap)
return bucket->virt_irq;
}
unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino)
static unsigned int sun4v_build_common(unsigned long sysino,
struct irq_chip *chip)
{
struct ino_bucket *bucket;
struct irq_handler_data *data;
unsigned long sysino;
BUG_ON(tlb_type != hypervisor);
sysino = sun4v_devino_to_sysino(devhandle, devino);
bucket = &ivector_table[sysino];
if (!bucket->virt_irq) {
bucket->virt_irq = virt_irq_alloc(__irq(bucket));
set_irq_chip(bucket->virt_irq, &sun4v_irq);
set_irq_chip(bucket->virt_irq, chip);
}
data = get_irq_chip_data(bucket->virt_irq);
......@@ -529,6 +616,32 @@ unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino)
return bucket->virt_irq;
}
unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino)
{
unsigned long sysino = sun4v_devino_to_sysino(devhandle, devino);
return sun4v_build_common(sysino, &sun4v_irq);
}
unsigned int sun4v_build_virq(u32 devhandle, unsigned int devino)
{
unsigned long sysino, hv_err;
BUG_ON(devhandle & ~IMAP_IGN);
BUG_ON(devino & ~IMAP_INO);
sysino = devhandle | devino;
hv_err = sun4v_vintr_set_cookie(devhandle, devino, sysino);
if (hv_err) {
prom_printf("IRQ: Fatal, cannot set cookie for [%x:%x] "
"err=%lu\n", devhandle, devino, hv_err);
prom_halt();
}
return sun4v_build_common(sysino, &sun4v_virq);
}
#ifdef CONFIG_PCI_MSI
unsigned int sun4v_build_msi(u32 devhandle, unsigned int *virt_irq_p,
unsigned int msi_start, unsigned int msi_end)
......
......@@ -46,6 +46,7 @@ extern void irq_install_pre_handler(int virt_irq,
#define irq_canonicalize(irq) (irq)
extern unsigned int build_irq(int inofixup, unsigned long iclr, unsigned long imap);
extern unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino);
extern unsigned int sun4v_build_virq(u32 devhandle, unsigned int devino);
extern unsigned int sun4v_build_msi(u32 devhandle, unsigned int *virt_irq_p,
unsigned int msi_devino_start,
unsigned int msi_devino_end);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment