Merge remote branch 'origin/master' into merge
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>
Fri, 20 May 2011 05:36:52 +0000 (15:36 +1000)
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>
Fri, 20 May 2011 05:36:52 +0000 (15:36 +1000)
Manual merge of arch/powerpc/kernel/smp.c and add missing scheduler_ipi()
call to arch/powerpc/platforms/cell/interrupt.c

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
1  2 
arch/powerpc/include/asm/mpic.h
arch/powerpc/kernel/smp.c
arch/powerpc/kernel/traps.c
arch/powerpc/platforms/cell/interrupt.c
arch/powerpc/platforms/powermac/pic.c
arch/powerpc/sysdev/ipic.c
arch/powerpc/sysdev/mpic.c

@@@ -3,7 -3,6 +3,6 @@@
  #ifdef __KERNEL__
  
  #include <linux/irq.h>
- #include <linux/sysdev.h>
  #include <asm/dcr.h>
  #include <asm/msi_bitmap.h>
  
@@@ -263,7 -262,6 +262,7 @@@ struct mpi
  #ifdef CONFIG_SMP
        struct irq_chip         hc_ipi;
  #endif
 +      struct irq_chip         hc_tm;
        const char              *name;
        /* Flags */
        unsigned int            flags;
  
        /* vector numbers used for internal sources (ipi/timers) */
        unsigned int            ipi_vecs[4];
 -      unsigned int            timer_vecs[4];
 +      unsigned int            timer_vecs[8];
  
        /* Spurious vector to program into unused sources */
        unsigned int            spurious_vec;
        /* link */
        struct mpic             *next;
  
-       struct sys_device       sysdev;
  #ifdef CONFIG_PM
        struct mpic_irq_save    *save_data;
  #endif
   * NOTE: This flag trumps MPIC_WANTS_RESET.
   */
  #define MPIC_NO_RESET                 0x00004000
 +/* Freescale MPIC (compatible includes "fsl,mpic") */
 +#define MPIC_FSL                      0x00008000
  
  /* MPIC HW modification ID */
  #define MPIC_REGSET_MASK              0xf0000000
@@@ -95,7 -95,7 +95,7 @@@ int smt_enabled_at_boot = 1
  static void (*crash_ipi_function_ptr)(struct pt_regs *) = NULL;
  
  #ifdef CONFIG_PPC64
 -void __devinit smp_generic_kick_cpu(int nr)
 +int __devinit smp_generic_kick_cpu(int nr)
  {
        BUG_ON(nr < 0 || nr >= NR_CPUS);
  
         */
        paca[nr].cpu_start = 1;
        smp_mb();
 -}
 -#endif
  
 -void smp_message_recv(int msg)
 -{
 -      switch(msg) {
 -      case PPC_MSG_CALL_FUNCTION:
 -              generic_smp_call_function_interrupt();
 -              break;
 -      case PPC_MSG_RESCHEDULE:
 -              scheduler_ipi();
 -              break;
 -      case PPC_MSG_CALL_FUNC_SINGLE:
 -              generic_smp_call_function_single_interrupt();
 -              break;
 -      case PPC_MSG_DEBUGGER_BREAK:
 -              if (crash_ipi_function_ptr) {
 -                      crash_ipi_function_ptr(get_irq_regs());
 -                      break;
 -              }
 -#ifdef CONFIG_DEBUGGER
 -              debugger_ipi(get_irq_regs());
 -              break;
 -#endif /* CONFIG_DEBUGGER */
 -              /* FALLTHROUGH */
 -      default:
 -              printk("SMP %d: smp_message_recv(): unknown msg %d\n",
 -                     smp_processor_id(), msg);
 -              break;
 -      }
 +      return 0;
  }
 +#endif
  
  static irqreturn_t call_function_action(int irq, void *data)
  {
  
  static irqreturn_t reschedule_action(int irq, void *data)
  {
-       /* we just need the return path side effect of checking need_resched */
+       scheduler_ipi();
        return IRQ_HANDLED;
  }
  
@@@ -129,17 -156,9 +129,17 @@@ static irqreturn_t call_function_single
        return IRQ_HANDLED;
  }
  
 -static irqreturn_t debug_ipi_action(int irq, void *data)
 +irqreturn_t debug_ipi_action(int irq, void *data)
  {
 -      smp_message_recv(PPC_MSG_DEBUGGER_BREAK);
 +      if (crash_ipi_function_ptr) {
 +              crash_ipi_function_ptr(get_irq_regs());
 +              return IRQ_HANDLED;
 +      }
 +
 +#ifdef CONFIG_DEBUGGER
 +      debugger_ipi(get_irq_regs());
 +#endif /* CONFIG_DEBUGGER */
 +
        return IRQ_HANDLED;
  }
  
@@@ -178,66 -197,6 +178,66 @@@ int smp_request_message_ipi(int virq, i
        return err;
  }
  
-                       reschedule_action(0, NULL); /* upcoming sched hook */
 +#ifdef CONFIG_PPC_SMP_MUXED_IPI
 +struct cpu_messages {
 +      int messages;                   /* current messages */
 +      unsigned long data;             /* data for cause ipi */
 +};
 +static DEFINE_PER_CPU_SHARED_ALIGNED(struct cpu_messages, ipi_message);
 +
 +void smp_muxed_ipi_set_data(int cpu, unsigned long data)
 +{
 +      struct cpu_messages *info = &per_cpu(ipi_message, cpu);
 +
 +      info->data = data;
 +}
 +
 +void smp_muxed_ipi_message_pass(int cpu, int msg)
 +{
 +      struct cpu_messages *info = &per_cpu(ipi_message, cpu);
 +      char *message = (char *)&info->messages;
 +
 +      message[msg] = 1;
 +      mb();
 +      smp_ops->cause_ipi(cpu, info->data);
 +}
 +
 +void smp_muxed_ipi_resend(void)
 +{
 +      struct cpu_messages *info = &__get_cpu_var(ipi_message);
 +
 +      if (info->messages)
 +              smp_ops->cause_ipi(smp_processor_id(), info->data);
 +}
 +
 +irqreturn_t smp_ipi_demux(void)
 +{
 +      struct cpu_messages *info = &__get_cpu_var(ipi_message);
 +      unsigned int all;
 +
 +      mb();   /* order any irq clear */
 +
 +      do {
 +              all = xchg_local(&info->messages, 0);
 +
 +#ifdef __BIG_ENDIAN
 +              if (all & (1 << (24 - 8 * PPC_MSG_CALL_FUNCTION)))
 +                      generic_smp_call_function_interrupt();
 +              if (all & (1 << (24 - 8 * PPC_MSG_RESCHEDULE)))
++                      scheduler_ipi();
 +              if (all & (1 << (24 - 8 * PPC_MSG_CALL_FUNC_SINGLE)))
 +                      generic_smp_call_function_single_interrupt();
 +              if (all & (1 << (24 - 8 * PPC_MSG_DEBUGGER_BREAK)))
 +                      debug_ipi_action(0, NULL);
 +#else
 +#error Unsupported ENDIAN
 +#endif
 +      } while (info->messages);
 +
 +      return IRQ_HANDLED;
 +}
 +#endif /* CONFIG_PPC_SMP_MUXED_IPI */
 +
  void smp_send_reschedule(int cpu)
  {
        if (likely(smp_ops))
@@@ -257,18 -216,11 +257,18 @@@ void arch_send_call_function_ipi_mask(c
                smp_ops->message_pass(cpu, PPC_MSG_CALL_FUNCTION);
  }
  
 -#ifdef CONFIG_DEBUGGER
 -void smp_send_debugger_break(int cpu)
 +#if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC)
 +void smp_send_debugger_break(void)
  {
 -      if (likely(smp_ops))
 -              smp_ops->message_pass(cpu, PPC_MSG_DEBUGGER_BREAK);
 +      int cpu;
 +      int me = raw_smp_processor_id();
 +
 +      if (unlikely(!smp_ops))
 +              return;
 +
 +      for_each_online_cpu(cpu)
 +              if (cpu != me)
 +                      smp_ops->message_pass(cpu, PPC_MSG_DEBUGGER_BREAK);
  }
  #endif
  
  void crash_send_ipi(void (*crash_ipi_callback)(struct pt_regs *))
  {
        crash_ipi_function_ptr = crash_ipi_callback;
 -      if (crash_ipi_callback && smp_ops) {
 +      if (crash_ipi_callback) {
                mb();
 -              smp_ops->message_pass(MSG_ALL_BUT_SELF, PPC_MSG_DEBUGGER_BREAK);
 +              smp_send_debugger_break();
        }
  }
  #endif
@@@ -458,6 -410,8 +458,6 @@@ int __cpuinit __cpu_up(unsigned int cpu
  {
        int rc, c;
  
 -      secondary_ti = current_set[cpu];
 -
        if (smp_ops == NULL ||
            (smp_ops->cpu_bootable && !smp_ops->cpu_bootable(cpu)))
                return -EINVAL;
        if (rc)
                return rc;
  
 +      secondary_ti = current_set[cpu];
 +
        /* Make sure callin-map entry is 0 (can be leftover a CPU
         * hotplug
         */
  
        /* wake up cpus */
        DBG("smp: kicking cpu %d\n", cpu);
 -      smp_ops->kick_cpu(cpu);
 +      rc = smp_ops->kick_cpu(cpu);
 +      if (rc) {
 +              pr_err("smp: failed starting cpu %d (rc %d)\n", cpu, rc);
 +              return rc;
 +      }
  
        /*
         * wait to see if the cpu made a callin (is actually up).
@@@ -559,7 -507,7 +559,7 @@@ int cpu_first_thread_of_core(int core
  }
  EXPORT_SYMBOL_GPL(cpu_first_thread_of_core);
  
 -/* Must be called when no change can occur to cpu_present_map,
 +/* Must be called when no change can occur to cpu_present_mask,
   * i.e. during cpu online or offline.
   */
  static struct device_node *cpu_to_l2cache(int cpu)
@@@ -660,7 -608,7 +660,7 @@@ void __init smp_cpus_done(unsigned int 
         * se we pin us down to CPU 0 for a short while
         */
        alloc_cpumask_var(&old_mask, GFP_NOWAIT);
 -      cpumask_copy(old_mask, &current->cpus_allowed);
 +      cpumask_copy(old_mask, tsk_cpus_allowed(current));
        set_cpus_allowed_ptr(current, cpumask_of(boot_cpuid));
        
        if (smp_ops && smp_ops->setup_cpu)
@@@ -143,7 -143,6 +143,6 @@@ int die(const char *str, struct pt_reg
  #endif
                printk("%s\n", ppc_md.name ? ppc_md.name : "");
  
-               sysfs_printk_last_file();
                if (notify_die(DIE_OOPS, str, regs, err, 255,
                               SIGSEGV) == NOTIFY_STOP)
                        return 1;
@@@ -199,7 -198,7 +198,7 @@@ void _exception(int signr, struct pt_re
        } else if (show_unhandled_signals &&
                    unhandled_signal(current, signr) &&
                    printk_ratelimit()) {
 -                      printk(regs->msr & MSR_SF ? fmt64 : fmt32,
 +                      printk(regs->msr & MSR_64BIT ? fmt64 : fmt32,
                                current->comm, current->pid, signr,
                                addr, regs->nip, regs->link, code);
                }
@@@ -221,7 -220,7 +220,7 @@@ void system_reset_exception(struct pt_r
        }
  
  #ifdef CONFIG_KEXEC
 -      cpu_set(smp_processor_id(), cpus_in_sr);
 +      cpumask_set_cpu(smp_processor_id(), &cpus_in_sr);
  #endif
  
        die("System Reset", regs, SIGABRT);
@@@ -909,26 -908,6 +908,26 @@@ static int emulate_instruction(struct p
                return emulate_isel(regs, instword);
        }
  
 +#ifdef CONFIG_PPC64
 +      /* Emulate the mfspr rD, DSCR. */
 +      if (((instword & PPC_INST_MFSPR_DSCR_MASK) == PPC_INST_MFSPR_DSCR) &&
 +                      cpu_has_feature(CPU_FTR_DSCR)) {
 +              PPC_WARN_EMULATED(mfdscr, regs);
 +              rd = (instword >> 21) & 0x1f;
 +              regs->gpr[rd] = mfspr(SPRN_DSCR);
 +              return 0;
 +      }
 +      /* Emulate the mtspr DSCR, rD. */
 +      if (((instword & PPC_INST_MTSPR_DSCR_MASK) == PPC_INST_MTSPR_DSCR) &&
 +                      cpu_has_feature(CPU_FTR_DSCR)) {
 +              PPC_WARN_EMULATED(mtdscr, regs);
 +              rd = (instword >> 21) & 0x1f;
 +              mtspr(SPRN_DSCR, regs->gpr[rd]);
 +              current->thread.dscr_inherit = 1;
 +              return 0;
 +      }
 +#endif
 +
        return -EINVAL;
  }
  
@@@ -1526,10 -1505,6 +1525,10 @@@ struct ppc_emulated ppc_emulated = 
  #ifdef CONFIG_VSX
        WARN_EMULATED_SETUP(vsx),
  #endif
 +#ifdef CONFIG_PPC64
 +      WARN_EMULATED_SETUP(mfdscr),
 +      WARN_EMULATED_SETUP(mtdscr),
 +#endif
  };
  
  u32 ppc_warn_emulated;
@@@ -196,20 -196,8 +196,20 @@@ static irqreturn_t iic_ipi_action(int i
  {
        int ipi = (int)(long)dev_id;
  
 -      smp_message_recv(ipi);
 -
 +      switch(ipi) {
 +      case PPC_MSG_CALL_FUNCTION:
 +              generic_smp_call_function_interrupt();
 +              break;
 +      case PPC_MSG_RESCHEDULE:
-               /* Upcoming sched hook */
++              scheduler_ipi();
 +              break;
 +      case PPC_MSG_CALL_FUNC_SINGLE:
 +              generic_smp_call_function_single_interrupt();
 +              break;
 +      case PPC_MSG_DEBUGGER_BREAK:
 +              debug_ipi_action(0, NULL);
 +              break;
 +      }
        return IRQ_HANDLED;
  }
  static void iic_request_ipi(int ipi, const char *name)
@@@ -21,7 -21,7 +21,7 @@@
  #include <linux/signal.h>
  #include <linux/pci.h>
  #include <linux/interrupt.h>
- #include <linux/sysdev.h>
+ #include <linux/syscore_ops.h>
  #include <linux/adb.h>
  #include <linux/pmu.h>
  #include <linux/module.h>
@@@ -84,7 -84,7 +84,7 @@@ static void __pmac_retrigger(unsigned i
  
  static void pmac_mask_and_ack_irq(struct irq_data *d)
  {
 -      unsigned int src = irq_map[d->irq].hwirq;
 +      unsigned int src = irqd_to_hwirq(d);
          unsigned long bit = 1UL << (src & 0x1f);
          int i = src >> 5;
          unsigned long flags;
  
  static void pmac_ack_irq(struct irq_data *d)
  {
 -      unsigned int src = irq_map[d->irq].hwirq;
 +      unsigned int src = irqd_to_hwirq(d);
          unsigned long bit = 1UL << (src & 0x1f);
          int i = src >> 5;
          unsigned long flags;
@@@ -152,7 -152,7 +152,7 @@@ static void __pmac_set_irq_mask(unsigne
  static unsigned int pmac_startup_irq(struct irq_data *d)
  {
        unsigned long flags;
 -      unsigned int src = irq_map[d->irq].hwirq;
 +      unsigned int src = irqd_to_hwirq(d);
          unsigned long bit = 1UL << (src & 0x1f);
          int i = src >> 5;
  
  static void pmac_mask_irq(struct irq_data *d)
  {
        unsigned long flags;
 -      unsigned int src = irq_map[d->irq].hwirq;
 +      unsigned int src = irqd_to_hwirq(d);
  
        raw_spin_lock_irqsave(&pmac_pic_lock, flags);
          __clear_bit(src, ppc_cached_irq_mask);
  static void pmac_unmask_irq(struct irq_data *d)
  {
        unsigned long flags;
 -      unsigned int src = irq_map[d->irq].hwirq;
 +      unsigned int src = irqd_to_hwirq(d);
  
        raw_spin_lock_irqsave(&pmac_pic_lock, flags);
        __set_bit(src, ppc_cached_irq_mask);
@@@ -193,7 -193,7 +193,7 @@@ static int pmac_retrigger(struct irq_da
        unsigned long flags;
  
        raw_spin_lock_irqsave(&pmac_pic_lock, flags);
 -      __pmac_retrigger(irq_map[d->irq].hwirq);
 +      __pmac_retrigger(irqd_to_hwirq(d));
        raw_spin_unlock_irqrestore(&pmac_pic_lock, flags);
        return 1;
  }
@@@ -239,12 -239,15 +239,12 @@@ static unsigned int pmac_pic_get_irq(vo
        unsigned long bits = 0;
        unsigned long flags;
  
 -#ifdef CONFIG_SMP
 -      void psurge_smp_message_recv(void);
 -
 -              /* IPI's are a hack on the powersurge -- Cort */
 -              if ( smp_processor_id() != 0 ) {
 -              psurge_smp_message_recv();
 -              return NO_IRQ_IGNORE;   /* ignore, already handled */
 +#ifdef CONFIG_PPC_PMAC32_PSURGE
 +      /* IPI's are a hack on the powersurge -- Cort */
 +      if (smp_processor_id() != 0) {
 +              return  psurge_secondary_virq;
          }
 -#endif /* CONFIG_SMP */
 +#endif /* CONFIG_PPC_PMAC32_PSURGE */
        raw_spin_lock_irqsave(&pmac_pic_lock, flags);
        for (irq = max_real_irqs; (irq -= 32) >= 0; ) {
                int i = irq >> 5;
@@@ -674,7 -677,7 +674,7 @@@ not_found
        return viaint;
  }
  
- static int pmacpic_suspend(struct sys_device *sysdev, pm_message_t state)
+ static int pmacpic_suspend(void)
  {
        int viaint = pmacpic_find_viaint();
  
          return 0;
  }
  
- static int pmacpic_resume(struct sys_device *sysdev)
+ static void pmacpic_resume(void)
  {
        int i;
  
        for (i = 0; i < max_real_irqs; ++i)
                if (test_bit(i, sleep_save_mask))
                        pmac_unmask_irq(irq_get_irq_data(i));
-       return 0;
  }
  
- #endif /* CONFIG_PM && CONFIG_PPC32 */
- static struct sysdev_class pmacpic_sysclass = {
-       .name = "pmac_pic",
+ static struct syscore_ops pmacpic_syscore_ops = {
+       .suspend        = pmacpic_suspend,
+       .resume         = pmacpic_resume,
  };
  
- static struct sys_device device_pmacpic = {
-       .id             = 0,
-       .cls            = &pmacpic_sysclass,
- };
- static struct sysdev_driver driver_pmacpic = {
- #if defined(CONFIG_PM) && defined(CONFIG_PPC32)
-       .suspend        = &pmacpic_suspend,
-       .resume         = &pmacpic_resume,
- #endif /* CONFIG_PM && CONFIG_PPC32 */
- };
- static int __init init_pmacpic_sysfs(void)
+ static int __init init_pmacpic_syscore(void)
  {
- #ifdef CONFIG_PPC32
-       if (max_irqs == 0)
-               return -ENODEV;
- #endif
-       printk(KERN_DEBUG "Registering pmac pic with sysfs...\n");
-       sysdev_class_register(&pmacpic_sysclass);
-       sysdev_register(&device_pmacpic);
-       sysdev_driver_register(&pmacpic_sysclass, &driver_pmacpic);
+       register_syscore_ops(&pmacpic_syscore_ops);
        return 0;
  }
- machine_subsys_initcall(powermac, init_pmacpic_sysfs);
  
+ machine_subsys_initcall(powermac, init_pmacpic_syscore);
+ #endif /* CONFIG_PM && CONFIG_PPC32 */
@@@ -18,7 -18,7 +18,7 @@@
  #include <linux/stddef.h>
  #include <linux/sched.h>
  #include <linux/signal.h>
- #include <linux/sysdev.h>
+ #include <linux/syscore_ops.h>
  #include <linux/device.h>
  #include <linux/bootmem.h>
  #include <linux/spinlock.h>
@@@ -521,10 -521,12 +521,10 @@@ static inline struct ipic * ipic_from_i
        return primary_ipic;
  }
  
 -#define ipic_irq_to_hw(virq)  ((unsigned int)irq_map[virq].hwirq)
 -
  static void ipic_unmask_irq(struct irq_data *d)
  {
        struct ipic *ipic = ipic_from_irq(d->irq);
 -      unsigned int src = ipic_irq_to_hw(d->irq);
 +      unsigned int src = irqd_to_hwirq(d);
        unsigned long flags;
        u32 temp;
  
  static void ipic_mask_irq(struct irq_data *d)
  {
        struct ipic *ipic = ipic_from_irq(d->irq);
 -      unsigned int src = ipic_irq_to_hw(d->irq);
 +      unsigned int src = irqd_to_hwirq(d);
        unsigned long flags;
        u32 temp;
  
  static void ipic_ack_irq(struct irq_data *d)
  {
        struct ipic *ipic = ipic_from_irq(d->irq);
 -      unsigned int src = ipic_irq_to_hw(d->irq);
 +      unsigned int src = irqd_to_hwirq(d);
        unsigned long flags;
        u32 temp;
  
  static void ipic_mask_irq_and_ack(struct irq_data *d)
  {
        struct ipic *ipic = ipic_from_irq(d->irq);
 -      unsigned int src = ipic_irq_to_hw(d->irq);
 +      unsigned int src = irqd_to_hwirq(d);
        unsigned long flags;
        u32 temp;
  
  static int ipic_set_irq_type(struct irq_data *d, unsigned int flow_type)
  {
        struct ipic *ipic = ipic_from_irq(d->irq);
 -      unsigned int src = ipic_irq_to_hw(d->irq);
 +      unsigned int src = irqd_to_hwirq(d);
        unsigned int vold, vnew, edibit;
  
        if (flow_type == IRQ_TYPE_NONE)
@@@ -791,7 -793,7 +791,7 @@@ struct ipic * __init ipic_init(struct d
  int ipic_set_priority(unsigned int virq, unsigned int priority)
  {
        struct ipic *ipic = ipic_from_irq(virq);
 -      unsigned int src = ipic_irq_to_hw(virq);
 +      unsigned int src = virq_to_hw(virq);
        u32 temp;
  
        if (priority > 7)
  void ipic_set_highest_priority(unsigned int virq)
  {
        struct ipic *ipic = ipic_from_irq(virq);
 -      unsigned int src = ipic_irq_to_hw(virq);
 +      unsigned int src = virq_to_hw(virq);
        u32 temp;
  
        temp = ipic_read(ipic->regs, IPIC_SICFR);
@@@ -900,7 -902,7 +900,7 @@@ static struct 
        u32 sercr;
  } ipic_saved_state;
  
- static int ipic_suspend(struct sys_device *sdev, pm_message_t state)
+ static int ipic_suspend(void)
  {
        struct ipic *ipic = primary_ipic;
  
        return 0;
  }
  
- static int ipic_resume(struct sys_device *sdev)
+ static void ipic_resume(void)
  {
        struct ipic *ipic = primary_ipic;
  
        ipic_write(ipic->regs, IPIC_SECNR, ipic_saved_state.secnr);
        ipic_write(ipic->regs, IPIC_SERMR, ipic_saved_state.sermr);
        ipic_write(ipic->regs, IPIC_SERCR, ipic_saved_state.sercr);
-       return 0;
  }
  #else
  #define ipic_suspend NULL
  #define ipic_resume NULL
  #endif
  
- static struct sysdev_class ipic_sysclass = {
-       .name = "ipic",
+ static struct syscore_ops ipic_syscore_ops = {
        .suspend = ipic_suspend,
        .resume = ipic_resume,
  };
  
- static struct sys_device device_ipic = {
-       .id             = 0,
-       .cls            = &ipic_sysclass,
- };
- static int __init init_ipic_sysfs(void)
+ static int __init init_ipic_syscore(void)
  {
-       int rc;
        if (!primary_ipic || !primary_ipic->regs)
                return -ENODEV;
-       printk(KERN_DEBUG "Registering ipic with sysfs...\n");
  
-       rc = sysdev_class_register(&ipic_sysclass);
-       if (rc) {
-               printk(KERN_ERR "Failed registering ipic sys class\n");
-               return -ENODEV;
-       }
-       rc = sysdev_register(&device_ipic);
-       if (rc) {
-               printk(KERN_ERR "Failed registering ipic sys device\n");
-               return -ENODEV;
-       }
+       printk(KERN_DEBUG "Registering ipic system core operations\n");
+       register_syscore_ops(&ipic_syscore_ops);
        return 0;
  }
  
- subsys_initcall(init_ipic_sysfs);
+ subsys_initcall(init_ipic_syscore);
@@@ -6,7 -6,6 +6,7 @@@
   *  with various broken implementations of this HW.
   *
   *  Copyright (C) 2004 Benjamin Herrenschmidt, IBM Corp.
 + *  Copyright 2010-2011 Freescale Semiconductor, Inc.
   *
   *  This file is subject to the terms and conditions of the GNU General Public
   *  License.  See the file COPYING in the main directory of this archive
@@@ -28,6 -27,7 +28,7 @@@
  #include <linux/spinlock.h>
  #include <linux/pci.h>
  #include <linux/slab.h>
+ #include <linux/syscore_ops.h>
  
  #include <asm/ptrace.h>
  #include <asm/signal.h>
@@@ -219,28 -219,6 +220,28 @@@ static inline void _mpic_ipi_write(stru
        _mpic_write(mpic->reg_type, &mpic->gregs, offset, value);
  }
  
 +static inline u32 _mpic_tm_read(struct mpic *mpic, unsigned int tm)
 +{
 +      unsigned int offset = MPIC_INFO(TIMER_VECTOR_PRI) +
 +                            ((tm & 3) * MPIC_INFO(TIMER_STRIDE));
 +
 +      if (tm >= 4)
 +              offset += 0x1000 / 4;
 +
 +      return _mpic_read(mpic->reg_type, &mpic->tmregs, offset);
 +}
 +
 +static inline void _mpic_tm_write(struct mpic *mpic, unsigned int tm, u32 value)
 +{
 +      unsigned int offset = MPIC_INFO(TIMER_VECTOR_PRI) +
 +                            ((tm & 3) * MPIC_INFO(TIMER_STRIDE));
 +
 +      if (tm >= 4)
 +              offset += 0x1000 / 4;
 +
 +      _mpic_write(mpic->reg_type, &mpic->tmregs, offset, value);
 +}
 +
  static inline u32 _mpic_cpu_read(struct mpic *mpic, unsigned int reg)
  {
        unsigned int cpu = mpic_processor_id(mpic);
@@@ -291,8 -269,6 +292,8 @@@ static inline void _mpic_irq_write(stru
  #define mpic_write(b,r,v)     _mpic_write(mpic->reg_type,&(b),(r),(v))
  #define mpic_ipi_read(i)      _mpic_ipi_read(mpic,(i))
  #define mpic_ipi_write(i,v)   _mpic_ipi_write(mpic,(i),(v))
 +#define mpic_tm_read(i)               _mpic_tm_read(mpic,(i))
 +#define mpic_tm_write(i,v)    _mpic_tm_write(mpic,(i),(v))
  #define mpic_cpu_read(i)      _mpic_cpu_read(mpic,(i))
  #define mpic_cpu_write(i,v)   _mpic_cpu_write(mpic,(i),(v))
  #define mpic_irq_read(s,r)    _mpic_irq_read(mpic,(s),(r))
@@@ -632,6 -608,8 +633,6 @@@ static int irq_choose_cpu(const struct 
  }
  #endif
  
 -#define mpic_irq_to_hw(virq)  ((unsigned int)irq_map[virq].hwirq)
 -
  /* Find an mpic associated with a given linux interrupt */
  static struct mpic *mpic_find(unsigned int irq)
  {
  /* Determine if the linux irq is an IPI */
  static unsigned int mpic_is_ipi(struct mpic *mpic, unsigned int irq)
  {
 -      unsigned int src = mpic_irq_to_hw(irq);
 +      unsigned int src = virq_to_hw(irq);
  
        return (src >= mpic->ipi_vecs[0] && src <= mpic->ipi_vecs[3]);
  }
  
 +/* Determine if the linux irq is a timer */
 +static unsigned int mpic_is_tm(struct mpic *mpic, unsigned int irq)
 +{
 +      unsigned int src = virq_to_hw(irq);
 +
 +      return (src >= mpic->timer_vecs[0] && src <= mpic->timer_vecs[7]);
 +}
  
  /* Convert a cpu mask from logical to physical cpu numbers. */
  static inline u32 mpic_physmask(u32 cpumask)
        int i;
        u32 mask = 0;
  
 -      for (i = 0; i < NR_CPUS; ++i, cpumask >>= 1)
 +      for (i = 0; i < min(32, NR_CPUS); ++i, cpumask >>= 1)
                mask |= (cpumask & 1) << get_hard_smp_processor_id(i);
        return mask;
  }
@@@ -704,7 -675,7 +705,7 @@@ void mpic_unmask_irq(struct irq_data *d
  {
        unsigned int loops = 100000;
        struct mpic *mpic = mpic_from_irq_data(d);
 -      unsigned int src = mpic_irq_to_hw(d->irq);
 +      unsigned int src = irqd_to_hwirq(d);
  
        DBG("%p: %s: enable_irq: %d (src %d)\n", mpic, mpic->name, d->irq, src);
  
@@@ -725,7 -696,7 +726,7 @@@ void mpic_mask_irq(struct irq_data *d
  {
        unsigned int loops = 100000;
        struct mpic *mpic = mpic_from_irq_data(d);
 -      unsigned int src = mpic_irq_to_hw(d->irq);
 +      unsigned int src = irqd_to_hwirq(d);
  
        DBG("%s: disable_irq: %d (src %d)\n", mpic->name, d->irq, src);
  
@@@ -763,7 -734,7 +764,7 @@@ void mpic_end_irq(struct irq_data *d
  static void mpic_unmask_ht_irq(struct irq_data *d)
  {
        struct mpic *mpic = mpic_from_irq_data(d);
 -      unsigned int src = mpic_irq_to_hw(d->irq);
 +      unsigned int src = irqd_to_hwirq(d);
  
        mpic_unmask_irq(d);
  
  static unsigned int mpic_startup_ht_irq(struct irq_data *d)
  {
        struct mpic *mpic = mpic_from_irq_data(d);
 -      unsigned int src = mpic_irq_to_hw(d->irq);
 +      unsigned int src = irqd_to_hwirq(d);
  
        mpic_unmask_irq(d);
        mpic_startup_ht_interrupt(mpic, src, irqd_is_level_type(d));
  static void mpic_shutdown_ht_irq(struct irq_data *d)
  {
        struct mpic *mpic = mpic_from_irq_data(d);
 -      unsigned int src = mpic_irq_to_hw(d->irq);
 +      unsigned int src = irqd_to_hwirq(d);
  
        mpic_shutdown_ht_interrupt(mpic, src);
        mpic_mask_irq(d);
  static void mpic_end_ht_irq(struct irq_data *d)
  {
        struct mpic *mpic = mpic_from_irq_data(d);
 -      unsigned int src = mpic_irq_to_hw(d->irq);
 +      unsigned int src = irqd_to_hwirq(d);
  
  #ifdef DEBUG_IRQ
        DBG("%s: end_irq: %d\n", mpic->name, d->irq);
  static void mpic_unmask_ipi(struct irq_data *d)
  {
        struct mpic *mpic = mpic_from_ipi(d);
 -      unsigned int src = mpic_irq_to_hw(d->irq) - mpic->ipi_vecs[0];
 +      unsigned int src = virq_to_hw(d->irq) - mpic->ipi_vecs[0];
  
        DBG("%s: enable_ipi: %d (ipi %d)\n", mpic->name, d->irq, src);
        mpic_ipi_write(src, mpic_ipi_read(src) & ~MPIC_VECPRI_MASK);
@@@ -842,42 -813,27 +843,42 @@@ static void mpic_end_ipi(struct irq_dat
  
  #endif /* CONFIG_SMP */
  
 +static void mpic_unmask_tm(struct irq_data *d)
 +{
 +      struct mpic *mpic = mpic_from_irq_data(d);
 +      unsigned int src = virq_to_hw(d->irq) - mpic->timer_vecs[0];
 +
 +      DBG("%s: enable_tm: %d (tm %d)\n", mpic->name, irq, src);
 +      mpic_tm_write(src, mpic_tm_read(src) & ~MPIC_VECPRI_MASK);
 +      mpic_tm_read(src);
 +}
 +
 +static void mpic_mask_tm(struct irq_data *d)
 +{
 +      struct mpic *mpic = mpic_from_irq_data(d);
 +      unsigned int src = virq_to_hw(d->irq) - mpic->timer_vecs[0];
 +
 +      mpic_tm_write(src, mpic_tm_read(src) | MPIC_VECPRI_MASK);
 +      mpic_tm_read(src);
 +}
 +
  int mpic_set_affinity(struct irq_data *d, const struct cpumask *cpumask,
                      bool force)
  {
        struct mpic *mpic = mpic_from_irq_data(d);
 -      unsigned int src = mpic_irq_to_hw(d->irq);
 +      unsigned int src = irqd_to_hwirq(d);
  
        if (mpic->flags & MPIC_SINGLE_DEST_CPU) {
                int cpuid = irq_choose_cpu(cpumask);
  
                mpic_irq_write(src, MPIC_INFO(IRQ_DESTINATION), 1 << cpuid);
        } else {
 -              cpumask_var_t tmp;
 -
 -              alloc_cpumask_var(&tmp, GFP_KERNEL);
 +              u32 mask = cpumask_bits(cpumask)[0];
  
 -              cpumask_and(tmp, cpumask, cpu_online_mask);
 +              mask &= cpumask_bits(cpu_online_mask)[0];
  
                mpic_irq_write(src, MPIC_INFO(IRQ_DESTINATION),
 -                             mpic_physmask(cpumask_bits(tmp)[0]));
 -
 -              free_cpumask_var(tmp);
 +                             mpic_physmask(mask));
        }
  
        return 0;
@@@ -907,7 -863,7 +908,7 @@@ static unsigned int mpic_type_to_vecpri
  int mpic_set_irq_type(struct irq_data *d, unsigned int flow_type)
  {
        struct mpic *mpic = mpic_from_irq_data(d);
 -      unsigned int src = mpic_irq_to_hw(d->irq);
 +      unsigned int src = irqd_to_hwirq(d);
        unsigned int vecpri, vold, vnew;
  
        DBG("mpic: set_irq_type(mpic:@%p,virq:%d,src:0x%x,type:0x%x)\n",
  void mpic_set_vector(unsigned int virq, unsigned int vector)
  {
        struct mpic *mpic = mpic_from_irq(virq);
 -      unsigned int src = mpic_irq_to_hw(virq);
 +      unsigned int src = virq_to_hw(virq);
        unsigned int vecpri;
  
        DBG("mpic: set_vector(mpic:@%p,virq:%d,src:%d,vector:0x%x)\n",
  void mpic_set_destination(unsigned int virq, unsigned int cpuid)
  {
        struct mpic *mpic = mpic_from_irq(virq);
 -      unsigned int src = mpic_irq_to_hw(virq);
 +      unsigned int src = virq_to_hw(virq);
  
        DBG("mpic: set_destination(mpic:@%p,virq:%d,src:%d,cpuid:0x%x)\n",
            mpic, virq, src, cpuid);
@@@ -987,12 -943,6 +988,12 @@@ static struct irq_chip mpic_ipi_chip = 
  };
  #endif /* CONFIG_SMP */
  
 +static struct irq_chip mpic_tm_chip = {
 +      .irq_mask       = mpic_mask_tm,
 +      .irq_unmask     = mpic_unmask_tm,
 +      .irq_eoi        = mpic_end_irq,
 +};
 +
  #ifdef CONFIG_MPIC_U3_HT_IRQS
  static struct irq_chip mpic_irq_ht_chip = {
        .irq_startup    = mpic_startup_ht_irq,
@@@ -1036,16 -986,6 +1037,16 @@@ static int mpic_host_map(struct irq_hos
        }
  #endif /* CONFIG_SMP */
  
 +      if (hw >= mpic->timer_vecs[0] && hw <= mpic->timer_vecs[7]) {
 +              WARN_ON(!(mpic->flags & MPIC_PRIMARY));
 +
 +              DBG("mpic: mapping as timer\n");
 +              irq_set_chip_data(virq, mpic);
 +              irq_set_chip_and_handler(virq, &mpic->hc_tm,
 +                                       handle_fasteoi_irq);
 +              return 0;
 +      }
 +
        if (hw >= mpic->irq_count)
                return -EINVAL;
  
@@@ -1086,7 -1026,6 +1087,7 @@@ static int mpic_host_xlate(struct irq_h
                           irq_hw_number_t *out_hwirq, unsigned int *out_flags)
  
  {
 +      struct mpic *mpic = h->host_data;
        static unsigned char map_mpic_senses[4] = {
                IRQ_TYPE_EDGE_RISING,
                IRQ_TYPE_LEVEL_LOW,
        };
  
        *out_hwirq = intspec[0];
 -      if (intsize > 1) {
 +      if (intsize >= 4 && (mpic->flags & MPIC_FSL)) {
 +              /*
 +               * Freescale MPIC with extended intspec:
 +               * First two cells are as usual.  Third specifies
 +               * an "interrupt type".  Fourth is type-specific data.
 +               *
 +               * See Documentation/devicetree/bindings/powerpc/fsl/mpic.txt
 +               */
 +              switch (intspec[2]) {
 +              case 0:
 +              case 1: /* no EISR/EIMR support for now, treat as shared IRQ */
 +                      break;
 +              case 2:
 +                      if (intspec[0] >= ARRAY_SIZE(mpic->ipi_vecs))
 +                              return -EINVAL;
 +
 +                      *out_hwirq = mpic->ipi_vecs[intspec[0]];
 +                      break;
 +              case 3:
 +                      if (intspec[0] >= ARRAY_SIZE(mpic->timer_vecs))
 +                              return -EINVAL;
 +
 +                      *out_hwirq = mpic->timer_vecs[intspec[0]];
 +                      break;
 +              default:
 +                      pr_debug("%s: unknown irq type %u\n",
 +                               __func__, intspec[2]);
 +                      return -EINVAL;
 +              }
 +
 +              *out_flags = map_mpic_senses[intspec[1] & 3];
 +      } else if (intsize > 1) {
                u32 mask = 0x3;
  
                /* Apple invented a new race of encoding on machines with
@@@ -1202,9 -1110,6 +1203,9 @@@ struct mpic * __init mpic_alloc(struct 
        mpic->hc_ipi.name = name;
  #endif /* CONFIG_SMP */
  
 +      mpic->hc_tm = mpic_tm_chip;
 +      mpic->hc_tm.name = name;
 +
        mpic->flags = flags;
        mpic->isu_size = isu_size;
        mpic->irq_count = irq_count;
        else
                intvec_top = 255;
  
 -      mpic->timer_vecs[0] = intvec_top - 8;
 -      mpic->timer_vecs[1] = intvec_top - 7;
 -      mpic->timer_vecs[2] = intvec_top - 6;
 -      mpic->timer_vecs[3] = intvec_top - 5;
 +      mpic->timer_vecs[0] = intvec_top - 12;
 +      mpic->timer_vecs[1] = intvec_top - 11;
 +      mpic->timer_vecs[2] = intvec_top - 10;
 +      mpic->timer_vecs[3] = intvec_top - 9;
 +      mpic->timer_vecs[4] = intvec_top - 8;
 +      mpic->timer_vecs[5] = intvec_top - 7;
 +      mpic->timer_vecs[6] = intvec_top - 6;
 +      mpic->timer_vecs[7] = intvec_top - 5;
        mpic->ipi_vecs[0]   = intvec_top - 4;
        mpic->ipi_vecs[1]   = intvec_top - 3;
        mpic->ipi_vecs[2]   = intvec_top - 2;
        /* Check for "big-endian" in device-tree */
        if (node && of_get_property(node, "big-endian", NULL) != NULL)
                mpic->flags |= MPIC_BIG_ENDIAN;
 +      if (node && of_device_is_compatible(node, "fsl,mpic"))
 +              mpic->flags |= MPIC_FSL;
  
        /* Look for protected sources */
        if (node) {
@@@ -1425,17 -1324,15 +1426,17 @@@ void __init mpic_init(struct mpic *mpic
        /* Set current processor priority to max */
        mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), 0xf);
  
 -      /* Initialize timers: just disable them all */
 +      /* Initialize timers to our reserved vectors and mask them for now */
        for (i = 0; i < 4; i++) {
                mpic_write(mpic->tmregs,
                           i * MPIC_INFO(TIMER_STRIDE) +
 -                         MPIC_INFO(TIMER_DESTINATION), 0);
 +                         MPIC_INFO(TIMER_DESTINATION),
 +                         1 << hard_smp_processor_id());
                mpic_write(mpic->tmregs,
                           i * MPIC_INFO(TIMER_STRIDE) +
                           MPIC_INFO(TIMER_VECTOR_PRI),
                           MPIC_VECPRI_MASK |
 +                         (9 << MPIC_VECPRI_PRIORITY_SHIFT) |
                           (mpic->timer_vecs[0] + i));
        }
  
@@@ -1531,7 -1428,7 +1532,7 @@@ void __init mpic_set_serial_int(struct 
  void mpic_irq_set_priority(unsigned int irq, unsigned int pri)
  {
        struct mpic *mpic = mpic_find(irq);
 -      unsigned int src = mpic_irq_to_hw(irq);
 +      unsigned int src = virq_to_hw(irq);
        unsigned long flags;
        u32 reg;
  
                        ~MPIC_VECPRI_PRIORITY_MASK;
                mpic_ipi_write(src - mpic->ipi_vecs[0],
                               reg | (pri << MPIC_VECPRI_PRIORITY_SHIFT));
 +      } else if (mpic_is_tm(mpic, irq)) {
 +              reg = mpic_tm_read(src - mpic->timer_vecs[0]) &
 +                      ~MPIC_VECPRI_PRIORITY_MASK;
 +              mpic_tm_write(src - mpic->timer_vecs[0],
 +                            reg | (pri << MPIC_VECPRI_PRIORITY_SHIFT));
        } else {
                reg = mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI))
                        & ~MPIC_VECPRI_PRIORITY_MASK;
@@@ -1728,28 -1620,46 +1729,28 @@@ void mpic_request_ipis(void
        }
  }
  
 -static void mpic_send_ipi(unsigned int ipi_no, const struct cpumask *cpu_mask)
 +void smp_mpic_message_pass(int cpu, int msg)
  {
        struct mpic *mpic = mpic_primary;
 +      u32 physmask;
  
        BUG_ON(mpic == NULL);
  
 -#ifdef DEBUG_IPI
 -      DBG("%s: send_ipi(ipi_no: %d)\n", mpic->name, ipi_no);
 -#endif
 -
 -      mpic_cpu_write(MPIC_INFO(CPU_IPI_DISPATCH_0) +
 -                     ipi_no * MPIC_INFO(CPU_IPI_DISPATCH_STRIDE),
 -                     mpic_physmask(cpumask_bits(cpu_mask)[0]));
 -}
 -
 -void smp_mpic_message_pass(int target, int msg)
 -{
 -      cpumask_var_t tmp;
 -
        /* make sure we're sending something that translates to an IPI */
        if ((unsigned int)msg > 3) {
                printk("SMP %d: smp_message_pass: unknown msg %d\n",
                       smp_processor_id(), msg);
                return;
        }
 -      switch (target) {
 -      case MSG_ALL:
 -              mpic_send_ipi(msg, cpu_online_mask);
 -              break;
 -      case MSG_ALL_BUT_SELF:
 -              alloc_cpumask_var(&tmp, GFP_NOWAIT);
 -              cpumask_andnot(tmp, cpu_online_mask,
 -                             cpumask_of(smp_processor_id()));
 -              mpic_send_ipi(msg, tmp);
 -              free_cpumask_var(tmp);
 -              break;
 -      default:
 -              mpic_send_ipi(msg, cpumask_of(target));
 -              break;
 -      }
 +
 +#ifdef DEBUG_IPI
 +      DBG("%s: send_ipi(ipi_no: %d)\n", mpic->name, msg);
 +#endif
 +
 +      physmask = 1 << get_hard_smp_processor_id(cpu);
 +
 +      mpic_cpu_write(MPIC_INFO(CPU_IPI_DISPATCH_0) +
 +                     msg * MPIC_INFO(CPU_IPI_DISPATCH_STRIDE), physmask);
  }
  
  int __init smp_mpic_probe(void)
@@@ -1793,9 -1703,8 +1794,8 @@@ void mpic_reset_core(int cpu
  #endif /* CONFIG_SMP */
  
  #ifdef CONFIG_PM
- static int mpic_suspend(struct sys_device *dev, pm_message_t state)
+ static void mpic_suspend_one(struct mpic *mpic)
  {
-       struct mpic *mpic = container_of(dev, struct mpic, sysdev);
        int i;
  
        for (i = 0; i < mpic->num_sources; i++) {
                mpic->save_data[i].dest =
                        mpic_irq_read(i, MPIC_INFO(IRQ_DESTINATION));
        }
+ }
+ static int mpic_suspend(void)
+ {
+       struct mpic *mpic = mpics;
+       while (mpic) {
+               mpic_suspend_one(mpic);
+               mpic = mpic->next;
+       }
  
        return 0;
  }
  
- static int mpic_resume(struct sys_device *dev)
+ static void mpic_resume_one(struct mpic *mpic)
  {
-       struct mpic *mpic = container_of(dev, struct mpic, sysdev);
        int i;
  
        for (i = 0; i < mpic->num_sources; i++) {
        }
  #endif
        } /* end for loop */
+ }
  
-       return 0;
+ static void mpic_resume(void)
+ {
+       struct mpic *mpic = mpics;
+       while (mpic) {
+               mpic_resume_one(mpic);
+               mpic = mpic->next;
+       }
  }
- #endif
  
- static struct sysdev_class mpic_sysclass = {
- #ifdef CONFIG_PM
+ static struct syscore_ops mpic_syscore_ops = {
        .resume = mpic_resume,
        .suspend = mpic_suspend,
- #endif
-       .name = "mpic",
  };
  
  static int mpic_init_sys(void)
  {
-       struct mpic *mpic = mpics;
-       int error, id = 0;
-       error = sysdev_class_register(&mpic_sysclass);
-       while (mpic && !error) {
-               mpic->sysdev.cls = &mpic_sysclass;
-               mpic->sysdev.id = id++;
-               error = sysdev_register(&mpic->sysdev);
-               mpic = mpic->next;
-       }
-       return error;
+       register_syscore_ops(&mpic_syscore_ops);
+       return 0;
  }
  
  device_initcall(mpic_init_sys);
+ #endif