/* 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. *Itisablockingfunctioncall,untilCPrespondsortimeout.
*/
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. *Itisablockingfunctioncall,untilCPrespondsortimeout.
*/
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);
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 *FlowControlisnotONforthatsession.
*/ 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 *stopthenrestart.Informthenetworkinterfacetorestart *sendingdata.
*/ 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.