#include <linux/sched.h>
 #include <linux/delay.h>
 #include <linux/mutex.h>
+#include <linux/workqueue.h>
+#include <linux/cpu.h>
 
 #include <asm/ldc.h>
 #include <asm/vio.h>
 #include <asm/power.h>
 #include <asm/mdesc.h>
+#include <asm/head.h>
+#include <asm/io.h>
+#include <asm/hvtramp.h>
 
 #define DRV_MODULE_NAME                "ds"
 #define PFX DRV_MODULE_NAME    ": "
        __u64                   handle;
 
        void                    (*data)(struct ldc_channel *lp,
-                                       struct ds_cap_state *dp,
+                                       struct ds_cap_state *cp,
                                        void *buf, int len);
 
        const char              *service_id;
 #define CAP_STATE_REGISTERED   0x02
 };
 
+static void md_update_data(struct ldc_channel *lp, struct ds_cap_state *cp,
+                          void *buf, int len);
+static void domain_shutdown_data(struct ldc_channel *lp,
+                                struct ds_cap_state *cp,
+                                void *buf, int len);
+static void domain_panic_data(struct ldc_channel *lp,
+                             struct ds_cap_state *cp,
+                             void *buf, int len);
+static void dr_cpu_data(struct ldc_channel *lp,
+                       struct ds_cap_state *cp,
+                       void *buf, int len);
+static void ds_pri_data(struct ldc_channel *lp,
+                       struct ds_cap_state *cp,
+                       void *buf, int len);
+static void ds_var_data(struct ldc_channel *lp,
+                       struct ds_cap_state *cp,
+                       void *buf, int len);
+
+struct ds_cap_state ds_states[] = {
+       {
+               .service_id     = "md-update",
+               .data           = md_update_data,
+       },
+       {
+               .service_id     = "domain-shutdown",
+               .data           = domain_shutdown_data,
+       },
+       {
+               .service_id     = "domain-panic",
+               .data           = domain_panic_data,
+       },
+       {
+               .service_id     = "dr-cpu",
+               .data           = dr_cpu_data,
+       },
+       {
+               .service_id     = "pri",
+               .data           = ds_pri_data,
+       },
+       {
+               .service_id     = "var-config",
+               .data           = ds_var_data,
+       },
+       {
+               .service_id     = "var-config-backup",
+               .data           = ds_var_data,
+       },
+};
+
+static DEFINE_SPINLOCK(ds_lock);
+
+struct ds_info {
+       struct ldc_channel      *lp;
+       u8                      hs_state;
+#define DS_HS_START            0x01
+#define DS_HS_DONE             0x02
+
+       void                    *rcv_buf;
+       int                     rcv_buf_len;
+};
+
+static struct ds_info *ds_info;
+
+static struct ds_cap_state *find_cap(u64 handle)
+{
+       unsigned int index = handle >> 32;
+
+       if (index >= ARRAY_SIZE(ds_states))
+               return NULL;
+       return &ds_states[index];
+}
+
+static struct ds_cap_state *find_cap_by_string(const char *name)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(ds_states); i++) {
+               if (strcmp(ds_states[i].service_id, name))
+                       continue;
+
+               return &ds_states[i];
+       }
+       return NULL;
+}
+
 static int ds_send(struct ldc_channel *lp, void *data, int len)
 {
        int err, limit = 1000;
        panic("PANIC requested by LDOM manager.");
 }
 
