All of lore.kernel.org
 help / color / mirror / Atom feed
From: Sagar Dharia <sdharia@codeaurora.org>
To: gregkh@linuxfoundation.org, broonie@kernel.org,
	linux-kernel@vger.kernel.org, bp@suse.de, poeschel@lemonage.de,
	sdharia@codeaurora.org, santosh.shilimkar@ti.com,
	treding@nvidia.com, gong.chen@linux.intel.com,
	andreas.noever@gmail.com, alan@linux.intel.com,
	mathieu.poirier@linaro.org, daniel@ffwll.ch, oded.gabbay@amd.com,
	jkosina@suse.cz, sharon.dvir1@mail.huji.ac.il, joe@perches.com,
	davem@davemloft.net, james.hogan@imgtec.com,
	michael.opdenacker@free-electrons.com,
	daniel.thompson@linaro.org, nkaje@codeaurora.org,
	mbutler@audience.com
Cc: kheitke@audience.com, mlocke@codeaurora.org,
	agross@codeaurora.org, linux-arm-msm@vger.kernel.org
Subject: [PATCH 3/3] slimbus: Add messaging APIs to slimbus framework
Date: Sat, 13 Jun 2015 23:49:18 -0600	[thread overview]
Message-ID: <1434260958-13732-4-git-send-email-sdharia@codeaurora.org> (raw)
In-Reply-To: <1434260958-13732-1-git-send-email-sdharia@codeaurora.org>

Slimbus devices use value-element, and information elements to
control device parameters (e.g. value element is used to represent
gain for codec, information element is used to represent interrupt
status for codec when codec interrupt fires).
Messaging APIs are used to set/get these value and information
elements. Slimbus specification uses 8-bit "transaction IDs" for
messages where a read-value is anticipated. Framework uses a table
of pointers to store those TIDs and responds back to the caller in
O(1).
Caller can opt to do synchronous, or asynchronous reads/writes. For
asynchronous operations, the callback can be called from atomic
context.

Signed-off-by: Sagar Dharia <sdharia@codeaurora.org>
Tested-by: Naveen Kaje <nkaje@codeaurora.org>
---
 drivers/slimbus/slimbus.c | 273 ++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/slimbus.h   | 124 +++++++++++++++++++++
 2 files changed, 397 insertions(+)

diff --git a/drivers/slimbus/slimbus.c b/drivers/slimbus/slimbus.c
index f51b503..44614e1 100644
--- a/drivers/slimbus/slimbus.c
+++ b/drivers/slimbus/slimbus.c
@@ -26,6 +26,14 @@ static DEFINE_IDR(ctrl_idr);
 static struct device_type slim_dev_type;
 static struct device_type slim_ctrl_type;
 
