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

Commit fafd67f1 authored by Karthikeyan Ramasubramanian's avatar Karthikeyan Ramasubramanian Committed by Gerrit - the friendly Code Review server
Browse files

soc: qcom: Add snapshot of QMI



This snapshot is taken as of msm-4.4 'commit <d2afad6a903b>
("Merge "ext4 crypto: enable HW based encryption with ICE"")'.

Fix the code style warnings and errors.

CRs-Fixed: 1079350
Change-Id: I7dfcaac6dd2f97b109793aee97db6e9951282194
Signed-off-by: default avatarKarthikeyan Ramasubramanian <kramasub@codeaurora.org>
parent 992e5a55
Loading
Loading
Loading
Loading
+520 −0
Original line number Diff line number Diff line
Introduction
============

Qualcomm Technologies, Inc. MSM Interface(QMI) is a messaging format used
to communicate between software components in the modem and other
peripheral subsystems. This document proposes an architecture to introduce
the QMI messaging into the kernel. This document proposes introducing a
QMI encode/decode library to enable QMI message marshaling and an
interface library to enable sending and receiving QMI messages through
MSM IPC Router.

Hardware description
====================

QMI is a messaging format used to interface with the components in modem
and other subsystems. QMI does not drive or manage any hardware resources.

Software description
====================
QMI communication is based on a client-server model, where clients and
servers exchange messages in QMI wire format. A module can act as a client
of any number of QMI services and a QMI service can serve any number of
clients.

QMI communication is of request/response type or an unsolicited event type.
QMI client driver sends a request to a QMI service and receives a response.
QMI client driver registers with the QMI service to receive indications
regarding a system event and the QMI service sends the indications to the
client when the event occurs in the system.

The wire format of QMI message is as follows:

   ----------------------------------------------------
   |  QMI Header  |  TLV 0  |  TLV 1  | ... |  TLV N  |
   ----------------------------------------------------

QMI Header:
-----------
   --------------------------------------------------------
   | Flags | Transaction ID | Message ID | Message Length |
   --------------------------------------------------------

The flags field is used to indicate the kind of QMI message - request,
response or indication. The transaction ID is a client specific field
to uniquely match the QMI request and the response. The message ID is
also a client specific field to indicate the kind of information present
in the QMI payload. The message length field holds the size information
of the QMI payload.

Flags:
------
  * 0 - QMI Request
  * 2 - QMI Response
  * 4 - QMI Indication

TLV:
----
QMI payload is represented using a series of Type, Length and Value fields.
Each information being passed is encoded into a type, length and value
combination. The type element identifies the type of information being
encoded. The length element specifies the length of the information/values
being encoded. The information can be of a primitive type or a structure
or an array.

    -------------------------------------------
    | Type | Length | Value 0 | ... | Value N |
    -------------------------------------------

QMI Message Marshaling and Transport:
-------------------------------------
QMI encode/decode library is designed to encode the kernel C data
structures into QMI wire format and to decode the QMI messages into kernel
C data strcuture format. This library will provide a single interface to
transform any data structure into a QMI message and vice-versa.

QMI interface library is designed to send and receive QMI messages over
IPC Router.


                 ----------------------------------
                 |         Kernel Drivers         |
                 ----------------------------------
                        |                  |
                        |                  |
                -----------------   -----------------
                | QMI Interface |___|  QMI Enc/Dec  |
                |    Library    |   |    Library    |
                -----------------   -----------------
                        |
                        |
               -------------------
               |   IPC Message   |
               |      Router     |
               -------------------
                        |
                        |
                     -------
                     | SMD |
                     -------

Design
======

The design goals of this proposed QMI messaging mechanism are:
    * To enable QMI messaging from within the kernel
    * To provide a common library to marshal QMI messages
    * To provide a common interface library to send/receive QMI messages
    * To support kernel QMI clients which have latency constraints

The reason behind this design decision is:
    * To provide a simple QMI marshaling interface to the kernel users
    * To hide the complexities of QMI message transports
    * To minimize code redundancy

In order to provide a single encode/decode API, the library expects
the kernel drivers to pass the:
    * starting address of the data structure to be encoded/decoded
    * starting address of the QMI message buffer
    * a table containing information regarding the data structure to
      be encoded/decoded

The design is based on the idea that any complex data structure is a
collection of primary data elements. Hence the information about any
data structure can be constructed as an array of information about its
primary data elements. The following structure is defined to describe
information about a primary data element.

