All of lore.kernel.org
 help / color / mirror / Atom feed
* [char-misc-next 0/9 RESEND] mei: support for async event notifications
@ 2015-07-26  6:54 Tomas Winkler
  2015-07-26  6:54 ` [char-misc-next 1/9 RESEND] mei: define async notification hbm commands Tomas Winkler
                   ` (9 more replies)
  0 siblings, 10 replies; 14+ messages in thread
From: Tomas Winkler @ 2015-07-26  6:54 UTC (permalink / raw)
  To: Greg Kroah-Hartman; +Cc: arnd, Alexander Usyskin, linux-kernel, Tomas Winkler

FW has gained new capability where a FW client can asynchronously
notify the host that an event has occurred in its process.
The notification doesn't provide any data and host may need to query
further the FW client in order to get details of the event.
New IOCTLs are introduced for the user space to enable/disable
and consume the event notifications.
The asynchronous nature is provided via poll and fasync.


Alexander Usyskin (1):
  mei: bus: add and call callback on notify event

Tomas Winkler (8):
  mei: define async notification hbm commands
  mei: implement async notification hbm messages
  mei: enable async event notifications only from hbm version 2.0
  mei: add mei_cl_notify_request command
  mei: add a handler that waits for notification on event
  mei: add async event notification ioctls
  mei: support polling for event notification
  mei: implement fasync for event notification

 Documentation/ioctl/ioctl-number.txt   |   2 +
 Documentation/misc-devices/mei/mei.txt |  45 ++++++-
 drivers/misc/mei/bus.c                 |  50 +++++++-
 drivers/misc/mei/client.c              | 224 +++++++++++++++++++++++++++++++++
 drivers/misc/mei/client.h              |   8 ++
 drivers/misc/mei/debugfs.c             |   2 +
 drivers/misc/mei/hbm.c                 | 136 ++++++++++++++++++++
 drivers/misc/mei/hbm.h                 |   2 +
 drivers/misc/mei/hw.h                  |  68 ++++++++++
 drivers/misc/mei/interrupt.c           |   7 ++
 drivers/misc/mei/main.c                |  96 ++++++++++++++
 drivers/misc/mei/mei_dev.h             |  15 +++
 drivers/nfc/mei_phy.c                  |   3 +-
 include/linux/mei_cl_bus.h             |   4 +
 include/uapi/linux/mei.h               |  19 +++
 15 files changed, 675 insertions(+), 6 deletions(-)

-- 
2.4.3


^ permalink raw reply	[flat|nested] 14+ messages in thread

* [char-misc-next 1/9 RESEND] mei: define async notification hbm commands
  2015-07-26  6:54 [char-misc-next 0/9 RESEND] mei: support for async event notifications Tomas Winkler
@ 2015-07-26  6:54 ` Tomas Winkler
  2015-07-26  6:54 ` [char-misc-next 2/9 RESEND] mei: implement async notification hbm messages Tomas Winkler
                   ` (8 subsequent siblings)
  9 siblings, 0 replies; 14+ messages in thread
From: Tomas Winkler @ 2015-07-26  6:54 UTC (permalink / raw)
  To: Greg Kroah-Hartman; +Cc: arnd, Alexander Usyskin, linux-kernel, Tomas Winkler

FW has gained new capability where a FW client can asynchronously
notify the host that an event has occurred in its process.
The notification doesn't provide any data and host may need to query
further the FW client in order to get details of the event.
Host can subscribe or unsubscribe to the event notification via
designated HBM commands, and also the notification is carried on
a new HBM command.
This patch adds definitions of asynchronous notification HBM commands.

Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
 drivers/misc/mei/hw.h | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 62 insertions(+)

diff --git a/drivers/misc/mei/hw.h b/drivers/misc/mei/hw.h
index e961be392fae..a2c7aaba25d4 100644
--- a/drivers/misc/mei/hw.h
+++ b/drivers/misc/mei/hw.h
@@ -95,6 +95,11 @@
 
 #define MEI_HBM_ADD_CLIENT_REQ_CMD          0x0f
 #define MEI_HBM_ADD_CLIENT_RES_CMD          0x8f
+
+#define MEI_HBM_NOTIFY_REQ_CMD              0x10
+#define MEI_HBM_NOTIFY_RES_CMD              0x90
+#define MEI_HBM_NOTIFICATION_CMD            0x11
+
 /*
  * MEI Stop Reason
  * used by hbm_host_stop_request.reason
@@ -352,5 +357,62 @@ struct hbm_flow_control {
 	u8 reserved[MEI_FC_MESSAGE_RESERVED_LENGTH];
 } __packed;
 
+#define MEI_HBM_NOTIFICATION_START 1
+#define MEI_HBM_NOTIFICATION_STOP  0
+/**
+ * struct hbm_notification_request - start/stop notification request
+ *
+ * @hbm_cmd: bus message command header
+ * @me_addr: address of the client in ME
+ * @host_addr: address of the client in the driver
+ * @start:  start = 1 or stop = 0 asynchronous notifications
+ */
+struct hbm_notification_request {
+	u8 hbm_cmd;
+	u8 me_addr;
+	u8 host_addr;
+	u8 start;
+} __packed;
+
+/**
+ * struct hbm_notification_response - start/stop notification response
+ *
+ * @hbm_cmd: bus message command header
+ * @me_addr: address of the client in ME
+ * @host_addr: - address of the client in the driver
+ * @status: (mei_hbm_status) response status for the request
+ *  - MEI_HBMS_SUCCESS: successful stop/start
+ *  - MEI_HBMS_CLIENT_NOT_FOUND: if the connection could not be found.
+ *  - MEI_HBMS_ALREADY_STARTED: for start requests for a previously
+ *                         started notification.
+ *  - MEI_HBMS_NOT_STARTED: for stop request for a connected client for whom
+ *                         asynchronous notifications are currently disabled.
+ *
+ * @start:  start = 1 or stop = 0 asynchronous notifications
+ * @reserved: reserved
+ */
+struct hbm_notification_response {
+	u8 hbm_cmd;
+	u8 me_addr;
+	u8 host_addr;
+	u8 status;
+	u8 start;
+	u8 reserved[3];
+} __packed;
+
+/**
+ * struct hbm_notification - notification event
+ *
+ * @hbm_cmd: bus message command header
+ * @me_addr:  address of the client in ME
+ * @host_addr:  address of the client in the driver
+ * @reserved: reserved for alignment
+ */
+struct hbm_notification {
+	u8 hbm_cmd;
+	u8 me_addr;
+	u8 host_addr;
+	u8 reserved[1];
+} __packed;
 
 #endif
-- 
2.4.3


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [char-misc-next 2/9 RESEND] mei: implement async notification hbm messages
  2015-07-26  6:54 [char-misc-next 0/9 RESEND] mei: support for async event notifications Tomas Winkler
  2015-07-26  6:54 ` [char-misc-next 1/9 RESEND] mei: define async notification hbm commands Tomas Winkler
