Commit 076802d0 authored by Alexander Usyskin's avatar Alexander Usyskin Committed by Greg Kroah-Hartman

mei: bus: enable non-blocking RX

Enable non-blocking receive for drivers on mei bus, this allows checking
for data availability by mei client drivers. This is most effective for
fixed address clients, that lacks flow control.

This function adds new API function mei_cldev_recv_nonblock(), it
retuns -EGAIN if function will block.
Signed-off-by: default avatarAlexander Usyskin <alexander.usyskin@intel.com>
Signed-off-by: default avatarTomas Winkler <tomas.winkler@intel.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent a2eb0fc0
...@@ -141,7 +141,7 @@ static int mei_osver(struct mei_cl_device *cldev) ...@@ -141,7 +141,7 @@ static int mei_osver(struct mei_cl_device *cldev)
if (ret < 0) if (ret < 0)
return ret; return ret;
ret = __mei_cl_recv(cldev->cl, buf, length); ret = __mei_cl_recv(cldev->cl, buf, length, 0);
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -272,7 +272,7 @@ static int mei_nfc_if_version(struct mei_cl *cl, ...@@ -272,7 +272,7 @@ static int mei_nfc_if_version(struct mei_cl *cl,
return -ENOMEM; return -ENOMEM;
ret = 0; ret = 0;
bytes_recv = __mei_cl_recv(cl, (u8 *)reply, if_version_length); bytes_recv = __mei_cl_recv(cl, (u8 *)reply, if_version_length, 0);
if (bytes_recv < if_version_length) { if (bytes_recv < if_version_length) {
dev_err(bus->dev, "Could not read IF version\n"); dev_err(bus->dev, "Could not read IF version\n");
ret = -EIO; ret = -EIO;
......
...@@ -98,15 +98,18 @@ ssize_t __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length, ...@@ -98,15 +98,18 @@ ssize_t __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length,
* @cl: host client * @cl: host client
* @buf: buffer to receive * @buf: buffer to receive
* @length: buffer length * @length: buffer length
* @mode: io mode
* *
* Return: read size in bytes of < 0 on error * Return: read size in bytes of < 0 on error
*/ */
ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length) ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length,
unsigned int mode)
{ {
struct mei_device *bus; struct mei_device *bus;
struct mei_cl_cb *cb; struct mei_cl_cb *cb;
size_t r_length; size_t r_length;
ssize_t rets; ssize_t rets;
bool nonblock = !!(mode & MEI_CL_IO_RX_NONBLOCK);
if (WARN_ON(!cl || !cl->dev)) if (WARN_ON(!cl || !cl->dev))
return -ENODEV; return -ENODEV;
...@@ -127,6 +130,11 @@ ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length) ...@@ -127,6 +130,11 @@ ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length)
if (rets && rets != -EBUSY) if (rets && rets != -EBUSY)
goto out; goto out;
if (nonblock) {
rets = -EAGAIN;
goto out;
}
/* wait on event only if there is no other waiter */ /* wait on event only if there is no other waiter */
/* synchronized under device mutex */ /* synchronized under device mutex */
if (!waitqueue_active(&cl->rx_wait)) { if (!waitqueue_active(&cl->rx_wait)) {
...@@ -191,6 +199,25 @@ ssize_t mei_cldev_send(struct mei_cl_device *cldev, u8 *buf, size_t length) ...@@ -191,6 +199,25 @@ ssize_t mei_cldev_send(struct mei_cl_device *cldev, u8 *buf, size_t length)
} }
EXPORT_SYMBOL_GPL(mei_cldev_send); EXPORT_SYMBOL_GPL(mei_cldev_send);
/**
* mei_cldev_recv_nonblock - non block client receive (read)
*
* @cldev: me client device
* @buf: buffer to receive
* @length: buffer length
*
* Return: read size in bytes of < 0 on error
* -EAGAIN if function will block.
*/
ssize_t mei_cldev_recv_nonblock(struct mei_cl_device *cldev, u8 *buf,
size_t length)
{
struct mei_cl *cl = cldev->cl;
return __mei_cl_recv(cl, buf, length, MEI_CL_IO_RX_NONBLOCK);
}
EXPORT_SYMBOL_GPL(mei_cldev_recv_nonblock);
/** /**
* mei_cldev_recv - client receive (read) * mei_cldev_recv - client receive (read)
* *
...@@ -204,7 +231,7 @@ ssize_t mei_cldev_recv(struct mei_cl_device *cldev, u8 *buf, size_t length) ...@@ -204,7 +231,7 @@ ssize_t mei_cldev_recv(struct mei_cl_device *cldev, u8 *buf, size_t length)
{ {
struct mei_cl *cl = cldev->cl; struct mei_cl *cl = cldev->cl;
return __mei_cl_recv(cl, buf, length); return __mei_cl_recv(cl, buf, length, 0);
} }
EXPORT_SYMBOL_GPL(mei_cldev_recv); EXPORT_SYMBOL_GPL(mei_cldev_recv);
......
...@@ -115,10 +115,14 @@ enum mei_cb_file_ops { ...@@ -115,10 +115,14 @@ enum mei_cb_file_ops {
* *
* @MEI_CL_IO_TX_BLOCKING: send is blocking * @MEI_CL_IO_TX_BLOCKING: send is blocking
* @MEI_CL_IO_TX_INTERNAL: internal communication between driver and FW * @MEI_CL_IO_TX_INTERNAL: internal communication between driver and FW
*
* @MEI_CL_IO_RX_NONBLOCK: recv is non-blocking
*/ */
enum mei_cl_io_mode { enum mei_cl_io_mode {
MEI_CL_IO_TX_BLOCKING = BIT(0), MEI_CL_IO_TX_BLOCKING = BIT(0),
MEI_CL_IO_TX_INTERNAL = BIT(1), MEI_CL_IO_TX_INTERNAL = BIT(1),
MEI_CL_IO_RX_NONBLOCK = BIT(2),
}; };
/* /*
...@@ -319,7 +323,8 @@ void mei_cl_bus_rescan_work(struct work_struct *work); ...@@ -319,7 +323,8 @@ void mei_cl_bus_rescan_work(struct work_struct *work);
void mei_cl_bus_dev_fixup(struct mei_cl_device *dev); void mei_cl_bus_dev_fixup(struct mei_cl_device *dev);
ssize_t __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length, ssize_t __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length,
unsigned int mode); unsigned int mode);
ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length); ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length,
unsigned int mode);
bool mei_cl_bus_rx_event(struct mei_cl *cl); bool mei_cl_bus_rx_event(struct mei_cl *cl);
bool mei_cl_bus_notify_event(struct mei_cl *cl); bool mei_cl_bus_notify_event(struct mei_cl *cl);
void mei_cl_bus_remove_devices(struct mei_device *bus); void mei_cl_bus_remove_devices(struct mei_device *bus);
......
...@@ -75,7 +75,7 @@ void mei_cldev_driver_unregister(struct mei_cl_driver *cldrv); ...@@ -75,7 +75,7 @@ void mei_cldev_driver_unregister(struct mei_cl_driver *cldrv);
/** /**
* module_mei_cl_driver - Helper macro for registering mei cl driver * module_mei_cl_driver - Helper macro for registering mei cl driver
* *
* @__mei_cldrv mei_cl_driver structure * @__mei_cldrv: mei_cl_driver structure
* *
* Helper macro for mei cl drivers which do not do anything special in module * Helper macro for mei cl drivers which do not do anything special in module
* init/exit, for eliminating a boilerplate code. * init/exit, for eliminating a boilerplate code.
...@@ -86,7 +86,9 @@ void mei_cldev_driver_unregister(struct mei_cl_driver *cldrv); ...@@ -86,7 +86,9 @@ void mei_cldev_driver_unregister(struct mei_cl_driver *cldrv);
mei_cldev_driver_unregister) mei_cldev_driver_unregister)
ssize_t mei_cldev_send(struct mei_cl_device *cldev, u8 *buf, size_t length); ssize_t mei_cldev_send(struct mei_cl_device *cldev, u8 *buf, size_t length);
ssize_t mei_cldev_recv(struct mei_cl_device *cldev, u8 *buf, size_t length); ssize_t mei_cldev_recv(struct mei_cl_device *cldev, u8 *buf, size_t length);
ssize_t mei_cldev_recv_nonblock(struct mei_cl_device *cldev, u8 *buf,
size_t length);
int mei_cldev_register_rx_cb(struct mei_cl_device *cldev, mei_cldev_cb_t rx_cb); int mei_cldev_register_rx_cb(struct mei_cl_device *cldev, mei_cldev_cb_t rx_cb);
int mei_cldev_register_notif_cb(struct mei_cl_device *cldev, int mei_cldev_register_notif_cb(struct mei_cl_device *cldev,
......
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