-struct ds_cpu_tag {
+struct dr_cpu_tag {
        __u64                           req_num;
        __u32                           type;
-#define DS_CPU_CONFIGURE               0x43
-#define DS_CPU_UNCONFIGURE             0x55
-#define DS_CPU_FORCE_UNCONFIGURE       0x46
-#define DS_CPU_STATUS                  0x53
+#define DR_CPU_CONFIGURE               0x43
+#define DR_CPU_UNCONFIGURE             0x55
+#define DR_CPU_FORCE_UNCONFIGURE       0x46
+#define DR_CPU_STATUS                  0x53
 
 /* Responses */
-#define DS_CPU_OK                      0x6f
-#define DS_CPU_ERROR                   0x65
+#define DR_CPU_OK                      0x6f
+#define DR_CPU_ERROR                   0x65
 
        __u32                           num_records;
 };
 
-struct ds_cpu_record {
-       __u32                           cpu_id;
+struct dr_cpu_resp_entry {
+       __u32                           cpu;
+       __u32                           result;
+#define DR_CPU_RES_OK                  0x00
+#define DR_CPU_RES_FAILURE             0x01
+#define DR_CPU_RES_BLOCKED             0x02
+#define DR_CPU_RES_CPU_NOT_RESPONDING  0x03
+#define DR_CPU_RES_NOT_IN_MD           0x04
+
+       __u32                           stat;
+#define DR_CPU_STAT_NOT_PRESENT                0x00
+#define DR_CPU_STAT_UNCONFIGURED       0x01
+#define DR_CPU_STAT_CONFIGURED         0x02
+
+       __u32                           str_off;
 };
 
+/* XXX Put this in some common place. XXX */
+static unsigned long kimage_addr_to_ra(void *p)
+{
+       unsigned long val = (unsigned long) p;
+
+       return kern_base + (val - KERNBASE);
+}
+
+void ldom_startcpu_cpuid(unsigned int cpu, unsigned long thread_reg)
+{
+       extern unsigned long sparc64_ttable_tl0;
+       extern unsigned long kern_locked_tte_data;
+       extern int bigkernel;
+       struct hvtramp_descr *hdesc;
+       unsigned long trampoline_ra;
+       struct trap_per_cpu *tb;
+       u64 tte_vaddr, tte_data;
+       unsigned long hv_err;
+
+       hdesc = kzalloc(sizeof(*hdesc), GFP_KERNEL);
+       if (!hdesc) {
+               printk(KERN_ERR PFX "ldom_startcpu_cpuid: Cannot allocate "
+                      "hvtramp_descr.\n");
+               return;
+       }
+
+       hdesc->cpu = cpu;
+       hdesc->num_mappings = (bigkernel ? 2 : 1);
+
+       tb = &trap_block[cpu];
+       tb->hdesc = hdesc;
+
+       hdesc->fault_info_va = (unsigned long) &tb->fault_info;
+       hdesc->fault_info_pa = kimage_addr_to_ra(&tb->fault_info);
+
+       hdesc->thread_reg = thread_reg;
+
+       tte_vaddr = (unsigned long) KERNBASE;
+       tte_data = kern_locked_tte_data;
+
+       hdesc->maps[0].vaddr = tte_vaddr;
+       hdesc->maps[0].tte   = tte_data;
+       if (bigkernel) {
+               tte_vaddr += 0x400000;
+               tte_data  += 0x400000;
+               hdesc->maps[1].vaddr = tte_vaddr;
+               hdesc->maps[1].tte   = tte_data;
+       }
+
+       trampoline_ra = kimage_addr_to_ra(hv_cpu_startup);
+
+       hv_err = sun4v_cpu_start(cpu, trampoline_ra,
+                                kimage_addr_to_ra(&sparc64_ttable_tl0),
+                                __pa(hdesc));
+}
+
+/* DR cpu requests get queued onto the work list by the
+ * dr_cpu_data() callback.  The list is protected by
+ * ds_lock, and processed by dr_cpu_process() in order.
+ */
+static LIST_HEAD(dr_cpu_work_list);
+
+struct dr_cpu_queue_entry {
+       struct list_head                list;
+       char                            req[0];
+};
+
+static void __dr_cpu_send_error(struct ds_cap_state *cp, struct ds_data *data)
+{
+       struct dr_cpu_tag *tag = (struct dr_cpu_tag *) (data + 1);
+       struct ds_info *dp = ds_info;
+       struct {
+               struct ds_data          data;
+               struct dr_cpu_tag       tag;
+       } pkt;
+       int msg_len;
+
+       memset(&pkt, 0, sizeof(pkt));
+       pkt.data.tag.type = DS_DATA;
+       pkt.data.handle = cp->handle;
+       pkt.tag.req_num = tag->req_num;
+       pkt.tag.type = DR_CPU_ERROR;
+       pkt.tag.num_records = 0;
+
+       msg_len = (sizeof(struct ds_data) +
+                  sizeof(struct dr_cpu_tag));
+
+       pkt.data.tag.len = msg_len - sizeof(struct ds_msg_tag);
+
+       ds_send(dp->lp, &pkt, msg_len);
+}
+
+static void dr_cpu_send_error(struct ds_cap_state *cp, struct ds_data *data)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&ds_lock, flags);
+       __dr_cpu_send_error(cp, data);
+       spin_unlock_irqrestore(&ds_lock, flags);
+}
+
+#define CPU_SENTINEL   0xffffffff
+
+static void purge_dups(u32 *list, u32 num_ents)
+{
+       unsigned int i;
+
+       for (i = 0; i < num_ents; i++) {
+               u32 cpu = list[i];
+               unsigned int j;
+
+               if (cpu == CPU_SENTINEL)
+                       continue;
+
+               for (j = i + 1; j < num_ents; j++) {
+                       if (list[j] == cpu)
+                               list[j] = CPU_SENTINEL;
+               }
+       }
+}
+
+static int dr_cpu_size_response(int ncpus)
+{
+       return (sizeof(struct ds_data) +
+               sizeof(struct dr_cpu_tag) +
+               (sizeof(struct dr_cpu_resp_entry) * ncpus));
+}
+
+static void dr_cpu_init_response(struct ds_data *resp, u64 req_num,
+                                u64 handle, int resp_len, int ncpus,
+                                cpumask_t *mask, u32 default_stat)
+{
+       struct dr_cpu_resp_entry *ent;
+       struct dr_cpu_tag *tag;
+       int i, cpu;
+
+       tag = (struct dr_cpu_tag *) (resp + 1);
+       ent = (struct dr_cpu_resp_entry *) (tag + 1);
+
+       resp->tag.type = DS_DATA;
+       resp->tag.len = resp_len - sizeof(struct ds_msg_tag);
+       resp->handle = handle;
+       tag->req_num = req_num;
+       tag->type = DR_CPU_OK;
+       tag->num_records = ncpus;
+
+       i = 0;
+       for_each_cpu_mask(cpu, *mask) {
+               ent[i].cpu = cpu;
+               ent[i].result = DR_CPU_RES_OK;
+               ent[i].stat = default_stat;
+               i++;
+       }
+       BUG_ON(i != ncpus);
+}
+
+static void dr_cpu_mark(struct ds_data *resp, int cpu, int ncpus,
+                       u32 res, u32 stat)
+{
+       struct dr_cpu_resp_entry *ent;
+       struct dr_cpu_tag *tag;
+       int i;
+
+       tag = (struct dr_cpu_tag *) (resp + 1);
+       ent = (struct dr_cpu_resp_entry *) (tag + 1);
+
+       for (i = 0; i < ncpus; i++) {
+               if (ent[i].cpu != cpu)
+                       continue;
+               ent[i].result = res;
+               ent[i].stat = stat;
+               break;
+       }
+}
+
+static int dr_cpu_configure(struct ds_cap_state *cp, u64 req_num,
+                           cpumask_t *mask)
+{
+       struct ds_data *resp;
+       int resp_len, ncpus, cpu;
+       unsigned long flags;
+
+       ncpus = cpus_weight(*mask);
+       resp_len = dr_cpu_size_response(ncpus);
+       resp = kzalloc(resp_len, GFP_KERNEL);
+       if (!resp)
+               return -ENOMEM;
+
+       dr_cpu_init_response(resp, req_num, cp->handle,
+                            resp_len, ncpus, mask,
+                            DR_CPU_STAT_CONFIGURED);
+
+       mdesc_fill_in_cpu_data(*mask);
+
+       for_each_cpu_mask(cpu, *mask) {
+               int err;
+
+               printk(KERN_INFO PFX "Starting cpu %d...\n", cpu);
+               err = cpu_up(cpu);
+               if (err)
+                       dr_cpu_mark(resp, cpu, ncpus,
+                                   DR_CPU_RES_FAILURE,
+                                   DR_CPU_STAT_UNCONFIGURED);
+       }
+
+       spin_lock_irqsave(&ds_lock, flags);
+       ds_send(ds_info->lp, resp, resp_len);
+       spin_unlock_irqrestore(&ds_lock, flags);
+
+       kfree(resp);
+
+       return 0;
+}
+
+static int dr_cpu_unconfigure(struct ds_cap_state *cp, u64 req_num,
+                             cpumask_t *mask)
+{
+       struct ds_data *resp;
+       int resp_len, ncpus;
+
+       ncpus = cpus_weight(*mask);
+       resp_len = dr_cpu_size_response(ncpus);
+       resp = kzalloc(resp_len, GFP_KERNEL);
+       if (!resp)
+               return -ENOMEM;
+
+       dr_cpu_init_response(resp, req_num, cp->handle,
+                            resp_len, ncpus, mask,
+                            DR_CPU_STAT_UNCONFIGURED);
+
+       kfree(resp);
+
+       return -EOPNOTSUPP;
+}
+
+static void dr_cpu_process(struct work_struct *work)
+{
+       struct dr_cpu_queue_entry *qp, *tmp;
+       struct ds_cap_state *cp;
+       unsigned long flags;
+       LIST_HEAD(todo);
+       cpumask_t mask;
+
+       cp = find_cap_by_string("dr-cpu");
+
+       spin_lock_irqsave(&ds_lock, flags);
+       list_splice(&dr_cpu_work_list, &todo);
+       spin_unlock_irqrestore(&ds_lock, flags);
+
+       list_for_each_entry_safe(qp, tmp, &todo, list) {
+               struct ds_data *data = (struct ds_data *) qp->req;
+               struct dr_cpu_tag *tag = (struct dr_cpu_tag *) (data + 1);
+               u32 *cpu_list = (u32 *) (tag + 1);
+               u64 req_num = tag->req_num;
+               unsigned int i;
+               int err;
+
+               switch (tag->type) {
+               case DR_CPU_CONFIGURE:
+               case DR_CPU_UNCONFIGURE:
+               case DR_CPU_FORCE_UNCONFIGURE:
+                       break;
+
+               default:
+                       dr_cpu_send_error(cp, data);
+                       goto next;
+               }
+
+               purge_dups(cpu_list, tag->num_records);
+
+               cpus_clear(mask);
+               for (i = 0; i < tag->num_records; i++) {
+                       if (cpu_list[i] == CPU_SENTINEL)
+                               continue;
+
+                       if (cpu_list[i] < NR_CPUS)
+                               cpu_set(cpu_list[i], mask);
+               }
+
+               if (tag->type == DR_CPU_CONFIGURE)
+                       err = dr_cpu_configure(cp, req_num, &mask);
+               else
+                       err = dr_cpu_unconfigure(cp, req_num, &mask);
+
+               if (err)
+                       dr_cpu_send_error(cp, data);
+
+next:
+               list_del(&qp->list);
+               kfree(qp);
+       }
+}
+
+static DECLARE_WORK(dr_cpu_work, dr_cpu_process);
+
 static void dr_cpu_data(struct ldc_channel *lp,
                        struct ds_cap_state *dp,
                        void *buf, int len)
 {
+       struct dr_cpu_queue_entry *qp;
        struct ds_data *dpkt = buf;
-       struct ds_cpu_tag *rp;
+       struct dr_cpu_tag *rp;
 
-       rp = (struct ds_cpu_tag *) (dpkt + 1);
+       rp = (struct dr_cpu_tag *) (dpkt + 1);
 
-       printk(KERN_ERR PFX "CPU REQ [%lx:%x], len=%d\n",
-              rp->req_num, rp->type, len);
+       qp = kmalloc(sizeof(struct dr_cpu_queue_entry) + len, GFP_ATOMIC);
+       if (!qp) {
+               struct ds_cap_state *cp;
+
+               cp = find_cap_by_string("dr-cpu");
+               __dr_cpu_send_error(cp, dpkt);
+       } else {
+               memcpy(&qp->req, buf, len);
+               list_add_tail(&qp->list, &dr_cpu_work_list);
+               schedule_work(&dr_cpu_work);
+       }
 }
 
 struct ds_pri_msg {
        ds_var_doorbell = 1;
 }
 