@ 2015-07-26  6:54 ` Tomas Winkler
  2015-07-26  6:54 ` [char-misc-next 3/9 RESEND] mei: enable async event notifications only from hbm version 2.0 Tomas Winkler
                   ` (7 subsequent siblings)
  9 siblings, 0 replies; 14+ messages in thread
From: Tomas Winkler @ 2015-07-26  6:54 UTC (permalink / raw)
  To: Greg Kroah-Hartman; +Cc: arnd, Alexander Usyskin, linux-kernel, Tomas Winkler

Implement sending and reception handlers for the
async event notification hbm commands.
Add client notification book keeping data required for the messages
    notify_en to indicate whether notification is enabled
    notify_ev to indicate whether an event is pending

Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com>
---
 drivers/misc/mei/hbm.c     | 135 +++++++++++++++++++++++++++++++++++++++++++++
 drivers/misc/mei/hbm.h     |   2 +
 drivers/misc/mei/mei_dev.h |   8 +++
 3 files changed, 145 insertions(+)

diff --git a/drivers/misc/mei/hbm.c b/drivers/misc/mei/hbm.c
index 07a8ea8362a3..8a73fa06f3c4 100644
--- a/drivers/misc/mei/hbm.c
+++ b/drivers/misc/mei/hbm.c
@@ -403,6 +403,125 @@ static int mei_hbm_fw_add_cl_req(struct mei_device *dev,
 }
 
 /**
+ * mei_hbm_cl_notify_req - send notification request
+ *
+ * @dev: the device structure
+ * @cl: a client to disconnect from
+ * @start: true for start false for stop
+ *
+ * Return: 0 on success and -EIO on write failure
+ */
+int mei_hbm_cl_notify_req(struct mei_device *dev,
+			  struct mei_cl *cl, u8 start)
+{
+
+	struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr;
+	struct hbm_notification_request *req;
+	const size_t len = sizeof(struct hbm_notification_request);
+	int ret;
+
+	mei_hbm_hdr(mei_hdr, len);
+	mei_hbm_cl_hdr(cl, MEI_HBM_NOTIFY_REQ_CMD, dev->wr_msg.data, len);
+
+	req = (struct hbm_notification_request *)dev->wr_msg.data;
+	req->start = start;
+
+	ret = mei_write_message(dev, mei_hdr, dev->wr_msg.data);
+	if (ret)
+		dev_err(dev->dev, "notify request failed: ret = %d\n", ret);
+
+	return ret;
+}
+
+/**
+ *  notify_res_to_fop - convert notification response to the proper
+ *      notification FOP
+ *
+ * @cmd: client notification start response command
+ *
+ * Return:  MEI_FOP_NOTIFY_START or MEI_FOP_NOTIFY_STOP;
+ */
+static inline enum mei_cb_file_ops notify_res_to_fop(struct mei_hbm_cl_cmd *cmd)
+{
+	struct hbm_notification_response *rs =
+		(struct hbm_notification_response *)cmd;
+
+	if (rs->start == MEI_HBM_NOTIFICATION_START)
+		return MEI_FOP_NOTIFY_START;
+	else
+		return MEI_FOP_NOTIFY_STOP;
+}
+
+/**
+ * mei_hbm_cl_notify_start_res - update the client state according
+ *       notify start response
+ *
+ * @dev: the device structure
+ * @cl: mei host client
+ * @cmd: client notification start response command
+ */
+static void mei_hbm_cl_notify_start_res(struct mei_device *dev,
+					struct mei_cl *cl,
+					struct mei_hbm_cl_cmd *cmd)
+{
+	struct hbm_notification_response *rs =
+		(struct hbm_notification_response *)cmd;
+
+	cl_dbg(dev, cl, "hbm: notify start response status=%d\n", rs->status);
+
+	if (rs->status == MEI_HBMS_SUCCESS ||
+	    rs->status == MEI_HBMS_ALREADY_STARTED) {
+		cl->notify_en = true;
+		cl->status = 0;
+	} else {
+		cl->status = -EINVAL;
+	}
+}
+
+/**
+ * mei_hbm_cl_notify_stop_res - update the client state according
+ *       notify stop response
+ *
+ * @dev: the device structure
+ * @cl: mei host client
+ * @cmd: client notification stop response command
+ */
+static void mei_hbm_cl_notify_stop_res(struct mei_device *dev,
+				       struct mei_cl *cl,
+				       struct mei_hbm_cl_cmd *cmd)
+{
+	struct hbm_notification_response *rs =
+		(struct hbm_notification_response *)cmd;
+
+	cl_dbg(dev, cl, "hbm: notify stop response status=%d\n", rs->status);
+
+	if (rs->status == MEI_HBMS_SUCCESS ||
+	    rs->status == MEI_HBMS_NOT_STARTED) {
+		cl->notify_en = false;
+		cl->status = 0;
+	} else {
+		/* TODO: spec is not clear yet about other possible issues */
+		cl->status = -EINVAL;
+	}
+}
+
+/**
+ * mei_hbm_cl_notify - signal notification event
+ *
+ * @dev: the device structure
+ * @cmd: notification client message
+ */
+static void mei_hbm_cl_notify(struct mei_device *dev,
+			      struct mei_hbm_cl_cmd *cmd)
+{
+	struct mei_cl *cl;
+
+	cl = mei_hbm_cl_find_by_cmd(dev, cmd);
+	if (cl && cl->notify_en)
+		cl->notify_ev = true;
+}
+
+/**
  * mei_hbm_prop_req - request property for a single client
  *
  * @dev: the device structure
@@ -716,6 +835,12 @@ static void mei_hbm_cl_res(struct mei_device *dev,
 	case MEI_FOP_DISCONNECT:
 		mei_hbm_cl_disconnect_res(dev, cl, rs);
 		break;
+	case MEI_FOP_NOTIFY_START:
+		mei_hbm_cl_notify_start_res(dev, cl, rs);
+		break;
+	case MEI_FOP_NOTIFY_STOP:
+		mei_hbm_cl_notify_stop_res(dev, cl, rs);
+		break;
 	default:
 		return;
 	}
@@ -1031,6 +1156,16 @@ int mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr)
 		dev_dbg(dev->dev, "hbm: add client request processed\n");
 		break;
 
+	case MEI_HBM_NOTIFY_RES_CMD:
+		dev_dbg(dev->dev, "hbm: notify response received\n");
+		mei_hbm_cl_res(dev, cl_cmd, notify_res_to_fop(cl_cmd));
+		break;
+
+	case MEI_HBM_NOTIFICATION_CMD:
+		dev_dbg(dev->dev, "hbm: notification\n");
+		mei_hbm_cl_notify(dev, cl_cmd);
+		break;
+
 	default:
 		BUG();
 		break;
diff --git a/drivers/misc/mei/hbm.h b/drivers/misc/mei/hbm.h
index 2544db7d1649..42d66d8fc1f7 100644
--- a/drivers/misc/mei/hbm.h
+++ b/drivers/misc/mei/hbm.h
@@ -54,6 +54,8 @@ int mei_hbm_cl_disconnect_rsp(struct mei_device *dev, struct mei_cl *cl);
 int mei_hbm_cl_connect_req(struct mei_device *dev, struct mei_cl *cl);
 bool mei_hbm_version_is_supported(struct mei_device *dev);
 int mei_hbm_pg(struct mei_device *dev, u8 pg_cmd);
+int mei_hbm_cl_notify_req(struct mei_device *dev,
+			  struct mei_cl *cl, u8 request);
 
 #endif /* _MEI_HBM_H_ */
 
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index 8bd46cd95b7a..362ebb15ccd9 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -136,6 +136,8 @@ enum mei_wd_states {
  * @MEI_FOP_CONNECT:    connect
  * @MEI_FOP_DISCONNECT: disconnect
  * @MEI_FOP_DISCONNECT_RSP: disconnect response
+ * @MEI_FOP_NOTIFY_START:   start notification
+ * @MEI_FOP_NOTIFY_STOP:    stop notification
  */
 enum mei_cb_file_ops {
 	MEI_FOP_READ = 0,
@@ -143,6 +145,8 @@ enum mei_cb_file_ops {
 	MEI_FOP_CONNECT,
 	MEI_FOP_DISCONNECT,
 	MEI_FOP_DISCONNECT_RSP,
+	MEI_FOP_NOTIFY_START,
+	MEI_FOP_NOTIFY_STOP,
 };
 
 /*
@@ -237,6 +241,8 @@ struct mei_cl_cb {
  * @mei_flow_ctrl_creds: transmit flow credentials
  * @timer_count:  watchdog timer for operation completion
  * @reserved: reserved for alignment
+ * @notify_en: notification - enabled/disabled
+ * @notify_ev: pending notification event
  * @writing_state: state of the tx
  * @rd_pending: pending read credits
  * @rd_completed: completed read
@@ -256,6 +262,8 @@ struct mei_cl {
 	u8 mei_flow_ctrl_creds;
 	u8 timer_count;
 	u8 reserved;
+	u8 notify_en;
+	u8 notify_ev;
 	enum mei_file_transaction_states writing_state;
 	struct list_head rd_pending;
 	struct list_head rd_completed;
-- 
2.4.3


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [char-misc-next 3/9 RESEND] mei: enable async event notifications only from hbm version 2.0
  2015-07-26  6:54 [char-misc-next 0/9 RESEND] mei: support for async event notifications Tomas Winkler
  2015-07-26  6:54 ` [char-misc-next 1/9 RESEND] mei: define async notification hbm commands Tomas Winkler
  2015-07-26  6:54 ` [char-misc-next 2/9 RESEND] mei: implement async notification hbm messages Tomas Winkler
@ 2015-07-26  6:54 ` Tomas Winkler
  2015-07-26  6:54 ` [char-misc-next 4/9 RESEND] mei: add mei_cl_notify_request command Tomas Winkler
                   ` (6 subsequent siblings)
  9 siblings, 0 replies; 14+ messages in thread
From: Tomas Winkler @ 2015-07-26  6:54 UTC (permalink / raw)
  To: Greg Kroah-Hartman; +Cc: arnd, Alexander Usyskin, linux-kernel, Tomas Winkler

Only FW version 2.0 and newer support the async event
notification. For backward compatibility block the feature
if the FW version is older then 2.0

Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com>
---
 drivers/misc/mei/debugfs.c | 2 ++
 drivers/misc/mei/hbm.c     | 4 ++++
 drivers/misc/mei/hw.h      | 6 ++++++
 drivers/misc/mei/mei_dev.h | 2 ++
 4 files changed, 14 insertions(+)

diff --git a/drivers/misc/mei/debugfs.c b/drivers/misc/mei/debugfs.c
index e39cfe6bc5bc..4b469cf9e60f 100644
--- a/drivers/misc/mei/debugfs.c
+++ b/drivers/misc/mei/debugfs.c
@@ -158,6 +158,8 @@ static ssize_t mei_dbgfs_read_devstate(struct file *fp, char __user *ubuf,
 				 dev->hbm_f_dc_supported);
 		pos += scnprintf(buf + pos, bufsz - pos, "\tDOT: %01d\n",
 				 dev->hbm_f_dot_supported);
+		pos += scnprintf(buf + pos, bufsz - pos, "\tEV: %01d\n",
+				 dev->hbm_f_ev_supported);
 	}
 
 	pos += scnprintf(buf + pos, bufsz - pos, "pg:  %s, %s\n",
diff --git a/drivers/misc/mei/hbm.c b/drivers/misc/mei/hbm.c
index 8a73fa06f3c4..95e918c84a6c 100644
--- a/drivers/misc/mei/hbm.c
+++ b/drivers/misc/mei/hbm.c
@@ -903,6 +903,10 @@ static void mei_hbm_config_features(struct mei_device *dev)
 	/* disconnect on connect timeout instead of link reset */
 	if (dev->version.major_version >= HBM_MAJOR_VERSION_DOT)
 		dev->hbm_f_dot_supported = 1;
+
+	/* Notification Event Support */
+	if (dev->version.major_version >= HBM_MAJOR_VERSION_EV)
+		dev->hbm_f_ev_supported = 1;
 }
 
 /**
diff --git a/drivers/misc/mei/hw.h b/drivers/misc/mei/hw.h
index a2c7aaba25d4..3f8901a503a6 100644
--- a/drivers/misc/mei/hw.h
+++ b/drivers/misc/mei/hw.h
@@ -58,6 +58,12 @@
 #define HBM_MINOR_VERSION_DOT              0
 #define HBM_MAJOR_VERSION_DOT              2
 
+/*
+ * MEI version with notifcation support
+ */
+#define HBM_MINOR_VERSION_EV               0
+#define HBM_MAJOR_VERSION_EV               2
+
 /* Host bus message command opcode */
 #define MEI_HBM_CMD_OP_MSK                  0x7f
 /* Host bus message command RESPONSE */
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index 362ebb15ccd9..e22bd21bb754 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -419,6 +419,7 @@ const char *mei_pg_state_str(enum mei_pg_state state);
  * @hbm_f_pg_supported  : hbm feature pgi protocol
  * @hbm_f_dc_supported  : hbm feature dynamic clients
  * @hbm_f_dot_supported : hbm feature disconnect on timeout
+ * @hbm_f_ev_supported  : hbm feature event notification
  *
  * @me_clients_rwsem: rw lock over me_clients list
  * @me_clients  : list of FW clients
