/* Create and send the session open command. */ staticstruct mux_cmd_open_session_resp *
ipc_mux_session_open_send(struct iosm_mux *ipc_mux, int if_id)
{ struct mux_cmd_open_session_resp *open_session_resp; struct mux_acb *acb = &ipc_mux->acb; union mux_cmd_param param;
/* open_session commands to one ACB and start transmission. */
param.open_session.flow_ctrl = 0;
param.open_session.ipv4v6_hints = 0;
param.open_session.reserved2 = 0;
param.open_session.dl_head_pad_len = cpu_to_le32(IPC_MEM_DL_ETH_OFFSET);
/* Finish and transfer ACB. The user thread is suspended. * It is a blocking function call, until CP responds or timeout.
*/
acb->wanted_response = MUX_CMD_OPEN_SESSION_RESP; if (ipc_mux_dl_acb_send_cmds(ipc_mux, MUX_CMD_OPEN_SESSION, if_id, 0,
¶m, sizeof(param.open_session), true, false) ||
acb->got_response != MUX_CMD_OPEN_SESSION_RESP) {
dev_err(ipc_mux->dev, "if_id %d: OPEN_SESSION send failed",
if_id); return NULL;
}
open_session_resp = &ipc_mux->acb.got_param.open_session_resp; if (open_session_resp->response != cpu_to_le32(MUX_CMD_RESP_SUCCESS)) {
dev_err(ipc_mux->dev, "if_id %d,session open failed,response=%d", if_id,
open_session_resp->response); return NULL;
}
return open_session_resp;
}
/* Open the first IP session. */ staticbool ipc_mux_session_open(struct iosm_mux *ipc_mux, struct mux_session_open *session_open)
{ struct mux_cmd_open_session_resp *open_session_resp; int if_id;
/* Search for a free session interface id. */
if_id = le32_to_cpu(session_open->if_id); if (if_id < 0 || if_id >= IPC_MEM_MUX_IP_SESSION_ENTRIES) {
dev_err(ipc_mux->dev, "invalid interface id=%d", if_id); returnfalse;
}
/* Create and send the session open command. * It is a blocking function call, until CP responds or timeout.
*/
open_session_resp = ipc_mux_session_open_send(ipc_mux, if_id); if (!open_session_resp) {
ipc_mux_session_free(ipc_mux, if_id);
session_open->if_id = cpu_to_le32(-1); returnfalse;
}
/* Initialize the uplink skb accumulator. */
skb_queue_head_init(&ipc_mux->session[if_id].ul_list);
/* Reset the flow ctrl stats of the session */
ipc_mux->session[if_id].flow_ctl_en_cnt = 0;
ipc_mux->session[if_id].flow_ctl_dis_cnt = 0;
ipc_mux->session[if_id].ul_flow_credits = 0;
ipc_mux->session[if_id].net_tx_stop = false;
ipc_mux->session[if_id].flow_ctl_mask = 0;
/* Save and return the assigned if id. */
session_open->if_id = cpu_to_le32(if_id);
ipc_mux->nr_sessions++;
returntrue;
}
/* Free pending session UL packet. */ staticvoid ipc_mux_session_reset(struct iosm_mux *ipc_mux, int if_id)
{ /* Reset the session/if id state. */
ipc_mux_session_free(ipc_mux, if_id);
/* Empty the uplink skb accumulator. */
skb_queue_purge(&ipc_mux->session[if_id].ul_list);
}
staticvoid ipc_mux_session_close(struct iosm_mux *ipc_mux, struct mux_session_close *msg)
{ int if_id;
/* Copy the session interface id. */
if_id = le32_to_cpu(msg->if_id);
if (if_id < 0 || if_id >= IPC_MEM_MUX_IP_SESSION_ENTRIES) {
dev_err(ipc_mux->dev, "invalid session id %d", if_id); return;
}
/* Create and send the session close command. * It is a blocking function call, until CP responds or timeout.
*/ if (ipc_mux_dl_acb_send_cmds(ipc_mux, MUX_CMD_CLOSE_SESSION, if_id, 0,
NULL, 0, true, false))
dev_err(ipc_mux->dev, "if_id %d: CLOSE_SESSION send failed",
if_id);
/* Reset the flow ctrl stats of the session */
ipc_mux->session[if_id].flow_ctl_en_cnt = 0;
ipc_mux->session[if_id].flow_ctl_dis_cnt = 0;
ipc_mux->session[if_id].flow_ctl_mask = 0;
staticvoid ipc_mux_channel_close(struct iosm_mux *ipc_mux, struct mux_channel_close *channel_close_p)
{ int i;
/* Free pending session UL packet. */ for (i = 0; i < IPC_MEM_MUX_IP_SESSION_ENTRIES; i++) if (ipc_mux->session[i].wwan)
ipc_mux_session_reset(ipc_mux, i);
/* CP has interrupted AP. If AP is in IP MUX mode, execute the pending ops. */ staticint ipc_mux_schedule(struct iosm_mux *ipc_mux, union mux_msg *msg)
{ enum mux_event order; bool success; int ret = -EIO;
if (!ipc_mux->initialized) {
ret = -EAGAIN; goto out;
}
order = msg->common.event;
switch (ipc_mux->state) { case MUX_S_INACTIVE: if (order != MUX_E_MUX_SESSION_OPEN) goto out; /* Wait for the request to open a session */
if (ipc_mux->event == MUX_E_INACTIVE) /* Establish the MUX channel and the new state. */
ipc_mux->channel_id = ipc_mux_channel_create(ipc_mux);
if (ipc_mux->state != MUX_S_ACTIVE) {
ret = ipc_mux->channel_id; /* Missing the MUX channel */ goto out;
}
/* Disable the TD update timer and open the first IP session. */
ipc_imem_td_update_timer_suspend(ipc_mux->imem, true);
ipc_mux->event = MUX_E_MUX_SESSION_OPEN;
success = ipc_mux_session_open(ipc_mux, &msg->session_open);
ipc_imem_td_update_timer_suspend(ipc_mux->imem, false); if (success)
ret = ipc_mux->channel_id; goto out;
case MUX_S_ACTIVE: switch (order) { case MUX_E_MUX_SESSION_OPEN: /* Disable the TD update timer and open a session */
ipc_imem_td_update_timer_suspend(ipc_mux->imem, true);
ipc_mux->event = MUX_E_MUX_SESSION_OPEN;
success = ipc_mux_session_open(ipc_mux,
&msg->session_open);
ipc_imem_td_update_timer_suspend(ipc_mux->imem, false); if (success)
ret = ipc_mux->channel_id; goto out;
case MUX_E_MUX_SESSION_CLOSE: /* Release an IP session. */
ipc_mux->event = MUX_E_MUX_SESSION_CLOSE;
ipc_mux_session_close(ipc_mux, &msg->session_close); if (!ipc_mux->nr_sessions) {
ipc_mux->event = MUX_E_MUX_CHANNEL_CLOSE;
ipc_mux_channel_close(ipc_mux,
&msg->channel_close);
}
ret = ipc_mux->channel_id; goto out;
case MUX_E_MUX_CHANNEL_CLOSE: /* Close the MUX channel pipes. */
ipc_mux->event = MUX_E_MUX_CHANNEL_CLOSE;
ipc_mux_channel_close(ipc_mux, &msg->channel_close);
ret = ipc_mux->channel_id; goto out;
/* Allocate the list of UL ADB. */ for (i = 0; i < ul_tds; i++) {
dma_addr_t mapping;
skb = ipc_pcie_alloc_skb(ipc_mux->pcie, ul_td_size, GFP_ATOMIC,
&mapping, DMA_TO_DEVICE, 0); if (!skb) {
ipc_mux_deinit(ipc_mux); return NULL;
} /* Extend the UL ADB list. */
skb_queue_tail(free_list, skb);
}
return ipc_mux;
}
/* Informs the network stack to restart transmission for all opened session if * Flow Control is not ON for that session.
*/ staticvoid ipc_mux_restart_tx_for_all_sessions(struct iosm_mux *ipc_mux)
{ struct mux_session *session; int idx;
/* If flow control of the session is OFF and if there was tx * stop then restart. Inform the network interface to restart * sending data.
*/ if (session->flow_ctl_mask == 0) {
session->net_tx_stop = false;
ipc_mux_netif_tx_flowctrl(session, idx, false);
}
}
}
/* Informs the network stack to stop sending further pkt for all opened * sessions
*/ staticvoid ipc_mux_stop_netif_for_all_sessions(struct iosm_mux *ipc_mux)
{ struct mux_session *session; int idx;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.