]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/message/i2o/exec-osm.c
Merge master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6
[linux-2.6-omap-h63xx.git] / drivers / message / i2o / exec-osm.c
index 5ea133c59afb3e7ab2788c2d68c1512723ddf5c6..902753b2c66101858fe295e7bc97c24cff674389 100644 (file)
@@ -55,6 +55,7 @@ struct i2o_exec_wait {
        u32 m;                  /* message id */
        struct i2o_message *msg;        /* pointer to the reply message */
        struct list_head list;  /* node in global wait list */
+       spinlock_t lock;        /* lock before modifying */
 };
 
 /* Work struct needed to handle LCT NOTIFY replies */
@@ -87,13 +88,14 @@ static struct i2o_exec_wait *i2o_exec_wait_alloc(void)
                return NULL;
 
        INIT_LIST_HEAD(&wait->list);
+       spin_lock_init(&wait->lock);
 
        return wait;
 };
 
 /**
- *     i2o_exec_wait_free - Free a i2o_exec_wait struct
- *     @i2o_exec_wait: I2O wait data which should be cleaned up
+ *     i2o_exec_wait_free - Free an i2o_exec_wait struct
+ *     @wait: I2O wait data which should be cleaned up
  */
 static void i2o_exec_wait_free(struct i2o_exec_wait *wait)
 {
@@ -103,7 +105,7 @@ static void i2o_exec_wait_free(struct i2o_exec_wait *wait)
 /**
  *     i2o_msg_post_wait_mem - Post and wait a message with DMA buffers
  *     @c: controller
- *     @m: message to post
+ *     @msg: message to post
  *     @timeout: time in seconds to wait
  *     @dma: i2o_dma struct of the DMA buffer to free on failure
  *
@@ -122,9 +124,10 @@ static void i2o_exec_wait_free(struct i2o_exec_wait *wait)
 int i2o_msg_post_wait_mem(struct i2o_controller *c, struct i2o_message *msg,
                          unsigned long timeout, struct i2o_dma *dma)
 {
-       DECLARE_WAIT_QUEUE_HEAD(wq);
+       DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq);
        struct i2o_exec_wait *wait;
        static u32 tcntxt = 0x80000000;
+       unsigned long flags;
        int rc = 0;
 
        wait = i2o_exec_wait_alloc();
@@ -146,33 +149,28 @@ int i2o_msg_post_wait_mem(struct i2o_controller *c, struct i2o_message *msg,
        wait->tcntxt = tcntxt++;
        msg->u.s.tcntxt = cpu_to_le32(wait->tcntxt);
 
+       wait->wq = &wq;
+       /*
+        * we add elements to the head, because if a entry in the list will
+        * never be removed, we have to iterate over it every time
+        */
+       list_add(&wait->list, &i2o_exec_wait_list);
+
        /*
         * Post the message to the controller. At some point later it will
         * return. If we time out before it returns then complete will be zero.
         */
        i2o_msg_post(c, msg);
 
-       if (!wait->complete) {
-               wait->wq = &wq;
-               /*
-                * we add elements add the head, because if a entry in the list
-                * will never be removed, we have to iterate over it every time
-                */
-               list_add(&wait->list, &i2o_exec_wait_list);
-
-               wait_event_interruptible_timeout(wq, wait->complete,
-                                                timeout * HZ);
+       wait_event_interruptible_timeout(wq, wait->complete, timeout * HZ);
 
-               wait->wq = NULL;
-       }
+       spin_lock_irqsave(&wait->lock, flags);
 
-       barrier();
+       wait->wq = NULL;
 
-       if (wait->complete) {
+       if (wait->complete)
                rc = le32_to_cpu(wait->msg->body[0]) >> 24;
-               i2o_flush_reply(c, wait->m);
-               i2o_exec_wait_free(wait);
-       } else {
+       else {
                /*
                 * We cannot remove it now. This is important. When it does
                 * terminate (which it must do if the controller has not
@@ -186,6 +184,13 @@ int i2o_msg_post_wait_mem(struct i2o_controller *c, struct i2o_message *msg,
                rc = -ETIMEDOUT;
        }
 
+       spin_unlock_irqrestore(&wait->lock, flags);
+
+       if (rc != -ETIMEDOUT) {
+               i2o_flush_reply(c, wait->m);
+               i2o_exec_wait_free(wait);
+       }
+
        return rc;
 };
 
@@ -213,7 +218,6 @@ static int i2o_msg_post_wait_complete(struct i2o_controller *c, u32 m,
 {
        struct i2o_exec_wait *wait, *tmp;
        unsigned long flags;
-       static spinlock_t lock = SPIN_LOCK_UNLOCKED;
        int rc = 1;
 
        /*
@@ -223,23 +227,24 @@ static int i2o_msg_post_wait_complete(struct i2o_controller *c, u32 m,
         * already expired. Not much we can do about that except log it for
         * debug purposes, increase timeout, and recompile.
         */
-       spin_lock_irqsave(&lock, flags);
        list_for_each_entry_safe(wait, tmp, &i2o_exec_wait_list, list) {
                if (wait->tcntxt == context) {
-                       list_del(&wait->list);
+                       spin_lock_irqsave(&wait->lock, flags);
 
-                       spin_unlock_irqrestore(&lock, flags);
+                       list_del(&wait->list);
 
                        wait->m = m;
                        wait->msg = msg;
                        wait->complete = 1;
 
-                       barrier();
-
-                       if (wait->wq) {
-                               wake_up_interruptible(wait->wq);
+                       if (wait->wq)
                                rc = 0;
-                       } else {
+                       else
+                               rc = -1;
+
+                       spin_unlock_irqrestore(&wait->lock, flags);
+
+                       if (rc) {
                                struct device *dev;
 
                                dev = &c->pdev->dev;
@@ -248,15 +253,13 @@ static int i2o_msg_post_wait_complete(struct i2o_controller *c, u32 m,
                                         c->name);
                                i2o_dma_free(dev, &wait->dma);
                                i2o_exec_wait_free(wait);
-                               rc = -1;
-                       }
+                       } else
+                               wake_up_interruptible(wait->wq);
 
                        return rc;
                }
        }
 
-       spin_unlock_irqrestore(&lock, flags);
-
        osm_warn("%s: Bogus reply in POST WAIT (tr-context: %08x)!\n", c->name,
                 context);
 
@@ -266,6 +269,7 @@ static int i2o_msg_post_wait_complete(struct i2o_controller *c, u32 m,
 /**
  *     i2o_exec_show_vendor_id - Displays Vendor ID of controller
  *     @d: device of which the Vendor ID should be displayed
+ *     @attr: device_attribute to display
  *     @buf: buffer into which the Vendor ID should be printed
  *
  *     Returns number of bytes printed into buffer.
@@ -287,6 +291,7 @@ static ssize_t i2o_exec_show_vendor_id(struct device *d,
 /**
  *     i2o_exec_show_product_id - Displays Product ID of controller
  *     @d: device of which the Product ID should be displayed
+ *     @attr: device_attribute to display
  *     @buf: buffer into which the Product ID should be printed
  *
  *     Returns number of bytes printed into buffer.
@@ -322,18 +327,24 @@ static DEVICE_ATTR(product_id, S_IRUGO, i2o_exec_show_product_id, NULL);
 static int i2o_exec_probe(struct device *dev)
 {
        struct i2o_device *i2o_dev = to_i2o_device(dev);
-       struct i2o_controller *c = i2o_dev->iop;
-
-       i2o_event_register(i2o_dev, &i2o_exec_driver, 0, 0xffffffff);
+       int rc;
 
-       c->exec = i2o_dev;
+       rc = i2o_event_register(i2o_dev, &i2o_exec_driver, 0, 0xffffffff);
+       if (rc) goto err_out;
 
-       i2o_exec_lct_notify(c, c->lct->change_ind + 1);
-
-       device_create_file(dev, &dev_attr_vendor_id);
-       device_create_file(dev, &dev_attr_product_id);
+       rc = device_create_file(dev, &dev_attr_vendor_id);
+       if (rc) goto err_evtreg;
+       rc = device_create_file(dev, &dev_attr_product_id);
+       if (rc) goto err_vid;
 
        return 0;
+
+err_vid:
+       device_remove_file(dev, &dev_attr_vendor_id);
+err_evtreg:
+       i2o_event_register(to_i2o_device(dev), &i2o_exec_driver, 0, 0);
+err_out:
+       return rc;
 };
 
 /**
@@ -356,14 +367,16 @@ static int i2o_exec_remove(struct device *dev)
 
 /**
  *     i2o_exec_lct_modified - Called on LCT NOTIFY reply
- *     @c: I2O controller on which the LCT has modified
+ *     @work: work struct for a specific controller
  *
  *     This function handles asynchronus LCT NOTIFY replies. It parses the
  *     new LCT and if the buffer for the LCT was to small sends a LCT NOTIFY
  *     again, otherwise send LCT NOTIFY to get informed on next LCT change.
  */
-static void i2o_exec_lct_modified(struct i2o_exec_lct_notify_work *work)
+static void i2o_exec_lct_modified(struct work_struct *_work)
 {
+       struct i2o_exec_lct_notify_work *work =
+               container_of(_work, struct i2o_exec_lct_notify_work, work);
        u32 change_ind = 0;
        struct i2o_controller *c = work->c;
 
@@ -430,8 +443,7 @@ static int i2o_exec_reply(struct i2o_controller *c, u32 m,
 
                work->c = c;
 
-               INIT_WORK(&work->work, (void (*)(void *))i2o_exec_lct_modified,
-                         work);
+               INIT_WORK(&work->work, i2o_exec_lct_modified);
                queue_work(i2o_exec_driver.event_queue, &work->work);
                return 1;
        }
@@ -451,13 +463,15 @@ static int i2o_exec_reply(struct i2o_controller *c, u32 m,
 
 /**
  *     i2o_exec_event - Event handling function
- *     @evt: Event which occurs
+ *     @work: Work item in occurring event
  *
  *     Handles events send by the Executive device. At the moment does not do
  *     anything useful.
  */
-static void i2o_exec_event(struct i2o_event *evt)
+static void i2o_exec_event(struct work_struct *work)
 {
+       struct i2o_event *evt = container_of(work, struct i2o_event, work);
+
        if (likely(evt->i2o_dev))
                osm_debug("Event received from device: %d\n",
                          evt->i2o_dev->lct_data.tid);
@@ -523,6 +537,8 @@ static int i2o_exec_lct_notify(struct i2o_controller *c, u32 change_ind)
        struct device *dev;
        struct i2o_message *msg;
 
+       down(&c->lct_lock);
+
        dev = &c->pdev->dev;
 
        if (i2o_dma_realloc
@@ -545,6 +561,8 @@ static int i2o_exec_lct_notify(struct i2o_controller *c, u32 change_ind)
 
        i2o_msg_post(c, msg);
 
+       up(&c->lct_lock);
+
        return 0;
 };