1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (C) 2020-21 Intel Corporation.
6 #include "iosm_ipc_imem.h"
7 #include "iosm_ipc_protocol.h"
8 #include "iosm_ipc_protocol_ops.h"
9 #include "iosm_ipc_pm.h"
10 #include "iosm_ipc_task_queue.h"
12 int ipc_protocol_tq_msg_send(struct iosm_protocol *ipc_protocol,
13 enum ipc_msg_prep_type msg_type,
14 union ipc_msg_prep_args *prep_args,
15 struct ipc_rsp *response)
17 int index = ipc_protocol_msg_prep(ipc_protocol->imem, msg_type,
20 /* Store reference towards caller specified response in response ring
23 if (index >= 0 && index < IPC_MEM_MSG_ENTRIES) {
24 ipc_protocol->rsp_ring[index] = response;
25 ipc_protocol_msg_hp_update(ipc_protocol->imem);
31 /* Callback for message send */
32 static int ipc_protocol_tq_msg_send_cb(struct iosm_imem *ipc_imem, int arg,
33 void *msg, size_t size)
35 struct ipc_call_msg_send_args *send_args = msg;
36 struct iosm_protocol *ipc_protocol = ipc_imem->ipc_protocol;
38 return ipc_protocol_tq_msg_send(ipc_protocol, send_args->msg_type,
43 /* Remove reference to a response. This is typically used when a requestor timed
44 * out and is no longer interested in the response.
46 static int ipc_protocol_tq_msg_remove(struct iosm_imem *ipc_imem, int arg,
47 void *msg, size_t size)
49 struct iosm_protocol *ipc_protocol = ipc_imem->ipc_protocol;
51 ipc_protocol->rsp_ring[arg] = NULL;
55 int ipc_protocol_msg_send(struct iosm_protocol *ipc_protocol,
56 enum ipc_msg_prep_type prep,
57 union ipc_msg_prep_args *prep_args)
59 struct ipc_call_msg_send_args send_args;
60 unsigned int exec_timeout;
61 struct ipc_rsp response;
64 exec_timeout = (ipc_protocol_get_ap_exec_stage(ipc_protocol) ==
65 IPC_MEM_EXEC_STAGE_RUN ?
66 IPC_MSG_COMPLETE_RUN_DEFAULT_TIMEOUT :
67 IPC_MSG_COMPLETE_BOOT_DEFAULT_TIMEOUT);
69 /* Trap if called from non-preemptible context */
72 response.status = IPC_MEM_MSG_CS_INVALID;
73 init_completion(&response.completion);
75 send_args.msg_type = prep;
76 send_args.prep_args = prep_args;
77 send_args.response = &response;
79 /* Allocate and prepare message to be sent in tasklet context.
80 * A positive index returned form tasklet_call references the message
81 * in case it needs to be cancelled when there is a timeout.
83 index = ipc_task_queue_send_task(ipc_protocol->imem,
84 ipc_protocol_tq_msg_send_cb, 0,
88 dev_err(ipc_protocol->dev, "msg %d failed", prep);
92 /* Wait for the device to respond to the message */
93 switch (wait_for_completion_timeout(&response.completion,
94 msecs_to_jiffies(exec_timeout))) {
96 /* Timeout, there was no response from the device.
97 * Remove the reference to the local response completion
98 * object as we are no longer interested in the response.
100 ipc_task_queue_send_task(ipc_protocol->imem,
101 ipc_protocol_tq_msg_remove, index,
103 dev_err(ipc_protocol->dev, "msg timeout");
104 ipc_uevent_send(ipc_protocol->pcie->dev, UEVENT_MDM_TIMEOUT);
107 /* We got a response in time; check completion status: */
108 if (response.status != IPC_MEM_MSG_CS_SUCCESS) {
109 dev_err(ipc_protocol->dev,
110 "msg completion status error %d",
119 static int ipc_protocol_msg_send_host_sleep(struct iosm_protocol *ipc_protocol,
122 union ipc_msg_prep_args prep_args = {
124 .sleep.state = state,
127 return ipc_protocol_msg_send(ipc_protocol, IPC_MSG_PREP_SLEEP,
131 void ipc_protocol_doorbell_trigger(struct iosm_protocol *ipc_protocol,
134 ipc_pm_signal_hpda_doorbell(&ipc_protocol->pm, identifier, true);
137 bool ipc_protocol_pm_dev_sleep_handle(struct iosm_protocol *ipc_protocol)
139 u32 ipc_status = ipc_protocol_get_ipc_status(ipc_protocol);
142 if (ipc_status != IPC_MEM_DEVICE_IPC_RUNNING) {
143 dev_err(ipc_protocol->dev,
144 "irq ignored, CP IPC state is %d, should be RUNNING",
147 /* Stop further processing. */
151 /* Get a copy of the requested PM state by the device and the local
154 requested = ipc_protocol_pm_dev_get_sleep_notification(ipc_protocol);
156 return ipc_pm_dev_slp_notification(&ipc_protocol->pm, requested);
159 static int ipc_protocol_tq_wakeup_dev_slp(struct iosm_imem *ipc_imem, int arg,
160 void *msg, size_t size)
162 struct iosm_pm *ipc_pm = &ipc_imem->ipc_protocol->pm;
164 /* Wakeup from device sleep if it is not ACTIVE */
165 ipc_pm_trigger(ipc_pm, IPC_PM_UNIT_HS, true);
167 ipc_pm_trigger(ipc_pm, IPC_PM_UNIT_HS, false);
172 void ipc_protocol_s2idle_sleep(struct iosm_protocol *ipc_protocol, bool sleep)
174 ipc_pm_set_s2idle_sleep(&ipc_protocol->pm, sleep);
177 bool ipc_protocol_suspend(struct iosm_protocol *ipc_protocol)
179 if (!ipc_pm_prepare_host_sleep(&ipc_protocol->pm))
182 ipc_task_queue_send_task(ipc_protocol->imem,
183 ipc_protocol_tq_wakeup_dev_slp, 0, NULL, 0,
186 if (!ipc_pm_wait_for_device_active(&ipc_protocol->pm)) {
187 ipc_uevent_send(ipc_protocol->pcie->dev, UEVENT_MDM_TIMEOUT);
191 /* Send the sleep message for sync sys calls. */
192 dev_dbg(ipc_protocol->dev, "send TARGET_HOST, ENTER_SLEEP");
193 if (ipc_protocol_msg_send_host_sleep(ipc_protocol,
194 IPC_HOST_SLEEP_ENTER_SLEEP)) {
195 /* Sending ENTER_SLEEP message failed, we are still active */
196 ipc_protocol->pm.host_pm_state = IPC_MEM_HOST_PM_ACTIVE;
200 ipc_protocol->pm.host_pm_state = IPC_MEM_HOST_PM_SLEEP;
206 bool ipc_protocol_resume(struct iosm_protocol *ipc_protocol)
208 if (!ipc_pm_prepare_host_active(&ipc_protocol->pm))
211 dev_dbg(ipc_protocol->dev, "send TARGET_HOST, EXIT_SLEEP");
212 if (ipc_protocol_msg_send_host_sleep(ipc_protocol,
213 IPC_HOST_SLEEP_EXIT_SLEEP)) {
214 ipc_protocol->pm.host_pm_state = IPC_MEM_HOST_PM_SLEEP;
218 ipc_protocol->pm.host_pm_state = IPC_MEM_HOST_PM_ACTIVE;
223 struct iosm_protocol *ipc_protocol_init(struct iosm_imem *ipc_imem)
225 struct iosm_protocol *ipc_protocol =
226 kzalloc(sizeof(*ipc_protocol), GFP_KERNEL);
227 struct ipc_protocol_context_info *p_ci;
233 ipc_protocol->dev = ipc_imem->dev;
234 ipc_protocol->pcie = ipc_imem->pcie;
235 ipc_protocol->imem = ipc_imem;
236 ipc_protocol->p_ap_shm = NULL;
237 ipc_protocol->phy_ap_shm = 0;
239 ipc_protocol->old_msg_tail = 0;
241 ipc_protocol->p_ap_shm =
242 pci_alloc_consistent(ipc_protocol->pcie->pci,
243 sizeof(*ipc_protocol->p_ap_shm),
244 &ipc_protocol->phy_ap_shm);
246 if (!ipc_protocol->p_ap_shm) {
247 dev_err(ipc_protocol->dev, "pci shm alloc error");
252 /* Prepare the context info for CP. */
253 addr = ipc_protocol->phy_ap_shm;
254 p_ci = &ipc_protocol->p_ap_shm->ci;
255 p_ci->device_info_addr =
256 addr + offsetof(struct ipc_protocol_ap_shm, device_info);
258 addr + offsetof(struct ipc_protocol_ap_shm, head_array);
260 addr + offsetof(struct ipc_protocol_ap_shm, tail_array);
261 p_ci->msg_head = addr + offsetof(struct ipc_protocol_ap_shm, msg_head);
262 p_ci->msg_tail = addr + offsetof(struct ipc_protocol_ap_shm, msg_tail);
263 p_ci->msg_ring_addr =
264 addr + offsetof(struct ipc_protocol_ap_shm, msg_ring);
265 p_ci->msg_ring_entries = cpu_to_le16(IPC_MEM_MSG_ENTRIES);
266 p_ci->msg_irq_vector = IPC_MSG_IRQ_VECTOR;
267 p_ci->device_info_irq_vector = IPC_DEVICE_IRQ_VECTOR;
269 ipc_mmio_set_contex_info_addr(ipc_imem->mmio, addr);
271 ipc_pm_init(ipc_protocol);
276 void ipc_protocol_deinit(struct iosm_protocol *proto)
278 pci_free_consistent(proto->pcie->pci, sizeof(*proto->p_ap_shm),
279 proto->p_ap_shm, proto->phy_ap_shm);
281 ipc_pm_deinit(proto);