/**
 * elem_info - Data structure to specify information about an element
 *             in a data structure. An array of this data structure
 *             can be used to specify info about a complex data
 *             structure to be encoded/decoded.
 * @data_type: Data type of this element
 * @elem_len: Array length of this element, if an array
 * @elem_size: Size of a single instance of this data type
 * @is_array: Array type of this element
 * @tlv_type: QMI message specific type to identify which element
 *            is present in an incoming message
 * @offset: To identify the address of the first instance of this
 *          element in the data structure
 * @ei_array: Array to provide information about the nested structure
 *            within a data structure to be encoded/decoded.
 */
struct elem_info {
    enum elem_type data_type;
    uint32_t elem_len;
    uint32_t elem_size;
    enum array_type is_array;
    uint8_t tlv_type;
    uint32_t offset;
    struct elem_info *ei_array;
};

The alternate design discussions include manual encoding/decoding of QMI
messages. From RPC experience, this approach has mostly been error prone.
This in turn lead to increased development and debugging effort. Another
approach included data-structure specific marshaling API -- i.e. every
data structure to be encoded/decoded should have a unique auto-generated
marshaling API. This approach comes with the cost of code redundancy and
was therefore rejected.

Power Management
================

N/A

SMP/multi-core
==============

The QMI encode/decode library does not access any global or shared data
structures. Hence it does not require any locking mechanisms to ensure
multi-core safety.

The QMI interface library uses mutexes while accessing shared resources.

Security
========

N/A

Performance
===========

This design proposal is to support kernel QMI clients which have latency
constraints. Hence the number and size of QMI messages are expected to be
kept short, in order to achieve latency of less than 1 ms consistently.

Interface
=========

Kernel-APIs:
------------

Encode/Decode Library APIs:
---------------------------

/**
 * elem_type - Enum to identify the data type of elements in a data
 *             structure.
 */
enum elem_type {
    QMI_OPT_FLAG = 1,
    QMI_DATA_LEN,
    QMI_UNSIGNED_1_BYTE,
    QMI_UNSIGNED_2_BYTE,
    QMI_UNSIGNED_4_BYTE,
    QMI_UNSIGNED_8_BYTE,
    QMI_SIGNED_2_BYTE_ENUM,
    QMI_SIGNED_4_BYTE_ENUM,
    QMI_STRUCT,
    QMI_END_OF_TYPE_INFO,
};

/**
 * array_type - Enum to identify if an element in a data structure is
 *              an array. If so, then is it a static length array or a
 *              variable length array.
 */
enum array_type {
    NO_ARRAY = 0,
    STATIC_ARRAY = 1,
    VAR_LEN_ARRAY = 2,
};

/**
 * msg_desc - Describe about the main/outer structure to be
 *            encoded/decoded.
 * @msg_id: Message ID to identify the kind of QMI message.
 * @max_msg_len: Maximum possible length of the QMI message.
 * @ei_array: Array to provide information about a data structure.
 */
struct msg_desc {
    uint16_t msg_id;
    int max_msg_len;
    struct elem_info *ei_array;
};

/**
 * qmi_kernel_encode() - Encode to QMI message wire format
 * @desc: Structure describing the data structure to be encoded.
 * @out_buf: Buffer to hold the encoded QMI message.
 * @out_buf_len: Length of the buffer to hold the QMI message.
 * @in_c_struct: C Structure to be encoded.
 *
 * @return: size of encoded message on success,
 *          -ve value on failure.
 */
int qmi_kernel_encode(struct msg_desc *desc,
                      void *out_buf, uint32_t out_buf_len,
                      void *in_c_struct);

/**
 * qmi_kernel_decode() - Decode to C Structure format
 * @desc: Structure describing the data structure format.
 * @out_c_struct: Buffer to hold the decoded C structure.
 * @in_buf: Buffer containg the QMI message to be decoded.
 * @in_buf_len: Length of the incoming QMI message.
 *
 * @return: 0 on success, -ve value on failure.
 */
int qmi_kernel_decode(struct msg_desc *desc, void *out_c_struct,
                      void *in_buf, uint32_t in_buf_len);

Interface Library APIs:
-----------------------

/**
 * qmi_svc_event_notifier_register() - Register a notifier block to receive
 *                                     events regarding a QMI service
 * @service_id: Service ID to identify the QMI service.
 * @instance_id: Instance ID to identify the instance of the QMI service.
 * @nb: Notifier block used to receive the event.
 *
 * @return: 0 if successfully registered, < 0 on error.
 */
