Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 26293589 authored by Chris Lew's avatar Chris Lew
Browse files

soc: qcom: Introduce QMI helpers



Drivers that needs to communicate with a remote QMI service all has to
perform the operations of discovering the service, encoding and decoding
the messages and operate the socket. This introduces an abstraction for
these common operations, reducing most of the duplication in such cases.

Change-Id: I937a35d631280843c0d9e13a7a4e103c35b3905b
Signed-off-by: default avatarBjorn Andersson <bjorn.andersson@linaro.org>
Patch-mainline: linux-arm-msm @ 15/11/2017 12:10
[clew@codeaurora.org: Bring downstream up to date by merging differences
 between v1 and v3 patchsets from "soc: qcom: Introduce QMI helpers"]
Signed-off-by: default avatarChris Lew <clew@codeaurora.org>
parent 835f3675
Loading
Loading
Loading
Loading
+533 −224

File changed.

Preview size limit exceeded, changes collapsed.

+81 −61
Original line number Diff line number Diff line
@@ -14,12 +14,8 @@
#ifndef __QMI_HELPERS_H__
#define __QMI_HELPERS_H__

#include <linux/idr.h>
#include <linux/qrtr.h>
#include <linux/types.h>
#include <linux/mutex.h>
#include <linux/workqueue.h>
#include <linux/completion.h>

/**
 * qmi_header - wireformat header of QMI messages
@@ -103,74 +99,68 @@ struct qmi_elem_info {
 * @error:	error value, when @result is QMI_RESULT_FAILURE_V01
 */
struct qmi_response_type_v01 {
	u32 result;
	u32 error;
	u16 result;
	u16 error;
};

extern struct qmi_elem_info qmi_response_type_v01_ei[];

/**
 * struct qrtr_service - context to track lookup-results
 * struct qmi_service - context to track lookup-results
 * @service:	service type
 * @version:	version of the @service
 * @instance:	instance id of the @service
 * @node:	node of the service
 * @port:	port of the service
 * @cookie:	handle for client's use
 * @priv:	handle for client's use
 * @list_node:	list_head for house keeping
 */
struct qrtr_service {
struct qmi_service {
	unsigned int service;
	unsigned int version;
	unsigned int instance;

	unsigned int node;
	unsigned int port;

	void *cookie;
	void *priv;
	struct list_head list_node;
};

struct qrtr_handle;
struct qmi_handle;

/**
 * struct qrtr_handle_ops - callbacks from qrtr_handle
 * @new_server:		invoked as a new_server message arrives
 * @del_server:		invoked as a del_server message arrives
 * @net_reset:		invoked as the name server is restarted
 * @msg_handler:	invoked as a non-control message arrives
 * struct qmi_ops - callbacks for qmi_handle
 * @new_server:		inform client of a new_server lookup-result, returning
 *                      successfully from this call causes the library to call
 *                      @del_server as the service is removed from the
 *                      lookup-result. @priv of the qmi_service can be used by
 *                      the client
 * @del_server:		inform client of a del_server lookup-result
 * @net_reset:		inform client that the name service was restarted and
 *                      that and any state needs to be released
 * @msg_handler:	invoked for incoming messages, allows a client to
 *                      override the usual QMI message handler
 * @bye:                inform a client that all clients from a node are gone
 * @del_client:         inform a client that a particular client is gone
 */
struct qrtr_handle_ops {
	int (*new_server)(struct qrtr_handle *, struct qrtr_service *);
	void (*del_server)(struct qrtr_handle *, struct qrtr_service *);
	void (*net_reset)(struct qrtr_handle *);
	void (*msg_handler)(struct qrtr_handle *, struct sockaddr_qrtr *,
			    const void *, size_t);
struct qmi_ops {
	int (*new_server)(struct qmi_handle *qmi, struct qmi_service *svc);
	void (*del_server)(struct qmi_handle *qmi, struct qmi_service *svc);
	void (*net_reset)(struct qmi_handle *qmi);
	void (*msg_handler)(struct qmi_handle *qmi, struct sockaddr_qrtr *sq,
			    const void *data, size_t count);
	void (*bye)(struct qmi_handle *qmi, unsigned int node);
	void (*del_client)(struct qmi_handle *qmi,
			   unsigned int node, unsigned int port);
};

/**
 * struct qrtr_handle - qrtr client context
 * @sock:	socket handle
 * @sq:		sockaddr of @sock
 * @work:	work for handling incoming messages
 * @wq:		workqueue to post @work on
 * @recv_buf:	scratch buffer for handling incoming messages
 * @recv_buf_size:	size of @recv_buf
 * @services:	list of services advertised to the client
 * @ops:	reference to callbacks
 */
struct qrtr_handle {
	struct socket *sock;
	struct sockaddr_qrtr sq;