-struct ds_cap_state ds_states[] = {
-       {
-               .service_id     = "md-update",
-               .data           = md_update_data,
-       },
-       {
-               .service_id     = "domain-shutdown",
-               .data           = domain_shutdown_data,
-       },
-       {
-               .service_id     = "domain-panic",
-               .data           = domain_panic_data,
-       },
-       {
-               .service_id     = "dr-cpu",
-               .data           = dr_cpu_data,
-       },
-       {
-               .service_id     = "pri",
-               .data           = ds_pri_data,
-       },
-       {
-               .service_id     = "var-config",
-               .data           = ds_var_data,
-       },
-       {
-               .service_id     = "var-config-backup",
-               .data           = ds_var_data,
-       },
-};
-
-static DEFINE_SPINLOCK(ds_lock);
-
-struct ds_info {
-       struct ldc_channel      *lp;
-       u8                      hs_state;
-#define DS_HS_START            0x01
-#define DS_HS_DONE             0x02
-
-       void                    *rcv_buf;
-       int                     rcv_buf_len;
-};
-
-static struct ds_info *ds_info;
-
-static struct ds_cap_state *find_cap(u64 handle)
-{
-       unsigned int index = handle >> 32;
-
-       if (index >= ARRAY_SIZE(ds_states))
-               return NULL;
-       return &ds_states[index];
-}
-
-static struct ds_cap_state *find_cap_by_string(const char *name)
-{
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(ds_states); i++) {
-               if (strcmp(ds_states[i].service_id, name))
-                       continue;
-
-               return &ds_states[i];
-       }
-       return NULL;
-}
-
 void ldom_set_var(const char *var, const char *value)
 {
        struct ds_info *dp = ds_info;
                p += strlen(value) + 1;
 
                msg_len = (sizeof(struct ds_data) +
-                              sizeof(struct ds_var_set_msg) +
-                              (p - base));
+                          sizeof(struct ds_var_set_msg) +
+                          (p - base));
                msg_len = (msg_len + 3) & ~3;
                pkt.header.data.tag.len = msg_len - sizeof(struct ds_msg_tag);
 
        sun4v_mach_sir();
 }
 
