M7350/kernel/Documentation/arm/msm/msm_qmi.txt
2024-09-09 08:57:42 +00:00

520 lines
18 KiB
Plaintext

Introduction
============
Qualcomm 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 dafault.
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.