diff options
Diffstat (limited to 'arch/ia64')
| -rw-r--r-- | arch/ia64/kernel/acpi.c | 30 | ||||
| -rw-r--r-- | arch/ia64/kernel/iosapic.c | 134 | ||||
| -rw-r--r-- | arch/ia64/pci/pci.c | 38 | 
3 files changed, 172 insertions, 30 deletions
| diff --git a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c index 72dfd9e7de0f..cda06f88c66e 100644 --- a/arch/ia64/kernel/acpi.c +++ b/arch/ia64/kernel/acpi.c | |||
| @@ -236,9 +236,7 @@ acpi_parse_iosapic (acpi_table_entry_header *header, const unsigned long end) | |||
| 236 | if (BAD_MADT_ENTRY(iosapic, end)) | 236 | if (BAD_MADT_ENTRY(iosapic, end)) | 
| 237 | return -EINVAL; | 237 | return -EINVAL; | 
| 238 | 238 | ||
| 239 | iosapic_init(iosapic->address, iosapic->global_irq_base); | 239 | return iosapic_init(iosapic->address, iosapic->global_irq_base); | 
| 240 | |||
| 241 | return 0; | ||
| 242 | } | 240 | } | 
| 243 | 241 | ||
| 244 | 242 | ||
| @@ -772,7 +770,7 @@ EXPORT_SYMBOL(acpi_unmap_lsapic); | |||
| 772 | 770 | ||
| 773 | 771 | ||
| 774 | #ifdef CONFIG_ACPI_NUMA | 772 | #ifdef CONFIG_ACPI_NUMA | 
| 775 | acpi_status __init | 773 | acpi_status __devinit | 
| 776 | acpi_map_iosapic (acpi_handle handle, u32 depth, void *context, void **ret) | 774 | acpi_map_iosapic (acpi_handle handle, u32 depth, void *context, void **ret) | 
| 777 | { | 775 | { | 
| 778 | struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; | 776 | struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; | 
| @@ -825,4 +823,28 @@ acpi_map_iosapic (acpi_handle handle, u32 depth, void *context, void **ret) | |||
| 825 | return AE_OK; | 823 | return AE_OK; | 
| 826 | } | 824 | } | 
| 827 | #endif /* CONFIG_NUMA */ | 825 | #endif /* CONFIG_NUMA */ | 
| 826 | |||
| 827 | int | ||
| 828 | acpi_register_ioapic (acpi_handle handle, u64 phys_addr, u32 gsi_base) | ||
| 829 | { | ||
| 830 | int err; | ||
| 831 | |||
| 832 | if ((err = iosapic_init(phys_addr, gsi_base))) | ||
| 833 | return err; | ||
| 834 | |||
| 835 | #if CONFIG_ACPI_NUMA | ||
| 836 | acpi_map_iosapic(handle, 0, NULL, NULL); | ||
| 837 | #endif /* CONFIG_ACPI_NUMA */ | ||
| 838 | |||
| 839 | return 0; | ||
| 840 | } | ||
| 841 | EXPORT_SYMBOL(acpi_register_ioapic); | ||
| 842 | |||
| 843 | int | ||
| 844 | acpi_unregister_ioapic (acpi_handle handle, u32 gsi_base) | ||
| 845 | { | ||
| 846 | return iosapic_remove(gsi_base); | ||
| 847 | } | ||
| 848 | EXPORT_SYMBOL(acpi_unregister_ioapic); | ||
| 849 | |||
| 828 | #endif /* CONFIG_ACPI_BOOT */ | 850 | #endif /* CONFIG_ACPI_BOOT */ | 
| diff --git a/arch/ia64/kernel/iosapic.c b/arch/ia64/kernel/iosapic.c index 88b014381df5..c170be095ccd 100644 --- a/arch/ia64/kernel/iosapic.c +++ b/arch/ia64/kernel/iosapic.c | |||
| @@ -129,14 +129,13 @@ static struct iosapic { | |||
| 129 | char __iomem *addr; /* base address of IOSAPIC */ | 129 | char __iomem *addr; /* base address of IOSAPIC */ | 
| 130 | unsigned int gsi_base; /* first GSI assigned to this IOSAPIC */ | 130 | unsigned int gsi_base; /* first GSI assigned to this IOSAPIC */ | 
| 131 | unsigned short num_rte; /* number of RTE in this IOSAPIC */ | 131 | unsigned short num_rte; /* number of RTE in this IOSAPIC */ | 
| 132 | int rtes_inuse; /* # of RTEs in use on this IOSAPIC */ | ||
| 132 | #ifdef CONFIG_NUMA | 133 | #ifdef CONFIG_NUMA | 
| 133 | unsigned short node; /* numa node association via pxm */ | 134 | unsigned short node; /* numa node association via pxm */ | 
| 134 | #endif | 135 | #endif | 
| 135 | } iosapic_lists[NR_IOSAPICS]; | 136 | } iosapic_lists[NR_IOSAPICS]; | 
| 136 | 137 | ||
| 137 | static int num_iosapic; | 138 | static unsigned char pcat_compat __devinitdata; /* 8259 compatibility flag */ | 
| 138 | |||
| 139 | static unsigned char pcat_compat __initdata; /* 8259 compatibility flag */ | ||
| 140 | 139 | ||
| 141 | static int iosapic_kmalloc_ok; | 140 | static int iosapic_kmalloc_ok; | 
| 142 | static LIST_HEAD(free_rte_list); | 141 | static LIST_HEAD(free_rte_list); | 
| @@ -149,7 +148,7 @@ find_iosapic (unsigned int gsi) | |||
| 149 | { | 148 | { | 
| 150 | int i; | 149 | int i; | 
| 151 | 150 | ||
| 152 | for (i = 0; i < num_iosapic; i++) { | 151 | for (i = 0; i < NR_IOSAPICS; i++) { | 
| 153 | if ((unsigned) (gsi - iosapic_lists[i].gsi_base) < iosapic_lists[i].num_rte) | 152 | if ((unsigned) (gsi - iosapic_lists[i].gsi_base) < iosapic_lists[i].num_rte) | 
| 154 | return i; | 153 | return i; | 
| 155 | } | 154 | } | 
| @@ -598,6 +597,7 @@ register_intr (unsigned int gsi, int vector, unsigned char delivery, | |||
| 598 | rte->refcnt++; | 597 | rte->refcnt++; | 
| 599 | list_add_tail(&rte->rte_list, &iosapic_intr_info[vector].rtes); | 598 | list_add_tail(&rte->rte_list, &iosapic_intr_info[vector].rtes); | 
| 600 | iosapic_intr_info[vector].count++; | 599 | iosapic_intr_info[vector].count++; | 
| 600 | iosapic_lists[index].rtes_inuse++; | ||
| 601 | } | 601 | } | 
| 602 | else if (vector_is_shared(vector)) { | 602 | else if (vector_is_shared(vector)) { | 
| 603 | struct iosapic_intr_info *info = &iosapic_intr_info[vector]; | 603 | struct iosapic_intr_info *info = &iosapic_intr_info[vector]; | 
| @@ -778,7 +778,7 @@ void | |||
| 778 | iosapic_unregister_intr (unsigned int gsi) | 778 | iosapic_unregister_intr (unsigned int gsi) | 
| 779 | { | 779 | { | 
| 780 | unsigned long flags; | 780 | unsigned long flags; | 
| 781 | int irq, vector; | 781 | int irq, vector, index; | 
| 782 | irq_desc_t *idesc; | 782 | irq_desc_t *idesc; | 
| 783 | u32 low32; | 783 | u32 low32; | 
| 784 | unsigned long trigger, polarity; | 784 | unsigned long trigger, polarity; | 
| @@ -819,6 +819,9 @@ iosapic_unregister_intr (unsigned int gsi) | |||
| 819 | list_del(&rte->rte_list); | 819 | list_del(&rte->rte_list); | 
| 820 | iosapic_intr_info[vector].count--; | 820 | iosapic_intr_info[vector].count--; | 
| 821 | iosapic_free_rte(rte); | 821 | iosapic_free_rte(rte); | 
| 822 | index = find_iosapic(gsi); | ||
| 823 | iosapic_lists[index].rtes_inuse--; | ||
| 824 | WARN_ON(iosapic_lists[index].rtes_inuse < 0); | ||
| 822 | 825 | ||
| 823 | trigger = iosapic_intr_info[vector].trigger; | 826 | trigger = iosapic_intr_info[vector].trigger; | 
| 824 | polarity = iosapic_intr_info[vector].polarity; | 827 | polarity = iosapic_intr_info[vector].polarity; | 
| @@ -952,30 +955,86 @@ iosapic_system_init (int system_pcat_compat) | |||
| 952 | } | 955 | } | 
| 953 | } | 956 | } | 
| 954 | 957 | ||
| 955 | void __init | 958 | static inline int | 
| 959 | iosapic_alloc (void) | ||
| 960 | { | ||
| 961 | int index; | ||
| 962 | |||
| 963 | for (index = 0; index < NR_IOSAPICS; index++) | ||
| 964 | if (!iosapic_lists[index].addr) | ||
| 965 | return index; | ||
| 966 | |||
| 967 | printk(KERN_WARNING "%s: failed to allocate iosapic\n", __FUNCTION__); | ||
| 968 | return -1; | ||
| 969 | } | ||
| 970 | |||
| 971 | static inline void | ||
| 972 | iosapic_free (int index) | ||
| 973 | { | ||
| 974 | memset(&iosapic_lists[index], 0, sizeof(iosapic_lists[0])); | ||
| 975 | } | ||
| 976 | |||
| 977 | static inline int | ||
| 978 | iosapic_check_gsi_range (unsigned int gsi_base, unsigned int ver) | ||
| 979 | { | ||
| 980 | int index; | ||
| 981 | unsigned int gsi_end, base, end; | ||
| 982 | |||
| 983 | /* check gsi range */ | ||
| 984 | gsi_end = gsi_base + ((ver >> 16) & 0xff); | ||
| 985 | for (index = 0; index < NR_IOSAPICS; index++) { | ||
| 986 | if (!iosapic_lists[index].addr) | ||
| 987 | continue; | ||
| 988 | |||
| 989 | base = iosapic_lists[index].gsi_base; | ||
| 990 | end = base + iosapic_lists[index].num_rte - 1; | ||
| 991 | |||
| 992 | if (gsi_base < base && gsi_end < base) | ||
| 993 | continue;/* OK */ | ||
| 994 | |||
| 995 | if (gsi_base > end && gsi_end > end) | ||
| 996 | continue; /* OK */ | ||
| 997 | |||
| 998 | return -EBUSY; | ||
| 999 | } | ||
| 1000 | return 0; | ||
| 1001 | } | ||
| 1002 | |||
| 1003 | int __devinit | ||
| 956 | iosapic_init (unsigned long phys_addr, unsigned int gsi_base) | 1004 | iosapic_init (unsigned long phys_addr, unsigned int gsi_base) | 
| 957 | { | 1005 | { | 
| 958 | int num_rte; | 1006 | int num_rte, err, index; | 
| 959 | unsigned int isa_irq, ver; | 1007 | unsigned int isa_irq, ver; | 
| 960 | char __iomem *addr; | 1008 | char __iomem *addr; | 
| 1009 | unsigned long flags; | ||
| 1010 | |||
| 1011 | spin_lock_irqsave(&iosapic_lock, flags); | ||
| 1012 | { | ||
| 1013 | addr = ioremap(phys_addr, 0); | ||
| 1014 | ver = iosapic_version(addr); | ||
| 961 | 1015 | ||
| 962 | addr = ioremap(phys_addr, 0); | 1016 | if ((err = iosapic_check_gsi_range(gsi_base, ver))) { | 
| 963 | ver = iosapic_version(addr); | 1017 | iounmap(addr); | 
| 1018 | spin_unlock_irqrestore(&iosapic_lock, flags); | ||
| 1019 | return err; | ||
| 1020 | } | ||
| 964 | 1021 | ||
| 965 | /* | 1022 | /* | 
| 966 | * The MAX_REDIR register holds the highest input pin | 1023 | * The MAX_REDIR register holds the highest input pin | 
| 967 | * number (starting from 0). | 1024 | * number (starting from 0). | 
| 968 | * We add 1 so that we can use it for number of pins (= RTEs) | 1025 | * We add 1 so that we can use it for number of pins (= RTEs) | 
| 969 | */ | 1026 | */ | 
| 970 | num_rte = ((ver >> 16) & 0xff) + 1; | 1027 | num_rte = ((ver >> 16) & 0xff) + 1; | 
| 971 | 1028 | ||
| 972 | iosapic_lists[num_iosapic].addr = addr; | 1029 | index = iosapic_alloc(); | 
| 973 | iosapic_lists[num_iosapic].gsi_base = gsi_base; | 1030 | iosapic_lists[index].addr = addr; | 
| 974 | iosapic_lists[num_iosapic].num_rte = num_rte; | 1031 | iosapic_lists[index].gsi_base = gsi_base; | 
| 1032 | iosapic_lists[index].num_rte = num_rte; | ||
| 975 | #ifdef CONFIG_NUMA | 1033 | #ifdef CONFIG_NUMA | 
| 976 | iosapic_lists[num_iosapic].node = MAX_NUMNODES; | 1034 | iosapic_lists[index].node = MAX_NUMNODES; | 
| 977 | #endif | 1035 | #endif | 
| 978 | num_iosapic++; | 1036 | } | 
| 1037 | spin_unlock_irqrestore(&iosapic_lock, flags); | ||
| 979 | 1038 | ||
| 980 | if ((gsi_base == 0) && pcat_compat) { | 1039 | if ((gsi_base == 0) && pcat_compat) { | 
| 981 | /* | 1040 | /* | 
| @@ -986,10 +1045,43 @@ iosapic_init (unsigned long phys_addr, unsigned int gsi_base) | |||
| 986 | for (isa_irq = 0; isa_irq < 16; ++isa_irq) | 1045 | for (isa_irq = 0; isa_irq < 16; ++isa_irq) | 
| 987 | iosapic_override_isa_irq(isa_irq, isa_irq, IOSAPIC_POL_HIGH, IOSAPIC_EDGE); | 1046 | iosapic_override_isa_irq(isa_irq, isa_irq, IOSAPIC_POL_HIGH, IOSAPIC_EDGE); | 
| 988 | } | 1047 | } | 
| 1048 | return 0; | ||
| 1049 | } | ||
| 1050 | |||
| 1051 | #ifdef CONFIG_HOTPLUG | ||
| 1052 | int | ||
| 1053 | iosapic_remove (unsigned int gsi_base) | ||
| 1054 | { | ||
| 1055 | int index, err = 0; | ||
| 1056 | unsigned long flags; | ||
| 1057 | |||
| 1058 | spin_lock_irqsave(&iosapic_lock, flags); | ||
| 1059 | { | ||
| 1060 | index = find_iosapic(gsi_base); | ||
| 1061 | if (index < 0) { | ||
| 1062 | printk(KERN_WARNING "%s: No IOSAPIC for GSI base %u\n", | ||
| 1063 | __FUNCTION__, gsi_base); | ||
| 1064 | goto out; | ||
| 1065 | } | ||
| 1066 | |||
| 1067 | if (iosapic_lists[index].rtes_inuse) { | ||
| 1068 | err = -EBUSY; | ||
| 1069 | printk(KERN_WARNING "%s: IOSAPIC for GSI base %u is busy\n", | ||
| 1070 | __FUNCTION__, gsi_base); | ||
| 1071 | goto out; | ||
| 1072 | } | ||
| 1073 | |||
| 1074 | iounmap(iosapic_lists[index].addr); | ||
| 1075 | iosapic_free(index); | ||
| 1076 | } | ||
| 1077 | out: | ||
| 1078 | spin_unlock_irqrestore(&iosapic_lock, flags); | ||
| 1079 | return err; | ||
| 989 | } | 1080 | } | 
| 1081 | #endif /* CONFIG_HOTPLUG */ | ||
| 990 | 1082 | ||
| 991 | #ifdef CONFIG_NUMA | 1083 | #ifdef CONFIG_NUMA | 
| 992 | void __init | 1084 | void __devinit | 
| 993 | map_iosapic_to_node(unsigned int gsi_base, int node) | 1085 | map_iosapic_to_node(unsigned int gsi_base, int node) | 
| 994 | { | 1086 | { | 
| 995 | int index; | 1087 | int index; | 
| diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c index e3fc4edea113..720a861f88be 100644 --- a/arch/ia64/pci/pci.c +++ b/arch/ia64/pci/pci.c | |||
| @@ -312,7 +312,7 @@ pci_acpi_scan_root(struct acpi_device *device, int domain, int bus) | |||
| 312 | acpi_walk_resources(device->handle, METHOD_NAME__CRS, add_window, | 312 | acpi_walk_resources(device->handle, METHOD_NAME__CRS, add_window, | 
| 313 | &info); | 313 | &info); | 
| 314 | 314 | ||
| 315 | pbus = pci_scan_bus(bus, &pci_root_ops, controller); | 315 | pbus = pci_scan_bus_parented(NULL, bus, &pci_root_ops, controller); | 
| 316 | if (pbus) | 316 | if (pbus) | 
| 317 | pcibios_setup_root_windows(pbus, controller); | 317 | pcibios_setup_root_windows(pbus, controller); | 
| 318 | 318 | ||
| @@ -373,6 +373,25 @@ void pcibios_bus_to_resource(struct pci_dev *dev, | |||
| 373 | res->end = region->end + offset; | 373 | res->end = region->end + offset; | 
| 374 | } | 374 | } | 
| 375 | 375 | ||
| 376 | static int __devinit is_valid_resource(struct pci_dev *dev, int idx) | ||
| 377 | { | ||
| 378 | unsigned int i, type_mask = IORESOURCE_IO | IORESOURCE_MEM; | ||
| 379 | struct resource *devr = &dev->resource[idx]; | ||
| 380 | |||
| 381 | if (!dev->bus) | ||
| 382 | return 0; | ||
| 383 | for (i=0; i<PCI_BUS_NUM_RESOURCES; i++) { | ||
| 384 | struct resource *busr = dev->bus->resource[i]; | ||
| 385 | |||
| 386 | if (!busr || ((busr->flags ^ devr->flags) & type_mask)) | ||
| 387 | continue; | ||
| 388 | if ((devr->start) && (devr->start >= busr->start) && | ||
| 389 | (devr->end <= busr->end)) | ||
| 390 | return 1; | ||
| 391 | } | ||
| 392 | return 0; | ||
| 393 | } | ||
| 394 | |||
| 376 | static void __devinit pcibios_fixup_device_resources(struct pci_dev *dev) | 395 | static void __devinit pcibios_fixup_device_resources(struct pci_dev *dev) | 
| 377 | { | 396 | { | 
| 378 | struct pci_bus_region region; | 397 | struct pci_bus_region region; | 
| @@ -386,7 +405,8 @@ static void __devinit pcibios_fixup_device_resources(struct pci_dev *dev) | |||
| 386 | region.start = dev->resource[i].start; | 405 | region.start = dev->resource[i].start; | 
| 387 | region.end = dev->resource[i].end; | 406 | region.end = dev->resource[i].end; | 
| 388 | pcibios_bus_to_resource(dev, &dev->resource[i], ®ion); | 407 | pcibios_bus_to_resource(dev, &dev->resource[i], ®ion); | 
| 389 | pci_claim_resource(dev, i); | 408 | if ((is_valid_resource(dev, i))) | 
| 409 | pci_claim_resource(dev, i); | ||
| 390 | } | 410 | } | 
| 391 | } | 411 | } | 
| 392 | 412 | ||
| @@ -398,6 +418,10 @@ pcibios_fixup_bus (struct pci_bus *b) | |||
| 398 | { | 418 | { | 
| 399 | struct pci_dev *dev; | 419 | struct pci_dev *dev; | 
| 400 | 420 | ||
| 421 | if (b->self) { | ||
| 422 | pci_read_bridge_bases(b); | ||
| 423 | pcibios_fixup_device_resources(b->self); | ||
| 424 | } | ||
| 401 | list_for_each_entry(dev, &b->devices, bus_list) | 425 | list_for_each_entry(dev, &b->devices, bus_list) | 
| 402 | pcibios_fixup_device_resources(dev); | 426 | pcibios_fixup_device_resources(dev); | 
| 403 | 427 | ||
| @@ -418,18 +442,24 @@ pcibios_enable_resources (struct pci_dev *dev, int mask) | |||
| 418 | u16 cmd, old_cmd; | 442 | u16 cmd, old_cmd; | 
| 419 | int idx; | 443 | int idx; | 
| 420 | struct resource *r; | 444 | struct resource *r; | 
| 445 | unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM; | ||
| 421 | 446 | ||
| 422 | if (!dev) | 447 | if (!dev) | 
| 423 | return -EINVAL; | 448 | return -EINVAL; | 
| 424 | 449 | ||
| 425 | pci_read_config_word(dev, PCI_COMMAND, &cmd); | 450 | pci_read_config_word(dev, PCI_COMMAND, &cmd); | 
| 426 | old_cmd = cmd; | 451 | old_cmd = cmd; | 
| 427 | for (idx=0; idx<6; idx++) { | 452 | for (idx=0; idx<PCI_NUM_RESOURCES; idx++) { | 
| 428 | /* Only set up the desired resources. */ | 453 | /* Only set up the desired resources. */ | 
| 429 | if (!(mask & (1 << idx))) | 454 | if (!(mask & (1 << idx))) | 
| 430 | continue; | 455 | continue; | 
| 431 | 456 | ||
| 432 | r = &dev->resource[idx]; | 457 | r = &dev->resource[idx]; | 
| 458 | if (!(r->flags & type_mask)) | ||
| 459 | continue; | ||
| 460 | if ((idx == PCI_ROM_RESOURCE) && | ||
| 461 | (!(r->flags & IORESOURCE_ROM_ENABLE))) | ||
| 462 | continue; | ||
| 433 | if (!r->start && r->end) { | 463 | if (!r->start && r->end) { | 
| 434 | printk(KERN_ERR | 464 | printk(KERN_ERR | 
| 435 | "PCI: Device %s not available because of resource collisions\n", | 465 | "PCI: Device %s not available because of resource collisions\n", | 
| @@ -441,8 +471,6 @@ pcibios_enable_resources (struct pci_dev *dev, int mask) | |||
| 441 | if (r->flags & IORESOURCE_MEM) | 471 | if (r->flags & IORESOURCE_MEM) | 
| 442 | cmd |= PCI_COMMAND_MEMORY; | 472 | cmd |= PCI_COMMAND_MEMORY; | 
| 443 | } | 473 | } | 
| 444 | if (dev->resource[PCI_ROM_RESOURCE].start) | ||
| 445 | cmd |= PCI_COMMAND_MEMORY; | ||
| 446 | if (cmd != old_cmd) { | 474 | if (cmd != old_cmd) { | 
| 447 | printk("PCI: Enabling device %s (%04x -> %04x)\n", pci_name(dev), old_cmd, cmd); | 475 | printk("PCI: Enabling device %s (%04x -> %04x)\n", pci_name(dev), old_cmd, cmd); | 
| 448 | pci_write_config_word(dev, PCI_COMMAND, cmd); | 476 | pci_write_config_word(dev, PCI_COMMAND, cmd); | 