int qmi_svc_event_notifier_register(uint32_t service_id,
                                    uint32_t instance_id,
                                    struct notifier_block *nb);

/**
 * qmi_handle_create() - Create a QMI handle
 * @notify: Callback to notify events on the handle created.
 * @notify_priv: Private info to be passed along with the notification.
 *
 * @return: Valid QMI handle on success, NULL on error.
 */
struct qmi_handle *qmi_handle_create(
    void (*notify)(struct qmi_handle *handle,
                   enum qmi_event_type event, void *notify_priv),
    void *notify_priv);

/**
 * qmi_connect_to_service() - Connect the QMI handle with a QMI service
 * @handle: QMI handle to be connected with the QMI service.
 * @service_id: Service id to identify the QMI service.
 * @instance_id: Instance id to identify the instance of the QMI service.
 *
 * @return: 0 on success, < 0 on error.
 */
int qmi_connect_to_service(struct qmi_handle *handle,
                           uint32_t service_id, uint32_t instance_id);

/**
 * qmi_register_ind_cb() - Register the indication callback function
 * @handle: QMI handle with which the function is registered.
 * @ind_cb: Callback function to be registered.
 * @ind_cb_priv: Private data to be passed with the indication callback.
 *
 * @return: 0 on success, < 0 on error.
 */
int qmi_register_ind_cb(struct qmi_handle *handle,
    void (*ind_cb)(struct qmi_handle *handle,
                   unsigned int msg_id, void *msg,
                   unsigned int msg_len, void *ind_cb_priv),
    void *ind_cb_priv);

/**
 * qmi_send_req_wait() - Send a synchronous QMI request
 * @handle: QMI handle through which the QMI request is sent.
 * @req_desc: Structure describing the request data structure.
 * @req: Buffer containing the request data structure.
 * @req_len: Length of the request data structure.
 * @resp_desc: Structure describing the response data structure.
 * @resp: Buffer to hold the response data structure.
 * @resp_len: Length of the response data structure.
 * @timeout_ms: Timeout before a response is received.
 *
 * @return: 0 on success, < 0 on error.
 */
int qmi_send_req_wait(struct qmi_handle *handle,
                      struct msg_desc *req_desc,
                      void *req, unsigned int req_len,
                      struct msg_desc *resp_desc,
                      void *resp, unsigned int resp_len,
                      unsigned long timeout_ms);

/**
 * qmi_send_req_nowait() - Send an asynchronous QMI request
 * @handle: QMI handle through which the QMI request is sent.
 * @req_desc: Structure describing the request data structure.
 * @req: Buffer containing the request data structure.
 * @req_len: Length of the request data structure.
 * @resp_desc: Structure describing the response data structure.
 * @resp: Buffer to hold the response data structure.
 * @resp_len: Length of the response data structure.
 * @resp_cb: Callback function to be invoked when the response arrives.
 * @resp_cb_data: Private information to be passed along with the callback.
 *
 * @return: 0 on success, < 0 on error.
 */
int qmi_send_req_nowait(struct qmi_handle *handle,
                        struct msg_desc *req_desc,
                        void *req, unsigned int req_len,
                        struct msg_desc *resp_desc,
                        void *resp, unsigned int resp_len,
                        void (*resp_cb)(struct qmi_handle *handle,
                                        unsigned int msg_id, void *msg,
                                        void *resp_cb_data),
                        void *resp_cb_data);

/**
 * qmi_recv_msg() - Receive the QMI message
 * @handle: Handle for which the QMI message has to be received.
 *
 * @return: 0 on success, < 0 on error.
 */
int qmi_recv_msg(struct qmi_handle *handle);

/**
 * qmi_handle_destroy() - Destroy the QMI handle
 * @handle: QMI handle to be destroyed.
 *
 * @return: 0 on success, < 0 on error.
 */
int qmi_handle_destroy(struct qmi_handle *handle);

/**
 * qmi_svc_event_notifier_unregister() - Unregister service event notifier block
 * @service_id: Service ID to identify the QMI service.
 * @instance_id: Instance ID to identify the instance of the QMI service.
 * @nb: Notifier block registered to receive the events.
 *
 * @return: 0 if successfully registered, < 0 on error.
 */
int qmi_svc_event_notifier_unregister(uint32_t service_id,
                                      uint32_t instance_id,
                                      struct notifier_block *nb);

