]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/infiniband/hw/ehca/ehca_main.c
IB/ehca: Change misleading error message on memory hotplug
[linux-2.6-omap-h63xx.git] / drivers / infiniband / hw / ehca / ehca_main.c
index 598844d2edc93131a0cd1c9264035e1651f2097a..bec7e0249358f6cb876729d9070c51d94f6e29e7 100644 (file)
@@ -44,6 +44,8 @@
 #include <linux/slab.h>
 #endif
 
+#include <linux/notifier.h>
+#include <linux/memory.h>
 #include "ehca_classes.h"
 #include "ehca_iverbs.h"
 #include "ehca_mrmw.h"
@@ -366,22 +368,23 @@ static int ehca_sense_attributes(struct ehca_shca *shca)
                        shca->hca_cap_mr_pgsize |= pgsize_map[i + 1];
 
        /* Set maximum number of CQs and QPs to calculate EQ size */
-       if (ehca_max_qp == -1)
-               ehca_max_qp = min_t(int, rblock->max_qp, EHCA_MAX_NUM_QUEUES);
-       else if (ehca_max_qp < 1 || ehca_max_qp > rblock->max_qp) {
-               ehca_gen_err("Requested number of QPs is out of range (1 - %i) "
-                       "specified by HW", rblock->max_qp);
-               ret = -EINVAL;
-               goto sense_attributes1;
+       if (shca->max_num_qps == -1)
+               shca->max_num_qps = min_t(int, rblock->max_qp,
+                                         EHCA_MAX_NUM_QUEUES);
+       else if (shca->max_num_qps < 1 || shca->max_num_qps > rblock->max_qp) {
+               ehca_gen_warn("The requested number of QPs is out of range "
+                             "(1 - %i) specified by HW. Value is set to %i",
+                             rblock->max_qp, rblock->max_qp);
+               shca->max_num_qps = rblock->max_qp;
        }
 
-       if (ehca_max_cq == -1)
-               ehca_max_cq = min_t(int, rblock->max_cq, EHCA_MAX_NUM_QUEUES);
-       else if (ehca_max_cq < 1 || ehca_max_cq > rblock->max_cq) {
-               ehca_gen_err("Requested number of CQs is out of range (1 - %i) "
-                       "specified by HW", rblock->max_cq);
-               ret = -EINVAL;
-               goto sense_attributes1;
+       if (shca->max_num_cqs == -1)
+               shca->max_num_cqs = min_t(int, rblock->max_cq,
+                                         EHCA_MAX_NUM_QUEUES);
+       else if (shca->max_num_cqs < 1 || shca->max_num_cqs > rblock->max_cq) {
+               ehca_gen_warn("The requested number of CQs is out of range "
+                             "(1 - %i) specified by HW. Value is set to %i",
+                             rblock->max_cq, rblock->max_cq);
        }
 
        /* query max MTU from first port -- it's the same for all ports */
@@ -733,9 +736,13 @@ static int __devinit ehca_probe(struct of_device *dev,
                ehca_gen_err("Cannot allocate shca memory.");
                return -ENOMEM;
        }
+
        mutex_init(&shca->modify_mutex);
        atomic_set(&shca->num_cqs, 0);
        atomic_set(&shca->num_qps, 0);
+       shca->max_num_qps = ehca_max_qp;
+       shca->max_num_cqs = ehca_max_cq;
+
        for (i = 0; i < ARRAY_SIZE(shca->sport); i++)
                spin_lock_init(&shca->sport[i].mod_sqp_lock);
 
@@ -755,7 +762,7 @@ static int __devinit ehca_probe(struct of_device *dev,
                goto probe1;
        }
 
-       eq_size = 2 * ehca_max_cq + 4 * ehca_max_qp;
+       eq_size = 2 * shca->max_num_cqs + 4 * shca->max_num_qps;
        /* create event queues */
        ret = ehca_create_eq(shca, &shca->eq, EHCA_EQ, eq_size);
        if (ret) {
@@ -964,6 +971,40 @@ void ehca_poll_eqs(unsigned long data)
        spin_unlock(&shca_list_lock);
 }
 
+static int ehca_mem_notifier(struct notifier_block *nb,
+                            unsigned long action, void *data)
+{
+       static unsigned long ehca_dmem_warn_time;
+
+       switch (action) {
+       case MEM_CANCEL_OFFLINE:
+       case MEM_CANCEL_ONLINE:
+       case MEM_ONLINE:
+       case MEM_OFFLINE:
+               return NOTIFY_OK;
+       case MEM_GOING_ONLINE:
+       case MEM_GOING_OFFLINE:
+               /* only ok if no hca is attached to the lpar */
+               spin_lock(&shca_list_lock);
+               if (list_empty(&shca_list)) {
+                       spin_unlock(&shca_list_lock);
+                       return NOTIFY_OK;
+               } else {
+                       spin_unlock(&shca_list_lock);
+                       if (printk_timed_ratelimit(&ehca_dmem_warn_time,
+                                                  30 * 1000))
+                               ehca_gen_err("DMEM operations are not allowed"
+                                            "in conjunction with eHCA");
+                       return NOTIFY_BAD;
+               }
+       }
+       return NOTIFY_OK;
+}
+
+static struct notifier_block ehca_mem_nb = {
+       .notifier_call = ehca_mem_notifier,
+};
+
 static int __init ehca_module_init(void)
 {
        int ret;
@@ -991,6 +1032,12 @@ static int __init ehca_module_init(void)
                goto module_init2;
        }
 
+       ret = register_memory_notifier(&ehca_mem_nb);
+       if (ret) {
+               ehca_gen_err("Failed registering memory add/remove notifier");
+               goto module_init3;
+       }
+
        if (ehca_poll_all_eqs != 1) {
                ehca_gen_err("WARNING!!!");
                ehca_gen_err("It is possible to lose interrupts.");
@@ -1003,6 +1050,9 @@ static int __init ehca_module_init(void)
 
        return 0;
 
+module_init3:
+       ibmebus_unregister_driver(&ehca_driver);
+
 module_init2:
        ehca_destroy_slab_caches();
 
@@ -1018,6 +1068,8 @@ static void __exit ehca_module_exit(void)
 
        ibmebus_unregister_driver(&ehca_driver);
 
+       unregister_memory_notifier(&ehca_mem_nb);
+
        ehca_destroy_slab_caches();
 
        ehca_destroy_comp_pool();