+void ldom_power_off(void)
+{
+       sun4v_mach_exit(0);
+}
+
 static void ds_conn_reset(struct ds_info *dp)
 {
        printk(KERN_ERR PFX "ds_conn_reset() from %p\n",
                               np->handle);
                        return 0;
                }
-               printk(KERN_ERR PFX "Could not register %s service\n",
+               printk(KERN_INFO PFX "Could not register %s service\n",
                       cp->service_id);
                cp->state = CAP_STATE_UNKNOWN;
        }
 
--- /dev/null
+/* hvtramp.S: Hypervisor start-cpu trampoline code.
+ *
+ * Copyright (C) 2007 David S. Miller <davem@davemloft.net>
+ */
+
+#include <asm/thread_info.h>
+#include <asm/hypervisor.h>
+#include <asm/scratchpad.h>
+#include <asm/spitfire.h>
+#include <asm/hvtramp.h>
+#include <asm/pstate.h>
+#include <asm/ptrace.h>
+#include <asm/asi.h>
+
+       .text
+       .align          8
+       .globl          hv_cpu_startup, hv_cpu_startup_end
+
+       /* This code executes directly out of the hypervisor
+        * with physical addressing (va==pa).  %o0 contains
+        * our client argument which for Linux points to
+        * a descriptor data structure which defines the
+        * MMU entries we need to load up.
+        *
+        * After we set things up we enable the MMU and call
+        * into the kernel.
+        *
+        * First setup basic privileged cpu state.
+        */
+hv_cpu_startup:
+       wrpr            %g0, 0, %gl
+       wrpr            %g0, 15, %pil
+       wrpr            %g0, 0, %canrestore
+       wrpr            %g0, 0, %otherwin
+       wrpr            %g0, 6, %cansave
+       wrpr            %g0, 6, %cleanwin
+       wrpr            %g0, 0, %cwp
+       wrpr            %g0, 0, %wstate
+       wrpr            %g0, 0, %tl
+
+       sethi           %hi(sparc64_ttable_tl0), %g1
+       wrpr            %g1, %tba
+
+       mov             %o0, %l0
+
+       lduw            [%l0 + HVTRAMP_DESCR_CPU], %g1
+       mov             SCRATCHPAD_CPUID, %g2
+       stxa            %g1, [%g2] ASI_SCRATCHPAD
+
+       ldx             [%l0 + HVTRAMP_DESCR_FAULT_INFO_VA], %g2
+       stxa            %g2, [%g0] ASI_SCRATCHPAD
+
+       mov             0, %l1
+       lduw            [%l0 + HVTRAMP_DESCR_NUM_MAPPINGS], %l2
+       add             %l0, HVTRAMP_DESCR_MAPS, %l3
+
+1:     ldx             [%l3 + HVTRAMP_MAPPING_VADDR], %o0
+       clr             %o1
+       ldx             [%l3 + HVTRAMP_MAPPING_TTE], %o2
+       mov             HV_MMU_IMMU | HV_MMU_DMMU, %o3
+       mov             HV_FAST_MMU_MAP_PERM_ADDR, %o5
+       ta              HV_FAST_TRAP
+
+       brnz,pn         %o0, 80f
+        nop
+
+       add             %l1, 1, %l1
+       cmp             %l1, %l2
+       blt,a,pt        %xcc, 1b
+        add            %l3, HVTRAMP_MAPPING_SIZE, %l3
+
+       ldx             [%l0 + HVTRAMP_DESCR_FAULT_INFO_PA], %o0
+       mov             HV_FAST_MMU_FAULT_AREA_CONF, %o5
+       ta              HV_FAST_TRAP
+
+       brnz,pn         %o0, 80f
+        nop
+
+       wrpr            %g0, (PSTATE_PRIV | PSTATE_PEF), %pstate
+
+       ldx             [%l0 + HVTRAMP_DESCR_THREAD_REG], %l6
+
+       mov             1, %o0
+       set             1f, %o1
+       mov             HV_FAST_MMU_ENABLE, %o5
+       ta              HV_FAST_TRAP
+
+       ba,pt           %xcc, 80f
+        nop
+
+1:
+       wr              %g0, 0, %fprs
+       wr              %g0, ASI_P, %asi
+
+       mov             PRIMARY_CONTEXT, %g7
+       stxa            %g0, [%g7] ASI_MMU
+       membar          #Sync
+
+       mov             SECONDARY_CONTEXT, %g7
+       stxa            %g0, [%g7] ASI_MMU
+       membar          #Sync
+
+       mov             %l6, %g6
+       ldx             [%g6 + TI_TASK], %g4
+
+       mov             1, %g5
+       sllx            %g5, THREAD_SHIFT, %g5
+       sub             %g5, (STACKFRAME_SZ + STACK_BIAS), %g5
+       add             %g6, %g5, %sp
+       mov             0, %fp
+
+       call            init_irqwork_curcpu
+        nop
+       call            hard_smp_processor_id
+        nop
+
+       mov             %o0, %o1
+       mov             0, %o0
+       mov             0, %o2
+       call            sun4v_init_mondo_queues
+        mov            1, %o3
+
+       call            init_cur_cpu_trap
+        mov            %g6, %o0
+
+       wrpr            %g0, (PSTATE_PRIV | PSTATE_PEF | PSTATE_IE), %pstate
+
+       call            smp_callin
+        nop
+       call            cpu_idle
+        mov            0, %o0
+       call            cpu_panic
+        nop
+
+80:    ba,pt           %xcc, 80b
+        nop
+
+       .align          8
+hv_cpu_startup_end:
 
        if (v)
                printk("PLATFORM: max-cpus [%lu]\n", *v);
 
