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