Merge git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux-2.6: [IA64] wire up pselect, ppoll [IA64] Add TIF_RESTORE_SIGMASK [IA64] unwind did not work for processes born with CLONE_STOPPED [IA64] Optional method to purge the TLB on SN systems [IA64] SPIN_LOCK_UNLOCKED macro cleanup in arch/ia64 [IA64-SN2][KJ] mmtimer.c-kzalloc [IA64] fix stack alignment for ia32 signal handlers [IA64] - Altix: hotplug after intr redirect can crash system [IA64] save and restore cpus_allowed in cpu_idle_wait [IA64] Removal of percpu TR cleanup in kexec code [IA64] Fix some section mismatch errors
This commit is contained in:
@@ -59,6 +59,22 @@ void sn_intr_free(nasid_t local_nasid, int local_widget,
|
||||
(u64) sn_irq_info->irq_cookie, 0, 0);
|
||||
}
|
||||
|
||||
u64 sn_intr_redirect(nasid_t local_nasid, int local_widget,
|
||||
struct sn_irq_info *sn_irq_info,
|
||||
nasid_t req_nasid, int req_slice)
|
||||
{
|
||||
struct ia64_sal_retval ret_stuff;
|
||||
ret_stuff.status = 0;
|
||||
ret_stuff.v0 = 0;
|
||||
|
||||
SAL_CALL_NOLOCK(ret_stuff, (u64) SN_SAL_IOIF_INTERRUPT,
|
||||
(u64) SAL_INTR_REDIRECT, (u64) local_nasid,
|
||||
(u64) local_widget, __pa(sn_irq_info),
|
||||
(u64) req_nasid, (u64) req_slice, 0);
|
||||
|
||||
return ret_stuff.status;
|
||||
}
|
||||
|
||||
static unsigned int sn_startup_irq(unsigned int irq)
|
||||
{
|
||||
return 0;
|
||||
@@ -127,15 +143,8 @@ struct sn_irq_info *sn_retarget_vector(struct sn_irq_info *sn_irq_info,
|
||||
struct sn_irq_info *new_irq_info;
|
||||
struct sn_pcibus_provider *pci_provider;
|
||||
|
||||
new_irq_info = kmalloc(sizeof(struct sn_irq_info), GFP_ATOMIC);
|
||||
if (new_irq_info == NULL)
|
||||
return NULL;
|
||||
|
||||
memcpy(new_irq_info, sn_irq_info, sizeof(struct sn_irq_info));
|
||||
|
||||
bridge = (u64) new_irq_info->irq_bridge;
|
||||
bridge = (u64) sn_irq_info->irq_bridge;
|
||||
if (!bridge) {
|
||||
kfree(new_irq_info);
|
||||
return NULL; /* irq is not a device interrupt */
|
||||
}
|
||||
|
||||
@@ -145,8 +154,25 @@ struct sn_irq_info *sn_retarget_vector(struct sn_irq_info *sn_irq_info,
|
||||
local_widget = TIO_SWIN_WIDGETNUM(bridge);
|
||||
else
|
||||
local_widget = SWIN_WIDGETNUM(bridge);
|
||||
|
||||
vector = sn_irq_info->irq_irq;
|
||||
|
||||
/* Make use of SAL_INTR_REDIRECT if PROM supports it */
|
||||
status = sn_intr_redirect(local_nasid, local_widget, sn_irq_info, nasid, slice);
|
||||
if (!status) {
|
||||
new_irq_info = sn_irq_info;
|
||||
goto finish_up;
|
||||
}
|
||||
|
||||
/*
|
||||
* PROM does not support SAL_INTR_REDIRECT, or it failed.
|
||||
* Revert to old method.
|
||||
*/
|
||||
new_irq_info = kmalloc(sizeof(struct sn_irq_info), GFP_ATOMIC);
|
||||
if (new_irq_info == NULL)
|
||||
return NULL;
|
||||
|
||||
memcpy(new_irq_info, sn_irq_info, sizeof(struct sn_irq_info));
|
||||
|
||||
/* Free the old PROM new_irq_info structure */
|
||||
sn_intr_free(local_nasid, local_widget, new_irq_info);
|
||||
unregister_intr_pda(new_irq_info);
|
||||
@@ -162,11 +188,18 @@ struct sn_irq_info *sn_retarget_vector(struct sn_irq_info *sn_irq_info,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
register_intr_pda(new_irq_info);
|
||||
spin_lock(&sn_irq_info_lock);
|
||||
list_replace_rcu(&sn_irq_info->list, &new_irq_info->list);
|
||||
spin_unlock(&sn_irq_info_lock);
|
||||
call_rcu(&sn_irq_info->rcu, sn_irq_info_free);
|
||||
|
||||
|
||||
finish_up:
|
||||
/* Update kernels new_irq_info with new target info */
|
||||
cpuid = nasid_slice_to_cpuid(new_irq_info->irq_nasid,
|
||||
new_irq_info->irq_slice);
|
||||
new_irq_info->irq_cpuid = cpuid;
|
||||
register_intr_pda(new_irq_info);
|
||||
|
||||
pci_provider = sn_pci_provider[new_irq_info->irq_bridge_type];
|
||||
|
||||
@@ -178,11 +211,6 @@ struct sn_irq_info *sn_retarget_vector(struct sn_irq_info *sn_irq_info,
|
||||
pci_provider && pci_provider->target_interrupt)
|
||||
(pci_provider->target_interrupt)(new_irq_info);
|
||||
|
||||
spin_lock(&sn_irq_info_lock);
|
||||
list_replace_rcu(&sn_irq_info->list, &new_irq_info->list);
|
||||
spin_unlock(&sn_irq_info_lock);
|
||||
call_rcu(&sn_irq_info->rcu, sn_irq_info_free);
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
cpuphys = cpu_physical_id(cpuid);
|
||||
set_irq_affinity_info((vector & 0xff), cpuphys, 0);
|
||||
|
@@ -46,6 +46,9 @@ DECLARE_PER_CPU(struct ptc_stats, ptcstats);
|
||||
|
||||
static __cacheline_aligned DEFINE_SPINLOCK(sn2_global_ptc_lock);
|
||||
|
||||
/* 0 = old algorithm (no IPI flushes), 1 = ipi deadlock flush, 2 = ipi instead of SHUB ptc, >2 = always ipi */
|
||||
static int sn2_flush_opt = 0;
|
||||
|
||||
extern unsigned long
|
||||
sn2_ptc_deadlock_recovery_core(volatile unsigned long *, unsigned long,
|
||||
volatile unsigned long *, unsigned long,
|
||||
@@ -76,6 +79,8 @@ struct ptc_stats {
|
||||
unsigned long shub_itc_clocks;
|
||||
unsigned long shub_itc_clocks_max;
|
||||
unsigned long shub_ptc_flushes_not_my_mm;
|
||||
unsigned long shub_ipi_flushes;
|
||||
unsigned long shub_ipi_flushes_itc_clocks;
|
||||
};
|
||||
|
||||
#define sn2_ptctest 0
|
||||
@@ -121,6 +126,18 @@ void sn_tlb_migrate_finish(struct mm_struct *mm)
|
||||
flush_tlb_mm(mm);
|
||||
}
|
||||
|
||||
static void
|
||||
sn2_ipi_flush_all_tlb(struct mm_struct *mm)
|
||||
{
|
||||
unsigned long itc;
|
||||
|
||||
itc = ia64_get_itc();
|
||||
smp_flush_tlb_cpumask(mm->cpu_vm_mask);
|
||||
itc = ia64_get_itc() - itc;
|
||||
__get_cpu_var(ptcstats).shub_ipi_flushes_itc_clocks += itc;
|
||||
__get_cpu_var(ptcstats).shub_ipi_flushes++;
|
||||
}
|
||||
|
||||
/**
|
||||
* sn2_global_tlb_purge - globally purge translation cache of virtual address range
|
||||
* @mm: mm_struct containing virtual address range
|
||||
@@ -154,7 +171,12 @@ sn2_global_tlb_purge(struct mm_struct *mm, unsigned long start,
|
||||
unsigned long itc, itc2, flags, data0 = 0, data1 = 0, rr_value, old_rr = 0;
|
||||
short nasids[MAX_NUMNODES], nix;
|
||||
nodemask_t nodes_flushed;
|
||||
int active, max_active, deadlock;
|
||||
int active, max_active, deadlock, flush_opt = sn2_flush_opt;
|
||||
|
||||
if (flush_opt > 2) {
|
||||
sn2_ipi_flush_all_tlb(mm);
|
||||
return;
|
||||
}
|
||||
|
||||
nodes_clear(nodes_flushed);
|
||||
i = 0;
|
||||
@@ -189,6 +211,12 @@ sn2_global_tlb_purge(struct mm_struct *mm, unsigned long start,
|
||||
return;
|
||||
}
|
||||
|
||||
if (flush_opt == 2) {
|
||||
sn2_ipi_flush_all_tlb(mm);
|
||||
preempt_enable();
|
||||
return;
|
||||
}
|
||||
|
||||
itc = ia64_get_itc();
|
||||
nix = 0;
|
||||
for_each_node_mask(cnode, nodes_flushed)
|
||||
@@ -256,6 +284,8 @@ sn2_global_tlb_purge(struct mm_struct *mm, unsigned long start,
|
||||
}
|
||||
if (active >= max_active || i == (nix - 1)) {
|
||||
if ((deadlock = wait_piowc())) {
|
||||
if (flush_opt == 1)
|
||||
goto done;
|
||||
sn2_ptc_deadlock_recovery(nasids, ibegin, i, mynasid, ptc0, data0, ptc1, data1);
|
||||
if (reset_max_active_on_deadlock())
|
||||
max_active = 1;
|
||||
@@ -267,6 +297,7 @@ sn2_global_tlb_purge(struct mm_struct *mm, unsigned long start,
|
||||
start += (1UL << nbits);
|
||||
} while (start < end);
|
||||
|
||||
done:
|
||||
itc2 = ia64_get_itc() - itc2;
|
||||
__get_cpu_var(ptcstats).shub_itc_clocks += itc2;
|
||||
if (itc2 > __get_cpu_var(ptcstats).shub_itc_clocks_max)
|
||||
@@ -279,6 +310,11 @@ sn2_global_tlb_purge(struct mm_struct *mm, unsigned long start,
|
||||
|
||||
spin_unlock_irqrestore(PTC_LOCK(shub1), flags);
|
||||
|
||||
if (flush_opt == 1 && deadlock) {
|
||||
__get_cpu_var(ptcstats).deadlocks++;
|
||||
sn2_ipi_flush_all_tlb(mm);
|
||||
}
|
||||
|
||||
preempt_enable();
|
||||
}
|
||||
|
||||
@@ -425,24 +461,42 @@ static int sn2_ptc_seq_show(struct seq_file *file, void *data)
|
||||
|
||||
if (!cpu) {
|
||||
seq_printf(file,
|
||||
"# cpu ptc_l newrid ptc_flushes nodes_flushed deadlocks lock_nsec shub_nsec shub_nsec_max not_my_mm deadlock2\n");
|
||||
seq_printf(file, "# ptctest %d\n", sn2_ptctest);
|
||||
"# cpu ptc_l newrid ptc_flushes nodes_flushed deadlocks lock_nsec shub_nsec shub_nsec_max not_my_mm deadlock2 ipi_fluches ipi_nsec\n");
|
||||
seq_printf(file, "# ptctest %d, flushopt %d\n", sn2_ptctest, sn2_flush_opt);
|
||||
}
|
||||
|
||||
if (cpu < NR_CPUS && cpu_online(cpu)) {
|
||||
stat = &per_cpu(ptcstats, cpu);
|
||||
seq_printf(file, "cpu %d %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld\n", cpu, stat->ptc_l,
|
||||
seq_printf(file, "cpu %d %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld\n", cpu, stat->ptc_l,
|
||||
stat->change_rid, stat->shub_ptc_flushes, stat->nodes_flushed,
|
||||
stat->deadlocks,
|
||||
1000 * stat->lock_itc_clocks / per_cpu(cpu_info, cpu).cyc_per_usec,
|
||||
1000 * stat->shub_itc_clocks / per_cpu(cpu_info, cpu).cyc_per_usec,
|
||||
1000 * stat->shub_itc_clocks_max / per_cpu(cpu_info, cpu).cyc_per_usec,
|
||||
stat->shub_ptc_flushes_not_my_mm,
|
||||
stat->deadlocks2);
|
||||
stat->deadlocks2,
|
||||
stat->shub_ipi_flushes,
|
||||
1000 * stat->shub_ipi_flushes_itc_clocks / per_cpu(cpu_info, cpu).cyc_per_usec);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t sn2_ptc_proc_write(struct file *file, const char __user *user, size_t count, loff_t *data)
|
||||
{
|
||||
int cpu;
|
||||
char optstr[64];
|
||||
|
||||
if (copy_from_user(optstr, user, count))
|
||||
return -EFAULT;
|
||||
optstr[count - 1] = '\0';
|
||||
sn2_flush_opt = simple_strtoul(optstr, NULL, 0);
|
||||
|
||||
for_each_online_cpu(cpu)
|
||||
memset(&per_cpu(ptcstats, cpu), 0, sizeof(struct ptc_stats));
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static struct seq_operations sn2_ptc_seq_ops = {
|
||||
.start = sn2_ptc_seq_start,
|
||||
.next = sn2_ptc_seq_next,
|
||||
@@ -458,6 +512,7 @@ static int sn2_ptc_proc_open(struct inode *inode, struct file *file)
|
||||
static const struct file_operations proc_sn2_ptc_operations = {
|
||||
.open = sn2_ptc_proc_open,
|
||||
.read = seq_read,
|
||||
.write = sn2_ptc_proc_write,
|
||||
.llseek = seq_lseek,
|
||||
.release = seq_release,
|
||||
};
|
||||
|
Reference in New Issue
Block a user