123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520 |
- 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.
|