Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 162589
b: refs/heads/master
c: 9f70484
h: refs/heads/master
i:
  162587: 8d74729
v: v3
  • Loading branch information
David Altobelli authored and Greg Kroah-Hartman committed Sep 15, 2009
1 parent 9a9edca commit 4327215
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 46 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 66d5e5169c96f3e0175235e2bcbaedc8bc1c728f
refs/heads/master: 9f7048412163d8f8175ba01063f3db02d42cc6a7
138 changes: 94 additions & 44 deletions trunk/drivers/misc/hpilo.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand All @@ -21,6 +22,7 @@
#include <linux/delay.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/wait.h>
#include "hpilo.h"

static struct class *ilo_class;
Expand Down Expand Up @@ -61,28 +63,30 @@ 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] |=
(entry & ENTRY_MASK_NOSTATE) | fifo_q->merge;
fifo_q->tail += 1;
ret = 1;
}
spin_unlock(&hw->fifo_lock);
spin_unlock_irqrestore(&hw->fifo_lock, flags);

return ret;
}

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)
Expand All @@ -93,7 +97,7 @@ 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;
}
Expand Down Expand Up @@ -374,7 +378,18 @@ static inline void clear_device(struct ilo_hwinfo *hw)
clear_pending_db(hw, -1);
}

static void ilo_locked_reset(struct ilo_hwinfo *hw)
static inline void ilo_enable_interrupts(struct ilo_hwinfo *hw)
{
iowrite8(ioread8(&hw->mmio_vaddr[DB_IRQ]) | 1, &hw->mmio_vaddr[DB_IRQ]);
}

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;

Expand All @@ -387,19 +402,6 @@ 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,
Expand All @@ -411,12 +413,11 @@ static ssize_t ilo_read(struct file *fp, char __user *buf,
struct ilo_hwinfo *hw = data->ilo_hw;
void *pkt;

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;
}

Expand Down Expand Up @@ -462,14 +463,8 @@ static ssize_t ilo_write(struct file *fp, const char __user *buf,
struct ilo_hwinfo *hw = data->ilo_hw;
void *pkt;

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))
Expand All @@ -496,27 +491,28 @@ 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;
}
Expand All @@ -526,6 +522,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);
Expand All @@ -535,10 +532,7 @@ 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) {
Expand All @@ -549,22 +543,31 @@ static int ilo_open(struct inode *ip, struct file *fp)
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;
}

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 @@ -580,7 +583,7 @@ static int ilo_open(struct inode *ip, struct file *fp)
}
}
out:
spin_unlock(&hw->alloc_lock);
spin_unlock(&hw->open_lock);

if (!error)
fp->private_data = hw->ccb_alloc[slot];
Expand All @@ -596,6 +599,41 @@ static const struct file_operations ilo_fops = {
.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);
Expand Down Expand Up @@ -649,6 +687,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);
Expand Down Expand Up @@ -684,6 +724,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)
Expand All @@ -702,13 +743,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++) {
Expand All @@ -721,6 +768,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:
Expand Down
8 changes: 7 additions & 1 deletion trunk/drivers/misc/hpilo.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,14 @@ struct ilo_hwinfo {

spinlock_t alloc_lock;
spinlock_t fifo_lock;
spinlock_t open_lock;

struct cdev cdev;
};

/* offset from mmio_vaddr */
/* offset from mmio_vaddr for enabling doorbell interrupts */
#define DB_IRQ 0xB2
/* offset from mmio_vaddr for outbound communications */
#define DB_OUT 0xD4
/* DB_OUT reset bit */
#define DB_RESET 26
Expand Down Expand Up @@ -131,6 +134,9 @@ struct ccb_data {
/* pointer to hardware device info */
struct ilo_hwinfo *ilo_hw;

/* queue for this ccb to wait for recv data */
wait_queue_head_t ccb_waitq;

/* usage count, to allow for shared ccb's */
int ccb_cnt;

Expand Down

0 comments on commit 4327215

Please sign in to comment.