|
@@ -13,6 +13,7 @@
|
|
|
#include <linux/module.h>
|
|
|
#include <linux/fs.h>
|
|
|
#include <linux/pci.h>
|
|
|
+#include <linux/interrupt.h>
|
|
|
#include <linux/ioport.h>
|
|
|
#include <linux/device.h>
|
|
|
#include <linux/file.h>
|
|
@@ -21,6 +22,8 @@
|
|
|
#include <linux/delay.h>
|
|
|
#include <linux/uaccess.h>
|
|
|
#include <linux/io.h>
|
|
|
+#include <linux/wait.h>
|
|
|
+#include <linux/poll.h>
|
|
|
#include "hpilo.h"
|
|
|
|
|
|
static struct class *ilo_class;
|
|
@@ -61,9 +64,10 @@ static inline int desc_mem_sz(int nr_entry)
|
|
|
static int fifo_enqueue(struct ilo_hwinfo *hw, char *fifobar, int entry)
|
|
|
{
|
|
|
struct fifo *fifo_q = FIFOBARTOHANDLE(fifobar);
|
|
|
+ unsigned long flags;
|
|
|
int ret = 0;
|
|
|
|
|
|
- spin_lock(&hw->fifo_lock);
|
|
|
+ spin_lock_irqsave(&hw->fifo_lock, flags);
|
|
|
if (!(fifo_q->fifobar[(fifo_q->tail + 1) & fifo_q->imask]
|
|
|
& ENTRY_MASK_O)) {
|
|
|
fifo_q->fifobar[fifo_q->tail & fifo_q->imask] |=
|
|
@@ -71,7 +75,7 @@ static int fifo_enqueue(struct ilo_hwinfo *hw, char *fifobar, int entry)
|
|
|
fifo_q->tail += 1;
|
|
|
ret = 1;
|
|
|
}
|
|
|
- spin_unlock(&hw->fifo_lock);
|
|
|
+ spin_unlock_irqrestore(&hw->fifo_lock, flags);
|
|
|
|
|
|
return ret;
|
|
|
}
|
|
@@ -79,10 +83,11 @@ static int fifo_enqueue(struct ilo_hwinfo *hw, char *fifobar, int entry)
|
|
|
static int fifo_dequeue(struct ilo_hwinfo *hw, char *fifobar, int *entry)
|
|
|
{
|
|
|
struct fifo *fifo_q = FIFOBARTOHANDLE(fifobar);
|
|
|
+ unsigned long flags;
|
|
|
int ret = 0;
|
|
|
u64 c;
|
|
|
|
|
|
- spin_lock(&hw->fifo_lock);
|
|
|
+ spin_lock_irqsave(&hw->fifo_lock, flags);
|
|
|
c = fifo_q->fifobar[fifo_q->head & fifo_q->imask];
|
|
|
if (c & ENTRY_MASK_C) {
|
|
|
if (entry)
|
|
@@ -93,7 +98,23 @@ static int fifo_dequeue(struct ilo_hwinfo *hw, char *fifobar, int *entry)
|
|
|
fifo_q->head += 1;
|
|
|
ret = 1;
|
|
|
}
|
|
|
- spin_unlock(&hw->fifo_lock);
|
|
|
+ spin_unlock_irqrestore(&hw->fifo_lock, flags);
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+static int fifo_check_recv(struct ilo_hwinfo *hw, char *fifobar)
|
|
|
+{
|
|
|
+ struct fifo *fifo_q = FIFOBARTOHANDLE(fifobar);
|
|
|
+ unsigned long flags;
|
|
|
+ int ret = 0;
|
|
|
+ u64 c;
|
|
|
+
|
|
|
+ spin_lock_irqsave(&hw->fifo_lock, flags);
|
|
|
+ c = fifo_q->fifobar[fifo_q->head & fifo_q->imask];
|
|
|
+ if (c & ENTRY_MASK_C)
|
|
|
+ ret = 1;
|
|
|
+ spin_unlock_irqrestore(&hw->fifo_lock, flags);
|
|
|
|
|
|
return ret;
|
|
|
}
|
|
@@ -142,6 +163,13 @@ static int ilo_pkt_dequeue(struct ilo_hwinfo *hw, struct ccb *ccb,
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+static int ilo_pkt_recv(struct ilo_hwinfo *hw, struct ccb *ccb)
|
|
|
+{
|
|
|
+ char *fifobar = ccb->ccb_u3.recv_fifobar;
|
|
|
+
|
|
|
+ return fifo_check_recv(hw, fifobar);
|
|
|
+}
|
|
|
+
|
|
|
static inline void doorbell_set(struct ccb *ccb)
|
|
|
{
|
|
|
iowrite8(1, ccb->ccb_u5.db_base);
|
|
@@ -151,6 +179,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 +189,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 +222,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 +252,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 +313,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 +337,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 +353,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,19 +375,45 @@ 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 inline void ilo_enable_interrupts(struct ilo_hwinfo *hw)
|
|
|
+{
|
|
|
+ iowrite8(ioread8(&hw->mmio_vaddr[DB_IRQ]) | 1, &hw->mmio_vaddr[DB_IRQ]);
|
|
|
}
|
|
|
|
|
|
-static void ilo_locked_reset(struct ilo_hwinfo *hw)
|
|
|
+static inline void ilo_disable_interrupts(struct ilo_hwinfo *hw)
|
|
|
+{
|
|
|
+ iowrite8(ioread8(&hw->mmio_vaddr[DB_IRQ]) & ~1,
|
|
|
+ &hw->mmio_vaddr[DB_IRQ]);
|
|
|
+}
|
|
|
+
|
|
|
+static void ilo_set_reset(struct ilo_hwinfo *hw)
|
|
|
{
|
|
|
int slot;
|
|
|
|
|
@@ -368,40 +426,22 @@ static void ilo_locked_reset(struct ilo_hwinfo *hw)
|
|
|
continue;
|
|
|
set_channel_reset(&hw->ccb_alloc[slot]->driver_ccb);
|
|
|
}
|
|
|
-
|
|
|
- clear_device(hw);
|
|
|
-}
|
|
|
-
|
|
|
-static void ilo_reset(struct ilo_hwinfo *hw)
|
|
|
-{
|
|
|
- spin_lock(&hw->alloc_lock);
|
|
|
-
|
|
|
- /* reset might have been handled after lock was taken */
|
|
|
- if (is_device_reset(hw))
|
|
|
- ilo_locked_reset(hw);
|
|
|
-
|
|
|
- spin_unlock(&hw->alloc_lock);
|
|
|
}
|
|
|
|
|
|
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 (is_channel_reset(driver_ccb)) {
|
|
|
/*
|
|
|
* If the device has been reset, applications
|
|
|
* need to close and reopen all ccbs.
|
|
|
*/
|
|
|
- ilo_reset(hw);
|
|
|
return -ENODEV;
|
|
|
}
|
|
|
|
|
@@ -442,23 +482,13 @@ 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
|
|
|
- * need to close and reopen all ccbs.
|
|
|
- */
|
|
|
- ilo_reset(hw);
|
|
|
+ if (is_channel_reset(driver_ccb))
|
|
|
return -ENODEV;
|
|
|
- }
|
|
|
|
|
|
/* get a packet to send the user command */
|
|
|
if (!ilo_pkt_dequeue(hw, driver_ccb, SENDQ, &pkt_id, &pkt_len, &pkt))
|
|
@@ -480,32 +510,48 @@ static ssize_t ilo_write(struct file *fp, const char __user *buf,
|
|
|
return err ? -EFAULT : len;
|
|
|
}
|
|
|
|
|
|
+static unsigned int ilo_poll(struct file *fp, poll_table *wait)
|
|
|
+{
|
|
|
+ struct ccb_data *data = fp->private_data;
|
|
|
+ struct ccb *driver_ccb = &data->driver_ccb;
|
|
|
+
|
|
|
+ poll_wait(fp, &data->ccb_waitq, wait);
|
|
|
+
|
|
|
+ if (is_channel_reset(driver_ccb))
|
|
|
+ return POLLERR;
|
|
|
+ else if (ilo_pkt_recv(data->ilo_hw, driver_ccb))
|
|
|
+ return POLLIN | POLLRDNORM;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
static int ilo_close(struct inode *ip, struct file *fp)
|
|
|
{
|
|
|
int slot;
|
|
|
struct ccb_data *data;
|
|
|
struct ilo_hwinfo *hw;
|
|
|
+ unsigned long flags;
|
|
|
|
|
|
slot = iminor(ip) % MAX_CCB;
|
|
|
hw = container_of(ip->i_cdev, struct ilo_hwinfo, cdev);
|
|
|
|
|
|
- spin_lock(&hw->alloc_lock);
|
|
|
-
|
|
|
- if (is_device_reset(hw))
|
|
|
- ilo_locked_reset(hw);
|
|
|
+ spin_lock(&hw->open_lock);
|
|
|
|
|
|
if (hw->ccb_alloc[slot]->ccb_cnt == 1) {
|
|
|
|
|
|
data = fp->private_data;
|
|
|
|
|
|
+ spin_lock_irqsave(&hw->alloc_lock, flags);
|
|
|
+ hw->ccb_alloc[slot] = NULL;
|
|
|
+ spin_unlock_irqrestore(&hw->alloc_lock, flags);
|
|
|
+
|
|
|
ilo_ccb_close(hw->ilo_dev, data);
|
|
|
|
|
|
kfree(data);
|
|
|
- hw->ccb_alloc[slot] = NULL;
|
|
|
} else
|
|
|
hw->ccb_alloc[slot]->ccb_cnt--;
|
|
|
|
|
|
- spin_unlock(&hw->alloc_lock);
|
|
|
+ spin_unlock(&hw->open_lock);
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
@@ -515,6 +561,7 @@ static int ilo_open(struct inode *ip, struct file *fp)
|
|
|
int slot, error;
|
|
|
struct ccb_data *data;
|
|
|
struct ilo_hwinfo *hw;
|
|
|
+ unsigned long flags;
|
|
|
|
|
|
slot = iminor(ip) % MAX_CCB;
|
|
|
hw = container_of(ip->i_cdev, struct ilo_hwinfo, cdev);
|
|
@@ -524,22 +571,42 @@ static int ilo_open(struct inode *ip, struct file *fp)
|
|
|
if (!data)
|
|
|
return -ENOMEM;
|
|
|
|
|
|
- spin_lock(&hw->alloc_lock);
|
|
|
-
|
|
|
- if (is_device_reset(hw))
|
|
|
- ilo_locked_reset(hw);
|
|
|
+ spin_lock(&hw->open_lock);
|
|
|
|
|
|
/* 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;
|
|
|
+ }
|
|
|
+
|
|
|
+ data->ccb_cnt = 1;
|
|
|
+ data->ccb_excl = fp->f_flags & O_EXCL;
|
|
|
+ data->ilo_hw = hw;
|
|
|
+ init_waitqueue_head(&data->ccb_waitq);
|
|
|
+
|
|
|
+ /* write the ccb to hw */
|
|
|
+ spin_lock_irqsave(&hw->alloc_lock, flags);
|
|
|
+ ilo_ccb_open(hw, data, slot);
|
|
|
+ hw->ccb_alloc[slot] = data;
|
|
|
+ spin_unlock_irqrestore(&hw->alloc_lock, flags);
|
|
|
+
|
|
|
+ /* make sure the channel is functional */
|
|
|
+ error = ilo_ccb_verify(hw, data);
|
|
|
+ if (error) {
|
|
|
+
|
|
|
+ spin_lock_irqsave(&hw->alloc_lock, flags);
|
|
|
+ hw->ccb_alloc[slot] = NULL;
|
|
|
+ spin_unlock_irqrestore(&hw->alloc_lock, flags);
|
|
|
+
|
|
|
+ ilo_ccb_close(hw->ilo_dev, data);
|
|
|
+
|
|
|
+ kfree(data);
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+
|
|
|
} else {
|
|
|
kfree(data);
|
|
|
if (fp->f_flags & O_EXCL || hw->ccb_alloc[slot]->ccb_excl) {
|
|
@@ -554,7 +621,8 @@ static int ilo_open(struct inode *ip, struct file *fp)
|
|
|
error = 0;
|
|
|
}
|
|
|
}
|
|
|
- spin_unlock(&hw->alloc_lock);
|
|
|
+out:
|
|
|
+ spin_unlock(&hw->open_lock);
|
|
|
|
|
|
if (!error)
|
|
|
fp->private_data = hw->ccb_alloc[slot];
|
|
@@ -566,10 +634,46 @@ static const struct file_operations ilo_fops = {
|
|
|
.owner = THIS_MODULE,
|
|
|
.read = ilo_read,
|
|
|
.write = ilo_write,
|
|
|
+ .poll = ilo_poll,
|
|
|
.open = ilo_open,
|
|
|
.release = ilo_close,
|
|
|
};
|
|
|
|
|
|
+static irqreturn_t ilo_isr(int irq, void *data)
|
|
|
+{
|
|
|
+ struct ilo_hwinfo *hw = data;
|
|
|
+ int pending, i;
|
|
|
+
|
|
|
+ spin_lock(&hw->alloc_lock);
|
|
|
+
|
|
|
+ /* check for ccbs which have data */
|
|
|
+ pending = get_device_outbound(hw);
|
|
|
+ if (!pending) {
|
|
|
+ spin_unlock(&hw->alloc_lock);
|
|
|
+ return IRQ_NONE;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (is_db_reset(pending)) {
|
|
|
+ /* wake up all ccbs if the device was reset */
|
|
|
+ pending = -1;
|
|
|
+ ilo_set_reset(hw);
|
|
|
+ }
|
|
|
+
|
|
|
+ for (i = 0; i < MAX_CCB; i++) {
|
|
|
+ if (!hw->ccb_alloc[i])
|
|
|
+ continue;
|
|
|
+ if (pending & (1 << i))
|
|
|
+ wake_up_interruptible(&hw->ccb_alloc[i]->ccb_waitq);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* clear the device of the channels that have been handled */
|
|
|
+ clear_pending_db(hw, pending);
|
|
|
+
|
|
|
+ spin_unlock(&hw->alloc_lock);
|
|
|
+
|
|
|
+ return IRQ_HANDLED;
|
|
|
+}
|
|
|
+
|
|
|
static void ilo_unmap_device(struct pci_dev *pdev, struct ilo_hwinfo *hw)
|
|
|
{
|
|
|
pci_iounmap(pdev, hw->db_vaddr);
|
|
@@ -623,6 +727,8 @@ static void ilo_remove(struct pci_dev *pdev)
|
|
|
device_destroy(ilo_class, MKDEV(ilo_major, i));
|
|
|
|
|
|
cdev_del(&ilo_hw->cdev);
|
|
|
+ ilo_disable_interrupts(ilo_hw);
|
|
|
+ free_irq(pdev->irq, ilo_hw);
|
|
|
ilo_unmap_device(pdev, ilo_hw);
|
|
|
pci_release_regions(pdev);
|
|
|
pci_disable_device(pdev);
|
|
@@ -658,6 +764,7 @@ static int __devinit ilo_probe(struct pci_dev *pdev,
|
|
|
ilo_hw->ilo_dev = pdev;
|
|
|
spin_lock_init(&ilo_hw->alloc_lock);
|
|
|
spin_lock_init(&ilo_hw->fifo_lock);
|
|
|
+ spin_lock_init(&ilo_hw->open_lock);
|
|
|
|
|
|
error = pci_enable_device(pdev);
|
|
|
if (error)
|
|
@@ -676,13 +783,19 @@ static int __devinit ilo_probe(struct pci_dev *pdev,
|
|
|
pci_set_drvdata(pdev, ilo_hw);
|
|
|
clear_device(ilo_hw);
|
|
|
|
|
|
+ error = request_irq(pdev->irq, ilo_isr, IRQF_SHARED, "hpilo", ilo_hw);
|
|
|
+ if (error)
|
|
|
+ goto unmap;
|
|
|
+
|
|
|
+ ilo_enable_interrupts(ilo_hw);
|
|
|
+
|
|
|
cdev_init(&ilo_hw->cdev, &ilo_fops);
|
|
|
ilo_hw->cdev.owner = THIS_MODULE;
|
|
|
start = devnum * MAX_CCB;
|
|
|
error = cdev_add(&ilo_hw->cdev, MKDEV(ilo_major, start), MAX_CCB);
|
|
|
if (error) {
|
|
|
dev_err(&pdev->dev, "Could not add cdev\n");
|
|
|
- goto unmap;
|
|
|
+ goto remove_isr;
|
|
|
}
|
|
|
|
|
|
for (minor = 0 ; minor < MAX_CCB; minor++) {
|
|
@@ -695,6 +808,9 @@ static int __devinit ilo_probe(struct pci_dev *pdev,
|
|
|
}
|
|
|
|
|
|
return 0;
|
|
|
+remove_isr:
|
|
|
+ ilo_disable_interrupts(ilo_hw);
|
|
|
+ free_irq(pdev->irq, ilo_hw);
|
|
|
unmap:
|
|
|
ilo_unmap_device(pdev, ilo_hw);
|
|
|
free_regions:
|
|
@@ -759,7 +875,7 @@ static void __exit ilo_exit(void)
|
|
|
class_destroy(ilo_class);
|
|
|
}
|
|
|
|
|
|
-MODULE_VERSION("1.1");
|
|
|
+MODULE_VERSION("1.2");
|
|
|
MODULE_ALIAS(ILO_NAME);
|
|
|
MODULE_DESCRIPTION(ILO_NAME);
|
|
|
MODULE_AUTHOR("David Altobelli <david.altobelli@hp.com>");
|