1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (c) 2021, MediaTek Inc. 4 * Copyright (c) 2021-2022, Intel Corporation. 5 * Copyright (c) 2024, Fibocom Wireless Inc. 6 * 7 * Authors: 8 * Amir Hanania <amir.hanania@intel.com> 9 * Chandrashekar Devegowda <chandrashekar.devegowda@intel.com> 10 * Haijun Liu <haijun.liu@mediatek.com> 11 * Moises Veleta <moises.veleta@intel.com> 12 * Ricardo Martinez <ricardo.martinez@linux.intel.com> 13 * 14 * Contributors: 15 * Andy Shevchenko <andriy.shevchenko@linux.intel.com> 16 * Chiranjeevi Rapolu <chiranjeevi.rapolu@intel.com> 17 * Eliot Lee <eliot.lee@intel.com> 18 * Sreehari Kancharla <sreehari.kancharla@intel.com> 19 * Jinjian Song <jinjian.song@fibocom.com> 20 */ 21 22 #include <linux/atomic.h> 23 #include <linux/bitfield.h> 24 #include <linux/dev_printk.h> 25 #include <linux/err.h> 26 #include <linux/gfp.h> 27 #include <linux/minmax.h> 28 #include <linux/netdevice.h> 29 #include <linux/skbuff.h> 30 #include <linux/spinlock.h> 31 #include <linux/string.h> 32 #include <linux/wwan.h> 33 34 #include "t7xx_port.h" 35 #include "t7xx_port_proxy.h" 36 #include "t7xx_state_monitor.h" 37 38 static int t7xx_port_wwan_start(struct wwan_port *port) 39 { 40 struct t7xx_port *port_mtk = wwan_port_get_drvdata(port); 41 42 if (atomic_read(&port_mtk->usage_cnt)) 43 return -EBUSY; 44 45 atomic_inc(&port_mtk->usage_cnt); 46 return 0; 47 } 48 49 static void t7xx_port_wwan_stop(struct wwan_port *port) 50 { 51 struct t7xx_port *port_mtk = wwan_port_get_drvdata(port); 52 53 atomic_dec(&port_mtk->usage_cnt); 54 } 55 56 static int t7xx_port_fastboot_tx(struct t7xx_port *port, struct sk_buff *skb) 57 { 58 struct sk_buff *cur = skb, *tx_skb; 59 size_t actual, len, offset = 0; 60 int txq_mtu; 61 int ret; 62 63 txq_mtu = t7xx_get_port_mtu(port); 64 if (txq_mtu < 0) 65 return -EINVAL; 66 67 actual = cur->len; 68 while (actual) { 69 len = min_t(size_t, actual, txq_mtu); 70 tx_skb = __dev_alloc_skb(len, GFP_KERNEL); 71 if (!tx_skb) 72 return -ENOMEM; 73 74 skb_put_data(tx_skb, cur->data + offset, len); 75 76 ret = t7xx_port_send_raw_skb(port, tx_skb); 77 if (ret) { 78 dev_kfree_skb(tx_skb); 79 dev_err(port->dev, "Write error on fastboot port, %d\n", ret); 80 break; 81 } 82 offset += len; 83 actual -= len; 84 } 85 86 dev_kfree_skb(skb); 87 return 0; 88 } 89 90 static int t7xx_port_ctrl_tx(struct t7xx_port *port, struct sk_buff *skb) 91 { 92 const struct t7xx_port_conf *port_conf; 93 struct sk_buff *cur = skb, *cloned; 94 struct t7xx_fsm_ctl *ctl; 95 enum md_state md_state; 96 int cnt = 0, ret; 97 98 port_conf = port->port_conf; 99 ctl = port->t7xx_dev->md->fsm_ctl; 100 md_state = t7xx_fsm_get_md_state(ctl); 101 if (md_state == MD_STATE_WAITING_FOR_HS1 || md_state == MD_STATE_WAITING_FOR_HS2) { 102 dev_warn(port->dev, "Cannot write to %s port when md_state=%d\n", 103 port_conf->name, md_state); 104 return -ENODEV; 105 } 106 107 while (cur) { 108 cloned = skb_clone(cur, GFP_KERNEL); 109 cloned->len = skb_headlen(cur); 110 ret = t7xx_port_send_skb(port, cloned, 0, 0); 111 if (ret) { 112 dev_kfree_skb(cloned); 113 dev_err(port->dev, "Write error on %s port, %d\n", 114 port_conf->name, ret); 115 return cnt ? cnt + ret : ret; 116 } 117 cnt += cur->len; 118 if (cur == skb) 119 cur = skb_shinfo(skb)->frag_list; 120 else 121 cur = cur->next; 122 } 123 124 dev_kfree_skb(skb); 125 return 0; 126 } 127 128 static int t7xx_port_wwan_tx(struct wwan_port *port, struct sk_buff *skb) 129 { 130 struct t7xx_port *port_private = wwan_port_get_drvdata(port); 131 const struct t7xx_port_conf *port_conf = port_private->port_conf; 132 int ret; 133 134 if (!port_private->chan_enable) 135 return -EINVAL; 136 137 if (port_conf->port_type != WWAN_PORT_FASTBOOT) 138 ret = t7xx_port_ctrl_tx(port_private, skb); 139 else 140 ret = t7xx_port_fastboot_tx(port_private, skb); 141 142 return ret; 143 } 144 145 static const struct wwan_port_ops wwan_ops = { 146 .start = t7xx_port_wwan_start, 147 .stop = t7xx_port_wwan_stop, 148 .tx = t7xx_port_wwan_tx, 149 }; 150 151 static void t7xx_port_wwan_create(struct t7xx_port *port) 152 { 153 const struct t7xx_port_conf *port_conf = port->port_conf; 154 unsigned int header_len = sizeof(struct ccci_header), mtu; 155 struct wwan_port_caps caps; 156 157 if (!port->wwan.wwan_port) { 158 mtu = t7xx_get_port_mtu(port); 159 caps.frag_len = mtu - header_len; 160 caps.headroom_len = header_len; 161 port->wwan.wwan_port = wwan_create_port(port->dev, port_conf->port_type, 162 &wwan_ops, &caps, port); 163 if (IS_ERR(port->wwan.wwan_port)) 164 dev_err(port->dev, "Unable to create WWAN port %s", port_conf->name); 165 } 166 } 167 168 static int t7xx_port_wwan_init(struct t7xx_port *port) 169 { 170 const struct t7xx_port_conf *port_conf = port->port_conf; 171 172 if (port_conf->port_type == WWAN_PORT_FASTBOOT) 173 t7xx_port_wwan_create(port); 174 175 port->rx_length_th = RX_QUEUE_MAXLEN; 176 return 0; 177 } 178 179 static void t7xx_port_wwan_uninit(struct t7xx_port *port) 180 { 181 if (!port->wwan.wwan_port) 182 return; 183 184 port->rx_length_th = 0; 185 wwan_remove_port(port->wwan.wwan_port); 186 port->wwan.wwan_port = NULL; 187 } 188 189 static int t7xx_port_wwan_recv_skb(struct t7xx_port *port, struct sk_buff *skb) 190 { 191 if (!atomic_read(&port->usage_cnt) || !port->chan_enable) { 192 const struct t7xx_port_conf *port_conf = port->port_conf; 193 194 dev_kfree_skb_any(skb); 195 dev_err_ratelimited(port->dev, "Port %s is not opened, drop packets\n", 196 port_conf->name); 197 /* Dropping skb, caller should not access skb.*/ 198 return 0; 199 } 200 201 wwan_port_rx(port->wwan.wwan_port, skb); 202 return 0; 203 } 204 205 static int t7xx_port_wwan_enable_chl(struct t7xx_port *port) 206 { 207 spin_lock(&port->port_update_lock); 208 port->chan_enable = true; 209 spin_unlock(&port->port_update_lock); 210 211 return 0; 212 } 213 214 static int t7xx_port_wwan_disable_chl(struct t7xx_port *port) 215 { 216 spin_lock(&port->port_update_lock); 217 port->chan_enable = false; 218 spin_unlock(&port->port_update_lock); 219 220 return 0; 221 } 222 223 static void t7xx_port_wwan_md_state_notify(struct t7xx_port *port, unsigned int state) 224 { 225 const struct t7xx_port_conf *port_conf = port->port_conf; 226 227 if (port_conf->port_type == WWAN_PORT_FASTBOOT) 228 return; 229 230 if (state != MD_STATE_READY) 231 return; 232 233 t7xx_port_wwan_create(port); 234 } 235 236 struct port_ops wwan_sub_port_ops = { 237 .init = t7xx_port_wwan_init, 238 .recv_skb = t7xx_port_wwan_recv_skb, 239 .uninit = t7xx_port_wwan_uninit, 240 .enable_chl = t7xx_port_wwan_enable_chl, 241 .disable_chl = t7xx_port_wwan_disable_chl, 242 .md_state_notify = t7xx_port_wwan_md_state_notify, 243 }; 244