Skip to content

Commit

Permalink
hpilo: staging for interrupt handling
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
David Altobelli authored and Greg Kroah-Hartman committed Sep 15, 2009
1 parent daa4122 commit 66d5e51
Showing 1 changed file with 73 additions and 47 deletions.
120 changes: 73 additions & 47 deletions drivers/misc/hpilo.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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 */
Expand Down Expand Up @@ -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),
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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--) {
Expand All @@ -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)
Expand All @@ -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)
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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) {
Expand All @@ -554,6 +579,7 @@ static int ilo_open(struct inode *ip, struct file *fp)
error = 0;
}
}
out:
spin_unlock(&hw->alloc_lock);

if (!error)
Expand Down

0 comments on commit 66d5e51

Please sign in to comment.