[POWERPC] PS3: Vuart add async read
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>
This commit is contained in:
parent
75c86e7422
commit
ea1547d311
2 changed files with 78 additions and 4 deletions
|
@ -21,6 +21,7 @@
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/workqueue.h>
|
||||||
#include <asm/ps3.h>
|
#include <asm/ps3.h>
|
||||||
|
|
||||||
#include <asm/firmware.h>
|
#include <asm/firmware.h>
|
||||||
|
@ -567,6 +568,44 @@ int ps3_vuart_read(struct ps3_vuart_port_device *dev, void* buf,
|
||||||
return 0;
|
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
|
* ps3_vuart_handle_interrupt_tx - third stage transmit interrupt handler
|
||||||
*
|
*
|
||||||
|
@ -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",
|
dev_dbg(&dev->core, "%s:%d: buf_%lu: queued %lxh bytes\n",
|
||||||
__func__, __LINE__, lb->dbg_number, bytes);
|
__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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -839,6 +887,11 @@ static int ps3_vuart_probe(struct device *_dev)
|
||||||
INIT_LIST_HEAD(&dev->priv->rx_list.head);
|
INIT_LIST_HEAD(&dev->priv->rx_list.head);
|
||||||
spin_lock_init(&dev->priv->rx_list.lock);
|
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) {
|
if (++vuart_bus_priv.use_count == 1) {
|
||||||
|
|
||||||
result = ps3_alloc_vuart_irq(PS3_BINDING_CPU_ANY,
|
result = ps3_alloc_vuart_irq(PS3_BINDING_CPU_ANY,
|
||||||
|
|
|
@ -31,6 +31,13 @@ struct ps3_vuart_stats {
|
||||||
unsigned long disconnect_interrupts;
|
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.
|
* struct ps3_vuart_port_priv - private vuart device data.
|
||||||
*/
|
*/
|
||||||
|
@ -49,6 +56,7 @@ struct ps3_vuart_port_priv {
|
||||||
struct list_head head;
|
struct list_head head;
|
||||||
} rx_list;
|
} rx_list;
|
||||||
struct ps3_vuart_stats stats;
|
struct ps3_vuart_stats stats;
|
||||||
|
struct ps3_vuart_work work;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -71,10 +79,6 @@ struct ps3_vuart_port_driver {
|
||||||
int ps3_vuart_port_driver_register(struct ps3_vuart_port_driver *drv);
|
int ps3_vuart_port_driver_register(struct ps3_vuart_port_driver *drv);
|
||||||
void ps3_vuart_port_driver_unregister(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(
|
static inline struct ps3_vuart_port_driver *to_ps3_vuart_port_driver(
|
||||||
struct device_driver *_drv)
|
struct device_driver *_drv)
|
||||||
{
|
{
|
||||||
|
@ -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);
|
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
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue