[POWERPC] PS3: Rename processor id symbols
[pandora-kernel.git] / arch / powerpc / platforms / ps3 / interrupt.c
index 631c300..e2de899 100644 (file)
 #include <asm/machdep.h>
 #include <asm/udbg.h>
 #include <asm/lv1call.h>
+#include <asm/smp.h>
 
 #include "platform.h"
 
 #if defined(DEBUG)
-#define DBG(fmt...) udbg_printf(fmt)
+#define DBG udbg_printf
 #else
-#define DBG(fmt...) do{if(0)printk(fmt);}while(0)
+#define DBG pr_debug
 #endif
 
 /**
@@ -77,19 +78,118 @@ struct ps3_bmp {
 /**
  * struct ps3_private - a per cpu data structure
  * @bmp: ps3_bmp structure
- * @node: HV logical_ppe_id
- * @cpu: HV thread_id
+ * @ppe_id: HV logical_ppe_id
+ * @thread_id: HV thread_id
  */
 
 struct ps3_private {
        struct ps3_bmp bmp __attribute__ ((aligned (PS3_BMP_MINALIGN)));
-       u64 node;
-       unsigned int cpu;
+       u64 ppe_id;
+       u64 thread_id;
 };
 
 static DEFINE_PER_CPU(struct ps3_private, ps3_private);
 
-int ps3_alloc_irq(enum ps3_cpu_binding cpu, unsigned long outlet,
+/**
+ * ps3_chip_mask - Set an interrupt mask bit in ps3_bmp.
+ * @virq: The assigned Linux virq.
+ *
+ * Sets ps3_bmp.mask and calls lv1_did_update_interrupt_mask().
+ */
+
+static void ps3_chip_mask(unsigned int virq)
+{
+       struct ps3_private *pd = get_irq_chip_data(virq);
+       u64 bit = 0x8000000000000000UL >> virq;
+       u64 *p = &pd->bmp.mask;
+       u64 old;
+       unsigned long flags;
+
+       pr_debug("%s:%d: thread_id %lu, virq %d\n", __func__, __LINE__,
+               pd->thread_id, virq);
+
+       local_irq_save(flags);
+       asm volatile(
+                    "1:        ldarx %0,0,%3\n"
+                    "andc      %0,%0,%2\n"
+                    "stdcx.    %0,0,%3\n"
+                    "bne-      1b"
+                    : "=&r" (old), "+m" (*p)
+                    : "r" (bit), "r" (p)
+                    : "cc" );
+
+       lv1_did_update_interrupt_mask(pd->ppe_id, pd->thread_id);
+       local_irq_restore(flags);
+}
+
+/**
+ * ps3_chip_unmask - Clear an interrupt mask bit in ps3_bmp.
+ * @virq: The assigned Linux virq.
+ *
+ * Clears ps3_bmp.mask and calls lv1_did_update_interrupt_mask().
+ */
+
+static void ps3_chip_unmask(unsigned int virq)
+{
+       struct ps3_private *pd = get_irq_chip_data(virq);
+       u64 bit = 0x8000000000000000UL >> virq;
+       u64 *p = &pd->bmp.mask;
+       u64 old;
+       unsigned long flags;
+
+       pr_debug("%s:%d: thread_id %lu, virq %d\n", __func__, __LINE__,
+               pd->thread_id, virq);
+
+       local_irq_save(flags);
+       asm volatile(
+                    "1:        ldarx %0,0,%3\n"
+                    "or        %0,%0,%2\n"
+                    "stdcx.    %0,0,%3\n"
+                    "bne-      1b"
+                    : "=&r" (old), "+m" (*p)
+                    : "r" (bit), "r" (p)
+                    : "cc" );
+
+       lv1_did_update_interrupt_mask(pd->ppe_id, pd->thread_id);
+       local_irq_restore(flags);
+}
+
+/**
+ * ps3_chip_eoi - HV end-of-interrupt.
+ * @virq: The assigned Linux virq.
+ *
+ * Calls lv1_end_of_interrupt_ext().
+ */
+
+static void ps3_chip_eoi(unsigned int virq)
+{
+       const struct ps3_private *pd = get_irq_chip_data(virq);
+       lv1_end_of_interrupt_ext(pd->ppe_id, pd->thread_id, virq);
+}
+
+/**
+ * ps3_irq_chip - Represents the ps3_bmp as a Linux struct irq_chip.
+ */
+
+static struct irq_chip ps3_irq_chip = {
+       .typename = "ps3",
+       .mask = ps3_chip_mask,
+       .unmask = ps3_chip_unmask,
+       .eoi = ps3_chip_eoi,
+};
+
+/**
+ * ps3_virq_setup - virq related setup.
+ * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be
+ * serviced on.
+ * @outlet: The HV outlet from the various create outlet routines.
+ * @virq: The assigned Linux virq.
+ *
+ * Calls irq_create_mapping() to get a virq and sets the chip data to
+ * ps3_private data.
+ */
+
+int ps3_virq_setup(enum ps3_cpu_binding cpu, unsigned long outlet,
        unsigned int *virq)
 {
        int result;
@@ -111,17 +211,6 @@ int ps3_alloc_irq(enum ps3_cpu_binding cpu, unsigned long outlet,
                goto fail_create;
        }
 
-       /* Binds outlet to cpu + virq. */
-
-       result = lv1_connect_irq_plug_ext(pd->node, pd->cpu, *virq, outlet, 0);
-
-       if (result) {
-               pr_info("%s:%d: lv1_connect_irq_plug_ext failed: %s\n",
-               __func__, __LINE__, ps3_result(result));
-               result = -EPERM;
-               goto fail_connect;
-       }
-
        pr_debug("%s:%d: outlet %lu => cpu %u, virq %u\n", __func__, __LINE__,
                outlet, cpu, *virq);
 
@@ -133,97 +222,126 @@ int ps3_alloc_irq(enum ps3_cpu_binding cpu, unsigned long outlet,
                goto fail_set;
        }
 
+       ps3_chip_mask(*virq);
+
        return result;
 
 fail_set:
-       lv1_disconnect_irq_plug_ext(pd->node, pd->cpu, *virq);
-fail_connect:
        irq_dispose_mapping(*virq);
 fail_create:
        return result;
 }
-EXPORT_SYMBOL_GPL(ps3_alloc_irq);
 
-int ps3_free_irq(unsigned int virq)
+/**
+ * ps3_virq_destroy - virq related teardown.
+ * @virq: The assigned Linux virq.
+ *
+ * Clears chip data and calls irq_dispose_mapping() for the virq.
+ */
+
+int ps3_virq_destroy(unsigned int virq)
 {
-       int result;
        const struct ps3_private *pd = get_irq_chip_data(virq);
 
-       pr_debug("%s:%d: node %lu, cpu %d, virq %u\n", __func__, __LINE__,
-               pd->node, pd->cpu, virq);
-
-       result = lv1_disconnect_irq_plug_ext(pd->node, pd->cpu, virq);
-
-       if (result)
-               pr_info("%s:%d: lv1_disconnect_irq_plug_ext failed: %s\n",
-               __func__, __LINE__, ps3_result(result));
+       pr_debug("%s:%d: ppe_id %lu, thread_id %lu, virq %u\n", __func__,
+               __LINE__, pd->ppe_id, pd->thread_id, virq);
 
        set_irq_chip_data(virq, NULL);
        irq_dispose_mapping(virq);
-       return result;
+
+       pr_debug("%s:%d <-\n", __func__, __LINE__);
+       return 0;
 }
-EXPORT_SYMBOL_GPL(ps3_free_irq);
 
 /**
- * ps3_alloc_io_irq - Assign a virq to a system bus device.
+ * ps3_irq_plug_setup - Generic outlet and virq related setup.
  * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be
  * serviced on.
- * @interrupt_id: The device interrupt id read from the system repository.
+ * @outlet: The HV outlet from the various create outlet routines.
  * @virq: The assigned Linux virq.
  *
- * An io irq represents a non-virtualized device interrupt.  interrupt_id
- * coresponds to the interrupt number of the interrupt controller.
+ * Sets up virq and connects the irq plug.
  */
 
-int ps3_alloc_io_irq(enum ps3_cpu_binding cpu, unsigned int interrupt_id,
+int ps3_irq_plug_setup(enum ps3_cpu_binding cpu, unsigned long outlet,
        unsigned int *virq)
 {
        int result;
-       unsigned long outlet;
+       struct ps3_private *pd;
 
-       result = lv1_construct_io_irq_outlet(interrupt_id, &outlet);
+       result = ps3_virq_setup(cpu, outlet, virq);
 
        if (result) {
-               pr_debug("%s:%d: lv1_construct_io_irq_outlet failed: %s\n",
-                       __func__, __LINE__, ps3_result(result));
-               return result;
+               pr_debug("%s:%d: ps3_virq_setup failed\n", __func__, __LINE__);
+               goto fail_setup;
        }
 
-       result = ps3_alloc_irq(cpu, outlet, virq);
-       BUG_ON(result);
+       pd = get_irq_chip_data(*virq);
+
+       /* Binds outlet to cpu + virq. */
+
+       result = lv1_connect_irq_plug_ext(pd->ppe_id, pd->thread_id, *virq,
+               outlet, 0);
+
+       if (result) {
+               pr_info("%s:%d: lv1_connect_irq_plug_ext failed: %s\n",
+               __func__, __LINE__, ps3_result(result));
+               result = -EPERM;
+               goto fail_connect;
+       }
 
        return result;
+
+fail_connect:
+       ps3_virq_destroy(*virq);
+fail_setup:
+       return result;
 }
-EXPORT_SYMBOL_GPL(ps3_alloc_io_irq);
+EXPORT_SYMBOL_GPL(ps3_irq_plug_setup);
+
+/**
+ * ps3_irq_plug_destroy - Generic outlet and virq related teardown.
+ * @virq: The assigned Linux virq.
+ *
+ * Disconnects the irq plug and tears down virq.
+ * Do not call for system bus event interrupts setup with
+ * ps3_sb_event_receive_port_setup().
+ */
 
-int ps3_free_io_irq(unsigned int virq)
+int ps3_irq_plug_destroy(unsigned int virq)
 {
        int result;
+       const struct ps3_private *pd = get_irq_chip_data(virq);
+
+       pr_debug("%s:%d: ppe_id %lu, thread_id %lu, virq %u\n", __func__,
+               __LINE__, pd->ppe_id, pd->thread_id, virq);
+
+       ps3_chip_mask(virq);
 
-       result = lv1_destruct_io_irq_outlet(virq_to_hw(virq));
+       result = lv1_disconnect_irq_plug_ext(pd->ppe_id, pd->thread_id, virq);
 
        if (result)
-               pr_debug("%s:%d: lv1_destruct_io_irq_outlet failed: %s\n",
-                       __func__, __LINE__, ps3_result(result));
+               pr_info("%s:%d: lv1_disconnect_irq_plug_ext failed: %s\n",
+               __func__, __LINE__, ps3_result(result));
 
-       ps3_free_irq(virq);
+       ps3_virq_destroy(virq);
 
        return result;
 }
-EXPORT_SYMBOL_GPL(ps3_free_io_irq);
+EXPORT_SYMBOL_GPL(ps3_irq_plug_destroy);
 
 /**
- * ps3_alloc_event_irq - Allocate a virq for use with a system event.
+ * ps3_event_receive_port_setup - Setup an event receive port.
  * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be
  * serviced on.
  * @virq: The assigned Linux virq.
  *
  * The virq can be used with lv1_connect_interrupt_event_receive_port() to
- * arrange to receive events, or with ps3_send_event_locally() to signal
- * events.
+ * arrange to receive interrupts from system-bus devices, or with
+ * ps3_send_event_locally() to signal events.
  */
 
-int ps3_alloc_event_irq(enum ps3_cpu_binding cpu, unsigned int *virq)
+int ps3_event_receive_port_setup(enum ps3_cpu_binding cpu, unsigned int *virq)
 {
        int result;
        unsigned long outlet;
@@ -237,17 +355,29 @@ int ps3_alloc_event_irq(enum ps3_cpu_binding cpu, unsigned int *virq)
                return result;
        }
 
-       result = ps3_alloc_irq(cpu, outlet, virq);
+       result = ps3_irq_plug_setup(cpu, outlet, virq);
        BUG_ON(result);
 
        return result;
 }
+EXPORT_SYMBOL_GPL(ps3_event_receive_port_setup);
 
-int ps3_free_event_irq(unsigned int virq)
+/**
+ * ps3_event_receive_port_destroy - Destroy an event receive port.
+ * @virq: The assigned Linux virq.
+ *
+ * Since ps3_event_receive_port_destroy destroys the receive port outlet,
+ * SB devices need to call disconnect_interrupt_event_receive_port() before
+ * this.
+ */
+
+int ps3_event_receive_port_destroy(unsigned int virq)
 {
        int result;
 
-       pr_debug(" -> %s:%d\n", __func__, __LINE__);
+       pr_debug(" -> %s:%d virq %u\n", __func__, __LINE__, virq);
+
+       ps3_chip_mask(virq);
 
        result = lv1_destruct_event_receive_port(virq_to_hw(virq));
 
@@ -255,7 +385,10 @@ int ps3_free_event_irq(unsigned int virq)
                pr_debug("%s:%d: lv1_destruct_event_receive_port failed: %s\n",
                        __func__, __LINE__, ps3_result(result));
 
-       ps3_free_irq(virq);
+       /*
+        * Don't call ps3_virq_destroy() here since ps3_smp_cleanup_cpu()
+        * calls from interrupt context (smp_call_function) when kexecing.
+        */
 
        pr_debug(" <- %s:%d\n", __func__, __LINE__);
        return result;
@@ -267,70 +400,140 @@ int ps3_send_event_locally(unsigned int virq)
 }
 
 /**
- * ps3_connect_event_irq - Assign a virq to a system bus device.
+ * ps3_sb_event_receive_port_setup - Setup a system bus event receive port.
  * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be
  * serviced on.
- * @did: The HV device identifier read from the system repository.
- * @interrupt_id: The device interrupt id read from the system repository.
+ * @dev: The system bus device instance.
  * @virq: The assigned Linux virq.
  *
  * An event irq represents a virtual device interrupt.  The interrupt_id
  * coresponds to the software interrupt number.
  */
 
-int ps3_connect_event_irq(enum ps3_cpu_binding cpu,
-       const struct ps3_device_id *did, unsigned int interrupt_id,
-       unsigned int *virq)
+int ps3_sb_event_receive_port_setup(struct ps3_system_bus_device *dev,
+       enum ps3_cpu_binding cpu, unsigned int *virq)
 {
+       /* this should go in system-bus.c */
+
        int result;
 
-       result = ps3_alloc_event_irq(cpu, virq);
+       result = ps3_event_receive_port_setup(cpu, virq);
 
        if (result)
                return result;
 
-       result = lv1_connect_interrupt_event_receive_port(did->bus_id,
-               did->dev_id, virq_to_hw(*virq), interrupt_id);
+       result = lv1_connect_interrupt_event_receive_port(dev->bus_id,
+               dev->dev_id, virq_to_hw(*virq), dev->interrupt_id);
 
        if (result) {
                pr_debug("%s:%d: lv1_connect_interrupt_event_receive_port"
                        " failed: %s\n", __func__, __LINE__,
                        ps3_result(result));
-               ps3_free_event_irq(*virq);
+               ps3_event_receive_port_destroy(*virq);
                *virq = NO_IRQ;
                return result;
        }
 
        pr_debug("%s:%d: interrupt_id %u, virq %u\n", __func__, __LINE__,
-               interrupt_id, *virq);
+               dev->interrupt_id, *virq);
 
        return 0;
 }