@@ -514,6 +515,7 @@ struct mei_device {
 	unsigned int hbm_f_pg_supported:1;
 	unsigned int hbm_f_dc_supported:1;
 	unsigned int hbm_f_dot_supported:1;
+	unsigned int hbm_f_ev_supported:1;
 
 	struct rw_semaphore me_clients_rwsem;
 	struct list_head me_clients;
-- 
2.4.3


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [char-misc-next 4/9 RESEND] mei: add mei_cl_notify_request command
  2015-07-26  6:54 [char-misc-next 0/9 RESEND] mei: support for async event notifications Tomas Winkler
                   ` (2 preceding siblings ...)
  2015-07-26  6:54 ` [char-misc-next 3/9 RESEND] mei: enable async event notifications only from hbm version 2.0 Tomas Winkler
@ 2015-07-26  6:54 ` Tomas Winkler
  2015-07-26  6:54 ` [char-misc-next 5/9 RESEND] mei: add a handler that waits for notification on event Tomas Winkler
                   ` (5 subsequent siblings)
  9 siblings, 0 replies; 14+ messages in thread
From: Tomas Winkler @ 2015-07-26  6:54 UTC (permalink / raw)
  To: Greg Kroah-Hartman; +Cc: arnd, Alexander Usyskin, linux-kernel, Tomas Winkler

Add per client notification request infrastructure
that allows client to enable or disable async
event notification.

Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com>
---
 drivers/misc/mei/client.c    | 143 +++++++++++++++++++++++++++++++++++++++++++
 drivers/misc/mei/client.h    |   6 ++
 drivers/misc/mei/hbm.c       |   5 +-
 drivers/misc/mei/interrupt.c |   7 +++
 4 files changed, 157 insertions(+), 4 deletions(-)

diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c
index 40285e02b612..fae4050413a2 100644
--- a/drivers/misc/mei/client.c
+++ b/drivers/misc/mei/client.c
@@ -1209,6 +1209,147 @@ int mei_cl_flow_ctrl_reduce(struct mei_cl *cl)
 }
 
 /**
+ *  mei_cl_notify_fop2req - convert fop to proper request
+ *
+ * @fop: client notification start response command
+ *
+ * Return:  MEI_HBM_NOTIFICATION_START/STOP
+ */
+u8 mei_cl_notify_fop2req(enum mei_cb_file_ops fop)
+{
+	if (fop == MEI_FOP_NOTIFY_START)
+		return MEI_HBM_NOTIFICATION_START;
+	else
+		return MEI_HBM_NOTIFICATION_STOP;
+}
+
+/**
+ *  mei_cl_notify_req2fop - convert notification request top file operation type
+ *
+ * @req: hbm notification request type
+ *
+ * Return:  MEI_FOP_NOTIFY_START/STOP
+ */
+enum mei_cb_file_ops mei_cl_notify_req2fop(u8 req)
+{
+	if (req == MEI_HBM_NOTIFICATION_START)
+		return MEI_FOP_NOTIFY_START;
+	else
+		return MEI_FOP_NOTIFY_STOP;
+}
+
+/**
+ * mei_cl_irq_notify - send notification request in irq_thread context
+ *
+ * @cl: client
+ * @cb: callback block.
+ * @cmpl_list: complete list.
+ *
+ * Return: 0 on such and error otherwise.
+ */
+int mei_cl_irq_notify(struct mei_cl *cl, struct mei_cl_cb *cb,
+		      struct mei_cl_cb *cmpl_list)
+{
+	struct mei_device *dev = cl->dev;
+	u32 msg_slots;
+	int slots;
+	int ret;
+	bool request;
+
+	msg_slots = mei_data2slots(sizeof(struct hbm_client_connect_request));
+	slots = mei_hbuf_empty_slots(dev);
+
+	if (slots < msg_slots)
+		return -EMSGSIZE;
+
+	request = mei_cl_notify_fop2req(cb->fop_type);
+	ret = mei_hbm_cl_notify_req(dev, cl, request);
+	if (ret) {
+		cl->status = ret;
+		list_move_tail(&cb->list, &cmpl_list->list);
+		return ret;
+	}
+
+	list_move_tail(&cb->list, &dev->ctrl_rd_list.list);
+	return 0;
+}
+
+/**
+ * mei_cl_notify_request - send notification stop/start request
+ *
+ * @cl: host client
+ * @file: associate request with file
+ * @request: 1 for start or 0 for stop
+ *
+ * Locking: called under "dev->device_lock" lock
+ *
+ * Return: 0 on such and error otherwise.
+ */
+int mei_cl_notify_request(struct mei_cl *cl, struct file *file, u8 request)
+{
+	struct mei_device *dev;
+	struct mei_cl_cb *cb;
+	enum mei_cb_file_ops fop_type;
+	int rets;
+
+	if (WARN_ON(!cl || !cl->dev))
+		return -ENODEV;
+
+	dev = cl->dev;
+
+	if (!dev->hbm_f_ev_supported) {
+		cl_dbg(dev, cl, "notifications not supported\n");
+		return -EOPNOTSUPP;
+	}
+
+	rets = pm_runtime_get(dev->dev);
+	if (rets < 0 && rets != -EINPROGRESS) {
+		pm_runtime_put_noidle(dev->dev);
+		cl_err(dev, cl, "rpm: get failed %d\n", rets);
+		return rets;
+	}
+
+	fop_type = mei_cl_notify_req2fop(request);
+	cb = mei_io_cb_init(cl, fop_type, file);
+	if (!cb) {
+		rets = -ENOMEM;
+		goto out;
+	}
+
+	if (mei_hbuf_acquire(dev)) {
+		if (mei_hbm_cl_notify_req(dev, cl, request)) {
+			rets = -ENODEV;
+			goto out;
+		}
+		list_add_tail(&cb->list, &dev->ctrl_rd_list.list);
+	} else {
+		list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
+	}
+
+	mutex_unlock(&dev->device_lock);
+	wait_event_timeout(cl->wait, cl->notify_en == request,
+			mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT));
+	mutex_lock(&dev->device_lock);
+
+	if (cl->notify_en != request) {
+		mei_io_list_flush(&dev->ctrl_rd_list, cl);
+		mei_io_list_flush(&dev->ctrl_wr_list, cl);
+		if (!cl->status)
+			cl->status = -EFAULT;
+	}
+
+	rets = cl->status;
+
+out:
+	cl_dbg(dev, cl, "rpm: autosuspend\n");
+	pm_runtime_mark_last_busy(dev->dev);
+	pm_runtime_put_autosuspend(dev->dev);
+
+	mei_io_cb_free(cb);
+	return rets;
+}
+
+/**
  * mei_cl_read_start - the start read client message function.
  *
  * @cl: host client
@@ -1516,6 +1657,8 @@ void mei_cl_complete(struct mei_cl *cl, struct mei_cl_cb *cb)
 
 	case MEI_FOP_CONNECT:
 	case MEI_FOP_DISCONNECT:
+	case MEI_FOP_NOTIFY_STOP:
+	case MEI_FOP_NOTIFY_START:
 		if (waitqueue_active(&cl->wait))
 			wake_up(&cl->wait);
 
diff --git a/drivers/misc/mei/client.h b/drivers/misc/mei/client.h
index 8d7f057f1045..506b7d40d427 100644
--- a/drivers/misc/mei/client.h
+++ b/drivers/misc/mei/client.h
@@ -219,6 +219,12 @@ void mei_cl_complete(struct mei_cl *cl, struct mei_cl_cb *cb);
 
 void mei_host_client_init(struct work_struct *work);
 
+u8 mei_cl_notify_fop2req(enum mei_cb_file_ops fop);
+enum mei_cb_file_ops mei_cl_notify_req2fop(u8 request);
+int mei_cl_notify_request(struct mei_cl *cl, struct file *file, u8 request);
+int mei_cl_irq_notify(struct mei_cl *cl, struct mei_cl_cb *cb,
+		      struct mei_cl_cb *cmpl_list);
+
 void mei_cl_all_disconnect(struct mei_device *dev);
 void mei_cl_all_wakeup(struct mei_device *dev);
 void mei_cl_all_write_clear(struct mei_device *dev);
diff --git a/drivers/misc/mei/hbm.c b/drivers/misc/mei/hbm.c
index 95e918c84a6c..12229ff4bc7e 100644
--- a/drivers/misc/mei/hbm.c
+++ b/drivers/misc/mei/hbm.c
@@ -446,10 +446,7 @@ static inline enum mei_cb_file_ops notify_res_to_fop(struct mei_hbm_cl_cmd *cmd)
 	struct hbm_notification_response *rs =
 		(struct hbm_notification_response *)cmd;
 
-	if (rs->start == MEI_HBM_NOTIFICATION_START)
-		return MEI_FOP_NOTIFY_START;
-	else
-		return MEI_FOP_NOTIFY_STOP;
+	return mei_cl_notify_req2fop(rs->start);
 }
 
 /**
diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c
index 89d8e1304077..c418d7888994 100644
--- a/drivers/misc/mei/interrupt.c
+++ b/drivers/misc/mei/interrupt.c
@@ -403,6 +403,13 @@ int mei_irq_write_handler(struct mei_device *dev, struct mei_cl_cb *cmpl_list)
 			if (ret)
 				return ret;
 			break;
+
+		case MEI_FOP_NOTIFY_START:
+		case MEI_FOP_NOTIFY_STOP:
+			ret = mei_cl_irq_notify(cl, cb, cmpl_list);
+			if (ret)
+				return ret;
+			break;
 		default:
 			BUG();
 		}
-- 
2.4.3


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [char-misc-next 5/9 RESEND] mei: add a handler that waits for notification on event
  2015-07-26  6:54 [char-misc-next 0/9 RESEND] mei: support for async event notifications Tomas Winkler
                   ` (3 preceding siblings ...)
  2015-07-26  6:54 ` [char-misc-next 4/9 RESEND] mei: add mei_cl_notify_request command Tomas Winkler
@ 2015-07-26  6:54 ` Tomas Winkler
  2015-07-26  6:54 ` [char-misc-next 6/9 RESEND] mei: add async event notification ioctls Tomas Winkler
                   ` (4 subsequent siblings)
  9 siblings, 0 replies; 14+ messages in thread
From: Tomas Winkler @ 2015-07-26  6:54 UTC (permalink / raw)
  To: Greg Kroah-Hartman; +Cc: arnd, Alexander Usyskin, linux-kernel, Tomas Winkler

mei_cl_notify_get is to be called by a host client
to wait, receive, and ack the event notification.

Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com>
---
 drivers/misc/mei/client.c  | 52 ++++++++++++++++++++++++++++++++++++++++++++++
 drivers/misc/mei/client.h  |  1 +
 drivers/misc/mei/hbm.c     |  4 +++-
 drivers/misc/mei/mei_dev.h |  2 ++
 4 files changed, 58 insertions(+), 1 deletion(-)

diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c
index fae4050413a2..d9396838774c 100644
--- a/drivers/misc/mei/client.c
+++ b/drivers/misc/mei/client.c
@@ -555,6 +555,7 @@ void mei_cl_init(struct mei_cl *cl, struct mei_device *dev)
 	init_waitqueue_head(&cl->wait);
 	init_waitqueue_head(&cl->rx_wait);
 	init_waitqueue_head(&cl->tx_wait);
+	init_waitqueue_head(&cl->ev_wait);
 	INIT_LIST_HEAD(&cl->rd_completed);
 	INIT_LIST_HEAD(&cl->rd_pending);
 	INIT_LIST_HEAD(&cl->link);
@@ -1350,6 +1351,51 @@ out:
 }
 
 /**
+ * mei_cl_notify_get - get or wait for notification event
+ *
+ * @cl: host client
+ * @block: this request is blocking
+ * @notify_ev: true if notification event was received
+ *
+ * Locking: called under "dev->device_lock" lock
+ *
+ * Return: 0 on such and error otherwise.
+ */
+int mei_cl_notify_get(struct mei_cl *cl, bool block, bool *notify_ev)
+{
+	struct mei_device *dev;
+	int rets;
+
+	*notify_ev = false;
+
+	if (WARN_ON(!cl || !cl->dev))
+		return -ENODEV;
+
+	dev = cl->dev;
+
+	if (!mei_cl_is_connected(cl))
+		return -ENODEV;
+
+	if (cl->notify_ev)
+		goto out;
+
+	if (!block)
+		return -EAGAIN;
+
+	mutex_unlock(&dev->device_lock);
+	rets = wait_event_interruptible(cl->ev_wait, cl->notify_ev);
+	mutex_lock(&dev->device_lock);
+
+	if (rets < 0)
+		return rets;
+
+out:
+	*notify_ev = cl->notify_ev;
+	cl->notify_ev = false;
+	return 0;
+}
+
+/**
  * mei_cl_read_start - the start read client message function.
  *
  * @cl: host client
@@ -1701,6 +1747,12 @@ void mei_cl_all_wakeup(struct mei_device *dev)
 			cl_dbg(dev, cl, "Waking up writing client!\n");
 			wake_up_interruptible(&cl->tx_wait);
 		}
+
+		/* synchronized under device mutex */
+		if (waitqueue_active(&cl->ev_wait)) {
+			cl_dbg(dev, cl, "Waking up waiting for event clients!\n");
+			wake_up_interruptible(&cl->ev_wait);
+		}
 	}
 }
 