/**
 * qmi_svc_ops_options - Operations and options to be specified when
 *                       a service registers.
 * @version: Version field to identify the ops_options structure.
 * @service_id: Service ID of the service being registered.
 * @instance_id: Instance ID of the service being registered.
 * @connect_cb: Callback when a new client connects with the service.
 * @disconnect_cb: Callback when the client exits the connection.
 * @req_desc_cb: Callback to get request structure and its descriptor
 *               for a message id.
 * @req_cb: Callback to process the request.
 */
struct qmi_svc_ops_options {
	unsigned version;
	uint32_t service_id;
	uint32_t instance_id;
	int (*connect_cb)(struct qmi_handle *handle,
			  struct qmi_svc_clnt *clnt);
	int (*disconnect_cb)(struct qmi_handle *handle,
			     struct qmi_svc_clnt *clnt);
	struct msg_desc *(*req_desc_cb)(unsigned int msg_id,
					void **req,
					unsigned int req_len);
	int (*req_cb)(struct qmi_handle *handle,
		      struct qmi_svc_clnt *clnt,
		      void *req_handle,
		      unsigned int msg_id,
		      void *req);
};

/**
 * qmi_svc_register() - Register a QMI service with a QMI handle
 * @handle: QMI handle on which the service has to be registered.
 * @ops_options: Service specific operations and options.
 *
 * @return: 0 if successfully registered, < 0 on error.
 */
int qmi_svc_register(struct qmi_handle *handle,
		     void *ops_options);

/**
 * qmi_send_resp() - Send response to a request
 * @handle: QMI handle from which the response is sent.
 * @clnt: Client to which the response is sent.
 * @req_handle: Request for which the response is sent.
 * @resp_desc: Descriptor explaining the response structure.
 * @resp: Pointer to the response structure.
 * @resp_len: Length of the response structure.
 *
 * @return: 0 on success, < 0 on error.
 */
int qmi_send_resp(struct qmi_handle *handle,
		  struct qmi_svc_clnt *clnt,
		  void *req_handle,
		  struct msg_desc *resp_desc,
		  void *resp,
		  unsigned int resp_len);

/**
 * qmi_send_ind() - Send unsolicited event/indication to a client
 * @handle: QMI handle from which the indication is sent.
 * @clnt: Client to which the indication is sent.
 * @ind_desc: Descriptor explaining the indication structure.
 * @ind: Pointer to the indication structure.
 * @ind_len: Length of the indication structure.
 *
 * @return: 0 on success, < 0 on error.
 */
int qmi_send_ind(struct qmi_handle *handle,
		 struct qmi_svc_clnt *clnt,
		 struct msg_desc *ind_desc,
		 void *ind,
		 unsigned int ind_len);

/**
 * qmi_svc_unregister() - Unregister the service from a QMI handle
 * @handle: QMI handle from which the service has to be unregistered.
 *
 * return: 0 on success, < 0 on error.
 */
int qmi_svc_unregister(struct qmi_handle *handle);

User-space APIs:
----------------
This proposal is meant only for kernel QMI clients/services and hence no
user-space interface is defined as part of this proposal.

Driver parameters
=================

N/A

Config options
==============

The QMI encode/decode library will be enabled by default in the kernel.
It can be disabled using CONFIG_QMI_ENCDEC kernel config option.

The QMI Interface library will be disabled by default in the kernel,
since it depends on other components which are disabled by default.
It can be enabled using CONFIG_MSM_QMI_INTERFACE kernel config option.

Dependencies
============

The QMI encode/decode library is a stand-alone module and is not
dependent on any other kernel modules.

The QMI Interface library depends on QMI Encode/Decode library and
IPC Message Router.

User space utilities
====================

N/A

Other
=====

N/A

Known issues
============

N/A

To do
=====

Look into the possibility of making QMI Interface Library transport
agnostic. This may involve the kernel drivers to register the transport,
with the QMI Interface Library, to be used for transporting QMI messages.
+10 −0
Original line number Diff line number Diff line
@@ -354,3 +354,13 @@ config MSM_IPC_ROUTER_GLINK_XPRT
	  a System-on-Chip(SoC). When the GLINK channels become available,
	  this layer registers a transport with IPC Router and enable
	  message exchange.

config MSM_QMI_INTERFACE
	depends on IPC_ROUTER
	depends on QMI_ENCDEC
	bool "MSM QMI Interface Library"
	help
	  Library to send and receive QMI messages over IPC Router.
	  This library provides interface functions to the kernel drivers
	  to perform QMI message marshaling and transport them over IPC
	  Router.