+EXPORT_SYMBOL(ps3_sb_event_receive_port_setup);
 
-int ps3_disconnect_event_irq(const struct ps3_device_id *did,
-       unsigned int interrupt_id, unsigned int virq)
+int ps3_sb_event_receive_port_destroy(struct ps3_system_bus_device *dev,
+       unsigned int virq)
 {
+       /* this should go in system-bus.c */
+
        int result;
 
        pr_debug(" -> %s:%d: interrupt_id %u, virq %u\n", __func__, __LINE__,
-               interrupt_id, virq);
+               dev->interrupt_id, virq);
 
-       result = lv1_disconnect_interrupt_event_receive_port(did->bus_id,
-               did->dev_id, virq_to_hw(virq), interrupt_id);
+       result = lv1_disconnect_interrupt_event_receive_port(dev->bus_id,
+               dev->dev_id, virq_to_hw(virq), dev->interrupt_id);
 
        if (result)
                pr_debug("%s:%d: lv1_disconnect_interrupt_event_receive_port"
                        " failed: %s\n", __func__, __LINE__,
                        ps3_result(result));
 
-       ps3_free_event_irq(virq);
+       result = ps3_event_receive_port_destroy(virq);
+       BUG_ON(result);
+
+       /*
+        * ps3_event_receive_port_destroy() destroys the IRQ plug,
+        * so don't call ps3_irq_plug_destroy() here.
+        */
+
+       result = ps3_virq_destroy(virq);
+       BUG_ON(result);
 
        pr_debug(" <- %s:%d\n", __func__, __LINE__);
        return result;
 }
