diff options
author | David S. Miller <davem@sunset.davemloft.net> | 2007-08-31 01:33:25 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2007-10-14 00:53:09 -0400 |
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 23956096b3bf..7f5a4c77e3e4 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) | |||
406 | } | 406 | } |
407 | 407 | ||
408 | #ifdef CONFIG_PCI_MSI | 408 | #ifdef CONFIG_PCI_MSI |
409 | static void sun4u_msi_enable(unsigned int virt_irq) | ||
410 | { | ||
411 | sun4u_irq_enable(virt_irq); | ||
412 | unmask_msi_irq(virt_irq); | ||
413 | } | ||
414 | |||
415 | static void sun4u_msi_disable(unsigned int virt_irq) | ||
416 | { | ||
417 | mask_msi_irq(virt_irq); | ||
418 | sun4u_irq_disable(virt_irq); | ||
419 | } | ||
420 | |||
409 | static void sun4v_msi_enable(unsigned int virt_irq) | 421 | static void sun4v_msi_enable(unsigned int virt_irq) |
410 | { | 422 | { |
411 | sun4v_irq_enable(virt_irq); | 423 | sun4v_irq_enable(virt_irq); |
@@ -583,6 +595,17 @@ static struct irq_chip sun4v_irq_ack = { | |||
583 | }; | 595 | }; |
584 | 596 | ||
585 | #ifdef CONFIG_PCI_MSI | 597 | #ifdef CONFIG_PCI_MSI |
598 | static struct irq_chip sun4u_msi = { | ||
599 | .typename = "sun4u+msi", | ||
600 | .mask = mask_msi_irq, | ||
601 | .unmask = unmask_msi_irq, | ||
602 | .enable = sun4u_msi_enable, | ||
603 | .disable = sun4u_msi_disable, | ||
604 | .ack = run_pre_handler, | ||
605 | .end = sun4u_irq_end, | ||
606 | .set_affinity = sun4u_set_affinity, | ||
607 | }; | ||
608 | |||
586 | static struct irq_chip sun4v_msi = { | 609 | static struct irq_chip sun4v_msi = { |
587 | .typename = "sun4v+msi", | 610 | .typename = "sun4v+msi", |
588 | .mask = mask_msi_irq, | 611 | .mask = mask_msi_irq, |
@@ -628,6 +651,7 @@ void irq_install_pre_handler(int virt_irq, | |||
628 | chip == &sun4v_irq_ack || | 651 | chip == &sun4v_irq_ack || |
629 | chip == &sun4v_virq_ack | 652 | chip == &sun4v_virq_ack |
630 | #ifdef CONFIG_PCI_MSI | 653 | #ifdef CONFIG_PCI_MSI |
654 | || chip == &sun4u_msi | ||
631 | || chip == &sun4v_msi | 655 | || chip == &sun4v_msi |
632 | #endif | 656 | #endif |
633 | ) | 657 | ) |
@@ -789,6 +813,53 @@ void sun4v_destroy_msi(unsigned int virt_irq) | |||
789 | { | 813 | { |
790 | virt_irq_free(virt_irq); | 814 | virt_irq_free(virt_irq); |
791 | } | 815 | } |
816 | |||
817 | unsigned int sun4u_build_msi(u32 portid, unsigned int *virt_irq_p, | ||
818 | unsigned int msi_start, unsigned int msi_end, | ||
819 | unsigned long imap_base, unsigned long iclr_base) | ||
820 | { | ||
821 | struct ino_bucket *bucket; | ||
822 | struct irq_handler_data *data; | ||
823 | unsigned long sysino; | ||
824 | unsigned int devino; | ||
825 | |||
826 | /* Find a free devino in the given range. */ | ||
827 | for (devino = msi_start; devino < msi_end; devino++) { | ||
828 | sysino = (portid << 6) | devino; | ||
829 | bucket = &ivector_table[sysino]; | ||
830 | if (!bucket->virt_irq) | ||
831 | break; | ||
832 | } | ||
833 | if (devino >= msi_end) | ||
834 | return -ENOSPC; | ||
835 | |||
836 | sysino = (portid << 6) | devino; | ||
837 | bucket = &ivector_table[sysino]; | ||
838 | bucket->virt_irq = virt_irq_alloc(__irq(bucket)); | ||
839 | *virt_irq_p = bucket->virt_irq; | ||
840 | set_irq_chip(bucket->virt_irq, &sun4u_msi); | ||
841 | |||
842 | data = get_irq_chip_data(bucket->virt_irq); | ||
843 | if (unlikely(data)) | ||
844 | return devino; | ||
845 | |||
846 | data = kzalloc(sizeof(struct irq_handler_data), GFP_ATOMIC); | ||
847 | if (unlikely(!data)) { | ||
848 | virt_irq_free(*virt_irq_p); | ||
849 | return -ENOMEM; | ||
850 | } | ||
851 | set_irq_chip_data(bucket->virt_irq, data); | ||
852 | |||
853 | data->imap = (imap_base + (devino * 0x8UL)); | ||
854 | data->iclr = (iclr_base + (devino * 0x8UL)); | ||
855 | |||
856 | return devino; | ||
857 | } | ||
858 | |||
859 | void sun4u_destroy_msi(unsigned int virt_irq) | ||
860 | { | ||
861 | virt_irq_free(virt_irq); | ||
862 | } | ||
792 | #endif | 863 | #endif |
793 | 864 | ||
794 | void ack_bad_irq(unsigned int virt_irq) | 865 | void ack_bad_irq(unsigned int virt_irq) |