Merge branch 'master' into for_paulus
[linux-drm-fsl-dcu.git] / arch / ia64 / sn / kernel / sn2 / sn2_smp.c
index f153a4c35c70b206cbcbb450de72feb943d3be16..601747b1e22aa82c54dba040f6cb31034436facf 100644 (file)
@@ -46,8 +46,14 @@ DECLARE_PER_CPU(struct ptc_stats, ptcstats);
 
 static  __cacheline_aligned DEFINE_SPINLOCK(sn2_global_ptc_lock);
 
-void sn2_ptc_deadlock_recovery(short *, short, short, int, volatile unsigned long *, unsigned long,
-       volatile unsigned long *, unsigned long);
+extern unsigned long
+sn2_ptc_deadlock_recovery_core(volatile unsigned long *, unsigned long,
+                              volatile unsigned long *, unsigned long,
+                              volatile unsigned long *, unsigned long);
+void
+sn2_ptc_deadlock_recovery(short *, short, short, int,
+                         volatile unsigned long *, unsigned long,
+                         volatile unsigned long *, unsigned long);
 
 /*
  * Note: some is the following is captured here to make degugging easier
@@ -59,16 +65,6 @@ void sn2_ptc_deadlock_recovery(short *, short, short, int, volatile unsigned lon
 #define reset_max_active_on_deadlock() 1
 #define PTC_LOCK(sh1)                  ((sh1) ? &sn2_global_ptc_lock : &sn_nodepda->ptc_lock)
 
-static inline void ptc_lock(int sh1, unsigned long *flagp)
-{
-       spin_lock_irqsave(PTC_LOCK(sh1), *flagp);
-}
-
-static inline void ptc_unlock(int sh1, unsigned long flags)
-{
-       spin_unlock_irqrestore(PTC_LOCK(sh1), flags);
-}
-
 struct ptc_stats {
        unsigned long ptc_l;
        unsigned long change_rid;
@@ -82,6 +78,8 @@ struct ptc_stats {
        unsigned long shub_ptc_flushes_not_my_mm;
 };
 
+#define sn2_ptctest    0
+
 static inline unsigned long wait_piowc(void)
 {
        volatile unsigned long *piows;
@@ -95,6 +93,27 @@ static inline unsigned long wait_piowc(void)
        return (ws & SH_PIO_WRITE_STATUS_WRITE_DEADLOCK_MASK) != 0;
 }
 
+/**
+ * sn_migrate - SN-specific task migration actions
+ * @task: Task being migrated to new CPU
+ *
+ * SN2 PIO writes from separate CPUs are not guaranteed to arrive in order.
+ * Context switching user threads which have memory-mapped MMIO may cause
+ * PIOs to issue from seperate CPUs, thus the PIO writes must be drained
+ * from the previous CPU's Shub before execution resumes on the new CPU.
+ */
+void sn_migrate(struct task_struct *task)
+{
+       pda_t *last_pda = pdacpu(task_thread_info(task)->last_cpu);
+       volatile unsigned long *adr = last_pda->pio_write_status_addr;
+       unsigned long val = last_pda->pio_write_status_val;
+
+       /* Drain PIO writes from old CPU's Shub */
+       while (unlikely((*adr & SH_PIO_WRITE_STATUS_PENDING_WRITE_COUNT_MASK)
+                       != val))
+               cpu_relax();
+}
+
 void sn_tlb_migrate_finish(struct mm_struct *mm)
 {
        /* flush_tlb_mm is inefficient if more than 1 users of mm */
@@ -200,7 +219,7 @@ sn2_global_tlb_purge(struct mm_struct *mm, unsigned long start,
        max_active = max_active_pio(shub1);
 
        itc = ia64_get_itc();
-       ptc_lock(shub1, &flags);
+       spin_lock_irqsave(PTC_LOCK(shub1), flags);
        itc2 = ia64_get_itc();
 
        __get_cpu_var(ptcstats).lock_itc_clocks += itc2 - itc;
@@ -258,7 +277,7 @@ sn2_global_tlb_purge(struct mm_struct *mm, unsigned long start,
                ia64_srlz_d();
        }
 
-       ptc_unlock(shub1, flags);
+       spin_unlock_irqrestore(PTC_LOCK(shub1), flags);
 
        preempt_enable();
 }
@@ -270,11 +289,12 @@ sn2_global_tlb_purge(struct mm_struct *mm, unsigned long start,
  * TLB flush transaction.  The recovery sequence is somewhat tricky & is
  * coded in assembly language.
  */
-void sn2_ptc_deadlock_recovery(short *nasids, short ib, short ie, int mynasid, volatile unsigned long *ptc0, unsigned long data0,
-       volatile unsigned long *ptc1, unsigned long data1)
+
+void
+sn2_ptc_deadlock_recovery(short *nasids, short ib, short ie, int mynasid,
+                         volatile unsigned long *ptc0, unsigned long data0,
+                         volatile unsigned long *ptc1, unsigned long data1)
 {
-       extern unsigned long sn2_ptc_deadlock_recovery_core(volatile unsigned long *, unsigned long,
-               volatile unsigned long *, unsigned long, volatile unsigned long *, unsigned long);
        short nasid, i;
        unsigned long *piows, zeroval, n;
 
@@ -435,7 +455,7 @@ static int sn2_ptc_proc_open(struct inode *inode, struct file *file)
        return seq_open(file, &sn2_ptc_seq_ops);
 }
 
-static struct file_operations proc_sn2_ptc_operations = {
+static const struct file_operations proc_sn2_ptc_operations = {
        .open = sn2_ptc_proc_open,
        .read = seq_read,
        .llseek = seq_lseek,
@@ -447,7 +467,7 @@ static struct proc_dir_entry *proc_sn2_ptc;
 static int __init sn2_ptc_init(void)
 {
        if (!ia64_platform_is("sn2"))
-               return -ENOSYS;
+               return 0;
 
        if (!(proc_sn2_ptc = create_proc_entry(PTC_BASENAME, 0444, NULL))) {
                printk(KERN_ERR "unable to create %s proc entry", PTC_BASENAME);