	struct work_struct work;
	struct workqueue_struct *wq;

	void *recv_buf;
	size_t recv_buf_size;

	struct list_head services;

	struct qrtr_handle_ops ops;
};

/**
 * struct qmi_txn - transaction context
 * @qmi:	QMI handle this transaction is associated with
 * @id:		transaction id
 * @lock:	for synchronization between handler and waiter of messages
 * @completion:	completion object as the transaction receives a response
 * @result:	result code for the completed transaction
 * @ei:		description of the QMI encoded response (optional)
@@ -181,6 +171,7 @@ struct qmi_txn {

	int id;

	struct mutex lock;
	struct completion completion;
	int result;

@@ -208,14 +199,39 @@ struct qmi_msg_handler {
};

/**
 * struct qmi_handle - QMI client handle
 * @qrtr:	qrtr handle backing the QMI client
 * struct qmi_handle - QMI context
 * @sock:	socket handle
 * @sock_lock:	synchronization of @sock modifications
 * @sq:		sockaddr of @sock
 * @work:	work for handling incoming messages
 * @wq:		workqueue to post @work on
 * @recv_buf:	scratch buffer for handling incoming messages
 * @recv_buf_size:	size of @recv_buf
 * @lookups:		list of registered lookup requests
 * @lookup_results:	list of lookup-results advertised to the client
 * @services:		list of registered services (by this client)
 * @ops:	reference to callbacks
 * @txns:	outstanding transactions
 * @txn_lock:	lock for modifications of @txns
 * @handlers:	list of handlers for incoming messages
 */
struct qmi_handle {
	struct qrtr_handle qrtr;
	struct socket *sock;
	struct mutex sock_lock;

	struct sockaddr_qrtr sq;

	struct work_struct work;
	struct workqueue_struct *wq;

	void *recv_buf;
	size_t recv_buf_size;

	struct list_head lookups;
	struct list_head lookup_results;
	struct list_head services;

	struct qmi_ops ops;

	struct idr txns;
	struct mutex txn_lock;
@@ -223,20 +239,24 @@ struct qmi_handle {
	struct qmi_msg_handler *handlers;
};

int qrtr_client_init(struct qrtr_handle *qrtr, size_t recv_buf_size,
		     struct qrtr_handle_ops *ops);
void qrtr_client_release(struct qrtr_handle *qrtr);
int qrtr_client_new_lookup(struct qrtr_handle *qrtr,
			   unsigned int service, unsigned int instance);
int qmi_add_lookup(struct qmi_handle *qmi, unsigned int service,
		   unsigned int version, unsigned int instance);
int qmi_add_server(struct qmi_handle *qmi, unsigned int service,
		   unsigned int version, unsigned int instance);

int qmi_client_init(struct qmi_handle *qmi, size_t max_msg_len,
		    struct qmi_msg_handler *handlers);
void qmi_client_release(struct qmi_handle *qmi);
int qmi_handle_init(struct qmi_handle *qmi, size_t max_msg_len,
		    struct qmi_ops *ops, struct qmi_msg_handler *handlers);
void qmi_handle_release(struct qmi_handle *qmi);

ssize_t qmi_send_message(struct qmi_handle *qmi,
			 struct sockaddr_qrtr *sq, struct qmi_txn *txn,
			 int type, int msg_id, size_t len,
ssize_t qmi_send_request(struct qmi_handle *qmi, struct sockaddr_qrtr *sq,
			 struct qmi_txn *txn, int msg_id, size_t len,
			 struct qmi_elem_info *ei, const void *c_struct);
ssize_t qmi_send_response(struct qmi_handle *qmi, struct sockaddr_qrtr *sq,
			  struct qmi_txn *txn, int msg_id, size_t len,
			  struct qmi_elem_info *ei, const void *c_struct);
ssize_t qmi_send_indication(struct qmi_handle *qmi, struct sockaddr_qrtr *sq,
			    int msg_id, size_t len, struct qmi_elem_info *ei,
			    const void *c_struct);

void *qmi_encode_message(int type, unsigned int msg_id, size_t *len,
			 unsigned int txn_id, struct qmi_elem_info *ei,