diff options
author | David S. Miller <davem@sunset.davemloft.net> | 2007-08-30 22:33:25 -0700 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2007-10-13 21:53:09 -0700 |
commit | 9bb3c227c47b23280eb50fac0872d96ef3e160a7 (patch) | |
tree | c519fa5e544bc1df018eafecb3563c7ce1b3c43b /arch/sparc64/kernel/irq.c | |
parent | f9c97e5d7cd9ff5e51e16d5db08d7e54fa4cb6bb (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.c | 71 |
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) |