Skip to content

Commit

Permalink
[POWERPC] PS3: Vuart add async read
Browse files Browse the repository at this point in the history
Add asynchronous read support to the PS3 vuart driver.  This is needed to
support the PS3 system manager driver.

Signed-off-by: Geoff Levand <geoffrey.levand@am.sony.com>
Signed-off-by: Paul Mackerras <paulus@samba.org>
  • Loading branch information
Geoff Levand authored and paulusmack committed Feb 16, 2007
1 parent 75c86e7 commit ea1547d
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 4 deletions.
53 changes: 53 additions & 0 deletions drivers/ps3/vuart.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/workqueue.h>
#include <asm/ps3.h>

#include <asm/firmware.h>
Expand Down Expand Up @@ -567,6 +568,44 @@ int ps3_vuart_read(struct ps3_vuart_port_device *dev, void* buf,
return 0;
}

int ps3_vuart_read_async(struct ps3_vuart_port_device *dev, work_func_t func,
unsigned int bytes)
{
unsigned long flags;

if(dev->priv->work.trigger) {
dev_dbg(&dev->core, "%s:%d: warning, multiple calls\n",
__func__, __LINE__);
return -EAGAIN;
}

BUG_ON(!bytes);

PREPARE_WORK(&dev->priv->work.work, func);

spin_lock_irqsave(&dev->priv->work.lock, flags);
if(dev->priv->rx_list.bytes_held >= bytes) {
dev_dbg(&dev->core, "%s:%d: schedule_work %xh bytes\n",
__func__, __LINE__, bytes);
schedule_work(&dev->priv->work.work);
spin_unlock_irqrestore(&dev->priv->work.lock, flags);
return 0;
}

dev->priv->work.trigger = bytes;
spin_unlock_irqrestore(&dev->priv->work.lock, flags);

dev_dbg(&dev->core, "%s:%d: waiting for %u(%xh) bytes\n", __func__,
__LINE__, bytes, bytes);

return 0;
}

void ps3_vuart_cancel_async(struct ps3_vuart_port_device *dev)
{
dev->priv->work.trigger = 0;
}

/**
* ps3_vuart_handle_interrupt_tx - third stage transmit interrupt handler
*
Expand Down Expand Up @@ -674,6 +713,15 @@ static int ps3_vuart_handle_interrupt_rx(struct ps3_vuart_port_device *dev)
dev_dbg(&dev->core, "%s:%d: buf_%lu: queued %lxh bytes\n",
__func__, __LINE__, lb->dbg_number, bytes);

spin_lock_irqsave(&dev->priv->work.lock, flags);
if(dev->priv->work.trigger
&& dev->priv->rx_list.bytes_held >= dev->priv->work.trigger) {
dev_dbg(&dev->core, "%s:%d: schedule_work %lxh bytes\n",
__func__, __LINE__, dev->priv->work.trigger);
dev->priv->work.trigger = 0;
schedule_work(&dev->priv->work.work);
}
spin_unlock_irqrestore(&dev->priv->work.lock, flags);
return 0;
}

Expand Down Expand Up @@ -839,6 +887,11 @@ static int ps3_vuart_probe(struct device *_dev)
INIT_LIST_HEAD(&dev->priv->rx_list.head);
spin_lock_init(&dev->priv->rx_list.lock);

INIT_WORK(&dev->priv->work.work, NULL);
spin_lock_init(&dev->priv->work.lock);
dev->priv->work.trigger = 0;
dev->priv->work.dev = dev;

if (++vuart_bus_priv.use_count == 1) {

result = ps3_alloc_vuart_irq(PS3_BINDING_CPU_ANY,
Expand Down
29 changes: 25 additions & 4 deletions drivers/ps3/vuart.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,13 @@ struct ps3_vuart_stats {
unsigned long disconnect_interrupts;
};

struct ps3_vuart_work {
struct work_struct work;
unsigned long trigger;
spinlock_t lock;
struct ps3_vuart_port_device* dev; /* to convert work to device */
};

/**
* struct ps3_vuart_port_priv - private vuart device data.
*/
Expand All @@ -49,6 +56,7 @@ struct ps3_vuart_port_priv {
struct list_head head;
} rx_list;
struct ps3_vuart_stats stats;
struct ps3_vuart_work work;
};

/**
Expand All @@ -71,10 +79,6 @@ struct ps3_vuart_port_driver {
int ps3_vuart_port_driver_register(struct ps3_vuart_port_driver *drv);
void ps3_vuart_port_driver_unregister(struct ps3_vuart_port_driver *drv);

int ps3_vuart_write(struct ps3_vuart_port_device *dev,
const void* buf, unsigned int bytes);
int ps3_vuart_read(struct ps3_vuart_port_device *dev, void* buf,
unsigned int bytes);
static inline struct ps3_vuart_port_driver *to_ps3_vuart_port_driver(
struct device_driver *_drv)
{
Expand All @@ -85,5 +89,22 @@ static inline struct ps3_vuart_port_device *to_ps3_vuart_port_device(
{
return container_of(_dev, struct ps3_vuart_port_device, core);
}
static inline struct ps3_vuart_port_device *ps3_vuart_work_to_port_device(
struct work_struct *_work)
{
struct ps3_vuart_work *vw = container_of(_work, struct ps3_vuart_work,
work);
return vw->dev;
}

int ps3_vuart_write(struct ps3_vuart_port_device *dev, const void* buf,
unsigned int bytes);
int ps3_vuart_read(struct ps3_vuart_port_device *dev, void* buf,
unsigned int bytes);
int ps3_vuart_read_async(struct ps3_vuart_port_device *dev, work_func_t func,
unsigned int bytes);
void ps3_vuart_cancel_async(struct ps3_vuart_port_device *dev);
void ps3_vuart_clear_rx_bytes(struct ps3_vuart_port_device *dev,
unsigned int bytes);

#endif

0 comments on commit ea1547d

Please sign in to comment.