+#ifdef CONFIG_SMP
+       {
+               int max_cpu, i;
+
+               if (v) {
+                       max_cpu = *v;
+                       if (max_cpu > NR_CPUS)
+                               max_cpu = NR_CPUS;
+               } else {
+                       max_cpu = NR_CPUS;
+               }
+               for (i = 0; i < max_cpu; i++)
+                       cpu_set(i, cpu_possible_map);
+       }
+#endif
+
        mdesc_release(hp);
 }
 
        return 0;
 }
 
-static void __init fill_in_one_cache(cpuinfo_sparc *c,
-                                    struct mdesc_handle *hp,
-                                    u64 mp)
+static void __devinit fill_in_one_cache(cpuinfo_sparc *c,
+                                       struct mdesc_handle *hp,
+                                       u64 mp)
 {
        const u64 *level = mdesc_get_property(hp, mp, "level", NULL);
        const u64 *size = mdesc_get_property(hp, mp, "size", NULL);
        }
 }
 
-static void __init mark_core_ids(struct mdesc_handle *hp, u64 mp, int core_id)
+static void __devinit mark_core_ids(struct mdesc_handle *hp, u64 mp,
+                                   int core_id)
 {
        u64 a;
 
        }
 }
 
-static void __init set_core_ids(struct mdesc_handle *hp)
+static void __devinit set_core_ids(struct mdesc_handle *hp)
 {
        int idx;
        u64 mp;
        }
 }
 
