diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-27 13:05:42 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-27 13:05:42 -0400 |
commit | fc67b16ecaf6ebde04096030c268adddade023f1 (patch) | |
tree | 1cce42cdca1fc9e4ec41b9f7f72c60e343cebca7 /arch | |
parent | e8108c98dd6d65613fa0ec9d2300f89c48d554bf (diff) | |
parent | 2d29306b231a1a0e7a70166c10e4c0f917b21334 (diff) |
Automatic merge of rsync://rsync.kernel.org/pub/scm/linux/kernel/git/aegl/linux-2.6.git
Diffstat (limited to 'arch')
35 files changed, 2308 insertions, 479 deletions
diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig index 33fcb205fcb7..468dbe8a6b9c 100644 --- a/arch/ia64/Kconfig +++ b/arch/ia64/Kconfig | |||
@@ -329,7 +329,7 @@ menu "Power management and ACPI" | |||
329 | 329 | ||
330 | config PM | 330 | config PM |
331 | bool "Power Management support" | 331 | bool "Power Management support" |
332 | depends on IA64_GENERIC || IA64_DIG || IA64_HP_ZX1 || IA64_HP_ZX1_SWIOTLB | 332 | depends on !IA64_HP_SIM |
333 | default y | 333 | default y |
334 | help | 334 | help |
335 | "Power Management" means that parts of your computer are shut | 335 | "Power Management" means that parts of your computer are shut |
diff --git a/arch/ia64/configs/sn2_defconfig b/arch/ia64/configs/sn2_defconfig index bfeb952fe8e2..6ff7107fee4d 100644 --- a/arch/ia64/configs/sn2_defconfig +++ b/arch/ia64/configs/sn2_defconfig | |||
@@ -574,6 +574,8 @@ CONFIG_SERIAL_NONSTANDARD=y | |||
574 | # CONFIG_N_HDLC is not set | 574 | # CONFIG_N_HDLC is not set |
575 | # CONFIG_STALDRV is not set | 575 | # CONFIG_STALDRV is not set |
576 | CONFIG_SGI_SNSC=y | 576 | CONFIG_SGI_SNSC=y |
577 | CONFIG_SGI_TIOCX=y | ||
578 | CONFIG_SGI_MBCS=m | ||
577 | 579 | ||
578 | # | 580 | # |
579 | # Serial drivers | 581 | # Serial drivers |
diff --git a/arch/ia64/hp/common/sba_iommu.c b/arch/ia64/hp/common/sba_iommu.c index 017c9ab5fc1b..6a8fcba7a853 100644 --- a/arch/ia64/hp/common/sba_iommu.c +++ b/arch/ia64/hp/common/sba_iommu.c | |||
@@ -1,9 +1,9 @@ | |||
1 | /* | 1 | /* |
2 | ** IA64 System Bus Adapter (SBA) I/O MMU manager | 2 | ** IA64 System Bus Adapter (SBA) I/O MMU manager |
3 | ** | 3 | ** |
4 | ** (c) Copyright 2002-2004 Alex Williamson | 4 | ** (c) Copyright 2002-2005 Alex Williamson |
5 | ** (c) Copyright 2002-2003 Grant Grundler | 5 | ** (c) Copyright 2002-2003 Grant Grundler |
6 | ** (c) Copyright 2002-2004 Hewlett-Packard Company | 6 | ** (c) Copyright 2002-2005 Hewlett-Packard Company |
7 | ** | 7 | ** |
8 | ** Portions (c) 2000 Grant Grundler (from parisc I/O MMU code) | 8 | ** Portions (c) 2000 Grant Grundler (from parisc I/O MMU code) |
9 | ** Portions (c) 1999 Dave S. Miller (from sparc64 I/O MMU code) | 9 | ** Portions (c) 1999 Dave S. Miller (from sparc64 I/O MMU code) |
@@ -459,21 +459,32 @@ get_iovp_order (unsigned long size) | |||
459 | * sba_search_bitmap - find free space in IO PDIR resource bitmap | 459 | * sba_search_bitmap - find free space in IO PDIR resource bitmap |
460 | * @ioc: IO MMU structure which owns the pdir we are interested in. | 460 | * @ioc: IO MMU structure which owns the pdir we are interested in. |
461 | * @bits_wanted: number of entries we need. | 461 | * @bits_wanted: number of entries we need. |
462 | * @use_hint: use res_hint to indicate where to start looking | ||
462 | * | 463 | * |
463 | * Find consecutive free bits in resource bitmap. | 464 | * Find consecutive free bits in resource bitmap. |
464 | * Each bit represents one entry in the IO Pdir. | 465 | * Each bit represents one entry in the IO Pdir. |
465 | * Cool perf optimization: search for log2(size) bits at a time. | 466 | * Cool perf optimization: search for log2(size) bits at a time. |
466 | */ | 467 | */ |
467 | static SBA_INLINE unsigned long | 468 | static SBA_INLINE unsigned long |
468 | sba_search_bitmap(struct ioc *ioc, unsigned long bits_wanted) | 469 | sba_search_bitmap(struct ioc *ioc, unsigned long bits_wanted, int use_hint) |
469 | { | 470 | { |
470 | unsigned long *res_ptr = ioc->res_hint; | 471 | unsigned long *res_ptr; |
471 | unsigned long *res_end = (unsigned long *) &(ioc->res_map[ioc->res_size]); | 472 | unsigned long *res_end = (unsigned long *) &(ioc->res_map[ioc->res_size]); |
472 | unsigned long pide = ~0UL; | 473 | unsigned long flags, pide = ~0UL; |
473 | 474 | ||
474 | ASSERT(((unsigned long) ioc->res_hint & (sizeof(unsigned long) - 1UL)) == 0); | 475 | ASSERT(((unsigned long) ioc->res_hint & (sizeof(unsigned long) - 1UL)) == 0); |
475 | ASSERT(res_ptr < res_end); | 476 | ASSERT(res_ptr < res_end); |
476 | 477 | ||
478 | spin_lock_irqsave(&ioc->res_lock, flags); | ||
479 | |||
480 | /* Allow caller to force a search through the entire resource space */ | ||
481 | if (likely(use_hint)) { | ||
482 | res_ptr = ioc->res_hint; | ||
483 | } else { | ||
484 | res_ptr = (ulong *)ioc->res_map; | ||
485 | ioc->res_bitshift = 0; | ||
486 | } | ||
487 | |||
477 | /* | 488 | /* |
478 | * N.B. REO/Grande defect AR2305 can cause TLB fetch timeouts | 489 | * N.B. REO/Grande defect AR2305 can cause TLB fetch timeouts |
479 | * if a TLB entry is purged while in use. sba_mark_invalid() | 490 | * if a TLB entry is purged while in use. sba_mark_invalid() |
@@ -570,10 +581,12 @@ not_found: | |||
570 | prefetch(ioc->res_map); | 581 | prefetch(ioc->res_map); |
571 | ioc->res_hint = (unsigned long *) ioc->res_map; | 582 | ioc->res_hint = (unsigned long *) ioc->res_map; |
572 | ioc->res_bitshift = 0; | 583 | ioc->res_bitshift = 0; |
584 | spin_unlock_irqrestore(&ioc->res_lock, flags); | ||
573 | return (pide); | 585 | return (pide); |
574 | 586 | ||
575 | found_it: | 587 | found_it: |
576 | ioc->res_hint = res_ptr; | 588 | ioc->res_hint = res_ptr; |
589 | spin_unlock_irqrestore(&ioc->res_lock, flags); | ||
577 | return (pide); | 590 | return (pide); |
578 | } | 591 | } |
579 | 592 | ||
@@ -594,36 +607,36 @@ sba_alloc_range(struct ioc *ioc, size_t size) | |||
594 | unsigned long itc_start; | 607 | unsigned long itc_start; |
595 | #endif | 608 | #endif |
596 | unsigned long pide; | 609 | unsigned long pide; |
597 | unsigned long flags; | ||
598 | 610 | ||
599 | ASSERT(pages_needed); | 611 | ASSERT(pages_needed); |
600 | ASSERT(0 == (size & ~iovp_mask)); | 612 | ASSERT(0 == (size & ~iovp_mask)); |
601 | 613 | ||
602 | spin_lock_irqsave(&ioc->res_lock, flags); | ||
603 | |||
604 | #ifdef PDIR_SEARCH_TIMING | 614 | #ifdef PDIR_SEARCH_TIMING |
605 | itc_start = ia64_get_itc(); | 615 | itc_start = ia64_get_itc(); |
606 | #endif | 616 | #endif |
607 | /* | 617 | /* |
608 | ** "seek and ye shall find"...praying never hurts either... | 618 | ** "seek and ye shall find"...praying never hurts either... |
609 | */ | 619 | */ |
610 | pide = sba_search_bitmap(ioc, pages_needed); | 620 | pide = sba_search_bitmap(ioc, pages_needed, 1); |
611 | if (unlikely(pide >= (ioc->res_size << 3))) { | 621 | if (unlikely(pide >= (ioc->res_size << 3))) { |
612 | pide = sba_search_bitmap(ioc, pages_needed); | 622 | pide = sba_search_bitmap(ioc, pages_needed, 0); |
613 | if (unlikely(pide >= (ioc->res_size << 3))) { | 623 | if (unlikely(pide >= (ioc->res_size << 3))) { |
614 | #if DELAYED_RESOURCE_CNT > 0 | 624 | #if DELAYED_RESOURCE_CNT > 0 |
625 | unsigned long flags; | ||
626 | |||
615 | /* | 627 | /* |
616 | ** With delayed resource freeing, we can give this one more shot. We're | 628 | ** With delayed resource freeing, we can give this one more shot. We're |
617 | ** getting close to being in trouble here, so do what we can to make this | 629 | ** getting close to being in trouble here, so do what we can to make this |
618 | ** one count. | 630 | ** one count. |
619 | */ | 631 | */ |
620 | spin_lock(&ioc->saved_lock); | 632 | spin_lock_irqsave(&ioc->saved_lock, flags); |
621 | if (ioc->saved_cnt > 0) { | 633 | if (ioc->saved_cnt > 0) { |
622 | struct sba_dma_pair *d; | 634 | struct sba_dma_pair *d; |
623 | int cnt = ioc->saved_cnt; | 635 | int cnt = ioc->saved_cnt; |
624 | 636 | ||
625 | d = &(ioc->saved[ioc->saved_cnt]); | 637 | d = &(ioc->saved[ioc->saved_cnt - 1]); |
626 | 638 | ||
639 | spin_lock(&ioc->res_lock); | ||
627 | while (cnt--) { | 640 | while (cnt--) { |
628 | sba_mark_invalid(ioc, d->iova, d->size); | 641 | sba_mark_invalid(ioc, d->iova, d->size); |
629 | sba_free_range(ioc, d->iova, d->size); | 642 | sba_free_range(ioc, d->iova, d->size); |
@@ -631,10 +644,11 @@ sba_alloc_range(struct ioc *ioc, size_t size) | |||
631 | } | 644 | } |
632 | ioc->saved_cnt = 0; | 645 | ioc->saved_cnt = 0; |
633 | READ_REG(ioc->ioc_hpa+IOC_PCOM); /* flush purges */ | 646 | READ_REG(ioc->ioc_hpa+IOC_PCOM); /* flush purges */ |
647 | spin_unlock(&ioc->res_lock); | ||
634 | } | 648 | } |
635 | spin_unlock(&ioc->saved_lock); | 649 | spin_unlock_irqrestore(&ioc->saved_lock, flags); |
636 | 650 | ||
637 | pide = sba_search_bitmap(ioc, pages_needed); | 651 | pide = sba_search_bitmap(ioc, pages_needed, 0); |
638 | if (unlikely(pide >= (ioc->res_size << 3))) | 652 | if (unlikely(pide >= (ioc->res_size << 3))) |
639 | panic(__FILE__ ": I/O MMU @ %p is out of mapping resources\n", | 653 | panic(__FILE__ ": I/O MMU @ %p is out of mapping resources\n", |
640 | ioc->ioc_hpa); | 654 | ioc->ioc_hpa); |
@@ -664,8 +678,6 @@ sba_alloc_range(struct ioc *ioc, size_t size) | |||
664 | (uint) ((unsigned long) ioc->res_hint - (unsigned long) ioc->res_map), | 678 | (uint) ((unsigned long) ioc->res_hint - (unsigned long) ioc->res_map), |
665 | ioc->res_bitshift ); | 679 | ioc->res_bitshift ); |
666 | 680 | ||
667 | spin_unlock_irqrestore(&ioc->res_lock, flags); | ||
668 | |||
669 | return (pide); | 681 | return (pide); |
670 | } | 682 | } |
671 | 683 | ||
@@ -950,6 +962,30 @@ sba_map_single(struct device *dev, void *addr, size_t size, int dir) | |||
950 | return SBA_IOVA(ioc, iovp, offset); | 962 | return SBA_IOVA(ioc, iovp, offset); |
951 | } | 963 | } |
952 | 964 | ||
965 | #ifdef ENABLE_MARK_CLEAN | ||
966 | static SBA_INLINE void | ||
967 | sba_mark_clean(struct ioc *ioc, dma_addr_t iova, size_t size) | ||
968 | { | ||
969 | u32 iovp = (u32) SBA_IOVP(ioc,iova); | ||
970 | int off = PDIR_INDEX(iovp); | ||
971 | void *addr; | ||
972 | |||
973 | if (size <= iovp_size) { | ||
974 | addr = phys_to_virt(ioc->pdir_base[off] & | ||
975 | ~0xE000000000000FFFULL); | ||
976 | mark_clean(addr, size); | ||
977 | } else { | ||
978 | do { | ||
979 | addr = phys_to_virt(ioc->pdir_base[off] & | ||
980 | ~0xE000000000000FFFULL); | ||
981 | mark_clean(addr, min(size, iovp_size)); | ||
982 | off++; | ||
983 | size -= iovp_size; | ||
984 | } while (size > 0); | ||
985 | } | ||
986 | } | ||
987 | #endif | ||
988 | |||
953 | /** | 989 | /** |
954 | * sba_unmap_single - unmap one IOVA and free resources | 990 | * sba_unmap_single - unmap one IOVA and free resources |
955 | * @dev: instance of PCI owned by the driver that's asking. | 991 | * @dev: instance of PCI owned by the driver that's asking. |
@@ -995,6 +1031,10 @@ void sba_unmap_single(struct device *dev, dma_addr_t iova, size_t size, int dir) | |||
995 | size += offset; | 1031 | size += offset; |
996 | size = ROUNDUP(size, iovp_size); | 1032 | size = ROUNDUP(size, iovp_size); |
997 | 1033 | ||
1034 | #ifdef ENABLE_MARK_CLEAN | ||
1035 | if (dir == DMA_FROM_DEVICE) | ||
1036 | sba_mark_clean(ioc, iova, size); | ||
1037 | #endif | ||
998 | 1038 | ||
999 | #if DELAYED_RESOURCE_CNT > 0 | 1039 | #if DELAYED_RESOURCE_CNT > 0 |
1000 | spin_lock_irqsave(&ioc->saved_lock, flags); | 1040 | spin_lock_irqsave(&ioc->saved_lock, flags); |
@@ -1021,30 +1061,6 @@ void sba_unmap_single(struct device *dev, dma_addr_t iova, size_t size, int dir) | |||
1021 | READ_REG(ioc->ioc_hpa+IOC_PCOM); /* flush purges */ | 1061 | READ_REG(ioc->ioc_hpa+IOC_PCOM); /* flush purges */ |
1022 | spin_unlock_irqrestore(&ioc->res_lock, flags); | 1062 | spin_unlock_irqrestore(&ioc->res_lock, flags); |
1023 | #endif /* DELAYED_RESOURCE_CNT == 0 */ | 1063 | #endif /* DELAYED_RESOURCE_CNT == 0 */ |
1024 | #ifdef ENABLE_MARK_CLEAN | ||
1025 | if (dir == DMA_FROM_DEVICE) { | ||
1026 | u32 iovp = (u32) SBA_IOVP(ioc,iova); | ||
1027 | int off = PDIR_INDEX(iovp); | ||
1028 | void *addr; | ||
1029 | |||
1030 | if (size <= iovp_size) { | ||
1031 | addr = phys_to_virt(ioc->pdir_base[off] & | ||
1032 | ~0xE000000000000FFFULL); | ||
1033 | mark_clean(addr, size); | ||
1034 | } else { | ||
1035 | size_t byte_cnt = size; | ||
1036 | |||
1037 | do { | ||
1038 | addr = phys_to_virt(ioc->pdir_base[off] & | ||
1039 | ~0xE000000000000FFFULL); | ||
1040 | mark_clean(addr, min(byte_cnt, iovp_size)); | ||
1041 | off++; | ||
1042 | byte_cnt -= iovp_size; | ||
1043 | |||
1044 | } while (byte_cnt > 0); | ||
1045 | } | ||
1046 | } | ||
1047 | #endif | ||
1048 | } | 1064 | } |
1049 | 1065 | ||
1050 | 1066 | ||
diff --git a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S index 0272c010a3ba..bd86fea49a0c 100644 --- a/arch/ia64/kernel/entry.S +++ b/arch/ia64/kernel/entry.S | |||
@@ -728,12 +728,8 @@ ENTRY(ia64_leave_syscall) | |||
728 | mov f8=f0 // clear f8 | 728 | mov f8=f0 // clear f8 |
729 | ;; | 729 | ;; |
730 | ld8 r30=[r2],16 // M0|1 load cr.ifs | 730 | ld8 r30=[r2],16 // M0|1 load cr.ifs |
731 | mov.m ar.ssd=r0 // M2 clear ar.ssd | ||
732 | cmp.eq p9,p0=r0,r0 // set p9 to indicate that we should restore cr.ifs | ||
733 | ;; | ||
734 | ld8 r25=[r3],16 // M0|1 load ar.unat | 731 | ld8 r25=[r3],16 // M0|1 load ar.unat |
735 | mov.m ar.csd=r0 // M2 clear ar.csd | 732 | cmp.eq p9,p0=r0,r0 // set p9 to indicate that we should restore cr.ifs |
736 | mov r22=r0 // clear r22 | ||
737 | ;; | 733 | ;; |
738 | ld8 r26=[r2],PT(B0)-PT(AR_PFS) // M0|1 load ar.pfs | 734 | ld8 r26=[r2],PT(B0)-PT(AR_PFS) // M0|1 load ar.pfs |
739 | (pKStk) mov r22=psr // M2 read PSR now that interrupts are disabled | 735 | (pKStk) mov r22=psr // M2 read PSR now that interrupts are disabled |
@@ -756,11 +752,15 @@ ENTRY(ia64_leave_syscall) | |||
756 | mov f7=f0 // clear f7 | 752 | mov f7=f0 // clear f7 |
757 | ;; | 753 | ;; |
758 | ld8.fill r12=[r2] // restore r12 (sp) | 754 | ld8.fill r12=[r2] // restore r12 (sp) |
755 | mov.m ar.ssd=r0 // M2 clear ar.ssd | ||
756 | mov r22=r0 // clear r22 | ||
757 | |||
759 | ld8.fill r15=[r3] // restore r15 | 758 | ld8.fill r15=[r3] // restore r15 |
759 | (pUStk) st1 [r14]=r17 | ||
760 | addl r3=THIS_CPU(ia64_phys_stacked_size_p8),r0 | 760 | addl r3=THIS_CPU(ia64_phys_stacked_size_p8),r0 |
761 | ;; | 761 | ;; |
762 | (pUStk) ld4 r3=[r3] // r3 = cpu_data->phys_stacked_size_p8 | 762 | (pUStk) ld4 r17=[r3] // r17 = cpu_data->phys_stacked_size_p8 |
763 | (pUStk) st1 [r14]=r17 | 763 | mov.m ar.csd=r0 // M2 clear ar.csd |
764 | mov b6=r18 // I0 restore b6 | 764 | mov b6=r18 // I0 restore b6 |
765 | ;; | 765 | ;; |
766 | mov r14=r0 // clear r14 | 766 | mov r14=r0 // clear r14 |
diff --git a/arch/ia64/kernel/iosapic.c b/arch/ia64/kernel/iosapic.c index c15be5c38f56..88b014381df5 100644 --- a/arch/ia64/kernel/iosapic.c +++ b/arch/ia64/kernel/iosapic.c | |||
@@ -79,6 +79,7 @@ | |||
79 | #include <linux/smp.h> | 79 | #include <linux/smp.h> |
80 | #include <linux/smp_lock.h> | 80 | #include <linux/smp_lock.h> |
81 | #include <linux/string.h> | 81 | #include <linux/string.h> |
82 | #include <linux/bootmem.h> | ||
82 | 83 | ||
83 | #include <asm/delay.h> | 84 | #include <asm/delay.h> |
84 | #include <asm/hw_irq.h> | 85 | #include <asm/hw_irq.h> |
@@ -98,19 +99,30 @@ | |||
98 | #define DBG(fmt...) | 99 | #define DBG(fmt...) |
99 | #endif | 100 | #endif |
100 | 101 | ||
102 | #define NR_PREALLOCATE_RTE_ENTRIES (PAGE_SIZE / sizeof(struct iosapic_rte_info)) | ||
103 | #define RTE_PREALLOCATED (1) | ||
104 | |||
101 | static DEFINE_SPINLOCK(iosapic_lock); | 105 | static DEFINE_SPINLOCK(iosapic_lock); |
102 | 106 | ||
103 | /* These tables map IA-64 vectors to the IOSAPIC pin that generates this vector. */ | 107 | /* These tables map IA-64 vectors to the IOSAPIC pin that generates this vector. */ |
104 | 108 | ||
105 | static struct iosapic_intr_info { | 109 | struct iosapic_rte_info { |
110 | struct list_head rte_list; /* node in list of RTEs sharing the same vector */ | ||
106 | char __iomem *addr; /* base address of IOSAPIC */ | 111 | char __iomem *addr; /* base address of IOSAPIC */ |
107 | u32 low32; /* current value of low word of Redirection table entry */ | ||
108 | unsigned int gsi_base; /* first GSI assigned to this IOSAPIC */ | 112 | unsigned int gsi_base; /* first GSI assigned to this IOSAPIC */ |
109 | char rte_index; /* IOSAPIC RTE index (-1 => not an IOSAPIC interrupt) */ | 113 | char rte_index; /* IOSAPIC RTE index */ |
114 | int refcnt; /* reference counter */ | ||
115 | unsigned int flags; /* flags */ | ||
116 | } ____cacheline_aligned; | ||
117 | |||
118 | static struct iosapic_intr_info { | ||
119 | struct list_head rtes; /* RTEs using this vector (empty => not an IOSAPIC interrupt) */ | ||
120 | int count; /* # of RTEs that shares this vector */ | ||
121 | u32 low32; /* current value of low word of Redirection table entry */ | ||
122 | unsigned int dest; /* destination CPU physical ID */ | ||
110 | unsigned char dmode : 3; /* delivery mode (see iosapic.h) */ | 123 | unsigned char dmode : 3; /* delivery mode (see iosapic.h) */ |
111 | unsigned char polarity: 1; /* interrupt polarity (see iosapic.h) */ | 124 | unsigned char polarity: 1; /* interrupt polarity (see iosapic.h) */ |
112 | unsigned char trigger : 1; /* trigger mode (see iosapic.h) */ | 125 | unsigned char trigger : 1; /* trigger mode (see iosapic.h) */ |
113 | int refcnt; /* reference counter */ | ||
114 | } iosapic_intr_info[IA64_NUM_VECTORS]; | 126 | } iosapic_intr_info[IA64_NUM_VECTORS]; |
115 | 127 | ||
116 | static struct iosapic { | 128 | static struct iosapic { |
@@ -126,6 +138,8 @@ static int num_iosapic; | |||
126 | 138 | ||
127 | static unsigned char pcat_compat __initdata; /* 8259 compatibility flag */ | 139 | static unsigned char pcat_compat __initdata; /* 8259 compatibility flag */ |
128 | 140 | ||
141 | static int iosapic_kmalloc_ok; | ||
142 | static LIST_HEAD(free_rte_list); | ||
129 | 143 | ||
130 | /* | 144 | /* |
131 | * Find an IOSAPIC associated with a GSI | 145 | * Find an IOSAPIC associated with a GSI |
@@ -147,10 +161,12 @@ static inline int | |||
147 | _gsi_to_vector (unsigned int gsi) | 161 | _gsi_to_vector (unsigned int gsi) |
148 | { | 162 | { |
149 | struct iosapic_intr_info *info; | 163 | struct iosapic_intr_info *info; |
164 | struct iosapic_rte_info *rte; | ||
150 | 165 | ||
151 | for (info = iosapic_intr_info; info < iosapic_intr_info + IA64_NUM_VECTORS; ++info) | 166 | for (info = iosapic_intr_info; info < iosapic_intr_info + IA64_NUM_VECTORS; ++info) |
152 | if (info->gsi_base + info->rte_index == gsi) | 167 | list_for_each_entry(rte, &info->rtes, rte_list) |
153 | return info - iosapic_intr_info; | 168 | if (rte->gsi_base + rte->rte_index == gsi) |
169 | return info - iosapic_intr_info; | ||
154 | return -1; | 170 | return -1; |
155 | } | 171 | } |
156 | 172 | ||
@@ -167,33 +183,52 @@ gsi_to_vector (unsigned int gsi) | |||
167 | int | 183 | int |
168 | gsi_to_irq (unsigned int gsi) | 184 | gsi_to_irq (unsigned int gsi) |
169 | { | 185 | { |
186 | unsigned long flags; | ||
187 | int irq; | ||
170 | /* | 188 | /* |
171 | * XXX fix me: this assumes an identity mapping vetween IA-64 vector and Linux irq | 189 | * XXX fix me: this assumes an identity mapping vetween IA-64 vector and Linux irq |
172 | * numbers... | 190 | * numbers... |
173 | */ | 191 | */ |
174 | return _gsi_to_vector(gsi); | 192 | spin_lock_irqsave(&iosapic_lock, flags); |
193 | { | ||
194 | irq = _gsi_to_vector(gsi); | ||
195 | } | ||
196 | spin_unlock_irqrestore(&iosapic_lock, flags); | ||
197 | |||
198 | return irq; | ||
199 | } | ||
200 | |||
201 | static struct iosapic_rte_info *gsi_vector_to_rte(unsigned int gsi, unsigned int vec) | ||
202 | { | ||
203 | struct iosapic_rte_info *rte; | ||
204 | |||
205 | list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, rte_list) | ||
206 | if (rte->gsi_base + rte->rte_index == gsi) | ||
207 | return rte; | ||
208 | return NULL; | ||
175 | } | 209 | } |
176 | 210 | ||
177 | static void | 211 | static void |
178 | set_rte (unsigned int vector, unsigned int dest, int mask) | 212 | set_rte (unsigned int gsi, unsigned int vector, unsigned int dest, int mask) |
179 | { | 213 | { |
180 | unsigned long pol, trigger, dmode; | 214 | unsigned long pol, trigger, dmode; |
181 | u32 low32, high32; | 215 | u32 low32, high32; |
182 | char __iomem *addr; | 216 | char __iomem *addr; |
183 | int rte_index; | 217 | int rte_index; |
184 | char redir; | 218 | char redir; |
219 | struct iosapic_rte_info *rte; | ||
185 | 220 | ||
186 | DBG(KERN_DEBUG"IOSAPIC: routing vector %d to 0x%x\n", vector, dest); | 221 | DBG(KERN_DEBUG"IOSAPIC: routing vector %d to 0x%x\n", vector, dest); |
187 | 222 | ||
188 | rte_index = iosapic_intr_info[vector].rte_index; | 223 | rte = gsi_vector_to_rte(gsi, vector); |
189 | if (rte_index < 0) | 224 | if (!rte) |
190 | return; /* not an IOSAPIC interrupt */ | 225 | return; /* not an IOSAPIC interrupt */ |
191 | 226 | ||
192 | addr = iosapic_intr_info[vector].addr; | 227 | rte_index = rte->rte_index; |
228 | addr = rte->addr; | ||
193 | pol = iosapic_intr_info[vector].polarity; | 229 | pol = iosapic_intr_info[vector].polarity; |
194 | trigger = iosapic_intr_info[vector].trigger; | 230 | trigger = iosapic_intr_info[vector].trigger; |
195 | dmode = iosapic_intr_info[vector].dmode; | 231 | dmode = iosapic_intr_info[vector].dmode; |
196 | vector &= (~IA64_IRQ_REDIRECTED); | ||
197 | 232 | ||
198 | redir = (dmode == IOSAPIC_LOWEST_PRIORITY) ? 1 : 0; | 233 | redir = (dmode == IOSAPIC_LOWEST_PRIORITY) ? 1 : 0; |
199 | 234 | ||
@@ -221,6 +256,7 @@ set_rte (unsigned int vector, unsigned int dest, int mask) | |||
221 | iosapic_write(addr, IOSAPIC_RTE_HIGH(rte_index), high32); | 256 | iosapic_write(addr, IOSAPIC_RTE_HIGH(rte_index), high32); |
222 | iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32); | 257 | iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32); |
223 | iosapic_intr_info[vector].low32 = low32; | 258 | iosapic_intr_info[vector].low32 = low32; |
259 | iosapic_intr_info[vector].dest = dest; | ||
224 | } | 260 | } |
225 | 261 | ||
226 | static void | 262 | static void |
@@ -237,18 +273,20 @@ mask_irq (unsigned int irq) | |||
237 | u32 low32; | 273 | u32 low32; |
238 | int rte_index; | 274 | int rte_index; |
239 | ia64_vector vec = irq_to_vector(irq); | 275 | ia64_vector vec = irq_to_vector(irq); |
276 | struct iosapic_rte_info *rte; | ||
240 | 277 | ||
241 | addr = iosapic_intr_info[vec].addr; | 278 | if (list_empty(&iosapic_intr_info[vec].rtes)) |
242 | rte_index = iosapic_intr_info[vec].rte_index; | ||
243 | |||
244 | if (rte_index < 0) | ||
245 | return; /* not an IOSAPIC interrupt! */ | 279 | return; /* not an IOSAPIC interrupt! */ |
246 | 280 | ||
247 | spin_lock_irqsave(&iosapic_lock, flags); | 281 | spin_lock_irqsave(&iosapic_lock, flags); |
248 | { | 282 | { |
249 | /* set only the mask bit */ | 283 | /* set only the mask bit */ |
250 | low32 = iosapic_intr_info[vec].low32 |= IOSAPIC_MASK; | 284 | low32 = iosapic_intr_info[vec].low32 |= IOSAPIC_MASK; |
251 | iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32); | 285 | list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, rte_list) { |
286 | addr = rte->addr; | ||
287 | rte_index = rte->rte_index; | ||
288 | iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32); | ||
289 | } | ||
252 | } | 290 | } |
253 | spin_unlock_irqrestore(&iosapic_lock, flags); | 291 | spin_unlock_irqrestore(&iosapic_lock, flags); |
254 | } | 292 | } |
@@ -261,16 +299,19 @@ unmask_irq (unsigned int irq) | |||
261 | u32 low32; | 299 | u32 low32; |
262 | int rte_index; | 300 | int rte_index; |
263 | ia64_vector vec = irq_to_vector(irq); | 301 | ia64_vector vec = irq_to_vector(irq); |
302 | struct iosapic_rte_info *rte; | ||
264 | 303 | ||
265 | addr = iosapic_intr_info[vec].addr; | 304 | if (list_empty(&iosapic_intr_info[vec].rtes)) |
266 | rte_index = iosapic_intr_info[vec].rte_index; | ||
267 | if (rte_index < 0) | ||
268 | return; /* not an IOSAPIC interrupt! */ | 305 | return; /* not an IOSAPIC interrupt! */ |
269 | 306 | ||
270 | spin_lock_irqsave(&iosapic_lock, flags); | 307 | spin_lock_irqsave(&iosapic_lock, flags); |
271 | { | 308 | { |
272 | low32 = iosapic_intr_info[vec].low32 &= ~IOSAPIC_MASK; | 309 | low32 = iosapic_intr_info[vec].low32 &= ~IOSAPIC_MASK; |
273 | iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32); | 310 | list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, rte_list) { |
311 | addr = rte->addr; | ||
312 | rte_index = rte->rte_index; | ||
313 | iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32); | ||
314 | } | ||
274 | } | 315 | } |
275 | spin_unlock_irqrestore(&iosapic_lock, flags); | 316 | spin_unlock_irqrestore(&iosapic_lock, flags); |
276 | } | 317 | } |
@@ -286,6 +327,7 @@ iosapic_set_affinity (unsigned int irq, cpumask_t mask) | |||
286 | char __iomem *addr; | 327 | char __iomem *addr; |
287 | int redir = (irq & IA64_IRQ_REDIRECTED) ? 1 : 0; | 328 | int redir = (irq & IA64_IRQ_REDIRECTED) ? 1 : 0; |
288 | ia64_vector vec; | 329 | ia64_vector vec; |
330 | struct iosapic_rte_info *rte; | ||
289 | 331 | ||
290 | irq &= (~IA64_IRQ_REDIRECTED); | 332 | irq &= (~IA64_IRQ_REDIRECTED); |
291 | vec = irq_to_vector(irq); | 333 | vec = irq_to_vector(irq); |
@@ -295,10 +337,7 @@ iosapic_set_affinity (unsigned int irq, cpumask_t mask) | |||
295 | 337 | ||
296 | dest = cpu_physical_id(first_cpu(mask)); | 338 | dest = cpu_physical_id(first_cpu(mask)); |
297 | 339 | ||
298 | rte_index = iosapic_intr_info[vec].rte_index; | 340 | if (list_empty(&iosapic_intr_info[vec].rtes)) |
299 | addr = iosapic_intr_info[vec].addr; | ||
300 | |||
301 | if (rte_index < 0) | ||
302 | return; /* not an IOSAPIC interrupt */ | 341 | return; /* not an IOSAPIC interrupt */ |
303 | 342 | ||
304 | set_irq_affinity_info(irq, dest, redir); | 343 | set_irq_affinity_info(irq, dest, redir); |
@@ -318,8 +357,13 @@ iosapic_set_affinity (unsigned int irq, cpumask_t mask) | |||
318 | low32 |= (IOSAPIC_FIXED << IOSAPIC_DELIVERY_SHIFT); | 357 | low32 |= (IOSAPIC_FIXED << IOSAPIC_DELIVERY_SHIFT); |
319 | 358 | ||
320 | iosapic_intr_info[vec].low32 = low32; | 359 | iosapic_intr_info[vec].low32 = low32; |
321 | iosapic_write(addr, IOSAPIC_RTE_HIGH(rte_index), high32); | 360 | iosapic_intr_info[vec].dest = dest; |
322 | iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32); | 361 | list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, rte_list) { |
362 | addr = rte->addr; | ||
363 | rte_index = rte->rte_index; | ||
364 | iosapic_write(addr, IOSAPIC_RTE_HIGH(rte_index), high32); | ||
365 | iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32); | ||
366 | } | ||
323 | } | 367 | } |
324 | spin_unlock_irqrestore(&iosapic_lock, flags); | 368 | spin_unlock_irqrestore(&iosapic_lock, flags); |
325 | #endif | 369 | #endif |
@@ -340,9 +384,11 @@ static void | |||
340 | iosapic_end_level_irq (unsigned int irq) | 384 | iosapic_end_level_irq (unsigned int irq) |
341 | { | 385 | { |
342 | ia64_vector vec = irq_to_vector(irq); | 386 | ia64_vector vec = irq_to_vector(irq); |
387 | struct iosapic_rte_info *rte; | ||
343 | 388 | ||
344 | move_irq(irq); | 389 | move_irq(irq); |
345 | iosapic_eoi(iosapic_intr_info[vec].addr, vec); | 390 | list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, rte_list) |
391 | iosapic_eoi(rte->addr, vec); | ||
346 | } | 392 | } |
347 | 393 | ||
348 | #define iosapic_shutdown_level_irq mask_irq | 394 | #define iosapic_shutdown_level_irq mask_irq |
@@ -422,6 +468,34 @@ iosapic_version (char __iomem *addr) | |||
422 | return iosapic_read(addr, IOSAPIC_VERSION); | 468 | return iosapic_read(addr, IOSAPIC_VERSION); |
423 | } | 469 | } |
424 | 470 | ||
471 | static int iosapic_find_sharable_vector (unsigned long trigger, unsigned long pol) | ||
472 | { | ||
473 | int i, vector = -1, min_count = -1; | ||
474 | struct iosapic_intr_info *info; | ||
475 | |||
476 | /* | ||
477 | * shared vectors for edge-triggered interrupts are not | ||
478 | * supported yet | ||
479 | */ | ||
480 | if (trigger == IOSAPIC_EDGE) | ||
481 | return -1; | ||
482 | |||
483 | for (i = IA64_FIRST_DEVICE_VECTOR; i <= IA64_LAST_DEVICE_VECTOR; i++) { | ||
484 | info = &iosapic_intr_info[i]; | ||
485 | if (info->trigger == trigger && info->polarity == pol && | ||
486 | (info->dmode == IOSAPIC_FIXED || info->dmode == IOSAPIC_LOWEST_PRIORITY)) { | ||
487 | if (min_count == -1 || info->count < min_count) { | ||
488 | vector = i; | ||
489 | min_count = info->count; | ||
490 | } | ||
491 | } | ||
492 | } | ||
493 | if (vector < 0) | ||
494 | panic("%s: out of interrupt vectors!\n", __FUNCTION__); | ||
495 | |||
496 | return vector; | ||
497 | } | ||
498 | |||
425 | /* | 499 | /* |
426 | * if the given vector is already owned by other, | 500 | * if the given vector is already owned by other, |
427 | * assign a new vector for the other and make the vector available | 501 | * assign a new vector for the other and make the vector available |
@@ -431,19 +505,63 @@ iosapic_reassign_vector (int vector) | |||
431 | { | 505 | { |
432 | int new_vector; | 506 | int new_vector; |
433 | 507 | ||
434 | if (iosapic_intr_info[vector].rte_index >= 0 || iosapic_intr_info[vector].addr | 508 | if (!list_empty(&iosapic_intr_info[vector].rtes)) { |
435 | || iosapic_intr_info[vector].gsi_base || iosapic_intr_info[vector].dmode | ||
436 | || iosapic_intr_info[vector].polarity || iosapic_intr_info[vector].trigger) | ||
437 | { | ||
438 | new_vector = assign_irq_vector(AUTO_ASSIGN); | 509 | new_vector = assign_irq_vector(AUTO_ASSIGN); |
439 | printk(KERN_INFO "Reassigning vector %d to %d\n", vector, new_vector); | 510 | printk(KERN_INFO "Reassigning vector %d to %d\n", vector, new_vector); |
440 | memcpy(&iosapic_intr_info[new_vector], &iosapic_intr_info[vector], | 511 | memcpy(&iosapic_intr_info[new_vector], &iosapic_intr_info[vector], |
441 | sizeof(struct iosapic_intr_info)); | 512 | sizeof(struct iosapic_intr_info)); |
513 | INIT_LIST_HEAD(&iosapic_intr_info[new_vector].rtes); | ||
514 | list_move(iosapic_intr_info[vector].rtes.next, &iosapic_intr_info[new_vector].rtes); | ||
442 | memset(&iosapic_intr_info[vector], 0, sizeof(struct iosapic_intr_info)); | 515 | memset(&iosapic_intr_info[vector], 0, sizeof(struct iosapic_intr_info)); |
443 | iosapic_intr_info[vector].rte_index = -1; | 516 | iosapic_intr_info[vector].low32 = IOSAPIC_MASK; |
517 | INIT_LIST_HEAD(&iosapic_intr_info[vector].rtes); | ||
444 | } | 518 | } |
445 | } | 519 | } |
446 | 520 | ||
521 | static struct iosapic_rte_info *iosapic_alloc_rte (void) | ||
522 | { | ||
523 | int i; | ||
524 | struct iosapic_rte_info *rte; | ||
525 | int preallocated = 0; | ||
526 | |||
527 | if (!iosapic_kmalloc_ok && list_empty(&free_rte_list)) { | ||
528 | rte = alloc_bootmem(sizeof(struct iosapic_rte_info) * NR_PREALLOCATE_RTE_ENTRIES); | ||
529 | if (!rte) | ||
530 | return NULL; | ||
531 | for (i = 0; i < NR_PREALLOCATE_RTE_ENTRIES; i++, rte++) | ||
532 | list_add(&rte->rte_list, &free_rte_list); | ||
533 | } | ||
534 | |||
535 | if (!list_empty(&free_rte_list)) { | ||
536 | rte = list_entry(free_rte_list.next, struct iosapic_rte_info, rte_list); | ||
537 | list_del(&rte->rte_list); | ||
538 | preallocated++; | ||
539 | } else { | ||
540 | rte = kmalloc(sizeof(struct iosapic_rte_info), GFP_ATOMIC); | ||
541 | if (!rte) | ||
542 | return NULL; | ||
543 | } | ||
544 | |||
545 | memset(rte, 0, sizeof(struct iosapic_rte_info)); | ||
546 | if (preallocated) | ||
547 | rte->flags |= RTE_PREALLOCATED; | ||
548 | |||
549 | return rte; | ||
550 | } | ||
551 | |||
552 | static void iosapic_free_rte (struct iosapic_rte_info *rte) | ||
553 | { | ||
554 | if (rte->flags & RTE_PREALLOCATED) | ||
555 | list_add_tail(&rte->rte_list, &free_rte_list); | ||
556 | else | ||
557 | kfree(rte); | ||
558 | } | ||
559 | |||
560 | static inline int vector_is_shared (int vector) | ||
561 | { | ||
562 | return (iosapic_intr_info[vector].count > 1); | ||
563 | } | ||
564 | |||
447 | static void | 565 | static void |
448 | register_intr (unsigned int gsi, int vector, unsigned char delivery, | 566 | register_intr (unsigned int gsi, int vector, unsigned char delivery, |
449 | unsigned long polarity, unsigned long trigger) | 567 | unsigned long polarity, unsigned long trigger) |
@@ -454,6 +572,7 @@ register_intr (unsigned int gsi, int vector, unsigned char delivery, | |||
454 | int index; | 572 | int index; |
455 | unsigned long gsi_base; | 573 | unsigned long gsi_base; |
456 | void __iomem *iosapic_address; | 574 | void __iomem *iosapic_address; |
575 | struct iosapic_rte_info *rte; | ||
457 | 576 | ||
458 | index = find_iosapic(gsi); | 577 | index = find_iosapic(gsi); |
459 | if (index < 0) { | 578 | if (index < 0) { |
@@ -464,14 +583,33 @@ register_intr (unsigned int gsi, int vector, unsigned char delivery, | |||
464 | iosapic_address = iosapic_lists[index].addr; | 583 | iosapic_address = iosapic_lists[index].addr; |
465 | gsi_base = iosapic_lists[index].gsi_base; | 584 | gsi_base = iosapic_lists[index].gsi_base; |
466 | 585 | ||
467 | rte_index = gsi - gsi_base; | 586 | rte = gsi_vector_to_rte(gsi, vector); |
468 | iosapic_intr_info[vector].rte_index = rte_index; | 587 | if (!rte) { |
588 | rte = iosapic_alloc_rte(); | ||
589 | if (!rte) { | ||
590 | printk(KERN_WARNING "%s: cannot allocate memory\n", __FUNCTION__); | ||
591 | return; | ||
592 | } | ||
593 | |||
594 | rte_index = gsi - gsi_base; | ||
595 | rte->rte_index = rte_index; | ||
596 | rte->addr = iosapic_address; | ||
597 | rte->gsi_base = gsi_base; | ||
598 | rte->refcnt++; | ||
599 | list_add_tail(&rte->rte_list, &iosapic_intr_info[vector].rtes); | ||
600 | iosapic_intr_info[vector].count++; | ||
601 | } | ||
602 | else if (vector_is_shared(vector)) { | ||
603 | struct iosapic_intr_info *info = &iosapic_intr_info[vector]; | ||
604 | if (info->trigger != trigger || info->polarity != polarity) { | ||
605 | printk (KERN_WARNING "%s: cannot override the interrupt\n", __FUNCTION__); | ||
606 | return; | ||
607 | } | ||
608 | } | ||
609 | |||
469 | iosapic_intr_info[vector].polarity = polarity; | 610 | iosapic_intr_info[vector].polarity = polarity; |
470 | iosapic_intr_info[vector].dmode = delivery; | 611 | iosapic_intr_info[vector].dmode = delivery; |
471 | iosapic_intr_info[vector].addr = iosapic_address; | ||
472 | iosapic_intr_info[vector].gsi_base = gsi_base; | ||
473 | iosapic_intr_info[vector].trigger = trigger; | 612 | iosapic_intr_info[vector].trigger = trigger; |
474 | iosapic_intr_info[vector].refcnt++; | ||
475 | 613 | ||
476 | if (trigger == IOSAPIC_EDGE) | 614 | if (trigger == IOSAPIC_EDGE) |
477 | irq_type = &irq_type_iosapic_edge; | 615 | irq_type = &irq_type_iosapic_edge; |
@@ -494,6 +632,13 @@ get_target_cpu (unsigned int gsi, int vector) | |||
494 | static int cpu = -1; | 632 | static int cpu = -1; |
495 | 633 | ||
496 | /* | 634 | /* |
635 | * In case of vector shared by multiple RTEs, all RTEs that | ||
636 | * share the vector need to use the same destination CPU. | ||
637 | */ | ||
638 | if (!list_empty(&iosapic_intr_info[vector].rtes)) | ||
639 | return iosapic_intr_info[vector].dest; | ||
640 | |||
641 | /* | ||
497 | * If the platform supports redirection via XTP, let it | 642 | * If the platform supports redirection via XTP, let it |
498 | * distribute interrupts. | 643 | * distribute interrupts. |
499 | */ | 644 | */ |
@@ -565,10 +710,12 @@ int | |||
565 | iosapic_register_intr (unsigned int gsi, | 710 | iosapic_register_intr (unsigned int gsi, |
566 | unsigned long polarity, unsigned long trigger) | 711 | unsigned long polarity, unsigned long trigger) |
567 | { | 712 | { |
568 | int vector; | 713 | int vector, mask = 1; |
569 | unsigned int dest; | 714 | unsigned int dest; |
570 | unsigned long flags; | 715 | unsigned long flags; |
571 | 716 | struct iosapic_rte_info *rte; | |
717 | u32 low32; | ||
718 | again: | ||
572 | /* | 719 | /* |
573 | * If this GSI has already been registered (i.e., it's a | 720 | * If this GSI has already been registered (i.e., it's a |
574 | * shared interrupt, or we lost a race to register it), | 721 | * shared interrupt, or we lost a race to register it), |
@@ -578,19 +725,45 @@ iosapic_register_intr (unsigned int gsi, | |||
578 | { | 725 | { |
579 | vector = gsi_to_vector(gsi); | 726 | vector = gsi_to_vector(gsi); |
580 | if (vector > 0) { | 727 | if (vector > 0) { |
581 | iosapic_intr_info[vector].refcnt++; | 728 | rte = gsi_vector_to_rte(gsi, vector); |
729 | rte->refcnt++; | ||
582 | spin_unlock_irqrestore(&iosapic_lock, flags); | 730 | spin_unlock_irqrestore(&iosapic_lock, flags); |
583 | return vector; | 731 | return vector; |
584 | } | 732 | } |
733 | } | ||
734 | spin_unlock_irqrestore(&iosapic_lock, flags); | ||
735 | |||
736 | /* If vector is running out, we try to find a sharable vector */ | ||
737 | vector = assign_irq_vector_nopanic(AUTO_ASSIGN); | ||
738 | if (vector < 0) | ||
739 | vector = iosapic_find_sharable_vector(trigger, polarity); | ||
740 | |||
741 | spin_lock_irqsave(&irq_descp(vector)->lock, flags); | ||
742 | spin_lock(&iosapic_lock); | ||
743 | { | ||
744 | if (gsi_to_vector(gsi) > 0) { | ||
745 | if (list_empty(&iosapic_intr_info[vector].rtes)) | ||
746 | free_irq_vector(vector); | ||
747 | spin_unlock(&iosapic_lock); | ||
748 | spin_unlock_irqrestore(&irq_descp(vector)->lock, flags); | ||
749 | goto again; | ||
750 | } | ||
585 | 751 | ||
586 | vector = assign_irq_vector(AUTO_ASSIGN); | ||
587 | dest = get_target_cpu(gsi, vector); | 752 | dest = get_target_cpu(gsi, vector); |
588 | register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY, | 753 | register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY, |
589 | polarity, trigger); | 754 | polarity, trigger); |
590 | 755 | ||
591 | set_rte(vector, dest, 1); | 756 | /* |
757 | * If the vector is shared and already unmasked for | ||
758 | * other interrupt sources, don't mask it. | ||
759 | */ | ||
760 | low32 = iosapic_intr_info[vector].low32; | ||
761 | if (vector_is_shared(vector) && !(low32 & IOSAPIC_MASK)) | ||
762 | mask = 0; | ||
763 | set_rte(gsi, vector, dest, mask); | ||
592 | } | 764 | } |
593 | spin_unlock_irqrestore(&iosapic_lock, flags); | 765 | spin_unlock(&iosapic_lock); |
766 | spin_unlock_irqrestore(&irq_descp(vector)->lock, flags); | ||
594 | 767 | ||
595 | printk(KERN_INFO "GSI %u (%s, %s) -> CPU %d (0x%04x) vector %d\n", | 768 | printk(KERN_INFO "GSI %u (%s, %s) -> CPU %d (0x%04x) vector %d\n", |
596 | gsi, (trigger == IOSAPIC_EDGE ? "edge" : "level"), | 769 | gsi, (trigger == IOSAPIC_EDGE ? "edge" : "level"), |
@@ -607,8 +780,10 @@ iosapic_unregister_intr (unsigned int gsi) | |||
607 | unsigned long flags; | 780 | unsigned long flags; |
608 | int irq, vector; | 781 | int irq, vector; |
609 | irq_desc_t *idesc; | 782 | irq_desc_t *idesc; |
610 | int rte_index; | 783 | u32 low32; |
611 | unsigned long trigger, polarity; | 784 | unsigned long trigger, polarity; |
785 | unsigned int dest; | ||
786 | struct iosapic_rte_info *rte; | ||
612 | 787 | ||
613 | /* | 788 | /* |
614 | * If the irq associated with the gsi is not found, | 789 | * If the irq associated with the gsi is not found, |
@@ -627,54 +802,56 @@ iosapic_unregister_intr (unsigned int gsi) | |||
627 | spin_lock_irqsave(&idesc->lock, flags); | 802 | spin_lock_irqsave(&idesc->lock, flags); |
628 | spin_lock(&iosapic_lock); | 803 | spin_lock(&iosapic_lock); |
629 | { | 804 | { |
630 | rte_index = iosapic_intr_info[vector].rte_index; | 805 | if ((rte = gsi_vector_to_rte(gsi, vector)) == NULL) { |
631 | if (rte_index < 0) { | ||
632 | spin_unlock(&iosapic_lock); | ||
633 | spin_unlock_irqrestore(&idesc->lock, flags); | ||
634 | printk(KERN_ERR "iosapic_unregister_intr(%u) unbalanced\n", gsi); | 806 | printk(KERN_ERR "iosapic_unregister_intr(%u) unbalanced\n", gsi); |
635 | WARN_ON(1); | 807 | WARN_ON(1); |
636 | return; | 808 | goto out; |
637 | } | 809 | } |
638 | 810 | ||
639 | if (--iosapic_intr_info[vector].refcnt > 0) { | 811 | if (--rte->refcnt > 0) |
640 | spin_unlock(&iosapic_lock); | 812 | goto out; |
641 | spin_unlock_irqrestore(&idesc->lock, flags); | ||
642 | return; | ||
643 | } | ||
644 | 813 | ||
645 | /* | 814 | /* Mask the interrupt */ |
646 | * If interrupt handlers still exist on the irq | 815 | low32 = iosapic_intr_info[vector].low32 | IOSAPIC_MASK; |
647 | * associated with the gsi, don't unregister the | 816 | iosapic_write(rte->addr, IOSAPIC_RTE_LOW(rte->rte_index), low32); |
648 | * interrupt. | ||
649 | */ | ||
650 | if (idesc->action) { | ||
651 | iosapic_intr_info[vector].refcnt++; | ||
652 | spin_unlock(&iosapic_lock); | ||
653 | spin_unlock_irqrestore(&idesc->lock, flags); | ||
654 | printk(KERN_WARNING "Cannot unregister GSI. IRQ %u is still in use.\n", irq); | ||
655 | return; | ||
656 | } | ||
657 | 817 | ||
658 | /* Clear the interrupt controller descriptor. */ | 818 | /* Remove the rte entry from the list */ |
659 | idesc->handler = &no_irq_type; | 819 | list_del(&rte->rte_list); |
820 | iosapic_intr_info[vector].count--; | ||
821 | iosapic_free_rte(rte); | ||
660 | 822 | ||
661 | trigger = iosapic_intr_info[vector].trigger; | 823 | trigger = iosapic_intr_info[vector].trigger; |
662 | polarity = iosapic_intr_info[vector].polarity; | 824 | polarity = iosapic_intr_info[vector].polarity; |
825 | dest = iosapic_intr_info[vector].dest; | ||
826 | printk(KERN_INFO "GSI %u (%s, %s) -> CPU %d (0x%04x) vector %d unregistered\n", | ||
827 | gsi, (trigger == IOSAPIC_EDGE ? "edge" : "level"), | ||
828 | (polarity == IOSAPIC_POL_HIGH ? "high" : "low"), | ||
829 | cpu_logical_id(dest), dest, vector); | ||
830 | |||
831 | if (list_empty(&iosapic_intr_info[vector].rtes)) { | ||
832 | /* Sanity check */ | ||
833 | BUG_ON(iosapic_intr_info[vector].count); | ||
834 | |||
835 | /* Clear the interrupt controller descriptor */ | ||
836 | idesc->handler = &no_irq_type; | ||
837 | |||
838 | /* Clear the interrupt information */ | ||
839 | memset(&iosapic_intr_info[vector], 0, sizeof(struct iosapic_intr_info)); | ||
840 | iosapic_intr_info[vector].low32 |= IOSAPIC_MASK; | ||
841 | INIT_LIST_HEAD(&iosapic_intr_info[vector].rtes); | ||
842 | |||
843 | if (idesc->action) { | ||
844 | printk(KERN_ERR "interrupt handlers still exist on IRQ %u\n", irq); | ||
845 | WARN_ON(1); | ||
846 | } | ||
663 | 847 | ||
664 | /* Clear the interrupt information. */ | 848 | /* Free the interrupt vector */ |
665 | memset(&iosapic_intr_info[vector], 0, sizeof(struct iosapic_intr_info)); | 849 | free_irq_vector(vector); |
666 | iosapic_intr_info[vector].rte_index = -1; /* mark as unused */ | 850 | } |
667 | } | 851 | } |
852 | out: | ||
668 | spin_unlock(&iosapic_lock); | 853 | spin_unlock(&iosapic_lock); |
669 | spin_unlock_irqrestore(&idesc->lock, flags); | 854 | spin_unlock_irqrestore(&idesc->lock, flags); |
670 | |||
671 | /* Free the interrupt vector */ | ||
672 | free_irq_vector(vector); | ||
673 | |||
674 | printk(KERN_INFO "GSI %u (%s, %s) -> vector %d unregisterd.\n", | ||
675 | gsi, (trigger == IOSAPIC_EDGE ? "edge" : "level"), | ||
676 | (polarity == IOSAPIC_POL_HIGH ? "high" : "low"), | ||
677 | vector); | ||
678 | } | 855 | } |
679 | #endif /* CONFIG_ACPI_DEALLOCATE_IRQ */ | 856 | #endif /* CONFIG_ACPI_DEALLOCATE_IRQ */ |
680 | 857 | ||
@@ -724,7 +901,7 @@ iosapic_register_platform_intr (u32 int_type, unsigned int gsi, | |||
724 | (polarity == IOSAPIC_POL_HIGH ? "high" : "low"), | 901 | (polarity == IOSAPIC_POL_HIGH ? "high" : "low"), |
725 | cpu_logical_id(dest), dest, vector); | 902 | cpu_logical_id(dest), dest, vector); |
726 | 903 | ||
727 | set_rte(vector, dest, mask); | 904 | set_rte(gsi, vector, dest, mask); |
728 | return vector; | 905 | return vector; |
729 | } | 906 | } |
730 | 907 | ||
@@ -750,7 +927,7 @@ iosapic_override_isa_irq (unsigned int isa_irq, unsigned int gsi, | |||
750 | polarity == IOSAPIC_POL_HIGH ? "high" : "low", | 927 | polarity == IOSAPIC_POL_HIGH ? "high" : "low", |
751 | cpu_logical_id(dest), dest, vector); | 928 | cpu_logical_id(dest), dest, vector); |
752 | 929 | ||
753 | set_rte(vector, dest, 1); | 930 | set_rte(gsi, vector, dest, 1); |
754 | } | 931 | } |
755 | 932 | ||
756 | void __init | 933 | void __init |
@@ -758,8 +935,10 @@ iosapic_system_init (int system_pcat_compat) | |||
758 | { | 935 | { |
759 | int vector; | 936 | int vector; |
760 | 937 | ||
761 | for (vector = 0; vector < IA64_NUM_VECTORS; ++vector) | 938 | for (vector = 0; vector < IA64_NUM_VECTORS; ++vector) { |
762 | iosapic_intr_info[vector].rte_index = -1; /* mark as unused */ | 939 | iosapic_intr_info[vector].low32 = IOSAPIC_MASK; |
940 | INIT_LIST_HEAD(&iosapic_intr_info[vector].rtes); /* mark as unused */ | ||
941 | } | ||
763 | 942 | ||
764 | pcat_compat = system_pcat_compat; | 943 | pcat_compat = system_pcat_compat; |
765 | if (pcat_compat) { | 944 | if (pcat_compat) { |
@@ -825,3 +1004,10 @@ map_iosapic_to_node(unsigned int gsi_base, int node) | |||
825 | return; | 1004 | return; |
826 | } | 1005 | } |
827 | #endif | 1006 | #endif |
1007 | |||
1008 | static int __init iosapic_enable_kmalloc (void) | ||
1009 | { | ||
1010 | iosapic_kmalloc_ok = 1; | ||
1011 | return 0; | ||
1012 | } | ||
1013 | core_initcall (iosapic_enable_kmalloc); | ||
diff --git a/arch/ia64/kernel/irq_ia64.c b/arch/ia64/kernel/irq_ia64.c index 5ba06ebe355b..4fe60c7a2e90 100644 --- a/arch/ia64/kernel/irq_ia64.c +++ b/arch/ia64/kernel/irq_ia64.c | |||
@@ -63,20 +63,30 @@ EXPORT_SYMBOL(isa_irq_to_vector_map); | |||
63 | static unsigned long ia64_vector_mask[BITS_TO_LONGS(IA64_NUM_DEVICE_VECTORS)]; | 63 | static unsigned long ia64_vector_mask[BITS_TO_LONGS(IA64_NUM_DEVICE_VECTORS)]; |
64 | 64 | ||
65 | int | 65 | int |
66 | assign_irq_vector (int irq) | 66 | assign_irq_vector_nopanic (int irq) |
67 | { | 67 | { |
68 | int pos, vector; | 68 | int pos, vector; |
69 | again: | 69 | again: |
70 | pos = find_first_zero_bit(ia64_vector_mask, IA64_NUM_DEVICE_VECTORS); | 70 | pos = find_first_zero_bit(ia64_vector_mask, IA64_NUM_DEVICE_VECTORS); |
71 | vector = IA64_FIRST_DEVICE_VECTOR + pos; | 71 | vector = IA64_FIRST_DEVICE_VECTOR + pos; |
72 | if (vector > IA64_LAST_DEVICE_VECTOR) | 72 | if (vector > IA64_LAST_DEVICE_VECTOR) |
73 | /* XXX could look for sharable vectors instead of panic'ing... */ | 73 | return -1; |
74 | panic("assign_irq_vector: out of interrupt vectors!"); | ||
75 | if (test_and_set_bit(pos, ia64_vector_mask)) | 74 | if (test_and_set_bit(pos, ia64_vector_mask)) |
76 | goto again; | 75 | goto again; |
77 | return vector; | 76 | return vector; |
78 | } | 77 | } |
79 | 78 | ||
79 | int | ||
80 | assign_irq_vector (int irq) | ||
81 | { | ||
82 | int vector = assign_irq_vector_nopanic(irq); | ||
83 | |||
84 | if (vector < 0) | ||
85 | panic("assign_irq_vector: out of interrupt vectors!"); | ||
86 | |||
87 | return vector; | ||
88 | } | ||
89 | |||
80 | void | 90 | void |
81 | free_irq_vector (int vector) | 91 | free_irq_vector (int vector) |
82 | { | 92 | { |
diff --git a/arch/ia64/kernel/perfmon.c b/arch/ia64/kernel/perfmon.c index 71147be3279c..376fcbc3f8da 100644 --- a/arch/ia64/kernel/perfmon.c +++ b/arch/ia64/kernel/perfmon.c | |||
@@ -480,14 +480,6 @@ typedef struct { | |||
480 | #define PFM_CMD_ARG_MANY -1 /* cannot be zero */ | 480 | #define PFM_CMD_ARG_MANY -1 /* cannot be zero */ |
481 | 481 | ||
482 | typedef struct { | 482 | typedef struct { |
483 | int debug; /* turn on/off debugging via syslog */ | ||
484 | int debug_ovfl; /* turn on/off debug printk in overflow handler */ | ||
485 | int fastctxsw; /* turn on/off fast (unsecure) ctxsw */ | ||
486 | int expert_mode; /* turn on/off value checking */ | ||
487 | int debug_pfm_read; | ||
488 | } pfm_sysctl_t; | ||
489 | |||
490 | typedef struct { | ||
491 | unsigned long pfm_spurious_ovfl_intr_count; /* keep track of spurious ovfl interrupts */ | 483 | unsigned long pfm_spurious_ovfl_intr_count; /* keep track of spurious ovfl interrupts */ |
492 | unsigned long pfm_replay_ovfl_intr_count; /* keep track of replayed ovfl interrupts */ | 484 | unsigned long pfm_replay_ovfl_intr_count; /* keep track of replayed ovfl interrupts */ |
493 | unsigned long pfm_ovfl_intr_count; /* keep track of ovfl interrupts */ | 485 | unsigned long pfm_ovfl_intr_count; /* keep track of ovfl interrupts */ |
@@ -514,8 +506,8 @@ static LIST_HEAD(pfm_buffer_fmt_list); | |||
514 | static pmu_config_t *pmu_conf; | 506 | static pmu_config_t *pmu_conf; |
515 | 507 | ||
516 | /* sysctl() controls */ | 508 | /* sysctl() controls */ |
517 | static pfm_sysctl_t pfm_sysctl; | 509 | pfm_sysctl_t pfm_sysctl; |
518 | int pfm_debug_var; | 510 | EXPORT_SYMBOL(pfm_sysctl); |
519 | 511 | ||
520 | static ctl_table pfm_ctl_table[]={ | 512 | static ctl_table pfm_ctl_table[]={ |
521 | {1, "debug", &pfm_sysctl.debug, sizeof(int), 0666, NULL, &proc_dointvec, NULL,}, | 513 | {1, "debug", &pfm_sysctl.debug, sizeof(int), 0666, NULL, &proc_dointvec, NULL,}, |
@@ -1576,7 +1568,7 @@ pfm_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos) | |||
1576 | goto abort_locked; | 1568 | goto abort_locked; |
1577 | } | 1569 | } |
1578 | 1570 | ||
1579 | DPRINT(("[%d] fd=%d type=%d\n", current->pid, msg->pfm_gen_msg.msg_ctx_fd, msg->pfm_gen_msg.msg_type)); | 1571 | DPRINT(("fd=%d type=%d\n", msg->pfm_gen_msg.msg_ctx_fd, msg->pfm_gen_msg.msg_type)); |
1580 | 1572 | ||
1581 | ret = -EFAULT; | 1573 | ret = -EFAULT; |
1582 | if(copy_to_user(buf, msg, sizeof(pfm_msg_t)) == 0) ret = sizeof(pfm_msg_t); | 1574 | if(copy_to_user(buf, msg, sizeof(pfm_msg_t)) == 0) ret = sizeof(pfm_msg_t); |
@@ -3695,8 +3687,6 @@ pfm_debug(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) | |||
3695 | 3687 | ||
3696 | pfm_sysctl.debug = m == 0 ? 0 : 1; | 3688 | pfm_sysctl.debug = m == 0 ? 0 : 1; |
3697 | 3689 | ||
3698 | pfm_debug_var = pfm_sysctl.debug; | ||
3699 | |||
3700 | printk(KERN_INFO "perfmon debugging %s (timing reset)\n", pfm_sysctl.debug ? "on" : "off"); | 3690 | printk(KERN_INFO "perfmon debugging %s (timing reset)\n", pfm_sysctl.debug ? "on" : "off"); |
3701 | 3691 | ||
3702 | if (m == 0) { | 3692 | if (m == 0) { |
@@ -4996,13 +4986,21 @@ pfm_context_force_terminate(pfm_context_t *ctx, struct pt_regs *regs) | |||
4996 | } | 4986 | } |
4997 | 4987 | ||
4998 | static int pfm_ovfl_notify_user(pfm_context_t *ctx, unsigned long ovfl_pmds); | 4988 | static int pfm_ovfl_notify_user(pfm_context_t *ctx, unsigned long ovfl_pmds); |
4999 | 4989 | /* | |
4990 | * pfm_handle_work() can be called with interrupts enabled | ||
4991 | * (TIF_NEED_RESCHED) or disabled. The down_interruptible | ||
4992 | * call may sleep, therefore we must re-enable interrupts | ||
4993 | * to avoid deadlocks. It is safe to do so because this function | ||
4994 | * is called ONLY when returning to user level (PUStk=1), in which case | ||
4995 | * there is no risk of kernel stack overflow due to deep | ||
4996 | * interrupt nesting. | ||
4997 | */ | ||
5000 | void | 4998 | void |
5001 | pfm_handle_work(void) | 4999 | pfm_handle_work(void) |
5002 | { | 5000 | { |
5003 | pfm_context_t *ctx; | 5001 | pfm_context_t *ctx; |
5004 | struct pt_regs *regs; | 5002 | struct pt_regs *regs; |
5005 | unsigned long flags; | 5003 | unsigned long flags, dummy_flags; |
5006 | unsigned long ovfl_regs; | 5004 | unsigned long ovfl_regs; |
5007 | unsigned int reason; | 5005 | unsigned int reason; |
5008 | int ret; | 5006 | int ret; |
@@ -5039,18 +5037,15 @@ pfm_handle_work(void) | |||
5039 | //if (CTX_OVFL_NOBLOCK(ctx)) goto skip_blocking; | 5037 | //if (CTX_OVFL_NOBLOCK(ctx)) goto skip_blocking; |
5040 | if (reason == PFM_TRAP_REASON_RESET) goto skip_blocking; | 5038 | if (reason == PFM_TRAP_REASON_RESET) goto skip_blocking; |
5041 | 5039 | ||
5040 | /* | ||
5041 | * restore interrupt mask to what it was on entry. | ||
5042 | * Could be enabled/diasbled. | ||
5043 | */ | ||
5042 | UNPROTECT_CTX(ctx, flags); | 5044 | UNPROTECT_CTX(ctx, flags); |
5043 | 5045 | ||
5044 | /* | 5046 | /* |
5045 | * pfm_handle_work() is currently called with interrupts disabled. | 5047 | * force interrupt enable because of down_interruptible() |
5046 | * The down_interruptible call may sleep, therefore we | 5048 | */ |
5047 | * must re-enable interrupts to avoid deadlocks. It is | ||
5048 | * safe to do so because this function is called ONLY | ||
5049 | * when returning to user level (PUStk=1), in which case | ||
5050 | * there is no risk of kernel stack overflow due to deep | ||
5051 | * interrupt nesting. | ||
5052 | */ | ||
5053 | BUG_ON(flags & IA64_PSR_I); | ||
5054 | local_irq_enable(); | 5049 | local_irq_enable(); |
5055 | 5050 | ||
5056 | DPRINT(("before block sleeping\n")); | 5051 | DPRINT(("before block sleeping\n")); |
@@ -5064,12 +5059,12 @@ pfm_handle_work(void) | |||
5064 | DPRINT(("after block sleeping ret=%d\n", ret)); | 5059 | DPRINT(("after block sleeping ret=%d\n", ret)); |
5065 | 5060 | ||
5066 | /* | 5061 | /* |
5067 | * disable interrupts to restore state we had upon entering | 5062 | * lock context and mask interrupts again |
5068 | * this function | 5063 | * We save flags into a dummy because we may have |
5064 | * altered interrupts mask compared to entry in this | ||
5065 | * function. | ||
5069 | */ | 5066 | */ |
5070 | local_irq_disable(); | 5067 | PROTECT_CTX(ctx, dummy_flags); |
5071 | |||
5072 | PROTECT_CTX(ctx, flags); | ||
5073 | 5068 | ||
5074 | /* | 5069 | /* |
5075 | * we need to read the ovfl_regs only after wake-up | 5070 | * we need to read the ovfl_regs only after wake-up |
@@ -5095,7 +5090,9 @@ skip_blocking: | |||
5095 | ctx->ctx_ovfl_regs[0] = 0UL; | 5090 | ctx->ctx_ovfl_regs[0] = 0UL; |
5096 | 5091 | ||
5097 | nothing_to_do: | 5092 | nothing_to_do: |
5098 | 5093 | /* | |
5094 | * restore flags as they were upon entry | ||
5095 | */ | ||
5099 | UNPROTECT_CTX(ctx, flags); | 5096 | UNPROTECT_CTX(ctx, flags); |
5100 | } | 5097 | } |
5101 | 5098 | ||
diff --git a/arch/ia64/kernel/perfmon_default_smpl.c b/arch/ia64/kernel/perfmon_default_smpl.c index 965d29004555..344941db0a9e 100644 --- a/arch/ia64/kernel/perfmon_default_smpl.c +++ b/arch/ia64/kernel/perfmon_default_smpl.c | |||
@@ -20,24 +20,17 @@ MODULE_AUTHOR("Stephane Eranian <eranian@hpl.hp.com>"); | |||
20 | MODULE_DESCRIPTION("perfmon default sampling format"); | 20 | MODULE_DESCRIPTION("perfmon default sampling format"); |
21 | MODULE_LICENSE("GPL"); | 21 | MODULE_LICENSE("GPL"); |
22 | 22 | ||
23 | MODULE_PARM(debug, "i"); | ||
24 | MODULE_PARM_DESC(debug, "debug"); | ||
25 | |||
26 | MODULE_PARM(debug_ovfl, "i"); | ||
27 | MODULE_PARM_DESC(debug_ovfl, "debug ovfl"); | ||
28 | |||
29 | |||
30 | #define DEFAULT_DEBUG 1 | 23 | #define DEFAULT_DEBUG 1 |
31 | 24 | ||
32 | #ifdef DEFAULT_DEBUG | 25 | #ifdef DEFAULT_DEBUG |
33 | #define DPRINT(a) \ | 26 | #define DPRINT(a) \ |
34 | do { \ | 27 | do { \ |
35 | if (unlikely(debug >0)) { printk("%s.%d: CPU%d ", __FUNCTION__, __LINE__, smp_processor_id()); printk a; } \ | 28 | if (unlikely(pfm_sysctl.debug >0)) { printk("%s.%d: CPU%d ", __FUNCTION__, __LINE__, smp_processor_id()); printk a; } \ |
36 | } while (0) | 29 | } while (0) |
37 | 30 | ||
38 | #define DPRINT_ovfl(a) \ | 31 | #define DPRINT_ovfl(a) \ |
39 | do { \ | 32 | do { \ |
40 | if (unlikely(debug_ovfl >0)) { printk("%s.%d: CPU%d ", __FUNCTION__, __LINE__, smp_processor_id()); printk a; } \ | 33 | if (unlikely(pfm_sysctl.debug > 0 && pfm_sysctl.debug_ovfl >0)) { printk("%s.%d: CPU%d ", __FUNCTION__, __LINE__, smp_processor_id()); printk a; } \ |
41 | } while (0) | 34 | } while (0) |
42 | 35 | ||
43 | #else | 36 | #else |
@@ -45,8 +38,6 @@ MODULE_PARM_DESC(debug_ovfl, "debug ovfl"); | |||
45 | #define DPRINT_ovfl(a) | 38 | #define DPRINT_ovfl(a) |
46 | #endif | 39 | #endif |
47 | 40 | ||
48 | static int debug, debug_ovfl; | ||
49 | |||
50 | static int | 41 | static int |
51 | default_validate(struct task_struct *task, unsigned int flags, int cpu, void *data) | 42 | default_validate(struct task_struct *task, unsigned int flags, int cpu, void *data) |
52 | { | 43 | { |
diff --git a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c index f05650c801d2..b7e6b4cb374b 100644 --- a/arch/ia64/kernel/setup.c +++ b/arch/ia64/kernel/setup.c | |||
@@ -4,10 +4,15 @@ | |||
4 | * Copyright (C) 1998-2001, 2003-2004 Hewlett-Packard Co | 4 | * Copyright (C) 1998-2001, 2003-2004 Hewlett-Packard Co |
5 | * David Mosberger-Tang <davidm@hpl.hp.com> | 5 | * David Mosberger-Tang <davidm@hpl.hp.com> |
6 | * Stephane Eranian <eranian@hpl.hp.com> | 6 | * Stephane Eranian <eranian@hpl.hp.com> |
7 | * Copyright (C) 2000, Rohit Seth <rohit.seth@intel.com> | 7 | * Copyright (C) 2000, 2004 Intel Corp |
8 | * Rohit Seth <rohit.seth@intel.com> | ||
9 | * Suresh Siddha <suresh.b.siddha@intel.com> | ||
10 | * Gordon Jin <gordon.jin@intel.com> | ||
8 | * Copyright (C) 1999 VA Linux Systems | 11 | * Copyright (C) 1999 VA Linux Systems |
9 | * Copyright (C) 1999 Walt Drummond <drummond@valinux.com> | 12 | * Copyright (C) 1999 Walt Drummond <drummond@valinux.com> |
10 | * | 13 | * |
14 | * 12/26/04 S.Siddha, G.Jin, R.Seth | ||
15 | * Add multi-threading and multi-core detection | ||
11 | * 11/12/01 D.Mosberger Convert get_cpuinfo() to seq_file based show_cpuinfo(). | 16 | * 11/12/01 D.Mosberger Convert get_cpuinfo() to seq_file based show_cpuinfo(). |
12 | * 04/04/00 D.Mosberger renamed cpu_initialized to cpu_online_map | 17 | * 04/04/00 D.Mosberger renamed cpu_initialized to cpu_online_map |
13 | * 03/31/00 R.Seth cpu_initialized and current->processor fixes | 18 | * 03/31/00 R.Seth cpu_initialized and current->processor fixes |
@@ -296,6 +301,34 @@ mark_bsp_online (void) | |||
296 | #endif | 301 | #endif |
297 | } | 302 | } |
298 | 303 | ||
304 | #ifdef CONFIG_SMP | ||
305 | static void | ||
306 | check_for_logical_procs (void) | ||
307 | { | ||
308 | pal_logical_to_physical_t info; | ||
309 | s64 status; | ||
310 | |||
311 | status = ia64_pal_logical_to_phys(0, &info); | ||
312 | if (status == -1) { | ||
313 | printk(KERN_INFO "No logical to physical processor mapping " | ||
314 | "available\n"); | ||
315 | return; | ||
316 | } | ||
317 | if (status) { | ||
318 | printk(KERN_ERR "ia64_pal_logical_to_phys failed with %ld\n", | ||
319 | status); | ||
320 | return; | ||
321 | } | ||
322 | /* | ||
323 | * Total number of siblings that BSP has. Though not all of them | ||
324 | * may have booted successfully. The correct number of siblings | ||
325 | * booted is in info.overview_num_log. | ||
326 | */ | ||
327 | smp_num_siblings = info.overview_tpc; | ||
328 | smp_num_cpucores = info.overview_cpp; | ||
329 | } | ||
330 | #endif | ||
331 | |||
299 | void __init | 332 | void __init |
300 | setup_arch (char **cmdline_p) | 333 | setup_arch (char **cmdline_p) |
301 | { | 334 | { |
@@ -356,6 +389,19 @@ setup_arch (char **cmdline_p) | |||
356 | 389 | ||
357 | #ifdef CONFIG_SMP | 390 | #ifdef CONFIG_SMP |
358 | cpu_physical_id(0) = hard_smp_processor_id(); | 391 | cpu_physical_id(0) = hard_smp_processor_id(); |
392 | |||
393 | cpu_set(0, cpu_sibling_map[0]); | ||
394 | cpu_set(0, cpu_core_map[0]); | ||
395 | |||
396 | check_for_logical_procs(); | ||
397 | if (smp_num_cpucores > 1) | ||
398 | printk(KERN_INFO | ||
399 | "cpu package is Multi-Core capable: number of cores=%d\n", | ||
400 | smp_num_cpucores); | ||
401 | if (smp_num_siblings > 1) | ||
402 | printk(KERN_INFO | ||
403 | "cpu package is Multi-Threading capable: number of siblings=%d\n", | ||
404 | smp_num_siblings); | ||
359 | #endif | 405 | #endif |
360 | 406 | ||
361 | cpu_init(); /* initialize the bootstrap CPU */ | 407 | cpu_init(); /* initialize the bootstrap CPU */ |
@@ -459,12 +505,23 @@ show_cpuinfo (struct seq_file *m, void *v) | |||
459 | "cpu regs : %u\n" | 505 | "cpu regs : %u\n" |
460 | "cpu MHz : %lu.%06lu\n" | 506 | "cpu MHz : %lu.%06lu\n" |
461 | "itc MHz : %lu.%06lu\n" | 507 | "itc MHz : %lu.%06lu\n" |
462 | "BogoMIPS : %lu.%02lu\n\n", | 508 | "BogoMIPS : %lu.%02lu\n", |
463 | cpunum, c->vendor, family, c->model, c->revision, c->archrev, | 509 | cpunum, c->vendor, family, c->model, c->revision, c->archrev, |
464 | features, c->ppn, c->number, | 510 | features, c->ppn, c->number, |
465 | c->proc_freq / 1000000, c->proc_freq % 1000000, | 511 | c->proc_freq / 1000000, c->proc_freq % 1000000, |
466 | c->itc_freq / 1000000, c->itc_freq % 1000000, | 512 | c->itc_freq / 1000000, c->itc_freq % 1000000, |
467 | lpj*HZ/500000, (lpj*HZ/5000) % 100); | 513 | lpj*HZ/500000, (lpj*HZ/5000) % 100); |
514 | #ifdef CONFIG_SMP | ||
515 | seq_printf(m, "siblings : %u\n", c->num_log); | ||
516 | if (c->threads_per_core > 1 || c->cores_per_socket > 1) | ||
517 | seq_printf(m, | ||
518 | "physical id: %u\n" | ||
519 | "core id : %u\n" | ||
520 | "thread id : %u\n", | ||
521 | c->socket_id, c->core_id, c->thread_id); | ||
522 | #endif | ||
523 | seq_printf(m,"\n"); | ||
524 | |||
468 | return 0; | 525 | return 0; |
469 | } | 526 | } |
470 | 527 | ||
@@ -533,6 +590,14 @@ identify_cpu (struct cpuinfo_ia64 *c) | |||
533 | memcpy(c->vendor, cpuid.field.vendor, 16); | 590 | memcpy(c->vendor, cpuid.field.vendor, 16); |
534 | #ifdef CONFIG_SMP | 591 | #ifdef CONFIG_SMP |
535 | c->cpu = smp_processor_id(); | 592 | c->cpu = smp_processor_id(); |
593 | |||
594 | /* below default values will be overwritten by identify_siblings() | ||
595 | * for Multi-Threading/Multi-Core capable cpu's | ||
596 | */ | ||
597 | c->threads_per_core = c->cores_per_socket = c->num_log = 1; | ||
598 | c->socket_id = -1; | ||
599 | |||
600 | identify_siblings(c); | ||
536 | #endif | 601 | #endif |
537 | c->ppn = cpuid.field.ppn; | 602 | c->ppn = cpuid.field.ppn; |
538 | c->number = cpuid.field.number; | 603 | c->number = cpuid.field.number; |
diff --git a/arch/ia64/kernel/smpboot.c b/arch/ia64/kernel/smpboot.c index ca1536db3394..0d5ee57c9865 100644 --- a/arch/ia64/kernel/smpboot.c +++ b/arch/ia64/kernel/smpboot.c | |||
@@ -1,8 +1,13 @@ | |||
1 | /* | 1 | /* |
2 | * SMP boot-related support | 2 | * SMP boot-related support |
3 | * | 3 | * |
4 | * Copyright (C) 1998-2003 Hewlett-Packard Co | 4 | * Copyright (C) 1998-2003, 2005 Hewlett-Packard Co |
5 | * David Mosberger-Tang <davidm@hpl.hp.com> | 5 | * David Mosberger-Tang <davidm@hpl.hp.com> |
6 | * Copyright (C) 2001, 2004-2005 Intel Corp | ||
7 | * Rohit Seth <rohit.seth@intel.com> | ||
8 | * Suresh Siddha <suresh.b.siddha@intel.com> | ||
9 | * Gordon Jin <gordon.jin@intel.com> | ||
10 | * Ashok Raj <ashok.raj@intel.com> | ||
6 | * | 11 | * |
7 | * 01/05/16 Rohit Seth <rohit.seth@intel.com> Moved SMP booting functions from smp.c to here. | 12 | * 01/05/16 Rohit Seth <rohit.seth@intel.com> Moved SMP booting functions from smp.c to here. |
8 | * 01/04/27 David Mosberger <davidm@hpl.hp.com> Added ITC synching code. | 13 | * 01/04/27 David Mosberger <davidm@hpl.hp.com> Added ITC synching code. |
@@ -10,6 +15,11 @@ | |||
10 | * smp_boot_cpus()/smp_commence() is replaced by | 15 | * smp_boot_cpus()/smp_commence() is replaced by |
11 | * smp_prepare_cpus()/__cpu_up()/smp_cpus_done(). | 16 | * smp_prepare_cpus()/__cpu_up()/smp_cpus_done(). |
12 | * 04/06/21 Ashok Raj <ashok.raj@intel.com> Added CPU Hotplug Support | 17 | * 04/06/21 Ashok Raj <ashok.raj@intel.com> Added CPU Hotplug Support |
18 | * 04/12/26 Jin Gordon <gordon.jin@intel.com> | ||
19 | * 04/12/26 Rohit Seth <rohit.seth@intel.com> | ||
20 | * Add multi-threading and multi-core detection | ||
21 | * 05/01/30 Suresh Siddha <suresh.b.siddha@intel.com> | ||
22 | * Setup cpu_sibling_map and cpu_core_map | ||
13 | */ | 23 | */ |
14 | #include <linux/config.h> | 24 | #include <linux/config.h> |
15 | 25 | ||
@@ -122,6 +132,11 @@ EXPORT_SYMBOL(cpu_online_map); | |||
122 | cpumask_t cpu_possible_map; | 132 | cpumask_t cpu_possible_map; |
123 | EXPORT_SYMBOL(cpu_possible_map); | 133 | EXPORT_SYMBOL(cpu_possible_map); |
124 | 134 | ||
135 | cpumask_t cpu_core_map[NR_CPUS] __cacheline_aligned; | ||
136 | cpumask_t cpu_sibling_map[NR_CPUS] __cacheline_aligned; | ||
137 | int smp_num_siblings = 1; | ||
138 | int smp_num_cpucores = 1; | ||
139 | |||
125 | /* which logical CPU number maps to which CPU (physical APIC ID) */ | 140 | /* which logical CPU number maps to which CPU (physical APIC ID) */ |
126 | volatile int ia64_cpu_to_sapicid[NR_CPUS]; | 141 | volatile int ia64_cpu_to_sapicid[NR_CPUS]; |
127 | EXPORT_SYMBOL(ia64_cpu_to_sapicid); | 142 | EXPORT_SYMBOL(ia64_cpu_to_sapicid); |
@@ -156,7 +171,8 @@ sync_master (void *arg) | |||
156 | local_irq_save(flags); | 171 | local_irq_save(flags); |
157 | { | 172 | { |
158 | for (i = 0; i < NUM_ROUNDS*NUM_ITERS; ++i) { | 173 | for (i = 0; i < NUM_ROUNDS*NUM_ITERS; ++i) { |
159 | while (!go[MASTER]); | 174 | while (!go[MASTER]) |
175 | cpu_relax(); | ||
160 | go[MASTER] = 0; | 176 | go[MASTER] = 0; |
161 | go[SLAVE] = ia64_get_itc(); | 177 | go[SLAVE] = ia64_get_itc(); |
162 | } | 178 | } |
@@ -179,7 +195,8 @@ get_delta (long *rt, long *master) | |||
179 | for (i = 0; i < NUM_ITERS; ++i) { | 195 | for (i = 0; i < NUM_ITERS; ++i) { |
180 | t0 = ia64_get_itc(); | 196 | t0 = ia64_get_itc(); |
181 | go[MASTER] = 1; | 197 | go[MASTER] = 1; |
182 | while (!(tm = go[SLAVE])); | 198 | while (!(tm = go[SLAVE])) |
199 | cpu_relax(); | ||
183 | go[SLAVE] = 0; | 200 | go[SLAVE] = 0; |
184 | t1 = ia64_get_itc(); | 201 | t1 = ia64_get_itc(); |
185 | 202 | ||
@@ -258,7 +275,8 @@ ia64_sync_itc (unsigned int master) | |||
258 | return; | 275 | return; |
259 | } | 276 | } |
260 | 277 | ||
261 | while (go[MASTER]); /* wait for master to be ready */ | 278 | while (go[MASTER]) |
279 | cpu_relax(); /* wait for master to be ready */ | ||
262 | 280 | ||
263 | spin_lock_irqsave(&itc_sync_lock, flags); | 281 | spin_lock_irqsave(&itc_sync_lock, flags); |
264 | { | 282 | { |
@@ -595,7 +613,68 @@ void __devinit smp_prepare_boot_cpu(void) | |||
595 | cpu_set(smp_processor_id(), cpu_callin_map); | 613 | cpu_set(smp_processor_id(), cpu_callin_map); |
596 | } | 614 | } |
597 | 615 | ||
616 | /* | ||
617 | * mt_info[] is a temporary store for all info returned by | ||
618 | * PAL_LOGICAL_TO_PHYSICAL, to be copied into cpuinfo_ia64 when the | ||
619 | * specific cpu comes. | ||
620 | */ | ||
621 | static struct { | ||
622 | __u32 socket_id; | ||
623 | __u16 core_id; | ||
624 | __u16 thread_id; | ||
625 | __u16 proc_fixed_addr; | ||
626 | __u8 valid; | ||
627 | }mt_info[NR_CPUS] __devinit; | ||
628 | |||
598 | #ifdef CONFIG_HOTPLUG_CPU | 629 | #ifdef CONFIG_HOTPLUG_CPU |
630 | static inline void | ||
631 | remove_from_mtinfo(int cpu) | ||
632 | { | ||
633 | int i; | ||
634 | |||
635 | for_each_cpu(i) | ||
636 | if (mt_info[i].valid && mt_info[i].socket_id == | ||
637 | cpu_data(cpu)->socket_id) | ||
638 | mt_info[i].valid = 0; | ||
639 | } | ||
640 | |||
641 | static inline void | ||
642 | clear_cpu_sibling_map(int cpu) | ||
643 | { | ||
644 | int i; | ||
645 | |||
646 | for_each_cpu_mask(i, cpu_sibling_map[cpu]) | ||
647 | cpu_clear(cpu, cpu_sibling_map[i]); | ||
648 | for_each_cpu_mask(i, cpu_core_map[cpu]) | ||
649 | cpu_clear(cpu, cpu_core_map[i]); | ||
650 | |||
651 | cpu_sibling_map[cpu] = cpu_core_map[cpu] = CPU_MASK_NONE; | ||
652 | } | ||
653 | |||
654 | static void | ||
655 | remove_siblinginfo(int cpu) | ||
656 | { | ||
657 | int last = 0; | ||
658 | |||
659 | if (cpu_data(cpu)->threads_per_core == 1 && | ||
660 | cpu_data(cpu)->cores_per_socket == 1) { | ||
661 | cpu_clear(cpu, cpu_core_map[cpu]); | ||
662 | cpu_clear(cpu, cpu_sibling_map[cpu]); | ||
663 | return; | ||
664 | } | ||
665 | |||
666 | last = (cpus_weight(cpu_core_map[cpu]) == 1 ? 1 : 0); | ||
667 | |||
668 | /* remove it from all sibling map's */ | ||
669 | clear_cpu_sibling_map(cpu); | ||
670 | |||
671 | /* if this cpu is the last in the core group, remove all its info | ||
672 | * from mt_info structure | ||
673 | */ | ||
674 | if (last) | ||
675 | remove_from_mtinfo(cpu); | ||
676 | } | ||
677 | |||
599 | extern void fixup_irqs(void); | 678 | extern void fixup_irqs(void); |
600 | /* must be called with cpucontrol mutex held */ | 679 | /* must be called with cpucontrol mutex held */ |
601 | int __cpu_disable(void) | 680 | int __cpu_disable(void) |
@@ -608,6 +687,7 @@ int __cpu_disable(void) | |||
608 | if (cpu == 0) | 687 | if (cpu == 0) |
609 | return -EBUSY; | 688 | return -EBUSY; |
610 | 689 | ||
690 | remove_siblinginfo(cpu); | ||
611 | fixup_irqs(); | 691 | fixup_irqs(); |
612 | local_flush_tlb_all(); | 692 | local_flush_tlb_all(); |
613 | cpu_clear(cpu, cpu_callin_map); | 693 | cpu_clear(cpu, cpu_callin_map); |
@@ -660,6 +740,23 @@ smp_cpus_done (unsigned int dummy) | |||
660 | (int)num_online_cpus(), bogosum/(500000/HZ), (bogosum/(5000/HZ))%100); | 740 | (int)num_online_cpus(), bogosum/(500000/HZ), (bogosum/(5000/HZ))%100); |
661 | } | 741 | } |
662 | 742 | ||
743 | static inline void __devinit | ||
744 | set_cpu_sibling_map(int cpu) | ||
745 | { | ||
746 | int i; | ||
747 | |||
748 | for_each_online_cpu(i) { | ||
749 | if ((cpu_data(cpu)->socket_id == cpu_data(i)->socket_id)) { | ||
750 | cpu_set(i, cpu_core_map[cpu]); | ||
751 | cpu_set(cpu, cpu_core_map[i]); | ||
752 | if (cpu_data(cpu)->core_id == cpu_data(i)->core_id) { | ||
753 | cpu_set(i, cpu_sibling_map[cpu]); | ||
754 | cpu_set(cpu, cpu_sibling_map[i]); | ||
755 | } | ||
756 | } | ||
757 | } | ||
758 | } | ||
759 | |||
663 | int __devinit | 760 | int __devinit |
664 | __cpu_up (unsigned int cpu) | 761 | __cpu_up (unsigned int cpu) |
665 | { | 762 | { |
@@ -682,6 +779,15 @@ __cpu_up (unsigned int cpu) | |||
682 | if (ret < 0) | 779 | if (ret < 0) |
683 | return ret; | 780 | return ret; |
684 | 781 | ||
782 | if (cpu_data(cpu)->threads_per_core == 1 && | ||
783 | cpu_data(cpu)->cores_per_socket == 1) { | ||
784 | cpu_set(cpu, cpu_sibling_map[cpu]); | ||
785 | cpu_set(cpu, cpu_core_map[cpu]); | ||
786 | return 0; | ||
787 | } | ||
788 | |||
789 | set_cpu_sibling_map(cpu); | ||
790 | |||
685 | return 0; | 791 | return 0; |
686 | } | 792 | } |
687 | 793 | ||
@@ -709,3 +815,106 @@ init_smp_config(void) | |||
709 | ia64_sal_strerror(sal_ret)); | 815 | ia64_sal_strerror(sal_ret)); |
710 | } | 816 | } |
711 | 817 | ||
818 | static inline int __devinit | ||
819 | check_for_mtinfo_index(void) | ||
820 | { | ||
821 | int i; | ||
822 | |||
823 | for_each_cpu(i) | ||
824 | if (!mt_info[i].valid) | ||
825 | return i; | ||
826 | |||
827 | return -1; | ||
828 | } | ||
829 | |||
830 | /* | ||
831 | * Search the mt_info to find out if this socket's cid/tid information is | ||
832 | * cached or not. If the socket exists, fill in the core_id and thread_id | ||
833 | * in cpuinfo | ||
834 | */ | ||
835 | static int __devinit | ||
836 | check_for_new_socket(__u16 logical_address, struct cpuinfo_ia64 *c) | ||
837 | { | ||
838 | int i; | ||
839 | __u32 sid = c->socket_id; | ||
840 | |||
841 | for_each_cpu(i) { | ||
842 | if (mt_info[i].valid && mt_info[i].proc_fixed_addr == logical_address | ||
843 | && mt_info[i].socket_id == sid) { | ||
844 | c->core_id = mt_info[i].core_id; | ||
845 | c->thread_id = mt_info[i].thread_id; | ||
846 | return 1; /* not a new socket */ | ||
847 | } | ||
848 | } | ||
849 | return 0; | ||
850 | } | ||
851 | |||
852 | /* | ||
853 | * identify_siblings(cpu) gets called from identify_cpu. This populates the | ||
854 | * information related to logical execution units in per_cpu_data structure. | ||
855 | */ | ||
856 | void __devinit | ||
857 | identify_siblings(struct cpuinfo_ia64 *c) | ||
858 | { | ||
859 | s64 status; | ||
860 | u16 pltid; | ||
861 | u64 proc_fixed_addr; | ||
862 | int count, i; | ||
863 | pal_logical_to_physical_t info; | ||
864 | |||
865 | if (smp_num_cpucores == 1 && smp_num_siblings == 1) | ||
866 | return; | ||
867 | |||
868 | if ((status = ia64_pal_logical_to_phys(0, &info)) != PAL_STATUS_SUCCESS) { | ||
869 | printk(KERN_ERR "ia64_pal_logical_to_phys failed with %ld\n", | ||
870 | status); | ||
871 | return; | ||
872 | } | ||
873 | if ((status = ia64_sal_physical_id_info(&pltid)) != PAL_STATUS_SUCCESS) { | ||
874 | printk(KERN_ERR "ia64_sal_pltid failed with %ld\n", status); | ||
875 | return; | ||
876 | } | ||
877 | if ((status = ia64_pal_fixed_addr(&proc_fixed_addr)) != PAL_STATUS_SUCCESS) { | ||
878 | printk(KERN_ERR "ia64_pal_fixed_addr failed with %ld\n", status); | ||
879 | return; | ||
880 | } | ||
881 | |||
882 | c->socket_id = (pltid << 8) | info.overview_ppid; | ||
883 | c->cores_per_socket = info.overview_cpp; | ||
884 | c->threads_per_core = info.overview_tpc; | ||
885 | count = c->num_log = info.overview_num_log; | ||
886 | |||
887 | /* If the thread and core id information is already cached, then | ||
888 | * we will simply update cpu_info and return. Otherwise, we will | ||
889 | * do the PAL calls and cache core and thread id's of all the siblings. | ||
890 | */ | ||
891 | if (check_for_new_socket(proc_fixed_addr, c)) | ||
892 | return; | ||
893 | |||
894 | for (i = 0; i < count; i++) { | ||
895 | int index; | ||
896 | |||
897 | if (i && (status = ia64_pal_logical_to_phys(i, &info)) | ||
898 | != PAL_STATUS_SUCCESS) { | ||
899 | printk(KERN_ERR "ia64_pal_logical_to_phys failed" | ||
900 | " with %ld\n", status); | ||
901 | return; | ||
902 | } | ||
903 | if (info.log2_la == proc_fixed_addr) { | ||
904 | c->core_id = info.log1_cid; | ||
905 | c->thread_id = info.log1_tid; | ||
906 | } | ||
907 | |||
908 | index = check_for_mtinfo_index(); | ||
909 | /* We will not do the mt_info caching optimization in this case. | ||
910 | */ | ||
911 | if (index < 0) | ||
912 | continue; | ||
913 | |||
914 | mt_info[index].valid = 1; | ||
915 | mt_info[index].socket_id = c->socket_id; | ||
916 | mt_info[index].core_id = info.log1_cid; | ||
917 | mt_info[index].thread_id = info.log1_tid; | ||
918 | mt_info[index].proc_fixed_addr = info.log2_la; | ||
919 | } | ||
920 | } | ||
diff --git a/arch/ia64/kernel/unwind.c b/arch/ia64/kernel/unwind.c index d494ff647cac..2776a074c6f1 100644 --- a/arch/ia64/kernel/unwind.c +++ b/arch/ia64/kernel/unwind.c | |||
@@ -1943,23 +1943,30 @@ EXPORT_SYMBOL(unw_unwind); | |||
1943 | int | 1943 | int |
1944 | unw_unwind_to_user (struct unw_frame_info *info) | 1944 | unw_unwind_to_user (struct unw_frame_info *info) |
1945 | { | 1945 | { |
1946 | unsigned long ip, sp; | 1946 | unsigned long ip, sp, pr = 0; |
1947 | 1947 | ||
1948 | while (unw_unwind(info) >= 0) { | 1948 | while (unw_unwind(info) >= 0) { |
1949 | if (unw_get_rp(info, &ip) < 0) { | ||
1950 | unw_get_ip(info, &ip); | ||
1951 | UNW_DPRINT(0, "unwind.%s: failed to read return pointer (ip=0x%lx)\n", | ||
1952 | __FUNCTION__, ip); | ||
1953 | return -1; | ||
1954 | } | ||
1955 | unw_get_sp(info, &sp); | 1949 | unw_get_sp(info, &sp); |
1956 | if (sp >= (unsigned long)info->task + IA64_STK_OFFSET) | 1950 | if ((long)((unsigned long)info->task + IA64_STK_OFFSET - sp) |
1951 | < IA64_PT_REGS_SIZE) { | ||
1952 | UNW_DPRINT(0, "unwind.%s: ran off the top of the kernel stack\n", | ||
1953 | __FUNCTION__); | ||
1957 | break; | 1954 | break; |
1958 | if (ip < FIXADDR_USER_END) | 1955 | } |
1956 | if (unw_is_intr_frame(info) && | ||
1957 | (pr & (1UL << PRED_USER_STACK))) | ||
1959 | return 0; | 1958 | return 0; |
1959 | if (unw_get_pr (info, &pr) < 0) { | ||
1960 | unw_get_rp(info, &ip); | ||
1961 | UNW_DPRINT(0, "unwind.%s: failed to read " | ||
1962 | "predicate register (ip=0x%lx)\n", | ||
1963 | __FUNCTION__, ip); | ||
1964 | return -1; | ||
1965 | } | ||
1960 | } | 1966 | } |
1961 | unw_get_ip(info, &ip); | 1967 | unw_get_ip(info, &ip); |
1962 | UNW_DPRINT(0, "unwind.%s: failed to unwind to user-level (ip=0x%lx)\n", __FUNCTION__, ip); | 1968 | UNW_DPRINT(0, "unwind.%s: failed to unwind to user-level (ip=0x%lx)\n", |
1969 | __FUNCTION__, ip); | ||
1963 | return -1; | 1970 | return -1; |
1964 | } | 1971 | } |
1965 | EXPORT_SYMBOL(unw_unwind_to_user); | 1972 | EXPORT_SYMBOL(unw_unwind_to_user); |
diff --git a/arch/ia64/lib/memcpy_mck.S b/arch/ia64/lib/memcpy_mck.S index 6f26ef7cc236..3c2cd2f04db9 100644 --- a/arch/ia64/lib/memcpy_mck.S +++ b/arch/ia64/lib/memcpy_mck.S | |||
@@ -300,7 +300,7 @@ EK(.ex_handler, (p[D]) st8 [dst1] = t15, 4*8) | |||
300 | add src_pre_mem=0,src0 // prefetch src pointer | 300 | add src_pre_mem=0,src0 // prefetch src pointer |
301 | add dst_pre_mem=0,dst0 // prefetch dest pointer | 301 | add dst_pre_mem=0,dst0 // prefetch dest pointer |
302 | and src0=-8,src0 // 1st src pointer | 302 | and src0=-8,src0 // 1st src pointer |
303 | (p7) mov ar.lc = r21 | 303 | (p7) mov ar.lc = cnt |
304 | (p8) mov ar.lc = r0 | 304 | (p8) mov ar.lc = r0 |
305 | ;; | 305 | ;; |
306 | TEXT_ALIGN(32) | 306 | TEXT_ALIGN(32) |
diff --git a/arch/ia64/mm/contig.c b/arch/ia64/mm/contig.c index 6daf15ac8940..91a055f5731f 100644 --- a/arch/ia64/mm/contig.c +++ b/arch/ia64/mm/contig.c | |||
@@ -61,7 +61,8 @@ show_mem (void) | |||
61 | printk("%d reserved pages\n", reserved); | 61 | printk("%d reserved pages\n", reserved); |
62 | printk("%d pages shared\n", shared); | 62 | printk("%d pages shared\n", shared); |
63 | printk("%d pages swap cached\n", cached); | 63 | printk("%d pages swap cached\n", cached); |
64 | printk("%ld pages in page table cache\n", pgtable_cache_size); | 64 | printk("%ld pages in page table cache\n", |
65 | pgtable_quicklist_total_size()); | ||
65 | } | 66 | } |
66 | 67 | ||
67 | /* physical address where the bootmem map is located */ | 68 | /* physical address where the bootmem map is located */ |
diff --git a/arch/ia64/mm/discontig.c b/arch/ia64/mm/discontig.c index 3456a9b6971e..c00710929390 100644 --- a/arch/ia64/mm/discontig.c +++ b/arch/ia64/mm/discontig.c | |||
@@ -582,7 +582,8 @@ void show_mem(void) | |||
582 | printk("%d reserved pages\n", total_reserved); | 582 | printk("%d reserved pages\n", total_reserved); |
583 | printk("%d pages shared\n", total_shared); | 583 | printk("%d pages shared\n", total_shared); |
584 | printk("%d pages swap cached\n", total_cached); | 584 | printk("%d pages swap cached\n", total_cached); |
585 | printk("Total of %ld pages in page table cache\n", pgtable_cache_size); | 585 | printk("Total of %ld pages in page table cache\n", |
586 | pgtable_quicklist_total_size()); | ||
586 | printk("%d free buffer pages\n", nr_free_buffer_pages()); | 587 | printk("%d free buffer pages\n", nr_free_buffer_pages()); |
587 | } | 588 | } |
588 | 589 | ||
diff --git a/arch/ia64/mm/fault.c b/arch/ia64/mm/fault.c index da859125aaef..4174ec999dde 100644 --- a/arch/ia64/mm/fault.c +++ b/arch/ia64/mm/fault.c | |||
@@ -209,10 +209,13 @@ ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_regs *re | |||
209 | } | 209 | } |
210 | 210 | ||
211 | no_context: | 211 | no_context: |
212 | if (isr & IA64_ISR_SP) { | 212 | if ((isr & IA64_ISR_SP) |
213 | || ((isr & IA64_ISR_NA) && (isr & IA64_ISR_CODE_MASK) == IA64_ISR_CODE_LFETCH)) | ||
214 | { | ||
213 | /* | 215 | /* |
214 | * This fault was due to a speculative load set the "ed" bit in the psr to | 216 | * This fault was due to a speculative load or lfetch.fault, set the "ed" |
215 | * ensure forward progress (target register will get a NaT). | 217 | * bit in the psr to ensure forward progress. (Target register will get a |
218 | * NaT for ld.s, lfetch will be canceled.) | ||
216 | */ | 219 | */ |
217 | ia64_psr(regs)->ed = 1; | 220 | ia64_psr(regs)->ed = 1; |
218 | return; | 221 | return; |
diff --git a/arch/ia64/mm/init.c b/arch/ia64/mm/init.c index 65cf839573ea..547785e3cba2 100644 --- a/arch/ia64/mm/init.c +++ b/arch/ia64/mm/init.c | |||
@@ -39,6 +39,9 @@ | |||
39 | 39 | ||
40 | DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); | 40 | DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); |
41 | 41 | ||
42 | DEFINE_PER_CPU(unsigned long *, __pgtable_quicklist); | ||
43 | DEFINE_PER_CPU(long, __pgtable_quicklist_size); | ||
44 | |||
42 | extern void ia64_tlb_init (void); | 45 | extern void ia64_tlb_init (void); |
43 | 46 | ||
44 | unsigned long MAX_DMA_ADDRESS = PAGE_OFFSET + 0x100000000UL; | 47 | unsigned long MAX_DMA_ADDRESS = PAGE_OFFSET + 0x100000000UL; |
@@ -50,27 +53,53 @@ struct page *vmem_map; | |||
50 | EXPORT_SYMBOL(vmem_map); | 53 | EXPORT_SYMBOL(vmem_map); |
51 | #endif | 54 | #endif |
52 | 55 | ||
53 | static int pgt_cache_water[2] = { 25, 50 }; | 56 | struct page *zero_page_memmap_ptr; /* map entry for zero page */ |
54 | |||
55 | struct page *zero_page_memmap_ptr; /* map entry for zero page */ | ||
56 | EXPORT_SYMBOL(zero_page_memmap_ptr); | 57 | EXPORT_SYMBOL(zero_page_memmap_ptr); |
57 | 58 | ||
59 | #define MIN_PGT_PAGES 25UL | ||
60 | #define MAX_PGT_FREES_PER_PASS 16L | ||
61 | #define PGT_FRACTION_OF_NODE_MEM 16 | ||
62 | |||
63 | static inline long | ||
64 | max_pgt_pages(void) | ||
65 | { | ||
66 | u64 node_free_pages, max_pgt_pages; | ||
67 | |||
68 | #ifndef CONFIG_NUMA | ||
69 | node_free_pages = nr_free_pages(); | ||
70 | #else | ||
71 | node_free_pages = nr_free_pages_pgdat(NODE_DATA(numa_node_id())); | ||
72 | #endif | ||
73 | max_pgt_pages = node_free_pages / PGT_FRACTION_OF_NODE_MEM; | ||
74 | max_pgt_pages = max(max_pgt_pages, MIN_PGT_PAGES); | ||
75 | return max_pgt_pages; | ||
76 | } | ||
77 | |||
78 | static inline long | ||
79 | min_pages_to_free(void) | ||
80 | { | ||
81 | long pages_to_free; | ||
82 | |||
83 | pages_to_free = pgtable_quicklist_size - max_pgt_pages(); | ||
84 | pages_to_free = min(pages_to_free, MAX_PGT_FREES_PER_PASS); | ||
85 | return pages_to_free; | ||
86 | } | ||
87 | |||
58 | void | 88 | void |
59 | check_pgt_cache (void) | 89 | check_pgt_cache(void) |
60 | { | 90 | { |
61 | int low, high; | 91 | long pages_to_free; |
62 | 92 | ||
63 | low = pgt_cache_water[0]; | 93 | if (unlikely(pgtable_quicklist_size <= MIN_PGT_PAGES)) |
64 | high = pgt_cache_water[1]; | 94 | return; |
65 | 95 | ||
66 | preempt_disable(); | 96 | preempt_disable(); |
67 | if (pgtable_cache_size > (u64) high) { | 97 | while (unlikely((pages_to_free = min_pages_to_free()) > 0)) { |
68 | do { | 98 | while (pages_to_free--) { |
69 | if (pgd_quicklist) | 99 | free_page((unsigned long)pgtable_quicklist_alloc()); |
70 | free_page((unsigned long)pgd_alloc_one_fast(NULL)); | 100 | } |
71 | if (pmd_quicklist) | 101 | preempt_enable(); |
72 | free_page((unsigned long)pmd_alloc_one_fast(NULL, 0)); | 102 | preempt_disable(); |
73 | } while (pgtable_cache_size > (u64) low); | ||
74 | } | 103 | } |
75 | preempt_enable(); | 104 | preempt_enable(); |
76 | } | 105 | } |
@@ -523,11 +552,14 @@ void | |||
523 | mem_init (void) | 552 | mem_init (void) |
524 | { | 553 | { |
525 | long reserved_pages, codesize, datasize, initsize; | 554 | long reserved_pages, codesize, datasize, initsize; |
526 | unsigned long num_pgt_pages; | ||
527 | pg_data_t *pgdat; | 555 | pg_data_t *pgdat; |
528 | int i; | 556 | int i; |
529 | static struct kcore_list kcore_mem, kcore_vmem, kcore_kernel; | 557 | static struct kcore_list kcore_mem, kcore_vmem, kcore_kernel; |
530 | 558 | ||
559 | BUG_ON(PTRS_PER_PGD * sizeof(pgd_t) != PAGE_SIZE); | ||
560 | BUG_ON(PTRS_PER_PMD * sizeof(pmd_t) != PAGE_SIZE); | ||
561 | BUG_ON(PTRS_PER_PTE * sizeof(pte_t) != PAGE_SIZE); | ||
562 | |||
531 | #ifdef CONFIG_PCI | 563 | #ifdef CONFIG_PCI |
532 | /* | 564 | /* |
533 | * This needs to be called _after_ the command line has been parsed but _before_ | 565 | * This needs to be called _after_ the command line has been parsed but _before_ |
@@ -564,18 +596,6 @@ mem_init (void) | |||
564 | num_physpages << (PAGE_SHIFT - 10), codesize >> 10, | 596 | num_physpages << (PAGE_SHIFT - 10), codesize >> 10, |
565 | reserved_pages << (PAGE_SHIFT - 10), datasize >> 10, initsize >> 10); | 597 | reserved_pages << (PAGE_SHIFT - 10), datasize >> 10, initsize >> 10); |
566 | 598 | ||
567 | /* | ||
568 | * Allow for enough (cached) page table pages so that we can map the entire memory | ||
569 | * at least once. Each task also needs a couple of page tables pages, so add in a | ||
570 | * fudge factor for that (don't use "threads-max" here; that would be wrong!). | ||
571 | * Don't allow the cache to be more than 10% of total memory, though. | ||
572 | */ | ||
573 | # define NUM_TASKS 500 /* typical number of tasks */ | ||
574 | num_pgt_pages = nr_free_pages() / PTRS_PER_PGD + NUM_TASKS; | ||
575 | if (num_pgt_pages > nr_free_pages() / 10) | ||
576 | num_pgt_pages = nr_free_pages() / 10; | ||
577 | if (num_pgt_pages > (u64) pgt_cache_water[1]) | ||
578 | pgt_cache_water[1] = num_pgt_pages; | ||
579 | 599 | ||
580 | /* | 600 | /* |
581 | * For fsyscall entrpoints with no light-weight handler, use the ordinary | 601 | * For fsyscall entrpoints with no light-weight handler, use the ordinary |
diff --git a/arch/ia64/sn/include/pci/pcibr_provider.h b/arch/ia64/sn/include/pci/pcibr_provider.h index b1f05ffec70b..1cd291d8badd 100644 --- a/arch/ia64/sn/include/pci/pcibr_provider.h +++ b/arch/ia64/sn/include/pci/pcibr_provider.h | |||
@@ -123,9 +123,11 @@ pcibr_lock(struct pcibus_info *pcibus_info) | |||
123 | } | 123 | } |
124 | #define pcibr_unlock(pcibus_info, flag) spin_unlock_irqrestore(&pcibus_info->pbi_lock, flag) | 124 | #define pcibr_unlock(pcibus_info, flag) spin_unlock_irqrestore(&pcibus_info->pbi_lock, flag) |
125 | 125 | ||
126 | extern int pcibr_init_provider(void); | ||
126 | extern void *pcibr_bus_fixup(struct pcibus_bussoft *); | 127 | extern void *pcibr_bus_fixup(struct pcibus_bussoft *); |
127 | extern uint64_t pcibr_dma_map(struct pcidev_info *, unsigned long, size_t, unsigned int); | 128 | extern dma_addr_t pcibr_dma_map(struct pci_dev *, unsigned long, size_t); |
128 | extern void pcibr_dma_unmap(struct pcidev_info *, dma_addr_t, int); | 129 | extern dma_addr_t pcibr_dma_map_consistent(struct pci_dev *, unsigned long, size_t); |
130 | extern void pcibr_dma_unmap(struct pci_dev *, dma_addr_t, int); | ||
129 | 131 | ||
130 | /* | 132 | /* |
131 | * prototypes for the bridge asic register access routines in pcibr_reg.c | 133 | * prototypes for the bridge asic register access routines in pcibr_reg.c |
diff --git a/arch/ia64/sn/include/pci/pcibus_provider_defs.h b/arch/ia64/sn/include/pci/pcibus_provider_defs.h deleted file mode 100644 index 07065615bbea..000000000000 --- a/arch/ia64/sn/include/pci/pcibus_provider_defs.h +++ /dev/null | |||
@@ -1,43 +0,0 @@ | |||
1 | /* | ||
2 | * This file is subject to the terms and conditions of the GNU General Public | ||
3 | * License. See the file "COPYING" in the main directory of this archive | ||
4 | * for more details. | ||
5 | * | ||
6 | * Copyright (C) 1992 - 1997, 2000-2004 Silicon Graphics, Inc. All rights reserved. | ||
7 | */ | ||
8 | #ifndef _ASM_IA64_SN_PCI_PCIBUS_PROVIDER_H | ||
9 | #define _ASM_IA64_SN_PCI_PCIBUS_PROVIDER_H | ||
10 | |||
11 | /* | ||
12 | * SN pci asic types. Do not ever renumber these or reuse values. The | ||
13 | * values must agree with what prom thinks they are. | ||
14 | */ | ||
15 | |||
16 | #define PCIIO_ASIC_TYPE_UNKNOWN 0 | ||
17 | #define PCIIO_ASIC_TYPE_PPB 1 | ||
18 | #define PCIIO_ASIC_TYPE_PIC 2 | ||
19 | #define PCIIO_ASIC_TYPE_TIOCP 3 | ||
20 | |||
21 | /* | ||
22 | * Common pciio bus provider data. There should be one of these as the | ||
23 | * first field in any pciio based provider soft structure (e.g. pcibr_soft | ||
24 | * tioca_soft, etc). | ||
25 | */ | ||
26 | |||
27 | struct pcibus_bussoft { | ||
28 | uint32_t bs_asic_type; /* chipset type */ | ||
29 | uint32_t bs_xid; /* xwidget id */ | ||
30 | uint64_t bs_persist_busnum; /* Persistent Bus Number */ | ||
31 | uint64_t bs_legacy_io; /* legacy io pio addr */ | ||
32 | uint64_t bs_legacy_mem; /* legacy mem pio addr */ | ||
33 | uint64_t bs_base; /* widget base */ | ||
34 | struct xwidget_info *bs_xwidget_info; | ||
35 | }; | ||
36 | |||
37 | /* | ||
38 | * DMA mapping flags | ||
39 | */ | ||
40 | |||
41 | #define SN_PCIDMA_CONSISTENT 0x0001 | ||
42 | |||
43 | #endif /* _ASM_IA64_SN_PCI_PCIBUS_PROVIDER_H */ | ||
diff --git a/arch/ia64/sn/include/pci/pcidev.h b/arch/ia64/sn/include/pci/pcidev.h deleted file mode 100644 index 81eb95d3bf47..000000000000 --- a/arch/ia64/sn/include/pci/pcidev.h +++ /dev/null | |||
@@ -1,54 +0,0 @@ | |||
1 | /* | ||
2 | * This file is subject to the terms and conditions of the GNU General Public | ||
3 | * License. See the file "COPYING" in the main directory of this archive | ||
4 | * for more details. | ||
5 | * | ||
6 | * Copyright (C) 1992 - 1997, 2000-2004 Silicon Graphics, Inc. All rights reserved. | ||
7 | */ | ||
8 | #ifndef _ASM_IA64_SN_PCI_PCIDEV_H | ||
9 | #define _ASM_IA64_SN_PCI_PCIDEV_H | ||
10 | |||
11 | #include <linux/pci.h> | ||
12 | |||
13 | extern struct sn_irq_info **sn_irq; | ||
14 | |||
15 | #define SN_PCIDEV_INFO(pci_dev) \ | ||
16 | ((struct pcidev_info *)(pci_dev)->sysdata) | ||
17 | |||
18 | /* | ||
19 | * Given a pci_bus, return the sn pcibus_bussoft struct. Note that | ||
20 | * this only works for root busses, not for busses represented by PPB's. | ||
21 | */ | ||
22 | |||
23 | #define SN_PCIBUS_BUSSOFT(pci_bus) \ | ||
24 | ((struct pcibus_bussoft *)(PCI_CONTROLLER((pci_bus))->platform_data)) | ||
25 | |||
26 | /* | ||
27 | * Given a struct pci_dev, return the sn pcibus_bussoft struct. Note | ||
28 | * that this is not equivalent to SN_PCIBUS_BUSSOFT(pci_dev->bus) due | ||
29 | * due to possible PPB's in the path. | ||
30 | */ | ||
31 | |||
32 | #define SN_PCIDEV_BUSSOFT(pci_dev) \ | ||
33 | (SN_PCIDEV_INFO(pci_dev)->pdi_host_pcidev_info->pdi_pcibus_info) | ||
34 | |||
35 | #define PCIIO_BUS_NONE 255 /* bus 255 reserved */ | ||
36 | #define PCIIO_SLOT_NONE 255 | ||
37 | #define PCIIO_FUNC_NONE 255 | ||
38 | #define PCIIO_VENDOR_ID_NONE (-1) | ||
39 | |||
40 | struct pcidev_info { | ||
41 | uint64_t pdi_pio_mapped_addr[7]; /* 6 BARs PLUS 1 ROM */ | ||
42 | uint64_t pdi_slot_host_handle; /* Bus and devfn Host pci_dev */ | ||
43 | |||
44 | struct pcibus_bussoft *pdi_pcibus_info; /* Kernel common bus soft */ | ||
45 | struct pcidev_info *pdi_host_pcidev_info; /* Kernel Host pci_dev */ | ||
46 | struct pci_dev *pdi_linux_pcidev; /* Kernel pci_dev */ | ||
47 | |||
48 | struct sn_irq_info *pdi_sn_irq_info; | ||
49 | }; | ||
50 | |||
51 | extern void sn_irq_fixup(struct pci_dev *pci_dev, | ||
52 | struct sn_irq_info *sn_irq_info); | ||
53 | |||
54 | #endif /* _ASM_IA64_SN_PCI_PCIDEV_H */ | ||
diff --git a/arch/ia64/sn/kernel/Makefile b/arch/ia64/sn/kernel/Makefile index 6c7f4d9e8ea0..4f381fb25049 100644 --- a/arch/ia64/sn/kernel/Makefile +++ b/arch/ia64/sn/kernel/Makefile | |||
@@ -10,3 +10,4 @@ | |||
10 | obj-y += setup.o bte.o bte_error.o irq.o mca.o idle.o \ | 10 | obj-y += setup.o bte.o bte_error.o irq.o mca.o idle.o \ |
11 | huberror.o io_init.o iomv.o klconflib.o sn2/ | 11 | huberror.o io_init.o iomv.o klconflib.o sn2/ |
12 | obj-$(CONFIG_IA64_GENERIC) += machvec.o | 12 | obj-$(CONFIG_IA64_GENERIC) += machvec.o |
13 | obj-$(CONFIG_SGI_TIOCX) += tiocx.o | ||
diff --git a/arch/ia64/sn/kernel/bte.c b/arch/ia64/sn/kernel/bte.c index ce0bc4085eae..647deae9bfcd 100644 --- a/arch/ia64/sn/kernel/bte.c +++ b/arch/ia64/sn/kernel/bte.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * License. See the file "COPYING" in the main directory of this archive | 3 | * License. See the file "COPYING" in the main directory of this archive |
4 | * for more details. | 4 | * for more details. |
5 | * | 5 | * |
6 | * Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. | 6 | * Copyright (c) 2000-2005 Silicon Graphics, Inc. All Rights Reserved. |
7 | */ | 7 | */ |
8 | 8 | ||
9 | #include <linux/config.h> | 9 | #include <linux/config.h> |
@@ -170,10 +170,6 @@ retry_bteop: | |||
170 | /* Initialize the notification to a known value. */ | 170 | /* Initialize the notification to a known value. */ |
171 | *bte->most_rcnt_na = BTE_WORD_BUSY; | 171 | *bte->most_rcnt_na = BTE_WORD_BUSY; |
172 | 172 | ||
173 | /* Set the status reg busy bit and transfer length */ | ||
174 | BTE_PRINTKV(("IBLS = 0x%lx\n", IBLS_BUSY | transfer_size)); | ||
175 | BTE_LNSTAT_STORE(bte, IBLS_BUSY | transfer_size); | ||
176 | |||
177 | /* Set the source and destination registers */ | 173 | /* Set the source and destination registers */ |
178 | BTE_PRINTKV(("IBSA = 0x%lx)\n", (TO_PHYS(src)))); | 174 | BTE_PRINTKV(("IBSA = 0x%lx)\n", (TO_PHYS(src)))); |
179 | BTE_SRC_STORE(bte, TO_PHYS(src)); | 175 | BTE_SRC_STORE(bte, TO_PHYS(src)); |
@@ -188,7 +184,7 @@ retry_bteop: | |||
188 | 184 | ||
189 | /* Initiate the transfer */ | 185 | /* Initiate the transfer */ |
190 | BTE_PRINTK(("IBCT = 0x%lx)\n", BTE_VALID_MODE(mode))); | 186 | BTE_PRINTK(("IBCT = 0x%lx)\n", BTE_VALID_MODE(mode))); |
191 | BTE_CTRL_STORE(bte, BTE_VALID_MODE(mode)); | 187 | BTE_START_TRANSFER(bte, transfer_size, BTE_VALID_MODE(mode)); |
192 | 188 | ||
193 | itc_end = ia64_get_itc() + (40000000 * local_cpu_data->cyc_per_usec); | 189 | itc_end = ia64_get_itc() + (40000000 * local_cpu_data->cyc_per_usec); |
194 | 190 | ||
@@ -429,10 +425,16 @@ void bte_init_node(nodepda_t * mynodepda, cnodeid_t cnode) | |||
429 | mynodepda->bte_recovery_timer.data = (unsigned long)mynodepda; | 425 | mynodepda->bte_recovery_timer.data = (unsigned long)mynodepda; |
430 | 426 | ||
431 | for (i = 0; i < BTES_PER_NODE; i++) { | 427 | for (i = 0; i < BTES_PER_NODE; i++) { |
428 | u64 *base_addr; | ||
429 | |||
432 | /* Which link status register should we use? */ | 430 | /* Which link status register should we use? */ |
433 | unsigned long link_status = (i == 0 ? IIO_IBLS0 : IIO_IBLS1); | 431 | base_addr = (u64 *) |
434 | mynodepda->bte_if[i].bte_base_addr = (u64 *) | 432 | REMOTE_HUB_ADDR(cnodeid_to_nasid(cnode), BTE_BASE_ADDR(i)); |
435 | REMOTE_HUB_ADDR(cnodeid_to_nasid(cnode), link_status); | 433 | mynodepda->bte_if[i].bte_base_addr = base_addr; |
434 | mynodepda->bte_if[i].bte_source_addr = BTE_SOURCE_ADDR(base_addr); | ||
435 | mynodepda->bte_if[i].bte_destination_addr = BTE_DEST_ADDR(base_addr); | ||
436 | mynodepda->bte_if[i].bte_control_addr = BTE_CTRL_ADDR(base_addr); | ||
437 | mynodepda->bte_if[i].bte_notify_addr = BTE_NOTIF_ADDR(base_addr); | ||
436 | 438 | ||
437 | /* | 439 | /* |
438 | * Initialize the notification and spinlock | 440 | * Initialize the notification and spinlock |
diff --git a/arch/ia64/sn/kernel/bte_error.c b/arch/ia64/sn/kernel/bte_error.c index fd104312c6bd..fcbc748ae433 100644 --- a/arch/ia64/sn/kernel/bte_error.c +++ b/arch/ia64/sn/kernel/bte_error.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * License. See the file "COPYING" in the main directory of this archive | 3 | * License. See the file "COPYING" in the main directory of this archive |
4 | * for more details. | 4 | * for more details. |
5 | * | 5 | * |
6 | * Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. | 6 | * Copyright (c) 2000-2005 Silicon Graphics, Inc. All Rights Reserved. |
7 | */ | 7 | */ |
8 | 8 | ||
9 | #include <linux/types.h> | 9 | #include <linux/types.h> |
@@ -33,48 +33,28 @@ void bte_error_handler(unsigned long); | |||
33 | * Wait until all BTE related CRBs are completed | 33 | * Wait until all BTE related CRBs are completed |
34 | * and then reset the interfaces. | 34 | * and then reset the interfaces. |
35 | */ | 35 | */ |
36 | void bte_error_handler(unsigned long _nodepda) | 36 | void shub1_bte_error_handler(unsigned long _nodepda) |
37 | { | 37 | { |
38 | struct nodepda_s *err_nodepda = (struct nodepda_s *)_nodepda; | 38 | struct nodepda_s *err_nodepda = (struct nodepda_s *)_nodepda; |
39 | spinlock_t *recovery_lock = &err_nodepda->bte_recovery_lock; | ||
40 | struct timer_list *recovery_timer = &err_nodepda->bte_recovery_timer; | 39 | struct timer_list *recovery_timer = &err_nodepda->bte_recovery_timer; |
41 | nasid_t nasid; | 40 | nasid_t nasid; |
42 | int i; | 41 | int i; |
43 | int valid_crbs; | 42 | int valid_crbs; |
44 | unsigned long irq_flags; | ||
45 | volatile u64 *notify; | ||
46 | bte_result_t bh_error; | ||
47 | ii_imem_u_t imem; /* II IMEM Register */ | 43 | ii_imem_u_t imem; /* II IMEM Register */ |
48 | ii_icrb0_d_u_t icrbd; /* II CRB Register D */ | 44 | ii_icrb0_d_u_t icrbd; /* II CRB Register D */ |
49 | ii_ibcr_u_t ibcr; | 45 | ii_ibcr_u_t ibcr; |
50 | ii_icmr_u_t icmr; | 46 | ii_icmr_u_t icmr; |
51 | ii_ieclr_u_t ieclr; | 47 | ii_ieclr_u_t ieclr; |
52 | 48 | ||
53 | BTE_PRINTK(("bte_error_handler(%p) - %d\n", err_nodepda, | 49 | BTE_PRINTK(("shub1_bte_error_handler(%p) - %d\n", err_nodepda, |
54 | smp_processor_id())); | 50 | smp_processor_id())); |
55 | 51 | ||
56 | spin_lock_irqsave(recovery_lock, irq_flags); | ||
57 | |||
58 | if ((err_nodepda->bte_if[0].bh_error == BTE_SUCCESS) && | 52 | if ((err_nodepda->bte_if[0].bh_error == BTE_SUCCESS) && |
59 | (err_nodepda->bte_if[1].bh_error == BTE_SUCCESS)) { | 53 | (err_nodepda->bte_if[1].bh_error == BTE_SUCCESS)) { |
60 | BTE_PRINTK(("eh:%p:%d Nothing to do.\n", err_nodepda, | 54 | BTE_PRINTK(("eh:%p:%d Nothing to do.\n", err_nodepda, |
61 | smp_processor_id())); | 55 | smp_processor_id())); |
62 | spin_unlock_irqrestore(recovery_lock, irq_flags); | ||
63 | return; | 56 | return; |
64 | } | 57 | } |
65 | /* | ||
66 | * Lock all interfaces on this node to prevent new transfers | ||
67 | * from being queued. | ||
68 | */ | ||
69 | for (i = 0; i < BTES_PER_NODE; i++) { | ||
70 | if (err_nodepda->bte_if[i].cleanup_active) { | ||
71 | continue; | ||
72 | } | ||
73 | spin_lock(&err_nodepda->bte_if[i].spinlock); | ||
74 | BTE_PRINTK(("eh:%p:%d locked %d\n", err_nodepda, | ||
75 | smp_processor_id(), i)); | ||
76 | err_nodepda->bte_if[i].cleanup_active = 1; | ||
77 | } | ||
78 | 58 | ||
79 | /* Determine information about our hub */ | 59 | /* Determine information about our hub */ |
80 | nasid = cnodeid_to_nasid(err_nodepda->bte_if[0].bte_cnode); | 60 | nasid = cnodeid_to_nasid(err_nodepda->bte_if[0].bte_cnode); |
@@ -101,7 +81,6 @@ void bte_error_handler(unsigned long _nodepda) | |||
101 | mod_timer(recovery_timer, HZ * 5); | 81 | mod_timer(recovery_timer, HZ * 5); |
102 | BTE_PRINTK(("eh:%p:%d Marked Giving up\n", err_nodepda, | 82 | BTE_PRINTK(("eh:%p:%d Marked Giving up\n", err_nodepda, |
103 | smp_processor_id())); | 83 | smp_processor_id())); |
104 | spin_unlock_irqrestore(recovery_lock, irq_flags); | ||
105 | return; | 84 | return; |
106 | } | 85 | } |
107 | if (icmr.ii_icmr_fld_s.i_crb_vld != 0) { | 86 | if (icmr.ii_icmr_fld_s.i_crb_vld != 0) { |
@@ -120,8 +99,6 @@ void bte_error_handler(unsigned long _nodepda) | |||
120 | BTE_PRINTK(("eh:%p:%d Valid %d, Giving up\n", | 99 | BTE_PRINTK(("eh:%p:%d Valid %d, Giving up\n", |
121 | err_nodepda, smp_processor_id(), | 100 | err_nodepda, smp_processor_id(), |
122 | i)); | 101 | i)); |
123 | spin_unlock_irqrestore(recovery_lock, | ||
124 | irq_flags); | ||
125 | return; | 102 | return; |
126 | } | 103 | } |
127 | } | 104 | } |
@@ -146,6 +123,51 @@ void bte_error_handler(unsigned long _nodepda) | |||
146 | ibcr.ii_ibcr_fld_s.i_soft_reset = 1; | 123 | ibcr.ii_ibcr_fld_s.i_soft_reset = 1; |
147 | REMOTE_HUB_S(nasid, IIO_IBCR, ibcr.ii_ibcr_regval); | 124 | REMOTE_HUB_S(nasid, IIO_IBCR, ibcr.ii_ibcr_regval); |
148 | 125 | ||
126 | del_timer(recovery_timer); | ||
127 | } | ||
128 | |||
129 | /* | ||
130 | * Wait until all BTE related CRBs are completed | ||
131 | * and then reset the interfaces. | ||
132 | */ | ||
133 | void bte_error_handler(unsigned long _nodepda) | ||
134 | { | ||
135 | struct nodepda_s *err_nodepda = (struct nodepda_s *)_nodepda; | ||
136 | spinlock_t *recovery_lock = &err_nodepda->bte_recovery_lock; | ||
137 | int i; | ||
138 | nasid_t nasid; | ||
139 | unsigned long irq_flags; | ||
140 | volatile u64 *notify; | ||
141 | bte_result_t bh_error; | ||
142 | |||
143 | BTE_PRINTK(("bte_error_handler(%p) - %d\n", err_nodepda, | ||
144 | smp_processor_id())); | ||
145 | |||
146 | spin_lock_irqsave(recovery_lock, irq_flags); | ||
147 | |||
148 | /* | ||
149 | * Lock all interfaces on this node to prevent new transfers | ||
150 | * from being queued. | ||
151 | */ | ||
152 | for (i = 0; i < BTES_PER_NODE; i++) { | ||
153 | if (err_nodepda->bte_if[i].cleanup_active) { | ||
154 | continue; | ||
155 | } | ||
156 | spin_lock(&err_nodepda->bte_if[i].spinlock); | ||
157 | BTE_PRINTK(("eh:%p:%d locked %d\n", err_nodepda, | ||
158 | smp_processor_id(), i)); | ||
159 | err_nodepda->bte_if[i].cleanup_active = 1; | ||
160 | } | ||
161 | |||
162 | if (is_shub1()) { | ||
163 | shub1_bte_error_handler(_nodepda); | ||
164 | } else { | ||
165 | nasid = cnodeid_to_nasid(err_nodepda->bte_if[0].bte_cnode); | ||
166 | |||
167 | if (ia64_sn_bte_recovery(nasid)) | ||
168 | panic("bte_error_handler(): Fatal BTE Error"); | ||
169 | } | ||
170 | |||
149 | for (i = 0; i < BTES_PER_NODE; i++) { | 171 | for (i = 0; i < BTES_PER_NODE; i++) { |
150 | bh_error = err_nodepda->bte_if[i].bh_error; | 172 | bh_error = err_nodepda->bte_if[i].bh_error; |
151 | if (bh_error != BTE_SUCCESS) { | 173 | if (bh_error != BTE_SUCCESS) { |
@@ -165,8 +187,6 @@ void bte_error_handler(unsigned long _nodepda) | |||
165 | spin_unlock(&err_nodepda->bte_if[i].spinlock); | 187 | spin_unlock(&err_nodepda->bte_if[i].spinlock); |
166 | } | 188 | } |
167 | 189 | ||
168 | del_timer(recovery_timer); | ||
169 | |||
170 | spin_unlock_irqrestore(recovery_lock, irq_flags); | 190 | spin_unlock_irqrestore(recovery_lock, irq_flags); |
171 | } | 191 | } |
172 | 192 | ||
diff --git a/arch/ia64/sn/kernel/huberror.c b/arch/ia64/sn/kernel/huberror.c index 2bdf684c5066..5c39b43ba3c0 100644 --- a/arch/ia64/sn/kernel/huberror.c +++ b/arch/ia64/sn/kernel/huberror.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * License. See the file "COPYING" in the main directory of this archive | 3 | * License. See the file "COPYING" in the main directory of this archive |
4 | * for more details. | 4 | * for more details. |
5 | * | 5 | * |
6 | * Copyright (C) 1992 - 1997, 2000,2002-2004 Silicon Graphics, Inc. All rights reserved. | 6 | * Copyright (C) 1992 - 1997, 2000,2002-2005 Silicon Graphics, Inc. All rights reserved. |
7 | */ | 7 | */ |
8 | 8 | ||
9 | #include <linux/types.h> | 9 | #include <linux/types.h> |
@@ -38,8 +38,11 @@ static irqreturn_t hub_eint_handler(int irq, void *arg, struct pt_regs *ep) | |||
38 | if ((int)ret_stuff.v0) | 38 | if ((int)ret_stuff.v0) |
39 | panic("hubii_eint_handler(): Fatal TIO Error"); | 39 | panic("hubii_eint_handler(): Fatal TIO Error"); |
40 | 40 | ||
41 | if (!(nasid & 1)) /* Not a TIO, handle CRB errors */ | 41 | if (is_shub1()) { |
42 | (void)hubiio_crb_error_handler(hubdev_info); | 42 | if (!(nasid & 1)) /* Not a TIO, handle CRB errors */ |
43 | (void)hubiio_crb_error_handler(hubdev_info); | ||
44 | } else | ||
45 | bte_error_handler((unsigned long)NODEPDA(nasid_to_cnodeid(nasid))); | ||
43 | 46 | ||
44 | return IRQ_HANDLED; | 47 | return IRQ_HANDLED; |
45 | } | 48 | } |
diff --git a/arch/ia64/sn/kernel/io_init.c b/arch/ia64/sn/kernel/io_init.c index 001880812b7c..18160a06a8c9 100644 --- a/arch/ia64/sn/kernel/io_init.c +++ b/arch/ia64/sn/kernel/io_init.c | |||
@@ -11,14 +11,15 @@ | |||
11 | #include <asm/sn/types.h> | 11 | #include <asm/sn/types.h> |
12 | #include <asm/sn/sn_sal.h> | 12 | #include <asm/sn/sn_sal.h> |
13 | #include <asm/sn/addrs.h> | 13 | #include <asm/sn/addrs.h> |
14 | #include "pci/pcibus_provider_defs.h" | 14 | #include <asm/sn/pcibus_provider_defs.h> |
15 | #include "pci/pcidev.h" | 15 | #include <asm/sn/pcidev.h> |
16 | #include "pci/pcibr_provider.h" | 16 | #include "pci/pcibr_provider.h" |
17 | #include "xtalk/xwidgetdev.h" | 17 | #include "xtalk/xwidgetdev.h" |
18 | #include <asm/sn/geo.h> | 18 | #include <asm/sn/geo.h> |
19 | #include "xtalk/hubdev.h" | 19 | #include "xtalk/hubdev.h" |
20 | #include <asm/sn/io.h> | 20 | #include <asm/sn/io.h> |
21 | #include <asm/sn/simulator.h> | 21 | #include <asm/sn/simulator.h> |
22 | #include <asm/sn/tioca_provider.h> | ||
22 | 23 | ||
23 | char master_baseio_wid; | 24 | char master_baseio_wid; |
24 | nasid_t master_nasid = INVALID_NASID; /* Partition Master */ | 25 | nasid_t master_nasid = INVALID_NASID; /* Partition Master */ |
@@ -34,6 +35,37 @@ struct brick { | |||
34 | 35 | ||
35 | int sn_ioif_inited = 0; /* SN I/O infrastructure initialized? */ | 36 | int sn_ioif_inited = 0; /* SN I/O infrastructure initialized? */ |
36 | 37 | ||
38 | struct sn_pcibus_provider *sn_pci_provider[PCIIO_ASIC_MAX_TYPES]; /* indexed by asic type */ | ||
39 | |||
40 | /* | ||
41 | * Hooks and struct for unsupported pci providers | ||
42 | */ | ||
43 | |||
44 | static dma_addr_t | ||
45 | sn_default_pci_map(struct pci_dev *pdev, unsigned long paddr, size_t size) | ||
46 | { | ||
47 | return 0; | ||
48 | } | ||
49 | |||
50 | static void | ||
51 | sn_default_pci_unmap(struct pci_dev *pdev, dma_addr_t addr, int direction) | ||
52 | { | ||
53 | return; | ||
54 | } | ||
55 | |||
56 | static void * | ||
57 | sn_default_pci_bus_fixup(struct pcibus_bussoft *soft) | ||
58 | { | ||
59 | return NULL; | ||
60 | } | ||
61 | |||
62 | static struct sn_pcibus_provider sn_pci_default_provider = { | ||
63 | .dma_map = sn_default_pci_map, | ||
64 | .dma_map_consistent = sn_default_pci_map, | ||
65 | .dma_unmap = sn_default_pci_unmap, | ||
66 | .bus_fixup = sn_default_pci_bus_fixup, | ||
67 | }; | ||
68 | |||
37 | /* | 69 | /* |
38 | * Retrieve the DMA Flush List given nasid. This list is needed | 70 | * Retrieve the DMA Flush List given nasid. This list is needed |
39 | * to implement the WAR - Flush DMA data on PIO Reads. | 71 | * to implement the WAR - Flush DMA data on PIO Reads. |
@@ -201,6 +233,7 @@ static void sn_pci_fixup_slot(struct pci_dev *dev) | |||
201 | struct sn_irq_info *sn_irq_info; | 233 | struct sn_irq_info *sn_irq_info; |
202 | struct pci_dev *host_pci_dev; | 234 | struct pci_dev *host_pci_dev; |
203 | int status = 0; | 235 | int status = 0; |
236 | struct pcibus_bussoft *bs; | ||
204 | 237 | ||
205 | dev->sysdata = kmalloc(sizeof(struct pcidev_info), GFP_KERNEL); | 238 | dev->sysdata = kmalloc(sizeof(struct pcidev_info), GFP_KERNEL); |
206 | if (SN_PCIDEV_INFO(dev) <= 0) | 239 | if (SN_PCIDEV_INFO(dev) <= 0) |
@@ -241,6 +274,7 @@ static void sn_pci_fixup_slot(struct pci_dev *dev) | |||
241 | } | 274 | } |
242 | 275 | ||
243 | /* set up host bus linkages */ | 276 | /* set up host bus linkages */ |
277 | bs = SN_PCIBUS_BUSSOFT(dev->bus); | ||
244 | host_pci_dev = | 278 | host_pci_dev = |
245 | pci_find_slot(SN_PCIDEV_INFO(dev)->pdi_slot_host_handle >> 32, | 279 | pci_find_slot(SN_PCIDEV_INFO(dev)->pdi_slot_host_handle >> 32, |
246 | SN_PCIDEV_INFO(dev)-> | 280 | SN_PCIDEV_INFO(dev)-> |
@@ -248,10 +282,16 @@ static void sn_pci_fixup_slot(struct pci_dev *dev) | |||
248 | SN_PCIDEV_INFO(dev)->pdi_host_pcidev_info = | 282 | SN_PCIDEV_INFO(dev)->pdi_host_pcidev_info = |
249 | SN_PCIDEV_INFO(host_pci_dev); | 283 | SN_PCIDEV_INFO(host_pci_dev); |
250 | SN_PCIDEV_INFO(dev)->pdi_linux_pcidev = dev; | 284 | SN_PCIDEV_INFO(dev)->pdi_linux_pcidev = dev; |
251 | SN_PCIDEV_INFO(dev)->pdi_pcibus_info = SN_PCIBUS_BUSSOFT(dev->bus); | 285 | SN_PCIDEV_INFO(dev)->pdi_pcibus_info = bs; |
286 | |||
287 | if (bs && bs->bs_asic_type < PCIIO_ASIC_MAX_TYPES) { | ||
288 | SN_PCIDEV_BUSPROVIDER(dev) = sn_pci_provider[bs->bs_asic_type]; | ||
289 | } else { | ||
290 | SN_PCIDEV_BUSPROVIDER(dev) = &sn_pci_default_provider; | ||
291 | } | ||
252 | 292 | ||
253 | /* Only set up IRQ stuff if this device has a host bus context */ | 293 | /* Only set up IRQ stuff if this device has a host bus context */ |
254 | if (SN_PCIDEV_BUSSOFT(dev) && sn_irq_info->irq_irq) { | 294 | if (bs && sn_irq_info->irq_irq) { |
255 | SN_PCIDEV_INFO(dev)->pdi_sn_irq_info = sn_irq_info; | 295 | SN_PCIDEV_INFO(dev)->pdi_sn_irq_info = sn_irq_info; |
256 | dev->irq = SN_PCIDEV_INFO(dev)->pdi_sn_irq_info->irq_irq; | 296 | dev->irq = SN_PCIDEV_INFO(dev)->pdi_sn_irq_info->irq_irq; |
257 | sn_irq_fixup(dev, sn_irq_info); | 297 | sn_irq_fixup(dev, sn_irq_info); |
@@ -271,6 +311,7 @@ static void sn_pci_controller_fixup(int segment, int busnum) | |||
271 | struct pcibus_bussoft *prom_bussoft_ptr; | 311 | struct pcibus_bussoft *prom_bussoft_ptr; |
272 | struct hubdev_info *hubdev_info; | 312 | struct hubdev_info *hubdev_info; |
273 | void *provider_soft; | 313 | void *provider_soft; |
314 | struct sn_pcibus_provider *provider; | ||
274 | 315 | ||
275 | status = | 316 | status = |
276 | sal_get_pcibus_info((u64) segment, (u64) busnum, | 317 | sal_get_pcibus_info((u64) segment, (u64) busnum, |
@@ -291,16 +332,22 @@ static void sn_pci_controller_fixup(int segment, int busnum) | |||
291 | /* | 332 | /* |
292 | * Per-provider fixup. Copies the contents from prom to local | 333 | * Per-provider fixup. Copies the contents from prom to local |
293 | * area and links SN_PCIBUS_BUSSOFT(). | 334 | * area and links SN_PCIBUS_BUSSOFT(). |
294 | * | ||
295 | * Note: Provider is responsible for ensuring that prom_bussoft_ptr | ||
296 | * represents an asic-type that it can handle. | ||
297 | */ | 335 | */ |
298 | 336 | ||
299 | if (prom_bussoft_ptr->bs_asic_type == PCIIO_ASIC_TYPE_PPB) { | 337 | if (prom_bussoft_ptr->bs_asic_type >= PCIIO_ASIC_MAX_TYPES) { |
300 | return; /* no further fixup necessary */ | 338 | return; /* unsupported asic type */ |
339 | } | ||
340 | |||
341 | provider = sn_pci_provider[prom_bussoft_ptr->bs_asic_type]; | ||
342 | if (provider == NULL) { | ||
343 | return; /* no provider registerd for this asic */ | ||
344 | } | ||
345 | |||
346 | provider_soft = NULL; | ||
347 | if (provider->bus_fixup) { | ||
348 | provider_soft = (*provider->bus_fixup) (prom_bussoft_ptr); | ||
301 | } | 349 | } |
302 | 350 | ||
303 | provider_soft = pcibr_bus_fixup(prom_bussoft_ptr); | ||
304 | if (provider_soft == NULL) { | 351 | if (provider_soft == NULL) { |
305 | return; /* fixup failed or not applicable */ | 352 | return; /* fixup failed or not applicable */ |
306 | } | 353 | } |
@@ -339,6 +386,17 @@ static int __init sn_pci_init(void) | |||
339 | return 0; | 386 | return 0; |
340 | 387 | ||
341 | /* | 388 | /* |
389 | * prime sn_pci_provider[]. Individial provider init routines will | ||
390 | * override their respective default entries. | ||
391 | */ | ||
392 | |||
393 | for (i = 0; i < PCIIO_ASIC_MAX_TYPES; i++) | ||
394 | sn_pci_provider[i] = &sn_pci_default_provider; | ||
395 | |||
396 | pcibr_init_provider(); | ||
397 | tioca_init_provider(); | ||
398 | |||
399 | /* | ||
342 | * This is needed to avoid bounce limit checks in the blk layer | 400 | * This is needed to avoid bounce limit checks in the blk layer |
343 | */ | 401 | */ |
344 | ia64_max_iommu_merge_mask = ~PAGE_MASK; | 402 | ia64_max_iommu_merge_mask = ~PAGE_MASK; |
diff --git a/arch/ia64/sn/kernel/irq.c b/arch/ia64/sn/kernel/irq.c index 3be44724f6c8..0f4e8138658f 100644 --- a/arch/ia64/sn/kernel/irq.c +++ b/arch/ia64/sn/kernel/irq.c | |||
@@ -13,8 +13,8 @@ | |||
13 | #include <asm/sn/addrs.h> | 13 | #include <asm/sn/addrs.h> |
14 | #include <asm/sn/arch.h> | 14 | #include <asm/sn/arch.h> |
15 | #include "xtalk/xwidgetdev.h" | 15 | #include "xtalk/xwidgetdev.h" |
16 | #include "pci/pcibus_provider_defs.h" | 16 | #include <asm/sn/pcibus_provider_defs.h> |
17 | #include "pci/pcidev.h" | 17 | #include <asm/sn/pcidev.h> |
18 | #include "pci/pcibr_provider.h" | 18 | #include "pci/pcibr_provider.h" |
19 | #include <asm/sn/shub_mmr.h> | 19 | #include <asm/sn/shub_mmr.h> |
20 | #include <asm/sn/sn_sal.h> | 20 | #include <asm/sn/sn_sal.h> |
@@ -82,20 +82,9 @@ static void sn_ack_irq(unsigned int irq) | |||
82 | nasid = get_nasid(); | 82 | nasid = get_nasid(); |
83 | event_occurred = | 83 | event_occurred = |
84 | HUB_L((uint64_t *) GLOBAL_MMR_ADDR(nasid, SH_EVENT_OCCURRED)); | 84 | HUB_L((uint64_t *) GLOBAL_MMR_ADDR(nasid, SH_EVENT_OCCURRED)); |
85 | if (event_occurred & SH_EVENT_OCCURRED_UART_INT_MASK) { | 85 | mask = event_occurred & SH_ALL_INT_MASK; |
86 | mask |= (1 << SH_EVENT_OCCURRED_UART_INT_SHFT); | ||
87 | } | ||
88 | if (event_occurred & SH_EVENT_OCCURRED_IPI_INT_MASK) { | ||
89 | mask |= (1 << SH_EVENT_OCCURRED_IPI_INT_SHFT); | ||
90 | } | ||
91 | if (event_occurred & SH_EVENT_OCCURRED_II_INT0_MASK) { | ||
92 | mask |= (1 << SH_EVENT_OCCURRED_II_INT0_SHFT); | ||
93 | } | ||
94 | if (event_occurred & SH_EVENT_OCCURRED_II_INT1_MASK) { | ||
95 | mask |= (1 << SH_EVENT_OCCURRED_II_INT1_SHFT); | ||
96 | } | ||
97 | HUB_S((uint64_t *) GLOBAL_MMR_ADDR(nasid, SH_EVENT_OCCURRED_ALIAS), | 86 | HUB_S((uint64_t *) GLOBAL_MMR_ADDR(nasid, SH_EVENT_OCCURRED_ALIAS), |
98 | mask); | 87 | mask); |
99 | __set_bit(irq, (volatile void *)pda->sn_in_service_ivecs); | 88 | __set_bit(irq, (volatile void *)pda->sn_in_service_ivecs); |
100 | 89 | ||
101 | move_irq(irq); | 90 | move_irq(irq); |
diff --git a/arch/ia64/sn/kernel/setup.c b/arch/ia64/sn/kernel/setup.c index f0306b516afb..d35f2a6f9c94 100644 --- a/arch/ia64/sn/kernel/setup.c +++ b/arch/ia64/sn/kernel/setup.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <linux/sched.h> | 29 | #include <linux/sched.h> |
30 | #include <linux/root_dev.h> | 30 | #include <linux/root_dev.h> |
31 | #include <linux/nodemask.h> | 31 | #include <linux/nodemask.h> |
32 | #include <linux/pm.h> | ||
32 | 33 | ||
33 | #include <asm/io.h> | 34 | #include <asm/io.h> |
34 | #include <asm/sal.h> | 35 | #include <asm/sal.h> |
@@ -353,6 +354,14 @@ void __init sn_setup(char **cmdline_p) | |||
353 | screen_info = sn_screen_info; | 354 | screen_info = sn_screen_info; |
354 | 355 | ||
355 | sn_timer_init(); | 356 | sn_timer_init(); |
357 | |||
358 | /* | ||
359 | * set pm_power_off to a SAL call to allow | ||
360 | * sn machines to power off. The SAL call can be replaced | ||
361 | * by an ACPI interface call when ACPI is fully implemented | ||
362 | * for sn. | ||
363 | */ | ||
364 | pm_power_off = ia64_sn_power_down; | ||
356 | } | 365 | } |
357 | 366 | ||
358 | /** | 367 | /** |
diff --git a/arch/ia64/sn/kernel/sn2/sn_hwperf.c b/arch/ia64/sn/kernel/sn2/sn_hwperf.c index 197356460ee1..833e700fdac9 100644 --- a/arch/ia64/sn/kernel/sn2/sn_hwperf.c +++ b/arch/ia64/sn/kernel/sn2/sn_hwperf.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <linux/vmalloc.h> | 28 | #include <linux/vmalloc.h> |
29 | #include <linux/seq_file.h> | 29 | #include <linux/seq_file.h> |
30 | #include <linux/miscdevice.h> | 30 | #include <linux/miscdevice.h> |
31 | #include <linux/utsname.h> | ||
31 | #include <linux/cpumask.h> | 32 | #include <linux/cpumask.h> |
32 | #include <linux/smp_lock.h> | 33 | #include <linux/smp_lock.h> |
33 | #include <linux/nodemask.h> | 34 | #include <linux/nodemask.h> |
@@ -43,6 +44,7 @@ | |||
43 | #include <asm/sn/module.h> | 44 | #include <asm/sn/module.h> |
44 | #include <asm/sn/geo.h> | 45 | #include <asm/sn/geo.h> |
45 | #include <asm/sn/sn2/sn_hwperf.h> | 46 | #include <asm/sn/sn2/sn_hwperf.h> |
47 | #include <asm/sn/addrs.h> | ||
46 | 48 | ||
47 | static void *sn_hwperf_salheap = NULL; | 49 | static void *sn_hwperf_salheap = NULL; |
48 | static int sn_hwperf_obj_cnt = 0; | 50 | static int sn_hwperf_obj_cnt = 0; |
@@ -81,26 +83,45 @@ out: | |||
81 | return e; | 83 | return e; |
82 | } | 84 | } |
83 | 85 | ||
86 | static int sn_hwperf_location_to_bpos(char *location, | ||
87 | int *rack, int *bay, int *slot, int *slab) | ||
88 | { | ||
89 | char type; | ||
90 | |||
91 | /* first scan for an old style geoid string */ | ||
92 | if (sscanf(location, "%03d%c%02d#%d", | ||
93 | rack, &type, bay, slab) == 4) | ||
94 | *slot = 0; | ||
95 | else /* scan for a new bladed geoid string */ | ||
96 | if (sscanf(location, "%03d%c%02d^%02d#%d", | ||
97 | rack, &type, bay, slot, slab) != 5) | ||
98 | return -1; | ||
99 | /* success */ | ||
100 | return 0; | ||
101 | } | ||
102 | |||
84 | static int sn_hwperf_geoid_to_cnode(char *location) | 103 | static int sn_hwperf_geoid_to_cnode(char *location) |
85 | { | 104 | { |
86 | int cnode; | 105 | int cnode; |
87 | geoid_t geoid; | 106 | geoid_t geoid; |
88 | moduleid_t module_id; | 107 | moduleid_t module_id; |
89 | char type; | 108 | int rack, bay, slot, slab; |
90 | int rack, slot, slab; | 109 | int this_rack, this_bay, this_slot, this_slab; |
91 | int this_rack, this_slot, this_slab; | ||
92 | 110 | ||
93 | if (sscanf(location, "%03d%c%02d#%d", &rack, &type, &slot, &slab) != 4) | 111 | if (sn_hwperf_location_to_bpos(location, &rack, &bay, &slot, &slab)) |
94 | return -1; | 112 | return -1; |
95 | 113 | ||
96 | for (cnode = 0; cnode < numionodes; cnode++) { | 114 | for (cnode = 0; cnode < numionodes; cnode++) { |
97 | geoid = cnodeid_get_geoid(cnode); | 115 | geoid = cnodeid_get_geoid(cnode); |
98 | module_id = geo_module(geoid); | 116 | module_id = geo_module(geoid); |
99 | this_rack = MODULE_GET_RACK(module_id); | 117 | this_rack = MODULE_GET_RACK(module_id); |
100 | this_slot = MODULE_GET_BPOS(module_id); | 118 | this_bay = MODULE_GET_BPOS(module_id); |
119 | this_slot = geo_slot(geoid); | ||
101 | this_slab = geo_slab(geoid); | 120 | this_slab = geo_slab(geoid); |
102 | if (rack == this_rack && slot == this_slot && slab == this_slab) | 121 | if (rack == this_rack && bay == this_bay && |
122 | slot == this_slot && slab == this_slab) { | ||
103 | break; | 123 | break; |
124 | } | ||
104 | } | 125 | } |
105 | 126 | ||
106 | return cnode < numionodes ? cnode : -1; | 127 | return cnode < numionodes ? cnode : -1; |
@@ -153,11 +174,36 @@ static const char *sn_hwperf_get_slabname(struct sn_hwperf_object_info *obj, | |||
153 | return slabname; | 174 | return slabname; |
154 | } | 175 | } |
155 | 176 | ||
177 | static void print_pci_topology(struct seq_file *s, | ||
178 | struct sn_hwperf_object_info *obj, int *ordinal, | ||
179 | u64 rack, u64 bay, u64 slot, u64 slab) | ||
180 | { | ||
181 | char *p1; | ||
182 | char *p2; | ||
183 | char *pg; | ||
184 | |||
185 | if (!(pg = (char *)get_zeroed_page(GFP_KERNEL))) | ||
186 | return; /* ignore */ | ||
187 | if (ia64_sn_ioif_get_pci_topology(rack, bay, slot, slab, | ||
188 | __pa(pg), PAGE_SIZE) == SN_HWPERF_OP_OK) { | ||
189 | for (p1=pg; *p1 && p1 < pg + PAGE_SIZE;) { | ||
190 | if (!(p2 = strchr(p1, '\n'))) | ||
191 | break; | ||
192 | *p2 = '\0'; | ||
193 | seq_printf(s, "pcibus %d %s-%s\n", | ||
194 | *ordinal, obj->location, p1); | ||
195 | (*ordinal)++; | ||
196 | p1 = p2 + 1; | ||
197 | } | ||
198 | } | ||
199 | free_page((unsigned long)pg); | ||
200 | } | ||
201 | |||
156 | static int sn_topology_show(struct seq_file *s, void *d) | 202 | static int sn_topology_show(struct seq_file *s, void *d) |
157 | { | 203 | { |
158 | int sz; | 204 | int sz; |
159 | int pt; | 205 | int pt; |
160 | int e; | 206 | int e = 0; |
161 | int i; | 207 | int i; |
162 | int j; | 208 | int j; |
163 | const char *slabname; | 209 | const char *slabname; |
@@ -169,11 +215,44 @@ static int sn_topology_show(struct seq_file *s, void *d) | |||
169 | struct sn_hwperf_object_info *p; | 215 | struct sn_hwperf_object_info *p; |
170 | struct sn_hwperf_object_info *obj = d; /* this object */ | 216 | struct sn_hwperf_object_info *obj = d; /* this object */ |
171 | struct sn_hwperf_object_info *objs = s->private; /* all objects */ | 217 | struct sn_hwperf_object_info *objs = s->private; /* all objects */ |
218 | int rack, bay, slot, slab; | ||
219 | u8 shubtype; | ||
220 | u8 system_size; | ||
221 | u8 sharing_size; | ||
222 | u8 partid; | ||
223 | u8 coher; | ||
224 | u8 nasid_shift; | ||
225 | u8 region_size; | ||
226 | u16 nasid_mask; | ||
227 | int nasid_msb; | ||
228 | int pci_bus_ordinal = 0; | ||
172 | 229 | ||
173 | if (obj == objs) { | 230 | if (obj == objs) { |
174 | seq_printf(s, "# sn_topology version 1\n"); | 231 | seq_printf(s, "# sn_topology version 2\n"); |
175 | seq_printf(s, "# objtype ordinal location partition" | 232 | seq_printf(s, "# objtype ordinal location partition" |
176 | " [attribute value [, ...]]\n"); | 233 | " [attribute value [, ...]]\n"); |
234 | |||
235 | if (ia64_sn_get_sn_info(0, | ||
236 | &shubtype, &nasid_mask, &nasid_shift, &system_size, | ||
237 | &sharing_size, &partid, &coher, ®ion_size)) | ||
238 | BUG(); | ||
239 | for (nasid_msb=63; nasid_msb > 0; nasid_msb--) { | ||
240 | if (((u64)nasid_mask << nasid_shift) & (1ULL << nasid_msb)) | ||
241 | break; | ||
242 | } | ||
243 | seq_printf(s, "partition %u %s local " | ||
244 | "shubtype %s, " | ||
245 | "nasid_mask 0x%016lx, " | ||
246 | "nasid_bits %d:%d, " | ||
247 | "system_size %d, " | ||
248 | "sharing_size %d, " | ||
249 | "coherency_domain %d, " | ||
250 | "region_size %d\n", | ||
251 | |||
252 | partid, system_utsname.nodename, | ||
253 | shubtype ? "shub2" : "shub1", | ||
254 | (u64)nasid_mask << nasid_shift, nasid_msb, nasid_shift, | ||
255 | system_size, sharing_size, coher, region_size); | ||
177 | } | 256 | } |
178 | 257 | ||
179 | if (SN_HWPERF_FOREIGN(obj)) { | 258 | if (SN_HWPERF_FOREIGN(obj)) { |
@@ -181,7 +260,7 @@ static int sn_topology_show(struct seq_file *s, void *d) | |||
181 | return 0; | 260 | return 0; |
182 | } | 261 | } |
183 | 262 | ||
184 | for (i = 0; obj->name[i]; i++) { | 263 | for (i = 0; i < SN_HWPERF_MAXSTRING && obj->name[i]; i++) { |
185 | if (obj->name[i] == ' ') | 264 | if (obj->name[i] == ' ') |
186 | obj->name[i] = '_'; | 265 | obj->name[i] = '_'; |
187 | } | 266 | } |
@@ -221,6 +300,17 @@ static int sn_topology_show(struct seq_file *s, void *d) | |||
221 | seq_putc(s, '\n'); | 300 | seq_putc(s, '\n'); |
222 | } | 301 | } |
223 | } | 302 | } |
303 | |||
304 | /* | ||
305 | * PCI busses attached to this node, if any | ||
306 | */ | ||
307 | if (sn_hwperf_location_to_bpos(obj->location, | ||
308 | &rack, &bay, &slot, &slab)) { | ||
309 | /* export pci bus info */ | ||
310 | print_pci_topology(s, obj, &pci_bus_ordinal, | ||
311 | rack, bay, slot, slab); | ||
312 | |||
313 | } | ||
224 | } | 314 | } |
225 | 315 | ||
226 | if (obj->ports) { | 316 | if (obj->ports) { |
@@ -397,6 +487,9 @@ static int sn_hwperf_map_err(int hwperf_err) | |||
397 | break; | 487 | break; |
398 | 488 | ||
399 | case SN_HWPERF_OP_BUSY: | 489 | case SN_HWPERF_OP_BUSY: |
490 | e = -EBUSY; | ||
491 | break; | ||
492 | |||
400 | case SN_HWPERF_OP_RECONFIGURE: | 493 | case SN_HWPERF_OP_RECONFIGURE: |
401 | e = -EAGAIN; | 494 | e = -EAGAIN; |
402 | break; | 495 | break; |
@@ -549,6 +642,7 @@ sn_hwperf_ioctl(struct inode *in, struct file *fp, u32 op, u64 arg) | |||
549 | r = sn_hwperf_op_cpu(&op_info); | 642 | r = sn_hwperf_op_cpu(&op_info); |
550 | if (r) { | 643 | if (r) { |
551 | r = sn_hwperf_map_err(r); | 644 | r = sn_hwperf_map_err(r); |
645 | a.v0 = v0; | ||
552 | goto error; | 646 | goto error; |
553 | } | 647 | } |
554 | break; | 648 | break; |
diff --git a/arch/ia64/sn/kernel/tiocx.c b/arch/ia64/sn/kernel/tiocx.c new file mode 100644 index 000000000000..66190d7e492d --- /dev/null +++ b/arch/ia64/sn/kernel/tiocx.c | |||
@@ -0,0 +1,548 @@ | |||
1 | /* | ||
2 | * This file is subject to the terms and conditions of the GNU General Public | ||
3 | * License. See the file "COPYING" in the main directory of this archive | ||
4 | * for more details. | ||
5 | * | ||
6 | * Copyright (c) 2005 Silicon Graphics, Inc. All rights reserved. | ||
7 | */ | ||
8 | |||
9 | #include <linux/module.h> | ||
10 | #include <linux/kernel.h> | ||
11 | #include <linux/version.h> | ||
12 | #include <linux/slab.h> | ||
13 | #include <linux/spinlock.h> | ||
14 | #include <linux/proc_fs.h> | ||
15 | #include <linux/device.h> | ||
16 | #include <linux/delay.h> | ||
17 | #include <asm/uaccess.h> | ||
18 | #include <asm/sn/sn_sal.h> | ||
19 | #include <asm/sn/addrs.h> | ||
20 | #include <asm/sn/io.h> | ||
21 | #include <asm/sn/types.h> | ||
22 | #include <asm/sn/shubio.h> | ||
23 | #include <asm/sn/tiocx.h> | ||
24 | #include "tio.h" | ||
25 | #include "xtalk/xwidgetdev.h" | ||
26 | #include "xtalk/hubdev.h" | ||
27 | |||
28 | #define CX_DEV_NONE 0 | ||
29 | #define DEVICE_NAME "tiocx" | ||
30 | #define WIDGET_ID 0 | ||
31 | #define TIOCX_DEBUG 0 | ||
32 | |||
33 | #if TIOCX_DEBUG | ||
34 | #define DBG(fmt...) printk(KERN_ALERT fmt) | ||
35 | #else | ||
36 | #define DBG(fmt...) | ||
37 | #endif | ||
38 | |||
39 | struct device_attribute dev_attr_cxdev_control; | ||
40 | |||
41 | /** | ||
42 | * tiocx_match - Try to match driver id list with device. | ||
43 | * @dev: device pointer | ||
44 | * @drv: driver pointer | ||
45 | * | ||
46 | * Returns 1 if match, 0 otherwise. | ||
47 | */ | ||
48 | static int tiocx_match(struct device *dev, struct device_driver *drv) | ||
49 | { | ||
50 | struct cx_dev *cx_dev = to_cx_dev(dev); | ||
51 | struct cx_drv *cx_drv = to_cx_driver(drv); | ||
52 | const struct cx_device_id *ids = cx_drv->id_table; | ||
53 | |||
54 | if (!ids) | ||
55 | return 0; | ||
56 | |||
57 | while (ids->part_num) { | ||
58 | if (ids->part_num == cx_dev->cx_id.part_num) | ||
59 | return 1; | ||
60 | ids++; | ||
61 | } | ||
62 | return 0; | ||
63 | |||
64 | } | ||
65 | |||
66 | static int tiocx_hotplug(struct device *dev, char **envp, int num_envp, | ||
67 | char *buffer, int buffer_size) | ||
68 | { | ||
69 | return -ENODEV; | ||
70 | } | ||
71 | |||
72 | static void tiocx_bus_release(struct device *dev) | ||
73 | { | ||
74 | kfree(to_cx_dev(dev)); | ||
75 | } | ||
76 | |||
77 | struct bus_type tiocx_bus_type = { | ||
78 | .name = "tiocx", | ||
79 | .match = tiocx_match, | ||
80 | .hotplug = tiocx_hotplug, | ||
81 | }; | ||
82 | |||
83 | /** | ||
84 | * cx_device_match - Find cx_device in the id table. | ||
85 | * @ids: id table from driver | ||
86 | * @cx_device: part/mfg id for the device | ||
87 | * | ||
88 | */ | ||
89 | static const struct cx_device_id *cx_device_match(const struct cx_device_id | ||
90 | *ids, | ||
91 | struct cx_dev *cx_device) | ||
92 | { | ||
93 | /* | ||
94 | * NOTES: We may want to check for CX_ANY_ID too. | ||
95 | * Do we want to match against nasid too? | ||
96 | * CX_DEV_NONE == 0, if the driver tries to register for | ||
97 | * part/mfg == 0 we should return no-match (NULL) here. | ||
98 | */ | ||
99 | while (ids->part_num && ids->mfg_num) { | ||
100 | if (ids->part_num == cx_device->cx_id.part_num && | ||
101 | ids->mfg_num == cx_device->cx_id.mfg_num) | ||
102 | return ids; | ||
103 | ids++; | ||
104 | } | ||
105 | |||
106 | return NULL; | ||
107 | } | ||
108 | |||
109 | /** | ||
110 | * cx_device_probe - Look for matching device. | ||
111 | * Call driver probe routine if found. | ||
112 | * @cx_driver: driver table (cx_drv struct) from driver | ||
113 | * @cx_device: part/mfg id for the device | ||
114 | */ | ||
115 | static int cx_device_probe(struct device *dev) | ||
116 | { | ||
117 | const struct cx_device_id *id; | ||
118 | struct cx_drv *cx_drv = to_cx_driver(dev->driver); | ||
119 | struct cx_dev *cx_dev = to_cx_dev(dev); | ||
120 | int error = 0; | ||
121 | |||
122 | if (!cx_dev->driver && cx_drv->probe) { | ||
123 | id = cx_device_match(cx_drv->id_table, cx_dev); | ||
124 | if (id) { | ||
125 | if ((error = cx_drv->probe(cx_dev, id)) < 0) | ||
126 | return error; | ||
127 | else | ||
128 | cx_dev->driver = cx_drv; | ||
129 | } | ||
130 | } | ||
131 | |||
132 | return error; | ||
133 | } | ||
134 | |||
135 | /** | ||
136 | * cx_driver_remove - Remove driver from device struct. | ||
137 | * @dev: device | ||
138 | */ | ||
139 | static int cx_driver_remove(struct device *dev) | ||
140 | { | ||
141 | struct cx_dev *cx_dev = to_cx_dev(dev); | ||
142 | struct cx_drv *cx_drv = cx_dev->driver; | ||
143 | if (cx_drv->remove) | ||
144 | cx_drv->remove(cx_dev); | ||
145 | cx_dev->driver = NULL; | ||
146 | return 0; | ||
147 | } | ||
148 | |||
149 | /** | ||
150 | * cx_driver_register - Register the driver. | ||
151 | * @cx_driver: driver table (cx_drv struct) from driver | ||
152 | * | ||
153 | * Called from the driver init routine to register a driver. | ||
154 | * The cx_drv struct contains the driver name, a pointer to | ||
155 | * a table of part/mfg numbers and a pointer to the driver's | ||
156 | * probe/attach routine. | ||
157 | */ | ||
158 | int cx_driver_register(struct cx_drv *cx_driver) | ||
159 | { | ||
160 | cx_driver->driver.name = cx_driver->name; | ||
161 | cx_driver->driver.bus = &tiocx_bus_type; | ||
162 | cx_driver->driver.probe = cx_device_probe; | ||
163 | cx_driver->driver.remove = cx_driver_remove; | ||
164 | |||
165 | return driver_register(&cx_driver->driver); | ||
166 | } | ||
167 | |||
168 | /** | ||
169 | * cx_driver_unregister - Unregister the driver. | ||
170 | * @cx_driver: driver table (cx_drv struct) from driver | ||
171 | */ | ||
172 | int cx_driver_unregister(struct cx_drv *cx_driver) | ||
173 | { | ||
174 | driver_unregister(&cx_driver->driver); | ||
175 | return 0; | ||
176 | } | ||
177 | |||
178 | /** | ||
179 | * cx_device_register - Register a device. | ||
180 | * @nasid: device's nasid | ||
181 | * @part_num: device's part number | ||
182 | * @mfg_num: device's manufacturer number | ||
183 | * @hubdev: hub info associated with this device | ||
184 | * | ||
185 | */ | ||
186 | int | ||
187 | cx_device_register(nasid_t nasid, int part_num, int mfg_num, | ||
188 | struct hubdev_info *hubdev) | ||
189 | { | ||
190 | struct cx_dev *cx_dev; | ||
191 | |||
192 | cx_dev = kcalloc(1, sizeof(struct cx_dev), GFP_KERNEL); | ||
193 | DBG("cx_dev= 0x%p\n", cx_dev); | ||
194 | if (cx_dev == NULL) | ||
195 | return -ENOMEM; | ||
196 | |||
197 | cx_dev->cx_id.part_num = part_num; | ||
198 | cx_dev->cx_id.mfg_num = mfg_num; | ||
199 | cx_dev->cx_id.nasid = nasid; | ||
200 | cx_dev->hubdev = hubdev; | ||
201 | |||
202 | cx_dev->dev.parent = NULL; | ||
203 | cx_dev->dev.bus = &tiocx_bus_type; | ||
204 | cx_dev->dev.release = tiocx_bus_release; | ||
205 | snprintf(cx_dev->dev.bus_id, BUS_ID_SIZE, "%d.0x%x", | ||
206 | cx_dev->cx_id.nasid, cx_dev->cx_id.part_num); | ||
207 | device_register(&cx_dev->dev); | ||
208 | get_device(&cx_dev->dev); | ||
209 | |||
210 | device_create_file(&cx_dev->dev, &dev_attr_cxdev_control); | ||
211 | |||
212 | return 0; | ||
213 | } | ||
214 | |||
215 | /** | ||
216 | * cx_device_unregister - Unregister a device. | ||
217 | * @cx_dev: part/mfg id for the device | ||
218 | */ | ||
219 | int cx_device_unregister(struct cx_dev *cx_dev) | ||
220 | { | ||
221 | put_device(&cx_dev->dev); | ||
222 | device_unregister(&cx_dev->dev); | ||
223 | return 0; | ||
224 | } | ||
225 | |||
226 | /** | ||
227 | * cx_device_reload - Reload the device. | ||
228 | * @nasid: device's nasid | ||
229 | * @part_num: device's part number | ||
230 | * @mfg_num: device's manufacturer number | ||
231 | * | ||
232 | * Remove the device associated with 'nasid' from device list and then | ||
233 | * call device-register with the given part/mfg numbers. | ||
234 | */ | ||
235 | static int cx_device_reload(struct cx_dev *cx_dev) | ||
236 | { | ||
237 | device_remove_file(&cx_dev->dev, &dev_attr_cxdev_control); | ||
238 | cx_device_unregister(cx_dev); | ||
239 | return cx_device_register(cx_dev->cx_id.nasid, cx_dev->cx_id.part_num, | ||
240 | cx_dev->cx_id.mfg_num, cx_dev->hubdev); | ||
241 | } | ||
242 | |||
243 | static inline uint64_t tiocx_intr_alloc(nasid_t nasid, int widget, | ||
244 | u64 sn_irq_info, | ||
245 | int req_irq, nasid_t req_nasid, | ||
246 | int req_slice) | ||
247 | { | ||
248 | struct ia64_sal_retval rv; | ||
249 | rv.status = 0; | ||
250 | rv.v0 = 0; | ||
251 | |||
252 | ia64_sal_oemcall_nolock(&rv, SN_SAL_IOIF_INTERRUPT, | ||
253 | SAL_INTR_ALLOC, nasid, | ||
254 | widget, sn_irq_info, req_irq, | ||
255 | req_nasid, req_slice); | ||
256 | return rv.status; | ||
257 | } | ||
258 | |||
259 | static inline void tiocx_intr_free(nasid_t nasid, int widget, | ||
260 | struct sn_irq_info *sn_irq_info) | ||
261 | { | ||
262 | struct ia64_sal_retval rv; | ||
263 | rv.status = 0; | ||
264 | rv.v0 = 0; | ||
265 | |||
266 | ia64_sal_oemcall_nolock(&rv, SN_SAL_IOIF_INTERRUPT, | ||
267 | SAL_INTR_FREE, nasid, | ||
268 | widget, sn_irq_info->irq_irq, | ||
269 | sn_irq_info->irq_cookie, 0, 0); | ||
270 | } | ||
271 | |||
272 | struct sn_irq_info *tiocx_irq_alloc(nasid_t nasid, int widget, int irq, | ||
273 | nasid_t req_nasid, int slice) | ||
274 | { | ||
275 | struct sn_irq_info *sn_irq_info; | ||
276 | int status; | ||
277 | int sn_irq_size = sizeof(struct sn_irq_info); | ||
278 | |||
279 | if ((nasid & 1) == 0) | ||
280 | return NULL; | ||
281 | |||
282 | sn_irq_info = kmalloc(sn_irq_size, GFP_KERNEL); | ||
283 | if (sn_irq_info == NULL) | ||
284 | return NULL; | ||
285 | |||
286 | memset(sn_irq_info, 0x0, sn_irq_size); | ||
287 | |||
288 | status = tiocx_intr_alloc(nasid, widget, __pa(sn_irq_info), irq, | ||
289 | req_nasid, slice); | ||
290 | if (status) { | ||
291 | kfree(sn_irq_info); | ||
292 | return NULL; | ||
293 | } else { | ||
294 | return sn_irq_info; | ||
295 | } | ||
296 | } | ||
297 | |||
298 | void tiocx_irq_free(struct sn_irq_info *sn_irq_info) | ||
299 | { | ||
300 | uint64_t bridge = (uint64_t) sn_irq_info->irq_bridge; | ||
301 | nasid_t nasid = NASID_GET(bridge); | ||
302 | int widget; | ||
303 | |||
304 | if (nasid & 1) { | ||
305 | widget = TIO_SWIN_WIDGETNUM(bridge); | ||
306 | tiocx_intr_free(nasid, widget, sn_irq_info); | ||
307 | kfree(sn_irq_info); | ||
308 | } | ||
309 | } | ||
310 | |||
311 | uint64_t | ||
312 | tiocx_dma_addr(uint64_t addr) | ||
313 | { | ||
314 | return PHYS_TO_TIODMA(addr); | ||
315 | } | ||
316 | |||
317 | uint64_t | ||
318 | tiocx_swin_base(int nasid) | ||
319 | { | ||
320 | return TIO_SWIN_BASE(nasid, TIOCX_CORELET); | ||
321 | } | ||
322 | |||
323 | EXPORT_SYMBOL(cx_driver_register); | ||
324 | EXPORT_SYMBOL(cx_driver_unregister); | ||
325 | EXPORT_SYMBOL(cx_device_register); | ||
326 | EXPORT_SYMBOL(cx_device_unregister); | ||
327 | EXPORT_SYMBOL(tiocx_irq_alloc); | ||
328 | EXPORT_SYMBOL(tiocx_irq_free); | ||
329 | EXPORT_SYMBOL(tiocx_bus_type); | ||
330 | EXPORT_SYMBOL(tiocx_dma_addr); | ||
331 | EXPORT_SYMBOL(tiocx_swin_base); | ||
332 | |||
333 | static uint64_t tiocx_get_hubdev_info(u64 handle, u64 address) | ||
334 | { | ||
335 | |||
336 | struct ia64_sal_retval ret_stuff; | ||
337 | ret_stuff.status = 0; | ||
338 | ret_stuff.v0 = 0; | ||
339 | |||
340 | ia64_sal_oemcall_nolock(&ret_stuff, | ||
341 | SN_SAL_IOIF_GET_HUBDEV_INFO, | ||
342 | handle, address, 0, 0, 0, 0, 0); | ||
343 | return ret_stuff.v0; | ||
344 | } | ||
345 | |||
346 | static void tio_conveyor_set(nasid_t nasid, int enable_flag) | ||
347 | { | ||
348 | uint64_t ice_frz; | ||
349 | uint64_t disable_cb = (1ull << 61); | ||
350 | |||
351 | if (!(nasid & 1)) | ||
352 | return; | ||
353 | |||
354 | ice_frz = REMOTE_HUB_L(nasid, TIO_ICE_FRZ_CFG); | ||
355 | if (enable_flag) { | ||
356 | if (!(ice_frz & disable_cb)) /* already enabled */ | ||
357 | return; | ||
358 | ice_frz &= ~disable_cb; | ||
359 | } else { | ||
360 | if (ice_frz & disable_cb) /* already disabled */ | ||
361 | return; | ||
362 | ice_frz |= disable_cb; | ||
363 | } | ||
364 | DBG(KERN_ALERT "TIO_ICE_FRZ_CFG= 0x%lx\n", ice_frz); | ||
365 | REMOTE_HUB_S(nasid, TIO_ICE_FRZ_CFG, ice_frz); | ||
366 | } | ||
367 | |||
368 | #define tio_conveyor_enable(nasid) tio_conveyor_set(nasid, 1) | ||
369 | #define tio_conveyor_disable(nasid) tio_conveyor_set(nasid, 0) | ||
370 | |||
371 | static void tio_corelet_reset(nasid_t nasid, int corelet) | ||
372 | { | ||
373 | if (!(nasid & 1)) | ||
374 | return; | ||
375 | |||
376 | REMOTE_HUB_S(nasid, TIO_ICE_PMI_TX_CFG, 1 << corelet); | ||
377 | udelay(2000); | ||
378 | REMOTE_HUB_S(nasid, TIO_ICE_PMI_TX_CFG, 0); | ||
379 | udelay(2000); | ||
380 | } | ||
381 | |||
382 | static int fpga_attached(nasid_t nasid) | ||
383 | { | ||
384 | uint64_t cx_credits; | ||
385 | |||
386 | cx_credits = REMOTE_HUB_L(nasid, TIO_ICE_PMI_TX_DYN_CREDIT_STAT_CB3); | ||
387 | cx_credits &= TIO_ICE_PMI_TX_DYN_CREDIT_STAT_CB3_CREDIT_CNT_MASK; | ||
388 | DBG("cx_credits= 0x%lx\n", cx_credits); | ||
389 | |||
390 | return (cx_credits == 0xf) ? 1 : 0; | ||
391 | } | ||
392 | |||
393 | static int tiocx_reload(struct cx_dev *cx_dev) | ||
394 | { | ||
395 | int part_num = CX_DEV_NONE; | ||
396 | int mfg_num = CX_DEV_NONE; | ||
397 | nasid_t nasid = cx_dev->cx_id.nasid; | ||
398 | |||
399 | if (fpga_attached(nasid)) { | ||
400 | uint64_t cx_id; | ||
401 | |||
402 | cx_id = | ||
403 | *(volatile int32_t *)(TIO_SWIN_BASE(nasid, TIOCX_CORELET) + | ||
404 | WIDGET_ID); | ||
405 | part_num = XWIDGET_PART_NUM(cx_id); | ||
406 | mfg_num = XWIDGET_MFG_NUM(cx_id); | ||
407 | DBG("part= 0x%x, mfg= 0x%x\n", part_num, mfg_num); | ||
408 | /* just ignore it if it's a CE */ | ||
409 | if (part_num == TIO_CE_ASIC_PARTNUM) | ||
410 | return 0; | ||
411 | } | ||
412 | |||
413 | cx_dev->cx_id.part_num = part_num; | ||
414 | cx_dev->cx_id.mfg_num = mfg_num; | ||
415 | |||
416 | /* | ||
417 | * Delete old device and register the new one. It's ok if | ||
418 | * part_num/mfg_num == CX_DEV_NONE. We want to register | ||
419 | * devices in the table even if a bitstream isn't loaded. | ||
420 | * That allows use to see that a bitstream isn't loaded via | ||
421 | * TIOCX_IOCTL_DEV_LIST. | ||
422 | */ | ||
423 | return cx_device_reload(cx_dev); | ||
424 | } | ||
425 | |||
426 | static ssize_t show_cxdev_control(struct device *dev, char *buf) | ||
427 | { | ||
428 | struct cx_dev *cx_dev = to_cx_dev(dev); | ||
429 | |||
430 | return sprintf(buf, "0x%x 0x%x 0x%x\n", | ||
431 | cx_dev->cx_id.nasid, | ||
432 | cx_dev->cx_id.part_num, cx_dev->cx_id.mfg_num); | ||
433 | } | ||
434 | |||
435 | static ssize_t store_cxdev_control(struct device *dev, const char *buf, | ||
436 | size_t count) | ||
437 | { | ||
438 | int n; | ||
439 | struct cx_dev *cx_dev = to_cx_dev(dev); | ||
440 | |||
441 | if (!capable(CAP_SYS_ADMIN)) | ||
442 | return -EPERM; | ||
443 | |||
444 | if (count <= 0) | ||
445 | return 0; | ||
446 | |||
447 | n = simple_strtoul(buf, NULL, 0); | ||
448 | |||
449 | switch (n) { | ||
450 | case 1: | ||
451 | tiocx_reload(cx_dev); | ||
452 | break; | ||
453 | case 3: | ||
454 | tio_corelet_reset(cx_dev->cx_id.nasid, TIOCX_CORELET); | ||
455 | break; | ||
456 | default: | ||
457 | break; | ||
458 | } | ||
459 | |||
460 | return count; | ||
461 | } | ||
462 | |||
463 | DEVICE_ATTR(cxdev_control, 0644, show_cxdev_control, store_cxdev_control); | ||
464 | |||
465 | static int __init tiocx_init(void) | ||
466 | { | ||
467 | cnodeid_t cnodeid; | ||
468 | int found_tiocx_device = 0; | ||
469 | |||
470 | bus_register(&tiocx_bus_type); | ||
471 | |||
472 | for (cnodeid = 0; cnodeid < MAX_COMPACT_NODES; cnodeid++) { | ||
473 | nasid_t nasid; | ||
474 | |||
475 | if ((nasid = cnodeid_to_nasid(cnodeid)) < 0) | ||
476 | break; /* No more nasids .. bail out of loop */ | ||
477 | |||
478 | if (nasid & 0x1) { /* TIO's are always odd */ | ||
479 | struct hubdev_info *hubdev; | ||
480 | uint64_t status; | ||
481 | struct xwidget_info *widgetp; | ||
482 | |||
483 | DBG("Found TIO at nasid 0x%x\n", nasid); | ||
484 | |||
485 | hubdev = | ||
486 | (struct hubdev_info *)(NODEPDA(cnodeid)->pdinfo); | ||
487 | status = | ||
488 | tiocx_get_hubdev_info(nasid, | ||
489 | (uint64_t) __pa(hubdev)); | ||
490 | if (status) | ||
491 | continue; | ||
492 | |||
493 | widgetp = &hubdev->hdi_xwidget_info[TIOCX_CORELET]; | ||
494 | |||
495 | /* The CE hangs off of the CX port but is not an FPGA */ | ||
496 | if (widgetp->xwi_hwid.part_num == TIO_CE_ASIC_PARTNUM) | ||
497 | continue; | ||
498 | |||
499 | tio_corelet_reset(nasid, TIOCX_CORELET); | ||
500 | tio_conveyor_enable(nasid); | ||
501 | |||
502 | if (cx_device_register | ||
503 | (nasid, widgetp->xwi_hwid.part_num, | ||
504 | widgetp->xwi_hwid.mfg_num, hubdev) < 0) | ||
505 | return -ENXIO; | ||
506 | else | ||
507 | found_tiocx_device++; | ||
508 | } | ||
509 | } | ||
510 | |||
511 | /* It's ok if we find zero devices. */ | ||
512 | DBG("found_tiocx_device= %d\n", found_tiocx_device); | ||
513 | |||
514 | return 0; | ||
515 | } | ||
516 | |||
517 | static void __exit tiocx_exit(void) | ||
518 | { | ||
519 | struct device *dev; | ||
520 | struct device *tdev; | ||
521 | |||
522 | DBG("tiocx_exit\n"); | ||
523 | |||
524 | /* | ||
525 | * Unregister devices. | ||
526 | */ | ||
527 | list_for_each_entry_safe(dev, tdev, &tiocx_bus_type.devices.list, | ||
528 | bus_list) { | ||
529 | if (dev) { | ||
530 | struct cx_dev *cx_dev = to_cx_dev(dev); | ||
531 | device_remove_file(dev, &dev_attr_cxdev_control); | ||
532 | cx_device_unregister(cx_dev); | ||
533 | } | ||
534 | } | ||
535 | |||
536 | bus_unregister(&tiocx_bus_type); | ||
537 | } | ||
538 | |||
539 | module_init(tiocx_init); | ||
540 | module_exit(tiocx_exit); | ||
541 | |||
542 | /************************************************************************ | ||
543 | * Module licensing and description | ||
544 | ************************************************************************/ | ||
545 | MODULE_LICENSE("GPL"); | ||
546 | MODULE_AUTHOR("Bruce Losure <blosure@sgi.com>"); | ||
547 | MODULE_DESCRIPTION("TIOCX module"); | ||
548 | MODULE_SUPPORTED_DEVICE(DEVICE_NAME); | ||
diff --git a/arch/ia64/sn/pci/Makefile b/arch/ia64/sn/pci/Makefile index b5dca0097a8e..2f915bce25f9 100644 --- a/arch/ia64/sn/pci/Makefile +++ b/arch/ia64/sn/pci/Makefile | |||
@@ -7,4 +7,4 @@ | |||
7 | # | 7 | # |
8 | # Makefile for the sn pci general routines. | 8 | # Makefile for the sn pci general routines. |
9 | 9 | ||
10 | obj-y := pci_dma.o pcibr/ | 10 | obj-y := pci_dma.o tioca_provider.o pcibr/ |
diff --git a/arch/ia64/sn/pci/pci_dma.c b/arch/ia64/sn/pci/pci_dma.c index f680824f819d..5da9bdbde7cb 100644 --- a/arch/ia64/sn/pci/pci_dma.c +++ b/arch/ia64/sn/pci/pci_dma.c | |||
@@ -12,9 +12,8 @@ | |||
12 | #include <linux/module.h> | 12 | #include <linux/module.h> |
13 | #include <asm/dma.h> | 13 | #include <asm/dma.h> |
14 | #include <asm/sn/sn_sal.h> | 14 | #include <asm/sn/sn_sal.h> |
15 | #include "pci/pcibus_provider_defs.h" | 15 | #include <asm/sn/pcibus_provider_defs.h> |
16 | #include "pci/pcidev.h" | 16 | #include <asm/sn/pcidev.h> |
17 | #include "pci/pcibr_provider.h" | ||
18 | 17 | ||
19 | #define SG_ENT_VIRT_ADDRESS(sg) (page_address((sg)->page) + (sg)->offset) | 18 | #define SG_ENT_VIRT_ADDRESS(sg) (page_address((sg)->page) + (sg)->offset) |
20 | #define SG_ENT_PHYS_ADDRESS(SG) virt_to_phys(SG_ENT_VIRT_ADDRESS(SG)) | 19 | #define SG_ENT_PHYS_ADDRESS(SG) virt_to_phys(SG_ENT_VIRT_ADDRESS(SG)) |
@@ -79,7 +78,8 @@ void *sn_dma_alloc_coherent(struct device *dev, size_t size, | |||
79 | { | 78 | { |
80 | void *cpuaddr; | 79 | void *cpuaddr; |
81 | unsigned long phys_addr; | 80 | unsigned long phys_addr; |
82 | struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(to_pci_dev(dev)); | 81 | struct pci_dev *pdev = to_pci_dev(dev); |
82 | struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev); | ||
83 | 83 | ||
84 | BUG_ON(dev->bus != &pci_bus_type); | 84 | BUG_ON(dev->bus != &pci_bus_type); |
85 | 85 | ||
@@ -102,8 +102,7 @@ void *sn_dma_alloc_coherent(struct device *dev, size_t size, | |||
102 | * resources. | 102 | * resources. |
103 | */ | 103 | */ |
104 | 104 | ||
105 | *dma_handle = pcibr_dma_map(pcidev_info, phys_addr, size, | 105 | *dma_handle = provider->dma_map_consistent(pdev, phys_addr, size); |
106 | SN_PCIDMA_CONSISTENT); | ||
107 | if (!*dma_handle) { | 106 | if (!*dma_handle) { |
108 | printk(KERN_ERR "%s: out of ATEs\n", __FUNCTION__); | 107 | printk(KERN_ERR "%s: out of ATEs\n", __FUNCTION__); |
109 | free_pages((unsigned long)cpuaddr, get_order(size)); | 108 | free_pages((unsigned long)cpuaddr, get_order(size)); |
@@ -127,11 +126,12 @@ EXPORT_SYMBOL(sn_dma_alloc_coherent); | |||
127 | void sn_dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, | 126 | void sn_dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, |
128 | dma_addr_t dma_handle) | 127 | dma_addr_t dma_handle) |
129 | { | 128 | { |
130 | struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(to_pci_dev(dev)); | 129 | struct pci_dev *pdev = to_pci_dev(dev); |
130 | struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev); | ||
131 | 131 | ||
132 | BUG_ON(dev->bus != &pci_bus_type); | 132 | BUG_ON(dev->bus != &pci_bus_type); |
133 | 133 | ||
134 | pcibr_dma_unmap(pcidev_info, dma_handle, 0); | 134 | provider->dma_unmap(pdev, dma_handle, 0); |
135 | free_pages((unsigned long)cpu_addr, get_order(size)); | 135 | free_pages((unsigned long)cpu_addr, get_order(size)); |
136 | } | 136 | } |
137 | EXPORT_SYMBOL(sn_dma_free_coherent); | 137 | EXPORT_SYMBOL(sn_dma_free_coherent); |
@@ -159,12 +159,13 @@ dma_addr_t sn_dma_map_single(struct device *dev, void *cpu_addr, size_t size, | |||
159 | { | 159 | { |
160 | dma_addr_t dma_addr; | 160 | dma_addr_t dma_addr; |
161 | unsigned long phys_addr; | 161 | unsigned long phys_addr; |
162 | struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(to_pci_dev(dev)); | 162 | struct pci_dev *pdev = to_pci_dev(dev); |
163 | struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev); | ||
163 | 164 | ||
164 | BUG_ON(dev->bus != &pci_bus_type); | 165 | BUG_ON(dev->bus != &pci_bus_type); |
165 | 166 | ||
166 | phys_addr = __pa(cpu_addr); | 167 | phys_addr = __pa(cpu_addr); |
167 | dma_addr = pcibr_dma_map(pcidev_info, phys_addr, size, 0); | 168 | dma_addr = provider->dma_map(pdev, phys_addr, size); |
168 | if (!dma_addr) { | 169 | if (!dma_addr) { |
169 | printk(KERN_ERR "%s: out of ATEs\n", __FUNCTION__); | 170 | printk(KERN_ERR "%s: out of ATEs\n", __FUNCTION__); |
170 | return 0; | 171 | return 0; |
@@ -187,10 +188,12 @@ EXPORT_SYMBOL(sn_dma_map_single); | |||
187 | void sn_dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, | 188 | void sn_dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, |
188 | int direction) | 189 | int direction) |
189 | { | 190 | { |
190 | struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(to_pci_dev(dev)); | 191 | struct pci_dev *pdev = to_pci_dev(dev); |
192 | struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev); | ||
191 | 193 | ||
192 | BUG_ON(dev->bus != &pci_bus_type); | 194 | BUG_ON(dev->bus != &pci_bus_type); |
193 | pcibr_dma_unmap(pcidev_info, dma_addr, direction); | 195 | |
196 | provider->dma_unmap(pdev, dma_addr, direction); | ||
194 | } | 197 | } |
195 | EXPORT_SYMBOL(sn_dma_unmap_single); | 198 | EXPORT_SYMBOL(sn_dma_unmap_single); |
196 | 199 | ||
@@ -207,12 +210,13 @@ void sn_dma_unmap_sg(struct device *dev, struct scatterlist *sg, | |||
207 | int nhwentries, int direction) | 210 | int nhwentries, int direction) |
208 | { | 211 | { |
209 | int i; | 212 | int i; |
210 | struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(to_pci_dev(dev)); | 213 | struct pci_dev *pdev = to_pci_dev(dev); |
214 | struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev); | ||
211 | 215 | ||
212 | BUG_ON(dev->bus != &pci_bus_type); | 216 | BUG_ON(dev->bus != &pci_bus_type); |
213 | 217 | ||
214 | for (i = 0; i < nhwentries; i++, sg++) { | 218 | for (i = 0; i < nhwentries; i++, sg++) { |
215 | pcibr_dma_unmap(pcidev_info, sg->dma_address, direction); | 219 | provider->dma_unmap(pdev, sg->dma_address, direction); |
216 | sg->dma_address = (dma_addr_t) NULL; | 220 | sg->dma_address = (dma_addr_t) NULL; |
217 | sg->dma_length = 0; | 221 | sg->dma_length = 0; |
218 | } | 222 | } |
@@ -233,7 +237,8 @@ int sn_dma_map_sg(struct device *dev, struct scatterlist *sg, int nhwentries, | |||
233 | { | 237 | { |
234 | unsigned long phys_addr; | 238 | unsigned long phys_addr; |
235 | struct scatterlist *saved_sg = sg; | 239 | struct scatterlist *saved_sg = sg; |
236 | struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(to_pci_dev(dev)); | 240 | struct pci_dev *pdev = to_pci_dev(dev); |
241 | struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev); | ||
237 | int i; | 242 | int i; |
238 | 243 | ||
239 | BUG_ON(dev->bus != &pci_bus_type); | 244 | BUG_ON(dev->bus != &pci_bus_type); |
@@ -243,8 +248,8 @@ int sn_dma_map_sg(struct device *dev, struct scatterlist *sg, int nhwentries, | |||
243 | */ | 248 | */ |
244 | for (i = 0; i < nhwentries; i++, sg++) { | 249 | for (i = 0; i < nhwentries; i++, sg++) { |
245 | phys_addr = SG_ENT_PHYS_ADDRESS(sg); | 250 | phys_addr = SG_ENT_PHYS_ADDRESS(sg); |
246 | sg->dma_address = pcibr_dma_map(pcidev_info, phys_addr, | 251 | sg->dma_address = provider->dma_map(pdev, |
247 | sg->length, 0); | 252 | phys_addr, sg->length); |
248 | 253 | ||
249 | if (!sg->dma_address) { | 254 | if (!sg->dma_address) { |
250 | printk(KERN_ERR "%s: out of ATEs\n", __FUNCTION__); | 255 | printk(KERN_ERR "%s: out of ATEs\n", __FUNCTION__); |
diff --git a/arch/ia64/sn/pci/pcibr/pcibr_ate.c b/arch/ia64/sn/pci/pcibr/pcibr_ate.c index 9d6854666f9b..0e47bce85f2d 100644 --- a/arch/ia64/sn/pci/pcibr/pcibr_ate.c +++ b/arch/ia64/sn/pci/pcibr/pcibr_ate.c | |||
@@ -8,8 +8,8 @@ | |||
8 | 8 | ||
9 | #include <linux/types.h> | 9 | #include <linux/types.h> |
10 | #include <asm/sn/sn_sal.h> | 10 | #include <asm/sn/sn_sal.h> |
11 | #include "pci/pcibus_provider_defs.h" | 11 | #include <asm/sn/pcibus_provider_defs.h> |
12 | #include "pci/pcidev.h" | 12 | #include <asm/sn/pcidev.h> |
13 | #include "pci/pcibr_provider.h" | 13 | #include "pci/pcibr_provider.h" |
14 | 14 | ||
15 | int pcibr_invalidate_ate = 0; /* by default don't invalidate ATE on free */ | 15 | int pcibr_invalidate_ate = 0; /* by default don't invalidate ATE on free */ |
diff --git a/arch/ia64/sn/pci/pcibr/pcibr_dma.c b/arch/ia64/sn/pci/pcibr/pcibr_dma.c index b1d66ac065c8..c90685985d81 100644 --- a/arch/ia64/sn/pci/pcibr/pcibr_dma.c +++ b/arch/ia64/sn/pci/pcibr/pcibr_dma.c | |||
@@ -12,8 +12,8 @@ | |||
12 | #include <asm/sn/geo.h> | 12 | #include <asm/sn/geo.h> |
13 | #include "xtalk/xwidgetdev.h" | 13 | #include "xtalk/xwidgetdev.h" |
14 | #include "xtalk/hubdev.h" | 14 | #include "xtalk/hubdev.h" |
15 | #include "pci/pcibus_provider_defs.h" | 15 | #include <asm/sn/pcibus_provider_defs.h> |
16 | #include "pci/pcidev.h" | 16 | #include <asm/sn/pcidev.h> |
17 | #include "pci/tiocp.h" | 17 | #include "pci/tiocp.h" |
18 | #include "pci/pic.h" | 18 | #include "pci/pic.h" |
19 | #include "pci/pcibr_provider.h" | 19 | #include "pci/pcibr_provider.h" |
@@ -40,7 +40,7 @@ extern int sn_ioif_inited; | |||
40 | * we do not have to allocate entries in the PMU. | 40 | * we do not have to allocate entries in the PMU. |
41 | */ | 41 | */ |
42 | 42 | ||
43 | static uint64_t | 43 | static dma_addr_t |
44 | pcibr_dmamap_ate32(struct pcidev_info *info, | 44 | pcibr_dmamap_ate32(struct pcidev_info *info, |
45 | uint64_t paddr, size_t req_size, uint64_t flags) | 45 | uint64_t paddr, size_t req_size, uint64_t flags) |
46 | { | 46 | { |
@@ -109,7 +109,7 @@ pcibr_dmamap_ate32(struct pcidev_info *info, | |||
109 | return pci_addr; | 109 | return pci_addr; |
110 | } | 110 | } |
111 | 111 | ||
112 | static uint64_t | 112 | static dma_addr_t |
113 | pcibr_dmatrans_direct64(struct pcidev_info * info, uint64_t paddr, | 113 | pcibr_dmatrans_direct64(struct pcidev_info * info, uint64_t paddr, |
114 | uint64_t dma_attributes) | 114 | uint64_t dma_attributes) |
115 | { | 115 | { |
@@ -141,7 +141,7 @@ pcibr_dmatrans_direct64(struct pcidev_info * info, uint64_t paddr, | |||
141 | 141 | ||
142 | } | 142 | } |
143 | 143 | ||
144 | static uint64_t | 144 | static dma_addr_t |
145 | pcibr_dmatrans_direct32(struct pcidev_info * info, | 145 | pcibr_dmatrans_direct32(struct pcidev_info * info, |
146 | uint64_t paddr, size_t req_size, uint64_t flags) | 146 | uint64_t paddr, size_t req_size, uint64_t flags) |
147 | { | 147 | { |
@@ -180,11 +180,11 @@ pcibr_dmatrans_direct32(struct pcidev_info * info, | |||
180 | * DMA mappings for Direct 64 and 32 do not have any DMA maps. | 180 | * DMA mappings for Direct 64 and 32 do not have any DMA maps. |
181 | */ | 181 | */ |
182 | void | 182 | void |
183 | pcibr_dma_unmap(struct pcidev_info *pcidev_info, dma_addr_t dma_handle, | 183 | pcibr_dma_unmap(struct pci_dev *hwdev, dma_addr_t dma_handle, int direction) |
184 | int direction) | ||
185 | { | 184 | { |
186 | struct pcibus_info *pcibus_info = (struct pcibus_info *)pcidev_info-> | 185 | struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(hwdev); |
187 | pdi_pcibus_info; | 186 | struct pcibus_info *pcibus_info = |
187 | (struct pcibus_info *)pcidev_info->pdi_pcibus_info; | ||
188 | 188 | ||
189 | if (IS_PCI32_MAPPED(dma_handle)) { | 189 | if (IS_PCI32_MAPPED(dma_handle)) { |
190 | int ate_index; | 190 | int ate_index; |
@@ -316,64 +316,63 @@ void sn_dma_flush(uint64_t addr) | |||
316 | } | 316 | } |
317 | 317 | ||
318 | /* | 318 | /* |
319 | * Wrapper DMA interface. Called from pci_dma.c routines. | 319 | * DMA interfaces. Called from pci_dma.c routines. |
320 | */ | 320 | */ |
321 | 321 | ||
322 | uint64_t | 322 | dma_addr_t |
323 | pcibr_dma_map(struct pcidev_info * pcidev_info, unsigned long phys_addr, | 323 | pcibr_dma_map(struct pci_dev * hwdev, unsigned long phys_addr, size_t size) |
324 | size_t size, unsigned int flags) | ||
325 | { | 324 | { |
326 | dma_addr_t dma_handle; | 325 | dma_addr_t dma_handle; |
327 | struct pci_dev *pcidev = pcidev_info->pdi_linux_pcidev; | 326 | struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(hwdev); |
328 | |||
329 | if (flags & SN_PCIDMA_CONSISTENT) { | ||
330 | /* sn_pci_alloc_consistent interfaces */ | ||
331 | if (pcidev->dev.coherent_dma_mask == ~0UL) { | ||
332 | dma_handle = | ||
333 | pcibr_dmatrans_direct64(pcidev_info, phys_addr, | ||
334 | PCI64_ATTR_BAR); | ||
335 | } else { | ||
336 | dma_handle = | ||
337 | (dma_addr_t) pcibr_dmamap_ate32(pcidev_info, | ||
338 | phys_addr, size, | ||
339 | PCI32_ATE_BAR); | ||
340 | } | ||
341 | } else { | ||
342 | /* map_sg/map_single interfaces */ | ||
343 | 327 | ||
344 | /* SN cannot support DMA addresses smaller than 32 bits. */ | 328 | /* SN cannot support DMA addresses smaller than 32 bits. */ |
345 | if (pcidev->dma_mask < 0x7fffffff) { | 329 | if (hwdev->dma_mask < 0x7fffffff) { |
346 | return 0; | 330 | return 0; |
347 | } | 331 | } |
348 | 332 | ||
349 | if (pcidev->dma_mask == ~0UL) { | 333 | if (hwdev->dma_mask == ~0UL) { |
334 | /* | ||
335 | * Handle the most common case: 64 bit cards. This | ||
336 | * call should always succeed. | ||
337 | */ | ||
338 | |||
339 | dma_handle = pcibr_dmatrans_direct64(pcidev_info, phys_addr, | ||
340 | PCI64_ATTR_PREF); | ||
341 | } else { | ||
342 | /* Handle 32-63 bit cards via direct mapping */ | ||
343 | dma_handle = pcibr_dmatrans_direct32(pcidev_info, phys_addr, | ||
344 | size, 0); | ||
345 | if (!dma_handle) { | ||
350 | /* | 346 | /* |
351 | * Handle the most common case: 64 bit cards. This | 347 | * It is a 32 bit card and we cannot do direct mapping, |
352 | * call should always succeed. | 348 | * so we use an ATE. |
353 | */ | 349 | */ |
354 | 350 | ||
355 | dma_handle = | 351 | dma_handle = pcibr_dmamap_ate32(pcidev_info, phys_addr, |
356 | pcibr_dmatrans_direct64(pcidev_info, phys_addr, | 352 | size, PCI32_ATE_PREF); |
357 | PCI64_ATTR_PREF); | ||
358 | } else { | ||
359 | /* Handle 32-63 bit cards via direct mapping */ | ||
360 | dma_handle = | ||
361 | pcibr_dmatrans_direct32(pcidev_info, phys_addr, | ||
362 | size, 0); | ||
363 | if (!dma_handle) { | ||
364 | /* | ||
365 | * It is a 32 bit card and we cannot do direct mapping, | ||
366 | * so we use an ATE. | ||
367 | */ | ||
368 | |||
369 | dma_handle = | ||
370 | pcibr_dmamap_ate32(pcidev_info, phys_addr, | ||
371 | size, PCI32_ATE_PREF); | ||
372 | } | ||
373 | } | 353 | } |
374 | } | 354 | } |
375 | 355 | ||
376 | return dma_handle; | 356 | return dma_handle; |
377 | } | 357 | } |
378 | 358 | ||
359 | dma_addr_t | ||
360 | pcibr_dma_map_consistent(struct pci_dev * hwdev, unsigned long phys_addr, | ||
361 | size_t size) | ||
362 | { | ||
363 | dma_addr_t dma_handle; | ||
364 | struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(hwdev); | ||
365 | |||
366 | if (hwdev->dev.coherent_dma_mask == ~0UL) { | ||
367 | dma_handle = pcibr_dmatrans_direct64(pcidev_info, phys_addr, | ||
368 | PCI64_ATTR_BAR); | ||
369 | } else { | ||
370 | dma_handle = (dma_addr_t) pcibr_dmamap_ate32(pcidev_info, | ||
371 | phys_addr, size, | ||
372 | PCI32_ATE_BAR); | ||
373 | } | ||
374 | |||
375 | return dma_handle; | ||
376 | } | ||
377 | |||
379 | EXPORT_SYMBOL(sn_dma_flush); | 378 | EXPORT_SYMBOL(sn_dma_flush); |
diff --git a/arch/ia64/sn/pci/pcibr/pcibr_provider.c b/arch/ia64/sn/pci/pcibr/pcibr_provider.c index 92bd278cf7ff..3893999d23d8 100644 --- a/arch/ia64/sn/pci/pcibr/pcibr_provider.c +++ b/arch/ia64/sn/pci/pcibr/pcibr_provider.c | |||
@@ -13,8 +13,8 @@ | |||
13 | #include "xtalk/xwidgetdev.h" | 13 | #include "xtalk/xwidgetdev.h" |
14 | #include <asm/sn/geo.h> | 14 | #include <asm/sn/geo.h> |
15 | #include "xtalk/hubdev.h" | 15 | #include "xtalk/hubdev.h" |
16 | #include "pci/pcibus_provider_defs.h" | 16 | #include <asm/sn/pcibus_provider_defs.h> |
17 | #include "pci/pcidev.h" | 17 | #include <asm/sn/pcidev.h> |
18 | #include "pci/pcibr_provider.h" | 18 | #include "pci/pcibr_provider.h" |
19 | #include <asm/sn/addrs.h> | 19 | #include <asm/sn/addrs.h> |
20 | 20 | ||
@@ -168,3 +168,23 @@ void pcibr_change_devices_irq(struct sn_irq_info *sn_irq_info) | |||
168 | pcibr_force_interrupt(sn_irq_info); | 168 | pcibr_force_interrupt(sn_irq_info); |
169 | } | 169 | } |
170 | } | 170 | } |
171 | |||
172 | /* | ||
173 | * Provider entries for PIC/CP | ||
174 | */ | ||
175 | |||
176 | struct sn_pcibus_provider pcibr_provider = { | ||
177 | .dma_map = pcibr_dma_map, | ||
178 | .dma_map_consistent = pcibr_dma_map_consistent, | ||
179 | .dma_unmap = pcibr_dma_unmap, | ||
180 | .bus_fixup = pcibr_bus_fixup, | ||
181 | }; | ||
182 | |||
183 | int | ||
184 | pcibr_init_provider(void) | ||
185 | { | ||
186 | sn_pci_provider[PCIIO_ASIC_TYPE_PIC] = &pcibr_provider; | ||
187 | sn_pci_provider[PCIIO_ASIC_TYPE_TIOCP] = &pcibr_provider; | ||
188 | |||
189 | return 0; | ||
190 | } | ||
diff --git a/arch/ia64/sn/pci/pcibr/pcibr_reg.c b/arch/ia64/sn/pci/pcibr/pcibr_reg.c index 74a74a7d2a13..865c11c3b50a 100644 --- a/arch/ia64/sn/pci/pcibr/pcibr_reg.c +++ b/arch/ia64/sn/pci/pcibr/pcibr_reg.c | |||
@@ -8,8 +8,8 @@ | |||
8 | 8 | ||
9 | #include <linux/types.h> | 9 | #include <linux/types.h> |
10 | #include <linux/interrupt.h> | 10 | #include <linux/interrupt.h> |
11 | #include "pci/pcibus_provider_defs.h" | 11 | #include <asm/sn/pcibus_provider_defs.h> |
12 | #include "pci/pcidev.h" | 12 | #include <asm/sn/pcidev.h> |
13 | #include "pci/tiocp.h" | 13 | #include "pci/tiocp.h" |
14 | #include "pci/pic.h" | 14 | #include "pci/pic.h" |
15 | #include "pci/pcibr_provider.h" | 15 | #include "pci/pcibr_provider.h" |
diff --git a/arch/ia64/sn/pci/tioca_provider.c b/arch/ia64/sn/pci/tioca_provider.c new file mode 100644 index 000000000000..54a0dd447e76 --- /dev/null +++ b/arch/ia64/sn/pci/tioca_provider.c | |||
@@ -0,0 +1,668 @@ | |||
1 | /* | ||
2 | * This file is subject to the terms and conditions of the GNU General Public | ||
3 | * License. See the file "COPYING" in the main directory of this archive | ||
4 | * for more details. | ||
5 | * | ||
6 | * Copyright (C) 2003-2005 Silicon Graphics, Inc. All Rights Reserved. | ||
7 | */ | ||
8 | |||
9 | #include <linux/types.h> | ||
10 | #include <linux/interrupt.h> | ||
11 | #include <linux/pci.h> | ||
12 | #include <asm/sn/sn_sal.h> | ||
13 | #include <asm/sn/addrs.h> | ||
14 | #include <asm/sn/pcidev.h> | ||
15 | #include <asm/sn/pcibus_provider_defs.h> | ||
16 | #include <asm/sn/tioca_provider.h> | ||
17 | |||
18 | uint32_t tioca_gart_found; | ||
19 | EXPORT_SYMBOL(tioca_gart_found); /* used by agp-sgi */ | ||
20 | |||
21 | LIST_HEAD(tioca_list); | ||
22 | EXPORT_SYMBOL(tioca_list); /* used by agp-sgi */ | ||
23 | |||
24 | static int tioca_gart_init(struct tioca_kernel *); | ||
25 | |||
26 | /** | ||
27 | * tioca_gart_init - Initialize SGI TIOCA GART | ||
28 | * @tioca_common: ptr to common prom/kernel struct identifying the | ||
29 | * | ||
30 | * If the indicated tioca has devices present, initialize its associated | ||
31 | * GART MMR's and kernel memory. | ||
32 | */ | ||
33 | static int | ||
34 | tioca_gart_init(struct tioca_kernel *tioca_kern) | ||
35 | { | ||
36 | uint64_t ap_reg; | ||
37 | uint64_t offset; | ||
38 | struct page *tmp; | ||
39 | struct tioca_common *tioca_common; | ||
40 | volatile struct tioca *ca_base; | ||
41 | |||
42 | tioca_common = tioca_kern->ca_common; | ||
43 | ca_base = (struct tioca *)tioca_common->ca_common.bs_base; | ||
44 | |||
45 | if (list_empty(tioca_kern->ca_devices)) | ||
46 | return 0; | ||
47 | |||
48 | ap_reg = 0; | ||
49 | |||
50 | /* | ||
51 | * Validate aperature size | ||
52 | */ | ||
53 | |||
54 | switch (CA_APERATURE_SIZE >> 20) { | ||
55 | case 4: | ||
56 | ap_reg |= (0x3ff << CA_GART_AP_SIZE_SHFT); /* 4MB */ | ||
57 | break; | ||
58 | case 8: | ||
59 | ap_reg |= (0x3fe << CA_GART_AP_SIZE_SHFT); /* 8MB */ | ||
60 | break; | ||
61 | case 16: | ||
62 | ap_reg |= (0x3fc << CA_GART_AP_SIZE_SHFT); /* 16MB */ | ||
63 | break; | ||
64 | case 32: | ||
65 | ap_reg |= (0x3f8 << CA_GART_AP_SIZE_SHFT); /* 32 MB */ | ||
66 | break; | ||
67 | case 64: | ||
68 | ap_reg |= (0x3f0 << CA_GART_AP_SIZE_SHFT); /* 64 MB */ | ||
69 | break; | ||
70 | case 128: | ||
71 | ap_reg |= (0x3e0 << CA_GART_AP_SIZE_SHFT); /* 128 MB */ | ||
72 | break; | ||
73 | case 256: | ||
74 | ap_reg |= (0x3c0 << CA_GART_AP_SIZE_SHFT); /* 256 MB */ | ||
75 | break; | ||
76 | case 512: | ||
77 | ap_reg |= (0x380 << CA_GART_AP_SIZE_SHFT); /* 512 MB */ | ||
78 | break; | ||
79 | case 1024: | ||
80 | ap_reg |= (0x300 << CA_GART_AP_SIZE_SHFT); /* 1GB */ | ||
81 | break; | ||
82 | case 2048: | ||
83 | ap_reg |= (0x200 << CA_GART_AP_SIZE_SHFT); /* 2GB */ | ||
84 | break; | ||
85 | case 4096: | ||
86 | ap_reg |= (0x000 << CA_GART_AP_SIZE_SHFT); /* 4 GB */ | ||
87 | break; | ||
88 | default: | ||
89 | printk(KERN_ERR "%s: Invalid CA_APERATURE_SIZE " | ||
90 | "0x%lx\n", __FUNCTION__, (ulong) CA_APERATURE_SIZE); | ||
91 | return -1; | ||
92 | } | ||
93 | |||
94 | /* | ||
95 | * Set up other aperature parameters | ||
96 | */ | ||
97 | |||
98 | if (PAGE_SIZE >= 16384) { | ||
99 | tioca_kern->ca_ap_pagesize = 16384; | ||
100 | ap_reg |= CA_GART_PAGE_SIZE; | ||
101 | } else { | ||
102 | tioca_kern->ca_ap_pagesize = 4096; | ||
103 | } | ||
104 | |||
105 | tioca_kern->ca_ap_size = CA_APERATURE_SIZE; | ||
106 | tioca_kern->ca_ap_bus_base = CA_APERATURE_BASE; | ||
107 | tioca_kern->ca_gart_entries = | ||
108 | tioca_kern->ca_ap_size / tioca_kern->ca_ap_pagesize; | ||
109 | |||
110 | ap_reg |= (CA_GART_AP_ENB_AGP | CA_GART_AP_ENB_PCI); | ||
111 | ap_reg |= tioca_kern->ca_ap_bus_base; | ||
112 | |||
113 | /* | ||
114 | * Allocate and set up the GART | ||
115 | */ | ||
116 | |||
117 | tioca_kern->ca_gart_size = tioca_kern->ca_gart_entries * sizeof(u64); | ||
118 | tmp = | ||
119 | alloc_pages_node(tioca_kern->ca_closest_node, | ||
120 | GFP_KERNEL | __GFP_ZERO, | ||
121 | get_order(tioca_kern->ca_gart_size)); | ||
122 | |||
123 | if (!tmp) { | ||
124 | printk(KERN_ERR "%s: Could not allocate " | ||
125 | "%lu bytes (order %d) for GART\n", | ||
126 | __FUNCTION__, | ||
127 | tioca_kern->ca_gart_size, | ||
128 | get_order(tioca_kern->ca_gart_size)); | ||
129 | return -ENOMEM; | ||
130 | } | ||
131 | |||
132 | tioca_kern->ca_gart = page_address(tmp); | ||
133 | tioca_kern->ca_gart_coretalk_addr = | ||
134 | PHYS_TO_TIODMA(virt_to_phys(tioca_kern->ca_gart)); | ||
135 | |||
136 | /* | ||
137 | * Compute PCI/AGP convenience fields | ||
138 | */ | ||
139 | |||
140 | offset = CA_PCI32_MAPPED_BASE - CA_APERATURE_BASE; | ||
141 | tioca_kern->ca_pciap_base = CA_PCI32_MAPPED_BASE; | ||
142 | tioca_kern->ca_pciap_size = CA_PCI32_MAPPED_SIZE; | ||
143 | tioca_kern->ca_pcigart_start = offset / tioca_kern->ca_ap_pagesize; | ||
144 | tioca_kern->ca_pcigart_base = | ||
145 | tioca_kern->ca_gart_coretalk_addr + offset; | ||
146 | tioca_kern->ca_pcigart = | ||
147 | &tioca_kern->ca_gart[tioca_kern->ca_pcigart_start]; | ||
148 | tioca_kern->ca_pcigart_entries = | ||
149 | tioca_kern->ca_pciap_size / tioca_kern->ca_ap_pagesize; | ||
150 | tioca_kern->ca_pcigart_pagemap = | ||
151 | kcalloc(1, tioca_kern->ca_pcigart_entries / 8, GFP_KERNEL); | ||
152 | if (!tioca_kern->ca_pcigart_pagemap) { | ||
153 | free_pages((unsigned long)tioca_kern->ca_gart, | ||
154 | get_order(tioca_kern->ca_gart_size)); | ||
155 | return -1; | ||
156 | } | ||
157 | |||
158 | offset = CA_AGP_MAPPED_BASE - CA_APERATURE_BASE; | ||
159 | tioca_kern->ca_gfxap_base = CA_AGP_MAPPED_BASE; | ||
160 | tioca_kern->ca_gfxap_size = CA_AGP_MAPPED_SIZE; | ||
161 | tioca_kern->ca_gfxgart_start = offset / tioca_kern->ca_ap_pagesize; | ||
162 | tioca_kern->ca_gfxgart_base = | ||
163 | tioca_kern->ca_gart_coretalk_addr + offset; | ||
164 | tioca_kern->ca_gfxgart = | ||
165 | &tioca_kern->ca_gart[tioca_kern->ca_gfxgart_start]; | ||
166 | tioca_kern->ca_gfxgart_entries = | ||
167 | tioca_kern->ca_gfxap_size / tioca_kern->ca_ap_pagesize; | ||
168 | |||
169 | /* | ||
170 | * various control settings: | ||
171 | * use agp op-combining | ||
172 | * use GET semantics to fetch memory | ||
173 | * participate in coherency domain | ||
174 | * DISABLE GART PREFETCHING due to hw bug tracked in SGI PV930029 | ||
175 | */ | ||
176 | |||
177 | ca_base->ca_control1 |= CA_AGPDMA_OP_ENB_COMBDELAY; /* PV895469 ? */ | ||
178 | ca_base->ca_control2 &= ~(CA_GART_MEM_PARAM); | ||
179 | ca_base->ca_control2 |= (0x2ull << CA_GART_MEM_PARAM_SHFT); | ||
180 | tioca_kern->ca_gart_iscoherent = 1; | ||
181 | ca_base->ca_control2 &= | ||
182 | ~(CA_GART_WR_PREFETCH_ENB | CA_GART_RD_PREFETCH_ENB); | ||
183 | |||
184 | /* | ||
185 | * Unmask GART fetch error interrupts. Clear residual errors first. | ||
186 | */ | ||
187 | |||
188 | ca_base->ca_int_status_alias = CA_GART_FETCH_ERR; | ||
189 | ca_base->ca_mult_error_alias = CA_GART_FETCH_ERR; | ||
190 | ca_base->ca_int_mask &= ~CA_GART_FETCH_ERR; | ||
191 | |||
192 | /* | ||
193 | * Program the aperature and gart registers in TIOCA | ||
194 | */ | ||
195 | |||
196 | ca_base->ca_gart_aperature = ap_reg; | ||
197 | ca_base->ca_gart_ptr_table = tioca_kern->ca_gart_coretalk_addr | 1; | ||
198 | |||
199 | return 0; | ||
200 | } | ||
201 | |||
202 | /** | ||
203 | * tioca_fastwrite_enable - enable AGP FW for a tioca and its functions | ||
204 | * @tioca_kernel: structure representing the CA | ||
205 | * | ||
206 | * Given a CA, scan all attached functions making sure they all support | ||
207 | * FastWrite. If so, enable FastWrite for all functions and the CA itself. | ||
208 | */ | ||
209 | |||
210 | void | ||
211 | tioca_fastwrite_enable(struct tioca_kernel *tioca_kern) | ||
212 | { | ||
213 | int cap_ptr; | ||
214 | uint64_t ca_control1; | ||
215 | uint32_t reg; | ||
216 | struct tioca *tioca_base; | ||
217 | struct pci_dev *pdev; | ||
218 | struct tioca_common *common; | ||
219 | |||
220 | common = tioca_kern->ca_common; | ||
221 | |||
222 | /* | ||
223 | * Scan all vga controllers on this bus making sure they all | ||
224 | * suport FW. If not, return. | ||
225 | */ | ||
226 | |||
227 | list_for_each_entry(pdev, tioca_kern->ca_devices, bus_list) { | ||
228 | if (pdev->class != (PCI_CLASS_DISPLAY_VGA << 8)) | ||
229 | continue; | ||
230 | |||
231 | cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP); | ||
232 | if (!cap_ptr) | ||
233 | return; /* no AGP CAP means no FW */ | ||
234 | |||
235 | pci_read_config_dword(pdev, cap_ptr + PCI_AGP_STATUS, ®); | ||
236 | if (!(reg & PCI_AGP_STATUS_FW)) | ||
237 | return; /* function doesn't support FW */ | ||
238 | } | ||
239 | |||
240 | /* | ||
241 | * Set fw for all vga fn's | ||
242 | */ | ||
243 | |||
244 | list_for_each_entry(pdev, tioca_kern->ca_devices, bus_list) { | ||
245 | if (pdev->class != (PCI_CLASS_DISPLAY_VGA << 8)) | ||
246 | continue; | ||
247 | |||
248 | cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP); | ||
249 | pci_read_config_dword(pdev, cap_ptr + PCI_AGP_COMMAND, ®); | ||
250 | reg |= PCI_AGP_COMMAND_FW; | ||
251 | pci_write_config_dword(pdev, cap_ptr + PCI_AGP_COMMAND, reg); | ||
252 | } | ||
253 | |||
254 | /* | ||
255 | * Set ca's fw to match | ||
256 | */ | ||
257 | |||
258 | tioca_base = (struct tioca *)common->ca_common.bs_base; | ||
259 | ca_control1 = tioca_base->ca_control1; | ||
260 | ca_control1 |= CA_AGP_FW_ENABLE; | ||
261 | tioca_base->ca_control1 = ca_control1; | ||
262 | } | ||
263 | |||
264 | EXPORT_SYMBOL(tioca_fastwrite_enable); /* used by agp-sgi */ | ||
265 | |||
266 | /** | ||
267 | * tioca_dma_d64 - create a DMA mapping using 64-bit direct mode | ||
268 | * @paddr: system physical address | ||
269 | * | ||
270 | * Map @paddr into 64-bit CA bus space. No device context is necessary. | ||
271 | * Bits 53:0 come from the coretalk address. We just need to mask in the | ||
272 | * following optional bits of the 64-bit pci address: | ||
273 | * | ||
274 | * 63:60 - Coretalk Packet Type - 0x1 for Mem Get/Put (coherent) | ||
275 | * 0x2 for PIO (non-coherent) | ||
276 | * We will always use 0x1 | ||
277 | * 55:55 - Swap bytes Currently unused | ||
278 | */ | ||
279 | static uint64_t | ||
280 | tioca_dma_d64(unsigned long paddr) | ||
281 | { | ||
282 | dma_addr_t bus_addr; | ||
283 | |||
284 | bus_addr = PHYS_TO_TIODMA(paddr); | ||
285 | |||
286 | BUG_ON(!bus_addr); | ||
287 | BUG_ON(bus_addr >> 54); | ||
288 | |||
289 | /* Set upper nibble to Cache Coherent Memory op */ | ||
290 | bus_addr |= (1UL << 60); | ||
291 | |||
292 | return bus_addr; | ||
293 | } | ||
294 | |||
295 | /** | ||
296 | * tioca_dma_d48 - create a DMA mapping using 48-bit direct mode | ||
297 | * @pdev: linux pci_dev representing the function | ||
298 | * @paddr: system physical address | ||
299 | * | ||
300 | * Map @paddr into 64-bit bus space of the CA associated with @pcidev_info. | ||
301 | * | ||
302 | * The CA agp 48 bit direct address falls out as follows: | ||
303 | * | ||
304 | * When direct mapping AGP addresses, the 48 bit AGP address is | ||
305 | * constructed as follows: | ||
306 | * | ||
307 | * [47:40] - Low 8 bits of the page Node ID extracted from coretalk | ||
308 | * address [47:40]. The upper 8 node bits are fixed | ||
309 | * and come from the xxx register bits [5:0] | ||
310 | * [39:38] - Chiplet ID extracted from coretalk address [39:38] | ||
311 | * [37:00] - node offset extracted from coretalk address [37:00] | ||
312 | * | ||
313 | * Since the node id in general will be non-zero, and the chiplet id | ||
314 | * will always be non-zero, it follows that the device must support | ||
315 | * a dma mask of at least 0xffffffffff (40 bits) to target node 0 | ||
316 | * and in general should be 0xffffffffffff (48 bits) to target nodes | ||
317 | * up to 255. Nodes above 255 need the support of the xxx register, | ||
318 | * and so a given CA can only directly target nodes in the range | ||
319 | * xxx - xxx+255. | ||
320 | */ | ||
321 | static uint64_t | ||
322 | tioca_dma_d48(struct pci_dev *pdev, uint64_t paddr) | ||
323 | { | ||
324 | struct tioca_common *tioca_common; | ||
325 | struct tioca *ca_base; | ||
326 | uint64_t ct_addr; | ||
327 | dma_addr_t bus_addr; | ||
328 | uint32_t node_upper; | ||
329 | uint64_t agp_dma_extn; | ||
330 | struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(pdev); | ||
331 | |||
332 | tioca_common = (struct tioca_common *)pcidev_info->pdi_pcibus_info; | ||
333 | ca_base = (struct tioca *)tioca_common->ca_common.bs_base; | ||
334 | |||
335 | ct_addr = PHYS_TO_TIODMA(paddr); | ||
336 | if (!ct_addr) | ||
337 | return 0; | ||
338 | |||
339 | bus_addr = (dma_addr_t) (ct_addr & 0xffffffffffff); | ||
340 | node_upper = ct_addr >> 48; | ||
341 | |||
342 | if (node_upper > 64) { | ||
343 | printk(KERN_ERR "%s: coretalk addr 0x%p node id out " | ||
344 | "of range\n", __FUNCTION__, (void *)ct_addr); | ||
345 | return 0; | ||
346 | } | ||
347 | |||
348 | agp_dma_extn = ca_base->ca_agp_dma_addr_extn; | ||
349 | if (node_upper != (agp_dma_extn >> CA_AGP_DMA_NODE_ID_SHFT)) { | ||
350 | printk(KERN_ERR "%s: coretalk upper node (%u) " | ||
351 | "mismatch with ca_agp_dma_addr_extn (%lu)\n", | ||
352 | __FUNCTION__, | ||
353 | node_upper, (agp_dma_extn >> CA_AGP_DMA_NODE_ID_SHFT)); | ||
354 | return 0; | ||
355 | } | ||
356 | |||
357 | return bus_addr; | ||
358 | } | ||
359 | |||
360 | /** | ||
361 | * tioca_dma_mapped - create a DMA mapping using a CA GART | ||
362 | * @pdev: linux pci_dev representing the function | ||
363 | * @paddr: host physical address to map | ||
364 | * @req_size: len (bytes) to map | ||
365 | * | ||
366 | * Map @paddr into CA address space using the GART mechanism. The mapped | ||
367 | * dma_addr_t is guarenteed to be contiguous in CA bus space. | ||
368 | */ | ||
369 | static dma_addr_t | ||
370 | tioca_dma_mapped(struct pci_dev *pdev, uint64_t paddr, size_t req_size) | ||
371 | { | ||
372 | int i, ps, ps_shift, entry, entries, mapsize, last_entry; | ||
373 | uint64_t xio_addr, end_xio_addr; | ||
374 | struct tioca_common *tioca_common; | ||
375 | struct tioca_kernel *tioca_kern; | ||
376 | dma_addr_t bus_addr = 0; | ||
377 | struct tioca_dmamap *ca_dmamap; | ||
378 | void *map; | ||
379 | unsigned long flags; | ||
380 | struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(pdev);; | ||
381 | |||
382 | tioca_common = (struct tioca_common *)pcidev_info->pdi_pcibus_info; | ||
383 | tioca_kern = (struct tioca_kernel *)tioca_common->ca_kernel_private; | ||
384 | |||
385 | xio_addr = PHYS_TO_TIODMA(paddr); | ||
386 | if (!xio_addr) | ||
387 | return 0; | ||
388 | |||
389 | spin_lock_irqsave(&tioca_kern->ca_lock, flags); | ||
390 | |||
391 | /* | ||
392 | * allocate a map struct | ||
393 | */ | ||
394 | |||
395 | ca_dmamap = kcalloc(1, sizeof(struct tioca_dmamap), GFP_ATOMIC); | ||
396 | if (!ca_dmamap) | ||
397 | goto map_return; | ||
398 | |||
399 | /* | ||
400 | * Locate free entries that can hold req_size. Account for | ||
401 | * unaligned start/length when allocating. | ||
402 | */ | ||
403 | |||
404 | ps = tioca_kern->ca_ap_pagesize; /* will be power of 2 */ | ||
405 | ps_shift = ffs(ps) - 1; | ||
406 | end_xio_addr = xio_addr + req_size - 1; | ||
407 | |||
408 | entries = (end_xio_addr >> ps_shift) - (xio_addr >> ps_shift) + 1; | ||
409 | |||
410 | map = tioca_kern->ca_pcigart_pagemap; | ||
411 | mapsize = tioca_kern->ca_pcigart_entries; | ||
412 | |||
413 | entry = find_first_zero_bit(map, mapsize); | ||
414 | while (entry < mapsize) { | ||
415 | last_entry = find_next_bit(map, mapsize, entry); | ||
416 | |||
417 | if (last_entry - entry >= entries) | ||
418 | break; | ||
419 | |||
420 | entry = find_next_zero_bit(map, mapsize, last_entry); | ||
421 | } | ||
422 | |||
423 | if (entry > mapsize) | ||
424 | goto map_return; | ||
425 | |||
426 | for (i = 0; i < entries; i++) | ||
427 | set_bit(entry + i, map); | ||
428 | |||
429 | bus_addr = tioca_kern->ca_pciap_base + (entry * ps); | ||
430 | |||
431 | ca_dmamap->cad_dma_addr = bus_addr; | ||
432 | ca_dmamap->cad_gart_size = entries; | ||
433 | ca_dmamap->cad_gart_entry = entry; | ||
434 | list_add(&ca_dmamap->cad_list, &tioca_kern->ca_list); | ||
435 | |||
436 | if (xio_addr % ps) { | ||
437 | tioca_kern->ca_pcigart[entry] = tioca_paddr_to_gart(xio_addr); | ||
438 | bus_addr += xio_addr & (ps - 1); | ||
439 | xio_addr &= ~(ps - 1); | ||
440 | xio_addr += ps; | ||
441 | entry++; | ||
442 | } | ||
443 | |||
444 | while (xio_addr < end_xio_addr) { | ||
445 | tioca_kern->ca_pcigart[entry] = tioca_paddr_to_gart(xio_addr); | ||
446 | xio_addr += ps; | ||
447 | entry++; | ||
448 | } | ||
449 | |||
450 | tioca_tlbflush(tioca_kern); | ||
451 | |||
452 | map_return: | ||
453 | spin_unlock_irqrestore(&tioca_kern->ca_lock, flags); | ||
454 | return bus_addr; | ||
455 | } | ||
456 | |||
457 | /** | ||
458 | * tioca_dma_unmap - release CA mapping resources | ||
459 | * @pdev: linux pci_dev representing the function | ||
460 | * @bus_addr: bus address returned by an earlier tioca_dma_map | ||
461 | * @dir: mapping direction (unused) | ||
462 | * | ||
463 | * Locate mapping resources associated with @bus_addr and release them. | ||
464 | * For mappings created using the direct modes (64 or 48) there are no | ||
465 | * resources to release. | ||
466 | */ | ||
467 | void | ||
468 | tioca_dma_unmap(struct pci_dev *pdev, dma_addr_t bus_addr, int dir) | ||
469 | { | ||
470 | int i, entry; | ||
471 | struct tioca_common *tioca_common; | ||
472 | struct tioca_kernel *tioca_kern; | ||
473 | struct tioca_dmamap *map; | ||
474 | struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(pdev); | ||
475 | unsigned long flags; | ||
476 | |||
477 | tioca_common = (struct tioca_common *)pcidev_info->pdi_pcibus_info; | ||
478 | tioca_kern = (struct tioca_kernel *)tioca_common->ca_kernel_private; | ||
479 | |||
480 | /* return straight away if this isn't be a mapped address */ | ||
481 | |||
482 | if (bus_addr < tioca_kern->ca_pciap_base || | ||
483 | bus_addr >= (tioca_kern->ca_pciap_base + tioca_kern->ca_pciap_size)) | ||
484 | return; | ||
485 | |||
486 | spin_lock_irqsave(&tioca_kern->ca_lock, flags); | ||
487 | |||
488 | list_for_each_entry(map, &tioca_kern->ca_dmamaps, cad_list) | ||
489 | if (map->cad_dma_addr == bus_addr) | ||
490 | break; | ||
491 | |||
492 | BUG_ON(map == NULL); | ||
493 | |||
494 | entry = map->cad_gart_entry; | ||
495 | |||
496 | for (i = 0; i < map->cad_gart_size; i++, entry++) { | ||
497 | clear_bit(entry, tioca_kern->ca_pcigart_pagemap); | ||
498 | tioca_kern->ca_pcigart[entry] = 0; | ||
499 | } | ||
500 | tioca_tlbflush(tioca_kern); | ||
501 | |||
502 | list_del(&map->cad_list); | ||
503 | spin_unlock_irqrestore(&tioca_kern->ca_lock, flags); | ||
504 | kfree(map); | ||
505 | } | ||
506 | |||
507 | /** | ||
508 | * tioca_dma_map - map pages for PCI DMA | ||
509 | * @pdev: linux pci_dev representing the function | ||
510 | * @paddr: host physical address to map | ||
511 | * @byte_count: bytes to map | ||
512 | * | ||
513 | * This is the main wrapper for mapping host physical pages to CA PCI space. | ||
514 | * The mapping mode used is based on the devices dma_mask. As a last resort | ||
515 | * use the GART mapped mode. | ||
516 | */ | ||
517 | uint64_t | ||
518 | tioca_dma_map(struct pci_dev *pdev, uint64_t paddr, size_t byte_count) | ||
519 | { | ||
520 | uint64_t mapaddr; | ||
521 | |||
522 | /* | ||
523 | * If card is 64 or 48 bit addresable, use a direct mapping. 32 | ||
524 | * bit direct is so restrictive w.r.t. where the memory resides that | ||
525 | * we don't use it even though CA has some support. | ||
526 | */ | ||
527 | |||
528 | if (pdev->dma_mask == ~0UL) | ||
529 | mapaddr = tioca_dma_d64(paddr); | ||
530 | else if (pdev->dma_mask == 0xffffffffffffUL) | ||
531 | mapaddr = tioca_dma_d48(pdev, paddr); | ||
532 | else | ||
533 | mapaddr = 0; | ||
534 | |||
535 | /* Last resort ... use PCI portion of CA GART */ | ||
536 | |||
537 | if (mapaddr == 0) | ||
538 | mapaddr = tioca_dma_mapped(pdev, paddr, byte_count); | ||
539 | |||
540 | return mapaddr; | ||
541 | } | ||
542 | |||
543 | /** | ||
544 | * tioca_error_intr_handler - SGI TIO CA error interrupt handler | ||
545 | * @irq: unused | ||
546 | * @arg: pointer to tioca_common struct for the given CA | ||
547 | * @pt: unused | ||
548 | * | ||
549 | * Handle a CA error interrupt. Simply a wrapper around a SAL call which | ||
550 | * defers processing to the SGI prom. | ||
551 | */ | ||
552 | static irqreturn_t | ||
553 | tioca_error_intr_handler(int irq, void *arg, struct pt_regs *pt) | ||
554 | { | ||
555 | struct tioca_common *soft = arg; | ||
556 | struct ia64_sal_retval ret_stuff; | ||
557 | uint64_t segment; | ||
558 | uint64_t busnum; | ||
559 | ret_stuff.status = 0; | ||
560 | ret_stuff.v0 = 0; | ||
561 | |||
562 | segment = 0; | ||
563 | busnum = soft->ca_common.bs_persist_busnum; | ||
564 | |||
565 | SAL_CALL_NOLOCK(ret_stuff, | ||
566 | (u64) SN_SAL_IOIF_ERROR_INTERRUPT, | ||
567 | segment, busnum, 0, 0, 0, 0, 0); | ||
568 | |||
569 | return IRQ_HANDLED; | ||
570 | } | ||
571 | |||
572 | /** | ||
573 | * tioca_bus_fixup - perform final PCI fixup for a TIO CA bus | ||
574 | * @prom_bussoft: Common prom/kernel struct representing the bus | ||
575 | * | ||
576 | * Replicates the tioca_common pointed to by @prom_bussoft in kernel | ||
577 | * space. Allocates and initializes a kernel-only area for a given CA, | ||
578 | * and sets up an irq for handling CA error interrupts. | ||
579 | * | ||
580 | * On successful setup, returns the kernel version of tioca_common back to | ||
581 | * the caller. | ||
582 | */ | ||
583 | void * | ||
584 | tioca_bus_fixup(struct pcibus_bussoft *prom_bussoft) | ||
585 | { | ||
586 | struct tioca_common *tioca_common; | ||
587 | struct tioca_kernel *tioca_kern; | ||
588 | struct pci_bus *bus; | ||
589 | |||
590 | /* sanity check prom rev */ | ||
591 | |||
592 | if (sn_sal_rev_major() < 4 || | ||
593 | (sn_sal_rev_major() == 4 && sn_sal_rev_minor() < 6)) { | ||
594 | printk | ||
595 | (KERN_ERR "%s: SGI prom rev 4.06 or greater required " | ||
596 | "for tioca support\n", __FUNCTION__); | ||
597 | return NULL; | ||
598 | } | ||
599 | |||
600 | /* | ||
601 | * Allocate kernel bus soft and copy from prom. | ||
602 | */ | ||
603 | |||
604 | tioca_common = kcalloc(1, sizeof(struct tioca_common), GFP_KERNEL); | ||
605 | if (!tioca_common) | ||
606 | return NULL; | ||
607 | |||
608 | memcpy(tioca_common, prom_bussoft, sizeof(struct tioca_common)); | ||
609 | tioca_common->ca_common.bs_base |= __IA64_UNCACHED_OFFSET; | ||
610 | |||
611 | /* init kernel-private area */ | ||
612 | |||
613 | tioca_kern = kcalloc(1, sizeof(struct tioca_kernel), GFP_KERNEL); | ||
614 | if (!tioca_kern) { | ||
615 | kfree(tioca_common); | ||
616 | return NULL; | ||
617 | } | ||
618 | |||
619 | tioca_kern->ca_common = tioca_common; | ||
620 | spin_lock_init(&tioca_kern->ca_lock); | ||
621 | INIT_LIST_HEAD(&tioca_kern->ca_dmamaps); | ||
622 | tioca_kern->ca_closest_node = | ||
623 | nasid_to_cnodeid(tioca_common->ca_closest_nasid); | ||
624 | tioca_common->ca_kernel_private = (uint64_t) tioca_kern; | ||
625 | |||
626 | bus = pci_find_bus(0, tioca_common->ca_common.bs_persist_busnum); | ||
627 | BUG_ON(!bus); | ||
628 | tioca_kern->ca_devices = &bus->devices; | ||
629 | |||
630 | /* init GART */ | ||
631 | |||
632 | if (tioca_gart_init(tioca_kern) < 0) { | ||
633 | kfree(tioca_kern); | ||
634 | kfree(tioca_common); | ||
635 | return NULL; | ||
636 | } | ||
637 | |||
638 | tioca_gart_found++; | ||
639 | list_add(&tioca_kern->ca_list, &tioca_list); | ||
640 | |||
641 | if (request_irq(SGI_TIOCA_ERROR, | ||
642 | tioca_error_intr_handler, | ||
643 | SA_SHIRQ, "TIOCA error", (void *)tioca_common)) | ||
644 | printk(KERN_WARNING | ||
645 | "%s: Unable to get irq %d. " | ||
646 | "Error interrupts won't be routed for TIOCA bus %d\n", | ||
647 | __FUNCTION__, SGI_TIOCA_ERROR, | ||
648 | (int)tioca_common->ca_common.bs_persist_busnum); | ||
649 | |||
650 | return tioca_common; | ||
651 | } | ||
652 | |||
653 | static struct sn_pcibus_provider tioca_pci_interfaces = { | ||
654 | .dma_map = tioca_dma_map, | ||
655 | .dma_map_consistent = tioca_dma_map, | ||
656 | .dma_unmap = tioca_dma_unmap, | ||
657 | .bus_fixup = tioca_bus_fixup, | ||
658 | }; | ||
659 | |||
660 | /** | ||
661 | * tioca_init_provider - init SN PCI provider ops for TIO CA | ||
662 | */ | ||
663 | int | ||
664 | tioca_init_provider(void) | ||
665 | { | ||
666 | sn_pci_provider[PCIIO_ASIC_TYPE_TIOCA] = &tioca_pci_interfaces; | ||
667 | return 0; | ||
668 | } | ||