http://lia64.bkbits.net/linux-ia64-test-2.6.11 kaos@sgi.com|ChangeSet|20041213231738|36030 kaos # This is a BitKeeper generated diff -Nru style patch. # # ChangeSet # 2005/01/04 23:15:40-08:00 akpm@bix.(none) # ss # # arch/ia64/kernel/irq_ia64.c # 2005/01/04 23:15:33-08:00 akpm@bix.(none) +0 -1 # ss # # kernel/sched.c # 2005/01/04 23:03:53-08:00 akpm@bix.(none) +0 -0 # Auto merged # # include/linux/sched.h # 2005/01/04 23:03:53-08:00 akpm@bix.(none) +0 -0 # Auto merged # # include/asm-ia64/hw_irq.h # 2005/01/04 23:03:53-08:00 akpm@bix.(none) +0 -0 # Auto merged # # arch/ia64/mm/init.c # 2005/01/04 23:03:53-08:00 akpm@bix.(none) +0 -0 # Auto merged # # arch/ia64/kernel/irq.c # 2005/01/04 23:03:53-08:00 akpm@bix.(none) +0 -0 # Auto merged # # arch/ia64/Kconfig # 2005/01/04 23:03:53-08:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/12/13 15:17:38-08:00 kaos@sgi.com # [IA64] Drop SALINFO_TIMER_DELAY from 5 minutes to 1 minute # # Experience with recoverable MCA events shows that a poll interval of 5 # minutes for new MCA/INIT records is a bit too long. Drop the poll # interval to one minute. # # Signed-off-by: Keith Owens # Signed-off-by: Tony Luck # # arch/ia64/kernel/salinfo.c # 2004/12/13 15:16:04-08:00 kaos@sgi.com +2 -2 # Drop SALINFO_TIMER_DELAY from 5 minutes to 1 minute # # ChangeSet # 2004/12/13 15:15:28-08:00 kaos@sgi.com # [IA64] Clear all corrected records as they occur # # Because MCA events are not irq safe, they cannot be logged via # salinfo_decode at the time that they occur. Instead kernel salinfo.c # runs a timer every few minutes to check for and to clear corrected MCA # records. If a second recoverable MCA occurs on the same cpu before # salinfo_decode has cleared the first record then OS_MCA reads the # record for the first MCA from SAL, which passes invalid data to the MCA # recovery routines. # # This patch treats all corrected records the same way, by clearing the # records from SAL as soon as they occur. CMC and CPE records are # cleared as they are read. Recoverable MCA records are cleared at the # time that we decide they can be corrected. If salinfo_decode is not # running or is backlogged then we lose some logging, but that has always # been the case for corrected errors. # # Signed-off-by: Keith Owens # Signed-off-by: Tony Luck # # include/asm-ia64/sal.h # 2004/12/13 15:13:54-08:00 kaos@sgi.com +4 -0 # Clear all corrected records as they occur # # arch/ia64/kernel/salinfo.c # 2004/12/13 15:13:50-08:00 kaos@sgi.com +11 -5 # Clear all corrected records as they occur # # arch/ia64/kernel/mca.c # 2004/12/13 15:13:41-08:00 kaos@sgi.com +10 -1 # Clear all corrected records as they occur # # ChangeSet # 2004/12/13 15:12:18-08:00 kaos@sgi.com # [IA64] Add TIF_SIGDELAYED, delay a signal until it is safe # # Some of the work on recoverable MCA events has a requirement to send a # signal to a user process. But it is not safe to send signals from # MCA/INIT/NMI/PMI, because the rest of the kernel is an unknown state. # This patch adds set_sigdelayed() which is called from the problem # contexts to set the delayed signal. The delayed signal will be # delivered from the right context on the next transition from kernel to # user space. # # If TIF_SIGDELAYED is set when we run ia64_leave_kernel or # ia64_leave_syscall then the delayed signal is delivered and cleared. # All code for sigdelayed processing is on the slow paths. # # A recoverable MCA handler that wants to kill a user task just does # # set_sigdelayed(pid, signo, code, addr); # # Signed-off-by: Keith Owens # Signed-off-by: Tony Luck # # kernel/sched.c # 2004/12/13 15:10:06-08:00 kaos@sgi.com +9 -0 # Add TIF_SIGDELAYED, delay a signal until it is safe # # include/linux/sched.h # 2004/12/13 15:10:05-08:00 kaos@sgi.com +1 -0 # Add TIF_SIGDELAYED, delay a signal until it is safe # # include/asm-ia64/thread_info.h # 2004/12/13 15:10:04-08:00 kaos@sgi.com +14 -4 # Add TIF_SIGDELAYED, delay a signal until it is safe # # include/asm-ia64/signal.h # 2004/12/13 15:10:02-08:00 kaos@sgi.com +2 -0 # Add TIF_SIGDELAYED, delay a signal until it is safe # # arch/ia64/kernel/signal.c # 2004/12/13 15:10:01-08:00 kaos@sgi.com +101 -0 # Add TIF_SIGDELAYED, delay a signal until it is safe # # arch/ia64/kernel/entry.S # 2004/12/13 15:09:56-08:00 kaos@sgi.com +15 -0 # Add TIF_SIGDELAYED, delay a signal until it is safe # # ChangeSet # 2004/12/10 16:29:07-08:00 tony.luck@intel.com # [IA64] hardirq.h: Add declaration for ack_bad_irq(). # # Cleanup a warning from my irq merge. # # Signed-off-by: Tony Luck # # include/asm-ia64/hardirq.h # 2004/12/10 16:27:45-08:00 tony.luck@intel.com +2 -0 # Add declaration for ack_bad_irq(). # # ChangeSet # 2004/12/10 13:36:35-08:00 rja@sgi.com # [IA64] per cpu MCA/INIT save areas # # Linux currently has one MCA & INIT save area for saving # stack and other data. This patch creates per cpu MCA # save areas, so that each cpu can save its own MCA stack # data. CPU register ar.k3 is used to hold a physical # address pointer to the cpuinfo structure. The cpuinfo # structure has a physical address pointer to the MCA save # area. The MCA handler runs in physical mode and the # physical address pointer avoids the problems associated # with doing the virtual to physical translation. # # The per MCA save areas replace the global areas defined # in arch/ia64/kernel/mca.c for MCA processor state dump, # MCA stack, MCA stack frame, and MCA bspstore. # # The code to access those save areas is updated to use the # per cpu save areas. # # No changes are made to the MCA flow, ie all the old locks # are still in place. The point of this patch is to establish # the per cpu save areas. Additional usage of the save areas, # such as enabling concurrent INIT or MCA handling, will be # the subject of other patches. # # Signed-off-by: Russ Anderson # Signed-off-by: Tony Luck # # include/asm-ia64/mca_asm.h # 2004/12/10 13:33:20-08:00 rja@sgi.com +31 -0 # macros for syntactic sugar to access per-cpu variables # in physcial mode in mca/init handlers. # # arch/ia64/kernel/minstate.h # 2004/12/10 13:31:49-08:00 rja@sgi.com +5 -2 # Modify MINSTATE_START_SAVE_MIN_PHYS to use ar.k3 # # arch/ia64/kernel/mca_asm.S # 2004/12/10 13:30:21-08:00 rja@sgi.com +18 -38 # Replace the global MCA save pointers with the # per CPU equivalents. Replace ia64_mca_tlb_list # with cpuinfo equivalents. # # arch/ia64/kernel/efi.c # 2004/12/10 13:29:46-08:00 rja@sgi.com +65 -4 # Add efi_get_pal_addr() to set pal_paddr and pal_base # in cpuinfo. Remove ia64_mca_tlb_list[] references. # # arch/ia64/kernel/mca.c # 2004/12/10 13:28:43-08:00 rja@sgi.com +0 -7 # Remove the global save areas: ia64_mca_proc_state_dump, # ia64_mca_stack, ia64_mca_stackframe, ia64_mca_bspstore, # ia64_init_stack and ia64_mca_tlb_info[NR_CPUS] # # arch/ia64/kernel/asm-offsets.c # 2004/12/10 13:27:55-08:00 rja@sgi.com +9 -1 # Define assembler constants to correspond with # the c structure layout of cpuinfo and the MCA/INIT # save area. # # arch/ia64/mm/discontig.c # 2004/12/10 13:27:15-08:00 rja@sgi.com +53 -4 # On each node, allocate MCA/INIT space for each # cpu that physically exists. # # arch/ia64/mm/init.c # 2004/12/10 13:26:32-08:00 rja@sgi.com +15 -12 # Replace global array ia64_mca_tlb_list with # ar.k3 pointing to this cpu's cpuinfo structure. # Set physical address pointer to MCA save area in # this cpu's cpuinfo structure. # # include/asm-ia64/kregs.h # 2004/12/10 13:25:43-08:00 rja@sgi.com +1 -0 # Define ar.k3 as used for physical address pointer # to this cpu's cpuinfo structure. # # include/asm-ia64/mca.h # 2004/12/10 13:25:02-08:00 rja@sgi.com +13 -11 # Define the structure layout of the MCA/INIT save area. # Remove ia64_mca_tlb_info structure. pal_paddr and # pal_base are moved to the cpuinfo structure. # # include/asm-ia64/processor.h # 2004/12/10 13:24:20-08:00 rja@sgi.com +4 -0 # Add a physical address pointer to cpuinfo. # Add pal_paddr, pal_base, and percpu_paddr to cpuinfo. # # ChangeSet # 2004/12/10 13:14:10-08:00 steiner@sgi.com # [IA64] Cachealign jiffies_64 to prevent unexpected aliasing in the caches. # # On large systems, system overhead on cpu 0 is higher than on other # cpus. On a completely idle 512p system, the average amount of system time # on cpu 0 is 2.4% and .15% on cpu 1-511. # # A second interesting data point is that if I run a busy-loop # program on cpus 1-511, the system overhead on cpu 0 drops # significantly. # # I moved the timekeeper to cpu 1. The excessive system time moved # to cpu 1 and the system time on cpu 0 dropped to .2%. # # Further investigation showed that the problem was caused by false # sharing of the cacheline containing jiffies_64. On the kernel that # I was running, both jiffies_64 & pal_halt share the same cacheline. # Idle cpus are frequently accessing pal_halt. Minor kernel # changes (including some of the debugging code that I used to find the # problem :-( ) can cause variables to move & change the false sharing - the # symptoms of the problem can change or disappear. # # Signed-off-by: Jack Steiner # Signed-off-by: Tony Luck # # arch/ia64/kernel/time.c # 2004/12/10 13:10:05-08:00 steiner@sgi.com +1 -1 # Cachealign jiffies_64 to prevent unexpected aliasing in the caches. # # ChangeSet # 2004/12/10 13:05:36-08:00 steiner@sgi.com # [IA64-SGI] Add support for a future SGI chipset (shub2) 4of4 # # Change the code that manages the LEDs so that it # works on both shub1 & shub2. # # Signed-off-by: Jack Steiner # # include/asm-ia64/sn/shub_mmr.h # 2004/12/10 13:04:21-08:00 steiner@sgi.com +14 -0 # Add support for a future SGI chipset (shub2) # # include/asm-ia64/sn/leds.h # 2004/12/10 13:04:21-08:00 steiner@sgi.com +1 -0 # Add support for a future SGI chipset (shub2) # # arch/ia64/sn/kernel/sn2/timer_interrupt.c # 2004/12/10 13:04:21-08:00 steiner@sgi.com +0 -1 # Add support for a future SGI chipset (shub2) # # arch/ia64/sn/kernel/setup.c # 2004/12/10 13:04:21-08:00 steiner@sgi.com +0 -1 # Add support for a future SGI chipset (shub2) # # ChangeSet # 2004/12/10 12:16:38-08:00 steiner@sgi.com # [IA64-SGI] Add support for a future SGI chipset (shub2) 3of4 # # Change the IPI & TLB flushing code so that it works on # both shub1 & shub2. # # Signed-off-by: Jack Steiner # # include/asm-ia64/sn/rw_mmr.h # 2004/12/10 12:15:27-08:00 steiner@sgi.com +5 -4 # Add support for a future SGI chipset (shub2) # # arch/ia64/sn/kernel/sn2/sn2_smp.c # 2004/12/10 12:15:27-08:00 steiner@sgi.com +43 -26 # Add support for a future SGI chipset (shub2) # # arch/ia64/sn/kernel/sn2/ptc_deadlock.S # 2004/12/10 12:15:27-08:00 steiner@sgi.com +9 -9 # Add support for a future SGI chipset (shub2) # # ChangeSet # 2004/12/10 12:14:33-08:00 steiner@sgi.com # [IA64-SGI] Add support for a future SGI chipset (shub2) 2of4 # # This patch adds the addresses of shub2 MMRS to the shub_mmr # header file. During boot, a SAL call is made to determine the # type of the shub. Platform initialization sets the appropriate # MMR addresses for the platform. # # A new macro (is_shub1() & is_shub2()) can be used at runtime to # determine the type of the shub. # # Signed-off-by: Jack Steiner # # include/asm-ia64/sn/sn_cpuid.h # 2004/12/10 12:12:43-08:00 steiner@sgi.com +2 -3 # Add support for a future SGI chipset (shub2) # # include/asm-ia64/sn/shub_mmr.h # 2004/12/10 12:12:43-08:00 steiner@sgi.com +115 -92 # Add support for a future SGI chipset (shub2) # # include/asm-ia64/sn/arch.h # 2004/12/10 12:12:43-08:00 steiner@sgi.com +2 -1 # Add support for a future SGI chipset (shub2) # # arch/ia64/sn/kernel/sn2/timer.c # 2004/12/10 12:12:43-08:00 steiner@sgi.com +0 -1 # Add support for a future SGI chipset (shub2) # # arch/ia64/sn/kernel/sn2/sn2_smp.c # 2004/12/10 12:12:43-08:00 steiner@sgi.com +14 -15 # Add support for a future SGI chipset (shub2) # # arch/ia64/sn/kernel/sn2/ptc_deadlock.S # 2004/12/10 12:12:43-08:00 steiner@sgi.com +3 -3 # Add support for a future SGI chipset (shub2) # # arch/ia64/sn/kernel/setup.c # 2004/12/10 12:12:43-08:00 steiner@sgi.com +26 -12 # Add support for a future SGI chipset (shub2) # # arch/ia64/sn/kernel/iomv.c # 2004/12/10 12:12:43-08:00 steiner@sgi.com +5 -5 # Add support for a future SGI chipset (shub2) # # ChangeSet # 2004/12/10 12:11:47-08:00 steiner@sgi.com # [IA64-SGI] Add support for a future SGI chipset (shub2) 1of4 # # This patch changes the SN macros for calulating the addresses # of shub MMRs. Functionally, shub1 (current chipset) and shub2 # are very similar. The primary differences are in the addresses # of MMRs and in the location of the NASID (node number) in # a physical address. This patch adds the basic infrastructure # for running a single binary kernel image on either shub1 or shub2. # # Signed-off-by: Jack Steiner # # include/asm-ia64/sn/sn_sal.h # 2004/12/10 12:10:33-08:00 steiner@sgi.com +51 -2 # Add support for a future SGI chipset (shub2) # # include/asm-ia64/sn/pda.h # 2004/12/10 12:10:33-08:00 steiner@sgi.com +10 -3 # Add support for a future SGI chipset (shub2) # # include/asm-ia64/sn/klconfig.h # 2004/12/10 12:10:33-08:00 steiner@sgi.com +1 -1 # Add support for a future SGI chipset (shub2) # # include/asm-ia64/sn/addrs.h # 2004/12/10 12:10:33-08:00 steiner@sgi.com +156 -231 # Add support for a future SGI chipset (shub2) # # arch/ia64/sn/kernel/sn2/timer.c # 2004/12/10 12:10:33-08:00 steiner@sgi.com +2 -2 # Add support for a future SGI chipset (shub2) # # arch/ia64/sn/kernel/setup.c # 2004/12/10 12:10:33-08:00 steiner@sgi.com +10 -6 # Add support for a future SGI chipset (shub2) # # ChangeSet # 2004/11/23 15:47:20-08:00 tony.luck@intel.com # [IA64] convert to use CONFIG_GENERIC_HARDIRQS # # Convert ia64 to use generic irq handling code. # # sn2 fixes and testing by Jesse Barnes # # Signed-off-by: Tony Luck # # include/asm-ia64/msi.h # 2004/11/23 15:45:37-08:00 tony.luck@intel.com +0 -1 # convert to use CONFIG_GENERIC_HARDIRQS # # include/asm-ia64/hw_irq.h # 2004/11/23 15:45:36-08:00 tony.luck@intel.com +2 -2 # convert to use CONFIG_GENERIC_HARDIRQS # # arch/ia64/sn/kernel/irq.c # 2004/11/23 15:45:34-08:00 tony.luck@intel.com +2 -2 # convert to use CONFIG_GENERIC_HARDIRQS # # arch/ia64/kernel/irq_ia64.c # 2004/11/23 15:45:33-08:00 tony.luck@intel.com +2 -0 # convert to use CONFIG_GENERIC_HARDIRQS # # arch/ia64/kernel/irq.c # 2004/11/23 15:45:24-08:00 tony.luck@intel.com +29 -957 # convert to use CONFIG_GENERIC_HARDIRQS # # arch/ia64/Kconfig # 2004/11/23 15:44:58-08:00 tony.luck@intel.com +11 -0 # convert to use CONFIG_GENERIC_HARDIRQS # diff -Nru a/arch/ia64/Kconfig b/arch/ia64/Kconfig --- a/arch/ia64/Kconfig 2005-01-05 18:28:29 -08:00 +++ b/arch/ia64/Kconfig 2005-01-05 18:28:29 -08:00 @@ -390,6 +390,17 @@ source "lib/Kconfig" +# +# Use the generic interrupt handling code in kernel/irq/: +# +config GENERIC_HARDIRQS + bool + default y + +config GENERIC_IRQ_PROBE + bool + default y + source "arch/ia64/hp/sim/Kconfig" source "arch/ia64/oprofile/Kconfig" diff -Nru a/arch/ia64/kernel/asm-offsets.c b/arch/ia64/kernel/asm-offsets.c --- a/arch/ia64/kernel/asm-offsets.c 2005-01-05 18:28:29 -08:00 +++ b/arch/ia64/kernel/asm-offsets.c 2005-01-05 18:28:29 -08:00 @@ -203,7 +203,15 @@ #endif BLANK(); - DEFINE(IA64_MCA_TLB_INFO_SIZE, sizeof (struct ia64_mca_tlb_info)); + /* used by arch/ia64/kernel/mca_asm.S */ + DEFINE(IA64_CPUINFO_PERCPU_PADDR, offsetof (struct cpuinfo_ia64, percpu_paddr)); + DEFINE(IA64_CPUINFO_PA_MCA_INFO, offsetof (struct cpuinfo_ia64, ia64_pa_mca_data)); + DEFINE(IA64_MCA_PROC_STATE_DUMP, offsetof (struct ia64_mca_cpu_s, ia64_mca_proc_state_dump)); + DEFINE(IA64_MCA_STACK, offsetof (struct ia64_mca_cpu_s, ia64_mca_stack)); + DEFINE(IA64_MCA_STACKFRAME, offsetof (struct ia64_mca_cpu_s, ia64_mca_stackframe)); + DEFINE(IA64_MCA_BSPSTORE, offsetof (struct ia64_mca_cpu_s, ia64_mca_bspstore)); + DEFINE(IA64_INIT_STACK, offsetof (struct ia64_mca_cpu_s, ia64_init_stack)); + /* used by head.S */ DEFINE(IA64_CPUINFO_NSEC_PER_CYC_OFFSET, offsetof (struct cpuinfo_ia64, nsec_per_cyc)); diff -Nru a/arch/ia64/kernel/efi.c b/arch/ia64/kernel/efi.c --- a/arch/ia64/kernel/efi.c 2005-01-05 18:28:29 -08:00 +++ b/arch/ia64/kernel/efi.c 2005-01-05 18:28:29 -08:00 @@ -423,7 +423,6 @@ int pal_code_count = 0; u64 mask, psr; u64 vaddr; - int cpu; efi_map_start = __va(ia64_boot_param->efi_memmap); efi_map_end = efi_map_start + ia64_boot_param->efi_memmap_size; @@ -485,11 +484,73 @@ ia64_set_psr(psr); /* restore psr */ ia64_srlz_i(); - cpu = smp_processor_id(); + } +} + +/* + * Put pal_base and pal_paddr in the cpuinfo structure. + */ +void +efi_get_pal_addr(void) +{ + void *efi_map_start, *efi_map_end, *p; + efi_memory_desc_t *md; + u64 efi_desc_size; + int pal_code_count = 0; + u64 mask; + u64 vaddr; + struct cpuinfo_ia64 *cpuinfo; + + efi_map_start = __va(ia64_boot_param->efi_memmap); + efi_map_end = efi_map_start + ia64_boot_param->efi_memmap_size; + efi_desc_size = ia64_boot_param->efi_memdesc_size; + + for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) { + md = p; + if (md->type != EFI_PAL_CODE) + continue; + + if (++pal_code_count > 1) { + printk(KERN_ERR "Too many EFI Pal Code memory ranges, dropped @ %lx\n", + md->phys_addr); + continue; + } + /* + * The only ITLB entry in region 7 that is used is the one installed by + * __start(). That entry covers a 64MB range. + */ + mask = ~((1 << KERNEL_TR_PAGE_SHIFT) - 1); + vaddr = PAGE_OFFSET + md->phys_addr; + + /* + * We must check that the PAL mapping won't overlap with the kernel + * mapping. + * + * PAL code is guaranteed to be aligned on a power of 2 between 4k and + * 256KB and that only one ITR is needed to map it. This implies that the + * PAL code is always aligned on its size, i.e., the closest matching page + * size supported by the TLB. Therefore PAL code is guaranteed never to + * cross a 64MB unless it is bigger than 64MB (very unlikely!). So for + * now the following test is enough to determine whether or not we need a + * dedicated ITR for the PAL code. + */ + if ((vaddr & mask) == (KERNEL_START & mask)) { + printk(KERN_INFO "%s: no need to install ITR for PAL code\n", + __FUNCTION__); + continue; + } + + if (md->num_pages << EFI_PAGE_SHIFT > IA64_GRANULE_SIZE) + panic("Woah! PAL code size bigger than a granule!"); + + mask = ~((1 << IA64_GRANULE_SHIFT) - 1); /* insert this TR into our list for MCA recovery purposes */ - ia64_mca_tlb_list[cpu].pal_base = vaddr & mask; - ia64_mca_tlb_list[cpu].pal_paddr = pte_val(mk_pte_phys(md->phys_addr, PAGE_KERNEL)); + cpuinfo = (struct cpuinfo_ia64 *)__va(ia64_get_kr(IA64_KR_PA_CPU_INFO)); + cpuinfo->pal_base = vaddr & mask; + cpuinfo->pal_paddr = pte_val(mk_pte_phys(md->phys_addr, PAGE_KERNEL)); + printk(KERN_INFO "CPU %d: late efi pal_base 0x%lx pal_paddr 0x%lx\n", + smp_processor_id(), cpuinfo->pal_base, cpuinfo->pal_paddr); } } diff -Nru a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S --- a/arch/ia64/kernel/entry.S 2005-01-05 18:28:29 -08:00 +++ b/arch/ia64/kernel/entry.S 2005-01-05 18:28:29 -08:00 @@ -1057,6 +1057,9 @@ * p6 = TRUE if work-pending-check needs to be redone */ .work_pending: + tbit.nz p6,p0=r31,TIF_SIGDELAYED // signal delayed from MCA/INIT/NMI/PMI context? +(p6) br.cond.sptk.few .sigdelayed + ;; tbit.z p6,p0=r31,TIF_NEED_RESCHED // current_thread_info()->need_resched==0? (p6) br.cond.sptk.few .notify #ifdef CONFIG_PREEMPT @@ -1082,6 +1085,18 @@ .ret10: cmp.ne p6,p0=r0,r0 // p6 <- 0 (pLvSys)br.cond.sptk.many .work_processed_syscall // don't re-check br.cond.sptk.many .work_processed_kernel // don't re-check + +// There is a delayed signal that was detected in MCA/INIT/NMI/PMI context where +// it could not be delivered. Deliver it now. The signal might be for us and +// may set TIF_SIGPENDING, so redrive ia64_leave_* after processing the delayed +// signal. + +.sigdelayed: + br.call.sptk.many rp=do_sigdelayed + cmp.eq p6,p0=r0,r0 // p6 <- 1, always re-check +(pLvSys)br.cond.sptk.many .work_processed_syscall // re-check + br.cond.sptk.many .work_processed_kernel // re-check + END(ia64_leave_kernel) ENTRY(handle_syscall_error) diff -Nru a/arch/ia64/kernel/irq.c b/arch/ia64/kernel/irq.c --- a/arch/ia64/kernel/irq.c 2005-01-05 18:28:29 -08:00 +++ b/arch/ia64/kernel/irq.c 2005-01-05 18:28:29 -08:00 @@ -16,73 +16,31 @@ * architecture. */ -/* - * (mostly architecture independent, will move to kernel/irq.c in 2.5.) - * - * IRQs are in fact implemented a bit like signal handlers for the kernel. - * Naturally it's not a 1:1 relation, but there are similarities. - */ - -#include -#include +#include +#include #include -#include -#include -#include +#include #include -#include -#include -#include -#include -#include -#include -#include #include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - /* - * Linux has a controller-independent x86 interrupt architecture. - * every controller has a 'controller-template', that is used - * by the main code to do the right thing. Each driver-visible - * interrupt source is transparently wired to the appropriate - * controller. Thus drivers need not be aware of the - * interrupt-controller. - * - * Various interrupt controllers we handle: 8259 PIC, SMP IO-APIC, - * PIIX4's internal 8259 PIC and SGI's Visual Workstation Cobalt (IO-)APIC. - * (IO-APICs assumed to be messaging to Pentium local-APICs) - * - * the code is designed to be easily extended with new/different - * interrupt controllers, without having to do assembly magic. + * 'what should we do if we get a hw irq event on an illegal vector'. + * each architecture has to answer this themselves. */ +void ack_bad_irq(unsigned int irq) +{ + printk(KERN_ERR "Unexpected irq vector 0x%x on CPU %u!\n", irq, smp_processor_id()); +} /* - * Controller mappings for all interrupt sources: + * do_IRQ handles all normal device IRQ's (the special + * SMP cross-CPU interrupts have their own specific + * handlers). */ -irq_desc_t _irq_desc[NR_IRQS] __cacheline_aligned = { - [0 ... NR_IRQS-1] = { - .status = IRQ_DISABLED, - .handler = &no_irq_type, - .lock = SPIN_LOCK_UNLOCKED - } -}; +unsigned int do_IRQ(unsigned long irq, struct pt_regs *regs) +{ + return __do_IRQ(irq, regs); +} #ifdef CONFIG_SMP /* @@ -95,7 +53,7 @@ #ifdef CONFIG_IA64_GENERIC irq_desc_t * __ia64_irq_desc (unsigned int irq) { - return _irq_desc + irq; + return irq_desc + irq; } ia64_vector __ia64_irq_to_vector (unsigned int irq) @@ -109,82 +67,24 @@ } #endif -static void register_irq_proc (unsigned int irq); - -/* - * Special irq handlers. - */ - -irqreturn_t no_action(int cpl, void *dev_id, struct pt_regs *regs) -{ return IRQ_NONE; } - -/* - * Generic no controller code - */ - -static void enable_none(unsigned int irq) { } -static unsigned int startup_none(unsigned int irq) { return 0; } -static void disable_none(unsigned int irq) { } -static void ack_none(unsigned int irq) -{ /* - * 'what should we do if we get a hw irq event on an illegal vector'. - * each architecture has to answer this themselves, it doesn't deserve - * a generic callback i think. + * Interrupt statistics: */ -#ifdef CONFIG_X86 - printk(KERN_ERR "unexpected IRQ trap at vector %02x\n", irq); -#ifdef CONFIG_X86_LOCAL_APIC - /* - * Currently unexpected vectors happen only on SMP and APIC. - * We _must_ ack these because every local APIC has only N - * irq slots per priority level, and a 'hanging, unacked' IRQ - * holds up an irq slot - in excessive cases (when multiple - * unexpected vectors occur) that might lock up the APIC - * completely. - */ - ack_APIC_irq(); -#endif -#endif -#ifdef CONFIG_IA64 - printk(KERN_ERR "Unexpected irq vector 0x%x on CPU %u!\n", irq, smp_processor_id()); -#endif -} - -/* startup is the same as "enable", shutdown is same as "disable" */ -#define shutdown_none disable_none -#define end_none enable_none - -struct hw_interrupt_type no_irq_type = { - "none", - startup_none, - shutdown_none, - enable_none, - disable_none, - ack_none, - end_none -}; atomic_t irq_err_count; -#ifdef CONFIG_X86_IO_APIC -#ifdef APIC_MISMATCH_DEBUG -atomic_t irq_mis_count; -#endif -#endif /* - * Generic, controller-independent functions: + * /proc/interrupts printing: */ int show_interrupts(struct seq_file *p, void *v) { - int j, i = *(loff_t *) v; + int i = *(loff_t *) v, j; struct irqaction * action; - irq_desc_t *idesc; unsigned long flags; if (i == 0) { - seq_puts(p, " "); + seq_printf(p, " "); for (j=0; jlock, flags); - action = idesc->action; + spin_lock_irqsave(&irq_desc[i].lock, flags); + action = irq_desc[i].action; if (!action) goto skip; seq_printf(p, "%3d: ",i); @@ -205,7 +104,7 @@ if (cpu_online(j)) seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]); #endif - seq_printf(p, " %14s", idesc->handler->typename); + seq_printf(p, " %14s", irq_desc[i].handler->typename); seq_printf(p, " %s", action->name); for (action=action->next; action; action = action->next) @@ -213,725 +112,25 @@ seq_putc(p, '\n'); skip: - spin_unlock_irqrestore(&idesc->lock, flags); + spin_unlock_irqrestore(&irq_desc[i].lock, flags); } else if (i == NR_IRQS) { -#ifdef CONFIG_X86_LOCAL_APIC +#if defined(CONFIG_X86_LOCAL_APIC) seq_puts(p, "LOC: "); for (j = 0; j < NR_CPUS; j++) if (cpu_online(j)) - seq_printf(p, "%10u ", irq_stat[j].apic_timer_irqs); + seq_printf(p, "%10u ", + irq_stat[j].apic_timer_irqs); seq_putc(p, '\n'); #endif seq_printf(p, "ERR: %10u\n", atomic_read(&irq_err_count)); -#ifdef CONFIG_X86_IO_APIC -#ifdef APIC_MISMATCH_DEBUG +#if defined(CONFIG_X86_IO_APIC) seq_printf(p, "MIS: %10u\n", atomic_read(&irq_mis_count)); #endif -#endif } return 0; } #ifdef CONFIG_SMP -inline void synchronize_irq(unsigned int irq) -{ - while (irq_descp(irq)->status & IRQ_INPROGRESS) - cpu_relax(); -} -EXPORT_SYMBOL(synchronize_irq); -#endif - -/* - * This should really return information about whether - * we should do bottom half handling etc. Right now we - * end up _always_ checking the bottom half, which is a - * waste of time and is not what some drivers would - * prefer. - */ -int handle_IRQ_event(unsigned int irq, - struct pt_regs *regs, struct irqaction *action) -{ - int status = 1; /* Force the "do bottom halves" bit */ - int ret, retval = 0; - - if (!(action->flags & SA_INTERRUPT)) - local_irq_enable(); - - do { - ret = action->handler(irq, action->dev_id, regs); - if (ret == IRQ_HANDLED) - status |= action->flags; - retval |= ret; - action = action->next; - } while (action); - if (status & SA_SAMPLE_RANDOM) - add_interrupt_randomness(irq); - local_irq_disable(); - return retval; -} - -static void __report_bad_irq(int irq, irq_desc_t *desc, irqreturn_t action_ret) -{ - struct irqaction *action; - - if (action_ret != IRQ_HANDLED && action_ret != IRQ_NONE) { - printk(KERN_ERR "irq event %d: bogus return value %x\n", - irq, action_ret); - } else { - printk(KERN_ERR "irq %d: nobody cared!\n", irq); - } - dump_stack(); - printk(KERN_ERR "handlers:\n"); - action = desc->action; - do { - printk(KERN_ERR "[<%p>]", action->handler); - print_symbol(" (%s)", - (unsigned long)action->handler); - printk("\n"); - action = action->next; - } while (action); -} - -static void report_bad_irq(int irq, irq_desc_t *desc, irqreturn_t action_ret) -{ - static int count = 100; - - if (count) { - count--; - __report_bad_irq(irq, desc, action_ret); - } -} - -static int noirqdebug; - -static int __init noirqdebug_setup(char *str) -{ - noirqdebug = 1; - printk("IRQ lockup detection disabled\n"); - return 1; -} - -__setup("noirqdebug", noirqdebug_setup); - -/* - * If 99,900 of the previous 100,000 interrupts have not been handled then - * assume that the IRQ is stuck in some manner. Drop a diagnostic and try to - * turn the IRQ off. - * - * (The other 100-of-100,000 interrupts may have been a correctly-functioning - * device sharing an IRQ with the failing one) - * - * Called under desc->lock - */ -static void note_interrupt(int irq, irq_desc_t *desc, irqreturn_t action_ret) -{ - if (action_ret != IRQ_HANDLED) { - desc->irqs_unhandled++; - if (action_ret != IRQ_NONE) - report_bad_irq(irq, desc, action_ret); - } - - desc->irq_count++; - if (desc->irq_count < 100000) - return; - - desc->irq_count = 0; - if (desc->irqs_unhandled > 99900) { - /* - * The interrupt is stuck - */ - __report_bad_irq(irq, desc, action_ret); - /* - * Now kill the IRQ - */ - printk(KERN_EMERG "Disabling IRQ #%d\n", irq); - desc->status |= IRQ_DISABLED; - desc->handler->disable(irq); - } - desc->irqs_unhandled = 0; -} - -/* - * Generic enable/disable code: this just calls - * down into the PIC-specific version for the actual - * hardware disable after having gotten the irq - * controller lock. - */ - -/** - * disable_irq_nosync - disable an irq without waiting - * @irq: Interrupt to disable - * - * Disable the selected interrupt line. Disables and Enables are - * nested. - * Unlike disable_irq(), this function does not ensure existing - * instances of the IRQ handler have completed before returning. - * - * This function may be called from IRQ context. - */ - -inline void disable_irq_nosync(unsigned int irq) -{ - irq_desc_t *desc = irq_descp(irq); - unsigned long flags; - - spin_lock_irqsave(&desc->lock, flags); - if (!desc->depth++) { - desc->status |= IRQ_DISABLED; - desc->handler->disable(irq); - } - spin_unlock_irqrestore(&desc->lock, flags); -} -EXPORT_SYMBOL(disable_irq_nosync); - -/** - * disable_irq - disable an irq and wait for completion - * @irq: Interrupt to disable - * - * Disable the selected interrupt line. Enables and Disables are - * nested. - * This function waits for any pending IRQ handlers for this interrupt - * to complete before returning. If you use this function while - * holding a resource the IRQ handler may need you will deadlock. - * - * This function may be called - with care - from IRQ context. - */ - -void disable_irq(unsigned int irq) -{ - irq_desc_t *desc = irq_descp(irq); - - disable_irq_nosync(irq); - if (desc->action) - synchronize_irq(irq); -} -EXPORT_SYMBOL(disable_irq); - -/** - * enable_irq - enable handling of an irq - * @irq: Interrupt to enable - * - * Undoes the effect of one call to disable_irq(). If this - * matches the last disable, processing of interrupts on this - * IRQ line is re-enabled. - * - * This function may be called from IRQ context. - */ - -void enable_irq(unsigned int irq) -{ - irq_desc_t *desc = irq_descp(irq); - unsigned long flags; - - spin_lock_irqsave(&desc->lock, flags); - switch (desc->depth) { - case 1: { - unsigned int status = desc->status & ~IRQ_DISABLED; - desc->status = status; - if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) { - desc->status = status | IRQ_REPLAY; - hw_resend_irq(desc->handler,irq); - } - desc->handler->enable(irq); - /* fall-through */ - } - default: - desc->depth--; - break; - case 0: - printk(KERN_ERR "enable_irq(%u) unbalanced from %p\n", - irq, (void *) __builtin_return_address(0)); - } - spin_unlock_irqrestore(&desc->lock, flags); -} -EXPORT_SYMBOL(enable_irq); - -/* - * do_IRQ handles all normal device IRQ's (the special - * SMP cross-CPU interrupts have their own specific - * handlers). - */ -unsigned int do_IRQ(unsigned long irq, struct pt_regs *regs) -{ - /* - * We ack quickly, we don't want the irq controller - * thinking we're snobs just because some other CPU has - * disabled global interrupts (we have already done the - * INT_ACK cycles, it's too late to try to pretend to the - * controller that we aren't taking the interrupt). - * - * 0 return value means that this irq is already being - * handled by some other CPU. (or is disabled) - */ - irq_desc_t *desc = irq_descp(irq); - struct irqaction * action; - irqreturn_t action_ret; - unsigned int status; - int cpu; - - cpu = smp_processor_id(); /* for CONFIG_PREEMPT, this must come after irq_enter()! */ - - kstat_cpu(cpu).irqs[irq]++; - - if (desc->status & IRQ_PER_CPU) { - /* no locking required for CPU-local interrupts: */ - desc->handler->ack(irq); - action_ret = handle_IRQ_event(irq, regs, desc->action); - desc->handler->end(irq); - } else { - spin_lock(&desc->lock); - desc->handler->ack(irq); - /* - * REPLAY is when Linux resends an IRQ that was dropped earlier - * WAITING is used by probe to mark irqs that are being tested - */ - status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING); - status |= IRQ_PENDING; /* we _want_ to handle it */ - - /* - * If the IRQ is disabled for whatever reason, we cannot - * use the action we have. - */ - action = NULL; - if (likely(!(status & (IRQ_DISABLED | IRQ_INPROGRESS)))) { - action = desc->action; - status &= ~IRQ_PENDING; /* we commit to handling */ - status |= IRQ_INPROGRESS; /* we are handling it */ - } - desc->status = status; - - /* - * If there is no IRQ handler or it was disabled, exit early. - * Since we set PENDING, if another processor is handling - * a different instance of this same irq, the other processor - * will take care of it. - */ - if (unlikely(!action)) - goto out; - - /* - * Edge triggered interrupts need to remember - * pending events. - * This applies to any hw interrupts that allow a second - * instance of the same irq to arrive while we are in do_IRQ - * or in the handler. But the code here only handles the _second_ - * instance of the irq, not the third or fourth. So it is mostly - * useful for irq hardware that does not mask cleanly in an - * SMP environment. - */ - for (;;) { - spin_unlock(&desc->lock); - action_ret = handle_IRQ_event(irq, regs, action); - spin_lock(&desc->lock); - if (!noirqdebug) - note_interrupt(irq, desc, action_ret); - if (!(desc->status & IRQ_PENDING)) - break; - desc->status &= ~IRQ_PENDING; - } - desc->status &= ~IRQ_INPROGRESS; - out: - /* - * The ->end() handler has to deal with interrupts which got - * disabled while the handler was running. - */ - desc->handler->end(irq); - spin_unlock(&desc->lock); - } - return 1; -} - -/** - * request_irq - allocate an interrupt line - * @irq: Interrupt line to allocate - * @handler: Function to be called when the IRQ occurs - * @irqflags: Interrupt type flags - * @devname: An ascii name for the claiming device - * @dev_id: A cookie passed back to the handler function - * - * This call allocates interrupt resources and enables the - * interrupt line and IRQ handling. From the point this - * call is made your handler function may be invoked. Since - * your handler function must clear any interrupt the board - * raises, you must take care both to initialise your hardware - * and to set up the interrupt handler in the right order. - * - * Dev_id must be globally unique. Normally the address of the - * device data structure is used as the cookie. Since the handler - * receives this value it makes sense to use it. - * - * If your interrupt is shared you must pass a non NULL dev_id - * as this is required when freeing the interrupt. - * - * Flags: - * - * SA_SHIRQ Interrupt is shared - * - * SA_INTERRUPT Disable local interrupts while processing - * - * SA_SAMPLE_RANDOM The interrupt can be used for entropy - * - */ - -int request_irq(unsigned int irq, - irqreturn_t (*handler)(int, void *, struct pt_regs *), - unsigned long irqflags, - const char * devname, - void *dev_id) -{ - int retval; - struct irqaction * action; - -#if 1 - /* - * Sanity-check: shared interrupts should REALLY pass in - * a real dev-ID, otherwise we'll have trouble later trying - * to figure out which interrupt is which (messes up the - * interrupt freeing logic etc). - */ - if (irqflags & SA_SHIRQ) { - if (!dev_id) - printk(KERN_ERR "Bad boy: %s called us without a dev_id!\n", devname); - } -#endif - - if (irq >= NR_IRQS) - return -EINVAL; - if (!handler) - return -EINVAL; - - action = (struct irqaction *) - kmalloc(sizeof(struct irqaction), GFP_ATOMIC); - if (!action) - return -ENOMEM; - - action->handler = handler; - action->flags = irqflags; - cpus_clear(action->mask); - action->name = devname; - action->next = NULL; - action->dev_id = dev_id; - - retval = setup_irq(irq, action); - if (retval) - kfree(action); - return retval; -} - -EXPORT_SYMBOL(request_irq); - -/** - * free_irq - free an interrupt - * @irq: Interrupt line to free - * @dev_id: Device identity to free - * - * Remove an interrupt handler. The handler is removed and if the - * interrupt line is no longer in use by any driver it is disabled. - * On a shared IRQ the caller must ensure the interrupt is disabled - * on the card it drives before calling this function. The function - * does not return until any executing interrupts for this IRQ - * have completed. - * - * This function must not be called from interrupt context. - */ - -void free_irq(unsigned int irq, void *dev_id) -{ - irq_desc_t *desc; - struct irqaction **p; - unsigned long flags; - - if (irq >= NR_IRQS) - return; - - desc = irq_descp(irq); - spin_lock_irqsave(&desc->lock,flags); - p = &desc->action; - for (;;) { - struct irqaction * action = *p; - if (action) { - struct irqaction **pp = p; - p = &action->next; - if (action->dev_id != dev_id) - continue; - - /* Found it - now remove it from the list of entries */ - *pp = action->next; - if (!desc->action) { - desc->status |= IRQ_DISABLED; - desc->handler->shutdown(irq); - } - spin_unlock_irqrestore(&desc->lock,flags); - - /* Wait to make sure it's not being used on another CPU */ - synchronize_irq(irq); - kfree(action); - return; - } - printk(KERN_ERR "Trying to free free IRQ%d\n",irq); - spin_unlock_irqrestore(&desc->lock,flags); - return; - } -} - -EXPORT_SYMBOL(free_irq); - -/* - * IRQ autodetection code.. - * - * This depends on the fact that any interrupt that - * comes in on to an unassigned handler will get stuck - * with "IRQ_WAITING" cleared and the interrupt - * disabled. - */ - -static DECLARE_MUTEX(probe_sem); - -/** - * probe_irq_on - begin an interrupt autodetect - * - * Commence probing for an interrupt. The interrupts are scanned - * and a mask of potential interrupt lines is returned. - * - */ - -unsigned long probe_irq_on(void) -{ - unsigned int i; - irq_desc_t *desc; - unsigned long val; - unsigned long delay; - - down(&probe_sem); - /* - * something may have generated an irq long ago and we want to - * flush such a longstanding irq before considering it as spurious. - */ - for (i = NR_IRQS-1; i > 0; i--) { - desc = irq_descp(i); - - spin_lock_irq(&desc->lock); - if (!desc->action) - desc->handler->startup(i); - spin_unlock_irq(&desc->lock); - } - - /* Wait for longstanding interrupts to trigger. */ - for (delay = jiffies + HZ/50; time_after(delay, jiffies); ) - /* about 20ms delay */ barrier(); - - /* - * enable any unassigned irqs - * (we must startup again here because if a longstanding irq - * happened in the previous stage, it may have masked itself) - */ - for (i = NR_IRQS-1; i > 0; i--) { - desc = irq_descp(i); - - spin_lock_irq(&desc->lock); - if (!desc->action) { - desc->status |= IRQ_AUTODETECT | IRQ_WAITING; - if (desc->handler->startup(i)) - desc->status |= IRQ_PENDING; - } - spin_unlock_irq(&desc->lock); - } - - /* - * Wait for spurious interrupts to trigger - */ - for (delay = jiffies + HZ/10; time_after(delay, jiffies); ) - /* about 100ms delay */ barrier(); - - /* - * Now filter out any obviously spurious interrupts - */ - val = 0; - for (i = 0; i < NR_IRQS; i++) { - irq_desc_t *desc = irq_descp(i); - unsigned int status; - - spin_lock_irq(&desc->lock); - status = desc->status; - - if (status & IRQ_AUTODETECT) { - /* It triggered already - consider it spurious. */ - if (!(status & IRQ_WAITING)) { - desc->status = status & ~IRQ_AUTODETECT; - desc->handler->shutdown(i); - } else - if (i < 32) - val |= 1 << i; - } - spin_unlock_irq(&desc->lock); - } - - return val; -} - -EXPORT_SYMBOL(probe_irq_on); - -/** - * probe_irq_mask - scan a bitmap of interrupt lines - * @val: mask of interrupts to consider - * - * Scan the ISA bus interrupt lines and return a bitmap of - * active interrupts. The interrupt probe logic state is then - * returned to its previous value. - * - * Note: we need to scan all the irq's even though we will - * only return ISA irq numbers - just so that we reset them - * all to a known state. - */ -unsigned int probe_irq_mask(unsigned long val) -{ - int i; - unsigned int mask; - - mask = 0; - for (i = 0; i < 16; i++) { - irq_desc_t *desc = irq_descp(i); - unsigned int status; - - spin_lock_irq(&desc->lock); - status = desc->status; - - if (status & IRQ_AUTODETECT) { - if (!(status & IRQ_WAITING)) - mask |= 1 << i; - - desc->status = status & ~IRQ_AUTODETECT; - desc->handler->shutdown(i); - } - spin_unlock_irq(&desc->lock); - } - up(&probe_sem); - - return mask & val; -} -EXPORT_SYMBOL(probe_irq_mask); - -/** - * probe_irq_off - end an interrupt autodetect - * @val: mask of potential interrupts (unused) - * - * Scans the unused interrupt lines and returns the line which - * appears to have triggered the interrupt. If no interrupt was - * found then zero is returned. If more than one interrupt is - * found then minus the first candidate is returned to indicate - * their is doubt. - * - * The interrupt probe logic state is returned to its previous - * value. - * - * BUGS: When used in a module (which arguably shouldn't happen) - * nothing prevents two IRQ probe callers from overlapping. The - * results of this are non-optimal. - */ - -int probe_irq_off(unsigned long val) -{ - int i, irq_found, nr_irqs; - - nr_irqs = 0; - irq_found = 0; - for (i = 0; i < NR_IRQS; i++) { - irq_desc_t *desc = irq_descp(i); - unsigned int status; - - spin_lock_irq(&desc->lock); - status = desc->status; - - if (status & IRQ_AUTODETECT) { - if (!(status & IRQ_WAITING)) { - if (!nr_irqs) - irq_found = i; - nr_irqs++; - } - desc->status = status & ~IRQ_AUTODETECT; - desc->handler->shutdown(i); - } - spin_unlock_irq(&desc->lock); - } - up(&probe_sem); - - if (nr_irqs > 1) - irq_found = -irq_found; - return irq_found; -} - -EXPORT_SYMBOL(probe_irq_off); - -int setup_irq(unsigned int irq, struct irqaction * new) -{ - int shared = 0; - unsigned long flags; - struct irqaction *old, **p; - irq_desc_t *desc = irq_descp(irq); - - if (desc->handler == &no_irq_type) - return -ENOSYS; - /* - * Some drivers like serial.c use request_irq() heavily, - * so we have to be careful not to interfere with a - * running system. - */ - if (new->flags & SA_SAMPLE_RANDOM) { - /* - * This function might sleep, we want to call it first, - * outside of the atomic block. - * Yes, this might clear the entropy pool if the wrong - * driver is attempted to be loaded, without actually - * installing a new handler, but is this really a problem, - * only the sysadmin is able to do this. - */ - rand_initialize_irq(irq); - } - - if (new->flags & SA_PERCPU_IRQ) { - desc->status |= IRQ_PER_CPU; - desc->handler = &irq_type_ia64_lsapic; - } - - /* - * The following block of code has to be executed atomically - */ - spin_lock_irqsave(&desc->lock,flags); - p = &desc->action; - if ((old = *p) != NULL) { - /* Can't share interrupts unless both agree to */ - if (!(old->flags & new->flags & SA_SHIRQ)) { - spin_unlock_irqrestore(&desc->lock,flags); - return -EBUSY; - } - - /* add new interrupt at end of irq queue */ - do { - p = &old->next; - old = *p; - } while (old); - shared = 1; - } - - *p = new; - - if (!shared) { - desc->depth = 0; - desc->status &= ~(IRQ_DISABLED | IRQ_AUTODETECT | IRQ_WAITING | IRQ_INPROGRESS); - desc->handler->startup(irq); - } - spin_unlock_irqrestore(&desc->lock,flags); - - register_irq_proc(irq); - return 0; -} - -static struct proc_dir_entry * root_irq_dir; -static struct proc_dir_entry * irq_dir [NR_IRQS]; - -#ifdef CONFIG_SMP - -static struct proc_dir_entry * smp_affinity_entry [NR_IRQS]; static cpumask_t irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = CPU_MASK_ALL }; @@ -949,79 +148,6 @@ } } -static int irq_affinity_read_proc (char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - int len = sprintf(page, "%s", irq_redir[(long)data] ? "r " : ""); - - len += cpumask_scnprintf(page+len, count, irq_affinity[(long)data]); - if (count - len < 2) - return -EINVAL; - len += sprintf(page + len, "\n"); - return len; -} - -static int irq_affinity_write_proc (struct file *file, const char __user *buffer, - unsigned long count, void *data) -{ - unsigned int irq = (unsigned long) data; - int full_count = count, err; - cpumask_t new_value, tmp; -# define R_PREFIX_LEN 16 - char rbuf[R_PREFIX_LEN]; - int rlen; - int prelen; - irq_desc_t *desc = irq_descp(irq); - unsigned long flags; - int redir = 0; - - if (!desc->handler->set_affinity) - return -EIO; - - /* - * If string being written starts with a prefix of 'r' or 'R' - * and some limited number of spaces, set IA64_IRQ_REDIRECTED. - * If more than (R_PREFIX_LEN - 2) spaces are passed, they won't - * all be trimmed as part of prelen, the untrimmed spaces will - * cause the hex parsing to fail, and this write() syscall will - * fail with EINVAL. - */ - - if (!count) - return -EINVAL; - rlen = min(sizeof(rbuf)-1, count); - if (copy_from_user(rbuf, buffer, rlen)) - return -EFAULT; - rbuf[rlen] = 0; - prelen = 0; - if (tolower(*rbuf) == 'r') { - prelen = strspn(rbuf, "Rr "); - redir++; - } - - err = cpumask_parse(buffer+prelen, count-prelen, new_value); - if (err) - return err; - - /* - * Do not allow disabling IRQs completely - it's a too easy - * way to make the system unusable accidentally :-) At least - * one online CPU still has to be targeted. - */ - cpus_and(tmp, new_value, cpu_online_map); - if (cpus_empty(tmp)) - return -EINVAL; - - spin_lock_irqsave(&desc->lock, flags); - pending_irq_cpumask[irq] = new_value; - if (redir) - set_bit(irq, pending_irq_redir); - else - clear_bit(irq, pending_irq_redir); - spin_unlock_irqrestore(&desc->lock, flags); - - return full_count; -} void move_irq(int irq) { @@ -1138,57 +264,3 @@ local_irq_disable(); } #endif - -#define MAX_NAMELEN 10 - -static void register_irq_proc (unsigned int irq) -{ - char name [MAX_NAMELEN]; - - if (!root_irq_dir || (irq_descp(irq)->handler == &no_irq_type) || irq_dir[irq]) - return; - - memset(name, 0, MAX_NAMELEN); - sprintf(name, "%d", irq); - - /* create /proc/irq/1234 */ - irq_dir[irq] = proc_mkdir(name, root_irq_dir); - -#ifdef CONFIG_SMP - { - struct proc_dir_entry *entry; - - /* create /proc/irq/1234/smp_affinity */ - entry = create_proc_entry("smp_affinity", 0600, irq_dir[irq]); - - if (entry) { - entry->nlink = 1; - entry->data = (void *)(long)irq; - entry->read_proc = irq_affinity_read_proc; - entry->write_proc = irq_affinity_write_proc; - } - - smp_affinity_entry[irq] = entry; - } -#endif -} - -void init_irq_proc (void) -{ - int i; - - /* create /proc/irq */ - root_irq_dir = proc_mkdir("irq", NULL); - - /* create /proc/irq/prof_cpu_mask */ - create_prof_cpu_mask(root_irq_dir); - - /* - * Create entries for all existing IRQs. - */ - for (i = 0; i < NR_IRQS; i++) { - if (irq_descp(i)->handler == &no_irq_type) - continue; - register_irq_proc(i); - } -} diff -Nru a/arch/ia64/kernel/mca.c b/arch/ia64/kernel/mca.c --- a/arch/ia64/kernel/mca.c 2005-01-05 18:28:29 -08:00 +++ b/arch/ia64/kernel/mca.c 2005-01-05 18:28:29 -08:00 @@ -85,11 +85,6 @@ /* Used by mca_asm.S */ ia64_mca_sal_to_os_state_t ia64_sal_to_os_handoff_state; ia64_mca_os_to_sal_state_t ia64_os_to_sal_handoff_state; -u64 ia64_mca_proc_state_dump[512]; -u64 ia64_mca_stack[1024] __attribute__((aligned(16))); -u64 ia64_mca_stackframe[32]; -u64 ia64_mca_bspstore[1024]; -u64 ia64_init_stack[KERNEL_STACK_SIZE/8] __attribute__((aligned(16))); u64 ia64_mca_serialize; /* In mca_asm.S */ @@ -98,8 +93,6 @@ static ia64_mc_info_t ia64_mc_info; -struct ia64_mca_tlb_info ia64_mca_tlb_list[NR_CPUS]; - #define MAX_CPE_POLL_INTERVAL (15*60*HZ) /* 15 minutes */ #define MIN_CPE_POLL_INTERVAL (2*60*HZ) /* 2 minutes */ #define CMC_POLL_INTERVAL (1*60*HZ) /* 1 minute */ @@ -240,6 +233,7 @@ ia64_mca_log_sal_error_record(int sal_info_type) { u8 *buffer; + sal_log_record_header_t *rh; u64 size; int irq_safe = sal_info_type != SAL_INFO_TYPE_MCA && sal_info_type != SAL_INFO_TYPE_INIT; #ifdef IA64_MCA_DEBUG_INFO @@ -258,7 +252,8 @@ sal_info_type < ARRAY_SIZE(rec_name) ? rec_name[sal_info_type] : "UNKNOWN"); /* Clear logs from corrected errors in case there's no user-level logger */ - if (sal_info_type == SAL_INFO_TYPE_CPE || sal_info_type == SAL_INFO_TYPE_CMC) + rh = (sal_log_record_header_t *)buffer; + if (rh->severity == sal_log_severity_corrected) ia64_sal_clear_state_info(sal_info_type); } @@ -887,6 +882,13 @@ &ia64_sal_to_os_handoff_state, &ia64_os_to_sal_handoff_state)); +return_to_sal: + + if (recover) { + sal_log_record_header_t *rh = IA64_LOG_CURR_BUFFER(SAL_INFO_TYPE_MCA); + rh->severity = sal_log_severity_corrected; + ia64_sal_clear_state_info(SAL_INFO_TYPE_MCA); + } /* * Wakeup all the processors which are spinning in the rendezvous * loop. diff -Nru a/arch/ia64/kernel/mca_asm.S b/arch/ia64/kernel/mca_asm.S --- a/arch/ia64/kernel/mca_asm.S 2005-01-05 18:28:29 -08:00 +++ b/arch/ia64/kernel/mca_asm.S 2005-01-05 18:28:29 -08:00 @@ -13,6 +13,9 @@ // 2. Restore current thread pointer to kr6 // 3. Move stack ptr 16 bytes to conform to C calling convention // +// 04/11/12 Russ Anderson +// Added per cpu MCA/INIT stack save areas. +// #include #include @@ -102,11 +105,6 @@ .global ia64_os_mca_dispatch_end .global ia64_sal_to_os_handoff_state .global ia64_os_to_sal_handoff_state - .global ia64_mca_proc_state_dump - .global ia64_mca_stack - .global ia64_mca_stackframe - .global ia64_mca_bspstore - .global ia64_init_stack .text .align 16 @@ -146,23 +144,12 @@ // The following code purges TC and TR entries. Then reload all TC entries. // Purge percpu data TC entries. begin_tlb_purge_and_reload: - mov r16=cr.lid - LOAD_PHYSICAL(p0,r17,ia64_mca_tlb_list) // Physical address of ia64_mca_tlb_list - mov r19=0 - mov r20=NR_CPUS - ;; -1: cmp.eq p6,p7=r19,r20 -(p6) br.spnt.few err - ld8 r18=[r17],IA64_MCA_TLB_INFO_SIZE - ;; - add r19=1,r19 - cmp.eq p6,p7=r18,r16 -(p7) br.sptk.few 1b + GET_PERCPU_PADDR(r2) // paddr of percpu_paddr in cpuinfo struct ;; - adds r17=-IA64_MCA_TLB_INFO_SIZE,r17 + mov r17=r2 + mov r23=r2 // save current ia64_mca_percpu_info addr pointer. ;; - mov r23=r17 // save current ia64_mca_percpu_info addr pointer. - adds r17=16,r17 + adds r17=8,r17 ;; ld8 r18=[r17],8 // r18=ptce_base ;; @@ -215,7 +202,7 @@ srlz.d ;; // 3. Purge ITR for PAL code. - adds r17=48,r23 + adds r17=40,r23 ;; ld8 r16=[r17] mov r18=IA64_GRANULE_SHIFT<<2 @@ -260,7 +247,7 @@ srlz.d ;; // 2. Reload DTR register for PERCPU data. - adds r17=8,r23 + mov r17=r23 movl r16=PERCPU_ADDR // vaddr movl r18=PERCPU_PAGE_SHIFT<<2 ;; @@ -318,17 +305,14 @@ done_tlb_purge_and_reload: // Setup new stack frame for OS_MCA handling - movl r2=ia64_mca_bspstore;; // local bspstore area location in r2 - DATA_VA_TO_PA(r2);; - movl r3=ia64_mca_stackframe;; // save stack frame to memory in r3 - DATA_VA_TO_PA(r3);; + GET_MCA_BSPSTORE(r2) // paddr of bspstore save area + GET_MCA_STACKFRAME(r3);; // paddr of stack frame save area rse_switch_context(r6,r3,r2);; // RSC management in this new context - movl r12=ia64_mca_stack - mov r2=8*1024;; // stack size must be same as C array - add r12=r2,r12;; // stack base @ bottom of array - adds r12=-16,r12;; // allow 16 bytes of scratch + GET_MCA_STACK(r2);; // paddr of stack save area + // stack size must be same as C array + addl r2=8*1024-16,r2;; // stack base @ bottom of array + mov r12=r2 // allow 16 bytes of scratch // (C calling convention) - DATA_VA_TO_PA(r12);; // Enter virtual mode from physical mode VIRTUAL_MODE_ENTER(r2, r3, ia64_os_mca_virtual_begin, r4) @@ -344,9 +328,7 @@ ia64_os_mca_virtual_end: // restore the original stack frame here - movl r2=ia64_mca_stackframe // restore stack frame from memory at r2 - ;; - DATA_VA_TO_PA(r2) + GET_MCA_STACKFRAME(r2);; // phys addr of MCA save area movl r4=IA64_PSR_MC ;; rse_return_context(r4,r3,r2) // switch from interrupt context for RSE @@ -387,7 +369,7 @@ ia64_os_mca_proc_state_dump: // Save bank 1 GRs 16-31 which will be used by c-language code when we switch // to virtual addressing mode. - LOAD_PHYSICAL(p0,r2,ia64_mca_proc_state_dump)// convert OS state dump area to physical address + GET_MCA_DUMP_PADDR(r2);; // phys addr of MCA save area // save ar.NaT mov r5=ar.unat // ar.unat @@ -618,9 +600,7 @@ ia64_os_mca_proc_state_restore: // Restore bank1 GR16-31 - movl r2=ia64_mca_proc_state_dump // Convert virtual address - ;; // of OS state dump area - DATA_VA_TO_PA(r2) // to physical address + GET_MCA_DUMP_PADDR(r2);; // phys addr of proc state dump area restore_GRs: // restore bank-1 GRs 16-31 bsw.1;; diff -Nru a/arch/ia64/kernel/minstate.h b/arch/ia64/kernel/minstate.h --- a/arch/ia64/kernel/minstate.h 2005-01-05 18:28:29 -08:00 +++ b/arch/ia64/kernel/minstate.h 2005-01-05 18:28:29 -08:00 @@ -37,12 +37,15 @@ * go virtual and don't want to destroy the iip or ipsr. */ #define MINSTATE_START_SAVE_MIN_PHYS \ -(pKStk) movl sp=ia64_init_stack+IA64_STK_OFFSET-IA64_PT_REGS_SIZE; \ +(pKStk) mov r3=ar.k3;; \ +(pKStk) addl r3=IA64_CPUINFO_PA_MCA_INFO,r3;; \ +(pKStk) ld8 r3 = [r3];; \ +(pKStk) addl r3=IA64_INIT_STACK,r3;; \ +(pKStk) addl sp=IA64_STK_OFFSET-IA64_PT_REGS_SIZE,r3; \ (pUStk) mov ar.rsc=0; /* set enforced lazy mode, pl 0, little-endian, loadrs=0 */ \ (pUStk) addl r22=IA64_RBS_OFFSET,r1; /* compute base of register backing store */ \ ;; \ (pUStk) mov r24=ar.rnat; \ -(pKStk) tpa r1=sp; /* compute physical addr of sp */ \ (pUStk) addl r1=IA64_STK_OFFSET-IA64_PT_REGS_SIZE,r1; /* compute base of memory stack */ \ (pUStk) mov r23=ar.bspstore; /* save ar.bspstore */ \ (pUStk) dep r22=-1,r22,61,3; /* compute kernel virtual addr of RBS */ \ diff -Nru a/arch/ia64/kernel/salinfo.c b/arch/ia64/kernel/salinfo.c --- a/arch/ia64/kernel/salinfo.c 2005-01-05 18:28:29 -08:00 +++ b/arch/ia64/kernel/salinfo.c 2005-01-05 18:28:29 -08:00 @@ -19,6 +19,9 @@ * * Jan 28 2004 kaos@sgi.com * Periodically check for outstanding MCA or INIT records. + * + * Dec 5 2004 kaos@sgi.com + * Standardize which records are cleared automatically. */ #include @@ -230,8 +233,8 @@ } } -/* Check for outstanding MCA/INIT records every 5 minutes (arbitrary) */ -#define SALINFO_TIMER_DELAY (5*60*HZ) +/* Check for outstanding MCA/INIT records every minute (arbitrary) */ +#define SALINFO_TIMER_DELAY (60*HZ) static struct timer_list salinfo_timer; static void @@ -382,8 +385,11 @@ salinfo_log_read_cpu(void *context) { struct salinfo_data *data = context; + sal_log_record_header_t *rh; data->log_size = ia64_sal_get_state_info(data->type, (u64 *) data->log_buffer); - if (data->type == SAL_INFO_TYPE_CPE || data->type == SAL_INFO_TYPE_CMC) + rh = (sal_log_record_header_t *)(data->log_buffer); + /* Clear corrected errors as they are read from SAL */ + if (rh->severity == sal_log_severity_corrected) ia64_sal_clear_state_info(data->type); } @@ -457,6 +463,7 @@ static int salinfo_log_clear(struct salinfo_data *data, int cpu) { + sal_log_record_header_t *rh; data->state = STATE_NO_DATA; if (!test_bit(cpu, &data->cpu_event)) return 0; @@ -469,10 +476,9 @@ data->saved_num = 0; spin_unlock_irqrestore(&data_saved_lock, flags); } - /* ia64_mca_log_sal_error_record or salinfo_log_read_cpu already cleared - * CPE and CMC errors - */ - if (data->type != SAL_INFO_TYPE_CPE && data->type != SAL_INFO_TYPE_CMC) + rh = (sal_log_record_header_t *)(data->log_buffer); + /* Corrected errors have already been cleared from SAL */ + if (rh->severity != sal_log_severity_corrected) call_on_cpu(cpu, salinfo_log_clear_cpu, data); /* clearing a record may make a new record visible */ salinfo_log_new_read(cpu, data); diff -Nru a/arch/ia64/kernel/signal.c b/arch/ia64/kernel/signal.c --- a/arch/ia64/kernel/signal.c 2005-01-05 18:28:29 -08:00 +++ b/arch/ia64/kernel/signal.c 2005-01-05 18:28:29 -08:00 @@ -589,3 +589,104 @@ } return 0; } + +/* Set a delayed signal that was detected in MCA/INIT/NMI/PMI context where it + * could not be delivered. It is important that the target process is not + * allowed to do any more work in user space. Possible cases for the target + * process: + * + * - It is sleeping and will wake up soon. Store the data in the current task, + * the signal will be sent when the current task returns from the next + * interrupt. + * + * - It is running in user context. Store the data in the current task, the + * signal will be sent when the current task returns from the next interrupt. + * + * - It is running in kernel context on this or another cpu and will return to + * user context. Store the data in the target task, the signal will be sent + * to itself when the target task returns to user space. + * + * - It is running in kernel context on this cpu and will sleep before + * returning to user context. Because this is also the current task, the + * signal will not get delivered and the task could sleep indefinitely. + * Store the data in the idle task for this cpu, the signal will be sent + * after the idle task processes its next interrupt. + * + * To cover all cases, store the data in the target task, the current task and + * the idle task on this cpu. Whatever happens, the signal will be delivered + * to the target task before it can do any useful user space work. Multiple + * deliveries have no unwanted side effects. + * + * Note: This code is executed in MCA/INIT/NMI/PMI context, with interrupts + * disabled. It must not take any locks nor use kernel structures or services + * that require locks. + */ + +/* To ensure that we get the right pid, check its start time. To avoid extra + * include files in thread_info.h, convert the task start_time to unsigned long, + * giving us a cycle time of > 580 years. + */ +static inline unsigned long +start_time_ul(const struct task_struct *t) +{ + return t->start_time.tv_sec * NSEC_PER_SEC + t->start_time.tv_nsec; +} + +void +set_sigdelayed(pid_t pid, int signo, int code, void __user *addr) +{ + struct task_struct *t; + unsigned long start_time = 0; + int i; + + for (i = 1; i <= 3; ++i) { + switch (i) { + case 1: + t = find_task_by_pid(pid); + if (t) + start_time = start_time_ul(t); + break; + case 2: + t = current; + break; + default: + t = idle_task(smp_processor_id()); + break; + } + + if (!t) + return; + t->thread_info->sigdelayed.signo = signo; + t->thread_info->sigdelayed.code = code; + t->thread_info->sigdelayed.addr = addr; + t->thread_info->sigdelayed.start_time = start_time; + t->thread_info->sigdelayed.pid = pid; + wmb(); + set_tsk_thread_flag(t, TIF_SIGDELAYED); + } +} + +/* Called from entry.S when it detects TIF_SIGDELAYED, a delayed signal that + * was detected in MCA/INIT/NMI/PMI context where it could not be delivered. + */ + +void +do_sigdelayed(void) +{ + struct siginfo siginfo; + pid_t pid; + struct task_struct *t; + + clear_thread_flag(TIF_SIGDELAYED); + memset(&siginfo, 0, sizeof(siginfo)); + siginfo.si_signo = current_thread_info()->sigdelayed.signo; + siginfo.si_code = current_thread_info()->sigdelayed.code; + siginfo.si_addr = current_thread_info()->sigdelayed.addr; + pid = current_thread_info()->sigdelayed.pid; + t = find_task_by_pid(pid); + if (!t) + return; + if (current_thread_info()->sigdelayed.start_time != start_time_ul(t)) + return; + force_sig_info(siginfo.si_signo, &siginfo, t); +} diff -Nru a/arch/ia64/kernel/time.c b/arch/ia64/kernel/time.c --- a/arch/ia64/kernel/time.c 2005-01-05 18:28:29 -08:00 +++ b/arch/ia64/kernel/time.c 2005-01-05 18:28:29 -08:00 @@ -32,7 +32,7 @@ extern unsigned long wall_jiffies; -u64 jiffies_64 = INITIAL_JIFFIES; +u64 jiffies_64 __cacheline_aligned_in_smp = INITIAL_JIFFIES; EXPORT_SYMBOL(jiffies_64); diff -Nru a/arch/ia64/mm/discontig.c b/arch/ia64/mm/discontig.c --- a/arch/ia64/mm/discontig.c 2005-01-05 18:28:29 -08:00 +++ b/arch/ia64/mm/discontig.c 2005-01-05 18:28:29 -08:00 @@ -4,6 +4,10 @@ * Copyright (c) 2001 Tony Luck * Copyright (c) 2002 NEC Corp. * Copyright (c) 2002 Kimio Suganuma + * Copyright (c) 2004 Silicon Graphics, Inc + * Russ Anderson + * Jesse Barnes + * Jack Steiner */ /* @@ -22,6 +26,7 @@ #include #include #include +#include /* * Track per-node information needed to setup the boot memory allocator, the @@ -220,12 +225,34 @@ } /** + * early_nr_phys_cpus_node - return number of physical cpus on a given node + * @node: node to check + * + * Count the number of physical cpus on @node. These are cpus that actually + * exist. We can't use nr_cpus_node() yet because + * acpi_boot_init() (which builds the node_to_cpu_mask array) hasn't been + * called yet. + */ +static int early_nr_phys_cpus_node(int node) +{ + int cpu, n = 0; + + for (cpu = 0; cpu < NR_CPUS; cpu++) + if (node == node_cpuid[cpu].nid) + if ((cpu == 0) || node_cpuid[cpu].phys_id) + n++; + + return n; +} + + +/** * early_nr_cpus_node - return number of cpus on a given node * @node: node to check * * Count the number of cpus on @node. We can't use nr_cpus_node() yet because * acpi_boot_init() (which builds the node_to_cpu_mask array) hasn't been - * called yet. + * called yet. Note that node 0 will also count all non-existent cpus. */ static int early_nr_cpus_node(int node) { @@ -252,12 +279,15 @@ * | | * |~~~~~~~~~~~~~~~~~~~~~~~~| <-- NODEDATA_ALIGN(start, node) for the first * | PERCPU_PAGE_SIZE * | start and length big enough - * | NR_CPUS | + * | cpus_on_this_node | Node 0 will also have entries for all non-existent cpus. * |------------------------| * | local pg_data_t * | * |------------------------| * | local ia64_node_data | * |------------------------| + * | MCA/INIT data * | + * | cpus_on_this_node | + * |------------------------| * | ??? | * |________________________| * @@ -269,9 +299,9 @@ static int __init find_pernode_space(unsigned long start, unsigned long len, int node) { - unsigned long epfn, cpu, cpus; + unsigned long epfn, cpu, cpus, phys_cpus; unsigned long pernodesize = 0, pernode, pages, mapsize; - void *cpu_data; + void *cpu_data, *mca_data_phys; struct bootmem_data *bdp = &mem_data[node].bootmem_data; epfn = (start + len) >> PAGE_SHIFT; @@ -295,9 +325,11 @@ * for good alignment and alias prevention. */ cpus = early_nr_cpus_node(node); + phys_cpus = early_nr_phys_cpus_node(node); pernodesize += PERCPU_PAGE_SIZE * cpus; pernodesize += L1_CACHE_ALIGN(sizeof(pg_data_t)); pernodesize += L1_CACHE_ALIGN(sizeof(struct ia64_node_data)); + pernodesize += L1_CACHE_ALIGN(sizeof(ia64_mca_cpu_t)) * phys_cpus; pernodesize = PAGE_ALIGN(pernodesize); pernode = NODEDATA_ALIGN(start, node); @@ -316,6 +348,9 @@ mem_data[node].node_data = __va(pernode); pernode += L1_CACHE_ALIGN(sizeof(struct ia64_node_data)); + mca_data_phys = (void *)pernode; + pernode += L1_CACHE_ALIGN(sizeof(ia64_mca_cpu_t)) * phys_cpus; + mem_data[node].pgdat->bdata = bdp; pernode += L1_CACHE_ALIGN(sizeof(pg_data_t)); @@ -328,6 +363,20 @@ if (node == node_cpuid[cpu].nid) { memcpy(__va(cpu_data), __phys_per_cpu_start, __per_cpu_end - __per_cpu_start); + if ((cpu == 0) || (node_cpuid[cpu].phys_id > 0)) { + /* + * The memory for the cpuinfo structure is allocated + * here, but the data in the structure is initialized + * later. Save the physical address of the MCA save + * area in IA64_KR_PA_CPU_INFO. When the cpuinfo struct + * is initialized, the value in IA64_KR_PA_CPU_INFO + * will be put in the cpuinfo structure and + * IA64_KR_PA_CPU_INFO will be set to the physical + * addresss of the cpuinfo structure. + */ + ia64_set_kr(IA64_KR_PA_CPU_INFO, __pa(mca_data_phys)); + mca_data_phys += L1_CACHE_ALIGN(sizeof(ia64_mca_cpu_t)); + } __per_cpu_offset[cpu] = (char*)__va(cpu_data) - __per_cpu_start; cpu_data += PERCPU_PAGE_SIZE; diff -Nru a/arch/ia64/mm/init.c b/arch/ia64/mm/init.c --- a/arch/ia64/mm/init.c 2005-01-05 18:28:29 -08:00 +++ b/arch/ia64/mm/init.c 2005-01-05 18:28:29 -08:00 @@ -40,6 +40,7 @@ DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); extern void ia64_tlb_init (void); +extern void efi_get_pal_addr (void); unsigned long MAX_DMA_ADDRESS = PAGE_OFFSET + 0x100000000UL; @@ -296,7 +297,7 @@ { unsigned long psr, pta, impl_va_bits; extern void __devinit tlb_init (void); - int cpu; + struct cpuinfo_ia64 *cpuinfo; #ifdef CONFIG_DISABLE_VHPT # define VHPT_ENABLE_BIT 0 @@ -362,19 +363,21 @@ ia64_srlz_d(); #endif - cpu = smp_processor_id(); + /* + * The MCA info structure was allocated earlier and a physical address pointer + * saved in k3. Move that pointer into the cpuinfo structure and save + * the physical address of the cpuinfo structure in k3. + */ + cpuinfo = (struct cpuinfo_ia64 *)my_cpu_data; + cpuinfo->ia64_pa_mca_data = (__u64 *)ia64_get_kr(IA64_KR_PA_CPU_INFO); - /* mca handler uses cr.lid as key to pick the right entry */ - ia64_mca_tlb_list[cpu].cr_lid = ia64_getreg(_IA64_REG_CR_LID); + cpuinfo->percpu_paddr = pte_val(mk_pte_phys(__pa(my_cpu_data), PAGE_KERNEL)); + ia64_set_kr(IA64_KR_PA_CPU_INFO, __pa(my_cpu_data)); - /* insert this percpu data information into our list for MCA recovery purposes */ - ia64_mca_tlb_list[cpu].percpu_paddr = pte_val(mk_pte_phys(__pa(my_cpu_data), PAGE_KERNEL)); - /* Also save per-cpu tlb flush recipe for use in physical mode mca handler */ - ia64_mca_tlb_list[cpu].ptce_base = local_cpu_data->ptce_base; - ia64_mca_tlb_list[cpu].ptce_count[0] = local_cpu_data->ptce_count[0]; - ia64_mca_tlb_list[cpu].ptce_count[1] = local_cpu_data->ptce_count[1]; - ia64_mca_tlb_list[cpu].ptce_stride[0] = local_cpu_data->ptce_stride[0]; - ia64_mca_tlb_list[cpu].ptce_stride[1] = local_cpu_data->ptce_stride[1]; + /* + * Set pal_base and pal_paddr in cpuinfo structure. + */ + efi_get_pal_addr(); } #ifdef CONFIG_VIRTUAL_MEM_MAP diff -Nru a/arch/ia64/sn/kernel/iomv.c b/arch/ia64/sn/kernel/iomv.c --- a/arch/ia64/sn/kernel/iomv.c 2005-01-05 18:28:29 -08:00 +++ b/arch/ia64/sn/kernel/iomv.c 2005-01-05 18:28:29 -08:00 @@ -42,8 +42,7 @@ */ if ((port >= 0x1f0 && port <= 0x1f7) || port == 0x3f6 || port == 0x3f7) { - io_base = (0xc000000fcc000000UL | - ((unsigned long)get_nasid() << 38)); + io_base = GLOBAL_MMR_ADDR(get_nasid(), 0xfcc000000UL); addr = io_base | ((port >> 2) << 12) | (port & 0xfff); } else { addr = __ia64_get_io_port_base() | ((port >> 2) << 2); @@ -66,9 +65,10 @@ */ void __sn_mmiowb(void) { - while ((((volatile unsigned long)(*pda->pio_write_status_addr)) & - SH_PIO_WRITE_STATUS_0_PENDING_WRITE_COUNT_MASK) != - SH_PIO_WRITE_STATUS_0_PENDING_WRITE_COUNT_MASK) + volatile unsigned long *adr = pda->pio_write_status_addr; + unsigned long val = pda->pio_write_status_val; + + while ((*adr & SH_PIO_WRITE_STATUS_PENDING_WRITE_COUNT_MASK) != val) cpu_relax(); } diff -Nru a/arch/ia64/sn/kernel/irq.c b/arch/ia64/sn/kernel/irq.c --- a/arch/ia64/sn/kernel/irq.c 2005-01-05 18:28:29 -08:00 +++ b/arch/ia64/sn/kernel/irq.c 2005-01-05 18:28:29 -08:00 @@ -204,7 +204,7 @@ struct irq_desc *sn_irq_desc(unsigned int irq) { - return (_irq_desc + irq); + return (irq_desc + irq); } u8 sn_irq_to_vector(unsigned int irq) @@ -220,7 +220,7 @@ void sn_irq_init(void) { int i; - irq_desc_t *base_desc = _irq_desc; + irq_desc_t *base_desc = irq_desc; for (i = 0; i < NR_IRQS; i++) { if (base_desc[i].handler == &no_irq_type) { diff -Nru a/arch/ia64/sn/kernel/setup.c b/arch/ia64/sn/kernel/setup.c --- a/arch/ia64/sn/kernel/setup.c 2005-01-05 18:28:29 -08:00 +++ b/arch/ia64/sn/kernel/setup.c 2005-01-05 18:28:29 -08:00 @@ -40,7 +40,6 @@ #include #include #include -#include "shub.h" #include #include #include @@ -215,8 +214,10 @@ unsigned long id; int rev; - id = REMOTE_HUB_L(nasid, SH_SHUB_ID); - rev = (id & SH_SHUB_ID_REVISION_MASK) >> SH_SHUB_ID_REVISION_SHFT; + if (is_shub2()) + return 0; + id = REMOTE_HUB_L(nasid, SH1_SHUB_ID); + rev = (id & SH1_SHUB_ID_REVISION_MASK) >> SH1_SHUB_ID_REVISION_SHFT; return rev <= 2; } @@ -224,9 +225,13 @@ { int cnode; - for (cnode = 0; cnode < numnodes; cnode++) - if (is_shub_1_1(cnodeid_to_nasid(cnode))) - shub_1_1_found = 1; + if (is_shub2()) { + /* none yet */ + } else { + for (cnode = 0; cnode < numnodes; cnode++) + if (is_shub_1_1(cnodeid_to_nasid(cnode))) + shub_1_1_found = 1; + } } /** @@ -340,7 +345,7 @@ * * One time setup for Node Data Area. Called by sn_setup(). */ -void __init sn_init_pdas(char **cmdline_p) +static void __init sn_init_pdas(char **cmdline_p) { cnodeid_t cnode; @@ -416,8 +421,17 @@ int slice; int cnode; int i; + u64 shubtype, nasid_bitmask, nasid_shift; static int wars_have_been_checked; + memset(pda, 0, sizeof(pda)); + if (ia64_sn_get_hub_info(0, &shubtype, &nasid_bitmask, &nasid_shift)) + BUG(); + pda->shub2 = (u8)shubtype; + pda->nasid_bitmask = (u16)nasid_bitmask; + pda->nasid_shift = (u8)nasid_shift; + pda->as_shift = pda->nasid_shift - 2; + /* * The boot cpu makes this call again after platform initialization is * complete. @@ -441,7 +455,6 @@ cnode = nasid_to_cnodeid(nasid); - memset(pda, 0, sizeof(pda)); pda->p_nodepda = nodepdaindr[cnode]; pda->led_address = (typeof(pda->led_address)) (LED0 + (slice << LED_CPU_SHIFT)); @@ -469,25 +482,29 @@ pda->shub_1_1_found = shub_1_1_found; /* - * We must use different memory allocators for first cpu (bootmem - * allocator) than for the other cpus (regular allocator). + * Set up addresses of PIO/MEM write status registers. */ - pda->pio_write_status_addr = (volatile unsigned long *) - LOCAL_MMR_ADDR((slice < - 2 ? SH_PIO_WRITE_STATUS_0 : SH_PIO_WRITE_STATUS_1)); - pda->mem_write_status_addr = (volatile u64 *) - LOCAL_MMR_ADDR((slice < - 2 ? SH_MEMORY_WRITE_STATUS_0 : - SH_MEMORY_WRITE_STATUS_1)); + { + u64 pio1[] = {SH1_PIO_WRITE_STATUS_0, 0, SH1_PIO_WRITE_STATUS_1, 0}; + u64 pio2[] = {SH2_PIO_WRITE_STATUS_0, SH2_PIO_WRITE_STATUS_1, + SH2_PIO_WRITE_STATUS_2, SH2_PIO_WRITE_STATUS_3}; + u64 *pio; + pio = is_shub1() ? pio1 : pio2; + pda->pio_write_status_addr = (volatile unsigned long *) LOCAL_MMR_ADDR(pio[slice]); + pda->pio_write_status_val = is_shub1() ? SH_PIO_WRITE_STATUS_PENDING_WRITE_COUNT_MASK : 0; + } - if (local_node_data->active_cpu_count++ == 0) { + /* + * WAR addresses for SHUB 1.x. + */ + if (local_node_data->active_cpu_count++ == 0 && is_shub1()) { int buddy_nasid; buddy_nasid = cnodeid_to_nasid(numa_node_id() == numnodes - 1 ? 0 : numa_node_id() + 1); pda->pio_shub_war_cam_addr = (volatile unsigned long *)GLOBAL_MMR_ADDR(nasid, - SH_PI_CAM_CONTROL); + SH1_PI_CAM_CONTROL); } } diff -Nru a/arch/ia64/sn/kernel/sn2/ptc_deadlock.S b/arch/ia64/sn/kernel/sn2/ptc_deadlock.S --- a/arch/ia64/sn/kernel/sn2/ptc_deadlock.S 2005-01-05 18:28:29 -08:00 +++ b/arch/ia64/sn/kernel/sn2/ptc_deadlock.S 2005-01-05 18:28:29 -08:00 @@ -8,34 +8,33 @@ #include -#define ZEROVAL 0x3f // "zero" value for outstanding PIO requests -#define DEADLOCKBIT SH_PIO_WRITE_STATUS_0_WRITE_DEADLOCK_SHFT -#define WRITECOUNT SH_PIO_WRITE_STATUS_0_PENDING_WRITE_COUNT_SHFT -#define ALIAS_OFFSET (SH_PIO_WRITE_STATUS_0_ALIAS-SH_PIO_WRITE_STATUS_0) +#define DEADLOCKBIT SH_PIO_WRITE_STATUS_WRITE_DEADLOCK_SHFT +#define WRITECOUNTMASK SH_PIO_WRITE_STATUS_PENDING_WRITE_COUNT_MASK +#define ALIAS_OFFSET (SH1_PIO_WRITE_STATUS_0_ALIAS-SH1_PIO_WRITE_STATUS_0) .global sn2_ptc_deadlock_recovery_core .proc sn2_ptc_deadlock_recovery_core sn2_ptc_deadlock_recovery_core: - .regstk 5,0,0,0 + .regstk 6,0,0,0 ptc0 = in0 data0 = in1 ptc1 = in2 data1 = in3 piowc = in4 + zeroval = in5 piowcphy = r30 psrsave = r2 - zeroval = r3 scr1 = r16 scr2 = r17 + mask = r18 extr.u piowcphy=piowc,0,61;; // Convert piowc to uncached physical address dep piowcphy=-1,piowcphy,63,1 - - mov zeroval=ZEROVAL // "zero" value for PIO write count + movl mask=WRITECOUNTMASK 1: add scr2=ALIAS_OFFSET,piowc // Address of WRITE_STATUS alias register @@ -43,7 +42,7 @@ st8.rel [scr2]=scr1;; 5: ld8.acq scr1=[piowc];; // Wait for PIOs to complete. - extr.u scr2=scr1,WRITECOUNT,7;;// PIO count + and scr2=scr1,mask;; // mask of writecount bits cmp.ne p6,p0=zeroval,scr2 (p6) br.cond.sptk 5b @@ -57,16 +56,17 @@ st8.rel [ptc0]=data0 // Write PTC0 & wait for completion. 5: ld8.acq scr1=[piowcphy];; // Wait for PIOs to complete. - extr.u scr2=scr1,WRITECOUNT,7;;// PIO count + and scr2=scr1,mask;; // mask of writecount bits cmp.ne p6,p0=zeroval,scr2 (p6) br.cond.sptk 5b;; tbit.nz p8,p7=scr1,DEADLOCKBIT;;// Test for DEADLOCK +(p7) cmp.ne p7,p0=r0,ptc1;; // Test for non-null ptc1 (p7) st8.rel [ptc1]=data1;; // Now write PTC1. 5: ld8.acq scr1=[piowcphy];; // Wait for PIOs to complete. - extr.u scr2=scr1,WRITECOUNT,7;;// PIO count + and scr2=scr1,mask;; // mask of writecount bits cmp.ne p6,p0=zeroval,scr2 (p6) br.cond.sptk 5b diff -Nru a/arch/ia64/sn/kernel/sn2/sn2_smp.c b/arch/ia64/sn/kernel/sn2/sn2_smp.c --- a/arch/ia64/sn/kernel/sn2/sn2_smp.c 2005-01-05 18:28:29 -08:00 +++ b/arch/ia64/sn/kernel/sn2/sn2_smp.c 2005-01-05 18:28:29 -08:00 @@ -38,7 +38,8 @@ #include #include -void sn2_ptc_deadlock_recovery(unsigned long data0, unsigned long data1); +void sn2_ptc_deadlock_recovery(volatile unsigned long *, unsigned long data0, + volatile unsigned long *, unsigned long data1); static spinlock_t sn2_global_ptc_lock __cacheline_aligned = SPIN_LOCK_UNLOCKED; @@ -46,15 +47,14 @@ static inline unsigned long wait_piowc(void) { - volatile unsigned long *piows; + volatile unsigned long *piows, zeroval; unsigned long ws; piows = pda->pio_write_status_addr; + zeroval = pda->pio_write_status_val; do { - ia64_mfa(); - } while (((ws = - *piows) & SH_PIO_WRITE_STATUS_0_PENDING_WRITE_COUNT_MASK) != - SH_PIO_WRITE_STATUS_0_PENDING_WRITE_COUNT_MASK); + cpu_relax(); + } while (((ws = *piows) & SH_PIO_WRITE_STATUS_PENDING_WRITE_COUNT_MASK) != zeroval); return ws; } @@ -88,9 +88,9 @@ sn2_global_tlb_purge(unsigned long start, unsigned long end, unsigned long nbits) { - int i, cnode, mynasid, cpu, lcpu = 0, nasid, flushed = 0; + int i, shub1, cnode, mynasid, cpu, lcpu = 0, nasid, flushed = 0; volatile unsigned long *ptc0, *ptc1; - unsigned long flags = 0, data0, data1; + unsigned long flags = 0, data0 = 0, data1 = 0; struct mm_struct *mm = current->active_mm; short nasids[NR_NODES], nix; DECLARE_BITMAP(nodes_flushed, NR_NODES); @@ -129,28 +129,42 @@ cnode = find_next_bit(&nodes_flushed, NR_NODES, ++cnode)) nasids[nix++] = cnodeid_to_nasid(cnode); - data0 = (1UL << SH_PTC_0_A_SHFT) | - (nbits << SH_PTC_0_PS_SHFT) | - ((ia64_get_rr(start) >> 8) << SH_PTC_0_RID_SHFT) | - (1UL << SH_PTC_0_START_SHFT); - - ptc0 = (long *)GLOBAL_MMR_PHYS_ADDR(0, SH_PTC_0); - ptc1 = (long *)GLOBAL_MMR_PHYS_ADDR(0, SH_PTC_1); + shub1 = is_shub1(); + if (shub1) { + data0 = (1UL << SH1_PTC_0_A_SHFT) | + (nbits << SH1_PTC_0_PS_SHFT) | + ((ia64_get_rr(start) >> 8) << SH1_PTC_0_RID_SHFT) | + (1UL << SH1_PTC_0_START_SHFT); + ptc0 = (long *)GLOBAL_MMR_PHYS_ADDR(0, SH1_PTC_0); + ptc1 = (long *)GLOBAL_MMR_PHYS_ADDR(0, SH1_PTC_1); + } else { + data0 = (1UL << SH2_PTC_A_SHFT) | + (nbits << SH2_PTC_PS_SHFT) | + (1UL << SH2_PTC_START_SHFT); + ptc0 = (long *)GLOBAL_MMR_PHYS_ADDR(0, SH2_PTC + + ((ia64_get_rr(start) >> 8) << SH2_PTC_RID_SHFT) ); + ptc1 = NULL; + } + mynasid = get_nasid(); spin_lock_irqsave(&sn2_global_ptc_lock, flags); do { - data1 = start | (1UL << SH_PTC_1_START_SHFT); + if (shub1) + data1 = start | (1UL << SH1_PTC_1_START_SHFT); + else + data0 = (data0 & ~SH2_PTC_ADDR_MASK) | (start & SH2_PTC_ADDR_MASK); for (i = 0; i < nix; i++) { nasid = nasids[i]; - if (likely(nasid == mynasid)) { + if (unlikely(nasid == mynasid)) { ia64_ptcga(start, nbits << 2); ia64_srlz_i(); } else { ptc0 = CHANGE_NASID(nasid, ptc0); - ptc1 = CHANGE_NASID(nasid, ptc1); + if (ptc1) + ptc1 = CHANGE_NASID(nasid, ptc1); pio_atomic_phys_write_mmrs(ptc0, data0, ptc1, data1); flushed = 1; @@ -159,8 +173,8 @@ if (flushed && (wait_piowc() & - SH_PIO_WRITE_STATUS_0_WRITE_DEADLOCK_MASK)) { - sn2_ptc_deadlock_recovery(data0, data1); + SH_PIO_WRITE_STATUS_WRITE_DEADLOCK_MASK)) { + sn2_ptc_deadlock_recovery(ptc0, data0, ptc1, data1); } start += (1UL << nbits); @@ -179,18 +193,19 @@ * TLB flush transaction. The recovery sequence is somewhat tricky & is * coded in assembly language. */ -void sn2_ptc_deadlock_recovery(unsigned long data0, unsigned long data1) +void sn2_ptc_deadlock_recovery(volatile unsigned long *ptc0, unsigned long data0, + volatile unsigned long *ptc1, unsigned long data1) { - extern void sn2_ptc_deadlock_recovery_core(long *, long, long *, long, - long *); + extern void sn2_ptc_deadlock_recovery_core(volatile unsigned long *, unsigned long, + volatile unsigned long *, unsigned long, volatile unsigned long *, unsigned long); int cnode, mycnode, nasid; - long *ptc0, *ptc1, *piows; + volatile unsigned long *piows; + volatile unsigned long zeroval; sn2_ptc_deadlock_count++; - ptc0 = (long *)GLOBAL_MMR_PHYS_ADDR(0, SH_PTC_0); - ptc1 = (long *)GLOBAL_MMR_PHYS_ADDR(0, SH_PTC_1); - piows = (long *)pda->pio_write_status_addr; + piows = pda->pio_write_status_addr; + zeroval = pda->pio_write_status_val; mycnode = numa_node_id(); @@ -199,8 +214,9 @@ continue; nasid = cnodeid_to_nasid(cnode); ptc0 = CHANGE_NASID(nasid, ptc0); - ptc1 = CHANGE_NASID(nasid, ptc1); - sn2_ptc_deadlock_recovery_core(ptc0, data0, ptc1, data1, piows); + if (ptc1) + ptc1 = CHANGE_NASID(nasid, ptc1); + sn2_ptc_deadlock_recovery_core(ptc0, data0, ptc1, data1, piows, zeroval); } } diff -Nru a/arch/ia64/sn/kernel/sn2/timer.c b/arch/ia64/sn/kernel/sn2/timer.c --- a/arch/ia64/sn/kernel/sn2/timer.c 2005-01-05 18:28:29 -08:00 +++ b/arch/ia64/sn/kernel/sn2/timer.c 2005-01-05 18:28:29 -08:00 @@ -15,7 +15,6 @@ #include #include -#include "shub.h" #include #include #include @@ -26,12 +25,12 @@ .drift = -1, .shift = 10, .mask = (1LL << 55) - 1, - .source = TIME_SOURCE_MMIO64, - .addr = RTC_COUNTER_ADDR + .source = TIME_SOURCE_MMIO64 }; void __init sn_timer_init(void) { sn2_interpolator.frequency = sn_rtc_cycles_per_second; + sn2_interpolator.addr = RTC_COUNTER_ADDR; register_time_interpolator(&sn2_interpolator); } diff -Nru a/arch/ia64/sn/kernel/sn2/timer_interrupt.c b/arch/ia64/sn/kernel/sn2/timer_interrupt.c --- a/arch/ia64/sn/kernel/sn2/timer_interrupt.c 2005-01-05 18:28:29 -08:00 +++ b/arch/ia64/sn/kernel/sn2/timer_interrupt.c 2005-01-05 18:28:29 -08:00 @@ -34,7 +34,6 @@ #include #include -#include "shub.h" #include extern void sn_lb_int_war_check(void); diff -Nru a/include/asm-ia64/hardirq.h b/include/asm-ia64/hardirq.h --- a/include/asm-ia64/hardirq.h 2005-01-05 18:28:29 -08:00 +++ b/include/asm-ia64/hardirq.h 2005-01-05 18:28:29 -08:00 @@ -34,4 +34,6 @@ extern void __iomem *ipi_base_addr; +void ack_bad_irq(unsigned int irq); + #endif /* _ASM_IA64_HARDIRQ_H */ diff -Nru a/include/asm-ia64/hw_irq.h b/include/asm-ia64/hw_irq.h --- a/include/asm-ia64/hw_irq.h 2005-01-05 18:28:29 -08:00 +++ b/include/asm-ia64/hw_irq.h 2005-01-05 18:28:29 -08:00 @@ -96,13 +96,13 @@ * Default implementations for the irq-descriptor API: */ -extern irq_desc_t _irq_desc[NR_IRQS]; +extern irq_desc_t irq_desc[NR_IRQS]; #ifndef CONFIG_IA64_GENERIC static inline irq_desc_t * __ia64_irq_desc (unsigned int irq) { - return _irq_desc + irq; + return irq_desc + irq; } static inline ia64_vector diff -Nru a/include/asm-ia64/kregs.h b/include/asm-ia64/kregs.h --- a/include/asm-ia64/kregs.h 2005-01-05 18:28:29 -08:00 +++ b/include/asm-ia64/kregs.h 2005-01-05 18:28:29 -08:00 @@ -14,6 +14,7 @@ */ #define IA64_KR_IO_BASE 0 /* ar.k0: legacy I/O base address */ #define IA64_KR_TSSD 1 /* ar.k1: IVE uses this as the TSSD */ +#define IA64_KR_PA_CPU_INFO 3 /* ar.k3: phys addr of this cpu's cpu_info struct */ #define IA64_KR_CURRENT_STACK 4 /* ar.k4: what's mapped in IA64_TR_CURRENT_STACK */ #define IA64_KR_FPU_OWNER 5 /* ar.k5: fpu-owner (UP only, at the moment) */ #define IA64_KR_CURRENT 6 /* ar.k6: "current" task pointer */ diff -Nru a/include/asm-ia64/mca.h b/include/asm-ia64/mca.h --- a/include/asm-ia64/mca.h 2005-01-05 18:28:29 -08:00 +++ b/include/asm-ia64/mca.h 2005-01-05 18:28:29 -08:00 @@ -5,6 +5,7 @@ * Copyright (C) 1999, 2004 Silicon Graphics, Inc. * Copyright (C) Vijay Chander (vijay@engr.sgi.com) * Copyright (C) Srinivasa Thirumalachar (sprasad@engr.sgi.com) + * Copyright (C) Russ Anderson (rja@sgi.com) */ #ifndef _ASM_IA64_MCA_H @@ -48,17 +49,6 @@ IA64_MCA_RENDEZ_CHECKIN_DONE = 0x1 }; -/* the following data structure is used for TLB error recovery purposes */ -extern struct ia64_mca_tlb_info { - u64 cr_lid; - u64 percpu_paddr; - u64 ptce_base; - u32 ptce_count[2]; - u32 ptce_stride[2]; - u64 pal_paddr; - u64 pal_base; -} ia64_mca_tlb_list[NR_CPUS]; - /* Information maintained by the MC infrastructure */ typedef struct ia64_mc_info_s { u64 imi_mca_handler; @@ -111,6 +101,18 @@ * back to SAL from OS after MCA handling. */ } ia64_mca_os_to_sal_state_t; + +#define IA64_MCA_STACK_SIZE 1024 +#define IA64_MCA_STACK_SIZE_BYTES (1024 * 8) +#define IA64_MCA_BSPSTORE_SIZE 1024 + +typedef struct ia64_mca_cpu_s { + u64 ia64_mca_stack[IA64_MCA_STACK_SIZE] __attribute__((aligned(16))); + u64 ia64_mca_proc_state_dump[512] __attribute__((aligned(16))); + u64 ia64_mca_stackframe[32] __attribute__((aligned(16))); + u64 ia64_mca_bspstore[IA64_MCA_BSPSTORE_SIZE] __attribute__((aligned(16))); + u64 ia64_init_stack[KERNEL_STACK_SIZE] __attribute__((aligned(16))); +} ia64_mca_cpu_t; extern void ia64_mca_init(void); extern void ia64_os_mca_dispatch(void); diff -Nru a/include/asm-ia64/mca_asm.h b/include/asm-ia64/mca_asm.h --- a/include/asm-ia64/mca_asm.h 2005-01-05 18:28:29 -08:00 +++ b/include/asm-ia64/mca_asm.h 2005-01-05 18:28:29 -08:00 @@ -47,6 +47,37 @@ dep addr = temp, addr, 61, 3 /* + * This macro gets the physical address of this cpu's cpuinfo structure. + */ +#define GET_PERCPU_PADDR(reg) \ + mov reg = ar.k3;; \ + addl reg = IA64_CPUINFO_PERCPU_PADDR,reg + +/* + * This macro gets the physical address of this cpu's MCA save structure. + */ +#define GET_CPUINFO_MCA_PADDR(reg) \ + mov reg = ar.k3;; \ + addl reg = IA64_CPUINFO_PA_MCA_INFO,reg;; \ + ld8 reg = [reg] + +#define GET_MCA_BSPSTORE(reg) \ + GET_CPUINFO_MCA_PADDR(reg);; \ + addl reg = IA64_MCA_BSPSTORE,reg + +#define GET_MCA_STACKFRAME(reg) \ + GET_CPUINFO_MCA_PADDR(reg);; \ + addl reg = IA64_MCA_STACKFRAME,reg + +#define GET_MCA_STACK(reg) \ + GET_CPUINFO_MCA_PADDR(reg);; \ + addl reg = IA64_MCA_STACK,reg + +#define GET_MCA_DUMP_PADDR(reg) \ + GET_CPUINFO_MCA_PADDR(reg);; \ + addl reg = IA64_MCA_PROC_STATE_DUMP,reg + +/* * This macro jumps to the instruction at the given virtual address * and starts execution in physical mode with all the address * translations turned off. diff -Nru a/include/asm-ia64/msi.h b/include/asm-ia64/msi.h --- a/include/asm-ia64/msi.h 2005-01-05 18:28:29 -08:00 +++ b/include/asm-ia64/msi.h 2005-01-05 18:28:29 -08:00 @@ -12,7 +12,6 @@ static inline void set_intr_gate (int nr, void *func) {} #define IO_APIC_VECTOR(irq) (irq) #define ack_APIC_irq ia64_eoi -#define irq_desc _irq_desc #define cpu_mask_to_apicid(mask) cpu_physical_id(first_cpu(mask)) #define MSI_DEST_MODE MSI_PHYSICAL_MODE #define MSI_TARGET_CPU ((ia64_getreg(_IA64_REG_CR_LID) >> 16) & 0xffff) diff -Nru a/include/asm-ia64/processor.h b/include/asm-ia64/processor.h --- a/include/asm-ia64/processor.h 2005-01-05 18:28:29 -08:00 +++ b/include/asm-ia64/processor.h 2005-01-05 18:28:29 -08:00 @@ -151,9 +151,12 @@ __u64 itc_freq; /* frequency of ITC counter */ __u64 proc_freq; /* frequency of processor */ __u64 cyc_per_usec; /* itc_freq/1000000 */ + __u64 percpu_paddr; __u64 ptce_base; __u32 ptce_count[2]; __u32 ptce_stride[2]; + __u64 pal_paddr; + __u64 pal_base; struct task_struct *ksoftirqd; /* kernel softirq daemon for this CPU */ #ifdef CONFIG_SMP @@ -174,6 +177,7 @@ #ifdef CONFIG_NUMA struct ia64_node_data *node_data; #endif + __u64 *ia64_pa_mca_data; /* prt to MCA/INIT processor state */ }; DECLARE_PER_CPU(struct cpuinfo_ia64, cpu_info); diff -Nru a/include/asm-ia64/sal.h b/include/asm-ia64/sal.h --- a/include/asm-ia64/sal.h 2005-01-05 18:28:29 -08:00 +++ b/include/asm-ia64/sal.h 2005-01-05 18:28:29 -08:00 @@ -325,6 +325,10 @@ efi_guid_t platform_guid; /* Unique OEM Platform ID */ } sal_log_record_header_t; +#define sal_log_severity_recoverable 0 +#define sal_log_severity_fatal 1 +#define sal_log_severity_corrected 2 + /* Definition of log section header structures */ typedef struct sal_log_sec_header { efi_guid_t guid; /* Unique Section ID */ diff -Nru a/include/asm-ia64/signal.h b/include/asm-ia64/signal.h --- a/include/asm-ia64/signal.h 2005-01-05 18:28:29 -08:00 +++ b/include/asm-ia64/signal.h 2005-01-05 18:28:29 -08:00 @@ -177,6 +177,8 @@ #define ptrace_signal_deliver(regs, cookie) do { } while (0) +void set_sigdelayed(pid_t pid, int signo, int code, void __user *addr); + #endif /* __KERNEL__ */ # endif /* !__ASSEMBLY__ */ diff -Nru a/include/asm-ia64/sn/addrs.h b/include/asm-ia64/sn/addrs.h --- a/include/asm-ia64/sn/addrs.h 2005-01-05 18:28:29 -08:00 +++ b/include/asm-ia64/sn/addrs.h 2005-01-05 18:28:29 -08:00 @@ -9,204 +9,175 @@ #ifndef _ASM_IA64_SN_ADDRS_H #define _ASM_IA64_SN_ADDRS_H +#include +#include +#include -/* McKinley Address Format: - * - * 4 4 3 3 3 3 - * 9 8 8 7 6 5 0 - * +-+---------+----+--------------+ - * |0| Node ID | AS | Node Offset | - * +-+---------+----+--------------+ +/* + * Memory/SHUB Address Format: + * +-+---------+--+--------------+ + * |0| NASID |AS| NodeOffset | + * +-+---------+--+--------------+ * - * Node ID: If bit 38 = 1, is ICE, else is SHUB - * AS: Address Space Identifier. Used only if bit 38 = 0. - * b'00: Local Resources and MMR space - * bit 35 + * NASID: (low NASID bit is 0) Memory and SHUB MMRs + * AS: 2-bit Address Space Identifier. Used only if low NASID bit is 0 + * 00: Local Resources and MMR space + * Top bit of NodeOffset * 0: Local resources space * node id: * 0: IA64/NT compatibility space * 2: Local MMR Space * 4: Local memory, regardless of local node id * 1: Global MMR space - * b'01: GET space. - * b'10: AMO space. - * b'11: Cacheable memory space. + * 01: GET space. + * 10: AMO space. + * 11: Cacheable memory space. * * NodeOffset: byte offset + * + * + * TIO address format: + * +-+----------+--+--------------+ + * |0| NASID |AS| Nodeoffset | + * +-+----------+--+--------------+ + * + * NASID: (low NASID bit is 1) TIO + * AS: 2-bit Chiplet Identifier + * 00: TIO LB (Indicates TIO MMR access.) + * 01: TIO ICE (indicates coretalk space access.) + * + * NodeOffset: top bit must be set. + * + * + * Note that in both of the above address formats, the low + * NASID bit indicates if the reference is to the SHUB or TIO MMRs. */ -/* TIO address format: - * 4 4 3 3 3 3 3 0 - * 9 8 8 7 6 5 4 - * +-+----------+-+---+--------------+ - * |0| Node ID |0|CID| Node offset | - * +-+----------+-+---+--------------+ - * - * Node ID: if bit 38 == 1, is ICE. - * Bit 37: Must be zero. - * CID: Chiplet ID: - * b'01: TIO LB (Indicates TIO MMR access.) - * b'11: TIO ICE (indicates coretalk space access.) - * Node offset: byte offest. + +/* + * Define basic shift & mask constants for manipulating NASIDs and AS values. */ +#define NASID_BITMASK (pda->nasid_bitmask) +#define NASID_SHIFT (pda->nasid_shift) +#define AS_SHIFT (pda->as_shift) +#define AS_BITMASK 0x3UL + +#define NASID_MASK ((u64)NASID_BITMASK << NASID_SHIFT) +#define AS_MASK ((u64)AS_BITMASK << AS_SHIFT) +#define REGION_BITS 0xe000000000000000UL + /* - * Note that in both of the above address formats, bit - * 35 set indicates that the reference is to the - * shub or tio MMRs. - */ - -#ifndef __ASSEMBLY__ -typedef union ia64_sn2_pa { - struct { - unsigned long off : 36; - unsigned long as : 2; - unsigned long nasid: 11; - unsigned long fill : 15; - } f; - unsigned long l; - void *p; -} ia64_sn2_pa_t; -#endif - -#define TO_PHYS_MASK 0x0001ffcfffffffffUL /* Note - clear AS bits */ - - -/* Regions determined by AS */ -#define LOCAL_MMR_SPACE 0xc000008000000000UL /* Local MMR space */ -#define LOCAL_PHYS_MMR_SPACE 0x8000008000000000UL /* Local PhysicalMMR space */ -#define LOCAL_MEM_SPACE 0xc000010000000000UL /* Local Memory space */ -/* It so happens that setting bit 35 indicates a reference to the SHUB or TIO - * MMR space. - */ -#define GLOBAL_MMR_SPACE 0xc000000800000000UL /* Global MMR space */ -#define TIO_MMR_SPACE 0xc000000800000000UL /* TIO MMR space */ -#define ICE_MMR_SPACE 0xc000000000000000UL /* ICE MMR space */ -#define GLOBAL_PHYS_MMR_SPACE 0x0000000800000000UL /* Global Physical MMR space */ -#define GET_SPACE 0xe000001000000000UL /* GET space */ -#define AMO_SPACE 0xc000002000000000UL /* AMO space */ -#define CACHEABLE_MEM_SPACE 0xe000003000000000UL /* Cacheable memory space */ -#define UNCACHED 0xc000000000000000UL /* UnCacheable memory space */ -#define UNCACHED_PHYS 0x8000000000000000UL /* UnCacheable physical memory space */ - -#define PHYS_MEM_SPACE 0x0000003000000000UL /* physical memory space */ - -/* SN2 address macros */ -/* NID_SHFT has the right value for both SHUB and TIO addresses.*/ -#define NID_SHFT 38 -#define LOCAL_MMR_ADDR(a) (UNCACHED | LOCAL_MMR_SPACE | (a)) -#define LOCAL_MMR_PHYS_ADDR(a) (UNCACHED_PHYS | LOCAL_PHYS_MMR_SPACE | (a)) -#define LOCAL_MEM_ADDR(a) (LOCAL_MEM_SPACE | (a)) -#define REMOTE_ADDR(n,a) ((((unsigned long)(n))< */ -#define BWIN_SIZE_BITS 29 /* big window size: 512M */ -#define TIO_BWIN_SIZE_BITS 30 /* big window size: 1G */ -#define NASID_BITS 11 /* bits <48:38> */ -#define NASID_BITMASK (0x7ffULL) -#define NASID_SHFT NID_SHFT -#define NASID_META_BITS 0 /* ???? */ -#define NASID_LOCAL_BITS 7 /* same router as SN1 */ - -#define NODE_ADDRSPACE_SIZE (1UL << NODE_SIZE_BITS) -#define NASID_MASK ((uint64_t) NASID_BITMASK << NASID_SHFT) -#define NASID_GET(_pa) (int) (((uint64_t) (_pa) >> \ - NASID_SHFT) & NASID_BITMASK) -#define PHYS_TO_DMA(x) ( ((x & NASID_MASK) >> 2) | \ - (x & (NODE_ADDRSPACE_SIZE - 1)) ) - -/* - * This address requires a chiplet id in bits 38-39. For DMA to memory, - * the chiplet id is zero. If we implement TIO-TIO dma, we might need - * to insert a chiplet id into this macro. However, it is our belief - * right now that this chiplet id will be ICE, which is also zero. - */ -#define PHYS_TO_TIODMA(x) ( ((x & NASID_MASK) << 2) | \ - (x & (NODE_ADDRSPACE_SIZE - 1)) ) - -#define CHANGE_NASID(n,x) ({ia64_sn2_pa_t _v; _v.l = (long) (x); _v.f.nasid = n; _v.p;}) - - -#ifndef __ASSEMBLY__ -#define NODE_SWIN_BASE(nasid, widget) \ - ((widget == 0) ? NODE_BWIN_BASE((nasid), SWIN0_BIGWIN) \ - : RAW_NODE_SWIN_BASE(nasid, widget)) -#else -#define NODE_SWIN_BASE(nasid, widget) \ - (NODE_IO_BASE(nasid) + ((uint64_t) (widget) << SWIN_SIZE_BITS)) -#define LOCAL_SWIN_BASE(widget) \ - (UNCACHED | LOCAL_MMR_SPACE | (((uint64_t) (widget) << SWIN_SIZE_BITS))) -#endif /* __ASSEMBLY__ */ +#define SH1_LOCAL_MMR_OFFSET 0x8000000000UL +#define SH2_LOCAL_MMR_OFFSET 0x0200000000UL +#define LOCAL_MMR_OFFSET (is_shub2() ? SH2_LOCAL_MMR_OFFSET : SH1_LOCAL_MMR_OFFSET) +#define LOCAL_MMR_SPACE (UNCACHED | LOCAL_MMR_OFFSET) +#define LOCAL_PHYS_MMR_SPACE (UNCACHED_PHYS | LOCAL_MMR_OFFSET) + +#define SH1_GLOBAL_MMR_OFFSET 0x0800000000UL +#define SH2_GLOBAL_MMR_OFFSET 0x0300000000UL +#define GLOBAL_MMR_OFFSET (is_shub2() ? SH2_GLOBAL_MMR_OFFSET : SH1_GLOBAL_MMR_OFFSET) +#define GLOBAL_MMR_SPACE (UNCACHED | GLOBAL_MMR_OFFSET) /* - * The following definitions pertain to the IO special address - * space. They define the location of the big and little windows - * of any given node. + * Physical mode addresses */ +#define GLOBAL_PHYS_MMR_SPACE (UNCACHED_PHYS | GLOBAL_MMR_OFFSET) -#define BWIN_SIZE (1UL << BWIN_SIZE_BITS) -#define BWIN_SIZEMASK (BWIN_SIZE - 1) -#define BWIN_WIDGET_MASK 0x7 -#define NODE_BWIN_BASE0(nasid) (NODE_IO_BASE(nasid) + BWIN_SIZE) -#define NODE_BWIN_BASE(nasid, bigwin) (NODE_BWIN_BASE0(nasid) + \ - ((uint64_t) (bigwin) << BWIN_SIZE_BITS)) -#define BWIN_WIDGETADDR(addr) ((addr) & BWIN_SIZEMASK) -#define BWIN_WINDOWNUM(addr) (((addr) >> BWIN_SIZE_BITS) & BWIN_WIDGET_MASK) +/* + * Clear region & AS bits. + */ +#define TO_PHYS_MASK (~(REGION_BITS | AS_MASK)) -#define TIO_BWIN_WINDOW_SELECT_MASK 0x7 -#define TIO_BWIN_WINDOWNUM(addr) (((addr) >> TIO_BWIN_SIZE_BITS) & TIO_BWIN_WINDOW_SELECT_MASK) +/* + * Misc NASID manipulation. + */ +#define NASID_SPACE(n) ((u64)(n) << NASID_SHIFT) +#define REMOTE_ADDR(n,a) (NASID_SPACE(n) | (a)) +#define NODE_OFFSET(x) ((x) & (NODE_ADDRSPACE_SIZE - 1)) +#define NODE_ADDRSPACE_SIZE (1UL << AS_SHIFT) +#define NASID_GET(x) (int) (((u64) (x) >> NASID_SHIFT) & NASID_BITMASK) +#define LOCAL_MMR_ADDR(a) (LOCAL_MMR_SPACE | (a)) +#define GLOBAL_MMR_ADDR(n,a) (GLOBAL_MMR_SPACE | REMOTE_ADDR(n,a)) +#define GLOBAL_MMR_PHYS_ADDR(n,a) (GLOBAL_PHYS_MMR_SPACE | REMOTE_ADDR(n,a)) +#define GLOBAL_CAC_ADDR(n,a) (CAC_BASE | REMOTE_ADDR(n,a)) +#define CHANGE_NASID(n,x) ((void *)(((u64)(x) & ~NASID_MASK) | NASID_SPACE(n))) -#ifndef __ASSEMBLY__ -#include -#endif + +/* non-II mmr's start at top of big window space (4G) */ +#define BWIN_TOP 0x0000000100000000UL /* - * The following macros are used to index to the beginning of a specific - * node's address space. + * general address defines */ +#define CAC_BASE (CACHED | AS_CAC_SPACE) +#define AMO_BASE (UNCACHED | AS_AMO_SPACE) +#define GET_BASE (CACHED | AS_GET_SPACE) -#define NODE_OFFSET(_n) ((uint64_t) (_n) << NASID_SHFT) +/* + * Convert Memory addresses between various addressing modes. + */ +#define TO_PHYS(x) (TO_PHYS_MASK & (x)) +#define TO_CAC(x) (CAC_BASE | TO_PHYS(x)) +#define TO_AMO(x) (AMO_BASE | TO_PHYS(x)) +#define TO_GET(x) (GET_BASE | TO_PHYS(x)) -#define NODE_CAC_BASE(_n) (CAC_BASE + NODE_OFFSET(_n)) -#define NODE_HSPEC_BASE(_n) (HSPEC_BASE + NODE_OFFSET(_n)) -#define NODE_IO_BASE(_n) (IO_BASE + NODE_OFFSET(_n)) -#define NODE_MSPEC_BASE(_n) (MSPEC_BASE + NODE_OFFSET(_n)) -#define NODE_UNCAC_BASE(_n) (UNCAC_BASE + NODE_OFFSET(_n)) -#define TO_NODE_CAC(_n, _x) (NODE_CAC_BASE(_n) | ((_x) & TO_PHYS_MASK)) +/* + * Covert from processor physical address to II/TIO physical address: + * II - squeeze out the AS bits + * TIO- requires a chiplet id in bits 38-39. For DMA to memory, + * the chiplet id is zero. If we implement TIO-TIO dma, we might need + * to insert a chiplet id into this macro. However, it is our belief + * right now that this chiplet id will be ICE, which is also zero. + */ +#define PHYS_TO_TIODMA(x) ( (((u64)(x) & NASID_MASK) << 2) | NODE_OFFSET(x)) +#define PHYS_TO_DMA(x) ( (((u64)(x) & NASID_MASK) >> 2) | NODE_OFFSET(x)) + + +/* + * The following definitions pertain to the IO special address + * space. They define the location of the big and little windows + * of any given node. + */ +#define BWIN_SIZE_BITS 29 /* big window size: 512M */ +#define TIO_BWIN_SIZE_BITS 30 /* big window size: 1G */ +#define NODE_SWIN_BASE(n, w) ((w == 0) ? NODE_BWIN_BASE((n), SWIN0_BIGWIN) \ + : RAW_NODE_SWIN_BASE(n, w)) +#define NODE_IO_BASE(n) (GLOBAL_MMR_SPACE | NASID_SPACE(n)) +#define BWIN_SIZE (1UL << BWIN_SIZE_BITS) +#define NODE_BWIN_BASE0(n) (NODE_IO_BASE(n) + BWIN_SIZE) +#define NODE_BWIN_BASE(n, w) (NODE_BWIN_BASE0(n) + ((u64) (w) << BWIN_SIZE_BITS)) +#define RAW_NODE_SWIN_BASE(n, w) (NODE_IO_BASE(n) + ((u64) (w) << SWIN_SIZE_BITS)) +#define BWIN_WIDGET_MASK 0x7 +#define BWIN_WINDOWNUM(x) (((x) >> BWIN_SIZE_BITS) & BWIN_WIDGET_MASK) + +#define TIO_BWIN_WINDOW_SELECT_MASK 0x7 +#define TIO_BWIN_WINDOWNUM(x) (((x) >> TIO_BWIN_SIZE_BITS) & TIO_BWIN_WINDOW_SELECT_MASK) -#define RAW_NODE_SWIN_BASE(nasid, widget) \ - (NODE_IO_BASE(nasid) + ((uint64_t) (widget) << SWIN_SIZE_BITS)) /* @@ -215,15 +186,12 @@ * of any given node. */ -#define SWIN_SIZE_BITS 24 -#define SWIN_SIZE (1UL << 24) -#define SWIN_SIZEMASK (SWIN_SIZE - 1) -#define SWIN_WIDGET_MASK 0xF - -#define TIO_SWIN_SIZE_BITS 28 -#define TIO_SWIN_SIZE (1UL << 28) -#define TIO_SWIN_SIZEMASK (SWIN_SIZE - 1) -#define TIO_SWIN_WIDGET_MASK 0x3 +#define SWIN_SIZE_BITS 24 +#define SWIN_WIDGET_MASK 0xF + +#define TIO_SWIN_SIZE_BITS 28 +#define TIO_SWIN_SIZE (1UL << TIO_SWIN_SIZE_BITS) +#define TIO_SWIN_WIDGET_MASK 0x3 /* * Convert smallwindow address to xtalk address. @@ -231,82 +199,39 @@ * 'addr' can be physical or virtual address, but will be converted * to Xtalk address in the range 0 -> SWINZ_SIZEMASK */ -#define SWIN_WIDGETNUM(addr) (((addr) >> SWIN_SIZE_BITS) & SWIN_WIDGET_MASK) +#define SWIN_WIDGETNUM(x) (((x) >> SWIN_SIZE_BITS) & SWIN_WIDGET_MASK) +#define TIO_SWIN_WIDGETNUM(x) (((x) >> TIO_SWIN_SIZE_BITS) & TIO_SWIN_WIDGET_MASK) -#define TIO_SWIN_WIDGETNUM(addr) (((addr) >> TIO_SWIN_SIZE_BITS) & TIO_SWIN_WIDGET_MASK) /* * The following macros produce the correct base virtual address for - * the hub registers. The LOCAL_HUB_* macros produce the appropriate - * address for the local registers. The REMOTE_HUB_* macro produce + * the hub registers. The REMOTE_HUB_* macro produce * the address for the specified hub's registers. The intent is * that the appropriate PI, MD, NI, or II register would be substituted - * for _x. - */ - - -/* - * SN2 has II mmr's located inside small window space. - * As all other non-II mmr's located at the top of big window - * space. - */ -#define REMOTE_HUB_BASE(_x) \ - (UNCACHED | GLOBAL_MMR_SPACE | \ - (((~(_x)) & BWIN_TOP)>>8) | \ - (((~(_x)) & BWIN_TOP)>>9) | (_x)) - -#define REMOTE_HUB(_n, _x) \ - ((uint64_t *)(REMOTE_HUB_BASE(_x) | ((((long)(_n))< #include +#include #define LED0 (LOCAL_MMR_ADDR(SH_REAL_JUNK_BUS_LED0)) #define LED_CPU_SHIFT 16 diff -Nru a/include/asm-ia64/sn/pda.h b/include/asm-ia64/sn/pda.h --- a/include/asm-ia64/sn/pda.h 2005-01-05 18:28:29 -08:00 +++ b/include/asm-ia64/sn/pda.h 2005-01-05 18:28:29 -08:00 @@ -37,17 +37,21 @@ * Support for SN LEDs */ volatile short *led_address; + u16 nasid_bitmask; + u8 shub2; + u8 nasid_shift; + u8 as_shift; + u8 shub_1_1_found; u8 led_state; u8 hb_state; /* supports blinking heartbeat leds */ - u8 shub_1_1_found; unsigned int hb_count; unsigned int idle_flag; volatile unsigned long *bedrock_rev_id; volatile unsigned long *pio_write_status_addr; + unsigned long pio_write_status_val; volatile unsigned long *pio_shub_war_cam_addr; - volatile unsigned long *mem_write_status_addr; struct bteinfo_s *cpu_bte_if[BTES_PER_NODE]; /* cpu interface order */ @@ -76,7 +80,7 @@ */ DECLARE_PER_CPU(struct pda_s, pda_percpu); -#define pda (&__get_cpu_var(pda_percpu)) +#define pda (&__ia64_per_cpu_var(pda_percpu)) #define pdacpu(cpu) (&per_cpu(pda_percpu, cpu)) @@ -84,5 +88,8 @@ * Use this macro to test if shub 1.1 wars should be enabled */ #define enable_shub_wars_1_1() (pda->shub_1_1_found) + +#define is_shub2() (pda->shub2) +#define is_shub1() (pda->shub2 == 0) #endif /* _ASM_IA64_SN_PDA_H */ diff -Nru a/include/asm-ia64/sn/rw_mmr.h b/include/asm-ia64/sn/rw_mmr.h --- a/include/asm-ia64/sn/rw_mmr.h 2005-01-05 18:28:29 -08:00 +++ b/include/asm-ia64/sn/rw_mmr.h 2005-01-05 18:28:29 -08:00 @@ -14,8 +14,8 @@ * uncached physical addresses. * pio_phys_read_mmr - read an MMR * pio_phys_write_mmr - write an MMR - * pio_atomic_phys_write_mmrs - atomically write 2 MMRs with psr.ic=0 - * (interrupt collection) + * pio_atomic_phys_write_mmrs - atomically write 1 or 2 MMRs with psr.ic=0 + * Second MMR will be skipped if address is NULL * * Addresses passed to these routines should be uncached physical addresses * ie., 0x80000.... @@ -61,13 +61,14 @@ asm volatile ("mov r2=psr;;" "rsm psr.i | psr.dt | psr.ic;;" + "cmp.ne p9,p0=%2,r0;" "srlz.i;;" "st8.rel [%0]=%1;" - "st8.rel [%2]=%3;;" + "(p9) st8.rel [%2]=%3;;" "mov psr.l=r2;;" "srlz.i;;" :: "r"(mmr1), "r"(val1), "r"(mmr2), "r"(val2) - : "r2", "memory"); + : "p9", "r2", "memory"); } #endif /* _ASM_IA64_SN_RW_MMR_H */ diff -Nru a/include/asm-ia64/sn/shub_mmr.h b/include/asm-ia64/sn/shub_mmr.h --- a/include/asm-ia64/sn/shub_mmr.h 2005-01-05 18:28:29 -08:00 +++ b/include/asm-ia64/sn/shub_mmr.h 2005-01-05 18:28:29 -08:00 @@ -14,117 +14,96 @@ /* Register "SH_IPI_INT" */ /* SHub Inter-Processor Interrupt Registers */ /* ==================================================================== */ -#define SH_IPI_INT 0x0000000110000380UL -#define SH_IPI_INT_MASK 0x8ff3ffffffefffffUL -#define SH_IPI_INT_INIT 0x0000000000000000UL +#define SH1_IPI_INT 0x0000000110000380 +#define SH2_IPI_INT 0x0000000010000380 /* SH_IPI_INT_TYPE */ /* Description: Type of Interrupt: 0=INT, 2=PMI, 4=NMI, 5=INIT */ #define SH_IPI_INT_TYPE_SHFT 0 -#define SH_IPI_INT_TYPE_MASK 0x0000000000000007UL +#define SH_IPI_INT_TYPE_MASK 0x0000000000000007 /* SH_IPI_INT_AGT */ /* Description: Agent, must be 0 for SHub */ #define SH_IPI_INT_AGT_SHFT 3 -#define SH_IPI_INT_AGT_MASK 0x0000000000000008UL +#define SH_IPI_INT_AGT_MASK 0x0000000000000008 /* SH_IPI_INT_PID */ /* Description: Processor ID, same setting as on targeted McKinley */ #define SH_IPI_INT_PID_SHFT 4 -#define SH_IPI_INT_PID_MASK 0x00000000000ffff0UL +#define SH_IPI_INT_PID_MASK 0x00000000000ffff0 /* SH_IPI_INT_BASE */ /* Description: Optional interrupt vector area, 2MB aligned */ #define SH_IPI_INT_BASE_SHFT 21 -#define SH_IPI_INT_BASE_MASK 0x0003ffffffe00000UL +#define SH_IPI_INT_BASE_MASK 0x0003ffffffe00000 /* SH_IPI_INT_IDX */ /* Description: Targeted McKinley interrupt vector */ #define SH_IPI_INT_IDX_SHFT 52 -#define SH_IPI_INT_IDX_MASK 0x0ff0000000000000UL +#define SH_IPI_INT_IDX_MASK 0x0ff0000000000000 /* SH_IPI_INT_SEND */ /* Description: Send Interrupt Message to PI, This generates a puls */ #define SH_IPI_INT_SEND_SHFT 63 -#define SH_IPI_INT_SEND_MASK 0x8000000000000000UL +#define SH_IPI_INT_SEND_MASK 0x8000000000000000 /* ==================================================================== */ /* Register "SH_EVENT_OCCURRED" */ /* SHub Interrupt Event Occurred */ /* ==================================================================== */ -#define SH_EVENT_OCCURRED 0x0000000110010000UL -#define SH_EVENT_OCCURRED_ALIAS 0x0000000110010008UL +#define SH1_EVENT_OCCURRED 0x0000000110010000 +#define SH1_EVENT_OCCURRED_ALIAS 0x0000000110010008 +#define SH2_EVENT_OCCURRED 0x0000000010010000 +#define SH2_EVENT_OCCURRED_ALIAS 0x0000000010010008 /* ==================================================================== */ /* Register "SH_PI_CAM_CONTROL" */ /* CRB CAM MMR Access Control */ /* ==================================================================== */ -#ifndef __ASSEMBLY__ -#define SH_PI_CAM_CONTROL 0x0000000120050300UL -#else -#define SH_PI_CAM_CONTROL 0x0000000120050300 -#endif +#define SH1_PI_CAM_CONTROL 0x0000000120050300 /* ==================================================================== */ /* Register "SH_SHUB_ID" */ /* SHub ID Number */ /* ==================================================================== */ -#define SH_SHUB_ID 0x0000000110060580UL -#define SH_SHUB_ID_REVISION_SHFT 28 -#define SH_SHUB_ID_REVISION_MASK 0x00000000f0000000 - -/* ==================================================================== */ -/* Register "SH_PTC_0" */ -/* Puge Translation Cache Message Configuration Information */ -/* ==================================================================== */ -#define SH_PTC_0 0x00000001101a0000UL -#define SH_PTC_1 0x00000001101a0080UL +#define SH1_SHUB_ID 0x0000000110060580 +#define SH1_SHUB_ID_REVISION_SHFT 28 +#define SH1_SHUB_ID_REVISION_MASK 0x00000000f0000000 /* ==================================================================== */ /* Register "SH_RTC" */ /* Real-time Clock */ /* ==================================================================== */ -#define SH_RTC 0x00000001101c0000UL -#define SH_RTC_MASK 0x007fffffffffffffUL - -/* ==================================================================== */ -/* Register "SH_MEMORY_WRITE_STATUS_0|1" */ -/* Memory Write Status for CPU 0 & 1 */ -/* ==================================================================== */ -#define SH_MEMORY_WRITE_STATUS_0 0x0000000120070000UL -#define SH_MEMORY_WRITE_STATUS_1 0x0000000120070080UL +#define SH1_RTC 0x00000001101c0000 +#define SH2_RTC 0x00000002101c0000 +#define SH_RTC_MASK 0x007fffffffffffff /* ==================================================================== */ /* Register "SH_PIO_WRITE_STATUS_0|1" */ /* PIO Write Status for CPU 0 & 1 */ /* ==================================================================== */ -#ifndef __ASSEMBLY__ -#define SH_PIO_WRITE_STATUS_0 0x0000000120070200UL -#define SH_PIO_WRITE_STATUS_1 0x0000000120070280UL +#define SH1_PIO_WRITE_STATUS_0 0x0000000120070200 +#define SH1_PIO_WRITE_STATUS_1 0x0000000120070280 +#define SH2_PIO_WRITE_STATUS_0 0x0000000020070200 +#define SH2_PIO_WRITE_STATUS_1 0x0000000020070280 +#define SH2_PIO_WRITE_STATUS_2 0x0000000020070300 +#define SH2_PIO_WRITE_STATUS_3 0x0000000020070380 /* SH_PIO_WRITE_STATUS_0_WRITE_DEADLOCK */ /* Description: Deadlock response detected */ -#define SH_PIO_WRITE_STATUS_0_WRITE_DEADLOCK_SHFT 1 -#define SH_PIO_WRITE_STATUS_0_WRITE_DEADLOCK_MASK 0x0000000000000002 +#define SH_PIO_WRITE_STATUS_WRITE_DEADLOCK_SHFT 1 +#define SH_PIO_WRITE_STATUS_WRITE_DEADLOCK_MASK 0x0000000000000002 /* SH_PIO_WRITE_STATUS_0_PENDING_WRITE_COUNT */ /* Description: Count of currently pending PIO writes */ -#define SH_PIO_WRITE_STATUS_0_PENDING_WRITE_COUNT_SHFT 56 -#define SH_PIO_WRITE_STATUS_0_PENDING_WRITE_COUNT_MASK 0x3f00000000000000UL -#else -#define SH_PIO_WRITE_STATUS_0 0x0000000120070200 -#define SH_PIO_WRITE_STATUS_0_PENDING_WRITE_COUNT_SHFT 56 -#define SH_PIO_WRITE_STATUS_0_WRITE_DEADLOCK_SHFT 1 -#endif +#define SH_PIO_WRITE_STATUS_PENDING_WRITE_COUNT_SHFT 56 +#define SH_PIO_WRITE_STATUS_PENDING_WRITE_COUNT_MASK 0x3f00000000000000 /* ==================================================================== */ /* Register "SH_PIO_WRITE_STATUS_0_ALIAS" */ /* ==================================================================== */ -#ifndef __ASSEMBLY__ -#define SH_PIO_WRITE_STATUS_0_ALIAS 0x0000000120070208UL -#else -#define SH_PIO_WRITE_STATUS_0_ALIAS 0x0000000120070208 -#endif +#define SH1_PIO_WRITE_STATUS_0_ALIAS 0x0000000120070208 +#define SH2_PIO_WRITE_STATUS_0_ALIAS 0x0000000020070208 /* ==================================================================== */ /* Register "SH_EVENT_OCCURRED" */ @@ -151,61 +130,85 @@ #define SH_EVENT_OCCURRED_II_INT1_MASK 0x0000000040000000 /* ==================================================================== */ -/* Register "SH_PTC_0" */ +/* LEDS */ +/* ==================================================================== */ +#define SH1_REAL_JUNK_BUS_LED0 0x7fed00000UL +#define SH1_REAL_JUNK_BUS_LED1 0x7fed10000UL +#define SH1_REAL_JUNK_BUS_LED2 0x7fed20000UL +#define SH1_REAL_JUNK_BUS_LED3 0x7fed30000UL + +#define SH2_REAL_JUNK_BUS_LED0 0xf0000000UL +#define SH2_REAL_JUNK_BUS_LED1 0xf0010000UL +#define SH2_REAL_JUNK_BUS_LED2 0xf0020000UL +#define SH2_REAL_JUNK_BUS_LED3 0xf0030000UL + +/* ==================================================================== */ +/* Register "SH1_PTC_0" */ /* Puge Translation Cache Message Configuration Information */ /* ==================================================================== */ -#define SH_PTC_0 0x00000001101a0000UL -#define SH_PTC_0_MASK 0x80000000fffffffd -#define SH_PTC_0_INIT 0x0000000000000000 +#define SH1_PTC_0 0x00000001101a0000 -/* SH_PTC_0_A */ +/* SH1_PTC_0_A */ /* Description: Type */ -#define SH_PTC_0_A_SHFT 0 -#define SH_PTC_0_A_MASK 0x0000000000000001 +#define SH1_PTC_0_A_SHFT 0 -/* SH_PTC_0_PS */ +/* SH1_PTC_0_PS */ /* Description: Page Size */ -#define SH_PTC_0_PS_SHFT 2 -#define SH_PTC_0_PS_MASK 0x00000000000000fc +#define SH1_PTC_0_PS_SHFT 2 -/* SH_PTC_0_RID */ +/* SH1_PTC_0_RID */ /* Description: Region ID */ -#define SH_PTC_0_RID_SHFT 8 -#define SH_PTC_0_RID_MASK 0x00000000ffffff00 +#define SH1_PTC_0_RID_SHFT 8 -/* SH_PTC_0_START */ +/* SH1_PTC_0_START */ /* Description: Start */ -#define SH_PTC_0_START_SHFT 63 -#define SH_PTC_0_START_MASK 0x8000000000000000 +#define SH1_PTC_0_START_SHFT 63 /* ==================================================================== */ -/* Register "SH_PTC_1" */ +/* Register "SH1_PTC_1" */ /* Puge Translation Cache Message Configuration Information */ /* ==================================================================== */ -#define SH_PTC_1 0x00000001101a0080UL -#define SH_PTC_1_MASK 0x9ffffffffffff000 -#define SH_PTC_1_INIT 0x0000000000000000 - -/* SH_PTC_1_VPN */ -/* Description: Virtual page number */ -#define SH_PTC_1_VPN_SHFT 12 -#define SH_PTC_1_VPN_MASK 0x1ffffffffffff000 +#define SH1_PTC_1 0x00000001101a0080 -/* SH_PTC_1_START */ +/* SH1_PTC_1_START */ /* Description: PTC_1 Start */ -#define SH_PTC_1_START_SHFT 63 -#define SH_PTC_1_START_MASK 0x8000000000000000 +#define SH1_PTC_1_START_SHFT 63 + + +/* ==================================================================== */ +/* Register "SH2_PTC" */ +/* Puge Translation Cache Message Configuration Information */ +/* ==================================================================== */ +#define SH2_PTC 0x0000000170000000 + +/* SH2_PTC_A */ +/* Description: Type */ +#define SH2_PTC_A_SHFT 0 + +/* SH2_PTC_PS */ +/* Description: Page Size */ +#define SH2_PTC_PS_SHFT 2 + +/* SH2_PTC_RID */ +/* Description: Region ID */ +#define SH2_PTC_RID_SHFT 4 + +/* SH2_PTC_START */ +/* Description: Start */ +#define SH2_PTC_START_SHFT 63 -/* - * Register definitions - */ +/* SH2_PTC_ADDR_RID */ +/* Description: Region ID */ +#define SH2_PTC_ADDR_SHFT 4 +#define SH2_PTC_ADDR_MASK 0x1ffffffffffff000 /* ==================================================================== */ /* Register "SH_RTC1_INT_CONFIG" */ /* SHub RTC 1 Interrupt Config Registers */ /* ==================================================================== */ -#define SH_RTC1_INT_CONFIG 0x0000000110001480 +#define SH1_RTC1_INT_CONFIG 0x0000000110001480 +#define SH2_RTC1_INT_CONFIG 0x0000000010001480 #define SH_RTC1_INT_CONFIG_MASK 0x0ff3ffffffefffff #define SH_RTC1_INT_CONFIG_INIT 0x0000000000000000 @@ -239,7 +242,8 @@ /* SHub RTC 1 Interrupt Enable Registers */ /* ==================================================================== */ -#define SH_RTC1_INT_ENABLE 0x0000000110001500 +#define SH1_RTC1_INT_ENABLE 0x0000000110001500 +#define SH2_RTC1_INT_ENABLE 0x0000000010001500 #define SH_RTC1_INT_ENABLE_MASK 0x0000000000000001 #define SH_RTC1_INT_ENABLE_INIT 0x0000000000000000 @@ -253,7 +257,8 @@ /* SHub RTC 2 Interrupt Config Registers */ /* ==================================================================== */ -#define SH_RTC2_INT_CONFIG 0x0000000110001580 +#define SH1_RTC2_INT_CONFIG 0x0000000110001580 +#define SH2_RTC2_INT_CONFIG 0x0000000010001580 #define SH_RTC2_INT_CONFIG_MASK 0x0ff3ffffffefffff #define SH_RTC2_INT_CONFIG_INIT 0x0000000000000000 @@ -287,7 +292,8 @@ /* SHub RTC 2 Interrupt Enable Registers */ /* ==================================================================== */ -#define SH_RTC2_INT_ENABLE 0x0000000110001600 +#define SH1_RTC2_INT_ENABLE 0x0000000110001600 +#define SH2_RTC2_INT_ENABLE 0x0000000010001600 #define SH_RTC2_INT_ENABLE_MASK 0x0000000000000001 #define SH_RTC2_INT_ENABLE_INIT 0x0000000000000000 @@ -301,7 +307,8 @@ /* SHub RTC 3 Interrupt Config Registers */ /* ==================================================================== */ -#define SH_RTC3_INT_CONFIG 0x0000000110001680 +#define SH1_RTC3_INT_CONFIG 0x0000000110001680 +#define SH2_RTC3_INT_CONFIG 0x0000000010001680 #define SH_RTC3_INT_CONFIG_MASK 0x0ff3ffffffefffff #define SH_RTC3_INT_CONFIG_INIT 0x0000000000000000 @@ -335,7 +342,8 @@ /* SHub RTC 3 Interrupt Enable Registers */ /* ==================================================================== */ -#define SH_RTC3_INT_ENABLE 0x0000000110001700 +#define SH1_RTC3_INT_ENABLE 0x0000000110001700 +#define SH2_RTC3_INT_ENABLE 0x0000000010001700 #define SH_RTC3_INT_ENABLE_MASK 0x0000000000000001 #define SH_RTC3_INT_ENABLE_INIT 0x0000000000000000 @@ -364,7 +372,8 @@ /* RTC Compare Value for Processor B */ /* ==================================================================== */ -#define SH_INT_CMPB 0x00000001101b0080 +#define SH1_INT_CMPB 0x00000001101b0080 +#define SH2_INT_CMPB 0x00000000101b0080 #define SH_INT_CMPB_MASK 0x007fffffffffffff #define SH_INT_CMPB_INIT 0x0000000000000000 @@ -378,7 +387,8 @@ /* RTC Compare Value for Processor C */ /* ==================================================================== */ -#define SH_INT_CMPC 0x00000001101b0100 +#define SH1_INT_CMPC 0x00000001101b0100 +#define SH2_INT_CMPC 0x00000000101b0100 #define SH_INT_CMPC_MASK 0x007fffffffffffff #define SH_INT_CMPC_INIT 0x0000000000000000 @@ -392,7 +402,8 @@ /* RTC Compare Value for Processor D */ /* ==================================================================== */ -#define SH_INT_CMPD 0x00000001101b0180 +#define SH1_INT_CMPD 0x00000001101b0180 +#define SH2_INT_CMPD 0x00000000101b0180 #define SH_INT_CMPD_MASK 0x007fffffffffffff #define SH_INT_CMPD_INIT 0x0000000000000000 @@ -400,5 +411,31 @@ /* Description: Real Time Clock Compare */ #define SH_INT_CMPD_REAL_TIME_CMPD_SHFT 0 #define SH_INT_CMPD_REAL_TIME_CMPD_MASK 0x007fffffffffffff + + +/* ==================================================================== */ +/* Some MMRs are functionally identical (or close enough) on both SHUB1 */ +/* and SHUB2 that it makes sense to define a geberic name for the MMR. */ +/* It is acceptible to use (for example) SH_IPI_INT to reference the */ +/* the IPI MMR. The value of SH_IPI_INT is determined at runtime based */ +/* on the type of the SHUB. Do not use these #defines in performance */ +/* critical code or loops - there is a small performance penalty. */ +/* ==================================================================== */ +#define shubmmr(a,b) (is_shub2() ? a##2_##b : a##1_##b) + +#define SH_REAL_JUNK_BUS_LED0 shubmmr(SH, REAL_JUNK_BUS_LED0) +#define SH_IPI_INT shubmmr(SH, IPI_INT) +#define SH_EVENT_OCCURRED shubmmr(SH, EVENT_OCCURRED) +#define SH_EVENT_OCCURRED_ALIAS shubmmr(SH, EVENT_OCCURRED_ALIAS) +#define SH_RTC shubmmr(SH, RTC) +#define SH_RTC1_INT_CONFIG shubmmr(SH, RTC1_INT_CONFIG) +#define SH_RTC1_INT_ENABLE shubmmr(SH, RTC1_INT_ENABLE) +#define SH_RTC2_INT_CONFIG shubmmr(SH, RTC2_INT_CONFIG) +#define SH_RTC2_INT_ENABLE shubmmr(SH, RTC2_INT_ENABLE) +#define SH_RTC3_INT_CONFIG shubmmr(SH, RTC3_INT_CONFIG) +#define SH_RTC3_INT_ENABLE shubmmr(SH, RTC3_INT_ENABLE) +#define SH_INT_CMPB shubmmr(SH, INT_CMPB) +#define SH_INT_CMPC shubmmr(SH, INT_CMPC) +#define SH_INT_CMPD shubmmr(SH, INT_CMPD) #endif /* _ASM_IA64_SN_SHUB_MMR_H */ diff -Nru a/include/asm-ia64/sn/sn_cpuid.h b/include/asm-ia64/sn/sn_cpuid.h --- a/include/asm-ia64/sn/sn_cpuid.h 2005-01-05 18:28:29 -08:00 +++ b/include/asm-ia64/sn/sn_cpuid.h 2005-01-05 18:28:29 -08:00 @@ -13,6 +13,7 @@ #include #include +#include #include #include @@ -86,11 +87,9 @@ #endif -#define get_node_number(addr) (((unsigned long)(addr)>>38) & 0x7ff) +#define get_node_number(addr) NASID_GET(addr) /* - * NOTE: id & eid refer to Intel's definitions of the LID register - * * NOTE: on non-MP systems, only cpuid 0 exists */ diff -Nru a/include/asm-ia64/sn/sn_sal.h b/include/asm-ia64/sn/sn_sal.h --- a/include/asm-ia64/sn/sn_sal.h 2005-01-05 18:28:29 -08:00 +++ b/include/asm-ia64/sn/sn_sal.h 2005-01-05 18:28:29 -08:00 @@ -32,9 +32,10 @@ #define SN_SAL_NO_FAULT_ZONE_VIRTUAL 0x02000010 #define SN_SAL_NO_FAULT_ZONE_PHYSICAL 0x02000011 #define SN_SAL_PRINT_ERROR 0x02000012 -#define SN_SAL_GET_SAPIC_INFO 0x02009999 //ZZZZ fix #define SN_SAL_SET_ERROR_HANDLING_FEATURES 0x0200001a // reentrant #define SN_SAL_GET_FIT_COMPT 0x0200001b // reentrant +#define SN_SAL_GET_HUB_INFO 0x0200001c +#define SN_SAL_GET_SAPIC_INFO 0x0200001d #define SN_SAL_CONSOLE_PUTC 0x02000021 #define SN_SAL_CONSOLE_GETC 0x02000022 #define SN_SAL_CONSOLE_PUTS 0x02000023 @@ -847,6 +848,14 @@ /* * Returns the nasid, subnode & slice corresponding to a SAPIC ID + * + * In: + * arg0 - SN_SAL_GET_SAPIC_INFO + * arg1 - sapicid (lid >> 16) + * Out: + * v0 - nasid + * v1 - subnode + * v2 - slice */ static inline u64 ia64_sn_get_sapic_info(int sapicid, int *nasid, int *subnode, int *slice) @@ -859,7 +868,7 @@ ret_stuff.v2 = 0; SAL_CALL_NOLOCK(ret_stuff, SN_SAL_GET_SAPIC_INFO, sapicid, 0, 0, 0, 0, 0, 0); -/***** BEGIN HACK - temp til new proms available ********/ +/***** BEGIN HACK - temp til old proms no longer supported ********/ if (ret_stuff.status == SALRET_NOT_IMPLEMENTED) { if (nasid) *nasid = sapicid & 0xfff; if (subnode) *subnode = (sapicid >> 13) & 1; @@ -876,6 +885,46 @@ if (slice) *slice = (int) ret_stuff.v2; return 0; } + +/* + * Returns information about the HUB/SHUB. + * In: + * arg0 - SN_SAL_GET_HUB_INFO + * arg1 - 0 (other values reserved for future use) + * Out: + * v0 - shub type (0=shub1, 1=shub2) + * v1 - masid mask (ex., 0x7ff for 11 bit nasid) + * v2 - bit position of low nasid bit + */ +static inline u64 +ia64_sn_get_hub_info(int fc, u64 *arg1, u64 *arg2, u64 *arg3) +{ + struct ia64_sal_retval ret_stuff; + + ret_stuff.status = 0; + ret_stuff.v0 = 0; + ret_stuff.v1 = 0; + ret_stuff.v2 = 0; + SAL_CALL_NOLOCK(ret_stuff, SN_SAL_GET_HUB_INFO, fc, 0, 0, 0, 0, 0, 0); + +/***** BEGIN HACK - temp til old proms no longer supported ********/ + if (ret_stuff.status == SALRET_NOT_IMPLEMENTED) { + if (arg1) *arg1 = 0; + if (arg2) *arg2 = 0x7ff; + if (arg3) *arg3 = 38; + return 0; + } +/***** END HACK *******/ + + if (ret_stuff.status < 0) + return ret_stuff.status; + + if (arg1) *arg1 = ret_stuff.v0; + if (arg2) *arg2 = ret_stuff.v1; + if (arg3) *arg3 = ret_stuff.v2; + return 0; +} + /* * This is the access point to the Altix PROM hardware performance * and status monitoring interface. For info on using this, see diff -Nru a/include/asm-ia64/thread_info.h b/include/asm-ia64/thread_info.h --- a/include/asm-ia64/thread_info.h 2005-01-05 18:28:29 -08:00 +++ b/include/asm-ia64/thread_info.h 2005-01-05 18:28:29 -08:00 @@ -27,6 +27,13 @@ mm_segment_t addr_limit; /* user-level address space limit */ __s32 preempt_count; /* 0=premptable, <0=BUG; will also serve as bh-counter */ struct restart_block restart_block; + struct { + int signo; + int code; + void __user *addr; + unsigned long start_time; + pid_t pid; + } sigdelayed; /* Saved information for TIF_SIGDELAYED */ }; #define THREAD_SIZE KERNEL_STACK_SIZE @@ -66,18 +73,21 @@ #define TIF_NEED_RESCHED 2 /* rescheduling necessary */ #define TIF_SYSCALL_TRACE 3 /* syscall trace active */ #define TIF_SYSCALL_AUDIT 4 /* syscall auditing active */ +#define TIF_SIGDELAYED 5 /* signal delayed from MCA/INIT/NMI/PMI context */ #define TIF_POLLING_NRFLAG 16 /* true if poll_idle() is polling TIF_NEED_RESCHED */ -#define TIF_WORK_MASK 0x7 /* like TIF_ALLWORK_BITS but sans TIF_SYSCALL_TRACE */ -#define TIF_ALLWORK_MASK 0x1f /* bits 0..4 are "work to do on user-return" bits */ - #define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE) #define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT) #define _TIF_SYSCALL_TRACEAUDIT (_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT) #define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME) #define _TIF_SIGPENDING (1 << TIF_SIGPENDING) #define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) -#define _TIF_USEDFPU (1 << TIF_USEDFPU) +#define _TIF_SIGDELAYED (1 << TIF_SIGDELAYED) #define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG) + +/* "work to do on user-return" bits */ +#define TIF_ALLWORK_MASK (_TIF_NOTIFY_RESUME|_TIF_SIGPENDING|_TIF_NEED_RESCHED|_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SIGDELAYED) +/* like TIF_ALLWORK_BITS but sans TIF_SYSCALL_TRACE or TIF_SYSCALL_AUDIT */ +#define TIF_WORK_MASK (TIF_ALLWORK_MASK&~(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT)) #endif /* _ASM_IA64_THREAD_INFO_H */ diff -Nru a/include/linux/sched.h b/include/linux/sched.h --- a/include/linux/sched.h 2005-01-05 18:28:29 -08:00 +++ b/include/linux/sched.h 2005-01-05 18:28:29 -08:00 @@ -762,6 +762,7 @@ extern int task_nice(const task_t *p); extern int task_curr(const task_t *p); extern int idle_cpu(int cpu); +extern task_t *idle_task(int cpu); void yield(void); diff -Nru a/kernel/sched.c b/kernel/sched.c --- a/kernel/sched.c 2005-01-05 18:28:29 -08:00 +++ b/kernel/sched.c 2005-01-05 18:28:29 -08:00 @@ -3068,6 +3068,15 @@ EXPORT_SYMBOL_GPL(idle_cpu); /** + * idle_task - return the idle task for a given cpu. + * @cpu: the processor in question. + */ +task_t *idle_task(int cpu) +{ + return cpu_rq(cpu)->idle; +} + +/** * find_process_by_pid - find a process with a matching PID value. * @pid: the pid in question. */