Commit e4e1da06 authored by David Altobelli's avatar David Altobelli Committed by Stephen Rothwell

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: default avatarDavid Altobelli <david.altobelli@hp.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 2e2cd755
...@@ -151,6 +151,7 @@ static inline void doorbell_clr(struct ccb *ccb) ...@@ -151,6 +151,7 @@ static inline void doorbell_clr(struct ccb *ccb)
{ {
iowrite8(2, ccb->ccb_u5.db_base); iowrite8(2, ccb->ccb_u5.db_base);
} }
static inline int ctrl_set(int l2sz, int idxmask, int desclim) static inline int ctrl_set(int l2sz, int idxmask, int desclim)
{ {
int active = 0, go = 1; int active = 0, go = 1;
...@@ -160,6 +161,7 @@ static inline int ctrl_set(int l2sz, int idxmask, int desclim) ...@@ -160,6 +161,7 @@ static inline int ctrl_set(int l2sz, int idxmask, int desclim)
active << CTRL_BITPOS_A | active << CTRL_BITPOS_A |
go << CTRL_BITPOS_G; go << CTRL_BITPOS_G;
} }
static void ctrl_setup(struct ccb *ccb, int nr_desc, int l2desc_sz) static void ctrl_setup(struct ccb *ccb, int nr_desc, int l2desc_sz)
{ {
/* for simplicity, use the same parameters for send and recv ctrls */ /* 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) ...@@ -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) static void ilo_ccb_close(struct pci_dev *pdev, struct ccb_data *data)
{ {
struct ccb *driver_ccb; struct ccb *driver_ccb = &data->driver_ccb;
struct ccb __iomem *device_ccb; struct ccb __iomem *device_ccb = data->mapped_ccb;
int retries; int retries;
driver_ccb = &data->driver_ccb;
device_ccb = data->mapped_ccb;
/* complicated dance to tell the hw we are stopping */ /* complicated dance to tell the hw we are stopping */
doorbell_clr(driver_ccb); doorbell_clr(driver_ccb);
iowrite32(ioread32(&device_ccb->send_ctrl) & ~(1 << CTRL_BITPOS_G), 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) ...@@ -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); 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; char *dma_va, *dma_pa;
int pkt_id, pkt_sz, i, error;
struct ccb *driver_ccb, *ilo_ccb; struct ccb *driver_ccb, *ilo_ccb;
struct pci_dev *pdev;
driver_ccb = &data->driver_ccb; driver_ccb = &data->driver_ccb;
ilo_ccb = &data->ilo_ccb; ilo_ccb = &data->ilo_ccb;
pdev = hw->ilo_dev;
data->dma_size = 2 * fifo_sz(NR_QENTRY) + data->dma_size = 2 * fifo_sz(NR_QENTRY) +
2 * desc_mem_sz(NR_QENTRY) + 2 * desc_mem_sz(NR_QENTRY) +
ILO_START_ALIGN + ILO_CACHE_SZ; ILO_START_ALIGN + ILO_CACHE_SZ;
error = -ENOMEM; data->dma_va = pci_alloc_consistent(hw->ilo_dev, data->dma_size,
data->dma_va = pci_alloc_consistent(pdev, data->dma_size,
&data->dma_pa); &data->dma_pa);
if (!data->dma_va) if (!data->dma_va)
goto out; return -ENOMEM;
dma_va = (char *)data->dma_va; dma_va = (char *)data->dma_va;
dma_pa = (char *)data->dma_pa; 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) ...@@ -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); 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 */ 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 */ /* copy the ccb with physical addrs to device memory */
data->mapped_ccb = (struct ccb __iomem *) data->mapped_ccb = (struct ccb __iomem *)
(hw->ram_vaddr + (slot * ILOHW_CCB_SZ)); (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 */ /* put packets on the send and receive queues */
pkt_sz = 0; pkt_sz = 0;
...@@ -306,7 +309,14 @@ static int ilo_ccb_open(struct ilo_hwinfo *hw, struct ccb_data *data, int slot) ...@@ -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++) for (pkt_id = 0; pkt_id < NR_QENTRY; pkt_id++)
ilo_pkt_enqueue(hw, driver_ccb, RECVQ, pkt_id, pkt_sz); ilo_pkt_enqueue(hw, driver_ccb, RECVQ, pkt_id, pkt_sz);
/* the ccb is ready to use */
doorbell_clr(driver_ccb); 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 */ /* make sure iLO is really handling requests */
for (i = MAX_WAIT; i > 0; i--) { 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) ...@@ -315,20 +325,14 @@ static int ilo_ccb_open(struct ilo_hwinfo *hw, struct ccb_data *data, int slot)
udelay(WAIT_TIME); udelay(WAIT_TIME);
} }
if (i) { if (i == 0) {
ilo_pkt_enqueue(hw, driver_ccb, SENDQ, pkt_id, 0); dev_err(&hw->ilo_dev->dev, "Open could not dequeue a packet\n");
doorbell_set(driver_ccb); return -EBUSY;
} else {
dev_err(&pdev->dev, "Open could not dequeue a packet\n");
error = -EBUSY;
goto free;
} }
ilo_pkt_enqueue(hw, driver_ccb, SENDQ, pkt_id, 0);
doorbell_set(driver_ccb);
return 0; return 0;
free:
ilo_ccb_close(pdev, data);
out:
return error;
} }
static inline int is_channel_reset(struct ccb *ccb) static inline int is_channel_reset(struct ccb *ccb)
...@@ -343,16 +347,31 @@ static inline void set_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; 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) static inline int is_device_reset(struct ilo_hwinfo *hw)
{ {
/* check for global reset condition */ /* 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) static inline void clear_device(struct ilo_hwinfo *hw)
{ {
/* clear the device (reset bits, pending channel entries) */ /* 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) static void ilo_locked_reset(struct ilo_hwinfo *hw)
...@@ -387,15 +406,11 @@ static ssize_t ilo_read(struct file *fp, char __user *buf, ...@@ -387,15 +406,11 @@ static ssize_t ilo_read(struct file *fp, char __user *buf,
size_t len, loff_t *off) size_t len, loff_t *off)
{ {
int err, found, cnt, pkt_id, pkt_len; int err, found, cnt, pkt_id, pkt_len;
struct ccb_data *data; struct ccb_data *data = fp->private_data;
struct ccb *driver_ccb; struct ccb *driver_ccb = &data->driver_ccb;
struct ilo_hwinfo *hw; struct ilo_hwinfo *hw = data->ilo_hw;
void *pkt; 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_device_reset(hw) || is_channel_reset(driver_ccb)) {
/* /*
* If the device has been reset, applications * If the device has been reset, applications
...@@ -442,15 +457,11 @@ static ssize_t ilo_write(struct file *fp, const char __user *buf, ...@@ -442,15 +457,11 @@ static ssize_t ilo_write(struct file *fp, const char __user *buf,
size_t len, loff_t *off) size_t len, loff_t *off)
{ {
int err, pkt_id, pkt_len; int err, pkt_id, pkt_len;
struct ccb_data *data; struct ccb_data *data = fp->private_data;
struct ccb *driver_ccb; struct ccb *driver_ccb = &data->driver_ccb;
struct ilo_hwinfo *hw; struct ilo_hwinfo *hw = data->ilo_hw;
void *pkt; 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_device_reset(hw) || is_channel_reset(driver_ccb)) {
/* /*
* If the device has been reset, applications * If the device has been reset, applications
...@@ -532,14 +543,28 @@ static int ilo_open(struct inode *ip, struct file *fp) ...@@ -532,14 +543,28 @@ static int ilo_open(struct inode *ip, struct file *fp)
/* each fd private_data holds sw/hw view of ccb */ /* each fd private_data holds sw/hw view of ccb */
if (hw->ccb_alloc[slot] == NULL) { if (hw->ccb_alloc[slot] == NULL) {
/* create a channel control block for this minor */ /* create a channel control block for this minor */
error = ilo_ccb_open(hw, data, slot); error = ilo_ccb_setup(hw, data, slot);
if (!error) { if (error) {
hw->ccb_alloc[slot] = data; kfree(data);
hw->ccb_alloc[slot]->ccb_cnt = 1; goto out;
hw->ccb_alloc[slot]->ccb_excl = fp->f_flags & O_EXCL; }
hw->ccb_alloc[slot]->ilo_hw = hw;
} else /* 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); 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 { } else {
kfree(data); kfree(data);
if (fp->f_flags & O_EXCL || hw->ccb_alloc[slot]->ccb_excl) { 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) ...@@ -554,6 +579,7 @@ static int ilo_open(struct inode *ip, struct file *fp)
error = 0; error = 0;
} }
} }
out:
spin_unlock(&hw->alloc_lock); spin_unlock(&hw->alloc_lock);
if (!error) if (!error)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment