sgi-xp: isolate xpc_vars_part structure to sn2 only
[pandora-kernel.git] / drivers / misc / sgi-xp / xpc_main.c
index 579b01f..be3a485 100644 (file)
@@ -175,6 +175,14 @@ static struct notifier_block xpc_die_notifier = {
        .notifier_call = xpc_system_die,
 };
 
+enum xp_retval (*xpc_rsvd_page_init) (struct xpc_rsvd_page *rp);
+enum xp_retval (*xpc_make_first_contact) (struct xpc_partition *part);
+u64 (*xpc_get_IPI_flags) (struct xpc_partition *part);
+struct xpc_msg *(*xpc_get_deliverable_msg) (struct xpc_channel *ch);
+enum xp_retval (*xpc_setup_infrastructure) (struct xpc_partition *part);
+void (*xpc_teardown_infrastructure) (struct xpc_partition *part);
+
+
 /*
  * Timer function to enforce the timelimit on the partition disengage request.
  */
@@ -229,11 +237,10 @@ xpc_hb_checker(void *ignore)
        int last_IRQ_count = 0;
        int new_IRQ_count;
        int force_IRQ = 0;
-       cpumask_of_cpu_ptr(cpumask, XPC_HB_CHECK_CPU);
 
        /* this thread was marked active by xpc_hb_init() */
 
-       set_cpus_allowed_ptr(current, cpumask);
+       set_cpus_allowed_ptr(current, &cpumask_of_cpu(XPC_HB_CHECK_CPU));
 
        /* set our heartbeating to other partitions into motion */
        xpc_hb_check_timeout = jiffies + (xpc_hb_check_interval * HZ);
@@ -311,38 +318,9 @@ xpc_initiate_discovery(void *ignore)
        return 0;
 }
 
-/*
- * Establish first contact with the remote partititon. This involves pulling
- * the XPC per partition variables from the remote partition and waiting for
- * the remote partition to pull ours.
- */
-static enum xp_retval
-xpc_make_first_contact(struct xpc_partition *part)
-{
-       enum xp_retval ret;
-
-       while ((ret = xpc_pull_remote_vars_part(part)) != xpSuccess) {
-               if (ret != xpRetry) {
-                       XPC_DEACTIVATE_PARTITION(part, ret);
-                       return ret;
-               }
-
-               dev_dbg(xpc_chan, "waiting to make first contact with "
-                       "partition %d\n", XPC_PARTID(part));
-
-               /* wait a 1/4 of a second or so */
-               (void)msleep_interruptible(250);
-
-               if (part->act_state == XPC_P_DEACTIVATING)
-                       return part->reason;
-       }
-
-       return xpc_mark_partition_active(part);
-}
-
 /*
  * The first kthread assigned to a newly activated partition is the one
- * created by XPC HB with which it calls xpc_partition_up(). XPC hangs on to
+ * created by XPC HB with which it calls xpc_activating(). XPC hangs on to
  * that kthread until the partition is brought down, at which time that kthread
  * returns back to XPC HB. (The return of that kthread will signify to XPC HB
  * that XPC has dismantled all communication infrastructure for the associated
@@ -392,41 +370,10 @@ xpc_channel_mgr(struct xpc_partition *part)
  * upped partition.
  *
  * The kthread that was created by XPC HB and which setup the XPC
- * infrastructure will remain assigned to the partition until the partition
- * goes down. At which time the kthread will teardown the XPC infrastructure
- * and then exit.
- *
- * XPC HB will put the remote partition's XPC per partition specific variables
- * physical address into xpc_partitions[partid].remote_vars_part_pa prior to
- * calling xpc_partition_up().
+ * infrastructure will remain assigned to the partition becoming the channel
+ * manager for that partition until the partition is deactivating, at which
+ * time the kthread will teardown the XPC infrastructure and then exit.
  */