diff --git a/drivers/misc/mei/client.h b/drivers/misc/mei/client.h
index 506b7d40d427..58a4b49701fe 100644
--- a/drivers/misc/mei/client.h
+++ b/drivers/misc/mei/client.h
@@ -224,6 +224,7 @@ enum mei_cb_file_ops mei_cl_notify_req2fop(u8 request);
 int mei_cl_notify_request(struct mei_cl *cl, struct file *file, u8 request);
 int mei_cl_irq_notify(struct mei_cl *cl, struct mei_cl_cb *cb,
 		      struct mei_cl_cb *cmpl_list);
+int mei_cl_notify_get(struct mei_cl *cl, bool block, bool *notify_ev);
 
 void mei_cl_all_disconnect(struct mei_device *dev);
 void mei_cl_all_wakeup(struct mei_device *dev);
diff --git a/drivers/misc/mei/hbm.c b/drivers/misc/mei/hbm.c
index 12229ff4bc7e..70c94a9cd905 100644
--- a/drivers/misc/mei/hbm.c
+++ b/drivers/misc/mei/hbm.c
@@ -514,8 +514,10 @@ static void mei_hbm_cl_notify(struct mei_device *dev,
 	struct mei_cl *cl;
 
 	cl = mei_hbm_cl_find_by_cmd(dev, cmd);
-	if (cl && cl->notify_en)
+	if (cl && cl->notify_en) {
 		cl->notify_ev = true;
+		wake_up_interruptible(&cl->ev_wait);
+	}
 }
 
 /**
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index e22bd21bb754..6f8f5e1e909e 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -235,6 +235,7 @@ struct mei_cl_cb {
  * @tx_wait: wait queue for tx completion
  * @rx_wait: wait queue for rx completion
  * @wait:  wait queue for management operation
+ * @ev_wait: notification wait queue
  * @status: connection status
  * @me_cl: fw client connected
  * @host_client_id: host id
@@ -256,6 +257,7 @@ struct mei_cl {
 	wait_queue_head_t tx_wait;
 	wait_queue_head_t rx_wait;
 	wait_queue_head_t wait;
+	wait_queue_head_t ev_wait;
 	int status;
 	struct mei_me_client *me_cl;
 	u8 host_client_id;
-- 
2.4.3


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [char-misc-next 6/9 RESEND] mei: add async event notification ioctls
  2015-07-26  6:54 [char-misc-next 0/9 RESEND] mei: support for async event notifications Tomas Winkler
                   ` (4 preceding siblings ...)
  2015-07-26  6:54 ` [char-misc-next 5/9 RESEND] mei: add a handler that waits for notification on event Tomas Winkler
@ 2015-07-26  6:54 ` Tomas Winkler
  2015-07-26  6:54 ` [char-misc-next 7/9 RESEND] mei: support polling for event notification Tomas Winkler
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 14+ messages in thread
From: Tomas Winkler @ 2015-07-26  6:54 UTC (permalink / raw)
  To: Greg Kroah-Hartman; +Cc: arnd, Alexander Usyskin, linux-kernel, Tomas Winkler

Add ioctl IOCTL_MEI_NOTIFY_SET for enabling and disabling
async event notification.
Add ioctl IOCTL_MEI_NOTIFY_GET for receiving and acking
an event notification.

Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com>
---
 Documentation/ioctl/ioctl-number.txt   |  2 +
 Documentation/misc-devices/mei/mei.txt | 45 ++++++++++++++++++++++-
 drivers/misc/mei/main.c                | 67 ++++++++++++++++++++++++++++++++++
 include/uapi/linux/mei.h               | 19 ++++++++++
 4 files changed, 132 insertions(+), 1 deletion(-)

diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt
index 611c52267d24..141f847c7648 100644
--- a/Documentation/ioctl/ioctl-number.txt
+++ b/Documentation/ioctl/ioctl-number.txt
@@ -124,6 +124,8 @@ Code  Seq#(hex)	Include File		Comments
 'H'	00-7F	linux/hiddev.h		conflict!
 'H'	00-0F	linux/hidraw.h		conflict!
 'H'	01	linux/mei.h		conflict!
+'H'	02	linux/mei.h		conflict!
+'H'	03	linux/mei.h		conflict!
 'H'	00-0F	sound/asound.h		conflict!
 'H'	20-40	sound/asound_fm.h	conflict!
 'H'	80-8F	sound/sfnt_info.h	conflict!
diff --git a/Documentation/misc-devices/mei/mei.txt b/Documentation/misc-devices/mei/mei.txt
index 8d47501bba0a..91c1fa34f48b 100644
--- a/Documentation/misc-devices/mei/mei.txt
+++ b/Documentation/misc-devices/mei/mei.txt
@@ -96,7 +96,7 @@ A code snippet for an application communicating with Intel AMTHI client:
 IOCTL
 =====
 
-The Intel MEI Driver supports the following IOCTL command:
+The Intel MEI Driver supports the following IOCTL commands:
 	IOCTL_MEI_CONNECT_CLIENT	Connect to firmware Feature (client).
 
 	usage:
@@ -125,6 +125,49 @@ The Intel MEI Driver supports the following IOCTL command:
         data that can be sent or received. (e.g. if MTU=2K, can send
         requests up to bytes 2k and received responses up to 2k bytes).
 
+	IOCTL_MEI_NOTIFY_SET: enable or disable event notifications
+
+	Usage:
+		uint32_t enable;
+		ioctl(fd, IOCTL_MEI_NOTIFY_SET, &enable);
+
+	Inputs:
+		uint32_t enable = 1;
+		or
+		uint32_t enable[disable] = 0;
+
+	Error returns:
+		EINVAL	Wrong IOCTL Number
+		ENODEV	Device  is not initialized or the client not connected
+		ENOMEM	Unable to allocate memory to client internal data.
+		EFAULT	Fatal Error (e.g. Unable to access user input data)
+		EOPNOTSUPP if the device doesn't support the feature
+
+	Notes:
+	The client must be connected in order to enable notification events
+
+
+	IOCTL_MEI_NOTIFY_GET : retrieve event
+
+	Usage:
+		uint32_t event;
+		ioctl(fd, IOCTL_MEI_NOTIFY_GET, &event);
+
+	Outputs:
+		1 - if an event is pending
+		0 - if there is no even pending
+
+	Error returns:
+		EINVAL	Wrong IOCTL Number
+		ENODEV	Device is not initialized or the client not connected
+		ENOMEM	Unable to allocate memory to client internal data.
+		EFAULT	Fatal Error (e.g. Unable to access user input data)
+		EOPNOTSUPP if the device doesn't support the feature
+
+	Notes:
+	The client must be connected and event notification has to be enabled
+	in order to receive an event
+
 
 Intel ME Applications
 =====================
diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c
index e9513d651cd3..ffa70035af29 100644
--- a/drivers/misc/mei/main.c
+++ b/drivers/misc/mei/main.c
@@ -446,6 +446,45 @@ end:
 }
 
 /**
+ * mei_ioctl_client_notify_request -
+ *     propagate event notification request to client
+ *
+ * @file: pointer to file structure
+ * @request: 0 - disable, 1 - enable
+ *
+ * Return: 0 on success , <0 on error
+ */
+static int mei_ioctl_client_notify_request(struct file *file, u32 request)
+{
+	struct mei_cl *cl = file->private_data;
+
+	return mei_cl_notify_request(cl, file, request);
+}
+
+/**
+ * mei_ioctl_client_notify_get -  wait for notification request
+ *
+ * @file: pointer to file structure
+ * @notify_get: 0 - disable, 1 - enable
+ *
+ * Return: 0 on success , <0 on error
+ */
+static int mei_ioctl_client_notify_get(struct file *file, u32 *notify_get)
+{
+	struct mei_cl *cl = file->private_data;
+	bool notify_ev;
+	bool block = (file->f_flags & O_NONBLOCK) == 0;
+	int rets;
+
+	rets = mei_cl_notify_get(cl, block, &notify_ev);
+	if (rets)
+		return rets;
+
+	*notify_get = notify_ev ? 1 : 0;
+	return 0;
+}
+
+/**
  * mei_ioctl - the IOCTL function
  *
  * @file: pointer to file structure
@@ -459,6 +498,7 @@ static long mei_ioctl(struct file *file, unsigned int cmd, unsigned long data)
 	struct mei_device *dev;
 	struct mei_cl *cl = file->private_data;
 	struct mei_connect_client_data connect_data;
+	u32 notify_get, notify_req;
 	int rets;
 
 
@@ -499,6 +539,33 @@ static long mei_ioctl(struct file *file, unsigned int cmd, unsigned long data)
 
 		break;
 
+	case IOCTL_MEI_NOTIFY_SET:
+		dev_dbg(dev->dev, ": IOCTL_MEI_NOTIFY_SET.\n");
+		if (copy_from_user(&notify_req,
+				   (char __user *)data, sizeof(notify_req))) {
+			dev_dbg(dev->dev, "failed to copy data from userland\n");
+			rets = -EFAULT;
+			goto out;
+		}
+		rets = mei_ioctl_client_notify_request(file, notify_req);
+		break;
+
+	case IOCTL_MEI_NOTIFY_GET:
+		dev_dbg(dev->dev, ": IOCTL_MEI_NOTIFY_GET.\n");
+		rets = mei_ioctl_client_notify_get(file, &notify_get);
+		if (rets)
+			goto out;
+
+		dev_dbg(dev->dev, "copy connect data to user\n");
+		if (copy_to_user((char __user *)data,
+				&notify_get, sizeof(notify_get))) {
+			dev_dbg(dev->dev, "failed to copy data to userland\n");
+			rets = -EFAULT;
+			goto out;
+
+		}
+		break;
+
 	default:
 		dev_err(dev->dev, ": unsupported ioctl %d.\n", cmd);
 		rets = -ENOIOCTLCMD;
diff --git a/include/uapi/linux/mei.h b/include/uapi/linux/mei.h
index bc0d8b69c49e..7c3b64f6a215 100644
--- a/include/uapi/linux/mei.h
+++ b/include/uapi/linux/mei.h
@@ -107,4 +107,23 @@ struct mei_connect_client_data {
 	};
 };
 
+/**
+ * DOC: set and unset event notification for a connected client
+ *
+ * The IOCTL argument is 1 for enabling event notification and 0 for
+ * disabling the service
+ * Return:  -EOPNOTSUPP if the devices doesn't support the feature
+ */
+#define IOCTL_MEI_NOTIFY_SET _IOW('H', 0x02, __u32)
+
+/**
+ * DOC: retrieve notification
+ *
+ * The IOCTL output argument is 1 if an event was is pending and 0 otherwise
+ * the ioctl has to be called in order to acknowledge pending event
+ *
+ * Return:  -EOPNOTSUPP if the devices doesn't support the feature
+ */
+#define IOCTL_MEI_NOTIFY_GET _IOR('H', 0x03, __u32)
+
 #endif /* _LINUX_MEI_H  */
