Merge branch 'linus' into x86/apic
authorIngo Molnar <mingo@elte.hu>
Fri, 17 Apr 2009 14:18:22 +0000 (16:18 +0200)
committerIngo Molnar <mingo@elte.hu>
Fri, 17 Apr 2009 14:18:28 +0000 (16:18 +0200)
Merge reason: new intr-remap patches depend on the s2ram iommu fixes from upstream

Signed-off-by: Ingo Molnar <mingo@elte.hu>
1  2 
arch/x86/kernel/apic/apic.c
arch/x86/kernel/apic/io_apic.c
arch/x86/kernel/irq.c

index 4b48ff9163caf28709b2992148454b8369df925c,f2870920f246a9f1d7e2075c37b65b05de27dbf1..83e47febcc893e29ec387377cc2db66c4ac4865b
@@@ -98,29 -98,6 +98,29 @@@ early_param("lapic", parse_lapic)
  /* Local APIC was disabled by the BIOS and enabled by the kernel */
  static int enabled_via_apicbase;
  
 +/*
 + * Handle interrupt mode configuration register (IMCR).
 + * This register controls whether the interrupt signals
 + * that reach the BSP come from the master PIC or from the
 + * local APIC. Before entering Symmetric I/O Mode, either
 + * the BIOS or the operating system must switch out of
 + * PIC Mode by changing the IMCR.
 + */
 +static inline void imcr_pic_to_apic(void)
 +{
 +      /* select IMCR register */
 +      outb(0x70, 0x22);
 +      /* NMI and 8259 INTR go through APIC */
 +      outb(0x01, 0x23);
 +}
 +
 +static inline void imcr_apic_to_pic(void)
 +{
 +      /* select IMCR register */
 +      outb(0x70, 0x22);
 +      /* NMI and 8259 INTR go directly to BSP */
 +      outb(0x00, 0x23);
 +}
  #endif
  
  #ifdef CONFIG_X86_64