-static void
-xpc_partition_up(struct xpc_partition *part)
-{
-       DBUG_ON(part->channels != NULL);
-
-       dev_dbg(xpc_chan, "activating partition %d\n", XPC_PARTID(part));
-
-       if (xpc_setup_infrastructure(part) != xpSuccess)
-               return;
-
-       /*
-        * The kthread that XPC HB called us with will become the
-        * channel manager for this partition. It will not return
-        * back to XPC HB until the partition's XPC infrastructure
-        * has been dismantled.
-        */
-
-       (void)xpc_part_ref(part);       /* this will always succeed */
-
-       if (xpc_make_first_contact(part) == xpSuccess)
-               xpc_channel_mgr(part);
-
-       xpc_part_deref(part);
-
-       xpc_teardown_infrastructure(part);
-}
-
 static int
 xpc_activating(void *__partid)
 {
@@ -434,7 +381,7 @@ xpc_activating(void *__partid)
        struct xpc_partition *part = &xpc_partitions[partid];
        unsigned long irq_flags;
 
-       DBUG_ON(partid <= 0 || partid >= XP_MAX_PARTITIONS);
+       DBUG_ON(partid < 0 || partid >= xp_max_npartitions);
 
        spin_lock_irqsave(&part->act_lock, irq_flags);
 
@@ -452,7 +399,7 @@ xpc_activating(void *__partid)
        XPC_SET_REASON(part, 0, 0);
        spin_unlock_irqrestore(&part->act_lock, irq_flags);
 
-       dev_dbg(xpc_part, "bringing partition %d up\n", partid);
+       dev_dbg(xpc_part, "activating partition %d\n", partid);
 
        /*
         * Register the remote partition's AMOs with SAL so it can handle
@@ -466,7 +413,7 @@ xpc_activating(void *__partid)
         */
        if (sn_register_xp_addr_region(part->remote_amos_page_pa,
                                       PAGE_SIZE, 1) < 0) {
-               dev_warn(xpc_part, "xpc_partition_up(%d) failed to register "
+               dev_warn(xpc_part, "xpc_activating(%d) failed to register "
                         "xp_addr region\n", partid);
 
                spin_lock_irqsave(&part->act_lock, irq_flags);
@@ -480,11 +427,18 @@ xpc_activating(void *__partid)
        xpc_allow_hb(partid, xpc_vars);
        xpc_IPI_send_activated(part);
 
-       /*
-        * xpc_partition_up() holds this thread and marks this partition as
-        * XPC_P_ACTIVE by calling xpc_hb_mark_active().
-        */
-       (void)xpc_partition_up(part);
+       if (xpc_setup_infrastructure(part) == xpSuccess) {
+               (void)xpc_part_ref(part);       /* this will always succeed */
+
+               if (xpc_make_first_contact(part) == xpSuccess) {
+                       xpc_mark_partition_active(part);
+                       xpc_channel_mgr(part);
+                       /* won't return until partition is deactivating */
+               }
+
+               xpc_part_deref(part);
+               xpc_teardown_infrastructure(part);
+       }
 
        xpc_disallow_hb(partid, xpc_vars);
        xpc_mark_partition_inactive(part);
@@ -545,7 +499,7 @@ xpc_notify_IRQ_handler(int irq, void *dev_id)
        short partid = (short)(u64)dev_id;
        struct xpc_partition *part = &xpc_partitions[partid];
 
-       DBUG_ON(partid <= 0 || partid >= XP_MAX_PARTITIONS);
+       DBUG_ON(partid < 0 || partid >= xp_max_npartitions);
 
        if (xpc_part_ref(part)) {
                xpc_check_for_channel_activity(part);
@@ -567,7 +521,7 @@ xpc_dropped_IPI_check(struct xpc_partition *part)
                xpc_check_for_channel_activity(part);
 
                part->dropped_IPI_timer.expires = jiffies +
-                   XPC_P_DROPPED_IPI_WAIT;
+                   XPC_P_DROPPED_IPI_WAIT_INTERVAL;
                add_timer(&part->dropped_IPI_timer);
                xpc_part_deref(part);
        }
@@ -816,7 +770,7 @@ xpc_disconnect_wait(int ch_number)
        int wakeup_channel_mgr;
 
        /* now wait for all callouts to the caller's function to cease */
-       for (partid = 1; partid < XP_MAX_PARTITIONS; partid++) {
+       for (partid = 0; partid < xp_max_npartitions; partid++) {
                part = &xpc_partitions[partid];
 
                if (!xpc_part_ref(part))
@@ -896,7 +850,7 @@ xpc_do_exit(enum xp_retval reason)
        do {
                active_part_count = 0;
 
-               for (partid = 1; partid < XP_MAX_PARTITIONS; partid++) {
+               for (partid = 0; partid < xp_max_npartitions; partid++) {
                        part = &xpc_partitions[partid];
 
                        if (xpc_partition_disengaged(part) &&
@@ -950,18 +904,15 @@ xpc_do_exit(enum xp_retval reason)
        DBUG_ON(xpc_partition_engaged(-1UL));
 
        /* indicate to others that our reserved page is uninitialized */
-       xpc_rsvd_page->vars_pa = 0;
+       xpc_rsvd_page->stamp = ZERO_STAMP;
 
        /* now it's time to eliminate our heartbeat */
        del_timer_sync(&xpc_hb_timer);
        DBUG_ON(xpc_vars->heartbeating_to_mask != 0);
 
        if (reason == xpUnloading) {
-               /* take ourselves off of the reboot_notifier_list */
-               (void)unregister_reboot_notifier(&xpc_reboot_notifier);
-
-               /* take ourselves off of the die_notifier list */
                (void)unregister_die_notifier(&xpc_die_notifier);
+               (void)unregister_reboot_notifier(&xpc_reboot_notifier);
        }
 
        /* close down protections for IPI operations */
@@ -973,6 +924,7 @@ xpc_do_exit(enum xp_retval reason)
        if (xpc_sysctl)
                unregister_sysctl_table(xpc_sysctl);
 
+       kfree(xpc_partitions);
        kfree(xpc_remote_copy_buffer_base);
 }
 
@@ -1018,7 +970,7 @@ xpc_die_disengage(void)
 
        xpc_vars->heartbeating_to_mask = 0;     /* indicate we're deactivated */
 
-       for (partid = 1; partid < XP_MAX_PARTITIONS; partid++) {
+       for (partid = 0; partid < xp_max_npartitions; partid++) {
                part = &xpc_partitions[partid];
 
                if (!XPC_SUPPORTS_DISENGAGE_REQUEST(part->
@@ -1054,7 +1006,8 @@ xpc_die_disengage(void)
 
                time = rtc_time();
                if (time >= disengage_request_timeout) {
-                       for (partid = 1; partid < XP_MAX_PARTITIONS; partid++) {
+                       for (partid = 0; partid < xp_max_npartitions;
+                            partid++) {
                                if (engaged & (1UL << partid)) {
                                        dev_info(xpc_part, "disengage from "
                                                 "remote partition %d timed "
@@ -1130,21 +1083,45 @@ xpc_init(void)
        struct task_struct *kthread;
        size_t buf_size;
 
-       if (!ia64_platform_is("sn2"))
+       if (is_shub()) {
+               /*
+                * The ia64-sn2 architecture supports at most 64 partitions.
+                * And the inability to unregister remote AMOs restricts us
+                * further to only support exactly 64 partitions on this
+                * architecture, no less.
+                */
+               if (xp_max_npartitions != 64)
+                       return -EINVAL;
+
+               xpc_init_sn2();
+
+       } else if (is_uv()) {
+               xpc_init_uv();
+
+       } else {
                return -ENODEV;
+       }
+
+       snprintf(xpc_part->bus_id, BUS_ID_SIZE, "part");
+       snprintf(xpc_chan->bus_id, BUS_ID_SIZE, "chan");
 
        buf_size = max(XPC_RP_VARS_SIZE,
                       XPC_RP_HEADER_SIZE + XP_NASID_MASK_BYTES);
        xpc_remote_copy_buffer = xpc_kmalloc_cacheline_aligned(buf_size,
                                                               GFP_KERNEL,
                                                  &xpc_remote_copy_buffer_base);
-       if (xpc_remote_copy_buffer == NULL)
+       if (xpc_remote_copy_buffer == NULL) {
+               dev_err(xpc_part, "can't get memory for remote copy buffer\n");
                return -ENOMEM;
+       }
 
-       snprintf(xpc_part->bus_id, BUS_ID_SIZE, "part");
-       snprintf(xpc_chan->bus_id, BUS_ID_SIZE, "chan");
-
-       xpc_sysctl = register_sysctl_table(xpc_sys_dir);
+       xpc_partitions = kzalloc(sizeof(struct xpc_partition) *
+                                xp_max_npartitions, GFP_KERNEL);
+       if (xpc_partitions == NULL) {
+               dev_err(xpc_part, "can't get memory for partition structure\n");
+               ret = -ENOMEM;
+               goto out_1;
+       }
 
        /*
         * The first few fields of each entry of xpc_partitions[] need to
@@ -1154,7 +1131,7 @@ xpc_init(void)
         * ENTRIES ARE MEANINGFUL UNTIL AFTER AN ENTRY'S CORRESPONDING
         * PARTITION HAS BEEN ACTIVATED.
         */
-       for (partid = 1; partid < XP_MAX_PARTITIONS; partid++) {
+       for (partid = 0; partid < xp_max_npartitions; partid++) {
                part = &xpc_partitions[partid];
 
                DBUG_ON((u64)part != L1_CACHE_ALIGN((u64)part));
@@ -1174,6 +1151,8 @@ xpc_init(void)
                atomic_set(&part->references, 0);
        }
 
+       xpc_sysctl = register_sysctl_table(xpc_sys_dir);
+
        /*
         * Open up protections for IPI operations (and AMO operations on
         * Shub 1.1 systems).
@@ -1197,14 +1176,8 @@ xpc_init(void)
        if (ret != 0) {
                dev_err(xpc_part, "can't register ACTIVATE IRQ handler, "
                        "errno=%d\n", -ret);
-
-               xpc_restrict_IPI_ops();
-
-               if (xpc_sysctl)
-                       unregister_sysctl_table(xpc_sysctl);
-
-               kfree(xpc_remote_copy_buffer_base);
-               return -EBUSY;
+               ret = -EBUSY;
+               goto out_2;
        }
 
        /*
@@ -1212,18 +1185,11 @@ xpc_init(void)
         * other partitions to discover we are alive and establish initial
         * communications.
         */
-       xpc_rsvd_page = xpc_rsvd_page_init();
+       xpc_rsvd_page = xpc_setup_rsvd_page();
        if (xpc_rsvd_page == NULL) {
-               dev_err(xpc_part, "could not setup our reserved page\n");
-
-               free_irq(SGI_XPC_ACTIVATE, NULL);
-               xpc_restrict_IPI_ops();
-
-               if (xpc_sysctl)
-                       unregister_sysctl_table(xpc_sysctl);
-
-               kfree(xpc_remote_copy_buffer_base);
-               return -EBUSY;
+               dev_err(xpc_part, "can't setup our reserved page\n");
+               ret = -EBUSY;
+               goto out_3;
        }
 
        /* add ourselves to the reboot_notifier_list */
@@ -1246,25 +1212,8 @@ xpc_init(void)
        kthread = kthread_run(xpc_hb_checker, NULL, XPC_HB_CHECK_THREAD_NAME);
        if (IS_ERR(kthread)) {
                dev_err(xpc_part, "failed while forking hb check thread\n");
-
-               /* indicate to others that our reserved page is uninitialized */
-               xpc_rsvd_page->vars_pa = 0;
-
-               /* take ourselves off of the reboot_notifier_list */
-               (void)unregister_reboot_notifier(&xpc_reboot_notifier);
-
-               /* take ourselves off of the die_notifier list */
-               (void)unregister_die_notifier(&xpc_die_notifier);
-
-               del_timer_sync(&xpc_hb_timer);
-               free_irq(SGI_XPC_ACTIVATE, NULL);
-               xpc_restrict_IPI_ops();
-
-               if (xpc_sysctl)
-                       unregister_sysctl_table(xpc_sysctl);
-
-               kfree(xpc_remote_copy_buffer_base);
-               return -EBUSY;
+               ret = -EBUSY;
+               goto out_4;
        }
 
        /*
@@ -1291,6 +1240,25 @@ xpc_init(void)
                          xpc_initiate_partid_to_nasids);
 
        return 0;
+
+       /* initialization was not successful */
+out_4:
+       /* indicate to others that our reserved page is uninitialized */
+       xpc_rsvd_page->stamp = ZERO_STAMP;
+
+       del_timer_sync(&xpc_hb_timer);
+       (void)unregister_die_notifier(&xpc_die_notifier);
+       (void)unregister_reboot_notifier(&xpc_reboot_notifier);
+out_3:
+       free_irq(SGI_XPC_ACTIVATE, NULL);
+out_2:
+       xpc_restrict_IPI_ops();
+       if (xpc_sysctl)
+               unregister_sysctl_table(xpc_sysctl);
+       kfree(xpc_partitions);
+out_1:
+       kfree(xpc_remote_copy_buffer_base);
+       return ret;
 }
 
 module_init(xpc_init);