aboutsummaryrefslogtreecommitdiff
path: root/arch/sparc64/kernel/irq.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@sunset.davemloft.net>2007-08-30 22:33:25 -0700
committerDavid S. Miller <davem@sunset.davemloft.net>2007-10-13 21:53:09 -0700
commit9bb3c227c47b23280eb50fac0872d96ef3e160a7 (patch)
treec519fa5e544bc1df018eafecb3563c7ce1b3c43b /arch/sparc64/kernel/irq.c
parentf9c97e5d7cd9ff5e51e16d5db08d7e54fa4cb6bb (diff)
[SPARC64]: Enable MSI on sun4u Fire PCI-E controllers.
The support code is identical to the hypervisor sun4v stuff, just replacing the hypervisor calls with register reads and writes in the Fire controller. Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/sparc64/kernel/irq.c')
-rw-r--r--arch/sparc64/kernel/irq.c71
1 files changed, 71 insertions, 0 deletions
diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c
index 23956096b3b..7f5a4c77e3e 100644
--- a/arch/sparc64/kernel/irq.c
+++ b/arch/sparc64/kernel/irq.c
@@ -406,6 +406,18 @@ static void sun4v_irq_disable(unsigned int virt_irq)
}
#ifdef CONFIG_PCI_MSI
+static void sun4u_msi_enable(unsigned int virt_irq)
+{
+ sun4u_irq_enable(virt_irq);
+ unmask_msi_irq(virt_irq);
+}
+
+static void sun4u_msi_disable(unsigned int virt_irq)
+{
+ mask_msi_irq(virt_irq);
+ sun4u_irq_disable(virt_irq);
+}
+
static void sun4v_msi_enable(unsigned int virt_irq)
{
sun4v_irq_enable(virt_irq);
@@ -583,6 +595,17 @@ static struct irq_chip sun4v_irq_ack = {
};
#ifdef CONFIG_PCI_MSI
+static struct irq_chip sun4u_msi = {
+ .typename = "sun4u+msi",
+ .mask = mask_msi_irq,
+ .unmask = unmask_msi_irq,
+ .enable = sun4u_msi_enable,
+ .disable = sun4u_msi_disable,
+ .ack = run_pre_handler,
+ .end = sun4u_irq_end,
+ .set_affinity = sun4u_set_affinity,
+};
+
static struct irq_chip sun4v_msi = {
.typename = "sun4v+msi",
.mask = mask_msi_irq,
@@ -628,6 +651,7 @@ void irq_install_pre_handler(int virt_irq,
chip == &sun4v_irq_ack ||
chip == &sun4v_virq_ack
#ifdef CONFIG_PCI_MSI
+ || chip == &sun4u_msi
|| chip == &sun4v_msi
#endif
)
@@ -789,6 +813,53 @@ void sun4v_destroy_msi(unsigned int virt_irq)
{
virt_irq_free(virt_irq);
}
+
+unsigned int sun4u_build_msi(u32 portid, unsigned int *virt_irq_p,
+ unsigned int msi_start, unsigned int msi_end,
+ unsigned long imap_base, unsigned long iclr_base)
+{
+ struct ino_bucket *bucket;
+ struct irq_handler_data *data;
+ unsigned long sysino;
+ unsigned int devino;
+
+ /* Find a free devino in the given range. */
+ for (devino = msi_start; devino < msi_end; devino++) {
+ sysino = (portid << 6) | devino;
+ bucket = &ivector_table[sysino];
+ if (!bucket->virt_irq)
+ break;
+ }
+ if (devino >= msi_end)
+ return -ENOSPC;
+
+ sysino = (portid << 6) | 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, &sun4u_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)) {
+ virt_irq_free(*virt_irq_p);
+ return -ENOMEM;
+ }
+ set_irq_chip_data(bucket->virt_irq, data);
+
+ data->imap = (imap_base + (devino * 0x8UL));
+ data->iclr = (iclr_base + (devino * 0x8UL));
+
+ return devino;
+}
+
+void sun4u_destroy_msi(unsigned int virt_irq)
+{
+ virt_irq_free(virt_irq);
+}
#endif
void ack_bad_irq(unsigned int virt_irq)