Merge branch 'stable/bug-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 10 Jan 2011 16:48:46 +0000 (08:48 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 10 Jan 2011 16:48:46 +0000 (08:48 -0800)
* 'stable/bug-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/konrad/xen:
  xen/event: validate irq before get evtchn by irq
  xen/fb: fix potential memory leak
  xen/fb: fix xenfb suspend/resume race.
  xen: disable ACPI NUMA for PV guests
  xen/irq: Cleanup the find_unbound_irq

1  2 
arch/x86/xen/enlighten.c
drivers/video/xen-fbfront.c
drivers/xen/events.c

diff --combined arch/x86/xen/enlighten.c
@@@ -574,8 -574,8 +574,8 @@@ static void xen_write_idt_entry(gate_de
  
        preempt_disable();
  
 -      start = __get_cpu_var(idt_desc).address;
 -      end = start + __get_cpu_var(idt_desc).size + 1;
 +      start = __this_cpu_read(idt_desc.address);
 +      end = start + __this_cpu_read(idt_desc.size) + 1;
  
        xen_mc_flush();
  
@@@ -1174,6 -1174,15 +1174,15 @@@ asmlinkage void __init xen_start_kernel
  
        xen_smp_init();
  
+ #ifdef CONFIG_ACPI_NUMA
+       /*
+        * The pages we from Xen are not related to machine pages, so
+        * any NUMA information the kernel tries to get from ACPI will
+        * be meaningless.  Prevent it from trying.
+        */
+       acpi_numa = -1;
+ #endif
        pgd = (pgd_t *)xen_start_info->pt_base;
  
        if (!xen_initial_domain())
  #endif
  }
  
 -static uint32_t xen_cpuid_base(void)
 -{
 -      uint32_t base, eax, ebx, ecx, edx;
 -      char signature[13];
 -
 -      for (base = 0x40000000; base < 0x40010000; base += 0x100) {
 -              cpuid(base, &eax, &ebx, &ecx, &edx);
 -              *(uint32_t *)(signature + 0) = ebx;
 -              *(uint32_t *)(signature + 4) = ecx;
 -              *(uint32_t *)(signature + 8) = edx;
 -              signature[12] = 0;
 -
 -              if (!strcmp("XenVMMXenVMM", signature) && ((eax - base) >= 2))
 -                      return base;
 -      }
 -
 -      return 0;
 -}
 -
  static int init_hvm_pv_info(int *major, int *minor)
  {
        uint32_t eax, ebx, ecx, edx, pages, msr, base;
@@@ -1365,18 -1393,6 +1374,18 @@@ static bool __init xen_hvm_platform(voi
        return true;
  }
  
 +bool xen_hvm_need_lapic(void)
 +{
 +      if (xen_pv_domain())
 +              return false;
 +      if (!xen_hvm_domain())
 +              return false;
 +      if (xen_feature(XENFEAT_hvm_pirqs) && xen_have_vector_callback)
 +              return false;
 +      return true;
 +}
 +EXPORT_SYMBOL_GPL(xen_hvm_need_lapic);
 +
  const __refconst struct hypervisor_x86 x86_hyper_xen_hvm = {
        .name                   = "Xen HVM",
        .detect                 = xen_hvm_platform,
@@@ -492,7 -492,7 +492,7 @@@ xenfb_make_preferred_console(void
                return;
  
        acquire_console_sem();
 -      for (c = console_drivers; c; c = c->next) {
 +      for_each_console(c) {
                if (!strcmp(c->name, "tty") && c->index == 0)
                        break;
        }
@@@ -562,26 -562,24 +562,24 @@@ static void xenfb_init_shared_page(stru
  static int xenfb_connect_backend(struct xenbus_device *dev,
                                 struct xenfb_info *info)
  {
-       int ret, evtchn;
+       int ret, evtchn, irq;
        struct xenbus_transaction xbt;
  
        ret = xenbus_alloc_evtchn(dev, &evtchn);
        if (ret)
                return ret;
-       ret = bind_evtchn_to_irqhandler(evtchn, xenfb_event_handler,
+       irq = bind_evtchn_to_irqhandler(evtchn, xenfb_event_handler,
                                        0, dev->devicetype, info);
-       if (ret < 0) {
+       if (irq < 0) {
                xenbus_free_evtchn(dev, evtchn);
                xenbus_dev_fatal(dev, ret, "bind_evtchn_to_irqhandler");
-               return ret;
+               return irq;
        }
-       info->irq = ret;
   again:
        ret = xenbus_transaction_start(&xbt);
        if (ret) {
                xenbus_dev_fatal(dev, ret, "starting transaction");
-               return ret;
+               goto unbind_irq;
        }
        ret = xenbus_printf(xbt, dev->nodename, "page-ref", "%lu",
                            virt_to_mfn(info->page));
                if (ret == -EAGAIN)
                        goto again;
                xenbus_dev_fatal(dev, ret, "completing transaction");
-               return ret;
+               goto unbind_irq;
        }
  
        xenbus_switch_state(dev, XenbusStateInitialised);
+       info->irq = irq;
        return 0;
  
   error_xenbus:
        xenbus_transaction_end(xbt, 1);
        xenbus_dev_fatal(dev, ret, "writing xenstore");
+  unbind_irq:
+       unbind_from_irqhandler(irq, info);
        return ret;
  }
  
  static void xenfb_disconnect_backend(struct xenfb_info *info)
  {
+       /* Prevent xenfb refresh */
+       info->update_wanted = 0;
        if (info->irq >= 0)
                unbind_from_irqhandler(info->irq, info);
        info->irq = -1;
diff --combined drivers/xen/events.c
@@@ -170,6 -170,9 +170,9 @@@ static struct irq_info *info_for_irq(un
  
  static unsigned int evtchn_from_irq(unsigned irq)
  {
+       if (unlikely(WARN(irq < 0 || irq >= nr_irqs, "Invalid irq %d!\n", irq)))
+               return 0;
        return info_for_irq(irq)->evtchn;
  }
  
@@@ -355,7 -358,7 +358,7 @@@ static void unmask_evtchn(int port
                struct evtchn_unmask unmask = { .port = port };
                (void)HYPERVISOR_event_channel_op(EVTCHNOP_unmask, &unmask);
        } else {
 -              struct vcpu_info *vcpu_info = __get_cpu_var(xen_vcpu);
 +              struct vcpu_info *vcpu_info = __this_cpu_read(xen_vcpu);
  
                sync_clear_bit(port, &s->evtchn_mask[0]);
  
@@@ -405,15 -408,21 +408,21 @@@ static int find_unbound_irq(void
  {
        struct irq_data *data;
        int irq, res;
-       int start = get_nr_hw_irqs();
+       int bottom = get_nr_hw_irqs();
+       int top = nr_irqs-1;
  
-       if (start == nr_irqs)
+       if (bottom == nr_irqs)
                goto no_irqs;
  
-       /* nr_irqs is a magic value. Must not use it.*/
-       for (irq = nr_irqs-1; irq > start; irq--) {
+       /* This loop starts from the top of IRQ space and goes down.
+        * We need this b/c if we have a PCI device in a Xen PV guest
+        * we do not have an IO-APIC (though the backend might have them)
+        * mapped in. To not have a collision of physical IRQs with the Xen
+        * event channels start at the top of the IRQ space for virtual IRQs.
+        */
+       for (irq = top; irq > bottom; irq--) {
                data = irq_get_irq_data(irq);
-               /* only 0->15 have init'd desc; handle irq > 16 */
+               /* only 15->0 have init'd desc; handle irq > 16 */
                if (!data)
                        break;
                if (data->chip == &no_irq_chip)
                        return irq;
        }
  
-       if (irq == start)
+       if (irq == bottom)
                goto no_irqs;
  
        res = irq_alloc_desc_at(irq, -1);
@@@ -1101,7 -1110,7 +1110,7 @@@ static void __xen_evtchn_do_upcall(void
  {
        int cpu = get_cpu();
        struct shared_info *s = HYPERVISOR_shared_info;
 -      struct vcpu_info *vcpu_info = __get_cpu_var(xen_vcpu);
 +      struct vcpu_info *vcpu_info = __this_cpu_read(xen_vcpu);
        unsigned count;
  
        do {
  
                vcpu_info->evtchn_upcall_pending = 0;
  
 -              if (__get_cpu_var(xed_nesting_count)++)
 +              if (__this_cpu_inc_return(xed_nesting_count) - 1)
                        goto out;
  
  #ifndef CONFIG_X86 /* No need for a barrier -- XCHG is a barrier on x86. */
  
                BUG_ON(!irqs_disabled());
  
 -              count = __get_cpu_var(xed_nesting_count);
 -              __get_cpu_var(xed_nesting_count) = 0;
 +              count = __this_cpu_read(xed_nesting_count);
 +              __this_cpu_write(xed_nesting_count, 0);
        } while (count != 1 || vcpu_info->evtchn_upcall_pending);
  
  out: