hpilo: staging for interrupt handling
authorDavid Altobelli <david.altobelli@hp.com>
Mon, 17 Aug 2009 23:07:03 +0000 (17:07 -0600)
committerGreg Kroah-Hartman <gregkh@suse.de>
Tue, 15 Sep 2009 16:50:48 +0000 (09:50 -0700)
Refactor some hpilo routines in order to allow for locking changes in
interrupt handling.  Should not be functionally different.

Signed-off-by: David Altobelli <david.altobelli@hp.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/misc/hpilo.c

index 880ccf3..35ed123 100644 (file)
@@ -151,6 +151,7 @@ static inline void doorbell_clr(struct ccb *ccb)
 {
        iowrite8(2, ccb->ccb_u5.db_base);
 }
+
 static inline int ctrl_set(int l2sz, int idxmask, int desclim)
 {
        int active = 0, go = 1;
@@ -160,6 +161,7 @@ static inline int ctrl_set(int l2sz, int idxmask, int desclim)
               active << CTRL_BITPOS_A |
               go << CTRL_BITPOS_G;
 }
+
 static void ctrl_setup(struct ccb *ccb, int nr_desc, int l2desc_sz)
 {
        /* for simplicity, use the same parameters for send and recv ctrls */
@@ -192,13 +194,10 @@ static void fifo_setup(void *base_addr, int nr_entry)
 
 static void ilo_ccb_close(struct pci_dev *pdev, struct ccb_data *data)
 {
-       struct ccb *driver_ccb;
-       struct ccb __iomem *device_ccb;
+       struct ccb *driver_ccb = &data->driver_ccb;
+       struct ccb __iomem *device_ccb = data->mapped_ccb;
        int retries;
 
-       driver_ccb = &data->driver_ccb;
-       device_ccb = data->mapped_ccb;
-
        /* complicated dance to tell the hw we are stopping */
        doorbell_clr(driver_ccb);
        iowrite32(ioread32(&device_ccb->send_ctrl) & ~(1 << CTRL_BITPOS_G),
@@ -225,26 +224,22 @@ static void ilo_ccb_close(struct pci_dev *pdev, struct ccb_data *data)
        pci_free_consistent(pdev, data->dma_size, data->dma_va, data->dma_pa);
 }
 
-static int ilo_ccb_open(struct ilo_hwinfo *hw, struct ccb_data *data, int slot)
+static int ilo_ccb_setup(struct ilo_hwinfo *hw, struct ccb_data *data, int slot)
 {
        char *dma_va, *dma_pa;
-       int pkt_id, pkt_sz, i, error;
        struct ccb *driver_ccb, *ilo_ccb;
-       struct pci_dev *pdev;
 
        driver_ccb = &data->driver_ccb;
        ilo_ccb = &data->ilo_ccb;
-       pdev = hw->ilo_dev;
 
        data->dma_size = 2 * fifo_sz(NR_QENTRY) +
                         2 * desc_mem_sz(NR_QENTRY) +
                         ILO_START_ALIGN + ILO_CACHE_SZ;
 
-       error = -ENOMEM;
-       data->dma_va = pci_alloc_consistent(pdev, data->dma_size,
+       data->dma_va = pci_alloc_consistent(hw->ilo_dev, data->dma_size,
                                            &data->dma_pa);
        if (!data->dma_va)
-               goto out;
+               return -ENOMEM;
 
        dma_va = (char *)data->dma_va;
        dma_pa = (char *)data->dma_pa;
@@ -290,10 +285,18 @@ static int ilo_ccb_open(struct ilo_hwinfo *hw, struct ccb_data *data, int slot)
        driver_ccb->ccb_u5.db_base = hw->db_vaddr + (slot << L2_DB_SIZE);
        ilo_ccb->ccb_u5.db_base = NULL; /* hw ccb's doorbell is not used */
 
+       return 0;
+}
+
+static void ilo_ccb_open(struct ilo_hwinfo *hw, struct ccb_data *data, int slot)
+{
+       int pkt_id, pkt_sz;
+       struct ccb *driver_ccb = &data->driver_ccb;
+
        /* copy the ccb with physical addrs to device memory */
        data->mapped_ccb = (struct ccb __iomem *)
                                (hw->ram_vaddr + (slot * ILOHW_CCB_SZ));
-       memcpy_toio(data->mapped_ccb, ilo_ccb, sizeof(struct ccb));
+       memcpy_toio(data->mapped_ccb, &data->ilo_ccb, sizeof(struct ccb));
 
        /* put packets on the send and receive queues */
        pkt_sz = 0;
@@ -306,7 +309,14 @@ static int ilo_ccb_open(struct ilo_hwinfo *hw, struct ccb_data *data, int slot)
        for (pkt_id = 0; pkt_id < NR_QENTRY; pkt_id++)
                ilo_pkt_enqueue(hw, driver_ccb, RECVQ, pkt_id, pkt_sz);
 
+       /* the ccb is ready to use */
        doorbell_clr(driver_ccb);
+}
+
+static int ilo_ccb_verify(struct ilo_hwinfo *hw, struct ccb_data *data)
+{
+       int pkt_id, i;
+       struct ccb *driver_ccb = &data->driver_ccb;
 
        /* make sure iLO is really handling requests */
        for (i = MAX_WAIT; i > 0; i--) {
@@ -315,20 +325,14 @@ static int ilo_ccb_open(struct ilo_hwinfo *hw, struct ccb_data *data, int slot)
                udelay(WAIT_TIME);
        }
 
-       if (i) {
-               ilo_pkt_enqueue(hw, driver_ccb, SENDQ, pkt_id, 0);
-               doorbell_set(driver_ccb);
-       } else {
-               dev_err(&pdev->dev, "Open could not dequeue a packet\n");
-               error = -EBUSY;
-               goto free;
+       if (i == 0) {
+               dev_err(&hw->ilo_dev->dev, "Open could not dequeue a packet\n");
+               return -EBUSY;
        }
 
+       ilo_pkt_enqueue(hw, driver_ccb, SENDQ, pkt_id, 0);
+       doorbell_set(driver_ccb);
        return 0;
-free:
-       ilo_ccb_close(pdev, data);
-out:
-       return error;
 }
 
 static inline int is_channel_reset(struct ccb *ccb)
@@ -343,16 +347,31 @@ static inline void set_channel_reset(struct ccb *ccb)
        FIFOBARTOHANDLE(ccb->ccb_u1.send_fifobar)->reset = 1;
 }
 
+static inline int get_device_outbound(struct ilo_hwinfo *hw)
+{
+       return ioread32(&hw->mmio_vaddr[DB_OUT]);
+}
+
+static inline int is_db_reset(int db_out)
+{
+       return db_out & (1 << DB_RESET);
+}
+
 static inline int is_device_reset(struct ilo_hwinfo *hw)
 {
        /* check for global reset condition */
-       return ioread32(&hw->mmio_vaddr[DB_OUT]) & (1 << DB_RESET);
+       return is_db_reset(get_device_outbound(hw));
+}
+
+static inline void clear_pending_db(struct ilo_hwinfo *hw, int clr)
+{
+       iowrite32(clr, &hw->mmio_vaddr[DB_OUT]);
 }
 
 static inline void clear_device(struct ilo_hwinfo *hw)
 {
        /* clear the device (reset bits, pending channel entries) */
-       iowrite32(-1, &hw->mmio_vaddr[DB_OUT]);
+       clear_pending_db(hw, -1);
 }
 
 static void ilo_locked_reset(struct ilo_hwinfo *hw)
@@ -387,15 +406,11 @@ static ssize_t ilo_read(struct file *fp, char __user *buf,
                        size_t len, loff_t *off)
 {
        int err, found, cnt, pkt_id, pkt_len;
-       struct ccb_data *data;
-       struct ccb *driver_ccb;
-       struct ilo_hwinfo *hw;
+       struct ccb_data *data = fp->private_data;
+       struct ccb *driver_ccb = &data->driver_ccb;
+       struct ilo_hwinfo *hw = data->ilo_hw;
        void *pkt;
 
-       data = fp->private_data;
-       driver_ccb = &data->driver_ccb;
-       hw = data->ilo_hw;
-
        if (is_device_reset(hw) || is_channel_reset(driver_ccb)) {
                /*
                 * If the device has been reset, applications
@@ -442,15 +457,11 @@ static ssize_t ilo_write(struct file *fp, const char __user *buf,
                         size_t len, loff_t *off)
 {
        int err, pkt_id, pkt_len;
-       struct ccb_data *data;
-       struct ccb *driver_ccb;
-       struct ilo_hwinfo *hw;
+       struct ccb_data *data = fp->private_data;
+       struct ccb *driver_ccb = &data->driver_ccb;
+       struct ilo_hwinfo *hw = data->ilo_hw;
        void *pkt;
 
-       data = fp->private_data;
-       driver_ccb = &data->driver_ccb;
-       hw = data->ilo_hw;
-
        if (is_device_reset(hw) || is_channel_reset(driver_ccb)) {
                /*
                 * If the device has been reset, applications
@@ -532,14 +543,28 @@ static int ilo_open(struct inode *ip, struct file *fp)
        /* each fd private_data holds sw/hw view of ccb */
        if (hw->ccb_alloc[slot] == NULL) {
                /* create a channel control block for this minor */
-               error = ilo_ccb_open(hw, data, slot);
-               if (!error) {
-                       hw->ccb_alloc[slot] = data;
-                       hw->ccb_alloc[slot]->ccb_cnt = 1;
-                       hw->ccb_alloc[slot]->ccb_excl = fp->f_flags & O_EXCL;
-                       hw->ccb_alloc[slot]->ilo_hw = hw;
-               } else
+               error = ilo_ccb_setup(hw, data, slot);
+               if (error) {
+                       kfree(data);
+                       goto out;
+               }
+
+               /* write the ccb to hw */
+               ilo_ccb_open(hw, data, slot);
+
+               /* make sure the channel is functional */
+               error = ilo_ccb_verify(hw, data);
+               if (error) {
+                       ilo_ccb_close(hw->ilo_dev, data);
                        kfree(data);
+                       goto out;
+               }
+
+               data->ccb_cnt = 1;
+               data->ccb_excl = fp->f_flags & O_EXCL;
+               data->ilo_hw = hw;
+               hw->ccb_alloc[slot] = data;
+
        } else {
                kfree(data);
                if (fp->f_flags & O_EXCL || hw->ccb_alloc[slot]->ccb_excl) {
@@ -554,6 +579,7 @@ static int ilo_open(struct inode *ip, struct file *fp)
                        error = 0;
                }
        }
+out:
        spin_unlock(&hw->alloc_lock);
 
        if (!error)