diff options
Diffstat (limited to 'arch/sparc64')
-rw-r--r-- | arch/sparc64/kernel/pci_sun4v.c | 116 |
1 files changed, 102 insertions, 14 deletions
diff --git a/arch/sparc64/kernel/pci_sun4v.c b/arch/sparc64/kernel/pci_sun4v.c index dc79b748feaf..5174346ce35d 100644 --- a/arch/sparc64/kernel/pci_sun4v.c +++ b/arch/sparc64/kernel/pci_sun4v.c | |||
@@ -538,6 +538,12 @@ static int pci_sun4v_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn, | |||
538 | ret = pci_sun4v_config_get(devhandle, | 538 | ret = pci_sun4v_config_get(devhandle, |
539 | HV_PCI_DEVICE_BUILD(bus, device, func), | 539 | HV_PCI_DEVICE_BUILD(bus, device, func), |
540 | where, size); | 540 | where, size); |
541 | #if 0 | ||
542 | printk("read_pci_cfg: devh[%x] device[%08x] where[%x] sz[%d] " | ||
543 | "== [%016lx]\n", | ||
544 | devhandle, HV_PCI_DEVICE_BUILD(bus, device, func), | ||
545 | where, size, ret); | ||
546 | #endif | ||
541 | } | 547 | } |
542 | switch (size) { | 548 | switch (size) { |
543 | case 1: | 549 | case 1: |
@@ -571,6 +577,12 @@ static int pci_sun4v_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn, | |||
571 | ret = pci_sun4v_config_put(devhandle, | 577 | ret = pci_sun4v_config_put(devhandle, |
572 | HV_PCI_DEVICE_BUILD(bus, device, func), | 578 | HV_PCI_DEVICE_BUILD(bus, device, func), |
573 | where, size, value); | 579 | where, size, value); |
580 | #if 0 | ||
581 | printk("write_pci_cfg: devh[%x] device[%08x] where[%x] sz[%d] " | ||
582 | "val[%08x] == [%016lx]\n", | ||
583 | devhandle, HV_PCI_DEVICE_BUILD(bus, device, func), | ||
584 | where, size, value, ret); | ||
585 | #endif | ||
574 | } | 586 | } |
575 | return PCIBIOS_SUCCESSFUL; | 587 | return PCIBIOS_SUCCESSFUL; |
576 | } | 588 | } |
@@ -598,10 +610,13 @@ static void pbm_scan_bus(struct pci_controller_info *p, | |||
598 | pbm->pci_bus = pci_scan_bus(pbm->pci_first_busno, | 610 | pbm->pci_bus = pci_scan_bus(pbm->pci_first_busno, |
599 | p->pci_ops, | 611 | p->pci_ops, |
600 | pbm); | 612 | pbm); |
613 | #if 0 | ||
601 | pci_fixup_host_bridge_self(pbm->pci_bus); | 614 | pci_fixup_host_bridge_self(pbm->pci_bus); |
602 | pbm->pci_bus->self->sysdata = cookie; | 615 | pbm->pci_bus->self->sysdata = cookie; |
616 | #endif | ||
603 | 617 | ||
604 | pci_fill_in_pbm_cookies(pbm->pci_bus, pbm, pbm->prom_node); | 618 | pci_fill_in_pbm_cookies(pbm->pci_bus, pbm, |
619 | prom_getchild(pbm->prom_node)); | ||
605 | pci_record_assignments(pbm, pbm->pci_bus); | 620 | pci_record_assignments(pbm, pbm->pci_bus); |
606 | pci_assign_unassigned(pbm, pbm->pci_bus); | 621 | pci_assign_unassigned(pbm, pbm->pci_bus); |
607 | pci_fixup_irq(pbm, pbm->pci_bus); | 622 | pci_fixup_irq(pbm, pbm->pci_bus); |
@@ -631,8 +646,65 @@ static unsigned int pci_sun4v_irq_build(struct pci_pbm_info *pbm, | |||
631 | struct pci_dev *pdev, | 646 | struct pci_dev *pdev, |
632 | unsigned int ino) | 647 | unsigned int ino) |
633 | { | 648 | { |
634 | /* XXX Implement me! XXX */ | 649 | struct ino_bucket *bucket; |
635 | return 0; | 650 | unsigned long sysino; |
651 | u32 devhandle = pbm->devhandle; | ||
652 | int pil; | ||
653 | |||
654 | sysino = sun4v_devino_to_sysino(devhandle, ino); | ||
655 | |||
656 | printk(KERN_INFO "pci_irq_buld: Mapping ( devh[%08x] ino[%08x] ) " | ||
657 | "--> sysino[%016lx]\n", devhandle, ino, sysino); | ||
658 | |||
659 | pil = 4; | ||
660 | if (pdev) { | ||
661 | switch ((pdev->class >> 16) & 0xff) { | ||
662 | case PCI_BASE_CLASS_STORAGE: | ||
663 | pil = 4; | ||
664 | break; | ||
665 | |||
666 | case PCI_BASE_CLASS_NETWORK: | ||
667 | pil = 6; | ||
668 | break; | ||
669 | |||
670 | case PCI_BASE_CLASS_DISPLAY: | ||
671 | pil = 9; | ||
672 | break; | ||
673 | |||
674 | case PCI_BASE_CLASS_MULTIMEDIA: | ||
675 | case PCI_BASE_CLASS_MEMORY: | ||
676 | case PCI_BASE_CLASS_BRIDGE: | ||
677 | case PCI_BASE_CLASS_SERIAL: | ||
678 | pil = 10; | ||
679 | break; | ||
680 | |||
681 | default: | ||
682 | pil = 4; | ||
683 | break; | ||
684 | }; | ||
685 | } | ||
686 | BUG_ON(PIL_RESERVED(pil)); | ||
687 | |||
688 | bucket = &ivector_table[sysino]; | ||
689 | |||
690 | /* Catch accidental accesses to these things. IMAP/ICLR handling | ||
691 | * is done by hypervisor calls on sun4v platforms, not by direct | ||
692 | * register accesses. | ||
693 | */ | ||
694 | bucket->imap = ~0UL; | ||
695 | bucket->iclr = ~0UL; | ||
696 | |||
697 | bucket->pil = pil; | ||
698 | bucket->flags = IBF_PCI; | ||
699 | |||
700 | bucket->irq_info = kmalloc(sizeof(struct irq_desc), GFP_ATOMIC); | ||
701 | if (!bucket->irq_info) { | ||
702 | prom_printf("IRQ: Error, kmalloc(irq_desc) failed.\n"); | ||
703 | prom_halt(); | ||
704 | } | ||
705 | memset(bucket->irq_info, 0, sizeof(struct irq_desc)); | ||
706 | |||
707 | return __irq(bucket); | ||
636 | } | 708 | } |
637 | 709 | ||
638 | static void pci_sun4v_base_address_update(struct pci_dev *pdev, int resource) | 710 | static void pci_sun4v_base_address_update(struct pci_dev *pdev, int resource) |
@@ -834,10 +906,35 @@ static void pci_sun4v_iommu_init(struct pci_pbm_info *pbm) | |||
834 | probe_existing_entries(pbm, iommu); | 906 | probe_existing_entries(pbm, iommu); |
835 | } | 907 | } |
836 | 908 | ||
909 | /* Don't get this from the root nexus, get it from the "pci@0" node below. */ | ||
910 | static void pci_sun4v_get_bus_range(struct pci_pbm_info *pbm) | ||
911 | { | ||
912 | unsigned int busrange[2]; | ||
913 | int prom_node = pbm->prom_node; | ||
914 | int err; | ||
915 | |||
916 | prom_node = prom_getchild(prom_node); | ||
917 | if (prom_node == 0) { | ||
918 | prom_printf("%s: Fatal error, no child OBP node.\n", pbm->name); | ||
919 | prom_halt(); | ||
920 | } | ||
921 | |||
922 | err = prom_getproperty(prom_node, "bus-range", | ||
923 | (char *)&busrange[0], | ||
924 | sizeof(busrange)); | ||
925 | if (err == 0 || err == -1) { | ||
926 | prom_printf("%s: Fatal error, no bus-range.\n", pbm->name); | ||
927 | prom_halt(); | ||
928 | } | ||
929 | |||
930 | pbm->pci_first_busno = busrange[0]; | ||
931 | pbm->pci_last_busno = busrange[1]; | ||
932 | |||
933 | } | ||
934 | |||
837 | static void pci_sun4v_pbm_init(struct pci_controller_info *p, int prom_node, unsigned int devhandle) | 935 | static void pci_sun4v_pbm_init(struct pci_controller_info *p, int prom_node, unsigned int devhandle) |
838 | { | 936 | { |
839 | struct pci_pbm_info *pbm; | 937 | struct pci_pbm_info *pbm; |
840 | unsigned int busrange[2]; | ||
841 | int err, i; | 938 | int err, i; |
842 | 939 | ||
843 | if (devhandle & 0x40) | 940 | if (devhandle & 0x40) |
@@ -898,16 +995,7 @@ static void pci_sun4v_pbm_init(struct pci_controller_info *p, int prom_node, uns | |||
898 | memset(&pbm->pbm_intmask, 0, sizeof(pbm->pbm_intmask)); | 995 | memset(&pbm->pbm_intmask, 0, sizeof(pbm->pbm_intmask)); |
899 | } | 996 | } |
900 | 997 | ||
901 | err = prom_getproperty(prom_node, "bus-range", | 998 | pci_sun4v_get_bus_range(pbm); |
902 | (char *)&busrange[0], | ||
903 | sizeof(busrange)); | ||
904 | if (err == 0 || err == -1) { | ||
905 | prom_printf("%s: Fatal error, no bus-range.\n", pbm->name); | ||
906 | prom_halt(); | ||
907 | } | ||
908 | pbm->pci_first_busno = busrange[0]; | ||
909 | pbm->pci_last_busno = busrange[1]; | ||
910 | |||
911 | pci_sun4v_iommu_init(pbm); | 999 | pci_sun4v_iommu_init(pbm); |
912 | } | 1000 | } |
913 | 1001 | ||