+EXPORT_SYMBOL(ps3_sb_event_receive_port_destroy);
 
 /**
- * ps3_alloc_vuart_irq - Configure the system virtual uart virq.
+ * ps3_io_irq_setup - Setup a system bus io irq.
+ * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be
+ * serviced on.
+ * @interrupt_id: The device interrupt id read from the system repository.
+ * @virq: The assigned Linux virq.
+ *
+ * An io irq represents a non-virtualized device interrupt.  interrupt_id
+ * coresponds to the interrupt number of the interrupt controller.
+ */
+
+int ps3_io_irq_setup(enum ps3_cpu_binding cpu, unsigned int interrupt_id,
+       unsigned int *virq)
+{
+       int result;
+       unsigned long outlet;
+
+       result = lv1_construct_io_irq_outlet(interrupt_id, &outlet);
+
+       if (result) {
+               pr_debug("%s:%d: lv1_construct_io_irq_outlet failed: %s\n",
+                       __func__, __LINE__, ps3_result(result));
+               return result;
+       }
+
+       result = ps3_irq_plug_setup(cpu, outlet, virq);
+       BUG_ON(result);
+
+       return result;
+}
+EXPORT_SYMBOL_GPL(ps3_io_irq_setup);
+
+int ps3_io_irq_destroy(unsigned int virq)
+{
+       int result;
+       unsigned long outlet = virq_to_hw(virq);
+
+       ps3_chip_mask(virq);
+
+       /*
+        * lv1_destruct_io_irq_outlet() will destroy the IRQ plug,
+        * so call ps3_irq_plug_destroy() first.
+        */
+
+       result = ps3_irq_plug_destroy(virq);
+       BUG_ON(result);
+
+       result = lv1_destruct_io_irq_outlet(outlet);
+
+       if (result)
+               pr_debug("%s:%d: lv1_destruct_io_irq_outlet failed: %s\n",
+                       __func__, __LINE__, ps3_result(result));
+
+       return result;
+}
+EXPORT_SYMBOL_GPL(ps3_io_irq_destroy);
+
+/**
+ * ps3_vuart_irq_setup - Setup the system virtual uart virq.
  * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be
  * serviced on.
  * @virt_addr_bmp: The caller supplied virtual uart interrupt bitmap.
@@ -340,7 +543,7 @@ int ps3_disconnect_event_irq(const struct ps3_device_id *did,
  * freeing the interrupt will return a wrong state error.
  */
 