-static void __init mark_proc_ids(struct mdesc_handle *hp, u64 mp, int proc_id)
+static void __devinit mark_proc_ids(struct mdesc_handle *hp, u64 mp,
+                                   int proc_id)
 {
        u64 a;
 
        }
 }
 
-static void __init __set_proc_ids(struct mdesc_handle *hp,
-                                 const char *exec_unit_name)
+static void __devinit __set_proc_ids(struct mdesc_handle *hp,
+                                    const char *exec_unit_name)
 {
        int idx;
        u64 mp;
        }
 }
 
-static void __init set_proc_ids(struct mdesc_handle *hp)
+static void __devinit set_proc_ids(struct mdesc_handle *hp)
 {
        __set_proc_ids(hp, "exec_unit");
        __set_proc_ids(hp, "exec-unit");
 }
 
-static void __init get_one_mondo_bits(const u64 *p, unsigned int *mask, unsigned char def)
+static void __devinit get_one_mondo_bits(const u64 *p, unsigned int *mask,
+                                        unsigned char def)
 {
        u64 val;
 
        *mask = ((1U << def) * 64U) - 1U;
 }
 
-static void __init get_mondo_data(struct mdesc_handle *hp, u64 mp,
-                                 struct trap_per_cpu *tb)
+static void __devinit get_mondo_data(struct mdesc_handle *hp, u64 mp,
+                                    struct trap_per_cpu *tb)
 {
        const u64 *val;
 
        get_one_mondo_bits(val, &tb->nonresum_qmask, 2);
 }
 