+1 −0
Original line number Diff line number Diff line
@@ -38,3 +38,4 @@ obj-$(CONFIG_MSM_IPC_ROUTER_SMD_XPRT) += ipc_router_smd_xprt.o
obj-$(CONFIG_MSM_IPC_ROUTER_HSIC_XPRT) += ipc_router_hsic_xprt.o
obj-$(CONFIG_MSM_IPC_ROUTER_MHI_XPRT) += ipc_router_mhi_xprt.o
obj-$(CONFIG_MSM_IPC_ROUTER_GLINK_XPRT) += ipc_router_glink_xprt.o
obj-$(CONFIG_MSM_QMI_INTERFACE) += qmi_interface.o
+2232 −0

File added.

Preview size limit exceeded, changes collapsed.

+123 −0
Original line number Diff line number Diff line
/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
 * only version 2 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

#ifndef _QMI_INTERFACE_PRIV_H_
#define _QMI_INTERFACE_PRIV_H_

#include <linux/types.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/list.h>
#include <linux/socket.h>
#include <linux/gfp.h>
#include <linux/platform_device.h>
#include <linux/qmi_encdec.h>

#include <soc/qcom/msm_qmi_interface.h>

enum txn_type {
	QMI_SYNC_TXN = 1,
	QMI_ASYNC_TXN,
};

/**
 * handle_type - Enum to identify QMI handle type
 */
enum handle_type {
	QMI_CLIENT_HANDLE = 1,
	QMI_SERVICE_HANDLE,
};

struct qmi_txn {
	struct list_head list;
	uint16_t txn_id;
	enum txn_type type;
	struct qmi_handle *handle;
	void *enc_data;
	unsigned int enc_data_len;
	struct msg_desc *resp_desc;
	void *resp;
	unsigned int resp_len;
	int resp_received;
	int send_stat;
	void (*resp_cb)(struct qmi_handle *handle, unsigned int msg_id,
			void *msg, void *resp_cb_data, int stat);
	void *resp_cb_data;
	wait_queue_head_t wait_q;
};

/**
 * svc_addr - Data structure to maintain a list of service addresses.
 * @list_node: Service address list node used by "svc_addr_list"
 * @port_addr: Service address in <node_id:port_id>.
 */
struct svc_addr {
	struct list_head list_node;
	struct msm_ipc_port_addr port_addr;
};

/**
 * svc_event_nb - Service event notification structure.
 * @nb_lock: Spinlock for the notifier block lists.
 * @service_id: Service id for which list of notifier blocks are maintained.
 * @instance_id: Instance id for which list of notifier blocks are maintained.
 * @svc_event_rcvr_list: List of notifier blocks which clients have registered.
 * @list: Used to chain this structure in a global list.
 * @svc_addr_list_lock: Lock to protect @svc_addr_list.
 * @svc_addr_list: List for mantaining all the address for a specific
 *			<service_id:instance_id>.
 */
struct svc_event_nb {
	spinlock_t nb_lock;
	uint32_t service_id;
	uint32_t instance_id;
	struct raw_notifier_head svc_event_rcvr_list;
	struct list_head list;
	struct mutex svc_addr_list_lock;
	struct list_head svc_addr_list;
};

/**
 * req_handle - Data structure to store request information
 * @list: Points to req_handle_list maintained per connection.
 * @conn_h: Connection handle on which the concerned request is received.
 * @msg_id: Message ID of the request.
 * @txn_id: Transaction ID of the request.
 */
struct req_handle {
	struct list_head list;
	struct qmi_svc_clnt_conn *conn_h;
	uint16_t msg_id;
	uint16_t txn_id;
};

/**
 * qmi_svc_clnt_conn - Data structure to identify client service connection
 * @list: List to chain up the client conncection to the connection list.
 * @svc_handle: Service side information of the connection.
 * @clnt_addr: Client side information of the connection.
 * @clnt_addr_len: Length of the client address.
 * @req_handle_list: Pending requests in this connection.
 * @pending_tx_list: Pending response/indications awaiting flow control.
 */
struct qmi_svc_clnt_conn {
	struct list_head list;
	void *svc_handle;
	void *clnt_addr;
	size_t clnt_addr_len;
	struct list_head req_handle_list;
	struct delayed_work resume_tx_work;
	struct list_head pending_txn_list;
	struct mutex pending_txn_lock;
};

#endif
Loading