-- 
2.4.3


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [char-misc-next 7/9 RESEND] mei: support polling for event notification
  2015-07-26  6:54 [char-misc-next 0/9 RESEND] mei: support for async event notifications Tomas Winkler
                   ` (5 preceding siblings ...)
  2015-07-26  6:54 ` [char-misc-next 6/9 RESEND] mei: add async event notification ioctls Tomas Winkler
@ 2015-07-26  6:54 ` Tomas Winkler
  2015-07-26  6:54 ` [char-misc-next 8/9 RESEND] mei: implement fasync " Tomas Winkler
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 14+ messages in thread
From: Tomas Winkler @ 2015-07-26  6:54 UTC (permalink / raw)
  To: Greg Kroah-Hartman; +Cc: arnd, Alexander Usyskin, linux-kernel, Tomas Winkler

Polling on priority events is translated on waiting for event
notification. One need to enable notification prior for
calling select or poll system call otherwise process
will not wait.

Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com>
---
 drivers/misc/mei/main.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c
index ffa70035af29..17b356f26686 100644
--- a/drivers/misc/mei/main.c
+++ b/drivers/misc/mei/main.c
@@ -608,6 +608,7 @@ static unsigned int mei_poll(struct file *file, poll_table *wait)
 	struct mei_cl *cl = file->private_data;
 	struct mei_device *dev;
 	unsigned int mask = 0;
+	bool notify_en;
 
 	if (WARN_ON(!cl || !cl->dev))
 		return POLLERR;
@@ -616,6 +617,7 @@ static unsigned int mei_poll(struct file *file, poll_table *wait)
 
 	mutex_lock(&dev->device_lock);
 
+	notify_en = cl->notify_en && (req_events & POLLPRI);
 
 	if (dev->dev_state != MEI_DEV_ENABLED ||
 	    !mei_cl_is_connected(cl)) {
@@ -628,6 +630,12 @@ static unsigned int mei_poll(struct file *file, poll_table *wait)
 		goto out;
 	}
 
