aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc64/kernel/prom.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@sunset.davemloft.net>2007-05-02 20:31:36 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2007-05-07 01:44:06 -0400
commit861fe90656b8e20d750d73c57088dc52d316ce7b (patch)
tree3f7df274478242ecf9f4186637c9cc38f59b5b8a /arch/sparc64/kernel/prom.c
parent4cad69174f385c183b2bcb369fb4304d8624ab96 (diff)
[SPARC64]: SUN4U PCI-E controller support.
Some minor refactoring in the generic code was necessary for this: 1) This controller requires 8-byte access to the interrupt map and clear register. They are 64-bits on all the other SBUS and PCI controllers anyways, so this was easy to cure. 2) The IMAP register has a different layout and some bits that we need to preserve, so use a read/modify/write when making changes to the IMAP register in generic code. 3) Flushing the entire IOMMU TLB is best done with a single write to a register on this PCI controller, add a iommu->iommu_flushinv for this. Still lacks MSI support, that will come later. Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/sparc64/kernel/prom.c')
-rw-r--r--arch/sparc64/kernel/prom.c89
1 files changed, 83 insertions, 6 deletions
diff --git a/arch/sparc64/kernel/prom.c b/arch/sparc64/kernel/prom.c
index 5e1fcd05160d..6625ac8d15fe 100644
--- a/arch/sparc64/kernel/prom.c
+++ b/arch/sparc64/kernel/prom.c
@@ -386,11 +386,9 @@ static unsigned int psycho_irq_build(struct device_node *dp,
386 386
387 /* Now build the IRQ bucket. */ 387 /* Now build the IRQ bucket. */
388 imap = controller_regs + imap_off; 388 imap = controller_regs + imap_off;
389 imap += 4;
390 389
391 iclr_off = psycho_iclr_offset(ino); 390 iclr_off = psycho_iclr_offset(ino);
392 iclr = controller_regs + iclr_off; 391 iclr = controller_regs + iclr_off;
393 iclr += 4;
394 392
395 if ((ino & 0x20) == 0) 393 if ((ino & 0x20) == 0)
396 inofixup = ino & 0x03; 394 inofixup = ino & 0x03;
@@ -613,11 +611,9 @@ static unsigned int sabre_irq_build(struct device_node *dp,
613 611
614 /* Now build the IRQ bucket. */ 612 /* Now build the IRQ bucket. */
615 imap = controller_regs + imap_off; 613 imap = controller_regs + imap_off;
616 imap += 4;
617 614
618 iclr_off = sabre_iclr_offset(ino); 615 iclr_off = sabre_iclr_offset(ino);
619 iclr = controller_regs + iclr_off; 616 iclr = controller_regs + iclr_off;
620 iclr += 4;
621 617
622 if ((ino & 0x20) == 0) 618 if ((ino & 0x20) == 0)
623 inofixup = ino & 0x03; 619 inofixup = ino & 0x03;
@@ -679,13 +675,14 @@ static unsigned long schizo_iclr_offset(unsigned long ino)
679static unsigned long schizo_ino_to_iclr(unsigned long pbm_regs, 675static unsigned long schizo_ino_to_iclr(unsigned long pbm_regs,
680 unsigned int ino) 676 unsigned int ino)
681{ 677{
682 return pbm_regs + schizo_iclr_offset(ino) + 4; 678
679 return pbm_regs + schizo_iclr_offset(ino);
683} 680}
684 681
685static unsigned long schizo_ino_to_imap(unsigned long pbm_regs, 682static unsigned long schizo_ino_to_imap(unsigned long pbm_regs,
686 unsigned int ino) 683 unsigned int ino)
687{ 684{
688 return pbm_regs + schizo_imap_offset(ino) + 4; 685 return pbm_regs + schizo_imap_offset(ino);
689} 686}
690 687
691#define schizo_read(__reg) \ 688#define schizo_read(__reg) \
@@ -848,6 +845,85 @@ static void pci_sun4v_irq_trans_init(struct device_node *dp)
848 dp->irq_trans->data = (void *) (unsigned long) 845 dp->irq_trans->data = (void *) (unsigned long)
849 ((regs->phys_addr >> 32UL) & 0x0fffffff); 846 ((regs->phys_addr >> 32UL) & 0x0fffffff);
850} 847}
848
849struct fire_irq_data {
850 unsigned long pbm_regs;
851 u32 portid;
852};
853
854#define FIRE_IMAP_BASE 0x001000
855#define FIRE_ICLR_BASE 0x001400
856
857static unsigned long fire_imap_offset(unsigned long ino)
858{
859 return FIRE_IMAP_BASE + (ino * 8UL);
860}
861
862static unsigned long fire_iclr_offset(unsigned long ino)
863{
864 return FIRE_ICLR_BASE + (ino * 8UL);
865}
866
867static unsigned long fire_ino_to_iclr(unsigned long pbm_regs,
868 unsigned int ino)
869{
870 return pbm_regs + fire_iclr_offset(ino);
871}
872
873static unsigned long fire_ino_to_imap(unsigned long pbm_regs,
874 unsigned int ino)
875{
876 return pbm_regs + fire_imap_offset(ino);
877}
878
879static unsigned int fire_irq_build(struct device_node *dp,
880 unsigned int ino,
881 void *_data)
882{
883 struct fire_irq_data *irq_data = _data;
884 unsigned long pbm_regs = irq_data->pbm_regs;
885 unsigned long imap, iclr;
886 unsigned long int_ctrlr;
887
888 ino &= 0x3f;
889
890 /* Now build the IRQ bucket. */
891 imap = fire_ino_to_imap(pbm_regs, ino);
892 iclr = fire_ino_to_iclr(pbm_regs, ino);
893
894 /* Set the interrupt controller number. */
895 int_ctrlr = 1 << 6;
896 upa_writeq(int_ctrlr, imap);
897
898 /* The interrupt map registers do not have an INO field
899 * like other chips do. They return zero in the INO
900 * field, and the interrupt controller number is controlled
901 * in bits 6 thru 9. So in order for build_irq() to get
902 * the INO right we pass it in as part of the fixup
903 * which will get added to the map register zero value
904 * read by build_irq().
905 */
906 ino |= (irq_data->portid << 6);
907 ino -= int_ctrlr;
908 return build_irq(ino, iclr, imap);
909}
910
911static void fire_irq_trans_init(struct device_node *dp)
912{
913 const struct linux_prom64_registers *regs;
914 struct fire_irq_data *irq_data;
915
916 dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
917 dp->irq_trans->irq_build = fire_irq_build;
918
919 irq_data = prom_early_alloc(sizeof(struct fire_irq_data));
920
921 regs = of_get_property(dp, "reg", NULL);
922 dp->irq_trans->data = irq_data;
923
924 irq_data->pbm_regs = regs[0].phys_addr;
925 irq_data->portid = of_getintprop_default(dp, "portid", 0);
926}
851#endif /* CONFIG_PCI */ 927#endif /* CONFIG_PCI */
852 928
853#ifdef CONFIG_SBUS 929#ifdef CONFIG_SBUS
@@ -1069,6 +1145,7 @@ static struct irq_trans pci_irq_trans_table[] = {
1069 { "SUNW,tomatillo", tomatillo_irq_trans_init }, 1145 { "SUNW,tomatillo", tomatillo_irq_trans_init },
1070 { "pci108e,a801", tomatillo_irq_trans_init }, 1146 { "pci108e,a801", tomatillo_irq_trans_init },
1071 { "SUNW,sun4v-pci", pci_sun4v_irq_trans_init }, 1147 { "SUNW,sun4v-pci", pci_sun4v_irq_trans_init },
1148 { "pciex108e,80f0", fire_irq_trans_init },
1072}; 1149};
1073#endif 1150#endif
1074 1151