Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 47641
b: refs/heads/master
c: 35a17eb
h: refs/heads/master
i:
  47639: 4178b5e
v: v3
  • Loading branch information
David S. Miller committed Feb 11, 2007
1 parent 19f57a7 commit b92b2ef
Show file tree
Hide file tree
Showing 9 changed files with 935 additions and 11 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 68c921869491c119142612fa5796c9f8b4e9970b
refs/heads/master: 35a17eb6a87c9ceb0d35dcb51f464fe6faf584ab
104 changes: 95 additions & 9 deletions trunk/arch/sparc64/kernel/irq.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include <linux/seq_file.h>
#include <linux/bootmem.h>
#include <linux/irq.h>
#include <linux/msi.h>

#include <asm/ptrace.h>
#include <asm/processor.h>
Expand Down Expand Up @@ -87,34 +88,39 @@ struct ino_bucket ivector_table[NUM_IVECS] __attribute__ ((aligned (SMP_CACHE_BY
#define irq_work(__cpu) &(trap_block[(__cpu)].irq_worklist)

static unsigned int virt_to_real_irq_table[NR_IRQS];
static unsigned char virt_irq_cur = 1;

static unsigned char virt_irq_alloc(unsigned int real_irq)
{
unsigned char ent;

BUILD_BUG_ON(NR_IRQS >= 256);

ent = virt_irq_cur;
for (ent = 1; ent < NR_IRQS; ent++) {
if (!virt_to_real_irq_table[ent])
break;
}
if (ent >= NR_IRQS) {
printk(KERN_ERR "IRQ: Out of virtual IRQs.\n");
return 0;
}

virt_irq_cur = ent + 1;
virt_to_real_irq_table[ent] = real_irq;

return ent;
}

#if 0 /* Currently unused. */
static unsigned char real_to_virt_irq(unsigned int real_irq)
static void virt_irq_free(unsigned int virt_irq)
{
struct ino_bucket *bucket = __bucket(real_irq);
unsigned int real_irq;

return bucket->virt_irq;
if (virt_irq >= NR_IRQS)
return;

real_irq = virt_to_real_irq_table[virt_irq];
virt_to_real_irq_table[virt_irq] = 0;

__bucket(real_irq)->virt_irq = 0;
}
#endif

static unsigned int virt_to_real_irq(unsigned char virt_irq)
{
Expand Down Expand Up @@ -341,6 +347,20 @@ static void sun4v_irq_disable(unsigned int virt_irq)
}
}

#ifdef CONFIG_PCI_MSI
static void sun4v_msi_enable(unsigned int virt_irq)
{
sun4v_irq_enable(virt_irq);
unmask_msi_irq(virt_irq);
}

static void sun4v_msi_disable(unsigned int virt_irq)
{
mask_msi_irq(virt_irq);
sun4v_irq_disable(virt_irq);
}
#endif

static void sun4v_irq_end(unsigned int virt_irq)
{
struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
Expand Down Expand Up @@ -398,6 +418,18 @@ static struct irq_chip sun4v_irq_ack = {
.end = sun4v_irq_end,
};

#ifdef CONFIG_PCI_MSI
static struct irq_chip sun4v_msi = {
.typename = "sun4v+msi",
.mask = mask_msi_irq,
.unmask = unmask_msi_irq,
.enable = sun4v_msi_enable,
.disable = sun4v_msi_disable,
.ack = run_pre_handler,
.end = sun4v_irq_end,
};
#endif

void irq_install_pre_handler(int virt_irq,
void (*func)(unsigned int, void *, void *),
void *arg1, void *arg2)
Expand All @@ -411,7 +443,11 @@ 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
#ifdef CONFIG_PCI_MSI
|| chip == &sun4v_msi
#endif
)
return;

chip = (chip == &sun4u_irq ?
Expand Down Expand Up @@ -489,6 +525,56 @@ unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino)
return bucket->virt_irq;
}

#ifdef CONFIG_PCI_MSI
unsigned int sun4v_build_msi(u32 devhandle, unsigned int *virt_irq_p,
unsigned int msi_start, unsigned int msi_end)
{
struct ino_bucket *bucket;
struct irq_handler_data *data;
unsigned long sysino;
unsigned int devino;

BUG_ON(tlb_type != hypervisor);

/* Find a free devino in the given range. */
for (devino = msi_start; devino < msi_end; devino++) {
sysino = sun4v_devino_to_sysino(devhandle, devino);
bucket = &ivector_table[sysino];
if (!bucket->virt_irq)
break;
}
if (devino >= msi_end)
return 0;

sysino = sun4v_devino_to_sysino(devhandle, devino);
bucket = &ivector_table[sysino];
bucket->virt_irq = virt_irq_alloc(__irq(bucket));
*virt_irq_p = bucket->virt_irq;
set_irq_chip(bucket->virt_irq, &sun4v_msi);

data = get_irq_chip_data(bucket->virt_irq);
if (unlikely(data))
return devino;

data = kzalloc(sizeof(struct irq_handler_data), GFP_ATOMIC);
if (unlikely(!data)) {
prom_printf("IRQ: kzalloc(irq_handler_data) failed.\n");
prom_halt();
}
set_irq_chip_data(bucket->virt_irq, data);

data->imap = ~0UL;
data->iclr = ~0UL;

return devino;
}

void sun4v_destroy_msi(unsigned int virt_irq)
{
virt_irq_free(virt_irq);
}
#endif

void ack_bad_irq(unsigned int virt_irq)
{
struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
Expand Down
35 changes: 35 additions & 0 deletions trunk/arch/sparc64/kernel/pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
#include <linux/capability.h>
#include <linux/errno.h>
#include <linux/smp_lock.h>
#include <linux/msi.h>
#include <linux/irq.h>
#include <linux/init.h>

#include <asm/uaccess.h>
Expand Down Expand Up @@ -646,4 +648,37 @@ int pci_domain_nr(struct pci_bus *pbus)
}
EXPORT_SYMBOL(pci_domain_nr);

#ifdef CONFIG_PCI_MSI
int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc)
{
struct pcidev_cookie *pcp = pdev->sysdata;
struct pci_pbm_info *pbm = pcp->pbm;
struct pci_controller_info *p = pbm->parent;
int virt_irq, err;

if (!pbm->msi_num || !p->setup_msi_irq)
return -EINVAL;

err = p->setup_msi_irq(&virt_irq, pdev, desc);
if (err < 0)
return err;

return virt_irq;
}

void arch_teardown_msi_irq(unsigned int virt_irq)
{
struct msi_desc *entry = get_irq_data(virt_irq);
struct pci_dev *pdev = entry->dev;
struct pcidev_cookie *pcp = pdev->sysdata;
struct pci_pbm_info *pbm = pcp->pbm;
struct pci_controller_info *p = pbm->parent;

if (!pbm->msi_num || !p->setup_msi_irq)
return;

return p->teardown_msi_irq(virt_irq, pdev);
}
#endif /* !(CONFIG_PCI_MSI) */

#endif /* !(CONFIG_PCI) */
Loading

0 comments on commit b92b2ef

Please sign in to comment.