1240 lines
60 KiB
Plaintext
1240 lines
60 KiB
Plaintext
|
Introduction
|
||
|
============
|
||
|
|
||
|
G-Link, short for Generic Link, is a generic link-layer transport that supports
|
||
|
a plug-in framework for physical transports. This allows it to adapt to
|
||
|
different physical transports such as shared memory, UARTs, buses, and DMA.
|
||
|
|
||
|
It is designed to enable zero copy, is power aware, and supports version and
|
||
|
feature negotiation to enable phased upgrades. The design is symmetrical with
|
||
|
the same high-level design and the same client API across all subsystems
|
||
|
regardless of OS.
|
||
|
|
||
|
Hardware description
|
||
|
====================
|
||
|
|
||
|
The hardware is managed by the transport plug-in. In the initial
|
||
|
driver version, this is done by the SMEM Native Transport which requires
|
||
|
shared memory and an interrupt in each direction between the local and remote
|
||
|
subsystems. This transport is a replacement for SMD.
|
||
|
|
||
|
Software description
|
||
|
=================================
|
||
|
|
||
|
G-Link consists of:
|
||
|
* Client API
|
||
|
* Core that implements the high-level protocol
|
||
|
* Transport plug-ins that handle translation of the high-level protocol to wire
|
||
|
format
|
||
|
|
||
|
The below diagram shows the organization of G-Link. Clients use G-Link to
|
||
|
interface with the Transport Plug-in, which interfaces directly with the
|
||
|
physical transport. The G-Link component is shown in further detail in the
|
||
|
"Design" section.
|
||
|
|
||
|
+-----------+ +---------+ +-----------+
|
||
|
| G-Link |---->|Transport|----->| Physical |
|
||
|
| |<----| Plug-in |<-----| Transport |
|
||
|
+-----------+ +---------+ +-----------+
|
||
|
|
||
|
Design
|
||
|
======
|
||
|
|
||
|
G-Link is conceptually broken down into a command and data queue. The command
|
||
|
queue is used to pass commands for synchronizing buffer status, channel state,
|
||
|
and for the equivalent of packet headers. The data queue is reserved for raw
|
||
|
client data.
|
||
|
|
||
|
For every packet in the data queue, there is at least one command
|
||
|
that acts as the packet header that goes through the command queue. This
|
||
|
separation is necessary to support the zero-copy use case for data packets and
|
||
|
for DMA-type transports that need to have the transfer size known ahead of time.
|
||
|
|
||
|
For copy-based transports, the command and data transports can be merged
|
||
|
together in the transport plug-in resulting in traditional packet headers like
|
||
|
we have today in other common protocols such as IP.
|
||
|
|
||
|
As shown in the diagram below, the client itself communicates directly with the
|
||
|
G-Link core, and uses the Transport Interface and the G-Link Core interface to
|
||
|
create the transport plug-in.
|
||
|
|
||
|
+-----------+
|
||
|
+------+ +---------+ | |
|
||
|
| |<---|Transport|-| |
|
||
|
+-------+ | | | IF | | |
|
||
|
|Clients|<-->| | +---------+ | Transport |
|
||
|
+-------+ |G-Link| | Plug-in |
|
||
|
| Core | | |
|
||
|
| | +-------+ | |
|
||
|
| |-|G-Link |----->| |
|
||
|
| | |Core IF| | |
|
||
|
+------+ +-------+ | |
|
||
|
+-----------+
|
||
|
|
||
|
A channel is a discrete data pipe used by a client to communicate with a
|
||
|
remote system. All channels are multiplexed onto one or more physical
|
||
|
transports.
|
||
|
|
||
|
A receive intent is queued by a client to indicate that it is ready to receive
|
||
|
a packet up to the specified size. The intent is sent to the remote side to
|
||
|
let clients know that they can transmit and expect the client to be able to
|
||
|
process it.
|
||
|
|
||
|
Intents provide back-pressure to transmitting clients and remove the
|
||
|
requirement for flow control. In addition, the intent size is used for
|
||
|
copy-based transports to either reserve buffer space or allocate buffers to
|
||
|
receive data to prevent blocking the underlying transport. Multiple intents
|
||
|
can be queued.
|
||
|
|
||
|
Transport Plug-in
|
||
|
-----------------
|
||
|
The transport plug-in is responsible for marshaling data and commands between
|
||
|
the G-Link core and the physical transport. If the remote side is not running
|
||
|
G-Link, then the transport plug-in will be more complex and will handle
|
||
|
translating G-Link core commands and data into the proper protocol to
|
||
|
interact with the remote system.
|
||
|
|
||
|
Client API
|
||
|
----------
|
||
|
The API into the G-Link core is asynchronous by default, but may have blocking
|
||
|
variants. If necessary, a thin client layer can be built on top of the
|
||
|
asynchronous API to create a synchronous API for clients. All client
|
||
|
notifications are serialized to ensure in-order notification of events.
|
||
|
|
||
|
The G-Link client API includes the following functions for the following
|
||
|
operations. Details of each function are described later in this section.
|
||
|
* glink_open() - Open a G-Link channel
|
||
|
* glink_close() - Close a G-Link channel
|
||
|
* glink_tx() - Transmit data
|
||
|
* glink_txv() - Transmit a buffer chain
|
||
|
* glink_queue_rx_intent() - Queue a receive intent
|
||
|
* glink_rx_done() - Signal consumption of the receive buffer
|
||
|
* glink_sigs_set() - Set a 32-bit signal field for client-specific signaling.
|
||
|
Standard TIOCM bits are reserved in the upper bits of the
|
||
|
field as a conviencence for users, but they are 100
|
||
|
percent pass-through.
|
||
|
* glink_sigs_local_get() - Get the local 32-bit control signal field
|
||
|
* glink_sigs_remote_get() - Get the remote 32-bit control signal field
|
||
|
|
||
|
The TIOCM bitmasks are defined as follows:
|
||
|
#define SMD_CTR_SIG_SHFT 31
|
||
|
#define SMD_CTS_SIG_SHFT 30
|
||
|
#define SMD_CD_SIG_SHFT 29
|
||
|
#define SMD_RI_SIG_SHFT 28
|
||
|
|
||
|
When a channel is opened by a client, the client provides an open
|
||
|
configuration to the G-Link core as a parameter to the glink_open() function.
|
||
|
This open configuration contains the following information:
|
||
|
* The name of the transport (optional)
|
||
|
* The name of the edge (remote processor)
|
||
|
* The name of the channel
|
||
|
|
||
|
The open configuration also contains function pointers for the following
|
||
|
operations, which are defined by the client:
|
||
|
* notify_rx() - Notify the client that data has been received
|
||
|
* notify_rxv() - Notify the client that vector data has been received
|
||
|
* notify_tx_done() - Notify the client that data has been transmitted
|
||
|
* notify_state() - Notify the client that the channel's state has changed
|
||
|
* notify_rx_intent_req() - Notify the client whether their request for a
|
||
|
receive intent was granted
|
||
|
* notify_rx_sigs() - Notify the client that there has been a change in the
|
||
|
state of the remote side's control signals
|
||
|
* notify_rx_abort() - During channel close, return structures associated
|
||
|
with receive intents to the client
|
||
|
* notify_tx_abort() - During channel close, return structures associated
|
||
|
with TX packets to the client
|
||
|
* notify_rx_tracer_pkt() - Notify the client that a tracer packet has been
|
||
|
received
|
||
|
|
||
|
Buffer ownership is transferred between the local G-Link and the remote G-Link
|
||
|
using message passing. A typical transmit sequence is as follows:
|
||
|
|
||
|
1. The remote side queues an RX intent. When the remote client queues the
|
||
|
intent by calling glink_queue_rx_intent(), the ownership of the buffer
|
||
|
transfers to the remote G-Link core, which notifies the local G-Link core
|
||
|
of the receive intent. The remote G-Link core is now ready to receive data
|
||
|
from the local client. In the zero-copy case, the remote G-Link core does
|
||
|
not need to allocate a buffer.
|
||
|
|
||
|
+------+ +------+ +------+
|
||
|
|Local | |Remote| |Remote|
|
||
|
|G-Link| |G-Link| |Client|
|
||
|
+------+ +------+ +------+
|
||
|
| | |
|
||
|
| | glink_queue_rx_intent()|
|
||
|
| +-+<---------------------+-+
|
||
|
| |-| |-|
|
||
|
| |-|(allocate/reserve |-|
|
||
|
| |-| buffer) |-|
|
||
|
| |-|-----+ |-|
|
||
|
| |-| | |-|
|
||
|
| |-|<----+ |-|
|
||
|
| +-+ +-+
|
||
|
| send_intent() | |
|
||
|
|<--------------------------+ |
|
||
|
| | |
|
||
|
| (signal) | |
|
||
|
+-+<-------------------------| |
|
||
|
|-| | |
|
||
|
|-| | |
|
||
|
|-| | |
|
||
|
+-+ | |
|
||
|
| | |
|
||
|
+------+ +------+ +------+
|
||
|
|Local | |Remote| |Remote|
|
||
|
|G-Link| |G-Link| |Client|
|
||
|
+------+ +------+ +------+
|
||
|
|
||
|
2. The local client can allocate a buffer, fill it, and send it to the remote
|
||
|
side. If multiple receive intents are available, then a first-fit
|
||
|
algorithm is used to select the receive intent.
|
||
|
|
||
|
+------+ +------+ +------+ +------+
|
||
|
|Local | |Local | |Remote| |Remote|
|
||
|
|Client| |G-Link| |G-Link| |Client|
|
||
|
+------+ +------+ +------+ +------+
|
||
|
| | | |
|
||
|
| (Allocate tx buffer) | | |
|
||
|
+-+--------+ | | |
|
||
|
|-| | | | |
|
||
|
|-|<-------+ | | |
|
||
|
|-| | | |
|
||
|
|-| (Copy data into | | |
|
||
|
|-| tx buffer) | | |
|
||
|
|-|--------+ | | |
|
||
|
|-| | | | |
|
||
|
|-|<-------+ | | |
|
||
|
|-| | | |
|
||
|
|-| glink_tx() | | |
|
||
|
|-|------------------->+-+ tx() | |
|
||
|
|-| |-|---------->+-+ notify_rx() |
|
||
|
|-| |-| |-|------------>+-+
|
||
|
+-+ |-| (signal) |-| |-|
|
||
|
| |-|---------->|-| |-|
|
||
|
| +-+ |-| |-|
|
||
|
| | +-+ |-|
|
||
|
| | | +-+
|
||
|
| | | |
|
||
|
+------+ +------+ +------+ +------+
|
||
|
|Local | |Local | |Remote| |Remote|
|
||
|
|Client| |G-Link| |G-Link| |Client|
|
||
|
+------+ +------+ +------+ +------+
|
||
|
|
||
|
3. The transmit buffer ownership is returned to the local client after the
|
||
|
remote client has finished with it. At this point, the local client can
|
||
|
destroy/reuse the buffer.
|
||
|
|
||
|
+------+ +------+ +------+ +------+
|
||
|
|Local | |Local | |Remote| |Remote|
|
||
|
|Client| |G-Link| |G-Link| |Client|
|
||
|
+------+ +------+ +------+ +------+
|
||
|
| | | |
|
||
|
| | | glink_rx_done() |
|
||
|
| | +-+<----------------+-+
|
||
|
| | |-| |-|
|
||
|
| | |-| (copy-based |-|
|
||
|
| | |-| transport: |-|
|
||
|
| | |-| destroy/reuse |-|
|
||
|
| | |-| buffer) |-|
|
||
|
| | |-|----------+ +-+
|
||
|
| | |-| | |
|
||
|
| | |-| | |
|
||
|
| | |-|<---------+ |
|
||
|
| | tx_done()|-| |
|
||
|
| +-+<----------|-| |
|
||
|
| |-| |-| |
|
||
|
| |-| (signal) |-| |
|
||
|
| notify_tx_done()|-|<----------|-| |
|
||
|
+-+<---------------|-| |-| |
|
||
|
|-| |-| +-+ |
|
||
|
|-| |-| | |
|
||
|
|-| +-+ | |
|
||
|
+-+ | | |
|
||
|
| | | |
|
||
|
+------+ +------+ +------+ +------+
|
||
|
|Local | |Local | |Remote| |Remote|
|
||
|
|Client| |G-Link| |G-Link| |Client|
|
||
|
+------+ +------+ +------+ +------+
|
||
|
|
||
|
Transport Interface
|
||
|
-------------------
|
||
|
The transport interface is used for function calls from the G-Link core to a
|
||
|
G-Link transport. Modules which implement this interface are G-Link
|
||
|
transports. All function calls include the pointer to the transport instance
|
||
|
and the data fields that should be encoded into a command packet to be sent to
|
||
|
the remote processor. These functions act on the transport itself - they
|
||
|
translate the commands into actions for each different transport. This interface
|
||
|
contains APIs for transport negotiation, channel state, channel data, and
|
||
|
power. Requests that change state always have an ACK to synchronize
|
||
|
the state between the local and remote subsystems.
|
||
|
|
||
|
The transport interface is implemented as follows:
|
||
|
|
||
|
struct glink_transport_if {
|
||
|
/* Negotiation */
|
||
|
void (*tx_cmd_version)(struct glink_transport_if *if_ptr,
|
||
|
uint32_t version,
|
||
|
uint32_t features);
|
||
|
void (*tx_cmd_version_ack)(struct glink_transport_if *if_ptr,
|
||
|
uint32_t version,
|
||
|
uint32_t features);
|
||
|
void (*set_version)(struct glink_transport_if *if_ptr, uint32_t version,
|
||
|
uint32_t features);
|
||
|
|
||
|
/* channel state */
|
||
|
int (*tx_cmd_ch_open)(struct glink_transport_if *if_ptr, uint32_t lcid,
|
||
|
const char *name);
|
||
|
int (*tx_cmd_ch_close)(struct glink_transport_if *if_ptr,
|
||
|
uint32_t lcid);
|
||
|
void (*tx_cmd_ch_remote_open_ack)(struct glink_transport_if *if_ptr,
|
||
|
uint32_t rcid);
|
||
|
void (*tx_cmd_ch_remote_close_ack)(struct glink_transport_if *if_ptr,
|
||
|
uint32_t rcid);
|
||
|
int (*ssr)(struct glink_transport_if *if_ptr);
|
||
|
|
||
|
/* channel data */
|
||
|
int (*allocate_rx_intent)(size_t size,
|
||
|
struct glink_core_rx_intent *intent);
|
||
|
int (*deallocate_rx_intent)(struct glink_core_rx_intent *intent);
|
||
|
|
||
|
int (*tx_cmd_local_rx_intent)(struct glink_transport_if *if_ptr,
|
||
|
uint32_t lcid, size_t size, uint32_t liid);
|
||
|
void (*tx_cmd_local_rx_done)(struct glink_transport_if *if_ptr,
|
||
|
uint32_t lcid, uint32_t liid);
|
||
|
int (*tx)(struct glink_transport_if *if_ptr, uint32_t lcid,
|
||
|
struct glink_core_tx_pkt *pctx);
|
||
|
int (*tx_cmd_rx_intent_req)(struct glink_transport_if *if_ptr,
|
||
|
uint32_t lcid, size_t size);
|
||
|
int (*tx_cmd_remote_rx_intent_req_ack)(
|
||
|
struct glink_transport_if *if_ptr,
|
||
|
uint32_t lcid, bool granted);
|
||
|
int (*tx_cmd_set_sigs)(struct glink_transport_if *if_ptr,
|
||
|
uint32_t lcid, uint32_t sigs);
|
||
|
|
||
|
/* Optional. If NULL at xprt registration, dummies will be used */
|
||
|
int (*poll)(struct glink_transport_if *if_ptr, uint32_t lcid);
|
||
|
int (*mask_rx_irq)(struct glink_transport_if *if_ptr, uint32_t lcid,
|
||
|
bool mask, void *pstruct);
|
||
|
int (*wait_link_down)(struct glink_transport_if *if_ptr);
|
||
|
int (*tx_cmd_tracer_pkt)(struct glink_transport_if *if_ptr,
|
||
|
uint32_t lcid, struct glink_core_tx_pkt *pctx);
|
||
|
|
||
|
/* private pointer for core */
|
||
|
struct glink_core_xprt_ctx *glink_core_priv;
|
||
|
|
||
|
/* core pointer (set during transport registration) */
|
||
|
struct glink_core_if *glink_core_if_ptr;
|
||
|
};
|
||
|
|
||
|
G-Link Core Interface
|
||
|
---------------------
|
||
|
The G-Link Core Interface is used by the transport to call back into G-Link
|
||
|
core for messages or events received from the transport. This interface has
|
||
|
APIs for transport negotiation, power, channel state, and channel data.
|
||
|
Like the transport interface, requests that change state always have an ACK
|
||
|
to synchronize the state between the local and remote subsystems.
|
||
|
|
||
|
The G-Link Core Interface is implemented as follows:
|
||
|
|
||
|
struct glink_core_if {
|
||
|
/* Negotiation */
|
||
|
void (*link_up)(struct glink_transport_if *if_ptr);
|
||
|
void (*rx_cmd_version)(struct glink_transport_if *if_ptr,
|
||
|
uint32_t version,
|
||
|
uint32_t features);
|
||
|
void (*rx_cmd_version_ack)(struct glink_transport_if *if_ptr,
|
||
|
uint32_t version,
|
||
|
uint32_t features);
|
||
|
|
||
|
/* channel management */
|
||
|
void (*rx_cmd_ch_remote_open)(struct glink_transport_if *if_ptr,
|
||
|
uint32_t rcid, const char *name);
|
||
|
void (*rx_cmd_ch_open_ack)(struct glink_transport_if *if_ptr,
|
||
|
uint32_t lcid);
|
||
|
void (*rx_cmd_ch_remote_close)(struct glink_transport_if *if_ptr,
|
||
|
uint32_t rcid);
|
||
|
void (*rx_cmd_ch_close_ack)(struct glink_transport_if *if_ptr,
|
||
|
uint32_t lcid);
|
||
|
void (*ch_state_local_trans)(struct glink_transport_if *if_ptr,
|
||
|
uint32_t lcid,
|
||
|
enum local_channel_state_e new_state);
|
||
|
|
||
|
/* channel data */
|
||
|
struct glink_core_rx_intent *(*rx_get_pkt_ctx)(
|
||
|
struct glink_transport_if *if_ptr,
|
||
|
uint32_t rcid, uint32_t liid);
|
||
|
void (*rx_put_pkt_ctx)(struct glink_transport_if *if_ptr, uint32_t rcid,
|
||
|
struct glink_core_rx_intent *intent_ptr, bool complete);
|
||
|
void (*rx_cmd_remote_rx_intent_put)(struct glink_transport_if *if_ptr,
|
||
|
uint32_t rcid, uint32_t riid, size_t size);
|
||
|
void (*rx_cmd_tx_done)(struct glink_transport_if *if_ptr, uint32_t rcid,
|
||
|
uint32_t riid);
|
||
|
void (*rx_cmd_remote_rx_intent_req)(struct glink_transport_if *if_ptr,
|
||
|
uint32_t rcid, size_t size);
|
||
|
void (*rx_cmd_rx_intent_req_ack)(struct glink_transport_if *if_ptr,
|
||
|
uint32_t rcid, bool granted);
|
||
|
void (*rx_cmd_remote_sigs)(struct glink_transport_if *if_ptr,
|
||
|
uint32_t rcid, uint32_t sigs);
|
||
|
|
||
|
/* channel scheduling */
|
||
|
void (*tx_resume)(struct glink_transport_if *if_ptr);
|
||
|
};
|
||
|
|
||
|
Power Management
|
||
|
================
|
||
|
|
||
|
Power management has yet to be implemented. See the "To do" section for more
|
||
|
information.
|
||
|
|
||
|
SMP/multi-core
|
||
|
==============
|
||
|
|
||
|
Locking and synchronization will be done using mutexes or spinlocks where
|
||
|
appropriate.
|
||
|
|
||
|
Security
|
||
|
========
|
||
|
|
||
|
No known security issues.
|
||
|
|
||
|
Performance
|
||
|
===========
|
||
|
|
||
|
No known performance issues.
|
||
|
|
||
|
Client Interface
|
||
|
================
|
||
|
|
||
|
Open
|
||
|
----
|
||
|
void *glink_open(const struct glink_open_config *cfg)
|
||
|
|
||
|
Opens a logical channel. When this function is called, a notification is sent
|
||
|
to the remote processor. Once the remote processor responds with an open
|
||
|
command, the channel will be opened locally. At this point, the channel is
|
||
|
considered fully open and ready for data operations. The client will be notified
|
||
|
at this point with a GLINK_CONNECTED notification.
|
||
|
|
||
|
When a channel is opened by calling glink_open(), a structure of configuration
|
||
|
information (struct glink_open_config) is passed to it. This includes the name
|
||
|
of the transport, the name of the edge, and the name of the channel, along with
|
||
|
pointers to notification functions:
|
||
|
* notify_rx() - Notify the client that data has been received
|
||
|
* notify_tx_done() - Notify the client that data has been transmitted
|
||
|
* notify_state() - Notify the client that the channel's state has
|
||
|
changed
|
||
|
* notify_rx_intent_req() - Notify the client whether their request for a
|
||
|
receive intent was granted
|
||
|
* notify_rxv() - Receive notification for vector buffers
|
||
|
* notify_rx_sigs() - Notification callback for change in state of remote
|
||
|
side's control signals.
|
||
|
* notify_rx_abort() - During channel close, return structures associated with
|
||
|
receive intents to the client.
|
||
|
* notify_tx_abort() - During channel close, return structures associated with
|
||
|
TX packets to the client.
|
||
|
* notify_rx_tracer_pkt() - Receive notification for tracer packet
|
||
|
|
||
|
This structure is copied internally during the glink_open() call. The full
|
||
|
definition of the structure is below:
|
||
|
|
||
|
struct glink_open_config {
|
||
|
unsigned options;
|
||
|
|
||
|
const char *transport;
|
||
|
const char *edge;
|
||
|
const char *name;
|
||
|
|
||
|
struct glink_ch_ctx (*notify_rx)(void *handle, const void *priv,
|
||
|
const void *pkt_priv, const void *ptr, size_t size);
|
||
|
struct glink_ch_ctx (*notify_tx_done)(void *handle, const void *priv,
|
||
|
const void *pkt_priv, const void *ptr);
|
||
|
struct glink_ch_ctx (*notify_state)(void *handle, const void *priv,
|
||
|
unsigned event);
|
||
|
bool (*notify_rx_intent_req)(void *handle, const void *priv,
|
||
|
size_t req_size);
|
||
|
struct glink_ch_ctx (*notify_rxv)(void *handle, const void *priv,
|
||
|
const void *pkt_priv, void *iovec, size_t size,
|
||
|
void *(*vbuf_provider)(void *iovec, size_t offset,
|
||
|
size_t *size),
|
||
|
void *(*pbuf_provider)(void *iovec, size_t offset,
|
||
|
size_t *size));
|
||
|
struct glink_ch_ctx (*notify_rx_sigs)(void *handle, const void *priv,
|
||
|
uint32_t old_sigs, uint32_t new_sigs);
|
||
|
struct glink_ch_ctx (*notify_rx_abort)(void *handle, const void *priv,
|
||
|
const void *pkt_priv);
|
||
|
struct glink_ch_ctx (*notify_tx_abort)(void *handle, const void *priv,
|
||
|
const void *pkt_priv);
|
||
|
struct glink_ch_ctx (*notify_rx_tracer_pkt)(void *handle,
|
||
|
const void *priv, const void *pkt_priv, const void *ptr,
|
||
|
size_t size);
|
||
|
};
|
||
|
|
||
|
The following are the possible event notification values. The GLINK_CONNECTED
|
||
|
notification is sent using the notify_state() callback once the channel has
|
||
|
been fully opened. See the Close section for the closing state details.
|
||
|
enum {
|
||
|
GLINK_CONNECTED,
|
||
|
GLINK_LOCAL_DISCONNECTED,
|
||
|
GLINK_REMOTE_DISCONNECTED,
|
||
|
};
|
||
|
|
||
|
glink_open() returns the following standard error codes:
|
||
|
* ERR_PTR(-EINVAL) - The glink_open_config structure which was passed to
|
||
|
glink_open() is invalid.
|
||
|
* ERR_PTR(-ENODEV) - No transport is available.
|
||
|
* ERR_PTR(-EBUSY) - The requested channel is not ready to be re-opened.
|
||
|
|
||
|
Close
|
||
|
-----
|
||
|
int glink_close (void *handle)
|
||
|
|
||
|
Closes the logical channel. Once the close request has been processed by the
|
||
|
remote processor, the GLINK_LOCAL_DISCONNECTED notification is sent to the
|
||
|
client. If the remote processor closes the channel first, then the
|
||
|
GLINK_REMOTE_DISCONNECTED notification is sent to the client. After the
|
||
|
GLINK_LOCAL_DISCONNECTED notification is sent, no additional activity will occur
|
||
|
on the channel, regardless of whether the GLINK_REMOTE_DISCONNECTED notification
|
||
|
was sent or not. At this point, it's safe for the callbacks and/or their
|
||
|
resources to be destroyed. If the client wishes to re-establish communication
|
||
|
on the channel, then the client will need to re-open the channel.
|
||
|
|
||
|
glink_close() returns the following standard error codes:
|
||
|
* -EINVAL - The channel to be closed is NULL.
|
||
|
* -EBUSY - The channel to be closed is already closing.
|
||
|
|
||
|
If the channel to be closed is already closed, 0 is returned.
|
||
|
|
||
|
Transmit Data
|
||
|
-------------
|
||
|
int glink_tx(void *handle, void *pkt_priv, void *data, size_t size,
|
||
|
bool req_intent)
|
||
|
|
||
|
Arguments:
|
||
|
handle: The handle returned by glink_open()
|
||
|
pkt_priv: Opaque data value that will be returned to client with the
|
||
|
notify_tx_done() notification
|
||
|
data: Pointer to the data being sent
|
||
|
size: Size of the data being sent
|
||
|
req_intent: Boolean indicating whether or not to request an intent from the
|
||
|
remote channel
|
||
|
|
||
|
Transmit data packet for a matching RX Intent.
|
||
|
|
||
|
If a client would like to transmit a packet, but a suitable RX Intent has not
|
||
|
been queued, the client can request that glink_tx() block and request a
|
||
|
receive intent from the remote system. The remote system can still deny the
|
||
|
request at which point glink_tx() will return -EAGAIN to the client. The call
|
||
|
sequence for this exchange is:
|
||
|
|
||
|
1. Client wants to transmit a packet, and sets the req_intent flag to true in
|
||
|
the call to glink_tx() in order to request an intent if one is not already
|
||
|
available.
|
||
|
3. Remote G-Link calls its client's notify_rx_intent_req() function and that
|
||
|
client returns a boolean indicating whether the intent will be granted or
|
||
|
not
|
||
|
4. If the client grants the remote intent request, glink_tx() receives the
|
||
|
intent and returns success
|
||
|
5. If the client rejects the remote intent request, glink_tx() returns an error
|
||
|
|
||
|
int glink_txv(void *handle, void* pkt_priv, const void *iovec, size_t size,
|
||
|
glink_buffer_provider_fn vbuff_provider,
|
||
|
glink_buffer_proivder_fn pbuff_provider,
|
||
|
bool req_intent)
|
||
|
|
||
|
Arguments:
|
||
|
handle: The handle returned by glink_open()
|
||
|
pkt_priv: Opaque data value that will be returned to client with the
|
||
|
notify_tx_done() notification
|
||
|
iovec: Pointer to the vector
|
||
|
size: Size of the data being sent
|
||
|
vbuf_provider: Client-provided helper function to iterate the vector in
|
||
|
virtual address space
|
||
|
pbuf_provider: Client-provided helper function to iterate the vector in
|
||
|
physical address space
|
||
|
req_intent: Boolean indicating whether or not to request an intent from the
|
||
|
remote channel
|
||
|
|
||
|
glink_txv() provides a transmit function that accommodates clients using vector
|
||
|
buffer implementations (DSM, SKB, etc.), and allows transports to operate on
|
||
|
virtual or physical address mappings when necessary. This is done through the
|
||
|
vbuf_provider() and pbuf_provider() functions, which are defined by the client
|
||
|
and return a pointer to the contiguous vector data after iteration. After
|
||
|
assembling the data from the vector, the call sequence is the same as
|
||
|
glink_tx().
|
||
|
|
||
|
Queue Receive Intent
|
||
|
--------------------
|
||
|
int glink_queue_rx_intent(void *handle, const void *pkt_priv, size_t size)
|
||
|
|
||
|
Queues a receive intent. A receive intent indicates that the client is ready to
|
||
|
receive a packet up to the specified size. The transport interface will either
|
||
|
reserve space for this packet or allocate a buffer to receive this packet such
|
||
|
that the packet can be received without stalling the physical transport.
|
||
|
|
||
|
The pkt_priv parameter is an opaque value provided by the client that is
|
||
|
returned in the notify_rx() callback.
|
||
|
|
||
|
Signal Consumption of Receive Buffer
|
||
|
------------------------------------
|
||
|
int glink_rx_done(void *handle, const void *ptr)
|
||
|
|
||
|
This function is called by the client to signal that they are done with the
|
||
|
receive buffer. The remote client is notified that it now owns the buffer again.
|
||
|
|
||
|
Set Control Signal Field
|
||
|
------------------------
|
||
|
glink_sigs_set(void *handle, uint32 *sig_value)
|
||
|
|
||
|
This function is called by the client to set a 32-bit control signal field.
|
||
|
Depending on the transport, it may take appropriate actions on the set bit-mask,
|
||
|
or transmit the entire 32-bit value to the remote host.
|
||
|
|
||
|
Get Local Control Signal Field
|
||
|
------------------------------
|
||
|
glink_sigs_local_get(void *handle, uint32 *sig_value)
|
||
|
|
||
|
This function is called by the client to retrieve the cached signals sent
|
||
|
using glink_sigs_set().
|
||
|
|
||
|
Get Remote Control Signal Field
|
||
|
-------------------------------
|
||
|
glink_sigs_remote_get(void *handle, uint32 *sig_value)
|
||
|
|
||
|
This function is called by the client to retrieve the cached remote signals
|
||
|
that were passed to notify_rx_sigs().
|
||
|
|
||
|
Register a Transport
|
||
|
--------------------
|
||
|
int glink_core_register_transport(struct glink_transport_if *if_ptr,
|
||
|
struct glink_core_transport_cfg *cfg)
|
||
|
|
||
|
Register a new transport with the G-Link Core. The if_ptr parameter is the
|
||
|
interface to the transport, and the cfg parameter is the configuration, which
|
||
|
contains the following information:
|
||
|
* The name of the transport
|
||
|
* The edge of the transport, i.e. remote processor name
|
||
|
* An array of the transport versions supported
|
||
|
* The maximum number of entries in the versions array
|
||
|
* The maximum number of channel identifiers supported
|
||
|
* The maximum number of intent identifiers supported
|
||
|
|
||
|
The implementation of this transport configuration structure is below.
|
||
|
|
||
|
struct glink_core_transport_cfg {
|
||
|
const char *name;
|
||
|
const char *edge;
|
||
|
const struct glink_core_version *versions;
|
||
|
size_t versions_count;
|
||
|
uint32_t max_cid;
|
||
|
uint32_t max_iid;
|
||
|
};
|
||
|
|
||
|
The initial state of a transport after it is registered is GLINK_XPRT_DOWN.
|
||
|
The possible states of a transport are as follows:
|
||
|
enum transport_state_e {
|
||
|
GLINK_XPRT_DOWN,
|
||
|
GLINK_XPRT_NEGOTIATING,
|
||
|
GLINK_XPRT_OPENED,
|
||
|
GLINK_XPRT_FAILED,
|
||
|
}
|
||
|
|
||
|
Unregister a Transport
|
||
|
----------------------
|
||
|
void glink_core_unregister_transport(struct glink_transport_if *if_ptr)
|
||
|
|
||
|
Unregister/destroy an existing transport. The transport's state is changed to
|
||
|
GLINK_XPRT_DOWN, and the following values are reset:
|
||
|
* the next local channel ID
|
||
|
* The local version index
|
||
|
* The remote version index
|
||
|
* The version negotiation completion flag
|
||
|
* The list of channels on the transport (list is deleted)
|
||
|
|
||
|
Driver parameters
|
||
|
=================
|
||
|
|
||
|
The G-Link core and G-Link Loopback Server modules both have a module parameter
|
||
|
called "debug_mask". The possible values are detailed in the "Config options"
|
||
|
section.
|
||
|
|
||
|
Config options
|
||
|
==============
|
||
|
|
||
|
G-Link supports several logging configurations. The following options are
|
||
|
available for the core and loopback client. They can be bitwise OR'ed together
|
||
|
to have multiple options at once.
|
||
|
|
||
|
QCOM_GLINK_INFO - The default option. Turn on only INFO messages
|
||
|
QCOM_GLINK_DEBUG - Turn on debug log messages - much more verbose logging to
|
||
|
aid in debugging.
|
||
|
QCOM_GLINK_PERF - Performance logging. This removes all other logging except
|
||
|
for logging messages that are created through a special
|
||
|
set of macros. These logs can be post-processed for
|
||
|
performance metrics.
|
||
|
|
||
|
The values of these options are as follows:
|
||
|
enum {
|
||
|
QCOM_GLINK_INFO = 1U << 0,
|
||
|
QCOM_GLINK_DEBUG = 1U << 1,
|
||
|
QCOM_GLINK_PERF = 1U << 2,
|
||
|
};
|
||
|
|
||
|
Dependencies
|
||
|
============
|
||
|
|
||
|
IPC Logging is a dependency of the G-Link core. The Transport Plug-ins will have
|
||
|
their own dependencies. The SMEM Native Transport depends on SMEM and the
|
||
|
interrupt subsystem.
|
||
|
|
||
|
DebugFS
|
||
|
=======
|
||
|
|
||
|
Several DebugFS nodes are exported under the glink directory for testing and
|
||
|
debugging. The directory structure below allows listing information by
|
||
|
subsystem, channel, and transport.
|
||
|
|
||
|
glink Directory
|
||
|
---------------
|
||
|
`-- debugfs
|
||
|
`-- glink
|
||
|
|-- channel
|
||
|
| |-- channels <- lists all of the channels in the system, their
|
||
|
| | state, the transport they are assigned to, etc.
|
||
|
| |-- SUBSYSTEM_NAME <- directory (such as "mpss")
|
||
|
| | `-- CHANNEL_NAME <- one directory per channel
|
||
|
| | |-- intents <- list of all open intents, their size, and
|
||
|
| | | their ID
|
||
|
| | `-- stats <- statistics for the channel (contents TBD)
|
||
|
`-- xprt
|
||
|
|-- xprts <- lists all of the transports in the system and basic
|
||
|
| transport-specific state
|
||
|
|-- XPRT_NAME <-- directory (such as "smem")
|
||
|
`-- XPRT_INFO <-- transport specific files
|
||
|
|
||
|
User space utilities
|
||
|
====================
|
||
|
|
||
|
A user space driver is provided which can export a character device for a single
|
||
|
channel based upon Device Tree configuration. The full DT schema is detailed in
|
||
|
Documentation/devicetree/bindings/arm/msm/glinkpkt.txt. The user space driver
|
||
|
implements the standard file operations of open, release, read, write, poll, and
|
||
|
mmap. An ioctl is defined to queue RX intents.
|
||
|
|
||
|
The file operations map to the G-Link Client API as follows:
|
||
|
open() -> glink_open() (Open a channel. Exported channels configured
|
||
|
through DT)
|
||
|
write() -> glink_tx() (Transmit data)
|
||
|
read() -> Receive data and send RX done notification (glink_rx_done())
|
||
|
release() -> glink_close() (Close a channel)
|
||
|
ioctl() -> glink_queue_rx_intent()
|
||
|
|
||
|
Other operations are:
|
||
|
poll() -> Poll waiting for the channel to become available
|
||
|
mmap() -> Prevent having to do a copy between kernel space and user space
|
||
|
for clients that need that performance.
|
||
|
|
||
|
A typical transmit and receive call flow is as follows:
|
||
|
1. G-Link user space driver opens the channel using open(), which returns a
|
||
|
file descriptor for the channel
|
||
|
2. An ioctl is sent to queue an RX intent on the channel
|
||
|
3. Data is transmitted on the channel using write()
|
||
|
4. The data is received using read(). read() also sends an RX done
|
||
|
notification.
|
||
|
|
||
|
Version/Feature Negotiation
|
||
|
===========================
|
||
|
|
||
|
To enable upgrading transports, G-Link supports a version number and feature
|
||
|
flags for each transport. The combination of the version number and feature
|
||
|
flags enable:
|
||
|
1. G-Link software updates to be rolled out to each processor
|
||
|
separately.
|
||
|
2. Individual features to be enabled or disabled on an edge-by-edge
|
||
|
basis.
|
||
|
|
||
|
Endpoints negotiate both the version and the feature flags when the transport
|
||
|
is opened; they cannot be changed after negotiation has been completed.
|
||
|
|
||
|
The version number represents any change in G-Link or the transport that
|
||
|
breaks compatibility between processors. Examples would be a change in the
|
||
|
shared data structures or changes to fundamental behavior in either the
|
||
|
transport or in G-Link Core. Each full implementation of G-Link must support a
|
||
|
minimum of the current version, the previous version, and the base negotiation
|
||
|
version called v0. For resource-constrained devices, this can be relaxed to
|
||
|
only support the latest version of the protocol and the v0 version.
|
||
|
|
||
|
The feature flags represent any changes in G-Link that are optional and
|
||
|
backwards-compatible. Feature flags can be version-specific, but to limit code
|
||
|
maintenance and documentation overhead, feature flags should not be re-used
|
||
|
unless the limit of 32 feature flags has been reached.
|
||
|
|
||
|
Negotiation Algorithm
|
||
|
---------------------
|
||
|
After a transport is registered with G-Link core, it should be configured with
|
||
|
the v0 transport settings. Once communication can be done without losing
|
||
|
messages, the link_up() call in the G-Link core should be made to start the
|
||
|
negotiation process. Both the local and remote sides will follow the same
|
||
|
negotiation state machines.
|
||
|
|
||
|
Since both sides follow the same sequence and both sides start once the link is
|
||
|
up, it is possible that both sides may start the negotiation sequence at the
|
||
|
same time resulting in a perceived race condition. However, both negotiation
|
||
|
sequences are independent and the transport is not considered opened until both
|
||
|
negotiation sequences are complete, so this is not a true race condition and
|
||
|
both sides will converge to the same version and feature set even if they
|
||
|
start with different versions and feature sets. Since this sequence is not
|
||
|
performance-critical, the extra complexity in the negotiation algorithm to
|
||
|
short-circuit the process is not deemed necessary.
|
||
|
|
||
|
Local-Initiated Negotiation Sequence
|
||
|
------------------------------------
|
||
|
The following local negotiation sequence is initiated and followed by each
|
||
|
side. The processor that is running this algorithm will be matched by the
|
||
|
remote processor following the Remote-Initiated Negotiation Sequence.
|
||
|
|
||
|
1. Set current version and feature variables to the maximum supported version
|
||
|
and feature set
|
||
|
2. Send Version Command (glink_transport_if::tx_cmd_version()) with local
|
||
|
version and feature set
|
||
|
3. If version is 0, then negotiation has failed and the transport should be
|
||
|
marked as having failed negotiation and the negotiation sequence
|
||
|
terminated.
|
||
|
4. When Version ACK is received (glink_core_if::rx_cmd_version_ack()):
|
||
|
a. Compare ACK version to the sent version and:
|
||
|
i. If equal, we are done with version negotiation
|
||
|
ii. Else set current version to the lower of:
|
||
|
1. Remote version number
|
||
|
2. Highest supported local version
|
||
|
b. Compare ACK features to the sent features and:
|
||
|
i. If equal, we are done with the negotiation sequence
|
||
|
ii. Else, call glink_core_version:: negotiate_features() for the
|
||
|
current version to set the features to either the bitwise AND of
|
||
|
the ACK features and the locally supported features or a lesser
|
||
|
feature set for cases where only certain combinations of features
|
||
|
are valid.
|
||
|
c. Go back to step 2 to send the updated version/feature set
|
||
|
|
||
|
Remote-Initiated Negotiation Sequence
|
||
|
-------------------------------------
|
||
|
The following remote negotiation sequence is followed by each side based upon
|
||
|
receiving a Version Command.
|
||
|
|
||
|
1. Receive Version Command (glink_core_if::rx_cmd_version())
|
||
|
2. Compare received version with the locally supported version and:
|
||
|
a. If equal, set ACK version to the received version
|
||
|
b. Else, set ACK version to the lower of:
|
||
|
i. Remote version number
|
||
|
ii. Highest supported local version
|
||
|
iii. Version 0 if no supported version less than or equal to
|
||
|
the remote version number can be found.
|
||
|
3. Compare received features with the locally supported features and:
|
||
|
a. If equal, set ACK features to the received features
|
||
|
b. Else, call glink_core_version:: negotiate_features() for the current
|
||
|
version to set the features to either the bitwise AND of the ACK
|
||
|
features and the locally supported features or a lesser feature set
|
||
|
for cases where only certain combinations of features are valid.
|
||
|
4. Send the Version ACK Command (glink_transport_if::tx_cmd_version_ack()).
|
||
|
|
||
|
Packets
|
||
|
=======
|
||
|
|
||
|
Packets are scheduled in a round-robin fashion from all active channels. Large
|
||
|
packets can be fragmented by the transport to ensure fairness between channels
|
||
|
and ensure latency.
|
||
|
|
||
|
Channel Migration
|
||
|
=================
|
||
|
|
||
|
The G-Link core has the capability of selecting the best transport available on
|
||
|
an edge-by-edge basis. The transport is selected based upon a pre-defined
|
||
|
transport priority and from optional transport selection information passed in
|
||
|
by the client in the glink_open_config structure.
|
||
|
|
||
|
Subsystem Restart (SSR)
|
||
|
=======================
|
||
|
|
||
|
In order to properly clean up channel state and recover buffer ownership
|
||
|
consistently across different physical transports, G-Link requires an
|
||
|
additional SSR notification system on top of the existing SSR framework. The
|
||
|
notification system is a star topology with the application processor as the
|
||
|
master. When a subsystem is restarted, all other subsystems are notified by the
|
||
|
application processor and must respond after cleaning up all affected channels
|
||
|
before the SSR event is allowed to continue.
|
||
|
|
||
|
The solution has four components:
|
||
|
1. Target-specific configuration for each subsystem, which consists of a list
|
||
|
of which subsystems should be notified in the event of SSR, specified in
|
||
|
Device Tree
|
||
|
2. SSR module that uses the G-Link Client API to isolate SSR functionality,
|
||
|
and handles calls to the SSR Framework, Device Tree parsing, etc.
|
||
|
3. SSR notification messages between the application processor and
|
||
|
other subsystems, which will be exchanged using G-Link.
|
||
|
4. SSR API:
|
||
|
a. glink_ssr(const char *subsystem_name) - G-Link Client API
|
||
|
b. ssr(struct glink_transport_if *if_ptr) - Transport Interface
|
||
|
|
||
|
1. Target-specific configuration using Device Tree
|
||
|
--------------------------------------------------
|
||
|
The target-specific configuration provides the G-Link SSR module with a list
|
||
|
of subsystems that should be notified in the event of SSR. This is necessary
|
||
|
to simplify handling of cases where there are multiple SoCs in one device -
|
||
|
there is no need to notify a subsystem on a second SoC of a restart in the
|
||
|
first SoC. The configuration also provides a mapping of the subsystem's name
|
||
|
in the SSR framework to its name as a G-Link edge, and allows the specification
|
||
|
of a transport for each notification. The figures below provide an example:
|
||
|
|
||
|
+----+ +------+ +-------------------+
|
||
|
|SSR |----->|G-Link|------->|Subsystem A |
|
||
|
|Name| |Name | |Subsystem B: xprt x|
|
||
|
+----+ +------+ |Subsystem C |
|
||
|
+-------------------+
|
||
|
|
||
|
+-------+ +------+ +--------------+
|
||
|
|"modem"|----->|"mpss"|------->|"wcnss" |
|
||
|
+-------+ +------+ |"lpass": "smd"|
|
||
|
|"dsps" |
|
||
|
+--------------+
|
||
|
|
||
|
The above configuration tells the G-Link SSR module to notify all subsystems
|
||
|
on G-Link edges "wcnss", "lpass", and "dsps" that the subsystem on edge "mpss"
|
||
|
has restarted, and to send the notifications to the "lpass" edge on the "smd"
|
||
|
transport.
|
||
|
|
||
|
2. G-Link SSR Module (glink_ssr)
|
||
|
--------------------------------
|
||
|
This module is a G-Link client which handles notifications from the SSR
|
||
|
framework on the application processor and triggers local clean-up in response
|
||
|
to these notifications by calling glink_ssr(const char *subsystem). This
|
||
|
module also sends notifications to any subsystems that need to be notified of
|
||
|
the SSR event, and ensures that they respond within the standard timeout (500
|
||
|
ms). If the subsystem fails to respond, it is restarted.
|
||
|
|
||
|
3. G-Link SSR Messages
|
||
|
----------------------
|
||
|
When an SSR event occurs, the application processor notifies all necessary
|
||
|
subsystems by sending a "do_cleanup" message. After the subsystem performs the
|
||
|
necessary clean-up, it sends back a "cleanup_done" message. If the
|
||
|
"cleanup_done" message for a given subsystem is not received within the
|
||
|
standard timeout (500 ms), the subsystem is restarted.
|
||
|
|
||
|
SSR "do_cleanup" Message
|
||
|
------------------------
|
||
|
+-----------------+-----------------------+------------------------------+
|
||
|
| Element | Type | Description |
|
||
|
+=================+=======================+==============================+
|
||
|
| version | uint32_t | G-Link SSR Protocol Version |
|
||
|
+-----------------+-----------------------+------------------------------+
|
||
|
| command | uint32_t | do_cleanup message (0) |
|
||
|
+-----------------+-----------------------+------------------------------+
|
||
|
| sequence_number | uint32_t | Sequence number |
|
||
|
+-----------------+-----------------------+------------------------------+
|
||
|
| name_len | uint32_t | Name length of the subsystem |
|
||
|
| | | being restarted |
|
||
|
+-----------------+-----------------------+------------------------------+
|
||
|
| name | char[GLINK_NAME_SIZE] | NULL-terminated name of the |
|
||
|
| | | subsystem being restarted |
|
||
|
| | | (GLINK_NAME_SIZE == 32) |
|
||
|
+-----------------+-----------------------+------------------------------+
|
||
|
|
||
|
SSR "cleanup_done" Message
|
||
|
--------------------------
|
||
|
+-----------------+-----------------------+------------------------------+
|
||
|
| Element | Type | Description |
|
||
|
+=================+=======================+==============================+
|
||
|
| version | uint32_t | G-Link SSR Protocol Version |
|
||
|
+-----------------+-----------------------+------------------------------+
|
||
|
| response | uint32_t | cleanup_done message (1) |
|
||
|
+-----------------+-----------------------+------------------------------+
|
||
|
| sequence_number | uint32_t | Sequence number |
|
||
|
+-----------------+-----------------------+------------------------------+
|
||
|
|
||
|
G-Link SSR Protocol Sequence Diagram
|
||
|
------------------------------------
|
||
|
+------+ +------+
|
||
|
+---------+ |G-Link| |G-Link| +----------+
|
||
|
|SSR | |SSR | |Client| +---------+ |Remote |
|
||
|
|Framework| |Module| |API | |Transport| |Processors|
|
||
|
+---------+ +------+ +------+ +---------+ +----------+
|
||
|
| | | | |
|
||
|
| SSR | | | |
|
||
|
| Notification | | | |
|
||
|
+--------------->| | | |
|
||
|
| | | | |
|
||
|
| | | | |
|
||
|
| | | | |
|
||
|
| | do_cleanup | | |
|
||
|
| +------------------------------------------------>|
|
||
|
| | | | |
|
||
|
| | glink_ssr(subsystem) | |
|
||
|
| +------------->| | |
|
||
|
| | | | |
|
||
|
| | | | |
|
||
|
| | | ssr(if_ptr) | |
|
||
|
| | +-------------->| |
|
||
|
| | | | |
|
||
|
| | | | |
|
||
|
| | | | |
|
||
|
| | | | cleanup_done |
|
||
|
| |<------------------------------------------------+
|
||
|
| | | | |
|
||
|
| | | | |
|
||
|
| | | | |
|
||
|
| ssr(subsystem)| | | |
|
||
|
|<---------------+ | | |
|
||
|
| | | | |
|
||
|
| +-----------+---------+ | | |
|
||
|
| |If no cleanup_done | | | |
|
||
|
| |response is received,| | | |
|
||
|
| |restart the subsystem| | | |
|
||
|
| +-----------+---------+ | | |
|
||
|
| | | | |
|
||
|
| | | | |
|
||
|
| | | | |
|
||
|
| | | | |
|
||
|
| | | | |
|
||
|
+---------+ +------+ +------+ +---------+ +----------+
|
||
|
|SSR | |G-Link| |G-Link| |Transport| |Remote |
|
||
|
|Framework| |SSR | |Client| +---------+ |Processors|
|
||
|
+---------+ |Module| |API | +----------+
|
||
|
+------+ +------+
|
||
|
|
||
|
4. SSR API
|
||
|
----------
|
||
|
glink_ssr(const char *subsystem_name)
|
||
|
-------------------------------------
|
||
|
Called by the G-Link SSR Module, this function calls into the transport using
|
||
|
ssr(struct glink_transport_if *if_ptr) to allow the transport to perform any
|
||
|
necessary clean-up, and simulates receiving a remote close from the restarting
|
||
|
subsystem for all channels on the affected edge.
|
||
|
|
||
|
ssr(struct glink_transport_if *if_ptr)
|
||
|
--------------------------------------
|
||
|
The ssr() function is part of the Transport Interface, and as mentioned above is
|
||
|
used to perform any necessary clean-up on the transport.
|
||
|
|
||
|
Tracer Packet Framework
|
||
|
=======================
|
||
|
|
||
|
A tracer packet is a special type of packet that can be used to trace the timing
|
||
|
of events. This helps profile the latency experienced by a packet, and provides
|
||
|
granular information regarding the individual latencies that make up the overall
|
||
|
latency. The information obtained using the tracer packet can be used to
|
||
|
configure the Power Management Quality of Service (PM QoS) in the system in
|
||
|
order to achieve a client's desired packet latency. The tracer packet moves
|
||
|
through the system along with other normal traffic without any impact on the
|
||
|
normal traffic.
|
||
|
|
||
|
When a transport is registered with the local G-Link core, it performs a
|
||
|
transport-specific version and feature negotiation with the remote G-Link core.
|
||
|
Based on this negotiation, the transport reports its capability of supporting
|
||
|
tracer packets to the local G-Link core.
|
||
|
|
||
|
Once the transport has successfully completed the negotiation, the clients open
|
||
|
the G-Link channel over the concerned transport. After the channel is open, the
|
||
|
clients can exchange tracer packets over G-Link, in a way similar to normal
|
||
|
traffic.
|
||
|
|
||
|
When a tracer packet is exchanged over a G-Link channel, the G-Link core and the
|
||
|
transport log events related to packet exchange and their time.
|
||
|
|
||
|
1. Tracer Packet Format
|
||
|
-----------------------
|
||
|
The tracer packet contains a header and a payload. The header contains
|
||
|
identification and configuration information associated with a tracer packet.
|
||
|
The payload contains a series of event logs. The below diagram shows the layout
|
||
|
of the tracer packet:
|
||
|
|
||
|
Tracer Packet Header Layout
|
||
|
---------------------------
|
||
|
31 16 15 14 13 12 11 4 3 0
|
||
|
+-------------------------------+-----+---+----+------+---------+
|
||
|
| Packet Length (words) | CCL | Q | ID | Res. | Version |
|
||
|
+-------------------------------+-------------------------------+
|
||
|
| Client Event Cfg. | Packet Offset (words) |
|
||
|
| Bit Mask | |
|
||
|
+-------------------------------+-------------------------------+
|
||
|
| G-Link Event Config Bit Mask |
|
||
|
+---------------------------------------------------------------+
|
||
|
| Base Timestamp (MS 32 bits) |
|
||
|
+---------------------------------------------------------------+
|
||
|
| Base Timestamp (LS 32 bits) |
|
||
|
+---------------------------------------------------------------+
|
||
|
| Client Cookie |
|
||
|
+---------------------------------------------------------------+
|
||
|
|
||
|
Tracer Packet Payload Layout
|
||
|
----------------------------
|
||
|
31 16 15 0
|
||
|
+-------------------------------+-------------------------------+
|
||
|
| Reserved | Event 1 ID |
|
||
|
+-------------------------------+-------------------------------+
|
||
|
| Event 1 Timestamp (LS 32 bits) |
|
||
|
+---------------------------------------------------------------+
|
||
|
.
|
||
|
.
|
||
|
.
|
||
|
+-------------------------------+-------------------------------+
|
||
|
| Reserved | Event N ID |
|
||
|
+-------------------------------+-------------------------------+
|
||
|
| Event N Timestamp (LS 32 bits) |
|
||
|
+---------------------------------------------------------------+
|
||
|
|
||
|
Tracer Packet Header Fields
|
||
|
---------------------------
|
||
|
Version - This field contains the tracer packet version. The current version
|
||
|
of tracer packet supported by G-Link is 1. If a version of the tracer
|
||
|
packet is not supported by G-Link or its transport abstraction layer,
|
||
|
the tracer packet is still exchanged, but no events are logged.
|
||
|
|
||
|
Reserved - The reserved bit fields are set to 0 and can be used for future
|
||
|
extension of tracer packet functionality.
|
||
|
|
||
|
ID - The ID bit field indicates the presence or absence of the Source Processor
|
||
|
ID, Destination Processor ID and Transport ID fields in the tracer
|
||
|
packet. Currently this field is set to 0 and the concerned IDs are not
|
||
|
defined.
|
||
|
|
||
|
CoreSight ("Q" in the diagram above) - This bit field is used to indicate the
|
||
|
location of the log events. If this bit
|
||
|
field is set, the log events are logged
|
||
|
into CoreSight, otherwise the log events
|
||
|
are logged into the packet itself. If the
|
||
|
log events are logged into the packet,
|
||
|
then the number of events logged into the
|
||
|
packet depends on the size of the packet.
|
||
|
|
||
|
CCL - The tracer packet framework allows clients to differentiate multiple
|
||
|
tracer packets through a client-specified cookie. The Client Cookie Length
|
||
|
(CCL) bit field indicates the length of that cookie in units of words.
|
||
|
|
||
|
Packet Length - These 16 bits indicate the length of the tracer packet in units
|
||
|
of words.
|
||
|
|
||
|
Packet Offset - This field is used when events are logged into the packet. This
|
||
|
16-bit field indicates the offset into the packet, in units of
|
||
|
words, to log an event. Once an event is logged, this field is
|
||
|
updated with the appropriate offset to log future events.
|
||
|
|
||
|
Client Configuration Bit Mask - This bit-mask is used to enable/disable the
|
||
|
G-Link client-specific events. The procedure to
|
||
|
enable/disable client events is dependent upon
|
||
|
the client's implementation and is not included
|
||
|
in this document.
|
||
|
|
||
|
G-Link Configuration Bit Mask - This bit-mask is used to enable/disable the
|
||
|
G-Link-specific events. When a bit is set, the
|
||
|
concerned event logging is enabled.
|
||
|
|
||
|
Base Timestamp - The base timestamp contains the starting time of the tracer
|
||
|
packet exchange. The timestamp logged along with the event is
|
||
|
used as an offset from this base timestamp. This optimization
|
||
|
helps in reducing the log size of an event.
|
||
|
|
||
|
Client Cookie - The tracer packet framework allows clients to differentiate
|
||
|
multiple tracer packets through a client-specified cookie.
|
||
|
|
||
|
Tracer Packet Payload Fields
|
||
|
----------------------------
|
||
|
Event ID - The Event ID field uniquely identifies the G-Link and client-specific
|
||
|
tracer packet events. This field is present only when the events are
|
||
|
logged into the packet. The G-Link and client event IDs are assigned
|
||
|
a unique range. Refer to the table below for more information
|
||
|
regarding the event ID definition.
|
||
|
|
||
|
Reserved - The reserved field is set to 0 and can be used for future extension
|
||
|
of tracer packet functionality.
|
||
|
|
||
|
Event Timestamp - The Event Timestamp field contains the time at which the event
|
||
|
is logged. This field is used as an offset from the Base
|
||
|
Timestamp field in the header to calculate the actual event
|
||
|
timestamp. This field is present only when the events are
|
||
|
logged into the packet.
|
||
|
|
||
|
2. Tracer Packet Events
|
||
|
-----------------------
|
||
|
Each event has a uniquely defined ID. Since G-Link clients can use the tracer
|
||
|
packet framework, G-Link events and G-Link client events are defined in mutually
|
||
|
exclusive ranges. Since client events are client-context specific, the event
|
||
|
IDs can be reused among the clients. The ranges are detailed in the table below:
|
||
|
+--------------------------+-----------------------+
|
||
|
| Event Type | Range |
|
||
|
+==========================+=======================+
|
||
|
| G-Link | 1-255 |
|
||
|
+--------------------------+-----------------------+
|
||
|
| Client | 255 and above |
|
||
|
+--------------------------+-----------------------+
|
||
|
|
||
|
The G-Link specific events and their associated IDs are defined in the below
|
||
|
table:
|
||
|
+--------------------------+-----------------------+
|
||
|
| G-Link Event | ID |
|
||
|
+==========================+=======================+
|
||
|
| GLINK_CORE_TX | 1 |
|
||
|
+--------------------------+-----------------------+
|
||
|
| GLINK_QUEUE_TO_SCHEDULER | 2 |
|
||
|
+--------------------------+-----------------------+
|
||
|
| GLINK_SCHEDULER_TX | 3 |
|
||
|
+--------------------------+-----------------------+
|
||
|
| GLINK_XPRT_TX | 4 |
|
||
|
+--------------------------+-----------------------+
|
||
|
| GLINK_XPRT_RX | 5 |
|
||
|
+--------------------------+-----------------------+
|
||
|
| GLINK_CORE_RX | 6 |
|
||
|
+--------------------------+-----------------------+
|
||
|
|
||
|
3. Tracer Packet API
|
||
|
--------------------
|
||
|
tracer_pkt_init(void *data, size_t data_len, uint16_t client_event_cfg,
|
||
|
uint32_t glink_event_cfg, void *pkt_priv, size_t pkt_priv_len)
|
||
|
--------------------------------------------------------------------------
|
||
|
Initialize a buffer with the tracer packet header. The tracer packet header
|
||
|
includes the data passed in the parameters.
|
||
|
|
||
|
tracer_pkt_set_event_cfg(void *data, uint16_t client_event_cfg,
|
||
|
uint32_t glink_event_cfg)
|
||
|
---------------------------------------------------------------
|
||
|
Initialize a buffer with the event configuration mask passed in the parameters.
|
||
|
|
||
|
tracer_pkt_log_event(void *data, uint32_t event_id)
|
||
|
---------------------------------------------------
|
||
|
Log an event specific to the tracer packet. The event is logged either into
|
||
|
the tracer packet itself or a different tracing mechanism as configured.
|
||
|
|
||
|
tracer_pkt_calc_hex_dump_size(void *data, size_t data_len)
|
||
|
----------------------------------------------------------
|
||
|
Calculate the length of the buffer required to hold the hex dump of the tracer
|
||
|
packet.
|
||
|
|
||
|
tracer_pkt_hex_dump(void *buf, size_t buf_len, void *data, size_t data_len)
|
||
|
---------------------------------------------------------------------------
|
||
|
Dump the contents of the tracer packet into a buffer in a specific hexadecimal
|
||
|
format. The hex dump buffer can then be dumped through debugfs.
|
||
|
|
||
|
Known issues
|
||
|
============
|
||
|
|
||
|
No known issues.
|
||
|
|
||
|
To do
|
||
|
=====
|
||
|
|
||
|
Power Management
|
||
|
----------------
|
||
|
An internal power voting API will be defined to bring the transport out of power
|
||
|
collapse for SMUX and BAM DMUX-type systems. In addition, power for
|
||
|
request/response type systems can be optimized to prevent powering down
|
||
|
unnecessarily after sending a request only to power up immediately to process
|
||
|
the response.
|
||
|
|
||
|
Round-Robin Scheduling
|
||
|
----------------------
|
||
|
Add deficit round-robin schedule to ensure fairness between channels that have
|
||
|
a large number of small packets and channels that are sending the maximum
|
||
|
MTU-sized packets.
|
||
|
|
||
|
Transport Filter Internal API
|
||
|
-----------------------------
|
||
|
An internal transport filter API will be defined. This can be plugged into a
|
||
|
filter chain at the transport level to easily add data coding, encryption,
|
||
|
integrity hashes, etc.
|