@@@ -232,24 -209,6 +232,24 @@@ static int modern_apic(void
        return lapic_get_version() >= 0x14;
  }
  
 +/*
 + * bare function to substitute write operation
 + * and it's _that_ fast :)
 + */
 +void native_apic_write_dummy(u32 reg, u32 v)
 +{
 +      WARN_ON_ONCE((cpu_has_apic || !disable_apic));
 +}
 +
 +/*
 + * right after this call apic->write doesn't do anything
 + * note that there is no restore operation it works one way
 + */
 +void apic_disable(void)
 +{
 +      apic->write = native_apic_write_dummy;
 +}
 +
  void native_apic_wait_icr_idle(void)
  {
        while (apic_read(APIC_ICR) & APIC_ICR_BUSY)
@@@ -472,6 -431,12 +472,12 @@@ static void __cpuinit setup_APIC_timer(
  {
        struct clock_event_device *levt = &__get_cpu_var(lapic_events);
  
+       if (cpu_has(&current_cpu_data, X86_FEATURE_ARAT)) {
+               lapic_clockevent.features &= ~CLOCK_EVT_FEAT_C3STOP;
+               /* Make LAPIC timer preferrable over percpu HPET */
+               lapic_clockevent.rating = 150;
+       }
        memcpy(levt, &lapic_clockevent, sizeof(*levt));
        levt->cpumask = cpumask_of(smp_processor_id());
  
@@@ -1600,12 -1565,6 +1606,12 @@@ void __init init_apic_mappings(void
         */
        if (boot_cpu_physical_apicid == -1U)
                boot_cpu_physical_apicid = read_apic_id();
 +
 +      /* lets check if we may to NOP'ify apic operations */
 +      if (!cpu_has_apic) {
 +              pr_info("APIC: disable apic facility\n");
 +              apic_disable();
 +      }
  }
  
  /*
@@@ -1774,7 -1733,8 +1780,7 @@@ void __init connect_bsp_APIC(void
                 */
                apic_printk(APIC_VERBOSE, "leaving PIC mode, "
                                "enabling APIC mode.\n");
 -              outb(0x70, 0x22);
 -              outb(0x01, 0x23);
 +              imcr_pic_to_apic();
        }
  #endif
        if (apic->enable_apic_mode)
@@@ -1802,7 -1762,8 +1808,7 @@@ void disconnect_bsp_APIC(int virt_wire_
                 */
                apic_printk(APIC_VERBOSE, "disabling APIC mode, "
                                "entering PIC mode.\n");
 -              outb(0x70, 0x22);
 -              outb(0x00, 0x23);
 +              imcr_apic_to_pic();
                return;
        }
  #endif
index 7c9d045ac83417b1c14be1316b3bb7a1eab0074f,a2789e42e162ec3d14eabb7e9bad6d96e57da0ea..84990002240745cf852b09a49ebd0202d09248cd
@@@ -518,6 -518,120 +518,6 @@@ static void ioapic_mask_entry(int apic
        spin_unlock_irqrestore(&ioapic_lock, flags);
  }
  
 -#ifdef CONFIG_SMP
 -static void send_cleanup_vector(struct irq_cfg *cfg)
 -{
 -      cpumask_var_t cleanup_mask;
 -
 -      if (unlikely(!alloc_cpumask_var(&cleanup_mask, GFP_ATOMIC))) {
 -              unsigned int i;
 -              cfg->move_cleanup_count = 0;
 -              for_each_cpu_and(i, cfg->old_domain, cpu_online_mask)
 -                      cfg->move_cleanup_count++;
 -              for_each_cpu_and(i, cfg->old_domain, cpu_online_mask)
 -                      apic->send_IPI_mask(cpumask_of(i), IRQ_MOVE_CLEANUP_VECTOR);
 -      } else {
 -              cpumask_and(cleanup_mask, cfg->old_domain, cpu_online_mask);
 -              cfg->move_cleanup_count = cpumask_weight(cleanup_mask);
 -              apic->send_IPI_mask(cleanup_mask, IRQ_MOVE_CLEANUP_VECTOR);
 -              free_cpumask_var(cleanup_mask);
 -      }
 -      cfg->move_in_progress = 0;
 -}
 -
 -static void __target_IO_APIC_irq(unsigned int irq, unsigned int dest, struct irq_cfg *cfg)
 -{
 -      int apic, pin;
 -      struct irq_pin_list *entry;
 -      u8 vector = cfg->vector;
 -
 -      entry = cfg->irq_2_pin;
 -      for (;;) {
 -              unsigned int reg;
 -
 -              if (!entry)
 -                      break;
 -
 -              apic = entry->apic;
 -              pin = entry->pin;
 -              /*
 -               * With interrupt-remapping, destination information comes
 -               * from interrupt-remapping table entry.
 -               */
 -              if (!irq_remapped(irq))
 -                      io_apic_write(apic, 0x11 + pin*2, dest);
 -              reg = io_apic_read(apic, 0x10 + pin*2);
 -              reg &= ~IO_APIC_REDIR_VECTOR_MASK;
 -              reg |= vector;
 -              io_apic_modify(apic, 0x10 + pin*2, reg);
 -              if (!entry->next)
 -                      break;
 -              entry = entry->next;
 -      }
 -}
 -
 -static int
 -assign_irq_vector(int irq, struct irq_cfg *cfg, const struct cpumask *mask);
 -
 -/*
 - * Either sets desc->affinity to a valid value, and returns
 - * ->cpu_mask_to_apicid of that, or returns BAD_APICID and
 - * leaves desc->affinity untouched.
 - */
 -static unsigned int
 -set_desc_affinity(struct irq_desc *desc, const struct cpumask *mask)
 -{
 -      struct irq_cfg *cfg;
 -      unsigned int irq;
 -
 -      if (!cpumask_intersects(mask, cpu_online_mask))
 -              return BAD_APICID;
 -
 -      irq = desc->irq;
 -      cfg = desc->chip_data;
 -      if (assign_irq_vector(irq, cfg, mask))
 -              return BAD_APICID;
 -
 -      /* check that before desc->addinity get updated */
 -      set_extra_move_desc(desc, mask);
 -
 -      cpumask_copy(desc->affinity, mask);
 -
 -      return apic->cpu_mask_to_apicid_and(desc->affinity, cfg->domain);
 -}
 -
 -static void
 -set_ioapic_affinity_irq_desc(struct irq_desc *desc, const struct cpumask *mask)
 -{
 -      struct irq_cfg *cfg;
 -      unsigned long flags;
 -      unsigned int dest;
 -      unsigned int irq;
 -
 -      irq = desc->irq;
 -      cfg = desc->chip_data;
 -
 -      spin_lock_irqsave(&ioapic_lock, flags);
 -      dest = set_desc_affinity(desc, mask);
 -      if (dest != BAD_APICID) {
 -              /* Only the high 8 bits are valid. */
 -              dest = SET_APIC_LOGICAL_ID(dest);
 -              __target_IO_APIC_irq(irq, dest, cfg);
 -      }
 -      spin_unlock_irqrestore(&ioapic_lock, flags);
 -}
 -
 -static void
 -set_ioapic_affinity_irq(unsigned int irq, const struct cpumask *mask)
 -{
 -      struct irq_desc *desc;
 -
 -      desc = irq_to_desc(irq);
 -
 -      set_ioapic_affinity_irq_desc(desc, mask);
 -}
 -#endif /* CONFIG_SMP */
 -
  /*
   * The common case is 1:1 IRQ<->pin mappings. Sometimes there are
   * shared ISA-space IRQs, so we have to support them. We are super
@@@ -2246,115 -2360,6 +2246,115 @@@ static int ioapic_retrigger_irq(unsigne
   */
  
  #ifdef CONFIG_SMP
 +static void send_cleanup_vector(struct irq_cfg *cfg)
 +{
 +      cpumask_var_t cleanup_mask;
 +
 +      if (unlikely(!alloc_cpumask_var(&cleanup_mask, GFP_ATOMIC))) {
 +              unsigned int i;
 +              cfg->move_cleanup_count = 0;
 +              for_each_cpu_and(i, cfg->old_domain, cpu_online_mask)
 +                      cfg->move_cleanup_count++;
 +              for_each_cpu_and(i, cfg->old_domain, cpu_online_mask)
 +                      apic->send_IPI_mask(cpumask_of(i), IRQ_MOVE_CLEANUP_VECTOR);
 +      } else {
 +              cpumask_and(cleanup_mask, cfg->old_domain, cpu_online_mask);
 +              cfg->move_cleanup_count = cpumask_weight(cleanup_mask);
 +              apic->send_IPI_mask(cleanup_mask, IRQ_MOVE_CLEANUP_VECTOR);
 +              free_cpumask_var(cleanup_mask);
 +      }
 +      cfg->move_in_progress = 0;
 +}
 +
 +static void
 +__target_IO_APIC_irq(unsigned int irq, unsigned int dest, struct irq_cfg *cfg)
 +{
 +      int apic, pin;
 +      struct irq_pin_list *entry;
 +      u8 vector = cfg->vector;
 +
 +      entry = cfg->irq_2_pin;
 +      for (;;) {
 +              unsigned int reg;
 +
 +              if (!entry)
 +                      break;
 +
 +              apic = entry->apic;
 +              pin = entry->pin;
 +              /*
 +               * With interrupt-remapping, destination information comes
 +               * from interrupt-remapping table entry.
 +               */
 +              if (!irq_remapped(irq))
 +                      io_apic_write(apic, 0x11 + pin*2, dest);
 +              reg = io_apic_read(apic, 0x10 + pin*2);
 +              reg &= ~IO_APIC_REDIR_VECTOR_MASK;
 +              reg |= vector;
 +              io_apic_modify(apic, 0x10 + pin*2, reg);
 +              if (!entry->next)
 +                      break;
 +              entry = entry->next;
 +      }
 +}
 +
 +/*
 + * Either sets desc->affinity to a valid value, and returns
 + * ->cpu_mask_to_apicid of that, or returns BAD_APICID and
 + * leaves desc->affinity untouched.
 + */
 +static unsigned int
 +set_desc_affinity(struct irq_desc *desc, const struct cpumask *mask)
 +{
 +      struct irq_cfg *cfg;
 +      unsigned int irq;
 +
 +      if (!cpumask_intersects(mask, cpu_online_mask))
 +              return BAD_APICID;
 +
 +      irq = desc->irq;
 +      cfg = desc->chip_data;
 +      if (assign_irq_vector(irq, cfg, mask))
 +              return BAD_APICID;
 +
 +      /* check that before desc->addinity get updated */
 +      set_extra_move_desc(desc, mask);
 +
 +      cpumask_copy(desc->affinity, mask);
 +
 +      return apic->cpu_mask_to_apicid_and(desc->affinity, cfg->domain);
 +}
 +
 +static void
 +set_ioapic_affinity_irq_desc(struct irq_desc *desc, const struct cpumask *mask)
 +{
 +      struct irq_cfg *cfg;
 +      unsigned long flags;
 +      unsigned int dest;
 +      unsigned int irq;
 +
 +      irq = desc->irq;
 +      cfg = desc->chip_data;
 +
 +      spin_lock_irqsave(&ioapic_lock, flags);
 +      dest = set_desc_affinity(desc, mask);
 +      if (dest != BAD_APICID) {
 +              /* Only the high 8 bits are valid. */
 +              dest = SET_APIC_LOGICAL_ID(dest);
 +              __target_IO_APIC_irq(irq, dest, cfg);
 +      }
 +      spin_unlock_irqrestore(&ioapic_lock, flags);
 +}
 +
 +static void
 +set_ioapic_affinity_irq(unsigned int irq, const struct cpumask *mask)
 +{
 +      struct irq_desc *desc;
 +
 +      desc = irq_to_desc(irq);
 +
 +      set_ioapic_affinity_irq_desc(desc, mask);
 +}
  
  #ifdef CONFIG_INTR_REMAP
  
@@@ -2519,7 -2524,6 +2519,6 @@@ static void irq_complete_move(struct ir
  static inline void irq_complete_move(struct irq_desc **descp) {}
  #endif
  
- #ifdef CONFIG_X86_X2APIC
  static void __eoi_ioapic_irq(unsigned int irq, struct irq_cfg *cfg)
  {
        int apic, pin;
@@@ -2553,6 -2557,7 +2552,7 @@@ eoi_ioapic_irq(struct irq_desc *desc
        spin_unlock_irqrestore(&ioapic_lock, flags);
  }
  
+ #ifdef CONFIG_X86_X2APIC
  static void ack_x2apic_level(unsigned int irq)
  {
        struct irq_desc *desc = irq_to_desc(irq);
@@@ -2629,6 -2634,9 +2629,9 @@@ static void ack_apic_level(unsigned in
         */
        ack_APIC_irq();
  
+       if (irq_remapped(irq))
+               eoi_ioapic_irq(desc);
        /* Now we can move and renable the irq */
        if (unlikely(do_unmask_irq)) {
                /* Only migrate the irq if the ack has been received.
diff --combined arch/x86/kernel/irq.c
index fd57bf35d0fc7c1f5ba966299f0fa7636b6860ea,c3fe010d74c8e8823793cd9ff816ee02adc8ebde..c1739ac29708cc8cd3ab9267f7b62a9e42b7ad2b
@@@ -24,9 -24,9 +24,9 @@@ void (*generic_interrupt_extension)(voi
   */
  void ack_bad_irq(unsigned int irq)
  {
 -      printk(KERN_ERR "unexpected IRQ trap at vector %02x\n", irq);
 +      if (printk_ratelimit())
 +              pr_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
@@@ -36,7 -36,9 +36,7 @@@
         * completely.
         * But only ack when the APIC is enabled -AK
         */
 -      if (cpu_has_apic)
 -              ack_APIC_irq();
 -#endif
 +      ack_APIC_irq();
  }
  
  #define irq_stats(x)          (&per_cpu(irq_stat, x))
@@@ -63,7 -65,7 +63,7 @@@ static int show_other_interrupts(struc
        seq_printf(p, "  Spurious interrupts\n");
  #endif
        if (generic_interrupt_extension) {
-               seq_printf(p, "PLT: ");
+               seq_printf(p, "%*s: ", prec, "PLT");
                for_each_online_cpu(j)
                        seq_printf(p, "%10u ", irq_stats(j)->generic_irqs);
                seq_printf(p, "  Platform interrupts\n");
@@@ -176,7 -178,7 +176,7 @@@ u64 arch_irq_stat_cpu(unsigned int cpu
        sum += irq_stats(cpu)->irq_thermal_count;
  # ifdef CONFIG_X86_64
        sum += irq_stats(cpu)->irq_threshold_count;
 -#endif
 +# endif
  #endif
        return sum;
  }
@@@ -211,11 -213,14 +211,11 @@@ unsigned int __irq_entry do_IRQ(struct 
        irq = __get_cpu_var(vector_irq)[vector];
  
        if (!handle_irq(irq, regs)) {
 -#ifdef CONFIG_X86_64
 -              if (!disable_apic)
 -                      ack_APIC_irq();
 -#endif
 +              ack_APIC_irq();
  
                if (printk_ratelimit())
 -                      printk(KERN_EMERG "%s: %d.%d No irq handler for vector (irq %d)\n",
 -                             __func__, smp_processor_id(), vector, irq);
 +                      pr_emerg("%s: %d.%d No irq handler for vector (irq %d)\n",
 +                              __func__, smp_processor_id(), vector, irq);
        }
  
        irq_exit();