+#define DEFINE_SLIM_LDEST_TXN(name, mc, rl, la, msg) \
+	struct slim_msg_txn name = { rl, 0, mc, SLIM_MSG_DEST_LOGICALADDR, 0,\
+					0, la, msg, }
+
+#define DEFINE_SLIM_BCAST_TXN(name, mc, rl, la, msg) \
+	struct slim_msg_txn name = { rl, 0, mc, SLIM_MSG_DEST_BROADCAST, 0,\
+					0, la, msg, }
+
 static int slim_compare_eaddr(struct slim_eaddr *a, struct slim_eaddr *b)
 {
 	if (a->manf_id == b->manf_id && a->prod_code == b->prod_code &&
@@ -762,6 +770,271 @@ int slim_get_logical_addr(struct slim_device *sb, struct slim_eaddr *e_addr,
 }
 EXPORT_SYMBOL(slim_get_logical_addr);
 
+/*
+ * slim_msg_response: Deliver Message response received from a device to the
+ *	framework.
+ * @ctrl: Controller handle
+ * @reply: Reply received from the device
+ * @len: Length of the reply
+ * @tid: Transaction ID received with which framework can associate reply.
+ * Called by controller to inform framework about the response received.
+ * This helps in making the API asynchronous, and controller-driver doesn't need
+ * to manage 1 more table other than the one managed by framework mapping TID
+ * with buffers
+ */
+void slim_msg_response(struct slim_controller *ctrl, u8 *reply, u8 tid, u8 len)
+{
+	struct slim_val_inf *msg;
+
+	spin_lock(&ctrl->txn_lock);
+	msg = ctrl->txnt[tid];
+	if (msg == NULL || msg->rbuf == NULL) {
+		spin_unlock(&ctrl->txn_lock);
+		dev_err(&ctrl->dev, "Got response to invalid TID:%d, len:%d",
+				tid, len);
+		return;
+	}
+	memcpy(msg->rbuf, reply, len);
+	ctrl->txnt[tid] = NULL;
+	if (msg->comp_cb)
+		msg->comp_cb(msg->ctx);
+	spin_unlock(&ctrl->txn_lock);
+}
+EXPORT_SYMBOL(slim_msg_response);
+
+static int slim_processtxn(struct slim_controller *ctrl,
+				struct slim_msg_txn *txn)
+{
+	int i = 0, ret = 0;
+	unsigned long flags;
+
+	if (txn->mt == SLIM_MSG_MT_CORE &&
+		(txn->mc == SLIM_MSG_MC_REQUEST_INFORMATION ||
+		 txn->mc == SLIM_MSG_MC_REQUEST_CLEAR_INFORMATION ||
+		 txn->mc == SLIM_MSG_MC_REQUEST_VALUE ||
+		 txn->mc == SLIM_MSG_MC_REQUEST_CLEAR_INFORMATION)) {
+		spin_lock_irqsave(&ctrl->txn_lock, flags);
+		for (i = 0; i < ctrl->last_tid; i++) {
+			if (ctrl->txnt[i] == NULL)
+				break;
+		}
+		if (i >= ctrl->last_tid) {
+			if (ctrl->last_tid == 255) {
+				spin_unlock_irqrestore(&ctrl->txn_lock, flags);
+				return -ENOMEM;
+			}
+			ctrl->last_tid++;
+		}
+		ctrl->txnt[i] = txn->msg;
+		txn->tid = i;
+		spin_unlock_irqrestore(&ctrl->txn_lock, flags);
+	}
+
+	ret = ctrl->xfer_msg(ctrl, txn);
+	return ret;
+}
+
+static int slim_val_inf_sanity(struct slim_val_inf *msg, int oper)
+{
+	if (!msg || msg->num_bytes > 16 ||
+		(msg->start_offset + msg->num_bytes) > 0xC00)
+		return -EINVAL;
+	switch (oper) {
+	case SLIM_MSG_MC_REQUEST_VALUE:
+	case SLIM_MSG_MC_REQUEST_INFORMATION:
+		if (msg->rbuf == NULL)
+			return -EINVAL;
+		return 0;
+	case SLIM_MSG_MC_CHANGE_VALUE:
+	case SLIM_MSG_MC_CLEAR_INFORMATION:
+		if (msg->wbuf == NULL)
+			return -EINVAL;
+		return 0;
+	case SLIM_MSG_MC_REQUEST_CHANGE_VALUE:
+	case SLIM_MSG_MC_REQUEST_CLEAR_INFORMATION:
+		if (msg->rbuf == NULL || msg->wbuf == NULL)
+			return -EINVAL;
+		return 0;
+	default:
+		return -EINVAL;
+	}
+}
+
+static u16 slim_slicecodefromsize(u16 req)
+{
+	static const u8 codetosize[8] = {1, 2, 3, 4, 6, 8, 12, 16};
+
+	if (req >= ARRAY_SIZE(codetosize))
+		return 0;
+	else
+		return codetosize[req];
+}
+
+static u16 slim_slicesize(int code)
+{
+	static const u8 sizetocode[16] = {
+		0, 1, 2, 3, 3, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7
+	};
+
+	clamp(code, 1, (int)ARRAY_SIZE(sizetocode));
+	return sizetocode[code - 1];
+}
+
+static void slim_sync_default_cb(void *ctx)
+{
+	struct completion *comp = ctx;
+
+	complete(comp);
+}
+
+static int slim_xfer_msg(struct slim_controller *ctrl,
+			struct slim_device *sbdev, struct slim_val_inf *msg,
+			u8 mc)
+{
+	DEFINE_SLIM_LDEST_TXN(txn_stack, mc, 6, sbdev->laddr, msg);
+	struct slim_msg_txn *txn = &txn_stack;
+	int ret;
+	unsigned long flags;
+	u16 sl, cur;
+	bool tid_txn, async = false;
+	DECLARE_COMPLETION_ONSTACK(complete);
+
+	ret = slim_val_inf_sanity(msg, mc);
+	if (ret) {
+		pr_err("Sanity check failed for msg:offset:0x%x, mc:%d",
+				msg->start_offset, mc);
+		return ret;
+	}
+
+	tid_txn = slim_tid_txn(mc);
+
+	sl = slim_slicesize(msg->num_bytes);
+	dev_err(&ctrl->dev, "SB xfer msg:os:%x, len:%d, MC:%x, sl:%x\n",
+				msg->start_offset, msg->num_bytes, mc, sl);
+
+	cur = slim_slicecodefromsize(sl);
+	txn->ec = ((sl | (1 << 3)) | ((msg->start_offset & 0xFFF) << 4));
+
+	if (!msg->comp_cb && tid_txn) {
+		msg->comp_cb = slim_sync_default_cb;
+		msg->ctx = &complete;
+	} else
+		async = true;
+
+	if (mc == SLIM_MSG_MC_REQUEST_CHANGE_VALUE ||
+		mc == SLIM_MSG_MC_CHANGE_VALUE ||
+		mc == SLIM_MSG_MC_REQUEST_CLEAR_INFORMATION ||
+		mc == SLIM_MSG_MC_CLEAR_INFORMATION)
+		txn->rl += msg->num_bytes;
+	if (tid_txn)
+		txn->rl++;
+
+	ret = slim_processtxn(ctrl, txn);
+
+	/* sync read */
+	if (!ret && tid_txn && !async) {
+		ret = wait_for_completion_timeout(&complete, HZ);
+		if (!ret)
+			ret = -ETIMEDOUT;
+		else
+			ret = 0;
+	}
+
+	if (ret && tid_txn) {
+		spin_lock_irqsave(&ctrl->txn_lock, flags);
+		/* Invalidate the transaction */
+		ctrl->txnt[txn->tid] = NULL;
+		spin_unlock_irqrestore(&ctrl->txn_lock, flags);
+	}
+	if (ret)
+		pr_err("slimbus transfer error:%d:offset:0x%x, MC:%d", ret,
+					msg->start_offset, mc);
+	if (!async && tid_txn) {
+		msg->comp_cb = NULL;
+		msg->ctx = NULL;
+	}
+	return ret;
+}
+EXPORT_SYMBOL(slim_xfer_msg);
+
+/* Message APIs Unicast message APIs used by slimbus slave drivers */
+
+/*
+ * Message API access routines.
+ * @sb: client handle requesting elemental message reads, writes.
+ * @msg: Input structure for start-offset, number of bytes to read.
+ * context: can sleep
+ * Returns:
+ * -EINVAL: Invalid parameters
+ * -ETIMEDOUT: If controller could not complete the request. This may happen if
+ *  the bus lines are not clocked, controller is not powered-on, slave with
+ *  given address is not enumerated/responding.
+ */
+int slim_request_val_element(struct slim_device *sb,
+				struct slim_val_inf *msg)
+{
+	struct slim_controller *ctrl = sb->ctrl;
+
+	if (!ctrl)
+		return -EINVAL;
+	return slim_xfer_msg(ctrl, sb, msg, SLIM_MSG_MC_REQUEST_VALUE);
+}
+EXPORT_SYMBOL(slim_request_val_element);
+
+int slim_request_inf_element(struct slim_device *sb,
+				struct slim_val_inf *msg)
+{
+	struct slim_controller *ctrl = sb->ctrl;
+
+	if (!ctrl)
+		return -EINVAL;
+	return slim_xfer_msg(ctrl, sb, msg, SLIM_MSG_MC_REQUEST_INFORMATION);
+}
+EXPORT_SYMBOL(slim_request_inf_element);
+
+int slim_change_val_element(struct slim_device *sb, struct slim_val_inf *msg)
+{
+	struct slim_controller *ctrl = sb->ctrl;
+
+	if (!ctrl)
+		return -EINVAL;
+	return slim_xfer_msg(ctrl, sb, msg, SLIM_MSG_MC_CHANGE_VALUE);
+}
+EXPORT_SYMBOL(slim_change_val_element);
+
+int slim_clear_inf_element(struct slim_device *sb, struct slim_val_inf *msg)
+{
+	struct slim_controller *ctrl = sb->ctrl;
+
+	if (!ctrl)
+		return -EINVAL;
+	return slim_xfer_msg(ctrl, sb, msg, SLIM_MSG_MC_CLEAR_INFORMATION);
+}
+EXPORT_SYMBOL(slim_clear_inf_element);
+
+int slim_request_change_val_element(struct slim_device *sb,
+					struct slim_val_inf *msg)
+{
+	struct slim_controller *ctrl = sb->ctrl;
+
+	if (!ctrl)
+		return -EINVAL;
+	return slim_xfer_msg(ctrl, sb, msg, SLIM_MSG_MC_REQUEST_CHANGE_VALUE);
+}
+EXPORT_SYMBOL(slim_request_change_val_element);
+
+int slim_request_clear_inf_element(struct slim_device *sb,
+					struct slim_val_inf *msg)
+{
+	struct slim_controller *ctrl = sb->ctrl;
+
+	if (!ctrl)
+		return -EINVAL;
+	return slim_xfer_msg(ctrl, sb, msg,
+					SLIM_MSG_MC_REQUEST_CLEAR_INFORMATION);
+}
+EXPORT_SYMBOL(slim_request_clear_inf_element);
+
 #if IS_ENABLED(CONFIG_OF)
 /* OF helpers for SLIMbus */
 int of_register_slim_devices(struct slim_controller *ctrl)
diff --git a/include/linux/slimbus.h b/include/linux/slimbus.h
index 61b7c74..1d98c58 100644
--- a/include/linux/slimbus.h
+++ b/include/linux/slimbus.h
@@ -34,6 +34,7 @@ extern struct bus_type slimbus_type;
 #define SLIM_FRM_SLOTS_PER_SUPERFRAME	16
 #define SLIM_GDE_SLOTS_PER_SUPERFRAME	2
 
+#define SLIM_MAX_TXNS			256
 struct slim_controller;
 struct slim_device;
 
@@ -97,12 +98,67 @@ struct slim_addrt {
 #define SLIM_MSG_MC_ASSIGN_LOGICAL_ADDRESS       0x2
 #define SLIM_MSG_MC_REPORT_ABSENT                0xF
 
+/* Information Element management messages */
+#define SLIM_MSG_MC_REQUEST_INFORMATION          0x20
+#define SLIM_MSG_MC_REQUEST_CLEAR_INFORMATION    0x21
+#define SLIM_MSG_MC_REPLY_INFORMATION            0x24
+#define SLIM_MSG_MC_CLEAR_INFORMATION            0x28
+#define SLIM_MSG_MC_REPORT_INFORMATION           0x29
+
+/* Value Element management messages */
+#define SLIM_MSG_MC_REQUEST_VALUE                0x60
+#define SLIM_MSG_MC_REQUEST_CHANGE_VALUE         0x61
+#define SLIM_MSG_MC_REPLY_VALUE                  0x64
+#define SLIM_MSG_MC_CHANGE_VALUE                 0x68
+
 /* Destination type Values */
 #define SLIM_MSG_DEST_LOGICALADDR	0
 #define SLIM_MSG_DEST_ENUMADDR		1
 #define	SLIM_MSG_DEST_BROADCAST		3
 
 /*
+ * struct slim_val_inf: Slimbus value or information element
+ * @start_offset: Specifies starting offset in information/value element map
+ * @num_bytes: upto 16. This ensures that the message will fit the slicesize
+ *		per slimbus spec
+ * @comp_cb: Callback if this read/write is asynchronous
+ * @ctx: Argument for comp_cb
+ */
+struct slim_val_inf {
+	u16			start_offset;
+	u8			num_bytes;
+	u8			*rbuf;
+	const u8		*wbuf;
+	void			(*comp_cb)(void *ctx);
+	void			*ctx;
+};
+
+/*
+ * struct slim_msg_txn: Message to be sent by the controller.
+ * This structure has packet header, payload and buffer to be filled (if any)
+ * @rl: Header field. remaining length.
+ * @mt: Header field. Message type.
+ * @mc: Header field. LSB is message code for type mt.
+ * @dt: Header field. Destination type.
+ * @ec: Element code. Used for elemental access APIs.
+ * @len: Length of payload. (excludes ec)
+ * @tid: Transaction ID. Used for messages expecting response.
+ *	(relevant for message-codes involving read operation)
+ * @la: Logical address of the device this message is going to.
+ *	(Not used when destination type is broadcast.)
+ * @msg: Elemental access message to be read/written
+ */
+struct slim_msg_txn {
+	u8			rl;
+	u8			mt;
+	u8			mc;
+	u8			dt;
+	u16			ec;
+	u8			tid;
+	u8			la;
+	struct slim_val_inf	*msg;
+};
+/*
  * struct slim_controller: Controls every instance of SLIMbus
  *				(similar to 'master' on SPI)
  *	'Manager device' is responsible for  device management, bandwidth
@@ -137,6 +193,9 @@ struct slim_addrt {
  * @num_dev: Number of active slimbus slaves on this bus
  * @devs: List of devices on this controller
  * @wq: Workqueue per controller used to notify devices when they report present
+ * @txnt: Table of transactions having transaction ID
+ * @txn_lock: Lock to protect table of transactions
+ * @last_tid: size of the table txnt (can't grow beyond 256 since TID is 8-bits)
  * @dev_released: completion used to signal when sysfs has released this
  *	controller so that it can be deleted during shutdown
  * @xfer_msg: Transfer a message on this controller (this can be a broadcast
@@ -163,7 +222,12 @@ struct slim_controller {
 	u8			num_dev;
 	struct list_head	devs;
 	struct workqueue_struct *wq;
+	struct slim_val_inf	*txnt[SLIM_MAX_TXNS];
+	u8			last_tid;
+	spinlock_t		txn_lock;
 	struct completion	dev_released;
+	int			(*xfer_msg)(struct slim_controller *ctrl,
+				struct slim_msg_txn *txn);
 	int			(*set_laddr)(struct slim_controller *ctrl,
 				struct slim_eaddr *ea, u8 laddr);
 	int			(*get_laddr)(struct slim_controller *ctrl,
@@ -409,4 +473,64 @@ static inline void slim_set_clientdata(struct slim_device *dev, void *data)
 	dev_set_drvdata(&dev->dev, data);
 }
 
+/* Message APIs Unicast message APIs used by slimbus slave drivers */
+
+/*
+ * Message API access routines for value elements.
+ * @sb: client handle requesting elemental message reads, writes.
+ * @msg: Input structure for start-offset, number of bytes to read.
+ * context: can sleep
+ * Returns:
+ * -EINVAL: Invalid parameters
+ * -ETIMEDOUT: If controller could not complete the request. This may happen if
+ *  the bus lines are not clocked, controller is not powered-on, slave with
+ *  given address is not enumerated/responding.
+ */
+extern int slim_request_val_element(struct slim_device *sb,
+					struct slim_val_inf *msg);
+extern int slim_change_val_element(struct slim_device *sb,
+					struct slim_val_inf *msg);
+extern int slim_request_change_val_element(struct slim_device *sb,
+					struct slim_val_inf *msg);
+
+
+/*
+ * Message API access routines for information elements.
+ * @sb: client handle requesting elemental message reads, writes.
+ * @msg: Input structure for start-offset, number of bytes to read
+ *	wbuf will contain information element(s) bit masks to be cleared.
+ *	rbuf will return what the information element value was
+ */
+
+extern int slim_request_inf_element(struct slim_device *sb,
+					struct slim_val_inf *msg);
+extern int slim_clear_inf_element(struct slim_device *sb,
+					struct slim_val_inf *msg);
+extern int slim_request_clear_inf_element(struct slim_device *sb,
+					struct slim_val_inf *msg);
+
+/*
+ * slim_msg_response: Deliver Message response received from a device to the
+ *	framework.
+ * @ctrl: Controller handle
+ * @reply: Reply received from the device
+ * @len: Length of the reply
+ * @tid: Transaction ID received with which framework can associate reply.
+ * Called by controller to inform framework about the response received.
+ * This helps in making the API asynchronous, and controller-driver doesn't need
+ * to manage 1 more table other than the one managed by framework mapping TID
+ * with buffers
+ */
+extern void slim_msg_response(struct slim_controller *ctrl, u8 *reply, u8 tid,
+				u8 len);
+
+/* end of message apis */
+
+static inline bool slim_tid_txn(u8 mc)
+{
+	return (mc == SLIM_MSG_MC_REQUEST_INFORMATION ||
+		mc == SLIM_MSG_MC_REQUEST_CLEAR_INFORMATION ||
+		mc == SLIM_MSG_MC_REQUEST_VALUE ||
+		mc == SLIM_MSG_MC_REQUEST_CLEAR_INFORMATION);
+}
 #endif /* _LINUX_SLIMBUS_H */
-- 
1.8.2.1

  parent reply	other threads:[~2015-06-14  5:50 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-06-14  5:49 [PATCH 0/3] Introduce framework for SLIMbus device drivers Sagar Dharia
2015-06-14  5:49 ` [PATCH 1/3] SLIMbus: Device management on SLIMbus Sagar Dharia
2015-06-15 10:54   ` Mark Brown
2015-06-16 15:22     ` Sagar Dharia
2015-06-17 11:45       ` Mark Brown
2015-06-17 17:10         ` Sagar Dharia
2015-06-18 21:23   ` Srinivas Kandagatla
2015-06-19  3:48     ` Sagar Dharia
2015-06-14  5:49 ` [PATCH 2/3] of/slimbus: OF helper for SLIMbus Sagar Dharia
2015-06-15 10:55   ` Mark Brown
2015-06-14  5:49 ` Sagar Dharia [this message]
2015-06-15 11:08   ` [PATCH 3/3] slimbus: Add messaging APIs to slimbus framework Mark Brown
2015-06-14 15:32 ` [PATCH 0/3] Introduce framework for SLIMbus device drivers Greg KH
2015-06-15 11:27   ` Mark Brown

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1434260958-13732-4-git-send-email-sdharia@codeaurora.org \
    --to=sdharia@codeaurora.org \
    --cc=agross@codeaurora.org \
    --cc=alan@linux.intel.com \
    --cc=andreas.noever@gmail.com \
    --cc=bp@suse.de \
    --cc=broonie@kernel.org \
    --cc=daniel.thompson@linaro.org \
    --cc=daniel@ffwll.ch \
    --cc=davem@davemloft.net \
    --cc=gong.chen@linux.intel.com \
    --cc=gregkh@linuxfoundation.org \
    --cc=james.hogan@imgtec.com \
    --cc=jkosina@suse.cz \
    --cc=joe@perches.com \
    --cc=kheitke@audience.com \
    --cc=linux-arm-msm@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mathieu.poirier@linaro.org \
    --cc=mbutler@audience.com \
    --cc=michael.opdenacker@free-electrons.com \
    --cc=mlocke@codeaurora.org \
    --cc=nkaje@codeaurora.org \
    --cc=oded.gabbay@amd.com \
    --cc=poeschel@lemonage.de \
    --cc=santosh.shilimkar@ti.com \
    --cc=sharon.dvir1@mail.huji.ac.il \
    --cc=treding@nvidia.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.