Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 27922b4260f65d317aabda37e42bbbff > files > 1952

kernel-2.6.18-238.el5.src.rpm

From: Tony Camuso <tcamuso@redhat.com>
Date: Mon, 16 Nov 2009 23:48:49 -0500
Subject: [misc] hpilo: staging for interrupt handling
Message-id: <20091116234839.12336.68428.sendpatchset@dhcp-100-2-186.bos.redhat.com>
Patchwork-id: 21389
O-Subject: [RHEL5.5 PATCH 1/3]HPILO: Staging for Interrupt Handling
Bugzilla: 515010
RH-Acked-by: Prarit Bhargava <prarit@redhat.com>

commit 66d5e5169c96f3e0175235e2bcbaedc8bc1c728f
Author: David Altobelli <david.altobelli@hp.com>
Date:   Mon Aug 17 17:07:03 2009 -0600

    hpilo: staging for interrupt handling

    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>

diff --git a/drivers/misc/hpilo.c b/drivers/misc/hpilo.c
index f2a6102..4d27ca0 100644
--- a/drivers/misc/hpilo.c
+++ b/drivers/misc/hpilo.c
@@ -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)