+	if (notify_en) {
+		poll_wait(file, &cl->ev_wait, wait);
+		if (cl->notify_ev)
+			mask |= POLLPRI;
+	}
+
 	if (req_events & (POLLIN | POLLRDNORM)) {
 		poll_wait(file, &cl->rx_wait, wait);
 
-- 
2.4.3


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [char-misc-next 8/9 RESEND] mei: implement fasync for event notification
  2015-07-26  6:54 [char-misc-next 0/9 RESEND] mei: support for async event notifications Tomas Winkler
                   ` (6 preceding siblings ...)
  2015-07-26  6:54 ` [char-misc-next 7/9 RESEND] mei: support polling for event notification Tomas Winkler
@ 2015-07-26  6:54 ` Tomas Winkler
  2015-07-26  6:54 ` [char-misc-next 9/9 RESEND] mei: bus: add and call callback on notify event Tomas Winkler
  2015-07-26 17:45 ` [char-misc-next 0/9 RESEND] mei: support for async event notifications Greg Kroah-Hartman
  9 siblings, 0 replies; 14+ messages in thread
From: Tomas Winkler @ 2015-07-26  6:54 UTC (permalink / raw)
  To: Greg Kroah-Hartman; +Cc: arnd, Alexander Usyskin, linux-kernel, Tomas Winkler

A process can be informed about client notification also via
SIGIO with POLL_PRI event.

Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
 drivers/misc/mei/client.c  | 27 +++++++++++++++++++++++++++
 drivers/misc/mei/client.h  |  1 +
 drivers/misc/mei/hbm.c     |  6 ++----
 drivers/misc/mei/main.c    | 21 +++++++++++++++++++++
 drivers/misc/mei/mei_dev.h |  2 ++
 5 files changed, 53 insertions(+), 4 deletions(-)

diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c
index d9396838774c..db2436aee2dc 100644
--- a/drivers/misc/mei/client.c
+++ b/drivers/misc/mei/client.c
@@ -1351,6 +1351,33 @@ out:
 }
 
 /**
+ * mei_cl_notify - raise notification
+ *
+ * @cl: host client
+ *
+ * Locking: called under "dev->device_lock" lock
+ */
+void mei_cl_notify(struct mei_cl *cl)
+{
+	struct mei_device *dev;
+
+	if (!cl || !cl->dev)
+		return;
+
+	dev = cl->dev;
+
+	if (!cl->notify_en)
+		return;
+
+	cl_dbg(dev, cl, "notify event");
+	cl->notify_ev = true;
+	wake_up_interruptible_all(&cl->ev_wait);
+
+	if (cl->ev_async)
+		kill_fasync(&cl->ev_async, SIGIO, POLL_PRI);
+}
+
+/**
  * mei_cl_notify_get - get or wait for notification event
  *
  * @cl: host client
diff --git a/drivers/misc/mei/client.h b/drivers/misc/mei/client.h
index 58a4b49701fe..1c7cad07d731 100644
--- a/drivers/misc/mei/client.h
+++ b/drivers/misc/mei/client.h
@@ -225,6 +225,7 @@ int mei_cl_notify_request(struct mei_cl *cl, struct file *file, u8 request);
 int mei_cl_irq_notify(struct mei_cl *cl, struct mei_cl_cb *cb,
 		      struct mei_cl_cb *cmpl_list);
 int mei_cl_notify_get(struct mei_cl *cl, bool block, bool *notify_ev);
+void mei_cl_notify(struct mei_cl *cl);
 
 void mei_cl_all_disconnect(struct mei_device *dev);
 void mei_cl_all_wakeup(struct mei_device *dev);
diff --git a/drivers/misc/mei/hbm.c b/drivers/misc/mei/hbm.c
index 70c94a9cd905..7f53597e697a 100644
--- a/drivers/misc/mei/hbm.c
+++ b/drivers/misc/mei/hbm.c
@@ -514,10 +514,8 @@ static void mei_hbm_cl_notify(struct mei_device *dev,
 	struct mei_cl *cl;
 
 	cl = mei_hbm_cl_find_by_cmd(dev, cmd);
-	if (cl && cl->notify_en) {
-		cl->notify_ev = true;
-		wake_up_interruptible(&cl->ev_wait);
-	}
+	if (cl)
+		mei_cl_notify(cl);
 }
 
 /**
diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c
index 17b356f26686..b2f2486b3d75 100644
--- a/drivers/misc/mei/main.c
+++ b/drivers/misc/mei/main.c
@@ -651,6 +651,26 @@ out:
 }
 
 /**
+ * mei_fasync - asynchronous io support
+ *
+ * @fd: file descriptor
+ * @file: pointer to file structure
+ * @band: band bitmap
+ *
+ * Return: poll mask
+ */
+static int mei_fasync(int fd, struct file *file, int band)
+{
+
+	struct mei_cl *cl = file->private_data;
+
+	if (!mei_cl_is_connected(cl))
+		return POLLERR;
+
+	return fasync_helper(fd, file, band, &cl->ev_async);
+}
+
+/**
  * fw_status_show - mei device attribute show method
  *
  * @device: device pointer
@@ -702,6 +722,7 @@ static const struct file_operations mei_fops = {
 	.release = mei_release,
 	.write = mei_write,
 	.poll = mei_poll,
+	.fasync = mei_fasync,
 	.llseek = no_llseek
 };
 
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index 6f8f5e1e909e..c960aaa538c0 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -236,6 +236,7 @@ struct mei_cl_cb {
  * @rx_wait: wait queue for rx completion
  * @wait:  wait queue for management operation
  * @ev_wait: notification wait queue
+ * @ev_async: event async notification
  * @status: connection status
  * @me_cl: fw client connected
  * @host_client_id: host id
@@ -258,6 +259,7 @@ struct mei_cl {
 	wait_queue_head_t rx_wait;
 	wait_queue_head_t wait;
 	wait_queue_head_t ev_wait;
+	struct fasync_struct *ev_async;
 	int status;
 	struct mei_me_client *me_cl;
 	u8 host_client_id;
-- 
2.4.3


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [char-misc-next 9/9 RESEND] mei: bus: add and call callback on notify event
  2015-07-26  6:54 [char-misc-next 0/9 RESEND] mei: support for async event notifications Tomas Winkler
                   ` (7 preceding siblings ...)
  2015-07-26  6:54 ` [char-misc-next 8/9 RESEND] mei: implement fasync " Tomas Winkler
@ 2015-07-26  6:54 ` Tomas Winkler
  2015-07-26 17:45 ` [char-misc-next 0/9 RESEND] mei: support for async event notifications Greg Kroah-Hartman
  9 siblings, 0 replies; 14+ messages in thread
From: Tomas Winkler @ 2015-07-26  6:54 UTC (permalink / raw)
  To: Greg Kroah-Hartman; +Cc: arnd, Alexander Usyskin, linux-kernel, Tomas Winkler

From: Alexander Usyskin <alexander.usyskin@intel.com>

Enable drivers on mei client bus to subscribe
to asynchronous event notifications.
Introduce events_mask to the existing callback infrastructure
so it is possible to handle both RX and event notification.

Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com>
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
 drivers/misc/mei/bus.c     | 50 ++++++++++++++++++++++++++++++++++++++++++----
 drivers/misc/mei/client.c  |  2 ++
 drivers/misc/mei/mei_dev.h |  1 +
 drivers/nfc/mei_phy.c      |  3 ++-
 include/linux/mei_cl_bus.h |  4 ++++
 5 files changed, 55 insertions(+), 5 deletions(-)

diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c
index 3ab08e522fb8..eef1c6b46ad8 100644
--- a/drivers/misc/mei/bus.c
+++ b/drivers/misc/mei/bus.c
@@ -222,7 +222,33 @@ static void mei_bus_event_work(struct work_struct *work)
 	cldev->events = 0;
 
 	/* Prepare for the next read */
-	mei_cl_read_start(cldev->cl, 0, NULL);
+	if (cldev->events_mask & BIT(MEI_CL_EVENT_RX))
+		mei_cl_read_start(cldev->cl, 0, NULL);
+}
+
+/**
+ * mei_cl_bus_notify_event - schedule notify cb on bus client
+ *
+ * @cl: host client
+ */
+void mei_cl_bus_notify_event(struct mei_cl *cl)
+{
+	struct mei_cl_device *cldev = cl->cldev;
+
+	if (!cldev || !cldev->event_cb)
+		return;
+
+	if (!(cldev->events_mask & BIT(MEI_CL_EVENT_NOTIF)))
+		return;
+
+	if (!cl->notify_ev)
+		return;
+
+	set_bit(MEI_CL_EVENT_NOTIF, &cldev->events);
+
+	schedule_work(&cldev->event_work);
+
+	cl->notify_ev = false;
 }
 
 /**
@@ -237,6 +263,9 @@ void mei_cl_bus_rx_event(struct mei_cl *cl)
 	if (!cldev || !cldev->event_cb)
 		return;
 
+	if (!(cldev->events_mask & BIT(MEI_CL_EVENT_RX)))
+		return;
+
 	set_bit(MEI_CL_EVENT_RX, &cldev->events);
 
 	schedule_work(&cldev->event_work);
@@ -247,6 +276,7 @@ void mei_cl_bus_rx_event(struct mei_cl *cl)
  *
  * @cldev: me client devices
  * @event_cb: callback function
+ * @events_mask: requested events bitmask
  * @context: driver context data
  *
  * Return: 0 on success
@@ -254,6 +284,7 @@ void mei_cl_bus_rx_event(struct mei_cl *cl)
  *         <0 on other errors
  */
 int mei_cl_register_event_cb(struct mei_cl_device *cldev,
+			  unsigned long events_mask,
 			  mei_cl_event_cb_t event_cb, void *context)
 {
 	int ret;
@@ -262,13 +293,24 @@ int mei_cl_register_event_cb(struct mei_cl_device *cldev,
 		return -EALREADY;
 
 	cldev->events = 0;
+	cldev->events_mask = events_mask;
 	cldev->event_cb = event_cb;
 	cldev->event_context = context;
 	INIT_WORK(&cldev->event_work, mei_bus_event_work);
 
-	ret = mei_cl_read_start(cldev->cl, 0, NULL);
-	if (ret && ret != -EBUSY)
-		return ret;
+	if (cldev->events_mask & BIT(MEI_CL_EVENT_RX)) {
+		ret = mei_cl_read_start(cldev->cl, 0, NULL);
+		if (ret && ret != -EBUSY)
+			return ret;
+	}
+
+	if (cldev->events_mask & BIT(MEI_CL_EVENT_NOTIF)) {
+		mutex_lock(&cldev->cl->dev->device_lock);
+		ret = mei_cl_notify_request(cldev->cl, NULL, event_cb ? 1 : 0);
+		mutex_unlock(&cldev->cl->dev->device_lock);
+		if (ret)
+			return ret;
+	}
 
 	return 0;
 }
diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c
index db2436aee2dc..5fcd70bcdf96 100644
--- a/drivers/misc/mei/client.c
+++ b/drivers/misc/mei/client.c
@@ -1375,6 +1375,8 @@ void mei_cl_notify(struct mei_cl *cl)
 
 	if (cl->ev_async)
 		kill_fasync(&cl->ev_async, SIGIO, POLL_PRI);
+
+	mei_cl_bus_notify_event(cl);
 }
 
 /**
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index c960aaa538c0..e25ee16c658e 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -345,6 +345,7 @@ ssize_t __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length,
 			bool blocking);
 ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length);
 void mei_cl_bus_rx_event(struct mei_cl *cl);
+void mei_cl_bus_notify_event(struct mei_cl *cl);
 void mei_cl_bus_remove_devices(struct mei_device *bus);
 int mei_cl_bus_init(void);
 void mei_cl_bus_exit(void);
diff --git a/drivers/nfc/mei_phy.c b/drivers/nfc/mei_phy.c
index 2b77ccf77f81..754a9bb0f58d 100644
--- a/drivers/nfc/mei_phy.c
+++ b/drivers/nfc/mei_phy.c
@@ -355,7 +355,8 @@ static int nfc_mei_phy_enable(void *phy_id)
 		goto err;
 	}
 
-	r = mei_cl_register_event_cb(phy->device, nfc_mei_event_cb, phy);
+	r = mei_cl_register_event_cb(phy->device, BIT(MEI_CL_EVENT_RX),
+				     nfc_mei_event_cb, phy);
 	if (r) {
 		pr_err("Event cb registration failed %d\n", r);
 		goto err;
diff --git a/include/linux/mei_cl_bus.h b/include/linux/mei_cl_bus.h
index 81ab56dd0ae0..0962b2ca628a 100644
--- a/include/linux/mei_cl_bus.h
+++ b/include/linux/mei_cl_bus.h
@@ -28,6 +28,7 @@ typedef void (*mei_cl_event_cb_t)(struct mei_cl_device *device,
  * @event_cb: Drivers register this callback to get asynchronous ME
  *	events (e.g. Rx buffer pending) notifications.
  * @event_context: event callback run context
+ * @events_mask: Events bit mask requested by driver.
  * @events: Events bitmask sent to the driver.
  *
  * @do_match: wheather device can be matched with a driver
@@ -46,6 +47,7 @@ struct mei_cl_device {
 	struct work_struct event_work;
 	mei_cl_event_cb_t event_cb;
 	void *event_context;
+	unsigned long events_mask;
 	unsigned long events;
 
 	unsigned int do_match:1;
@@ -76,10 +78,12 @@ ssize_t mei_cl_send(struct mei_cl_device *device, u8 *buf, size_t length);
 ssize_t  mei_cl_recv(struct mei_cl_device *device, u8 *buf, size_t length);
 
 int mei_cl_register_event_cb(struct mei_cl_device *device,
+			  unsigned long event_mask,
 			  mei_cl_event_cb_t read_cb, void *context);
 
 #define MEI_CL_EVENT_RX 0
 #define MEI_CL_EVENT_TX 1
+#define MEI_CL_EVENT_NOTIF 2
 
 void *mei_cl_get_drvdata(const struct mei_cl_device *device);
 void mei_cl_set_drvdata(struct mei_cl_device *device, void *data);
-- 
2.4.3


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* Re: [char-misc-next 0/9 RESEND] mei: support for async event notifications
  2015-07-26  6:54 [char-misc-next 0/9 RESEND] mei: support for async event notifications Tomas Winkler
                   ` (8 preceding siblings ...)
  2015-07-26  6:54 ` [char-misc-next 9/9 RESEND] mei: bus: add and call callback on notify event Tomas Winkler
@ 2015-07-26 17:45 ` Greg Kroah-Hartman
  2015-07-27  6:36   ` Winkler, Tomas
  9 siblings, 1 reply; 14+ messages in thread
From: Greg Kroah-Hartman @ 2015-07-26 17:45 UTC (permalink / raw)
  To: Tomas Winkler; +Cc: arnd, Alexander Usyskin, linux-kernel

On Sun, Jul 26, 2015 at 09:54:14AM +0300, Tomas Winkler wrote:
> FW has gained new capability where a FW client can asynchronously
> notify the host that an event has occurred in its process.
> The notification doesn't provide any data and host may need to query
> further the FW client in order to get details of the event.
> New IOCTLs are introduced for the user space to enable/disable
> and consume the event notifications.
> The asynchronous nature is provided via poll and fasync.

What changed to require a RESEND?

^ permalink raw reply	[flat|nested] 14+ messages in thread

* RE: [char-misc-next 0/9 RESEND] mei: support for async event notifications
  2015-07-26 17:45 ` [char-misc-next 0/9 RESEND] mei: support for async event notifications Greg Kroah-Hartman
@ 2015-07-27  6:36   ` Winkler, Tomas
  2015-08-04  0:18     ` Greg Kroah-Hartman
  0 siblings, 1 reply; 14+ messages in thread
From: Winkler, Tomas @ 2015-07-27  6:36 UTC (permalink / raw)
  To: Greg Kroah-Hartman; +Cc: arnd, Usyskin, Alexander, linux-kernel


> 
> On Sun, Jul 26, 2015 at 09:54:14AM +0300, Tomas Winkler wrote:
> > FW has gained new capability where a FW client can asynchronously
> > notify the host that an event has occurred in its process.
> > The notification doesn't provide any data and host may need to query
> > further the FW client in order to get details of the event.
> > New IOCTLs are introduced for the user space to enable/disable
> > and consume the event notifications.
> > The asynchronous nature is provided via poll and fasync.
> 
> What changed to require a RESEND?

You've asked for it.
Tomas


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [char-misc-next 0/9 RESEND] mei: support for async event notifications
  2015-07-27  6:36   ` Winkler, Tomas
@ 2015-08-04  0:18     ` Greg Kroah-Hartman
  2015-08-04 10:59       ` Winkler, Tomas
  0 siblings, 1 reply; 14+ messages in thread
From: Greg Kroah-Hartman @ 2015-08-04  0:18 UTC (permalink / raw)
  To: Winkler, Tomas; +Cc: arnd, Usyskin, Alexander, linux-kernel

On Mon, Jul 27, 2015 at 06:36:18AM +0000, Winkler, Tomas wrote:
> 
> > 
> > On Sun, Jul 26, 2015 at 09:54:14AM +0300, Tomas Winkler wrote:
> > > FW has gained new capability where a FW client can asynchronously
> > > notify the host that an event has occurred in its process.
> > > The notification doesn't provide any data and host may need to query
> > > further the FW client in order to get details of the event.
> > > New IOCTLs are introduced for the user space to enable/disable
> > > and consume the event notifications.
> > > The asynchronous nature is provided via poll and fasync.
> > 
> > What changed to require a RESEND?
> 
> You've asked for it.

You might want to give me some context, as I have no idea why I asked
for a resend.  Obviously you must have done something to the series from
the previous one, right?

thanks,

greg "short term memory of a squirrel" k-h

^ permalink raw reply	[flat|nested] 14+ messages in thread

* RE: [char-misc-next 0/9 RESEND] mei: support for async event notifications
  2015-08-04  0:18     ` Greg Kroah-Hartman
@ 2015-08-04 10:59       ` Winkler, Tomas
  0 siblings, 0 replies; 14+ messages in thread
From: Winkler, Tomas @ 2015-08-04 10:59 UTC (permalink / raw)
  To: Greg Kroah-Hartman; +Cc: arnd, Usyskin, Alexander, linux-kernel


> > > > and consume the event notifications.
> > > > The asynchronous nature is provided via poll and fasync.
> > >
> > > What changed to require a RESEND?
> >
> > You've asked for it.
> 
> You might want to give me some context, as I have no idea why I asked
> for a resend.  Obviously you must have done something to the series from
> the previous one, right?

Quoting from (https://lkml.org/lkml/2015/7/23/5) and referring to the second sentence.

'Due to the changes in Linus's tree, this doesn't apply to 4.2-rc3.  Can
you refresh this series and resend?  Same for the other outstanding mei
patches you have sent that I haven't applied.'

Thanks
Tomas

^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2015-08-04 11:00 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-07-26  6:54 [char-misc-next 0/9 RESEND] mei: support for async event notifications Tomas Winkler
2015-07-26  6:54 ` [char-misc-next 1/9 RESEND] mei: define async notification hbm commands Tomas Winkler
2015-07-26  6:54 ` [char-misc-next 2/9 RESEND] mei: implement async notification hbm messages Tomas Winkler
2015-07-26  6:54 ` [char-misc-next 3/9 RESEND] mei: enable async event notifications only from hbm version 2.0 Tomas Winkler
2015-07-26  6:54 ` [char-misc-next 4/9 RESEND] mei: add mei_cl_notify_request command Tomas Winkler
2015-07-26  6:54 ` [char-misc-next 5/9 RESEND] mei: add a handler that waits for notification on event Tomas Winkler
2015-07-26  6:54 ` [char-misc-next 6/9 RESEND] mei: add async event notification ioctls Tomas Winkler
2015-07-26  6:54 ` [char-misc-next 7/9 RESEND] mei: support polling for event notification Tomas Winkler
2015-07-26  6:54 ` [char-misc-next 8/9 RESEND] mei: implement fasync " Tomas Winkler
2015-07-26  6:54 ` [char-misc-next 9/9 RESEND] mei: bus: add and call callback on notify event Tomas Winkler
2015-07-26 17:45 ` [char-misc-next 0/9 RESEND] mei: support for async event notifications Greg Kroah-Hartman
2015-07-27  6:36   ` Winkler, Tomas
2015-08-04  0:18     ` Greg Kroah-Hartman
2015-08-04 10:59       ` Winkler, Tomas

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.