-static void __init mdesc_fill_in_cpu_data(void)
+void __devinit mdesc_fill_in_cpu_data(cpumask_t mask)
 {
        struct mdesc_handle *hp = mdesc_grab();
        u64 mp;
 #ifdef CONFIG_SMP
                if (cpuid >= NR_CPUS)
                        continue;
+               if (!cpu_isset(cpuid, mask))
+                       continue;
 #else
                /* On uniprocessor we only want the values for the
                 * real physical cpu the kernel booted onto, however
 
 #ifdef CONFIG_SMP
                cpu_set(cpuid, cpu_present_map);
-               cpu_set(cpuid, phys_cpu_present_map);
 #endif
 
                c->core_id = 0;
 {
        struct mdesc_handle *hp;
        unsigned long len, real_len, status;
+       cpumask_t mask;
 
        (void) sun4v_mach_desc(0UL, 0UL, &len);
 
        cur_mdesc = hp;
 
        report_platform_properties();
-       mdesc_fill_in_cpu_data();
+
+       cpus_setall(mask);
+       mdesc_fill_in_cpu_data(mask);
 }
 
 #include <asm/sections.h>
 #include <asm/prom.h>
 #include <asm/mdesc.h>
+#include <asm/ldc.h>
 
 extern void calibrate_delay(void);
 
 /* Please don't make this stuff initdata!!!  --DaveM */
 unsigned char boot_cpu_id;
 
+cpumask_t cpu_possible_map __read_mostly = CPU_MASK_NONE;
 cpumask_t cpu_online_map __read_mostly = CPU_MASK_NONE;
-cpumask_t phys_cpu_present_map __read_mostly = CPU_MASK_NONE;
 cpumask_t cpu_sibling_map[NR_CPUS] __read_mostly =
        { [0 ... NR_CPUS-1] = CPU_MASK_NONE };
 cpumask_t cpu_core_map[NR_CPUS] __read_mostly =
        { [0 ... NR_CPUS-1] = CPU_MASK_NONE };
+
+EXPORT_SYMBOL(cpu_possible_map);
+EXPORT_SYMBOL(cpu_online_map);
+EXPORT_SYMBOL(cpu_sibling_map);
+EXPORT_SYMBOL(cpu_core_map);
+
 static cpumask_t smp_commenced_mask;
 static cpumask_t cpu_callout_map;
 
 
 static volatile unsigned long callin_flag = 0;
 
-void __init smp_callin(void)
+void __devinit smp_callin(void)
 {
        int cpuid = hard_smp_processor_id();
+       struct trap_per_cpu *tb = &trap_block[cpuid];;
 
        __local_per_cpu_offset = __per_cpu_offset(cpuid);
 
        atomic_inc(&init_mm.mm_count);
        current->active_mm = &init_mm;
 
+       if (tb->hdesc) {
+               kfree(tb->hdesc);
+               tb->hdesc = NULL;
+       }
+
        while (!cpu_isset(cpuid, smp_commenced_mask))
                rmb();
 
                /* Alloc the mondo queues, cpu will load them.  */
                sun4v_init_mondo_queues(0, cpu, 1, 0);
 
-               prom_startcpu_cpuid(cpu, entry, cookie);
+#ifdef CONFIG_SUN_LDOMS
+               if (ldom_domaining_enabled)
+                       ldom_startcpu_cpuid(cpu,
+                                           (unsigned long) cpu_new_thread);
+               else
+#endif
+                       prom_startcpu_cpuid(cpu, entry, cookie);
        } else {
                struct device_node *dp = of_find_node_by_cpuid(cpu);
 
                prom_startcpu(dp->node, entry, cookie);
        }
 
-       for (timeout = 0; timeout < 5000000; timeout++) {
+       for (timeout = 0; timeout < 50000; timeout++) {
                if (callin_flag)
                        break;
                udelay(100);
        return -EINVAL;
 }
 
-/* Constrain the number of cpus to max_cpus.  */
 void __init smp_prepare_cpus(unsigned int max_cpus)
 {
-       int i;
-
-       if (num_possible_cpus() > max_cpus) {
-               for_each_possible_cpu(i) {
-                       if (i != boot_cpu_id) {
-                               cpu_clear(i, phys_cpu_present_map);
-                               cpu_clear(i, cpu_present_map);
-                               if (num_possible_cpus() <= max_cpus)
-                                       break;
-                       }
-               }
-       }
-
        cpu_data(boot_cpu_id).udelay_val = loops_per_jiffy;
 }
 
        return ret;
 }
 
+#ifdef CONFIG_HOTPLUG_CPU
+int __cpu_disable(void)
+{
+       printk(KERN_ERR "SMP: __cpu_disable() on cpu %d\n",
+              smp_processor_id());
+       return -ENODEV;
+}
+
+void __cpu_die(unsigned int cpu)
+{
+       printk(KERN_ERR "SMP: __cpu_die(%u)\n", cpu);
+}
+#endif
+
 void __init smp_cpus_done(unsigned int max_cpus)
 {
        unsigned long bogosum = 0;