1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2020-21 Intel Corporation. 4 */ 5 6 #include <linux/pm_runtime.h> 7 8 #include "iosm_ipc_chnl_cfg.h" 9 #include "iosm_ipc_imem_ops.h" 10 #include "iosm_ipc_port.h" 11 12 /* open logical channel for control communication */ 13 static int ipc_port_ctrl_start(struct wwan_port *port) 14 { 15 struct iosm_cdev *ipc_port = wwan_port_get_drvdata(port); 16 int ret = 0; 17 18 pm_runtime_get_sync(ipc_port->ipc_imem->dev); 19 ipc_port->channel = ipc_imem_sys_port_open(ipc_port->ipc_imem, 20 ipc_port->chl_id, 21 IPC_HP_CDEV_OPEN); 22 if (!ipc_port->channel) 23 ret = -EIO; 24 25 pm_runtime_mark_last_busy(ipc_port->ipc_imem->dev); 26 pm_runtime_put_autosuspend(ipc_port->ipc_imem->dev); 27 28 return ret; 29 } 30 31 /* close logical channel */ 32 static void ipc_port_ctrl_stop(struct wwan_port *port) 33 { 34 struct iosm_cdev *ipc_port = wwan_port_get_drvdata(port); 35 36 pm_runtime_get_sync(ipc_port->ipc_imem->dev); 37 ipc_imem_sys_port_close(ipc_port->ipc_imem, ipc_port->channel); 38 pm_runtime_mark_last_busy(ipc_port->ipc_imem->dev); 39 pm_runtime_put_autosuspend(ipc_port->ipc_imem->dev); 40 } 41 42 /* transfer control data to modem */ 43 static int ipc_port_ctrl_tx(struct wwan_port *port, struct sk_buff *skb) 44 { 45 struct iosm_cdev *ipc_port = wwan_port_get_drvdata(port); 46 int ret; 47 48 pm_runtime_get_sync(ipc_port->ipc_imem->dev); 49 ret = ipc_imem_sys_cdev_write(ipc_port, skb); 50 pm_runtime_mark_last_busy(ipc_port->ipc_imem->dev); 51 pm_runtime_put_autosuspend(ipc_port->ipc_imem->dev); 52 53 return ret; 54 } 55 56 static const struct wwan_port_ops ipc_wwan_ctrl_ops = { 57 .start = ipc_port_ctrl_start, 58 .stop = ipc_port_ctrl_stop, 59 .tx = ipc_port_ctrl_tx, 60 }; 61 62 /* Port init func */ 63 struct iosm_cdev *ipc_port_init(struct iosm_imem *ipc_imem, 64 struct ipc_chnl_cfg ipc_port_cfg) 65 { 66 struct iosm_cdev *ipc_port = kzalloc(sizeof(*ipc_port), GFP_KERNEL); 67 enum wwan_port_type port_type = ipc_port_cfg.wwan_port_type; 68 enum ipc_channel_id chl_id = ipc_port_cfg.id; 69 70 if (!ipc_port) 71 return NULL; 72 73 ipc_port->dev = ipc_imem->dev; 74 ipc_port->pcie = ipc_imem->pcie; 75 76 ipc_port->port_type = port_type; 77 ipc_port->chl_id = chl_id; 78 ipc_port->ipc_imem = ipc_imem; 79 80 ipc_port->iosm_port = wwan_create_port(ipc_port->dev, port_type, 81 &ipc_wwan_ctrl_ops, NULL, 82 ipc_port); 83 84 return ipc_port; 85 } 86 87 /* Port deinit func */ 88 void ipc_port_deinit(struct iosm_cdev *port[]) 89 { 90 struct iosm_cdev *ipc_port; 91 u8 ctrl_chl_nr; 92 93 for (ctrl_chl_nr = 0; ctrl_chl_nr < IPC_MEM_MAX_CHANNELS; 94 ctrl_chl_nr++) { 95 if (port[ctrl_chl_nr]) { 96 ipc_port = port[ctrl_chl_nr]; 97 wwan_remove_port(ipc_port->iosm_port); 98 kfree(ipc_port); 99 } 100 } 101 } 102