-int ps3_alloc_vuart_irq(enum ps3_cpu_binding cpu, void* virt_addr_bmp,
+int ps3_vuart_irq_setup(enum ps3_cpu_binding cpu, void* virt_addr_bmp,
        unsigned int *virq)
 {
        int result;
@@ -359,16 +562,18 @@ int ps3_alloc_vuart_irq(enum ps3_cpu_binding cpu, void* virt_addr_bmp,
                return result;
        }
 
-       result = ps3_alloc_irq(cpu, outlet, virq);
+       result = ps3_irq_plug_setup(cpu, outlet, virq);
        BUG_ON(result);
 
        return result;
 }
+EXPORT_SYMBOL_GPL(ps3_vuart_irq_setup);
 
-int ps3_free_vuart_irq(unsigned int virq)
+int ps3_vuart_irq_destroy(unsigned int virq)
 {
        int result;
 
+       ps3_chip_mask(virq);
        result = lv1_deconfigure_virtual_uart_irq();
 
        if (result) {
@@ -377,13 +582,15 @@ int ps3_free_vuart_irq(unsigned int virq)
                return result;
        }
 
-       ps3_free_irq(virq);
+       result = ps3_irq_plug_destroy(virq);
+       BUG_ON(result);
 
        return result;
 }
+EXPORT_SYMBOL_GPL(ps3_vuart_irq_destroy);
 
 /**
- * ps3_alloc_spe_irq - Configure an spe virq.
+ * ps3_spe_irq_setup - Setup an spe virq.
  * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be
  * serviced on.
  * @spe_id: The spe_id returned from lv1_construct_logical_spe().
@@ -392,7 +599,7 @@ int ps3_free_vuart_irq(unsigned int virq)
  *
  */
 
-int ps3_alloc_spe_irq(enum ps3_cpu_binding cpu, unsigned long spe_id,
+int ps3_spe_irq_setup(enum ps3_cpu_binding cpu, unsigned long spe_id,
        unsigned int class, unsigned int *virq)
 {
        int result;
@@ -408,16 +615,22 @@ int ps3_alloc_spe_irq(enum ps3_cpu_binding cpu, unsigned long spe_id,
                return result;
        }
 
-       result = ps3_alloc_irq(cpu, outlet, virq);
+       result = ps3_irq_plug_setup(cpu, outlet, virq);
        BUG_ON(result);
 
        return result;
 }
 
-int ps3_free_spe_irq(unsigned int virq)
+int ps3_spe_irq_destroy(unsigned int virq)
 {
-       ps3_free_irq(virq);
-       return 0;
+       int result;
+
+       ps3_chip_mask(virq);
+
+       result = ps3_irq_plug_destroy(virq);
+       BUG_ON(result);
+
+       return result;
 }
 
 
@@ -434,7 +647,7 @@ static void _dump_64_bmp(const char *header, const u64 *p, unsigned cpu,
                *p & 0xffff);
 }
 
-static void __attribute__ ((unused)) _dump_256_bmp(const char *header,
+static void __maybe_unused _dump_256_bmp(const char *header,
        const u64 *p, unsigned cpu, const char* func, int line)
 {
        pr_debug("%s:%d: %s %u {%016lx:%016lx:%016lx:%016lx}\n",
@@ -447,86 +660,25 @@ static void _dump_bmp(struct ps3_private* pd, const char* func, int line)
        unsigned long flags;
 
        spin_lock_irqsave(&pd->bmp.lock, flags);
-       _dump_64_bmp("stat", &pd->bmp.status, pd->cpu, func, line);
-       _dump_64_bmp("mask", &pd->bmp.mask, pd->cpu, func, line);
+       _dump_64_bmp("stat", &pd->bmp.status, pd->thread_id, func, line);
+       _dump_64_bmp("mask", &pd->bmp.mask, pd->thread_id, func, line);
        spin_unlock_irqrestore(&pd->bmp.lock, flags);
 }
 
 #define dump_mask(_x) _dump_mask(_x, __func__, __LINE__)
-static void __attribute__ ((unused)) _dump_mask(struct ps3_private* pd,
+static void __maybe_unused _dump_mask(struct ps3_private *pd,
        const char* func, int line)
 {
        unsigned long flags;
 
        spin_lock_irqsave(&pd->bmp.lock, flags);
-       _dump_64_bmp("mask", &pd->bmp.mask, pd->cpu, func, line);
+       _dump_64_bmp("mask", &pd->bmp.mask, pd->thread_id, func, line);
        spin_unlock_irqrestore(&pd->bmp.lock, flags);
 }
 #else
 static void dump_bmp(struct ps3_private* pd) {};
 #endif /* defined(DEBUG) */
 
-static void ps3_chip_mask(unsigned int virq)
-{
-       struct ps3_private *pd = get_irq_chip_data(virq);
-       u64 bit = 0x8000000000000000UL >> virq;
-       u64 *p = &pd->bmp.mask;
-       u64 old;
-       unsigned long flags;
-
-       pr_debug("%s:%d: cpu %u, virq %d\n", __func__, __LINE__, pd->cpu, virq);
-
-       local_irq_save(flags);
-       asm volatile(
-                    "1:        ldarx %0,0,%3\n"
-                    "andc      %0,%0,%2\n"
-                    "stdcx.    %0,0,%3\n"
-                    "bne-      1b"
-                    : "=&r" (old), "+m" (*p)
-                    : "r" (bit), "r" (p)
-                    : "cc" );
-
-       lv1_did_update_interrupt_mask(pd->node, pd->cpu);
-       local_irq_restore(flags);
-}
-
-static void ps3_chip_unmask(unsigned int virq)
-{
-       struct ps3_private *pd = get_irq_chip_data(virq);
-       u64 bit = 0x8000000000000000UL >> virq;
-       u64 *p = &pd->bmp.mask;
-       u64 old;
-       unsigned long flags;
-
-       pr_debug("%s:%d: cpu %u, virq %d\n", __func__, __LINE__, pd->cpu, virq);
-
-       local_irq_save(flags);
-       asm volatile(
-                    "1:        ldarx %0,0,%3\n"
-                    "or        %0,%0,%2\n"
-                    "stdcx.    %0,0,%3\n"
-                    "bne-      1b"
-                    : "=&r" (old), "+m" (*p)
-                    : "r" (bit), "r" (p)
-                    : "cc" );
-
-       lv1_did_update_interrupt_mask(pd->node, pd->cpu);
-       local_irq_restore(flags);
-}
-
-static void ps3_chip_eoi(unsigned int virq)
-{
-       const struct ps3_private *pd = get_irq_chip_data(virq);
-       lv1_end_of_interrupt_ext(pd->node, pd->cpu, virq);
-}
-
-static struct irq_chip irq_chip = {
-       .typename = "ps3",
-       .mask = ps3_chip_mask,
-       .unmask = ps3_chip_unmask,
-       .eoi = ps3_chip_eoi,
-};
-
 static void ps3_host_unmap(struct irq_host *h, unsigned int virq)
 {
        set_irq_chip_data(virq, NULL);
@@ -538,7 +690,7 @@ static int ps3_host_map(struct irq_host *h, unsigned int virq,
        pr_debug("%s:%d: hwirq %lu, virq %u\n", __func__, __LINE__, hwirq,
                virq);
 
-       set_irq_chip_and_handler(virq, &irq_chip, handle_fasteoi_irq);
+       set_irq_chip_and_handler(virq, &ps3_irq_chip, handle_fasteoi_irq);
 
        return 0;
 }
@@ -558,7 +710,7 @@ void __init ps3_register_ipi_debug_brk(unsigned int cpu, unsigned int virq)
                cpu, virq, pd->bmp.ipi_debug_brk_mask);
 }
 
-unsigned int ps3_get_irq(void)
+static unsigned int ps3_get_irq(void)
 {
        struct ps3_private *pd = &__get_cpu_var(ps3_private);
        u64 x = (pd->bmp.status & pd->bmp.mask);
@@ -573,8 +725,8 @@ unsigned int ps3_get_irq(void)
        plug &= 0x3f;
 
        if (unlikely(plug) == NO_IRQ) {
-               pr_debug("%s:%d: no plug found: cpu %u\n", __func__, __LINE__,
-                       pd->cpu);
+               pr_debug("%s:%d: no plug found: thread_id %lu\n", __func__,
+                       __LINE__, pd->thread_id);
                dump_bmp(&per_cpu(ps3_private, 0));
                dump_bmp(&per_cpu(ps3_private, 1));
                return NO_IRQ;
@@ -604,16 +756,16 @@ void __init ps3_init_IRQ(void)
        for_each_possible_cpu(cpu) {
                struct ps3_private *pd = &per_cpu(ps3_private, cpu);
 
-               lv1_get_logical_ppe_id(&pd->node);
-               pd->cpu = get_hard_smp_processor_id(cpu);
+               lv1_get_logical_ppe_id(&pd->ppe_id);
+               pd->thread_id = get_hard_smp_processor_id(cpu);
                spin_lock_init(&pd->bmp.lock);
 
-               pr_debug("%s:%d: node %lu, cpu %d, bmp %lxh\n", __func__,
-                       __LINE__, pd->node, pd->cpu,
+               pr_debug("%s:%d: ppe_id %lu, thread_id %lu, bmp %lxh\n",
+                       __func__, __LINE__, pd->ppe_id, pd->thread_id,
                        ps3_mm_phys_to_lpar(__pa(&pd->bmp)));
 
-               result = lv1_configure_irq_state_bitmap(pd->node, pd->cpu,
-                       ps3_mm_phys_to_lpar(__pa(&pd->bmp)));
+               result = lv1_configure_irq_state_bitmap(pd->ppe_id,
+                       pd->thread_id, ps3_mm_phys_to_lpar(__pa(&pd->bmp)));
 
                if (result)
                        pr_debug("%s:%d: lv1_configure_irq_state_bitmap failed:"
@@ -623,3 +775,16 @@ void __init ps3_init_IRQ(void)
 
        ppc_md.get_irq = ps3_get_irq;
 }
+
+void ps3_shutdown_IRQ(int cpu)
+{
+       int result;
+       u64 ppe_id;
+       u64 thread_id = get_hard_smp_processor_id(cpu);
+
+       lv1_get_logical_ppe_id(&ppe_id);
+       result = lv1_configure_irq_state_bitmap(ppe_id, thread_id, 0);
+
+       DBG("%s:%d: lv1_configure_irq_state_bitmap (%lu:%lu/%d) %s\n", __func__,
+               __LINE__, ppe_id, thread_id, cpu, ps3_result(result));
+}