1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2020-21 Intel Corporation. 4 */ 5 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" 11 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) 16 { 17 int index = ipc_protocol_msg_prep(ipc_protocol->imem, msg_type, 18 prep_args); 19 20 /* Store reference towards caller specified response in response ring 21 * and signal CP 22 */ 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); 26 } 27 28 return index; 29 } 30 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) 34 { 35 struct ipc_call_msg_send_args *send_args = msg; 36 struct iosm_protocol *ipc_protocol = ipc_imem->ipc_protocol; 37 38 return ipc_protocol_tq_msg_send(ipc_protocol, send_args->msg_type, 39 send_args->prep_args, 40 send_args->response); 41 } 42 43 /* Remove reference to a response. This is typically used when a requestor timed 44 * out and is no longer interested in the response. 45 */ 46 static int ipc_protocol_tq_msg_remove(struct iosm_imem *ipc_imem, int arg, 47 void *msg, size_t size) 48 { 49 struct iosm_protocol *ipc_protocol = ipc_imem->ipc_protocol; 50 51 ipc_protocol->rsp_ring[arg] = NULL; 52 return 0; 53 } 54 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) 58 { 59 struct ipc_call_msg_send_args send_args; 60 unsigned int exec_timeout; 61 struct ipc_rsp response; 62 int index; 63 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); 68 69 /* Trap if called from non-preemptible context */ 70 might_sleep(); 71 72 response.status = IPC_MEM_MSG_CS_INVALID; 73 init_completion(&response.completion); 74 75 send_args.msg_type = prep; 76 send_args.prep_args = prep_args; 77 send_args.response = &response; 78 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. 82 */ 83 index = ipc_task_queue_send_task(ipc_protocol->imem, 84 ipc_protocol_tq_msg_send_cb, 0, 85 &send_args, 0, true); 86 87 if (index < 0) { 88 dev_err(ipc_protocol->dev, "msg %d failed", prep); 89 return index; 90 } 91 92 /* Wait for the device to respond to the message */ 93 switch (wait_for_completion_timeout(&response.completion, 94 msecs_to_jiffies(exec_timeout))) { 95 case 0: 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. 99 */ 100 ipc_task_queue_send_task(ipc_protocol->imem, 101 ipc_protocol_tq_msg_remove, index, 102 NULL, 0, true); 103 dev_err(ipc_protocol->dev, "msg timeout"); 104 ipc_uevent_send(ipc_protocol->pcie->dev, UEVENT_MDM_TIMEOUT); 105 break; 106 default: 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", 111 response.status); 112 return -EIO; 113 } 114 } 115 116 return 0; 117 } 118 119 static int ipc_protocol_msg_send_host_sleep(struct iosm_protocol *ipc_protocol, 120 u32 state) 121 { 122 union ipc_msg_prep_args prep_args = { 123 .sleep.target = 0, 124 .sleep.state = state, 125 }; 126 127 return ipc_protocol_msg_send(ipc_protocol, IPC_MSG_PREP_SLEEP, 128 &prep_args); 129 } 130 131 void ipc_protocol_doorbell_trigger(struct iosm_protocol *ipc_protocol, 132 u32 identifier) 133 { 134 ipc_pm_signal_hpda_doorbell(&ipc_protocol->pm, identifier, true); 135 } 136 137 bool ipc_protocol_pm_dev_sleep_handle(struct iosm_protocol *ipc_protocol) 138 { 139 u32 ipc_status = ipc_protocol_get_ipc_status(ipc_protocol); 140 u32 requested; 141 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", 145 ipc_status); 146 147 /* Stop further processing. */ 148 return false; 149 } 150 151 /* Get a copy of the requested PM state by the device and the local 152 * device PM state. 153 */ 154 requested = ipc_protocol_pm_dev_get_sleep_notification(ipc_protocol); 155 156 return ipc_pm_dev_slp_notification(&ipc_protocol->pm, requested); 157 } 158 159 static int ipc_protocol_tq_wakeup_dev_slp(struct iosm_imem *ipc_imem, int arg, 160 void *msg, size_t size) 161 { 162 struct iosm_pm *ipc_pm = &ipc_imem->ipc_protocol->pm; 163 164 /* Wakeup from device sleep if it is not ACTIVE */ 165 ipc_pm_trigger(ipc_pm, IPC_PM_UNIT_HS, true); 166 167 ipc_pm_trigger(ipc_pm, IPC_PM_UNIT_HS, false); 168 169 return 0; 170 } 171 172 void ipc_protocol_s2idle_sleep(struct iosm_protocol *ipc_protocol, bool sleep) 173 { 174 ipc_pm_set_s2idle_sleep(&ipc_protocol->pm, sleep); 175 } 176 177 bool ipc_protocol_suspend(struct iosm_protocol *ipc_protocol) 178 { 179 if (!ipc_pm_prepare_host_sleep(&ipc_protocol->pm)) 180 goto err; 181 182 ipc_task_queue_send_task(ipc_protocol->imem, 183 ipc_protocol_tq_wakeup_dev_slp, 0, NULL, 0, 184 true); 185 186 if (!ipc_pm_wait_for_device_active(&ipc_protocol->pm)) { 187 ipc_uevent_send(ipc_protocol->pcie->dev, UEVENT_MDM_TIMEOUT); 188 goto err; 189 } 190 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; 197 goto err; 198 } 199 200 ipc_protocol->pm.host_pm_state = IPC_MEM_HOST_PM_SLEEP; 201 return true; 202 err: 203 return false; 204 } 205 206 bool ipc_protocol_resume(struct iosm_protocol *ipc_protocol) 207 { 208 if (!ipc_pm_prepare_host_active(&ipc_protocol->pm)) 209 return false; 210 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; 215 return false; 216 } 217 218 ipc_protocol->pm.host_pm_state = IPC_MEM_HOST_PM_ACTIVE; 219 220 return true; 221 } 222 223 struct iosm_protocol *ipc_protocol_init(struct iosm_imem *ipc_imem) 224 { 225 struct iosm_protocol *ipc_protocol = 226 kzalloc(sizeof(*ipc_protocol), GFP_KERNEL); 227 struct ipc_protocol_context_info *p_ci; 228 u64 addr; 229 230 if (!ipc_protocol) 231 return NULL; 232 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; 238 239 ipc_protocol->old_msg_tail = 0; 240 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); 245 246 if (!ipc_protocol->p_ap_shm) { 247 dev_err(ipc_protocol->dev, "pci shm alloc error"); 248 kfree(ipc_protocol); 249 return NULL; 250 } 251 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); 257 p_ci->head_array = 258 addr + offsetof(struct ipc_protocol_ap_shm, head_array); 259 p_ci->tail_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; 268 269 ipc_mmio_set_contex_info_addr(ipc_imem->mmio, addr); 270 271 ipc_pm_init(ipc_protocol); 272 273 return ipc_protocol; 274 } 275 276 void ipc_protocol_deinit(struct iosm_protocol *proto) 277 { 278 pci_free_consistent(proto->pcie->pci, sizeof(*proto->p_ap_shm), 279 proto->p_ap_shm, proto->phy_ap_shm); 280 281 ipc_pm_deinit(proto); 282 kfree(proto); 283 } 284