1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (C) 2020-21 Intel Corporation.
6 #include <linux/delay.h>
8 #include "iosm_ipc_chnl_cfg.h"
9 #include "iosm_ipc_imem.h"
10 #include "iosm_ipc_imem_ops.h"
11 #include "iosm_ipc_port.h"
12 #include "iosm_ipc_task_queue.h"
14 /* Open a packet data online channel between the network layer and CP. */
15 int ipc_imem_sys_wwan_open(struct iosm_imem *ipc_imem, int if_id)
17 dev_dbg(ipc_imem->dev, "%s if id: %d",
18 ipc_imem_phase_get_string(ipc_imem->phase), if_id);
20 /* The network interface is only supported in the runtime phase. */
21 if (ipc_imem_phase_update(ipc_imem) != IPC_P_RUN) {
22 dev_err(ipc_imem->dev, "net:%d : refused phase %s", if_id,
23 ipc_imem_phase_get_string(ipc_imem->phase));
27 /* check for the interafce id
28 * if if_id 1 to 8 then create IP MUX channel sessions.
29 * To start MUX session from 0 as network interface id would start
30 * from 1 so map it to if_id = if_id - 1
32 if (if_id >= IP_MUX_SESSION_START && if_id <= IP_MUX_SESSION_END)
33 return ipc_mux_open_session(ipc_imem->mux, if_id - 1);
38 /* Release a net link to CP. */
39 void ipc_imem_sys_wwan_close(struct iosm_imem *ipc_imem, int if_id,
42 if (ipc_imem->mux && if_id >= IP_MUX_SESSION_START &&
43 if_id <= IP_MUX_SESSION_END)
44 ipc_mux_close_session(ipc_imem->mux, if_id - 1);
47 /* Tasklet call to do uplink transfer. */
48 static int ipc_imem_tq_cdev_write(struct iosm_imem *ipc_imem, int arg,
49 void *msg, size_t size)
51 ipc_imem->ev_cdev_write_pending = false;
52 ipc_imem_ul_send(ipc_imem);
57 /* Through tasklet to do sio write. */
58 static int ipc_imem_call_cdev_write(struct iosm_imem *ipc_imem)
60 if (ipc_imem->ev_cdev_write_pending)
63 ipc_imem->ev_cdev_write_pending = true;
65 return ipc_task_queue_send_task(ipc_imem, ipc_imem_tq_cdev_write, 0,
69 /* Function for transfer UL data */
70 int ipc_imem_sys_wwan_transmit(struct iosm_imem *ipc_imem,
71 int if_id, int channel_id, struct sk_buff *skb)
75 if (!ipc_imem || channel_id < 0)
79 if (ipc_imem->phase != IPC_P_RUN) {
80 dev_dbg(ipc_imem->dev, "phase %s transmit",
81 ipc_imem_phase_get_string(ipc_imem->phase));
86 if (if_id >= IP_MUX_SESSION_START && if_id <= IP_MUX_SESSION_END)
87 /* Route the UL packet through IP MUX Layer */
88 ret = ipc_mux_ul_trigger_encode(ipc_imem->mux,
91 dev_err(ipc_imem->dev,
92 "invalid if_id %d: ", if_id);
97 /* Initialize wwan channel */
98 void ipc_imem_wwan_channel_init(struct iosm_imem *ipc_imem,
99 enum ipc_mux_protocol mux_type)
101 struct ipc_chnl_cfg chnl_cfg = { 0 };
103 ipc_imem->cp_version = ipc_mmio_get_cp_version(ipc_imem->mmio);
105 /* If modem version is invalid (0xffffffff), do not initialize WWAN. */
106 if (ipc_imem->cp_version == -1) {
107 dev_err(ipc_imem->dev, "invalid CP version");
111 ipc_chnl_cfg_get(&chnl_cfg, ipc_imem->nr_of_channels);
112 ipc_imem_channel_init(ipc_imem, IPC_CTYPE_WWAN, chnl_cfg,
115 /* WWAN registration. */
116 ipc_imem->wwan = ipc_wwan_init(ipc_imem, ipc_imem->dev);
118 dev_err(ipc_imem->dev,
119 "failed to register the ipc_wwan interfaces");
122 /* Map SKB to DMA for transfer */
123 static int ipc_imem_map_skb_to_dma(struct iosm_imem *ipc_imem,
126 struct iosm_pcie *ipc_pcie = ipc_imem->pcie;
127 char *buf = skb->data;
132 ret = ipc_pcie_addr_map(ipc_pcie, buf, len, &mapping, DMA_TO_DEVICE);
137 BUILD_BUG_ON(sizeof(*IPC_CB(skb)) > sizeof(skb->cb));
139 IPC_CB(skb)->mapping = mapping;
140 IPC_CB(skb)->direction = DMA_TO_DEVICE;
141 IPC_CB(skb)->len = len;
142 IPC_CB(skb)->op_type = (u8)UL_DEFAULT;
148 /* return true if channel is ready for use */
149 static bool ipc_imem_is_channel_active(struct iosm_imem *ipc_imem,
150 struct ipc_mem_channel *channel)
152 enum ipc_phase phase;
154 /* Update the current operation phase. */
155 phase = ipc_imem->phase;
157 /* Select the operation depending on the execution stage. */
165 /* Prepare the PSI image for the CP ROM driver and
166 * suspend the flash app.
168 if (channel->state != IMEM_CHANNEL_RESERVED) {
169 dev_err(ipc_imem->dev,
170 "ch[%d]:invalid channel state %d,expected %d",
171 channel->channel_id, channel->state,
172 IMEM_CHANNEL_RESERVED);
173 goto channel_unavailable;
175 goto channel_available;
178 /* Ignore uplink actions in all other phases. */
179 dev_err(ipc_imem->dev, "ch[%d]: confused phase %d",
180 channel->channel_id, phase);
181 goto channel_unavailable;
183 /* Check the full availability of the channel. */
184 if (channel->state != IMEM_CHANNEL_ACTIVE) {
185 dev_err(ipc_imem->dev, "ch[%d]: confused channel state %d",
186 channel->channel_id, channel->state);
187 goto channel_unavailable;
197 /* Release a sio link to CP. */
198 void ipc_imem_sys_cdev_close(struct iosm_cdev *ipc_cdev)
200 struct iosm_imem *ipc_imem = ipc_cdev->ipc_imem;
201 struct ipc_mem_channel *channel = ipc_cdev->channel;
202 enum ipc_phase curr_phase;
206 curr_phase = ipc_imem->phase;
208 /* If current phase is IPC_P_OFF or SIO ID is -ve then
209 * channel is already freed. Nothing to do.
211 if (curr_phase == IPC_P_OFF) {
212 dev_err(ipc_imem->dev,
213 "nothing to do. Current Phase: %s",
214 ipc_imem_phase_get_string(curr_phase));
218 if (channel->state == IMEM_CHANNEL_FREE) {
219 dev_err(ipc_imem->dev, "ch[%d]: invalid channel state %d",
220 channel->channel_id, channel->state);
224 /* If there are any pending TDs then wait for Timeout/Completion before
227 if (channel->ul_pipe.old_tail != channel->ul_pipe.old_head) {
228 ipc_imem->app_notify_ul_pend = 1;
230 /* Suspend the user app and wait a certain time for processing
233 status = wait_for_completion_interruptible_timeout
234 (&ipc_imem->ul_pend_sem,
235 msecs_to_jiffies(IPC_PEND_DATA_TIMEOUT));
237 dev_dbg(ipc_imem->dev,
238 "Pend data Timeout UL-Pipe:%d Head:%d Tail:%d",
239 channel->ul_pipe.pipe_nr,
240 channel->ul_pipe.old_head,
241 channel->ul_pipe.old_tail);
244 ipc_imem->app_notify_ul_pend = 0;
247 /* If there are any pending TDs then wait for Timeout/Completion before
250 ipc_protocol_get_head_tail_index(ipc_imem->ipc_protocol,
251 &channel->dl_pipe, NULL, &tail);
253 if (tail != channel->dl_pipe.old_tail) {
254 ipc_imem->app_notify_dl_pend = 1;
256 /* Suspend the user app and wait a certain time for processing
259 status = wait_for_completion_interruptible_timeout
260 (&ipc_imem->dl_pend_sem,
261 msecs_to_jiffies(IPC_PEND_DATA_TIMEOUT));
263 dev_dbg(ipc_imem->dev,
264 "Pend data Timeout DL-Pipe:%d Head:%d Tail:%d",
265 channel->dl_pipe.pipe_nr,
266 channel->dl_pipe.old_head,
267 channel->dl_pipe.old_tail);
270 ipc_imem->app_notify_dl_pend = 0;
273 /* Due to wait for completion in messages, there is a small window
274 * between closing the pipe and updating the channel is closed. In this
275 * small window there could be HP update from Host Driver. Hence update
276 * the channel state as CLOSING to aviod unnecessary interrupt
279 channel->state = IMEM_CHANNEL_CLOSING;
281 ipc_imem_pipe_close(ipc_imem, &channel->ul_pipe);
282 ipc_imem_pipe_close(ipc_imem, &channel->dl_pipe);
284 ipc_imem_channel_free(channel);
287 /* Open a PORT link to CP and return the channel */
288 struct ipc_mem_channel *ipc_imem_sys_port_open(struct iosm_imem *ipc_imem,
289 int chl_id, int hp_id)
291 struct ipc_mem_channel *channel;
294 /* The PORT interface is only supported in the runtime phase. */
295 if (ipc_imem_phase_update(ipc_imem) != IPC_P_RUN) {
296 dev_err(ipc_imem->dev, "PORT open refused, phase %s",
297 ipc_imem_phase_get_string(ipc_imem->phase));
301 ch_id = ipc_imem_channel_alloc(ipc_imem, chl_id, IPC_CTYPE_CTRL);
304 dev_err(ipc_imem->dev, "reservation of an PORT chnl id failed");
308 channel = ipc_imem_channel_open(ipc_imem, ch_id, hp_id);
311 dev_err(ipc_imem->dev, "PORT channel id open failed");
318 /* transfer skb to modem */
319 int ipc_imem_sys_cdev_write(struct iosm_cdev *ipc_cdev, struct sk_buff *skb)
321 struct ipc_mem_channel *channel = ipc_cdev->channel;
322 struct iosm_imem *ipc_imem = ipc_cdev->ipc_imem;
325 if (!ipc_imem_is_channel_active(ipc_imem, channel) ||
326 ipc_imem->phase == IPC_P_OFF_REQ)
329 ret = ipc_imem_map_skb_to_dma(ipc_imem, skb);
334 /* Add skb to the uplink skbuf accumulator. */
335 skb_queue_tail(&channel->ul_list, skb);
337 ret = ipc_imem_call_cdev_write(ipc_imem);
340 skb_dequeue_tail(&channel->ul_list);
341 dev_err(ipc_cdev->dev, "channel id[%d] write failed\n",
342 ipc_cdev->channel->channel_id);